Update from HH master
authorCezary Kaliszyk <cek@colo12-c703.uibk.ac.at>
Fri, 30 Aug 2013 09:32:28 +0000 (11:32 +0200)
committerCezary Kaliszyk <cek@colo12-c703.uibk.ac.at>
Fri, 30 Aug 2013 09:32:28 +0000 (11:32 +0200)
27 files changed:
Multivariate/canal.ml [new file with mode: 0644]
Multivariate/cauchy.ml [new file with mode: 0644]
Multivariate/clifford.ml [new file with mode: 0644]
Multivariate/complex_database.ml [new file with mode: 0644]
Multivariate/complexes.ml [new file with mode: 0644]
Multivariate/convex.ml [new file with mode: 0644]
Multivariate/cross.ml [new file with mode: 0644]
Multivariate/derivatives.ml [new file with mode: 0644]
Multivariate/determinants.ml [new file with mode: 0644]
Multivariate/dimension.ml [new file with mode: 0644]
Multivariate/flyspeck.ml [new file with mode: 0644]
Multivariate/geom.ml [new file with mode: 0644]
Multivariate/integration.ml [new file with mode: 0644]
Multivariate/make_complex.ml [new file with mode: 0644]
Multivariate/measure.ml [new file with mode: 0644]
Multivariate/misc.ml [new file with mode: 0644]
Multivariate/multivariate_database.ml [new file with mode: 0644]
Multivariate/paths.ml [new file with mode: 0644]
Multivariate/polytope.ml [new file with mode: 0644]
Multivariate/realanalysis.ml [new file with mode: 0644]
Multivariate/tarski.ml [new file with mode: 0644]
Multivariate/topology.ml [new file with mode: 0644]
Multivariate/transcendentals.ml [new file with mode: 0644]
Multivariate/vectors.ml [new file with mode: 0644]
Multivariate/wlog.ml [new file with mode: 0644]
Multivariate/wlog_examples.ml [new file with mode: 0644]
make.ml [new file with mode: 0644]

diff --git a/Multivariate/canal.ml b/Multivariate/canal.ml
new file mode 100644 (file)
index 0000000..f09184f
--- /dev/null
@@ -0,0 +1,3207 @@
+(* ========================================================================= *)
+(* Complex analysis.                                                         *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(* (c) Copyright, Marco Maggesi, Graziano Gentili and Gianni Ciolli, 2008.   *)
+(*              (c) Copyright, Valentina Bruno 2010                          *)
+(* ========================================================================= *)
+
+needs "Library/floor.ml";;
+needs "Library/iter.ml";;
+needs "Multivariate/complexes.ml";;
+
+prioritize_complex();;
+
+(* ------------------------------------------------------------------------- *)
+(* Some toplogical facts formulated for the complex numbers.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let CLOSED_HALFSPACE_RE_GE = prove
+ (`!b. closed {z | Re(z) >= b}`,
+  GEN_TAC THEN MP_TAC(ISPECL [`Cx(&1)`; `b:real`] CLOSED_HALFSPACE_GE) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; dot; SUM_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[RE_CX; IM_CX; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let CLOSED_HALFSPACE_RE_LE = prove
+ (`!b. closed {z | Re(z) <= b}`,
+  GEN_TAC THEN MP_TAC(ISPECL [`Cx(&1)`; `b:real`] CLOSED_HALFSPACE_LE) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; dot; SUM_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[RE_CX; IM_CX; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let CLOSED_HALFSPACE_RE_EQ = prove
+ (`!b. closed {z | Re(z) = b}`,
+  GEN_TAC THEN 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
+  SIMP_TAC[CLOSED_INTER; CLOSED_HALFSPACE_RE_GE; CLOSED_HALFSPACE_RE_LE]);;
+
+let OPEN_HALFSPACE_RE_GT = prove
+ (`!b. open {z | Re(z) > b}`,
+  REWRITE_TAC[OPEN_CLOSED; CLOSED_HALFSPACE_RE_LE;
+              REAL_ARITH `x > y <=> ~(x <= y)`;
+              SET_RULE `UNIV DIFF {x | ~p x} = {x | p x}`]);;
+
+let OPEN_HALFSPACE_RE_LT = prove
+ (`!b. open {z | Re(z) < b}`,
+  REWRITE_TAC[OPEN_CLOSED; CLOSED_HALFSPACE_RE_GE;
+              REAL_ARITH `x < y <=> ~(x >= y)`;
+              SET_RULE `UNIV DIFF {x | ~p x} = {x | p x}`]);;
+
+let CLOSED_HALFSPACE_IM_GE = prove
+ (`!b. closed {z | Im(z) >= b}`,
+  GEN_TAC THEN MP_TAC(ISPECL [`ii`; `b:real`] CLOSED_HALFSPACE_GE) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; dot; SUM_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[ii; RE_CX; IM_CX; RE; IM; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let CLOSED_HALFSPACE_IM_LE = prove
+ (`!b. closed {z | Im(z) <= b}`,
+  GEN_TAC THEN MP_TAC(ISPECL [`ii`; `b:real`] CLOSED_HALFSPACE_LE) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; dot; SUM_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[ii; RE_CX; IM_CX; RE; IM; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let CLOSED_HALFSPACE_IM_EQ = prove
+ (`!b. closed {z | Im(z) = b}`,
+  GEN_TAC THEN 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
+  SIMP_TAC[CLOSED_INTER; CLOSED_HALFSPACE_IM_GE; CLOSED_HALFSPACE_IM_LE]);;
+
+let OPEN_HALFSPACE_IM_GT = prove
+ (`!b. open {z | Im(z) > b}`,
+  REWRITE_TAC[OPEN_CLOSED; CLOSED_HALFSPACE_IM_LE;
+              REAL_ARITH `x > y <=> ~(x <= y)`;
+              SET_RULE `UNIV DIFF {x | ~p x} = {x | p x}`]);;
+
+let OPEN_HALFSPACE_IM_LT = prove
+ (`!b. open {z | Im(z) < b}`,
+  REWRITE_TAC[OPEN_CLOSED; CLOSED_HALFSPACE_IM_GE;
+              REAL_ARITH `x < y <=> ~(x >= y)`;
+              SET_RULE `UNIV DIFF {x | ~p x} = {x | p x}`]);;
+
+let CONVEX_HALFSPACE_RE_GE = prove
+ (`!b. convex {z | Re(z) >= b}`,
+  GEN_TAC THEN MP_TAC(ISPECL [`Cx(&1)`; `b:real`] CONVEX_HALFSPACE_GE) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; dot; SUM_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[ii; RE_CX; IM_CX; RE; IM; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let CONVEX_HALFSPACE_RE_GT = prove
+ (`!b. convex {z | Re(z) > b}`,
+  GEN_TAC THEN MP_TAC(ISPECL [`Cx(&1)`; `b:real`] CONVEX_HALFSPACE_GT) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; dot; SUM_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[ii; RE_CX; IM_CX; RE; IM; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let CONVEX_HALFSPACE_RE_LE = prove
+ (`!b. convex {z | Re(z) <= b}`,
+  GEN_TAC THEN MP_TAC(ISPECL [`Cx(&1)`; `b:real`] CONVEX_HALFSPACE_LE) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; dot; SUM_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[ii; RE_CX; IM_CX; RE; IM; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let CONVEX_HALFSPACE_RE_LT = prove
+ (`!b. convex {z | Re(z) < b}`,
+  GEN_TAC THEN MP_TAC(ISPECL [`Cx(&1)`; `b:real`] CONVEX_HALFSPACE_LT) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; dot; SUM_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[ii; RE_CX; IM_CX; RE; IM; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let CONVEX_HALFSPACE_IM_GE = prove
+ (`!b. convex {z | Im(z) >= b}`,
+  GEN_TAC THEN MP_TAC(ISPECL [`ii`; `b:real`] CONVEX_HALFSPACE_GE) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; dot; SUM_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[ii; RE_CX; IM_CX; RE; IM; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let CONVEX_HALFSPACE_IM_GT = prove
+ (`!b. convex {z | Im(z) > b}`,
+  GEN_TAC THEN MP_TAC(ISPECL [`ii`; `b:real`] CONVEX_HALFSPACE_GT) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; dot; SUM_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[ii; RE_CX; IM_CX; RE; IM; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let CONVEX_HALFSPACE_IM_LE = prove
+ (`!b. convex {z | Im(z) <= b}`,
+  GEN_TAC THEN MP_TAC(ISPECL [`ii`; `b:real`] CONVEX_HALFSPACE_LE) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; dot; SUM_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[ii; RE_CX; IM_CX; RE; IM; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let CONVEX_HALFSPACE_IM_LT = prove
+ (`!b. convex {z | Im(z) < b}`,
+  GEN_TAC THEN MP_TAC(ISPECL [`ii`; `b:real`] CONVEX_HALFSPACE_LT) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; dot; SUM_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[ii; RE_CX; IM_CX; RE; IM; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let COMPLEX_IN_BALL_0 = prove
+ (`!v r. v IN ball(Cx(&0),r) <=> norm v < r`,
+  REWRITE_TAC [GSYM COMPLEX_VEC_0; IN_BALL_0]);;
+
+let COMPLEX_IN_CBALL_0 = prove
+ (`!v r. v IN cball(Cx(&0),r) <=> norm v <= r`,
+  REWRITE_TAC [GSYM COMPLEX_VEC_0; IN_CBALL_0]);;
+
+let COMPLEX_IN_SPHERE_0 = prove
+ (`!v r. v IN sphere(Cx(&0),r) <=> norm v = r`,
+  REWRITE_TAC [GSYM COMPLEX_VEC_0; IN_SPHERE_0]);;
+
+let IN_BALL_RE = prove
+ (`!x z e. x IN ball(z,e) ==> abs(Re(x) - Re(z)) < e`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[IN_BALL; dist] THEN
+  MP_TAC(SPEC `z - x:complex` COMPLEX_NORM_GE_RE_IM) THEN
+  REWRITE_TAC[RE_SUB] THEN REAL_ARITH_TAC);;
+
+let IN_BALL_IM = prove
+ (`!x z e. x IN ball(z,e) ==> abs(Im(x) - Im(z)) < e`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[IN_BALL; dist] THEN
+  MP_TAC(SPEC `z - x:complex` COMPLEX_NORM_GE_RE_IM) THEN
+  REWRITE_TAC[IM_SUB] THEN REAL_ARITH_TAC);;
+
+let IN_CBALL_RE = prove
+ (`!x z e. x IN cball(z,e) ==> abs(Re(x) - Re(z)) <= e`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[IN_CBALL; dist] THEN
+  MP_TAC(SPEC `z - x:complex` COMPLEX_NORM_GE_RE_IM) THEN
+  REWRITE_TAC[RE_SUB] THEN REAL_ARITH_TAC);;
+
+let IN_CBALL_IM = prove
+ (`!x z e. x IN cball(z,e) ==> abs(Im(x) - Im(z)) <= e`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[IN_CBALL; dist] THEN
+  MP_TAC(SPEC `z - x:complex` COMPLEX_NORM_GE_RE_IM) THEN
+  REWRITE_TAC[IM_SUB] THEN REAL_ARITH_TAC);;
+
+let CLOSED_REAL_SET = prove
+ (`closed {z | real z}`,
+  REWRITE_TAC[CLOSED_HALFSPACE_IM_EQ; real]);;
+
+let CLOSED_REAL = prove
+ (`closed real`,
+  GEN_REWRITE_TAC RAND_CONV [SET_RULE `s = {x | s x}`] THEN
+  REWRITE_TAC[CLOSED_REAL_SET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex-specific uniform limit composition theorems.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let UNIFORM_LIM_COMPLEX_MUL = prove
+ (`!net:(A)net P f g l m b1 b2.
+        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(f n x * g n x - l n * m n) < e)
+                     net`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o CONJ BILINEAR_COMPLEX_MUL) THEN
+  REWRITE_TAC[UNIFORM_LIM_BILINEAR]);;
+
+let UNIFORM_LIM_COMPLEX_INV = prove
+ (`!net:(A)net P f l b.
+        (!e. &0 < e
+             ==> eventually (\x. !n:B. P n ==> norm(f n x - l n) < e) net) /\
+        &0 < b /\ eventually (\x. !n. P n ==> b <= norm(l n)) net
+        ==> !e. &0 < e
+                ==> eventually
+                    (\x. !n. P n ==> norm(inv(f n x) - inv(l n)) < e) net`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EVENTUALLY_MONO THEN
+  EXISTS_TAC
+   `\x. !n. P n ==> b <= norm(l n) /\
+                    b / &2 <= norm((f:B->A->complex) n x) /\
+                    norm(f n x - l n) < e * b pow 2 / &2` THEN
+  REWRITE_TAC[TAUT `(p ==> q /\ r) <=> (p ==> q) /\ (p ==> r)`] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN CONJ_TAC THENL
+   [X_GEN_TAC `x:A` THEN STRIP_TAC THEN X_GEN_TAC `n:B` THEN DISCH_TAC THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `n:B`) THEN ASM_REWRITE_TAC[]) THEN
+    REPEAT DISCH_TAC THEN
+    SUBGOAL_THEN `~((f:B->A->complex) n x = Cx(&0)) /\ ~(l n = Cx(&0))`
+    STRIP_ASSUME_TAC THENL
+     [CONJ_TAC THEN DISCH_THEN SUBST_ALL_TAC THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[COMPLEX_NORM_CX]) THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[COMPLEX_FIELD
+     `~(x = Cx(&0)) /\ ~(y = Cx(&0))
+      ==> inv x - inv y = (y - x) / (x * y)`] THEN
+    ASM_SIMP_TAC[COMPLEX_NORM_DIV; REAL_LT_LDIV_EQ; COMPLEX_NORM_NZ;
+                 COMPLEX_ENTIRE] THEN
+    ONCE_REWRITE_TAC[NORM_SUB] 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_ARITH `b pow 2 / &2 = b / &2 * b`] THEN
+    REWRITE_TAC[COMPLEX_NORM_MUL] THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+    ASM_REAL_ARITH_TAC;
+    ASM_REWRITE_TAC[EVENTUALLY_AND] THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `b / &2`) THEN
+      ASM_REWRITE_TAC[REAL_HALF] THEN
+      FIRST_X_ASSUM(fun th -> MP_TAC th THEN REWRITE_TAC[IMP_IMP] THEN
+        GEN_REWRITE_TAC LAND_CONV [GSYM EVENTUALLY_AND]) THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+      REWRITE_TAC[] THEN
+      ASM_MESON_TAC[NORM_ARITH
+       `b <= norm l /\ norm(f - l) < b / &2 ==> b / &2 <= norm f`];
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_SIMP_TAC[REAL_HALF; REAL_POW_LT; REAL_LT_MUL]]]);;
+
+let UNIFORM_LIM_COMPLEX_DIV = prove
+ (`!net:(A)net P f g l m b1 b2.
+        eventually (\x. !n. P n ==> norm(l n) <= b1) net /\
+        &0 < b2 /\ eventually (\x. !n. P n ==> b2 <= norm(m n)) 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(f n x / g n x - l n / m n) < e)
+                     net`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  REWRITE_TAC[complex_div] THEN MATCH_MP_TAC UNIFORM_LIM_COMPLEX_MUL THEN
+  MAP_EVERY EXISTS_TAC [`b1:real`; `inv(b2):real`] THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM(CONJUNCTS_THEN2 ASSUME_TAC
+     (MP_TAC o CONJUNCT1) o CONJUNCT2) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+    GEN_TAC THEN REWRITE_TAC[] THEN MATCH_MP_TAC MONO_FORALL THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[COMPLEX_NORM_INV] THEN
+    MATCH_MP_TAC REAL_LE_INV2 THEN ASM_SIMP_TAC[];
+    MATCH_MP_TAC UNIFORM_LIM_COMPLEX_INV THEN
+    EXISTS_TAC `b2:real` THEN ASM_REWRITE_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The usual non-uniform versions.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_COMPLEX_MUL = prove
+ (`!net:(A)net f g l m.
+         (f --> l) net /\ (g --> m) net ==> ((\x. f x * g x) --> l * m) net`,
+  SIMP_TAC[LIM_BILINEAR; BILINEAR_COMPLEX_MUL]);;
+
+let LIM_COMPLEX_INV = prove
+ (`!net:(A)net f g l m.
+         (f --> l) net /\ ~(l = Cx(&0)) ==> ((\x. inv(f x)) --> inv(l)) net`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`net:(A)net`; `\x:one. T`;
+    `\n:one. (f:A->complex)`;
+    `\n:one. (l:complex)`;
+    `norm(l:complex)`] UNIFORM_LIM_COMPLEX_INV) THEN
+  ASM_REWRITE_TAC[REAL_LE_REFL; EVENTUALLY_TRUE] THEN
+  ASM_REWRITE_TAC[GSYM dist; GSYM tendsto; COMPLEX_NORM_NZ]);;
+
+let LIM_COMPLEX_DIV = prove
+ (`!net:(A)net f g l m.
+         (f --> l) net /\ (g --> m) net /\ ~(m = Cx(&0))
+         ==> ((\x. f x / g x) --> l / m) net`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[complex_div] THEN
+  MATCH_MP_TAC LIM_COMPLEX_MUL THEN ASM_SIMP_TAC[LIM_COMPLEX_INV]);;
+
+let LIM_COMPLEX_POW = prove
+ (`!net:(A)net f l n.
+         (f --> l) net ==> ((\x. f(x) pow n) --> l pow n) net`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN DISCH_TAC THEN
+  INDUCT_TAC THEN ASM_SIMP_TAC[LIM_COMPLEX_MUL; complex_pow; LIM_CONST]);;
+
+let LIM_COMPLEX_LMUL = prove
+ (`!f l c. (f --> l) net ==> ((\x. c * f x) --> c * l) net`,
+  SIMP_TAC[LIM_COMPLEX_MUL; LIM_CONST]);;
+
+let LIM_COMPLEX_RMUL = prove
+ (`!f l c. (f --> l) net ==> ((\x. f x * c) --> l * c) net`,
+  SIMP_TAC[LIM_COMPLEX_MUL; LIM_CONST]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Special cases of null limits.                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_NULL_COMPLEX_NEG = prove
+ (`!net f. (f --> Cx(&0)) net ==> ((\x. --(f x)) --> Cx(&0)) net`,
+  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP LIM_NEG) THEN
+  REWRITE_TAC[COMPLEX_NEG_0]);;
+
+let LIM_NULL_COMPLEX_ADD = prove
+ (`!net f g. (f --> Cx(&0)) net /\ (g --> Cx(&0)) net
+             ==> ((\x. f x + g x) --> Cx(&0)) net`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LIM_ADD) THEN
+  REWRITE_TAC[COMPLEX_ADD_LID]);;
+
+let LIM_NULL_COMPLEX_SUB = prove
+ (`!net f g. (f --> Cx(&0)) net /\ (g --> Cx(&0)) net
+             ==> ((\x. f x - g x) --> Cx(&0)) net`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LIM_SUB) THEN
+  REWRITE_TAC[COMPLEX_SUB_REFL]);;
+
+let LIM_NULL_COMPLEX_MUL = prove
+ (`!net f g. (f --> Cx(&0)) net /\ (g --> Cx(&0)) net
+             ==> ((\x. f x * g x) --> Cx(&0)) net`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LIM_COMPLEX_MUL) THEN
+  REWRITE_TAC[COMPLEX_MUL_LZERO]);;
+
+let LIM_NULL_COMPLEX_LMUL = prove
+ (`!net f c. (f --> Cx(&0)) net ==> ((\x. c * f x) --> Cx(&0)) net`,
+  REPEAT STRIP_TAC THEN SUBST1_TAC(COMPLEX_RING `Cx(&0) = c * Cx(&0)`) THEN
+  ASM_SIMP_TAC[LIM_COMPLEX_LMUL]);;
+
+let LIM_NULL_COMPLEX_RMUL = prove
+ (`!net f c. (f --> Cx(&0)) net ==> ((\x. f x * c) --> Cx(&0)) net`,
+  REPEAT STRIP_TAC THEN SUBST1_TAC(COMPLEX_RING `Cx(&0) = Cx(&0) * c`) THEN
+  ASM_SIMP_TAC[LIM_COMPLEX_RMUL]);;
+
+let LIM_NULL_COMPLEX_POW = prove
+ (`!net f n. (f --> Cx(&0)) net /\ ~(n = 0)
+             ==> ((\x. (f x) pow n) --> Cx(&0)) net`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `n:num` o MATCH_MP LIM_COMPLEX_POW) THEN
+  ASM_REWRITE_TAC[COMPLEX_POW_ZERO]);;
+
+let LIM_NULL_COMPLEX_BOUND = prove
+ (`!f g. eventually (\n. norm (f n) <= norm (g n)) net /\ (g --> Cx(&0)) net
+         ==> (f --> Cx(&0)) net`,
+  REWRITE_TAC[GSYM COMPLEX_VEC_0; LIM_TRANSFORM_BOUND]);;
+
+let SUMS_COMPLEX_0 = prove
+ (`!f s. (!n. n IN s ==> f n = Cx(&0)) ==> (f sums Cx(&0)) s`,
+  REWRITE_TAC[GSYM COMPLEX_VEC_0; SUMS_0]);;
+
+let LIM_NULL_COMPLEX_RMUL_BOUNDED = prove
+ (`!f g. (f --> Cx(&0)) net /\
+         eventually (\a. f a = Cx(&0) \/ norm(g a) <= B) net
+         ==> ((\z. f(z) * g(z)) --> Cx(&0)) net`,
+  REWRITE_TAC[GSYM COMPLEX_VEC_0] THEN
+  ONCE_REWRITE_TAC[LIM_NULL_NORM] THEN
+  REWRITE_TAC[LIFT_CMUL; COMPLEX_NORM_MUL] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC LIM_NULL_VMUL_BOUNDED THEN
+  EXISTS_TAC `B:real` THEN
+  ASM_REWRITE_TAC[o_DEF; NORM_LIFT; REAL_ABS_NORM; NORM_EQ_0]);;
+
+let LIM_NULL_COMPLEX_LMUL_BOUNDED = prove
+ (`!f g. eventually (\a. norm(f a) <= B \/ g a = Cx(&0)) net /\
+         (g --> Cx(&0)) net
+         ==> ((\z. f(z) * g(z)) --> Cx(&0)) net`,
+  ONCE_REWRITE_TAC[DISJ_SYM; COMPLEX_MUL_SYM] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC LIM_NULL_COMPLEX_RMUL_BOUNDED THEN ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Bound results for real and imaginary components of limits.                *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_RE_UBOUND = prove
+ (`!net:(A)net f l b.
+        ~(trivial_limit net) /\ (f --> l) net /\
+        eventually (\x. Re(f x) <= b) net
+        ==> Re(l) <= b`,
+  REWRITE_TAC[RE_DEF] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`net:(A)net`; `f:A->complex`; `l:complex`; `b:real`; `1`]
+                LIM_COMPONENT_UBOUND) THEN
+  ASM_REWRITE_TAC[DIMINDEX_2; ARITH]);;
+
+let LIM_RE_LBOUND = prove
+ (`!net:(A)net f l b.
+        ~(trivial_limit net) /\ (f --> l) net /\
+        eventually (\x. b <= Re(f x)) net
+        ==> b <= Re(l)`,
+  REWRITE_TAC[RE_DEF] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`net:(A)net`; `f:A->complex`; `l:complex`; `b:real`; `1`]
+                LIM_COMPONENT_LBOUND) THEN
+  ASM_REWRITE_TAC[DIMINDEX_2; ARITH]);;
+
+let LIM_IM_UBOUND = prove
+ (`!net:(A)net f l b.
+        ~(trivial_limit net) /\ (f --> l) net /\
+        eventually (\x. Im(f x) <= b) net
+        ==> Im(l) <= b`,
+  REWRITE_TAC[IM_DEF] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`net:(A)net`; `f:A->complex`; `l:complex`; `b:real`; `2`]
+                LIM_COMPONENT_UBOUND) THEN
+  ASM_REWRITE_TAC[DIMINDEX_2; ARITH]);;
+
+let LIM_IM_LBOUND = prove
+ (`!net:(A)net f l b.
+        ~(trivial_limit net) /\ (f --> l) net /\
+        eventually (\x. b <= Im(f x)) net
+        ==> b <= Im(l)`,
+  REWRITE_TAC[IM_DEF] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`net:(A)net`; `f:A->complex`; `l:complex`; `b:real`; `2`]
+                LIM_COMPONENT_LBOUND) THEN
+  ASM_REWRITE_TAC[DIMINDEX_2; ARITH]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Left and right multiplication of series.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let SERIES_COMPLEX_LMUL = prove
+ (`!f l c s. (f sums l) s ==> ((\x. c * f x) sums c * l) s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SERIES_LINEAR THEN
+  ASM_REWRITE_TAC[] THEN GEN_REWRITE_TAC RAND_CONV [GSYM ETA_AX] THEN
+  REWRITE_TAC[LINEAR_COMPLEX_MUL]);;
+
+let SERIES_COMPLEX_RMUL = prove
+ (`!f l c s. (f sums l) s ==> ((\x. f x * c) sums l * c) s`,
+  ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN REWRITE_TAC[SERIES_COMPLEX_LMUL]);;
+
+let SERIES_COMPLEX_DIV = prove
+ (`!f l c s. (f sums l) s ==> ((\x. f x / c) sums (l / c)) s`,
+  REWRITE_TAC[complex_div; SERIES_COMPLEX_RMUL]);;
+
+let SUMMABLE_COMPLEX_LMUL = prove
+ (`!f c s. summable s f ==> summable s (\x. c * f x)`,
+  REWRITE_TAC[summable] THEN MESON_TAC[SERIES_COMPLEX_LMUL]);;
+
+let SUMMABLE_COMPLEX_RMUL = prove
+ (`!f c s. summable s f ==> summable s (\x. f x * c)`,
+  REWRITE_TAC[summable] THEN MESON_TAC[SERIES_COMPLEX_RMUL]);;
+
+let SUMMABLE_COMPLEX_DIV = prove
+ (`!f c s. summable s f ==> summable s (\x. f x / c)`,
+  REWRITE_TAC[summable] THEN MESON_TAC[SERIES_COMPLEX_DIV]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex-specific continuity closures.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_COMPLEX_MUL = prove
+ (`!net f g.
+    f continuous net /\ g continuous net ==> (\x. f(x) * g(x)) continuous net`,
+  SIMP_TAC[continuous; LIM_COMPLEX_MUL]);;
+
+let CONTINUOUS_COMPLEX_INV = prove
+ (`!net f.
+    f continuous net /\ ~(f(netlimit net) = Cx(&0))
+    ==> (\x. inv(f x)) continuous net`,
+  SIMP_TAC[continuous; LIM_COMPLEX_INV]);;
+
+let CONTINUOUS_COMPLEX_DIV = prove
+ (`!net f g.
+    f continuous net /\ g continuous net /\ ~(g(netlimit net) = Cx(&0))
+    ==> (\x. f(x) / g(x)) continuous net`,
+  SIMP_TAC[continuous; LIM_COMPLEX_DIV]);;
+
+let CONTINUOUS_COMPLEX_POW = prove
+ (`!net f n. f continuous net ==> (\x. f(x) pow n) continuous net`,
+  SIMP_TAC[continuous; LIM_COMPLEX_POW]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Write away the netlimit, which is otherwise a bit tedious.                *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_COMPLEX_INV_WITHIN = prove
+ (`!f s a.
+    f continuous (at a within s) /\ ~(f a = Cx(&0))
+    ==> (\x. inv(f x)) continuous (at a within s)`,
+  MESON_TAC[CONTINUOUS_COMPLEX_INV; CONTINUOUS_TRIVIAL_LIMIT;
+            NETLIMIT_WITHIN]);;
+
+let CONTINUOUS_COMPLEX_INV_AT = prove
+ (`!f a.
+    f continuous (at a) /\ ~(f a = Cx(&0))
+    ==> (\x. inv(f x)) continuous (at a)`,
+  SIMP_TAC[CONTINUOUS_COMPLEX_INV; NETLIMIT_AT]);;
+
+let CONTINUOUS_COMPLEX_DIV_WITHIN = prove
+ (`!f g s a.
+    f continuous (at a within s) /\ g continuous (at a within s) /\
+    ~(g a = Cx(&0))
+    ==> (\x. f x / g x) continuous (at a within s)`,
+  MESON_TAC[CONTINUOUS_COMPLEX_DIV; CONTINUOUS_TRIVIAL_LIMIT;
+            NETLIMIT_WITHIN]);;
+
+let CONTINUOUS_COMPLEX_DIV_AT = prove
+ (`!f g a.
+    f continuous at a /\ g continuous at a /\ ~(g a = Cx(&0))
+    ==> (\x. f x / g x) continuous at a`,
+  SIMP_TAC[CONTINUOUS_COMPLEX_DIV; NETLIMIT_AT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Also prove "on" variants as needed.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_ON_COMPLEX_MUL = prove
+ (`!f g s. f continuous_on s /\ g continuous_on s
+           ==> (\x. f(x) * g(x)) continuous_on s`,
+  REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  SIMP_TAC[CONTINUOUS_COMPLEX_MUL]);;
+
+let CONTINUOUS_ON_COMPLEX_LMUL = prove
+ (`!f:real^N->complex s. f continuous_on s ==> (\x. c * f(x)) continuous_on s`,
+  REWRITE_TAC[CONTINUOUS_ON] THEN SIMP_TAC[LIM_COMPLEX_MUL; LIM_CONST]);;
+
+let CONTINUOUS_ON_COMPLEX_RMUL = prove
+ (`!f:real^N->complex s. f continuous_on s ==> (\x. f(x) * c) continuous_on s`,
+  REWRITE_TAC[CONTINUOUS_ON] THEN SIMP_TAC[LIM_COMPLEX_MUL; LIM_CONST]);;
+
+let CONTINUOUS_ON_COMPLEX_INV = prove
+ (`!f:real^N->complex.
+        f continuous_on s /\
+        (!x. x IN s ==> ~(f x = Cx(&0)))
+        ==> (\x. inv(f x)) continuous_on s`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+           CONTINUOUS_COMPLEX_INV_WITHIN]);;
+
+let CONTINUOUS_ON_COMPLEX_DIV = prove
+ (`!f g s. f continuous_on s /\ g continuous_on s /\
+           (!x. x IN s ==> ~(g x = Cx(&0)))
+           ==> (\x. f(x) / g(x)) continuous_on s`,
+  REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  SIMP_TAC[CONTINUOUS_COMPLEX_DIV_WITHIN]);;
+
+let CONTINUOUS_ON_COMPLEX_POW = prove
+ (`!f n s. f continuous_on s ==> (\x. f(x) pow n) continuous_on s`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_COMPLEX_POW]);;
+
+(* ------------------------------------------------------------------------- *)
+(* And also uniform versions.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let UNIFORMLY_CONTINUOUS_ON_COMPLEX_MUL = prove
+ (`!f g s:real^N->bool.
+        f uniformly_continuous_on s /\ g uniformly_continuous_on s /\
+        bounded(IMAGE f s) /\ bounded(IMAGE g s)
+        ==> (\x. f(x) * g(x)) uniformly_continuous_on s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`f:real^N->complex`; `g:real^N->complex`;
+    `( * ):complex->complex->complex`; `s:real^N->bool`]
+    BILINEAR_UNIFORMLY_CONTINUOUS_ON_COMPOSE) THEN
+  ASM_REWRITE_TAC[BILINEAR_COMPLEX_MUL]);;
+
+let UNIFORMLY_CONTINUOUS_ON_COMPLEX_LMUL = prove
+ (`!f c s:real^N->bool.
+      f uniformly_continuous_on s ==> (\x. c * f x) uniformly_continuous_on s`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o ISPEC `\x:complex. c * x` o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] UNIFORMLY_CONTINUOUS_ON_COMPOSE)) THEN
+  ASM_SIMP_TAC[o_DEF; LINEAR_COMPLEX_MUL; LINEAR_UNIFORMLY_CONTINUOUS_ON]);;
+
+let UNIFORMLY_CONTINUOUS_ON_COMPLEX_RMUL = prove
+ (`!f c s:real^N->bool.
+      f uniformly_continuous_on s ==> (\x. f x * c) uniformly_continuous_on s`,
+  ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+  REWRITE_TAC[UNIFORMLY_CONTINUOUS_ON_COMPLEX_LMUL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Continuity prover (not just for complex numbers but with more for them).  *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_TAC =
+  let ETA_THM = prove
+   (`f continuous net <=> (\x. f x) continuous net`,
+    REWRITE_TAC[ETA_AX]) in
+  let ETA_TWEAK =
+    GEN_REWRITE_RULE (LAND_CONV o ONCE_DEPTH_CONV) [ETA_THM] o SPEC_ALL in
+  let tac_base =
+    MATCH_ACCEPT_TAC CONTINUOUS_CONST ORELSE
+    MATCH_ACCEPT_TAC CONTINUOUS_AT_ID ORELSE
+    MATCH_ACCEPT_TAC CONTINUOUS_WITHIN_ID
+  and tac_1 =
+    MATCH_MP_TAC(ETA_TWEAK CONTINUOUS_CMUL) ORELSE
+    MATCH_MP_TAC(ETA_TWEAK CONTINUOUS_NEG) ORELSE
+    MATCH_MP_TAC(ETA_TWEAK CONTINUOUS_COMPLEX_POW)
+  and tac_2 =
+    MATCH_MP_TAC(ETA_TWEAK CONTINUOUS_ADD) ORELSE
+    MATCH_MP_TAC(ETA_TWEAK CONTINUOUS_SUB) ORELSE
+    MATCH_MP_TAC(ETA_TWEAK CONTINUOUS_COMPLEX_MUL)
+  and tac_1' = MATCH_MP_TAC (ETA_TWEAK CONTINUOUS_COMPLEX_INV)
+  and tac_2' = MATCH_MP_TAC (ETA_TWEAK CONTINUOUS_COMPLEX_DIV) in
+  let rec CONTINUOUS_TAC gl =
+   (tac_base ORELSE
+    (tac_1 THEN CONTINUOUS_TAC) ORELSE
+    (tac_2 THEN CONJ_TAC THEN CONTINUOUS_TAC) ORELSE
+    (tac_1' THEN CONJ_TAC THENL
+     [CONTINUOUS_TAC; REWRITE_TAC[NETLIMIT_AT; NETLIMIT_WITHIN]]) ORELSE
+    (tac_2' THEN REPEAT CONJ_TAC THENL
+     [CONTINUOUS_TAC; CONTINUOUS_TAC;
+      REWRITE_TAC[NETLIMIT_AT; NETLIMIT_WITHIN]]) ORELSE
+    ALL_TAC) gl in
+  CONTINUOUS_TAC;;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence a limit calculator                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_CONTINUOUS = prove
+ (`!net f l. f continuous net /\ f(netlimit net) = l ==> (f --> l) net`,
+  MESON_TAC[continuous]);;
+
+let LIM_TAC =
+  MATCH_MP_TAC LIM_CONTINUOUS THEN CONJ_TAC THENL
+   [CONTINUOUS_TAC; REWRITE_TAC[NETLIMIT_AT; NETLIMIT_WITHIN]];;
+
+(* ------------------------------------------------------------------------- *)
+(* Continuity of the norm.                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_AT_CX_NORM = prove
+ (`!z:real^N. (\z. Cx(norm z)) continuous at z`,
+  REWRITE_TAC[continuous_at; dist; GSYM CX_SUB; COMPLEX_NORM_CX] THEN
+  MESON_TAC[NORM_ARITH `norm(a - b:real^N) < d ==> abs(norm a - norm b) < d`]);;
+
+let CONTINUOUS_WITHIN_CX_NORM = prove
+ (`!z:real^N s. (\z. Cx(norm z)) continuous (at z within s)`,
+  SIMP_TAC[CONTINUOUS_AT_CX_NORM; CONTINUOUS_AT_WITHIN]);;
+
+let CONTINUOUS_ON_CX_NORM = prove
+ (`!s. (\z. Cx(norm z)) continuous_on s`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_WITHIN_CX_NORM]);;
+
+let CONTINUOUS_AT_CX_DOT = prove
+ (`!c z:real^N. (\z. Cx(c dot z)) continuous at z`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_AT THEN
+  REWRITE_TAC[linear; DOT_RADD; DOT_RMUL; CX_ADD; COMPLEX_CMUL; CX_MUL]);;
+
+let CONTINUOUS_WITHIN_CX_DOT = prove
+ (`!c z:real^N s. (\z. Cx(c dot z)) continuous (at z within s)`,
+  SIMP_TAC[CONTINUOUS_AT_CX_DOT; CONTINUOUS_AT_WITHIN]);;
+
+let CONTINUOUS_ON_CX_DOT = prove
+ (`!s c:real^N. (\z. Cx(c dot z)) continuous_on s`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_WITHIN_CX_DOT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Continuity switching range between complex and real^1                     *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_CX_DROP = prove
+ (`!net f. f continuous net ==> (\x. Cx(drop(f x))) continuous net`,
+  REWRITE_TAC[continuous; tendsto] THEN
+  REWRITE_TAC[dist; GSYM CX_SUB; COMPLEX_NORM_CX; GSYM DROP_SUB] THEN
+  REWRITE_TAC[GSYM ABS_DROP]);;
+
+let CONTINUOUS_ON_CX_DROP = prove
+ (`!f s. f continuous_on s ==> (\x. Cx(drop(f x))) continuous_on s`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_CX_DROP]);;
+
+let CONTINUOUS_CX_LIFT = prove
+ (`!f. (\x. Cx(f x)) continuous net <=> (\x. lift(f x)) continuous net`,
+  REWRITE_TAC[continuous; LIM; dist; GSYM CX_SUB; GSYM LIFT_SUB] THEN
+  REWRITE_TAC[COMPLEX_NORM_CX; NORM_LIFT]);;
+
+let CONTINUOUS_ON_CX_LIFT = prove
+ (`!f s. (\x. Cx(f x)) continuous_on s <=> (\x. lift(f x)) continuous_on s`,
+  REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_CX_LIFT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Linearity and continuity of the components.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_CX_RE = prove
+ (`linear(Cx o Re)`,
+  SIMP_TAC[linear; o_THM; COMPLEX_CMUL; RE_ADD; RE_MUL_CX; CX_MUL; CX_ADD]);;
+
+let CONTINUOUS_AT_CX_RE = prove
+ (`!z. (Cx o Re) continuous at z`,
+  SIMP_TAC[LINEAR_CONTINUOUS_AT; LINEAR_CX_RE]);;
+
+let CONTINUOUS_ON_CX_RE = prove
+ (`!s. (Cx o Re) continuous_on s`,
+  SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_CX_RE]);;
+
+let LINEAR_CX_IM = prove
+ (`linear(Cx o Im)`,
+  SIMP_TAC[linear; o_THM; COMPLEX_CMUL; IM_ADD; IM_MUL_CX; CX_MUL; CX_ADD]);;
+
+let CONTINUOUS_AT_CX_IM = prove
+ (`!z. (Cx o Im) continuous at z`,
+  SIMP_TAC[LINEAR_CONTINUOUS_AT; LINEAR_CX_IM]);;
+
+let CONTINUOUS_ON_CX_IM = prove
+ (`!s. (Cx o Im) continuous_on s`,
+  SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_CX_IM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex differentiability.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix ("has_complex_derivative",(12,"right"));;
+parse_as_infix ("complex_differentiable",(12,"right"));;
+parse_as_infix ("holomorphic_on",(12,"right"));;
+
+let has_complex_derivative = new_definition
+ `(f has_complex_derivative f') net <=> (f has_derivative (\x. f' * x)) net`;;
+
+let complex_differentiable = new_definition
+ `f complex_differentiable net <=> ?f'. (f has_complex_derivative f') net`;;
+
+let complex_derivative = new_definition
+ `complex_derivative f x = @f'. (f has_complex_derivative f') (at x)`;;
+
+let higher_complex_derivative = define
+ `higher_complex_derivative 0 f = f /\
+  (!n. higher_complex_derivative (SUC n) f =
+                complex_derivative (higher_complex_derivative n f))`;;
+
+let holomorphic_on = new_definition
+ `f holomorphic_on s <=>
+     !x. x IN s ==> ?f'. (f has_complex_derivative f') (at x within s)`;;
+
+let HOLOMORPHIC_ON_DIFFERENTIABLE = prove
+ (`!f s. f holomorphic_on s <=>
+         !x. x IN s ==> f complex_differentiable (at x within s)`,
+  REWRITE_TAC[holomorphic_on; complex_differentiable]);;
+
+let HOLOMORPHIC_ON_OPEN = prove
+ (`!f s. open s
+         ==> (f holomorphic_on s <=>
+              !x. x IN s ==> ?f'. (f has_complex_derivative f') (at x))`,
+  REWRITE_TAC[holomorphic_on; has_complex_derivative] THEN
+  REWRITE_TAC[has_derivative_at; has_derivative_within] THEN
+  SIMP_TAC[LIM_WITHIN_OPEN]);;
+
+let HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_WITHIN = prove
+ (`!f s x. f holomorphic_on s /\ x IN s
+           ==> f complex_differentiable (at x within s)`,
+  MESON_TAC[HOLOMORPHIC_ON_DIFFERENTIABLE]);;
+
+let HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT = prove
+ (`!f s x. f holomorphic_on s /\ open s /\ x IN s
+           ==> f complex_differentiable (at x)`,
+  MESON_TAC[HOLOMORPHIC_ON_OPEN; complex_differentiable]);;
+
+let HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT = prove
+ (`!f f' x. (f has_complex_derivative f') (at x) ==> f continuous at x`,
+  REWRITE_TAC[has_complex_derivative] THEN
+  MESON_TAC[differentiable; DIFFERENTIABLE_IMP_CONTINUOUS_AT]);;
+
+let HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_WITHIN = prove
+ (`!f f' x s. (f has_complex_derivative f') (at x within s)
+              ==> f continuous (at x within s)`,
+  REWRITE_TAC[has_complex_derivative] THEN
+  MESON_TAC[differentiable; DIFFERENTIABLE_IMP_CONTINUOUS_WITHIN]);;
+
+let COMPLEX_DIFFERENTIABLE_IMP_CONTINUOUS_AT = prove
+ (`!f x. f complex_differentiable at x ==> f continuous at x`,
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT; complex_differentiable]);;
+
+let HOLOMORPHIC_ON_IMP_CONTINUOUS_ON = prove
+ (`!f s. f holomorphic_on s ==> f continuous_on s`,
+  REWRITE_TAC[holomorphic_on; CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  REWRITE_TAC[has_complex_derivative] THEN
+  MESON_TAC[DIFFERENTIABLE_IMP_CONTINUOUS_WITHIN; differentiable]);;
+
+let HOLOMORPHIC_ON_SUBSET = prove
+ (`!f s t. f holomorphic_on s /\ t SUBSET s ==> f holomorphic_on t`,
+  REWRITE_TAC[holomorphic_on; has_complex_derivative] THEN
+  MESON_TAC[SUBSET; HAS_DERIVATIVE_WITHIN_SUBSET]);;
+
+let HAS_COMPLEX_DERIVATIVE_WITHIN_SUBSET = prove
+ (`!f s t x. (f has_complex_derivative f') (at x within s) /\ t SUBSET s
+             ==> (f has_complex_derivative f') (at x within t)`,
+  REWRITE_TAC[has_complex_derivative; HAS_DERIVATIVE_WITHIN_SUBSET]);;
+
+let COMPLEX_DIFFERENTIABLE_WITHIN_SUBSET = prove
+ (`!f s t. f complex_differentiable (at x within s) /\ t SUBSET s
+           ==> f complex_differentiable (at x within t)`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN_SUBSET]);;
+
+let HAS_COMPLEX_DERIVATIVE_AT_WITHIN = prove
+ (`!f f' x s. (f has_complex_derivative f') (at x)
+              ==> (f has_complex_derivative f') (at x within s)`,
+  REWRITE_TAC[has_complex_derivative; HAS_DERIVATIVE_AT_WITHIN]);;
+
+let HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN = prove
+ (`!f f' a s.
+         a IN s /\ open s
+         ==> ((f has_complex_derivative f') (at a within s) <=>
+              (f has_complex_derivative f') (at a))`,
+  REWRITE_TAC[has_complex_derivative; HAS_DERIVATIVE_WITHIN_OPEN]);;
+
+let COMPLEX_DIFFERENTIABLE_AT_WITHIN = prove
+ (`!f s z. f complex_differentiable (at z)
+           ==> f complex_differentiable (at z within s)`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN]);;
+
+let HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN = prove
+ (`!f f' g x s d.
+       &0 < d /\ x IN s /\
+       (!x'. x' IN s /\ dist (x',x) < d ==> f x' = g x') /\
+       (f has_complex_derivative f') (at x within s)
+       ==> (g has_complex_derivative f') (at x within s)`,
+  REWRITE_TAC[has_complex_derivative] THEN
+  MESON_TAC[HAS_DERIVATIVE_TRANSFORM_WITHIN]);;
+
+let HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN = prove
+  (`!f g f' s z. open s /\ z IN s /\ (!w. w IN s ==> f w = g w) /\
+                 (f has_complex_derivative f') (at z)
+                 ==> (g has_complex_derivative f') (at z)`,
+   REWRITE_TAC [has_complex_derivative] THEN
+   ASM_MESON_TAC [HAS_DERIVATIVE_TRANSFORM_WITHIN_OPEN]);;
+
+let HAS_COMPLEX_DERIVATIVE_TRANSFORM_AT = prove
+ (`!f f' g x d.
+       &0 < d /\ (!x'. dist (x',x) < d ==> f x' = g x') /\
+       (f has_complex_derivative f') (at x)
+       ==> (g has_complex_derivative f') (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN; IN_UNIV]);;
+
+let HAS_COMPLEX_DERIVATIVE_ZERO_CONSTANT = prove
+ (`!f s.
+        convex s /\
+        (!x. x IN s ==> (f has_complex_derivative Cx(&0)) (at x within s))
+        ==> ?c. !x. x IN s ==> f(x) = c`,
+  REWRITE_TAC[has_complex_derivative; COMPLEX_MUL_LZERO] THEN
+  REWRITE_TAC[GSYM COMPLEX_VEC_0; HAS_DERIVATIVE_ZERO_CONSTANT]);;
+
+let HAS_COMPLEX_DERIVATIVE_ZERO_UNIQUE = prove
+ (`!f s c a.
+        convex s /\ a IN s /\ f a = c /\
+        (!x. x IN s ==> (f has_complex_derivative Cx(&0)) (at x within s))
+        ==> !x. x IN s ==> f(x) = c`,
+  REWRITE_TAC[has_complex_derivative; COMPLEX_MUL_LZERO] THEN
+  REWRITE_TAC[GSYM COMPLEX_VEC_0; HAS_DERIVATIVE_ZERO_UNIQUE]);;
+
+let HAS_COMPLEX_DERIVATIVE_ZERO_CONNECTED_CONSTANT = prove
+ (`!f s.
+        open s /\ connected s /\
+        (!x. x IN s ==> (f has_complex_derivative Cx(&0)) (at x))
+        ==> ?c. !x. x IN s ==> f(x) = c`,
+  REWRITE_TAC[has_complex_derivative; COMPLEX_MUL_LZERO] THEN
+  REWRITE_TAC[GSYM COMPLEX_VEC_0; HAS_DERIVATIVE_ZERO_CONNECTED_CONSTANT]);;
+
+let HAS_COMPLEX_DERIVATIVE_ZERO_CONNECTED_UNIQUE = prove
+ (`!f s c a.
+        open s /\ connected s /\ a IN s /\ f a = c /\
+        (!x. x IN s ==> (f has_complex_derivative Cx(&0)) (at x))
+        ==> !x. x IN s ==> f(x) = c`,
+  REWRITE_TAC[has_complex_derivative; COMPLEX_MUL_LZERO] THEN
+  REWRITE_TAC[GSYM COMPLEX_VEC_0; HAS_DERIVATIVE_ZERO_CONNECTED_UNIQUE]);;
+
+let COMPLEX_DIFF_CHAIN_WITHIN = prove
+ (`!f g f' g' x s.
+        (f has_complex_derivative f') (at x within s) /\
+        (g has_complex_derivative g') (at (f x) within (IMAGE f s))
+        ==> ((g o f) has_complex_derivative (g' * f'))(at x within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_complex_derivative] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP DIFF_CHAIN_WITHIN) THEN
+  REWRITE_TAC[o_DEF; COMPLEX_MUL_ASSOC]);;
+
+let COMPLEX_DIFF_CHAIN_AT = prove
+ (`!f g f' g' x.
+        (f has_complex_derivative f') (at x) /\
+        (g has_complex_derivative g') (at (f x))
+        ==> ((g o f) has_complex_derivative (g' * f')) (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  ASM_MESON_TAC[COMPLEX_DIFF_CHAIN_WITHIN; SUBSET_UNIV;
+                HAS_COMPLEX_DERIVATIVE_WITHIN_SUBSET]);;
+
+let HAS_COMPLEX_DERIVATIVE_CHAIN = prove
+ (`!P f g.
+        (!x. P x ==> (g has_complex_derivative g'(x)) (at x))
+        ==> (!x s. (f has_complex_derivative f') (at x within s) /\ P(f x)
+                   ==> ((\x. g(f x)) has_complex_derivative f' * g'(f x))
+                       (at x within s)) /\
+            (!x. (f has_complex_derivative f') (at x) /\ P(f x)
+                 ==> ((\x. g(f x)) has_complex_derivative f' * g'(f x))
+                     (at x))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM o_DEF] THEN
+  ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+  ASM_MESON_TAC[COMPLEX_DIFF_CHAIN_WITHIN; COMPLEX_DIFF_CHAIN_AT;
+                HAS_COMPLEX_DERIVATIVE_AT_WITHIN]);;
+
+let HAS_COMPLEX_DERIVATIVE_CHAIN_UNIV = prove
+ (`!f g. (!x. (g has_complex_derivative g'(x)) (at x))
+         ==> (!x s. (f has_complex_derivative f') (at x within s)
+                    ==> ((\x. g(f x)) has_complex_derivative f' * g'(f x))
+                        (at x within s)) /\
+             (!x. (f has_complex_derivative f') (at x)
+                  ==> ((\x. g(f x)) has_complex_derivative f' * g'(f x))
+                      (at x))`,
+  MP_TAC(SPEC `\x:complex. T` HAS_COMPLEX_DERIVATIVE_CHAIN) THEN SIMP_TAC[]);;
+
+let COMPLEX_DERIVATIVE_UNIQUE_AT = prove
+ (`!f z f' f''.
+        (f has_complex_derivative f') (at z) /\
+        (f has_complex_derivative f'') (at z)
+        ==> f' = f''`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_complex_derivative] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP FRECHET_DERIVATIVE_UNIQUE_AT) THEN
+  DISCH_THEN(MP_TAC o C AP_THM `Cx(&1)`) THEN
+  REWRITE_TAC[COMPLEX_MUL_RID]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_1 = prove
+ (`!f z. higher_complex_derivative 1 f z = complex_derivative f z`,
+  REWRITE_TAC[num_CONV `1`; higher_complex_derivative]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A more direct characterization.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_COMPLEX_DERIVATIVE_WITHIN = prove
+ (`!f s a. (f has_complex_derivative f') (at a within s) <=>
+           ((\x. (f(x) - f(a)) / (x - a)) --> f') (at a within s)`,
+  REWRITE_TAC[has_complex_derivative; has_derivative_within] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[LINEAR_COMPLEX_MUL] THEN
+  GEN_REWRITE_TAC RAND_CONV [LIM_NULL] THEN
+  REWRITE_TAC[LIM_WITHIN; dist; VECTOR_SUB_RZERO; NORM_MUL] THEN
+  REWRITE_TAC[NORM_POS_LT; VECTOR_SUB_EQ] THEN SIMP_TAC[COMPLEX_FIELD
+  `~(x:complex = a) ==> y / (x - a) - z = inv(x - a) * (y - z * (x - a))`] THEN
+  REWRITE_TAC[REAL_ABS_INV; COMPLEX_NORM_MUL; REAL_ABS_NORM;
+         COMPLEX_NORM_INV; VECTOR_ARITH `a:complex - (b + c) = a - b - c`]);;
+
+let HAS_COMPLEX_DERIVATIVE_AT = prove
+ (`!f a. (f has_complex_derivative f') (at a) <=>
+         ((\x. (f(x) - f(a)) / (x - a)) --> f') (at a)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Arithmetical combining theorems.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_COMPLEX_CMUL = prove
+ (`!net c. ((\x. c * x) has_derivative (\x. c * x)) net`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_LINEAR THEN
+  REWRITE_TAC[LINEAR_COMPLEX_MUL]);;
+
+let HAS_COMPLEX_DERIVATIVE_LINEAR = prove
+ (`!net c. ((\x. c * x) has_complex_derivative c) net`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_complex_derivative] THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_LINEAR THEN
+  REWRITE_TAC[linear; COMPLEX_CMUL] THEN CONV_TAC COMPLEX_RING);;
+
+let HAS_COMPLEX_DERIVATIVE_LMUL_WITHIN = prove
+ (`!f f' c x s.
+        (f has_complex_derivative f') (at x within s)
+        ==> ((\x. c * f(x)) has_complex_derivative (c * f')) (at x within s)`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`at ((f:complex->complex) x) within (IMAGE f s)`; `c:complex`]
+    HAS_COMPLEX_DERIVATIVE_LINEAR) THEN
+  ONCE_REWRITE_TAC[TAUT `a ==> b ==> c <=> b /\ a ==> c`] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP COMPLEX_DIFF_CHAIN_WITHIN) THEN
+  REWRITE_TAC[o_DEF]);;
+
+let HAS_COMPLEX_DERIVATIVE_LMUL_AT = prove
+ (`!f f' c x.
+        (f has_complex_derivative f') (at x)
+        ==> ((\x. c * f(x)) has_complex_derivative (c * f')) (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_LMUL_WITHIN]);;
+
+let HAS_COMPLEX_DERIVATIVE_RMUL_WITHIN = prove
+ (`!f f' c x s.
+        (f has_complex_derivative f') (at x within s)
+        ==> ((\x. f(x) * c) has_complex_derivative (f' * c)) (at x within s)`,
+  ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+  REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_LMUL_WITHIN]);;
+
+let HAS_COMPLEX_DERIVATIVE_RMUL_AT = prove
+ (`!f f' c x.
+        (f has_complex_derivative f') (at x)
+        ==> ((\x. f(x) * c) has_complex_derivative (f' * c)) (at x)`,
+  ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+  REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_LMUL_AT]);;
+
+let HAS_COMPLEX_DERIVATIVE_CDIV_WITHIN = prove
+ (`!f f' c x s.
+        (f has_complex_derivative f') (at x within s)
+        ==> ((\x. f(x) / c) has_complex_derivative (f' / c)) (at x within s)`,
+  SIMP_TAC[complex_div; HAS_COMPLEX_DERIVATIVE_RMUL_WITHIN]);;
+
+let HAS_COMPLEX_DERIVATIVE_CDIV_AT = prove
+ (`!f f' c x s.
+        (f has_complex_derivative f') (at x)
+        ==> ((\x. f(x) / c) has_complex_derivative (f' / c)) (at x)`,
+  SIMP_TAC[complex_div; HAS_COMPLEX_DERIVATIVE_RMUL_AT]);;
+
+let HAS_COMPLEX_DERIVATIVE_ID = prove
+ (`!net. ((\x. x) has_complex_derivative Cx(&1)) net`,
+  REWRITE_TAC[has_complex_derivative; HAS_DERIVATIVE_ID; COMPLEX_MUL_LID]);;
+
+let HAS_COMPLEX_DERIVATIVE_CONST = prove
+ (`!c net. ((\x. c) has_complex_derivative Cx(&0)) net`,
+  REWRITE_TAC[has_complex_derivative; COMPLEX_MUL_LZERO] THEN
+  REWRITE_TAC[GSYM COMPLEX_VEC_0; HAS_DERIVATIVE_CONST]);;
+
+let HAS_COMPLEX_DERIVATIVE_NEG = prove
+ (`!f f' net. (f has_complex_derivative f') net
+            ==> ((\x. --(f(x))) has_complex_derivative (--f')) net`,
+  SIMP_TAC[has_complex_derivative; COMPLEX_MUL_LNEG; HAS_DERIVATIVE_NEG]);;
+
+let HAS_COMPLEX_DERIVATIVE_ADD = prove
+ (`!f f' g g' net.
+        (f has_complex_derivative f') net /\ (g has_complex_derivative g') net
+        ==> ((\x. f(x) + g(x)) has_complex_derivative (f' + g')) net`,
+  SIMP_TAC[has_complex_derivative; COMPLEX_ADD_RDISTRIB; HAS_DERIVATIVE_ADD]);;
+
+let HAS_COMPLEX_DERIVATIVE_SUB = prove
+ (`!f f' g g' net.
+        (f has_complex_derivative f') net /\ (g has_complex_derivative g') net
+        ==> ((\x. f(x) - g(x)) has_complex_derivative (f' - g')) net`,
+  SIMP_TAC[has_complex_derivative; COMPLEX_SUB_RDISTRIB; HAS_DERIVATIVE_SUB]);;
+
+let HAS_COMPLEX_DERIVATIVE_MUL_WITHIN = prove
+ (`!f f' g g' x s.
+        (f has_complex_derivative f') (at x within s) /\
+        (g has_complex_derivative g') (at x within s)
+        ==> ((\x. f(x) * g(x)) has_complex_derivative
+             (f(x) * g' + f' * g(x))) (at x within s)`,
+  REPEAT GEN_TAC THEN SIMP_TAC[has_complex_derivative] THEN
+  DISCH_THEN(MP_TAC o C CONJ BILINEAR_COMPLEX_MUL) THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_DERIVATIVE_BILINEAR_WITHIN) THEN
+  MATCH_MP_TAC EQ_IMP THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let HAS_COMPLEX_DERIVATIVE_MUL_AT = prove
+ (`!f f' g g' x.
+        (f has_complex_derivative f') (at x) /\
+        (g has_complex_derivative g') (at x)
+        ==> ((\x. f(x) * g(x)) has_complex_derivative
+             (f(x) * g' + f' * g(x))) (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_MUL_WITHIN]);;
+
+let HAS_COMPLEX_DERIVATIVE_POW_WITHIN = prove
+ (`!f f' x s n. (f has_complex_derivative f') (at x within s)
+                ==> ((\x. f(x) pow n) has_complex_derivative
+                     (Cx(&n) * f(x) pow (n - 1) * f')) (at x within s)`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN DISCH_TAC THEN
+  INDUCT_TAC THEN REWRITE_TAC[complex_pow] THEN
+  REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_CONST; COMPLEX_MUL_LZERO] THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_COMPLEX_DERIVATIVE_MUL_WITHIN) THEN
+  REWRITE_TAC[SUC_SUB1] THEN MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN
+  BINOP_TAC THEN REWRITE_TAC[COMPLEX_MUL_AC; GSYM REAL_OF_NUM_SUC] THEN
+  SPEC_TAC(`n:num`,`n:num`) THEN REWRITE_TAC[CX_ADD] THEN INDUCT_TAC THEN
+  CONV_TAC NUM_REDUCE_CONV THEN REWRITE_TAC[SUC_SUB1; complex_pow] THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let HAS_COMPLEX_DERIVATIVE_POW_AT = prove
+ (`!f f' x n. (f has_complex_derivative f') (at x)
+              ==> ((\x. f(x) pow n) has_complex_derivative
+                   (Cx(&n) * f(x) pow (n - 1) * f')) (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_POW_WITHIN]);;
+
+let HAS_COMPLEX_DERIVATIVE_INV_BASIC = prove
+ (`!x. ~(x = Cx(&0))
+         ==> ((inv) has_complex_derivative (--inv(x pow 2))) (at x)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[has_complex_derivative; has_derivative_at] THEN
+  REWRITE_TAC[LINEAR_COMPLEX_MUL; COMPLEX_VEC_0] THEN
+  MATCH_MP_TAC LIM_TRANSFORM_AWAY_AT THEN
+  MAP_EVERY EXISTS_TAC
+   [`\y. inv(norm(y - x)) % inv(x pow 2 * y) * (y - x) pow 2`; `Cx(&0)`] THEN
+  ASM_REWRITE_TAC[COMPLEX_CMUL] THEN CONJ_TAC THENL
+   [POP_ASSUM MP_TAC THEN CONV_TAC COMPLEX_FIELD; ALL_TAC] THEN
+  SUBGOAL_THEN `((\y. inv(x pow 2 * y) * (y - x)) --> Cx(&0)) (at x)`
+  MP_TAC THENL
+   [LIM_TAC THEN POP_ASSUM MP_TAC THEN CONV_TAC COMPLEX_FIELD; ALL_TAC] THEN
+  MATCH_MP_TAC EQ_IMP THEN REWRITE_TAC[LIM_AT] THEN
+  REWRITE_TAC[dist; COMPLEX_SUB_RZERO] THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_INV; COMPLEX_NORM_POW] THEN
+  REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_INV; REAL_ABS_NORM] THEN
+  REPLICATE_TAC 2 (AP_TERM_TAC THEN ABS_TAC THEN AP_TERM_TAC) THEN
+  AP_TERM_TAC THEN ABS_TAC THEN
+  MATCH_MP_TAC(MESON[]
+   `(p ==> x = y) ==> ((p ==> x < e) <=> (p ==> y < e))`) THEN
+  MAP_EVERY ABBREV_TAC
+   [`n = norm(x' - x:complex)`;
+    `m = inv (norm(x:complex) pow 2 * norm(x':complex))`] THEN
+  CONV_TAC REAL_FIELD);;
+
+let HAS_COMPLEX_DERIVATIVE_INV_WITHIN = prove
+ (`!f f' x s. (f has_complex_derivative f') (at x within s) /\
+              ~(f x = Cx(&0))
+              ==> ((\x. inv(f(x))) has_complex_derivative (--f' / f(x) pow 2))
+                  (at x within s)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+  ASM_SIMP_TAC[COMPLEX_FIELD
+   `~(g = Cx(&0)) ==> --f / g pow 2 = --inv(g pow 2) * f`] THEN
+  MATCH_MP_TAC COMPLEX_DIFF_CHAIN_WITHIN THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_AT_WITHIN THEN
+  ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_INV_BASIC]);;
+
+let HAS_COMPLEX_DERIVATIVE_INV_AT = prove
+ (`!f f' x. (f has_complex_derivative f') (at x) /\
+            ~(f x = Cx(&0))
+            ==> ((\x. inv(f(x))) has_complex_derivative (--f' / f(x) pow 2))
+                (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_INV_WITHIN]);;
+
+let HAS_COMPLEX_DERIVATIVE_DIV_WITHIN = prove
+ (`!f f' g g' x s.
+        (f has_complex_derivative f') (at x within s) /\
+        (g has_complex_derivative g') (at x within s) /\
+        ~(g(x) = Cx(&0))
+        ==> ((\x. f(x) / g(x)) has_complex_derivative
+             (f' * g(x) - f(x) * g') / g(x) pow 2) (at x within s)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(fun th -> ASSUME_TAC(CONJUNCT2 th) THEN MP_TAC th) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_COMPLEX_DERIVATIVE_INV_WITHIN) THEN
+  UNDISCH_TAC `(f has_complex_derivative f') (at x within s)` THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_COMPLEX_DERIVATIVE_MUL_WITHIN) THEN
+  REWRITE_TAC[GSYM complex_div] THEN MATCH_MP_TAC EQ_IMP THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN
+  POP_ASSUM MP_TAC THEN CONV_TAC COMPLEX_FIELD);;
+
+let HAS_COMPLEX_DERIVATIVE_DIV_AT = prove
+ (`!f f' g g' x.
+        (f has_complex_derivative f') (at x) /\
+        (g has_complex_derivative g') (at x) /\
+        ~(g(x) = Cx(&0))
+        ==> ((\x. f(x) / g(x)) has_complex_derivative
+             (f' * g(x) - f(x) * g') / g(x) pow 2) (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIV_WITHIN]);;
+
+let HAS_COMPLEX_DERIVATIVE_VSUM = prove
+ (`!f net s.
+         FINITE s /\ (!a. a IN s ==> (f a has_complex_derivative f' a) net)
+         ==> ((\x. vsum s (\a. f a x)) has_complex_derivative (vsum s f'))
+             net`,
+  SIMP_TAC[GSYM VSUM_COMPLEX_RMUL; has_complex_derivative] THEN
+  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP HAS_DERIVATIVE_VSUM) THEN
+  REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Same thing just for complex differentiability.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_DIFFERENTIABLE_LINEAR = prove
+ (`(\z. c * z) complex_differentiable p`,
+  REWRITE_TAC [complex_differentiable] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_LINEAR]);;
+
+let COMPLEX_DIFFERENTIABLE_CONST = prove
+ (`!c net. (\z. c) complex_differentiable net`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CONST]);;
+
+let COMPLEX_DIFFERENTIABLE_ID = prove
+ (`!net. (\z. z) complex_differentiable net`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_ID]);;
+
+let COMPLEX_DIFFERENTIABLE_NEG = prove
+ (`!f net.
+        f complex_differentiable net
+        ==> (\z. --(f z)) complex_differentiable net`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_NEG]);;
+
+let COMPLEX_DIFFERENTIABLE_ADD = prove
+ (`!f g net.
+        f complex_differentiable net /\
+        g complex_differentiable net
+        ==> (\z. f z + g z) complex_differentiable net`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_ADD]);;
+
+let COMPLEX_DIFFERENTIABLE_SUB = prove
+ (`!f g net.
+        f complex_differentiable net /\
+        g complex_differentiable net
+        ==> (\z. f z - g z) complex_differentiable net`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_SUB]);;
+
+let COMPLEX_DIFFERENTIABLE_INV_WITHIN = prove
+ (`!f z s.
+        f complex_differentiable (at z within s) /\ ~(f z = Cx(&0))
+        ==> (\z. inv(f z)) complex_differentiable (at z within s)`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_INV_WITHIN]);;
+
+let COMPLEX_DIFFERENTIABLE_MUL_WITHIN = prove
+ (`!f g z s.
+        f complex_differentiable (at z within s) /\
+        g complex_differentiable (at z within s)
+        ==> (\z. f z * g z) complex_differentiable (at z within s)`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_MUL_WITHIN]);;
+
+let COMPLEX_DIFFERENTIABLE_DIV_WITHIN = prove
+ (`!f g z s.
+        f complex_differentiable (at z within s) /\
+        g complex_differentiable (at z within s) /\
+        ~(g z = Cx(&0))
+        ==> (\z. f z / g z) complex_differentiable (at z within s)`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_DIV_WITHIN]);;
+
+let COMPLEX_DIFFERENTIABLE_POW_WITHIN = prove
+ (`!f n z s.
+        f complex_differentiable (at z within s)
+        ==> (\z. f z pow n) complex_differentiable (at z within s)`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_POW_WITHIN]);;
+
+let COMPLEX_DIFFERENTIABLE_TRANSFORM_WITHIN = prove
+ (`!f g x s d.
+        &0 < d /\
+        x IN s /\
+        (!x'. x' IN s /\ dist (x',x) < d ==> f x' = g x') /\
+        f complex_differentiable (at x within s)
+        ==> g complex_differentiable (at x within s)`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN]);;
+
+let HOLOMORPHIC_TRANSFORM = prove
+ (`!f g s. (!x. x IN s ==> f x = g x) /\ f holomorphic_on s
+           ==> g holomorphic_on s`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[holomorphic_on; GSYM complex_differentiable] THEN
+  MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_TRANSFORM_WITHIN THEN
+  MAP_EVERY EXISTS_TAC [`f:complex->complex`; `&1`] THEN
+  ASM_SIMP_TAC[REAL_LT_01]);;
+
+let HOLOMORPHIC_EQ = prove
+ (`!f g s. (!x. x IN s ==> f x = g x)
+           ==> (f holomorphic_on s <=> g holomorphic_on s)`,
+  MESON_TAC[HOLOMORPHIC_TRANSFORM]);;
+
+let COMPLEX_DIFFERENTIABLE_INV_AT = prove
+ (`!f z.
+        f complex_differentiable at z /\ ~(f z = Cx(&0))
+        ==> (\z. inv(f z)) complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_INV_AT]);;
+
+let COMPLEX_DIFFERENTIABLE_MUL_AT = prove
+ (`!f g z.
+        f complex_differentiable at z /\
+        g complex_differentiable at z
+        ==> (\z. f z * g z) complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_MUL_AT]);;
+
+let COMPLEX_DIFFERENTIABLE_DIV_AT = prove
+ (`!f g z.
+        f complex_differentiable at z /\
+        g complex_differentiable at z /\
+        ~(g z = Cx(&0))
+        ==> (\z. f z / g z) complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_DIV_AT]);;
+
+let COMPLEX_DIFFERENTIABLE_POW_AT = prove
+ (`!f n z.
+        f complex_differentiable at z
+        ==> (\z. f z pow n) complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_POW_AT]);;
+
+let COMPLEX_DIFFERENTIABLE_TRANSFORM_AT = prove
+ (`!f g x d.
+        &0 < d /\
+        (!x'. dist (x',x) < d ==> f x' = g x') /\
+        f complex_differentiable at x
+        ==> g complex_differentiable at x`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_TRANSFORM_AT]);;
+
+let COMPLEX_DIFFERENTIABLE_COMPOSE_WITHIN = prove
+ (`!f g x s.
+         f complex_differentiable (at x within s) /\
+         g complex_differentiable (at (f x) within IMAGE f s)
+         ==> (g o f) complex_differentiable (at x within s)`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[COMPLEX_DIFF_CHAIN_WITHIN]);;
+
+let COMPLEX_DIFFERENTIABLE_COMPOSE_AT = prove
+ (`!f g x s.
+         f complex_differentiable (at x) /\
+         g complex_differentiable (at (f x))
+         ==> (g o f) complex_differentiable (at x)`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[COMPLEX_DIFF_CHAIN_AT]);;
+
+let COMPLEX_DIFFERENTIABLE_WITHIN_OPEN = prove
+ (`!f a s.
+        a IN s /\ open s
+        ==> (f complex_differentiable at a within s <=>
+             f complex_differentiable at a)`,
+  SIMP_TAC[complex_differentiable; HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Same again for being holomorphic on a set.                                *)
+(* ------------------------------------------------------------------------- *)
+
+let HOLOMORPHIC_ON_LINEAR = prove
+ (`!s c. (\w. c * w) holomorphic_on s`,
+  REWRITE_TAC [holomorphic_on] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_LINEAR]);;
+
+let HOLOMORPHIC_ON_CONST = prove
+ (`!c s. (\z. c) holomorphic_on s`,
+  REWRITE_TAC[HOLOMORPHIC_ON_DIFFERENTIABLE; COMPLEX_DIFFERENTIABLE_CONST]);;
+
+let HOLOMORPHIC_ON_ID = prove
+ (`!s. (\z. z) holomorphic_on s`,
+  REWRITE_TAC[HOLOMORPHIC_ON_DIFFERENTIABLE; COMPLEX_DIFFERENTIABLE_ID]);;
+
+let HOLOMORPHIC_ON_COMPOSE = prove
+ (`!f g s. f holomorphic_on s /\ g holomorphic_on (IMAGE f s)
+           ==> (g o f) holomorphic_on s`,
+  SIMP_TAC[holomorphic_on; GSYM complex_differentiable; FORALL_IN_IMAGE] THEN
+  MESON_TAC[COMPLEX_DIFFERENTIABLE_COMPOSE_WITHIN]);;
+
+let HOLOMORPHIC_ON_NEG = prove
+ (`!f s. f holomorphic_on s ==> (\z. --(f z)) holomorphic_on s`,
+  SIMP_TAC[HOLOMORPHIC_ON_DIFFERENTIABLE; COMPLEX_DIFFERENTIABLE_NEG]);;
+
+let HOLOMORPHIC_ON_ADD = prove
+ (`!f g s.
+        f holomorphic_on s /\ g holomorphic_on s
+        ==> (\z. f z + g z) holomorphic_on s`,
+  SIMP_TAC[HOLOMORPHIC_ON_DIFFERENTIABLE; COMPLEX_DIFFERENTIABLE_ADD]);;
+
+let HOLOMORPHIC_ON_SUB = prove
+ (`!f g s.
+        f holomorphic_on s /\ g holomorphic_on s
+        ==> (\z. f z - g z) holomorphic_on s`,
+  SIMP_TAC[HOLOMORPHIC_ON_DIFFERENTIABLE; COMPLEX_DIFFERENTIABLE_SUB]);;
+
+let HOLOMORPHIC_ON_MUL = prove
+ (`!f g s.
+        f holomorphic_on s /\ g holomorphic_on s
+        ==> (\z. f z * g z) holomorphic_on s`,
+  SIMP_TAC[HOLOMORPHIC_ON_DIFFERENTIABLE; COMPLEX_DIFFERENTIABLE_MUL_WITHIN]);;
+
+let HOLOMORPHIC_ON_INV = prove
+ (`!f s. f holomorphic_on s /\ (!z. z IN s ==> ~(f z = Cx(&0)))
+         ==> (\z. inv(f z)) holomorphic_on s`,
+  SIMP_TAC[HOLOMORPHIC_ON_DIFFERENTIABLE; COMPLEX_DIFFERENTIABLE_INV_WITHIN]);;
+
+let HOLOMORPHIC_ON_DIV = prove
+ (`!f g s.
+        f holomorphic_on s /\ g holomorphic_on s /\
+        (!z. z IN s ==> ~(g z = Cx(&0)))
+        ==> (\z. f z / g z) holomorphic_on s`,
+  SIMP_TAC[HOLOMORPHIC_ON_DIFFERENTIABLE; COMPLEX_DIFFERENTIABLE_DIV_WITHIN]);;
+
+let HOLOMORPHIC_ON_POW = prove
+ (`!f s n. f holomorphic_on s ==> (\z. (f z) pow n) holomorphic_on s`,
+  SIMP_TAC[HOLOMORPHIC_ON_DIFFERENTIABLE; COMPLEX_DIFFERENTIABLE_POW_WITHIN]);;
+
+let HOLOMORPHIC_ON_VSUM = prove
+ (`!f s k. FINITE k /\ (!a. a IN k ==> (f a) holomorphic_on s)
+           ==> (\x. vsum k (\a. f a x)) holomorphic_on s`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[VSUM_CLAUSES] THEN
+  SIMP_TAC[HOLOMORPHIC_ON_CONST; IN_INSERT; NOT_IN_EMPTY] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOLOMORPHIC_ON_ADD THEN
+  ASM_SIMP_TAC[ETA_AX]);;
+
+let HOLOMORPHIC_ON_COMPOSE_GEN = prove
+ (`!f g s t. f holomorphic_on s /\ g holomorphic_on t /\
+             (!z. z IN s ==> f z IN t)
+             ==>  g o f holomorphic_on s`,
+  REWRITE_TAC [holomorphic_on] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `IMAGE (f:complex->complex) s SUBSET t` MP_TAC THENL
+   [ASM SET_TAC []; ASM_MESON_TAC [HAS_COMPLEX_DERIVATIVE_WITHIN_SUBSET;
+                                   COMPLEX_DIFF_CHAIN_WITHIN]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Same again for the actual derivative function.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_COMPLEX_DERIVATIVE_DERIVATIVE = prove
+ (`!f f' x. (f has_complex_derivative f') (at x)
+                ==> complex_derivative f x = f'`,
+  REWRITE_TAC[complex_derivative] THEN
+  MESON_TAC[COMPLEX_DERIVATIVE_UNIQUE_AT]);;
+
+let HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE = prove
+ (`!f x. (f has_complex_derivative (complex_derivative f x)) (at x) <=>
+         f complex_differentiable at x`,
+  REWRITE_TAC[complex_differentiable; complex_derivative] THEN MESON_TAC[]);;
+
+let COMPLEX_DIFFERENTIABLE_COMPOSE = prove
+ (`!f g z. f complex_differentiable at z /\ g complex_differentiable at (f z)
+          ==> (g o f) complex_differentiable at z`,
+  REWRITE_TAC [complex_differentiable] THEN
+  MESON_TAC [COMPLEX_DIFF_CHAIN_AT]);;
+
+let COMPLEX_DERIVATIVE_CHAIN = prove
+ (`!f g z. f complex_differentiable at z /\ g complex_differentiable at (f z)
+           ==> complex_derivative (g o f) z =
+               complex_derivative g (f z) * complex_derivative f z`,
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_DERIVATIVE; COMPLEX_DIFF_CHAIN_AT;
+             HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE]);;
+
+let COMPLEX_DERIVATIVE_LINEAR = prove
+ (`!c. complex_derivative (\w. c * w) = \z. c`,
+  REWRITE_TAC [FUN_EQ_THM] THEN REPEAT GEN_TAC THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+  REWRITE_TAC [HAS_COMPLEX_DERIVATIVE_LINEAR]);;
+
+let COMPLEX_DERIVATIVE_ID = prove
+ (`complex_derivative (\w.w) = \z. Cx(&1)`,
+  REWRITE_TAC [FUN_EQ_THM] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_DERIVATIVE; HAS_COMPLEX_DERIVATIVE_ID]);;
+
+let COMPLEX_DERIVATIVE_CONST = prove
+ (`!c. complex_derivative (\w.c) = \z. Cx(&0)`,
+  REWRITE_TAC [FUN_EQ_THM] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_DERIVATIVE;
+             HAS_COMPLEX_DERIVATIVE_CONST]);;
+
+let COMPLEX_DERIVATIVE_ADD = prove
+ (`!f g z. f complex_differentiable at z /\ g complex_differentiable at z
+           ==> complex_derivative (\w. f w + g w) z =
+               complex_derivative f z + complex_derivative g z`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+  ASM_SIMP_TAC [HAS_COMPLEX_DERIVATIVE_ADD;
+                HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE]);;
+
+let COMPLEX_DERIVATIVE_SUB = prove
+ (`!f g z. f complex_differentiable at z /\ g complex_differentiable at z
+           ==> complex_derivative (\w. f w - g w) z =
+               complex_derivative f z - complex_derivative g z`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+  ASM_SIMP_TAC [HAS_COMPLEX_DERIVATIVE_SUB;
+                HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE]);;
+
+let COMPLEX_DERIVATIVE_MUL = prove
+ (`!f g z. f complex_differentiable at z /\ g complex_differentiable at z
+           ==> complex_derivative (\w. f w * g w) z =
+               f z * complex_derivative g z + complex_derivative f z * g z`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+  ASM_SIMP_TAC [HAS_COMPLEX_DERIVATIVE_MUL_AT;
+                HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE]);;
+
+let COMPLEX_DERIVATIVE_LMUL = prove
+ (`!f c z. f complex_differentiable at z
+             ==> complex_derivative (\w. c * f w) z =
+                 c * complex_derivative f z`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+  ASM_SIMP_TAC [HAS_COMPLEX_DERIVATIVE_LMUL_AT;
+                HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE]);;
+
+let COMPLEX_DERIVATIVE_RMUL = prove
+ (`!f c z. f complex_differentiable at z
+           ==> complex_derivative (\w. f w * c) z =
+               complex_derivative f z * c`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+  ASM_SIMP_TAC [HAS_COMPLEX_DERIVATIVE_RMUL_AT;
+                HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE]);;
+
+let COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN = prove
+ (`!f g s z. open s /\ f holomorphic_on s /\ g holomorphic_on s /\ z IN s /\
+             (!w. w IN s ==> f w = g w)
+             ==> complex_derivative f z = complex_derivative g z`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC COMPLEX_DERIVATIVE_UNIQUE_AT THEN
+  ASM_MESON_TAC[HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN;
+                HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT;
+                HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE]);;
+
+let COMPLEX_DERIVATIVE_COMPOSE_LINEAR = prove
+ (`!f c z. f complex_differentiable at (c * z)
+           ==> complex_derivative (\w. f (c * w)) z =
+               c * complex_derivative f (c * z)`,
+  SIMP_TAC
+    [COMPLEX_MUL_SYM; REWRITE_RULE [o_DEF; COMPLEX_DIFFERENTIABLE_ID;
+                   COMPLEX_DIFFERENTIABLE_LINEAR;
+                   COMPLEX_DERIVATIVE_LINEAR]
+     (SPECL [`\w:complex. c * w`] COMPLEX_DERIVATIVE_CHAIN)]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Caratheodory characterization.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_COMPLEX_DERIVATIVE_CARATHEODORY_AT = prove
+ (`!f f' z.
+        (f has_complex_derivative f') (at z) <=>
+        ?g. (!w. f(w) - f(z) = g(w) * (w - z)) /\
+            g continuous at z /\ g(z) = f'`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[COMPLEX_RING `w' - z':complex = a <=> w' = z' + a`] THEN
+  SIMP_TAC[GSYM FUN_EQ_THM; HAS_COMPLEX_DERIVATIVE_AT; CONTINUOUS_AT] THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
+   [EXISTS_TAC `\w. if w = z then f':complex else (f(w) - f(z)) / (w - z)` THEN
+    ASM_SIMP_TAC[FUN_EQ_THM; COND_RAND; COND_RATOR; COMPLEX_SUB_REFL] THEN
+    CONV_TAC COMPLEX_FIELD;
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN FIRST_X_ASSUM SUBST1_TAC THEN
+    ASM_SIMP_TAC[COMPLEX_RING `(z + a) - (z + b * (w - w)):complex = a`] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+      LIM_TRANSFORM)) THEN
+    SIMP_TAC[LIM_CONST; COMPLEX_VEC_0; COMPLEX_FIELD
+     `~(w = z) ==> x - (x * (w - z)) / (w - z) = Cx(&0)`]]);;
+
+let HAS_COMPLEX_DERIVATIVE_CARATHEODORY_WITHIN = prove
+ (`!f f' z s.
+        (f has_complex_derivative f') (at z within s) <=>
+        ?g. (!w. f(w) - f(z) = g(w) * (w - z)) /\
+            g continuous (at z within s) /\ g(z) = f'`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[COMPLEX_RING `w' - z':complex = a <=> w' = z' + a`] THEN
+  SIMP_TAC[GSYM FUN_EQ_THM; HAS_COMPLEX_DERIVATIVE_WITHIN;
+           CONTINUOUS_WITHIN] THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
+   [EXISTS_TAC `\w. if w = z then f':complex else (f(w) - f(z)) / (w - z)` THEN
+    ASM_SIMP_TAC[FUN_EQ_THM; COND_RAND; COND_RATOR; COMPLEX_SUB_REFL] THEN
+    CONV_TAC COMPLEX_FIELD;
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN FIRST_X_ASSUM SUBST1_TAC THEN
+    ASM_SIMP_TAC[COMPLEX_RING `(z + a) - (z + b * (w - w)):complex = a`] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+      LIM_TRANSFORM)) THEN
+    SIMP_TAC[LIM_CONST; COMPLEX_VEC_0; COMPLEX_FIELD
+     `~(w = z) ==> x - (x * (w - z)) / (w - z) = Cx(&0)`]]);;
+
+let COMPLEX_DIFFERENTIABLE_CARATHEODORY_AT = prove
+ (`!f z. f complex_differentiable at z <=>
+         ?g. (!w. f(w) - f(z) = g(w) * (w - z)) /\ g continuous at z`,
+  SIMP_TAC[complex_differentiable; HAS_COMPLEX_DERIVATIVE_CARATHEODORY_AT] THEN
+  MESON_TAC[]);;
+
+let COMPLEX_DIFFERENTIABLE_CARATHEODORY_WITHIN = prove
+ (`!f z s.
+      f complex_differentiable (at z within s) <=>
+      ?g. (!w. f(w) - f(z) = g(w) * (w - z)) /\ g continuous (at z within s)`,
+  SIMP_TAC[complex_differentiable;
+           HAS_COMPLEX_DERIVATIVE_CARATHEODORY_WITHIN] THEN
+  MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A slightly stronger, more traditional notion of analyticity on a set.     *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix ("analytic_on",(12,"right"));;
+
+let analytic_on = new_definition
+ `f analytic_on s <=>
+      !x. x IN s ==> ?e. &0 < e /\ f holomorphic_on ball(x,e)`;;
+
+let ANALYTIC_IMP_HOLOMORPHIC = prove
+ (`!f s. f analytic_on s ==> f holomorphic_on s`,
+  REWRITE_TAC[analytic_on; holomorphic_on] THEN
+  SIMP_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN; OPEN_BALL] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN; CENTRE_IN_BALL]);;
+
+let ANALYTIC_ON_OPEN = prove
+ (`!f s. open s ==> (f analytic_on s <=> f holomorphic_on s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REWRITE_TAC[ANALYTIC_IMP_HOLOMORPHIC] THEN
+  REWRITE_TAC[analytic_on; holomorphic_on] THEN
+  ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN; OPEN_BALL] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+  REWRITE_TAC[SUBSET] THEN MESON_TAC[CENTRE_IN_BALL]);;
+
+let ANALYTIC_ON_IMP_DIFFERENTIABLE_AT = prove
+ (`!f s x. f analytic_on s /\ x IN s ==> f complex_differentiable (at x)`,
+  SIMP_TAC[analytic_on; HOLOMORPHIC_ON_OPEN; OPEN_BALL;
+           complex_differentiable] THEN
+  MESON_TAC[CENTRE_IN_BALL]);;
+
+let ANALYTIC_ON_SUBSET = prove
+ (`!f s t. f analytic_on s /\ t SUBSET s ==> f analytic_on t`,
+  REWRITE_TAC[analytic_on; SUBSET] THEN MESON_TAC[]);;
+
+let ANALYTIC_ON_UNION = prove
+ (`!f s t. f analytic_on (s UNION t) <=> f analytic_on s /\ f analytic_on t`,
+  REWRITE_TAC [analytic_on; IN_UNION] THEN MESON_TAC[]);;
+
+let ANALYTIC_ON_UNIONS = prove
+ (`!f s. f analytic_on (UNIONS s) <=> (!t. t IN s ==> f analytic_on t)`,
+  REWRITE_TAC [analytic_on; IN_UNIONS] THEN MESON_TAC[]);;
+
+let ANALYTIC_ON_HOLOMORPHIC = prove
+ (`!f s. f analytic_on s <=> ?t. open t /\ s SUBSET t /\ f holomorphic_on t`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `?t. open t /\ s SUBSET t /\ f analytic_on t` THEN CONJ_TAC THENL
+   [EQ_TAC THENL
+    [DISCH_TAC THEN EXISTS_TAC `UNIONS {u | open u /\ f analytic_on u}` THEN
+     SIMP_TAC [IN_ELIM_THM; OPEN_UNIONS; ANALYTIC_ON_UNIONS] THEN
+     REWRITE_TAC [SUBSET; IN_UNIONS; IN_ELIM_THM] THEN
+     ASM_MESON_TAC [analytic_on; ANALYTIC_ON_OPEN; OPEN_BALL; CENTRE_IN_BALL];
+     MESON_TAC [ANALYTIC_ON_SUBSET]];
+    MESON_TAC [ANALYTIC_ON_OPEN]]);;
+
+let ANALYTIC_ON_LINEAR = prove
+ (`!s c. (\w. c * w) analytic_on s`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC [ANALYTIC_ON_HOLOMORPHIC; HOLOMORPHIC_ON_LINEAR] THEN
+  EXISTS_TAC `(:complex)` THEN REWRITE_TAC [OPEN_UNIV; SUBSET_UNIV]);;
+
+let ANALYTIC_ON_CONST = prove
+ (`!c s. (\z. c) analytic_on s`,
+  REWRITE_TAC[analytic_on; HOLOMORPHIC_ON_CONST] THEN MESON_TAC[REAL_LT_01]);;
+
+let ANALYTIC_ON_ID = prove
+ (`!s. (\z. z) analytic_on s`,
+  REWRITE_TAC[analytic_on; HOLOMORPHIC_ON_ID] THEN MESON_TAC[REAL_LT_01]);;
+
+let ANALYTIC_ON_COMPOSE = prove
+ (`!f g s. f analytic_on s /\ g analytic_on (IMAGE f s)
+           ==> (g o f) analytic_on s`,
+  REWRITE_TAC[analytic_on; FORALL_IN_IMAGE] THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "f") (LABEL_TAC "g")) THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  REMOVE_THEN "f" (MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HOLOMORPHIC_ON_IMP_CONTINUOUS_ON) THEN
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; OPEN_BALL] THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[CENTRE_IN_BALL; CONTINUOUS_AT_BALL] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(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:real) k` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+  MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN
+  CONJ_TAC THEN MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THENL
+   [EXISTS_TAC `ball(z:complex,d)`;
+    EXISTS_TAC `ball((f:complex->complex) z,e)`] THEN
+  ASM_REWRITE_TAC[BALL_MIN_INTER; INTER_SUBSET] THEN ASM SET_TAC[]);;
+
+let ANALYTIC_ON_COMPOSE_GEN = prove
+ (`!f g s t. f analytic_on s /\ g analytic_on t /\ (!z. z IN s ==> f z IN t)
+             ==> g o f analytic_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ANALYTIC_ON_COMPOSE THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC ANALYTIC_ON_SUBSET THEN ASM SET_TAC[]);;
+
+let ANALYTIC_ON_NEG = prove
+ (`!f s. f analytic_on s ==> (\z. --(f z)) analytic_on s`,
+  SIMP_TAC[analytic_on] THEN MESON_TAC[HOLOMORPHIC_ON_NEG]);;
+
+let ANALYTIC_ON_ADD = prove
+ (`!f g s.
+        f analytic_on s /\ g analytic_on s ==> (\z. f z + g z) analytic_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[analytic_on] THEN
+  REWRITE_TAC[AND_FORALL_THM] THEN MATCH_MP_TAC MONO_FORALL THEN
+  GEN_TAC THEN DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_TAC `d:real`) (X_CHOOSE_TAC `e:real`)) THEN
+  EXISTS_TAC `min (d:real) e` THEN
+  ASM_REWRITE_TAC[REAL_LT_MIN; BALL_MIN_INTER; IN_INTER] THEN
+  MATCH_MP_TAC HOLOMORPHIC_ON_ADD THEN
+  ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET; INTER_SUBSET]);;
+
+let ANALYTIC_ON_SUB = prove
+ (`!f g s.
+        f analytic_on s /\ g analytic_on s ==> (\z. f z - g z) analytic_on s`,
+  SIMP_TAC[complex_sub; ANALYTIC_ON_ADD; ANALYTIC_ON_NEG]);;
+
+let ANALYTIC_ON_MUL = prove
+ (`!f g s.
+        f analytic_on s /\ g analytic_on s ==> (\z. f z * g z) analytic_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[analytic_on] THEN
+  REWRITE_TAC[AND_FORALL_THM] THEN MATCH_MP_TAC MONO_FORALL THEN
+  GEN_TAC THEN DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_TAC `d:real`) (X_CHOOSE_TAC `e:real`)) THEN
+  EXISTS_TAC `min (d:real) e` THEN
+  ASM_REWRITE_TAC[REAL_LT_MIN; BALL_MIN_INTER; IN_INTER] THEN
+  MATCH_MP_TAC HOLOMORPHIC_ON_MUL THEN
+  ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET; INTER_SUBSET]);;
+
+let ANALYTIC_ON_INV = prove
+ (`!f s. f analytic_on s /\ (!z. z IN s ==> ~(f z = Cx(&0)))
+         ==> (\z. inv(f z)) analytic_on s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[analytic_on] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [analytic_on]) THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `?e. &0 < e /\ !y:complex. dist(z,y) < e ==> ~(f y = Cx(&0))`
+  MP_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_OPEN_AVOID THEN
+    EXISTS_TAC `ball(z:complex,d)` THEN
+    ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON; CENTRE_IN_BALL; OPEN_BALL];
+    REWRITE_TAC[GSYM IN_BALL] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `min (d:real) e` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_INV THEN
+    ASM_SIMP_TAC[BALL_MIN_INTER; IN_INTER] THEN
+    ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET; INTER_SUBSET]]);;
+
+let ANALYTIC_ON_DIV = prove
+ (`!f g s.
+        f analytic_on s /\ g analytic_on s /\
+        (!z. z IN s ==> ~(g z = Cx(&0)))
+        ==> (\z. f z / g z) analytic_on s`,
+  SIMP_TAC[complex_div; ANALYTIC_ON_MUL; ANALYTIC_ON_INV]);;
+
+let ANALYTIC_ON_POW = prove
+ (`!f s n. f analytic_on s ==> (\z. (f z) pow n) analytic_on s`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN
+  DISCH_TAC THEN INDUCT_TAC THEN REWRITE_TAC[complex_pow] THEN
+  ASM_SIMP_TAC[ANALYTIC_ON_CONST; ANALYTIC_ON_MUL]);;
+
+let ANALYTIC_ON_VSUM = prove
+ (`!f s k. FINITE k /\ (!a. a IN k ==> (f a) analytic_on s)
+           ==> (\x. vsum k (\a. f a x)) analytic_on s`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[VSUM_CLAUSES] THEN
+  SIMP_TAC[ANALYTIC_ON_CONST; IN_INSERT; NOT_IN_EMPTY] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ANALYTIC_ON_ADD THEN
+  ASM_SIMP_TAC[ETA_AX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The case of analyticity at a point.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let ANALYTIC_AT_BALL = prove
+ (`!f z. f analytic_on {z} <=> ?e. &0<e /\ f holomorphic_on ball (z,e)`,
+  REWRITE_TAC [analytic_on; IN_SING] THEN MESON_TAC []);;
+
+let ANALYTIC_AT = prove
+ (`!f z. f analytic_on {z} <=> ?s. open s /\ z IN s /\ f holomorphic_on s`,
+  REWRITE_TAC [ANALYTIC_ON_HOLOMORPHIC; SING_SUBSET]);;
+
+let ANALYTIC_ON_ANALYTIC_AT = prove
+ (`!f s. f analytic_on s <=> !z. z IN s ==> f analytic_on {z}`,
+  REWRITE_TAC [ANALYTIC_AT_BALL; analytic_on]);;
+
+let ANALYTIC_AT_TWO = prove
+ (`!f g z. f analytic_on {z} /\ g analytic_on {z} <=>
+    ?s. open s /\ z IN s /\ f holomorphic_on s /\ g holomorphic_on s`,
+  REWRITE_TAC [ANALYTIC_AT] THEN
+  MESON_TAC [HOLOMORPHIC_ON_SUBSET; OPEN_INTER; INTER_SUBSET; IN_INTER]);;
+
+let ANALYTIC_AT_ADD = prove
+ (`!f g z. f analytic_on {z} /\ g analytic_on {z}
+     ==> (\w. f w + g w) analytic_on {z}`,
+  REWRITE_TAC [ANALYTIC_AT_TWO] THEN REWRITE_TAC [ANALYTIC_AT] THEN
+  MESON_TAC [HOLOMORPHIC_ON_ADD]);;
+
+let ANALYTIC_AT_SUB = prove
+ (`!f g z. f analytic_on {z} /\ g analytic_on {z}
+     ==> (\w. f w - g w) analytic_on {z}`,
+  REWRITE_TAC [ANALYTIC_AT_TWO] THEN REWRITE_TAC [ANALYTIC_AT] THEN
+  MESON_TAC [HOLOMORPHIC_ON_SUB]);;
+
+let ANALYTIC_AT_MUL = prove
+ (`!f g z. f analytic_on {z} /\ g analytic_on {z}
+
+     ==> (\w. f w * g w) analytic_on {z}`,
+  REWRITE_TAC [ANALYTIC_AT_TWO] THEN REWRITE_TAC [ANALYTIC_AT] THEN
+  MESON_TAC [HOLOMORPHIC_ON_MUL]);;
+
+let ANALYTIC_AT_POW = prove
+ (`!f n z. f analytic_on {z}
+     ==> (\w. f w pow n) analytic_on {z}`,
+  REWRITE_TAC [ANALYTIC_AT] THEN MESON_TAC [HOLOMORPHIC_ON_POW]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Combining theorems for derivative with analytic_at {z} hypotheses.        *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_DERIVATIVE_ADD_AT = prove
+ (`!f g z. f analytic_on {z} /\ g analytic_on {z}
+     ==> complex_derivative (\w. f w + g w) z =
+           complex_derivative f z + complex_derivative g z`,
+  REWRITE_TAC [ANALYTIC_AT_TWO] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC COMPLEX_DERIVATIVE_ADD THEN
+  ASM_MESON_TAC [HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT]);;
+
+let COMPLEX_DERIVATIVE_SUB_AT = prove
+ (`!f g z. f analytic_on {z} /\ g analytic_on {z}
+     ==> complex_derivative (\w. f w - g w) z =
+           complex_derivative f z - complex_derivative g z`,
+  REWRITE_TAC [ANALYTIC_AT_TWO] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC COMPLEX_DERIVATIVE_SUB THEN
+  ASM_MESON_TAC [HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT]);;
+
+let COMPLEX_DERIVATIVE_MUL_AT = prove
+ (`!f g z. f analytic_on {z} /\ g analytic_on {z}
+     ==> complex_derivative (\w. f w * g w) z =
+           f z * complex_derivative g z + complex_derivative f z * g z`,
+  REWRITE_TAC [ANALYTIC_AT_TWO] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC COMPLEX_DERIVATIVE_MUL THEN
+  ASM_MESON_TAC [HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT]);;
+
+let COMPLEX_DERIVATIVE_LMUL_AT = prove
+ (`!f c z. f analytic_on {z}
+    ==> complex_derivative (\w. c * f w) z = c * complex_derivative f z`,
+  REWRITE_TAC [ANALYTIC_AT] THEN
+  MESON_TAC [HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT; COMPLEX_DERIVATIVE_LMUL]);;
+
+let COMPLEX_DERIVATIVE_RMUL_AT = prove
+ (`!f c z. f analytic_on {z}
+    ==> complex_derivative (\w. f w * c) z = complex_derivative f z * c`,
+  REWRITE_TAC [ANALYTIC_AT] THEN
+  MESON_TAC [HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT; COMPLEX_DERIVATIVE_RMUL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A composition lemma for functions of mixed type.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_VECTOR_DERIVATIVE_REAL_COMPLEX = prove
+ (`(f has_complex_derivative f') (at(Cx(drop a)))
+   ==> ((\x. f(Cx(drop x))) has_vector_derivative f') (at a)`,
+  REWRITE_TAC[has_complex_derivative; has_vector_derivative] THEN
+  REWRITE_TAC[COMPLEX_CMUL] THEN MP_TAC(ISPECL
+   [`\x. Cx(drop x)`; `f:complex->complex`;
+    `\x. Cx(drop x)`; `\x:complex. f' * x`; `a:real^1`] DIFF_CHAIN_AT) THEN
+  REWRITE_TAC[o_DEF; COMPLEX_MUL_SYM; IMP_CONJ] THEN
+  DISCH_THEN MATCH_MP_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_LINEAR THEN
+  REWRITE_TAC[linear; DROP_ADD; DROP_CMUL; CX_ADD; CX_MUL; COMPLEX_CMUL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex differentiation of sequences and series.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_COMPLEX_DERIVATIVE_SEQUENCE = prove
+ (`!s f f' g'.
+         convex s /\
+         (!n x. x IN s
+                ==> (f n has_complex_derivative f' n x) (at x within s)) /\
+         (!e. &0 < e
+              ==> ?N. !n x. n >= N /\ x IN s ==> norm (f' n x - g' x) <= e) /\
+         (?x l. x IN s /\ ((\n. f n x) --> l) sequentially)
+         ==> ?g. !x. x IN s
+                     ==> ((\n. f n x) --> g x) sequentially /\
+                         (g has_complex_derivative g' x) (at x within s)`,
+  REWRITE_TAC[has_complex_derivative] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_SEQUENCE THEN
+  EXISTS_TAC `\n x h:complex. (f':num->complex->complex) n x * h` THEN
+  ASM_SIMP_TAC[] THEN CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+  REWRITE_TAC[GSYM COMPLEX_SUB_RDISTRIB; COMPLEX_NORM_MUL] THEN
+  ASM_MESON_TAC[REAL_LE_RMUL; NORM_POS_LE]);;
+
+let HAS_COMPLEX_DERIVATIVE_SERIES = prove
+ (`!s f f' g' k.
+         convex s /\
+         (!n x. x IN s
+                ==> (f n has_complex_derivative f' n x) (at x within s)) /\
+         (!e. &0 < e
+              ==> ?N. !n x. n >= N /\ x IN s
+                            ==> norm(vsum (k INTER (0..n)) (\i. f' i x) - g' x)
+                                    <= e) /\
+         (?x l. x IN s /\ ((\n. f n x) sums l) k)
+         ==> ?g. !x. x IN s
+                     ==> ((\n. f n x) sums g x) k /\
+                         (g has_complex_derivative g' x) (at x within s)`,
+  REWRITE_TAC[has_complex_derivative] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_SERIES THEN
+  EXISTS_TAC `\n x h:complex. (f':num->complex->complex) n x * h` THEN
+  ASM_SIMP_TAC[] THEN CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+  SIMP_TAC[GSYM COMPLEX_SUB_RDISTRIB; VSUM_COMPLEX_RMUL; FINITE_NUMSEG;
+           FINITE_INTER; COMPLEX_NORM_MUL] THEN
+  ASM_MESON_TAC[REAL_LE_RMUL; NORM_POS_LE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Bound theorem.                                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_DIFFERENTIABLE_BOUND = prove
+ (`!f f' s B.
+        convex s /\
+        (!x. x IN s ==> (f has_complex_derivative f'(x)) (at x within s) /\
+                        norm(f' x) <= B)
+        ==> !x y. x IN s /\ y IN s ==> norm(f x - f y) <= B * norm(x - y)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_complex_derivative] THEN
+  STRIP_TAC THEN MATCH_MP_TAC DIFFERENTIABLE_BOUND THEN
+  EXISTS_TAC `\x:complex h. f' x * h` THEN ASM_SIMP_TAC[] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `\h. (f':complex->complex) x * h` ONORM) THEN
+  REWRITE_TAC[LINEAR_COMPLEX_MUL] THEN
+  DISCH_THEN(MATCH_MP_TAC o CONJUNCT2) THEN
+  GEN_TAC THEN REWRITE_TAC[COMPLEX_NORM_MUL] THEN
+  ASM_MESON_TAC[REAL_LE_RMUL; NORM_POS_LE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Inverse function theorem for complex derivatives.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_COMPLEX_DERIVATIVE_INVERSE_BASIC = prove
+ (`!f g f' t y.
+        (f has_complex_derivative f') (at (g y)) /\
+        ~(f' = Cx(&0)) /\
+        g continuous at y /\
+        open t /\
+        y IN t /\
+        (!z. z IN t ==> f (g z) = z)
+        ==> (g has_complex_derivative inv(f')) (at y)`,
+  REWRITE_TAC[has_complex_derivative] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_INVERSE_BASIC THEN
+  MAP_EVERY EXISTS_TAC
+   [`f:complex->complex`; `\x:complex. f' * x`; `t:complex->bool`] THEN
+  ASM_REWRITE_TAC[LINEAR_COMPLEX_MUL; FUN_EQ_THM; o_THM; I_THM] THEN
+  UNDISCH_TAC `~(f' = Cx(&0))` THEN CONV_TAC COMPLEX_FIELD);;
+
+let HAS_COMPLEX_DERIVATIVE_INVERSE_STRONG = prove
+ (`!f g f' s x.
+         open s /\
+         x IN s /\
+         f continuous_on s /\
+         (!x. x IN s ==> g (f x) = x) /\
+         (f has_complex_derivative f') (at x) /\
+         ~(f' = Cx(&0))
+         ==> (g has_complex_derivative inv(f')) (at (f x))`,
+  REWRITE_TAC[has_complex_derivative] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_INVERSE_STRONG THEN
+  MAP_EVERY EXISTS_TAC [`\x:complex. f' * x`; `s:complex->bool`] THEN
+  ASM_REWRITE_TAC[] THEN ASM_SIMP_TAC[FUN_EQ_THM; o_THM; I_THM] THEN
+  UNDISCH_TAC `~(f' = Cx(&0))` THEN CONV_TAC COMPLEX_FIELD);;
+
+let HAS_COMPLEX_DERIVATIVE_INVERSE_STRONG_X = prove
+ (`!f g f' s y.
+        open s /\ (g y) IN s /\ f continuous_on s /\
+        (!x. x IN s ==> (g(f(x)) = x)) /\
+        (f has_complex_derivative f') (at (g y)) /\ ~(f' = Cx(&0)) /\
+        f(g y) = y
+        ==> (g has_complex_derivative inv(f')) (at y)`,
+  REWRITE_TAC[has_complex_derivative] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_INVERSE_STRONG_X THEN MAP_EVERY EXISTS_TAC
+   [`f:complex->complex`; `\x:complex. f' * x`; `s:complex->bool`] THEN
+  ASM_REWRITE_TAC[] THEN ASM_SIMP_TAC[FUN_EQ_THM; o_THM; I_THM] THEN
+  UNDISCH_TAC `~(f' = Cx(&0))` THEN CONV_TAC COMPLEX_FIELD);;
+
+(* ------------------------------------------------------------------------- *)
+(* Cauchy-Riemann condition and relation to conformal.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_BASIS = prove
+ (`basis 1 = Cx(&1) /\ basis 2 = ii`,
+  SIMP_TAC[CART_EQ; FORALL_2; BASIS_COMPONENT; DIMINDEX_2; ARITH] THEN
+  REWRITE_TAC[GSYM RE_DEF; GSYM IM_DEF; RE_CX; IM_CX] THEN
+  REWRITE_TAC[ii] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_DIFFERENTIABLE_IMP_DIFFERENTIABLE = prove
+ (`!net f. f complex_differentiable net ==> f differentiable net`,
+  SIMP_TAC[complex_differentiable; differentiable; has_complex_derivative] THEN
+  MESON_TAC[]);;
+
+let CAUCHY_RIEMANN = prove
+ (`!f z. f complex_differentiable at z <=>
+         f differentiable at z  /\
+         (jacobian f (at z))$1$1 = (jacobian f (at z))$2$2 /\
+         (jacobian f (at z))$1$2 = --((jacobian f (at z))$2$1)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[complex_differentiable] THEN EQ_TAC THENL
+   [REWRITE_TAC[has_complex_derivative] THEN
+    DISCH_THEN(X_CHOOSE_THEN `f':complex` ASSUME_TAC) THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[differentiable]; ALL_TAC] THEN
+    REWRITE_TAC[jacobian] THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP FRECHET_DERIVATIVE_AT) THEN
+    SIMP_TAC[matrix; LAMBDA_BETA; DIMINDEX_2; ARITH] THEN
+    REWRITE_TAC[COMPLEX_BASIS; GSYM RE_DEF; GSYM IM_DEF; ii] THEN
+    SIMPLE_COMPLEX_ARITH_TAC;
+    STRIP_TAC THEN EXISTS_TAC
+     `complex(jacobian (f:complex->complex) (at z)$1$1,
+              jacobian f (at z)$2$1)` THEN
+    REWRITE_TAC[has_complex_derivative] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [JACOBIAN_WORKS]) THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    ASM_SIMP_TAC[CART_EQ; matrix_vector_mul; DIMINDEX_2; SUM_2; ARITH;
+                 FORALL_2; FUN_EQ_THM; LAMBDA_BETA] THEN
+    REWRITE_TAC[GSYM RE_DEF; GSYM IM_DEF; IM; RE; complex_mul] THEN
+    REAL_ARITH_TAC]);;
+
+let COMPLEX_DERIVATIVE_JACOBIAN = prove
+ (`!f z.
+        f complex_differentiable (at z)
+        ==> complex_derivative f z =
+            complex(jacobian f (at z)$1$1,jacobian f (at z)$2$1)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC COMPLEX_DERIVATIVE_UNIQUE_AT THEN
+  MAP_EVERY EXISTS_TAC [`f:complex->complex`; `z:complex`] THEN
+  ASM_REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+  REWRITE_TAC[has_complex_derivative] THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [CAUCHY_RIEMANN]) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [JACOBIAN_WORKS]) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  ASM_SIMP_TAC[CART_EQ; matrix_vector_mul; DIMINDEX_2; SUM_2; ARITH;
+               FORALL_2; FUN_EQ_THM; LAMBDA_BETA] THEN
+  REWRITE_TAC[GSYM RE_DEF; GSYM IM_DEF; IM; RE; complex_mul] THEN
+  REAL_ARITH_TAC);;
+
+let COMPLEX_DIFFERENTIABLE_EQ_CONFORMAL = prove
+ (`!f z.
+      f complex_differentiable at z /\ ~(complex_derivative f z = Cx(&0)) <=>
+      f differentiable at z  /\
+      ?a. ~(a = &0) /\ rotation_matrix (a %% jacobian f (at z))`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    ASM_SIMP_TAC[COMPLEX_DIFFERENTIABLE_IMP_DIFFERENTIABLE;
+                 COMPLEX_DERIVATIVE_JACOBIAN] THEN
+    REWRITE_TAC[GSYM COMPLEX_VEC_0; GSYM DOT_EQ_0] THEN
+    REWRITE_TAC[DOT_2; GSYM RE_DEF; GSYM IM_DEF; RE; IM; GSYM REAL_POW_2] THEN
+    REWRITE_TAC[RE_DEF; IM_DEF; ROTATION_MATRIX_2] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[CAUCHY_RIEMANN]) THEN
+    ASM_REWRITE_TAC[MATRIX_CMUL_COMPONENT] THEN DISCH_TAC THEN
+    REWRITE_TAC[REAL_MUL_RNEG; GSYM REAL_ADD_LDISTRIB;
+                REAL_ARITH `(a * x:real) pow 2 = a pow 2 * x pow 2`] THEN
+    EXISTS_TAC
+     `inv(sqrt(jacobian (f:complex->complex) (at z)$2$2 pow 2 +
+               jacobian f (at z)$2$1 pow 2))` THEN
+    MATCH_MP_TAC(REAL_FIELD
+     `x pow 2 = y /\ ~(y = &0)
+      ==> ~(inv x = &0) /\ inv(x) pow 2 * y = &1`) THEN
+    ASM_SIMP_TAC[SQRT_POW_2; REAL_LE_ADD; REAL_LE_POW_2];
+    REWRITE_TAC[ROTATION_MATRIX_2; MATRIX_CMUL_COMPONENT] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `a:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    ASM_REWRITE_TAC[GSYM REAL_MUL_RNEG; REAL_EQ_MUL_LCANCEL] THEN
+    STRIP_TAC THEN MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN
+    CONJ_TAC THENL [ASM_REWRITE_TAC[CAUCHY_RIEMANN]; DISCH_TAC] THEN
+    ASM_SIMP_TAC[COMPLEX_DERIVATIVE_JACOBIAN] THEN
+    REWRITE_TAC[GSYM COMPLEX_VEC_0; GSYM DOT_EQ_0] THEN
+    REWRITE_TAC[DOT_2; GSYM RE_DEF; GSYM IM_DEF; RE; IM; GSYM REAL_POW_2] THEN
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP
+     (REAL_RING `(a * x) pow 2 + (a * y) pow 2 = &1
+                 ==> ~(x pow 2 + y pow 2 = &0)`)) THEN
+    ASM_REWRITE_TAC[RE_DEF; IM_DEF]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Differentiation conversion.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let complex_differentiation_theorems = ref [];;
+
+let add_complex_differentiation_theorems =
+  let ETA_THM = prove
+   (`(f has_complex_derivative f') net <=>
+     ((\x. f x) has_complex_derivative f') net`,
+    REWRITE_TAC[ETA_AX]) in
+  let ETA_TWEAK =
+    PURE_REWRITE_RULE [IMP_CONJ] o
+    GEN_REWRITE_RULE (LAND_CONV o ONCE_DEPTH_CONV) [ETA_THM] o
+    SPEC_ALL in
+  fun l -> complex_differentiation_theorems :=
+              !complex_differentiation_theorems @ map ETA_TWEAK l;;
+
+add_complex_differentiation_theorems
+ [HAS_COMPLEX_DERIVATIVE_LMUL_WITHIN; HAS_COMPLEX_DERIVATIVE_LMUL_AT;
+  HAS_COMPLEX_DERIVATIVE_RMUL_WITHIN; HAS_COMPLEX_DERIVATIVE_RMUL_AT;
+  HAS_COMPLEX_DERIVATIVE_CDIV_WITHIN; HAS_COMPLEX_DERIVATIVE_CDIV_AT;
+  HAS_COMPLEX_DERIVATIVE_ID;
+  HAS_COMPLEX_DERIVATIVE_CONST;
+  HAS_COMPLEX_DERIVATIVE_NEG;
+  HAS_COMPLEX_DERIVATIVE_ADD;
+  HAS_COMPLEX_DERIVATIVE_SUB;
+  HAS_COMPLEX_DERIVATIVE_MUL_WITHIN; HAS_COMPLEX_DERIVATIVE_MUL_AT;
+  HAS_COMPLEX_DERIVATIVE_DIV_WITHIN; HAS_COMPLEX_DERIVATIVE_DIV_AT;
+  HAS_COMPLEX_DERIVATIVE_POW_WITHIN; HAS_COMPLEX_DERIVATIVE_POW_AT;
+  HAS_COMPLEX_DERIVATIVE_INV_WITHIN; HAS_COMPLEX_DERIVATIVE_INV_AT];;
+
+let rec COMPLEX_DIFF_CONV =
+  let partfn tm = let l,r = dest_comb tm in mk_pair(lhand l,r)
+  and is_deriv = can (term_match [] `(f has_complex_derivative f') net`) in
+  let rec COMPLEX_DIFF_CONV tm =
+    try tryfind (fun th -> PART_MATCH partfn th (partfn tm))
+                (!complex_differentiation_theorems)
+    with Failure _ ->
+        let ith = tryfind (fun th ->
+         PART_MATCH (partfn o repeat (snd o dest_imp)) th (partfn tm))
+                    (!complex_differentiation_theorems) in
+        COMPLEX_DIFF_ELIM ith
+  and COMPLEX_DIFF_ELIM th =
+    let tm = concl th in
+    if not(is_imp tm) then th else
+    let t = lhand tm in
+    if not(is_deriv t) then UNDISCH th
+    else COMPLEX_DIFF_ELIM (MATCH_MP th (COMPLEX_DIFF_CONV t)) in
+  COMPLEX_DIFF_CONV;;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence a tactic.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_DIFF_TAC =
+  let pth = MESON[]
+   `(f has_complex_derivative f') net
+    ==> f' = g'
+        ==> (f has_complex_derivative g') net` in
+  W(fun (asl,w) -> let th = MATCH_MP pth (COMPLEX_DIFF_CONV w) in
+       MATCH_MP_TAC(repeat (GEN_REWRITE_RULE I [IMP_IMP]) (DISCH_ALL th)));;
+
+let COMPLEX_DIFFERENTIABLE_TAC =
+  let DISCH_FIRST th = DISCH (hd(hyp th)) th in
+  GEN_REWRITE_TAC I [complex_differentiable] THEN
+  W(fun (asl,w) ->
+        let th = COMPLEX_DIFF_CONV(snd(dest_exists w)) in
+        let f' = rand(rator(concl th)) in
+        EXISTS_TAC f' THEN
+        (if hyp th = [] then MATCH_ACCEPT_TAC th else
+         let th' = repeat (GEN_REWRITE_RULE I [IMP_IMP] o DISCH_FIRST)
+                          (DISCH_FIRST th) in
+         MATCH_MP_TAC th'));;
+
+(* ------------------------------------------------------------------------- *)
+(* A kind of complex Taylor theorem.                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_TAYLOR = prove
+ (`!f n s B.
+    convex s /\
+    (!i x. x IN s /\ i <= n
+           ==> ((f i) has_complex_derivative f (i + 1) x) (at x within s)) /\
+    (!x. x IN s ==> norm(f (n + 1) x) <= B)
+    ==> !w z. w IN s /\ z IN s
+              ==> norm(f 0 z -
+                       vsum (0..n) (\i. f i w * (z - w) pow i / Cx(&(FACT i))))
+                  <= B * norm(z - w) pow (n + 1) / &(FACT n)`,
+  let lemma = prove
+   (`!f:num->real^N.
+          vsum (0..n) f = f 0 - f (n + 1) + vsum (0..n) (\i. f (i + 1))`,
+    REWRITE_TAC[GSYM(REWRITE_CONV[o_DEF] `(f:num->real^N) o (\i. i + 1)`)] THEN
+    ASM_SIMP_TAC[GSYM VSUM_IMAGE; EQ_ADD_RCANCEL; FINITE_NUMSEG] THEN
+    REWRITE_TAC[GSYM NUMSEG_OFFSET_IMAGE] THEN
+    SIMP_TAC[VSUM_CLAUSES_LEFT; LE_0] THEN
+    REWRITE_TAC[VSUM_CLAUSES_NUMSEG; GSYM ADD1] THEN
+    REWRITE_TAC[ARITH; ARITH_RULE `1 <= SUC n`] THEN VECTOR_ARITH_TAC) in
+  REPEAT STRIP_TAC THEN MP_TAC(SPECL
+   [`(\w. vsum (0..n) (\i. f i w * (z - w) pow i / Cx(&(FACT i))))`;
+    `\w. (f:num->complex->complex) (n + 1) w *
+         (z - w) pow n / Cx(&(FACT n))`; `segment[w:complex,z]`;
+    `B * norm(z - w:complex) pow n / &(FACT n)`]
+   COMPLEX_DIFFERENTIABLE_BOUND) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[CONVEX_SEGMENT] THEN X_GEN_TAC `u:complex` THEN
+    DISCH_TAC THEN SUBGOAL_THEN `(u:complex) IN s` ASSUME_TAC THENL
+     [ASM_MESON_TAC[CONVEX_CONTAINS_SEGMENT; SUBSET]; ALL_TAC] THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_DIV; COMPLEX_NORM_CX;
+                  COMPLEX_NORM_POW; REAL_ABS_NUM] THEN
+      MATCH_MP_TAC REAL_LE_MUL2 THEN
+      ASM_SIMP_TAC[REAL_LE_DIV; NORM_POS_LE; REAL_POS; REAL_POW_LE] THEN
+      ASM_SIMP_TAC[REAL_LE_DIV2_EQ; REAL_OF_NUM_LT; FACT_LT] THEN
+      MATCH_MP_TAC REAL_POW_LE2 THEN REWRITE_TAC[NORM_POS_LE] THEN
+      ASM_MESON_TAC[SEGMENT_BOUND; NORM_SUB]] THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_WITHIN_SUBSET THEN
+    EXISTS_TAC `s:complex->bool` THEN CONJ_TAC THENL
+     [ALL_TAC; ASM_MESON_TAC[CONVEX_CONTAINS_SEGMENT]] THEN
+    SUBGOAL_THEN
+     `((\u. vsum (0..n) (\i. f i u * (z - u) pow i / Cx (&(FACT i))))
+       has_complex_derivative
+       vsum (0..n) (\i. f i u * (-- Cx(&i) * (z - u) pow (i - 1)) /
+                                Cx(&(FACT i)) +
+                        f (i + 1) u * (z - u) pow i / Cx (&(FACT i))))
+      (at u within s)`
+    MP_TAC THENL
+     [MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_VSUM THEN
+      REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_MUL_WITHIN THEN
+      ASM_SIMP_TAC[ETA_AX] THEN W(MP_TAC o COMPLEX_DIFF_CONV o snd) THEN
+      MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+      REWRITE_TAC[complex_div] THEN CONV_TAC COMPLEX_RING;
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[] THEN MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN
+    AP_TERM_TAC THEN REWRITE_TAC[VSUM_ADD_NUMSEG] THEN
+    GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [lemma] THEN
+    REWRITE_TAC[GSYM VSUM_ADD_NUMSEG; GSYM COMPLEX_ADD_ASSOC] THEN
+    REWRITE_TAC[ADD_SUB] THEN REWRITE_TAC[GSYM ADD1; FACT] THEN
+    REWRITE_TAC[GSYM REAL_OF_NUM_SUC; GSYM REAL_OF_NUM_MUL; CX_MUL] THEN
+    REWRITE_TAC[complex_div; COMPLEX_INV_MUL; GSYM COMPLEX_MUL_ASSOC] THEN
+    REWRITE_TAC[COMPLEX_RING
+      `--a * b * inv a * c:complex = --(a * inv a) * b * c`] THEN
+    SIMP_TAC[COMPLEX_MUL_RINV; CX_INJ; REAL_ARITH `~(&n + &1 = &0)`] THEN
+    REWRITE_TAC[COMPLEX_MUL_LNEG; COMPLEX_MUL_RNEG; COMPLEX_MUL_LID] THEN
+    REWRITE_TAC[COMPLEX_ADD_LINV; GSYM COMPLEX_VEC_0; VSUM_0] THEN
+    REWRITE_TAC[COMPLEX_VEC_0; COMPLEX_ADD_RID] THEN
+    REWRITE_TAC[COMPLEX_MUL_LZERO; COMPLEX_MUL_RZERO; COMPLEX_NEG_0] THEN
+    CONV_TAC COMPLEX_RING;
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPECL [`z:complex`; `w:complex`]) THEN ANTS_TAC THEN
+  ASM_REWRITE_TAC[ENDS_IN_SEGMENT] THEN MATCH_MP_TAC EQ_IMP THEN
+  BINOP_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[REAL_POW_ADD; real_div; REAL_POW_1] THEN REAL_ARITH_TAC] THEN
+  AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  SIMP_TAC[VSUM_CLAUSES_LEFT; LE_0; complex_pow; FACT; COMPLEX_DIV_1] THEN
+  REWRITE_TAC[SIMPLE_COMPLEX_ARITH `x * Cx(&1) + y = x <=> y = Cx(&0)`] THEN
+  REWRITE_TAC[GSYM COMPLEX_VEC_0] THEN MATCH_MP_TAC VSUM_EQ_0 THEN
+  INDUCT_TAC THEN
+  ASM_REWRITE_TAC[complex_pow; complex_div; COMPLEX_MUL_LZERO;
+                  COMPLEX_MUL_RZERO; COMPLEX_SUB_REFL; COMPLEX_VEC_0] THEN
+  REWRITE_TAC[IN_NUMSEG] THEN ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* The simplest special case.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_MVT = prove
+ (`!f f' s B.
+        convex s /\
+        (!z. z IN s ==> (f has_complex_derivative f' z) (at z within s)) /\
+        (!z. z IN s ==> norm (f' z) <= B)
+        ==> !w z. w IN s /\ z IN s ==> norm (f z - f w) <= B * norm (z - w)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`(\n. if n = 0 then f else f'):num->complex->complex`;
+                `0`; `s:complex->bool`; `B:real`] COMPLEX_TAYLOR) THEN
+  SIMP_TAC[NUMSEG_SING; VSUM_SING; LE; ARITH] THEN
+  REWRITE_TAC[complex_pow; REAL_POW_1; FACT; REAL_DIV_1] THEN
+  ASM_SIMP_TAC[COMPLEX_DIV_1; COMPLEX_MUL_RID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Something more like the traditional MVT for real components.              *)
+(* Could, perhaps should, sharpen this to derivatives inside the segment.    *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_MVT_LINE = prove
+ (`!f f' w z.
+        (!u. u IN segment[w,z]
+             ==> (f has_complex_derivative f'(u)) (at u))
+        ==> ?u. u IN segment[w,z] /\ Re(f z) - Re(f w) = Re(f'(u) * (z - w))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`(lift o Re) o (f:complex->complex) o
+     (\t. (&1 - drop t) % w + drop t % z)`;
+    `\u. (lift o Re) o
+         (\h. (f':complex->complex)((&1 - drop u) % w + drop u % z) * h) o
+         (\t. drop t % (z - w))`;
+    `vec 0:real^1`; `vec 1:real^1`]
+        MVT_VERY_SIMPLE) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[DROP_VEC; REAL_POS] THEN
+    X_GEN_TAC `t:real^1` THEN STRIP_TAC THEN
+    MATCH_MP_TAC HAS_DERIVATIVE_AT_WITHIN THEN
+    MATCH_MP_TAC DIFF_CHAIN_AT THEN CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC HAS_DERIVATIVE_LINEAR THEN
+      REWRITE_TAC[linear; LIFT_ADD; RE_ADD; LIFT_CMUL; RE_CMUL; o_DEF]] THEN
+    MATCH_MP_TAC DIFF_CHAIN_AT THEN CONJ_TAC THENL
+     [REWRITE_TAC[VECTOR_ARITH `(&1 - t) % w + t % z = w + t % (z - w)`] THEN
+      GEN_REWRITE_TAC (RATOR_CONV o RAND_CONV o ABS_CONV)
+        [GSYM VECTOR_ADD_LID] THEN
+      MATCH_MP_TAC HAS_DERIVATIVE_ADD THEN
+      REWRITE_TAC[HAS_DERIVATIVE_CONST] THEN
+      MATCH_MP_TAC HAS_DERIVATIVE_LINEAR THEN
+      REWRITE_TAC[linear; DROP_ADD; DROP_CMUL] THEN
+      CONJ_TAC THEN VECTOR_ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[GSYM has_complex_derivative] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC;
+    REWRITE_TAC[o_THM; GSYM LIFT_SUB; LIFT_EQ; DROP_VEC; VECTOR_SUB_RZERO] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[VECTOR_MUL_LID; VECTOR_MUL_LZERO] THEN
+    REWRITE_TAC[VECTOR_ADD_LID; VECTOR_ADD_RID] THEN
+    DISCH_THEN(X_CHOOSE_THEN `t:real^1` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(&1 - drop t) % w + drop t % z:complex`] THEN
+  ASM_REWRITE_TAC[segment; IN_ELIM_THM] THEN
+  EXISTS_TAC `drop t` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+  REWRITE_TAC[DROP_VEC]);;
+
+let COMPLEX_TAYLOR_MVT = prove
+ (`!f w z n.
+    (!i x. x IN segment[w,z] /\ i <= n
+           ==> ((f i) has_complex_derivative f (i + 1) x) (at x))
+    ==> ?u. u IN segment[w,z] /\
+            Re(f 0 z) =
+            Re(vsum (0..n) (\i. f i w * (z - w) pow i / Cx(&(FACT i))) +
+               (f (n + 1) u * (z - u) pow n / Cx (&(FACT n))) * (z - w))`,
+  let lemma = prove
+   (`!f:num->real^N.
+          vsum (0..n) f = f 0 - f (n + 1) + vsum (0..n) (\i. f (i + 1))`,
+    REWRITE_TAC[GSYM(REWRITE_CONV[o_DEF] `(f:num->real^N) o (\i. i + 1)`)] THEN
+    ASM_SIMP_TAC[GSYM VSUM_IMAGE; EQ_ADD_RCANCEL; FINITE_NUMSEG] THEN
+    REWRITE_TAC[GSYM NUMSEG_OFFSET_IMAGE] THEN
+    SIMP_TAC[VSUM_CLAUSES_LEFT; LE_0] THEN
+    REWRITE_TAC[VSUM_CLAUSES_NUMSEG; GSYM ADD1] THEN
+    REWRITE_TAC[ARITH; ARITH_RULE `1 <= SUC n`] THEN VECTOR_ARITH_TAC) in
+  REPEAT STRIP_TAC THEN MP_TAC(SPECL
+   [`(\w. vsum (0..n) (\i. f i w * (z - w) pow i / Cx(&(FACT i))))`;
+    `\w. (f:num->complex->complex) (n + 1) w *
+         (z - w) pow n / Cx(&(FACT n))`;
+    `w:complex`; `z:complex`]
+    COMPLEX_MVT_LINE) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[CONVEX_SEGMENT] THEN X_GEN_TAC `u:complex` THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN
+     `((\u. vsum (0..n) (\i. f i u * (z - u) pow i / Cx (&(FACT i))))
+       has_complex_derivative
+       vsum (0..n) (\i. f i u * (-- Cx(&i) * (z - u) pow (i - 1)) /
+                                Cx(&(FACT i)) +
+                        f (i + 1) u * (z - u) pow i / Cx (&(FACT i))))
+      (at u)`
+    MP_TAC THENL
+     [MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_VSUM THEN
+      REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_MUL_AT THEN
+      ASM_SIMP_TAC[ETA_AX] THEN W(MP_TAC o COMPLEX_DIFF_CONV o snd) THEN
+      MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+      REWRITE_TAC[complex_div] THEN CONV_TAC COMPLEX_RING;
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[] THEN MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN
+    AP_TERM_TAC THEN REWRITE_TAC[VSUM_ADD_NUMSEG] THEN
+    GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [lemma] THEN
+    REWRITE_TAC[GSYM VSUM_ADD_NUMSEG; GSYM COMPLEX_ADD_ASSOC] THEN
+    REWRITE_TAC[ADD_SUB] THEN REWRITE_TAC[GSYM ADD1; FACT] THEN
+    REWRITE_TAC[GSYM REAL_OF_NUM_SUC; GSYM REAL_OF_NUM_MUL; CX_MUL] THEN
+    REWRITE_TAC[complex_div; COMPLEX_INV_MUL; GSYM COMPLEX_MUL_ASSOC] THEN
+    REWRITE_TAC[COMPLEX_RING
+      `--a * b * inv a * c:complex = --(a * inv a) * b * c`] THEN
+    SIMP_TAC[COMPLEX_MUL_RINV; CX_INJ; REAL_ARITH `~(&n + &1 = &0)`] THEN
+    REWRITE_TAC[COMPLEX_MUL_LNEG; COMPLEX_MUL_RNEG; COMPLEX_MUL_LID] THEN
+    REWRITE_TAC[COMPLEX_ADD_LINV; GSYM COMPLEX_VEC_0; VSUM_0] THEN
+    REWRITE_TAC[COMPLEX_VEC_0; COMPLEX_ADD_RID] THEN
+    REWRITE_TAC[COMPLEX_MUL_LZERO; COMPLEX_MUL_RZERO; COMPLEX_NEG_0] THEN
+    CONV_TAC COMPLEX_RING;
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:complex` THEN
+  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[RE_ADD] THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[REAL_ADD_SYM] REAL_EQ_SUB_RADD] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  SIMP_TAC[VSUM_CLAUSES_LEFT; LE_0; complex_pow; FACT; COMPLEX_DIV_1] THEN
+  REWRITE_TAC[COMPLEX_MUL_RID; RE_ADD] THEN
+  MATCH_MP_TAC(REAL_ARITH `Re x = &0 ==> y = y + Re x`) THEN
+  SIMP_TAC[RE_VSUM; FINITE_NUMSEG] THEN
+  MATCH_MP_TAC SUM_EQ_0_NUMSEG THEN
+  INDUCT_TAC THEN REWRITE_TAC[ARITH] THEN
+  REWRITE_TAC[COMPLEX_SUB_REFL; complex_pow; complex_div] THEN
+  REWRITE_TAC[COMPLEX_MUL_LZERO; COMPLEX_MUL_RZERO; RE_CX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Further useful properties of complex conjugation.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_CNJ = prove
+ (`!net f l. ((\x. cnj(f x)) --> cnj l) net <=> (f --> l) net`,
+  REWRITE_TAC[LIM; dist; GSYM CNJ_SUB; COMPLEX_NORM_CNJ]);;
+
+let SUMS_CNJ = prove
+ (`!net f l. ((\x. cnj(f x)) sums cnj l) net <=> (f sums l) net`,
+  SIMP_TAC[sums; LIM_CNJ; GSYM CNJ_VSUM; FINITE_INTER_NUMSEG]);;
+
+let CONTINUOUS_WITHIN_CNJ = prove
+ (`!s z. cnj continuous (at z within s)`,
+  SIMP_TAC[LINEAR_CONTINUOUS_WITHIN; LINEAR_CNJ]);;
+
+let CONTINUOUS_AT_CNJ = prove
+ (`!z. cnj continuous (at z)`,
+  SIMP_TAC[LINEAR_CONTINUOUS_AT; LINEAR_CNJ]);;
+
+let CONTINUOUS_ON_CNJ = prove
+ (`!s. cnj continuous_on s`,
+  SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_CNJ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some limit theorems about real part of real series etc.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_LIM = prove
+ (`!net:(A)net f l.
+        (f --> l) net /\ ~(trivial_limit net) /\
+        (?b. (?a. netord net a b) /\ !a. netord net a b ==> real(f a))
+        ==> real l`,
+  REWRITE_TAC[IM_DEF; real] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC LIM_COMPONENT_EQ THEN
+  REWRITE_TAC[eventually; DIMINDEX_2; ARITH] THEN ASM_MESON_TAC[]);;
+
+let REAL_LIM_SEQUENTIALLY = prove
+ (`!f l. (f --> l) sequentially /\ (?N. !n. n >= N ==> real(f n))
+         ==> real l`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(ISPEC `sequentially` REAL_LIM) THEN
+  REWRITE_TAC[SEQUENTIALLY; TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+  ASM_MESON_TAC[GE_REFL]);;
+
+let REAL_SERIES = prove
+ (`!f l s. (f sums l) s /\ (!n. real(f n)) ==> real l`,
+  REWRITE_TAC[sums] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_LIM_SEQUENTIALLY THEN
+  EXISTS_TAC `\n. vsum(s INTER (0..n)) f :complex` THEN
+  ASM_SIMP_TAC[REAL_VSUM; FINITE_INTER; FINITE_NUMSEG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Often convenient to use comparison with real limit of complex type.       *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_NULL_COMPARISON_COMPLEX = prove
+ (`!net:(A)net f g.
+        eventually (\x. norm(f x) <= norm(g x)) net /\
+        (g --> Cx(&0)) net
+        ==> (f --> Cx(&0)) net`,
+  REWRITE_TAC[GSYM COMPLEX_VEC_0] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(ISPEC `net:(A)net` LIM_NULL_COMPARISON) THEN
+  EXISTS_TAC `norm o (g:A->complex)` THEN
+  ASM_REWRITE_TAC[o_THM; GSYM LIM_NULL_NORM]);;
+
+let LIM_NULL_COMPARISON_COMPLEX_RE = prove
+ (`!net:(A)net f g.
+        eventually (\x. norm(f x) <= Re(g x)) net /\
+        (g --> Cx(&0)) net
+        ==> (f --> Cx(&0)) net`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(ISPEC `net:(A)net` LIM_NULL_COMPARISON_COMPLEX) THEN
+  EXISTS_TAC `g:A->complex` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ_ALT] EVENTUALLY_MONO)) THEN
+  REWRITE_TAC[] THEN
+  MESON_TAC[COMPLEX_NORM_GE_RE_IM; REAL_ABS_LE; REAL_LE_TRANS]);;
+
+let SERIES_COMPARISON_COMPLEX = prove
+ (`!f:num->real^N g s.
+        summable s g /\
+        (!n. n IN s ==> real(g n) /\ &0 <= Re(g n)) /\
+        (?N. !n. n >= N /\ n IN s ==> norm(f n) <= norm(g n))
+        ==> summable s f`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[summable] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  MATCH_MP_TAC SERIES_COMPARISON THEN
+  EXISTS_TAC `\n. norm((g:num->complex) n)` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `l:complex` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `lift(Re l)` THEN MATCH_MP_TAC SUMS_EQ THEN
+  EXISTS_TAC `\i:num. lift(Re(g i))` THEN
+  ASM_SIMP_TAC[REAL_NORM_POS; o_DEF] THEN
+  REWRITE_TAC[RE_DEF] THEN MATCH_MP_TAC SERIES_COMPONENT THEN
+  ASM_REWRITE_TAC[DIMINDEX_2; ARITH]);;
+
+let SERIES_COMPARISON_UNIFORM_COMPLEX = prove
+ (`!f:A->num->real^N g P s.
+        summable s g /\
+        (!n. n IN s ==> real(g n) /\ &0 <= Re(g n)) /\
+        (?N. !n x. N <= n /\ n IN s /\ P x ==> norm(f x n) <= norm(g n))
+        ==> ?l. !e. &0 < e
+                    ==> ?N. !n x. N <= n /\ P x
+                                  ==> dist(vsum(s INTER (0..n)) (f x),l x) <
+                                       e`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[summable] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  MATCH_MP_TAC SERIES_COMPARISON_UNIFORM THEN
+  EXISTS_TAC `\n. norm((g:num->complex) n)` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `l:complex` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `lift(Re l)` THEN MATCH_MP_TAC SUMS_EQ THEN
+  EXISTS_TAC `\i:num. lift(Re(g i))` THEN
+  ASM_SIMP_TAC[REAL_NORM_POS; o_DEF] THEN
+  REWRITE_TAC[RE_DEF] THEN MATCH_MP_TAC SERIES_COMPONENT THEN
+  ASM_REWRITE_TAC[DIMINDEX_2; ARITH]);;
+
+let SUMMABLE_SUBSET_COMPLEX = prove
+ (`!x s t. (!n. n IN s ==> real(x n) /\ &0 <= Re(x n)) /\
+           summable s x /\ t SUBSET s
+           ==> summable t x`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUMMABLE_SUBSET THEN
+  EXISTS_TAC `s:num->bool` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC SERIES_COMPARISON_COMPLEX THEN
+  EXISTS_TAC `x:num->complex` THEN ASM_REWRITE_TAC[] THEN
+  MESON_TAC[REAL_LE_REFL; NORM_0; NORM_POS_LE]);;
+
+let SERIES_ABSCONV_IMP_CONV = prove
+ (`!x:num->real^N k. summable k (\n. Cx(norm(x n))) ==> summable k x`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SERIES_COMPARISON_COMPLEX THEN
+  EXISTS_TAC `\n:num. Cx(norm(x n:real^N))` THEN
+  ASM_REWRITE_TAC[REAL_CX; RE_CX; NORM_POS_LE; COMPLEX_NORM_CX] THEN
+  REWRITE_TAC[REAL_ABS_NORM; REAL_LE_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex-valued geometric series.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let SUMS_GP = prove
+ (`!n z. norm(z) < &1
+         ==> ((\k. z pow k) sums (z pow n / (Cx(&1) - z))) (from n)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[SERIES_FROM; VSUM_GP] THEN
+  ASM_CASES_TAC `z = Cx(&1)` THENL
+   [ASM_MESON_TAC[COMPLEX_NORM_NUM; REAL_LT_REFL]; ALL_TAC] THEN
+  MATCH_MP_TAC LIM_TRANSFORM_EVENTUALLY THEN
+  EXISTS_TAC `\m. (z pow n - z pow SUC m) / (Cx (&1) - z)` THEN CONJ_TAC THENL
+   [ASM_REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+    EXISTS_TAC `n:num` THEN SIMP_TAC[GSYM NOT_LE];
+    MATCH_MP_TAC LIM_COMPLEX_DIV THEN
+    ASM_REWRITE_TAC[COMPLEX_SUB_0; LIM_CONST] THEN
+    GEN_REWRITE_TAC (RATOR_CONV o RAND_CONV) [GSYM COMPLEX_SUB_RZERO] THEN
+    MATCH_MP_TAC LIM_SUB THEN REWRITE_TAC[LIM_CONST] THEN
+    REWRITE_TAC[LIM_SEQUENTIALLY; GSYM COMPLEX_VEC_0] THEN
+    REWRITE_TAC[NORM_ARITH `dist(x,vec 0) = norm x`] THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    MP_TAC(SPECL [`norm(z:complex)`; `e:real`] REAL_ARCH_POW_INV) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `n:num` THEN DISCH_TAC THEN X_GEN_TAC `m:num` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `x < e ==> y <= x ==> y < e`)) THEN
+    REWRITE_TAC[COMPLEX_NORM_POW] THEN MATCH_MP_TAC REAL_POW_MONO_INV THEN
+    ASM_SIMP_TAC[NORM_POS_LE; REAL_LT_IMP_LE] THEN
+    UNDISCH_TAC `n:num <= m` THEN ARITH_TAC]);;
+
+let SUMMABLE_GP = prove
+ (`!z k. norm(z) < &1 ==> summable k (\n. z pow n)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SUMMABLE_SUBSET THEN EXISTS_TAC `(:num)` THEN
+  REWRITE_TAC[SUBSET_UNIV] THEN
+  MATCH_MP_TAC SERIES_COMPARISON_COMPLEX THEN
+  EXISTS_TAC `\n. Cx(norm(z:complex) pow n)` THEN
+  REWRITE_TAC[REAL_CX; RE_CX; COMPLEX_NORM_CX] THEN
+  SIMP_TAC[REAL_POW_LE; NORM_POS_LE] THEN CONJ_TAC THENL
+   [REWRITE_TAC[summable; GSYM FROM_0; CX_POW] THEN
+    EXISTS_TAC `Cx(norm z) pow 0 / (Cx(&1) - Cx(norm(z:complex)))` THEN
+    MATCH_MP_TAC SUMS_GP THEN
+    ASM_REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_NORM];
+    EXISTS_TAC `0` THEN REPEAT STRIP_TAC THEN
+    COND_CASES_TAC THEN
+    ASM_SIMP_TAC[REAL_ABS_POW; REAL_ABS_NORM; REAL_LE_REFL; NORM_POS_LE;
+                 COMPLEX_NORM_POW; NORM_0; REAL_ABS_POS; REAL_POW_LE]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex version (the usual one) of Dirichlet convergence test.            *)
+(* ------------------------------------------------------------------------- *)
+
+let SERIES_DIRICHLET_COMPLEX_GEN = prove
+ (`!f g N k m p l.
+        bounded {vsum (m..n) f | n IN (:num)} /\
+        summable (from p) (\n. Cx(norm(g(n + 1) - g(n)))) /\
+        ((\n. vsum(1..n) f * g(n + 1)) --> l) sequentially
+        ==> summable (from k) (\n. f(n) * g(n))`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+  MATCH_MP_TAC SERIES_DIRICHLET_BILINEAR THEN
+  MAP_EVERY EXISTS_TAC [`m:num`; `p:num`; `l:complex`] THEN
+  ASM_REWRITE_TAC[BILINEAR_COMPLEX_MUL] THEN
+  ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [summable]) THEN
+  REWRITE_TAC[summable; SERIES_CAUCHY] THEN
+  SIMP_TAC[GSYM(REWRITE_RULE[o_DEF] LIFT_SUM); FINITE_NUMSEG; FINITE_INTER;
+           VSUM_CX; NORM_LIFT; COMPLEX_NORM_CX]);;
+
+let SERIES_DIRICHLET_COMPLEX = prove
+ (`!f g N k m.
+        bounded {vsum (m..n) f | n IN (:num)} /\
+        (!n. real(g n)) /\
+        (!n. N <= n ==> Re(g(n + 1)) <= Re(g n)) /\
+        (g --> Cx(&0)) sequentially
+        ==> summable (from k) (\n. f(n) * g(n))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:num->complex`; `\n:num. Re(g n)`; `N:num`; `k:num`;
+                 `m:num`] SERIES_DIRICHLET) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIM_SEQUENTIALLY]) THEN
+    REWRITE_TAC[LIM_SEQUENTIALLY; o_THM; dist; VECTOR_SUB_RZERO] THEN
+    REWRITE_TAC[COMPLEX_SUB_RZERO; NORM_LIFT] THEN
+    MESON_TAC[COMPLEX_NORM_GE_RE_IM; REAL_LET_TRANS];
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+    REWRITE_TAC[COMPLEX_CMUL; FUN_EQ_THM] THEN
+    ASM_MESON_TAC[REAL; COMPLEX_MUL_SYM]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Versions with explicit bounds are sometimes useful.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let SERIES_DIRICHLET_COMPLEX_VERY_EXPLICIT = prove
+ (`!f g B p.
+        &0 < B /\ 1 <= p /\
+        (!m n. p <= m ==> norm(vsum(m..n) f) <= B) /\
+        (!n. p <= n ==> real(g n) /\ &0 <= Re(g n)) /\
+        (!n. p <= n ==> Re(g(n + 1)) <= Re(g n))
+        ==> !m n. p <= m
+                  ==> norm(vsum(m..n) (\k. f k * g k)) <= &2 * B * norm(g m)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC
+   `norm(vsum(m..n) (\k. (vsum(p..k) f - vsum(p..(k-1)) f) * g k))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_EQ_IMP_LE THEN AP_TERM_TAC THEN
+    MATCH_MP_TAC VSUM_EQ_NUMSEG THEN X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+    REWRITE_TAC[] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    SUBGOAL_THEN `p:num <= k`
+     (fun th -> SIMP_TAC[GSYM(MATCH_MP NUMSEG_RREC th)])
+    THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+    SIMP_TAC[VSUM_CLAUSES; FINITE_NUMSEG; IN_NUMSEG] THEN
+    COND_CASES_TAC THENL [ASM_ARITH_TAC; VECTOR_ARITH_TAC];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+  REWRITE_TAC[MATCH_MP BILINEAR_VSUM_PARTIAL_PRE BILINEAR_COMPLEX_MUL] THEN
+  COND_CASES_TAC THEN
+  ASM_SIMP_TAC[NORM_0; REAL_LE_MUL; REAL_POS; REAL_LT_IMP_LE; NORM_POS_LE] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `norm(c) <= e - norm(a) - norm(b) ==> norm(a - b - c) <= e`) THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum (m..n) (\k. norm(g(k + 1) - g(k)) * B)` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC VSUM_NORM_LE THEN REWRITE_TAC[IN_NUMSEG; FINITE_NUMSEG] THEN
+    X_GEN_TAC `k:num` THEN STRIP_TAC THEN REWRITE_TAC[COMPLEX_NORM_MUL] THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN
+    ASM_SIMP_TAC[REAL_LE_REFL; LE_REFL; NORM_POS_LE];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum(m..n) (\k. Re(g(k)) - Re(g(k + 1))) * B` THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[SUM_RMUL; REAL_LE_RMUL_EQ] THEN
+    MATCH_MP_TAC REAL_EQ_IMP_LE THEN MATCH_MP_TAC SUM_EQ_NUMSEG THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    SUBGOAL_THEN `p <= i /\ p <= i + 1` ASSUME_TAC THENL
+     [ASM_ARITH_TAC; ALL_TAC] THEN
+    ASM_SIMP_TAC[REAL_NORM; REAL_SUB; RE_SUB] THEN
+    ASM_SIMP_TAC[REAL_ARITH `abs(x - y) = y - x <=> x <= y`];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[SUM_DIFFS; COMPLEX_NORM_MUL] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `w * n1 <= w * B /\ z * n2 <= z * B /\ &0 <= B * (&2 * y - (x + w + z))
+    ==> x * B <= &2 * B * y - w * n1 - z * n2`) THEN
+  REPEAT(CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_LE_LMUL THEN
+    ASM_SIMP_TAC[NORM_POS_LE; LE_REFL]; ALL_TAC]) THEN
+  MATCH_MP_TAC REAL_LE_MUL THEN ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+  SUBGOAL_THEN
+   `p <= m /\ p <= m + 1 /\ p <= n /\ p <= n + 1`
+  STRIP_ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_NORM; real_abs] THEN REAL_ARITH_TAC);;
+
+let SERIES_DIRICHLET_COMPLEX_EXPLICIT = prove
+ (`!f g p q.
+           1 <= p /\
+           bounded {vsum (q..n) f | n IN (:num)} /\
+           (!n. p <= n ==> real(g n) /\ &0 <= Re(g n)) /\
+           (!n. p <= n ==> Re(g(n + 1)) <= Re(g n))
+           ==> ?B. &0 < B /\
+                   !m n. p <= m
+                         ==> norm(vsum(m..n) (\k. f k * g k))
+                                 <= B * norm(g m)`,
+  REWRITE_TAC[FORALL_AND_THM] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP BOUNDED_PARTIAL_SUMS) THEN
+  SIMP_TAC[BOUNDED_POS; IN_ELIM_THM; IN_UNIV; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[MESON[] `(!x a b. x = f a b ==> p a b) <=> (!a b. p a b)`] THEN
+  X_GEN_TAC `B:real` THEN STRIP_TAC THEN EXISTS_TAC `&2 * B` THEN
+  ASM_SIMP_TAC[GSYM REAL_MUL_ASSOC; REAL_LT_MUL; REAL_OF_NUM_LT; ARITH] THEN
+  MATCH_MP_TAC SERIES_DIRICHLET_COMPLEX_VERY_EXPLICIT THEN
+  ASM_SIMP_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relations among convergence and absolute convergence for power series.    *)
+(* ------------------------------------------------------------------------- *)
+
+let ABEL_LEMMA = prove
+ (`!a M r r0.
+        &0 <= r /\ r < r0 /\
+        (!n. n IN k ==> norm(a n) * r0 pow n <= M)
+        ==> summable k (\n. Cx(norm(a(n)) * r pow n))`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `&0 < r0` ASSUME_TAC THENL
+   [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_CASES_TAC `k:num->bool = {}` THEN ASM_REWRITE_TAC[SUMMABLE_TRIVIAL] THEN
+  SUBGOAL_THEN `&0 <= M` ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `i:num`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= x ==> x <= y ==> &0 <= y`) THEN
+    MATCH_MP_TAC REAL_LE_MUL THEN
+    ASM_SIMP_TAC[NORM_POS_LE; REAL_POW_LE; REAL_LT_IMP_LE];
+    ALL_TAC] THEN
+  MATCH_MP_TAC SERIES_COMPARISON_COMPLEX THEN
+  EXISTS_TAC `\n. Cx(M * (r / r0) pow n)` THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[CX_MUL; CX_POW] THEN MATCH_MP_TAC SUMMABLE_COMPLEX_LMUL THEN
+    MATCH_MP_TAC SUMMABLE_GP THEN REWRITE_TAC[COMPLEX_NORM_CX] THEN
+    ASM_SIMP_TAC[REAL_ABS_DIV; real_abs; REAL_LT_IMP_LE] THEN
+    ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_MUL_LID];
+    REWRITE_TAC[REAL_CX; RE_CX] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_MUL THEN ASM_REWRITE_TAC[] THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; REAL_POW_LE; REAL_LT_IMP_LE];
+    EXISTS_TAC `0` THEN REWRITE_TAC[COMPLEX_NORM_CX] THEN REPEAT STRIP_TAC THEN
+    REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_POW; REAL_ABS_NORM; REAL_ABS_DIV] THEN
+    ASM_SIMP_TAC[real_abs; REAL_LT_IMP_LE; REAL_POW_DIV] THEN
+    REWRITE_TAC[real_div; REAL_MUL_ASSOC] THEN
+    ASM_SIMP_TAC[GSYM real_div; REAL_LE_RDIV_EQ; REAL_POW_LT] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `(a * b) * c:real = (a * c) * b`] THEN
+    ASM_SIMP_TAC[REAL_LE_RMUL; REAL_POW_LE; REAL_LT_IMP_LE]]);;
+
+let POWER_SERIES_CONV_IMP_ABSCONV = prove
+ (`!a k w z.
+        summable k (\n. a(n) * z pow n) /\ norm(w) < norm(z)
+        ==> summable k (\n. Cx(norm(a(n) * w pow n)))`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_POW] THEN
+  MATCH_MP_TAC ABEL_LEMMA THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP SUMMABLE_IMP_BOUNDED) THEN
+  REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `B:real` THEN STRIP_TAC THEN
+  EXISTS_TAC `norm(z:complex)` THEN REWRITE_TAC[NORM_POS_LE] THEN
+  ASM_REWRITE_TAC[GSYM COMPLEX_NORM_POW; GSYM COMPLEX_NORM_MUL]);;
+
+let POWER_SERIES_CONV_IMP_ABSCONV_WEAK = prove
+ (`!a k w z.
+        summable k (\n. a(n) * z pow n) /\ norm(w) < norm(z)
+        ==> summable k (\n. Cx(norm(a(n))) * w pow n)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SERIES_COMPARISON_COMPLEX THEN
+  EXISTS_TAC `\n. Cx(norm(a(n) * w pow n))` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC POWER_SERIES_CONV_IMP_ABSCONV THEN
+    EXISTS_TAC `z:complex` THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[REAL_CX; RE_CX; NORM_POS_LE] THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX; REAL_ABS_NORM;
+              REAL_ABS_MUL; REAL_LE_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Comparing sums and "integrals" via complex antiderivatives.               *)
+(* ------------------------------------------------------------------------- *)
+
+let SUM_INTEGRAL_UBOUND_INCREASING = prove
+ (`!f g m n.
+      m <= n /\
+      (!x. x IN segment[Cx(&m),Cx(&n + &1)]
+           ==> (g has_complex_derivative f(x)) (at x)) /\
+      (!x y. &m <= x /\ x <= y /\ y <= &n + &1 ==> Re(f(Cx x)) <= Re(f(Cx y)))
+      ==> sum(m..n) (\k. Re(f(Cx(&k)))) <= Re(g(Cx(&n + &1)) - g(Cx(&m)))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `--sum(m..n) (\k. Re(g(Cx(&k))) - Re(g(Cx(&(k + 1)))))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_REWRITE_TAC[SUM_DIFFS; RE_SUB; REAL_NEG_SUB; REAL_OF_NUM_ADD] THEN
+    REWRITE_TAC[REAL_LE_REFL]] THEN
+  REWRITE_TAC[GSYM SUM_NEG] THEN MATCH_MP_TAC SUM_LE_NUMSEG THEN
+  REWRITE_TAC[REAL_NEG_SUB] THEN X_GEN_TAC `r:num` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`g:complex->complex`; `f:complex->complex`;
+                 `Cx(&r)`; `Cx(&r + &1)`] COMPLEX_MVT_LINE) THEN
+  ANTS_TAC THENL
+   [X_GEN_TAC `u:complex` THEN STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    UNDISCH_TAC `u IN segment[Cx(&r),Cx(&r + &1)]` THEN
+    REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+    SPEC_TAC(`u:complex`,`u:complex`) THEN REWRITE_TAC[GSYM SUBSET] THEN
+    MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_CONVEX_HULL] THEN
+    REWRITE_TAC[SUBSET; IN_INSERT; NOT_IN_EMPTY; GSYM SEGMENT_CONVEX_HULL] THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[IN_SEGMENT_CX] THEN
+    REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE] THEN
+    ASM_ARITH_TAC;
+    REWRITE_TAC[GSYM REAL_OF_NUM_ADD] THEN DISCH_THEN(X_CHOOSE_THEN `u:complex`
+     (CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC)) THEN
+    REWRITE_TAC[CX_ADD; COMPLEX_RING `y * ((x + Cx(&1)) - x) = y`] THEN
+    SUBGOAL_THEN `?y. u = Cx y` (CHOOSE_THEN SUBST_ALL_TAC) THENL
+     [ASM_MESON_TAC[REAL_SEGMENT; REAL_CX; REAL]; ALL_TAC] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_SEGMENT_CX]) THEN
+    REPEAT(FIRST_X_ASSUM
+     (MP_TAC o GEN_REWRITE_RULE I [GSYM REAL_OF_NUM_LE])) THEN
+    REAL_ARITH_TAC]);;
+
+let SUM_INTEGRAL_UBOUND_DECREASING = prove
+ (`!f g m n.
+      m <= n /\
+      (!x. x IN segment[Cx(&m - &1),Cx(&n)]
+           ==> (g has_complex_derivative f(x)) (at x)) /\
+      (!x y. &m - &1 <= x /\ x <= y /\ y <= &n ==> Re(f(Cx y)) <= Re(f(Cx x)))
+      ==> sum(m..n) (\k. Re(f(Cx(&k)))) <= Re(g(Cx(&n)) - g(Cx(&m - &1)))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+   `--sum(m..n) (\k. Re(g(Cx(&(k) - &1))) - Re(g(Cx(&(k+1) - &1))))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_REWRITE_TAC[SUM_DIFFS; REAL_NEG_SUB] THEN
+    REWRITE_TAC[GSYM REAL_OF_NUM_ADD; GSYM REAL_OF_NUM_SUB] THEN
+    REWRITE_TAC[RE_SUB; REAL_ARITH `(x + &1) - &1 = x`; REAL_LE_REFL]] THEN
+  REWRITE_TAC[GSYM SUM_NEG] THEN MATCH_MP_TAC SUM_LE_NUMSEG THEN
+  REWRITE_TAC[REAL_NEG_SUB] THEN X_GEN_TAC `r:num` THEN STRIP_TAC THEN
+  REWRITE_TAC[GSYM REAL_OF_NUM_ADD; REAL_ARITH `(x + &1) - &1 = x`] THEN
+  MP_TAC(ISPECL [`g:complex->complex`; `f:complex->complex`;
+                 `Cx(&r - &1)`; `Cx(&r)`] COMPLEX_MVT_LINE) THEN
+  ANTS_TAC THENL
+   [X_GEN_TAC `u:complex` THEN STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    UNDISCH_TAC `u IN segment[Cx(&r - &1),Cx(&r)]` THEN
+    REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+    SPEC_TAC(`u:complex`,`u:complex`) THEN REWRITE_TAC[GSYM SUBSET] THEN
+    MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_CONVEX_HULL] THEN
+    REWRITE_TAC[SUBSET; IN_INSERT; NOT_IN_EMPTY; GSYM SEGMENT_CONVEX_HULL] THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[IN_SEGMENT_CX] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN
+    REWRITE_TAC[GSYM REAL_OF_NUM_LE] THEN REAL_ARITH_TAC;
+    REWRITE_TAC[GSYM REAL_OF_NUM_ADD] THEN DISCH_THEN(X_CHOOSE_THEN `u:complex`
+     (CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC)) THEN
+    REWRITE_TAC[CX_SUB; COMPLEX_RING `y * (x - (x - Cx(&1))) = y`] THEN
+    SUBGOAL_THEN `?y. u = Cx y` (CHOOSE_THEN SUBST_ALL_TAC) THENL
+     [ASM_MESON_TAC[REAL_SEGMENT; REAL_CX; REAL]; ALL_TAC] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_SEGMENT_CX]) THEN
+    REPEAT(FIRST_X_ASSUM
+     (MP_TAC o GEN_REWRITE_RULE I [GSYM REAL_OF_NUM_LE])) THEN
+    REAL_ARITH_TAC]);;
+
+let SUM_INTEGRAL_LBOUND_INCREASING = prove
+ (`!f g m n.
+      m <= n /\
+      (!x. x IN segment[Cx(&m - &1),Cx(&n)]
+           ==> (g has_complex_derivative f(x)) (at x)) /\
+      (!x y. &m - &1 <= x /\ x <= y /\ y <= &n ==> Re(f(Cx x)) <= Re(f(Cx y)))
+      ==> Re(g(Cx(&n)) - g(Cx(&m - &1))) <= sum(m..n) (\k. Re(f(Cx(&k))))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\z. --((f:complex->complex) z)`;
+                 `\z. --((g:complex->complex) z)`;
+                 `m:num`; `n:num`] SUM_INTEGRAL_UBOUND_DECREASING) THEN
+  REWRITE_TAC[RE_NEG; RE_SUB; SUM_NEG; REAL_LE_NEG2;
+              REAL_ARITH `--x - --y:real = --(x - y)`] THEN
+  ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_NEG]);;
+
+let SUM_INTEGRAL_LBOUND_DECREASING = prove
+ (`!f g m n.
+      m <= n /\
+      (!x. x IN segment[Cx(&m),Cx(&n + &1)]
+           ==> (g has_complex_derivative f(x)) (at x)) /\
+      (!x y. &m <= x /\ x <= y /\ y <= &n + &1 ==> Re(f(Cx y)) <= Re(f(Cx x)))
+      ==> Re(g(Cx(&n + &1)) - g(Cx(&m))) <= sum(m..n) (\k. Re(f(Cx(&k))))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\z. --((f:complex->complex) z)`;
+                 `\z. --((g:complex->complex) z)`;
+                 `m:num`; `n:num`] SUM_INTEGRAL_UBOUND_INCREASING) THEN
+  REWRITE_TAC[RE_NEG; RE_SUB; SUM_NEG; REAL_LE_NEG2;
+              REAL_ARITH `--x - --y:real = --(x - y)`] THEN
+  ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_NEG]);;
+
+let SUM_INTEGRAL_BOUNDS_INCREASING = prove
+ (`!f g m n.
+         m <= n /\
+         (!x. x IN segment[Cx(&m - &1),Cx (&n + &1)]
+              ==> (g has_complex_derivative f x) (at x)) /\
+         (!x y.
+              &m - &1 <= x /\ x <= y /\ y <= &n + &1
+              ==> Re(f(Cx x)) <= Re(f(Cx y)))
+         ==> Re(g(Cx(&n)) - g(Cx(&m - &1))) <= sum(m..n) (\k. Re(f(Cx(&k)))) /\
+             sum (m..n) (\k. Re(f(Cx(&k)))) <= Re(g(Cx(&n + &1)) - g(Cx(&m)))`,
+  REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC SUM_INTEGRAL_LBOUND_INCREASING;
+    MATCH_MP_TAC SUM_INTEGRAL_UBOUND_INCREASING] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_SEGMENT_CX_GEN; GSYM REAL_OF_NUM_LE]) THEN
+  REWRITE_TAC[IN_SEGMENT_CX_GEN] THEN ASM_REAL_ARITH_TAC);;
+
+let SUM_INTEGRAL_BOUNDS_DECREASING = prove
+ (`!f g m n.
+      m <= n /\
+      (!x. x IN segment[Cx(&m - &1),Cx(&n + &1)]
+           ==> (g has_complex_derivative f(x)) (at x)) /\
+      (!x y. &m - &1 <= x /\ x <= y /\ y <= &n + &1
+             ==> Re(f(Cx y)) <= Re(f(Cx x)))
+      ==> Re(g(Cx(&n + &1)) - g(Cx(&m))) <= sum(m..n) (\k. Re(f(Cx(&k)))) /\
+          sum(m..n) (\k. Re(f(Cx(&k)))) <= Re(g(Cx(&n)) - g(Cx(&m - &1)))`,
+  REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC SUM_INTEGRAL_LBOUND_DECREASING;
+    MATCH_MP_TAC SUM_INTEGRAL_UBOUND_DECREASING] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_SEGMENT_CX_GEN; GSYM REAL_OF_NUM_LE]) THEN
+  REWRITE_TAC[IN_SEGMENT_CX_GEN] THEN ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relating different kinds of complex limits.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_INFINITY_SEQUENTIALLY_COMPLEX = prove
+ (`!f l. (f --> l) at_infinity ==> ((\n. f(Cx(&n))) --> l) sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[LIM_AT_INFINITY; LIM_SEQUENTIALLY] 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_TAC `B:real`) THEN
+  MP_TAC(ISPEC `B:real` REAL_ARCH_SIMPLE) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[COMPLEX_NORM_CX] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[GSYM REAL_OF_NUM_LE] THEN REAL_ARITH_TAC);;
+
+let LIM_ZERO_INFINITY_COMPLEX = prove
+ (`!f l. ((\x. f(Cx(&1) / x)) --> l) (at (Cx(&0))) ==> (f --> l) at_infinity`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[LIM_AT; LIM_AT_INFINITY] 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
+  REWRITE_TAC[dist; COMPLEX_SUB_RZERO; real_ge] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `&2 / d` THEN X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `inv(z):complex`) THEN
+  REWRITE_TAC[complex_div; COMPLEX_MUL_LINV; COMPLEX_INV_INV] THEN
+  REWRITE_TAC[COMPLEX_MUL_LID] THEN DISCH_THEN MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[COMPLEX_NORM_INV; REAL_LT_INV_EQ] THEN CONJ_TAC THENL
+   [UNDISCH_TAC `&2 / d <= norm(z:complex)` THEN
+    ASM_CASES_TAC `z = Cx(&0)` THEN ASM_REWRITE_TAC[COMPLEX_NORM_NZ] THEN
+    REWRITE_TAC[COMPLEX_NORM_0; REAL_NOT_LE] THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH];
+    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_INV_INV] THEN
+    MATCH_MP_TAC REAL_LT_INV2 THEN ASM_REWRITE_TAC[REAL_LT_INV_EQ] THEN
+    MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `&2 / d` THEN
+    ASM_REWRITE_TAC[] THEN REWRITE_TAC[real_div] THEN
+    ASM_REWRITE_TAC[REAL_LT_INV_EQ; REAL_ARITH `x < &2 * x <=> &0 < x`]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Transforming complex limits to real ones.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_COMPLEX_REAL = prove
+ (`!f g l m.
+         eventually (\n. Re(g n) = f n) sequentially /\
+         Re m = l /\
+         (g --> m) sequentially
+         ==> !e. &0 < e ==> ?N. !n. N <= n ==> abs(f n - l) < e`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[EVENTUALLY_SEQUENTIALLY; LIM_SEQUENTIALLY] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `N1:num`)
+   (CONJUNCTS_THEN2 (SUBST1_TAC o SYM) ASSUME_TAC)) THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[dist] THEN
+  DISCH_THEN(X_CHOOSE_TAC `N0:num`) THEN EXISTS_TAC `N0 + N1:num` THEN
+  X_GEN_TAC `n:num` THEN DISCH_THEN(STRIP_ASSUME_TAC o MATCH_MP (ARITH_RULE
+   `N0 + N1:num <= n ==> N0 <= n /\ N1 <= n`)) THEN
+  UNDISCH_THEN `!n. N0 <= n ==> norm ((g:num->complex) n - m) < e`
+   (MP_TAC o SPEC `n:num`) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `n:num`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[GSYM RE_SUB] THEN
+  MATCH_MP_TAC(REAL_ARITH `x <= y ==> y < e ==> x < e`) THEN
+  REWRITE_TAC[COMPLEX_NORM_GE_RE_IM]);;
+
+let LIM_COMPLEX_REAL_0 = prove
+ (`!f g. eventually (\n. Re(g n) = f n) sequentially /\
+         (g --> Cx(&0)) sequentially
+         ==> !e. &0 < e ==> ?N. !n. N <= n ==> abs(f n) < e`,
+  MP_TAC LIM_COMPLEX_REAL THEN
+  REPLICATE_TAC 2 (MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  DISCH_THEN(MP_TAC o SPECL [`&0`; `Cx(&0)`]) THEN
+  REWRITE_TAC[RE_CX; REAL_SUB_RZERO]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Uniform convergence of power series in a "Stolz angle".                   *)
+(* ------------------------------------------------------------------------- *)
+
+let POWER_SERIES_UNIFORM_CONVERGENCE_STOLZ_1 = prove
+ (`!M a s e.
+        summable s a /\ &0 < M /\ &0 < e
+        ==> eventually
+             (\n. !z. norm(Cx(&1) - z) <= M * (&1 - norm z)
+                      ==> norm(vsum (s INTER (0..n)) (\i. a i * z pow i) -
+                               infsum s (\i. a i * z pow i)) < e)
+             sequentially`,
+  let lemma = prove
+   (`!M w z. &0 < M /\ norm(w - z) <= M * (norm w - norm z) /\ ~(z = w)
+             ==> norm(z) < norm(w)`,
+    REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_LT_LE] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[REAL_LE_MUL_EQ; REAL_SUB_LE; NORM_POS_LE; REAL_LE_TRANS];
+      DISCH_THEN SUBST_ALL_TAC THEN
+      ASM_MESON_TAC[REAL_SUB_REFL; REAL_MUL_RZERO;NORM_LE_0; VECTOR_SUB_EQ]])
+  and lemma1 = prove
+   (`!m n. m < n
+           ==> vsum (m..n) (\i. a i * z pow i) =
+               (Cx(&1) - z) * vsum(m..n-1) (\i. vsum (m..i) a * z pow i) +
+               vsum(m..n) a * z pow n`,
+    GEN_TAC THEN INDUCT_TAC THEN REWRITE_TAC[NOT_SUC; SUC_SUB1] THEN
+    SIMP_TAC[VSUM_CLAUSES_NUMSEG; LT; LT_IMP_LE] THEN STRIP_TAC THENL
+     [ASM_REWRITE_TAC[VSUM_SING_NUMSEG; complex_pow] THEN CONV_TAC COMPLEX_RING;
+      ASM_SIMP_TAC[] THEN UNDISCH_TAC `m:num < n` THEN
+      POP_ASSUM(K ALL_TAC)] THEN
+    SPEC_TAC(`n:num`,`n:num`) THEN
+    INDUCT_TAC THEN REWRITE_TAC[CONJUNCT1 LT] THEN POP_ASSUM(K ALL_TAC) THEN
+    SIMP_TAC[SUC_SUB1; VSUM_CLAUSES_NUMSEG; LT_IMP_LE] THEN
+    ASM_REWRITE_TAC[VSUM_SING_NUMSEG; complex_pow] THEN
+    CONV_TAC COMPLEX_RING) in
+  SUBGOAL_THEN
+   `!M a e.
+        summable (:num) a /\ &0 < M /\ &0 < e
+        ==> eventually
+             (\n. !z. norm(Cx(&1) - z) <= M * (&1 - norm z)
+                      ==> norm(vsum (0..n) (\i. a i * z pow i) -
+                               infsum (:num) (\i. a i * z pow i)) < e)
+             sequentially`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o ISPECL
+     [`M:real`; `\i:num. if i IN s then a i else Cx(&0)`; `e:real`]) THEN
+    REWRITE_TAC[COND_RAND; COND_RATOR; COMPLEX_MUL_LZERO] THEN
+    ASM_REWRITE_TAC[GSYM COMPLEX_VEC_0; GSYM VSUM_RESTRICT_SET;
+                    INFSUM_RESTRICT; SUMMABLE_RESTRICT] THEN
+    REWRITE_TAC[SET_RULE `{i | i IN t /\ i IN s} = s INTER t`]] THEN
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[MESON[]
+   `(!z. P z) <=> P (Cx(&1)) /\ (!z. ~(z = Cx(&1)) ==> P z)`] THEN
+  REWRITE_TAC[EVENTUALLY_AND] THEN CONJ_TAC THENL
+   [REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_NUM; COMPLEX_SUB_REFL;
+                REAL_SUB_REFL; REAL_MUL_RZERO; REAL_LE_REFL] THEN
+    UNDISCH_TAC `&0 < e` THEN SPEC_TAC(`e:real`,`e:real`) THEN
+    REWRITE_TAC[GSYM tendsto; COMPLEX_POW_ONE; COMPLEX_MUL_RID; GSYM dist;
+                ETA_AX] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM SUMS_INFSUM]) THEN
+    REWRITE_TAC[sums; INTER_UNIV];
+    ALL_TAC] THEN
+  REWRITE_TAC[IMP_IMP; EVENTUALLY_SEQUENTIALLY] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; GSYM dist] THEN
+  UNDISCH_TAC `&0 < e` THEN SPEC_TAC(`e:real`,`e:real`) THEN
+  MATCH_MP_TAC UNIFORMLY_CAUCHY_IMP_UNIFORMLY_CONVERGENT THEN
+  REWRITE_TAC[GSYM LIM_SEQUENTIALLY] THEN CONJ_TAC THENL
+   [X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    REWRITE_TAC[MESON[] `(!m n z. P m /\ P n /\ Q z ==> R m n z) <=>
+                         (!z. Q z ==> !m n. P m /\ P n ==> R m n z)`] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM SUMS_INFSUM]) THEN
+    REWRITE_TAC[sums] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP CONVERGENT_IMP_CAUCHY) THEN
+    REWRITE_TAC[cauchy; GSYM dist] THEN
+    DISCH_THEN(MP_TAC o SPEC `min (e / &2) (e / &2 / M)`) THEN
+    ASM_SIMP_TAC[REAL_LT_MIN; REAL_LT_DIV; REAL_HALF; GE; INTER_UNIV] THEN
+    REWRITE_TAC[GSYM REAL_LT_MIN] THEN
+    ONCE_REWRITE_TAC[SEQUENCE_CAUCHY_WLOG] THEN
+    SUBGOAL_THEN
+     `!f:num->complex m n. m <= n
+              ==> dist(vsum (0..m) f,vsum (0..n) f) = norm(vsum (m+1..n) f)`
+     (fun th -> SIMP_TAC[th])
+    THENL
+     [REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC(NORM_ARITH `a + c = b ==> dist(a,b) = norm c`) THEN
+      MATCH_MP_TAC VSUM_COMBINE_R THEN ASM_ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+    REWRITE_TAC[REAL_LT_MIN] THEN STRIP_TAC THEN
+    X_GEN_TAC `z:complex` THEN REWRITE_TAC[dist] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `norm(z:complex) < &1` ASSUME_TAC THENL
+     [UNDISCH_TAC `~(z = Cx(&1))` THEN
+      ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+      REWRITE_TAC[NORM_POS_LT; VECTOR_SUB_EQ] THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (NORM_ARITH
+       `norm(a - b) <= M ==> &0 <= --M ==> b = a`)) THEN
+      REWRITE_TAC[GSYM REAL_MUL_RNEG; REAL_NEG_SUB] THEN
+      MATCH_MP_TAC REAL_LE_MUL THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN STRIP_TAC THEN
+    ASM_CASES_TAC `m + 1 < n` THENL
+     [ASM_SIMP_TAC[lemma1] THEN
+      MATCH_MP_TAC(NORM_ARITH
+       `norm(a) < e / &2 /\ norm(b) < e / &2 ==> norm(a + b) < e`) THEN
+      REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_POW] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC REAL_LET_TRANS THEN
+        EXISTS_TAC `(M * (&1 - norm(z:complex))) *
+                    sum (m+1..n-1) (\i. e / &2 / M * norm(z) pow i)` THEN
+        CONJ_TAC THENL
+         [MATCH_MP_TAC REAL_LE_MUL2 THEN ASM_REWRITE_TAC[NORM_POS_LE] THEN
+          MATCH_MP_TAC VSUM_NORM_LE THEN
+          REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+          X_GEN_TAC `p:num` THEN STRIP_TAC THEN
+          ASM_SIMP_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_POW] THEN
+          MATCH_MP_TAC REAL_LE_RMUL THEN
+          SIMP_TAC[REAL_POW_LE; NORM_POS_LE] THEN
+          MATCH_MP_TAC(REAL_ARITH
+            `x < e / &2 /\ x < e / &2 / M ==> x <= e / &2 / M`) THEN
+          FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC;
+          REWRITE_TAC[SUM_LMUL] THEN
+          REWRITE_TAC[REAL_ARITH
+           `(M * z1) * e / &2 / M * s < e / &2 <=>
+            e * (M / M) * s * z1 < e * &1`] THEN
+          ASM_SIMP_TAC[REAL_LT_LMUL_EQ] THEN
+          ASM_SIMP_TAC[REAL_DIV_REFL; REAL_LT_IMP_NZ; REAL_MUL_LID] THEN
+          ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_SUB_LT] THEN
+          REWRITE_TAC[SUM_GP] THEN
+          COND_CASES_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+          COND_CASES_TAC THENL
+           [UNDISCH_TAC `norm(Cx(&1) - z) <= M * (&1 - norm z)` THEN
+            ASM_REWRITE_TAC[REAL_SUB_REFL; REAL_MUL_RZERO] THEN
+            ASM_REWRITE_TAC[NORM_ARITH `norm(x - y:complex) <= &0 <=> x = y`];
+            ALL_TAC] THEN
+          ASM_SIMP_TAC[REAL_LT_DIV2_EQ; REAL_SUB_LT] THEN
+          MATCH_MP_TAC(REAL_ARITH
+           `&0 <= y /\ x < &1 ==> x - y < &1`) THEN
+          ASM_SIMP_TAC[REAL_POW_LE; NORM_POS_LE] THEN
+          MATCH_MP_TAC REAL_POW_1_LT THEN
+          ASM_REWRITE_TAC[NORM_POS_LE] THEN ARITH_TAC];
+        GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
+        MATCH_MP_TAC REAL_LT_MUL2 THEN SIMP_TAC[NORM_POS_LE; REAL_POW_LE] THEN
+        CONJ_TAC THENL
+         [MATCH_MP_TAC(REAL_ARITH
+            `x < e / &2 /\ x < e / &2 / M ==> x < e / &2`) THEN
+          FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC;
+          MATCH_MP_TAC REAL_POW_1_LT THEN
+          ASM_REWRITE_TAC[NORM_POS_LE] THEN ASM_ARITH_TAC]];
+      ASM_CASES_TAC `(m+1)..n = {}` THENL
+       [ASM_REWRITE_TAC[VSUM_CLAUSES; NORM_0]; ALL_TAC] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[NUMSEG_EMPTY]) THEN
+      SUBGOAL_THEN `m + 1 = n` SUBST1_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+      REWRITE_TAC[VSUM_SING_NUMSEG] THEN
+      REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_POW] THEN
+      GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
+      MATCH_MP_TAC REAL_LT_MUL2 THEN SIMP_TAC[NORM_POS_LE; REAL_POW_LE] THEN
+      CONJ_TAC THENL
+       [FIRST_X_ASSUM(MP_TAC o SPECL [`m:num`; `n:num`]) THEN
+        SUBGOAL_THEN `m + 1 = n` SUBST1_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+        ANTS_TAC THENL [ASM_ARITH_TAC; REWRITE_TAC[VSUM_SING_NUMSEG]] THEN
+        ASM_REAL_ARITH_TAC;
+        MATCH_MP_TAC REAL_POW_1_LT THEN
+        ASM_REWRITE_TAC[NORM_POS_LE] THEN ASM_ARITH_TAC]];
+    X_GEN_TAC `z:complex` THEN REWRITE_TAC[dist] THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`M:real`; `Cx(&1)`; `z:complex`] lemma) THEN
+    ASM_REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_NUM] THEN DISCH_TAC THEN
+    SUBGOAL_THEN `summable (:num) (\i. a i * z pow i)` MP_TAC THENL
+     [MATCH_MP_TAC SERIES_ABSCONV_IMP_CONV THEN
+      REWRITE_TAC[] THEN MATCH_MP_TAC POWER_SERIES_CONV_IMP_ABSCONV THEN
+      EXISTS_TAC `Cx(&1)` THEN
+      REWRITE_TAC[COMPLEX_POW_ONE; COMPLEX_NORM_CX] THEN
+      ASM_REWRITE_TAC[REAL_ABS_NUM; COMPLEX_MUL_RID; ETA_AX];
+      REWRITE_TAC[GSYM SUMS_INFSUM] THEN
+      REWRITE_TAC[sums; INTER_UNIV]]]);;
+
+let POWER_SERIES_UNIFORM_CONVERGENCE_STOLZ = prove
+ (`!M a w s e.
+        summable s (\i. a i * w pow i) /\ &0 < M /\ &0 < e
+        ==> eventually
+             (\n. !z. norm(w - z) <= M * (norm w - norm z)
+                      ==> norm(vsum (s INTER (0..n)) (\i. a i * z pow i) -
+                               infsum s (\i. a i * z pow i)) < e)
+             sequentially`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN ASM_CASES_TAC `w = Cx(&0)` THENL
+   [ASM_REWRITE_TAC[COMPLEX_SUB_LZERO; REAL_SUB_LZERO; COMPLEX_NORM_0] THEN
+    REWRITE_TAC[NORM_NEG; REAL_ARITH
+      `n <= M * --n <=> &0 <= --n * (&1 + M)`] THEN
+    ASM_SIMP_TAC[REAL_LE_MUL_EQ; REAL_ARITH `&0 < M ==> &0 < &1 + M`] THEN
+    REWRITE_TAC[NORM_ARITH `&0 <= --norm z <=> z = vec 0`] THEN
+    REWRITE_TAC[EVENTUALLY_SEQUENTIALLY; FORALL_UNWIND_THM2] THEN
+    EXISTS_TAC `1` THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+    REWRITE_TAC[COMPLEX_VEC_0; COMPLEX_POW_ZERO] THEN
+    REWRITE_TAC[COND_RATOR; COND_RAND; COMPLEX_MUL_RZERO; COMPLEX_MUL_RID] THEN
+    MATCH_MP_TAC(NORM_ARITH `x = y /\ &0 < e ==> norm(y - x) < e`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC INFSUM_UNIQUE THEN
+    REWRITE_TAC[sums] THEN MATCH_MP_TAC LIM_EVENTUALLY THEN
+    REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN EXISTS_TAC `1` THEN
+    X_GEN_TAC `m:num` THEN DISCH_TAC THEN
+    SIMP_TAC[GSYM COMPLEX_VEC_0; VSUM_DELTA] THEN
+    REWRITE_TAC[IN_INTER; LE_0; IN_NUMSEG];
+    FIRST_ASSUM(MP_TAC o MATCH_MP POWER_SERIES_UNIFORM_CONVERGENCE_STOLZ_1) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+    X_GEN_TAC `n:num` THEN REWRITE_TAC[] THEN DISCH_TAC THEN
+    X_GEN_TAC `z:complex` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `z / w:complex`) THEN
+    ASM_SIMP_TAC[GSYM COMPLEX_MUL_ASSOC; GSYM COMPLEX_POW_MUL] THEN
+    ASM_SIMP_TAC[COMPLEX_DIV_LMUL] THEN DISCH_THEN MATCH_MP_TAC THEN
+    MATCH_MP_TAC REAL_LE_RCANCEL_IMP THEN EXISTS_TAC `norm(w:complex)` THEN
+    ASM_REWRITE_TAC[COMPLEX_NORM_NZ; GSYM COMPLEX_NORM_MUL] THEN
+    ASM_SIMP_TAC[COMPLEX_FIELD
+     `~(w = Cx(&0)) ==> (Cx(&1) - z / w) * w = w - z`] THEN
+    REWRITE_TAC[GSYM REAL_MUL_ASSOC; REAL_SUB_RDISTRIB] THEN
+    REWRITE_TAC[GSYM COMPLEX_NORM_MUL; REAL_MUL_LID] THEN
+    ASM_SIMP_TAC[COMPLEX_DIV_RMUL]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence continuity and the Abel limit theorem.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let ABEL_POWER_SERIES_CONTINUOUS = prove
+ (`!M s a.
+        summable s a /\ &0 < M
+        ==> (\z. infsum s (\i. a i * z pow i)) continuous_on
+            {z | norm(Cx(&1) - z) <= M * (&1 - norm z)}`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(ISPEC `sequentially` CONTINUOUS_UNIFORM_LIMIT) THEN
+  EXISTS_TAC `\n z. vsum (s INTER (0..n)) (\i. a i * z pow i)` THEN
+  ASM_SIMP_TAC[POWER_SERIES_UNIFORM_CONVERGENCE_STOLZ_1; IN_ELIM_THM;
+               TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+  MATCH_MP_TAC ALWAYS_EVENTUALLY THEN X_GEN_TAC `n:num` THEN
+  REWRITE_TAC[] THEN MATCH_MP_TAC CONTINUOUS_ON_VSUM THEN
+  SIMP_TAC[CONTINUOUS_ON_COMPLEX_MUL; CONTINUOUS_ON_COMPLEX_POW;
+           CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST; FINITE_INTER;
+           FINITE_NUMSEG]);;
+
+let ABEL_LIMIT_THEOREM = prove
+ (`!M s a.
+        summable s a /\ &0 < M
+        ==> (!z. norm(z) < &1 ==> summable s (\i. a i * z pow i)) /\
+            ((\z. infsum s (\i. a i * z pow i)) --> infsum s a)
+            (at (Cx(&1)) within {z | norm(Cx(&1) - z) <= M * (&1 - norm z)})`,
+  GEN_TAC THEN ASM_CASES_TAC `&0 < M` THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `!a. summable (:num) a
+        ==> (!z. norm(z) < &1 ==> summable (:num) (\i. a i * z pow i)) /\
+            ((\z. infsum (:num) (\i. a i * z pow i))
+              --> infsum (:num) a)
+            (at (Cx(&1)) within {z | norm(Cx(&1) - z) <= M * (&1 - norm z)})`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REPEAT GEN_TAC THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC
+     `(\n. if n IN s then a n else vec 0):num->complex`) THEN
+    REWRITE_TAC[COND_RAND; COND_RATOR; COMPLEX_VEC_0; COMPLEX_MUL_LZERO] THEN
+    REWRITE_TAC[GSYM COMPLEX_VEC_0] THEN
+    ASM_REWRITE_TAC[SUMMABLE_RESTRICT; INFSUM_RESTRICT]] THEN
+  GEN_TAC THEN STRIP_TAC THEN CONJ_TAC THENL
+   [X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+    MATCH_MP_TAC SERIES_ABSCONV_IMP_CONV THEN
+    REWRITE_TAC[] THEN MATCH_MP_TAC POWER_SERIES_CONV_IMP_ABSCONV THEN
+    EXISTS_TAC `Cx(&1)` THEN REWRITE_TAC[COMPLEX_POW_ONE; COMPLEX_NORM_CX] THEN
+    ASM_REWRITE_TAC[REAL_ABS_NUM; COMPLEX_MUL_RID; ETA_AX];
+    MP_TAC(ISPECL [`M:real`; `(:num)`; `a:num->complex`]
+       ABEL_POWER_SERIES_CONTINUOUS) THEN
+    ASM_REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+    DISCH_THEN(MP_TAC o SPEC `Cx(&1)`) THEN
+    REWRITE_TAC[IN_ELIM_THM; CONTINUOUS_WITHIN] THEN
+    REWRITE_TAC[COMPLEX_SUB_REFL; COMPLEX_NORM_CX; COMPLEX_POW_ONE;
+                COMPLEX_MUL_RID; ETA_AX; REAL_ABS_NUM; REAL_SUB_REFL;
+                REAL_LE_REFL; REAL_MUL_RZERO]]);;
diff --git a/Multivariate/cauchy.ml b/Multivariate/cauchy.ml
new file mode 100644 (file)
index 0000000..81be303
--- /dev/null
@@ -0,0 +1,16641 @@
+(* ========================================================================= *)
+(* Complex path integrals and Cauchy's theorem.                              *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(* (c) Copyright, Gianni Ciolli, Graziano Gentili, Marco Maggesi 2008-2009.  *)
+(*              (c) Copyright, Valentina Bruno 2010                          *)
+(* ========================================================================= *)
+
+needs "Library/binomial.ml";;
+needs "Library/iter.ml";;
+needs "Multivariate/realanalysis.ml";;
+
+prioritize_complex();;
+
+(* ------------------------------------------------------------------------- *)
+(* A couple of extra tactics used in some proofs below.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let ASSERT_TAC tm =
+  SUBGOAL_THEN tm STRIP_ASSUME_TAC;;
+
+let EQ_TRANS_TAC tm =
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC tm THEN CONJ_TAC;;
+
+(* ------------------------------------------------------------------------- *)
+(* Piecewise differentiability on a 1-D interval. The definition doesn't     *)
+(* tie it to real^1 but it's not obviously that useful elsewhere.            *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("piecewise_differentiable_on",(12,"right"));;
+
+let piecewise_differentiable_on = new_definition
+ `f piecewise_differentiable_on i <=>
+        f continuous_on i /\
+        (?s. FINITE s /\ !x. x IN (i DIFF s) ==> f differentiable at x)`;;
+
+let PIECEWISE_DIFFERENTIABLE_ON_IMP_CONTINUOUS_ON = prove
+ (`!f s. f piecewise_differentiable_on s ==> f continuous_on s`,
+  SIMP_TAC[piecewise_differentiable_on]);;
+
+let PIECEWISE_DIFFERENTIABLE_ON_SUBSET = prove
+ (`!f s t.
+        f piecewise_differentiable_on s /\ t SUBSET s
+        ==> f piecewise_differentiable_on t`,
+  REWRITE_TAC[piecewise_differentiable_on] THEN
+  MESON_TAC[SUBSET; IN_DIFF; CONTINUOUS_ON_SUBSET]);;
+
+let DIFFERENTIABLE_ON_IMP_PIECEWISE_DIFFERENTIABLE = prove
+ (`!f:real^1->real^N a b.
+        f differentiable_on interval[a,b]
+        ==> f piecewise_differentiable_on interval[a,b]`,
+  SIMP_TAC[piecewise_differentiable_on;
+           DIFFERENTIABLE_IMP_CONTINUOUS_ON] THEN
+  REPEAT STRIP_TAC THEN EXISTS_TAC `{a,b}:real^1->bool` THEN
+  ASM_REWRITE_TAC[FINITE_INSERT; FINITE_RULES] THEN
+  REWRITE_TAC[GSYM OPEN_CLOSED_INTERVAL_1] THEN
+  SIMP_TAC[GSYM DIFFERENTIABLE_ON_EQ_DIFFERENTIABLE_AT; OPEN_INTERVAL] THEN
+  MATCH_MP_TAC DIFFERENTIABLE_ON_SUBSET THEN
+  EXISTS_TAC `interval[a:real^1,b]` THEN
+  ASM_REWRITE_TAC[INTERVAL_OPEN_SUBSET_CLOSED]);;
+
+let DIFFERENTIABLE_IMP_PIECEWISE_DIFFERENTIABLE = prove
+ (`!f s. (!x. x IN s ==> f differentiable (at x))
+         ==> f piecewise_differentiable_on s`,
+  SIMP_TAC[piecewise_differentiable_on; DIFFERENTIABLE_IMP_CONTINUOUS_AT;
+           CONTINUOUS_AT_IMP_CONTINUOUS_ON; IN_DIFF] THEN
+  MESON_TAC[FINITE_RULES]);;
+
+let PIECEWISE_DIFFERENTIABLE_COMPOSE = prove
+ (`!f:real^M->real^N g:real^N->real^P s.
+        f piecewise_differentiable_on s /\
+        g piecewise_differentiable_on (IMAGE f s) /\
+        (!b. FINITE {x | x IN s /\ f(x) = b})
+        ==> (g o f) piecewise_differentiable_on s`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[piecewise_differentiable_on; CONTINUOUS_ON_COMPOSE] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_THEN `ks:real^M->bool`
+                                STRIP_ASSUME_TAC))
+   (CONJUNCTS_THEN2
+     (CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_THEN `kt:real^N->bool`
+                                  STRIP_ASSUME_TAC))
+     ASSUME_TAC)) THEN
+  EXISTS_TAC
+    `ks UNION
+     UNIONS(IMAGE (\b. {x | x IN s /\ (f:real^M->real^N) x = b}) kt)` THEN
+  ASM_SIMP_TAC[FINITE_UNION; FINITE_UNIONS; FINITE_IMAGE] THEN
+  REWRITE_TAC[UNIONS_IMAGE; FORALL_IN_IMAGE; IN_DIFF; IN_UNION] THEN
+  ASM_REWRITE_TAC[IN_ELIM_THM; DE_MORGAN_THM] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC DIFFERENTIABLE_CHAIN_AT THEN
+  CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM SET_TAC[]);;
+
+let PIECEWISE_DIFFERENTIABLE_AFFINE = prove
+ (`!f:real^M->real^N s m c.
+        f piecewise_differentiable_on (IMAGE (\x. m % x + c) s)
+        ==> (f o (\x. m % x + c)) piecewise_differentiable_on s`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `m = &0` THENL
+   [ASM_REWRITE_TAC[o_DEF; VECTOR_MUL_LZERO] THEN
+    MATCH_MP_TAC DIFFERENTIABLE_IMP_PIECEWISE_DIFFERENTIABLE THEN
+    SIMP_TAC[DIFFERENTIABLE_CONST];
+    MATCH_MP_TAC PIECEWISE_DIFFERENTIABLE_COMPOSE THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC DIFFERENTIABLE_IMP_PIECEWISE_DIFFERENTIABLE THEN
+      SIMP_TAC[DIFFERENTIABLE_ADD; DIFFERENTIABLE_CMUL; DIFFERENTIABLE_CONST;
+               DIFFERENTIABLE_ID];
+      X_GEN_TAC `b:real^M` THEN ASM_SIMP_TAC[VECTOR_AFFINITY_EQ] THEN
+      MATCH_MP_TAC FINITE_SUBSET THEN
+      EXISTS_TAC `{inv m % b + --(inv m % c):real^M}` THEN
+      SIMP_TAC[FINITE_RULES] THEN SET_TAC[]]]);;
+
+let PIECEWISE_DIFFERENTIABLE_CASES = prove
+ (`!f g:real^1->real^N a b c.
+        drop a <= drop c /\ drop c <= drop b /\ f c = g c /\
+        f piecewise_differentiable_on interval[a,c] /\
+        g piecewise_differentiable_on interval[c,b]
+        ==> (\x. if drop x <= drop c then f(x) else g(x))
+            piecewise_differentiable_on interval[a,b]`,
+  REPEAT GEN_TAC THEN
+  REPLICATE_TAC 3 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[piecewise_differentiable_on] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_THEN `s:real^1->bool`
+                                STRIP_ASSUME_TAC))
+   (CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_THEN `t:real^1->bool`
+                                STRIP_ASSUME_TAC))) THEN
+  CONJ_TAC THENL
+   [SUBGOAL_THEN `interval[a:real^1,b] = interval[a,c] UNION interval[c,b]`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[EXTENSION; IN_UNION; IN_INTERVAL_1] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CASES THEN
+    ASM_REWRITE_TAC[CLOSED_INTERVAL; IN_INTERVAL_1] THEN
+    ASM_MESON_TAC[REAL_LE_ANTISYM; DROP_EQ];
+    ALL_TAC] THEN
+  EXISTS_TAC `(c:real^1) INSERT s UNION t` THEN
+  ASM_REWRITE_TAC[FINITE_INSERT; FINITE_UNION] THEN
+  REWRITE_TAC[DE_MORGAN_THM; IN_DIFF; IN_INTERVAL_1; IN_INSERT; IN_UNION] THEN
+  X_GEN_TAC `x:real^1` THEN STRIP_TAC THEN
+  DISJ_CASES_TAC(REAL_ARITH `drop x <= drop c \/ drop c <= drop x`) THEN
+  MATCH_MP_TAC DIFFERENTIABLE_TRANSFORM_AT THENL
+   [EXISTS_TAC `f:real^1->real^N`; EXISTS_TAC `g:real^1->real^N`] THEN
+  EXISTS_TAC `dist(x:real^1,c)` THEN ASM_REWRITE_TAC[GSYM DIST_NZ] THEN
+  (CONJ_TAC THENL
+    [GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+     REWRITE_TAC[dist; NORM_REAL; GSYM drop; DROP_SUB] THEN
+     ASM_REAL_ARITH_TAC;
+     FIRST_X_ASSUM MATCH_MP_TAC THEN
+     ASM_REWRITE_TAC[IN_INTERVAL_1; IN_DIFF]]));;
+
+let PIECEWISE_DIFFERENTIABLE_NEG = prove
+ (`!f:real^M->real^N s.
+        f piecewise_differentiable_on s
+        ==> (\x. --(f x)) piecewise_differentiable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[piecewise_differentiable_on] THEN
+  MATCH_MP_TAC MONO_AND THEN SIMP_TAC[CONTINUOUS_ON_NEG] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[DIFFERENTIABLE_NEG]);;
+
+let PIECEWISE_DIFFERENTIABLE_ADD = prove
+ (`!f g:real^M->real^N s.
+        f piecewise_differentiable_on s /\
+        g piecewise_differentiable_on s
+        ==> (\x. f x + g x) piecewise_differentiable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[piecewise_differentiable_on] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_ADD] THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `t:real^M->bool` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `u:real^M->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `t UNION u :real^M->bool` THEN
+  ASM_SIMP_TAC[FINITE_UNION; DIFFERENTIABLE_ADD; IN_INTER;
+               SET_RULE `s DIFF (t UNION u) = (s DIFF t) INTER (s DIFF u)`]);;
+
+let PIECEWISE_DIFFERENTIABLE_SUB = prove
+ (`!f g:real^M->real^N s.
+        f piecewise_differentiable_on s /\
+        g piecewise_differentiable_on s
+        ==> (\x. f x - g x) piecewise_differentiable_on s`,
+  SIMP_TAC[VECTOR_SUB; PIECEWISE_DIFFERENTIABLE_ADD;
+           PIECEWISE_DIFFERENTIABLE_NEG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Valid paths, and their start and finish.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let valid_path = new_definition
+ `valid_path (f:real^1->complex) <=>
+     f piecewise_differentiable_on interval[vec 0,vec 1]`;;
+
+let closed_path = new_definition
+ `closed_path g <=> pathstart g = pathfinish g`;;
+
+let VALID_PATH_COMPOSE = prove
+ (`!f g. valid_path g /\ f differentiable_on (path_image g)
+         ==> valid_path (f o g)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[valid_path; piecewise_differentiable_on] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
+   (X_CHOOSE_THEN `s:real^1->bool` STRIP_ASSUME_TAC)) THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_COMPOSE; DIFFERENTIABLE_IMP_CONTINUOUS_ON] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    ASM_MESON_TAC[DIFFERENTIABLE_IMP_CONTINUOUS_ON; path_image];
+    EXISTS_TAC `{vec 0:real^1,vec 1} UNION s` THEN
+    ASM_REWRITE_TAC[FINITE_UNION; FINITE_INSERT; FINITE_EMPTY] THEN
+    REWRITE_TAC[SET_RULE `s DIFF (t UNION u) = (s DIFF t) DIFF u`] THEN
+    REWRITE_TAC[GSYM OPEN_CLOSED_INTERVAL_1] THEN
+    X_GEN_TAC `t:real^1` THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `((f:complex->complex) o (g:real^1->complex))
+      differentiable (at t within (interval(vec 0,vec 1) DIFF s))`
+    MP_TAC THENL
+     [MATCH_MP_TAC DIFFERENTIABLE_CHAIN_WITHIN THEN CONJ_TAC THENL
+       [MATCH_MP_TAC DIFFERENTIABLE_AT_WITHIN THEN
+        FIRST_X_ASSUM MATCH_MP_TAC;
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [differentiable_on]) THEN
+        DISCH_THEN(MP_TAC o SPEC `(g:real^1->complex) t`) THEN
+        ANTS_TAC THENL
+         [REWRITE_TAC[path_image; IN_IMAGE] THEN EXISTS_TAC `t:real^1`;
+          MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT]
+            DIFFERENTIABLE_WITHIN_SUBSET) THEN
+          REWRITE_TAC[path_image] THEN MATCH_MP_TAC IMAGE_SUBSET]] THEN
+      MP_TAC(ISPECL [`vec 0:real^1`; `vec 1:real^1`]
+        INTERVAL_OPEN_SUBSET_CLOSED) THEN ASM SET_TAC[];
+      ASM_SIMP_TAC[DIFFERENTIABLE_WITHIN_OPEN; OPEN_DIFF; OPEN_INTERVAL;
+                   FINITE_IMP_CLOSED]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In particular, all results for paths apply.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let VALID_PATH_IMP_PATH = prove
+ (`!g. valid_path g ==> path g`,
+  SIMP_TAC[valid_path; path; piecewise_differentiable_on]);;
+
+let CONNECTED_VALID_PATH_IMAGE = prove
+ (`!g. valid_path g ==> connected(path_image g)`,
+  MESON_TAC[CONNECTED_PATH_IMAGE; VALID_PATH_IMP_PATH]);;
+
+let COMPACT_VALID_PATH_IMAGE = prove
+ (`!g. valid_path g ==> compact(path_image g)`,
+  MESON_TAC[COMPACT_PATH_IMAGE; VALID_PATH_IMP_PATH]);;
+
+let BOUNDED_VALID_PATH_IMAGE = prove
+ (`!g. valid_path g ==> bounded(path_image g)`,
+  MESON_TAC[BOUNDED_PATH_IMAGE; VALID_PATH_IMP_PATH]);;
+
+let CLOSED_VALID_PATH_IMAGE = prove
+ (`!g. valid_path g ==> closed(path_image g)`,
+  MESON_TAC[CLOSED_PATH_IMAGE; VALID_PATH_IMP_PATH]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Theorems about rectifiable valid paths.                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let RECTIFIABLE_VALID_PATH = prove
+ (`!g. valid_path g
+       ==> (rectifiable_path g <=>
+              (\t. vector_derivative g (at t)) absolutely_integrable_on
+              interval [vec 0,vec 1])`,
+  REWRITE_TAC[valid_path; piecewise_differentiable_on; GSYM path] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC RECTIFIABLE_PATH_DIFFERENTIABLE THEN
+  ASM_MESON_TAC[FINITE_IMP_COUNTABLE]);;
+
+let PATH_LENGTH_VALID_PATH = prove
+ (`!g. valid_path g /\ rectifiable_path g
+       ==> path_length g =
+                 drop(integral (interval[vec 0,vec 1])
+                               (\t. lift(norm(vector_derivative g (at t)))))`,
+  REWRITE_TAC[valid_path; piecewise_differentiable_on; GSYM path] THEN
+
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_LENGTH_DIFFERENTIABLE THEN
+  ASM_MESON_TAC[FINITE_IMP_COUNTABLE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Negligibility of valid_path image                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_VALID_PATH_IMAGE = prove
+ (`!g. valid_path g ==> negligible(path_image g)`,
+  REWRITE_TAC[piecewise_differentiable_on; piecewise_differentiable_on;
+              valid_path; path_image] THEN
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real^1->bool` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `IMAGE (g:real^1->real^2)
+                    (k UNION (interval [vec 0,vec 1] DIFF k))` THEN
+  CONJ_TAC THENL [REWRITE_TAC[IMAGE_UNION]; SET_TAC[]] THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_UNION_EQ; NEGLIGIBLE_FINITE; FINITE_IMAGE] THEN
+  MATCH_MP_TAC NEGLIGIBLE_DIFFERENTIABLE_IMAGE_LOWDIM THEN
+  REWRITE_TAC[DIMINDEX_1; DIMINDEX_2; ARITH] THEN
+  ASM_SIMP_TAC[DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Integrals along a path (= piecewise differentiable function on [0,1]).    *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("has_path_integral",(12,"right"));;
+parse_as_infix("path_integrable_on",(12,"right"));;
+
+let has_path_integral = define
+  `(f has_path_integral i) (g) <=>
+       ((\x. f(g(x)) * vector_derivative g (at x within interval[vec 0,vec 1]))
+        has_integral i)
+       (interval[vec 0,vec 1])`;;
+
+let path_integral = new_definition
+ `path_integral g f = @i. (f has_path_integral i) (g)`;;
+
+let path_integrable_on = new_definition
+ `f path_integrable_on g <=> ?i. (f has_path_integral i) g`;;
+
+let PATH_INTEGRAL_UNIQUE = prove
+ (`!f g i. (f has_path_integral i) (g) ==> path_integral(g) f = i`,
+  REWRITE_TAC[path_integral; has_path_integral; GSYM integral] THEN
+  MESON_TAC[INTEGRAL_UNIQUE]);;
+
+let HAS_PATH_INTEGRAL_INTEGRAL = prove
+ (`!f i. f path_integrable_on i
+         ==> (f has_path_integral (path_integral i f)) i`,
+  REWRITE_TAC[path_integral; path_integrable_on] THEN
+  MESON_TAC[PATH_INTEGRAL_UNIQUE]);;
+
+let HAS_PATH_INTEGRAL_UNIQUE = prove
+ (`!f i j g. (f has_path_integral i) g /\
+             (f has_path_integral j) g
+             ==> i = j`,
+  REWRITE_TAC[has_path_integral] THEN MESON_TAC[HAS_INTEGRAL_UNIQUE]);;
+
+let HAS_PATH_INTEGRAL_INTEGRABLE = prove
+ (`!f g i. (f has_path_integral i) g ==> f path_integrable_on g`,
+  REWRITE_TAC[path_integrable_on] THEN MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Show that we can forget about the localized derivative.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let VECTOR_DERIVATIVE_WITHIN_INTERIOR = prove
+ (`!a b x.
+        x IN interior(interval[a,b])
+        ==> vector_derivative f (at x within interval[a,b]) =
+            vector_derivative f (at x)`,
+  SIMP_TAC[vector_derivative; has_vector_derivative; has_derivative;
+           LIM_WITHIN_INTERIOR; NETLIMIT_WITHIN_INTERIOR; NETLIMIT_AT]);;
+
+let HAS_INTEGRAL_LOCALIZED_VECTOR_DERIVATIVE = prove
+ (`((\x. f' (g x) * vector_derivative g (at x within interval [a,b]))
+    has_integral i) (interval [a,b]) <=>
+    ((\x. f' (g x) * vector_derivative g (at x))
+     has_integral i) (interval [a,b])`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_SPIKE_EQ THEN
+  EXISTS_TAC `{a:real^1,b}` THEN
+  REWRITE_TAC[NEGLIGIBLE_INSERT; NEGLIGIBLE_EMPTY] THEN
+  SUBGOAL_THEN `interval[a:real^1,b] DIFF {a,b} = interior(interval[a,b])`
+   (fun th -> SIMP_TAC[th; VECTOR_DERIVATIVE_WITHIN_INTERIOR]) THEN
+  REWRITE_TAC[INTERIOR_CLOSED_INTERVAL] THEN
+  REWRITE_TAC[EXTENSION; IN_DIFF; IN_INTERVAL; IN_INSERT; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[DIMINDEX_1; FORALL_1; GSYM drop; GSYM DROP_EQ] THEN
+  REAL_ARITH_TAC);;
+
+let HAS_PATH_INTEGRAL = prove
+ (`(f has_path_integral i) g <=>
+        ((\x. f (g x) * vector_derivative g (at x)) has_integral i)
+        (interval[vec 0,vec 1])`,
+  SIMP_TAC[HAS_INTEGRAL_LOCALIZED_VECTOR_DERIVATIVE; has_path_integral]);;
+
+let PATH_INTEGRABLE_ON = prove
+ (`f path_integrable_on g <=>
+        (\t. f(g t) * vector_derivative g (at t))
+            integrable_on interval[vec 0,vec 1]`,
+  REWRITE_TAC[path_integrable_on; HAS_PATH_INTEGRAL; GSYM integrable_on]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Reversing a path.                                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let VALID_PATH_REVERSEPATH = prove
+ (`!g. valid_path(reversepath g) <=> valid_path g`,
+  SUBGOAL_THEN `!g. valid_path g ==> valid_path(reversepath g)`
+   (fun th -> MESON_TAC[th; REVERSEPATH_REVERSEPATH]) THEN GEN_TAC THEN
+  SIMP_TAC[valid_path; piecewise_differentiable_on; GSYM path;
+           PATH_REVERSEPATH] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (K ALL_TAC) MP_TAC) THEN
+  REWRITE_TAC[IN_DIFF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^1->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `IMAGE (\x:real^1. vec 1 - x) s` THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; reversepath] THEN
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC DIFFERENTIABLE_CHAIN_AT THEN
+  SIMP_TAC[DIFFERENTIABLE_SUB; DIFFERENTIABLE_CONST; DIFFERENTIABLE_ID] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN CONJ_TAC THENL
+   [UNDISCH_TAC `(x:real^1) IN interval[vec 0,vec 1]` THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_SUB; DROP_VEC] THEN REAL_ARITH_TAC;
+    DISCH_THEN(MP_TAC o ISPEC `\x:real^1. vec 1 - x` o
+     MATCH_MP FUN_IN_IMAGE) THEN
+    UNDISCH_TAC `~((x:real^1) IN IMAGE (\x. vec 1 - x) s)` THEN
+    REWRITE_TAC[VECTOR_ARITH `vec 1 - (vec 1 - x):real^1 = x`]]);;
+
+let HAS_PATH_INTEGRAL_REVERSEPATH = prove
+ (`!f g i. valid_path g /\ (f has_path_integral i) g
+           ==> (f has_path_integral (--i)) (reversepath g)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_PATH_INTEGRAL] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(MP_TAC o C CONJ (REAL_ARITH `~(-- &1 = &0)`)) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_AFFINITY) THEN
+  DISCH_THEN(MP_TAC o SPEC `vec 1:real^1`) THEN
+  REWRITE_TAC[IMAGE_AFFINITY_INTERVAL; INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[VECTOR_ARITH `x + --x:real^1 = vec 0`] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID; VECTOR_MUL_LNEG] THEN
+  REWRITE_TAC[VECTOR_MUL_LID; VECTOR_NEG_NEG; REAL_POW_ONE] THEN
+  REWRITE_TAC[reversepath; VECTOR_ARITH `-- x + a:real^N = a - x`] THEN
+  REWRITE_TAC[REAL_INV_1; VECTOR_MUL_LID] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_NEG) THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO] THEN
+  MATCH_MP_TAC(REWRITE_RULE [TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+                HAS_INTEGRAL_SPIKE_FINITE) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [valid_path]) THEN
+  REWRITE_TAC[piecewise_differentiable_on] THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^1->bool` STRIP_ASSUME_TAC o CONJUNCT2) THEN
+  EXISTS_TAC `IMAGE (\x:real^1. vec 1 - x) s` THEN
+  ASM_SIMP_TAC[FINITE_IMAGE] THEN X_GEN_TAC `x:real^1` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[GSYM COMPLEX_MUL_RNEG] THEN
+  AP_TERM_TAC THEN MATCH_MP_TAC VECTOR_DERIVATIVE_AT THEN
+  GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `--x = --(&1) % x`] THEN
+  REWRITE_TAC[GSYM DROP_VEC; GSYM DROP_NEG] THEN
+  MATCH_MP_TAC VECTOR_DIFF_CHAIN_AT THEN REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `--x:real^N = vec 0 - x`] THEN
+  SIMP_TAC[HAS_VECTOR_DERIVATIVE_SUB; HAS_VECTOR_DERIVATIVE_CONST;
+           HAS_VECTOR_DERIVATIVE_ID] THEN
+  REWRITE_TAC[GSYM VECTOR_DERIVATIVE_WORKS] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_DIFF]) THEN
+  REWRITE_TAC[IN_DIFF] THEN MATCH_MP_TAC MONO_AND THEN
+  REWRITE_TAC[CONTRAPOS_THM; IN_DIFF; IN_INTERVAL_1; DROP_SUB; DROP_VEC] THEN
+  CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN REWRITE_TAC[IN_IMAGE] THEN
+  MESON_TAC[VECTOR_ARITH `vec 1 - (vec 1 - x):real^1 = x`]);;
+
+let PATH_INTEGRABLE_REVERSEPATH = prove
+ (`!f g. valid_path g /\ f path_integrable_on g
+         ==> f path_integrable_on (reversepath g)`,
+  REWRITE_TAC[path_integrable_on] THEN
+  MESON_TAC[HAS_PATH_INTEGRAL_REVERSEPATH]);;
+
+let PATH_INTEGRABLE_REVERSEPATH_EQ = prove
+ (`!f g. valid_path g
+         ==> (f path_integrable_on (reversepath g) <=>
+              f path_integrable_on g)`,
+  MESON_TAC[PATH_INTEGRABLE_REVERSEPATH; VALID_PATH_REVERSEPATH;
+            REVERSEPATH_REVERSEPATH]);;
+
+let PATH_INTEGRAL_REVERSEPATH = prove
+ (`!f g. valid_path g /\ f path_integrable_on g
+         ==> path_integral (reversepath g) f = --(path_integral g f)`,
+  MESON_TAC[PATH_INTEGRAL_UNIQUE; HAS_PATH_INTEGRAL_REVERSEPATH;
+            HAS_PATH_INTEGRAL_INTEGRAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Joining two paths together.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let VALID_PATH_JOIN_EQ = prove
+ (`!g1 g2.
+        pathfinish g1 = pathstart g2
+        ==> (valid_path(g1 ++ g2) <=> valid_path g1 /\ valid_path g2)`,
+  REWRITE_TAC[valid_path; piecewise_differentiable_on; GSYM path] THEN
+  ASM_SIMP_TAC[PATH_JOIN] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `path(g1:real^1->complex)` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `path(g2:real^1->complex)` THEN ASM_REWRITE_TAC[] THEN
+  EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `s:real^1->bool` STRIP_ASSUME_TAC) THEN
+    CONJ_TAC THENL
+     [EXISTS_TAC `(vec 0) INSERT (vec 1) INSERT
+                  {x:real^1 | ((&1 / &2) % x) IN s}` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[FINITE_INSERT] THEN MATCH_MP_TAC FINITE_IMAGE_INJ THEN
+        ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC;
+        ALL_TAC] THEN
+      X_GEN_TAC `x:real^1` THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `(&1 / &2) % x:real^1`) THEN
+      REWRITE_TAC[IN_DIFF; IN_ELIM_THM; IN_INTERVAL_1; DROP_CMUL; DROP_VEC;
+                  IN_INSERT; DE_MORGAN_THM; GSYM DROP_EQ; NOT_EXISTS_THM] THEN
+      DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ANTS_TAC THENL
+       [ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      DISCH_TAC THEN
+      SUBGOAL_THEN
+       `(g1:real^1->complex) = (\x. g1 (&2 % x)) o (\x. &1 / &2 % x)`
+      SUBST1_TAC THENL
+       [REWRITE_TAC[FUN_EQ_THM; o_THM] THEN GEN_TAC THEN AP_TERM_TAC THEN
+        VECTOR_ARITH_TAC;
+        ALL_TAC] THEN
+      MATCH_MP_TAC DIFFERENTIABLE_CHAIN_AT THEN
+      SIMP_TAC[DIFFERENTIABLE_CMUL; DIFFERENTIABLE_ID] THEN
+      MATCH_MP_TAC DIFFERENTIABLE_TRANSFORM_AT THEN
+      EXISTS_TAC `(g1 ++ g2):real^1->complex` THEN
+      EXISTS_TAC `dist(&1 / &2 % x:real^1,lift(&1 / &2))` THEN
+      ASM_REWRITE_TAC[dist; NORM_REAL; GSYM drop; DROP_SUB; DROP_CMUL;
+                      LIFT_DROP] THEN
+      REWRITE_TAC[joinpaths] THEN
+      REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      ASM_REAL_ARITH_TAC;
+
+      EXISTS_TAC `(vec 0) INSERT (vec 1) INSERT
+                  {x:real^1 | ((&1 / &2) % (x + vec 1)) IN s}` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[FINITE_INSERT] THEN MATCH_MP_TAC FINITE_IMAGE_INJ THEN
+        ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC;
+        ALL_TAC] THEN
+      X_GEN_TAC `x:real^1` THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `(&1 / &2) % (x + vec 1):real^1`) THEN
+      REWRITE_TAC[IN_DIFF; IN_ELIM_THM; IN_INTERVAL_1; DROP_CMUL; DROP_VEC;
+       DROP_ADD; IN_INSERT; DE_MORGAN_THM; GSYM DROP_EQ; NOT_EXISTS_THM] THEN
+      DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ANTS_TAC THENL
+       [ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      DISCH_TAC THEN
+      SUBGOAL_THEN
+       `(g2:real^1->complex) =
+        (\x. g2 (&2 % x - vec 1)) o (\x. &1 / &2 % (x + vec 1))`
+      SUBST1_TAC THENL
+       [REWRITE_TAC[FUN_EQ_THM; o_THM] THEN GEN_TAC THEN AP_TERM_TAC THEN
+        VECTOR_ARITH_TAC;
+        ALL_TAC] THEN
+      MATCH_MP_TAC DIFFERENTIABLE_CHAIN_AT THEN
+      SIMP_TAC[DIFFERENTIABLE_CMUL; DIFFERENTIABLE_ADD;
+               DIFFERENTIABLE_CONST; DIFFERENTIABLE_ID] THEN
+      MATCH_MP_TAC DIFFERENTIABLE_TRANSFORM_AT THEN
+      EXISTS_TAC `(g1 ++ g2):real^1->complex` THEN
+      EXISTS_TAC `dist(&1 / &2 % (x + vec 1):real^1,lift(&1 / &2))` THEN
+      ASM_REWRITE_TAC[dist; NORM_REAL; GSYM drop; DROP_SUB; DROP_CMUL;
+                      DROP_ADD; DROP_VEC; LIFT_DROP] THEN
+      REWRITE_TAC[joinpaths] THEN
+      REPEAT STRIP_TAC THEN REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+      ASM_REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `s1:real^1->bool` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `s2:real^1->bool` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `(&1 / &2 % vec 1:real^1) INSERT
+              {x:real^1 | (&2 % x) IN s1} UNION
+              {x:real^1 | (&2 % x - vec 1) IN s2}` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[FINITE_INSERT; FINITE_UNION] THEN
+    CONJ_TAC THEN MATCH_MP_TAC FINITE_IMAGE_INJ THEN
+    ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  X_GEN_TAC `x:real^1` THEN
+  REWRITE_TAC[IN_INTERVAL_1; IN_DIFF; DROP_VEC; IN_INSERT; IN_ELIM_THM;
+              DE_MORGAN_THM; IN_UNION; GSYM DROP_EQ; DROP_CMUL] THEN
+  STRIP_TAC THEN
+  REWRITE_TAC[joinpaths] THEN ASM_CASES_TAC `drop x <= &1 / &2` THENL
+   [MATCH_MP_TAC DIFFERENTIABLE_TRANSFORM_AT THEN
+    EXISTS_TAC `\x. (g1:real^1->complex)(&2 % x)` THEN
+    EXISTS_TAC `abs(&1 / &2 - drop x)` THEN
+    REWRITE_TAC[dist; NORM_REAL; GSYM drop; DROP_SUB; DROP_CMUL;
+                    DROP_ADD; DROP_VEC; LIFT_DROP] THEN
+    CONJ_TAC THENL
+     [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    CONJ_TAC THENL
+     [GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC];
+    MATCH_MP_TAC DIFFERENTIABLE_TRANSFORM_AT THEN
+    EXISTS_TAC `\x. (g2:real^1->complex)(&2 % x - vec 1)` THEN
+    EXISTS_TAC `abs(&1 / &2 - drop x)` THEN
+    REWRITE_TAC[dist; NORM_REAL; GSYM drop; DROP_SUB; DROP_CMUL;
+                    DROP_ADD; DROP_VEC; LIFT_DROP] THEN
+    CONJ_TAC THENL
+     [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    CONJ_TAC THENL
+     [GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC]] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC DIFFERENTIABLE_CHAIN_AT THEN
+  SIMP_TAC[DIFFERENTIABLE_CMUL; DIFFERENTIABLE_SUB; DIFFERENTIABLE_CONST;
+           DIFFERENTIABLE_ID] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_SUB; IN_DIFF; DROP_VEC; DROP_CMUL] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let VALID_PATH_JOIN = prove
+ (`!g1 g2.
+        valid_path g1 /\ valid_path g2 /\ pathfinish g1 = pathstart g2
+        ==> valid_path(g1 ++ g2)`,
+  MESON_TAC[VALID_PATH_JOIN_EQ]);;
+
+let HAS_PATH_INTEGRAL_JOIN = prove
+ (`!f g1 g2 i1 i2.
+        (f has_path_integral i1) g1 /\
+        (f has_path_integral i2) g2 /\
+        valid_path g1 /\ valid_path g2
+        ==> (f has_path_integral (i1 + i2)) (g1 ++ g2)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_PATH_INTEGRAL; CONJ_ASSOC] THEN
+  REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC)) THEN
+  DISCH_THEN(CONJUNCTS_THEN
+   (MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] HAS_INTEGRAL_AFFINITY))) THEN
+  DISCH_THEN(ASSUME_TAC o SPECL [`&2`; `--(vec 1):real^1`]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`&2`; `vec 0:real^1`]) THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[DIMINDEX_1] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[IMAGE_AFFINITY_INTERVAL] THEN
+  REWRITE_TAC[INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[VECTOR_MUL_RNEG; VECTOR_NEG_NEG; VECTOR_MUL_RZERO;
+              VECTOR_ADD_LID; VECTOR_NEG_0; VECTOR_ADD_RID;
+              VECTOR_ARITH `&1 / &2 % x + &1 / &2 % x = x:real^N`] THEN
+  REWRITE_TAC[DROP_CMUL; DROP_ADD; DROP_NEG; DROP_VEC; VECTOR_MUL_ASSOC] THEN
+  REWRITE_TAC[VECTOR_ARITH `x % (a + b) + y % b = x % a + (x + y) % b`;
+              VECTOR_ARITH `x % a + y % (a + b) = (x + y) % a + y % b`] THEN
+  REWRITE_TAC[REAL_ARITH `(&1 - (&2 * x + --(&1))) * inv(&2) = &1 - x`;
+              REAL_ARITH `&1 - x + &2 * x + --(&1) = x`;
+              REAL_ARITH `&1 - &2 * x + (&2 * x) * inv(&2) = &1 - x`;
+              REAL_ARITH `(&2 * x) * inv(&2) = x`] THEN
+  REWRITE_TAC[VECTOR_ARITH `b - inv(&2) % (a + b) = inv(&2) % (b - a)`;
+              VECTOR_ARITH `inv(&2) % (a + b) - a = inv(&2) % (b - a)`] THEN
+  REPEAT(DISCH_THEN(MP_TAC o SPEC `&2` o MATCH_MP HAS_INTEGRAL_CMUL) THEN
+         REWRITE_TAC[COMPLEX_CMUL; SIMPLE_COMPLEX_ARITH
+          `Cx(&2) * Cx(&1 / &2) * j = j /\
+           Cx(&2) * (a * Cx(inv(&2)) * b) = a * b`] THEN DISCH_TAC) THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMBINE THEN
+  EXISTS_TAC `&1 / &2 % vec 1:real^1` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[DROP_CMUL; DROP_VEC] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  CONJ_TAC THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE
+   [TAUT `a1 /\ a2 /\ b ==> c <=> b ==> a1 /\ a2 ==> c`]
+   HAS_INTEGRAL_SPIKE_FINITE)) THENL
+   [MP_TAC(REWRITE_RULE[valid_path] (ASSUME `valid_path g1`));
+    MP_TAC(REWRITE_RULE[valid_path] (ASSUME `valid_path g2`))] THEN
+  REWRITE_TAC[piecewise_differentiable_on] THEN
+  DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^1->bool` STRIP_ASSUME_TAC) THENL
+   [EXISTS_TAC `((&1 / &2) % vec 1) INSERT {x:real^1 | (&2 % x) IN s}`;
+    EXISTS_TAC `((&1 / &2) % vec 1) INSERT
+                {x:real^1 | (&2 % x - vec 1) IN s}`] THEN
+  (CONJ_TAC THENL
+    [REWRITE_TAC[FINITE_INSERT] THEN MATCH_MP_TAC FINITE_IMAGE_INJ THEN
+     ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC;
+     ALL_TAC]) THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FINITE_INSERT; IN_DIFF; IN_INSERT; DE_MORGAN_THM;
+              joinpaths; IN_INTERVAL_1; DROP_VEC; DROP_CMUL; GSYM DROP_EQ] THEN
+  SIMP_TAC[REAL_LT_IMP_LE; REAL_MUL_RID; IN_ELIM_THM;
+         REAL_ARITH `&1 / &2 <= x /\ ~(x = &1 / &2) ==> ~(x <= &1 / &2)`] THEN
+  REWRITE_TAC[LIFT_CMUL; LIFT_SUB; LIFT_DROP; LIFT_NUM; GSYM VECTOR_SUB] THEN
+  X_GEN_TAC `x:real^1` THEN STRIP_TAC THEN
+  MATCH_MP_TAC(COMPLEX_RING `x = Cx(&2) * y ==> g * x = Cx(&2) * g * y`) THEN
+  MATCH_MP_TAC VECTOR_DERIVATIVE_AT THEN
+  MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_TRANSFORM_AT THENL
+   [EXISTS_TAC `(\x. g1(&2 % x)):real^1->complex`;
+    EXISTS_TAC `(\x. g2(&2 % x - vec 1)):real^1->complex`] THEN
+  EXISTS_TAC `abs(drop x - &1 / &2)` THEN
+  REWRITE_TAC[DIST_REAL; GSYM drop; GSYM REAL_ABS_NZ] THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_NE; REAL_SUB_0] THEN
+  (CONJ_TAC THENL
+    [GEN_TAC THEN COND_CASES_TAC THEN REWRITE_TAC[] THEN
+     ASM_REAL_ARITH_TAC;
+     ALL_TAC]) THEN
+  GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+  REWRITE_TAC[GSYM COMPLEX_CMUL] THEN
+  SUBST1_TAC(SYM(SPEC `2` DROP_VEC)) THEN
+  MATCH_MP_TAC VECTOR_DIFF_CHAIN_AT THEN
+  (CONJ_TAC THENL
+    [TRY(GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_SUB_RZERO] THEN
+         MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_SUB THEN
+         REWRITE_TAC[HAS_VECTOR_DERIVATIVE_CONST]) THEN
+     REWRITE_TAC[has_vector_derivative] THEN
+     MATCH_MP_TAC(MESON[HAS_DERIVATIVE_LINEAR]
+      `f = g /\ linear f ==> (f has_derivative g) net`) THEN
+     REWRITE_TAC[linear; FUN_EQ_THM; DROP_VEC] THEN
+     REWRITE_TAC[GSYM DROP_EQ; DROP_ADD; DROP_CMUL; DROP_VEC] THEN
+     REAL_ARITH_TAC;
+     REWRITE_TAC[GSYM VECTOR_DERIVATIVE_WORKS] THEN
+     FIRST_X_ASSUM MATCH_MP_TAC THEN
+     ASM_SIMP_TAC[IN_DIFF; IN_INTERVAL_1; DROP_SUB; DROP_CMUL; DROP_VEC] THEN
+     ASM_REAL_ARITH_TAC]));;
+
+let PATH_INTEGRABLE_JOIN = prove
+ (`!f g1 g2.
+        valid_path g1 /\ valid_path g2
+        ==> (f path_integrable_on (g1 ++ g2) <=>
+             f path_integrable_on g1 /\ f path_integrable_on g2)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[path_integrable_on] THEN
+    ASM_MESON_TAC[HAS_PATH_INTEGRAL_JOIN]] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[valid_path]) THEN
+  REWRITE_TAC[PATH_INTEGRABLE_ON; joinpaths] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] INTEGRABLE_ON_SUBINTERVAL))
+  THENL
+   [DISCH_THEN(MP_TAC o SPECL [`lift(&0)`; `lift(&1 / &2)`]);
+    DISCH_THEN(MP_TAC o SPECL [`lift(&1 / &2)`; `lift(&1)`])] THEN
+  REWRITE_TAC[SUBSET_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  DISCH_THEN(MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] INTEGRABLE_AFFINITY))
+  THENL
+   [DISCH_THEN(MP_TAC o SPECL [`&1 / &2`; `vec 0:real^1`]);
+    DISCH_THEN(MP_TAC o SPECL [`&1 / &2`; `lift(&1 / &2)`])] THEN
+  REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[IMAGE_AFFINITY_INTERVAL; INTERVAL_EQ_EMPTY_1] THEN
+  REWRITE_TAC[LIFT_DROP; LIFT_NUM; VECTOR_MUL_RZERO; VECTOR_NEG_0;
+              GSYM LIFT_CMUL; VECTOR_ADD_RID; VECTOR_MUL_RNEG] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[LIFT_NUM] THEN
+  REWRITE_TAC[VECTOR_ARITH `vec 2 + --vec 1:real^1 = vec 1`;
+              VECTOR_ARITH `vec 1 + --vec 1:real^1 = vec 0`] THEN
+  DISCH_THEN(MP_TAC o SPEC `&1 / &2` o MATCH_MP INTEGRABLE_CMUL) THEN
+  REWRITE_TAC[] THEN MATCH_MP_TAC INTEGRABLE_SPIKE_FINITE THEN
+  REWRITE_TAC[IN_DIFF; IN_INTERVAL_1; DROP_VEC; DROP_CMUL; DROP_ADD;
+              LIFT_DROP; COMPLEX_CMUL] THEN
+  REWRITE_TAC[COMPLEX_RING `a * b = Cx(&1 / &2) * x * y <=>
+                                x * y = a * Cx(&2) * b`]
+  THENL
+   [UNDISCH_TAC `(g1:real^1->complex) piecewise_differentiable_on
+                        interval[vec 0,vec 1]`;
+    UNDISCH_TAC `(g2:real^1->complex) piecewise_differentiable_on
+                        interval[vec 0,vec 1]`] THEN
+  REWRITE_TAC[piecewise_differentiable_on] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^1->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(vec 0:real^1) INSERT (vec 1) INSERT s` THEN
+  ASM_REWRITE_TAC[FINITE_INSERT; IN_INSERT; DE_MORGAN_THM] THEN
+  REWRITE_TAC[GSYM DROP_EQ; DROP_VEC] THEN X_GEN_TAC `t:real^1` THEN
+  STRIP_TAC THEN BINOP_TAC THENL
+   [AP_TERM_TAC THEN
+    ASM_SIMP_TAC[REAL_ARITH `x <= &1 ==> &1 / &2 * x <= &1 / &2`] THEN
+    AP_TERM_TAC THEN VECTOR_ARITH_TAC;
+    ALL_TAC;
+    AP_TERM_TAC THEN ASM_SIMP_TAC[REAL_ARITH
+     `&0 <= t /\ ~(t = &0) ==> ~(&1 / &2 * t + &1 / &2 <= &1 / &2)`] THEN
+    AP_TERM_TAC THEN
+    REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; DROP_ADD; DROP_SUB; LIFT_DROP] THEN
+    REWRITE_TAC[DROP_VEC] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC VECTOR_DERIVATIVE_AT THEN
+  MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_TRANSFORM_AT THENL
+   [EXISTS_TAC `(\x. g1(&2 % x)):real^1->complex` THEN
+    EXISTS_TAC `abs(drop t - &1) / &2` THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < abs x / &2 <=> ~(x = &0)`; REAL_SUB_0] THEN
+    REWRITE_TAC[DIST_REAL; GSYM drop; DROP_CMUL] THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[REAL_ARITH
+       `t <= &1 /\ ~(t = &1) /\ abs(x - &1 / &2 * t) < abs(t - &1) / &2
+        ==> x <= &1 / &2`];
+      ALL_TAC];
+    EXISTS_TAC `(\x. g2(&2 % x - vec 1)):real^1->complex` THEN
+    EXISTS_TAC `abs(drop t) / &2` THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < abs x / &2 <=> ~(x = &0)`; REAL_SUB_0] THEN
+    REWRITE_TAC[DIST_REAL; GSYM drop; DROP_CMUL; DROP_ADD; LIFT_DROP] THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[REAL_ARITH
+       `&0 <= t /\ abs(x - (&1 / &2 * t + &1 / &2)) < abs(t) / &2
+        ==> ~(x <= &1 / &2)`];
+      ALL_TAC]] THEN
+  GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+  REWRITE_TAC[GSYM COMPLEX_CMUL] THEN
+  SUBST1_TAC(SYM(SPEC `2` DROP_VEC)) THEN
+  MATCH_MP_TAC VECTOR_DIFF_CHAIN_AT THEN
+  (CONJ_TAC THENL
+    [TRY(GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_SUB_RZERO] THEN
+         MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_SUB THEN
+         REWRITE_TAC[HAS_VECTOR_DERIVATIVE_CONST]) THEN
+     REWRITE_TAC[has_vector_derivative] THEN
+     MATCH_MP_TAC(MESON[HAS_DERIVATIVE_LINEAR]
+      `f = g /\ linear f ==> (f has_derivative g) net`) THEN
+     REWRITE_TAC[linear; FUN_EQ_THM; DROP_VEC] THEN
+     REWRITE_TAC[GSYM DROP_EQ; DROP_ADD; DROP_CMUL; DROP_VEC] THEN
+     REAL_ARITH_TAC;
+     MATCH_MP_TAC(MESON[VECTOR_DERIVATIVE_WORKS]
+       `f differentiable (at t) /\ t' = t
+        ==> (f has_vector_derivative
+                  (vector_derivative f (at t))) (at t')`) THEN
+     CONJ_TAC THENL
+      [FIRST_X_ASSUM MATCH_MP_TAC THEN
+       ASM_REWRITE_TAC[IN_DIFF; IN_INTERVAL_1; DROP_VEC];
+       ALL_TAC] THEN
+     REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; DROP_ADD; DROP_SUB; LIFT_DROP;
+                 DROP_VEC] THEN
+     REAL_ARITH_TAC]));;
+
+let PATH_INTEGRAL_JOIN = prove
+ (`!f g1 g2:real^1->complex.
+        valid_path g1 /\ valid_path g2 /\
+        f path_integrable_on g1 /\ f path_integrable_on g2
+        ==> path_integral (g1 ++ g2) f =
+            path_integral g1 f + path_integral g2 f`,
+  MESON_TAC[PATH_INTEGRAL_UNIQUE; HAS_PATH_INTEGRAL_INTEGRAL;
+            HAS_PATH_INTEGRAL_JOIN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Reparametrizing to shift the starting point of a (closed) path.           *)
+(* ------------------------------------------------------------------------- *)
+
+let VALID_PATH_SHIFTPATH = prove
+ (`!g a. valid_path g /\ pathfinish g = pathstart g /\
+         a IN interval[vec 0,vec 1]
+         ==> valid_path(shiftpath a g)`,
+  REWRITE_TAC[valid_path; shiftpath; DROP_ADD; GSYM DROP_VEC] THEN
+  REWRITE_TAC[REAL_ARITH `a + x <= y <=> x <= y - a`; GSYM DROP_SUB] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PIECEWISE_DIFFERENTIABLE_CASES THEN
+  REPLICATE_TAC 2 (CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+    REWRITE_TAC[DROP_SUB; DROP_VEC] THEN REAL_ARITH_TAC;
+    ALL_TAC]) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH `a + vec 1 - a - vec 1:real^1 = vec 0`;
+                  VECTOR_ARITH `a + vec 1 - a:real^1 = vec 1`] THEN
+  CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[VECTOR_ARITH `a + x:real^1 = &1 % x + a`];
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+     `a + x - vec 1:real^1 = &1 % x + (a - vec 1)`]] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC PIECEWISE_DIFFERENTIABLE_AFFINE THEN
+  MATCH_MP_TAC PIECEWISE_DIFFERENTIABLE_ON_SUBSET THEN
+  EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+  REWRITE_TAC[IMAGE_AFFINITY_INTERVAL; REAL_POS; INTERVAL_EQ_EMPTY_1;
+              IN_INTERVAL_1; DROP_SUB; DROP_VEC] THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+  REWRITE_TAC[EMPTY_SUBSET; SUBSET_INTERVAL_1; DROP_ADD; DROP_CMUL;
+              DROP_SUB; DROP_VEC] THEN
+  REAL_ARITH_TAC);;
+
+let HAS_PATH_INTEGRAL_SHIFTPATH = prove
+ (`!f g i a.
+        (f has_path_integral i) g /\ valid_path g /\
+        a IN interval[vec 0,vec 1]
+        ==> (f has_path_integral i) (shiftpath a g)`,
+  REWRITE_TAC[HAS_PATH_INTEGRAL; IN_INTERVAL_1; DROP_VEC] THEN
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `i = integral (interval[a,vec 1])
+                 (\x. f ((g:real^1->real^2) x) * vector_derivative g (at x)) +
+        integral (interval[vec 0,a])
+                 (\x. f (g x) * vector_derivative g (at x))`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC(INST_TYPE [`:1`,`:M`; `:2`,`:N`] HAS_INTEGRAL_UNIQUE) THEN
+    MAP_EVERY EXISTS_TAC
+     [`\x. f ((g:real^1->real^2) x) * vector_derivative g (at x)`;
+      `interval[vec 0:real^1,vec 1]`] THEN
+    ONCE_REWRITE_TAC[COMPLEX_ADD_SYM] THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC HAS_INTEGRAL_COMBINE THEN EXISTS_TAC `a:real^1` THEN
+    ASM_REWRITE_TAC[DROP_VEC] THEN
+    CONJ_TAC THEN MATCH_MP_TAC INTEGRABLE_INTEGRAL THEN
+    MATCH_MP_TAC INTEGRABLE_SUBINTERVAL THEN
+    MAP_EVERY EXISTS_TAC [`vec 0:real^1`; `vec 1:real^1`] THEN
+    (CONJ_TAC THENL [ASM_MESON_TAC[integrable_on]; ALL_TAC]) THEN
+    REWRITE_TAC[DROP_SUB; DROP_VEC; SUBSET_INTERVAL_1] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMBINE THEN EXISTS_TAC `vec 1 - a:real^1` THEN
+  ASM_REWRITE_TAC[DROP_SUB; DROP_VEC; REAL_SUB_LE;
+                  REAL_ARITH `&1 - x <= &1 <=> &0 <= x`] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [valid_path]) THEN
+  REWRITE_TAC[piecewise_differentiable_on] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^1->bool` STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[shiftpath] THEN CONJ_TAC THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPIKE_FINITE THENL
+   [EXISTS_TAC `\x. f(g(a + x)) * vector_derivative g (at(a + x))` THEN
+    EXISTS_TAC `(vec 1 - a) INSERT IMAGE (\x:real^1. x - a) s` THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; FINITE_INSERT] THEN CONJ_TAC THENL
+     [X_GEN_TAC `x:real^1` THEN
+      REWRITE_TAC[IN_DIFF; IN_INTERVAL_1; IN_INSERT; IN_IMAGE; UNWIND_THM2;
+                  DROP_SUB; DROP_ADD; DROP_VEC; DE_MORGAN_THM;
+                  VECTOR_ARITH `x:real^1 = y - a <=> y = a + x`] THEN
+      REWRITE_TAC[GSYM DROP_EQ; DROP_ADD; DROP_VEC] THEN STRIP_TAC THEN
+      ASM_SIMP_TAC[REAL_ARITH `x <= &1 - a ==> a + x <= &1`] THEN
+      AP_TERM_TAC THEN MATCH_MP_TAC VECTOR_DERIVATIVE_AT THEN
+      MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_TRANSFORM_AT THEN
+      MAP_EVERY EXISTS_TAC
+       [`\x. (g:real^1->complex)(a + x)`; `dist(vec 1 - a:real^1,x)`] THEN
+      SIMP_TAC[CONJ_ASSOC; dist; NORM_REAL; GSYM drop; DROP_VEC; DROP_SUB] THEN
+      CONJ_TAC THENL
+       [REPEAT STRIP_TAC THEN REPEAT COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+        ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_MUL_LID] THEN
+      REWRITE_TAC[GSYM DROP_VEC] THEN MATCH_MP_TAC VECTOR_DIFF_CHAIN_AT THEN
+      SUBST1_TAC(VECTOR_ARITH `vec 1:real^1 = vec 0 + vec 1`) THEN
+      SIMP_TAC[HAS_VECTOR_DERIVATIVE_ADD; HAS_VECTOR_DERIVATIVE_CONST;
+               HAS_VECTOR_DERIVATIVE_ID] THEN
+      REWRITE_TAC[GSYM VECTOR_DERIVATIVE_WORKS] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REWRITE_TAC[IN_DIFF; IN_INTERVAL_1; DROP_VEC; DROP_ADD] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN `(\x. f (g x) * vector_derivative g (at x)) integrable_on
+                  (interval [a,vec 1])`
+    MP_TAC THENL
+     [MATCH_MP_TAC INTEGRABLE_SUBINTERVAL THEN
+      MAP_EVERY EXISTS_TAC [`vec 0:real^1`; `vec 1:real^1`] THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[integrable_on]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[DROP_SUB; DROP_VEC; SUBSET_INTERVAL_1; REAL_LE_REFL];
+      ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o C CONJ (REAL_ARITH `~(&1 = &0)`) o MATCH_MP
+      INTEGRABLE_INTEGRAL) THEN
+    DISCH_THEN(MP_TAC o SPEC `a:real^1` o MATCH_MP HAS_INTEGRAL_AFFINITY) THEN
+    REWRITE_TAC[IMAGE_AFFINITY_INTERVAL] THEN
+    REWRITE_TAC[VECTOR_ARITH `&1 % x + a:real^1 = a + x`] THEN
+    REWRITE_TAC[REAL_INV_1; REAL_POS; REAL_ABS_NUM; REAL_POW_ONE] THEN
+    ASM_REWRITE_TAC[INTERVAL_EQ_EMPTY_1; DROP_VEC; GSYM REAL_NOT_LE] THEN
+    REWRITE_TAC[VECTOR_MUL_LID; GSYM VECTOR_SUB; VECTOR_SUB_REFL];
+    EXISTS_TAC `\x. f(g(a + x - vec 1)) *
+                    vector_derivative g (at(a + x - vec 1))` THEN
+    EXISTS_TAC `(vec 1 - a) INSERT IMAGE (\x:real^1. x - a + vec 1) s` THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; FINITE_INSERT] THEN CONJ_TAC THENL
+     [X_GEN_TAC `x:real^1` THEN
+      REWRITE_TAC[IN_DIFF; IN_INTERVAL_1; IN_INSERT; IN_IMAGE; UNWIND_THM2;
+                  DROP_SUB; DROP_ADD; DROP_VEC; DE_MORGAN_THM;
+                  VECTOR_ARITH `x:real^1 = y - a + z <=> y = a + (x - z)`] THEN
+      REWRITE_TAC[GSYM DROP_EQ; DROP_ADD; DROP_VEC; DROP_SUB] THEN
+      STRIP_TAC THEN
+      ASM_SIMP_TAC[REAL_ARITH
+       `&1 - a <= x /\ ~(x = &1 - a) ==> ~(a + x <= &1)`] THEN
+      AP_TERM_TAC THEN MATCH_MP_TAC VECTOR_DERIVATIVE_AT THEN
+      MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_TRANSFORM_AT THEN
+      MAP_EVERY EXISTS_TAC
+       [`\x. (g:real^1->complex)(a + x - vec 1)`;
+        `dist(vec 1 - a:real^1,x)`] THEN
+      SIMP_TAC[CONJ_ASSOC; dist; NORM_REAL; GSYM drop; DROP_VEC; DROP_SUB] THEN
+      CONJ_TAC THENL
+       [REPEAT STRIP_TAC THEN REPEAT COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+        ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_MUL_LID] THEN
+      REWRITE_TAC[GSYM DROP_VEC] THEN MATCH_MP_TAC VECTOR_DIFF_CHAIN_AT THEN
+      CONJ_TAC THENL
+       [GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_ADD_LID] THEN
+        ONCE_REWRITE_TAC[VECTOR_ARITH
+         `a + x - vec 1:real^1 = (a - vec 1) + x`] THEN
+        SIMP_TAC[HAS_VECTOR_DERIVATIVE_ADD; HAS_VECTOR_DERIVATIVE_CONST;
+                 HAS_VECTOR_DERIVATIVE_ID];
+        ALL_TAC] THEN
+      REWRITE_TAC[GSYM VECTOR_DERIVATIVE_WORKS] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_SIMP_TAC[IN_DIFF; DROP_SUB; IN_INTERVAL_1; DROP_VEC; DROP_ADD] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN `(\x. f (g x) * vector_derivative g (at x)) integrable_on
+                  (interval [vec 0,a])`
+    MP_TAC THENL
+     [MATCH_MP_TAC INTEGRABLE_SUBINTERVAL THEN
+      MAP_EVERY EXISTS_TAC [`vec 0:real^1`; `vec 1:real^1`] THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[integrable_on]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[DROP_SUB; DROP_VEC; SUBSET_INTERVAL_1; REAL_LE_REFL];
+      ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o C CONJ (REAL_ARITH `~(&1 = &0)`) o MATCH_MP
+      INTEGRABLE_INTEGRAL) THEN
+    DISCH_THEN(MP_TAC o SPEC `a - vec 1:real^1` o
+      MATCH_MP HAS_INTEGRAL_AFFINITY) THEN
+    REWRITE_TAC[IMAGE_AFFINITY_INTERVAL] THEN
+    REWRITE_TAC[VECTOR_ARITH `&1 % x + a - vec 1:real^1 = a + x - vec 1`] THEN
+    REWRITE_TAC[REAL_INV_1; REAL_POS; REAL_ABS_NUM; REAL_POW_ONE] THEN
+    ASM_REWRITE_TAC[INTERVAL_EQ_EMPTY_1; DROP_VEC; GSYM REAL_NOT_LE] THEN
+    REWRITE_TAC[VECTOR_MUL_LID;
+                VECTOR_ARITH `vec 0 + --(a - vec 1):real^1 = vec 1 - a`;
+                VECTOR_ARITH `a + --(a - vec 1):real^1 = vec 1`]]);;
+
+let HAS_PATH_INTEGRAL_SHIFTPATH_EQ = prove
+ (`!f g i a.
+        valid_path g /\ pathfinish g = pathstart g /\
+        a IN interval[vec 0,vec 1]
+        ==> ((f has_path_integral i) (shiftpath a g) <=>
+             (f has_path_integral i) g)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[HAS_PATH_INTEGRAL_SHIFTPATH] THEN
+  SUBGOAL_THEN
+   `(f has_path_integral i) (shiftpath (vec 1 - a) (shiftpath a g))`
+  MP_TAC THENL
+   [MATCH_MP_TAC HAS_PATH_INTEGRAL_SHIFTPATH THEN
+    ASM_SIMP_TAC[VALID_PATH_SHIFTPATH] THEN REPEAT(POP_ASSUM MP_TAC) THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_SUB] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[HAS_PATH_INTEGRAL] THEN MATCH_MP_TAC EQ_IMP THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPIKE_FINITE_EQ THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [valid_path]) THEN
+  REWRITE_TAC[piecewise_differentiable_on] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^1->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(s:real^1->bool) UNION {vec 0,vec 1}` THEN
+  ASM_SIMP_TAC[FINITE_UNION; FINITE_RULES] THEN
+  REWRITE_TAC[SET_RULE `s DIFF (t UNION u) = (s DIFF u) DIFF t`] THEN
+  REWRITE_TAC[GSYM OPEN_CLOSED_INTERVAL_1] THEN X_GEN_TAC `x:real^1` THEN
+  STRIP_TAC THEN   BINOP_TAC THEN CONV_TAC SYM_CONV THENL
+   [AP_TERM_TAC THEN MATCH_MP_TAC SHIFTPATH_SHIFTPATH THEN ASM_SIMP_TAC[] THEN
+    ASM_MESON_TAC[INTERVAL_OPEN_SUBSET_CLOSED; SUBSET; IN_DIFF];
+    ALL_TAC] THEN
+  MATCH_MP_TAC VECTOR_DERIVATIVE_AT THEN
+  MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+  MAP_EVERY EXISTS_TAC
+   [`g:real^1->real^2`; `interval(vec 0,vec 1) DIFF s:real^1->bool`] THEN
+  ASM_SIMP_TAC[GSYM VECTOR_DERIVATIVE_WORKS; OPEN_DIFF; FINITE_IMP_CLOSED;
+               OPEN_INTERVAL] THEN
+  REPEAT STRIP_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC SHIFTPATH_SHIFTPATH;
+    FIRST_X_ASSUM MATCH_MP_TAC] THEN
+  ASM_MESON_TAC[INTERVAL_OPEN_SUBSET_CLOSED; SUBSET; IN_DIFF]);;
+
+let PATH_INTEGRAL_SHIFTPATH = prove
+ (`!f g a. valid_path g /\ pathfinish g = pathstart g /\
+           a IN interval[vec 0,vec 1]
+           ==> path_integral (shiftpath a g) f = path_integral g f`,
+  SIMP_TAC[path_integral; HAS_PATH_INTEGRAL_SHIFTPATH_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More about straight-line paths.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_VECTOR_DERIVATIVE_LINEPATH_WITHIN = prove
+ (`!a b:complex x s.
+    (linepath(a,b) has_vector_derivative (b - a)) (at x within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[linepath; has_vector_derivative] THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `u % (b - a) = vec 0 + u % (b - a)`] THEN
+  REWRITE_TAC[VECTOR_ARITH `(&1 - u) % a + u % b = a + u % (b - a)`] THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_ADD THEN REWRITE_TAC[HAS_DERIVATIVE_CONST] THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_VMUL_DROP THEN REWRITE_TAC[HAS_DERIVATIVE_ID]);;
+
+let HAS_VECTOR_DERIVATIVE_LINEPATH_AT = prove
+ (`!a b:complex x.
+    (linepath(a,b) has_vector_derivative (b - a)) (at x)`,
+  MESON_TAC[WITHIN_UNIV; HAS_VECTOR_DERIVATIVE_LINEPATH_WITHIN]);;
+
+let VALID_PATH_LINEPATH = prove
+ (`!a b. valid_path(linepath(a,b))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[valid_path] THEN
+  MATCH_MP_TAC DIFFERENTIABLE_ON_IMP_PIECEWISE_DIFFERENTIABLE THEN
+  REWRITE_TAC[differentiable_on; differentiable] THEN
+  MESON_TAC[HAS_VECTOR_DERIVATIVE_LINEPATH_WITHIN; has_vector_derivative]);;
+
+let VECTOR_DERIVATIVE_LINEPATH_WITHIN = prove
+ (`!a b x. x IN interval[vec 0,vec 1]
+           ==> vector_derivative (linepath(a,b))
+                (at x within interval[vec 0,vec 1]) = b - a`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC VECTOR_DERIVATIVE_WITHIN_CLOSED_INTERVAL THEN
+  ASM_REWRITE_TAC[HAS_VECTOR_DERIVATIVE_LINEPATH_WITHIN] THEN
+  REWRITE_TAC[DROP_VEC; REAL_LT_01]);;
+
+let VECTOR_DERIVATIVE_LINEPATH_AT = prove
+ (`!a b x. vector_derivative (linepath(a,b)) (at x) = b - a`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC VECTOR_DERIVATIVE_AT THEN
+  ASM_REWRITE_TAC[HAS_VECTOR_DERIVATIVE_LINEPATH_AT]);;
+
+let HAS_PATH_INTEGRAL_LINEPATH = prove
+ (`!f i a b. (f has_path_integral i) (linepath(a,b)) <=>
+             ((\x. f(linepath(a,b) x) * (b - a)) has_integral i)
+             (interval[vec 0,vec 1])`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_path_integral] THEN
+  MATCH_MP_TAC HAS_INTEGRAL_EQ_EQ THEN
+  SIMP_TAC[VECTOR_DERIVATIVE_LINEPATH_WITHIN]);;
+
+let LINEPATH_IN_PATH = prove
+ (`!x. x IN interval[vec 0,vec 1] ==> linepath(a,b) x IN segment[a,b]`,
+  REWRITE_TAC[segment; linepath; IN_ELIM_THM; IN_INTERVAL_1; DROP_VEC] THEN
+  MESON_TAC[]);;
+
+let RE_LINEPATH_CX = prove
+ (`!a b x. Re(linepath(Cx a,Cx b) x) = (&1 - drop x) * a + drop x * b`,
+  REWRITE_TAC[linepath; RE_ADD; COMPLEX_CMUL; RE_MUL_CX; RE_CX]);;
+
+let IM_LINEPATH_CX = prove
+ (`!a b x. Im(linepath(Cx a,Cx b) x) = &0`,
+  REWRITE_TAC[linepath; IM_ADD; COMPLEX_CMUL; IM_MUL_CX; IM_CX] THEN
+  REAL_ARITH_TAC);;
+
+let LINEPATH_CX = prove
+ (`!a b x. linepath(Cx a,Cx b) x = Cx((&1 - drop x) * a + drop x * b)`,
+  REWRITE_TAC[COMPLEX_EQ; RE_LINEPATH_CX; IM_LINEPATH_CX; RE_CX; IM_CX]);;
+
+let HAS_PATH_INTEGRAL_TRIVIAL = prove
+ (`!f a. (f has_path_integral (Cx(&0))) (linepath(a,a))`,
+  REWRITE_TAC[HAS_PATH_INTEGRAL_LINEPATH; COMPLEX_SUB_REFL;
+              COMPLEX_MUL_RZERO] THEN
+  REWRITE_TAC[GSYM COMPLEX_VEC_0; HAS_INTEGRAL_0]);;
+
+let PATH_INTEGRAL_TRIVIAL = prove
+ (`!f a. path_integral (linepath(a,a)) f = Cx(&0)`,
+  MESON_TAC[HAS_PATH_INTEGRAL_TRIVIAL; PATH_INTEGRAL_UNIQUE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relation to subpath construction.                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let VALID_PATH_SUBPATH = prove
+ (`!g u v. valid_path g /\
+           u IN interval[vec 0,vec 1] /\ v IN interval[vec 0,vec 1]
+           ==> valid_path(subpath u v g)`,
+  SIMP_TAC[valid_path; PATH_SUBPATH] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[subpath] THEN
+  ASM_CASES_TAC `v:real^1 = u` THENL
+   [MATCH_MP_TAC DIFFERENTIABLE_ON_IMP_PIECEWISE_DIFFERENTIABLE THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_REFL; VECTOR_MUL_LZERO; DROP_VEC] THEN
+    REWRITE_TAC[DIFFERENTIABLE_ON_CONST];
+    MATCH_MP_TAC(REWRITE_RULE[o_DEF] PIECEWISE_DIFFERENTIABLE_COMPOSE) THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC DIFFERENTIABLE_ON_IMP_PIECEWISE_DIFFERENTIABLE THEN
+      MATCH_MP_TAC DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC DIFFERENTIABLE_ADD THEN
+      REWRITE_TAC[DIFFERENTIABLE_CONST] THEN
+      MATCH_MP_TAC DIFFERENTIABLE_CMUL THEN REWRITE_TAC[DIFFERENTIABLE_ID];
+      MATCH_MP_TAC PIECEWISE_DIFFERENTIABLE_ON_SUBSET THEN
+      EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN ASM_REWRITE_TAC[] THEN
+      ONCE_REWRITE_TAC[VECTOR_ADD_SYM] THEN
+      REWRITE_TAC[IMAGE_AFFINITY_INTERVAL] THEN
+      REPEAT(COND_CASES_TAC THEN REWRITE_TAC[EMPTY_SUBSET]) THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1])) THEN
+      SIMP_TAC[SUBSET_INTERVAL_1; DROP_ADD; DROP_CMUL; DROP_SUB; DROP_VEC] THEN
+      REAL_ARITH_TAC;
+      REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; DROP_ADD; DROP_SUB] THEN
+      ASM_SIMP_TAC[DROP_EQ; REAL_FIELD `~(u:real = v) ==>
+        (u + (v - u) * x = b <=> x = (b - u) / (v - u))`] THEN
+      X_GEN_TAC `b:real^1` THEN MATCH_MP_TAC FINITE_SUBSET THEN
+      EXISTS_TAC `{lift((drop b - drop u) / (drop v - drop u))}` THEN
+      REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY; SUBSET; IN_ELIM_THM] THEN
+      SIMP_TAC[GSYM LIFT_EQ; LIFT_DROP; IN_SING]]]);;
+
+let HAS_PATH_INTEGRAL_SUBPATH_REFL = prove
+ (`!f g u. (f has_path_integral (Cx(&0))) (subpath u u g)`,
+  REWRITE_TAC[HAS_PATH_INTEGRAL; subpath; VECTOR_SUB_REFL] THEN
+  REWRITE_TAC[DROP_VEC; VECTOR_MUL_LZERO; VECTOR_DERIVATIVE_CONST_AT] THEN
+  REWRITE_TAC[COMPLEX_VEC_0; COMPLEX_MUL_RZERO] THEN
+  REWRITE_TAC[GSYM COMPLEX_VEC_0; HAS_INTEGRAL_0]);;
+
+let PATH_INTEGRABLE_SUBPATH_REFL = prove
+ (`!f g u. f path_integrable_on (subpath u u g)`,
+  REWRITE_TAC[path_integrable_on] THEN
+  MESON_TAC[HAS_PATH_INTEGRAL_SUBPATH_REFL]);;
+
+let PATH_INTEGRAL_SUBPATH_REFL = prove
+ (`!f g u. path_integral (subpath u u g) f = Cx(&0)`,
+  MESON_TAC[PATH_INTEGRAL_UNIQUE; HAS_PATH_INTEGRAL_SUBPATH_REFL]);;
+
+let HAS_PATH_INTEGRAL_SUBPATH = prove
+ (`!f g u v.
+        valid_path g /\ f path_integrable_on g /\
+        u IN interval[vec 0,vec 1] /\ v IN interval[vec 0,vec 1] /\
+        drop u <= drop v
+        ==> (f has_path_integral
+             integral (interval[u,v])
+                      (\x. f(g x) * vector_derivative g (at x)))
+            (subpath u v g)`,
+  REWRITE_TAC[path_integrable_on; HAS_PATH_INTEGRAL; subpath] THEN
+  REWRITE_TAC[GSYM integrable_on] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `v:real^1 = u` THENL
+   [ASM_REWRITE_TAC[INTEGRAL_REFL; VECTOR_SUB_REFL; DROP_VEC] THEN
+    REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_DERIVATIVE_CONST_AT] THEN
+    REWRITE_TAC[COMPLEX_VEC_0; COMPLEX_MUL_RZERO] THEN
+    REWRITE_TAC[GSYM COMPLEX_VEC_0; HAS_INTEGRAL_0];
+    SUBGOAL_THEN `drop u < drop v` ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[REAL_LT_LE; DROP_EQ]; ALL_TAC]] THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`u:real^1`; `v:real^1`] o
+   MATCH_MP(REWRITE_RULE[IMP_CONJ] INTEGRABLE_ON_SUBINTERVAL)) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[SUBSET_INTERVAL_1; IN_INTERVAL_1; REAL_LT_IMP_LE];
+    REWRITE_TAC[HAS_INTEGRAL_INTEGRAL]] THEN
+  DISCH_THEN(MP_TAC o SPECL [`drop(v - u)`; `u:real^1`] o
+   MATCH_MP(REWRITE_RULE[IMP_CONJ] HAS_INTEGRAL_AFFINITY)) THEN
+  ASM_SIMP_TAC[DROP_SUB; REAL_ARITH `u < v ==> ~(v - u = &0)`] THEN
+  REWRITE_TAC[IMAGE_AFFINITY_INTERVAL; INTERVAL_EQ_EMPTY_1; DROP_SUB] THEN
+  ASM_SIMP_TAC[REAL_LE_INV_EQ; REAL_ARITH `u < v ==> ~(v < u) /\ &0 <= v - u`;
+               VECTOR_ARITH `a % u + --(a % v):real^N = a % (u - v)`] THEN
+  REWRITE_TAC[VECTOR_SUB_REFL; VECTOR_MUL_RZERO] THEN
+  SUBGOAL_THEN `inv(drop v - drop u) % (v - u) = vec 1` SUBST1_TAC THENL
+   [REWRITE_TAC[GSYM DROP_EQ; DROP_VEC; DROP_CMUL; DROP_SUB] THEN
+    UNDISCH_TAC `drop u < drop v` THEN CONV_TAC REAL_FIELD;
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `drop(v - u)` o MATCH_MP HAS_INTEGRAL_CMUL) THEN
+  ASM_SIMP_TAC[real_abs; REAL_LT_IMP_LE; REAL_SUB_LE] THEN
+  REWRITE_TAC[DIMINDEX_1; REAL_POW_1; VECTOR_MUL_ASSOC; DROP_SUB] THEN
+  ASM_SIMP_TAC[REAL_FIELD `u < v ==> (v - u) * inv(v - u) = &1`] THEN
+  REWRITE_TAC[VECTOR_MUL_LID] THEN
+  MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+    HAS_INTEGRAL_SPIKE_FINITE) THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [valid_path]) THEN
+  REWRITE_TAC[piecewise_differentiable_on; IN_DIFF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real^1->bool` STRIP_ASSUME_TAC o CONJUNCT2) THEN
+  EXISTS_TAC `{t | ((drop v - drop u) % t + u) IN k}` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC FINITE_IMAGE_INJ THEN
+    ASM_REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; DROP_SUB; DROP_ADD] THEN
+    UNDISCH_TAC `drop u < drop v` THEN CONV_TAC REAL_FIELD;
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_ELIM_THM] THEN
+  X_GEN_TAC `t:real^1` THEN STRIP_TAC THEN REWRITE_TAC[COMPLEX_CMUL] THEN
+  ONCE_REWRITE_TAC[COMPLEX_RING `a * b * c:complex = b * a * c`] THEN
+  REWRITE_TAC[VECTOR_ARITH `x + a % y:real^N = a % y + x`] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[GSYM COMPLEX_CMUL; GSYM DROP_SUB] THEN
+  MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_UNIQUE_AT THEN
+  MATCH_MP_TAC(REWRITE_RULE[o_DEF] VECTOR_DIFF_CHAIN_AT) THEN
+  REWRITE_TAC[DROP_SUB] THEN CONJ_TAC THENL
+   [SUBST1_TAC(VECTOR_ARITH `v - u:real^1 = (v - u) + vec 0`) THEN
+    MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_ADD THEN
+    REWRITE_TAC[HAS_VECTOR_DERIVATIVE_CONST] THEN
+    SUBST1_TAC(MESON[LIFT_DROP; LIFT_EQ_CMUL]
+     `v - u = drop(v - u) % vec 1`) THEN REWRITE_TAC[GSYM DROP_SUB] THEN
+    MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_CMUL THEN
+    REWRITE_TAC[HAS_VECTOR_DERIVATIVE_ID];
+    REWRITE_TAC[GSYM VECTOR_DERIVATIVE_WORKS] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[IN_INTERVAL_1] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1])) THEN
+    REWRITE_TAC[DROP_ADD; DROP_SUB; DROP_CMUL; DROP_VEC] THEN
+    REPEAT STRIP_TAC THENL
+     [MATCH_MP_TAC REAL_LE_ADD THEN CONJ_TAC THEN
+      TRY(MATCH_MP_TAC REAL_LE_MUL) THEN ASM_REAL_ARITH_TAC;
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `(drop v - drop u) * &1 + drop u` THEN
+      ASM_SIMP_TAC[REAL_LE_RADD; REAL_LE_LMUL;
+                   REAL_SUB_LE; REAL_LT_IMP_LE] THEN
+      ASM_REAL_ARITH_TAC]]);;
+
+let PATH_INTEGRABLE_SUBPATH = prove
+ (`!f g u v.
+        valid_path g /\ f path_integrable_on g /\
+        u IN interval[vec 0,vec 1] /\ v IN interval[vec 0,vec 1]
+        ==> f path_integrable_on (subpath u v g)`,
+  REPEAT STRIP_TAC THEN DISJ_CASES_TAC(REAL_ARITH
+   `drop u <= drop v \/ drop v <= drop u`)
+  THENL
+   [ASM_MESON_TAC[path_integrable_on; HAS_PATH_INTEGRAL_SUBPATH];
+    ONCE_REWRITE_TAC[GSYM REVERSEPATH_SUBPATH] THEN
+    MATCH_MP_TAC PATH_INTEGRABLE_REVERSEPATH THEN
+    ASM_SIMP_TAC[VALID_PATH_SUBPATH] THEN
+    ASM_MESON_TAC[path_integrable_on; HAS_PATH_INTEGRAL_SUBPATH]]);;
+
+let HAS_INTEGRAL_PATH_INTEGRAL_SUBPATH = prove
+ (`!f g u v.
+        valid_path g /\ f path_integrable_on g /\
+        u IN interval[vec 0,vec 1] /\ v IN interval[vec 0,vec 1] /\
+        drop u <= drop v
+        ==> (((\x. f(g x) * vector_derivative g (at x))) has_integral
+             path_integral (subpath u v g) f)
+            (interval[u,v])`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[HAS_INTEGRAL_INTEGRABLE_INTEGRAL] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+    EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+    ASM_REWRITE_TAC[GSYM PATH_INTEGRABLE_ON; SUBSET_INTERVAL_1] THEN
+    ASM_MESON_TAC[IN_INTERVAL_1];
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+    ASM_SIMP_TAC[HAS_PATH_INTEGRAL_SUBPATH]]);;
+
+let PATH_INTEGRAL_SUBPATH_INTEGRAL = prove
+ (`!f g u v.
+        valid_path g /\ f path_integrable_on g /\
+        u IN interval[vec 0,vec 1] /\ v IN interval[vec 0,vec 1] /\
+        drop u <= drop v
+        ==> path_integral (subpath u v g) f =
+            integral (interval[u,v])
+                     (\x. f(g x) * vector_derivative g (at x))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_PATH_INTEGRAL_SUBPATH]);;
+
+let PATH_INTEGRAL_SUBPATH_COMBINE = prove
+ (`!f g u v w.
+        valid_path g /\ f path_integrable_on g /\
+        u IN interval[vec 0,vec 1] /\
+        v IN interval[vec 0,vec 1] /\
+        w IN interval[vec 0,vec 1]
+        ==> path_integral (subpath u v g) f + path_integral (subpath v w g) f =
+            path_integral (subpath u w g) f`,
+  REPLICATE_TAC 3 GEN_TAC THEN
+  SUBGOAL_THEN
+   `!u v w.
+        drop u <= drop v /\ drop v <= drop w
+        ==> valid_path g /\ f path_integrable_on g /\
+            u IN interval[vec 0,vec 1] /\
+            v IN interval[vec 0,vec 1] /\
+            w IN interval[vec 0,vec 1]
+            ==> path_integral (subpath u v g) f +
+                path_integral (subpath v w g) f =
+                path_integral (subpath u w g) f`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REPEAT STRIP_TAC THEN REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
+     (REAL_ARITH `drop u <= drop v /\ drop v <= drop w \/
+                  drop u <= drop w /\ drop w <= drop v \/
+                  drop v <= drop u /\ drop u <= drop w \/
+                  drop v <= drop w /\ drop w <= drop u \/
+                  drop w <= drop u /\ drop u <= drop v \/
+                  drop w <= drop v /\ drop v <= drop u`) THEN
+    FIRST_ASSUM(ANTE_RES_THEN MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+    REPEAT_TCL CONJUNCTS_THEN SUBST1_TAC (MESON[REVERSEPATH_SUBPATH]
+     `subpath v u (g:real^1->complex) = reversepath(subpath u v g) /\
+      subpath w u g = reversepath(subpath u w g) /\
+      subpath w v g = reversepath(subpath v w g)`) THEN
+    ASM_SIMP_TAC[PATH_INTEGRAL_REVERSEPATH; PATH_INTEGRABLE_SUBPATH;
+                 VALID_PATH_REVERSEPATH; VALID_PATH_SUBPATH] THEN
+    CONV_TAC COMPLEX_RING] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  SUBGOAL_THEN `drop u <= drop w` ASSUME_TAC THENL
+   [ASM_REAL_ARITH_TAC; STRIP_TAC] THEN
+  ASM_SIMP_TAC[PATH_INTEGRAL_SUBPATH_INTEGRAL] THEN
+  MATCH_MP_TAC INTEGRAL_COMBINE THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+  EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+  ASM_REWRITE_TAC[GSYM PATH_INTEGRABLE_ON; SUBSET_INTERVAL_1] THEN
+  ASM_MESON_TAC[IN_INTERVAL_1]);;
+
+let PATH_INTEGRAL_INTEGRAL = prove
+ (`!f g. path_integral g f =
+         integral (interval [vec 0,vec 1])
+                  (\x. f (g x) * vector_derivative g (at x))`,
+  REWRITE_TAC[path_integral; integral; HAS_PATH_INTEGRAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Easier to reason about segments via convex hulls.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let SEGMENTS_SUBSET_CONVEX_HULL = prove
+ (`!a b c. segment[a,b] SUBSET (convex hull {a,b,c}) /\
+           segment[a,c] SUBSET (convex hull {a,b,c}) /\
+           segment[b,c] SUBSET (convex hull {a,b,c}) /\
+           segment[b,a] SUBSET (convex hull {a,b,c}) /\
+           segment[c,a] SUBSET (convex hull {a,b,c}) /\
+           segment[c,b] SUBSET (convex hull {a,b,c})`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+  MATCH_MP_TAC HULL_MONO THEN SET_TAC[]);;
+
+let MIDPOINTS_IN_CONVEX_HULL = prove
+ (`!x:real^N s. x IN convex hull s /\ y IN convex hull s
+         ==> midpoint(x,y) IN convex hull s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[midpoint; VECTOR_ARITH
+    `inv(&2) % (x + y):real^N = (&1 - inv(&2)) % x + inv(&2) % y`] THEN
+  MATCH_MP_TAC IN_CONVEX_SET THEN
+  ASM_REWRITE_TAC[CONVEX_CONVEX_HULL] THEN REAL_ARITH_TAC);;
+
+let POINTS_IN_CONVEX_HULL = prove
+ (`!x s. x IN s ==> x IN convex hull s`,
+  MESON_TAC[SUBSET; HULL_SUBSET]);;
+
+let CONVEX_HULL_SUBSET = prove
+ (`(!x. x IN s ==> x IN convex hull t)
+   ==> (convex hull s) SUBSET (convex hull t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HULL_MINIMAL THEN
+  ASM_REWRITE_TAC[CONVEX_CONVEX_HULL; SUBSET]);;
+
+let NOT_IN_INTERIOR_CONVEX_HULL_3 = prove
+ (`!a b c:complex. ~(a IN interior(convex hull {a,b,c})) /\
+                   ~(b IN interior(convex hull {a,b,c})) /\
+                   ~(c IN interior(convex hull {a,b,c}))`,
+  REPEAT GEN_TAC THEN REPEAT CONJ_TAC THEN
+  MATCH_MP_TAC NOT_IN_INTERIOR_CONVEX_HULL THEN
+  ASM_SIMP_TAC[CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY; IN_INSERT] THEN
+  REWRITE_TAC[DIMINDEX_2] THEN ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Cauchy's theorem where there's a primitive.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_INTEGRAL_PRIMITIVE_LEMMA = prove
+ (`!f f' g a b s.
+        ~(interval[a,b] = {}) /\
+        (!x. x IN s ==> (f has_complex_derivative f'(x)) (at x within s)) /\
+        g piecewise_differentiable_on interval[a,b] /\
+        (!x. x IN interval[a,b] ==> g(x) IN s)
+        ==> ((\x. f'(g x) * vector_derivative g (at x within interval[a,b]))
+             has_integral (f(g b) - f(g a))) (interval[a,b])`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[valid_path; piecewise_differentiable_on] THEN
+  REWRITE_TAC[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `k:real^1->bool` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG THEN
+  EXISTS_TAC `k:real^1->bool` THEN ASM_REWRITE_TAC[DROP_VEC; REAL_POS] THEN
+  ASM_SIMP_TAC[FINITE_IMP_COUNTABLE; GSYM o_DEF] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:complex->bool` THEN
+    ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON THEN
+    ASM_MESON_TAC[holomorphic_on];
+    ALL_TAC] THEN
+  X_GEN_TAC `x:real^1` THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[has_vector_derivative; COMPLEX_CMUL] THEN
+  SUBGOAL_THEN `(f has_complex_derivative f'(g x))
+                (at (g x) within (IMAGE g (interval[a:real^1,b])))`
+  MP_TAC THENL
+   [MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_WITHIN_SUBSET THEN
+    EXISTS_TAC `s:complex->bool` THEN
+    ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_MESON_TAC[INTERVAL_OPEN_SUBSET_CLOSED; SUBSET; IN_DIFF];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(g:real^1->complex) differentiable (at x within interval[a,b])`
+  MP_TAC THENL
+   [MATCH_MP_TAC DIFFERENTIABLE_AT_WITHIN THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_MESON_TAC[INTERVAL_OPEN_SUBSET_CLOSED; SUBSET; IN_DIFF];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [VECTOR_DERIVATIVE_WORKS] THEN
+  REWRITE_TAC[has_vector_derivative; IMP_IMP; has_complex_derivative] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP DIFF_CHAIN_WITHIN) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    HAS_DERIVATIVE_WITHIN_SUBSET)) THEN
+  DISCH_THEN(MP_TAC o SPEC `interval(a:real^1,b)`) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_DIFF]) THEN
+  ASM_SIMP_TAC[INTERVAL_OPEN_SUBSET_CLOSED; OPEN_INTERVAL;
+               HAS_DERIVATIVE_WITHIN_OPEN] THEN
+  REWRITE_TAC[o_DEF; COMPLEX_CMUL] THEN REWRITE_TAC[COMPLEX_MUL_AC]);;
+
+let PATH_INTEGRAL_PRIMITIVE = prove
+ (`!f f' g s.
+        (!x. x IN s ==> (f has_complex_derivative f'(x)) (at x within s)) /\
+        valid_path g /\ (path_image g) SUBSET s
+        ==> (f' has_path_integral (f(pathfinish g) - f(pathstart g))) (g)`,
+  REWRITE_TAC[valid_path; path_image; pathfinish; pathstart] THEN
+  REWRITE_TAC[has_path_integral] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_PRIMITIVE_LEMMA THEN
+  ASM_REWRITE_TAC[INTERVAL_EQ_EMPTY_1; DROP_VEC; REAL_POS; REAL_NOT_LT] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; FORALL_IN_IMAGE]) THEN
+  ASM_MESON_TAC[]);;
+
+let CAUCHY_THEOREM_PRIMITIVE = prove
+ (`!f f' g s.
+        (!x. x IN s ==> (f has_complex_derivative f'(x)) (at x within s)) /\
+        valid_path g /\ (path_image g) SUBSET s /\
+        pathfinish g = pathstart g
+        ==> (f' has_path_integral Cx(&0)) (g)`,
+  MESON_TAC[PATH_INTEGRAL_PRIMITIVE; COMPLEX_SUB_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Existence of path integral for continuous function.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_INTEGRABLE_CONTINUOUS_LINEPATH = prove
+ (`!f a b. f continuous_on segment[a,b]
+           ==> f path_integrable_on (linepath(a,b))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[path_integrable_on; has_path_integral] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  REWRITE_TAC[GSYM integrable_on] THEN MATCH_MP_TAC INTEGRABLE_CONTINUOUS THEN
+  MATCH_MP_TAC CONTINUOUS_ON_EQ THEN
+  EXISTS_TAC `\x. f(linepath(a,b) x) * (b - a)` THEN
+  SIMP_TAC[VECTOR_DERIVATIVE_LINEPATH_WITHIN] THEN
+  ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_LMUL THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  ASM_REWRITE_TAC[GSYM path_image; ETA_AX; PATH_IMAGE_LINEPATH] THEN
+  REWRITE_TAC[CONTINUOUS_ON_LINEPATH]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A complex-specific theorem for integrals.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_COMPLEX_CMUL = prove
+ (`!f y i c. (f has_integral y) i ==> ((\x. c * f(x)) has_integral (c * y)) i`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC
+   (REWRITE_RULE[o_DEF] HAS_INTEGRAL_LINEAR) THEN
+  ASM_REWRITE_TAC[linear; COMPLEX_CMUL] THEN CONV_TAC COMPLEX_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* Arithmetical combining theorems.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_PATH_INTEGRAL_CONST_LINEPATH = prove
+ (`!a b c. ((\x. c) has_path_integral (c * (b - a))) (linepath(a,b))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_PATH_INTEGRAL_LINEPATH] THEN
+  MP_TAC(ISPECL [`vec 0:real^1`; `vec 1:real^1`; `c * (b - a):complex`]
+         HAS_INTEGRAL_CONST) THEN
+  REWRITE_TAC[CONTENT_UNIT; VECTOR_MUL_LID]);;
+
+let HAS_PATH_INTEGRAL_NEG = prove
+ (`!f i g. (f has_path_integral i) g
+           ==> ((\x. --(f x)) has_path_integral (--i)) g`,
+  REWRITE_TAC[has_path_integral; COMPLEX_MUL_LNEG; HAS_INTEGRAL_NEG]);;
+
+let HAS_PATH_INTEGRAL_ADD = prove
+ (`!f1 i1 f2 i2 g.
+        (f1 has_path_integral i1) g /\ (f2 has_path_integral i2) g
+        ==> ((\x. f1(x) + f2(x)) has_path_integral (i1 + i2)) g`,
+  REWRITE_TAC[has_path_integral; COMPLEX_ADD_RDISTRIB] THEN
+  SIMP_TAC[HAS_INTEGRAL_ADD]);;
+
+let HAS_PATH_INTEGRAL_SUB = prove
+ (`!f1 i1 f2 i2 g.
+        (f1 has_path_integral i1) g /\ (f2 has_path_integral i2) g
+         ==> ((\x. f1(x) - f2(x)) has_path_integral (i1 - i2)) g`,
+  REWRITE_TAC[has_path_integral; COMPLEX_SUB_RDISTRIB] THEN
+  SIMP_TAC[HAS_INTEGRAL_SUB]);;
+
+let HAS_PATH_INTEGRAL_COMPLEX_LMUL = prove
+ (`!f g i c. (f has_path_integral i) g
+             ==> ((\x. c * f x) has_path_integral (c * i)) g`,
+  REWRITE_TAC[has_path_integral; HAS_INTEGRAL_COMPLEX_CMUL;
+              GSYM COMPLEX_MUL_ASSOC]);;
+
+let HAS_PATH_INTEGRAL_COMPLEX_RMUL = prove
+ (`!f g i c. (f has_path_integral i) g
+             ==> ((\x. f x * c) has_path_integral (i * c)) g`,
+  ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+  REWRITE_TAC[HAS_PATH_INTEGRAL_COMPLEX_LMUL]);;
+
+let HAS_PATH_INTEGRAL_COMPLEX_DIV = prove
+ (`!f g i c. (f has_path_integral i) g
+             ==> ((\x. f x / c) has_path_integral (i / c)) g`,
+  REWRITE_TAC[complex_div; HAS_PATH_INTEGRAL_COMPLEX_RMUL]);;
+
+let HAS_PATH_INTEGRAL_EQ = prove
+ (`!f g p y.
+        (!x. x IN path_image p ==> f x = g x) /\
+        (f has_path_integral y) p
+        ==> (g has_path_integral y) p`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[path_image; IN_IMAGE; has_path_integral; IMP_CONJ] THEN
+  DISCH_TAC THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HAS_INTEGRAL_EQ) THEN
+  ASM_SIMP_TAC[] THEN ASM_MESON_TAC[]);;
+
+let HAS_PATH_INTEGRAL_BOUND_LINEPATH = prove
+ (`!f i a b B.
+        (f has_path_integral i) (linepath(a,b)) /\
+        &0 <= B /\ (!x. x IN segment[a,b] ==> norm(f x) <= B)
+        ==> norm(i) <= B * norm(b - a)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_path_integral] THEN STRIP_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
+  REWRITE_TAC[GSYM CONTENT_UNIT_1] THEN MATCH_MP_TAC HAS_INTEGRAL_BOUND THEN
+  EXISTS_TAC `\x. f (linepath (a,b) x) *
+                    vector_derivative (linepath (a,b))
+                       (at x within interval [vec 0,vec 1])` THEN
+  ASM_SIMP_TAC[REAL_LE_MUL; NORM_POS_LE;
+               VECTOR_DERIVATIVE_LINEPATH_WITHIN] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[COMPLEX_NORM_MUL] THEN
+  MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[GSYM PATH_IMAGE_LINEPATH; path_image] THEN
+  ASM SET_TAC[]);;
+
+let HAS_PATH_INTEGRAL_BOUND_LINEPATH_STRONG = prove
+ (`!f i a b B k.
+        FINITE k /\
+        (f has_path_integral i) (linepath(a,b)) /\
+        &0 <= B /\ (!x. x IN segment[a,b] DIFF k ==> norm(f x) <= B)
+        ==> norm(i) <= B * norm(b - a)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `b:complex = a` THENL
+   [ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0; REAL_MUL_RZERO] THEN
+    STRIP_TAC THEN SUBGOAL_THEN `i = Cx(&0)`
+      (fun th -> REWRITE_TAC[th; COMPLEX_NORM_0; REAL_LE_REFL]) THEN
+    MATCH_MP_TAC HAS_PATH_INTEGRAL_UNIQUE THEN
+    ASM_MESON_TAC[HAS_PATH_INTEGRAL_TRIVIAL];
+    STRIP_TAC THEN MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_LINEPATH THEN
+    EXISTS_TAC `\x. if x IN k then Cx(&0) else (f:complex->complex) x` THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ALL_TAC; ASM SET_TAC[COMPLEX_NORM_0]] THEN
+    UNDISCH_TAC `(f has_path_integral i) (linepath (a,b))` THEN
+    MATCH_MP_TAC EQ_IMP THEN REWRITE_TAC[has_path_integral] THEN
+    MATCH_MP_TAC HAS_INTEGRAL_SPIKE_EQ THEN
+    EXISTS_TAC `{t | t IN interval[vec 0,vec 1] /\
+                     linepath(a:complex,b) t IN k}` THEN
+    CONJ_TAC THENL [MATCH_MP_TAC NEGLIGIBLE_FINITE; SET_TAC[]] THEN
+    MATCH_MP_TAC FINITE_FINITE_PREIMAGE_GENERAL THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `c:complex` THEN DISCH_TAC THEN
+    MATCH_MP_TAC(MESON[FINITE_SING; FINITE_SUBSET]
+     `(?a. s SUBSET {a}) ==> FINITE s`) THEN
+    MATCH_MP_TAC(SET_RULE
+     `(!a b. a IN s /\ b IN s ==> a = b) ==> (?a. s SUBSET {a})`) THEN
+    MAP_EVERY X_GEN_TAC [`s:real^1`; `t:real^1`] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SYM) THEN FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[linepath; VECTOR_ARITH
+     `(&1 - s) % a + s % b:real^N = (&1 - t) % a + t % b <=>
+      (s - t) % (b - a) = vec 0`] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ; REAL_SUB_0] THEN
+    REWRITE_TAC[DROP_EQ]]);;
+
+let HAS_PATH_INTEGRAL_0 = prove
+ (`!g. ((\x. Cx(&0)) has_path_integral Cx(&0)) g`,
+  REWRITE_TAC[has_path_integral; COMPLEX_MUL_LZERO] THEN
+  REWRITE_TAC[GSYM COMPLEX_VEC_0; HAS_INTEGRAL_0]);;
+
+let HAS_PATH_INTEGRAL_IS_0 = prove
+ (`!f g. (!z. z IN path_image g ==> f(z) = Cx(&0))
+         ==> (f has_path_integral Cx(&0)) g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_PATH_INTEGRAL_EQ THEN
+  EXISTS_TAC `\z:complex. Cx(&0)` THEN
+  ASM_REWRITE_TAC[HAS_PATH_INTEGRAL_0] THEN ASM_MESON_TAC[]);;
+
+let HAS_PATH_INTEGRAL_VSUM = prove
+ (`!f p s. FINITE s /\ (!a. a IN s ==> (f a has_path_integral i a) p)
+           ==> ((\x. vsum s (\a. f a x)) has_path_integral vsum s i) p`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; HAS_PATH_INTEGRAL_0; COMPLEX_VEC_0; IN_INSERT] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_PATH_INTEGRAL_ADD THEN
+  ASM_REWRITE_TAC[ETA_AX] THEN CONJ_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Same thing non-relationally.                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_INTEGRAL_CONST_LINEPATH = prove
+ (`!a b c. path_integral (linepath(a,b)) (\x. c) = c * (b - a)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+  REWRITE_TAC[HAS_PATH_INTEGRAL_CONST_LINEPATH]);;
+
+let PATH_INTEGRAL_NEG = prove
+ (`!f g. f path_integrable_on g
+         ==> path_integral g (\x. --(f x)) = --(path_integral g f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_NEG THEN
+  ASM_SIMP_TAC[HAS_PATH_INTEGRAL_INTEGRAL]);;
+
+let PATH_INTEGRAL_ADD = prove
+ (`!f1 f2 g.
+        f1 path_integrable_on g /\ f2 path_integrable_on g
+        ==> path_integral g (\x. f1(x) + f2(x)) =
+                path_integral g f1 + path_integral g f2`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_ADD THEN
+  ASM_SIMP_TAC[HAS_PATH_INTEGRAL_INTEGRAL]);;
+
+let PATH_INTEGRAL_SUB = prove
+ (`!f1 f2 g.
+        f1 path_integrable_on g /\ f2 path_integrable_on g
+        ==> path_integral g (\x. f1(x) - f2(x)) =
+                path_integral g f1 - path_integral g f2`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_SUB THEN
+  ASM_SIMP_TAC[HAS_PATH_INTEGRAL_INTEGRAL]);;
+
+let PATH_INTEGRAL_COMPLEX_LMUL = prove
+ (`!f g c.  f path_integrable_on g
+           ==> path_integral g (\x. c * f x) = c * path_integral g f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_COMPLEX_LMUL THEN
+  ASM_SIMP_TAC[HAS_PATH_INTEGRAL_INTEGRAL]);;
+
+let PATH_INTEGRAL_COMPLEX_RMUL = prove
+ (`!f g c.  f path_integrable_on g
+           ==> path_integral g (\x. f x * c) = path_integral g f * c`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_COMPLEX_RMUL THEN
+  ASM_SIMP_TAC[HAS_PATH_INTEGRAL_INTEGRAL]);;
+
+let PATH_INTEGRAL_COMPLEX_DIV = prove
+ (`!f g c.  f path_integrable_on g
+           ==> path_integral g (\x. f x / c) = path_integral g f / c`,
+   REWRITE_TAC[complex_div; PATH_INTEGRAL_COMPLEX_RMUL]);;
+
+let PATH_INTEGRAL_EQ = prove
+ (`!f g p.
+        (!x. x IN path_image p ==> f x = g x)
+        ==> path_integral p f = path_integral p g`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[path_integral] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN
+  ASM_MESON_TAC[HAS_PATH_INTEGRAL_EQ]);;
+
+let PATH_INTEGRAL_EQ_0 = prove
+ (`!f g. (!z. z IN path_image g ==> f(z) = Cx(&0))
+         ==> path_integral g f = Cx(&0)`,
+  MESON_TAC[HAS_PATH_INTEGRAL_IS_0; PATH_INTEGRAL_UNIQUE]);;
+
+let PATH_INTEGRAL_BOUND_LINEPATH = prove
+ (`!f a b.
+        f path_integrable_on (linepath(a,b)) /\
+        &0 <= B /\ (!x. x IN segment[a,b] ==> norm(f x) <= B)
+        ==> norm(path_integral (linepath(a,b)) f) <= B * norm(b - a)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_LINEPATH THEN
+  EXISTS_TAC `f:complex->complex` THEN
+  ASM_SIMP_TAC[HAS_PATH_INTEGRAL_INTEGRAL]);;
+
+let PATH_INTEGRAL_0 = prove
+ (`!g. path_integral g (\x. Cx(&0)) = Cx(&0)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+  REWRITE_TAC[HAS_PATH_INTEGRAL_0]);;
+
+let PATH_INTEGRAL_VSUM = prove
+ (`!f p s. FINITE s /\ (!a. a IN s ==> (f a) path_integrable_on p)
+           ==> path_integral p (\x. vsum s (\a. f a x)) =
+                vsum s (\a. path_integral p (f a))`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_VSUM THEN
+  ASM_SIMP_TAC[HAS_PATH_INTEGRAL_INTEGRAL]);;
+
+let PATH_INTEGRABLE_EQ = prove
+ (`!f g p. (!x. x IN path_image p ==> f x = g x) /\ f path_integrable_on p
+           ==> g path_integrable_on p`,
+  REWRITE_TAC[path_integrable_on] THEN MESON_TAC[HAS_PATH_INTEGRAL_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Arithmetic theorems for path integrability.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_INTEGRABLE_NEG = prove
+ (`!f g. f path_integrable_on g
+           ==> (\x. --(f x)) path_integrable_on g`,
+  REWRITE_TAC[path_integrable_on] THEN MESON_TAC[HAS_PATH_INTEGRAL_NEG]);;
+
+let PATH_INTEGRABLE_ADD = prove
+ (`!f1 f2 g.
+        f1 path_integrable_on g /\ f2 path_integrable_on g
+        ==> (\x. f1(x) + f2(x)) path_integrable_on g`,
+  REWRITE_TAC[path_integrable_on] THEN MESON_TAC[HAS_PATH_INTEGRAL_ADD]);;
+
+let PATH_INTEGRABLE_SUB = prove
+ (`!f1 f2 g.
+        f1 path_integrable_on g /\ f2 path_integrable_on g
+        ==> (\x. f1(x) - f2(x)) path_integrable_on g`,
+  REWRITE_TAC[path_integrable_on] THEN MESON_TAC[HAS_PATH_INTEGRAL_SUB]);;
+
+let PATH_INTEGRABLE_COMPLEX_LMUL = prove
+ (`!f g c. f path_integrable_on g
+             ==> (\x. c * f x) path_integrable_on g`,
+  REWRITE_TAC[path_integrable_on] THEN
+  MESON_TAC[HAS_PATH_INTEGRAL_COMPLEX_LMUL]);;
+
+let PATH_INTEGRABLE_COMPLEX_RMUL = prove
+ (`!f g c. f path_integrable_on g
+             ==> (\x. f x * c) path_integrable_on g`,
+  ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+  REWRITE_TAC[PATH_INTEGRABLE_COMPLEX_LMUL]);;
+
+let PATH_INTEGRABLE_COMPLEX_DIV = prove
+ (`!f g c. f path_integrable_on g
+             ==> (\x. f x / c) path_integrable_on g`,
+  REWRITE_TAC[path_integrable_on] THEN
+  MESON_TAC[HAS_PATH_INTEGRAL_COMPLEX_DIV]);;
+
+let PATH_INTEGRABLE_VSUM = prove
+ (`!f g s. FINITE s /\ (!a. a IN s ==> f a path_integrable_on g)
+           ==> (\x. vsum s (\a. f a x)) path_integrable_on g`,
+  REWRITE_TAC[path_integrable_on] THEN
+  MESON_TAC[HAS_PATH_INTEGRAL_VSUM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Considering a path integral "backwards".                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_PATH_INTEGRAL_REVERSE_LINEPATH = prove
+ (`!f a b i.
+        (f has_path_integral i) (linepath(a,b))
+        ==> (f has_path_integral (--i)) (linepath(b,a))`,
+  MESON_TAC[REVERSEPATH_LINEPATH; VALID_PATH_LINEPATH;
+            HAS_PATH_INTEGRAL_REVERSEPATH]);;
+
+let PATH_INTEGRAL_REVERSE_LINEPATH = prove
+ (`!f a b.
+        f continuous_on (segment[a,b])
+        ==> path_integral(linepath(a,b)) f =
+            --(path_integral(linepath(b,a)) f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_REVERSE_LINEPATH THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_INTEGRAL THEN
+  MATCH_MP_TAC PATH_INTEGRABLE_CONTINUOUS_LINEPATH THEN
+  ASM_MESON_TAC[SEGMENT_SYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Splitting a path integral in a flat way.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_PATH_INTEGRAL_SPLIT = prove
+ (`!f a b c i j k.
+        &0 <= k /\ k <= &1 /\ c - a = k % (b - a) /\
+        (f has_path_integral i) (linepath(a,c)) /\
+        (f has_path_integral j) (linepath(c,b))
+        ==> (f has_path_integral (i + j)) (linepath(a,b))`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_CASES_TAC `k = &0` THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_SUB_EQ] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[HAS_PATH_INTEGRAL_TRIVIAL; PATH_INTEGRAL_UNIQUE;
+                  COMPLEX_ADD_LID];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `k = &1` THEN ASM_REWRITE_TAC[VECTOR_MUL_LID] THENL
+   [REWRITE_TAC[VECTOR_ARITH `c - a = b - a <=> c = b:real^N`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[HAS_PATH_INTEGRAL_TRIVIAL; PATH_INTEGRAL_UNIQUE;
+                  COMPLEX_ADD_RID];
+    ALL_TAC] THEN
+  REWRITE_TAC[HAS_PATH_INTEGRAL_LINEPATH] THEN
+  REWRITE_TAC[linepath] THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN
+   (MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] HAS_INTEGRAL_AFFINITY))) THEN
+  DISCH_THEN(ASSUME_TAC o SPECL
+    [`inv(&1 - k):real`; `--(k / (&1 - k)) % vec 1:real^1`]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`inv(k):real`; `vec 0:real^1`]) THEN
+  POP_ASSUM MP_TAC THEN ASM_REWRITE_TAC[REAL_INV_EQ_0; REAL_SUB_0] THEN
+  REWRITE_TAC[REAL_INV_INV; DIMINDEX_1; REAL_POW_1; REAL_ABS_INV] THEN
+  REWRITE_TAC[IMAGE_AFFINITY_INTERVAL] THEN
+  REWRITE_TAC[INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN
+  ASM_REWRITE_TAC[REAL_SUB_LE; REAL_ARITH `~(&1 < &0)`] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_NEG_0; VECTOR_ADD_RID] THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC; VECTOR_MUL_LNEG] THEN
+  ASM_SIMP_TAC[REAL_FIELD
+    `~(k = &1) ==> (&1 - k) * --(k / (&1 - k)) = --k`] THEN
+  REWRITE_TAC[VECTOR_ADD_LID; VECTOR_MUL_LNEG; VECTOR_NEG_NEG;
+              VECTOR_ARITH `(&1 - k) % x + k % x:real^1 = x`] THEN
+  REWRITE_TAC[DROP_ADD; DROP_CMUL; DROP_NEG; DROP_VEC; REAL_MUL_RID] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP (VECTOR_ARITH
+    `c - a = x ==> c = x + a`)) THEN
+  REWRITE_TAC[VECTOR_ARITH `b - (k % (b - a) + a) = (&1 - k) % (b - a)`] THEN
+  SUBGOAL_THEN
+   `!x. (&1 - (inv (&1 - k) * drop x + --(k / (&1 - k)))) % (k % (b - a) + a) +
+        (inv (&1 - k) * drop x + --(k / (&1 - k))) % b =
+        (&1 - drop x) % a + drop x % b`
+   (fun th -> REWRITE_TAC[th]) THENL
+   [REWRITE_TAC[VECTOR_ARITH
+     `x % (k % (b - a) + a) + y % b =
+      (x * (&1 - k)) % a + (y + x * k) % b`] THEN
+    GEN_TAC THEN BINOP_TAC THEN BINOP_TAC THEN REWRITE_TAC[] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x. (&1 - inv k * drop x) % a + (inv k * drop x) % (k % (b - a) + a) =
+        (&1 - drop x) % a + drop x % b`
+   (fun th -> REWRITE_TAC[th]) THENL
+   [REWRITE_TAC[VECTOR_ARITH
+     `x % a + y % (k % (b - a) + a) =
+      (x + y * (&1 - k)) % a + (y * k) % b`] THEN
+    GEN_TAC THEN BINOP_TAC THEN BINOP_TAC THEN REWRITE_TAC[] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD;
+    ALL_TAC] THEN
+  DISCH_TAC THEN
+  DISCH_THEN(MP_TAC o SPEC `inv(k:real)` o MATCH_MP HAS_INTEGRAL_CMUL) THEN
+  FIRST_ASSUM(MP_TAC o SPEC `inv(&1 - k)` o MATCH_MP HAS_INTEGRAL_CMUL) THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 <= k ==> abs k = k`;
+               REAL_ARITH `k <= &1 ==> abs(&1 - k) = &1 - k`] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; REAL_SUB_0] THEN
+  REWRITE_TAC[IMP_IMP; VECTOR_MUL_LID] THEN
+  REWRITE_TAC[COMPLEX_CMUL] THEN
+  ONCE_REWRITE_TAC[COMPLEX_RING
+   `Cx(inv a) * b * Cx(a) * c = (Cx(inv a) * Cx a) * b * c`] THEN
+  ASM_SIMP_TAC[GSYM CX_MUL; REAL_MUL_LINV; REAL_SUB_0; COMPLEX_MUL_LID] THEN
+  STRIP_TAC THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMBINE THEN EXISTS_TAC `k % vec 1:real^1` THEN
+  ASM_REWRITE_TAC[DROP_CMUL; DROP_VEC; REAL_MUL_RID]);;
+
+let PATH_INTEGRAL_SPLIT = prove
+ (`!f a b c k.
+        &0 <= k /\ k <= &1 /\ c - a = k % (b - a) /\
+        f continuous_on (segment[a,b])
+        ==> path_integral(linepath(a,b)) f =
+            path_integral(linepath(a,c)) f +
+            path_integral(linepath(c,b)) f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_SPLIT THEN
+  MAP_EVERY EXISTS_TAC [`c:complex`; `k:real`] THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THEN MATCH_MP_TAC HAS_PATH_INTEGRAL_INTEGRAL THEN
+  MATCH_MP_TAC PATH_INTEGRABLE_CONTINUOUS_LINEPATH THEN
+  MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+  EXISTS_TAC `segment[a:complex,b]` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC CONVEX_HULL_SUBSET THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[POINTS_IN_CONVEX_HULL; IN_INSERT] THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP (VECTOR_ARITH
+   `c - a = k % (b - a) ==> c = (&1 - k) % a + k % b`)) THEN
+  MATCH_MP_TAC IN_CONVEX_SET THEN
+  ASM_SIMP_TAC[CONVEX_CONVEX_HULL; POINTS_IN_CONVEX_HULL; IN_INSERT]);;
+
+let PATH_INTEGRAL_SPLIT_LINEPATH = prove
+ (`!f a b c.
+        f continuous_on segment[a,b] /\ c IN segment[a,b]
+        ==> path_integral(linepath (a,b)) f =
+            path_integral(linepath (a,c)) f +
+            path_integral(linepath (c,b)) f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_SPLIT THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_SEGMENT]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  VECTOR_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* The special case of midpoints used in the main quadrisection.             *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_PATH_INTEGRAL_MIDPOINT = prove
+ (`!f a b i j.
+        (f has_path_integral i) (linepath(a,midpoint(a,b))) /\
+        (f has_path_integral j) (linepath(midpoint(a,b),b))
+        ==> (f has_path_integral (i + j)) (linepath(a,b))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_PATH_INTEGRAL_SPLIT THEN
+  MAP_EVERY EXISTS_TAC [`midpoint(a:complex,b)`; `&1 / &2`] THEN
+  ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[midpoint] THEN VECTOR_ARITH_TAC);;
+
+let PATH_INTEGRAL_MIDPOINT = prove
+ (`!f a b.
+        f continuous_on (segment[a,b])
+        ==> path_integral(linepath(a,b)) f =
+            path_integral(linepath(a,midpoint(a,b))) f +
+            path_integral(linepath(midpoint(a,b),b)) f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_SPLIT THEN
+  EXISTS_TAC `&1 / &2` THEN
+  ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[midpoint] THEN VECTOR_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* A couple of special case lemmas that are useful below.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let TRIANGLE_LINEAR_HAS_CHAIN_INTEGRAL = prove
+ (`!a b c m d. ((\x. m * x + d) has_path_integral Cx(&0))
+         (linepath(a,b) ++ linepath(b,c) ++ linepath(c,a))`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC CAUCHY_THEOREM_PRIMITIVE THEN
+  MAP_EVERY EXISTS_TAC [`\x. m / Cx(&2) * x pow 2 + d * x`; `(:complex)`] THEN
+  SIMP_TAC[PATHSTART_JOIN; PATHFINISH_JOIN; PATHSTART_LINEPATH; SUBSET_UNIV;
+           PATHFINISH_LINEPATH; VALID_PATH_JOIN; VALID_PATH_LINEPATH] THEN
+  REPEAT STRIP_TAC THEN COMPLEX_DIFF_TAC THEN CONV_TAC NUM_REDUCE_CONV THEN
+  CONV_TAC COMPLEX_RING);;
+
+let HAS_CHAIN_INTEGRAL_CHAIN_INTEGRAL = prove
+ (`!f i a b c d.
+        (f has_path_integral i)
+        (linepath(a,b) ++ linepath(b,c) ++ linepath(c,d))
+        ==> path_integral (linepath(a,b)) f +
+            path_integral (linepath(b,c)) f +
+            path_integral (linepath(c,d)) f = i`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP PATH_INTEGRAL_UNIQUE) THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_INTEGRABLE) THEN
+  SIMP_TAC[PATH_INTEGRABLE_JOIN; VALID_PATH_LINEPATH; VALID_PATH_JOIN;
+           PATHSTART_JOIN; PATHFINISH_JOIN; PATHSTART_LINEPATH;
+           PATHFINISH_LINEPATH] THEN
+  STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+  REPEAT(MATCH_MP_TAC HAS_PATH_INTEGRAL_JOIN THEN
+         SIMP_TAC[VALID_PATH_LINEPATH; VALID_PATH_JOIN;
+                  PATHSTART_JOIN; PATHFINISH_JOIN; PATHSTART_LINEPATH;
+                  PATHFINISH_LINEPATH] THEN
+         CONJ_TAC) THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_INTEGRAL THEN ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Reversing the order in a double path integral. The condition is           *)
+(* stronger than needed but it's often true in typical situations.           *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_INTEGRAL_SWAP = prove
+ (`!f g h.
+    (\y. f (fstcart y) (sndcart y)) continuous_on
+    (path_image g PCROSS path_image h) /\
+    valid_path g /\ valid_path h /\
+    (\t. vector_derivative g (at t)) continuous_on interval[vec 0,vec 1] /\
+    (\t. vector_derivative h (at t)) continuous_on interval[vec 0,vec 1]
+    ==> path_integral g (\w. path_integral h (f w)) =
+        path_integral h (\z. path_integral g (\w. f w z))`,
+  REWRITE_TAC[PCROSS] THEN REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[PATH_INTEGRAL_INTEGRAL] THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC
+   `integral (interval[vec 0,vec 1])
+             (\x. path_integral h
+                    (\y. f (g x) y * vector_derivative g (at x)))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC INTEGRAL_EQ THEN X_GEN_TAC `x:real^1` THEN
+    DISCH_TAC THEN REWRITE_TAC[] THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC PATH_INTEGRAL_COMPLEX_RMUL THEN
+    REWRITE_TAC[PATH_INTEGRABLE_ON] THEN
+    MATCH_MP_TAC INTEGRABLE_CONTINUOUS THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN
+     `(\t:real^1. (f:complex->complex->complex) (g x) (h t)) =
+      (\y. f (fstcart y) (sndcart y)) o
+      (\t. pastecart (g(x:real^1)) (h t))`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[o_DEF; FSTCART_PASTECART; SNDCART_PASTECART];
+      ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+      ASM_SIMP_TAC[CONTINUOUS_ON_CONST; GSYM path; VALID_PATH_IMP_PATH];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+         CONTINUOUS_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_PASTECART_THM] THEN
+      ASM_SIMP_TAC[path_image; FUN_IN_IMAGE]];
+    ALL_TAC] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `integral (interval[vec 0,vec 1])
+             (\y. path_integral g
+                    (\x. f x (h y) * vector_derivative h (at y)))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC INTEGRAL_EQ THEN X_GEN_TAC `y:real^1` THEN
+    DISCH_TAC THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC PATH_INTEGRAL_COMPLEX_RMUL THEN
+    REWRITE_TAC[PATH_INTEGRABLE_ON] THEN
+    MATCH_MP_TAC INTEGRABLE_CONTINUOUS THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN
+     `(\t:real^1. (f:complex->complex->complex) (g t) (h y)) =
+      (\z. f (fstcart z) (sndcart z)) o
+      (\t. pastecart (g t) (h(y:real^1)))`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[o_DEF; FSTCART_PASTECART; SNDCART_PASTECART];
+      ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+      ASM_SIMP_TAC[CONTINUOUS_ON_CONST; GSYM path; VALID_PATH_IMP_PATH];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+         CONTINUOUS_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_PASTECART_THM] THEN
+      ASM_SIMP_TAC[path_image; FUN_IN_IMAGE]]] THEN
+  REWRITE_TAC[PATH_INTEGRAL_INTEGRAL] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand)
+     INTEGRAL_SWAP_CONTINUOUS o lhs o snd) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ALL_TAC;
+    DISCH_THEN(fun th -> GEN_REWRITE_TAC LAND_CONV [th]) THEN
+    REPEAT(MATCH_MP_TAC INTEGRAL_EQ THEN
+           REWRITE_TAC[] THEN REPEAT STRIP_TAC) THEN
+    REWRITE_TAC[COMPLEX_MUL_AC]] THEN
+  REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN CONJ_TAC) THENL
+   [ALL_TAC;
+    SUBGOAL_THEN
+     `(\z:real^(1,1)finite_sum. vector_derivative g (at (fstcart z))) =
+      (\t. vector_derivative (g:real^1->complex) (at t)) o fstcart`
+    SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_PASTECART_THM; PCROSS;
+             FORALL_PASTECART; GSYM PCROSS_INTERVAL; FSTCART_PASTECART];
+    SUBGOAL_THEN
+     `(\z:real^(1,1)finite_sum. vector_derivative h (at (sndcart z))) =
+      (\t. vector_derivative (h:real^1->complex) (at t)) o sndcart`
+    SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_PASTECART_THM; PCROSS;
+          FORALL_PASTECART; GSYM PCROSS_INTERVAL; SNDCART_PASTECART]] THEN
+  SUBGOAL_THEN
+   `(\z. f (g (fstcart z)) (h (sndcart z))) =
+    (\y. (f:complex->complex->complex) (fstcart y) (sndcart y)) o
+    (\p. pastecart (g(fstcart p:real^1)) (h(sndcart p:real^1)))`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[o_DEF; FSTCART_PASTECART; SNDCART_PASTECART]; ALL_TAC] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+    CONJ_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART] THEN
+    REWRITE_TAC[GSYM PCROSS_INTERVAL; PCROSS; GSYM SIMPLE_IMAGE] THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART;
+                SET_RULE `{f x | x IN {g a b | P a /\ Q b}} =
+                          {f(g a b) | P a /\ Q b}`] THEN
+    REPEAT(FIRST_X_ASSUM(ASSUME_TAC o REWRITE_RULE[path] o
+        MATCH_MP VALID_PATH_IMP_PATH)) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      CONTINUOUS_ON_SUBSET)) THEN
+    SIMP_TAC[SUBSET; FORALL_IN_GSPEC];
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      CONTINUOUS_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_PASTECART_THM;
+                FORALL_PASTECART; GSYM PCROSS_INTERVAL; PCROSS;
+                path_image; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    SIMP_TAC[FUN_IN_IMAGE]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The key quadrisection step.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let NORM_SUM_LEMMA = prove
+ (`norm(a + b + c + d:complex) >= e
+   ==> norm(a) >= e / &4 \/
+       norm(b) >= e / &4 \/
+       norm(c) >= e / &4 \/
+       norm(d) >= e / &4`,
+  NORM_ARITH_TAC);;
+
+let CAUCHY_THEOREM_QUADRISECTION = prove
+ (`!f a b c e K.
+        f continuous_on (convex hull {a,b,c}) /\
+        dist (a,b) <= K /\
+        dist (b,c) <= K /\
+        dist (c,a) <= K /\
+        norm(path_integral(linepath(a,b)) f +
+             path_integral(linepath(b,c)) f +
+             path_integral(linepath(c,a)) f) >= e * K pow 2
+        ==> ?a' b' c'. a' IN convex hull {a,b,c} /\
+                       b' IN convex hull {a,b,c} /\
+                       c' IN convex hull {a,b,c} /\
+                       dist(a',b') <= K / &2 /\
+                       dist(b',c') <= K / &2 /\
+                       dist(c',a') <= K / &2 /\
+                       norm(path_integral(linepath(a',b')) f +
+                            path_integral(linepath(b',c')) f +
+                            path_integral(linepath(c',a')) f)
+                        >= e * (K / &2) pow 2`,
+  REPEAT STRIP_TAC THEN MAP_EVERY ABBREV_TAC
+   [`a':complex = midpoint(b,c)`;
+    `b':complex = midpoint(c,a)`;
+    `c':complex = midpoint(a,b)`] THEN
+  SUBGOAL_THEN
+   `path_integral(linepath(a,b)) f +
+    path_integral(linepath(b,c)) f +
+    path_integral(linepath(c,a)) f =
+    (path_integral(linepath(a,c')) f +
+     path_integral(linepath(c',b')) f +
+     path_integral(linepath(b',a)) f) +
+    (path_integral(linepath(a',c')) f +
+     path_integral(linepath(c',b)) f +
+     path_integral(linepath(b,a')) f) +
+    (path_integral(linepath(a',c)) f +
+     path_integral(linepath(c,b')) f +
+     path_integral(linepath(b',a')) f) +
+    (path_integral(linepath(a',b')) f +
+     path_integral(linepath(b',c')) f +
+     path_integral(linepath(c',a')) f)`
+  SUBST_ALL_TAC THENL
+   [MP_TAC(SPEC `f:complex->complex` PATH_INTEGRAL_MIDPOINT) THEN DISCH_THEN
+     (fun th -> MP_TAC(SPECL [`a:complex`; `b:complex`] th) THEN
+                MP_TAC(SPECL [`b:complex`; `c:complex`] th) THEN
+                MP_TAC(SPECL [`c:complex`; `a:complex`] th)) THEN
+    MP_TAC(SPEC `f:complex->complex` PATH_INTEGRAL_REVERSE_LINEPATH) THEN DISCH_THEN
+     (fun th -> MP_TAC(SPECL [`a':complex`; `b':complex`] th) THEN
+                MP_TAC(SPECL [`b':complex`; `c':complex`] th) THEN
+                MP_TAC(SPECL [`c':complex`; `a':complex`] th)) THEN
+    ASM_REWRITE_TAC[] THEN
+    REPEAT(MATCH_MP_TAC(TAUT
+     `((a /\ c ==> b /\ d) ==> e) ==> (a ==> b) ==> (c ==> d) ==> e`)) THEN
+    ANTS_TAC THENL [ALL_TAC; CONV_TAC COMPLEX_RING] THEN
+    REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+    REPEAT CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+    EXISTS_TAC `convex hull {a:complex,b,c}` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC CONVEX_HULL_SUBSET THEN
+    SIMP_TAC[IN_INSERT; NOT_IN_EMPTY;
+             TAUT `(a \/ b ==> c) <=> (a ==> c) /\ (b ==> c)`] THEN
+    MAP_EVERY EXPAND_TAC ["a'"; "b'"; "c'"] THEN
+    SIMP_TAC[MIDPOINTS_IN_CONVEX_HULL; POINTS_IN_CONVEX_HULL; IN_INSERT];
+    ALL_TAC] THEN
+  REWRITE_TAC[REAL_ARITH `e * (K / &2) pow 2 = (e * K pow 2) / &4`] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP NORM_SUM_LEMMA) THEN STRIP_TAC THENL
+   [MAP_EVERY EXISTS_TAC [`a:complex`; `c':complex`; `b':complex`];
+    MAP_EVERY EXISTS_TAC [`a':complex`; `c':complex`; `b:complex`];
+    MAP_EVERY EXISTS_TAC [`a':complex`; `c:complex`; `b':complex`];
+    MAP_EVERY EXISTS_TAC [`a':complex`; `b':complex`; `c':complex`]] THEN
+  ASM_REWRITE_TAC[] THEN
+  MAP_EVERY EXPAND_TAC ["a'"; "b'"; "c'"] THEN
+  SIMP_TAC[MIDPOINTS_IN_CONVEX_HULL; POINTS_IN_CONVEX_HULL; IN_INSERT] THEN
+  REWRITE_TAC[midpoint; dist; GSYM VECTOR_SUB_LDISTRIB;
+              VECTOR_ARITH `a - inv(&2) % (a + b) = inv(&2) % (a - b)`;
+              VECTOR_ARITH `inv(&2) % (c + a) - a = inv(&2) % (c - a)`;
+              VECTOR_ARITH `(a + b) - (c + a) = b - c`;
+              VECTOR_ARITH `(b + c) - (c + a) = b - a`] THEN
+  SIMP_TAC[NORM_MUL; REAL_ARITH `abs(inv(&2)) * x <= k / &2 <=> x <= k`] THEN
+  ASM_REWRITE_TAC[GSYM dist] THEN ASM_MESON_TAC[DIST_SYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Yet at small enough scales this cannot be the case.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let TRIANGLE_POINTS_CLOSER = prove
+ (`!a b c x y:real^N.
+        x IN convex hull {a,b,c} /\
+        y IN convex hull {a,b,c}
+        ==> norm(x - y) <= norm(a - b) \/
+            norm(x - y) <= norm(b - c) \/
+            norm(x - y) <= norm(c - a)`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPEC `{a:real^N,b,c}` SIMPLEX_EXTREMAL_LE) THEN
+  REWRITE_TAC[FINITE_INSERT; FINITE_RULES; NOT_INSERT_EMPTY] THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `y:real^N`]) THEN
+  ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+  ASM_MESON_TAC[NORM_POS_LE; REAL_LE_TRANS; NORM_SUB]);;
+
+let HOLOMORPHIC_POINT_SMALL_TRIANGLE = prove
+ (`!f s x e.
+        x IN s /\ f continuous_on s /\
+        f complex_differentiable (at x within s) /\
+        &0 < e
+        ==> ?k. &0 < k /\
+                !a b c. dist(a,b) <= k /\ dist(b,c) <= k /\ dist(c,a) <= k /\
+                        x IN convex hull {a,b,c} /\ convex hull {a,b,c} SUBSET s
+                        ==> norm(path_integral(linepath(a,b)) f +
+                                 path_integral(linepath(b,c)) f +
+                                 path_integral(linepath(c,a)) f)
+                            <= e * (dist(a,b) + dist(b,c) + dist(c,a)) pow 2`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [complex_differentiable]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `f':complex` MP_TAC) THEN
+  GEN_REWRITE_TAC LAND_CONV [has_complex_derivative] THEN
+  REWRITE_TAC[HAS_DERIVATIVE_WITHIN_ALT] THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real` o CONJUNCT2) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+   [TAUT `a /\ b ==> c <=> b ==> a ==> c`] THEN
+  REWRITE_TAC[APPROACHABLE_LT_LE] THEN
+  ONCE_REWRITE_TAC[TAUT `b ==> a ==> c <=> a /\ b ==> c`] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[dist] THEN
+  MAP_EVERY X_GEN_TAC [`a:complex`; `b:complex`; `c:complex`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN
+   `path_integral (linepath(a,b)) f +
+    path_integral (linepath(b,c)) f +
+    path_integral (linepath(c,a)) f =
+    path_integral (linepath(a,b)) (\y. f y - f x - f' * (y - x)) +
+    path_integral (linepath(b,c)) (\y. f y - f x - f' * (y - x)) +
+    path_integral (linepath(c,a)) (\y. f y - f x - f' * (y - x))`
+  SUBST1_TAC THENL
+   [SUBGOAL_THEN
+     `path_integral (linepath(a,b)) (\y. f y - f x - f' * (y - x)) =
+      path_integral (linepath(a,b)) f -
+      path_integral (linepath(a,b)) (\y. f x + f' * (y - x)) /\
+      path_integral (linepath(b,c)) (\y. f y - f x - f' * (y - x)) =
+      path_integral (linepath(b,c)) f -
+      path_integral (linepath(b,c)) (\y. f x + f' * (y - x)) /\
+      path_integral (linepath(c,a)) (\y. f y - f x - f' * (y - x)) =
+      path_integral (linepath(c,a)) f -
+      path_integral (linepath(c,a)) (\y. f x + f' * (y - x))`
+    (REPEAT_TCL CONJUNCTS_THEN SUBST1_TAC) THENL
+     [REWRITE_TAC[SIMPLE_COMPLEX_ARITH `a - b - c = a - (b + c)`] THEN
+      REPEAT CONJ_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+      MATCH_MP_TAC HAS_PATH_INTEGRAL_SUB THEN
+      CONJ_TAC THEN MATCH_MP_TAC HAS_PATH_INTEGRAL_INTEGRAL THEN
+      MATCH_MP_TAC PATH_INTEGRABLE_CONTINUOUS_LINEPATH THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+      EXISTS_TAC `s:complex->bool` THEN
+      ASM_SIMP_TAC[CONTINUOUS_ON_ID; CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST;
+                   CONTINUOUS_ON_COMPLEX_MUL; CONTINUOUS_ON_SUB] THEN
+      MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `convex hull {a:complex,b,c}` THEN
+      ASM_REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+      MATCH_MP_TAC CONVEX_HULL_SUBSET THEN
+      REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN REPEAT STRIP_TAC THEN
+      ASM_SIMP_TAC[MIDPOINTS_IN_CONVEX_HULL; POINTS_IN_CONVEX_HULL; IN_INSERT];
+      ALL_TAC] THEN
+    REWRITE_TAC[COMPLEX_RING
+     `x + y + z = (x - x') + (y - y') + (z - z') <=>
+      x' + y' + z' = Cx(&0)`] THEN
+    MP_TAC(ISPECL [`a:complex`; `b:complex`; `c:complex`;
+                   `f':complex`; `f x - f' * x`]
+           TRIANGLE_LINEAR_HAS_CHAIN_INTEGRAL) THEN
+    REWRITE_TAC[COMPLEX_RING
+     `f' * x' + f x - f' * x = f x + f' * (x' - x)`] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_CHAIN_INTEGRAL_CHAIN_INTEGRAL) THEN
+    REWRITE_TAC[];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[NORM_SUB] THEN MATCH_MP_TAC(REAL_ARITH
+   `&0 <= x * y /\ &0 <= x * z /\ &0 <= y * z /\
+    a <= (e * (x + y + z)) * x +
+         (e * (x + y + z)) * y +
+         (e * (x + y + z)) * z
+    ==> a <= e * (x + y + z) pow 2`) THEN
+  SIMP_TAC[REAL_LE_MUL; NORM_POS_LE] THEN
+  REPEAT(MATCH_MP_TAC NORM_TRIANGLE_LE THEN
+         MATCH_MP_TAC REAL_LE_ADD2 THEN CONJ_TAC) THEN
+  (MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_LINEPATH THEN
+   EXISTS_TAC `\y:complex. f y - f x - f' * (y - x)` THEN
+   ASM_SIMP_TAC[REAL_LE_MUL; REAL_LE_ADD; REAL_LT_IMP_LE; NORM_POS_LE] THEN
+   CONJ_TAC THENL
+    [MATCH_MP_TAC HAS_PATH_INTEGRAL_INTEGRAL THEN
+     MATCH_MP_TAC PATH_INTEGRABLE_CONTINUOUS_LINEPATH THEN
+     MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:complex->bool` THEN
+     ASM_SIMP_TAC[CONTINUOUS_ON_SUB; ETA_AX; CONTINUOUS_ON_COMPLEX_MUL;
+                 CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+     MATCH_MP_TAC SUBSET_TRANS THEN
+     EXISTS_TAC `convex hull {a:complex,b,c}` THEN
+     ASM_REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+     MATCH_MP_TAC CONVEX_HULL_SUBSET THEN
+     REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN REPEAT STRIP_TAC THEN
+     ASM_SIMP_TAC[MIDPOINTS_IN_CONVEX_HULL; POINTS_IN_CONVEX_HULL; IN_INSERT];
+     ALL_TAC] THEN
+   X_GEN_TAC `y:complex` THEN STRIP_TAC THEN
+   MATCH_MP_TAC REAL_LE_TRANS THEN
+   EXISTS_TAC `e * norm(y - x:complex)` THEN CONJ_TAC THENL
+    [FIRST_X_ASSUM MATCH_MP_TAC THEN CONJ_TAC THENL
+      [MATCH_MP_TAC(SET_RULE `!t. y IN t /\ t SUBSET s ==> y IN s`) THEN
+       EXISTS_TAC `convex hull {a:complex,b,c}` THEN ASM_REWRITE_TAC[];
+       MATCH_MP_TAC(REAL_ARITH
+        `!n1 n2 n3. n1 <= d /\ n2 <= d /\ n3 <= d /\
+                    (n <= n1 \/ n <= n2 \/ n <= n3)
+                    ==> n <= d`) THEN
+       MAP_EVERY EXISTS_TAC
+        [`norm(a - b:complex)`; `norm(b - c:complex)`;
+         `norm(c - a:complex)`] THEN
+       ASM_REWRITE_TAC[] THEN MATCH_MP_TAC TRIANGLE_POINTS_CLOSER];
+     ASM_SIMP_TAC[REAL_LE_LMUL_EQ] THEN
+     ONCE_REWRITE_TAC[NORM_SUB] THEN
+     MATCH_MP_TAC(REAL_ARITH
+      `(x <= a \/ x <= b \/ x <= c) /\ (&0 <= a /\ &0 <= b /\ &0 <= c)
+       ==> x <= a + b + c`) THEN
+     REWRITE_TAC[NORM_POS_LE] THEN MATCH_MP_TAC TRIANGLE_POINTS_CLOSER THEN
+     ASM_REWRITE_TAC[]] THEN
+    REPEAT CONJ_TAC THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `x IN s ==> s SUBSET t ==> x IN t`)) THEN
+    REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC CONVEX_HULL_SUBSET THEN
+    REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN REPEAT STRIP_TAC THEN
+    ASM_SIMP_TAC[MIDPOINTS_IN_CONVEX_HULL; POINTS_IN_CONVEX_HULL;
+                 IN_INSERT]));;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence the most basic theorem for a triangle.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_THEOREM_TRIANGLE = prove
+ (`!f a b c.
+        f holomorphic_on (convex hull {a,b,c})
+        ==> (f has_path_integral Cx(&0))
+            (linepath(a,b) ++ linepath(b,c) ++ linepath(c,a))`,
+  let lemma1 = prove
+   (`!P Q abc.
+          P abc 0 /\
+          (!abc:A n. P abc n ==> ?abc'. P abc' (SUC n) /\ Q abc' abc)
+          ==> ?ABC. ABC 0 = abc /\ !n. P (ABC n) n /\ Q (ABC(SUC n)) (ABC n)`,
+    REPEAT STRIP_TAC THEN
+    (MP_TAC o prove_recursive_functions_exist num_RECURSION)
+      `ABC 0 = abc:A /\
+       !n. ABC(SUC n) = @abc. P abc (SUC n) /\ Q abc (ABC n)` THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+    STRIP_TAC THEN CONJ_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+    REWRITE_TAC[FORALL_AND_THM] THEN
+    MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+     [INDUCT_TAC THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+    DISCH_TAC THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]) in
+  let lemma3 = prove
+   (`!P Q a:A b:A c:A.
+          P a b c 0 /\
+          (!a b c n. P a b c n
+                     ==> ?a' b' c'. P a' b' c' (SUC n) /\ Q a' b' c' a b c)
+          ==> ?A B C. A 0 = a /\ B 0 = b /\ C 0 = c /\
+                      !n. P (A n) (B n) (C n) n /\
+                          Q (A(SUC n)) (B(SUC n)) (C(SUC n)) (A n) (B n) (C n)`,
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`\(a,b,c). (P:A->A->A->num->bool) a b c`;
+      `\(a,b,c) (a',b',c'). (Q:A->A->A->A->A->A->bool) a b c a' b' c'`;
+      `(a:A,b:A,c:A)`]
+          lemma1) THEN
+    REWRITE_TAC[FORALL_PAIR_THM; EXISTS_PAIR_THM] THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `ABC:num->A#A#A` STRIP_ASSUME_TAC) THEN
+    MAP_EVERY EXISTS_TAC
+     [`(\(a,b,c). a) o (ABC:num->A#A#A)`;
+      `(\(a,b,c). b) o (ABC:num->A#A#A)`;
+      `(\(a,b,c). c) o (ABC:num->A#A#A)`] THEN
+    REWRITE_TAC[o_THM] THEN
+    REPEAT(CONJ_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC]) THEN
+    X_GEN_TAC `n:num` THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `n:num`) THEN
+    SPEC_TAC(`(ABC:num->A#A#A) (SUC n)`,`y:A#A#A`) THEN
+    SPEC_TAC(`(ABC:num->A#A#A) n`,`x:A#A#A`) THEN
+    REWRITE_TAC[FORALL_PAIR_THM]) in
+  REPEAT STRIP_TAC THEN
+  STRIP_ASSUME_TAC(ISPECL [`a:complex`; `b:complex`; `c:complex`]
+                SEGMENTS_SUBSET_CONVEX_HULL) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP HOLOMORPHIC_ON_IMP_CONTINUOUS_ON) THEN
+  SUBGOAL_THEN
+   `f path_integrable_on (linepath(a,b) ++ linepath(b,c) ++ linepath(c,a))`
+  MP_TAC THENL
+   [SIMP_TAC[PATH_INTEGRABLE_JOIN; VALID_PATH_JOIN; VALID_PATH_LINEPATH;
+             PATHSTART_JOIN; PATHFINISH_JOIN; PATHSTART_LINEPATH;
+             PATHFINISH_LINEPATH] THEN
+    ASM_MESON_TAC[PATH_INTEGRABLE_CONTINUOUS_LINEPATH; CONTINUOUS_ON_SUBSET];
+    ALL_TAC] THEN
+  SIMP_TAC[path_integrable_on] THEN DISCH_THEN(X_CHOOSE_TAC `y:complex`) THEN
+  ASM_CASES_TAC `y = Cx(&0)` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  ABBREV_TAC
+   `K = &1 + max (dist(a:complex,b)) (max (dist(b,c)) (dist(c,a)))` THEN
+  SUBGOAL_THEN `&0 < K` ASSUME_TAC THENL
+   [EXPAND_TAC "K" THEN MATCH_MP_TAC(REAL_ARITH `&0 <= x ==> &0 < &1 + x`) THEN
+    REWRITE_TAC[REAL_LE_MAX; DIST_POS_LE];
+    ALL_TAC] THEN
+  ABBREV_TAC `e = norm(y:complex) / K pow 2` THEN
+  SUBGOAL_THEN `&0 < e` ASSUME_TAC THENL
+   [EXPAND_TAC "e" THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_POW_LT; COMPLEX_NORM_NZ];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?A B C. A 0 = a /\ B 0 = b /\ C 0 = c /\
+            !n. (convex hull {A n,B n,C n} SUBSET convex hull {a,b,c} /\
+                 dist(A n,B n) <= K / &2 pow n /\
+                 dist(B n,C n) <= K / &2 pow n /\
+                 dist(C n,A n) <= K / &2 pow n /\
+                 norm(path_integral(linepath (A n,B n)) f +
+                      path_integral(linepath (B n,C n)) f +
+                      path_integral(linepath (C n,A n)) f) >=
+                 e * (K / &2 pow n) pow 2) /\
+                convex hull {A(SUC n),B(SUC n),C(SUC n)} SUBSET
+                convex hull {A n,B n,C n}`
+  MP_TAC THENL
+   [MATCH_MP_TAC lemma3 THEN CONJ_TAC THENL
+     [ASM_REWRITE_TAC[real_pow; REAL_DIV_1; CONJ_ASSOC; SUBSET_REFL] THEN
+      CONJ_TAC THENL [EXPAND_TAC "K" THEN REAL_ARITH_TAC; ALL_TAC] THEN
+      EXPAND_TAC "e" THEN
+      ASM_SIMP_TAC[REAL_DIV_RMUL; REAL_LT_IMP_NZ; REAL_POW_LT] THEN
+      MATCH_MP_TAC(REAL_ARITH `x = y ==> x >= y`) THEN AP_TERM_TAC THEN
+      FIRST_ASSUM(SUBST1_TAC o SYM o
+        MATCH_MP HAS_CHAIN_INTEGRAL_CHAIN_INTEGRAL) THEN
+      REWRITE_TAC[];
+      ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC
+     [`a':complex`; `b':complex`; `c':complex`; `n:num`] THEN
+    REPEAT STRIP_TAC THEN
+    MP_TAC(SPECL [`f:complex->complex`; `a':complex`; `b':complex`;
+       `c':complex`; `e:real`; `K / &2 pow n`]
+       CAUCHY_THEOREM_QUADRISECTION) THEN
+    ASM_REWRITE_TAC[] THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ALL_TAC] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[real_pow; REAL_FIELD `x / (&2 * y) = x / y / &2`] THEN
+    MATCH_MP_TAC(SET_RULE
+     `s SUBSET t /\ t SUBSET u ==> s SUBSET u /\ s SUBSET t`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONVEX_HULL_SUBSET THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?x:complex. !n:num. x IN convex hull {A n,B n,C n}`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC BOUNDED_CLOSED_NEST THEN REPEAT CONJ_TAC THENL
+     [GEN_TAC THEN MATCH_MP_TAC COMPACT_IMP_CLOSED;
+      REWRITE_TAC[CONVEX_HULL_EQ_EMPTY; NOT_INSERT_EMPTY];
+      MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN ASM_REWRITE_TAC[] THEN
+      MESON_TAC[SUBSET_REFL; SUBSET_TRANS];
+      MATCH_MP_TAC COMPACT_IMP_BOUNDED] THEN
+    MATCH_MP_TAC FINITE_IMP_COMPACT_CONVEX_HULL THEN
+    REWRITE_TAC[FINITE_INSERT; FINITE_RULES];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`f:complex->complex`; `convex hull {a:complex,b,c}`;
+                 `x:complex`; `e / &10`] HOLOMORPHIC_POINT_SMALL_TRIANGLE) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON; complex_differentiable] THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+    ASM_MESON_TAC[holomorphic_on; SUBSET];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPEC `K:real / k` REAL_ARCH_POW2) THEN
+  ASM_SIMP_TAC[REAL_LT_LDIV_EQ] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  SIMP_TAC[GSYM REAL_LT_LDIV_EQ; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_TAC `n:num`) THEN FIRST_X_ASSUM(MP_TAC o SPECL
+   [`(A:num->complex) n`; `(B:num->complex) n`; `(C:num->complex) n`]) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[REAL_LE_TRANS; REAL_LT_IMP_LE]; ALL_TAC] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_THEN(K ALL_TAC) THEN
+  REWRITE_TAC[REAL_NOT_LE] THEN
+  MATCH_MP_TAC REAL_LTE_TRANS THEN
+  EXISTS_TAC `e * (K / &2 pow n) pow 2` THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_REWRITE_TAC[GSYM real_ge]] THEN
+  ASM_SIMP_TAC[real_div; GSYM REAL_MUL_ASSOC; REAL_LT_LMUL_EQ] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `&0 < x /\ y <= &9 * x ==> inv(&10) * y < x`) THEN
+  ASM_SIMP_TAC[REAL_POW_LT; REAL_LT_MUL; REAL_LT_INV_EQ;
+                REAL_OF_NUM_LT; ARITH] THEN
+  REWRITE_TAC[REAL_ARITH `&9 * x pow 2 = (&3 * x) pow 2`] THEN
+  MATCH_MP_TAC REAL_POW_LE2 THEN
+  SIMP_TAC[REAL_LE_ADD; DIST_POS_LE; GSYM real_div] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `x <= a /\ y <= a /\ z <= a ==> x + y + z <= &3 * a`) THEN
+  ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Version needing function holomorphic in interior only.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_THEOREM_FLAT_LEMMA = prove
+ (`!f a b c k.
+        f continuous_on convex hull {a,b,c} /\ c - a = k % (b - a) /\ &0 <= k
+        ==> path_integral (linepath(a,b)) f +
+            path_integral (linepath(b,c)) f +
+            path_integral (linepath(c,a)) f = Cx(&0)`,
+  REPEAT STRIP_TAC THEN
+  STRIP_ASSUME_TAC(ISPECL [`a:complex`; `b:complex`; `c:complex`]
+                SEGMENTS_SUBSET_CONVEX_HULL) THEN
+  ASM_CASES_TAC `k <= &1` THENL
+   [MP_TAC(SPECL [`f:complex->complex`; `a:complex`; `b:complex`; `c:complex`;
+                  `k:real`] PATH_INTEGRAL_SPLIT) THEN
+    ASM_REWRITE_TAC[] THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ALL_TAC] THEN
+    DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC(COMPLEX_RING
+     `x = --b /\ y = --a ==> (x + y) + (a + b) = Cx(&0)`) THEN
+    CONJ_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_REVERSE_LINEPATH THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+    MP_TAC(SPECL [`f:complex->complex`; `a:complex`; `c:complex`; `b:complex`;
+                  `inv k:real`] PATH_INTEGRAL_SPLIT) THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_LE_INV_EQ; REAL_MUL_LINV; REAL_INV_LE_1;
+      VECTOR_MUL_LID; REAL_ARITH `~(k <= &1) ==> ~(k = &0) /\ &1 <= k`] THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ALL_TAC] THEN
+    MATCH_MP_TAC(COMPLEX_RING
+     `ac = --ca ==> ac = ab + bc ==> ab + bc + ca = Cx(&0)`) THEN
+    MATCH_MP_TAC PATH_INTEGRAL_REVERSE_LINEPATH THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]]);;
+
+let CAUCHY_THEOREM_FLAT = prove
+ (`!f a b c k.
+        f continuous_on convex hull {a,b,c} /\ c - a = k % (b - a)
+        ==> path_integral (linepath(a,b)) f +
+            path_integral (linepath(b,c)) f +
+            path_integral (linepath(c,a)) f = Cx(&0)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `&0 <= k` THENL
+   [ASM_MESON_TAC[CAUCHY_THEOREM_FLAT_LEMMA]; ALL_TAC] THEN
+  STRIP_ASSUME_TAC(ISPECL [`a:complex`; `b:complex`; `c:complex`]
+                SEGMENTS_SUBSET_CONVEX_HULL) THEN
+  MP_TAC(ISPECL [`f:complex->complex`; `b:complex`; `a:complex`; `c:complex`;
+                 `&1 - k`] CAUCHY_THEOREM_FLAT_LEMMA) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[INSERT_AC; REAL_ARITH `~(&0 <= k) ==> &0 <= &1 - k`;
+         VECTOR_ARITH `b - a = k % (c - a) ==> (b - c) = (&1 - k) % (a - c)`];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(COMPLEX_RING
+     `ab = --ba /\ ac = --ca /\ bc = --cb
+      ==> ba + ac + cb = Cx(&0) ==> ab + bc + ca = Cx(&0)`) THEN
+  REPEAT CONJ_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_REVERSE_LINEPATH THEN
+  ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]);;
+
+let CAUCHY_THEOREM_TRIANGLE_INTERIOR = prove
+ (`!f a b c.
+        f continuous_on (convex hull {a,b,c}) /\
+        f holomorphic_on interior (convex hull {a,b,c})
+        ==> (f has_path_integral Cx(&0))
+            (linepath(a,b) ++ linepath(b,c) ++ linepath(c,a))`,
+  REPEAT STRIP_TAC THEN
+  STRIP_ASSUME_TAC(ISPECL [`a:complex`; `b:complex`; `c:complex`]
+                SEGMENTS_SUBSET_CONVEX_HULL) THEN
+  SUBGOAL_THEN
+    `?B. &0 < B /\
+         !y. y IN IMAGE (f:complex->complex) (convex hull {a,b,c})
+             ==> norm(y) <= B`
+  MP_TAC THENL
+   [REWRITE_TAC[GSYM BOUNDED_POS] THEN MATCH_MP_TAC COMPACT_IMP_BOUNDED THEN
+    MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+    ASM_SIMP_TAC[FINITE_IMP_COMPACT_CONVEX_HULL; FINITE_INSERT; FINITE_RULES];
+    REWRITE_TAC[FORALL_IN_IMAGE] THEN STRIP_TAC] THEN
+  SUBGOAL_THEN
+    `?C. &0 < C /\ !x:complex. x IN convex hull {a,b,c} ==> norm(x) <= C`
+  MP_TAC THENL
+   [REWRITE_TAC[GSYM BOUNDED_POS] THEN
+    MATCH_MP_TAC COMPACT_IMP_BOUNDED THEN
+    ASM_SIMP_TAC[FINITE_IMP_COMPACT_CONVEX_HULL; FINITE_INSERT; FINITE_RULES];
+    STRIP_TAC] THEN
+  SUBGOAL_THEN
+   `(f:complex->complex) uniformly_continuous_on (convex hull {a,b,c})`
+  MP_TAC THENL
+   [MATCH_MP_TAC COMPACT_UNIFORMLY_CONTINUOUS THEN
+    ASM_SIMP_TAC[FINITE_IMP_COMPACT_CONVEX_HULL; FINITE_RULES; FINITE_INSERT];
+    ALL_TAC] THEN
+  REWRITE_TAC[uniformly_continuous_on] THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `f path_integrable_on
+    (linepath (a,b) ++ linepath(b,c) ++ linepath(c,a))`
+  MP_TAC THENL
+   [SIMP_TAC[PATH_INTEGRABLE_JOIN; VALID_PATH_JOIN; VALID_PATH_LINEPATH;
+             PATHSTART_JOIN; PATHFINISH_JOIN; PATHSTART_LINEPATH;
+             PATHFINISH_LINEPATH] THEN
+    ASM_MESON_TAC[PATH_INTEGRABLE_CONTINUOUS_LINEPATH; CONTINUOUS_ON_SUBSET];
+    ALL_TAC] THEN
+  SIMP_TAC[path_integrable_on] THEN DISCH_THEN(X_CHOOSE_TAC `y:complex`) THEN
+  ASM_CASES_TAC `y = Cx(&0)` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  UNDISCH_TAC `~(y = Cx(&0))` THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  DISCH_THEN(K ALL_TAC) THEN REWRITE_TAC[] THEN
+  FIRST_ASSUM(ASSUME_TAC o SYM o MATCH_MP
+     HAS_CHAIN_INTEGRAL_CHAIN_INTEGRAL) THEN
+  ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `c:complex = a` THENL
+   [MATCH_MP_TAC CAUCHY_THEOREM_FLAT THEN
+    EXISTS_TAC `&0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_SUB_EQ];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `b:complex = c` THENL
+   [ONCE_REWRITE_TAC[COMPLEX_RING `a + b + c:complex = c + a + b`] THEN
+    MATCH_MP_TAC CAUCHY_THEOREM_FLAT THEN
+    EXISTS_TAC `&0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_SUB_EQ] THEN
+    ASM_MESON_TAC[INSERT_AC];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `a:complex = b` THENL
+   [ONCE_REWRITE_TAC[COMPLEX_RING `a + b + c:complex = b + c + a`] THEN
+    MATCH_MP_TAC CAUCHY_THEOREM_FLAT THEN
+    EXISTS_TAC `&0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_SUB_EQ] THEN
+    ASM_MESON_TAC[INSERT_AC];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `interior(convex hull {a:complex,b,c}) = {}` THENL
+   [MATCH_MP_TAC CAUCHY_THEOREM_FLAT THEN
+    SUBGOAL_THEN `{a:complex,b,c} HAS_SIZE (dimindex(:2) + 1)`
+    MP_TAC THENL
+     [ASM_SIMP_TAC[HAS_SIZE; CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN
+      ASM_REWRITE_TAC[DIMINDEX_2; ARITH; IN_INSERT; NOT_IN_EMPTY];
+      ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP INTERIOR_CONVEX_HULL_EQ_EMPTY) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+    SUBGOAL_THEN `collinear{a:complex,b,c}` MP_TAC THENL
+     [ASM_REWRITE_TAC[COLLINEAR_3_EQ_AFFINE_DEPENDENT]; ALL_TAC] THEN
+    ONCE_REWRITE_TAC[SET_RULE `{a,b,c} = {b,a,c}`] THEN
+    ONCE_REWRITE_TAC[COLLINEAR_3] THEN
+    ASM_REWRITE_TAC[COLLINEAR_LEMMA; VECTOR_SUB_EQ];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `d:complex`) THEN FIRST_X_ASSUM(MP_TAC o SYM) THEN
+  DISCH_TAC THEN
+  ASM_REWRITE_TAC[] THEN ASM_CASES_TAC `y = Cx(&0)` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `norm(y:complex) / &24 / C`) THEN
+  SUBGOAL_THEN `&0 < norm(y:complex) / &24 / C` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH; NORM_POS_LE; REAL_LTE_ADD;
+                 COMPLEX_NORM_NZ; COMPLEX_SUB_0];
+    ASM_REWRITE_TAC[dist]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN ABBREV_TAC
+   `e = min (&1)
+            (min (d1 / (&4 * C))
+                 ((norm(y:complex) / &24 / C) / B))` THEN
+  SUBGOAL_THEN `&0 < e` ASSUME_TAC THENL
+   [EXPAND_TAC "e" THEN
+    ASM_SIMP_TAC[REAL_HALF; REAL_LT_MIN; REAL_LT_DIV; COMPLEX_NORM_NZ;
+                 REAL_LT_MUL; REAL_OF_NUM_LT; ARITH];
+    ALL_TAC] THEN
+  ABBREV_TAC `shrink = \x:complex. x - e % (x - d)` THEN
+  SUBGOAL_THEN `shrink (a:complex) IN interior(convex hull {a,b,c}) /\
+                shrink b IN interior(convex hull {a,b,c}) /\
+                shrink c IN interior(convex hull {a,b,c})`
+  STRIP_ASSUME_TAC THENL
+   [REPEAT CONJ_TAC THEN EXPAND_TAC "shrink" THEN
+    MATCH_MP_TAC IN_INTERIOR_CONVEX_SHRINK THEN
+    ASM_REWRITE_TAC[CONVEX_CONVEX_HULL] THEN
+    (CONJ_TAC THENL [ALL_TAC; EXPAND_TAC "e" THEN REAL_ARITH_TAC]) THEN
+    MATCH_MP_TAC(REWRITE_RULE[SUBSET] HULL_SUBSET) THEN
+    REWRITE_TAC[IN_INSERT];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `norm((path_integral(linepath(shrink a,shrink b)) f -
+          path_integral(linepath(a,b)) f) +
+         (path_integral(linepath(shrink b,shrink c)) f -
+          path_integral(linepath(b,c)) f) +
+         (path_integral(linepath(shrink c,shrink a)) f -
+          path_integral(linepath(c,a)) f)) <= norm(y:complex) / &2`
+  MP_TAC THENL
+   [ALL_TAC;
+    ASM_REWRITE_TAC[COMPLEX_RING
+     `(ab' - ab) + (bc' - bc) + (ca' - ca) =
+      (ab' + bc' + ca') - (ab + bc + ca)`] THEN
+    SUBGOAL_THEN
+     `(f has_path_integral (Cx(&0)))
+      (linepath (shrink a,shrink b) ++
+       linepath (shrink b,shrink c) ++
+       linepath (shrink c,shrink (a:complex)))`
+    MP_TAC THENL
+     [MATCH_MP_TAC CAUCHY_THEOREM_TRIANGLE THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+      EXISTS_TAC `interior(convex hull {a:complex,b,c})` THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+      SIMP_TAC[CONVEX_INTERIOR; CONVEX_CONVEX_HULL] THEN
+      ASM SET_TAC[];
+      ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_CHAIN_INTEGRAL_CHAIN_INTEGRAL) THEN
+    SIMP_TAC[] THEN DISCH_THEN(K ALL_TAC) THEN
+    REWRITE_TAC[COMPLEX_SUB_LZERO; NORM_NEG] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= y /\ ~(y = &0) ==> ~(y <= y / &2)`) THEN
+    ASM_REWRITE_TAC[COMPLEX_NORM_ZERO; NORM_POS_LE]] THEN
+  SUBGOAL_THEN
+   `!x y. x IN convex hull {a,b,c} /\ y IN convex hull {a,b,c}
+          ==> norm(x - y) <= &2 * C`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_MUL_2; VECTOR_SUB] THEN
+    MATCH_MP_TAC NORM_TRIANGLE_LE THEN REWRITE_TAC[NORM_NEG] THEN
+    MATCH_MP_TAC REAL_LE_ADD2 THEN ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[REAL_ARITH `x / &2 = x / &6 + x / &6 + x / &6`] THEN
+  REPEAT(MATCH_MP_TAC NORM_TRIANGLE_LE THEN
+         MATCH_MP_TAC REAL_LE_ADD2 THEN CONJ_TAC) THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM CONTENT_UNIT_1] THEN
+  MATCH_MP_TAC HAS_INTEGRAL_BOUND THENL
+   [EXISTS_TAC `\x. f(linepath(shrink a,shrink b) x) *
+                    (shrink b - shrink a) -
+                    f(linepath(a,b) x) * (b - a)`;
+    EXISTS_TAC `\x. f(linepath(shrink b,shrink c) x) *
+                    (shrink c - shrink b) -
+                    f(linepath(b,c) x) * (c - b)`;
+    EXISTS_TAC `\x. f(linepath(shrink c,shrink a) x) *
+                    (shrink a - shrink c) -
+                    f(linepath(c,a) x) * (a - c)`] THEN
+  ASM_SIMP_TAC[COMPLEX_NORM_NZ; REAL_ARITH `&0 < x ==> &0 <= x / &6`] THEN
+  (CONJ_TAC THENL
+    [MATCH_MP_TAC HAS_INTEGRAL_SUB THEN
+     REWRITE_TAC[GSYM HAS_PATH_INTEGRAL_LINEPATH] THEN
+     CONJ_TAC THEN MATCH_MP_TAC HAS_PATH_INTEGRAL_INTEGRAL THEN
+     MATCH_MP_TAC PATH_INTEGRABLE_CONTINUOUS_LINEPATH THEN
+     MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+     EXISTS_TAC `convex hull {a:complex,b,c}` THEN
+     ASM_REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+     MATCH_MP_TAC HULL_MINIMAL THEN
+     REWRITE_TAC[CONVEX_CONVEX_HULL; SUBSET; IN_INSERT; NOT_IN_EMPTY] THEN
+     ASM_MESON_TAC[SUBSET; INTERIOR_SUBSET];
+     ALL_TAC] THEN
+   REPEAT STRIP_TAC THEN
+   ONCE_REWRITE_TAC[COMPLEX_RING
+    `f' * x' - f * x = f' * (x' - x) + x * (f' - f):complex`] THEN
+   MATCH_MP_TAC NORM_TRIANGLE_LE THEN REWRITE_TAC[COMPLEX_NORM_MUL] THEN
+   MATCH_MP_TAC REAL_LE_TRANS THEN
+   EXISTS_TAC `B * (norm(y:complex) / &24 / C / B) * &2 * C +
+               (&2 * C) * (norm y / &24 / C)` THEN
+   CONJ_TAC THENL
+    [ALL_TAC;
+     MATCH_MP_TAC REAL_EQ_IMP_LE THEN
+     MAP_EVERY UNDISCH_TAC [`&0 < B`; `&0 < C`] THEN CONV_TAC REAL_FIELD] THEN
+   MATCH_MP_TAC REAL_LE_ADD2 THEN CONJ_TAC THEN
+   MATCH_MP_TAC REAL_LE_MUL2 THEN REWRITE_TAC[NORM_POS_LE] THENL
+    [CONJ_TAC THENL
+      [FIRST_X_ASSUM MATCH_MP_TAC THEN
+       W(fun (asl,w) ->
+         MP_TAC(PART_MATCH (lhand o rand) LINEPATH_IN_PATH (lhand w))) THEN
+       ASM_REWRITE_TAC[] THEN
+       W(fun (asl,w) -> SPEC_TAC(lhand(rand w),`x:complex`)) THEN
+       REWRITE_TAC[GSYM SUBSET; SEGMENT_CONVEX_HULL] THEN
+       MATCH_MP_TAC HULL_MINIMAL THEN
+       REWRITE_TAC[CONVEX_CONVEX_HULL; SUBSET; IN_INSERT; NOT_IN_EMPTY] THEN
+       ASM_MESON_TAC[SUBSET; INTERIOR_SUBSET];
+       ALL_TAC] THEN
+     EXPAND_TAC "shrink" THEN
+     REWRITE_TAC[VECTOR_ARITH `(b - e % (b - d)) - (a - e % (a - d)) -
+                           (b - a) = e % (a - b)`] THEN
+     REWRITE_TAC[NORM_MUL] THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+     ASM_SIMP_TAC[NORM_POS_LE; REAL_ARITH `&0 < x ==> abs x = x`;
+                  REAL_ABS_POS] THEN
+     CONJ_TAC THENL [EXPAND_TAC "e" THEN REAL_ARITH_TAC; ALL_TAC] THEN
+     FIRST_X_ASSUM MATCH_MP_TAC THEN CONJ_TAC THEN
+     MATCH_MP_TAC(REWRITE_RULE[SUBSET] HULL_SUBSET) THEN
+     REWRITE_TAC[IN_INSERT];
+     ALL_TAC] THEN
+   CONJ_TAC THENL
+    [FIRST_X_ASSUM MATCH_MP_TAC THEN CONJ_TAC THEN
+     MATCH_MP_TAC(REWRITE_RULE[SUBSET] HULL_SUBSET) THEN
+     REWRITE_TAC[IN_INSERT];
+     ALL_TAC] THEN
+   MATCH_MP_TAC REAL_LT_IMP_LE THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+   CONJ_TAC THENL
+    [W(fun (asl,w) ->
+       MP_TAC(PART_MATCH (lhand o rand) LINEPATH_IN_PATH (lhand w))) THEN
+     ASM_MESON_TAC[SUBSET];
+     ALL_TAC] THEN
+   CONJ_TAC THENL
+    [W(fun (asl,w) ->
+       MP_TAC(PART_MATCH (lhand o rand) LINEPATH_IN_PATH (lhand w))) THEN
+     ASM_REWRITE_TAC[] THEN
+     W(fun (asl,w) -> SPEC_TAC(lhand(rand w),`x:complex`)) THEN
+     REWRITE_TAC[GSYM SUBSET; SEGMENT_CONVEX_HULL] THEN
+     MATCH_MP_TAC HULL_MINIMAL THEN
+     REWRITE_TAC[CONVEX_CONVEX_HULL; SUBSET; IN_INSERT; NOT_IN_EMPTY] THEN
+     ASM_MESON_TAC[SUBSET; INTERIOR_SUBSET];
+     ALL_TAC] THEN
+   REWRITE_TAC[linepath] THEN REWRITE_TAC[VECTOR_ARITH
+     `((&1 - x) % a' + x % b') - ((&1 - x) % a + x % b) =
+      (&1 - x) % (a' - a) + x % (b' - b)`] THEN
+   EXPAND_TAC "shrink" THEN REWRITE_TAC[VECTOR_ARITH `a - b - a = --b`] THEN
+   MATCH_MP_TAC NORM_TRIANGLE_LT THEN REWRITE_TAC[NORM_MUL; NORM_NEG] THEN
+   MATCH_MP_TAC REAL_CONVEX_BOUND_LT THEN ONCE_REWRITE_TAC[TAUT
+    `a /\ b /\ c /\ d /\ e <=> (c /\ d /\ e) /\ a /\ b`] THEN
+   CONJ_TAC THENL
+    [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+     REWRITE_TAC[DROP_VEC] THEN REAL_ARITH_TAC;
+     ALL_TAC] THEN
+   CONJ_TAC THEN
+   MATCH_MP_TAC REAL_LET_TRANS THEN
+   EXISTS_TAC `e * &2 * C` THEN
+   ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_ARITH `&0 < x ==> abs x = x`] THEN
+   (CONJ_TAC THENL
+     [FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_MESON_TAC[SUBSET; INTERIOR_SUBSET; HULL_SUBSET; IN_INSERT];
+      ALL_TAC]) THEN
+   ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_LT_MUL; REAL_OF_NUM_LT; ARITH] THEN
+   EXPAND_TAC "e" THEN REWRITE_TAC[REAL_MIN_LT] THEN
+   DISJ2_TAC THEN DISJ1_TAC THEN
+   REWRITE_TAC[REAL_FIELD `d / (a * b) = inv(a:real) * d / b`] THEN
+   REWRITE_TAC[REAL_ARITH `inv(&4) * x < inv(&2) * x <=> &0 < x`] THEN
+   ASM_SIMP_TAC[REAL_LT_DIV]));;
+
+(* ------------------------------------------------------------------------- *)
+(* Version allowing finite number of exceptional points.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_THEOREM_TRIANGLE_COFINITE = prove
+ (`!f s a b c.
+        f continuous_on (convex hull {a,b,c}) /\
+        FINITE s /\
+        (!x. x IN interior(convex hull {a,b,c}) DIFF s
+             ==> f complex_differentiable (at x))
+        ==> (f has_path_integral Cx(&0))
+            (linepath (a,b) ++ linepath(b,c) ++ linepath(c,a))`,
+  GEN_TAC THEN GEN_TAC THEN WF_INDUCT_TAC `CARD(s:complex->bool)` THEN
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:complex->bool = {}` THENL
+   [MATCH_MP_TAC CAUCHY_THEOREM_TRIANGLE_INTERIOR THEN
+    ASM_REWRITE_TAC[holomorphic_on] THEN X_GEN_TAC `z:complex` THEN
+    DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN
+    ASM_REWRITE_TAC[complex_differentiable; IN_DIFF; NOT_IN_EMPTY] THEN
+    MESON_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `d:complex`) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `s DELETE (d:complex)`) THEN
+  ASM_SIMP_TAC[CARD_DELETE; CARD_EQ_0;
+                 ARITH_RULE `n - 1 < n <=> ~(n = 0)`] THEN
+  ASM_CASES_TAC `(d:complex) IN convex hull {a,b,c}` THENL
+   [ALL_TAC;
+    DISCH_THEN MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[FINITE_DELETE; IN_DIFF; IN_DELETE] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[IN_DIFF] THEN ASM_MESON_TAC[INTERIOR_SUBSET; SUBSET]] THEN
+  DISCH_TAC THEN SUBGOAL_THEN
+   `(f has_path_integral Cx(&0))
+    (linepath(a,b) ++ linepath(b,d) ++ linepath(d,a)) /\
+    (f has_path_integral Cx(&0))
+    (linepath(b,c) ++ linepath(c,d) ++ linepath(d,b)) /\
+    (f has_path_integral Cx(&0))
+    (linepath(c,a) ++ linepath(a,d) ++ linepath(d,c))`
+  MP_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[IMP_IMP; RIGHT_IMP_FORALL_THM]) THEN
+    REPEAT CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[FINITE_DELETE] THEN
+    (CONJ_TAC THENL
+      [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+       EXISTS_TAC `convex hull {a:complex,b,c}` THEN ASM_REWRITE_TAC[] THEN
+       MATCH_MP_TAC CONVEX_HULL_SUBSET THEN
+       REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+       REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+       MATCH_MP_TAC(REWRITE_RULE[SUBSET] HULL_SUBSET) THEN
+       REWRITE_TAC[IN_INSERT];
+       ALL_TAC]) THEN
+    ASM_REWRITE_TAC[FINITE_DELETE; IN_DIFF; IN_DELETE] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [DE_MORGAN_THM]) THEN
+    (ASM_CASES_TAC `x:complex = d` THEN ASM_REWRITE_TAC[] THENL
+      [ASM_MESON_TAC[NOT_IN_INTERIOR_CONVEX_HULL_3]; ALL_TAC]) THEN
+    DISCH_TAC THEN ASM_REWRITE_TAC[IN_DIFF] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `x IN interior s
+      ==> interior s SUBSET interior t ==> x IN interior t`)) THEN
+    MATCH_MP_TAC SUBSET_INTERIOR THEN
+    MATCH_MP_TAC CONVEX_HULL_SUBSET THEN
+    SIMP_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[SUBSET] HULL_SUBSET) THEN REWRITE_TAC[IN_INSERT];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `f path_integrable_on
+    (linepath (a,b) ++ linepath(b,c) ++ linepath(c,a))`
+  MP_TAC THENL
+   [SIMP_TAC[PATH_INTEGRABLE_JOIN; VALID_PATH_JOIN; VALID_PATH_LINEPATH;
+             PATHSTART_JOIN; PATHFINISH_JOIN; PATHSTART_LINEPATH;
+             PATHFINISH_LINEPATH] THEN
+    STRIP_ASSUME_TAC(ISPECL [`a:complex`; `b:complex`; `c:complex`]
+                  SEGMENTS_SUBSET_CONVEX_HULL) THEN
+    ASM_MESON_TAC[PATH_INTEGRABLE_CONTINUOUS_LINEPATH; CONTINUOUS_ON_SUBSET];
+    ALL_TAC] THEN
+  REWRITE_TAC[path_integrable_on; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `y:complex` THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN
+   (MP_TAC o MATCH_MP HAS_CHAIN_INTEGRAL_CHAIN_INTEGRAL)) THEN
+  ASM_CASES_TAC `y = Cx(&0)` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_MESON_TAC[]; UNDISCH_TAC `~(y = Cx(&0))`] THEN
+  REWRITE_TAC[] THEN
+  SUBGOAL_THEN `(f:complex->complex) continuous_on segment[a,d] /\
+                f continuous_on segment[b,d] /\
+                f continuous_on segment[c,d]`
+  MP_TAC THENL
+   [ALL_TAC;
+    DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN (MP_TAC o MATCH_MP
+               PATH_INTEGRAL_REVERSE_LINEPATH)) THEN
+    CONV_TAC COMPLEX_RING] THEN
+  REPEAT CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+  EXISTS_TAC `convex hull {a:complex,b,c}` THEN
+  ASM_REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+  MATCH_MP_TAC CONVEX_HULL_SUBSET THEN
+  SIMP_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[SUBSET] HULL_SUBSET) THEN REWRITE_TAC[IN_INSERT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Existence of a primitive.                                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let STARLIKE_CONVEX_SUBSET = prove
+ (`!s a b c:real^N.
+        a IN s /\ segment[b,c] SUBSET s /\
+        (!x. x IN s ==> segment[a,x] SUBSET s)
+        ==> convex hull {a,b,c} SUBSET s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`{b:real^N,c}`; `a:real^N`] CONVEX_HULL_INSERT) THEN
+  REWRITE_TAC[NOT_INSERT_EMPTY] THEN DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `u:real`; `v:real`; `d:real^N`] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `d:real^N`) THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[SUBSET; SEGMENT_CONVEX_HULL];
+    ASM_REWRITE_TAC[SUBSET] THEN DISCH_THEN MATCH_MP_TAC THEN
+    REWRITE_TAC[SEGMENT_CONVEX_HULL; CONVEX_HULL_2; IN_ELIM_THM] THEN
+    ASM_MESON_TAC[]]);;
+
+let TRIANGLE_PATH_INTEGRALS_STARLIKE_PRIMITIVE = prove
+ (`!f s a.
+      a IN s /\ open s /\ f continuous_on s /\
+      (!z. z IN s ==> segment[a,z] SUBSET s) /\
+      (!b c. segment[b,c] SUBSET s
+             ==> path_integral (linepath(a,b)) f +
+                 path_integral (linepath(b,c)) f +
+                 path_integral (linepath(c,a)) f = Cx(&0))
+      ==> ?g. !z. z IN s ==> (g has_complex_derivative f(z)) (at z)`,
+  REPEAT STRIP_TAC THEN
+  EXISTS_TAC `\x. path_integral (linepath(a,x)) f` THEN
+  X_GEN_TAC `x:complex` THEN STRIP_TAC THEN
+  REWRITE_TAC[has_complex_derivative] THEN
+  REWRITE_TAC[has_derivative_at; LINEAR_COMPLEX_MUL] THEN
+  MATCH_MP_TAC LIM_TRANSFORM THEN
+  EXISTS_TAC `\y. inv(norm(y - x)) % (path_integral(linepath(x,y)) f -
+                   f x * (y - x))` THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `i % (x - a) - i % (y - (z + a)) = i % (x + z - y)`] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC LIM_EVENTUALLY THEN REWRITE_TAC[EVENTUALLY_AT] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `x:complex`) 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 `y:complex` THEN REWRITE_TAC[dist] THEN STRIP_TAC THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISJ2_TAC THEN
+    MP_TAC(SPECL [`f:complex->complex`; `a:complex`; `y:complex`]
+         PATH_INTEGRAL_REVERSE_LINEPATH) THEN
+    ANTS_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+      EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+      ASM_REWRITE_TAC[IN_BALL; ONCE_REWRITE_RULE[NORM_SUB] dist];
+      REWRITE_TAC[COMPLEX_VEC_0] THEN MATCH_MP_TAC(COMPLEX_RING
+        `ax + xy + ya = Cx(&0) ==> ay = --ya ==> xy + ax - ay = Cx(&0)`) THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o
+       MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] SUBSET_TRANS)) THEN
+      REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+      MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_BALL] THEN
+      REWRITE_TAC[SUBSET; IN_BALL; IN_INSERT; NOT_IN_EMPTY] THEN
+      REPEAT STRIP_TAC THEN
+      ASM_REWRITE_TAC[dist; NORM_0; VECTOR_SUB_REFL] THEN
+      ASM_MESON_TAC[NORM_SUB]];
+    REWRITE_TAC[LIM_AT] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `(f:complex->complex) continuous at x` MP_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_INTERIOR THEN ASM_MESON_TAC[INTERIOR_OPEN];
+      ALL_TAC] THEN
+    REWRITE_TAC[continuous_at; dist; VECTOR_SUB_RZERO] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `x:complex`) THEN
+    ASM_REWRITE_TAC[SUBSET; IN_BALL; 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
+    X_GEN_TAC `y:complex` THEN STRIP_TAC THEN
+    SUBGOAL_THEN `f path_integrable_on linepath(x,y)` MP_TAC THENL
+     [MATCH_MP_TAC PATH_INTEGRABLE_CONTINUOUS_LINEPATH THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:complex->bool` THEN
+      ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `ball(x:complex,d2)` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+        MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_BALL] THEN
+        REWRITE_TAC[SUBSET; IN_BALL; IN_INSERT; NOT_IN_EMPTY] THEN
+        REPEAT STRIP_TAC THEN
+        ASM_REWRITE_TAC[dist; NORM_0; VECTOR_SUB_REFL] THEN
+        ASM_MESON_TAC[NORM_SUB];
+        ASM_REWRITE_TAC[SUBSET; IN_BALL; dist]];
+      ALL_TAC] THEN
+    REWRITE_TAC[path_integrable_on; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `z:complex` THEN
+    MP_TAC(SPECL [`x:complex`; `y:complex`; `(f:complex->complex) x`]
+                  HAS_PATH_INTEGRAL_CONST_LINEPATH) THEN
+    REWRITE_TAC[IMP_IMP] THEN
+    DISCH_THEN(fun th -> ASSUME_TAC(CONJUNCT2 th) THEN MP_TAC th) THEN
+    FIRST_ASSUM(SUBST1_TAC o MATCH_MP PATH_INTEGRAL_UNIQUE) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_SUB) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_NEG) THEN
+    REWRITE_TAC[COMPLEX_NEG_SUB] THEN STRIP_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= e / &2 /\ &0 < e ==> x < e`) THEN
+    ASM_REWRITE_TAC[NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM real_div] THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ] THEN
+    MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_LINEPATH THEN
+    EXISTS_TAC `\w. (f:complex->complex) w - f x` THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < e ==> &0 <= e / &2`] THEN
+    X_GEN_TAC `w:complex` THEN STRIP_TAC THEN MATCH_MP_TAC REAL_LT_IMP_LE THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_MESON_TAC[REAL_LET_TRANS; SEGMENT_BOUND]]);;
+
+let HOLOMORPHIC_STARLIKE_PRIMITIVE = prove
+ (`!f s k. open s /\ starlike s /\ FINITE k /\ f continuous_on s /\
+           (!x. x IN s DIFF k ==> f complex_differentiable at x)
+           ==> ?g. !x. x IN s ==> (g has_complex_derivative f(x)) (at x)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `a:complex` STRIP_ASSUME_TAC o
+        GEN_REWRITE_RULE I [starlike]) THEN
+  MATCH_MP_TAC TRIANGLE_PATH_INTEGRALS_STARLIKE_PRIMITIVE THEN
+  EXISTS_TAC `a:complex` THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`x:complex`; `y:complex`] THEN STRIP_TAC THEN
+  MATCH_MP_TAC HAS_CHAIN_INTEGRAL_CHAIN_INTEGRAL THEN
+  MATCH_MP_TAC CAUCHY_THEOREM_TRIANGLE_COFINITE THEN
+  EXISTS_TAC `k:complex->bool` THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `convex hull {a:complex,x,y} SUBSET s` ASSUME_TAC THENL
+   [MATCH_MP_TAC STARLIKE_CONVEX_SUBSET THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ALL_TAC] THEN
+  REWRITE_TAC[IN_DIFF] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[IN_DIFF] THEN
+  ASM_MESON_TAC[SUBSET; INTERIOR_SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Cauchy's theorem for an open starlike set.                                *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_THEOREM_STARLIKE = prove
+ (`!f s k g. open s /\ starlike s /\ FINITE k /\ f continuous_on s /\
+             (!x. x IN s DIFF k ==> f complex_differentiable at x) /\
+             valid_path g /\ (path_image g) SUBSET s /\
+             pathfinish g = pathstart g
+             ==> (f has_path_integral Cx(&0)) (g)`,
+  MESON_TAC[HOLOMORPHIC_STARLIKE_PRIMITIVE; CAUCHY_THEOREM_PRIMITIVE;
+            HAS_COMPLEX_DERIVATIVE_AT_WITHIN]);;
+
+let CAUCHY_THEOREM_STARLIKE_SIMPLE = prove
+ (`!f s g. open s /\ starlike s /\ f holomorphic_on s /\
+           valid_path g /\ (path_image g) SUBSET s /\
+           pathfinish g = pathstart g
+           ==> (f has_path_integral Cx(&0)) (g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CAUCHY_THEOREM_STARLIKE THEN
+  MAP_EVERY EXISTS_TAC [`s:complex->bool`; `{}:complex->bool`] THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON; FINITE_RULES] THEN
+  REWRITE_TAC[IN_DIFF; NOT_IN_EMPTY; complex_differentiable] THEN
+  ASM_MESON_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN; holomorphic_on]);;
+
+(* ------------------------------------------------------------------------- *)
+(* For a convex set we can avoid assuming openness and boundary analyticity. *)
+(* ------------------------------------------------------------------------- *)
+
+let TRIANGLE_PATH_INTEGRALS_CONVEX_PRIMITIVE = prove
+ (`!f s a.
+      a IN s /\ convex s /\ f continuous_on s /\
+      (!b c. b IN s /\ c IN s
+             ==> path_integral (linepath(a,b)) f +
+                 path_integral (linepath(b,c)) f +
+                 path_integral (linepath(c,a)) f = Cx(&0))
+      ==> ?g. !z. z IN s ==> (g has_complex_derivative f(z)) (at z within s)`,
+  REPEAT STRIP_TAC THEN
+  EXISTS_TAC `\x. path_integral (linepath(a,x)) f` THEN
+  X_GEN_TAC `x:complex` THEN STRIP_TAC THEN
+  REWRITE_TAC[has_complex_derivative] THEN
+  REWRITE_TAC[has_derivative_within; LINEAR_COMPLEX_MUL] THEN
+  MATCH_MP_TAC LIM_TRANSFORM THEN
+  EXISTS_TAC `\y. inv(norm(y - x)) % (path_integral(linepath(x,y)) f -
+                   f x * (y - x))` THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `i % (x - a) - i % (y - (z + a)) = i % (x + z - y)`] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC LIM_EVENTUALLY THEN REWRITE_TAC[EVENTUALLY_WITHIN] THEN
+    EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN
+    X_GEN_TAC `y:complex` THEN STRIP_TAC THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISJ2_TAC THEN
+    MP_TAC(SPECL [`f:complex->complex`; `a:complex`; `y:complex`]
+         PATH_INTEGRAL_REVERSE_LINEPATH) THEN
+    ANTS_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+      EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+      MATCH_MP_TAC HULL_MINIMAL THEN ASM SET_TAC[];
+      REWRITE_TAC[COMPLEX_VEC_0] THEN MATCH_MP_TAC(COMPLEX_RING
+        `ax + xy + ya = Cx(&0) ==> ay = --ya ==> xy + ax - ay = Cx(&0)`) THEN
+      ASM_SIMP_TAC[]];
+    REWRITE_TAC[LIM_WITHIN] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `(f:complex->complex) continuous (at x within s)` MP_TAC THENL
+     [ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN]; ALL_TAC] THEN
+    REWRITE_TAC[continuous_within; dist; VECTOR_SUB_RZERO] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `d1:real` THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `y:complex` THEN STRIP_TAC THEN
+    SUBGOAL_THEN `f path_integrable_on linepath(x,y)` MP_TAC THENL
+     [MATCH_MP_TAC PATH_INTEGRABLE_CONTINUOUS_LINEPATH THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:complex->bool` THEN
+      ASM_REWRITE_TAC[] THEN REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+      MATCH_MP_TAC HULL_MINIMAL THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    REWRITE_TAC[path_integrable_on; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `z:complex` THEN
+    MP_TAC(SPECL [`x:complex`; `y:complex`; `(f:complex->complex) x`]
+                  HAS_PATH_INTEGRAL_CONST_LINEPATH) THEN
+    REWRITE_TAC[IMP_IMP] THEN
+    DISCH_THEN(fun th -> ASSUME_TAC(CONJUNCT2 th) THEN MP_TAC th) THEN
+    FIRST_ASSUM(SUBST1_TAC o MATCH_MP PATH_INTEGRAL_UNIQUE) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_SUB) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_NEG) THEN
+    REWRITE_TAC[COMPLEX_NEG_SUB] THEN STRIP_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= e / &2 /\ &0 < e ==> x < e`) THEN
+    ASM_REWRITE_TAC[NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM real_div] THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ] THEN
+    MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_LINEPATH THEN
+    EXISTS_TAC `\w. (f:complex->complex) w - f x` THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < e ==> &0 <= e / &2`] THEN
+    X_GEN_TAC `w:complex` THEN STRIP_TAC THEN MATCH_MP_TAC REAL_LT_IMP_LE THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `w IN t ==> t SUBSET s ==> w IN s`)) THEN
+      REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+      MATCH_MP_TAC HULL_MINIMAL THEN ASM SET_TAC[];
+      ASM_MESON_TAC[REAL_LET_TRANS; SEGMENT_BOUND]]]);;
+
+let PATHINTEGRAL_CONVEX_PRIMITIVE = prove
+ (`!f s. convex s /\ f continuous_on s /\
+         (!a b c. a IN s /\ b IN s /\ c IN s
+                  ==>  (f has_path_integral Cx(&0))
+                       (linepath (a,b) ++ linepath(b,c) ++ linepath(c,a)))
+         ==> ?g. !x. x IN s
+                     ==> (g has_complex_derivative f(x)) (at x within s)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:complex->bool = {}` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `a:complex` STRIP_ASSUME_TAC o
+        GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  MATCH_MP_TAC TRIANGLE_PATH_INTEGRALS_CONVEX_PRIMITIVE THEN
+  EXISTS_TAC `a:complex` THEN ASM_REWRITE_TAC[] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_CHAIN_INTEGRAL_CHAIN_INTEGRAL THEN
+  ASM_SIMP_TAC[]);;
+
+let HOLOMORPHIC_CONVEX_PRIMITIVE = prove
+ (`!f s k. convex s /\ FINITE k /\ f continuous_on s /\
+           (!x. x IN interior(s) DIFF k ==> f complex_differentiable at x)
+           ==> ?g. !x. x IN s
+                       ==> (g has_complex_derivative f(x)) (at x within s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATHINTEGRAL_CONVEX_PRIMITIVE THEN
+  ASM_REWRITE_TAC[] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CAUCHY_THEOREM_TRIANGLE_COFINITE THEN
+  EXISTS_TAC `k:complex->bool` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:complex->bool` THEN
+    ASM_REWRITE_TAC[];
+    X_GEN_TAC `w:complex` THEN
+    DISCH_THEN(fun th -> FIRST_X_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+    SPEC_TAC(`w:complex`,`w:complex`) THEN ASM_REWRITE_TAC[GSYM SUBSET] THEN
+    MATCH_MP_TAC(SET_RULE `s SUBSET t ==> (s DIFF k) SUBSET (t DIFF k)`) THEN
+    MATCH_MP_TAC SUBSET_INTERIOR] THEN
+  MATCH_MP_TAC HULL_MINIMAL THEN ASM_REWRITE_TAC[] THEN ASM SET_TAC[]);;
+
+let CAUCHY_THEOREM_CONVEX = prove
+ (`!f s k g. convex s /\ FINITE k /\ f continuous_on s /\
+             (!x. x IN interior(s) DIFF k ==> f complex_differentiable at x) /\
+             valid_path g /\ (path_image g) SUBSET s /\
+             pathfinish g = pathstart g
+             ==> (f has_path_integral Cx(&0)) (g)`,
+  MESON_TAC[HOLOMORPHIC_CONVEX_PRIMITIVE; CAUCHY_THEOREM_PRIMITIVE]);;
+
+let CAUCHY_THEOREM_CONVEX_SIMPLE = prove
+ (`!f s g. convex s /\ f holomorphic_on s /\
+           valid_path g /\ (path_image g) SUBSET s /\
+           pathfinish g = pathstart g
+           ==> (f has_path_integral Cx(&0)) (g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CAUCHY_THEOREM_CONVEX THEN
+  MAP_EVERY EXISTS_TAC [`s:complex->bool`; `{}:complex->bool`] THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON; FINITE_RULES] THEN
+  REWRITE_TAC[IN_DIFF; NOT_IN_EMPTY; complex_differentiable] THEN
+  SUBGOAL_THEN `f holomorphic_on (interior s)` MP_TAC THENL
+   [ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET; INTERIOR_SUBSET]; ALL_TAC] THEN
+  MESON_TAC[holomorphic_on; HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN;
+            OPEN_INTERIOR]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In particular for a disc.                                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_THEOREM_DISC = prove
+ (`!f g k a e.
+        FINITE k /\ f continuous_on cball(a,e) /\
+        (!x. x IN ball(a,e) DIFF k ==> f complex_differentiable at x) /\
+        valid_path g /\ (path_image g) SUBSET cball(a,e) /\
+        pathfinish g = pathstart g
+        ==> (f has_path_integral Cx(&0)) (g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CAUCHY_THEOREM_CONVEX THEN
+  MAP_EVERY EXISTS_TAC [`cball(a:complex,e)`; `k:complex->bool`] THEN
+  ASM_REWRITE_TAC[INTERIOR_CBALL; CONVEX_CBALL]);;
+
+let CAUCHY_THEOREM_DISC_SIMPLE = prove
+ (`!f g a e.
+        f holomorphic_on ball(a,e) /\
+        valid_path g /\ (path_image g) SUBSET ball(a,e) /\
+        pathfinish g = pathstart g
+        ==> (f has_path_integral Cx(&0)) (g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CAUCHY_THEOREM_CONVEX_SIMPLE THEN
+  EXISTS_TAC `ball(a:complex,e)` THEN ASM_REWRITE_TAC[CONVEX_BALL; OPEN_BALL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Generalize integrability to local primitives.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_INTEGRAL_LOCAL_PRIMITIVE_LEMMA = prove
+ (`!f f' g s a b.
+        (!x. x IN s ==> (f has_complex_derivative f' x) (at x within s)) /\
+        g piecewise_differentiable_on interval[a,b] /\
+        (!x. x IN interval[a,b] ==> g(x) IN s)
+        ==> (\x. f' (g x) * vector_derivative g (at x within interval[a,b]))
+            integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `interval[a:real^1,b] = {}` THENL
+   [ASM_REWRITE_TAC[INTEGRABLE_ON_EMPTY];
+    REWRITE_TAC[integrable_on] THEN
+    EXISTS_TAC `(f:complex->complex) (g(b:real^1)) - f(g a)` THEN
+    MATCH_MP_TAC PATH_INTEGRAL_PRIMITIVE_LEMMA THEN
+    ASM_MESON_TAC[]]);;
+
+let PATH_INTEGRAL_LOCAL_PRIMITIVE_ANY = prove
+ (`!f g s a b.
+    (!x. x IN s
+         ==> ?d h. &0 < d /\
+                   !y. norm(y - x) < d
+                       ==> (h has_complex_derivative f(y)) (at y within s)) /\
+    g piecewise_differentiable_on interval[a,b] /\
+    (!x. x IN interval[a,b] ==> g(x) IN s)
+    ==> (\x. f(g x) * vector_derivative g (at x)) integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_LITTLE_SUBINTERVALS THEN
+  X_GEN_TAC `x:real^1` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(g:real^1->complex) x`) THEN
+  ASM_SIMP_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`d:real`; `h:complex->complex`] THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP
+    PIECEWISE_DIFFERENTIABLE_ON_IMP_CONTINUOUS_ON) THEN
+  REWRITE_TAC[continuous_on] THEN DISCH_THEN(MP_TAC o SPEC `x:real^1`) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `d:real`) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+  SIMP_TAC[integrable_on; GSYM HAS_INTEGRAL_LOCALIZED_VECTOR_DERIVATIVE] THEN
+  REWRITE_TAC[GSYM integrable_on] THEN
+  MATCH_MP_TAC PATH_INTEGRAL_LOCAL_PRIMITIVE_LEMMA THEN
+  MAP_EVERY EXISTS_TAC
+   [`h:complex->complex`; `IMAGE (g:real^1->complex) (interval[u,v])`] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_WITHIN_SUBSET THEN
+    EXISTS_TAC `s:complex->bool` THEN
+    CONJ_TAC THENL [FIRST_X_ASSUM MATCH_MP_TAC; ASM SET_TAC[]] THEN
+    REWRITE_TAC[GSYM dist] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_MESON_TAC[SUBSET; IN_BALL; DIST_SYM];
+    ASM_MESON_TAC[PIECEWISE_DIFFERENTIABLE_ON_SUBSET];
+    ASM SET_TAC[]]);;
+
+let PATH_INTEGRAL_LOCAL_PRIMITIVE = prove
+ (`!f g s.
+        (!x. x IN s
+         ==> ?d h. &0 < d /\
+                   !y. norm(y - x) < d
+                       ==> (h has_complex_derivative f(y)) (at y within s)) /\
+        valid_path g /\ (path_image g) SUBSET s
+        ==> f path_integrable_on g`,
+  REWRITE_TAC[valid_path; path_image; SUBSET; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[path_integrable_on; has_path_integral] THEN
+  REWRITE_TAC[HAS_INTEGRAL_LOCALIZED_VECTOR_DERIVATIVE] THEN
+  REWRITE_TAC[GSYM integrable_on; PATH_INTEGRAL_LOCAL_PRIMITIVE_ANY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In particular if a function is holomorphic.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_INTEGRABLE_HOLOMORPHIC = prove
+ (`!f g s k.
+        open s /\ FINITE k /\
+        f continuous_on s /\
+        (!x. x IN s DIFF k ==> f complex_differentiable at x) /\
+        valid_path g /\ path_image g SUBSET s
+        ==> f path_integrable_on g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRAL_LOCAL_PRIMITIVE THEN
+  EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:complex->complex`; `ball(z:complex,d)`;
+                 `k:complex->bool`] HOLOMORPHIC_CONVEX_PRIMITIVE) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[CONVEX_BALL; DIFF_EMPTY] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ALL_TAC] THEN
+    GEN_TAC THEN DISCH_THEN(fun th ->
+        FIRST_X_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+    SIMP_TAC[IN_DIFF] THEN ASM_MESON_TAC[INTERIOR_SUBSET; SUBSET];
+    MATCH_MP_TAC MONO_EXISTS THEN
+    SIMP_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN; OPEN_BALL] THEN
+    ONCE_REWRITE_TAC[NORM_SUB] THEN REWRITE_TAC[IN_BALL; dist] THEN
+    ASM_MESON_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN]]);;
+
+let PATH_INTEGRABLE_HOLOMORPHIC_SIMPLE = prove
+ (`!f g s. open s /\ f holomorphic_on s /\ valid_path g /\ path_image g SUBSET s
+           ==> f path_integrable_on g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRABLE_HOLOMORPHIC THEN
+  MAP_EVERY EXISTS_TAC [`s:complex->bool`; `{}:complex->bool`] THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON; FINITE_RULES; DIFF_EMPTY] THEN
+  ASM_MESON_TAC[HOLOMORPHIC_ON_OPEN; complex_differentiable]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Key fact that path integral is the same for a "nearby" path. This is the  *)
+(* main lemma for the homotopy form of Cauchy's theorem and is also useful   *)
+(* if we want "without loss of generality" to assume some niceness of our    *)
+(* path (e.g. smoothness). It can also be used to define the integrals of    *)
+(* analytic functions over arbitrary continuous paths. This is just done for *)
+(* winding numbers now; I'm not sure if it's worth going further with that.  *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_INTEGRAL_NEARBY_ENDS,PATH_INTEGRAL_NEARBY_LOOP = (CONJ_PAIR o prove)
+ (`(!s p.
+      open s /\ path p /\ path_image p SUBSET s
+      ==> ?d. &0 < d /\
+              !g h. valid_path g /\ valid_path h /\
+                    (!t. t IN interval[vec 0,vec 1]
+                         ==> norm(g t - p t) < d /\ norm(h t - p t) < d) /\
+                    pathstart h = pathstart g /\ pathfinish h = pathfinish g
+                    ==> path_image g SUBSET s /\
+                        path_image h SUBSET s /\
+                        !f. f holomorphic_on s
+                            ==> path_integral h f = path_integral g f) /\
+   (!s p.
+      open s /\ path p /\ path_image p SUBSET s
+      ==> ?d. &0 < d /\
+              !g h. valid_path g /\ valid_path h /\
+                    (!t. t IN interval[vec 0,vec 1]
+                         ==> norm(g t - p t) < d /\ norm(h t - p t) < d) /\
+                    pathfinish g = pathstart g /\ pathfinish h = pathstart h
+                    ==> path_image g SUBSET s /\
+                        path_image h SUBSET s /\
+                        !f. f holomorphic_on s
+                            ==> path_integral h f = path_integral g f)`,
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN
+  MAP_EVERY (fun t -> ASM_CASES_TAC t THEN ASM_REWRITE_TAC[])
+   [`open(s:complex->bool)`;
+    `path(p:real^1->complex)`;
+    `path_image(p:real^1->complex) SUBSET s`] THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM] THEN
+  MATCH_MP_TAC(MESON[] `(?x. P x /\ Q x) ==> (?x. P x) /\ (?x. Q x)`) THEN
+  SUBGOAL_THEN
+   `!z. z IN path_image p ==> ?e. &0 < e /\ ball(z:complex,e) SUBSET s`
+  MP_TAC THENL
+   [ASM_MESON_TAC[OPEN_CONTAINS_BALL; SUBSET]; ALL_TAC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV)
+   [RIGHT_IMP_EXISTS_THM; RIGHT_AND_EXISTS_THM; SKOLEM_THM] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `ee:complex->real` THEN
+  DISCH_THEN(LABEL_TAC "*") THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_IMP_HEINE_BOREL o
+    MATCH_MP COMPACT_PATH_IMAGE) THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `IMAGE (\z:complex. ball(z,ee z / &3)) (path_image p)`) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[FORALL_IN_IMAGE; OPEN_BALL; SUBSET] THEN
+    X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+    REWRITE_TAC[UNIONS_IMAGE; IN_ELIM_THM] THEN EXISTS_TAC `z:complex` THEN
+    ASM_SIMP_TAC[CENTRE_IN_BALL; REAL_ARITH `&0 < e / &3 <=> &0 < e`];
+    ALL_TAC] THEN
+  REWRITE_TAC[path_image; GSYM IMAGE_o] THEN REWRITE_TAC[GSYM path_image] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> b /\ a /\ c`] THEN
+  REWRITE_TAC[CONJ_ASSOC; FINITE_SUBSET_IMAGE] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM; MESON[]
+   `(?f s. (P s /\ f = g s) /\ Q f) <=> ?s. P s /\ Q(g s)`] THEN
+  REWRITE_TAC[UNIONS_IMAGE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `k:real^1->bool` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  GEN_REWRITE_TAC LAND_CONV [SUBSET] THEN REWRITE_TAC[IN_ELIM_THM; o_THM] THEN
+  ASM_CASES_TAC `k:real^1->bool = {}` THENL
+   [ASM_REWRITE_TAC[NOT_IN_EMPTY; GSYM NOT_EXISTS_THM; MEMBER_NOT_EMPTY] THEN
+    REWRITE_TAC[PATH_IMAGE_NONEMPTY];
+    DISCH_THEN(LABEL_TAC "+")] THEN
+  SUBGOAL_THEN
+    `!i:real^1. i IN k ==> &0 < ee((p i):complex)`
+  ASSUME_TAC THENL
+   [ASM_MESON_TAC[SUBSET; path_image; IN_IMAGE]; ALL_TAC] THEN
+  ABBREV_TAC `e = inf(IMAGE ((ee:complex->real) o (p:real^1->complex)) k)` THEN
+  MP_TAC(ISPEC `IMAGE ((ee:complex->real) o (p:real^1->complex)) k`
+    INF_FINITE) THEN
+  MP_TAC(ISPECL [`IMAGE ((ee:complex->real) o (p:real^1->complex)) k`; `&0`]
+    REAL_LT_INF_FINITE) THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; IMAGE_EQ_EMPTY; FORALL_IN_IMAGE] THEN
+  ASM_REWRITE_TAC[o_THM] THEN DISCH_TAC THEN
+  DISCH_THEN(ASSUME_TAC o CONJUNCT2) THEN
+  EXISTS_TAC `e / &3` THEN
+  MP_TAC(ISPECL [`p:real^1->complex`; `interval[vec 0:real^1,vec 1]`]
+        COMPACT_UNIFORMLY_CONTINUOUS) THEN REWRITE_TAC[COMPACT_INTERVAL] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[path]; ALL_TAC] THEN
+  REWRITE_TAC[uniformly_continuous_on] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &3`) THEN
+  ASM_REWRITE_TAC[REAL_ARITH `&0 < e / &3 <=> &0 < e`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; AND_FORALL_THM] THEN
+  MAP_EVERY X_GEN_TAC [`g:real^1->complex`; `h:real^1->complex`] THEN
+  MAP_EVERY (fun t -> ASM_CASES_TAC t THEN ASM_REWRITE_TAC[])
+   [`!t. t IN interval[vec 0,vec 1]
+         ==> norm((g:real^1->complex) t - p t) < e / &3 /\
+             norm((h:real^1->complex) t - p t) < e / &3`;
+    `valid_path(g:real^1->complex)`; `valid_path(h:real^1->complex)`] THEN
+  MATCH_MP_TAC(TAUT
+   `q /\ (p1 \/ p2 ==> q ==> r) ==> (p1 ==> q /\ r) /\ (p2 ==> q /\ r)`) THEN
+  CONJ_TAC THENL
+   [CONJ_TAC THEN REWRITE_TAC[path_image; SUBSET; FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+    REMOVE_THEN "+" (MP_TAC o SPEC `(p:real^1->complex) t`) THEN
+    ASM_SIMP_TAC[path_image; FUN_IN_IMAGE; IN_BALL] THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^1` STRIP_ASSUME_TAC) THENL
+     [SUBGOAL_THEN `(g:real^1->complex) t IN ball(p(u:real^1),ee(p u))`
+      MP_TAC THENL [ALL_TAC; ASM_MESON_TAC[path_image; IN_IMAGE; SUBSET]];
+      SUBGOAL_THEN `(h:real^1->complex) t IN ball(p(u:real^1),ee(p u))`
+      MP_TAC THENL [ALL_TAC; ASM_MESON_TAC[path_image; IN_IMAGE; SUBSET]]] THEN
+    REWRITE_TAC[IN_BALL] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (NORM_ARITH `dist(gu,gt) < eu / &3
+                  ==> norm(ht - gt) < e / &3 /\ e <= eu
+                  ==> dist(gu,ht) < eu`)) THEN
+    ASM_SIMP_TAC[];
+    DISCH_TAC THEN STRIP_TAC THEN
+    X_GEN_TAC `f:complex->complex` THEN DISCH_TAC] THEN
+  SUBGOAL_THEN
+   `?ff. !z. z IN path_image p
+             ==> &0 < ee z /\ ball(z,ee z) SUBSET s /\
+                 !w. w IN ball(z,ee z)
+                     ==> (ff z has_complex_derivative f w) (at w)`
+  MP_TAC THENL
+   [REWRITE_TAC[GSYM SKOLEM_THM; RIGHT_EXISTS_IMP_THM;
+                RIGHT_EXISTS_AND_THM] THEN
+    X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+    REMOVE_THEN "*" (MP_TAC o SPEC `z:complex`) THEN
+    ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPECL [`f:complex->complex`; `ball(z:complex,ee z)`;
+                   `{}:complex->bool`] HOLOMORPHIC_CONVEX_PRIMITIVE) THEN
+    SIMP_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN; OPEN_BALL] THEN
+    DISCH_THEN MATCH_MP_TAC THEN REWRITE_TAC[CONVEX_BALL; FINITE_EMPTY] THEN
+    SIMP_TAC[DIFF_EMPTY; INTERIOR_OPEN; OPEN_BALL] THEN
+    SUBGOAL_THEN `f holomorphic_on ball(z,ee z)` MP_TAC THENL
+     [MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN EXISTS_TAC `s:complex->bool` THEN
+      ASM_REWRITE_TAC[];
+      SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON] THEN
+      SIMP_TAC[holomorphic_on; HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN; OPEN_BALL;
+               complex_differentiable]];
+    REMOVE_THEN "*" (K ALL_TAC) THEN
+    DISCH_THEN(CHOOSE_THEN (LABEL_TAC "*"))] THEN
+  MP_TAC(ISPEC `d:real` REAL_ARCH_INV) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N:num` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `!n. n <= N
+        ==> path_integral(subpath (vec 0) (&n / &N % vec 1) h) f -
+            path_integral(subpath (vec 0) (&n / &N % vec 1) g) f =
+            path_integral(linepath (g(&n / &N % vec 1),h(&n / &N % vec 1))) f -
+            path_integral(linepath (g(vec 0),h(vec 0))) f`
+  (MP_TAC o SPEC `N:num`) THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[LE_REFL; REAL_DIV_REFL; REAL_OF_NUM_EQ; VECTOR_MUL_LID] THEN
+    FIRST_X_ASSUM(DISJ_CASES_THEN MP_TAC) THEN
+    REWRITE_TAC[pathstart; pathfinish] THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[SUBPATH_TRIVIAL; PATH_INTEGRAL_TRIVIAL] THEN
+    CONV_TAC COMPLEX_RING] THEN
+  INDUCT_TAC THENL
+   [REWRITE_TAC[real_div; REAL_MUL_LZERO; VECTOR_MUL_LZERO] THEN
+    FIRST_X_ASSUM(DISJ_CASES_THEN MP_TAC) THEN
+    REWRITE_TAC[pathstart; pathfinish] THEN REPEAT STRIP_TAC THEN
+    ASM_REWRITE_TAC[PATH_INTEGRAL_TRIVIAL; PATH_INTEGRAL_SUBPATH_REFL] THEN
+    REWRITE_TAC[COMPLEX_SUB_REFL];
+    DISCH_TAC THEN FIRST_X_ASSUM(K ALL_TAC o check (is_disj o concl))] THEN
+  REMOVE_THEN "+" (MP_TAC o SPEC `(p:real^1->complex)(&n / &N % vec 1)`) THEN
+  REWRITE_TAC[IN_BALL] THEN ANTS_TAC THENL
+   [REWRITE_TAC[path_image] THEN MATCH_MP_TAC FUN_IN_IMAGE THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_CMUL; DROP_VEC; REAL_MUL_RID] THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; LE_1] THEN
+    REWRITE_TAC[REAL_OF_NUM_MUL; REAL_OF_NUM_LE] THEN ASM_ARITH_TAC;
+    DISCH_THEN(X_CHOOSE_THEN `t:real^1` STRIP_ASSUME_TAC)] THEN
+  MP_TAC(ISPECL
+   [`(ff:complex->complex->complex) (p(t:real^1))`; `f:complex->complex`;
+    `subpath (&n / &N % vec 1) (&(SUC n) / &N % vec 1) (g:real^1->complex) ++
+     linepath(g (&(SUC n) / &N % vec 1),h(&(SUC n) / &N % vec 1)) ++
+     subpath (&(SUC n) / &N % vec 1) (&n / &N % vec 1) h ++
+     linepath(h (&n / &N % vec 1),g (&n / &N % vec 1))`;
+    `ball((p:real^1->complex) t,ee(p t))`] CAUCHY_THEOREM_PRIMITIVE) THEN
+  ASM_SIMP_TAC[VALID_PATH_JOIN_EQ; PATHSTART_JOIN; PATHFINISH_JOIN;
+   PATHSTART_SUBPATH; PATHFINISH_SUBPATH; PATH_IMAGE_JOIN; PATHSTART_LINEPATH;
+   PATHFINISH_LINEPATH; VALID_PATH_LINEPATH; UNION_SUBSET] THEN
+  ONCE_REWRITE_TAC[IMP_CONJ] THEN ANTS_TAC THENL
+   [X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+    REMOVE_THEN "*" (MP_TAC o SPEC `(p:real^1->complex) t`) THEN ANTS_TAC THENL
+     [ASM_MESON_TAC[path_image; IN_IMAGE; SUBSET];
+      ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN; CENTRE_IN_BALL]];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(TAUT `p /\ q /\ (p ==> r ==> s) ==> (p /\ q ==> r) ==> s`) THEN
+  CONJ_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC VALID_PATH_SUBPATH THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_CMUL; DROP_VEC; REAL_MUL_RID] THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; LE_1] THEN
+    REWRITE_TAC[REAL_OF_NUM_MUL; REAL_OF_NUM_LE] THEN ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [SUBGOAL_THEN `drop(&n / &N % vec 1) <= drop(&(SUC n) / &N % vec 1)`
+    ASSUME_TAC THENL
+     [ASM_SIMP_TAC[DROP_CMUL; DROP_VEC; REAL_MUL_RID; REAL_LE_DIV2_EQ;
+                   REAL_OF_NUM_LT; LE_1; REAL_OF_NUM_LE] THEN
+      ARITH_TAC;
+      ASM_SIMP_TAC[PATH_IMAGE_SUBPATH; PATH_IMAGE_LINEPATH] THEN
+      ONCE_REWRITE_TAC[GSYM REVERSEPATH_SUBPATH] THEN
+      ASM_SIMP_TAC[PATH_IMAGE_SUBPATH; PATH_IMAGE_REVERSEPATH]] THEN
+    MATCH_MP_TAC(TAUT
+     `(p /\ r) /\ (p /\ r ==> q /\ s) ==> p /\ q /\ r /\ s`) THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+      REWRITE_TAC[AND_FORALL_THM; TAUT
+        `(p ==> q) /\ (p ==> r) <=> p ==> q /\ r`] THEN
+      X_GEN_TAC `u:real^1` THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+      REWRITE_TAC[DROP_CMUL; DROP_VEC; REAL_MUL_RID] THEN STRIP_TAC THEN
+      REWRITE_TAC[IN_BALL] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (NORM_ARITH
+       `!e pu. dist(pt,pn) < ee / &3
+               ==> dist(pn,pu) < e / &3 /\ e <= ee /\
+                   norm(gu - pu) < e / &3 /\ norm(hu - pu) < e / &3
+                   ==> dist(pt,gu) < ee /\ dist(pt,hu) < ee`)) THEN
+      MAP_EVERY EXISTS_TAC [`e:real`; `(p:real^1->complex) u`] THEN
+      ASM_SIMP_TAC[] THEN
+      SUBGOAL_THEN `(u:real^1) IN interval[vec 0,vec 1]` ASSUME_TAC THENL
+       [REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN CONJ_TAC THENL
+         [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+           REAL_LE_TRANS)) THEN ASM_SIMP_TAC[REAL_LE_DIV; REAL_POS];
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+           REAL_LE_TRANS)) THEN
+          ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; LE_1] THEN
+          ASM_REWRITE_TAC[REAL_MUL_LID; REAL_OF_NUM_LE]];
+        ASM_SIMP_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+        ASM_REWRITE_TAC[] THEN
+        REWRITE_TAC[DIST_REAL; GSYM drop; IN_INTERVAL_1;
+                    DROP_VEC; DROP_CMUL; REAL_MUL_RID] THEN
+        ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_POS; REAL_LE_DIV;
+              REAL_OF_NUM_LT; LE_1; REAL_MUL_LID; REAL_OF_NUM_LE;
+              ARITH_RULE `SUC n <= N ==> n <= N`] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+         `u <= s ==> n <= u /\ s - n < d ==> abs(n - u) < d`)) THEN
+        ASM_REWRITE_TAC[] THEN
+        REWRITE_TAC[real_div; GSYM REAL_SUB_RDISTRIB] THEN
+        SIMP_TAC[REAL_OF_NUM_SUB; ARITH_RULE `n <= SUC n`] THEN
+        ASM_REWRITE_TAC[ARITH_RULE `SUC n - n = 1`; REAL_MUL_LID]];
+      GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [SUBSET] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE] THEN STRIP_TAC THEN
+      REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN CONJ_TAC THEN
+      MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_BALL] THEN
+      REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET] THEN
+      CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_EQ_EMPTY_1; REAL_NOT_LT] THEN
+      REWRITE_TAC[DROP_VEC; DROP_CMUL; REAL_MUL_RID] THEN
+        ASM_SIMP_TAC[REAL_LE_DIV2_EQ; REAL_POS; REAL_LE_DIV;
+              REAL_OF_NUM_LT; LE_1; REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+      ARITH_TAC];
+    STRIP_TAC THEN DISCH_THEN(fun th ->
+        MP_TAC(MATCH_MP PATH_INTEGRAL_UNIQUE th) THEN
+        MP_TAC(MATCH_MP HAS_PATH_INTEGRAL_INTEGRABLE th)) THEN
+    ASM_SIMP_TAC[PATH_INTEGRABLE_JOIN; VALID_PATH_JOIN_EQ; VALID_PATH_LINEPATH;
+      PATHSTART_SUBPATH; PATHFINISH_SUBPATH; PATHSTART_JOIN; PATHFINISH_JOIN;
+      PATHSTART_LINEPATH; PATHFINISH_LINEPATH; VALID_PATH_LINEPATH;
+      PATH_INTEGRAL_JOIN] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o check(is_imp o concl)) THEN
+    ASM_SIMP_TAC[ARITH_RULE `SUC n <= N ==> n <= N`] THEN
+    MATCH_MP_TAC(COMPLEX_RING
+     `hn - he = hn' /\ gn + gd = gn' /\ hgn = --ghn
+      ==> hn - gn = ghn - gh0
+          ==> gd + ghn' + he + hgn = Cx(&0)
+              ==> hn' - gn' = ghn' - gh0`) THEN
+    REPEAT CONJ_TAC THENL
+     [ASM_SIMP_TAC[complex_sub; GSYM PATH_INTEGRAL_REVERSEPATH] THEN
+      REWRITE_TAC[REVERSEPATH_SUBPATH] THEN
+      MATCH_MP_TAC PATH_INTEGRAL_SUBPATH_COMBINE;
+      MATCH_MP_TAC PATH_INTEGRAL_SUBPATH_COMBINE;
+      GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+       [GSYM REVERSEPATH_LINEPATH] THEN
+      MATCH_MP_TAC PATH_INTEGRAL_REVERSEPATH] THEN
+    ASM_REWRITE_TAC[VALID_PATH_LINEPATH] THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_CMUL; DROP_VEC; REAL_MUL_RID] THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; REAL_POS; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; LE_1;
+                 REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+    ASM_SIMP_TAC[ARITH_RULE `SUC n <= N ==> n <= N`] THEN
+    TRY(MATCH_MP_TAC PATH_INTEGRABLE_HOLOMORPHIC_SIMPLE THEN
+        EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[] THEN NO_TAC) THEN
+    ASM_MESON_TAC[PATH_INTEGRABLE_REVERSEPATH; VALID_PATH_LINEPATH;
+                  REVERSEPATH_LINEPATH]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence we can treat even non-rectifiable paths as having a "length"        *)
+(* for bounds on analytic functions in open sets.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION = prove
+ (`!p:real^1->complex.
+     vector_polynomial_function p ==> valid_path p`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[valid_path] THEN
+  MATCH_MP_TAC DIFFERENTIABLE_ON_IMP_PIECEWISE_DIFFERENTIABLE THEN
+  MATCH_MP_TAC DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON THEN
+  REWRITE_TAC[VECTOR_DERIVATIVE_WORKS] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[vector_derivative] THEN
+  CONV_TAC SELECT_CONV THEN
+  ASM_MESON_TAC[HAS_VECTOR_DERIVATIVE_VECTOR_POLYNOMIAL_FUNCTION]);;
+
+let PATH_INTEGRAL_BOUND_EXISTS = prove
+ (`!s g. open s /\ valid_path g /\ path_image g SUBSET s
+         ==> ?L. &0 < L /\
+                 !f B. f holomorphic_on s /\ (!z. z IN s ==> norm(f z) <= B)
+                       ==> norm(path_integral g f) <= L * B`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:complex->bool`; `g:real^1->complex`]
+        PATH_INTEGRAL_NEARBY_ENDS) THEN
+  ASM_SIMP_TAC[VALID_PATH_IMP_PATH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(MP_TAC o SPEC `g:real^1->complex`) THEN
+  ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+  DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `d:real`]
+   PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION) THEN
+  ASM_SIMP_TAC[VALID_PATH_IMP_PATH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:real^1->complex` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `p:real^1->complex`) THEN
+  ASM_SIMP_TAC[VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN STRIP_TAC THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `p':real^1->complex` STRIP_ASSUME_TAC o
+    MATCH_MP HAS_VECTOR_DERIVATIVE_VECTOR_POLYNOMIAL_FUNCTION) THEN
+  SUBGOAL_THEN `bounded(IMAGE (p':real^1->complex) (interval[vec 0,vec 1]))`
+  MP_TAC THENL
+   [MATCH_MP_TAC COMPACT_IMP_BOUNDED THEN
+    MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+    REWRITE_TAC[COMPACT_INTERVAL] THEN
+    ASM_MESON_TAC[CONTINUOUS_VECTOR_POLYNOMIAL_FUNCTION;
+                  CONTINUOUS_AT_IMP_CONTINUOUS_ON];
+    REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE]] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `L:real` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `f path_integrable_on p /\ valid_path p` STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[PATH_INTEGRABLE_HOLOMORPHIC_SIMPLE;
+                  VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`f:complex->complex`; `p:real^1->complex`]
+        PATH_INTEGRAL_INTEGRAL) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+   `drop(integral (interval[vec 0,vec 1]) (\x:real^1. lift(L * B)))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+    ASM_REWRITE_TAC[INTEGRABLE_CONST; GSYM PATH_INTEGRABLE_ON] THEN
+    X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    REWRITE_TAC[LIFT_DROP; COMPLEX_NORM_MUL] THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN REWRITE_TAC[NORM_POS_LE] THEN
+    CONJ_TAC THENL
+     [FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_MESON_TAC[path_image; SUBSET; IN_IMAGE];
+      ASM_MESON_TAC[HAS_VECTOR_DERIVATIVE_UNIQUE_AT]];
+    REWRITE_TAC[INTEGRAL_CONST; CONTENT_UNIT_1; VECTOR_MUL_LID] THEN
+    REWRITE_TAC[LIFT_DROP; REAL_LE_REFL]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Winding number.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let winding_number = new_definition
+ `winding_number(g,z) =
+    @n. !e. &0 < e
+            ==> ?p. valid_path p /\ ~(z IN path_image p) /\
+                    pathstart p = pathstart g /\
+                    pathfinish p = pathfinish g /\
+                    (!t. t IN interval[vec 0,vec 1] ==> norm(g t - p t) < e) /\
+                    path_integral p (\w. Cx(&1) / (w - z)) =
+                    Cx(&2) * Cx(pi) * ii * n`;;
+
+let CX_2PII_NZ = prove
+ (`~(Cx(&2) * Cx(pi) * ii = Cx(&0))`,
+  SIMP_TAC[COMPLEX_ENTIRE; CX_PI_NZ; II_NZ; CX_INJ; REAL_OF_NUM_EQ; ARITH]);;
+
+let PATH_INTEGRABLE_INVERSEDIFF = prove
+ (`!g z. valid_path g /\ ~(z IN path_image g)
+         ==> (\w. Cx(&1) / (w - z)) path_integrable_on g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_INTEGRABLE_HOLOMORPHIC_SIMPLE THEN
+  EXISTS_TAC `(:complex) DELETE z` THEN
+  ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV; HOLOMORPHIC_ON_OPEN; SET_RULE
+   `s SUBSET (UNIV DELETE x) <=> ~(x IN s)`] THEN
+  X_GEN_TAC `w:complex` THEN REWRITE_TAC[IN_UNIV; IN_DELETE] THEN
+  STRIP_TAC THEN
+  W(MP_TAC o DISCH_ALL o COMPLEX_DIFF_CONV o snd o dest_exists o snd) THEN
+  ASM_REWRITE_TAC[COMPLEX_SUB_0] THEN MESON_TAC[]);;
+
+let WINDING_NUMBER = prove
+ (`!g z e.
+        path g /\ ~(z IN path_image g) /\ &0 < e
+         ==> ?p. valid_path p /\ ~(z IN path_image p) /\
+                 pathstart p = pathstart g /\
+                 pathfinish p = pathfinish g /\
+                 (!t. t IN interval[vec 0,vec 1] ==> norm(g t - p t) < e) /\
+                 path_integral p (\w. Cx(&1) / (w - z)) =
+                 Cx(&2) * Cx(pi) * ii * winding_number(g,z)`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN DISCH_TAC THEN
+  REWRITE_TAC[winding_number] THEN CONV_TAC SELECT_CONV THEN
+  MP_TAC(ISPECL [`(:complex) DELETE z`; `g:real^1->complex`]
+        PATH_INTEGRAL_NEARBY_ENDS) THEN
+  ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `d / &2`]
+    PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION) THEN
+  ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^1->complex` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `Cx (&1) / (Cx (&2) * Cx pi * ii) *
+              path_integral h (\w. Cx (&1) / (w - z))` THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `min d e / &2`]
+    PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION) THEN
+  ASM_REWRITE_TAC[REAL_HALF; REAL_LT_MIN] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `p:real^1->complex` THEN
+  STRIP_TAC THEN
+  ASM_SIMP_TAC[VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION; CX_2PII_NZ; COMPLEX_FIELD
+   `~(a * b * c = Cx(&0))
+    ==> a * b * c * Cx(&1) / (a * b * c) * z = z`] THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`h:real^1->complex`; `p:real^1->complex`]) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN
+    ASM_MESON_TAC[NORM_ARITH
+     `norm(h - g) < d / &2 /\ norm(p - g) < min d e / &2
+      ==> norm(h - g) < d /\ norm(p - g) < d`];
+    ALL_TAC] THEN
+  REWRITE_TAC[SET_RULE `t SUBSET UNIV DELETE x <=> ~(x IN t)`] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[NORM_SUB; REAL_ARITH `&0 < e /\ x < min d e / &2 ==> x < e`];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV; HOLOMORPHIC_ON_OPEN] THEN
+  REWRITE_TAC[IN_DELETE; IN_UNIV; GSYM complex_differentiable] THEN
+  REPEAT STRIP_TAC THEN COMPLEX_DIFFERENTIABLE_TAC THEN
+  ASM_REWRITE_TAC[COMPLEX_SUB_0]);;
+
+let WINDING_NUMBER_UNIQUE = prove
+ (`!g z e n.
+        path g /\ ~(z IN path_image g) /\
+        (!e. &0 < e
+             ==> ?p. valid_path p /\ ~(z IN path_image p) /\
+                     pathstart p = pathstart g /\
+                     pathfinish p = pathfinish g /\
+                     (!t. t IN interval[vec 0,vec 1]
+                          ==> norm(g t - p t) < e) /\
+                     path_integral p (\w. Cx(&1) / (w - z)) =
+                     Cx(&2) * Cx(pi) * ii * n)
+        ==> winding_number(g,z) = n`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(:complex) DELETE z`; `g:real^1->complex`]
+        PATH_INTEGRAL_NEARBY_ENDS) THEN
+  ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:real^1->complex` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`] WINDING_NUMBER) THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `q:real^1->complex` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`p:real^1->complex`; `q:real^1->complex`]) THEN
+  ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[NORM_SUB] THEN ASM_SIMP_TAC[] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `\w. Cx(&1) / (w - z)`) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV; HOLOMORPHIC_ON_OPEN] THEN
+    REWRITE_TAC[IN_DELETE; IN_UNIV; GSYM complex_differentiable] THEN
+    REPEAT STRIP_TAC THEN COMPLEX_DIFFERENTIABLE_TAC THEN
+    ASM_REWRITE_TAC[COMPLEX_SUB_0];
+    ASM_REWRITE_TAC[] THEN MP_TAC CX_2PII_NZ THEN
+    CONV_TAC COMPLEX_RING]);;
+
+let WINDING_NUMBER_UNIQUE_LOOP = prove
+ (`!g z e n.
+        path g /\ ~(z IN path_image g) /\ pathfinish g = pathstart g /\
+        (!e. &0 < e
+             ==> ?p. valid_path p /\ ~(z IN path_image p) /\
+                     pathfinish p = pathstart p /\
+                     (!t. t IN interval[vec 0,vec 1]
+                          ==> norm(g t - p t) < e) /\
+                     path_integral p (\w. Cx(&1) / (w - z)) =
+                     Cx(&2) * Cx(pi) * ii * n)
+        ==> winding_number(g,z) = n`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(:complex) DELETE z`; `g:real^1->complex`]
+        PATH_INTEGRAL_NEARBY_LOOP) THEN
+  ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:real^1->complex` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`] WINDING_NUMBER) THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `q:real^1->complex` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`p:real^1->complex`; `q:real^1->complex`]) THEN
+  ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[NORM_SUB] THEN ASM_SIMP_TAC[] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `\w. Cx(&1) / (w - z)`) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV; HOLOMORPHIC_ON_OPEN] THEN
+    REWRITE_TAC[IN_DELETE; IN_UNIV; GSYM complex_differentiable] THEN
+    REPEAT STRIP_TAC THEN COMPLEX_DIFFERENTIABLE_TAC THEN
+    ASM_REWRITE_TAC[COMPLEX_SUB_0];
+    ASM_REWRITE_TAC[] THEN MP_TAC CX_2PII_NZ THEN
+    CONV_TAC COMPLEX_RING]);;
+
+let WINDING_NUMBER_VALID_PATH = prove
+ (`!g z. valid_path g /\ ~(z IN path_image g)
+         ==> winding_number(g,z) =
+             Cx(&1) / (Cx(&2) * Cx(pi) * ii) *
+             path_integral g (\w. Cx(&1) / (w - z))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC WINDING_NUMBER_UNIQUE THEN
+  ASM_SIMP_TAC[VALID_PATH_IMP_PATH] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  EXISTS_TAC `g:real^1->complex` THEN
+  ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+  MP_TAC CX_2PII_NZ THEN CONV_TAC COMPLEX_FIELD);;
+
+let HAS_PATH_INTEGRAL_WINDING_NUMBER = prove
+ (`!g z. valid_path g /\ ~(z IN path_image g)
+         ==> ((\w. Cx(&1) / (w - z)) has_path_integral
+              (Cx(&2) * Cx(pi) * ii * winding_number(g,z))) g`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[WINDING_NUMBER_VALID_PATH] THEN
+  ASM_SIMP_TAC[CX_2PII_NZ; COMPLEX_FIELD
+   `~(a * b * c = Cx(&0))
+    ==> a * b * c * Cx(&1) / (a * b * c) * z = z`] THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_INTEGRAL THEN
+  ASM_SIMP_TAC[PATH_INTEGRABLE_INVERSEDIFF]);;
+
+let WINDING_NUMBER_TRIVIAL = prove
+ (`!a z. ~(z = a) ==> winding_number(linepath(a,a),z) = Cx(&0)`,
+  SIMP_TAC[VALID_PATH_LINEPATH; PATH_INTEGRAL_TRIVIAL; COMPLEX_MUL_RZERO;
+           WINDING_NUMBER_VALID_PATH; PATH_IMAGE_LINEPATH; SEGMENT_REFL;
+           IN_SING]);;
+
+let WINDING_NUMBER_JOIN = prove
+ (`!g1 g2 z.
+        path g1 /\ path g2 /\ pathfinish g1 = pathstart g2 /\
+        ~(z IN path_image g1) /\ ~(z IN path_image g2)
+        ==> winding_number(g1 ++ g2,z) =
+            winding_number(g1,z) + winding_number(g2,z)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC WINDING_NUMBER_UNIQUE THEN
+  ASM_SIMP_TAC[PATH_JOIN; PATH_IMAGE_JOIN; IN_UNION] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`g2:real^1->complex`; `z:complex`; `e:real`]
+    WINDING_NUMBER) THEN
+  MP_TAC(ISPECL [`g1:real^1->complex`; `z:complex`; `e:real`]
+    WINDING_NUMBER) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `p1:real^1->complex` THEN STRIP_TAC THEN
+  X_GEN_TAC `p2:real^1->complex` THEN STRIP_TAC THEN
+  EXISTS_TAC `p1 ++ p2:real^1->complex` THEN
+  ASM_SIMP_TAC[VALID_PATH_JOIN; PATHSTART_JOIN; PATHFINISH_JOIN] THEN
+  ASM_SIMP_TAC[PATH_IMAGE_JOIN; IN_UNION] THEN  CONJ_TAC THENL
+   [REWRITE_TAC[joinpaths; IN_INTERVAL_1; DROP_VEC] THEN REPEAT STRIP_TAC THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_CMUL; DROP_SUB] THEN
+    ASM_REAL_ARITH_TAC;
+    W(MP_TAC o PART_MATCH (lhs o rand) PATH_INTEGRAL_JOIN o lhand o snd) THEN
+    ASM_REWRITE_TAC[COMPLEX_ADD_LDISTRIB] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    CONJ_TAC THEN MATCH_MP_TAC PATH_INTEGRABLE_INVERSEDIFF THEN
+    ASM_REWRITE_TAC[]]);;
+
+let WINDING_NUMBER_REVERSEPATH = prove
+ (`!g z. path g /\ ~(z IN path_image g)
+         ==> winding_number(reversepath g,z) = --(winding_number(g,z))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC WINDING_NUMBER_UNIQUE THEN
+  ASM_SIMP_TAC[PATH_REVERSEPATH; PATH_IMAGE_REVERSEPATH] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`; `e:real`]
+    WINDING_NUMBER) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:real^1->complex` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `reversepath p:real^1->complex` THEN
+  ASM_SIMP_TAC[VALID_PATH_REVERSEPATH; PATH_IMAGE_REVERSEPATH;
+               PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+               PATH_INTEGRAL_REVERSEPATH; PATH_INTEGRABLE_INVERSEDIFF] THEN
+  REWRITE_TAC[COMPLEX_MUL_RNEG; reversepath; IN_INTERVAL_1; DROP_VEC] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_SUB] THEN ASM_REAL_ARITH_TAC);;
+
+let WINDING_NUMBER_SHIFTPATH = prove
+ (`!g a z. path g /\ pathfinish g = pathstart g /\ ~(z IN path_image g) /\
+           a IN interval[vec 0,vec 1]
+           ==> winding_number(shiftpath a g,z) = winding_number(g,z)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC WINDING_NUMBER_UNIQUE_LOOP THEN
+  ASM_SIMP_TAC[PATH_SHIFTPATH; PATH_IMAGE_SHIFTPATH] THEN CONJ_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+    ASM_SIMP_TAC[PATHSTART_SHIFTPATH; PATHFINISH_SHIFTPATH];
+    ALL_TAC] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`; `e:real`]
+    WINDING_NUMBER) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:real^1->complex` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `shiftpath a p:real^1->complex` THEN
+  ASM_SIMP_TAC[VALID_PATH_SHIFTPATH; PATH_IMAGE_SHIFTPATH;
+               PATH_INTEGRAL_SHIFTPATH; PATH_INTEGRABLE_INVERSEDIFF] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+  ASM_SIMP_TAC[PATHSTART_SHIFTPATH; PATHFINISH_SHIFTPATH] THEN
+  SIMP_TAC[COMPLEX_MUL_RNEG; shiftpath; IN_INTERVAL_1; DROP_ADD; DROP_VEC] THEN
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_SUB; DROP_ADD] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let WINDING_NUMBER_SPLIT_LINEPATH = prove
+ (`!a b c z.
+    c IN segment[a,b] /\ ~(z IN segment[a,b])
+    ==> winding_number(linepath(a,b),z) =
+        winding_number(linepath(a,c),z) +
+        winding_number(linepath(c,b),z)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `~((z:complex) IN segment[a,c]) /\ ~(z IN segment[c,b])`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `~(z IN s) ==> t SUBSET s ==> ~(z IN t)`)) THEN
+    ASM_REWRITE_TAC[SUBSET_SEGMENT; ENDS_IN_SEGMENT];
+    ASM_SIMP_TAC[WINDING_NUMBER_VALID_PATH; PATH_IMAGE_LINEPATH;
+                 VALID_PATH_LINEPATH] THEN
+    REWRITE_TAC[GSYM COMPLEX_ADD_LDISTRIB] THEN AP_TERM_TAC THEN
+    MATCH_MP_TAC PATH_INTEGRAL_SPLIT_LINEPATH THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_DIV THEN
+    SIMP_TAC[CONTINUOUS_ON_CONST; CONTINUOUS_ON_SUB; CONTINUOUS_ON_ID] THEN
+    ASM_MESON_TAC[COMPLEX_SUB_0]]);;
+
+let WINDING_NUMBER_EQUAL = prove
+ (`!p q z. (!t. t IN interval[vec 0,vec 1] ==> p t = q t)
+           ==> winding_number(p,z) = winding_number(q,z)`,
+  REPEAT STRIP_TAC THEN SIMP_TAC[winding_number; PATH_INTEGRAL_INTEGRAL] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `W:complex` THEN REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `e:real` THEN REWRITE_TAC[] THEN
+  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `g:real^1->complex` THEN
+  ASM_SIMP_TAC[pathstart; pathfinish; ENDS_IN_UNIT_INTERVAL]);;
+
+let WINDING_NUMBER_OFFSET = prove
+ (`!p z. winding_number(p,z) = winding_number((\w. p w - z),Cx(&0))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[winding_number; PATH_INTEGRAL_INTEGRAL] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `W:complex` THEN REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `e:real` THEN REWRITE_TAC[] THEN
+  ASM_CASES_TAC `&0 < e` THEN
+  ASM_REWRITE_TAC[path_image; valid_path; pathstart; pathfinish] THEN
+  EQ_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^1->complex` STRIP_ASSUME_TAC) THENL
+   [EXISTS_TAC `\t. (g:real^1->complex) t - z`;
+    EXISTS_TAC `\t. (g:real^1->complex) t + z`] THEN
+  ASM_REWRITE_TAC[COMPLEX_RING `(p - z) - (g - z):complex = p - g`;
+                  COMPLEX_RING `p - (g + z):complex = p - z - g`;
+                  COMPLEX_RING `(p - z) + z:complex = p`;
+                  COMPLEX_SUB_RZERO] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_IMAGE]) THEN
+  ASM_SIMP_TAC[PIECEWISE_DIFFERENTIABLE_ADD; PIECEWISE_DIFFERENTIABLE_SUB;
+               DIFFERENTIABLE_ON_IMP_PIECEWISE_DIFFERENTIABLE;
+               DIFFERENTIABLE_ON_CONST; IN_IMAGE] THEN
+  ASM_REWRITE_TAC[COMPLEX_RING `Cx(&0) = w - z <=> z = w`;
+                  COMPLEX_RING `z = w + z <=> Cx(&0) = w`] THEN
+  FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [SYM th]) THEN
+  MATCH_MP_TAC INTEGRAL_EQ THEN X_GEN_TAC `t:real^1` THEN STRIP_TAC THEN
+  REWRITE_TAC[COMPLEX_RING `(w + z) - z = w - Cx(&0)`] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[vector_derivative; has_vector_derivative; HAS_DERIVATIVE_AT;
+              COMPLEX_RING `(x - z) - (w - z):complex = x - w`;
+              COMPLEX_RING `(x + z) - (w + z):complex = x - w`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A combined theorem deducing several things piecewise.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_JOIN_POS_COMBINED = prove
+ (`!g1 g2 z.
+       (valid_path g1 /\
+        ~(z IN path_image g1) /\
+        &0 < Re(winding_number(g1,z))) /\
+       (valid_path g2 /\
+        ~(z IN path_image g2) /\
+        &0 < Re(winding_number(g2,z))) /\
+       pathfinish g1 = pathstart g2
+       ==> valid_path(g1 ++ g2) /\
+           ~(z IN path_image(g1 ++ g2)) /\
+           &0 < Re(winding_number(g1 ++ g2,z))`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN ASM_SIMP_TAC[VALID_PATH_JOIN] THEN
+  ASM_SIMP_TAC[PATH_IMAGE_JOIN; VALID_PATH_IMP_PATH; IN_UNION] THEN
+  ASM_SIMP_TAC[WINDING_NUMBER_JOIN; VALID_PATH_IMP_PATH; RE_ADD] THEN
+  ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Useful sufficient conditions for the winding number to be positive etc.   *)
+(* ------------------------------------------------------------------------- *)
+
+let RE_WINDING_NUMBER = prove
+ (`!g z. valid_path g /\ ~(z IN path_image g)
+         ==> Re(winding_number(g,z)) =
+             Im(path_integral g (\w. Cx(&1) / (w - z))) / (&2 * pi)`,
+  SIMP_TAC[WINDING_NUMBER_VALID_PATH; complex_div; COMPLEX_MUL_LID] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[COMPLEX_MUL_ASSOC; GSYM CX_MUL] THEN
+  REWRITE_TAC[COMPLEX_INV_MUL; GSYM CX_INV; COMPLEX_INV_II] THEN
+  REWRITE_TAC[COMPLEX_MUL_LNEG; COMPLEX_MUL_RNEG; RE_NEG] THEN
+  REWRITE_TAC[GSYM COMPLEX_MUL_ASSOC; RE_MUL_CX; RE_MUL_II] THEN
+  MP_TAC PI_POS THEN CONV_TAC REAL_FIELD);;
+
+let WINDING_NUMBER_POS_LE = prove
+ (`!g z. valid_path g /\ ~(z IN path_image g) /\
+         (!x. x IN interval(vec 0,vec 1)
+              ==> &0 <= Im(vector_derivative g (at x) * cnj(g x - z)))
+         ==> &0 <= Re(winding_number(g,z))`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[RE_WINDING_NUMBER] THEN
+  MATCH_MP_TAC REAL_LE_DIV THEN
+  SIMP_TAC[REAL_LE_MUL; REAL_POS; PI_POS; REAL_LT_IMP_LE; IM_DEF] THEN
+  MATCH_MP_TAC(INST_TYPE [`:1`,`:M`; `:2`,`:N`]
+    HAS_INTEGRAL_COMPONENT_POS) THEN
+  MAP_EVERY EXISTS_TAC
+   [`\x:real^1. if x IN interval(vec 0,vec 1)
+                then Cx(&1) / (g x - z) * vector_derivative g (at x)
+                else Cx(&0)`;
+    `interval[vec 0:real^1,vec 1]`] THEN
+  REWRITE_TAC[ARITH; DIMINDEX_2] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HAS_INTEGRAL_SPIKE_INTERIOR THEN
+    EXISTS_TAC `\x:real^1. Cx(&1) / (g x - z) * vector_derivative g (at x)` THEN
+    ASM_SIMP_TAC[] THEN REWRITE_TAC[GSYM HAS_PATH_INTEGRAL] THEN
+    MATCH_MP_TAC HAS_PATH_INTEGRAL_INTEGRAL THEN
+    ASM_SIMP_TAC[PATH_INTEGRABLE_INVERSEDIFF];
+    ALL_TAC] THEN
+  X_GEN_TAC `x:real^1` THEN DISCH_TAC THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[GSYM IM_DEF; IM_CX; REAL_LE_REFL] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `x:real^1`) THEN
+  ASM_REWRITE_TAC[complex_div; COMPLEX_MUL_LID] THEN
+  REWRITE_TAC[complex_inv; complex_inv; complex_mul; RE; IM; cnj] THEN
+  REWRITE_TAC[real_div; REAL_RING
+   `(a * x) * b + (--c * x) * d:real = x * (a * b - c * d)`] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_MUL THEN
+  SIMP_TAC[REAL_POW_2; REAL_LE_INV_EQ; REAL_LE_ADD; REAL_LE_SQUARE] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let WINDING_NUMBER_POS_LT_LEMMA = prove
+ (`!g z e. valid_path g /\ ~(z IN path_image g) /\ &0 < e /\
+           (!x. x IN interval(vec 0,vec 1)
+                ==> e <= Im(vector_derivative g (at x) / (g x - z)))
+           ==> &0 < Re(winding_number(g,z))`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[RE_WINDING_NUMBER] THEN
+  MATCH_MP_TAC REAL_LT_DIV THEN
+  SIMP_TAC[REAL_LT_MUL; REAL_OF_NUM_LT; ARITH; PI_POS] THEN
+  MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `Im(ii * Cx e)` THEN
+  CONJ_TAC THENL
+   [ASM_REWRITE_TAC[COMPLEX_MUL_LNEG; IM_MUL_II; IM_NEG; RE_CX]; ALL_TAC] THEN
+  REWRITE_TAC[IM_DEF] THEN
+  MATCH_MP_TAC(ISPECL [`\x:real^1. ii * Cx e`;
+        `\x:real^1. if x IN interval(vec 0,vec 1)
+                    then Cx(&1) / (g x - z) * vector_derivative g (at x)
+                    else ii * Cx e`;
+        `interval[vec 0:real^1,vec 1]`; `ii * Cx e`;
+        `path_integral g (\w. Cx(&1) / (w - z))`; `2`]
+       HAS_INTEGRAL_COMPONENT_LE) THEN
+  REWRITE_TAC[DIMINDEX_2; ARITH] THEN REPEAT CONJ_TAC THENL
+   [GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_MUL_LID] THEN
+    ONCE_REWRITE_TAC[GSYM CONTENT_UNIT_1] THEN
+    REWRITE_TAC[HAS_INTEGRAL_CONST];
+    MATCH_MP_TAC HAS_INTEGRAL_SPIKE_INTERIOR THEN
+    EXISTS_TAC `\x:real^1. Cx(&1) / (g x - z) * vector_derivative g (at x)` THEN
+    ASM_SIMP_TAC[] THEN REWRITE_TAC[GSYM HAS_PATH_INTEGRAL] THEN
+    MATCH_MP_TAC HAS_PATH_INTEGRAL_INTEGRAL THEN
+    ASM_SIMP_TAC[PATH_INTEGRABLE_INVERSEDIFF];
+    X_GEN_TAC `x:real^1` THEN DISCH_TAC THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[GSYM IM_DEF; IM_CX; REAL_LE_REFL] THEN
+    REWRITE_TAC[IM_MUL_II; RE_CX] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^1`) THEN
+    ASM_REWRITE_TAC[complex_div; COMPLEX_MUL_LID; COMPLEX_MUL_SYM]]);;
+
+let WINDING_NUMBER_POS_LT = prove
+ (`!g z e. valid_path g /\ ~(z IN path_image g) /\ &0 < e /\
+           (!x. x IN interval(vec 0,vec 1)
+                ==> e <= Im(vector_derivative g (at x) * cnj(g x - z)))
+           ==> &0 < Re(winding_number(g,z))`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `bounded (IMAGE (\w. w - z) (path_image g))` MP_TAC THENL
+   [REWRITE_TAC[path_image; GSYM IMAGE_o] THEN
+    MATCH_MP_TAC COMPACT_IMP_BOUNDED THEN
+    MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+    REWRITE_TAC[COMPACT_INTERVAL] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+    MATCH_MP_TAC PIECEWISE_DIFFERENTIABLE_ON_IMP_CONTINUOUS_ON THEN
+    ASM_REWRITE_TAC[GSYM valid_path];
+    ALL_TAC] THEN
+  REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC WINDING_NUMBER_POS_LT_LEMMA THEN
+  EXISTS_TAC `e:real / B pow 2` THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_POW_LT] THEN
+  X_GEN_TAC `x:real^1` THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[COMPLEX_DIV_CNJ] THEN
+  REWRITE_TAC[real_div; complex_div; GSYM CX_INV; GSYM CX_POW] THEN
+  REWRITE_TAC[IM_MUL_CX] THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LE_INV_EQ; REAL_POW_LE] THEN
+  MATCH_MP_TAC REAL_LE_INV2 THEN CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_POW_LT THEN REWRITE_TAC[NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    UNDISCH_TAC `~((z:complex) IN path_image g)`;
+    MATCH_MP_TAC REAL_POW_LE2 THEN REWRITE_TAC[NORM_POS_LE] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC] THEN
+  REWRITE_TAC[path_image; IN_IMAGE] THEN
+  ASM_MESON_TAC[SUBSET; INTERVAL_OPEN_SUBSET_CLOSED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The winding number is an integer (proof from Ahlfors's book).             *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_AHLFORS_LEMMA = prove
+ (`!g a b.
+        g piecewise_differentiable_on interval [a,b] /\
+        drop a <= drop b /\ (!x. x IN interval [a,b] ==> ~(g x = z))
+        ==> (\x. vector_derivative g (at x within interval[a,b]) / (g(x) - z))
+            integrable_on interval[a,b] /\
+            cexp(--(integral (interval[a,b])
+                        (\x. vector_derivative g (at x within interval[a,b]) /
+                               (g(x) - z)))) *
+            (g(b) - z) = g(a) - z`,
+  let lemma = prove
+   (`!f g g' s x z.
+          (g has_vector_derivative g') (at x within s) /\
+          (f has_vector_derivative (g' / (g x - z))) (at x within s) /\
+          ~(g x = z)
+          ==> ((\x. cexp(--f x) * (g x - z)) has_vector_derivative Cx(&0))
+              (at x within s)`,
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+     `cexp(--f x) * (g' - Cx(&0)) +
+      (cexp(--f x) * --(g' / ((g:real^1->complex) x - z))) * (g x - z) = Cx(&0)`
+     (SUBST1_TAC o SYM)
+    THENL
+     [FIRST_X_ASSUM(MP_TAC o check (is_neg o concl)) THEN
+      CONV_TAC COMPLEX_FIELD;
+      ALL_TAC] THEN
+    MATCH_MP_TAC(ISPEC `( * ):complex->complex->complex`
+      HAS_VECTOR_DERIVATIVE_BILINEAR_WITHIN) THEN
+    REWRITE_TAC[BILINEAR_COMPLEX_MUL; GSYM COMPLEX_VEC_0] THEN
+    ASM_SIMP_TAC[HAS_VECTOR_DERIVATIVE_SUB; ETA_AX;
+                 HAS_VECTOR_DERIVATIVE_CONST] THEN
+    GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+    REWRITE_TAC[has_vector_derivative] THEN
+    SUBGOAL_THEN `!x y. (\z. drop z % (x * y :complex)) =
+                        (\w. x * w) o (\z. drop z % y)`
+     (fun th -> REWRITE_TAC[th])
+    THENL
+     [REWRITE_TAC[FUN_EQ_THM; o_THM; COMPLEX_CMUL] THEN
+      SIMPLE_COMPLEX_ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC DIFF_CHAIN_WITHIN THEN
+    REWRITE_TAC[GSYM has_complex_derivative; GSYM has_vector_derivative] THEN
+    SIMP_TAC[HAS_COMPLEX_DERIVATIVE_CEXP; HAS_COMPLEX_DERIVATIVE_AT_WITHIN] THEN
+    ASM_SIMP_TAC[HAS_VECTOR_DERIVATIVE_NEG]) in
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!w. ~(w = z)
+        ==> ?h. !y. norm(y - w) < norm(w - z)
+                    ==> (h has_complex_derivative inv(y - z)) (at y)`
+   (LABEL_TAC "P")
+  THENL
+   [REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`\w:complex. inv(w - z)`;
+               `ball(w:complex,norm(w - z))`;
+               `{}:complex->bool`]
+              HOLOMORPHIC_CONVEX_PRIMITIVE) THEN
+    SIMP_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN; OPEN_BALL; INTERIOR_OPEN] THEN
+    REWRITE_TAC[CONVEX_BALL; FINITE_RULES; DIFF_EMPTY] THEN ANTS_TAC THENL
+     [SUBGOAL_THEN `(\w. inv(w - z)) holomorphic_on ball(w:complex,norm(w - z))`
+       (fun th ->
+        MESON_TAC[HOLOMORPHIC_ON_OPEN; HOLOMORPHIC_ON_IMP_CONTINUOUS_ON;
+                  OPEN_BALL; complex_differentiable; th]) THEN
+      SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL; IN_BALL] THEN
+      X_GEN_TAC `u:complex` THEN DISCH_TAC THEN
+      EXISTS_TAC `--Cx(&1) / (u - z) pow 2` THEN COMPLEX_DIFF_TAC THEN
+      REWRITE_TAC[COMPLEX_SUB_RZERO; COMPLEX_SUB_0] THEN
+      ASM_MESON_TAC[REAL_LT_REFL; dist];
+      ALL_TAC] THEN
+    REWRITE_TAC[IN_BALL; dist] THEN MESON_TAC[NORM_SUB];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!t. t IN interval[a,b]
+        ==> (\x. vector_derivative g (at x within interval[a,b]) / (g(x) - z))
+            integrable_on interval[a,t] /\
+            cexp(--(integral (interval[a,t])
+                         (\x. vector_derivative g (at x within interval[a,b]) /
+                              (g(x) - z)))) *
+            (g(t) - z) = g(a) - z`
+   (fun th -> MATCH_MP_TAC th THEN
+              ASM_REWRITE_TAC[IN_INTERVAL_1; REAL_LE_REFL]) THEN
+  REWRITE_TAC[TAUT `a ==> b /\ c <=> (a ==> b) /\ (a ==> c)`] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_SUBINTERVAL THEN
+    MAP_EVERY EXISTS_TAC [`a:real^1`; `b:real^1`] THEN
+    ASM_REWRITE_TAC[SUBSET_INTERVAL_1; REAL_LE_REFL] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[IN_INTERVAL_1]] THEN
+    REWRITE_TAC[integrable_on; complex_div] THEN
+    ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+    REWRITE_TAC[HAS_INTEGRAL_LOCALIZED_VECTOR_DERIVATIVE] THEN
+    REWRITE_TAC[GSYM integrable_on] THEN
+    MATCH_MP_TAC PATH_INTEGRAL_LOCAL_PRIMITIVE_ANY THEN
+    EXISTS_TAC `(:complex) DELETE z` THEN
+    ASM_SIMP_TAC[IN_DELETE; IN_UNIV;
+                 DIFFERENTIABLE_ON_IMP_PIECEWISE_DIFFERENTIABLE] THEN
+    X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+    EXISTS_TAC `norm(w - z:complex)` THEN
+    ASM_REWRITE_TAC[COMPLEX_NORM_NZ; COMPLEX_SUB_0] THEN
+    ASM_MESON_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN];
+    ALL_TAC] THEN
+  DISCH_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_INTERVAL THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [piecewise_differentiable_on]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[IN_DIFF; FINITE_IMP_COUNTABLE] THEN
+  X_GEN_TAC `k:real^1->bool` THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[CONVEX_INTERVAL; INTEGRAL_REFL] THEN
+  REWRITE_TAC[COMPLEX_VEC_0; COMPLEX_NEG_0; CEXP_0; COMPLEX_MUL_LID] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; ETA_AX;
+                 PIECEWISE_DIFFERENTIABLE_ON_IMP_CONTINUOUS_ON] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    REWRITE_TAC[CONTINUOUS_ON_CEXP] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_NEG THEN
+    MATCH_MP_TAC INDEFINITE_INTEGRAL_CONTINUOUS_RIGHT THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; REAL_LE_REFL];
+    ALL_TAC] THEN
+  X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`\w:complex. inv(w - z)`;
+                 `ball((g:real^1->complex) t,dist(g t,z))`;
+                 `{}:complex->bool`]
+                HOLOMORPHIC_CONVEX_PRIMITIVE) THEN
+  SIMP_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN; OPEN_BALL; INTERIOR_OPEN] THEN
+  REWRITE_TAC[CONVEX_BALL; FINITE_RULES; DIFF_EMPTY] THEN ANTS_TAC THENL
+   [SUBGOAL_THEN `(\w. inv(w - z)) holomorphic_on ball(g(t:real^1),dist(g t,z))`
+     (fun th ->
+      MESON_TAC[HOLOMORPHIC_ON_OPEN; HOLOMORPHIC_ON_IMP_CONTINUOUS_ON;
+                OPEN_BALL; complex_differentiable; th]) THEN
+    SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL; IN_BALL] THEN
+    X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+    EXISTS_TAC `--Cx(&1) / (w - z) pow 2` THEN COMPLEX_DIFF_TAC THEN
+    REWRITE_TAC[COMPLEX_SUB_RZERO; COMPLEX_SUB_0] THEN
+    ASM_MESON_TAC[REAL_LT_REFL];
+    ALL_TAC] THEN
+  REWRITE_TAC[IN_BALL; dist] THEN
+  DISCH_THEN(X_CHOOSE_TAC `h:complex->complex`) THEN
+  SUBGOAL_THEN `(\h. Cx(&0)) = (\h. drop h % Cx(&0))` SUBST1_TAC THENL
+   [REWRITE_TAC[FUN_EQ_THM; GSYM COMPLEX_VEC_0; VECTOR_MUL_RZERO];
+    ALL_TAC] THEN
+  REWRITE_TAC[GSYM has_vector_derivative] THEN MATCH_MP_TAC lemma THEN
+  EXISTS_TAC `vector_derivative g (at t within interval[a,b]):complex` THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[GSYM VECTOR_DERIVATIVE_WORKS] THEN
+    ASM_MESON_TAC[DIFFERENTIABLE_AT_WITHIN];
+    ALL_TAC;
+    ASM_MESON_TAC[]] THEN
+  REWRITE_TAC[has_vector_derivative] THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_TRANSFORM_WITHIN THEN
+  ASM_REWRITE_TAC[GSYM has_vector_derivative] THEN
+  EXISTS_TAC `\u. integral (interval [a,t])
+                  (\x. vector_derivative g (at x within interval [a,b]) /
+                       ((g:real^1->complex) x - z)) + (h(g(u)) - h(g(t)))` THEN
+  REWRITE_TAC[LEFT_EXISTS_AND_THM; CONJ_ASSOC] THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[COMPLEX_RING `a + (b - c) = b + (a - c):complex`] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_ADD_RID] THEN
+    MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_ADD THEN
+    REWRITE_TAC[HAS_VECTOR_DERIVATIVE_CONST] THEN
+    REWRITE_TAC[has_vector_derivative] THEN
+    SUBGOAL_THEN `!x y. (\h. drop h % x / y) =
+                        (\x. inv(y) * x) o (\h. drop h % x)`
+     (fun th -> REWRITE_TAC[th])
+    THENL
+     [REWRITE_TAC[FUN_EQ_THM; o_THM; COMPLEX_CMUL] THEN
+      SIMPLE_COMPLEX_ARITH_TAC;
+      ALL_TAC] THEN
+    GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+    MATCH_MP_TAC DIFF_CHAIN_WITHIN THEN
+    REWRITE_TAC[GSYM has_complex_derivative; GSYM has_vector_derivative] THEN
+    REWRITE_TAC[GSYM VECTOR_DERIVATIVE_WORKS] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[DIFFERENTIABLE_AT_WITHIN]; ALL_TAC] THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_AT_WITHIN THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[COMPLEX_SUB_REFL; COMPLEX_NORM_0; COMPLEX_NORM_NZ] THEN
+    ASM_SIMP_TAC[COMPLEX_SUB_0]] THEN
+  SUBGOAL_THEN
+   `?d. &0 < d /\
+        !y:real^1. y IN interval[a,b] /\ dist(y,t) < d
+                   ==> dist(g y:complex,g t) < norm(g t - z) /\ ~(y IN k)`
+  MP_TAC THENL
+   [SUBGOAL_THEN `(g:real^1->complex) continuous (at t within interval[a,b])`
+    MP_TAC THENL
+     [ASM_MESON_TAC[PIECEWISE_DIFFERENTIABLE_ON_IMP_CONTINUOUS_ON;
+                    CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN];
+      ALL_TAC] THEN
+    REWRITE_TAC[continuous_within] THEN
+    DISCH_THEN(MP_TAC o SPEC `norm((g:real^1->complex) t - z)`) THEN
+    ASM_SIMP_TAC[COMPLEX_NORM_NZ; COMPLEX_SUB_0] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(X_CHOOSE_THEN `d2:real` STRIP_ASSUME_TAC o
+      SPEC `t:real^1` o MATCH_MP FINITE_SET_AVOID) THEN
+    EXISTS_TAC `min d1 d2` THEN ASM_SIMP_TAC[REAL_LT_MIN] THEN
+    ASM_MESON_TAC[DIST_SYM; REAL_NOT_LE];
+    ALL_TAC] THEN
+  REWRITE_TAC[TAUT `a ==> b /\ c <=> (a ==> b) /\ (a ==> c)`] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `u:real^1` THEN REWRITE_TAC[dist] THEN
+  STRIP_TAC THEN
+  DISJ_CASES_TAC(REAL_ARITH `drop t <= drop u \/ drop u <= drop t`) THENL
+   [SUBGOAL_THEN
+     `integral (interval [a,u])
+        (\x. vector_derivative g (at x within interval [a,b]) / (g x - z)) =
+      integral (interval [a,t])
+        (\x. vector_derivative g (at x within interval [a,b]) / (g x - z)) +
+      integral (interval [t,u])
+        (\x. vector_derivative g (at x within interval [a,b]) / (g x - z))`
+    SUBST1_TAC THENL
+     [CONV_TAC SYM_CONV THEN MATCH_MP_TAC INTEGRAL_COMBINE THEN
+      ASM_MESON_TAC[IN_INTERVAL_1];
+      ALL_TAC] THEN
+    SIMP_TAC[COMPLEX_RING `a + x = a + y <=> y:complex = x`];
+    SUBGOAL_THEN
+     `integral (interval [a,t])
+        (\x. vector_derivative g (at x within interval [a,b]) / (g x - z)) =
+      integral (interval [a,u])
+        (\x. vector_derivative g (at x within interval [a,b]) / (g x - z)) +
+      integral (interval [u,t])
+        (\x. vector_derivative g (at x within interval [a,b]) / (g x - z))`
+    SUBST1_TAC THENL
+     [CONV_TAC SYM_CONV THEN MATCH_MP_TAC INTEGRAL_COMBINE THEN
+      ASM_MESON_TAC[IN_INTERVAL_1];
+      ALL_TAC] THEN
+    SIMP_TAC[COMPLEX_RING `(a + x) + (w - z) = a <=> x:complex = z - w`]] THEN
+  (MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+   MATCH_MP_TAC FUNDAMENTAL_THEOREM_OF_CALCULUS THEN
+   ASM_REWRITE_TAC[GSYM o_DEF] THEN X_GEN_TAC `x:real^1` THEN
+   REPEAT STRIP_TAC THEN REWRITE_TAC[has_vector_derivative; COMPLEX_CMUL] THEN
+   SUBGOAL_THEN `!x y. (\h. Cx(drop h) * x / y) =
+                       (\x. inv(y) * x) o (\h. drop h % x)`
+    (fun th -> REWRITE_TAC[th])
+   THENL
+    [REWRITE_TAC[FUN_EQ_THM; o_THM; COMPLEX_CMUL] THEN
+     SIMPLE_COMPLEX_ARITH_TAC;
+     ALL_TAC] THEN
+   MATCH_MP_TAC DIFF_CHAIN_WITHIN THEN
+   REWRITE_TAC[GSYM has_complex_derivative; GSYM has_vector_derivative] THEN
+   CONJ_TAC THENL
+    [MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_WITHIN_SUBSET THEN
+     EXISTS_TAC `interval[a:real^1,b]` THEN
+     REWRITE_TAC[GSYM VECTOR_DERIVATIVE_WORKS] THEN CONJ_TAC THENL
+      [MATCH_MP_TAC DIFFERENTIABLE_AT_WITHIN THEN
+       FIRST_X_ASSUM MATCH_MP_TAC THEN CONJ_TAC THENL
+        [ALL_TAC; FIRST_X_ASSUM MATCH_MP_TAC];
+       ALL_TAC] THEN
+     REPEAT(FIRST_X_ASSUM(MP_TAC o
+        check (fun t -> not(is_forall (concl t))))) THEN
+     REWRITE_TAC[dist; NORM_REAL; GSYM drop; DROP_SUB] THEN
+     REWRITE_TAC[SUBSET_INTERVAL_1; IN_INTERVAL_1; REAL_LE_REFL] THEN
+     REAL_ARITH_TAC;
+     ALL_TAC] THEN
+   MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_AT_WITHIN THEN
+   FIRST_X_ASSUM MATCH_MP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM dist] THEN
+   ONCE_REWRITE_TAC[DIST_SYM] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+   CONJ_TAC THENL [ASM_MESON_TAC[IN_INTERVAL_1; REAL_LE_TRANS]; ALL_TAC] THEN
+   REPEAT(FIRST_X_ASSUM(MP_TAC o
+      check (fun t -> not(is_forall (concl t))))) THEN
+   REWRITE_TAC[dist; NORM_REAL; GSYM drop; DROP_SUB] THEN
+   REWRITE_TAC[SUBSET_INTERVAL_1; IN_INTERVAL_1; REAL_LE_REFL] THEN
+   REAL_ARITH_TAC));;
+
+let WINDING_NUMBER_AHLFORS = prove
+ (`!g z a b.
+        g piecewise_differentiable_on interval [a,b] /\
+        drop a <= drop b /\ (!x. x IN interval [a,b] ==> ~(g x = z))
+        ==> (\x. vector_derivative g (at x) / (g(x) - z))
+            integrable_on interval[a,b] /\
+            cexp(--(integral (interval[a,b])
+                             (\x. vector_derivative g (at x) / (g(x) - z)))) *
+            (g(b) - z) = g(a) - z`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  REWRITE_TAC[integrable_on; integral] THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[COMPLEX_MUL_SYM] complex_div] THEN
+  REWRITE_TAC[GSYM HAS_INTEGRAL_LOCALIZED_VECTOR_DERIVATIVE] THEN
+  ONCE_REWRITE_TAC[ONCE_REWRITE_RULE[COMPLEX_MUL_SYM](GSYM complex_div)] THEN
+  REWRITE_TAC[GSYM integral; GSYM integrable_on] THEN
+  MATCH_MP_TAC WINDING_NUMBER_AHLFORS_LEMMA THEN ASM_REWRITE_TAC[]);;
+
+let WINDING_NUMBER_AHLFORS_FULL = prove
+ (`!p z. path p /\ ~(z IN path_image p)
+         ==> pathfinish p - z =
+             cexp(Cx(&2) * Cx pi * ii * winding_number(p,z)) *
+             (pathstart p - z)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`p:real^1->complex`; `z:complex`; `&1`] WINDING_NUMBER) THEN
+  ASM_REWRITE_TAC[REAL_LT_01; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `g:real^1->complex` THEN STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(SUBST_ALL_TAC o SYM)) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[valid_path; path_image; IN_IMAGE;
+        NOT_EXISTS_THM]) THEN
+  MP_TAC(ISPECL
+   [`g:real^1->complex`; `z:complex`; `vec 0:real^1`; `vec 1:real^1`]
+   WINDING_NUMBER_AHLFORS) THEN
+  ASM_SIMP_TAC[DROP_VEC; REAL_POS; pathstart; pathfinish] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[]; DISCH_THEN(SUBST1_TAC o SYM o CONJUNCT2)] THEN
+  REWRITE_TAC[GSYM CEXP_ADD; COMPLEX_MUL_ASSOC; PATH_INTEGRAL_INTEGRAL] THEN
+  REWRITE_TAC[SIMPLE_COMPLEX_ARITH `Cx(&1) / z * w = w / z`] THEN
+  REWRITE_TAC[GSYM complex_sub; COMPLEX_SUB_REFL; CEXP_0; COMPLEX_MUL_LID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* State in terms of complex integers. Note the useful equality version.     *)
+(* ------------------------------------------------------------------------- *)
+
+let complex_integer = new_definition
+ `complex_integer z <=> integer(Re z) /\ Im z = &0`;;
+
+let COMPLEX_INTEGER = prove
+ (`complex_integer z <=> ?n. integer n /\ z = Cx n`,
+  REWRITE_TAC[COMPLEX_EQ; RE_CX; IM_CX; complex_integer] THEN MESON_TAC[]);;
+
+let INTEGER_WINDING_NUMBER_EQ = prove
+ (`!g z. path g /\ ~(z IN path_image g)
+         ==> (complex_integer(winding_number(g,z)) <=>
+              pathfinish g = pathstart g)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `(:complex) DIFF path_image g` OPEN_CONTAINS_BALL) THEN
+  ASM_SIMP_TAC[GSYM closed; CLOSED_PATH_IMAGE; VALID_PATH_IMP_PATH] THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; SUBSET; IN_BALL] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`; `e:real`]
+    WINDING_NUMBER) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:real^1->complex` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `complex_integer(winding_number(p,z)) <=>
+    pathfinish p = pathstart p`
+  MP_TAC THENL
+   [UNDISCH_THEN
+     `path_integral p (\w. Cx (&1) / (w - z)) =
+      Cx (&2) * Cx pi * ii * winding_number (g,z)` (K ALL_TAC) THEN
+    ASM_SIMP_TAC[WINDING_NUMBER_VALID_PATH];
+    ASM_SIMP_TAC[WINDING_NUMBER_VALID_PATH; CX_2PII_NZ; COMPLEX_FIELD
+     `~(a * b * c = Cx(&0))
+      ==> Cx(&1) / (a * b * c) * a * b * c * z = z`]] THEN
+  UNDISCH_THEN `pathstart p:complex = pathstart g` (SUBST_ALL_TAC o SYM) THEN
+  UNDISCH_THEN `pathfinish p:complex = pathfinish g` (SUBST_ALL_TAC o SYM) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[valid_path; path_image]) THEN
+  REWRITE_TAC[pathfinish; pathstart] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `cexp(path_integral p (\w. Cx(&1) / (w - z))) = Cx(&1)` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[CEXP_EQ_1; complex_integer] THEN
+    REWRITE_TAC[complex_div; COMPLEX_MUL_LID; COMPLEX_INV_MUL] THEN
+    SIMP_TAC[GSYM CX_INV; GSYM CX_MUL; COMPLEX_MUL_ASSOC; COMPLEX_INV_II] THEN
+    REWRITE_TAC[RE_MUL_CX; IM_MUL_CX; GSYM COMPLEX_MUL_ASSOC] THEN
+    REWRITE_TAC[COMPLEX_MUL_LNEG; RE_MUL_II; IM_MUL_II; RE_NEG; IM_NEG] THEN
+    REWRITE_TAC[REAL_NEGNEG; REAL_ENTIRE; REAL_INV_EQ_0; REAL_NEG_EQ_0] THEN
+    SIMP_TAC[REAL_OF_NUM_EQ; ARITH; REAL_LT_IMP_NZ; PI_POS] THEN
+    SIMP_TAC[PI_POS; REAL_FIELD
+     `&0 < p ==> (x = &2 * n * p <=> (inv(&2) * inv(p)) * x = n)`] THEN
+    MESON_TAC[];
+    MP_TAC(ISPECL [`p:real^1->complex`; `z:complex`;
+                   `vec 0:real^1`; `vec 1:real^1`]
+                  WINDING_NUMBER_AHLFORS) THEN
+    ASM_REWRITE_TAC[DROP_VEC; REAL_POS] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+    REWRITE_TAC[ONCE_REWRITE_RULE[COMPLEX_MUL_SYM] complex_div] THEN
+    REWRITE_TAC[integral; GSYM HAS_INTEGRAL_LOCALIZED_VECTOR_DERIVATIVE] THEN
+    REWRITE_TAC[GSYM has_path_integral; GSYM path_integral] THEN
+    REWRITE_TAC[CEXP_NEG; COMPLEX_MUL_RID] THEN
+    MATCH_MP_TAC(COMPLEX_FIELD
+     `~(i = Cx(&0)) /\ ~(g0 = z)
+      ==> (inv i * (g1 - z) = g0 - z ==> (i = Cx(&1) <=> g1 = g0))`) THEN
+    REWRITE_TAC[CEXP_NZ] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [IN_IMAGE]) THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN MESON_TAC[REAL_POS; DROP_VEC]]);;
+
+let INTEGER_WINDING_NUMBER = prove
+ (`!g z. path g /\ pathfinish g = pathstart g /\ ~(z IN path_image g)
+         ==> complex_integer(winding_number(g,z))`,
+  MESON_TAC[INTEGER_WINDING_NUMBER_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* For |WN| >= 1 the path must contain points in every direction.            *)
+(* We can thus bound the WN of a path that doesn't meet some "cut".          *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_POS_MEETS = prove
+ (`!g z. valid_path g /\ ~(z IN path_image g) /\
+         Re(winding_number(g,z)) >= &1
+         ==> !w. ~(w = z)
+                 ==> ?a. &0 < a /\ z + (Cx a * (w - z)) IN path_image g`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!t. t IN interval[vec 0,vec 1] ==> ~((g:real^1->complex) t = z)`
+  ASSUME_TAC THENL
+   [UNDISCH_TAC `~((z:complex) IN path_image g)` THEN
+    REWRITE_TAC[path_image; IN_IMAGE] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  ABBREV_TAC `r:complex = (w - z) / (pathstart g - z)` THEN
+  STRIP_ASSUME_TAC(GSYM(SPEC `r:complex` ARG)) THEN
+  SUBGOAL_THEN
+   `?t. t IN interval[vec 0,vec 1] /\
+        Im(integral (interval[vec 0,t])
+                    (\x. vector_derivative g (at x) / (g x - z))) = Arg r`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[IM_DEF] THEN MATCH_MP_TAC IVT_INCREASING_COMPONENT_ON_1 THEN
+    ASM_SIMP_TAC[DIMINDEX_2; DROP_VEC; ARITH; INTEGRAL_REFL; REAL_POS;
+                 VEC_COMPONENT] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC INDEFINITE_INTEGRAL_CONTINUOUS_RIGHT THEN
+      REWRITE_TAC[ONCE_REWRITE_RULE[COMPLEX_MUL_SYM] complex_div] THEN
+      REWRITE_TAC[GSYM PATH_INTEGRABLE_ON] THEN
+      REWRITE_TAC[SIMPLE_COMPLEX_ARITH `inv z = Cx(&1) / z`] THEN
+      MATCH_MP_TAC PATH_INTEGRABLE_INVERSEDIFF THEN ASM_REWRITE_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `&2 * pi` THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+    UNDISCH_TAC `Re(winding_number (g,z)) >= &1` THEN
+    ASM_SIMP_TAC[WINDING_NUMBER_VALID_PATH; GSYM IM_DEF] THEN
+    REWRITE_TAC[path_integral; HAS_PATH_INTEGRAL; GSYM integral] THEN
+    SUBST1_TAC(COMPLEX_FIELD `ii = --inv ii`) THEN
+    REWRITE_TAC[complex_div; COMPLEX_INV_MUL; COMPLEX_INV_NEG] THEN
+    REWRITE_TAC[GSYM CX_INV; GSYM CX_MUL; COMPLEX_MUL_ASSOC] THEN
+    REWRITE_TAC[RE_MUL_CX; RE; COMPLEX_MUL_RNEG; RE_NEG; COMPLEX_MUL_LNEG;
+                COMPLEX_INV_INV; GSYM COMPLEX_MUL_ASSOC; RE_MUL_II] THEN
+    REWRITE_TAC[REAL_MUL_RNEG; REAL_NEGNEG] THEN
+    SIMP_TAC[REAL_ARITH `((&1 * inv(&2)) * p) * x >= &1 <=> &2 <= x * p`] THEN
+    SIMP_TAC[GSYM real_div; REAL_LE_RDIV_EQ; PI_POS] THEN
+    REWRITE_TAC[COMPLEX_MUL_LID; COMPLEX_MUL_AC];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`g:real^1->complex`; `z:complex`; `vec 0:real^1`; `t:real^1`]
+   WINDING_NUMBER_AHLFORS) THEN
+  ANTS_TAC THENL
+   [REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC PIECEWISE_DIFFERENTIABLE_ON_SUBSET THEN
+      EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[valid_path]) THEN ASM_REWRITE_TAC[];
+      ALL_TAC;
+      GEN_TAC THEN
+      DISCH_THEN(fun th -> FIRST_ASSUM MATCH_MP_TAC THEN MP_TAC th)] THEN
+    UNDISCH_TAC `(t:real^1) IN interval[vec 0,vec 1]` THEN
+    REWRITE_TAC[SUBSET; IN_INTERVAL_1; DROP_VEC] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o CONJUNCT2) THEN REWRITE_TAC[CEXP_NEG] THEN
+  ABBREV_TAC `i = integral (interval [vec 0,t])
+    (\x. vector_derivative g (at x) / (g x - z))` THEN
+  SUBST1_TAC(SPEC `i:complex` COMPLEX_EXPAND) THEN
+  ASM_REWRITE_TAC[CEXP_ADD; COMPLEX_INV_MUL; GSYM CX_EXP] THEN
+  UNDISCH_TAC `Cx(norm r) * cexp(ii * Cx(Arg r)) = r` THEN
+  REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP (COMPLEX_FIELD
+   `x * e = r /\ (y * inv e) * w = z
+    ==> ~(e = Cx(&0)) ==> x * y * w = r * z`)) THEN
+  REWRITE_TAC[CEXP_NZ] THEN
+  EXPAND_TAC "r" THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o ONCE_DEPTH_CONV) [pathstart] THEN
+  SUBGOAL_THEN `~((g:real^1->complex)(vec 0) = z)` ASSUME_TAC THENL
+   [FIRST_ASSUM MATCH_MP_TAC THEN SIMP_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[COMPLEX_DIV_RMUL; COMPLEX_SUB_0; GSYM CX_INV; GSYM CX_MUL;
+               COMPLEX_MUL_ASSOC; GSYM real_div] THEN
+  DISCH_TAC THEN
+  EXISTS_TAC `exp(Re i) / norm(r:complex)` THEN
+  SUBGOAL_THEN `~(r = Cx(&0))` ASSUME_TAC THENL
+   [EXPAND_TAC "r" THEN MATCH_MP_TAC(COMPLEX_FIELD
+   `~(x = Cx(&0)) /\ ~(y = Cx(&0)) ==> ~(x / y = Cx(&0))`) THEN
+    ASM_REWRITE_TAC[COMPLEX_SUB_0; pathstart];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_EXP_POS_LT; COMPLEX_NORM_NZ] THEN
+  REWRITE_TAC[path_image; IN_IMAGE] THEN
+  EXISTS_TAC `t:real^1` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(COMPLEX_FIELD
+   `inv i * (gt - z) = wz /\ ~(i = Cx(&0)) ==> z + i * wz = gt`) THEN
+  ASM_REWRITE_TAC[GSYM CX_INV; REAL_INV_DIV; CX_INJ] THEN
+  MATCH_MP_TAC(REAL_FIELD `~(x = &0) /\ ~(y = &0) ==> ~(x / y = &0)`) THEN
+  ASM_REWRITE_TAC[REAL_EXP_NZ; COMPLEX_NORM_ZERO]);;
+
+let WINDING_NUMBER_BIG_MEETS = prove
+ (`!g z. valid_path g /\ ~(z IN path_image g) /\
+         abs(Re(winding_number(g,z))) >= &1
+         ==> !w. ~(w = z)
+                 ==> ?a. &0 < a /\ z + (Cx a * (w - z)) IN path_image g`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_abs] THEN COND_CASES_TAC THEN
+  ASM_SIMP_TAC[WINDING_NUMBER_POS_MEETS] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ASM_SIMP_TAC[GSYM RE_NEG; VALID_PATH_IMP_PATH;
+               GSYM WINDING_NUMBER_REVERSEPATH] THEN
+  DISCH_TAC THEN ONCE_REWRITE_TAC[GSYM PATH_IMAGE_REVERSEPATH] THEN
+  MATCH_MP_TAC WINDING_NUMBER_POS_MEETS THEN
+  ASM_SIMP_TAC[PATH_IMAGE_REVERSEPATH; VALID_PATH_REVERSEPATH]);;
+
+let WINDING_NUMBER_LT_1 = prove
+ (`!g w z. valid_path g /\ ~(z IN path_image g) /\ ~(w = z) /\
+           (!a. &0 < a ==> ~(z + (Cx a * (w - z)) IN path_image g))
+           ==> Re(winding_number(g,z)) < &1`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[GSYM REAL_NOT_LE; GSYM real_ge] THEN
+  ASM_MESON_TAC[WINDING_NUMBER_POS_MEETS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* One way of proving that WN=1 for a loop.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_EQ_1 = prove
+ (`!g z. valid_path g /\ ~(z IN path_image g) /\ pathfinish g = pathstart g /\
+         &0 < Re(winding_number(g,z)) /\ Re(winding_number(g,z)) < &2
+         ==> winding_number(g,z) = Cx(&1)`,
+  REPEAT GEN_TAC THEN
+  REPLICATE_TAC 3 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  SUBGOAL_THEN `complex_integer(winding_number(g,z))` MP_TAC THENL
+   [ASM_SIMP_TAC[INTEGER_WINDING_NUMBER; VALID_PATH_IMP_PATH]; ALL_TAC] THEN
+  SIMP_TAC[complex_integer; COMPLEX_EQ; RE_CX; IM_CX] THEN
+  SIMP_TAC[REAL_LT_INTEGERS; INTEGER_CLOSED] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Continuity of winding number and invariance on connected sets.            *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_AT_WINDING_NUMBER = prove
+ (`!g z. path g /\ ~(z IN path_image g)
+         ==> (\w. winding_number(g,w)) continuous (at z)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `(:complex) DIFF path_image g` OPEN_CONTAINS_CBALL) THEN
+  ASM_SIMP_TAC[GSYM closed; CLOSED_PATH_IMAGE] THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; SUBSET; IN_CBALL] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`(:complex) DIFF cball(z,e / &2)`; `g:real^1->complex`]
+        PATH_INTEGRAL_NEARBY_ENDS) THEN
+  ASM_SIMP_TAC[OPEN_DIFF; OPEN_UNIV; CLOSED_CBALL] THEN ANTS_TAC THENL
+   [REWRITE_TAC[SUBSET; IN_DIFF; IN_CBALL; SUBSET; IN_UNIV] THEN
+    GEN_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[] THEN DISCH_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`; `min d e / &2`]
+    WINDING_NUMBER) THEN
+  ASM_REWRITE_TAC[REAL_HALF; REAL_LT_MIN] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:real^1->complex` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC CONTINUOUS_TRANSFORM_AT THEN
+  MAP_EVERY EXISTS_TAC [`\w. winding_number(p,w)`; `min d e / &2`] THEN
+  ASM_REWRITE_TAC[REAL_HALF; REAL_LT_MIN] THEN CONJ_TAC THENL
+   [X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+    MATCH_MP_TAC WINDING_NUMBER_UNIQUE THEN
+    ASM_SIMP_TAC[VALID_PATH_IMP_PATH] THEN
+    MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+     [REWRITE_TAC[path_image; IN_IMAGE] THEN
+      DISCH_THEN(X_CHOOSE_THEN `t:real^1` STRIP_ASSUME_TAC) THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `(g:real^1->complex) t`) THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `t:real^1`) THEN
+      ASM_SIMP_TAC[path_image; FUN_IN_IMAGE] THEN
+      UNDISCH_TAC `dist (w:complex,z) < min d e / &2` THEN
+      ASM_REWRITE_TAC[] THEN CONV_TAC NORM_ARITH;
+      DISCH_TAC THEN X_GEN_TAC `k:real` THEN DISCH_TAC THEN
+      MP_TAC(ISPECL [`g:real^1->complex`; `w:complex`; `min k (min d e) / &2`]
+         WINDING_NUMBER) THEN
+      ASM_REWRITE_TAC[REAL_HALF; REAL_LT_MIN] THEN ANTS_TAC THENL
+       [FIRST_X_ASSUM MATCH_MP_TAC THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+        ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      DISCH_THEN(X_CHOOSE_THEN `q:real^1->complex` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `p:real^1->complex` THEN ASM_REWRITE_TAC[] THEN
+      ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+      FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [SYM th]) THEN
+      CONV_TAC SYM_CONV THEN FIRST_X_ASSUM(MP_TAC o SPECL
+        [`p:real^1->complex`; `q:real^1->complex`]) THEN
+      ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+       [X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+        REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `t:real^1`)) THEN
+        ASM_REWRITE_TAC[] THEN CONV_TAC NORM_ARITH;
+        DISCH_THEN(MATCH_MP_TAC o last o CONJUNCTS)] THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+      SIMP_TAC[HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_ID; HOLOMORPHIC_ON_CONST;
+               IN_DELETE; IN_UNIV; COMPLEX_SUB_0] THEN
+      ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN SIMP_TAC[IN_DIFF] THEN
+      REWRITE_TAC[IN_UNIV; IN_CBALL] THEN
+      ONCE_REWRITE_TAC[DIST_SYM] THEN ASM_REAL_ARITH_TAC];
+    UNDISCH_TAC `~((z:complex) IN path_image p)` THEN
+    UNDISCH_TAC `valid_path(p:real^1->complex)` THEN
+    POP_ASSUM_LIST(K ALL_TAC) THEN SPEC_TAC(`z:complex`,`z:complex`) THEN
+    SPEC_TAC(`p:real^1->complex`,`g:real^1->complex`)] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `(:complex) DIFF path_image g` OPEN_CONTAINS_BALL) THEN
+  ASM_SIMP_TAC[GSYM closed; CLOSED_PATH_IMAGE; VALID_PATH_IMP_PATH] THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; SUBSET; IN_BALL] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`(:complex) DIFF cball(z, &3 / &4 * d)`; `g:real^1->complex`]
+        PATH_INTEGRAL_BOUND_EXISTS) THEN
+  ASM_REWRITE_TAC[GSYM closed; CLOSED_CBALL; SUBSET; IN_DIFF;
+                  IN_CBALL; IN_UNIV; REAL_NOT_LE] THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[REAL_ARITH `&0 < d /\ ~(&3 / &4 * d < x) ==> x < d`];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `L:real` STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[continuous_at] THEN X_GEN_TAC `e:real` THEN STRIP_TAC THEN
+  EXISTS_TAC `min (d / &4) (e / &2 * d pow 2 / L / &4)` THEN
+  ASM_SIMP_TAC[REAL_LT_MIN; REAL_POW_LT; REAL_LT_DIV; REAL_LT_MUL; REAL_HALF;
+               REAL_ARITH `&0 < x / &4 <=> &0 < x`] THEN
+  X_GEN_TAC `w:complex` THEN STRIP_TAC THEN
+  SUBGOAL_THEN `~((w:complex) IN path_image g)` ASSUME_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[dist; WINDING_NUMBER_VALID_PATH; GSYM COMPLEX_SUB_LDISTRIB] THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_DIV; COMPLEX_NORM_CX] THEN
+  REWRITE_TAC[REAL_ABS_NUM; COMPLEX_NORM_II; REAL_ABS_PI] THEN
+  REWRITE_TAC[real_div; REAL_MUL_LID; REAL_MUL_RID] THEN
+  MATCH_MP_TAC(REAL_ARITH
+    `inv p * x <= &1 * x /\ x < e ==> inv p * x < e`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+    MATCH_MP_TAC REAL_INV_LE_1 THEN MP_TAC PI_APPROX_32 THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH `!d. &0 < e /\ d = e / &2 /\ x <= d ==> x < e`) THEN
+  EXISTS_TAC `L * (e / &2 * d pow 2 / L / &4) * inv(d / &2) pow 2` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MAP_EVERY UNDISCH_TAC [`&0 < d`; `&0 < L`] THEN CONV_TAC REAL_FIELD;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `path_integral g (\x. Cx(&1) / (x - w)) -
+    path_integral g (\x. Cx(&1) / (x - z)) =
+    path_integral g (\x. Cx(&1) / (x - w) - Cx(&1) / (x - z))`
+  SUBST1_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC PATH_INTEGRAL_SUB THEN
+    CONJ_TAC THEN MATCH_MP_TAC PATH_INTEGRABLE_INVERSEDIFF THEN
+    ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ONCE_REWRITE_TAC[DIST_SYM] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  SIMP_TAC[HOLOMORPHIC_ON_OPEN; GSYM closed; CLOSED_CBALL] THEN
+  REWRITE_TAC[IN_UNIV; IN_DIFF; IN_CBALL; REAL_NOT_LE; AND_FORALL_THM] THEN
+  X_GEN_TAC `x:complex` THEN
+  REWRITE_TAC[TAUT `(a ==> b) /\ (a ==> c) <=> a ==> b /\ c`] THEN
+  DISCH_TAC THEN REWRITE_TAC[GSYM complex_differentiable] THEN
+  SUBGOAL_THEN `~(x:complex = w) /\ ~(x = z)` STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN DISCH_THEN SUBST_ALL_TAC THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM REAL_NOT_LE])) THEN
+    CONV_TAC NORM_ARITH;
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_SUB THEN
+    CONJ_TAC THEN MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_DIV_AT THEN
+    ASM_SIMP_TAC[COMPLEX_SUB_0; COMPLEX_DIFFERENTIABLE_SUB;
+                 COMPLEX_DIFFERENTIABLE_ID; COMPLEX_DIFFERENTIABLE_CONST];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[COMPLEX_FIELD
+   `~(x = w) /\ ~(x = z)
+    ==> Cx(&1) / (x - w) - Cx(&1) / (x - z) =
+        (w - z) * inv((x - w) * (x - z))`] THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL] THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+  ASM_SIMP_TAC[NORM_POS_LE; GSYM dist; REAL_LT_IMP_LE] THEN
+  REWRITE_TAC[COMPLEX_NORM_INV; REAL_POW_INV] THEN
+  MATCH_MP_TAC REAL_LE_INV2 THEN
+  ASM_SIMP_TAC[REAL_POW_2; REAL_LT_MUL; REAL_HALF; COMPLEX_NORM_MUL] THEN
+  MATCH_MP_TAC REAL_LE_MUL2 THEN ASM_SIMP_TAC[REAL_HALF; REAL_LT_IMP_LE] THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM REAL_NOT_LE])) THEN
+  CONV_TAC NORM_ARITH);;
+
+let CONTINUOUS_ON_WINDING_NUMBER = prove
+ (`!g. path g
+       ==> (\w. winding_number(g,w)) continuous_on
+           ((:complex) DIFF path_image g)`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; GSYM closed;
+           OPEN_UNIV; CLOSED_PATH_IMAGE; VALID_PATH_IMP_PATH] THEN
+  SIMP_TAC[IN_DIFF; IN_UNIV; CONTINUOUS_AT_WINDING_NUMBER]);;
+
+let WINDING_NUMBER_CONSTANT = prove
+ (`!s g. path g /\ pathfinish g = pathstart g /\
+         connected s /\ s INTER path_image g = {}
+         ==> ?k. !z. z IN s ==> winding_number(g,z) = k`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_DISCRETE_RANGE_CONSTANT THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+    EXISTS_TAC `(:complex) DIFF path_image g` THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_WINDING_NUMBER] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN
+  X_GEN_TAC `w:complex` THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  SUBGOAL_THEN
+   `complex_integer(winding_number(g,w)) /\
+    complex_integer(winding_number(g,z))`
+  MP_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC INTEGER_WINDING_NUMBER THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    REWRITE_TAC[COMPLEX_INTEGER] THEN STRIP_TAC THEN ASM_REWRITE_TAC[]] THEN
+  REWRITE_TAC[GSYM CX_SUB; CX_INJ; COMPLEX_NORM_CX] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_ABS_INTEGER_LEMMA THEN
+  ASM_SIMP_TAC[REAL_SUB_0; INTEGER_CLOSED]);;
+
+let WINDING_NUMBER_EQ = prove
+ (`!g s w z.
+        path g /\ pathfinish g = pathstart g /\
+        w IN s /\ z IN s /\ connected s /\ s INTER path_image g = {}
+        ==> winding_number(g,w) = winding_number(g,z)`,
+  MESON_TAC[WINDING_NUMBER_CONSTANT]);;
+
+let OPEN_WINDING_NUMBER_LEVELSETS = prove
+ (`!g k. path g /\ pathfinish g = pathstart g
+         ==> open {z | ~(z IN path_image g) /\ winding_number(g,z) = k}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[open_def; IN_ELIM_THM] THEN
+  X_GEN_TAC `z:complex` THEN STRIP_TAC THEN
+  MP_TAC(ISPEC `(:complex) DIFF path_image g` OPEN_CONTAINS_BALL) THEN
+  ASM_SIMP_TAC[GSYM closed; CLOSED_PATH_IMAGE; VALID_PATH_IMP_PATH] THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; SUBSET; IN_BALL] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `w:complex` THEN
+  REPEAT STRIP_TAC THENL [ASM_MESON_TAC[DIST_SYM]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`ball(z:complex,e)`; `g:real^1->complex`]
+        WINDING_NUMBER_CONSTANT) THEN
+  ASM_SIMP_TAC[CONNECTED_BALL; EXTENSION; IN_INTER; NOT_IN_EMPTY; IN_BALL] THEN
+  ASM_MESON_TAC[DIST_REFL; DIST_SYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Winding number is zero "outside" a curve, in various senses.              *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_ZERO_IN_OUTSIDE = prove
+ (`!g z. path g /\ pathfinish g = pathstart g /\ z IN outside(path_image g)
+         ==> winding_number(g,z) = Cx(&0)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`path_image(g:real^1->complex)`; `Cx(&0)`]
+   BOUNDED_SUBSET_BALL) THEN ASM_SIMP_TAC[BOUNDED_PATH_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `?w. ~(w IN ball(Cx(&0),B + &1))` STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC(SET_RULE `~(s = UNIV) ==> ?z. ~(z IN s)`) THEN
+    MESON_TAC[BOUNDED_BALL; NOT_BOUNDED_UNIV];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`Cx(&0)`; `B:real`; `B + &1`] SUBSET_BALL) THEN
+  REWRITE_TAC[REAL_ARITH `B <= B + &1`] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`path_image(g:real^1->complex)`; `ball(Cx(&0),B + &1)`]
+        OUTSIDE_SUBSET_CONVEX) THEN
+  ASM_REWRITE_TAC[CONVEX_BALL] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[SUBSET; IN_UNIV; IN_DIFF] THEN DISCH_TAC THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `winding_number(g,w)` THEN
+  CONJ_TAC THENL
+   [MP_TAC(ISPECL [`outside(path_image(g:real^1->complex))`;
+                   `g:real^1->complex`] WINDING_NUMBER_CONSTANT) THEN
+    ASM_SIMP_TAC[OUTSIDE_NO_OVERLAP; CONNECTED_OUTSIDE;
+                 DIMINDEX_2; LE_REFL; BOUNDED_PATH_IMAGE] THEN
+    ASM SET_TAC[];
+    MATCH_MP_TAC WINDING_NUMBER_UNIQUE THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+     [ASM SET_TAC[]; DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC] THEN
+    MP_TAC(ISPECL [`g:real^1->complex`; `min e (&1)`]
+        PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION) THEN
+    ASM_REWRITE_TAC[REAL_LT_MIN; REAL_LT_01] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `p:real^1->complex` THEN
+    STRIP_TAC THEN ONCE_REWRITE_TAC[NORM_SUB] THEN
+    ASM_SIMP_TAC[VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN CONJ_TAC THENL
+     [UNDISCH_TAC `~(w IN ball (Cx (&0),B + &1))` THEN
+      REWRITE_TAC[CONTRAPOS_THM; path_image; IN_BALL] THEN
+      SPEC_TAC(`w:complex`,`x:complex`) THEN REWRITE_TAC[FORALL_IN_IMAGE];
+      REWRITE_TAC[COMPLEX_MUL_RZERO] THEN
+      MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+      MATCH_MP_TAC CAUCHY_THEOREM_CONVEX_SIMPLE THEN
+      EXISTS_TAC `ball(Cx(&0),B + &1)` THEN
+      ASM_SIMP_TAC[CONVEX_BALL; VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+        SIMP_TAC[HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_ID; HOLOMORPHIC_ON_CONST;
+                 COMPLEX_SUB_0] THEN
+        ASM_MESON_TAC[];
+        REWRITE_TAC[path_image; SUBSET; FORALL_IN_IMAGE; IN_BALL]]] THEN
+      X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+      REWRITE_TAC[dist; COMPLEX_SUB_LZERO; NORM_NEG] THEN
+      MATCH_MP_TAC(NORM_ARITH
+       `!g:real^1->complex. norm(p t - g t) < &1 /\ norm(g t) <= B
+                            ==> norm(p t) < B + &1`) THEN
+      EXISTS_TAC `g:real^1->complex` THEN
+      UNDISCH_TAC `path_image g SUBSET ball (Cx (&0),B)` THEN
+      ASM_SIMP_TAC[SUBSET; IN_BALL; path_image; FORALL_IN_IMAGE] THEN
+      ASM_SIMP_TAC[dist; COMPLEX_SUB_LZERO; NORM_NEG; REAL_LT_IMP_LE]]);;
+
+let WINDING_NUMBER_ZERO_OUTSIDE = prove
+ (`!g s z. path g /\ convex s /\ pathfinish g = pathstart g /\
+           ~(z IN s) /\ path_image g SUBSET s
+           ==> winding_number(g,z) = Cx(&0)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC WINDING_NUMBER_ZERO_IN_OUTSIDE THEN
+  ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPECL [`path_image(g:real^1->complex)`; `s:complex->bool`]
+        OUTSIDE_SUBSET_CONVEX) THEN
+  ASM SET_TAC[]);;
+
+let WINDING_NUMBER_ZERO_ATINFINITY = prove
+ (`!g. path g /\ pathfinish g = pathstart g
+       ==> ?B. !z. B <= norm(z) ==> winding_number(g,z) = Cx(&0)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `bounded (path_image g :complex->bool)` MP_TAC THENL
+   [ASM_SIMP_TAC[BOUNDED_PATH_IMAGE]; ALL_TAC] THEN
+  REWRITE_TAC[bounded] THEN DISCH_THEN(X_CHOOSE_TAC `B:real`) THEN
+  EXISTS_TAC `B + &1` THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC WINDING_NUMBER_ZERO_OUTSIDE THEN
+  EXISTS_TAC `cball(Cx(&0),B)` THEN ASM_REWRITE_TAC[CONVEX_CBALL] THEN
+  REWRITE_TAC[SUBSET; IN_CBALL; dist; COMPLEX_SUB_LZERO; NORM_NEG] THEN
+  ASM_MESON_TAC[REAL_ARITH `~(B + &1 <= z /\ z <= B)`]);;
+
+let WINDING_NUMBER_ZERO_POINT = prove
+ (`!g s. path g /\ pathfinish g = pathstart g /\
+         open s /\ path_image g SUBSET s
+         ==> ?z. z IN s /\ winding_number(g,z) = Cx(&0)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`path_image g:complex->bool`; `s:complex->bool`]
+        OUTSIDE_COMPACT_IN_OPEN) THEN
+  ASM_SIMP_TAC[COMPACT_PATH_IMAGE] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[SUBSET_EMPTY; PATH_IMAGE_NONEMPTY]; ALL_TAC] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  GEN_TAC THEN REWRITE_TAC[IN_INTER] THEN
+  ASM_SIMP_TAC[WINDING_NUMBER_ZERO_IN_OUTSIDE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* If a path winds round a set, it winds rounds its inside.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_AROUND_INSIDE = prove
+ (`!g s z.
+        path g /\ pathfinish g = pathstart g /\
+        closed s /\ connected s /\ s INTER path_image g = {} /\
+        z IN s /\ ~(winding_number(g,z) = Cx(&0))
+        ==> !w. w IN s UNION inside(s)
+                ==> winding_number(g,w) = winding_number(g,z)`,
+  MAP_EVERY X_GEN_TAC
+   [`g:real^1->complex`; `s:complex->bool`; `z0:complex`] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `!z. z IN s ==> winding_number(g,z) = winding_number(g,z0)`
+  ASSUME_TAC THENL [ASM_MESON_TAC[WINDING_NUMBER_EQ]; ALL_TAC] THEN
+  ABBREV_TAC `k = winding_number (g,z0)` THEN
+  SUBGOAL_THEN `(s:complex->bool) SUBSET inside(path_image g)` ASSUME_TAC THENL
+   [REWRITE_TAC[SUBSET; INSIDE_OUTSIDE; IN_DIFF; IN_UNIV; IN_UNION] THEN
+    X_GEN_TAC `z:complex` THEN REPEAT STRIP_TAC THENL
+     [ASM SET_TAC[]; ASM_MESON_TAC[WINDING_NUMBER_ZERO_IN_OUTSIDE]];
+    ALL_TAC] THEN
+  X_GEN_TAC `z:complex` THEN REWRITE_TAC[IN_UNION] THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+  MP_TAC(ISPECL [`s:complex->bool`;
+                 `path_image g:complex->bool`]
+        INSIDE_INSIDE_COMPACT_CONNECTED) THEN
+  ASM_SIMP_TAC[COMPACT_PATH_IMAGE; CONNECTED_PATH_IMAGE] THEN STRIP_TAC THEN
+  EXPAND_TAC "k" THEN MATCH_MP_TAC WINDING_NUMBER_EQ THEN
+  EXISTS_TAC `s UNION inside s :complex->bool` THEN
+  ASM_SIMP_TAC[CONNECTED_WITH_INSIDE; IN_UNION] THEN
+  MP_TAC(ISPEC `path_image g :complex->bool` INSIDE_NO_OVERLAP) THEN
+  ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Bounding a WN by 1/2 for a path and point in opposite halfspaces.         *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_SUBPATH_CONTINUOUS = prove
+ (`!g z. valid_path g /\ ~(z IN path_image g)
+         ==> (\a. winding_number(subpath (vec 0) a g,z)) continuous_on
+             interval[vec 0,vec 1]`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_EQ THEN EXISTS_TAC
+    `\a. Cx(&1) / (Cx(&2) * Cx pi * ii) *
+         integral (interval[vec 0,a])
+                  (\t. Cx(&1) / (g t - z) * vector_derivative g (at t))` THEN
+  CONJ_TAC THENL
+   [X_GEN_TAC `a:real^1` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+     `Cx(&1) / (Cx(&2) * Cx pi * ii) *
+      path_integral (subpath (vec 0) a g) (\w. Cx (&1) / (w - z))` THEN
+    CONJ_TAC THENL
+     [AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN
+      MATCH_MP_TAC PATH_INTEGRAL_SUBPATH_INTEGRAL THEN
+      ASM_SIMP_TAC[ENDS_IN_UNIT_INTERVAL; PATH_INTEGRABLE_INVERSEDIFF] THEN
+      ASM_MESON_TAC[IN_INTERVAL_1];
+      REPEAT STRIP_TAC THEN REWRITE_TAC[] THEN CONV_TAC SYM_CONV THEN
+      MATCH_MP_TAC WINDING_NUMBER_VALID_PATH THEN
+      ASM_MESON_TAC[VALID_PATH_SUBPATH; SUBSET; VALID_PATH_IMP_PATH;
+                 ENDS_IN_UNIT_INTERVAL; PATH_IMAGE_SUBPATH_SUBSET]];
+    MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_LMUL THEN
+    MATCH_MP_TAC INDEFINITE_INTEGRAL_CONTINUOUS_RIGHT THEN
+    REWRITE_TAC[GSYM PATH_INTEGRABLE_ON] THEN
+    ASM_SIMP_TAC[PATH_INTEGRABLE_INVERSEDIFF]]);;
+
+let WINDING_NUMBER_IVT_POS = prove
+ (`!g z w.
+        valid_path g /\ ~(z IN path_image g) /\
+        &0 <= w /\ w <= Re(winding_number(g,z))
+        ==> ?t. t IN interval[vec 0,vec 1] /\
+                Re(winding_number(subpath (vec 0) t g,z)) = w`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[RE_DEF] THEN
+  MATCH_MP_TAC IVT_INCREASING_COMPONENT_ON_1 THEN
+  ASM_SIMP_TAC[WINDING_NUMBER_SUBPATH_CONTINUOUS] THEN
+  ASM_REWRITE_TAC[SUBPATH_TRIVIAL; GSYM RE_DEF; DIMINDEX_2; ARITH] THEN
+  REWRITE_TAC[DROP_VEC; REAL_POS; SUBPATH_REFL] THEN
+  MP_TAC(ISPECL [`(g:real^1->complex) (vec 0)`; `z:complex`]
+        WINDING_NUMBER_TRIVIAL) THEN
+  ASM_MESON_TAC[pathstart; PATHSTART_IN_PATH_IMAGE; RE_CX]);;
+
+let WINDING_NUMBER_IVT_NEG = prove
+ (`!g z w.
+        valid_path g /\ ~(z IN path_image g) /\
+        Re(winding_number(g,z)) <= w /\ w <= &0
+        ==> ?t. t IN interval[vec 0,vec 1] /\
+                Re(winding_number(subpath (vec 0) t g,z)) = w`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[RE_DEF] THEN
+  MATCH_MP_TAC IVT_DECREASING_COMPONENT_ON_1 THEN
+  ASM_SIMP_TAC[WINDING_NUMBER_SUBPATH_CONTINUOUS] THEN
+  ASM_REWRITE_TAC[SUBPATH_TRIVIAL; GSYM RE_DEF; DIMINDEX_2; ARITH] THEN
+  REWRITE_TAC[DROP_VEC; REAL_POS; SUBPATH_REFL] THEN
+  MP_TAC(ISPECL [`(g:real^1->complex) (vec 0)`; `z:complex`]
+        WINDING_NUMBER_TRIVIAL) THEN
+  ASM_MESON_TAC[pathstart; PATHSTART_IN_PATH_IMAGE; RE_CX]);;
+
+let WINDING_NUMBER_IVT_ABS = prove
+ (`!g z w.
+        valid_path g /\ ~(z IN path_image g) /\
+        &0 <= w /\ w <= abs(Re(winding_number(g,z)))
+        ==> ?t. t IN interval[vec 0,vec 1] /\
+                abs(Re(winding_number(subpath (vec 0) t g,z))) = w`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `&0 <= Re(winding_number(g,z))` THEN
+  ASM_REWRITE_TAC[real_abs] THEN REWRITE_TAC[GSYM real_abs] THEN
+  REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`; `w:real`]
+        WINDING_NUMBER_IVT_POS);
+    MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`; `--w:real`]
+        WINDING_NUMBER_IVT_NEG)] THEN
+  (ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN ASM_REAL_ARITH_TAC);;
+
+let WINDING_NUMBER_LT_HALF = prove
+ (`!g z a b.
+        valid_path g /\ a dot z <= b /\ path_image g SUBSET {w | a dot w > b}
+        ==> abs(Re(winding_number(g,z))) < &1 / &2`,
+  let lemma = prove
+   (`!g z a b.
+          valid_path g /\ ~(z IN path_image g) /\
+          a dot z <= b /\ path_image g SUBSET {w | a dot w > b}
+          ==> Re(winding_number(g,z)) < &1 / &2`,
+    REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_NOT_LE] THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`; `&1 / &2`]
+      WINDING_NUMBER_IVT_POS) THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[NOT_EXISTS_THM] THEN
+    X_GEN_TAC `t:real^1` THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`subpath (vec 0) t (g:real^1->complex)`; `z:complex`]
+          WINDING_NUMBER_AHLFORS_FULL) THEN
+    ASM_SIMP_TAC[VALID_PATH_SUBPATH; VALID_PATH_IMP_PATH;
+                 ENDS_IN_UNIT_INTERVAL; NOT_IMP] THEN
+    CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `~(z IN t) ==> s SUBSET t ==> ~(z IN s)`)) THEN
+      ASM_SIMP_TAC[PATH_IMAGE_SUBPATH_SUBSET; ENDS_IN_UNIT_INTERVAL;
+                   VALID_PATH_IMP_PATH];
+      ASM_REWRITE_TAC[EULER; RE_MUL_CX; RE_MUL_II; IM_MUL_CX; IM_MUL_II] THEN
+      REWRITE_TAC[REAL_ARITH `&2 * pi * &1 / &2 = pi`; SIN_PI; COS_PI] THEN
+      REWRITE_TAC[COMPLEX_MUL_RZERO; COMPLEX_ADD_RID] THEN
+      REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+      REWRITE_TAC[COMPLEX_MUL_ASSOC; GSYM CX_MUL] THEN
+      REWRITE_TAC[REAL_MUL_RNEG; REAL_MUL_RID; GSYM COMPLEX_CMUL] THEN
+      DISCH_TAC THEN
+      SUBGOAL_THEN `&0 < a dot ((g:real^1->complex) t - z) /\
+                    &0 < a dot (g(vec 0) - z)`
+      MP_TAC THENL
+       [REWRITE_TAC[DOT_RSUB; REAL_SUB_LT] THEN CONJ_TAC THEN
+        MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `b:real` THEN
+        ASM_REWRITE_TAC[GSYM real_gt] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `g SUBSET {z | a dot z > b} ==> t IN g ==> a dot t > b`)) THEN
+        REWRITE_TAC[path_image] THEN MATCH_MP_TAC FUN_IN_IMAGE THEN
+        ASM_REWRITE_TAC[ENDS_IN_UNIT_INTERVAL];
+        ASM_REWRITE_TAC[DOT_RMUL] THEN
+        DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+        ASM_SIMP_TAC[REAL_LT_MUL_EQ] THEN
+        MATCH_MP_TAC(REAL_ARITH `&0 < x ==> ~(&0 < -- x)`) THEN
+        REWRITE_TAC[REAL_EXP_POS_LT]]]) in
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[IN_ELIM_THM; REAL_ARITH `a:real > b <=> ~(a <= b)`] THEN
+  DISCH_TAC THEN MATCH_MP_TAC(REAL_ARITH `x < a /\ --x < a ==> abs x < a`) THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[lemma]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`reversepath g:real^1->complex`; `z:complex`;
+                 `a:complex`; `b:real`] lemma) THEN
+  ASM_SIMP_TAC[VALID_PATH_REVERSEPATH; PATH_IMAGE_REVERSEPATH;
+               WINDING_NUMBER_REVERSEPATH; VALID_PATH_IMP_PATH; RE_NEG] THEN
+  REAL_ARITH_TAC);;
+
+let WINDING_NUMBER_LE_HALF = prove
+ (`!g z a b.
+        valid_path g /\ ~(z IN path_image g) /\
+        ~(a = vec 0) /\ a dot z <= b /\ path_image g SUBSET {w | a dot w >= b}
+        ==> abs(Re(winding_number(g,z))) <= &1 / &2`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`]
+   CONTINUOUS_AT_WINDING_NUMBER) THEN
+  ASM_SIMP_TAC[VALID_PATH_IMP_PATH; continuous_at] THEN
+  DISCH_THEN(MP_TAC o SPEC `abs(Re(winding_number(g,z))) - &1 / &2`) THEN
+  ASM_REWRITE_TAC[REAL_SUB_LT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z - d / &2 / norm(a) % a:complex`) THEN
+  REWRITE_TAC[NORM_ARITH `dist(z - d:complex,z) = norm d`] THEN
+  ASM_SIMP_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM; REAL_DIV_RMUL;
+               NORM_EQ_0; NOT_IMP] THEN
+  CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  MATCH_MP_TAC(NORM_ARITH
+    `abs(Re w' - Re w) <= norm(w' - w) /\ abs(Re w') < &1 / &2
+     ==> ~(dist(w',w) < abs(Re w) - &1 / &2)`) THEN
+  REWRITE_TAC[GSYM RE_SUB] THEN CONJ_TAC THENL
+   [SIMP_TAC[COMPONENT_LE_NORM; RE_DEF; DIMINDEX_2; ARITH]; ALL_TAC] THEN
+  MATCH_MP_TAC WINDING_NUMBER_LT_HALF THEN EXISTS_TAC `a:complex` THEN
+  EXISTS_TAC `b - d / &3 * norm(a:complex)` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [REWRITE_TAC[DOT_RSUB; DOT_RMUL; GSYM NORM_POW_2] THEN
+    ASM_SIMP_TAC[NORM_EQ_0; REAL_FIELD
+     `~(a = &0) ==> x / a * a pow 2 = x * a`] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `a:real <= b ==> d <= e ==> a - e <= b - d`)) THEN
+    MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+    ASM_REAL_ARITH_TAC;
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        SUBSET_TRANS)) THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN MATCH_MP_TAC(REAL_ARITH
+     `&0 < e ==> !x. a dot x >= b ==> a dot x > b - e`) THEN
+    MATCH_MP_TAC REAL_LT_MUL THEN ASM_SIMP_TAC[NORM_POS_LT] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let WINDING_NUMBER_LT_HALF_LINEPATH = prove
+ (`!a b z.
+        ~(z IN segment[a,b])
+        ==> abs(Re(winding_number(linepath(a,b),z))) < &1 / &2`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC WINDING_NUMBER_LT_HALF THEN
+  MP_TAC(ISPECL [`segment[a:complex,b]`; `z:complex`]
+        SEPARATING_HYPERPLANE_CLOSED_POINT) THEN
+  ASM_REWRITE_TAC[CONVEX_SEGMENT; CLOSED_SEGMENT] THEN
+  REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+  SIMP_TAC[VALID_PATH_LINEPATH; PATH_IMAGE_LINEPATH; SUBSET; IN_ELIM_THM;
+           REAL_LT_IMP_LE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Positivity of WN for a linepath.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_LINEPATH_POS_LT = prove
+ (`!a b z. &0 < Im((b - a) * cnj(b - z))
+           ==> &0 < Re(winding_number(linepath(a,b),z))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC WINDING_NUMBER_POS_LT THEN
+  EXISTS_TAC `Im((b - a) * cnj(b - z))` THEN
+  ASM_REWRITE_TAC[VALID_PATH_LINEPATH; VECTOR_DERIVATIVE_LINEPATH_AT] THEN
+  CONJ_TAC THENL
+   [POP_ASSUM MP_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    SPEC_TAC(`z:complex`,`z:complex`) THEN
+    REWRITE_TAC[path_image; FORALL_IN_IMAGE; linepath] THEN
+    REWRITE_TAC[VECTOR_ARITH
+     `b - ((&1 - x) % a + x % b) = (&1 - x) % (b - a)`] THEN
+    REWRITE_TAC[COMPLEX_CMUL; CNJ_MUL; CNJ_CX] THEN
+    REWRITE_TAC[COMPLEX_RING `a * Cx x * cnj a = Cx x * a * cnj a`] THEN
+    SIMP_TAC[COMPLEX_MUL_CNJ; GSYM CX_POW; GSYM CX_MUL; IM_CX; REAL_LT_REFL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+    `segment[a,b] SUBSET
+      {y | Im((b - a) * cnj(b - z)) <= Im((b - a) * cnj(y - z))}`
+  MP_TAC THENL
+   [REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[SET_RULE `{a,b} SUBSET {y | P y} <=> P a /\ P b`] THEN
+      POP_ASSUM MP_TAC THEN
+      REWRITE_TAC[cnj; complex_mul; RE; IM; RE_SUB; IM_SUB] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[COMPLEX_SUB_LDISTRIB; IM_SUB; CNJ_SUB; REAL_LE_SUB_LADD] THEN
+    REWRITE_TAC[CONVEX_ALT; cnj; complex_mul; RE; IM; RE_SUB; IM_SUB] THEN
+    REWRITE_TAC[IN_ELIM_THM; IM_ADD; RE_ADD; IM_CMUL; RE_CMUL] THEN
+    REWRITE_TAC[REAL_NEG_ADD; REAL_NEG_RMUL] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH
+     `e <= ab * ((&1 - u) * x + u * y) + ab' * ((&1 - u) * x' + u * y') <=>
+      (&1 - u) * e + u * e <=
+        (&1 - u) * (ab * x + ab' * x') + u * (ab * y + ab' * y')`] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_ADD2 THEN
+    CONJ_TAC THEN MATCH_MP_TAC REAL_LE_LMUL THEN ASM_REWRITE_TAC[] THEN
+    ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[GSYM PATH_IMAGE_LINEPATH] THEN
+    REWRITE_TAC[SUBSET; path_image; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+    ASM_MESON_TAC[SUBSET; INTERVAL_OPEN_SUBSET_CLOSED]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Winding number for a triangle.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_TRIANGLE = prove
+ (`!a b c z.
+        z IN interior(convex hull {a,b,c})
+        ==> winding_number(linepath(a,b) ++ linepath(b,c) ++ linepath(c,a),z) =
+            if &0 < Im((b - a) * cnj (b - z)) then Cx(&1) else --Cx(&1)`,
+  let lemma1 = prove
+   (`!a b c. vec 0 IN interior(convex hull {a,b,c})
+             ==> ~(Im(a / b) <= &0 /\ &0 <= Im(b / c))`,
+    REPEAT GEN_TAC THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN SIMP_TAC[] THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o ONCE_DEPTH_CONV)
+     [GSYM COMPLEX_INV_DIV] THEN
+    REWRITE_TAC[IM_COMPLEX_INV_GE_0] THEN
+    GEOM_BASIS_MULTIPLE_TAC 1 `b:complex` THEN
+    REWRITE_TAC[COMPLEX_CMUL; COMPLEX_BASIS; GSYM CX_MUL; REAL_MUL_RID] THEN
+    X_GEN_TAC `x:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+    REWRITE_TAC[IM_DIV_CX] THEN ASM_CASES_TAC `x = &0` THEN
+    ASM_REWRITE_TAC[NOT_IN_INTERIOR_CONVEX_HULL_3; COMPLEX_VEC_0] THEN
+    DISCH_TAC THEN REPEAT GEN_TAC THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_MUL_LZERO] THEN STRIP_TAC THEN
+    MATCH_MP_TAC(SET_RULE
+     `!s. ~(x IN s) /\ t SUBSET s ==> ~(x IN t)`) THEN
+    EXISTS_TAC `interior {z | Im z <= &0}` THEN CONJ_TAC THENL
+     [REWRITE_TAC[IM_DEF; INTERIOR_HALFSPACE_COMPONENT_LE] THEN
+      REWRITE_TAC[GSYM COMPLEX_VEC_0; IN_ELIM_THM; VEC_COMPONENT] THEN
+      REAL_ARITH_TAC;
+      MATCH_MP_TAC SUBSET_INTERIOR THEN MATCH_MP_TAC HULL_MINIMAL THEN
+      REWRITE_TAC[CONVEX_HALFSPACE_IM_LE] THEN
+      ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; IN_ELIM_THM] THEN
+      REWRITE_TAC[IM_CX; REAL_LE_REFL]]) in
+  let lemma2 = prove
+   (`z IN interior(convex hull {a,b,c})
+     ==>  &0 < Im((b - a) * cnj (b - z)) /\
+          &0 < Im((c - b) * cnj (c - z)) /\
+          &0 < Im((a - c) * cnj (a - z)) \/
+          Im((b - a) * cnj (b - z)) < &0 /\
+          &0 < Im((b - c) * cnj (b - z)) /\
+          &0 < Im((a - b) * cnj (a - z)) /\
+          &0 < Im((c - a) * cnj (c - z))`,
+    GEOM_ORIGIN_TAC `z:complex` THEN
+    REWRITE_TAC[VECTOR_SUB_RZERO; COMPLEX_SUB_RDISTRIB] THEN
+    REWRITE_TAC[COMPLEX_MUL_CNJ; IM_SUB; GSYM CX_POW; IM_CX] THEN
+    REWRITE_TAC[REAL_ARITH `&0 < &0 - x <=> x < &0`;
+                REAL_ARITH `&0 - x < &0 <=> &0 < x`] THEN
+    REWRITE_TAC[GSYM IM_COMPLEX_DIV_GT_0; GSYM IM_COMPLEX_DIV_LT_0] THEN
+    REPEAT STRIP_TAC THEN
+    GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [GSYM COMPLEX_INV_DIV] THEN
+    REWRITE_TAC[IM_COMPLEX_INV_LT_0; IM_COMPLEX_INV_GT_0] THEN
+    GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o LAND_CONV o RAND_CONV)
+     [GSYM COMPLEX_INV_DIV] THEN
+    REWRITE_TAC[IM_COMPLEX_INV_LT_0] THEN
+    MP_TAC(ISPECL [`a:complex`; `b:complex`; `c:complex`] lemma1) THEN
+    MP_TAC(ISPECL [`b:complex`; `c:complex`; `a:complex`] lemma1) THEN
+    MP_TAC(ISPECL [`c:complex`; `a:complex`; `b:complex`] lemma1) THEN
+    POP_ASSUM MP_TAC THEN SIMP_TAC[INSERT_AC] THEN REAL_ARITH_TAC) in
+  let lemma3 = prove
+   (`!a b c z.
+          z IN interior(convex hull {a,b,c}) /\
+          &0 < Im((b - a) * cnj (b - z)) /\
+          &0 < Im((c - b) * cnj (c - z)) /\
+          &0 < Im((a - c) * cnj (a - z))
+          ==> winding_number
+               (linepath(a,b) ++ linepath(b,c) ++ linepath(c,a),z) = Cx(&1)`,
+    REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC WINDING_NUMBER_EQ_1 THEN
+    REWRITE_TAC[PATHSTART_JOIN; PATHFINISH_JOIN; CONJ_ASSOC;
+                PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[GSYM CONJ_ASSOC] THEN
+      REPEAT(MATCH_MP_TAC WINDING_NUMBER_JOIN_POS_COMBINED THEN
+             REWRITE_TAC[PATHSTART_JOIN; PATHFINISH_JOIN;
+                         PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+             CONJ_TAC) THEN
+      ASM_SIMP_TAC[WINDING_NUMBER_LINEPATH_POS_LT; VALID_PATH_LINEPATH] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE
+       [INTERIOR_OF_TRIANGLE; IN_DIFF; IN_UNION; DE_MORGAN_THM]) THEN
+      ASM_REWRITE_TAC[PATH_IMAGE_LINEPATH];
+      RULE_ASSUM_TAC(REWRITE_RULE
+         [INTERIOR_OF_TRIANGLE; IN_DIFF; IN_UNION; DE_MORGAN_THM]) THEN
+      ASM_SIMP_TAC[WINDING_NUMBER_JOIN; PATH_IMAGE_JOIN; PATH_JOIN; IN_UNION;
+             PATH_LINEPATH; PATHSTART_JOIN; PATHFINISH_JOIN; RE_ADD;
+             PATHSTART_LINEPATH; PATHFINISH_LINEPATH; PATH_IMAGE_LINEPATH] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `abs a < &1 / &2 /\ abs b < &1 / &2 /\ abs c < &1 / &2
+        ==> a + b + c < &2`) THEN
+      REPEAT CONJ_TAC THEN MATCH_MP_TAC WINDING_NUMBER_LT_HALF_LINEPATH THEN
+      ASM_REWRITE_TAC[]]) in
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP lemma2) THEN
+  ASM_SIMP_TAC[lemma3; COMPLEX_NORM_CX; REAL_ABS_NUM] THEN
+  SUBGOAL_THEN
+   `winding_number
+      (linepath(c,b) ++ linepath(b,a) ++ linepath(a,c),z) = Cx(&1)`
+  MP_TAC THENL
+   [MATCH_MP_TAC lemma3 THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[INSERT_AC];
+    COND_CASES_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN CONV_TAC SYM_CONV THEN
+  REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_NUM] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE
+   [INTERIOR_OF_TRIANGLE; IN_DIFF; IN_UNION; DE_MORGAN_THM]) THEN
+  FIRST_ASSUM(ASSUME_TAC o ONCE_REWRITE_RULE[SEGMENT_SYM] o CONJUNCT2) THEN
+  ASM_SIMP_TAC[WINDING_NUMBER_JOIN; PATH_IMAGE_JOIN; PATH_JOIN; IN_UNION;
+         PATH_LINEPATH; PATHSTART_JOIN; PATHFINISH_JOIN; RE_ADD;
+         PATHSTART_LINEPATH; PATHFINISH_LINEPATH; PATH_IMAGE_LINEPATH] THEN
+  ASM_SIMP_TAC[COMPLEX_NEG_ADD; GSYM WINDING_NUMBER_REVERSEPATH;
+              PATH_IMAGE_LINEPATH; PATH_LINEPATH; REVERSEPATH_LINEPATH] THEN
+  CONV_TAC COMPLEX_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* Cauchy's integral formula, again for a convex enclosing set.              *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_INTEGRAL_FORMULA_WEAK = prove
+ (`!f s k g z.
+        convex s /\ FINITE k /\ f continuous_on s /\
+        (!x. x IN interior(s) DIFF k ==> f complex_differentiable at x) /\
+        z IN interior(s) DIFF k /\
+        valid_path g /\ (path_image g) SUBSET (s DELETE z) /\
+        pathfinish g = pathstart g
+        ==> ((\w. f(w) / (w - z)) has_path_integral
+             (Cx(&2) * Cx(pi) * ii * winding_number(g,z) * f(z))) g`,
+  REWRITE_TAC[IN_DIFF] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `z:complex`) THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[complex_differentiable; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `f':complex` THEN DISCH_TAC THEN MP_TAC(SPECL
+   [`\w:complex. if w = z then f' else (f w - f z) / (w - z)`;
+    `s:complex->bool`;
+    `(z:complex) INSERT k`;
+    `g:real^1->complex`] CAUCHY_THEOREM_CONVEX) THEN
+  REWRITE_TAC[IN_DIFF; IN_INSERT; DE_MORGAN_THM] THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[FINITE_INSERT] THEN REPEAT CONJ_TAC THENL
+     [ALL_TAC;
+      X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+      MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_TRANSFORM_AT THEN
+      EXISTS_TAC `\w:complex. (f w - f z) / (w - z)` THEN
+      EXISTS_TAC `dist(w:complex,z)` THEN ASM_SIMP_TAC[DIST_POS_LT] THEN
+      CONJ_TAC THENL [MESON_TAC[DIST_SYM; REAL_LT_REFL]; ALL_TAC] THEN
+      MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_DIV_AT THEN
+      ASM_REWRITE_TAC[COMPLEX_SUB_0] THEN CONJ_TAC THEN
+      MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_SUB THEN
+      ASM_SIMP_TAC[ETA_AX; COMPLEX_DIFFERENTIABLE_CONST;
+                   COMPLEX_DIFFERENTIABLE_ID];
+      ASM SET_TAC[]] THEN
+    REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+    X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `w:complex = z` THENL
+     [ALL_TAC;
+      MATCH_MP_TAC CONTINUOUS_TRANSFORM_WITHIN THEN
+      EXISTS_TAC `\w:complex. (f w - f z) / (w - z)` THEN
+      EXISTS_TAC `dist(w:complex,z)` THEN ASM_SIMP_TAC[DIST_POS_LT] THEN
+      CONJ_TAC THENL [MESON_TAC[DIST_SYM; REAL_LT_REFL]; ALL_TAC] THEN
+      MATCH_MP_TAC CONTINUOUS_COMPLEX_DIV_WITHIN THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN]) THEN
+      ASM_SIMP_TAC[CONTINUOUS_CONST; CONTINUOUS_SUB; CONTINUOUS_WITHIN_ID;
+                   ETA_AX; COMPLEX_SUB_0]] THEN
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN REWRITE_TAC[CONTINUOUS_WITHIN] THEN
+    MATCH_MP_TAC LIM_TRANSFORM_AWAY_WITHIN THEN
+    EXISTS_TAC `\w:complex. (f w - f z) / (w - z)` THEN SIMP_TAC[] THEN
+    EXISTS_TAC `z + Cx(&1)` THEN
+    CONJ_TAC THENL [CONV_TAC COMPLEX_RING; ALL_TAC] THEN
+    REWRITE_TAC[GSYM HAS_COMPLEX_DERIVATIVE_WITHIN] THEN
+    ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN];
+    ALL_TAC] THEN
+  MP_TAC(SPECL [`g:real^1->complex`; `z:complex`]
+    HAS_PATH_INTEGRAL_WINDING_NUMBER) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `(f:complex->complex) z` o MATCH_MP
+    HAS_PATH_INTEGRAL_COMPLEX_LMUL) THEN REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_ADD) THEN
+  REWRITE_TAC[COMPLEX_RING
+   `f * Cx(&2) * a * b * c + Cx(&0) = Cx(&2) * a * b * c * f`] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HAS_PATH_INTEGRAL_EQ) THEN
+  X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `~(w:complex = z)` MP_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN CONV_TAC COMPLEX_FIELD);;
+
+let CAUCHY_INTEGRAL_FORMULA_CONVEX_SIMPLE = prove
+ (`!f s g z.
+        convex s /\ f holomorphic_on s /\
+        z IN interior(s) /\
+        valid_path g /\ (path_image g) SUBSET (s DELETE z) /\
+        pathfinish g = pathstart g
+        ==> ((\w. f(w) / (w - z)) has_path_integral
+             (Cx(&2) * Cx(pi) * ii * winding_number(g,z) * f(z))) g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CAUCHY_INTEGRAL_FORMULA_WEAK THEN
+  MAP_EVERY EXISTS_TAC [`s:complex->bool`; `{}:complex->bool`] THEN
+  ASM_REWRITE_TAC[DIFF_EMPTY; FINITE_RULES] THEN
+  SIMP_TAC[OPEN_INTERIOR; complex_differentiable; GSYM HOLOMORPHIC_ON_OPEN] THEN
+  ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON;
+                HOLOMORPHIC_ON_SUBSET; INTERIOR_SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homotopy forms of Cauchy's theorem. The first two proofs are almost the   *)
+(* same and could potentially be unified with a little more work.            *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_THEOREM_HOMOTOPIC_PATHS = prove
+ (`!f g h s.
+        open s /\ f holomorphic_on s /\
+        valid_path g /\ valid_path h /\ homotopic_paths s g h
+        ==> path_integral g f = path_integral h f`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o SYM o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHSTART) THEN
+  FIRST_ASSUM(ASSUME_TAC o SYM o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHFINISH) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopic_paths]) THEN
+  REWRITE_TAC[homotopic_with; LEFT_IMP_EXISTS_THM; PCROSS] THEN
+  X_GEN_TAC `k:real^(1,1)finite_sum->complex` THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!t. t IN interval[vec 0:real^1,vec 1]
+        ==> ?e. &0 < e /\
+              !t1 t2. t1 IN interval[vec 0:real^1,vec 1] /\
+                      t2 IN interval[vec 0,vec 1] /\
+                      norm(t1 - t) < e /\ norm(t2 - t) < e
+                   ==> ?d. &0 < d /\
+                        !g1 g2. valid_path g1 /\ valid_path g2 /\
+                                (!u. u IN interval[vec 0,vec 1]
+                                     ==> norm(g1 u - k(pastecart t1 u)) < d /\
+                                         norm(g2 u - k(pastecart t2 u)) < d) /\
+                                pathstart g1 = pathstart g /\
+                                pathfinish g1 = pathfinish g /\
+                                pathstart g2 = pathstart g /\
+                                pathfinish g2 = pathfinish g
+                                ==> path_image g1 SUBSET s /\
+                                    path_image g2 SUBSET s /\
+                                    path_integral g2 f = path_integral g1 f`
+  MP_TAC THENL
+   [X_GEN_TAC `t:real^1` THEN STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`s:complex->bool`; `\u. (k:real^(1,1)finite_sum->complex)(pastecart t u)`]
+     PATH_INTEGRAL_NEARBY_ENDS) THEN
+    REWRITE_TAC[] THEN ANTS_TAC THENL
+     [ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+      REWRITE_TAC[path_image; path; IMAGE_o] THEN CONJ_TAC THENL
+       [ALL_TAC; ASM SET_TAC[]] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_ID;
+               CONTINUOUS_ON_CONST] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN ASM SET_TAC[];
+      DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC)] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          COMPACT_UNIFORMLY_CONTINUOUS)) THEN
+    SIMP_TAC[REWRITE_RULE[PCROSS] COMPACT_PCROSS; COMPACT_INTERVAL] THEN
+    REWRITE_TAC[uniformly_continuous_on] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &4`) THEN
+    ASM_REWRITE_TAC[REAL_ARITH `&0 < e / &4 <=> &0 < e`] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; GSYM CONJ_ASSOC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (MESON[]
+     `(!t x t' x'. P t x t' x') ==> (!t t' u. P t u t' u)`)) THEN
+    REWRITE_TAC[dist; NORM_PASTECART; PASTECART_SUB] THEN
+    REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[TAUT `a /\ b /\ c /\ b /\ d <=> a /\ c /\ b /\ d`] THEN
+    SIMP_TAC[REAL_ADD_RID; POW_2_SQRT; NORM_POS_LE] THEN DISCH_TAC THEN
+    ASM_REWRITE_TAC[] THEN
+    MAP_EVERY X_GEN_TAC [`t1:real^1`; `t2:real^1`] THEN
+    STRIP_TAC THEN EXISTS_TAC `e / &4` THEN
+    ASM_REWRITE_TAC[REAL_ARITH `&0 < e / &4 <=> &0 < e`] THEN
+    MAP_EVERY X_GEN_TAC [`g1:real^1->complex`; `g2:real^1->complex`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM
+     (MP_TAC o SPECL [`g1:real^1->complex`; `g2:real^1->complex`]) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+    X_GEN_TAC `u:real^1` THEN STRIP_TAC THEN
+    ASM_MESON_TAC[NORM_ARITH
+     `norm(g1 - k1) < e / &4 /\ norm(g2 - k2) < e / &4 /\
+      norm(k1 - kt) < e / &4 /\ norm(k2 - kt) < e / &4
+      ==> norm(g1 - kt) < e /\ norm(g2 - kt) < e`];
+    GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[ SKOLEM_THM; LEFT_IMP_EXISTS_THM]] THEN
+  X_GEN_TAC `ee:real^1->real` THEN DISCH_THEN(LABEL_TAC "*") THEN
+  MP_TAC(ISPEC `interval[vec 0:real^1,vec 1]` COMPACT_IMP_HEINE_BOREL) THEN
+  REWRITE_TAC[COMPACT_INTERVAL] THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `IMAGE (\t:real^1. ball(t,ee t / &3)) (interval[vec 0,vec 1])`) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[FORALL_IN_IMAGE; OPEN_BALL; SUBSET] THEN
+    X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+    REWRITE_TAC[UNIONS_IMAGE; IN_ELIM_THM] THEN EXISTS_TAC `t:real^1` THEN
+    ASM_SIMP_TAC[CENTRE_IN_BALL; REAL_ARITH `&0 < e / &3 <=> &0 < e`];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> b /\ a /\ c`] THEN
+  REWRITE_TAC[CONJ_ASSOC; FINITE_SUBSET_IMAGE] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM; MESON[]
+   `(?f s. (P s /\ f = g s) /\ Q f) <=> ?s. P s /\ Q(g s)`] THEN
+  REWRITE_TAC[UNIONS_IMAGE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `k:real^1->bool` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  GEN_REWRITE_TAC LAND_CONV [SUBSET] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  ASM_CASES_TAC `k:real^1->bool = {}` THENL
+   [ASM_REWRITE_TAC[NOT_IN_EMPTY; GSYM NOT_EXISTS_THM; MEMBER_NOT_EMPTY] THEN
+    REWRITE_TAC[INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN REAL_ARITH_TAC;
+    DISCH_THEN(LABEL_TAC "+")] THEN
+  SUBGOAL_THEN `!i:real^1. i IN k ==> &0 < ee(i)`
+  ASSUME_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+  ABBREV_TAC `e = inf(IMAGE (ee:real^1->real) k)` THEN
+  MP_TAC(ISPEC `IMAGE (ee:real^1->real) k` INF_FINITE) THEN
+  MP_TAC(ISPECL [`IMAGE (ee:real^1->real) k`; `&0`]
+    REAL_LT_INF_FINITE) THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; IMAGE_EQ_EMPTY; FORALL_IN_IMAGE] THEN
+  DISCH_TAC THEN DISCH_THEN(ASSUME_TAC o CONJUNCT2) THEN
+  MP_TAC(ISPEC `e / &3` REAL_ARCH_INV) THEN
+  ASM_REWRITE_TAC[REAL_ARITH `&0 < e / &3 <=> &0 < e`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N:num` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `!n. n <= N
+        ==> ?d. &0 < d /\
+                !j. valid_path j /\
+                    (!u. u IN interval [vec 0,vec 1]
+                        ==> norm(j u - k(pastecart (lift(&n / &N)) u)) < d) /\
+                    pathstart j = pathstart g /\
+                    pathfinish j = pathfinish g
+                    ==> path_image j SUBSET s /\
+                        path_integral j f = path_integral g f`
+  (MP_TAC o SPEC `N:num`) THENL
+   [ALL_TAC;
+    REWRITE_TAC[LE_REFL; LEFT_IMP_EXISTS_THM] THEN
+    GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(MP_TAC o SPEC `h:real^1->complex`) THEN
+    ASM_SIMP_TAC[REAL_DIV_REFL; REAL_OF_NUM_EQ; LIFT_NUM] THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN MESON_TAC[]] THEN
+  INDUCT_TAC THENL
+   [REMOVE_THEN "*" (MP_TAC o SPEC `vec 0:real^1`) THEN
+    ASM_REWRITE_TAC[real_div; REAL_MUL_LZERO; LE_0; LIFT_NUM] THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    REPEAT(DISCH_THEN(MP_TAC o SPEC `vec 0:real^1`) THEN
+           REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL]) THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `j:real^1->complex` THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+     [`g:real^1->complex`; `j:real^1->complex`]) THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN MESON_TAC[];
+    DISCH_TAC] THEN
+  SUBGOAL_THEN `lift(&n / &N) IN interval[vec 0,vec 1] /\
+                lift(&(SUC n) / &N) IN interval[vec 0,vec 1]`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; LE_1] THEN
+    REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+    ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  REMOVE_THEN "+" (MP_TAC o SPEC `lift(&n / &N)`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^1` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o check (is_imp o concl)) THEN
+  ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real`
+    (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "1"))) THEN
+  REMOVE_THEN "*" (MP_TAC o SPEC `t:real^1`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(MP_TAC o SPECL [`lift(&n / &N)`; `lift(&(SUC n) / &N)`]) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_BALL]) THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `!e. norm(n' - n:real^N) < e / &3 /\ e <= ee
+     ==> dist(t,n) < ee / &3 ==> norm(n - t) < ee /\ norm(n' - t) < ee`) THEN
+    EXISTS_TAC `e:real` THEN
+    REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB; LIFT_DROP] THEN
+    REWRITE_TAC[real_div; GSYM REAL_SUB_RDISTRIB] THEN
+    SIMP_TAC[REAL_OF_NUM_SUB; ARITH_RULE `n <= SUC n`] THEN
+    REWRITE_TAC[ARITH_RULE `SUC n - n = 1`; REAL_MUL_LID] THEN
+    REWRITE_TAC[REAL_ABS_INV; REAL_ABS_NUM] THEN
+    ASM_SIMP_TAC[GSYM real_div];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d2:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `j:real^1->complex` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`\u:real^1. (k(pastecart (lift (&n / &N)) u):complex)`;
+    `min d1 d2`] PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION) THEN
+  ASM_SIMP_TAC[REAL_LT_MIN; REAL_ARITH `&0 < e / &4 <=> &0 < e`] THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[path] THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_ID;
+             CONTINUOUS_ON_CONST] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    ASM SET_TAC[];
+    DISCH_THEN(X_CHOOSE_THEN `p:real^1->complex` STRIP_ASSUME_TAC)] THEN
+  REMOVE_THEN "1" (MP_TAC o SPEC `p:real^1->complex`) THEN
+  ASM_SIMP_TAC[VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`p:real^1->complex`; `j:real^1->complex`]) THEN
+  ASM_SIMP_TAC[VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION]);;
+
+let CAUCHY_THEOREM_HOMOTOPIC_LOOPS = prove
+ (`!f g h s.
+        open s /\ f holomorphic_on s /\
+        valid_path g /\ valid_path h /\ homotopic_loops s g h
+        ==> path_integral g f = path_integral h f`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP HOMOTOPIC_LOOPS_IMP_LOOP) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopic_loops]) THEN
+  REWRITE_TAC[homotopic_with; PCROSS; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `k:real^(1,1)finite_sum->complex` THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!t. t IN interval[vec 0:real^1,vec 1]
+        ==> ?e. &0 < e /\
+              !t1 t2. t1 IN interval[vec 0:real^1,vec 1] /\
+                      t2 IN interval[vec 0,vec 1] /\
+                      norm(t1 - t) < e /\ norm(t2 - t) < e
+                   ==> ?d. &0 < d /\
+                        !g1 g2. valid_path g1 /\ valid_path g2 /\
+                                (!u. u IN interval[vec 0,vec 1]
+                                     ==> norm(g1 u - k(pastecart t1 u)) < d /\
+                                         norm(g2 u - k(pastecart t2 u)) < d) /\
+                                pathfinish g1 = pathstart g1 /\
+                                pathfinish g2 = pathstart g2
+                                ==> path_image g1 SUBSET s /\
+                                    path_image g2 SUBSET s /\
+                                    path_integral g2 f = path_integral g1 f`
+  MP_TAC THENL
+   [X_GEN_TAC `t:real^1` THEN STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`s:complex->bool`; `\u. (k:real^(1,1)finite_sum->complex)(pastecart t u)`]
+     PATH_INTEGRAL_NEARBY_LOOP) THEN
+    REWRITE_TAC[] THEN ANTS_TAC THENL
+     [ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+      REWRITE_TAC[path_image; path; IMAGE_o] THEN CONJ_TAC THENL
+       [ALL_TAC; ASM SET_TAC[]] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_ID;
+               CONTINUOUS_ON_CONST] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN ASM SET_TAC[];
+      DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC)] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          COMPACT_UNIFORMLY_CONTINUOUS)) THEN
+    SIMP_TAC[REWRITE_RULE[PCROSS] COMPACT_PCROSS; COMPACT_INTERVAL] THEN
+    REWRITE_TAC[uniformly_continuous_on] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &4`) THEN
+    ASM_REWRITE_TAC[REAL_ARITH `&0 < e / &4 <=> &0 < e`] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; GSYM CONJ_ASSOC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (MESON[]
+     `(!t x t' x'. P t x t' x') ==> (!t t' u. P t u t' u)`)) THEN
+    REWRITE_TAC[dist; NORM_PASTECART; PASTECART_SUB] THEN
+    REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[TAUT `a /\ b /\ c /\ b /\ d <=> a /\ c /\ b /\ d`] THEN
+    SIMP_TAC[REAL_ADD_RID; POW_2_SQRT; NORM_POS_LE] THEN DISCH_TAC THEN
+    ASM_REWRITE_TAC[] THEN
+    MAP_EVERY X_GEN_TAC [`t1:real^1`; `t2:real^1`] THEN
+    STRIP_TAC THEN EXISTS_TAC `e / &4` THEN
+    ASM_REWRITE_TAC[REAL_ARITH `&0 < e / &4 <=> &0 < e`] THEN
+    MAP_EVERY X_GEN_TAC [`g1:real^1->complex`; `g2:real^1->complex`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM
+     (MP_TAC o SPECL [`g1:real^1->complex`; `g2:real^1->complex`]) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+    X_GEN_TAC `u:real^1` THEN STRIP_TAC THEN
+    ASM_MESON_TAC[NORM_ARITH
+     `norm(g1 - k1) < e / &4 /\ norm(g2 - k2) < e / &4 /\
+      norm(k1 - kt) < e / &4 /\ norm(k2 - kt) < e / &4
+      ==> norm(g1 - kt) < e /\ norm(g2 - kt) < e`];
+    GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[ SKOLEM_THM; LEFT_IMP_EXISTS_THM]] THEN
+  X_GEN_TAC `ee:real^1->real` THEN DISCH_THEN(LABEL_TAC "*") THEN
+  MP_TAC(ISPEC `interval[vec 0:real^1,vec 1]` COMPACT_IMP_HEINE_BOREL) THEN
+  REWRITE_TAC[COMPACT_INTERVAL] THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `IMAGE (\t:real^1. ball(t,ee t / &3)) (interval[vec 0,vec 1])`) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[FORALL_IN_IMAGE; OPEN_BALL; SUBSET] THEN
+    X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+    REWRITE_TAC[UNIONS_IMAGE; IN_ELIM_THM] THEN EXISTS_TAC `t:real^1` THEN
+    ASM_SIMP_TAC[CENTRE_IN_BALL; REAL_ARITH `&0 < e / &3 <=> &0 < e`];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> b /\ a /\ c`] THEN
+  REWRITE_TAC[CONJ_ASSOC; FINITE_SUBSET_IMAGE] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM; MESON[]
+   `(?f s. (P s /\ f = g s) /\ Q f) <=> ?s. P s /\ Q(g s)`] THEN
+  REWRITE_TAC[UNIONS_IMAGE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `k:real^1->bool` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  GEN_REWRITE_TAC LAND_CONV [SUBSET] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  ASM_CASES_TAC `k:real^1->bool = {}` THENL
+   [ASM_REWRITE_TAC[NOT_IN_EMPTY; GSYM NOT_EXISTS_THM; MEMBER_NOT_EMPTY] THEN
+    REWRITE_TAC[INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN REAL_ARITH_TAC;
+    DISCH_THEN(LABEL_TAC "+")] THEN
+  SUBGOAL_THEN `!i:real^1. i IN k ==> &0 < ee(i)`
+  ASSUME_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+  ABBREV_TAC `e = inf(IMAGE (ee:real^1->real) k)` THEN
+  MP_TAC(ISPEC `IMAGE (ee:real^1->real) k` INF_FINITE) THEN
+  MP_TAC(ISPECL [`IMAGE (ee:real^1->real) k`; `&0`]
+    REAL_LT_INF_FINITE) THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; IMAGE_EQ_EMPTY; FORALL_IN_IMAGE] THEN
+  DISCH_TAC THEN DISCH_THEN(ASSUME_TAC o CONJUNCT2) THEN
+  MP_TAC(ISPEC `e / &3` REAL_ARCH_INV) THEN
+  ASM_REWRITE_TAC[REAL_ARITH `&0 < e / &3 <=> &0 < e`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N:num` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `!n. n <= N
+        ==> ?d. &0 < d /\
+                !j. valid_path j /\
+                    (!u. u IN interval [vec 0,vec 1]
+                        ==> norm(j u - k(pastecart (lift(&n / &N)) u)) < d) /\
+                    pathfinish j = pathstart j
+                    ==> path_image j SUBSET s /\
+                        path_integral j f = path_integral g f`
+  (MP_TAC o SPEC `N:num`) THENL
+   [ALL_TAC;
+    REWRITE_TAC[LE_REFL; LEFT_IMP_EXISTS_THM] THEN
+    GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(MP_TAC o SPEC `h:real^1->complex`) THEN
+    ASM_SIMP_TAC[REAL_DIV_REFL; REAL_OF_NUM_EQ; LIFT_NUM] THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN MESON_TAC[]] THEN
+  INDUCT_TAC THENL
+   [REMOVE_THEN "*" (MP_TAC o SPEC `vec 0:real^1`) THEN
+    ASM_REWRITE_TAC[real_div; REAL_MUL_LZERO; LE_0; LIFT_NUM] THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    REPEAT(DISCH_THEN(MP_TAC o SPEC `vec 0:real^1`) THEN
+           REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL]) THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `j:real^1->complex` THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+     [`g:real^1->complex`; `j:real^1->complex`]) THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN MESON_TAC[];
+    DISCH_TAC] THEN
+  SUBGOAL_THEN `lift(&n / &N) IN interval[vec 0,vec 1] /\
+                lift(&(SUC n) / &N) IN interval[vec 0,vec 1]`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; LE_1] THEN
+    REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+    ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  REMOVE_THEN "+" (MP_TAC o SPEC `lift(&n / &N)`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^1` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o check (is_imp o concl)) THEN
+  ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real`
+    (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "1"))) THEN
+  REMOVE_THEN "*" (MP_TAC o SPEC `t:real^1`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(MP_TAC o SPECL [`lift(&n / &N)`; `lift(&(SUC n) / &N)`]) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_BALL]) THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `!e. norm(n' - n:real^N) < e / &3 /\ e <= ee
+     ==> dist(t,n) < ee / &3 ==> norm(n - t) < ee /\ norm(n' - t) < ee`) THEN
+    EXISTS_TAC `e:real` THEN
+    REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB; LIFT_DROP] THEN
+    REWRITE_TAC[real_div; GSYM REAL_SUB_RDISTRIB] THEN
+    SIMP_TAC[REAL_OF_NUM_SUB; ARITH_RULE `n <= SUC n`] THEN
+    REWRITE_TAC[ARITH_RULE `SUC n - n = 1`; REAL_MUL_LID] THEN
+    REWRITE_TAC[REAL_ABS_INV; REAL_ABS_NUM] THEN
+    ASM_SIMP_TAC[GSYM real_div];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d2:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `j:real^1->complex` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`\u:real^1. (k(pastecart (lift (&n / &N)) u):complex)`;
+    `min d1 d2`] PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION) THEN
+  ASM_SIMP_TAC[REAL_LT_MIN; REAL_ARITH `&0 < e / &4 <=> &0 < e`] THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[path] THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_ID;
+             CONTINUOUS_ON_CONST] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    ASM SET_TAC[];
+    DISCH_THEN(X_CHOOSE_THEN `p:real^1->complex` STRIP_ASSUME_TAC)] THEN
+  REMOVE_THEN "1" (MP_TAC o SPEC `p:real^1->complex`) THEN
+  ASM_SIMP_TAC[VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`p:real^1->complex`; `j:real^1->complex`]) THEN
+  ASM_SIMP_TAC[VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION]);;
+
+let CAUCHY_THEOREM_NULL_HOMOTOPIC = prove
+ (`!f g s a.
+        open s /\ f holomorphic_on s /\ a IN s /\ valid_path g /\
+        homotopic_loops s g (linepath(a,a))
+        ==> (f has_path_integral Cx(&0)) g`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP HOMOTOPIC_LOOPS_IMP_SUBSET) THEN
+  MATCH_MP_TAC
+   (MESON[HAS_PATH_INTEGRAL_INTEGRAL; path_integrable_on; PATH_INTEGRAL_UNIQUE]
+     `!p. f path_integrable_on g /\ (f has_path_integral y) p /\
+          path_integral g f = path_integral p f
+          ==> (f has_path_integral y) g`) THEN
+  EXISTS_TAC `linepath(a:complex,a)` THEN REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[PATH_INTEGRABLE_HOLOMORPHIC_SIMPLE];
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `a:complex`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    MATCH_MP_TAC CAUCHY_THEOREM_CONVEX_SIMPLE THEN
+    EXISTS_TAC `ball(a:complex,e)` THEN
+    ASM_REWRITE_TAC[VALID_PATH_LINEPATH; CONVEX_BALL; PATH_IMAGE_LINEPATH;
+                    PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+    ASM_REWRITE_TAC[SEGMENT_REFL; SING_SUBSET; IN_BALL; CENTRE_IN_BALL] THEN
+    ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET];
+    MATCH_MP_TAC CAUCHY_THEOREM_HOMOTOPIC_LOOPS THEN
+    EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[VALID_PATH_LINEPATH]]);;
+
+let CAUCHY_THEOREM_SIMPLY_CONNECTED = prove
+ (`!f g s. open s /\ simply_connected s /\ f holomorphic_on s /\
+           valid_path g /\ path_image g SUBSET s /\ pathfinish g = pathstart g
+           ==> (f has_path_integral Cx(&0)) g`,
+  REWRITE_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_PATH] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC CAUCHY_THEOREM_NULL_HOMOTOPIC THEN
+  MAP_EVERY EXISTS_TAC [`s:complex->bool`; `pathstart g :complex`] THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; SUBSET];
+    MATCH_MP_TAC HOMOTOPIC_PATHS_IMP_HOMOTOPIC_LOOPS THEN
+    ASM_SIMP_TAC[PATHFINISH_LINEPATH; VALID_PATH_IMP_PATH]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More winding number properties, including the fact that it's +-1 inside   *)
+(* a simple closed curve.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_HOMOTOPIC_PATHS = prove
+ (`!g h z. homotopic_paths ((:complex) DELETE z) g h
+           ==> winding_number(g,z) = winding_number(h,z)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATH) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_SUBSET) THEN
+  REWRITE_TAC[SET_RULE `s SUBSET UNIV DELETE z <=> ~(z IN s)`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `(:complex) DELETE z`]
+     HOMOTOPIC_NEARBY_PATHS) THEN
+  ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV; SET_RULE
+   `s SUBSET UNIV DELETE z <=> ~(z IN s)`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`; `d:real`]
+    WINDING_NUMBER) THEN ASM_SIMP_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:real^1->complex` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`h:real^1->complex`; `(:complex) DELETE z`]
+     HOMOTOPIC_NEARBY_PATHS) THEN
+  ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV; SET_RULE
+   `s SUBSET UNIV DELETE z <=> ~(z IN s)`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`h:real^1->complex`; `z:complex`; `e:real`]
+    WINDING_NUMBER) THEN ASM_SIMP_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `q:real^1->complex` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `path_integral p (\w. Cx(&1) / (w - z)) =
+    path_integral q (\w. Cx(&1) / (w - z))`
+  MP_TAC THENL
+   [MATCH_MP_TAC CAUCHY_THEOREM_HOMOTOPIC_PATHS THEN
+    EXISTS_TAC `(:complex) DELETE z` THEN
+    ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+      SIMP_TAC[HOLOMORPHIC_ON_CONST; HOLOMORPHIC_ON_ID;
+               HOLOMORPHIC_ON_SUB; IN_DELETE; COMPLEX_SUB_0];
+      ALL_TAC] THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+    EXISTS_TAC `g:real^1->complex` THEN CONJ_TAC THENL
+     [ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_MESON_TAC[NORM_SUB; VALID_PATH_IMP_PATH];
+      MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+      EXISTS_TAC `h:real^1->complex` THEN ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_MESON_TAC[NORM_SUB; VALID_PATH_IMP_PATH]];
+    ASM_REWRITE_TAC[] THEN MP_TAC CX_2PII_NZ THEN CONV_TAC COMPLEX_RING]);;
+
+let WINDING_NUMBER_HOMOTOPIC_LOOPS = prove
+ (`!g h z. homotopic_loops ((:complex) DELETE z) g h
+           ==> winding_number(g,z) = winding_number(h,z)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP HOMOTOPIC_LOOPS_IMP_PATH) THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP HOMOTOPIC_LOOPS_IMP_LOOP) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_LOOPS_IMP_SUBSET) THEN
+  REWRITE_TAC[SET_RULE `s SUBSET UNIV DELETE z <=> ~(z IN s)`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `(:complex) DELETE z`]
+     HOMOTOPIC_NEARBY_LOOPS) THEN
+  ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV; SET_RULE
+   `s SUBSET UNIV DELETE z <=> ~(z IN s)`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`; `d:real`]
+    WINDING_NUMBER) THEN ASM_SIMP_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:real^1->complex` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`h:real^1->complex`; `(:complex) DELETE z`]
+     HOMOTOPIC_NEARBY_LOOPS) THEN
+  ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV; SET_RULE
+   `s SUBSET UNIV DELETE z <=> ~(z IN s)`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`h:real^1->complex`; `z:complex`; `e:real`]
+    WINDING_NUMBER) THEN ASM_SIMP_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `q:real^1->complex` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `path_integral p (\w. Cx(&1) / (w - z)) =
+    path_integral q (\w. Cx(&1) / (w - z))`
+  MP_TAC THENL
+   [MATCH_MP_TAC CAUCHY_THEOREM_HOMOTOPIC_LOOPS THEN
+    EXISTS_TAC `(:complex) DELETE z` THEN
+    ASM_SIMP_TAC[OPEN_DELETE; OPEN_UNIV] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+      SIMP_TAC[HOLOMORPHIC_ON_CONST; HOLOMORPHIC_ON_ID;
+               HOLOMORPHIC_ON_SUB; IN_DELETE; COMPLEX_SUB_0];
+      ALL_TAC] THEN
+    MATCH_MP_TAC HOMOTOPIC_LOOPS_TRANS THEN
+    EXISTS_TAC `g:real^1->complex` THEN CONJ_TAC THENL
+     [ONCE_REWRITE_TAC[HOMOTOPIC_LOOPS_SYM] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_MESON_TAC[NORM_SUB; VALID_PATH_IMP_PATH];
+      MATCH_MP_TAC HOMOTOPIC_LOOPS_TRANS THEN
+      EXISTS_TAC `h:real^1->complex` THEN ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_MESON_TAC[NORM_SUB; VALID_PATH_IMP_PATH]];
+    ASM_REWRITE_TAC[] THEN MP_TAC CX_2PII_NZ THEN CONV_TAC COMPLEX_RING]);;
+
+let WINDING_NUMBER_PATHS_LINEAR_EQ = prove
+ (`!g h z.
+        path g /\ path h /\
+        pathstart h = pathstart g /\
+        pathfinish h = pathfinish g /\
+        (!t. t IN interval[vec 0,vec 1] ==> ~(z IN segment[g t,h t]))
+        ==> winding_number(h,z) = winding_number(g,z)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC WINDING_NUMBER_HOMOTOPIC_PATHS THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_LINEAR THEN ASM SET_TAC[]);;
+
+let WINDING_NUMBER_LOOPS_LINEAR_EQ = prove
+ (`!g h z.
+        path g /\ path h /\
+        pathfinish g = pathstart g /\
+        pathfinish h = pathstart h /\
+        (!t. t IN interval[vec 0,vec 1] ==> ~(z IN segment[g t,h t]))
+        ==> winding_number(h,z) = winding_number(g,z)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC WINDING_NUMBER_HOMOTOPIC_LOOPS THEN
+  MATCH_MP_TAC HOMOTOPIC_LOOPS_LINEAR THEN ASM SET_TAC[]);;
+
+let WINDING_NUMBER_NEARBY_PATHS_EQ = prove
+ (`!g h z.
+        path g /\ path h /\
+        pathstart h = pathstart g /\
+        pathfinish h = pathfinish g /\
+        (!t. t IN interval[vec 0,vec 1] ==> norm(h t - g t) < norm(g t - z))
+        ==> winding_number(h,z) = winding_number(g,z)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC WINDING_NUMBER_HOMOTOPIC_PATHS THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_NEARBY_EXPLICIT THEN ASM SET_TAC[]);;
+
+let WINDING_NUMBER_NEARBY_LOOPS_EQ = prove
+ (`!g h z.
+        path g /\ path h /\
+        pathfinish g = pathstart g /\
+        pathfinish h = pathstart h /\
+        (!t. t IN interval[vec 0,vec 1] ==> norm(h t - g t) < norm(g t - z))
+        ==> winding_number(h,z) = winding_number(g,z)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC WINDING_NUMBER_HOMOTOPIC_LOOPS THEN
+  MATCH_MP_TAC HOMOTOPIC_LOOPS_NEARBY_EXPLICIT THEN ASM SET_TAC[]);;
+
+let WINDING_NUMBER_SUBPATH_COMBINE = prove
+ (`!g u v w z.
+        path g /\ ~(z IN path_image g) /\
+        u IN interval [vec 0,vec 1] /\
+        v IN interval [vec 0,vec 1] /\
+        w IN interval [vec 0,vec 1]
+        ==> winding_number(subpath u v g,z) +
+            winding_number(subpath v w g,z) =
+            winding_number(subpath u w g,z)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `winding_number(subpath u v g ++ subpath v w g,z)` THEN
+  CONJ_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC WINDING_NUMBER_JOIN THEN
+    ASM_SIMP_TAC[PATH_SUBPATH; PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+    ASM_MESON_TAC[SUBSET; PATH_IMAGE_SUBPATH_SUBSET];
+    MATCH_MP_TAC WINDING_NUMBER_HOMOTOPIC_PATHS THEN
+    MATCH_MP_TAC HOMOTOPIC_JOIN_SUBPATHS THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[]]);;
+
+let WINDING_NUMBER_STRONG = prove
+ (`!g z e.
+        path g /\ ~(z IN path_image g) /\ &0 < e
+         ==> ?p. vector_polynomial_function p /\ valid_path p /\
+                 ~(z IN path_image p) /\
+                 pathstart p = pathstart g /\
+                 pathfinish p = pathfinish g /\
+                 (!t. t IN interval[vec 0,vec 1] ==> norm(g t - p t) < e) /\
+                 path_integral p (\w. Cx(&1) / (w - z)) =
+                 Cx(&2) * Cx(pi) * ii * winding_number(g,z)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?d. &0 < d /\
+       !t. t IN interval[vec 0,vec 1] ==> d <= norm((g:real^1->complex) t - z)`
+  STRIP_ASSUME_TAC THENL
+   [EXISTS_TAC `setdist({z:complex},path_image g)` THEN
+    REWRITE_TAC[SETDIST_POS_LE; REAL_ARITH
+     `&0 < x <=> &0 <= x /\ ~(x = &0)`] THEN
+     ASM_SIMP_TAC[SETDIST_EQ_0_CLOSED_COMPACT; CLOSED_SING; COMPACT_PATH_IMAGE;
+                  PATH_IMAGE_NONEMPTY] THEN
+     CONJ_TAC THENL [ASM SET_TAC[]; REPEAT STRIP_TAC] THEN
+     REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] (GSYM dist)] THEN
+     MATCH_MP_TAC SETDIST_LE_DIST THEN REWRITE_TAC[path_image] THEN
+     ASM SET_TAC[];
+     MP_TAC(ISPECL [`g:real^1->complex`; `min d e`]
+      PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION) THEN
+     ASM_REWRITE_TAC[REAL_LT_MIN] THEN MATCH_MP_TAC MONO_EXISTS THEN
+     X_GEN_TAC `p:real^1->complex` THEN STRIP_TAC THEN
+     ONCE_REWRITE_TAC[NORM_SUB] THEN
+     ASM_SIMP_TAC[VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN
+     MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+      [REWRITE_TAC[path_image; IN_IMAGE] THEN
+       ASM_MESON_TAC[NORM_SUB; REAL_NOT_LT];
+       DISCH_TAC THEN MATCH_MP_TAC(COMPLEX_FIELD
+        `!w'. ~(a * b * c = Cx(&0)) /\ w' = w /\ w' = Cx(&1) / (a * b * c) * i
+              ==> i = a * b * c * w`) THEN
+       EXISTS_TAC `winding_number(p,z)` THEN
+       REWRITE_TAC[CX_2PII_NZ] THEN CONJ_TAC THENL
+        [MATCH_MP_TAC WINDING_NUMBER_NEARBY_PATHS_EQ; ALL_TAC] THEN
+       ASM_SIMP_TAC[WINDING_NUMBER_VALID_PATH; VALID_PATH_IMP_PATH;
+                    VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN
+       ASM_MESON_TAC[REAL_LTE_TRANS; NORM_SUB]]]);;
+
+let WINDING_NUMBER_FROM_INNERPATH = prove
+ (`!c1 c2 c a b z:complex d.
+        ~(a = b) /\
+        simple_path c1 /\ pathstart c1 = a /\ pathfinish c1 = b /\
+        simple_path c2 /\ pathstart c2 = a /\ pathfinish c2 = b /\
+        simple_path c /\ pathstart c = a /\ pathfinish c = b /\
+        path_image c1 INTER path_image c2 = {a,b} /\
+        path_image c1 INTER path_image c = {a,b} /\
+        path_image c2 INTER path_image c = {a,b} /\
+        ~(path_image c INTER inside(path_image c1 UNION path_image c2) = {}) /\
+        z IN inside(path_image c1 UNION path_image c) /\
+        winding_number(c1 ++ reversepath c,z) = d /\ ~(d = Cx(&0))
+        ==> z IN inside(path_image c1 UNION path_image c2) /\
+            winding_number(c1 ++ reversepath c2,z) = d`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`c1:real^1->complex`; `c2:real^1->complex`;
+                 `c:real^1->complex`; `a:complex`; `b:complex`]
+         SPLIT_INSIDE_SIMPLE_CLOSED_CURVE) THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  UNDISCH_TAC `winding_number(c1 ++ reversepath c,z) = d` THEN
+  MP_TAC(ISPECL
+   [`c ++ reversepath(c2:real^1->complex)`; `z:complex`]
+   WINDING_NUMBER_ZERO_IN_OUTSIDE) THEN
+  SUBGOAL_THEN
+   `~((z:complex) IN path_image c) /\
+    ~(z IN path_image c1) /\
+    ~(z IN path_image c2)`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPEC `(path_image c1 UNION path_image c):complex->bool`
+                 INSIDE_NO_OVERLAP) THEN
+    MP_TAC(ISPEC `(path_image c1 UNION path_image c2):complex->bool`
+                 INSIDE_NO_OVERLAP) THEN
+    ASM SET_TAC[];
+    ASM_SIMP_TAC[PATHSTART_JOIN; PATHFINISH_JOIN; PATH_IMAGE_JOIN;
+      PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH; PATH_IMAGE_REVERSEPATH;
+      PATH_JOIN; PATH_REVERSEPATH; SIMPLE_PATH_IMP_PATH;
+      WINDING_NUMBER_JOIN; WINDING_NUMBER_REVERSEPATH] THEN
+    ANTS_TAC THENL
+     [ASM_REWRITE_TAC[OUTSIDE_INSIDE; IN_DIFF; IN_UNION; IN_UNIV] THEN
+      ONCE_REWRITE_TAC[UNION_COMM] THEN ASM SET_TAC[];
+      CONV_TAC COMPLEX_RING]]);;
+
+let SIMPLE_CLOSED_PATH_WINDING_NUMBER_INSIDE = prove
+ (`!g. simple_path g
+       ==> (!z. z IN inside(path_image g) ==> winding_number(g,z) = Cx(&1)) \/
+           (!z. z IN inside(path_image g) ==> winding_number(g,z) = --Cx(&1))`,
+  let lemma1 = prove
+   (`!p a e.
+          &0 < e /\
+          simple_path(p ++ linepath(a - e % basis 1,a + e % basis 1)) /\
+          pathstart p = a + e % basis 1 /\ pathfinish p = a - e % basis 1 /\
+          ball(a,e) INTER path_image p = {}
+          ==> ?z. z IN inside(path_image
+                         (p ++ linepath(a - e % basis 1,a + e % basis 1))) /\
+                  norm(winding_number
+                   (p ++ linepath(a - e % basis 1,a + e % basis 1),z)) = &1`,
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`p:real^1->complex`; `linepath(a - e % basis 1,a + e % basis 1)`]
+     SIMPLE_PATH_JOIN_LOOP_EQ) THEN
+    ASM_REWRITE_TAC[PATHFINISH_LINEPATH; PATHSTART_LINEPATH] THEN
+    STRIP_TAC THEN
+    SUBGOAL_THEN
+      `(a:complex) IN frontier(inside
+       (path_image(p ++ linepath(a - e % basis 1,a + e % basis 1))))`
+    MP_TAC THENL
+     [FIRST_ASSUM
+       (MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] JORDAN_INSIDE_OUTSIDE)) THEN
+      ASM_REWRITE_TAC[PATHSTART_JOIN; PATHFINISH_JOIN;
+                      PATHFINISH_LINEPATH] THEN
+      STRIP_TAC THEN ASM_SIMP_TAC[PATH_IMAGE_JOIN; PATHSTART_LINEPATH] THEN
+      REWRITE_TAC[IN_UNION; PATH_IMAGE_LINEPATH] THEN DISJ2_TAC THEN
+      REWRITE_TAC[IN_SEGMENT] THEN EXISTS_TAC `&1 / &2` THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN VECTOR_ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[FRONTIER_STRADDLE] THEN
+    DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `c:complex` STRIP_ASSUME_TAC o CONJUNCT1) THEN
+    MP_TAC(ISPEC
+     `path_image (p ++ linepath(a - e % basis 1:complex,a + e % basis 1))`
+     INSIDE_NO_OVERLAP) THEN
+    REWRITE_TAC[EXTENSION] THEN DISCH_THEN(MP_TAC o SPEC `c:complex`) THEN
+    ASM_REWRITE_TAC[IN_INTER; NOT_IN_EMPTY] THEN
+    ASM_SIMP_TAC[PATH_IMAGE_JOIN; PATHSTART_LINEPATH; PATH_IMAGE_LINEPATH] THEN
+    REWRITE_TAC[IN_UNION; DE_MORGAN_THM] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [SEGMENT_AS_BALL] THEN
+    ASM_REWRITE_TAC[IN_INTER;
+      VECTOR_ARITH `inv(&2) % ((a - e) + (a + e)):complex = a`;
+      VECTOR_ARITH `(a + e) - (a - e):complex = &2 % e`] THEN
+    ASM_SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_2; ARITH] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < e ==> (abs(&2) * abs e * &1) / &2 = e`] THEN
+    ASM_SIMP_TAC[IN_CBALL; REAL_LT_IMP_LE] THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `~collinear{a - e % basis 1,c:complex,a + e % basis 1}`
+    ASSUME_TAC THENL
+     [MP_TAC(ISPECL
+       [`a - e % basis 1:complex`; `a + e % basis  1:complex`; `c:complex`]
+       COLLINEAR_3_AFFINE_HULL) THEN
+      ASM_SIMP_TAC[VECTOR_ARITH `a - x:complex = a + x <=> x = vec 0`;
+                   BASIS_NONZERO; DIMINDEX_2; ARITH; VECTOR_MUL_EQ_0;
+                   REAL_LT_IMP_NZ] THEN
+      REWRITE_TAC[INSERT_AC];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+    `~(interior(convex hull {a - e % basis 1,c:complex,a + e % basis 1}) = {})`
+    MP_TAC THENL
+     [ASM_SIMP_TAC[INTERIOR_CONVEX_HULL_3_MINIMAL] THEN
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+      REPEAT(ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN EXISTS_TAC `&1 / &3`) THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN MESON_TAC[];
+      ALL_TAC] THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o AP_TERM `norm:complex->real` o
+      MATCH_MP WINDING_NUMBER_TRIANGLE) THEN
+    REWRITE_TAC[] THEN ONCE_REWRITE_TAC[COND_RAND] THEN
+    REWRITE_TAC[NORM_NEG; COND_ID; COMPLEX_NORM_CX; REAL_ABS_NUM] THEN
+    DISCH_TAC THEN
+    MP_TAC(ISPECL
+     [`linepath(a + e % basis 1:complex,a - e % basis 1)`;
+      `p:real^1->complex`;
+      `linepath(a + e % basis 1:complex,c) ++ linepath(c,a - e % basis 1)`;
+      `a + e % basis 1:complex`; `a - e % basis 1:complex`;
+      `z:complex`;
+      `winding_number
+        (linepath(a - e % basis 1,c) ++
+         linepath(c,a + e % basis 1) ++
+         linepath(a + e % basis 1,a - e % basis 1),
+         z)`] WINDING_NUMBER_FROM_INNERPATH) THEN
+    ASM_SIMP_TAC[SIMPLE_PATH_LINEPATH; PATHSTART_JOIN; PATHFINISH_JOIN;
+             VECTOR_ARITH `a + x:complex = a - x <=> x = vec 0`;
+             BASIS_NONZERO; DIMINDEX_2; ARITH; VECTOR_MUL_EQ_0;
+             REAL_LT_IMP_NZ; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+             ARC_IMP_SIMPLE_PATH; PATH_IMAGE_JOIN; PATH_IMAGE_LINEPATH] THEN
+    ANTS_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC(TAUT
+       `(p ==> p') /\ (p /\ q ==> q') ==> p /\ q ==> p' /\ q'`) THEN
+      CONJ_TAC THENL [MESON_TAC[UNION_COMM; SEGMENT_SYM]; ALL_TAC] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (SUBST_ALL_TAC o SYM)) THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (NORM_ARITH
+       `norm(z:complex) = &1 ==> u = --z ==> norm u = &1`)) THEN
+      GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV)
+       [GSYM REVERSEPATH_LINEPATH] THEN
+      ASM_SIMP_TAC[GSYM REVERSEPATH_JOINPATHS; PATHSTART_LINEPATH] THEN
+      ONCE_REWRITE_TAC[COMPLEX_RING `a:complex = --b <=> b = --a`] THEN
+      MATCH_MP_TAC WINDING_NUMBER_REVERSEPATH THEN
+      ASM_SIMP_TAC[PATH_JOIN; PATHSTART_LINEPATH; PATH_IMAGE_JOIN;
+                   PATH_LINEPATH; ARC_IMP_PATH; PATH_IMAGE_LINEPATH] THEN
+      ONCE_REWRITE_TAC[SEGMENT_SYM] THEN ONCE_REWRITE_TAC[UNION_COMM] THEN
+      ASM_MESON_TAC[INSIDE_NO_OVERLAP; IN_INTER; NOT_IN_EMPTY]] THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC ARC_IMP_SIMPLE_PATH THEN MATCH_MP_TAC ARC_JOIN THEN
+      REWRITE_TAC[ARC_LINEPATH_EQ; PATHSTART_LINEPATH;
+                  PATHFINISH_LINEPATH] THEN
+      REPEAT(CONJ_TAC THENL
+       [DISCH_THEN SUBST_ALL_TAC THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[INSERT_AC; COLLINEAR_2]) THEN
+        FIRST_X_ASSUM CONTR_TAC;
+        ALL_TAC]) THEN
+      REWRITE_TAC[PATH_IMAGE_LINEPATH] THEN
+      MATCH_MP_TAC(SET_RULE `s = t ==> s SUBSET t`) THEN
+      MATCH_MP_TAC INTER_SEGMENT THEN ASM_MESON_TAC[INSERT_AC];
+      REWRITE_TAC[SEGMENT_CLOSED_OPEN] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `b INTER p = {}
+        ==> s SUBSET b /\ k SUBSET p
+            ==> (s UNION k) INTER p = k`)) THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[SUBSET; IN_SEGMENT; IN_BALL] THEN
+        REWRITE_TAC[VECTOR_ARITH
+         `(&1 - u) % (a + e) + u % (a - e):complex =
+          a + (&1 - &2 * u) % e`] THEN
+        REPEAT STRIP_TAC THEN
+        ASM_REWRITE_TAC[NORM_ARITH `dist(a:complex,a + e) = norm e`] THEN
+        SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_2; ARITH] THEN
+        MATCH_MP_TAC(REAL_ARITH
+         `x * e < &1 * e /\ &0 < e ==> x * abs e * &1 < e`) THEN
+        ASM_SIMP_TAC[REAL_LT_RMUL_EQ] THEN ASM_REAL_ARITH_TAC;
+        REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET] THEN
+        ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; PATHFINISH_IN_PATH_IMAGE]];
+      MATCH_MP_TAC(SET_RULE
+       `s INTER t1 = {a} /\ s INTER t2 = {b}
+        ==> s INTER (t1 UNION t2) = {a,b}`) THEN
+      CONJ_TAC THENL
+       [GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [SEGMENT_SYM];
+        GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [SEGMENT_SYM]] THEN
+      MATCH_MP_TAC INTER_SEGMENT THEN DISJ2_TAC THEN
+      ASM_MESON_TAC[INSERT_AC];
+      MATCH_MP_TAC(SET_RULE
+       `s INTER t1 = {a} /\ s INTER t2 = {b}
+        ==> s INTER (t1 UNION t2) = {a,b}`) THEN
+      CONJ_TAC THENL [ONCE_REWRITE_TAC[SEGMENT_SYM]; ALL_TAC] THEN
+      REWRITE_TAC[SEGMENT_CLOSED_OPEN] THEN
+      MATCH_MP_TAC(SET_RULE
+       `b IN p /\ ~(c IN p) /\ p INTER s = {}
+        ==> p INTER (s UNION {c,b}) = {b}`) THEN
+      (CONJ_TAC THENL
+        [ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; PATHFINISH_IN_PATH_IMAGE];
+         ASM_REWRITE_TAC[]]) THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `b INTER p = {} ==> s SUBSET b ==> p INTER s = {}`)) THEN
+      REWRITE_TAC[GSYM INTERIOR_CBALL] THEN
+      MATCH_MP_TAC IN_INTERIOR_CLOSURE_CONVEX_SEGMENT THEN
+      ASM_REWRITE_TAC[CONVEX_CBALL; INTERIOR_CBALL; IN_BALL] THEN
+      MATCH_MP_TAC(REWRITE_RULE[SUBSET] CLOSURE_SUBSET) THEN
+      REWRITE_TAC[IN_CBALL;
+                  NORM_ARITH `dist(a:complex,a - e) = norm e`;
+                  NORM_ARITH `dist(a:complex,a + e) = norm e`] THEN
+      ASM_SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_2; ARITH] THEN
+      ASM_REAL_ARITH_TAC;
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `c:complex` THEN
+      REWRITE_TAC[IN_INTER; ENDS_IN_SEGMENT; IN_UNION] THEN
+      FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `c IN s ==> s = t ==> c IN t`)) THEN
+      ASM_SIMP_TAC[PATH_IMAGE_JOIN; PATHSTART_LINEPATH] THEN
+      REWRITE_TAC[UNION_COMM; PATH_IMAGE_LINEPATH; SEGMENT_SYM];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [GSYM
+        INSIDE_OF_TRIANGLE]) THEN
+      REWRITE_TAC[UNION_ACI; SEGMENT_SYM];
+      ASM_SIMP_TAC[REVERSEPATH_JOINPATHS; PATHSTART_JOIN; PATHFINISH_JOIN;
+           PATHSTART_LINEPATH; PATHFINISH_LINEPATH; REVERSEPATH_LINEPATH] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE
+        [INTERIOR_OF_TRIANGLE; IN_DIFF; IN_UNION; DE_MORGAN_THM]) THEN
+      ASM_SIMP_TAC[WINDING_NUMBER_JOIN; PATH_JOIN; PATH_LINEPATH;
+          PATH_IMAGE_JOIN; IN_UNION; PATHSTART_JOIN; PATHFINISH_JOIN;
+          PATHSTART_LINEPATH; PATHFINISH_LINEPATH; PATH_IMAGE_LINEPATH] THEN
+      CONV_TAC COMPLEX_RING;
+      DISCH_THEN SUBST_ALL_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE LAND_CONV [COMPLEX_NORM_CX]) THEN
+      REAL_ARITH_TAC]) in
+  let lemma2 = prove
+   (`!p a d e.
+          &0 < d /\ &0 < e /\
+          simple_path(p ++ linepath(a - d % basis 1,a + e % basis 1)) /\
+          pathstart p = a + e % basis 1 /\ pathfinish p = a - d % basis 1
+          ==> ?z. z IN inside(path_image
+                         (p ++ linepath(a - d % basis 1,a + e % basis 1))) /\
+                  norm(winding_number
+                   (p ++ linepath(a - d % basis 1,a + e % basis 1),z)) = &1`,
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`p:real^1->complex`; `linepath(a - d % basis 1,a + e % basis 1)`]
+     SIMPLE_PATH_JOIN_LOOP_EQ) THEN
+    ASM_REWRITE_TAC[PATHFINISH_LINEPATH; PATHSTART_LINEPATH] THEN
+    REWRITE_TAC[ARC_LINEPATH_EQ; PATH_IMAGE_LINEPATH] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `~((a:complex) IN path_image p)` ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `p INTER s SUBSET {d,e}
+        ==> a IN s /\ ~(d = a) /\ ~(e = a) ==> ~(a IN p)`)) THEN
+      REWRITE_TAC[GSYM BETWEEN_IN_SEGMENT; between] THEN
+      REWRITE_TAC[NORM_ARITH `dist(a - d:complex,a + e) = norm(d + e)`;
+        NORM_ARITH `dist(a - d:complex,a) + dist(a,a + e) = norm(d) + norm(e)`;
+        VECTOR_ARITH `a + e:complex = a <=> e = vec 0`;
+        VECTOR_ARITH `a - d:complex = a <=> d = vec 0`] THEN
+      SIMP_TAC[GSYM VECTOR_ADD_RDISTRIB; NORM_MUL; VECTOR_MUL_EQ_0] THEN
+      ASM_SIMP_TAC[BASIS_NONZERO; NORM_BASIS; DIMINDEX_2; ARITH] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MP_TAC(ISPEC `(:complex) DIFF path_image p` OPEN_CONTAINS_BALL) THEN
+    ASM_SIMP_TAC[GSYM closed; CLOSED_ARC_IMAGE; IN_UNIV; IN_DIFF] THEN
+    DISCH_THEN(MP_TAC o SPEC `a:complex`) THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[SET_RULE `s SUBSET UNIV DIFF t <=> s INTER t = {}`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN
+    ABBREV_TAC `kde:real = min k (min d e) / &2` THEN
+    SUBGOAL_THEN `&0 < kde /\ kde < k /\ kde < d /\ kde < e`
+    STRIP_ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`linepath(a + kde % basis 1,a + e % basis 1) ++ p ++
+       linepath(a - d % basis 1,a - kde % basis 1)`;
+      `a:complex`; `kde:real`] lemma1) THEN
+    ASM_SIMP_TAC[PATHSTART_JOIN; PATHFINISH_JOIN; PATH_IMAGE_JOIN;
+      PATHSTART_LINEPATH; PATHFINISH_LINEPATH; PATH_IMAGE_LINEPATH;
+      SIMPLE_PATH_JOIN_LOOP_EQ] THEN
+    ANTS_TAC THENL
+     [REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC ARC_JOIN THEN
+        ASM_SIMP_TAC[ARC_JOIN_EQ; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+                     PATHSTART_JOIN; PATHFINISH_JOIN; PATH_IMAGE_LINEPATH;
+                     ARC_LINEPATH_EQ; PATH_IMAGE_JOIN] THEN
+        REWRITE_TAC[VECTOR_ARITH `a + e:complex = a + d <=> e - d = vec 0`;
+                  VECTOR_ARITH `a - d:complex = a - e <=> e - d = vec 0`] THEN
+        REWRITE_TAC[GSYM VECTOR_SUB_RDISTRIB; VECTOR_MUL_EQ_0; REAL_SUB_0] THEN
+        ASM_SIMP_TAC[BASIS_NONZERO; NORM_BASIS; DIMINDEX_2; ARITH] THEN
+        ASM_SIMP_TAC[REAL_LT_IMP_NE] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `p INTER de SUBSET {e,d}
+          ==> dk SUBSET de /\ ke SUBSET de /\ ~(e IN dk) /\ ~(d IN ke) /\
+              ke INTER dk = {}
+          ==> p INTER dk SUBSET {d} /\ ke INTER (p UNION dk) SUBSET {e}`)) THEN
+        REWRITE_TAC[SUBSET_SEGMENT; ENDS_IN_SEGMENT] THEN
+        REWRITE_TAC[GSYM BETWEEN_IN_SEGMENT; between] THEN
+        REWRITE_TAC[NORM_ARITH `dist(a - d:complex,a + e) = norm(d + e) /\
+                                dist(a + d,a - e) = norm(d + e) /\
+                                dist(a - d,a - e) = norm(d - e) /\
+                                dist(a + d,a + e) = norm(d - e)`] THEN
+        REWRITE_TAC[GSYM VECTOR_ADD_RDISTRIB; GSYM VECTOR_SUB_RDISTRIB] THEN
+        ASM_SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_2; ARITH] THEN
+        REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+        REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INTER; NOT_IN_EMPTY] THEN
+        MATCH_MP_TAC(MESON[REAL_LT_ANTISYM]
+         `!a:complex. (!x. x IN t ==> x$1 < a$1) /\ (!x. x IN s ==> a$1 < x$1)
+                      ==> !x. ~(x IN s /\ x IN t)`) THEN
+        EXISTS_TAC `a:complex` THEN
+        SIMP_TAC[IN_SEGMENT; LEFT_IMP_EXISTS_THM] THEN
+        SIMP_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT;
+                 VECTOR_MUL_COMPONENT; BASIS_COMPONENT; DIMINDEX_2; ARITH] THEN
+        REWRITE_TAC[REAL_ARITH
+         `(a < (&1 - u) * (a + x) + u * (a + y) <=>
+           &0 < (&1 - u) * x + u * y) /\
+          ((&1 - u) * (a - x) + u * (a - y) < a <=>
+           &0 < (&1 - u) * x + u * y)`] THEN
+        REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_MUL_RID] THEN
+        REWRITE_TAC[REAL_ARITH `&0 < (&1 - u) * x + u * y <=>
+                                (&1 - u) * --x + u * --y < &0`] THEN
+        MATCH_MP_TAC REAL_CONVEX_BOUND_LT THEN ASM_REAL_ARITH_TAC;
+        REWRITE_TAC[ARC_LINEPATH_EQ; VECTOR_MUL_EQ_0;
+                    VECTOR_ARITH `a - k:complex = a + k <=> k = vec 0`] THEN
+        ASM_SIMP_TAC[REAL_LT_IMP_NZ; BASIS_NONZERO; DIMINDEX_2; ARITH];
+        MATCH_MP_TAC(SET_RULE
+          `kk INTER p = {} /\ kk INTER ke = {kp} /\ dk INTER kk = {kn}
+           ==> (ke UNION p UNION dk) INTER kk SUBSET {kp,kn}`) THEN
+        CONJ_TAC THENL
+         [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+           `b INTER p = {} ==> s SUBSET b ==> s INTER p = {}`)) THEN
+          SIMP_TAC[SUBSET; IN_SEGMENT; IN_BALL; LEFT_IMP_EXISTS_THM] THEN
+          REWRITE_TAC[VECTOR_ARITH
+            `(&1 - u) % (a - d) + u % (a + d):complex = a - (&1 - &2 * u) % d`;
+           NORM_ARITH `dist(a:complex,a - d) = norm d`] THEN
+          REPEAT STRIP_TAC THEN
+          SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_2; ARITH] THEN
+          MATCH_MP_TAC(REAL_ARITH
+           `&0 < kd /\ a * kd <= &1 * kd /\ kd < k
+            ==> a * abs kd * &1 < k`) THEN
+          ASM_SIMP_TAC[REAL_LE_RMUL_EQ] THEN ASM_REAL_ARITH_TAC;
+          CONJ_TAC THEN MATCH_MP_TAC INTER_SEGMENT THEN DISJ1_TAC THEN
+          REWRITE_TAC[GSYM BETWEEN_IN_SEGMENT; between] THEN
+          REWRITE_TAC[NORM_ARITH `dist(a - d:complex,a + e) = norm(d + e) /\
+                                  dist(a + d,a - e) = norm(d + e) /\
+                                  dist(a - d,a - e) = norm(d - e) /\
+                                  dist(a + d,a + e) = norm(d - e)`] THEN
+          REWRITE_TAC[GSYM VECTOR_ADD_RDISTRIB; GSYM VECTOR_SUB_RDISTRIB] THEN
+          ASM_SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_2; ARITH] THEN
+          ASM_REAL_ARITH_TAC];
+        REWRITE_TAC[UNION_OVER_INTER; EMPTY_UNION] THEN
+        ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> b /\ a /\ c`] THEN CONJ_TAC THENL
+         [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+           `b INTER p = {} ==> c SUBSET b ==> c INTER p = {}`)) THEN
+          MATCH_MP_TAC SUBSET_BALL THEN ASM_SIMP_TAC[REAL_LT_IMP_LE];
+          ALL_TAC] THEN
+        REWRITE_TAC[SET_RULE `s INTER t = {} <=>
+                              !x. x IN t ==> ~(x IN s)`] THEN
+        SIMP_TAC[IN_SEGMENT; LEFT_IMP_EXISTS_THM; IN_BALL] THEN
+        REWRITE_TAC[VECTOR_ARITH
+        `(&1 - u) % (a - d) + u % (a - e):complex =
+         a - ((&1 - u) % d + u % e) /\
+         (&1 - u) % (a + d) + u % (a + e):complex =
+         a + ((&1 - u) % d + u % e)`;
+        NORM_ARITH
+         `dist(a:complex,a + d) = norm d /\ dist(a,a - e) = norm e`] THEN
+        REWRITE_TAC[VECTOR_MUL_ASSOC; GSYM VECTOR_ADD_RDISTRIB] THEN
+        SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_2; ARITH] THEN
+        REWRITE_TAC[REAL_NOT_LT; REAL_MUL_RID] THEN REPEAT STRIP_TAC THEN
+        MATCH_MP_TAC(REAL_ARITH `x <= y ==> x <= abs y`) THEN
+        REWRITE_TAC[REAL_ARITH
+         `(k <= (&1 - u) * k + u * e <=> &0 <= u * (e - k)) /\
+          (k <= (&1 - u) * d + u * k <=> &0 <= (&1 - u) * (d - k))`] THEN
+        MATCH_MP_TAC REAL_LE_MUL THEN ASM_REAL_ARITH_TAC];
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `z:complex` THEN
+    MATCH_MP_TAC(TAUT
+     `(p <=> p') /\ (p /\ p' ==> (q <=> q')) ==> p /\ q ==> p' /\ q'`) THEN
+    CONJ_TAC THENL
+     [AP_TERM_TAC THEN AP_TERM_TAC THEN
+      ONCE_REWRITE_TAC[SET_RULE
+       `(c UNION p UNION a) UNION b = p UNION (a UNION b UNION c)`] THEN
+      AP_TERM_TAC THEN
+      W(MP_TAC o PART_MATCH (lhand o rand) UNION_SEGMENT o
+         rand o lhand o snd) THEN
+      REWRITE_TAC[GSYM BETWEEN_IN_SEGMENT; between;
+                  NORM_ARITH `dist(a - d:complex,a + e) = norm(d + e)`;
+                  NORM_ARITH `dist(a + d:complex,a + e) = norm(d - e)`] THEN
+      ASM_SIMP_TAC[GSYM VECTOR_ADD_RDISTRIB; GSYM VECTOR_SUB_RDISTRIB;
+                   NORM_MUL; NORM_BASIS; DIMINDEX_2; ARITH] THEN
+      ANTS_TAC THENL [ASM_REAL_ARITH_TAC; DISCH_THEN SUBST1_TAC] THEN
+      MATCH_MP_TAC UNION_SEGMENT THEN
+      REWRITE_TAC[GSYM BETWEEN_IN_SEGMENT; between;
+                  NORM_ARITH `dist(a - d:complex,a + e) = norm(d + e)`;
+                  NORM_ARITH `dist(a - d:complex,a - e) = norm(d - e)`] THEN
+      ASM_SIMP_TAC[GSYM VECTOR_ADD_RDISTRIB; GSYM VECTOR_SUB_RDISTRIB;
+                   NORM_MUL; NORM_BASIS; DIMINDEX_2; ARITH] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    DISCH_THEN(CONJUNCTS_THEN (MP_TAC o MATCH_MP
+     (MESON[INSIDE_NO_OVERLAP; IN_INTER; NOT_IN_EMPTY]
+       `z IN inside s ==> ~(z IN s)`))) THEN
+    REWRITE_TAC[IN_UNION; DE_MORGAN_THM] THEN REPEAT STRIP_TAC THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    ASM_SIMP_TAC[WINDING_NUMBER_JOIN; PATH_JOIN; ARC_IMP_PATH; PATH_LINEPATH;
+      PATH_IMAGE_JOIN; IN_UNION; PATH_IMAGE_LINEPATH; PATHSTART_JOIN;
+      PATHFINISH_JOIN; PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+    MATCH_MP_TAC(COMPLEX_RING
+     `d + k + e:complex = z ==> (e + p + d) + k = p + z`) THEN
+    MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC
+     `winding_number(linepath (a - d % basis 1:complex,a - kde % basis 1),z) +
+      winding_number(linepath (a - kde % basis 1,a + e % basis 1),z)` THEN
+    CONJ_TAC THENL [AP_TERM_TAC; ALL_TAC] THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC WINDING_NUMBER_SPLIT_LINEPATH THEN
+    ASM_REWRITE_TAC[] THENL
+     [CONJ_TAC THENL
+       [ALL_TAC;
+        SUBGOAL_THEN
+         `~(z IN segment[a - kde % basis 1:complex,a + kde % basis 1]) /\
+          ~(z IN segment[a + kde % basis 1,a + e % basis 1])`
+        MP_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+        MATCH_MP_TAC(SET_RULE
+         `s UNION t = u ==> ~(z IN s) /\ ~(z IN t) ==> ~(z IN u)`) THEN
+        MATCH_MP_TAC UNION_SEGMENT];
+      ALL_TAC] THEN
+    REWRITE_TAC[GSYM BETWEEN_IN_SEGMENT; between] THEN
+    REWRITE_TAC[NORM_ARITH `dist(a - d:complex,a + e) = norm(d + e)`;
+                NORM_ARITH `dist(a - d:complex,a - e) = norm(d - e)`;
+                NORM_ARITH `dist(a + d:complex,a + e) = norm(d - e)`] THEN
+    ASM_SIMP_TAC[GSYM VECTOR_ADD_RDISTRIB; GSYM VECTOR_SUB_RDISTRIB; NORM_MUL;
+                   NORM_BASIS; DIMINDEX_2; ARITH] THEN
+    ASM_REAL_ARITH_TAC) in
+  let lemma3 = prove
+   (`!p:real^1->complex.
+          simple_path p /\ pathfinish p = pathstart p
+          ==> ?z. z IN inside(path_image p) /\ norm(winding_number(p,z)) = &1`,
+    GEN_TAC THEN STRIP_TAC THEN
+    MP_TAC(ISPEC `p:real^1->complex` JORDAN_INSIDE_OUTSIDE) THEN
+    ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+    UNDISCH_TAC `~(inside(path_image p):complex->bool = {})` THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `a:complex`) THEN
+    MP_TAC(ISPECL [`inside(path_image p):complex->bool`;
+                   `a:complex`; `basis 1:complex`]
+          RAY_TO_FRONTIER) THEN
+    MP_TAC(ISPECL [`inside(path_image p):complex->bool`;
+                   `a:complex`; `--basis 1:complex`]
+          RAY_TO_FRONTIER) THEN
+    ASM_SIMP_TAC[INTERIOR_OPEN; VECTOR_NEG_EQ_0; BASIS_NONZERO;
+                 DIMINDEX_2; ARITH] THEN
+    REWRITE_TAC[VECTOR_ARITH `a + d % --b:complex = a - d % b`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `?t. t IN interval[vec 0,vec 1] /\
+          (p:real^1->complex) t = a - d % basis 1`
+    STRIP_ASSUME_TAC THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[path_image; IN_IMAGE]) THEN
+      ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?q. simple_path q /\
+          pathstart q:complex = a - d % basis 1 /\
+          pathfinish q = a - d % basis 1 /\
+          path_image q = path_image p /\
+          (!z. z IN inside(path_image p)
+               ==> winding_number(q,z) = winding_number(p,z))`
+    MP_TAC THENL
+     [EXISTS_TAC `shiftpath t (p:real^1->complex)` THEN
+      FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+      ASM_SIMP_TAC[PATHSTART_SHIFTPATH; PATHFINISH_SHIFTPATH; DROP_VEC;
+                   SIMPLE_PATH_SHIFTPATH; PATH_IMAGE_SHIFTPATH] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC WINDING_NUMBER_SHIFTPATH THEN
+      ASM_SIMP_TAC[SIMPLE_PATH_IMP_PATH] THEN
+      ASM_MESON_TAC[INSIDE_NO_OVERLAP; IN_INTER; NOT_IN_EMPTY];
+      DISCH_THEN(X_CHOOSE_THEN `q:real^1->complex` MP_TAC) THEN
+      REPLICATE_TAC 3 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+      REWRITE_TAC[IMP_CONJ] THEN DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+      SUBGOAL_THEN
+       `?z. z IN inside(path_image q) /\ norm(winding_number(q,z)) = &1`
+       (fun th -> MESON_TAC[th]) THEN
+      POP_ASSUM_LIST(MP_TAC o end_itlist CONJ o rev o
+          filter (fun tm -> not(free_in `t:real^1` (concl tm) or
+                                free_in `p:real^1->complex` (concl tm)))) THEN
+      STRIP_TAC] THEN
+    SUBGOAL_THEN
+     `?t. t IN interval[vec 0,vec 1] /\
+          (q:real^1->complex) t = a + e % basis 1`
+    STRIP_ASSUME_TAC THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[path_image; IN_IMAGE]) THEN
+      ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `~(a - d % basis 1:complex = a + e % basis 1)`
+    ASSUME_TAC THENL
+     [REWRITE_TAC[VECTOR_ARITH
+       `a - d % l:complex = a + e % l <=> (e + d) % l = vec 0`] THEN
+      SIMP_TAC[VECTOR_MUL_EQ_0; BASIS_NONZERO; DIMINDEX_2; ARITH] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+      `path_image q INTER segment[a - d % basis 1,a + e % basis 1] =
+       {a - d % basis 1:complex,a + e % basis 1}`
+    ASSUME_TAC THENL
+     [REWRITE_TAC[SEGMENT_CLOSED_OPEN] THEN
+      MATCH_MP_TAC(SET_RULE
+       `a IN p /\ b IN p /\ p INTER s = {}
+        ==> p INTER (s UNION {a,b}) = {a,b}`) THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE]; ALL_TAC] THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[path_image; IN_IMAGE]; ALL_TAC] THEN
+      ASM_SIMP_TAC[PATH_IMAGE_SUBPATH_SUBSET; SIMPLE_PATH_IMP_PATH;
+                   ENDS_IN_UNIT_INTERVAL] THEN
+      REWRITE_TAC[SET_RULE `s INTER t = {} <=> !x. x IN t ==> ~(x IN s)`] THEN
+      REWRITE_TAC[IN_SEGMENT; VECTOR_ARITH
+       `(&1 - u) % (a - d % l) + u % (a + e % l):complex =
+         a + (u * e - (&1 - u) * d) % l`] THEN
+      X_GEN_TAC `y:complex` THEN
+      DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC o CONJUNCT2) THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(MESON
+       [INSIDE_NO_OVERLAP; IN_INTER; NOT_IN_EMPTY]
+       `x IN inside s ==> ~(x IN s)`) THEN
+      ASM_CASES_TAC `&0 <= k * e - (&1 - k) * d` THENL
+       [ALL_TAC;
+        ONCE_REWRITE_TAC[VECTOR_ARITH
+         `a + (s - t) % l:complex = a - (t - s) % l`]] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_SIMP_TAC[REAL_ARITH `~(&0 <= a - b) ==> &0 <= b - a`] THEN
+      REWRITE_TAC[REAL_ARITH `k * e - (&1 - k) * d < e <=>
+                              &0 < (&1 - k) * (d + e)`] THEN
+      REWRITE_TAC[REAL_ARITH `(&1 - k) * d - k * e < d <=>
+                              &0 < k * (d + e)`] THEN
+      MATCH_MP_TAC REAL_LT_MUL THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`subpath t (vec 0) (q:real^1->complex)`;
+      `a:complex`; `d:real`; `e:real`] lemma2) THEN
+    ASM_SIMP_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH;
+                 PATH_IMAGE_JOIN; PATHSTART_LINEPATH] THEN
+    ANTS_TAC THENL
+     [CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[pathstart]] THEN
+      MATCH_MP_TAC SIMPLE_PATH_JOIN_LOOP THEN
+      ASM_REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH;
+                      PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+      ASM_REWRITE_TAC[ARC_LINEPATH_EQ] THEN REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC ARC_SIMPLE_PATH_SUBPATH THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[pathstart]) THEN
+        ASM_REWRITE_TAC[ENDS_IN_UNIT_INTERVAL];
+        RULE_ASSUM_TAC(REWRITE_RULE[pathstart]) THEN ASM_REWRITE_TAC[];
+        REWRITE_TAC[PATH_IMAGE_LINEPATH] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `p INTER s = {a,b} ==> p' SUBSET p ==> p' INTER s SUBSET {b,a}`)) THEN
+        ASM_SIMP_TAC[PATH_IMAGE_SUBPATH_SUBSET; SIMPLE_PATH_IMP_PATH;
+                     ENDS_IN_UNIT_INTERVAL]];
+      DISCH_THEN(X_CHOOSE_THEN `z:complex` STRIP_ASSUME_TAC)] THEN
+    MP_TAC(ISPECL
+     [`subpath (vec 0) t (q:real^1->complex)`;
+      `subpath (vec 1) t (q:real^1->complex)`;
+      `linepath(a - d % basis 1:complex,a + e % basis 1)`;
+      `a - d % basis 1:complex`; `a + e % basis 1:complex`;
+      `z:complex`;
+      `--winding_number
+          (subpath t (vec 0) q ++
+           linepath (a - d % basis 1,a + e % basis 1),z)`]
+      WINDING_NUMBER_FROM_INNERPATH) THEN
+    ASM_REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH;
+                    PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+    REWRITE_TAC[REVERSEPATH_SUBPATH; REVERSEPATH_LINEPATH] THEN
+    SUBGOAL_THEN
+     `path_image (subpath (vec 0) t q) UNION
+      path_image (subpath (vec 1) t q) :complex->bool =
+      path_image q`
+    SUBST1_TAC THENL
+     [FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+      SIMP_TAC[DROP_VEC; PATH_IMAGE_SUBPATH] THEN
+      ONCE_REWRITE_TAC[GSYM PATH_IMAGE_REVERSEPATH] THEN
+      REWRITE_TAC[REVERSEPATH_SUBPATH] THEN
+      SIMP_TAC[DROP_VEC; PATH_IMAGE_SUBPATH] THEN STRIP_TAC THEN
+      REWRITE_TAC[GSYM IMAGE_UNION; PATH_IMAGE_REVERSEPATH] THEN
+      SUBGOAL_THEN `interval[vec 0:real^1,t] UNION interval[t,vec 1] =
+                    interval[vec 0,vec 1]`
+        (fun th -> ASM_REWRITE_TAC[th; GSYM path_image]) THEN
+      REWRITE_TAC[EXTENSION; IN_UNION; IN_INTERVAL_1; DROP_VEC] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    ANTS_TAC THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+      REPLICATE_TAC 2 (ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC SIMPLE_PATH_SUBPATH THEN
+        ASM_REWRITE_TAC[ENDS_IN_UNIT_INTERVAL] THEN ASM_MESON_TAC[];
+        ALL_TAC]) THEN
+      ASM_REWRITE_TAC[SIMPLE_PATH_LINEPATH_EQ; PATH_IMAGE_LINEPATH] THEN
+      REPEAT CONJ_TAC THENL
+       [FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+        SIMP_TAC[DROP_VEC; PATH_IMAGE_SUBPATH] THEN
+        ONCE_REWRITE_TAC[GSYM PATH_IMAGE_REVERSEPATH] THEN
+        REWRITE_TAC[REVERSEPATH_SUBPATH] THEN
+        SIMP_TAC[DROP_VEC; PATH_IMAGE_SUBPATH] THEN STRIP_TAC THEN
+        MATCH_MP_TAC(SET_RULE
+          `a IN s /\ a IN t /\ b IN s /\ b IN t /\
+           (!x. x IN s ==> !y. y IN t ==> x = y ==> x = a \/ x = b)
+           ==> s INTER t = {a,b}`) THEN
+        REPEAT CONJ_TAC THENL
+         [REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `vec 0:real^1` THEN
+          ASM_REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN
+          ASM_REAL_ARITH_TAC;
+          REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `vec 1:real^1` THEN
+          ASM_REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN
+          ASM_REAL_ARITH_TAC;
+          REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `t:real^1` THEN
+          ASM_REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN
+          ASM_REAL_ARITH_TAC;
+          REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `t:real^1` THEN
+          ASM_REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN
+          ASM_REAL_ARITH_TAC;
+          ALL_TAC] THEN
+        REWRITE_TAC[FORALL_IN_IMAGE; IN_INTERVAL_1; DROP_VEC] THEN
+        X_GEN_TAC `s:real^1` THEN STRIP_TAC THEN
+        X_GEN_TAC `u:real^1` THEN STRIP_TAC THEN DISCH_TAC THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [simple_path]) THEN
+        DISCH_THEN(MP_TAC o SPECL [`s:real^1`; `u:real^1`] o CONJUNCT2) THEN
+        ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN
+        ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+        DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN
+          (REPEAT_TCL CONJUNCTS_THEN SUBST_ALL_TAC)) THEN
+        ASM_REWRITE_TAC[] THEN SUBGOAL_THEN `drop u = drop t` MP_TAC THENL
+         [ASM_REAL_ARITH_TAC; ASM_MESON_TAC[DROP_EQ]];
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `p INTER s = {a,b}
+          ==> a IN q /\ b IN q /\ q SUBSET p ==> q INTER s = {a,b}`)) THEN
+        ASM_SIMP_TAC[PATH_IMAGE_SUBPATH_SUBSET; SIMPLE_PATH_IMP_PATH;
+                     ENDS_IN_UNIT_INTERVAL] THEN
+        FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+        SIMP_TAC[DROP_VEC; PATH_IMAGE_SUBPATH] THEN STRIP_TAC THEN
+        REWRITE_TAC[IN_IMAGE] THEN CONJ_TAC THENL
+         [EXISTS_TAC `vec 0:real^1`; EXISTS_TAC `t:real^1`] THEN
+        ASM_REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN
+        ASM_REAL_ARITH_TAC;
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `p INTER s = {a,b}
+          ==> a IN q /\ b IN q /\ q SUBSET p ==> q INTER s = {a,b}`)) THEN
+        ASM_SIMP_TAC[PATH_IMAGE_SUBPATH_SUBSET; SIMPLE_PATH_IMP_PATH;
+                     ENDS_IN_UNIT_INTERVAL] THEN
+        ONCE_REWRITE_TAC[GSYM PATH_IMAGE_REVERSEPATH] THEN
+        REWRITE_TAC[REVERSEPATH_SUBPATH] THEN
+        FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+        SIMP_TAC[DROP_VEC; PATH_IMAGE_SUBPATH] THEN STRIP_TAC THEN
+        REWRITE_TAC[IN_IMAGE] THEN CONJ_TAC THENL
+         [EXISTS_TAC `vec 1:real^1`; EXISTS_TAC `t:real^1`] THEN
+        ASM_REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN
+        ASM_REAL_ARITH_TAC;
+        REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+        EXISTS_TAC `a:complex` THEN
+        ASM_REWRITE_TAC[GSYM BETWEEN_IN_SEGMENT; between] THEN
+        REWRITE_TAC[NORM_ARITH `dist(a - d:complex,a + e) = norm(d + e)`;
+              NORM_ARITH `dist(a - d:complex,a) = norm(d)`;
+              NORM_ARITH `dist(a:complex,a + e) = norm e`] THEN
+        ASM_SIMP_TAC[GSYM VECTOR_ADD_RDISTRIB; NORM_MUL;
+                 NORM_BASIS; DIMINDEX_2; ARITH] THEN
+        ASM_REAL_ARITH_TAC;
+        ONCE_REWRITE_TAC[GSYM PATH_IMAGE_REVERSEPATH] THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[PATH_IMAGE_LINEPATH]) THEN
+        ASM_REWRITE_TAC[REVERSEPATH_SUBPATH];
+        W(MP_TAC o PART_MATCH (rand o rand) WINDING_NUMBER_REVERSEPATH o
+          rand o snd) THEN
+        ANTS_TAC THENL
+         [ASM_SIMP_TAC[PATH_JOIN_EQ; PATH_IMAGE_JOIN; PATH_LINEPATH;
+            SIMPLE_PATH_IMP_PATH; PATHSTART_LINEPATH; PATHFINISH_SUBPATH;
+            PATH_SUBPATH; ENDS_IN_UNIT_INTERVAL] THEN
+          ASM_MESON_TAC[INSIDE_NO_OVERLAP; IN_INTER; NOT_IN_EMPTY];
+          DISCH_THEN(SUBST1_TAC o SYM) THEN
+          ASM_SIMP_TAC[REVERSEPATH_JOINPATHS; REVERSEPATH_LINEPATH;
+                       REVERSEPATH_SUBPATH; PATHFINISH_SUBPATH;
+                       PATHSTART_LINEPATH] THEN
+          MATCH_MP_TAC(MESON[COMPLEX_ADD_SYM]
+           `winding_number(g ++ h,z) =
+            winding_number(g,z) + winding_number(h,z) /\
+            winding_number(h ++ g,z) =
+            winding_number(h,z) + winding_number(g,z)
+            ==> winding_number(g ++ h,z) =winding_number(h ++ g,z)`) THEN
+          CONJ_TAC THEN MATCH_MP_TAC WINDING_NUMBER_JOIN THEN
+          ASM_SIMP_TAC[PATH_LINEPATH; PATH_SUBPATH; PATH_SUBPATH;
+                       SIMPLE_PATH_IMP_PATH; ENDS_IN_UNIT_INTERVAL;
+                       PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+                       PATHSTART_SUBPATH; PATHFINISH_SUBPATH]
+          THENL [ALL_TAC; ONCE_REWRITE_TAC[CONJ_SYM]] THEN
+          REWRITE_TAC[SET_RULE
+           `~(z IN s) /\ ~(z IN t) <=> ~(z IN s UNION t)`] THEN
+          ONCE_REWRITE_TAC[GSYM PATH_IMAGE_REVERSEPATH] THEN
+          REWRITE_TAC[REVERSEPATH_LINEPATH; REVERSEPATH_SUBPATH] THEN
+          ASM_MESON_TAC[INSIDE_NO_OVERLAP; IN_INTER; NOT_IN_EMPTY]];
+        REWRITE_TAC[COMPLEX_NEG_EQ_0] THEN DISCH_THEN SUBST_ALL_TAC THEN
+        RULE_ASSUM_TAC(REWRITE_RULE
+         [COMPLEX_NORM_CX; REAL_OF_NUM_EQ; REAL_ABS_NUM; ARITH]) THEN
+        FIRST_X_ASSUM CONTR_TAC];
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+      ONCE_REWRITE_TAC[COMPLEX_RING `a:complex = --b <=> --a = b`] THEN
+      DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[NORM_NEG])] THEN
+    EXISTS_TAC `z:complex` THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN
+     `winding_number(subpath (vec 0) t q ++ subpath t (vec 1) q,z) =
+      winding_number(subpath (vec 0) (vec 1) q,z)`
+     (fun th -> ASM_MESON_TAC[th; SUBPATH_TRIVIAL]) THEN
+    MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `winding_number(subpath (vec 0) t q,z) +
+                winding_number(subpath t (vec 1) q,z)` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC WINDING_NUMBER_JOIN THEN
+      ASM_SIMP_TAC[PATH_SUBPATH; ENDS_IN_UNIT_INTERVAL; SIMPLE_PATH_IMP_PATH;
+                   PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+      SUBGOAL_THEN `~((z:complex) IN path_image q)` MP_TAC THENL
+       [ASM_MESON_TAC[INSIDE_NO_OVERLAP; IN_INTER; NOT_IN_EMPTY];
+        MATCH_MP_TAC(SET_RULE
+          `s1 SUBSET s /\ s2 SUBSET s
+           ==> ~(z IN s) ==> ~(z IN s1) /\ ~(z IN s2)`) THEN
+        ASM_SIMP_TAC[PATH_IMAGE_SUBPATH_SUBSET; ENDS_IN_UNIT_INTERVAL;
+                  SIMPLE_PATH_IMP_PATH]];
+      MATCH_MP_TAC WINDING_NUMBER_SUBPATH_COMBINE THEN
+      ASM_REWRITE_TAC[ENDS_IN_INTERVAL; GSYM IN_INTERVAL_1] THEN
+      ASM_SIMP_TAC[UNIT_INTERVAL_NONEMPTY; SIMPLE_PATH_IMP_PATH] THEN
+      ASM_MESON_TAC[INSIDE_NO_OVERLAP; IN_INTER; NOT_IN_EMPTY]]) in
+  GEN_TAC THEN DISCH_TAC THEN
+  ASM_CASES_TAC `pathfinish g:complex = pathstart g` THENL
+   [ALL_TAC; ASM_MESON_TAC[INSIDE_SIMPLE_CURVE_IMP_CLOSED]] THEN
+  MATCH_MP_TAC(MESON[]
+   `(?k. !z. z IN s ==> f z = k) /\
+    (?z. z IN s /\ (f z = a \/ f z = b))
+    ==> (!z. z IN s ==> f z = a) \/ (!z. z IN s ==> f z = b)`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC WINDING_NUMBER_CONSTANT THEN
+    ASM_SIMP_TAC[INSIDE_NO_OVERLAP; SIMPLE_PATH_IMP_PATH] THEN
+    ASM_SIMP_TAC[JORDAN_INSIDE_OUTSIDE];
+    MP_TAC(SPEC `g:real^1->complex` lemma3) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `z:complex` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`]
+      INTEGER_WINDING_NUMBER) THEN
+    ANTS_TAC THENL
+     [ASM_SIMP_TAC[SIMPLE_PATH_IMP_PATH] THEN
+      ASM_MESON_TAC[INSIDE_NO_OVERLAP; IN_INTER; NOT_IN_EMPTY];
+      SIMP_TAC[complex_integer; COMPLEX_EQ; IM_NEG; IM_CX] THEN
+      SIMP_TAC[GSYM real; REAL_NORM; RE_NEG; RE_CX] THEN REAL_ARITH_TAC]]);;
+
+let SIMPLE_CLOSED_PATH_ABS_WINDING_NUMBER_INSIDE = prove
+ (`!g z. simple_path g /\ z IN inside(path_image g)
+         ==> abs(Re(winding_number(g,z))) = &1`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP
+    SIMPLE_CLOSED_PATH_WINDING_NUMBER_INSIDE) THEN
+  ASM_SIMP_TAC[RE_NEG; RE_CX; REAL_ABS_NUM; REAL_ABS_NEG]);;
+
+let SIMPLE_CLOSED_PATH_NORM_WINDING_NUMBER_INSIDE = prove
+ (`!g z. simple_path g /\ z IN inside(path_image g)
+         ==> norm(winding_number(g,z)) = &1`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `pathfinish g:complex = pathstart g` ASSUME_TAC THENL
+   [ASM_MESON_TAC[INSIDE_SIMPLE_CURVE_IMP_CLOSED]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`]
+      INTEGER_WINDING_NUMBER) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[SIMPLE_PATH_IMP_PATH] THEN
+    ASM_MESON_TAC[INSIDE_NO_OVERLAP; IN_INTER; NOT_IN_EMPTY];
+    ASM_SIMP_TAC[complex_integer; GSYM real; REAL_NORM;
+                 SIMPLE_CLOSED_PATH_ABS_WINDING_NUMBER_INSIDE]]);;
+
+let SIMPLE_CLOSED_PATH_WINDING_NUMBER_CASES = prove
+ (`!g z. simple_path g /\ pathfinish g = pathstart g /\ ~(z IN path_image g)
+         ==> winding_number(g,z) IN {--Cx(&1),Cx(&0),Cx(&1)}`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `path_image g:complex->bool` INSIDE_UNION_OUTSIDE) THEN
+  REWRITE_TAC[EXTENSION; IN_DIFF; IN_UNIV; IN_UNION] THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[WINDING_NUMBER_ZERO_IN_OUTSIDE; SIMPLE_PATH_IMP_PATH] THEN
+  ASM_MESON_TAC[SIMPLE_CLOSED_PATH_WINDING_NUMBER_INSIDE]);;
+
+let SIMPLE_CLOSED_PATH_WINDING_NUMBER_POS = prove
+ (`!g z. simple_path g /\ pathfinish g = pathstart g /\ ~(z IN path_image g) /\
+         &0 < Re(winding_number(g,z))
+         ==> winding_number(g,z) = Cx(&1)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`g:real^1->complex`; `z:complex`]
+      SIMPLE_CLOSED_PATH_WINDING_NUMBER_CASES) THEN
+  ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+  STRIP_TAC THEN UNDISCH_TAC `&0 < Re(winding_number(g,z))` THEN
+  ASM_REWRITE_TAC[RE_NEG; RE_CX] THEN REAL_ARITH_TAC);;
+
+let SIMPLY_CONNECTED_IMP_WINDING_NUMBER_ZERO = prove
+ (`!s g z. simply_connected s /\
+           path g /\ path_image g SUBSET s /\
+           pathfinish g = pathstart g /\ ~(z IN s)
+           ==> winding_number(g,z) = Cx(&0)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `winding_number(linepath(pathstart g,pathstart g),z)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC WINDING_NUMBER_HOMOTOPIC_PATHS THEN
+    MATCH_MP_TAC HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_PATHS_NULL THEN
+    EXISTS_TAC `pathstart(g:real^1->complex)` THEN
+    MATCH_MP_TAC HOMOTOPIC_LOOPS_SUBSET THEN
+    EXISTS_TAC `s:complex->bool` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [simply_connected]) THEN
+    ASM_REWRITE_TAC[PATH_LINEPATH; PATHSTART_LINEPATH;
+                    PATHFINISH_LINEPATH; PATH_IMAGE_LINEPATH; SEGMENT_REFL;
+                    INSERT_SUBSET; EMPTY_SUBSET];
+    MATCH_MP_TAC WINDING_NUMBER_TRIVIAL] THEN
+  MP_TAC(ISPEC `g:real^1->complex` PATHSTART_IN_PATH_IMAGE) THEN
+  ASM SET_TAC[]);;
+
+let NO_BOUNDED_CONNECTED_COMPONENT_IMP_WINDING_NUMBER_ZERO = prove
+ (`!s. ~(?z. ~(z IN s) /\ bounded(connected_component ((:complex) DIFF s) z))
+       ==> !g z. path g /\ path_image g SUBSET s /\
+                 pathfinish g = pathstart g /\ ~(z IN s)
+                 ==> winding_number(g,z) = Cx(&0)`,
+  REWRITE_TAC[NOT_EXISTS_THM] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC WINDING_NUMBER_ZERO_IN_OUTSIDE THEN
+  ASM_REWRITE_TAC[outside; IN_ELIM_THM] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[CONTRAPOS_THM] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] BOUNDED_SUBSET) THEN
+  MATCH_MP_TAC CONNECTED_COMPONENT_MONO THEN ASM SET_TAC[]);;
+
+let NO_BOUNDED_PATH_COMPONENT_IMP_WINDING_NUMBER_ZERO = prove
+ (`!s. ~(?z. ~(z IN s) /\ bounded(path_component ((:complex) DIFF s) z))
+       ==> !g z. path g /\ path_image g SUBSET s /\
+                 pathfinish g = pathstart g /\ ~(z IN s)
+                 ==> winding_number(g,z) = Cx(&0)`,
+  GEN_TAC THEN DISCH_TAC THEN
+  MATCH_MP_TAC NO_BOUNDED_CONNECTED_COMPONENT_IMP_WINDING_NUMBER_ZERO THEN
+  ASM_MESON_TAC[PATH_COMPONENT_SUBSET_CONNECTED_COMPONENT; BOUNDED_SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Partial circle path.                                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let partcirclepath = new_definition
+ `partcirclepath(z,r,s,t) =
+    \x. z + Cx(r) * cexp(ii * linepath(Cx(s),Cx(t)) x)`;;
+
+let PATHSTART_PARTCIRCLEPATH = prove
+ (`!r z s t. pathstart(partcirclepath(z,r,s,t)) =
+                z + Cx(r) * cexp(ii * Cx(s))`,
+  REWRITE_TAC[pathstart; partcirclepath;
+              REWRITE_RULE[pathstart] PATHSTART_LINEPATH]);;
+
+let PATHFINISH_PARTCIRCLEPATH = prove
+ (`!r z s t. pathfinish(partcirclepath(z,r,s,t)) =
+                z + Cx(r) * cexp(ii * Cx(t))`,
+  REWRITE_TAC[pathfinish; partcirclepath;
+              REWRITE_RULE[pathfinish] PATHFINISH_LINEPATH]);;
+
+let HAS_VECTOR_DERIVATIVE_PARTCIRCLEPATH = prove
+ (`!z r s t x.
+        ((partcirclepath(z,r,s,t)) has_vector_derivative
+         (ii * Cx(r) * (Cx t - Cx s) * cexp(ii * linepath(Cx(s),Cx(t)) x)))
+        (at x)`,
+  REWRITE_TAC[partcirclepath; linepath; COMPLEX_CMUL; CX_SUB] THEN
+  REPEAT GEN_TAC THEN MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_REAL_COMPLEX THEN
+  COMPLEX_DIFF_TAC THEN CONV_TAC COMPLEX_RING);;
+
+let VECTOR_DERIVATIVE_PARTCIRCLEPATH = prove
+ (`!z r s t x.
+        vector_derivative (partcirclepath(z,r,s,t)) (at x) =
+        ii * Cx(r) * (Cx t - Cx s) * cexp(ii * linepath(Cx(s),Cx(t)) x)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC VECTOR_DERIVATIVE_AT THEN
+  REWRITE_TAC[HAS_VECTOR_DERIVATIVE_PARTCIRCLEPATH]);;
+
+let VALID_PATH_PARTCIRCLEPATH = prove
+ (`!z r s t. valid_path(partcirclepath(z,r,s,t))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[valid_path] THEN
+  MATCH_MP_TAC DIFFERENTIABLE_ON_IMP_PIECEWISE_DIFFERENTIABLE THEN
+  REWRITE_TAC[differentiable_on] THEN X_GEN_TAC `x:real^1` THEN STRIP_TAC THEN
+  MATCH_MP_TAC DIFFERENTIABLE_AT_WITHIN THEN
+  REWRITE_TAC[VECTOR_DERIVATIVE_WORKS; VECTOR_DERIVATIVE_PARTCIRCLEPATH;
+              HAS_VECTOR_DERIVATIVE_PARTCIRCLEPATH]);;
+
+let PATH_PARTCIRCLEPATH = prove
+ (`!z r s t. path(partcirclepath(z,r,s,t))`,
+  SIMP_TAC[VALID_PATH_PARTCIRCLEPATH; VALID_PATH_IMP_PATH]);;
+
+let PATH_IMAGE_PARTCIRCLEPATH = prove
+ (`!z r s t.
+        &0 <= r /\ s <= t
+        ==> path_image(partcirclepath(z,r,s,t)) =
+                {z + Cx(r) * cexp(ii * Cx x) | s <= x /\ x <= t}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[path_image; partcirclepath] THEN
+  REWRITE_TAC[EXTENSION; TAUT `(a <=> b) <=> (a ==> b) /\ (b ==> a)`] THEN
+  REWRITE_TAC[FORALL_AND_THM; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+  CONJ_TAC THENL
+   [X_GEN_TAC `x:real^1` THEN REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN
+    DISCH_TAC THEN EXISTS_TAC `(&1 - drop x) * s + drop x * t` THEN
+    REWRITE_TAC[linepath; CX_ADD; CX_SUB; COMPLEX_CMUL; CX_MUL] THEN
+    REWRITE_TAC[REAL_ARITH `s <= (&1 - x) * s + x * t <=> &0 <= x * (t - s)`;
+      REAL_ARITH `(&1 - x) * s + x * t <= t <=> &0 <= (&1 - x) * (t - s)`] THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; REAL_SUB_LE];
+    ALL_TAC] THEN
+  X_GEN_TAC `w:complex` THEN
+  DISCH_THEN(X_CHOOSE_THEN `x:real` STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[IN_IMAGE] THEN ASM_CASES_TAC `s:real < t` THENL
+   [EXISTS_TAC `lift((x - s) / (t - s))` THEN
+    ASM_SIMP_TAC[IN_INTERVAL_1; REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; REAL_SUB_LT;
+                 LIFT_DROP; DROP_VEC; linepath; REAL_MUL_LZERO; REAL_MUL_LID;
+                 REAL_SUB_LE; REAL_ARITH `x - s:real <= t - s <=> x <= t`] THEN
+    AP_TERM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    REWRITE_TAC[COMPLEX_CMUL; CX_SUB; CX_DIV] THEN
+    SUBGOAL_THEN `~(Cx(s) = Cx(t))` MP_TAC THENL
+     [ASM_SIMP_TAC[CX_INJ; REAL_LT_IMP_NE]; CONV_TAC COMPLEX_FIELD];
+    UNDISCH_TAC `s:real <= t` THEN ASM_REWRITE_TAC[REAL_LE_LT] THEN
+    DISCH_THEN SUBST_ALL_TAC THEN EXISTS_TAC `vec 0:real^1` THEN
+    SIMP_TAC[IN_INTERVAL_1; DROP_VEC; linepath; VECTOR_MUL_LZERO;
+             REAL_SUB_RZERO; VECTOR_MUL_LID; VECTOR_ADD_RID; REAL_POS] THEN
+    AP_TERM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    REWRITE_TAC[CX_INJ] THEN ASM_REAL_ARITH_TAC]);;
+
+let PATH_IMAGE_PARTCIRCLEPATH_SUBSET = prove
+ (`!z r s t.
+        &0 <= r /\ s <= t
+        ==> path_image(partcirclepath(z,r,s,t)) SUBSET sphere(z,r)`,
+  SIMP_TAC[PATH_IMAGE_PARTCIRCLEPATH] THEN
+  SIMP_TAC[SUBSET; IN_ELIM_THM; IN_SPHERE; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[NORM_ARITH `dist(z,z + a) = norm a`] THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL; NORM_CEXP; COMPLEX_NORM_CX;
+              RE_MUL_II; IM_CX; REAL_NEG_0; REAL_EXP_0] THEN
+  REAL_ARITH_TAC);;
+
+let IN_PATH_IMAGE_PARTCIRCLEPATH = prove
+ (`!z r s t w.
+        &0 <= r /\ s <= t /\ w IN path_image(partcirclepath(z,r,s,t))
+        ==> norm(w - z) = r`,
+  MP_TAC PATH_IMAGE_PARTCIRCLEPATH_SUBSET THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  REWRITE_TAC[SUBSET; IN_SPHERE; dist; NORM_SUB] THEN SET_TAC[]);;
+
+let HAS_PATH_INTEGRAL_BOUND_PARTCIRCLEPATH_STRONG = prove
+ (`!f i z r s t B k.
+        FINITE k /\
+        (f has_path_integral i) (partcirclepath(z,r,s,t)) /\
+        &0 <= B /\ &0 < r /\ s <= t /\
+        (!x. x IN path_image(partcirclepath(z,r,s,t)) DIFF k
+             ==> norm(f x) <= B)
+        ==> norm(i) <= B * r * (t - s)`,
+  let lemma1 = prove
+   (`!b w. FINITE {z | norm(z) <= b /\ cexp(z) = w}`,
+    REPEAT GEN_TAC THEN ASM_CASES_TAC `w = Cx(&0)` THEN
+    ASM_REWRITE_TAC[CEXP_NZ; SET_RULE `{x | F} = {}`; FINITE_RULES] THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP CEXP_CLOG) THEN
+    REWRITE_TAC[CEXP_EQ] THEN
+    REWRITE_TAC[SET_RULE
+     `{z | P z /\ ?n. Q n /\ z = f n} = IMAGE f {n | Q n /\ P(f n)}`] THEN
+    MATCH_MP_TAC FINITE_IMAGE THEN
+    MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC `{n | integer n /\
+                     norm(Cx (&2 * n * pi) * ii) <= b + norm(clog w)}` THEN
+    CONJ_TAC THENL
+     [ALL_TAC; SIMP_TAC[SUBSET; IN_ELIM_THM] THEN NORM_ARITH_TAC] THEN
+    REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX; COMPLEX_NORM_II] THEN
+    REWRITE_TAC[REAL_MUL_RID; REAL_ABS_MUL; REAL_ABS_NUM; REAL_ABS_PI] THEN
+    ASM_SIMP_TAC[REAL_MUL_ASSOC; GSYM REAL_LE_RDIV_EQ; PI_POS] THEN
+    REWRITE_TAC[REAL_ARITH `&2 * x <= a <=> x <= a / &2`] THEN
+    REWRITE_TAC[GSYM REAL_BOUNDS_LE; FINITE_INTSEG]) in
+  let lemma2 = prove
+   (`!a b. ~(a = Cx(&0)) ==> FINITE {z | norm(z) <= b /\ cexp(a * z) = w}`,
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC
+     `IMAGE (\z. z / a) {z | norm(z) <= b * norm(a) /\ cexp(z) = w}` THEN
+    SIMP_TAC[lemma1; FINITE_IMAGE] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    REWRITE_TAC[SUBSET; IN_IMAGE; IN_ELIM_THM] THEN
+    ASM_SIMP_TAC[COMPLEX_FIELD `~(a = Cx(&0)) ==> (x = y / a <=> a * x = y)`;
+                 UNWIND_THM1; COMPLEX_NORM_MUL; REAL_LE_LMUL; NORM_POS_LE]) in
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_PATH_INTEGRAL] THEN STRIP_TAC THEN
+  MP_TAC(ASSUME `s <= t`) THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  STRIP_TAC THENL
+   [ALL_TAC;
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN
+    REWRITE_TAC[VECTOR_DERIVATIVE_PARTCIRCLEPATH] THEN
+    REWRITE_TAC[COMPLEX_SUB_REFL; COMPLEX_MUL_LZERO; COMPLEX_MUL_RZERO] THEN
+    SIMP_TAC[GSYM COMPLEX_VEC_0; HAS_INTEGRAL_0_EQ; NORM_0] THEN
+    REAL_ARITH_TAC] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
+  REWRITE_TAC[GSYM CONTENT_UNIT_1] THEN MATCH_MP_TAC HAS_INTEGRAL_BOUND THEN
+  EXISTS_TAC `\x. if (partcirclepath(z,r,s,t) x) IN k then Cx(&0)
+                  else f(partcirclepath(z,r,s,t) x) *
+                       vector_derivative (partcirclepath(z,r,s,t)) (at x)` THEN
+  ASM_SIMP_TAC[] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[REAL_LE_MUL; REAL_POS; REAL_LT_IMP_LE; REAL_SUB_LE];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC HAS_INTEGRAL_SPIKE THEN
+    EXISTS_TAC `\x. f(partcirclepath(z,r,s,t) x) *
+                    vector_derivative (partcirclepath(z,r,s,t)) (at x)` THEN
+    EXISTS_TAC `{x | x IN interval[vec 0,vec 1] /\
+                     (partcirclepath(z,r,s,t) x) IN k}` THEN
+    ASM_SIMP_TAC[IN_DIFF; IN_ELIM_THM; IMP_CONJ] THEN
+    MATCH_MP_TAC NEGLIGIBLE_FINITE THEN
+    MATCH_MP_TAC FINITE_FINITE_PREIMAGE_GENERAL THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `y:complex` THEN DISCH_TAC THEN
+    REWRITE_TAC[partcirclepath] THEN
+    ASM_SIMP_TAC[CX_INJ; REAL_LT_IMP_NZ; COMPLEX_FIELD
+     `~(r = Cx(&0)) ==> (z + r * e = y <=> e = (y - z) / r)`] THEN
+    REWRITE_TAC[linepath; COMPLEX_CMUL] THEN
+    REWRITE_TAC[GSYM CX_MUL; GSYM CX_ADD] THEN
+    REWRITE_TAC[REAL_ARITH `(&1 - t) * x + t * y = x + t * (y - x)`] THEN
+    REWRITE_TAC[CX_ADD; COMPLEX_ADD_LDISTRIB; CEXP_ADD] THEN
+    SIMP_TAC[CEXP_NZ; COMPLEX_FIELD
+     `~(e = Cx(&0)) ==> (e * x = y <=> x = y / e)`] THEN
+    ABBREV_TAC `w = (y - z) / Cx r / cexp(ii * Cx s)` THEN
+    REWRITE_TAC[CX_MUL; COMPLEX_RING
+     `ii * Cx x * Cx(t - s) = (ii * Cx(t - s)) * Cx x`] THEN
+    MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC
+     `{x | Cx(drop x) IN
+           {z | norm(z) <= &1 /\ cexp((ii * Cx(t - s)) * z) = w}}` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC FINITE_IMAGE_INJ THEN REWRITE_TAC[CX_INJ; DROP_EQ] THEN
+      MATCH_MP_TAC lemma2 THEN
+      REWRITE_TAC[COMPLEX_RING `ii * x = Cx(&0) <=> x = Cx(&0)`] THEN
+      ASM_SIMP_TAC[CX_INJ; REAL_SUB_0; REAL_LT_IMP_NE];
+      SIMP_TAC[SUBSET; IN_ELIM_THM; IN_INTERVAL_1; DROP_VEC] THEN
+      SIMP_TAC[COMPLEX_NORM_CX] THEN REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  X_GEN_TAC `x:real^1` THEN DISCH_TAC THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[COMPLEX_NORM_0] THEN
+  ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE; REAL_SUB_LE] THEN
+  REWRITE_TAC[VECTOR_DERIVATIVE_PARTCIRCLEPATH] THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX; COMPLEX_NORM_II] THEN
+  REWRITE_TAC[REAL_ABS_NUM; REAL_MUL_LID] THEN
+  REWRITE_TAC[NORM_CEXP; RE_MUL_II; IM_LINEPATH_CX] THEN
+  REWRITE_TAC[REAL_EXP_0; REAL_NEG_0; REAL_MUL_RID] THEN
+  MATCH_MP_TAC REAL_LE_MUL2 THEN REWRITE_TAC[NORM_POS_LE] THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[path_image] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SIMP_TAC[REAL_LE_MUL; NORM_POS_LE; REAL_ABS_POS] THEN
+  MATCH_MP_TAC REAL_LE_MUL2 THEN
+  ASM_SIMP_TAC[NORM_POS_LE; GSYM CX_SUB; COMPLEX_NORM_CX] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let HAS_PATH_INTEGRAL_BOUND_PARTCIRCLEPATH = prove
+ (`!f i z r s t B.
+        (f has_path_integral i) (partcirclepath(z,r,s,t)) /\
+        &0 <= B /\ &0 < r /\ s <= t /\
+        (!x. x IN path_image(partcirclepath(z,r,s,t))
+             ==> norm(f x) <= B)
+        ==> norm(i) <= B * r * (t - s)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_PARTCIRCLEPATH_STRONG THEN
+  MAP_EVERY EXISTS_TAC
+   [`f:complex->complex`; `z:complex`; `{}:complex->bool`] THEN
+  ASM_REWRITE_TAC[FINITE_RULES; IN_DIFF; NOT_IN_EMPTY]);;
+
+let PATH_INTEGRABLE_CONTINUOUS_PARTCIRCLEPATH = prove
+ (`!f z r s t. f continuous_on path_image(partcirclepath(z,r,s,t))
+               ==> f path_integrable_on (partcirclepath(z,r,s,t))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[path_integrable_on; HAS_PATH_INTEGRAL] THEN
+  REWRITE_TAC[VECTOR_DERIVATIVE_PARTCIRCLEPATH; GSYM integrable_on] THEN
+  DISCH_TAC THEN MATCH_MP_TAC INTEGRABLE_CONTINUOUS THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    ASM_REWRITE_TAC[GSYM path_image; ETA_AX] THEN
+    MATCH_MP_TAC PIECEWISE_DIFFERENTIABLE_ON_IMP_CONTINUOUS_ON THEN
+    ASM_REWRITE_TAC[GSYM valid_path; VALID_PATH_PARTCIRCLEPATH];
+    ALL_TAC] THEN
+  REWRITE_TAC[linepath] THEN
+  REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN
+         REWRITE_TAC[CONTINUOUS_ON_CONST]) THEN
+  ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  REWRITE_TAC[CONTINUOUS_ON_CEXP] THEN
+  REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN
+         REWRITE_TAC[CONTINUOUS_ON_CONST]) THEN
+  REWRITE_TAC[VECTOR_ARITH `(&1 - x) % s + x % t = s + x % (t - s)`] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_ADD THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+  MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN
+  REWRITE_TAC[linear; DROP_ADD; DROP_CMUL; CX_ADD; COMPLEX_CMUL; CX_MUL;
+              CX_SUB] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let WINDING_NUMBER_PARTCIRCLEPATH_POS_LT = prove
+ (`!r z s t w.
+        s < t /\ norm(w - z) < r
+        ==> &0 < Re(winding_number(partcirclepath(z,r,s,t),w))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC WINDING_NUMBER_POS_LT THEN
+  EXISTS_TAC `r * (t - s) * (r - norm(w - z:complex))` THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP (REAL_ARITH
+   `n < r ==> &0 <= n ==> &0 < r`)) THEN
+  REWRITE_TAC[NORM_POS_LE] THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[REAL_LT_MUL; REAL_SUB_LT; VALID_PATH_PARTCIRCLEPATH] THEN
+  ASM_REWRITE_TAC[VALID_PATH_PARTCIRCLEPATH] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[IN_PATH_IMAGE_PARTCIRCLEPATH; REAL_LT_IMP_LE; REAL_LT_REFL];
+    ALL_TAC] THEN
+  X_GEN_TAC `x:real^1` THEN DISCH_TAC THEN
+  REWRITE_TAC[VECTOR_DERIVATIVE_PARTCIRCLEPATH] THEN
+  REWRITE_TAC[partcirclepath] THEN
+  REWRITE_TAC[GSYM COMPLEX_MUL_ASSOC; IM_MUL_II; RE_MUL_CX; GSYM CX_SUB] THEN
+  REWRITE_TAC[CNJ_ADD; CNJ_SUB; CNJ_MUL; CNJ_CX] THEN
+  REWRITE_TAC[COMPLEX_RING
+   `c * ((z + r * c') - w):complex = r * c * c' - c * (w - z)`] THEN
+  REWRITE_TAC[COMPLEX_MUL_CNJ; NORM_CEXP; RE_MUL_II] THEN
+  REWRITE_TAC[IM_LINEPATH_CX; REAL_NEG_0; REAL_EXP_0; COMPLEX_MUL_RID;
+              COMPLEX_POW_2] THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_SUB_LT; RE_SUB; RE_CX] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `norm(x) <= norm(y) /\ abs(Re(x)) <= norm(x)
+    ==> r - norm(y) <= r - Re x`) THEN
+  REWRITE_TAC[COMPLEX_NORM_GE_RE_IM] THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL; NORM_CEXP; RE_MUL_II; IM_LINEPATH_CX] THEN
+  REWRITE_TAC[REAL_EXP_0; REAL_NEG_0; REAL_MUL_LID; GSYM CNJ_SUB] THEN
+  REWRITE_TAC[COMPLEX_NORM_CNJ; REAL_LE_REFL]);;
+
+let SIMPLE_PATH_PARTCIRCLEPATH = prove
+ (`!z r s t. simple_path(partcirclepath(z,r,s,t)) <=>
+                ~(r = &0) /\ ~(s = t) /\ abs(s - t) <= &2 * pi`,
+  let lemma = prove
+   (`(!x y. (&0 <= x /\ x <= &1) /\ (&0 <= y /\ y <= &1) ==> P(abs(x - y))) <=>
+     (!x. &0 <= x /\ x <= &1 ==> P x)`,
+    MESON_TAC[REAL_ARITH `(&0 <= x /\ x <= &1) /\ (&0 <= y /\ y <= &1)
+                          ==> &0 <= abs(x - y) /\ abs(x - y) <= &1`;
+              REAL_ARITH `&0 <= &0 /\ &0 <= &1`;
+              REAL_ARITH `(&0 <= x ==> abs(x - &0) = x)`]) in
+  REPEAT GEN_TAC THEN REWRITE_TAC[simple_path; PATH_PARTCIRCLEPATH] THEN
+  REWRITE_TAC[partcirclepath] THEN
+  SIMP_TAC[COMPLEX_RING `z + r * x = z + r * y <=> r * (x - y) = Cx(&0)`] THEN
+  REWRITE_TAC[COMPLEX_ENTIRE; CX_INJ] THEN
+  ASM_CASES_TAC `r = &0` THEN ASM_REWRITE_TAC[] THENL
+   [DISCH_THEN(MP_TAC o SPECL [`lift(&1 / &3)`; `lift(&1 / &2)`]) THEN
+    REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP; GSYM LIFT_NUM; LIFT_EQ] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  ASM_CASES_TAC `s:real = t` THEN ASM_REWRITE_TAC[] THENL
+   [DISCH_THEN(MP_TAC o SPECL [`lift(&1 / &3)`; `lift(&1 / &2)`]) THEN
+    REWRITE_TAC[linepath; VECTOR_ARITH `(&1 - t) % x + t % x = x`] THEN
+    REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP; GSYM LIFT_NUM; LIFT_EQ] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[COMPLEX_SUB_0];
+    ALL_TAC] THEN
+  REWRITE_TAC[COMPLEX_SUB_0; CEXP_EQ] THEN
+  REWRITE_TAC[COMPLEX_RING
+   `ii * x = ii * y + z * ii <=> ii * (x - (y + z)) = Cx(&0)`] THEN
+  REWRITE_TAC[COMPLEX_ENTIRE; II_NZ; LINEPATH_CX] THEN
+  REWRITE_TAC[GSYM CX_SUB; GSYM CX_ADD; CX_INJ] THEN
+  REWRITE_TAC[REAL_ARITH
+   `((&1 - x) * s + x * t) - (((&1 - y) * s + y * t) + z) = &0 <=>
+    (x - y) * (t - s) = z`] THEN
+  REWRITE_TAC[GSYM DROP_EQ; DROP_VEC; IN_INTERVAL_1] THEN
+  SIMP_TAC[REAL_ARITH
+   `&0 <= x /\ x <= &1 /\ &0 <= y /\ y <= &1
+    ==> (x = y \/ x = &0 /\ y = &1 \/ x = &1 /\ y = &0 <=>
+         abs(x - y) = &0 \/ abs(x - y) = &1)`] THEN
+  SIMP_TAC[PI_POS; REAL_FIELD
+   `&0 < pi ==> (x = &2 * n * pi <=> n = x / (&2 * pi))`] THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[CONJ_SYM] UNWIND_THM2] THEN
+  ONCE_REWRITE_TAC[GSYM INTEGER_ABS] THEN
+  REWRITE_TAC[GSYM FORALL_DROP; REAL_ABS_MUL; REAL_ABS_DIV] THEN
+  REWRITE_TAC[REAL_ABS_NUM; REAL_ABS_PI] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`] THEN
+  REWRITE_TAC[lemma] THEN EQ_TAC THENL
+   [DISCH_THEN(MP_TAC o SPEC `(&2 * pi) / abs(t - s)`) THEN
+    ASM_SIMP_TAC[REAL_ABS_SUB; REAL_FIELD
+     `~(s = t) ==> x / abs(s - t) * abs(s - t) = x`] THEN
+    ASM_SIMP_TAC[PI_POS; INTEGER_CLOSED; REAL_FIELD
+     `&0 < pi ==> (&2 * pi) / (&2 * pi) = &1`] THEN
+    ASM_SIMP_TAC[REAL_EQ_LDIV_EQ; REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ;
+                 GSYM REAL_ABS_NZ; REAL_SUB_0] THEN
+    MP_TAC PI_POS THEN REAL_ARITH_TAC;
+    DISCH_TAC THEN X_GEN_TAC `x:real` THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+       REAL_ABS_INTEGER_LEMMA)) THEN
+    SIMP_TAC[REAL_ABS_DIV; REAL_ABS_MUL; REAL_ABS_ABS; REAL_ABS_NUM;
+             REAL_ABS_PI] THEN
+    SIMP_TAC[REAL_EQ_LDIV_EQ; REAL_LE_RDIV_EQ; PI_POS; REAL_LT_MUL;
+             REAL_OF_NUM_LT; ARITH] THEN
+    ASM_CASES_TAC `x = &0` THEN ASM_REWRITE_TAC[REAL_MUL_LZERO] THEN
+    ASM_REWRITE_TAC[REAL_ENTIRE; REAL_MUL_LID;
+                    REAL_ARITH `abs(t - s) = &0 <=> s = t`] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+     `p <= x * abs(s - t)
+      ==> abs(s - t) <= p ==> &1 * abs(s - t) <= x * abs(s - t)`)) THEN
+    ONCE_REWRITE_TAC[REAL_ABS_SUB] THEN ASM_REWRITE_TAC[] THEN
+    ASM_SIMP_TAC[REAL_LE_RMUL_EQ; GSYM REAL_ABS_NZ; REAL_SUB_0] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let ARC_PARTCIRCLEPATH = prove
+ (`!z r s t. ~(r = &0) /\ ~(s = t) /\ abs(s - t) < &2 * pi
+             ==> arc(partcirclepath(z,r,s,t))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[arc; PATH_PARTCIRCLEPATH] THEN
+  REWRITE_TAC[partcirclepath] THEN
+  SIMP_TAC[COMPLEX_RING `z + r * x = z + r * y <=> r * (x - y) = Cx(&0)`] THEN
+  ASM_REWRITE_TAC[COMPLEX_ENTIRE; CX_INJ] THEN
+  REWRITE_TAC[COMPLEX_SUB_0; CEXP_EQ] THEN
+  REWRITE_TAC[COMPLEX_RING
+   `ii * x = ii * y + z * ii <=> ii * (x - (y + z)) = Cx(&0)`] THEN
+  REWRITE_TAC[COMPLEX_ENTIRE; II_NZ; LINEPATH_CX] THEN
+  REWRITE_TAC[GSYM CX_SUB; GSYM CX_ADD; CX_INJ] THEN
+  REWRITE_TAC[REAL_ARITH
+   `((&1 - x) * s + x * t) - (((&1 - y) * s + y * t) + z) = &0 <=>
+    (x - y) * (t - s) = z`] THEN
+  REPEAT GEN_TAC THEN DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `n:real` MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_CASES_TAC `n = &0` THEN
+  ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_RZERO; REAL_ENTIRE; REAL_SUB_0;
+                  DROP_EQ] THEN
+  MP_TAC(SPEC `n:real` REAL_ABS_INTEGER_LEMMA) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_THEN(K ALL_TAC) THEN
+  MATCH_MP_TAC(REAL_ARITH `abs x < abs y ==> ~(x = y)`) THEN
+  REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_NUM; REAL_ABS_PI] THEN
+  MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `&1 * &2 * pi` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[REAL_ARITH `&2 * n * pi = n * &2 * pi`] THEN
+    MATCH_MP_TAC REAL_LE_RMUL THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC PI_POS THEN REAL_ARITH_TAC] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `&1 * abs(t - s)` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_REWRITE_TAC[REAL_MUL_LID] THEN ASM_MESON_TAC[REAL_ABS_SUB]] THEN
+  MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[REAL_ABS_POS] THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1])) THEN
+  REWRITE_TAC[DROP_VEC] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Special case of one complete circle.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let circlepath = new_definition
+ `circlepath(z,r) = partcirclepath(z,r,&0,&2 * pi)`;;
+
+let CIRCLEPATH = prove
+ (`circlepath(z,r) = \x. z + Cx(r) * cexp(Cx(&2) * Cx pi * ii * Cx(drop x))`,
+  REWRITE_TAC[circlepath; partcirclepath; linepath; COMPLEX_CMUL] THEN
+  REWRITE_TAC[COMPLEX_MUL_RZERO; COMPLEX_ADD_LID] THEN
+  REWRITE_TAC[CX_MUL; COMPLEX_MUL_AC]);;
+
+let PATHSTART_CIRCLEPATH = prove
+ (`!r z. pathstart(circlepath(z,r)) = z + Cx(r)`,
+  REWRITE_TAC[circlepath; PATHSTART_PARTCIRCLEPATH] THEN
+  REWRITE_TAC[COMPLEX_MUL_RZERO; CEXP_0; COMPLEX_MUL_RID]);;
+
+let PATHFINISH_CIRCLEPATH = prove
+ (`!r z. pathfinish(circlepath(z,r)) = z + Cx(r)`,
+  REWRITE_TAC[circlepath; PATHFINISH_PARTCIRCLEPATH] THEN
+  REWRITE_TAC[CEXP_EULER; GSYM CX_COS; GSYM CX_SIN] THEN
+  REWRITE_TAC[SIN_NPI; COS_NPI; REAL_POW_NEG; ARITH; REAL_POW_ONE] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let HAS_VECTOR_DERIVATIVE_CIRCLEPATH = prove
+ (`((circlepath (z,r)) has_vector_derivative
+    (Cx(&2) * Cx(pi) * ii * Cx(r) * cexp(Cx(&2) * Cx pi * ii * Cx(drop x))))
+   (at x)`,
+  REWRITE_TAC[CIRCLEPATH] THEN
+  MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_REAL_COMPLEX THEN
+  COMPLEX_DIFF_TAC THEN CONV_TAC COMPLEX_RING);;
+
+let VECTOR_DERIVATIVE_CIRCLEPATH = prove
+ (`vector_derivative (circlepath (z,r)) (at x) =
+        Cx(&2) * Cx(pi) * ii * Cx(r) * cexp(Cx(&2) * Cx pi * ii * Cx(drop x))`,
+  MATCH_MP_TAC VECTOR_DERIVATIVE_AT THEN
+  REWRITE_TAC[HAS_VECTOR_DERIVATIVE_CIRCLEPATH]);;
+
+let VALID_PATH_CIRCLEPATH = prove
+ (`!z r. valid_path (circlepath(z,r))`,
+  REWRITE_TAC[circlepath; VALID_PATH_PARTCIRCLEPATH]);;
+
+let PATH_IMAGE_CIRCLEPATH = prove
+ (`!z r. &0 <= r ==> path_image (circlepath(z,r)) = sphere(z,r)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CIRCLEPATH; path_image] THEN
+  REWRITE_TAC[sphere; NORM_ARITH `dist(w,z) = norm(z - w)`] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[IN_ELIM_THM; COMPLEX_RING `(z + r) - z = r:complex`] THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL; NORM_CEXP] THEN CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[COMPLEX_RING
+     `Cx(&2) * p * i * z = (Cx(&2) * p * z) * i`] THEN
+    REWRITE_TAC[RE_MUL_II; GSYM CX_MUL; IM_CX] THEN
+    REWRITE_TAC[REAL_EXP_NEG; REAL_EXP_0; REAL_MUL_RID; COMPLEX_NORM_CX] THEN
+    POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  X_GEN_TAC `x:complex` THEN DISCH_TAC THEN ABBREV_TAC `w:complex = x - z` THEN
+  FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP (COMPLEX_RING
+   `x - z = w:complex ==> x = z + w`)) THEN
+  REWRITE_TAC[IN_IMAGE; COMPLEX_RING `z + a = z + b:complex <=> a = b`] THEN
+  ASM_CASES_TAC `w = Cx(&0)` THENL
+   [UNDISCH_THEN `norm(w:complex) = r` (MP_TAC o SYM) THEN
+    ASM_REWRITE_TAC[COMPLEX_NORM_0; REAL_ABS_ZERO] THEN
+    DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[COMPLEX_MUL_LZERO] THEN
+    REWRITE_TAC[MEMBER_NOT_EMPTY; INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN
+    REWRITE_TAC[REAL_NOT_LT; REAL_POS];
+    ALL_TAC] THEN
+  MP_TAC(SPECL [`Re(w / Cx(norm w))`; `Im(w / Cx(norm w))`]
+    SINCOS_TOTAL_2PI) THEN
+  REWRITE_TAC[GSYM COMPLEX_SQNORM] THEN
+  REWRITE_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_CX; REAL_ABS_NORM] THEN
+  ASM_SIMP_TAC[REAL_DIV_REFL; REAL_POW_ONE; COMPLEX_NORM_ZERO] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real` (STRIP_ASSUME_TAC o GSYM)) THEN
+  EXISTS_TAC `lift(t / (&2 * pi))` THEN
+  ONCE_REWRITE_TAC[COMPLEX_RING
+     `Cx(&2) * p * i * z = i * (Cx(&2) * p * z)`] THEN
+  REWRITE_TAC[CEXP_EULER; LIFT_DROP; CX_DIV; CX_MUL] THEN
+  ASM_SIMP_TAC[CX_PI_NZ; COMPLEX_FIELD
+   `~(p = Cx(&0)) ==> Cx(&2) * p * t / (Cx(&2) * p) = t`] THEN
+  ASM_REWRITE_TAC[GSYM CX_COS; GSYM CX_SIN] THEN CONJ_TAC THENL
+   [REWRITE_TAC[complex_div; GSYM CX_INV] THEN
+    REWRITE_TAC[SIMPLE_COMPLEX_ARITH `Re(w * Cx x) = Re(w) * x`;
+                SIMPLE_COMPLEX_ARITH `Im(w * Cx x) = Im(w) * x`] THEN
+    REWRITE_TAC[COMPLEX_ADD_LDISTRIB; GSYM CX_MUL] THEN
+    SUBGOAL_THEN `!z:real. r * z * inv r = z` MP_TAC THENL
+     [SUBGOAL_THEN `~(r = &0)` MP_TAC THENL [ALL_TAC; CONV_TAC REAL_FIELD] THEN
+      ASM_MESON_TAC[COMPLEX_NORM_ZERO];
+      ONCE_REWRITE_TAC[COMPLEX_RING `t * ii * s = ii * t * s`] THEN
+      SIMP_TAC[GSYM CX_MUL; GSYM COMPLEX_EXPAND]];
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; REAL_LT_MUL;
+                 PI_POS; REAL_OF_NUM_LT; ARITH] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let HAS_PATH_INTEGRAL_BOUND_CIRCLEPATH_STRONG = prove
+ (`!f i z r B k.
+        FINITE k /\
+        (f has_path_integral i) (circlepath(z,r)) /\
+        &0 <= B /\ &0 < r /\
+        (!x. norm(x - z) = r /\ ~(x IN k) ==> norm(f x) <= B)
+        ==> norm(i) <= B * (&2 * pi * r)`,
+  REWRITE_TAC[circlepath] THEN REPEAT STRIP_TAC THEN
+  SUBST1_TAC(REAL_ARITH `B * (&2 * pi * r) = B * r * (&2 * pi - &0)`) THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_PARTCIRCLEPATH_STRONG THEN
+  MAP_EVERY EXISTS_TAC
+   [`f:complex->complex`; `z:complex`; `k:complex->bool`] THEN
+  ASM_SIMP_TAC[REAL_LE_MUL; REAL_POS; REAL_LT_IMP_LE; PI_POS; IN_DIFF] THEN
+  ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; GSYM circlepath; REAL_LT_IMP_LE] THEN
+  ASM_REWRITE_TAC[IN_SPHERE; NORM_ARITH `dist(w,z) = norm(z - w)`]);;
+
+let HAS_PATH_INTEGRAL_BOUND_CIRCLEPATH = prove
+ (`!f i z r B.
+        (f has_path_integral i) (circlepath(z,r)) /\
+        &0 <= B /\ &0 < r /\ (!x. norm(x - z) = r ==> norm(f x) <= B)
+        ==> norm(i) <= B * (&2 * pi * r)`,
+  REWRITE_TAC[circlepath] THEN REPEAT STRIP_TAC THEN
+  SUBST1_TAC(REAL_ARITH `B * (&2 * pi * r) = B * r * (&2 * pi - &0)`) THEN
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_PARTCIRCLEPATH THEN
+  MAP_EVERY EXISTS_TAC [`f:complex->complex`; `z:complex`] THEN
+  ASM_SIMP_TAC[REAL_LE_MUL; REAL_POS; REAL_LT_IMP_LE; PI_POS] THEN
+  ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; GSYM circlepath; REAL_LT_IMP_LE] THEN
+  ASM_REWRITE_TAC[IN_SPHERE; NORM_ARITH `dist(w,z) = norm(z - w)`]);;
+
+let PATH_INTEGRABLE_CONTINUOUS_CIRCLEPATH = prove
+ (`!f z r. f continuous_on path_image(circlepath(z,r))
+           ==> f path_integrable_on (circlepath(z,r))`,
+  SIMP_TAC[PATH_INTEGRABLE_CONTINUOUS_PARTCIRCLEPATH; circlepath]);;
+
+let SIMPLE_PATH_CIRCLEPATH = prove
+ (`!z r. simple_path(circlepath(z,r)) <=> ~(r = &0)`,
+  REWRITE_TAC[circlepath; SIMPLE_PATH_PARTCIRCLEPATH] THEN
+  MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+let WINDING_NUMBER_CIRCLEPATH = prove
+ (`!z r w. norm(w - z) < r ==> winding_number(circlepath(z,r),w) = Cx(&1)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SIMPLE_CLOSED_PATH_WINDING_NUMBER_POS THEN
+  REWRITE_TAC[SIMPLE_PATH_CIRCLEPATH;
+              PATHSTART_CIRCLEPATH; PATHFINISH_CIRCLEPATH; CONJ_ASSOC] THEN
+  CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o MATCH_MP (REAL_ARITH
+     `n < r ==> (&0 <= n ==> &0 <= r /\ &0 < r) /\ n < r`)) THEN
+    SIMP_TAC[NORM_POS_LE; PATH_IMAGE_CIRCLEPATH; IN_ELIM_THM] THEN
+    ASM_REWRITE_TAC[IN_SPHERE; NORM_ARITH `dist(w,z) = norm(z - w)`] THEN
+    REAL_ARITH_TAC;
+    REWRITE_TAC[circlepath] THEN
+    MATCH_MP_TAC WINDING_NUMBER_PARTCIRCLEPATH_POS_LT THEN
+    ASM_SIMP_TAC[REAL_LT_MUL; PI_POS; REAL_OF_NUM_LT; ARITH]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence the Cauchy formula for points inside a circle.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_INTEGRAL_CIRCLEPATH = prove
+ (`!f z r w.
+        f continuous_on cball(z,r) /\
+        f holomorphic_on ball(z,r) /\
+        w IN ball(z,r)
+        ==> ((\u. f(u) / (u - w)) has_path_integral
+             (Cx(&2) * Cx(pi) * ii * f(w))) (circlepath(z,r))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`f:complex->complex`; `cball(z:complex,r)`;
+                `{}:complex->bool`; `circlepath(z,r)`; `w:complex`]
+               CAUCHY_INTEGRAL_FORMULA_WEAK) THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_BALL]) THEN
+  ONCE_REWRITE_TAC[DIST_SYM] THEN REWRITE_TAC[dist] THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[WINDING_NUMBER_CIRCLEPATH; COMPLEX_MUL_LID] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[VALID_PATH_CIRCLEPATH; PATHSTART_CIRCLEPATH; FINITE_RULES;
+       PATHFINISH_CIRCLEPATH; CONVEX_CBALL; INTERIOR_CBALL; DIFF_EMPTY] THEN
+  REWRITE_TAC[complex_differentiable] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL]; ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP (REAL_ARITH
+   `n < r ==> &0 <= n ==> &0 <= r`)) THEN
+  SIMP_TAC[NORM_POS_LE; PATH_IMAGE_CIRCLEPATH] THEN
+  REWRITE_TAC[SET_RULE `s SUBSET c DELETE q <=> s SUBSET c /\ ~(q IN s)`] THEN
+  REWRITE_TAC[SPHERE_SUBSET_CBALL; IN_SPHERE] THEN
+  UNDISCH_TAC `norm(w - z:complex) < r` THEN CONV_TAC NORM_ARITH);;
+
+let CAUCHY_INTEGRAL_CIRCLEPATH_SIMPLE = prove
+ (`!f z r w.
+        f holomorphic_on cball(z,r) /\ w IN ball(z,r)
+        ==> ((\u. f(u) / (u - w)) has_path_integral
+             (Cx(&2) * Cx(pi) * ii * f(w))) (circlepath(z,r))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CAUCHY_INTEGRAL_CIRCLEPATH THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON] THEN
+  ASM_MESON_TAC[BALL_SUBSET_CBALL; HOLOMORPHIC_ON_SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Uniform convergence of path integral when the derivative of the path is   *)
+(* bounded, and in particular for the special case of a circle.              *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_INTEGRAL_UNIFORM_LIMIT = prove
+ (`!net f B g l.
+     ~(trivial_limit net) /\ valid_path g /\
+     (!t. t IN interval[vec 0,vec 1]
+          ==> norm(vector_derivative g (at t)) <= B) /\
+     eventually (\n:A. (f n) path_integrable_on g) net /\
+     (!e. &0 < e
+          ==> eventually (\n. !x. x IN path_image g
+                                  ==> norm(f n x - l x) < e) net)
+     ==> l path_integrable_on g /\
+         ((\n. path_integral g (f n)) --> path_integral g l) net`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REWRITE_TAC[path_integrable_on; HAS_PATH_INTEGRAL; GSYM integrable_on] THEN
+    MATCH_MP_TAC INTEGRABLE_UNIFORM_LIMIT 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 B + &1`] THEN
+    UNDISCH_TAC `eventually (\n:A. (f n) path_integrable_on g) net` THEN
+    REWRITE_TAC[IMP_IMP; GSYM EVENTUALLY_AND] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP EVENTUALLY_HAPPENS) THEN
+    ASM_REWRITE_TAC[path_image; path_integrable_on; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[HAS_PATH_INTEGRAL; GSYM integrable_on] THEN
+    DISCH_THEN(X_CHOOSE_THEN `a:A` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\x. f (a:A) (g x) * vector_derivative g (at x)` THEN
+    ASM_REWRITE_TAC[GSYM COMPLEX_SUB_RDISTRIB] THEN
+    X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `e / (abs B + &1) * B` THEN CONJ_TAC THENL
+     [REWRITE_TAC[COMPLEX_NORM_MUL] THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+      ASM_SIMP_TAC[NORM_POS_LE] THEN ONCE_REWRITE_TAC[NORM_SUB] THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE];
+      REWRITE_TAC[REAL_ARITH `e / x * B <= e <=> &0 <= e * (&1 - B / x)`] THEN
+      MATCH_MP_TAC REAL_LE_MUL THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_SUB_LE; REAL_LE_LDIV_EQ;
+                   REAL_ARITH `&0 < abs B + &1`] THEN
+      REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  DISCH_TAC THEN ONCE_REWRITE_TAC[LIM_NULL] THEN REWRITE_TAC[tendsto] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2 / (abs B + &1)`) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < abs B + &1`; REAL_HALF] THEN
+  UNDISCH_TAC `eventually (\n:A. (f n) path_integrable_on g) net` THEN
+  REWRITE_TAC[IMP_IMP; GSYM EVENTUALLY_AND] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+  X_GEN_TAC `a:A` THEN REWRITE_TAC[] THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[PATH_INTEGRAL_INTEGRAL; DIST_0; GSYM INTEGRAL_SUB;
+               GSYM PATH_INTEGRABLE_ON; ETA_AX] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC
+   `drop(integral (interval[vec 0,vec 1]) (\x:real^1. lift(e / &2)))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+    ASM_SIMP_TAC[INTEGRABLE_SUB; GSYM PATH_INTEGRABLE_ON; ETA_AX] THEN
+    REWRITE_TAC[INTEGRABLE_CONST; GSYM COMPLEX_SUB_RDISTRIB; LIFT_DROP] THEN
+    X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `e / &2 / (abs B + &1) * B` THEN CONJ_TAC THENL
+     [REWRITE_TAC[COMPLEX_NORM_MUL] THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+      ASM_SIMP_TAC[NORM_POS_LE] THEN MATCH_MP_TAC REAL_LT_IMP_LE THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      REWRITE_TAC[IN_IMAGE; path_image] THEN ASM_MESON_TAC[];
+      REWRITE_TAC[REAL_ARITH `e / x * B <= e <=> &0 <= e * (&1 - B / x)`] THEN
+      MATCH_MP_TAC REAL_LE_MUL THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_SUB_LE; REAL_LE_LDIV_EQ;
+                   REAL_ARITH `&0 < abs B + &1`] THEN
+      ASM_REAL_ARITH_TAC];
+    REWRITE_TAC[INTEGRAL_CONST; CONTENT_UNIT_1; VECTOR_MUL_LID; LIFT_DROP] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let PATH_INTEGRAL_UNIFORM_LIMIT_CIRCLEPATH = prove
+ (`!net f l z r.
+     &0 < r /\ ~(trivial_limit net) /\
+     eventually (\n:A. (f n) path_integrable_on circlepath(z,r)) net /\
+     (!e. &0 < e
+          ==> eventually (\n. !x. x IN path_image (circlepath(z,r))
+                                  ==> norm(f n x - l x) < e) net)
+     ==> l path_integrable_on circlepath(z,r) /\
+         ((\n. path_integral (circlepath(z,r)) (f n))
+          --> path_integral (circlepath(z,r)) l) net`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC PATH_INTEGRAL_UNIFORM_LIMIT THEN EXISTS_TAC `&2 * pi * r` THEN
+  ASM_SIMP_TAC[PI_POS; REAL_LT_MUL; REAL_OF_NUM_LT; ARITH] THEN
+  REWRITE_TAC[VALID_PATH_CIRCLEPATH; VECTOR_DERIVATIVE_CIRCLEPATH] THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX; COMPLEX_NORM_II] THEN
+  REWRITE_TAC[REAL_ABS_NUM; REAL_ABS_PI; REAL_MUL_LID] THEN
+  REWRITE_TAC[NORM_CEXP; RE_MUL_CX; RE_MUL_II; IM_CX] THEN
+  REWRITE_TAC[REAL_NEG_0; REAL_MUL_RZERO; REAL_EXP_0; REAL_MUL_RID] THEN
+  ASM_SIMP_TAC[real_abs; REAL_LE_REFL; REAL_LT_IMP_LE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* General stepping result for derivative formulas.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_NEXT_DERIVATIVE = prove
+ (`!f' f g s k B.
+     ~(k = 0) /\
+     open s /\ valid_path g /\
+     (!t. t IN interval[vec 0,vec 1]
+          ==> norm(vector_derivative g (at t)) <= B) /\
+     f' continuous_on path_image g /\
+     (!w. w IN s DIFF path_image g
+          ==> ((\u. f'(u) / (u - w) pow k) has_path_integral f w) g)
+     ==> !w. w IN s DIFF path_image g
+             ==> (\u. f'(u) / (u - w) pow (k + 1)) path_integrable_on g /\
+                 (f has_complex_derivative
+                  (Cx(&k) * path_integral g (\u. f'(u) / (u - w) pow (k + 1))))
+                  (at w)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN X_GEN_TAC `w:complex` THEN
+  REWRITE_TAC[IN_DIFF] THEN STRIP_TAC THEN
+  MP_TAC(ISPEC `s DIFF path_image(g:real^1->complex)`
+        OPEN_CONTAINS_BALL) THEN
+  ASM_SIMP_TAC[OPEN_DIFF; CLOSED_PATH_IMAGE; VALID_PATH_IMP_PATH] THEN
+  DISCH_THEN(MP_TAC o SPEC `w:complex`) THEN
+  ASM_REWRITE_TAC[IN_DIFF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`at(w:complex)`;
+    `\u x:complex. f'(x) * (inv(x - u) pow k - inv(x - w) pow k) /
+                   (u - w) / Cx(&k)`;
+    `B:real`; `g:real^1->complex`;
+    `\u. f'(u) / (u - w) pow (k + 1)`]
+        PATH_INTEGRAL_UNIFORM_LIMIT) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o SPEC `Cx(&k)` o MATCH_MP LIM_COMPLEX_LMUL) THEN
+    REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_AT] THEN
+    MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+                  LIM_TRANSFORM_AT) THEN
+    EXISTS_TAC `d:real` THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `u:complex` THEN
+    REWRITE_TAC[dist] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `~(u:complex = w)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[COMPLEX_SUB_0; COMPLEX_NORM_0; REAL_LT_REFL]; ALL_TAC] THEN
+    ASM_SIMP_TAC[CX_INJ; REAL_OF_NUM_EQ; COMPLEX_FIELD
+     `~(y = Cx(&0)) ==> (y * x = z <=> x = z / y)`] THEN
+    ASM_SIMP_TAC[COMPLEX_SUB_0; CX_INJ; REAL_OF_NUM_EQ; COMPLEX_SUB_LDISTRIB;
+           COMPLEX_FIELD `~(c = Cx(&0)) ==> (a - b) / c = a / c - b / c`] THEN
+    MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+    MATCH_MP_TAC HAS_PATH_INTEGRAL_SUB THEN
+    REWRITE_TAC[complex_div; COMPLEX_MUL_ASSOC] THEN
+    REWRITE_TAC[GSYM complex_div] THEN
+    CONJ_TAC THEN REPEAT(MATCH_MP_TAC HAS_PATH_INTEGRAL_COMPLEX_DIV) THEN
+    REWRITE_TAC[GSYM complex_div; COMPLEX_POW_INV] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    ASM_REWRITE_TAC[IN_BALL; dist; VECTOR_SUB_REFL; NORM_0] THEN
+    ASM_MESON_TAC[NORM_SUB]] THEN
+  ASM_REWRITE_TAC[TRIVIAL_LIMIT_AT] THEN CONJ_TAC THENL
+   [REWRITE_TAC[EVENTUALLY_AT] THEN EXISTS_TAC `d:real` THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `u:complex` THEN
+    REWRITE_TAC[dist] THEN STRIP_TAC THEN
+    REWRITE_TAC[complex_div; COMPLEX_MUL_ASSOC] THEN
+    REPEAT(MATCH_MP_TAC PATH_INTEGRABLE_COMPLEX_RMUL) THEN
+    REWRITE_TAC[COMPLEX_SUB_LDISTRIB; COMPLEX_POW_INV; GSYM complex_div] THEN
+    MATCH_MP_TAC PATH_INTEGRABLE_SUB THEN
+    REWRITE_TAC[path_integrable_on] THEN CONJ_TAC THENL
+     [EXISTS_TAC `(f:complex->complex) u`;
+      EXISTS_TAC `(f:complex->complex) w`] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    REWRITE_TAC[IN_BALL; dist; VECTOR_SUB_REFL; NORM_0] THEN
+    ASM_MESON_TAC[NORM_SUB];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!e. &0 < e
+     ==> eventually
+         (\n. !x. x IN path_image g
+                  ==> norm
+                      ((inv (x - n) pow k - inv (x - w) pow k) /
+                       (n - w) / Cx(&k) - inv(x - w) pow (k + 1)) <
+                      e)
+         (at w)`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `bounded(IMAGE (f':complex->complex) (path_image g))`
+    MP_TAC THENL
+     [MATCH_MP_TAC COMPACT_IMP_BOUNDED THEN
+      MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+      ASM_SIMP_TAC[COMPACT_VALID_PATH_IMAGE];
+      ALL_TAC] THEN
+    REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `C:real` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `e / C:real`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+    X_GEN_TAC `u:complex` THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:complex` THEN
+    DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+    ASM_REWRITE_TAC[complex_div; GSYM COMPLEX_MUL_ASSOC] THEN
+    REWRITE_TAC[GSYM COMPLEX_SUB_LDISTRIB; COMPLEX_NORM_MUL] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN ASM_SIMP_TAC[REAL_LT_RDIV_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH `a <= b ==> b < x ==> a < x`) THEN
+    REWRITE_TAC[COMPLEX_POW_INV] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
+    ASM_SIMP_TAC[NORM_POS_LE; REAL_LT_IMP_LE]] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN REWRITE_TAC[EVENTUALLY_AT] THEN
+  EXISTS_TAC `min (d / &2) ((e * (d / &2) pow (k + 2)) / (&k + &1))` THEN
+  ASM_SIMP_TAC[REAL_LT_MIN; REAL_HALF; REAL_POW_LT; REAL_LT_MUL; dist;
+               REAL_LT_DIV; REAL_ARITH `&0 < &k + &1`] THEN
+  X_GEN_TAC `u:complex` THEN STRIP_TAC THEN
+  X_GEN_TAC `x:complex` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`\n w. if n = 0 then inv(x - w) pow k
+                        else if n = 1 then Cx(&k) / (x - w) pow (k + 1)
+                        else (Cx(&k) * Cx(&k + &1)) / (x - w) pow (k + 2)`;
+                 `1`; `ball(w:complex,d / &2)`;
+                 `(&k * (&k + &1)) / (d / &2) pow (k + 2)`]
+         COMPLEX_TAYLOR) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [REWRITE_TAC[CONVEX_BALL; ADD_EQ_0; ARITH] THEN CONJ_TAC THENL
+     [ALL_TAC;
+      X_GEN_TAC `v:complex` THEN REWRITE_TAC[IN_BALL; dist] THEN DISCH_TAC THEN
+      REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_DIV; COMPLEX_NORM_CX]THEN
+      REWRITE_TAC[real_div; GSYM REAL_POW_INV; GSYM REAL_MUL_ASSOC] THEN
+      REWRITE_TAC[REAL_ABS_NUM; REAL_ARITH `abs(&k + &1) = &k + &1`] THEN
+      REPEAT(MATCH_MP_TAC REAL_LE_LMUL THEN
+             CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC]) THEN
+      REWRITE_TAC[REAL_POW_INV] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+      ASM_SIMP_TAC[GSYM real_div; REAL_POW_LT; REAL_HALF] THEN
+      REWRITE_TAC[COMPLEX_NORM_POW] THEN MATCH_MP_TAC REAL_POW_LE2 THEN
+      ASM_SIMP_TAC[REAL_ARITH `&0 < d ==> &0 <= d / &2`] THEN
+      UNDISCH_TAC `ball(w:complex,d) SUBSET s DIFF path_image g` THEN
+      REWRITE_TAC[SUBSET] THEN DISCH_THEN(MP_TAC o SPEC `x:complex`) THEN
+      ASM_REWRITE_TAC[IN_DIFF; IN_BALL] THEN
+      UNDISCH_TAC `norm(w - v:complex) < d / &2` THEN
+      CONV_TAC NORM_ARITH] THEN
+    GEN_TAC THEN X_GEN_TAC `y:complex` THEN
+    REWRITE_TAC[IN_BALL; dist] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `~(y:complex = x)` ASSUME_TAC THENL
+     [DISCH_THEN SUBST_ALL_TAC THEN
+      UNDISCH_TAC `ball(w:complex,d) SUBSET s DIFF path_image g` THEN
+      REWRITE_TAC[SUBSET] THEN DISCH_THEN(MP_TAC o SPEC `x:complex`) THEN
+      ASM_REWRITE_TAC[IN_DIFF; IN_BALL; dist] THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(DISJ_CASES_THEN SUBST_ALL_TAC o MATCH_MP
+      (ARITH_RULE `i <= 1 ==> i = 0 \/ i = 1`)) THEN
+    REWRITE_TAC[ARITH] THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_AT_WITHIN THEN
+    COMPLEX_DIFF_TAC THEN
+    REWRITE_TAC[COMPLEX_POW_EQ_0; COMPLEX_INV_EQ_0; CONJ_ASSOC;
+       COMPLEX_MUL_LZERO; COMPLEX_SUB_0; ADD_EQ_0; ARITH] THEN
+    REWRITE_TAC[COMPLEX_SUB_LZERO; COMPLEX_NEG_NEG; complex_div] THEN
+    REWRITE_TAC[COMPLEX_MUL_LID; GSYM COMPLEX_MUL_ASSOC;
+     GSYM COMPLEX_POW_INV; GSYM COMPLEX_INV_MUL; GSYM COMPLEX_POW_ADD] THEN
+    ASM_SIMP_TAC[ARITH_RULE `~(k = 0) ==> k - 1 + 2 = k + 1`] THEN
+    REWRITE_TAC[COMPLEX_INV_INV; ADD_SUB; COMPLEX_MUL_RNEG;
+                COMPLEX_NEG_NEG; COMPLEX_MUL_RID; COMPLEX_POW_POW] THEN
+    REWRITE_TAC[GSYM COMPLEX_MUL_ASSOC; GSYM REAL_OF_NUM_ADD] THEN
+    AP_TERM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[COMPLEX_POW_INV] THEN
+    ASM_SIMP_TAC[COMPLEX_POW_EQ_0; COMPLEX_INV_EQ_0; COMPLEX_SUB_0;
+                 COMPLEX_FIELD `~(x = Cx(&0)) /\ ~(y = Cx(&0))
+                                ==> (z * inv x = inv y <=> y * z = x)`] THEN
+    REWRITE_TAC[GSYM COMPLEX_POW_ADD] THEN AP_TERM_TAC THEN ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPECL [`w:complex`; `u:complex`]) THEN
+  ASM_REWRITE_TAC[CENTRE_IN_BALL; REAL_HALF; NUMSEG_CONV `0..1`] THEN
+  ASM_SIMP_TAC[IN_BALL; dist; VSUM_CLAUSES; FINITE_RULES] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[NORM_SUB]; ALL_TAC] THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; ARITH] THEN
+  REWRITE_TAC[complex_pow; VECTOR_ADD_RID; ARITH; FACT] THEN
+  CONV_TAC NUM_REDUCE_CONV THEN
+  REWRITE_TAC[COMPLEX_DIV_1; COMPLEX_MUL_RID; COMPLEX_POW_1] THEN
+  SUBGOAL_THEN `~(u:complex = w)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[COMPLEX_SUB_REFL; COMPLEX_NORM_0; REAL_LT_REFL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~(x:complex = w)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  ASM_SIMP_TAC[COMPLEX_SUB_0; COMPLEX_POW_EQ_0; CX_INJ; REAL_OF_NUM_EQ;
+     COMPLEX_FIELD
+        `~(d = Cx(&0)) /\ ~(c = Cx(&0)) /\ ~(e = Cx(&0))
+         ==> a - (b + c / d * e) = ((a - b) / e / c - inv d) * c * e`] THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX; REAL_DIV_1] THEN
+  REWRITE_TAC[REAL_ABS_NUM; GSYM COMPLEX_POW_INV] THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LT_RCANCEL_IMP THEN
+  EXISTS_TAC `&k * norm(u - w:complex)` THEN
+  ASM_SIMP_TAC[REAL_LT_MUL; REAL_OF_NUM_LT; LT_NZ] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+   `n <= x ==> x < y ==> n < y`)) THEN
+  REWRITE_TAC[REAL_POW_2; REAL_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_POW_2; REAL_MUL_ASSOC; REAL_LT_RMUL_EQ] THEN
+  GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
+  REWRITE_TAC[real_div; GSYM REAL_MUL_ASSOC] THEN
+  MATCH_MP_TAC REAL_LT_LMUL THEN ASM_REWRITE_TAC[REAL_OF_NUM_LT; LT_NZ] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a * b * c:real = (c * a) * b`] THEN
+  ASM_SIMP_TAC[GSYM real_div; REAL_LT_LDIV_EQ; REAL_HALF; REAL_POW_LT] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_ARITH `&0 < &k + &1`]);;
+
+let CAUCHY_NEXT_DERIVATIVE_CIRCLEPATH = prove
+ (`!f g z r k.
+        ~(k = 0) /\
+        (f continuous_on path_image(circlepath(z,r))) /\
+        (!w. w IN ball(z,r)
+             ==> ((\u. f(u) / (u - w) pow k) has_path_integral g w)
+                 (circlepath(z,r)))
+        ==> !w. w IN ball(z,r)
+                ==> (\u. f(u) / (u - w) pow (k + 1)) path_integrable_on
+                            (circlepath(z,r)) /\
+                    (g has_complex_derivative
+                     (Cx(&k) * path_integral(circlepath(z,r))
+                                 (\u. f(u) / (u - w) pow (k + 1))))
+                    (at w)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN ASM_CASES_TAC `&0 <= r` THENL
+   [ALL_TAC;
+    GEN_TAC THEN REWRITE_TAC[IN_BALL] THEN
+    MATCH_MP_TAC(TAUT `~p ==> p ==> q`) THEN
+    UNDISCH_TAC `~(&0 <= r)` THEN CONV_TAC NORM_ARITH] THEN
+  MP_TAC(ISPECL
+   [`f:complex->complex`; `g:complex->complex`; `circlepath(z,r)`;
+    `ball(z:complex,r)`; `k:num`; `&2 * pi * r`] CAUCHY_NEXT_DERIVATIVE) THEN
+  ASM_REWRITE_TAC[OPEN_BALL; VALID_PATH_CIRCLEPATH] THEN
+  SUBGOAL_THEN `ball(z,r) DIFF path_image(circlepath (z,r)) = ball(z,r)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[SET_RULE `s DIFF t = s <=> !x. x IN t ==> ~(x IN s)`] THEN
+    ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; IN_SPHERE; IN_BALL; REAL_LT_REFL];
+    DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[VECTOR_DERIVATIVE_CIRCLEPATH] THEN
+    REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX; COMPLEX_NORM_II] THEN
+    REWRITE_TAC[REAL_ABS_NUM; REAL_ABS_PI; REAL_MUL_LID] THEN
+    REWRITE_TAC[NORM_CEXP; RE_MUL_CX; RE_MUL_II; IM_CX] THEN
+    REWRITE_TAC[REAL_NEG_0; REAL_MUL_RZERO; REAL_EXP_0; REAL_MUL_RID] THEN
+    ASM_SIMP_TAC[real_abs; REAL_LE_REFL]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In particular, the first derivative formula.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_DERIVATIVE_INTEGRAL_CIRCLEPATH = prove
+ (`!f z r w.
+        f continuous_on cball(z,r) /\
+        f holomorphic_on ball(z,r) /\
+        w IN ball(z,r)
+        ==> (\u. f(u) / (u - w) pow 2) path_integrable_on circlepath(z,r) /\
+            (f has_complex_derivative
+                (Cx(&1) / (Cx(&2) * Cx(pi) * ii) *
+                 path_integral(circlepath(z,r)) (\u. f(u) / (u - w) pow 2)))
+            (at w)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(SPECL [`f:complex->complex`; `\x:complex. Cx(&2) * Cx(pi) * ii * f x`;
+                `z:complex`; `r:real`; `1`]
+         CAUCHY_NEXT_DERIVATIVE_CIRCLEPATH) THEN
+  ASM_SIMP_TAC[COMPLEX_POW_1; ARITH; CAUCHY_INTEGRAL_CIRCLEPATH] THEN
+  ANTS_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `cball(z:complex,r)` THEN
+    ASM_REWRITE_TAC[] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_BALL]) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+     `n < r ==> &0 <= n ==> &0 <= r`)) THEN
+    SIMP_TAC[DIST_POS_LE; PATH_IMAGE_CIRCLEPATH; SPHERE_SUBSET_CBALL];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `w:complex`) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[COMPLEX_MUL_LID] THEN
+  DISCH_THEN(MP_TAC o SPEC `Cx(&1) / (Cx(&2) * Cx pi * ii)` o
+        MATCH_MP HAS_COMPLEX_DERIVATIVE_LMUL_AT) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN MP_TAC CX_2PII_NZ THEN CONV_TAC COMPLEX_FIELD);;
+
+(* ------------------------------------------------------------------------- *)
+(* Existence of all higher derivatives.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let HOLOMORPHIC_DERIVATIVE = prove
+ (`!f f' s. open s /\ (!z. z IN s ==> (f has_complex_derivative f'(z)) (at z))
+            ==> f' holomorphic_on s`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[HOLOMORPHIC_ON_OPEN] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPECL [`\x. Cx(&1) / (Cx(&2) * Cx pi * ii) * f(x:complex)`;
+                `f':complex->complex`; `z:complex`; `r:real`; `2`]
+               CAUCHY_NEXT_DERIVATIVE_CIRCLEPATH) THEN
+  ANTS_TAC THENL [ALL_TAC; ASM_MESON_TAC[CENTRE_IN_BALL]] THEN
+  SUBGOAL_THEN `f holomorphic_on cball(z,r)` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[holomorphic_on] THEN
+    ASM_MESON_TAC[SUBSET; HAS_COMPLEX_DERIVATIVE_AT_WITHIN];
+    ALL_TAC] THEN
+  REWRITE_TAC[ARITH] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_LMUL THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `cball(z:complex,r)` THEN
+    ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON] THEN
+    ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; REAL_LT_IMP_LE; SPHERE_SUBSET_CBALL];
+    ALL_TAC] THEN
+  X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+  MP_TAC(SPECL [`f:complex->complex`; `z:complex`; `r:real`; `w:complex`]
+               CAUCHY_DERIVATIVE_INTEGRAL_CIRCLEPATH) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON; HOLOMORPHIC_ON_SUBSET;
+                  BALL_SUBSET_CBALL];
+    ALL_TAC] THEN
+  STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_INTEGRAL) THEN
+  DISCH_THEN(MP_TAC o SPEC `Cx(&1) / (Cx(&2) * Cx pi * ii)` o
+    MATCH_MP HAS_PATH_INTEGRAL_COMPLEX_LMUL) THEN
+  REWRITE_TAC[complex_div; GSYM COMPLEX_MUL_ASSOC] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[COMPLEX_MUL_ASSOC; GSYM complex_div] THEN
+  MATCH_MP_TAC COMPLEX_DERIVATIVE_UNIQUE_AT THEN
+  MAP_EVERY EXISTS_TAC [`f:complex->complex`; `w:complex`] THEN
+  ASM_REWRITE_TAC[GSYM COMPLEX_MUL_ASSOC] THEN
+  ASM_MESON_TAC[SUBSET; BALL_SUBSET_CBALL]);;
+
+let HOLOMORPHIC_COMPLEX_DERIVATIVE = prove
+ (`!f s. open s /\ f holomorphic_on s
+         ==> (complex_derivative f) holomorphic_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOLOMORPHIC_DERIVATIVE THEN
+  EXISTS_TAC `f:complex->complex` THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[HAS_COMPLEX_DERIVATIVE_DERIVATIVE; HOLOMORPHIC_ON_OPEN]);;
+
+let ANALYTIC_COMPLEX_DERIVATIVE = prove
+ (`!f s. f analytic_on s ==> (complex_derivative f) analytic_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[analytic_on] THEN DISCH_TAC THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  SIMP_TAC[HOLOMORPHIC_COMPLEX_DERIVATIVE; OPEN_BALL]);;
+
+let HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE = prove
+ (`!f s n. open s /\ f holomorphic_on s
+           ==> (higher_complex_derivative n f) holomorphic_on s`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
+  INDUCT_TAC THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_COMPLEX_DERIVATIVE; higher_complex_derivative]);;
+
+let ANALYTIC_HIGHER_COMPLEX_DERIVATIVE = prove
+ (`!f s n. f analytic_on s ==> (higher_complex_derivative n f) analytic_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[analytic_on] THEN DISCH_TAC THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE; OPEN_BALL]);;
+
+let HAS_COMPLEX_DERIVATIVE_HIGHER_COMPLEX_DERIVATIVE = prove
+ (`!f s x n. open s /\ f holomorphic_on s /\ x IN s
+             ==> ((higher_complex_derivative n f) has_complex_derivative
+                          (higher_complex_derivative (SUC n) f x)) (at x)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[higher_complex_derivative] THEN
+  REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+  MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT THEN
+  EXISTS_TAC `s:complex->bool` THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Morera's theorem.                                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let MORERA_LOCAL_TRIANGLE_GEN = prove
+ (`!f s.
+     (!z. z IN s
+          ==> ?e a. &0 < e /\ z IN ball(a,e) /\ f continuous_on ball(a,e) /\
+                    !b c. segment[b,c] SUBSET ball(a,e)
+                           ==> path_integral (linepath(a,b)) f +
+                               path_integral (linepath(b,c)) f +
+                               path_integral (linepath(c,a)) f = Cx(&0))
+     ==> f analytic_on s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[analytic_on] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`e:real`; `a:complex`] THEN STRIP_TAC THEN
+  EXISTS_TAC `e - dist(a:complex,z)` THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_BALL]) THEN NORM_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN EXISTS_TAC `ball(a:complex,e)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC HOLOMORPHIC_DERIVATIVE THEN REWRITE_TAC[OPEN_BALL] THEN
+    MATCH_MP_TAC TRIANGLE_PATH_INTEGRALS_STARLIKE_PRIMITIVE THEN
+    EXISTS_TAC `a:complex` THEN ASM_REWRITE_TAC[CENTRE_IN_BALL; OPEN_BALL] THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+    MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_BALL] THEN
+    ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; CENTRE_IN_BALL];
+    REWRITE_TAC[SUBSET; IN_BALL] THEN NORM_ARITH_TAC]);;
+
+let MORERA_LOCAL_TRIANGLE = prove
+ (`!f s. (!z. z IN s
+              ==> ?t. open t /\ z IN t /\ f continuous_on t /\
+                      !a b c. convex hull {a,b,c} SUBSET t
+                              ==> path_integral (linepath(a,b)) f +
+                                  path_integral (linepath(b,c)) f +
+                                  path_integral (linepath(c,a)) f = Cx(&0))
+         ==> f analytic_on s`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  MATCH_MP_TAC MORERA_LOCAL_TRIANGLE_GEN THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `t:complex->bool` THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN STRIP_TAC THEN
+  EXISTS_TAC `z:complex` THEN ASM_REWRITE_TAC[CENTRE_IN_BALL] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`x:complex`; `w:complex`] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM
+   (MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] SUBSET_TRANS)) THEN
+  MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_BALL] THEN
+  ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; CENTRE_IN_BALL] THEN
+  MP_TAC(ISPECL [`x:complex`; `w:complex`] ENDS_IN_SEGMENT) THEN
+  ASM SET_TAC[]);;
+
+let MORERA_TRIANGLE = prove
+ (`!f s. open s /\ f continuous_on s /\
+         (!a b c. convex hull {a,b,c} SUBSET s
+                  ==> path_integral (linepath(a,b)) f +
+                      path_integral (linepath(b,c)) f +
+                      path_integral (linepath(c,a)) f = Cx(&0))
+         ==> f analytic_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MORERA_LOCAL_TRIANGLE THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN EXISTS_TAC `s:complex->bool` THEN
+  ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Combining theorems for higher derivatives including Leibniz rule.         *)
+(* ------------------------------------------------------------------------- *)
+
+let HIGHER_COMPLEX_DERIVATIVE_EQ_ITER = prove
+ (`!n. higher_complex_derivative n = ITER n complex_derivative`,
+  INDUCT_TAC THEN
+  ASM_REWRITE_TAC [FUN_EQ_THM; ITER; higher_complex_derivative]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_HIGHER_COMPLEX_DERIVATIVE = prove
+ (`!f m n. higher_complex_derivative m (higher_complex_derivative n f) =
+           higher_complex_derivative (m + n) f`,
+  REWRITE_TAC[HIGHER_COMPLEX_DERIVATIVE_EQ_ITER; ITER_ADD]);;
+
+let higher_complex_derivative_alt = prove
+ (`(!f. higher_complex_derivative 0 f = f) /\
+   (!f z n. higher_complex_derivative (SUC n) f =
+            higher_complex_derivative n (complex_derivative f))`,
+  REWRITE_TAC [HIGHER_COMPLEX_DERIVATIVE_EQ_ITER; ITER_ALT]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_LINEAR = prove
+ (`!c n. higher_complex_derivative n (\w. c * w) =
+    \z. if n = 0 then c * z else if n = 1 then c else (Cx(&0))`,
+  GEN_TAC THEN INDUCT_TAC THEN
+  ASM_REWRITE_TAC [higher_complex_derivative; NOT_SUC; SUC_INJ; ONE] THEN
+  STRUCT_CASES_TAC (SPEC `n:num` num_CASES) THEN
+  REWRITE_TAC [NOT_SUC; SUC_INJ;
+               COMPLEX_DERIVATIVE_LINEAR; COMPLEX_DERIVATIVE_CONST]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_CONST = prove
+ (`!i c. higher_complex_derivative i (\w.c) = \w. if i=0 then c else Cx(&0)`,
+  INDUCT_TAC THEN ASM_REWRITE_TAC [higher_complex_derivative_alt; NOT_SUC;
+                                   COMPLEX_DERIVATIVE_CONST; FUN_EQ_THM] THEN
+  MESON_TAC[]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_ID = prove
+ (`!z i. higher_complex_derivative i (\w.w) z =
+            if i = 0 then z else if i = 1 then Cx(&1) else Cx(&0)`,
+  GEN_TAC THEN INDUCT_TAC THEN
+  ASM_REWRITE_TAC [higher_complex_derivative_alt; NOT_SUC; ONE; SUC_INJ] THEN
+  REWRITE_TAC[COMPLEX_DERIVATIVE_ID; HIGHER_COMPLEX_DERIVATIVE_CONST; ONE]);;
+
+let HAS_COMPLEX_DERIVATIVE_ITER_1 = prove
+ (`!f n z. f z = z /\ (f has_complex_derivative Cx(&1)) (at z)
+           ==> (ITER n f has_complex_derivative Cx(&1)) (at z)`,
+  GEN_TAC THEN INDUCT_TAC THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC [ITER_POINTLESS; I_DEF; HAS_COMPLEX_DERIVATIVE_ID] THEN
+  SUBGOAL_THEN `Cx(&1) = Cx(&1) * Cx(&1)` SUBST1_TAC THENL
+  [REWRITE_TAC [COMPLEX_MUL_LID];
+   ASM_SIMP_TAC [ITER_FIXPOINT; COMPLEX_DIFF_CHAIN_AT]]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_NEG = prove
+ (`!f s n z.
+     open s /\ f holomorphic_on s /\ z IN s
+     ==> higher_complex_derivative n (\w. --(f w)) z =
+                --(higher_complex_derivative n f z)`,
+  REWRITE_TAC [IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN
+  REPEAT DISCH_TAC THEN INDUCT_TAC THEN
+  REWRITE_TAC [higher_complex_derivative] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+  EXISTS_TAC `(\w. --(higher_complex_derivative n f w))` THEN
+  EXISTS_TAC `s:complex->bool` THEN ASM_SIMP_TAC [] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_NEG THEN
+  REWRITE_TAC [ETA_AX; GSYM higher_complex_derivative] THEN
+  ASM_MESON_TAC [HAS_COMPLEX_DERIVATIVE_HIGHER_COMPLEX_DERIVATIVE]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_ADD = prove
+ (`!f g s n z.
+     open s /\ f holomorphic_on s /\ g holomorphic_on s /\ z IN s ==>
+     higher_complex_derivative n (\w. f w + g w) z  =
+     higher_complex_derivative n f z + higher_complex_derivative n g z`,
+  REWRITE_TAC [IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN
+  REPEAT DISCH_TAC THEN INDUCT_TAC THEN
+  REWRITE_TAC [higher_complex_derivative] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+  EXISTS_TAC `(\w. higher_complex_derivative n f w +
+                   higher_complex_derivative n g w)` THEN
+  EXISTS_TAC `s:complex->bool` THEN ASM_SIMP_TAC [] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_ADD THEN
+  REWRITE_TAC [ETA_AX; GSYM higher_complex_derivative] THEN
+  ASM_MESON_TAC [HAS_COMPLEX_DERIVATIVE_HIGHER_COMPLEX_DERIVATIVE]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_SUB = prove
+ (`!f g s n z.
+     open s /\ f holomorphic_on s /\ g holomorphic_on s /\ z IN s ==>
+     higher_complex_derivative n (\w. f w - g w) z  =
+     higher_complex_derivative n f z - higher_complex_derivative n g z`,
+  REWRITE_TAC [IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN
+  REPEAT DISCH_TAC THEN INDUCT_TAC THEN
+  REWRITE_TAC [higher_complex_derivative] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+  EXISTS_TAC `(\w. higher_complex_derivative n f w -
+                   higher_complex_derivative n g w)` THEN
+  EXISTS_TAC `s:complex->bool` THEN ASM_SIMP_TAC [] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_SUB THEN
+  REWRITE_TAC [ETA_AX; GSYM higher_complex_derivative] THEN
+  ASM_MESON_TAC [HAS_COMPLEX_DERIVATIVE_HIGHER_COMPLEX_DERIVATIVE]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_MUL = prove
+ (`!f g s n z.
+     open s /\ f holomorphic_on s /\ g holomorphic_on s /\ z IN s
+     ==> higher_complex_derivative n (\w. f w * g w) z =
+         vsum (0..n) (\i. Cx(&(binom(n,i))) *
+                          higher_complex_derivative i f z *
+                          higher_complex_derivative (n-i) g z)`,
+  REWRITE_TAC [IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN
+  REPEAT DISCH_TAC THEN INDUCT_TAC THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC [NUMSEG_SING; VSUM_SING; SUB] THEN
+  REWRITE_TAC [higher_complex_derivative; binom; COMPLEX_MUL_LID] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+  EXISTS_TAC `\w. vsum (0..n)
+                    (\i. Cx (&(binom (n,i))) *
+                         higher_complex_derivative i f w *
+                         higher_complex_derivative (n-i) g w)` THEN
+  EXISTS_TAC `s:complex->bool` THEN ASM_SIMP_TAC [] THEN
+  SUBGOAL_THEN `vsum (0..SUC n) (\i. Cx (&(binom (SUC n,i))) *
+                                     higher_complex_derivative i f z *
+                                     higher_complex_derivative (SUC n-i) g z) =
+                vsum (0..n) (\i. Cx (&(binom (n,i))) *
+                                 (higher_complex_derivative i f z *
+                                  higher_complex_derivative (SUC n-i) g z +
+                                  higher_complex_derivative (SUC i) f z *
+                                  higher_complex_derivative (n-i) g z))`
+    SUBST1_TAC THENL
+  [SUBGOAL_THEN
+       `!i. binom(SUC n,i) = binom(n,i) + if i=0 then 0 else binom(n,PRE i)`
+     (fun th -> REWRITE_TAC[th; GSYM REAL_OF_NUM_ADD; CX_ADD]) THENL
+   [INDUCT_TAC THEN REWRITE_TAC[binom; NOT_SUC; PRE; ADD_SYM; ADD_0];
+    REWRITE_TAC [COMPLEX_ADD_LDISTRIB; COMPLEX_ADD_RDISTRIB]] THEN
+   SIMP_TAC [VSUM_ADD; FINITE_NUMSEG] THEN BINOP_TAC THENL
+   [REWRITE_TAC [VSUM_CLAUSES_NUMSEG; LE_0] THEN
+    SUBGOAL_THEN `binom(n,SUC n)=0` SUBST1_TAC THENL
+    [REWRITE_TAC [BINOM_EQ_0] THEN ARITH_TAC; CONV_TAC COMPLEX_RING];
+    SIMP_TAC [VSUM_CLAUSES_LEFT; SPEC `SUC n` LE_0] THEN
+    REWRITE_TAC [COMPLEX_MUL_LZERO; COMPLEX_ADD_LID; GSYM ADD1;
+                 VSUM_SUC; o_DEF; SUB_SUC; NOT_SUC; PRE]];
+   MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_VSUM THEN
+   REWRITE_TAC [FINITE_NUMSEG; IN_NUMSEG] THEN REPEAT STRIP_TAC THEN
+   MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_LMUL_AT THEN
+   MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_MUL_AT THEN
+   ASM_SIMP_TAC [ETA_AX; ARITH_RULE `i <= n ==> SUC n - i = SUC (n-i)`] THEN
+   ASM_MESON_TAC [HAS_COMPLEX_DERIVATIVE_HIGHER_COMPLEX_DERIVATIVE]]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN = prove
+ (`!f g s i z.
+     open s /\ f holomorphic_on s /\ g holomorphic_on s /\
+     (!w. w IN s ==> f w = g w) /\ z IN s
+     ==> higher_complex_derivative i f z = higher_complex_derivative i g z`,
+  REWRITE_TAC [IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN
+  REPEAT DISCH_TAC THEN INDUCT_TAC THEN REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC [higher_complex_derivative] THEN
+  MATCH_MP_TAC COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+  ASM_MESON_TAC [HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_COMPOSE_LINEAR = prove
+ (`!f u s t n z.
+     f holomorphic_on t /\ open s /\ open t /\
+     (!w. w IN s ==> u * w IN t) /\ z IN s
+     ==> higher_complex_derivative n (\w. f (u * w)) z =
+         u pow n * higher_complex_derivative n f (u * z)`,
+  REWRITE_TAC [RIGHT_FORALL_IMP_THM; IMP_CONJ] THEN
+  REPEAT GEN_TAC THEN REPEAT DISCH_TAC THEN INDUCT_TAC THEN
+  REWRITE_TAC [higher_complex_derivative; complex_pow; COMPLEX_MUL_LID] THEN
+  REPEAT STRIP_TAC THEN EQ_TRANS_TAC
+    `complex_derivative
+      (\z. u pow n * higher_complex_derivative n f (u * z)) z` THENL
+  [MATCH_MP_TAC COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+   EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC
+     (REWRITE_RULE [o_DEF]
+       (SPECL [`\z:complex. u * z`; `f:complex->complex`]
+              HOLOMORPHIC_ON_COMPOSE_GEN)) THEN
+    EXISTS_TAC `t:complex->bool` THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC
+     (REWRITE_RULE [o_DEF]
+       (SPECL [`\w:complex. u:complex`; `\w:complex. w`]
+              HOLOMORPHIC_ON_MUL)) THEN
+    REWRITE_TAC [HOLOMORPHIC_ON_CONST; HOLOMORPHIC_ON_ID];
+    MATCH_MP_TAC HOLOMORPHIC_ON_MUL THEN
+    SIMP_TAC [HOLOMORPHIC_ON_POW; HOLOMORPHIC_ON_CONST] THEN MATCH_MP_TAC
+     (REWRITE_RULE [o_DEF]
+       (SPECL [`\w. u * w`; `higher_complex_derivative f n`]
+              HOLOMORPHIC_ON_COMPOSE_GEN)) THEN
+    EXISTS_TAC `t:complex->bool` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+    [MATCH_MP_TAC
+      (REWRITE_RULE [o_DEF]
+        (SPECL [`\w:complex. u:complex`; `\w:complex. w`]
+               HOLOMORPHIC_ON_MUL)) THEN
+     REWRITE_TAC [HOLOMORPHIC_ON_CONST; HOLOMORPHIC_ON_ID];
+     ASM_SIMP_TAC [HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE]]];
+   EQ_TRANS_TAC
+     `u pow n * complex_derivative
+        (\z. higher_complex_derivative n f (u * z)) z` THENL
+   [MATCH_MP_TAC COMPLEX_DERIVATIVE_LMUL THEN
+    MATCH_MP_TAC ANALYTIC_ON_IMP_DIFFERENTIABLE_AT THEN
+    EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC (REWRITE_RULE [o_DEF] ANALYTIC_ON_COMPOSE_GEN) THEN
+    EXISTS_TAC `t:complex->bool` THEN
+    ASM_SIMP_TAC [ANALYTIC_ON_LINEAR; ANALYTIC_HIGHER_COMPLEX_DERIVATIVE;
+                  ANALYTIC_ON_OPEN];
+    ABBREV_TAC `a = u:complex pow n` THEN
+    REWRITE_TAC [COMPLEX_MUL_AC; COMPLEX_EQ_MUL_LCANCEL] THEN
+    ASM_CASES_TAC `a = Cx(&0)` THEN ASM_REWRITE_TAC[] THEN
+    GEN_REWRITE_TAC RAND_CONV [COMPLEX_MUL_SYM] THEN MATCH_MP_TAC
+     (REWRITE_RULE [o_DEF; COMPLEX_DIFFERENTIABLE_LINEAR;
+                    COMPLEX_DERIVATIVE_LINEAR]
+       (SPECL [`\w. u * w`;`higher_complex_derivative n f`]
+              COMPLEX_DERIVATIVE_CHAIN)) THEN
+    ASM_MESON_TAC [HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT;
+                   HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE]]]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_ADD_AT = prove
+ (`!f g n z.
+     f analytic_on {z} /\ g analytic_on {z}
+     ==> higher_complex_derivative n (\w. f w + g w) z =
+         higher_complex_derivative n f z +
+         higher_complex_derivative n g z`,
+  REWRITE_TAC [ANALYTIC_AT_TWO] THEN
+  MESON_TAC [HIGHER_COMPLEX_DERIVATIVE_ADD]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_SUB_AT = prove
+ (`!f g n z.
+     f analytic_on {z} /\ g analytic_on {z}
+     ==> higher_complex_derivative n (\w. f w - g w) z =
+         higher_complex_derivative n f z -
+         higher_complex_derivative n g z`,
+  REWRITE_TAC [ANALYTIC_AT_TWO] THEN
+  MESON_TAC [HIGHER_COMPLEX_DERIVATIVE_SUB]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_NEG_AT = prove
+ (`!f n z.
+     f analytic_on {z}
+     ==> higher_complex_derivative n (\w. --(f w)) z =
+         --(higher_complex_derivative n f z)`,
+  REWRITE_TAC [ANALYTIC_AT] THEN
+  MESON_TAC [HIGHER_COMPLEX_DERIVATIVE_NEG]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_MUL_AT = prove
+ (`!f g n z.
+     f analytic_on {z} /\ g analytic_on {z}
+     ==> higher_complex_derivative n (\w. f w * g w) z =
+         vsum (0..n) (\i. Cx(&(binom(n,i))) *
+                          higher_complex_derivative i f z *
+                          higher_complex_derivative (n-i) g z)`,
+  REWRITE_TAC [ANALYTIC_AT_TWO] THEN
+  MESON_TAC [HIGHER_COMPLEX_DERIVATIVE_MUL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Nonexistence of isolated singularities and a stronger integral formula.   *)
+(* ------------------------------------------------------------------------- *)
+
+let NO_ISOLATED_SINGULARITY = prove
+ (`!f s k. open s /\ FINITE k /\
+           f continuous_on s /\ f holomorphic_on (s DIFF k)
+           ==> f holomorphic_on s`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_DIFF; FINITE_IMP_CLOSED; IMP_CONJ] THEN
+  REWRITE_TAC[GSYM complex_differentiable] THEN REPEAT DISCH_TAC THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `(z:complex) IN k` THEN ASM_SIMP_TAC[IN_DIFF] THEN
+  MP_TAC(ISPECL [`z:complex`; `k:complex->bool`] FINITE_SET_AVOID) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `d:real` THEN
+  STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `f holomorphic_on ball(z,min d e)` MP_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL; CENTRE_IN_BALL; REAL_LT_MIN;
+                 complex_differentiable]] THEN
+  SUBGOAL_THEN
+   `?g. !w. w IN ball(z,min d e)
+            ==> (g has_complex_derivative f w) (at w within ball(z,min d e))`
+  MP_TAC THENL
+   [ALL_TAC;
+    SIMP_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN; OPEN_BALL] THEN
+    MESON_TAC[HOLOMORPHIC_DERIVATIVE; OPEN_BALL]] THEN
+  MATCH_MP_TAC PATHINTEGRAL_CONVEX_PRIMITIVE THEN
+  REWRITE_TAC[CONVEX_BALL] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:complex->bool` THEN
+    ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (SET_RULE `b SUBSET s ==> c SUBSET b ==> c SUBSET s`)) THEN
+    REWRITE_TAC[SUBSET; IN_BALL] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CAUCHY_THEOREM_TRIANGLE_COFINITE THEN
+  EXISTS_TAC `k:complex->bool` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:complex->bool` THEN
+    ASM_REWRITE_TAC[];
+    X_GEN_TAC `w:complex` THEN
+    DISCH_THEN(fun th -> FIRST_X_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+    SPEC_TAC(`w:complex`,`w:complex`) THEN ASM_REWRITE_TAC[GSYM SUBSET] THEN
+    MATCH_MP_TAC(SET_RULE `s SUBSET t ==> (s DIFF k) SUBSET (t DIFF k)`) THEN
+    MATCH_MP_TAC(SET_RULE
+     `interior s SUBSET s /\ s SUBSET t ==> interior s SUBSET t`) THEN
+    REWRITE_TAC[INTERIOR_SUBSET]] THEN
+  (MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `ball(z:complex,e)` THEN
+   ASM_REWRITE_TAC[] THEN
+   MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `ball(z:complex,min d e)` THEN
+   CONJ_TAC THENL
+    [MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_BALL] THEN
+     ASM SET_TAC[];
+     REWRITE_TAC[SUBSET; IN_BALL] THEN REAL_ARITH_TAC]));;
+
+let CAUCHY_INTEGRAL_FORMULA_CONVEX = prove
+ (`!f s k g z.
+        convex s /\ FINITE k /\ f continuous_on s /\
+        (!x. x IN interior(s) DIFF k ==> f complex_differentiable at x) /\
+        z IN interior(s) /\
+        valid_path g /\ (path_image g) SUBSET (s DELETE z) /\
+        pathfinish g = pathstart g
+        ==> ((\w. f(w) / (w - z)) has_path_integral
+             (Cx(&2) * Cx(pi) * ii * winding_number(g,z) * f(z))) g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CAUCHY_INTEGRAL_FORMULA_WEAK THEN
+  MAP_EVERY EXISTS_TAC [`s:complex->bool`; `{}:complex->bool`] THEN
+  ASM_REWRITE_TAC[DIFF_EMPTY; FINITE_RULES] THEN
+  SIMP_TAC[GSYM HOLOMORPHIC_ON_OPEN; complex_differentiable; OPEN_INTERIOR] THEN
+  MATCH_MP_TAC NO_ISOLATED_SINGULARITY THEN
+  EXISTS_TAC `k:complex->bool` THEN
+  ASM_REWRITE_TAC[OPEN_INTERIOR] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:complex->bool` THEN
+    ASM_REWRITE_TAC[INTERIOR_SUBSET];
+    ASM_SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_DIFF; FINITE_IMP_CLOSED;
+                 OPEN_INTERIOR; GSYM complex_differentiable]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Formula for higher derivatives.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_HAS_PATH_INTEGRAL_HIGHER_DERIVATIVE_CIRCLEPATH = prove
+ (`!f z r k w.
+        f continuous_on cball(z,r) /\
+        f holomorphic_on ball(z,r) /\
+        w IN ball(z,r)
+        ==> ((\u. f(u) / (u - w) pow (k + 1))
+             has_path_integral
+             ((Cx(&2) * Cx(pi) * ii) / Cx(&(FACT k)) *
+              higher_complex_derivative k f w))
+            (circlepath(z,r))`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REPEAT GEN_TAC THEN DISCH_TAC THEN DISCH_TAC THEN
+  ASM_CASES_TAC `&0 < r` THENL
+   [ALL_TAC;
+    REWRITE_TAC[IN_BALL] THEN
+    ASM_MESON_TAC[NORM_ARITH `~(&0 < r) ==> ~(dist(a,b) < r)`]] THEN
+  INDUCT_TAC THEN REWRITE_TAC[higher_complex_derivative] THENL
+   [REWRITE_TAC[ARITH; COMPLEX_POW_1; FACT; COMPLEX_DIV_1] THEN
+    ASM_SIMP_TAC[GSYM COMPLEX_MUL_ASSOC; CAUCHY_INTEGRAL_CIRCLEPATH];
+    ALL_TAC] THEN
+  MP_TAC(SPECL
+   [`f:complex->complex`;
+    `\x. (Cx(&2) * Cx(pi) * ii) / Cx(&(FACT k)) *
+         higher_complex_derivative k f x`;
+    `z:complex`; `r:real`; `k + 1`] CAUCHY_NEXT_DERIVATIVE_CIRCLEPATH) THEN
+  ASM_REWRITE_TAC[ADD1; ARITH_RULE `(k + 1) + 1 = k + 2`] THEN ANTS_TAC THENL
+   [REWRITE_TAC[ADD_EQ_0; ARITH_EQ] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+    EXISTS_TAC `cball(z:complex,r)` THEN ASM_REWRITE_TAC[] THEN
+    ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; REAL_LT_IMP_LE; SPHERE_SUBSET_CBALL];
+    ALL_TAC] THEN
+  DISCH_THEN(fun th ->
+    X_GEN_TAC `w:complex` THEN DISCH_TAC THEN MP_TAC(SPEC `w:complex` th)) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[path_integrable_on; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `y:complex` THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC(COMPLEX_FIELD
+   `~(a = Cx(&0)) /\ ~(b = Cx(&0)) /\ x = b / a * y ==> y = a / b * x`) THEN
+  REWRITE_TAC[CX_2PII_NZ; CX_INJ; REAL_OF_NUM_EQ; FACT_NZ] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HAS_COMPLEX_DERIVATIVE_LMUL_AT) THEN
+  DISCH_THEN(MP_TAC o SPEC `Cx(&(FACT k)) / (Cx(&2) * Cx pi * ii)`) THEN
+  REWRITE_TAC[] THEN MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN BINOP_TAC THENL
+   [REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN
+    MATCH_MP_TAC(COMPLEX_FIELD
+     `~(a = Cx(&0)) /\ ~(b = Cx(&0)) ==> (a / b) * (b / a) * x = x`) THEN
+    REWRITE_TAC[CX_2PII_NZ; CX_INJ; REAL_OF_NUM_EQ; FACT_NZ];
+    REWRITE_TAC[FACT; GSYM REAL_OF_NUM_MUL; GSYM ADD1; CX_MUL] THEN
+    MATCH_MP_TAC(COMPLEX_FIELD
+     `z:complex = y /\ ~(d = Cx(&0))
+      ==> k / d * k1 * z = (k1 * k) / d * y`) THEN
+    REWRITE_TAC[CX_2PII_NZ] THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+    ASM_REWRITE_TAC[]]);;
+
+let CAUCHY_HIGHER_DERIVATIVE_INTEGRAL_CIRCLEPATH = prove
+ (`!f z r k w.
+        f continuous_on cball(z,r) /\
+        f holomorphic_on ball(z,r) /\
+        w IN ball(z,r)
+        ==> (\u. f(u) / (u - w) pow (k + 1))
+                path_integrable_on circlepath(z,r) /\
+            higher_complex_derivative k f w =
+              Cx(&(FACT k)) / (Cx(&2) * Cx(pi) * ii) *
+              path_integral(circlepath(z,r)) (\u. f(u) / (u - w) pow (k + 1))`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP
+    CAUCHY_HAS_PATH_INTEGRAL_HIGHER_DERIVATIVE_CIRCLEPATH) THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[path_integrable_on]; ALL_TAC] THEN
+  MATCH_MP_TAC(COMPLEX_FIELD
+   `~(a = Cx(&0)) /\ ~(b = Cx(&0)) /\ x = b / a * y ==> y = a / b * x`) THEN
+  REWRITE_TAC[CX_2PII_NZ; CX_INJ; REAL_OF_NUM_EQ; FACT_NZ] THEN
+  MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A holomorphic function is analytic, i.e. has local power series.          *)
+(* ------------------------------------------------------------------------- *)
+
+let HOLOMORPHIC_POWER_SERIES = prove
+ (`!f z w r.
+     f holomorphic_on ball(z,r) /\ w IN ball(z,r)
+     ==> ((\n. higher_complex_derivative n f z / Cx(&(FACT n)) * (w - z) pow n)
+          sums f(w)) (from 0)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?r. &0 < r /\ f holomorphic_on cball(z,r) /\ w IN ball(z,r)`
+  MP_TAC THENL
+   [EXISTS_TAC `(r + dist(w:complex,z)) / &2` THEN REPEAT CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+      EXISTS_TAC `ball(z:complex,r)` THEN ASM_REWRITE_TAC[SUBSET];
+      ALL_TAC] THEN
+    UNDISCH_TAC `(w:complex) IN ball(z,r)` THEN
+    REWRITE_TAC[IN_BALL; IN_CBALL] THEN NORM_ARITH_TAC;
+    ALL_TAC] THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `f holomorphic_on ball(z,r) /\ f continuous_on cball(z,r)`
+  STRIP_ASSUME_TAC THENL
+   [ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON] THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN ASM_MESON_TAC[BALL_SUBSET_CBALL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `((\k. path_integral (circlepath(z,r)) (\u. f u / (u - z) pow (k + 1)) *
+          (w - z) pow k)
+     sums path_integral (circlepath(z,r)) (\u. f u / (u - w))) (from 0)`
+  MP_TAC THENL
+   [ALL_TAC;
+    DISCH_THEN(MP_TAC o SPEC `inv(Cx(&2) * Cx(pi) * ii)` o
+        MATCH_MP SERIES_COMPLEX_LMUL) THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN BINOP_TAC THENL
+     [REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `k:num` THEN
+      MP_TAC(SPECL [`f:complex->complex`; `z:complex`; `r:real`; `k:num`;
+       `z:complex`] CAUCHY_HAS_PATH_INTEGRAL_HIGHER_DERIVATIVE_CIRCLEPATH) THEN
+      ASM_REWRITE_TAC[CENTRE_IN_BALL] THEN
+      DISCH_THEN(SUBST1_TAC o MATCH_MP PATH_INTEGRAL_UNIQUE) THEN
+      MATCH_MP_TAC(COMPLEX_FIELD
+       `~(pit = Cx(&0)) /\ ~(fact = Cx(&0))
+        ==> inv(pit) * ((pit / fact) * d) * wz = d / fact * wz`) THEN
+      REWRITE_TAC[CX_2PII_NZ; CX_INJ; REAL_OF_NUM_EQ; FACT_NZ];
+      MP_TAC(SPECL [`f:complex->complex`; `z:complex`; `r:real`; `w:complex`]
+        CAUCHY_INTEGRAL_CIRCLEPATH_SIMPLE) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(SUBST1_TAC o MATCH_MP PATH_INTEGRAL_UNIQUE) THEN
+      MATCH_MP_TAC(COMPLEX_FIELD
+       `~(x * y * z = Cx(&0)) ==> inv(x * y * z) * x * y * z * w = w`) THEN
+      REWRITE_TAC[CX_2PII_NZ]]] THEN
+  REWRITE_TAC[sums; FROM_0; INTER_UNIV] THEN
+  MATCH_MP_TAC LIM_TRANSFORM_EVENTUALLY THEN
+  EXISTS_TAC `\n. path_integral (circlepath(z,r))
+                   (\u. vsum (0..n)
+                         (\k. f u * (w - z) pow k / (u - z) pow (k + 1)))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC ALWAYS_EVENTUALLY THEN
+    X_GEN_TAC `k:num` THEN REWRITE_TAC[] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) PATH_INTEGRAL_VSUM o lhand o snd) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[FINITE_NUMSEG] THEN X_GEN_TAC `m:num` THEN DISCH_TAC THEN
+      ONCE_REWRITE_TAC[SIMPLE_COMPLEX_ARITH
+       `a * b / c:complex = b * a / c`] THEN
+      MATCH_MP_TAC PATH_INTEGRABLE_COMPLEX_LMUL THEN
+      ASM_SIMP_TAC[CAUCHY_HIGHER_DERIVATIVE_INTEGRAL_CIRCLEPATH;
+                   CENTRE_IN_BALL];
+      ALL_TAC] THEN
+    DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC VSUM_EQ THEN
+    X_GEN_TAC `m:num` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[SIMPLE_COMPLEX_ARITH `a * b / c:complex = a / c * b`] THEN
+    MATCH_MP_TAC PATH_INTEGRAL_COMPLEX_RMUL THEN
+    ASM_SIMP_TAC[CAUCHY_HIGHER_DERIVATIVE_INTEGRAL_CIRCLEPATH; CENTRE_IN_BALL];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(CONJUNCT2
+   (REWRITE_RULE[FORALL_AND_THM; TAUT `a ==> b /\ c <=> (a ==> b) /\ (a ==> c)`]
+        PATH_INTEGRAL_UNIFORM_LIMIT_CIRCLEPATH)) THEN
+  ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC ALWAYS_EVENTUALLY THEN
+    X_GEN_TAC `k:num` THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC PATH_INTEGRABLE_VSUM THEN
+    REWRITE_TAC[FINITE_NUMSEG] THEN X_GEN_TAC `m:num` THEN DISCH_TAC THEN
+    ONCE_REWRITE_TAC[SIMPLE_COMPLEX_ARITH `a * b / c:complex = b * a / c`] THEN
+    MATCH_MP_TAC PATH_INTEGRABLE_COMPLEX_LMUL THEN
+    ASM_SIMP_TAC[CAUCHY_HIGHER_DERIVATIVE_INTEGRAL_CIRCLEPATH; CENTRE_IN_BALL];
+    ALL_TAC] THEN
+  X_GEN_TAC `e:real` THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; REAL_LT_IMP_LE; IN_ELIM_THM] THEN
+  SIMP_TAC[VSUM_COMPLEX_LMUL; FINITE_NUMSEG; complex_div] THEN
+  REWRITE_TAC[GSYM COMPLEX_SUB_LDISTRIB; COMPLEX_NORM_MUL] THEN
+  REWRITE_TAC[COMPLEX_POW_ADD; COMPLEX_INV_MUL; COMPLEX_POW_1] THEN
+  SIMP_TAC[COMPLEX_MUL_ASSOC; VSUM_COMPLEX_RMUL; FINITE_NUMSEG] THEN
+  REWRITE_TAC[GSYM complex_div; GSYM COMPLEX_POW_DIV] THEN
+  REWRITE_TAC[VSUM_GP; CONJUNCT1 LT; CONJUNCT1 complex_pow] THEN
+  REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+  SUBGOAL_THEN
+   `?B. &0 < B /\
+        !u:complex. u IN cball(z,r) ==> norm(f u:complex) <= B`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPEC `IMAGE (f:complex->complex) (cball(z,r))`
+      COMPACT_IMP_BOUNDED) THEN
+    ASM_SIMP_TAC[COMPACT_CONTINUOUS_IMAGE; COMPACT_CBALL] THEN
+    REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `?k. &0 < k /\ k <= r /\ norm(w - z) <= r - k /\
+                    !u. norm(u - z) = r ==> k <= norm(u - w)`
+  STRIP_ASSUME_TAC THENL
+   [EXISTS_TAC `r - dist(z:complex,w)` THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN REWRITE_TAC[IN_BALL] THEN
+    NORM_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[IN_SPHERE; NORM_ARITH `dist(z,x) = r <=> norm(x - z) = r`] THEN
+  MP_TAC(SPECL [`(r - k) / r:real`; `e / B * k:real`] REAL_ARCH_POW_INV) THEN
+  ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_LT_DIV; REAL_HALF; REAL_LT_MUL] THEN
+  ASM_REWRITE_TAC[REAL_ARITH `r - k < &1 * r <=> &0 < k`] 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
+  X_GEN_TAC `u:complex` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `~(u:complex = z) /\ ~(u = w)` STRIP_ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_BALL]) THEN
+    MAP_EVERY UNDISCH_TAC [`&0 < r`; `norm(u - z:complex) = r`] THEN
+    NORM_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[COMPLEX_FIELD
+   `~(u = z) /\ ~(u = w) ==> ~((w - z) / (u - z) = Cx(&1))`] THEN
+  ASM_SIMP_TAC[COMPLEX_FIELD
+   `~(u = z) /\ ~(u = w)
+    ==> x / (Cx(&1) - (w - z) / (u - z)) / (u - z) = x / (u - w)`] THEN
+  ASM_SIMP_TAC[COMPLEX_FIELD
+   `~(u = w)
+    ==> (Cx(&1) - e) / (u - w) - inv(u - w) = --(e / (u - w))`] THEN
+  REWRITE_TAC[COMPLEX_NORM_DIV; NORM_NEG; COMPLEX_NORM_POW] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `B * ((r - k) / r) pow N / k:real` THEN CONJ_TAC THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_LT_LDIV_EQ]] THEN
+  MATCH_MP_TAC REAL_LE_MUL2 THEN ASM_SIMP_TAC[NORM_POS_LE] THEN
+  REPEAT CONJ_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[IN_CBALL] THEN
+    ONCE_REWRITE_TAC[DIST_SYM] THEN ASM_REWRITE_TAC[dist; REAL_LE_REFL];
+    MATCH_MP_TAC REAL_LE_DIV THEN REWRITE_TAC[NORM_POS_LE] THEN
+    MATCH_MP_TAC REAL_POW_LE THEN MATCH_MP_TAC REAL_LE_DIV THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; NORM_POS_LE];
+    ALL_TAC] THEN
+  REWRITE_TAC[real_div] THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+  REWRITE_TAC[GSYM real_div] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_POW_LE THEN MATCH_MP_TAC REAL_LE_DIV THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; NORM_POS_LE];
+    ALL_TAC;
+    REWRITE_TAC[REAL_LE_INV_EQ; NORM_POS_LE];
+    MATCH_MP_TAC REAL_LE_INV2 THEN ASM_SIMP_TAC[]] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `((r - k) / r:real) pow (SUC n)` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_POW_LE2 THEN
+    ASM_SIMP_TAC[REAL_LE_DIV2_EQ; REAL_LE_DIV; NORM_POS_LE; REAL_LT_IMP_LE];
+    MATCH_MP_TAC REAL_POW_MONO_INV THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ] THEN
+    ASM_SIMP_TAC[ARITH_RULE `N <= n ==> N <= SUC n`] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Liouville's theorem.                                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let LIOUVILLE_THEOREM = prove
+ (`!f. f holomorphic_on (:complex) /\ bounded (IMAGE f (:complex))
+       ==> ?c. !z. f(z) = c`,
+  GEN_TAC THEN
+  SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_UNIV; BOUNDED_POS; IN_UNIV;
+           FORALL_IN_IMAGE; SKOLEM_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `f':complex->complex`)
+               (X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC)) THEN
+  SUBGOAL_THEN `!w. w IN (:complex) ==> f w:complex = f z`
+   (fun th -> MESON_TAC[th; IN_UNIV]) THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_ZERO_UNIQUE THEN
+  EXISTS_TAC `z:complex` THEN
+  REWRITE_TAC[IN_UNIV; CONVEX_UNIV; WITHIN_UNIV] THEN
+  X_GEN_TAC `w:complex` THEN
+  SUBGOAL_THEN `(f':complex->complex) w = Cx(&0)`
+   (fun th -> ASM_MESON_TAC[th]) THEN
+  REWRITE_TAC[GSYM COMPLEX_NORM_ZERO] THEN
+  MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ ~(&0 < x) ==> x = &0`) THEN
+  REWRITE_TAC[NORM_POS_LE] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `?R. &0 < R /\ B / R < norm((f':complex->complex) w)`
+  STRIP_ASSUME_TAC THENL
+   [EXISTS_TAC `&2 * B / norm((f':complex->complex) w)` THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_MUL; REAL_OF_NUM_LT; ARITH] THEN
+    REWRITE_TAC[real_div; REAL_INV_MUL; REAL_INV_INV; GSYM REAL_MUL_ASSOC] THEN
+    ASM_SIMP_TAC[REAL_FIELD
+     `&0 < B ==> B * inv(&2) * inv(B) * c = c / &2`] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(SPECL [`f:complex->complex`; `w:complex`;
+                `R:real`; `w:complex`]
+               CAUCHY_DERIVATIVE_INTEGRAL_CIRCLEPATH) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; HOLOMORPHIC_ON_OPEN;
+                 OPEN_BALL; CENTRE_IN_BALL; REAL_LT_DIV; REAL_HALF] THEN
+    ASM_MESON_TAC[HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT;
+                  CONTINUOUS_AT_WITHIN];
+    ALL_TAC] THEN
+  STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_INTEGRAL) THEN
+  DISCH_THEN(MP_TAC o SPEC `B:real / R pow 2` o MATCH_MP
+   (ONCE_REWRITE_RULE[IMP_CONJ] HAS_PATH_INTEGRAL_BOUND_CIRCLEPATH)) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_IMP_LE; REAL_POW_LT] THEN
+  ASM_SIMP_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_POW; REAL_LE_DIV2_EQ;
+               REAL_POW_LT; REAL_NOT_LE] THEN
+  MATCH_MP_TAC REAL_LT_LCANCEL_IMP THEN
+  EXISTS_TAC `norm(Cx(&1) / (Cx (&2) * Cx pi * ii))` THEN
+  REWRITE_TAC[GSYM COMPLEX_NORM_MUL] THEN
+  SUBGOAL_THEN
+   `Cx(&1) / (Cx(&2) * Cx pi * ii) *
+    path_integral (circlepath (w,R)) (\u. f u / (u - w) pow 2) =
+    f' w`
+  SUBST1_TAC THENL [ASM_MESON_TAC[COMPLEX_DERIVATIVE_UNIQUE_AT]; ALL_TAC] THEN
+  REWRITE_TAC[COMPLEX_NORM_NZ] THEN
+  ASM_SIMP_TAC[CX_2PII_NZ;
+    COMPLEX_FIELD `~(y = Cx(&0)) ==> ~(Cx(&1) / y = Cx(&0))`] THEN
+  REWRITE_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_MUL; COMPLEX_NORM_CX] THEN
+  REWRITE_TAC[REAL_ABS_NUM; REAL_ABS_PI; COMPLEX_NORM_II] THEN
+  ASM_SIMP_TAC[PI_POS; REAL_FIELD
+   `&0 < R /\ &0 < pi
+   ==> &1 / (&2 * pi * &1) * B / R pow 2 * &2 * pi * R = B / R`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* These weaker versions don't even need the derivative formula.             *)
+(* ------------------------------------------------------------------------- *)
+
+let LIOUVILLE_WEAK = prove
+ (`!f. f holomorphic_on (:complex) /\ (f --> Cx(&0)) at_infinity
+       ==> !z. f(z) = Cx(&0)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[TAUT `p = ~ ~ p`] THEN
+  PURE_REWRITE_TAC[GSYM COMPLEX_NORM_NZ] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIM_AT_INFINITY]) THEN
+  DISCH_THEN(MP_TAC o SPEC `norm((f:complex->complex) z) / &2`) THEN
+  ASM_REWRITE_TAC[dist; REAL_HALF; COMPLEX_SUB_RZERO] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPECL [`f:complex->complex`; `z:complex`;
+                `&1 + abs B + norm(z:complex)`; `z:complex`]
+                CAUCHY_INTEGRAL_CIRCLEPATH) THEN
+  ASM_SIMP_TAC[CONVEX_UNIV; INTERIOR_OPEN; OPEN_UNIV; IN_UNIV] THEN
+  ABBREV_TAC `R = &1 + abs B + norm(z:complex)` THEN
+  SUBGOAL_THEN `&0 < R` ASSUME_TAC THENL
+   [ASM_MESON_TAC[NORM_POS_LE; REAL_ABS_POS; REAL_ARITH
+     `&0 <= x /\ &0 <= y ==> &0 < &1 + x + y`]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[CENTRE_IN_BALL; NOT_IMP; CONJ_ASSOC] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON; HOLOMORPHIC_ON_SUBSET;
+                  SUBSET_UNIV];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP
+   (ONCE_REWRITE_RULE[IMP_CONJ] HAS_PATH_INTEGRAL_BOUND_CIRCLEPATH)) THEN
+  DISCH_THEN(MP_TAC o SPEC `norm((f:complex->complex) z) / &2 / R`) THEN
+  ASM_SIMP_TAC[REAL_LE_DIV; NORM_POS_LE; REAL_POS; REAL_LT_IMP_LE] THEN
+  ASM_SIMP_TAC[REAL_FIELD `&0 < R ==> x / R * &2 * pi * R = &2 * pi * x`] THEN
+  REWRITE_TAC[NOT_IMP; REAL_NOT_LE] THEN CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN ASM_SIMP_TAC[COMPLEX_NORM_DIV; REAL_LE_DIV2_EQ] THEN
+    MATCH_MP_TAC REAL_LT_IMP_LE THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    UNDISCH_TAC `norm(x - z:complex) = R` THEN EXPAND_TAC "R" THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `d <= x + z ==> d = &1 + abs b + z ==> x >= b`) THEN
+    REWRITE_TAC[VECTOR_SUB] THEN MESON_TAC[NORM_TRIANGLE; NORM_NEG];
+    REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX; REAL_ABS_NUM; REAL_ABS_PI;
+                COMPLEX_NORM_II] THEN
+    SIMP_TAC[REAL_LT_LMUL_EQ; REAL_OF_NUM_LT; ARITH; PI_POS; REAL_MUL_LID] THEN
+    SUBGOAL_THEN `?w:complex. norm w = abs B` MP_TAC THENL
+     [MESON_TAC[VECTOR_CHOOSE_SIZE; REAL_ABS_POS]; ALL_TAC] THEN
+    ASM_MESON_TAC[NORM_POS_LE; REAL_ARITH
+     `abs B >= B /\ (&0 <= x /\ x < z / &2 ==> z / &2 < z)`]]);;
+
+let LIOUVILLE_WEAK_INVERSE = prove
+ (`!f. f holomorphic_on (:complex) /\
+       (!B. eventually (\x. norm(f x) >= B) at_infinity)
+       ==> ?z. f(z) = Cx(&0)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN
+  PURE_REWRITE_TAC[NOT_EXISTS_THM] THEN DISCH_TAC THEN
+  MP_TAC(SPEC `\x:complex. Cx(&1) / (f(x))` LIOUVILLE_WEAK) THEN
+  ASM_SIMP_TAC[COMPLEX_FIELD `~(y = Cx(&0)) ==> ~(Cx(&1) / y = Cx(&0))`] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[holomorphic_on; complex_div; COMPLEX_MUL_LID; IN_UNIV] THEN
+    GEN_TAC THEN REWRITE_TAC[GSYM complex_differentiable; WITHIN_UNIV] THEN
+    MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_INV_AT THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[OPEN_UNIV; HOLOMORPHIC_ON_OPEN; IN_UNIV;
+                  complex_differentiable];
+    REWRITE_TAC[tendsto] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `&2/ e`) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+    REWRITE_TAC[dist; COMPLEX_SUB_RZERO; real_ge; COMPLEX_NORM_DIV;
+                COMPLEX_NORM_CX; REAL_ABS_POS] THEN
+    ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_LE_LDIV_EQ; COMPLEX_NORM_NZ] THEN
+    REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In particular we get the Fundamental Theorem of Algebra.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let FTA = prove
+ (`!a n. a(0) = Cx(&0) \/ ~(!k. k IN 1..n ==> a(k) = Cx(&0))
+         ==> ?z. vsum(0..n) (\i. a(i) * z pow i) = Cx(&0)`,
+  REPEAT STRIP_TAC THENL
+   [EXISTS_TAC `Cx(&0)` THEN
+    SIMP_TAC[VSUM_CLAUSES_LEFT; LE_0] THEN
+    ASM_SIMP_TAC[ADD_CLAUSES; COMPLEX_POW_ZERO; LE_1; COMPLEX_ADD_LID;
+                 COMPLEX_MUL_RZERO; COMPLEX_MUL_LZERO] THEN
+    REWRITE_TAC[GSYM COMPLEX_VEC_0; VSUM_0];
+    MATCH_MP_TAC LIOUVILLE_WEAK_INVERSE THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HOLOMORPHIC_ON_VSUM THEN
+      SIMP_TAC[FINITE_NUMSEG; HOLOMORPHIC_ON_POW; HOLOMORPHIC_ON_MUL;
+               HOLOMORPHIC_ON_CONST; HOLOMORPHIC_ON_ID];
+      ASM_MESON_TAC[COMPLEX_POLYFUN_EXTREMAL]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Weierstrass convergence theorem.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let HOLOMORPHIC_UNIFORM_LIMIT = prove
+ (`!net:(A net) f g z r.
+        ~(trivial_limit net) /\
+        eventually
+           (\n. (f n) continuous_on cball(z,r) /\
+                (f n) holomorphic_on ball(z,r))
+           net /\
+        (!e. &0 < e
+             ==> eventually (\n. !x. x IN cball(z,r) ==> norm(f n x - g x) < e)
+                            net)
+        ==> g continuous_on cball(z,r) /\ g holomorphic_on ball(z,r)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  DISJ_CASES_TAC(REAL_ARITH `r <= &0 \/ &0 < r`) THENL
+   [ASM_SIMP_TAC[BALL_EMPTY; holomorphic_on; NOT_IN_EMPTY] THEN
+    FIRST_X_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+     `r <= &0 ==> r < &0 \/ r = &0`)) THEN
+    ASM_SIMP_TAC[continuous_on; CBALL_EMPTY; CBALL_SING; NOT_IN_EMPTY] THEN
+    SIMP_TAC[IN_SING; DIST_REFL] THEN MESON_TAC[REAL_LT_01];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_UNIFORM_LIMIT THEN
+    MAP_EVERY EXISTS_TAC [`net:A net`; `f:A->complex->complex`] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[EVENTUALLY_AND]) THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  DISCH_TAC THEN
+  MP_TAC(ISPECL
+   [`\x. Cx(&1) / (Cx(&2) * Cx pi * ii) * g(x:complex)`;
+    `g:complex->complex`; `z:complex`; `r:real`; `1`]
+     CAUCHY_NEXT_DERIVATIVE_CIRCLEPATH) THEN
+  SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL] THEN
+  ANTS_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+  REWRITE_TAC[ARITH] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+    ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; REAL_LT_IMP_LE] THEN
+    EXISTS_TAC `cball(z:complex,r)` THEN ASM_REWRITE_TAC[ETA_AX] THEN
+    SIMP_TAC[SPHERE_SUBSET_CBALL];
+    ALL_TAC] THEN
+  X_GEN_TAC `w:complex` THEN DISCH_TAC THEN REWRITE_TAC[COMPLEX_POW_1] THEN
+  REWRITE_TAC[complex_div; GSYM COMPLEX_MUL_ASSOC] THEN
+  REWRITE_TAC[GSYM complex_div] THEN REWRITE_TAC[COMPLEX_MUL_ASSOC] THEN
+  REWRITE_TAC[GSYM complex_div] THEN REWRITE_TAC[GSYM COMPLEX_MUL_ASSOC] THEN
+  SUBGOAL_THEN
+   `(\u. g u / (u - w)) path_integrable_on circlepath(z,r) /\
+    ((\n:A. path_integral(circlepath(z,r))
+            (\u. f n u / (u - w))) -->
+     path_integral(circlepath(z,r)) (\u. g u / (u - w))) net`
+  MP_TAC THENL
+   [MATCH_MP_TAC PATH_INTEGRAL_UNIFORM_LIMIT_CIRCLEPATH THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(fun th -> MP_TAC th THEN
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO)) THEN
+      X_GEN_TAC `a:A` THEN REWRITE_TAC[] THEN STRIP_TAC THEN
+      MATCH_MP_TAC PATH_INTEGRABLE_CONTINUOUS_CIRCLEPATH THEN
+      ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; REAL_LT_IMP_LE] THEN
+      REWRITE_TAC[sphere; NORM_ARITH `dist(z,w) = norm(w - z)`] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_DIV THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+        EXISTS_TAC `cball(z:complex,r)` THEN ASM_REWRITE_TAC[ETA_AX] THEN
+        SIMP_TAC[SUBSET; IN_CBALL; IN_ELIM_THM; NORM_SUB; dist; REAL_LE_REFL];
+        ALL_TAC] THEN
+      ASM_SIMP_TAC[CONTINUOUS_ON_COMPLEX_POW; CONTINUOUS_ON_SUB;
+                   CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+      REWRITE_TAC[COMPLEX_POW_EQ_0; ARITH; IN_ELIM_THM] THEN
+      GEN_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+      SIMP_TAC[COMPLEX_SUB_0] THEN DISCH_THEN SUBST_ALL_TAC THEN
+      ASM_MESON_TAC[IN_BALL; dist; REAL_LT_REFL; DIST_SYM];
+      ALL_TAC] THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `e * abs(r - norm(w - z:complex))`) THEN
+    SUBGOAL_THEN `&0 < e * abs(r - norm(w - z:complex))` ASSUME_TAC THENL
+     [MATCH_MP_TAC REAL_LT_MUL THEN ASM_REWRITE_TAC[GSYM REAL_ABS_NZ] THEN
+      SIMP_TAC[REAL_SUB_0] THEN
+      ASM_MESON_TAC[IN_BALL; dist; REAL_LT_REFL; DIST_SYM];
+      ALL_TAC] THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+    X_GEN_TAC `a:A` THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:complex` THEN
+    ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[sphere; NORM_ARITH `dist(z,w) = norm(w - z)`] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+    ASM_REWRITE_TAC[IN_CBALL] THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+    ASM_REWRITE_TAC[dist; REAL_LE_REFL] THEN
+    SUBGOAL_THEN `~(x:complex = w)` ASSUME_TAC THENL
+     [DISCH_THEN SUBST_ALL_TAC THEN
+      ASM_MESON_TAC[IN_BALL; dist; NORM_SUB; REAL_LT_REFL];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[COMPLEX_FIELD
+     `~(x = w) ==> a / (x - w) - b / (x - w) =
+                   (a - b:complex) / (x - w)`] THEN
+    ASM_SIMP_TAC[COMPLEX_NORM_DIV; REAL_LT_LDIV_EQ; COMPLEX_NORM_NZ;
+                 COMPLEX_POW_EQ_0; COMPLEX_SUB_0] THEN
+    MATCH_MP_TAC(REAL_ARITH `a <= b ==> x < a ==> x < b`) THEN
+    ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_LT_IMP_LE; COMPLEX_NORM_POW] THEN
+    MATCH_MP_TAC(REAL_ARITH `w < r /\ r <= x + w ==> abs(r - w) <= x`) THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[IN_BALL; dist; NORM_SUB]; ALL_TAC] THEN
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[GSYM dist] THEN MESON_TAC[DIST_TRIANGLE];
+    ALL_TAC] THEN
+  STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_INTEGRAL) THEN
+  DISCH_THEN(MP_TAC o SPEC `Cx(&1) / (Cx(&2) * Cx pi * ii)` o
+    MATCH_MP HAS_PATH_INTEGRAL_COMPLEX_LMUL) THEN
+  MATCH_MP_TAC EQ_IMP THEN REWRITE_TAC[] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC LIM_UNIQUE THEN
+  MAP_EVERY EXISTS_TAC [`net:A net`; `\n. (f:A->complex->complex) n w`] THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[tendsto; dist] THEN X_GEN_TAC `e:real` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+    REWRITE_TAC[] THEN ASM_MESON_TAC[SUBSET; BALL_SUBSET_CBALL]] THEN
+  SUBGOAL_THEN
+   `((\n:A. Cx(&2) * Cx pi * ii * f n w)
+     --> path_integral (circlepath (z,r)) (\u. g u / (u - w))) net`
+  MP_TAC THENL
+   [MATCH_MP_TAC LIM_TRANSFORM_EVENTUALLY THEN EXISTS_TAC
+     `\n:A. path_integral (circlepath (z,r)) (\u. f n u / (u - w))` THEN
+    ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(fun th -> MP_TAC th THEN
+     MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO)) THEN
+    X_GEN_TAC `a:A` THEN REWRITE_TAC[] THEN STRIP_TAC THEN
+    MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+    MATCH_MP_TAC CAUCHY_INTEGRAL_CIRCLEPATH THEN
+    ASM_REWRITE_TAC[ETA_AX];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `Cx(&1) / (Cx(&2) * Cx pi * ii)` o
+    MATCH_MP LIM_COMPLEX_LMUL) THEN
+  SIMP_TAC[CX_2PII_NZ; COMPLEX_FIELD
+   `~(x * y * z = Cx(&0)) ==> Cx(&1) / (x * y * z) * x * y * z * w = w`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Version showing that the limit is the limit of the derivatives.           *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_COMPLEX_DERIVATIVE_UNIFORM_LIMIT = prove
+ (`!net:(A net) f f' g z r.
+        &0 < r /\ ~(trivial_limit net) /\
+        eventually
+          (\n. (f n) continuous_on cball(z,r) /\
+               (!w. w IN ball(z,r)
+                    ==> ((f n) has_complex_derivative (f' n w)) (at w)))
+          net /\
+        (!e. &0 < e
+             ==> eventually (\n. !x. x IN cball(z,r) ==> norm(f n x - g x) < e)
+                            net)
+        ==> g continuous_on cball(z,r) /\
+            ?g'. !w. w IN ball(z,r)
+                     ==> (g has_complex_derivative (g' w)) (at w) /\
+                         ((\n. f' n w) --> g' w) net`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(SPECL [`net:(A)net`; `f:A->complex->complex`;
+                `g:complex->complex`; `z:complex`; `r:real`]
+               HOLOMORPHIC_UNIFORM_LIMIT) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(fun th ->
+      MP_TAC th THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ]
+        EVENTUALLY_MONO)) THEN
+    SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
+    (MP_TAC o REWRITE_RULE[RIGHT_IMP_EXISTS_THM])) THEN
+  REWRITE_TAC[SKOLEM_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `g':complex->complex` THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[] THEN X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[LIM_NULL] THEN MATCH_MP_TAC LIM_TRANSFORM_EVENTUALLY THEN
+  EXISTS_TAC
+   `\n. Cx(&1) / (Cx(&2) * Cx pi * ii) *
+        (path_integral(circlepath(z,r)) (\x. f (n:A) x / (x - w) pow 2) -
+         path_integral(circlepath(z,r)) (\x. g x / (x - w) pow 2))` THEN
+  REWRITE_TAC[] THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM(fun th ->
+      MP_TAC th THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ]
+        EVENTUALLY_MONO)) THEN
+    X_GEN_TAC `a:A` THEN REWRITE_TAC[] THEN STRIP_TAC THEN
+    REWRITE_TAC[COMPLEX_SUB_LDISTRIB] THEN BINOP_TAC THEN
+    MATCH_MP_TAC COMPLEX_DERIVATIVE_UNIQUE_AT THENL
+     [EXISTS_TAC `(f:A->complex->complex) a`;
+      EXISTS_TAC `g:complex->complex`] THEN
+    EXISTS_TAC `w:complex` THEN ASM_SIMP_TAC[] THEN
+    W(fun (asl,w) -> MP_TAC(PART_MATCH (rand o rand)
+      CAUCHY_DERIVATIVE_INTEGRAL_CIRCLEPATH w)) THEN
+    ASM_SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL] THEN
+    ANTS_TAC THEN SIMP_TAC[] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[COMPLEX_VEC_0] THEN
+  SUBST1_TAC(SYM(SPEC `Cx(&1) / (Cx(&2) * Cx pi * ii)` COMPLEX_MUL_RZERO)) THEN
+  MATCH_MP_TAC LIM_COMPLEX_MUL THEN REWRITE_TAC[LIM_CONST] THEN
+  REWRITE_TAC[GSYM COMPLEX_VEC_0] THEN REWRITE_TAC[GSYM LIM_NULL] THEN
+  W(fun (asl,w) -> MP_TAC(PART_MATCH (rand o rand)
+      PATH_INTEGRAL_UNIFORM_LIMIT_CIRCLEPATH w)) THEN
+  ANTS_TAC THEN ASM_SIMP_TAC[] THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM(fun th -> MP_TAC th THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO)) THEN
+    X_GEN_TAC `a:A` THEN REWRITE_TAC[] THEN STRIP_TAC THEN
+    MATCH_MP_TAC PATH_INTEGRABLE_CONTINUOUS_CIRCLEPATH THEN
+    ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[sphere; NORM_ARITH `dist(z,w) = norm(w - z)`] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_DIV THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+      EXISTS_TAC `cball(z:complex,r)` THEN ASM_REWRITE_TAC[ETA_AX] THEN
+      SIMP_TAC[SUBSET; IN_CBALL; IN_ELIM_THM; NORM_SUB; dist; REAL_LE_REFL];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_COMPLEX_POW; CONTINUOUS_ON_SUB;
+                 CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+    REWRITE_TAC[COMPLEX_POW_EQ_0; ARITH; IN_ELIM_THM] THEN
+    GEN_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    SIMP_TAC[COMPLEX_SUB_0] THEN DISCH_THEN SUBST_ALL_TAC THEN
+    ASM_MESON_TAC[IN_BALL; dist; REAL_LT_REFL; DIST_SYM];
+    ALL_TAC] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e * abs(r - norm(w - z:complex)) pow 2`) THEN
+  SUBGOAL_THEN `&0 < e * abs(r - norm(w - z:complex)) pow 2` ASSUME_TAC THENL
+   [MATCH_MP_TAC REAL_LT_MUL THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC REAL_POW_LT THEN REWRITE_TAC[GSYM REAL_ABS_NZ] THEN
+    SIMP_TAC[REAL_SUB_0] THEN
+    ASM_MESON_TAC[IN_BALL; dist; REAL_LT_REFL; DIST_SYM];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+  X_GEN_TAC `a:A` THEN REWRITE_TAC[] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:complex` THEN
+  ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; REAL_LT_IMP_LE] THEN
+  REWRITE_TAC[sphere; NORM_ARITH `dist(z,w) = norm(w - z)`] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[IN_CBALL] THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+  ASM_REWRITE_TAC[dist; REAL_LE_REFL] THEN
+  SUBGOAL_THEN `~(x:complex = w)` ASSUME_TAC THENL
+   [DISCH_THEN SUBST_ALL_TAC THEN
+    ASM_MESON_TAC[IN_BALL; dist; NORM_SUB; REAL_LT_REFL];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[COMPLEX_FIELD
+   `~(x = w) ==> a / (x - w) pow 2 - b / (x - w) pow 2 =
+                 (a - b:complex) / (x - w) pow 2`] THEN
+  ASM_SIMP_TAC[COMPLEX_NORM_DIV; REAL_LT_LDIV_EQ; COMPLEX_NORM_NZ;
+               COMPLEX_POW_EQ_0; COMPLEX_SUB_0] THEN
+  MATCH_MP_TAC(REAL_ARITH `a <= b ==> x < a ==> x < b`) THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_LT_IMP_LE; COMPLEX_NORM_POW] THEN
+  MATCH_MP_TAC REAL_POW_LE2 THEN REWRITE_TAC[REAL_ABS_POS] THEN
+  MATCH_MP_TAC(REAL_ARITH `w < r /\ r <= x + w ==> abs(r - w) <= x`) THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[IN_BALL; dist; NORM_SUB]; ALL_TAC] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[GSYM dist] THEN MESON_TAC[DIST_TRIANGLE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some more simple/convenient versions for applications.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let HOLOMORPHIC_UNIFORM_SEQUENCE = prove
+ (`!f g s.
+        open s /\
+        (!n. (f n) holomorphic_on s) /\
+        (!x. x IN s
+             ==> ?d. &0 < d /\ cball(x,d) SUBSET s /\
+                     !e. &0 < e
+                         ==> eventually (\n. !y. y IN cball(x,d)
+                                                 ==> norm(f n y - g y) < e)
+                                        sequentially)
+        ==> g holomorphic_on s`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[HOLOMORPHIC_ON_OPEN] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`sequentially`; `f:num->complex->complex`;
+                 `g:complex->complex`; `z:complex`; `r:real`]
+                HOLOMORPHIC_UNIFORM_LIMIT) THEN
+  ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN ANTS_TAC THENL
+   [MATCH_MP_TAC ALWAYS_EVENTUALLY THEN
+    ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON; HOLOMORPHIC_ON_SUBSET;
+                  BALL_SUBSET_CBALL];
+    SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL] THEN
+    ASM_MESON_TAC[CENTRE_IN_BALL]]);;
+
+let HAS_COMPLEX_DERIVATIVE_UNIFORM_SEQUENCE = prove
+ (`!f f' g s.
+        open s /\
+        (!n x. x IN s ==> ((f n) has_complex_derivative f' n x) (at x)) /\
+        (!x. x IN s
+             ==> ?d. &0 < d /\ cball(x,d) SUBSET s /\
+                     !e. &0 < e
+                         ==> eventually (\n. !y. y IN cball(x,d)
+                                                 ==> norm(f n y - g y) < e)
+                                        sequentially)
+        ==> ?g'. !x. x IN s ==> (g has_complex_derivative g'(x)) (at x) /\
+                                ((\n. f' n x) --> g'(x)) sequentially`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM SKOLEM_THM; RIGHT_EXISTS_IMP_THM] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`sequentially`; `f:num->complex->complex`;
+                 `f':num->complex->complex`;
+                 `g:complex->complex`; `z:complex`; `r:real`]
+                HAS_COMPLEX_DERIVATIVE_UNIFORM_LIMIT) THEN
+  ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN ANTS_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[CENTRE_IN_BALL]] THEN
+  MATCH_MP_TAC ALWAYS_EVENTUALLY THEN X_GEN_TAC `n:num` THEN
+  REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN
+    ASM_MESON_TAC[HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT; SUBSET];
+    ASM_MESON_TAC[BALL_SUBSET_CBALL; SUBSET]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A one-stop shop for an analytic function defined by a series.             *)
+(* ------------------------------------------------------------------------- *)
+
+let SERIES_AND_DERIVATIVE_COMPARISON = prove
+ (`!f f' s k h.
+     open s /\
+     (!n x. n IN k /\ x IN s ==> (f n has_complex_derivative f' n x) (at x)) /\
+     (?l. (lift o h sums l) k) /\
+     (?N. !n x. N <= n /\ n IN k /\ x IN s ==> norm(f n x) <= h n)
+          ==> ?g g'. !x. x IN s
+                         ==> ((\n. f n x) sums g x) k /\
+                             ((\n. f' n x) sums g' x) k /\
+                             (g has_complex_derivative g' x) (at x)`,
+  REPEAT GEN_TAC THEN
+  REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SERIES_COMPARISON_UNIFORM) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:complex->complex` THEN
+  REWRITE_TAC[] THEN DISCH_TAC THEN
+  REWRITE_TAC[TAUT `a ==> b /\ c /\ d <=> (a ==> b) /\ (a ==> d /\ c)`] THEN
+  REWRITE_TAC[FORALL_AND_THM; RIGHT_EXISTS_AND_THM] THEN CONJ_TAC THENL
+   [REWRITE_TAC[sums; LIM_SEQUENTIALLY] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[sums] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_UNIFORM_SEQUENCE THEN
+  EXISTS_TAC `\n x. vsum
+    (k INTER (0..n)) (\n. (f:num->complex->complex) n x)` THEN
+  ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_VSUM; FINITE_INTER_NUMSEG; IN_INTER] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[GSYM dist] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+  ASM_MESON_TAC[SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A version where we only have local uniform/comparative convergence.       *)
+(* ------------------------------------------------------------------------- *)
+
+let SERIES_AND_DERIVATIVE_COMPARISON_LOCAL = prove
+ (`!f f' s k.
+     open s /\
+     (!n x. n IN k /\ x IN s ==> (f n has_complex_derivative f' n x) (at x)) /\
+     (!x. x IN s
+          ==> ?d h N. &0 < d /\ (?l. (lift o h sums l) k) /\
+                      !n y. N <= n /\ n IN k /\ y IN ball(x,d)
+                               ==> norm(f n y) <= h n)
+     ==> ?g g'. !x. x IN s
+                    ==> ((\n. f n x) sums g x) k /\
+                        ((\n. f' n x) sums g' x) k /\
+                        (g has_complex_derivative g' x) (at x)`,
+  REPEAT STRIP_TAC THEN
+  EXISTS_TAC `\x. infsum k (\n. (f:num->complex->complex) n x)` THEN
+  REWRITE_TAC[GSYM SKOLEM_THM; RIGHT_EXISTS_IMP_THM] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`d:real`; `h:num->real`; `N:num`] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`f:num->complex->complex`; `f':num->complex->complex`;
+                 `ball(z:complex,d) INTER s`; `k:num->bool`; `h:num->real`]
+                SERIES_AND_DERIVATIVE_COMPARISON) THEN
+  ASM_SIMP_TAC[OPEN_INTER; OPEN_BALL; IN_INTER] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` MP_TAC) THEN
+  ONCE_REWRITE_TAC[TAUT `a ==> b /\ c <=> (a ==> b) /\ (a ==> c)`] THEN
+  REWRITE_TAC[FORALL_AND_THM; RIGHT_EXISTS_AND_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[GSYM SKOLEM_THM; RIGHT_AND_EXISTS_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN ASM_SIMP_TAC[CENTRE_IN_BALL] THEN
+  X_GEN_TAC `g':complex` THEN REPEAT STRIP_TAC THENL
+   [ASM_MESON_TAC[SUMS_INFSUM; CENTRE_IN_BALL; summable]; ALL_TAC] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_AT THEN
+  EXISTS_TAC `g:complex->complex` THEN
+  MP_TAC(ISPEC `ball(z:complex,d) INTER s` OPEN_CONTAINS_BALL) THEN
+  ASM_SIMP_TAC[OPEN_INTER; OPEN_BALL] THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[IN_INTER; CENTRE_IN_BALL] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  REWRITE_TAC[SUBSET; IN_BALL; IN_INTER] THEN
+  ASM_MESON_TAC[INFSUM_UNIQUE; SUBSET; IN_BALL; DIST_SYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Sometimes convenient to compare with a complex series of +ve reals.       *)
+(* ------------------------------------------------------------------------- *)
+
+let SERIES_AND_DERIVATIVE_COMPARISON_COMPLEX = prove
+ (`!f f' s k.
+     open s /\
+     (!n x. n IN k /\ x IN s ==> (f n has_complex_derivative f' n x) (at x)) /\
+     (!x. x IN s
+          ==> ?d h N. &0 < d /\ summable k h /\
+                      (!n. n IN k ==> real(h n) /\ &0 <= Re(h n)) /\
+                      (!n y. N <= n /\ n IN k /\ y IN ball(x,d)
+                             ==> norm(f n y) <= norm(h n)))
+     ==> ?g g'. !x. x IN s
+                    ==> ((\n. f n x) sums g x) k /\
+                        ((\n. f' n x) sums g' x) k /\
+                        (g has_complex_derivative g' x) (at x)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SERIES_AND_DERIVATIVE_COMPARISON_LOCAL THEN
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `z:complex` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `d:real` THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:num->complex` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\n. norm((h:num->complex) n)` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [summable]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `l:complex` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `lift(Re l)` THEN MATCH_MP_TAC SUMS_EQ THEN
+  EXISTS_TAC `\i:num. lift(Re(h i))` THEN
+  ASM_SIMP_TAC[REAL_NORM_POS; o_DEF] THEN
+  REWRITE_TAC[RE_DEF] THEN MATCH_MP_TAC SERIES_COMPONENT THEN
+  ASM_REWRITE_TAC[DIMINDEX_2; ARITH]);;
+
+let SERIES_DIFFERENTIABLE_COMPARISON_COMPLEX = prove
+ (`!f s k.
+     open s /\
+     (!n x. n IN k /\ x IN s ==> (f n) complex_differentiable (at x)) /\
+     (!x. x IN s
+          ==> ?d h N. &0 < d /\ summable k h /\
+                      (!n. n IN k ==> real(h n) /\ &0 <= Re(h n)) /\
+                      (!n y. N <= n /\ n IN k /\ y IN ball(x,d)
+                             ==> norm(f n y) <= norm(h n)))
+     ==> ?g. !x. x IN s
+                 ==> ((\n. f n x) sums g x) k /\
+                      g complex_differentiable (at x)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[complex_differentiable; RIGHT_AND_EXISTS_THM] THEN
+  GEN_REWRITE_TAC (PAT_CONV `\x. a /\ x /\ b ==> x` o ONCE_DEPTH_CONV)
+   [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM; LEFT_AND_EXISTS_THM] THEN
+  DISCH_THEN(CHOOSE_THEN (MP_TAC o MATCH_MP
+     SERIES_AND_DERIVATIVE_COMPARISON_COMPLEX)) THEN
+  MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In particular, a power series is analytic inside circle of convergence.   *)
+(* ------------------------------------------------------------------------- *)
+
+let POWER_SERIES_AND_DERIVATIVE_0 = prove
+ (`!k a r. summable k (\n. a(n) * Cx(r) pow n)
+           ==> ?g g'.
+                  !z. norm(z) < r
+                      ==> ((\n. a(n) * z pow n) sums g(z)) k /\
+                          ((\n. Cx(&n) * a(n) * z pow (n - 1)) sums g'(z)) k /\
+                          (g has_complex_derivative g' z) (at z)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `&0 < r` THEN
+  ASM_SIMP_TAC[NORM_ARITH `~(&0 < r) ==> ~(norm z < r)`] THEN
+  SUBGOAL_THEN `!z. norm(z) < r <=> z IN ball(Cx(&0),r)`
+   (fun th -> REWRITE_TAC[th])
+  THENL
+   [REWRITE_TAC[IN_BALL; dist; COMPLEX_SUB_LZERO; NORM_NEG]; ALL_TAC] THEN
+  MATCH_MP_TAC SERIES_AND_DERIVATIVE_COMPARISON_COMPLEX THEN
+  REWRITE_TAC[OPEN_BALL; IN_BALL; dist; COMPLEX_SUB_LZERO; NORM_NEG] THEN
+  CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN COMPLEX_DIFF_TAC THEN CONV_TAC COMPLEX_RING;
+    ALL_TAC] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  MAP_EVERY EXISTS_TAC
+   [`(r - norm(z:complex)) / &2`;
+    `\n. Cx(norm(a(n):complex) * ((r + norm(z:complex)) / &2) pow n)`;
+    `0`] THEN
+  ASM_REWRITE_TAC[REAL_SUB_LT; REAL_HALF; REAL_CX; RE_CX] THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[CX_MUL; CX_POW] THEN
+    MATCH_MP_TAC POWER_SERIES_CONV_IMP_ABSCONV_WEAK THEN
+    EXISTS_TAC `Cx r` THEN ASM_REWRITE_TAC[] THEN REWRITE_TAC[COMPLEX_NORM_CX];
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_MUL THEN
+    REWRITE_TAC[NORM_POS_LE] THEN MATCH_MP_TAC REAL_POW_LE;
+    REPEAT STRIP_TAC THEN REWRITE_TAC[COMPLEX_NORM_CX; COMPLEX_NORM_MUL] THEN
+    REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_NORM] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+    REWRITE_TAC[COMPLEX_NORM_POW; REAL_ABS_POW] THEN
+    MATCH_MP_TAC REAL_POW_LE2] THEN
+  ASM_NORM_ARITH_TAC);;
+
+let POWER_SERIES_AND_DERIVATIVE = prove
+ (`!k a r w.
+        summable k (\n. a(n) * Cx(r) pow n)
+        ==> ?g g'.
+             !z. z IN ball(w,r)
+                 ==> ((\n. a(n) * (z - w) pow n) sums g(z)) k /\
+                     ((\n. Cx(&n) * a(n) * (z - w) pow (n - 1)) sums g'(z)) k /\
+                     (g has_complex_derivative g' z) (at z)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP POWER_SERIES_AND_DERIVATIVE_0) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`g:complex->complex`; `g':complex->complex`] THEN
+  DISCH_TAC THEN
+  EXISTS_TAC `(\z. g(z - w)):complex->complex` THEN
+  EXISTS_TAC `(\z. g'(z - w)):complex->complex` THEN
+  REWRITE_TAC[IN_BALL; dist] THEN X_GEN_TAC `z:complex` THEN
+  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `z - w:complex`) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[NORM_SUB]; ALL_TAC] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+  GEN_REWRITE_TAC (RATOR_CONV o RAND_CONV) [GSYM COMPLEX_MUL_RID] THEN
+  MATCH_MP_TAC COMPLEX_DIFF_CHAIN_AT THEN ASM_REWRITE_TAC[] THEN
+  COMPLEX_DIFF_TAC THEN REWRITE_TAC[COMPLEX_SUB_RZERO]);;
+
+let POWER_SERIES_HOLOMORPHIC = prove
+ (`!a k f z r. (!w. w IN ball(z,r) ==> ((\n. a(n) * (w - z) pow n) sums f w) k)
+               ==> f holomorphic_on ball(z,r)`,
+  REPEAT STRIP_TAC THEN SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL] THEN
+  X_GEN_TAC `w:complex` THEN REWRITE_TAC[IN_BALL; dist] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`k:num->bool`; `a:num->complex`;
+                 `(norm(z - w:complex) + r) / &2`; `z:complex`]
+                POWER_SERIES_AND_DERIVATIVE) THEN
+  ANTS_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o SPEC `z + Cx((norm(z - w) + r) / &2)`) THEN
+    REWRITE_TAC[IN_BALL; dist; COMPLEX_RING `(z + w) - z:complex = w`;
+                NORM_ARITH `norm(z - (z + w)) = norm w`; summable] THEN
+    ANTS_TAC THENL [REWRITE_TAC[COMPLEX_NORM_CX]; MESON_TAC[]] THEN
+    POP_ASSUM MP_TAC THEN NORM_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `g':complex->complex` (LABEL_TAC "*")) THEN
+  EXISTS_TAC `(g':complex->complex) w` THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_AT THEN
+  MAP_EVERY EXISTS_TAC
+   [`g:complex->complex`; `(r - norm(z - w:complex)) / &2`] THEN
+  REPEAT CONJ_TAC THENL
+   [UNDISCH_TAC `norm(z - w:complex) < r` THEN NORM_ARITH_TAC;
+    ALL_TAC;
+    REMOVE_THEN "*" (MP_TAC o SPEC `w:complex`) THEN ANTS_TAC THENL
+     [ALL_TAC; SIMP_TAC[]] THEN REWRITE_TAC[IN_BALL] THEN
+    UNDISCH_TAC `norm(z - w:complex) < r` THEN NORM_ARITH_TAC] THEN
+  X_GEN_TAC `u:complex` THEN REWRITE_TAC[dist] THEN DISCH_TAC THEN
+  MATCH_MP_TAC SERIES_UNIQUE THEN
+  EXISTS_TAC `(\n. a(n) * (u - z) pow n):num->complex` THEN
+  EXISTS_TAC `k:num->bool` THEN CONJ_TAC THENL
+   [REMOVE_THEN "*" (MP_TAC o SPEC `u:complex`) THEN
+    ANTS_TAC THENL [ALL_TAC; SIMP_TAC[]];
+    FIRST_X_ASSUM MATCH_MP_TAC] THEN
+  REWRITE_TAC[IN_BALL] THEN ASM_NORM_ARITH_TAC);;
+
+let HOLOMORPHIC_IFF_POWER_SERIES = prove
+ (`!f z r. f holomorphic_on ball(z,r) <=>
+             !w. w IN ball(z,r)
+                 ==> ((\n. higher_complex_derivative n f z / Cx(&(FACT n)) *
+                       (w - z) pow n) sums
+                      f w)
+                     (from 0)`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [ASM_MESON_TAC[HOLOMORPHIC_POWER_SERIES]; ALL_TAC] THEN
+  MATCH_MP_TAC POWER_SERIES_HOLOMORPHIC THEN
+  MAP_EVERY EXISTS_TAC
+   [`\n. higher_complex_derivative n f z / Cx(&(FACT n))`;
+    `from 0`] THEN
+  ASM_REWRITE_TAC[]);;
+
+let POWER_SERIES_ANALYTIC = prove
+ (`!a k f z r. (!w. w IN ball(z,r) ==> ((\n. a(n) * (w - z) pow n) sums f w) k)
+               ==> f analytic_on ball(z,r)`,
+  SIMP_TAC[ANALYTIC_ON_OPEN; OPEN_BALL] THEN
+  REWRITE_TAC[POWER_SERIES_HOLOMORPHIC]);;
+
+let ANALYTIC_IFF_POWER_SERIES = prove
+ (`!f z r. f analytic_on ball(z,r) <=>
+             !w. w IN ball(z,r)
+                 ==> ((\n. higher_complex_derivative n f z / Cx(&(FACT n)) *
+                       (w - z) pow n) sums
+                      f w)
+                     (from 0)`,
+  SIMP_TAC[ANALYTIC_ON_OPEN; OPEN_BALL] THEN
+  REWRITE_TAC[HOLOMORPHIC_IFF_POWER_SERIES]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Equality between holomorphic functions, on open ball then connected set.  *)
+(* ------------------------------------------------------------------------- *)
+
+let HOLOMORPHIC_FUN_EQ_ON_BALL = prove
+ (`!f g z r w.
+     f holomorphic_on ball(z,r) /\ g holomorphic_on ball(z,r) /\
+     w IN ball(z,r) /\
+     (!n. higher_complex_derivative n f z = higher_complex_derivative n g z)
+     ==> f w = g w`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SERIES_UNIQUE THEN
+  EXISTS_TAC `(\n. higher_complex_derivative n f z /
+                   Cx (&(FACT n)) * (w - z) pow n)` THEN
+  EXISTS_TAC `(from 0)` THEN CONJ_TAC THENL [ALL_TAC; ASM_REWRITE_TAC []] THEN
+  ASM_MESON_TAC [HOLOMORPHIC_POWER_SERIES]);;
+
+let HOLOMORPHIC_FUN_EQ_0_ON_BALL = prove
+ (`!f z r w.
+     w IN ball(z,r) /\ f holomorphic_on ball(z,r) /\
+     (!n. higher_complex_derivative n f z = Cx(&0))
+     ==> f w = Cx(&0)`,
+  REPEAT STRIP_TAC THEN
+  SUBST1_TAC (GSYM (BETA_CONV `(\z:complex. Cx(&0)) w`)) THEN
+  MATCH_MP_TAC HOLOMORPHIC_FUN_EQ_ON_BALL THEN
+  REWRITE_TAC [HOLOMORPHIC_ON_CONST; HIGHER_COMPLEX_DERIVATIVE_CONST] THEN
+  ASM_MESON_TAC []);;
+
+let HOLOMORPHIC_FUN_EQ_0_ON_CONNECTED = prove
+ (`!f s z.
+        open s /\ connected s /\ f holomorphic_on s /\
+        z IN s /\ (!n. higher_complex_derivative n f z = Cx(&0))
+        ==> !w. w IN s ==> f w = Cx(&0)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[CONNECTED_CLOPEN] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC
+   `{w | w IN s /\ !n. higher_complex_derivative n f w = Cx(&0)}`) THEN
+  ANTS_TAC THENL [ALL_TAC; ASM SET_TAC[higher_complex_derivative]] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC OPEN_SUBSET THEN CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+    UNDISCH_TAC `open(s:complex->bool)` THEN
+    REWRITE_TAC[OPEN_CONTAINS_BALL; IN_ELIM_THM] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `w:complex` THEN
+    DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+    X_GEN_TAC `u:complex` THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC HOLOMORPHIC_FUN_EQ_0_ON_BALL THEN
+    MAP_EVERY EXISTS_TAC [`w:complex`; `e:real`] THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE THEN
+      ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET; OPEN_BALL; SUBSET];
+      ASM_REWRITE_TAC[HIGHER_COMPLEX_DERIVATIVE_HIGHER_COMPLEX_DERIVATIVE]];
+    SUBGOAL_THEN
+     `closed_in (subtopology euclidean s)
+                (INTERS (IMAGE
+              (\n. {w | w IN s /\ higher_complex_derivative n f w = Cx(&0)})
+                (:num)))`
+    MP_TAC THENL
+     [MATCH_MP_TAC CLOSED_IN_INTERS THEN
+      REWRITE_TAC[IMAGE_EQ_EMPTY; UNIV_NOT_EMPTY] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; IN_UNIV] THEN X_GEN_TAC `n:num` THEN
+      MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE_CONSTANT THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON THEN SIMP_TAC[ETA_AX] THEN
+      MATCH_MP_TAC HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE THEN
+      ASM_REWRITE_TAC[];
+      MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+      SIMP_TAC[INTERS; IN_IMAGE; IN_UNIV; LEFT_IMP_EXISTS_THM; IN_ELIM_THM] THEN
+      ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+      REWRITE_TAC[LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN SET_TAC[]]]);;
+
+let HOLOMORPHIC_FUN_EQ_ON_CONNECTED = prove
+ (`!f g z s w.
+     open s /\ connected s /\ f holomorphic_on s /\ g holomorphic_on s /\
+     w IN s /\ z IN s /\
+     (!n. higher_complex_derivative n f z = higher_complex_derivative n g z)
+     ==> f w = g w`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\z. (f:complex->complex) z - g z`; `s:complex->bool`;
+                 `z:complex`] HOLOMORPHIC_FUN_EQ_0_ON_CONNECTED) THEN
+  ASM_REWRITE_TAC[RIGHT_IMP_FORALL_THM; HOLOMORPHIC_ON_SUB] THEN
+  DISCH_THEN(MP_TAC o SPEC `w:complex`) THEN
+  ASM_REWRITE_TAC[COMPLEX_SUB_0] THEN DISCH_THEN MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_SUB] THEN
+  MP_TAC(ISPECL [`f:complex->complex`; `g:complex->complex`; `s:complex->bool`]
+        HIGHER_COMPLEX_DERIVATIVE_SUB) THEN
+  ASM_SIMP_TAC[COMPLEX_SUB_0]);;
+
+let HOLOMORPHIC_FUN_EQ_CONST_ON_CONNECTED = prove
+ (`!f s z.
+        open s /\
+        connected s /\
+        f holomorphic_on s /\
+        z IN s /\
+        (!n. 0 < n ==> higher_complex_derivative n f z = Cx (&0))
+        ==> !w. w IN s ==> f w = f z`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`\w. (f:complex->complex) w - f z`; `s:complex->bool`; `z:complex`]
+   HOLOMORPHIC_FUN_EQ_0_ON_CONNECTED) THEN
+  ASM_REWRITE_TAC[COMPLEX_SUB_0; RIGHT_IMP_FORALL_THM; IMP_IMP] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_CONST] THEN
+  X_GEN_TAC `n:num` THEN ASM_CASES_TAC `n = 0` THEN
+  ASM_REWRITE_TAC[higher_complex_derivative; COMPLEX_SUB_REFL] THEN
+  MP_TAC(ISPECL
+   [`f:complex->complex`; `(\w. f(z:complex)):complex->complex`;
+    `s:complex->bool`; `n:num`; `z:complex`]
+   HIGHER_COMPLEX_DERIVATIVE_SUB) THEN
+  ASM_REWRITE_TAC[HOLOMORPHIC_ON_CONST] THEN DISCH_THEN SUBST1_TAC THEN
+  ASM_SIMP_TAC[LE_1; HIGHER_COMPLEX_DERIVATIVE_CONST; COMPLEX_SUB_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some basic lemmas about poles/singularities.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let POLE_LEMMA = prove
+ (`!f s a.
+        f holomorphic_on s /\ a IN interior(s)
+        ==> (\z. if z = a then complex_derivative f a
+                 else (f(z) - f(a)) / (z - a)) holomorphic_on s`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN `(a:complex) IN s` ASSUME_TAC THENL
+   [ASM_MESON_TAC[INTERIOR_SUBSET; SUBSET]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!z. z IN s /\ ~(z = a)
+        ==> (\z. if z = a then complex_derivative f a
+                 else (f(z) - f(a)) / (z - a))
+            complex_differentiable (at z within s)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_TRANSFORM_WITHIN THEN
+    EXISTS_TAC `\z:complex. (f(z) - f(a)) / (z - a)` THEN
+    EXISTS_TAC `dist(a:complex,z)` THEN ASM_SIMP_TAC[DIST_POS_LT] THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `w:complex` THEN COND_CASES_TAC THEN
+      ASM_REWRITE_TAC[REAL_LT_REFL] THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `w:complex`) THEN ASM_REWRITE_TAC[] THEN
+      REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC COMPLEX_FIELD;
+      MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_DIV_WITHIN THEN
+      ASM_REWRITE_TAC[COMPLEX_SUB_0] THEN CONJ_TAC THEN
+      MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_SUB THEN
+      REWRITE_TAC[COMPLEX_DIFFERENTIABLE_CONST; COMPLEX_DIFFERENTIABLE_ID] THEN
+      ASM_MESON_TAC[holomorphic_on; complex_differentiable]];
+    ALL_TAC] THEN
+  REWRITE_TAC[holomorphic_on; GSYM complex_differentiable] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `z:complex = a` THENL [ALL_TAC; ASM_SIMP_TAC[]] THEN
+  FIRST_X_ASSUM SUBST_ALL_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERIOR]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_AT_WITHIN THEN
+  SUBGOAL_THEN
+   `(\z. if z = a then complex_derivative f a else (f z - f a) / (z - a))
+    holomorphic_on ball(a,e)`
+  MP_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL; GSYM complex_differentiable;
+                 CENTRE_IN_BALL; COMPLEX_DIFFERENTIABLE_AT_WITHIN]] THEN
+  MATCH_MP_TAC NO_ISOLATED_SINGULARITY THEN
+  EXISTS_TAC `{a:complex}` THEN SIMP_TAC[OPEN_BALL; FINITE_RULES] THEN
+  MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+    EXISTS_TAC `s DELETE (a:complex)` THEN
+    ASM_SIMP_TAC[SET_RULE `b SUBSET s ==> b DIFF {a} SUBSET s DELETE a`] THEN
+    ASM_SIMP_TAC[holomorphic_on; GSYM complex_differentiable; IN_DELETE] THEN
+    REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_WITHIN_SUBSET THEN
+    EXISTS_TAC `s:complex->bool` THEN ASM_SIMP_TAC[] THEN SET_TAC[];
+    ALL_TAC] THEN
+  SIMP_TAC[HOLOMORPHIC_ON_OPEN; CONTINUOUS_ON_EQ_CONTINUOUS_AT;
+           OPEN_DIFF; FINITE_IMP_CLOSED; OPEN_BALL; FINITE_INSERT;
+           FINITE_RULES; GSYM complex_differentiable] THEN
+  REWRITE_TAC[IN_DIFF; IN_BALL; IN_SING] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `w:complex` THEN
+  ASM_CASES_TAC `w:complex = a` THENL
+   [ALL_TAC; ASM_SIMP_TAC[COMPLEX_DIFFERENTIABLE_IMP_CONTINUOUS_AT]] THEN
+  FIRST_X_ASSUM SUBST_ALL_TAC THEN REWRITE_TAC[] THEN
+  SUBGOAL_THEN `f holomorphic_on ball(a,e)` MP_TAC THENL
+   [ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET]; ALL_TAC] THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL] THEN
+  REWRITE_TAC[GSYM complex_differentiable; IN_BALL] THEN
+  DISCH_THEN(MP_TAC o SPEC `a:complex`) THEN
+  ASM_REWRITE_TAC[GSYM HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+  REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_AT; CONTINUOUS_AT] THEN
+  MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+              LIM_TRANSFORM_AT) THEN
+  EXISTS_TAC `&1` THEN REWRITE_TAC[GSYM DIST_NZ; REAL_LT_01] THEN
+  X_GEN_TAC `u:complex` THEN STRIP_TAC THEN ASM_REWRITE_TAC[]);;
+
+let POLE_LEMMA_OPEN = prove
+ (`!f s a.
+        open s /\ f holomorphic_on s
+        ==> (\z. if z = a
+                 then complex_derivative f a
+                 else (f z - f a) / (z - a)) holomorphic_on s`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `(a:complex) IN s` THENL
+   [MATCH_MP_TAC POLE_LEMMA THEN ASM_SIMP_TAC[INTERIOR_OPEN];
+    ALL_TAC] THEN
+  REWRITE_TAC[holomorphic_on; GSYM complex_differentiable] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_TRANSFORM_WITHIN THEN
+  MAP_EVERY EXISTS_TAC [`\z:complex. (f(z) - f(a)) / (z - a)`; `&1`] THEN
+  ASM_REWRITE_TAC[REAL_LT_01] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_DIV_WITHIN THEN
+  ASM_REWRITE_TAC[COMPLEX_SUB_0; CONJ_ASSOC] THEN
+  CONJ_TAC THENL [CONJ_TAC; ASM_MESON_TAC[]] THEN
+  MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_SUB THEN
+  REWRITE_TAC[COMPLEX_DIFFERENTIABLE_CONST; COMPLEX_DIFFERENTIABLE_ID] THEN
+  ASM_MESON_TAC[holomorphic_on; complex_differentiable]);;
+
+let POLE_THEOREM = prove
+ (`!f g s a.
+        g holomorphic_on s /\ a IN interior(s) /\
+        (!z. z IN s /\ ~(z = a) ==> g(z) = (z - a) * f(z))
+        ==> (\z. if z = a then complex_derivative g a
+                 else f(z) - g(a) / (z - a)) holomorphic_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP POLE_LEMMA) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HOLOMORPHIC_TRANSFORM) THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex` o last o CONJUNCTS) THEN
+  ASM_REWRITE_TAC[] THEN REPEAT(POP_ASSUM MP_TAC) THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let POLE_THEOREM_OPEN = prove
+ (`!f g s a.
+        open s /\ g holomorphic_on s /\
+        (!z. z IN s /\ ~(z = a) ==> g(z) = (z - a) * f(z))
+        ==> (\z. if z = a then complex_derivative g a
+                 else f(z) - g(a) / (z - a)) holomorphic_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o SPEC `a:complex` o MATCH_MP POLE_LEMMA_OPEN) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HOLOMORPHIC_TRANSFORM) THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex` o last o CONJUNCTS) THEN
+  ASM_REWRITE_TAC[] THEN REPEAT(POP_ASSUM MP_TAC) THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let POLE_THEOREM_0 = prove
+ (`!f g s a.
+        g holomorphic_on s /\ a IN interior(s) /\
+        (!z. z IN s /\ ~(z = a) ==> g(z) = (z - a) * f(z)) /\
+        f a = complex_derivative g a /\ g(a) = Cx(&0)
+        ==> f holomorphic_on s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `(\z. if z = a then complex_derivative g a
+         else f(z) - g(a) / (z - a)) holomorphic_on s`
+  MP_TAC THENL [ASM_SIMP_TAC[POLE_THEOREM]; ALL_TAC] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HOLOMORPHIC_TRANSFORM) THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[complex_div] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let POLE_THEOREM_OPEN_0 = prove
+ (`!f g s a.
+        open s /\ g holomorphic_on s /\
+        (!z. z IN s /\ ~(z = a) ==> g(z) = (z - a) * f(z)) /\
+        f a = complex_derivative g a /\ g(a) = Cx(&0)
+        ==> f holomorphic_on s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `(\z. if z = a then complex_derivative g a
+         else f(z) - g(a) / (z - a)) holomorphic_on s`
+  MP_TAC THENL [ASM_SIMP_TAC[POLE_THEOREM_OPEN]; ALL_TAC] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HOLOMORPHIC_TRANSFORM) THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[complex_div] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let POLE_THEOREM_ANALYTIC = prove
+ (`!f g s a.
+        g analytic_on s /\
+        (!z. z IN s
+             ==> ?d. &0 < d /\
+                     !w. w IN ball(z,d) /\ ~(w = a) ==> g(w) = (w - a) * f(w))
+        ==> (\z. if z = a then complex_derivative g a
+                 else f(z) - g(a) / (z - a)) analytic_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[analytic_on] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "A") (LABEL_TAC "B")) THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  REMOVE_THEN "A" (MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_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
+  MATCH_MP_TAC POLE_THEOREM_OPEN THEN
+  ASM_SIMP_TAC[BALL_MIN_INTER; OPEN_BALL; IN_INTER] THEN
+  ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET; INTER_SUBSET]);;
+
+let POLE_THEOREM_ANALYTIC_0 = prove
+ (`!f g s a.
+        g analytic_on s /\
+        (!z. z IN s
+             ==> ?d. &0 < d /\
+                     !w. w IN ball(z,d) /\ ~(w = a)
+                         ==> g(w) = (w - a) * f(w)) /\
+        f a = complex_derivative g a /\ g(a) = Cx(&0)
+        ==> f analytic_on s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `(\z. if z = a then complex_derivative g a
+         else f(z) - g(a) / (z - a)) analytic_on s`
+  MP_TAC THENL [ASM_SIMP_TAC[POLE_THEOREM_ANALYTIC]; ALL_TAC] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[complex_div] THEN CONV_TAC COMPLEX_RING);;
+
+let POLE_THEOREM_ANALYTIC_OPEN_SUPERSET = prove
+ (`!f g s a t.
+        s SUBSET t /\ open t /\ g analytic_on s /\
+        (!z. z IN t /\ ~(z = a) ==> g(z) = (z - a) * f(z))
+        ==> (\z. if z = a then complex_derivative g a
+                 else f(z) - g(a) / (z - a)) analytic_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC POLE_THEOREM_ANALYTIC THEN
+  ASM_MESON_TAC[OPEN_CONTAINS_BALL; SUBSET]);;
+
+let POLE_THEOREM_ANALYTIC_OPEN_SUPERSET_0 = prove
+ (`!f g s a t.
+        s SUBSET t /\ open t /\ g analytic_on s /\
+        (!z. z IN t /\ ~(z = a) ==> g(z) = (z - a) * f(z)) /\
+        f a = complex_derivative g a /\ g(a) = Cx(&0)
+        ==> f analytic_on s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `(\z. if z = a then complex_derivative g a
+         else f(z) - g(a) / (z - a)) analytic_on s`
+  MP_TAC THENL
+   [MATCH_MP_TAC POLE_THEOREM_ANALYTIC_OPEN_SUPERSET THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[complex_div] THEN CONV_TAC COMPLEX_RING);;
+
+let HOLOMORPHIC_ON_EXTEND_LIM,HOLOMORPHIC_ON_EXTEND_BOUNDED =
+ (CONJ_PAIR o prove)
+ (`(!f a s.
+      f holomorphic_on (s DELETE a) /\ a IN interior s
+      ==> ((?g. g holomorphic_on s /\ (!z. z IN s DELETE a ==> g z = f z)) <=>
+           ((\z. (z - a) * f(z)) --> Cx(&0)) (at a))) /\
+   (!f a s.
+      f holomorphic_on (s DELETE a) /\ a IN interior s
+      ==> ((?g. g holomorphic_on s /\ (!z. z IN s DELETE a ==> g z = f z)) <=>
+           (?B. eventually (\z. norm(f z) <= B) (at a))))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN
+  REWRITE_TAC[TAUT `(p ==> q) /\ (p ==> r) <=> (p ==> q /\ r)`] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC(TAUT
+   `(p ==> r) /\ (r ==> q) /\ (q ==> p) ==> (p <=> q) /\ (p <=> r)`) THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[IN_DELETE] THEN DISCH_THEN(X_CHOOSE_THEN `g:complex->complex`
+     (CONJUNCTS_THEN2
+       (MP_TAC o MATCH_MP HOLOMORPHIC_ON_IMP_CONTINUOUS_ON) ASSUME_TAC)) THEN
+    DISCH_THEN(MP_TAC o SPEC `interior s:complex->bool` o
+     MATCH_MP(REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_SUBSET)) THEN
+    REWRITE_TAC[INTERIOR_SUBSET; CONTINUOUS_ON] THEN
+    DISCH_THEN(MP_TAC o SPEC `a:complex`) THEN
+    ASM_SIMP_TAC[LIM_WITHIN_OPEN; OPEN_INTERIOR; tendsto] THEN
+    DISCH_THEN(MP_TAC o SPEC `&1`) THEN REWRITE_TAC[REAL_LT_01] THEN
+    DISCH_THEN(fun th -> EXISTS_TAC `norm((g:complex->complex) a) + &1` THEN
+                         MP_TAC th) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MP) THEN
+    FIRST_ASSUM(fun th ->
+     REWRITE_TAC[GSYM(MATCH_MP EVENTUALLY_WITHIN_INTERIOR th)]) THEN
+    ASM_SIMP_TAC[EVENTUALLY_WITHIN; GSYM DIST_NZ] THEN
+    EXISTS_TAC `&1` THEN CONV_TAC NORM_ARITH;
+    DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+    MATCH_MP_TAC LIM_NULL_COMPLEX_RMUL_BOUNDED THEN
+    SUBST1_TAC(COMPLEX_RING `Cx(&0) = a - a`) THEN
+    SIMP_TAC[LIM_AT_ID; LIM_CONST; LIM_SUB] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+        EVENTUALLY_MONO)) THEN
+    SIMP_TAC[];
+    DISCH_TAC THEN ABBREV_TAC `h = \z. (z - a) pow 2 * f z` THEN
+    SUBGOAL_THEN `(h has_complex_derivative Cx(&0)) (at a)` ASSUME_TAC THENL
+     [EXPAND_TAC "h" THEN REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_AT] THEN
+      MATCH_MP_TAC LIM_TRANSFORM_AT THEN
+      MAP_EVERY EXISTS_TAC [`\z:complex. (z - a) * f z`; `&1`] THEN
+      ASM_SIMP_TAC[REAL_LT_01; GSYM DIST_NZ] THEN CONV_TAC COMPLEX_FIELD;
+      ALL_TAC] THEN
+    SUBGOAL_THEN `h holomorphic_on s` ASSUME_TAC THENL
+     [REWRITE_TAC[holomorphic_on; GSYM complex_differentiable] THEN
+      X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+      ASM_CASES_TAC `z:complex = a` THENL
+       [ASM_MESON_TAC[complex_differentiable; COMPLEX_DIFFERENTIABLE_AT_WITHIN];
+        ALL_TAC] THEN
+      EXPAND_TAC "h" THEN MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_MUL_WITHIN THEN
+      CONJ_TAC THENL [COMPLEX_DIFFERENTIABLE_TAC; ALL_TAC] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [holomorphic_on]) THEN
+      DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+      ASM_REWRITE_TAC[IN_DELETE; complex_differentiable] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:complex` THEN
+      REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN] THEN
+      MATCH_MP_TAC EQ_IMP THEN MATCH_MP_TAC LIM_TRANSFORM_WITHIN_SET THEN
+      REWRITE_TAC[EVENTUALLY_AT] THEN EXISTS_TAC `dist(a:complex,z)` THEN
+      ASM_REWRITE_TAC[IN_DELETE; NORM_ARITH `&0 < dist(a,b) <=> ~(a = b)`] THEN
+      MESON_TAC[REAL_LT_REFL];
+      MP_TAC(SPECL [`h:complex->complex`; `s:complex->bool`; `a:complex`]
+            POLE_LEMMA) THEN ASM_REWRITE_TAC[] THEN
+      ABBREV_TAC
+       `g = \z. if z = a then complex_derivative h a
+                else (h z - h a) / (z - a)` THEN
+      DISCH_TAC THEN
+      EXISTS_TAC
+       `\z. if z = a then complex_derivative g a
+            else (g z - g a) / (z - a)` THEN
+      ASM_SIMP_TAC[POLE_LEMMA; IN_DELETE] THEN EXPAND_TAC "g" THEN
+      FIRST_ASSUM(fun th ->
+        REWRITE_TAC[MATCH_MP HAS_COMPLEX_DERIVATIVE_DERIVATIVE th]) THEN
+      SIMP_TAC[COMPLEX_SUB_RZERO] THEN
+      EXPAND_TAC "h" THEN SIMP_TAC[] THEN CONV_TAC COMPLEX_FIELD]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* General, homology form of Cauchy's theorem. Proof is based on Dixon's,    *)
+(* as presented in Lang's "Complex Analysis" book.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_INTEGRAL_FORMULA_GLOBAL = prove
+ (`!f s g z.
+        open s /\ f holomorphic_on s /\ z IN s /\
+        valid_path g /\ pathfinish g = pathstart g /\
+        path_image g SUBSET s DELETE z /\
+        (!w. ~(w IN s) ==> winding_number(g,w) = Cx(&0))
+        ==> ((\w. f(w) / (w - z)) has_path_integral
+             (Cx(&2) * Cx(pi) * ii * winding_number(g,z) * f(z))) g`,
+  MATCH_MP_TAC(MESON[]
+   `((!f s g. vector_polynomial_function g ==> P f s g) ==> !f s g. P f s g) /\
+    (!f s g. vector_polynomial_function g ==> P f s g)
+    ==> !f s g. P f s g`) THEN
+  CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`s DELETE (z:complex)`; `g:real^1->complex`]
+      PATH_INTEGRAL_NEARBY_ENDS) THEN
+    ASM_SIMP_TAC[VALID_PATH_IMP_PATH; OPEN_DELETE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`g:real^1->complex`; `d:real`]
+      PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION) THEN
+    ASM_SIMP_TAC[VALID_PATH_IMP_PATH] THEN
+    DISCH_THEN(X_CHOOSE_THEN `p:real^1->complex` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`g:real^1->complex`; `p:real^1->complex`]) THEN
+    ASM_SIMP_TAC[VECTOR_SUB_REFL; NORM_0;
+                 VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+     [`f:complex->complex`; `s:complex->bool`; `p:real^1->complex`]) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+    SUBGOAL_THEN
+     `winding_number(p,z) = winding_number(g,z) /\
+      !w. ~(w IN s) ==> winding_number(p,w) = winding_number(g,w)`
+     (fun th -> SIMP_TAC[th])
+    THENL
+     [FIRST_X_ASSUM(K ALL_TAC o SPEC `z:complex`) THEN
+      REPEAT(FIRST_X_ASSUM(STRIP_ASSUME_TAC o MATCH_MP (SET_RULE
+       `g SUBSET s DELETE z
+        ==> ~(z IN g) /\ (!y. ~(y IN s) ==> ~(y IN g))`))) THEN
+      ASM_SIMP_TAC[WINDING_NUMBER_VALID_PATH;
+                   VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN
+      REPEAT STRIP_TAC THEN AP_TERM_TAC THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      REWRITE_TAC[complex_div; COMPLEX_MUL_LID] THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_INV THEN
+      SIMP_TAC[HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_ID; HOLOMORPHIC_ON_CONST;
+               IN_DELETE; COMPLEX_SUB_0] THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN
+    MATCH_MP_TAC(MESON[HAS_PATH_INTEGRAL_INTEGRAL; path_integrable_on;
+                       PATH_INTEGRAL_UNIQUE]
+     `f path_integrable_on g /\ path_integral p f = path_integral g f
+      ==> (f has_path_integral y) p ==> (f has_path_integral y) g`) THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC PATH_INTEGRABLE_HOLOMORPHIC_SIMPLE THEN
+      EXISTS_TAC `s DELETE (z:complex)` THEN ASM_SIMP_TAC[OPEN_DELETE];
+      FIRST_X_ASSUM MATCH_MP_TAC] THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+    SIMP_TAC[HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_ID; HOLOMORPHIC_ON_CONST;
+             IN_DELETE; COMPLEX_SUB_0] THEN
+    ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET; DELETE_SUBSET];
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC
+   [`f:complex->complex`; `u:complex->bool`; `g:real^1->complex`] THEN
+  DISCH_TAC THEN X_GEN_TAC `z:complex` THEN STRIP_TAC THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `g':real^1->complex` STRIP_ASSUME_TAC o
+      MATCH_MP HAS_VECTOR_DERIVATIVE_VECTOR_POLYNOMIAL_FUNCTION) THEN
+  SUBGOAL_THEN
+   `bounded(IMAGE (g':real^1->complex) (interval[vec 0,vec 1]))`
+  MP_TAC THENL
+   [MATCH_MP_TAC COMPACT_IMP_BOUNDED THEN
+    MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+    REWRITE_TAC[COMPACT_INTERVAL] THEN
+    ASM_MESON_TAC[CONTINUOUS_VECTOR_POLYNOMIAL_FUNCTION;
+                  CONTINUOUS_AT_IMP_CONTINUOUS_ON];
+    REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC)] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP VALID_PATH_IMP_PATH) THEN
+  MAP_EVERY ABBREV_TAC
+   [`d = \z w. if w = z then complex_derivative f z
+              else (f(w) - f(z)) / (w - z)`;
+    `v = {w | ~(w IN path_image g) /\ winding_number(g,w) = Cx(&0)}`] THEN
+  SUBGOAL_THEN `open(v:complex->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "v" THEN MATCH_MP_TAC OPEN_WINDING_NUMBER_LEVELSETS THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `u UNION v = (:complex)` ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `!y:complex. y IN u ==> (d y) holomorphic_on u` ASSUME_TAC THENL
+   [X_GEN_TAC `y:complex` THEN STRIP_TAC THEN EXPAND_TAC "d" THEN
+    MATCH_MP_TAC NO_ISOLATED_SINGULARITY THEN EXISTS_TAC `{y:complex}` THEN
+    ASM_REWRITE_TAC[FINITE_SING] THEN CONJ_TAC THENL
+     [ASM_SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT] THEN
+      X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+      ASM_CASES_TAC `w:complex = y` THENL
+       [UNDISCH_THEN `w:complex = y` SUBST_ALL_TAC THEN
+        REWRITE_TAC[CONTINUOUS_AT] THEN
+        MATCH_MP_TAC LIM_TRANSFORM_AWAY_AT THEN
+        EXISTS_TAC `\w:complex. (f w - f y) / (w - y)` THEN SIMP_TAC[] THEN
+        EXISTS_TAC `y + Cx(&1)` THEN
+        CONJ_TAC THENL [CONV_TAC COMPLEX_RING; ALL_TAC] THEN
+        REWRITE_TAC[GSYM HAS_COMPLEX_DERIVATIVE_AT] THEN
+        REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+        ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT];
+        MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_IMP_CONTINUOUS_AT];
+      ASM_SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_DELETE; IN_DELETE;
+        SET_RULE `s DIFF {x} = s DELETE x`; GSYM complex_differentiable] THEN
+      X_GEN_TAC `w:complex` THEN STRIP_TAC] THEN
+     MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_TRANSFORM_AT THEN
+     EXISTS_TAC `\w:complex. (f w - f y) / (w - y)` THEN
+     EXISTS_TAC `dist(w:complex,y)` THEN ASM_SIMP_TAC[DIST_POS_LT] THEN
+     (CONJ_TAC THENL [MESON_TAC[DIST_SYM; REAL_LT_REFL]; ALL_TAC]) THEN
+     MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_DIV_AT THEN
+     ASM_REWRITE_TAC[COMPLEX_SUB_0] THEN CONJ_TAC THEN
+     MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_SUB THEN
+     ASM_SIMP_TAC[ETA_AX; COMPLEX_DIFFERENTIABLE_CONST;
+                  COMPLEX_DIFFERENTIABLE_ID] THEN
+     ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT];
+     ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!y. ~(y IN path_image g)
+        ==> (\x. (f x - f y) / (x - y)) path_integrable_on g`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `y:complex` THEN DISCH_TAC THEN
+    MATCH_MP_TAC PATH_INTEGRABLE_HOLOMORPHIC_SIMPLE THEN
+    EXISTS_TAC `u DELETE (y:complex)` THEN ASM_SIMP_TAC[OPEN_DELETE] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+    SIMP_TAC[IN_DELETE; COMPLEX_SUB_0] THEN
+    CONJ_TAC THEN MATCH_MP_TAC HOLOMORPHIC_ON_SUB THEN
+    ASM_REWRITE_TAC[HOLOMORPHIC_ON_CONST; HOLOMORPHIC_ON_ID] THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+    EXISTS_TAC `u:complex->bool` THEN ASM_REWRITE_TAC[DELETE_SUBSET];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!y:complex. d y path_integrable_on g`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `y:complex` THEN
+    ASM_CASES_TAC `(y:complex) IN path_image g` THENL
+     [MATCH_MP_TAC PATH_INTEGRABLE_HOLOMORPHIC_SIMPLE THEN
+      EXISTS_TAC `u:complex->bool` THEN ASM_SIMP_TAC[] THEN ASM SET_TAC[];
+      MATCH_MP_TAC PATH_INTEGRABLE_EQ THEN
+      EXISTS_TAC `\x:complex. (f x - f y) / (x - y)` THEN
+      ASM_SIMP_TAC[] THEN EXPAND_TAC "d" THEN ASM_MESON_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?h. (!z. z IN u ==> ((d z) has_path_integral h(z)) g) /\
+        (!z. z IN v ==> ((\w. f(w) / (w - z)) has_path_integral h(z)) g)`
+   (CHOOSE_THEN (CONJUNCTS_THEN2 (LABEL_TAC "u") (LABEL_TAC "v")))
+  THENL
+   [EXISTS_TAC `\z. if z IN u then path_integral g (d z)
+                    else path_integral g (\w. f(w) / (w - z))` THEN
+    SIMP_TAC[] THEN CONJ_TAC THEN X_GEN_TAC `w:complex` THEN DISCH_TAC THENL
+     [ASM_MESON_TAC[HAS_PATH_INTEGRAL_INTEGRAL]; ALL_TAC] THEN
+    ASM_CASES_TAC `(w:complex) IN u` THEN ASM_REWRITE_TAC[] THENL
+     [ALL_TAC;
+      MATCH_MP_TAC HAS_PATH_INTEGRAL_INTEGRAL THEN
+      MATCH_MP_TAC PATH_INTEGRABLE_HOLOMORPHIC_SIMPLE THEN
+      EXISTS_TAC `u:complex->bool` THEN ASM_SIMP_TAC[] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+        ASM_SIMP_TAC[COMPLEX_SUB_0; HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_CONST;
+                     HOLOMORPHIC_ON_ID] THEN
+        ASM_MESON_TAC[];
+        ASM SET_TAC[]]] THEN
+    MATCH_MP_TAC HAS_PATH_INTEGRAL_EQ THEN
+    EXISTS_TAC `\x:complex. (f x - f w) / (x - w) + f(w) / (x - w)` THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `x:complex` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+      SIMPLE_COMPLEX_ARITH_TAC;
+      ALL_TAC] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM COMPLEX_ADD_RID] THEN
+    MATCH_MP_TAC HAS_PATH_INTEGRAL_ADD THEN
+    UNDISCH_TAC `(w:complex) IN v` THEN EXPAND_TAC "v" THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN REPEAT STRIP_TAC THENL
+     [MATCH_MP_TAC(MESON[PATH_INTEGRAL_UNIQUE; HAS_PATH_INTEGRAL_INTEGRAL;
+                   path_integrable_on; PATH_INTEGRAL_EQ; PATH_INTEGRABLE_EQ]
+       `g path_integrable_on p /\
+        (!x. x IN path_image p ==> f x = g x)
+        ==> (f has_path_integral path_integral p g) p`) THEN
+      ASM_REWRITE_TAC[] THEN EXPAND_TAC "d" THEN ASM_MESON_TAC[];
+      SUBGOAL_THEN
+       `Cx(&0) = (f w) * Cx(&2) * Cx pi * ii * winding_number(g,w)`
+      SUBST1_TAC THENL [ASM_REWRITE_TAC[COMPLEX_MUL_RZERO]; ALL_TAC] THEN
+      ONCE_REWRITE_TAC[SIMPLE_COMPLEX_ARITH `x / y = x * Cx(&1) / y`] THEN
+      MATCH_MP_TAC HAS_PATH_INTEGRAL_COMPLEX_LMUL THEN
+      MATCH_MP_TAC HAS_PATH_INTEGRAL_WINDING_NUMBER THEN
+      ASM_REWRITE_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!z. (h:complex->complex) z = Cx(&0)` ASSUME_TAC THENL
+   [ALL_TAC;
+    REMOVE_THEN "u" (MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+    EXPAND_TAC "d" THEN REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o SPEC `\w. (f w - f z) / (w - z)` o
+     MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] HAS_PATH_INTEGRAL_EQ)) THEN
+    REWRITE_TAC[] THEN ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    MP_TAC(SPECL [`g:real^1->complex`; `z:complex`]
+      HAS_PATH_INTEGRAL_WINDING_NUMBER) THEN ASM_REWRITE_TAC[] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_COMPLEX_RMUL) THEN
+    DISCH_THEN(MP_TAC o SPEC `(f:complex->complex) z`) THEN
+    REWRITE_TAC[IMP_IMP] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_ADD) THEN
+    REWRITE_TAC[complex_div; COMPLEX_ADD_RID; COMPLEX_RING
+     `(Cx(&1) * i) * fz + (fx - fz) * i = fx * i`] THEN
+    REWRITE_TAC[GSYM COMPLEX_MUL_ASSOC]] THEN
+  UNDISCH_THEN `(z:complex) IN u` (K ALL_TAC) THEN
+  FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP (SET_RULE
+   `p SUBSET u DELETE z ==> p SUBSET u`)) THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ o rev) THEN STRIP_TAC THEN
+  MATCH_MP_TAC LIOUVILLE_WEAK THEN
+  MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+   [SUBGOAL_THEN
+     `?t:complex->bool.
+        compact t /\ path_image g SUBSET interior t /\ t SUBSET u`
+    STRIP_ASSUME_TAC THENL
+     [SUBGOAL_THEN
+       `?dd. &0 < dd /\
+            {y + k | y IN path_image g /\ k IN ball(vec 0,dd)} SUBSET u`
+      STRIP_ASSUME_TAC THENL
+       [ASM_CASES_TAC `u = (:complex)` THENL
+         [EXISTS_TAC `&1` THEN ASM_REWRITE_TAC[REAL_LT_01; SUBSET_UNIV];
+          ALL_TAC] THEN
+        MP_TAC(ISPECL [`path_image g:complex->bool`; `(:complex) DIFF u`]
+          SEPARATE_COMPACT_CLOSED) THEN
+        ASM_SIMP_TAC[COMPACT_PATH_IMAGE; GSYM OPEN_CLOSED] THEN
+        ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+        DISCH_THEN(X_CHOOSE_THEN `dd:real` STRIP_ASSUME_TAC) THEN
+        EXISTS_TAC `dd / &2` THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+        MAP_EVERY X_GEN_TAC [`y:complex`; `k:complex`] THEN
+        MATCH_MP_TAC(TAUT `(a /\ ~c ==> ~b) ==> a /\ b ==> c`) THEN
+        STRIP_TAC THEN
+        FIRST_X_ASSUM(MP_TAC o SPECL [`y:complex`; `y + k:complex`]) THEN
+        ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; IN_BALL] THEN CONV_TAC NORM_ARITH;
+        ALL_TAC] THEN
+      EXISTS_TAC `{y + k:complex |
+                   y IN path_image g /\ k IN cball(vec 0,dd / &2)}` THEN
+      ASM_SIMP_TAC[COMPACT_SUMS; COMPACT_PATH_IMAGE; COMPACT_CBALL] THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[SUBSET; IN_INTERIOR; IN_ELIM_THM] THEN
+        X_GEN_TAC `y:complex` THEN DISCH_TAC THEN
+        EXISTS_TAC `dd / &2` THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+        X_GEN_TAC `x:complex` THEN REWRITE_TAC[IN_BALL] THEN DISCH_TAC THEN
+        MAP_EVERY EXISTS_TAC [`y:complex`; `x - y:complex`] THEN
+        ASM_REWRITE_TAC[IN_CBALL] THEN
+        UNDISCH_TAC `dist(y:complex,x) < dd / &2` THEN CONV_TAC NORM_ARITH;
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `{x + y:real^N | x IN s /\ y IN t} SUBSET u
+          ==> t' SUBSET t ==> {x + y | x IN s /\ y IN t'} SUBSET u`)) THEN
+        REWRITE_TAC[SUBSET; IN_BALL; IN_CBALL] THEN
+        UNDISCH_TAC `&0 < dd` THEN CONV_TAC NORM_ARITH];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`interior t:complex->bool`; `g:real^1->complex`]
+        PATH_INTEGRAL_BOUND_EXISTS) THEN
+    ASM_REWRITE_TAC[OPEN_INTERIOR] THEN
+    DISCH_THEN(X_CHOOSE_THEN `L:real` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `bounded(IMAGE (f:complex->complex) t)` MP_TAC THENL
+     [MATCH_MP_TAC COMPACT_IMP_BOUNDED THEN
+      MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+      ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON; CONTINUOUS_ON_SUBSET];
+      REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE] THEN
+      DISCH_THEN(X_CHOOSE_THEN `D:real` STRIP_ASSUME_TAC)] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_IMP_BOUNDED) THEN
+    REWRITE_TAC[BOUNDED_POS] THEN
+    DISCH_THEN(X_CHOOSE_THEN `C:real` STRIP_ASSUME_TAC) THEN
+    REWRITE_TAC[LIM_AT_INFINITY] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    EXISTS_TAC `(D * L) / (e / &2) + C:real` THEN REWRITE_TAC[real_ge] THEN
+    X_GEN_TAC `y:complex` THEN DISCH_TAC THEN
+    REWRITE_TAC[dist; COMPLEX_SUB_RZERO] THEN
+    SUBGOAL_THEN `h y = path_integral g (\w. f w / (w - y))` SUBST1_TAC THENL
+     [CONV_TAC SYM_CONV THEN MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN EXPAND_TAC "v" THEN
+      REWRITE_TAC[IN_ELIM_THM] THEN CONJ_TAC THENL
+       [DISCH_TAC THEN
+        UNDISCH_TAC `(D * L) / (e / &2) + C <= norm(y:complex)` THEN
+        MATCH_MP_TAC(REAL_ARITH `&0 < d /\ x <= c ==> d + c <= x ==> F`) THEN
+        ASM_SIMP_TAC[REAL_LT_MUL; REAL_LT_DIV; REAL_HALF] THEN
+        ASM_MESON_TAC[INTERIOR_SUBSET; SUBSET];
+        MATCH_MP_TAC WINDING_NUMBER_ZERO_OUTSIDE THEN
+        EXISTS_TAC `cball(Cx(&0),C)` THEN
+        ASM_REWRITE_TAC[CONVEX_CBALL; SUBSET; IN_CBALL; dist;
+                        COMPLEX_SUB_LZERO; NORM_NEG] THEN
+        CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[INTERIOR_SUBSET; SUBSET]] THEN
+        UNDISCH_TAC `(D * L) / (e / &2) + C <= norm(y:complex)` THEN
+        MATCH_MP_TAC(REAL_ARITH `&0 < d ==> d + c <= x ==> ~(x <= c)`) THEN
+        ASM_SIMP_TAC[REAL_LT_MUL; REAL_LT_DIV; REAL_HALF]];
+      ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `L * (e / &2 / L)` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      ASM_SIMP_TAC[REAL_DIV_LMUL; REAL_LT_IMP_NZ; REAL_HALF] THEN
+      ASM_REAL_ARITH_TAC] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET; SUBSET_TRANS; INTERIOR_SUBSET];
+        SIMP_TAC[HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_ID;
+                 HOLOMORPHIC_ON_CONST; COMPLEX_SUB_0]] THEN
+      X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (NORM_ARITH
+       `d + c <= norm y ==> &0 < d /\ norm w <= c ==> ~(w = y)`)) THEN
+      ASM_SIMP_TAC[REAL_LT_MUL; REAL_LT_DIV; REAL_HALF] THEN
+      ASM_MESON_TAC[SUBSET; INTERIOR_SUBSET];
+      ALL_TAC] THEN
+    X_GEN_TAC `w:complex` THEN DISCH_TAC THEN SIMP_TAC[COMPLEX_NORM_DIV] THEN
+    SUBGOAL_THEN `&0 < norm(w - y)` ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (NORM_ARITH
+       `d + c <= norm y ==> &0 < d /\ norm w <= c ==> &0 < norm(w - y)`)) THEN
+      ASM_SIMP_TAC[REAL_LT_MUL; REAL_LT_DIV; REAL_HALF] THEN
+      ASM_MESON_TAC[SUBSET; INTERIOR_SUBSET];
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ]] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `D:real` THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[SUBSET; INTERIOR_SUBSET]; ALL_TAC] THEN
+    REWRITE_TAC[REAL_ARITH `e / &2 / L * x = (x * (e / &2)) / L`] THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; GSYM REAL_LE_LDIV_EQ; REAL_HALF] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (NORM_ARITH
+       `d + c <= norm y ==> norm w <= c ==> d <= norm(w - y)`)) THEN
+    ASM_MESON_TAC[SUBSET; INTERIOR_SUBSET];
+    DISCH_TAC] THEN
+  SUBGOAL_THEN
+   `(\y. (d:complex->complex->complex) (fstcart y) (sndcart y)) continuous_on
+    {pastecart x z | x IN u /\ z IN u}`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN EXPAND_TAC "d" THEN
+    REWRITE_TAC[FORALL_IN_GSPEC; continuous_within; IMP_CONJ] THEN
+    MAP_EVERY X_GEN_TAC [`x:complex`; `z:complex`] THEN REPEAT DISCH_TAC THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; FORALL_PASTECART] THEN
+    REWRITE_TAC[dist; IMP_IMP; GSYM CONJ_ASSOC; PASTECART_SUB] THEN
+    ASM_CASES_TAC `z:complex = x` THEN ASM_REWRITE_TAC[] THENL
+     [UNDISCH_THEN `z:complex = x` (SUBST_ALL_TAC o SYM);
+      SUBGOAL_THEN
+        `(\y. (f(sndcart y) - f(fstcart y)) / (sndcart y - fstcart y))
+         continuous at (pastecart x z)`
+      MP_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_COMPLEX_DIV_AT THEN
+        ASM_SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART; COMPLEX_SUB_0] THEN
+        CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_SUB THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_AT; LINEAR_FSTCART; LINEAR_SNDCART] THEN
+        CONJ_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+        MATCH_MP_TAC CONTINUOUS_AT_COMPOSE THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_AT; LINEAR_FSTCART; LINEAR_SNDCART] THEN
+        REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+        ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON;
+                      CONTINUOUS_ON_EQ_CONTINUOUS_AT];
+        ALL_TAC] THEN
+      REWRITE_TAC[continuous_at; dist; FORALL_PASTECART] THEN
+      REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; PASTECART_SUB] THEN
+      DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(X_CHOOSE_THEN `k1:real` STRIP_ASSUME_TAC) THEN
+      SUBGOAL_THEN
+       `open({pastecart x z | x IN u /\ z IN u} DIFF
+             {y | y IN UNIV /\ fstcart y - sndcart y = Cx(&0)})`
+      MP_TAC THENL
+       [MATCH_MP_TAC OPEN_DIFF THEN
+        ASM_SIMP_TAC[REWRITE_RULE[PCROSS] OPEN_PCROSS] THEN
+        MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE_CONSTANT THEN
+        REWRITE_TAC[CLOSED_UNIV] THEN MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART];
+        SIMP_TAC[OPEN_CONTAINS_BALL; IN_DIFF; IMP_CONJ; FORALL_IN_GSPEC] THEN
+        DISCH_THEN(MP_TAC o SPECL [`x:complex`; `z:complex`]) THEN
+        ASM_REWRITE_TAC[IN_ELIM_THM; IN_UNIV; COMPLEX_SUB_0] THEN
+        ASM_REWRITE_TAC[SUBSET; IN_BALL; FORALL_PASTECART; IN_DIFF;
+          IN_ELIM_PASTECART_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+        REWRITE_TAC[IN_ELIM_THM; IMP_IMP; GSYM CONJ_ASSOC] THEN
+        REWRITE_TAC[ONCE_REWRITE_RULE[NORM_SUB] dist; PASTECART_SUB;
+               FSTCART_PASTECART; SNDCART_PASTECART] THEN
+        DISCH_THEN(X_CHOOSE_THEN `k2:real` STRIP_ASSUME_TAC)] THEN
+      EXISTS_TAC `min k1 k2:real` THEN
+      ASM_SIMP_TAC[REAL_LT_MIN; COMPLEX_NORM_NZ; COMPLEX_SUB_0]] THEN
+    SUBGOAL_THEN `(complex_derivative f) continuous at z` MP_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_INTERIOR THEN
+      EXISTS_TAC `u:complex->bool` THEN ASM_SIMP_TAC[INTERIOR_OPEN] THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON THEN
+      MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE THEN
+      ASM_REWRITE_TAC[];
+      REWRITE_TAC[continuous_at] THEN DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
+      ASM_REWRITE_TAC[dist; REAL_HALF]] THEN
+    DISCH_THEN(X_CHOOSE_THEN `k1:real` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPEC `u:complex->bool` OPEN_CONTAINS_BALL) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `k2:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `min k1 k2:real` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+    MAP_EVERY X_GEN_TAC [`x':complex`; `z':complex`] THEN STRIP_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+     [ASM_MESON_TAC[NORM_LE_PASTECART; REAL_LET_TRANS; REAL_LT_IMP_LE];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `e / &2 = e / &2 / norm(z' - x') * norm(z' - x':complex)`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ]; ALL_TAC] THEN
+    MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_LINEPATH THEN
+    EXISTS_TAC `\u. (complex_derivative f u - complex_derivative f z) /
+                    (z' - x')` THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; NORM_POS_LE; REAL_LT_IMP_LE; REAL_HALF] THEN
+    CONJ_TAC THENL
+     [ASM_SIMP_TAC[COMPLEX_FIELD
+       `~(z:complex = x)
+         ==> a / (z - x) - b = (a - b * (z - x)) / (z - x)`] THEN
+      MATCH_MP_TAC HAS_PATH_INTEGRAL_COMPLEX_DIV THEN
+      MATCH_MP_TAC HAS_PATH_INTEGRAL_SUB THEN
+      REWRITE_TAC[HAS_PATH_INTEGRAL_CONST_LINEPATH] THEN
+      MP_TAC(ISPECL [`f:complex->complex`; `complex_derivative f`;
+                     `linepath(x':complex,z')`; `u:complex->bool`]
+                PATH_INTEGRAL_PRIMITIVE) THEN
+      REWRITE_TAC[ETA_AX; PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+      DISCH_THEN MATCH_MP_TAC THEN
+      REWRITE_TAC[VALID_PATH_LINEPATH] THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE;
+                      GSYM HOLOMORPHIC_ON_DIFFERENTIABLE;
+                      HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HOLOMORPHIC_ON_OPEN;
+                      complex_differentiable];
+        MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `ball(z:complex,k2)`];
+      X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+      REWRITE_TAC[COMPLEX_NORM_DIV; real_div] THEN
+      MATCH_MP_TAC REAL_LE_RMUL THEN
+      REWRITE_TAC[REAL_LE_INV_EQ; NORM_POS_LE] THEN
+      MATCH_MP_TAC(REAL_ARITH `x < e / &2 ==> x <= e * inv(&2)`) THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      REWRITE_TAC[REWRITE_RULE[ONCE_REWRITE_RULE[NORM_SUB] dist]
+       (GSYM IN_BALL)] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `w IN s ==> s SUBSET t ==> w IN t`))] THEN
+    ASM_REWRITE_TAC[PATH_IMAGE_LINEPATH; SEGMENT_CONVEX_HULL] THEN
+    MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_BALL] THEN
+    REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; IN_BALL; dist] THEN
+    ONCE_REWRITE_TAC[NORM_SUB] THEN
+    ASM_MESON_TAC[NORM_LE_PASTECART; REAL_LET_TRANS];
+    ALL_TAC] THEN
+  SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_UNIV; IN_UNIV;
+           GSYM complex_differentiable] THEN
+  X_GEN_TAC `z0:complex` THEN ASM_CASES_TAC `(z0:complex) IN v` THENL
+   [MP_TAC(ISPECL
+    [`f:complex->complex`; `h:complex->complex`; `g:real^1->complex`;
+     `v:complex->bool`; `1`; `B:real`]
+        CAUCHY_NEXT_DERIVATIVE) THEN
+    ASM_SIMP_TAC[IN_DIFF; ARITH_EQ; COMPLEX_POW_1] THEN ANTS_TAC THENL
+     [CONJ_TAC THENL
+       [ASM_MESON_TAC[HAS_VECTOR_DERIVATIVE_UNIQUE_AT]; ALL_TAC] THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+      EXISTS_TAC `u:complex->bool` THEN ASM SET_TAC[];
+      DISCH_THEN(MP_TAC o SPEC `z0:complex`) THEN
+      UNDISCH_TAC `(z0:complex) IN v` THEN EXPAND_TAC "v" THEN
+      SIMP_TAC[IN_ELIM_THM; complex_differentiable] THEN MESON_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(z0:complex) IN u` ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPEC `u:complex->bool` OPEN_CONTAINS_BALL) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `z0:complex`) THEN
+  ASM_SIMP_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT THEN
+  EXISTS_TAC `ball(z0:complex,e)` THEN
+  ASM_REWRITE_TAC[OPEN_BALL; CENTRE_IN_BALL] THEN
+  MATCH_MP_TAC ANALYTIC_IMP_HOLOMORPHIC THEN MATCH_MP_TAC MORERA_TRIANGLE THEN
+  REWRITE_TAC[OPEN_BALL] THEN
+  SUBGOAL_THEN `(h:complex->complex) continuous_on u` ASSUME_TAC THENL
+   [REWRITE_TAC[CONTINUOUS_ON_SEQUENTIALLY] THEN
+    MAP_EVERY X_GEN_TAC [`a:num->complex`; `x:complex`] THEN STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`sequentially`; `\n:num x. (d:complex->complex->complex) (a n) x`;
+      `B:real`; `g:real^1->complex`; `(d:complex->complex->complex) x`]
+      PATH_INTEGRAL_UNIFORM_LIMIT) THEN
+    ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; ETA_AX; EVENTUALLY_TRUE] THEN
+    ANTS_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN BINOP_TAC THEN
+      REWRITE_TAC[FUN_EQ_THM; o_THM] THEN REPEAT GEN_TAC THEN
+      MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]] THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[HAS_VECTOR_DERIVATIVE_UNIQUE_AT]; ALL_TAC] THEN
+    X_GEN_TAC `ee:real` THEN DISCH_TAC THEN
+    MP_TAC(ISPEC `u:complex->bool` OPEN_CONTAINS_CBALL) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `x:complex`) THEN
+    ASM_SIMP_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `dd:real` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `(\y. (d:complex->complex->complex) (fstcart y) (sndcart y))
+      uniformly_continuous_on
+      {pastecart w z | w IN cball(x,dd) /\ z IN path_image g}`
+    MP_TAC THENL
+     [MATCH_MP_TAC COMPACT_UNIFORMLY_CONTINUOUS THEN
+      ASM_SIMP_TAC[REWRITE_RULE[PCROSS] COMPACT_PCROSS; COMPACT_CBALL;
+                   COMPACT_VALID_PATH_IMAGE] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_ELIM_PASTECART_THM] THEN
+      ASM SET_TAC[];
+      ALL_TAC] THEN
+    REWRITE_TAC[uniformly_continuous_on] THEN
+    DISCH_THEN(MP_TAC o SPEC `ee:real`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `kk:real`
+      (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(MP_TAC o GENL [`w:complex`; `z:complex`] o
+     SPECL [`pastecart (x:complex) (z:complex)`;
+            `pastecart (w:complex) (z:complex)`]) THEN
+    SIMP_TAC[IN_ELIM_PASTECART_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    ASM_SIMP_TAC[CENTRE_IN_CBALL; REAL_LT_IMP_LE; dist; PASTECART_SUB] THEN
+    REWRITE_TAC[VECTOR_SUB_REFL; NORM_0; NORM_PASTECART] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[TAUT `b /\ (a /\ b) /\ c ==> d <=> a /\ b /\ c ==> d`] THEN
+    SIMP_TAC[REAL_ADD_RID; POW_2_SQRT; NORM_POS_LE] THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIM_SEQUENTIALLY]) THEN
+    DISCH_THEN(MP_TAC o SPEC `min dd kk:real`) THEN
+    ASM_REWRITE_TAC[EVENTUALLY_SEQUENTIALLY; REAL_LT_MIN] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[ONCE_REWRITE_RULE[DIST_SYM] IN_CBALL; GSYM dist;
+                 REAL_LT_IMP_LE];
+    ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ALL_TAC] THEN
+
+  SUBGOAL_THEN
+   `!w. w IN u ==> (\z. d z w) holomorphic_on u`
+  ASSUME_TAC THENL
+   [EXPAND_TAC "d" THEN X_GEN_TAC `y:complex` THEN STRIP_TAC THEN
+    MATCH_MP_TAC NO_ISOLATED_SINGULARITY THEN EXISTS_TAC `{y:complex}` THEN
+    ASM_REWRITE_TAC[FINITE_SING] THEN CONJ_TAC THENL
+     [SUBGOAL_THEN
+       `((\y. (d:complex->complex->complex) (fstcart y) (sndcart y)) o
+        (\z. pastecart y z))
+        continuous_on u`
+      MP_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_ID;
+                 CONTINUOUS_ON_CONST] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_PASTECART_THM];
+        EXPAND_TAC "d" THEN
+        REWRITE_TAC[o_DEF; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_EQ) THEN
+        GEN_TAC THEN REWRITE_TAC[] THEN COND_CASES_TAC THEN
+        ASM_REWRITE_TAC[] THEN
+        DISCH_TAC THEN REWRITE_TAC[complex_div] THEN MATCH_MP_TAC(COMPLEX_RING
+         `x':complex = --x /\ y' = --y ==> x * y = x' * y'`) THEN
+        REWRITE_TAC[GSYM COMPLEX_INV_NEG; COMPLEX_NEG_SUB]];
+      ASM_SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_DELETE; IN_DELETE;
+        SET_RULE `s DIFF {x} = s DELETE x`; GSYM complex_differentiable] THEN
+      X_GEN_TAC `w:complex` THEN STRIP_TAC THEN
+      MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_TRANSFORM_AT THEN
+      EXISTS_TAC `\w:complex. (f y - f w) / (y - w)` THEN
+      EXISTS_TAC `dist(w:complex,y)` THEN ASM_SIMP_TAC[DIST_POS_LT] THEN
+      (CONJ_TAC THENL [MESON_TAC[DIST_SYM; REAL_LT_REFL]; ALL_TAC]) THEN
+      MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_DIV_AT THEN
+      ASM_REWRITE_TAC[COMPLEX_SUB_0] THEN CONJ_TAC THEN
+      MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_SUB THEN
+      ASM_SIMP_TAC[ETA_AX; COMPLEX_DIFFERENTIABLE_CONST;
+                   COMPLEX_DIFFERENTIABLE_ID] THEN
+      ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!w a b:complex. w IN u /\ segment[a,b] SUBSET u
+                    ==> (\z. d z w) path_integrable_on (linepath(a,b))`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC PATH_INTEGRABLE_CONTINUOUS_LINEPATH THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; HOLOMORPHIC_ON_IMP_CONTINUOUS_ON];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!a b:complex.
+        segment[a,b] SUBSET u
+        ==> (\w. path_integral (linepath(a,b)) (\z. d z w))
+            continuous_on u`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN ASM_CASES_TAC `a:complex = b` THENL
+     [ASM_SIMP_TAC[PATH_INTEGRAL_TRIVIAL; CONTINUOUS_ON_CONST]; ALL_TAC] THEN
+    REWRITE_TAC[continuous_on] THEN X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+    X_GEN_TAC `ee:real` THEN DISCH_TAC THEN
+    ASM_SIMP_TAC[dist; GSYM PATH_INTEGRAL_SUB] THEN
+    MP_TAC(ISPEC `u:complex->bool` OPEN_CONTAINS_CBALL) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `w:complex`) THEN
+    ASM_SIMP_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `dd:real` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `(\y. (d:complex->complex->complex) (fstcart y) (sndcart y))
+      uniformly_continuous_on
+      {pastecart z t | z IN segment[a,b] /\ t IN cball(w,dd)}`
+    MP_TAC THENL
+     [MATCH_MP_TAC COMPACT_UNIFORMLY_CONTINUOUS THEN
+      ASM_SIMP_TAC[REWRITE_RULE[PCROSS] COMPACT_PCROSS;
+                   COMPACT_CBALL; COMPACT_SEGMENT] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_ELIM_PASTECART_THM] THEN
+      ASM SET_TAC[];
+      ALL_TAC] THEN
+    REWRITE_TAC[uniformly_continuous_on] THEN
+    DISCH_THEN(MP_TAC o SPEC `ee / &2 / norm(b - a:complex)`) THEN
+    ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; COMPLEX_NORM_NZ; COMPLEX_SUB_0] THEN
+    DISCH_THEN(X_CHOOSE_THEN `kk:real`
+      (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(MP_TAC o GENL [`z:complex`; `r:complex`] o
+     SPECL [`pastecart (r:complex) (z:complex)`;
+            `pastecart (r:complex) (w:complex)`]) THEN
+    SIMP_TAC[IN_ELIM_PASTECART_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    ASM_SIMP_TAC[CENTRE_IN_CBALL; REAL_LT_IMP_LE; dist; PASTECART_SUB] THEN
+    REWRITE_TAC[VECTOR_SUB_REFL; NORM_0; NORM_PASTECART] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[TAUT `(a /\ b) /\ a /\ c ==> d <=> a /\ b /\ c ==> d`] THEN
+    SIMP_TAC[REAL_ADD_LID; POW_2_SQRT; NORM_POS_LE] THEN DISCH_TAC THEN
+    EXISTS_TAC `min dd kk:real` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+    X_GEN_TAC `x:complex` THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
+    ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `ee / &2 = ee / &2 / norm(b - a) * norm(b - a:complex)`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ]; ALL_TAC] THEN
+    MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_LINEPATH THEN
+    EXISTS_TAC `\r. (d:complex->complex->complex) r x - d r w` THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; NORM_POS_LE; REAL_LT_IMP_LE; REAL_HALF] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC HAS_PATH_INTEGRAL_INTEGRAL THEN
+      MATCH_MP_TAC PATH_INTEGRABLE_SUB THEN ASM_SIMP_TAC[];
+      REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [NORM_SUB] THEN
+      MATCH_MP_TAC REAL_LT_IMP_LE THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REWRITE_TAC[IN_CBALL; dist] THEN
+      ASM_MESON_TAC[NORM_SUB; REAL_LT_IMP_LE]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!a b. segment[a,b] SUBSET u
+          ==> (\w. path_integral (linepath (a,b)) (\z. d z w))
+              path_integrable_on g`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[PATH_INTEGRABLE_ON] THEN
+    MATCH_MP_TAC INTEGRABLE_CONTINUOUS THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN CONJ_TAC THENL
+     [SUBGOAL_THEN
+       `((\w. path_integral (linepath(a,b)) (\z. d z w)) o (g:real^1->complex))
+        continuous_on interval[vec 0,vec 1]`
+      MP_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        ASM_SIMP_TAC[GSYM path; VALID_PATH_IMP_PATH] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+        EXISTS_TAC `u:complex->bool` THEN ASM_SIMP_TAC[GSYM path_image];
+        REWRITE_TAC[o_DEF]];
+      FIRST_ASSUM(fun th -> REWRITE_TAC
+       [MATCH_MP HAS_VECTOR_DERIVATIVE_UNIQUE_AT (SPEC_ALL th)]) THEN
+      ASM_SIMP_TAC[ETA_AX; GSYM path; VALID_PATH_IMP_PATH;
+                   VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!a b. segment[a,b] SUBSET u
+          ==> path_integral (linepath(a,b)) h =
+              path_integral g (\w. path_integral (linepath (a,b)) (\z. d z w))`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    MAP_EVERY X_GEN_TAC [`a:complex`; `b:complex`; `c:complex`] THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN
+     `segment[a:complex,b] SUBSET u /\
+      segment[b,c] SUBSET u /\ segment[c,a] SUBSET u`
+    STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[SEGMENTS_SUBSET_CONVEX_HULL; SUBSET_TRANS]; ALL_TAC] THEN
+    ASM_SIMP_TAC[] THEN
+    ASM_SIMP_TAC[GSYM PATH_INTEGRAL_ADD; PATH_INTEGRABLE_ADD] THEN
+    MATCH_MP_TAC PATH_INTEGRAL_EQ_0 THEN
+    X_GEN_TAC `w:complex` THEN REWRITE_TAC[] THEN DISCH_TAC THEN
+    SUBGOAL_THEN `(w:complex) IN u` ASSUME_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    ASM_SIMP_TAC[GSYM PATH_INTEGRAL_JOIN; VALID_PATH_LINEPATH;
+     VALID_PATH_JOIN; PATHSTART_JOIN;
+     PATH_INTEGRABLE_JOIN; PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+    MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+    MATCH_MP_TAC CAUCHY_THEOREM_TRIANGLE THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN EXISTS_TAC `u:complex->bool` THEN
+    ASM_SIMP_TAC[] THEN ASM SET_TAC[]] THEN
+  MAP_EVERY X_GEN_TAC [`a:complex`; `b:complex`] THEN DISCH_TAC THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `path_integral (linepath(a,b)) (\z. path_integral g (d z))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC PATH_INTEGRAL_EQ THEN
+    REWRITE_TAC[PATH_IMAGE_LINEPATH] THEN
+    REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[SUBSET];
+    MATCH_MP_TAC(REWRITE_RULE[PCROSS] PATH_INTEGRAL_SWAP) THEN
+    REWRITE_TAC[VALID_PATH_LINEPATH; VECTOR_DERIVATIVE_LINEPATH_AT;
+                CONTINUOUS_ON_CONST] THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC
+     [MATCH_MP HAS_VECTOR_DERIVATIVE_UNIQUE_AT (SPEC_ALL th)]) THEN
+    ASM_SIMP_TAC[ETA_AX; CONTINUOUS_VECTOR_POLYNOMIAL_FUNCTION;
+                 CONTINUOUS_AT_IMP_CONTINUOUS_ON] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_ELIM_PASTECART_THM] THEN
+    REWRITE_TAC[PATH_IMAGE_LINEPATH] THEN ASM SET_TAC[]]);;
+
+let CAUCHY_THEOREM_GLOBAL = prove
+ (`!f s g.
+        open s /\ f holomorphic_on s /\
+        valid_path g /\ pathfinish g = pathstart g /\ path_image g SUBSET s /\
+        (!z. ~(z IN s) ==> winding_number(g,z) = Cx(&0))
+        ==> (f has_path_integral Cx(&0)) g`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?z:complex. z IN s /\ ~(z IN path_image g)`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `t SUBSET s /\ ~(t = s) ==> ?z. z IN s /\ ~(z IN t)`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(MESON
+     [CLOPEN; COMPACT_EQ_BOUNDED_CLOSED; NOT_BOUNDED_UNIV]
+     `open s /\ compact t /\ ~(t = {}) ==> ~(t = s)`) THEN
+    ASM_SIMP_TAC[COMPACT_PATH_IMAGE; PATH_IMAGE_NONEMPTY; VALID_PATH_IMP_PATH];
+    MP_TAC(ISPECL [`\w:complex. (w - z) * f(w)`; `s:complex->bool`;
+                   `g:real^1->complex`; `z:complex`]
+      CAUCHY_INTEGRAL_FORMULA_GLOBAL) THEN
+    ASM_SIMP_TAC[COMPLEX_SUB_REFL; COMPLEX_MUL_LZERO; COMPLEX_MUL_RZERO;
+                 HOLOMORPHIC_ON_MUL; HOLOMORPHIC_ON_SUB;
+                 HOLOMORPHIC_ON_ID; HOLOMORPHIC_ON_CONST] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HAS_PATH_INTEGRAL_EQ) THEN
+    X_GEN_TAC `w:complex` THEN ASM_CASES_TAC `w:complex = z` THEN
+    ASM_SIMP_TAC[COMPLEX_FIELD
+     `~(w:complex = z) ==> ((w - z) * f) / (w - z) = f`]]);;
+
+let CAUCHY_THEOREM_GLOBAL_OUTSIDE = prove
+ (`!f s g.
+        open s /\ f holomorphic_on s /\
+        valid_path g /\ pathfinish g = pathstart g /\
+        (!z. ~(z IN s) ==> z IN outside(path_image g))
+        ==> (f has_path_integral Cx(&0)) g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CAUCHY_THEOREM_GLOBAL THEN
+  EXISTS_TAC `s:complex->bool` THEN
+  ASM_SIMP_TAC[WINDING_NUMBER_ZERO_IN_OUTSIDE; VALID_PATH_IMP_PATH] THEN
+  MP_TAC(ISPEC `path_image(g:real^1->complex)` OUTSIDE_NO_OVERLAP) THEN
+  ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* First Cartan Theorem.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let HIGHER_COMPLEX_DERIVATIVE_COMP_LEMMA = prove
+ (`!f g z s t n i.
+     open s /\ f holomorphic_on s /\ z IN s /\
+     open t /\ g holomorphic_on t /\ (!w. w IN s ==> f w IN t) /\
+     complex_derivative f z = Cx(&1) /\
+     (!i. 1 < i /\ i <= n ==> higher_complex_derivative i f z = Cx(&0)) /\
+     i <= n
+     ==> higher_complex_derivative i (g o f) z =
+         higher_complex_derivative i g (f z)`,
+  REPEAT GEN_TAC  THEN
+  SUBGOAL_THEN
+   `open s /\ f holomorphic_on s /\ z IN s /\ open t /\
+      (!w. w IN s ==> f w IN t) /\
+      complex_derivative f z = Cx(&1) /\
+      (!i. 1 < i /\ i <= n ==> higher_complex_derivative i f z = Cx(&0))
+      ==> !i g. g holomorphic_on t /\ i <= n
+          ==> higher_complex_derivative i (g o f) z =
+              higher_complex_derivative i g (f z)`
+    (fun th -> MESON_TAC [th])  THEN
+  STRIP_TAC  THEN
+  INDUCT_TAC THEN
+  REWRITE_TAC [LE_SUC_LT; higher_complex_derivative_alt; o_THM]  THEN
+  REPEAT STRIP_TAC  THEN
+  EQ_TRANS_TAC `higher_complex_derivative i
+             (\w. complex_derivative g (f w) * complex_derivative f w) z` THENL
+   [MATCH_MP_TAC HIGHER_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN  THEN
+    EXISTS_TAC `s:complex->bool`  THEN
+    ASM_REWRITE_TAC []  THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE  THEN
+      ASM_REWRITE_TAC []  THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE_GEN  THEN
+      EXISTS_TAC `t:complex->bool`  THEN
+      ASM_SIMP_TAC [];
+      MATCH_MP_TAC HOLOMORPHIC_ON_MUL  THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC [GSYM o_DEF]  THEN
+        MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE_GEN  THEN
+        EXISTS_TAC `t:complex->bool`  THEN
+        ASM_REWRITE_TAC []  THEN
+        MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE  THEN
+        ASM_REWRITE_TAC [];
+        ASM_REWRITE_TAC [ETA_AX]  THEN
+        MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE  THEN
+        ASM_REWRITE_TAC []];
+      REPEAT STRIP_TAC  THEN
+      MATCH_MP_TAC COMPLEX_DERIVATIVE_CHAIN  THEN
+      ASM_MESON_TAC [HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT]];
+    EQ_TRANS_TAC
+     `vsum (0..i)
+        (\j. Cx (&(binom (i,j))) *
+             higher_complex_derivative j (\w. complex_derivative g (f w)) z *
+             higher_complex_derivative (i - j) (complex_derivative f) z)` THENL
+     [MATCH_MP_TAC HIGHER_COMPLEX_DERIVATIVE_MUL  THEN
+      EXISTS_TAC `s:complex->bool`  THEN
+      ASM_REWRITE_TAC []  THEN
+      ASM_SIMP_TAC [HOLOMORPHIC_COMPLEX_DERIVATIVE]  THEN
+      REWRITE_TAC [GSYM o_DEF]  THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE_GEN  THEN
+      EXISTS_TAC `t:complex->bool`  THEN
+      ASM_REWRITE_TAC []  THEN
+      ASM_SIMP_TAC [HOLOMORPHIC_COMPLEX_DERIVATIVE];
+      REWRITE_TAC [GSYM higher_complex_derivative_alt]  THEN
+      EQ_TRANS_TAC
+        `vsum (i..i)
+           (\j. Cx (&(binom (i,j))) *
+                higher_complex_derivative j
+                  (\w. complex_derivative g (f w)) z *
+                higher_complex_derivative (SUC (i - j)) f z)` THENL
+       [MATCH_MP_TAC VSUM_SUPERSET  THEN
+        REWRITE_TAC[SUBSET_NUMSEG; LT_REFL; LE_0;
+                    LE_REFL; IN_NUMSEG_0; NUMSEG_SING; IN_SING]  THEN
+        X_GEN_TAC `j:num`  THEN
+        REWRITE_TAC [ARITH_RULE `j:num <= i /\ ~(j = i) <=> j < i`]  THEN
+        DISCH_TAC  THEN
+        ASSERT_TAC `1 < SUC (i - j) /\ SUC (i - j) <= n`  THENL
+         [ASM_SIMP_TAC [ARITH_RULE
+           `i < n /\ j < i ==> 1 < SUC (i - j) /\ SUC (i - j) <= n`]  THEN
+          MATCH_MP_TAC (ARITH_RULE `i < n /\ j < i ==> 1 < SUC (i - j)`)  THEN
+          ASM_REWRITE_TAC [];
+          ASM_SIMP_TAC [COMPLEX_MUL_RZERO; COMPLEX_VEC_0]];
+        REWRITE_TAC [NUMSEG_SING; VSUM_SING; BINOM_REFL; SUB_REFL]  THEN
+        ASM_REWRITE_TAC [COMPLEX_MUL_LID; COMPLEX_MUL_RID;
+                         higher_complex_derivative]  THEN
+        ASM_REWRITE_TAC [GSYM o_DEF]  THEN
+        REWRITE_TAC [GSYM higher_complex_derivative;
+                     higher_complex_derivative_alt]  THEN
+        FIRST_X_ASSUM MATCH_MP_TAC  THEN
+        ASM_SIMP_TAC [ARITH_RULE `i:num < n ==> i <= n`]  THEN
+        MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE  THEN
+        ASM_REWRITE_TAC []]]]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_COMP_ITER_LEMMA = prove
+ (`!f s z n m i.
+     open s /\ f holomorphic_on s /\ (!w. w IN s ==> f w IN s) /\
+     z IN s /\ f z = z /\ complex_derivative f z = Cx (&1) /\
+     (!i. 1 < i /\ i <= n ==> higher_complex_derivative i f z = Cx (&0)) /\
+     i <= n
+     ==> higher_complex_derivative i (ITER m f) z =
+         higher_complex_derivative i f z`,
+  GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN GEN_TAC  THEN
+  REWRITE_TAC [RIGHT_FORALL_IMP_THM; IMP_CONJ]  THEN
+  REWRITE_TAC [IMP_IMP]  THEN
+  STRIP_TAC  THEN
+  ASSERT_TAC `!m. ITER m f z = z:complex`  THENL
+   [INDUCT_TAC THEN ASM_REWRITE_TAC [ITER]; ALL_TAC] THEN
+  ASSERT_TAC `!m (w:complex). w IN s ==> ITER m f w IN s`  THENL
+   [INDUCT_TAC THEN ASM_SIMP_TAC [ITER]; ALL_TAC] THEN
+  ASSERT_TAC `!m. ITER m f holomorphic_on s`  THENL
+   [INDUCT_TAC THEN REWRITE_TAC [ITER_POINTLESS] THENL
+     [ASM_SIMP_TAC [I_DEF; HOLOMORPHIC_ON_ID];
+      MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE_GEN  THEN
+      EXISTS_TAC `s:complex ->bool`  THEN
+      ASM_REWRITE_TAC []];
+    ALL_TAC] THEN
+  INDUCT_TAC  THENL
+   [REWRITE_TAC [ITER_POINTLESS; I_DEF; HIGHER_COMPLEX_DERIVATIVE_ID]  THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THENL
+     [ASM_REWRITE_TAC [higher_complex_derivative]; ALL_TAC] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THENL
+     [ASM_REWRITE_TAC [higher_complex_derivative; ONE]; ALL_TAC] THEN
+    MATCH_MP_TAC EQ_SYM  THEN
+    FIRST_X_ASSUM MATCH_MP_TAC  THEN
+    ASM_SIMP_TAC [ARITH_RULE `~(i = 0) /\ ~(i = 1) ==> 1 < i`];
+    GEN_TAC THEN DISCH_TAC  THEN
+    REWRITE_TAC [ITER_ALT_POINTLESS]  THEN
+    EQ_TRANS_TAC `higher_complex_derivative i (ITER m f) (f z)`  THENL
+     [MATCH_MP_TAC HIGHER_COMPLEX_DERIVATIVE_COMP_LEMMA  THEN
+      EXISTS_TAC `s:complex ->bool`  THEN
+      EXISTS_TAC `s:complex ->bool`  THEN
+      EXISTS_TAC `n:num`  THEN
+      ASM_REWRITE_TAC [];
+      ASM_REWRITE_TAC []  THEN
+      FIRST_X_ASSUM MATCH_MP_TAC  THEN
+      ASM_REWRITE_TAC []]]);;
+
+let HIGHER_COMPLEX_DERIVATIVE_ITER_TOP_LEMMA = prove
+ (`!f s z n m.
+     open s /\ f holomorphic_on s /\ (!w. w IN s ==> f w IN s) /\
+     z IN s /\ f z = z /\ complex_derivative f z = Cx (&1) /\
+     (!i. 1 < i /\ i < n ==> higher_complex_derivative i f z = Cx (&0)) /\
+     1 < n
+     ==> higher_complex_derivative n (ITER m f) z =
+         Cx(&m) * higher_complex_derivative n f z`,
+  GEN_TAC THEN GEN_TAC THEN GEN_TAC  THEN
+  INDUCT_TAC THEN REWRITE_TAC [LT_SUC_LE] THEN REWRITE_TAC [LT]  THEN
+  REWRITE_TAC [RIGHT_FORALL_IMP_THM]  THEN
+  STRIP_TAC  THEN
+  ASSERT_TAC `!m. ITER m f z = z:complex`  THENL
+   [INDUCT_TAC THEN ASM_REWRITE_TAC [ITER]; ALL_TAC] THEN
+  ASSERT_TAC `!m (w:complex). w IN s ==> ITER m f w IN s`  THENL
+   [INDUCT_TAC THEN ASM_SIMP_TAC [ITER]; ALL_TAC] THEN
+  ASSERT_TAC `!m. ITER m f holomorphic_on s`  THENL
+   [INDUCT_TAC THEN REWRITE_TAC [ITER_POINTLESS]  THEN
+    ASM_SIMP_TAC [I_DEF; HOLOMORPHIC_ON_ID]  THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE_GEN  THEN
+    EXISTS_TAC `s:complex ->bool`  THEN
+    ASM_REWRITE_TAC [];
+    ALL_TAC] THEN
+  ASSERT_TAC `!w. w IN s ==> f complex_differentiable at w`  THENL
+   [ASM_MESON_TAC [HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT]; ALL_TAC] THEN
+  ASSERT_TAC `!m w. w IN s ==> ITER m f complex_differentiable at w`  THENL
+   [ASM_MESON_TAC [HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT]; ALL_TAC] THEN
+  ASSERT_TAC `!m. complex_derivative (ITER m f) z = Cx(&1)`  THENL
+   [INDUCT_TAC THEN ASM_REWRITE_TAC [ITER_POINTLESS]  THENL
+     [REWRITE_TAC [I_DEF; COMPLEX_DERIVATIVE_ID]; ALL_TAC] THEN
+    ASM_SIMP_TAC [COMPLEX_DERIVATIVE_CHAIN;
+                  HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT]  THEN
+    REWRITE_TAC [COMPLEX_MUL_LID];
+    ALL_TAC] THEN
+  INDUCT_TAC THEN
+  REWRITE_TAC [higher_complex_derivative_alt; ITER_POINTLESS]  THENL
+   [ASM_REWRITE_TAC [COMPLEX_MUL_LZERO; I_DEF; COMPLEX_DERIVATIVE_ID;
+                     HIGHER_COMPLEX_DERIVATIVE_CONST;
+                     ARITH_RULE `n = 0 <=> ~(1 <= n)`];
+    ALL_TAC] THEN
+  EQ_TRANS_TAC `higher_complex_derivative n
+             (\w. complex_derivative f (ITER m f w) *
+                  complex_derivative (ITER m f) w) z`  THENL
+   [MATCH_MP_TAC HIGHER_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN  THEN
+    EXISTS_TAC `s:complex->bool`  THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC  THENL
+     [REWRITE_TAC [o_DEF]  THEN
+      MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE  THEN
+      ASM_REWRITE_TAC []  THEN
+      ONCE_REWRITE_TAC [GSYM o_DEF]  THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE_GEN  THEN
+      EXISTS_TAC `s:complex->bool`  THEN
+      ASM_REWRITE_TAC [ETA_AX];
+      ALL_TAC] THEN
+    CONJ_TAC  THENL
+     [MATCH_MP_TAC HOLOMORPHIC_ON_MUL  THEN CONJ_TAC  THENL
+       [ONCE_REWRITE_TAC [GSYM o_DEF]  THEN
+        MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE_GEN  THEN
+        EXISTS_TAC `s:complex->bool`  THEN
+        ASM_REWRITE_TAC[ETA_AX]  THEN
+        MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE  THEN
+        ASM_REWRITE_TAC[];
+        ONCE_REWRITE_TAC [GSYM o_DEF]  THEN
+        MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE_GEN  THEN
+        EXISTS_TAC `s:complex->bool`  THEN
+        ASM_REWRITE_TAC[HOLOMORPHIC_ON_ID]  THEN
+        MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE  THEN
+        ASM_REWRITE_TAC[]];
+      GEN_TAC THEN DISCH_TAC  THEN
+      MATCH_MP_TAC COMPLEX_DERIVATIVE_CHAIN  THEN
+      CONJ_TAC  THENL
+       [MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT  THEN
+        ASM_MESON_TAC [];
+        MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT  THEN
+        ASM_MESON_TAC []]];
+    ALL_TAC] THEN
+  EQ_TRANS_TAC
+   `vsum (0..n)
+      (\i. Cx (&(binom (n,i))) *
+           higher_complex_derivative i
+             (\w. complex_derivative f (ITER m f w)) z *
+           higher_complex_derivative (n - i)
+             (complex_derivative (ITER m f)) z)`  THENL
+   [MATCH_MP_TAC HIGHER_COMPLEX_DERIVATIVE_MUL  THEN
+    EXISTS_TAC `s:complex->bool`  THEN
+    ASM_REWRITE_TAC[]  THEN CONJ_TAC  THENL
+     [ONCE_REWRITE_TAC [GSYM o_DEF]  THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE_GEN  THEN
+      EXISTS_TAC `s:complex->bool`  THEN
+      ASM_REWRITE_TAC[ETA_AX]  THEN
+      MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE  THEN
+      ASM_REWRITE_TAC[];
+      MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE  THEN
+      ASM_REWRITE_TAC[]];
+    ALL_TAC] THEN
+  EQ_TRANS_TAC
+   `vsum {0,n}
+      (\i. Cx (&(binom (n,i))) *
+           higher_complex_derivative i
+             (\w. complex_derivative f (ITER m f w)) z *
+           higher_complex_derivative (n - i)
+             (complex_derivative (ITER m f)) z)`  THENL
+   [MATCH_MP_TAC VSUM_SUPERSET  THEN
+    REWRITE_TAC [INSERT_SUBSET; EMPTY_SUBSET; IN_NUMSEG_0; LE_0; LE_REFL;
+                 IN_INSERT; NOT_IN_EMPTY; DE_MORGAN_THM]  THEN
+    X_GEN_TAC `i:num`  THEN
+    STRIP_TAC  THEN
+    REWRITE_TAC [GSYM higher_complex_derivative_alt]  THEN
+    ASSERT_TAC `1 < SUC (n-i) /\ SUC (n-i) <= n`  THENL
+     [ASM_SIMP_TAC [ARITH_RULE `i <= n /\ ~(i=0) /\ ~(i=n)
+                                ==> 1 < SUC (n-i) /\ SUC (n-i) <= n`];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC []  THEN
+    SUBGOAL_THEN
+      `higher_complex_derivative (SUC (n - i)) (ITER m f) z = Cx(&0)`
+      SUBST1_TAC  THENL
+     [EQ_TRANS_TAC `higher_complex_derivative (SUC (n - i)) f z`  THENL
+       [MATCH_MP_TAC HIGHER_COMPLEX_DERIVATIVE_COMP_ITER_LEMMA  THEN
+        EXISTS_TAC `s:complex->bool`  THEN
+        ASM_REWRITE_TAC []  THEN
+        EXISTS_TAC `n:num`  THEN
+        ASM_REWRITE_TAC [];
+        FIRST_X_ASSUM MATCH_MP_TAC  THEN
+        ASM_REWRITE_TAC []];
+      ASM_REWRITE_TAC [COMPLEX_MUL_RZERO; COMPLEX_VEC_0]];
+    ALL_TAC] THEN
+  SIMP_TAC [VSUM_CLAUSES; FINITE_RULES; IN_INSERT; NOT_IN_EMPTY]  THEN
+  REWRITE_TAC [binom; BINOM_REFL; COMPLEX_MUL_LID;
+               SUB_REFL; SUB; higher_complex_derivative]  THEN
+  ASM_CASES_TAC `n = 0` THEN ASM_REWRITE_TAC []  THENL
+   [REWRITE_TAC [higher_complex_derivative]  THEN
+    POP_ASSUM SUBST_ALL_TAC  THEN
+    RULE_ASSUM_TAC (REWRITE_RULE [higher_complex_derivative])  THEN
+    ASM_REWRITE_TAC [COMPLEX_MUL_RID; COMPLEX_MUL_LID;
+                     COMPLEX_VEC_0; COMPLEX_ADD_RID]  THEN
+    ASM_MESON_TAC [ARITH_RULE `~(1 <= 0)`];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC [COMPLEX_MUL_LID; COMPLEX_VEC_0; COMPLEX_ADD_RID]  THEN
+  ASM_REWRITE_TAC [COMPLEX_MUL_RID]  THEN
+  ASM_REWRITE_TAC [GSYM higher_complex_derivative_alt]  THEN
+  SUBGOAL_THEN
+    `(\w. complex_derivative f (ITER m f w)) = complex_derivative f o ITER m f`
+    SUBST1_TAC
+  THENL [REWRITE_TAC [FUN_EQ_THM; o_THM]; ALL_TAC] THEN
+  SUBGOAL_THEN
+    `higher_complex_derivative n (complex_derivative f o ITER m f) z =
+     higher_complex_derivative n (complex_derivative f) (ITER m f z)`
+  SUBST1_TAC  THENL
+   [MATCH_MP_TAC HIGHER_COMPLEX_DERIVATIVE_COMP_LEMMA  THEN
+    EXISTS_TAC `s:complex->bool`  THEN
+    EXISTS_TAC `s:complex->bool`  THEN
+    EXISTS_TAC `n:num`  THEN
+    ASM_REWRITE_TAC[]  THEN
+    ASM_SIMP_TAC[HOLOMORPHIC_COMPLEX_DERIVATIVE; LE_REFL]  THEN
+    REPEAT STRIP_TAC  THEN
+    EQ_TRANS_TAC `higher_complex_derivative i f z`  THENL
+     [MATCH_MP_TAC HIGHER_COMPLEX_DERIVATIVE_COMP_ITER_LEMMA  THEN
+      EXISTS_TAC `s:complex->bool`  THEN
+      EXISTS_TAC `n:num`  THEN
+      ASM_REWRITE_TAC[];
+      ASM_SIMP_TAC[]];
+    ALL_TAC] THEN
+  ASSERT_TAC `Cx (&(SUC m)) = Cx (&m) +  Cx (&1)`  THENL
+   [REWRITE_TAC [GSYM CX_ADD; REAL_OF_NUM_ADD; ONE; ADD_SUC; ADD_0];
+    ASM_REWRITE_TAC[COMPLEX_POLY_CLAUSES;
+                    GSYM higher_complex_derivative_alt]]);;
+
+let CAUCHY_HIGHER_COMPLEX_DERIVATIVE_BOUND = prove
+ (`!f z y r B0 n.
+     &0 < r /\ 0 < n /\
+     f holomorphic_on ball(z,r) /\
+     f continuous_on cball(z,r) /\
+     (!w. w IN ball(z,r) ==> f w IN ball(y,B0))
+     ==> norm (higher_complex_derivative n f z) <= &(FACT n) * B0 / r pow n`,
+  REPEAT STRIP_TAC  THEN
+  SUBGOAL_THEN `higher_complex_derivative n f z =
+                higher_complex_derivative n (\w. f w - y) z`
+  SUBST1_TAC  THENL
+   [EQ_TRANS_TAC `higher_complex_derivative n (\w. f w) z -
+             higher_complex_derivative n (\w. y) z`  THENL
+     [ASM_SIMP_TAC
+       [HIGHER_COMPLEX_DERIVATIVE_CONST; ARITH_RULE `0<n ==> ~(n=0)`]  THEN
+      REWRITE_TAC [COMPLEX_SUB_RZERO; ETA_AX];
+      MATCH_MP_TAC EQ_SYM  THEN
+      REWRITE_TAC [ETA_AX]  THEN
+      MATCH_MP_TAC HIGHER_COMPLEX_DERIVATIVE_SUB  THEN
+      EXISTS_TAC `ball(z:complex,r)`  THEN
+      ASM_SIMP_TAC [OPEN_BALL; HOLOMORPHIC_ON_CONST; CENTRE_IN_BALL]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `norm ((Cx (&2) * Cx pi * ii) / Cx (&(FACT n))
+          * higher_complex_derivative n (\w. f w - y) z)
+    <= (B0 / r pow (n + 1)) * &2 * pi * r`
+  MP_TAC THENL
+   [MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_CIRCLEPATH  THEN
+    EXISTS_TAC `(\u. (f u - y) / (u - z) pow (n + 1))`  THEN
+    EXISTS_TAC `z:complex`  THEN STRIP_TAC  THENL
+     [MATCH_MP_TAC CAUCHY_HAS_PATH_INTEGRAL_HIGHER_DERIVATIVE_CIRCLEPATH  THEN
+      ASM_SIMP_TAC[CENTRE_IN_BALL]  THEN CONJ_TAC  THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_SUB  THEN
+        ASM_REWRITE_TAC [CONTINUOUS_ON_CONST];
+        MATCH_MP_TAC HOLOMORPHIC_ON_SUB  THEN
+        ASM_REWRITE_TAC [HOLOMORPHIC_ON_CONST]];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[]  THEN STRIP_TAC  THENL
+     [MATCH_MP_TAC REAL_LE_DIV  THEN STRIP_TAC  THENL
+       [MATCH_MP_TAC REAL_LT_IMP_LE  THEN
+        MATCH_MP_TAC
+         (prove(`(?x. &0 <= x /\ x < B0) ==> &0 < B0`, REAL_ARITH_TAC))  THEN
+        EXISTS_TAC `norm ((\u. (f:complex->complex) u - y) z)`  THEN
+        SIMP_TAC[NORM_POS_LE]  THEN
+        SUBGOAL_THEN
+         `!w:complex. f w IN ball(y,B0) ==> norm (f w - y) < B0`
+        MATCH_MP_TAC  THENL
+         [ASM_MESON_TAC [dist; DIST_SYM; IN_BALL; CENTRE_IN_BALL];
+          ALL_TAC] THEN
+        FIRST_ASSUM MATCH_MP_TAC  THEN
+        ASM_SIMP_TAC[CENTRE_IN_BALL];
+        MATCH_MP_TAC(SPECL [`r:real`;`n + 1`] REAL_POW_LE)  THEN
+        ASM_SIMP_TAC[REAL_LT_IMP_LE]];
+      REPEAT STRIP_TAC  THEN
+      ASM_REWRITE_TAC[COMPLEX_NORM_DIV;COMPLEX_NORM_POW]  THEN
+      ASM_SIMP_TAC [REAL_LE_DIV2_EQ; REAL_POW_LT]  THEN
+      ONCE_REWRITE_TAC[MESON[] `!(f:complex->complex).
+        (f x - y) = (\w. f w - y) x`]  THEN
+      MATCH_MP_TAC CONTINUOUS_ON_CLOSURE_NORM_LE  THEN
+      EXISTS_TAC `ball(z:complex,r)`  THEN
+      ASM_SIMP_TAC[CLOSURE_BALL]  THEN
+      REPEAT STRIP_TAC  THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_SUB  THEN
+        ASM_SIMP_TAC[CONTINUOUS_ON_CONST];
+        SUBGOAL_THEN
+        `!w:complex. f w IN ball(y,B0) ==> norm (f w - y) <= B0`
+        MATCH_MP_TAC  THENL
+         [REWRITE_TAC[GSYM dist;IN_BALL;DIST_SYM;REAL_LT_IMP_LE];
+          ASM_MESON_TAC [dist; DIST_SYM; IN_BALL; CENTRE_IN_BALL]];
+        ASM_REWRITE_TAC[cball;IN_ELIM_THM;dist;DIST_SYM]  THEN
+        ASM_SIMP_TAC[REAL_EQ_IMP_LE]]];
+      ALL_TAC] THEN
+  REWRITE_TAC [COMPLEX_NORM_MUL; COMPLEX_NORM_DIV; COMPLEX_NORM_II;
+               COMPLEX_NORM_CX; REAL_ABS_NUM; REAL_ABS_PI;
+               REAL_MUL_RID]  THEN
+  STRIP_TAC  THEN
+  ABBREV_TAC `a = (&2 * pi) / &(FACT n)`  THEN
+  SUBGOAL_THEN `&0 < a` ASSUME_TAC  THENL
+   [EXPAND_TAC "a"  THEN
+    SIMP_TAC[REAL_LT_DIV; REAL_LT_MUL; REAL_OF_NUM_LT; FACT_LT; ARITH; PI_POS];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+  `B0 / r pow (n + 1) * &2 * pi * r = a * (&(FACT n) * B0 / r pow n)`
+  SUBST_ALL_TAC  THENL
+   [EXPAND_TAC "a"  THEN
+    REWRITE_TAC [GSYM ADD1; real_pow] THEN
+    SUBGOAL_THEN `~(&(FACT n) = &0) /\ &0 < r` MP_TAC  THENL
+     [ASM_REWRITE_TAC[FACT_NZ; REAL_OF_NUM_EQ];
+      CONV_TAC REAL_FIELD];
+   ASM_MESON_TAC [REAL_LE_LCANCEL_IMP]]);;
+
+let FIRST_CARTAN_THM_DIM_1 = prove
+  (`!f s z w.
+      open s /\ connected s /\ bounded s /\
+      (!w. w IN s ==> f w IN s) /\ f holomorphic_on s /\
+      z IN s /\ f z = z /\
+      complex_derivative f z = Cx (&1) /\ w IN s
+      ==> f w = w`,
+   REWRITE_TAC [RIGHT_FORALL_IMP_THM; IMP_CONJ] THEN REPEAT GEN_TAC THEN
+   REPEAT DISCH_TAC THEN REPEAT STRIP_TAC THEN EQ_TRANS_TAC `I w:complex` THENL
+   [MATCH_MP_TAC HOLOMORPHIC_FUN_EQ_ON_CONNECTED;
+    REWRITE_TAC [I_THM]] THEN
+   EXISTS_TAC `z:complex` THEN EXISTS_TAC `s:complex->bool` THEN
+   ASM_REWRITE_TAC [I_DEF; HOLOMORPHIC_ON_ID] THEN
+   GEN_TAC THEN STRIP_ASSUME_TAC (ARITH_RULE `n = 0 \/ n = 1 \/ 1 < n`) THENL
+   [ASM_REWRITE_TAC [higher_complex_derivative];
+    ASM_REWRITE_TAC [ONE; higher_complex_derivative; COMPLEX_DERIVATIVE_ID];
+    ASM_REWRITE_TAC [HIGHER_COMPLEX_DERIVATIVE_ID]] THEN
+   ASM_SIMP_TAC [ARITH_RULE `1 < n ==> ~(n=0) /\ ~(n=1)`] THEN
+   POP_ASSUM MP_TAC THEN SPEC_TAC (`n:num`,`n:num`) THEN
+   MATCH_MP_TAC num_WF THEN REPEAT STRIP_TAC THEN
+   REWRITE_TAC [GSYM COMPLEX_NORM_ZERO] THEN
+   MATCH_MP_TAC REAL_ARCH_RDIV_EQ_0 THEN REWRITE_TAC [NORM_POS_LE] THEN
+   ASSERT_TAC `?c. s SUBSET ball(z:complex,c)` THENL
+   [ASSERT_TAC `?c. !w:complex. w IN s ==> norm w <= c` THENL
+    [ASM_REWRITE_TAC[GSYM bounded];
+     EXISTS_TAC `&2 * c + &1` THEN REWRITE_TAC [SUBSET] THEN GEN_TAC THEN
+     DISCH_TAC THEN
+     SUBGOAL_THEN `norm (x:complex) <= c /\ norm (z:complex) <= c` MP_TAC THENL
+     [ASM_MESON_TAC[]; REWRITE_TAC [IN_BALL] THEN NORM_ARITH_TAC]];
+    ALL_TAC] THEN
+   ASSERT_TAC `?r. &0 < r /\ cball(z:complex,r) SUBSET s` THENL
+   [ASM_MESON_TAC [OPEN_CONTAINS_CBALL];
+    EXISTS_TAC `&(FACT n) * c / r pow n`] THEN
+   ASSERT_TAC `&0 < c` THENL
+   [SUBGOAL_THEN `~(ball(z:complex,c) = {})` MP_TAC THENL
+    [ASM SET_TAC[]; ASM_REWRITE_TAC [BALL_EQ_EMPTY; REAL_NOT_LE]];
+    ALL_TAC] THEN
+   ASSERT_TAC `ball(z:complex,r) SUBSET s` THENL
+   [ASM_MESON_TAC [SUBSET_TRANS; BALL_SUBSET_CBALL]; ALL_TAC] THEN
+   CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_LE_MUL THEN CONJ_TAC THENL
+    [MATCH_MP_TAC REAL_LT_IMP_LE THEN MATCH_MP_TAC REAL_LTE_TRANS THEN
+     EXISTS_TAC `&1` THEN REWRITE_TAC [REAL_LT_01; FACT_LE; REAL_OF_NUM_LE];
+     MATCH_MP_TAC REAL_LE_DIV THEN ASM_SIMP_TAC [REAL_LT_IMP_LE; REAL_POW_LE]];
+    ALL_TAC] THEN
+   REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC [GSYM COMPLEX_NORM_NUM] THEN
+   REWRITE_TAC [GSYM COMPLEX_NORM_MUL] THEN SUBGOAL_THEN
+      `Cx(&m) * higher_complex_derivative n f z =
+       higher_complex_derivative n (ITER m f) z`
+     SUBST1_TAC THENL
+   [MATCH_MP_TAC (GSYM HIGHER_COMPLEX_DERIVATIVE_ITER_TOP_LEMMA) THEN
+    EXISTS_TAC `s:complex->bool` THEN ASM_SIMP_TAC [];
+    ALL_TAC] THEN
+   REWRITE_TAC [COMPLEX_NORM_CX; REAL_ABS_NUM; REAL_POS] THEN
+   MATCH_MP_TAC CAUCHY_HIGHER_COMPLEX_DERIVATIVE_BOUND THEN
+   EXISTS_TAC `z:complex` THEN ASM_SIMP_TAC [ARITH_RULE `1<n ==> 0 < n`] THEN
+   ASSERT_TAC `!m w. w:complex IN s ==> ITER m f w IN s` THENL
+   [INDUCT_TAC THEN ASM_SIMP_TAC [ITER];
+    ASSERT_TAC `!m. ITER m f holomorphic_on s` THENL
+    [INDUCT_TAC THEN REWRITE_TAC [ITER_POINTLESS] THENL
+     [ASM_SIMP_TAC [I_DEF; HOLOMORPHIC_ON_ID];
+      MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE_GEN THEN
+      EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC []];
+     ASSERT_TAC `ITER m f holomorphic_on ball(z,r)` THENL
+     [MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN ASM SET_TAC [];
+      ASM_REWRITE_TAC[]] THEN
+     CONJ_TAC THENL
+     [ASM_MESON_TAC [CONTINUOUS_ON_SUBSET; HOLOMORPHIC_ON_IMP_CONTINUOUS_ON];
+      ASM SET_TAC []]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Second Cartan Theorem.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let SECOND_CARTAN_THM_DIM_1 = prove
+ (`!g f r.
+     &0 < r /\
+     g holomorphic_on ball(Cx(&0),r) /\
+     (!z. z IN ball(Cx(&0),r) ==> g z IN ball(Cx(&0),r)) /\
+     g(Cx(&0)) = Cx(&0) /\
+     f holomorphic_on ball(Cx(&0),r) /\
+     (!z. z IN ball(Cx(&0),r) ==> f z IN ball(Cx(&0),r)) /\
+     f (Cx(&0)) = Cx(&0) /\
+     (!z. z IN ball(Cx(&0),r) ==> g (f z) = z) /\
+     (!z. z IN ball(Cx(&0),r) ==> f (g z) = z)
+     ==> ?t. !z. z IN ball(Cx(&0),r) ==> g z = cexp (ii * Cx t) * z`,
+  let COMPLEX_DERIVATIVE_LEFT_INVERSE = prove
+    (`!s t f g w.
+       open s /\ open t /\
+       (!z. z IN s ==> f z IN t) /\ f holomorphic_on s /\
+       (!z. z IN t ==> g z IN s) /\ g holomorphic_on t /\
+       (!z. z IN s ==> g (f z) = z) /\ w IN s
+       ==> complex_derivative f w * complex_derivative g (f w) = Cx(&1)`,
+     REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC [COMPLEX_MUL_SYM] THEN
+     SUBGOAL_THEN `complex_derivative g (f w) * complex_derivative f w =
+                   complex_derivative (g o f) w ` SUBST1_TAC THENL
+     [ASM_MESON_TAC [HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT;
+                     COMPLEX_DERIVATIVE_CHAIN];
+      EQ_TRANS_TAC `complex_derivative (\u. u) w` THENL
+      [MATCH_MP_TAC COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+       EXISTS_TAC `s:complex->bool` THEN
+       ASM_SIMP_TAC[HOLOMORPHIC_ON_ID;o_THM] THEN
+       ASM_MESON_TAC [HOLOMORPHIC_ON_COMPOSE_GEN];
+       ASM_SIMP_TAC[COMPLEX_DERIVATIVE_ID]]]) in
+  let LEMMA_1 = prove
+    (`!s f.
+        open s /\ connected s /\ f holomorphic_on s /\ Cx(&0) IN s /\
+        (!u z. norm u = &1 /\ z IN s ==> u * z IN s) /\
+        (!u z. norm u = &1 /\ z IN s ==> f (u * z) = u * f z)
+        ==> ?c. !z. z IN s ==> f z = c * z`,
+     REPEAT STRIP_TAC THEN ABBREV_TAC `c = complex_derivative f (Cx(&0))` THEN
+     EXISTS_TAC `c : complex` THEN
+     SUBGOAL_THEN `f(Cx(&0)) = Cx(&0)` ASSUME_TAC THENL
+     [FIRST_X_ASSUM (MP_TAC o SPECL [`--Cx(&1)`;`Cx(&0)`]) THEN
+      ASM_REWRITE_TAC [NORM_NEG; COMPLEX_NORM_NUM; COMPLEX_MUL_RZERO] THEN
+      CONV_TAC COMPLEX_RING; ALL_TAC] THEN
+     SUBGOAL_THEN
+       `!n u z.
+          norm u = &1 /\ z IN s ==>
+          u pow n * higher_complex_derivative n f (u * z) =
+       u * higher_complex_derivative n f z`
+       ASSUME_TAC THENL
+     [REPEAT STRIP_TAC THEN
+      EQ_TRANS_TAC `higher_complex_derivative n (\w. f (u * w)) z` THENL
+      [MATCH_MP_TAC EQ_SYM THEN
+       MATCH_MP_TAC HIGHER_COMPLEX_DERIVATIVE_COMPOSE_LINEAR THEN
+       EXISTS_TAC `s:complex->bool` THEN EXISTS_TAC `s:complex->bool` THEN
+       ASM_SIMP_TAC[]; ALL_TAC] THEN
+      EQ_TRANS_TAC `higher_complex_derivative n (\w. u * f w) z` THENL
+      [MATCH_MP_TAC HIGHER_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+       EXISTS_TAC `s:complex->bool` THEN ASM_SIMP_TAC[] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC
+         (REWRITE_RULE [o_DEF]
+           (SPECL [`\w:complex. u*w`; `f:complex->complex`]
+               HOLOMORPHIC_ON_COMPOSE_GEN)) THEN
+        EXISTS_TAC `s:complex->bool` THEN
+        ASM_SIMP_TAC [HOLOMORPHIC_ON_LINEAR];
+        MATCH_MP_TAC
+          (REWRITE_RULE [o_DEF]
+            (SPECL [`f:complex->complex`; `\w:complex. u*w`]
+                   HOLOMORPHIC_ON_COMPOSE_GEN)) THEN
+        EXISTS_TAC `(:complex)` THEN
+        ASM_REWRITE_TAC [HOLOMORPHIC_ON_LINEAR; IN_UNIV]];
+        POP_ASSUM MP_TAC THEN SPEC_TAC (`z:complex`,`z:complex`) THEN
+       SPEC_TAC (`n:num`,`n:num`) THEN INDUCT_TAC THEN
+       REWRITE_TAC [higher_complex_derivative] THEN GEN_TAC THEN
+       DISCH_TAC THEN EQ_TRANS_TAC
+         `complex_derivative (\w. u * higher_complex_derivative n f w) z`
+       THENL
+       [MATCH_MP_TAC COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+        EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+        [MATCH_MP_TAC HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE THEN
+         ASM_REWRITE_TAC[] THEN MATCH_MP_TAC HOLOMORPHIC_ON_MUL THEN
+         ASM_REWRITE_TAC [HOLOMORPHIC_ON_CONST];
+         MATCH_MP_TAC HOLOMORPHIC_ON_MUL THEN
+         ASM_REWRITE_TAC [HOLOMORPHIC_ON_CONST; ETA_AX] THEN
+         MATCH_MP_TAC HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE THEN
+         ASM_REWRITE_TAC[]];
+        MATCH_MP_TAC COMPLEX_DERIVATIVE_LMUL THEN
+        MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT THEN
+        ASM_MESON_TAC [HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE]]];
+      SUBGOAL_THEN
+        `!n. 2 <= n ==> higher_complex_derivative n f (Cx(&0)) = Cx(&0)`
+        ASSUME_TAC THENL
+      [GEN_TAC THEN  DISCH_TAC THEN SUBGOAL_THEN
+         `!n z. 2 <= n /\
+                (!u. norm u = &1 ==> u pow n * z = u * z) ==> z = Cx(&0)`
+         MATCH_MP_TAC THENL
+       [REPEAT STRIP_TAC THEN MATCH_MP_TAC
+         (COMPLEX_RING
+           `!u. ~(u pow n' = u) /\ u pow n' * z = u * z ==> z = Cx(&0)`) THEN
+        SUBGOAL_THEN `2 <= n' ==> ?u. norm u = &1 /\ ~(u pow n' = u)`
+          (fun th -> ASM_MESON_TAC [th]) THEN
+        STRUCT_CASES_TAC (SPEC `n':num` num_CASES) THEN
+        REWRITE_TAC
+          [ARITH_LE; ARITH_RULE `2 <= SUC n'' <=> 1 <= n''`; complex_pow] THEN
+        DISCH_TAC THEN MP_TAC (SPEC `n'':num` COMPLEX_NOT_ROOT_UNITY) THEN
+        ASM_REWRITE_TAC [] THEN STRIP_TAC THEN EXISTS_TAC `u:complex` THEN
+        ASM_REWRITE_TAC [] THEN POP_ASSUM MP_TAC THEN
+        REWRITE_TAC [CONTRAPOS_THM] THEN
+        SUBGOAL_THEN `~(u = Cx(&0))` MP_TAC THENL
+        [ASM_REWRITE_TAC [GSYM COMPLEX_NORM_ZERO; REAL_OF_NUM_EQ; ARITH_EQ];
+         CONV_TAC COMPLEX_FIELD];
+        EXISTS_TAC `n:num` THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+        FIRST_X_ASSUM (MP_TAC o SPECL [`n:num`;`u:complex`;`Cx(&0)`]) THEN
+        ASM_REWRITE_TAC[COMPLEX_MUL_RZERO]];
+       REPEAT STRIP_TAC THEN MATCH_MP_TAC
+        (REWRITE_RULE []
+          (SPECL [`f:complex->complex`; `\z. c*z`; `Cx(&0)`;
+                  `s:complex->bool`]
+             HOLOMORPHIC_FUN_EQ_ON_CONNECTED)) THEN
+       ASM_REWRITE_TAC [COMPLEX_MUL_RZERO; HOLOMORPHIC_ON_LINEAR;
+                        HIGHER_COMPLEX_DERIVATIVE_LINEAR] THEN
+       GEN_TAC THEN FIRST_X_ASSUM (MP_TAC o SPEC `n:num`) THEN
+       STRUCT_CASES_TAC (ARITH_RULE `n = 0 \/ n = 1 \/ 2 <= n`) THEN
+       ASM_SIMP_TAC [higher_complex_derivative; ARITH_EQ; ARITH_LE; ONE] THEN
+       ASM_SIMP_TAC [ARITH_RULE `2 <= n ==> ~(n=0)`] THEN
+       ASM_SIMP_TAC [ARITH_RULE `2 <= n ==> ~(n=SUC 0)`]]]) in
+  let LEMMA_2 = prove
+    (`!r c. &0 < r /\ &0 <= c /\
+            (!x. &0 <= x /\ x < r ==> c * x < r)
+            ==> c <= &1`,
+     REPEAT STRIP_TAC THEN REWRITE_TAC [GSYM REAL_NOT_LT] THEN STRIP_TAC THEN
+     FIRST_X_ASSUM (MP_TAC o SPEC `r * (c + &1) / (&2 * c)`) THEN
+     REWRITE_TAC [MESON [] `((a ==> b) ==> F) <=> (a /\ ~b)`] THEN
+     CONJ_TAC THENL
+     [CONJ_TAC THENL
+      [MATCH_MP_TAC REAL_LE_MUL THEN CONJ_TAC THENL
+       [ASM_REAL_ARITH_TAC; MATCH_MP_TAC REAL_LE_DIV THEN ASM_REAL_ARITH_TAC];
+       ALL_TAC] THEN
+      MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `r * &1` THEN
+      CONJ_TAC THENL [ALL_TAC; REWRITE_TAC [REAL_MUL_RID; REAL_LE_REFL]] THEN
+      MATCH_MP_TAC REAL_LT_LMUL THEN ASM_REWRITE_TAC[] THEN
+      SUBGOAL_THEN `&0 < &2 * c` ASSUME_TAC THENL
+      [ASM_REAL_ARITH_TAC;
+       ASM_SIMP_TAC [REAL_LT_LDIV_EQ] THEN ASM_REAL_ARITH_TAC];
+      REWRITE_TAC [REAL_NOT_LT] THEN
+      ONCE_REWRITE_TAC [REAL_RING `!a b c:real. a * b * c = b * a * c`] THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `r * &1` THEN CONJ_TAC THENL
+      [REWRITE_TAC [REAL_MUL_RID; REAL_LE_REFL]; ALL_TAC] THEN
+      MATCH_MP_TAC REAL_LE_LMUL THEN CONJ_TAC THENL
+      [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+      SUBGOAL_THEN `&0 < &2 * c` ASSUME_TAC THENL
+      [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+       ASM_SIMP_TAC [REAL_ARITH `&0 < c ==> a * b / c = (a * b) / c`] THEN
+       SUBGOAL_THEN `(c * (c + &1)) / (&2 * c) = (c + &1) / &2`
+         SUBST1_TAC THENL
+       [ASM_SIMP_TAC [RAT_LEMMA5; REAL_ARITH `&0 < &2`] THEN
+        ASM_REAL_ARITH_TAC;
+        ASM_REAL_ARITH_TAC]]) in
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+    `!u z. norm u = &1 /\ z IN ball(Cx(&0),r) ==> u * g z = g (u * z)`
+    ASSUME_TAC THENL
+  [REPEAT STRIP_TAC THEN SUBGOAL_THEN `~(u = Cx(&0))` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[GSYM COMPLEX_NORM_NZ] THEN REAL_ARITH_TAC; ALL_TAC] THEN
+   SUBGOAL_THEN `!w. w IN ball(Cx(&0),r) ==> f (u * g w) / u = w`
+     ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC FIRST_CARTAN_THM_DIM_1 THEN
+    EXISTS_TAC `ball(Cx(&0),r)` THEN EXISTS_TAC `Cx(&0)` THEN
+    ASM_REWRITE_TAC [OPEN_BALL;CONNECTED_BALL;BOUNDED_BALL;
+                    COMPLEX_MUL_RZERO; CENTRE_IN_BALL] THEN
+    ASSERT_TAC `!z. norm (u * z) = norm z` THENL
+    [ASM_REWRITE_TAC [COMPLEX_NORM_MUL; REAL_MUL_LID]; ALL_TAC] THEN
+    ASSERT_TAC `!z. z IN ball(Cx(&0),r) ==> u * z IN ball(Cx(&0),r)` THENL
+    [ASM_REWRITE_TAC [COMPLEX_IN_BALL_0]; ALL_TAC] THEN
+    ASSERT_TAC `!z. z IN ball(Cx(&0),r) ==> z / u IN ball(Cx(&0),r)` THENL
+    [ASM_REWRITE_TAC [COMPLEX_IN_BALL_0; COMPLEX_NORM_DIV; REAL_DIV_1];
+     ALL_TAC] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN CONJ_TAC THENL
+    [MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN CONJ_TAC THENL
+     [ALL_TAC; ASM_REWRITE_TAC[HOLOMORPHIC_ON_CONST]] THEN
+     SUBGOAL_THEN `(\w:complex. f (u * g w) : complex) = f o (\w. u * g w)`
+       SUBST1_TAC THENL
+     [REWRITE_TAC [o_DEF]; MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE_GEN] THEN
+     EXISTS_TAC `ball(Cx(&0),r)` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HOLOMORPHIC_ON_MUL THEN
+      ASM_REWRITE_TAC[HOLOMORPHIC_ON_CONST];
+      ASM_SIMP_TAC[]];
+     ALL_TAC] THEN
+    CONJ_TAC THENL
+    [REWRITE_TAC [complex_div; COMPLEX_MUL_LZERO]; ALL_TAC] THEN
+    SUBGOAL_THEN `Cx(&1) = u / u` SUBST1_TAC THENL
+    [ASM_SIMP_TAC [COMPLEX_DIV_REFL]; ALL_TAC] THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_CDIV_AT THEN
+    SUBGOAL_THEN `(\w:complex. f (u * g w) : complex) = f o (\w. u * g w)`
+    SUBST1_TAC THENL [REWRITE_TAC [o_DEF]; ALL_TAC] THEN
+    SUBGOAL_THEN
+    `((\w. f (u * g w)) has_complex_derivative
+      complex_derivative f (u * g(Cx(&0))) *
+      (u * complex_derivative g (Cx(&0))))
+     (at (Cx (&0)))` MP_TAC THENL
+    [MATCH_MP_TAC (REWRITE_RULE [o_DEF]
+      (SPECL [`\w:complex. u * g(w):complex`; `f:complex->complex`]
+      COMPLEX_DIFF_CHAIN_AT)) THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_LMUL_AT THEN
+      REWRITE_TAC [HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT THEN
+      EXISTS_TAC `ball(Cx(&0),r)` THEN
+      ASM_REWRITE_TAC[OPEN_BALL; CENTRE_IN_BALL];
+      REWRITE_TAC [HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT THEN
+      EXISTS_TAC `ball(Cx(&0),r)` THEN
+      ASM_REWRITE_TAC[OPEN_BALL; CENTRE_IN_BALL; COMPLEX_MUL_RZERO]];
+     SUBGOAL_THEN
+       `complex_derivative f (u * g (Cx (&0))) *
+        (u * complex_derivative g (Cx (&0))) = u`
+       SUBST1_TAC THENL
+     [ALL_TAC; REWRITE_TAC[o_DEF]] THEN
+     ABBREV_TAC `g' = complex_derivative g (Cx(&0))` THEN
+     ABBREV_TAC `f' = complex_derivative f (Cx(&0))` THEN
+     SUBGOAL_THEN `f' * g' = Cx(&1)` ASSUME_TAC THENL
+     [EXPAND_TAC "g'" THEN EXPAND_TAC "f'" THEN
+      SUBGOAL_THEN `complex_derivative g (Cx(&0)) =
+                    complex_derivative g (f (Cx(&0)))` SUBST1_TAC THENL
+      [ASM_REWRITE_TAC [];
+       MATCH_MP_TAC COMPLEX_DERIVATIVE_LEFT_INVERSE THEN
+       EXISTS_TAC `ball(Cx(&0),r)` THEN EXISTS_TAC `ball(Cx(&0),r)` THEN
+       ASM_REWRITE_TAC [OPEN_BALL; CENTRE_IN_BALL]];
+      ASM_REWRITE_TAC [COMPLEX_MUL_RZERO] THEN
+      POP_ASSUM MP_TAC THEN CONV_TAC COMPLEX_RING]];
+    SUBGOAL_THEN `f(u*g(z)) = f (g (u * z)) : complex` MP_TAC THENL
+    [MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `u * z:complex` THEN CONJ_TAC THENL
+     [SUBGOAL_THEN `!x y:complex. x / u = y ==> x = u * y` MATCH_MP_TAC THENL
+      [REWRITE_TAC [complex_div] THEN GEN_TAC THEN GEN_TAC THEN
+       DISCH_THEN (SUBST1_TAC o GSYM) THEN
+       SUBGOAL_THEN `x = (inv u * u) * x` MP_TAC THENL
+       [ASM_SIMP_TAC [COMPLEX_MUL_LINV; COMPLEX_MUL_LID];
+        REWRITE_TAC [COMPLEX_MUL_AC]];
+       POP_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC []];
+      MATCH_MP_TAC EQ_SYM THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REWRITE_TAC [COMPLEX_IN_BALL_0; COMPLEX_NORM_MUL; REAL_MUL_LID] THEN
+      ASM_REWRITE_TAC [GSYM COMPLEX_IN_BALL_0]];
+     DISCH_TAC THEN SUBGOAL_THEN
+       `g (f (u * g z)) = g (f (g (u * z : complex))) : complex` MP_TAC THENL
+     [POP_ASSUM SUBST1_TAC THEN REWRITE_TAC [];
+      SUBGOAL_THEN `u * g z IN ball (Cx(&0),r) /\ u * z IN ball(Cx(&0),r)`
+      MP_TAC THENL
+      [ASM_REWRITE_TAC [COMPLEX_IN_BALL_0; COMPLEX_NORM_MUL; REAL_MUL_LID] THEN
+       REWRITE_TAC [GSYM COMPLEX_IN_BALL_0] THEN ASM_SIMP_TAC[];
+       ASM_SIMP_TAC[]]]]];
+   SUBGOAL_THEN `?c. !z. z IN ball(Cx(&0),r) ==> g z = c * z`
+     STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC LEMMA_1 THEN
+    ASM_SIMP_TAC [OPEN_BALL; CONNECTED_BALL; CENTRE_IN_BALL] THEN
+    SIMP_TAC [COMPLEX_IN_BALL_0; COMPLEX_NORM_MUL; REAL_MUL_LID];
+    ALL_TAC] THEN
+   SUBGOAL_THEN `norm (c:complex) = &1` ASSUME_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC [COMPLEX_NORM_EQ_1_CEXP]] THEN
+   SUBGOAL_THEN `~(norm (c:complex) = &0)` ASSUME_TAC THENL
+   [REWRITE_TAC [COMPLEX_NORM_ZERO] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `Cx(&0) = Cx(r / &2)` MP_TAC THENL
+    [ALL_TAC; REWRITE_TAC [CX_INJ] THEN ASM_REAL_ARITH_TAC] THEN
+    SUBGOAL_THEN `Cx(r / &2) IN ball(Cx(&0),r)` ASSUME_TAC THENL
+    [REWRITE_TAC [COMPLEX_IN_BALL_0; CX_DIV; COMPLEX_NORM_DIV;
+                  COMPLEX_NORM_NUM] THEN
+     REWRITE_TAC [COMPLEX_NORM_CX] THEN ASM_REAL_ARITH_TAC;
+     EQ_TRANS_TAC `g (f (Cx(r / &2)):complex):complex` THENL
+     [EQ_TRANS_TAC `c * (f (Cx(r / &2)):complex)` THENL
+      [ASM_REWRITE_TAC [COMPLEX_MUL_LZERO]; ASM_MESON_TAC[]];
+      ASM_MESON_TAC[]]];
+    ALL_TAC] THEN SUBGOAL_THEN `&0 < norm (c:complex)` ASSUME_TAC THENL
+   [POP_ASSUM MP_TAC THEN CONV_TAC NORM_ARITH; ALL_TAC] THEN
+    REWRITE_TAC [GSYM REAL_LE_ANTISYM] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC LEMMA_2 THEN EXISTS_TAC `r : real` THEN
+    ASM_REWRITE_TAC [NORM_POS_LE] THEN GEN_TAC THEN STRIP_TAC THEN
+    ABBREV_TAC `p = Cx x` THEN
+    SUBGOAL_THEN `x = norm (p:complex)` SUBST_ALL_TAC THENL
+    [EXPAND_TAC "p" THEN REWRITE_TAC [COMPLEX_NORM_CX] THEN
+     ASM_REAL_ARITH_TAC;
+     REWRITE_TAC [GSYM COMPLEX_NORM_MUL] THEN
+     SUBGOAL_THEN `c * p = g p` SUBST1_TAC THENL
+     [ALL_TAC; ASM_MESON_TAC [COMPLEX_IN_BALL_0]] THEN
+     FIRST_X_ASSUM (MATCH_MP_TAC o GSYM) THEN
+     ASM_MESON_TAC [COMPLEX_IN_BALL_0]];
+    ALL_TAC] THEN
+   SUBST1_TAC (GSYM (SPEC `norm (c:complex)` REAL_INV_INV)) THEN
+   MATCH_MP_TAC REAL_INV_1_LE THEN CONJ_TAC THENL
+   [ASM_MESON_TAC [REAL_LT_INV]; ALL_TAC] THEN
+   MATCH_MP_TAC LEMMA_2 THEN EXISTS_TAC `r:real` THEN ASM_REWRITE_TAC [] THEN
+   CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_LE_INV THEN ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+   GEN_TAC THEN STRIP_TAC THEN
+   SUBGOAL_THEN `x = norm (g (f (Cx x):complex):complex)` SUBST1_TAC THENL
+   [SUBGOAL_THEN `g (f (Cx x):complex) = Cx x` SUBST1_TAC THENL
+    [FIRST_X_ASSUM MATCH_MP_TAC THEN
+     REWRITE_TAC [COMPLEX_IN_BALL_0; COMPLEX_NORM_CX] THEN
+     ASM_REAL_ARITH_TAC;
+     REWRITE_TAC [COMPLEX_NORM_CX] THEN ASM_REAL_ARITH_TAC];
+    SUBGOAL_THEN `g (f (Cx x):complex) = c * f (Cx x) : complex`
+      SUBST1_TAC THENL
+    [FIRST_X_ASSUM MATCH_MP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+     REWRITE_TAC [COMPLEX_IN_BALL_0; COMPLEX_NORM_CX] THEN
+     ASM_REAL_ARITH_TAC;
+     REWRITE_TAC [COMPLEX_NORM_MUL; REAL_MUL_ASSOC] THEN
+     ASM_SIMP_TAC [REAL_MUL_LINV; REAL_MUL_LID; GSYM COMPLEX_IN_BALL_0] THEN
+     FIRST_X_ASSUM MATCH_MP_TAC THEN
+     REWRITE_TAC [COMPLEX_IN_BALL_0; COMPLEX_NORM_CX] THEN
+     ASM_REAL_ARITH_TAC]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Cauchy's inequality.                                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_INEQUALITY = prove
+ (`!f z r (B:real) n.
+     f continuous_on cball(z,r) /\
+     f holomorphic_on ball(z,r) /\ &0 < r /\
+     (!x:complex. norm(z-x) = r ==> norm(f x) <= B)
+     ==> norm (higher_complex_derivative n f z) <= &(FACT n) * B / r pow n`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN `&0 <= B` ASSUME_TAC THENL
+  [SUBGOAL_THEN `?x:complex. norm (z-x) = r` STRIP_ASSUME_TAC THENL [
+  EXISTS_TAC `z + Cx r` THEN ASM_SIMP_TAC[COMPLEX_ADD_SUB2;NORM_NEG;
+  COMPLEX_NORM_CX;REAL_ABS_REFL;REAL_LT_IMP_LE];ALL_TAC] THEN
+  ASM_MESON_TAC [NORM_POS_LE;REAL_LE_TRANS];
+  SUBGOAL_THEN `norm ((Cx(&2) * Cx pi * ii) / Cx(&(FACT n))
+          * higher_complex_derivative n f z)
+    <= (B / r pow (n + 1)) * &2 * pi * r` MP_TAC THENL[
+  MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_CIRCLEPATH THEN
+  EXISTS_TAC `\u. (f:complex->complex) u / (u - z) pow (n + 1)` THEN
+  EXISTS_TAC `z:complex` THEN CONJ_TAC THENL [MATCH_MP_TAC
+  CAUCHY_HAS_PATH_INTEGRAL_HIGHER_DERIVATIVE_CIRCLEPATH THEN
+  ASM_SIMP_TAC [CENTRE_IN_BALL]; ALL_TAC] THEN CONJ_TAC THENL
+  [MATCH_MP_TAC REAL_LE_DIV THEN ASM_SIMP_TAC
+  [REAL_POW_LE;REAL_LT_IMP_LE];ALL_TAC]THEN ASM_REWRITE_TAC []
+  THEN GEN_TAC THEN DISCH_TAC THEN
+  ASM_REWRITE_TAC [COMPLEX_NORM_DIV;COMPLEX_NORM_POW] THEN MATCH_MP_TAC
+  REAL_LE_TRANS THEN EXISTS_TAC `B:real / r pow (n+1)` THEN
+  ASM_SIMP_TAC[ REAL_LE_DIV2_EQ; REAL_POW_LT;NORM_SUB;REAL_LE_REFL];
+  REWRITE_TAC[COMPLEX_NORM_DIV;COMPLEX_NORM_MUL; COMPLEX_NORM_II;
+  COMPLEX_NORM_CX; REAL_ABS_NUM; REAL_ABS_PI; REAL_MUL_RID;REAL_ABS_NUM]
+  THEN SUBGOAL_THEN `B / r pow (n + 1) * &2 * pi * r =
+                (&2 * pi) / &(FACT n) * (((&(FACT n) * B) * r/ r pow (n+1)))`
+  SUBST1_TAC THENL [SUBGOAL_THEN `~(&(FACT n) = &0)` MP_TAC THENL
+  [REWRITE_TAC [FACT_NZ;REAL_OF_NUM_EQ];ALL_TAC]
+  THEN CONV_TAC REAL_FIELD;SUBGOAL_THEN `&0 < (&2 * pi) / &(FACT n)` ASSUME_TAC
+  THENL[MATCH_MP_TAC REAL_LT_DIV THEN SIMP_TAC[FACT_LT;REAL_OF_NUM_LT] THEN
+  MP_TAC PI_POS THEN REAL_ARITH_TAC;SUBGOAL_THEN `(&(FACT n) * B) * r / r pow
+  (n + 1) = &(FACT n) * B / r pow n` SUBST1_TAC THENL
+  [REWRITE_TAC[GSYM ADD1; real_pow] THEN MP_TAC (ASSUME `&0 < r`) THEN
+  CONV_TAC REAL_FIELD; ASM_MESON_TAC [REAL_LE_LCANCEL_IMP]]]]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A holomorphic function f has only isolated zeros unless f is 0.           *)
+(* ------------------------------------------------------------------------- *)
+
+let ISOLATED_ZEROS = prove
+ (`!f a z w.
+     open a /\ connected a /\ f holomorphic_on a /\ z IN a /\ f z = Cx(&0) /\
+     w IN a /\ ~(f w = Cx(&0))
+     ==> (?r. &0 < r /\ ball(z,r) SUBSET a /\
+              (!w. w IN ball(z,r) /\ ~(w=z) ==> ~(f w = Cx(&0))))`,
+  REPEAT STRIP_TAC THEN ASSERT_TAC `?k.
+         ~(higher_complex_derivative k f z = Cx(&0)) /\
+         (!n. n < k ==> higher_complex_derivative n f z = Cx(&0))` THENL
+  [EXISTS_TAC `minimal n. (~(higher_complex_derivative n f z = Cx(&0)))`
+  THEN SUBGOAL_THEN `?k'. ~(higher_complex_derivative k' f z = Cx(&0))`
+  (fun th-> ASM_MESON_TAC[th;MINIMAL]) THEN REWRITE_TAC[GSYM NOT_FORALL_THM]
+  THEN STRIP_TAC THEN ASM_MESON_TAC[HOLOMORPHIC_FUN_EQ_0_ON_CONNECTED];
+  ALL_TAC] THEN SUBGOAL_THEN `~(k = 0)`ASSUME_TAC THENL
+  [STRIP_TAC THEN MP_TAC(ASSUME `~(higher_complex_derivative k f z = Cx(&0))`)
+  THEN ASM_MESON_TAC[higher_complex_derivative];
+  STRIP_ASSUME_TAC (MESON [OPEN_CONTAINS_BALL;ASSUME `open (a:complex->bool)`;
+  ASSUME `z:complex IN a`] `?s. &0 < s /\ ball (z:complex,s) SUBSET a`)
+  THEN ASSUME_TAC (MESON [HOLOMORPHIC_POWER_SERIES;
+  ASSUME `f holomorphic_on a`;ASSUME `ball (z:complex,s)
+  SUBSET a`;HOLOMORPHIC_ON_SUBSET] `!w:complex. w IN ball(z,s) ==>
+  ((\n. higher_complex_derivative n f z / Cx(&(FACT n))*(w -z) pow n) sums f w)
+  (from 0)`) THEN ASSERT_TAC `?g:complex->complex. !x:complex.
+                x IN ball(z,s) ==>
+        (((\n. higher_complex_derivative n f z / Cx(&(FACT n)) *
+          (x - z) pow (n-k))) sums g x) (from k)` THENL
+  [EXISTS_TAC `\x:complex. lim sequentially
+  (\m. vsum (k..m) (\n. higher_complex_derivative n f z / Cx(&(FACT n)) *
+  (x - z) pow (n-k)))` THEN GEN_TAC THEN DISCH_TAC THEN
+  SUBGOAL_THEN `!m. k..m = (0..m) INTER from k` ASSUME_TAC THENL
+  [REWRITE_TAC[EXTENSION; IN_FROM; IN_INTER; IN_ELIM_THM; IN_NUMSEG] THEN
+  ARITH_TAC;ASM_REWRITE_TAC[] THEN REWRITE_TAC
+  [SET_RULE `!m. (0..m) INTER from k = from k INTER (0..m)`;SUMS_LIM]] THEN
+  ASM_CASES_TAC `x:complex = z` THENL
+  [ASM_REWRITE_TAC[COMPLEX_SUB_REFL;summable] THEN
+  EXISTS_TAC `higher_complex_derivative k f z / Cx(&(FACT k))` THEN
+  MATCH_MP_TAC SUMS_EQ THEN EXISTS_TAC `\n. if n = k then
+  higher_complex_derivative k f z / Cx(&(FACT k)) else Cx(&0)`
+  THEN CONJ_TAC THENL [REWRITE_TAC [IN_FROM] THEN GEN_TAC THEN DISCH_TAC
+  THEN COND_CASES_TAC THENL
+  [ASM_REWRITE_TAC[COMPLEX_POW_ZERO;SUB_REFL;COMPLEX_MUL_RID];
+  ASM_SIMP_TAC[COMPLEX_POW_ZERO; ARITH_RULE `k <= x' /\ ~(x' = k) ==>
+  ~(x' - k = 0)`;COMPLEX_MUL_RZERO]]; MATCH_MP_TAC SERIES_VSUM THEN
+  EXISTS_TAC `{k:num}` THEN SIMP_TAC [FINITE_SING;from;IN_SING;
+  COMPLEX_VEC_0;VSUM_SING] THEN SET_TAC[LE_REFL]];
+  MATCH_MP_TAC SUMMABLE_EQ THEN EXISTS_TAC
+  `\n. higher_complex_derivative n f z / Cx(&(FACT n)) *
+  (x - z) pow n / (x-z) pow k` THEN CONJ_TAC THENL [REWRITE_TAC [IN_FROM]
+  THEN GEN_TAC THEN DISCH_TAC THEN SUBGOAL_THEN `(x:complex - z) pow (x' - k)
+  = (x - z) pow x' / (x - z) pow k` (fun th->
+  REWRITE_TAC[th;COMPLEX_EQ_MUL_LCANCEL]) THEN MATCH_MP_TAC
+  COMPLEX_DIV_POW THEN ASM_SIMP_TAC [COMPLEX_SUB_0];
+  SUBGOAL_THEN `(\n. higher_complex_derivative n f z / Cx(&(FACT n)) *
+  (x - z) pow n / (x - z) pow k) = (\n. (higher_complex_derivative n f z /
+  Cx(&(FACT n)) *(x - z) pow n) / (x - z) pow k) ` SUBST1_TAC
+  THENL [REWRITE_TAC [FUN_EQ_THM] THEN GEN_TAC THEN CONV_TAC COMPLEX_FIELD;
+  MATCH_MP_TAC SUMMABLE_COMPLEX_DIV THEN MATCH_MP_TAC SUMMABLE_FROM_ELSEWHERE
+  THEN EXISTS_TAC `0` THEN ASM_MESON_TAC[summable]]]];ALL_TAC] THEN
+  ASSERT_TAC `~(g (z:complex) = Cx(&0)) /\
+  (!x. x IN ball(z,s) ==> f x = (x - z) pow k * g(x))` THENL
+  [CONJ_TAC THENL [MATCH_MP_TAC
+  (COMPLEX_FIELD `!x y:complex. x = y /\ ~(y= Cx(&0)) ==> ~(x=Cx(&0))`) THEN
+  EXISTS_TAC `higher_complex_derivative k f z / Cx(&(FACT k))` THEN
+  CONJ_TAC THENL [ONCE_REWRITE_TAC [GSYM COMPLEX_SUB_0] THEN
+  MATCH_MP_TAC SERIES_UNIQUE THEN EXISTS_TAC
+  `(\n. higher_complex_derivative n f z / Cx(&(FACT n)) *
+  Cx(&0) pow (n-k))` THEN EXISTS_TAC `from (k +1)` THEN
+  CONJ_TAC THENL [SUBST1_TAC (MESON [VSUM_SING_NUMSEG]
+  `higher_complex_derivative k f z / Cx(&(FACT k)) =
+  vsum (k..k) (\n. higher_complex_derivative n f z / Cx(&(FACT n))) `)
+  THEN SUBGOAL_THEN  `vsum (k..k)  (\n. higher_complex_derivative n f z
+  / Cx(&(FACT n))) = vsum (k..((k+1)-1)) (\n. higher_complex_derivative n f z
+  / Cx(&(FACT n)) * Cx(&0) pow (n - k))` SUBST1_TAC THENL [
+  REWRITE_TAC[VSUM_SING_NUMSEG; COMPLEX_POW_ZERO;SUB_REFL;COMPLEX_MUL_RID;
+  ARITH_RULE `((k:num) + 1) -1 = k`];
+  MATCH_MP_TAC SUMS_OFFSET THEN ASM_REWRITE_TAC[ARITH_RULE `k:num < k+1`]
+  THEN POP_ASSUM (MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[CENTRE_IN_BALL;COMPLEX_SUB_REFL]];MATCH_MP_TAC
+  SUMS_COMPLEX_0 THEN GEN_TAC THEN SIMP_TAC [IN_FROM;COMPLEX_POW_ZERO;
+  ARITH_RULE `k + 1 <= n <=> ~(n-k= 0)`;COMPLEX_MUL_RZERO]];
+  MATCH_MP_TAC (COMPLEX_FIELD `!x y. ~(x = Cx(&0)) /\ ~(y = Cx(&0))
+  ==> ~(x / y = Cx(&0))`) THEN ASM_REWRITE_TAC[GSYM COMPLEX_NORM_ZERO] THEN
+  SUBST1_TAC (MESON [COMPLEX_NORM_CX]
+  `norm (Cx(&(FACT k))) = abs ((&(FACT k)))`) THEN
+  SIMP_TAC [REAL_ABS_ZERO;FACT_LT;REAL_OF_NUM_LT;REAL_LT_IMP_NZ]]; ALL_TAC]
+  THEN GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC SERIES_UNIQUE THEN
+  EXISTS_TAC `(\n. higher_complex_derivative n f z / Cx(&(FACT n)) *
+  (x - z) pow n)`THEN EXISTS_TAC `(from 0)` THEN
+  CONJ_TAC  THENL [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[];
+  ASM_CASES_TAC `x:complex = z` THENL [
+  ASM_REWRITE_TAC[COMPLEX_SUB_REFL] THEN MATCH_MP_TAC SUMS_EQ THEN
+  EXISTS_TAC `\n:num. Cx(&0)` THEN  CONJ_TAC THENL
+  [REWRITE_TAC[IN_FROM;COMPLEX_POW_ZERO] THEN X_GEN_TAC `n:num` THEN
+  DISCH_TAC THEN  COND_CASES_TAC THENL [
+  ASM_REWRITE_TAC[higher_complex_derivative] THEN CONV_TAC COMPLEX_FIELD;
+  REWRITE_TAC[COMPLEX_MUL_RZERO]];
+  ASM_REWRITE_TAC[COMPLEX_POW_ZERO;COMPLEX_MUL_LZERO] THEN
+  ASM_REWRITE_TAC[SERIES_0;GSYM COMPLEX_VEC_0]];ALL_TAC] THEN
+  MATCH_MP_TAC SUMS_EQ THEN EXISTS_TAC `\n.(x-z) pow k *
+  higher_complex_derivative n f z / Cx(&(FACT n)) *(x - z) pow (n - k)`
+  THEN CONJ_TAC THENL [REWRITE_TAC[IN_FROM] THEN X_GEN_TAC `n:num`
+  THEN DISCH_TAC THEN ASM_CASES_TAC `n:num < k` THENL [ASM_SIMP_TAC[]
+  THEN CONV_TAC COMPLEX_FIELD;
+  SUBGOAL_THEN `(x:complex-z) pow (n-k) = (x-z) pow n / (x-z) pow k`
+  SUBST1_TAC THENL [MATCH_MP_TAC COMPLEX_DIV_POW THEN
+  ASM_SIMP_TAC[COMPLEX_SUB_0; ARITH_RULE `~(n:num < k) ==> k <= n`];
+  SUBST1_TAC (COMPLEX_FIELD `(x - z) pow k *
+     higher_complex_derivative n f z / Cx(&(FACT n)) *
+     (x - z) pow n / (x - z) pow k =
+         higher_complex_derivative n f z / Cx(&(FACT n)) * (x-z) pow k *
+     (x - z) pow n / (x - z) pow k`) THEN MESON_TAC [ASSUME `~(x:complex = z)`;
+  COMPLEX_DIV_LMUL;COMPLEX_SUB_0;COMPLEX_POW_EQ_0]]];
+  MATCH_MP_TAC SERIES_COMPLEX_LMUL THEN SUBST1_TAC
+  (MESON [COMPLEX_ADD_RID] `(g:complex->complex) x = g x + Cx(&0)`) THEN
+  SUBGOAL_THEN `Cx(&0) = vsum (0.. (k-1))
+  (\n. higher_complex_derivative n f z / Cx(&(FACT n)) * (x - z) pow (n - k))`
+  SUBST1_TAC THENL [ONCE_REWRITE_TAC[EQ_SYM_EQ] THEN
+  REWRITE_TAC [GSYM COMPLEX_VEC_0] THEN MATCH_MP_TAC VSUM_EQ_0 THEN
+  REWRITE_TAC [IN_NUMSEG] THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[ARITH_RULE ` ~(k = 0) /\ n <= k - 1 ==> n < k`] THEN
+  REWRITE_TAC[COMPLEX_VEC_0] THEN CONV_TAC COMPLEX_FIELD;
+  MATCH_MP_TAC SUMS_OFFSET_REV THEN
+  ASM_SIMP_TAC[ARITH_RULE `0 <= k /\ ~(k = 0) ==> 0 < k`;LE_0]]]];ALL_TAC] THEN
+  ASSERT_TAC `?r. &0 < r /\ (!x:complex. dist (z,x) < r ==>
+                ~((g:complex->complex) x = Cx(&0)))` THENL [
+  MATCH_MP_TAC CONTINUOUS_ON_OPEN_AVOID THEN
+  EXISTS_TAC `ball(z:complex, s)` THEN
+  ASM_REWRITE_TAC[OPEN_BALL;CENTRE_IN_BALL]
+  THEN MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON THEN
+  MATCH_MP_TAC ANALYTIC_IMP_HOLOMORPHIC THEN MATCH_MP_TAC POWER_SERIES_ANALYTIC
+  THEN EXISTS_TAC `\n. higher_complex_derivative (n+k) f z / Cx(&(FACT (n+k)))`
+  THEN EXISTS_TAC `from 0` THEN REWRITE_TAC[] THEN GEN_TAC THEN DISCH_TAC
+  THEN REWRITE_TAC[SERIES_FROM] THEN MATCH_MP_TAC LIM_TRANSFORM THEN
+  EXISTS_TAC `(\n.vsum (k..(k+n))
+  (\n. higher_complex_derivative n f z / Cx(&(FACT n)) *(w' - z) pow (n-k)))`
+  THEN CONJ_TAC THENL [SIMP_TAC [VSUM_OFFSET_0;ARITH_RULE
+  `!k n :num.(k + n) - k = n`; ARITH_RULE `!k n:num. k <= k + n`;ADD_ASSOC;
+  ARITH_RULE `!k n :num.(n + k) - k = n`] THEN
+  SUBGOAL_THEN `(\x. vsum (0..x) (\i. higher_complex_derivative (i + k)
+         f z / Cx(&(FACT (i + k))) * (w' - z) pow i)
+         - vsum (0..x) (\n. higher_complex_derivative (n + k) f z
+        / Cx(&(FACT (n + k))) * (w' - z) pow n)) = (\x. Cx(&0))`
+        (fun th-> SIMP_TAC[th;COMPLEX_VEC_0;LIM_CONST]) THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN REWRITE_TAC[COMPLEX_SUB_0];
+  SUBGOAL_THEN `(\n. vsum (k..k + n)
+  (\n. higher_complex_derivative n f z / Cx(&(FACT n)) *(w' - z) pow (n - k)))
+  = (\n. vsum (k..n+k)(\n. higher_complex_derivative n f z / Cx(&(FACT n)) *
+  (w' - z) pow (n - k)))` SUBST1_TAC THENL [
+  REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN REWRITE_TAC[ADD_SYM];
+  MP_TAC (ISPECL [`(\n. vsum (k..n)
+        (\n. higher_complex_derivative n f z / Cx(&(FACT n)) *
+        (w' - z) pow (n - k)))`;`(g:complex->complex) w'`;`k:num`]
+  SEQ_OFFSET) THEN ONCE_REWRITE_TAC[GSYM SERIES_FROM] THEN ASM_SIMP_TAC[]]];
+  ALL_TAC] THEN EXISTS_TAC `min r s` THEN CONJ_TAC THENL
+  [MP_TAC (CONJ (ASSUME `&0 < r`) (ASSUME `&0 < s`)) THEN REAL_ARITH_TAC;
+  CONJ_TAC THENL [REWRITE_TAC[real_min] THEN COND_CASES_TAC
+  THENL [MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `ball(z:complex,s)`
+  THEN ASM_REWRITE_TAC[ball] THEN SET_TAC[ASSUME `r:real <= s`;REAL_LTE_TRANS];
+  ASM_REWRITE_TAC[]];GEN_TAC THEN STRIP_TAC THEN
+  SUBGOAL_THEN `(f:complex->complex) w' =
+                (w' - z) pow k * (g:complex->complex) w'` SUBST1_TAC
+   THENL [FIRST_ASSUM MATCH_MP_TAC THEN
+  MP_TAC (ASSUME `w':complex IN ball (z,min r s)`) THEN REWRITE_TAC [real_min]
+  THEN COND_CASES_TAC THENL [ASM_MESON_TAC[IN_BALL;REAL_LTE_TRANS];
+  REWRITE_TAC[]];SIMP_TAC [COMPLEX_ENTIRE;DE_MORGAN_THM] THEN
+  CONJ_TAC THENL  [REWRITE_TAC[COMPLEX_POW_EQ_0;DE_MORGAN_THM]
+  THEN DISJ1_TAC THEN ASM_REWRITE_TAC [COMPLEX_SUB_0];
+  FIRST_X_ASSUM MATCH_MP_TAC THEN MP_TAC (ASSUME `w':complex IN
+  ball (z,min r s)`) THEN REWRITE_TAC [real_min] THEN COND_CASES_TAC
+  THENL [REWRITE_TAC[IN_BALL];
+  ASM_MESON_TAC[REAL_NOT_LE;IN_BALL;REAL_LT_TRANS]]]]]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Analytic continuation.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let ANALYTIC_CONTINUATION = prove
+ (`!f a u z.
+     open a /\ connected a /\ f holomorphic_on a /\ u SUBSET a /\ z IN a /\
+     z limit_point_of u /\ (!w. w IN u ==> f w = Cx(&0))
+     ==> (!w. w IN a ==> f w = Cx(&0))`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  REWRITE_TAC[TAUT ` (p ==> q) <=> ~( p /\ (~ q))`;GSYM NOT_EXISTS_THM]
+  THEN STRIP_TAC THEN SUBGOAL_THEN  `(f:complex->complex) z = Cx(&0)`
+  ASSUME_TAC THENL [STRIP_ASSUME_TAC(MESON [OPEN_CONTAINS_CBALL;
+  ASSUME `open (a:complex->bool)`; ASSUME `z:complex IN a`]
+  `?e. &0 < e /\ cball (z:complex,e) SUBSET a`) THEN ABBREV_TAC
+  `s = cball(z:complex,e) INTER (u:complex->bool)` THEN
+  ASSERT_TAC `f:complex->complex continuous_on closure s /\
+                (!x:complex. x IN s ==> f x = Cx(&0)) /\
+                z:complex IN closure s`
+  THENL [CONJ_TAC THENL [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+  EXISTS_TAC `a:complex->bool` THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON] THEN MATCH_MP_TAC
+  SUBSET_TRANS THEN EXISTS_TAC `cball(z:complex,e)` THEN
+  ASM_MESON_TAC[CLOSED_CBALL;INTER_SUBSET;CLOSURE_MINIMAL];
+  CONJ_TAC THENL [ASM_MESON_TAC[INTER_SUBSET;SUBSET];
+  ASM_SIMP_TAC[closure;IN_UNION] THEN DISJ2_TAC THEN SUBGOAL_THEN
+  `z:complex limit_point_of s` (fun thm-> SET_TAC[thm]) THEN
+  REWRITE_TAC [LIMPT_APPROACHABLE] THEN GEN_TAC THEN DISCH_TAC THEN
+  ASSERT_TAC `?x:complex. x IN u /\ ~(x = z) /\ dist (x , z) < min e' e`
+  THENL [MP_TAC (ISPECL [`z:complex`;`u:complex->bool`] LIMPT_APPROACHABLE)
+  THEN ASM_SIMP_TAC[REAL_LT_MIN];EXISTS_TAC `x:complex` THEN ASM_REWRITE_TAC[]
+  THEN CONJ_TAC THENL
+  [REWRITE_TAC [GSYM (ASSUME `cball (z:complex,e) INTER u = s`);IN_INTER;
+  ASSUME `x:complex IN u`;IN_CBALL] THEN ASM_MESON_TAC[REAL_LT_IMP_LE;
+  REAL_LT_MIN;DIST_SYM]; ASM_MESON_TAC [REAL_LT_MIN]]]]];
+  ASM_MESON_TAC [CONTINUOUS_CONSTANT_ON_CLOSURE]];
+  MP_TAC(SPECL [`f:complex->complex`;`a:complex->bool`;`z:complex`;`w:complex`]
+  ISOLATED_ZEROS) THEN ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `?x:complex. x IN ball(z,r) /\ x IN u /\ ~(x=z) /\
+    (f:complex->complex) x = Cx(&0)`(fun thm->ASM_MESON_TAC[thm]) THEN
+  MP_TAC (ISPECL [`z:complex`;`u:complex->bool`] LIMPT_APPROACHABLE) THEN
+  ASM_REWRITE_TAC [] THEN DISCH_TAC THEN POP_ASSUM (MP_TAC o SPEC `r:real`)
+  THEN ASM_REWRITE_TAC [] THEN STRIP_TAC THEN EXISTS_TAC `x':complex`
+  THEN ASM_MESON_TAC[IN_BALL;DIST_SYM]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Open mapping theorem.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let OPEN_MAPPING_THM = prove
+  (`!a f.
+     open a /\ connected a /\ f holomorphic_on a /\
+     ~(?c:complex. !z:complex. z IN a ==> f z = c)
+     ==> (!u. open u /\ u SUBSET a ==> open(IMAGE f u))`,
+  let LEMMA_ZERO = prove
+  (`!f z r. f continuous_on cball(z,r) /\ f holomorphic_on ball(z,r) /\
+      &0 < r /\ (!w. norm(z-w) =r ==> norm(f z) < norm(f w))
+      ==> (?w. w IN ball(z,r) /\ f w = Cx(&0))`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN  ` ((!x:complex. x IN ball(z,r) ==>
+  ~((f:complex->complex) x = Cx(&0))) ==> F ) ==> ( ?w:complex. w IN ball(z,r)
+  /\ f w = Cx(&0))` MATCH_MP_TAC THENL [MESON_TAC[];
+  STRIP_TAC THEN SUBGOAL_THEN `&0 < norm ((f:complex->complex) z)` ASSUME_TAC
+  THENL [ASM_SIMP_TAC[COMPLEX_NORM_NZ; CENTRE_IN_BALL; SPEC `z:complex`
+  (ASSUME`!x:complex. x IN ball(z,r) ==> ~((f:complex->complex) x = Cx(&0))`)];
+  ALL_TAC] THEN SUBGOAL_THEN
+    `(!x:complex. x IN cball(z,r) ==> ~((f:complex->complex) x = Cx(&0)))`
+  ASSUME_TAC THENL [GEN_TAC THEN REWRITE_TAC [IN_CBALL;dist]
+  THEN REWRITE_TAC[REAL_ARITH `a <= b <=> a < b \/ a = b`] THEN
+  REWRITE_TAC [TAUT `((p \/ q) ==> r ) <=> ((p ==> r ) /\ (q ==> r))`] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[IN_BALL;dist];
+  DISCH_TAC THEN REWRITE_TAC[GSYM COMPLEX_NORM_ZERO] THEN MATCH_MP_TAC
+  REAL_LT_IMP_NZ THEN MATCH_MP_TAC REAL_LT_TRANS THEN EXISTS_TAC
+  `norm ((f:complex->complex) z)` THEN
+  ASM_SIMP_TAC [SPEC `z':complex` (ASSUME `!w:complex. norm (w - z) = r
+                ==> norm ((f:complex->complex) z) < norm (f w)`)]];
+  ALL_TAC] THEN SUBGOAL_THEN `~(frontier(cball(z:complex,r))={})` ASSUME_TAC
+  THENL [REWRITE_TAC[FRONTIER_CBALL;sphere;dist] THEN SUBGOAL_THEN `?x:complex.
+  norm(z-x) = r` (fun th-> SET_TAC [MEMBER_NOT_EMPTY;th]) THEN EXISTS_TAC
+  `z + Cx r` THEN ASM_SIMP_TAC[COMPLEX_ADD_SUB2;NORM_NEG;COMPLEX_NORM_CX;
+  REAL_ABS_REFL;REAL_LT_IMP_LE];ALL_TAC] THEN
+  ABBREV_TAC `g = \z. inv ((f:complex->complex) z)` THEN ASSERT_TAC
+  `(g:complex->complex) continuous_on cball(z,r) /\ g holomorphic_on ball(z,r)`
+   THENL [CONJ_TAC THENL [EXPAND_TAC "g" THEN
+   REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN GEN_TAC THEN DISCH_TAC
+  THEN MATCH_MP_TAC CONTINUOUS_COMPLEX_INV_WITHIN THEN ASM_MESON_TAC
+  [CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN];EXPAND_TAC "g" THEN MATCH_MP_TAC
+  HOLOMORPHIC_ON_INV THEN ASM_REWRITE_TAC[]];ALL_TAC] THEN
+  SUBGOAL_THEN `?w:complex. w IN frontier(cball(z,r)) /\
+                (!x:complex. x IN frontier(cball(z,r)) ==>
+                norm ((f:complex->complex) w) <= norm (f x))`
+  STRIP_ASSUME_TAC THENL [MATCH_MP_TAC CONTINUOUS_ATTAINS_INF
+  THEN ASM_SIMP_TAC[COMPACT_FRONTIER;COMPACT_CBALL;CBALL_EQ_EMPTY;
+  REAL_ARITH `!r:real. &0 < r ==> ~(r < &0)` ] THEN
+  SUBGOAL_THEN `lift o (\x. norm ((f:complex->complex) x)) =
+                 (lift o norm) o (\x. f x) ` SUBST1_TAC THENL
+  [REWRITE_TAC[o_DEF]; MATCH_MP_TAC CONTINUOUS_ON_COMPOSE
+  THEN CONJ_TAC THENL [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC
+  `cball(z:complex,r)` THEN ASM_REWRITE_TAC[ETA_AX] THEN
+  ASM_SIMP_TAC[SUBSET_TRANS;CLOSED_CBALL;FRONTIER_SUBSET_CLOSED];
+  ASM_MESON_TAC [CONTINUOUS_ON_LIFT_NORM; HOLOMORPHIC_ON_SUBSET;
+  HOLOMORPHIC_ON_IMP_CONTINUOUS_ON;SUBSET_TRANS;CLOSED_CBALL;
+  FRONTIER_SUBSET_CLOSED]]];ALL_TAC] THEN
+  SUBGOAL_THEN `?w:complex. norm (z-w) = r /\
+                norm ((f:complex->complex) w) <= norm (f z)`
+                (fun thm -> ASM_MESON_TAC[thm;REAL_NOT_LE])
+  THEN EXISTS_TAC `w:complex` THEN CONJ_TAC
+  THENL [MP_TAC (ASSUME `w:complex IN frontier (cball (z,r))`) THEN
+  REWRITE_TAC[FRONTIER_CBALL;sphere;dist] THEN SET_TAC[];ALL_TAC] THEN
+  SUBGOAL_THEN `&0 < norm ((f:complex->complex) w)` ASSUME_TAC THENL
+  [REWRITE_TAC[NORM_POS_LT;COMPLEX_VEC_0] THEN MATCH_MP_TAC (ASSUME `!x.
+  x:complex IN cball (z,r) ==> ~(f x = Cx(&0))`) THEN MATCH_MP_TAC
+  (SET_RULE `!x:complex u s. x IN u /\ u SUBSET s ==> x IN s `) THEN
+  EXISTS_TAC `frontier(cball(z:complex,r))` THEN
+  ASM_SIMP_TAC[CLOSED_CBALL;FRONTIER_SUBSET_CLOSED];ALL_TAC] THEN
+  SUBGOAL_THEN `inv (norm ((f:complex-> complex) w)) = &1/ (norm (f w))`
+  ASSUME_TAC THENL [MATCH_MP_TAC REAL_MUL_RINV_UNIQ THEN MATCH_MP_TAC
+  REAL_DIV_LMUL THEN ASM_REWRITE_TAC[COMPLEX_NORM_ZERO;GSYM COMPLEX_NORM_NZ];
+  ASSERT_TAC `?x:complex. x IN frontier(cball(z,r)) /\ (!y. y IN
+  frontier(cball(z,r)) ==> norm ((g:complex->complex) y) <= norm (g x))`
+  THENL [MATCH_MP_TAC CONTINUOUS_ATTAINS_SUP THEN
+  ASM_SIMP_TAC[COMPACT_FRONTIER;
+  COMPACT_CBALL;CBALL_EQ_EMPTY; REAL_ARITH `!r:real. &0 < r ==> ~(r < &0)`]
+  THEN SUBGOAL_THEN `lift o (\x. norm ((g:complex->complex) x)) =
+                          (lift o norm) o (\x. g x) ` SUBST1_TAC
+  THENL [REWRITE_TAC[o_DEF]; MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  CONJ_TAC THENL [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+  EXISTS_TAC `cball(z:complex,r)` THEN ASM_REWRITE_TAC[ETA_AX]
+  THEN ASM_SIMP_TAC[SUBSET_TRANS;CLOSED_CBALL;
+  FRONTIER_SUBSET_CLOSED]; ASM_MESON_TAC [CONTINUOUS_ON_LIFT_NORM;
+  HOLOMORPHIC_ON_SUBSET; HOLOMORPHIC_ON_IMP_CONTINUOUS_ON;SUBSET_TRANS;
+  CLOSED_CBALL; FRONTIER_SUBSET_CLOSED]]];ALL_TAC] THEN SUBGOAL_THEN
+  `&0 < norm ((f:complex->complex) x)` ASSUME_TAC THENL
+  [REWRITE_TAC[NORM_POS_LT;COMPLEX_VEC_0] THEN MATCH_MP_TAC
+  (ASSUME `!x. x:complex IN cball (z,r) ==> ~(f x = Cx(&0))`)
+  THEN MATCH_MP_TAC (SET_RULE `!x:complex u s. x IN u /\ u SUBSET s
+                ==> x IN s `) THEN  EXISTS_TAC `frontier(cball(z:complex,r))`
+  THEN ASM_SIMP_TAC[CLOSED_CBALL;FRONTIER_SUBSET_CLOSED];
+  ABBREV_TAC `B = norm ((g:complex->complex) x)`
+  THEN SUBGOAL_THEN `norm (higher_complex_derivative 0 g z) <=
+                (&(FACT 0)) * B / (r pow 0) `
+  MP_TAC THENL[MATCH_MP_TAC CAUCHY_INEQUALITY THEN
+  ASM_REWRITE_TAC[] THEN MP_TAC
+  (ASSUME `!y:complex. y IN frontier (cball (z,r)) ==>
+                 norm ((g:complex ->complex) y) <= B`)
+  THEN SIMP_TAC [FRONTIER_CBALL;sphere;dist] THEN SET_TAC[];
+  REWRITE_TAC [higher_complex_derivative;FACT;real_pow;
+  REAL_MUL_LID;REAL_DIV_1] THEN DISCH_TAC THEN SUBGOAL_THEN
+        `inv (norm ((f:complex->complex) z)) <=
+        inv (norm (f w)) ==> norm (f w) <= norm (f z)` MATCH_MP_TAC
+  THENL [SUBGOAL_THEN `inv (norm ((f:complex-> complex) z)) =
+                         &1/ (norm (f z))` SUBST1_TAC
+  THENL [MATCH_MP_TAC REAL_MUL_RINV_UNIQ THEN MATCH_MP_TAC REAL_DIV_LMUL THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 < norm ((f:complex->complex) z) ==>
+  ~(norm (f z) = &0) `]; ASM_REWRITE_TAC[] THEN DISCH_TAC THEN SUBST1_TAC
+  (REAL_ARITH `norm ((f:complex->complex) w)= &1 * norm (f w)`) THEN
+   SUBST1_TAC(REAL_ARITH `norm ((f:complex->complex) z)=
+                        &1 * norm (f z)`) THEN POP_ASSUM
+  MP_TAC THEN MATCH_MP_TAC (TAUT `(p <=> q ) ==> ( p ==> q)`)
+  THEN MATCH_MP_TAC RAT_LEMMA4 THEN ASM_REWRITE_TAC[]];
+  REWRITE_TAC[GSYM COMPLEX_NORM_INV] THEN
+  SUBGOAL_THEN `inv ((f:complex->complex) z) = g z /\ inv (f w) = g w`
+                (fun thm -> REWRITE_TAC[thm])
+  THENL [ASM_MESON_TAC[];MATCH_MP_TAC (REAL_ARITH
+  `!x y z:real. x <= y /\ y = z ==> x <= z`) THEN  EXISTS_TAC `B:real` THEN
+  ASM_REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN CONJ_TAC THENL [EXPAND_TAC "B"
+  THEN REWRITE_TAC[SYM (ASSUME`(\z. inv ((f:complex->complex) z)) =
+  g`);COMPLEX_NORM_INV] THEN SUBGOAL_THEN `inv (norm ((f:complex->complex) x))
+  = &1 / norm (f x)` (fun thm -> REWRITE_TAC[thm]) THENL [MATCH_MP_TAC
+  REAL_MUL_RINV_UNIQ THEN MATCH_MP_TAC REAL_DIV_LMUL THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_NZ]; ASM_REWRITE_TAC[] THEN
+  MP_TAC (SPEC `x:complex`(ASSUME`!x:complex. x IN frontier (cball (z,r))
+                ==> norm ((f:complex->complex) w) <= norm (f x)`))
+  THEN REWRITE_TAC [ASSUME`x:complex IN frontier
+  (cball (z,r))`] THEN SUBST1_TAC
+  (REAL_ARITH `norm ((f:complex->complex) w)= &1* norm (f w)`) THEN
+  SUBST1_TAC (REAL_ARITH `norm ((f:complex->complex) x)= &1 * norm (f x)`)
+  THEN  DISCH_TAC THEN REWRITE_TAC[REAL_MUL_LID] THEN POP_ASSUM
+  MP_TAC THEN MATCH_MP_TAC (TAUT `(q <=> p ) ==> ( p ==> q)`) THEN MATCH_MP_TAC
+  (RAT_LEMMA4) THEN ASM_REWRITE_TAC[]];ASM_MESON_TAC[]]]]]]]]) in
+  REPEAT STRIP_TAC THEN ASSUME_TAC (MESON [HOLOMORPHIC_ON_SUBSET;
+  ASSUME `(u:complex->bool) SUBSET a`;ASSUME `f holomorphic_on a`]
+  `f holomorphic_on u`) THEN ASM_CASES_TAC `(u:complex->bool)={}` THENL [
+  ASM_MESON_TAC[SUBSET_EMPTY;IMAGE_EQ_EMPTY;OPEN_EMPTY];ALL_TAC] THEN
+  SUBGOAL_THEN `!f u. ~(u={}) /\ open u /\ connected u /\
+                 f holomorphic_on u /\
+         ~(?c:complex. !z:complex. z IN u ==> f z=c) ==>
+                         open (IMAGE f u)` ASSUME_TAC
+  THENL [REPEAT STRIP_TAC THEN REWRITE_TAC[OPEN_CONTAINS_BALL;IN_IMAGE]
+  THEN GEN_TAC THEN STRIP_TAC THEN
+  ASSERT_TAC `(\z:complex.(f':complex->complex)z - f' x') holomorphic_on
+  (u':complex->bool) /\ (\z:complex. f' z - f' x')x' = Cx(&0)` THENL [
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_CONST;HOLOMORPHIC_ON_SUB;
+  BETA_THM;COMPLEX_SUB_REFL];ALL_TAC] THEN
+  ASSERT_TAC `?s:real. &0 < s /\ ball(x',s) SUBSET u' /\
+        (!z:complex. z IN ball(x',s) /\ ~(z = x') ==>
+        ~((\z:complex.(f':complex->complex)z - f' x') z = Cx(&0)))` THENL [
+  MATCH_MP_TAC ISOLATED_ZEROS THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[COMPLEX_SUB_0];
+  ASSERT_TAC `?r. &0 < r /\ cball(x':complex,r) SUBSET ball(x',s)` THENL[
+  EXISTS_TAC `s:real / &2` THEN ASM_SIMP_TAC [REAL_ARITH `&0 < s
+  ==> &0 < s/ &2`;SUBSET;IN_CBALL;IN_BALL] THEN MP_TAC (ASSUME `&0 < s`)
+  THEN REAL_ARITH_TAC;ALL_TAC] THEN
+  ASSERT_TAC `cball(x',r) SUBSET u' /\
+     (!z:complex. z IN cball(x',r) /\
+        ~(z=x')==> ~((\z:complex.(f':complex->complex)z - f' x') z = Cx(&0)))`
+  THENL [CONJ_TAC THENL [ASM_MESON_TAC[SUBSET_TRANS];
+  MESON_TAC[ASSUME `!z:complex. z IN ball (x',s) /\ ~(z = x')
+  ==> ~((\z. (f':complex->complex) z - f' x') z = Cx(&0))`;
+  ASSUME `cball (x':complex,r) SUBSET ball (x',s)`;SUBSET]];ALL_TAC]
+  THEN SUBGOAL_THEN `frontier (cball (x':complex,r)) SUBSET u'` ASSUME_TAC
+  THENL [MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `cball(x':complex,r)`
+  THEN ASM_MESON_TAC[CLOSED_CBALL;FRONTIER_SUBSET_CLOSED];ALL_TAC] THEN
+  ASSERT_TAC `?w. w IN frontier(cball(x':complex,r)) /\
+        (!z. z IN frontier(cball(x',r)) ==>
+        norm ((f':complex->complex)w - f' x') <= norm(f' z - f' x'))`
+  THENL [MATCH_MP_TAC CONTINUOUS_ATTAINS_INF THEN
+  ASM_SIMP_TAC[COMPACT_FRONTIER;COMPACT_CBALL;CBALL_EQ_EMPTY;
+  REAL_ARITH `!r:real. &0 < r ==> ~(r < &0)` ] THEN
+  CONJ_TAC THENL [REWRITE_TAC[REWRITE_RULE[sphere] FRONTIER_CBALL;dist] THEN
+  SUBGOAL_THEN `?x:complex. norm(x'-x) = r` (fun th-> SET_TAC
+   [MEMBER_NOT_EMPTY;th]) THEN EXISTS_TAC `x' + Cx r` THEN
+  ASM_SIMP_TAC[COMPLEX_ADD_SUB2;NORM_NEG;COMPLEX_NORM_CX;
+  REAL_ABS_REFL;REAL_LT_IMP_LE];
+  SUBGOAL_THEN `lift o (\z. norm ((f':complex->complex) z - f' x')) =
+        (lift o norm) o (\z. f' z - f' x') ` SUBST1_TAC THENL [
+  REWRITE_TAC[o_DEF]; MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  ASM_MESON_TAC [CONTINUOUS_ON_LIFT_NORM; HOLOMORPHIC_ON_SUBSET;
+  HOLOMORPHIC_ON_IMP_CONTINUOUS_ON]]];ALL_TAC] THEN
+  ABBREV_TAC `e = (norm ((f':complex->complex) w - f' x'))*(&1/ &3)`
+  THEN SUBGOAL_THEN `&0<e` ASSUME_TAC THENL [
+  EXPAND_TAC "e" THEN MATCH_MP_TAC REAL_LT_MUL THEN
+  REWRITE_TAC [REAL_ARITH `&0 < &1 / &3`; COMPLEX_NORM_NZ] THEN
+  SUBST1_TAC (MESON [BETA_THM] `(f':complex->complex) w - f' x' =
+  (\w. f' w - f' x')w `) THEN FIRST_ASSUM MATCH_MP_TAC THEN
+  CONJ_TAC THENL[MESON_TAC[ASSUME `w:complex IN frontier (cball (x',r))`;
+  FRONTIER_SUBSET_CLOSED; CLOSED_CBALL;SET_RULE `!x:complex s t. x IN s /\
+  s SUBSET t ==> x IN t` ];ONCE_REWRITE_TAC[GSYM COMPLEX_SUB_0] THEN
+  REWRITE_TAC[GSYM COMPLEX_NORM_ZERO] THEN MATCH_MP_TAC REAL_LT_IMP_NZ
+  THEN MATCH_MP_TAC (REAL_ARITH `&0 < r /\ r = norm (w:complex - x') ==>
+  &0 < norm (w - x')`) THEN ASM_REWRITE_TAC[] THEN
+  MP_TAC (ASSUME `w:complex IN frontier (cball (x',r))`) THEN
+  SIMP_TAC[FRONTIER_CBALL; sphere; dist; IN_ELIM_THM; NORM_SUB]];
+      ALL_TAC]
+  THEN EXISTS_TAC `e:real` THEN REWRITE_TAC[ASSUME `&0<e`] THEN
+  REWRITE_TAC[SUBSET;IN_IMAGE] THEN GEN_TAC THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC [GSYM COMPLEX_SUB_0] THEN
+  SUBGOAL_THEN `(?x:complex. x IN ball(x',r) /\
+        x'' - (f':complex->complex) x = Cx(&0)) ==>
+                ?x. x'' - f' x = Cx(&0) /\ x IN u'` MATCH_MP_TAC THENL [
+  STRIP_TAC THEN EXISTS_TAC `x''':complex` THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC (SET_RULE `!x:complex u s. x IN u /\ u SUBSET s ==> x IN s`)
+  THEN EXISTS_TAC `ball(x':complex,r)` THEN ASM_REWRITE_TAC[]
+  THEN ASM_MESON_TAC[BALL_SUBSET_CBALL;SUBSET_TRANS];
+  MATCH_MP_TAC LEMMA_ZERO THEN CONJ_TAC THENL
+  [MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON THEN
+  MATCH_MP_TAC HOLOMORPHIC_ON_SUB THEN ASM_MESON_TAC
+  [HOLOMORPHIC_ON_CONST; HOLOMORPHIC_ON_SUBSET];
+  CONJ_TAC THENL [MATCH_MP_TAC HOLOMORPHIC_ON_SUB THEN ASM_MESON_TAC[
+  HOLOMORPHIC_ON_CONST;HOLOMORPHIC_ON_SUBSET;BALL_SUBSET_CBALL];
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `w':complex` THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LTE_TRANS THEN
+  EXISTS_TAC  `e:real` THEN CONJ_TAC THENL
+  [MESON_TAC [NORM_SUB;dist;IN_BALL; ASSUME`x'':complex IN ball (x,e)`;
+  ASSUME `x:complex = (f':complex->complex) x'`];
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `&2*e` THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0<e ==> e <= &2 * e`;NORM_SUB] THEN
+  SUBST1_TAC (COMPLEX_RING `(f':complex->complex) w' - x'' =
+                 f' w' -x + x - x''`) THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `norm ((f':complex->complex) w' - x) - norm (x-x'')` THEN
+  CONJ_TAC THENL [SUBST1_TAC (REAL_ARITH `&2 * e = &3 *e - e`) THEN
+  MATCH_MP_TAC (REAL_ARITH `!x y z w:real. x<=y /\ z<w ==> x-w <= y-z`)
+  THEN CONJ_TAC THENL [EXPAND_TAC "e" THEN
+  ASM_REWRITE_TAC[REAL_ARITH `&3 * norm ((f':complex->complex) w - f' x') *
+  &1 / &3 = norm (f' w - f' x')`] THEN FIRST_ASSUM MATCH_MP_TAC THEN
+  POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[FRONTIER_CBALL; sphere; NORM_SUB; IN_ELIM_THM; dist];
+  UNDISCH_TAC `x'':complex IN ball (x,e)` THEN
+  REWRITE_TAC [IN_BALL;dist;ASSUME`x:complex = (f':complex->complex) x'`]];
+  MATCH_MP_TAC (REAL_ARITH `!x y z:real. x<=y+z ==> x-z<=y`) THEN
+  REWRITE_TAC[COMPLEX_NORM_TRIANGLE_SUB]]]]]]];ALL_TAC] THEN
+  ASM_CASES_TAC `connected (u:complex->bool)` THENL [
+  SUBGOAL_THEN `~(?c:complex. !z:complex. z IN u ==> f z=c)`
+          (fun th-> ASM_MESON_TAC [th]) THEN
+  ONCE_REWRITE_TAC[GSYM COMPLEX_SUB_0]
+  THEN STRIP_TAC THEN ABBREV_TAC `w:complex= CHOICE u` THEN
+  ASSUME_TAC (MESON [CHOICE_DEF;GSYM (ASSUME `CHOICE u = w:complex`);
+  ASSUME `~(u:complex->bool = {})`] `w:complex IN u`) THEN
+  ASSERT_TAC `w:complex limit_point_of u` THENL
+  [MATCH_MP_TAC INTERIOR_LIMIT_POINT THEN ASM_SIMP_TAC [INTERIOR_OPEN];
+  SUBGOAL_THEN `(\z. (f:complex->complex) z - c) holomorphic_on a` ASSUME_TAC
+  THENL [ASM_SIMP_TAC [HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_CONST];
+  ASSUME_TAC (MESON [ASSUME `w:complex IN u`;ASSUME `u:complex->bool SUBSET a`;
+  SET_RULE `w:complex IN u /\ u SUBSET a ==> w IN a`] `w:complex IN a`) THEN
+  MP_TAC(SPECL [`\z:complex.(f:complex->complex)z - c`;
+        `a:complex->bool`; `u:complex->bool`; `w:complex`]
+         ANALYTIC_CONTINUATION) THEN
+  ASM_REWRITE_TAC [] THEN MP_TAC (ASSUME `~(?c:complex. !z. z IN a ==>
+  (f:complex->complex) z = c)`) THEN ONCE_REWRITE_TAC [GSYM COMPLEX_SUB_0;
+  GSYM COMPLEX_SUB_RZERO] THEN ONCE_REWRITE_TAC [COMPLEX_SUB_RZERO] THEN
+  MESON_TAC[]]];ALL_TAC] THEN SUBST1_TAC (MESON [UNIONS_COMPONENTS]
+  `u:complex->bool = UNIONS ( components u)`) THEN
+  REWRITE_TAC [IMAGE_UNIONS] THEN MATCH_MP_TAC OPEN_UNIONS THEN
+  REWRITE_TAC[IN_IMAGE] THEN GEN_TAC THEN STRIP_TAC THEN
+  FIRST_X_ASSUM SUBST1_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  STRIP_ASSUME_TAC(MESON [IN_COMPONENTS;
+  ASSUME `(x:complex->bool) IN components u`]
+  `?w:complex. w IN u /\ x = connected_component u w`) THEN
+  ASM_SIMP_TAC[CONNECTED_COMPONENT_EQ_EMPTY;OPEN_CONNECTED_COMPONENT;
+  CONNECTED_CONNECTED_COMPONENT] THEN CONJ_TAC THENL
+  [ASM_MESON_TAC [CONNECTED_COMPONENT_SUBSET;
+  HOLOMORPHIC_ON_SUBSET]; ONCE_REWRITE_TAC[GSYM COMPLEX_SUB_0] THEN
+  STRIP_TAC THEN ABBREV_TAC `y = CHOICE (x:complex->bool)` THEN
+  SUBGOAL_THEN `y:complex IN x` ASSUME_TAC THENL
+  [EXPAND_TAC "y" THEN MATCH_MP_TAC CHOICE_DEF THEN
+  ASM_MESON_TAC [CONNECTED_COMPONENT_EQ_EMPTY];
+  ASSUME_TAC (MESON [OPEN_COMPONENTS;ASSUME `open (u:complex->bool)`;
+  ASSUME` x:complex->bool IN components u`] `open (x:complex->bool)`) THEN
+  ASSERT_TAC `y:complex limit_point_of x` THENL [
+  MATCH_MP_TAC INTERIOR_LIMIT_POINT THEN ASSUME_TAC
+  (MESON [OPEN_COMPONENTS;ASSUME `open (u:complex->bool)`;
+  ASSUME` x:complex->bool IN components u`] `open (x:complex->bool)`) THEN
+  SIMP_TAC [INTERIOR_OPEN;ASSUME `open (x:complex->bool)`;
+  ASSUME `y:complex IN x`]; SUBGOAL_THEN `(\z. (f:complex->complex) z - c)
+  holomorphic_on a` ASSUME_TAC THENL [
+  ASM_SIMP_TAC [HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_CONST];
+  SUBGOAL_THEN `x:complex->bool SUBSET a` ASSUME_TAC THENL [
+  MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `u:complex->bool` THEN
+  ASM_REWRITE_TAC[CONNECTED_COMPONENT_SUBSET];
+  SUBGOAL_THEN `y:complex IN a` ASSUME_TAC THENL [
+  MATCH_MP_TAC (SET_RULE `y:complex IN x /\ x SUBSET a ==> y IN a`)
+  THEN ASM_REWRITE_TAC[]; MP_TAC(SPECL [`\z:complex.(f:complex->complex)z - c`;
+  `a:complex->bool`; `x:complex->bool`; `y:complex`] ANALYTIC_CONTINUATION)
+  THEN ASM_REWRITE_TAC [] THEN MP_TAC (ASSUME `~(?c:complex. !z. z IN a ==>
+  (f:complex->complex) z = c)`) THEN
+  ONCE_REWRITE_TAC [GSYM COMPLEX_SUB_0;GSYM COMPLEX_SUB_RZERO] THEN
+  ONCE_REWRITE_TAC [COMPLEX_SUB_RZERO] THEN MESON_TAC[]]]]]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Maximum modulus principle.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let MAXIMUM_MODULUS_PRINCIPLE = prove
+  (`!f a u w.
+      open a /\ connected a /\ f holomorphic_on a /\
+      open u /\ u SUBSET a /\ w IN u /\
+      (!z. z IN u ==> norm(f z) <= norm(f w))
+      ==> (?c. !z. z IN a ==> f z = c)`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+    `~(open (IMAGE (f:complex->complex) u))`
+    (fun th -> ASM_MESON_TAC[th; OPEN_MAPPING_THM]) THEN
+  REWRITE_TAC[OPEN_CONTAINS_BALL;NOT_FORALL_THM] THEN
+  EXISTS_TAC `(f:complex->complex) w` THEN
+  MATCH_MP_TAC (TAUT `!p q. (p /\ ~ q) ==> ~(p ==> q)`) THEN CONJ_TAC THENL
+  [ASM_MESON_TAC[IN_IMAGE]; ALL_TAC] THEN
+  REWRITE_TAC[NOT_EXISTS_THM;DE_MORGAN_THM;SUBSET] THEN
+  GEN_TAC THEN ASM_CASES_TAC `~(&0 < e)` THENL
+  [ASM_REWRITE_TAC[]; ALL_TAC] THEN POP_ASSUM MP_TAC THEN REWRITE_TAC[] THEN
+  DISCH_TAC THEN DISJ2_TAC THEN REWRITE_TAC[NOT_FORALL_THM] THEN
+  EXISTS_TAC `if &0 < Re((f:complex->complex) w)
+              then f w + Cx(e / &2)
+              else f w - Cx(e/ &2) ` THEN
+  ABBREV_TAC `x = if &0<Re((f:complex->complex) w)
+                  then f w + Cx(e / &2)
+                  else f w - Cx(e / &2)` THEN
+  MATCH_MP_TAC (TAUT `!p q. (p /\ ~ q) ==> ~(p ==> q)`) THEN CONJ_TAC THENL
+  [REWRITE_TAC[IN_BALL;dist] THEN
+  MATCH_MP_TAC (REAL_ARITH `!x y z:real. x = y /\ y < z ==> x < z `) THEN
+  EXISTS_TAC `e / &2` THEN EXPAND_TAC "x" THEN COND_CASES_TAC THENL
+  [ASM_SIMP_TAC [NORM_NEG;COMPLEX_ADD_SUB2;REAL_ARITH `&0 < e ==> e / &2 <e`;
+                  COMPLEX_NORM_CX;REAL_ABS_REFL;
+                  REAL_ARITH `&0 < e ==> &0 <= e / &2`];
+  ASM_SIMP_TAC [COMPLEX_SUB_SUB2; REAL_ARITH `&0 < e ==> e / &2 <e`;
+                  COMPLEX_NORM_CX; REAL_ABS_REFL;
+                  REAL_ARITH `&0 < e ==> &0 <= e / &2`]]; ALL_TAC] THEN
+  REWRITE_TAC[IN_IMAGE; NOT_EXISTS_THM; DE_MORGAN_THM] THEN
+  GEN_TAC THEN ASM_CASES_TAC `~(x':complex IN u)` THENL
+  [ASM_REWRITE_TAC[]; ALL_TAC] THEN DISJ1_TAC THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[] THEN DISCH_TAC THEN
+  MATCH_MP_TAC (NORM_ARITH `!x y:complex. ~(norm x=norm y) ==> ~(x=y)`) THEN
+  REWRITE_TAC[REAL_NOT_EQ] THEN DISJ2_TAC THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `norm ((f:complex->complex) w)` THEN ASM_SIMP_TAC[] THEN
+  EXPAND_TAC "x" THEN COND_CASES_TAC THEN
+  REWRITE_TAC [complex_norm;RE_ADD;IM_ADD; IM_CX;RE_CX;REAL_ADD_RID] THENL
+  [MATCH_MP_TAC SQRT_MONO_LT THEN CONJ_TAC THENL
+  [SIMP_TAC[REAL_ARITH `!x:real. x pow 2 = x*x`;
+               REAL_LE_SQUARE;REAL_LE_ADD]; ALL_TAC] THEN
+  MATCH_MP_TAC (REAL_ARITH `!x:real y z. x < y ==> x + z < y + z`) THEN
+  REWRITE_TAC[GSYM REAL_LT_SQUARE_ABS] THEN
+  ASM_SIMP_TAC [REAL_ARITH `!x y. &0 < x /\ &0 < y
+                          ==> abs (x+y) = abs x + abs y`;
+                REAL_ARITH `!x:real. &0 < x ==> &0 < x / &2`] THEN
+  ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC [complex_norm;RE_SUB;IM_SUB; IM_CX;RE_CX;REAL_SUB_RZERO] THEN
+  MATCH_MP_TAC SQRT_MONO_LT THEN CONJ_TAC THENL
+  [SIMP_TAC[REAL_LE_SQUARE; REAL_LE_ADD;
+                REAL_ARITH `!x:real. x pow 2 = x*x`]; ALL_TAC] THEN
+  MATCH_MP_TAC (REAL_ARITH `!x:real y z. x < y ==> x + z < y + z`) THEN
+  REWRITE_TAC[GSYM REAL_LT_SQUARE_ABS] THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[REAL_NOT_LT] THEN DISCH_TAC THEN
+  ASM_SIMP_TAC [REAL_ARITH `!x y. x <= &0 /\ &0 < y
+                            ==> abs (x - y) = abs x + abs y`;
+              REAL_ARITH `!x. &0 < x ==> &0 < x/ &2`] THEN
+  ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Factoring out a zero according to its order.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let HOLOMORPHIC_FACTOR_ORDER_OF_ZERO = prove
+ (`!f s n.
+      open s /\ z IN s /\ f holomorphic_on s /\
+      0 < n /\ ~(higher_complex_derivative n f z = Cx(&0)) /\
+      (!m. 0 < m /\ m < n ==> higher_complex_derivative m f z = Cx(&0))
+      ==> ?g r. &0 < r /\
+                g holomorphic_on ball(z,r) /\
+                (!w. w IN ball(z,r) ==> f(w) - f(z) = (w - z) pow n * g(w)) /\
+                (!w. w IN ball(z,r) ==> ~(g w = Cx(&0)))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `!w. w IN ball(z,r)
+        ==> ((\m. higher_complex_derivative m f z / Cx(&(FACT m)) *
+                  (w - z) pow m) sums f(w) - f(z)) (from n)`
+  ASSUME_TAC THENL
+   [GEN_TAC THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`f:complex->complex`; `z:complex`; `w:complex`; `r:real`]
+        HOLOMORPHIC_POWER_SERIES) THEN ASM_REWRITE_TAC[] THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET]; ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o SPEC `1` o
+      MATCH_MP (REWRITE_RULE[IMP_CONJ] SUMS_OFFSET)) THEN
+    CONV_TAC NUM_REDUCE_CONV THEN REWRITE_TAC[VSUM_SING_NUMSEG] THEN
+    REWRITE_TAC[FACT; higher_complex_derivative; COMPLEX_DIV_1] THEN
+    REWRITE_TAC[complex_pow; COMPLEX_MUL_RID] THEN
+    ASM_CASES_TAC `n = 1` THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o SPEC `n:num` o
+      MATCH_MP (REWRITE_RULE[IMP_CONJ] SUMS_OFFSET)) THEN
+    ANTS_TAC THENL [ASM_ARITH_TAC; MATCH_MP_TAC EQ_IMP] THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN MATCH_MP_TAC(COMPLEX_RING
+     `p = Cx(&0) ==> w - z - p = w - z`) THEN
+    REWRITE_TAC[GSYM COMPLEX_VEC_0] THEN MATCH_MP_TAC VSUM_EQ_0 THEN
+    REWRITE_TAC[IN_NUMSEG; COMPLEX_VEC_0] THEN REPEAT STRIP_TAC THEN
+    REWRITE_TAC[COMPLEX_ENTIRE; complex_div] THEN REPEAT DISJ1_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  ABBREV_TAC
+   `g = \w. infsum (from 0)
+                   (\m. higher_complex_derivative (m + n) f z /
+                        Cx(&(FACT(m + n))) * (w - z) pow m)` THEN
+  SUBGOAL_THEN
+   `!w. w IN ball(z,r)
+        ==> ((\m. higher_complex_derivative (m + n) f z /
+                  Cx(&(FACT(m + n))) * (w - z) pow m)
+             sums g(w)) (from 0)`
+  (LABEL_TAC "*") THENL
+   [REPEAT STRIP_TAC THEN EXPAND_TAC "g" THEN REWRITE_TAC[SUMS_INFSUM] THEN
+    ASM_CASES_TAC `w:complex = z` THENL
+     [MATCH_MP_TAC SUMMABLE_FROM_ELSEWHERE THEN EXISTS_TAC `1` THEN
+      MATCH_MP_TAC SUMMABLE_EQ THEN EXISTS_TAC `\n:num. Cx(&0)` THEN
+      REWRITE_TAC[SUMMABLE_0; GSYM COMPLEX_VEC_0] THEN
+      ASM_SIMP_TAC[IN_FROM; COMPLEX_VEC_0; COMPLEX_SUB_REFL;
+                   COMPLEX_POW_ZERO; LE_1; COMPLEX_MUL_RZERO];
+      SUBGOAL_THEN
+       `!x:complex m. x * (w - z) pow m =
+                      (x * (w - z) pow (m + n)) / (w - z) pow n`
+       (fun th -> ONCE_REWRITE_TAC[th])
+      THENL
+       [REPEAT GEN_TAC THEN
+        SIMP_TAC[complex_div; GSYM COMPLEX_MUL_ASSOC; COMPLEX_POW_ADD] THEN
+        ASM_SIMP_TAC[COMPLEX_MUL_RINV; COMPLEX_POW_EQ_0; COMPLEX_SUB_0] THEN
+        REWRITE_TAC[COMPLEX_MUL_RID];
+        MATCH_MP_TAC SUMMABLE_COMPLEX_DIV THEN
+        MP_TAC(GEN `a:num->complex`
+          (ISPECL [`n:num`; `a:num->complex`] SUMMABLE_REINDEX)) THEN
+        DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN
+        REWRITE_TAC[summable; ADD_CLAUSES] THEN ASM_MESON_TAC[]]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `g holomorphic_on ball(z,r)` ASSUME_TAC THENL
+   [MATCH_MP_TAC POWER_SERIES_HOLOMORPHIC THEN
+    EXISTS_TAC `\m. higher_complex_derivative (m + n) f z /
+                    Cx(&(FACT (m + n)))` THEN
+    EXISTS_TAC `from 0` THEN ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!w. w IN ball(z,r) ==> f w - f z = (w - z) pow n * g(w)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC SERIES_UNIQUE THEN
+    EXISTS_TAC `\m. higher_complex_derivative m f z / Cx(&(FACT m)) *
+                    (w - z) pow m` THEN
+    EXISTS_TAC `from n` THEN ASM_SIMP_TAC[] THEN
+    GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [ARITH_RULE `n = 0 + n`] THEN
+    REWRITE_TAC[GSYM SUMS_REINDEX] THEN REWRITE_TAC[COMPLEX_POW_ADD] THEN
+    ONCE_REWRITE_TAC[COMPLEX_RING `a * b * c:complex = c * a * b`] THEN
+    MATCH_MP_TAC SERIES_COMPLEX_LMUL THEN ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  EXISTS_TAC `g:complex->complex` THEN
+  SUBGOAL_THEN `(g:complex->complex) continuous_on ball(z,r)` MP_TAC THENL
+   [ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON]; ALL_TAC] THEN
+  REWRITE_TAC[continuous_on] THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[CENTRE_IN_BALL] THEN DISCH_THEN(MP_TAC o SPEC
+   `norm((g:complex->complex) z)`) THEN
+  ANTS_TAC THENL
+   [REMOVE_THEN "*" (MP_TAC o SPEC `z:complex`) THEN
+    ASM_REWRITE_TAC[CENTRE_IN_BALL] THEN
+    DISCH_THEN(MP_TAC o SPEC `1` o
+      MATCH_MP (REWRITE_RULE[IMP_CONJ] SUMS_OFFSET)) THEN
+    CONV_TAC NUM_REDUCE_CONV THEN REWRITE_TAC[VSUM_SING_NUMSEG] THEN
+    DISCH_THEN(MP_TAC o SPEC `Cx(&0)` o
+        MATCH_MP(REWRITE_RULE[IMP_CONJ] SERIES_UNIQUE)) THEN
+    REWRITE_TAC[complex_pow; ADD_CLAUSES; COMPLEX_MUL_RID] THEN ANTS_TAC THENL
+     [REWRITE_TAC[GSYM COMPLEX_VEC_0] THEN MATCH_MP_TAC SUMS_0 THEN
+      SIMP_TAC[IN_FROM; LE_1; COMPLEX_SUB_REFL; COMPLEX_POW_ZERO] THEN
+      REWRITE_TAC[COMPLEX_VEC_0; COMPLEX_MUL_RZERO];
+      SIMP_TAC[COMPLEX_SUB_0; NORM_POS_LT] THEN DISCH_THEN(K ALL_TAC) THEN
+      ASM_REWRITE_TAC[COMPLEX_VEC_0; complex_div; COMPLEX_ENTIRE] THEN
+      REWRITE_TAC[COMPLEX_INV_EQ_0; CX_INJ; REAL_OF_NUM_EQ; FACT_NZ]];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `min d r:real` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+  SUBGOAL_THEN `ball(z,min d r) SUBSET ball(z:complex,r)` ASSUME_TAC THENL
+   [SIMP_TAC[SUBSET_BALL; REAL_ARITH `min d r <= r`]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+  REWRITE_TAC[IN_BALL; REAL_LT_MIN; GSYM COMPLEX_VEC_0] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_BALL]) THEN
+  ASM_MESON_TAC[DIST_SYM; NORM_ARITH `dist(x,y) < norm y ==> ~(x = vec 0)`]);;
+
+let HOLOMORPHIC_FACTOR_ORDER_OF_ZERO_STRONG = prove
+ (`!f s n z.
+      open s /\ z IN s /\ f holomorphic_on s /\
+      0 < n /\ ~(higher_complex_derivative n f z = Cx(&0)) /\
+      (!m. 0 < m /\ m < n ==> higher_complex_derivative m f z = Cx(&0))
+      ==> ?g r. &0 < r /\
+                g holomorphic_on ball(z,r) /\
+                (!w. w IN ball(z,r)
+                     ==> f(w) - f(z) = ((w - z) * g w) pow n) /\
+                (!w. w IN ball(z,r) ==> ~(g w = Cx(&0)))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:complex->complex`; `s:complex->bool`; `n:num`]
+        HOLOMORPHIC_FACTOR_ORDER_OF_ZERO) THEN
+  ASM_REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `r:real` THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`\z. complex_derivative g z / g z`; `ball(z:complex,r)`;
+    `{}:complex->bool`] HOLOMORPHIC_CONVEX_PRIMITIVE) THEN
+  REWRITE_TAC[CONVEX_BALL; FINITE_RULES; DIFF_EMPTY] THEN ANTS_TAC THENL
+   [SIMP_TAC[GSYM HOLOMORPHIC_ON_OPEN; OPEN_BALL;
+             INTERIOR_OPEN; complex_differentiable] THEN
+    MATCH_MP_TAC(TAUT `q /\ (q ==> p) ==> p /\ q`) THEN
+    REWRITE_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON] THEN
+    ASM_SIMP_TAC[HOLOMORPHIC_COMPLEX_DERIVATIVE; OPEN_BALL;
+                 HOLOMORPHIC_ON_DIV; ETA_AX];
+    SIMP_TAC[OPEN_BALL; HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN] THEN
+    DISCH_THEN(X_CHOOSE_THEN `h:complex->complex` STRIP_ASSUME_TAC)] THEN
+  MP_TAC(ISPECL [`\z:complex. cexp(h z) / g z`; `ball(z:complex,r)`]
+    HAS_COMPLEX_DERIVATIVE_ZERO_CONNECTED_CONSTANT) THEN
+  REWRITE_TAC[OPEN_BALL; CONNECTED_BALL] THEN ANTS_TAC THENL
+   [X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `Cx(&0) = ((complex_derivative g w / g w * cexp (h w)) * g w -
+                cexp (h w) * complex_derivative g w) / g w pow 2`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[COMPLEX_FIELD
+       `~(z = Cx(&0)) ==> (d / z * e) * z = e * d`] THEN
+      SIMPLE_COMPLEX_ARITH_TAC;
+      MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DIV_AT THEN
+      ASM_SIMP_TAC[] THEN CONJ_TAC THENL
+       [GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+        ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+        MATCH_MP_TAC COMPLEX_DIFF_CHAIN_AT THEN
+        ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_CEXP];
+        ASM_MESON_TAC[HOLOMORPHIC_ON_OPEN; complex_differentiable;
+          OPEN_BALL; HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE]]];
+    DISCH_THEN(X_CHOOSE_THEN `c:complex` MP_TAC) THEN
+    ASM_CASES_TAC `c = Cx(&0)` THENL
+     [ASM_SIMP_TAC[CEXP_NZ; COMPLEX_FIELD
+       `~(x = Cx(&0)) /\ ~(y = Cx(&0)) ==> ~(x / y = Cx(&0))`] THEN
+      ASM_MESON_TAC[];
+      ASM_SIMP_TAC[COMPLEX_FIELD
+       `~(y = Cx(&0)) /\ ~(z = Cx(&0))
+        ==> (x / y = z <=> y = inv(z) * x)`] THEN
+      DISCH_TAC THEN EXISTS_TAC
+       `\z:complex. cexp((clog(inv c) + h z) / Cx(&n))` THEN
+      REWRITE_TAC[CEXP_NZ; GSYM CEXP_N; COMPLEX_POW_MUL] THEN
+      ASM_SIMP_TAC[COMPLEX_DIV_LMUL; CX_INJ; REAL_OF_NUM_EQ; LE_1] THEN
+      ASM_SIMP_TAC[CEXP_ADD; CEXP_CLOG; COMPLEX_INV_EQ_0] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN
+      REWRITE_TAC[HOLOMORPHIC_ON_CEXP] THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+      ASM_SIMP_TAC[HOLOMORPHIC_ON_CONST; CX_INJ; REAL_OF_NUM_EQ; LE_1] THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_ADD THEN
+      REWRITE_TAC[HOLOMORPHIC_ON_CONST] THEN
+      ASM_MESON_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL]]]);;
+
+let HOLOMORPHIC_FACTOR_ZERO_NONCONSTANT = prove
+ (`!f s z.
+        open s /\ connected s /\ z IN s /\
+        f holomorphic_on s /\ f(z) = Cx(&0) /\ ~(?c. !w. w IN s ==> f w = c)
+        ==> ?g r n.
+                0 < n /\ &0 < r /\ ball(z,r) SUBSET s /\
+                g holomorphic_on ball(z,r) /\
+                (!w. w IN ball(z,r) ==> f w = (w - z) pow n * g w) /\
+                (!w. w IN ball(z,r) ==> ~(g w = Cx (&0)))`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `!n. 0 < n ==> higher_complex_derivative n f z = Cx(&0)` THENL
+   [MP_TAC(ISPECL
+     [`f:complex->complex`; `s:complex->bool`; `z:complex`]
+     HOLOMORPHIC_FUN_EQ_CONST_ON_CONNECTED) THEN
+    ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[];
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `r0:real` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM]) THEN
+    GEN_REWRITE_TAC LAND_CONV [num_WOP] THEN
+    REWRITE_TAC[NOT_IMP; GSYM IMP_CONJ_ALT] THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:num` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`f:complex->complex`; `s:complex->bool`; `n:num`]
+        HOLOMORPHIC_FACTOR_ORDER_OF_ZERO) THEN
+    ASM_REWRITE_TAC[COMPLEX_SUB_RZERO] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `g:complex->complex` THEN
+    DISCH_THEN(X_CHOOSE_THEN `r1:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `min r0 r1:real` THEN EXISTS_TAC `n:num` THEN
+    ASM_SIMP_TAC[BALL_MIN_INTER; IN_INTER; REAL_LT_MIN] THEN CONJ_TAC THENL
+     [ASM SET_TAC[];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        HOLOMORPHIC_ON_SUBSET)) THEN
+      ASM SET_TAC[]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relating invertibility and nonvanishing of derivative.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_COMPLEX_DERIVATIVE_LOCALLY_INJECTIVE = prove
+ (`!f s z.
+        f holomorphic_on s /\ open s /\ z IN s /\
+        ~(complex_derivative f z = Cx(&0))
+        ==> ?t. z IN t /\
+                open t /\
+                (!x x'. x IN t /\ x' IN t /\ f x' = f x ==> x' = x)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_LOCALLY_INJECTIVE THEN
+  EXISTS_TAC `\z h. complex_derivative f z * h` THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN EXISTS_TAC `s:complex->bool` THEN
+  ASM_REWRITE_TAC[GSYM has_complex_derivative] THEN
+  REWRITE_TAC[CONJ_ASSOC; LEFT_EXISTS_AND_THM] THEN
+  ASM_REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC LINEAR_INJECTIVE_LEFT_INVERSE THEN
+    ASM_SIMP_TAC[LINEAR_COMPLEX_MUL; COMPLEX_EQ_MUL_LCANCEL];
+    ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT];
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `(complex_derivative f) continuous_on s` MP_TAC THENL
+     [MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON THEN
+      ASM_SIMP_TAC[HOLOMORPHIC_COMPLEX_DERIVATIVE];
+      ALL_TAC] THEN
+    ONCE_REWRITE_TAC[DIST_SYM] THEN REWRITE_TAC[continuous_on] THEN
+    DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
+    ASM_REWRITE_TAC[dist; REAL_HALF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+    ASM_REWRITE_TAC[SUBSET; IN_BALL; ONCE_REWRITE_RULE[DIST_SYM] dist] THEN
+    DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `min d r:real` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+    X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
+    ASM_REWRITE_TAC[GSYM COMPLEX_SUB_RDISTRIB] THEN MATCH_MP_TAC
+     (CONJUNCT2(MATCH_MP ONORM (SPEC_ALL LINEAR_COMPLEX_MUL))) THEN
+    GEN_TAC THEN REWRITE_TAC[COMPLEX_NORM_MUL] THEN
+    MATCH_MP_TAC REAL_LE_RMUL THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; NORM_POS_LE]]);;
+
+let HAS_COMPLEX_DERIVATIVE_LOCALLY_INVERTIBLE = prove
+ (`!f s z.
+        f holomorphic_on s /\ open s /\ z IN s /\
+        ~(complex_derivative f z = Cx(&0))
+        ==> ?t g. z IN t /\ open t /\ open(IMAGE f t) /\ t SUBSET s /\
+                  (!w. w IN t ==> g(f w) = w) /\
+                  (!y. y IN (IMAGE f t) ==> f(g y) = y)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HAS_COMPLEX_DERIVATIVE_LOCALLY_INJECTIVE) THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:complex->bool` MP_TAC) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
+  REWRITE_TAC[INJECTIVE_ON_LEFT_INVERSE] THEN
+  DISCH_THEN(X_CHOOSE_TAC `g:complex->complex`) THEN
+  EXISTS_TAC `s INTER t:complex->bool` THEN
+  EXISTS_TAC `g:complex->complex` THEN
+  ASM_SIMP_TAC[OPEN_INTER; IN_INTER; INTER_SUBSET; FORALL_IN_IMAGE] THEN
+  MATCH_MP_TAC INVARIANCE_OF_DOMAIN THEN
+  ASM_SIMP_TAC[OPEN_INTER; IN_INTER] THEN
+  ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON;
+                HOLOMORPHIC_ON_SUBSET; INTER_SUBSET]);;
+
+let HOLOMORPHIC_INJECTIVE_IMP_REGULAR = prove
+ (`!f s.
+        f holomorphic_on s /\ open s /\
+        (!w z. w IN s /\ z IN s /\ f w = f z ==> w = z)
+        ==> !z. z IN s ==> ~(complex_derivative f z = Cx(&0))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+  ASM_CASES_TAC `!n. 0 < n ==> higher_complex_derivative n f z = Cx(&0)` THENL
+   [MP_TAC(ISPECL
+     [`f:complex->complex`; `ball(z:complex,r)`; `z:complex`]
+     HOLOMORPHIC_FUN_EQ_CONST_ON_CONNECTED) THEN
+    ASM_SIMP_TAC[OPEN_BALL; CONNECTED_BALL; CENTRE_IN_BALL; NOT_IMP] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET]; ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o SPEC `z + Cx(r / &2)`) THEN
+    REWRITE_TAC[IN_BALL; NORM_ARITH `dist(z,z + r) = norm r`] THEN
+    REWRITE_TAC[COMPLEX_NORM_CX; NOT_IMP] THEN
+    CONJ_TAC THENL [ASM_REAL_ARITH_TAC; DISCH_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`z:complex`; `z + Cx(r / &2)`]) THEN
+    ASM_REWRITE_TAC[COMPLEX_RING `z = z + a <=> a = Cx(&0)`] THEN
+    REWRITE_TAC[NOT_IMP; CX_INJ] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    REWRITE_TAC[IN_BALL; NORM_ARITH `dist(z,z + r) = norm r`] THEN
+    REWRITE_TAC[COMPLEX_NORM_CX] THEN ASM_REAL_ARITH_TAC;
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM])] THEN
+  GEN_REWRITE_TAC LAND_CONV [num_WOP] THEN
+  REWRITE_TAC[NOT_IMP; GSYM IMP_CONJ_ALT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `n:num` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`f:complex->complex`; `s:complex->bool`; `n:num`; `z:complex`]
+     HOLOMORPHIC_FACTOR_ORDER_OF_ZERO_STRONG) THEN
+  ASM_REWRITE_TAC[NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`g:complex->complex`; `k:real`] THEN STRIP_TAC THEN
+  ASM_CASES_TAC `n = 1` THENL
+   [ASM_MESON_TAC[HIGHER_COMPLEX_DERIVATIVE_1]; ALL_TAC] THEN
+  MP_TAC(ISPECL[`\w:complex. (w - z) * g(w)`; `ball(z:complex,min r k)`;
+                `z:complex`] HAS_COMPLEX_DERIVATIVE_LOCALLY_INVERTIBLE) THEN
+  ASM_REWRITE_TAC[OPEN_BALL; CENTRE_IN_BALL; NOT_IMP; REAL_LT_MIN] THEN
+  CONJ_TAC THENL
+   [SUBGOAL_THEN
+     `!w. w IN ball(z,min r k)
+          ==> ((\w. (w - z) * g w) has_complex_derivative
+               ((w - z) * complex_derivative g w + (Cx(&1) - Cx(&0)) * g w))
+              (at w)`
+    (LABEL_TAC "*")
+    THENL
+     [REPEAT STRIP_TAC THEN
+      SUBGOAL_THEN `w IN ball(z:complex,k)` ASSUME_TAC THENL
+       [ASM_MESON_TAC[SUBSET; SUBSET_BALL; REAL_ARITH `min r k <= k`];
+        ALL_TAC] THEN
+      MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_MUL_AT THEN
+      SIMP_TAC[HAS_COMPLEX_DERIVATIVE_ID; HAS_COMPLEX_DERIVATIVE_SUB;
+       HAS_COMPLEX_DERIVATIVE_CONST; HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+      ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT; OPEN_BALL];
+      SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL] THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+      REMOVE_THEN "*" (MP_TAC o SPEC `z:complex`) THEN
+      ASM_REWRITE_TAC[CENTRE_IN_BALL; REAL_LT_MIN] THEN
+      DISCH_THEN(SUBST1_TAC o  MATCH_MP HAS_COMPLEX_DERIVATIVE_DERIVATIVE) THEN
+      REWRITE_TAC[COMPLEX_SUB_REFL; COMPLEX_MUL_LZERO; COMPLEX_ADD_LID;
+                  COMPLEX_SUB_RZERO; COMPLEX_MUL_LID] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[CENTRE_IN_BALL]];
+    REWRITE_TAC[NOT_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`t:complex->bool`; `h:complex->complex`] THEN
+    ABBREV_TAC `u = IMAGE (\w:complex. (w - z) * g w) t` THEN STRIP_TAC THEN
+    MP_TAC(ISPEC `u:complex->bool` OPEN_CONTAINS_CBALL) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `Cx(&0)`) THEN
+    ANTS_TAC THENL
+     [EXPAND_TAC "u" THEN REWRITE_TAC[IN_IMAGE] THEN
+      EXISTS_TAC `z:complex` THEN ASM_REWRITE_TAC[] THEN
+      CONV_TAC COMPLEX_RING;
+      ALL_TAC] THEN
+    REWRITE_TAC[NOT_EXISTS_THM; SUBSET; IN_CBALL; dist;
+                COMPLEX_SUB_LZERO; NORM_NEG] THEN
+    X_GEN_TAC `e:real` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(fun th ->
+     MP_TAC(ISPEC `Cx(e) * cexp(Cx(&2) * Cx pi * ii * Cx(&0 / &n))` th) THEN
+     MP_TAC(ISPEC `Cx(e) * cexp(Cx(&2) * Cx pi * ii * Cx(&1 / &n))` th)) THEN
+    REWRITE_TAC[COMPLEX_NORM_MUL; NORM_CEXP; RE_MUL_CX; RE_MUL_II] THEN
+    REWRITE_TAC[IM_CX; REAL_NEG_0; REAL_MUL_RZERO; REAL_EXP_0] THEN
+    REWRITE_TAC[COMPLEX_NORM_CX; REAL_MUL_RID] THEN
+    SIMP_TAC[REAL_ARITH `&0 < e ==> abs e <= e`; ASSUME `&0 < e`] THEN
+    EXPAND_TAC "u" THEN REWRITE_TAC[IN_IMAGE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `y1:complex` (STRIP_ASSUME_TAC o GSYM)) THEN
+    DISCH_THEN(X_CHOOSE_THEN `y0:complex` (STRIP_ASSUME_TAC o GSYM)) THEN
+    UNDISCH_THEN `!w. w IN ball (z,k) ==> f w - f z = ((w - z) * g w) pow n`
+      (fun th -> MP_TAC(SPEC `y1:complex` th) THEN
+                 MP_TAC(SPEC `y0:complex` th)) THEN
+    MATCH_MP_TAC(TAUT `(p1 /\ p2) /\ ~(q1 /\ q2)
+                       ==> (p1 ==> q1) ==> (p2 ==> q2) ==> F`) THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[SUBSET; SUBSET_BALL; REAL_ARITH `min r k <= k`];
+      MATCH_MP_TAC(MESON[] `x' = y' /\ ~(x = y) ==> ~(x = x' /\ y = y')`)] THEN
+    CONJ_TAC THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[INJECTIVE_ON_LEFT_INVERSE]) THEN
+      ASM_SIMP_TAC[] THEN REWRITE_TAC[COMPLEX_POW_MUL] THEN
+      ASM_SIMP_TAC[COMPLEX_ROOT_UNITY; LE_1];
+      REWRITE_TAC[COMPLEX_RING `x - a:complex = y - a <=> x = y`] THEN
+      DISCH_TAC THEN UNDISCH_THEN
+       `!w z. w IN s /\ z IN s /\ (f:complex->complex) w = f z ==> w = z`
+       (MP_TAC o SPECL [`y0:complex`; `y1:complex`]) THEN
+      ASM_REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[SUBSET; SUBSET_BALL; REAL_ARITH `min r k <= r`];
+        DISCH_THEN SUBST_ALL_TAC] THEN
+      MP_TAC(ISPECL [`n:num`; `0`; `1`] COMPLEX_ROOT_UNITY_EQ) THEN
+      ASM_SIMP_TAC[LE_1] THEN MATCH_MP_TAC(TAUT `a /\ ~b ==> ~(a <=> b)`) THEN
+      CONJ_TAC THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (COMPLEX_RING
+         `z = e * y ==> z = e * x /\ ~(e = Cx(&0)) ==> x = y`)) THEN
+        ASM_SIMP_TAC[CX_INJ; REAL_LT_IMP_NZ];
+        REWRITE_TAC[num_congruent; int_congruent] THEN
+        DISCH_THEN(X_CHOOSE_THEN `d:int`
+         (MP_TAC o AP_TERM `abs:int->int` o SYM)) THEN
+        REWRITE_TAC[INT_ABS_NUM; INT_SUB_LZERO; INT_ABS_NEG] THEN
+        ASM_REWRITE_TAC[INT_ABS_MUL_1; INT_OF_NUM_EQ; INT_ABS_NUM]]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence a nice clean inverse function theorem.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let HOLOMORPHIC_ON_INVERSE = prove
+ (`!f s. f holomorphic_on s /\ open s /\
+         (!w z. w IN s /\ z IN s /\ f w = f z ==> w = z)
+         ==> open(IMAGE f s) /\
+             ?g. g holomorphic_on (IMAGE f s) /\
+                 (!z. z IN s
+                      ==> complex_derivative f z * complex_derivative g (f z) =
+                          Cx(&1)) /\
+                 (!z. z IN s ==> g(f z) = z) /\
+                 (!y. y IN (IMAGE f s) ==> f(g y) = y)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC INVARIANCE_OF_DOMAIN THEN
+    ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON];
+    DISCH_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INJECTIVE_ON_LEFT_INVERSE]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:complex->complex` THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[FORALL_IN_IMAGE] THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_OPEN; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[AND_FORALL_THM] THEN X_GEN_TAC `z:complex` THEN
+  ASM_CASES_TAC `(z:complex) IN s` THEN ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPECL
+   [`f:complex->complex`; `g:complex->complex`;
+    `complex_derivative f z`; `s:complex->bool`;
+    `z:complex`] HAS_COMPLEX_DERIVATIVE_INVERSE_STRONG) THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON; IMP_CONJ] THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE; HOLOMORPHIC_ON_OPEN;
+                        complex_differentiable];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`f:complex->complex`; `s:complex->bool`]
+        HOLOMORPHIC_INJECTIVE_IMP_REGULAR) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[]; DISCH_THEN(MP_TAC o SPEC `z:complex`)] THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[COMPLEX_FIELD
+   `~(z = Cx(&0)) ==> (z * w = Cx(&1) <=> w = inv z)`] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_DERIVATIVE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Holomorphism of covering maps and lifts.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let COVERING_SPACE_LIFT_IS_HOLOMORPHIC = prove
+ (`!p c s f g u.
+        covering_space (c,p) s /\ open c /\ p holomorphic_on c /\
+        f holomorphic_on u /\ IMAGE f u SUBSET s /\ IMAGE g u SUBSET c /\
+        g continuous_on u /\ (!x. x IN u ==> p(g x) = f x)
+        ==> g holomorphic_on u`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[holomorphic_on; GSYM complex_differentiable] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `(f:complex->complex) z` o last o CONJUNCTS o
+              GEN_REWRITE_RULE I [covering_space]) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ASM_SIMP_TAC[OPEN_IN_OPEN_EQ]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:complex->bool` MP_TAC) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `vv:(complex->bool)->bool` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+  DISCH_THEN(MP_TAC o snd o EQ_IMP_RULE o SPEC `(g:complex->complex) z`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[IN_UNIONS]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:complex->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`p:complex->complex`; `v:complex->bool`]
+        HOLOMORPHIC_ON_INVERSE) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL [ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET]; ALL_TAC] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[homeomorphism]) THEN ASM SET_TAC[];
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `p':complex->complex` STRIP_ASSUME_TAC)] THEN
+  MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_TRANSFORM_WITHIN THEN
+  EXISTS_TAC `(p':complex->complex) o (f:complex->complex)` THEN
+  MP_TAC(ISPECL
+   [`g:complex->complex`; `u:complex->bool`; `c:complex->bool`;
+    `v:complex->bool`] CONTINUOUS_OPEN_IN_PREIMAGE_GEN) THEN
+  ASM_SIMP_TAC[OPEN_IN_OPEN_EQ] THEN REWRITE_TAC[open_in] THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex` o CONJUNCT2) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[o_THM; IN_ELIM_THM]] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_COMPOSE_WITHIN THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_WITHIN THEN
+    ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET];
+    MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_AT_WITHIN THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT THEN
+    EXISTS_TAC `IMAGE (p:complex->complex) v` THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[]]);;
+
+let COVERING_SPACE_LIFT_HOLOMORPHIC = prove
+ (`!p c s f u.
+        covering_space (c,p) s /\ p holomorphic_on c /\ open c /\
+        simply_connected u /\ locally path_connected u /\
+        f holomorphic_on u /\ IMAGE f u SUBSET s
+        ==> ?g. g holomorphic_on u /\ IMAGE g u SUBSET c /\
+                !y. y IN u ==> p(g y) = f y`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`p:complex->complex`; `c:complex->bool`; `s:complex->bool`;
+    `f:complex->complex`; `u:complex->bool`] COVERING_SPACE_LIFT) THEN
+    ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:complex->complex` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        COVERING_SPACE_LIFT_IS_HOLOMORPHIC)) THEN
+  EXISTS_TAC `f:complex->complex` THEN ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The Schwarz lemma.                                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let SCHWARZ_LEMMA = prove
+ (`!f. f holomorphic_on ball(Cx(&0),&1) /\
+       (!z:complex. norm z < &1 ==> norm (f z) < &1) /\
+       f(Cx(&0)) = Cx(&0)
+       ==> (!z. norm z < &1 ==> norm(f z) <= norm z) /\
+           norm(complex_derivative f(Cx(&0))) <= &1 /\
+           ((?z. norm z < &1 /\ ~(z= Cx(&0)) /\ norm(f z) = norm z) \/
+            norm(complex_derivative f (Cx(&0))) = &1
+            ==> ?c. (!z. norm z < &1 ==> f z = c*z) /\ norm c = &1)`,
+  let LEMMA1 = prove
+  (`!f a. open a /\ connected a /\ bounded a /\ ~(a = {}) /\
+         f holomorphic_on a /\ f continuous_on (closure a)
+         ==> (?w. w IN (frontier a) /\
+                  (!z. z IN (closure a) ==> norm (f z) <= norm (f w)))`,
+  REPEAT STRIP_TAC THEN ASSERT_TAC
+    `?x. x IN closure a /\
+         (!z. z IN closure a ==>
+              norm((f:complex->complex) z) <= norm(f x))` THENL
+  [MATCH_MP_TAC CONTINUOUS_ATTAINS_SUP THEN
+  ASM_SIMP_TAC [COMPACT_CLOSURE;CLOSURE_EQ_EMPTY] THEN
+  SUBGOAL_THEN `lift o (\x. norm((f:complex->complex) x)) =
+                 (lift o norm) o (\x. f x) ` SUBST1_TAC THENL
+  [REWRITE_TAC[o_DEF]; MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  ASM_REWRITE_TAC [CONTINUOUS_ON_LIFT_NORM;ETA_AX]]; ALL_TAC] THEN
+  ASM_CASES_TAC `x:complex IN frontier a` THENL
+  [EXISTS_TAC `x:complex` THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `x:complex IN interior a` MP_TAC THENL
+  [POP_ASSUM MP_TAC THEN REWRITE_TAC[frontier;DIFF] THEN
+  SET_TAC[ASSUME `x:complex IN closure a`]; ALL_TAC] THEN
+  ASM_SIMP_TAC[INTERIOR_OPEN] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `?c. !z. z IN a ==> (f:complex->complex) z = c`
+  STRIP_ASSUME_TAC THENL
+  [MATCH_MP_TAC MAXIMUM_MODULUS_PRINCIPLE THEN
+  EXISTS_TAC `a:complex->bool` THEN
+  EXISTS_TAC `x:complex` THEN ASM_REWRITE_TAC[SUBSET_REFL] THEN GEN_TAC THEN
+  DISCH_TAC THEN FIRST_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[closure;UNION] THEN
+  SET_TAC[ASSUME `z:complex IN a`]; ALL_TAC] THEN
+  SUBGOAL_THEN `CHOICE(frontier(a:complex->bool)) IN frontier a`
+  ASSUME_TAC THENL
+  [MATCH_MP_TAC CHOICE_DEF THEN MATCH_MP_TAC FRONTIER_NOT_EMPTY THEN
+   CONJ_TAC THENL [ASM SET_TAC[]; ASM_MESON_TAC[NOT_BOUNDED_UNIV]];
+   ALL_TAC] THEN
+  EXISTS_TAC `CHOICE(frontier(a:complex->bool))` THEN ASM_REWRITE_TAC[] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_EQ_IMP_LE THEN
+  SUBGOAL_THEN `!z. z IN closure a ==> (f:complex->complex) z = c`
+  ASSUME_TAC THENL
+  [MP_TAC (ISPECL [`f:complex->complex`; `closure (a:complex->bool)`;
+  `{c:complex}`] CONTINUOUS_CLOSED_PREIMAGE) THEN
+  ASM_REWRITE_TAC [CLOSED_CLOSURE; CLOSED_SING] THEN
+  ABBREV_TAC `s = {x | x IN closure(a:complex->bool) /\
+  (f:complex->complex) x IN {c}}` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `closure a SUBSET (s:complex->bool)` ASSUME_TAC THENL
+  [MATCH_MP_TAC CLOSURE_MINIMAL THEN CONJ_TAC THENL
+  [REWRITE_TAC[SUBSET] THEN EXPAND_TAC "s" THEN
+   ASSUME_TAC (MESON [CLOSURE_SUBSET;GSYM SUBSET]
+       `!x:complex. x IN a ==> x IN closure a`) THEN
+  SET_TAC [ASSUME `!x:complex. x IN a ==> x IN closure a`;
+              ASSUME `!z:complex. z IN a ==> f z = c:complex`];
+  ASM_REWRITE_TAC[]];
+  POP_ASSUM MP_TAC THEN EXPAND_TAC "s" THEN SET_TAC[]];
+  EQ_TRANS_TAC `norm(c:complex)` THENL
+  [ASM_SIMP_TAC[]; ONCE_REWRITE_TAC [EQ_SYM_EQ] THEN
+  MATCH_MP_TAC (NORM_ARITH `!x y:complex. x = y ==> norm x = norm y`) THEN
+  FIRST_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[frontier;IN_DIFF]]])
+  in
+  let LEMMA2 = prove
+  (`!(f:complex->complex) r w s.
+      &0 < r /\ f holomorphic_on ball(Cx(&0),r) /\
+      &0 < s /\ ball(w,s) SUBSET ball(Cx(&0),r) /\
+      (!z. norm (w-z) < s ==> norm(f z) <= norm(f w))
+      ==> (?c. !z. norm z < r ==> f z = c)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC (SPECL[`f:complex->complex`;`ball (Cx(&0),r)`; `ball (w:complex,s)`;
+                `w:complex`] MAXIMUM_MODULUS_PRINCIPLE) THEN
+  ASM_REWRITE_TAC[OPEN_BALL; CONNECTED_BALL; IN_BALL;DIST_REFL] THEN
+  ASM_REWRITE_TAC[dist;COMPLEX_SUB_LZERO;NORM_NEG])
+  in
+  let LEMMA3 = prove
+  (`!r:real f. f holomorphic_on (ball(Cx(&0),r)) /\ f (Cx(&0))=Cx(&0)
+   ==> (?h. h holomorphic_on (ball(Cx(&0),r)) /\
+  ((!z. norm z < r ==> f z=z*(h z)) /\
+  (complex_derivative f (Cx(&0)))= h (Cx(&0))))`,
+  REPEAT STRIP_TAC THEN ABBREV_TAC `h = \z. if z = Cx(&0) then
+  complex_derivative f (Cx(&0)) else f z/z` THEN EXISTS_TAC
+  `h:complex->complex` THEN ASSERT_TAC `(!z:complex. norm z < r ==>
+  (f:complex->complex) z = z * h z) /\ complex_derivative f (Cx(&0))
+  = h (Cx(&0))` THENL [CONJ_TAC THENL
+  [GEN_TAC THEN DISCH_TAC THEN EXPAND_TAC "h" THEN
+  COND_CASES_TAC THENL [ASM_REWRITE_TAC[COMPLEX_MUL_LZERO];
+  POP_ASSUM MP_TAC THEN CONV_TAC COMPLEX_FIELD];
+  EXPAND_TAC "h" THEN ASM_REWRITE_TAC[]];ALL_TAC] THEN ASM_REWRITE_TAC[]
+  THEN MATCH_MP_TAC  POLE_THEOREM_OPEN_0 THEN  EXISTS_TAC `(f:complex->complex)`
+  THEN EXISTS_TAC `Cx(&0)` THEN
+  ASM_SIMP_TAC[OPEN_BALL;IN_BALL;COMPLEX_SUB_RZERO;
+   dist;COMPLEX_SUB_LZERO;NORM_NEG])
+  in
+  GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC (SPECL [`&1`;`f:complex->complex`] LEMMA3) THEN ASM_REWRITE_TAC[] THEN
+  STRIP_TAC THEN SUBGOAL_THEN
+    `!z. norm z < &1 ==> norm ((h:complex->complex) z) <= &1`
+    ASSUME_TAC THENL
+  [GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC
+  (prove
+  (`!x y:real. (!a. y<a ==> x<a) ==> x <= y`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN
+  ONCE_REWRITE_TAC[REAL_LT_BETWEEN] THEN REWRITE_TAC[NOT_EXISTS_THM;
+  DE_MORGAN_THM] THEN X_GEN_TAC `z:real` THEN
+  POP_ASSUM (MP_TAC o SPEC `z:real`) THEN REAL_ARITH_TAC)) THEN
+  X_GEN_TAC `a:real` THEN
+  DISCH_TAC THEN SUBGOAL_THEN
+   `?r. norm (z:complex) < r /\ inv r < a /\ r < &1` MP_TAC THENL
+  [SUBGOAL_THEN `max (inv a) (norm(z:complex)) < &1` MP_TAC THENL
+  [ASM_SIMP_TAC[REAL_MAX_LT; REAL_INV_LT_1];
+  GEN_REWRITE_TAC LAND_CONV [REAL_LT_BETWEEN] THEN
+  DISCH_THEN (X_CHOOSE_TAC `r:real`) THEN EXISTS_TAC `r:real` THEN
+  POP_ASSUM MP_TAC THEN ASM_REWRITE_TAC[REAL_MAX_LT] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LT_LINV THEN
+  ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC]; ALL_TAC] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `&0 < r` ASSUME_TAC THENL
+  [ASM_MESON_TAC[REAL_LET_TRANS; NORM_POS_LE]; ALL_TAC] THEN
+  SUBGOAL_THEN `inv (r:real) = &1/r` ASSUME_TAC THENL
+  [MATCH_MP_TAC REAL_MUL_RINV_UNIQ THEN MATCH_MP_TAC REAL_DIV_LMUL THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_NZ]; ALL_TAC] THEN
+  SUBGOAL_THEN `?w. norm w = r /\ (!z. norm z < r
+                    ==> norm((h:complex->complex) z) <= norm(h w))`
+                  STRIP_ASSUME_TAC THENL
+  [MATCH_MP_TAC(prove (`!f r. &0 < r /\ f holomorphic_on ball(Cx(&0),r) /\
+         f continuous_on cball(Cx(&0),r)
+         ==> (?w. norm w = r /\ (!z. norm z < r ==> norm(f z) <= norm(f w)))`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(SPECL[`f:complex->complex`; `ball(Cx(&0),r)`] LEMMA1) THEN
+  ASM_REWRITE_TAC[OPEN_BALL; CONNECTED_BALL; BOUNDED_BALL; BALL_EQ_EMPTY;
+                  REAL_ARITH `!r:real. ~(r <= &0) <=> &0 < r`] THEN
+  ASM_SIMP_TAC[CLOSURE_BALL] THEN STRIP_TAC THEN EXISTS_TAC `w:complex` THEN
+  CONJ_TAC THENL
+  [UNDISCH_TAC `w:complex IN frontier(ball(Cx(&0),r))` THEN
+  ASM_SIMP_TAC[FRONTIER_BALL;sphere;dist;COMPLEX_SUB_LZERO;NORM_NEG] THEN
+  SET_TAC[];
+  POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[IN_CBALL;dist;COMPLEX_SUB_LZERO;NORM_NEG] THEN
+  MESON_TAC [REAL_LT_IMP_LE]])) THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL [MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET
+  THEN EXISTS_TAC `ball(Cx(&0),&1)` THEN
+  ASM_SIMP_TAC [SUBSET_BALL;REAL_LT_IMP_LE];
+  MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON THEN
+  MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN EXISTS_TAC `ball(Cx(&0),&1)` THEN
+  ASM_REWRITE_TAC[SUBSET; IN_CBALL; IN_BALL] THEN
+  ASM_MESON_TAC[REAL_LET_TRANS]]; ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `norm(h(w:complex):complex)` THEN CONJ_TAC THENL
+  [ASM_SIMP_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `h w:complex = f w / w` SUBST1_TAC THENL
+  [ASM_SIMP_TAC[] THEN
+  MP_TAC (MESON [GSYM COMPLEX_NORM_ZERO;REAL_NOT_EQ;
+                    ASSUME `norm(w:complex) =r`;
+                    ASSUME `&0 < r`] `~(w=Cx(&0))`) THEN
+  CONV_TAC(COMPLEX_FIELD);
+  ASM_REWRITE_TAC[COMPLEX_NORM_DIV] THEN MATCH_MP_TAC REAL_LT_TRANS THEN
+  EXISTS_TAC `&1/(r:real)` THEN ASM_SIMP_TAC [REAL_LT_DIV2_EQ] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `inv (r:real)` THEN
+  ASM_REWRITE_TAC[REAL_LE_REFL]]; ALL_TAC] THEN
+  CONJ_TAC THENL
+  [GEN_TAC THEN DISCH_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THENL
+  [ASM_SIMP_TAC[COMPLEX_MUL_LZERO;REAL_LE_REFL];
+  SUBST1_TAC (REAL_ARITH `norm (z:complex) = norm z * &1`) THEN
+  ASM_SIMP_TAC[COMPLEX_NORM_MUL] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
+  ASM_SIMP_TAC[NORM_POS_LE]]; ALL_TAC] THEN CONJ_TAC THENL
+  [ASM_MESON_TAC [COMPLEX_NORM_ZERO;REAL_LT_01]; ALL_TAC] THEN
+  REWRITE_TAC[TAUT `((p \/ q) ==> r) <=> ((p ==> r) /\ (q ==> r))`] THEN
+  CONJ_TAC THENL [STRIP_TAC THEN SUBGOAL_THEN
+   `norm ((h:complex->complex) z) = &1` ASSUME_TAC THENL
+  [SUBGOAL_THEN `(h:complex->complex) z = f z/z` SUBST1_TAC THENL
+  [UNDISCH_THEN `!z:complex. norm z < &1  ==> f z = z * h z`
+  (MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  UNDISCH_TAC `~(z = Cx(&0))` THEN CONV_TAC(COMPLEX_FIELD);
+  ASM_SIMP_TAC[COMPLEX_NORM_ZERO;REAL_DIV_REFL;COMPLEX_NORM_DIV]];
+  SUBGOAL_THEN `?c. (!z. norm z < &1 ==> (h:complex->complex) z = c)`
+  STRIP_ASSUME_TAC THENL [MATCH_MP_TAC LEMMA2
+  THEN EXISTS_TAC `z:complex` THEN EXISTS_TAC `&1 - norm(z:complex)`
+  THEN ASM_REWRITE_TAC[REAL_LT_01] THEN CONJ_TAC THENL
+  [ASM_MESON_TAC[REAL_SUB_LT]; CONJ_TAC THENL
+  [REWRITE_TAC[SUBSET;IN_BALL] THEN GEN_TAC THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `dist(Cx(&0), z) + dist(z,x)` THEN
+  REWRITE_TAC[DIST_TRIANGLE] THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[dist;COMPLEX_SUB_LZERO;NORM_NEG] THEN REAL_ARITH_TAC;
+  GEN_TAC THEN DISCH_TAC THEN FIRST_ASSUM MATCH_MP_TAC THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `norm(z:complex) + norm(z' - z)` THEN
+  REWRITE_TAC[NORM_TRIANGLE_SUB] THEN REWRITE_TAC[NORM_SUB] THEN
+  POP_ASSUM MP_TAC THEN REWRITE_TAC[NORM_SUB] THEN REAL_ARITH_TAC]];
+  EXISTS_TAC `c:complex` THEN CONJ_TAC THENL
+  [ASM_SIMP_TAC[COMPLEX_MUL_SYM];
+  POP_ASSUM (MP_TAC o SPEC `z:complex`) THEN ASM_MESON_TAC[]]]];
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `?c. (!z. norm z < &1 ==> (h:complex->complex) z = c)`
+  STRIP_ASSUME_TAC THENL[MATCH_MP_TAC LEMMA2 THEN EXISTS_TAC `Cx(&0)`
+  THEN EXISTS_TAC `&1` THEN ASM_REWRITE_TAC[REAL_ARITH `&0 < &1`;
+  SUBSET_REFL; COMPLEX_SUB_LZERO; NORM_NEG];
+  EXISTS_TAC `c:complex` THEN CONJ_TAC THENL
+  [ASM_SIMP_TAC[COMPLEX_MUL_SYM];POP_ASSUM (MP_TAC o SPEC `Cx(&0)`) THEN
+  ASM_MESON_TAC[COMPLEX_NORM_0; REAL_LT_01]]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The Schwarz reflection principle.                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let HOLOMORPHIC_ON_PASTE_ACROSS_LINE = prove
+ (`!f s a k.
+        open s /\ ~(a = vec 0) /\
+        f holomorphic_on {z | z IN s /\ k < a dot z} /\
+        f holomorphic_on {z | z IN s /\ a dot z < k} /\
+        f continuous_on s
+        ==> f holomorphic_on s`,
+  let lemma0 = prove
+   (`!d a b:real^N k.
+          d dot a <= k /\ k <= d dot b
+          ==> ?c. c IN segment[a,b] /\ d dot c = k /\
+                  (!z. z IN segment[a,c] ==> d dot z <= k) /\
+                  (!z. z IN segment[c,b] ==> k <= d dot z)`,
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`segment[a:real^N,b]`; `a:real^N`; `b:real^N`;
+                   `d:real^N`; `k:real`] CONNECTED_IVT_HYPERPLANE) THEN
+    ASM_REWRITE_TAC[CONNECTED_SEGMENT; ENDS_IN_SEGMENT] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^N` THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[SET_RULE
+     `(!z. z IN s ==> P z) <=> s SUBSET {x | P x}`] THEN
+    REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN CONJ_TAC THEN
+    MATCH_MP_TAC HULL_MINIMAL THEN
+    REWRITE_TAC[CONVEX_HALFSPACE_LE; REWRITE_RULE[real_ge] CONVEX_HALFSPACE_GE;
+                SUBSET; FORALL_IN_INSERT; NOT_IN_EMPTY] THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM; REAL_LE_REFL]) in
+  let lemma1 = prove
+   (`!f s d k a b c.
+          convex s /\ open s /\ a IN s /\ b IN s /\ c IN s /\ ~(d = vec 0) /\
+          d dot a <= k /\ d dot b <= k /\ d dot c <= k /\
+          f holomorphic_on {z | z IN s /\ d dot z < k} /\
+          f holomorphic_on {z | z IN s /\ k < d dot z} /\
+          f continuous_on s
+          ==> path_integral (linepath (a,b)) f +
+              path_integral (linepath (b,c)) f +
+              path_integral (linepath (c,a)) f = Cx(&0)`,
+    REPEAT STRIP_TAC THEN
+    MP_TAC(SPECL [`f:complex->complex`; `a:complex`; `b:complex`; `c:complex`]
+          CAUCHY_THEOREM_TRIANGLE_INTERIOR) THEN
+    ANTS_TAC THENL
+     [CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+        EXISTS_TAC `s:complex->bool` THEN
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC HULL_MINIMAL THEN ASM SET_TAC[];
+        MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+        EXISTS_TAC `{z:complex | z IN s /\ d dot z < k}` THEN
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC SUBSET_TRANS THEN
+        EXISTS_TAC `interior(s INTER {x:complex | d dot x <= k})` THEN
+        CONJ_TAC THENL
+         [MATCH_MP_TAC SUBSET_INTERIOR THEN MATCH_MP_TAC HULL_MINIMAL THEN
+          ASM_SIMP_TAC[CONVEX_INTER; CONVEX_HALFSPACE_LE] THEN ASM SET_TAC[];
+          ASM_SIMP_TAC[INTERIOR_INTER; INTERIOR_HALFSPACE_LE;
+                       INTERIOR_OPEN] THEN
+          SET_TAC[]]];
+      REWRITE_TAC[HAS_CHAIN_INTEGRAL_CHAIN_INTEGRAL]]) in
+  let lemma2 = prove
+   (`!f s d k a b c.
+          convex s /\ open s /\ a IN s /\ b IN s /\ c IN s /\ ~(d = vec 0) /\
+          d dot a <= k /\ d dot b <= k /\
+          f holomorphic_on {z | z IN s /\ d dot z < k} /\
+          f holomorphic_on {z | z IN s /\ k < d dot z} /\
+          f continuous_on s
+          ==> path_integral (linepath (a,b)) f +
+              path_integral (linepath (b,c)) f +
+              path_integral (linepath (c,a)) f = Cx(&0)`,
+    REPEAT STRIP_TAC THEN ASM_CASES_TAC `(d:complex) dot c <= k` THENL
+     [MATCH_MP_TAC lemma1 THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LE]) THEN
+    MP_TAC(ISPECL [`d:complex`; `b:complex`; `c:complex`; `k:real`]
+          lemma0) THEN
+    MP_TAC(ISPECL [`d:complex`; `a:complex`; `c:complex`; `k:real`]
+          lemma0) THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `a':complex` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `b':complex` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `(a':complex) IN s /\ b' IN s` STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[CONVEX_CONTAINS_SEGMENT; SEGMENT_SYM; SUBSET];
+      ALL_TAC] THEN
+    MP_TAC(SPECL
+     [`f:complex->complex`; `c:complex`; `a:complex`; `a':complex`]
+          PATH_INTEGRAL_SPLIT_LINEPATH) THEN
+    MP_TAC(SPECL
+     [`f:complex->complex`; `b:complex`; `c:complex`; `b':complex`]
+          PATH_INTEGRAL_SPLIT_LINEPATH) THEN
+    ASM_REWRITE_TAC[] THEN REPEAT(ANTS_TAC THENL
+     [ASM_MESON_TAC[CONVEX_CONTAINS_SEGMENT; SEGMENT_SYM;
+                    CONTINUOUS_ON_SUBSET];
+      ONCE_REWRITE_TAC[TAUT `p ==> q ==> r <=> q ==> p ==> r`]]) THEN
+    MP_TAC(ISPECL [`f:complex->complex`; `linepath(a':complex,b')`]
+          PATH_INTEGRAL_REVERSEPATH) THEN
+    REWRITE_TAC[REVERSEPATH_LINEPATH; VALID_PATH_LINEPATH] THEN ANTS_TAC THENL
+     [MATCH_MP_TAC PATH_INTEGRABLE_CONTINUOUS_LINEPATH THEN
+      ASM_MESON_TAC[CONVEX_CONTAINS_SEGMENT; CONTINUOUS_ON_SUBSET];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`f:complex->complex`; `s INTER {x:complex | d dot x <= k}`;
+                   `{}:complex->bool`;
+                   `linepath(a:complex,b) ++ linepath(b,b') ++
+                    linepath(b',a') ++ linepath(a',a)`]
+          CAUCHY_THEOREM_CONVEX) THEN
+    MP_TAC(ISPECL [`f:complex->complex`; `s INTER {x:complex | k <= d dot x}`;
+                   `{}:complex->bool`;
+                   `linepath(b':complex,c) ++ linepath(c,a') ++
+                    linepath(a',b')`]
+          CAUCHY_THEOREM_CONVEX) THEN
+    MATCH_MP_TAC(TAUT
+     `(q /\ q' ==> r) /\ (p /\ p') ==> (p ==> q) ==> (p' ==> q') ==> r`) THEN
+    CONJ_TAC THENL
+     [DISCH_THEN(CONJUNCTS_THEN
+       (fun th -> MP_TAC(MATCH_MP PATH_INTEGRAL_UNIQUE th) THEN
+                  MP_TAC(MATCH_MP HAS_PATH_INTEGRAL_INTEGRABLE th)));
+      ASM_SIMP_TAC[DIFF_EMPTY; INTERIOR_INTER; INTERIOR_HALFSPACE_LE;
+                   REWRITE_RULE[real_ge] INTERIOR_HALFSPACE_GE] THEN
+      ASM_SIMP_TAC[CONVEX_INTER; CONVEX_HALFSPACE_LE; FINITE_EMPTY;
+                   REWRITE_RULE[real_ge] CONVEX_HALFSPACE_GE]] THEN
+    SIMP_TAC[PATH_INTEGRABLE_JOIN; VALID_PATH_JOIN_EQ;
+             PATHSTART_JOIN; PATHFINISH_JOIN; PATH_IMAGE_JOIN;
+             VALID_PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+             PATH_INTEGRAL_JOIN]
+    THENL [CONV_TAC COMPLEX_RING; ALL_TAC] THEN
+    REWRITE_TAC[PATH_IMAGE_LINEPATH; UNION_SUBSET; SUBSET_INTER] THEN
+    ASM_SIMP_TAC[fst(EQ_IMP_RULE(SPEC_ALL CONVEX_CONTAINS_SEGMENT_EQ));
+               CONVEX_HALFSPACE_LE; REWRITE_RULE[real_ge] CONVEX_HALFSPACE_GE;
+                 IN_ELIM_THM; REAL_LT_IMP_LE; REAL_LE_REFL] THEN
+    ASM_SIMP_TAC[complex_differentiable; GSYM HOLOMORPHIC_ON_OPEN;
+                 OPEN_INTER; INTERIOR_OPEN; OPEN_HALFSPACE_LT;
+                 OPEN_HALFSPACE_GT] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[SET_RULE
+     `{x | x IN s /\ P x} = s INTER {x | P x}`]) THEN
+    ASM_REWRITE_TAC[real_gt] THEN
+    ASM_MESON_TAC[INTER_SUBSET; CONTINUOUS_ON_SUBSET]) in
+  let lemma3 = prove
+   (`!f s d k a b c.
+          convex s /\ open s /\ a IN s /\ b IN s /\ c IN s /\ ~(d = vec 0) /\
+          d dot a <= k /\
+          f holomorphic_on {z | z IN s /\ d dot z < k} /\
+          f holomorphic_on {z | z IN s /\ k < d dot z} /\
+          f continuous_on s
+          ==> path_integral (linepath (a,b)) f +
+              path_integral (linepath (b,c)) f +
+              path_integral (linepath (c,a)) f = Cx(&0)`,
+    REPEAT STRIP_TAC THEN ASM_CASES_TAC `(d:complex) dot b <= k` THENL
+     [MATCH_MP_TAC lemma2 THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+    ASM_CASES_TAC `(d:complex) dot c <= k` THENL
+     [ONCE_REWRITE_TAC[COMPLEX_RING `a + b + c:complex = c + a + b`] THEN
+      MATCH_MP_TAC(GEN_ALL lemma2) THEN ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    ONCE_REWRITE_TAC[COMPLEX_RING `a + b + c:complex = b + c + a`] THEN
+    MATCH_MP_TAC(GEN_ALL lemma2) THEN
+    MAP_EVERY EXISTS_TAC
+     [`s:complex->bool`; `--d:real^2`; `--k:real`] THEN
+    ASM_REWRITE_TAC[DOT_LNEG; REAL_LE_NEG2; REAL_LT_NEG2; VECTOR_NEG_EQ_0] THEN
+    ASM_REAL_ARITH_TAC) in
+  let lemma4 = prove
+   (`!f s d k a b c.
+          convex s /\ open s /\ a IN s /\ b IN s /\ c IN s /\ ~(d = vec 0) /\
+          f holomorphic_on {z | z IN s /\ d dot z < k} /\
+          f holomorphic_on {z | z IN s /\ k < d dot z} /\
+          f continuous_on s
+          ==> path_integral (linepath (a,b)) f +
+              path_integral (linepath (b,c)) f +
+              path_integral (linepath (c,a)) f = Cx(&0)`,
+    REPEAT STRIP_TAC THEN ASM_CASES_TAC `(d:complex) dot a <= k` THENL
+     [MATCH_MP_TAC lemma3 THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC lemma3 THEN
+    MAP_EVERY EXISTS_TAC
+     [`s:complex->bool`; `--d:real^2`; `--k:real`] THEN
+    ASM_REWRITE_TAC[DOT_LNEG; REAL_LE_NEG2; REAL_LT_NEG2; VECTOR_NEG_EQ_0] THEN
+    ASM_REAL_ARITH_TAC) in
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ANALYTIC_IMP_HOLOMORPHIC THEN
+  MATCH_MP_TAC MORERA_LOCAL_TRIANGLE THEN
+  X_GEN_TAC `p:complex` THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `p:complex`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `ball(p:complex,e)` THEN
+  ASM_REWRITE_TAC[OPEN_BALL; CENTRE_IN_BALL] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`u:complex`; `v:complex`; `w:complex`] THEN
+  SIMP_TAC[SUBSET_HULL; CONVEX_BALL; INSERT_SUBSET; EMPTY_SUBSET] THEN
+  STRIP_TAC THEN MATCH_MP_TAC lemma4 THEN
+  MAP_EVERY EXISTS_TAC [`ball(p:complex,e)`; `a:complex`; `k:real`] THEN
+  ASM_REWRITE_TAC[CONVEX_BALL; OPEN_BALL] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+    EXISTS_TAC `{z:complex | z IN s /\ a dot z < k}`;
+    MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+    EXISTS_TAC `{z:complex | z IN s /\ k < a dot z}`;
+    MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+    EXISTS_TAC `s:complex->bool`] THEN
+  ASM_REWRITE_TAC[] THEN ASM SET_TAC[]);;
+
+let SCHWARZ_REFLECTION = prove
+ (`!f s. open s /\ (!z. z IN s ==> cnj z IN s) /\
+         f holomorphic_on {z | z IN s /\ &0 < Im z} /\
+         f continuous_on {z | z IN s /\ &0 <= Im z} /\
+         (!z. z IN s /\ real z ==> real(f z))
+         ==> (\z. if &0 <= Im z then f(z) else cnj(f(cnj z)))
+             holomorphic_on s`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HOLOMORPHIC_ON_PASTE_ACROSS_LINE THEN
+  MAP_EVERY EXISTS_TAC [`basis 2:complex`; `&0`] THEN
+  ASM_SIMP_TAC[BASIS_NONZERO; DOT_BASIS; DIMINDEX_2; ARITH] THEN
+  REWRITE_TAC[GSYM IM_DEF] THEN REPEAT CONJ_TAC THENL
+   [UNDISCH_TAC `f holomorphic_on {z | z IN s /\ &0 < Im z}` THEN
+    MATCH_MP_TAC EQ_IMP THEN MATCH_MP_TAC HOLOMORPHIC_EQ THEN
+    SIMP_TAC[IN_ELIM_THM; REAL_LT_IMP_LE];
+    SUBGOAL_THEN
+     `(cnj o f o cnj) holomorphic_on {z | z IN s /\ Im z < &0}`
+    MP_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC EQ_IMP THEN MATCH_MP_TAC HOLOMORPHIC_EQ THEN
+      SIMP_TAC[IN_ELIM_THM; GSYM REAL_NOT_LE; o_THM]] THEN
+    UNDISCH_TAC `f holomorphic_on {z | z IN s /\ &0 < Im z}` THEN
+    REWRITE_TAC[holomorphic_on; IN_ELIM_THM] THEN DISCH_TAC THEN
+    X_GEN_TAC `z:complex` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `cnj z`) THEN
+    ASM_SIMP_TAC[IM_CNJ; REAL_ARITH `&0 < --x <=> x < &0`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `w:complex`
+      (fun th -> EXISTS_TAC `cnj w` THEN MP_TAC th)) THEN
+    REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN; LIM_WITHIN] THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [GSYM FORALL_CNJ] THEN
+    REWRITE_TAC[IN_ELIM_THM; dist; GSYM CNJ_SUB; o_THM] THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [GSYM COMPLEX_NORM_CNJ] THEN
+    REWRITE_TAC[CNJ_SUB; CNJ_DIV; CNJ_CNJ] 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 REPEAT STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[IM_CNJ] THEN ASM_REAL_ARITH_TAC;
+    SUBGOAL_THEN
+     `s = {z | z IN s /\ &0 <= Im z} UNION
+          {z | z IN s /\ Im z <= &0}`
+     (fun th -> SUBST1_TAC th THEN ASSUME_TAC(SYM th))
+    THENL [SET_TAC[REAL_LE_TOTAL]; ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM] THEN
+    REWRITE_TAC[SET_RULE `{z | z IN s /\ P z} = s INTER {z | P z}`] THEN
+    SIMP_TAC[CLOSED_IN_CLOSED_INTER; CLOSED_HALFSPACE_IM_LE;
+             REWRITE_RULE[real_ge] CLOSED_HALFSPACE_IM_GE] THEN
+    CONJ_TAC THENL
+     [REPLICATE_TAC 2
+       (MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_COMPOSE) THEN
+        REWRITE_TAC[CONTINUOUS_ON_CNJ]) THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+      ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM; IN_INTER; IM_CNJ] THEN
+      REAL_ARITH_TAC;
+      X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+      SUBGOAL_THEN `real z` ASSUME_TAC THENL
+       [REWRITE_TAC[real] THEN ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[REAL_CNJ]) THEN ASM_MESON_TAC[]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Bloch's theorem.                                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let BLOCH_LEMMA = prove
+ (`!f a r.
+    &0 < r /\ f holomorphic_on cball(a,r) /\
+    (!z. z IN ball(a,r)
+         ==> norm(complex_derivative f z) <= &2 * norm(complex_derivative f a))
+    ==> ball(f(a),(&3 - &2 * sqrt(&2)) * r * norm(complex_derivative f a))
+        SUBSET IMAGE f (ball(a,r))`,
+  SUBGOAL_THEN
+   `!f r.
+        &0 < r /\ f holomorphic_on cball(Cx(&0),r) /\ f(Cx(&0)) = Cx(&0) /\
+        (!z. z IN ball(Cx(&0),r)
+             ==> norm(complex_derivative f z)
+                 <= &2 * norm(complex_derivative f (Cx(&0))))
+        ==> ball(Cx(&0),
+                 (&3 - &2 * sqrt(&2)) *
+                 r * norm(complex_derivative f (Cx(&0))))
+            SUBSET IMAGE f (ball(Cx(&0),r))`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+     [`\z. (f:complex->complex)(a + z) - f(a)`; `r:real`]) THEN
+    ASM_REWRITE_TAC[COMPLEX_ADD_RID; COMPLEX_SUB_REFL] THEN
+    SUBGOAL_THEN
+     `!z. z IN ball(Cx(&0),r)
+          ==> complex_derivative (\w. f (a + w) - f a) z =
+              complex_derivative f (a + z)`
+     (fun th -> ASM_SIMP_TAC[CENTRE_IN_BALL; COMPLEX_ADD_RID; th])
+    THENL
+     [REWRITE_TAC[COMPLEX_IN_BALL_0] THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+      ONCE_REWRITE_TAC [COMPLEX_RING
+       `complex_derivative f z =
+        complex_derivative f z * (Cx(&0) + Cx(&1)) - Cx(&0)`] THEN
+      MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_SUB THEN
+      REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_CONST] THEN
+      GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+      MATCH_MP_TAC COMPLEX_DIFF_CHAIN_AT THEN
+      SIMP_TAC[HAS_COMPLEX_DERIVATIVE_ADD; HAS_COMPLEX_DERIVATIVE_CONST;
+        HAS_COMPLEX_DERIVATIVE_ID; HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [holomorphic_on]) THEN
+      DISCH_THEN(MP_TAC o SPEC `a + z:complex`) THEN
+      ASM_SIMP_TAC[IN_CBALL; NORM_ARITH `norm z < r ==> dist(a,a+z) <= r`] THEN
+      REWRITE_TAC[GSYM complex_differentiable] THEN
+      DISCH_THEN(MP_TAC o SPEC `ball(a:complex,r)` o
+        MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        COMPLEX_DIFFERENTIABLE_WITHIN_SUBSET)) THEN
+      ASM_REWRITE_TAC[BALL_SUBSET_CBALL] THEN MATCH_MP_TAC EQ_IMP THEN
+      MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_WITHIN_OPEN THEN
+      ASM_REWRITE_TAC[IN_BALL; OPEN_BALL; NORM_ARITH `dist(a,a + z) = norm z`];
+      ANTS_TAC THENL
+       [CONJ_TAC THENL
+         [MATCH_MP_TAC HOLOMORPHIC_ON_SUB THEN
+          REWRITE_TAC[HOLOMORPHIC_ON_CONST] THEN
+          GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+          MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE_GEN THEN
+          EXISTS_TAC `cball(a:complex,r)` THEN
+          ASM_SIMP_TAC[HOLOMORPHIC_ON_ADD; HOLOMORPHIC_ON_ID;
+                       HOLOMORPHIC_ON_CONST; COMPLEX_IN_CBALL_0] THEN
+          REWRITE_TAC[IN_CBALL] THEN NORM_ARITH_TAC;
+          X_GEN_TAC `z:complex` THEN REWRITE_TAC[COMPLEX_IN_BALL_0] THEN
+          STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+          ASM_REWRITE_TAC[IN_BALL; NORM_ARITH `dist(a,a + z) = norm z`]];
+        REWRITE_TAC[SUBSET; COMPLEX_IN_BALL_0; IN_IMAGE] THEN
+        REWRITE_TAC[IN_BALL; ONCE_REWRITE_RULE[DIST_SYM] dist] THEN
+        DISCH_THEN(fun th ->
+         X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+         MP_TAC(SPEC `z - (f:complex->complex) a` th)) THEN
+        ASM_REWRITE_TAC[COMPLEX_RING `z - a:complex = w - a <=> z = w`] THEN
+        DISCH_THEN(X_CHOOSE_TAC `x:complex`) THEN
+        EXISTS_TAC `a + x:complex` THEN
+        ASM_REWRITE_TAC[COMPLEX_ADD_SUB]]]] THEN
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `&0 < &3 - &2 * sqrt(&2)` ASSUME_TAC THENL
+   [REWRITE_TAC[REAL_ARITH `&0 < a - &2 * b <=> b < a / &2`] THEN
+    MATCH_MP_TAC REAL_LT_LSQRT THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_CASES_TAC `&0 < r` THEN ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+  ASM_CASES_TAC `complex_derivative f (Cx(&0)) = Cx(&0)` THEN
+  ASM_SIMP_TAC[COMPLEX_NORM_0; REAL_MUL_RZERO; BALL_TRIVIAL; EMPTY_SUBSET] THEN
+  ABBREV_TAC `C = &2 * norm(complex_derivative f (Cx(&0)))` THEN
+  SUBGOAL_THEN `&0 < C` ASSUME_TAC THENL
+   [ASM_MESON_TAC[COMPLEX_NORM_NZ; REAL_ARITH `&0 < &2 * x <=> &0 < x`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!z. z IN ball(Cx(&0),r)
+        ==> norm(complex_derivative f z - complex_derivative f (Cx(&0)))
+            <= norm(z) / (r - norm(z)) * C`
+  (LABEL_TAC "+") THENL
+   [REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+     `!R. norm z < R /\ R < r
+          ==> norm(complex_derivative f z - complex_derivative f (Cx(&0)))
+              <= norm(z) / (R - norm(z)) * C`
+    MP_TAC THENL
+     [REPEAT STRIP_TAC THEN
+      MP_TAC(ISPECL
+       [`complex_derivative f`;
+        `cball(Cx(&0),R)`;
+        `circlepath(Cx(&0),R)`]
+        CAUCHY_INTEGRAL_FORMULA_CONVEX_SIMPLE) THEN
+      REWRITE_TAC[CONVEX_CBALL; VALID_PATH_CIRCLEPATH; INTERIOR_CBALL;
+                  PATHSTART_CIRCLEPATH; PATHFINISH_CIRCLEPATH] THEN
+      SUBGOAL_THEN `&0 < R` ASSUME_TAC THENL
+       [ASM_MESON_TAC[REAL_LET_TRANS; NORM_POS_LE]; ALL_TAC] THEN
+      ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; REAL_LT_IMP_LE] THEN
+      REWRITE_TAC[sphere; NORM_ARITH `dist(z,w) = norm(w - z)`] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_CBALL; IN_BALL; IN_DELETE] THEN
+      SIMP_TAC[WINDING_NUMBER_CIRCLEPATH; COMPLEX_SUB_RZERO; COMPLEX_SUB_LZERO;
+               dist; NORM_NEG;  REAL_LE_REFL; MESON[REAL_LT_REFL]
+          `norm z < R /\ (!w. norm w = R ==> ~(w = z)) <=> norm z < R`] THEN
+      REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ] THEN ANTS_TAC THENL
+       [MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+        EXISTS_TAC `ball(Cx(&0),r)` THEN CONJ_TAC THENL
+         [MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE THEN
+          REWRITE_TAC[OPEN_BALL] THEN
+          MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+          EXISTS_TAC `cball(Cx(&0),r)` THEN ASM_REWRITE_TAC[BALL_SUBSET_CBALL];
+          ASM_REWRITE_TAC[SUBSET_BALLS; DIST_REFL; REAL_ADD_LID]];
+        REWRITE_TAC[COMPLEX_MUL_LID]] THEN
+      DISCH_THEN(fun th ->
+        MP_TAC (CONJ (SPEC `z:complex` th) (SPEC `Cx(&0)` th))) THEN
+      ASM_REWRITE_TAC[COMPLEX_NORM_0; COMPLEX_SUB_RZERO] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_SUB) THEN
+      DISCH_THEN(MP_TAC o SPEC `C * norm(z) / (R * (R - norm(z:complex)))` o
+        MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+          HAS_PATH_INTEGRAL_BOUND_CIRCLEPATH)) THEN
+      ASM_REWRITE_TAC[GSYM COMPLEX_SUB_LDISTRIB] THEN
+      REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX; COMPLEX_NORM_II] THEN
+      REWRITE_TAC[REAL_ABS_NUM; REAL_MUL_LID; REAL_ABS_PI] THEN
+      ASM_SIMP_TAC[REAL_FIELD
+       `&0 < R /\ z < R
+        ==> (C * z / (R * (R - z))) * &2 * pi * R =
+            &2 * pi * z / (R - z) * C`] THEN
+      ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_ARITH `&0 < &2`; PI_POS] THEN
+      DISCH_THEN MATCH_MP_TAC THEN
+      ASM_SIMP_TAC[REAL_LE_MUL_EQ; REAL_LE_DIV; REAL_LE_MUL; REAL_SUB_LE;
+                   REAL_LT_IMP_LE; NORM_POS_LE; COMPLEX_SUB_RZERO] THEN
+      X_GEN_TAC `x:complex` THEN DISCH_TAC THEN
+      SUBGOAL_THEN `~(x = Cx(&0)) /\ ~(x = z)` STRIP_ASSUME_TAC THENL
+       [ASM_MESON_TAC[REAL_LT_REFL; COMPLEX_NORM_0]; ALL_TAC] THEN
+      ASM_SIMP_TAC[COMPLEX_FIELD
+       `~(x = Cx(&0)) /\ ~(x = z)
+        ==> d / (x - z) - d / x = d * z / (x * (x - z))`] THEN
+      REWRITE_TAC[COMPLEX_NORM_MUL] THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+      ASM_SIMP_TAC[NORM_POS_LE; REAL_LT_IMP_LE; IN_BALL; dist; NORM_NEG;
+                   COMPLEX_SUB_LZERO] THEN
+      REWRITE_TAC[COMPLEX_NORM_DIV; real_div] THEN
+      MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+      MATCH_MP_TAC REAL_LE_INV2 THEN
+      ASM_SIMP_TAC[REAL_LT_MUL; REAL_SUB_LT; COMPLEX_NORM_MUL] THEN
+      ASM_SIMP_TAC[REAL_LE_LMUL_EQ] THEN
+      UNDISCH_TAC `norm(x:complex) = R` THEN CONV_TAC NORM_ARITH;
+      DISCH_TAC THEN MP_TAC(ISPECL
+       [`\x. lift(norm(z:complex) / (drop x - norm z) * C)`;
+        `interval(lift((norm(z:complex) + r) / &2),lift r)`; `lift r`;
+        `norm(complex_derivative f z - complex_derivative f (Cx (&0)))`;
+        `1`] CONTINUOUS_ON_CLOSURE_COMPONENT_GE) THEN
+      REWRITE_TAC[GSYM drop; LIFT_DROP; CLOSURE_INTERVAL] THEN
+      DISCH_THEN MATCH_MP_TAC THEN REWRITE_TAC[INTERVAL_EQ_EMPTY_1] THEN
+      FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_BALL]) THEN
+      REWRITE_TAC[dist; COMPLEX_SUB_LZERO; NORM_NEG] THEN DISCH_TAC THEN
+      ASM_SIMP_TAC[ENDS_IN_INTERVAL; INTERVAL_EQ_EMPTY_1; LIFT_DROP; REAL_ARITH
+        `z < r ==> ~(r <= (z + r) / &2) /\ ~(r < (z + r) / &2)`] THEN
+      REWRITE_TAC[FORALL_LIFT; LIFT_DROP; IN_INTERVAL_1] THEN
+      CONJ_TAC THENL
+       [ALL_TAC;
+        ASM_MESON_TAC[REAL_ARITH `(z + r) / &2 < R /\ R < r ==> z < R`]] THEN
+      REWRITE_TAC[LIFT_CMUL; real_div] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+      REWRITE_TAC[CONTINUOUS_ON_CONST; o_DEF; LIFT_CMUL] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+      REWRITE_TAC[CONTINUOUS_ON_CONST; o_DEF; LIFT_CMUL] THEN
+      MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
+      SIMP_TAC[LIFT_SUB; CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; LIFT_DROP;
+               CONTINUOUS_ON_LIFT_NORM_COMPOSE; CONTINUOUS_ON_ID] THEN
+      REWRITE_TAC[IN_INTERVAL_1; DROP_CMUL; LIFT_DROP] THEN
+      ASM_REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!z.  z IN ball(Cx(&0),r)
+         ==> (norm(z) - norm(z) pow 2 / (r - norm(z))) *
+             norm(complex_derivative f (Cx(&0)))
+             <= norm(f z)`
+  (LABEL_TAC "*") THENL
+   [REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_BALL]) THEN
+    REWRITE_TAC[dist; COMPLEX_SUB_LZERO; NORM_NEG] THEN DISCH_TAC THEN
+    MP_TAC(ISPECL[`\z. f(z) - complex_derivative f (Cx(&0)) * z`;
+                  `\z. complex_derivative f z - complex_derivative f (Cx(&0))`;
+                  `linepath(Cx(&0),z)`; `ball(Cx(&0),r)`]
+        PATH_INTEGRAL_PRIMITIVE) THEN
+    REWRITE_TAC[PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN ANTS_TAC THENL
+     [REWRITE_TAC[VALID_PATH_LINEPATH; PATH_IMAGE_LINEPATH] THEN
+      ONCE_REWRITE_TAC[COMPLEX_RING
+       `a - complex_derivative f b = a - complex_derivative f b * Cx(&1)`] THEN
+      CONJ_TAC THENL
+       [X_GEN_TAC `x:complex` THEN STRIP_TAC THEN
+        MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_SUB THEN
+        SIMP_TAC[HAS_COMPLEX_DERIVATIVE_LMUL_WITHIN;
+                 HAS_COMPLEX_DERIVATIVE_ID] THEN
+        MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_AT_WITHIN THEN
+        REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [holomorphic_on]) THEN
+        DISCH_THEN(MP_TAC o SPEC `x:complex`) THEN
+        ASM_SIMP_TAC[REWRITE_RULE[SUBSET] BALL_SUBSET_CBALL] THEN
+        REWRITE_TAC[GSYM complex_differentiable] THEN
+        DISCH_THEN(MP_TAC o SPEC `ball(Cx(&0),r)` o
+          MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          COMPLEX_DIFFERENTIABLE_WITHIN_SUBSET)) THEN
+        ASM_SIMP_TAC[COMPLEX_DIFFERENTIABLE_WITHIN_OPEN; OPEN_BALL] THEN
+        REWRITE_TAC[BALL_SUBSET_CBALL];
+        MATCH_MP_TAC(REWRITE_RULE[CONVEX_CONTAINS_SEGMENT] CONVEX_BALL) THEN
+        ASM_REWRITE_TAC[CENTRE_IN_BALL]];
+      ALL_TAC] THEN
+    SIMP_TAC[HAS_INTEGRAL_INTEGRABLE_INTEGRAL; HAS_PATH_INTEGRAL_LINEPATH] THEN
+    REWRITE_TAC[COMPLEX_SUB_RZERO; COMPLEX_MUL_RZERO] THEN
+    REWRITE_TAC[linepath; COMPLEX_CMUL; COMPLEX_MUL_RZERO; LIFT_DROP] THEN
+    REWRITE_TAC[COMPLEX_ADD_LID; FORALL_LIFT; IN_INTERVAL_1; LIFT_DROP] THEN
+    STRIP_TAC THEN FIRST_ASSUM(MP_TAC o
+     SPEC `\t. lift(norm(z:complex) pow 2 * drop t / (r - norm(z)) * C)` o
+      MATCH_MP (REWRITE_RULE[IMP_CONJ] INTEGRAL_NORM_BOUND_INTEGRAL)) THEN
+    REWRITE_TAC[linepath; COMPLEX_CMUL; COMPLEX_MUL_RZERO; LIFT_DROP] THEN
+    REWRITE_TAC[COMPLEX_ADD_LID; FORALL_LIFT; IN_INTERVAL_1; LIFT_DROP] THEN
+    REWRITE_TAC[REAL_ARITH `a * b / c * d:real = (a / c * d) * b`] THEN
+    REWRITE_TAC[LIFT_CMUL; LIFT_DROP; DROP_VEC] THEN
+    MP_TAC(ISPECL
+     [`\x. inv(&2) * x pow 2`; `\x:real. x`; `&0`; `&1`]
+        REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS) THEN
+    REWRITE_TAC[REAL_POS] THEN ANTS_TAC THENL
+     [REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN CONV_TAC NUM_REDUCE_CONV THEN
+      REAL_ARITH_TAC;
+      REWRITE_TAC[has_real_integral; o_DEF; IMAGE_LIFT_REAL_INTERVAL] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[LIFT_DROP; LIFT_NUM] THEN
+      DISCH_THEN(MP_TAC o SPEC `norm(z:complex) pow 2 / (r - norm z) * C` o
+        MATCH_MP HAS_INTEGRAL_CMUL) THEN
+      REWRITE_TAC[HAS_INTEGRAL_INTEGRABLE_INTEGRAL] THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[]] THEN
+    ANTS_TAC THENL
+     [X_GEN_TAC `t:real` THEN STRIP_TAC THEN
+      REWRITE_TAC[REAL_ARITH
+        `(z pow 2 / y * c) * t:real = (z / y * t * c) * z`] THEN
+      REWRITE_TAC[COMPLEX_NORM_MUL] THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+      REWRITE_TAC[NORM_POS_LE] THEN
+      REMOVE_THEN "+" (MP_TAC o SPEC `Cx(t) * z`) THEN
+      REWRITE_TAC[IN_BALL; dist; COMPLEX_SUB_LZERO; NORM_NEG] THEN
+      SUBGOAL_THEN `norm(Cx t * z) <= norm z` ASSUME_TAC THENL
+       [GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
+        REWRITE_TAC[COMPLEX_NORM_MUL] THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+        REWRITE_TAC[NORM_POS_LE; COMPLEX_NORM_CX] THEN ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+      ASM_SIMP_TAC[REAL_LE_RMUL_EQ; REAL_MUL_ASSOC; real_div] THEN
+      ASM_REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX; real_abs] THEN
+      GEN_REWRITE_TAC LAND_CONV
+       [REAL_ARITH `(t * z) * w:real = (z * w) * t`] THEN
+      MATCH_MP_TAC REAL_LE_RMUL THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC REAL_LE_MUL2 THEN
+      REWRITE_TAC[NORM_POS_LE; REAL_LE_INV_EQ; REAL_SUB_LE] THEN
+      REWRITE_TAC[REAL_LE_REFL] THEN CONJ_TAC THENL
+       [ALL_TAC; MATCH_MP_TAC REAL_LE_INV2] THEN
+      ASM_REWRITE_TAC[REAL_SUB_LT] THEN FIRST_X_ASSUM(MP_TAC o
+        GEN_REWRITE_RULE LAND_CONV [COMPLEX_NORM_MUL]) THEN
+      REWRITE_TAC[COMPLEX_NORM_CX] THEN ASM_REAL_ARITH_TAC;
+      REWRITE_TAC[COMPLEX_SUB_RZERO]] THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `abc <= norm d - e ==> norm(f - d) <= e ==> abc <= norm f`) THEN
+    REWRITE_TAC[REAL_SUB_RDISTRIB;
+                ONCE_REWRITE_RULE[COMPLEX_MUL_SYM] COMPLEX_NORM_MUL] THEN
+    MATCH_MP_TAC(REAL_ARITH `y <= x ==> a - x <= a - y`) THEN
+    REWRITE_TAC[DROP_CMUL; GSYM REAL_MUL_ASSOC; LIFT_DROP] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; REAL_SUB_LE; REAL_LT_IMP_LE; REAL_LE_POW_2] THEN
+    EXPAND_TAC "C" THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `IMAGE (f:complex->complex)
+                    (ball(Cx(&0),(&1 - sqrt(&2) / &2) * r))` THEN
+  SUBGOAL_THEN `&0 < &1 - sqrt(&2) / &2 /\  &1 - sqrt(&2) / &2 < &1`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[REAL_ARITH
+     `&0 < &1 - s / &2 /\  &1 - s / &2 < &1 <=> &0 < s /\ s < &2`] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_LT_RSQRT; MATCH_MP_TAC REAL_LT_LSQRT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC IMAGE_SUBSET THEN MATCH_MP_TAC SUBSET_BALL THEN
+    REWRITE_TAC[REAL_ARITH `x * r <= r <=> &0 <= r * (&1 - x)`] THEN
+    MATCH_MP_TAC REAL_LE_MUL THEN ASM_REAL_ARITH_TAC] THEN
+  FIRST_ASSUM(fun th ->
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o LAND_CONV) [SYM th]) THEN
+  MATCH_MP_TAC BALL_SUBSET_OPEN_MAP_IMAGE THEN
+  ASM_SIMP_TAC[REAL_LT_MUL; BOUNDED_BALL; CLOSURE_BALL; CENTRE_IN_BALL] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+    EXISTS_TAC `cball(Cx(&0),r)` THEN
+    ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON] THEN
+    MATCH_MP_TAC SUBSET_CBALL THEN
+    REWRITE_TAC[REAL_ARITH `x * r <= r <=> &0 <= r * (&1 - x)`] THEN
+    MATCH_MP_TAC REAL_LE_MUL THEN ASM_REAL_ARITH_TAC;
+    MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+        OPEN_MAPPING_THM) THEN
+    EXISTS_TAC `ball(Cx(&0),r)` THEN
+    ASM_SIMP_TAC[OPEN_BALL; CONNECTED_BALL; INTERIOR_OPEN; SUBSET_REFL] THEN
+    REPEAT CONJ_TAC THENL
+     [ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET; BALL_SUBSET_CBALL];
+      ALL_TAC;
+      MATCH_MP_TAC SUBSET_BALL THEN
+      REWRITE_TAC[REAL_ARITH `x * r <= r <=> &0 <= r * (&1 - x)`] THEN
+      MATCH_MP_TAC REAL_LE_MUL THEN ASM_REAL_ARITH_TAC] THEN
+    DISCH_THEN(X_CHOOSE_TAC `y:complex`) THEN
+    MP_TAC(ISPECL
+     [`f:complex->complex`; `(\x. y):complex->complex`;
+      `ball(Cx(&0),r)`; `Cx(&0)`]
+     COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN) THEN
+    ASM_REWRITE_TAC[OPEN_BALL; HOLOMORPHIC_ON_CONST; COMPLEX_DERIVATIVE_CONST;
+                    CENTRE_IN_BALL] THEN
+    ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET; BALL_SUBSET_CBALL];
+    REPEAT(MATCH_MP_TAC REAL_LT_MUL THEN CONJ_TAC) THEN
+    ASM_REWRITE_TAC[REAL_ARITH `&0 < &3 - &2 * s <=> s < &3 / &2`] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[FRONTIER_BALL; sphere; REAL_LT_MUL; dist; IN_ELIM_THM] THEN
+  X_GEN_TAC `z:complex` THEN REWRITE_TAC[COMPLEX_SUB_LZERO; NORM_NEG] THEN
+  DISCH_TAC THEN REMOVE_THEN "*" (MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[IN_BALL; dist; COMPLEX_SUB_LZERO; COMPLEX_SUB_RZERO] THEN
+  ASM_REWRITE_TAC[NORM_NEG] THEN ANTS_TAC THENL
+   [REWRITE_TAC[REAL_ARITH `x * r < r <=> &0 < r * (&1 - x)`] THEN
+    MATCH_MP_TAC REAL_LT_MUL THEN ASM_REAL_ARITH_TAC;
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_LE_TRANS)] THEN
+  REWRITE_TAC[REAL_MUL_ASSOC] THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+  REWRITE_TAC[NORM_POS_LE; REAL_ARITH `r - (&1 - s) * r = s * r`] THEN
+  REWRITE_TAC[real_div; REAL_INV_MUL; REAL_INV_INV] THEN
+  ASM_SIMP_TAC[REAL_LE_RMUL_EQ; REAL_FIELD
+   `&0 < r
+    ==> a * r - (b * r) pow 2 * x * inv r =  (a - b pow 2 * x) * r`] THEN
+  MATCH_MP_TAC REAL_EQ_IMP_LE THEN
+  MP_TAC(SPEC `&2` SQRT_WORKS) THEN CONV_TAC REAL_FIELD);;
+
+let BLOCH_UNIT = prove
+ (`!f a. f holomorphic_on ball(a,&1) /\
+       complex_derivative f a = Cx(&1)
+       ==> ?b r. &1 / &12 < r /\ ball(b,r) SUBSET IMAGE f (ball(a,&1))`,
+  REPEAT STRIP_TAC THEN ABBREV_TAC `r = &249 / &256` THEN
+  SUBGOAL_THEN `&0 < r` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ABBREV_TAC `g = \z. complex_derivative f z * Cx(r - norm(z - a))` THEN
+  MP_TAC(ISPECL [`IMAGE (g:complex->complex) (cball(a,r))`; `Cx(&0)`]
+        DISTANCE_ATTAINS_SUP) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[IMAGE_EQ_EMPTY; CBALL_EQ_EMPTY] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+    MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN REWRITE_TAC[COMPACT_CBALL] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `ball(a:complex,&1)` THEN
+    REWRITE_TAC[SUBSET_BALLS; DIST_REFL] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN EXPAND_TAC "g" THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON THEN
+      ASM_SIMP_TAC[HOLOMORPHIC_COMPLEX_DERIVATIVE; ETA_AX; OPEN_BALL];
+      REWRITE_TAC[CONTINUOUS_ON_CX_LIFT; LIFT_SUB] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUB THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_LIFT_NORM_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST]];
+    REWRITE_TAC[EXISTS_IN_IMAGE; FORALL_IN_IMAGE; IN_CBALL] THEN
+    REWRITE_TAC[NORM_ARITH `dist(a,b) = norm(b - a)`] THEN
+    REWRITE_TAC[COMPLEX_SUB_RZERO] THEN
+    DISCH_THEN(X_CHOOSE_THEN `p:complex` STRIP_ASSUME_TAC)] THEN
+  SUBGOAL_THEN `norm(p - a:complex) < r` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[REAL_LT_LE] THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `a:complex`) THEN
+    ASM_SIMP_TAC[COMPLEX_SUB_REFL; COMPLEX_NORM_0; REAL_LT_IMP_LE] THEN
+    EXPAND_TAC "g" THEN REWRITE_TAC[COMPLEX_NORM_MUL] THEN
+    ASM_REWRITE_TAC[REAL_SUB_REFL; COMPLEX_SUB_RZERO; COMPLEX_NORM_CX] THEN
+    REWRITE_TAC[COMPLEX_SUB_REFL; COMPLEX_NORM_0] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ABBREV_TAC `t = (r - norm(p - a:complex)) / &2` THEN
+  SUBGOAL_THEN `&0 < t` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  EXISTS_TAC `(f:complex->complex) p` THEN
+  EXISTS_TAC `(&3 - &2 * sqrt (&2)) * t * norm (complex_derivative f p)` THEN
+  MP_TAC(ISPECL [`f:complex->complex`; `p:complex`; `t:real`]
+        BLOCH_LEMMA) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        HOLOMORPHIC_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET_BALLS; dist; COMPLEX_SUB_RZERO] THEN
+      ASM_REAL_ARITH_TAC;
+      X_GEN_TAC `z:complex` THEN REWRITE_TAC[IN_BALL] THEN DISCH_TAC THEN
+      SUBGOAL_THEN `norm(z - a:complex) < r` ASSUME_TAC THENL
+       [REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC; ALL_TAC] THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN EXPAND_TAC "g" THEN
+      REWRITE_TAC[COMPLEX_NORM_MUL] THEN
+      ASM_SIMP_TAC[COMPLEX_NORM_CX; GSYM REAL_LE_RDIV_EQ;
+                   REAL_ARITH `z < r ==> &0 < abs(r - z)`] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+      GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
+      REWRITE_TAC[real_div; GSYM REAL_MUL_ASSOC] THEN
+      MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+      ASM_SIMP_TAC[GSYM real_div; REAL_LE_LDIV_EQ; REAL_ARITH
+       `z < r ==> &0 < abs(r - z)`] THEN
+      REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC];
+    DISCH_TAC THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `a:complex`) THEN
+      ASM_SIMP_TAC[COMPLEX_SUB_REFL; COMPLEX_NORM_0; REAL_LT_IMP_LE] THEN
+      EXPAND_TAC "g" THEN REWRITE_TAC[COMPLEX_NORM_MUL] THEN
+      ASM_REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_NUM; REAL_MUL_LID] THEN
+      ASM_SIMP_TAC[REAL_SUB_RZERO; real_abs; REAL_SUB_LE; REAL_LT_IMP_LE;
+                   COMPLEX_SUB_REFL; COMPLEX_NORM_0] THEN
+      EXPAND_TAC "t" THEN
+      REWRITE_TAC[REAL_ARITH
+       `a < b * c / &2 * d <=> a < (d * c) * (b / &2)`] THEN
+      SUBGOAL_THEN `sqrt (&2) < &2113 / &1494` ASSUME_TAC THENL
+       [MATCH_MP_TAC REAL_LT_LSQRT THEN CONV_TAC REAL_RAT_REDUCE_CONV;
+        ALL_TAC] THEN
+      SUBGOAL_THEN `&0 < &3 - &2 * sqrt(&2)` ASSUME_TAC THENL
+       [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+      ASM_SIMP_TAC[GSYM REAL_LT_LDIV_EQ; REAL_HALF] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_LTE_TRANS) THEN
+      ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_HALF] THEN
+      EXPAND_TAC "r" THEN ASM_REAL_ARITH_TAC;
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        SUBSET_TRANS)) THEN
+      MATCH_MP_TAC IMAGE_SUBSET THEN
+      REWRITE_TAC[SUBSET_BALLS; dist; COMPLEX_SUB_RZERO] THEN
+      REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC]]);;
+
+let BLOCH = prove
+ (`!f a r r'.
+      &0 < r /\ f holomorphic_on ball(a,r) /\
+      r' <= r * norm(complex_derivative f a) / &12
+      ==> ?b. ball(b,r') SUBSET IMAGE f (ball(a,r))`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `complex_derivative f a = Cx(&0)` THENL
+   [ASM_SIMP_TAC[COMPLEX_NORM_0; real_div; REAL_MUL_RZERO; REAL_MUL_LZERO;
+                 BALL_EMPTY; EMPTY_SUBSET];
+    ALL_TAC] THEN
+  ABBREV_TAC `C = complex_derivative f a` THEN
+  SUBGOAL_THEN `&0 < norm(C:complex)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[COMPLEX_NORM_NZ]; STRIP_TAC] THEN
+  MP_TAC(ISPECL
+   [`\z. (f:complex->complex)(a + Cx r * z) / (C * Cx r)`; `Cx(&0)`]
+   BLOCH_UNIT) THEN
+  SUBGOAL_THEN
+   `!z. z IN ball(Cx(&0),&1)
+        ==> ((\z. f (a + Cx r * z) / (C * Cx r)) has_complex_derivative
+             (complex_derivative f (a + Cx r * z) / C)) (at z)`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[COMPLEX_IN_BALL_0] THEN REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+     `complex_derivative f (a + Cx r * z) / C =
+      (complex_derivative f (a + Cx r * z) * Cx r) / (C * Cx r)`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[CX_INJ; REAL_LT_IMP_NZ; COMPLEX_FIELD
+        `~(r = Cx(&0)) /\ ~(c = Cx(&0)) ==> (d * r) / (c * r) = d / c`];
+      ALL_TAC] THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_CDIV_AT THEN
+    GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+    MATCH_MP_TAC COMPLEX_DIFF_CHAIN_AT THEN CONJ_TAC THENL
+     [COMPLEX_DIFF_TAC THEN CONV_TAC COMPLEX_RING; ALL_TAC] THEN
+    REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+    FIRST_ASSUM(MATCH_MP_TAC o
+     MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+       HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT)) THEN
+    REWRITE_TAC[OPEN_BALL; IN_BALL; NORM_ARITH `dist(a,a + b) = norm b`] THEN
+    REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < r ==> (abs r * z < r <=> &0 < r * (&1 - z))`;
+                 REAL_LT_MUL; REAL_SUB_LT];
+    ALL_TAC] THEN
+  ANTS_TAC THENL
+   [SIMP_TAC[HOLOMORPHIC_ON_OPEN; OPEN_BALL] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `Cx(&0)`) THEN
+    ASM_REWRITE_TAC[CENTRE_IN_BALL; REAL_LT_01] THEN
+    DISCH_THEN(SUBST1_TAC o MATCH_MP HAS_COMPLEX_DERIVATIVE_DERIVATIVE) THEN
+    ASM_SIMP_TAC[COMPLEX_MUL_RZERO; COMPLEX_ADD_RID; COMPLEX_DIV_REFL];
+    ALL_TAC] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`b:complex`; `t:real`] THEN STRIP_TAC THEN
+  EXISTS_TAC `(C * Cx r) * b` THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `\z. (C * Cx r) * z` o MATCH_MP IMAGE_SUBSET) THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF] THEN
+  ASM_SIMP_TAC[COMPLEX_DIV_LMUL; COMPLEX_ENTIRE; CX_INJ; REAL_LT_IMP_NZ] THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o LAND_CONV) [GSYM o_DEF] THEN
+  REWRITE_TAC[IMAGE_o] THEN MATCH_MP_TAC(SET_RULE
+   `v SUBSET s /\ t SUBSET w
+    ==> s SUBSET IMAGE f t ==> v SUBSET IMAGE f w`) THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; IN_IMAGE; IN_BALL; dist] THEN
+    X_GEN_TAC `x:complex` THEN DISCH_TAC THEN
+    EXISTS_TAC `x / (C * Cx r)` THEN
+    ASM_SIMP_TAC[COMPLEX_DIV_LMUL; COMPLEX_ENTIRE; CX_INJ; REAL_LT_IMP_NZ] THEN
+    MATCH_MP_TAC REAL_LT_LCANCEL_IMP THEN EXISTS_TAC `norm(C * Cx r)` THEN
+    ASM_SIMP_TAC[COMPLEX_NORM_NZ; COMPLEX_ENTIRE; CX_INJ; REAL_LT_IMP_NZ] THEN
+    REWRITE_TAC[GSYM COMPLEX_NORM_MUL; COMPLEX_SUB_LDISTRIB] THEN
+    ASM_SIMP_TAC[COMPLEX_DIV_LMUL; COMPLEX_ENTIRE; CX_INJ; REAL_LT_IMP_NZ] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      REAL_LTE_TRANS)) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      REAL_LE_TRANS)) THEN
+    REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < r ==> a * abs r = r * a`] THEN
+    ASM_REWRITE_TAC[real_div; GSYM REAL_MUL_ASSOC] THEN
+    ASM_SIMP_TAC[REAL_LE_LMUL_EQ; COMPLEX_NORM_NZ] THEN ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; COMPLEX_IN_BALL_0] THEN
+    REWRITE_TAC[OPEN_BALL; IN_BALL; NORM_ARITH `dist(a,a + b) = norm b`] THEN
+    REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < r ==> (abs r * z < r <=> &0 < r * (&1 - z))`;
+                 REAL_LT_MUL; REAL_SUB_LT]]);;
+
+let BLOCH_COROLLARY = prove
+ (`!f s a t r.
+      f holomorphic_on s /\ a IN s /\
+      (!z. z IN frontier s ==> t <= dist(a,z)) /\
+      r <= t * norm(complex_derivative f a) / &12
+      ==> ?b. ball(b,r) SUBSET IMAGE f s`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(DISJ_CASES_THEN MP_TAC o
+    MATCH_MP (REAL_ARITH `r <= t ==> r <= &0 \/ &0 < t`)) THEN
+  SIMP_TAC[BALL_EMPTY; EMPTY_SUBSET] THEN
+  ASM_CASES_TAC `complex_derivative f a = Cx(&0)` THEN
+  ASM_REWRITE_TAC[COMPLEX_NORM_0] THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_LT_MUL_EQ; REAL_ARITH `&0 < x / &12 <=> &0 < x`;
+               COMPLEX_NORM_NZ] THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN `ball(a:complex,t) SUBSET s` ASSUME_TAC THENL
+   [MP_TAC(ISPECL [`ball(a:complex,t)`; `s:complex->bool`]
+          CONNECTED_INTER_FRONTIER) THEN
+    REWRITE_TAC[CONNECTED_BALL; SET_RULE `s DIFF t = {} <=> s SUBSET t`] THEN
+    MATCH_MP_TAC(TAUT `~p /\ r ==> (~p /\ ~q ==> ~r) ==> q`) THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `a:complex` THEN
+
+      ASM_REWRITE_TAC[IN_INTER; CENTRE_IN_BALL];
+      REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_INTER; IN_BALL] THEN
+      ASM_MESON_TAC[REAL_NOT_LE]];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`f:complex->complex`; `a:complex`; `t:real`; `r:real`] BLOCH) THEN
+  ASM_REWRITE_TAC[] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Schottky's theorem.                                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let SCHOTTKY = prove
+ (`!f r. f holomorphic_on cball(Cx(&0),&1) /\ norm(f(Cx(&0))) <= r /\
+         (!z. z IN cball(Cx(&0),&1) ==> ~(f z = Cx(&0) \/ f z = Cx(&1)))
+         ==> !t z. &0 < t /\ t < &1 /\ norm(z) <= t
+                   ==> norm(f z)
+                       <= exp(pi * exp(pi *
+                                       (&2 + &2 * r + &12 * t / (&1 - t))))`,
+  let lemma0 = prove
+   (`!f s a.
+          f holomorphic_on s /\
+          contractible s /\
+          a IN s /\
+          (!z. z IN s ==> ~(f z = Cx (&1)) /\ ~(f z = --Cx (&1)))
+          ==> (?g. g holomorphic_on s /\
+                   norm(g a) <= &1 + norm(f a) / &3 /\
+                   (!z. z IN s ==> f z = ccos(Cx pi * g z)))`,
+    REPEAT GEN_TAC THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC o MATCH_MP
+          CONTRACTIBLE_IMP_HOLOMORPHIC_ACS_BOUNDED) THEN
+    EXISTS_TAC `\z:complex. g z / Cx pi` THEN
+    ASM_SIMP_TAC[COMPLEX_DIV_LMUL; CX_INJ; PI_NZ; COMPLEX_NORM_DIV;
+                 HOLOMORPHIC_ON_DIV; HOLOMORPHIC_ON_CONST; REAL_LE_LDIV_EQ;
+                 COMPLEX_NORM_CX; REAL_ABS_PI; PI_POS] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `x <= pi + a ==> a * &3 <= n * pi ==> x <= (&1 + n / &3) * pi`)) THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+    MP_TAC PI_APPROX_32 THEN REAL_ARITH_TAC) in
+  let lemma1 = prove
+   (`!n. 0 < n ==> &0 < &n + sqrt(&n pow 2 - &1)`,
+    MESON_TAC[REAL_LTE_ADD; REAL_OF_NUM_LT; SQRT_POS_LE; REAL_POW_LE_1;
+              REAL_SUB_LE; REAL_OF_NUM_LE; LE_1]) in
+  let lemma2 = prove
+   (`!x. &0 <= x
+         ==> ?n. 0 < n /\
+                 abs(x - log(&n + sqrt(&n pow 2 - &1)) / pi) < &1 / &2`,
+    REPEAT STRIP_TAC THEN MP_TAC(SPEC
+     `\n. 0 < n /\ log(&n + sqrt(&n pow 2 - &1)) / pi <= x` num_MAX) THEN
+    SIMP_TAC[] THEN
+    MATCH_MP_TAC(TAUT `p /\ (q ==> r) ==> (p <=> q) ==> r`) THEN
+    REPEAT CONJ_TAC THENL
+     [EXISTS_TAC `1` THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      ASM_REWRITE_TAC[ARITH; SQRT_0; REAL_ADD_RID; LOG_1] THEN
+      REWRITE_TAC[real_div; REAL_MUL_LZERO] THEN ASM_REAL_ARITH_TAC;
+      MP_TAC(ISPEC `exp(x * pi)` REAL_ARCH_SIMPLE) THEN
+      MATCH_MP_TAC MONO_EXISTS THEN
+      X_GEN_TAC `n:num` THEN DISCH_TAC THEN X_GEN_TAC `m:num` THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+      SIMP_TAC[REAL_LE_LDIV_EQ; PI_POS] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM REAL_EXP_MONO_LE] THEN
+      ASM_SIMP_TAC[lemma1; EXP_LOG] THEN
+      REWRITE_TAC[GSYM REAL_OF_NUM_LE] THEN MATCH_MP_TAC(REAL_ARITH
+       `e <= n /\ &0 <= x ==> m + x <= e ==> m <= n`) THEN
+      ASM_SIMP_TAC[SQRT_POS_LE; REAL_POW_LE_1; REAL_SUB_LE;
+                   REAL_OF_NUM_LE; LE_1];
+      DISCH_THEN(X_CHOOSE_THEN `n:num`
+       (CONJUNCTS_THEN2 (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)
+                        (MP_TAC o SPEC `n + 1`))) THEN
+      REWRITE_TAC[ARITH_RULE `~(n + 1 <= n) /\ 0 < n + 1`] THEN
+      REWRITE_TAC[REAL_NOT_LE; IMP_IMP] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+       `x < b /\ a <= x ==> b - a < &1
+        ==> abs(x - a) < &1 / &2 \/ abs(x - b) < &1 / &2`)) THEN
+      ANTS_TAC THENL [ALL_TAC; ASM_MESON_TAC[ARITH_RULE `0 < n + 1`]] THEN
+      REWRITE_TAC[REAL_ARITH `x / pi - y / pi = (x - y) / pi`] THEN
+      SIMP_TAC[PI_POS; REAL_LT_LDIV_EQ; REAL_MUL_LID] THEN
+      MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `&3` THEN
+      CONJ_TAC THENL [ALL_TAC; MP_TAC PI_APPROX_32 THEN REAL_ARITH_TAC] THEN
+      ASM_SIMP_TAC[lemma1; GSYM LOG_DIV; ARITH_RULE `0 < n + 1`] THEN
+      FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (ARITH_RULE
+       `0 < n ==> n = 1 \/ 2 <= n`))
+      THENL
+       [ASM_REWRITE_TAC[] THEN CONV_TAC NUM_REDUCE_CONV THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV THEN
+        REWRITE_TAC[SQRT_0; REAL_ADD_RID; REAL_DIV_1] THEN
+        ONCE_REWRITE_TAC[GSYM REAL_EXP_MONO_LE] THEN
+        SIMP_TAC[EXP_LOG; REAL_LTE_ADD; SQRT_POS_LE; REAL_POS; REAL_OF_NUM_LT;
+                 ARITH] THEN
+        MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `&1 + &3` THEN
+        SIMP_TAC[REAL_EXP_LE_X; REAL_POS] THEN
+        REWRITE_TAC[REAL_ARITH `&2 + s <= a <=> s <= a - &2`] THEN
+        MATCH_MP_TAC REAL_LE_LSQRT THEN CONV_TAC REAL_RAT_REDUCE_CONV;
+        MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `log(&2)` THEN
+        CONJ_TAC THENL
+         [MATCH_MP_TAC LOG_MONO_LE_IMP THEN
+          ASM_SIMP_TAC[lemma1; ARITH_RULE `0 < n + 1`; REAL_LT_DIV;
+                       REAL_LE_LDIV_EQ] THEN
+          REWRITE_TAC[GSYM REAL_OF_NUM_ADD] THEN MATCH_MP_TAC(REAL_ARITH
+           `&1 <= n /\ s <= &2 * t ==> (n + &1) + s <= &2 * (n + t)`) THEN
+          ASM_SIMP_TAC[REAL_OF_NUM_LE; LE_1] THEN
+          MATCH_MP_TAC REAL_LE_LSQRT THEN
+          ASM_SIMP_TAC[REAL_SUB_LE; REAL_POW_LE_1; REAL_ARITH `&1 <= &n + &1`;
+            REAL_ARITH `&0 <= &2 * x <=> &0 <= x`; REAL_POW_MUL; SQRT_POW_2;
+            REAL_LE_MUL; REAL_POS; SQRT_POS_LE; REAL_OF_NUM_LE; LE_1] THEN
+          MATCH_MP_TAC(REAL_ARITH
+           `&2 <= n /\ &2 * n <= n * n
+            ==> (n + &1) pow 2 - &1 <= &2 pow 2 * (n pow 2 - &1)`) THEN
+          ASM_SIMP_TAC[REAL_LE_RMUL; REAL_OF_NUM_LE; LE_0];
+          ONCE_REWRITE_TAC[GSYM REAL_EXP_MONO_LE] THEN
+          SIMP_TAC[EXP_LOG; REAL_OF_NUM_LT; ARITH] THEN
+          MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `&1 + &3` THEN
+          SIMP_TAC[REAL_EXP_LE_X; REAL_POS] THEN REAL_ARITH_TAC]]]) in
+  let lemma3 = prove
+   (`!z.
+      z IN
+       ({complex(m,log(&n + sqrt(&n pow 2 - &1)) / pi) | integer m /\ 0 < n}
+        UNION
+        {complex(m,--log(&n + sqrt(&n pow 2 - &1)) / pi) | integer m /\ 0 < n})
+         ==> ccos(Cx(pi) * ccos(Cx pi * z)) = Cx(&1) \/
+             ccos(Cx(pi) * ccos(Cx pi * z)) = --Cx(&1)`,
+    REWRITE_TAC[COMPLEX_RING
+     `x = Cx(&1) \/ x = --Cx(&1) <=> Cx(&1) - x pow 2 = Cx(&0)`] THEN
+    REWRITE_TAC[COMPLEX_POW_EQ_0; ARITH_EQ; CSIN_EQ_0;
+     REWRITE_RULE[COMPLEX_RING
+     `s pow 2 + c pow 2 = Cx(&1) <=>
+      Cx(&1) - c pow 2 = s pow 2`] CSIN_CIRCLE] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[CX_MUL] THEN
+    REWRITE_TAC[COMPLEX_EQ_MUL_LCANCEL; CX_INJ; PI_NZ] THEN
+    REWRITE_TAC[IN_UNION; TAUT `p \/ q ==> r <=> (p ==> r) /\ (q ==> r)`] THEN
+    REWRITE_TAC[FORALL_AND_THM; FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[complex_mul; RE; IM; RE_CX; IM_CX; REAL_MUL_LZERO] THEN
+    ASM_SIMP_TAC[REAL_DIV_LMUL; PI_NZ; REAL_ADD_RID; REAL_SUB_RZERO] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    REWRITE_TAC[ccos; COMPLEX_MUL_LNEG; CEXP_NEG] THEN CONJ_TAC THENL
+     [ASM_SIMP_TAC[CEXP_NZ; COMPLEX_FIELD
+       `~(e = Cx(&0))
+        ==> ((e + inv e) / Cx(&2) = n <=>
+             inv e pow 2 - Cx(&2) * n * inv e + Cx(&1) = Cx(&0))`];
+      ASM_SIMP_TAC[CEXP_NZ; COMPLEX_FIELD
+       `~(e = Cx(&0))
+        ==> ((e + inv e) / Cx(&2) = n <=>
+             e pow 2 - Cx(&2) * n * e + Cx(&1) = Cx(&0))`]] THEN
+    SIMP_TAC[COMPLEX_TRAD; COMPLEX_RING
+      `ii * (a + ii * b) = --b + ii * a`] THEN
+    REWRITE_TAC[GSYM COMPLEX_TRAD; GSYM CX_NEG; CEXP_COMPLEX] THEN
+    SIMP_TAC[REAL_EXP_NEG; EXP_LOG; lemma1] THEN
+    SIMP_TAC[SIN_INTEGER_PI; REAL_INV_INV] THEN
+    REWRITE_TAC[COMPLEX_TRAD; COMPLEX_MUL_RZERO; COMPLEX_ADD_RID] THEN
+    REWRITE_TAC[GSYM CX_POW; GSYM CX_MUL; GSYM CX_ADD; GSYM CX_ADD;
+                GSYM CX_SUB; GSYM CX_INV; CX_INJ] THEN
+    REWRITE_TAC[REAL_INV_MUL; REAL_INV_INV; REAL_POW_MUL] THEN
+    ONCE_REWRITE_TAC[GSYM COS_ABS] THEN REWRITE_TAC[REAL_ABS_MUL] THEN
+    MAP_EVERY X_GEN_TAC [`i:real`; `n:num`] THEN REWRITE_TAC[integer] THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `m:num` SUBST_ALL_TAC) ASSUME_TAC) THEN
+    REWRITE_TAC[GSYM integer] THEN REWRITE_TAC[real_abs; PI_POS_LE] THEN
+    REWRITE_TAC[COS_NPI; REAL_POW_INV; REAL_POW_POW] THEN
+    REWRITE_TAC[REAL_POW_NEG; EVEN_MULT; ARITH; REAL_POW_ONE] THEN
+    (ASM_CASES_TAC `EVEN m` THEN
+     ASM_REWRITE_TAC[REAL_INV_NEG; REAL_INV_1; REAL_MUL_RID] THEN
+     REWRITE_TAC[REAL_ARITH `a - &2 * n * x * --(&1) = a - &2 * --n * x`] THENL
+      [EXISTS_TAC `&n:real`; EXISTS_TAC `--(&n):real`] THEN
+     REWRITE_TAC[REAL_NEG_NEG; REAL_RING
+     `(n + s) pow 2 - &2 * n * (n + s) + &1 = &0 <=>
+      s pow 2 = n pow 2 - &1`] THEN
+     SIMP_TAC[INTEGER_CLOSED] THEN MATCH_MP_TAC SQRT_POW_2 THEN
+     ASM_SIMP_TAC[REAL_SUB_LE; REAL_POW_LE_1; REAL_OF_NUM_LE; LE_1])) in
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`\z:complex. Cx(&2) * f z - Cx(&1)`; `cball(Cx(&0),&1)`; `Cx(&0)`]
+        lemma0) THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_MUL;
+               HOLOMORPHIC_ON_CONST; CENTRE_IN_CBALL; REAL_POS;
+               COMPLEX_RING `Cx(&2) * z - Cx(&1) = Cx(&1) <=> z = Cx(&1)`;
+               COMPLEX_RING `Cx(&2) * z - Cx(&1) = --Cx(&1) <=> z = Cx(&0)`;
+               CONVEX_IMP_CONTRACTIBLE; CONVEX_CBALL] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:complex->complex` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`h:complex->complex`; `cball(Cx(&0),&1)`; `Cx(&0)`]
+        lemma0) THEN
+  ASM_SIMP_TAC[CENTRE_IN_CBALL; REAL_POS; CONVEX_IMP_CONTRACTIBLE;
+               CONVEX_CBALL] THEN
+  ANTS_TAC THENL
+   [X_GEN_TAC `z:complex` THEN REPEAT STRIP_TAC THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`)) THEN
+    ASM_REWRITE_TAC[COMPLEX_MUL_RID; COMPLEX_MUL_RNEG; CCOS_NEG;
+                    GSYM CX_COS; COS_PI; CX_NEG] THEN
+    CONV_TAC COMPLEX_RING;
+    DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC)] THEN
+  MAP_EVERY UNDISCH_TAC
+   [`!z. z IN cball (Cx (&0),&1)
+          ==> Cx(&2) * f z - Cx(&1) = ccos(Cx pi * h z)`;
+    `!z. z IN cball(Cx(&0),&1) ==> h z = ccos(Cx pi * g z)`] THEN
+  SIMP_TAC[] THEN DISCH_THEN(K ALL_TAC) THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `norm(g(Cx(&0)):complex) <= &2 + norm(f(Cx(&0)):complex)`
+  ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      REAL_LE_TRANS)) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `h <= p ==> p / &3 <= &1 + f ==> &1 + h / &3 <= &2 + f`)) THEN
+    MP_TAC(ISPEC `&1` COMPLEX_NORM_CX) THEN
+    REWRITE_TAC[GSYM COMPLEX_CMUL] THEN CONV_TAC NORM_ARITH;
+    MAP_EVERY (C UNDISCH_THEN (K ALL_TAC))
+     [`h holomorphic_on cball(Cx (&0),&1)`;
+      `norm(g(Cx(&0)):complex) <= &1 + norm(h(Cx(&0)):complex) / &3`;
+      `norm(h(Cx(&0)):complex) <=
+       &1 + norm(Cx(&2) * f(Cx(&0)) - Cx(&1)) / &3`]] THEN
+  MAP_EVERY X_GEN_TAC [`t:real`; `z:complex`] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `z IN ball(Cx(&0),&1)` ASSUME_TAC THENL
+   [REWRITE_TAC[COMPLEX_IN_BALL_0] THEN ASM_REAL_ARITH_TAC;
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP
+      (REWRITE_RULE[SUBSET] BALL_SUBSET_CBALL))] THEN
+  SUBGOAL_THEN
+   `norm(g(z) - g(Cx(&0))) <= &12 * t / (&1 - t)`
+  ASSUME_TAC THENL
+   [FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [holomorphic_on]) THEN
+    REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+    DISCH_THEN(X_CHOOSE_TAC `g':complex->complex`) THEN
+    MP_TAC(ISPECL [`g:complex->complex`; `g':complex->complex`;
+                   `linepath(Cx(&0),z)`; `cball(Cx(&0),&1)`]
+        PATH_INTEGRAL_PRIMITIVE) THEN
+    ASM_REWRITE_TAC[VALID_PATH_LINEPATH; PATH_IMAGE_LINEPATH;
+                    PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+    ASM_SIMP_TAC[CONVEX_CONTAINS_SEGMENT_IMP; CONVEX_CBALL] THEN
+    REWRITE_TAC[CENTRE_IN_CBALL; REAL_POS] THEN
+    DISCH_THEN(MP_TAC o SPEC `&12 / (&1 - t)` o MATCH_MP
+     (ONCE_REWRITE_RULE[IMP_CONJ] HAS_PATH_INTEGRAL_BOUND_LINEPATH)) THEN
+    ANTS_TAC THENL
+     [ASM_SIMP_TAC[REAL_LE_DIV; REAL_POS; REAL_SUB_LT; REAL_LT_IMP_LE] THEN
+      X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+      MP_TAC(ISPECL [`Cx(&0)`; `z:complex`; `w:complex`] SEGMENT_BOUND) THEN
+      ASM_REWRITE_TAC[COMPLEX_SUB_RZERO] THEN STRIP_TAC THEN
+      MP_TAC(ISPECL
+       [`g:complex->complex`; `cball(Cx(&0),&1)`; `w:complex`;
+        `&1 - t`; `&1`] BLOCH_COROLLARY) THEN
+      ASM_REWRITE_TAC[FRONTIER_CBALL; COMPLEX_IN_CBALL_0;
+                      COMPLEX_IN_SPHERE_0] THEN
+      MATCH_MP_TAC(TAUT
+       `p /\ q /\ ~s /\ (~r ==> t) ==> (p /\ q /\ r ==> s) ==> t`) THEN
+      REWRITE_TAC[REAL_NOT_LE] THEN REPEAT CONJ_TAC THENL
+       [ASM_REAL_ARITH_TAC;
+        MAP_EVERY UNDISCH_TAC
+         [`norm(w:complex) <= norm(z:complex)`; `norm(z:complex) <= t`] THEN
+        CONV_TAC NORM_ARITH;
+        MATCH_MP_TAC(SET_RULE
+         `!t u. (!b. (?w. w IN t /\ w IN ball(b,&1)) \/
+                     (?w. w IN u /\ w IN ball(b,&1))) /\
+                (!x. x IN d ==> ~(g x IN t UNION u))
+                ==> ~(?b. ball(b,&1) SUBSET IMAGE g d)`) THEN
+        MAP_EVERY EXISTS_TAC
+         [`{ complex(m,log(&n + sqrt(&n pow 2 - &1)) / pi) |
+              integer m /\ 0 < n}`;
+          `{ complex(m,--log(&n + sqrt(&n pow 2 - &1)) / pi) |
+             integer m /\ 0 < n}`] THEN
+        REWRITE_TAC[EXISTS_IN_GSPEC] THEN CONJ_TAC THENL
+         [X_GEN_TAC `b:complex` THEN REWRITE_TAC[OR_EXISTS_THM] THEN
+          MP_TAC(ISPEC `Re b` INTEGER_ROUND) THEN
+          MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `m:real` THEN
+          STRIP_TAC THEN ASM_REWRITE_TAC[IN_BALL] THEN
+          DISJ_CASES_TAC(REAL_ARITH `&0 <= Im b \/ &0 <= --(Im b)`) THENL
+           [MP_TAC(SPEC `Im b` lemma2); MP_TAC(SPEC `--(Im b)` lemma2)] THEN
+          ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+          X_GEN_TAC `n:num` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
+           [DISJ1_TAC; DISJ2_TAC] THEN
+          REWRITE_TAC[dist] THEN
+          W(MP_TAC o PART_MATCH lhand COMPLEX_NORM_LE_RE_IM o lhand o snd) THEN
+          MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LET_TRANS) THEN
+          MATCH_MP_TAC(REAL_ARITH
+           `x <= &1 / &2 /\ y < &1 / &2 ==> x + y < &1`) THEN
+          ASM_REWRITE_TAC[RE_SUB; IM_SUB; RE; IM] THEN ASM_REAL_ARITH_TAC;
+          X_GEN_TAC `v:complex` THEN DISCH_TAC THEN
+          DISCH_THEN(DISJ_CASES_TAC o MATCH_MP lemma3) THEN
+          REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `v:complex`)) THEN
+          ASM_REWRITE_TAC[] THEN CONV_TAC COMPLEX_RING];
+          REWRITE_TAC[REAL_ARITH `a * c / &12 < &1 <=> c * a < &12`] THEN
+          ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_SUB_LT] THEN MATCH_MP_TAC
+           (NORM_ARITH `x = y ==> norm(x) < d ==> norm(y) <= d`) THEN
+          MATCH_MP_TAC COMPLEX_DERIVATIVE_UNIQUE_AT THEN
+          MAP_EVERY EXISTS_TAC [`g:complex->complex`; `w:complex`] THEN
+          REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+          MATCH_MP_TAC(TAUT `(q ==> p) /\ q ==> p /\ q`) THEN
+          CONJ_TAC THENL [MESON_TAC[complex_differentiable]; ALL_TAC] THEN
+          MATCH_MP_TAC(MESON[]
+           `!s. (g has_complex_derivative g') (at x within s) /\
+                ((g has_complex_derivative g') (at x within s) <=>
+                 (g has_complex_derivative g') (at x))
+                ==> (g has_complex_derivative g') (at x)`) THEN
+          EXISTS_TAC `cball(Cx(&0),&1)` THEN CONJ_TAC THENL
+           [FIRST_X_ASSUM MATCH_MP_TAC THEN
+            REWRITE_TAC[COMPLEX_IN_CBALL_0] THEN ASM_REAL_ARITH_TAC;
+            REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN;
+                        HAS_COMPLEX_DERIVATIVE_AT] THEN
+            MATCH_MP_TAC LIM_WITHIN_INTERIOR THEN
+            REWRITE_TAC[INTERIOR_CBALL; COMPLEX_IN_BALL_0] THEN
+            ASM_REAL_ARITH_TAC]];
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+      ONCE_REWRITE_TAC[REAL_ARITH `&12 * t / s = &12 / s * t`] THEN
+      MATCH_MP_TAC REAL_LE_LMUL THEN
+      ASM_SIMP_TAC[REAL_LE_DIV; REAL_POS; REAL_SUB_LT; REAL_LT_IMP_LE] THEN
+      ASM_REWRITE_TAC[COMPLEX_SUB_RZERO]];
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV)
+     [COMPLEX_RING `y = (Cx(&1) + (Cx(&2) * y - Cx (&1))) / Cx(&2)`] THEN
+    ASM_SIMP_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_CX; REAL_ABS_NUM] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `x / &2 <= y <=> x <= &2 * y`] THEN
+    W(MP_TAC o PART_MATCH lhand NORM_CCOS_PLUS1_LE o lhand o snd) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN
+    REWRITE_TAC[REAL_POS; REAL_EXP_MONO_LE; COMPLEX_NORM_MUL] THEN
+    REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_PI] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[PI_POS_LE] THEN
+    W(MP_TAC o PART_MATCH lhand NORM_CCOS_LE o lhand o snd) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+    REWRITE_TAC[REAL_EXP_MONO_LE; COMPLEX_NORM_MUL] THEN
+    REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_PI] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[PI_POS_LE] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (NORM_ARITH
+     `norm(z - w) <= c ==> norm w <= a + b ==> norm z <= a + b + c`)) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        REAL_LE_TRANS)) THEN
+    UNDISCH_TAC `norm(f(Cx(&0)):complex) <= r` THEN
+    CONV_TAC NORM_ARITH]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The Little Picard Theorem.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let LANDAU_PICARD = prove
+ (`?R. (!z. &0 < R z) /\
+       !f. f holomorphic_on cball(Cx(&0),R(f(Cx(&0)))) /\
+           (!z. z IN cball(Cx(&0),R(f(Cx(&0))))
+                ==> ~(f(z) = Cx(&0)) /\ ~(f(z) = Cx(&1)))
+           ==> norm(complex_derivative f (Cx(&0))) < &1`,
+  ABBREV_TAC
+   `R = \z:complex. &3 * exp(pi * exp(pi * (&2 + &2 * norm(z) + &12)))` THEN
+  EXISTS_TAC `R:complex->real` THEN
+  MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+   [EXPAND_TAC "R" THEN
+    REWRITE_TAC[REAL_EXP_POS_LT; REAL_ARITH `&0 < &3 * x <=> &0 < x`];
+    DISCH_TAC] THEN
+  REPEAT STRIP_TAC THEN
+  ABBREV_TAC `r = (R:complex->real)(f(Cx(&0)))` THEN
+  SUBGOAL_THEN `&0 < r` ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  ABBREV_TAC `g = \z. (f:complex->complex)(Cx r * z)` THEN
+  SUBGOAL_THEN
+   `!z. z IN cball(Cx(&0),&1) ==> (Cx r * z) IN cball(Cx(&0),r)`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[COMPLEX_IN_CBALL_0; COMPLEX_NORM_MUL; COMPLEX_NORM_CX] THEN
+    ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_ARITH
+     `&0 < r ==> (abs r * z <= r <=> r * z <= r * &1)`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `g holomorphic_on cball(Cx(&0),&1)` ASSUME_TAC THENL
+   [EXPAND_TAC "g" THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN
+    SIMP_TAC[HOLOMORPHIC_ON_MUL; HOLOMORPHIC_ON_ID; HOLOMORPHIC_ON_CONST] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      HOLOMORPHIC_ON_SUBSET)) THEN
+    ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`g:complex->complex`; `norm(f(Cx(&0)):complex)`]
+    SCHOTTKY) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [EXPAND_TAC "g" THEN REWRITE_TAC[COMPLEX_MUL_RZERO; REAL_LE_REFL] THEN
+    GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[DE_MORGAN_THM] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `&1 / &2`) THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  MP_TAC(ASSUME `(R:complex->real)(f(Cx(&0))) = r`) THEN
+  EXPAND_TAC "R" THEN
+  SIMP_TAC[REAL_ARITH `&3 * x = r <=> x = r / &3`] THEN
+  DISCH_THEN SUBST1_TAC THEN DISCH_THEN(LABEL_TAC "*") THEN
+  MP_TAC(ISPECL
+   [`g:complex->complex`; `Cx(&0)`; `&1 / &2`; `r / &3`; `1`]
+        CAUCHY_INEQUALITY) THEN
+  CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[HIGHER_COMPLEX_DERIVATIVE_1] THEN
+  ASM_SIMP_TAC[COMPLEX_SUB_LZERO; NORM_NEG; REAL_EQ_IMP_LE] THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON; ALL_TAC] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      HOLOMORPHIC_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET_BALLS; DIST_REFL] THEN CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `complex_derivative g (Cx(&0)) = Cx r * complex_derivative f (Cx(&0))`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN EXPAND_TAC "g" THEN
+    REWRITE_TAC[] THEN ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+    ONCE_REWRITE_TAC[GSYM o_DEF] THEN MATCH_MP_TAC COMPLEX_DIFF_CHAIN_AT THEN
+    CONJ_TAC THENL
+     [COMPLEX_DIFF_TAC THEN REWRITE_TAC[COMPLEX_MUL_LID]; ALL_TAC] THEN
+    REWRITE_TAC[COMPLEX_MUL_LZERO; HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT THEN
+    EXISTS_TAC `ball(Cx(&0),r)` THEN
+    ASM_REWRITE_TAC[OPEN_BALL; CENTRE_IN_BALL] THEN
+    ASM_MESON_TAC[BALL_SUBSET_CBALL; HOLOMORPHIC_ON_SUBSET];
+    REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX] THEN
+    ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_ARITH
+     `&0 < r ==> (abs r * z <= &1 * r / &3 / (&1 / &2) <=>
+                  r * z <= r * &2 / &3)`] THEN
+    REAL_ARITH_TAC]);;
+
+let LITTLE_PICARD = prove
+ (`!f a b.
+      f holomorphic_on (:complex) /\
+      ~(a = b) /\ IMAGE f (:complex) INTER {a,b} = {}
+      ==> ?c. f = \x. c`,
+  let lemma = prove
+   (`!f. f holomorphic_on (:complex) /\
+         (!z. ~(f z = Cx(&0)) /\ ~(f z = Cx(&1)))
+         ==> ?c. f = \x. c`,
+    X_CHOOSE_THEN `R:complex->real` MP_TAC LANDAU_PICARD THEN
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`f:complex->complex`; `(:complex)`]
+      HAS_COMPLEX_DERIVATIVE_ZERO_CONNECTED_CONSTANT) THEN
+    REWRITE_TAC[IN_UNIV; FUN_EQ_THM; CONNECTED_UNIV; OPEN_UNIV] THEN
+    DISCH_THEN MATCH_MP_TAC THEN X_GEN_TAC `w:complex` THEN
+    ASM_CASES_TAC `complex_derivative f w = Cx(&0)` THENL
+     [FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+      REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+      ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT; OPEN_UNIV; IN_UNIV];
+      MATCH_MP_TAC(TAUT `F ==> p`)] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC
+     `\z. (f:complex->complex)(w + z / complex_derivative f w)`) THEN
+    ASM_REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THENL
+     [GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN CONJ_TAC THENL
+       [ALL_TAC; ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET; SUBSET_UNIV]] THEN
+      REWRITE_TAC[HOLOMORPHIC_ON_DIFFERENTIABLE] THEN
+      REPEAT STRIP_TAC THEN COMPLEX_DIFFERENTIABLE_TAC;
+      SUBGOAL_THEN
+       `complex_derivative (\z. f (w + z / complex_derivative f w)) (Cx(&0)) =
+        complex_derivative f w * inv(complex_derivative f w)`
+      SUBST1_TAC THENL
+       [ALL_TAC;
+        ASM_SIMP_TAC[COMPLEX_MUL_RINV; COMPLEX_NORM_CX; REAL_ABS_NUM;
+                     REAL_LT_REFL]] THEN
+      ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+      MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+      MATCH_MP_TAC COMPLEX_DIFF_CHAIN_AT THEN CONJ_TAC THENL
+       [COMPLEX_DIFF_TAC THEN
+        REWRITE_TAC[COMPLEX_ADD_LID; COMPLEX_MUL_LID; complex_div];
+        REWRITE_TAC[complex_div; COMPLEX_MUL_LZERO; COMPLEX_ADD_RID] THEN
+        REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+        ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT; OPEN_UNIV;
+                      IN_UNIV]]]) in
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPEC `\x:complex. Cx(&1) / (b - a) * (f x - b) + Cx(&1)` lemma) THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_ADD; HOLOMORPHIC_ON_MUL; HOLOMORPHIC_ON_SUB;
+               HOLOMORPHIC_ON_CONST] THEN
+  ASM_SIMP_TAC[FUN_EQ_THM; COMPLEX_FIELD
+   `~(a = b)
+    ==> (Cx(&1) / (b - a) * (f - b) + Cx(&1) = c <=>
+         f = b + (b - a) / Cx(&1) * (c - Cx(&1)))`] THEN
+  ANTS_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+   [SET_RULE `IMAGE f UNIV INTER t = {} <=> !x. ~(f x IN t)`]) THEN
+  MATCH_MP_TAC MONO_FORALL THEN
+  REWRITE_TAC[CONTRAPOS_THM; IN_INSERT; NOT_IN_EMPTY] THEN
+  CONV_TAC COMPLEX_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* A couple of little applications of Little Picard.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let HOLOMORPHIC_PERIODIC_FIXPOINT = prove
+ (`!f p. f holomorphic_on (:complex) /\ ~(p = Cx(&0)) /\ (!z. f(z + p) = f(z))
+         ==> ?x. f(x) = x`,
+  REWRITE_TAC[MESON[] `(?x. P x) <=> ~(!x. ~P x)`] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`\z:complex. f(z) - z`; `Cx(&0)`; `p:complex`] LITTLE_PICARD) THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_ID; NOT_IMP] THEN
+  REWRITE_TAC[SET_RULE `IMAGE f UNIV INTER {a,b} = {} <=>
+                          !x. ~(f x = a) /\ ~(f x = b)`] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[COMPLEX_RING `a - b:complex = c <=> a = b + c`;
+                COMPLEX_ADD_RID] THEN
+    ASM_MESON_TAC[];
+    REWRITE_TAC[NOT_EXISTS_THM; FUN_EQ_THM] THEN GEN_TAC THEN
+    DISCH_THEN(fun th ->
+     MP_TAC(SPEC `p + p:complex` th) THEN
+     MP_TAC(SPEC `p:complex` th)) THEN
+    ASM_REWRITE_TAC[] THEN
+    UNDISCH_TAC `~(p = Cx(&0))` THEN CONV_TAC COMPLEX_RING]);;
+
+let HOLOMORPHIC_INVOLUTION_POINT = prove
+ (`!f. f holomorphic_on (:complex) /\ ~(?a. f = \x. a + x) ==> ?x. f(f x) = x`,
+  REWRITE_TAC[MESON[] `(?x. P x) <=> ~(!x. ~P x)`] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `!z:complex. ~(f z = z)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`\x. (f(f x) - x) / (f x - x)`; `Cx(&0)`; `Cx(&1)`]
+        LITTLE_PICARD) THEN
+  REWRITE_TAC[NOT_IMP; CX_INJ; REAL_OF_NUM_EQ; ARITH_EQ] THEN
+  REWRITE_TAC[SET_RULE `IMAGE f UNIV INTER {a,b} = {} <=>
+                          !x. ~(f x = a) /\ ~(f x = b)`] THEN
+  ASM_SIMP_TAC[FUN_EQ_THM; COMPLEX_FIELD
+     `~(a:complex = b) ==> (x / (a - b) = c <=> x = c * (a - b))`] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+    ASM_SIMP_TAC[COMPLEX_SUB_0] THEN CONJ_TAC THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_SUB THEN
+    ASM_REWRITE_TAC[HOLOMORPHIC_ON_ID] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN
+    ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET; SUBSET_UNIV];
+    ASM_REWRITE_TAC[COMPLEX_MUL_LZERO; COMPLEX_MUL_LID; COMPLEX_SUB_0] THEN
+    REWRITE_TAC[COMPLEX_RING `x - a:complex = y - a <=> x = y`] THEN
+    ASM_MESON_TAC[];
+    DISCH_THEN(X_CHOOSE_THEN `c:complex` MP_TAC)] THEN
+  ASM_CASES_TAC `c = Cx(&0)` THEN
+  ASM_REWRITE_TAC[COMPLEX_MUL_LZERO; COMPLEX_SUB_0] THEN
+  ASM_CASES_TAC `c = Cx(&1)` THEN
+  ASM_REWRITE_TAC[COMPLEX_RING `ffx - x = Cx(&1) * (fx - x) <=> ffx = fx`] THEN
+  REWRITE_TAC[COMPLEX_RING
+   `ffx - x = c * (fx - x) <=> (ffx - c * fx) = x * (Cx(&1) - c)`] THEN
+  DISCH_TAC THEN
+  MP_TAC(SPECL
+   [`complex_derivative f o f`; `Cx(&0)`; `c:complex`] LITTLE_PICARD) THEN
+  REWRITE_TAC[SET_RULE `IMAGE f UNIV INTER {a,b} = {} <=>
+                          !x. ~(f x = a) /\ ~(f x = b)`] THEN
+  ASM_REWRITE_TAC[o_THM; NOT_IMP] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN
+    ASM_MESON_TAC[HOLOMORPHIC_COMPLEX_DERIVATIVE; OPEN_UNIV; SUBSET_UNIV;
+                  HOLOMORPHIC_ON_SUBSET];
+    MP_TAC(MATCH_MP MONO_FORALL (GEN `z:complex` (SPECL
+     [`\x:complex. f(f x) - c * f x`; `z:complex`;
+      `complex_derivative f z * (complex_derivative f (f z) - c)`;
+      `Cx(&1) * (Cx(&1) - c)`] COMPLEX_DERIVATIVE_UNIQUE_AT))) THEN
+    ANTS_TAC THENL
+     [REPEAT STRIP_TAC THENL
+       [REWRITE_TAC[COMPLEX_RING `a * (b - c):complex = b * a - c * a`] THEN
+        MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_SUB THEN CONJ_TAC THENL
+         [ONCE_REWRITE_TAC[GSYM o_DEF] THEN MATCH_MP_TAC COMPLEX_DIFF_CHAIN_AT;
+          MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_LMUL_AT] THEN
+        REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+        ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT; IN_UNIV; OPEN_UNIV];
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_RMUL_AT THEN
+        REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_ID]];
+      DISCH_THEN(fun th -> X_GEN_TAC `z:complex` THEN REPEAT STRIP_TAC THEN
+                        MP_TAC th)
+      THENL [DISCH_THEN(MP_TAC o SPEC `(f:complex->complex) z`);
+             DISCH_THEN(MP_TAC o SPEC `z:complex`)] THEN
+      ASM_REWRITE_TAC[] THEN
+      UNDISCH_TAC `~(c = Cx(&1))` THEN CONV_TAC COMPLEX_RING];
+      REWRITE_TAC[FUN_EQ_THM; o_THM] THEN
+      DISCH_THEN(X_CHOOSE_TAC `k:complex`) THEN
+      SUBGOAL_THEN `open(IMAGE (f:complex->complex) (:complex))`
+      ASSUME_TAC THENL
+       [MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+         OPEN_MAPPING_THM) THEN
+        EXISTS_TAC `(:complex)` THEN
+        ASM_REWRITE_TAC[OPEN_UNIV; CONNECTED_UNIV; SUBSET_UNIV; IN_UNIV] THEN
+        ASM_MESON_TAC[];
+        ALL_TAC] THEN
+      MP_TAC(ISPECL
+        [`\z. complex_derivative f z - k`; `(:complex)`;
+         `IMAGE (f:complex->complex) (:complex)`; `(f:complex->complex) z`]
+        ANALYTIC_CONTINUATION) THEN
+      REWRITE_TAC[OPEN_UNIV; CONNECTED_UNIV; SUBSET_UNIV; IN_UNIV] THEN
+      ASM_REWRITE_TAC[FORALL_IN_IMAGE; COMPLEX_SUB_0; NOT_IMP] THEN
+      REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC HOLOMORPHIC_ON_SUB THEN REWRITE_TAC[ETA_AX] THEN
+        ASM_MESON_TAC[HOLOMORPHIC_COMPLEX_DERIVATIVE; OPEN_UNIV; SUBSET_UNIV;
+                      HOLOMORPHIC_ON_SUBSET; HOLOMORPHIC_ON_CONST];
+        MATCH_MP_TAC LIMPT_OF_OPEN THEN ASM_REWRITE_TAC[] THEN SET_TAC[];
+        DISCH_TAC] THEN
+      MP_TAC(ISPECL
+       [`\x:complex. f x - k * x`; `(:complex)`]
+        HAS_COMPLEX_DERIVATIVE_ZERO_CONNECTED_CONSTANT) THEN
+      REWRITE_TAC[OPEN_UNIV; CONNECTED_UNIV; IN_UNIV; NOT_IMP] THEN
+      CONJ_TAC THENL
+       [X_GEN_TAC `z:complex` THEN
+        SUBST1_TAC(COMPLEX_RING `Cx(&0) = k - k * Cx(&1)`) THEN
+        MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_SUB THEN CONJ_TAC THENL
+         [ASM_MESON_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE;
+                        HOLOMORPHIC_ON_OPEN; OPEN_UNIV; IN_UNIV;
+                        complex_differentiable];
+          COMPLEX_DIFF_TAC THEN CONV_TAC COMPLEX_RING];
+        DISCH_THEN(X_CHOOSE_THEN `l:complex` MP_TAC) THEN
+        REWRITE_TAC[COMPLEX_RING `a - b:complex = c <=> a = b + c`] THEN
+        DISCH_THEN(fun th -> RULE_ASSUM_TAC(REWRITE_RULE[th; FUN_EQ_THM])) THEN
+        ASM_CASES_TAC `k = Cx(&1)` THENL
+         [UNDISCH_TAC `!a:complex. ~(!x. k * x + l = a + x)` THEN
+          ASM_REWRITE_TAC[COMPLEX_MUL_LID] THEN MESON_TAC[COMPLEX_ADD_SYM];
+          UNDISCH_TAC `!z:complex. ~(k * z + l = z)` THEN
+          ASM_SIMP_TAC[COMPLEX_FIELD
+           `~(k = Cx(&1)) ==> (k * z + l = z <=> z = l / (Cx(&1) - k))`] THEN
+          MESON_TAC[]]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Montel's theorem: a sequence of holomorphic functions uniformly bounded   *)
+(* on compact subsets of an open set S has a subsequence that converges to a *)
+(* holomorphic function, and converges *uniformly* on compact subsets of S.  *)
+(* ------------------------------------------------------------------------- *)
+
+let MONTEL = prove
+ (`!(f:num->complex->complex) p s.
+    open s /\ (!h. h IN p ==> h holomorphic_on s) /\
+    (!k. compact k /\ k SUBSET s
+         ==> ?b. !h z. h IN p /\ z IN k ==> norm(h z) <= b) /\
+    (!n. (f n) IN p)
+    ==> ?g r. g holomorphic_on s /\
+              (!m n:num. m < n ==> r m < r n) /\
+              (!x. x IN s ==> ((\n. f (r n) x) --> g(x)) sequentially) /\
+              (!k e. compact k /\ k SUBSET s /\ &0 < e
+                     ==> ?N. !n x. n >= N /\ x IN k
+                                   ==> norm(f (r n) x - g x) < e)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  SPEC_TAC(`f:num->complex->complex`,`f:num->complex->complex`) THEN
+  REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; GSYM GE; dist] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_UNION_COMPACT_SUBSETS) THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:num->complex->bool`
+   (fun th -> FIRST_X_ASSUM(MP_TAC o GEN `i:num `o
+                SPEC `(k:num->complex->bool) i`) THEN
+              STRIP_ASSUME_TAC th)) THEN
+  ASM_REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `B:num->real` THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `!(f:num->complex->complex) (i:num).
+        (!n. f n IN p)
+        ==>  ?r g. (!m n:num. m < n ==> r m < r n) /\
+                   (!e. &0 < e ==> ?N. !n x. n >= N /\ x IN k i
+                                             ==> norm((f o r) n x - g x) < e)`
+  MP_TAC THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[o_THM] THEN
+    MP_TAC(ISPECL [`f:num->complex->complex`; `(k:num->complex->bool) i`;
+                   `(B:num->real) i`] ARZELA_ASCOLI) THEN
+    ANTS_TAC THENL [ASM_SIMP_TAC[]; MESON_TAC[]] THEN
+    MAP_EVERY X_GEN_TAC [`z:complex`; `e:real`] THEN STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[SUBSET; IN_CBALL]] THEN
+    DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `?M. &0 < M /\
+          !n w. dist(z,w) <= &2 / &3 * r
+                ==> norm((f:num->complex->complex) n w) <= M`
+    STRIP_ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `cball(z:complex,&2 / &3 * r)`) THEN
+      ASM_SIMP_TAC[SUBSET; IN_CBALL; COMPACT_CBALL;
+              NORM_ARITH `dist(a,b) <= &2 / &3 * r ==> dist(a,b) <= r`] THEN
+      DISCH_THEN(X_CHOOSE_THEN `N:num` (MP_TAC o SPEC `N:num`)) THEN
+      REWRITE_TAC[GE; LE_REFL] THEN DISCH_TAC THEN
+      EXISTS_TAC `abs(B(N:num)) + &1` THEN
+      REWRITE_TAC[REAL_ARITH `&0 < abs x + &1`] THEN
+      ASM_MESON_TAC[SUBSET; REAL_ARITH `x <= b ==> x <= abs b + &1`];
+      ALL_TAC] THEN
+    EXISTS_TAC `min (r / &3) ((e * r) / (&6 * M))` THEN
+    ASM_SIMP_TAC[REAL_LT_MIN; REAL_LT_DIV;
+                 REAL_LT_MUL; REAL_OF_NUM_LT; ARITH] THEN
+    MAP_EVERY X_GEN_TAC [`n:num`; `y:complex`] THEN STRIP_TAC THEN
+    MP_TAC
+     (ISPECL [`(f:num->complex->complex) n`;  `cball(z:complex,&2 / &3 * r)`;
+              `circlepath(z:complex,&2 / &3 * r)`]
+        CAUCHY_INTEGRAL_FORMULA_CONVEX_SIMPLE) THEN
+    REWRITE_TAC[CONVEX_CBALL; VALID_PATH_CIRCLEPATH] THEN
+    REWRITE_TAC[PATHSTART_CIRCLEPATH; PATHFINISH_CIRCLEPATH] THEN
+    SIMP_TAC[INTERIOR_CBALL; IN_BALL; WINDING_NUMBER_CIRCLEPATH;
+             NORM_ARITH `dist(z,w) = norm(w - z)`] THEN
+    ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH;
+                 REAL_ARITH `&0 < r ==> &0 <= &2 / &3 * r`] THEN
+    REWRITE_TAC[sphere; NORM_ARITH `dist(z,w) = norm(w - z)`] THEN
+    SIMP_TAC[SUBSET; IN_CBALL; IN_DELETE; IN_ELIM_THM; REAL_LE_REFL;
+             NORM_ARITH `dist(z,w) = norm(w - z)`] THEN
+    ONCE_REWRITE_TAC[TAUT `p ==> ~q <=> q ==> ~p`] THEN
+    SIMP_TAC[FORALL_UNWIND_THM2; IMP_CONJ; REAL_LT_IMP_NE] THEN
+    REWRITE_TAC[RIGHT_FORALL_IMP_THM; COMPLEX_MUL_LID] THEN ANTS_TAC THENL
+     [MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+      EXISTS_TAC `s:complex->bool` THEN ASM_SIMP_TAC[SUBSET; IN_CBALL] THEN
+      ASM_SIMP_TAC[NORM_ARITH `dist(a,b) <= &2 / &3 * r ==> dist(a,b) <= r`];
+      ALL_TAC] THEN
+    DISCH_THEN(fun th ->
+      MP_TAC(SPEC `y:complex` th) THEN MP_TAC(SPEC `z:complex` th)) THEN
+    ASM_SIMP_TAC[VECTOR_SUB_REFL; NORM_0; REAL_LT_MUL; REAL_LT_DIV;
+      REAL_OF_NUM_LT; ARITH; NORM_ARITH
+       `norm(z - y) < r / &3 ==> norm(y - z) < &2 / &3 * r`] THEN
+    REWRITE_TAC[IMP_IMP] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_SUB) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        HAS_PATH_INTEGRAL_BOUND_CIRCLEPATH)) THEN
+    REWRITE_TAC[GSYM COMPLEX_SUB_LDISTRIB; COMPLEX_NORM_MUL] THEN
+    REWRITE_TAC[COMPLEX_NORM_II; COMPLEX_NORM_CX; REAL_ABS_PI;
+                REAL_ABS_NUM; REAL_MUL_LID] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / r:real`) THEN
+    ASM_SIMP_TAC[REAL_FIELD
+     `&0 < r ==> e / r * &2 * pi * c * r = &2 * pi * e * c`] THEN
+    SIMP_TAC[REAL_LE_LMUL_EQ; REAL_OF_NUM_LT; ARITH; PI_POS] THEN
+    ANTS_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH;
+                 REAL_LT_MUL] THEN
+    X_GEN_TAC `w:complex` THEN STRIP_TAC THEN
+    SUBGOAL_THEN `~(w:complex = z) /\ ~(w = y)` STRIP_ASSUME_TAC THENL
+     [CONJ_TAC THEN DISCH_THEN SUBST_ALL_TAC THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[NORM_0; VECTOR_SUB_REFL]) THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[NORM_SUB]) THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[COMPLEX_FIELD
+     `~(w:complex = z) /\ ~(w = y)
+      ==> (a / (w - z) - a / (w - y) =
+           (a * (z - y)) / ((w - z) * (w - y)))`] THEN
+    REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_DIV] THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LT_MUL; NORM_POS_LT; VECTOR_SUB_EQ;
+     REAL_FIELD `&0 < r ==> e / r * (&2 / &3 * r) * x = &2 / &3 * e * x`] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `M * (e * r) / (&6 * M)` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_LE_MUL2 THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE; NORM_POS_LE] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REWRITE_TAC[NORM_ARITH `dist(x,y) = norm(y - x)`; REAL_LE_REFL];
+      ASM_SIMP_TAC[REAL_FIELD `&0 < M ==> M * e / (&6 * M) = e / &6`] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `&0 < x /\ x <= y * &3 ==> x / &6 <= &2 / &3 * y`) THEN
+      ASM_SIMP_TAC[REAL_LT_MUL; GSYM REAL_MUL_ASSOC; REAL_LE_LMUL_EQ] THEN
+      MAP_EVERY UNDISCH_TAC
+       [`norm(w - z:complex) = &2 / &3 * r`;
+        `norm(z - y:complex) < r / &3`] THEN
+      CONV_TAC NORM_ARITH];
+    ALL_TAC] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+  DISCH_THEN(fun th -> X_GEN_TAC `f:num->complex->complex` THEN
+                       DISCH_TAC THEN MP_TAC th) THEN
+  DISCH_THEN(MP_TAC o GENL [`i:num`; `r:num->num`] o
+    SPECL [`(f:num->complex->complex) o (r:num->num)`; `i:num`]) THEN
+  GEN_REWRITE_TAC
+   (LAND_CONV o funpow 2 BINDER_CONV o LAND_CONV o ONCE_DEPTH_CONV)
+   [o_THM] THEN ASM_REWRITE_TAC[GSYM o_ASSOC] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+    SUBSEQUENCE_DIAGONALIZATION_LEMMA)) THEN
+  ANTS_TAC THENL
+   [SIMP_TAC[o_THM; GE] THEN REPEAT GEN_TAC THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:complex->complex` THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN
+    MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_TAC `M:num`) THEN
+    EXISTS_TAC `MAX M N` THEN
+    REWRITE_TAC[ARITH_RULE `MAX m n <= x <=> m <= x /\ n <= x`] THEN
+    ASM_MESON_TAC[LE_TRANS];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `I:num->num`) THEN
+  REWRITE_TAC[I_O_ID; RIGHT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `r:num->num` THEN
+  REWRITE_TAC[o_THM] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `!x. x IN s
+        ==> ?l. !e. &0 < e
+                    ==> ?N:num. !n. n >= N
+                                ==> norm((f:num->complex->complex) (r n) x - l)
+                                    < e`
+  MP_TAC THENL
+   [X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `{z:complex}`) THEN
+    ASM_REWRITE_TAC[COMPACT_SING; SING_SUBSET] THEN
+    DISCH_THEN(X_CHOOSE_THEN `N:num` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SKOLEM_THM]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `G:num->complex->complex` MP_TAC) THEN
+    DISCH_THEN(LABEL_TAC "*" o SPEC `N:num`) THEN
+    EXISTS_TAC `(G:num->complex->complex) N z` THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    REMOVE_THEN "*" (MP_TAC o SPEC `e:real`) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `M:num` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `MAX M N` THEN
+    REWRITE_TAC[ARITH_RULE `a >= MAX m n <=> a >= m /\ a >= n`] THEN
+    ASM_MESON_TAC[GE_REFL];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; RIGHT_IMP_FORALL_THM; IMP_IMP] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:complex->complex` THEN
+  DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`t:complex->bool`; `e:real`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `t:complex->bool`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_TAC `N:num`) THEN
+    FIRST_X_ASSUM(X_CHOOSE_THEN `h:complex->complex` (LABEL_TAC "*") o
+      SPEC `N:num`) THEN
+    SUBGOAL_THEN
+     `!w. w IN t ==> g w = (h:complex->complex) w`
+     (fun th -> ASM_MESON_TAC[GE_REFL; SUBSET; th]) THEN
+    X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+    MATCH_MP_TAC(ISPEC `sequentially` LIM_UNIQUE) THEN
+    EXISTS_TAC `\n:num. (f:num->complex->complex)(r n) w` THEN
+    ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; LIM_SEQUENTIALLY] THEN
+    REWRITE_TAC[GSYM GE; dist; o_THM] THEN
+    ASM_MESON_TAC[SUBSET; GE_REFL];
+    DISCH_THEN(LABEL_TAC "*")] THEN
+  MATCH_MP_TAC HOLOMORPHIC_UNIFORM_SEQUENCE THEN
+  EXISTS_TAC `(f:num->complex->complex) o (r:num->num)` THEN
+  ASM_SIMP_TAC[o_THM] THEN X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN ASM_MESON_TAC[COMPACT_CBALL; GE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Moebius functions are biholomorphisms of the unit disc.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let moebius_function = new_definition
+  `!t w z. moebius_function t w z =
+           cexp (ii * Cx t) * (z - w) / (Cx(&1) - cnj w * z)`;;
+
+let MOEBIUS_FUNCTION_SIMPLE = prove
+ (`!w z. moebius_function (&0) w z = (z - w) / (Cx(&1) - cnj w * z)`,
+  REWRITE_TAC[moebius_function; COMPLEX_MUL_RZERO; CEXP_0; COMPLEX_MUL_LID]);;
+
+let MOEBIUS_FUNCTION_EQ_ZERO = prove
+  (`!t w. moebius_function t w w = Cx(&0)`,
+   REWRITE_TAC [moebius_function] THEN CONV_TAC COMPLEX_FIELD);;
+
+let MOEBIUS_FUNCTION_OF_ZERO = prove
+  (`!t w. moebius_function t w (Cx(&0)) = -- cexp (ii * Cx t) * w`,
+   REWRITE_TAC [moebius_function] THEN CONV_TAC COMPLEX_FIELD);;
+
+let MOEBIUS_FUNCTION_NORM_LT_1 = prove
+  (`!t w z. norm w < &1 /\ norm z < &1
+            ==> norm (moebius_function t w z) < &1`,
+   REPEAT STRIP_TAC THEN SUBGOAL_THEN
+     `!a. &0 <= a /\ &0 < &1 - a pow 2 ==> a < &1` MATCH_MP_TAC THENL
+   [GEN_TAC THEN ASM_CASES_TAC `&0 <= a` THEN
+    ASM_REWRITE_TAC [REAL_FIELD `&1 - a pow 2 = (&1 - a) * (&1 + a)`;
+                     REAL_MUL_POS_LT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+   REWRITE_TAC [NORM_POS_LE] THEN
+   SUBGOAL_THEN `~(Cx (&1) - cnj w * z = Cx (&0))` ASSUME_TAC THENL
+   [REWRITE_TAC [COMPLEX_SUB_0] THEN
+    SUBGOAL_THEN `~(norm (Cx(&1)) = norm (cnj w * z))`
+     (fun th -> MESON_TAC [th]) THEN
+    REWRITE_TAC [COMPLEX_NORM_NUM; COMPLEX_NORM_MUL; COMPLEX_NORM_CNJ] THEN
+    MATCH_MP_TAC (REAL_ARITH `a * b < &1  ==> ~(&1 = a * b)`) THEN
+    STRIP_ASSUME_TAC (NORM_ARITH `norm (z:complex) = &0 \/ &0 < norm z`) THENL
+    [ASM_REWRITE_TAC [REAL_MUL_RZERO; REAL_LT_01];
+     MATCH_MP_TAC REAL_LT_TRANS THEN EXISTS_TAC `&1 * norm (z:complex)` THEN
+     ASM_SIMP_TAC[REAL_LT_RMUL; REAL_MUL_LID]];
+   ALL_TAC] THEN
+   SUBGOAL_THEN
+    `&1 - norm (moebius_function t w z) pow 2 =
+     ((&1 - norm w pow 2) / (norm (Cx(&1) - cnj w * z) pow 2)) *
+     (&1 - norm z pow 2)`
+   SUBST1_TAC THENL
+   [REWRITE_TAC [moebius_function;
+                 GSYM CX_INJ; CX_SUB; CX_MUL; CX_DIV; CX_POW; CNJ_SUB; CNJ_CX;
+                 CNJ_MUL; CNJ_DIV; CNJ_CNJ; COMPLEX_NORM_POW_2] THEN
+    SUBGOAL_THEN
+      `cnj (cexp (ii * Cx t)) * (cexp (ii * Cx t)) = Cx(&1) /\
+       ~(Cx(&1) - cnj w * z = Cx(&0)) /\ ~(Cx(&1) - w * cnj z = Cx(&0))`
+     MP_TAC THENL [ALL_TAC; CONV_TAC COMPLEX_FIELD] THEN
+    REWRITE_TAC [CNJ_CEXP; CNJ_MUL; CNJ_II; CNJ_CX;
+                  COMPLEX_MUL_LNEG; CEXP_NEG_LMUL] THEN ASM_REWRITE_TAC [] THEN
+    SUBGOAL_THEN `~(cnj (Cx (&1) - cnj w * z) = Cx (&0))` MP_TAC THENL
+    [ASM_REWRITE_TAC [CNJ_EQ_0];
+     REWRITE_TAC [CNJ_SUB; CNJ_CX; CNJ_MUL; CNJ_CNJ]];
+    SUBGOAL_THEN `!u:complex. norm u < &1 ==> &0 < &1 - norm u pow 2`
+      ASSUME_TAC THENL
+    [REWRITE_TAC [REAL_FIELD `!a. &1 - a pow 2 = (&1 - a) * (&1 + a)`] THEN
+     ASM_SIMP_TAC [REAL_LT_MUL; REAL_SUB_LT; REAL_LTE_ADD; REAL_LT_01;
+                   NORM_POS_LE];
+     SUBGOAL_THEN `&0 < norm (Cx (&1) - cnj w * z) pow 2`
+      (fun th -> ASM_MESON_TAC [th; REAL_LT_MUL; REAL_LT_DIV]) THEN
+     ASM_REWRITE_TAC [REAL_RING `!a:real. a pow 2 =  a * a`;
+                      REAL_LT_SQUARE; COMPLEX_NORM_ZERO]]]);;
+
+let MOEBIUS_FUNCTION_HOLOMORPHIC = prove
+  (`!t w. norm w < &1 ==> moebius_function t w holomorphic_on ball(Cx(&0),&1)`,
+   let LEMMA_1 = prove
+    (`!a b:complex. norm a < &1 /\ norm b < &1 ==> ~(Cx(&1) - a * b = Cx(&0))`,
+     GEN_TAC THEN GEN_TAC THEN STRIP_TAC THEN REWRITE_TAC [COMPLEX_SUB_0] THEN
+     SUBGOAL_THEN `~(norm (Cx(&1)) = norm (a * b))`
+       (fun th -> MESON_TAC[th]) THEN
+     REWRITE_TAC [COMPLEX_NORM_NUM; COMPLEX_NORM_MUL] THEN
+     MATCH_MP_TAC (REAL_ARITH `!x y. y < x ==> ~(x = y)`) THEN
+     ASM_CASES_TAC `b = Cx(&0)` THEN
+     ASM_REWRITE_TAC [COMPLEX_NORM_NUM; REAL_MUL_RZERO; REAL_LT_01] THEN
+     MATCH_MP_TAC REAL_LT_TRANS THEN EXISTS_TAC `&1 * norm (b:complex)` THEN
+     CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_LT_RMUL THEN ASM_REWRITE_TAC [COMPLEX_NORM_NZ];
+      ASM_REWRITE_TAC [REAL_MUL_LID]]) in
+   REPEAT STRIP_TAC THEN
+   SUBST1_TAC (GSYM (ISPEC `moebius_function t w` ETA_AX)) THEN
+   REWRITE_TAC [moebius_function] THEN
+   MATCH_MP_TAC HOLOMORPHIC_ON_MUL THEN  CONJ_TAC THENL
+   [MATCH_MP_TAC (REWRITE_RULE [o_DEF] HOLOMORPHIC_ON_COMPOSE_GEN) THEN
+    EXISTS_TAC `(:complex)` THEN REWRITE_TAC [HOLOMORPHIC_ON_CEXP; IN_UNIV] THEN
+    SIMP_TAC [HOLOMORPHIC_ON_MUL; HOLOMORPHIC_ON_CONST];
+    MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+    SIMP_TAC[HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_CONST;
+             HOLOMORPHIC_ON_ID; HOLOMORPHIC_ON_MUL] THEN
+    ASM_SIMP_TAC[COMPLEX_IN_BALL_0; LEMMA_1; COMPLEX_NORM_CNJ]]);;
+
+let MOEBIUS_FUNCTION_COMPOSE = prove
+ (`!w1 w2 z.
+     -- w1 = w2  /\ norm w1 < &1 /\ norm z < &1
+     ==> moebius_function (&0) w1 (moebius_function (&0) w2 z) = z`,
+  let LEMMA_1 = prove
+   (`!a b:complex. norm a < &1 /\ norm b < &1
+                   ==> ~(Cx(&1) - a * b = Cx(&0))`,
+    GEN_TAC THEN GEN_TAC THEN STRIP_TAC THEN REWRITE_TAC [COMPLEX_SUB_0] THEN
+    SUBGOAL_THEN `~(norm (Cx(&1)) = norm (a * b))`
+      (fun th -> MESON_TAC[th]) THEN
+    REWRITE_TAC [COMPLEX_NORM_NUM; COMPLEX_NORM_MUL] THEN
+    MATCH_MP_TAC (REAL_ARITH `!x y. y < x ==> ~(x = y)`) THEN
+    ASM_CASES_TAC `b = Cx(&0)` THEN
+    ASM_REWRITE_TAC [COMPLEX_NORM_NUM; REAL_MUL_RZERO; REAL_LT_01] THEN
+    MATCH_MP_TAC REAL_LT_TRANS THEN EXISTS_TAC `&1 * norm (b:complex)` THEN
+    CONJ_TAC THENL
+    [MATCH_MP_TAC REAL_LT_RMUL THEN ASM_REWRITE_TAC [COMPLEX_NORM_NZ];
+     ASM_REWRITE_TAC [REAL_MUL_LID]]) in
+  let LEMMA_1_ALT = prove
+    (`!a b:complex. norm a < &1 /\ norm b < &1
+                    ==> ~(Cx(&1) + a * b = Cx(&0))`,
+     REPEAT GEN_TAC THEN STRIP_TAC THEN
+     SUBST1_TAC (COMPLEX_RING `a : complex = -- (-- a)`) THEN
+     ABBREV_TAC `u : complex= -- a` THEN
+     REWRITE_TAC [COMPLEX_MUL_LNEG; GSYM complex_sub] THEN
+     MATCH_MP_TAC LEMMA_1 THEN EXPAND_TAC "u" THEN
+     ASM_REWRITE_TAC[NORM_NEG]) in
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `norm (w2:complex) < &1` ASSUME_TAC THENL
+   [EXPAND_TAC "w2" THEN ASM_REWRITE_TAC [NORM_NEG]; ALL_TAC] THEN
+  REWRITE_TAC [moebius_function; COMPLEX_MUL_RZERO;
+               CEXP_0; COMPLEX_MUL_LID] THEN
+  MATCH_MP_TAC (COMPLEX_FIELD
+     `!a b c. ~(b = Cx(&0)) /\ a = b * c ==> a / b = c`) THEN
+  CONJ_TAC THENL
+   [ALL_TAC; MP_TAC (SPECL [`cnj w2`;`z:complex`] LEMMA_1) THEN
+    ASM_REWRITE_TAC [COMPLEX_NORM_CNJ] THEN EXPAND_TAC "w2" THEN
+    REWRITE_TAC [CNJ_NEG] THEN CONV_TAC COMPLEX_FIELD] THEN
+  MATCH_MP_TAC (COMPLEX_FIELD
+      `!a b c d. ~(d = Cx(&0)) /\ ~(d * a - b * c  = Cx(&0))
+                 ==> ~(a - b * c / d  = Cx(&0))`) THEN
+  ASM_SIMP_TAC [LEMMA_1; COMPLEX_NORM_CNJ] THEN
+  ASM_REWRITE_TAC [COMPLEX_MUL_RID] THEN
+  SUBGOAL_THEN
+      `Cx(&1) - cnj w2 * z - cnj w1 * (z - w2) =
+       Cx(&1) + cnj w1 * w2` SUBST1_TAC THENL
+   [EXPAND_TAC "w2" THEN REWRITE_TAC [CNJ_NEG] THEN CONV_TAC COMPLEX_RING;
+    ASM_SIMP_TAC [LEMMA_1_ALT; COMPLEX_NORM_CNJ]]);;
+
+let BALL_BIHOLOMORPHISM_EXISTS = prove
+ (`!a. a IN ball(Cx(&0),&1)
+       ==> ?f g. f(a) = Cx(&0) /\
+                 f holomorphic_on ball (Cx(&0),&1) /\
+                 (!z. z IN ball (Cx(&0),&1) ==> f z IN ball (Cx(&0),&1)) /\
+                 g holomorphic_on ball (Cx(&0),&1) /\
+                 (!z. z IN ball (Cx(&0),&1) ==> g z IN ball (Cx(&0),&1)) /\
+                 (!z. z IN ball (Cx(&0),&1) ==> f (g z) = z) /\
+                 (!z. z IN ball (Cx(&0),&1) ==> g (f z) = z)`,
+  REWRITE_TAC[COMPLEX_IN_BALL_0] THEN REPEAT STRIP_TAC THEN
+  EXISTS_TAC `moebius_function (&0) a` THEN
+  EXISTS_TAC `moebius_function (&0) (--a)` THEN
+  ASM_SIMP_TAC[COMPLEX_IN_BALL_0; MOEBIUS_FUNCTION_COMPOSE; COMPLEX_NEG_NEG;
+               NORM_NEG] THEN
+  ASM_SIMP_TAC[MOEBIUS_FUNCTION_NORM_LT_1; NORM_NEG;
+               MOEBIUS_FUNCTION_HOLOMORPHIC; MOEBIUS_FUNCTION_EQ_ZERO]);;
+
+let BALL_BIHOLOMORPHISM_MOEBIUS_FUNCTION = prove
+  (`!f g.
+      f holomorphic_on ball (Cx(&0),&1) /\
+      (!z. z IN ball (Cx(&0),&1) ==> f z IN ball (Cx(&0),&1)) /\
+      g holomorphic_on ball (Cx(&0),&1) /\
+      (!z. z IN ball (Cx(&0),&1) ==> g z IN ball (Cx(&0),&1)) /\
+      (!z. z IN ball (Cx(&0),&1) ==> f (g z) = z) /\
+      (!z. z IN ball (Cx(&0),&1) ==> g (f z) = z)
+      ==> ?t w. w IN ball (Cx(&0),&1) /\
+                (!z. z IN ball (Cx(&0),&1) ==> f z = moebius_function t w z)`,
+   let LEMMA_1 = prove
+     (`!a b:complex. norm a < &1 /\ norm b < &1
+                     ==> ~(Cx(&1) - a * b = Cx(&0))`,
+      GEN_TAC THEN GEN_TAC THEN STRIP_TAC THEN REWRITE_TAC [COMPLEX_SUB_0] THEN
+      SUBGOAL_THEN `~(norm (Cx(&1)) = norm (a * b))`
+        (fun th -> MESON_TAC[th]) THEN
+      REWRITE_TAC [COMPLEX_NORM_NUM; COMPLEX_NORM_MUL] THEN
+      MATCH_MP_TAC (REAL_ARITH `!x y. y < x ==> ~(x = y)`) THEN
+      ASM_CASES_TAC `b = Cx(&0)` THEN
+      ASM_REWRITE_TAC [COMPLEX_NORM_NUM; REAL_MUL_RZERO; REAL_LT_01] THEN
+      MATCH_MP_TAC REAL_LT_TRANS THEN EXISTS_TAC `&1 * norm (b:complex)` THEN
+      CONJ_TAC THENL
+      [MATCH_MP_TAC REAL_LT_RMUL THEN ASM_REWRITE_TAC [COMPLEX_NORM_NZ];
+       ASM_REWRITE_TAC [REAL_MUL_LID]]) in
+   let LEMMA_2 = prove
+     (`!t w s z. norm w < &1 /\ norm z < &1
+                 ==> moebius_function t w (cexp (ii * Cx s) * z) =
+                     moebius_function (t + s) (cexp (-- (ii * Cx s)) * w) z`,
+      REPEAT STRIP_TAC THEN
+      REWRITE_TAC[moebius_function; CX_ADD; COMPLEX_ADD_LDISTRIB; CEXP_ADD;
+                  GSYM COMPLEX_MUL_ASSOC; COMPLEX_EQ_MUL_LCANCEL; CEXP_NZ;
+               CNJ_MUL] THEN
+      MATCH_MP_TAC (COMPLEX_FIELD
+        `!a b c d e. ~(b = Cx(&0)) /\ ~(e = Cx(&0)) /\ e * a = b * c * d
+                     ==> a / b = c * d / e`) THEN CONJ_TAC THENL
+      [MATCH_MP_TAC LEMMA_1 THEN
+       ASM_REWRITE_TAC [COMPLEX_NORM_CNJ; COMPLEX_NORM_MUL; NORM_CEXP_II;
+                        REAL_MUL_LID];
+       ALL_TAC] THEN
+      CONJ_TAC THENL
+      [REWRITE_TAC [COMPLEX_MUL_ASSOC] THEN MATCH_MP_TAC LEMMA_1 THEN
+       ASM_REWRITE_TAC [COMPLEX_NORM_MUL; COMPLEX_NORM_CNJ; COMPLEX_NEG_RMUL;
+                        GSYM CX_NEG; NORM_CEXP_II; REAL_MUL_LID];
+       REWRITE_TAC [CNJ_CEXP; CNJ_NEG; CNJ_MUL; CNJ_II; CNJ_CX;
+                    COMPLEX_MUL_LNEG; COMPLEX_NEG_NEG; CEXP_NEG] THEN
+       ABBREV_TAC `a = cexp (ii * Cx s)` THEN
+       SUBGOAL_THEN `inv a * a = Cx(&1)` MP_TAC THENL
+       [ALL_TAC; CONV_TAC COMPLEX_RING] THEN
+       MATCH_MP_TAC COMPLEX_MUL_LINV THEN EXPAND_TAC "a" THEN
+       REWRITE_TAC [CEXP_NZ]]) in
+   REWRITE_TAC [COMPLEX_IN_BALL_0] THEN REPEAT STRIP_TAC THEN
+   ABBREV_TAC `w:complex = f (Cx(&0))` THEN
+   SUBGOAL_THEN `norm(w:complex) < &1` ASSUME_TAC THENL
+   [ASM_MESON_TAC [COMPLEX_NORM_NUM; REAL_LT_01]; ALL_TAC] THEN
+   SUBGOAL_THEN
+    `?t. !z. z IN ball (Cx(&0),&1)
+             ==> moebius_function (&0) w (f z) = cexp (ii * Cx t) * z`
+    STRIP_ASSUME_TAC THENL
+   [ALL_TAC;
+    EXISTS_TAC `t:real` THEN EXISTS_TAC `-- (cexp(-- (ii * Cx t)) * w)` THEN
+    ASM_REWRITE_TAC [NORM_NEG; COMPLEX_NORM_MUL; COMPLEX_NEG_RMUL;
+                     GSYM CX_NEG; NORM_CEXP_II; REAL_MUL_LID] THEN
+    GEN_TAC THEN DISCH_TAC THEN EQ_TRANS_TAC
+      `moebius_function (&0) (--w)
+         (moebius_function (&0) w (f (z:complex)))` THENL
+    [MATCH_MP_TAC EQ_SYM THEN MATCH_MP_TAC MOEBIUS_FUNCTION_COMPOSE THEN
+     ASM_SIMP_TAC [COMPLEX_NEG_NEG; NORM_NEG];
+     ASM_SIMP_TAC[COMPLEX_IN_BALL_0] THEN ASM_SIMP_TAC[LEMMA_2; NORM_NEG] THEN
+     REWRITE_TAC [REAL_ADD_LID; CX_NEG; COMPLEX_MUL_RNEG]]] THEN
+   MATCH_MP_TAC SECOND_CARTAN_THM_DIM_1 THEN EXISTS_TAC
+     `\z. g (moebius_function (&0) (--w) z) : complex` THEN
+   REWRITE_TAC [COMPLEX_IN_BALL_0] THEN REWRITE_TAC [REAL_LT_01] THEN
+   CONJ_TAC THENL
+   [MATCH_MP_TAC (REWRITE_RULE [o_DEF] HOLOMORPHIC_ON_COMPOSE_GEN) THEN
+    EXISTS_TAC `ball(Cx(&0),&1)` THEN
+    ASM_SIMP_TAC [ETA_AX; MOEBIUS_FUNCTION_HOLOMORPHIC; COMPLEX_IN_BALL_0];
+    ALL_TAC] THEN CONJ_TAC THENL [ASM_SIMP_TAC [MOEBIUS_FUNCTION_NORM_LT_1];
+    ALL_TAC] THEN
+   CONJ_TAC THENL [ASM_REWRITE_TAC [MOEBIUS_FUNCTION_EQ_ZERO]; ALL_TAC] THEN
+   CONJ_TAC THENL
+   [MATCH_MP_TAC (REWRITE_RULE [o_DEF] HOLOMORPHIC_ON_COMPOSE_GEN) THEN
+    EXISTS_TAC `ball(Cx(&0),&1)` THEN
+    ASM_SIMP_TAC [COMPLEX_IN_BALL_0; MOEBIUS_FUNCTION_NORM_LT_1;
+                  NORM_NEG] THEN
+    ASM_SIMP_TAC [ETA_AX; MOEBIUS_FUNCTION_HOLOMORPHIC; NORM_NEG];
+    ALL_TAC] THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC [MOEBIUS_FUNCTION_NORM_LT_1; NORM_NEG]; ALL_TAC] THEN
+   CONJ_TAC THENL
+   [ASM_REWRITE_TAC [MOEBIUS_FUNCTION_OF_ZERO; COMPLEX_MUL_RZERO; CEXP_0;
+                     GSYM COMPLEX_NEG_LMUL; COMPLEX_MUL_LID;
+                      COMPLEX_NEG_NEG] THEN
+    ASM_MESON_TAC [COMPLEX_NORM_0; REAL_LT_01];
+    ALL_TAC] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC [REWRITE_RULE [COMPLEX_NEG_NEG; NORM_NEG]
+         (SPECL [`--w:complex`;`w:complex`] MOEBIUS_FUNCTION_COMPOSE)]] THEN
+    REPEAT STRIP_TAC THEN SUBGOAL_THEN
+     `f (g (moebius_function (&0) (--w) z) : complex) =
+      (moebius_function (&0) (--w) z)`
+     SUBST1_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_SIMP_TAC [MOEBIUS_FUNCTION_NORM_LT_1; NORM_NEG];
+    MATCH_MP_TAC MOEBIUS_FUNCTION_COMPOSE THEN ASM_REWRITE_TAC []]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some simple but useful cases of Hurwitz's theorem.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let HURWITZ_NO_ZEROS = prove
+ (`!f:num->complex->complex g s.
+        open s /\ connected s /\
+        (!n. (f n) holomorphic_on s) /\ g holomorphic_on s /\
+        (!k e. compact k /\ k SUBSET s /\ &0 < e
+               ==> ?N. !n x. n >= N /\ x IN k ==> norm(f n x - g x) < e) /\
+        ~(?c. !z. z IN s ==> g z = c) /\
+        (!n z. z IN s ==> ~(f n z = Cx(&0)))
+        ==> (!z. z IN s ==> ~(g z = Cx(&0)))`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN X_GEN_TAC `z0:complex` THEN
+  REPEAT DISCH_TAC THEN
+  MP_TAC(ISPECL [`g:complex->complex`; `s:complex->bool`; `z0:complex`]
+   HOLOMORPHIC_FACTOR_ZERO_NONCONSTANT) THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`h:complex->complex`; `r:real`; `m:num`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`sequentially`; `\n:num z. complex_derivative (f n) z / f n z`;
+    `\z. complex_derivative g z / g z`;  `z0:complex`; `r / &2`]
+   PATH_INTEGRAL_UNIFORM_LIMIT_CIRCLEPATH) THEN
+  ASM_REWRITE_TAC[REAL_HALF; TRIVIAL_LIMIT_SEQUENTIALLY; NOT_IMP] THEN
+  SUBGOAL_THEN
+   `!n:num. ((\z. complex_derivative (f n) z / f n z)
+             has_path_integral (Cx(&0))) (circlepath(z0,r / &2))`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `n:num` THEN MATCH_MP_TAC CAUCHY_THEOREM_DISC_SIMPLE THEN
+    MAP_EVERY EXISTS_TAC [`z0:complex`; `r:real`] THEN
+    ASM_SIMP_TAC[VALID_PATH_CIRCLEPATH; PATHSTART_CIRCLEPATH;
+                 PATHFINISH_CIRCLEPATH; PATH_IMAGE_CIRCLEPATH;
+                 REAL_HALF; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[sphere; NORM_ARITH `dist(z,w) = norm(w - z)`] THEN
+    REWRITE_TAC[SUBSET; IN_BALL; ONCE_REWRITE_RULE[DIST_SYM] dist] THEN
+    ASM_SIMP_TAC[IN_ELIM_THM; REAL_ARITH `&0 < r ==> r / &2 < r`] THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[ETA_AX] THEN MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE THEN
+      REWRITE_TAC[OPEN_BALL];
+      REWRITE_TAC[ETA_AX];
+      ASM_MESON_TAC[SUBSET]] THEN
+    ASM_MESON_TAC[HOLOMORPHIC_ON_SUBSET];
+    ALL_TAC] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC ALWAYS_EVENTUALLY THEN
+    REWRITE_TAC[path_integrable_on] THEN ASM_MESON_TAC[];
+    MATCH_MP_TAC UNIFORM_LIM_COMPLEX_DIV THEN
+    REWRITE_TAC[LEFT_EXISTS_AND_THM; CONJ_ASSOC] THEN
+    REWRITE_TAC[RIGHT_EXISTS_AND_THM; GSYM CONJ_ASSOC] THEN
+    REWRITE_TAC[LEFT_EXISTS_AND_THM] THEN
+
+    ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; REAL_HALF; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[sphere; NORM_ARITH `dist(z,w) = norm(w - z)`] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN REPEAT CONJ_TAC THENL
+     [MP_TAC(ISPEC `IMAGE (complex_derivative g) {w | norm(w - z0) = r / &2}`
+        COMPACT_IMP_BOUNDED) THEN
+      ANTS_TAC THENL
+       [MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+        REWRITE_TAC[o_DEF;
+         REWRITE_RULE[sphere; NORM_ARITH `dist(w:real^N,z) = norm(z - w)`]
+                    COMPACT_SPHERE] THEN
+        MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON THEN
+        MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+        EXISTS_TAC `s:complex->bool` THEN
+        ASM_SIMP_TAC[HOLOMORPHIC_COMPLEX_DERIVATIVE] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+          SUBSET_TRANS)) THEN
+        REWRITE_TAC[SUBSET; IN_BALL; IN_ELIM_THM] THEN
+        UNDISCH_TAC `&0 < r` THEN CONV_TAC NORM_ARITH;
+        REWRITE_TAC[bounded; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+        MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN DISCH_TAC THEN
+        MATCH_MP_TAC ALWAYS_EVENTUALLY THEN ASM_SIMP_TAC[]];
+      MP_TAC(ISPEC `IMAGE (norm o (g:complex->complex))
+          {w | norm(w - z0) = r / &2}`
+          COMPACT_ATTAINS_INF) THEN
+      REWRITE_TAC[EXISTS_IN_IMAGE; FORALL_IN_IMAGE; IMAGE_EQ_EMPTY] THEN
+      REWRITE_TAC[GSYM IMAGE_o; FORALL_IN_GSPEC; EXISTS_IN_GSPEC; o_THM] THEN
+      ANTS_TAC THENL
+       [CONJ_TAC THENL
+         [MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+          REWRITE_TAC[o_DEF;
+            REWRITE_RULE[sphere; NORM_ARITH `dist(w:real^N,z) = norm(z - w)`]
+                        COMPACT_SPHERE] THEN
+          MATCH_MP_TAC CONTINUOUS_ON_LIFT_NORM_COMPOSE THEN
+          MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            HOLOMORPHIC_ON_SUBSET)) THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+            SUBSET_TRANS)) THEN
+          REWRITE_TAC[SUBSET; IN_BALL; IN_ELIM_THM] THEN
+          UNDISCH_TAC `&0 < r` THEN CONV_TAC NORM_ARITH;
+          REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+          EXISTS_TAC `z0 + Cx(r / &2)` THEN
+          REWRITE_TAC[VECTOR_ARITH `(a + b) - a:real^N = b`] THEN
+          REWRITE_TAC[COMPLEX_NORM_CX] THEN ASM_REAL_ARITH_TAC];
+        DISCH_THEN(X_CHOOSE_THEN `ww:complex` MP_TAC) THEN
+        STRIP_TAC THEN EXISTS_TAC `norm((g:complex->complex) ww)` THEN
+        ASM_SIMP_TAC[ALWAYS_EVENTUALLY; COMPLEX_NORM_NZ] THEN
+        DISCH_THEN(ASSUME_TAC o REWRITE_RULE[COMPLEX_NORM_ZERO]) THEN
+        UNDISCH_TAC `!w. w IN ball(z0,r) ==> g w = (w - z0) pow m * h w` THEN
+        DISCH_THEN(MP_TAC o SPEC `ww:complex`) THEN
+        CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN
+        ASM_SIMP_TAC[COMPLEX_ENTIRE; COMPLEX_POW_EQ_0] THEN
+        REWRITE_TAC[IN_BALL; GSYM COMPLEX_NORM_ZERO] THEN
+        ASM_REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] dist] THEN
+        ASM_REAL_ARITH_TAC];
+      X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+      FIRST_ASSUM(MP_TAC o SPECL
+       [`cball(z0:complex,&3 * r / &4)`; `r / &4 * e / &2`]) THEN
+      REWRITE_TAC[COMPACT_CBALL] THEN ANTS_TAC THENL
+       [ASM_SIMP_TAC[REAL_LT_MUL; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+          SUBSET_TRANS)) THEN
+        REWRITE_TAC[SUBSET; IN_BALL; IN_CBALL; IN_ELIM_THM] THEN
+        UNDISCH_TAC `&0 < r` THEN CONV_TAC NORM_ARITH;
+        REWRITE_TAC[GE; EVENTUALLY_SEQUENTIALLY; IN_CBALL; dist] THEN
+        MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+        MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `n:num` THEN
+        DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+        ASM_REWRITE_TAC[] THEN DISCH_TAC] THEN
+      X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+      MP_TAC(ISPECL
+       [`\z. (f:num->complex->complex) n z - g z`;
+        `w:complex`; `Cx(&0)`; `r / &4`; `r / &4 * e / &2`; `1`]
+        CAUCHY_HIGHER_COMPLEX_DERIVATIVE_BOUND) THEN
+      REWRITE_TAC[HIGHER_COMPLEX_DERIVATIVE_1; COMPLEX_IN_BALL_0] THEN
+      ANTS_TAC THENL
+       [CONJ_TAC THENL [ASM_REAL_ARITH_TAC; CONV_TAC NUM_REDUCE_CONV] THEN
+        REPEAT CONJ_TAC THENL
+         [ALL_TAC;
+          MATCH_MP_TAC HOLOMORPHIC_ON_IMP_CONTINUOUS_ON;
+          X_GEN_TAC `y:complex` THEN REWRITE_TAC[IN_BALL] THEN
+          DISCH_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+          MAP_EVERY UNDISCH_TAC
+           [`norm(w - z0:complex) = r / &2`; `dist(w:complex,y) < r / &4`] THEN
+          CONV_TAC NORM_ARITH] THEN
+        (MATCH_MP_TAC HOLOMORPHIC_ON_SUB THEN
+         CONJ_TAC THEN MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+         EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[ETA_AX] THEN
+         FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+          SUBSET_TRANS)) THEN
+         REWRITE_TAC[SUBSET; IN_BALL; IN_CBALL; IN_ELIM_THM] THEN
+         UNDISCH_TAC `norm(w - z0:complex) = r / &2` THEN
+         UNDISCH_TAC `&0 < r` THEN CONV_TAC NORM_ARITH);
+        CONV_TAC NUM_REDUCE_CONV THEN
+        ASM_SIMP_TAC[REAL_FIELD
+         `&0 < r /\ &0 < e
+          ==> &1 * (r / &4 * e / &2) / (r / &4) pow 1 = e / &2`] THEN
+        MATCH_MP_TAC(NORM_ARITH
+         `x = y /\ &0 < e ==> norm(x) <= e / &2 ==> norm(y) < e`) THEN
+        ASM_REWRITE_TAC[] THEN
+        MATCH_MP_TAC COMPLEX_DERIVATIVE_SUB THEN CONJ_TAC THEN
+        MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT THEN
+        EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+        ASM_REWRITE_TAC[IN_BALL; ONCE_REWRITE_RULE[DIST_SYM] dist] THEN
+        ASM_REAL_ARITH_TAC];
+      X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+      REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL
+       [`{w:complex | norm(w - z0) = r / &2}`; `e:real`]) THEN
+      ASM_REWRITE_TAC[GE; IN_ELIM_THM;
+         REWRITE_RULE[sphere; NORM_ARITH `dist(w:real^N,z) = norm(z - w)`]
+                    COMPACT_SPHERE] THEN
+      ANTS_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+          SUBSET_TRANS)) THEN
+      REWRITE_TAC[SUBSET; IN_BALL; IN_ELIM_THM] THEN
+      UNDISCH_TAC `&0 < r` THEN CONV_TAC NORM_ARITH];
+    FIRST_ASSUM(ASSUME_TAC o GEN `n:num` o MATCH_MP PATH_INTEGRAL_UNIQUE o
+        SPEC `n:num`) THEN
+    DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+    ASM_REWRITE_TAC[LIM_CONST_EQ; TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+    MATCH_MP_TAC(COMPLEX_RING
+     `!q r. p = q /\ q = r /\ ~(r = Cx(&0)) ==> ~(Cx(&0) = p)`) THEN
+    MAP_EVERY EXISTS_TAC
+     [`path_integral (circlepath(z0,r / &2))
+                     (\z. Cx(&m) / (z - z0) +
+                          complex_derivative h z / h z)`;
+      `Cx(&2) * Cx pi * ii * Cx(&m)`] THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC PATH_INTEGRAL_EQ THEN X_GEN_TAC `w:complex` THEN
+      ASM_SIMP_TAC[PATH_IMAGE_CIRCLEPATH; IN_ELIM_THM; REAL_HALF;
+        REAL_LT_IMP_LE; sphere; NORM_ARITH `dist(z,w) = norm(w - z)`] THEN
+      ASM_CASES_TAC `w:complex = z0` THEN
+      ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THENL
+       [ASM_REAL_ARITH_TAC; DISCH_TAC] THEN
+      SUBGOAL_THEN `w IN ball(z0:complex,r)` ASSUME_TAC THENL
+       [REWRITE_TAC[IN_BALL] THEN
+        MAP_EVERY UNDISCH_TAC [`norm (w - z0) = r / &2`; `&0 < r`] THEN
+        CONV_TAC NORM_ARITH;
+        ALL_TAC] THEN
+      ASM_SIMP_TAC[] THEN
+      ASM_SIMP_TAC[COMPLEX_ENTIRE; COMPLEX_POW_EQ_0; COMPLEX_SUB_0;
+            COMPLEX_FIELD `~(y = Cx(&0)) ==> (x / y = w <=> x = y * w)`] THEN
+      ASM_SIMP_TAC[COMPLEX_FIELD
+       `~(h = Cx(&0)) ==> (m * h) * (x + y / h) = m * y + m * h * x`] THEN
+      MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+      MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+      EXISTS_TAC `\w:complex. (w - z0) pow m * h w` THEN
+      EXISTS_TAC `ball(z0:complex,r)` THEN ASM_SIMP_TAC[OPEN_BALL] THEN
+      SUBGOAL_THEN
+       `(w - z0) pow m * h w * Cx(&m) / (w - z0) =
+        (Cx(&m) * (w - z0) pow (m - 1)) * h w`
+      SUBST1_TAC THENL
+       [MATCH_MP_TAC(COMPLEX_FIELD
+         `w * mm = z /\ ~(w = Cx(&0))
+          ==> z * h * m / w = (m * mm) * h`) THEN
+        ASM_REWRITE_TAC[COMPLEX_SUB_0; GSYM(CONJUNCT2 complex_pow)] THEN
+        AP_TERM_TAC THEN ASM_ARITH_TAC;
+        MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_MUL_AT THEN CONJ_TAC THENL
+         [COMPLEX_DIFF_TAC THEN CONV_TAC COMPLEX_RING;
+          REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+          ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT; OPEN_BALL]]];
+      GEN_REWRITE_TAC RAND_CONV [GSYM COMPLEX_ADD_RID] THEN
+      MATCH_MP_TAC PATH_INTEGRAL_UNIQUE THEN
+      MATCH_MP_TAC HAS_PATH_INTEGRAL_ADD THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CAUCHY_INTEGRAL_CIRCLEPATH_SIMPLE THEN
+        ASM_REWRITE_TAC[CENTRE_IN_BALL; REAL_HALF; HOLOMORPHIC_ON_CONST];
+        MATCH_MP_TAC CAUCHY_THEOREM_DISC_SIMPLE THEN
+        MAP_EVERY EXISTS_TAC [`z0:complex`; `r:real`] THEN
+        ASM_SIMP_TAC[VALID_PATH_CIRCLEPATH; PATHSTART_CIRCLEPATH;
+                     PATHFINISH_CIRCLEPATH; PATH_IMAGE_CIRCLEPATH;
+                     REAL_HALF; REAL_LT_IMP_LE] THEN
+        REWRITE_TAC[sphere; NORM_ARITH `dist(z,w) = norm(w - z)`] THEN
+        REWRITE_TAC[SUBSET; IN_BALL; ONCE_REWRITE_RULE[DIST_SYM] dist] THEN
+        ASM_SIMP_TAC[IN_ELIM_THM; REAL_ARITH `&0 < r ==> r / &2 < r`] THEN
+        MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN ASM_REWRITE_TAC[ETA_AX] THEN
+        MATCH_MP_TAC HOLOMORPHIC_COMPLEX_DERIVATIVE THEN
+        ASM_REWRITE_TAC[OPEN_BALL]];
+      REWRITE_TAC[COMPLEX_ENTIRE; CX_INJ; PI_NZ; II_NZ; REAL_OF_NUM_EQ] THEN
+      ASM_SIMP_TAC[LE_1; ARITH_EQ] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REWRITE_TAC[CENTRE_IN_BALL]]]);;
+
+let HURWITZ_INJECTIVE = prove
+ (`!f:num->complex->complex g s.
+    open s /\ connected s /\
+    (!n. (f n) holomorphic_on s) /\ g holomorphic_on s /\
+    (!k e. compact k /\ k SUBSET s /\ &0 < e
+           ==> ?N. !n x. n >= N /\ x IN k ==> norm(f n x - g x) < e) /\
+    ~(?c. !z. z IN s ==> g z = c) /\
+    (!n w z. w IN s /\ z IN s /\ f n w = f n z ==> w = z)
+    ==> (!w z. w IN s /\ z IN s /\ g w = g z ==> w = z)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`z1:complex`; `z2:complex`] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REPEAT DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_EXISTS_THM]) THEN
+  DISCH_THEN(MP_TAC o SPEC `(g:complex->complex) z2`) THEN
+  REWRITE_TAC[] THEN X_GEN_TAC `z0:complex` THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REPEAT DISCH_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[MESON[]
+   `(!x y. x IN s /\ y IN s /\ g x = g y ==> x = y) <=>
+    (!x y. x IN s /\ y IN s ==> (g x = g y <=> x = y))`]) THEN
+  MP_TAC(ISPECL
+   [`\z. (g:complex->complex) z - g z1`; `s:complex->bool`;
+    `z2:complex`; `z0:complex`]
+        ISOLATED_ZEROS) THEN
+  ASM_SIMP_TAC[COMPLEX_SUB_0; HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_ID;
+               HOLOMORPHIC_ON_CONST] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`\n z. (f:num->complex->complex) n z - f n z1`;
+    `\z. (g:complex->complex) z - g z1`; `s DELETE (z1:complex)`]
+        HURWITZ_NO_ZEROS) THEN
+  REWRITE_TAC[NOT_IMP; COMPLEX_SUB_0] THEN REPEAT CONJ_TAC THENL
+   [ASM_SIMP_TAC[OPEN_DELETE];
+    ASM_SIMP_TAC[CONNECTED_OPEN_DELETE; DIMINDEX_2; LE_REFL];
+    GEN_TAC THEN MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+    EXISTS_TAC `s:complex->bool` THEN
+    ASM_SIMP_TAC[HOLOMORPHIC_ON_SUB; ETA_AX; HOLOMORPHIC_ON_CONST] THEN
+    SET_TAC[];
+    MATCH_MP_TAC HOLOMORPHIC_ON_SUBSET THEN
+    EXISTS_TAC `s:complex->bool` THEN
+    ASM_SIMP_TAC[HOLOMORPHIC_ON_SUB; ETA_AX; HOLOMORPHIC_ON_CONST] THEN
+    SET_TAC[];
+    MAP_EVERY X_GEN_TAC [`k:complex->bool`; `e:real`] THEN STRIP_TAC THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP (SET_RULE
+     `k SUBSET s DELETE z ==> k SUBSET s`)) THEN
+    FIRST_X_ASSUM(fun th ->
+     MP_TAC(SPECL [`k:complex->bool`; `e / &2`] th) THEN
+     MP_TAC(SPECL [`{z1:complex}`; `e / &2`] th)) THEN
+    ASM_REWRITE_TAC[COMPACT_SING; SING_SUBSET; REAL_HALF] THEN
+    SIMP_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; IN_SING; FORALL_UNWIND_THM2] THEN
+    REWRITE_TAC[IMP_IMP; RIGHT_IMP_FORALL_THM] THEN DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_TAC `N1:num`) (X_CHOOSE_TAC `N2:num`)) THEN
+    EXISTS_TAC `MAX N1 N2` THEN REPEAT STRIP_TAC THEN
+    UNDISCH_THEN `(g:complex->complex) z1 = g z2` (SUBST1_TAC o SYM) THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `norm(x1 - x2) < e / &2 /\ norm(y1 - y2) < e / &2
+      ==> norm(x1 - y1 - (x2 - y2)) < e`) THEN
+    ASM_MESON_TAC[ARITH_RULE `x >= MAX m n <=> x >= m /\ x >= n`];
+    REWRITE_TAC[IN_DELETE; COMPLEX_EQ_SUB_RADD] THEN DISCH_THEN(CHOOSE_THEN
+     (fun th -> MAP_EVERY (MP_TAC o C SPEC th)
+                 [`z0:complex`; `z1:complex`; `z2:complex`])) THEN
+    ASM_MESON_TAC[];
+    REWRITE_TAC[IN_DELETE] THEN ASM_MESON_TAC[];
+    REWRITE_TAC[IN_DELETE] THEN ASM_MESON_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A big chain of equivalents of simple connectedness for an open set.       *)
+(* ------------------------------------------------------------------------- *)
+
+let [SIMPLY_CONNECTED_EQ_WINDING_NUMBER_ZERO;
+     SIMPLY_CONNECTED_EQ_PATH_INTEGRAL_ZERO;
+     SIMPLY_CONNECTED_EQ_GLOBAL_PRIMITIVE;
+     SIMPLY_CONNECTED_EQ_HOLOMORPHIC_LOG;
+     SIMPLY_CONNECTED_EQ_HOLOMORPHIC_SQRT;
+     SIMPLY_CONNECTED_EQ_INJECTIVE_HOLOMORPHIC_SQRT;
+     SIMPLY_CONNECTED_EQ_BIHOLOMORPHIC_TO_DISC;
+     SIMPLY_CONNECTED_EQ_HOMEOMORPHIC_TO_DISC] =
+ (CONJUNCTS o prove)
+ (`(!s. open s
+        ==> (simply_connected s <=>
+             connected s /\
+             !g z. path g /\ path_image g SUBSET s /\
+                   pathfinish g = pathstart g /\ ~(z IN s)
+                   ==> winding_number(g,z) = Cx(&0))) /\
+   (!s. open s
+        ==> (simply_connected s <=>
+             connected s /\
+             !g f. valid_path g /\ path_image g SUBSET s /\
+                   pathfinish g = pathstart g /\ f holomorphic_on s
+                 ==> (f has_path_integral Cx(&0)) g)) /\
+   (!s. open s
+        ==> (simply_connected s <=>
+             connected s /\
+             !f. f holomorphic_on s
+                 ==> ?h. !z. z IN s
+                             ==> (h has_complex_derivative f(z)) (at z))) /\
+   (!s. open s
+        ==> (simply_connected s <=>
+             connected s /\
+             !f. f holomorphic_on s /\ (!z. z IN s ==> ~(f z = Cx(&0)))
+                 ==> ?g. g holomorphic_on s /\
+                         !z. z IN s ==> f z = cexp(g z))) /\
+   (!s. open s
+        ==> (simply_connected s <=>
+             connected s /\
+             !f. f holomorphic_on s /\ (!z. z IN s ==> ~(f z = Cx(&0)))
+                 ==> ?g. g holomorphic_on s /\
+                         !z. z IN s ==> f z = g z pow 2)) /\
+   (!s. open s
+        ==> (simply_connected s <=>
+             connected s /\
+             !f. f holomorphic_on s /\ (!z. z IN s ==> ~(f z = Cx(&0))) /\
+                 (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+                 ==> ?g. g holomorphic_on s /\
+                         !z. z IN s ==> f z = g z pow 2)) /\
+   (!s. open s
+        ==> (simply_connected s <=>
+             s = {} \/ s = (:complex) \/
+             ?f g. f holomorphic_on s /\ g holomorphic_on ball(Cx(&0),&1) /\
+                   (!z. z IN s ==> f(z) IN ball(Cx(&0),&1) /\ g(f z) = z) /\
+                   (!z. z IN ball(Cx(&0),&1) ==> g(z) IN s /\ f(g z) = z))) /\
+   (!s. open s
+        ==> (simply_connected(s:complex->bool) <=>
+             s = {} \/ s homeomorphic ball(Cx(&0),&1)))`,
+  REWRITE_TAC[AND_FORALL_THM; TAUT
+   `(p ==> q) /\ (p ==> r) <=> p ==> q /\ r`] THEN
+  X_GEN_TAC `s:complex->bool` THEN DISCH_TAC THEN MATCH_MP_TAC(TAUT
+   `(p0 ==> p1) /\ (p1 ==> p2) /\ (p2 ==> p3) /\ (p3 ==> p4) /\
+    (p4 ==> p5) /\ (p5 ==> p6) /\ (p6 ==> p7) /\ (p7 ==> p8) /\ (p8 ==> p0)
+    ==> (p0 <=> p1) /\ (p0 <=> p2) /\
+        (p0 <=> p3) /\ (p0 <=> p4) /\
+        (p0 <=> p5) /\ (p0 <=> p6) /\ (p0 <=> p7) /\ (p0 <=> p8)`) THEN
+  REPEAT CONJ_TAC THENL
+   [SIMP_TAC[SIMPLY_CONNECTED_IMP_CONNECTED] THEN
+    MESON_TAC[SIMPLY_CONNECTED_IMP_WINDING_NUMBER_ZERO];
+
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC CAUCHY_THEOREM_GLOBAL THEN
+    EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[VALID_PATH_IMP_PATH];
+
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `f:complex->complex` THEN
+    ASM_CASES_TAC `s:complex->bool = {}` THENL
+     [ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN ASM_MESON_TAC[]; DISCH_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `a:complex`) THEN EXISTS_TAC
+     `\z. path_integral
+           (@g. vector_polynomial_function g /\ path_image g SUBSET s /\
+                pathstart g = a /\ pathfinish g = z)
+           f` THEN
+    X_GEN_TAC `x:complex` THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `x:complex`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    REWRITE_TAC[has_complex_derivative] THEN
+    REWRITE_TAC[has_derivative_at; LINEAR_COMPLEX_MUL] THEN
+    MATCH_MP_TAC LIM_TRANSFORM THEN
+    EXISTS_TAC `\y. inv(norm(y - x)) % (path_integral(linepath(x,y)) f -
+                     f x * (y - x))` THEN
+    REWRITE_TAC[VECTOR_ARITH
+     `i % (x - a) - i % (y - (z + a)) = i % (x + z - y)`] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC LIM_EVENTUALLY THEN REWRITE_TAC[EVENTUALLY_AT] THEN
+      EXISTS_TAC `d:real` THEN ASM_REWRITE_TAC[] THEN
+      X_GEN_TAC `y:complex` THEN STRIP_TAC THEN
+      REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISJ2_TAC THEN MP_TAC(ISPEC
+        `s:complex->bool` CONNECTED_OPEN_VECTOR_POLYNOMIAL_CONNECTED) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(MP_TAC o SPEC `a:complex`) THEN ASM_REWRITE_TAC[] THEN
+      SUBGOAL_THEN `(y:complex) IN s` ASSUME_TAC THENL
+       [ASM_MESON_TAC[SUBSET; IN_CBALL; REAL_LT_IMP_LE; DIST_SYM];
+        ALL_TAC] THEN
+      DISCH_THEN(fun th ->
+        MP_TAC(SPEC `y:complex` th) THEN MP_TAC(SPEC `x:complex` th)) THEN
+      ASM_REWRITE_TAC[] THEN MAP_EVERY ABBREV_TAC
+       [`g1 = @g. vector_polynomial_function g /\ path_image g SUBSET s /\
+                  pathstart g = (a:complex) /\ pathfinish g = x`;
+        `g2 = @g. vector_polynomial_function g /\ path_image g SUBSET s /\
+                  pathstart g = (a:complex) /\ pathfinish g = y`] THEN
+      DISCH_THEN(MP_TAC o SELECT_RULE) THEN ASM_REWRITE_TAC[] THEN
+      STRIP_TAC THEN DISCH_THEN(MP_TAC o SELECT_RULE) THEN
+      ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL
+       [`g1 ++ linepath (x:complex,y) ++ reversepath g2`;
+        `f:complex->complex`]) THEN
+      ASM_REWRITE_TAC[PATHSTART_JOIN; PATHFINISH_JOIN; PATHFINISH_REVERSEPATH;
+                      PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+      SUBGOAL_THEN `segment[x:complex,y] SUBSET s` ASSUME_TAC THENL
+       [MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `cball(x:complex,d)` THEN
+        ASM_REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+        MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_CBALL] THEN
+        REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET] THEN
+        ASM_SIMP_TAC[IN_CBALL; DIST_REFL] THEN
+        ASM_MESON_TAC[REAL_LT_IMP_LE; DIST_SYM];
+        ALL_TAC] THEN
+      SUBGOAL_THEN
+       `f path_integrable_on g1 /\ f path_integrable_on g2 /\
+        f path_integrable_on linepath(x,y)`
+      STRIP_ASSUME_TAC THENL
+       [REPEAT CONJ_TAC THEN
+        MATCH_MP_TAC PATH_INTEGRABLE_HOLOMORPHIC_SIMPLE THEN
+        EXISTS_TAC `s:complex->bool` THEN
+        ASM_SIMP_TAC[VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN
+        ASM_REWRITE_TAC[VALID_PATH_LINEPATH; PATH_IMAGE_LINEPATH];
+        ALL_TAC] THEN
+      ANTS_TAC THENL
+       [ALL_TAC; DISCH_THEN(MP_TAC o MATCH_MP PATH_INTEGRAL_UNIQUE)] THEN
+      ASM_SIMP_TAC[VALID_PATH_JOIN_EQ; PATHSTART_JOIN; PATHFINISH_JOIN;
+                   PATHFINISH_REVERSEPATH; PATHSTART_LINEPATH;
+                   PATHFINISH_LINEPATH; VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION;
+                   PATH_IMAGE_JOIN; PATH_IMAGE_LINEPATH;
+                   PATH_IMAGE_REVERSEPATH; PATHSTART_REVERSEPATH;
+                   VALID_PATH_LINEPATH; VALID_PATH_REVERSEPATH; UNION_SUBSET;
+                   PATH_INTEGRAL_JOIN; PATH_INTEGRABLE_JOIN;
+                   PATH_INTEGRABLE_REVERSEPATH; PATH_INTEGRAL_REVERSEPATH] THEN
+      REWRITE_TAC[COMPLEX_VEC_0] THEN CONV_TAC COMPLEX_RING;
+      REWRITE_TAC[LIM_AT] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+      SUBGOAL_THEN `(f:complex->complex) continuous at x` MP_TAC THENL
+       [ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON;
+                      CONTINUOUS_ON_EQ_CONTINUOUS_AT];
+        ALL_TAC] THEN
+      REWRITE_TAC[continuous_at; dist; VECTOR_SUB_RZERO] THEN
+      DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+      DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+      DISCH_THEN(MP_TAC o SPEC `x:complex`) THEN
+      ASM_REWRITE_TAC[SUBSET; IN_BALL; 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
+      X_GEN_TAC `y:complex` THEN STRIP_TAC THEN
+      SUBGOAL_THEN `f path_integrable_on linepath(x,y)` MP_TAC THENL
+       [MATCH_MP_TAC PATH_INTEGRABLE_CONTINUOUS_LINEPATH THEN
+        MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+        EXISTS_TAC `s:complex->bool` THEN CONJ_TAC THENL
+         [ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON;
+                        CONTINUOUS_ON_EQ_CONTINUOUS_AT];
+          MATCH_MP_TAC SUBSET_TRANS THEN
+          EXISTS_TAC `ball(x:complex,d2)` THEN CONJ_TAC THENL
+           [REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+            MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_BALL] THEN
+            REWRITE_TAC[SUBSET; IN_BALL; IN_INSERT; NOT_IN_EMPTY; dist] THEN
+            REPEAT STRIP_TAC THEN
+            ASM_REWRITE_TAC[dist; NORM_0; VECTOR_SUB_REFL] THEN
+            ASM_MESON_TAC[NORM_SUB];
+            ASM_REWRITE_TAC[SUBSET; dist; IN_BALL]]];
+        ALL_TAC] THEN
+      REWRITE_TAC[path_integrable_on; LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `z:complex` THEN
+      MP_TAC(SPECL [`x:complex`; `y:complex`; `(f:complex->complex) x`]
+                    HAS_PATH_INTEGRAL_CONST_LINEPATH) THEN
+      REWRITE_TAC[IMP_IMP] THEN
+      DISCH_THEN(fun th -> ASSUME_TAC(CONJUNCT2 th) THEN MP_TAC th) THEN
+      FIRST_ASSUM(SUBST1_TAC o MATCH_MP PATH_INTEGRAL_UNIQUE) THEN
+      DISCH_THEN(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_SUB) THEN
+      DISCH_THEN(MP_TAC o MATCH_MP HAS_PATH_INTEGRAL_NEG) THEN
+      REWRITE_TAC[COMPLEX_NEG_SUB] THEN STRIP_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH `x <= e / &2 /\ &0 < e ==> x < e`) THEN
+      ASM_REWRITE_TAC[NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM real_div] THEN
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ] THEN
+      MATCH_MP_TAC HAS_PATH_INTEGRAL_BOUND_LINEPATH THEN
+      EXISTS_TAC `\w. (f:complex->complex) w - f x` THEN
+      ASM_SIMP_TAC[REAL_ARITH `&0 < e ==> &0 <= e / &2`] THEN
+      X_GEN_TAC `w:complex` THEN STRIP_TAC THEN
+      MATCH_MP_TAC REAL_LT_IMP_LE THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_MESON_TAC[REAL_LET_TRANS; SEGMENT_BOUND]];
+
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `f:complex->complex` THEN
+    ASM_CASES_TAC `s:complex->bool = {}` THENL
+     [ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN ASM_MESON_TAC[]; STRIP_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `\z. complex_derivative f z / f z`) THEN
+    ASM_SIMP_TAC[HOLOMORPHIC_COMPLEX_DERIVATIVE;
+                 HOLOMORPHIC_ON_DIV; ETA_AX] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`\z:complex. cexp(g z) / f z`; `s:complex->bool`]
+        HAS_COMPLEX_DERIVATIVE_ZERO_CONNECTED_CONSTANT) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+      SUBGOAL_THEN
+       `Cx(&0) = ((complex_derivative f z / f z * cexp (g z)) * f z -
+                  cexp (g z) * complex_derivative f z) / f z pow 2`
+      SUBST1_TAC THENL
+       [ASM_SIMP_TAC[COMPLEX_FIELD
+         `~(z = Cx(&0)) ==> (d / z * e) * z = e * d`] THEN
+        SIMPLE_COMPLEX_ARITH_TAC;
+        MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DIV_AT THEN
+        ASM_SIMP_TAC[] THEN CONJ_TAC THENL
+         [GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+          ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+          MATCH_MP_TAC COMPLEX_DIFF_CHAIN_AT THEN
+          ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_CEXP];
+          ASM_MESON_TAC[HOLOMORPHIC_ON_OPEN; complex_differentiable;
+                        HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE]]];
+      DISCH_THEN(X_CHOOSE_THEN `c:complex` MP_TAC) THEN
+      ASM_CASES_TAC `c = Cx(&0)` THENL
+       [ASM_SIMP_TAC[CEXP_NZ; COMPLEX_FIELD
+         `~(x = Cx(&0)) /\ ~(y = Cx(&0)) ==> ~(x / y = Cx(&0))`] THEN
+        ASM_MESON_TAC[];
+      ASM_SIMP_TAC[COMPLEX_FIELD
+       `~(y = Cx(&0)) /\ ~(z = Cx(&0))
+        ==> (x / y = z <=> y = inv(z) * x)`] THEN
+      DISCH_TAC THEN EXISTS_TAC `\z:complex. clog(inv c) + g z` THEN
+      ASM_SIMP_TAC[CEXP_CLOG; CEXP_ADD; COMPLEX_INV_EQ_0] THEN
+      MATCH_MP_TAC HOLOMORPHIC_ON_ADD THEN
+      REWRITE_TAC[HOLOMORPHIC_ON_CONST] THEN
+      ASM_MESON_TAC[HOLOMORPHIC_ON_OPEN]]];
+
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `f:complex->complex` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `f:complex->complex`) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\z:complex. cexp(g z / Cx(&2))` THEN
+    ASM_SIMP_TAC[GSYM CEXP_N; COMPLEX_RING `Cx(&2) * z / Cx(&2) = z`] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN
+    REWRITE_TAC[HOLOMORPHIC_ON_CEXP] THEN
+    MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+    ASM_SIMP_TAC[HOLOMORPHIC_ON_CONST] THEN
+    CONV_TAC COMPLEX_RING;
+
+    MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_FORALL THEN MESON_TAC[];
+
+    POP_ASSUM MP_TAC THEN SPEC_TAC(`s:complex->bool`,`s:complex->bool`) THEN
+    REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC; FORALL_AND_THM] THEN
+    SUBGOAL_THEN
+     `!s:complex->bool.
+          open s /\ connected s /\ Cx(&0) IN s /\ s SUBSET ball(Cx(&0),&1) /\
+          (!f. f holomorphic_on s /\ (!z. z IN s ==> ~(f z = Cx(&0))) /\
+               (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+               ==> ?g. g holomorphic_on s /\ (!z. z IN s ==> f z = g z pow 2))
+          ==> ?f g. f holomorphic_on s /\
+                    g holomorphic_on ball(Cx(&0),&1) /\
+                    (!z. z IN s ==> f z IN ball(Cx(&0),&1) /\ g(f z) = z) /\
+                    (!z. z IN ball(Cx(&0),&1) ==> g z IN s /\ f(g z) = z)`
+    ASSUME_TAC THENL
+     [ALL_TAC;
+      REPEAT STRIP_TAC THEN
+      ASM_CASES_TAC `s:complex->bool = {}` THEN ASM_REWRITE_TAC[] THEN
+      ASM_CASES_TAC `s = (:complex)` THEN ASM_REWRITE_TAC[] THEN
+      SUBGOAL_THEN `?a b:complex. a IN s /\ ~(b IN s)` STRIP_ASSUME_TAC THENL
+       [ASM SET_TAC[]; ALL_TAC] THEN
+      SUBGOAL_THEN
+       `?f. f holomorphic_on s /\
+            f(a) = Cx(&0) /\
+            IMAGE f s SUBSET ball(Cx(&0),&1) /\
+            (!w z. w IN s /\ z IN s /\ f w = f z ==> w = z)`
+      MP_TAC THENL
+       [FIRST_X_ASSUM(K ALL_TAC o SPEC `(:complex)`) THEN
+        FIRST_X_ASSUM(MP_TAC o SPEC `\z:complex. z - b`) THEN ANTS_TAC THENL
+         [SIMP_TAC[HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_CONST; HOLOMORPHIC_ON_ID;
+                   COMPLEX_RING `x - b:complex = y - b <=> x = y`] THEN
+          ASM_MESON_TAC[COMPLEX_SUB_0];
+         ALL_TAC] THEN
+        REWRITE_TAC[COMPLEX_EQ_SUB_RADD] THEN
+        DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC) THEN
+        MP_TAC(ISPECL [`s:complex->bool`; `g:complex->complex`]
+          OPEN_MAPPING_THM) THEN ASM_REWRITE_TAC[] THEN
+        FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+        DISCH_THEN(MP_TAC o SPEC `a:complex`) THEN ASM_REWRITE_TAC[SUBSET] THEN
+        DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN ANTS_TAC THENL
+         [SUBGOAL_THEN `a IN ball(a,d) /\ (a + Cx(d / &2)) IN ball(a,d) /\
+                        ~(a + Cx(d / &2) = a)`
+          MP_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+          ASM_REWRITE_TAC[CENTRE_IN_BALL;
+                          COMPLEX_EQ_ADD_LCANCEL_0; CX_INJ] THEN
+          REWRITE_TAC[IN_BALL; NORM_ARITH `dist(a,a + d) = norm d`] THEN
+          REWRITE_TAC[COMPLEX_NORM_CX] THEN ASM_REAL_ARITH_TAC;
+          ALL_TAC] THEN
+        DISCH_THEN(MP_TAC o SPEC `ball(a:complex,d)`) THEN
+        ASM_REWRITE_TAC[OPEN_BALL] THEN REWRITE_TAC[OPEN_CONTAINS_BALL] THEN
+        DISCH_THEN(MP_TAC o SPEC `(g:complex->complex) a`) THEN
+        ASM_SIMP_TAC[FUN_IN_IMAGE; CENTRE_IN_BALL] THEN
+        DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+        SUBGOAL_THEN `!z:complex. z IN s ==> ~(g(z) IN ball(--(g a),r))`
+        MP_TAC THENL
+         [REWRITE_TAC[IN_BALL] THEN X_GEN_TAC `z:complex` THEN
+          REPEAT DISCH_TAC THEN
+          FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+          DISCH_THEN(MP_TAC o SPEC `--((g:complex->complex) z)`) THEN
+          ASM_REWRITE_TAC[IN_BALL; NORM_ARITH `dist(w,--z) = dist(--w,z)`] THEN
+          REWRITE_TAC[IN_IMAGE; NOT_EXISTS_THM] THEN X_GEN_TAC `w:complex` THEN
+          ASM_CASES_TAC `w:complex = z` THENL
+           [ASM_REWRITE_TAC[COMPLEX_RING `--z = z <=> z = Cx(&0)`] THEN
+            ASM_MESON_TAC[COMPLEX_RING `Cx(&0) pow 2 + b = b`];
+            ASM_MESON_TAC[COMPLEX_RING `(--z:complex) pow 2 = z pow 2`]];
+          REWRITE_TAC[IN_BALL; NORM_ARITH `dist(--a,b) = norm(b + a)`] THEN
+          ASM_CASES_TAC `!z:complex. z IN s ==> ~(g z + g a = Cx(&0))` THENL
+           [REWRITE_TAC[REAL_NOT_LT] THEN DISCH_TAC;
+            ASM_MESON_TAC[COMPLEX_NORM_0]] THEN
+          EXISTS_TAC `\z:complex.
+            Cx(r / &3) / (g z + g a) - Cx(r / &3) / (g a + g a)` THEN
+          REWRITE_TAC[COMPLEX_SUB_REFL] THEN CONJ_TAC THENL
+           [MATCH_MP_TAC HOLOMORPHIC_ON_SUB THEN
+            REWRITE_TAC[HOLOMORPHIC_ON_CONST] THEN
+            MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+            ASM_SIMP_TAC[HOLOMORPHIC_ON_ADD; HOLOMORPHIC_ON_CONST; ETA_AX];
+            ASM_SIMP_TAC[IMP_CONJ; CX_INJ; REAL_LT_IMP_NZ;
+             REAL_ARITH `&0 < r ==> ~(r / &3 = &0)`;
+             COMPLEX_FIELD
+             `~(a = Cx(&0)) /\ ~(x + k = Cx(&0)) /\ ~(y + k = Cx(&0))
+              ==> (a / (x + k) - c = a / (y + k) - c <=> x = y)`] THEN
+            CONJ_TAC THENL [REWRITE_TAC[dist]; ASM_MESON_TAC[]] THEN
+            REWRITE_TAC[FORALL_IN_IMAGE; COMPLEX_SUB_LZERO; NORM_NEG] THEN
+            X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+            MATCH_MP_TAC(NORM_ARITH
+             `norm(x) <= &1 / &3 /\ norm(y) <= &1 / &3
+              ==> norm(x - y) < &1`) THEN
+            REWRITE_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_CX; REAL_ABS_DIV] THEN
+            ASM_SIMP_TAC[real_abs; REAL_LT_IMP_LE; REAL_POS] THEN
+            REWRITE_TAC[REAL_ARITH
+             `r / &3 / x <= &1 / &3 <=> r / x <= &1`] THEN
+            ASM_SIMP_TAC[REAL_LE_LDIV_EQ; NORM_POS_LT; COMPLEX_NORM_NZ] THEN
+            ASM_SIMP_TAC[REAL_MUL_LID]]];
+        REWRITE_TAC[MESON[]
+         `(!x y. P x /\ P y /\ f x = f y ==> x = y) <=>
+          (!x y. P x /\ P y ==> (f x = f y <=> x = y))`] THEN
+        DISCH_THEN(X_CHOOSE_THEN `h:complex->complex` STRIP_ASSUME_TAC) THEN
+        MP_TAC(ISPECL [`h:complex->complex`; `s:complex->bool`]
+            HOLOMORPHIC_ON_INVERSE) THEN
+        ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+        DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
+         (X_CHOOSE_THEN `k:complex->complex` STRIP_ASSUME_TAC)) THEN
+        FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE (h:complex->complex) s`) THEN
+        ANTS_TAC THENL
+         [ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+           [MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN
+            ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON];
+            ASM SET_TAC[];
+            REWRITE_TAC[FORALL_IN_IMAGE]] THEN
+          X_GEN_TAC `f:complex->complex` THEN STRIP_TAC THEN
+          FIRST_X_ASSUM(MP_TAC o SPEC
+           `(f:complex->complex) o (h:complex->complex)`) THEN
+          ANTS_TAC THENL
+           [CONJ_TAC THENL
+             [ASM_MESON_TAC[HOLOMORPHIC_ON_COMPOSE]; ALL_TAC] THEN
+            ASM_REWRITE_TAC[o_THM] THEN ASM SET_TAC[];
+            ALL_TAC] THEN
+          REWRITE_TAC[o_THM] THEN
+          DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC) THEN
+          EXISTS_TAC `(g:complex->complex) o (k:complex->complex)` THEN
+          ASM_SIMP_TAC[o_THM] THEN MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN
+          ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+           (REWRITE_RULE[IMP_CONJ] HOLOMORPHIC_ON_SUBSET)) THEN ASM SET_TAC[];
+          ALL_TAC] THEN
+        REWRITE_TAC[FORALL_IN_IMAGE] THEN
+        DISCH_THEN(X_CHOOSE_THEN `f:complex->complex`
+          (X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC)) THEN
+        EXISTS_TAC `(f:complex->complex) o (h:complex->complex)` THEN
+        EXISTS_TAC `(k:complex->complex) o (g:complex->complex)` THEN
+        ASM_SIMP_TAC[o_THM; HOLOMORPHIC_ON_COMPOSE] THEN CONJ_TAC THENL
+         [MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE; ASM SET_TAC[]] THEN
+        ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+           (REWRITE_RULE[IMP_CONJ] HOLOMORPHIC_ON_SUBSET)) THEN
+        ASM SET_TAC[]]] THEN
+    X_GEN_TAC `s:complex->bool` THEN STRIP_TAC THEN
+    ABBREV_TAC
+     `ff = { h | h holomorphic_on s /\
+                 IMAGE h s SUBSET ball(Cx(&0),&1) /\
+                 h(Cx(&0)) = Cx(&0) /\
+                 (!x y. x IN s /\ y IN s ==> (h x = h y <=> x = y))}` THEN
+    SUBGOAL_THEN `(\z:complex. z) IN ff` MP_TAC THENL
+     [EXPAND_TAC "ff" THEN REWRITE_TAC[IN_ELIM_THM; IMAGE_ID] THEN
+      ASM_REWRITE_TAC[HOLOMORPHIC_ON_ID];
+      ASM_CASES_TAC `ff:(complex->complex)->bool = {}` THEN
+      ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN DISCH_TAC] THEN
+    SUBGOAL_THEN `!h. h IN ff ==> h holomorphic_on s` ASSUME_TAC THENL
+     [EXPAND_TAC "ff" THEN SIMP_TAC[IN_ELIM_THM]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?f:complex->complex.
+          f IN ff /\
+          (!h. h IN ff
+               ==> norm(complex_derivative h (Cx(&0)))
+                   <= norm(complex_derivative f (Cx(&0))))`
+    MP_TAC THENL
+     [MP_TAC(ISPEC
+       `{ norm(complex_derivative h (Cx(&0))) | h IN ff}` SUP) THEN
+      ANTS_TAC THENL
+       [ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+        ASM_REWRITE_TAC[IMAGE_EQ_EMPTY; FORALL_IN_IMAGE] THEN
+        FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+        DISCH_THEN(MP_TAC o SPEC `Cx(&0)`) THEN
+        ASM_REWRITE_TAC[SUBSET; IN_BALL; COMPLEX_SUB_LZERO;
+                        dist; NORM_NEG] THEN
+        DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+        EXISTS_TAC `inv(r):real` THEN X_GEN_TAC `f:complex->complex` THEN
+        EXPAND_TAC "ff" THEN
+        REWRITE_TAC[IN_ELIM_THM; FORALL_IN_IMAGE; SUBSET] THEN
+        ASM_REWRITE_TAC[SUBSET; IN_BALL; COMPLEX_SUB_LZERO;
+                        dist; NORM_NEG] THEN
+        STRIP_TAC THEN
+        MP_TAC(ISPEC `\z. (f:complex->complex) (Cx(r) * z)`
+          SCHWARZ_LEMMA) THEN
+        ASM_REWRITE_TAC[COMPLEX_MUL_RZERO] THEN
+        SUBGOAL_THEN
+         `!z. z IN ball(Cx(&0),&1)
+              ==> ((\z. f (Cx r * z)) has_complex_derivative
+                   complex_derivative f (Cx(r) * z) * Cx(r)) (at z)`
+         (LABEL_TAC "*")
+        THENL
+         [REPEAT STRIP_TAC THEN MATCH_MP_TAC
+           (REWRITE_RULE[o_DEF] COMPLEX_DIFF_CHAIN_AT) THEN
+          CONJ_TAC THENL
+           [COMPLEX_DIFF_TAC THEN REWRITE_TAC[COMPLEX_MUL_RID];
+            REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE]] THEN
+          MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT THEN
+          EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[] THEN
+          FIRST_X_ASSUM MATCH_MP_TAC THEN
+          REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX] THEN
+          ASM_SIMP_TAC[real_abs; REAL_LT_IMP_LE] THEN
+          GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
+          ASM_SIMP_TAC[GSYM COMPLEX_IN_BALL_0; REAL_LT_LMUL_EQ];
+          ALL_TAC] THEN
+        ANTS_TAC THENL
+         [CONJ_TAC THENL
+           [REWRITE_TAC[holomorphic_on] THEN
+            ASM_MESON_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN];
+            REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+            FIRST_X_ASSUM MATCH_MP_TAC THEN
+            REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX] THEN
+            ASM_SIMP_TAC[real_abs; REAL_LT_IMP_LE] THEN
+            GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
+            ASM_SIMP_TAC[GSYM COMPLEX_IN_BALL_0; REAL_LT_LMUL_EQ]];
+          REMOVE_THEN "*" (MP_TAC o SPEC `Cx(&0)`) THEN
+          REWRITE_TAC[CENTRE_IN_BALL; REAL_LT_01] THEN
+          DISCH_THEN(SUBST1_TAC o
+            MATCH_MP HAS_COMPLEX_DERIVATIVE_DERIVATIVE) THEN
+          DISCH_THEN(MP_TAC o CONJUNCT1 o CONJUNCT2) THEN
+          REWRITE_TAC[COMPLEX_MUL_RZERO; COMPLEX_NORM_MUL] THEN
+          ASM_SIMP_TAC[COMPLEX_NORM_CX; real_abs; REAL_LT_IMP_LE] THEN
+          ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; real_div; REAL_MUL_LID]];
+        ALL_TAC] THEN
+      ABBREV_TAC
+       `l = sup { norm(complex_derivative h (Cx(&0))) | h IN ff}` THEN
+      REWRITE_TAC[FORALL_IN_GSPEC] THEN DISCH_TAC THEN
+      SUBGOAL_THEN
+       `?f. (!n. (f n) IN ff) /\
+            ((\n. Cx(norm(complex_derivative (f n) (Cx(&0))))) --> Cx(l))
+            sequentially`
+      STRIP_ASSUME_TAC THENL
+       [SUBGOAL_THEN
+         `!n. ?f. f IN ff /\
+                  abs(norm(complex_derivative f (Cx (&0))) - l) < inv(&n + &1)`
+        MP_TAC THENL
+         [X_GEN_TAC `n:num` THEN
+          FIRST_ASSUM(MP_TAC o SPEC `l - inv(&n + &1)` o CONJUNCT2) THEN
+          REWRITE_TAC[REAL_ARITH `l <= l - i <=> ~(&0 < i)`; REAL_LT_INV_EQ;
+             REAL_ARITH `&0 < &n + &1`; NOT_FORALL_THM; NOT_IMP] THEN
+          MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:complex->complex` THEN
+          ASM_CASES_TAC `(f:complex->complex) IN ff` THEN
+          ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(REAL_ARITH
+           `n <= l ==> ~(n <= l - e) ==> abs(n - l) < e`) THEN
+          ASM_SIMP_TAC[];
+          REWRITE_TAC[SKOLEM_THM; FORALL_AND_THM] THEN
+          MATCH_MP_TAC MONO_EXISTS THEN
+          X_GEN_TAC `f:num->complex->complex` THEN
+          STRIP_TAC THEN ASM_REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+          X_GEN_TAC `e:real` THEN
+          DISCH_THEN(MP_TAC o GEN_REWRITE_RULE I [REAL_ARCH_INV]) THEN
+          MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN STRIP_TAC THEN
+          X_GEN_TAC `m:num` THEN DISCH_TAC THEN REWRITE_TAC[dist] THEN
+          MATCH_MP_TAC REAL_LT_TRANS THEN EXISTS_TAC `inv(&m + &1)` THEN
+          ASM_REWRITE_TAC[COMPLEX_NORM_CX; GSYM CX_SUB] THEN
+          MATCH_MP_TAC REAL_LT_TRANS THEN EXISTS_TAC `inv(&N)` THEN
+          ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LT_INV2 THEN
+          ASM_REWRITE_TAC[REAL_OF_NUM_LT; REAL_OF_NUM_ADD] THEN ASM_ARITH_TAC];
+        ALL_TAC] THEN
+      MP_TAC(ISPECL [`f:num->complex->complex`; `ff:(complex->complex)->bool`;
+                     `s:complex->bool`] MONTEL) THEN
+      ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+       [EXPAND_TAC "ff" THEN SIMP_TAC[IN_ELIM_THM] THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_BALL; COMPLEX_SUB_LZERO;
+                    dist; NORM_NEG] THEN
+        MESON_TAC[REAL_LT_IMP_LE];
+        ALL_TAC] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:complex->complex` THEN
+      DISCH_THEN(X_CHOOSE_THEN `r:num->num` STRIP_ASSUME_TAC) THEN
+      SUBGOAL_THEN
+       `g complex_differentiable (at(Cx(&0))) /\
+        norm(complex_derivative g (Cx(&0))) = l`
+      STRIP_ASSUME_TAC THENL
+       [MP_TAC(ISPECL [`(f:num->complex->complex) o (r:num->num)`;
+                       `(\n:num z. complex_derivative (f n) z) o (r:num->num)`;
+                       `g:complex->complex`; `s:complex->bool`]
+                    HAS_COMPLEX_DERIVATIVE_UNIFORM_SEQUENCE) THEN
+        ASM_REWRITE_TAC[o_THM] THEN ANTS_TAC THENL
+         [CONJ_TAC THENL
+           [REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+            REPEAT STRIP_TAC THEN
+            MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT THEN
+            EXISTS_TAC `s:complex->bool` THEN ASM_SIMP_TAC[];
+            ALL_TAC] THEN
+          X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+          FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+          DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+          MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+          STRIP_TAC THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `e:real` THEN
+          DISCH_TAC THEN REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+          FIRST_X_ASSUM(MP_TAC o SPECL [`cball(z:complex,d)`; `e:real`]) THEN
+          ASM_REWRITE_TAC[COMPACT_CBALL; GE] THEN
+          MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[];
+          DISCH_THEN(X_CHOOSE_THEN `g':complex->complex` MP_TAC) THEN
+          DISCH_THEN(MP_TAC o SPEC `Cx(&0)`) THEN
+          ASM_REWRITE_TAC[IMP_CONJ_ALT] THEN
+          DISCH_THEN(MP_TAC o ISPEC `\z:complex. Cx(norm z)` o MATCH_MP
+           (REWRITE_RULE[IMP_CONJ_ALT] LIM_CONTINUOUS_FUNCTION)) THEN
+          REWRITE_TAC[CONTINUOUS_AT_CX_NORM] THEN DISCH_TAC THEN DISCH_TAC THEN
+          CONJ_TAC THENL [ASM_MESON_TAC[complex_differentiable]; ALL_TAC] THEN
+          GEN_REWRITE_TAC I [GSYM CX_INJ] THEN
+          FIRST_ASSUM(SUBST1_TAC o
+            MATCH_MP HAS_COMPLEX_DERIVATIVE_DERIVATIVE) THEN
+          MATCH_MP_TAC(ISPEC `sequentially` LIM_UNIQUE) THEN EXISTS_TAC
+           `\n. Cx(norm(complex_derivative(f((r:num->num) n)) (Cx (&0))))` THEN
+          ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN MP_TAC(ISPECL
+           [`\n:num. Cx(norm(complex_derivative (f n) (Cx (&0))))`;
+            `r:num->num`; `Cx l`] LIM_SUBSEQUENCE) THEN
+          ASM_REWRITE_TAC[o_DEF]];
+        ALL_TAC] THEN
+      ASM_SIMP_TAC[] THEN
+      SUBGOAL_THEN `~(?c. !z. z IN s ==> (g:complex->complex) z = c)`
+      ASSUME_TAC THENL
+       [DISCH_THEN(X_CHOOSE_TAC `c:complex`) THEN
+        SUBGOAL_THEN `complex_derivative g (Cx(&0)) = Cx(&0)` MP_TAC THENL
+         [MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+          MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+          MAP_EVERY EXISTS_TAC
+           [`(\z. c):complex->complex`; `s:complex->bool`] THEN
+          ASM_REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_CONST] THEN ASM_MESON_TAC[];
+          DISCH_THEN(MP_TAC o AP_TERM `norm:complex->real`) THEN
+          ASM_REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_NUM] THEN
+          DISCH_THEN SUBST_ALL_TAC THEN
+          FIRST_ASSUM(MP_TAC o SPEC `\z:complex. z` o CONJUNCT1) THEN
+          ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+          REWRITE_TAC[COMPLEX_DERIVATIVE_ID; COMPLEX_NORM_CX] THEN
+          REAL_ARITH_TAC];
+        ALL_TAC] THEN
+      EXPAND_TAC "ff" THEN REWRITE_TAC[IN_ELIM_THM] THEN ASM_REWRITE_TAC[] THEN
+      REPEAT CONJ_TAC THENL
+       [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; COMPLEX_IN_BALL_0] THEN
+        SUBGOAL_THEN `!z. z IN s ==> norm((g:complex->complex) z) <= &1`
+        ASSUME_TAC THENL
+         [X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+          MATCH_MP_TAC(ISPEC `sequentially` LIM_NORM_UBOUND) THEN
+          EXISTS_TAC `\n:num. (f:num->complex->complex) (r n) z` THEN
+          ASM_SIMP_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+          MATCH_MP_TAC ALWAYS_EVENTUALLY THEN X_GEN_TAC `n:num` THEN
+          SUBGOAL_THEN
+           `(f:num->complex->complex) (r(n:num)) IN ff`
+          MP_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+          EXPAND_TAC "ff" THEN REWRITE_TAC[IN_ELIM_THM] THEN
+          ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; COMPLEX_IN_BALL_0;
+                       REAL_LT_IMP_LE];
+          X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+          ASM_SIMP_TAC[REAL_LT_LE] THEN DISCH_TAC THEN MP_TAC(ISPECL
+           [`g:complex->complex`; `s:complex->bool`; `s:complex->bool`;
+            `z:complex`] MAXIMUM_MODULUS_PRINCIPLE) THEN
+          ASM_REWRITE_TAC[SUBSET_REFL]];
+        MATCH_MP_TAC(ISPEC `sequentially` LIM_UNIQUE) THEN
+        EXISTS_TAC `\n:num. (f:num->complex->complex) (r n) (Cx(&0))` THEN
+        ASM_SIMP_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+        MATCH_MP_TAC LIM_EVENTUALLY THEN MATCH_MP_TAC ALWAYS_EVENTUALLY THEN
+        X_GEN_TAC `n:num` THEN
+        SUBGOAL_THEN `(f:num->complex->complex) (r(n:num)) IN ff`
+        MP_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+        EXPAND_TAC "ff" THEN SIMP_TAC[IN_ELIM_THM];
+        MATCH_MP_TAC(REWRITE_RULE
+         [MESON[] `(!x y. P x /\ P y /\ f x = f y ==> x = y) <=>
+                   (!x y. P x /\ P y ==> (f x = f y <=> x = y))`]
+         HURWITZ_INJECTIVE) THEN
+        EXISTS_TAC `(f:num->complex->complex) o (r:num->num)` THEN
+        ASM_SIMP_TAC[o_THM] THEN X_GEN_TAC `n:num` THEN
+        SUBGOAL_THEN `(f:num->complex->complex) (r(n:num)) IN ff`
+        MP_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+        EXPAND_TAC "ff" THEN SIMP_TAC[IN_ELIM_THM]];
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:complex->complex` THEN
+    STRIP_TAC THEN
+    MP_TAC(SPECL [`f:complex->complex`; `s:complex->bool`]
+          HOLOMORPHIC_ON_INVERSE) THEN
+    ANTS_TAC THENL
+     [UNDISCH_TAC `(f:complex->complex) IN ff` THEN EXPAND_TAC "ff" THEN
+      REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[];
+      DISCH_THEN(MP_TAC o CONJUNCT2)] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:complex->complex` THEN
+    ASM_CASES_TAC `IMAGE (f:complex->complex) s = ball(Cx(&0),&1)` THENL
+     [ASM_SIMP_TAC[] THEN ASM SET_TAC[]; ALL_TAC] THEN
+    STRIP_TAC THEN
+    UNDISCH_TAC `~(IMAGE (f:complex->complex) s = ball(Cx(&0),&1))` THEN
+    MATCH_MP_TAC(TAUT `p ==> ~p ==> q`) THEN
+    MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+     [UNDISCH_TAC `(f:complex->complex) IN ff` THEN EXPAND_TAC "ff" THEN
+      REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    REWRITE_TAC[SUBSET; COMPLEX_IN_BALL_0] THEN
+    X_GEN_TAC `a:complex` THEN DISCH_TAC THEN
+    REWRITE_TAC[IN_IMAGE; MESON[]
+      `(?x. a = f x /\ x IN s) <=> ~(!x. x IN s ==> ~(f x = a))`] THEN
+    DISCH_TAC THEN
+    MP_TAC(ISPEC `a:complex` BALL_BIHOLOMORPHISM_EXISTS) THEN
+    ASM_REWRITE_TAC[COMPLEX_IN_BALL_0; NOT_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`t:complex->complex`; `t':complex->complex`] THEN
+    STRIP_TAC THEN
+    SUBGOAL_THEN
+     `!z. z IN s ==> norm((f:complex->complex) z) < &1`
+    ASSUME_TAC THENL
+     [UNDISCH_TAC `(f:complex->complex) IN ff` THEN EXPAND_TAC "ff" THEN
+      SIMP_TAC[IN_ELIM_THM; SUBSET; FORALL_IN_IMAGE; COMPLEX_IN_BALL_0];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?sq. sq holomorphic_on (IMAGE (t o f) s) /\
+           !z. z IN s
+               ==> sq((t:complex->complex) ((f:complex->complex) z)) pow 2 =
+                   t(f z)`
+    STRIP_ASSUME_TAC THENL
+     [UNDISCH_TAC
+       `!f. f holomorphic_on s /\ (!z. z IN s ==> ~(f z = Cx (&0))) /\
+            (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+            ==> ?g. g holomorphic_on s /\
+                    (!z. z IN s ==> f z = g z pow 2)` THEN
+      DISCH_THEN(MP_TAC o SPEC
+       `(t:complex->complex) o (f:complex->complex)`) THEN
+      ASM_REWRITE_TAC[FORALL_IN_IMAGE; o_THM] THEN ANTS_TAC THENL
+       [REPEAT CONJ_TAC THENL
+         [MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN ASM_SIMP_TAC[] THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+           (REWRITE_RULE[IMP_CONJ] HOLOMORPHIC_ON_SUBSET)) THEN
+          UNDISCH_TAC `(f:complex->complex) IN ff` THEN EXPAND_TAC "ff" THEN
+          REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[];
+          UNDISCH_TAC `(f:complex->complex) IN ff` THEN EXPAND_TAC "ff" THEN
+          REWRITE_TAC[IN_ELIM_THM; SUBSET; FORALL_IN_IMAGE] THEN
+          RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; COMPLEX_IN_BALL_0]) THEN
+          REWRITE_TAC[COMPLEX_IN_BALL_0] THEN STRIP_TAC THEN
+          GEN_TAC THEN DISCH_TAC THEN
+          DISCH_THEN(MP_TAC o AP_TERM `t':complex->complex`) THEN
+          ASM_SIMP_TAC[] THEN ASM_MESON_TAC[];
+          UNDISCH_TAC `(f:complex->complex) IN ff` THEN EXPAND_TAC "ff" THEN
+          REWRITE_TAC[IN_ELIM_THM] THEN
+          REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; COMPLEX_IN_BALL_0] THEN
+          REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+          REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN ASM_MESON_TAC[]];
+        DISCH_THEN(X_CHOOSE_THEN `q:complex->complex` STRIP_ASSUME_TAC) THEN
+        EXISTS_TAC `(q:complex->complex) o (g:complex->complex) o
+                    (t':complex->complex)` THEN
+        ASM_REWRITE_TAC[o_THM] THEN CONJ_TAC THENL
+         [MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN CONJ_TAC THENL
+           [MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN CONJ_TAC;
+            ALL_TAC] THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+           (REWRITE_RULE[IMP_CONJ] HOLOMORPHIC_ON_SUBSET)) THEN
+          REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; COMPLEX_IN_BALL_0; o_THM] THENL
+           [ASM_MESON_TAC[]; ASM SET_TAC[]; ASM_MESON_TAC[]];
+          X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+          MATCH_MP_TAC EQ_TRANS THEN
+          EXISTS_TAC `(q:complex->complex) z pow 2` THEN
+          CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+          AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+          UNDISCH_TAC `(f:complex->complex) IN ff` THEN EXPAND_TAC "ff" THEN
+          REWRITE_TAC[IN_ELIM_THM; SUBSET; FORALL_IN_IMAGE] THEN
+          REWRITE_TAC[COMPLEX_IN_BALL_0] THEN ASM_MESON_TAC[]]];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!z. z IN s
+          ==> norm((sq:complex->complex)
+                   ((t:complex->complex)((f:complex->complex) z))) < &1`
+    ASSUME_TAC THENL
+     [REPEAT STRIP_TAC THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM REAL_ABS_NORM] THEN
+      REWRITE_TAC[GSYM ABS_SQUARE_LT_1; GSYM COMPLEX_NORM_POW] THEN
+      ASM_SIMP_TAC[];
+      ALL_TAC] THEN
+    MP_TAC(ISPEC
+     `(sq:complex->complex)
+      ((t:complex->complex)((f:complex->complex) (Cx(&0))))`
+      BALL_BIHOLOMORPHISM_EXISTS) THEN
+    ASM_SIMP_TAC[COMPLEX_IN_BALL_0; NOT_IMP; NOT_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`r:complex->complex`; `r':complex->complex`] THEN
+    STRIP_TAC THEN UNDISCH_TAC
+     `!h. h IN ff
+          ==> norm(complex_derivative h (Cx (&0))) <=
+              norm(complex_derivative f (Cx (&0)))` THEN
+    DISCH_THEN(fun th -> MP_TAC(SPEC
+     `(r:complex->complex) o (sq:complex->complex) o
+      (t:complex->complex) o (f:complex->complex)` th) THEN
+     MP_TAC(SPEC `\z:complex. z` th)) THEN
+    ASM_REWRITE_TAC[COMPLEX_DERIVATIVE_ID; COMPLEX_NORM_CX; REAL_ABS_NUM] THEN
+    DISCH_TAC THEN REWRITE_TAC[NOT_IMP; REAL_NOT_LE] THEN
+    EXPAND_TAC "ff" THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN REPEAT CONJ_TAC THENL
+     [REPEAT(MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN CONJ_TAC) THEN
+      ASM_SIMP_TAC[] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+           (REWRITE_RULE[IMP_CONJ] HOLOMORPHIC_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; o_THM; COMPLEX_IN_BALL_0] THEN
+      ASM_SIMP_TAC[];
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; o_THM; COMPLEX_IN_BALL_0] THEN
+      ASM_SIMP_TAC[];
+      ASM_SIMP_TAC[o_THM];
+      MAP_EVERY X_GEN_TAC [`w:complex`; `z:complex`] THEN STRIP_TAC THEN
+      EQ_TAC THEN SIMP_TAC[] THEN
+      DISCH_THEN(MP_TAC o AP_TERM `r':complex->complex`) THEN
+      ASM_SIMP_TAC[o_THM] THEN
+      DISCH_THEN(MP_TAC o AP_TERM `\z:complex. z pow 2`) THEN
+      ASM_SIMP_TAC[] THEN
+      DISCH_THEN(MP_TAC o AP_TERM `t':complex->complex`) THEN
+      ASM_SIMP_TAC[] THEN ASM_MESON_TAC[];
+      STRIP_TAC] THEN
+    MP_TAC(ISPEC
+     `(t':complex->complex) o (\z. z pow 2) o (r':complex->complex)`
+     SCHWARZ_LEMMA) THEN
+    REWRITE_TAC[] THEN ANTS_TAC THENL
+     [REPEAT CONJ_TAC THENL
+       [REPEAT(MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN CONJ_TAC) THEN
+        SIMP_TAC[HOLOMORPHIC_ON_POW; HOLOMORPHIC_ON_ID] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+           (REWRITE_RULE[IMP_CONJ] HOLOMORPHIC_ON_SUBSET)) THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; o_THM; COMPLEX_IN_BALL_0] THEN
+        ASM_SIMP_TAC[COMPLEX_NORM_POW; ABS_SQUARE_LT_1; REAL_ABS_NORM];
+        ASM_SIMP_TAC[COMPLEX_NORM_POW; ABS_SQUARE_LT_1; REAL_ABS_NORM; o_THM];
+        UNDISCH_THEN `(r:complex->complex) ((sq:complex->complex)
+                      ((t:complex->complex) (f(Cx(&0))))) = Cx (&0)`
+         (fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [SYM th]) THEN
+        ASM_SIMP_TAC[o_THM] THEN
+        UNDISCH_TAC `(f:complex->complex) IN ff` THEN EXPAND_TAC "ff" THEN
+        SIMP_TAC[IN_ELIM_THM]];
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN MATCH_MP_TAC
+       (TAUT `~r /\ (p /\ ~q ==> s) ==> p /\ (q' \/ q ==> r) ==> s`) THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[NOT_EXISTS_THM] THEN X_GEN_TAC `c:complex` THEN
+        ASM_CASES_TAC `c = Cx(&0)` THEN
+        ASM_SIMP_TAC[COMPLEX_NORM_CX; REAL_ABS_NUM; REAL_OF_NUM_EQ; ARITH] THEN
+        DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+        DISCH_THEN(fun th ->
+          MP_TAC(ISPEC `(r:complex->complex) (--(Cx(&1) / Cx(&2)))` th) THEN
+          MP_TAC(ISPEC `(r:complex->complex) (Cx(&1) / Cx(&2))` th)) THEN
+        MATCH_MP_TAC(TAUT `(p1 /\ p2) /\ (q1 /\ q2 ==> r)
+                           ==> (p1 ==> q1) ==> (p2 ==> q2) ==> r`) THEN
+        CONJ_TAC THENL
+         [CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+          REWRITE_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_CX; NORM_NEG] THEN
+          REAL_ARITH_TAC;
+          ALL_TAC] THEN
+        MATCH_MP_TAC(MESON[]
+         `~(b1 = b2) /\ a1 = a2 ==> (a1 = b1 /\ a2 = b2 ==> F)`) THEN
+        CONJ_TAC THENL
+         [ASM_REWRITE_TAC[COMPLEX_EQ_MUL_LCANCEL] THEN
+          DISCH_THEN(MP_TAC o AP_TERM `r':complex->complex`) THEN
+          FIRST_ASSUM(fun th ->
+            W(MP_TAC o PART_MATCH (lhand o rand) th o
+               lhand o lhand o snd)) THEN
+          REWRITE_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_CX; NORM_NEG] THEN
+          CONV_TAC REAL_RAT_REDUCE_CONV THEN DISCH_THEN SUBST1_TAC THEN
+          MATCH_MP_TAC(COMPLEX_RING
+           `x = --(Cx(&1) / Cx(&2)) ==> ~(Cx(&1) / Cx(&2) = x)`) THEN
+          FIRST_X_ASSUM MATCH_MP_TAC THEN
+          REWRITE_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_CX; NORM_NEG] THEN
+          CONV_TAC REAL_RAT_REDUCE_CONV;
+          REWRITE_TAC[o_DEF] THEN AP_TERM_TAC THEN
+          MATCH_MP_TAC(COMPLEX_RING
+           `x = Cx(&1) / Cx(&2) /\ y = --(Cx(&1) / Cx(&2))
+            ==> x pow 2 = y pow 2`) THEN
+          CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+          REWRITE_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_CX; NORM_NEG] THEN
+          CONV_TAC REAL_RAT_REDUCE_CONV];
+        REWRITE_TAC[GSYM REAL_LT_LE] THEN DISCH_TAC THEN
+        UNDISCH_TAC `&1 <= norm (complex_derivative f (Cx (&0)))` THEN
+        SUBGOAL_THEN
+         `complex_derivative f (Cx (&0)) =
+          complex_derivative (t' o (\z:complex. z pow 2) o r') (Cx(&0)) *
+          complex_derivative
+            (r o (sq:complex->complex) o (t:complex->complex) o f) (Cx(&0))`
+         (fun th -> REWRITE_TAC[th; COMPLEX_NORM_MUL])
+        THENL
+         [ALL_TAC;
+          REWRITE_TAC[REAL_ARITH `a * b < b <=> &0 < (&1 - a) * b`] THEN
+          DISCH_THEN(MP_TAC o MATCH_MP
+           (REAL_ARITH `&1 <= x ==> ~(x = &0)`)) THEN
+          SIMP_TAC[REAL_ENTIRE; NORM_EQ_0; GSYM NORM_POS_LT; DE_MORGAN_THM] THEN
+          ASM_SIMP_TAC[REAL_LT_MUL_EQ] THEN ASM_REAL_ARITH_TAC] THEN
+        MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_DERIVATIVE THEN
+        MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN THEN
+        EXISTS_TAC `((t':complex->complex) o
+                     (\z:complex. z pow 2) o (r':complex->complex)) o
+                    ((r:complex->complex) o (sq:complex->complex) o
+                     (t:complex->complex) o (f:complex->complex))` THEN
+        EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+         [ASM_SIMP_TAC[o_THM]; ALL_TAC] THEN
+        MATCH_MP_TAC COMPLEX_DIFF_CHAIN_AT THEN
+        ASM_REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE] THEN
+        CONJ_TAC THEN MATCH_MP_TAC HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT THENL
+         [EXISTS_TAC `s:complex->bool` THEN ASM_REWRITE_TAC[];
+          EXISTS_TAC `ball(Cx(&0),&1)` THEN
+          ASM_REWRITE_TAC[OPEN_BALL; CENTRE_IN_BALL; REAL_LT_01] THEN
+          REPEAT(MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN CONJ_TAC) THEN
+          SIMP_TAC[HOLOMORPHIC_ON_POW; HOLOMORPHIC_ON_ID] THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+           (REWRITE_RULE[IMP_CONJ] HOLOMORPHIC_ON_SUBSET)) THEN
+          REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; o_THM; COMPLEX_IN_BALL_0] THEN
+          ASM_SIMP_TAC[COMPLEX_NORM_POW; ABS_SQUARE_LT_1; REAL_ABS_NORM]]]];
+    ASM_CASES_TAC `s:complex->bool = {}` THEN ASM_REWRITE_TAC[] THEN
+    ASM_CASES_TAC `s = (:complex)` THEN ASM_REWRITE_TAC[] THENL
+     [ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+      MATCH_MP_TAC HOMEOMORPHIC_BALL_UNIV THEN REWRITE_TAC[REAL_LT_01];
+      REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
+      REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+      MESON_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON]];
+    STRIP_TAC THEN ASM_REWRITE_TAC[SIMPLY_CONNECTED_EMPTY] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP HOMEOMORPHIC_SIMPLY_CONNECTED_EQ) THEN
+    SIMP_TAC[CONVEX_IMP_SIMPLY_CONNECTED; CONVEX_BALL]]);;
+
+let CONTRACTIBLE_EQ_SIMPLY_CONNECTED_2D = prove
+ (`!s:real^2->bool. open s ==> (contractible s <=> simply_connected s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  REWRITE_TAC[CONTRACTIBLE_IMP_SIMPLY_CONNECTED] THEN
+  ASM_SIMP_TAC[SIMPLY_CONNECTED_EQ_HOMEOMORPHIC_TO_DISC] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[CONTRACTIBLE_EMPTY] THEN
+  ASM_MESON_TAC[HOMEOMORPHIC_CONTRACTIBLE_EQ; CONVEX_IMP_CONTRACTIBLE;
+                CONVEX_BALL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A further chain of equivalents about components of the complement of a    *)
+(* simply connected set (following 1.35 in Burckel's book).                  *)
+(* ------------------------------------------------------------------------- *)
+
+let [SIMPLY_CONNECTED_EQ_FRONTIER_PROPERTIES;
+     SIMPLY_CONNECTED_EQ_UNBOUNDED_COMPLEMENT_COMPONENTS;
+     SIMPLY_CONNECTED_EQ_EMPTY_INSIDE] = (CONJUNCTS o prove)
+ (`(!s:complex->bool.
+        open s
+        ==> (simply_connected s <=>
+             connected s /\
+             if bounded s then connected(frontier s)
+             else !c. c IN components(frontier s) ==> ~bounded c)) /\
+   (!s. open s
+        ==> (simply_connected s <=>
+             connected s /\
+             !c. c IN components ((:complex) DIFF s) ==> ~bounded c)) /\
+   (!s:complex->bool.
+        open s ==> (simply_connected s <=> connected s /\ inside s = {}))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN X_GEN_TAC `s:complex->bool` THEN
+  ASM_CASES_TAC `open(s:complex->bool)` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(TAUT
+   `(q3 ==> p) /\ (q2 ==> q3) /\ (q1 ==> q2) /\ (p ==> q1)
+    ==> (p <=> q1) /\ (p <=> q2) /\ (p <=> q3)`) THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[INSIDE_OUTSIDE] THEN
+    REWRITE_TAC[SET_RULE `UNIV DIFF (s UNION t) = {} <=>
+                          !x. ~(x IN s) ==> x IN t`] THEN
+    STRIP_TAC THEN ASM_SIMP_TAC[SIMPLY_CONNECTED_EQ_WINDING_NUMBER_ZERO] THEN
+    GEN_TAC THEN X_GEN_TAC `z:complex` THEN STRIP_TAC THEN
+    MATCH_MP_TAC WINDING_NUMBER_ZERO_IN_OUTSIDE THEN ASM_REWRITE_TAC[] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP OUTSIDE_MONO) THEN ASM SET_TAC[];
+    REWRITE_TAC[components; FORALL_IN_GSPEC; inside] THEN SET_TAC[];
+    ASM_CASES_TAC `connected(s:complex->bool)` THEN ASM_REWRITE_TAC[] THEN
+    COND_CASES_TAC THENL
+     [DISCH_TAC THEN
+      REWRITE_TAC[components; FORALL_IN_GSPEC; IN_DIFF; IN_UNIV] THEN
+      ASM_CASES_TAC `s:complex->bool = {}` THEN
+      ASM_SIMP_TAC[DIFF_EMPTY; CONNECTED_COMPONENT_EQ_SELF;
+                   CONNECTED_UNIV; IN_UNIV; NOT_BOUNDED_UNIV] THEN
+      ASM_CASES_TAC `s = (:complex)` THENL
+       [ASM_MESON_TAC[NOT_BOUNDED_UNIV]; ALL_TAC] THEN
+      X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP OUTSIDE_BOUNDED_NONEMPTY) THEN
+      REWRITE_TAC[outside; GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+      DISCH_THEN(X_CHOOSE_THEN `z:complex` STRIP_ASSUME_TAC) THEN
+      SUBGOAL_THEN
+       `connected_component ((:complex) DIFF s) w =
+        connected_component ((:complex) DIFF s) z`
+       (fun th -> ASM_REWRITE_TAC[th]) THEN
+      MATCH_MP_TAC JOINABLE_CONNECTED_COMPONENT_EQ THEN
+      EXISTS_TAC `frontier s :complex->bool` THEN ASM_REWRITE_TAC[] THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[frontier] THEN MATCH_MP_TAC(SET_RULE
+         `i = s ==> s' DIFF i SUBSET UNIV DIFF s`) THEN
+        ASM_REWRITE_TAC[INTERIOR_EQ];
+        ALL_TAC] THEN
+      ONCE_REWRITE_TAC[GSYM FRONTIER_COMPLEMENT] THEN CONJ_TAC THEN
+      MATCH_MP_TAC(SET_RULE
+       `frontier c SUBSET c /\ frontier c SUBSET f /\ ~(frontier c = {})
+        ==> ~(c INTER f = {})`) THEN
+      REWRITE_TAC[FRONTIER_OF_CONNECTED_COMPONENT_SUBSET] THEN
+      ASM_REWRITE_TAC[FRONTIER_EQ_EMPTY; CONNECTED_COMPONENT_EQ_EMPTY;
+                      IN_DIFF; IN_UNIV; CONNECTED_COMPONENT_EQ_UNIV;
+                      SET_RULE `UNIV DIFF s = UNIV <=> s = {}`] THEN
+      REWRITE_TAC[frontier] THEN MATCH_MP_TAC(SET_RULE
+       `c = s ==> c DIFF i SUBSET s`) THEN
+      ASM_REWRITE_TAC[CLOSURE_EQ] THEN
+      MATCH_MP_TAC CLOSED_CONNECTED_COMPONENT THEN
+      ASM_REWRITE_TAC[GSYM OPEN_CLOSED];
+      DISCH_TAC THEN REWRITE_TAC[components; FORALL_IN_GSPEC] THEN
+      X_GEN_TAC `w:complex` THEN REWRITE_TAC[IN_DIFF; IN_UNIV] THEN
+      DISCH_TAC THEN
+      SUBGOAL_THEN
+       `?z:complex. z IN frontier s /\
+                    z IN connected_component ((:real^2) DIFF s) w`
+      STRIP_ASSUME_TAC THENL
+       [ONCE_REWRITE_TAC[GSYM FRONTIER_COMPLEMENT] THEN
+        MATCH_MP_TAC(SET_RULE
+         `frontier c SUBSET c /\ frontier c SUBSET f /\ ~(frontier c = {})
+          ==> ?z. z IN f /\ z IN c`) THEN
+        ASM_REWRITE_TAC[FRONTIER_OF_CONNECTED_COMPONENT_SUBSET] THEN
+        CONJ_TAC THENL
+         [REWRITE_TAC[frontier] THEN MATCH_MP_TAC(SET_RULE
+           `c = s ==> c DIFF i SUBSET s`) THEN
+          ASM_REWRITE_TAC[CLOSURE_EQ] THEN
+          MATCH_MP_TAC CLOSED_CONNECTED_COMPONENT THEN
+          ASM_REWRITE_TAC[GSYM OPEN_CLOSED];
+          ASM_REWRITE_TAC[FRONTIER_EQ_EMPTY; CONNECTED_COMPONENT_EQ_EMPTY;
+                          CONNECTED_COMPONENT_EQ_UNIV; IN_DIFF; IN_UNIV] THEN
+          REWRITE_TAC[SET_RULE `UNIV DIFF s = UNIV <=> s = {}`] THEN
+          ASM_MESON_TAC[BOUNDED_EMPTY]];
+        FIRST_X_ASSUM(MP_TAC o SPEC
+         `connected_component (frontier s) (z:complex)`) THEN
+        REWRITE_TAC[components; IN_ELIM_THM] THEN
+        ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[CONTRAPOS_THM]] THEN
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] BOUNDED_SUBSET) THEN
+        SUBGOAL_THEN
+         `connected_component ((:complex) DIFF s) w =
+          connected_component ((:complex) DIFF s) z`
+        SUBST1_TAC THENL
+         [ASM_MESON_TAC[CONNECTED_COMPONENT_EQ];
+          MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+          ASM_REWRITE_TAC[IN; CONNECTED_COMPONENT_REFL_EQ] THEN
+          REWRITE_TAC[CONNECTED_CONNECTED_COMPONENT] THEN
+          MATCH_MP_TAC SUBSET_TRANS THEN
+          EXISTS_TAC `frontier s :complex->bool` THEN
+          REWRITE_TAC[CONNECTED_COMPONENT_SUBSET] THEN
+          REWRITE_TAC[frontier] THEN MATCH_MP_TAC(SET_RULE
+            `i = s ==> s' DIFF i SUBSET UNIV DIFF s`) THEN
+          ASM_REWRITE_TAC[INTERIOR_EQ]]]];
+    ALL_TAC] THEN
+  DISCH_THEN(fun th ->
+   ASSUME_TAC(MATCH_MP SIMPLY_CONNECTED_IMP_CONNECTED th) THEN MP_TAC th) THEN
+  ASM_SIMP_TAC[SIMPLY_CONNECTED_EQ_HOMEOMORPHIC_TO_DISC] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[BOUNDED_EMPTY; FRONTIER_EMPTY; CONNECTED_EMPTY] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homeomorphic]) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; homeomorphism] THEN
+  MAP_EVERY X_GEN_TAC [`g:real^2->real^2`; `f:real^2->real^2`] THEN
+  STRIP_TAC THEN MAP_EVERY ABBREV_TAC
+   [`D = \n. ball(vec 0:real^2,&1 - inv(&n + &2))`;
+    `A = \n. {z:real^2 | &1 - inv(&n + &2) < norm z /\ norm z < &1}`;
+    `X = \n:num. closure(IMAGE (f:real^2->real^2) (A n))`] THEN
+  SUBGOAL_THEN
+   `frontier s = INTERS {X n:real^2->bool | n IN (:num)}`
+  SUBST1_TAC THENL
+   [ASM_SIMP_TAC[frontier; INTERIOR_OPEN; INTERS_GSPEC; IN_UNIV] THEN
+    MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET; IN_DIFF] THEN X_GEN_TAC `x:real^2` THEN
+      STRIP_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN X_GEN_TAC `n:num` THEN
+      UNDISCH_TAC `(x:real^2) IN closure s` THEN
+      SUBGOAL_THEN
+       `s = IMAGE (f:real^2->real^2) (closure (D(n:num))) UNION IMAGE f (A n)`
+      SUBST1_TAC THENL
+       [EXPAND_TAC "s" THEN MATCH_MP_TAC(SET_RULE
+         `t UNION u = s /\ (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+          ==> IMAGE f s = IMAGE f t UNION IMAGE f u`) THEN
+        CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+        MAP_EVERY EXPAND_TAC ["A"; "D"] THEN
+        SIMP_TAC[CLOSURE_BALL; REAL_SUB_LT; REAL_INV_LT_1;
+                 REAL_ARITH `&1 < &n + &2`] THEN
+        REWRITE_TAC[EXTENSION; IN_UNION; COMPLEX_IN_BALL_0; IN_CBALL_0;
+                   IN_ELIM_THM] THEN GEN_TAC THEN
+        MATCH_MP_TAC(REAL_ARITH
+         `&0 < e /\ e <= &1
+          ==> (x <= &1 - e \/ &1 - e < x /\ x < &1 <=> x < &1)`) THEN
+        SIMP_TAC[REAL_LT_INV_EQ; REAL_INV_LE_1; REAL_ARITH `&1 <= &n + &2`;
+                 REAL_ARITH `&0 < &n + &2`];
+        EXPAND_TAC "X" THEN REWRITE_TAC[CLOSURE_UNION] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `~(x IN s) ==> t SUBSET s ==> x IN t UNION u ==> x IN u`)) THEN
+        EXPAND_TAC "D" THEN
+        SIMP_TAC[CLOSURE_BALL; REAL_SUB_LT; REAL_INV_LT_1;
+                 REAL_ARITH `&1 < &n + &2`; COMPACT_CBALL] THEN
+        MATCH_MP_TAC(SET_RULE
+         `closure s = s /\ s SUBSET t ==> closure s SUBSET t`) THEN
+        CONJ_TAC THENL
+         [MATCH_MP_TAC CLOSURE_CLOSED THEN MATCH_MP_TAC COMPACT_IMP_CLOSED THEN
+          MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+          REWRITE_TAC[COMPACT_CBALL] THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP(REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET));
+          EXPAND_TAC "s" THEN MATCH_MP_TAC IMAGE_SUBSET] THEN
+        REWRITE_TAC[SUBSET; COMPLEX_IN_BALL_0; IN_CBALL_0] THEN GEN_TAC THEN
+        MATCH_MP_TAC(REAL_ARITH `&0 < x ==> a <= &1 - x ==> a < &1`) THEN
+        REWRITE_TAC[REAL_LT_INV_EQ] THEN REAL_ARITH_TAC];
+      MATCH_MP_TAC(SET_RULE
+       `s SUBSET t /\ s INTER u = {} ==> s SUBSET t DIFF u`) THEN
+      CONJ_TAC THENL
+       [EXPAND_TAC "X" THEN REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+        X_GEN_TAC `x:real^2` THEN DISCH_THEN(MP_TAC o SPEC `0`) THEN
+        SPEC_TAC(`x:real^2`,`x:real^2`) THEN REWRITE_TAC[GSYM SUBSET] THEN
+        MATCH_MP_TAC SUBSET_CLOSURE THEN EXPAND_TAC "s" THEN
+        MATCH_MP_TAC IMAGE_SUBSET THEN EXPAND_TAC "A" THEN
+        REWRITE_TAC[SUBSET; IN_ELIM_THM; COMPLEX_IN_BALL_0] THEN
+        REAL_ARITH_TAC;
+        REWRITE_TAC[EXTENSION; IN_INTER; IN_ELIM_THM; NOT_IN_EMPTY] THEN
+        MAP_EVERY EXPAND_TAC ["s"; "X"] THEN
+        REWRITE_TAC[TAUT `~(a /\ b) <=> b ==> ~a`; FORALL_IN_IMAGE] THEN
+        X_GEN_TAC `x:real^2` THEN REWRITE_TAC[COMPLEX_IN_BALL_0] THEN
+        DISCH_TAC THEN MP_TAC(SPEC `&1 - norm(x:real^2)` REAL_ARCH_INV) THEN
+        ASM_REWRITE_TAC[REAL_SUB_LT; NOT_FORALL_THM] THEN
+        MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `n:num` THEN STRIP_TAC THEN
+        MATCH_MP_TAC(SET_RULE
+         `!s. y IN s /\ (s INTER t = {}) ==> ~(y IN t)`) THEN
+        EXISTS_TAC `IMAGE (f:real^2->real^2) (D(n:num))` THEN CONJ_TAC THENL
+         [MATCH_MP_TAC FUN_IN_IMAGE THEN EXPAND_TAC "D" THEN
+          REWRITE_TAC[IN_BALL_0] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+           (REAL_ARITH `n < &1 - x ==> m < n ==> x < &1 - m`)) THEN
+          MATCH_MP_TAC REAL_LT_INV2 THEN
+          ASM_SIMP_TAC[REAL_OF_NUM_LT; LE_1] THEN REAL_ARITH_TAC;
+          SUBGOAL_THEN `open(IMAGE (f:real^2->real^2) (D(n:num)))` MP_TAC THENL
+           [MATCH_MP_TAC INVARIANCE_OF_DOMAIN THEN
+            SUBGOAL_THEN `(D:num->real^2->bool) n SUBSET ball(Cx(&0),&1)`
+            ASSUME_TAC THENL
+             [EXPAND_TAC "D" THEN REWRITE_TAC[GSYM COMPLEX_VEC_0] THEN
+              MATCH_MP_TAC SUBSET_BALL THEN
+              REWRITE_TAC[REAL_ARITH `&1 - x <= &1 <=> &0 <= x`] THEN
+              REWRITE_TAC[REAL_LE_INV_EQ] THEN REAL_ARITH_TAC;
+              REPEAT CONJ_TAC THENL
+               [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+                EXPAND_TAC "D" THEN REWRITE_TAC[OPEN_BALL];
+                ASM SET_TAC[]]];
+            SIMP_TAC[OPEN_INTER_CLOSURE_EQ_EMPTY] THEN DISCH_TAC THEN
+            MATCH_MP_TAC(SET_RULE
+             `!u. (!x y. x IN u /\ y IN u /\ f x = f y ==> x = y) /\
+                  s UNION t SUBSET u /\ s INTER t = {}
+                  ==> IMAGE f s INTER IMAGE f t = {}`) THEN
+            EXISTS_TAC `ball(Cx(&0),&1)` THEN
+            CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+            MAP_EVERY EXPAND_TAC ["D"; "A"] THEN
+            REWRITE_TAC[COMPLEX_IN_BALL_0; IN_BALL_0; SUBSET; NOT_IN_EMPTY;
+              IN_UNION; IN_ELIM_THM; IN_INTER; EXTENSION] THEN
+            CONJ_TAC THENL [GEN_TAC; REAL_ARITH_TAC] THEN
+            MATCH_MP_TAC(REAL_ARITH
+             `&0 < e ==> x < &1 - e \/ &1 - e < x /\ x < &1 ==> x < &1`) THEN
+            REWRITE_TAC[REAL_LT_INV_EQ] THEN REAL_ARITH_TAC]]]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!n. closed((X:num->complex->bool) n)` ASSUME_TAC THENL
+   [EXPAND_TAC "X" THEN REWRITE_TAC[CLOSED_CLOSURE]; ALL_TAC] THEN
+  SUBGOAL_THEN `!n. connected((X:num->complex->bool) n)` ASSUME_TAC THENL
+   [X_GEN_TAC `n:num` THEN EXPAND_TAC "X" THEN
+    MATCH_MP_TAC CONNECTED_CLOSURE THEN
+    MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN
+    EXPAND_TAC "A" THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP(REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN
+      SIMP_TAC[SUBSET; COMPLEX_IN_BALL_0; IN_ELIM_THM];
+      ONCE_REWRITE_TAC[NORM_ARITH `norm z = norm(z - vec 0)`] THEN
+      SIMP_TAC[CONNECTED_ANNULUS; DIMINDEX_2; LE_REFL]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n. ((X:num->complex->bool) n) SUBSET closure s`
+  ASSUME_TAC THENL
+   [GEN_TAC THEN EXPAND_TAC "X" THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC SUBSET_CLOSURE THEN EXPAND_TAC "s" THEN
+    MATCH_MP_TAC IMAGE_SUBSET THEN  EXPAND_TAC "A" THEN
+    SIMP_TAC[SUBSET; COMPLEX_IN_BALL_0; IN_ELIM_THM];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!m n. m <= n ==> (X:num->complex->bool) n SUBSET X m`
+  ASSUME_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN STRIP_TAC THEN
+    EXPAND_TAC "X" THEN MATCH_MP_TAC SUBSET_CLOSURE THEN
+    MATCH_MP_TAC IMAGE_SUBSET THEN EXPAND_TAC "A" THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN GEN_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `n <= m ==> &1 - n < x /\ x < &1 ==> &1 - m < x /\ x < &1`) THEN
+    MATCH_MP_TAC REAL_LE_INV2 THEN
+    ASM_REWRITE_TAC[REAL_LE_RADD; REAL_OF_NUM_LE] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  COND_CASES_TAC THENL
+   [MATCH_MP_TAC CONNECTED_NEST THEN
+    ASM_REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN
+    ASM_MESON_TAC[BOUNDED_SUBSET; BOUNDED_CLOSURE];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!n. ~(bounded((X:num->complex->bool) n))` ASSUME_TAC THENL
+   [X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+    UNDISCH_TAC `~bounded(s:complex->bool)` THEN EXPAND_TAC "s" THEN
+    REWRITE_TAC[] THEN MATCH_MP_TAC BOUNDED_SUBSET THEN EXISTS_TAC
+      `IMAGE (f:complex->complex)
+             (cball(Cx(&0),&1 - inv(&n + &2)) UNION A n)` THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[IMAGE_UNION; BOUNDED_UNION] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC COMPACT_IMP_BOUNDED THEN
+        MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN SIMP_TAC[COMPACT_CBALL] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP(REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN
+        SIMP_TAC[SUBSET; COMPLEX_IN_CBALL_0; COMPLEX_IN_BALL_0] THEN
+        GEN_TAC THEN MATCH_MP_TAC(REAL_ARITH
+         `&0 < e ==> x <= &1 - e ==> x < &1`) THEN
+        ASM_REWRITE_TAC[REAL_LT_INV_EQ] THEN REAL_ARITH_TAC;
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP(REWRITE_RULE[IMP_CONJ]
+              BOUNDED_SUBSET)) THEN EXPAND_TAC "X" THEN
+        REWRITE_TAC[CLOSURE_SUBSET]];
+      MATCH_MP_TAC IMAGE_SUBSET THEN EXPAND_TAC "A" THEN
+      REWRITE_TAC[SUBSET; IN_UNION; COMPLEX_IN_BALL_0; COMPLEX_IN_CBALL_0;
+                  IN_ELIM_THM] THEN REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  X_GEN_TAC `c:complex->bool` THEN REPEAT DISCH_TAC THEN
+  SUBGOAL_THEN `closed(INTERS {X n:complex->bool | n IN (:num)})`
+  ASSUME_TAC THENL
+   [ASM_SIMP_TAC[CLOSED_INTERS; FORALL_IN_GSPEC]; ALL_TAC] THEN
+  SUBGOAL_THEN `closed(c:complex->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[CLOSED_COMPONENTS]; ALL_TAC] THEN
+  SUBGOAL_THEN `compact(c:complex->bool)` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?k:complex->bool.
+        c SUBSET k /\ compact k /\
+        k SUBSET INTERS {X n | n IN (:num)} /\
+        closed(INTERS {X n | n IN (:num)} DIFF k)`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPECL[`INTERS {X n:complex->bool | n IN (:num)}`;`c:complex->bool`]
+        SURA_BURA_CLOSED) THEN
+    ASM_REWRITE_TAC[OPEN_IN_CLOSED_IN_EQ; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN
+    MATCH_MP_TAC(MESON[]
+     `~(c = i {}) /\ (~(f = {}) ==> P)
+      ==> c = i f ==> P`) THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[INTERS_0] THEN ASM_MESON_TAC[NOT_BOUNDED_UNIV];
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN MATCH_MP_TAC MONO_EXISTS THEN
+      X_GEN_TAC `k:complex->bool` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+      ASM_MESON_TAC[CLOSED_IN_CLOSED_TRANS]];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`k:complex->bool`;
+                 `INTERS {X n:complex->bool | n IN (:num)} DIFF k`]
+        SEPARATION_NORMAL_COMPACT) THEN
+  ASM_SIMP_TAC[NOT_EXISTS_THM; SET_RULE `k INTER (s DIFF k) = {}`] THEN
+  MAP_EVERY X_GEN_TAC [`v:complex->bool`; `v':complex->bool`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `v INTER (INTERS {X n:complex->bool | n IN (:num)} DIFF k) = {}`
+  ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`closure(v) DIFF v:complex->bool`;
+    `{X n INTER closure(v:complex->bool) | n IN (:num)}`]
+   COMPACT_IMP_FIP) THEN
+  ASM_SIMP_TAC[COMPACT_DIFF; FORALL_IN_GSPEC; CLOSED_INTER; CLOSED_CLOSURE;
+               NOT_IMP] THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    SUBGOAL_THEN
+     `INTERS {X n INTER closure v :complex->bool | n IN (:num)} =
+      INTERS {X n | n IN (:num)} INTER closure v`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[INTERS_GSPEC; EXTENSION; IN_ELIM_THM; IN_INTER; IN_UNIV] THEN
+      MESON_TAC[];
+      MP_TAC(ISPECL [`v':complex->bool`; `v:complex->bool`]
+        OPEN_INTER_CLOSURE_EQ_EMPTY) THEN
+      ASM_REWRITE_TAC[] THEN ASM SET_TAC[]]] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+  REWRITE_TAC[FINITE_SUBSET_IMAGE; SUBSET_UNIV; LEFT_IMP_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_UNWIND_THM2] THEN
+  X_GEN_TAC `i:num->bool` THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `\n:num. n` o MATCH_MP UPPER_BOUND_FINITE_SET) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `i:num->bool = {}` THENL
+   [ASM_REWRITE_TAC[IMAGE_CLAUSES; INTERS_0; INTER_UNIV] THEN
+    MP_TAC(ISPEC `v:complex->bool` FRONTIER_EQ_EMPTY) THEN
+    ASM_SIMP_TAC[frontier; INTERIOR_OPEN] THEN DISCH_THEN SUBST1_TAC THEN
+    DISCH_THEN(DISJ_CASES_THEN SUBST_ALL_TAC) THENL
+     [FIRST_ASSUM(MP_TAC o MATCH_MP IN_COMPONENTS_NONEMPTY) THEN
+      ASM SET_TAC[];
+      ASM_MESON_TAC[CLOSURE_UNIV; COMPACT_IMP_BOUNDED; NOT_BOUNDED_UNIV]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `?n:num. n IN i /\ !m. m IN i ==> m <= n`
+   (X_CHOOSE_TAC `p:num`) THENL
+   [MAP_EVERY UNDISCH_TAC [`~(i:num->bool = {})`; `FINITE(i:num->bool)`] THEN
+    POP_ASSUM_LIST(K ALL_TAC) THEN SPEC_TAC(`i:num->bool`,`i:num->bool`) THEN
+    MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+    REWRITE_TAC[EXISTS_IN_INSERT; FORALL_IN_INSERT; NOT_INSERT_EMPTY] THEN
+    MAP_EVERY X_GEN_TAC [`n:num`; `i:num->bool`] THEN
+    ASM_CASES_TAC `i:num->bool = {}` THEN
+    ASM_REWRITE_TAC[LE_REFL; NOT_IN_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_THEN `p:num` STRIP_ASSUME_TAC o CONJUNCT1) THEN
+    DISJ_CASES_TAC(ARITH_RULE `n:num <= p \/ p <= n`) THEN
+    ASM_MESON_TAC[LE_TRANS];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `INTERS (IMAGE (\n:num. X n INTER closure v) i):complex->bool =
+    X p INTER closure v`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; INTERS_IMAGE; IN_ELIM_THM; IN_INTER] THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(ASSUME_TAC o MATCH_MP (SET_RULE
+    `(c DIFF v) INTER (x INTER c) = {} ==> x INTER c SUBSET v`)) THEN
+  SUBGOAL_THEN `connected((X:num->complex->bool) p)` MP_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[CONNECTED_CLOPEN] THEN
+  DISCH_THEN(MP_TAC o SPEC `(X:num->complex->bool) p INTER closure v`) THEN
+  REWRITE_TAC[NOT_IMP; DE_MORGAN_THM] THEN REPEAT CONJ_TAC THENL
+   [SUBGOAL_THEN `(X:num->complex->bool) p INTER closure v = X p INTER v`
+    SUBST1_TAC THENL
+     [MP_TAC(ISPEC `v:complex->bool` CLOSURE_SUBSET) THEN ASM SET_TAC[];
+      MATCH_MP_TAC OPEN_IN_OPEN_INTER THEN ASM_REWRITE_TAC[]];
+    MATCH_MP_TAC CLOSED_IN_CLOSED_INTER THEN REWRITE_TAC[CLOSED_CLOSURE];
+    MATCH_MP_TAC(SET_RULE `!k. k SUBSET s /\ ~(k = {}) ==> ~(s = {})`) THEN
+    EXISTS_TAC `k:complex->bool` THEN CONJ_TAC THENL
+     [MP_TAC(ISPEC `v:complex->bool` CLOSURE_SUBSET) THEN ASM SET_TAC[];
+      FIRST_ASSUM(MP_TAC o MATCH_MP IN_COMPONENTS_NONEMPTY) THEN
+      ASM SET_TAC[]];
+    DISCH_THEN(MP_TAC o AP_TERM `bounded:(complex->bool)->bool`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC BOUNDED_SUBSET THEN
+    EXISTS_TAC `closure v:complex->bool` THEN
+    ASM_SIMP_TAC[COMPACT_IMP_BOUNDED] THEN SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Yet another set of equivalences based on *continuous* logs and sqrts.     *)
+(* ------------------------------------------------------------------------- *)
+
+let SIMPLY_CONNECTED_EQ_CONTINUOUS_LOG,SIMPLY_CONNECTED_EQ_CONTINUOUS_SQRT =
+  (CONJ_PAIR o prove)
+ (`(!s. open s
+        ==> (simply_connected s <=>
+             connected s /\
+             !f. f continuous_on s /\ (!z:complex. z IN s ==> ~(f z = Cx(&0)))
+                 ==> ?g. g continuous_on s /\
+                         !z. z IN s ==> f z = cexp(g z))) /\
+   (!s. open s
+        ==> (simply_connected s <=>
+             connected s /\
+             !f. f continuous_on s /\ (!z:complex. z IN s ==> ~(f z = Cx(&0)))
+                 ==> ?g. g continuous_on s /\
+                         !z. z IN s ==> f z = g z pow 2))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN X_GEN_TAC `s:complex->bool` THEN
+  ASM_CASES_TAC `open(s:complex->bool)` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `connected(s:complex->bool)` THEN ASM_REWRITE_TAC[] THENL
+   [ALL_TAC; ASM_MESON_TAC[SIMPLY_CONNECTED_IMP_CONNECTED]] THEN
+  MATCH_MP_TAC(TAUT
+   `(p ==> q) /\ (q ==> r) /\ (r ==> p) ==> (p <=> q) /\ (p <=> r)`) THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_SIMP_TAC[SIMPLY_CONNECTED_EQ_HOMEOMORPHIC_TO_DISC] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[CONTINUOUS_ON_EMPTY; NOT_IN_EMPTY] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homeomorphic]) THEN
+    REWRITE_TAC[homeomorphism; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`k:complex->complex`; `h:complex->complex`] THEN
+    STRIP_TAC THEN X_GEN_TAC `f:complex->complex` THEN STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`(f:complex->complex) o (h:complex->complex)`; `Cx(&0)`; `&1`]
+        CONTINUOUS_LOGARITHM_ON_BALL) THEN
+    ASM_REWRITE_TAC[o_THM] THEN ANTS_TAC THENL
+     [CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+      DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `(g:complex->complex) o (k:complex->complex)` THEN
+      REWRITE_TAC[o_THM] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]];
+    DISCH_TAC THEN X_GEN_TAC `f:complex->complex` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `f:complex->complex`) THEN ASM_SIMP_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\z:complex. cexp(g z / Cx(&2))` THEN
+    ASM_SIMP_TAC[GSYM CEXP_N; COMPLEX_RING `Cx(&2) * z / Cx(&2) = z`] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    REWRITE_TAC[CONTINUOUS_ON_CEXP] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_DIV THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_CONST] THEN
+    CONV_TAC COMPLEX_RING;
+    DISCH_TAC THEN ASM_SIMP_TAC[SIMPLY_CONNECTED_EQ_HOLOMORPHIC_SQRT] THEN
+    X_GEN_TAC `f:complex->complex` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `f:complex->complex`) THEN
+    ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:complex->complex` THEN
+    STRIP_TAC THEN ASM_SIMP_TAC[HOLOMORPHIC_ON_OPEN] THEN
+    X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `~((g:complex->complex) z = Cx(&0))` ASSUME_TAC THENL
+     [ASM_MESON_TAC[COMPLEX_RING `Cx(&0) pow 2 = Cx(&0)`]; ALL_TAC] THEN
+    EXISTS_TAC `complex_derivative f z / (Cx(&2) * g z)` THEN
+    REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_AT] THEN
+    MATCH_MP_TAC LIM_TRANSFORM_WITHIN_OPEN THEN
+    EXISTS_TAC `\x:complex. (f(x) - f(z)) / (x - z) / (g(x) + g(z))` THEN
+    SUBGOAL_THEN
+      `?d. &0 < d /\
+           !w:complex. w IN s /\ w IN ball(z,d) ==> ~(g w + g z = Cx(&0))`
+    STRIP_ASSUME_TAC THENL
+     [FIRST_ASSUM(MP_TAC o SPEC `z:complex` o
+      GEN_REWRITE_RULE I [continuous_on]) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(MP_TAC o SPEC `norm((g:complex->complex) z)`) THEN
+      ASM_REWRITE_TAC[COMPLEX_NORM_NZ] THEN MATCH_MP_TAC MONO_EXISTS THEN
+      ONCE_REWRITE_TAC[DIST_SYM] THEN
+      REWRITE_TAC[IN_BALL; GSYM COMPLEX_VEC_0] THEN
+      MESON_TAC[NORM_ARITH `dist(z,x) < norm z ==> ~(x + z = vec 0)`];
+      ALL_TAC] THEN
+    EXISTS_TAC `ball(z:complex,d) INTER s` THEN
+    ASM_REWRITE_TAC[IN_INTER; CENTRE_IN_BALL] THEN REPEAT CONJ_TAC THENL
+     [ASM_SIMP_TAC[OPEN_INTER; OPEN_BALL];
+      ASM_SIMP_TAC[] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC(COMPLEX_FIELD
+       `~(x = z) /\ ~(gx + gz = Cx(&0))
+        ==> (gx pow 2 - gz pow 2) / (x - z) / (gx + gz) =
+             (gx - gz) / (x - z)`) THEN
+      ASM_SIMP_TAC[];
+      MATCH_MP_TAC LIM_COMPLEX_DIV THEN
+      ASM_REWRITE_TAC[COMPLEX_ENTIRE; GSYM HAS_COMPLEX_DERIVATIVE_AT] THEN
+      REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE; CX_INJ] THEN
+      REWRITE_TAC[COMPLEX_MUL_2; REAL_OF_NUM_EQ; ARITH_EQ] THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT]; ALL_TAC] THEN
+      MATCH_MP_TAC LIM_ADD THEN REWRITE_TAC[LIM_CONST; GSYM CONTINUOUS_AT] THEN
+      ASM_MESON_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON;
+                    CONTINUOUS_ON_INTERIOR; INTERIOR_OPEN]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A per-function version for continuous logs, a kind of monodromy.          *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_COMPOSE_CEXP = prove
+ (`!p. path p
+       ==> winding_number(cexp o p,Cx(&0)) =
+           Cx(&1) / (Cx(&2) * Cx pi * ii) * (pathfinish p - pathstart p)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?e. &0 < e /\
+       !t:real^1. t IN interval[vec 0,vec 1] ==> e <= norm(cexp(p t))`
+  STRIP_ASSUME_TAC THENL
+   [EXISTS_TAC `setdist({Cx(&0)},path_image (cexp o p))` THEN
+    REWRITE_TAC[SETDIST_POS_LE; REAL_ARITH
+     `&0 < x <=> &0 <= x /\ ~(x = &0)`] THEN
+    ASM_SIMP_TAC[PATH_CONTINUOUS_IMAGE; CONTINUOUS_ON_CEXP; CLOSED_SING;
+     SETDIST_EQ_0_CLOSED_COMPACT; COMPACT_PATH_IMAGE; PATH_IMAGE_NONEMPTY] THEN
+    REWRITE_TAC[NOT_INSERT_EMPTY; path_image; IMAGE_o] THEN CONJ_TAC THENL
+     [MP_TAC CEXP_NZ THEN SET_TAC[]; REPEAT STRIP_TAC] THEN
+    ONCE_REWRITE_TAC[GSYM NORM_NEG] THEN
+    REWRITE_TAC[COMPLEX_RING `--x = Cx(&0) - x`] THEN
+    REWRITE_TAC[GSYM dist] THEN MATCH_MP_TAC SETDIST_LE_DIST THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`path_image(p:real^1->complex)`; `Cx(&0)`]
+        BOUNDED_SUBSET_CBALL) THEN
+  ASM_SIMP_TAC[BOUNDED_PATH_IMAGE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `B:real` THEN REWRITE_TAC[SUBSET; COMPLEX_IN_CBALL_0] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`cexp`; `cball(Cx(&0),B + &1)`]
+        COMPACT_UNIFORMLY_CONTINUOUS) THEN
+  REWRITE_TAC[CONTINUOUS_ON_CEXP; COMPACT_CBALL] THEN
+  REWRITE_TAC[uniformly_continuous_on] THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN
+  ASM_REWRITE_TAC[COMPLEX_IN_CBALL_0] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`p:real^1->complex`; `min (&1) d`]
+      PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION) THEN
+  ASM_REWRITE_TAC[REAL_LT_MIN; REAL_LT_01; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `g:real^1->complex` THEN STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `winding_number(cexp o g,Cx(&0))` THEN CONJ_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC WINDING_NUMBER_NEARBY_PATHS_EQ THEN
+    ASM_SIMP_TAC[PATH_CONTINUOUS_IMAGE; CONTINUOUS_ON_CEXP;
+                 PATH_VECTOR_POLYNOMIAL_FUNCTION] THEN
+    ASM_REWRITE_TAC[PATHSTART_COMPOSE; PATHFINISH_COMPOSE] THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[COMPLEX_SUB_RZERO; o_THM] THEN
+    REWRITE_TAC[GSYM dist] THEN MATCH_MP_TAC REAL_LTE_TRANS THEN
+    EXISTS_TAC `e:real` THEN ASM_SIMP_TAC[] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[dist] THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `norm(g - p) < &1 /\ norm(p) <= B
+      ==> norm(p) <= B + &1 /\ norm(g) <= B + &1`) THEN
+    ASM_SIMP_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[path_image] THEN ASM SET_TAC[];
+    W(MP_TAC o
+      PART_MATCH (lhs o rand) WINDING_NUMBER_VALID_PATH o lhs o snd) THEN
+    REWRITE_TAC[PATH_INTEGRAL_INTEGRAL; COMPLEX_SUB_RZERO] THEN ANTS_TAC THENL
+     [REWRITE_TAC[path_image; IN_IMAGE; o_THM; CEXP_NZ] THEN
+      REWRITE_TAC[valid_path] THEN
+      MATCH_MP_TAC DIFFERENTIABLE_ON_IMP_PIECEWISE_DIFFERENTIABLE THEN
+      MATCH_MP_TAC DIFFERENTIABLE_ON_COMPOSE THEN
+      REWRITE_TAC[differentiable_on] THEN REPEAT STRIP_TAC THENL
+       [MATCH_MP_TAC DIFFERENTIABLE_AT_WITHIN THEN
+        REWRITE_TAC[differentiable] THEN
+        ASM_MESON_TAC[has_vector_derivative;
+                        HAS_VECTOR_DERIVATIVE_VECTOR_POLYNOMIAL_FUNCTION];
+        GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN
+        MATCH_MP_TAC COMPLEX_DIFFERENTIABLE_IMP_DIFFERENTIABLE THEN
+        COMPLEX_DIFFERENTIABLE_TAC];
+      DISCH_THEN SUBST1_TAC THEN AP_TERM_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+      EXISTS_TAC `integral (interval [vec 0,vec 1])
+                    (\x. vector_derivative (g:real^1->complex) (at x))` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC INTEGRAL_EQ THEN X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+        REWRITE_TAC[o_THM] THEN MATCH_MP_TAC(COMPLEX_FIELD
+         `~(e = Cx(&0)) /\ v' = e * v ==> Cx(&1) / e * v' = v`) THEN
+        REWRITE_TAC[CEXP_NZ] THEN
+        MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_UNIQUE_AT THEN
+        MP_TAC(ISPECL [`g:real^1->complex`; `cexp`;
+         `\h. drop h % vector_derivative (g:real^1->complex) (at t)`;
+         `\w. cexp(g(t:real^1)) * w`; `t:real^1`]
+        DIFF_CHAIN_AT) THEN
+        REWRITE_TAC[GSYM has_vector_derivative; GSYM has_complex_derivative;
+                    GSYM VECTOR_DERIVATIVE_WORKS;
+                    HAS_COMPLEX_DERIVATIVE_CEXP; differentiable] THEN
+        ANTS_TAC THENL
+         [ASM_MESON_TAC[HAS_VECTOR_DERIVATIVE_VECTOR_POLYNOMIAL_FUNCTION;
+                        has_vector_derivative];
+          REWRITE_TAC[has_vector_derivative; o_DEF] THEN
+          MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+          REWRITE_TAC[FUN_EQ_THM; COMPLEX_CMUL] THEN
+          CONV_TAC COMPLEX_RING];
+        MP_TAC(ISPECL [`g:real^1->complex`;
+                        `\x. vector_derivative (g:real^1->complex) (at x)`;
+                       `vec 0:real^1`; `vec 1:real^1`]
+          FUNDAMENTAL_THEOREM_OF_CALCULUS) THEN
+        ASM_REWRITE_TAC[DROP_VEC; REAL_POS] THEN ANTS_TAC THENL
+         [REPEAT STRIP_TAC THEN
+          MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_AT_WITHIN THEN
+          REWRITE_TAC[GSYM VECTOR_DERIVATIVE_WORKS] THEN
+          REWRITE_TAC[differentiable] THEN
+          ASM_MESON_TAC[has_vector_derivative;
+                        HAS_VECTOR_DERIVATIVE_VECTOR_POLYNOMIAL_FUNCTION];
+          DISCH_THEN(SUBST1_TAC o MATCH_MP INTEGRAL_UNIQUE) THEN
+          RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+          ASM_REWRITE_TAC[pathstart; pathfinish]]]]]);;
+
+let MONODROMY_CONTINUOUS_LOG = prove
+ (`!f:complex->complex s.
+        open s /\ f continuous_on s /\
+        (!z. z IN s ==> ~(f z = Cx(&0)))
+        ==> ((!p. path p /\ path_image p SUBSET s /\
+                  pathfinish p = pathstart p
+                  ==> winding_number(f o p,Cx(&0)) = Cx(&0)) <=>
+             (?g. g continuous_on s /\ !z. z IN s ==> f(z) = cexp(g z)))`,
+  let lemma = prove
+   (`!f g s p.
+           f continuous_on s /\ g continuous_on s /\
+           (!z:complex. z IN s ==> f(z) = cexp(g z)) /\
+           path p /\ path_image p SUBSET s
+           ==> winding_number(f o p,Cx(&0)) =
+               Cx(&1) / (Cx(&2) * Cx pi * ii) *
+               (pathfinish(g o p) - pathstart(g o p))`,
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `winding_number(cexp o g o (p:real^1->complex),Cx(&0))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC WINDING_NUMBER_NEARBY_PATHS_EQ THEN
+      REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC PATH_CONTINUOUS_IMAGE THEN
+        REWRITE_TAC[CONTINUOUS_ON_CEXP] THEN
+        MATCH_MP_TAC PATH_CONTINUOUS_IMAGE THEN
+        ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+        MATCH_MP_TAC PATH_CONTINUOUS_IMAGE THEN
+        ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+        REWRITE_TAC[PATHSTART_COMPOSE] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+        ASM_MESON_TAC[SUBSET; PATHSTART_IN_PATH_IMAGE];
+        REWRITE_TAC[PATHFINISH_COMPOSE] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+        ASM_MESON_TAC[SUBSET; PATHFINISH_IN_PATH_IMAGE];
+        GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[o_THM; COMPLEX_SUB_RZERO] THEN
+        MATCH_MP_TAC(NORM_ARITH
+         `x = y /\ ~(z = vec 0) ==> norm(x - y) < norm z`) THEN
+        REWRITE_TAC[COMPLEX_VEC_0; CEXP_NZ] THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN
+        ASM_MESON_TAC[SUBSET; path_image; IN_IMAGE]];
+      MATCH_MP_TAC WINDING_NUMBER_COMPOSE_CEXP THEN
+      ASM_REWRITE_TAC[PATHSTART_COMPOSE; PATHFINISH_COMPOSE] THEN
+      MATCH_MP_TAC PATH_CONTINUOUS_IMAGE THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]]) in
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ALL_TAC;
+    DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC) THEN
+    X_GEN_TAC `p:real^1->complex` THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`f:complex->complex`; `g:complex->complex`;
+                   `s:complex->bool`; `p:real^1->complex`]
+        lemma) THEN
+    ASM_REWRITE_TAC[PATHSTART_COMPOSE; PATHFINISH_COMPOSE] THEN
+    REWRITE_TAC[COMPLEX_SUB_REFL; COMPLEX_MUL_RZERO]] THEN
+  DISCH_TAC THEN
+  EXISTS_TAC `\z. let c = connected_component s (z:complex) in
+                  let z0 = (@) c in
+                  let p = @p. path p /\ path_image p SUBSET c /\
+                              pathstart p = z0 /\ pathfinish p = z in
+                  Cx(&2) * Cx(pi) * ii * winding_number(f o p,Cx(&0)) +
+                  clog(f z0)` THEN
+
+  CONJ_TAC THENL
+   [ALL_TAC;
+    X_GEN_TAC `z:complex` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+    REPEAT LET_TAC THEN
+    SUBGOAL_THEN `(z:complex) IN c` ASSUME_TAC THENL
+     [ASM_MESON_TAC[CONNECTED_COMPONENT_REFL; IN]; ALL_TAC] THEN
+    SUBGOAL_THEN `(z0:complex) IN c` ASSUME_TAC THENL
+     [EXPAND_TAC "z0" THEN REWRITE_TAC[IN] THEN MATCH_MP_TAC SELECT_AX THEN
+      ASM_MESON_TAC[IN];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `(c:complex->bool) SUBSET s` ASSUME_TAC THENL
+     [ASM_MESON_TAC[CONNECTED_COMPONENT_SUBSET]; ALL_TAC] THEN
+    SUBGOAL_THEN `connected(c:complex->bool)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[CONNECTED_CONNECTED_COMPONENT]; ALL_TAC] THEN
+    SUBGOAL_THEN `open(c:complex->bool)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[OPEN_CONNECTED_COMPONENT]; ALL_TAC] THEN
+    SUBGOAL_THEN `path_connected(c:complex->bool)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[CONNECTED_OPEN_PATH_CONNECTED]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `path p /\ path_image p SUBSET c /\
+      pathstart p = z0 /\ pathfinish p = (z:complex)`
+    STRIP_ASSUME_TAC THENL
+     [EXPAND_TAC "p" THEN CONV_TAC SELECT_CONV THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o REWRITE_RULE[path_connected]) THEN
+      ASM_REWRITE_TAC[];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`(f:complex->complex) o (p:real^1->complex)`; `Cx(&0)`]
+      WINDING_NUMBER_AHLFORS_FULL) THEN
+    REWRITE_TAC[CEXP_ADD] THEN ANTS_TAC THENL
+     [CONJ_TAC THENL
+       [MATCH_MP_TAC PATH_CONTINUOUS_IMAGE THEN
+        ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+        REWRITE_TAC[path_image; IMAGE_o] THEN
+        REWRITE_TAC[GSYM path_image] THEN ASM SET_TAC[]];
+      ASM_REWRITE_TAC[PATHSTART_COMPOSE; PATHFINISH_COMPOSE] THEN
+      REWRITE_TAC[COMPLEX_SUB_RZERO] THEN DISCH_THEN SUBST1_TAC THEN
+      AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC CEXP_CLOG THEN
+      ASM SET_TAC[]]] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPONENTS THEN
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `c:complex->bool` THEN DISCH_TAC THEN
+  ABBREV_TAC `z0:complex = (@) c` THEN
+  MATCH_MP_TAC CONTINUOUS_ON_EQ THEN
+  ABBREV_TAC
+   `g = \z. let p = @p. path p /\ path_image p SUBSET c /\
+                        pathstart p = z0 /\ pathfinish p = z in
+            Cx(&2) * Cx(pi) * ii * winding_number(f o p,Cx(&0)) +
+            clog(f(z0:complex))` THEN
+  EXISTS_TAC `g:complex->complex` THEN REWRITE_TAC[] THEN CONJ_TAC THENL
+   [X_GEN_TAC `z:complex` THEN DISCH_TAC THEN EXPAND_TAC "g" THEN
+    CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN EXPAND_TAC "z0" THEN
+    SUBGOAL_THEN `connected_component s (z:complex) = c`
+     (fun th -> REWRITE_TAC[th]) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_COMPONENTS]) THEN
+    ASM_MESON_TAC[CONNECTED_COMPONENT_EQ];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(z0:complex) IN c` ASSUME_TAC THENL
+   [EXPAND_TAC "z0" THEN REWRITE_TAC[IN] THEN MATCH_MP_TAC SELECT_AX THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP IN_COMPONENTS_NONEMPTY) THEN SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(c:complex->bool) SUBSET s` ASSUME_TAC THENL
+   [ASM_MESON_TAC[IN_COMPONENTS_SUBSET]; ALL_TAC] THEN
+  SUBGOAL_THEN `connected(c:complex->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[IN_COMPONENTS_CONNECTED]; ALL_TAC] THEN
+  SUBGOAL_THEN `open(c:complex->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[OPEN_COMPONENTS]; ALL_TAC] THEN
+  SUBGOAL_THEN `path_connected(c:complex->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[CONNECTED_OPEN_PATH_CONNECTED]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x. x IN c
+        ==> ?p. path (p:real^1->complex) /\ path_image p SUBSET c /\
+                pathstart p = z0 /\ pathfinish p = x /\
+                g(x) = Cx(&2) * Cx pi * ii * winding_number(f o p,Cx(&0)) +
+                       clog (f z0)`
+   (LABEL_TAC "*")
+  THENL
+   [X_GEN_TAC `z:complex` THEN DISCH_TAC THEN EXPAND_TAC "g" THEN
+    ABBREV_TAC `p = @p. path p /\ path_image p SUBSET c /\
+                        pathstart p = z0 /\ pathfinish p = (z:complex)` THEN
+    EXISTS_TAC `p:real^1->complex` THEN
+    CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN REWRITE_TAC[] THEN
+    EXPAND_TAC "p" THEN CONV_TAC SELECT_CONV THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [path_connected]) THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `z:complex` o GEN_REWRITE_RULE I
+   [OPEN_CONTAINS_BALL]) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `e:real` THEN
+  STRIP_TAC THEN
+  MP_TAC(SPEC `ball(z:complex,e)` SIMPLY_CONNECTED_EQ_CONTINUOUS_LOG) THEN
+  SIMP_TAC[OPEN_BALL; CONVEX_BALL; CONVEX_IMP_SIMPLY_CONNECTED] THEN
+  DISCH_THEN(MP_TAC o SPEC `f:complex->complex` o CONJUNCT2) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET];
+    DISCH_THEN(X_CHOOSE_THEN `l:complex->complex` STRIP_ASSUME_TAC)] THEN
+  REWRITE_TAC[CONTINUOUS_AT] THEN ONCE_REWRITE_TAC[LIM_NULL] THEN
+  MATCH_MP_TAC LIM_TRANSFORM_AT THEN
+  ONCE_REWRITE_TAC[DIST_SYM] THEN EXISTS_TAC
+   `\w. Cx (&2) * Cx pi * ii *
+        winding_number((f:complex->complex) o linepath(z,w),Cx(&0))` THEN
+  EXISTS_TAC `e:real` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [X_GEN_TAC `w:complex` THEN STRIP_TAC THEN REMOVE_THEN "*"
+     (fun th -> MP_TAC(SPEC `w:complex` th) THEN
+                MP_TAC(SPEC `z:complex` th)) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `p:real^1->complex` THEN STRIP_TAC THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[SUBSET; IN_BALL; DIST_SYM]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `q:real^1->complex` STRIP_ASSUME_TAC) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(COMPLEX_RING
+     `(z + x) - y = Cx(&0)
+      ==> a * b * c * x = (a * b * c * y + l) - (a * b * c * z + l)`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC
+     `p ++ linepath(z:complex,w) ++ reversepath q`) THEN
+    ASM_SIMP_TAC[PATHSTART_JOIN; PATHFINISH_JOIN;
+                 PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+                 PATH_JOIN_EQ; PATH_LINEPATH; PATH_REVERSEPATH;
+                 PATHSTART_LINEPATH; PATHFINISH_LINEPATH; PATH_IMAGE_JOIN] THEN
+    ASM_REWRITE_TAC[UNION_SUBSET; PATH_IMAGE_REVERSEPATH] THEN ANTS_TAC THENL
+     [REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `c:complex->bool` THEN
+      ASM_REWRITE_TAC[PATH_IMAGE_LINEPATH] THEN
+      MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `ball(z:complex,e)` THEN
+      ASM_REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+      ASM_REWRITE_TAC[INSERT_SUBSET; CENTRE_IN_BALL; EMPTY_SUBSET] THEN
+      ASM_REWRITE_TAC[IN_BALL; CONVEX_BALL];
+      DISCH_THEN(fun th -> GEN_REWRITE_TAC RAND_CONV [GSYM th]) THEN
+      REWRITE_TAC[PATH_COMPOSE_JOIN; PATH_COMPOSE_REVERSEPATH] THEN
+      W(MP_TAC o PART_MATCH (lhand o rand) WINDING_NUMBER_JOIN o
+        rand o snd) THEN
+      ANTS_TAC THENL
+       [ALL_TAC;
+        DISCH_THEN SUBST1_TAC THEN
+        REWRITE_TAC[VECTOR_SUB; GSYM VECTOR_ADD_ASSOC] THEN
+        AP_TERM_TAC THEN
+        W(MP_TAC o PART_MATCH (lhand o rand) WINDING_NUMBER_JOIN o
+          rand o snd) THEN
+        ANTS_TAC THENL
+         [ALL_TAC;
+          DISCH_THEN SUBST1_TAC THEN AP_TERM_TAC THEN
+          MATCH_MP_TAC(GSYM WINDING_NUMBER_REVERSEPATH)]] THEN
+      ASM_SIMP_TAC[PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+                 PATHSTART_COMPOSE; PATHFINISH_COMPOSE; PATH_IMAGE_REVERSEPATH;
+                 PATHSTART_JOIN; PATHFINISH_JOIN; PATH_REVERSEPATH;
+                 PATHSTART_LINEPATH; PATHFINISH_LINEPATH; PATH_JOIN;
+                 PATH_IMAGE_JOIN; IN_UNION; DE_MORGAN_THM] THEN
+      REWRITE_TAC[PATH_IMAGE_COMPOSE; SET_RULE
+       `~(z IN IMAGE f s) <=> !x. x IN s ==> ~(f x = z)`] THEN
+      REPEAT CONJ_TAC THEN
+      ((MATCH_MP_TAC PATH_CONTINUOUS_IMAGE)
+       ORELSE
+       (X_GEN_TAC `x:complex` THEN DISCH_TAC THEN
+        FIRST_X_ASSUM MATCH_MP_TAC)) THEN
+      ASM_REWRITE_TAC[PATH_LINEPATH] THEN
+      TRY(FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN
+          REWRITE_TAC[SUBSET] THEN X_GEN_TAC `x:complex` THEN STRIP_TAC) THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+      TRY(FIRST_X_ASSUM(fun th ->
+            MATCH_MP_TAC(GEN_REWRITE_RULE I [SUBSET] th) THEN
+            FIRST_X_ASSUM ACCEPT_TAC)) THEN
+      UNDISCH_TAC `(x:complex) IN path_image(linepath(z,w))` THEN
+      SPEC_TAC(`x:complex`,`x:complex`) THEN
+      REWRITE_TAC[GSYM SUBSET; PATH_IMAGE_LINEPATH; SEGMENT_CONVEX_HULL] THEN
+      MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `ball(z:complex,e)` THEN
+      ASM_REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+      ASM_REWRITE_TAC[INSERT_SUBSET; CENTRE_IN_BALL; EMPTY_SUBSET] THEN
+      ASM_REWRITE_TAC[IN_BALL; CONVEX_BALL]];
+    MATCH_MP_TAC LIM_TRANSFORM THEN
+    EXISTS_TAC `\w. Cx(&2) * Cx pi * ii *
+                    Cx(&1) / (Cx(&2) * Cx pi * ii) *
+                    (pathfinish(l o linepath(z:complex,w)) -
+                     pathstart (l o linepath(z,w)))` THEN
+    REWRITE_TAC[] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC LIM_EVENTUALLY THEN REWRITE_TAC[EVENTUALLY_AT] THEN
+      EXISTS_TAC `e:real` THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+      ASM_REWRITE_TAC[] THEN X_GEN_TAC `w:complex` THEN STRIP_TAC THEN
+      REWRITE_TAC[VECTOR_ARITH `x - y = vec 0 <=> y = x`] THEN
+      REPLICATE_TAC 3 AP_TERM_TAC THEN MATCH_MP_TAC lemma THEN
+      EXISTS_TAC `ball(z:complex,e)` THEN ASM_REWRITE_TAC[PATH_LINEPATH] THEN
+      CONJ_TAC THENL[ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET]; ALL_TAC] THEN
+      REWRITE_TAC[PATH_IMAGE_LINEPATH; SEGMENT_CONVEX_HULL] THEN
+      MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_BALL] THEN
+      ASM_REWRITE_TAC[INSERT_SUBSET; CENTRE_IN_BALL; EMPTY_SUBSET] THEN
+      ASM_REWRITE_TAC[IN_BALL];
+      REWRITE_TAC[COMPLEX_VEC_0] THEN
+      REPEAT(MATCH_MP_TAC LIM_NULL_COMPLEX_LMUL) THEN
+      REWRITE_TAC[PATHSTART_COMPOSE; PATHSTART_LINEPATH;
+                  PATHFINISH_COMPOSE; PATHFINISH_LINEPATH] THEN
+      REWRITE_TAC[GSYM COMPLEX_VEC_0; GSYM LIM_NULL; GSYM CONTINUOUS_AT] THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; OPEN_BALL;
+                    CENTRE_IN_BALL]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The winding number defines a continuous logarithm for the path itself.    *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_AS_CONTINUOUS_LOGARITHM = prove
+ (`!p z.
+      path p /\ ~(z IN path_image p)
+      ==> ?q. path q /\
+              pathfinish q - pathstart q =
+              Cx(&2) * Cx pi * ii * winding_number(p,z) /\
+              !t. t IN interval[vec 0,vec 1] ==> p(t) = z + cexp(q t)`,
+  REPEAT STRIP_TAC THEN EXISTS_TAC
+  `\t:real^1. Cx(&2) * Cx pi * ii * winding_number(subpath (vec 0) t p,z) +
+              clog(pathstart p - z)` THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[path] THEN MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+    REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN
+           REWRITE_TAC[CONTINUOUS_ON_CONST]) THEN
+    REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+    X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `~((p:real^1->complex) t = z)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[path_image; IN_IMAGE]; ALL_TAC] THEN
+    MP_TAC(SPEC `ball((p:real^1->complex) t,norm(p t - z))`
+      SIMPLY_CONNECTED_EQ_CONTINUOUS_LOG) THEN
+    SIMP_TAC[OPEN_BALL; CONVEX_BALL; CONVEX_IMP_SIMPLY_CONNECTED] THEN
+    DISCH_THEN(MP_TAC o SPEC `\w:complex. w - z` o CONJUNCT2) THEN
+    SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST] THEN
+    REWRITE_TAC[COMPLEX_SUB_0] THEN ANTS_TAC THENL
+     [GEN_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+      SIMP_TAC[IN_BALL; dist; REAL_LT_REFL];
+      DISCH_THEN(X_CHOOSE_THEN `l:complex->complex` STRIP_ASSUME_TAC)] THEN
+    ONCE_REWRITE_TAC[WINDING_NUMBER_OFFSET] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [path]) THEN
+    GEN_REWRITE_TAC LAND_CONV [continuous_on] THEN
+    DISCH_THEN(MP_TAC o SPEC `t:real^1`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o SPEC `norm((p:real^1->complex) t - z)`) THEN
+    ASM_REWRITE_TAC[NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    ONCE_REWRITE_TAC[DIST_SYM] THEN REWRITE_TAC[GSYM IN_BALL] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    REWRITE_TAC[CONTINUOUS_WITHIN] THEN ONCE_REWRITE_TAC[LIM_NULL] THEN
+    MATCH_MP_TAC LIM_TRANSFORM_WITHIN THEN EXISTS_TAC
+     `\u. Cx(&1) / (Cx(&2) * Cx pi * ii) *
+          (pathfinish((l:complex->complex) o subpath t u p) -
+           pathstart(l o subpath t u p))` THEN
+    EXISTS_TAC `d:real` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [X_GEN_TAC `u:real^1` THEN STRIP_TAC THEN
+      SUBGOAL_THEN
+       `path_image(subpath t u p) SUBSET ball(p t:complex,norm (p t - z))`
+      ASSUME_TAC THENL
+       [REWRITE_TAC[PATH_IMAGE_SUBPATH_GEN] THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+        SUBGOAL_THEN
+         `segment[t,u] SUBSET interval[vec 0,vec 1] /\
+          segment[t,u] SUBSET ball(t:real^1,d)`
+        MP_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+        CONJ_TAC THEN REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+        MATCH_MP_TAC HULL_MINIMAL THEN
+        REWRITE_TAC[CONVEX_BALL; CONVEX_INTERVAL] THEN
+        ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; CENTRE_IN_BALL] THEN
+        ASM_REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] IN_BALL];
+        ALL_TAC] THEN
+      W(MP_TAC o PART_MATCH (rand o rand) WINDING_NUMBER_COMPOSE_CEXP o
+        lhand o snd) THEN
+      ANTS_TAC THENL
+       [MATCH_MP_TAC PATH_CONTINUOUS_IMAGE THEN ASM_SIMP_TAC[PATH_SUBPATH] THEN
+        ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+        DISCH_THEN(SUBST1_TAC o SYM)] THEN
+      MATCH_MP_TAC EQ_TRANS THEN
+      EXISTS_TAC `winding_number((\w. subpath t u p w - z),Cx(&0))` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC WINDING_NUMBER_EQUAL THEN
+        REWRITE_TAC[o_THM; GSYM path_image; SET_RULE
+         `(!x. x IN s ==> cexp(l(subpath t u p x)) = subpath t u p x - z) <=>
+          (!y. y IN IMAGE (subpath t u p) s ==> cexp(l y) = y - z)`] THEN
+        ASM SET_TAC[];
+        ONCE_REWRITE_TAC[GSYM WINDING_NUMBER_OFFSET] THEN
+        REWRITE_TAC[ETA_AX] THEN
+        MP_TAC(ISPECL [`p:real^1->complex`; `vec 0:real^1`; `t:real^1`;
+                       `u:real^1`; `z:complex`]
+          WINDING_NUMBER_SUBPATH_COMBINE) THEN
+        ASM_REWRITE_TAC[ENDS_IN_UNIT_INTERVAL] THEN
+        CONV_TAC COMPLEX_RING];
+      REWRITE_TAC[COMPLEX_VEC_0] THEN MATCH_MP_TAC LIM_NULL_COMPLEX_LMUL THEN
+      REWRITE_TAC[PATHSTART_COMPOSE; PATHSTART_SUBPATH;
+                  PATHFINISH_COMPOSE; PATHFINISH_SUBPATH] THEN
+      REWRITE_TAC[GSYM COMPLEX_VEC_0; GSYM LIM_NULL] THEN
+      REWRITE_TAC[GSYM CONTINUOUS_WITHIN] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_WITHIN_COMPOSE THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; path];
+        MATCH_MP_TAC CONTINUOUS_AT_WITHIN THEN
+        UNDISCH_TAC `(l:complex->complex) continuous_on
+                     ball(p(t:real^1),norm(p t - z))` THEN
+        SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; OPEN_BALL] THEN
+        DISCH_THEN MATCH_MP_TAC THEN REWRITE_TAC[CENTRE_IN_BALL] THEN
+        ASM_REWRITE_TAC[VECTOR_SUB_EQ; NORM_POS_LT]]];
+    REWRITE_TAC[pathstart; pathfinish; SUBPATH_REFL; SUBPATH_TRIVIAL] THEN
+    MATCH_MP_TAC(COMPLEX_FIELD
+     `w' = Cx(&0)
+      ==> (a * b * c * w + l) - (a * b * c * w' + l) = a * b * c * w`) THEN
+    MATCH_MP_TAC WINDING_NUMBER_TRIVIAL THEN
+    MP_TAC(ISPEC `p:real^1->complex` PATHSTART_IN_PATH_IMAGE) THEN
+    REWRITE_TAC[pathstart] THEN ASM_MESON_TAC[];
+    X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`subpath (vec 0) t (p:real^1->complex)`; `z:complex`]
+        WINDING_NUMBER_AHLFORS_FULL) THEN
+    REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+    ASM_SIMP_TAC[ENDS_IN_UNIT_INTERVAL; PATH_SUBPATH; CEXP_ADD;
+      REWRITE_RULE[SET_RULE `s SUBSET t <=> !x. ~(x IN t) ==> ~(x IN s)`]
+                  PATH_IMAGE_SUBPATH_SUBSET] THEN
+    MATCH_MP_TAC(COMPLEX_RING
+     `t:complex = s ==> p - z = e * s ==> p = z + e * t`) THEN
+    REWRITE_TAC[pathstart] THEN MATCH_MP_TAC CEXP_CLOG THEN
+    REWRITE_TAC[COMPLEX_SUB_0] THEN
+    ASM_MESON_TAC[pathstart; PATHSTART_IN_PATH_IMAGE]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Winding number equality is the same as path/loop homotopy in C - {0}.     *)
+(* ------------------------------------------------------------------------- *)
+
+let WINDING_NUMBER_HOMOTOPIC_LOOPS_NULL_EQ = prove
+ (`!p z. path p /\ ~(z IN path_image p)
+         ==> (winding_number(p,z) = Cx(&0) <=>
+              ?a. homotopic_loops ((:complex) DELETE z) p (\t. a))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN STRIP_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MP_TAC(SPECL [`p:real^1->complex`; `z:complex`]
+          WINDING_NUMBER_AS_CONTINUOUS_LOGARITHM) THEN
+    ASM_REWRITE_TAC[COMPLEX_MUL_RZERO; COMPLEX_ADD_LID; COMPLEX_SUB_0] THEN
+    DISCH_THEN(X_CHOOSE_THEN `q:real^1->complex` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `z + Cx(&1)` THEN
+    MP_TAC(ISPECL [`\r:real^1->complex. pathfinish r = pathstart r`;
+                   `q:real^1->complex`; `\t:real^1. Cx(&0)`;
+                   `\w. z + cexp w`;
+                   `interval[vec 0:real^1,vec 1]`; `(:complex)`;
+                   `(:complex) DELETE z`]
+     HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT) THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_CEXP; CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST;
+                 CEXP_0; homotopic_loops; o_DEF] THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[CEXP_NZ; COMPLEX_EQ_ADD_LCANCEL_0; SET_RULE
+       `IMAGE f UNIV SUBSET UNIV DELETE z <=> !x. ~(f x = z)`] THEN
+      MATCH_MP_TAC HOMOTOPIC_WITH_MONO THEN
+      EXISTS_TAC `\r:real^1->complex. pathfinish r = pathstart r` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[GSYM homotopic_loops] THEN
+        MATCH_MP_TAC HOMOTOPIC_LOOPS_LINEAR THEN
+        ASM_REWRITE_TAC[SUBSET_UNIV] THEN
+        REWRITE_TAC[path; pathstart; pathfinish; CONTINUOUS_ON_CONST];
+        SIMP_TAC[pathstart; pathfinish]];
+      MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_EQ) THEN
+     ASM_SIMP_TAC[o_THM; pathstart; pathfinish; ENDS_IN_UNIT_INTERVAL]];
+   FIRST_ASSUM(MP_TAC o MATCH_MP WINDING_NUMBER_HOMOTOPIC_LOOPS) THEN
+   ASM_REWRITE_TAC[GSYM LINEPATH_REFL] THEN
+   DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC WINDING_NUMBER_TRIVIAL THEN
+   FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_LOOPS_IMP_SUBSET) THEN
+   REWRITE_TAC[GSYM LINEPATH_REFL; PATH_IMAGE_LINEPATH; SEGMENT_REFL] THEN
+   SET_TAC[]]);;
+
+let WINDING_NUMBER_HOMOTOPIC_PATHS_NULL_EXPLICIT_EQ = prove
+ (`!p z. path p /\ ~(z IN path_image p)
+         ==> (winding_number(p,z) = Cx(&0) <=>
+              homotopic_paths ((:complex) DELETE z)
+                              p (linepath(pathstart p,pathstart p)))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ASM_SIMP_TAC[WINDING_NUMBER_HOMOTOPIC_LOOPS_NULL_EQ] THEN
+    REWRITE_TAC[GSYM LINEPATH_REFL; HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_PATHS_NULL;
+                LEFT_IMP_EXISTS_THM];
+    STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP WINDING_NUMBER_HOMOTOPIC_PATHS) THEN
+    ASM_REWRITE_TAC[GSYM LINEPATH_REFL] THEN
+    DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC WINDING_NUMBER_TRIVIAL THEN
+    ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE]]);;
+
+let WINDING_NUMBER_HOMOTOPIC_PATHS_NULL_EQ = prove
+ (`!p z. path p /\ ~(z IN path_image p)
+         ==> (winding_number(p,z) = Cx(&0) <=>
+              ?a. homotopic_paths ((:complex) DELETE z) p (\t. a))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ASM_SIMP_TAC[WINDING_NUMBER_HOMOTOPIC_PATHS_NULL_EXPLICIT_EQ] THEN
+    REWRITE_TAC[GSYM LINEPATH_REFL] THEN MESON_TAC[];
+    STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP WINDING_NUMBER_HOMOTOPIC_PATHS) THEN
+    ASM_REWRITE_TAC[GSYM LINEPATH_REFL] THEN
+    DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC WINDING_NUMBER_TRIVIAL THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_SUBSET) THEN
+    REWRITE_TAC[GSYM LINEPATH_REFL; PATH_IMAGE_LINEPATH; SEGMENT_REFL] THEN
+    SET_TAC[]]);;
+
+let WINDING_NUMBER_HOMOTOPIC_PATHS_EQ = prove
+ (`!p q z.
+        path p /\ ~(z IN path_image p) /\
+        path q /\ ~(z IN path_image q) /\
+        pathstart q = pathstart p /\ pathfinish q = pathfinish p
+        ==> (winding_number(p,z) = winding_number(q,z) <=>
+             homotopic_paths ((:complex) DELETE z) p q)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  REWRITE_TAC[WINDING_NUMBER_HOMOTOPIC_PATHS] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`p ++ reversepath q:real^1->complex`; `z:complex`]
+        WINDING_NUMBER_HOMOTOPIC_PATHS_NULL_EQ) THEN
+  ASM_SIMP_TAC[PATH_JOIN; PATH_REVERSEPATH; PATH_IMAGE_JOIN; IN_UNION;
+               PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+                PATH_IMAGE_REVERSEPATH; WINDING_NUMBER_JOIN;
+               WINDING_NUMBER_REVERSEPATH; COMPLEX_ADD_RINV] THEN
+  REWRITE_TAC[GSYM LINEPATH_REFL] THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] HOMOTOPIC_PATHS_IMP_HOMOTOPIC_LOOPS)) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHSTART) THEN
+  ASM_REWRITE_TAC[PATHSTART_JOIN; PATHFINISH_JOIN;
+                  PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+                  PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+  DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP
+    (REWRITE_RULE[IMP_CONJ] HOMOTOPIC_PATHS_LOOP_PARTS)) THEN
+  ASM_REWRITE_TAC[]);;
+
+let WINDING_NUMBER_HOMOTOPIC_LOOPS_EQ = prove
+ (`!p q z.
+        path p /\ pathfinish p = pathstart p /\ ~(z IN path_image p) /\
+        path q /\ pathfinish q = pathstart q /\ ~(z IN path_image q)
+        ==> (winding_number(p,z) = winding_number(q,z) <=>
+             homotopic_loops ((:complex) DELETE z) p q)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  REWRITE_TAC[WINDING_NUMBER_HOMOTOPIC_LOOPS] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `~(pathstart p:complex = z) /\ ~(pathstart q = z)`
+  STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; PATHFINISH_IN_PATH_IMAGE];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`(:complex)`; `z:complex`]
+        PATH_CONNECTED_OPEN_DELETE) THEN
+  REWRITE_TAC[OPEN_UNIV; CONNECTED_UNIV; DIMINDEX_2; LE_REFL] THEN
+  REWRITE_TAC[path_connected] THEN DISCH_THEN(MP_TAC o SPECL
+   [`pathstart p:complex`; `pathstart q:complex`]) THEN
+  ASM_REWRITE_TAC[IN_UNIV; IN_DELETE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `r:real^1->complex` THEN
+  REWRITE_TAC[SET_RULE `s SUBSET UNIV DELETE z <=> ~(z IN s)`] THEN
+  STRIP_TAC THEN SUBGOAL_THEN `~(pathstart r:complex = z)`
+  STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; PATHFINISH_IN_PATH_IMAGE];
+    ALL_TAC] THEN
+  MATCH_MP_TAC HOMOTOPIC_LOOPS_TRANS THEN
+  EXISTS_TAC `r ++ q ++ reversepath r:real^1->complex` THEN
+  ASM_SIMP_TAC[HOMOTOPIC_LOOPS_CONJUGATE; SET_RULE
+    `s SUBSET UNIV DELETE z <=> ~(z IN s)`] THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_IMP_HOMOTOPIC_LOOPS THEN
+  ASM_REWRITE_TAC[PATHFINISH_JOIN; PATHFINISH_REVERSEPATH] THEN
+  W(MP_TAC o PART_MATCH (rand o rand) WINDING_NUMBER_HOMOTOPIC_PATHS_EQ o
+    snd) THEN
+  ASM_SIMP_TAC[PATH_JOIN; PATH_REVERSEPATH; PATHSTART_JOIN; PATHFINISH_JOIN;
+               PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+               PATH_IMAGE_JOIN; IN_UNION; PATH_IMAGE_REVERSEPATH;
+               WINDING_NUMBER_JOIN; WINDING_NUMBER_REVERSEPATH] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* A few simple corollaries from the various equivalences.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let SIMPLY_CONNECTED_INSIDE_SIMPLE_PATH = prove
+ (`!p:real^1->real^2.
+     simple_path p ==> simply_connected(inside(path_image p))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP SIMPLE_PATH_IMP_PATH) THEN
+  ASM_SIMP_TAC[SIMPLY_CONNECTED_EQ_EMPTY_INSIDE;
+               OPEN_INSIDE; CLOSED_PATH_IMAGE; INSIDE_INSIDE_EQ_EMPTY;
+               CONNECTED_PATH_IMAGE] THEN
+  ASM_CASES_TAC `pathstart(p):real^2 = pathfinish p` THEN
+  ASM_SIMP_TAC[JORDAN_INSIDE_OUTSIDE; INSIDE_ARC_EMPTY; ARC_SIMPLE_PATH] THEN
+  REWRITE_TAC[CONNECTED_EMPTY]);;
+
+let SIMPLY_CONNECTED_INTER = prove
+ (`!s t:real^2->bool.
+        open s /\ open t /\ simply_connected s /\ simply_connected t /\
+        connected (s INTER t)
+        ==> simply_connected (s INTER t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  SIMP_TAC[SIMPLY_CONNECTED_EQ_WINDING_NUMBER_ZERO; OPEN_INTER] THEN
+  REWRITE_TAC[SUBSET; IN_INTER] THEN MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Pick out the Riemann Mapping Theorem from the earlier chain.              *)
+(* ------------------------------------------------------------------------- *)
+
+let RIEMANN_MAPPING_THEOREM = prove
+ (`!s. open s /\ simply_connected s <=>
+       s = {} \/
+       s = (:real^2) \/
+       ?f g. f holomorphic_on s /\
+             g holomorphic_on ball(Cx(&0),&1) /\
+             (!z. z IN s ==> f z IN ball(Cx(&0),&1) /\ g(f z) = z) /\
+             (!z. z IN ball(Cx(&0),&1) ==> g z IN s /\ f(g z) = z)`,
+  GEN_TAC THEN MATCH_MP_TAC(TAUT
+   `(a ==> (b <=> c)) /\ (c ==> a) ==> (a /\ b <=> c)`) THEN
+  REWRITE_TAC[SIMPLY_CONNECTED_EQ_BIHOLOMORPHIC_TO_DISC] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[OPEN_EMPTY; OPEN_UNIV] THEN
+  SUBGOAL_THEN `s = IMAGE (g:complex->complex) (ball(Cx(&0),&1))`
+  SUBST1_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC INVARIANCE_OF_DOMAIN THEN
+  ASM_SIMP_TAC[OPEN_BALL; HOLOMORPHIC_ON_IMP_CONTINUOUS_ON] THEN
+  ASM_MESON_TAC[]);;
diff --git a/Multivariate/clifford.ml b/Multivariate/clifford.ml
new file mode 100644 (file)
index 0000000..f8a6969
--- /dev/null
@@ -0,0 +1,979 @@
+(* ========================================================================= *)
+(* Geometric algebra.                                                        *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(* ========================================================================= *)
+
+needs "Multivariate/vectors.ml";;
+needs "Library/binary.ml";;
+
+prioritize_real();;
+
+(* ------------------------------------------------------------------------- *)
+(* Some basic lemmas, mostly set theory.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let CARD_UNION_LEMMA = prove
+ (`FINITE s /\ FINITE t /\ FINITE u /\ FINITE v /\
+   s INTER t = {} /\ u INTER v = {} /\ s UNION t = u UNION v
+   ==> CARD(s) + CARD(t) = CARD(u) + CARD(v)`,
+  MESON_TAC[CARD_UNION]);;
+
+let CARD_DIFF_INTER = prove
+ (`!s t. FINITE s ==> CARD s = CARD(s DIFF t) + CARD(s INTER t)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC CARD_UNION_EQ THEN
+  ASM_REWRITE_TAC[] THEN SET_TAC[]);;
+
+let CARD_ADD_SYMDIFF_INTER = prove
+ (`!s t:A->bool.
+        FINITE s /\ FINITE t
+        ==> CARD s + CARD t =
+            CARD((s DIFF t) UNION (t DIFF s)) + 2 * CARD(s INTER t)`,
+  REPEAT STRIP_TAC THEN
+  SUBST1_TAC(SPEC `t:A->bool`(MATCH_MP CARD_DIFF_INTER
+   (ASSUME `FINITE(s:A->bool)`))) THEN
+  SUBST1_TAC(SPEC `s:A->bool`(MATCH_MP CARD_DIFF_INTER
+   (ASSUME `FINITE(t:A->bool)`))) THEN
+  REWRITE_TAC[INTER_ACI] THEN
+  MATCH_MP_TAC(ARITH_RULE `c = a + b ==> (a + x) + (b + x) = c + 2 * x`) THEN
+  MATCH_MP_TAC CARD_UNION THEN ASM_SIMP_TAC[FINITE_DIFF] THEN SET_TAC[]);;
+
+let SYMDIFF_PARITY_LEMMA = prove
+ (`!s t u. FINITE s /\ FINITE t /\ (s DIFF t) UNION (t DIFF s) = u
+           ==> EVEN(CARD u) = (EVEN(CARD s) <=> EVEN(CARD t))`,
+  ONCE_REWRITE_TAC[GSYM EVEN_ADD] THEN
+  SIMP_TAC[CARD_ADD_SYMDIFF_INTER] THEN
+  REWRITE_TAC[EVEN_ADD; EVEN_MULT; ARITH]);;
+
+let FINITE_CART_SUBSET_LEMMA = prove
+ (`!P m n. FINITE {i,j | i IN 1..m /\ j IN 1..n /\ P i j}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN
+  EXISTS_TAC `{i,j | i IN 1..m /\ j IN 1..n}` THEN
+  SIMP_TAC[SUBSET; FINITE_PRODUCT; FINITE_NUMSEG] THEN
+  SIMP_TAC[FORALL_PAIR_THM; IN_ELIM_PAIR_THM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Index type for "multivectors" (k-vectors for all k <= N).                 *)
+(* ------------------------------------------------------------------------- *)
+
+let multivector_tybij_th = prove
+ (`?s. s SUBSET (1..dimindex(:N))`,
+  MESON_TAC[EMPTY_SUBSET]);;
+
+let multivector_tybij =
+  new_type_definition "multivector" ("mk_multivector","dest_multivector")
+    multivector_tybij_th;;
+
+let MULTIVECTOR_IMAGE = prove
+ (`(:(N)multivector) = IMAGE mk_multivector {s | s SUBSET 1..dimindex(:N)}`,
+  REWRITE_TAC[EXTENSION; IN_UNIV; IN_IMAGE; IN_ELIM_THM] THEN
+  MESON_TAC[multivector_tybij]);;
+
+let HAS_SIZE_MULTIVECTOR = prove
+ (`(:(N)multivector) HAS_SIZE (2 EXP dimindex(:N))`,
+  REWRITE_TAC[MULTIVECTOR_IMAGE] THEN MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN
+  SIMP_TAC[HAS_SIZE_POWERSET; HAS_SIZE_NUMSEG_1; IN_ELIM_THM] THEN
+  MESON_TAC[multivector_tybij]);;
+
+let FINITE_MULTIVECTOR = prove
+ (`FINITE(:(N)multivector)`,
+  MESON_TAC[HAS_SIZE; HAS_SIZE_MULTIVECTOR]);;
+
+let DIMINDEX_MULTIVECTOR = prove
+ (`dimindex(:(N)multivector) = 2 EXP dimindex(:N)`,
+  MESON_TAC[DIMINDEX_UNIQUE; HAS_SIZE_MULTIVECTOR]);;
+
+let DEST_MK_MULTIVECTOR = prove
+ (`!s. s SUBSET 1..dimindex(:N)
+         ==> dest_multivector(mk_multivector s :(N)multivector) = s`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC I [GSYM multivector_tybij] THEN
+  ASM_REWRITE_TAC[]);;
+
+let FORALL_MULTIVECTOR = prove
+ (`(!s. s SUBSET 1..dimindex(:N) ==> P(mk_multivector s)) <=>
+   (!m:(N)multivector. P m)`,
+  EQ_TAC THENL [ALL_TAC; SIMP_TAC[]] THEN DISCH_TAC THEN GEN_TAC THEN
+  MP_TAC(ISPEC `m:(N)multivector`
+   (REWRITE_RULE[EXTENSION] MULTIVECTOR_IMAGE)) THEN
+  REWRITE_TAC[IN_UNIV; IN_IMAGE; EXISTS_PAIR_THM; IN_ELIM_THM] THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The bijections we use for indexing.                                       *)
+(*                                                                           *)
+(* Note that we need a *single* bijection over the entire space that also    *)
+(* works for the various subsets. Hence the tedious explicit construction.   *)
+(* ------------------------------------------------------------------------- *)
+
+let setcode = new_definition
+ `setcode s = 1 + binarysum (IMAGE PRE s)`;;
+
+let codeset = new_definition
+ `codeset n = IMAGE SUC (bitset(n - 1))`;;
+
+let CODESET_SETCODE_BIJECTIONS = prove
+ (`(!i. i IN 1..(2 EXP n)
+        ==> codeset i SUBSET 1..n /\ setcode(codeset i) = i) /\
+   (!s. s SUBSET (1..n)
+        ==> (setcode s) IN 1..(2 EXP n) /\ codeset(setcode s) = s)`,
+  REWRITE_TAC[codeset; setcode; ADD_SUB2; GSYM IMAGE_o; o_DEF; PRE] THEN
+  REWRITE_TAC[SET_RULE `IMAGE (\x. x) s = s`] THEN CONJ_TAC THEN GEN_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_NUMSEG] THEN
+    SIMP_TAC[ARITH_RULE `1 <= i ==> (1 + b = i <=> b = i - 1)`] THEN
+    REWRITE_TAC[ARITH_RULE `1 <= SUC n /\ SUC n <= k <=> n < k`] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP
+     (ARITH_RULE `1 <= i /\ i <= t ==> i - 1 < t`)) THEN
+    MESON_TAC[BITSET_BOUND; BINARYSUM_BITSET];
+    ALL_TAC] THEN
+  DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `PRE` o MATCH_MP IMAGE_SUBSET) THEN
+  REWRITE_TAC[IN_NUMSEG; SUBSET] THEN DISCH_TAC THEN CONJ_TAC THENL
+   [MATCH_MP_TAC(ARITH_RULE `x < n ==> 1 <= 1 + x /\ 1 + x <= n`) THEN
+    MATCH_MP_TAC BINARYSUM_BOUND THEN X_GEN_TAC `i:num` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
+    ASM_REWRITE_TAC[IN_IMAGE; IN_NUMSEG] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `IMAGE SUC (IMAGE PRE s)` THEN
+  CONJ_TAC THENL
+   [ASM_MESON_TAC[FINITE_IMAGE; FINITE_SUBSET; FINITE_NUMSEG; BITSET_BINARYSUM];
+    ALL_TAC] THEN
+  UNDISCH_TAC `s SUBSET 1..n` THEN
+  REWRITE_TAC[SUBSET; EXTENSION; IN_IMAGE; IN_NUMSEG] THEN
+  MESON_TAC[ARITH_RULE `1 <= n ==> SUC(PRE n) = n`]);;
+
+let FORALL_SETCODE = prove
+ (`(!s. s SUBSET (1..n) ==> P(setcode s)) <=> (!i. i IN 1..(2 EXP n) ==> P i)`,
+  MESON_TAC[CODESET_SETCODE_BIJECTIONS; SUBSET]);;
+
+let SETCODE_BOUNDS = prove
+ (`!s n. s SUBSET 1..n ==> setcode s IN (1..(2 EXP n))`,
+  MESON_TAC[CODESET_SETCODE_BIJECTIONS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Indexing directly via subsets.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("$$",(25,"left"));;
+
+let sindex = new_definition
+  `(x:real^(N)multivector)$$s = x$(setcode s)`;;
+
+parse_as_binder "lambdas";;
+
+let lambdas = new_definition
+ `(lambdas) (g:(num->bool)->real) =
+    (lambda i. g(codeset i)):real^(N)multivector`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Crucial properties.                                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let MULTIVECTOR_EQ = prove
+ (`!x y:real^(N)multivector.
+        x = y <=> !s. s SUBSET 1..dimindex(:N) ==> x$$s = y$$s`,
+  SIMP_TAC[CART_EQ; sindex; FORALL_SETCODE; GSYM IN_NUMSEG;
+           DIMINDEX_MULTIVECTOR]);;
+
+let MULTIVECTOR_BETA = prove
+ (`!s. s SUBSET 1..dimindex(:N)
+         ==> ((lambdas) g :real^(N)multivector)$$s = g s`,
+  SIMP_TAC[sindex; lambdas; LAMBDA_BETA; SETCODE_BOUNDS;
+           DIMINDEX_MULTIVECTOR; GSYM IN_NUMSEG] THEN
+  MESON_TAC[CODESET_SETCODE_BIJECTIONS]);;
+
+let MULTIVECTOR_UNIQUE = prove
+ (`!m:real^(N)multivector g.
+        (!s. s SUBSET 1..dimindex(:N) ==> m$$s = g s)
+        ==> (lambdas) g = m`,
+  SIMP_TAC[MULTIVECTOR_EQ; MULTIVECTOR_BETA] THEN MESON_TAC[]);;
+
+let MULTIVECTOR_ETA = prove
+ (`(lambdas s. m$$s) = m`,
+  SIMP_TAC[MULTIVECTOR_EQ; MULTIVECTOR_BETA]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Also componentwise operations; they all work in this style.               *)
+(* ------------------------------------------------------------------------- *)
+
+let MULTIVECTOR_ADD_COMPONENT = prove
+ (`!x y:real^(N)multivector s.
+      s SUBSET (1..dimindex(:N)) ==> (x + y)$$s = x$$s + y$$s`,
+  SIMP_TAC[sindex; SETCODE_BOUNDS; DIMINDEX_MULTIVECTOR;
+           GSYM IN_NUMSEG; VECTOR_ADD_COMPONENT]);;
+
+let MULTIVECTOR_MUL_COMPONENT = prove
+ (`!c x:real^(N)multivector s.
+      s SUBSET (1..dimindex(:N)) ==> (c % x)$$s = c * x$$s`,
+  SIMP_TAC[sindex; SETCODE_BOUNDS; DIMINDEX_MULTIVECTOR;
+           GSYM IN_NUMSEG; VECTOR_MUL_COMPONENT]);;
+
+let MULTIVECTOR_VEC_COMPONENT = prove
+ (`!k s. s SUBSET (1..dimindex(:N)) ==> (vec k :real^(N)multivector)$$s = &k`,
+  SIMP_TAC[sindex; SETCODE_BOUNDS; DIMINDEX_MULTIVECTOR;
+           GSYM IN_NUMSEG; VEC_COMPONENT]);;
+
+let MULTIVECTOR_VSUM_COMPONENT = prove
+ (`!f:A->real^(N)multivector t s.
+        s SUBSET (1..dimindex(:N))
+        ==> (vsum t f)$$s = sum t (\x. (f x)$$s)`,
+  SIMP_TAC[vsum; sindex; LAMBDA_BETA; SETCODE_BOUNDS; GSYM IN_NUMSEG;
+           DIMINDEX_MULTIVECTOR]);;
+
+let MULTIVECTOR_VSUM = prove
+ (`!t f. vsum t f = lambdas s. sum t (\x. (f x)$$s)`,
+  SIMP_TAC[MULTIVECTOR_EQ; MULTIVECTOR_BETA; MULTIVECTOR_VSUM_COMPONENT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basis vectors indexed by subsets of 1..N.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let mbasis = new_definition
+ `mbasis i = lambdas s. if i = s then &1 else &0`;;
+
+let MBASIS_COMPONENT = prove
+ (`!s t. s SUBSET (1..dimindex(:N))
+         ==> (mbasis t :real^(N)multivector)$$s = if s = t then &1 else &0`,
+  SIMP_TAC[mbasis; IN_ELIM_THM; MULTIVECTOR_BETA] THEN MESON_TAC[]);;
+
+let MBASIS_EQ_0 = prove
+ (`!s. (mbasis s :real^(N)multivector = vec 0) <=>
+       ~(s SUBSET 1..dimindex(:N))`,
+  SIMP_TAC[MULTIVECTOR_EQ; MBASIS_COMPONENT; MULTIVECTOR_VEC_COMPONENT] THEN
+  MESON_TAC[REAL_ARITH `~(&1 = &0)`]);;
+
+let MBASIS_NONZERO = prove
+ (`!s. s SUBSET 1..dimindex(:N) ==> ~(mbasis s :real^(N)multivector = vec 0)`,
+  REWRITE_TAC[MBASIS_EQ_0]);;
+
+let MBASIS_EXPANSION = prove
+ (`!x:real^(N)multivector.
+        vsum {s | s SUBSET 1..dimindex(:N)} (\s. x$$s % mbasis s) = x`,
+  SIMP_TAC[MULTIVECTOR_EQ; MULTIVECTOR_VSUM_COMPONENT;
+           MULTIVECTOR_MUL_COMPONENT; MBASIS_COMPONENT] THEN
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
+  ASM_SIMP_TAC[REAL_ARITH `x * (if p then &1 else &0) = if p then x else &0`;
+               SUM_DELTA; IN_ELIM_THM]);;
+
+let SPAN_MBASIS = prove
+ (`span {mbasis s :real^(N)multivector | s SUBSET 1..dimindex(:N)} = UNIV`,
+  REWRITE_TAC[EXTENSION; IN_UNIV] THEN X_GEN_TAC `x:real^(N)multivector` THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM MBASIS_EXPANSION] THEN
+  MATCH_MP_TAC SPAN_VSUM THEN
+  SIMP_TAC[FINITE_NUMSEG; FINITE_POWERSET; IN_ELIM_THM] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SPAN_MUL THEN
+  MATCH_MP_TAC SPAN_SUPERSET THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Linear and bilinear functions are determined by their effect on basis.    *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_EQ_MBASIS = prove
+ (`!f:real^(M)multivector->real^N g b s.
+        linear f /\ linear g /\
+        (!s. s SUBSET 1..dimindex(:M) ==> f(mbasis s) = g(mbasis s))
+        ==> f = g`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `!x. x IN UNIV ==> (f:real^(M)multivector->real^N) x = g x`
+   (fun th -> MP_TAC th THEN REWRITE_TAC[FUN_EQ_THM; IN_UNIV]) THEN
+  MATCH_MP_TAC LINEAR_EQ THEN
+  EXISTS_TAC `{mbasis s :real^(M)multivector | s SUBSET 1..dimindex(:M)}` THEN
+  ASM_REWRITE_TAC[SPAN_MBASIS; SUBSET_REFL; IN_ELIM_THM] THEN
+  ASM_MESON_TAC[]);;
+
+let BILINEAR_EQ_MBASIS = prove
+ (`!f:real^(M)multivector->real^(N)multivector->real^P g b s.
+        bilinear f /\ bilinear g /\
+        (!s t.  s SUBSET 1..dimindex(:M) /\ t SUBSET 1..dimindex(:N)
+                ==> f (mbasis s) (mbasis t) = g (mbasis s) (mbasis t))
+        ==> f = g`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+   `!x y. x IN UNIV /\ y IN UNIV
+          ==> (f:real^(M)multivector->real^(N)multivector->real^P) x y = g x y`
+   (fun th -> MP_TAC th THEN REWRITE_TAC[FUN_EQ_THM; IN_UNIV]) THEN
+  MATCH_MP_TAC BILINEAR_EQ THEN
+  EXISTS_TAC `{mbasis s :real^(M)multivector | s SUBSET 1..dimindex(:M)}` THEN
+  EXISTS_TAC `{mbasis t :real^(N)multivector | t SUBSET 1..dimindex(:N)}` THEN
+  ASM_REWRITE_TAC[SPAN_MBASIS; SUBSET_REFL; IN_ELIM_THM] THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A way of proving linear properties by extension from basis.               *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_PROPERTY = prove
+ (`!P. P(vec 0) /\ (!x y. P x /\ P y ==> P(x + y))
+       ==> !f s. FINITE s /\ (!i. i IN s ==> P(f i)) ==> P(vsum s f)`,
+  GEN_TAC THEN STRIP_TAC THEN GEN_TAC THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  ASM_SIMP_TAC[VSUM_CLAUSES; IN_INSERT]);;
+
+let MBASIS_EXTENSION = prove
+ (`!P. (!s. s SUBSET 1..dimindex(:N) ==> P(mbasis s)) /\
+       (!c x. P x ==> P(c % x)) /\ (!x y. P x /\ P y ==> P(x + y))
+       ==> !x:real^(N)multivector. P x`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC RAND_CONV [GSYM MBASIS_EXPANSION] THEN
+  MATCH_MP_TAC(SIMP_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP] LINEAR_PROPERTY) THEN
+  ASM_SIMP_TAC[FINITE_POWERSET; FINITE_NUMSEG; IN_ELIM_THM] THEN
+  ASM_MESON_TAC[EMPTY_SUBSET; VECTOR_MUL_LZERO]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Injection from regular vectors.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let multivec = new_definition
+ `(multivec:real^N->real^(N)multivector) x =
+      vsum(1..dimindex(:N)) (\i. x$i % mbasis{i})`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Subspace of k-vectors.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("multivector",(12,"right"));;
+
+let multivector = new_definition
+ `k multivector (p:real^(N)multivector) <=>
+        !s. s SUBSET (1..dimindex(:N)) /\ ~(p$$s = &0) ==> s HAS_SIZE k`;;
+
+(* ------------------------------------------------------------------------- *)
+(* k-grade part of a multivector.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("grade",(22,"right"));;
+
+let grade = new_definition
+ `k grade (p:real^(N)multivector) =
+     (lambdas s. if s HAS_SIZE k then p$$s else &0):real^(N)multivector`;;
+
+let MULTIVECTOR_GRADE = prove
+ (`!k x. k multivector (k grade x)`,
+  SIMP_TAC[multivector; grade; MULTIVECTOR_BETA; IMP_CONJ] THEN
+  MESON_TAC[]);;
+
+let GRADE_ADD = prove
+ (`!x y k. k grade (x + y) = (k grade x) + (k grade y)`,
+  SIMP_TAC[grade; MULTIVECTOR_EQ; MULTIVECTOR_ADD_COMPONENT;
+           MULTIVECTOR_BETA; COND_COMPONENT] THEN
+  REAL_ARITH_TAC);;
+
+let GRADE_CMUL = prove
+ (`!c x k. k grade (c % x) = c % (k grade x)`,
+  SIMP_TAC[grade; MULTIVECTOR_EQ; MULTIVECTOR_MUL_COMPONENT;
+           MULTIVECTOR_BETA; COND_COMPONENT] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* General product construct.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let Product_DEF = new_definition
+ `(Product mult op
+     :real^(N)multivector->real^(N)multivector->real^(N)multivector) x y =
+        vsum {s | s SUBSET 1..dimindex(:N)}
+         (\s. vsum {s | s SUBSET 1..dimindex(:N)}
+                (\t. (x$$s * y$$t * mult s t) % mbasis (op s t)))`;;
+
+(* ------------------------------------------------------------------------- *)
+(* This is always bilinear.                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let BILINEAR_PRODUCT = prove
+ (`!mult op. bilinear(Product mult op)`,
+  REWRITE_TAC[bilinear; linear; Product_DEF] THEN
+  SIMP_TAC[GSYM VSUM_LMUL; MULTIVECTOR_MUL_COMPONENT] THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC; REAL_MUL_AC] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[Product_DEF] THEN
+  SIMP_TAC[GSYM VSUM_ADD; FINITE_POWERSET; FINITE_NUMSEG] THEN
+  REPEAT(MATCH_MP_TAC VSUM_EQ THEN REWRITE_TAC[IN_ELIM_THM] THEN
+         REPEAT STRIP_TAC) THEN
+  ASM_SIMP_TAC[MULTIVECTOR_ADD_COMPONENT] THEN VECTOR_ARITH_TAC);;
+
+let PRODUCT_LADD = (MATCH_MP BILINEAR_LADD o SPEC_ALL) BILINEAR_PRODUCT;;
+let PRODUCT_RADD = (MATCH_MP BILINEAR_RADD o SPEC_ALL) BILINEAR_PRODUCT;;
+let PRODUCT_LMUL = (MATCH_MP BILINEAR_LMUL o SPEC_ALL) BILINEAR_PRODUCT;;
+let PRODUCT_RMUL = (MATCH_MP BILINEAR_RMUL o SPEC_ALL) BILINEAR_PRODUCT;;
+let PRODUCT_LNEG = (MATCH_MP BILINEAR_LNEG o SPEC_ALL) BILINEAR_PRODUCT;;
+let PRODUCT_RNEG = (MATCH_MP BILINEAR_RNEG o SPEC_ALL) BILINEAR_PRODUCT;;
+let PRODUCT_LZERO = (MATCH_MP BILINEAR_LZERO o SPEC_ALL) BILINEAR_PRODUCT;;
+let PRODUCT_RZERO = (MATCH_MP BILINEAR_RZERO o SPEC_ALL) BILINEAR_PRODUCT;;
+
+(* ------------------------------------------------------------------------- *)
+(* Under suitable conditions, it's also associative.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let PRODUCT_ASSOCIATIVE = prove
+ (`!op mult. (!s t. s SUBSET 1..dimindex(:N) /\ t SUBSET 1..dimindex(:N)
+                    ==> (op s t) SUBSET 1..dimindex(:N)) /\
+             (!s t u. op s (op t u) = op (op s t) u) /\
+             (!s t u. mult t u * mult s (op t u) = mult s t * mult (op s t) u)
+             ==> !x y z:real^(N)multivector.
+                        Product mult op x (Product mult op y z) =
+                        Product mult op (Product mult op x y) z`,
+  let SUM_SWAP_POWERSET =
+    SIMP_RULE[FINITE_POWERSET; FINITE_NUMSEG]
+     (repeat(SPEC `{s | s SUBSET 1..dimindex(:N)}`)
+        (ISPEC `f:(num->bool)->(num->bool)->real` SUM_SWAP)) in
+  let SWAP_TAC cnv n =
+    GEN_REWRITE_TAC (cnv o funpow n BINDER_CONV) [SUM_SWAP_POWERSET] THEN
+    REWRITE_TAC[] in
+  let SWAPS_TAC cnv ns x =
+    MAP_EVERY (SWAP_TAC cnv) ns THEN MATCH_MP_TAC SUM_EQ THEN X_GEN_TAC x THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC in
+  REWRITE_TAC[Product_DEF] THEN REPEAT STRIP_TAC THEN
+  SIMP_TAC[MULTIVECTOR_EQ; MULTIVECTOR_VSUM_COMPONENT; MBASIS_COMPONENT;
+           MULTIVECTOR_MUL_COMPONENT] THEN
+  SIMP_TAC[GSYM SUM_LMUL; GSYM SUM_RMUL] THEN
+  X_GEN_TAC `r:num->bool` THEN STRIP_TAC THEN
+  SWAPS_TAC RAND_CONV [1;0] `s:num->bool` THEN
+  SWAP_TAC LAND_CONV 0 THEN SWAPS_TAC RAND_CONV [1;0] `t:num->bool` THEN
+  SWAP_TAC RAND_CONV 0 THEN SWAPS_TAC LAND_CONV [0] `u:num->bool` THEN
+  REWRITE_TAC[GSYM REAL_MUL_ASSOC;
+    REAL_ARITH `(if p then a else &0) * b = if p then a * b else &0`;
+    REAL_ARITH `a * (if p then b else &0) = if p then a * b else &0`] THEN
+  SIMP_TAC[SUM_DELTA] THEN ASM_SIMP_TAC[IN_ELIM_THM] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_MUL_LID; REAL_MUL_RID] THEN
+  ASM_REWRITE_TAC[] THEN REWRITE_TAC[REAL_MUL_AC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Geometric product.                                                        *)
+(* ------------------------------------------------------------------------- *)
+
+overload_interface
+ ("*",
+  `geom_mul:real^(N)multivector->real^(N)multivector->real^(N)multivector`);;
+
+let geom_mul = new_definition
+ `(x:real^(N)multivector) * y =
+        Product (\s t. --(&1) pow CARD {i,j | i IN 1..dimindex(:N) /\
+                                              j IN 1..dimindex(:N) /\
+                                              i IN s /\ j IN t /\ i > j})
+                (\s t. (s DIFF t) UNION (t DIFF s))
+                x y`;;
+
+let BILINEAR_GEOM = prove
+ (`bilinear(geom_mul)`,
+  REWRITE_TAC[REWRITE_RULE[GSYM FUN_EQ_THM; ETA_AX] geom_mul] THEN
+  MATCH_ACCEPT_TAC BILINEAR_PRODUCT);;
+
+let GEOM_LADD = (MATCH_MP BILINEAR_LADD o SPEC_ALL) BILINEAR_GEOM;;
+let GEOM_RADD = (MATCH_MP BILINEAR_RADD o SPEC_ALL) BILINEAR_GEOM;;
+let GEOM_LMUL = (MATCH_MP BILINEAR_LMUL o SPEC_ALL) BILINEAR_GEOM;;
+let GEOM_RMUL = (MATCH_MP BILINEAR_RMUL o SPEC_ALL) BILINEAR_GEOM;;
+let GEOM_LNEG = (MATCH_MP BILINEAR_LNEG o SPEC_ALL) BILINEAR_GEOM;;
+let GEOM_RNEG = (MATCH_MP BILINEAR_RNEG o SPEC_ALL) BILINEAR_GEOM;;
+let GEOM_LZERO = (MATCH_MP BILINEAR_LZERO o SPEC_ALL) BILINEAR_GEOM;;
+let GEOM_RZERO = (MATCH_MP BILINEAR_RZERO o SPEC_ALL) BILINEAR_GEOM;;
+
+let GEOM_ASSOC = prove
+ (`!x y z:real^(N)multivector. x * (y * z) = (x * y) * z`,
+  REWRITE_TAC[geom_mul] THEN MATCH_MP_TAC PRODUCT_ASSOCIATIVE THEN
+  REPEAT(CONJ_TAC THENL [SET_TAC[]; ALL_TAC]) THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM REAL_POW_ADD] THEN
+  REWRITE_TAC[REAL_POW_NEG; REAL_POW_ONE] THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EVEN_ADD] THEN
+  W(fun (_,w) -> let tu = funpow 2 lhand w in
+                 let su = vsubst[`s:num->bool`,`t:num->bool`] tu in
+                 let st = vsubst[`t:num->bool`,`u:num->bool`] su in
+                 MATCH_MP_TAC EQ_TRANS THEN
+                 EXISTS_TAC(end_itlist (curry mk_eq) [st; su; tu])) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC(TAUT `(x <=> y <=> z) ==> ((a <=> x) <=> (y <=> z <=> a))`);
+    AP_TERM_TAC THEN CONV_TAC SYM_CONV] THEN
+  MATCH_MP_TAC SYMDIFF_PARITY_LEMMA THEN
+  REWRITE_TAC[FINITE_CART_SUBSET_LEMMA] THEN
+  REWRITE_TAC[EXTENSION; FORALL_PAIR_THM; IN_ELIM_PAIR_THM;
+              IN_UNION; IN_DIFF] THEN
+  CONV_TAC TAUT);;
+
+(* ------------------------------------------------------------------------- *)
+(* Outer product.                                                            *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("outer",(20,"right"));;
+
+let outer = new_definition
+ `!x y:real^(N)multivector.
+    x outer y =
+        Product (\s t. if ~(s INTER t = {}) then &0
+                       else --(&1) pow CARD {i,j | i IN 1..dimindex(:N) /\
+                                                   j IN 1..dimindex(:N) /\
+                                                   i IN s /\ j IN t /\ i > j})
+                (\s t. (s DIFF t) UNION (t DIFF s))
+                x y`;;
+
+let OUTER = prove
+ (`!x y:real^(N)multivector.
+    x outer y =
+        Product (\s t. if ~(s INTER t = {}) then &0
+                       else --(&1) pow CARD {i,j | i IN 1..dimindex(:N) /\
+                                                   j IN 1..dimindex(:N) /\
+                                                   i IN s /\ j IN t /\ i > j})
+                (UNION)
+                x y`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[outer; Product_DEF] THEN
+  REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+  ASM_CASES_TAC `s INTER t :num->bool = {}` THEN
+  ASM_REWRITE_TAC[REAL_MUL_RZERO; VECTOR_MUL_LZERO] THEN
+  ASM_SIMP_TAC[SET_RULE
+   `(s INTER t = {}) ==> (s DIFF t) UNION (t DIFF s) = s UNION t`]);;
+
+let BILINEAR_OUTER = prove
+ (`bilinear(outer)`,
+  REWRITE_TAC[REWRITE_RULE[GSYM FUN_EQ_THM; ETA_AX] outer] THEN
+  MATCH_ACCEPT_TAC BILINEAR_PRODUCT);;
+
+let OUTER_LADD = (MATCH_MP BILINEAR_LADD o SPEC_ALL) BILINEAR_OUTER;;
+let OUTER_RADD = (MATCH_MP BILINEAR_RADD o SPEC_ALL) BILINEAR_OUTER;;
+let OUTER_LMUL = (MATCH_MP BILINEAR_LMUL o SPEC_ALL) BILINEAR_OUTER;;
+let OUTER_RMUL = (MATCH_MP BILINEAR_RMUL o SPEC_ALL) BILINEAR_OUTER;;
+let OUTER_LNEG = (MATCH_MP BILINEAR_LNEG o SPEC_ALL) BILINEAR_OUTER;;
+let OUTER_RNEG = (MATCH_MP BILINEAR_RNEG o SPEC_ALL) BILINEAR_OUTER;;
+let OUTER_LZERO = (MATCH_MP BILINEAR_LZERO o SPEC_ALL) BILINEAR_OUTER;;
+let OUTER_RZERO = (MATCH_MP BILINEAR_RZERO o SPEC_ALL) BILINEAR_OUTER;;
+
+let OUTER_ASSOC = prove
+ (`!x y z:real^(N)multivector. x outer (y outer z) = (x outer y) outer z`,
+  REWRITE_TAC[OUTER] THEN MATCH_MP_TAC PRODUCT_ASSOCIATIVE THEN
+  SIMP_TAC[UNION_SUBSET; UNION_ASSOC;
+     SET_RULE `s INTER (t UNION u) = (s INTER t) UNION (s INTER u)`;
+     SET_RULE `(t UNION u) INTER s = (t INTER s) UNION (u INTER s)`] THEN
+  REWRITE_TAC[EMPTY_UNION] THEN REPEAT GEN_TAC THEN
+  MAP_EVERY ASM_CASES_TAC
+   [`s INTER t :num->bool = {}`;
+    `s INTER u :num->bool = {}`;
+    `t INTER u :num->bool = {}`] THEN
+  ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_RZERO] THEN
+  REWRITE_TAC[GSYM REAL_POW_ADD] THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC CARD_UNION_LEMMA THEN REWRITE_TAC[FINITE_CART_SUBSET_LEMMA] THEN
+  SIMP_TAC[EXTENSION; FORALL_PAIR_THM; NOT_IN_EMPTY; IN_UNION; IN_INTER] THEN
+  REWRITE_TAC[IN_ELIM_PAIR_THM] THEN ASM SET_TAC []);;
+
+(* ------------------------------------------------------------------------- *)
+(* Inner product.                                                            *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("inner",(20,"right"));;
+
+let inner = new_definition
+ `!x y:real^(N)multivector.
+    x inner y =
+        Product (\s t. if s = {} \/ t = {} \/
+                          ~((s DIFF t) = {} /\ ~(t DIFF s = {}))
+                       then &0
+                       else --(&1) pow CARD {i,j | i IN 1..dimindex(:N) /\
+                                                   j IN 1..dimindex(:N) /\
+                                                   i IN s /\ j IN t /\ i > j})
+                (\s t. (s DIFF t) UNION (t DIFF s))
+                x y`;;
+
+let BILINEAR_INNER = prove
+ (`bilinear(inner)`,
+  REWRITE_TAC[REWRITE_RULE[GSYM FUN_EQ_THM; ETA_AX] inner] THEN
+  MATCH_ACCEPT_TAC BILINEAR_PRODUCT);;
+
+let INNER_LADD = (MATCH_MP BILINEAR_LADD o SPEC_ALL) BILINEAR_INNER;;
+let INNER_RADD = (MATCH_MP BILINEAR_RADD o SPEC_ALL) BILINEAR_INNER;;
+let INNER_LMUL = (MATCH_MP BILINEAR_LMUL o SPEC_ALL) BILINEAR_INNER;;
+let INNER_RMUL = (MATCH_MP BILINEAR_RMUL o SPEC_ALL) BILINEAR_INNER;;
+let INNER_LNEG = (MATCH_MP BILINEAR_LNEG o SPEC_ALL) BILINEAR_INNER;;
+let INNER_RNEG = (MATCH_MP BILINEAR_RNEG o SPEC_ALL) BILINEAR_INNER;;
+let INNER_LZERO = (MATCH_MP BILINEAR_LZERO o SPEC_ALL) BILINEAR_INNER;;
+let INNER_RZERO = (MATCH_MP BILINEAR_RZERO o SPEC_ALL) BILINEAR_INNER;;
+
+(* ------------------------------------------------------------------------- *)
+(* Actions of products on basis and singleton basis.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let PRODUCT_MBASIS = prove
+ (`!s t. Product mult op (mbasis s) (mbasis t) :real^(N)multivector =
+            if s SUBSET 1..dimindex(:N) /\ t SUBSET 1..dimindex(:N)
+            then mult s t % mbasis(op s t)
+            else vec 0`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[Product_DEF] THEN
+  SIMP_TAC[MULTIVECTOR_MUL_COMPONENT; MBASIS_COMPONENT] THEN
+  REWRITE_TAC[REAL_ARITH
+   `(if p then &1 else &0) * (if q then &1 else &0) * x =
+    if q then if p then x else &0 else &0`] THEN
+  REPEAT
+   (GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [COND_RAND] THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [COND_RATOR] THEN
+    SIMP_TAC[VECTOR_MUL_LZERO; COND_ID; VSUM_DELTA; IN_ELIM_THM; VSUM_0] THEN
+    ASM_CASES_TAC `t SUBSET 1..dimindex(:N)` THEN ASM_REWRITE_TAC[]));;
+
+let PRODUCT_MBASIS_SING = prove
+ (`!i j. Product mult op (mbasis{i}) (mbasis{j}) :real^(N)multivector =
+            if i IN 1..dimindex(:N) /\ j IN 1..dimindex(:N)
+            then mult {i} {j} % mbasis(op {i} {j})
+            else vec 0`,
+  REWRITE_TAC[PRODUCT_MBASIS; SET_RULE `{x} SUBSET s <=> x IN s`]);;
+
+let GEOM_MBASIS = prove
+ (`!s t. mbasis s * mbasis t :real^(N)multivector =
+                if s SUBSET 1..dimindex(:N) /\ t SUBSET 1..dimindex(:N)
+                then --(&1) pow CARD {i,j | i IN s /\ j IN t /\ i > j} %
+                     mbasis((s DIFF t) UNION (t DIFF s))
+                else vec 0`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[geom_mul; PRODUCT_MBASIS] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_PAIR_THM; FORALL_PAIR_THM] THEN
+  ASM_MESON_TAC[SUBSET]);;
+
+let GEOM_MBASIS_SING = prove
+ (`!i j. mbasis{i} * mbasis{j} :real^(N)multivector =
+                if i IN 1..dimindex(:N) /\ j IN 1..dimindex(:N)
+                then if i = j then mbasis{}
+                     else if i < j then mbasis{i,j}
+                     else --(mbasis{i,j})
+                else vec 0`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[geom_mul; PRODUCT_MBASIS_SING] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_SING] THEN
+  SUBGOAL_THEN
+   `{i',j' | i' IN 1 .. dimindex (:N) /\
+             j' IN 1 .. dimindex (:N) /\
+             i' = i /\
+             j' = j /\
+             i' > j'} =
+    if i > j then {(i,j)} else {}`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; FORALL_PAIR_THM; IN_ELIM_PAIR_THM; IN_SING] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_SING; NOT_IN_EMPTY; PAIR_EQ] THEN
+    ASM_MESON_TAC[LT_REFL];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `i:num = j` THEN ASM_REWRITE_TAC[GT; LT_REFL] THENL
+   [REWRITE_TAC[CARD_CLAUSES; real_pow; VECTOR_MUL_LID] THEN
+    AP_TERM_TAC THEN SET_TAC[];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[SET_RULE
+   `~(i = j) ==> ({i} DIFF {j}) UNION ({j} DIFF {i}) = {i,j}`] THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP (ARITH_RULE
+   `~(i:num = j) ==> (j < i <=> ~(i < j))`)) THEN
+  ASM_CASES_TAC `i:num < j` THEN
+  ASM_SIMP_TAC[CARD_CLAUSES; real_pow; VECTOR_MUL_LID; FINITE_RULES;
+               NOT_IN_EMPTY] THEN
+  VECTOR_ARITH_TAC);;
+
+let OUTER_MBASIS = prove
+ (`!s t. (mbasis s) outer (mbasis t) :real^(N)multivector =
+                if s SUBSET 1..dimindex(:N) /\ t SUBSET 1..dimindex(:N) /\
+                   s INTER t = {}
+                then --(&1) pow CARD {i,j | i IN s /\ j IN t /\ i > j} %
+                     mbasis(s UNION t)
+                else vec 0`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[OUTER; PRODUCT_MBASIS] THEN
+  ASM_CASES_TAC `(s:num->bool) INTER t = {}` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LZERO; COND_ID] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_PAIR_THM; FORALL_PAIR_THM] THEN
+  ASM_MESON_TAC[SUBSET]);;
+
+let OUTER_MBASIS_SING = prove
+ (`!i j. mbasis{i} outer mbasis{j} :real^(N)multivector =
+                if i IN 1..dimindex(:N) /\ j IN 1..dimindex(:N) /\ ~(i = j)
+                then if i < j then mbasis{i,j} else --(mbasis{i,j})
+                else vec 0`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[OUTER; PRODUCT_MBASIS_SING] THEN
+  REWRITE_TAC[SET_RULE `{i} INTER {j} = {} <=> ~(i = j)`] THEN
+  ASM_CASES_TAC `i:num = j` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LZERO; COND_ID] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_SING] THEN
+  SUBGOAL_THEN
+   `{i',j' | i' IN 1 .. dimindex (:N) /\
+             j' IN 1 .. dimindex (:N) /\
+             i' = i /\
+             j' = j /\
+             i' > j'} =
+    if i > j then {(i,j)} else {}`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; FORALL_PAIR_THM; IN_ELIM_PAIR_THM; IN_SING] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_SING; NOT_IN_EMPTY; PAIR_EQ] THEN
+    ASM_MESON_TAC[LT_REFL];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[GT; SET_RULE `{i} UNION {j} = {i,j}`] THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP (ARITH_RULE
+   `~(i:num = j) ==> (j < i <=> ~(i < j))`)) THEN
+  ASM_CASES_TAC `i:num < j` THEN
+  ASM_SIMP_TAC[CARD_CLAUSES; real_pow; VECTOR_MUL_LID; FINITE_RULES;
+               NOT_IN_EMPTY] THEN
+  VECTOR_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some simple consequences.                                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let OUTER_MBASIS_SKEWSYM = prove
+ (`!i j. mbasis{i} outer mbasis{j} = --(mbasis{j} outer mbasis{i})`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[OUTER_MBASIS_SING] THEN
+  ASM_CASES_TAC `i:num = j` THEN ASM_REWRITE_TAC[VECTOR_NEG_0] THEN
+  FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (ARITH_RULE
+   `~(i:num = j) ==> i < j /\ ~(j < i) \/ j < i /\ ~(i < j)`)) THEN
+  ASM_REWRITE_TAC[CONJ_ACI] THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_NEG_NEG; VECTOR_NEG_0] THEN
+  REPEAT AP_TERM_TAC THEN SET_TAC[]);;
+
+let OUTER_MBASIS_REFL = prove
+ (`!i. mbasis{i} outer mbasis{i} = vec 0`,
+  GEN_TAC THEN MATCH_MP_TAC(VECTOR_ARITH
+   `!x:real^N. x = --x ==> x = vec 0`) THEN
+  MATCH_ACCEPT_TAC OUTER_MBASIS_SKEWSYM);;
+
+let OUTER_MBASIS_LSCALAR = prove
+ (`!x. mbasis{} outer x = x`,
+  MATCH_MP_TAC MBASIS_EXTENSION THEN SIMP_TAC[OUTER_RMUL; OUTER_RADD] THEN
+  SIMP_TAC[OUTER_MBASIS; EMPTY_SUBSET; INTER_EMPTY; UNION_EMPTY] THEN
+  REWRITE_TAC[SET_RULE `{i,j | i IN {} /\ j IN s /\ i:num > j} = {}`] THEN
+  REWRITE_TAC[CARD_CLAUSES; real_pow; VECTOR_MUL_LID]);;
+
+let OUTER_MBASIS_RSCALAR = prove
+ (`!x. x outer mbasis{} = x`,
+  MATCH_MP_TAC MBASIS_EXTENSION THEN SIMP_TAC[OUTER_LMUL; OUTER_LADD] THEN
+  SIMP_TAC[OUTER_MBASIS; EMPTY_SUBSET; INTER_EMPTY; UNION_EMPTY] THEN
+  REWRITE_TAC[SET_RULE `{i,j | i IN s /\ j IN {} /\ i:num > j} = {}`] THEN
+  REWRITE_TAC[CARD_CLAUSES; real_pow; VECTOR_MUL_LID]);;
+
+let MBASIS_SPLIT = prove
+ (`!a s. (!x. x IN s ==> a < x)
+         ==> mbasis (a INSERT s) = mbasis{a} outer mbasis s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[OUTER_MBASIS] THEN
+  SUBGOAL_THEN `{a:num} INTER s = {}` SUBST1_TAC THENL
+   [ASM SET_TAC [LT_REFL]; ALL_TAC] THEN
+  SIMP_TAC[SET_RULE`{a} SUBSET t /\ s SUBSET t <=> (a INSERT s) SUBSET t`] THEN
+  COND_CASES_TAC THENL [ALL_TAC; ASM_MESON_TAC[MBASIS_EQ_0]] THEN
+  REWRITE_TAC[SET_RULE `{a} UNION s = a INSERT s`] THEN
+  SUBGOAL_THEN `{(i:num),(j:num) | i IN {a} /\ j IN s /\ i > j} = {}`
+   (fun th -> SIMP_TAC[th; CARD_CLAUSES; real_pow; VECTOR_MUL_LID]) THEN
+  REWRITE_TAC[EXTENSION; FORALL_PAIR_THM; IN_ELIM_PAIR_THM; IN_SING;
+              NOT_IN_EMPTY] THEN
+  ASM_MESON_TAC[ARITH_RULE `~(n < m /\ n:num > m)`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Just for generality, normalize a set enumeration.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let SETENUM_NORM_CONV =
+  let conv =
+    GEN_REWRITE_CONV I [EXTENSION] THENC
+    GEN_REWRITE_CONV TOP_SWEEP_CONV [IN_SING; IN_INSERT] THENC
+    BINDER_CONV(EQT_INTRO o DISJ_ACI_RULE) THENC
+    GEN_REWRITE_CONV I [FORALL_SIMP] in
+  fun tm ->
+    let nums = dest_setenum tm in
+    let nums' = map mk_numeral (sort (</) (map dest_numeral (setify nums))) in
+    if nums' = nums then REFL tm else
+    let eq = mk_eq(tm,mk_setenum(nums',fst(dest_fun_ty(type_of tm)))) in
+    EQT_ELIM(conv eq);;
+
+(* ------------------------------------------------------------------------- *)
+(* Conversion to split extended basis combinations.                          *)
+(*                                                                           *)
+(* Also 1-step merge from left, which can be DEPTH_CONV'd. In this case the  *)
+(* order must be correct.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let MBASIS_SPLIT_CONV,MBASIS_MERGE_CONV =
+  let setlemma = SET_RULE
+   `((!x:num. x IN {} ==> a < x) <=> T) /\
+    ((!x:num. x IN (y INSERT s) ==> a < x) <=>
+              a < y /\ (!x. x IN s ==> a < x))` in
+  let SET_CHECK_CONV =
+    GEN_REWRITE_CONV TOP_SWEEP_CONV [setlemma] THENC NUM_REDUCE_CONV
+  and INST_SPLIT = PART_MATCH (lhs o rand) MBASIS_SPLIT
+  and INST_MERGE = PART_MATCH (lhs o rand) (GSYM MBASIS_SPLIT) in
+  let rec conv tm =
+    if length(dest_setenum(rand tm)) <= 1 then REFL tm else
+    let th = MP_CONV SET_CHECK_CONV (INST_SPLIT tm) in
+    let th' = RAND_CONV conv (rand(concl th)) in
+    TRANS th th' in
+  (fun tm ->
+    try let op,se = dest_comb tm in
+        if fst(dest_const op) = "mbasis" & forall is_numeral (dest_setenum se)
+        then (RAND_CONV SETENUM_NORM_CONV THENC conv) tm
+        else fail()
+    with Failure _ -> failwith "MBASIS_SPLIT_CONV"),
+  (fun tm -> try MP_CONV SET_CHECK_CONV (INST_MERGE tm)
+             with Failure _ -> failwith "MBASIS_MERGE_CONV");;
+
+(* ------------------------------------------------------------------------- *)
+(* Convergent (if slow) rewrite set to bubble into position.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let OUTER_ACI = prove
+ (`(!x y z. (x outer y) outer z = x outer (y outer z)) /\
+   (!i j. i > j
+          ==> mbasis{i} outer mbasis{j} =
+              --(&1) % (mbasis{j} outer mbasis{i})) /\
+   (!i j x. i > j
+            ==> mbasis{i} outer mbasis{j} outer x =
+                --(&1) % (mbasis{j} outer mbasis{i} outer x)) /\
+   (!i. mbasis{i} outer mbasis{i} = vec 0) /\
+   (!i x. mbasis{i} outer mbasis{i} outer x = vec 0) /\
+   (!x. mbasis{} outer x = x) /\
+   (!x. x outer mbasis{} = x)`,
+  REWRITE_TAC[OUTER_ASSOC; OUTER_LZERO; OUTER_RZERO; OUTER_LADD;
+            OUTER_RADD; OUTER_LMUL; OUTER_RMUL; OUTER_LZERO; OUTER_RZERO] THEN
+  REWRITE_TAC[OUTER_MBASIS_REFL; OUTER_LZERO] THEN
+  REWRITE_TAC[OUTER_MBASIS_LSCALAR; OUTER_MBASIS_RSCALAR] THEN
+  SIMP_TAC[GSYM VECTOR_NEG_MINUS1; VECTOR_ARITH `x - y:real^N = x + --y`] THEN
+  MESON_TAC[OUTER_MBASIS_SKEWSYM; OUTER_LNEG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Group the final "c1 % mbasis s1 + ... + cn % mbasis sn".                  *)
+(* ------------------------------------------------------------------------- *)
+
+let MBASIS_GROUP_CONV tm =
+  let tms = striplist(dest_binary "vector_add") tm in
+  if length tms = 1 then LAND_CONV REAL_POLY_CONV tm else
+  let vadd_tm = rator(rator tm) in
+  let mk_vadd = mk_binop vadd_tm in
+  let mbs = map (snd o dest_binary "%") tms in
+  let tmbs = zip mbs tms and mset = setify mbs in
+  let grps = map (fun x -> map snd (filter (fun (x',_) -> x' = x) tmbs))
+                 mset in
+  let tm' = end_itlist mk_vadd (map (end_itlist mk_vadd) grps) in
+  let th1 = AC VECTOR_ADD_AC (mk_eq(tm,tm'))
+  and th2 =
+   (GEN_REWRITE_CONV DEPTH_CONV [GSYM VECTOR_ADD_RDISTRIB] THENC
+    DEPTH_BINOP_CONV vadd_tm (LAND_CONV REAL_POLY_CONV)) tm' in
+  TRANS th1 th2;;
+
+(* ------------------------------------------------------------------------- *)
+(* Overall conversion.                                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let OUTER_CANON_CONV =
+  ONCE_DEPTH_CONV MBASIS_SPLIT_CONV THENC
+  GEN_REWRITE_CONV TOP_DEPTH_CONV
+   [VECTOR_SUB; VECTOR_NEG_MINUS1;
+    OUTER_LADD; OUTER_RADD; OUTER_LMUL; OUTER_RMUL; OUTER_LZERO; OUTER_RZERO;
+    VECTOR_ADD_LDISTRIB; VECTOR_ADD_RDISTRIB; VECTOR_MUL_ASSOC;
+    VECTOR_MUL_LZERO; VECTOR_MUL_RZERO] THENC
+  REAL_RAT_REDUCE_CONV THENC
+  PURE_SIMP_CONV[OUTER_ACI; ARITH_GT; ARITH_GE; OUTER_LMUL; OUTER_RMUL;
+                 OUTER_LZERO; OUTER_RZERO] THENC
+  PURE_REWRITE_CONV[VECTOR_MUL_LZERO; VECTOR_MUL_RZERO;
+                    VECTOR_ADD_LID; VECTOR_ADD_RID; VECTOR_MUL_ASSOC] THENC
+  GEN_REWRITE_CONV I [GSYM VECTOR_MUL_LID] THENC
+  PURE_REWRITE_CONV
+   [VECTOR_ADD_LDISTRIB; VECTOR_ADD_RDISTRIB; VECTOR_MUL_ASSOC] THENC
+  REAL_RAT_REDUCE_CONV THENC PURE_REWRITE_CONV[GSYM VECTOR_ADD_ASSOC] THENC
+  DEPTH_CONV MBASIS_MERGE_CONV THENC
+  MBASIS_GROUP_CONV THENC
+  GEN_REWRITE_CONV DEPTH_CONV [GSYM VECTOR_ADD_RDISTRIB] THENC
+  REAL_RAT_REDUCE_CONV;;
+
+(* ------------------------------------------------------------------------- *)
+(* Iterated operation in order.                                              *)
+(* I guess this ought to be added to the core...                             *)
+(* ------------------------------------------------------------------------- *)
+
+let seqiterate_EXISTS = prove
+ (`!op f. ?h.
+        !s. h s = if INFINITE s \/ s = {} then neutral op else
+                  let i = minimal x. x IN s in
+                  if s = {i} then f(i) else op (f i) (h (s DELETE i))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[INFINITE] THEN
+  MATCH_MP_TAC(MATCH_MP WF_REC (ISPEC `CARD:(num->bool)->num` WF_MEASURE)) THEN
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  LET_TAC THEN CONV_TAC(ONCE_DEPTH_CONV let_CONV) THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN AP_TERM_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[MEASURE] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[DE_MORGAN_THM]) THEN
+  SUBGOAL_THEN `?i:num. i IN s` MP_TAC THENL
+   [ASM_MESON_TAC[MEMBER_NOT_EMPTY]; ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [MINIMAL] THEN
+  ASM_SIMP_TAC[CARD_DELETE; CARD_EQ_0; ARITH_RULE `n - 1 < n <=> ~(n = 0)`]);;
+
+let EXISTS_SWAP = prove
+ (`!P. (?f. P f) <=> (?f:A->B->C. P (\b a. f a b))`,
+  GEN_TAC THEN EQ_TAC THEN DISCH_THEN CHOOSE_TAC THENL
+   [EXISTS_TAC `\a b. (f:B->A->C) b a` THEN ASM_REWRITE_TAC[ETA_AX];
+    ASM_MESON_TAC[]]);;
+
+let seqiterate = new_specification ["seqiterate"]
+ (REWRITE_RULE[SKOLEM_THM]
+   (ONCE_REWRITE_RULE[EXISTS_SWAP]
+    (ONCE_REWRITE_RULE[SKOLEM_THM] seqiterate_EXISTS)));;
+
+let MINIMAL_IN_INSERT = prove
+ (`!s i. (!j. j IN s ==> i < j) ==> (minimal j. j IN (i INSERT s)) = i`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[minimal] THEN
+  MATCH_MP_TAC SELECT_UNIQUE THEN
+  REWRITE_TAC[IN_INSERT] THEN ASM_MESON_TAC[LT_ANTISYM]);;
+
+let SEQITERATE_CLAUSES = prove
+ (`(!op f. seqiterate op {} f = neutral op) /\
+   (!op f i. seqiterate op {i} f = f(i)) /\
+   (!op f i s. FINITE s /\ ~(s = {}) /\ (!j. j IN s ==> i < j)
+               ==> seqiterate op (i INSERT s) f =
+                   op (f i) (seqiterate op s f))`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [seqiterate] THEN
+  ASM_SIMP_TAC[NOT_INSERT_EMPTY; INFINITE; FINITE_INSERT; FINITE_RULES] THEN
+  ASM_SIMP_TAC[MINIMAL_IN_INSERT; NOT_IN_EMPTY; LET_DEF; LET_END_DEF] THEN
+  SUBGOAL_THEN `~((i:num) IN s)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[LT_REFL]; ALL_TAC] THEN
+  ASM_SIMP_TAC[DELETE_INSERT; SET_RULE
+   `~(i IN s) /\ ~(s = {}) ==> (s DELETE i = s) /\ ~(i INSERT s = {i})`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In the "common" case this agrees with ordinary iteration.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let SEQITERATE_ITERATE = prove
+ (`!op f s. monoidal op /\ FINITE s ==> seqiterate op s f = iterate op s f`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN
+  MATCH_MP_TAC FINITE_INDUCT_DELETE THEN
+  ASM_SIMP_TAC[SEQITERATE_CLAUSES; ITERATE_CLAUSES] THEN
+  GEN_TAC THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  GEN_REWRITE_TAC LAND_CONV [num_WOP] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `i:num` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP (SET_RULE
+   `i IN s ==> s = i INSERT (s DELETE i)`)) THEN
+  ASM_SIMP_TAC[ITERATE_CLAUSES; FINITE_DELETE; IN_DELETE] THEN
+  ASM_CASES_TAC `s DELETE (i:num) = {}` THEN
+  ASM_SIMP_TAC[SEQITERATE_CLAUSES; ITERATE_CLAUSES] THENL
+   [ASM_MESON_TAC[monoidal]; FIRST_X_ASSUM(SUBST1_TAC o SYM)] THEN
+  MATCH_MP_TAC(last(CONJUNCTS SEQITERATE_CLAUSES)) THEN
+  ASM_REWRITE_TAC[FINITE_DELETE; IN_DELETE] THEN
+  ASM_MESON_TAC[LT_ANTISYM; LT_CASES]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Outermorphism extension.                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let outermorphism = new_definition
+ `outermorphism(f:real^N->real^P) (x:real^(N)multivector) =
+        vsum {s | s SUBSET 1..dimindex(:N)}
+             (\s. x$$s % seqiterate(outer) s (multivec o f o basis))`;;
+
+let NEUTRAL_OUTER = prove
+ (`neutral(outer) = mbasis{}`,
+  REWRITE_TAC[neutral] THEN MATCH_MP_TAC SELECT_UNIQUE THEN
+  MESON_TAC[OUTER_MBASIS_LSCALAR; OUTER_MBASIS_RSCALAR]);;
+
+let OUTERMORPHISM_MBASIS = prove
+ (`!f:real^M->real^N s t.
+        s SUBSET 1..dimindex(:M)
+        ==> outermorphism f (mbasis s) =
+            seqiterate(outer) s (multivec o f o basis)`,
+  REWRITE_TAC[outermorphism] THEN SIMP_TAC[MBASIS_COMPONENT] THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+  SIMP_TAC[VECTOR_MUL_LZERO; VSUM_DELTA; IN_ELIM_THM; VECTOR_MUL_LID]);;
+
+let OUTERMORPHISM_MBASIS_EMPTY = prove
+ (`!f. outermorphism f (mbasis {}) = mbasis {}`,
+  SIMP_TAC[OUTERMORPHISM_MBASIS; EMPTY_SUBSET; SEQITERATE_CLAUSES] THEN
+  REWRITE_TAC[NEUTRAL_OUTER]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Reversion operation.                                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let reversion = new_definition
+ `(reversion:real^(N)multivector->real^(N)multivector) x =
+    lambdas s. --(&1) pow ((CARD(s) * (CARD(s) - 1)) DIV 2) * x$$s`;;
diff --git a/Multivariate/complex_database.ml b/Multivariate/complex_database.ml
new file mode 100644 (file)
index 0000000..6f3b7a3
--- /dev/null
@@ -0,0 +1,11152 @@
+needs "help.ml";;
+
+theorems :=
+[
+"ABEL_LEMMA",ABEL_LEMMA;
+"ABEL_LIMIT_THEOREM",ABEL_LIMIT_THEOREM;
+"ABEL_POWER_SERIES_CONTINUOUS",ABEL_POWER_SERIES_CONTINUOUS;
+"ABSOLUTELY_INTEGRABLE_0",ABSOLUTELY_INTEGRABLE_0;
+"ABSOLUTELY_INTEGRABLE_ABS",ABSOLUTELY_INTEGRABLE_ABS;
+"ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_BOUND",ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_BOUND;
+"ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_LBOUND",ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_LBOUND;
+"ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_UBOUND",ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_UBOUND;
+"ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_DROP_LBOUND",ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_DROP_LBOUND;
+"ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_DROP_UBOUND",ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_DROP_UBOUND;
+"ABSOLUTELY_INTEGRABLE_ABS_1",ABSOLUTELY_INTEGRABLE_ABS_1;
+"ABSOLUTELY_INTEGRABLE_ABS_EQ",ABSOLUTELY_INTEGRABLE_ABS_EQ;
+"ABSOLUTELY_INTEGRABLE_ADD",ABSOLUTELY_INTEGRABLE_ADD;
+"ABSOLUTELY_INTEGRABLE_APPROXIMATE_CONTINUOUS",ABSOLUTELY_INTEGRABLE_APPROXIMATE_CONTINUOUS;
+"ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION",ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION;
+"ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION_EQ",ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION_EQ;
+"ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION_UNIV_EQ",ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION_UNIV_EQ;
+"ABSOLUTELY_INTEGRABLE_CMUL",ABSOLUTELY_INTEGRABLE_CMUL;
+"ABSOLUTELY_INTEGRABLE_COMPONENTWISE",ABSOLUTELY_INTEGRABLE_COMPONENTWISE;
+"ABSOLUTELY_INTEGRABLE_CONST",ABSOLUTELY_INTEGRABLE_CONST;
+"ABSOLUTELY_INTEGRABLE_CONTINUOUS",ABSOLUTELY_INTEGRABLE_CONTINUOUS;
+"ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE",ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE;
+"ABSOLUTELY_INTEGRABLE_INF_1",ABSOLUTELY_INTEGRABLE_INF_1;
+"ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND",ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND;
+"ABSOLUTELY_INTEGRABLE_LE",ABSOLUTELY_INTEGRABLE_LE;
+"ABSOLUTELY_INTEGRABLE_LEBESGUE_POINTS",ABSOLUTELY_INTEGRABLE_LEBESGUE_POINTS;
+"ABSOLUTELY_INTEGRABLE_LINEAR",ABSOLUTELY_INTEGRABLE_LINEAR;
+"ABSOLUTELY_INTEGRABLE_MAX",ABSOLUTELY_INTEGRABLE_MAX;
+"ABSOLUTELY_INTEGRABLE_MAX_1",ABSOLUTELY_INTEGRABLE_MAX_1;
+"ABSOLUTELY_INTEGRABLE_MEASURABLE",ABSOLUTELY_INTEGRABLE_MEASURABLE;
+"ABSOLUTELY_INTEGRABLE_MIN",ABSOLUTELY_INTEGRABLE_MIN;
+"ABSOLUTELY_INTEGRABLE_MIN_1",ABSOLUTELY_INTEGRABLE_MIN_1;
+"ABSOLUTELY_INTEGRABLE_NEG",ABSOLUTELY_INTEGRABLE_NEG;
+"ABSOLUTELY_INTEGRABLE_NORM",ABSOLUTELY_INTEGRABLE_NORM;
+"ABSOLUTELY_INTEGRABLE_ON_CONST",ABSOLUTELY_INTEGRABLE_ON_CONST;
+"ABSOLUTELY_INTEGRABLE_ON_SUBINTERVAL",ABSOLUTELY_INTEGRABLE_ON_SUBINTERVAL;
+"ABSOLUTELY_INTEGRABLE_RESTRICT_UNIV",ABSOLUTELY_INTEGRABLE_RESTRICT_UNIV;
+"ABSOLUTELY_INTEGRABLE_SET_VARIATION",ABSOLUTELY_INTEGRABLE_SET_VARIATION;
+"ABSOLUTELY_INTEGRABLE_SUB",ABSOLUTELY_INTEGRABLE_SUB;
+"ABSOLUTELY_INTEGRABLE_SUP_1",ABSOLUTELY_INTEGRABLE_SUP_1;
+"ABSOLUTELY_INTEGRABLE_VSUM",ABSOLUTELY_INTEGRABLE_VSUM;
+"ABSOLUTELY_REAL_INTEGRABLE_0",ABSOLUTELY_REAL_INTEGRABLE_0;
+"ABSOLUTELY_REAL_INTEGRABLE_ABS",ABSOLUTELY_REAL_INTEGRABLE_ABS;
+"ABSOLUTELY_REAL_INTEGRABLE_ABSOLUTELY_REAL_INTEGRABLE_BOUND",ABSOLUTELY_REAL_INTEGRABLE_ABSOLUTELY_REAL_INTEGRABLE_BOUND;
+"ABSOLUTELY_REAL_INTEGRABLE_ABSOLUTELY_REAL_INTEGRABLE_LBOUND",ABSOLUTELY_REAL_INTEGRABLE_ABSOLUTELY_REAL_INTEGRABLE_LBOUND;
+"ABSOLUTELY_REAL_INTEGRABLE_ABSOLUTELY_REAL_INTEGRABLE_UBOUND",ABSOLUTELY_REAL_INTEGRABLE_ABSOLUTELY_REAL_INTEGRABLE_UBOUND;
+"ABSOLUTELY_REAL_INTEGRABLE_ADD",ABSOLUTELY_REAL_INTEGRABLE_ADD;
+"ABSOLUTELY_REAL_INTEGRABLE_BOUNDED_MEASURABLE_PRODUCT",ABSOLUTELY_REAL_INTEGRABLE_BOUNDED_MEASURABLE_PRODUCT;
+"ABSOLUTELY_REAL_INTEGRABLE_CONST",ABSOLUTELY_REAL_INTEGRABLE_CONST;
+"ABSOLUTELY_REAL_INTEGRABLE_CONTINUOUS",ABSOLUTELY_REAL_INTEGRABLE_CONTINUOUS;
+"ABSOLUTELY_REAL_INTEGRABLE_DECREASING",ABSOLUTELY_REAL_INTEGRABLE_DECREASING;
+"ABSOLUTELY_REAL_INTEGRABLE_DECREASING_PRODUCT",ABSOLUTELY_REAL_INTEGRABLE_DECREASING_PRODUCT;
+"ABSOLUTELY_REAL_INTEGRABLE_IMP_INTEGRABLE",ABSOLUTELY_REAL_INTEGRABLE_IMP_INTEGRABLE;
+"ABSOLUTELY_REAL_INTEGRABLE_INCREASING",ABSOLUTELY_REAL_INTEGRABLE_INCREASING;
+"ABSOLUTELY_REAL_INTEGRABLE_INCREASING_PRODUCT",ABSOLUTELY_REAL_INTEGRABLE_INCREASING_PRODUCT;
+"ABSOLUTELY_REAL_INTEGRABLE_INF",ABSOLUTELY_REAL_INTEGRABLE_INF;
+"ABSOLUTELY_REAL_INTEGRABLE_INTEGRABLE_BOUND",ABSOLUTELY_REAL_INTEGRABLE_INTEGRABLE_BOUND;
+"ABSOLUTELY_REAL_INTEGRABLE_LE",ABSOLUTELY_REAL_INTEGRABLE_LE;
+"ABSOLUTELY_REAL_INTEGRABLE_LINEAR",ABSOLUTELY_REAL_INTEGRABLE_LINEAR;
+"ABSOLUTELY_REAL_INTEGRABLE_LMUL",ABSOLUTELY_REAL_INTEGRABLE_LMUL;
+"ABSOLUTELY_REAL_INTEGRABLE_MAX",ABSOLUTELY_REAL_INTEGRABLE_MAX;
+"ABSOLUTELY_REAL_INTEGRABLE_MIN",ABSOLUTELY_REAL_INTEGRABLE_MIN;
+"ABSOLUTELY_REAL_INTEGRABLE_NEG",ABSOLUTELY_REAL_INTEGRABLE_NEG;
+"ABSOLUTELY_REAL_INTEGRABLE_ON",ABSOLUTELY_REAL_INTEGRABLE_ON;
+"ABSOLUTELY_REAL_INTEGRABLE_ON_SUBINTERVAL",ABSOLUTELY_REAL_INTEGRABLE_ON_SUBINTERVAL;
+"ABSOLUTELY_REAL_INTEGRABLE_REAL_MEASURABLE",ABSOLUTELY_REAL_INTEGRABLE_REAL_MEASURABLE;
+"ABSOLUTELY_REAL_INTEGRABLE_RESTRICT_UNIV",ABSOLUTELY_REAL_INTEGRABLE_RESTRICT_UNIV;
+"ABSOLUTELY_REAL_INTEGRABLE_RMUL",ABSOLUTELY_REAL_INTEGRABLE_RMUL;
+"ABSOLUTELY_REAL_INTEGRABLE_SUB",ABSOLUTELY_REAL_INTEGRABLE_SUB;
+"ABSOLUTELY_REAL_INTEGRABLE_SUM",ABSOLUTELY_REAL_INTEGRABLE_SUM;
+"ABSOLUTELY_REAL_INTEGRABLE_SUP",ABSOLUTELY_REAL_INTEGRABLE_SUP;
+"ABSOLUTE_RETRACTION_CONVEX_CLOSED",ABSOLUTE_RETRACTION_CONVEX_CLOSED;
+"ABSOLUTE_RETRACTION_CONVEX_CLOSED_RELATIVE",ABSOLUTE_RETRACTION_CONVEX_CLOSED_RELATIVE;
+"ABSOLUTE_RETRACT_CONTRACTIBLE_ANR",ABSOLUTE_RETRACT_CONTRACTIBLE_ANR;
+"ABSOLUTE_RETRACT_CONVEX_CLOSED",ABSOLUTE_RETRACT_CONVEX_CLOSED;
+"ABSOLUTE_RETRACT_HOMEOMORPHIC_CONVEX_COMPACT",ABSOLUTE_RETRACT_HOMEOMORPHIC_CONVEX_COMPACT;
+"ABSOLUTE_RETRACT_IMP_AR",ABSOLUTE_RETRACT_IMP_AR;
+"ABSOLUTE_RETRACT_IMP_AR_GEN",ABSOLUTE_RETRACT_IMP_AR_GEN;
+"ABSOLUTE_RETRACT_PATH_IMAGE_ARC",ABSOLUTE_RETRACT_PATH_IMAGE_ARC;
+"ABSORPTION",ABSORPTION;
+"ABS_DROP",ABS_DROP;
+"ABS_SIMP",ABS_SIMP;
+"ABS_SQUARE_EQ_1",ABS_SQUARE_EQ_1;
+"ABS_SQUARE_LE_1",ABS_SQUARE_LE_1;
+"ABS_SQUARE_LT_1",ABS_SQUARE_LT_1;
+"ACS_0",ACS_0;
+"ACS_1",ACS_1;
+"ACS_ASN",ACS_ASN;
+"ACS_ASN_SQRT_NEG",ACS_ASN_SQRT_NEG;
+"ACS_ASN_SQRT_POS",ACS_ASN_SQRT_POS;
+"ACS_ATN",ACS_ATN;
+"ACS_BOUNDS",ACS_BOUNDS;
+"ACS_BOUNDS_LT",ACS_BOUNDS_LT;
+"ACS_COS",ACS_COS;
+"ACS_INJ",ACS_INJ;
+"ACS_MONO_LE",ACS_MONO_LE;
+"ACS_MONO_LE_EQ",ACS_MONO_LE_EQ;
+"ACS_MONO_LT",ACS_MONO_LT;
+"ACS_MONO_LT_EQ",ACS_MONO_LT_EQ;
+"ACS_NEG",ACS_NEG;
+"ACS_NEG_1",ACS_NEG_1;
+"ADD",ADD;
+"ADD1",ADD1;
+"ADDITIVE_CONTENT_DIVISION",ADDITIVE_CONTENT_DIVISION;
+"ADDITIVE_CONTENT_TAGGED_DIVISION",ADDITIVE_CONTENT_TAGGED_DIVISION;
+"ADDITIVE_TAGGED_DIVISION_1",ADDITIVE_TAGGED_DIVISION_1;
+"ADD_0",ADD_0;
+"ADD_AC",ADD_AC;
+"ADD_ASSOC",ADD_ASSOC;
+"ADD_CLAUSES",ADD_CLAUSES;
+"ADD_EQ_0",ADD_EQ_0;
+"ADD_SUB",ADD_SUB;
+"ADD_SUB2",ADD_SUB2;
+"ADD_SUBR",ADD_SUBR;
+"ADD_SUBR2",ADD_SUBR2;
+"ADD_SUC",ADD_SUC;
+"ADD_SYM",ADD_SYM;
+"ADJOINT_ADJOINT",ADJOINT_ADJOINT;
+"ADJOINT_CLAUSES",ADJOINT_CLAUSES;
+"ADJOINT_COMPOSE",ADJOINT_COMPOSE;
+"ADJOINT_INJECTIVE",ADJOINT_INJECTIVE;
+"ADJOINT_INJECTIVE_INJECTIVE",ADJOINT_INJECTIVE_INJECTIVE;
+"ADJOINT_INJECTIVE_INJECTIVE_0",ADJOINT_INJECTIVE_INJECTIVE_0;
+"ADJOINT_LINEAR",ADJOINT_LINEAR;
+"ADJOINT_MATRIX",ADJOINT_MATRIX;
+"ADJOINT_SURJECTIVE",ADJOINT_SURJECTIVE;
+"ADJOINT_UNIQUE",ADJOINT_UNIQUE;
+"ADJOINT_WORKS",ADJOINT_WORKS;
+"ADMISSIBLE_BASE",ADMISSIBLE_BASE;
+"ADMISSIBLE_COMB",ADMISSIBLE_COMB;
+"ADMISSIBLE_COND",ADMISSIBLE_COND;
+"ADMISSIBLE_CONST",ADMISSIBLE_CONST;
+"ADMISSIBLE_GUARDED_PATTERN",ADMISSIBLE_GUARDED_PATTERN;
+"ADMISSIBLE_IMP_SUPERADMISSIBLE",ADMISSIBLE_IMP_SUPERADMISSIBLE;
+"ADMISSIBLE_LAMBDA",ADMISSIBLE_LAMBDA;
+"ADMISSIBLE_MAP",ADMISSIBLE_MAP;
+"ADMISSIBLE_MATCH",ADMISSIBLE_MATCH;
+"ADMISSIBLE_MATCH_SEQPATTERN",ADMISSIBLE_MATCH_SEQPATTERN;
+"ADMISSIBLE_NEST",ADMISSIBLE_NEST;
+"ADMISSIBLE_NSUM",ADMISSIBLE_NSUM;
+"ADMISSIBLE_RAND",ADMISSIBLE_RAND;
+"ADMISSIBLE_SEQPATTERN",ADMISSIBLE_SEQPATTERN;
+"ADMISSIBLE_SUM",ADMISSIBLE_SUM;
+"ADMISSIBLE_UNGUARDED_PATTERN",ADMISSIBLE_UNGUARDED_PATTERN;
+"AFFINE",AFFINE;
+"AFFINE_AFFINE_HULL",AFFINE_AFFINE_HULL;
+"AFFINE_AFFINITY",AFFINE_AFFINITY;
+"AFFINE_ALT",AFFINE_ALT;
+"AFFINE_BASIS_EXISTS",AFFINE_BASIS_EXISTS;
+"AFFINE_BOUNDED_EQ_LOWDIM",AFFINE_BOUNDED_EQ_LOWDIM;
+"AFFINE_BOUNDED_EQ_TRIVIAL",AFFINE_BOUNDED_EQ_TRIVIAL;
+"AFFINE_DEPENDENT_BIGGERSET",AFFINE_DEPENDENT_BIGGERSET;
+"AFFINE_DEPENDENT_BIGGERSET_GENERAL",AFFINE_DEPENDENT_BIGGERSET_GENERAL;
+"AFFINE_DEPENDENT_CHOOSE",AFFINE_DEPENDENT_CHOOSE;
+"AFFINE_DEPENDENT_EXPLICIT",AFFINE_DEPENDENT_EXPLICIT;
+"AFFINE_DEPENDENT_EXPLICIT_FINITE",AFFINE_DEPENDENT_EXPLICIT_FINITE;
+"AFFINE_DEPENDENT_IMP_COLLINEAR_3",AFFINE_DEPENDENT_IMP_COLLINEAR_3;
+"AFFINE_DEPENDENT_IMP_DEPENDENT",AFFINE_DEPENDENT_IMP_DEPENDENT;
+"AFFINE_DEPENDENT_LINEAR_IMAGE",AFFINE_DEPENDENT_LINEAR_IMAGE;
+"AFFINE_DEPENDENT_LINEAR_IMAGE_EQ",AFFINE_DEPENDENT_LINEAR_IMAGE_EQ;
+"AFFINE_DEPENDENT_MONO",AFFINE_DEPENDENT_MONO;
+"AFFINE_DEPENDENT_TRANSLATION",AFFINE_DEPENDENT_TRANSLATION;
+"AFFINE_DEPENDENT_TRANSLATION_EQ",AFFINE_DEPENDENT_TRANSLATION_EQ;
+"AFFINE_DIFFERENCES",AFFINE_DIFFERENCES;
+"AFFINE_DIFFS_SUBSPACE",AFFINE_DIFFS_SUBSPACE;
+"AFFINE_EMPTY",AFFINE_EMPTY;
+"AFFINE_EQ_SUBSPACE",AFFINE_EQ_SUBSPACE;
+"AFFINE_EXPLICIT",AFFINE_EXPLICIT;
+"AFFINE_HULLS_EQ",AFFINE_HULLS_EQ;
+"AFFINE_HULL_2",AFFINE_HULL_2;
+"AFFINE_HULL_2_ALT",AFFINE_HULL_2_ALT;
+"AFFINE_HULL_3",AFFINE_HULL_3;
+"AFFINE_HULL_3_IMP_COLLINEAR",AFFINE_HULL_3_IMP_COLLINEAR;
+"AFFINE_HULL_AFFINE_INTER_NONEMPTY_INTERIOR",AFFINE_HULL_AFFINE_INTER_NONEMPTY_INTERIOR;
+"AFFINE_HULL_AFFINE_INTER_OPEN",AFFINE_HULL_AFFINE_INTER_OPEN;
+"AFFINE_HULL_AFFINE_INTER_OPEN_IN",AFFINE_HULL_AFFINE_INTER_OPEN_IN;
+"AFFINE_HULL_CLOSURE",AFFINE_HULL_CLOSURE;
+"AFFINE_HULL_CONVEX_HULL",AFFINE_HULL_CONVEX_HULL;
+"AFFINE_HULL_CONVEX_INTER_NONEMPTY_INTERIOR",AFFINE_HULL_CONVEX_INTER_NONEMPTY_INTERIOR;
+"AFFINE_HULL_CONVEX_INTER_OPEN",AFFINE_HULL_CONVEX_INTER_OPEN;
+"AFFINE_HULL_CONVEX_INTER_OPEN_IN",AFFINE_HULL_CONVEX_INTER_OPEN_IN;
+"AFFINE_HULL_EMPTY",AFFINE_HULL_EMPTY;
+"AFFINE_HULL_EQ",AFFINE_HULL_EQ;
+"AFFINE_HULL_EQ_EMPTY",AFFINE_HULL_EQ_EMPTY;
+"AFFINE_HULL_EQ_SING",AFFINE_HULL_EQ_SING;
+"AFFINE_HULL_EQ_SPAN",AFFINE_HULL_EQ_SPAN;
+"AFFINE_HULL_EQ_SPAN_EQ",AFFINE_HULL_EQ_SPAN_EQ;
+"AFFINE_HULL_EXPLICIT",AFFINE_HULL_EXPLICIT;
+"AFFINE_HULL_EXPLICIT_ALT",AFFINE_HULL_EXPLICIT_ALT;
+"AFFINE_HULL_EXPLICIT_UNIQUE",AFFINE_HULL_EXPLICIT_UNIQUE;
+"AFFINE_HULL_FACE_OF_DISJOINT_RELATIVE_INTERIOR",AFFINE_HULL_FACE_OF_DISJOINT_RELATIVE_INTERIOR;
+"AFFINE_HULL_FINITE",AFFINE_HULL_FINITE;
+"AFFINE_HULL_FINITE_INTERSECTION_HYPERPLANES",AFFINE_HULL_FINITE_INTERSECTION_HYPERPLANES;
+"AFFINE_HULL_FINITE_STEP",AFFINE_HULL_FINITE_STEP;
+"AFFINE_HULL_FINITE_STEP_GEN",AFFINE_HULL_FINITE_STEP_GEN;
+"AFFINE_HULL_HALFSPACE_GE",AFFINE_HULL_HALFSPACE_GE;
+"AFFINE_HULL_HALFSPACE_GT",AFFINE_HULL_HALFSPACE_GT;
+"AFFINE_HULL_HALFSPACE_LE",AFFINE_HULL_HALFSPACE_LE;
+"AFFINE_HULL_HALFSPACE_LT",AFFINE_HULL_HALFSPACE_LT;
+"AFFINE_HULL_INDEXED",AFFINE_HULL_INDEXED;
+"AFFINE_HULL_INSERT_SPAN",AFFINE_HULL_INSERT_SPAN;
+"AFFINE_HULL_INSERT_SUBSET_SPAN",AFFINE_HULL_INSERT_SUBSET_SPAN;
+"AFFINE_HULL_INTER",AFFINE_HULL_INTER;
+"AFFINE_HULL_INTERS",AFFINE_HULL_INTERS;
+"AFFINE_HULL_LINEAR_IMAGE",AFFINE_HULL_LINEAR_IMAGE;
+"AFFINE_HULL_NONEMPTY_INTERIOR",AFFINE_HULL_NONEMPTY_INTERIOR;
+"AFFINE_HULL_OPEN",AFFINE_HULL_OPEN;
+"AFFINE_HULL_OPEN_IN",AFFINE_HULL_OPEN_IN;
+"AFFINE_HULL_PCROSS",AFFINE_HULL_PCROSS;
+"AFFINE_HULL_RELATIVE_INTERIOR",AFFINE_HULL_RELATIVE_INTERIOR;
+"AFFINE_HULL_SEGMENT",AFFINE_HULL_SEGMENT;
+"AFFINE_HULL_SING",AFFINE_HULL_SING;
+"AFFINE_HULL_SPAN",AFFINE_HULL_SPAN;
+"AFFINE_HULL_SUBSET_SPAN",AFFINE_HULL_SUBSET_SPAN;
+"AFFINE_HULL_TRANSLATION",AFFINE_HULL_TRANSLATION;
+"AFFINE_HULL_UNIV",AFFINE_HULL_UNIV;
+"AFFINE_HYPERPLANE",AFFINE_HYPERPLANE;
+"AFFINE_HYPERPLANE_SUMS_EQ_UNIV",AFFINE_HYPERPLANE_SUMS_EQ_UNIV;
+"AFFINE_IMP_CONVEX",AFFINE_IMP_CONVEX;
+"AFFINE_IMP_POLYHEDRON",AFFINE_IMP_POLYHEDRON;
+"AFFINE_IMP_SUBSPACE",AFFINE_IMP_SUBSPACE;
+"AFFINE_INDEPENDENT_1",AFFINE_INDEPENDENT_1;
+"AFFINE_INDEPENDENT_2",AFFINE_INDEPENDENT_2;
+"AFFINE_INDEPENDENT_CARD_DIM_DIFFS",AFFINE_INDEPENDENT_CARD_DIM_DIFFS;
+"AFFINE_INDEPENDENT_CARD_LE",AFFINE_INDEPENDENT_CARD_LE;
+"AFFINE_INDEPENDENT_CONVEX_AFFINE_HULL",AFFINE_INDEPENDENT_CONVEX_AFFINE_HULL;
+"AFFINE_INDEPENDENT_DELETE",AFFINE_INDEPENDENT_DELETE;
+"AFFINE_INDEPENDENT_EMPTY",AFFINE_INDEPENDENT_EMPTY;
+"AFFINE_INDEPENDENT_IFF_CARD",AFFINE_INDEPENDENT_IFF_CARD;
+"AFFINE_INDEPENDENT_IMP_FINITE",AFFINE_INDEPENDENT_IMP_FINITE;
+"AFFINE_INDEPENDENT_INSERT",AFFINE_INDEPENDENT_INSERT;
+"AFFINE_INDEPENDENT_SPAN_EQ",AFFINE_INDEPENDENT_SPAN_EQ;
+"AFFINE_INDEPENDENT_SPAN_GT",AFFINE_INDEPENDENT_SPAN_GT;
+"AFFINE_INDEPENDENT_STDBASIS",AFFINE_INDEPENDENT_STDBASIS;
+"AFFINE_INDEPENDENT_SUBSET",AFFINE_INDEPENDENT_SUBSET;
+"AFFINE_INDEXED",AFFINE_INDEXED;
+"AFFINE_INTER",AFFINE_INTER;
+"AFFINE_INTERS",AFFINE_INTERS;
+"AFFINE_LINEAR_IMAGE",AFFINE_LINEAR_IMAGE;
+"AFFINE_LINEAR_IMAGE_EQ",AFFINE_LINEAR_IMAGE_EQ;
+"AFFINE_NEGATIONS",AFFINE_NEGATIONS;
+"AFFINE_PARALLEL_SLICE",AFFINE_PARALLEL_SLICE;
+"AFFINE_PCROSS",AFFINE_PCROSS;
+"AFFINE_PCROSS_EQ",AFFINE_PCROSS_EQ;
+"AFFINE_SCALING",AFFINE_SCALING;
+"AFFINE_SCALING_EQ",AFFINE_SCALING_EQ;
+"AFFINE_SING",AFFINE_SING;
+"AFFINE_SPAN",AFFINE_SPAN;
+"AFFINE_STANDARD_HYPERPLANE",AFFINE_STANDARD_HYPERPLANE;
+"AFFINE_SUMS",AFFINE_SUMS;
+"AFFINE_TRANSLATION",AFFINE_TRANSLATION;
+"AFFINE_TRANSLATION_EQ",AFFINE_TRANSLATION_EQ;
+"AFFINE_TRANSLATION_SUBSPACE",AFFINE_TRANSLATION_SUBSPACE;
+"AFFINE_TRANSLATION_SUBSPACE_EXPLICIT",AFFINE_TRANSLATION_SUBSPACE_EXPLICIT;
+"AFFINE_TRANSLATION_UNIQUE_SUBSPACE",AFFINE_TRANSLATION_UNIQUE_SUBSPACE;
+"AFFINE_UNIV",AFFINE_UNIV;
+"AFFINE_VSUM",AFFINE_VSUM;
+"AFFINITY_INVERSES",AFFINITY_INVERSES;
+"AFF_DIM",AFF_DIM;
+"AFF_DIM_2",AFF_DIM_2;
+"AFF_DIM_AFFINE_HULL",AFF_DIM_AFFINE_HULL;
+"AFF_DIM_AFFINE_INDEPENDENT",AFF_DIM_AFFINE_INDEPENDENT;
+"AFF_DIM_AFFINE_INTER_HYPERPLANE",AFF_DIM_AFFINE_INTER_HYPERPLANE;
+"AFF_DIM_BALL",AFF_DIM_BALL;
+"AFF_DIM_CBALL",AFF_DIM_CBALL;
+"AFF_DIM_CLOSURE",AFF_DIM_CLOSURE;
+"AFF_DIM_CONVEX_HULL",AFF_DIM_CONVEX_HULL;
+"AFF_DIM_CONVEX_INTER_NONEMPTY_INTERIOR",AFF_DIM_CONVEX_INTER_NONEMPTY_INTERIOR;
+"AFF_DIM_CONVEX_INTER_OPEN",AFF_DIM_CONVEX_INTER_OPEN;
+"AFF_DIM_DIM_0",AFF_DIM_DIM_0;
+"AFF_DIM_DIM_AFFINE_DIFFS",AFF_DIM_DIM_AFFINE_DIFFS;
+"AFF_DIM_DIM_SUBSPACE",AFF_DIM_DIM_SUBSPACE;
+"AFF_DIM_EMPTY",AFF_DIM_EMPTY;
+"AFF_DIM_EQ_0",AFF_DIM_EQ_0;
+"AFF_DIM_EQ_AFFINE_HULL",AFF_DIM_EQ_AFFINE_HULL;
+"AFF_DIM_EQ_FULL",AFF_DIM_EQ_FULL;
+"AFF_DIM_EQ_HYPERPLANE",AFF_DIM_EQ_HYPERPLANE;
+"AFF_DIM_EQ_MINUS1",AFF_DIM_EQ_MINUS1;
+"AFF_DIM_GE",AFF_DIM_GE;
+"AFF_DIM_HALFSPACE_GE",AFF_DIM_HALFSPACE_GE;
+"AFF_DIM_HALFSPACE_GT",AFF_DIM_HALFSPACE_GT;
+"AFF_DIM_HALFSPACE_LE",AFF_DIM_HALFSPACE_LE;
+"AFF_DIM_HALFSPACE_LT",AFF_DIM_HALFSPACE_LT;
+"AFF_DIM_HYPERPLANE",AFF_DIM_HYPERPLANE;
+"AFF_DIM_INJECTIVE_LINEAR_IMAGE",AFF_DIM_INJECTIVE_LINEAR_IMAGE;
+"AFF_DIM_INSERT",AFF_DIM_INSERT;
+"AFF_DIM_INTERVAL",AFF_DIM_INTERVAL;
+"AFF_DIM_LE_CARD",AFF_DIM_LE_CARD;
+"AFF_DIM_LE_DIM",AFF_DIM_LE_DIM;
+"AFF_DIM_LE_UNIV",AFF_DIM_LE_UNIV;
+"AFF_DIM_LINEAR_IMAGE_LE",AFF_DIM_LINEAR_IMAGE_LE;
+"AFF_DIM_LT_FULL",AFF_DIM_LT_FULL;
+"AFF_DIM_NONEMPTY_INTERIOR",AFF_DIM_NONEMPTY_INTERIOR;
+"AFF_DIM_NONEMPTY_INTERIOR_EQ",AFF_DIM_NONEMPTY_INTERIOR_EQ;
+"AFF_DIM_OPEN",AFF_DIM_OPEN;
+"AFF_DIM_OPEN_IN",AFF_DIM_OPEN_IN;
+"AFF_DIM_POS_LE",AFF_DIM_POS_LE;
+"AFF_DIM_PSUBSET",AFF_DIM_PSUBSET;
+"AFF_DIM_SIMPLEX",AFF_DIM_SIMPLEX;
+"AFF_DIM_SING",AFF_DIM_SING;
+"AFF_DIM_SUBSET",AFF_DIM_SUBSET;
+"AFF_DIM_SUMS_INTER",AFF_DIM_SUMS_INTER;
+"AFF_DIM_TRANSLATION_EQ",AFF_DIM_TRANSLATION_EQ;
+"AFF_DIM_UNIQUE",AFF_DIM_UNIQUE;
+"AFF_DIM_UNIV",AFF_DIM_UNIV;
+"AFF_LOWDIM_SUBSET_HYPERPLANE",AFF_LOWDIM_SUBSET_HYPERPLANE;
+"ALL",ALL;
+"ALL2",ALL2;
+"ALL2_ALL",ALL2_ALL;
+"ALL2_AND_RIGHT",ALL2_AND_RIGHT;
+"ALL2_DEF",ALL2_DEF;
+"ALL2_MAP",ALL2_MAP;
+"ALL2_MAP2",ALL2_MAP2;
+"ALL_APPEND",ALL_APPEND;
+"ALL_EL",ALL_EL;
+"ALL_FILTER",ALL_FILTER;
+"ALL_IMP",ALL_IMP;
+"ALL_MAP",ALL_MAP;
+"ALL_MEM",ALL_MEM;
+"ALL_MP",ALL_MP;
+"ALL_T",ALL_T;
+"ALWAYS_EVENTUALLY",ALWAYS_EVENTUALLY;
+"ANALYTIC_AT",ANALYTIC_AT;
+"ANALYTIC_AT_ADD",ANALYTIC_AT_ADD;
+"ANALYTIC_AT_BALL",ANALYTIC_AT_BALL;
+"ANALYTIC_AT_MUL",ANALYTIC_AT_MUL;
+"ANALYTIC_AT_POW",ANALYTIC_AT_POW;
+"ANALYTIC_AT_SUB",ANALYTIC_AT_SUB;
+"ANALYTIC_AT_TWO",ANALYTIC_AT_TWO;
+"ANALYTIC_COMPLEX_DERIVATIVE",ANALYTIC_COMPLEX_DERIVATIVE;
+"ANALYTIC_CONTINUATION",ANALYTIC_CONTINUATION;
+"ANALYTIC_HIGHER_COMPLEX_DERIVATIVE",ANALYTIC_HIGHER_COMPLEX_DERIVATIVE;
+"ANALYTIC_IFF_POWER_SERIES",ANALYTIC_IFF_POWER_SERIES;
+"ANALYTIC_IMP_HOLOMORPHIC",ANALYTIC_IMP_HOLOMORPHIC;
+"ANALYTIC_ON_ADD",ANALYTIC_ON_ADD;
+"ANALYTIC_ON_ANALYTIC_AT",ANALYTIC_ON_ANALYTIC_AT;
+"ANALYTIC_ON_COMPOSE",ANALYTIC_ON_COMPOSE;
+"ANALYTIC_ON_COMPOSE_GEN",ANALYTIC_ON_COMPOSE_GEN;
+"ANALYTIC_ON_CONST",ANALYTIC_ON_CONST;
+"ANALYTIC_ON_DIV",ANALYTIC_ON_DIV;
+"ANALYTIC_ON_HOLOMORPHIC",ANALYTIC_ON_HOLOMORPHIC;
+"ANALYTIC_ON_ID",ANALYTIC_ON_ID;
+"ANALYTIC_ON_IMP_DIFFERENTIABLE_AT",ANALYTIC_ON_IMP_DIFFERENTIABLE_AT;
+"ANALYTIC_ON_INV",ANALYTIC_ON_INV;
+"ANALYTIC_ON_LINEAR",ANALYTIC_ON_LINEAR;
+"ANALYTIC_ON_MUL",ANALYTIC_ON_MUL;
+"ANALYTIC_ON_NEG",ANALYTIC_ON_NEG;
+"ANALYTIC_ON_OPEN",ANALYTIC_ON_OPEN;
+"ANALYTIC_ON_POW",ANALYTIC_ON_POW;
+"ANALYTIC_ON_SUB",ANALYTIC_ON_SUB;
+"ANALYTIC_ON_SUBSET",ANALYTIC_ON_SUBSET;
+"ANALYTIC_ON_UNION",ANALYTIC_ON_UNION;
+"ANALYTIC_ON_UNIONS",ANALYTIC_ON_UNIONS;
+"ANALYTIC_ON_VSUM",ANALYTIC_ON_VSUM;
+"AND_ALL",AND_ALL;
+"AND_ALL2",AND_ALL2;
+"AND_CLAUSES",AND_CLAUSES;
+"AND_DEF",AND_DEF;
+"AND_FORALL_THM",AND_FORALL_THM;
+"ANR_PATH_IMAGE_SIMPLE_PATH",ANR_PATH_IMAGE_SIMPLE_PATH;
+"ANR_RELATIVE_FRONTIER_CONVEX",ANR_RELATIVE_FRONTIER_CONVEX;
+"ANTIDERIVATIVE_CONTINUOUS",ANTIDERIVATIVE_CONTINUOUS;
+"ANTIDERIVATIVE_INTEGRAL_CONTINUOUS",ANTIDERIVATIVE_INTEGRAL_CONTINUOUS;
+"ANY_CLOSEST_POINT_AFFINE_ORTHOGONAL",ANY_CLOSEST_POINT_AFFINE_ORTHOGONAL;
+"ANY_CLOSEST_POINT_DOT",ANY_CLOSEST_POINT_DOT;
+"ANY_CLOSEST_POINT_UNIQUE",ANY_CLOSEST_POINT_UNIQUE;
+"APPEND",APPEND;
+"APPEND_ASSOC",APPEND_ASSOC;
+"APPEND_BUTLAST_LAST",APPEND_BUTLAST_LAST;
+"APPEND_EQ_NIL",APPEND_EQ_NIL;
+"APPEND_NIL",APPEND_NIL;
+"APPEND_SING",APPEND_SING;
+"APPROACHABLE_LT_LE",APPROACHABLE_LT_LE;
+"APPROXIMABLE_ON_DIVISION",APPROXIMABLE_ON_DIVISION;
+"ARC_ASSOC",ARC_ASSOC;
+"ARC_CONNECTED_TRANS",ARC_CONNECTED_TRANS;
+"ARC_DISTINCT_ENDS",ARC_DISTINCT_ENDS;
+"ARC_IMP_PATH",ARC_IMP_PATH;
+"ARC_IMP_SIMPLE_PATH",ARC_IMP_SIMPLE_PATH;
+"ARC_JOIN",ARC_JOIN;
+"ARC_JOIN_EQ",ARC_JOIN_EQ;
+"ARC_JOIN_EQ_ALT",ARC_JOIN_EQ_ALT;
+"ARC_LINEAR_IMAGE_EQ",ARC_LINEAR_IMAGE_EQ;
+"ARC_LINEPATH",ARC_LINEPATH;
+"ARC_LINEPATH_EQ",ARC_LINEPATH_EQ;
+"ARC_PARTCIRCLEPATH",ARC_PARTCIRCLEPATH;
+"ARC_REVERSEPATH",ARC_REVERSEPATH;
+"ARC_SIMPLE_PATH",ARC_SIMPLE_PATH;
+"ARC_SIMPLE_PATH_SUBPATH",ARC_SIMPLE_PATH_SUBPATH;
+"ARC_SIMPLE_PATH_SUBPATH_INTERIOR",ARC_SIMPLE_PATH_SUBPATH_INTERIOR;
+"ARC_SUBPATH_ARC",ARC_SUBPATH_ARC;
+"ARC_SUBPATH_EQ",ARC_SUBPATH_EQ;
+"ARC_TRANSLATION_EQ",ARC_TRANSLATION_EQ;
+"ARG",ARG;
+"ARG_0",ARG_0;
+"ARG_ATAN_UPPERHALF",ARG_ATAN_UPPERHALF;
+"ARG_CEXP",ARG_CEXP;
+"ARG_CLOG",ARG_CLOG;
+"ARG_CNJ",ARG_CNJ;
+"ARG_DIV_CX",ARG_DIV_CX;
+"ARG_EQ",ARG_EQ;
+"ARG_EQ_0",ARG_EQ_0;
+"ARG_EQ_0_PI",ARG_EQ_0_PI;
+"ARG_EQ_PI",ARG_EQ_PI;
+"ARG_INV",ARG_INV;
+"ARG_INV_EQ_0",ARG_INV_EQ_0;
+"ARG_LE_DIV_SUM",ARG_LE_DIV_SUM;
+"ARG_LE_DIV_SUM_EQ",ARG_LE_DIV_SUM_EQ;
+"ARG_LE_PI",ARG_LE_PI;
+"ARG_LT_NZ",ARG_LT_NZ;
+"ARG_LT_PI",ARG_LT_PI;
+"ARG_MUL",ARG_MUL;
+"ARG_MUL_CX",ARG_MUL_CX;
+"ARG_NUM",ARG_NUM;
+"ARG_REAL",ARG_REAL;
+"ARG_ROTATE2D",ARG_ROTATE2D;
+"ARG_ROTATE2D_UNIQUE",ARG_ROTATE2D_UNIQUE;
+"ARG_ROTATE2D_UNIQUE_2PI",ARG_ROTATE2D_UNIQUE_2PI;
+"ARG_UNIQUE",ARG_UNIQUE;
+"ARITH",ARITH;
+"ARITH_ADD",ARITH_ADD;
+"ARITH_EQ",ARITH_EQ;
+"ARITH_EVEN",ARITH_EVEN;
+"ARITH_EXP",ARITH_EXP;
+"ARITH_GE",ARITH_GE;
+"ARITH_GT",ARITH_GT;
+"ARITH_LE",ARITH_LE;
+"ARITH_LT",ARITH_LT;
+"ARITH_MULT",ARITH_MULT;
+"ARITH_ODD",ARITH_ODD;
+"ARITH_PRE",ARITH_PRE;
+"ARITH_SUB",ARITH_SUB;
+"ARITH_SUC",ARITH_SUC;
+"ARITH_ZERO",ARITH_ZERO;
+"ARZELA_ASCOLI",ARZELA_ASCOLI;
+"ASN_0",ASN_0;
+"ASN_1",ASN_1;
+"ASN_ACS",ASN_ACS;
+"ASN_ACS_SQRT_NEG",ASN_ACS_SQRT_NEG;
+"ASN_ACS_SQRT_POS",ASN_ACS_SQRT_POS;
+"ASN_ATN",ASN_ATN;
+"ASN_BOUNDS",ASN_BOUNDS;
+"ASN_BOUNDS_LT",ASN_BOUNDS_LT;
+"ASN_MONO_LE",ASN_MONO_LE;
+"ASN_MONO_LE_EQ",ASN_MONO_LE_EQ;
+"ASN_MONO_LT",ASN_MONO_LT;
+"ASN_MONO_LT_EQ",ASN_MONO_LT_EQ;
+"ASN_NEG",ASN_NEG;
+"ASN_NEG_1",ASN_NEG_1;
+"ASN_PLUS_ACS",ASN_PLUS_ACS;
+"ASN_SIN",ASN_SIN;
+"ASSOC",ASSOC;
+"AT",AT;
+"ATN_0",ATN_0;
+"ATN_1",ATN_1;
+"ATN_ABS_LE_X",ATN_ABS_LE_X;
+"ATN_BOUND",ATN_BOUND;
+"ATN_BOUNDS",ATN_BOUNDS;
+"ATN_INJ",ATN_INJ;
+"ATN_LE_PI4",ATN_LE_PI4;
+"ATN_LE_X",ATN_LE_X;
+"ATN_LT_PI4",ATN_LT_PI4;
+"ATN_LT_PI4_NEG",ATN_LT_PI4_NEG;
+"ATN_LT_PI4_POS",ATN_LT_PI4_POS;
+"ATN_MONO_LE_EQ",ATN_MONO_LE_EQ;
+"ATN_MONO_LT",ATN_MONO_LT;
+"ATN_MONO_LT_EQ",ATN_MONO_LT_EQ;
+"ATN_NEG",ATN_NEG;
+"ATN_POS_LE",ATN_POS_LE;
+"ATN_POS_LT",ATN_POS_LT;
+"ATN_TAN",ATN_TAN;
+"ATREAL",ATREAL;
+"AT_INFINITY",AT_INFINITY;
+"AT_NEGINFINITY",AT_NEGINFINITY;
+"AT_POSINFINITY",AT_POSINFINITY;
+"AUSTIN_LEMMA",AUSTIN_LEMMA;
+"Arg_DEF",Arg_DEF;
+"BABY_SARD",BABY_SARD;
+"BALL_1",BALL_1;
+"BALL_BIHOLOMORPHISM_EXISTS",BALL_BIHOLOMORPHISM_EXISTS;
+"BALL_BIHOLOMORPHISM_MOEBIUS_FUNCTION",BALL_BIHOLOMORPHISM_MOEBIUS_FUNCTION;
+"BALL_EMPTY",BALL_EMPTY;
+"BALL_EQ_EMPTY",BALL_EQ_EMPTY;
+"BALL_INTERVAL",BALL_INTERVAL;
+"BALL_INTERVAL_0",BALL_INTERVAL_0;
+"BALL_LINEAR_IMAGE",BALL_LINEAR_IMAGE;
+"BALL_MAX_UNION",BALL_MAX_UNION;
+"BALL_MIN_INTER",BALL_MIN_INTER;
+"BALL_SCALING",BALL_SCALING;
+"BALL_SUBSET_CBALL",BALL_SUBSET_CBALL;
+"BALL_SUBSET_OPEN_MAP_IMAGE",BALL_SUBSET_OPEN_MAP_IMAGE;
+"BALL_TRANSLATION",BALL_TRANSLATION;
+"BALL_TRIVIAL",BALL_TRIVIAL;
+"BALL_UNION_SPHERE",BALL_UNION_SPHERE;
+"BANACH_FIX",BANACH_FIX;
+"BASIS_CARD_EQ_DIM",BASIS_CARD_EQ_DIM;
+"BASIS_COMPONENT",BASIS_COMPONENT;
+"BASIS_COORDINATES_CONTINUOUS",BASIS_COORDINATES_CONTINUOUS;
+"BASIS_COORDINATES_LIPSCHITZ",BASIS_COORDINATES_LIPSCHITZ;
+"BASIS_EQ_0",BASIS_EQ_0;
+"BASIS_EXISTS",BASIS_EXISTS;
+"BASIS_EXISTS_FINITE",BASIS_EXISTS_FINITE;
+"BASIS_EXPANSION",BASIS_EXPANSION;
+"BASIS_EXPANSION_UNIQUE",BASIS_EXPANSION_UNIQUE;
+"BASIS_HAS_SIZE_DIM",BASIS_HAS_SIZE_DIM;
+"BASIS_HAS_SIZE_UNIV",BASIS_HAS_SIZE_UNIV;
+"BASIS_INJ",BASIS_INJ;
+"BASIS_INJ_EQ",BASIS_INJ_EQ;
+"BASIS_NE",BASIS_NE;
+"BASIS_NONZERO",BASIS_NONZERO;
+"BASIS_ORTHOGONAL",BASIS_ORTHOGONAL;
+"BASIS_SUBSPACE_EXISTS",BASIS_SUBSPACE_EXISTS;
+"BEPPO_LEVI_DECREASING",BEPPO_LEVI_DECREASING;
+"BEPPO_LEVI_INCREASING",BEPPO_LEVI_INCREASING;
+"BEPPO_LEVI_MONOTONE_CONVERGENCE_DECREASING",BEPPO_LEVI_MONOTONE_CONVERGENCE_DECREASING;
+"BEPPO_LEVI_MONOTONE_CONVERGENCE_INCREASING",BEPPO_LEVI_MONOTONE_CONVERGENCE_INCREASING;
+"BERNSTEIN_LEMMA",BERNSTEIN_LEMMA;
+"BERNSTEIN_POS",BERNSTEIN_POS;
+"BERNSTEIN_WEIERSTRASS",BERNSTEIN_WEIERSTRASS;
+"BESSEL_INEQUALITY",BESSEL_INEQUALITY;
+"BETA_THM",BETA_THM;
+"BETWEEN_ANTISYM",BETWEEN_ANTISYM;
+"BETWEEN_COLLINEAR_DIST_EQ",BETWEEN_COLLINEAR_DIST_EQ;
+"BETWEEN_DIST_LE",BETWEEN_DIST_LE;
+"BETWEEN_DIST_LT",BETWEEN_DIST_LT;
+"BETWEEN_DOT",BETWEEN_DOT;
+"BETWEEN_EXISTS_EXTENSION",BETWEEN_EXISTS_EXTENSION;
+"BETWEEN_IMP_COLLINEAR",BETWEEN_IMP_COLLINEAR;
+"BETWEEN_IN_CONVEX_HULL",BETWEEN_IN_CONVEX_HULL;
+"BETWEEN_IN_SEGMENT",BETWEEN_IN_SEGMENT;
+"BETWEEN_LINEAR_IMAGE_EQ",BETWEEN_LINEAR_IMAGE_EQ;
+"BETWEEN_MIDPOINT",BETWEEN_MIDPOINT;
+"BETWEEN_NORM",BETWEEN_NORM;
+"BETWEEN_NORM_LE",BETWEEN_NORM_LE;
+"BETWEEN_NORM_LT",BETWEEN_NORM_LT;
+"BETWEEN_REFL",BETWEEN_REFL;
+"BETWEEN_REFL_EQ",BETWEEN_REFL_EQ;
+"BETWEEN_SYM",BETWEEN_SYM;
+"BETWEEN_TRANS",BETWEEN_TRANS;
+"BETWEEN_TRANSLATION",BETWEEN_TRANSLATION;
+"BETWEEN_TRANS_2",BETWEEN_TRANS_2;
+"BIJ",BIJ;
+"BIJECTIONS_CARD_EQ",BIJECTIONS_CARD_EQ;
+"BIJECTIONS_HAS_SIZE",BIJECTIONS_HAS_SIZE;
+"BIJECTIONS_HAS_SIZE_EQ",BIJECTIONS_HAS_SIZE_EQ;
+"BIJECTIVE_INJECTIVE_SURJECTIVE",BIJECTIVE_INJECTIVE_SURJECTIVE;
+"BIJECTIVE_INVERSES",BIJECTIVE_INVERSES;
+"BIJECTIVE_LEFT_RIGHT_INVERSE",BIJECTIVE_LEFT_RIGHT_INVERSE;
+"BIJECTIVE_ON_LEFT_RIGHT_INVERSE",BIJECTIVE_ON_LEFT_RIGHT_INVERSE;
+"BILINEAR_BOUNDED",BILINEAR_BOUNDED;
+"BILINEAR_BOUNDED_POS",BILINEAR_BOUNDED_POS;
+"BILINEAR_COMPLEX_MUL",BILINEAR_COMPLEX_MUL;
+"BILINEAR_CONTINUOUS_COMPOSE",BILINEAR_CONTINUOUS_COMPOSE;
+"BILINEAR_CONTINUOUS_ON_COMPOSE",BILINEAR_CONTINUOUS_ON_COMPOSE;
+"BILINEAR_DIFFERENTIABLE_AT_COMPOSE",BILINEAR_DIFFERENTIABLE_AT_COMPOSE;
+"BILINEAR_DIFFERENTIABLE_ON_COMPOSE",BILINEAR_DIFFERENTIABLE_ON_COMPOSE;
+"BILINEAR_DIFFERENTIABLE_WITHIN_COMPOSE",BILINEAR_DIFFERENTIABLE_WITHIN_COMPOSE;
+"BILINEAR_DOT",BILINEAR_DOT;
+"BILINEAR_DROP_MUL",BILINEAR_DROP_MUL;
+"BILINEAR_EQ",BILINEAR_EQ;
+"BILINEAR_EQ_MBASIS",BILINEAR_EQ_MBASIS;
+"BILINEAR_EQ_STDBASIS",BILINEAR_EQ_STDBASIS;
+"BILINEAR_GEOM",BILINEAR_GEOM;
+"BILINEAR_INNER",BILINEAR_INNER;
+"BILINEAR_LADD",BILINEAR_LADD;
+"BILINEAR_LMUL",BILINEAR_LMUL;
+"BILINEAR_LNEG",BILINEAR_LNEG;
+"BILINEAR_LSUB",BILINEAR_LSUB;
+"BILINEAR_LZERO",BILINEAR_LZERO;
+"BILINEAR_OUTER",BILINEAR_OUTER;
+"BILINEAR_PRODUCT",BILINEAR_PRODUCT;
+"BILINEAR_RADD",BILINEAR_RADD;
+"BILINEAR_RMUL",BILINEAR_RMUL;
+"BILINEAR_RNEG",BILINEAR_RNEG;
+"BILINEAR_RSUB",BILINEAR_RSUB;
+"BILINEAR_RZERO",BILINEAR_RZERO;
+"BILINEAR_UNIFORMLY_CONTINUOUS_ON_COMPOSE",BILINEAR_UNIFORMLY_CONTINUOUS_ON_COMPOSE;
+"BILINEAR_VSUM",BILINEAR_VSUM;
+"BILINEAR_VSUM_PARTIAL_PRE",BILINEAR_VSUM_PARTIAL_PRE;
+"BILINEAR_VSUM_PARTIAL_SUC",BILINEAR_VSUM_PARTIAL_SUC;
+"BINARYSUM_BITSET",BINARYSUM_BITSET;
+"BINARYSUM_BOUND",BINARYSUM_BOUND;
+"BINARYSUM_BOUND_EQ",BINARYSUM_BOUND_EQ;
+"BINARYSUM_BOUND_LEMMA",BINARYSUM_BOUND_LEMMA;
+"BINARYSUM_DIV",BINARYSUM_DIV;
+"BINARYSUM_DIV_DIVISIBLE",BINARYSUM_DIV_DIVISIBLE;
+"BINARY_INDUCT",BINARY_INDUCT;
+"BINOM",BINOM;
+"BINOMIAL_THEOREM",BINOMIAL_THEOREM;
+"BINOM_1",BINOM_1;
+"BINOM_BOTH_STEP",BINOM_BOTH_STEP;
+"BINOM_BOTH_STEP_DOWN",BINOM_BOTH_STEP_DOWN;
+"BINOM_BOTH_STEP_REAL",BINOM_BOTH_STEP_REAL;
+"BINOM_BOTTOM_STEP",BINOM_BOTTOM_STEP;
+"BINOM_BOTTOM_STEP_REAL",BINOM_BOTTOM_STEP_REAL;
+"BINOM_EQ_0",BINOM_EQ_0;
+"BINOM_FACT",BINOM_FACT;
+"BINOM_LT",BINOM_LT;
+"BINOM_PENULT",BINOM_PENULT;
+"BINOM_REFL",BINOM_REFL;
+"BINOM_TOP_STEP",BINOM_TOP_STEP;
+"BINOM_TOP_STEP_REAL",BINOM_TOP_STEP_REAL;
+"BIT0",BIT0;
+"BIT0_DEF",BIT0_DEF;
+"BIT0_THM",BIT0_THM;
+"BIT1",BIT1;
+"BIT1_DEF",BIT1_DEF;
+"BIT1_THM",BIT1_THM;
+"BITSET_0",BITSET_0;
+"BITSET_BINARYSUM",BITSET_BINARYSUM;
+"BITSET_BOUND",BITSET_BOUND;
+"BITSET_BOUND_EQ",BITSET_BOUND_EQ;
+"BITSET_BOUND_LEMMA",BITSET_BOUND_LEMMA;
+"BITSET_BOUND_WEAK",BITSET_BOUND_WEAK;
+"BITSET_EQ",BITSET_EQ;
+"BITSET_EQ_EMPTY",BITSET_EQ_EMPTY;
+"BITSET_STEP",BITSET_STEP;
+"BLOCH",BLOCH;
+"BLOCH_COROLLARY",BLOCH_COROLLARY;
+"BLOCH_LEMMA",BLOCH_LEMMA;
+"BLOCH_UNIT",BLOCH_UNIT;
+"BOLZANO_WEIERSTRASS",BOLZANO_WEIERSTRASS;
+"BOLZANO_WEIERSTRASS_CONTRAPOS",BOLZANO_WEIERSTRASS_CONTRAPOS;
+"BOLZANO_WEIERSTRASS_IMP_BOUNDED",BOLZANO_WEIERSTRASS_IMP_BOUNDED;
+"BOLZANO_WEIERSTRASS_IMP_CLOSED",BOLZANO_WEIERSTRASS_IMP_CLOSED;
+"BOOL_CASES_AX",BOOL_CASES_AX;
+"BORSUK_HOMOTOPY_EXTENSION",BORSUK_HOMOTOPY_EXTENSION;
+"BORSUK_MAPS_HOMOTOPIC_IN_CONNECTED_COMPONENT_EQ",BORSUK_MAPS_HOMOTOPIC_IN_CONNECTED_COMPONENT_EQ;
+"BORSUK_MAPS_HOMOTOPIC_IN_PATH_COMPONENT",BORSUK_MAPS_HOMOTOPIC_IN_PATH_COMPONENT;
+"BORSUK_MAP_ESSENTIAL_BOUNDED_COMPONENT",BORSUK_MAP_ESSENTIAL_BOUNDED_COMPONENT;
+"BORSUK_MAP_INTO_SPHERE",BORSUK_MAP_INTO_SPHERE;
+"BORSUK_SEPARATION_THEOREM",BORSUK_SEPARATION_THEOREM;
+"BORSUK_SEPARATION_THEOREM_GEN",BORSUK_SEPARATION_THEOREM_GEN;
+"BOTTOM",BOTTOM;
+"BOUNDED_ARC_IMAGE",BOUNDED_ARC_IMAGE;
+"BOUNDED_BALL",BOUNDED_BALL;
+"BOUNDED_CBALL",BOUNDED_CBALL;
+"BOUNDED_CLOSED_CHAIN",BOUNDED_CLOSED_CHAIN;
+"BOUNDED_CLOSED_IMP_COMPACT",BOUNDED_CLOSED_IMP_COMPACT;
+"BOUNDED_CLOSED_INTERVAL",BOUNDED_CLOSED_INTERVAL;
+"BOUNDED_CLOSED_NEST",BOUNDED_CLOSED_NEST;
+"BOUNDED_CLOSURE",BOUNDED_CLOSURE;
+"BOUNDED_CLOSURE_EQ",BOUNDED_CLOSURE_EQ;
+"BOUNDED_COMPONENTWISE",BOUNDED_COMPONENTWISE;
+"BOUNDED_CONVEX_HULL",BOUNDED_CONVEX_HULL;
+"BOUNDED_CONVEX_HULL_EQ",BOUNDED_CONVEX_HULL_EQ;
+"BOUNDED_DECREASING_CONVERGENT",BOUNDED_DECREASING_CONVERGENT;
+"BOUNDED_DIFF",BOUNDED_DIFF;
+"BOUNDED_DIFFS",BOUNDED_DIFFS;
+"BOUNDED_EMPTY",BOUNDED_EMPTY;
+"BOUNDED_EQUIINTEGRAL_OVER_THIN_TAGGED_PARTIAL_DIVISION",BOUNDED_EQUIINTEGRAL_OVER_THIN_TAGGED_PARTIAL_DIVISION;
+"BOUNDED_FINITE",BOUNDED_FINITE;
+"BOUNDED_FRONTIER",BOUNDED_FRONTIER;
+"BOUNDED_FUNCTIONS_BIJECTIONS_1",BOUNDED_FUNCTIONS_BIJECTIONS_1;
+"BOUNDED_FUNCTIONS_BIJECTIONS_2",BOUNDED_FUNCTIONS_BIJECTIONS_2;
+"BOUNDED_HALFSPACE_GE",BOUNDED_HALFSPACE_GE;
+"BOUNDED_HALFSPACE_GT",BOUNDED_HALFSPACE_GT;
+"BOUNDED_HALFSPACE_LE",BOUNDED_HALFSPACE_LE;
+"BOUNDED_HALFSPACE_LT",BOUNDED_HALFSPACE_LT;
+"BOUNDED_HAS_INF",BOUNDED_HAS_INF;
+"BOUNDED_HAS_SUP",BOUNDED_HAS_SUP;
+"BOUNDED_HYPERPLANE_EQ_TRIVIAL",BOUNDED_HYPERPLANE_EQ_TRIVIAL;
+"BOUNDED_INCREASING_CONVERGENT",BOUNDED_INCREASING_CONVERGENT;
+"BOUNDED_INSERT",BOUNDED_INSERT;
+"BOUNDED_INSIDE",BOUNDED_INSIDE;
+"BOUNDED_INTER",BOUNDED_INTER;
+"BOUNDED_INTERIOR",BOUNDED_INTERIOR;
+"BOUNDED_INTERS",BOUNDED_INTERS;
+"BOUNDED_INTERVAL",BOUNDED_INTERVAL;
+"BOUNDED_LIFT",BOUNDED_LIFT;
+"BOUNDED_LINEAR_IMAGE",BOUNDED_LINEAR_IMAGE;
+"BOUNDED_LINEAR_IMAGE_EQ",BOUNDED_LINEAR_IMAGE_EQ;
+"BOUNDED_NEGATIONS",BOUNDED_NEGATIONS;
+"BOUNDED_PARTIAL_REAL_SUMS",BOUNDED_PARTIAL_REAL_SUMS;
+"BOUNDED_PARTIAL_SUMS",BOUNDED_PARTIAL_SUMS;
+"BOUNDED_PATH_IMAGE",BOUNDED_PATH_IMAGE;
+"BOUNDED_PCROSS",BOUNDED_PCROSS;
+"BOUNDED_PCROSS_EQ",BOUNDED_PCROSS_EQ;
+"BOUNDED_POS",BOUNDED_POS;
+"BOUNDED_POS_LT",BOUNDED_POS_LT;
+"BOUNDED_RECTIFIABLE_PATH_IMAGE",BOUNDED_RECTIFIABLE_PATH_IMAGE;
+"BOUNDED_RELATIVE_FRONTIER",BOUNDED_RELATIVE_FRONTIER;
+"BOUNDED_SCALING",BOUNDED_SCALING;
+"BOUNDED_SEGMENT",BOUNDED_SEGMENT;
+"BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE",BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE;
+"BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE_INTERVAL",BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE_INTERVAL;
+"BOUNDED_SIMPLE_PATH_IMAGE",BOUNDED_SIMPLE_PATH_IMAGE;
+"BOUNDED_SING",BOUNDED_SING;
+"BOUNDED_SLICE",BOUNDED_SLICE;
+"BOUNDED_SPHERE",BOUNDED_SPHERE;
+"BOUNDED_SUBSET",BOUNDED_SUBSET;
+"BOUNDED_SUBSET_BALL",BOUNDED_SUBSET_BALL;
+"BOUNDED_SUBSET_CBALL",BOUNDED_SUBSET_CBALL;
+"BOUNDED_SUBSET_CLOSED_INTERVAL",BOUNDED_SUBSET_CLOSED_INTERVAL;
+"BOUNDED_SUBSET_CLOSED_INTERVAL_SYMMETRIC",BOUNDED_SUBSET_CLOSED_INTERVAL_SYMMETRIC;
+"BOUNDED_SUBSET_OPEN_INTERVAL",BOUNDED_SUBSET_OPEN_INTERVAL;
+"BOUNDED_SUBSET_OPEN_INTERVAL_SYMMETRIC",BOUNDED_SUBSET_OPEN_INTERVAL_SYMMETRIC;
+"BOUNDED_SUMS",BOUNDED_SUMS;
+"BOUNDED_SUMS_IMAGE",BOUNDED_SUMS_IMAGE;
+"BOUNDED_SUMS_IMAGES",BOUNDED_SUMS_IMAGES;
+"BOUNDED_TRANSLATION",BOUNDED_TRANSLATION;
+"BOUNDED_TRANSLATION_EQ",BOUNDED_TRANSLATION_EQ;
+"BOUNDED_UNIFORMLY_CONTINUOUS_IMAGE",BOUNDED_UNIFORMLY_CONTINUOUS_IMAGE;
+"BOUNDED_UNION",BOUNDED_UNION;
+"BOUNDED_UNIONS",BOUNDED_UNIONS;
+"BOUNDED_UNIQUE_OUTSIDE",BOUNDED_UNIQUE_OUTSIDE;
+"BOUNDED_VALID_PATH_IMAGE",BOUNDED_VALID_PATH_IMAGE;
+"BOUNDS_DIVIDED",BOUNDS_DIVIDED;
+"BOUNDS_IGNORE",BOUNDS_IGNORE;
+"BOUNDS_LINEAR",BOUNDS_LINEAR;
+"BOUNDS_LINEAR_0",BOUNDS_LINEAR_0;
+"BOUNDS_NOTZERO",BOUNDS_NOTZERO;
+"BROUWER",BROUWER;
+"BROUWER_BALL",BROUWER_BALL;
+"BROUWER_COMPACTNESS_LEMMA",BROUWER_COMPACTNESS_LEMMA;
+"BROUWER_CONTRACTIBLE_ANR",BROUWER_CONTRACTIBLE_ANR;
+"BROUWER_CUBE",BROUWER_CUBE;
+"BROUWER_INESSENTIAL_ANR",BROUWER_INESSENTIAL_ANR;
+"BROUWER_REDUCTION_THEOREM",BROUWER_REDUCTION_THEOREM;
+"BROUWER_REDUCTION_THEOREM_GEN",BROUWER_REDUCTION_THEOREM_GEN;
+"BROUWER_SURJECTIVE",BROUWER_SURJECTIVE;
+"BROUWER_SURJECTIVE_CBALL",BROUWER_SURJECTIVE_CBALL;
+"BROUWER_WEAK",BROUWER_WEAK;
+"BUTLAST",BUTLAST;
+"CACS_0",CACS_0;
+"CACS_1",CACS_1;
+"CACS_BODY_LEMMA",CACS_BODY_LEMMA;
+"CACS_BOUNDS",CACS_BOUNDS;
+"CACS_CASN_SQRT_POS",CACS_CASN_SQRT_POS;
+"CACS_CCOS",CACS_CCOS;
+"CACS_NEG_1",CACS_NEG_1;
+"CACS_RANGE_LEMMA",CACS_RANGE_LEMMA;
+"CACS_UNIQUE",CACS_UNIQUE;
+"CANTOR_THM",CANTOR_THM;
+"CANTOR_THM_UNIV",CANTOR_THM_UNIV;
+"CARATHEODORY",CARATHEODORY;
+"CARATHEODORY_AFF_DIM",CARATHEODORY_AFF_DIM;
+"CARD",CARD;
+"CARD_ADD2_ABSORB_LE",CARD_ADD2_ABSORB_LE;
+"CARD_ADD2_ABSORB_LT",CARD_ADD2_ABSORB_LT;
+"CARD_ADD_ABSORB",CARD_ADD_ABSORB;
+"CARD_ADD_ABSORB_LE",CARD_ADD_ABSORB_LE;
+"CARD_ADD_ASSOC",CARD_ADD_ASSOC;
+"CARD_ADD_C",CARD_ADD_C;
+"CARD_ADD_CONG",CARD_ADD_CONG;
+"CARD_ADD_FINITE",CARD_ADD_FINITE;
+"CARD_ADD_FINITE_EQ",CARD_ADD_FINITE_EQ;
+"CARD_ADD_LE_MUL_INFINITE",CARD_ADD_LE_MUL_INFINITE;
+"CARD_ADD_SYM",CARD_ADD_SYM;
+"CARD_ADD_SYMDIFF_INTER",CARD_ADD_SYMDIFF_INTER;
+"CARD_BOOL",CARD_BOOL;
+"CARD_CART_UNIV",CARD_CART_UNIV;
+"CARD_CLAUSES",CARD_CLAUSES;
+"CARD_COMPLEX_ROOTS_UNITY",CARD_COMPLEX_ROOTS_UNITY;
+"CARD_COUNTABLE_CONG",CARD_COUNTABLE_CONG;
+"CARD_CROSS",CARD_CROSS;
+"CARD_DELETE",CARD_DELETE;
+"CARD_DIFF",CARD_DIFF;
+"CARD_DIFF_INTER",CARD_DIFF_INTER;
+"CARD_DISJOINT_UNION",CARD_DISJOINT_UNION;
+"CARD_EQ_0",CARD_EQ_0;
+"CARD_EQ_ARC_IMAGE",CARD_EQ_ARC_IMAGE;
+"CARD_EQ_BALL",CARD_EQ_BALL;
+"CARD_EQ_BIJECTION",CARD_EQ_BIJECTION;
+"CARD_EQ_BIJECTIONS",CARD_EQ_BIJECTIONS;
+"CARD_EQ_CARD",CARD_EQ_CARD;
+"CARD_EQ_CARD_IMP",CARD_EQ_CARD_IMP;
+"CARD_EQ_CART",CARD_EQ_CART;
+"CARD_EQ_CBALL",CARD_EQ_CBALL;
+"CARD_EQ_CLOSED",CARD_EQ_CLOSED;
+"CARD_EQ_CLOSED_SETS",CARD_EQ_CLOSED_SETS;
+"CARD_EQ_COMPACT_SETS",CARD_EQ_COMPACT_SETS;
+"CARD_EQ_CONDENSATION_POINTS",CARD_EQ_CONDENSATION_POINTS;
+"CARD_EQ_CONDENSATION_POINTS_IN_SET",CARD_EQ_CONDENSATION_POINTS_IN_SET;
+"CARD_EQ_CONG",CARD_EQ_CONG;
+"CARD_EQ_CONNECTED",CARD_EQ_CONNECTED;
+"CARD_EQ_CONVEX",CARD_EQ_CONVEX;
+"CARD_EQ_COUNTABLE",CARD_EQ_COUNTABLE;
+"CARD_EQ_COUNTABLE_SUBSETS_REAL",CARD_EQ_COUNTABLE_SUBSETS_REAL;
+"CARD_EQ_COVERING_MAP_FIBRES",CARD_EQ_COVERING_MAP_FIBRES;
+"CARD_EQ_DIM",CARD_EQ_DIM;
+"CARD_EQ_EMPTY",CARD_EQ_EMPTY;
+"CARD_EQ_EUCLIDEAN",CARD_EQ_EUCLIDEAN;
+"CARD_EQ_FINITE",CARD_EQ_FINITE;
+"CARD_EQ_FINITE_SUBSETS",CARD_EQ_FINITE_SUBSETS;
+"CARD_EQ_IMAGE",CARD_EQ_IMAGE;
+"CARD_EQ_IMP_LE",CARD_EQ_IMP_LE;
+"CARD_EQ_INTEGER",CARD_EQ_INTEGER;
+"CARD_EQ_INTERVAL",CARD_EQ_INTERVAL;
+"CARD_EQ_LIST",CARD_EQ_LIST;
+"CARD_EQ_LIST_GEN",CARD_EQ_LIST_GEN;
+"CARD_EQ_NONEMPTY_INTERIOR",CARD_EQ_NONEMPTY_INTERIOR;
+"CARD_EQ_NSUM",CARD_EQ_NSUM;
+"CARD_EQ_OPEN",CARD_EQ_OPEN;
+"CARD_EQ_OPEN_IN",CARD_EQ_OPEN_IN;
+"CARD_EQ_OPEN_IN_AFFINE",CARD_EQ_OPEN_IN_AFFINE;
+"CARD_EQ_OPEN_SETS",CARD_EQ_OPEN_SETS;
+"CARD_EQ_PATH_CONNECTED",CARD_EQ_PATH_CONNECTED;
+"CARD_EQ_PCROSS",CARD_EQ_PCROSS;
+"CARD_EQ_RATIONAL",CARD_EQ_RATIONAL;
+"CARD_EQ_REAL",CARD_EQ_REAL;
+"CARD_EQ_REAL_IMP_UNCOUNTABLE",CARD_EQ_REAL_IMP_UNCOUNTABLE;
+"CARD_EQ_REAL_SEQUENCES",CARD_EQ_REAL_SEQUENCES;
+"CARD_EQ_REFL",CARD_EQ_REFL;
+"CARD_EQ_SEGMENT",CARD_EQ_SEGMENT;
+"CARD_EQ_SIMPLE_PATH_IMAGE",CARD_EQ_SIMPLE_PATH_IMAGE;
+"CARD_EQ_SPHERE",CARD_EQ_SPHERE;
+"CARD_EQ_SUM",CARD_EQ_SUM;
+"CARD_EQ_SYM",CARD_EQ_SYM;
+"CARD_EQ_TRANS",CARD_EQ_TRANS;
+"CARD_FACES_OF_SIMPLEX",CARD_FACES_OF_SIMPLEX;
+"CARD_FINITE_CONG",CARD_FINITE_CONG;
+"CARD_FINITE_IMAGE",CARD_FINITE_IMAGE;
+"CARD_FUNSPACE",CARD_FUNSPACE;
+"CARD_FUNSPACE_CONG",CARD_FUNSPACE_CONG;
+"CARD_FUNSPACE_CURRY",CARD_FUNSPACE_CURRY;
+"CARD_FUNSPACE_LE",CARD_FUNSPACE_LE;
+"CARD_FUNSPACE_UNIV",CARD_FUNSPACE_UNIV;
+"CARD_GE_DIM_INDEPENDENT",CARD_GE_DIM_INDEPENDENT;
+"CARD_HAS_SIZE_CONG",CARD_HAS_SIZE_CONG;
+"CARD_IMAGE_EQ_INJ",CARD_IMAGE_EQ_INJ;
+"CARD_IMAGE_INJ",CARD_IMAGE_INJ;
+"CARD_IMAGE_INJ_EQ",CARD_IMAGE_INJ_EQ;
+"CARD_IMAGE_LE",CARD_IMAGE_LE;
+"CARD_INFINITE_CONG",CARD_INFINITE_CONG;
+"CARD_INTSEG_INT",CARD_INTSEG_INT;
+"CARD_LDISTRIB",CARD_LDISTRIB;
+"CARD_LET_TOTAL",CARD_LET_TOTAL;
+"CARD_LET_TRANS",CARD_LET_TRANS;
+"CARD_LE_ADD",CARD_LE_ADD;
+"CARD_LE_ADDL",CARD_LE_ADDL;
+"CARD_LE_ADDR",CARD_LE_ADDR;
+"CARD_LE_ANTISYM",CARD_LE_ANTISYM;
+"CARD_LE_CARD",CARD_LE_CARD;
+"CARD_LE_CARD_IMP",CARD_LE_CARD_IMP;
+"CARD_LE_CONG",CARD_LE_CONG;
+"CARD_LE_COUNTABLE",CARD_LE_COUNTABLE;
+"CARD_LE_COUNTABLE_SUBSETS",CARD_LE_COUNTABLE_SUBSETS;
+"CARD_LE_DIM_SPANNING",CARD_LE_DIM_SPANNING;
+"CARD_LE_EMPTY",CARD_LE_EMPTY;
+"CARD_LE_EQ_SUBSET",CARD_LE_EQ_SUBSET;
+"CARD_LE_FINITE",CARD_LE_FINITE;
+"CARD_LE_FINITE_SUBSETS",CARD_LE_FINITE_SUBSETS;
+"CARD_LE_IMAGE",CARD_LE_IMAGE;
+"CARD_LE_IMAGE_GEN",CARD_LE_IMAGE_GEN;
+"CARD_LE_INFINITE",CARD_LE_INFINITE;
+"CARD_LE_INJ",CARD_LE_INJ;
+"CARD_LE_LIST",CARD_LE_LIST;
+"CARD_LE_LT",CARD_LE_LT;
+"CARD_LE_MUL",CARD_LE_MUL;
+"CARD_LE_POWERSET",CARD_LE_POWERSET;
+"CARD_LE_REFL",CARD_LE_REFL;
+"CARD_LE_RELATIONAL",CARD_LE_RELATIONAL;
+"CARD_LE_SQUARE",CARD_LE_SQUARE;
+"CARD_LE_SUBPOWERSET",CARD_LE_SUBPOWERSET;
+"CARD_LE_SUBSET",CARD_LE_SUBSET;
+"CARD_LE_TOTAL",CARD_LE_TOTAL;
+"CARD_LE_TRANS",CARD_LE_TRANS;
+"CARD_LE_UNIV",CARD_LE_UNIV;
+"CARD_LTE_TOTAL",CARD_LTE_TOTAL;
+"CARD_LTE_TRANS",CARD_LTE_TRANS;
+"CARD_LT_ADD",CARD_LT_ADD;
+"CARD_LT_CARD",CARD_LT_CARD;
+"CARD_LT_CONG",CARD_LT_CONG;
+"CARD_LT_FINITE_INFINITE",CARD_LT_FINITE_INFINITE;
+"CARD_LT_IMP_DISCONNECTED",CARD_LT_IMP_DISCONNECTED;
+"CARD_LT_IMP_LE",CARD_LT_IMP_LE;
+"CARD_LT_LE",CARD_LT_LE;
+"CARD_LT_REFL",CARD_LT_REFL;
+"CARD_LT_TOTAL",CARD_LT_TOTAL;
+"CARD_LT_TRANS",CARD_LT_TRANS;
+"CARD_MUL2_ABSORB_LE",CARD_MUL2_ABSORB_LE;
+"CARD_MUL_ABSORB",CARD_MUL_ABSORB;
+"CARD_MUL_ABSORB_LE",CARD_MUL_ABSORB_LE;
+"CARD_MUL_ASSOC",CARD_MUL_ASSOC;
+"CARD_MUL_CONG",CARD_MUL_CONG;
+"CARD_MUL_FINITE",CARD_MUL_FINITE;
+"CARD_MUL_LT_INFINITE",CARD_MUL_LT_INFINITE;
+"CARD_MUL_LT_LEMMA",CARD_MUL_LT_LEMMA;
+"CARD_MUL_SYM",CARD_MUL_SYM;
+"CARD_NOT_LE",CARD_NOT_LE;
+"CARD_NOT_LT",CARD_NOT_LT;
+"CARD_NUMSEG",CARD_NUMSEG;
+"CARD_NUMSEG_1",CARD_NUMSEG_1;
+"CARD_NUMSEG_LE",CARD_NUMSEG_LE;
+"CARD_NUMSEG_LEMMA",CARD_NUMSEG_LEMMA;
+"CARD_NUMSEG_LT",CARD_NUMSEG_LT;
+"CARD_PERMUTATIONS",CARD_PERMUTATIONS;
+"CARD_POWERSET",CARD_POWERSET;
+"CARD_PRODUCT",CARD_PRODUCT;
+"CARD_PSUBSET",CARD_PSUBSET;
+"CARD_RDISTRIB",CARD_RDISTRIB;
+"CARD_SET_OF_LIST_LE",CARD_SET_OF_LIST_LE;
+"CARD_SING",CARD_SING;
+"CARD_SQUARE_INFINITE",CARD_SQUARE_INFINITE;
+"CARD_SQUARE_NUM",CARD_SQUARE_NUM;
+"CARD_STDBASIS",CARD_STDBASIS;
+"CARD_SUBSET",CARD_SUBSET;
+"CARD_SUBSET_EQ",CARD_SUBSET_EQ;
+"CARD_SUBSET_IMAGE",CARD_SUBSET_IMAGE;
+"CARD_SUBSET_LE",CARD_SUBSET_LE;
+"CARD_UNION",CARD_UNION;
+"CARD_UNIONS",CARD_UNIONS;
+"CARD_UNIONS_LE",CARD_UNIONS_LE;
+"CARD_UNION_EQ",CARD_UNION_EQ;
+"CARD_UNION_GEN",CARD_UNION_GEN;
+"CARD_UNION_LE",CARD_UNION_LE;
+"CARD_UNION_LEMMA",CARD_UNION_LEMMA;
+"CARD_UNION_OVERLAP",CARD_UNION_OVERLAP;
+"CARD_UNION_OVERLAP_EQ",CARD_UNION_OVERLAP_EQ;
+"CART_EQ",CART_EQ;
+"CART_EQ_FULL",CART_EQ_FULL;
+"CASEWISE",CASEWISE;
+"CASEWISE_CASES",CASEWISE_CASES;
+"CASEWISE_DEF",CASEWISE_DEF;
+"CASEWISE_WORKS",CASEWISE_WORKS;
+"CASN_0",CASN_0;
+"CASN_1",CASN_1;
+"CASN_BODY_LEMMA",CASN_BODY_LEMMA;
+"CASN_BOUNDS",CASN_BOUNDS;
+"CASN_CACS_SQRT_POS",CASN_CACS_SQRT_POS;
+"CASN_CSIN",CASN_CSIN;
+"CASN_NEG_1",CASN_NEG_1;
+"CASN_RANGE_LEMMA",CASN_RANGE_LEMMA;
+"CASN_UNIQUE",CASN_UNIQUE;
+"CATN_CTAN",CATN_CTAN;
+"CAUCHY",CAUCHY;
+"CAUCHY_CONTINUOUS_EXTENDS_TO_CLOSURE",CAUCHY_CONTINUOUS_EXTENDS_TO_CLOSURE;
+"CAUCHY_CONTINUOUS_IMP_CONTINUOUS",CAUCHY_CONTINUOUS_IMP_CONTINUOUS;
+"CAUCHY_CONTINUOUS_UNIQUENESS_LEMMA",CAUCHY_CONTINUOUS_UNIQUENESS_LEMMA;
+"CAUCHY_DERIVATIVE_INTEGRAL_CIRCLEPATH",CAUCHY_DERIVATIVE_INTEGRAL_CIRCLEPATH;
+"CAUCHY_HAS_PATH_INTEGRAL_HIGHER_DERIVATIVE_CIRCLEPATH",CAUCHY_HAS_PATH_INTEGRAL_HIGHER_DERIVATIVE_CIRCLEPATH;
+"CAUCHY_HIGHER_COMPLEX_DERIVATIVE_BOUND",CAUCHY_HIGHER_COMPLEX_DERIVATIVE_BOUND;
+"CAUCHY_HIGHER_DERIVATIVE_INTEGRAL_CIRCLEPATH",CAUCHY_HIGHER_DERIVATIVE_INTEGRAL_CIRCLEPATH;
+"CAUCHY_IMP_BOUNDED",CAUCHY_IMP_BOUNDED;
+"CAUCHY_INEQUALITY",CAUCHY_INEQUALITY;
+"CAUCHY_INTEGRAL_CIRCLEPATH",CAUCHY_INTEGRAL_CIRCLEPATH;
+"CAUCHY_INTEGRAL_CIRCLEPATH_SIMPLE",CAUCHY_INTEGRAL_CIRCLEPATH_SIMPLE;
+"CAUCHY_INTEGRAL_FORMULA_CONVEX",CAUCHY_INTEGRAL_FORMULA_CONVEX;
+"CAUCHY_INTEGRAL_FORMULA_CONVEX_SIMPLE",CAUCHY_INTEGRAL_FORMULA_CONVEX_SIMPLE;
+"CAUCHY_INTEGRAL_FORMULA_GLOBAL",CAUCHY_INTEGRAL_FORMULA_GLOBAL;
+"CAUCHY_INTEGRAL_FORMULA_WEAK",CAUCHY_INTEGRAL_FORMULA_WEAK;
+"CAUCHY_ISOMETRIC",CAUCHY_ISOMETRIC;
+"CAUCHY_NEXT_DERIVATIVE",CAUCHY_NEXT_DERIVATIVE;
+"CAUCHY_NEXT_DERIVATIVE_CIRCLEPATH",CAUCHY_NEXT_DERIVATIVE_CIRCLEPATH;
+"CAUCHY_RIEMANN",CAUCHY_RIEMANN;
+"CAUCHY_THEOREM_CONVEX",CAUCHY_THEOREM_CONVEX;
+"CAUCHY_THEOREM_CONVEX_SIMPLE",CAUCHY_THEOREM_CONVEX_SIMPLE;
+"CAUCHY_THEOREM_DISC",CAUCHY_THEOREM_DISC;
+"CAUCHY_THEOREM_DISC_SIMPLE",CAUCHY_THEOREM_DISC_SIMPLE;
+"CAUCHY_THEOREM_FLAT",CAUCHY_THEOREM_FLAT;
+"CAUCHY_THEOREM_FLAT_LEMMA",CAUCHY_THEOREM_FLAT_LEMMA;
+"CAUCHY_THEOREM_GLOBAL",CAUCHY_THEOREM_GLOBAL;
+"CAUCHY_THEOREM_GLOBAL_OUTSIDE",CAUCHY_THEOREM_GLOBAL_OUTSIDE;
+"CAUCHY_THEOREM_HOMOTOPIC_LOOPS",CAUCHY_THEOREM_HOMOTOPIC_LOOPS;
+"CAUCHY_THEOREM_HOMOTOPIC_PATHS",CAUCHY_THEOREM_HOMOTOPIC_PATHS;
+"CAUCHY_THEOREM_NULL_HOMOTOPIC",CAUCHY_THEOREM_NULL_HOMOTOPIC;
+"CAUCHY_THEOREM_PRIMITIVE",CAUCHY_THEOREM_PRIMITIVE;
+"CAUCHY_THEOREM_QUADRISECTION",CAUCHY_THEOREM_QUADRISECTION;
+"CAUCHY_THEOREM_SIMPLY_CONNECTED",CAUCHY_THEOREM_SIMPLY_CONNECTED;
+"CAUCHY_THEOREM_STARLIKE",CAUCHY_THEOREM_STARLIKE;
+"CAUCHY_THEOREM_STARLIKE_SIMPLE",CAUCHY_THEOREM_STARLIKE_SIMPLE;
+"CAUCHY_THEOREM_TRIANGLE",CAUCHY_THEOREM_TRIANGLE;
+"CAUCHY_THEOREM_TRIANGLE_COFINITE",CAUCHY_THEOREM_TRIANGLE_COFINITE;
+"CAUCHY_THEOREM_TRIANGLE_INTERIOR",CAUCHY_THEOREM_TRIANGLE_INTERIOR;
+"CBALL_DIFF_BALL",CBALL_DIFF_BALL;
+"CBALL_DIFF_SPHERE",CBALL_DIFF_SPHERE;
+"CBALL_EMPTY",CBALL_EMPTY;
+"CBALL_EQ_EMPTY",CBALL_EQ_EMPTY;
+"CBALL_EQ_SING",CBALL_EQ_SING;
+"CBALL_INTERVAL",CBALL_INTERVAL;
+"CBALL_INTERVAL_0",CBALL_INTERVAL_0;
+"CBALL_LINEAR_IMAGE",CBALL_LINEAR_IMAGE;
+"CBALL_SCALING",CBALL_SCALING;
+"CBALL_SING",CBALL_SING;
+"CBALL_TRANSLATION",CBALL_TRANSLATION;
+"CBALL_TRIVIAL",CBALL_TRIVIAL;
+"CCOS_0",CCOS_0;
+"CCOS_ADD",CCOS_ADD;
+"CCOS_CACS",CCOS_CACS;
+"CCOS_CASN",CCOS_CASN;
+"CCOS_CASN_NZ",CCOS_CASN_NZ;
+"CCOS_CSIN_CSQRT",CCOS_CSIN_CSQRT;
+"CCOS_DOUBLE",CCOS_DOUBLE;
+"CCOS_DOUBLE_CCOS",CCOS_DOUBLE_CCOS;
+"CCOS_DOUBLE_CSIN",CCOS_DOUBLE_CSIN;
+"CCOS_EQ",CCOS_EQ;
+"CCOS_EQ_0",CCOS_EQ_0;
+"CCOS_EQ_1",CCOS_EQ_1;
+"CCOS_EQ_MINUS1",CCOS_EQ_MINUS1;
+"CCOS_NEG",CCOS_NEG;
+"CCOS_SUB",CCOS_SUB;
+"CELL_COMPLEX_SUBDIVISION_EXISTS",CELL_COMPLEX_SUBDIVISION_EXISTS;
+"CENTRE_IN_BALL",CENTRE_IN_BALL;
+"CENTRE_IN_CBALL",CENTRE_IN_CBALL;
+"CEXP_0",CEXP_0;
+"CEXP_ADD",CEXP_ADD;
+"CEXP_ADD_MUL",CEXP_ADD_MUL;
+"CEXP_BOUND_BLEMMA",CEXP_BOUND_BLEMMA;
+"CEXP_BOUND_HALF",CEXP_BOUND_HALF;
+"CEXP_BOUND_LEMMA",CEXP_BOUND_LEMMA;
+"CEXP_CLOG",CEXP_CLOG;
+"CEXP_COMPLEX",CEXP_COMPLEX;
+"CEXP_CONVERGES",CEXP_CONVERGES;
+"CEXP_CONVERGES_UNIFORMLY",CEXP_CONVERGES_UNIFORMLY;
+"CEXP_CONVERGES_UNIFORMLY_CAUCHY",CEXP_CONVERGES_UNIFORMLY_CAUCHY;
+"CEXP_CONVERGES_UNIQUE",CEXP_CONVERGES_UNIQUE;
+"CEXP_EQ",CEXP_EQ;
+"CEXP_EQ_1",CEXP_EQ_1;
+"CEXP_EULER",CEXP_EULER;
+"CEXP_II_NE_1",CEXP_II_NE_1;
+"CEXP_INTEGER_2PI",CEXP_INTEGER_2PI;
+"CEXP_N",CEXP_N;
+"CEXP_NEG",CEXP_NEG;
+"CEXP_NEG_LMUL",CEXP_NEG_LMUL;
+"CEXP_NEG_RMUL",CEXP_NEG_RMUL;
+"CEXP_NZ",CEXP_NZ;
+"CEXP_SUB",CEXP_SUB;
+"CEXP_VSUM",CEXP_VSUM;
+"CHAIN_SUBSET",CHAIN_SUBSET;
+"CHARACTERISTIC_POLYNOMIAL",CHARACTERISTIC_POLYNOMIAL;
+"CHOICE",CHOICE;
+"CHOICE_DEF",CHOICE_DEF;
+"CHOOSE_AFFINE_SUBSET",CHOOSE_AFFINE_SUBSET;
+"CHOOSE_POLYTOPE",CHOOSE_POLYTOPE;
+"CHOOSE_SIMPLEX",CHOOSE_SIMPLEX;
+"CHOOSE_SUBSET",CHOOSE_SUBSET;
+"CHOOSE_SUBSET_BETWEEN",CHOOSE_SUBSET_BETWEEN;
+"CHOOSE_SUBSET_STRONG",CHOOSE_SUBSET_STRONG;
+"CHOOSE_SUBSPACE_OF_SUBSPACE",CHOOSE_SUBSPACE_OF_SUBSPACE;
+"CIRCLEPATH",CIRCLEPATH;
+"CIRCLE_SINCOS",CIRCLE_SINCOS;
+"CLOG_1",CLOG_1;
+"CLOG_CEXP",CLOG_CEXP;
+"CLOG_EQ",CLOG_EQ;
+"CLOG_II",CLOG_II;
+"CLOG_INV",CLOG_INV;
+"CLOG_MUL",CLOG_MUL;
+"CLOG_MUL_II",CLOG_MUL_II;
+"CLOG_MUL_SIMPLE",CLOG_MUL_SIMPLE;
+"CLOG_MUL_UNWINDING",CLOG_MUL_UNWINDING;
+"CLOG_NEG",CLOG_NEG;
+"CLOG_NEG_1",CLOG_NEG_1;
+"CLOG_NEG_II",CLOG_NEG_II;
+"CLOG_UNIQUE",CLOG_UNIQUE;
+"CLOG_WORKS",CLOG_WORKS;
+"CLOPEN",CLOPEN;
+"CLOSED_AFFINE",CLOSED_AFFINE;
+"CLOSED_AFFINE_HULL",CLOSED_AFFINE_HULL;
+"CLOSED_APPROACHABLE",CLOSED_APPROACHABLE;
+"CLOSED_ARC_IMAGE",CLOSED_ARC_IMAGE;
+"CLOSED_ARG_LE",CLOSED_ARG_LE;
+"CLOSED_AS_FRONTIER",CLOSED_AS_FRONTIER;
+"CLOSED_AS_FRONTIER_OF_SUBSET",CLOSED_AS_FRONTIER_OF_SUBSET;
+"CLOSED_BOUNDEDPREIM_CONTINUOUS_IMAGE",CLOSED_BOUNDEDPREIM_CONTINUOUS_IMAGE;
+"CLOSED_CBALL",CLOSED_CBALL;
+"CLOSED_CLOSED_IN_TRANS",CLOSED_CLOSED_IN_TRANS;
+"CLOSED_CLOSURE",CLOSED_CLOSURE;
+"CLOSED_COMPACT_DIFFERENCES",CLOSED_COMPACT_DIFFERENCES;
+"CLOSED_COMPACT_PROJECTION",CLOSED_COMPACT_PROJECTION;
+"CLOSED_COMPACT_SUMS",CLOSED_COMPACT_SUMS;
+"CLOSED_COMPONENTS",CLOSED_COMPONENTS;
+"CLOSED_CONDENSATION_POINTS",CLOSED_CONDENSATION_POINTS;
+"CLOSED_CONNECTED_COMPONENT",CLOSED_CONNECTED_COMPONENT;
+"CLOSED_CONTAINS_SEQUENTIAL_LIMIT",CLOSED_CONTAINS_SEQUENTIAL_LIMIT;
+"CLOSED_CONVEX_CONE_HULL",CLOSED_CONVEX_CONE_HULL;
+"CLOSED_DIFF",CLOSED_DIFF;
+"CLOSED_DIFF_OPEN_INTERVAL_1",CLOSED_DIFF_OPEN_INTERVAL_1;
+"CLOSED_EMPTY",CLOSED_EMPTY;
+"CLOSED_FIP",CLOSED_FIP;
+"CLOSED_FORALL",CLOSED_FORALL;
+"CLOSED_FORALL_IN",CLOSED_FORALL_IN;
+"CLOSED_HALFSPACE_COMPONENT_GE",CLOSED_HALFSPACE_COMPONENT_GE;
+"CLOSED_HALFSPACE_COMPONENT_LE",CLOSED_HALFSPACE_COMPONENT_LE;
+"CLOSED_HALFSPACE_GE",CLOSED_HALFSPACE_GE;
+"CLOSED_HALFSPACE_IM_EQ",CLOSED_HALFSPACE_IM_EQ;
+"CLOSED_HALFSPACE_IM_GE",CLOSED_HALFSPACE_IM_GE;
+"CLOSED_HALFSPACE_IM_LE",CLOSED_HALFSPACE_IM_LE;
+"CLOSED_HALFSPACE_LE",CLOSED_HALFSPACE_LE;
+"CLOSED_HALFSPACE_RE_EQ",CLOSED_HALFSPACE_RE_EQ;
+"CLOSED_HALFSPACE_RE_GE",CLOSED_HALFSPACE_RE_GE;
+"CLOSED_HALFSPACE_RE_LE",CLOSED_HALFSPACE_RE_LE;
+"CLOSED_HYPERPLANE",CLOSED_HYPERPLANE;
+"CLOSED_IMP_LOCALLY_COMPACT",CLOSED_IMP_LOCALLY_COMPACT;
+"CLOSED_IN",CLOSED_IN;
+"CLOSED_INJECTIVE_IMAGE_SUBSET_SUBSPACE",CLOSED_INJECTIVE_IMAGE_SUBSET_SUBSPACE;
+"CLOSED_INJECTIVE_IMAGE_SUBSPACE",CLOSED_INJECTIVE_IMAGE_SUBSPACE;
+"CLOSED_INJECTIVE_LINEAR_IMAGE",CLOSED_INJECTIVE_LINEAR_IMAGE;
+"CLOSED_INJECTIVE_LINEAR_IMAGE_EQ",CLOSED_INJECTIVE_LINEAR_IMAGE_EQ;
+"CLOSED_INSERT",CLOSED_INSERT;
+"CLOSED_INTER",CLOSED_INTER;
+"CLOSED_INTERS",CLOSED_INTERS;
+"CLOSED_INTERS_COMPACT",CLOSED_INTERS_COMPACT;
+"CLOSED_INTERVAL",CLOSED_INTERVAL;
+"CLOSED_INTERVAL_AS_CONVEX_HULL",CLOSED_INTERVAL_AS_CONVEX_HULL;
+"CLOSED_INTERVAL_DROPOUT",CLOSED_INTERVAL_DROPOUT;
+"CLOSED_INTERVAL_EQ",CLOSED_INTERVAL_EQ;
+"CLOSED_INTERVAL_IMAGE_UNIT_INTERVAL",CLOSED_INTERVAL_IMAGE_UNIT_INTERVAL;
+"CLOSED_INTERVAL_LEFT",CLOSED_INTERVAL_LEFT;
+"CLOSED_INTERVAL_RIGHT",CLOSED_INTERVAL_RIGHT;
+"CLOSED_INTER_COMPACT",CLOSED_INTER_COMPACT;
+"CLOSED_IN_CLOSED",CLOSED_IN_CLOSED;
+"CLOSED_IN_CLOSED_EQ",CLOSED_IN_CLOSED_EQ;
+"CLOSED_IN_CLOSED_INTER",CLOSED_IN_CLOSED_INTER;
+"CLOSED_IN_CLOSED_TRANS",CLOSED_IN_CLOSED_TRANS;
+"CLOSED_IN_COMPACT",CLOSED_IN_COMPACT;
+"CLOSED_IN_COMPACT_PROJECTION",CLOSED_IN_COMPACT_PROJECTION;
+"CLOSED_IN_CONNECTED_COMPONENT",CLOSED_IN_CONNECTED_COMPONENT;
+"CLOSED_IN_DIFF",CLOSED_IN_DIFF;
+"CLOSED_IN_EMPTY",CLOSED_IN_EMPTY;
+"CLOSED_IN_IMP_SUBSET",CLOSED_IN_IMP_SUBSET;
+"CLOSED_IN_INJECTIVE_LINEAR_IMAGE",CLOSED_IN_INJECTIVE_LINEAR_IMAGE;
+"CLOSED_IN_INTER",CLOSED_IN_INTER;
+"CLOSED_IN_INTERS",CLOSED_IN_INTERS;
+"CLOSED_IN_INTER_CLOSED",CLOSED_IN_INTER_CLOSED;
+"CLOSED_IN_LIMPT",CLOSED_IN_LIMPT;
+"CLOSED_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED",CLOSED_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED;
+"CLOSED_IN_REFL",CLOSED_IN_REFL;
+"CLOSED_IN_RETRACT",CLOSED_IN_RETRACT;
+"CLOSED_IN_SING",CLOSED_IN_SING;
+"CLOSED_IN_SUBSET",CLOSED_IN_SUBSET;
+"CLOSED_IN_SUBSET_TRANS",CLOSED_IN_SUBSET_TRANS;
+"CLOSED_IN_SUBTOPOLOGY",CLOSED_IN_SUBTOPOLOGY;
+"CLOSED_IN_SUBTOPOLOGY_EMPTY",CLOSED_IN_SUBTOPOLOGY_EMPTY;
+"CLOSED_IN_SUBTOPOLOGY_REFL",CLOSED_IN_SUBTOPOLOGY_REFL;
+"CLOSED_IN_SUBTOPOLOGY_UNION",CLOSED_IN_SUBTOPOLOGY_UNION;
+"CLOSED_IN_TOPSPACE",CLOSED_IN_TOPSPACE;
+"CLOSED_IN_TRANS",CLOSED_IN_TRANS;
+"CLOSED_IN_TRANSLATION_EQ",CLOSED_IN_TRANSLATION_EQ;
+"CLOSED_IN_UNION",CLOSED_IN_UNION;
+"CLOSED_IN_UNIONS",CLOSED_IN_UNIONS;
+"CLOSED_IN_UNION_COMPLEMENT_COMPONENT",CLOSED_IN_UNION_COMPLEMENT_COMPONENT;
+"CLOSED_LIFT",CLOSED_LIFT;
+"CLOSED_LIMPT",CLOSED_LIMPT;
+"CLOSED_LIMPTS",CLOSED_LIMPTS;
+"CLOSED_MAP_FROM_COMPOSITION_INJECTIVE",CLOSED_MAP_FROM_COMPOSITION_INJECTIVE;
+"CLOSED_MAP_FROM_COMPOSITION_SURJECTIVE",CLOSED_MAP_FROM_COMPOSITION_SURJECTIVE;
+"CLOSED_MAP_IMP_OPEN_MAP",CLOSED_MAP_IMP_OPEN_MAP;
+"CLOSED_MAP_IMP_QUOTIENT_MAP",CLOSED_MAP_IMP_QUOTIENT_MAP;
+"CLOSED_NEGATIONS",CLOSED_NEGATIONS;
+"CLOSED_OPEN_INTERVAL_1",CLOSED_OPEN_INTERVAL_1;
+"CLOSED_PATH_IMAGE",CLOSED_PATH_IMAGE;
+"CLOSED_PCROSS",CLOSED_PCROSS;
+"CLOSED_PCROSS_EQ",CLOSED_PCROSS_EQ;
+"CLOSED_POSITIVE_ORTHANT",CLOSED_POSITIVE_ORTHANT;
+"CLOSED_REAL",CLOSED_REAL;
+"CLOSED_REAL_SET",CLOSED_REAL_SET;
+"CLOSED_RELATIVE_BOUNDARY",CLOSED_RELATIVE_BOUNDARY;
+"CLOSED_RELATIVE_FRONTIER",CLOSED_RELATIVE_FRONTIER;
+"CLOSED_SCALING",CLOSED_SCALING;
+"CLOSED_SEGMENT",CLOSED_SEGMENT;
+"CLOSED_SEGMENT_LINEAR_IMAGE",CLOSED_SEGMENT_LINEAR_IMAGE;
+"CLOSED_SEQUENTIAL_LIMITS",CLOSED_SEQUENTIAL_LIMITS;
+"CLOSED_SHIFTPATH",CLOSED_SHIFTPATH;
+"CLOSED_SIMPLE_PATH_IMAGE",CLOSED_SIMPLE_PATH_IMAGE;
+"CLOSED_SING",CLOSED_SING;
+"CLOSED_SLICE",CLOSED_SLICE;
+"CLOSED_SPAN",CLOSED_SPAN;
+"CLOSED_SPHERE",CLOSED_SPHERE;
+"CLOSED_STANDARD_HYPERPLANE",CLOSED_STANDARD_HYPERPLANE;
+"CLOSED_SUBSET",CLOSED_SUBSET;
+"CLOSED_SUBSET_EQ",CLOSED_SUBSET_EQ;
+"CLOSED_SUBSPACE",CLOSED_SUBSPACE;
+"CLOSED_SUBSTANDARD",CLOSED_SUBSTANDARD;
+"CLOSED_TRANSLATION",CLOSED_TRANSLATION;
+"CLOSED_TRANSLATION_EQ",CLOSED_TRANSLATION_EQ;
+"CLOSED_UNION",CLOSED_UNION;
+"CLOSED_UNIONS",CLOSED_UNIONS;
+"CLOSED_UNION_COMPACT_SUBSETS",CLOSED_UNION_COMPACT_SUBSETS;
+"CLOSED_UNION_COMPLEMENT_COMPONENT",CLOSED_UNION_COMPLEMENT_COMPONENT;
+"CLOSED_UNIV",CLOSED_UNIV;
+"CLOSED_VALID_PATH_IMAGE",CLOSED_VALID_PATH_IMAGE;
+"CLOSER_POINTS_LEMMA",CLOSER_POINTS_LEMMA;
+"CLOSER_POINT_LEMMA",CLOSER_POINT_LEMMA;
+"CLOSEST_POINT_AFFINE_ORTHOGONAL",CLOSEST_POINT_AFFINE_ORTHOGONAL;
+"CLOSEST_POINT_AFFINE_ORTHOGONAL_EQ",CLOSEST_POINT_AFFINE_ORTHOGONAL_EQ;
+"CLOSEST_POINT_DOT",CLOSEST_POINT_DOT;
+"CLOSEST_POINT_EXISTS",CLOSEST_POINT_EXISTS;
+"CLOSEST_POINT_IN_FRONTIER",CLOSEST_POINT_IN_FRONTIER;
+"CLOSEST_POINT_IN_INTERIOR",CLOSEST_POINT_IN_INTERIOR;
+"CLOSEST_POINT_IN_RELATIVE_FRONTIER",CLOSEST_POINT_IN_RELATIVE_FRONTIER;
+"CLOSEST_POINT_IN_RELATIVE_INTERIOR",CLOSEST_POINT_IN_RELATIVE_INTERIOR;
+"CLOSEST_POINT_IN_SET",CLOSEST_POINT_IN_SET;
+"CLOSEST_POINT_LE",CLOSEST_POINT_LE;
+"CLOSEST_POINT_LIPSCHITZ",CLOSEST_POINT_LIPSCHITZ;
+"CLOSEST_POINT_LT",CLOSEST_POINT_LT;
+"CLOSEST_POINT_REFL",CLOSEST_POINT_REFL;
+"CLOSEST_POINT_SELF",CLOSEST_POINT_SELF;
+"CLOSEST_POINT_UNIQUE",CLOSEST_POINT_UNIQUE;
+"CLOSURE_APPROACHABLE",CLOSURE_APPROACHABLE;
+"CLOSURE_BALL",CLOSURE_BALL;
+"CLOSURE_BOUNDED_LINEAR_IMAGE",CLOSURE_BOUNDED_LINEAR_IMAGE;
+"CLOSURE_CLOSED",CLOSURE_CLOSED;
+"CLOSURE_CLOSURE",CLOSURE_CLOSURE;
+"CLOSURE_COCOUNTABLE_COORDINATES",CLOSURE_COCOUNTABLE_COORDINATES;
+"CLOSURE_COMPLEMENT",CLOSURE_COMPLEMENT;
+"CLOSURE_CONVEX_HULL",CLOSURE_CONVEX_HULL;
+"CLOSURE_CONVEX_INTER_AFFINE",CLOSURE_CONVEX_INTER_AFFINE;
+"CLOSURE_CONVEX_INTER_SUPERSET",CLOSURE_CONVEX_INTER_SUPERSET;
+"CLOSURE_COSMALL_COORDINATES",CLOSURE_COSMALL_COORDINATES;
+"CLOSURE_DYADIC_RATIONALS",CLOSURE_DYADIC_RATIONALS;
+"CLOSURE_DYADIC_RATIONALS_IN_CONVEX_SET",CLOSURE_DYADIC_RATIONALS_IN_CONVEX_SET;
+"CLOSURE_DYADIC_RATIONALS_IN_OPEN_SET",CLOSURE_DYADIC_RATIONALS_IN_OPEN_SET;
+"CLOSURE_EMPTY",CLOSURE_EMPTY;
+"CLOSURE_EQ",CLOSURE_EQ;
+"CLOSURE_EQ_EMPTY",CLOSURE_EQ_EMPTY;
+"CLOSURE_HALFSPACE_COMPONENT_GT",CLOSURE_HALFSPACE_COMPONENT_GT;
+"CLOSURE_HALFSPACE_COMPONENT_LT",CLOSURE_HALFSPACE_COMPONENT_LT;
+"CLOSURE_HALFSPACE_GT",CLOSURE_HALFSPACE_GT;
+"CLOSURE_HALFSPACE_LT",CLOSURE_HALFSPACE_LT;
+"CLOSURE_HULL",CLOSURE_HULL;
+"CLOSURE_IMAGE_CLOSURE",CLOSURE_IMAGE_CLOSURE;
+"CLOSURE_INJECTIVE_LINEAR_IMAGE",CLOSURE_INJECTIVE_LINEAR_IMAGE;
+"CLOSURE_INSIDE_SUBSET",CLOSURE_INSIDE_SUBSET;
+"CLOSURE_INTERIOR",CLOSURE_INTERIOR;
+"CLOSURE_INTERIOR_IDEMP",CLOSURE_INTERIOR_IDEMP;
+"CLOSURE_INTERS_CONVEX",CLOSURE_INTERS_CONVEX;
+"CLOSURE_INTERS_CONVEX_OPEN",CLOSURE_INTERS_CONVEX_OPEN;
+"CLOSURE_INTERS_SUBSET",CLOSURE_INTERS_SUBSET;
+"CLOSURE_INTERVAL",CLOSURE_INTERVAL;
+"CLOSURE_INTER_CONVEX",CLOSURE_INTER_CONVEX;
+"CLOSURE_INTER_CONVEX_OPEN",CLOSURE_INTER_CONVEX_OPEN;
+"CLOSURE_INTER_SUBSET",CLOSURE_INTER_SUBSET;
+"CLOSURE_IRRATIONAL_COORDINATES",CLOSURE_IRRATIONAL_COORDINATES;
+"CLOSURE_LINEAR_IMAGE_SUBSET",CLOSURE_LINEAR_IMAGE_SUBSET;
+"CLOSURE_MINIMAL",CLOSURE_MINIMAL;
+"CLOSURE_MINIMAL_EQ",CLOSURE_MINIMAL_EQ;
+"CLOSURE_NEGATIONS",CLOSURE_NEGATIONS;
+"CLOSURE_OPEN_INTERVAL",CLOSURE_OPEN_INTERVAL;
+"CLOSURE_OPEN_INTER_SUPERSET",CLOSURE_OPEN_INTER_SUPERSET;
+"CLOSURE_OUTSIDE_SUBSET",CLOSURE_OUTSIDE_SUBSET;
+"CLOSURE_PCROSS",CLOSURE_PCROSS;
+"CLOSURE_RATIONALS_IN_CONVEX_SET",CLOSURE_RATIONALS_IN_CONVEX_SET;
+"CLOSURE_RATIONALS_IN_OPEN_SET",CLOSURE_RATIONALS_IN_OPEN_SET;
+"CLOSURE_RATIONAL_COORDINATES",CLOSURE_RATIONAL_COORDINATES;
+"CLOSURE_SEGMENT",CLOSURE_SEGMENT;
+"CLOSURE_SEQUENTIAL",CLOSURE_SEQUENTIAL;
+"CLOSURE_SING",CLOSURE_SING;
+"CLOSURE_SUBSET",CLOSURE_SUBSET;
+"CLOSURE_SUBSET_AFFINE_HULL",CLOSURE_SUBSET_AFFINE_HULL;
+"CLOSURE_SUBSET_EQ",CLOSURE_SUBSET_EQ;
+"CLOSURE_SURJECTIVE_LINEAR_IMAGE",CLOSURE_SURJECTIVE_LINEAR_IMAGE;
+"CLOSURE_TRANSLATION",CLOSURE_TRANSLATION;
+"CLOSURE_UNION",CLOSURE_UNION;
+"CLOSURE_UNIONS",CLOSURE_UNIONS;
+"CLOSURE_UNION_FRONTIER",CLOSURE_UNION_FRONTIER;
+"CLOSURE_UNIQUE",CLOSURE_UNIQUE;
+"CLOSURE_UNIV",CLOSURE_UNIV;
+"CNJ_ADD",CNJ_ADD;
+"CNJ_CCOS",CNJ_CCOS;
+"CNJ_CEXP",CNJ_CEXP;
+"CNJ_CLOG",CNJ_CLOG;
+"CNJ_CNJ",CNJ_CNJ;
+"CNJ_CSIN",CNJ_CSIN;
+"CNJ_CSQRT",CNJ_CSQRT;
+"CNJ_CTAN",CNJ_CTAN;
+"CNJ_CX",CNJ_CX;
+"CNJ_DIV",CNJ_DIV;
+"CNJ_EQ_0",CNJ_EQ_0;
+"CNJ_EQ_CX",CNJ_EQ_CX;
+"CNJ_II",CNJ_II;
+"CNJ_INJ",CNJ_INJ;
+"CNJ_INV",CNJ_INV;
+"CNJ_MUL",CNJ_MUL;
+"CNJ_NEG",CNJ_NEG;
+"CNJ_POW",CNJ_POW;
+"CNJ_SUB",CNJ_SUB;
+"CNJ_VSUM",CNJ_VSUM;
+"COBOUNDED_HAS_BOUNDED_COMPONENT",COBOUNDED_HAS_BOUNDED_COMPONENT;
+"COBOUNDED_IMP_UNBOUNDED",COBOUNDED_IMP_UNBOUNDED;
+"COBOUNDED_INTER_UNBOUNDED",COBOUNDED_INTER_UNBOUNDED;
+"COBOUNDED_OUTSIDE",COBOUNDED_OUTSIDE;
+"COBOUNDED_UNBOUNDED_COMPONENT",COBOUNDED_UNBOUNDED_COMPONENT;
+"COBOUNDED_UNBOUNDED_COMPONENTS",COBOUNDED_UNBOUNDED_COMPONENTS;
+"COBOUNDED_UNIQUE_UNBOUNDED_COMPONENT",COBOUNDED_UNIQUE_UNBOUNDED_COMPONENT;
+"COBOUNDED_UNIQUE_UNBOUNDED_COMPONENTS",COBOUNDED_UNIQUE_UNBOUNDED_COMPONENTS;
+"COCOUNTABLE_APPROXIMATION",COCOUNTABLE_APPROXIMATION;
+"CODESET_SETCODE_BIJECTIONS",CODESET_SETCODE_BIJECTIONS;
+"COFACTOR_0",COFACTOR_0;
+"COFACTOR_CMUL",COFACTOR_CMUL;
+"COFACTOR_COFACTOR",COFACTOR_COFACTOR;
+"COFACTOR_COLUMN",COFACTOR_COLUMN;
+"COFACTOR_I",COFACTOR_I;
+"COFACTOR_MATRIX_INV",COFACTOR_MATRIX_INV;
+"COFACTOR_MATRIX_MUL",COFACTOR_MATRIX_MUL;
+"COFACTOR_ROW",COFACTOR_ROW;
+"COFACTOR_TRANSP",COFACTOR_TRANSP;
+"COHOMOTOPICALLY_TRIVIAL_RETRACTION_GEN",COHOMOTOPICALLY_TRIVIAL_RETRACTION_GEN;
+"COHOMOTOPICALLY_TRIVIAL_RETRACTION_NULL_GEN",COHOMOTOPICALLY_TRIVIAL_RETRACTION_NULL_GEN;
+"COLLINEAR_1",COLLINEAR_1;
+"COLLINEAR_2",COLLINEAR_2;
+"COLLINEAR_3",COLLINEAR_3;
+"COLLINEAR_3_2D",COLLINEAR_3_2D;
+"COLLINEAR_3_AFFINE_HULL",COLLINEAR_3_AFFINE_HULL;
+"COLLINEAR_3_DOT_MULTIPLES",COLLINEAR_3_DOT_MULTIPLES;
+"COLLINEAR_3_EQ_AFFINE_DEPENDENT",COLLINEAR_3_EQ_AFFINE_DEPENDENT;
+"COLLINEAR_3_EXPAND",COLLINEAR_3_EXPAND;
+"COLLINEAR_3_IN_AFFINE_HULL",COLLINEAR_3_IN_AFFINE_HULL;
+"COLLINEAR_3_TRANS",COLLINEAR_3_TRANS;
+"COLLINEAR_4_3",COLLINEAR_4_3;
+"COLLINEAR_AFFINE_HULL",COLLINEAR_AFFINE_HULL;
+"COLLINEAR_AFFINE_HULL_COLLINEAR",COLLINEAR_AFFINE_HULL_COLLINEAR;
+"COLLINEAR_AFF_DIM",COLLINEAR_AFF_DIM;
+"COLLINEAR_BETWEEN_CASES",COLLINEAR_BETWEEN_CASES;
+"COLLINEAR_CONVEX_HULL_COLLINEAR",COLLINEAR_CONVEX_HULL_COLLINEAR;
+"COLLINEAR_DIST_BETWEEN",COLLINEAR_DIST_BETWEEN;
+"COLLINEAR_DIST_IN_CLOSED_SEGMENT",COLLINEAR_DIST_IN_CLOSED_SEGMENT;
+"COLLINEAR_DIST_IN_OPEN_SEGMENT",COLLINEAR_DIST_IN_OPEN_SEGMENT;
+"COLLINEAR_EMPTY",COLLINEAR_EMPTY;
+"COLLINEAR_EXTREME_POINTS",COLLINEAR_EXTREME_POINTS;
+"COLLINEAR_IMP_COPLANAR",COLLINEAR_IMP_COPLANAR;
+"COLLINEAR_LEMMA",COLLINEAR_LEMMA;
+"COLLINEAR_LEMMA_ALT",COLLINEAR_LEMMA_ALT;
+"COLLINEAR_LINEAR_IMAGE",COLLINEAR_LINEAR_IMAGE;
+"COLLINEAR_LINEAR_IMAGE_EQ",COLLINEAR_LINEAR_IMAGE_EQ;
+"COLLINEAR_MIDPOINT",COLLINEAR_MIDPOINT;
+"COLLINEAR_SEGMENT",COLLINEAR_SEGMENT;
+"COLLINEAR_SING",COLLINEAR_SING;
+"COLLINEAR_SMALL",COLLINEAR_SMALL;
+"COLLINEAR_SUBSET",COLLINEAR_SUBSET;
+"COLLINEAR_TRANSLATION",COLLINEAR_TRANSLATION;
+"COLLINEAR_TRANSLATION_EQ",COLLINEAR_TRANSLATION_EQ;
+"COLLINEAR_TRIPLES",COLLINEAR_TRIPLES;
+"COLUMNS_IMAGE_BASIS",COLUMNS_IMAGE_BASIS;
+"COLUMNS_TRANSP",COLUMNS_TRANSP;
+"COLUMN_TRANSP",COLUMN_TRANSP;
+"COMMA_DEF",COMMA_DEF;
+"COMPACT_AFFINITY",COMPACT_AFFINITY;
+"COMPACT_ARC_IMAGE",COMPACT_ARC_IMAGE;
+"COMPACT_ATTAINS_INF",COMPACT_ATTAINS_INF;
+"COMPACT_ATTAINS_SUP",COMPACT_ATTAINS_SUP;
+"COMPACT_CBALL",COMPACT_CBALL;
+"COMPACT_CHAIN",COMPACT_CHAIN;
+"COMPACT_CLOSED_DIFFERENCES",COMPACT_CLOSED_DIFFERENCES;
+"COMPACT_CLOSED_SUMS",COMPACT_CLOSED_SUMS;
+"COMPACT_CLOSURE",COMPACT_CLOSURE;
+"COMPACT_CONTINUOUS_IMAGE",COMPACT_CONTINUOUS_IMAGE;
+"COMPACT_CONTINUOUS_IMAGE_EQ",COMPACT_CONTINUOUS_IMAGE_EQ;
+"COMPACT_CONVEX_COLLINEAR_SEGMENT",COMPACT_CONVEX_COLLINEAR_SEGMENT;
+"COMPACT_CONVEX_COMBINATIONS",COMPACT_CONVEX_COMBINATIONS;
+"COMPACT_CONVEX_HULL",COMPACT_CONVEX_HULL;
+"COMPACT_DIFF",COMPACT_DIFF;
+"COMPACT_DIFFERENCES",COMPACT_DIFFERENCES;
+"COMPACT_EMPTY",COMPACT_EMPTY;
+"COMPACT_EQ_BOLZANO_WEIERSTRASS",COMPACT_EQ_BOLZANO_WEIERSTRASS;
+"COMPACT_EQ_BOUNDED_CLOSED",COMPACT_EQ_BOUNDED_CLOSED;
+"COMPACT_EQ_HEINE_BOREL",COMPACT_EQ_HEINE_BOREL;
+"COMPACT_EQ_HEINE_BOREL_SUBTOPOLOGY",COMPACT_EQ_HEINE_BOREL_SUBTOPOLOGY;
+"COMPACT_FIP",COMPACT_FIP;
+"COMPACT_FRONTIER",COMPACT_FRONTIER;
+"COMPACT_FRONTIER_BOUNDED",COMPACT_FRONTIER_BOUNDED;
+"COMPACT_FRONTIER_LINE_LEMMA",COMPACT_FRONTIER_LINE_LEMMA;
+"COMPACT_IMP_BOUNDED",COMPACT_IMP_BOUNDED;
+"COMPACT_IMP_CLOSED",COMPACT_IMP_CLOSED;
+"COMPACT_IMP_COMPLETE",COMPACT_IMP_COMPLETE;
+"COMPACT_IMP_FIP",COMPACT_IMP_FIP;
+"COMPACT_IMP_HEINE_BOREL",COMPACT_IMP_HEINE_BOREL;
+"COMPACT_IMP_TOTALLY_BOUNDED",COMPACT_IMP_TOTALLY_BOUNDED;
+"COMPACT_INSERT",COMPACT_INSERT;
+"COMPACT_INTER",COMPACT_INTER;
+"COMPACT_INTERS",COMPACT_INTERS;
+"COMPACT_INTERVAL",COMPACT_INTERVAL;
+"COMPACT_INTERVAL_EQ",COMPACT_INTERVAL_EQ;
+"COMPACT_INTER_CLOSED",COMPACT_INTER_CLOSED;
+"COMPACT_LEMMA",COMPACT_LEMMA;
+"COMPACT_LINEAR_IMAGE",COMPACT_LINEAR_IMAGE;
+"COMPACT_LINEAR_IMAGE_EQ",COMPACT_LINEAR_IMAGE_EQ;
+"COMPACT_NEGATIONS",COMPACT_NEGATIONS;
+"COMPACT_NEST",COMPACT_NEST;
+"COMPACT_OPEN",COMPACT_OPEN;
+"COMPACT_PATH_IMAGE",COMPACT_PATH_IMAGE;
+"COMPACT_PCROSS",COMPACT_PCROSS;
+"COMPACT_PCROSS_EQ",COMPACT_PCROSS_EQ;
+"COMPACT_REAL_LEMMA",COMPACT_REAL_LEMMA;
+"COMPACT_RELATIVE_BOUNDARY",COMPACT_RELATIVE_BOUNDARY;
+"COMPACT_RELATIVE_FRONTIER",COMPACT_RELATIVE_FRONTIER;
+"COMPACT_RELATIVE_FRONTIER_BOUNDED",COMPACT_RELATIVE_FRONTIER_BOUNDED;
+"COMPACT_SCALING",COMPACT_SCALING;
+"COMPACT_SEGMENT",COMPACT_SEGMENT;
+"COMPACT_SEQUENCE_WITH_LIMIT",COMPACT_SEQUENCE_WITH_LIMIT;
+"COMPACT_SIMPLEX",COMPACT_SIMPLEX;
+"COMPACT_SIMPLE_PATH_IMAGE",COMPACT_SIMPLE_PATH_IMAGE;
+"COMPACT_SING",COMPACT_SING;
+"COMPACT_SLICE",COMPACT_SLICE;
+"COMPACT_SPHERE",COMPACT_SPHERE;
+"COMPACT_SUBSET_FRONTIER_RETRACTION",COMPACT_SUBSET_FRONTIER_RETRACTION;
+"COMPACT_SUMS",COMPACT_SUMS;
+"COMPACT_SUP_MAXDISTANCE",COMPACT_SUP_MAXDISTANCE;
+"COMPACT_TRANSLATION",COMPACT_TRANSLATION;
+"COMPACT_TRANSLATION_EQ",COMPACT_TRANSLATION_EQ;
+"COMPACT_UNIFORMLY_CONTINUOUS",COMPACT_UNIFORMLY_CONTINUOUS;
+"COMPACT_UNIFORMLY_EQUICONTINUOUS",COMPACT_UNIFORMLY_EQUICONTINUOUS;
+"COMPACT_UNION",COMPACT_UNION;
+"COMPACT_UNIONS",COMPACT_UNIONS;
+"COMPACT_VALID_PATH_IMAGE",COMPACT_VALID_PATH_IMAGE;
+"COMPLETE_EQ_CLOSED",COMPLETE_EQ_CLOSED;
+"COMPLETE_FACE_TOP",COMPLETE_FACE_TOP;
+"COMPLETE_INJECTIVE_LINEAR_IMAGE",COMPLETE_INJECTIVE_LINEAR_IMAGE;
+"COMPLETE_INJECTIVE_LINEAR_IMAGE_EQ",COMPLETE_INJECTIVE_LINEAR_IMAGE_EQ;
+"COMPLETE_ISOMETRIC_IMAGE",COMPLETE_ISOMETRIC_IMAGE;
+"COMPLETE_SUBSPACE",COMPLETE_SUBSPACE;
+"COMPLETE_TRANSLATION_EQ",COMPLETE_TRANSLATION_EQ;
+"COMPLETE_UNIV",COMPLETE_UNIV;
+"COMPLEX",COMPLEX;
+"COMPLEX_ADD2_SUB2",COMPLEX_ADD2_SUB2;
+"COMPLEX_ADD_AC",COMPLEX_ADD_AC;
+"COMPLEX_ADD_ASSOC",COMPLEX_ADD_ASSOC;
+"COMPLEX_ADD_CCOS",COMPLEX_ADD_CCOS;
+"COMPLEX_ADD_CNJ",COMPLEX_ADD_CNJ;
+"COMPLEX_ADD_CSIN",COMPLEX_ADD_CSIN;
+"COMPLEX_ADD_CTAN",COMPLEX_ADD_CTAN;
+"COMPLEX_ADD_LDISTRIB",COMPLEX_ADD_LDISTRIB;
+"COMPLEX_ADD_LID",COMPLEX_ADD_LID;
+"COMPLEX_ADD_LINV",COMPLEX_ADD_LINV;
+"COMPLEX_ADD_RDISTRIB",COMPLEX_ADD_RDISTRIB;
+"COMPLEX_ADD_RID",COMPLEX_ADD_RID;
+"COMPLEX_ADD_RINV",COMPLEX_ADD_RINV;
+"COMPLEX_ADD_SUB",COMPLEX_ADD_SUB;
+"COMPLEX_ADD_SUB2",COMPLEX_ADD_SUB2;
+"COMPLEX_ADD_SYM",COMPLEX_ADD_SYM;
+"COMPLEX_BASIS",COMPLEX_BASIS;
+"COMPLEX_CMUL",COMPLEX_CMUL;
+"COMPLEX_DERIVATIVE_ADD",COMPLEX_DERIVATIVE_ADD;
+"COMPLEX_DERIVATIVE_ADD_AT",COMPLEX_DERIVATIVE_ADD_AT;
+"COMPLEX_DERIVATIVE_CHAIN",COMPLEX_DERIVATIVE_CHAIN;
+"COMPLEX_DERIVATIVE_COMPOSE_LINEAR",COMPLEX_DERIVATIVE_COMPOSE_LINEAR;
+"COMPLEX_DERIVATIVE_CONST",COMPLEX_DERIVATIVE_CONST;
+"COMPLEX_DERIVATIVE_ID",COMPLEX_DERIVATIVE_ID;
+"COMPLEX_DERIVATIVE_JACOBIAN",COMPLEX_DERIVATIVE_JACOBIAN;
+"COMPLEX_DERIVATIVE_LINEAR",COMPLEX_DERIVATIVE_LINEAR;
+"COMPLEX_DERIVATIVE_LMUL",COMPLEX_DERIVATIVE_LMUL;
+"COMPLEX_DERIVATIVE_LMUL_AT",COMPLEX_DERIVATIVE_LMUL_AT;
+"COMPLEX_DERIVATIVE_MUL",COMPLEX_DERIVATIVE_MUL;
+"COMPLEX_DERIVATIVE_MUL_AT",COMPLEX_DERIVATIVE_MUL_AT;
+"COMPLEX_DERIVATIVE_RMUL",COMPLEX_DERIVATIVE_RMUL;
+"COMPLEX_DERIVATIVE_RMUL_AT",COMPLEX_DERIVATIVE_RMUL_AT;
+"COMPLEX_DERIVATIVE_SUB",COMPLEX_DERIVATIVE_SUB;
+"COMPLEX_DERIVATIVE_SUB_AT",COMPLEX_DERIVATIVE_SUB_AT;
+"COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN",COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN;
+"COMPLEX_DERIVATIVE_UNIQUE_AT",COMPLEX_DERIVATIVE_UNIQUE_AT;
+"COMPLEX_DIFFERENTIABLE_ADD",COMPLEX_DIFFERENTIABLE_ADD;
+"COMPLEX_DIFFERENTIABLE_AT_CACS",COMPLEX_DIFFERENTIABLE_AT_CACS;
+"COMPLEX_DIFFERENTIABLE_AT_CASN",COMPLEX_DIFFERENTIABLE_AT_CASN;
+"COMPLEX_DIFFERENTIABLE_AT_CATN",COMPLEX_DIFFERENTIABLE_AT_CATN;
+"COMPLEX_DIFFERENTIABLE_AT_CCOS",COMPLEX_DIFFERENTIABLE_AT_CCOS;
+"COMPLEX_DIFFERENTIABLE_AT_CEXP",COMPLEX_DIFFERENTIABLE_AT_CEXP;
+"COMPLEX_DIFFERENTIABLE_AT_CLOG",COMPLEX_DIFFERENTIABLE_AT_CLOG;
+"COMPLEX_DIFFERENTIABLE_AT_CSIN",COMPLEX_DIFFERENTIABLE_AT_CSIN;
+"COMPLEX_DIFFERENTIABLE_AT_CSQRT",COMPLEX_DIFFERENTIABLE_AT_CSQRT;
+"COMPLEX_DIFFERENTIABLE_AT_CTAN",COMPLEX_DIFFERENTIABLE_AT_CTAN;
+"COMPLEX_DIFFERENTIABLE_AT_WITHIN",COMPLEX_DIFFERENTIABLE_AT_WITHIN;
+"COMPLEX_DIFFERENTIABLE_BOUND",COMPLEX_DIFFERENTIABLE_BOUND;
+"COMPLEX_DIFFERENTIABLE_CARATHEODORY_AT",COMPLEX_DIFFERENTIABLE_CARATHEODORY_AT;
+"COMPLEX_DIFFERENTIABLE_CARATHEODORY_WITHIN",COMPLEX_DIFFERENTIABLE_CARATHEODORY_WITHIN;
+"COMPLEX_DIFFERENTIABLE_COMPOSE",COMPLEX_DIFFERENTIABLE_COMPOSE;
+"COMPLEX_DIFFERENTIABLE_COMPOSE_AT",COMPLEX_DIFFERENTIABLE_COMPOSE_AT;
+"COMPLEX_DIFFERENTIABLE_COMPOSE_WITHIN",COMPLEX_DIFFERENTIABLE_COMPOSE_WITHIN;
+"COMPLEX_DIFFERENTIABLE_CONST",COMPLEX_DIFFERENTIABLE_CONST;
+"COMPLEX_DIFFERENTIABLE_CPOW_RIGHT",COMPLEX_DIFFERENTIABLE_CPOW_RIGHT;
+"COMPLEX_DIFFERENTIABLE_DIV_AT",COMPLEX_DIFFERENTIABLE_DIV_AT;
+"COMPLEX_DIFFERENTIABLE_DIV_WITHIN",COMPLEX_DIFFERENTIABLE_DIV_WITHIN;
+"COMPLEX_DIFFERENTIABLE_EQ_CONFORMAL",COMPLEX_DIFFERENTIABLE_EQ_CONFORMAL;
+"COMPLEX_DIFFERENTIABLE_ID",COMPLEX_DIFFERENTIABLE_ID;
+"COMPLEX_DIFFERENTIABLE_IMP_CONTINUOUS_AT",COMPLEX_DIFFERENTIABLE_IMP_CONTINUOUS_AT;
+"COMPLEX_DIFFERENTIABLE_IMP_DIFFERENTIABLE",COMPLEX_DIFFERENTIABLE_IMP_DIFFERENTIABLE;
+"COMPLEX_DIFFERENTIABLE_INV_AT",COMPLEX_DIFFERENTIABLE_INV_AT;
+"COMPLEX_DIFFERENTIABLE_INV_WITHIN",COMPLEX_DIFFERENTIABLE_INV_WITHIN;
+"COMPLEX_DIFFERENTIABLE_LINEAR",COMPLEX_DIFFERENTIABLE_LINEAR;
+"COMPLEX_DIFFERENTIABLE_MUL_AT",COMPLEX_DIFFERENTIABLE_MUL_AT;
+"COMPLEX_DIFFERENTIABLE_MUL_WITHIN",COMPLEX_DIFFERENTIABLE_MUL_WITHIN;
+"COMPLEX_DIFFERENTIABLE_NEG",COMPLEX_DIFFERENTIABLE_NEG;
+"COMPLEX_DIFFERENTIABLE_POW_AT",COMPLEX_DIFFERENTIABLE_POW_AT;
+"COMPLEX_DIFFERENTIABLE_POW_WITHIN",COMPLEX_DIFFERENTIABLE_POW_WITHIN;
+"COMPLEX_DIFFERENTIABLE_SUB",COMPLEX_DIFFERENTIABLE_SUB;
+"COMPLEX_DIFFERENTIABLE_TRANSFORM_AT",COMPLEX_DIFFERENTIABLE_TRANSFORM_AT;
+"COMPLEX_DIFFERENTIABLE_TRANSFORM_WITHIN",COMPLEX_DIFFERENTIABLE_TRANSFORM_WITHIN;
+"COMPLEX_DIFFERENTIABLE_WITHIN_CACS",COMPLEX_DIFFERENTIABLE_WITHIN_CACS;
+"COMPLEX_DIFFERENTIABLE_WITHIN_CASN",COMPLEX_DIFFERENTIABLE_WITHIN_CASN;
+"COMPLEX_DIFFERENTIABLE_WITHIN_CATN",COMPLEX_DIFFERENTIABLE_WITHIN_CATN;
+"COMPLEX_DIFFERENTIABLE_WITHIN_CCOS",COMPLEX_DIFFERENTIABLE_WITHIN_CCOS;
+"COMPLEX_DIFFERENTIABLE_WITHIN_CEXP",COMPLEX_DIFFERENTIABLE_WITHIN_CEXP;
+"COMPLEX_DIFFERENTIABLE_WITHIN_CLOG",COMPLEX_DIFFERENTIABLE_WITHIN_CLOG;
+"COMPLEX_DIFFERENTIABLE_WITHIN_CSIN",COMPLEX_DIFFERENTIABLE_WITHIN_CSIN;
+"COMPLEX_DIFFERENTIABLE_WITHIN_CSQRT",COMPLEX_DIFFERENTIABLE_WITHIN_CSQRT;
+"COMPLEX_DIFFERENTIABLE_WITHIN_CTAN",COMPLEX_DIFFERENTIABLE_WITHIN_CTAN;
+"COMPLEX_DIFFERENTIABLE_WITHIN_OPEN",COMPLEX_DIFFERENTIABLE_WITHIN_OPEN;
+"COMPLEX_DIFFERENTIABLE_WITHIN_SUBSET",COMPLEX_DIFFERENTIABLE_WITHIN_SUBSET;
+"COMPLEX_DIFFSQ",COMPLEX_DIFFSQ;
+"COMPLEX_DIFF_CHAIN_AT",COMPLEX_DIFF_CHAIN_AT;
+"COMPLEX_DIFF_CHAIN_WITHIN",COMPLEX_DIFF_CHAIN_WITHIN;
+"COMPLEX_DIV_1",COMPLEX_DIV_1;
+"COMPLEX_DIV_CNJ",COMPLEX_DIV_CNJ;
+"COMPLEX_DIV_EQ_0",COMPLEX_DIV_EQ_0;
+"COMPLEX_DIV_LMUL",COMPLEX_DIV_LMUL;
+"COMPLEX_DIV_POW",COMPLEX_DIV_POW;
+"COMPLEX_DIV_REFL",COMPLEX_DIV_REFL;
+"COMPLEX_DIV_RMUL",COMPLEX_DIV_RMUL;
+"COMPLEX_DIV_ROTATION",COMPLEX_DIV_ROTATION;
+"COMPLEX_ENTIRE",COMPLEX_ENTIRE;
+"COMPLEX_EQ",COMPLEX_EQ;
+"COMPLEX_EQ_0",COMPLEX_EQ_0;
+"COMPLEX_EQ_ADD_LCANCEL",COMPLEX_EQ_ADD_LCANCEL;
+"COMPLEX_EQ_ADD_LCANCEL_0",COMPLEX_EQ_ADD_LCANCEL_0;
+"COMPLEX_EQ_ADD_RCANCEL",COMPLEX_EQ_ADD_RCANCEL;
+"COMPLEX_EQ_ADD_RCANCEL_0",COMPLEX_EQ_ADD_RCANCEL_0;
+"COMPLEX_EQ_CEXP",COMPLEX_EQ_CEXP;
+"COMPLEX_EQ_MUL_LCANCEL",COMPLEX_EQ_MUL_LCANCEL;
+"COMPLEX_EQ_MUL_RCANCEL",COMPLEX_EQ_MUL_RCANCEL;
+"COMPLEX_EQ_NEG2",COMPLEX_EQ_NEG2;
+"COMPLEX_EQ_SUB_LADD",COMPLEX_EQ_SUB_LADD;
+"COMPLEX_EQ_SUB_RADD",COMPLEX_EQ_SUB_RADD;
+"COMPLEX_EXPAND",COMPLEX_EXPAND;
+"COMPLEX_INTEGER",COMPLEX_INTEGER;
+"COMPLEX_INV_0",COMPLEX_INV_0;
+"COMPLEX_INV_1",COMPLEX_INV_1;
+"COMPLEX_INV_CNJ",COMPLEX_INV_CNJ;
+"COMPLEX_INV_DIV",COMPLEX_INV_DIV;
+"COMPLEX_INV_EQ_0",COMPLEX_INV_EQ_0;
+"COMPLEX_INV_EQ_1",COMPLEX_INV_EQ_1;
+"COMPLEX_INV_II",COMPLEX_INV_II;
+"COMPLEX_INV_INV",COMPLEX_INV_INV;
+"COMPLEX_INV_MUL",COMPLEX_INV_MUL;
+"COMPLEX_INV_NEG",COMPLEX_INV_NEG;
+"COMPLEX_IN_BALL_0",COMPLEX_IN_BALL_0;
+"COMPLEX_IN_CBALL_0",COMPLEX_IN_CBALL_0;
+"COMPLEX_IN_SPHERE_0",COMPLEX_IN_SPHERE_0;
+"COMPLEX_L1_LE_NORM",COMPLEX_L1_LE_NORM;
+"COMPLEX_LNEG_UNIQ",COMPLEX_LNEG_UNIQ;
+"COMPLEX_MUL_2",COMPLEX_MUL_2;
+"COMPLEX_MUL_AC",COMPLEX_MUL_AC;
+"COMPLEX_MUL_ASSOC",COMPLEX_MUL_ASSOC;
+"COMPLEX_MUL_CCOS_CCOS",COMPLEX_MUL_CCOS_CCOS;
+"COMPLEX_MUL_CCOS_CSIN",COMPLEX_MUL_CCOS_CSIN;
+"COMPLEX_MUL_CNJ",COMPLEX_MUL_CNJ;
+"COMPLEX_MUL_CSIN_CCOS",COMPLEX_MUL_CSIN_CCOS;
+"COMPLEX_MUL_CSIN_CSIN",COMPLEX_MUL_CSIN_CSIN;
+"COMPLEX_MUL_LID",COMPLEX_MUL_LID;
+"COMPLEX_MUL_LINV",COMPLEX_MUL_LINV;
+"COMPLEX_MUL_LNEG",COMPLEX_MUL_LNEG;
+"COMPLEX_MUL_LZERO",COMPLEX_MUL_LZERO;
+"COMPLEX_MUL_RID",COMPLEX_MUL_RID;
+"COMPLEX_MUL_RINV",COMPLEX_MUL_RINV;
+"COMPLEX_MUL_RNEG",COMPLEX_MUL_RNEG;
+"COMPLEX_MUL_RZERO",COMPLEX_MUL_RZERO;
+"COMPLEX_MUL_SYM",COMPLEX_MUL_SYM;
+"COMPLEX_MVT",COMPLEX_MVT;
+"COMPLEX_MVT_LINE",COMPLEX_MVT_LINE;
+"COMPLEX_NEG_0",COMPLEX_NEG_0;
+"COMPLEX_NEG_ADD",COMPLEX_NEG_ADD;
+"COMPLEX_NEG_EQ",COMPLEX_NEG_EQ;
+"COMPLEX_NEG_EQ_0",COMPLEX_NEG_EQ_0;
+"COMPLEX_NEG_INV",COMPLEX_NEG_INV;
+"COMPLEX_NEG_LMUL",COMPLEX_NEG_LMUL;
+"COMPLEX_NEG_MINUS1",COMPLEX_NEG_MINUS1;
+"COMPLEX_NEG_MUL2",COMPLEX_NEG_MUL2;
+"COMPLEX_NEG_NEG",COMPLEX_NEG_NEG;
+"COMPLEX_NEG_RMUL",COMPLEX_NEG_RMUL;
+"COMPLEX_NEG_SUB",COMPLEX_NEG_SUB;
+"COMPLEX_NORM_0",COMPLEX_NORM_0;
+"COMPLEX_NORM_ABS_NORM",COMPLEX_NORM_ABS_NORM;
+"COMPLEX_NORM_CNJ",COMPLEX_NORM_CNJ;
+"COMPLEX_NORM_CX",COMPLEX_NORM_CX;
+"COMPLEX_NORM_DIV",COMPLEX_NORM_DIV;
+"COMPLEX_NORM_EQ_1_CEXP",COMPLEX_NORM_EQ_1_CEXP;
+"COMPLEX_NORM_GE_RE_IM",COMPLEX_NORM_GE_RE_IM;
+"COMPLEX_NORM_II",COMPLEX_NORM_II;
+"COMPLEX_NORM_INV",COMPLEX_NORM_INV;
+"COMPLEX_NORM_LE_RE_IM",COMPLEX_NORM_LE_RE_IM;
+"COMPLEX_NORM_MUL",COMPLEX_NORM_MUL;
+"COMPLEX_NORM_NUM",COMPLEX_NORM_NUM;
+"COMPLEX_NORM_NZ",COMPLEX_NORM_NZ;
+"COMPLEX_NORM_POW",COMPLEX_NORM_POW;
+"COMPLEX_NORM_POW_2",COMPLEX_NORM_POW_2;
+"COMPLEX_NORM_TRIANGLE_SUB",COMPLEX_NORM_TRIANGLE_SUB;
+"COMPLEX_NORM_VSUM_BOUND",COMPLEX_NORM_VSUM_BOUND;
+"COMPLEX_NORM_VSUM_BOUND_SUBSET",COMPLEX_NORM_VSUM_BOUND_SUBSET;
+"COMPLEX_NORM_VSUM_SUM_RE",COMPLEX_NORM_VSUM_SUM_RE;
+"COMPLEX_NORM_ZERO",COMPLEX_NORM_ZERO;
+"COMPLEX_NOT_ROOT_UNITY",COMPLEX_NOT_ROOT_UNITY;
+"COMPLEX_POLYFUN_EQ_0",COMPLEX_POLYFUN_EQ_0;
+"COMPLEX_POLYFUN_EQ_CONST",COMPLEX_POLYFUN_EQ_CONST;
+"COMPLEX_POLYFUN_EXTREMAL",COMPLEX_POLYFUN_EXTREMAL;
+"COMPLEX_POLYFUN_EXTREMAL_LEMMA",COMPLEX_POLYFUN_EXTREMAL_LEMMA;
+"COMPLEX_POLYFUN_FINITE_ROOTS",COMPLEX_POLYFUN_FINITE_ROOTS;
+"COMPLEX_POLYFUN_LINEAR_FACTOR",COMPLEX_POLYFUN_LINEAR_FACTOR;
+"COMPLEX_POLYFUN_LINEAR_FACTOR_ROOT",COMPLEX_POLYFUN_LINEAR_FACTOR_ROOT;
+"COMPLEX_POLYFUN_ROOTBOUND",COMPLEX_POLYFUN_ROOTBOUND;
+"COMPLEX_POLY_CLAUSES",COMPLEX_POLY_CLAUSES;
+"COMPLEX_POLY_NEG_CLAUSES",COMPLEX_POLY_NEG_CLAUSES;
+"COMPLEX_POW_1",COMPLEX_POW_1;
+"COMPLEX_POW_2",COMPLEX_POW_2;
+"COMPLEX_POW_ADD",COMPLEX_POW_ADD;
+"COMPLEX_POW_DIV",COMPLEX_POW_DIV;
+"COMPLEX_POW_EQ_0",COMPLEX_POW_EQ_0;
+"COMPLEX_POW_EQ_1",COMPLEX_POW_EQ_1;
+"COMPLEX_POW_II_2",COMPLEX_POW_II_2;
+"COMPLEX_POW_INV",COMPLEX_POW_INV;
+"COMPLEX_POW_MUL",COMPLEX_POW_MUL;
+"COMPLEX_POW_NEG",COMPLEX_POW_NEG;
+"COMPLEX_POW_ONE",COMPLEX_POW_ONE;
+"COMPLEX_POW_POW",COMPLEX_POW_POW;
+"COMPLEX_POW_ZERO",COMPLEX_POW_ZERO;
+"COMPLEX_RNEG_UNIQ",COMPLEX_RNEG_UNIQ;
+"COMPLEX_ROOTS_UNITY",COMPLEX_ROOTS_UNITY;
+"COMPLEX_ROOT_POLYFUN",COMPLEX_ROOT_POLYFUN;
+"COMPLEX_ROOT_UNITY",COMPLEX_ROOT_UNITY;
+"COMPLEX_ROOT_UNITY_EQ",COMPLEX_ROOT_UNITY_EQ;
+"COMPLEX_ROOT_UNITY_EQ_1",COMPLEX_ROOT_UNITY_EQ_1;
+"COMPLEX_SQNORM",COMPLEX_SQNORM;
+"COMPLEX_STONE_WEIERSTRASS",COMPLEX_STONE_WEIERSTRASS;
+"COMPLEX_STONE_WEIERSTRASS_ALT",COMPLEX_STONE_WEIERSTRASS_ALT;
+"COMPLEX_SUB_0",COMPLEX_SUB_0;
+"COMPLEX_SUB_ADD",COMPLEX_SUB_ADD;
+"COMPLEX_SUB_ADD2",COMPLEX_SUB_ADD2;
+"COMPLEX_SUB_CCOS",COMPLEX_SUB_CCOS;
+"COMPLEX_SUB_CSIN",COMPLEX_SUB_CSIN;
+"COMPLEX_SUB_CTAN",COMPLEX_SUB_CTAN;
+"COMPLEX_SUB_LDISTRIB",COMPLEX_SUB_LDISTRIB;
+"COMPLEX_SUB_LNEG",COMPLEX_SUB_LNEG;
+"COMPLEX_SUB_LZERO",COMPLEX_SUB_LZERO;
+"COMPLEX_SUB_NEG2",COMPLEX_SUB_NEG2;
+"COMPLEX_SUB_POLYFUN",COMPLEX_SUB_POLYFUN;
+"COMPLEX_SUB_POLYFUN_ALT",COMPLEX_SUB_POLYFUN_ALT;
+"COMPLEX_SUB_POW",COMPLEX_SUB_POW;
+"COMPLEX_SUB_POW_L1",COMPLEX_SUB_POW_L1;
+"COMPLEX_SUB_POW_R1",COMPLEX_SUB_POW_R1;
+"COMPLEX_SUB_RDISTRIB",COMPLEX_SUB_RDISTRIB;
+"COMPLEX_SUB_REFL",COMPLEX_SUB_REFL;
+"COMPLEX_SUB_RNEG",COMPLEX_SUB_RNEG;
+"COMPLEX_SUB_RZERO",COMPLEX_SUB_RZERO;
+"COMPLEX_SUB_SUB",COMPLEX_SUB_SUB;
+"COMPLEX_SUB_SUB2",COMPLEX_SUB_SUB2;
+"COMPLEX_SUB_TRIANGLE",COMPLEX_SUB_TRIANGLE;
+"COMPLEX_TAYLOR",COMPLEX_TAYLOR;
+"COMPLEX_TAYLOR_MVT",COMPLEX_TAYLOR_MVT;
+"COMPLEX_TRAD",COMPLEX_TRAD;
+"COMPLEX_UNIMODULAR_POLAR",COMPLEX_UNIMODULAR_POLAR;
+"COMPLEX_VEC_0",COMPLEX_VEC_0;
+"COMPONENT",COMPONENT;
+"COMPONENTS_EQ",COMPONENTS_EQ;
+"COMPONENTS_EQ_EMPTY",COMPONENTS_EQ_EMPTY;
+"COMPONENTS_EQ_SING",COMPONENTS_EQ_SING;
+"COMPONENTS_EQ_SING_EXISTS",COMPONENTS_EQ_SING_EXISTS;
+"COMPONENTS_LINEAR_IMAGE",COMPONENTS_LINEAR_IMAGE;
+"COMPONENTS_MAXIMAL",COMPONENTS_MAXIMAL;
+"COMPONENTS_NONOVERLAP",COMPONENTS_NONOVERLAP;
+"COMPONENTS_OPEN_UNIQUE",COMPONENTS_OPEN_UNIQUE;
+"COMPONENTS_TRANSLATION",COMPONENTS_TRANSLATION;
+"COMPONENTS_UNIQUE",COMPONENTS_UNIQUE;
+"COMPONENTS_UNIQUE_EQ",COMPONENTS_UNIQUE_EQ;
+"COMPONENT_COMPLEMENT_CONNECTED",COMPONENT_COMPLEMENT_CONNECTED;
+"COMPONENT_LE_INFNORM",COMPONENT_LE_INFNORM;
+"COMPONENT_LE_NORM",COMPONENT_LE_NORM;
+"CONDENSATION_POINTS_EQ_EMPTY",CONDENSATION_POINTS_EQ_EMPTY;
+"CONDENSATION_POINT_IMP_LIMPT",CONDENSATION_POINT_IMP_LIMPT;
+"CONDENSATION_POINT_INFINITE_BALL",CONDENSATION_POINT_INFINITE_BALL;
+"CONDENSATION_POINT_INFINITE_CBALL",CONDENSATION_POINT_INFINITE_CBALL;
+"COND_ABS",COND_ABS;
+"COND_CLAUSES",COND_CLAUSES;
+"COND_COMPONENT",COND_COMPONENT;
+"COND_DEF",COND_DEF;
+"COND_ELIM_THM",COND_ELIM_THM;
+"COND_EXPAND",COND_EXPAND;
+"COND_ID",COND_ID;
+"COND_RAND",COND_RAND;
+"COND_RATOR",COND_RATOR;
+"CONGRUENT_IMAGE_STD_SIMPLEX",CONGRUENT_IMAGE_STD_SIMPLEX;
+"CONIC_CONIC_HULL",CONIC_CONIC_HULL;
+"CONIC_CONTAINS_0",CONIC_CONTAINS_0;
+"CONIC_CONVEX_CONE_HULL",CONIC_CONVEX_CONE_HULL;
+"CONIC_EMPTY",CONIC_EMPTY;
+"CONIC_HALFSPACE_GE",CONIC_HALFSPACE_GE;
+"CONIC_HALFSPACE_LE",CONIC_HALFSPACE_LE;
+"CONIC_HULL_EMPTY",CONIC_HULL_EMPTY;
+"CONIC_HULL_EQ",CONIC_HULL_EQ;
+"CONIC_HULL_EQ_EMPTY",CONIC_HULL_EQ_EMPTY;
+"CONIC_HULL_EXPLICIT",CONIC_HULL_EXPLICIT;
+"CONIC_HULL_LINEAR_IMAGE",CONIC_HULL_LINEAR_IMAGE;
+"CONIC_HULL_SUBSET_CONVEX_CONE_HULL",CONIC_HULL_SUBSET_CONVEX_CONE_HULL;
+"CONIC_INTERS",CONIC_INTERS;
+"CONIC_LINEAR_IMAGE",CONIC_LINEAR_IMAGE;
+"CONIC_LINEAR_IMAGE_EQ",CONIC_LINEAR_IMAGE_EQ;
+"CONIC_NEGATIONS",CONIC_NEGATIONS;
+"CONIC_PCROSS",CONIC_PCROSS;
+"CONIC_PCROSS_EQ",CONIC_PCROSS_EQ;
+"CONIC_POSITIVE_ORTHANT",CONIC_POSITIVE_ORTHANT;
+"CONIC_SPAN",CONIC_SPAN;
+"CONIC_SUMS",CONIC_SUMS;
+"CONIC_UNIV",CONIC_UNIV;
+"CONJ_ACI",CONJ_ACI;
+"CONJ_ASSOC",CONJ_ASSOC;
+"CONJ_SYM",CONJ_SYM;
+"CONNECTED_ANNULUS",CONNECTED_ANNULUS;
+"CONNECTED_ARC_COMPLEMENT",CONNECTED_ARC_COMPLEMENT;
+"CONNECTED_ARC_IMAGE",CONNECTED_ARC_IMAGE;
+"CONNECTED_BALL",CONNECTED_BALL;
+"CONNECTED_CARD_EQ_IFF_NONTRIVIAL",CONNECTED_CARD_EQ_IFF_NONTRIVIAL;
+"CONNECTED_CBALL",CONNECTED_CBALL;
+"CONNECTED_CHAIN",CONNECTED_CHAIN;
+"CONNECTED_CHAIN_GEN",CONNECTED_CHAIN_GEN;
+"CONNECTED_CLOPEN",CONNECTED_CLOPEN;
+"CONNECTED_CLOSED",CONNECTED_CLOSED;
+"CONNECTED_CLOSED_IN",CONNECTED_CLOSED_IN;
+"CONNECTED_CLOSED_IN_EQ",CONNECTED_CLOSED_IN_EQ;
+"CONNECTED_CLOSED_SET",CONNECTED_CLOSED_SET;
+"CONNECTED_CLOSURE",CONNECTED_CLOSURE;
+"CONNECTED_COMPACT_INTERVAL_1",CONNECTED_COMPACT_INTERVAL_1;
+"CONNECTED_COMPLEMENT_ABSOLUTE_RETRACT",CONNECTED_COMPLEMENT_ABSOLUTE_RETRACT;
+"CONNECTED_COMPLEMENT_BOUNDED_CONVEX",CONNECTED_COMPLEMENT_BOUNDED_CONVEX;
+"CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT",CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT;
+"CONNECTED_COMPONENT_1",CONNECTED_COMPONENT_1;
+"CONNECTED_COMPONENT_1_GEN",CONNECTED_COMPONENT_1_GEN;
+"CONNECTED_COMPONENT_DISJOINT",CONNECTED_COMPONENT_DISJOINT;
+"CONNECTED_COMPONENT_EMPTY",CONNECTED_COMPONENT_EMPTY;
+"CONNECTED_COMPONENT_EQ",CONNECTED_COMPONENT_EQ;
+"CONNECTED_COMPONENT_EQUIVALENCE_RELATION",CONNECTED_COMPONENT_EQUIVALENCE_RELATION;
+"CONNECTED_COMPONENT_EQ_EMPTY",CONNECTED_COMPONENT_EQ_EMPTY;
+"CONNECTED_COMPONENT_EQ_EQ",CONNECTED_COMPONENT_EQ_EQ;
+"CONNECTED_COMPONENT_EQ_SELF",CONNECTED_COMPONENT_EQ_SELF;
+"CONNECTED_COMPONENT_EQ_UNIV",CONNECTED_COMPONENT_EQ_UNIV;
+"CONNECTED_COMPONENT_IDEMP",CONNECTED_COMPONENT_IDEMP;
+"CONNECTED_COMPONENT_IN",CONNECTED_COMPONENT_IN;
+"CONNECTED_COMPONENT_LINEAR_IMAGE",CONNECTED_COMPONENT_LINEAR_IMAGE;
+"CONNECTED_COMPONENT_MAXIMAL",CONNECTED_COMPONENT_MAXIMAL;
+"CONNECTED_COMPONENT_MONO",CONNECTED_COMPONENT_MONO;
+"CONNECTED_COMPONENT_NONOVERLAP",CONNECTED_COMPONENT_NONOVERLAP;
+"CONNECTED_COMPONENT_OF_SUBSET",CONNECTED_COMPONENT_OF_SUBSET;
+"CONNECTED_COMPONENT_OVERLAP",CONNECTED_COMPONENT_OVERLAP;
+"CONNECTED_COMPONENT_REFL",CONNECTED_COMPONENT_REFL;
+"CONNECTED_COMPONENT_REFL_EQ",CONNECTED_COMPONENT_REFL_EQ;
+"CONNECTED_COMPONENT_SET",CONNECTED_COMPONENT_SET;
+"CONNECTED_COMPONENT_SUBSET",CONNECTED_COMPONENT_SUBSET;
+"CONNECTED_COMPONENT_SYM",CONNECTED_COMPONENT_SYM;
+"CONNECTED_COMPONENT_SYM_EQ",CONNECTED_COMPONENT_SYM_EQ;
+"CONNECTED_COMPONENT_TRANS",CONNECTED_COMPONENT_TRANS;
+"CONNECTED_COMPONENT_TRANSLATION",CONNECTED_COMPONENT_TRANSLATION;
+"CONNECTED_COMPONENT_UNIONS",CONNECTED_COMPONENT_UNIONS;
+"CONNECTED_COMPONENT_UNIQUE",CONNECTED_COMPONENT_UNIQUE;
+"CONNECTED_COMPONENT_UNIV",CONNECTED_COMPONENT_UNIV;
+"CONNECTED_CONNECTED_COMPONENT",CONNECTED_CONNECTED_COMPONENT;
+"CONNECTED_CONNECTED_COMPONENT_SET",CONNECTED_CONNECTED_COMPONENT_SET;
+"CONNECTED_CONTINUOUS_IMAGE",CONNECTED_CONTINUOUS_IMAGE;
+"CONNECTED_CONVEX_1",CONNECTED_CONVEX_1;
+"CONNECTED_CONVEX_1_GEN",CONNECTED_CONVEX_1_GEN;
+"CONNECTED_DIFF_BALL",CONNECTED_DIFF_BALL;
+"CONNECTED_DIFF_OPEN_FROM_CLOSED",CONNECTED_DIFF_OPEN_FROM_CLOSED;
+"CONNECTED_DISJOINT_UNIONS_OPEN_UNIQUE",CONNECTED_DISJOINT_UNIONS_OPEN_UNIQUE;
+"CONNECTED_EMPTY",CONNECTED_EMPTY;
+"CONNECTED_EQUIVALENCE_RELATION",CONNECTED_EQUIVALENCE_RELATION;
+"CONNECTED_EQUIVALENCE_RELATION_GEN",CONNECTED_EQUIVALENCE_RELATION_GEN;
+"CONNECTED_EQ_CONNECTED_COMPONENTS_EQ",CONNECTED_EQ_CONNECTED_COMPONENTS_EQ;
+"CONNECTED_EQ_CONNECTED_COMPONENT_EQ",CONNECTED_EQ_CONNECTED_COMPONENT_EQ;
+"CONNECTED_FINITE_IFF_COUNTABLE",CONNECTED_FINITE_IFF_COUNTABLE;
+"CONNECTED_FINITE_IFF_SING",CONNECTED_FINITE_IFF_SING;
+"CONNECTED_IFF_CONNECTED_COMPONENT",CONNECTED_IFF_CONNECTED_COMPONENT;
+"CONNECTED_IMP_PERFECT",CONNECTED_IMP_PERFECT;
+"CONNECTED_IMP_PERFECT_AFF_DIM",CONNECTED_IMP_PERFECT_AFF_DIM;
+"CONNECTED_INDUCTION",CONNECTED_INDUCTION;
+"CONNECTED_INDUCTION_SIMPLE",CONNECTED_INDUCTION_SIMPLE;
+"CONNECTED_INFINITE_IFF_CARD_EQ",CONNECTED_INFINITE_IFF_CARD_EQ;
+"CONNECTED_INTERMEDIATE_CLOSURE",CONNECTED_INTERMEDIATE_CLOSURE;
+"CONNECTED_INTERVAL",CONNECTED_INTERVAL;
+"CONNECTED_INTER_FRONTIER",CONNECTED_INTER_FRONTIER;
+"CONNECTED_INTER_RELATIVE_FRONTIER",CONNECTED_INTER_RELATIVE_FRONTIER;
+"CONNECTED_IVT_COMPONENT",CONNECTED_IVT_COMPONENT;
+"CONNECTED_IVT_HYPERPLANE",CONNECTED_IVT_HYPERPLANE;
+"CONNECTED_LINEAR_IMAGE",CONNECTED_LINEAR_IMAGE;
+"CONNECTED_LINEAR_IMAGE_EQ",CONNECTED_LINEAR_IMAGE_EQ;
+"CONNECTED_NEGATIONS",CONNECTED_NEGATIONS;
+"CONNECTED_NEST",CONNECTED_NEST;
+"CONNECTED_NEST_GEN",CONNECTED_NEST_GEN;
+"CONNECTED_OPEN_ARC_CONNECTED",CONNECTED_OPEN_ARC_CONNECTED;
+"CONNECTED_OPEN_DELETE",CONNECTED_OPEN_DELETE;
+"CONNECTED_OPEN_DIFF_CARD_LT",CONNECTED_OPEN_DIFF_CARD_LT;
+"CONNECTED_OPEN_DIFF_CBALL",CONNECTED_OPEN_DIFF_CBALL;
+"CONNECTED_OPEN_DIFF_COUNTABLE",CONNECTED_OPEN_DIFF_COUNTABLE;
+"CONNECTED_OPEN_IN",CONNECTED_OPEN_IN;
+"CONNECTED_OPEN_IN_DIFF_CARD_LT",CONNECTED_OPEN_IN_DIFF_CARD_LT;
+"CONNECTED_OPEN_IN_EQ",CONNECTED_OPEN_IN_EQ;
+"CONNECTED_OPEN_PATH_CONNECTED",CONNECTED_OPEN_PATH_CONNECTED;
+"CONNECTED_OPEN_SET",CONNECTED_OPEN_SET;
+"CONNECTED_OPEN_VECTOR_POLYNOMIAL_CONNECTED",CONNECTED_OPEN_VECTOR_POLYNOMIAL_CONNECTED;
+"CONNECTED_OUTSIDE",CONNECTED_OUTSIDE;
+"CONNECTED_PATH_IMAGE",CONNECTED_PATH_IMAGE;
+"CONNECTED_PCROSS",CONNECTED_PCROSS;
+"CONNECTED_PCROSS_EQ",CONNECTED_PCROSS_EQ;
+"CONNECTED_PUNCTURED_BALL",CONNECTED_PUNCTURED_BALL;
+"CONNECTED_PUNCTURED_UNIVERSE",CONNECTED_PUNCTURED_UNIVERSE;
+"CONNECTED_REAL_LEMMA",CONNECTED_REAL_LEMMA;
+"CONNECTED_SCALING",CONNECTED_SCALING;
+"CONNECTED_SEGMENT",CONNECTED_SEGMENT;
+"CONNECTED_SEMIOPEN_SEGMENT",CONNECTED_SEMIOPEN_SEGMENT;
+"CONNECTED_SIMPLE_PATH_ENDLESS",CONNECTED_SIMPLE_PATH_ENDLESS;
+"CONNECTED_SIMPLE_PATH_IMAGE",CONNECTED_SIMPLE_PATH_IMAGE;
+"CONNECTED_SING",CONNECTED_SING;
+"CONNECTED_SPHERE",CONNECTED_SPHERE;
+"CONNECTED_SPHERE_EQ",CONNECTED_SPHERE_EQ;
+"CONNECTED_SUMS",CONNECTED_SUMS;
+"CONNECTED_TRANSLATION",CONNECTED_TRANSLATION;
+"CONNECTED_TRANSLATION_EQ",CONNECTED_TRANSLATION_EQ;
+"CONNECTED_UNION",CONNECTED_UNION;
+"CONNECTED_UNIONS",CONNECTED_UNIONS;
+"CONNECTED_UNION_CLOPEN_IN_COMPLEMENT",CONNECTED_UNION_CLOPEN_IN_COMPLEMENT;
+"CONNECTED_UNION_STRONG",CONNECTED_UNION_STRONG;
+"CONNECTED_UNIV",CONNECTED_UNIV;
+"CONNECTED_VALID_PATH_IMAGE",CONNECTED_VALID_PATH_IMAGE;
+"CONNECTED_WITH_INSIDE",CONNECTED_WITH_INSIDE;
+"CONNECTED_WITH_OUTSIDE",CONNECTED_WITH_OUTSIDE;
+"CONSTR",CONSTR;
+"CONSTR_BOT",CONSTR_BOT;
+"CONSTR_IND",CONSTR_IND;
+"CONSTR_INJ",CONSTR_INJ;
+"CONSTR_REC",CONSTR_REC;
+"CONS_11",CONS_11;
+"CONS_HD_TL",CONS_HD_TL;
+"CONTENT_0_SUBSET",CONTENT_0_SUBSET;
+"CONTENT_0_SUBSET_GEN",CONTENT_0_SUBSET_GEN;
+"CONTENT_1",CONTENT_1;
+"CONTENT_CLOSED_INTERVAL",CONTENT_CLOSED_INTERVAL;
+"CONTENT_CLOSED_INTERVAL_CASES",CONTENT_CLOSED_INTERVAL_CASES;
+"CONTENT_DOUBLESPLIT",CONTENT_DOUBLESPLIT;
+"CONTENT_EMPTY",CONTENT_EMPTY;
+"CONTENT_EQ_0",CONTENT_EQ_0;
+"CONTENT_EQ_0_1",CONTENT_EQ_0_1;
+"CONTENT_EQ_0_GEN",CONTENT_EQ_0_GEN;
+"CONTENT_EQ_0_INTERIOR",CONTENT_EQ_0_INTERIOR;
+"CONTENT_IMAGE_AFFINITY_INTERVAL",CONTENT_IMAGE_AFFINITY_INTERVAL;
+"CONTENT_IMAGE_STRETCH_INTERVAL",CONTENT_IMAGE_STRETCH_INTERVAL;
+"CONTENT_LT_NZ",CONTENT_LT_NZ;
+"CONTENT_PASTECART",CONTENT_PASTECART;
+"CONTENT_POS_LE",CONTENT_POS_LE;
+"CONTENT_POS_LT",CONTENT_POS_LT;
+"CONTENT_POS_LT_1",CONTENT_POS_LT_1;
+"CONTENT_POS_LT_EQ",CONTENT_POS_LT_EQ;
+"CONTENT_SPLIT",CONTENT_SPLIT;
+"CONTENT_SUBSET",CONTENT_SUBSET;
+"CONTENT_UNIT",CONTENT_UNIT;
+"CONTENT_UNIT_1",CONTENT_UNIT_1;
+"CONTINUOUS_ABS",CONTINUOUS_ABS;
+"CONTINUOUS_ADD",CONTINUOUS_ADD;
+"CONTINUOUS_ADDITIVE_IMP_LINEAR",CONTINUOUS_ADDITIVE_IMP_LINEAR;
+"CONTINUOUS_AGREE_ON_CLOSURE",CONTINUOUS_AGREE_ON_CLOSURE;
+"CONTINUOUS_AT",CONTINUOUS_AT;
+"CONTINUOUS_ATREAL",CONTINUOUS_ATREAL;
+"CONTINUOUS_ATREAL_COMPOSE",CONTINUOUS_ATREAL_COMPOSE;
+"CONTINUOUS_ATREAL_SQRT_COMPOSE",CONTINUOUS_ATREAL_SQRT_COMPOSE;
+"CONTINUOUS_ATREAL_WITHINREAL",CONTINUOUS_ATREAL_WITHINREAL;
+"CONTINUOUS_ATTAINS_INF",CONTINUOUS_ATTAINS_INF;
+"CONTINUOUS_ATTAINS_SUP",CONTINUOUS_ATTAINS_SUP;
+"CONTINUOUS_AT_ARG",CONTINUOUS_AT_ARG;
+"CONTINUOUS_AT_AVOID",CONTINUOUS_AT_AVOID;
+"CONTINUOUS_AT_BALL",CONTINUOUS_AT_BALL;
+"CONTINUOUS_AT_CACS",CONTINUOUS_AT_CACS;
+"CONTINUOUS_AT_CASN",CONTINUOUS_AT_CASN;
+"CONTINUOUS_AT_CATN",CONTINUOUS_AT_CATN;
+"CONTINUOUS_AT_CCOS",CONTINUOUS_AT_CCOS;
+"CONTINUOUS_AT_CEXP",CONTINUOUS_AT_CEXP;
+"CONTINUOUS_AT_CLOG",CONTINUOUS_AT_CLOG;
+"CONTINUOUS_AT_CLOSEST_POINT",CONTINUOUS_AT_CLOSEST_POINT;
+"CONTINUOUS_AT_CNJ",CONTINUOUS_AT_CNJ;
+"CONTINUOUS_AT_COMPOSE",CONTINUOUS_AT_COMPOSE;
+"CONTINUOUS_AT_COMPOSE_EQ",CONTINUOUS_AT_COMPOSE_EQ;
+"CONTINUOUS_AT_CSIN",CONTINUOUS_AT_CSIN;
+"CONTINUOUS_AT_CSQRT",CONTINUOUS_AT_CSQRT;
+"CONTINUOUS_AT_CTAN",CONTINUOUS_AT_CTAN;
+"CONTINUOUS_AT_CX_DOT",CONTINUOUS_AT_CX_DOT;
+"CONTINUOUS_AT_CX_IM",CONTINUOUS_AT_CX_IM;
+"CONTINUOUS_AT_CX_NORM",CONTINUOUS_AT_CX_NORM;
+"CONTINUOUS_AT_CX_RE",CONTINUOUS_AT_CX_RE;
+"CONTINUOUS_AT_DIST_CLOSEST_POINT",CONTINUOUS_AT_DIST_CLOSEST_POINT;
+"CONTINUOUS_AT_ID",CONTINUOUS_AT_ID;
+"CONTINUOUS_AT_IMP_CONTINUOUS_ON",CONTINUOUS_AT_IMP_CONTINUOUS_ON;
+"CONTINUOUS_AT_INV",CONTINUOUS_AT_INV;
+"CONTINUOUS_AT_LIFT_COMPONENT",CONTINUOUS_AT_LIFT_COMPONENT;
+"CONTINUOUS_AT_LIFT_DIST",CONTINUOUS_AT_LIFT_DIST;
+"CONTINUOUS_AT_LIFT_DOT",CONTINUOUS_AT_LIFT_DOT;
+"CONTINUOUS_AT_LIFT_INFNORM",CONTINUOUS_AT_LIFT_INFNORM;
+"CONTINUOUS_AT_LIFT_NORM",CONTINUOUS_AT_LIFT_NORM;
+"CONTINUOUS_AT_LIFT_RANGE",CONTINUOUS_AT_LIFT_RANGE;
+"CONTINUOUS_AT_LIFT_SETDIST",CONTINUOUS_AT_LIFT_SETDIST;
+"CONTINUOUS_AT_LINEAR_IMAGE",CONTINUOUS_AT_LINEAR_IMAGE;
+"CONTINUOUS_AT_OPEN",CONTINUOUS_AT_OPEN;
+"CONTINUOUS_AT_SEQUENTIALLY",CONTINUOUS_AT_SEQUENTIALLY;
+"CONTINUOUS_AT_SQRT",CONTINUOUS_AT_SQRT;
+"CONTINUOUS_AT_SQRT_COMPOSE",CONTINUOUS_AT_SQRT_COMPOSE;
+"CONTINUOUS_AT_TRANSLATION",CONTINUOUS_AT_TRANSLATION;
+"CONTINUOUS_AT_WINDING_NUMBER",CONTINUOUS_AT_WINDING_NUMBER;
+"CONTINUOUS_AT_WITHIN",CONTINUOUS_AT_WITHIN;
+"CONTINUOUS_AT_WITHIN_INV",CONTINUOUS_AT_WITHIN_INV;
+"CONTINUOUS_CARD_LT_RANGE_CONSTANT",CONTINUOUS_CARD_LT_RANGE_CONSTANT;
+"CONTINUOUS_CARD_LT_RANGE_CONSTANT_EQ",CONTINUOUS_CARD_LT_RANGE_CONSTANT_EQ;
+"CONTINUOUS_CLOSED_IMP_CAUCHY_CONTINUOUS",CONTINUOUS_CLOSED_IMP_CAUCHY_CONTINUOUS;
+"CONTINUOUS_CLOSED_IN_PREIMAGE",CONTINUOUS_CLOSED_IN_PREIMAGE;
+"CONTINUOUS_CLOSED_IN_PREIMAGE_CONSTANT",CONTINUOUS_CLOSED_IN_PREIMAGE_CONSTANT;
+"CONTINUOUS_CLOSED_IN_PREIMAGE_EQ",CONTINUOUS_CLOSED_IN_PREIMAGE_EQ;
+"CONTINUOUS_CLOSED_IN_PREIMAGE_GEN",CONTINUOUS_CLOSED_IN_PREIMAGE_GEN;
+"CONTINUOUS_CLOSED_PREIMAGE",CONTINUOUS_CLOSED_PREIMAGE;
+"CONTINUOUS_CLOSED_PREIMAGE_CONSTANT",CONTINUOUS_CLOSED_PREIMAGE_CONSTANT;
+"CONTINUOUS_CLOSED_PREIMAGE_UNIV",CONTINUOUS_CLOSED_PREIMAGE_UNIV;
+"CONTINUOUS_CMUL",CONTINUOUS_CMUL;
+"CONTINUOUS_COMPLEX_DIV",CONTINUOUS_COMPLEX_DIV;
+"CONTINUOUS_COMPLEX_DIV_AT",CONTINUOUS_COMPLEX_DIV_AT;
+"CONTINUOUS_COMPLEX_DIV_WITHIN",CONTINUOUS_COMPLEX_DIV_WITHIN;
+"CONTINUOUS_COMPLEX_INV",CONTINUOUS_COMPLEX_INV;
+"CONTINUOUS_COMPLEX_INV_AT",CONTINUOUS_COMPLEX_INV_AT;
+"CONTINUOUS_COMPLEX_INV_WITHIN",CONTINUOUS_COMPLEX_INV_WITHIN;
+"CONTINUOUS_COMPLEX_MUL",CONTINUOUS_COMPLEX_MUL;
+"CONTINUOUS_COMPLEX_POW",CONTINUOUS_COMPLEX_POW;
+"CONTINUOUS_COMPONENTWISE",CONTINUOUS_COMPONENTWISE;
+"CONTINUOUS_COMPONENTWISE_LIFT",CONTINUOUS_COMPONENTWISE_LIFT;
+"CONTINUOUS_CONST",CONTINUOUS_CONST;
+"CONTINUOUS_CONSTANT_ON_CLOSURE",CONTINUOUS_CONSTANT_ON_CLOSURE;
+"CONTINUOUS_CONTINUOUS_ATREAL",CONTINUOUS_CONTINUOUS_ATREAL;
+"CONTINUOUS_CONTINUOUS_WITHINREAL",CONTINUOUS_CONTINUOUS_WITHINREAL;
+"CONTINUOUS_COUNTABLE_RANGE_CONSTANT",CONTINUOUS_COUNTABLE_RANGE_CONSTANT;
+"CONTINUOUS_COUNTABLE_RANGE_CONSTANT_EQ",CONTINUOUS_COUNTABLE_RANGE_CONSTANT_EQ;
+"CONTINUOUS_CX_ATREAL",CONTINUOUS_CX_ATREAL;
+"CONTINUOUS_CX_DROP",CONTINUOUS_CX_DROP;
+"CONTINUOUS_CX_LIFT",CONTINUOUS_CX_LIFT;
+"CONTINUOUS_CX_WITHINREAL",CONTINUOUS_CX_WITHINREAL;
+"CONTINUOUS_DISCONNECTED_RANGE_CONSTANT",CONTINUOUS_DISCONNECTED_RANGE_CONSTANT;
+"CONTINUOUS_DISCONNECTED_RANGE_CONSTANT_EQ",CONTINUOUS_DISCONNECTED_RANGE_CONSTANT_EQ;
+"CONTINUOUS_DISCRETE_RANGE_CONSTANT",CONTINUOUS_DISCRETE_RANGE_CONSTANT;
+"CONTINUOUS_DISCRETE_RANGE_CONSTANT_EQ",CONTINUOUS_DISCRETE_RANGE_CONSTANT_EQ;
+"CONTINUOUS_FINITE_RANGE_CONSTANT",CONTINUOUS_FINITE_RANGE_CONSTANT;
+"CONTINUOUS_FINITE_RANGE_CONSTANT_EQ",CONTINUOUS_FINITE_RANGE_CONSTANT_EQ;
+"CONTINUOUS_GE_ON_CLOSURE",CONTINUOUS_GE_ON_CLOSURE;
+"CONTINUOUS_IMAGE_SUBSET_INTERIOR",CONTINUOUS_IMAGE_SUBSET_INTERIOR;
+"CONTINUOUS_IMAGE_SUBSET_RELATIVE_INTERIOR",CONTINUOUS_IMAGE_SUBSET_RELATIVE_INTERIOR;
+"CONTINUOUS_IMP_CLOSED_MAP",CONTINUOUS_IMP_CLOSED_MAP;
+"CONTINUOUS_IMP_MEASURABLE_ON",CONTINUOUS_IMP_MEASURABLE_ON;
+"CONTINUOUS_IMP_MEASURABLE_ON_CLOSED_SUBSET",CONTINUOUS_IMP_MEASURABLE_ON_CLOSED_SUBSET;
+"CONTINUOUS_IMP_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET",CONTINUOUS_IMP_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET;
+"CONTINUOUS_IMP_REAL_MEASURABLE_ON",CONTINUOUS_IMP_REAL_MEASURABLE_ON;
+"CONTINUOUS_INJECTIVE_IFF_MONOTONIC",CONTINUOUS_INJECTIVE_IFF_MONOTONIC;
+"CONTINUOUS_INJECTIVE_IMAGE_OPEN_SEGMENT_1",CONTINUOUS_INJECTIVE_IMAGE_OPEN_SEGMENT_1;
+"CONTINUOUS_INJECTIVE_IMAGE_SEGMENT_1",CONTINUOUS_INJECTIVE_IMAGE_SEGMENT_1;
+"CONTINUOUS_INJECTIVE_IMAGE_SUBSPACE_DIM_LE",CONTINUOUS_INJECTIVE_IMAGE_SUBSPACE_DIM_LE;
+"CONTINUOUS_INTERVAL_BIJ",CONTINUOUS_INTERVAL_BIJ;
+"CONTINUOUS_INV",CONTINUOUS_INV;
+"CONTINUOUS_IVT_LOCAL_EXTREMUM",CONTINUOUS_IVT_LOCAL_EXTREMUM;
+"CONTINUOUS_LEFT_INVERSE_IMP_QUOTIENT_MAP",CONTINUOUS_LEFT_INVERSE_IMP_QUOTIENT_MAP;
+"CONTINUOUS_LEVELSET_OPEN",CONTINUOUS_LEVELSET_OPEN;
+"CONTINUOUS_LEVELSET_OPEN_IN",CONTINUOUS_LEVELSET_OPEN_IN;
+"CONTINUOUS_LEVELSET_OPEN_IN_CASES",CONTINUOUS_LEVELSET_OPEN_IN_CASES;
+"CONTINUOUS_LE_ON_CLOSURE",CONTINUOUS_LE_ON_CLOSURE;
+"CONTINUOUS_LIFT_COMPONENT_COMPOSE",CONTINUOUS_LIFT_COMPONENT_COMPOSE;
+"CONTINUOUS_LIFT_DET",CONTINUOUS_LIFT_DET;
+"CONTINUOUS_LIFT_DOT2",CONTINUOUS_LIFT_DOT2;
+"CONTINUOUS_LIFT_NORM_COMPOSE",CONTINUOUS_LIFT_NORM_COMPOSE;
+"CONTINUOUS_LIFT_POW",CONTINUOUS_LIFT_POW;
+"CONTINUOUS_LIFT_PRODUCT",CONTINUOUS_LIFT_PRODUCT;
+"CONTINUOUS_LINEPATH_AT",CONTINUOUS_LINEPATH_AT;
+"CONTINUOUS_LOGARITHM_ON_BALL",CONTINUOUS_LOGARITHM_ON_BALL;
+"CONTINUOUS_LOGARITHM_ON_CBALL",CONTINUOUS_LOGARITHM_ON_CBALL;
+"CONTINUOUS_LOGARITHM_ON_CONTRACTIBLE",CONTINUOUS_LOGARITHM_ON_CONTRACTIBLE;
+"CONTINUOUS_LOGARITHM_ON_SIMPLY_CONNECTED",CONTINUOUS_LOGARITHM_ON_SIMPLY_CONNECTED;
+"CONTINUOUS_MAX",CONTINUOUS_MAX;
+"CONTINUOUS_MIDPOINT_CONVEX",CONTINUOUS_MIDPOINT_CONVEX;
+"CONTINUOUS_MIN",CONTINUOUS_MIN;
+"CONTINUOUS_MUL",CONTINUOUS_MUL;
+"CONTINUOUS_NEG",CONTINUOUS_NEG;
+"CONTINUOUS_ON",CONTINUOUS_ON;
+"CONTINUOUS_ON_ABS",CONTINUOUS_ON_ABS;
+"CONTINUOUS_ON_ADD",CONTINUOUS_ON_ADD;
+"CONTINUOUS_ON_AVOID",CONTINUOUS_ON_AVOID;
+"CONTINUOUS_ON_BORSUK_MAP",CONTINUOUS_ON_BORSUK_MAP;
+"CONTINUOUS_ON_CACS",CONTINUOUS_ON_CACS;
+"CONTINUOUS_ON_CACS_REAL",CONTINUOUS_ON_CACS_REAL;
+"CONTINUOUS_ON_CASES",CONTINUOUS_ON_CASES;
+"CONTINUOUS_ON_CASES_1",CONTINUOUS_ON_CASES_1;
+"CONTINUOUS_ON_CASES_LE",CONTINUOUS_ON_CASES_LE;
+"CONTINUOUS_ON_CASES_LOCAL",CONTINUOUS_ON_CASES_LOCAL;
+"CONTINUOUS_ON_CASES_LOCAL_OPEN",CONTINUOUS_ON_CASES_LOCAL_OPEN;
+"CONTINUOUS_ON_CASES_OPEN",CONTINUOUS_ON_CASES_OPEN;
+"CONTINUOUS_ON_CASN",CONTINUOUS_ON_CASN;
+"CONTINUOUS_ON_CASN_REAL",CONTINUOUS_ON_CASN_REAL;
+"CONTINUOUS_ON_CATN",CONTINUOUS_ON_CATN;
+"CONTINUOUS_ON_CCOS",CONTINUOUS_ON_CCOS;
+"CONTINUOUS_ON_CEXP",CONTINUOUS_ON_CEXP;
+"CONTINUOUS_ON_CLOG",CONTINUOUS_ON_CLOG;
+"CONTINUOUS_ON_CLOSED",CONTINUOUS_ON_CLOSED;
+"CONTINUOUS_ON_CLOSED_GEN",CONTINUOUS_ON_CLOSED_GEN;
+"CONTINUOUS_ON_CLOSEST_POINT",CONTINUOUS_ON_CLOSEST_POINT;
+"CONTINUOUS_ON_CLOSURE",CONTINUOUS_ON_CLOSURE;
+"CONTINUOUS_ON_CLOSURE_COMPONENT_GE",CONTINUOUS_ON_CLOSURE_COMPONENT_GE;
+"CONTINUOUS_ON_CLOSURE_COMPONENT_LE",CONTINUOUS_ON_CLOSURE_COMPONENT_LE;
+"CONTINUOUS_ON_CLOSURE_NORM_LE",CONTINUOUS_ON_CLOSURE_NORM_LE;
+"CONTINUOUS_ON_CLOSURE_SEQUENTIALLY",CONTINUOUS_ON_CLOSURE_SEQUENTIALLY;
+"CONTINUOUS_ON_CMUL",CONTINUOUS_ON_CMUL;
+"CONTINUOUS_ON_CNJ",CONTINUOUS_ON_CNJ;
+"CONTINUOUS_ON_COMPACT_SURFACE_PROJECTION",CONTINUOUS_ON_COMPACT_SURFACE_PROJECTION;
+"CONTINUOUS_ON_COMPLEX_DIV",CONTINUOUS_ON_COMPLEX_DIV;
+"CONTINUOUS_ON_COMPLEX_INV",CONTINUOUS_ON_COMPLEX_INV;
+"CONTINUOUS_ON_COMPLEX_LMUL",CONTINUOUS_ON_COMPLEX_LMUL;
+"CONTINUOUS_ON_COMPLEX_MUL",CONTINUOUS_ON_COMPLEX_MUL;
+"CONTINUOUS_ON_COMPLEX_POW",CONTINUOUS_ON_COMPLEX_POW;
+"CONTINUOUS_ON_COMPLEX_RMUL",CONTINUOUS_ON_COMPLEX_RMUL;
+"CONTINUOUS_ON_COMPONENTS",CONTINUOUS_ON_COMPONENTS;
+"CONTINUOUS_ON_COMPONENTS_CLOSED",CONTINUOUS_ON_COMPONENTS_CLOSED;
+"CONTINUOUS_ON_COMPONENTS_CLOSED_GEN",CONTINUOUS_ON_COMPONENTS_CLOSED_GEN;
+"CONTINUOUS_ON_COMPONENTS_EQ",CONTINUOUS_ON_COMPONENTS_EQ;
+"CONTINUOUS_ON_COMPONENTS_GEN",CONTINUOUS_ON_COMPONENTS_GEN;
+"CONTINUOUS_ON_COMPONENTWISE_LIFT",CONTINUOUS_ON_COMPONENTWISE_LIFT;
+"CONTINUOUS_ON_COMPOSE",CONTINUOUS_ON_COMPOSE;
+"CONTINUOUS_ON_COMPOSE_ARG",CONTINUOUS_ON_COMPOSE_ARG;
+"CONTINUOUS_ON_CONST",CONTINUOUS_ON_CONST;
+"CONTINUOUS_ON_CONST_DYADIC_RATIONALS",CONTINUOUS_ON_CONST_DYADIC_RATIONALS;
+"CONTINUOUS_ON_CSIN",CONTINUOUS_ON_CSIN;
+"CONTINUOUS_ON_CSQRT",CONTINUOUS_ON_CSQRT;
+"CONTINUOUS_ON_CTAN",CONTINUOUS_ON_CTAN;
+"CONTINUOUS_ON_CX_DOT",CONTINUOUS_ON_CX_DOT;
+"CONTINUOUS_ON_CX_DROP",CONTINUOUS_ON_CX_DROP;
+"CONTINUOUS_ON_CX_IM",CONTINUOUS_ON_CX_IM;
+"CONTINUOUS_ON_CX_LIFT",CONTINUOUS_ON_CX_LIFT;
+"CONTINUOUS_ON_CX_NORM",CONTINUOUS_ON_CX_NORM;
+"CONTINUOUS_ON_CX_RE",CONTINUOUS_ON_CX_RE;
+"CONTINUOUS_ON_DIST_CLOSEST_POINT",CONTINUOUS_ON_DIST_CLOSEST_POINT;
+"CONTINUOUS_ON_EMPTY",CONTINUOUS_ON_EMPTY;
+"CONTINUOUS_ON_EQ",CONTINUOUS_ON_EQ;
+"CONTINUOUS_ON_EQ_CONTINUOUS_AT",CONTINUOUS_ON_EQ_CONTINUOUS_AT;
+"CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN",CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+"CONTINUOUS_ON_FINITE",CONTINUOUS_ON_FINITE;
+"CONTINUOUS_ON_ID",CONTINUOUS_ON_ID;
+"CONTINUOUS_ON_IMP_CLOSED_IN",CONTINUOUS_ON_IMP_CLOSED_IN;
+"CONTINUOUS_ON_IMP_OPEN_IN",CONTINUOUS_ON_IMP_OPEN_IN;
+"CONTINUOUS_ON_INTERIOR",CONTINUOUS_ON_INTERIOR;
+"CONTINUOUS_ON_INTERVAL_BIJ",CONTINUOUS_ON_INTERVAL_BIJ;
+"CONTINUOUS_ON_INV",CONTINUOUS_ON_INV;
+"CONTINUOUS_ON_INVERSE",CONTINUOUS_ON_INVERSE;
+"CONTINUOUS_ON_INVERSE_CLOSED_MAP",CONTINUOUS_ON_INVERSE_CLOSED_MAP;
+"CONTINUOUS_ON_INVERSE_INTO_1D",CONTINUOUS_ON_INVERSE_INTO_1D;
+"CONTINUOUS_ON_INVERSE_OPEN",CONTINUOUS_ON_INVERSE_OPEN;
+"CONTINUOUS_ON_INVERSE_OPEN_MAP",CONTINUOUS_ON_INVERSE_OPEN_MAP;
+"CONTINUOUS_ON_LIFT_COMPONENT",CONTINUOUS_ON_LIFT_COMPONENT;
+"CONTINUOUS_ON_LIFT_COMPONENT_COMPOSE",CONTINUOUS_ON_LIFT_COMPONENT_COMPOSE;
+"CONTINUOUS_ON_LIFT_DET",CONTINUOUS_ON_LIFT_DET;
+"CONTINUOUS_ON_LIFT_DIST",CONTINUOUS_ON_LIFT_DIST;
+"CONTINUOUS_ON_LIFT_DOT",CONTINUOUS_ON_LIFT_DOT;
+"CONTINUOUS_ON_LIFT_DOT2",CONTINUOUS_ON_LIFT_DOT2;
+"CONTINUOUS_ON_LIFT_NORM",CONTINUOUS_ON_LIFT_NORM;
+"CONTINUOUS_ON_LIFT_NORM_COMPOSE",CONTINUOUS_ON_LIFT_NORM_COMPOSE;
+"CONTINUOUS_ON_LIFT_POW",CONTINUOUS_ON_LIFT_POW;
+"CONTINUOUS_ON_LIFT_PRODUCT",CONTINUOUS_ON_LIFT_PRODUCT;
+"CONTINUOUS_ON_LIFT_RANGE",CONTINUOUS_ON_LIFT_RANGE;
+"CONTINUOUS_ON_LIFT_SETDIST",CONTINUOUS_ON_LIFT_SETDIST;
+"CONTINUOUS_ON_LIFT_SQRT",CONTINUOUS_ON_LIFT_SQRT;
+"CONTINUOUS_ON_LIFT_SQRT_COMPOSE",CONTINUOUS_ON_LIFT_SQRT_COMPOSE;
+"CONTINUOUS_ON_LINEPATH",CONTINUOUS_ON_LINEPATH;
+"CONTINUOUS_ON_MAX",CONTINUOUS_ON_MAX;
+"CONTINUOUS_ON_MIN",CONTINUOUS_ON_MIN;
+"CONTINUOUS_ON_MUL",CONTINUOUS_ON_MUL;
+"CONTINUOUS_ON_NEG",CONTINUOUS_ON_NEG;
+"CONTINUOUS_ON_NO_LIMPT",CONTINUOUS_ON_NO_LIMPT;
+"CONTINUOUS_ON_OPEN",CONTINUOUS_ON_OPEN;
+"CONTINUOUS_ON_OPEN_AVOID",CONTINUOUS_ON_OPEN_AVOID;
+"CONTINUOUS_ON_OPEN_GEN",CONTINUOUS_ON_OPEN_GEN;
+"CONTINUOUS_ON_PASTECART",CONTINUOUS_ON_PASTECART;
+"CONTINUOUS_ON_SEQUENTIALLY",CONTINUOUS_ON_SEQUENTIALLY;
+"CONTINUOUS_ON_SING",CONTINUOUS_ON_SING;
+"CONTINUOUS_ON_SUB",CONTINUOUS_ON_SUB;
+"CONTINUOUS_ON_SUBSET",CONTINUOUS_ON_SUBSET;
+"CONTINUOUS_ON_UNION",CONTINUOUS_ON_UNION;
+"CONTINUOUS_ON_UNION_LOCAL",CONTINUOUS_ON_UNION_LOCAL;
+"CONTINUOUS_ON_UNION_LOCAL_OPEN",CONTINUOUS_ON_UNION_LOCAL_OPEN;
+"CONTINUOUS_ON_UNION_OPEN",CONTINUOUS_ON_UNION_OPEN;
+"CONTINUOUS_ON_UPPERHALF_ARG",CONTINUOUS_ON_UPPERHALF_ARG;
+"CONTINUOUS_ON_VECTOR_POLYNOMIAL_FUNCTION",CONTINUOUS_ON_VECTOR_POLYNOMIAL_FUNCTION;
+"CONTINUOUS_ON_VMUL",CONTINUOUS_ON_VMUL;
+"CONTINUOUS_ON_VSUM",CONTINUOUS_ON_VSUM;
+"CONTINUOUS_ON_WINDING_NUMBER",CONTINUOUS_ON_WINDING_NUMBER;
+"CONTINUOUS_OPEN_IN_PREIMAGE",CONTINUOUS_OPEN_IN_PREIMAGE;
+"CONTINUOUS_OPEN_IN_PREIMAGE_EQ",CONTINUOUS_OPEN_IN_PREIMAGE_EQ;
+"CONTINUOUS_OPEN_IN_PREIMAGE_GEN",CONTINUOUS_OPEN_IN_PREIMAGE_GEN;
+"CONTINUOUS_OPEN_PREIMAGE",CONTINUOUS_OPEN_PREIMAGE;
+"CONTINUOUS_OPEN_PREIMAGE_UNIV",CONTINUOUS_OPEN_PREIMAGE_UNIV;
+"CONTINUOUS_PASTECART",CONTINUOUS_PASTECART;
+"CONTINUOUS_REAL_CONTINUOUS_ATREAL_COMPOSE",CONTINUOUS_REAL_CONTINUOUS_ATREAL_COMPOSE;
+"CONTINUOUS_REAL_CONTINUOUS_AT_COMPOSE",CONTINUOUS_REAL_CONTINUOUS_AT_COMPOSE;
+"CONTINUOUS_REAL_CONTINUOUS_WITHINREAL_COMPOSE",CONTINUOUS_REAL_CONTINUOUS_WITHINREAL_COMPOSE;
+"CONTINUOUS_REAL_CONTINUOUS_WITHIN_COMPOSE",CONTINUOUS_REAL_CONTINUOUS_WITHIN_COMPOSE;
+"CONTINUOUS_RIGHT_INVERSE_IMP_QUOTIENT_MAP",CONTINUOUS_RIGHT_INVERSE_IMP_QUOTIENT_MAP;
+"CONTINUOUS_SQRT_ON_CONTRACTIBLE",CONTINUOUS_SQRT_ON_CONTRACTIBLE;
+"CONTINUOUS_SQRT_ON_SIMPLY_CONNECTED",CONTINUOUS_SQRT_ON_SIMPLY_CONNECTED;
+"CONTINUOUS_SUB",CONTINUOUS_SUB;
+"CONTINUOUS_TRANSFORM_AT",CONTINUOUS_TRANSFORM_AT;
+"CONTINUOUS_TRANSFORM_WITHIN",CONTINUOUS_TRANSFORM_WITHIN;
+"CONTINUOUS_TRIVIAL_LIMIT",CONTINUOUS_TRIVIAL_LIMIT;
+"CONTINUOUS_UNIFORM_LIMIT",CONTINUOUS_UNIFORM_LIMIT;
+"CONTINUOUS_VECTOR_POLYNOMIAL_FUNCTION",CONTINUOUS_VECTOR_POLYNOMIAL_FUNCTION;
+"CONTINUOUS_VMUL",CONTINUOUS_VMUL;
+"CONTINUOUS_VSUM",CONTINUOUS_VSUM;
+"CONTINUOUS_WITHIN",CONTINUOUS_WITHIN;
+"CONTINUOUS_WITHINREAL",CONTINUOUS_WITHINREAL;
+"CONTINUOUS_WITHINREAL_COMPOSE",CONTINUOUS_WITHINREAL_COMPOSE;
+"CONTINUOUS_WITHINREAL_SQRT_COMPOSE",CONTINUOUS_WITHINREAL_SQRT_COMPOSE;
+"CONTINUOUS_WITHINREAL_SUBSET",CONTINUOUS_WITHINREAL_SUBSET;
+"CONTINUOUS_WITHIN_AVOID",CONTINUOUS_WITHIN_AVOID;
+"CONTINUOUS_WITHIN_BALL",CONTINUOUS_WITHIN_BALL;
+"CONTINUOUS_WITHIN_CACS",CONTINUOUS_WITHIN_CACS;
+"CONTINUOUS_WITHIN_CACS_REAL",CONTINUOUS_WITHIN_CACS_REAL;
+"CONTINUOUS_WITHIN_CASN",CONTINUOUS_WITHIN_CASN;
+"CONTINUOUS_WITHIN_CASN_REAL",CONTINUOUS_WITHIN_CASN_REAL;
+"CONTINUOUS_WITHIN_CATN",CONTINUOUS_WITHIN_CATN;
+"CONTINUOUS_WITHIN_CCOS",CONTINUOUS_WITHIN_CCOS;
+"CONTINUOUS_WITHIN_CEXP",CONTINUOUS_WITHIN_CEXP;
+"CONTINUOUS_WITHIN_CLOG",CONTINUOUS_WITHIN_CLOG;
+"CONTINUOUS_WITHIN_CLOSED_NONTRIVIAL",CONTINUOUS_WITHIN_CLOSED_NONTRIVIAL;
+"CONTINUOUS_WITHIN_CNJ",CONTINUOUS_WITHIN_CNJ;
+"CONTINUOUS_WITHIN_COMPOSE",CONTINUOUS_WITHIN_COMPOSE;
+"CONTINUOUS_WITHIN_CSIN",CONTINUOUS_WITHIN_CSIN;
+"CONTINUOUS_WITHIN_CSQRT",CONTINUOUS_WITHIN_CSQRT;
+"CONTINUOUS_WITHIN_CSQRT_POSREAL",CONTINUOUS_WITHIN_CSQRT_POSREAL;
+"CONTINUOUS_WITHIN_CTAN",CONTINUOUS_WITHIN_CTAN;
+"CONTINUOUS_WITHIN_CX_DOT",CONTINUOUS_WITHIN_CX_DOT;
+"CONTINUOUS_WITHIN_CX_NORM",CONTINUOUS_WITHIN_CX_NORM;
+"CONTINUOUS_WITHIN_ID",CONTINUOUS_WITHIN_ID;
+"CONTINUOUS_WITHIN_LIFT_SQRT",CONTINUOUS_WITHIN_LIFT_SQRT;
+"CONTINUOUS_WITHIN_OPEN",CONTINUOUS_WITHIN_OPEN;
+"CONTINUOUS_WITHIN_SEQUENTIALLY",CONTINUOUS_WITHIN_SEQUENTIALLY;
+"CONTINUOUS_WITHIN_SQRT_COMPOSE",CONTINUOUS_WITHIN_SQRT_COMPOSE;
+"CONTINUOUS_WITHIN_SUBSET",CONTINUOUS_WITHIN_SUBSET;
+"CONTINUOUS_WITHIN_UPPERHALF_ARG",CONTINUOUS_WITHIN_UPPERHALF_ARG;
+"CONTRACTIBLE_CONVEX_TWEAK_BOUNDARY_POINTS",CONTRACTIBLE_CONVEX_TWEAK_BOUNDARY_POINTS;
+"CONTRACTIBLE_EMPTY",CONTRACTIBLE_EMPTY;
+"CONTRACTIBLE_EQ_SIMPLY_CONNECTED_2D",CONTRACTIBLE_EQ_SIMPLY_CONNECTED_2D;
+"CONTRACTIBLE_IMP_CONNECTED",CONTRACTIBLE_IMP_CONNECTED;
+"CONTRACTIBLE_IMP_HOLOMORPHIC_ACS",CONTRACTIBLE_IMP_HOLOMORPHIC_ACS;
+"CONTRACTIBLE_IMP_HOLOMORPHIC_ACS_BOUNDED",CONTRACTIBLE_IMP_HOLOMORPHIC_ACS_BOUNDED;
+"CONTRACTIBLE_IMP_HOLOMORPHIC_LOG",CONTRACTIBLE_IMP_HOLOMORPHIC_LOG;
+"CONTRACTIBLE_IMP_HOLOMORPHIC_SQRT",CONTRACTIBLE_IMP_HOLOMORPHIC_SQRT;
+"CONTRACTIBLE_IMP_PATH_CONNECTED",CONTRACTIBLE_IMP_PATH_CONNECTED;
+"CONTRACTIBLE_IMP_SIMPLY_CONNECTED",CONTRACTIBLE_IMP_SIMPLY_CONNECTED;
+"CONTRACTIBLE_IMP_UNICOHERENT",CONTRACTIBLE_IMP_UNICOHERENT;
+"CONTRACTIBLE_INJECTIVE_LINEAR_IMAGE",CONTRACTIBLE_INJECTIVE_LINEAR_IMAGE;
+"CONTRACTIBLE_PCROSS",CONTRACTIBLE_PCROSS;
+"CONTRACTIBLE_PCROSS_EQ",CONTRACTIBLE_PCROSS_EQ;
+"CONTRACTIBLE_PUNCTURED_SPHERE",CONTRACTIBLE_PUNCTURED_SPHERE;
+"CONTRACTIBLE_SING",CONTRACTIBLE_SING;
+"CONTRACTIBLE_SPHERE",CONTRACTIBLE_SPHERE;
+"CONTRACTIBLE_TRANSLATION",CONTRACTIBLE_TRANSLATION;
+"CONTRACTIBLE_UNIV",CONTRACTIBLE_UNIV;
+"CONTRACTION_IMP_CONTINUOUS_ON",CONTRACTION_IMP_CONTINUOUS_ON;
+"CONTRAPOS_THM",CONTRAPOS_THM;
+"CONVERGENT_BOUNDED_INCREASING",CONVERGENT_BOUNDED_INCREASING;
+"CONVERGENT_BOUNDED_MONOTONE",CONVERGENT_BOUNDED_MONOTONE;
+"CONVERGENT_EQ_CAUCHY",CONVERGENT_EQ_CAUCHY;
+"CONVERGENT_IMP_BOUNDED",CONVERGENT_IMP_BOUNDED;
+"CONVERGENT_IMP_CAUCHY",CONVERGENT_IMP_CAUCHY;
+"CONVEX",CONVEX;
+"CONVEX_ADD",CONVEX_ADD;
+"CONVEX_AFFINITY",CONVEX_AFFINITY;
+"CONVEX_ALT",CONVEX_ALT;
+"CONVEX_AND_AFFINE_INTER_OPEN",CONVEX_AND_AFFINE_INTER_OPEN;
+"CONVEX_BALL",CONVEX_BALL;
+"CONVEX_BOUNDS_LEMMA",CONVEX_BOUNDS_LEMMA;
+"CONVEX_CBALL",CONVEX_CBALL;
+"CONVEX_CLOSED_CONTAINS_SAME_RAY",CONVEX_CLOSED_CONTAINS_SAME_RAY;
+"CONVEX_CLOSURE",CONVEX_CLOSURE;
+"CONVEX_CLOSURE_INTERIOR",CONVEX_CLOSURE_INTERIOR;
+"CONVEX_CLOSURE_RELATIVE_INTERIOR",CONVEX_CLOSURE_RELATIVE_INTERIOR;
+"CONVEX_CMUL",CONVEX_CMUL;
+"CONVEX_CONE",CONVEX_CONE;
+"CONVEX_CONE_CONTAINS_0",CONVEX_CONE_CONTAINS_0;
+"CONVEX_CONE_CONVEX_CONE_HULL",CONVEX_CONE_CONVEX_CONE_HULL;
+"CONVEX_CONE_HALFSPACE_GE",CONVEX_CONE_HALFSPACE_GE;
+"CONVEX_CONE_HALFSPACE_LE",CONVEX_CONE_HALFSPACE_LE;
+"CONVEX_CONE_HULL_ADD",CONVEX_CONE_HULL_ADD;
+"CONVEX_CONE_HULL_CONTAINS_0",CONVEX_CONE_HULL_CONTAINS_0;
+"CONVEX_CONE_HULL_CONVEX_HULL",CONVEX_CONE_HULL_CONVEX_HULL;
+"CONVEX_CONE_HULL_CONVEX_HULL_NONEMPTY",CONVEX_CONE_HULL_CONVEX_HULL_NONEMPTY;
+"CONVEX_CONE_HULL_EMPTY",CONVEX_CONE_HULL_EMPTY;
+"CONVEX_CONE_HULL_LINEAR_IMAGE",CONVEX_CONE_HULL_LINEAR_IMAGE;
+"CONVEX_CONE_HULL_MUL",CONVEX_CONE_HULL_MUL;
+"CONVEX_CONE_HULL_NONEMPTY",CONVEX_CONE_HULL_NONEMPTY;
+"CONVEX_CONE_HULL_SEPARATE",CONVEX_CONE_HULL_SEPARATE;
+"CONVEX_CONE_HULL_SEPARATE_NONEMPTY",CONVEX_CONE_HULL_SEPARATE_NONEMPTY;
+"CONVEX_CONE_HULL_UNION",CONVEX_CONE_HULL_UNION;
+"CONVEX_CONE_INTERS",CONVEX_CONE_INTERS;
+"CONVEX_CONE_LINEAR_IMAGE",CONVEX_CONE_LINEAR_IMAGE;
+"CONVEX_CONE_LINEAR_IMAGE_EQ",CONVEX_CONE_LINEAR_IMAGE_EQ;
+"CONVEX_CONE_NEGATIONS",CONVEX_CONE_NEGATIONS;
+"CONVEX_CONE_PCROSS",CONVEX_CONE_PCROSS;
+"CONVEX_CONE_PCROSS_EQ",CONVEX_CONE_PCROSS_EQ;
+"CONVEX_CONE_SING",CONVEX_CONE_SING;
+"CONVEX_CONE_SPAN",CONVEX_CONE_SPAN;
+"CONVEX_CONE_SUMS",CONVEX_CONE_SUMS;
+"CONVEX_CONIC_HULL",CONVEX_CONIC_HULL;
+"CONVEX_CONNECTED",CONVEX_CONNECTED;
+"CONVEX_CONNECTED_1",CONVEX_CONNECTED_1;
+"CONVEX_CONNECTED_1_GEN",CONVEX_CONNECTED_1_GEN;
+"CONVEX_CONTAINS_SEGMENT",CONVEX_CONTAINS_SEGMENT;
+"CONVEX_CONTAINS_SEGMENT_EQ",CONVEX_CONTAINS_SEGMENT_EQ;
+"CONVEX_CONTAINS_SEGMENT_IMP",CONVEX_CONTAINS_SEGMENT_IMP;
+"CONVEX_CONVEX_CONE_HULL",CONVEX_CONVEX_CONE_HULL;
+"CONVEX_CONVEX_HULL",CONVEX_CONVEX_HULL;
+"CONVEX_DIFFERENCES",CONVEX_DIFFERENCES;
+"CONVEX_DISTANCE",CONVEX_DISTANCE;
+"CONVEX_EMPTY",CONVEX_EMPTY;
+"CONVEX_EPIGRAPH",CONVEX_EPIGRAPH;
+"CONVEX_EPIGRAPH_CONVEX",CONVEX_EPIGRAPH_CONVEX;
+"CONVEX_EXPLICIT",CONVEX_EXPLICIT;
+"CONVEX_FINITE",CONVEX_FINITE;
+"CONVEX_HALFSPACE_COMPONENT_GE",CONVEX_HALFSPACE_COMPONENT_GE;
+"CONVEX_HALFSPACE_COMPONENT_GT",CONVEX_HALFSPACE_COMPONENT_GT;
+"CONVEX_HALFSPACE_COMPONENT_LE",CONVEX_HALFSPACE_COMPONENT_LE;
+"CONVEX_HALFSPACE_COMPONENT_LT",CONVEX_HALFSPACE_COMPONENT_LT;
+"CONVEX_HALFSPACE_GE",CONVEX_HALFSPACE_GE;
+"CONVEX_HALFSPACE_GT",CONVEX_HALFSPACE_GT;
+"CONVEX_HALFSPACE_IM_GE",CONVEX_HALFSPACE_IM_GE;
+"CONVEX_HALFSPACE_IM_GT",CONVEX_HALFSPACE_IM_GT;
+"CONVEX_HALFSPACE_IM_LE",CONVEX_HALFSPACE_IM_LE;
+"CONVEX_HALFSPACE_IM_LT",CONVEX_HALFSPACE_IM_LT;
+"CONVEX_HALFSPACE_INTERSECTION",CONVEX_HALFSPACE_INTERSECTION;
+"CONVEX_HALFSPACE_LE",CONVEX_HALFSPACE_LE;
+"CONVEX_HALFSPACE_LT",CONVEX_HALFSPACE_LT;
+"CONVEX_HALFSPACE_RE_GE",CONVEX_HALFSPACE_RE_GE;
+"CONVEX_HALFSPACE_RE_GT",CONVEX_HALFSPACE_RE_GT;
+"CONVEX_HALFSPACE_RE_LE",CONVEX_HALFSPACE_RE_LE;
+"CONVEX_HALFSPACE_RE_LT",CONVEX_HALFSPACE_RE_LT;
+"CONVEX_HULLS_EQ",CONVEX_HULLS_EQ;
+"CONVEX_HULL_2",CONVEX_HULL_2;
+"CONVEX_HULL_2_ALT",CONVEX_HULL_2_ALT;
+"CONVEX_HULL_3",CONVEX_HULL_3;
+"CONVEX_HULL_3_ALT",CONVEX_HULL_3_ALT;
+"CONVEX_HULL_AFFINITY",CONVEX_HULL_AFFINITY;
+"CONVEX_HULL_CARATHEODORY",CONVEX_HULL_CARATHEODORY;
+"CONVEX_HULL_CARATHEODORY_AFF_DIM",CONVEX_HULL_CARATHEODORY_AFF_DIM;
+"CONVEX_HULL_EMPTY",CONVEX_HULL_EMPTY;
+"CONVEX_HULL_EQ",CONVEX_HULL_EQ;
+"CONVEX_HULL_EQ_EMPTY",CONVEX_HULL_EQ_EMPTY;
+"CONVEX_HULL_EQ_SING",CONVEX_HULL_EQ_SING;
+"CONVEX_HULL_EXCHANGE_INTER",CONVEX_HULL_EXCHANGE_INTER;
+"CONVEX_HULL_EXCHANGE_UNION",CONVEX_HULL_EXCHANGE_UNION;
+"CONVEX_HULL_EXPLICIT",CONVEX_HULL_EXPLICIT;
+"CONVEX_HULL_FINITE",CONVEX_HULL_FINITE;
+"CONVEX_HULL_FINITE_STEP",CONVEX_HULL_FINITE_STEP;
+"CONVEX_HULL_INDEXED",CONVEX_HULL_INDEXED;
+"CONVEX_HULL_INSERT",CONVEX_HULL_INSERT;
+"CONVEX_HULL_INSERT_ALT",CONVEX_HULL_INSERT_ALT;
+"CONVEX_HULL_INTER",CONVEX_HULL_INTER;
+"CONVEX_HULL_INTERS",CONVEX_HULL_INTERS;
+"CONVEX_HULL_LINEAR_IMAGE",CONVEX_HULL_LINEAR_IMAGE;
+"CONVEX_HULL_PCROSS",CONVEX_HULL_PCROSS;
+"CONVEX_HULL_SCALING",CONVEX_HULL_SCALING;
+"CONVEX_HULL_SING",CONVEX_HULL_SING;
+"CONVEX_HULL_SUBSET",CONVEX_HULL_SUBSET;
+"CONVEX_HULL_SUBSET_AFFINE_HULL",CONVEX_HULL_SUBSET_AFFINE_HULL;
+"CONVEX_HULL_SUBSET_CONVEX_CONE_HULL",CONVEX_HULL_SUBSET_CONVEX_CONE_HULL;
+"CONVEX_HULL_SUBSET_SPAN",CONVEX_HULL_SUBSET_SPAN;
+"CONVEX_HULL_SUMS",CONVEX_HULL_SUMS;
+"CONVEX_HULL_TRANSLATION",CONVEX_HULL_TRANSLATION;
+"CONVEX_HULL_UNION_EXPLICIT",CONVEX_HULL_UNION_EXPLICIT;
+"CONVEX_HULL_UNION_NONEMPTY_EXPLICIT",CONVEX_HULL_UNION_NONEMPTY_EXPLICIT;
+"CONVEX_HULL_UNION_UNIONS",CONVEX_HULL_UNION_UNIONS;
+"CONVEX_HULL_UNIV",CONVEX_HULL_UNIV;
+"CONVEX_HYPERPLANE",CONVEX_HYPERPLANE;
+"CONVEX_IMP_CONTRACTIBLE",CONVEX_IMP_CONTRACTIBLE;
+"CONVEX_IMP_LOCALLY_CONNECTED",CONVEX_IMP_LOCALLY_CONNECTED;
+"CONVEX_IMP_LOCALLY_PATH_CONNECTED",CONVEX_IMP_LOCALLY_PATH_CONNECTED;
+"CONVEX_IMP_PATH_CONNECTED",CONVEX_IMP_PATH_CONNECTED;
+"CONVEX_IMP_SIMPLY_CONNECTED",CONVEX_IMP_SIMPLY_CONNECTED;
+"CONVEX_IMP_STARLIKE",CONVEX_IMP_STARLIKE;
+"CONVEX_IMP_UNICOHERENT",CONVEX_IMP_UNICOHERENT;
+"CONVEX_INDEXED",CONVEX_INDEXED;
+"CONVEX_INTER",CONVEX_INTER;
+"CONVEX_INTERIOR",CONVEX_INTERIOR;
+"CONVEX_INTERIOR_CLOSURE",CONVEX_INTERIOR_CLOSURE;
+"CONVEX_INTERS",CONVEX_INTERS;
+"CONVEX_INTERVAL",CONVEX_INTERVAL;
+"CONVEX_LINEAR_IMAGE",CONVEX_LINEAR_IMAGE;
+"CONVEX_LINEAR_IMAGE_EQ",CONVEX_LINEAR_IMAGE_EQ;
+"CONVEX_LINEAR_PREIMAGE",CONVEX_LINEAR_PREIMAGE;
+"CONVEX_LOCAL_GLOBAL_MINIMUM",CONVEX_LOCAL_GLOBAL_MINIMUM;
+"CONVEX_LOWER",CONVEX_LOWER;
+"CONVEX_LOWER_SEGMENT",CONVEX_LOWER_SEGMENT;
+"CONVEX_MAX",CONVEX_MAX;
+"CONVEX_NEGATIONS",CONVEX_NEGATIONS;
+"CONVEX_NORM",CONVEX_NORM;
+"CONVEX_ON_BOUNDED_CONTINUOUS",CONVEX_ON_BOUNDED_CONTINUOUS;
+"CONVEX_ON_COMPOSE_LINEAR",CONVEX_ON_COMPOSE_LINEAR;
+"CONVEX_ON_CONTINUOUS",CONVEX_ON_CONTINUOUS;
+"CONVEX_ON_CONVEX_HULL_BOUND",CONVEX_ON_CONVEX_HULL_BOUND;
+"CONVEX_ON_DERIVATIVES",CONVEX_ON_DERIVATIVES;
+"CONVEX_ON_DERIVATIVES_IMP",CONVEX_ON_DERIVATIVES_IMP;
+"CONVEX_ON_DERIVATIVE_SECANT",CONVEX_ON_DERIVATIVE_SECANT;
+"CONVEX_ON_DERIVATIVE_SECANT_IMP",CONVEX_ON_DERIVATIVE_SECANT_IMP;
+"CONVEX_ON_EPIGRAPH_SLICE_LE",CONVEX_ON_EPIGRAPH_SLICE_LE;
+"CONVEX_ON_EPIGRAPH_SLICE_LT",CONVEX_ON_EPIGRAPH_SLICE_LT;
+"CONVEX_ON_JENSEN",CONVEX_ON_JENSEN;
+"CONVEX_ON_LEFT_SECANT",CONVEX_ON_LEFT_SECANT;
+"CONVEX_ON_LEFT_SECANT_MUL",CONVEX_ON_LEFT_SECANT_MUL;
+"CONVEX_ON_RIGHT_SECANT",CONVEX_ON_RIGHT_SECANT;
+"CONVEX_ON_RIGHT_SECANT_MUL",CONVEX_ON_RIGHT_SECANT_MUL;
+"CONVEX_ON_SECANT_DERIVATIVE",CONVEX_ON_SECANT_DERIVATIVE;
+"CONVEX_ON_SECANT_DERIVATIVE_IMP",CONVEX_ON_SECANT_DERIVATIVE_IMP;
+"CONVEX_ON_SUBSET",CONVEX_ON_SUBSET;
+"CONVEX_ON_TRANSLATION",CONVEX_ON_TRANSLATION;
+"CONVEX_PCROSS",CONVEX_PCROSS;
+"CONVEX_PCROSS_EQ",CONVEX_PCROSS_EQ;
+"CONVEX_POSITIVE_ORTHANT",CONVEX_POSITIVE_ORTHANT;
+"CONVEX_REAL",CONVEX_REAL;
+"CONVEX_RELATIVE_INTERIOR",CONVEX_RELATIVE_INTERIOR;
+"CONVEX_RELATIVE_INTERIOR_CLOSURE",CONVEX_RELATIVE_INTERIOR_CLOSURE;
+"CONVEX_SAME_RELATIVE_INTERIOR_CLOSURE",CONVEX_SAME_RELATIVE_INTERIOR_CLOSURE;
+"CONVEX_SAME_RELATIVE_INTERIOR_CLOSURE_STRADDLE",CONVEX_SAME_RELATIVE_INTERIOR_CLOSURE_STRADDLE;
+"CONVEX_SCALING",CONVEX_SCALING;
+"CONVEX_SCALING_EQ",CONVEX_SCALING_EQ;
+"CONVEX_SEGMENT",CONVEX_SEGMENT;
+"CONVEX_SEMIOPEN_SEGMENT",CONVEX_SEMIOPEN_SEGMENT;
+"CONVEX_SIMPLEX",CONVEX_SIMPLEX;
+"CONVEX_SING",CONVEX_SING;
+"CONVEX_SLICE",CONVEX_SLICE;
+"CONVEX_SPAN",CONVEX_SPAN;
+"CONVEX_STANDARD_HYPERPLANE",CONVEX_STANDARD_HYPERPLANE;
+"CONVEX_SUMS",CONVEX_SUMS;
+"CONVEX_TRANSLATION",CONVEX_TRANSLATION;
+"CONVEX_TRANSLATION_EQ",CONVEX_TRANSLATION_EQ;
+"CONVEX_UNIV",CONVEX_UNIV;
+"CONVEX_VSUM",CONVEX_VSUM;
+"CONVEX_VSUM_STRONG",CONVEX_VSUM_STRONG;
+"COPLANAR_2",COPLANAR_2;
+"COPLANAR_3",COPLANAR_3;
+"COPLANAR_AFFINE_HULL_COPLANAR",COPLANAR_AFFINE_HULL_COPLANAR;
+"COPLANAR_EMPTY",COPLANAR_EMPTY;
+"COPLANAR_LINEAR_IMAGE",COPLANAR_LINEAR_IMAGE;
+"COPLANAR_LINEAR_IMAGE_EQ",COPLANAR_LINEAR_IMAGE_EQ;
+"COPLANAR_SING",COPLANAR_SING;
+"COPLANAR_SMALL",COPLANAR_SMALL;
+"COPLANAR_SUBSET",COPLANAR_SUBSET;
+"COPLANAR_TRANSLATION",COPLANAR_TRANSLATION;
+"COPLANAR_TRANSLATION_EQ",COPLANAR_TRANSLATION_EQ;
+"COSMALL_APPROXIMATION",COSMALL_APPROXIMATION;
+"COS_0",COS_0;
+"COS_ABS",COS_ABS;
+"COS_ACS",COS_ACS;
+"COS_ADD",COS_ADD;
+"COS_ASN",COS_ASN;
+"COS_ASN_NZ",COS_ASN_NZ;
+"COS_ATN",COS_ATN;
+"COS_ATN_NZ",COS_ATN_NZ;
+"COS_BOUND",COS_BOUND;
+"COS_BOUNDS",COS_BOUNDS;
+"COS_DOUBLE",COS_DOUBLE;
+"COS_DOUBLE_BOUND",COS_DOUBLE_BOUND;
+"COS_DOUBLE_COS",COS_DOUBLE_COS;
+"COS_DOUBLE_SIN",COS_DOUBLE_SIN;
+"COS_EQ",COS_EQ;
+"COS_EQ_0",COS_EQ_0;
+"COS_EQ_1",COS_EQ_1;
+"COS_EQ_MINUS1",COS_EQ_MINUS1;
+"COS_GOESNEGATIVE",COS_GOESNEGATIVE;
+"COS_GOESNEGATIVE_LEMMA",COS_GOESNEGATIVE_LEMMA;
+"COS_HASZERO",COS_HASZERO;
+"COS_INJ_PI",COS_INJ_PI;
+"COS_INTEGER_2PI",COS_INTEGER_2PI;
+"COS_MONO_LE",COS_MONO_LE;
+"COS_MONO_LE_EQ",COS_MONO_LE_EQ;
+"COS_MONO_LT",COS_MONO_LT;
+"COS_MONO_LT_EQ",COS_MONO_LT_EQ;
+"COS_NEG",COS_NEG;
+"COS_NONTRIVIAL",COS_NONTRIVIAL;
+"COS_NPI",COS_NPI;
+"COS_ONE_2PI",COS_ONE_2PI;
+"COS_PERIODIC",COS_PERIODIC;
+"COS_PERIODIC_PI",COS_PERIODIC_PI;
+"COS_PI",COS_PI;
+"COS_PI2",COS_PI2;
+"COS_PI6",COS_PI6;
+"COS_POS_PI",COS_POS_PI;
+"COS_POS_PI2",COS_POS_PI2;
+"COS_POS_PI_LE",COS_POS_PI_LE;
+"COS_SIN",COS_SIN;
+"COS_SUB",COS_SUB;
+"COS_TAN",COS_TAN;
+"COS_TREBLE_COS",COS_TREBLE_COS;
+"COS_ZERO",COS_ZERO;
+"COS_ZERO_PI",COS_ZERO_PI;
+"COUNTABLE",COUNTABLE;
+"COUNTABLE_ALT",COUNTABLE_ALT;
+"COUNTABLE_AS_IMAGE",COUNTABLE_AS_IMAGE;
+"COUNTABLE_AS_IMAGE_SUBSET",COUNTABLE_AS_IMAGE_SUBSET;
+"COUNTABLE_AS_IMAGE_SUBSET_EQ",COUNTABLE_AS_IMAGE_SUBSET_EQ;
+"COUNTABLE_AS_INJECTIVE_IMAGE",COUNTABLE_AS_INJECTIVE_IMAGE;
+"COUNTABLE_CARD_MUL",COUNTABLE_CARD_MUL;
+"COUNTABLE_CARD_MUL_EQ",COUNTABLE_CARD_MUL_EQ;
+"COUNTABLE_CART",COUNTABLE_CART;
+"COUNTABLE_CASES",COUNTABLE_CASES;
+"COUNTABLE_COMPONENTS",COUNTABLE_COMPONENTS;
+"COUNTABLE_CROSS",COUNTABLE_CROSS;
+"COUNTABLE_DELETE",COUNTABLE_DELETE;
+"COUNTABLE_DIFF_FINITE",COUNTABLE_DIFF_FINITE;
+"COUNTABLE_DISJOINT_OPEN_SUBSETS",COUNTABLE_DISJOINT_OPEN_SUBSETS;
+"COUNTABLE_ELEMENTARY_DIVISION",COUNTABLE_ELEMENTARY_DIVISION;
+"COUNTABLE_EMPTY",COUNTABLE_EMPTY;
+"COUNTABLE_EMPTY_INTERIOR",COUNTABLE_EMPTY_INTERIOR;
+"COUNTABLE_FINITE_SUBSETS",COUNTABLE_FINITE_SUBSETS;
+"COUNTABLE_IMAGE",COUNTABLE_IMAGE;
+"COUNTABLE_IMAGE_INJ",COUNTABLE_IMAGE_INJ;
+"COUNTABLE_IMAGE_INJ_EQ",COUNTABLE_IMAGE_INJ_EQ;
+"COUNTABLE_IMAGE_INJ_GENERAL",COUNTABLE_IMAGE_INJ_GENERAL;
+"COUNTABLE_IMP_CARD_LT_REAL",COUNTABLE_IMP_CARD_LT_REAL;
+"COUNTABLE_IMP_DISCONNECTED",COUNTABLE_IMP_DISCONNECTED;
+"COUNTABLE_INSERT",COUNTABLE_INSERT;
+"COUNTABLE_INTEGER",COUNTABLE_INTEGER;
+"COUNTABLE_INTEGER_COORDINATES",COUNTABLE_INTEGER_COORDINATES;
+"COUNTABLE_INTER",COUNTABLE_INTER;
+"COUNTABLE_LIST",COUNTABLE_LIST;
+"COUNTABLE_LIST_GEN",COUNTABLE_LIST_GEN;
+"COUNTABLE_NON_CONDENSATION_POINTS",COUNTABLE_NON_CONDENSATION_POINTS;
+"COUNTABLE_OPEN_INTERVAL",COUNTABLE_OPEN_INTERVAL;
+"COUNTABLE_PCROSS",COUNTABLE_PCROSS;
+"COUNTABLE_PCROSS_EQ",COUNTABLE_PCROSS_EQ;
+"COUNTABLE_PRODUCT_DEPENDENT",COUNTABLE_PRODUCT_DEPENDENT;
+"COUNTABLE_RATIONAL",COUNTABLE_RATIONAL;
+"COUNTABLE_RATIONAL_COORDINATES",COUNTABLE_RATIONAL_COORDINATES;
+"COUNTABLE_RESTRICT",COUNTABLE_RESTRICT;
+"COUNTABLE_SING",COUNTABLE_SING;
+"COUNTABLE_SUBSET",COUNTABLE_SUBSET;
+"COUNTABLE_SUBSET_IMAGE",COUNTABLE_SUBSET_IMAGE;
+"COUNTABLE_UNION",COUNTABLE_UNION;
+"COUNTABLE_UNIONS",COUNTABLE_UNIONS;
+"COUNTABLE_UNION_IMP",COUNTABLE_UNION_IMP;
+"COVERING_LEMMA",COVERING_LEMMA;
+"COVERING_SPACE_CEXP_PUNCTURED_PLANE",COVERING_SPACE_CEXP_PUNCTURED_PLANE;
+"COVERING_SPACE_CLOSED_MAP",COVERING_SPACE_CLOSED_MAP;
+"COVERING_SPACE_COMPACT",COVERING_SPACE_COMPACT;
+"COVERING_SPACE_COUNTABLE_SHEETS",COVERING_SPACE_COUNTABLE_SHEETS;
+"COVERING_SPACE_FIBRE_NO_LIMPT",COVERING_SPACE_FIBRE_NO_LIMPT;
+"COVERING_SPACE_FINITE_EQ_COMPACT_FIBRE",COVERING_SPACE_FINITE_EQ_COMPACT_FIBRE;
+"COVERING_SPACE_FINITE_SHEETS",COVERING_SPACE_FINITE_SHEETS;
+"COVERING_SPACE_FINITE_SHEETS_EQ_CLOSED_MAP",COVERING_SPACE_FINITE_SHEETS_EQ_CLOSED_MAP;
+"COVERING_SPACE_FINITE_SHEETS_EQ_CLOSED_MAP_STRONG",COVERING_SPACE_FINITE_SHEETS_EQ_CLOSED_MAP_STRONG;
+"COVERING_SPACE_FINITE_SHEETS_EQ_PROPER_MAP",COVERING_SPACE_FINITE_SHEETS_EQ_PROPER_MAP;
+"COVERING_SPACE_HOMEOMORPHISM",COVERING_SPACE_HOMEOMORPHISM;
+"COVERING_SPACE_IMP_CONTINUOUS",COVERING_SPACE_IMP_CONTINUOUS;
+"COVERING_SPACE_IMP_SURJECTIVE",COVERING_SPACE_IMP_SURJECTIVE;
+"COVERING_SPACE_INESSENTIAL_LOOP_LIFT_IS_LOOP",COVERING_SPACE_INESSENTIAL_LOOP_LIFT_IS_LOOP;
+"COVERING_SPACE_INJECTIVE",COVERING_SPACE_INJECTIVE;
+"COVERING_SPACE_LIFT",COVERING_SPACE_LIFT;
+"COVERING_SPACE_LIFT_GENERAL",COVERING_SPACE_LIFT_GENERAL;
+"COVERING_SPACE_LIFT_HOLOMORPHIC",COVERING_SPACE_LIFT_HOLOMORPHIC;
+"COVERING_SPACE_LIFT_HOMOTOPIC_FUNCTION",COVERING_SPACE_LIFT_HOMOTOPIC_FUNCTION;
+"COVERING_SPACE_LIFT_HOMOTOPIC_PATH",COVERING_SPACE_LIFT_HOMOTOPIC_PATH;
+"COVERING_SPACE_LIFT_HOMOTOPIC_PATHS",COVERING_SPACE_LIFT_HOMOTOPIC_PATHS;
+"COVERING_SPACE_LIFT_HOMOTOPY",COVERING_SPACE_LIFT_HOMOTOPY;
+"COVERING_SPACE_LIFT_HOMOTOPY_ALT",COVERING_SPACE_LIFT_HOMOTOPY_ALT;
+"COVERING_SPACE_LIFT_INESSENTIAL_FUNCTION",COVERING_SPACE_LIFT_INESSENTIAL_FUNCTION;
+"COVERING_SPACE_LIFT_IS_HOLOMORPHIC",COVERING_SPACE_LIFT_IS_HOLOMORPHIC;
+"COVERING_SPACE_LIFT_PATH",COVERING_SPACE_LIFT_PATH;
+"COVERING_SPACE_LIFT_PATH_STRONG",COVERING_SPACE_LIFT_PATH_STRONG;
+"COVERING_SPACE_LIFT_STRONG",COVERING_SPACE_LIFT_STRONG;
+"COVERING_SPACE_LIFT_STRONGER",COVERING_SPACE_LIFT_STRONGER;
+"COVERING_SPACE_LIFT_UNIQUE",COVERING_SPACE_LIFT_UNIQUE;
+"COVERING_SPACE_LIFT_UNIQUE_GEN",COVERING_SPACE_LIFT_UNIQUE_GEN;
+"COVERING_SPACE_LIFT_UNIQUE_IDENTITY",COVERING_SPACE_LIFT_UNIQUE_IDENTITY;
+"COVERING_SPACE_LOCALLY",COVERING_SPACE_LOCALLY;
+"COVERING_SPACE_LOCALLY_CONNECTED",COVERING_SPACE_LOCALLY_CONNECTED;
+"COVERING_SPACE_LOCALLY_PATH_CONNECTED",COVERING_SPACE_LOCALLY_PATH_CONNECTED;
+"COVERING_SPACE_LOCAL_HOMEOMORPHISM",COVERING_SPACE_LOCAL_HOMEOMORPHISM;
+"COVERING_SPACE_LOCAL_HOMEOMORPHISM_ALT",COVERING_SPACE_LOCAL_HOMEOMORPHISM_ALT;
+"COVERING_SPACE_MONODROMY",COVERING_SPACE_MONODROMY;
+"COVERING_SPACE_OPEN_MAP",COVERING_SPACE_OPEN_MAP;
+"COVERING_SPACE_POW_PUNCTURED_PLANE",COVERING_SPACE_POW_PUNCTURED_PLANE;
+"COVERING_SPACE_QUOTIENT_MAP",COVERING_SPACE_QUOTIENT_MAP;
+"COVERING_SPACE_SIMPLY_CONNECTED_LOOP_LIFT_IS_LOOP",COVERING_SPACE_SIMPLY_CONNECTED_LOOP_LIFT_IS_LOOP;
+"COVERING_SPACE_SQUARE_PUNCTURED_PLANE",COVERING_SPACE_SQUARE_PUNCTURED_PLANE;
+"CPOW_0",CPOW_0;
+"CPOW_1",CPOW_1;
+"CPOW_ADD",CPOW_ADD;
+"CPOW_EQ_0",CPOW_EQ_0;
+"CPOW_MUL_REAL",CPOW_MUL_REAL;
+"CPOW_N",CPOW_N;
+"CPOW_NEG",CPOW_NEG;
+"CPOW_REAL_REAL",CPOW_REAL_REAL;
+"CPOW_SUB",CPOW_SUB;
+"CPRODUCT_1",CPRODUCT_1;
+"CPRODUCT_CLAUSES",CPRODUCT_CLAUSES;
+"CPRODUCT_EQ",CPRODUCT_EQ;
+"CPRODUCT_EQ_0",CPRODUCT_EQ_0;
+"CPRODUCT_EQ_1",CPRODUCT_EQ_1;
+"CPRODUCT_INV",CPRODUCT_INV;
+"CPRODUCT_MUL",CPRODUCT_MUL;
+"CPRODUCT_POW",CPRODUCT_POW;
+"CRAMER",CRAMER;
+"CRAMER_LEMMA",CRAMER_LEMMA;
+"CRAMER_LEMMA_TRANSP",CRAMER_LEMMA_TRANSP;
+"CRAMER_MATRIX_LEFT",CRAMER_MATRIX_LEFT;
+"CRAMER_MATRIX_LEFT_INVERSE",CRAMER_MATRIX_LEFT_INVERSE;
+"CRAMER_MATRIX_RIGHT",CRAMER_MATRIX_RIGHT;
+"CRAMER_MATRIX_RIGHT_INVERSE",CRAMER_MATRIX_RIGHT_INVERSE;
+"CROSS",CROSS;
+"CROSS_EQ_EMPTY",CROSS_EQ_EMPTY;
+"CSIN_0",CSIN_0;
+"CSIN_ADD",CSIN_ADD;
+"CSIN_CACS",CSIN_CACS;
+"CSIN_CACS_NZ",CSIN_CACS_NZ;
+"CSIN_CASN",CSIN_CASN;
+"CSIN_CCOS_CSQRT",CSIN_CCOS_CSQRT;
+"CSIN_CIRCLE",CSIN_CIRCLE;
+"CSIN_DOUBLE",CSIN_DOUBLE;
+"CSIN_EQ",CSIN_EQ;
+"CSIN_EQ_0",CSIN_EQ_0;
+"CSIN_EQ_1",CSIN_EQ_1;
+"CSIN_EQ_MINUS1",CSIN_EQ_MINUS1;
+"CSIN_NEG",CSIN_NEG;
+"CSIN_SUB",CSIN_SUB;
+"CSQRT",CSQRT;
+"CSQRT_0",CSQRT_0;
+"CSQRT_1",CSQRT_1;
+"CSQRT_CEXP_CLOG",CSQRT_CEXP_CLOG;
+"CSQRT_CX",CSQRT_CX;
+"CSQRT_EQ_0",CSQRT_EQ_0;
+"CSQRT_PRINCIPAL",CSQRT_PRINCIPAL;
+"CSQRT_UNIQUE",CSQRT_UNIQUE;
+"CTAN_0",CTAN_0;
+"CTAN_ADD",CTAN_ADD;
+"CTAN_CATN",CTAN_CATN;
+"CTAN_DOUBLE",CTAN_DOUBLE;
+"CTAN_NEG",CTAN_NEG;
+"CTAN_SUB",CTAN_SUB;
+"CURRY_DEF",CURRY_DEF;
+"CX_2PII_NZ",CX_2PII_NZ;
+"CX_ABS",CX_ABS;
+"CX_ACS",CX_ACS;
+"CX_ADD",CX_ADD;
+"CX_ASN",CX_ASN;
+"CX_ATN",CX_ATN;
+"CX_COS",CX_COS;
+"CX_COSH",CX_COSH;
+"CX_DEF",CX_DEF;
+"CX_DIV",CX_DIV;
+"CX_EXP",CX_EXP;
+"CX_IM_CNJ",CX_IM_CNJ;
+"CX_INJ",CX_INJ;
+"CX_INV",CX_INV;
+"CX_LOG",CX_LOG;
+"CX_MUL",CX_MUL;
+"CX_NEG",CX_NEG;
+"CX_PI_NZ",CX_PI_NZ;
+"CX_POW",CX_POW;
+"CX_RE_CNJ",CX_RE_CNJ;
+"CX_SIN",CX_SIN;
+"CX_SINH",CX_SINH;
+"CX_SQRT",CX_SQRT;
+"CX_SUB",CX_SUB;
+"CX_TAN",CX_TAN;
+"DECIMAL",DECIMAL;
+"DECOMPOSITION",DECOMPOSITION;
+"DECREASING_BOUNDED_VARIATION",DECREASING_BOUNDED_VARIATION;
+"DECREASING_CLOSED_NEST",DECREASING_CLOSED_NEST;
+"DECREASING_CLOSED_NEST_SING",DECREASING_CLOSED_NEST_SING;
+"DECREASING_LEFT_LIMIT",DECREASING_LEFT_LIMIT;
+"DECREASING_LEFT_LIMIT_1",DECREASING_LEFT_LIMIT_1;
+"DECREASING_RIGHT_LIMIT",DECREASING_RIGHT_LIMIT;
+"DECREASING_RIGHT_LIMIT_1",DECREASING_RIGHT_LIMIT_1;
+"DECREASING_VECTOR_VARIATION",DECREASING_VECTOR_VARIATION;
+"DELETE",DELETE;
+"DELETE_COMM",DELETE_COMM;
+"DELETE_DELETE",DELETE_DELETE;
+"DELETE_INSERT",DELETE_INSERT;
+"DELETE_INTER",DELETE_INTER;
+"DELETE_NON_ELEMENT",DELETE_NON_ELEMENT;
+"DELETE_SUBSET",DELETE_SUBSET;
+"DEMOIVRE",DEMOIVRE;
+"DENSE_ACCESSIBLE_FRONTIER_POINTS",DENSE_ACCESSIBLE_FRONTIER_POINTS;
+"DENSE_ACCESSIBLE_FRONTIER_POINTS_CONNECTED",DENSE_ACCESSIBLE_FRONTIER_POINTS_CONNECTED;
+"DENSE_ACCESSIBLE_FRONTIER_POINT_PAIRS",DENSE_ACCESSIBLE_FRONTIER_POINT_PAIRS;
+"DEPENDENT_2",DEPENDENT_2;
+"DEPENDENT_3",DEPENDENT_3;
+"DEPENDENT_AFFINE_DEPENDENT_CASES",DEPENDENT_AFFINE_DEPENDENT_CASES;
+"DEPENDENT_BIGGERSET",DEPENDENT_BIGGERSET;
+"DEPENDENT_BIGGERSET_GENERAL",DEPENDENT_BIGGERSET_GENERAL;
+"DEPENDENT_EXPLICIT",DEPENDENT_EXPLICIT;
+"DEPENDENT_FINITE",DEPENDENT_FINITE;
+"DEPENDENT_IMP_AFFINE_DEPENDENT",DEPENDENT_IMP_AFFINE_DEPENDENT;
+"DEPENDENT_LINEAR_IMAGE",DEPENDENT_LINEAR_IMAGE;
+"DEPENDENT_LINEAR_IMAGE_EQ",DEPENDENT_LINEAR_IMAGE_EQ;
+"DEPENDENT_MONO",DEPENDENT_MONO;
+"DEPENDENT_SING",DEPENDENT_SING;
+"DEST_MK_MULTIVECTOR",DEST_MK_MULTIVECTOR;
+"DEST_REC_INJ",DEST_REC_INJ;
+"DET_0",DET_0;
+"DET_1",DET_1;
+"DET_2",DET_2;
+"DET_3",DET_3;
+"DET_4",DET_4;
+"DET_CMUL",DET_CMUL;
+"DET_COFACTOR",DET_COFACTOR;
+"DET_COFACTOR_EXPANSION",DET_COFACTOR_EXPANSION;
+"DET_DEPENDENT_COLUMNS",DET_DEPENDENT_COLUMNS;
+"DET_DEPENDENT_ROWS",DET_DEPENDENT_ROWS;
+"DET_DIAGONAL",DET_DIAGONAL;
+"DET_EQ_0",DET_EQ_0;
+"DET_EQ_0_RANK",DET_EQ_0_RANK;
+"DET_I",DET_I;
+"DET_IDENTICAL_COLUMNS",DET_IDENTICAL_COLUMNS;
+"DET_IDENTICAL_ROWS",DET_IDENTICAL_ROWS;
+"DET_LINEAR_ROWS_VSUM",DET_LINEAR_ROWS_VSUM;
+"DET_LINEAR_ROWS_VSUM_LEMMA",DET_LINEAR_ROWS_VSUM_LEMMA;
+"DET_LINEAR_ROW_VSUM",DET_LINEAR_ROW_VSUM;
+"DET_LOWERTRIANGULAR",DET_LOWERTRIANGULAR;
+"DET_MATRIX_EQ_0",DET_MATRIX_EQ_0;
+"DET_MATRIX_EQ_0_LEFT",DET_MATRIX_EQ_0_LEFT;
+"DET_MATRIX_EQ_0_RIGHT",DET_MATRIX_EQ_0_RIGHT;
+"DET_MATRIX_REFLECT_ALONG",DET_MATRIX_REFLECT_ALONG;
+"DET_MATRIX_ROTATE2D",DET_MATRIX_ROTATE2D;
+"DET_MUL",DET_MUL;
+"DET_NEG",DET_NEG;
+"DET_ORTHOGONAL_MATRIX",DET_ORTHOGONAL_MATRIX;
+"DET_PERMUTE_COLUMNS",DET_PERMUTE_COLUMNS;
+"DET_PERMUTE_ROWS",DET_PERMUTE_ROWS;
+"DET_ROWS_MUL",DET_ROWS_MUL;
+"DET_ROW_ADD",DET_ROW_ADD;
+"DET_ROW_MUL",DET_ROW_MUL;
+"DET_ROW_OPERATION",DET_ROW_OPERATION;
+"DET_ROW_SPAN",DET_ROW_SPAN;
+"DET_TRANSP",DET_TRANSP;
+"DET_UPPERTRIANGULAR",DET_UPPERTRIANGULAR;
+"DET_ZERO_COLUMN",DET_ZERO_COLUMN;
+"DET_ZERO_ROW",DET_ZERO_ROW;
+"DE_MORGAN_THM",DE_MORGAN_THM;
+"DIAMETER_ATTAINED_FRONTIER",DIAMETER_ATTAINED_FRONTIER;
+"DIAMETER_ATTAINED_RELATIVE_FRONTIER",DIAMETER_ATTAINED_RELATIVE_FRONTIER;
+"DIAMETER_BALL",DIAMETER_BALL;
+"DIAMETER_BOUNDED",DIAMETER_BOUNDED;
+"DIAMETER_BOUNDED_BOUND",DIAMETER_BOUNDED_BOUND;
+"DIAMETER_BOUNDED_BOUND_LT",DIAMETER_BOUNDED_BOUND_LT;
+"DIAMETER_CBALL",DIAMETER_CBALL;
+"DIAMETER_CLOSURE",DIAMETER_CLOSURE;
+"DIAMETER_COMPACT_ATTAINED",DIAMETER_COMPACT_ATTAINED;
+"DIAMETER_CONVEX_HULL",DIAMETER_CONVEX_HULL;
+"DIAMETER_EMPTY",DIAMETER_EMPTY;
+"DIAMETER_EQ_0",DIAMETER_EQ_0;
+"DIAMETER_FRONTIER",DIAMETER_FRONTIER;
+"DIAMETER_INTERVAL",DIAMETER_INTERVAL;
+"DIAMETER_LE",DIAMETER_LE;
+"DIAMETER_LINEAR_IMAGE",DIAMETER_LINEAR_IMAGE;
+"DIAMETER_POS_LE",DIAMETER_POS_LE;
+"DIAMETER_RELATIVE_FRONTIER",DIAMETER_RELATIVE_FRONTIER;
+"DIAMETER_SIMPLEX",DIAMETER_SIMPLEX;
+"DIAMETER_SING",DIAMETER_SING;
+"DIAMETER_SPHERE",DIAMETER_SPHERE;
+"DIAMETER_SUBSET",DIAMETER_SUBSET;
+"DIAMETER_SUBSET_CBALL",DIAMETER_SUBSET_CBALL;
+"DIAMETER_SUBSET_CBALL_NONEMPTY",DIAMETER_SUBSET_CBALL_NONEMPTY;
+"DIAMETER_TRANSLATION",DIAMETER_TRANSLATION;
+"DIFF",DIFF;
+"DIFFERENTIABLE_ADD",DIFFERENTIABLE_ADD;
+"DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON",DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON;
+"DIFFERENTIABLE_AT_LIFT_DOT2",DIFFERENTIABLE_AT_LIFT_DOT2;
+"DIFFERENTIABLE_AT_WITHIN",DIFFERENTIABLE_AT_WITHIN;
+"DIFFERENTIABLE_BOUND",DIFFERENTIABLE_BOUND;
+"DIFFERENTIABLE_CHAIN_AT",DIFFERENTIABLE_CHAIN_AT;
+"DIFFERENTIABLE_CHAIN_WITHIN",DIFFERENTIABLE_CHAIN_WITHIN;
+"DIFFERENTIABLE_CMUL",DIFFERENTIABLE_CMUL;
+"DIFFERENTIABLE_COMPONENTWISE_AT",DIFFERENTIABLE_COMPONENTWISE_AT;
+"DIFFERENTIABLE_COMPONENTWISE_WITHIN",DIFFERENTIABLE_COMPONENTWISE_WITHIN;
+"DIFFERENTIABLE_CONST",DIFFERENTIABLE_CONST;
+"DIFFERENTIABLE_ID",DIFFERENTIABLE_ID;
+"DIFFERENTIABLE_IMP_CONTINUOUS_AT",DIFFERENTIABLE_IMP_CONTINUOUS_AT;
+"DIFFERENTIABLE_IMP_CONTINUOUS_ON",DIFFERENTIABLE_IMP_CONTINUOUS_ON;
+"DIFFERENTIABLE_IMP_CONTINUOUS_WITHIN",DIFFERENTIABLE_IMP_CONTINUOUS_WITHIN;
+"DIFFERENTIABLE_IMP_PIECEWISE_DIFFERENTIABLE",DIFFERENTIABLE_IMP_PIECEWISE_DIFFERENTIABLE;
+"DIFFERENTIABLE_LIFT_COMPONENT",DIFFERENTIABLE_LIFT_COMPONENT;
+"DIFFERENTIABLE_LINEAR",DIFFERENTIABLE_LINEAR;
+"DIFFERENTIABLE_MUL_AT",DIFFERENTIABLE_MUL_AT;
+"DIFFERENTIABLE_MUL_WITHIN",DIFFERENTIABLE_MUL_WITHIN;
+"DIFFERENTIABLE_NEG",DIFFERENTIABLE_NEG;
+"DIFFERENTIABLE_NORM_AT",DIFFERENTIABLE_NORM_AT;
+"DIFFERENTIABLE_ON_ADD",DIFFERENTIABLE_ON_ADD;
+"DIFFERENTIABLE_ON_COMPOSE",DIFFERENTIABLE_ON_COMPOSE;
+"DIFFERENTIABLE_ON_CONST",DIFFERENTIABLE_ON_CONST;
+"DIFFERENTIABLE_ON_EMPTY",DIFFERENTIABLE_ON_EMPTY;
+"DIFFERENTIABLE_ON_EQ_DIFFERENTIABLE_AT",DIFFERENTIABLE_ON_EQ_DIFFERENTIABLE_AT;
+"DIFFERENTIABLE_ON_ID",DIFFERENTIABLE_ON_ID;
+"DIFFERENTIABLE_ON_IMP_PIECEWISE_DIFFERENTIABLE",DIFFERENTIABLE_ON_IMP_PIECEWISE_DIFFERENTIABLE;
+"DIFFERENTIABLE_ON_LIFT_DOT2",DIFFERENTIABLE_ON_LIFT_DOT2;
+"DIFFERENTIABLE_ON_LINEAR",DIFFERENTIABLE_ON_LINEAR;
+"DIFFERENTIABLE_ON_MUL",DIFFERENTIABLE_ON_MUL;
+"DIFFERENTIABLE_ON_NEG",DIFFERENTIABLE_ON_NEG;
+"DIFFERENTIABLE_ON_NORM",DIFFERENTIABLE_ON_NORM;
+"DIFFERENTIABLE_ON_REAL_POLYNOMIAL_FUNCTION",DIFFERENTIABLE_ON_REAL_POLYNOMIAL_FUNCTION;
+"DIFFERENTIABLE_ON_SQNORM",DIFFERENTIABLE_ON_SQNORM;
+"DIFFERENTIABLE_ON_SUB",DIFFERENTIABLE_ON_SUB;
+"DIFFERENTIABLE_ON_SUBSET",DIFFERENTIABLE_ON_SUBSET;
+"DIFFERENTIABLE_ON_VECTOR_POLYNOMIAL_FUNCTION",DIFFERENTIABLE_ON_VECTOR_POLYNOMIAL_FUNCTION;
+"DIFFERENTIABLE_REAL_POLYNOMIAL_FUNCTION_AT",DIFFERENTIABLE_REAL_POLYNOMIAL_FUNCTION_AT;
+"DIFFERENTIABLE_SQNORM_AT",DIFFERENTIABLE_SQNORM_AT;
+"DIFFERENTIABLE_SUB",DIFFERENTIABLE_SUB;
+"DIFFERENTIABLE_TRANSFORM_AT",DIFFERENTIABLE_TRANSFORM_AT;
+"DIFFERENTIABLE_TRANSFORM_WITHIN",DIFFERENTIABLE_TRANSFORM_WITHIN;
+"DIFFERENTIABLE_VECTOR_POLYNOMIAL_FUNCTION",DIFFERENTIABLE_VECTOR_POLYNOMIAL_FUNCTION;
+"DIFFERENTIABLE_VSUM",DIFFERENTIABLE_VSUM;
+"DIFFERENTIABLE_VSUM_NUMSEG",DIFFERENTIABLE_VSUM_NUMSEG;
+"DIFFERENTIABLE_WITHIN_LIFT_DOT2",DIFFERENTIABLE_WITHIN_LIFT_DOT2;
+"DIFFERENTIABLE_WITHIN_OPEN",DIFFERENTIABLE_WITHIN_OPEN;
+"DIFFERENTIABLE_WITHIN_SUBSET",DIFFERENTIABLE_WITHIN_SUBSET;
+"DIFFERENTIAL_COMPONENT_NEG_AT_MAXIMUM",DIFFERENTIAL_COMPONENT_NEG_AT_MAXIMUM;
+"DIFFERENTIAL_COMPONENT_POS_AT_MINIMUM",DIFFERENTIAL_COMPONENT_POS_AT_MINIMUM;
+"DIFFERENTIAL_COMPONENT_ZERO_AT_MAXMIN",DIFFERENTIAL_COMPONENT_ZERO_AT_MAXMIN;
+"DIFFERENTIAL_ZERO_MAXMIN",DIFFERENTIAL_ZERO_MAXMIN;
+"DIFFERENTIAL_ZERO_MAXMIN_COMPONENT",DIFFERENTIAL_ZERO_MAXMIN_COMPONENT;
+"DIFFERENT_NORM_3_COLLINEAR_POINTS",DIFFERENT_NORM_3_COLLINEAR_POINTS;
+"DIFFS_AFFINE_HULL_SPAN",DIFFS_AFFINE_HULL_SPAN;
+"DIFF_CHAIN_AT",DIFF_CHAIN_AT;
+"DIFF_CHAIN_WITHIN",DIFF_CHAIN_WITHIN;
+"DIFF_DIFF",DIFF_DIFF;
+"DIFF_EMPTY",DIFF_EMPTY;
+"DIFF_EQ_EMPTY",DIFF_EQ_EMPTY;
+"DIFF_INSERT",DIFF_INSERT;
+"DIFF_INTERS",DIFF_INTERS;
+"DIFF_UNIONS",DIFF_UNIONS;
+"DIFF_UNIONS_NONEMPTY",DIFF_UNIONS_NONEMPTY;
+"DIFF_UNIV",DIFF_UNIV;
+"DIMINDEX_1",DIMINDEX_1;
+"DIMINDEX_2",DIMINDEX_2;
+"DIMINDEX_3",DIMINDEX_3;
+"DIMINDEX_4",DIMINDEX_4;
+"DIMINDEX_FINITE_IMAGE",DIMINDEX_FINITE_IMAGE;
+"DIMINDEX_FINITE_SUM",DIMINDEX_FINITE_SUM;
+"DIMINDEX_GE_1",DIMINDEX_GE_1;
+"DIMINDEX_HAS_SIZE_FINITE_SUM",DIMINDEX_HAS_SIZE_FINITE_SUM;
+"DIMINDEX_MULTIVECTOR",DIMINDEX_MULTIVECTOR;
+"DIMINDEX_NONZERO",DIMINDEX_NONZERO;
+"DIMINDEX_UNIQUE",DIMINDEX_UNIQUE;
+"DIMINDEX_UNIV",DIMINDEX_UNIV;
+"DIM_CLOSURE",DIM_CLOSURE;
+"DIM_EMPTY",DIM_EMPTY;
+"DIM_EQ_0",DIM_EQ_0;
+"DIM_EQ_CARD",DIM_EQ_CARD;
+"DIM_EQ_FULL",DIM_EQ_FULL;
+"DIM_EQ_HYPERPLANE",DIM_EQ_HYPERPLANE;
+"DIM_EQ_SPAN",DIM_EQ_SPAN;
+"DIM_HYPERPLANE",DIM_HYPERPLANE;
+"DIM_IMAGE_KERNEL",DIM_IMAGE_KERNEL;
+"DIM_IMAGE_KERNEL_GEN",DIM_IMAGE_KERNEL_GEN;
+"DIM_INJECTIVE_LINEAR_IMAGE",DIM_INJECTIVE_LINEAR_IMAGE;
+"DIM_INSERT",DIM_INSERT;
+"DIM_INSERT_0",DIM_INSERT_0;
+"DIM_KERNEL_COMPOSE",DIM_KERNEL_COMPOSE;
+"DIM_LE_CARD",DIM_LE_CARD;
+"DIM_LINEAR_IMAGE_LE",DIM_LINEAR_IMAGE_LE;
+"DIM_OPEN",DIM_OPEN;
+"DIM_OPEN_IN",DIM_OPEN_IN;
+"DIM_ORTHOGONAL_SUM",DIM_ORTHOGONAL_SUM;
+"DIM_PCROSS",DIM_PCROSS;
+"DIM_PCROSS_STRONG",DIM_PCROSS_STRONG;
+"DIM_PSUBSET",DIM_PSUBSET;
+"DIM_ROWS_LE_DIM_COLUMNS",DIM_ROWS_LE_DIM_COLUMNS;
+"DIM_SING",DIM_SING;
+"DIM_SPAN",DIM_SPAN;
+"DIM_SPECIAL_HYPERPLANE",DIM_SPECIAL_HYPERPLANE;
+"DIM_SPECIAL_SUBSPACE",DIM_SPECIAL_SUBSPACE;
+"DIM_SUBSET",DIM_SUBSET;
+"DIM_SUBSET_UNIV",DIM_SUBSET_UNIV;
+"DIM_SUBSPACE_ORTHOGONAL_TO_VECTORS",DIM_SUBSPACE_ORTHOGONAL_TO_VECTORS;
+"DIM_SUBSTANDARD",DIM_SUBSTANDARD;
+"DIM_SUMS_INTER",DIM_SUMS_INTER;
+"DIM_UNIQUE",DIM_UNIQUE;
+"DIM_UNIV",DIM_UNIV;
+"DINI",DINI;
+"DISCRETE_BOUNDED_IMP_FINITE",DISCRETE_BOUNDED_IMP_FINITE;
+"DISCRETE_IMP_CLOSED",DISCRETE_IMP_CLOSED;
+"DISCRETE_IMP_COUNTABLE",DISCRETE_IMP_COUNTABLE;
+"DISJOINT",DISJOINT;
+"DISJOINT_AFFINE_HULL",DISJOINT_AFFINE_HULL;
+"DISJOINT_DELETE_SYM",DISJOINT_DELETE_SYM;
+"DISJOINT_EMPTY",DISJOINT_EMPTY;
+"DISJOINT_EMPTY_REFL",DISJOINT_EMPTY_REFL;
+"DISJOINT_INSERT",DISJOINT_INSERT;
+"DISJOINT_INTERVAL",DISJOINT_INTERVAL;
+"DISJOINT_INTERVAL_1",DISJOINT_INTERVAL_1;
+"DISJOINT_NUMSEG",DISJOINT_NUMSEG;
+"DISJOINT_SYM",DISJOINT_SYM;
+"DISJOINT_UNION",DISJOINT_UNION;
+"DISJ_ACI",DISJ_ACI;
+"DISJ_ASSOC",DISJ_ASSOC;
+"DISJ_SYM",DISJ_SYM;
+"DISTANCE_ATTAINS_INF",DISTANCE_ATTAINS_INF;
+"DISTANCE_ATTAINS_SUP",DISTANCE_ATTAINS_SUP;
+"DIST_0",DIST_0;
+"DIST_ADD2",DIST_ADD2;
+"DIST_ADD2_REV",DIST_ADD2_REV;
+"DIST_ADDBOUND",DIST_ADDBOUND;
+"DIST_CEXP_II_1",DIST_CEXP_II_1;
+"DIST_CLOSEST_POINT_LIPSCHITZ",DIST_CLOSEST_POINT_LIPSCHITZ;
+"DIST_ELIM_THM",DIST_ELIM_THM;
+"DIST_EQ",DIST_EQ;
+"DIST_EQ_0",DIST_EQ_0;
+"DIST_FSTCART",DIST_FSTCART;
+"DIST_INCREASES_ONLINE",DIST_INCREASES_ONLINE;
+"DIST_IN_CLOSED_SEGMENT",DIST_IN_CLOSED_SEGMENT;
+"DIST_IN_OPEN_SEGMENT",DIST_IN_OPEN_SEGMENT;
+"DIST_LADD",DIST_LADD;
+"DIST_LADD_0",DIST_LADD_0;
+"DIST_LE_0",DIST_LE_0;
+"DIST_LE_CASES",DIST_LE_CASES;
+"DIST_LIFT",DIST_LIFT;
+"DIST_LMUL",DIST_LMUL;
+"DIST_LZERO",DIST_LZERO;
+"DIST_MIDPOINT",DIST_MIDPOINT;
+"DIST_MUL",DIST_MUL;
+"DIST_NZ",DIST_NZ;
+"DIST_PASTECART_CANCEL",DIST_PASTECART_CANCEL;
+"DIST_POS_LE",DIST_POS_LE;
+"DIST_POS_LT",DIST_POS_LT;
+"DIST_RADD",DIST_RADD;
+"DIST_RADD_0",DIST_RADD_0;
+"DIST_REAL",DIST_REAL;
+"DIST_REFL",DIST_REFL;
+"DIST_RMUL",DIST_RMUL;
+"DIST_RZERO",DIST_RZERO;
+"DIST_SNDCART",DIST_SNDCART;
+"DIST_SYM",DIST_SYM;
+"DIST_TRIANGLE",DIST_TRIANGLE;
+"DIST_TRIANGLES_LE",DIST_TRIANGLES_LE;
+"DIST_TRIANGLE_ADD",DIST_TRIANGLE_ADD;
+"DIST_TRIANGLE_ADD_HALF",DIST_TRIANGLE_ADD_HALF;
+"DIST_TRIANGLE_ALT",DIST_TRIANGLE_ALT;
+"DIST_TRIANGLE_EQ",DIST_TRIANGLE_EQ;
+"DIST_TRIANGLE_HALF_L",DIST_TRIANGLE_HALF_L;
+"DIST_TRIANGLE_HALF_R",DIST_TRIANGLE_HALF_R;
+"DIST_TRIANGLE_LE",DIST_TRIANGLE_LE;
+"DIST_TRIANGLE_LT",DIST_TRIANGLE_LT;
+"DIVISION",DIVISION;
+"DIVISION_0",DIVISION_0;
+"DIVISION_COMMON_POINT_BOUND",DIVISION_COMMON_POINT_BOUND;
+"DIVISION_CONTAINS",DIVISION_CONTAINS;
+"DIVISION_DISJOINT_UNION",DIVISION_DISJOINT_UNION;
+"DIVISION_DOUBLESPLIT",DIVISION_DOUBLESPLIT;
+"DIVISION_INTER",DIVISION_INTER;
+"DIVISION_INTER_1",DIVISION_INTER_1;
+"DIVISION_OF",DIVISION_OF;
+"DIVISION_OF_AFFINITY",DIVISION_OF_AFFINITY;
+"DIVISION_OF_CLOSED",DIVISION_OF_CLOSED;
+"DIVISION_OF_CONTENT_0",DIVISION_OF_CONTENT_0;
+"DIVISION_OF_FINITE",DIVISION_OF_FINITE;
+"DIVISION_OF_NONTRIVIAL",DIVISION_OF_NONTRIVIAL;
+"DIVISION_OF_REFLECT",DIVISION_OF_REFLECT;
+"DIVISION_OF_SELF",DIVISION_OF_SELF;
+"DIVISION_OF_SING",DIVISION_OF_SING;
+"DIVISION_OF_SUBSET",DIVISION_OF_SUBSET;
+"DIVISION_OF_TAGGED_DIVISION",DIVISION_OF_TAGGED_DIVISION;
+"DIVISION_OF_TRANSLATION",DIVISION_OF_TRANSLATION;
+"DIVISION_OF_TRIVIAL",DIVISION_OF_TRIVIAL;
+"DIVISION_OF_UNIONS",DIVISION_OF_UNIONS;
+"DIVISION_OF_UNION_SELF",DIVISION_OF_UNION_SELF;
+"DIVISION_POINTS_FINITE",DIVISION_POINTS_FINITE;
+"DIVISION_POINTS_PSUBSET",DIVISION_POINTS_PSUBSET;
+"DIVISION_POINTS_SUBSET",DIVISION_POINTS_SUBSET;
+"DIVISION_SIMP",DIVISION_SIMP;
+"DIVISION_SPLIT",DIVISION_SPLIT;
+"DIVISION_SPLIT_LEFT_INJ",DIVISION_SPLIT_LEFT_INJ;
+"DIVISION_SPLIT_RIGHT_INJ",DIVISION_SPLIT_RIGHT_INJ;
+"DIVISION_UNION_INTERVALS_EXISTS",DIVISION_UNION_INTERVALS_EXISTS;
+"DIVMOD_ELIM_THM",DIVMOD_ELIM_THM;
+"DIVMOD_ELIM_THM'",DIVMOD_ELIM_THM';
+"DIVMOD_EXIST",DIVMOD_EXIST;
+"DIVMOD_EXIST_0",DIVMOD_EXIST_0;
+"DIVMOD_UNIQ",DIVMOD_UNIQ;
+"DIVMOD_UNIQ_LEMMA",DIVMOD_UNIQ_LEMMA;
+"DIV_0",DIV_0;
+"DIV_1",DIV_1;
+"DIV_ADD_MOD",DIV_ADD_MOD;
+"DIV_DIV",DIV_DIV;
+"DIV_EQ_0",DIV_EQ_0;
+"DIV_EQ_EXCLUSION",DIV_EQ_EXCLUSION;
+"DIV_LE",DIV_LE;
+"DIV_LE_EXCLUSION",DIV_LE_EXCLUSION;
+"DIV_LT",DIV_LT;
+"DIV_MOD",DIV_MOD;
+"DIV_MONO",DIV_MONO;
+"DIV_MONO2",DIV_MONO2;
+"DIV_MONO_LT",DIV_MONO_LT;
+"DIV_MULT",DIV_MULT;
+"DIV_MULT2",DIV_MULT2;
+"DIV_MULT_ADD",DIV_MULT_ADD;
+"DIV_MUL_LE",DIV_MUL_LE;
+"DIV_REFL",DIV_REFL;
+"DIV_UNIQ",DIV_UNIQ;
+"DOMINATED_CONVERGENCE",DOMINATED_CONVERGENCE;
+"DOMINATED_CONVERGENCE_ABSOLUTELY_INTEGRABLE",DOMINATED_CONVERGENCE_ABSOLUTELY_INTEGRABLE;
+"DOMINATED_CONVERGENCE_INTEGRABLE",DOMINATED_CONVERGENCE_INTEGRABLE;
+"DOT_1",DOT_1;
+"DOT_2",DOT_2;
+"DOT_3",DOT_3;
+"DOT_4",DOT_4;
+"DOT_BASIS",DOT_BASIS;
+"DOT_BASIS_BASIS",DOT_BASIS_BASIS;
+"DOT_BASIS_BASIS_UNEQUAL",DOT_BASIS_BASIS_UNEQUAL;
+"DOT_CAUCHY_SCHWARZ_EQUAL",DOT_CAUCHY_SCHWARZ_EQUAL;
+"DOT_DROPOUT",DOT_DROPOUT;
+"DOT_EQ_0",DOT_EQ_0;
+"DOT_LADD",DOT_LADD;
+"DOT_LMUL",DOT_LMUL;
+"DOT_LMUL_MATRIX",DOT_LMUL_MATRIX;
+"DOT_LNEG",DOT_LNEG;
+"DOT_LSUB",DOT_LSUB;
+"DOT_LSUM",DOT_LSUM;
+"DOT_LZERO",DOT_LZERO;
+"DOT_MATRIX_PRODUCT",DOT_MATRIX_PRODUCT;
+"DOT_MATRIX_VECTOR_MUL",DOT_MATRIX_VECTOR_MUL;
+"DOT_NORM",DOT_NORM;
+"DOT_NORM_NEG",DOT_NORM_NEG;
+"DOT_NORM_SUB",DOT_NORM_SUB;
+"DOT_PASTECART",DOT_PASTECART;
+"DOT_POS_LE",DOT_POS_LE;
+"DOT_POS_LT",DOT_POS_LT;
+"DOT_PUSHIN",DOT_PUSHIN;
+"DOT_RADD",DOT_RADD;
+"DOT_RMUL",DOT_RMUL;
+"DOT_RNEG",DOT_RNEG;
+"DOT_ROWVECTOR_COLUMNVECTOR",DOT_ROWVECTOR_COLUMNVECTOR;
+"DOT_RSUB",DOT_RSUB;
+"DOT_RSUM",DOT_RSUM;
+"DOT_RZERO",DOT_RZERO;
+"DOT_SQUARE_NORM",DOT_SQUARE_NORM;
+"DOT_SYM",DOT_SYM;
+"DROPOUT_0",DROPOUT_0;
+"DROPOUT_ADD",DROPOUT_ADD;
+"DROPOUT_EQ",DROPOUT_EQ;
+"DROPOUT_GALOIS",DROPOUT_GALOIS;
+"DROPOUT_MUL",DROPOUT_MUL;
+"DROPOUT_PUSHIN",DROPOUT_PUSHIN;
+"DROPOUT_SUB",DROPOUT_SUB;
+"DROP_ADD",DROP_ADD;
+"DROP_CMUL",DROP_CMUL;
+"DROP_DIFFERENTIAL_NEG_AT_MAXIMUM",DROP_DIFFERENTIAL_NEG_AT_MAXIMUM;
+"DROP_DIFFERENTIAL_POS_AT_MINIMUM",DROP_DIFFERENTIAL_POS_AT_MINIMUM;
+"DROP_EQ",DROP_EQ;
+"DROP_EQ_0",DROP_EQ_0;
+"DROP_INDICATOR",DROP_INDICATOR;
+"DROP_INDICATOR_ABS_LE_1",DROP_INDICATOR_ABS_LE_1;
+"DROP_INDICATOR_LE_1",DROP_INDICATOR_LE_1;
+"DROP_INDICATOR_POS_LE",DROP_INDICATOR_POS_LE;
+"DROP_IN_IMAGE_DROP",DROP_IN_IMAGE_DROP;
+"DROP_LAMBDA",DROP_LAMBDA;
+"DROP_NEG",DROP_NEG;
+"DROP_SUB",DROP_SUB;
+"DROP_VEC",DROP_VEC;
+"DROP_VSUM",DROP_VSUM;
+"DROP_WLOG_LE",DROP_WLOG_LE;
+"DSUM_BOUND",DSUM_BOUND;
+"EDELSTEIN_FIX",EDELSTEIN_FIX;
+"EDGE_OF_IMP_SUBSET",EDGE_OF_IMP_SUBSET;
+"EDGE_OF_LINEAR_IMAGE",EDGE_OF_LINEAR_IMAGE;
+"EDGE_OF_TRANSLATION_EQ",EDGE_OF_TRANSLATION_EQ;
+"EL",EL;
+"ELEMENTARY_BOUNDED",ELEMENTARY_BOUNDED;
+"ELEMENTARY_COMPACT",ELEMENTARY_COMPACT;
+"ELEMENTARY_EMPTY",ELEMENTARY_EMPTY;
+"ELEMENTARY_INTER",ELEMENTARY_INTER;
+"ELEMENTARY_INTERS",ELEMENTARY_INTERS;
+"ELEMENTARY_INTERVAL",ELEMENTARY_INTERVAL;
+"ELEMENTARY_SUBSET_INTERVAL",ELEMENTARY_SUBSET_INTERVAL;
+"ELEMENTARY_UNION",ELEMENTARY_UNION;
+"ELEMENTARY_UNIONS_INTERVALS",ELEMENTARY_UNIONS_INTERVALS;
+"ELEMENTARY_UNION_INTERVAL",ELEMENTARY_UNION_INTERVAL;
+"ELEMENTARY_UNION_INTERVAL_STRONG",ELEMENTARY_UNION_INTERVAL_STRONG;
+"EL_APPEND",EL_APPEND;
+"EL_CONS",EL_CONS;
+"EL_MAP",EL_MAP;
+"EL_TL",EL_TL;
+"EMPTY",EMPTY;
+"EMPTY_AS_INTERVAL",EMPTY_AS_INTERVAL;
+"EMPTY_AS_REAL_INTERVAL",EMPTY_AS_REAL_INTERVAL;
+"EMPTY_DELETE",EMPTY_DELETE;
+"EMPTY_DIFF",EMPTY_DIFF;
+"EMPTY_DIVISION_OF",EMPTY_DIVISION_OF;
+"EMPTY_EXPOSED_FACE_OF",EMPTY_EXPOSED_FACE_OF;
+"EMPTY_FACE_OF",EMPTY_FACE_OF;
+"EMPTY_GSPEC",EMPTY_GSPEC;
+"EMPTY_INTERIOR_AFFINE_HULL",EMPTY_INTERIOR_AFFINE_HULL;
+"EMPTY_INTERIOR_CONVEX_HULL",EMPTY_INTERIOR_CONVEX_HULL;
+"EMPTY_INTERIOR_FINITE",EMPTY_INTERIOR_FINITE;
+"EMPTY_INTERIOR_LOWDIM",EMPTY_INTERIOR_LOWDIM;
+"EMPTY_INTERIOR_SUBSET_HYPERPLANE",EMPTY_INTERIOR_SUBSET_HYPERPLANE;
+"EMPTY_NOT_UNIV",EMPTY_NOT_UNIV;
+"EMPTY_SUBSET",EMPTY_SUBSET;
+"EMPTY_UNION",EMPTY_UNION;
+"EMPTY_UNIONS",EMPTY_UNIONS;
+"ENDPOINTS_SHIFTPATH",ENDPOINTS_SHIFTPATH;
+"ENDS_IN_INTERVAL",ENDS_IN_INTERVAL;
+"ENDS_IN_REAL_INTERVAL",ENDS_IN_REAL_INTERVAL;
+"ENDS_IN_SEGMENT",ENDS_IN_SEGMENT;
+"ENDS_IN_UNIT_INTERVAL",ENDS_IN_UNIT_INTERVAL;
+"ENDS_NOT_IN_SEGMENT",ENDS_NOT_IN_SEGMENT;
+"EPSILON_DELTA_MINIMAL",EPSILON_DELTA_MINIMAL;
+"EQUIINTEGRABLE_ADD",EQUIINTEGRABLE_ADD;
+"EQUIINTEGRABLE_CLOSED_INTERVAL_RESTRICTIONS",EQUIINTEGRABLE_CLOSED_INTERVAL_RESTRICTIONS;
+"EQUIINTEGRABLE_CMUL",EQUIINTEGRABLE_CMUL;
+"EQUIINTEGRABLE_DIVISION",EQUIINTEGRABLE_DIVISION;
+"EQUIINTEGRABLE_EQ",EQUIINTEGRABLE_EQ;
+"EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GE",EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GE;
+"EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GT",EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GT;
+"EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LE",EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LE;
+"EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LT",EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LT;
+"EQUIINTEGRABLE_LIMIT",EQUIINTEGRABLE_LIMIT;
+"EQUIINTEGRABLE_NEG",EQUIINTEGRABLE_NEG;
+"EQUIINTEGRABLE_ON_NULL",EQUIINTEGRABLE_ON_NULL;
+"EQUIINTEGRABLE_ON_SING",EQUIINTEGRABLE_ON_SING;
+"EQUIINTEGRABLE_ON_SPLIT",EQUIINTEGRABLE_ON_SPLIT;
+"EQUIINTEGRABLE_OPEN_INTERVAL_RESTRICTIONS",EQUIINTEGRABLE_OPEN_INTERVAL_RESTRICTIONS;
+"EQUIINTEGRABLE_REFLECT",EQUIINTEGRABLE_REFLECT;
+"EQUIINTEGRABLE_SUB",EQUIINTEGRABLE_SUB;
+"EQUIINTEGRABLE_SUBSET",EQUIINTEGRABLE_SUBSET;
+"EQUIINTEGRABLE_SUM",EQUIINTEGRABLE_SUM;
+"EQUIINTEGRABLE_UNIFORM_LIMIT",EQUIINTEGRABLE_UNIFORM_LIMIT;
+"EQUIINTEGRABLE_UNION",EQUIINTEGRABLE_UNION;
+"EQ_ADD_LCANCEL",EQ_ADD_LCANCEL;
+"EQ_ADD_LCANCEL_0",EQ_ADD_LCANCEL_0;
+"EQ_ADD_RCANCEL",EQ_ADD_RCANCEL;
+"EQ_ADD_RCANCEL_0",EQ_ADD_RCANCEL_0;
+"EQ_BALLS",EQ_BALLS;
+"EQ_C",EQ_C;
+"EQ_CLAUSES",EQ_CLAUSES;
+"EQ_C_BIJECTIONS",EQ_C_BIJECTIONS;
+"EQ_EXP",EQ_EXP;
+"EQ_EXT",EQ_EXT;
+"EQ_IMP",EQ_IMP;
+"EQ_IMP_LE",EQ_IMP_LE;
+"EQ_INTERVAL",EQ_INTERVAL;
+"EQ_INTERVAL_1",EQ_INTERVAL_1;
+"EQ_MULT_LCANCEL",EQ_MULT_LCANCEL;
+"EQ_MULT_RCANCEL",EQ_MULT_RCANCEL;
+"EQ_REFL",EQ_REFL;
+"EQ_SPAN_INSERT_EQ",EQ_SPAN_INSERT_EQ;
+"EQ_SYM",EQ_SYM;
+"EQ_SYM_EQ",EQ_SYM_EQ;
+"EQ_TRANS",EQ_TRANS;
+"EQ_UNIV",EQ_UNIV;
+"ETA_AX",ETA_AX;
+"EUCLIDEAN_SPACE_INFINITE",EUCLIDEAN_SPACE_INFINITE;
+"EULER",EULER;
+"EULER_ROTATION_THEOREM",EULER_ROTATION_THEOREM;
+"EULER_ROTOINVERSION_THEOREM",EULER_ROTOINVERSION_THEOREM;
+"EVEN",EVEN;
+"EVENPERM_COMPOSE",EVENPERM_COMPOSE;
+"EVENPERM_I",EVENPERM_I;
+"EVENPERM_INVERSE",EVENPERM_INVERSE;
+"EVENPERM_SWAP",EVENPERM_SWAP;
+"EVENPERM_UNIQUE",EVENPERM_UNIQUE;
+"EVENTUALLY_AND",EVENTUALLY_AND;
+"EVENTUALLY_AT",EVENTUALLY_AT;
+"EVENTUALLY_ATREAL",EVENTUALLY_ATREAL;
+"EVENTUALLY_AT_INFINITY",EVENTUALLY_AT_INFINITY;
+"EVENTUALLY_AT_NEGINFINITY",EVENTUALLY_AT_NEGINFINITY;
+"EVENTUALLY_AT_POSINFINITY",EVENTUALLY_AT_POSINFINITY;
+"EVENTUALLY_FALSE",EVENTUALLY_FALSE;
+"EVENTUALLY_FORALL",EVENTUALLY_FORALL;
+"EVENTUALLY_HAPPENS",EVENTUALLY_HAPPENS;
+"EVENTUALLY_MONO",EVENTUALLY_MONO;
+"EVENTUALLY_MP",EVENTUALLY_MP;
+"EVENTUALLY_SEQUENTIALLY",EVENTUALLY_SEQUENTIALLY;
+"EVENTUALLY_TRUE",EVENTUALLY_TRUE;
+"EVENTUALLY_WITHIN",EVENTUALLY_WITHIN;
+"EVENTUALLY_WITHINREAL",EVENTUALLY_WITHINREAL;
+"EVENTUALLY_WITHINREAL_LE",EVENTUALLY_WITHINREAL_LE;
+"EVENTUALLY_WITHIN_INTERIOR",EVENTUALLY_WITHIN_INTERIOR;
+"EVENTUALLY_WITHIN_LE",EVENTUALLY_WITHIN_LE;
+"EVEN_ADD",EVEN_ADD;
+"EVEN_AND_ODD",EVEN_AND_ODD;
+"EVEN_DOUBLE",EVEN_DOUBLE;
+"EVEN_EXISTS",EVEN_EXISTS;
+"EVEN_EXISTS_LEMMA",EVEN_EXISTS_LEMMA;
+"EVEN_EXP",EVEN_EXP;
+"EVEN_MOD",EVEN_MOD;
+"EVEN_MULT",EVEN_MULT;
+"EVEN_NSUM",EVEN_NSUM;
+"EVEN_ODD_DECOMPOSITION",EVEN_ODD_DECOMPOSITION;
+"EVEN_OR_ODD",EVEN_OR_ODD;
+"EVEN_SUB",EVEN_SUB;
+"EX",EX;
+"EXCHANGE_LEMMA",EXCHANGE_LEMMA;
+"EXCLUDED_MIDDLE",EXCLUDED_MIDDLE;
+"EXISTS_ARC_PSUBSET_SIMPLE_PATH",EXISTS_ARC_PSUBSET_SIMPLE_PATH;
+"EXISTS_BOOL_THM",EXISTS_BOOL_THM;
+"EXISTS_CNJ",EXISTS_CNJ;
+"EXISTS_COMPLEX",EXISTS_COMPLEX;
+"EXISTS_COMPLEX'",EXISTS_COMPLEX';
+"EXISTS_COMPLEX_ROOT",EXISTS_COMPLEX_ROOT;
+"EXISTS_COUNTABLE_SUBSET_IMAGE",EXISTS_COUNTABLE_SUBSET_IMAGE;
+"EXISTS_CURRY",EXISTS_CURRY;
+"EXISTS_DEF",EXISTS_DEF;
+"EXISTS_DIFF",EXISTS_DIFF;
+"EXISTS_DOUBLE_ARC",EXISTS_DOUBLE_ARC;
+"EXISTS_DROP",EXISTS_DROP;
+"EXISTS_DROP_FUN",EXISTS_DROP_FUN;
+"EXISTS_DROP_IMAGE",EXISTS_DROP_IMAGE;
+"EXISTS_EX",EXISTS_EX;
+"EXISTS_FINITE_SUBSET_IMAGE",EXISTS_FINITE_SUBSET_IMAGE;
+"EXISTS_IN_CLAUSES",EXISTS_IN_CLAUSES;
+"EXISTS_IN_GSPEC",EXISTS_IN_GSPEC;
+"EXISTS_IN_IMAGE",EXISTS_IN_IMAGE;
+"EXISTS_IN_INSERT",EXISTS_IN_INSERT;
+"EXISTS_IN_PCROSS",EXISTS_IN_PCROSS;
+"EXISTS_IN_UNIONS",EXISTS_IN_UNIONS;
+"EXISTS_LIFT",EXISTS_LIFT;
+"EXISTS_LIFT_FUN",EXISTS_LIFT_FUN;
+"EXISTS_LIFT_IMAGE",EXISTS_LIFT_IMAGE;
+"EXISTS_NOT_THM",EXISTS_NOT_THM;
+"EXISTS_ONE_REP",EXISTS_ONE_REP;
+"EXISTS_OPTION",EXISTS_OPTION;
+"EXISTS_OR_THM",EXISTS_OR_THM;
+"EXISTS_PAIRED_THM",EXISTS_PAIRED_THM;
+"EXISTS_PAIR_THM",EXISTS_PAIR_THM;
+"EXISTS_PASTECART",EXISTS_PASTECART;
+"EXISTS_PATH_SUBPATH_TO_FRONTIER",EXISTS_PATH_SUBPATH_TO_FRONTIER;
+"EXISTS_PATH_SUBPATH_TO_FRONTIER_CLOSED",EXISTS_PATH_SUBPATH_TO_FRONTIER_CLOSED;
+"EXISTS_REAL",EXISTS_REAL;
+"EXISTS_REFL",EXISTS_REFL;
+"EXISTS_SIMP",EXISTS_SIMP;
+"EXISTS_SUBARC_OF_ARC_NOENDS",EXISTS_SUBARC_OF_ARC_NOENDS;
+"EXISTS_SUBPATH_OF_ARC_NOENDS",EXISTS_SUBPATH_OF_ARC_NOENDS;
+"EXISTS_SUBPATH_OF_PATH",EXISTS_SUBPATH_OF_PATH;
+"EXISTS_SUBSET_IMAGE",EXISTS_SUBSET_IMAGE;
+"EXISTS_SUBSET_UNION",EXISTS_SUBSET_UNION;
+"EXISTS_SUM_THM",EXISTS_SUM_THM;
+"EXISTS_SWAP",EXISTS_SWAP;
+"EXISTS_THM",EXISTS_THM;
+"EXISTS_TRIPLED_THM",EXISTS_TRIPLED_THM;
+"EXISTS_UNCURRY",EXISTS_UNCURRY;
+"EXISTS_UNIQUE",EXISTS_UNIQUE;
+"EXISTS_UNIQUE_ALT",EXISTS_UNIQUE_ALT;
+"EXISTS_UNIQUE_DEF",EXISTS_UNIQUE_DEF;
+"EXISTS_UNIQUE_REFL",EXISTS_UNIQUE_REFL;
+"EXISTS_UNIQUE_THM",EXISTS_UNIQUE_THM;
+"EXISTS_VECTOR_1",EXISTS_VECTOR_1;
+"EXISTS_VECTOR_2",EXISTS_VECTOR_2;
+"EXISTS_VECTOR_3",EXISTS_VECTOR_3;
+"EXISTS_VECTOR_4",EXISTS_VECTOR_4;
+"EXP",EXP;
+"EXPAND_CLOSED_OPEN_INTERVAL",EXPAND_CLOSED_OPEN_INTERVAL;
+"EXPLICIT_SUBSET_INTERIOR_CONVEX_HULL",EXPLICIT_SUBSET_INTERIOR_CONVEX_HULL;
+"EXPLICIT_SUBSET_INTERIOR_CONVEX_HULL_MINIMAL",EXPLICIT_SUBSET_INTERIOR_CONVEX_HULL_MINIMAL;
+"EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL",EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL;
+"EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL_MINIMAL",EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL_MINIMAL;
+"EXPOSED_FACE_OF",EXPOSED_FACE_OF;
+"EXPOSED_FACE_OF_INTER",EXPOSED_FACE_OF_INTER;
+"EXPOSED_FACE_OF_INTERS",EXPOSED_FACE_OF_INTERS;
+"EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE",EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE;
+"EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE",EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE;
+"EXPOSED_FACE_OF_LINEAR_IMAGE",EXPOSED_FACE_OF_LINEAR_IMAGE;
+"EXPOSED_FACE_OF_PARALLEL",EXPOSED_FACE_OF_PARALLEL;
+"EXPOSED_FACE_OF_POLYHEDRON",EXPOSED_FACE_OF_POLYHEDRON;
+"EXPOSED_FACE_OF_REFL",EXPOSED_FACE_OF_REFL;
+"EXPOSED_FACE_OF_REFL_EQ",EXPOSED_FACE_OF_REFL_EQ;
+"EXPOSED_FACE_OF_SUMS",EXPOSED_FACE_OF_SUMS;
+"EXPOSED_FACE_OF_TRANSLATION_EQ",EXPOSED_FACE_OF_TRANSLATION_EQ;
+"EXPOSED_POINT_OF_FURTHEST_POINT",EXPOSED_POINT_OF_FURTHEST_POINT;
+"EXPOSED_POINT_OF_INTER_SUPPORTING_HYPERPLANE_GE",EXPOSED_POINT_OF_INTER_SUPPORTING_HYPERPLANE_GE;
+"EXPOSED_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE",EXPOSED_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE;
+"EXP_1",EXP_1;
+"EXP_2",EXP_2;
+"EXP_ADD",EXP_ADD;
+"EXP_EQ_0",EXP_EQ_0;
+"EXP_EQ_1",EXP_EQ_1;
+"EXP_LOG",EXP_LOG;
+"EXP_LT_0",EXP_LT_0;
+"EXP_MONO_EQ",EXP_MONO_EQ;
+"EXP_MONO_LE",EXP_MONO_LE;
+"EXP_MONO_LE_IMP",EXP_MONO_LE_IMP;
+"EXP_MONO_LT",EXP_MONO_LT;
+"EXP_MONO_LT_IMP",EXP_MONO_LT_IMP;
+"EXP_MULT",EXP_MULT;
+"EXP_ONE",EXP_ONE;
+"EXP_ZERO",EXP_ZERO;
+"EXTEND_FL",EXTEND_FL;
+"EXTEND_INSEG",EXTEND_INSEG;
+"EXTEND_LINSEG",EXTEND_LINSEG;
+"EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE",EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE;
+"EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE_GEN",EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE_GEN;
+"EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE_SIMPLE",EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE_SIMPLE;
+"EXTEND_MAP_CELL_COMPLEX_TO_SPHERE",EXTEND_MAP_CELL_COMPLEX_TO_SPHERE;
+"EXTEND_MAP_CELL_COMPLEX_TO_SPHERE_COFINITE",EXTEND_MAP_CELL_COMPLEX_TO_SPHERE_COFINITE;
+"EXTEND_MAP_SPHERE_TO_SPHERE",EXTEND_MAP_SPHERE_TO_SPHERE;
+"EXTEND_MAP_SPHERE_TO_SPHERE_COFINITE",EXTEND_MAP_SPHERE_TO_SPHERE_COFINITE;
+"EXTEND_MAP_SPHERE_TO_SPHERE_COFINITE_GEN",EXTEND_MAP_SPHERE_TO_SPHERE_COFINITE_GEN;
+"EXTEND_MAP_SPHERE_TO_SPHERE_GEN",EXTEND_MAP_SPHERE_TO_SPHERE_GEN;
+"EXTEND_MAP_UNIV_TO_SPHERE_COFINITE",EXTEND_MAP_UNIV_TO_SPHERE_COFINITE;
+"EXTEND_MAP_UNIV_TO_SPHERE_NO_BOUNDED_COMPONENT",EXTEND_MAP_UNIV_TO_SPHERE_NO_BOUNDED_COMPONENT;
+"EXTEND_TO_AFFINE_BASIS",EXTEND_TO_AFFINE_BASIS;
+"EXTENSION",EXTENSION;
+"EXTREME_POINTS_OF_CONVEX_HULL",EXTREME_POINTS_OF_CONVEX_HULL;
+"EXTREME_POINTS_OF_CONVEX_HULL_EQ",EXTREME_POINTS_OF_CONVEX_HULL_EQ;
+"EXTREME_POINTS_OF_LINEAR_IMAGE",EXTREME_POINTS_OF_LINEAR_IMAGE;
+"EXTREME_POINTS_OF_TRANSLATION",EXTREME_POINTS_OF_TRANSLATION;
+"EXTREME_POINT_EXISTS_CONVEX",EXTREME_POINT_EXISTS_CONVEX;
+"EXTREME_POINT_NOT_IN_INTERIOR",EXTREME_POINT_NOT_IN_INTERIOR;
+"EXTREME_POINT_NOT_IN_RELATIVE_INTERIOR",EXTREME_POINT_NOT_IN_RELATIVE_INTERIOR;
+"EXTREME_POINT_OF_CONIC",EXTREME_POINT_OF_CONIC;
+"EXTREME_POINT_OF_CONVEX_HULL",EXTREME_POINT_OF_CONVEX_HULL;
+"EXTREME_POINT_OF_CONVEX_HULL_2",EXTREME_POINT_OF_CONVEX_HULL_2;
+"EXTREME_POINT_OF_CONVEX_HULL_AFFINE_INDEPENDENT",EXTREME_POINT_OF_CONVEX_HULL_AFFINE_INDEPENDENT;
+"EXTREME_POINT_OF_CONVEX_HULL_CONVEX_INDEPENDENT",EXTREME_POINT_OF_CONVEX_HULL_CONVEX_INDEPENDENT;
+"EXTREME_POINT_OF_CONVEX_HULL_EQ",EXTREME_POINT_OF_CONVEX_HULL_EQ;
+"EXTREME_POINT_OF_CONVEX_HULL_INSERT",EXTREME_POINT_OF_CONVEX_HULL_INSERT;
+"EXTREME_POINT_OF_CONVEX_HULL_INSERT_EQ",EXTREME_POINT_OF_CONVEX_HULL_INSERT_EQ;
+"EXTREME_POINT_OF_EMPTY",EXTREME_POINT_OF_EMPTY;
+"EXTREME_POINT_OF_FACE",EXTREME_POINT_OF_FACE;
+"EXTREME_POINT_OF_INTER",EXTREME_POINT_OF_INTER;
+"EXTREME_POINT_OF_INTER_SUPPORTING_HYPERPLANE_GE",EXTREME_POINT_OF_INTER_SUPPORTING_HYPERPLANE_GE;
+"EXTREME_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE",EXTREME_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE;
+"EXTREME_POINT_OF_LINEAR_IMAGE",EXTREME_POINT_OF_LINEAR_IMAGE;
+"EXTREME_POINT_OF_MIDPOINT",EXTREME_POINT_OF_MIDPOINT;
+"EXTREME_POINT_OF_SEGMENT",EXTREME_POINT_OF_SEGMENT;
+"EXTREME_POINT_OF_SING",EXTREME_POINT_OF_SING;
+"EXTREME_POINT_OF_STILLCONVEX",EXTREME_POINT_OF_STILLCONVEX;
+"EXTREME_POINT_OF_TRANSLATION_EQ",EXTREME_POINT_OF_TRANSLATION_EQ;
+"EX_IMP",EX_IMP;
+"EX_MAP",EX_MAP;
+"EX_MEM",EX_MEM;
+"E_APPROX_32",E_APPROX_32;
+"FACES_OF_LINEAR_IMAGE",FACES_OF_LINEAR_IMAGE;
+"FACES_OF_SIMPLEX",FACES_OF_SIMPLEX;
+"FACES_OF_TRANSLATION",FACES_OF_TRANSLATION;
+"FACETS_OF_POLYHEDRON_EXPLICIT_DISTINCT",FACETS_OF_POLYHEDRON_EXPLICIT_DISTINCT;
+"FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT",FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT;
+"FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT_ALT",FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT_ALT;
+"FACET_OF_EMPTY",FACET_OF_EMPTY;
+"FACET_OF_HALFSPACE_GE",FACET_OF_HALFSPACE_GE;
+"FACET_OF_HALFSPACE_LE",FACET_OF_HALFSPACE_LE;
+"FACET_OF_IMP_FACE_OF",FACET_OF_IMP_FACE_OF;
+"FACET_OF_IMP_PROPER",FACET_OF_IMP_PROPER;
+"FACET_OF_IMP_SUBSET",FACET_OF_IMP_SUBSET;
+"FACET_OF_LINEAR_IMAGE",FACET_OF_LINEAR_IMAGE;
+"FACET_OF_POLYHEDRON",FACET_OF_POLYHEDRON;
+"FACET_OF_POLYHEDRON_EXPLICIT",FACET_OF_POLYHEDRON_EXPLICIT;
+"FACET_OF_REFL",FACET_OF_REFL;
+"FACET_OF_TRANSLATION_EQ",FACET_OF_TRANSLATION_EQ;
+"FACE_OF_AFFINE_EQ",FACE_OF_AFFINE_EQ;
+"FACE_OF_AFFINE_TRIVIAL",FACE_OF_AFFINE_TRIVIAL;
+"FACE_OF_AFF_DIM_LT",FACE_OF_AFF_DIM_LT;
+"FACE_OF_CONIC",FACE_OF_CONIC;
+"FACE_OF_CONVEX_HULLS",FACE_OF_CONVEX_HULLS;
+"FACE_OF_CONVEX_HULL_AFFINE_INDEPENDENT",FACE_OF_CONVEX_HULL_AFFINE_INDEPENDENT;
+"FACE_OF_CONVEX_HULL_INSERT",FACE_OF_CONVEX_HULL_INSERT;
+"FACE_OF_CONVEX_HULL_INSERT_EQ",FACE_OF_CONVEX_HULL_INSERT_EQ;
+"FACE_OF_CONVEX_HULL_SUBSET",FACE_OF_CONVEX_HULL_SUBSET;
+"FACE_OF_DISJOINT_INTERIOR",FACE_OF_DISJOINT_INTERIOR;
+"FACE_OF_DISJOINT_RELATIVE_INTERIOR",FACE_OF_DISJOINT_RELATIVE_INTERIOR;
+"FACE_OF_EMPTY",FACE_OF_EMPTY;
+"FACE_OF_EQ",FACE_OF_EQ;
+"FACE_OF_FACE",FACE_OF_FACE;
+"FACE_OF_HALFSPACE_GE",FACE_OF_HALFSPACE_GE;
+"FACE_OF_HALFSPACE_LE",FACE_OF_HALFSPACE_LE;
+"FACE_OF_IMP_CLOSED",FACE_OF_IMP_CLOSED;
+"FACE_OF_IMP_COMPACT",FACE_OF_IMP_COMPACT;
+"FACE_OF_IMP_CONVEX",FACE_OF_IMP_CONVEX;
+"FACE_OF_IMP_SUBSET",FACE_OF_IMP_SUBSET;
+"FACE_OF_INTER",FACE_OF_INTER;
+"FACE_OF_INTERS",FACE_OF_INTERS;
+"FACE_OF_INTER_INTER",FACE_OF_INTER_INTER;
+"FACE_OF_INTER_SUBFACE",FACE_OF_INTER_SUBFACE;
+"FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE",FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE;
+"FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE_STRONG",FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE_STRONG;
+"FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE",FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE;
+"FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE_STRONG",FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE_STRONG;
+"FACE_OF_LINEAR_IMAGE",FACE_OF_LINEAR_IMAGE;
+"FACE_OF_PCROSS",FACE_OF_PCROSS;
+"FACE_OF_PCROSS_DECOMP",FACE_OF_PCROSS_DECOMP;
+"FACE_OF_PCROSS_EQ",FACE_OF_PCROSS_EQ;
+"FACE_OF_POLYHEDRON",FACE_OF_POLYHEDRON;
+"FACE_OF_POLYHEDRON_EXPLICIT",FACE_OF_POLYHEDRON_EXPLICIT;
+"FACE_OF_POLYHEDRON_POLYHEDRON",FACE_OF_POLYHEDRON_POLYHEDRON;
+"FACE_OF_POLYHEDRON_SUBSET_EXPLICIT",FACE_OF_POLYHEDRON_SUBSET_EXPLICIT;
+"FACE_OF_POLYHEDRON_SUBSET_FACET",FACE_OF_POLYHEDRON_SUBSET_FACET;
+"FACE_OF_POLYTOPE_POLYTOPE",FACE_OF_POLYTOPE_POLYTOPE;
+"FACE_OF_REFL",FACE_OF_REFL;
+"FACE_OF_REFL_EQ",FACE_OF_REFL_EQ;
+"FACE_OF_SIMPLEX_SUBSET",FACE_OF_SIMPLEX_SUBSET;
+"FACE_OF_SING",FACE_OF_SING;
+"FACE_OF_SLICE",FACE_OF_SLICE;
+"FACE_OF_STILLCONVEX",FACE_OF_STILLCONVEX;
+"FACE_OF_SUBSET",FACE_OF_SUBSET;
+"FACE_OF_SUBSET_RELATIVE_BOUNDARY",FACE_OF_SUBSET_RELATIVE_BOUNDARY;
+"FACE_OF_SUBSET_RELATIVE_FRONTIER",FACE_OF_SUBSET_RELATIVE_FRONTIER;
+"FACE_OF_TRANS",FACE_OF_TRANS;
+"FACE_OF_TRANSLATION_EQ",FACE_OF_TRANSLATION_EQ;
+"FACT",FACT;
+"FACT_LE",FACT_LE;
+"FACT_LT",FACT_LT;
+"FACT_MONO",FACT_MONO;
+"FACT_NZ",FACT_NZ;
+"FARKAS_LEMMA",FARKAS_LEMMA;
+"FARKAS_LEMMA_ALT",FARKAS_LEMMA_ALT;
+"FASHODA",FASHODA;
+"FASHODA_INTERLACE",FASHODA_INTERLACE;
+"FASHODA_UNIT",FASHODA_UNIT;
+"FASHODA_UNIT_PATH",FASHODA_UNIT_PATH;
+"FCONS",FCONS;
+"FCONS_UNDO",FCONS_UNDO;
+"FILTER",FILTER;
+"FILTER_APPEND",FILTER_APPEND;
+"FILTER_MAP",FILTER_MAP;
+"FINE_DIVISION_EXISTS",FINE_DIVISION_EXISTS;
+"FINE_INTER",FINE_INTER;
+"FINE_INTERS",FINE_INTERS;
+"FINE_SUBSET",FINE_SUBSET;
+"FINE_UNION",FINE_UNION;
+"FINE_UNIONS",FINE_UNIONS;
+"FINITELY_GENERATED_CONIC_POLYHEDRON",FINITELY_GENERATED_CONIC_POLYHEDRON;
+"FINITE_BALL",FINITE_BALL;
+"FINITE_BITSET",FINITE_BITSET;
+"FINITE_BOOL",FINITE_BOOL;
+"FINITE_BOUNDED_FUNCTIONS",FINITE_BOUNDED_FUNCTIONS;
+"FINITE_CARD_COMPLEX_ROOTS_UNITY",FINITE_CARD_COMPLEX_ROOTS_UNITY;
+"FINITE_CARD_COMPLEX_ROOTS_UNITY_EXPLICIT",FINITE_CARD_COMPLEX_ROOTS_UNITY_EXPLICIT;
+"FINITE_CARD_LT",FINITE_CARD_LT;
+"FINITE_CART",FINITE_CART;
+"FINITE_CART_SUBSET_LEMMA",FINITE_CART_SUBSET_LEMMA;
+"FINITE_CART_UNIV",FINITE_CART_UNIV;
+"FINITE_CASES",FINITE_CASES;
+"FINITE_CBALL",FINITE_CBALL;
+"FINITE_COLUMNS",FINITE_COLUMNS;
+"FINITE_COMPLEX_ROOTS_UNITY",FINITE_COMPLEX_ROOTS_UNITY;
+"FINITE_COMPONENTS",FINITE_COMPONENTS;
+"FINITE_CROSS",FINITE_CROSS;
+"FINITE_DELETE",FINITE_DELETE;
+"FINITE_DELETE_IMP",FINITE_DELETE_IMP;
+"FINITE_DIFF",FINITE_DIFF;
+"FINITE_EMPTY",FINITE_EMPTY;
+"FINITE_EMPTY_INTERIOR",FINITE_EMPTY_INTERIOR;
+"FINITE_FACES_OF_SIMPLEX",FINITE_FACES_OF_SIMPLEX;
+"FINITE_FINITE_IMAGE",FINITE_FINITE_IMAGE;
+"FINITE_FINITE_PREIMAGE",FINITE_FINITE_PREIMAGE;
+"FINITE_FINITE_PREIMAGE_GENERAL",FINITE_FINITE_PREIMAGE_GENERAL;
+"FINITE_FINITE_UNIONS",FINITE_FINITE_UNIONS;
+"FINITE_FUNSPACE",FINITE_FUNSPACE;
+"FINITE_FUNSPACE_UNIV",FINITE_FUNSPACE_UNIV;
+"FINITE_HAS_SIZE",FINITE_HAS_SIZE;
+"FINITE_IMAGE",FINITE_IMAGE;
+"FINITE_IMAGE_EXPAND",FINITE_IMAGE_EXPAND;
+"FINITE_IMAGE_IMAGE",FINITE_IMAGE_IMAGE;
+"FINITE_IMAGE_INJ",FINITE_IMAGE_INJ;
+"FINITE_IMAGE_INJ_EQ",FINITE_IMAGE_INJ_EQ;
+"FINITE_IMAGE_INJ_GENERAL",FINITE_IMAGE_INJ_GENERAL;
+"FINITE_IMP_BOUNDED",FINITE_IMP_BOUNDED;
+"FINITE_IMP_BOUNDED_CONVEX_HULL",FINITE_IMP_BOUNDED_CONVEX_HULL;
+"FINITE_IMP_CLOSED",FINITE_IMP_CLOSED;
+"FINITE_IMP_CLOSED_IN",FINITE_IMP_CLOSED_IN;
+"FINITE_IMP_COMPACT",FINITE_IMP_COMPACT;
+"FINITE_IMP_COMPACT_CONVEX_HULL",FINITE_IMP_COMPACT_CONVEX_HULL;
+"FINITE_IMP_COUNTABLE",FINITE_IMP_COUNTABLE;
+"FINITE_IMP_NOT_OPEN",FINITE_IMP_NOT_OPEN;
+"FINITE_INDEX_INJ",FINITE_INDEX_INJ;
+"FINITE_INDEX_INRANGE",FINITE_INDEX_INRANGE;
+"FINITE_INDEX_INRANGE_2",FINITE_INDEX_INRANGE_2;
+"FINITE_INDEX_NUMBERS",FINITE_INDEX_NUMBERS;
+"FINITE_INDEX_NUMSEG",FINITE_INDEX_NUMSEG;
+"FINITE_INDEX_NUMSEG_SPECIAL",FINITE_INDEX_NUMSEG_SPECIAL;
+"FINITE_INDEX_WORKS",FINITE_INDEX_WORKS;
+"FINITE_INDUCT",FINITE_INDUCT;
+"FINITE_INDUCT_DELETE",FINITE_INDUCT_DELETE;
+"FINITE_INDUCT_STRONG",FINITE_INDUCT_STRONG;
+"FINITE_INSERT",FINITE_INSERT;
+"FINITE_INTER",FINITE_INTER;
+"FINITE_INTERVAL_1",FINITE_INTERVAL_1;
+"FINITE_INTER_COLLINEAR_OPEN_SEGMENTS",FINITE_INTER_COLLINEAR_OPEN_SEGMENTS;
+"FINITE_INTER_NUMSEG",FINITE_INTER_NUMSEG;
+"FINITE_INTSEG",FINITE_INTSEG;
+"FINITE_MULTIVECTOR",FINITE_MULTIVECTOR;
+"FINITE_NUMSEG",FINITE_NUMSEG;
+"FINITE_NUMSEG_LE",FINITE_NUMSEG_LE;
+"FINITE_NUMSEG_LT",FINITE_NUMSEG_LT;
+"FINITE_PCROSS",FINITE_PCROSS;
+"FINITE_PCROSS_EQ",FINITE_PCROSS_EQ;
+"FINITE_PERMUTATIONS",FINITE_PERMUTATIONS;
+"FINITE_POLYHEDRON_EXPOSED_FACES",FINITE_POLYHEDRON_EXPOSED_FACES;
+"FINITE_POLYHEDRON_EXTREME_POINTS",FINITE_POLYHEDRON_EXTREME_POINTS;
+"FINITE_POLYHEDRON_FACES",FINITE_POLYHEDRON_FACES;
+"FINITE_POLYHEDRON_FACETS",FINITE_POLYHEDRON_FACETS;
+"FINITE_POLYTOPE_FACES",FINITE_POLYTOPE_FACES;
+"FINITE_POLYTOPE_FACETS",FINITE_POLYTOPE_FACETS;
+"FINITE_POWERSET",FINITE_POWERSET;
+"FINITE_PRODUCT",FINITE_PRODUCT;
+"FINITE_PRODUCT_DEPENDENT",FINITE_PRODUCT_DEPENDENT;
+"FINITE_REAL_INTERVAL",FINITE_REAL_INTERVAL;
+"FINITE_RECURSION",FINITE_RECURSION;
+"FINITE_RECURSION_DELETE",FINITE_RECURSION_DELETE;
+"FINITE_RESTRICT",FINITE_RESTRICT;
+"FINITE_ROWS",FINITE_ROWS;
+"FINITE_RULES",FINITE_RULES;
+"FINITE_SEGMENT",FINITE_SEGMENT;
+"FINITE_SET_AVOID",FINITE_SET_AVOID;
+"FINITE_SET_OF_LIST",FINITE_SET_OF_LIST;
+"FINITE_SIMPLICES",FINITE_SIMPLICES;
+"FINITE_SING",FINITE_SING;
+"FINITE_SPHERE",FINITE_SPHERE;
+"FINITE_SPHERE_1",FINITE_SPHERE_1;
+"FINITE_STDBASIS",FINITE_STDBASIS;
+"FINITE_SUBSET",FINITE_SUBSET;
+"FINITE_SUBSET_IMAGE",FINITE_SUBSET_IMAGE;
+"FINITE_SUBSET_IMAGE_IMP",FINITE_SUBSET_IMAGE_IMP;
+"FINITE_SUM_IMAGE",FINITE_SUM_IMAGE;
+"FINITE_SUPPORT",FINITE_SUPPORT;
+"FINITE_SUPPORT_DELTA",FINITE_SUPPORT_DELTA;
+"FINITE_TRANSITIVITY_CHAIN",FINITE_TRANSITIVITY_CHAIN;
+"FINITE_UNION",FINITE_UNION;
+"FINITE_UNIONS",FINITE_UNIONS;
+"FINITE_UNION_IMP",FINITE_UNION_IMP;
+"FINREC",FINREC;
+"FINREC_1_LEMMA",FINREC_1_LEMMA;
+"FINREC_EXISTS_LEMMA",FINREC_EXISTS_LEMMA;
+"FINREC_FUN",FINREC_FUN;
+"FINREC_FUN_LEMMA",FINREC_FUN_LEMMA;
+"FINREC_SUC_LEMMA",FINREC_SUC_LEMMA;
+"FINREC_UNIQUE_LEMMA",FINREC_UNIQUE_LEMMA;
+"FIRST_CARTAN_THM_DIM_1",FIRST_CARTAN_THM_DIM_1;
+"FIXED_POINT_INESSENTIAL_SPHERE_MAP",FIXED_POINT_INESSENTIAL_SPHERE_MAP;
+"FIXING_SWAPSEQ_DECREASE",FIXING_SWAPSEQ_DECREASE;
+"FLATTEN_LEMMA",FLATTEN_LEMMA;
+"FLOOR",FLOOR;
+"FLOOR_DIV_DIV",FLOOR_DIV_DIV;
+"FLOOR_DOUBLE",FLOOR_DOUBLE;
+"FLOOR_EQ_0",FLOOR_EQ_0;
+"FLOOR_FRAC",FLOOR_FRAC;
+"FLOOR_MONO",FLOOR_MONO;
+"FLOOR_NUM",FLOOR_NUM;
+"FLOOR_POS",FLOOR_POS;
+"FLOOR_POS_LE",FLOOR_POS_LE;
+"FLOOR_UNIQUE",FLOOR_UNIQUE;
+"FL_RESTRICT",FL_RESTRICT;
+"FL_RESTRICTED_SUBSET",FL_RESTRICTED_SUBSET;
+"FL_SUC",FL_SUC;
+"FNIL",FNIL;
+"FORALL_1",FORALL_1;
+"FORALL_2",FORALL_2;
+"FORALL_3",FORALL_3;
+"FORALL_4",FORALL_4;
+"FORALL_ALL",FORALL_ALL;
+"FORALL_AND_THM",FORALL_AND_THM;
+"FORALL_BOOL_THM",FORALL_BOOL_THM;
+"FORALL_CNJ",FORALL_CNJ;
+"FORALL_COMPLEX",FORALL_COMPLEX;
+"FORALL_COUNTABLE_AS_IMAGE",FORALL_COUNTABLE_AS_IMAGE;
+"FORALL_COUNTABLE_SUBSET_IMAGE",FORALL_COUNTABLE_SUBSET_IMAGE;
+"FORALL_CURRY",FORALL_CURRY;
+"FORALL_DEF",FORALL_DEF;
+"FORALL_DIMINDEX_1",FORALL_DIMINDEX_1;
+"FORALL_DOT_EQ_0",FORALL_DOT_EQ_0;
+"FORALL_DROP",FORALL_DROP;
+"FORALL_DROP_FUN",FORALL_DROP_FUN;
+"FORALL_DROP_IMAGE",FORALL_DROP_IMAGE;
+"FORALL_EVENTUALLY",FORALL_EVENTUALLY;
+"FORALL_FINITE_INDEX",FORALL_FINITE_INDEX;
+"FORALL_FINITE_SUBSET_IMAGE",FORALL_FINITE_SUBSET_IMAGE;
+"FORALL_INTEGER",FORALL_INTEGER;
+"FORALL_IN_CLAUSES",FORALL_IN_CLAUSES;
+"FORALL_IN_CLOSURE",FORALL_IN_CLOSURE;
+"FORALL_IN_DIVISION",FORALL_IN_DIVISION;
+"FORALL_IN_DIVISION_NONEMPTY",FORALL_IN_DIVISION_NONEMPTY;
+"FORALL_IN_GSPEC",FORALL_IN_GSPEC;
+"FORALL_IN_IMAGE",FORALL_IN_IMAGE;
+"FORALL_IN_INSERT",FORALL_IN_INSERT;
+"FORALL_IN_PCROSS",FORALL_IN_PCROSS;
+"FORALL_IN_UNIONS",FORALL_IN_UNIONS;
+"FORALL_LIFT",FORALL_LIFT;
+"FORALL_LIFT_FUN",FORALL_LIFT_FUN;
+"FORALL_LIFT_IMAGE",FORALL_LIFT_IMAGE;
+"FORALL_MULTIVECTOR",FORALL_MULTIVECTOR;
+"FORALL_NOT_THM",FORALL_NOT_THM;
+"FORALL_OF_DROP",FORALL_OF_DROP;
+"FORALL_OF_PASTECART",FORALL_OF_PASTECART;
+"FORALL_OPTION",FORALL_OPTION;
+"FORALL_PAIRED_THM",FORALL_PAIRED_THM;
+"FORALL_PAIR_THM",FORALL_PAIR_THM;
+"FORALL_PASTECART",FORALL_PASTECART;
+"FORALL_POS_MONO",FORALL_POS_MONO;
+"FORALL_POS_MONO_1",FORALL_POS_MONO_1;
+"FORALL_REAL",FORALL_REAL;
+"FORALL_REAL_ONE",FORALL_REAL_ONE;
+"FORALL_SETCODE",FORALL_SETCODE;
+"FORALL_SIMP",FORALL_SIMP;
+"FORALL_SUBSET_IMAGE",FORALL_SUBSET_IMAGE;
+"FORALL_SUBSET_UNION",FORALL_SUBSET_UNION;
+"FORALL_SUC",FORALL_SUC;
+"FORALL_SUM_THM",FORALL_SUM_THM;
+"FORALL_TRIPLED_THM",FORALL_TRIPLED_THM;
+"FORALL_UNCURRY",FORALL_UNCURRY;
+"FORALL_UNWIND_THM1",FORALL_UNWIND_THM1;
+"FORALL_UNWIND_THM2",FORALL_UNWIND_THM2;
+"FORALL_VECTOR_1",FORALL_VECTOR_1;
+"FORALL_VECTOR_2",FORALL_VECTOR_2;
+"FORALL_VECTOR_3",FORALL_VECTOR_3;
+"FORALL_VECTOR_4",FORALL_VECTOR_4;
+"FRAC_FLOOR",FRAC_FLOOR;
+"FRAC_NUM",FRAC_NUM;
+"FRAC_UNIQUE",FRAC_UNIQUE;
+"FRECHET_DERIVATIVE_AT",FRECHET_DERIVATIVE_AT;
+"FRECHET_DERIVATIVE_CONST_AT",FRECHET_DERIVATIVE_CONST_AT;
+"FRECHET_DERIVATIVE_UNIQUE_AT",FRECHET_DERIVATIVE_UNIQUE_AT;
+"FRECHET_DERIVATIVE_UNIQUE_WITHIN",FRECHET_DERIVATIVE_UNIQUE_WITHIN;
+"FRECHET_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL",FRECHET_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL;
+"FRECHET_DERIVATIVE_UNIQUE_WITHIN_OPEN_INTERVAL",FRECHET_DERIVATIVE_UNIQUE_WITHIN_OPEN_INTERVAL;
+"FRECHET_DERIVATIVE_WITHIN_CLOSED_INTERVAL",FRECHET_DERIVATIVE_WITHIN_CLOSED_INTERVAL;
+"FRECHET_DERIVATIVE_WORKS",FRECHET_DERIVATIVE_WORKS;
+"FROM_0",FROM_0;
+"FROM_INTER_NUMSEG",FROM_INTER_NUMSEG;
+"FROM_INTER_NUMSEG_GEN",FROM_INTER_NUMSEG_GEN;
+"FRONTIER_BALL",FRONTIER_BALL;
+"FRONTIER_BIJECTIVE_LINEAR_IMAGE",FRONTIER_BIJECTIVE_LINEAR_IMAGE;
+"FRONTIER_CBALL",FRONTIER_CBALL;
+"FRONTIER_CLOSED",FRONTIER_CLOSED;
+"FRONTIER_CLOSED_INTERVAL",FRONTIER_CLOSED_INTERVAL;
+"FRONTIER_CLOSURES",FRONTIER_CLOSURES;
+"FRONTIER_CLOSURE_CONVEX",FRONTIER_CLOSURE_CONVEX;
+"FRONTIER_COMPLEMENT",FRONTIER_COMPLEMENT;
+"FRONTIER_CONVEX_HULL_CASES",FRONTIER_CONVEX_HULL_CASES;
+"FRONTIER_CONVEX_HULL_EXPLICIT",FRONTIER_CONVEX_HULL_EXPLICIT;
+"FRONTIER_DISJOINT_EQ",FRONTIER_DISJOINT_EQ;
+"FRONTIER_EMPTY",FRONTIER_EMPTY;
+"FRONTIER_EQ_EMPTY",FRONTIER_EQ_EMPTY;
+"FRONTIER_FRONTIER_FRONTIER",FRONTIER_FRONTIER_FRONTIER;
+"FRONTIER_FRONTIER_SUBSET",FRONTIER_FRONTIER_SUBSET;
+"FRONTIER_HALFSPACE_GE",FRONTIER_HALFSPACE_GE;
+"FRONTIER_HALFSPACE_GT",FRONTIER_HALFSPACE_GT;
+"FRONTIER_HALFSPACE_LE",FRONTIER_HALFSPACE_LE;
+"FRONTIER_HALFSPACE_LT",FRONTIER_HALFSPACE_LT;
+"FRONTIER_INJECTIVE_LINEAR_IMAGE",FRONTIER_INJECTIVE_LINEAR_IMAGE;
+"FRONTIER_INSIDE_SUBSET",FRONTIER_INSIDE_SUBSET;
+"FRONTIER_INTERIORS",FRONTIER_INTERIORS;
+"FRONTIER_INTER_SUBSET",FRONTIER_INTER_SUBSET;
+"FRONTIER_MINIMAL_SEPARATING_CLOSED",FRONTIER_MINIMAL_SEPARATING_CLOSED;
+"FRONTIER_NOT_EMPTY",FRONTIER_NOT_EMPTY;
+"FRONTIER_OF_COMPONENTS_CLOSED_COMPLEMENT",FRONTIER_OF_COMPONENTS_CLOSED_COMPLEMENT;
+"FRONTIER_OF_COMPONENTS_SUBSET",FRONTIER_OF_COMPONENTS_SUBSET;
+"FRONTIER_OF_CONNECTED_COMPONENT_SUBSET",FRONTIER_OF_CONNECTED_COMPONENT_SUBSET;
+"FRONTIER_OF_CONVEX_HULL",FRONTIER_OF_CONVEX_HULL;
+"FRONTIER_OF_TRIANGLE",FRONTIER_OF_TRIANGLE;
+"FRONTIER_OPEN_INTERVAL",FRONTIER_OPEN_INTERVAL;
+"FRONTIER_OUTSIDE_SUBSET",FRONTIER_OUTSIDE_SUBSET;
+"FRONTIER_RETRACT_OF_PUNCTURED_UNIVERSE",FRONTIER_RETRACT_OF_PUNCTURED_UNIVERSE;
+"FRONTIER_SING",FRONTIER_SING;
+"FRONTIER_STRADDLE",FRONTIER_STRADDLE;
+"FRONTIER_SUBSET_CLOSED",FRONTIER_SUBSET_CLOSED;
+"FRONTIER_SUBSET_COMPACT",FRONTIER_SUBSET_COMPACT;
+"FRONTIER_SUBSET_EQ",FRONTIER_SUBSET_EQ;
+"FRONTIER_SUBSET_RETRACTION",FRONTIER_SUBSET_RETRACTION;
+"FRONTIER_SURJECTIVE_LINEAR_IMAGE",FRONTIER_SURJECTIVE_LINEAR_IMAGE;
+"FRONTIER_TRANSLATION",FRONTIER_TRANSLATION;
+"FRONTIER_UNION",FRONTIER_UNION;
+"FRONTIER_UNIONS_SUBSET_CLOSURE",FRONTIER_UNIONS_SUBSET_CLOSURE;
+"FRONTIER_UNION_SUBSET",FRONTIER_UNION_SUBSET;
+"FRONTIER_UNIV",FRONTIER_UNIV;
+"FST",FST;
+"FSTCART_ADD",FSTCART_ADD;
+"FSTCART_CMUL",FSTCART_CMUL;
+"FSTCART_NEG",FSTCART_NEG;
+"FSTCART_PASTECART",FSTCART_PASTECART;
+"FSTCART_SUB",FSTCART_SUB;
+"FSTCART_VEC",FSTCART_VEC;
+"FSTCART_VSUM",FSTCART_VSUM;
+"FST_DEF",FST_DEF;
+"FTA",FTA;
+"FUBINI_CLOSED_INTERVAL",FUBINI_CLOSED_INTERVAL;
+"FUBINI_SIMPLE",FUBINI_SIMPLE;
+"FUBINI_SIMPLE_ALT",FUBINI_SIMPLE_ALT;
+"FUBINI_SIMPLE_COMPACT",FUBINI_SIMPLE_COMPACT;
+"FUBINI_SIMPLE_COMPACT_STRONG",FUBINI_SIMPLE_COMPACT_STRONG;
+"FUBINI_SIMPLE_CONVEX",FUBINI_SIMPLE_CONVEX;
+"FUBINI_SIMPLE_CONVEX_STRONG",FUBINI_SIMPLE_CONVEX_STRONG;
+"FUBINI_SIMPLE_LEMMA",FUBINI_SIMPLE_LEMMA;
+"FUBINI_SIMPLE_OPEN",FUBINI_SIMPLE_OPEN;
+"FUBINI_SIMPLE_OPEN_STRONG",FUBINI_SIMPLE_OPEN_STRONG;
+"FULL_RANK_INJECTIVE",FULL_RANK_INJECTIVE;
+"FULL_RANK_SURJECTIVE",FULL_RANK_SURJECTIVE;
+"FUNCTION_CONVERGENT_SUBSEQUENCE",FUNCTION_CONVERGENT_SUBSEQUENCE;
+"FUNCTION_FACTORS_LEFT",FUNCTION_FACTORS_LEFT;
+"FUNCTION_FACTORS_LEFT_GEN",FUNCTION_FACTORS_LEFT_GEN;
+"FUNCTION_FACTORS_RIGHT",FUNCTION_FACTORS_RIGHT;
+"FUNCTION_FACTORS_RIGHT_GEN",FUNCTION_FACTORS_RIGHT_GEN;
+"FUNDAMENTAL_THEOREM_OF_CALCULUS",FUNDAMENTAL_THEOREM_OF_CALCULUS;
+"FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR",FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR;
+"FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG",FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG;
+"FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG",FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG;
+"FUN_EQ_THM",FUN_EQ_THM;
+"FUN_IN_IMAGE",FUN_IN_IMAGE;
+"F_DEF",F_DEF;
+"GABS_DEF",GABS_DEF;
+"GAUGE_BALL",GAUGE_BALL;
+"GAUGE_BALL_DEPENDENT",GAUGE_BALL_DEPENDENT;
+"GAUGE_EXISTENCE_LEMMA",GAUGE_EXISTENCE_LEMMA;
+"GAUGE_INTER",GAUGE_INTER;
+"GAUGE_INTERS",GAUGE_INTERS;
+"GAUGE_MODIFY",GAUGE_MODIFY;
+"GAUGE_TRIVIAL",GAUGE_TRIVIAL;
+"GE",GE;
+"GENERAL_CONNECTED_OPEN",GENERAL_CONNECTED_OPEN;
+"GEOM_ASSOC",GEOM_ASSOC;
+"GEOM_LADD",GEOM_LADD;
+"GEOM_LMUL",GEOM_LMUL;
+"GEOM_LNEG",GEOM_LNEG;
+"GEOM_LZERO",GEOM_LZERO;
+"GEOM_MBASIS",GEOM_MBASIS;
+"GEOM_MBASIS_SING",GEOM_MBASIS_SING;
+"GEOM_RADD",GEOM_RADD;
+"GEOM_RMUL",GEOM_RMUL;
+"GEOM_RNEG",GEOM_RNEG;
+"GEOM_RZERO",GEOM_RZERO;
+"GEQ_DEF",GEQ_DEF;
+"GE_C",GE_C;
+"GE_REFL",GE_REFL;
+"GRADE_ADD",GRADE_ADD;
+"GRADE_CMUL",GRADE_CMUL;
+"GRAM_SCHMIDT_STEP",GRAM_SCHMIDT_STEP;
+"GRASSMANN_PLUCKER_2",GRASSMANN_PLUCKER_2;
+"GRASSMANN_PLUCKER_3",GRASSMANN_PLUCKER_3;
+"GRASSMANN_PLUCKER_4",GRASSMANN_PLUCKER_4;
+"GSPEC",GSPEC;
+"GT",GT;
+"HALFSPACE_EQ_EMPTY_GE",HALFSPACE_EQ_EMPTY_GE;
+"HALFSPACE_EQ_EMPTY_GT",HALFSPACE_EQ_EMPTY_GT;
+"HALFSPACE_EQ_EMPTY_LE",HALFSPACE_EQ_EMPTY_LE;
+"HALFSPACE_EQ_EMPTY_LT",HALFSPACE_EQ_EMPTY_LT;
+"HAS_ANTIDERIVATIVE_LIMIT",HAS_ANTIDERIVATIVE_LIMIT;
+"HAS_ANTIDERIVATIVE_SEQUENCE",HAS_ANTIDERIVATIVE_SEQUENCE;
+"HAS_BOUNDED_REAL_VARIATION_AFFINITY2_EQ",HAS_BOUNDED_REAL_VARIATION_AFFINITY2_EQ;
+"HAS_BOUNDED_REAL_VARIATION_AFFINITY_EQ",HAS_BOUNDED_REAL_VARIATION_AFFINITY_EQ;
+"HAS_BOUNDED_REAL_VARIATION_COUNTABLE_DISCONTINUITIES",HAS_BOUNDED_REAL_VARIATION_COUNTABLE_DISCONTINUITIES;
+"HAS_BOUNDED_REAL_VARIATION_DARBOUX",HAS_BOUNDED_REAL_VARIATION_DARBOUX;
+"HAS_BOUNDED_REAL_VARIATION_DARBOUX_STRICT",HAS_BOUNDED_REAL_VARIATION_DARBOUX_STRICT;
+"HAS_BOUNDED_REAL_VARIATION_DARBOUX_STRONG",HAS_BOUNDED_REAL_VARIATION_DARBOUX_STRONG;
+"HAS_BOUNDED_REAL_VARIATION_LEFT_LIMIT",HAS_BOUNDED_REAL_VARIATION_LEFT_LIMIT;
+"HAS_BOUNDED_REAL_VARIATION_ON_ABS",HAS_BOUNDED_REAL_VARIATION_ON_ABS;
+"HAS_BOUNDED_REAL_VARIATION_ON_ADD",HAS_BOUNDED_REAL_VARIATION_ON_ADD;
+"HAS_BOUNDED_REAL_VARIATION_ON_COMBINE",HAS_BOUNDED_REAL_VARIATION_ON_COMBINE;
+"HAS_BOUNDED_REAL_VARIATION_ON_EMPTY",HAS_BOUNDED_REAL_VARIATION_ON_EMPTY;
+"HAS_BOUNDED_REAL_VARIATION_ON_EQ",HAS_BOUNDED_REAL_VARIATION_ON_EQ;
+"HAS_BOUNDED_REAL_VARIATION_ON_IMP_BOUNDED_ON_INTERVAL",HAS_BOUNDED_REAL_VARIATION_ON_IMP_BOUNDED_ON_INTERVAL;
+"HAS_BOUNDED_REAL_VARIATION_ON_LMUL",HAS_BOUNDED_REAL_VARIATION_ON_LMUL;
+"HAS_BOUNDED_REAL_VARIATION_ON_MAX",HAS_BOUNDED_REAL_VARIATION_ON_MAX;
+"HAS_BOUNDED_REAL_VARIATION_ON_MIN",HAS_BOUNDED_REAL_VARIATION_ON_MIN;
+"HAS_BOUNDED_REAL_VARIATION_ON_MUL",HAS_BOUNDED_REAL_VARIATION_ON_MUL;
+"HAS_BOUNDED_REAL_VARIATION_ON_NEG",HAS_BOUNDED_REAL_VARIATION_ON_NEG;
+"HAS_BOUNDED_REAL_VARIATION_ON_NULL",HAS_BOUNDED_REAL_VARIATION_ON_NULL;
+"HAS_BOUNDED_REAL_VARIATION_ON_RMUL",HAS_BOUNDED_REAL_VARIATION_ON_RMUL;
+"HAS_BOUNDED_REAL_VARIATION_ON_SUB",HAS_BOUNDED_REAL_VARIATION_ON_SUB;
+"HAS_BOUNDED_REAL_VARIATION_ON_SUBSET",HAS_BOUNDED_REAL_VARIATION_ON_SUBSET;
+"HAS_BOUNDED_REAL_VARIATION_REFLECT2_EQ",HAS_BOUNDED_REAL_VARIATION_REFLECT2_EQ;
+"HAS_BOUNDED_REAL_VARIATION_REFLECT_EQ",HAS_BOUNDED_REAL_VARIATION_REFLECT_EQ;
+"HAS_BOUNDED_REAL_VARIATION_REFLECT_EQ_INTERVAL",HAS_BOUNDED_REAL_VARIATION_REFLECT_EQ_INTERVAL;
+"HAS_BOUNDED_REAL_VARIATION_RIGHT_LIMIT",HAS_BOUNDED_REAL_VARIATION_RIGHT_LIMIT;
+"HAS_BOUNDED_REAL_VARIATION_TRANSLATION",HAS_BOUNDED_REAL_VARIATION_TRANSLATION;
+"HAS_BOUNDED_REAL_VARIATION_TRANSLATION2_EQ",HAS_BOUNDED_REAL_VARIATION_TRANSLATION2_EQ;
+"HAS_BOUNDED_REAL_VARIATION_TRANSLATION_EQ",HAS_BOUNDED_REAL_VARIATION_TRANSLATION_EQ;
+"HAS_BOUNDED_REAL_VARIATION_TRANSLATION_EQ_INTERVAL",HAS_BOUNDED_REAL_VARIATION_TRANSLATION_EQ_INTERVAL;
+"HAS_BOUNDED_SETVARIATION_ON",HAS_BOUNDED_SETVARIATION_ON;
+"HAS_BOUNDED_SETVARIATION_ON_0",HAS_BOUNDED_SETVARIATION_ON_0;
+"HAS_BOUNDED_SETVARIATION_ON_ADD",HAS_BOUNDED_SETVARIATION_ON_ADD;
+"HAS_BOUNDED_SETVARIATION_ON_CMUL",HAS_BOUNDED_SETVARIATION_ON_CMUL;
+"HAS_BOUNDED_SETVARIATION_ON_COMPONENTWISE",HAS_BOUNDED_SETVARIATION_ON_COMPONENTWISE;
+"HAS_BOUNDED_SETVARIATION_ON_COMPOSE_LINEAR",HAS_BOUNDED_SETVARIATION_ON_COMPOSE_LINEAR;
+"HAS_BOUNDED_SETVARIATION_ON_DIVISION",HAS_BOUNDED_SETVARIATION_ON_DIVISION;
+"HAS_BOUNDED_SETVARIATION_ON_ELEMENTARY",HAS_BOUNDED_SETVARIATION_ON_ELEMENTARY;
+"HAS_BOUNDED_SETVARIATION_ON_EQ",HAS_BOUNDED_SETVARIATION_ON_EQ;
+"HAS_BOUNDED_SETVARIATION_ON_IMP_BOUNDED_ON_SUBINTERVALS",HAS_BOUNDED_SETVARIATION_ON_IMP_BOUNDED_ON_SUBINTERVALS;
+"HAS_BOUNDED_SETVARIATION_ON_INTERVAL",HAS_BOUNDED_SETVARIATION_ON_INTERVAL;
+"HAS_BOUNDED_SETVARIATION_ON_NEG",HAS_BOUNDED_SETVARIATION_ON_NEG;
+"HAS_BOUNDED_SETVARIATION_ON_NORM",HAS_BOUNDED_SETVARIATION_ON_NORM;
+"HAS_BOUNDED_SETVARIATION_ON_NULL",HAS_BOUNDED_SETVARIATION_ON_NULL;
+"HAS_BOUNDED_SETVARIATION_ON_SUB",HAS_BOUNDED_SETVARIATION_ON_SUB;
+"HAS_BOUNDED_SETVARIATION_ON_SUBSET",HAS_BOUNDED_SETVARIATION_ON_SUBSET;
+"HAS_BOUNDED_SETVARIATION_ON_UNIV",HAS_BOUNDED_SETVARIATION_ON_UNIV;
+"HAS_BOUNDED_SETVARIATION_REFLECT2_EQ",HAS_BOUNDED_SETVARIATION_REFLECT2_EQ;
+"HAS_BOUNDED_SETVARIATION_TRANSLATION",HAS_BOUNDED_SETVARIATION_TRANSLATION;
+"HAS_BOUNDED_SETVARIATION_TRANSLATION2_EQ",HAS_BOUNDED_SETVARIATION_TRANSLATION2_EQ;
+"HAS_BOUNDED_SETVARIATION_WORKS",HAS_BOUNDED_SETVARIATION_WORKS;
+"HAS_BOUNDED_SETVARIATION_WORKS_ON_ELEMENTARY",HAS_BOUNDED_SETVARIATION_WORKS_ON_ELEMENTARY;
+"HAS_BOUNDED_SETVARIATION_WORKS_ON_INTERVAL",HAS_BOUNDED_SETVARIATION_WORKS_ON_INTERVAL;
+"HAS_BOUNDED_VARIATION_ABSOLUTELY_INTEGRABLE_DERIVATIVE",HAS_BOUNDED_VARIATION_ABSOLUTELY_INTEGRABLE_DERIVATIVE;
+"HAS_BOUNDED_VARIATION_AFFINITY2_EQ",HAS_BOUNDED_VARIATION_AFFINITY2_EQ;
+"HAS_BOUNDED_VARIATION_AFFINITY_EQ",HAS_BOUNDED_VARIATION_AFFINITY_EQ;
+"HAS_BOUNDED_VARIATION_COMPOSE_DECREASING",HAS_BOUNDED_VARIATION_COMPOSE_DECREASING;
+"HAS_BOUNDED_VARIATION_COMPOSE_INCREASING",HAS_BOUNDED_VARIATION_COMPOSE_INCREASING;
+"HAS_BOUNDED_VARIATION_COUNTABLE_DISCONTINUITIES",HAS_BOUNDED_VARIATION_COUNTABLE_DISCONTINUITIES;
+"HAS_BOUNDED_VARIATION_DARBOUX",HAS_BOUNDED_VARIATION_DARBOUX;
+"HAS_BOUNDED_VARIATION_DARBOUX_STRICT",HAS_BOUNDED_VARIATION_DARBOUX_STRICT;
+"HAS_BOUNDED_VARIATION_DARBOUX_STRONG",HAS_BOUNDED_VARIATION_DARBOUX_STRONG;
+"HAS_BOUNDED_VARIATION_INTEGRABLE_NORM_DERIVATIVE",HAS_BOUNDED_VARIATION_INTEGRABLE_NORM_DERIVATIVE;
+"HAS_BOUNDED_VARIATION_ON_ADD",HAS_BOUNDED_VARIATION_ON_ADD;
+"HAS_BOUNDED_VARIATION_ON_CMUL",HAS_BOUNDED_VARIATION_ON_CMUL;
+"HAS_BOUNDED_VARIATION_ON_COMBINE",HAS_BOUNDED_VARIATION_ON_COMBINE;
+"HAS_BOUNDED_VARIATION_ON_COMPONENTWISE",HAS_BOUNDED_VARIATION_ON_COMPONENTWISE;
+"HAS_BOUNDED_VARIATION_ON_COMPOSE_LINEAR",HAS_BOUNDED_VARIATION_ON_COMPOSE_LINEAR;
+"HAS_BOUNDED_VARIATION_ON_CONST",HAS_BOUNDED_VARIATION_ON_CONST;
+"HAS_BOUNDED_VARIATION_ON_DIVISION",HAS_BOUNDED_VARIATION_ON_DIVISION;
+"HAS_BOUNDED_VARIATION_ON_EMPTY",HAS_BOUNDED_VARIATION_ON_EMPTY;
+"HAS_BOUNDED_VARIATION_ON_EQ",HAS_BOUNDED_VARIATION_ON_EQ;
+"HAS_BOUNDED_VARIATION_ON_ID",HAS_BOUNDED_VARIATION_ON_ID;
+"HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_INTERVAL",HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_INTERVAL;
+"HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_SUBINTERVALS",HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_SUBINTERVALS;
+"HAS_BOUNDED_VARIATION_ON_LINEAR_IMAGE",HAS_BOUNDED_VARIATION_ON_LINEAR_IMAGE;
+"HAS_BOUNDED_VARIATION_ON_MAX",HAS_BOUNDED_VARIATION_ON_MAX;
+"HAS_BOUNDED_VARIATION_ON_MIN",HAS_BOUNDED_VARIATION_ON_MIN;
+"HAS_BOUNDED_VARIATION_ON_MUL",HAS_BOUNDED_VARIATION_ON_MUL;
+"HAS_BOUNDED_VARIATION_ON_NEG",HAS_BOUNDED_VARIATION_ON_NEG;
+"HAS_BOUNDED_VARIATION_ON_NORM",HAS_BOUNDED_VARIATION_ON_NORM;
+"HAS_BOUNDED_VARIATION_ON_NULL",HAS_BOUNDED_VARIATION_ON_NULL;
+"HAS_BOUNDED_VARIATION_ON_REFLECT",HAS_BOUNDED_VARIATION_ON_REFLECT;
+"HAS_BOUNDED_VARIATION_ON_REFLECT_INTERVAL",HAS_BOUNDED_VARIATION_ON_REFLECT_INTERVAL;
+"HAS_BOUNDED_VARIATION_ON_SUB",HAS_BOUNDED_VARIATION_ON_SUB;
+"HAS_BOUNDED_VARIATION_ON_SUBSET",HAS_BOUNDED_VARIATION_ON_SUBSET;
+"HAS_BOUNDED_VARIATION_REFLECT2_EQ",HAS_BOUNDED_VARIATION_REFLECT2_EQ;
+"HAS_BOUNDED_VARIATION_REFLECT_EQ",HAS_BOUNDED_VARIATION_REFLECT_EQ;
+"HAS_BOUNDED_VARIATION_REFLECT_EQ_INTERVAL",HAS_BOUNDED_VARIATION_REFLECT_EQ_INTERVAL;
+"HAS_BOUNDED_VARIATION_TRANSLATION",HAS_BOUNDED_VARIATION_TRANSLATION;
+"HAS_BOUNDED_VARIATION_TRANSLATION2_EQ",HAS_BOUNDED_VARIATION_TRANSLATION2_EQ;
+"HAS_BOUNDED_VARIATION_TRANSLATION_EQ",HAS_BOUNDED_VARIATION_TRANSLATION_EQ;
+"HAS_BOUNDED_VARIATION_TRANSLATION_EQ_INTERVAL",HAS_BOUNDED_VARIATION_TRANSLATION_EQ_INTERVAL;
+"HAS_BOUNDED_VECTOR_VARIATION_LEFT_LIMIT",HAS_BOUNDED_VECTOR_VARIATION_LEFT_LIMIT;
+"HAS_BOUNDED_VECTOR_VARIATION_RIGHT_LIMIT",HAS_BOUNDED_VECTOR_VARIATION_RIGHT_LIMIT;
+"HAS_CHAIN_INTEGRAL_CHAIN_INTEGRAL",HAS_CHAIN_INTEGRAL_CHAIN_INTEGRAL;
+"HAS_COMPLEX_DERIVATIVE_ADD",HAS_COMPLEX_DERIVATIVE_ADD;
+"HAS_COMPLEX_DERIVATIVE_AT",HAS_COMPLEX_DERIVATIVE_AT;
+"HAS_COMPLEX_DERIVATIVE_AT_WITHIN",HAS_COMPLEX_DERIVATIVE_AT_WITHIN;
+"HAS_COMPLEX_DERIVATIVE_CACS",HAS_COMPLEX_DERIVATIVE_CACS;
+"HAS_COMPLEX_DERIVATIVE_CARATHEODORY_AT",HAS_COMPLEX_DERIVATIVE_CARATHEODORY_AT;
+"HAS_COMPLEX_DERIVATIVE_CARATHEODORY_WITHIN",HAS_COMPLEX_DERIVATIVE_CARATHEODORY_WITHIN;
+"HAS_COMPLEX_DERIVATIVE_CASN",HAS_COMPLEX_DERIVATIVE_CASN;
+"HAS_COMPLEX_DERIVATIVE_CATN",HAS_COMPLEX_DERIVATIVE_CATN;
+"HAS_COMPLEX_DERIVATIVE_CCOS",HAS_COMPLEX_DERIVATIVE_CCOS;
+"HAS_COMPLEX_DERIVATIVE_CDIV_AT",HAS_COMPLEX_DERIVATIVE_CDIV_AT;
+"HAS_COMPLEX_DERIVATIVE_CDIV_WITHIN",HAS_COMPLEX_DERIVATIVE_CDIV_WITHIN;
+"HAS_COMPLEX_DERIVATIVE_CEXP",HAS_COMPLEX_DERIVATIVE_CEXP;
+"HAS_COMPLEX_DERIVATIVE_CHAIN",HAS_COMPLEX_DERIVATIVE_CHAIN;
+"HAS_COMPLEX_DERIVATIVE_CHAIN_UNIV",HAS_COMPLEX_DERIVATIVE_CHAIN_UNIV;
+"HAS_COMPLEX_DERIVATIVE_CLOG",HAS_COMPLEX_DERIVATIVE_CLOG;
+"HAS_COMPLEX_DERIVATIVE_CONST",HAS_COMPLEX_DERIVATIVE_CONST;
+"HAS_COMPLEX_DERIVATIVE_CPOW",HAS_COMPLEX_DERIVATIVE_CPOW;
+"HAS_COMPLEX_DERIVATIVE_CPOW_RIGHT",HAS_COMPLEX_DERIVATIVE_CPOW_RIGHT;
+"HAS_COMPLEX_DERIVATIVE_CSIN",HAS_COMPLEX_DERIVATIVE_CSIN;
+"HAS_COMPLEX_DERIVATIVE_CSQRT",HAS_COMPLEX_DERIVATIVE_CSQRT;
+"HAS_COMPLEX_DERIVATIVE_CTAN",HAS_COMPLEX_DERIVATIVE_CTAN;
+"HAS_COMPLEX_DERIVATIVE_DERIVATIVE",HAS_COMPLEX_DERIVATIVE_DERIVATIVE;
+"HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE",HAS_COMPLEX_DERIVATIVE_DIFFERENTIABLE;
+"HAS_COMPLEX_DERIVATIVE_DIV_AT",HAS_COMPLEX_DERIVATIVE_DIV_AT;
+"HAS_COMPLEX_DERIVATIVE_DIV_WITHIN",HAS_COMPLEX_DERIVATIVE_DIV_WITHIN;
+"HAS_COMPLEX_DERIVATIVE_HIGHER_COMPLEX_DERIVATIVE",HAS_COMPLEX_DERIVATIVE_HIGHER_COMPLEX_DERIVATIVE;
+"HAS_COMPLEX_DERIVATIVE_ID",HAS_COMPLEX_DERIVATIVE_ID;
+"HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT",HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT;
+"HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_WITHIN",HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_WITHIN;
+"HAS_COMPLEX_DERIVATIVE_INVERSE_BASIC",HAS_COMPLEX_DERIVATIVE_INVERSE_BASIC;
+"HAS_COMPLEX_DERIVATIVE_INVERSE_STRONG",HAS_COMPLEX_DERIVATIVE_INVERSE_STRONG;
+"HAS_COMPLEX_DERIVATIVE_INVERSE_STRONG_X",HAS_COMPLEX_DERIVATIVE_INVERSE_STRONG_X;
+"HAS_COMPLEX_DERIVATIVE_INV_AT",HAS_COMPLEX_DERIVATIVE_INV_AT;
+"HAS_COMPLEX_DERIVATIVE_INV_BASIC",HAS_COMPLEX_DERIVATIVE_INV_BASIC;
+"HAS_COMPLEX_DERIVATIVE_INV_WITHIN",HAS_COMPLEX_DERIVATIVE_INV_WITHIN;
+"HAS_COMPLEX_DERIVATIVE_ITER_1",HAS_COMPLEX_DERIVATIVE_ITER_1;
+"HAS_COMPLEX_DERIVATIVE_LINEAR",HAS_COMPLEX_DERIVATIVE_LINEAR;
+"HAS_COMPLEX_DERIVATIVE_LMUL_AT",HAS_COMPLEX_DERIVATIVE_LMUL_AT;
+"HAS_COMPLEX_DERIVATIVE_LMUL_WITHIN",HAS_COMPLEX_DERIVATIVE_LMUL_WITHIN;
+"HAS_COMPLEX_DERIVATIVE_LOCALLY_INJECTIVE",HAS_COMPLEX_DERIVATIVE_LOCALLY_INJECTIVE;
+"HAS_COMPLEX_DERIVATIVE_LOCALLY_INVERTIBLE",HAS_COMPLEX_DERIVATIVE_LOCALLY_INVERTIBLE;
+"HAS_COMPLEX_DERIVATIVE_MUL_AT",HAS_COMPLEX_DERIVATIVE_MUL_AT;
+"HAS_COMPLEX_DERIVATIVE_MUL_WITHIN",HAS_COMPLEX_DERIVATIVE_MUL_WITHIN;
+"HAS_COMPLEX_DERIVATIVE_NEG",HAS_COMPLEX_DERIVATIVE_NEG;
+"HAS_COMPLEX_DERIVATIVE_POW_AT",HAS_COMPLEX_DERIVATIVE_POW_AT;
+"HAS_COMPLEX_DERIVATIVE_POW_WITHIN",HAS_COMPLEX_DERIVATIVE_POW_WITHIN;
+"HAS_COMPLEX_DERIVATIVE_RMUL_AT",HAS_COMPLEX_DERIVATIVE_RMUL_AT;
+"HAS_COMPLEX_DERIVATIVE_RMUL_WITHIN",HAS_COMPLEX_DERIVATIVE_RMUL_WITHIN;
+"HAS_COMPLEX_DERIVATIVE_SEQUENCE",HAS_COMPLEX_DERIVATIVE_SEQUENCE;
+"HAS_COMPLEX_DERIVATIVE_SERIES",HAS_COMPLEX_DERIVATIVE_SERIES;
+"HAS_COMPLEX_DERIVATIVE_SUB",HAS_COMPLEX_DERIVATIVE_SUB;
+"HAS_COMPLEX_DERIVATIVE_TRANSFORM_AT",HAS_COMPLEX_DERIVATIVE_TRANSFORM_AT;
+"HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN",HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN;
+"HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN",HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN;
+"HAS_COMPLEX_DERIVATIVE_UNIFORM_LIMIT",HAS_COMPLEX_DERIVATIVE_UNIFORM_LIMIT;
+"HAS_COMPLEX_DERIVATIVE_UNIFORM_SEQUENCE",HAS_COMPLEX_DERIVATIVE_UNIFORM_SEQUENCE;
+"HAS_COMPLEX_DERIVATIVE_VSUM",HAS_COMPLEX_DERIVATIVE_VSUM;
+"HAS_COMPLEX_DERIVATIVE_WITHIN",HAS_COMPLEX_DERIVATIVE_WITHIN;
+"HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN",HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN;
+"HAS_COMPLEX_DERIVATIVE_WITHIN_SUBSET",HAS_COMPLEX_DERIVATIVE_WITHIN_SUBSET;
+"HAS_COMPLEX_DERIVATIVE_ZERO_CONNECTED_CONSTANT",HAS_COMPLEX_DERIVATIVE_ZERO_CONNECTED_CONSTANT;
+"HAS_COMPLEX_DERIVATIVE_ZERO_CONNECTED_UNIQUE",HAS_COMPLEX_DERIVATIVE_ZERO_CONNECTED_UNIQUE;
+"HAS_COMPLEX_DERIVATIVE_ZERO_CONSTANT",HAS_COMPLEX_DERIVATIVE_ZERO_CONSTANT;
+"HAS_COMPLEX_DERIVATIVE_ZERO_UNIQUE",HAS_COMPLEX_DERIVATIVE_ZERO_UNIQUE;
+"HAS_COMPLEX_REAL_DERIVATIVE_AT",HAS_COMPLEX_REAL_DERIVATIVE_AT;
+"HAS_COMPLEX_REAL_DERIVATIVE_AT_GEN",HAS_COMPLEX_REAL_DERIVATIVE_AT_GEN;
+"HAS_COMPLEX_REAL_DERIVATIVE_WITHIN",HAS_COMPLEX_REAL_DERIVATIVE_WITHIN;
+"HAS_COMPLEX_REAL_DERIVATIVE_WITHIN_GEN",HAS_COMPLEX_REAL_DERIVATIVE_WITHIN_GEN;
+"HAS_DERIVATIVE_ADD",HAS_DERIVATIVE_ADD;
+"HAS_DERIVATIVE_AT",HAS_DERIVATIVE_AT;
+"HAS_DERIVATIVE_AT_ALT",HAS_DERIVATIVE_AT_ALT;
+"HAS_DERIVATIVE_AT_WITHIN",HAS_DERIVATIVE_AT_WITHIN;
+"HAS_DERIVATIVE_BILINEAR_AT",HAS_DERIVATIVE_BILINEAR_AT;
+"HAS_DERIVATIVE_BILINEAR_WITHIN",HAS_DERIVATIVE_BILINEAR_WITHIN;
+"HAS_DERIVATIVE_CMUL",HAS_DERIVATIVE_CMUL;
+"HAS_DERIVATIVE_CMUL_EQ",HAS_DERIVATIVE_CMUL_EQ;
+"HAS_DERIVATIVE_COMPLEX_CMUL",HAS_DERIVATIVE_COMPLEX_CMUL;
+"HAS_DERIVATIVE_COMPONENTWISE_AT",HAS_DERIVATIVE_COMPONENTWISE_AT;
+"HAS_DERIVATIVE_COMPONENTWISE_WITHIN",HAS_DERIVATIVE_COMPONENTWISE_WITHIN;
+"HAS_DERIVATIVE_CONST",HAS_DERIVATIVE_CONST;
+"HAS_DERIVATIVE_ID",HAS_DERIVATIVE_ID;
+"HAS_DERIVATIVE_IMP_DIFFERENTIABLE",HAS_DERIVATIVE_IMP_DIFFERENTIABLE;
+"HAS_DERIVATIVE_INVERSE",HAS_DERIVATIVE_INVERSE;
+"HAS_DERIVATIVE_INVERSE_BASIC",HAS_DERIVATIVE_INVERSE_BASIC;
+"HAS_DERIVATIVE_INVERSE_BASIC_X",HAS_DERIVATIVE_INVERSE_BASIC_X;
+"HAS_DERIVATIVE_INVERSE_DIEUDONNE",HAS_DERIVATIVE_INVERSE_DIEUDONNE;
+"HAS_DERIVATIVE_INVERSE_ON",HAS_DERIVATIVE_INVERSE_ON;
+"HAS_DERIVATIVE_INVERSE_STRONG",HAS_DERIVATIVE_INVERSE_STRONG;
+"HAS_DERIVATIVE_INVERSE_STRONG_X",HAS_DERIVATIVE_INVERSE_STRONG_X;
+"HAS_DERIVATIVE_LIFT_COMPONENT",HAS_DERIVATIVE_LIFT_COMPONENT;
+"HAS_DERIVATIVE_LIFT_DOT",HAS_DERIVATIVE_LIFT_DOT;
+"HAS_DERIVATIVE_LINEAR",HAS_DERIVATIVE_LINEAR;
+"HAS_DERIVATIVE_LOCALLY_INJECTIVE",HAS_DERIVATIVE_LOCALLY_INJECTIVE;
+"HAS_DERIVATIVE_MUL_AT",HAS_DERIVATIVE_MUL_AT;
+"HAS_DERIVATIVE_MUL_WITHIN",HAS_DERIVATIVE_MUL_WITHIN;
+"HAS_DERIVATIVE_NEG",HAS_DERIVATIVE_NEG;
+"HAS_DERIVATIVE_NEG_EQ",HAS_DERIVATIVE_NEG_EQ;
+"HAS_DERIVATIVE_SEQUENCE",HAS_DERIVATIVE_SEQUENCE;
+"HAS_DERIVATIVE_SEQUENCE_LIPSCHITZ",HAS_DERIVATIVE_SEQUENCE_LIPSCHITZ;
+"HAS_DERIVATIVE_SERIES",HAS_DERIVATIVE_SERIES;
+"HAS_DERIVATIVE_SQNORM_AT",HAS_DERIVATIVE_SQNORM_AT;
+"HAS_DERIVATIVE_SUB",HAS_DERIVATIVE_SUB;
+"HAS_DERIVATIVE_TRANSFORM_AT",HAS_DERIVATIVE_TRANSFORM_AT;
+"HAS_DERIVATIVE_TRANSFORM_WITHIN",HAS_DERIVATIVE_TRANSFORM_WITHIN;
+"HAS_DERIVATIVE_TRANSFORM_WITHIN_OPEN",HAS_DERIVATIVE_TRANSFORM_WITHIN_OPEN;
+"HAS_DERIVATIVE_VMUL_COMPONENT",HAS_DERIVATIVE_VMUL_COMPONENT;
+"HAS_DERIVATIVE_VMUL_DROP",HAS_DERIVATIVE_VMUL_DROP;
+"HAS_DERIVATIVE_VSUM",HAS_DERIVATIVE_VSUM;
+"HAS_DERIVATIVE_VSUM_NUMSEG",HAS_DERIVATIVE_VSUM_NUMSEG;
+"HAS_DERIVATIVE_WITHIN",HAS_DERIVATIVE_WITHIN;
+"HAS_DERIVATIVE_WITHIN_ALT",HAS_DERIVATIVE_WITHIN_ALT;
+"HAS_DERIVATIVE_WITHIN_OPEN",HAS_DERIVATIVE_WITHIN_OPEN;
+"HAS_DERIVATIVE_WITHIN_SUBSET",HAS_DERIVATIVE_WITHIN_SUBSET;
+"HAS_DERIVATIVE_ZERO_CONNECTED_CONSTANT",HAS_DERIVATIVE_ZERO_CONNECTED_CONSTANT;
+"HAS_DERIVATIVE_ZERO_CONNECTED_UNIQUE",HAS_DERIVATIVE_ZERO_CONNECTED_UNIQUE;
+"HAS_DERIVATIVE_ZERO_CONSTANT",HAS_DERIVATIVE_ZERO_CONSTANT;
+"HAS_DERIVATIVE_ZERO_UNIQUE",HAS_DERIVATIVE_ZERO_UNIQUE;
+"HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_CONNECTED",HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_CONNECTED;
+"HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_CONVEX",HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_CONVEX;
+"HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_INTERVAL",HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_INTERVAL;
+"HAS_FRECHET_DERIVATIVE_UNIQUE_AT",HAS_FRECHET_DERIVATIVE_UNIQUE_AT;
+"HAS_INTEGRAL",HAS_INTEGRAL;
+"HAS_INTEGRAL_0",HAS_INTEGRAL_0;
+"HAS_INTEGRAL_0_EQ",HAS_INTEGRAL_0_EQ;
+"HAS_INTEGRAL_ADD",HAS_INTEGRAL_ADD;
+"HAS_INTEGRAL_AFFINITY",HAS_INTEGRAL_AFFINITY;
+"HAS_INTEGRAL_ALT",HAS_INTEGRAL_ALT;
+"HAS_INTEGRAL_BOUND",HAS_INTEGRAL_BOUND;
+"HAS_INTEGRAL_CLOSURE",HAS_INTEGRAL_CLOSURE;
+"HAS_INTEGRAL_CMUL",HAS_INTEGRAL_CMUL;
+"HAS_INTEGRAL_COMBINE",HAS_INTEGRAL_COMBINE;
+"HAS_INTEGRAL_COMBINE_DIVISION",HAS_INTEGRAL_COMBINE_DIVISION;
+"HAS_INTEGRAL_COMBINE_DIVISION_TOPDOWN",HAS_INTEGRAL_COMBINE_DIVISION_TOPDOWN;
+"HAS_INTEGRAL_COMBINE_TAGGED_DIVISION",HAS_INTEGRAL_COMBINE_TAGGED_DIVISION;
+"HAS_INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN",HAS_INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN;
+"HAS_INTEGRAL_COMPLEX_CMUL",HAS_INTEGRAL_COMPLEX_CMUL;
+"HAS_INTEGRAL_COMPONENTWISE",HAS_INTEGRAL_COMPONENTWISE;
+"HAS_INTEGRAL_COMPONENT_LBOUND",HAS_INTEGRAL_COMPONENT_LBOUND;
+"HAS_INTEGRAL_COMPONENT_LE",HAS_INTEGRAL_COMPONENT_LE;
+"HAS_INTEGRAL_COMPONENT_NEG",HAS_INTEGRAL_COMPONENT_NEG;
+"HAS_INTEGRAL_COMPONENT_POS",HAS_INTEGRAL_COMPONENT_POS;
+"HAS_INTEGRAL_COMPONENT_UBOUND",HAS_INTEGRAL_COMPONENT_UBOUND;
+"HAS_INTEGRAL_CONST",HAS_INTEGRAL_CONST;
+"HAS_INTEGRAL_DIFF",HAS_INTEGRAL_DIFF;
+"HAS_INTEGRAL_DROP_LE",HAS_INTEGRAL_DROP_LE;
+"HAS_INTEGRAL_DROP_NEG",HAS_INTEGRAL_DROP_NEG;
+"HAS_INTEGRAL_DROP_POS",HAS_INTEGRAL_DROP_POS;
+"HAS_INTEGRAL_EMPTY",HAS_INTEGRAL_EMPTY;
+"HAS_INTEGRAL_EMPTY_EQ",HAS_INTEGRAL_EMPTY_EQ;
+"HAS_INTEGRAL_EQ",HAS_INTEGRAL_EQ;
+"HAS_INTEGRAL_EQ_EQ",HAS_INTEGRAL_EQ_EQ;
+"HAS_INTEGRAL_FACTOR_CONTENT",HAS_INTEGRAL_FACTOR_CONTENT;
+"HAS_INTEGRAL_INTEGRABLE",HAS_INTEGRAL_INTEGRABLE;
+"HAS_INTEGRAL_INTEGRABLE_INTEGRAL",HAS_INTEGRAL_INTEGRABLE_INTEGRAL;
+"HAS_INTEGRAL_INTEGRAL",HAS_INTEGRAL_INTEGRAL;
+"HAS_INTEGRAL_INTERIOR",HAS_INTEGRAL_INTERIOR;
+"HAS_INTEGRAL_IS_0",HAS_INTEGRAL_IS_0;
+"HAS_INTEGRAL_LINEAR",HAS_INTEGRAL_LINEAR;
+"HAS_INTEGRAL_LOCALIZED_VECTOR_DERIVATIVE",HAS_INTEGRAL_LOCALIZED_VECTOR_DERIVATIVE;
+"HAS_INTEGRAL_NEG",HAS_INTEGRAL_NEG;
+"HAS_INTEGRAL_NEGLIGIBLE",HAS_INTEGRAL_NEGLIGIBLE;
+"HAS_INTEGRAL_NEGLIGIBLE_EQ",HAS_INTEGRAL_NEGLIGIBLE_EQ;
+"HAS_INTEGRAL_NORM_BOUND_INTEGRAL_COMPONENT",HAS_INTEGRAL_NORM_BOUND_INTEGRAL_COMPONENT;
+"HAS_INTEGRAL_NULL",HAS_INTEGRAL_NULL;
+"HAS_INTEGRAL_NULL_EQ",HAS_INTEGRAL_NULL_EQ;
+"HAS_INTEGRAL_ON_SUPERSET",HAS_INTEGRAL_ON_SUPERSET;
+"HAS_INTEGRAL_OPEN_INTERVAL",HAS_INTEGRAL_OPEN_INTERVAL;
+"HAS_INTEGRAL_PATH_INTEGRAL_SUBPATH",HAS_INTEGRAL_PATH_INTEGRAL_SUBPATH;
+"HAS_INTEGRAL_REFL",HAS_INTEGRAL_REFL;
+"HAS_INTEGRAL_REFLECT",HAS_INTEGRAL_REFLECT;
+"HAS_INTEGRAL_REFLECT_LEMMA",HAS_INTEGRAL_REFLECT_LEMMA;
+"HAS_INTEGRAL_RESTRICT",HAS_INTEGRAL_RESTRICT;
+"HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVAL",HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVAL;
+"HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVALS_EQ",HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVALS_EQ;
+"HAS_INTEGRAL_RESTRICT_INTER",HAS_INTEGRAL_RESTRICT_INTER;
+"HAS_INTEGRAL_RESTRICT_OPEN_SUBINTERVAL",HAS_INTEGRAL_RESTRICT_OPEN_SUBINTERVAL;
+"HAS_INTEGRAL_RESTRICT_UNIV",HAS_INTEGRAL_RESTRICT_UNIV;
+"HAS_INTEGRAL_SEPARATE_SIDES",HAS_INTEGRAL_SEPARATE_SIDES;
+"HAS_INTEGRAL_SPIKE",HAS_INTEGRAL_SPIKE;
+"HAS_INTEGRAL_SPIKE_EQ",HAS_INTEGRAL_SPIKE_EQ;
+"HAS_INTEGRAL_SPIKE_FINITE",HAS_INTEGRAL_SPIKE_FINITE;
+"HAS_INTEGRAL_SPIKE_FINITE_EQ",HAS_INTEGRAL_SPIKE_FINITE_EQ;
+"HAS_INTEGRAL_SPIKE_INTERIOR",HAS_INTEGRAL_SPIKE_INTERIOR;
+"HAS_INTEGRAL_SPIKE_INTERIOR_EQ",HAS_INTEGRAL_SPIKE_INTERIOR_EQ;
+"HAS_INTEGRAL_SPIKE_SET",HAS_INTEGRAL_SPIKE_SET;
+"HAS_INTEGRAL_SPIKE_SET_EQ",HAS_INTEGRAL_SPIKE_SET_EQ;
+"HAS_INTEGRAL_SPLIT",HAS_INTEGRAL_SPLIT;
+"HAS_INTEGRAL_STRADDLE_NULL",HAS_INTEGRAL_STRADDLE_NULL;
+"HAS_INTEGRAL_STRETCH",HAS_INTEGRAL_STRETCH;
+"HAS_INTEGRAL_SUB",HAS_INTEGRAL_SUB;
+"HAS_INTEGRAL_SUBSET_COMPONENT_LE",HAS_INTEGRAL_SUBSET_COMPONENT_LE;
+"HAS_INTEGRAL_SUBSET_DROP_LE",HAS_INTEGRAL_SUBSET_DROP_LE;
+"HAS_INTEGRAL_TWIDDLE",HAS_INTEGRAL_TWIDDLE;
+"HAS_INTEGRAL_UNION",HAS_INTEGRAL_UNION;
+"HAS_INTEGRAL_UNIONS",HAS_INTEGRAL_UNIONS;
+"HAS_INTEGRAL_UNIQUE",HAS_INTEGRAL_UNIQUE;
+"HAS_INTEGRAL_VSUM",HAS_INTEGRAL_VSUM;
+"HAS_MEASURE",HAS_MEASURE;
+"HAS_MEASURE_0",HAS_MEASURE_0;
+"HAS_MEASURE_AFFINITY",HAS_MEASURE_AFFINITY;
+"HAS_MEASURE_ALMOST",HAS_MEASURE_ALMOST;
+"HAS_MEASURE_ALMOST_EQ",HAS_MEASURE_ALMOST_EQ;
+"HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS",HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS;
+"HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS_BOUNDED",HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS_BOUNDED;
+"HAS_MEASURE_DIFF_NEGLIGIBLE",HAS_MEASURE_DIFF_NEGLIGIBLE;
+"HAS_MEASURE_DIFF_NEGLIGIBLE_EQ",HAS_MEASURE_DIFF_NEGLIGIBLE_EQ;
+"HAS_MEASURE_DIFF_SUBSET",HAS_MEASURE_DIFF_SUBSET;
+"HAS_MEASURE_DISJOINT_UNION",HAS_MEASURE_DISJOINT_UNION;
+"HAS_MEASURE_DISJOINT_UNIONS",HAS_MEASURE_DISJOINT_UNIONS;
+"HAS_MEASURE_DISJOINT_UNIONS_IMAGE",HAS_MEASURE_DISJOINT_UNIONS_IMAGE;
+"HAS_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG",HAS_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG;
+"HAS_MEASURE_ELEMENTARY",HAS_MEASURE_ELEMENTARY;
+"HAS_MEASURE_EMPTY",HAS_MEASURE_EMPTY;
+"HAS_MEASURE_IMAGE_STD_SIMPLEX",HAS_MEASURE_IMAGE_STD_SIMPLEX;
+"HAS_MEASURE_IMP_MEASURABLE",HAS_MEASURE_IMP_MEASURABLE;
+"HAS_MEASURE_INNER_OUTER",HAS_MEASURE_INNER_OUTER;
+"HAS_MEASURE_INNER_OUTER_LE",HAS_MEASURE_INNER_OUTER_LE;
+"HAS_MEASURE_INTERVAL",HAS_MEASURE_INTERVAL;
+"HAS_MEASURE_LIMIT",HAS_MEASURE_LIMIT;
+"HAS_MEASURE_LINEAR_IMAGE",HAS_MEASURE_LINEAR_IMAGE;
+"HAS_MEASURE_LINEAR_IMAGE_ALT",HAS_MEASURE_LINEAR_IMAGE_ALT;
+"HAS_MEASURE_LINEAR_IMAGE_SAME",HAS_MEASURE_LINEAR_IMAGE_SAME;
+"HAS_MEASURE_LINEAR_SUFFICIENT",HAS_MEASURE_LINEAR_SUFFICIENT;
+"HAS_MEASURE_MEASURABLE_MEASURE",HAS_MEASURE_MEASURABLE_MEASURE;
+"HAS_MEASURE_MEASURE",HAS_MEASURE_MEASURE;
+"HAS_MEASURE_NEGLIGIBLE_SYMDIFF",HAS_MEASURE_NEGLIGIBLE_SYMDIFF;
+"HAS_MEASURE_NEGLIGIBLE_UNION",HAS_MEASURE_NEGLIGIBLE_UNION;
+"HAS_MEASURE_NEGLIGIBLE_UNIONS",HAS_MEASURE_NEGLIGIBLE_UNIONS;
+"HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE",HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE;
+"HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG",HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG;
+"HAS_MEASURE_NESTED_INTERS",HAS_MEASURE_NESTED_INTERS;
+"HAS_MEASURE_NESTED_UNIONS",HAS_MEASURE_NESTED_UNIONS;
+"HAS_MEASURE_ORTHOGONAL_IMAGE",HAS_MEASURE_ORTHOGONAL_IMAGE;
+"HAS_MEASURE_ORTHOGONAL_IMAGE_EQ",HAS_MEASURE_ORTHOGONAL_IMAGE_EQ;
+"HAS_MEASURE_POS_LE",HAS_MEASURE_POS_LE;
+"HAS_MEASURE_SCALING",HAS_MEASURE_SCALING;
+"HAS_MEASURE_SCALING_EQ",HAS_MEASURE_SCALING_EQ;
+"HAS_MEASURE_SHEAR_INTERVAL",HAS_MEASURE_SHEAR_INTERVAL;
+"HAS_MEASURE_SIMPLEX",HAS_MEASURE_SIMPLEX;
+"HAS_MEASURE_SIMPLEX_0",HAS_MEASURE_SIMPLEX_0;
+"HAS_MEASURE_STD_SIMPLEX",HAS_MEASURE_STD_SIMPLEX;
+"HAS_MEASURE_STRETCH",HAS_MEASURE_STRETCH;
+"HAS_MEASURE_SUBSET",HAS_MEASURE_SUBSET;
+"HAS_MEASURE_TETRAHEDRON",HAS_MEASURE_TETRAHEDRON;
+"HAS_MEASURE_TRANSLATION",HAS_MEASURE_TRANSLATION;
+"HAS_MEASURE_TRANSLATION_EQ",HAS_MEASURE_TRANSLATION_EQ;
+"HAS_MEASURE_TRIANGLE",HAS_MEASURE_TRIANGLE;
+"HAS_MEASURE_UNION_NEGLIGIBLE",HAS_MEASURE_UNION_NEGLIGIBLE;
+"HAS_MEASURE_UNION_NEGLIGIBLE_EQ",HAS_MEASURE_UNION_NEGLIGIBLE_EQ;
+"HAS_MEASURE_UNIQUE",HAS_MEASURE_UNIQUE;
+"HAS_PATH_INTEGRAL",HAS_PATH_INTEGRAL;
+"HAS_PATH_INTEGRAL_0",HAS_PATH_INTEGRAL_0;
+"HAS_PATH_INTEGRAL_ADD",HAS_PATH_INTEGRAL_ADD;
+"HAS_PATH_INTEGRAL_BOUND_CIRCLEPATH",HAS_PATH_INTEGRAL_BOUND_CIRCLEPATH;
+"HAS_PATH_INTEGRAL_BOUND_CIRCLEPATH_STRONG",HAS_PATH_INTEGRAL_BOUND_CIRCLEPATH_STRONG;
+"HAS_PATH_INTEGRAL_BOUND_LINEPATH",HAS_PATH_INTEGRAL_BOUND_LINEPATH;
+"HAS_PATH_INTEGRAL_BOUND_LINEPATH_STRONG",HAS_PATH_INTEGRAL_BOUND_LINEPATH_STRONG;
+"HAS_PATH_INTEGRAL_BOUND_PARTCIRCLEPATH",HAS_PATH_INTEGRAL_BOUND_PARTCIRCLEPATH;
+"HAS_PATH_INTEGRAL_BOUND_PARTCIRCLEPATH_STRONG",HAS_PATH_INTEGRAL_BOUND_PARTCIRCLEPATH_STRONG;
+"HAS_PATH_INTEGRAL_COMPLEX_DIV",HAS_PATH_INTEGRAL_COMPLEX_DIV;
+"HAS_PATH_INTEGRAL_COMPLEX_LMUL",HAS_PATH_INTEGRAL_COMPLEX_LMUL;
+"HAS_PATH_INTEGRAL_COMPLEX_RMUL",HAS_PATH_INTEGRAL_COMPLEX_RMUL;
+"HAS_PATH_INTEGRAL_CONST_LINEPATH",HAS_PATH_INTEGRAL_CONST_LINEPATH;
+"HAS_PATH_INTEGRAL_EQ",HAS_PATH_INTEGRAL_EQ;
+"HAS_PATH_INTEGRAL_INTEGRABLE",HAS_PATH_INTEGRAL_INTEGRABLE;
+"HAS_PATH_INTEGRAL_INTEGRAL",HAS_PATH_INTEGRAL_INTEGRAL;
+"HAS_PATH_INTEGRAL_IS_0",HAS_PATH_INTEGRAL_IS_0;
+"HAS_PATH_INTEGRAL_JOIN",HAS_PATH_INTEGRAL_JOIN;
+"HAS_PATH_INTEGRAL_LINEPATH",HAS_PATH_INTEGRAL_LINEPATH;
+"HAS_PATH_INTEGRAL_MIDPOINT",HAS_PATH_INTEGRAL_MIDPOINT;
+"HAS_PATH_INTEGRAL_NEG",HAS_PATH_INTEGRAL_NEG;
+"HAS_PATH_INTEGRAL_REVERSEPATH",HAS_PATH_INTEGRAL_REVERSEPATH;
+"HAS_PATH_INTEGRAL_REVERSE_LINEPATH",HAS_PATH_INTEGRAL_REVERSE_LINEPATH;
+"HAS_PATH_INTEGRAL_SHIFTPATH",HAS_PATH_INTEGRAL_SHIFTPATH;
+"HAS_PATH_INTEGRAL_SHIFTPATH_EQ",HAS_PATH_INTEGRAL_SHIFTPATH_EQ;
+"HAS_PATH_INTEGRAL_SPLIT",HAS_PATH_INTEGRAL_SPLIT;
+"HAS_PATH_INTEGRAL_SUB",HAS_PATH_INTEGRAL_SUB;
+"HAS_PATH_INTEGRAL_SUBPATH",HAS_PATH_INTEGRAL_SUBPATH;
+"HAS_PATH_INTEGRAL_SUBPATH_REFL",HAS_PATH_INTEGRAL_SUBPATH_REFL;
+"HAS_PATH_INTEGRAL_TRIVIAL",HAS_PATH_INTEGRAL_TRIVIAL;
+"HAS_PATH_INTEGRAL_UNIQUE",HAS_PATH_INTEGRAL_UNIQUE;
+"HAS_PATH_INTEGRAL_VSUM",HAS_PATH_INTEGRAL_VSUM;
+"HAS_PATH_INTEGRAL_WINDING_NUMBER",HAS_PATH_INTEGRAL_WINDING_NUMBER;
+"HAS_REAL_COMPLEX_DERIVATIVE_AT",HAS_REAL_COMPLEX_DERIVATIVE_AT;
+"HAS_REAL_COMPLEX_DERIVATIVE_WITHIN",HAS_REAL_COMPLEX_DERIVATIVE_WITHIN;
+"HAS_REAL_DERIVATIVE_ACS",HAS_REAL_DERIVATIVE_ACS;
+"HAS_REAL_DERIVATIVE_ACS_SIN",HAS_REAL_DERIVATIVE_ACS_SIN;
+"HAS_REAL_DERIVATIVE_ADD",HAS_REAL_DERIVATIVE_ADD;
+"HAS_REAL_DERIVATIVE_ASN",HAS_REAL_DERIVATIVE_ASN;
+"HAS_REAL_DERIVATIVE_ASN_COS",HAS_REAL_DERIVATIVE_ASN_COS;
+"HAS_REAL_DERIVATIVE_ATN",HAS_REAL_DERIVATIVE_ATN;
+"HAS_REAL_DERIVATIVE_ATREAL",HAS_REAL_DERIVATIVE_ATREAL;
+"HAS_REAL_DERIVATIVE_ATREAL_WITHIN",HAS_REAL_DERIVATIVE_ATREAL_WITHIN;
+"HAS_REAL_DERIVATIVE_CARATHEODORY_ATREAL",HAS_REAL_DERIVATIVE_CARATHEODORY_ATREAL;
+"HAS_REAL_DERIVATIVE_CARATHEODORY_WITHINREAL",HAS_REAL_DERIVATIVE_CARATHEODORY_WITHINREAL;
+"HAS_REAL_DERIVATIVE_CDIV_ATREAL",HAS_REAL_DERIVATIVE_CDIV_ATREAL;
+"HAS_REAL_DERIVATIVE_CDIV_WITHIN",HAS_REAL_DERIVATIVE_CDIV_WITHIN;
+"HAS_REAL_DERIVATIVE_CHAIN",HAS_REAL_DERIVATIVE_CHAIN;
+"HAS_REAL_DERIVATIVE_CHAIN_UNIV",HAS_REAL_DERIVATIVE_CHAIN_UNIV;
+"HAS_REAL_DERIVATIVE_CONST",HAS_REAL_DERIVATIVE_CONST;
+"HAS_REAL_DERIVATIVE_COS",HAS_REAL_DERIVATIVE_COS;
+"HAS_REAL_DERIVATIVE_DERIVATIVE",HAS_REAL_DERIVATIVE_DERIVATIVE;
+"HAS_REAL_DERIVATIVE_DIFFERENTIABLE",HAS_REAL_DERIVATIVE_DIFFERENTIABLE;
+"HAS_REAL_DERIVATIVE_DIV_ATREAL",HAS_REAL_DERIVATIVE_DIV_ATREAL;
+"HAS_REAL_DERIVATIVE_DIV_WITHIN",HAS_REAL_DERIVATIVE_DIV_WITHIN;
+"HAS_REAL_DERIVATIVE_EXP",HAS_REAL_DERIVATIVE_EXP;
+"HAS_REAL_DERIVATIVE_ID",HAS_REAL_DERIVATIVE_ID;
+"HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL",HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL;
+"HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_WITHINREAL",HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_WITHINREAL;
+"HAS_REAL_DERIVATIVE_INCREASING",HAS_REAL_DERIVATIVE_INCREASING;
+"HAS_REAL_DERIVATIVE_INCREASING_IMP",HAS_REAL_DERIVATIVE_INCREASING_IMP;
+"HAS_REAL_DERIVATIVE_INDEFINITE_INTEGRAL",HAS_REAL_DERIVATIVE_INDEFINITE_INTEGRAL;
+"HAS_REAL_DERIVATIVE_INVERSE_BASIC",HAS_REAL_DERIVATIVE_INVERSE_BASIC;
+"HAS_REAL_DERIVATIVE_INVERSE_STRONG",HAS_REAL_DERIVATIVE_INVERSE_STRONG;
+"HAS_REAL_DERIVATIVE_INVERSE_STRONG_X",HAS_REAL_DERIVATIVE_INVERSE_STRONG_X;
+"HAS_REAL_DERIVATIVE_INV_ATREAL",HAS_REAL_DERIVATIVE_INV_ATREAL;
+"HAS_REAL_DERIVATIVE_INV_BASIC",HAS_REAL_DERIVATIVE_INV_BASIC;
+"HAS_REAL_DERIVATIVE_INV_WITHIN",HAS_REAL_DERIVATIVE_INV_WITHIN;
+"HAS_REAL_DERIVATIVE_LMUL_ATREAL",HAS_REAL_DERIVATIVE_LMUL_ATREAL;
+"HAS_REAL_DERIVATIVE_LMUL_WITHIN",HAS_REAL_DERIVATIVE_LMUL_WITHIN;
+"HAS_REAL_DERIVATIVE_LOG",HAS_REAL_DERIVATIVE_LOG;
+"HAS_REAL_DERIVATIVE_MUL_ATREAL",HAS_REAL_DERIVATIVE_MUL_ATREAL;
+"HAS_REAL_DERIVATIVE_MUL_WITHIN",HAS_REAL_DERIVATIVE_MUL_WITHIN;
+"HAS_REAL_DERIVATIVE_NEG",HAS_REAL_DERIVATIVE_NEG;
+"HAS_REAL_DERIVATIVE_POW_ATREAL",HAS_REAL_DERIVATIVE_POW_ATREAL;
+"HAS_REAL_DERIVATIVE_POW_WITHIN",HAS_REAL_DERIVATIVE_POW_WITHIN;
+"HAS_REAL_DERIVATIVE_RMUL_ATREAL",HAS_REAL_DERIVATIVE_RMUL_ATREAL;
+"HAS_REAL_DERIVATIVE_RMUL_WITHIN",HAS_REAL_DERIVATIVE_RMUL_WITHIN;
+"HAS_REAL_DERIVATIVE_RPOW",HAS_REAL_DERIVATIVE_RPOW;
+"HAS_REAL_DERIVATIVE_SEQUENCE",HAS_REAL_DERIVATIVE_SEQUENCE;
+"HAS_REAL_DERIVATIVE_SERIES",HAS_REAL_DERIVATIVE_SERIES;
+"HAS_REAL_DERIVATIVE_SIN",HAS_REAL_DERIVATIVE_SIN;
+"HAS_REAL_DERIVATIVE_SQRT",HAS_REAL_DERIVATIVE_SQRT;
+"HAS_REAL_DERIVATIVE_SUB",HAS_REAL_DERIVATIVE_SUB;
+"HAS_REAL_DERIVATIVE_SUM",HAS_REAL_DERIVATIVE_SUM;
+"HAS_REAL_DERIVATIVE_TAN",HAS_REAL_DERIVATIVE_TAN;
+"HAS_REAL_DERIVATIVE_TRANSFORM_ATREAL",HAS_REAL_DERIVATIVE_TRANSFORM_ATREAL;
+"HAS_REAL_DERIVATIVE_TRANSFORM_WITHIN",HAS_REAL_DERIVATIVE_TRANSFORM_WITHIN;
+"HAS_REAL_DERIVATIVE_WITHINREAL",HAS_REAL_DERIVATIVE_WITHINREAL;
+"HAS_REAL_DERIVATIVE_WITHIN_REAL_OPEN",HAS_REAL_DERIVATIVE_WITHIN_REAL_OPEN;
+"HAS_REAL_DERIVATIVE_WITHIN_SUBSET",HAS_REAL_DERIVATIVE_WITHIN_SUBSET;
+"HAS_REAL_DERIVATIVE_ZERO_CONSTANT",HAS_REAL_DERIVATIVE_ZERO_CONSTANT;
+"HAS_REAL_DERIVATIVE_ZERO_UNIQUE",HAS_REAL_DERIVATIVE_ZERO_UNIQUE;
+"HAS_REAL_DERIVATIVE_ZERO_UNIQUE_STRONG_CONVEX",HAS_REAL_DERIVATIVE_ZERO_UNIQUE_STRONG_CONVEX;
+"HAS_REAL_DERIVATIVE_ZERO_UNIQUE_STRONG_INTERVAL",HAS_REAL_DERIVATIVE_ZERO_UNIQUE_STRONG_INTERVAL;
+"HAS_REAL_FRECHET_DERIVATIVE_AT",HAS_REAL_FRECHET_DERIVATIVE_AT;
+"HAS_REAL_FRECHET_DERIVATIVE_WITHIN",HAS_REAL_FRECHET_DERIVATIVE_WITHIN;
+"HAS_REAL_INTEGRAL",HAS_REAL_INTEGRAL;
+"HAS_REAL_INTEGRAL_0",HAS_REAL_INTEGRAL_0;
+"HAS_REAL_INTEGRAL_0_EQ",HAS_REAL_INTEGRAL_0_EQ;
+"HAS_REAL_INTEGRAL_ADD",HAS_REAL_INTEGRAL_ADD;
+"HAS_REAL_INTEGRAL_AFFINITY",HAS_REAL_INTEGRAL_AFFINITY;
+"HAS_REAL_INTEGRAL_BOUND",HAS_REAL_INTEGRAL_BOUND;
+"HAS_REAL_INTEGRAL_COMBINE",HAS_REAL_INTEGRAL_COMBINE;
+"HAS_REAL_INTEGRAL_CONST",HAS_REAL_INTEGRAL_CONST;
+"HAS_REAL_INTEGRAL_EMPTY",HAS_REAL_INTEGRAL_EMPTY;
+"HAS_REAL_INTEGRAL_EMPTY_EQ",HAS_REAL_INTEGRAL_EMPTY_EQ;
+"HAS_REAL_INTEGRAL_EQ",HAS_REAL_INTEGRAL_EQ;
+"HAS_REAL_INTEGRAL_EQ_EQ",HAS_REAL_INTEGRAL_EQ_EQ;
+"HAS_REAL_INTEGRAL_INTEGRABLE",HAS_REAL_INTEGRAL_INTEGRABLE;
+"HAS_REAL_INTEGRAL_INTEGRABLE_INTEGRAL",HAS_REAL_INTEGRAL_INTEGRABLE_INTEGRAL;
+"HAS_REAL_INTEGRAL_INTEGRAL",HAS_REAL_INTEGRAL_INTEGRAL;
+"HAS_REAL_INTEGRAL_ISNEG",HAS_REAL_INTEGRAL_ISNEG;
+"HAS_REAL_INTEGRAL_IS_0",HAS_REAL_INTEGRAL_IS_0;
+"HAS_REAL_INTEGRAL_LBOUND",HAS_REAL_INTEGRAL_LBOUND;
+"HAS_REAL_INTEGRAL_LE",HAS_REAL_INTEGRAL_LE;
+"HAS_REAL_INTEGRAL_LINEAR",HAS_REAL_INTEGRAL_LINEAR;
+"HAS_REAL_INTEGRAL_LMUL",HAS_REAL_INTEGRAL_LMUL;
+"HAS_REAL_INTEGRAL_NEG",HAS_REAL_INTEGRAL_NEG;
+"HAS_REAL_INTEGRAL_NEGLIGIBLE",HAS_REAL_INTEGRAL_NEGLIGIBLE;
+"HAS_REAL_INTEGRAL_NEGLIGIBLE_EQ",HAS_REAL_INTEGRAL_NEGLIGIBLE_EQ;
+"HAS_REAL_INTEGRAL_NULL",HAS_REAL_INTEGRAL_NULL;
+"HAS_REAL_INTEGRAL_NULL_EQ",HAS_REAL_INTEGRAL_NULL_EQ;
+"HAS_REAL_INTEGRAL_ON_SUPERSET",HAS_REAL_INTEGRAL_ON_SUPERSET;
+"HAS_REAL_INTEGRAL_OPEN_INTERVAL",HAS_REAL_INTEGRAL_OPEN_INTERVAL;
+"HAS_REAL_INTEGRAL_POS",HAS_REAL_INTEGRAL_POS;
+"HAS_REAL_INTEGRAL_REFL",HAS_REAL_INTEGRAL_REFL;
+"HAS_REAL_INTEGRAL_REFLECT",HAS_REAL_INTEGRAL_REFLECT;
+"HAS_REAL_INTEGRAL_REFLECT_LEMMA",HAS_REAL_INTEGRAL_REFLECT_LEMMA;
+"HAS_REAL_INTEGRAL_RESTRICT",HAS_REAL_INTEGRAL_RESTRICT;
+"HAS_REAL_INTEGRAL_RESTRICT_INTER",HAS_REAL_INTEGRAL_RESTRICT_INTER;
+"HAS_REAL_INTEGRAL_RESTRICT_UNIV",HAS_REAL_INTEGRAL_RESTRICT_UNIV;
+"HAS_REAL_INTEGRAL_RMUL",HAS_REAL_INTEGRAL_RMUL;
+"HAS_REAL_INTEGRAL_SPIKE",HAS_REAL_INTEGRAL_SPIKE;
+"HAS_REAL_INTEGRAL_SPIKE_EQ",HAS_REAL_INTEGRAL_SPIKE_EQ;
+"HAS_REAL_INTEGRAL_SPIKE_FINITE",HAS_REAL_INTEGRAL_SPIKE_FINITE;
+"HAS_REAL_INTEGRAL_SPIKE_FINITE_EQ",HAS_REAL_INTEGRAL_SPIKE_FINITE_EQ;
+"HAS_REAL_INTEGRAL_SPIKE_INTERIOR",HAS_REAL_INTEGRAL_SPIKE_INTERIOR;
+"HAS_REAL_INTEGRAL_SPIKE_INTERIOR_EQ",HAS_REAL_INTEGRAL_SPIKE_INTERIOR_EQ;
+"HAS_REAL_INTEGRAL_SPIKE_SET",HAS_REAL_INTEGRAL_SPIKE_SET;
+"HAS_REAL_INTEGRAL_SPIKE_SET_EQ",HAS_REAL_INTEGRAL_SPIKE_SET_EQ;
+"HAS_REAL_INTEGRAL_STRADDLE_NULL",HAS_REAL_INTEGRAL_STRADDLE_NULL;
+"HAS_REAL_INTEGRAL_STRETCH",HAS_REAL_INTEGRAL_STRETCH;
+"HAS_REAL_INTEGRAL_SUB",HAS_REAL_INTEGRAL_SUB;
+"HAS_REAL_INTEGRAL_SUBSET_LE",HAS_REAL_INTEGRAL_SUBSET_LE;
+"HAS_REAL_INTEGRAL_SUM",HAS_REAL_INTEGRAL_SUM;
+"HAS_REAL_INTEGRAL_UBOUND",HAS_REAL_INTEGRAL_UBOUND;
+"HAS_REAL_INTEGRAL_UNION",HAS_REAL_INTEGRAL_UNION;
+"HAS_REAL_INTEGRAL_UNIONS",HAS_REAL_INTEGRAL_UNIONS;
+"HAS_REAL_INTEGRAL_UNIQUE",HAS_REAL_INTEGRAL_UNIQUE;
+"HAS_REAL_MEASURE",HAS_REAL_MEASURE;
+"HAS_REAL_MEASURE_0",HAS_REAL_MEASURE_0;
+"HAS_REAL_MEASURE_AFFINITY",HAS_REAL_MEASURE_AFFINITY;
+"HAS_REAL_MEASURE_ALMOST",HAS_REAL_MEASURE_ALMOST;
+"HAS_REAL_MEASURE_ALMOST_EQ",HAS_REAL_MEASURE_ALMOST_EQ;
+"HAS_REAL_MEASURE_COUNTABLE_REAL_NEGLIGIBLE_UNIONS",HAS_REAL_MEASURE_COUNTABLE_REAL_NEGLIGIBLE_UNIONS;
+"HAS_REAL_MEASURE_COUNTABLE_REAL_NEGLIGIBLE_UNIONS_BOUNDED",HAS_REAL_MEASURE_COUNTABLE_REAL_NEGLIGIBLE_UNIONS_BOUNDED;
+"HAS_REAL_MEASURE_DIFF_REAL_NEGLIGIBLE",HAS_REAL_MEASURE_DIFF_REAL_NEGLIGIBLE;
+"HAS_REAL_MEASURE_DIFF_REAL_NEGLIGIBLE_EQ",HAS_REAL_MEASURE_DIFF_REAL_NEGLIGIBLE_EQ;
+"HAS_REAL_MEASURE_DIFF_SUBSET",HAS_REAL_MEASURE_DIFF_SUBSET;
+"HAS_REAL_MEASURE_DISJOINT_UNION",HAS_REAL_MEASURE_DISJOINT_UNION;
+"HAS_REAL_MEASURE_DISJOINT_UNIONS",HAS_REAL_MEASURE_DISJOINT_UNIONS;
+"HAS_REAL_MEASURE_DISJOINT_UNIONS_IMAGE",HAS_REAL_MEASURE_DISJOINT_UNIONS_IMAGE;
+"HAS_REAL_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG",HAS_REAL_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG;
+"HAS_REAL_MEASURE_EMPTY",HAS_REAL_MEASURE_EMPTY;
+"HAS_REAL_MEASURE_HAS_MEASURE",HAS_REAL_MEASURE_HAS_MEASURE;
+"HAS_REAL_MEASURE_IMP_REAL_MEASURABLE",HAS_REAL_MEASURE_IMP_REAL_MEASURABLE;
+"HAS_REAL_MEASURE_INNER_OUTER",HAS_REAL_MEASURE_INNER_OUTER;
+"HAS_REAL_MEASURE_INNER_OUTER_LE",HAS_REAL_MEASURE_INNER_OUTER_LE;
+"HAS_REAL_MEASURE_MEASURE",HAS_REAL_MEASURE_MEASURE;
+"HAS_REAL_MEASURE_NESTED_UNIONS",HAS_REAL_MEASURE_NESTED_UNIONS;
+"HAS_REAL_MEASURE_POS_LE",HAS_REAL_MEASURE_POS_LE;
+"HAS_REAL_MEASURE_REAL_INTERVAL",HAS_REAL_MEASURE_REAL_INTERVAL;
+"HAS_REAL_MEASURE_REAL_MEASURABLE_REAL_MEASURE",HAS_REAL_MEASURE_REAL_MEASURABLE_REAL_MEASURE;
+"HAS_REAL_MEASURE_REAL_NEGLIGIBLE_SYMDIFF",HAS_REAL_MEASURE_REAL_NEGLIGIBLE_SYMDIFF;
+"HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNION",HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNION;
+"HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS",HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS;
+"HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE",HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE;
+"HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE_STRONG",HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE_STRONG;
+"HAS_REAL_MEASURE_SCALING",HAS_REAL_MEASURE_SCALING;
+"HAS_REAL_MEASURE_SCALING_EQ",HAS_REAL_MEASURE_SCALING_EQ;
+"HAS_REAL_MEASURE_SUBSET",HAS_REAL_MEASURE_SUBSET;
+"HAS_REAL_MEASURE_TRANSLATION",HAS_REAL_MEASURE_TRANSLATION;
+"HAS_REAL_MEASURE_TRANSLATION_EQ",HAS_REAL_MEASURE_TRANSLATION_EQ;
+"HAS_REAL_MEASURE_UNION_REAL_NEGLIGIBLE",HAS_REAL_MEASURE_UNION_REAL_NEGLIGIBLE;
+"HAS_REAL_MEASURE_UNION_REAL_NEGLIGIBLE_EQ",HAS_REAL_MEASURE_UNION_REAL_NEGLIGIBLE_EQ;
+"HAS_REAL_MEASURE_UNIQUE",HAS_REAL_MEASURE_UNIQUE;
+"HAS_REAL_VECTOR_DERIVATIVE_AT",HAS_REAL_VECTOR_DERIVATIVE_AT;
+"HAS_REAL_VECTOR_DERIVATIVE_WITHIN",HAS_REAL_VECTOR_DERIVATIVE_WITHIN;
+"HAS_SIZE",HAS_SIZE;
+"HAS_SIZE_0",HAS_SIZE_0;
+"HAS_SIZE_1",HAS_SIZE_1;
+"HAS_SIZE_1_EXISTS",HAS_SIZE_1_EXISTS;
+"HAS_SIZE_2",HAS_SIZE_2;
+"HAS_SIZE_2_EXISTS",HAS_SIZE_2_EXISTS;
+"HAS_SIZE_3",HAS_SIZE_3;
+"HAS_SIZE_4",HAS_SIZE_4;
+"HAS_SIZE_BOOL",HAS_SIZE_BOOL;
+"HAS_SIZE_CARD",HAS_SIZE_CARD;
+"HAS_SIZE_CART_UNIV",HAS_SIZE_CART_UNIV;
+"HAS_SIZE_CLAUSES",HAS_SIZE_CLAUSES;
+"HAS_SIZE_COMPLEX_ROOTS_UNITY",HAS_SIZE_COMPLEX_ROOTS_UNITY;
+"HAS_SIZE_CROSS",HAS_SIZE_CROSS;
+"HAS_SIZE_DIFF",HAS_SIZE_DIFF;
+"HAS_SIZE_FACES_OF_SIMPLEX",HAS_SIZE_FACES_OF_SIMPLEX;
+"HAS_SIZE_FINITE_IMAGE",HAS_SIZE_FINITE_IMAGE;
+"HAS_SIZE_FUNSPACE",HAS_SIZE_FUNSPACE;
+"HAS_SIZE_FUNSPACE_UNIV",HAS_SIZE_FUNSPACE_UNIV;
+"HAS_SIZE_IMAGE_INJ",HAS_SIZE_IMAGE_INJ;
+"HAS_SIZE_IMAGE_INJ_EQ",HAS_SIZE_IMAGE_INJ_EQ;
+"HAS_SIZE_INDEX",HAS_SIZE_INDEX;
+"HAS_SIZE_INTSEG_INT",HAS_SIZE_INTSEG_INT;
+"HAS_SIZE_INTSEG_NUM",HAS_SIZE_INTSEG_NUM;
+"HAS_SIZE_MULTIVECTOR",HAS_SIZE_MULTIVECTOR;
+"HAS_SIZE_NUMSEG",HAS_SIZE_NUMSEG;
+"HAS_SIZE_NUMSEG_1",HAS_SIZE_NUMSEG_1;
+"HAS_SIZE_NUMSEG_LE",HAS_SIZE_NUMSEG_LE;
+"HAS_SIZE_NUMSEG_LT",HAS_SIZE_NUMSEG_LT;
+"HAS_SIZE_PCROSS",HAS_SIZE_PCROSS;
+"HAS_SIZE_PERMUTATIONS",HAS_SIZE_PERMUTATIONS;
+"HAS_SIZE_POWERSET",HAS_SIZE_POWERSET;
+"HAS_SIZE_PRODUCT",HAS_SIZE_PRODUCT;
+"HAS_SIZE_PRODUCT_DEPENDENT",HAS_SIZE_PRODUCT_DEPENDENT;
+"HAS_SIZE_SET_OF_LIST",HAS_SIZE_SET_OF_LIST;
+"HAS_SIZE_STDBASIS",HAS_SIZE_STDBASIS;
+"HAS_SIZE_SUC",HAS_SIZE_SUC;
+"HAS_SIZE_UNION",HAS_SIZE_UNION;
+"HAS_SIZE_UNIONS",HAS_SIZE_UNIONS;
+"HAS_VECTOR_DERIVATIVE_ADD",HAS_VECTOR_DERIVATIVE_ADD;
+"HAS_VECTOR_DERIVATIVE_AT_WITHIN",HAS_VECTOR_DERIVATIVE_AT_WITHIN;
+"HAS_VECTOR_DERIVATIVE_BILINEAR_AT",HAS_VECTOR_DERIVATIVE_BILINEAR_AT;
+"HAS_VECTOR_DERIVATIVE_BILINEAR_WITHIN",HAS_VECTOR_DERIVATIVE_BILINEAR_WITHIN;
+"HAS_VECTOR_DERIVATIVE_CIRCLEPATH",HAS_VECTOR_DERIVATIVE_CIRCLEPATH;
+"HAS_VECTOR_DERIVATIVE_CMUL",HAS_VECTOR_DERIVATIVE_CMUL;
+"HAS_VECTOR_DERIVATIVE_CMUL_EQ",HAS_VECTOR_DERIVATIVE_CMUL_EQ;
+"HAS_VECTOR_DERIVATIVE_CONST",HAS_VECTOR_DERIVATIVE_CONST;
+"HAS_VECTOR_DERIVATIVE_ID",HAS_VECTOR_DERIVATIVE_ID;
+"HAS_VECTOR_DERIVATIVE_INDEFINITE_INTEGRAL",HAS_VECTOR_DERIVATIVE_INDEFINITE_INTEGRAL;
+"HAS_VECTOR_DERIVATIVE_LINEPATH_AT",HAS_VECTOR_DERIVATIVE_LINEPATH_AT;
+"HAS_VECTOR_DERIVATIVE_LINEPATH_WITHIN",HAS_VECTOR_DERIVATIVE_LINEPATH_WITHIN;
+"HAS_VECTOR_DERIVATIVE_NEG",HAS_VECTOR_DERIVATIVE_NEG;
+"HAS_VECTOR_DERIVATIVE_NEG_EQ",HAS_VECTOR_DERIVATIVE_NEG_EQ;
+"HAS_VECTOR_DERIVATIVE_PARTCIRCLEPATH",HAS_VECTOR_DERIVATIVE_PARTCIRCLEPATH;
+"HAS_VECTOR_DERIVATIVE_REAL_COMPLEX",HAS_VECTOR_DERIVATIVE_REAL_COMPLEX;
+"HAS_VECTOR_DERIVATIVE_SUB",HAS_VECTOR_DERIVATIVE_SUB;
+"HAS_VECTOR_DERIVATIVE_TRANSFORM_AT",HAS_VECTOR_DERIVATIVE_TRANSFORM_AT;
+"HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN",HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN;
+"HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN_OPEN",HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN_OPEN;
+"HAS_VECTOR_DERIVATIVE_UNIQUE_AT",HAS_VECTOR_DERIVATIVE_UNIQUE_AT;
+"HAS_VECTOR_DERIVATIVE_VECTOR_POLYNOMIAL_FUNCTION",HAS_VECTOR_DERIVATIVE_VECTOR_POLYNOMIAL_FUNCTION;
+"HAS_VECTOR_DERIVATIVE_WITHIN_SUBSET",HAS_VECTOR_DERIVATIVE_WITHIN_SUBSET;
+"HD",HD;
+"HD_APPEND",HD_APPEND;
+"HEINE_BOREL_IMP_BOLZANO_WEIERSTRASS",HEINE_BOREL_IMP_BOLZANO_WEIERSTRASS;
+"HEINE_BOREL_LEMMA",HEINE_BOREL_LEMMA;
+"HELLY",HELLY;
+"HELLY_ALT",HELLY_ALT;
+"HELLY_CLOSED",HELLY_CLOSED;
+"HELLY_CLOSED_ALT",HELLY_CLOSED_ALT;
+"HELLY_COMPACT",HELLY_COMPACT;
+"HELLY_COMPACT_ALT",HELLY_COMPACT_ALT;
+"HELLY_INDUCT",HELLY_INDUCT;
+"HENSTOCK_LEMMA",HENSTOCK_LEMMA;
+"HENSTOCK_LEMMA_PART1",HENSTOCK_LEMMA_PART1;
+"HENSTOCK_LEMMA_PART2",HENSTOCK_LEMMA_PART2;
+"HIGHER_COMPLEX_DERIVATIVE_1",HIGHER_COMPLEX_DERIVATIVE_1;
+"HIGHER_COMPLEX_DERIVATIVE_ADD",HIGHER_COMPLEX_DERIVATIVE_ADD;
+"HIGHER_COMPLEX_DERIVATIVE_ADD_AT",HIGHER_COMPLEX_DERIVATIVE_ADD_AT;
+"HIGHER_COMPLEX_DERIVATIVE_COMPOSE_LINEAR",HIGHER_COMPLEX_DERIVATIVE_COMPOSE_LINEAR;
+"HIGHER_COMPLEX_DERIVATIVE_COMP_ITER_LEMMA",HIGHER_COMPLEX_DERIVATIVE_COMP_ITER_LEMMA;
+"HIGHER_COMPLEX_DERIVATIVE_COMP_LEMMA",HIGHER_COMPLEX_DERIVATIVE_COMP_LEMMA;
+"HIGHER_COMPLEX_DERIVATIVE_CONST",HIGHER_COMPLEX_DERIVATIVE_CONST;
+"HIGHER_COMPLEX_DERIVATIVE_EQ_ITER",HIGHER_COMPLEX_DERIVATIVE_EQ_ITER;
+"HIGHER_COMPLEX_DERIVATIVE_HIGHER_COMPLEX_DERIVATIVE",HIGHER_COMPLEX_DERIVATIVE_HIGHER_COMPLEX_DERIVATIVE;
+"HIGHER_COMPLEX_DERIVATIVE_ID",HIGHER_COMPLEX_DERIVATIVE_ID;
+"HIGHER_COMPLEX_DERIVATIVE_ITER_TOP_LEMMA",HIGHER_COMPLEX_DERIVATIVE_ITER_TOP_LEMMA;
+"HIGHER_COMPLEX_DERIVATIVE_LINEAR",HIGHER_COMPLEX_DERIVATIVE_LINEAR;
+"HIGHER_COMPLEX_DERIVATIVE_MUL",HIGHER_COMPLEX_DERIVATIVE_MUL;
+"HIGHER_COMPLEX_DERIVATIVE_MUL_AT",HIGHER_COMPLEX_DERIVATIVE_MUL_AT;
+"HIGHER_COMPLEX_DERIVATIVE_NEG",HIGHER_COMPLEX_DERIVATIVE_NEG;
+"HIGHER_COMPLEX_DERIVATIVE_NEG_AT",HIGHER_COMPLEX_DERIVATIVE_NEG_AT;
+"HIGHER_COMPLEX_DERIVATIVE_SUB",HIGHER_COMPLEX_DERIVATIVE_SUB;
+"HIGHER_COMPLEX_DERIVATIVE_SUB_AT",HIGHER_COMPLEX_DERIVATIVE_SUB_AT;
+"HIGHER_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN",HIGHER_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN_OPEN;
+"HOLOMORPHIC_COMPLEX_DERIVATIVE",HOLOMORPHIC_COMPLEX_DERIVATIVE;
+"HOLOMORPHIC_CONVEX_PRIMITIVE",HOLOMORPHIC_CONVEX_PRIMITIVE;
+"HOLOMORPHIC_DERIVATIVE",HOLOMORPHIC_DERIVATIVE;
+"HOLOMORPHIC_EQ",HOLOMORPHIC_EQ;
+"HOLOMORPHIC_FACTOR_ORDER_OF_ZERO",HOLOMORPHIC_FACTOR_ORDER_OF_ZERO;
+"HOLOMORPHIC_FACTOR_ORDER_OF_ZERO_STRONG",HOLOMORPHIC_FACTOR_ORDER_OF_ZERO_STRONG;
+"HOLOMORPHIC_FACTOR_ZERO_NONCONSTANT",HOLOMORPHIC_FACTOR_ZERO_NONCONSTANT;
+"HOLOMORPHIC_FUN_EQ_0_ON_BALL",HOLOMORPHIC_FUN_EQ_0_ON_BALL;
+"HOLOMORPHIC_FUN_EQ_0_ON_CONNECTED",HOLOMORPHIC_FUN_EQ_0_ON_CONNECTED;
+"HOLOMORPHIC_FUN_EQ_CONST_ON_CONNECTED",HOLOMORPHIC_FUN_EQ_CONST_ON_CONNECTED;
+"HOLOMORPHIC_FUN_EQ_ON_BALL",HOLOMORPHIC_FUN_EQ_ON_BALL;
+"HOLOMORPHIC_FUN_EQ_ON_CONNECTED",HOLOMORPHIC_FUN_EQ_ON_CONNECTED;
+"HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE",HOLOMORPHIC_HIGHER_COMPLEX_DERIVATIVE;
+"HOLOMORPHIC_IFF_POWER_SERIES",HOLOMORPHIC_IFF_POWER_SERIES;
+"HOLOMORPHIC_INJECTIVE_IMP_REGULAR",HOLOMORPHIC_INJECTIVE_IMP_REGULAR;
+"HOLOMORPHIC_INVOLUTION_POINT",HOLOMORPHIC_INVOLUTION_POINT;
+"HOLOMORPHIC_ON_ADD",HOLOMORPHIC_ON_ADD;
+"HOLOMORPHIC_ON_CACS",HOLOMORPHIC_ON_CACS;
+"HOLOMORPHIC_ON_CASN",HOLOMORPHIC_ON_CASN;
+"HOLOMORPHIC_ON_CATN",HOLOMORPHIC_ON_CATN;
+"HOLOMORPHIC_ON_CCOS",HOLOMORPHIC_ON_CCOS;
+"HOLOMORPHIC_ON_CEXP",HOLOMORPHIC_ON_CEXP;
+"HOLOMORPHIC_ON_CLOG",HOLOMORPHIC_ON_CLOG;
+"HOLOMORPHIC_ON_COMPOSE",HOLOMORPHIC_ON_COMPOSE;
+"HOLOMORPHIC_ON_COMPOSE_GEN",HOLOMORPHIC_ON_COMPOSE_GEN;
+"HOLOMORPHIC_ON_CONST",HOLOMORPHIC_ON_CONST;
+"HOLOMORPHIC_ON_CPOW_RIGHT",HOLOMORPHIC_ON_CPOW_RIGHT;
+"HOLOMORPHIC_ON_CSIN",HOLOMORPHIC_ON_CSIN;
+"HOLOMORPHIC_ON_CSQRT",HOLOMORPHIC_ON_CSQRT;
+"HOLOMORPHIC_ON_CTAN",HOLOMORPHIC_ON_CTAN;
+"HOLOMORPHIC_ON_DIFFERENTIABLE",HOLOMORPHIC_ON_DIFFERENTIABLE;
+"HOLOMORPHIC_ON_DIV",HOLOMORPHIC_ON_DIV;
+"HOLOMORPHIC_ON_EXTEND_BOUNDED",HOLOMORPHIC_ON_EXTEND_BOUNDED;
+"HOLOMORPHIC_ON_EXTEND_LIM",HOLOMORPHIC_ON_EXTEND_LIM;
+"HOLOMORPHIC_ON_ID",HOLOMORPHIC_ON_ID;
+"HOLOMORPHIC_ON_IMP_CONTINUOUS_ON",HOLOMORPHIC_ON_IMP_CONTINUOUS_ON;
+"HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT",HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_AT;
+"HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_WITHIN",HOLOMORPHIC_ON_IMP_DIFFERENTIABLE_WITHIN;
+"HOLOMORPHIC_ON_INV",HOLOMORPHIC_ON_INV;
+"HOLOMORPHIC_ON_INVERSE",HOLOMORPHIC_ON_INVERSE;
+"HOLOMORPHIC_ON_LINEAR",HOLOMORPHIC_ON_LINEAR;
+"HOLOMORPHIC_ON_MUL",HOLOMORPHIC_ON_MUL;
+"HOLOMORPHIC_ON_NEG",HOLOMORPHIC_ON_NEG;
+"HOLOMORPHIC_ON_OPEN",HOLOMORPHIC_ON_OPEN;
+"HOLOMORPHIC_ON_PASTE_ACROSS_LINE",HOLOMORPHIC_ON_PASTE_ACROSS_LINE;
+"HOLOMORPHIC_ON_POW",HOLOMORPHIC_ON_POW;
+"HOLOMORPHIC_ON_SUB",HOLOMORPHIC_ON_SUB;
+"HOLOMORPHIC_ON_SUBSET",HOLOMORPHIC_ON_SUBSET;
+"HOLOMORPHIC_ON_VSUM",HOLOMORPHIC_ON_VSUM;
+"HOLOMORPHIC_PERIODIC_FIXPOINT",HOLOMORPHIC_PERIODIC_FIXPOINT;
+"HOLOMORPHIC_POINT_SMALL_TRIANGLE",HOLOMORPHIC_POINT_SMALL_TRIANGLE;
+"HOLOMORPHIC_POWER_SERIES",HOLOMORPHIC_POWER_SERIES;
+"HOLOMORPHIC_STARLIKE_PRIMITIVE",HOLOMORPHIC_STARLIKE_PRIMITIVE;
+"HOLOMORPHIC_TRANSFORM",HOLOMORPHIC_TRANSFORM;
+"HOLOMORPHIC_UNIFORM_LIMIT",HOLOMORPHIC_UNIFORM_LIMIT;
+"HOLOMORPHIC_UNIFORM_SEQUENCE",HOLOMORPHIC_UNIFORM_SEQUENCE;
+"HOMEOMORPHIC_AFFINE_SETS",HOMEOMORPHIC_AFFINE_SETS;
+"HOMEOMORPHIC_AFFINE_SETS_EQ",HOMEOMORPHIC_AFFINE_SETS_EQ;
+"HOMEOMORPHIC_AFFINITY",HOMEOMORPHIC_AFFINITY;
+"HOMEOMORPHIC_ANRNESS",HOMEOMORPHIC_ANRNESS;
+"HOMEOMORPHIC_ARC_IMAGES",HOMEOMORPHIC_ARC_IMAGES;
+"HOMEOMORPHIC_ARC_IMAGE_INTERVAL",HOMEOMORPHIC_ARC_IMAGE_INTERVAL;
+"HOMEOMORPHIC_ARC_IMAGE_SEGMENT",HOMEOMORPHIC_ARC_IMAGE_SEGMENT;
+"HOMEOMORPHIC_BALLS",HOMEOMORPHIC_BALLS;
+"HOMEOMORPHIC_BALLS_EQ",HOMEOMORPHIC_BALLS_EQ;
+"HOMEOMORPHIC_BALL_UNIV",HOMEOMORPHIC_BALL_UNIV;
+"HOMEOMORPHIC_CBALLS",HOMEOMORPHIC_CBALLS;
+"HOMEOMORPHIC_CBALLS_EQ",HOMEOMORPHIC_CBALLS_EQ;
+"HOMEOMORPHIC_CLOSED_INTERVALS",HOMEOMORPHIC_CLOSED_INTERVALS;
+"HOMEOMORPHIC_COMPACT",HOMEOMORPHIC_COMPACT;
+"HOMEOMORPHIC_COMPACTNESS",HOMEOMORPHIC_COMPACTNESS;
+"HOMEOMORPHIC_COMPACT_ARNESS",HOMEOMORPHIC_COMPACT_ARNESS;
+"HOMEOMORPHIC_CONNECTEDNESS",HOMEOMORPHIC_CONNECTEDNESS;
+"HOMEOMORPHIC_CONTRACTIBLE",HOMEOMORPHIC_CONTRACTIBLE;
+"HOMEOMORPHIC_CONTRACTIBLE_EQ",HOMEOMORPHIC_CONTRACTIBLE_EQ;
+"HOMEOMORPHIC_CONVEX_COMPACT",HOMEOMORPHIC_CONVEX_COMPACT;
+"HOMEOMORPHIC_CONVEX_COMPACT_CBALL",HOMEOMORPHIC_CONVEX_COMPACT_CBALL;
+"HOMEOMORPHIC_CONVEX_COMPACT_SETS",HOMEOMORPHIC_CONVEX_COMPACT_SETS;
+"HOMEOMORPHIC_CONVEX_COMPACT_SETS_EQ",HOMEOMORPHIC_CONVEX_COMPACT_SETS_EQ;
+"HOMEOMORPHIC_CONVEX_SETS",HOMEOMORPHIC_CONVEX_SETS;
+"HOMEOMORPHIC_EMPTY",HOMEOMORPHIC_EMPTY;
+"HOMEOMORPHIC_FINITE",HOMEOMORPHIC_FINITE;
+"HOMEOMORPHIC_FINITE_STRONG",HOMEOMORPHIC_FINITE_STRONG;
+"HOMEOMORPHIC_FIXPOINT_PROPERTY",HOMEOMORPHIC_FIXPOINT_PROPERTY;
+"HOMEOMORPHIC_FRONTIERS",HOMEOMORPHIC_FRONTIERS;
+"HOMEOMORPHIC_FRONTIERS_SAME_DIMENSION",HOMEOMORPHIC_FRONTIERS_SAME_DIMENSION;
+"HOMEOMORPHIC_HYPERPLANES",HOMEOMORPHIC_HYPERPLANES;
+"HOMEOMORPHIC_HYPERPLANES_EQ",HOMEOMORPHIC_HYPERPLANES_EQ;
+"HOMEOMORPHIC_HYPERPLANE_STANDARD_HYPERPLANE",HOMEOMORPHIC_HYPERPLANE_STANDARD_HYPERPLANE;
+"HOMEOMORPHIC_HYPERPLANE_UNIV",HOMEOMORPHIC_HYPERPLANE_UNIV;
+"HOMEOMORPHIC_IMP_CARD_EQ",HOMEOMORPHIC_IMP_CARD_EQ;
+"HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT",HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT;
+"HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_LEFT_EQ",HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_LEFT_EQ;
+"HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ",HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ;
+"HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_SELF",HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_SELF;
+"HOMEOMORPHIC_INTERIORS",HOMEOMORPHIC_INTERIORS;
+"HOMEOMORPHIC_INTERIORS_SAME_DIMENSION",HOMEOMORPHIC_INTERIORS_SAME_DIMENSION;
+"HOMEOMORPHIC_INTERVALS_EQ",HOMEOMORPHIC_INTERVALS_EQ;
+"HOMEOMORPHIC_LOCALLY",HOMEOMORPHIC_LOCALLY;
+"HOMEOMORPHIC_LOCAL_COMPACTNESS",HOMEOMORPHIC_LOCAL_COMPACTNESS;
+"HOMEOMORPHIC_LOCAL_CONNECTEDNESS",HOMEOMORPHIC_LOCAL_CONNECTEDNESS;
+"HOMEOMORPHIC_LOCAL_PATH_CONNECTEDNESS",HOMEOMORPHIC_LOCAL_PATH_CONNECTEDNESS;
+"HOMEOMORPHIC_MINIMAL",HOMEOMORPHIC_MINIMAL;
+"HOMEOMORPHIC_MONOTONE_IMAGE_INTERVAL",HOMEOMORPHIC_MONOTONE_IMAGE_INTERVAL;
+"HOMEOMORPHIC_ONE_POINT_COMPACTIFICATIONS",HOMEOMORPHIC_ONE_POINT_COMPACTIFICATIONS;
+"HOMEOMORPHIC_OPEN_INTERVALS",HOMEOMORPHIC_OPEN_INTERVALS;
+"HOMEOMORPHIC_OPEN_INTERVALS_1",HOMEOMORPHIC_OPEN_INTERVALS_1;
+"HOMEOMORPHIC_OPEN_INTERVAL_UNIV",HOMEOMORPHIC_OPEN_INTERVAL_UNIV;
+"HOMEOMORPHIC_OPEN_INTERVAL_UNIV_1",HOMEOMORPHIC_OPEN_INTERVAL_UNIV_1;
+"HOMEOMORPHIC_PATH_CONNECTEDNESS",HOMEOMORPHIC_PATH_CONNECTEDNESS;
+"HOMEOMORPHIC_PCROSS",HOMEOMORPHIC_PCROSS;
+"HOMEOMORPHIC_PCROSS_ASSOC",HOMEOMORPHIC_PCROSS_ASSOC;
+"HOMEOMORPHIC_PCROSS_SING",HOMEOMORPHIC_PCROSS_SING;
+"HOMEOMORPHIC_PCROSS_SYM",HOMEOMORPHIC_PCROSS_SYM;
+"HOMEOMORPHIC_PUNCTURED_AFFINE_SPHERE_AFFINE",HOMEOMORPHIC_PUNCTURED_AFFINE_SPHERE_AFFINE;
+"HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE",HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE;
+"HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE_GEN",HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE_GEN;
+"HOMEOMORPHIC_PUNCTURED_SPHERE_HYPERPLANE",HOMEOMORPHIC_PUNCTURED_SPHERE_HYPERPLANE;
+"HOMEOMORPHIC_PUNCTURED_SPHERE_UNIV",HOMEOMORPHIC_PUNCTURED_SPHERE_UNIV;
+"HOMEOMORPHIC_REFL",HOMEOMORPHIC_REFL;
+"HOMEOMORPHIC_RELATIVE_BOUNDARIES",HOMEOMORPHIC_RELATIVE_BOUNDARIES;
+"HOMEOMORPHIC_RELATIVE_BOUNDARIES_SAME_DIMENSION",HOMEOMORPHIC_RELATIVE_BOUNDARIES_SAME_DIMENSION;
+"HOMEOMORPHIC_RELATIVE_FRONTIERS_CONVEX_BOUNDED_SETS",HOMEOMORPHIC_RELATIVE_FRONTIERS_CONVEX_BOUNDED_SETS;
+"HOMEOMORPHIC_RELATIVE_INTERIORS",HOMEOMORPHIC_RELATIVE_INTERIORS;
+"HOMEOMORPHIC_RELATIVE_INTERIORS_SAME_DIMENSION",HOMEOMORPHIC_RELATIVE_INTERIORS_SAME_DIMENSION;
+"HOMEOMORPHIC_SCALING",HOMEOMORPHIC_SCALING;
+"HOMEOMORPHIC_SCALING_LEFT",HOMEOMORPHIC_SCALING_LEFT;
+"HOMEOMORPHIC_SCALING_RIGHT",HOMEOMORPHIC_SCALING_RIGHT;
+"HOMEOMORPHIC_SIMPLE_PATH_IMAGES",HOMEOMORPHIC_SIMPLE_PATH_IMAGES;
+"HOMEOMORPHIC_SIMPLE_PATH_IMAGE_CIRCLE",HOMEOMORPHIC_SIMPLE_PATH_IMAGE_CIRCLE;
+"HOMEOMORPHIC_SIMPLY_CONNECTED",HOMEOMORPHIC_SIMPLY_CONNECTED;
+"HOMEOMORPHIC_SIMPLY_CONNECTED_EQ",HOMEOMORPHIC_SIMPLY_CONNECTED_EQ;
+"HOMEOMORPHIC_SING",HOMEOMORPHIC_SING;
+"HOMEOMORPHIC_SPHERES",HOMEOMORPHIC_SPHERES;
+"HOMEOMORPHIC_SPHERES_EQ",HOMEOMORPHIC_SPHERES_EQ;
+"HOMEOMORPHIC_STANDARD_HYPERPLANE_HYPERPLANE",HOMEOMORPHIC_STANDARD_HYPERPLANE_HYPERPLANE;
+"HOMEOMORPHIC_SUBSPACES",HOMEOMORPHIC_SUBSPACES;
+"HOMEOMORPHIC_SUBSPACES_EQ",HOMEOMORPHIC_SUBSPACES_EQ;
+"HOMEOMORPHIC_SYM",HOMEOMORPHIC_SYM;
+"HOMEOMORPHIC_TRANS",HOMEOMORPHIC_TRANS;
+"HOMEOMORPHIC_TRANSLATION",HOMEOMORPHIC_TRANSLATION;
+"HOMEOMORPHIC_TRANSLATION_LEFT_EQ",HOMEOMORPHIC_TRANSLATION_LEFT_EQ;
+"HOMEOMORPHIC_TRANSLATION_RIGHT_EQ",HOMEOMORPHIC_TRANSLATION_RIGHT_EQ;
+"HOMEOMORPHIC_TRANSLATION_SELF",HOMEOMORPHIC_TRANSLATION_SELF;
+"HOMEOMORPHIC_UNIV_UNIV",HOMEOMORPHIC_UNIV_UNIV;
+"HOMEOMORPHISM",HOMEOMORPHISM;
+"HOMEOMORPHISM_ARC",HOMEOMORPHISM_ARC;
+"HOMEOMORPHISM_COMPACT",HOMEOMORPHISM_COMPACT;
+"HOMEOMORPHISM_COMPOSE",HOMEOMORPHISM_COMPOSE;
+"HOMEOMORPHISM_FROM_COMPOSITION_INJECTIVE",HOMEOMORPHISM_FROM_COMPOSITION_INJECTIVE;
+"HOMEOMORPHISM_FROM_COMPOSITION_SURJECTIVE",HOMEOMORPHISM_FROM_COMPOSITION_SURJECTIVE;
+"HOMEOMORPHISM_GROUPING_POINTS_EXISTS",HOMEOMORPHISM_GROUPING_POINTS_EXISTS;
+"HOMEOMORPHISM_GROUPING_POINTS_EXISTS_GEN",HOMEOMORPHISM_GROUPING_POINTS_EXISTS_GEN;
+"HOMEOMORPHISM_I",HOMEOMORPHISM_I;
+"HOMEOMORPHISM_ID",HOMEOMORPHISM_ID;
+"HOMEOMORPHISM_IMP_CLOSED_MAP",HOMEOMORPHISM_IMP_CLOSED_MAP;
+"HOMEOMORPHISM_IMP_COVERING_SPACE",HOMEOMORPHISM_IMP_COVERING_SPACE;
+"HOMEOMORPHISM_IMP_OPEN_MAP",HOMEOMORPHISM_IMP_OPEN_MAP;
+"HOMEOMORPHISM_IMP_QUOTIENT_MAP",HOMEOMORPHISM_IMP_QUOTIENT_MAP;
+"HOMEOMORPHISM_INJECTIVE_CLOSED_MAP",HOMEOMORPHISM_INJECTIVE_CLOSED_MAP;
+"HOMEOMORPHISM_INJECTIVE_CLOSED_MAP_EQ",HOMEOMORPHISM_INJECTIVE_CLOSED_MAP_EQ;
+"HOMEOMORPHISM_INJECTIVE_OPEN_MAP",HOMEOMORPHISM_INJECTIVE_OPEN_MAP;
+"HOMEOMORPHISM_INJECTIVE_OPEN_MAP_EQ",HOMEOMORPHISM_INJECTIVE_OPEN_MAP_EQ;
+"HOMEOMORPHISM_LOCALLY",HOMEOMORPHISM_LOCALLY;
+"HOMEOMORPHISM_MOVING_POINTS_EXISTS",HOMEOMORPHISM_MOVING_POINTS_EXISTS;
+"HOMEOMORPHISM_MOVING_POINTS_EXISTS_GEN",HOMEOMORPHISM_MOVING_POINTS_EXISTS_GEN;
+"HOMEOMORPHISM_MOVING_POINT_EXISTS",HOMEOMORPHISM_MOVING_POINT_EXISTS;
+"HOMEOMORPHISM_OF_SUBSETS",HOMEOMORPHISM_OF_SUBSETS;
+"HOMEOMORPHISM_SYM",HOMEOMORPHISM_SYM;
+"HOMOGENEOUS_LINEAR_EQUATIONS_DET",HOMOGENEOUS_LINEAR_EQUATIONS_DET;
+"HOMOTOPICALLY_TRIVIAL_RETRACTION_GEN",HOMOTOPICALLY_TRIVIAL_RETRACTION_GEN;
+"HOMOTOPICALLY_TRIVIAL_RETRACTION_NULL_GEN",HOMOTOPICALLY_TRIVIAL_RETRACTION_NULL_GEN;
+"HOMOTOPIC_BORSUK_MAPS_IN_BOUNDED_COMPONENT",HOMOTOPIC_BORSUK_MAPS_IN_BOUNDED_COMPONENT;
+"HOMOTOPIC_CIRCLEMAPS_DIV",HOMOTOPIC_CIRCLEMAPS_DIV;
+"HOMOTOPIC_CIRCLEMAPS_DIV_1",HOMOTOPIC_CIRCLEMAPS_DIV_1;
+"HOMOTOPIC_CIRCLEMAPS_IMP_HOMOTOPIC_LOOPS",HOMOTOPIC_CIRCLEMAPS_IMP_HOMOTOPIC_LOOPS;
+"HOMOTOPIC_COMPOSE_CONTINUOUS_LEFT",HOMOTOPIC_COMPOSE_CONTINUOUS_LEFT;
+"HOMOTOPIC_COMPOSE_CONTINUOUS_RIGHT",HOMOTOPIC_COMPOSE_CONTINUOUS_RIGHT;
+"HOMOTOPIC_CONSTANT_MAPS",HOMOTOPIC_CONSTANT_MAPS;
+"HOMOTOPIC_FROM_CONTRACTIBLE",HOMOTOPIC_FROM_CONTRACTIBLE;
+"HOMOTOPIC_INTO_CONTRACTIBLE",HOMOTOPIC_INTO_CONTRACTIBLE;
+"HOMOTOPIC_JOIN_LEMMA",HOMOTOPIC_JOIN_LEMMA;
+"HOMOTOPIC_JOIN_SUBPATHS",HOMOTOPIC_JOIN_SUBPATHS;
+"HOMOTOPIC_LOOPS",HOMOTOPIC_LOOPS;
+"HOMOTOPIC_LOOPS_ADD_SYM",HOMOTOPIC_LOOPS_ADD_SYM;
+"HOMOTOPIC_LOOPS_CONJUGATE",HOMOTOPIC_LOOPS_CONJUGATE;
+"HOMOTOPIC_LOOPS_CONTINUOUS_IMAGE",HOMOTOPIC_LOOPS_CONTINUOUS_IMAGE;
+"HOMOTOPIC_LOOPS_EQ",HOMOTOPIC_LOOPS_EQ;
+"HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_CIRCLEMAPS",HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_CIRCLEMAPS;
+"HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_PATHS_NULL",HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_PATHS_NULL;
+"HOMOTOPIC_LOOPS_IMP_LOOP",HOMOTOPIC_LOOPS_IMP_LOOP;
+"HOMOTOPIC_LOOPS_IMP_PATH",HOMOTOPIC_LOOPS_IMP_PATH;
+"HOMOTOPIC_LOOPS_IMP_PATH_COMPONENT_VALUE",HOMOTOPIC_LOOPS_IMP_PATH_COMPONENT_VALUE;
+"HOMOTOPIC_LOOPS_IMP_SUBSET",HOMOTOPIC_LOOPS_IMP_SUBSET;
+"HOMOTOPIC_LOOPS_LINEAR",HOMOTOPIC_LOOPS_LINEAR;
+"HOMOTOPIC_LOOPS_NEARBY_EXPLICIT",HOMOTOPIC_LOOPS_NEARBY_EXPLICIT;
+"HOMOTOPIC_LOOPS_REFL",HOMOTOPIC_LOOPS_REFL;
+"HOMOTOPIC_LOOPS_SHIFTPATH",HOMOTOPIC_LOOPS_SHIFTPATH;
+"HOMOTOPIC_LOOPS_SHIFTPATH_SELF",HOMOTOPIC_LOOPS_SHIFTPATH_SELF;
+"HOMOTOPIC_LOOPS_SUBSET",HOMOTOPIC_LOOPS_SUBSET;
+"HOMOTOPIC_LOOPS_SYM",HOMOTOPIC_LOOPS_SYM;
+"HOMOTOPIC_LOOPS_TRANS",HOMOTOPIC_LOOPS_TRANS;
+"HOMOTOPIC_NEARBY_LOOPS",HOMOTOPIC_NEARBY_LOOPS;
+"HOMOTOPIC_NEARBY_PATHS",HOMOTOPIC_NEARBY_PATHS;
+"HOMOTOPIC_NON_ANTIPODAL_SPHEREMAPS",HOMOTOPIC_NON_ANTIPODAL_SPHEREMAPS;
+"HOMOTOPIC_NON_MIDPOINT_SPHEREMAPS",HOMOTOPIC_NON_MIDPOINT_SPHEREMAPS;
+"HOMOTOPIC_ORTHOGONAL_TRANSFORMATIONS",HOMOTOPIC_ORTHOGONAL_TRANSFORMATIONS;
+"HOMOTOPIC_PATHS",HOMOTOPIC_PATHS;
+"HOMOTOPIC_PATHS_ASSOC",HOMOTOPIC_PATHS_ASSOC;
+"HOMOTOPIC_PATHS_CONTINUOUS_IMAGE",HOMOTOPIC_PATHS_CONTINUOUS_IMAGE;
+"HOMOTOPIC_PATHS_EQ",HOMOTOPIC_PATHS_EQ;
+"HOMOTOPIC_PATHS_IMP_HOMOTOPIC_LOOPS",HOMOTOPIC_PATHS_IMP_HOMOTOPIC_LOOPS;
+"HOMOTOPIC_PATHS_IMP_PATH",HOMOTOPIC_PATHS_IMP_PATH;
+"HOMOTOPIC_PATHS_IMP_PATHFINISH",HOMOTOPIC_PATHS_IMP_PATHFINISH;
+"HOMOTOPIC_PATHS_IMP_PATHSTART",HOMOTOPIC_PATHS_IMP_PATHSTART;
+"HOMOTOPIC_PATHS_IMP_SUBSET",HOMOTOPIC_PATHS_IMP_SUBSET;
+"HOMOTOPIC_PATHS_JOIN",HOMOTOPIC_PATHS_JOIN;
+"HOMOTOPIC_PATHS_LID",HOMOTOPIC_PATHS_LID;
+"HOMOTOPIC_PATHS_LINEAR",HOMOTOPIC_PATHS_LINEAR;
+"HOMOTOPIC_PATHS_LINV",HOMOTOPIC_PATHS_LINV;
+"HOMOTOPIC_PATHS_LOOP_PARTS",HOMOTOPIC_PATHS_LOOP_PARTS;
+"HOMOTOPIC_PATHS_NEARBY_EXPLICIT",HOMOTOPIC_PATHS_NEARBY_EXPLICIT;
+"HOMOTOPIC_PATHS_REFL",HOMOTOPIC_PATHS_REFL;
+"HOMOTOPIC_PATHS_REPARAMETRIZE",HOMOTOPIC_PATHS_REPARAMETRIZE;
+"HOMOTOPIC_PATHS_REVERSEPATH",HOMOTOPIC_PATHS_REVERSEPATH;
+"HOMOTOPIC_PATHS_RID",HOMOTOPIC_PATHS_RID;
+"HOMOTOPIC_PATHS_RINV",HOMOTOPIC_PATHS_RINV;
+"HOMOTOPIC_PATHS_SUBSET",HOMOTOPIC_PATHS_SUBSET;
+"HOMOTOPIC_PATHS_SYM",HOMOTOPIC_PATHS_SYM;
+"HOMOTOPIC_PATHS_TRANS",HOMOTOPIC_PATHS_TRANS;
+"HOMOTOPIC_POINTS_EQ_PATH_COMPONENT",HOMOTOPIC_POINTS_EQ_PATH_COMPONENT;
+"HOMOTOPIC_SPECIAL_ORTHOGONAL_TRANSFORMATIONS",HOMOTOPIC_SPECIAL_ORTHOGONAL_TRANSFORMATIONS;
+"HOMOTOPIC_THROUGH_CONTRACTIBLE",HOMOTOPIC_THROUGH_CONTRACTIBLE;
+"HOMOTOPIC_TRIVIALITY",HOMOTOPIC_TRIVIALITY;
+"HOMOTOPIC_WITH",HOMOTOPIC_WITH;
+"HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT",HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT;
+"HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT",HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT;
+"HOMOTOPIC_WITH_EQ",HOMOTOPIC_WITH_EQ;
+"HOMOTOPIC_WITH_EQUAL",HOMOTOPIC_WITH_EQUAL;
+"HOMOTOPIC_WITH_IMP_CONTINUOUS",HOMOTOPIC_WITH_IMP_CONTINUOUS;
+"HOMOTOPIC_WITH_IMP_PROPERTY",HOMOTOPIC_WITH_IMP_PROPERTY;
+"HOMOTOPIC_WITH_IMP_SUBSET",HOMOTOPIC_WITH_IMP_SUBSET;
+"HOMOTOPIC_WITH_LINEAR",HOMOTOPIC_WITH_LINEAR;
+"HOMOTOPIC_WITH_MONO",HOMOTOPIC_WITH_MONO;
+"HOMOTOPIC_WITH_PCROSS",HOMOTOPIC_WITH_PCROSS;
+"HOMOTOPIC_WITH_REFL",HOMOTOPIC_WITH_REFL;
+"HOMOTOPIC_WITH_SUBSET_LEFT",HOMOTOPIC_WITH_SUBSET_LEFT;
+"HOMOTOPIC_WITH_SUBSET_RIGHT",HOMOTOPIC_WITH_SUBSET_RIGHT;
+"HOMOTOPIC_WITH_SYM",HOMOTOPIC_WITH_SYM;
+"HOMOTOPIC_WITH_TRANS",HOMOTOPIC_WITH_TRANS;
+"HOMOTOPY_EQUIVALENT",HOMOTOPY_EQUIVALENT;
+"HOMOTOPY_EQUIVALENT_COHOMOTOPIC_TRIVIALITY",HOMOTOPY_EQUIVALENT_COHOMOTOPIC_TRIVIALITY;
+"HOMOTOPY_EQUIVALENT_COHOMOTOPIC_TRIVIALITY_NULL",HOMOTOPY_EQUIVALENT_COHOMOTOPIC_TRIVIALITY_NULL;
+"HOMOTOPY_EQUIVALENT_CONNECTEDNESS",HOMOTOPY_EQUIVALENT_CONNECTEDNESS;
+"HOMOTOPY_EQUIVALENT_CONTRACTIBILITY",HOMOTOPY_EQUIVALENT_CONTRACTIBILITY;
+"HOMOTOPY_EQUIVALENT_CONTRACTIBLE_SETS",HOMOTOPY_EQUIVALENT_CONTRACTIBLE_SETS;
+"HOMOTOPY_EQUIVALENT_EMPTY",HOMOTOPY_EQUIVALENT_EMPTY;
+"HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY",HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY;
+"HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY_NULL",HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY_NULL;
+"HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_LEFT_EQ",HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_LEFT_EQ;
+"HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ",HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ;
+"HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_SELF",HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_SELF;
+"HOMOTOPY_EQUIVALENT_PATH_CONNECTEDNESS",HOMOTOPY_EQUIVALENT_PATH_CONNECTEDNESS;
+"HOMOTOPY_EQUIVALENT_REFL",HOMOTOPY_EQUIVALENT_REFL;
+"HOMOTOPY_EQUIVALENT_SEPARATION",HOMOTOPY_EQUIVALENT_SEPARATION;
+"HOMOTOPY_EQUIVALENT_SIMPLE_CONNECTEDNESS",HOMOTOPY_EQUIVALENT_SIMPLE_CONNECTEDNESS;
+"HOMOTOPY_EQUIVALENT_SING",HOMOTOPY_EQUIVALENT_SING;
+"HOMOTOPY_EQUIVALENT_SPHERES_EQ",HOMOTOPY_EQUIVALENT_SPHERES_EQ;
+"HOMOTOPY_EQUIVALENT_SYM",HOMOTOPY_EQUIVALENT_SYM;
+"HOMOTOPY_EQUIVALENT_TRANS",HOMOTOPY_EQUIVALENT_TRANS;
+"HOMOTOPY_EQUIVALENT_TRANSLATION_LEFT_EQ",HOMOTOPY_EQUIVALENT_TRANSLATION_LEFT_EQ;
+"HOMOTOPY_EQUIVALENT_TRANSLATION_RIGHT_EQ",HOMOTOPY_EQUIVALENT_TRANSLATION_RIGHT_EQ;
+"HOMOTOPY_EQUIVALENT_TRANSLATION_SELF",HOMOTOPY_EQUIVALENT_TRANSLATION_SELF;
+"HOMOTOPY_INVARIANT_CONNECTEDNESS",HOMOTOPY_INVARIANT_CONNECTEDNESS;
+"HOMOTOPY_INVARIANT_PATH_CONNECTEDNESS",HOMOTOPY_INVARIANT_PATH_CONNECTEDNESS;
+"HP",HP;
+"HREAL_ADD_AC",HREAL_ADD_AC;
+"HREAL_ADD_ASSOC",HREAL_ADD_ASSOC;
+"HREAL_ADD_LCANCEL",HREAL_ADD_LCANCEL;
+"HREAL_ADD_LDISTRIB",HREAL_ADD_LDISTRIB;
+"HREAL_ADD_LID",HREAL_ADD_LID;
+"HREAL_ADD_RDISTRIB",HREAL_ADD_RDISTRIB;
+"HREAL_ADD_RID",HREAL_ADD_RID;
+"HREAL_ADD_SYM",HREAL_ADD_SYM;
+"HREAL_ARCH",HREAL_ARCH;
+"HREAL_COMPLETE",HREAL_COMPLETE;
+"HREAL_EQ_ADD_LCANCEL",HREAL_EQ_ADD_LCANCEL;
+"HREAL_EQ_ADD_RCANCEL",HREAL_EQ_ADD_RCANCEL;
+"HREAL_INV_0",HREAL_INV_0;
+"HREAL_LE_ADD",HREAL_LE_ADD;
+"HREAL_LE_ADD2",HREAL_LE_ADD2;
+"HREAL_LE_ADD_LCANCEL",HREAL_LE_ADD_LCANCEL;
+"HREAL_LE_ADD_RCANCEL",HREAL_LE_ADD_RCANCEL;
+"HREAL_LE_ANTISYM",HREAL_LE_ANTISYM;
+"HREAL_LE_EXISTS",HREAL_LE_EXISTS;
+"HREAL_LE_EXISTS_DEF",HREAL_LE_EXISTS_DEF;
+"HREAL_LE_MUL_RCANCEL_IMP",HREAL_LE_MUL_RCANCEL_IMP;
+"HREAL_LE_REFL",HREAL_LE_REFL;
+"HREAL_LE_TOTAL",HREAL_LE_TOTAL;
+"HREAL_LE_TRANS",HREAL_LE_TRANS;
+"HREAL_MUL_ASSOC",HREAL_MUL_ASSOC;
+"HREAL_MUL_LID",HREAL_MUL_LID;
+"HREAL_MUL_LINV",HREAL_MUL_LINV;
+"HREAL_MUL_LZERO",HREAL_MUL_LZERO;
+"HREAL_MUL_RZERO",HREAL_MUL_RZERO;
+"HREAL_MUL_SYM",HREAL_MUL_SYM;
+"HREAL_OF_NUM_ADD",HREAL_OF_NUM_ADD;
+"HREAL_OF_NUM_EQ",HREAL_OF_NUM_EQ;
+"HREAL_OF_NUM_LE",HREAL_OF_NUM_LE;
+"HREAL_OF_NUM_MUL",HREAL_OF_NUM_MUL;
+"HULLS_EQ",HULLS_EQ;
+"HULL_ANTIMONO",HULL_ANTIMONO;
+"HULL_EQ",HULL_EQ;
+"HULL_HULL",HULL_HULL;
+"HULL_IMAGE",HULL_IMAGE;
+"HULL_IMAGE_GALOIS",HULL_IMAGE_GALOIS;
+"HULL_IMAGE_SUBSET",HULL_IMAGE_SUBSET;
+"HULL_INC",HULL_INC;
+"HULL_INDUCT",HULL_INDUCT;
+"HULL_MINIMAL",HULL_MINIMAL;
+"HULL_MONO",HULL_MONO;
+"HULL_P",HULL_P;
+"HULL_P_AND_Q",HULL_P_AND_Q;
+"HULL_REDUNDANT",HULL_REDUNDANT;
+"HULL_REDUNDANT_EQ",HULL_REDUNDANT_EQ;
+"HULL_SUBSET",HULL_SUBSET;
+"HULL_UNION",HULL_UNION;
+"HULL_UNION_LEFT",HULL_UNION_LEFT;
+"HULL_UNION_RIGHT",HULL_UNION_RIGHT;
+"HULL_UNION_SUBSET",HULL_UNION_SUBSET;
+"HULL_UNIQUE",HULL_UNIQUE;
+"HURWITZ_INJECTIVE",HURWITZ_INJECTIVE;
+"HURWITZ_NO_ZEROS",HURWITZ_NO_ZEROS;
+"HYPERPLANE_EQ_EMPTY",HYPERPLANE_EQ_EMPTY;
+"HYPERPLANE_EQ_UNIV",HYPERPLANE_EQ_UNIV;
+"HYPERPLANE_FACET_OF_HALFSPACE_GE",HYPERPLANE_FACET_OF_HALFSPACE_GE;
+"HYPERPLANE_FACET_OF_HALFSPACE_LE",HYPERPLANE_FACET_OF_HALFSPACE_LE;
+"HYPERPLANE_FACE_OF_HALFSPACE_GE",HYPERPLANE_FACE_OF_HALFSPACE_GE;
+"HYPERPLANE_FACE_OF_HALFSPACE_LE",HYPERPLANE_FACE_OF_HALFSPACE_LE;
+"IDEMPOTENT_IMP_RETRACTION",IDEMPOTENT_IMP_RETRACTION;
+"II_NZ",II_NZ;
+"IM",IM;
+"IMAGE",IMAGE;
+"IMAGE_AFFINITY_INTERVAL",IMAGE_AFFINITY_INTERVAL;
+"IMAGE_AFFINITY_REAL_INTERVAL",IMAGE_AFFINITY_REAL_INTERVAL;
+"IMAGE_CLAUSES",IMAGE_CLAUSES;
+"IMAGE_CLOSURE_SUBSET",IMAGE_CLOSURE_SUBSET;
+"IMAGE_COMPOSE_PERMUTATIONS_L",IMAGE_COMPOSE_PERMUTATIONS_L;
+"IMAGE_COMPOSE_PERMUTATIONS_R",IMAGE_COMPOSE_PERMUTATIONS_R;
+"IMAGE_CONST",IMAGE_CONST;
+"IMAGE_CX",IMAGE_CX;
+"IMAGE_DELETE_INJ",IMAGE_DELETE_INJ;
+"IMAGE_DIFF_INJ",IMAGE_DIFF_INJ;
+"IMAGE_DROPOUT_CLOSED_INTERVAL",IMAGE_DROPOUT_CLOSED_INTERVAL;
+"IMAGE_DROP_INTERVAL",IMAGE_DROP_INTERVAL;
+"IMAGE_DROP_UNIV",IMAGE_DROP_UNIV;
+"IMAGE_EQ_EMPTY",IMAGE_EQ_EMPTY;
+"IMAGE_FSTCART_PCROSS",IMAGE_FSTCART_PCROSS;
+"IMAGE_I",IMAGE_I;
+"IMAGE_ID",IMAGE_ID;
+"IMAGE_IMP_INJECTIVE",IMAGE_IMP_INJECTIVE;
+"IMAGE_IMP_INJECTIVE_GEN",IMAGE_IMP_INJECTIVE_GEN;
+"IMAGE_INJECTIVE_IMAGE_OF_SUBSET",IMAGE_INJECTIVE_IMAGE_OF_SUBSET;
+"IMAGE_INTER_INJ",IMAGE_INTER_INJ;
+"IMAGE_INVERSE_PERMUTATIONS",IMAGE_INVERSE_PERMUTATIONS;
+"IMAGE_LEMMA_0",IMAGE_LEMMA_0;
+"IMAGE_LEMMA_1",IMAGE_LEMMA_1;
+"IMAGE_LEMMA_2",IMAGE_LEMMA_2;
+"IMAGE_LIFT_DROP",IMAGE_LIFT_DROP;
+"IMAGE_LIFT_REAL_INTERVAL",IMAGE_LIFT_REAL_INTERVAL;
+"IMAGE_LIFT_REAL_SEGMENT",IMAGE_LIFT_REAL_SEGMENT;
+"IMAGE_LIFT_UNIV",IMAGE_LIFT_UNIV;
+"IMAGE_SNDCART_PCROSS",IMAGE_SNDCART_PCROSS;
+"IMAGE_STRETCH_INTERVAL",IMAGE_STRETCH_INTERVAL;
+"IMAGE_STRETCH_REAL_INTERVAL",IMAGE_STRETCH_REAL_INTERVAL;
+"IMAGE_SUBSET",IMAGE_SUBSET;
+"IMAGE_UNION",IMAGE_UNION;
+"IMAGE_UNIONS",IMAGE_UNIONS;
+"IMAGE_o",IMAGE_o;
+"IMP_CLAUSES",IMP_CLAUSES;
+"IMP_CONJ",IMP_CONJ;
+"IMP_CONJ_ALT",IMP_CONJ_ALT;
+"IMP_DEF",IMP_DEF;
+"IMP_IMP",IMP_IMP;
+"IM_ADD",IM_ADD;
+"IM_CCOS",IM_CCOS;
+"IM_CEXP",IM_CEXP;
+"IM_CLOG_EQ_0",IM_CLOG_EQ_0;
+"IM_CLOG_EQ_PI",IM_CLOG_EQ_PI;
+"IM_CLOG_POS_LE",IM_CLOG_POS_LE;
+"IM_CLOG_POS_LT",IM_CLOG_POS_LT;
+"IM_CLOG_POS_LT_IMP",IM_CLOG_POS_LT_IMP;
+"IM_CMUL",IM_CMUL;
+"IM_CNJ",IM_CNJ;
+"IM_COMPLEX_DIV_EQ_0",IM_COMPLEX_DIV_EQ_0;
+"IM_COMPLEX_DIV_GE_0",IM_COMPLEX_DIV_GE_0;
+"IM_COMPLEX_DIV_GT_0",IM_COMPLEX_DIV_GT_0;
+"IM_COMPLEX_DIV_LEMMA",IM_COMPLEX_DIV_LEMMA;
+"IM_COMPLEX_DIV_LE_0",IM_COMPLEX_DIV_LE_0;
+"IM_COMPLEX_DIV_LT_0",IM_COMPLEX_DIV_LT_0;
+"IM_COMPLEX_INV_EQ_0",IM_COMPLEX_INV_EQ_0;
+"IM_COMPLEX_INV_GE_0",IM_COMPLEX_INV_GE_0;
+"IM_COMPLEX_INV_GT_0",IM_COMPLEX_INV_GT_0;
+"IM_COMPLEX_INV_LE_0",IM_COMPLEX_INV_LE_0;
+"IM_COMPLEX_INV_LT_0",IM_COMPLEX_INV_LT_0;
+"IM_CSIN",IM_CSIN;
+"IM_CX",IM_CX;
+"IM_DEF",IM_DEF;
+"IM_DIV_CX",IM_DIV_CX;
+"IM_II",IM_II;
+"IM_LINEPATH_CX",IM_LINEPATH_CX;
+"IM_MUL_CX",IM_MUL_CX;
+"IM_MUL_II",IM_MUL_II;
+"IM_NEG",IM_NEG;
+"IM_POW_2",IM_POW_2;
+"IM_SUB",IM_SUB;
+"IM_VSUM",IM_VSUM;
+"IN",IN;
+"INCREASING_BOUNDED_REAL_VARIATION",INCREASING_BOUNDED_REAL_VARIATION;
+"INCREASING_BOUNDED_VARIATION",INCREASING_BOUNDED_VARIATION;
+"INCREASING_LEFT_LIMIT",INCREASING_LEFT_LIMIT;
+"INCREASING_LEFT_LIMIT_1",INCREASING_LEFT_LIMIT_1;
+"INCREASING_REAL_VARIATION",INCREASING_REAL_VARIATION;
+"INCREASING_RIGHT_LIMIT",INCREASING_RIGHT_LIMIT;
+"INCREASING_RIGHT_LIMIT_1",INCREASING_RIGHT_LIMIT_1;
+"INCREASING_VECTOR_VARIATION",INCREASING_VECTOR_VARIATION;
+"INDEFINITE_INTEGRAL_CONTINUOUS",INDEFINITE_INTEGRAL_CONTINUOUS;
+"INDEFINITE_INTEGRAL_CONTINUOUS_LEFT",INDEFINITE_INTEGRAL_CONTINUOUS_LEFT;
+"INDEFINITE_INTEGRAL_CONTINUOUS_RIGHT",INDEFINITE_INTEGRAL_CONTINUOUS_RIGHT;
+"INDEFINITE_INTEGRAL_UNIFORMLY_CONTINUOUS",INDEFINITE_INTEGRAL_UNIFORMLY_CONTINUOUS;
+"INDEFINITE_INTEGRAL_UNIFORMLY_CONTINUOUS_EXPLICIT",INDEFINITE_INTEGRAL_UNIFORMLY_CONTINUOUS_EXPLICIT;
+"INDEPENDENT_2",INDEPENDENT_2;
+"INDEPENDENT_3",INDEPENDENT_3;
+"INDEPENDENT_BOUND",INDEPENDENT_BOUND;
+"INDEPENDENT_BOUND_GENERAL",INDEPENDENT_BOUND_GENERAL;
+"INDEPENDENT_CARD_LE_DIM",INDEPENDENT_CARD_LE_DIM;
+"INDEPENDENT_EMPTY",INDEPENDENT_EMPTY;
+"INDEPENDENT_EXPLICIT",INDEPENDENT_EXPLICIT;
+"INDEPENDENT_IMP_AFFINE_DEPENDENT_0",INDEPENDENT_IMP_AFFINE_DEPENDENT_0;
+"INDEPENDENT_IMP_FINITE",INDEPENDENT_IMP_FINITE;
+"INDEPENDENT_INJECTIVE_IMAGE",INDEPENDENT_INJECTIVE_IMAGE;
+"INDEPENDENT_INJECTIVE_IMAGE_GEN",INDEPENDENT_INJECTIVE_IMAGE_GEN;
+"INDEPENDENT_INSERT",INDEPENDENT_INSERT;
+"INDEPENDENT_LINEAR_IMAGE_EQ",INDEPENDENT_LINEAR_IMAGE_EQ;
+"INDEPENDENT_MONO",INDEPENDENT_MONO;
+"INDEPENDENT_NONZERO",INDEPENDENT_NONZERO;
+"INDEPENDENT_SING",INDEPENDENT_SING;
+"INDEPENDENT_SPAN_BOUND",INDEPENDENT_SPAN_BOUND;
+"INDEPENDENT_STDBASIS",INDEPENDENT_STDBASIS;
+"INDUCT_LINEAR_ELEMENTARY",INDUCT_LINEAR_ELEMENTARY;
+"INDUCT_MATRIX_ELEMENTARY",INDUCT_MATRIX_ELEMENTARY;
+"INDUCT_MATRIX_ELEMENTARY_ALT",INDUCT_MATRIX_ELEMENTARY_ALT;
+"INDUCT_MATRIX_ROW_OPERATIONS",INDUCT_MATRIX_ROW_OPERATIONS;
+"IND_SUC_0",IND_SUC_0;
+"IND_SUC_0_EXISTS",IND_SUC_0_EXISTS;
+"IND_SUC_INJ",IND_SUC_INJ;
+"IND_SUC_SPEC",IND_SUC_SPEC;
+"INESSENTIAL_EQ_CONTINUOUS_LOGARITHM",INESSENTIAL_EQ_CONTINUOUS_LOGARITHM;
+"INESSENTIAL_EQ_CONTINUOUS_LOGARITHM_CIRCLE",INESSENTIAL_EQ_CONTINUOUS_LOGARITHM_CIRCLE;
+"INESSENTIAL_EQ_EXTENSIBLE",INESSENTIAL_EQ_EXTENSIBLE;
+"INESSENTIAL_IMP_CONTINUOUS_LOGARITHM_CIRCLE",INESSENTIAL_IMP_CONTINUOUS_LOGARITHM_CIRCLE;
+"INESSENTIAL_IMP_UNICOHERENT",INESSENTIAL_IMP_UNICOHERENT;
+"INESSENTIAL_SPHEREMAP_2",INESSENTIAL_SPHEREMAP_2;
+"INESSENTIAL_SPHEREMAP_LOWDIM",INESSENTIAL_SPHEREMAP_LOWDIM;
+"INESSENTIAL_SPHEREMAP_LOWDIM_GEN",INESSENTIAL_SPHEREMAP_LOWDIM_GEN;
+"INF",INF;
+"INFINITE",INFINITE;
+"INFINITE_ARC_IMAGE",INFINITE_ARC_IMAGE;
+"INFINITE_CARD_LE",INFINITE_CARD_LE;
+"INFINITE_DIFF_FINITE",INFINITE_DIFF_FINITE;
+"INFINITE_ENUMERATE",INFINITE_ENUMERATE;
+"INFINITE_FROM",INFINITE_FROM;
+"INFINITE_IMAGE_INJ",INFINITE_IMAGE_INJ;
+"INFINITE_INTEGER",INFINITE_INTEGER;
+"INFINITE_NONEMPTY",INFINITE_NONEMPTY;
+"INFINITE_OPEN_IN",INFINITE_OPEN_IN;
+"INFINITE_RATIONAL",INFINITE_RATIONAL;
+"INFINITE_SIMPLE_PATH_IMAGE",INFINITE_SIMPLE_PATH_IMAGE;
+"INFINITE_SUPERSET",INFINITE_SUPERSET;
+"INFINITY_AX",INFINITY_AX;
+"INFNORM_0",INFNORM_0;
+"INFNORM_2",INFNORM_2;
+"INFNORM_EQ_0",INFNORM_EQ_0;
+"INFNORM_EQ_1_2",INFNORM_EQ_1_2;
+"INFNORM_EQ_1_IMP",INFNORM_EQ_1_IMP;
+"INFNORM_LE_NORM",INFNORM_LE_NORM;
+"INFNORM_MUL",INFNORM_MUL;
+"INFNORM_MUL_LEMMA",INFNORM_MUL_LEMMA;
+"INFNORM_NEG",INFNORM_NEG;
+"INFNORM_POS_LE",INFNORM_POS_LE;
+"INFNORM_POS_LT",INFNORM_POS_LT;
+"INFNORM_SET_IMAGE",INFNORM_SET_IMAGE;
+"INFNORM_SET_LEMMA",INFNORM_SET_LEMMA;
+"INFNORM_SUB",INFNORM_SUB;
+"INFNORM_TRIANGLE",INFNORM_TRIANGLE;
+"INFSUM_0",INFSUM_0;
+"INFSUM_ADD",INFSUM_ADD;
+"INFSUM_CMUL",INFSUM_CMUL;
+"INFSUM_EQ",INFSUM_EQ;
+"INFSUM_LINEAR",INFSUM_LINEAR;
+"INFSUM_NEG",INFSUM_NEG;
+"INFSUM_RESTRICT",INFSUM_RESTRICT;
+"INFSUM_SUB",INFSUM_SUB;
+"INFSUM_UNIQUE",INFSUM_UNIQUE;
+"INF_EQ",INF_EQ;
+"INF_FINITE",INF_FINITE;
+"INF_FINITE_LEMMA",INF_FINITE_LEMMA;
+"INF_INSERT",INF_INSERT;
+"INF_INSERT_FINITE",INF_INSERT_FINITE;
+"INF_SING",INF_SING;
+"INF_UNIQUE_FINITE",INF_UNIQUE_FINITE;
+"INJ",INJ;
+"INJA",INJA;
+"INJA_INJ",INJA_INJ;
+"INJECTIVE_ALT",INJECTIVE_ALT;
+"INJECTIVE_EQ_1D_OPEN_MAP_UNIV",INJECTIVE_EQ_1D_OPEN_MAP_UNIV;
+"INJECTIVE_IMAGE",INJECTIVE_IMAGE;
+"INJECTIVE_IMP_ISOMETRIC",INJECTIVE_IMP_ISOMETRIC;
+"INJECTIVE_INTO_1D_EQ_HOMEOMORPHISM",INJECTIVE_INTO_1D_EQ_HOMEOMORPHISM;
+"INJECTIVE_INTO_1D_IMP_OPEN_MAP",INJECTIVE_INTO_1D_IMP_OPEN_MAP;
+"INJECTIVE_INTO_1D_IMP_OPEN_MAP_UNIV",INJECTIVE_INTO_1D_IMP_OPEN_MAP_UNIV;
+"INJECTIVE_INVERSE",INJECTIVE_INVERSE;
+"INJECTIVE_INVERSE_o",INJECTIVE_INVERSE_o;
+"INJECTIVE_LEFT_INVERSE",INJECTIVE_LEFT_INVERSE;
+"INJECTIVE_LEFT_INVERSE_NONEMPTY",INJECTIVE_LEFT_INVERSE_NONEMPTY;
+"INJECTIVE_MAP",INJECTIVE_MAP;
+"INJECTIVE_MAP_OPEN_IFF_CLOSED",INJECTIVE_MAP_OPEN_IFF_CLOSED;
+"INJECTIVE_ON_ALT",INJECTIVE_ON_ALT;
+"INJECTIVE_ON_IMAGE",INJECTIVE_ON_IMAGE;
+"INJECTIVE_ON_LEFT_INVERSE",INJECTIVE_ON_LEFT_INVERSE;
+"INJECTIVE_SCALING",INJECTIVE_SCALING;
+"INJF",INJF;
+"INJF_INJ",INJF_INJ;
+"INJN",INJN;
+"INJN_INJ",INJN_INJ;
+"INJP",INJP;
+"INJP_INJ",INJP_INJ;
+"INJ_INVERSE2",INJ_INVERSE2;
+"INNER_LADD",INNER_LADD;
+"INNER_LMUL",INNER_LMUL;
+"INNER_LNEG",INNER_LNEG;
+"INNER_LZERO",INNER_LZERO;
+"INNER_RADD",INNER_RADD;
+"INNER_RMUL",INNER_RMUL;
+"INNER_RNEG",INNER_RNEG;
+"INNER_RZERO",INNER_RZERO;
+"INSEG_LINSEG",INSEG_LINSEG;
+"INSEG_PROPER_SUBSET",INSEG_PROPER_SUBSET;
+"INSEG_PROPER_SUBSET_FL",INSEG_PROPER_SUBSET_FL;
+"INSEG_SUBSET",INSEG_SUBSET;
+"INSEG_SUBSET_FL",INSEG_SUBSET_FL;
+"INSEG_WOSET",INSEG_WOSET;
+"INSERT",INSERT;
+"INSERT_AC",INSERT_AC;
+"INSERT_COMM",INSERT_COMM;
+"INSERT_DEF",INSERT_DEF;
+"INSERT_DELETE",INSERT_DELETE;
+"INSERT_DIFF",INSERT_DIFF;
+"INSERT_INSERT",INSERT_INSERT;
+"INSERT_INTER",INSERT_INTER;
+"INSERT_SUBSET",INSERT_SUBSET;
+"INSERT_UNION",INSERT_UNION;
+"INSERT_UNION_EQ",INSERT_UNION_EQ;
+"INSERT_UNIV",INSERT_UNIV;
+"INSIDE_ARC_EMPTY",INSIDE_ARC_EMPTY;
+"INSIDE_BOUNDED_COMPLEMENT_CONNECTED_EMPTY",INSIDE_BOUNDED_COMPLEMENT_CONNECTED_EMPTY;
+"INSIDE_COMPLEMENT_UNBOUNDED_CONNECTED_EMPTY",INSIDE_COMPLEMENT_UNBOUNDED_CONNECTED_EMPTY;
+"INSIDE_CONNECTED_COMPONENT_LE",INSIDE_CONNECTED_COMPONENT_LE;
+"INSIDE_CONNECTED_COMPONENT_LT",INSIDE_CONNECTED_COMPONENT_LT;
+"INSIDE_CONVEX",INSIDE_CONVEX;
+"INSIDE_EMPTY",INSIDE_EMPTY;
+"INSIDE_EQ_OUTSIDE",INSIDE_EQ_OUTSIDE;
+"INSIDE_FRONTIER_EQ_INTERIOR",INSIDE_FRONTIER_EQ_INTERIOR;
+"INSIDE_INSIDE",INSIDE_INSIDE;
+"INSIDE_INSIDE_COMPACT_CONNECTED",INSIDE_INSIDE_COMPACT_CONNECTED;
+"INSIDE_INSIDE_EQ_EMPTY",INSIDE_INSIDE_EQ_EMPTY;
+"INSIDE_INSIDE_SUBSET",INSIDE_INSIDE_SUBSET;
+"INSIDE_INTER_OUTSIDE",INSIDE_INTER_OUTSIDE;
+"INSIDE_IN_COMPONENTS",INSIDE_IN_COMPONENTS;
+"INSIDE_LINEAR_IMAGE",INSIDE_LINEAR_IMAGE;
+"INSIDE_MONO",INSIDE_MONO;
+"INSIDE_NO_OVERLAP",INSIDE_NO_OVERLAP;
+"INSIDE_OF_TRIANGLE",INSIDE_OF_TRIANGLE;
+"INSIDE_OUTSIDE",INSIDE_OUTSIDE;
+"INSIDE_OUTSIDE_INTERSECT_CONNECTED",INSIDE_OUTSIDE_INTERSECT_CONNECTED;
+"INSIDE_OUTSIDE_UNIQUE",INSIDE_OUTSIDE_UNIQUE;
+"INSIDE_SAME_COMPONENT",INSIDE_SAME_COMPONENT;
+"INSIDE_SIMPLE_CURVE_IMP_CLOSED",INSIDE_SIMPLE_CURVE_IMP_CLOSED;
+"INSIDE_SUBSET",INSIDE_SUBSET;
+"INSIDE_TRANSLATION",INSIDE_TRANSLATION;
+"INSIDE_UNION_OUTSIDE",INSIDE_UNION_OUTSIDE;
+"INSIDE_UNIQUE",INSIDE_UNIQUE;
+"INTEGER_ABS",INTEGER_ABS;
+"INTEGER_ABS_MUL_EQ_1",INTEGER_ABS_MUL_EQ_1;
+"INTEGER_ADD",INTEGER_ADD;
+"INTEGER_ADD_EQ",INTEGER_ADD_EQ;
+"INTEGER_CASES",INTEGER_CASES;
+"INTEGER_CLOSED",INTEGER_CLOSED;
+"INTEGER_DET",INTEGER_DET;
+"INTEGER_EXISTS_BETWEEN",INTEGER_EXISTS_BETWEEN;
+"INTEGER_EXISTS_BETWEEN_ABS",INTEGER_EXISTS_BETWEEN_ABS;
+"INTEGER_EXISTS_BETWEEN_ABS_LT",INTEGER_EXISTS_BETWEEN_ABS_LT;
+"INTEGER_EXISTS_BETWEEN_ALT",INTEGER_EXISTS_BETWEEN_ALT;
+"INTEGER_EXISTS_BETWEEN_LT",INTEGER_EXISTS_BETWEEN_LT;
+"INTEGER_MUL",INTEGER_MUL;
+"INTEGER_NEG",INTEGER_NEG;
+"INTEGER_POS",INTEGER_POS;
+"INTEGER_POW",INTEGER_POW;
+"INTEGER_PRODUCT",INTEGER_PRODUCT;
+"INTEGER_ROUND",INTEGER_ROUND;
+"INTEGER_SIGN",INTEGER_SIGN;
+"INTEGER_SUB",INTEGER_SUB;
+"INTEGER_SUB_EQ",INTEGER_SUB_EQ;
+"INTEGER_SUM",INTEGER_SUM;
+"INTEGER_WINDING_NUMBER",INTEGER_WINDING_NUMBER;
+"INTEGER_WINDING_NUMBER_EQ",INTEGER_WINDING_NUMBER_EQ;
+"INTEGRABLE_0",INTEGRABLE_0;
+"INTEGRABLE_ADD",INTEGRABLE_ADD;
+"INTEGRABLE_AFFINITY",INTEGRABLE_AFFINITY;
+"INTEGRABLE_ALT",INTEGRABLE_ALT;
+"INTEGRABLE_ALT_SUBSET",INTEGRABLE_ALT_SUBSET;
+"INTEGRABLE_CAUCHY",INTEGRABLE_CAUCHY;
+"INTEGRABLE_CCONTINUOUS_EXPLICIT",INTEGRABLE_CCONTINUOUS_EXPLICIT;
+"INTEGRABLE_CCONTINUOUS_EXPLICIT_SYMMETRIC",INTEGRABLE_CCONTINUOUS_EXPLICIT_SYMMETRIC;
+"INTEGRABLE_CMUL",INTEGRABLE_CMUL;
+"INTEGRABLE_COMBINE",INTEGRABLE_COMBINE;
+"INTEGRABLE_COMBINE_DIVISION",INTEGRABLE_COMBINE_DIVISION;
+"INTEGRABLE_COMPONENTWISE",INTEGRABLE_COMPONENTWISE;
+"INTEGRABLE_CONST",INTEGRABLE_CONST;
+"INTEGRABLE_CONTINUOUS",INTEGRABLE_CONTINUOUS;
+"INTEGRABLE_DECREASING",INTEGRABLE_DECREASING;
+"INTEGRABLE_DECREASING_1",INTEGRABLE_DECREASING_1;
+"INTEGRABLE_DECREASING_PRODUCT",INTEGRABLE_DECREASING_PRODUCT;
+"INTEGRABLE_DECREASING_PRODUCT_UNIV",INTEGRABLE_DECREASING_PRODUCT_UNIV;
+"INTEGRABLE_EQ",INTEGRABLE_EQ;
+"INTEGRABLE_IMP_MEASURABLE",INTEGRABLE_IMP_MEASURABLE;
+"INTEGRABLE_IMP_REAL_MEASURABLE",INTEGRABLE_IMP_REAL_MEASURABLE;
+"INTEGRABLE_INCREASING",INTEGRABLE_INCREASING;
+"INTEGRABLE_INCREASING_1",INTEGRABLE_INCREASING_1;
+"INTEGRABLE_INCREASING_PRODUCT",INTEGRABLE_INCREASING_PRODUCT;
+"INTEGRABLE_INCREASING_PRODUCT_UNIV",INTEGRABLE_INCREASING_PRODUCT_UNIV;
+"INTEGRABLE_INTEGRAL",INTEGRABLE_INTEGRAL;
+"INTEGRABLE_LINEAR",INTEGRABLE_LINEAR;
+"INTEGRABLE_MIN_CONST_1",INTEGRABLE_MIN_CONST_1;
+"INTEGRABLE_NEG",INTEGRABLE_NEG;
+"INTEGRABLE_ON_ALL_INTERVALS_INTEGRABLE_BOUND",INTEGRABLE_ON_ALL_INTERVALS_INTEGRABLE_BOUND;
+"INTEGRABLE_ON_CONST",INTEGRABLE_ON_CONST;
+"INTEGRABLE_ON_EMPTY",INTEGRABLE_ON_EMPTY;
+"INTEGRABLE_ON_LITTLE_SUBINTERVALS",INTEGRABLE_ON_LITTLE_SUBINTERVALS;
+"INTEGRABLE_ON_NULL",INTEGRABLE_ON_NULL;
+"INTEGRABLE_ON_OPEN_INTERVAL",INTEGRABLE_ON_OPEN_INTERVAL;
+"INTEGRABLE_ON_REFL",INTEGRABLE_ON_REFL;
+"INTEGRABLE_ON_SUBDIVISION",INTEGRABLE_ON_SUBDIVISION;
+"INTEGRABLE_ON_SUBINTERVAL",INTEGRABLE_ON_SUBINTERVAL;
+"INTEGRABLE_ON_SUPERSET",INTEGRABLE_ON_SUPERSET;
+"INTEGRABLE_REFLECT",INTEGRABLE_REFLECT;
+"INTEGRABLE_RESTRICT",INTEGRABLE_RESTRICT;
+"INTEGRABLE_RESTRICT_INTER",INTEGRABLE_RESTRICT_INTER;
+"INTEGRABLE_RESTRICT_UNIV",INTEGRABLE_RESTRICT_UNIV;
+"INTEGRABLE_SPIKE",INTEGRABLE_SPIKE;
+"INTEGRABLE_SPIKE_FINITE",INTEGRABLE_SPIKE_FINITE;
+"INTEGRABLE_SPIKE_INTERIOR",INTEGRABLE_SPIKE_INTERIOR;
+"INTEGRABLE_SPIKE_SET",INTEGRABLE_SPIKE_SET;
+"INTEGRABLE_SPIKE_SET_EQ",INTEGRABLE_SPIKE_SET_EQ;
+"INTEGRABLE_SPLIT",INTEGRABLE_SPLIT;
+"INTEGRABLE_STRADDLE",INTEGRABLE_STRADDLE;
+"INTEGRABLE_STRADDLE_INTERVAL",INTEGRABLE_STRADDLE_INTERVAL;
+"INTEGRABLE_STRETCH",INTEGRABLE_STRETCH;
+"INTEGRABLE_SUB",INTEGRABLE_SUB;
+"INTEGRABLE_SUBINTERVAL",INTEGRABLE_SUBINTERVAL;
+"INTEGRABLE_SUBINTERVALS_IMP_MEASURABLE",INTEGRABLE_SUBINTERVALS_IMP_MEASURABLE;
+"INTEGRABLE_SUBINTERVALS_IMP_REAL_MEASURABLE",INTEGRABLE_SUBINTERVALS_IMP_REAL_MEASURABLE;
+"INTEGRABLE_UNIFORM_LIMIT",INTEGRABLE_UNIFORM_LIMIT;
+"INTEGRABLE_VSUM",INTEGRABLE_VSUM;
+"INTEGRAL_0",INTEGRAL_0;
+"INTEGRAL_ADD",INTEGRAL_ADD;
+"INTEGRAL_CMUL",INTEGRAL_CMUL;
+"INTEGRAL_COMBINE",INTEGRAL_COMBINE;
+"INTEGRAL_COMBINE_DIVISION_BOTTOMUP",INTEGRAL_COMBINE_DIVISION_BOTTOMUP;
+"INTEGRAL_COMBINE_DIVISION_TOPDOWN",INTEGRAL_COMBINE_DIVISION_TOPDOWN;
+"INTEGRAL_COMBINE_TAGGED_DIVISION_BOTTOMUP",INTEGRAL_COMBINE_TAGGED_DIVISION_BOTTOMUP;
+"INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN",INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN;
+"INTEGRAL_COMPONENT",INTEGRAL_COMPONENT;
+"INTEGRAL_COMPONENT_LBOUND",INTEGRAL_COMPONENT_LBOUND;
+"INTEGRAL_COMPONENT_LE",INTEGRAL_COMPONENT_LE;
+"INTEGRAL_COMPONENT_POS",INTEGRAL_COMPONENT_POS;
+"INTEGRAL_COMPONENT_UBOUND",INTEGRAL_COMPONENT_UBOUND;
+"INTEGRAL_CONST",INTEGRAL_CONST;
+"INTEGRAL_DIFF",INTEGRAL_DIFF;
+"INTEGRAL_DROP_LE",INTEGRAL_DROP_LE;
+"INTEGRAL_DROP_LE_MEASURABLE",INTEGRAL_DROP_LE_MEASURABLE;
+"INTEGRAL_DROP_POS",INTEGRAL_DROP_POS;
+"INTEGRAL_EMPTY",INTEGRAL_EMPTY;
+"INTEGRAL_EQ",INTEGRAL_EQ;
+"INTEGRAL_EQ_0",INTEGRAL_EQ_0;
+"INTEGRAL_EQ_HAS_INTEGRAL",INTEGRAL_EQ_HAS_INTEGRAL;
+"INTEGRAL_HAS_VECTOR_DERIVATIVE",INTEGRAL_HAS_VECTOR_DERIVATIVE;
+"INTEGRAL_INTERVALS_DIFF_INCLUSION_EXCLUSION",INTEGRAL_INTERVALS_DIFF_INCLUSION_EXCLUSION;
+"INTEGRAL_INTERVALS_INCLUSION_EXCLUSION",INTEGRAL_INTERVALS_INCLUSION_EXCLUSION;
+"INTEGRAL_INTERVALS_INCLUSION_EXCLUSION_LEFT",INTEGRAL_INTERVALS_INCLUSION_EXCLUSION_LEFT;
+"INTEGRAL_INTERVALS_INCLUSION_EXCLUSION_RIGHT",INTEGRAL_INTERVALS_INCLUSION_EXCLUSION_RIGHT;
+"INTEGRAL_LINEAR",INTEGRAL_LINEAR;
+"INTEGRAL_MEASURE",INTEGRAL_MEASURE;
+"INTEGRAL_MEASURE_UNIV",INTEGRAL_MEASURE_UNIV;
+"INTEGRAL_NEG",INTEGRAL_NEG;
+"INTEGRAL_NORM_BOUND_INTEGRAL",INTEGRAL_NORM_BOUND_INTEGRAL;
+"INTEGRAL_NORM_BOUND_INTEGRAL_COMPONENT",INTEGRAL_NORM_BOUND_INTEGRAL_COMPONENT;
+"INTEGRAL_NULL",INTEGRAL_NULL;
+"INTEGRAL_OPEN_INTERVAL",INTEGRAL_OPEN_INTERVAL;
+"INTEGRAL_PASTECART_CONST",INTEGRAL_PASTECART_CONST;
+"INTEGRAL_PASTECART_CONTINUOUS",INTEGRAL_PASTECART_CONTINUOUS;
+"INTEGRAL_REFL",INTEGRAL_REFL;
+"INTEGRAL_REFLECT",INTEGRAL_REFLECT;
+"INTEGRAL_RESTRICT",INTEGRAL_RESTRICT;
+"INTEGRAL_RESTRICT_INTER",INTEGRAL_RESTRICT_INTER;
+"INTEGRAL_RESTRICT_UNIV",INTEGRAL_RESTRICT_UNIV;
+"INTEGRAL_SPIKE",INTEGRAL_SPIKE;
+"INTEGRAL_SPIKE_SET",INTEGRAL_SPIKE_SET;
+"INTEGRAL_SPLIT",INTEGRAL_SPLIT;
+"INTEGRAL_SPLIT_SIGNED",INTEGRAL_SPLIT_SIGNED;
+"INTEGRAL_SUB",INTEGRAL_SUB;
+"INTEGRAL_SUBSET_COMPONENT_LE",INTEGRAL_SUBSET_COMPONENT_LE;
+"INTEGRAL_SUBSET_DROP_LE",INTEGRAL_SUBSET_DROP_LE;
+"INTEGRAL_SWAP_CONTINUOUS",INTEGRAL_SWAP_CONTINUOUS;
+"INTEGRAL_UNION",INTEGRAL_UNION;
+"INTEGRAL_UNIQUE",INTEGRAL_UNIQUE;
+"INTEGRAL_VSUM",INTEGRAL_VSUM;
+"INTER",INTER;
+"INTERIOR_BIJECTIVE_LINEAR_IMAGE",INTERIOR_BIJECTIVE_LINEAR_IMAGE;
+"INTERIOR_CBALL",INTERIOR_CBALL;
+"INTERIOR_CLOSED_EQ_EMPTY_AS_FRONTIER",INTERIOR_CLOSED_EQ_EMPTY_AS_FRONTIER;
+"INTERIOR_CLOSED_INTERVAL",INTERIOR_CLOSED_INTERVAL;
+"INTERIOR_CLOSED_UNION_EMPTY_INTERIOR",INTERIOR_CLOSED_UNION_EMPTY_INTERIOR;
+"INTERIOR_CLOSURE",INTERIOR_CLOSURE;
+"INTERIOR_CLOSURE_IDEMP",INTERIOR_CLOSURE_IDEMP;
+"INTERIOR_COMPLEMENT",INTERIOR_COMPLEMENT;
+"INTERIOR_CONVEX_HULL_3",INTERIOR_CONVEX_HULL_3;
+"INTERIOR_CONVEX_HULL_3_MINIMAL",INTERIOR_CONVEX_HULL_3_MINIMAL;
+"INTERIOR_CONVEX_HULL_EQ_EMPTY",INTERIOR_CONVEX_HULL_EQ_EMPTY;
+"INTERIOR_CONVEX_HULL_EXPLICIT",INTERIOR_CONVEX_HULL_EXPLICIT;
+"INTERIOR_CONVEX_HULL_EXPLICIT_MINIMAL",INTERIOR_CONVEX_HULL_EXPLICIT_MINIMAL;
+"INTERIOR_DIFF",INTERIOR_DIFF;
+"INTERIOR_EMPTY",INTERIOR_EMPTY;
+"INTERIOR_EQ",INTERIOR_EQ;
+"INTERIOR_EQ_EMPTY",INTERIOR_EQ_EMPTY;
+"INTERIOR_EQ_EMPTY_ALT",INTERIOR_EQ_EMPTY_ALT;
+"INTERIOR_FINITE_INTERS",INTERIOR_FINITE_INTERS;
+"INTERIOR_FRONTIER",INTERIOR_FRONTIER;
+"INTERIOR_FRONTIER_EMPTY",INTERIOR_FRONTIER_EMPTY;
+"INTERIOR_HALFSPACE_COMPONENT_GE",INTERIOR_HALFSPACE_COMPONENT_GE;
+"INTERIOR_HALFSPACE_COMPONENT_LE",INTERIOR_HALFSPACE_COMPONENT_LE;
+"INTERIOR_HALFSPACE_GE",INTERIOR_HALFSPACE_GE;
+"INTERIOR_HALFSPACE_LE",INTERIOR_HALFSPACE_LE;
+"INTERIOR_HYPERPLANE",INTERIOR_HYPERPLANE;
+"INTERIOR_IMAGE_SUBSET",INTERIOR_IMAGE_SUBSET;
+"INTERIOR_INJECTIVE_LINEAR_IMAGE",INTERIOR_INJECTIVE_LINEAR_IMAGE;
+"INTERIOR_INSIDE_FRONTIER",INTERIOR_INSIDE_FRONTIER;
+"INTERIOR_INTER",INTERIOR_INTER;
+"INTERIOR_INTERIOR",INTERIOR_INTERIOR;
+"INTERIOR_INTERS_SUBSET",INTERIOR_INTERS_SUBSET;
+"INTERIOR_INTERVAL",INTERIOR_INTERVAL;
+"INTERIOR_LIMIT_POINT",INTERIOR_LIMIT_POINT;
+"INTERIOR_MAXIMAL",INTERIOR_MAXIMAL;
+"INTERIOR_MAXIMAL_EQ",INTERIOR_MAXIMAL_EQ;
+"INTERIOR_NEGATIONS",INTERIOR_NEGATIONS;
+"INTERIOR_OF_TRIANGLE",INTERIOR_OF_TRIANGLE;
+"INTERIOR_OPEN",INTERIOR_OPEN;
+"INTERIOR_PCROSS",INTERIOR_PCROSS;
+"INTERIOR_SEGMENT",INTERIOR_SEGMENT;
+"INTERIOR_SIMPLEX_NONEMPTY",INTERIOR_SIMPLEX_NONEMPTY;
+"INTERIOR_SING",INTERIOR_SING;
+"INTERIOR_STANDARD_HYPERPLANE",INTERIOR_STANDARD_HYPERPLANE;
+"INTERIOR_STD_SIMPLEX",INTERIOR_STD_SIMPLEX;
+"INTERIOR_SUBSET",INTERIOR_SUBSET;
+"INTERIOR_SUBSET_RELATIVE_INTERIOR",INTERIOR_SUBSET_RELATIVE_INTERIOR;
+"INTERIOR_SUBSET_UNION_INTERVALS",INTERIOR_SUBSET_UNION_INTERVALS;
+"INTERIOR_SURJECTIVE_LINEAR_IMAGE",INTERIOR_SURJECTIVE_LINEAR_IMAGE;
+"INTERIOR_TRANSLATION",INTERIOR_TRANSLATION;
+"INTERIOR_UNIONS_OPEN_SUBSETS",INTERIOR_UNIONS_OPEN_SUBSETS;
+"INTERIOR_UNION_EQ_EMPTY",INTERIOR_UNION_EQ_EMPTY;
+"INTERIOR_UNIQUE",INTERIOR_UNIQUE;
+"INTERIOR_UNIV",INTERIOR_UNIV;
+"INTERS",INTERS;
+"INTERS_0",INTERS_0;
+"INTERS_1",INTERS_1;
+"INTERS_2",INTERS_2;
+"INTERS_FACES_FINITE_ALTBOUND",INTERS_FACES_FINITE_ALTBOUND;
+"INTERS_FACES_FINITE_BOUND",INTERS_FACES_FINITE_BOUND;
+"INTERS_GSPEC",INTERS_GSPEC;
+"INTERS_IMAGE",INTERS_IMAGE;
+"INTERS_INSERT",INTERS_INSERT;
+"INTERS_OVER_UNIONS",INTERS_OVER_UNIONS;
+"INTERS_UNION",INTERS_UNION;
+"INTERS_UNIONS",INTERS_UNIONS;
+"INTERVAL_BIJ_AFFINE",INTERVAL_BIJ_AFFINE;
+"INTERVAL_BIJ_BIJ",INTERVAL_BIJ_BIJ;
+"INTERVAL_BISECTION",INTERVAL_BISECTION;
+"INTERVAL_BISECTION_STEP",INTERVAL_BISECTION_STEP;
+"INTERVAL_BOUNDS_EMPTY_1",INTERVAL_BOUNDS_EMPTY_1;
+"INTERVAL_BOUNDS_NULL_1",INTERVAL_BOUNDS_NULL_1;
+"INTERVAL_CASES_1",INTERVAL_CASES_1;
+"INTERVAL_CONTAINS_COMPACT_NEIGHBOURHOOD",INTERVAL_CONTAINS_COMPACT_NEIGHBOURHOOD;
+"INTERVAL_DOUBLESPLIT",INTERVAL_DOUBLESPLIT;
+"INTERVAL_EQ_EMPTY",INTERVAL_EQ_EMPTY;
+"INTERVAL_EQ_EMPTY_1",INTERVAL_EQ_EMPTY_1;
+"INTERVAL_IMAGE_AFFINITY_INTERVAL",INTERVAL_IMAGE_AFFINITY_INTERVAL;
+"INTERVAL_IMAGE_STRETCH_INTERVAL",INTERVAL_IMAGE_STRETCH_INTERVAL;
+"INTERVAL_INTER_HYPERPLANE",INTERVAL_INTER_HYPERPLANE;
+"INTERVAL_LOWERBOUND",INTERVAL_LOWERBOUND;
+"INTERVAL_LOWERBOUND_1",INTERVAL_LOWERBOUND_1;
+"INTERVAL_NE_EMPTY",INTERVAL_NE_EMPTY;
+"INTERVAL_NE_EMPTY_1",INTERVAL_NE_EMPTY_1;
+"INTERVAL_OPEN_SUBSET_CLOSED",INTERVAL_OPEN_SUBSET_CLOSED;
+"INTERVAL_REAL_INTERVAL",INTERVAL_REAL_INTERVAL;
+"INTERVAL_SING",INTERVAL_SING;
+"INTERVAL_SPLIT",INTERVAL_SPLIT;
+"INTERVAL_SUBDIVISION",INTERVAL_SUBDIVISION;
+"INTERVAL_SUBSET_IS_INTERVAL",INTERVAL_SUBSET_IS_INTERVAL;
+"INTERVAL_TRANSLATION",INTERVAL_TRANSLATION;
+"INTERVAL_UPPERBOUND",INTERVAL_UPPERBOUND;
+"INTERVAL_UPPERBOUND_1",INTERVAL_UPPERBOUND_1;
+"INTER_ACI",INTER_ACI;
+"INTER_ASSOC",INTER_ASSOC;
+"INTER_COMM",INTER_COMM;
+"INTER_EMPTY",INTER_EMPTY;
+"INTER_IDEMPOT",INTER_IDEMPOT;
+"INTER_INTERIOR_UNIONS_INTERVALS",INTER_INTERIOR_UNIONS_INTERVALS;
+"INTER_INTERVAL",INTER_INTERVAL;
+"INTER_INTERVAL_1",INTER_INTERVAL_1;
+"INTER_INTERVAL_MIXED_EQ_EMPTY",INTER_INTERVAL_MIXED_EQ_EMPTY;
+"INTER_OVER_UNION",INTER_OVER_UNION;
+"INTER_SEGMENT",INTER_SEGMENT;
+"INTER_SUBSET",INTER_SUBSET;
+"INTER_UNIONS",INTER_UNIONS;
+"INTER_UNIV",INTER_UNIV;
+"INT_ABS",INT_ABS;
+"INT_ABS_0",INT_ABS_0;
+"INT_ABS_1",INT_ABS_1;
+"INT_ABS_ABS",INT_ABS_ABS;
+"INT_ABS_BETWEEN",INT_ABS_BETWEEN;
+"INT_ABS_BETWEEN1",INT_ABS_BETWEEN1;
+"INT_ABS_BETWEEN2",INT_ABS_BETWEEN2;
+"INT_ABS_BOUND",INT_ABS_BOUND;
+"INT_ABS_CASES",INT_ABS_CASES;
+"INT_ABS_CIRCLE",INT_ABS_CIRCLE;
+"INT_ABS_LE",INT_ABS_LE;
+"INT_ABS_MUL",INT_ABS_MUL;
+"INT_ABS_MUL_1",INT_ABS_MUL_1;
+"INT_ABS_NEG",INT_ABS_NEG;
+"INT_ABS_NUM",INT_ABS_NUM;
+"INT_ABS_NZ",INT_ABS_NZ;
+"INT_ABS_POS",INT_ABS_POS;
+"INT_ABS_POW",INT_ABS_POW;
+"INT_ABS_REFL",INT_ABS_REFL;
+"INT_ABS_SGN",INT_ABS_SGN;
+"INT_ABS_SIGN",INT_ABS_SIGN;
+"INT_ABS_SIGN2",INT_ABS_SIGN2;
+"INT_ABS_STILLNZ",INT_ABS_STILLNZ;
+"INT_ABS_SUB",INT_ABS_SUB;
+"INT_ABS_SUB_ABS",INT_ABS_SUB_ABS;
+"INT_ABS_TRIANGLE",INT_ABS_TRIANGLE;
+"INT_ABS_ZERO",INT_ABS_ZERO;
+"INT_ADD2_SUB2",INT_ADD2_SUB2;
+"INT_ADD_AC",INT_ADD_AC;
+"INT_ADD_ASSOC",INT_ADD_ASSOC;
+"INT_ADD_LDISTRIB",INT_ADD_LDISTRIB;
+"INT_ADD_LID",INT_ADD_LID;
+"INT_ADD_LINV",INT_ADD_LINV;
+"INT_ADD_RDISTRIB",INT_ADD_RDISTRIB;
+"INT_ADD_RID",INT_ADD_RID;
+"INT_ADD_RINV",INT_ADD_RINV;
+"INT_ADD_SUB",INT_ADD_SUB;
+"INT_ADD_SUB2",INT_ADD_SUB2;
+"INT_ADD_SYM",INT_ADD_SYM;
+"INT_ARCH",INT_ARCH;
+"INT_BOUNDS_LE",INT_BOUNDS_LE;
+"INT_BOUNDS_LT",INT_BOUNDS_LT;
+"INT_DIFFSQ",INT_DIFFSQ;
+"INT_DIVISION",INT_DIVISION;
+"INT_DIVISION_0",INT_DIVISION_0;
+"INT_DIVMOD_EXIST_0",INT_DIVMOD_EXIST_0;
+"INT_DIVMOD_UNIQ",INT_DIVMOD_UNIQ;
+"INT_ENTIRE",INT_ENTIRE;
+"INT_EQ_ADD_LCANCEL",INT_EQ_ADD_LCANCEL;
+"INT_EQ_ADD_LCANCEL_0",INT_EQ_ADD_LCANCEL_0;
+"INT_EQ_ADD_RCANCEL",INT_EQ_ADD_RCANCEL;
+"INT_EQ_ADD_RCANCEL_0",INT_EQ_ADD_RCANCEL_0;
+"INT_EQ_IMP_LE",INT_EQ_IMP_LE;
+"INT_EQ_MUL_LCANCEL",INT_EQ_MUL_LCANCEL;
+"INT_EQ_MUL_RCANCEL",INT_EQ_MUL_RCANCEL;
+"INT_EQ_NEG2",INT_EQ_NEG2;
+"INT_EQ_SQUARE_ABS",INT_EQ_SQUARE_ABS;
+"INT_EQ_SUB_LADD",INT_EQ_SUB_LADD;
+"INT_EQ_SUB_RADD",INT_EQ_SUB_RADD;
+"INT_EXISTS_ABS",INT_EXISTS_ABS;
+"INT_EXISTS_POS",INT_EXISTS_POS;
+"INT_FORALL_ABS",INT_FORALL_ABS;
+"INT_FORALL_POS",INT_FORALL_POS;
+"INT_GCD_EXISTS",INT_GCD_EXISTS;
+"INT_GCD_EXISTS_POS",INT_GCD_EXISTS_POS;
+"INT_GE",INT_GE;
+"INT_GT",INT_GT;
+"INT_GT_DISCRETE",INT_GT_DISCRETE;
+"INT_IMAGE",INT_IMAGE;
+"INT_LET_ADD",INT_LET_ADD;
+"INT_LET_ADD2",INT_LET_ADD2;
+"INT_LET_ANTISYM",INT_LET_ANTISYM;
+"INT_LET_TOTAL",INT_LET_TOTAL;
+"INT_LET_TRANS",INT_LET_TRANS;
+"INT_LE_01",INT_LE_01;
+"INT_LE_ADD",INT_LE_ADD;
+"INT_LE_ADD2",INT_LE_ADD2;
+"INT_LE_ADDL",INT_LE_ADDL;
+"INT_LE_ADDR",INT_LE_ADDR;
+"INT_LE_ANTISYM",INT_LE_ANTISYM;
+"INT_LE_DOUBLE",INT_LE_DOUBLE;
+"INT_LE_LADD",INT_LE_LADD;
+"INT_LE_LADD_IMP",INT_LE_LADD_IMP;
+"INT_LE_LMUL",INT_LE_LMUL;
+"INT_LE_LNEG",INT_LE_LNEG;
+"INT_LE_LT",INT_LE_LT;
+"INT_LE_MAX",INT_LE_MAX;
+"INT_LE_MIN",INT_LE_MIN;
+"INT_LE_MUL",INT_LE_MUL;
+"INT_LE_MUL_EQ",INT_LE_MUL_EQ;
+"INT_LE_NEG",INT_LE_NEG;
+"INT_LE_NEG2",INT_LE_NEG2;
+"INT_LE_NEGL",INT_LE_NEGL;
+"INT_LE_NEGR",INT_LE_NEGR;
+"INT_LE_NEGTOTAL",INT_LE_NEGTOTAL;
+"INT_LE_POW2",INT_LE_POW2;
+"INT_LE_RADD",INT_LE_RADD;
+"INT_LE_REFL",INT_LE_REFL;
+"INT_LE_RMUL",INT_LE_RMUL;
+"INT_LE_RNEG",INT_LE_RNEG;
+"INT_LE_SQUARE",INT_LE_SQUARE;
+"INT_LE_SQUARE_ABS",INT_LE_SQUARE_ABS;
+"INT_LE_SUB_LADD",INT_LE_SUB_LADD;
+"INT_LE_SUB_RADD",INT_LE_SUB_RADD;
+"INT_LE_TOTAL",INT_LE_TOTAL;
+"INT_LE_TRANS",INT_LE_TRANS;
+"INT_LNEG_UNIQ",INT_LNEG_UNIQ;
+"INT_LT",INT_LT;
+"INT_LTE_ADD",INT_LTE_ADD;
+"INT_LTE_ADD2",INT_LTE_ADD2;
+"INT_LTE_ANTISYM",INT_LTE_ANTISYM;
+"INT_LTE_TOTAL",INT_LTE_TOTAL;
+"INT_LTE_TRANS",INT_LTE_TRANS;
+"INT_LT_01",INT_LT_01;
+"INT_LT_ADD",INT_LT_ADD;
+"INT_LT_ADD1",INT_LT_ADD1;
+"INT_LT_ADD2",INT_LT_ADD2;
+"INT_LT_ADDL",INT_LT_ADDL;
+"INT_LT_ADDNEG",INT_LT_ADDNEG;
+"INT_LT_ADDNEG2",INT_LT_ADDNEG2;
+"INT_LT_ADDR",INT_LT_ADDR;
+"INT_LT_ADD_SUB",INT_LT_ADD_SUB;
+"INT_LT_ANTISYM",INT_LT_ANTISYM;
+"INT_LT_DISCRETE",INT_LT_DISCRETE;
+"INT_LT_GT",INT_LT_GT;
+"INT_LT_IMP_LE",INT_LT_IMP_LE;
+"INT_LT_IMP_NE",INT_LT_IMP_NE;
+"INT_LT_LADD",INT_LT_LADD;
+"INT_LT_LE",INT_LT_LE;
+"INT_LT_LMUL_EQ",INT_LT_LMUL_EQ;
+"INT_LT_MAX",INT_LT_MAX;
+"INT_LT_MIN",INT_LT_MIN;
+"INT_LT_MUL",INT_LT_MUL;
+"INT_LT_MUL_EQ",INT_LT_MUL_EQ;
+"INT_LT_NEG",INT_LT_NEG;
+"INT_LT_NEG2",INT_LT_NEG2;
+"INT_LT_NEGTOTAL",INT_LT_NEGTOTAL;
+"INT_LT_POW2",INT_LT_POW2;
+"INT_LT_RADD",INT_LT_RADD;
+"INT_LT_REFL",INT_LT_REFL;
+"INT_LT_RMUL_EQ",INT_LT_RMUL_EQ;
+"INT_LT_SQUARE_ABS",INT_LT_SQUARE_ABS;
+"INT_LT_SUB_LADD",INT_LT_SUB_LADD;
+"INT_LT_SUB_RADD",INT_LT_SUB_RADD;
+"INT_LT_TOTAL",INT_LT_TOTAL;
+"INT_LT_TRANS",INT_LT_TRANS;
+"INT_MAX",INT_MAX;
+"INT_MAX_ACI",INT_MAX_ACI;
+"INT_MAX_ASSOC",INT_MAX_ASSOC;
+"INT_MAX_LE",INT_MAX_LE;
+"INT_MAX_LT",INT_MAX_LT;
+"INT_MAX_MAX",INT_MAX_MAX;
+"INT_MAX_MIN",INT_MAX_MIN;
+"INT_MAX_SYM",INT_MAX_SYM;
+"INT_MIN",INT_MIN;
+"INT_MIN_ACI",INT_MIN_ACI;
+"INT_MIN_ASSOC",INT_MIN_ASSOC;
+"INT_MIN_LE",INT_MIN_LE;
+"INT_MIN_LT",INT_MIN_LT;
+"INT_MIN_MAX",INT_MIN_MAX;
+"INT_MIN_MIN",INT_MIN_MIN;
+"INT_MIN_SYM",INT_MIN_SYM;
+"INT_MUL_AC",INT_MUL_AC;
+"INT_MUL_ASSOC",INT_MUL_ASSOC;
+"INT_MUL_LID",INT_MUL_LID;
+"INT_MUL_LNEG",INT_MUL_LNEG;
+"INT_MUL_LZERO",INT_MUL_LZERO;
+"INT_MUL_POS_LE",INT_MUL_POS_LE;
+"INT_MUL_POS_LT",INT_MUL_POS_LT;
+"INT_MUL_RID",INT_MUL_RID;
+"INT_MUL_RNEG",INT_MUL_RNEG;
+"INT_MUL_RZERO",INT_MUL_RZERO;
+"INT_MUL_SYM",INT_MUL_SYM;
+"INT_NEGNEG",INT_NEGNEG;
+"INT_NEG_0",INT_NEG_0;
+"INT_NEG_ADD",INT_NEG_ADD;
+"INT_NEG_EQ",INT_NEG_EQ;
+"INT_NEG_EQ_0",INT_NEG_EQ_0;
+"INT_NEG_GE0",INT_NEG_GE0;
+"INT_NEG_GT0",INT_NEG_GT0;
+"INT_NEG_LE0",INT_NEG_LE0;
+"INT_NEG_LMUL",INT_NEG_LMUL;
+"INT_NEG_LT0",INT_NEG_LT0;
+"INT_NEG_MINUS1",INT_NEG_MINUS1;
+"INT_NEG_MUL2",INT_NEG_MUL2;
+"INT_NEG_NEG",INT_NEG_NEG;
+"INT_NEG_RMUL",INT_NEG_RMUL;
+"INT_NEG_SUB",INT_NEG_SUB;
+"INT_NOT_EQ",INT_NOT_EQ;
+"INT_NOT_LE",INT_NOT_LE;
+"INT_NOT_LT",INT_NOT_LT;
+"INT_OF_NUM_ADD",INT_OF_NUM_ADD;
+"INT_OF_NUM_EQ",INT_OF_NUM_EQ;
+"INT_OF_NUM_EXISTS",INT_OF_NUM_EXISTS;
+"INT_OF_NUM_GE",INT_OF_NUM_GE;
+"INT_OF_NUM_GT",INT_OF_NUM_GT;
+"INT_OF_NUM_LE",INT_OF_NUM_LE;
+"INT_OF_NUM_LT",INT_OF_NUM_LT;
+"INT_OF_NUM_MAX",INT_OF_NUM_MAX;
+"INT_OF_NUM_MIN",INT_OF_NUM_MIN;
+"INT_OF_NUM_MUL",INT_OF_NUM_MUL;
+"INT_OF_NUM_OF_INT",INT_OF_NUM_OF_INT;
+"INT_OF_NUM_POW",INT_OF_NUM_POW;
+"INT_OF_NUM_SUB",INT_OF_NUM_SUB;
+"INT_OF_NUM_SUC",INT_OF_NUM_SUC;
+"INT_OF_REAL_OF_INT",INT_OF_REAL_OF_INT;
+"INT_POS",INT_POS;
+"INT_POS_NZ",INT_POS_NZ;
+"INT_POW",INT_POW;
+"INT_POW2_ABS",INT_POW2_ABS;
+"INT_POW_1",INT_POW_1;
+"INT_POW_1_LE",INT_POW_1_LE;
+"INT_POW_1_LT",INT_POW_1_LT;
+"INT_POW_2",INT_POW_2;
+"INT_POW_ADD",INT_POW_ADD;
+"INT_POW_EQ",INT_POW_EQ;
+"INT_POW_EQ_0",INT_POW_EQ_0;
+"INT_POW_EQ_ABS",INT_POW_EQ_ABS;
+"INT_POW_LE",INT_POW_LE;
+"INT_POW_LE2",INT_POW_LE2;
+"INT_POW_LE2_ODD",INT_POW_LE2_ODD;
+"INT_POW_LE2_REV",INT_POW_LE2_REV;
+"INT_POW_LE_1",INT_POW_LE_1;
+"INT_POW_LT",INT_POW_LT;
+"INT_POW_LT2",INT_POW_LT2;
+"INT_POW_LT2_REV",INT_POW_LT2_REV;
+"INT_POW_LT_1",INT_POW_LT_1;
+"INT_POW_MONO",INT_POW_MONO;
+"INT_POW_MONO_LT",INT_POW_MONO_LT;
+"INT_POW_MUL",INT_POW_MUL;
+"INT_POW_NEG",INT_POW_NEG;
+"INT_POW_NZ",INT_POW_NZ;
+"INT_POW_ONE",INT_POW_ONE;
+"INT_POW_POW",INT_POW_POW;
+"INT_POW_ZERO",INT_POW_ZERO;
+"INT_RNEG_UNIQ",INT_RNEG_UNIQ;
+"INT_SGN",INT_SGN;
+"INT_SGN_0",INT_SGN_0;
+"INT_SGN_ABS",INT_SGN_ABS;
+"INT_SGN_CASES",INT_SGN_CASES;
+"INT_SGN_EQ",INT_SGN_EQ;
+"INT_SGN_INEQS",INT_SGN_INEQS;
+"INT_SGN_MUL",INT_SGN_MUL;
+"INT_SGN_NEG",INT_SGN_NEG;
+"INT_SOS_EQ_0",INT_SOS_EQ_0;
+"INT_SUB",INT_SUB;
+"INT_SUB_0",INT_SUB_0;
+"INT_SUB_ABS",INT_SUB_ABS;
+"INT_SUB_ADD",INT_SUB_ADD;
+"INT_SUB_ADD2",INT_SUB_ADD2;
+"INT_SUB_LDISTRIB",INT_SUB_LDISTRIB;
+"INT_SUB_LE",INT_SUB_LE;
+"INT_SUB_LNEG",INT_SUB_LNEG;
+"INT_SUB_LT",INT_SUB_LT;
+"INT_SUB_LZERO",INT_SUB_LZERO;
+"INT_SUB_NEG2",INT_SUB_NEG2;
+"INT_SUB_RDISTRIB",INT_SUB_RDISTRIB;
+"INT_SUB_REFL",INT_SUB_REFL;
+"INT_SUB_RNEG",INT_SUB_RNEG;
+"INT_SUB_RZERO",INT_SUB_RZERO;
+"INT_SUB_SUB",INT_SUB_SUB;
+"INT_SUB_SUB2",INT_SUB_SUB2;
+"INT_SUB_TRIANGLE",INT_SUB_TRIANGLE;
+"INT_WOP",INT_WOP;
+"INVARIANCE_OF_DIMENSION",INVARIANCE_OF_DIMENSION;
+"INVARIANCE_OF_DIMENSION_AFFINE_SETS",INVARIANCE_OF_DIMENSION_AFFINE_SETS;
+"INVARIANCE_OF_DIMENSION_CONVEX_DOMAIN",INVARIANCE_OF_DIMENSION_CONVEX_DOMAIN;
+"INVARIANCE_OF_DIMENSION_SUBSPACES",INVARIANCE_OF_DIMENSION_SUBSPACES;
+"INVARIANCE_OF_DOMAIN",INVARIANCE_OF_DOMAIN;
+"INVARIANCE_OF_DOMAIN_AFFINE_SETS",INVARIANCE_OF_DOMAIN_AFFINE_SETS;
+"INVARIANCE_OF_DOMAIN_GEN",INVARIANCE_OF_DOMAIN_GEN;
+"INVARIANCE_OF_DOMAIN_HOMEOMORPHIC",INVARIANCE_OF_DOMAIN_HOMEOMORPHIC;
+"INVARIANCE_OF_DOMAIN_HOMEOMORPHISM",INVARIANCE_OF_DOMAIN_HOMEOMORPHISM;
+"INVARIANCE_OF_DOMAIN_SPHERE_AFFINE_SET",INVARIANCE_OF_DOMAIN_SPHERE_AFFINE_SET;
+"INVARIANCE_OF_DOMAIN_SPHERE_AFFINE_SET_GEN",INVARIANCE_OF_DOMAIN_SPHERE_AFFINE_SET_GEN;
+"INVARIANCE_OF_DOMAIN_SUBSPACES",INVARIANCE_OF_DOMAIN_SUBSPACES;
+"INVERSE_I",INVERSE_I;
+"INVERSE_SWAP",INVERSE_SWAP;
+"INVERSE_UNIQUE_o",INVERSE_UNIQUE_o;
+"INVERTIBLE_COFACTOR",INVERTIBLE_COFACTOR;
+"INVERTIBLE_DET_NZ",INVERTIBLE_DET_NZ;
+"INVERTIBLE_FIXPOINT_PROPERTY",INVERTIBLE_FIXPOINT_PROPERTY;
+"INVERTIBLE_IMP_SQUARE_MATRIX",INVERTIBLE_IMP_SQUARE_MATRIX;
+"INVERTIBLE_LEFT_INVERSE",INVERTIBLE_LEFT_INVERSE;
+"INVERTIBLE_MATRIX_MUL",INVERTIBLE_MATRIX_MUL;
+"INVERTIBLE_NEG",INVERTIBLE_NEG;
+"INVERTIBLE_RIGHT_INVERSE",INVERTIBLE_RIGHT_INVERSE;
+"INVERTIBLE_TRANSP",INVERTIBLE_TRANSP;
+"IN_AFFINE_ADD_MUL",IN_AFFINE_ADD_MUL;
+"IN_AFFINE_ADD_MUL_DIFF",IN_AFFINE_ADD_MUL_DIFF;
+"IN_AFFINE_HULL_LINEAR_IMAGE",IN_AFFINE_HULL_LINEAR_IMAGE;
+"IN_AFFINE_MUL_DIFF_ADD",IN_AFFINE_MUL_DIFF_ADD;
+"IN_AFFINE_SUB_MUL_DIFF",IN_AFFINE_SUB_MUL_DIFF;
+"IN_BALL",IN_BALL;
+"IN_BALL_0",IN_BALL_0;
+"IN_BALL_IM",IN_BALL_IM;
+"IN_BALL_RE",IN_BALL_RE;
+"IN_CARD_ADD",IN_CARD_ADD;
+"IN_CARD_MUL",IN_CARD_MUL;
+"IN_CBALL",IN_CBALL;
+"IN_CBALL_0",IN_CBALL_0;
+"IN_CBALL_IM",IN_CBALL_IM;
+"IN_CBALL_RE",IN_CBALL_RE;
+"IN_CLOSURE_CONNECTED_COMPONENT",IN_CLOSURE_CONNECTED_COMPONENT;
+"IN_CLOSURE_DELETE",IN_CLOSURE_DELETE;
+"IN_COMPONENTS",IN_COMPONENTS;
+"IN_COMPONENTS_CONNECTED",IN_COMPONENTS_CONNECTED;
+"IN_COMPONENTS_MAXIMAL",IN_COMPONENTS_MAXIMAL;
+"IN_COMPONENTS_NONEMPTY",IN_COMPONENTS_NONEMPTY;
+"IN_COMPONENTS_SELF",IN_COMPONENTS_SELF;
+"IN_COMPONENTS_SUBSET",IN_COMPONENTS_SUBSET;
+"IN_CONVEX_HULL_EXCHANGE",IN_CONVEX_HULL_EXCHANGE;
+"IN_CONVEX_HULL_EXCHANGE_UNIQUE",IN_CONVEX_HULL_EXCHANGE_UNIQUE;
+"IN_CONVEX_HULL_LINEAR_IMAGE",IN_CONVEX_HULL_LINEAR_IMAGE;
+"IN_CONVEX_SET",IN_CONVEX_SET;
+"IN_CROSS",IN_CROSS;
+"IN_DELETE",IN_DELETE;
+"IN_DELETE_EQ",IN_DELETE_EQ;
+"IN_DIFF",IN_DIFF;
+"IN_DIMINDEX_SWAP",IN_DIMINDEX_SWAP;
+"IN_DIRECTION",IN_DIRECTION;
+"IN_DISJOINT",IN_DISJOINT;
+"IN_ELIM_PAIR_THM",IN_ELIM_PAIR_THM;
+"IN_ELIM_PASTECART_THM",IN_ELIM_PASTECART_THM;
+"IN_ELIM_THM",IN_ELIM_THM;
+"IN_EPIGRAPH",IN_EPIGRAPH;
+"IN_FROM",IN_FROM;
+"IN_FRONTIER_CONVEX_HULL",IN_FRONTIER_CONVEX_HULL;
+"IN_IMAGE",IN_IMAGE;
+"IN_IMAGE_DROPOUT",IN_IMAGE_DROPOUT;
+"IN_IMAGE_LIFT_DROP",IN_IMAGE_LIFT_DROP;
+"IN_INSERT",IN_INSERT;
+"IN_INTER",IN_INTER;
+"IN_INTERIOR",IN_INTERIOR;
+"IN_INTERIOR_CBALL",IN_INTERIOR_CBALL;
+"IN_INTERIOR_CLOSURE_CONVEX_SEGMENT",IN_INTERIOR_CLOSURE_CONVEX_SEGMENT;
+"IN_INTERIOR_CLOSURE_CONVEX_SHRINK",IN_INTERIOR_CLOSURE_CONVEX_SHRINK;
+"IN_INTERIOR_CONVEX_SHRINK",IN_INTERIOR_CONVEX_SHRINK;
+"IN_INTERIOR_LINEAR_IMAGE",IN_INTERIOR_LINEAR_IMAGE;
+"IN_INTERS",IN_INTERS;
+"IN_INTERVAL",IN_INTERVAL;
+"IN_INTERVAL_1",IN_INTERVAL_1;
+"IN_INTERVAL_INTERVAL_BIJ",IN_INTERVAL_INTERVAL_BIJ;
+"IN_INTERVAL_REFLECT",IN_INTERVAL_REFLECT;
+"IN_NUMSEG",IN_NUMSEG;
+"IN_NUMSEG_0",IN_NUMSEG_0;
+"IN_OPEN_SEGMENT",IN_OPEN_SEGMENT;
+"IN_OPEN_SEGMENT_ALT",IN_OPEN_SEGMENT_ALT;
+"IN_PATH_IMAGE_PARTCIRCLEPATH",IN_PATH_IMAGE_PARTCIRCLEPATH;
+"IN_REAL_INTERVAL",IN_REAL_INTERVAL;
+"IN_REAL_INTERVAL_REFLECT",IN_REAL_INTERVAL_REFLECT;
+"IN_RELATIVE_INTERIOR",IN_RELATIVE_INTERIOR;
+"IN_RELATIVE_INTERIOR_CBALL",IN_RELATIVE_INTERIOR_CBALL;
+"IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SEGMENT",IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SEGMENT;
+"IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SHRINK",IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SHRINK;
+"IN_RELATIVE_INTERIOR_CONVEX_SHRINK",IN_RELATIVE_INTERIOR_CONVEX_SHRINK;
+"IN_REST",IN_REST;
+"IN_SEGMENT",IN_SEGMENT;
+"IN_SEGMENT_COMPONENT",IN_SEGMENT_COMPONENT;
+"IN_SEGMENT_CX",IN_SEGMENT_CX;
+"IN_SEGMENT_CX_GEN",IN_SEGMENT_CX_GEN;
+"IN_SET_OF_LIST",IN_SET_OF_LIST;
+"IN_SING",IN_SING;
+"IN_SLICE",IN_SLICE;
+"IN_SPAN_DELETE",IN_SPAN_DELETE;
+"IN_SPAN_IMAGE_BASIS",IN_SPAN_IMAGE_BASIS;
+"IN_SPAN_INSERT",IN_SPAN_INSERT;
+"IN_SPHERE",IN_SPHERE;
+"IN_SPHERE_0",IN_SPHERE_0;
+"IN_SUPPORT",IN_SUPPORT;
+"IN_UNION",IN_UNION;
+"IN_UNIONS",IN_UNIONS;
+"IN_UNIV",IN_UNIV;
+"IRRATIONAL_APPROXIMATION",IRRATIONAL_APPROXIMATION;
+"ISO",ISO;
+"ISOLATED_ZEROS",ISOLATED_ZEROS;
+"ISOMETRIES_SUBSPACES",ISOMETRIES_SUBSPACES;
+"ISOMETRY_IMP_AFFINITY",ISOMETRY_IMP_AFFINITY;
+"ISOMETRY_LINEAR",ISOMETRY_LINEAR;
+"ISOMETRY_ON_IMP_CONTINUOUS_ON",ISOMETRY_ON_IMP_CONTINUOUS_ON;
+"ISOMETRY_SPHERE_EXTEND",ISOMETRY_SPHERE_EXTEND;
+"ISOMETRY_SUBSET_SUBSPACE",ISOMETRY_SUBSET_SUBSPACE;
+"ISOMETRY_SUBSPACES",ISOMETRY_SUBSPACES;
+"ISOMETRY_UNIV_SUBSPACE",ISOMETRY_UNIV_SUBSPACE;
+"ISOMETRY_UNIV_SUPERSET_SUBSPACE",ISOMETRY_UNIV_SUPERSET_SUBSPACE;
+"ISOMETRY_UNIV_UNIV",ISOMETRY_UNIV_UNIV;
+"ISOMORPHISMS_UNIV_UNIV",ISOMORPHISMS_UNIV_UNIV;
+"ISOMORPHISM_EXPAND",ISOMORPHISM_EXPAND;
+"ISO_FUN",ISO_FUN;
+"ISO_REFL",ISO_REFL;
+"ISO_USAGE",ISO_USAGE;
+"ISTOPLOGY_SUBTOPOLOGY",ISTOPLOGY_SUBTOPOLOGY;
+"ISTOPOLOGY_OPEN_IN",ISTOPOLOGY_OPEN_IN;
+"IS_AFFINE_HULL",IS_AFFINE_HULL;
+"IS_CONVEX_HULL",IS_CONVEX_HULL;
+"IS_HULL",IS_HULL;
+"IS_INTERVAL_1",IS_INTERVAL_1;
+"IS_INTERVAL_1_CASES",IS_INTERVAL_1_CASES;
+"IS_INTERVAL_COMPACT",IS_INTERVAL_COMPACT;
+"IS_INTERVAL_CONNECTED",IS_INTERVAL_CONNECTED;
+"IS_INTERVAL_CONNECTED_1",IS_INTERVAL_CONNECTED_1;
+"IS_INTERVAL_CONTRACTIBLE_1",IS_INTERVAL_CONTRACTIBLE_1;
+"IS_INTERVAL_CONVEX",IS_INTERVAL_CONVEX;
+"IS_INTERVAL_CONVEX_1",IS_INTERVAL_CONVEX_1;
+"IS_INTERVAL_EMPTY",IS_INTERVAL_EMPTY;
+"IS_INTERVAL_IMP_LOCALLY_COMPACT",IS_INTERVAL_IMP_LOCALLY_COMPACT;
+"IS_INTERVAL_INTER",IS_INTERVAL_INTER;
+"IS_INTERVAL_INTERVAL",IS_INTERVAL_INTERVAL;
+"IS_INTERVAL_PATH_CONNECTED",IS_INTERVAL_PATH_CONNECTED;
+"IS_INTERVAL_PATH_CONNECTED_1",IS_INTERVAL_PATH_CONNECTED_1;
+"IS_INTERVAL_PCROSS",IS_INTERVAL_PCROSS;
+"IS_INTERVAL_PCROSS_EQ",IS_INTERVAL_PCROSS_EQ;
+"IS_INTERVAL_POINTWISE",IS_INTERVAL_POINTWISE;
+"IS_INTERVAL_SCALING",IS_INTERVAL_SCALING;
+"IS_INTERVAL_SCALING_EQ",IS_INTERVAL_SCALING_EQ;
+"IS_INTERVAL_SIMPLY_CONNECTED_1",IS_INTERVAL_SIMPLY_CONNECTED_1;
+"IS_INTERVAL_SING",IS_INTERVAL_SING;
+"IS_INTERVAL_SUMS",IS_INTERVAL_SUMS;
+"IS_INTERVAL_TRANSLATION",IS_INTERVAL_TRANSLATION;
+"IS_INTERVAL_TRANSLATION_EQ",IS_INTERVAL_TRANSLATION_EQ;
+"IS_INTERVAL_UNIV",IS_INTERVAL_UNIV;
+"IS_REALINTERVAL_CONNECTED",IS_REALINTERVAL_CONNECTED;
+"IS_REALINTERVAL_CONTINUOUS_IMAGE",IS_REALINTERVAL_CONTINUOUS_IMAGE;
+"IS_REALINTERVAL_CONVEX",IS_REALINTERVAL_CONVEX;
+"IS_REALINTERVAL_CONVEX_COMPLEX",IS_REALINTERVAL_CONVEX_COMPLEX;
+"IS_REALINTERVAL_EMPTY",IS_REALINTERVAL_EMPTY;
+"IS_REALINTERVAL_INTERVAL",IS_REALINTERVAL_INTERVAL;
+"IS_REALINTERVAL_IS_INTERVAL",IS_REALINTERVAL_IS_INTERVAL;
+"IS_REALINTERVAL_UNION",IS_REALINTERVAL_UNION;
+"IS_REALINTERVAL_UNIV",IS_REALINTERVAL_UNIV;
+"IS_REAL_INTERVAL_CASES",IS_REAL_INTERVAL_CASES;
+"ITER",ITER;
+"ITERATE_AND",ITERATE_AND;
+"ITERATE_BIJECTION",ITERATE_BIJECTION;
+"ITERATE_CASES",ITERATE_CASES;
+"ITERATE_CLAUSES",ITERATE_CLAUSES;
+"ITERATE_CLAUSES_GEN",ITERATE_CLAUSES_GEN;
+"ITERATE_CLAUSES_NUMSEG",ITERATE_CLAUSES_NUMSEG;
+"ITERATE_CLOSED",ITERATE_CLOSED;
+"ITERATE_DELETE",ITERATE_DELETE;
+"ITERATE_DELTA",ITERATE_DELTA;
+"ITERATE_DIFF",ITERATE_DIFF;
+"ITERATE_DIFF_GEN",ITERATE_DIFF_GEN;
+"ITERATE_EQ",ITERATE_EQ;
+"ITERATE_EQ_GENERAL",ITERATE_EQ_GENERAL;
+"ITERATE_EQ_GENERAL_INVERSES",ITERATE_EQ_GENERAL_INVERSES;
+"ITERATE_EQ_NEUTRAL",ITERATE_EQ_NEUTRAL;
+"ITERATE_EXPAND_CASES",ITERATE_EXPAND_CASES;
+"ITERATE_IMAGE",ITERATE_IMAGE;
+"ITERATE_IMAGE_NONZERO",ITERATE_IMAGE_NONZERO;
+"ITERATE_INCL_EXCL",ITERATE_INCL_EXCL;
+"ITERATE_INJECTION",ITERATE_INJECTION;
+"ITERATE_ITERATE_PRODUCT",ITERATE_ITERATE_PRODUCT;
+"ITERATE_NONZERO_IMAGE_LEMMA",ITERATE_NONZERO_IMAGE_LEMMA;
+"ITERATE_OP",ITERATE_OP;
+"ITERATE_OP_GEN",ITERATE_OP_GEN;
+"ITERATE_PAIR",ITERATE_PAIR;
+"ITERATE_PERMUTE",ITERATE_PERMUTE;
+"ITERATE_RELATED",ITERATE_RELATED;
+"ITERATE_SING",ITERATE_SING;
+"ITERATE_SOME",ITERATE_SOME;
+"ITERATE_SUPERSET",ITERATE_SUPERSET;
+"ITERATE_SUPPORT",ITERATE_SUPPORT;
+"ITERATE_UNION",ITERATE_UNION;
+"ITERATE_UNION_GEN",ITERATE_UNION_GEN;
+"ITERATE_UNION_NONZERO",ITERATE_UNION_NONZERO;
+"ITER_1",ITER_1;
+"ITER_ADD",ITER_ADD;
+"ITER_ALT",ITER_ALT;
+"ITER_ALT_POINTLESS",ITER_ALT_POINTLESS;
+"ITER_FIXPOINT",ITER_FIXPOINT;
+"ITER_MUL",ITER_MUL;
+"ITER_POINTLESS",ITER_POINTLESS;
+"ITLIST",ITLIST;
+"ITLIST2",ITLIST2;
+"ITLIST2_DEF",ITLIST2_DEF;
+"ITLIST_APPEND",ITLIST_APPEND;
+"ITLIST_EXTRA",ITLIST_EXTRA;
+"ITSET",ITSET;
+"ITSET_EQ",ITSET_EQ;
+"IVT_DECREASING_COMPONENT_1",IVT_DECREASING_COMPONENT_1;
+"IVT_DECREASING_COMPONENT_ON_1",IVT_DECREASING_COMPONENT_ON_1;
+"IVT_DECREASING_IM",IVT_DECREASING_IM;
+"IVT_DECREASING_RE",IVT_DECREASING_RE;
+"IVT_INCREASING_COMPONENT_1",IVT_INCREASING_COMPONENT_1;
+"IVT_INCREASING_COMPONENT_ON_1",IVT_INCREASING_COMPONENT_ON_1;
+"IVT_INCREASING_IM",IVT_INCREASING_IM;
+"IVT_INCREASING_RE",IVT_INCREASING_RE;
+"I_DEF",I_DEF;
+"I_O_ID",I_O_ID;
+"I_THM",I_THM;
+"JACOBIAN_WORKS",JACOBIAN_WORKS;
+"JANISZEWSKI",JANISZEWSKI;
+"JANISZEWSKI_GEN",JANISZEWSKI_GEN;
+"JOINABLE_COMPONENTS_EQ",JOINABLE_COMPONENTS_EQ;
+"JOINABLE_CONNECTED_COMPONENT_EQ",JOINABLE_CONNECTED_COMPONENT_EQ;
+"JOINPATHS",JOINPATHS;
+"JOINPATHS_LINEAR_IMAGE",JOINPATHS_LINEAR_IMAGE;
+"JOINPATHS_TRANSLATION",JOINPATHS_TRANSLATION;
+"JOIN_PATHS_EQ",JOIN_PATHS_EQ;
+"JOIN_SUBPATHS_MIDDLE",JOIN_SUBPATHS_MIDDLE;
+"JORDAN_BROUWER_ACCESSIBILITY",JORDAN_BROUWER_ACCESSIBILITY;
+"JORDAN_BROUWER_FRONTIER",JORDAN_BROUWER_FRONTIER;
+"JORDAN_BROUWER_NONSEPARATION",JORDAN_BROUWER_NONSEPARATION;
+"JORDAN_BROUWER_SEPARATION",JORDAN_BROUWER_SEPARATION;
+"JORDAN_CURVE_THEOREM",JORDAN_CURVE_THEOREM;
+"JORDAN_DISCONNECTED",JORDAN_DISCONNECTED;
+"JORDAN_INSIDE_OUTSIDE",JORDAN_INSIDE_OUTSIDE;
+"JUNG",JUNG;
+"KIRCHBERGER",KIRCHBERGER;
+"KL",KL;
+"KLE_ADJACENT",KLE_ADJACENT;
+"KLE_ANTISYM",KLE_ANTISYM;
+"KLE_BETWEEN_L",KLE_BETWEEN_L;
+"KLE_BETWEEN_R",KLE_BETWEEN_R;
+"KLE_IMP_POINTWISE",KLE_IMP_POINTWISE;
+"KLE_MAXIMAL",KLE_MAXIMAL;
+"KLE_MINIMAL",KLE_MINIMAL;
+"KLE_RANGE_COMBINE",KLE_RANGE_COMBINE;
+"KLE_RANGE_COMBINE_L",KLE_RANGE_COMBINE_L;
+"KLE_RANGE_COMBINE_R",KLE_RANGE_COMBINE_R;
+"KLE_RANGE_INDUCT",KLE_RANGE_INDUCT;
+"KLE_REFL",KLE_REFL;
+"KLE_STRICT",KLE_STRICT;
+"KLE_STRICT_SET",KLE_STRICT_SET;
+"KLE_SUC",KLE_SUC;
+"KLE_TRANS",KLE_TRANS;
+"KLE_TRANS_1",KLE_TRANS_1;
+"KLE_TRANS_2",KLE_TRANS_2;
+"KL_POSET_LEMMA",KL_POSET_LEMMA;
+"KREIN_MILMAN",KREIN_MILMAN;
+"KREIN_MILMAN_FRONTIER",KREIN_MILMAN_FRONTIER;
+"KREIN_MILMAN_MINKOWSKI",KREIN_MILMAN_MINKOWSKI;
+"KREIN_MILMAN_POLYTOPE",KREIN_MILMAN_POLYTOPE;
+"KREIN_MILMAN_RELATIVE_FRONTIER",KREIN_MILMAN_RELATIVE_FRONTIER;
+"KSIMPLEX_0",KSIMPLEX_0;
+"KSIMPLEX_EXTREMA",KSIMPLEX_EXTREMA;
+"KSIMPLEX_EXTREMA_STRONG",KSIMPLEX_EXTREMA_STRONG;
+"KSIMPLEX_FIX_PLANE",KSIMPLEX_FIX_PLANE;
+"KSIMPLEX_FIX_PLANE_0",KSIMPLEX_FIX_PLANE_0;
+"KSIMPLEX_FIX_PLANE_P",KSIMPLEX_FIX_PLANE_P;
+"KSIMPLEX_PREDECESSOR",KSIMPLEX_PREDECESSOR;
+"KSIMPLEX_REPLACE_0",KSIMPLEX_REPLACE_0;
+"KSIMPLEX_REPLACE_1",KSIMPLEX_REPLACE_1;
+"KSIMPLEX_REPLACE_2",KSIMPLEX_REPLACE_2;
+"KSIMPLEX_SUCCESSOR",KSIMPLEX_SUCCESSOR;
+"KUHN_COMBINATORIAL",KUHN_COMBINATORIAL;
+"KUHN_COMPLETE_LEMMA",KUHN_COMPLETE_LEMMA;
+"KUHN_COUNTING_LEMMA",KUHN_COUNTING_LEMMA;
+"KUHN_INDUCTION",KUHN_INDUCTION;
+"KUHN_LABELLING_LEMMA",KUHN_LABELLING_LEMMA;
+"KUHN_LEMMA",KUHN_LEMMA;
+"KUHN_SIMPLEX_LEMMA",KUHN_SIMPLEX_LEMMA;
+"L1_LE_NORM",L1_LE_NORM;
+"LAMBDA_ADD_GALOIS",LAMBDA_ADD_GALOIS;
+"LAMBDA_BETA",LAMBDA_BETA;
+"LAMBDA_BETA_PERM",LAMBDA_BETA_PERM;
+"LAMBDA_ETA",LAMBDA_ETA;
+"LAMBDA_PAIR",LAMBDA_PAIR;
+"LAMBDA_PAIR_THM",LAMBDA_PAIR_THM;
+"LAMBDA_SKOLEM",LAMBDA_SKOLEM;
+"LAMBDA_SWAP_GALOIS",LAMBDA_SWAP_GALOIS;
+"LAMBDA_UNIQUE",LAMBDA_UNIQUE;
+"LANDAU_PICARD",LANDAU_PICARD;
+"LAST",LAST;
+"LAST_APPEND",LAST_APPEND;
+"LAST_CLAUSES",LAST_CLAUSES;
+"LAST_EL",LAST_EL;
+"LE",LE;
+"LEBESGUE_COVERING_LEMMA",LEBESGUE_COVERING_LEMMA;
+"LEBESGUE_DENSITY_THEOREM",LEBESGUE_DENSITY_THEOREM;
+"LEBESGUE_MEASURABLE_CLOSED",LEBESGUE_MEASURABLE_CLOSED;
+"LEBESGUE_MEASURABLE_COMPACT",LEBESGUE_MEASURABLE_COMPACT;
+"LEBESGUE_MEASURABLE_COMPL",LEBESGUE_MEASURABLE_COMPL;
+"LEBESGUE_MEASURABLE_CONTINUOUS_IMAGE",LEBESGUE_MEASURABLE_CONTINUOUS_IMAGE;
+"LEBESGUE_MEASURABLE_CONVEX",LEBESGUE_MEASURABLE_CONVEX;
+"LEBESGUE_MEASURABLE_COUNTABLE_INTERS",LEBESGUE_MEASURABLE_COUNTABLE_INTERS;
+"LEBESGUE_MEASURABLE_COUNTABLE_INTERS_EXPLICIT",LEBESGUE_MEASURABLE_COUNTABLE_INTERS_EXPLICIT;
+"LEBESGUE_MEASURABLE_COUNTABLE_UNIONS",LEBESGUE_MEASURABLE_COUNTABLE_UNIONS;
+"LEBESGUE_MEASURABLE_COUNTABLE_UNIONS_EXPLICIT",LEBESGUE_MEASURABLE_COUNTABLE_UNIONS_EXPLICIT;
+"LEBESGUE_MEASURABLE_DIFF",LEBESGUE_MEASURABLE_DIFF;
+"LEBESGUE_MEASURABLE_DIFFERENTIABLE_IMAGE",LEBESGUE_MEASURABLE_DIFFERENTIABLE_IMAGE;
+"LEBESGUE_MEASURABLE_EMPTY",LEBESGUE_MEASURABLE_EMPTY;
+"LEBESGUE_MEASURABLE_IFF_MEASURABLE",LEBESGUE_MEASURABLE_IFF_MEASURABLE;
+"LEBESGUE_MEASURABLE_INNER_CLOSED",LEBESGUE_MEASURABLE_INNER_CLOSED;
+"LEBESGUE_MEASURABLE_INTER",LEBESGUE_MEASURABLE_INTER;
+"LEBESGUE_MEASURABLE_INTERS",LEBESGUE_MEASURABLE_INTERS;
+"LEBESGUE_MEASURABLE_INTERVAL",LEBESGUE_MEASURABLE_INTERVAL;
+"LEBESGUE_MEASURABLE_JORDAN",LEBESGUE_MEASURABLE_JORDAN;
+"LEBESGUE_MEASURABLE_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED",LEBESGUE_MEASURABLE_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED;
+"LEBESGUE_MEASURABLE_LEBESGUE_MEASURABLE_PREIMAGE_OPEN",LEBESGUE_MEASURABLE_LEBESGUE_MEASURABLE_PREIMAGE_OPEN;
+"LEBESGUE_MEASURABLE_LINEAR_IMAGE_EQ",LEBESGUE_MEASURABLE_LINEAR_IMAGE_EQ;
+"LEBESGUE_MEASURABLE_ON_SUBINTERVALS",LEBESGUE_MEASURABLE_ON_SUBINTERVALS;
+"LEBESGUE_MEASURABLE_OPEN",LEBESGUE_MEASURABLE_OPEN;
+"LEBESGUE_MEASURABLE_OUTER_OPEN",LEBESGUE_MEASURABLE_OUTER_OPEN;
+"LEBESGUE_MEASURABLE_PREIMAGE_CLOSED",LEBESGUE_MEASURABLE_PREIMAGE_CLOSED;
+"LEBESGUE_MEASURABLE_PREIMAGE_OPEN",LEBESGUE_MEASURABLE_PREIMAGE_OPEN;
+"LEBESGUE_MEASURABLE_REGULAR_INNER",LEBESGUE_MEASURABLE_REGULAR_INNER;
+"LEBESGUE_MEASURABLE_REGULAR_OUTER",LEBESGUE_MEASURABLE_REGULAR_OUTER;
+"LEBESGUE_MEASURABLE_TRANSLATION",LEBESGUE_MEASURABLE_TRANSLATION;
+"LEBESGUE_MEASURABLE_UNION",LEBESGUE_MEASURABLE_UNION;
+"LEBESGUE_MEASURABLE_UNIONS",LEBESGUE_MEASURABLE_UNIONS;
+"LEBESGUE_MEASURABLE_UNIV",LEBESGUE_MEASURABLE_UNIV;
+"LEFT_ADD_DISTRIB",LEFT_ADD_DISTRIB;
+"LEFT_AND_EXISTS_THM",LEFT_AND_EXISTS_THM;
+"LEFT_AND_FORALL_THM",LEFT_AND_FORALL_THM;
+"LEFT_EXISTS_AND_THM",LEFT_EXISTS_AND_THM;
+"LEFT_EXISTS_IMP_THM",LEFT_EXISTS_IMP_THM;
+"LEFT_FORALL_IMP_THM",LEFT_FORALL_IMP_THM;
+"LEFT_FORALL_OR_THM",LEFT_FORALL_OR_THM;
+"LEFT_IMP_EXISTS_THM",LEFT_IMP_EXISTS_THM;
+"LEFT_IMP_FORALL_THM",LEFT_IMP_FORALL_THM;
+"LEFT_INVERSE_LINEAR",LEFT_INVERSE_LINEAR;
+"LEFT_INVERTIBLE_TRANSP",LEFT_INVERTIBLE_TRANSP;
+"LEFT_OR_DISTRIB",LEFT_OR_DISTRIB;
+"LEFT_OR_EXISTS_THM",LEFT_OR_EXISTS_THM;
+"LEFT_OR_FORALL_THM",LEFT_OR_FORALL_THM;
+"LEFT_RIGHT_INVERSE_EQ",LEFT_RIGHT_INVERSE_EQ;
+"LEFT_RIGHT_INVERSE_LINEAR",LEFT_RIGHT_INVERSE_LINEAR;
+"LEFT_SUB_DISTRIB",LEFT_SUB_DISTRIB;
+"LEMMA",LEMMA;
+"LENGTH",LENGTH;
+"LENGTH_APPEND",LENGTH_APPEND;
+"LENGTH_EQ_CONS",LENGTH_EQ_CONS;
+"LENGTH_EQ_NIL",LENGTH_EQ_NIL;
+"LENGTH_LIST_OF_SET",LENGTH_LIST_OF_SET;
+"LENGTH_MAP",LENGTH_MAP;
+"LENGTH_MAP2",LENGTH_MAP2;
+"LENGTH_REPLICATE",LENGTH_REPLICATE;
+"LENGTH_TL",LENGTH_TL;
+"LET_ADD2",LET_ADD2;
+"LET_ANTISYM",LET_ANTISYM;
+"LET_CASES",LET_CASES;
+"LET_DEF",LET_DEF;
+"LET_END_DEF",LET_END_DEF;
+"LET_TRANS",LET_TRANS;
+"LE_0",LE_0;
+"LE_1",LE_1;
+"LE_ADD",LE_ADD;
+"LE_ADD2",LE_ADD2;
+"LE_ADDR",LE_ADDR;
+"LE_ADD_LCANCEL",LE_ADD_LCANCEL;
+"LE_ADD_RCANCEL",LE_ADD_RCANCEL;
+"LE_ANTISYM",LE_ANTISYM;
+"LE_C",LE_C;
+"LE_CASES",LE_CASES;
+"LE_EXISTS",LE_EXISTS;
+"LE_EXP",LE_EXP;
+"LE_LDIV",LE_LDIV;
+"LE_LDIV_EQ",LE_LDIV_EQ;
+"LE_LT",LE_LT;
+"LE_MULT2",LE_MULT2;
+"LE_MULT_LCANCEL",LE_MULT_LCANCEL;
+"LE_MULT_RCANCEL",LE_MULT_RCANCEL;
+"LE_RDIV_EQ",LE_RDIV_EQ;
+"LE_REFL",LE_REFL;
+"LE_SQUARE_REFL",LE_SQUARE_REFL;
+"LE_SUC",LE_SUC;
+"LE_SUC_LT",LE_SUC_LT;
+"LE_TRANS",LE_TRANS;
+"LHOSPITAL",LHOSPITAL;
+"LIFT_ADD",LIFT_ADD;
+"LIFT_CMUL",LIFT_CMUL;
+"LIFT_COMPONENT",LIFT_COMPONENT;
+"LIFT_DROP",LIFT_DROP;
+"LIFT_EQ",LIFT_EQ;
+"LIFT_EQ_CMUL",LIFT_EQ_CMUL;
+"LIFT_INTEGRAL_COMPONENT",LIFT_INTEGRAL_COMPONENT;
+"LIFT_IN_IMAGE_LIFT",LIFT_IN_IMAGE_LIFT;
+"LIFT_NEG",LIFT_NEG;
+"LIFT_NUM",LIFT_NUM;
+"LIFT_SUB",LIFT_SUB;
+"LIFT_SUM",LIFT_SUM;
+"LIM",LIM;
+"LIMIT_POINT_FINITE",LIMIT_POINT_FINITE;
+"LIMIT_POINT_OF_SPHERE",LIMIT_POINT_OF_SPHERE;
+"LIMIT_POINT_UNION",LIMIT_POINT_UNION;
+"LIMPT_APPROACHABLE",LIMPT_APPROACHABLE;
+"LIMPT_APPROACHABLE_LE",LIMPT_APPROACHABLE_LE;
+"LIMPT_APPROACHABLE_LIFT",LIMPT_APPROACHABLE_LIFT;
+"LIMPT_BALL",LIMPT_BALL;
+"LIMPT_EMPTY",LIMPT_EMPTY;
+"LIMPT_INFINITE_BALL",LIMPT_INFINITE_BALL;
+"LIMPT_INFINITE_CBALL",LIMPT_INFINITE_CBALL;
+"LIMPT_INFINITE_OPEN",LIMPT_INFINITE_OPEN;
+"LIMPT_INJECTIVE_LINEAR_IMAGE_EQ",LIMPT_INJECTIVE_LINEAR_IMAGE_EQ;
+"LIMPT_INSERT",LIMPT_INSERT;
+"LIMPT_OF_CLOSURE",LIMPT_OF_CLOSURE;
+"LIMPT_OF_CONDENSATION_POINTS",LIMPT_OF_CONDENSATION_POINTS;
+"LIMPT_OF_CONVEX",LIMPT_OF_CONVEX;
+"LIMPT_OF_LIMPTS",LIMPT_OF_LIMPTS;
+"LIMPT_OF_OPEN",LIMPT_OF_OPEN;
+"LIMPT_OF_OPEN_IN",LIMPT_OF_OPEN_IN;
+"LIMPT_OF_SEQUENCE_SUBSEQUENCE",LIMPT_OF_SEQUENCE_SUBSEQUENCE;
+"LIMPT_OF_UNIV",LIMPT_OF_UNIV;
+"LIMPT_PCROSS",LIMPT_PCROSS;
+"LIMPT_SEQUENTIAL",LIMPT_SEQUENTIAL;
+"LIMPT_SEQUENTIAL_INJ",LIMPT_SEQUENTIAL_INJ;
+"LIMPT_SING",LIMPT_SING;
+"LIMPT_SUBSET",LIMPT_SUBSET;
+"LIMPT_TRANSLATION_EQ",LIMPT_TRANSLATION_EQ;
+"LIMPT_UNIV",LIMPT_UNIV;
+"LIM_1_OVER_LOG",LIM_1_OVER_LOG;
+"LIM_1_OVER_N",LIM_1_OVER_N;
+"LIM_1_OVER_POWER",LIM_1_OVER_POWER;
+"LIM_ABS",LIM_ABS;
+"LIM_ADD",LIM_ADD;
+"LIM_AT",LIM_AT;
+"LIM_ATREAL",LIM_ATREAL;
+"LIM_ATREAL_AT",LIM_ATREAL_AT;
+"LIM_ATREAL_ATCOMPLEX",LIM_ATREAL_ATCOMPLEX;
+"LIM_ATREAL_WITHINREAL",LIM_ATREAL_WITHINREAL;
+"LIM_AT_ID",LIM_AT_ID;
+"LIM_AT_INFINITY",LIM_AT_INFINITY;
+"LIM_AT_NEGINFINITY",LIM_AT_NEGINFINITY;
+"LIM_AT_POSINFINITY",LIM_AT_POSINFINITY;
+"LIM_AT_WITHIN",LIM_AT_WITHIN;
+"LIM_AT_ZERO",LIM_AT_ZERO;
+"LIM_BILINEAR",LIM_BILINEAR;
+"LIM_CASES_COFINITE_SEQUENTIALLY",LIM_CASES_COFINITE_SEQUENTIALLY;
+"LIM_CASES_FINITE_SEQUENTIALLY",LIM_CASES_FINITE_SEQUENTIALLY;
+"LIM_CASES_SEQUENTIALLY",LIM_CASES_SEQUENTIALLY;
+"LIM_CEXP_MINUS_1",LIM_CEXP_MINUS_1;
+"LIM_CMUL",LIM_CMUL;
+"LIM_CMUL_EQ",LIM_CMUL_EQ;
+"LIM_CNJ",LIM_CNJ;
+"LIM_COMPLEX_DIV",LIM_COMPLEX_DIV;
+"LIM_COMPLEX_INV",LIM_COMPLEX_INV;
+"LIM_COMPLEX_LMUL",LIM_COMPLEX_LMUL;
+"LIM_COMPLEX_MUL",LIM_COMPLEX_MUL;
+"LIM_COMPLEX_POW",LIM_COMPLEX_POW;
+"LIM_COMPLEX_REAL",LIM_COMPLEX_REAL;
+"LIM_COMPLEX_REAL_0",LIM_COMPLEX_REAL_0;
+"LIM_COMPLEX_RMUL",LIM_COMPLEX_RMUL;
+"LIM_COMPONENT",LIM_COMPONENT;
+"LIM_COMPONENTWISE",LIM_COMPONENTWISE;
+"LIM_COMPONENTWISE_LIFT",LIM_COMPONENTWISE_LIFT;
+"LIM_COMPONENT_EQ",LIM_COMPONENT_EQ;
+"LIM_COMPONENT_LBOUND",LIM_COMPONENT_LBOUND;
+"LIM_COMPONENT_LE",LIM_COMPONENT_LE;
+"LIM_COMPONENT_UBOUND",LIM_COMPONENT_UBOUND;
+"LIM_COMPOSE_AT",LIM_COMPOSE_AT;
+"LIM_COMPOSE_WITHIN",LIM_COMPOSE_WITHIN;
+"LIM_CONG_AT",LIM_CONG_AT;
+"LIM_CONG_ATREAL",LIM_CONG_ATREAL;
+"LIM_CONG_WITHIN",LIM_CONG_WITHIN;
+"LIM_CONG_WITHINREAL",LIM_CONG_WITHINREAL;
+"LIM_CONST",LIM_CONST;
+"LIM_CONST_EQ",LIM_CONST_EQ;
+"LIM_CONTINUOUS",LIM_CONTINUOUS;
+"LIM_CONTINUOUS_FUNCTION",LIM_CONTINUOUS_FUNCTION;
+"LIM_DROP_LBOUND",LIM_DROP_LBOUND;
+"LIM_DROP_LE",LIM_DROP_LE;
+"LIM_DROP_UBOUND",LIM_DROP_UBOUND;
+"LIM_EVENTUALLY",LIM_EVENTUALLY;
+"LIM_IM_LBOUND",LIM_IM_LBOUND;
+"LIM_IM_UBOUND",LIM_IM_UBOUND;
+"LIM_INFINITY_SEQUENTIALLY_COMPLEX",LIM_INFINITY_SEQUENTIALLY_COMPLEX;
+"LIM_INV",LIM_INV;
+"LIM_INV_N",LIM_INV_N;
+"LIM_IN_CLOSED_SET",LIM_IN_CLOSED_SET;
+"LIM_LIFT_DOT",LIM_LIFT_DOT;
+"LIM_LINEAR",LIM_LINEAR;
+"LIM_LOG_OVER_N",LIM_LOG_OVER_N;
+"LIM_LOG_OVER_POWER",LIM_LOG_OVER_POWER;
+"LIM_MAX",LIM_MAX;
+"LIM_MIN",LIM_MIN;
+"LIM_MUL",LIM_MUL;
+"LIM_MUL_NORM_WITHIN",LIM_MUL_NORM_WITHIN;
+"LIM_NEG",LIM_NEG;
+"LIM_NEG_EQ",LIM_NEG_EQ;
+"LIM_NORM",LIM_NORM;
+"LIM_NORM_LBOUND",LIM_NORM_LBOUND;
+"LIM_NORM_UBOUND",LIM_NORM_UBOUND;
+"LIM_NULL",LIM_NULL;
+"LIM_NULL_CMUL_BOUNDED",LIM_NULL_CMUL_BOUNDED;
+"LIM_NULL_CMUL_EQ",LIM_NULL_CMUL_EQ;
+"LIM_NULL_COMPARISON",LIM_NULL_COMPARISON;
+"LIM_NULL_COMPARISON_COMPLEX",LIM_NULL_COMPARISON_COMPLEX;
+"LIM_NULL_COMPARISON_COMPLEX_RE",LIM_NULL_COMPARISON_COMPLEX_RE;
+"LIM_NULL_COMPLEX_ADD",LIM_NULL_COMPLEX_ADD;
+"LIM_NULL_COMPLEX_BOUND",LIM_NULL_COMPLEX_BOUND;
+"LIM_NULL_COMPLEX_LMUL",LIM_NULL_COMPLEX_LMUL;
+"LIM_NULL_COMPLEX_LMUL_BOUNDED",LIM_NULL_COMPLEX_LMUL_BOUNDED;
+"LIM_NULL_COMPLEX_MUL",LIM_NULL_COMPLEX_MUL;
+"LIM_NULL_COMPLEX_NEG",LIM_NULL_COMPLEX_NEG;
+"LIM_NULL_COMPLEX_POW",LIM_NULL_COMPLEX_POW;
+"LIM_NULL_COMPLEX_POW_EQ",LIM_NULL_COMPLEX_POW_EQ;
+"LIM_NULL_COMPLEX_RMUL",LIM_NULL_COMPLEX_RMUL;
+"LIM_NULL_COMPLEX_RMUL_BOUNDED",LIM_NULL_COMPLEX_RMUL_BOUNDED;
+"LIM_NULL_COMPLEX_SUB",LIM_NULL_COMPLEX_SUB;
+"LIM_NULL_NORM",LIM_NULL_NORM;
+"LIM_NULL_VMUL_BOUNDED",LIM_NULL_VMUL_BOUNDED;
+"LIM_N_OVER_POWN",LIM_N_OVER_POWN;
+"LIM_N_TIMES_POWN",LIM_N_TIMES_POWN;
+"LIM_PASTECART",LIM_PASTECART;
+"LIM_PASTECART_EQ",LIM_PASTECART_EQ;
+"LIM_POSINFINITY_SEQUENTIALLY",LIM_POSINFINITY_SEQUENTIALLY;
+"LIM_POWN",LIM_POWN;
+"LIM_REAL_CONTINUOUS_FUNCTION",LIM_REAL_CONTINUOUS_FUNCTION;
+"LIM_RE_LBOUND",LIM_RE_LBOUND;
+"LIM_RE_UBOUND",LIM_RE_UBOUND;
+"LIM_SEQUENTIALLY",LIM_SEQUENTIALLY;
+"LIM_SUB",LIM_SUB;
+"LIM_SUBSEQUENCE",LIM_SUBSEQUENCE;
+"LIM_TRANSFORM",LIM_TRANSFORM;
+"LIM_TRANSFORM_AT",LIM_TRANSFORM_AT;
+"LIM_TRANSFORM_AWAY_AT",LIM_TRANSFORM_AWAY_AT;
+"LIM_TRANSFORM_AWAY_WITHIN",LIM_TRANSFORM_AWAY_WITHIN;
+"LIM_TRANSFORM_BOUND",LIM_TRANSFORM_BOUND;
+"LIM_TRANSFORM_EQ",LIM_TRANSFORM_EQ;
+"LIM_TRANSFORM_EVENTUALLY",LIM_TRANSFORM_EVENTUALLY;
+"LIM_TRANSFORM_WITHIN",LIM_TRANSFORM_WITHIN;
+"LIM_TRANSFORM_WITHINREAL_SET",LIM_TRANSFORM_WITHINREAL_SET;
+"LIM_TRANSFORM_WITHIN_OPEN",LIM_TRANSFORM_WITHIN_OPEN;
+"LIM_TRANSFORM_WITHIN_SET",LIM_TRANSFORM_WITHIN_SET;
+"LIM_UNION",LIM_UNION;
+"LIM_UNION_UNIV",LIM_UNION_UNIV;
+"LIM_UNIQUE",LIM_UNIQUE;
+"LIM_VMUL",LIM_VMUL;
+"LIM_VSUM",LIM_VSUM;
+"LIM_WITHIN",LIM_WITHIN;
+"LIM_WITHINREAL",LIM_WITHINREAL;
+"LIM_WITHINREAL_LE",LIM_WITHINREAL_LE;
+"LIM_WITHINREAL_SUBSET",LIM_WITHINREAL_SUBSET;
+"LIM_WITHINREAL_WITHIN",LIM_WITHINREAL_WITHIN;
+"LIM_WITHINREAL_WITHINCOMPLEX",LIM_WITHINREAL_WITHINCOMPLEX;
+"LIM_WITHIN_CLOSED_TRIVIAL",LIM_WITHIN_CLOSED_TRIVIAL;
+"LIM_WITHIN_EMPTY",LIM_WITHIN_EMPTY;
+"LIM_WITHIN_ID",LIM_WITHIN_ID;
+"LIM_WITHIN_INTERIOR",LIM_WITHIN_INTERIOR;
+"LIM_WITHIN_LE",LIM_WITHIN_LE;
+"LIM_WITHIN_OPEN",LIM_WITHIN_OPEN;
+"LIM_WITHIN_REAL_OPEN",LIM_WITHIN_REAL_OPEN;
+"LIM_WITHIN_SUBSET",LIM_WITHIN_SUBSET;
+"LIM_WITHIN_UNION",LIM_WITHIN_UNION;
+"LIM_ZERO_INFINITY_COMPLEX",LIM_ZERO_INFINITY_COMPLEX;
+"LIM_ZERO_NEGINFINITY",LIM_ZERO_NEGINFINITY;
+"LIM_ZERO_POSINFINITY",LIM_ZERO_POSINFINITY;
+"LINDELOF",LINDELOF;
+"LINDELOF_OPEN_IN",LINDELOF_OPEN_IN;
+"LINEAR_0",LINEAR_0;
+"LINEAR_1",LINEAR_1;
+"LINEAR_ADD",LINEAR_ADD;
+"LINEAR_BIJECTIVE_DIMINDEX_EQ",LINEAR_BIJECTIVE_DIMINDEX_EQ;
+"LINEAR_BIJECTIVE_LEFT_RIGHT_INVERSE",LINEAR_BIJECTIVE_LEFT_RIGHT_INVERSE;
+"LINEAR_BOUNDED",LINEAR_BOUNDED;
+"LINEAR_BOUNDED_POS",LINEAR_BOUNDED_POS;
+"LINEAR_CMUL",LINEAR_CMUL;
+"LINEAR_CNJ",LINEAR_CNJ;
+"LINEAR_COMPLEX_MUL",LINEAR_COMPLEX_MUL;
+"LINEAR_COMPONENTWISE",LINEAR_COMPONENTWISE;
+"LINEAR_COMPONENTWISE_EXPANSION",LINEAR_COMPONENTWISE_EXPANSION;
+"LINEAR_COMPOSE",LINEAR_COMPOSE;
+"LINEAR_COMPOSE_ADD",LINEAR_COMPOSE_ADD;
+"LINEAR_COMPOSE_CMUL",LINEAR_COMPOSE_CMUL;
+"LINEAR_COMPOSE_NEG",LINEAR_COMPOSE_NEG;
+"LINEAR_COMPOSE_SUB",LINEAR_COMPOSE_SUB;
+"LINEAR_COMPOSE_VSUM",LINEAR_COMPOSE_VSUM;
+"LINEAR_CONTINUOUS_AT",LINEAR_CONTINUOUS_AT;
+"LINEAR_CONTINUOUS_COMPOSE",LINEAR_CONTINUOUS_COMPOSE;
+"LINEAR_CONTINUOUS_ON",LINEAR_CONTINUOUS_ON;
+"LINEAR_CONTINUOUS_ON_COMPOSE",LINEAR_CONTINUOUS_ON_COMPOSE;
+"LINEAR_CONTINUOUS_WITHIN",LINEAR_CONTINUOUS_WITHIN;
+"LINEAR_CX_IM",LINEAR_CX_IM;
+"LINEAR_CX_RE",LINEAR_CX_RE;
+"LINEAR_DROPOUT",LINEAR_DROPOUT;
+"LINEAR_EQ",LINEAR_EQ;
+"LINEAR_EQ_0",LINEAR_EQ_0;
+"LINEAR_EQ_0_SPAN",LINEAR_EQ_0_SPAN;
+"LINEAR_EQ_MATRIX",LINEAR_EQ_MATRIX;
+"LINEAR_EQ_MBASIS",LINEAR_EQ_MBASIS;
+"LINEAR_EQ_STDBASIS",LINEAR_EQ_STDBASIS;
+"LINEAR_FRECHET_DERIVATIVE",LINEAR_FRECHET_DERIVATIVE;
+"LINEAR_FROM_REALS",LINEAR_FROM_REALS;
+"LINEAR_FSTCART",LINEAR_FSTCART;
+"LINEAR_I",LINEAR_I;
+"LINEAR_ID",LINEAR_ID;
+"LINEAR_IMAGE_SUBSET_INTERIOR",LINEAR_IMAGE_SUBSET_INTERIOR;
+"LINEAR_INDEPENDENT_EXTEND",LINEAR_INDEPENDENT_EXTEND;
+"LINEAR_INDEPENDENT_EXTEND_LEMMA",LINEAR_INDEPENDENT_EXTEND_LEMMA;
+"LINEAR_INDEP_IMAGE_LEMMA",LINEAR_INDEP_IMAGE_LEMMA;
+"LINEAR_INJECTIVE_0",LINEAR_INJECTIVE_0;
+"LINEAR_INJECTIVE_0_SUBSPACE",LINEAR_INJECTIVE_0_SUBSPACE;
+"LINEAR_INJECTIVE_BOUNDED_BELOW_POS",LINEAR_INJECTIVE_BOUNDED_BELOW_POS;
+"LINEAR_INJECTIVE_DIMINDEX_LE",LINEAR_INJECTIVE_DIMINDEX_LE;
+"LINEAR_INJECTIVE_IMP_SURJECTIVE",LINEAR_INJECTIVE_IMP_SURJECTIVE;
+"LINEAR_INJECTIVE_ISOMORPHISM",LINEAR_INJECTIVE_ISOMORPHISM;
+"LINEAR_INJECTIVE_LEFT_INVERSE",LINEAR_INJECTIVE_LEFT_INVERSE;
+"LINEAR_INTERIOR_IMAGE_SUBSET",LINEAR_INTERIOR_IMAGE_SUBSET;
+"LINEAR_INVERSE_LEFT",LINEAR_INVERSE_LEFT;
+"LINEAR_INVERTIBLE_BOUNDED_BELOW",LINEAR_INVERTIBLE_BOUNDED_BELOW;
+"LINEAR_INVERTIBLE_BOUNDED_BELOW_POS",LINEAR_INVERTIBLE_BOUNDED_BELOW_POS;
+"LINEAR_LIFT_COMPONENT",LINEAR_LIFT_COMPONENT;
+"LINEAR_LIFT_DOT",LINEAR_LIFT_DOT;
+"LINEAR_LIM_0",LINEAR_LIM_0;
+"LINEAR_MATRIX_EXISTS",LINEAR_MATRIX_EXISTS;
+"LINEAR_NEG",LINEAR_NEG;
+"LINEAR_NEGATION",LINEAR_NEGATION;
+"LINEAR_OPEN_MAPPING",LINEAR_OPEN_MAPPING;
+"LINEAR_PASTECART",LINEAR_PASTECART;
+"LINEAR_PROPERTY",LINEAR_PROPERTY;
+"LINEAR_REFLECT_ALONG",LINEAR_REFLECT_ALONG;
+"LINEAR_ROTATE2D",LINEAR_ROTATE2D;
+"LINEAR_SCALING",LINEAR_SCALING;
+"LINEAR_SINGULAR_IMAGE_HYPERPLANE",LINEAR_SINGULAR_IMAGE_HYPERPLANE;
+"LINEAR_SINGULAR_INTO_HYPERPLANE",LINEAR_SINGULAR_INTO_HYPERPLANE;
+"LINEAR_SNDCART",LINEAR_SNDCART;
+"LINEAR_SUB",LINEAR_SUB;
+"LINEAR_SUBSPACE_GRAPH",LINEAR_SUBSPACE_GRAPH;
+"LINEAR_SURJECTIVE_DIMINDEX_LE",LINEAR_SURJECTIVE_DIMINDEX_LE;
+"LINEAR_SURJECTIVE_IFF_INJECTIVE",LINEAR_SURJECTIVE_IFF_INJECTIVE;
+"LINEAR_SURJECTIVE_IMP_INJECTIVE",LINEAR_SURJECTIVE_IMP_INJECTIVE;
+"LINEAR_SURJECTIVE_ISOMORPHISM",LINEAR_SURJECTIVE_ISOMORPHISM;
+"LINEAR_SURJECTIVE_RIGHT_INVERSE",LINEAR_SURJECTIVE_RIGHT_INVERSE;
+"LINEAR_TO_REALS",LINEAR_TO_REALS;
+"LINEAR_UNIFORMLY_CONTINUOUS_ON",LINEAR_UNIFORMLY_CONTINUOUS_ON;
+"LINEAR_VMUL_COMPONENT",LINEAR_VMUL_COMPONENT;
+"LINEAR_VMUL_DROP",LINEAR_VMUL_DROP;
+"LINEAR_VSUM",LINEAR_VSUM;
+"LINEAR_VSUM_MUL",LINEAR_VSUM_MUL;
+"LINEAR_ZERO",LINEAR_ZERO;
+"LINEPATH_CX",LINEPATH_CX;
+"LINEPATH_IN_PATH",LINEPATH_IN_PATH;
+"LINEPATH_LINEAR_IMAGE",LINEPATH_LINEAR_IMAGE;
+"LINEPATH_REFL",LINEPATH_REFL;
+"LINEPATH_TRANSLATION",LINEPATH_TRANSLATION;
+"LINSEG_FL",LINSEG_FL;
+"LINSEG_INSEG",LINSEG_INSEG;
+"LINSEG_WOSET",LINSEG_WOSET;
+"LIOUVILLE_THEOREM",LIOUVILLE_THEOREM;
+"LIOUVILLE_WEAK",LIOUVILLE_WEAK;
+"LIOUVILLE_WEAK_INVERSE",LIOUVILLE_WEAK_INVERSE;
+"LIPSCHITZ_REAL_POLYNOMIAL_FUNCTION",LIPSCHITZ_REAL_POLYNOMIAL_FUNCTION;
+"LIPSCHITZ_VECTOR_POLYNOMIAL_FUNCTION",LIPSCHITZ_VECTOR_POLYNOMIAL_FUNCTION;
+"LIST_OF_SET_PROPERTIES",LIST_OF_SET_PROPERTIES;
+"LITTLE_PICARD",LITTLE_PICARD;
+"LOCALLY_CLOSED",LOCALLY_CLOSED;
+"LOCALLY_COMPACT",LOCALLY_COMPACT;
+"LOCALLY_COMPACT_CLOSED_IN",LOCALLY_COMPACT_CLOSED_IN;
+"LOCALLY_COMPACT_CLOSED_IN_OPEN",LOCALLY_COMPACT_CLOSED_IN_OPEN;
+"LOCALLY_COMPACT_HOMEOMORPHIC_CLOSED",LOCALLY_COMPACT_HOMEOMORPHIC_CLOSED;
+"LOCALLY_COMPACT_HOMEOMORPHISM_PROJECTION_CLOSED",LOCALLY_COMPACT_HOMEOMORPHISM_PROJECTION_CLOSED;
+"LOCALLY_COMPACT_INTER",LOCALLY_COMPACT_INTER;
+"LOCALLY_COMPACT_LINEAR_IMAGE_EQ",LOCALLY_COMPACT_LINEAR_IMAGE_EQ;
+"LOCALLY_COMPACT_OPEN_IN",LOCALLY_COMPACT_OPEN_IN;
+"LOCALLY_COMPACT_OPEN_INTER_CLOSURE",LOCALLY_COMPACT_OPEN_INTER_CLOSURE;
+"LOCALLY_COMPACT_TRANSLATION_EQ",LOCALLY_COMPACT_TRANSLATION_EQ;
+"LOCALLY_COMPACT_UNIV",LOCALLY_COMPACT_UNIV;
+"LOCALLY_CONNECTED",LOCALLY_CONNECTED;
+"LOCALLY_CONNECTED_COMPONENTS",LOCALLY_CONNECTED_COMPONENTS;
+"LOCALLY_CONNECTED_CONNECTED_COMPONENT",LOCALLY_CONNECTED_CONNECTED_COMPONENT;
+"LOCALLY_CONNECTED_CONTINUOUS_IMAGE_COMPACT",LOCALLY_CONNECTED_CONTINUOUS_IMAGE_COMPACT;
+"LOCALLY_CONNECTED_IM_KLEINEN",LOCALLY_CONNECTED_IM_KLEINEN;
+"LOCALLY_CONNECTED_LEFT_INVERTIBLE_IMAGE",LOCALLY_CONNECTED_LEFT_INVERTIBLE_IMAGE;
+"LOCALLY_CONNECTED_LINEAR_IMAGE_EQ",LOCALLY_CONNECTED_LINEAR_IMAGE_EQ;
+"LOCALLY_CONNECTED_OPEN_COMPONENT",LOCALLY_CONNECTED_OPEN_COMPONENT;
+"LOCALLY_CONNECTED_OPEN_CONNECTED_COMPONENT",LOCALLY_CONNECTED_OPEN_CONNECTED_COMPONENT;
+"LOCALLY_CONNECTED_PATH_IMAGE",LOCALLY_CONNECTED_PATH_IMAGE;
+"LOCALLY_CONNECTED_PCROSS",LOCALLY_CONNECTED_PCROSS;
+"LOCALLY_CONNECTED_PCROSS_EQ",LOCALLY_CONNECTED_PCROSS_EQ;
+"LOCALLY_CONNECTED_QUOTIENT_IMAGE",LOCALLY_CONNECTED_QUOTIENT_IMAGE;
+"LOCALLY_CONNECTED_RIGHT_INVERTIBLE_IMAGE",LOCALLY_CONNECTED_RIGHT_INVERTIBLE_IMAGE;
+"LOCALLY_CONNECTED_SPHERE",LOCALLY_CONNECTED_SPHERE;
+"LOCALLY_CONNECTED_SPHERE_GEN",LOCALLY_CONNECTED_SPHERE_GEN;
+"LOCALLY_CONNECTED_TRANSLATION_EQ",LOCALLY_CONNECTED_TRANSLATION_EQ;
+"LOCALLY_CONNECTED_UNIV",LOCALLY_CONNECTED_UNIV;
+"LOCALLY_DIFF_CLOSED",LOCALLY_DIFF_CLOSED;
+"LOCALLY_EMPTY",LOCALLY_EMPTY;
+"LOCALLY_INJECTIVE_LINEAR_IMAGE",LOCALLY_INJECTIVE_LINEAR_IMAGE;
+"LOCALLY_INTER",LOCALLY_INTER;
+"LOCALLY_MONO",LOCALLY_MONO;
+"LOCALLY_OPEN_MAP_IMAGE",LOCALLY_OPEN_MAP_IMAGE;
+"LOCALLY_OPEN_SUBSET",LOCALLY_OPEN_SUBSET;
+"LOCALLY_PATH_CONNECTED",LOCALLY_PATH_CONNECTED;
+"LOCALLY_PATH_CONNECTED_COMPONENTS",LOCALLY_PATH_CONNECTED_COMPONENTS;
+"LOCALLY_PATH_CONNECTED_CONNECTED_COMPONENT",LOCALLY_PATH_CONNECTED_CONNECTED_COMPONENT;
+"LOCALLY_PATH_CONNECTED_CONTINUOUS_IMAGE_COMPACT",LOCALLY_PATH_CONNECTED_CONTINUOUS_IMAGE_COMPACT;
+"LOCALLY_PATH_CONNECTED_IMP_LOCALLY_CONNECTED",LOCALLY_PATH_CONNECTED_IMP_LOCALLY_CONNECTED;
+"LOCALLY_PATH_CONNECTED_IM_KLEINEN",LOCALLY_PATH_CONNECTED_IM_KLEINEN;
+"LOCALLY_PATH_CONNECTED_LEFT_INVERTIBLE_IMAGE",LOCALLY_PATH_CONNECTED_LEFT_INVERTIBLE_IMAGE;
+"LOCALLY_PATH_CONNECTED_LINEAR_IMAGE_EQ",LOCALLY_PATH_CONNECTED_LINEAR_IMAGE_EQ;
+"LOCALLY_PATH_CONNECTED_OPEN_PATH_COMPONENT",LOCALLY_PATH_CONNECTED_OPEN_PATH_COMPONENT;
+"LOCALLY_PATH_CONNECTED_PATH_COMPONENT",LOCALLY_PATH_CONNECTED_PATH_COMPONENT;
+"LOCALLY_PATH_CONNECTED_PATH_IMAGE",LOCALLY_PATH_CONNECTED_PATH_IMAGE;
+"LOCALLY_PATH_CONNECTED_PCROSS",LOCALLY_PATH_CONNECTED_PCROSS;
+"LOCALLY_PATH_CONNECTED_PCROSS_EQ",LOCALLY_PATH_CONNECTED_PCROSS_EQ;
+"LOCALLY_PATH_CONNECTED_QUOTIENT_IMAGE",LOCALLY_PATH_CONNECTED_QUOTIENT_IMAGE;
+"LOCALLY_PATH_CONNECTED_RIGHT_INVERTIBLE_IMAGE",LOCALLY_PATH_CONNECTED_RIGHT_INVERTIBLE_IMAGE;
+"LOCALLY_PATH_CONNECTED_SPHERE",LOCALLY_PATH_CONNECTED_SPHERE;
+"LOCALLY_PATH_CONNECTED_SPHERE_GEN",LOCALLY_PATH_CONNECTED_SPHERE_GEN;
+"LOCALLY_PATH_CONNECTED_TRANSLATION_EQ",LOCALLY_PATH_CONNECTED_TRANSLATION_EQ;
+"LOCALLY_PATH_CONNECTED_UNIV",LOCALLY_PATH_CONNECTED_UNIV;
+"LOCALLY_PCROSS",LOCALLY_PCROSS;
+"LOCALLY_SING",LOCALLY_SING;
+"LOCALLY_TRANSLATION",LOCALLY_TRANSLATION;
+"LOG_1",LOG_1;
+"LOG_DIV",LOG_DIV;
+"LOG_EXP",LOG_EXP;
+"LOG_INJ",LOG_INJ;
+"LOG_INV",LOG_INV;
+"LOG_LE",LOG_LE;
+"LOG_LT_X",LOG_LT_X;
+"LOG_MONO_LE",LOG_MONO_LE;
+"LOG_MONO_LE_IMP",LOG_MONO_LE_IMP;
+"LOG_MONO_LT",LOG_MONO_LT;
+"LOG_MONO_LT_IMP",LOG_MONO_LT_IMP;
+"LOG_MUL",LOG_MUL;
+"LOG_POS",LOG_POS;
+"LOG_POS_LT",LOG_POS_LT;
+"LOG_POW",LOG_POW;
+"LOG_ROOT",LOG_ROOT;
+"LOWDIM_EQ_HYPERPLANE",LOWDIM_EQ_HYPERPLANE;
+"LOWDIM_EXPAND_BASIS",LOWDIM_EXPAND_BASIS;
+"LOWDIM_EXPAND_DIMENSION",LOWDIM_EXPAND_DIMENSION;
+"LOWDIM_SUBSET_HYPERPLANE",LOWDIM_SUBSET_HYPERPLANE;
+"LOWER_BOUND_FINITE_SET",LOWER_BOUND_FINITE_SET;
+"LOWER_BOUND_FINITE_SET_REAL",LOWER_BOUND_FINITE_SET_REAL;
+"LT",LT;
+"LTE_ADD2",LTE_ADD2;
+"LTE_ANTISYM",LTE_ANTISYM;
+"LTE_CASES",LTE_CASES;
+"LTE_TRANS",LTE_TRANS;
+"LT_0",LT_0;
+"LT_ADD",LT_ADD;
+"LT_ADD2",LT_ADD2;
+"LT_ADDR",LT_ADDR;
+"LT_ADD_LCANCEL",LT_ADD_LCANCEL;
+"LT_ADD_RCANCEL",LT_ADD_RCANCEL;
+"LT_ANTISYM",LT_ANTISYM;
+"LT_CASES",LT_CASES;
+"LT_EXISTS",LT_EXISTS;
+"LT_EXP",LT_EXP;
+"LT_IMP_LE",LT_IMP_LE;
+"LT_LE",LT_LE;
+"LT_LMULT",LT_LMULT;
+"LT_MULT",LT_MULT;
+"LT_MULT2",LT_MULT2;
+"LT_MULT_LCANCEL",LT_MULT_LCANCEL;
+"LT_MULT_RCANCEL",LT_MULT_RCANCEL;
+"LT_NZ",LT_NZ;
+"LT_POW2_REFL",LT_POW2_REFL;
+"LT_REFL",LT_REFL;
+"LT_SUC",LT_SUC;
+"LT_SUC_LE",LT_SUC_LE;
+"LT_TRANS",LT_TRANS;
+"LUZIN",LUZIN;
+"LUZIN_EQ",LUZIN_EQ;
+"LUZIN_EQ_ALT",LUZIN_EQ_ALT;
+"MAP",MAP;
+"MAP2",MAP2;
+"MAP2_DEF",MAP2_DEF;
+"MAP_APPEND",MAP_APPEND;
+"MAP_EQ",MAP_EQ;
+"MAP_EQ_ALL2",MAP_EQ_ALL2;
+"MAP_EQ_DEGEN",MAP_EQ_DEGEN;
+"MAP_EQ_NIL",MAP_EQ_NIL;
+"MAP_FST_ZIP",MAP_FST_ZIP;
+"MAP_I",MAP_I;
+"MAP_ID",MAP_ID;
+"MAP_REVERSE",MAP_REVERSE;
+"MAP_SND_ZIP",MAP_SND_ZIP;
+"MAP_o",MAP_o;
+"MATCH_SEQPATTERN",MATCH_SEQPATTERN;
+"MATRIX_ADD_AC",MATRIX_ADD_AC;
+"MATRIX_ADD_ASSOC",MATRIX_ADD_ASSOC;
+"MATRIX_ADD_COMPONENT",MATRIX_ADD_COMPONENT;
+"MATRIX_ADD_LDISTRIB",MATRIX_ADD_LDISTRIB;
+"MATRIX_ADD_LID",MATRIX_ADD_LID;
+"MATRIX_ADD_LNEG",MATRIX_ADD_LNEG;
+"MATRIX_ADD_RDISTRIB",MATRIX_ADD_RDISTRIB;
+"MATRIX_ADD_RID",MATRIX_ADD_RID;
+"MATRIX_ADD_RNEG",MATRIX_ADD_RNEG;
+"MATRIX_ADD_SYM",MATRIX_ADD_SYM;
+"MATRIX_ADJOINT",MATRIX_ADJOINT;
+"MATRIX_CMUL_ADD_LDISTRIB",MATRIX_CMUL_ADD_LDISTRIB;
+"MATRIX_CMUL_ADD_RDISTRIB",MATRIX_CMUL_ADD_RDISTRIB;
+"MATRIX_CMUL_ASSOC",MATRIX_CMUL_ASSOC;
+"MATRIX_CMUL_COMPONENT",MATRIX_CMUL_COMPONENT;
+"MATRIX_CMUL_LID",MATRIX_CMUL_LID;
+"MATRIX_CMUL_LZERO",MATRIX_CMUL_LZERO;
+"MATRIX_CMUL_RZERO",MATRIX_CMUL_RZERO;
+"MATRIX_CMUL_SUB_LDISTRIB",MATRIX_CMUL_SUB_LDISTRIB;
+"MATRIX_CMUL_SUB_RDISTRIB",MATRIX_CMUL_SUB_RDISTRIB;
+"MATRIX_COMPOSE",MATRIX_COMPOSE;
+"MATRIX_EQ",MATRIX_EQ;
+"MATRIX_EQUAL_COLUMNS",MATRIX_EQUAL_COLUMNS;
+"MATRIX_EQUAL_ROWS",MATRIX_EQUAL_ROWS;
+"MATRIX_FULL_LINEAR_EQUATIONS",MATRIX_FULL_LINEAR_EQUATIONS;
+"MATRIX_I",MATRIX_I;
+"MATRIX_ID",MATRIX_ID;
+"MATRIX_INV",MATRIX_INV;
+"MATRIX_INVERTIBLE",MATRIX_INVERTIBLE;
+"MATRIX_INV_COFACTOR",MATRIX_INV_COFACTOR;
+"MATRIX_INV_I",MATRIX_INV_I;
+"MATRIX_INV_MUL",MATRIX_INV_MUL;
+"MATRIX_INV_UNIQUE",MATRIX_INV_UNIQUE;
+"MATRIX_INV_UNIQUE_LEFT",MATRIX_INV_UNIQUE_LEFT;
+"MATRIX_INV_UNIQUE_RIGHT",MATRIX_INV_UNIQUE_RIGHT;
+"MATRIX_LEFT_INVERSE_COFACTOR",MATRIX_LEFT_INVERSE_COFACTOR;
+"MATRIX_LEFT_INVERTIBLE",MATRIX_LEFT_INVERTIBLE;
+"MATRIX_LEFT_INVERTIBLE_INDEPENDENT_COLUMNS",MATRIX_LEFT_INVERTIBLE_INDEPENDENT_COLUMNS;
+"MATRIX_LEFT_INVERTIBLE_INJECTIVE",MATRIX_LEFT_INVERTIBLE_INJECTIVE;
+"MATRIX_LEFT_INVERTIBLE_KER",MATRIX_LEFT_INVERTIBLE_KER;
+"MATRIX_LEFT_INVERTIBLE_SPAN_ROWS",MATRIX_LEFT_INVERTIBLE_SPAN_ROWS;
+"MATRIX_LEFT_RIGHT_INVERSE",MATRIX_LEFT_RIGHT_INVERSE;
+"MATRIX_MUL_ASSOC",MATRIX_MUL_ASSOC;
+"MATRIX_MUL_COMPONENT",MATRIX_MUL_COMPONENT;
+"MATRIX_MUL_DOT",MATRIX_MUL_DOT;
+"MATRIX_MUL_LEFT_COFACTOR",MATRIX_MUL_LEFT_COFACTOR;
+"MATRIX_MUL_LID",MATRIX_MUL_LID;
+"MATRIX_MUL_LINV",MATRIX_MUL_LINV;
+"MATRIX_MUL_LMUL",MATRIX_MUL_LMUL;
+"MATRIX_MUL_LNEG",MATRIX_MUL_LNEG;
+"MATRIX_MUL_LTRANSP_DOT_COLUMN",MATRIX_MUL_LTRANSP_DOT_COLUMN;
+"MATRIX_MUL_LZERO",MATRIX_MUL_LZERO;
+"MATRIX_MUL_RID",MATRIX_MUL_RID;
+"MATRIX_MUL_RIGHT_COFACTOR",MATRIX_MUL_RIGHT_COFACTOR;
+"MATRIX_MUL_RINV",MATRIX_MUL_RINV;
+"MATRIX_MUL_RMUL",MATRIX_MUL_RMUL;
+"MATRIX_MUL_RNEG",MATRIX_MUL_RNEG;
+"MATRIX_MUL_RTRANSP_DOT_ROW",MATRIX_MUL_RTRANSP_DOT_ROW;
+"MATRIX_MUL_RZERO",MATRIX_MUL_RZERO;
+"MATRIX_MUL_VSUM",MATRIX_MUL_VSUM;
+"MATRIX_MUL_VSUM_ALT",MATRIX_MUL_VSUM_ALT;
+"MATRIX_NEG_0",MATRIX_NEG_0;
+"MATRIX_NEG_ADD",MATRIX_NEG_ADD;
+"MATRIX_NEG_COMPONENT",MATRIX_NEG_COMPONENT;
+"MATRIX_NEG_EQ_0",MATRIX_NEG_EQ_0;
+"MATRIX_NEG_MINUS1",MATRIX_NEG_MINUS1;
+"MATRIX_NEG_NEG",MATRIX_NEG_NEG;
+"MATRIX_NEG_SUB",MATRIX_NEG_SUB;
+"MATRIX_NONFULL_LINEAR_EQUATIONS",MATRIX_NONFULL_LINEAR_EQUATIONS;
+"MATRIX_NONFULL_LINEAR_EQUATIONS_EQ",MATRIX_NONFULL_LINEAR_EQUATIONS_EQ;
+"MATRIX_OF_MATRIX_VECTOR_MUL",MATRIX_OF_MATRIX_VECTOR_MUL;
+"MATRIX_REFLECT_ALONG_BASIS",MATRIX_REFLECT_ALONG_BASIS;
+"MATRIX_RIGHT_INVERSE_COFACTOR",MATRIX_RIGHT_INVERSE_COFACTOR;
+"MATRIX_RIGHT_INVERTIBLE",MATRIX_RIGHT_INVERTIBLE;
+"MATRIX_RIGHT_INVERTIBLE_INDEPENDENT_ROWS",MATRIX_RIGHT_INVERTIBLE_INDEPENDENT_ROWS;
+"MATRIX_RIGHT_INVERTIBLE_SPAN_COLUMNS",MATRIX_RIGHT_INVERTIBLE_SPAN_COLUMNS;
+"MATRIX_RIGHT_INVERTIBLE_SURJECTIVE",MATRIX_RIGHT_INVERTIBLE_SURJECTIVE;
+"MATRIX_ROTATE2D",MATRIX_ROTATE2D;
+"MATRIX_SELF_ADJOINT",MATRIX_SELF_ADJOINT;
+"MATRIX_SUB",MATRIX_SUB;
+"MATRIX_SUB_COMPONENT",MATRIX_SUB_COMPONENT;
+"MATRIX_SUB_LDISTRIB",MATRIX_SUB_LDISTRIB;
+"MATRIX_SUB_LZERO",MATRIX_SUB_LZERO;
+"MATRIX_SUB_RDISTRIB",MATRIX_SUB_RDISTRIB;
+"MATRIX_SUB_REFL",MATRIX_SUB_REFL;
+"MATRIX_SUB_RZERO",MATRIX_SUB_RZERO;
+"MATRIX_TRANSP_MUL",MATRIX_TRANSP_MUL;
+"MATRIX_TRIVIAL_LINEAR_EQUATIONS",MATRIX_TRIVIAL_LINEAR_EQUATIONS;
+"MATRIX_VECTOR_COLUMN",MATRIX_VECTOR_COLUMN;
+"MATRIX_VECTOR_MUL",MATRIX_VECTOR_MUL;
+"MATRIX_VECTOR_MUL_ADD_LDISTRIB",MATRIX_VECTOR_MUL_ADD_LDISTRIB;
+"MATRIX_VECTOR_MUL_ADD_RDISTRIB",MATRIX_VECTOR_MUL_ADD_RDISTRIB;
+"MATRIX_VECTOR_MUL_ASSOC",MATRIX_VECTOR_MUL_ASSOC;
+"MATRIX_VECTOR_MUL_BASIS",MATRIX_VECTOR_MUL_BASIS;
+"MATRIX_VECTOR_MUL_COMPONENT",MATRIX_VECTOR_MUL_COMPONENT;
+"MATRIX_VECTOR_MUL_INJECTIVE_ON_ROWSPACE",MATRIX_VECTOR_MUL_INJECTIVE_ON_ROWSPACE;
+"MATRIX_VECTOR_MUL_IN_COLUMNSPACE",MATRIX_VECTOR_MUL_IN_COLUMNSPACE;
+"MATRIX_VECTOR_MUL_LID",MATRIX_VECTOR_MUL_LID;
+"MATRIX_VECTOR_MUL_LINEAR",MATRIX_VECTOR_MUL_LINEAR;
+"MATRIX_VECTOR_MUL_LZERO",MATRIX_VECTOR_MUL_LZERO;
+"MATRIX_VECTOR_MUL_RMUL",MATRIX_VECTOR_MUL_RMUL;
+"MATRIX_VECTOR_MUL_RZERO",MATRIX_VECTOR_MUL_RZERO;
+"MATRIX_VECTOR_MUL_SUB_LDISTRIB",MATRIX_VECTOR_MUL_SUB_LDISTRIB;
+"MATRIX_VECTOR_MUL_SUB_RDISTRIB",MATRIX_VECTOR_MUL_SUB_RDISTRIB;
+"MATRIX_VECTOR_MUL_TRANSP",MATRIX_VECTOR_MUL_TRANSP;
+"MATRIX_WLOG_INVERTIBLE",MATRIX_WLOG_INVERTIBLE;
+"MATRIX_WORKS",MATRIX_WORKS;
+"MAT_0_COMPONENT",MAT_0_COMPONENT;
+"MAT_COMPONENT",MAT_COMPONENT;
+"MAX",MAX;
+"MAXIMAL_AFFINE_INDEPENDENT_SUBSET",MAXIMAL_AFFINE_INDEPENDENT_SUBSET;
+"MAXIMAL_AFFINE_INDEPENDENT_SUBSET_AFFINE",MAXIMAL_AFFINE_INDEPENDENT_SUBSET_AFFINE;
+"MAXIMAL_INDEPENDENT_SUBSET",MAXIMAL_INDEPENDENT_SUBSET;
+"MAXIMAL_INDEPENDENT_SUBSET_EXTEND",MAXIMAL_INDEPENDENT_SUBSET_EXTEND;
+"MAXIMUM_MODULUS_PRINCIPLE",MAXIMUM_MODULUS_PRINCIPLE;
+"MBASIS_COMPONENT",MBASIS_COMPONENT;
+"MBASIS_EQ_0",MBASIS_EQ_0;
+"MBASIS_EXPANSION",MBASIS_EXPANSION;
+"MBASIS_EXTENSION",MBASIS_EXTENSION;
+"MBASIS_NONZERO",MBASIS_NONZERO;
+"MBASIS_SPLIT",MBASIS_SPLIT;
+"MEASURABLE",MEASURABLE;
+"MEASURABLE_ADDITIVE_IMP_LINEAR",MEASURABLE_ADDITIVE_IMP_LINEAR;
+"MEASURABLE_ALMOST",MEASURABLE_ALMOST;
+"MEASURABLE_BALL",MEASURABLE_BALL;
+"MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_ABSOLUTELY_INTEGRABLE",MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_ABSOLUTELY_INTEGRABLE;
+"MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE",MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE;
+"MEASURABLE_CBALL",MEASURABLE_CBALL;
+"MEASURABLE_CLOSURE",MEASURABLE_CLOSURE;
+"MEASURABLE_COMPACT",MEASURABLE_COMPACT;
+"MEASURABLE_CONVEX",MEASURABLE_CONVEX;
+"MEASURABLE_CONVEX_HULL",MEASURABLE_CONVEX_HULL;
+"MEASURABLE_COUNTABLE_INTERS",MEASURABLE_COUNTABLE_INTERS;
+"MEASURABLE_COUNTABLE_INTERS_GEN",MEASURABLE_COUNTABLE_INTERS_GEN;
+"MEASURABLE_COUNTABLE_UNIONS",MEASURABLE_COUNTABLE_UNIONS;
+"MEASURABLE_COUNTABLE_UNIONS_BOUNDED",MEASURABLE_COUNTABLE_UNIONS_BOUNDED;
+"MEASURABLE_COUNTABLE_UNIONS_STRONG",MEASURABLE_COUNTABLE_UNIONS_STRONG;
+"MEASURABLE_DIFF",MEASURABLE_DIFF;
+"MEASURABLE_ELEMENTARY",MEASURABLE_ELEMENTARY;
+"MEASURABLE_EMPTY",MEASURABLE_EMPTY;
+"MEASURABLE_FRONTIER",MEASURABLE_FRONTIER;
+"MEASURABLE_IMP_LEBESGUE_MEASURABLE",MEASURABLE_IMP_LEBESGUE_MEASURABLE;
+"MEASURABLE_INNER_COMPACT",MEASURABLE_INNER_COMPACT;
+"MEASURABLE_INNER_OUTER",MEASURABLE_INNER_OUTER;
+"MEASURABLE_INSERT",MEASURABLE_INSERT;
+"MEASURABLE_INSIDE",MEASURABLE_INSIDE;
+"MEASURABLE_INTEGRABLE",MEASURABLE_INTEGRABLE;
+"MEASURABLE_INTER",MEASURABLE_INTER;
+"MEASURABLE_INTERIOR",MEASURABLE_INTERIOR;
+"MEASURABLE_INTERVAL",MEASURABLE_INTERVAL;
+"MEASURABLE_INTER_HALFSPACE_GE",MEASURABLE_INTER_HALFSPACE_GE;
+"MEASURABLE_INTER_HALFSPACE_LE",MEASURABLE_INTER_HALFSPACE_LE;
+"MEASURABLE_INTER_INTERVAL",MEASURABLE_INTER_INTERVAL;
+"MEASURABLE_JORDAN",MEASURABLE_JORDAN;
+"MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE",MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE;
+"MEASURABLE_LEGESGUE_MEASURABLE_SUBSET",MEASURABLE_LEGESGUE_MEASURABLE_SUBSET;
+"MEASURABLE_LINEAR_IMAGE",MEASURABLE_LINEAR_IMAGE;
+"MEASURABLE_LINEAR_IMAGE_EQ",MEASURABLE_LINEAR_IMAGE_EQ;
+"MEASURABLE_LINEAR_IMAGE_INTERVAL",MEASURABLE_LINEAR_IMAGE_INTERVAL;
+"MEASURABLE_MEASURABLE_DIFF_LEGESGUE_MEASURABLE",MEASURABLE_MEASURABLE_DIFF_LEGESGUE_MEASURABLE;
+"MEASURABLE_MEASURABLE_INTER_LEGESGUE_MEASURABLE",MEASURABLE_MEASURABLE_INTER_LEGESGUE_MEASURABLE;
+"MEASURABLE_MEASURABLE_PREIMAGE_CLOSED",MEASURABLE_MEASURABLE_PREIMAGE_CLOSED;
+"MEASURABLE_MEASURABLE_PREIMAGE_OPEN",MEASURABLE_MEASURABLE_PREIMAGE_OPEN;
+"MEASURABLE_MEASURE_EQ_0",MEASURABLE_MEASURE_EQ_0;
+"MEASURABLE_MEASURE_POS_LT",MEASURABLE_MEASURE_POS_LT;
+"MEASURABLE_NEGLIGIBLE_SYMDIFF",MEASURABLE_NEGLIGIBLE_SYMDIFF;
+"MEASURABLE_NEGLIGIBLE_SYMDIFF_EQ",MEASURABLE_NEGLIGIBLE_SYMDIFF_EQ;
+"MEASURABLE_NESTED_UNIONS",MEASURABLE_NESTED_UNIONS;
+"MEASURABLE_NONNEGLIGIBLE_IMP_LARGE",MEASURABLE_NONNEGLIGIBLE_IMP_LARGE;
+"MEASURABLE_ON_0",MEASURABLE_ON_0;
+"MEASURABLE_ON_ADD",MEASURABLE_ON_ADD;
+"MEASURABLE_ON_CASES",MEASURABLE_ON_CASES;
+"MEASURABLE_ON_CMUL",MEASURABLE_ON_CMUL;
+"MEASURABLE_ON_COMBINE",MEASURABLE_ON_COMBINE;
+"MEASURABLE_ON_COMPLEX_DIV",MEASURABLE_ON_COMPLEX_DIV;
+"MEASURABLE_ON_COMPLEX_INV",MEASURABLE_ON_COMPLEX_INV;
+"MEASURABLE_ON_COMPLEX_MUL",MEASURABLE_ON_COMPLEX_MUL;
+"MEASURABLE_ON_COMPONENTWISE",MEASURABLE_ON_COMPONENTWISE;
+"MEASURABLE_ON_COMPOSE_CONTINUOUS",MEASURABLE_ON_COMPOSE_CONTINUOUS;
+"MEASURABLE_ON_COMPOSE_CONTINUOUS_0",MEASURABLE_ON_COMPOSE_CONTINUOUS_0;
+"MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET",MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET;
+"MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET_0",MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET_0;
+"MEASURABLE_ON_COMPOSE_CONTINUOUS_OPEN_INTERVAL",MEASURABLE_ON_COMPOSE_CONTINUOUS_OPEN_INTERVAL;
+"MEASURABLE_ON_CONST",MEASURABLE_ON_CONST;
+"MEASURABLE_ON_COUNTABLE_UNIONS",MEASURABLE_ON_COUNTABLE_UNIONS;
+"MEASURABLE_ON_DIFF",MEASURABLE_ON_DIFF;
+"MEASURABLE_ON_DROP_MUL",MEASURABLE_ON_DROP_MUL;
+"MEASURABLE_ON_EMPTY",MEASURABLE_ON_EMPTY;
+"MEASURABLE_ON_INTER",MEASURABLE_ON_INTER;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED_EQ",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED_EQ;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED_INTERVAL",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED_INTERVAL;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_EQ",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_EQ;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_INTERVAL",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_INTERVAL;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET",MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET;
+"MEASURABLE_ON_LIFT_MUL",MEASURABLE_ON_LIFT_MUL;
+"MEASURABLE_ON_LIMIT",MEASURABLE_ON_LIMIT;
+"MEASURABLE_ON_LINEAR_IMAGE_EQ",MEASURABLE_ON_LINEAR_IMAGE_EQ;
+"MEASURABLE_ON_MAX",MEASURABLE_ON_MAX;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED",MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED_EQ",MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED_EQ;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED_INTERVAL",MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED_INTERVAL;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_EQ",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_EQ;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_INTERVAL",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_INTERVAL;
+"MEASURABLE_ON_MEASURABLE_SUBSET",MEASURABLE_ON_MEASURABLE_SUBSET;
+"MEASURABLE_ON_MIN",MEASURABLE_ON_MIN;
+"MEASURABLE_ON_NEG",MEASURABLE_ON_NEG;
+"MEASURABLE_ON_NEG_EQ",MEASURABLE_ON_NEG_EQ;
+"MEASURABLE_ON_NORM",MEASURABLE_ON_NORM;
+"MEASURABLE_ON_PASTECART",MEASURABLE_ON_PASTECART;
+"MEASURABLE_ON_PREIMAGE_CLOSED",MEASURABLE_ON_PREIMAGE_CLOSED;
+"MEASURABLE_ON_PREIMAGE_CLOSED_INTERVAL",MEASURABLE_ON_PREIMAGE_CLOSED_INTERVAL;
+"MEASURABLE_ON_PREIMAGE_OPEN",MEASURABLE_ON_PREIMAGE_OPEN;
+"MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE",MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE;
+"MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT",MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT;
+"MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE",MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE;
+"MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT",MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT;
+"MEASURABLE_ON_PREIMAGE_OPEN_INTERVAL",MEASURABLE_ON_PREIMAGE_OPEN_INTERVAL;
+"MEASURABLE_ON_RESTRICT",MEASURABLE_ON_RESTRICT;
+"MEASURABLE_ON_SIMPLE_FUNCTION_LIMIT",MEASURABLE_ON_SIMPLE_FUNCTION_LIMIT;
+"MEASURABLE_ON_SPIKE",MEASURABLE_ON_SPIKE;
+"MEASURABLE_ON_SPIKE_SET",MEASURABLE_ON_SPIKE_SET;
+"MEASURABLE_ON_SUB",MEASURABLE_ON_SUB;
+"MEASURABLE_ON_TRANSLATION",MEASURABLE_ON_TRANSLATION;
+"MEASURABLE_ON_TRANSLATION_EQ",MEASURABLE_ON_TRANSLATION_EQ;
+"MEASURABLE_ON_UNION",MEASURABLE_ON_UNION;
+"MEASURABLE_ON_UNIONS",MEASURABLE_ON_UNIONS;
+"MEASURABLE_ON_UNIV",MEASURABLE_ON_UNIV;
+"MEASURABLE_ON_VECTOR_DERIVATIVE",MEASURABLE_ON_VECTOR_DERIVATIVE;
+"MEASURABLE_ON_VSUM",MEASURABLE_ON_VSUM;
+"MEASURABLE_OPEN",MEASURABLE_OPEN;
+"MEASURABLE_OUTER_CLOSED_INTERVALS",MEASURABLE_OUTER_CLOSED_INTERVALS;
+"MEASURABLE_OUTER_INTERVALS_BOUNDED",MEASURABLE_OUTER_INTERVALS_BOUNDED;
+"MEASURABLE_OUTER_INTERVALS_BOUNDED_EXPLICIT_SPECIAL",MEASURABLE_OUTER_INTERVALS_BOUNDED_EXPLICIT_SPECIAL;
+"MEASURABLE_OUTER_OPEN",MEASURABLE_OUTER_OPEN;
+"MEASURABLE_OUTER_OPEN_INTERVALS",MEASURABLE_OUTER_OPEN_INTERVALS;
+"MEASURABLE_SCALING",MEASURABLE_SCALING;
+"MEASURABLE_SCALING_EQ",MEASURABLE_SCALING_EQ;
+"MEASURABLE_SIMPLEX",MEASURABLE_SIMPLEX;
+"MEASURABLE_SMALL_IMP_NEGLIGIBLE",MEASURABLE_SMALL_IMP_NEGLIGIBLE;
+"MEASURABLE_TETRAHEDRON",MEASURABLE_TETRAHEDRON;
+"MEASURABLE_TRANSLATION",MEASURABLE_TRANSLATION;
+"MEASURABLE_TRANSLATION_EQ",MEASURABLE_TRANSLATION_EQ;
+"MEASURABLE_TRIANGLE",MEASURABLE_TRIANGLE;
+"MEASURABLE_UNION",MEASURABLE_UNION;
+"MEASURABLE_UNIONS",MEASURABLE_UNIONS;
+"MEASURE",MEASURE;
+"MEASURE_BALL_BOUND",MEASURE_BALL_BOUND;
+"MEASURE_BALL_POS",MEASURE_BALL_POS;
+"MEASURE_CBALL_BOUND",MEASURE_CBALL_BOUND;
+"MEASURE_CBALL_POS",MEASURE_CBALL_POS;
+"MEASURE_CLOSURE",MEASURE_CLOSURE;
+"MEASURE_COUNTABLE_UNIONS_APPROACHABLE",MEASURE_COUNTABLE_UNIONS_APPROACHABLE;
+"MEASURE_COUNTABLE_UNIONS_LE",MEASURE_COUNTABLE_UNIONS_LE;
+"MEASURE_COUNTABLE_UNIONS_LE_GEN",MEASURE_COUNTABLE_UNIONS_LE_GEN;
+"MEASURE_COUNTABLE_UNIONS_LE_STRONG",MEASURE_COUNTABLE_UNIONS_LE_STRONG;
+"MEASURE_COUNTABLE_UNIONS_LE_STRONG_GEN",MEASURE_COUNTABLE_UNIONS_LE_STRONG_GEN;
+"MEASURE_DIFF_SUBSET",MEASURE_DIFF_SUBSET;
+"MEASURE_DISJOINT_UNION",MEASURE_DISJOINT_UNION;
+"MEASURE_DISJOINT_UNIONS",MEASURE_DISJOINT_UNIONS;
+"MEASURE_DISJOINT_UNIONS_IMAGE",MEASURE_DISJOINT_UNIONS_IMAGE;
+"MEASURE_DISJOINT_UNIONS_IMAGE_STRONG",MEASURE_DISJOINT_UNIONS_IMAGE_STRONG;
+"MEASURE_DISJOINT_UNION_EQ",MEASURE_DISJOINT_UNION_EQ;
+"MEASURE_ELEMENTARY",MEASURE_ELEMENTARY;
+"MEASURE_EMPTY",MEASURE_EMPTY;
+"MEASURE_EQ_0",MEASURE_EQ_0;
+"MEASURE_FRONTIER",MEASURE_FRONTIER;
+"MEASURE_INSERT",MEASURE_INSERT;
+"MEASURE_INTEGRAL",MEASURE_INTEGRAL;
+"MEASURE_INTEGRAL_UNIV",MEASURE_INTEGRAL_UNIV;
+"MEASURE_INTERIOR",MEASURE_INTERIOR;
+"MEASURE_INTERVAL",MEASURE_INTERVAL;
+"MEASURE_INTERVAL_1",MEASURE_INTERVAL_1;
+"MEASURE_INTERVAL_1_ALT",MEASURE_INTERVAL_1_ALT;
+"MEASURE_INTERVAL_2",MEASURE_INTERVAL_2;
+"MEASURE_INTERVAL_2_ALT",MEASURE_INTERVAL_2_ALT;
+"MEASURE_INTERVAL_3",MEASURE_INTERVAL_3;
+"MEASURE_INTERVAL_3_ALT",MEASURE_INTERVAL_3_ALT;
+"MEASURE_INTERVAL_4",MEASURE_INTERVAL_4;
+"MEASURE_INTERVAL_4_ALT",MEASURE_INTERVAL_4_ALT;
+"MEASURE_LE",MEASURE_LE;
+"MEASURE_LIMIT",MEASURE_LIMIT;
+"MEASURE_LINEAR_IMAGE",MEASURE_LINEAR_IMAGE;
+"MEASURE_LINEAR_IMAGE_SAME",MEASURE_LINEAR_IMAGE_SAME;
+"MEASURE_NEGLIGIBLE_SYMDIFF",MEASURE_NEGLIGIBLE_SYMDIFF;
+"MEASURE_NEGLIGIBLE_UNION",MEASURE_NEGLIGIBLE_UNION;
+"MEASURE_NEGLIGIBLE_UNIONS",MEASURE_NEGLIGIBLE_UNIONS;
+"MEASURE_NEGLIGIBLE_UNIONS_IMAGE",MEASURE_NEGLIGIBLE_UNIONS_IMAGE;
+"MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG",MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG;
+"MEASURE_NEGLIGIBLE_UNION_EQ",MEASURE_NEGLIGIBLE_UNION_EQ;
+"MEASURE_OPEN_POS_LT",MEASURE_OPEN_POS_LT;
+"MEASURE_ORTHOGONAL_IMAGE_EQ",MEASURE_ORTHOGONAL_IMAGE_EQ;
+"MEASURE_POS_LE",MEASURE_POS_LE;
+"MEASURE_SCALING",MEASURE_SCALING;
+"MEASURE_SIMPLEX",MEASURE_SIMPLEX;
+"MEASURE_SUBSET",MEASURE_SUBSET;
+"MEASURE_TETRAHEDRON",MEASURE_TETRAHEDRON;
+"MEASURE_TRANSLATION",MEASURE_TRANSLATION;
+"MEASURE_TRIANGLE",MEASURE_TRIANGLE;
+"MEASURE_UNION",MEASURE_UNION;
+"MEASURE_UNIONS_LE",MEASURE_UNIONS_LE;
+"MEASURE_UNIONS_LE_IMAGE",MEASURE_UNIONS_LE_IMAGE;
+"MEASURE_UNION_LE",MEASURE_UNION_LE;
+"MEASURE_UNIQUE",MEASURE_UNIQUE;
+"MEM",MEM;
+"MEMBER_NOT_EMPTY",MEMBER_NOT_EMPTY;
+"MEM_APPEND",MEM_APPEND;
+"MEM_APPEND_DECOMPOSE",MEM_APPEND_DECOMPOSE;
+"MEM_APPEND_DECOMPOSE_LEFT",MEM_APPEND_DECOMPOSE_LEFT;
+"MEM_ASSOC",MEM_ASSOC;
+"MEM_EL",MEM_EL;
+"MEM_EXISTS_EL",MEM_EXISTS_EL;
+"MEM_FILTER",MEM_FILTER;
+"MEM_LINEAR_IMAGE",MEM_LINEAR_IMAGE;
+"MEM_LIST_OF_SET",MEM_LIST_OF_SET;
+"MEM_MAP",MEM_MAP;
+"MEM_TRANSLATION",MEM_TRANSLATION;
+"MIDPOINTS_IN_CONVEX_HULL",MIDPOINTS_IN_CONVEX_HULL;
+"MIDPOINT_BETWEEN",MIDPOINT_BETWEEN;
+"MIDPOINT_COLLINEAR",MIDPOINT_COLLINEAR;
+"MIDPOINT_CONVEX_DYADIC_RATIONALS",MIDPOINT_CONVEX_DYADIC_RATIONALS;
+"MIDPOINT_EQ_ENDPOINT",MIDPOINT_EQ_ENDPOINT;
+"MIDPOINT_IN_SEGMENT",MIDPOINT_IN_SEGMENT;
+"MIDPOINT_LINEAR_IMAGE",MIDPOINT_LINEAR_IMAGE;
+"MIDPOINT_REFL",MIDPOINT_REFL;
+"MIDPOINT_SYM",MIDPOINT_SYM;
+"MIN",MIN;
+"MINIMAL",MINIMAL;
+"MINIMAL_IN_INSERT",MINIMAL_IN_INSERT;
+"MK_REC_INJ",MK_REC_INJ;
+"MOD_0",MOD_0;
+"MOD_1",MOD_1;
+"MOD_ADD_MOD",MOD_ADD_MOD;
+"MOD_EQ",MOD_EQ;
+"MOD_EQ_0",MOD_EQ_0;
+"MOD_EXISTS",MOD_EXISTS;
+"MOD_EXP_MOD",MOD_EXP_MOD;
+"MOD_LE",MOD_LE;
+"MOD_LT",MOD_LT;
+"MOD_MOD",MOD_MOD;
+"MOD_MOD_EXP_MIN",MOD_MOD_EXP_MIN;
+"MOD_MOD_REFL",MOD_MOD_REFL;
+"MOD_MULT",MOD_MULT;
+"MOD_MULT2",MOD_MULT2;
+"MOD_MULT_ADD",MOD_MULT_ADD;
+"MOD_MULT_LMOD",MOD_MULT_LMOD;
+"MOD_MULT_MOD2",MOD_MULT_MOD2;
+"MOD_MULT_RMOD",MOD_MULT_RMOD;
+"MOD_NSUM_MOD",MOD_NSUM_MOD;
+"MOD_NSUM_MOD_NUMSEG",MOD_NSUM_MOD_NUMSEG;
+"MOD_UNIQ",MOD_UNIQ;
+"MOEBIUS_FUNCTION_COMPOSE",MOEBIUS_FUNCTION_COMPOSE;
+"MOEBIUS_FUNCTION_EQ_ZERO",MOEBIUS_FUNCTION_EQ_ZERO;
+"MOEBIUS_FUNCTION_HOLOMORPHIC",MOEBIUS_FUNCTION_HOLOMORPHIC;
+"MOEBIUS_FUNCTION_NORM_LT_1",MOEBIUS_FUNCTION_NORM_LT_1;
+"MOEBIUS_FUNCTION_OF_ZERO",MOEBIUS_FUNCTION_OF_ZERO;
+"MOEBIUS_FUNCTION_SIMPLE",MOEBIUS_FUNCTION_SIMPLE;
+"MONODROMY_CONTINUOUS_LOG",MONODROMY_CONTINUOUS_LOG;
+"MONOIDAL_AC",MONOIDAL_AC;
+"MONOIDAL_ADD",MONOIDAL_ADD;
+"MONOIDAL_AND",MONOIDAL_AND;
+"MONOIDAL_COMPLEX_MUL",MONOIDAL_COMPLEX_MUL;
+"MONOIDAL_LIFTED",MONOIDAL_LIFTED;
+"MONOIDAL_MUL",MONOIDAL_MUL;
+"MONOIDAL_REAL_ADD",MONOIDAL_REAL_ADD;
+"MONOIDAL_REAL_MUL",MONOIDAL_REAL_MUL;
+"MONOIDAL_VECTOR_ADD",MONOIDAL_VECTOR_ADD;
+"MONOTONE_BIGGER",MONOTONE_BIGGER;
+"MONOTONE_CONVERGENCE_DECREASING",MONOTONE_CONVERGENCE_DECREASING;
+"MONOTONE_CONVERGENCE_INCREASING",MONOTONE_CONVERGENCE_INCREASING;
+"MONOTONE_CONVERGENCE_INTERVAL",MONOTONE_CONVERGENCE_INTERVAL;
+"MONOTONE_SUBSEQUENCE",MONOTONE_SUBSEQUENCE;
+"MONO_ALL",MONO_ALL;
+"MONO_ALL2",MONO_ALL2;
+"MONO_AND",MONO_AND;
+"MONO_COND",MONO_COND;
+"MONO_EXISTS",MONO_EXISTS;
+"MONO_FORALL",MONO_FORALL;
+"MONO_IMP",MONO_IMP;
+"MONO_NOT",MONO_NOT;
+"MONO_OR",MONO_OR;
+"MONTEL",MONTEL;
+"MORERA_LOCAL_TRIANGLE",MORERA_LOCAL_TRIANGLE;
+"MORERA_LOCAL_TRIANGLE_GEN",MORERA_LOCAL_TRIANGLE_GEN;
+"MORERA_TRIANGLE",MORERA_TRIANGLE;
+"MULT",MULT;
+"MULTIVECTOR_ADD_COMPONENT",MULTIVECTOR_ADD_COMPONENT;
+"MULTIVECTOR_BETA",MULTIVECTOR_BETA;
+"MULTIVECTOR_EQ",MULTIVECTOR_EQ;
+"MULTIVECTOR_ETA",MULTIVECTOR_ETA;
+"MULTIVECTOR_GRADE",MULTIVECTOR_GRADE;
+"MULTIVECTOR_IMAGE",MULTIVECTOR_IMAGE;
+"MULTIVECTOR_MUL_COMPONENT",MULTIVECTOR_MUL_COMPONENT;
+"MULTIVECTOR_UNIQUE",MULTIVECTOR_UNIQUE;
+"MULTIVECTOR_VEC_COMPONENT",MULTIVECTOR_VEC_COMPONENT;
+"MULTIVECTOR_VSUM",MULTIVECTOR_VSUM;
+"MULTIVECTOR_VSUM_COMPONENT",MULTIVECTOR_VSUM_COMPONENT;
+"MULT_0",MULT_0;
+"MULT_2",MULT_2;
+"MULT_AC",MULT_AC;
+"MULT_ASSOC",MULT_ASSOC;
+"MULT_CLAUSES",MULT_CLAUSES;
+"MULT_DIV_LE",MULT_DIV_LE;
+"MULT_EQ_0",MULT_EQ_0;
+"MULT_EQ_1",MULT_EQ_1;
+"MULT_EXP",MULT_EXP;
+"MULT_SUC",MULT_SUC;
+"MULT_SYM",MULT_SYM;
+"MUL_C_UNIV",MUL_C_UNIV;
+"MVT",MVT;
+"MVT_GENERAL",MVT_GENERAL;
+"MVT_SIMPLE",MVT_SIMPLE;
+"MVT_VERY_SIMPLE",MVT_VERY_SIMPLE;
+"NADD_ADD",NADD_ADD;
+"NADD_ADDITIVE",NADD_ADDITIVE;
+"NADD_ADD_ASSOC",NADD_ADD_ASSOC;
+"NADD_ADD_LCANCEL",NADD_ADD_LCANCEL;
+"NADD_ADD_LID",NADD_ADD_LID;
+"NADD_ADD_SYM",NADD_ADD_SYM;
+"NADD_ADD_WELLDEF",NADD_ADD_WELLDEF;
+"NADD_ALTMUL",NADD_ALTMUL;
+"NADD_ARCH",NADD_ARCH;
+"NADD_ARCH_LEMMA",NADD_ARCH_LEMMA;
+"NADD_ARCH_MULT",NADD_ARCH_MULT;
+"NADD_ARCH_ZERO",NADD_ARCH_ZERO;
+"NADD_BOUND",NADD_BOUND;
+"NADD_CAUCHY",NADD_CAUCHY;
+"NADD_COMPLETE",NADD_COMPLETE;
+"NADD_DIST",NADD_DIST;
+"NADD_DIST_LEMMA",NADD_DIST_LEMMA;
+"NADD_EQ_IMP_LE",NADD_EQ_IMP_LE;
+"NADD_EQ_REFL",NADD_EQ_REFL;
+"NADD_EQ_SYM",NADD_EQ_SYM;
+"NADD_EQ_TRANS",NADD_EQ_TRANS;
+"NADD_INV",NADD_INV;
+"NADD_INV_0",NADD_INV_0;
+"NADD_INV_WELLDEF",NADD_INV_WELLDEF;
+"NADD_LBOUND",NADD_LBOUND;
+"NADD_LDISTRIB",NADD_LDISTRIB;
+"NADD_LE_0",NADD_LE_0;
+"NADD_LE_ADD",NADD_LE_ADD;
+"NADD_LE_ANTISYM",NADD_LE_ANTISYM;
+"NADD_LE_EXISTS",NADD_LE_EXISTS;
+"NADD_LE_LADD",NADD_LE_LADD;
+"NADD_LE_LMUL",NADD_LE_LMUL;
+"NADD_LE_RADD",NADD_LE_RADD;
+"NADD_LE_REFL",NADD_LE_REFL;
+"NADD_LE_RMUL",NADD_LE_RMUL;
+"NADD_LE_TOTAL",NADD_LE_TOTAL;
+"NADD_LE_TOTAL_LEMMA",NADD_LE_TOTAL_LEMMA;
+"NADD_LE_TRANS",NADD_LE_TRANS;
+"NADD_LE_WELLDEF",NADD_LE_WELLDEF;
+"NADD_LE_WELLDEF_LEMMA",NADD_LE_WELLDEF_LEMMA;
+"NADD_MUL",NADD_MUL;
+"NADD_MULTIPLICATIVE",NADD_MULTIPLICATIVE;
+"NADD_MUL_ASSOC",NADD_MUL_ASSOC;
+"NADD_MUL_LID",NADD_MUL_LID;
+"NADD_MUL_LINV",NADD_MUL_LINV;
+"NADD_MUL_LINV_LEMMA0",NADD_MUL_LINV_LEMMA0;
+"NADD_MUL_LINV_LEMMA1",NADD_MUL_LINV_LEMMA1;
+"NADD_MUL_LINV_LEMMA2",NADD_MUL_LINV_LEMMA2;
+"NADD_MUL_LINV_LEMMA3",NADD_MUL_LINV_LEMMA3;
+"NADD_MUL_LINV_LEMMA4",NADD_MUL_LINV_LEMMA4;
+"NADD_MUL_LINV_LEMMA5",NADD_MUL_LINV_LEMMA5;
+"NADD_MUL_LINV_LEMMA6",NADD_MUL_LINV_LEMMA6;
+"NADD_MUL_LINV_LEMMA7",NADD_MUL_LINV_LEMMA7;
+"NADD_MUL_LINV_LEMMA7a",NADD_MUL_LINV_LEMMA7a;
+"NADD_MUL_LINV_LEMMA8",NADD_MUL_LINV_LEMMA8;
+"NADD_MUL_SYM",NADD_MUL_SYM;
+"NADD_MUL_WELLDEF",NADD_MUL_WELLDEF;
+"NADD_MUL_WELLDEF_LEMMA",NADD_MUL_WELLDEF_LEMMA;
+"NADD_NONZERO",NADD_NONZERO;
+"NADD_OF_NUM",NADD_OF_NUM;
+"NADD_OF_NUM_ADD",NADD_OF_NUM_ADD;
+"NADD_OF_NUM_EQ",NADD_OF_NUM_EQ;
+"NADD_OF_NUM_LE",NADD_OF_NUM_LE;
+"NADD_OF_NUM_MUL",NADD_OF_NUM_MUL;
+"NADD_OF_NUM_WELLDEF",NADD_OF_NUM_WELLDEF;
+"NADD_RDISTRIB",NADD_RDISTRIB;
+"NADD_SUC",NADD_SUC;
+"NADD_UBOUND",NADD_UBOUND;
+"NEARBY_INVERTIBLE_MATRIX",NEARBY_INVERTIBLE_MATRIX;
+"NEGATIONS_BALL",NEGATIONS_BALL;
+"NEGATIONS_CBALL",NEGATIONS_CBALL;
+"NEGATIONS_SPHERE",NEGATIONS_SPHERE;
+"NEGLIGIBLE",NEGLIGIBLE;
+"NEGLIGIBLE_AFFINE_HULL",NEGLIGIBLE_AFFINE_HULL;
+"NEGLIGIBLE_AFFINE_HULL_1",NEGLIGIBLE_AFFINE_HULL_1;
+"NEGLIGIBLE_AFFINE_HULL_2",NEGLIGIBLE_AFFINE_HULL_2;
+"NEGLIGIBLE_AFFINE_HULL_3",NEGLIGIBLE_AFFINE_HULL_3;
+"NEGLIGIBLE_CONVEX_FRONTIER",NEGLIGIBLE_CONVEX_FRONTIER;
+"NEGLIGIBLE_CONVEX_HULL",NEGLIGIBLE_CONVEX_HULL;
+"NEGLIGIBLE_CONVEX_HULL_1",NEGLIGIBLE_CONVEX_HULL_1;
+"NEGLIGIBLE_CONVEX_HULL_2",NEGLIGIBLE_CONVEX_HULL_2;
+"NEGLIGIBLE_CONVEX_HULL_3",NEGLIGIBLE_CONVEX_HULL_3;
+"NEGLIGIBLE_COUNTABLE",NEGLIGIBLE_COUNTABLE;
+"NEGLIGIBLE_COUNTABLE_UNIONS",NEGLIGIBLE_COUNTABLE_UNIONS;
+"NEGLIGIBLE_COUNTABLE_UNIONS_GEN",NEGLIGIBLE_COUNTABLE_UNIONS_GEN;
+"NEGLIGIBLE_DELETE",NEGLIGIBLE_DELETE;
+"NEGLIGIBLE_DIFF",NEGLIGIBLE_DIFF;
+"NEGLIGIBLE_DIFFERENTIABLE_IMAGE_LOWDIM",NEGLIGIBLE_DIFFERENTIABLE_IMAGE_LOWDIM;
+"NEGLIGIBLE_DIFFERENTIABLE_IMAGE_NEGLIGIBLE",NEGLIGIBLE_DIFFERENTIABLE_IMAGE_NEGLIGIBLE;
+"NEGLIGIBLE_EMPTY",NEGLIGIBLE_EMPTY;
+"NEGLIGIBLE_EQ_MEASURE_0",NEGLIGIBLE_EQ_MEASURE_0;
+"NEGLIGIBLE_FINITE",NEGLIGIBLE_FINITE;
+"NEGLIGIBLE_FRONTIER_INTERVAL",NEGLIGIBLE_FRONTIER_INTERVAL;
+"NEGLIGIBLE_HYPERPLANE",NEGLIGIBLE_HYPERPLANE;
+"NEGLIGIBLE_IFF_LEBESGUE_MEASURABLE_SUBSETS",NEGLIGIBLE_IFF_LEBESGUE_MEASURABLE_SUBSETS;
+"NEGLIGIBLE_IFF_MEASURABLE_SUBSETS",NEGLIGIBLE_IFF_MEASURABLE_SUBSETS;
+"NEGLIGIBLE_IMAGE_BOUNDED_VARIATION_INTERVAL",NEGLIGIBLE_IMAGE_BOUNDED_VARIATION_INTERVAL;
+"NEGLIGIBLE_IMP_LEBESGUE_MEASURABLE",NEGLIGIBLE_IMP_LEBESGUE_MEASURABLE;
+"NEGLIGIBLE_IMP_MEASURABLE",NEGLIGIBLE_IMP_MEASURABLE;
+"NEGLIGIBLE_INSERT",NEGLIGIBLE_INSERT;
+"NEGLIGIBLE_INTER",NEGLIGIBLE_INTER;
+"NEGLIGIBLE_INTERVAL",NEGLIGIBLE_INTERVAL;
+"NEGLIGIBLE_LINEAR_IMAGE",NEGLIGIBLE_LINEAR_IMAGE;
+"NEGLIGIBLE_LINEAR_IMAGE_EQ",NEGLIGIBLE_LINEAR_IMAGE_EQ;
+"NEGLIGIBLE_LINEAR_SINGULAR_IMAGE",NEGLIGIBLE_LINEAR_SINGULAR_IMAGE;
+"NEGLIGIBLE_LIPSCHITZ_IMAGE_UNIV",NEGLIGIBLE_LIPSCHITZ_IMAGE_UNIV;
+"NEGLIGIBLE_LOCALLY_LIPSCHITZ_IMAGE",NEGLIGIBLE_LOCALLY_LIPSCHITZ_IMAGE;
+"NEGLIGIBLE_LOWDIM",NEGLIGIBLE_LOWDIM;
+"NEGLIGIBLE_ON_INTERVALS",NEGLIGIBLE_ON_INTERVALS;
+"NEGLIGIBLE_ON_UNIV",NEGLIGIBLE_ON_UNIV;
+"NEGLIGIBLE_OUTER",NEGLIGIBLE_OUTER;
+"NEGLIGIBLE_OUTER_LE",NEGLIGIBLE_OUTER_LE;
+"NEGLIGIBLE_RECTIFIABLE_PATH_IMAGE",NEGLIGIBLE_RECTIFIABLE_PATH_IMAGE;
+"NEGLIGIBLE_SING",NEGLIGIBLE_SING;
+"NEGLIGIBLE_SPHERE",NEGLIGIBLE_SPHERE;
+"NEGLIGIBLE_STANDARD_HYPERPLANE",NEGLIGIBLE_STANDARD_HYPERPLANE;
+"NEGLIGIBLE_SUBSET",NEGLIGIBLE_SUBSET;
+"NEGLIGIBLE_SYMDIFF_EQ",NEGLIGIBLE_SYMDIFF_EQ;
+"NEGLIGIBLE_TRANSLATION",NEGLIGIBLE_TRANSLATION;
+"NEGLIGIBLE_TRANSLATION_EQ",NEGLIGIBLE_TRANSLATION_EQ;
+"NEGLIGIBLE_TRANSLATION_REV",NEGLIGIBLE_TRANSLATION_REV;
+"NEGLIGIBLE_UNION",NEGLIGIBLE_UNION;
+"NEGLIGIBLE_UNIONS",NEGLIGIBLE_UNIONS;
+"NEGLIGIBLE_UNION_EQ",NEGLIGIBLE_UNION_EQ;
+"NEGLIGIBLE_VALID_PATH_IMAGE",NEGLIGIBLE_VALID_PATH_IMAGE;
+"NEIGHBOURHOOD_EXTENSION_INTO_ANR",NEIGHBOURHOOD_EXTENSION_INTO_ANR;
+"NEIGHBOURHOOD_EXTENSION_INTO_ANR_LOCAL",NEIGHBOURHOOD_EXTENSION_INTO_ANR_LOCAL;
+"NEIGHBOURHOOD_RETRACT_IMP_ANR",NEIGHBOURHOOD_RETRACT_IMP_ANR;
+"NEIGHBOURHOOD_RETRACT_IMP_ANR_UNIV",NEIGHBOURHOOD_RETRACT_IMP_ANR_UNIV;
+"NET",NET;
+"NETLIMIT_AT",NETLIMIT_AT;
+"NETLIMIT_ATREAL",NETLIMIT_ATREAL;
+"NETLIMIT_WITHIN",NETLIMIT_WITHIN;
+"NETLIMIT_WITHINREAL",NETLIMIT_WITHINREAL;
+"NETLIMIT_WITHIN_INTERIOR",NETLIMIT_WITHIN_INTERIOR;
+"NET_DILEMMA",NET_DILEMMA;
+"NEUTRAL_ADD",NEUTRAL_ADD;
+"NEUTRAL_AND",NEUTRAL_AND;
+"NEUTRAL_COMPLEX_MUL",NEUTRAL_COMPLEX_MUL;
+"NEUTRAL_LIFTED",NEUTRAL_LIFTED;
+"NEUTRAL_MUL",NEUTRAL_MUL;
+"NEUTRAL_OUTER",NEUTRAL_OUTER;
+"NEUTRAL_REAL_ADD",NEUTRAL_REAL_ADD;
+"NEUTRAL_REAL_MUL",NEUTRAL_REAL_MUL;
+"NEUTRAL_VECTOR_ADD",NEUTRAL_VECTOR_ADD;
+"NONEMPTY_SIMPLE_PATH_ENDLESS",NONEMPTY_SIMPLE_PATH_ENDLESS;
+"NONNEGATIVE_ABSOLUTELY_INTEGRABLE",NONNEGATIVE_ABSOLUTELY_INTEGRABLE;
+"NONNEGATIVE_ABSOLUTELY_REAL_INTEGRABLE",NONNEGATIVE_ABSOLUTELY_REAL_INTEGRABLE;
+"NONTRIVIAL_LIMIT_WITHIN",NONTRIVIAL_LIMIT_WITHIN;
+"NON_EXTENSIBLE_BORSUK_MAP",NON_EXTENSIBLE_BORSUK_MAP;
+"NORM_0",NORM_0;
+"NORM_1",NORM_1;
+"NORM_1_POS",NORM_1_POS;
+"NORM_ADD_PYTHAGOREAN",NORM_ADD_PYTHAGOREAN;
+"NORM_BASIS",NORM_BASIS;
+"NORM_BASIS_1",NORM_BASIS_1;
+"NORM_BOUND_COMPONENT_LE",NORM_BOUND_COMPONENT_LE;
+"NORM_BOUND_COMPONENT_LT",NORM_BOUND_COMPONENT_LT;
+"NORM_BOUND_GENERALIZE",NORM_BOUND_GENERALIZE;
+"NORM_CAUCHY_SCHWARZ",NORM_CAUCHY_SCHWARZ;
+"NORM_CAUCHY_SCHWARZ_ABS",NORM_CAUCHY_SCHWARZ_ABS;
+"NORM_CAUCHY_SCHWARZ_ABS_EQ",NORM_CAUCHY_SCHWARZ_ABS_EQ;
+"NORM_CAUCHY_SCHWARZ_DIV",NORM_CAUCHY_SCHWARZ_DIV;
+"NORM_CAUCHY_SCHWARZ_EQ",NORM_CAUCHY_SCHWARZ_EQ;
+"NORM_CAUCHY_SCHWARZ_EQUAL",NORM_CAUCHY_SCHWARZ_EQUAL;
+"NORM_CCOS_LE",NORM_CCOS_LE;
+"NORM_CCOS_PLUS1_LE",NORM_CCOS_PLUS1_LE;
+"NORM_CCOS_POW_2",NORM_CCOS_POW_2;
+"NORM_CEXP",NORM_CEXP;
+"NORM_CEXP_II",NORM_CEXP_II;
+"NORM_CEXP_IMAGINARY",NORM_CEXP_IMAGINARY;
+"NORM_COSSIN",NORM_COSSIN;
+"NORM_CPOW_REAL",NORM_CPOW_REAL;
+"NORM_CPOW_REAL_MONO",NORM_CPOW_REAL_MONO;
+"NORM_CPRODUCT",NORM_CPRODUCT;
+"NORM_CROSS_MULTIPLY",NORM_CROSS_MULTIPLY;
+"NORM_CSIN_POW_2",NORM_CSIN_POW_2;
+"NORM_EQ",NORM_EQ;
+"NORM_EQ_0",NORM_EQ_0;
+"NORM_EQ_0_DOT",NORM_EQ_0_DOT;
+"NORM_EQ_0_IMP",NORM_EQ_0_IMP;
+"NORM_EQ_1",NORM_EQ_1;
+"NORM_EQ_SQUARE",NORM_EQ_SQUARE;
+"NORM_FSTCART",NORM_FSTCART;
+"NORM_GE_SQUARE",NORM_GE_SQUARE;
+"NORM_GT_SQUARE",NORM_GT_SQUARE;
+"NORM_INCREASES_ONLINE",NORM_INCREASES_ONLINE;
+"NORM_LE",NORM_LE;
+"NORM_LE_0",NORM_LE_0;
+"NORM_LE_COMPONENTWISE",NORM_LE_COMPONENTWISE;
+"NORM_LE_INFNORM",NORM_LE_INFNORM;
+"NORM_LE_L1",NORM_LE_L1;
+"NORM_LE_PASTECART",NORM_LE_PASTECART;
+"NORM_LE_SQUARE",NORM_LE_SQUARE;
+"NORM_LIFT",NORM_LIFT;
+"NORM_LT",NORM_LT;
+"NORM_LT_SQUARE",NORM_LT_SQUARE;
+"NORM_LT_SQUARE_ALT",NORM_LT_SQUARE_ALT;
+"NORM_MUL",NORM_MUL;
+"NORM_NEG",NORM_NEG;
+"NORM_PASTECART",NORM_PASTECART;
+"NORM_PASTECART_0",NORM_PASTECART_0;
+"NORM_PASTECART_LE",NORM_PASTECART_LE;
+"NORM_POS_LE",NORM_POS_LE;
+"NORM_POS_LT",NORM_POS_LT;
+"NORM_POW_2",NORM_POW_2;
+"NORM_REAL",NORM_REAL;
+"NORM_ROTATE2D",NORM_ROTATE2D;
+"NORM_SEGMENT_LOWERBOUND",NORM_SEGMENT_LOWERBOUND;
+"NORM_SEGMENT_ORTHOGONAL_LOWERBOUND",NORM_SEGMENT_ORTHOGONAL_LOWERBOUND;
+"NORM_SNDCART",NORM_SNDCART;
+"NORM_SUB",NORM_SUB;
+"NORM_SUM_LEMMA",NORM_SUM_LEMMA;
+"NORM_TRIANGLE",NORM_TRIANGLE;
+"NORM_TRIANGLE_EQ",NORM_TRIANGLE_EQ;
+"NORM_TRIANGLE_LE",NORM_TRIANGLE_LE;
+"NORM_TRIANGLE_LT",NORM_TRIANGLE_LT;
+"NORM_TRIANGLE_SUB",NORM_TRIANGLE_SUB;
+"NORM_VSUM_PYTHAGOREAN",NORM_VSUM_PYTHAGOREAN;
+"NORM_VSUM_TRIVIAL_LEMMA",NORM_VSUM_TRIVIAL_LEMMA;
+"NOT_ABSOLUTE_RETRACT_COBOUNDED",NOT_ABSOLUTE_RETRACT_COBOUNDED;
+"NOT_ALL",NOT_ALL;
+"NOT_BOUNDED_UNIV",NOT_BOUNDED_UNIV;
+"NOT_CLAUSES",NOT_CLAUSES;
+"NOT_CLAUSES_WEAK",NOT_CLAUSES_WEAK;
+"NOT_CONS_NIL",NOT_CONS_NIL;
+"NOT_DEF",NOT_DEF;
+"NOT_EMPTY_INSERT",NOT_EMPTY_INSERT;
+"NOT_EQUAL_SETS",NOT_EQUAL_SETS;
+"NOT_EVEN",NOT_EVEN;
+"NOT_EVENTUALLY",NOT_EVENTUALLY;
+"NOT_EX",NOT_EX;
+"NOT_EXISTS_THM",NOT_EXISTS_THM;
+"NOT_FORALL_THM",NOT_FORALL_THM;
+"NOT_IMP",NOT_IMP;
+"NOT_INSERT_EMPTY",NOT_INSERT_EMPTY;
+"NOT_INTERVAL_UNIV",NOT_INTERVAL_UNIV;
+"NOT_IN_EMPTY",NOT_IN_EMPTY;
+"NOT_IN_INTERIOR_CONVEX_HULL",NOT_IN_INTERIOR_CONVEX_HULL;
+"NOT_IN_INTERIOR_CONVEX_HULL_3",NOT_IN_INTERIOR_CONVEX_HULL_3;
+"NOT_IN_PATH_IMAGE_JOIN",NOT_IN_PATH_IMAGE_JOIN;
+"NOT_LE",NOT_LE;
+"NOT_LT",NOT_LT;
+"NOT_NEGLIGIBLE_UNIV",NOT_NEGLIGIBLE_UNIV;
+"NOT_ODD",NOT_ODD;
+"NOT_ON_PATH_BALL",NOT_ON_PATH_BALL;
+"NOT_ON_PATH_CBALL",NOT_ON_PATH_CBALL;
+"NOT_OUTSIDE_CONNECTED_COMPONENT_LE",NOT_OUTSIDE_CONNECTED_COMPONENT_LE;
+"NOT_OUTSIDE_CONNECTED_COMPONENT_LT",NOT_OUTSIDE_CONNECTED_COMPONENT_LT;
+"NOT_PSUBSET_EMPTY",NOT_PSUBSET_EMPTY;
+"NOT_SIMPLY_CONNECTED_CIRCLE",NOT_SIMPLY_CONNECTED_CIRCLE;
+"NOT_SUC",NOT_SUC;
+"NOT_UNIV_PSUBSET",NOT_UNIV_PSUBSET;
+"NOWHERE_DENSE",NOWHERE_DENSE;
+"NOWHERE_DENSE_UNION",NOWHERE_DENSE_UNION;
+"NO_BOUNDED_CONNECTED_COMPONENT_IMP_WINDING_NUMBER_ZERO",NO_BOUNDED_CONNECTED_COMPONENT_IMP_WINDING_NUMBER_ZERO;
+"NO_BOUNDED_PATH_COMPONENT_IMP_WINDING_NUMBER_ZERO",NO_BOUNDED_PATH_COMPONENT_IMP_WINDING_NUMBER_ZERO;
+"NO_EMBEDDING_SPHERE_LOWDIM",NO_EMBEDDING_SPHERE_LOWDIM;
+"NO_ISOLATED_SINGULARITY",NO_ISOLATED_SINGULARITY;
+"NO_LIMIT_POINT_IMP_CLOSED",NO_LIMIT_POINT_IMP_CLOSED;
+"NO_RETRACTION_CBALL",NO_RETRACTION_CBALL;
+"NO_RETRACTION_FRONTIER_BOUNDED",NO_RETRACTION_FRONTIER_BOUNDED;
+"NSUM_0",NSUM_0;
+"NSUM_ADD",NSUM_ADD;
+"NSUM_ADD_GEN",NSUM_ADD_GEN;
+"NSUM_ADD_NUMSEG",NSUM_ADD_NUMSEG;
+"NSUM_ADD_SPLIT",NSUM_ADD_SPLIT;
+"NSUM_BIJECTION",NSUM_BIJECTION;
+"NSUM_BOUND",NSUM_BOUND;
+"NSUM_BOUND_GEN",NSUM_BOUND_GEN;
+"NSUM_BOUND_LT",NSUM_BOUND_LT;
+"NSUM_BOUND_LT_ALL",NSUM_BOUND_LT_ALL;
+"NSUM_BOUND_LT_GEN",NSUM_BOUND_LT_GEN;
+"NSUM_CASES",NSUM_CASES;
+"NSUM_CLAUSES",NSUM_CLAUSES;
+"NSUM_CLAUSES_LEFT",NSUM_CLAUSES_LEFT;
+"NSUM_CLAUSES_NUMSEG",NSUM_CLAUSES_NUMSEG;
+"NSUM_CLAUSES_RIGHT",NSUM_CLAUSES_RIGHT;
+"NSUM_CLOSED",NSUM_CLOSED;
+"NSUM_CONST",NSUM_CONST;
+"NSUM_CONST_NUMSEG",NSUM_CONST_NUMSEG;
+"NSUM_DELETE",NSUM_DELETE;
+"NSUM_DELTA",NSUM_DELTA;
+"NSUM_DIFF",NSUM_DIFF;
+"NSUM_EQ",NSUM_EQ;
+"NSUM_EQ_0",NSUM_EQ_0;
+"NSUM_EQ_0_IFF",NSUM_EQ_0_IFF;
+"NSUM_EQ_0_IFF_NUMSEG",NSUM_EQ_0_IFF_NUMSEG;
+"NSUM_EQ_0_NUMSEG",NSUM_EQ_0_NUMSEG;
+"NSUM_EQ_GENERAL",NSUM_EQ_GENERAL;
+"NSUM_EQ_GENERAL_INVERSES",NSUM_EQ_GENERAL_INVERSES;
+"NSUM_EQ_NUMSEG",NSUM_EQ_NUMSEG;
+"NSUM_EQ_SUPERSET",NSUM_EQ_SUPERSET;
+"NSUM_GROUP",NSUM_GROUP;
+"NSUM_IMAGE",NSUM_IMAGE;
+"NSUM_IMAGE_GEN",NSUM_IMAGE_GEN;
+"NSUM_IMAGE_NONZERO",NSUM_IMAGE_NONZERO;
+"NSUM_INCL_EXCL",NSUM_INCL_EXCL;
+"NSUM_INJECTION",NSUM_INJECTION;
+"NSUM_LE",NSUM_LE;
+"NSUM_LE_NUMSEG",NSUM_LE_NUMSEG;
+"NSUM_LMUL",NSUM_LMUL;
+"NSUM_LT",NSUM_LT;
+"NSUM_LT_ALL",NSUM_LT_ALL;
+"NSUM_MULTICOUNT",NSUM_MULTICOUNT;
+"NSUM_MULTICOUNT_GEN",NSUM_MULTICOUNT_GEN;
+"NSUM_NSUM_PRODUCT",NSUM_NSUM_PRODUCT;
+"NSUM_NSUM_RESTRICT",NSUM_NSUM_RESTRICT;
+"NSUM_OFFSET",NSUM_OFFSET;
+"NSUM_OFFSET_0",NSUM_OFFSET_0;
+"NSUM_PAIR",NSUM_PAIR;
+"NSUM_PERMUTE",NSUM_PERMUTE;
+"NSUM_PERMUTE_NUMSEG",NSUM_PERMUTE_NUMSEG;
+"NSUM_POS_BOUND",NSUM_POS_BOUND;
+"NSUM_POS_LT",NSUM_POS_LT;
+"NSUM_RESTRICT",NSUM_RESTRICT;
+"NSUM_RESTRICT_SET",NSUM_RESTRICT_SET;
+"NSUM_RMUL",NSUM_RMUL;
+"NSUM_SING",NSUM_SING;
+"NSUM_SING_NUMSEG",NSUM_SING_NUMSEG;
+"NSUM_SUBSET",NSUM_SUBSET;
+"NSUM_SUBSET_SIMPLE",NSUM_SUBSET_SIMPLE;
+"NSUM_SUPERSET",NSUM_SUPERSET;
+"NSUM_SUPPORT",NSUM_SUPPORT;
+"NSUM_SWAP",NSUM_SWAP;
+"NSUM_SWAP_NUMSEG",NSUM_SWAP_NUMSEG;
+"NSUM_TRIV_NUMSEG",NSUM_TRIV_NUMSEG;
+"NSUM_UNION",NSUM_UNION;
+"NSUM_UNIONS_NONZERO",NSUM_UNIONS_NONZERO;
+"NSUM_UNION_EQ",NSUM_UNION_EQ;
+"NSUM_UNION_LZERO",NSUM_UNION_LZERO;
+"NSUM_UNION_NONZERO",NSUM_UNION_NONZERO;
+"NSUM_UNION_RZERO",NSUM_UNION_RZERO;
+"NULL",NULL;
+"NULLHOMOTOPIC_FROM_CONTRACTIBLE",NULLHOMOTOPIC_FROM_CONTRACTIBLE;
+"NULLHOMOTOPIC_FROM_SPHERE_EXTENSION",NULLHOMOTOPIC_FROM_SPHERE_EXTENSION;
+"NULLHOMOTOPIC_INTO_ANR_EXTENSION",NULLHOMOTOPIC_INTO_ANR_EXTENSION;
+"NULLHOMOTOPIC_INTO_CONTRACTIBLE",NULLHOMOTOPIC_INTO_CONTRACTIBLE;
+"NULLHOMOTOPIC_INTO_RELATIVE_FRONTIER_EXTENSION",NULLHOMOTOPIC_INTO_RELATIVE_FRONTIER_EXTENSION;
+"NULLHOMOTOPIC_INTO_SPHERE_EXTENSION",NULLHOMOTOPIC_INTO_SPHERE_EXTENSION;
+"NULLHOMOTOPIC_ORTHOGONAL_TRANSFORMATION",NULLHOMOTOPIC_ORTHOGONAL_TRANSFORMATION;
+"NULLHOMOTOPIC_THROUGH_CONTRACTIBLE",NULLHOMOTOPIC_THROUGH_CONTRACTIBLE;
+"NULLSPACE_INTER_ROWSPACE",NULLSPACE_INTER_ROWSPACE;
+"NUMERAL",NUMERAL;
+"NUMPAIR",NUMPAIR;
+"NUMPAIR_DEST",NUMPAIR_DEST;
+"NUMPAIR_INJ",NUMPAIR_INJ;
+"NUMPAIR_INJ_LEMMA",NUMPAIR_INJ_LEMMA;
+"NUMSEG_ADD_SPLIT",NUMSEG_ADD_SPLIT;
+"NUMSEG_CLAUSES",NUMSEG_CLAUSES;
+"NUMSEG_COMBINE_L",NUMSEG_COMBINE_L;
+"NUMSEG_COMBINE_R",NUMSEG_COMBINE_R;
+"NUMSEG_DIMINDEX_NONEMPTY",NUMSEG_DIMINDEX_NONEMPTY;
+"NUMSEG_EMPTY",NUMSEG_EMPTY;
+"NUMSEG_LE",NUMSEG_LE;
+"NUMSEG_LREC",NUMSEG_LREC;
+"NUMSEG_LT",NUMSEG_LT;
+"NUMSEG_OFFSET_IMAGE",NUMSEG_OFFSET_IMAGE;
+"NUMSEG_REC",NUMSEG_REC;
+"NUMSEG_RREC",NUMSEG_RREC;
+"NUMSEG_SING",NUMSEG_SING;
+"NUMSUM",NUMSUM;
+"NUMSUM_DEST",NUMSUM_DEST;
+"NUMSUM_INJ",NUMSUM_INJ;
+"NUM_COUNTABLE",NUM_COUNTABLE;
+"NUM_GCD",NUM_GCD;
+"NUM_OF_INT",NUM_OF_INT;
+"NUM_OF_INT_OF_NUM",NUM_OF_INT_OF_NUM;
+"NUM_REP_CASES",NUM_REP_CASES;
+"NUM_REP_INDUCT",NUM_REP_INDUCT;
+"NUM_REP_RULES",NUM_REP_RULES;
+"ODD",ODD;
+"ODD_ADD",ODD_ADD;
+"ODD_DOUBLE",ODD_DOUBLE;
+"ODD_EXISTS",ODD_EXISTS;
+"ODD_EXP",ODD_EXP;
+"ODD_MOD",ODD_MOD;
+"ODD_MULT",ODD_MULT;
+"ODD_SUB",ODD_SUB;
+"OEP",OEP;
+"OLDNET",OLDNET;
+"ONE",ONE;
+"ONE_ONE",ONE_ONE;
+"ONORM",ONORM;
+"ONORM_COMPOSE",ONORM_COMPOSE;
+"ONORM_CONST",ONORM_CONST;
+"ONORM_EQ_0",ONORM_EQ_0;
+"ONORM_I",ONORM_I;
+"ONORM_ID",ONORM_ID;
+"ONORM_NEG",ONORM_NEG;
+"ONORM_NEG_LEMMA",ONORM_NEG_LEMMA;
+"ONORM_POS_LE",ONORM_POS_LE;
+"ONORM_POS_LT",ONORM_POS_LT;
+"ONORM_TRIANGLE",ONORM_TRIANGLE;
+"ONORM_TRIANGLE_LE",ONORM_TRIANGLE_LE;
+"ONORM_TRIANGLE_LT",ONORM_TRIANGLE_LT;
+"ONTO",ONTO;
+"OPEN_AFFINITY",OPEN_AFFINITY;
+"OPEN_ARG_GT",OPEN_ARG_GT;
+"OPEN_ARG_LTT",OPEN_ARG_LTT;
+"OPEN_BALL",OPEN_BALL;
+"OPEN_BIJECTIVE_LINEAR_IMAGE_EQ",OPEN_BIJECTIVE_LINEAR_IMAGE_EQ;
+"OPEN_CLOSED",OPEN_CLOSED;
+"OPEN_CLOSED_INTERVAL_1",OPEN_CLOSED_INTERVAL_1;
+"OPEN_CLOSED_INTERVAL_CONVEX",OPEN_CLOSED_INTERVAL_CONVEX;
+"OPEN_COMPONENTS",OPEN_COMPONENTS;
+"OPEN_CONNECTED_COMPONENT",OPEN_CONNECTED_COMPONENT;
+"OPEN_CONTAINS_BALL",OPEN_CONTAINS_BALL;
+"OPEN_CONTAINS_BALL_EQ",OPEN_CONTAINS_BALL_EQ;
+"OPEN_CONTAINS_CBALL",OPEN_CONTAINS_CBALL;
+"OPEN_CONTAINS_CBALL_EQ",OPEN_CONTAINS_CBALL_EQ;
+"OPEN_CONTAINS_INTERVAL",OPEN_CONTAINS_INTERVAL;
+"OPEN_CONTAINS_OPEN_INTERVAL",OPEN_CONTAINS_OPEN_INTERVAL;
+"OPEN_CONVEX_HULL",OPEN_CONVEX_HULL;
+"OPEN_COUNTABLE_UNION_CLOSED_INTERVALS",OPEN_COUNTABLE_UNION_CLOSED_INTERVALS;
+"OPEN_COUNTABLE_UNION_OPEN_INTERVALS",OPEN_COUNTABLE_UNION_OPEN_INTERVALS;
+"OPEN_DELETE",OPEN_DELETE;
+"OPEN_DIFF",OPEN_DIFF;
+"OPEN_EMPTY",OPEN_EMPTY;
+"OPEN_EXISTS",OPEN_EXISTS;
+"OPEN_EXISTS_IN",OPEN_EXISTS_IN;
+"OPEN_GENERAL_COMPONENT",OPEN_GENERAL_COMPONENT;
+"OPEN_HALFSPACE_COMPONENT_GT",OPEN_HALFSPACE_COMPONENT_GT;
+"OPEN_HALFSPACE_COMPONENT_LT",OPEN_HALFSPACE_COMPONENT_LT;
+"OPEN_HALFSPACE_GT",OPEN_HALFSPACE_GT;
+"OPEN_HALFSPACE_IM_GT",OPEN_HALFSPACE_IM_GT;
+"OPEN_HALFSPACE_IM_LT",OPEN_HALFSPACE_IM_LT;
+"OPEN_HALFSPACE_LT",OPEN_HALFSPACE_LT;
+"OPEN_HALFSPACE_RE_GT",OPEN_HALFSPACE_RE_GT;
+"OPEN_HALFSPACE_RE_LT",OPEN_HALFSPACE_RE_LT;
+"OPEN_IMP_INFINITE",OPEN_IMP_INFINITE;
+"OPEN_IMP_LOCALLY_COMPACT",OPEN_IMP_LOCALLY_COMPACT;
+"OPEN_IMP_LOCALLY_CONNECTED",OPEN_IMP_LOCALLY_CONNECTED;
+"OPEN_IMP_LOCALLY_PATH_CONNECTED",OPEN_IMP_LOCALLY_PATH_CONNECTED;
+"OPEN_IN",OPEN_IN;
+"OPEN_INSIDE",OPEN_INSIDE;
+"OPEN_INTER",OPEN_INTER;
+"OPEN_INTERIOR",OPEN_INTERIOR;
+"OPEN_INTERS",OPEN_INTERS;
+"OPEN_INTERVAL",OPEN_INTERVAL;
+"OPEN_INTERVAL_EQ",OPEN_INTERVAL_EQ;
+"OPEN_INTERVAL_LEMMA",OPEN_INTERVAL_LEMMA;
+"OPEN_INTERVAL_MIDPOINT",OPEN_INTERVAL_MIDPOINT;
+"OPEN_INTER_CLOSURE_EQ_EMPTY",OPEN_INTER_CLOSURE_EQ_EMPTY;
+"OPEN_INTER_CLOSURE_SUBSET",OPEN_INTER_CLOSURE_SUBSET;
+"OPEN_IN_CLAUSES",OPEN_IN_CLAUSES;
+"OPEN_IN_CLOSED_IN",OPEN_IN_CLOSED_IN;
+"OPEN_IN_CLOSED_IN_EQ",OPEN_IN_CLOSED_IN_EQ;
+"OPEN_IN_COMPONENTS_LOCALLY_CONNECTED",OPEN_IN_COMPONENTS_LOCALLY_CONNECTED;
+"OPEN_IN_CONNECTED_COMPONENT",OPEN_IN_CONNECTED_COMPONENT;
+"OPEN_IN_CONNECTED_COMPONENTS",OPEN_IN_CONNECTED_COMPONENTS;
+"OPEN_IN_CONNECTED_COMPONENT_LOCALLY_CONNECTED",OPEN_IN_CONNECTED_COMPONENT_LOCALLY_CONNECTED;
+"OPEN_IN_CONTAINS_BALL",OPEN_IN_CONTAINS_BALL;
+"OPEN_IN_CONTAINS_CBALL",OPEN_IN_CONTAINS_CBALL;
+"OPEN_IN_DELETE",OPEN_IN_DELETE;
+"OPEN_IN_DIFF",OPEN_IN_DIFF;
+"OPEN_IN_EMPTY",OPEN_IN_EMPTY;
+"OPEN_IN_IMP_SUBSET",OPEN_IN_IMP_SUBSET;
+"OPEN_IN_INJECTIVE_LINEAR_IMAGE",OPEN_IN_INJECTIVE_LINEAR_IMAGE;
+"OPEN_IN_INTER",OPEN_IN_INTER;
+"OPEN_IN_INTERS",OPEN_IN_INTERS;
+"OPEN_IN_INTER_OPEN",OPEN_IN_INTER_OPEN;
+"OPEN_IN_OPEN",OPEN_IN_OPEN;
+"OPEN_IN_OPEN_EQ",OPEN_IN_OPEN_EQ;
+"OPEN_IN_OPEN_INTER",OPEN_IN_OPEN_INTER;
+"OPEN_IN_OPEN_TRANS",OPEN_IN_OPEN_TRANS;
+"OPEN_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED",OPEN_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED;
+"OPEN_IN_PCROSS",OPEN_IN_PCROSS;
+"OPEN_IN_PCROSS_EQ",OPEN_IN_PCROSS_EQ;
+"OPEN_IN_REFL",OPEN_IN_REFL;
+"OPEN_IN_RELATIVE_INTERIOR",OPEN_IN_RELATIVE_INTERIOR;
+"OPEN_IN_SING",OPEN_IN_SING;
+"OPEN_IN_SUBOPEN",OPEN_IN_SUBOPEN;
+"OPEN_IN_SUBSET",OPEN_IN_SUBSET;
+"OPEN_IN_SUBSET_RELATIVE_INTERIOR",OPEN_IN_SUBSET_RELATIVE_INTERIOR;
+"OPEN_IN_SUBSET_TRANS",OPEN_IN_SUBSET_TRANS;
+"OPEN_IN_SUBTOPOLOGY",OPEN_IN_SUBTOPOLOGY;
+"OPEN_IN_SUBTOPOLOGY_EMPTY",OPEN_IN_SUBTOPOLOGY_EMPTY;
+"OPEN_IN_SUBTOPOLOGY_INTER_SUBSET",OPEN_IN_SUBTOPOLOGY_INTER_SUBSET;
+"OPEN_IN_SUBTOPOLOGY_REFL",OPEN_IN_SUBTOPOLOGY_REFL;
+"OPEN_IN_SUBTOPOLOGY_UNION",OPEN_IN_SUBTOPOLOGY_UNION;
+"OPEN_IN_TOPSPACE",OPEN_IN_TOPSPACE;
+"OPEN_IN_TRANS",OPEN_IN_TRANS;
+"OPEN_IN_TRANSLATION_EQ",OPEN_IN_TRANSLATION_EQ;
+"OPEN_IN_UNION",OPEN_IN_UNION;
+"OPEN_IN_UNIONS",OPEN_IN_UNIONS;
+"OPEN_LIFT",OPEN_LIFT;
+"OPEN_MAPPING_THM",OPEN_MAPPING_THM;
+"OPEN_MAP_FROM_COMPOSITION_INJECTIVE",OPEN_MAP_FROM_COMPOSITION_INJECTIVE;
+"OPEN_MAP_FROM_COMPOSITION_SURJECTIVE",OPEN_MAP_FROM_COMPOSITION_SURJECTIVE;
+"OPEN_MAP_IMP_CLOSED_MAP",OPEN_MAP_IMP_CLOSED_MAP;
+"OPEN_MAP_IMP_QUOTIENT_MAP",OPEN_MAP_IMP_QUOTIENT_MAP;
+"OPEN_MEASURABLE_INNER_DIVISION",OPEN_MEASURABLE_INNER_DIVISION;
+"OPEN_NEGATIONS",OPEN_NEGATIONS;
+"OPEN_NON_GENERAL_COMPONENT",OPEN_NON_GENERAL_COMPONENT;
+"OPEN_NON_PATH_COMPONENT",OPEN_NON_PATH_COMPONENT;
+"OPEN_NOT_NEGLIGIBLE",OPEN_NOT_NEGLIGIBLE;
+"OPEN_OPEN_IN_TRANS",OPEN_OPEN_IN_TRANS;
+"OPEN_OPEN_LEFT_PROJECTION",OPEN_OPEN_LEFT_PROJECTION;
+"OPEN_OPEN_RIGHT_PROJECTION",OPEN_OPEN_RIGHT_PROJECTION;
+"OPEN_OUTSIDE",OPEN_OUTSIDE;
+"OPEN_PATH_COMPONENT",OPEN_PATH_COMPONENT;
+"OPEN_PATH_CONNECTED_COMPONENT",OPEN_PATH_CONNECTED_COMPONENT;
+"OPEN_PCROSS",OPEN_PCROSS;
+"OPEN_PCROSS_EQ",OPEN_PCROSS_EQ;
+"OPEN_POSITIVE_MULTIPLES",OPEN_POSITIVE_MULTIPLES;
+"OPEN_SCALING",OPEN_SCALING;
+"OPEN_SEGMENT_1",OPEN_SEGMENT_1;
+"OPEN_SEGMENT_ALT",OPEN_SEGMENT_ALT;
+"OPEN_SEGMENT_LINEAR_IMAGE",OPEN_SEGMENT_LINEAR_IMAGE;
+"OPEN_SET_COCOUNTABLE_COORDINATES",OPEN_SET_COCOUNTABLE_COORDINATES;
+"OPEN_SET_COSMALL_COORDINATES",OPEN_SET_COSMALL_COORDINATES;
+"OPEN_SET_IRRATIONAL_COORDINATES",OPEN_SET_IRRATIONAL_COORDINATES;
+"OPEN_SET_RATIONAL_COORDINATES",OPEN_SET_RATIONAL_COORDINATES;
+"OPEN_SLICE",OPEN_SLICE;
+"OPEN_SUBOPEN",OPEN_SUBOPEN;
+"OPEN_SUBSET",OPEN_SUBSET;
+"OPEN_SUBSET_INTERIOR",OPEN_SUBSET_INTERIOR;
+"OPEN_SUMS",OPEN_SUMS;
+"OPEN_SURJECTIVE_LINEAR_IMAGE",OPEN_SURJECTIVE_LINEAR_IMAGE;
+"OPEN_TRANSLATION",OPEN_TRANSLATION;
+"OPEN_TRANSLATION_EQ",OPEN_TRANSLATION_EQ;
+"OPEN_UNION",OPEN_UNION;
+"OPEN_UNIONS",OPEN_UNIONS;
+"OPEN_UNION_COMPACT_SUBSETS",OPEN_UNION_COMPACT_SUBSETS;
+"OPEN_UNIV",OPEN_UNIV;
+"OPEN_WINDING_NUMBER_LEVELSETS",OPEN_WINDING_NUMBER_LEVELSETS;
+"OPERATIVE_1_LE",OPERATIVE_1_LE;
+"OPERATIVE_1_LT",OPERATIVE_1_LT;
+"OPERATIVE_APPROXIMABLE",OPERATIVE_APPROXIMABLE;
+"OPERATIVE_CONTENT",OPERATIVE_CONTENT;
+"OPERATIVE_DIVISION",OPERATIVE_DIVISION;
+"OPERATIVE_DIVISION_AND",OPERATIVE_DIVISION_AND;
+"OPERATIVE_EMPTY",OPERATIVE_EMPTY;
+"OPERATIVE_FUNCTION_ENDPOINT_DIFF",OPERATIVE_FUNCTION_ENDPOINT_DIFF;
+"OPERATIVE_INTEGRABLE",OPERATIVE_INTEGRABLE;
+"OPERATIVE_INTEGRAL",OPERATIVE_INTEGRAL;
+"OPERATIVE_LIFTED_SETVARIATION",OPERATIVE_LIFTED_SETVARIATION;
+"OPERATIVE_LIFTED_VECTOR_VARIATION",OPERATIVE_LIFTED_VECTOR_VARIATION;
+"OPERATIVE_REAL_FUNCTION_ENDPOINT_DIFF",OPERATIVE_REAL_FUNCTION_ENDPOINT_DIFF;
+"OPERATIVE_TAGGED_DIVISION",OPERATIVE_TAGGED_DIVISION;
+"OPERATIVE_TRIVIAL",OPERATIVE_TRIVIAL;
+"ORDINAL_CHAINED",ORDINAL_CHAINED;
+"ORDINAL_CHAINED_LEMMA",ORDINAL_CHAINED_LEMMA;
+"ORDINAL_SUC",ORDINAL_SUC;
+"ORDINAL_UNION",ORDINAL_UNION;
+"ORDINAL_UNION_LEMMA",ORDINAL_UNION_LEMMA;
+"ORDINAL_UP",ORDINAL_UP;
+"ORTHGOONAL_TRANSFORMATION_REFLECT_ALONG",ORTHGOONAL_TRANSFORMATION_REFLECT_ALONG;
+"ORTHOGONAL_0",ORTHOGONAL_0;
+"ORTHOGONAL_ANY_CLOSEST_POINT",ORTHOGONAL_ANY_CLOSEST_POINT;
+"ORTHOGONAL_BASIS",ORTHOGONAL_BASIS;
+"ORTHOGONAL_BASIS_BASIS",ORTHOGONAL_BASIS_BASIS;
+"ORTHOGONAL_BASIS_EXISTS",ORTHOGONAL_BASIS_EXISTS;
+"ORTHOGONAL_BASIS_SUBSPACE",ORTHOGONAL_BASIS_SUBSPACE;
+"ORTHOGONAL_CLAUSES",ORTHOGONAL_CLAUSES;
+"ORTHOGONAL_EXTENSION",ORTHOGONAL_EXTENSION;
+"ORTHOGONAL_EXTENSION_STRONG",ORTHOGONAL_EXTENSION_STRONG;
+"ORTHOGONAL_LINEAR_IMAGE_EQ",ORTHOGONAL_LINEAR_IMAGE_EQ;
+"ORTHOGONAL_LNEG",ORTHOGONAL_LNEG;
+"ORTHOGONAL_LVSUM",ORTHOGONAL_LVSUM;
+"ORTHOGONAL_MATRIX",ORTHOGONAL_MATRIX;
+"ORTHOGONAL_MATRIX_2",ORTHOGONAL_MATRIX_2;
+"ORTHOGONAL_MATRIX_2_ALT",ORTHOGONAL_MATRIX_2_ALT;
+"ORTHOGONAL_MATRIX_ALT",ORTHOGONAL_MATRIX_ALT;
+"ORTHOGONAL_MATRIX_EXISTS_BASIS",ORTHOGONAL_MATRIX_EXISTS_BASIS;
+"ORTHOGONAL_MATRIX_ID",ORTHOGONAL_MATRIX_ID;
+"ORTHOGONAL_MATRIX_INV",ORTHOGONAL_MATRIX_INV;
+"ORTHOGONAL_MATRIX_MATRIX",ORTHOGONAL_MATRIX_MATRIX;
+"ORTHOGONAL_MATRIX_MUL",ORTHOGONAL_MATRIX_MUL;
+"ORTHOGONAL_MATRIX_ORTHOGONAL_EIGENVECTORS",ORTHOGONAL_MATRIX_ORTHOGONAL_EIGENVECTORS;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS",ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_INDEXED",ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_INDEXED;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_PAIRWISE",ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_PAIRWISE;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_SPAN",ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_SPAN;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS",ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_INDEXED",ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_INDEXED;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_PAIRWISE",ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_PAIRWISE;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_SPAN",ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_SPAN;
+"ORTHOGONAL_MATRIX_TRANSFORMATION",ORTHOGONAL_MATRIX_TRANSFORMATION;
+"ORTHOGONAL_MATRIX_TRANSP",ORTHOGONAL_MATRIX_TRANSP;
+"ORTHOGONAL_MUL",ORTHOGONAL_MUL;
+"ORTHOGONAL_NULLSPACE_ROWSPACE",ORTHOGONAL_NULLSPACE_ROWSPACE;
+"ORTHOGONAL_REFL",ORTHOGONAL_REFL;
+"ORTHOGONAL_RNEG",ORTHOGONAL_RNEG;
+"ORTHOGONAL_ROTATION_OR_ROTOINVERSION",ORTHOGONAL_ROTATION_OR_ROTOINVERSION;
+"ORTHOGONAL_RVSUM",ORTHOGONAL_RVSUM;
+"ORTHOGONAL_SPANNINGSET_SUBSPACE",ORTHOGONAL_SPANNINGSET_SUBSPACE;
+"ORTHOGONAL_SUBSPACE_DECOMP",ORTHOGONAL_SUBSPACE_DECOMP;
+"ORTHOGONAL_SUBSPACE_DECOMP_EXISTS",ORTHOGONAL_SUBSPACE_DECOMP_EXISTS;
+"ORTHOGONAL_SUBSPACE_DECOMP_UNIQUE",ORTHOGONAL_SUBSPACE_DECOMP_UNIQUE;
+"ORTHOGONAL_SYM",ORTHOGONAL_SYM;
+"ORTHOGONAL_TO_ORTHOGONAL_2D",ORTHOGONAL_TO_ORTHOGONAL_2D;
+"ORTHOGONAL_TO_SPAN",ORTHOGONAL_TO_SPAN;
+"ORTHOGONAL_TO_SPANS_EQ",ORTHOGONAL_TO_SPANS_EQ;
+"ORTHOGONAL_TO_SPAN_EQ",ORTHOGONAL_TO_SPAN_EQ;
+"ORTHOGONAL_TO_SUBSPACE_EXISTS",ORTHOGONAL_TO_SUBSPACE_EXISTS;
+"ORTHOGONAL_TO_SUBSPACE_EXISTS_GEN",ORTHOGONAL_TO_SUBSPACE_EXISTS_GEN;
+"ORTHOGONAL_TO_VECTOR_EXISTS",ORTHOGONAL_TO_VECTOR_EXISTS;
+"ORTHOGONAL_TRANSFORMATION",ORTHOGONAL_TRANSFORMATION;
+"ORTHOGONAL_TRANSFORMATION_BETWEEN_ORTHOGONAL_SETS",ORTHOGONAL_TRANSFORMATION_BETWEEN_ORTHOGONAL_SETS;
+"ORTHOGONAL_TRANSFORMATION_COMPOSE",ORTHOGONAL_TRANSFORMATION_COMPOSE;
+"ORTHOGONAL_TRANSFORMATION_EXISTS",ORTHOGONAL_TRANSFORMATION_EXISTS;
+"ORTHOGONAL_TRANSFORMATION_EXISTS_1",ORTHOGONAL_TRANSFORMATION_EXISTS_1;
+"ORTHOGONAL_TRANSFORMATION_GENERATED_BY_REFLECTIONS",ORTHOGONAL_TRANSFORMATION_GENERATED_BY_REFLECTIONS;
+"ORTHOGONAL_TRANSFORMATION_I",ORTHOGONAL_TRANSFORMATION_I;
+"ORTHOGONAL_TRANSFORMATION_ID",ORTHOGONAL_TRANSFORMATION_ID;
+"ORTHOGONAL_TRANSFORMATION_INJECTIVE",ORTHOGONAL_TRANSFORMATION_INJECTIVE;
+"ORTHOGONAL_TRANSFORMATION_INTO_SUBSPACE",ORTHOGONAL_TRANSFORMATION_INTO_SUBSPACE;
+"ORTHOGONAL_TRANSFORMATION_INVERSE",ORTHOGONAL_TRANSFORMATION_INVERSE;
+"ORTHOGONAL_TRANSFORMATION_INVERSE_o",ORTHOGONAL_TRANSFORMATION_INVERSE_o;
+"ORTHOGONAL_TRANSFORMATION_ISOMETRY",ORTHOGONAL_TRANSFORMATION_ISOMETRY;
+"ORTHOGONAL_TRANSFORMATION_LINEAR",ORTHOGONAL_TRANSFORMATION_LINEAR;
+"ORTHOGONAL_TRANSFORMATION_LOWDIM_HORIZONTAL",ORTHOGONAL_TRANSFORMATION_LOWDIM_HORIZONTAL;
+"ORTHOGONAL_TRANSFORMATION_MATRIX",ORTHOGONAL_TRANSFORMATION_MATRIX;
+"ORTHOGONAL_TRANSFORMATION_ONTO_SUBSPACE",ORTHOGONAL_TRANSFORMATION_ONTO_SUBSPACE;
+"ORTHOGONAL_TRANSFORMATION_ORTHOGONAL_EIGENVECTORS",ORTHOGONAL_TRANSFORMATION_ORTHOGONAL_EIGENVECTORS;
+"ORTHOGONAL_TRANSFORMATION_ROTATE2D",ORTHOGONAL_TRANSFORMATION_ROTATE2D;
+"ORTHOGONAL_TRANSFORMATION_SURJECTIVE",ORTHOGONAL_TRANSFORMATION_SURJECTIVE;
+"ORTHONORMAL_BASIS_EXPAND",ORTHONORMAL_BASIS_EXPAND;
+"ORTHONORMAL_BASIS_SUBSPACE",ORTHONORMAL_BASIS_SUBSPACE;
+"ORTHONORMAL_EXTENSION",ORTHONORMAL_EXTENSION;
+"OR_CLAUSES",OR_CLAUSES;
+"OR_DEF",OR_DEF;
+"OR_EXISTS_THM",OR_EXISTS_THM;
+"OSTROWSKI_THEOREM",OSTROWSKI_THEOREM;
+"OUTER",OUTER;
+"OUTERMORPHISM_MBASIS",OUTERMORPHISM_MBASIS;
+"OUTERMORPHISM_MBASIS_EMPTY",OUTERMORPHISM_MBASIS_EMPTY;
+"OUTER_ACI",OUTER_ACI;
+"OUTER_ASSOC",OUTER_ASSOC;
+"OUTER_LADD",OUTER_LADD;
+"OUTER_LMUL",OUTER_LMUL;
+"OUTER_LNEG",OUTER_LNEG;
+"OUTER_LZERO",OUTER_LZERO;
+"OUTER_MBASIS",OUTER_MBASIS;
+"OUTER_MBASIS_LSCALAR",OUTER_MBASIS_LSCALAR;
+"OUTER_MBASIS_REFL",OUTER_MBASIS_REFL;
+"OUTER_MBASIS_RSCALAR",OUTER_MBASIS_RSCALAR;
+"OUTER_MBASIS_SING",OUTER_MBASIS_SING;
+"OUTER_MBASIS_SKEWSYM",OUTER_MBASIS_SKEWSYM;
+"OUTER_RADD",OUTER_RADD;
+"OUTER_RMUL",OUTER_RMUL;
+"OUTER_RNEG",OUTER_RNEG;
+"OUTER_RZERO",OUTER_RZERO;
+"OUTL",OUTL;
+"OUTR",OUTR;
+"OUTSIDE",OUTSIDE;
+"OUTSIDE_BOUNDED_NONEMPTY",OUTSIDE_BOUNDED_NONEMPTY;
+"OUTSIDE_COMPACT_IN_OPEN",OUTSIDE_COMPACT_IN_OPEN;
+"OUTSIDE_CONNECTED_COMPONENT_LE",OUTSIDE_CONNECTED_COMPONENT_LE;
+"OUTSIDE_CONNECTED_COMPONENT_LT",OUTSIDE_CONNECTED_COMPONENT_LT;
+"OUTSIDE_CONVEX",OUTSIDE_CONVEX;
+"OUTSIDE_EMPTY",OUTSIDE_EMPTY;
+"OUTSIDE_FRONTIER_EQ_COMPLEMENT_CLOSURE",OUTSIDE_FRONTIER_EQ_COMPLEMENT_CLOSURE;
+"OUTSIDE_FRONTIER_MISSES_CLOSURE",OUTSIDE_FRONTIER_MISSES_CLOSURE;
+"OUTSIDE_INSIDE",OUTSIDE_INSIDE;
+"OUTSIDE_IN_COMPONENTS",OUTSIDE_IN_COMPONENTS;
+"OUTSIDE_LINEAR_IMAGE",OUTSIDE_LINEAR_IMAGE;
+"OUTSIDE_MONO",OUTSIDE_MONO;
+"OUTSIDE_NO_OVERLAP",OUTSIDE_NO_OVERLAP;
+"OUTSIDE_SAME_COMPONENT",OUTSIDE_SAME_COMPONENT;
+"OUTSIDE_SUBSET_CONVEX",OUTSIDE_SUBSET_CONVEX;
+"OUTSIDE_TRANSLATION",OUTSIDE_TRANSLATION;
+"OUTSIDE_UNION_OUTSIDE_UNION",OUTSIDE_UNION_OUTSIDE_UNION;
+"PAIR",PAIR;
+"PAIRED_ETA_THM",PAIRED_ETA_THM;
+"PAIRED_EXT",PAIRED_EXT;
+"PAIRWISE",PAIRWISE;
+"PAIRWISE_DISJOINT_COMPONENTS",PAIRWISE_DISJOINT_COMPONENTS;
+"PAIRWISE_EMPTY",PAIRWISE_EMPTY;
+"PAIRWISE_IMAGE",PAIRWISE_IMAGE;
+"PAIRWISE_INSERT",PAIRWISE_INSERT;
+"PAIRWISE_MONO",PAIRWISE_MONO;
+"PAIRWISE_ORTHOGONAL_IMP_FINITE",PAIRWISE_ORTHOGONAL_IMP_FINITE;
+"PAIRWISE_ORTHOGONAL_INDEPENDENT",PAIRWISE_ORTHOGONAL_INDEPENDENT;
+"PAIRWISE_SING",PAIRWISE_SING;
+"PAIR_EQ",PAIR_EQ;
+"PAIR_EXISTS_THM",PAIR_EXISTS_THM;
+"PAIR_SURJECTIVE",PAIR_SURJECTIVE;
+"PARTIAL_DIVISION_EXTEND",PARTIAL_DIVISION_EXTEND;
+"PARTIAL_DIVISION_EXTEND_1",PARTIAL_DIVISION_EXTEND_1;
+"PARTIAL_DIVISION_EXTEND_INTERVAL",PARTIAL_DIVISION_EXTEND_INTERVAL;
+"PARTIAL_DIVISION_OF_TAGGED_DIVISION",PARTIAL_DIVISION_OF_TAGGED_DIVISION;
+"PARTIAL_SUMS_COMPONENT_LE_INFSUM",PARTIAL_SUMS_COMPONENT_LE_INFSUM;
+"PARTIAL_SUMS_DROP_LE_INFSUM",PARTIAL_SUMS_DROP_LE_INFSUM;
+"PASSOC_DEF",PASSOC_DEF;
+"PASTECART_ADD",PASTECART_ADD;
+"PASTECART_AS_ORTHOGONAL_SUM",PASTECART_AS_ORTHOGONAL_SUM;
+"PASTECART_CMUL",PASTECART_CMUL;
+"PASTECART_EQ",PASTECART_EQ;
+"PASTECART_EQ_VEC",PASTECART_EQ_VEC;
+"PASTECART_FST_SND",PASTECART_FST_SND;
+"PASTECART_INJ",PASTECART_INJ;
+"PASTECART_IN_INTERIOR_SUBTOPOLOGY",PASTECART_IN_INTERIOR_SUBTOPOLOGY;
+"PASTECART_IN_PCROSS",PASTECART_IN_PCROSS;
+"PASTECART_NEG",PASTECART_NEG;
+"PASTECART_SUB",PASTECART_SUB;
+"PASTECART_VEC",PASTECART_VEC;
+"PASTECART_VSUM",PASTECART_VSUM;
+"PASTING_LEMMA",PASTING_LEMMA;
+"PASTING_LEMMA_CLOSED",PASTING_LEMMA_CLOSED;
+"PASTING_LEMMA_EXISTS",PASTING_LEMMA_EXISTS;
+"PASTING_LEMMA_EXISTS_CLOSED",PASTING_LEMMA_EXISTS_CLOSED;
+"PATHFINISH_CIRCLEPATH",PATHFINISH_CIRCLEPATH;
+"PATHFINISH_COMPOSE",PATHFINISH_COMPOSE;
+"PATHFINISH_IN_PATH_IMAGE",PATHFINISH_IN_PATH_IMAGE;
+"PATHFINISH_JOIN",PATHFINISH_JOIN;
+"PATHFINISH_LINEAR_IMAGE",PATHFINISH_LINEAR_IMAGE;
+"PATHFINISH_LINEPATH",PATHFINISH_LINEPATH;
+"PATHFINISH_PARTCIRCLEPATH",PATHFINISH_PARTCIRCLEPATH;
+"PATHFINISH_REVERSEPATH",PATHFINISH_REVERSEPATH;
+"PATHFINISH_SHIFTPATH",PATHFINISH_SHIFTPATH;
+"PATHFINISH_SUBPATH",PATHFINISH_SUBPATH;
+"PATHFINISH_TRANSLATION",PATHFINISH_TRANSLATION;
+"PATHINTEGRAL_CONVEX_PRIMITIVE",PATHINTEGRAL_CONVEX_PRIMITIVE;
+"PATHSTART_CIRCLEPATH",PATHSTART_CIRCLEPATH;
+"PATHSTART_COMPOSE",PATHSTART_COMPOSE;
+"PATHSTART_IN_PATH_IMAGE",PATHSTART_IN_PATH_IMAGE;
+"PATHSTART_JOIN",PATHSTART_JOIN;
+"PATHSTART_LINEAR_IMAGE_EQ",PATHSTART_LINEAR_IMAGE_EQ;
+"PATHSTART_LINEPATH",PATHSTART_LINEPATH;
+"PATHSTART_PARTCIRCLEPATH",PATHSTART_PARTCIRCLEPATH;
+"PATHSTART_REVERSEPATH",PATHSTART_REVERSEPATH;
+"PATHSTART_SHIFTPATH",PATHSTART_SHIFTPATH;
+"PATHSTART_SUBPATH",PATHSTART_SUBPATH;
+"PATHSTART_TRANSLATION",PATHSTART_TRANSLATION;
+"PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION",PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION;
+"PATH_ASSOC",PATH_ASSOC;
+"PATH_COMPONENT",PATH_COMPONENT;
+"PATH_COMPONENT_DISJOINT",PATH_COMPONENT_DISJOINT;
+"PATH_COMPONENT_EMPTY",PATH_COMPONENT_EMPTY;
+"PATH_COMPONENT_EQ",PATH_COMPONENT_EQ;
+"PATH_COMPONENT_EQ_CONNECTED_COMPONENT",PATH_COMPONENT_EQ_CONNECTED_COMPONENT;
+"PATH_COMPONENT_EQ_EMPTY",PATH_COMPONENT_EQ_EMPTY;
+"PATH_COMPONENT_EQ_EQ",PATH_COMPONENT_EQ_EQ;
+"PATH_COMPONENT_IMP_HOMOTOPIC_POINTS",PATH_COMPONENT_IMP_HOMOTOPIC_POINTS;
+"PATH_COMPONENT_IN",PATH_COMPONENT_IN;
+"PATH_COMPONENT_LINEAR_IMAGE",PATH_COMPONENT_LINEAR_IMAGE;
+"PATH_COMPONENT_MAXIMAL",PATH_COMPONENT_MAXIMAL;
+"PATH_COMPONENT_MONO",PATH_COMPONENT_MONO;
+"PATH_COMPONENT_OF_SUBSET",PATH_COMPONENT_OF_SUBSET;
+"PATH_COMPONENT_PATH_COMPONENT",PATH_COMPONENT_PATH_COMPONENT;
+"PATH_COMPONENT_PATH_IMAGE_PATHSTART",PATH_COMPONENT_PATH_IMAGE_PATHSTART;
+"PATH_COMPONENT_REFL",PATH_COMPONENT_REFL;
+"PATH_COMPONENT_REFL_EQ",PATH_COMPONENT_REFL_EQ;
+"PATH_COMPONENT_SET",PATH_COMPONENT_SET;
+"PATH_COMPONENT_SUBSET",PATH_COMPONENT_SUBSET;
+"PATH_COMPONENT_SUBSET_CONNECTED_COMPONENT",PATH_COMPONENT_SUBSET_CONNECTED_COMPONENT;
+"PATH_COMPONENT_SYM",PATH_COMPONENT_SYM;
+"PATH_COMPONENT_SYM_EQ",PATH_COMPONENT_SYM_EQ;
+"PATH_COMPONENT_TRANS",PATH_COMPONENT_TRANS;
+"PATH_COMPONENT_TRANSLATION",PATH_COMPONENT_TRANSLATION;
+"PATH_COMPONENT_UNIV",PATH_COMPONENT_UNIV;
+"PATH_COMPOSE_JOIN",PATH_COMPOSE_JOIN;
+"PATH_COMPOSE_REVERSEPATH",PATH_COMPOSE_REVERSEPATH;
+"PATH_CONNECTED_ANNULUS",PATH_CONNECTED_ANNULUS;
+"PATH_CONNECTED_ARCWISE",PATH_CONNECTED_ARCWISE;
+"PATH_CONNECTED_ARC_COMPLEMENT",PATH_CONNECTED_ARC_COMPLEMENT;
+"PATH_CONNECTED_COMPLEMENT_ABSOLUTE_RETRACT",PATH_CONNECTED_COMPLEMENT_ABSOLUTE_RETRACT;
+"PATH_CONNECTED_COMPLEMENT_BOUNDED_CONVEX",PATH_CONNECTED_COMPLEMENT_BOUNDED_CONVEX;
+"PATH_CONNECTED_COMPLEMENT_CARD_LT",PATH_CONNECTED_COMPLEMENT_CARD_LT;
+"PATH_CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT",PATH_CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT;
+"PATH_CONNECTED_COMPONENT_SET",PATH_CONNECTED_COMPONENT_SET;
+"PATH_CONNECTED_CONTINUOUS_IMAGE",PATH_CONNECTED_CONTINUOUS_IMAGE;
+"PATH_CONNECTED_CONVEX_DIFF_CARD_LT",PATH_CONNECTED_CONVEX_DIFF_CARD_LT;
+"PATH_CONNECTED_DIFF_BALL",PATH_CONNECTED_DIFF_BALL;
+"PATH_CONNECTED_EMPTY",PATH_CONNECTED_EMPTY;
+"PATH_CONNECTED_EQ_CONNECTED",PATH_CONNECTED_EQ_CONNECTED;
+"PATH_CONNECTED_EQ_CONNECTED_LPC",PATH_CONNECTED_EQ_CONNECTED_LPC;
+"PATH_CONNECTED_EQ_HOMOTOPIC_POINTS",PATH_CONNECTED_EQ_HOMOTOPIC_POINTS;
+"PATH_CONNECTED_IFF_PATH_COMPONENT",PATH_CONNECTED_IFF_PATH_COMPONENT;
+"PATH_CONNECTED_IMP_CONNECTED",PATH_CONNECTED_IMP_CONNECTED;
+"PATH_CONNECTED_INTERVAL",PATH_CONNECTED_INTERVAL;
+"PATH_CONNECTED_LINEAR_IMAGE",PATH_CONNECTED_LINEAR_IMAGE;
+"PATH_CONNECTED_LINEAR_IMAGE_EQ",PATH_CONNECTED_LINEAR_IMAGE_EQ;
+"PATH_CONNECTED_LINEPATH",PATH_CONNECTED_LINEPATH;
+"PATH_CONNECTED_NEGATIONS",PATH_CONNECTED_NEGATIONS;
+"PATH_CONNECTED_OPEN_DELETE",PATH_CONNECTED_OPEN_DELETE;
+"PATH_CONNECTED_OPEN_DIFF_CARD_LT",PATH_CONNECTED_OPEN_DIFF_CARD_LT;
+"PATH_CONNECTED_OPEN_DIFF_COUNTABLE",PATH_CONNECTED_OPEN_DIFF_COUNTABLE;
+"PATH_CONNECTED_OPEN_IN_DIFF_CARD_LT",PATH_CONNECTED_OPEN_IN_DIFF_CARD_LT;
+"PATH_CONNECTED_PATH_COMPONENT",PATH_CONNECTED_PATH_COMPONENT;
+"PATH_CONNECTED_PATH_IMAGE",PATH_CONNECTED_PATH_IMAGE;
+"PATH_CONNECTED_PCROSS",PATH_CONNECTED_PCROSS;
+"PATH_CONNECTED_PCROSS_EQ",PATH_CONNECTED_PCROSS_EQ;
+"PATH_CONNECTED_PUNCTURED_BALL",PATH_CONNECTED_PUNCTURED_BALL;
+"PATH_CONNECTED_PUNCTURED_UNIVERSE",PATH_CONNECTED_PUNCTURED_UNIVERSE;
+"PATH_CONNECTED_SCALING",PATH_CONNECTED_SCALING;
+"PATH_CONNECTED_SEGMENT",PATH_CONNECTED_SEGMENT;
+"PATH_CONNECTED_SEMIOPEN_SEGMENT",PATH_CONNECTED_SEMIOPEN_SEGMENT;
+"PATH_CONNECTED_SING",PATH_CONNECTED_SING;
+"PATH_CONNECTED_SPHERE",PATH_CONNECTED_SPHERE;
+"PATH_CONNECTED_SPHERE_EQ",PATH_CONNECTED_SPHERE_EQ;
+"PATH_CONNECTED_SUMS",PATH_CONNECTED_SUMS;
+"PATH_CONNECTED_TRANSLATION",PATH_CONNECTED_TRANSLATION;
+"PATH_CONNECTED_TRANSLATION_EQ",PATH_CONNECTED_TRANSLATION_EQ;
+"PATH_CONNECTED_UNION",PATH_CONNECTED_UNION;
+"PATH_CONNECTED_UNIV",PATH_CONNECTED_UNIV;
+"PATH_CONTAINS_ARC",PATH_CONTAINS_ARC;
+"PATH_CONTINUOUS_IMAGE",PATH_CONTINUOUS_IMAGE;
+"PATH_EQ",PATH_EQ;
+"PATH_IMAGE_CIRCLEPATH",PATH_IMAGE_CIRCLEPATH;
+"PATH_IMAGE_COMPOSE",PATH_IMAGE_COMPOSE;
+"PATH_IMAGE_JOIN",PATH_IMAGE_JOIN;
+"PATH_IMAGE_JOIN_SUBSET",PATH_IMAGE_JOIN_SUBSET;
+"PATH_IMAGE_LINEAR_IMAGE",PATH_IMAGE_LINEAR_IMAGE;
+"PATH_IMAGE_LINEPATH",PATH_IMAGE_LINEPATH;
+"PATH_IMAGE_NONEMPTY",PATH_IMAGE_NONEMPTY;
+"PATH_IMAGE_PARTCIRCLEPATH",PATH_IMAGE_PARTCIRCLEPATH;
+"PATH_IMAGE_PARTCIRCLEPATH_SUBSET",PATH_IMAGE_PARTCIRCLEPATH_SUBSET;
+"PATH_IMAGE_REVERSEPATH",PATH_IMAGE_REVERSEPATH;
+"PATH_IMAGE_SHIFTPATH",PATH_IMAGE_SHIFTPATH;
+"PATH_IMAGE_SUBPATH",PATH_IMAGE_SUBPATH;
+"PATH_IMAGE_SUBPATH_GEN",PATH_IMAGE_SUBPATH_GEN;
+"PATH_IMAGE_SUBPATH_SUBSET",PATH_IMAGE_SUBPATH_SUBSET;
+"PATH_IMAGE_SYM",PATH_IMAGE_SYM;
+"PATH_IMAGE_TRANSLATION",PATH_IMAGE_TRANSLATION;
+"PATH_INTEGRABLE_ADD",PATH_INTEGRABLE_ADD;
+"PATH_INTEGRABLE_COMPLEX_DIV",PATH_INTEGRABLE_COMPLEX_DIV;
+"PATH_INTEGRABLE_COMPLEX_LMUL",PATH_INTEGRABLE_COMPLEX_LMUL;
+"PATH_INTEGRABLE_COMPLEX_RMUL",PATH_INTEGRABLE_COMPLEX_RMUL;
+"PATH_INTEGRABLE_CONTINUOUS_CIRCLEPATH",PATH_INTEGRABLE_CONTINUOUS_CIRCLEPATH;
+"PATH_INTEGRABLE_CONTINUOUS_LINEPATH",PATH_INTEGRABLE_CONTINUOUS_LINEPATH;
+"PATH_INTEGRABLE_CONTINUOUS_PARTCIRCLEPATH",PATH_INTEGRABLE_CONTINUOUS_PARTCIRCLEPATH;
+"PATH_INTEGRABLE_EQ",PATH_INTEGRABLE_EQ;
+"PATH_INTEGRABLE_HOLOMORPHIC",PATH_INTEGRABLE_HOLOMORPHIC;
+"PATH_INTEGRABLE_HOLOMORPHIC_SIMPLE",PATH_INTEGRABLE_HOLOMORPHIC_SIMPLE;
+"PATH_INTEGRABLE_INVERSEDIFF",PATH_INTEGRABLE_INVERSEDIFF;
+"PATH_INTEGRABLE_JOIN",PATH_INTEGRABLE_JOIN;
+"PATH_INTEGRABLE_NEG",PATH_INTEGRABLE_NEG;
+"PATH_INTEGRABLE_ON",PATH_INTEGRABLE_ON;
+"PATH_INTEGRABLE_REVERSEPATH",PATH_INTEGRABLE_REVERSEPATH;
+"PATH_INTEGRABLE_REVERSEPATH_EQ",PATH_INTEGRABLE_REVERSEPATH_EQ;
+"PATH_INTEGRABLE_SUB",PATH_INTEGRABLE_SUB;
+"PATH_INTEGRABLE_SUBPATH",PATH_INTEGRABLE_SUBPATH;
+"PATH_INTEGRABLE_SUBPATH_REFL",PATH_INTEGRABLE_SUBPATH_REFL;
+"PATH_INTEGRABLE_VSUM",PATH_INTEGRABLE_VSUM;
+"PATH_INTEGRAL_0",PATH_INTEGRAL_0;
+"PATH_INTEGRAL_ADD",PATH_INTEGRAL_ADD;
+"PATH_INTEGRAL_BOUND_EXISTS",PATH_INTEGRAL_BOUND_EXISTS;
+"PATH_INTEGRAL_BOUND_LINEPATH",PATH_INTEGRAL_BOUND_LINEPATH;
+"PATH_INTEGRAL_COMPLEX_DIV",PATH_INTEGRAL_COMPLEX_DIV;
+"PATH_INTEGRAL_COMPLEX_LMUL",PATH_INTEGRAL_COMPLEX_LMUL;
+"PATH_INTEGRAL_COMPLEX_RMUL",PATH_INTEGRAL_COMPLEX_RMUL;
+"PATH_INTEGRAL_CONST_LINEPATH",PATH_INTEGRAL_CONST_LINEPATH;
+"PATH_INTEGRAL_EQ",PATH_INTEGRAL_EQ;
+"PATH_INTEGRAL_EQ_0",PATH_INTEGRAL_EQ_0;
+"PATH_INTEGRAL_INTEGRAL",PATH_INTEGRAL_INTEGRAL;
+"PATH_INTEGRAL_JOIN",PATH_INTEGRAL_JOIN;
+"PATH_INTEGRAL_LOCAL_PRIMITIVE",PATH_INTEGRAL_LOCAL_PRIMITIVE;
+"PATH_INTEGRAL_LOCAL_PRIMITIVE_ANY",PATH_INTEGRAL_LOCAL_PRIMITIVE_ANY;
+"PATH_INTEGRAL_LOCAL_PRIMITIVE_LEMMA",PATH_INTEGRAL_LOCAL_PRIMITIVE_LEMMA;
+"PATH_INTEGRAL_MIDPOINT",PATH_INTEGRAL_MIDPOINT;
+"PATH_INTEGRAL_NEARBY_ENDS",PATH_INTEGRAL_NEARBY_ENDS;
+"PATH_INTEGRAL_NEARBY_LOOP",PATH_INTEGRAL_NEARBY_LOOP;
+"PATH_INTEGRAL_NEG",PATH_INTEGRAL_NEG;
+"PATH_INTEGRAL_PRIMITIVE",PATH_INTEGRAL_PRIMITIVE;
+"PATH_INTEGRAL_PRIMITIVE_LEMMA",PATH_INTEGRAL_PRIMITIVE_LEMMA;
+"PATH_INTEGRAL_REVERSEPATH",PATH_INTEGRAL_REVERSEPATH;
+"PATH_INTEGRAL_REVERSE_LINEPATH",PATH_INTEGRAL_REVERSE_LINEPATH;
+"PATH_INTEGRAL_SHIFTPATH",PATH_INTEGRAL_SHIFTPATH;
+"PATH_INTEGRAL_SPLIT",PATH_INTEGRAL_SPLIT;
+"PATH_INTEGRAL_SPLIT_LINEPATH",PATH_INTEGRAL_SPLIT_LINEPATH;
+"PATH_INTEGRAL_SUB",PATH_INTEGRAL_SUB;
+"PATH_INTEGRAL_SUBPATH_COMBINE",PATH_INTEGRAL_SUBPATH_COMBINE;
+"PATH_INTEGRAL_SUBPATH_INTEGRAL",PATH_INTEGRAL_SUBPATH_INTEGRAL;
+"PATH_INTEGRAL_SUBPATH_REFL",PATH_INTEGRAL_SUBPATH_REFL;
+"PATH_INTEGRAL_SWAP",PATH_INTEGRAL_SWAP;
+"PATH_INTEGRAL_TRIVIAL",PATH_INTEGRAL_TRIVIAL;
+"PATH_INTEGRAL_UNIFORM_LIMIT",PATH_INTEGRAL_UNIFORM_LIMIT;
+"PATH_INTEGRAL_UNIFORM_LIMIT_CIRCLEPATH",PATH_INTEGRAL_UNIFORM_LIMIT_CIRCLEPATH;
+"PATH_INTEGRAL_UNIQUE",PATH_INTEGRAL_UNIQUE;
+"PATH_INTEGRAL_VSUM",PATH_INTEGRAL_VSUM;
+"PATH_JOIN",PATH_JOIN;
+"PATH_JOIN_EQ",PATH_JOIN_EQ;
+"PATH_JOIN_IMP",PATH_JOIN_IMP;
+"PATH_JOIN_PATH_ENDS",PATH_JOIN_PATH_ENDS;
+"PATH_LENGTH_DIFFERENTIABLE",PATH_LENGTH_DIFFERENTIABLE;
+"PATH_LENGTH_JOIN",PATH_LENGTH_JOIN;
+"PATH_LENGTH_REVERSEPATH",PATH_LENGTH_REVERSEPATH;
+"PATH_LENGTH_VALID_PATH",PATH_LENGTH_VALID_PATH;
+"PATH_LINEAR_IMAGE_EQ",PATH_LINEAR_IMAGE_EQ;
+"PATH_LINEPATH",PATH_LINEPATH;
+"PATH_PARTCIRCLEPATH",PATH_PARTCIRCLEPATH;
+"PATH_REVERSEPATH",PATH_REVERSEPATH;
+"PATH_SHIFTPATH",PATH_SHIFTPATH;
+"PATH_SUBPATH",PATH_SUBPATH;
+"PATH_SYM",PATH_SYM;
+"PATH_TRANSLATION_EQ",PATH_TRANSLATION_EQ;
+"PATH_VECTOR_POLYNOMIAL_FUNCTION",PATH_VECTOR_POLYNOMIAL_FUNCTION;
+"PCROSS",PCROSS;
+"PCROSS_AS_ORTHOGONAL_SUM",PCROSS_AS_ORTHOGONAL_SUM;
+"PCROSS_EMPTY",PCROSS_EMPTY;
+"PCROSS_EQ",PCROSS_EQ;
+"PCROSS_EQ_EMPTY",PCROSS_EQ_EMPTY;
+"PCROSS_INTER",PCROSS_INTER;
+"PCROSS_INTERVAL",PCROSS_INTERVAL;
+"PCROSS_MONO",PCROSS_MONO;
+"PCROSS_UNION",PCROSS_UNION;
+"PCROSS_UNIONS",PCROSS_UNIONS;
+"PCROSS_UNIONS_UNIONS",PCROSS_UNIONS_UNIONS;
+"PERMUTATION",PERMUTATION;
+"PERMUTATION_BIJECTIVE",PERMUTATION_BIJECTIVE;
+"PERMUTATION_COMPOSE",PERMUTATION_COMPOSE;
+"PERMUTATION_COMPOSE_EQ",PERMUTATION_COMPOSE_EQ;
+"PERMUTATION_COMPOSE_SWAP",PERMUTATION_COMPOSE_SWAP;
+"PERMUTATION_FINITE_SUPPORT",PERMUTATION_FINITE_SUPPORT;
+"PERMUTATION_I",PERMUTATION_I;
+"PERMUTATION_INVERSE",PERMUTATION_INVERSE;
+"PERMUTATION_INVERSE_COMPOSE",PERMUTATION_INVERSE_COMPOSE;
+"PERMUTATION_INVERSE_WORKS",PERMUTATION_INVERSE_WORKS;
+"PERMUTATION_LEMMA",PERMUTATION_LEMMA;
+"PERMUTATION_PERMUTES",PERMUTATION_PERMUTES;
+"PERMUTATION_SWAP",PERMUTATION_SWAP;
+"PERMUTES_COMPOSE",PERMUTES_COMPOSE;
+"PERMUTES_EMPTY",PERMUTES_EMPTY;
+"PERMUTES_FINITE_INJECTIVE",PERMUTES_FINITE_INJECTIVE;
+"PERMUTES_FINITE_SURJECTIVE",PERMUTES_FINITE_SURJECTIVE;
+"PERMUTES_I",PERMUTES_I;
+"PERMUTES_IMAGE",PERMUTES_IMAGE;
+"PERMUTES_INDUCT",PERMUTES_INDUCT;
+"PERMUTES_INJECTIVE",PERMUTES_INJECTIVE;
+"PERMUTES_INSERT",PERMUTES_INSERT;
+"PERMUTES_INSERT_LEMMA",PERMUTES_INSERT_LEMMA;
+"PERMUTES_INVERSE",PERMUTES_INVERSE;
+"PERMUTES_INVERSES",PERMUTES_INVERSES;
+"PERMUTES_INVERSES_o",PERMUTES_INVERSES_o;
+"PERMUTES_INVERSE_EQ",PERMUTES_INVERSE_EQ;
+"PERMUTES_INVERSE_INVERSE",PERMUTES_INVERSE_INVERSE;
+"PERMUTES_IN_IMAGE",PERMUTES_IN_IMAGE;
+"PERMUTES_IN_NUMSEG",PERMUTES_IN_NUMSEG;
+"PERMUTES_NUMSET_GE",PERMUTES_NUMSET_GE;
+"PERMUTES_NUMSET_LE",PERMUTES_NUMSET_LE;
+"PERMUTES_SING",PERMUTES_SING;
+"PERMUTES_SUBSET",PERMUTES_SUBSET;
+"PERMUTES_SUPERSET",PERMUTES_SUPERSET;
+"PERMUTES_SURJECTIVE",PERMUTES_SURJECTIVE;
+"PERMUTES_SWAP",PERMUTES_SWAP;
+"PERMUTES_UNIV",PERMUTES_UNIV;
+"PI2_BOUNDS",PI2_BOUNDS;
+"PIECEWISE_DIFFERENTIABLE_ADD",PIECEWISE_DIFFERENTIABLE_ADD;
+"PIECEWISE_DIFFERENTIABLE_AFFINE",PIECEWISE_DIFFERENTIABLE_AFFINE;
+"PIECEWISE_DIFFERENTIABLE_CASES",PIECEWISE_DIFFERENTIABLE_CASES;
+"PIECEWISE_DIFFERENTIABLE_COMPOSE",PIECEWISE_DIFFERENTIABLE_COMPOSE;
+"PIECEWISE_DIFFERENTIABLE_NEG",PIECEWISE_DIFFERENTIABLE_NEG;
+"PIECEWISE_DIFFERENTIABLE_ON_IMP_CONTINUOUS_ON",PIECEWISE_DIFFERENTIABLE_ON_IMP_CONTINUOUS_ON;
+"PIECEWISE_DIFFERENTIABLE_ON_SUBSET",PIECEWISE_DIFFERENTIABLE_ON_SUBSET;
+"PIECEWISE_DIFFERENTIABLE_SUB",PIECEWISE_DIFFERENTIABLE_SUB;
+"PI_APPROX_32",PI_APPROX_32;
+"PI_NZ",PI_NZ;
+"PI_POS",PI_POS;
+"PI_POS_LE",PI_POS_LE;
+"PI_WORKS",PI_WORKS;
+"POINTS_IN_CONVEX_HULL",POINTS_IN_CONVEX_HULL;
+"POINTWISE_ANTISYM",POINTWISE_ANTISYM;
+"POINTWISE_MAXIMAL",POINTWISE_MAXIMAL;
+"POINTWISE_MINIMAL",POINTWISE_MINIMAL;
+"POLE_LEMMA",POLE_LEMMA;
+"POLE_LEMMA_OPEN",POLE_LEMMA_OPEN;
+"POLE_THEOREM",POLE_THEOREM;
+"POLE_THEOREM_0",POLE_THEOREM_0;
+"POLE_THEOREM_ANALYTIC",POLE_THEOREM_ANALYTIC;
+"POLE_THEOREM_ANALYTIC_0",POLE_THEOREM_ANALYTIC_0;
+"POLE_THEOREM_ANALYTIC_OPEN_SUPERSET",POLE_THEOREM_ANALYTIC_OPEN_SUPERSET;
+"POLE_THEOREM_ANALYTIC_OPEN_SUPERSET_0",POLE_THEOREM_ANALYTIC_OPEN_SUPERSET_0;
+"POLE_THEOREM_OPEN",POLE_THEOREM_OPEN;
+"POLE_THEOREM_OPEN_0",POLE_THEOREM_OPEN_0;
+"POLYHEDRON_AFFINE_HULL",POLYHEDRON_AFFINE_HULL;
+"POLYHEDRON_AS_CONE_PLUS_CONV",POLYHEDRON_AS_CONE_PLUS_CONV;
+"POLYHEDRON_CONVEX_CONE_HULL",POLYHEDRON_CONVEX_CONE_HULL;
+"POLYHEDRON_CONVEX_HULL",POLYHEDRON_CONVEX_HULL;
+"POLYHEDRON_EMPTY",POLYHEDRON_EMPTY;
+"POLYHEDRON_EQ_FINITE_EXPOSED_FACES",POLYHEDRON_EQ_FINITE_EXPOSED_FACES;
+"POLYHEDRON_EQ_FINITE_FACES",POLYHEDRON_EQ_FINITE_FACES;
+"POLYHEDRON_HALFSPACE_GE",POLYHEDRON_HALFSPACE_GE;
+"POLYHEDRON_HALFSPACE_LE",POLYHEDRON_HALFSPACE_LE;
+"POLYHEDRON_HYPERPLANE",POLYHEDRON_HYPERPLANE;
+"POLYHEDRON_IMP_CLOSED",POLYHEDRON_IMP_CLOSED;
+"POLYHEDRON_IMP_CONVEX",POLYHEDRON_IMP_CONVEX;
+"POLYHEDRON_INTER",POLYHEDRON_INTER;
+"POLYHEDRON_INTERS",POLYHEDRON_INTERS;
+"POLYHEDRON_INTERVAL",POLYHEDRON_INTERVAL;
+"POLYHEDRON_INTER_AFFINE",POLYHEDRON_INTER_AFFINE;
+"POLYHEDRON_INTER_AFFINE_MINIMAL",POLYHEDRON_INTER_AFFINE_MINIMAL;
+"POLYHEDRON_INTER_AFFINE_PARALLEL",POLYHEDRON_INTER_AFFINE_PARALLEL;
+"POLYHEDRON_INTER_AFFINE_PARALLEL_MINIMAL",POLYHEDRON_INTER_AFFINE_PARALLEL_MINIMAL;
+"POLYHEDRON_INTER_POLYTOPE",POLYHEDRON_INTER_POLYTOPE;
+"POLYHEDRON_LINEAR_IMAGE",POLYHEDRON_LINEAR_IMAGE;
+"POLYHEDRON_LINEAR_IMAGE_EQ",POLYHEDRON_LINEAR_IMAGE_EQ;
+"POLYHEDRON_NEGATIONS",POLYHEDRON_NEGATIONS;
+"POLYHEDRON_POLYTOPE_SUMS",POLYHEDRON_POLYTOPE_SUMS;
+"POLYHEDRON_POSITIVE_ORTHANT",POLYHEDRON_POSITIVE_ORTHANT;
+"POLYHEDRON_RIDGE_TWO_FACETS",POLYHEDRON_RIDGE_TWO_FACETS;
+"POLYHEDRON_SUMS",POLYHEDRON_SUMS;
+"POLYHEDRON_TRANSLATION_EQ",POLYHEDRON_TRANSLATION_EQ;
+"POLYHEDRON_UNIV",POLYHEDRON_UNIV;
+"POLYTOPE_CONVEX_HULL",POLYTOPE_CONVEX_HULL;
+"POLYTOPE_EMPTY",POLYTOPE_EMPTY;
+"POLYTOPE_EQ_BOUNDED_POLYHEDRON",POLYTOPE_EQ_BOUNDED_POLYHEDRON;
+"POLYTOPE_FACET_EXISTS",POLYTOPE_FACET_EXISTS;
+"POLYTOPE_FACET_LOWER_BOUND",POLYTOPE_FACET_LOWER_BOUND;
+"POLYTOPE_IMP_BOUNDED",POLYTOPE_IMP_BOUNDED;
+"POLYTOPE_IMP_CLOSED",POLYTOPE_IMP_CLOSED;
+"POLYTOPE_IMP_COMPACT",POLYTOPE_IMP_COMPACT;
+"POLYTOPE_IMP_CONVEX",POLYTOPE_IMP_CONVEX;
+"POLYTOPE_IMP_POLYHEDRON",POLYTOPE_IMP_POLYHEDRON;
+"POLYTOPE_INTER",POLYTOPE_INTER;
+"POLYTOPE_INTERVAL",POLYTOPE_INTERVAL;
+"POLYTOPE_INTER_POLYHEDRON",POLYTOPE_INTER_POLYHEDRON;
+"POLYTOPE_LINEAR_IMAGE",POLYTOPE_LINEAR_IMAGE;
+"POLYTOPE_LINEAR_IMAGE_EQ",POLYTOPE_LINEAR_IMAGE_EQ;
+"POLYTOPE_NEGATIONS",POLYTOPE_NEGATIONS;
+"POLYTOPE_PCROSS",POLYTOPE_PCROSS;
+"POLYTOPE_PCROSS_EQ",POLYTOPE_PCROSS_EQ;
+"POLYTOPE_SCALING",POLYTOPE_SCALING;
+"POLYTOPE_SCALING_EQ",POLYTOPE_SCALING_EQ;
+"POLYTOPE_SING",POLYTOPE_SING;
+"POLYTOPE_SUMS",POLYTOPE_SUMS;
+"POLYTOPE_TRANSLATION_EQ",POLYTOPE_TRANSLATION_EQ;
+"POLYTOPE_UNION_CONVEX_HULL_FACETS",POLYTOPE_UNION_CONVEX_HULL_FACETS;
+"POLYTOPE_VERTEX_LOWER_BOUND",POLYTOPE_VERTEX_LOWER_BOUND;
+"POSET_ANTISYM",POSET_ANTISYM;
+"POSET_FLEQ",POSET_FLEQ;
+"POSET_REFL",POSET_REFL;
+"POSET_RESTRICTED_SUBSET",POSET_RESTRICTED_SUBSET;
+"POSET_TRANS",POSET_TRANS;
+"POWERSET_CLAUSES",POWERSET_CLAUSES;
+"POWER_REAL_SERIES_CONV_IMP_ABSCONV_WEAK",POWER_REAL_SERIES_CONV_IMP_ABSCONV_WEAK;
+"POWER_SERIES_ANALYTIC",POWER_SERIES_ANALYTIC;
+"POWER_SERIES_AND_DERIVATIVE",POWER_SERIES_AND_DERIVATIVE;
+"POWER_SERIES_AND_DERIVATIVE_0",POWER_SERIES_AND_DERIVATIVE_0;
+"POWER_SERIES_CONV_IMP_ABSCONV",POWER_SERIES_CONV_IMP_ABSCONV;
+"POWER_SERIES_CONV_IMP_ABSCONV_WEAK",POWER_SERIES_CONV_IMP_ABSCONV_WEAK;
+"POWER_SERIES_HOLOMORPHIC",POWER_SERIES_HOLOMORPHIC;
+"POWER_SERIES_UNIFORM_CONVERGENCE_STOLZ",POWER_SERIES_UNIFORM_CONVERGENCE_STOLZ;
+"POWER_SERIES_UNIFORM_CONVERGENCE_STOLZ_1",POWER_SERIES_UNIFORM_CONVERGENCE_STOLZ_1;
+"POW_2_CSQRT",POW_2_CSQRT;
+"POW_2_SQRT",POW_2_SQRT;
+"POW_2_SQRT_ABS",POW_2_SQRT_ABS;
+"PRE",PRE;
+"PRESERVES_LEBESGUE_MEASURABLE_IMP_PRESERVES_NEGLIGIBLE",PRESERVES_LEBESGUE_MEASURABLE_IMP_PRESERVES_NEGLIGIBLE;
+"PRESERVES_NORM_INJECTIVE",PRESERVES_NORM_INJECTIVE;
+"PRESERVES_NORM_PRESERVES_DOT",PRESERVES_NORM_PRESERVES_DOT;
+"PRE_ELIM_THM",PRE_ELIM_THM;
+"PRE_ELIM_THM'",PRE_ELIM_THM';
+"PRODUCT_1",PRODUCT_1;
+"PRODUCT_2",PRODUCT_2;
+"PRODUCT_3",PRODUCT_3;
+"PRODUCT_4",PRODUCT_4;
+"PRODUCT_ABS",PRODUCT_ABS;
+"PRODUCT_ADD_SPLIT",PRODUCT_ADD_SPLIT;
+"PRODUCT_ASSOCIATIVE",PRODUCT_ASSOCIATIVE;
+"PRODUCT_CLAUSES",PRODUCT_CLAUSES;
+"PRODUCT_CLAUSES_LEFT",PRODUCT_CLAUSES_LEFT;
+"PRODUCT_CLAUSES_NUMSEG",PRODUCT_CLAUSES_NUMSEG;
+"PRODUCT_CLAUSES_RIGHT",PRODUCT_CLAUSES_RIGHT;
+"PRODUCT_CLOSED",PRODUCT_CLOSED;
+"PRODUCT_CONST",PRODUCT_CONST;
+"PRODUCT_CONST_NUMSEG",PRODUCT_CONST_NUMSEG;
+"PRODUCT_CONST_NUMSEG_1",PRODUCT_CONST_NUMSEG_1;
+"PRODUCT_DIV",PRODUCT_DIV;
+"PRODUCT_DIV_NUMSEG",PRODUCT_DIV_NUMSEG;
+"PRODUCT_EQ",PRODUCT_EQ;
+"PRODUCT_EQ_0",PRODUCT_EQ_0;
+"PRODUCT_EQ_0_NUMSEG",PRODUCT_EQ_0_NUMSEG;
+"PRODUCT_EQ_1",PRODUCT_EQ_1;
+"PRODUCT_EQ_1_NUMSEG",PRODUCT_EQ_1_NUMSEG;
+"PRODUCT_EQ_NUMSEG",PRODUCT_EQ_NUMSEG;
+"PRODUCT_IMAGE",PRODUCT_IMAGE;
+"PRODUCT_INV",PRODUCT_INV;
+"PRODUCT_LADD",PRODUCT_LADD;
+"PRODUCT_LE",PRODUCT_LE;
+"PRODUCT_LE_1",PRODUCT_LE_1;
+"PRODUCT_LE_NUMSEG",PRODUCT_LE_NUMSEG;
+"PRODUCT_LMUL",PRODUCT_LMUL;
+"PRODUCT_LNEG",PRODUCT_LNEG;
+"PRODUCT_LZERO",PRODUCT_LZERO;
+"PRODUCT_MBASIS",PRODUCT_MBASIS;
+"PRODUCT_MBASIS_SING",PRODUCT_MBASIS_SING;
+"PRODUCT_MUL",PRODUCT_MUL;
+"PRODUCT_MUL_NUMSEG",PRODUCT_MUL_NUMSEG;
+"PRODUCT_NEG",PRODUCT_NEG;
+"PRODUCT_NEG_NUMSEG",PRODUCT_NEG_NUMSEG;
+"PRODUCT_NEG_NUMSEG_1",PRODUCT_NEG_NUMSEG_1;
+"PRODUCT_OFFSET",PRODUCT_OFFSET;
+"PRODUCT_ONE",PRODUCT_ONE;
+"PRODUCT_PERMUTE",PRODUCT_PERMUTE;
+"PRODUCT_PERMUTE_NUMSEG",PRODUCT_PERMUTE_NUMSEG;
+"PRODUCT_POS_LE",PRODUCT_POS_LE;
+"PRODUCT_POS_LE_NUMSEG",PRODUCT_POS_LE_NUMSEG;
+"PRODUCT_POS_LT",PRODUCT_POS_LT;
+"PRODUCT_POS_LT_NUMSEG",PRODUCT_POS_LT_NUMSEG;
+"PRODUCT_RADD",PRODUCT_RADD;
+"PRODUCT_RMUL",PRODUCT_RMUL;
+"PRODUCT_RNEG",PRODUCT_RNEG;
+"PRODUCT_RZERO",PRODUCT_RZERO;
+"PRODUCT_SING",PRODUCT_SING;
+"PRODUCT_SING_NUMSEG",PRODUCT_SING_NUMSEG;
+"PRODUCT_UNION",PRODUCT_UNION;
+"PROPERTY_EMPTY_INTERVAL",PROPERTY_EMPTY_INTERVAL;
+"PROPER_MAP",PROPER_MAP;
+"PROPER_MAP_FROM_COMPACT",PROPER_MAP_FROM_COMPACT;
+"PSUBSET",PSUBSET;
+"PSUBSET_ALT",PSUBSET_ALT;
+"PSUBSET_INSERT_SUBSET",PSUBSET_INSERT_SUBSET;
+"PSUBSET_IRREFL",PSUBSET_IRREFL;
+"PSUBSET_MEMBER",PSUBSET_MEMBER;
+"PSUBSET_SUBSET_TRANS",PSUBSET_SUBSET_TRANS;
+"PSUBSET_TRANS",PSUBSET_TRANS;
+"PSUBSET_UNIV",PSUBSET_UNIV;
+"PUSHIN_DROPOUT",PUSHIN_DROPOUT;
+"P_HULL",P_HULL;
+"Product_DEF",Product_DEF;
+"QUANTIFY_SURJECTION_HIGHER_THM",QUANTIFY_SURJECTION_HIGHER_THM;
+"QUANTIFY_SURJECTION_THM",QUANTIFY_SURJECTION_THM;
+"QUOTIENT_MAP_OPEN_CLOSED",QUOTIENT_MAP_OPEN_CLOSED;
+"RADON",RADON;
+"RADON_EX_LEMMA",RADON_EX_LEMMA;
+"RADON_PARTITION",RADON_PARTITION;
+"RADON_S_LEMMA",RADON_S_LEMMA;
+"RADON_V_LEMMA",RADON_V_LEMMA;
+"RANK_0",RANK_0;
+"RANK_BOUND",RANK_BOUND;
+"RANK_DIM_IM",RANK_DIM_IM;
+"RANK_EQ_0",RANK_EQ_0;
+"RANK_GRAM",RANK_GRAM;
+"RANK_I",RANK_I;
+"RANK_MUL_LE_LEFT",RANK_MUL_LE_LEFT;
+"RANK_MUL_LE_RIGHT",RANK_MUL_LE_RIGHT;
+"RANK_NULLSPACE",RANK_NULLSPACE;
+"RANK_ROW",RANK_ROW;
+"RANK_SYLVESTER",RANK_SYLVESTER;
+"RANK_TRANSP",RANK_TRANSP;
+"RANK_TRIANGLE",RANK_TRIANGLE;
+"RATIONAL_ABS",RATIONAL_ABS;
+"RATIONAL_ADD",RATIONAL_ADD;
+"RATIONAL_ALT",RATIONAL_ALT;
+"RATIONAL_APPROXIMATION",RATIONAL_APPROXIMATION;
+"RATIONAL_APPROXIMATION_STRADDLE",RATIONAL_APPROXIMATION_STRADDLE;
+"RATIONAL_BETWEEN",RATIONAL_BETWEEN;
+"RATIONAL_CLOSED",RATIONAL_CLOSED;
+"RATIONAL_DIV",RATIONAL_DIV;
+"RATIONAL_INTEGER",RATIONAL_INTEGER;
+"RATIONAL_INV",RATIONAL_INV;
+"RATIONAL_INV_EQ",RATIONAL_INV_EQ;
+"RATIONAL_MUL",RATIONAL_MUL;
+"RATIONAL_NEG",RATIONAL_NEG;
+"RATIONAL_NEG_EQ",RATIONAL_NEG_EQ;
+"RATIONAL_NUM",RATIONAL_NUM;
+"RATIONAL_POW",RATIONAL_POW;
+"RATIONAL_SUB",RATIONAL_SUB;
+"RAT_LEMMA1",RAT_LEMMA1;
+"RAT_LEMMA2",RAT_LEMMA2;
+"RAT_LEMMA3",RAT_LEMMA3;
+"RAT_LEMMA4",RAT_LEMMA4;
+"RAT_LEMMA5",RAT_LEMMA5;
+"RAY_TO_FRONTIER",RAY_TO_FRONTIER;
+"RAY_TO_RELATIVE_FRONTIER",RAY_TO_RELATIVE_FRONTIER;
+"RE",RE;
+"REAL",REAL;
+"REALLIM",REALLIM;
+"REALLIM_1_OVER_LOG",REALLIM_1_OVER_LOG;
+"REALLIM_1_OVER_N",REALLIM_1_OVER_N;
+"REALLIM_ABS",REALLIM_ABS;
+"REALLIM_ADD",REALLIM_ADD;
+"REALLIM_AT",REALLIM_AT;
+"REALLIM_ATREAL",REALLIM_ATREAL;
+"REALLIM_ATREAL_AT",REALLIM_ATREAL_AT;
+"REALLIM_ATREAL_ID",REALLIM_ATREAL_ID;
+"REALLIM_ATREAL_WITHINREAL",REALLIM_ATREAL_WITHINREAL;
+"REALLIM_AT_INFINITY",REALLIM_AT_INFINITY;
+"REALLIM_AT_NEGINFINITY",REALLIM_AT_NEGINFINITY;
+"REALLIM_AT_POSINFINITY",REALLIM_AT_POSINFINITY;
+"REALLIM_COMPLEX",REALLIM_COMPLEX;
+"REALLIM_CONG_AT",REALLIM_CONG_AT;
+"REALLIM_CONG_ATREAL",REALLIM_CONG_ATREAL;
+"REALLIM_CONG_WITHIN",REALLIM_CONG_WITHIN;
+"REALLIM_CONG_WITHINREAL",REALLIM_CONG_WITHINREAL;
+"REALLIM_CONST",REALLIM_CONST;
+"REALLIM_CONST_EQ",REALLIM_CONST_EQ;
+"REALLIM_CONTINUOUS_FUNCTION",REALLIM_CONTINUOUS_FUNCTION;
+"REALLIM_DIV",REALLIM_DIV;
+"REALLIM_EVENTUALLY",REALLIM_EVENTUALLY;
+"REALLIM_IM",REALLIM_IM;
+"REALLIM_INV",REALLIM_INV;
+"REALLIM_LBOUND",REALLIM_LBOUND;
+"REALLIM_LE",REALLIM_LE;
+"REALLIM_LMUL",REALLIM_LMUL;
+"REALLIM_LMUL_EQ",REALLIM_LMUL_EQ;
+"REALLIM_LOG_OVER_N",REALLIM_LOG_OVER_N;
+"REALLIM_MAX",REALLIM_MAX;
+"REALLIM_MIN",REALLIM_MIN;
+"REALLIM_MUL",REALLIM_MUL;
+"REALLIM_NEG",REALLIM_NEG;
+"REALLIM_NEG_EQ",REALLIM_NEG_EQ;
+"REALLIM_NULL",REALLIM_NULL;
+"REALLIM_NULL_ABS",REALLIM_NULL_ABS;
+"REALLIM_NULL_ADD",REALLIM_NULL_ADD;
+"REALLIM_NULL_COMPARISON",REALLIM_NULL_COMPARISON;
+"REALLIM_NULL_LMUL",REALLIM_NULL_LMUL;
+"REALLIM_NULL_LMUL_EQ",REALLIM_NULL_LMUL_EQ;
+"REALLIM_NULL_POW",REALLIM_NULL_POW;
+"REALLIM_NULL_POW_EQ",REALLIM_NULL_POW_EQ;
+"REALLIM_NULL_RMUL",REALLIM_NULL_RMUL;
+"REALLIM_NULL_RMUL_EQ",REALLIM_NULL_RMUL_EQ;
+"REALLIM_POSINFINITY_SEQUENTIALLY",REALLIM_POSINFINITY_SEQUENTIALLY;
+"REALLIM_POW",REALLIM_POW;
+"REALLIM_POWN",REALLIM_POWN;
+"REALLIM_RE",REALLIM_RE;
+"REALLIM_REAL_CONTINUOUS_FUNCTION",REALLIM_REAL_CONTINUOUS_FUNCTION;
+"REALLIM_RMUL",REALLIM_RMUL;
+"REALLIM_RMUL_EQ",REALLIM_RMUL_EQ;
+"REALLIM_RPOW",REALLIM_RPOW;
+"REALLIM_SEQUENTIALLY",REALLIM_SEQUENTIALLY;
+"REALLIM_SUB",REALLIM_SUB;
+"REALLIM_SUM",REALLIM_SUM;
+"REALLIM_TRANSFORM",REALLIM_TRANSFORM;
+"REALLIM_TRANSFORM_BOUND",REALLIM_TRANSFORM_BOUND;
+"REALLIM_TRANSFORM_EQ",REALLIM_TRANSFORM_EQ;
+"REALLIM_TRANSFORM_EVENTUALLY",REALLIM_TRANSFORM_EVENTUALLY;
+"REALLIM_TRANSFORM_STRADDLE",REALLIM_TRANSFORM_STRADDLE;
+"REALLIM_TRANSFORM_WITHINREAL_SET",REALLIM_TRANSFORM_WITHINREAL_SET;
+"REALLIM_TRANSFORM_WITHIN_SET",REALLIM_TRANSFORM_WITHIN_SET;
+"REALLIM_UBOUND",REALLIM_UBOUND;
+"REALLIM_UNIQUE",REALLIM_UNIQUE;
+"REALLIM_WITHIN",REALLIM_WITHIN;
+"REALLIM_WITHINREAL",REALLIM_WITHINREAL;
+"REALLIM_WITHINREAL_ID",REALLIM_WITHINREAL_ID;
+"REALLIM_WITHINREAL_LE",REALLIM_WITHINREAL_LE;
+"REALLIM_WITHINREAL_SUBSET",REALLIM_WITHINREAL_SUBSET;
+"REALLIM_WITHINREAL_WITHIN",REALLIM_WITHINREAL_WITHIN;
+"REALLIM_WITHIN_LE",REALLIM_WITHIN_LE;
+"REALLIM_WITHIN_OPEN",REALLIM_WITHIN_OPEN;
+"REALLIM_WITHIN_REAL_OPEN",REALLIM_WITHIN_REAL_OPEN;
+"REALLIM_WITHIN_SUBSET",REALLIM_WITHIN_SUBSET;
+"REALLIM_ZERO_NEGINFINITY",REALLIM_ZERO_NEGINFINITY;
+"REALLIM_ZERO_POSINFINITY",REALLIM_ZERO_POSINFINITY;
+"REAL_ABEL_LEMMA",REAL_ABEL_LEMMA;
+"REAL_ABEL_LIMIT_THEOREM",REAL_ABEL_LIMIT_THEOREM;
+"REAL_ABS_0",REAL_ABS_0;
+"REAL_ABS_1",REAL_ABS_1;
+"REAL_ABS_ABS",REAL_ABS_ABS;
+"REAL_ABS_BETWEEN",REAL_ABS_BETWEEN;
+"REAL_ABS_BETWEEN1",REAL_ABS_BETWEEN1;
+"REAL_ABS_BETWEEN2",REAL_ABS_BETWEEN2;
+"REAL_ABS_BOUND",REAL_ABS_BOUND;
+"REAL_ABS_BOUNDS",REAL_ABS_BOUNDS;
+"REAL_ABS_CASES",REAL_ABS_CASES;
+"REAL_ABS_CIRCLE",REAL_ABS_CIRCLE;
+"REAL_ABS_DIV",REAL_ABS_DIV;
+"REAL_ABS_EXP",REAL_ABS_EXP;
+"REAL_ABS_INFNORM",REAL_ABS_INFNORM;
+"REAL_ABS_INF_LE",REAL_ABS_INF_LE;
+"REAL_ABS_INTEGER_LEMMA",REAL_ABS_INTEGER_LEMMA;
+"REAL_ABS_INV",REAL_ABS_INV;
+"REAL_ABS_LE",REAL_ABS_LE;
+"REAL_ABS_MUL",REAL_ABS_MUL;
+"REAL_ABS_NEG",REAL_ABS_NEG;
+"REAL_ABS_NORM",REAL_ABS_NORM;
+"REAL_ABS_NUM",REAL_ABS_NUM;
+"REAL_ABS_NZ",REAL_ABS_NZ;
+"REAL_ABS_PI",REAL_ABS_PI;
+"REAL_ABS_POS",REAL_ABS_POS;
+"REAL_ABS_POW",REAL_ABS_POW;
+"REAL_ABS_REFL",REAL_ABS_REFL;
+"REAL_ABS_RPOW",REAL_ABS_RPOW;
+"REAL_ABS_SGN",REAL_ABS_SGN;
+"REAL_ABS_SIGN",REAL_ABS_SIGN;
+"REAL_ABS_SIGN2",REAL_ABS_SIGN2;
+"REAL_ABS_STILLNZ",REAL_ABS_STILLNZ;
+"REAL_ABS_SUB",REAL_ABS_SUB;
+"REAL_ABS_SUB_ABS",REAL_ABS_SUB_ABS;
+"REAL_ABS_SUB_INFNORM",REAL_ABS_SUB_INFNORM;
+"REAL_ABS_SUB_NORM",REAL_ABS_SUB_NORM;
+"REAL_ABS_SUP_LE",REAL_ABS_SUP_LE;
+"REAL_ABS_TRIANGLE",REAL_ABS_TRIANGLE;
+"REAL_ABS_TRIANGLE_LE",REAL_ABS_TRIANGLE_LE;
+"REAL_ABS_TRIANGLE_LT",REAL_ABS_TRIANGLE_LT;
+"REAL_ABS_ZERO",REAL_ABS_ZERO;
+"REAL_ACS",REAL_ACS;
+"REAL_ADD",REAL_ADD;
+"REAL_ADD2_SUB2",REAL_ADD2_SUB2;
+"REAL_ADD_AC",REAL_ADD_AC;
+"REAL_ADD_ARG",REAL_ADD_ARG;
+"REAL_ADD_ASSOC",REAL_ADD_ASSOC;
+"REAL_ADD_COS",REAL_ADD_COS;
+"REAL_ADD_LDISTRIB",REAL_ADD_LDISTRIB;
+"REAL_ADD_LID",REAL_ADD_LID;
+"REAL_ADD_LINV",REAL_ADD_LINV;
+"REAL_ADD_RDISTRIB",REAL_ADD_RDISTRIB;
+"REAL_ADD_RID",REAL_ADD_RID;
+"REAL_ADD_RINV",REAL_ADD_RINV;
+"REAL_ADD_SIN",REAL_ADD_SIN;
+"REAL_ADD_SUB",REAL_ADD_SUB;
+"REAL_ADD_SUB2",REAL_ADD_SUB2;
+"REAL_ADD_SYM",REAL_ADD_SYM;
+"REAL_ADD_TAN",REAL_ADD_TAN;
+"REAL_AFFINITY_EQ",REAL_AFFINITY_EQ;
+"REAL_AFFINITY_LE",REAL_AFFINITY_LE;
+"REAL_AFFINITY_LT",REAL_AFFINITY_LT;
+"REAL_ANTIDERIVATIVE_CONTINUOUS",REAL_ANTIDERIVATIVE_CONTINUOUS;
+"REAL_ANTIDERIVATIVE_INTEGRAL_CONTINUOUS",REAL_ANTIDERIVATIVE_INTEGRAL_CONTINUOUS;
+"REAL_ARCH",REAL_ARCH;
+"REAL_ARCH_INV",REAL_ARCH_INV;
+"REAL_ARCH_LT",REAL_ARCH_LT;
+"REAL_ARCH_POW",REAL_ARCH_POW;
+"REAL_ARCH_POW2",REAL_ARCH_POW2;
+"REAL_ARCH_POW_INV",REAL_ARCH_POW_INV;
+"REAL_ARCH_RDIV_EQ_0",REAL_ARCH_RDIV_EQ_0;
+"REAL_ARCH_SIMPLE",REAL_ARCH_SIMPLE;
+"REAL_ASN",REAL_ASN;
+"REAL_BEPPO_LEVI_DECREASING",REAL_BEPPO_LEVI_DECREASING;
+"REAL_BEPPO_LEVI_INCREASING",REAL_BEPPO_LEVI_INCREASING;
+"REAL_BEPPO_LEVI_MONOTONE_CONVERGENCE_DECREASING",REAL_BEPPO_LEVI_MONOTONE_CONVERGENCE_DECREASING;
+"REAL_BEPPO_LEVI_MONOTONE_CONVERGENCE_INCREASING",REAL_BEPPO_LEVI_MONOTONE_CONVERGENCE_INCREASING;
+"REAL_BINOMIAL_THEOREM",REAL_BINOMIAL_THEOREM;
+"REAL_BOUNDED",REAL_BOUNDED;
+"REAL_BOUNDED_POS",REAL_BOUNDED_POS;
+"REAL_BOUNDED_POS_LT",REAL_BOUNDED_POS_LT;
+"REAL_BOUNDED_REAL_INTERVAL",REAL_BOUNDED_REAL_INTERVAL;
+"REAL_BOUNDED_SUBSET",REAL_BOUNDED_SUBSET;
+"REAL_BOUNDED_UNION",REAL_BOUNDED_UNION;
+"REAL_BOUNDS_LE",REAL_BOUNDS_LE;
+"REAL_BOUNDS_LT",REAL_BOUNDS_LT;
+"REAL_CARD_INTSEG_INT",REAL_CARD_INTSEG_INT;
+"REAL_CLOSED",REAL_CLOSED;
+"REAL_CLOSED_DIFF",REAL_CLOSED_DIFF;
+"REAL_CLOSED_EMPTY",REAL_CLOSED_EMPTY;
+"REAL_CLOSED_HALFSPACE_GE",REAL_CLOSED_HALFSPACE_GE;
+"REAL_CLOSED_HALFSPACE_LE",REAL_CLOSED_HALFSPACE_LE;
+"REAL_CLOSED_IN",REAL_CLOSED_IN;
+"REAL_CLOSED_INTER",REAL_CLOSED_INTER;
+"REAL_CLOSED_INTERS",REAL_CLOSED_INTERS;
+"REAL_CLOSED_OPEN_INTERVAL",REAL_CLOSED_OPEN_INTERVAL;
+"REAL_CLOSED_REAL_INTERVAL",REAL_CLOSED_REAL_INTERVAL;
+"REAL_CLOSED_UNION",REAL_CLOSED_UNION;
+"REAL_CLOSED_UNIONS",REAL_CLOSED_UNIONS;
+"REAL_CLOSED_UNIV",REAL_CLOSED_UNIV;
+"REAL_CNJ",REAL_CNJ;
+"REAL_COMPACT_ATTAINS_INF",REAL_COMPACT_ATTAINS_INF;
+"REAL_COMPACT_ATTAINS_SUP",REAL_COMPACT_ATTAINS_SUP;
+"REAL_COMPACT_CONTINUOUS_IMAGE",REAL_COMPACT_CONTINUOUS_IMAGE;
+"REAL_COMPACT_EQ_BOUNDED_CLOSED",REAL_COMPACT_EQ_BOUNDED_CLOSED;
+"REAL_COMPACT_IMP_BOUNDED",REAL_COMPACT_IMP_BOUNDED;
+"REAL_COMPACT_IMP_CLOSED",REAL_COMPACT_IMP_CLOSED;
+"REAL_COMPACT_INTERVAL",REAL_COMPACT_INTERVAL;
+"REAL_COMPACT_UNIFORMLY_CONTINUOUS",REAL_COMPACT_UNIFORMLY_CONTINUOUS;
+"REAL_COMPACT_UNION",REAL_COMPACT_UNION;
+"REAL_COMPLETE",REAL_COMPLETE;
+"REAL_COMPLETE_SOMEPOS",REAL_COMPLETE_SOMEPOS;
+"REAL_COMPLEX_CONTINUOUS_ATREAL",REAL_COMPLEX_CONTINUOUS_ATREAL;
+"REAL_COMPLEX_CONTINUOUS_WITHINREAL",REAL_COMPLEX_CONTINUOUS_WITHINREAL;
+"REAL_COMPLEX_MEASURABLE_ON",REAL_COMPLEX_MEASURABLE_ON;
+"REAL_CONTINUOUS_ABS",REAL_CONTINUOUS_ABS;
+"REAL_CONTINUOUS_ADD",REAL_CONTINUOUS_ADD;
+"REAL_CONTINUOUS_ADDITIVE_EXTEND",REAL_CONTINUOUS_ADDITIVE_EXTEND;
+"REAL_CONTINUOUS_ADDITIVE_IMP_LINEAR",REAL_CONTINUOUS_ADDITIVE_IMP_LINEAR;
+"REAL_CONTINUOUS_ADDITIVE_IMP_LINEAR_INTERVAL",REAL_CONTINUOUS_ADDITIVE_IMP_LINEAR_INTERVAL;
+"REAL_CONTINUOUS_AT",REAL_CONTINUOUS_AT;
+"REAL_CONTINUOUS_ATREAL",REAL_CONTINUOUS_ATREAL;
+"REAL_CONTINUOUS_ATREAL_COMPOSE",REAL_CONTINUOUS_ATREAL_COMPOSE;
+"REAL_CONTINUOUS_ATREAL_SQRT_COMPOSE",REAL_CONTINUOUS_ATREAL_SQRT_COMPOSE;
+"REAL_CONTINUOUS_ATREAL_WITHINREAL",REAL_CONTINUOUS_ATREAL_WITHINREAL;
+"REAL_CONTINUOUS_ATTAINS_INF",REAL_CONTINUOUS_ATTAINS_INF;
+"REAL_CONTINUOUS_ATTAINS_SUP",REAL_CONTINUOUS_ATTAINS_SUP;
+"REAL_CONTINUOUS_AT_ACS",REAL_CONTINUOUS_AT_ACS;
+"REAL_CONTINUOUS_AT_ARG",REAL_CONTINUOUS_AT_ARG;
+"REAL_CONTINUOUS_AT_ASN",REAL_CONTINUOUS_AT_ASN;
+"REAL_CONTINUOUS_AT_ATN",REAL_CONTINUOUS_AT_ATN;
+"REAL_CONTINUOUS_AT_COMPONENT",REAL_CONTINUOUS_AT_COMPONENT;
+"REAL_CONTINUOUS_AT_COMPOSE",REAL_CONTINUOUS_AT_COMPOSE;
+"REAL_CONTINUOUS_AT_COS",REAL_CONTINUOUS_AT_COS;
+"REAL_CONTINUOUS_AT_EXP",REAL_CONTINUOUS_AT_EXP;
+"REAL_CONTINUOUS_AT_ID",REAL_CONTINUOUS_AT_ID;
+"REAL_CONTINUOUS_AT_LINEAR_IMAGE",REAL_CONTINUOUS_AT_LINEAR_IMAGE;
+"REAL_CONTINUOUS_AT_LOG",REAL_CONTINUOUS_AT_LOG;
+"REAL_CONTINUOUS_AT_RPOW",REAL_CONTINUOUS_AT_RPOW;
+"REAL_CONTINUOUS_AT_SIN",REAL_CONTINUOUS_AT_SIN;
+"REAL_CONTINUOUS_AT_SQRT",REAL_CONTINUOUS_AT_SQRT;
+"REAL_CONTINUOUS_AT_SQRT_COMPOSE",REAL_CONTINUOUS_AT_SQRT_COMPOSE;
+"REAL_CONTINUOUS_AT_TAN",REAL_CONTINUOUS_AT_TAN;
+"REAL_CONTINUOUS_AT_TRANSLATION",REAL_CONTINUOUS_AT_TRANSLATION;
+"REAL_CONTINUOUS_AT_WITHIN",REAL_CONTINUOUS_AT_WITHIN;
+"REAL_CONTINUOUS_COMPLEX_COMPONENTS_AT",REAL_CONTINUOUS_COMPLEX_COMPONENTS_AT;
+"REAL_CONTINUOUS_COMPLEX_COMPONENTS_WITHIN",REAL_CONTINUOUS_COMPLEX_COMPONENTS_WITHIN;
+"REAL_CONTINUOUS_CONST",REAL_CONTINUOUS_CONST;
+"REAL_CONTINUOUS_CONTINUOUS",REAL_CONTINUOUS_CONTINUOUS;
+"REAL_CONTINUOUS_CONTINUOUS1",REAL_CONTINUOUS_CONTINUOUS1;
+"REAL_CONTINUOUS_CONTINUOUS_ATREAL",REAL_CONTINUOUS_CONTINUOUS_ATREAL;
+"REAL_CONTINUOUS_CONTINUOUS_ATREAL_COMPOSE",REAL_CONTINUOUS_CONTINUOUS_ATREAL_COMPOSE;
+"REAL_CONTINUOUS_CONTINUOUS_AT_COMPOSE",REAL_CONTINUOUS_CONTINUOUS_AT_COMPOSE;
+"REAL_CONTINUOUS_CONTINUOUS_WITHINREAL",REAL_CONTINUOUS_CONTINUOUS_WITHINREAL;
+"REAL_CONTINUOUS_CONTINUOUS_WITHINREAL_COMPOSE",REAL_CONTINUOUS_CONTINUOUS_WITHINREAL_COMPOSE;
+"REAL_CONTINUOUS_CONTINUOUS_WITHIN_COMPOSE",REAL_CONTINUOUS_CONTINUOUS_WITHIN_COMPOSE;
+"REAL_CONTINUOUS_DIST_AT",REAL_CONTINUOUS_DIST_AT;
+"REAL_CONTINUOUS_DIST_WITHIN",REAL_CONTINUOUS_DIST_WITHIN;
+"REAL_CONTINUOUS_DIV",REAL_CONTINUOUS_DIV;
+"REAL_CONTINUOUS_DIV_AT",REAL_CONTINUOUS_DIV_AT;
+"REAL_CONTINUOUS_DIV_ATREAL",REAL_CONTINUOUS_DIV_ATREAL;
+"REAL_CONTINUOUS_DIV_WITHIN",REAL_CONTINUOUS_DIV_WITHIN;
+"REAL_CONTINUOUS_DIV_WITHINREAL",REAL_CONTINUOUS_DIV_WITHINREAL;
+"REAL_CONTINUOUS_FLOOR",REAL_CONTINUOUS_FLOOR;
+"REAL_CONTINUOUS_FRAC",REAL_CONTINUOUS_FRAC;
+"REAL_CONTINUOUS_IMP_REAL_MEASURABLE_ON_CLOSED_SUBSET",REAL_CONTINUOUS_IMP_REAL_MEASURABLE_ON_CLOSED_SUBSET;
+"REAL_CONTINUOUS_INJECTIVE_IFF_MONOTONIC",REAL_CONTINUOUS_INJECTIVE_IFF_MONOTONIC;
+"REAL_CONTINUOUS_INV",REAL_CONTINUOUS_INV;
+"REAL_CONTINUOUS_INV_AT",REAL_CONTINUOUS_INV_AT;
+"REAL_CONTINUOUS_INV_ATREAL",REAL_CONTINUOUS_INV_ATREAL;
+"REAL_CONTINUOUS_INV_WITHIN",REAL_CONTINUOUS_INV_WITHIN;
+"REAL_CONTINUOUS_INV_WITHINREAL",REAL_CONTINUOUS_INV_WITHINREAL;
+"REAL_CONTINUOUS_LMUL",REAL_CONTINUOUS_LMUL;
+"REAL_CONTINUOUS_MAX",REAL_CONTINUOUS_MAX;
+"REAL_CONTINUOUS_MEASURE_IN_HALFSPACE_LE",REAL_CONTINUOUS_MEASURE_IN_HALFSPACE_LE;
+"REAL_CONTINUOUS_MIN",REAL_CONTINUOUS_MIN;
+"REAL_CONTINUOUS_MUL",REAL_CONTINUOUS_MUL;
+"REAL_CONTINUOUS_NEG",REAL_CONTINUOUS_NEG;
+"REAL_CONTINUOUS_NORM_AT",REAL_CONTINUOUS_NORM_AT;
+"REAL_CONTINUOUS_NORM_WITHIN",REAL_CONTINUOUS_NORM_WITHIN;
+"REAL_CONTINUOUS_ON",REAL_CONTINUOUS_ON;
+"REAL_CONTINUOUS_ON_ACS",REAL_CONTINUOUS_ON_ACS;
+"REAL_CONTINUOUS_ON_ADD",REAL_CONTINUOUS_ON_ADD;
+"REAL_CONTINUOUS_ON_ASN",REAL_CONTINUOUS_ON_ASN;
+"REAL_CONTINUOUS_ON_ATN",REAL_CONTINUOUS_ON_ATN;
+"REAL_CONTINUOUS_ON_CASES",REAL_CONTINUOUS_ON_CASES;
+"REAL_CONTINUOUS_ON_CASES_OPEN",REAL_CONTINUOUS_ON_CASES_OPEN;
+"REAL_CONTINUOUS_ON_COMPOSE",REAL_CONTINUOUS_ON_COMPOSE;
+"REAL_CONTINUOUS_ON_COMPOSE_FRAC",REAL_CONTINUOUS_ON_COMPOSE_FRAC;
+"REAL_CONTINUOUS_ON_CONST",REAL_CONTINUOUS_ON_CONST;
+"REAL_CONTINUOUS_ON_CONST_DYADIC_RATIONALS",REAL_CONTINUOUS_ON_CONST_DYADIC_RATIONALS;
+"REAL_CONTINUOUS_ON_COS",REAL_CONTINUOUS_ON_COS;
+"REAL_CONTINUOUS_ON_EQ",REAL_CONTINUOUS_ON_EQ;
+"REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN",REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+"REAL_CONTINUOUS_ON_EQ_REAL_CONTINUOUS_AT",REAL_CONTINUOUS_ON_EQ_REAL_CONTINUOUS_AT;
+"REAL_CONTINUOUS_ON_EXP",REAL_CONTINUOUS_ON_EXP;
+"REAL_CONTINUOUS_ON_ID",REAL_CONTINUOUS_ON_ID;
+"REAL_CONTINUOUS_ON_INVERSE",REAL_CONTINUOUS_ON_INVERSE;
+"REAL_CONTINUOUS_ON_INVERSE_ALT",REAL_CONTINUOUS_ON_INVERSE_ALT;
+"REAL_CONTINUOUS_ON_LMUL",REAL_CONTINUOUS_ON_LMUL;
+"REAL_CONTINUOUS_ON_LOG",REAL_CONTINUOUS_ON_LOG;
+"REAL_CONTINUOUS_ON_MUL",REAL_CONTINUOUS_ON_MUL;
+"REAL_CONTINUOUS_ON_NEG",REAL_CONTINUOUS_ON_NEG;
+"REAL_CONTINUOUS_ON_POW",REAL_CONTINUOUS_ON_POW;
+"REAL_CONTINUOUS_ON_RMUL",REAL_CONTINUOUS_ON_RMUL;
+"REAL_CONTINUOUS_ON_RPOW",REAL_CONTINUOUS_ON_RPOW;
+"REAL_CONTINUOUS_ON_SIN",REAL_CONTINUOUS_ON_SIN;
+"REAL_CONTINUOUS_ON_SQRT",REAL_CONTINUOUS_ON_SQRT;
+"REAL_CONTINUOUS_ON_SUB",REAL_CONTINUOUS_ON_SUB;
+"REAL_CONTINUOUS_ON_SUBSET",REAL_CONTINUOUS_ON_SUBSET;
+"REAL_CONTINUOUS_ON_SUM",REAL_CONTINUOUS_ON_SUM;
+"REAL_CONTINUOUS_ON_TAN",REAL_CONTINUOUS_ON_TAN;
+"REAL_CONTINUOUS_ON_UNION",REAL_CONTINUOUS_ON_UNION;
+"REAL_CONTINUOUS_ON_UNION_OPEN",REAL_CONTINUOUS_ON_UNION_OPEN;
+"REAL_CONTINUOUS_POW",REAL_CONTINUOUS_POW;
+"REAL_CONTINUOUS_REAL_CONTINUOUS_ATREAL",REAL_CONTINUOUS_REAL_CONTINUOUS_ATREAL;
+"REAL_CONTINUOUS_REAL_CONTINUOUS_WITHINREAL",REAL_CONTINUOUS_REAL_CONTINUOUS_WITHINREAL;
+"REAL_CONTINUOUS_REAL_POLYMONIAL_FUNCTION",REAL_CONTINUOUS_REAL_POLYMONIAL_FUNCTION;
+"REAL_CONTINUOUS_RMUL",REAL_CONTINUOUS_RMUL;
+"REAL_CONTINUOUS_SUB",REAL_CONTINUOUS_SUB;
+"REAL_CONTINUOUS_TRIVIAL_LIMIT",REAL_CONTINUOUS_TRIVIAL_LIMIT;
+"REAL_CONTINUOUS_WITHIN",REAL_CONTINUOUS_WITHIN;
+"REAL_CONTINUOUS_WITHINREAL",REAL_CONTINUOUS_WITHINREAL;
+"REAL_CONTINUOUS_WITHINREAL_COMPOSE",REAL_CONTINUOUS_WITHINREAL_COMPOSE;
+"REAL_CONTINUOUS_WITHINREAL_SQRT_COMPOSE",REAL_CONTINUOUS_WITHINREAL_SQRT_COMPOSE;
+"REAL_CONTINUOUS_WITHINREAL_SUBSET",REAL_CONTINUOUS_WITHINREAL_SUBSET;
+"REAL_CONTINUOUS_WITHIN_ACS",REAL_CONTINUOUS_WITHIN_ACS;
+"REAL_CONTINUOUS_WITHIN_ACS_STRONG",REAL_CONTINUOUS_WITHIN_ACS_STRONG;
+"REAL_CONTINUOUS_WITHIN_ASN",REAL_CONTINUOUS_WITHIN_ASN;
+"REAL_CONTINUOUS_WITHIN_ASN_STRONG",REAL_CONTINUOUS_WITHIN_ASN_STRONG;
+"REAL_CONTINUOUS_WITHIN_ATN",REAL_CONTINUOUS_WITHIN_ATN;
+"REAL_CONTINUOUS_WITHIN_COMPOSE",REAL_CONTINUOUS_WITHIN_COMPOSE;
+"REAL_CONTINUOUS_WITHIN_COS",REAL_CONTINUOUS_WITHIN_COS;
+"REAL_CONTINUOUS_WITHIN_EXP",REAL_CONTINUOUS_WITHIN_EXP;
+"REAL_CONTINUOUS_WITHIN_ID",REAL_CONTINUOUS_WITHIN_ID;
+"REAL_CONTINUOUS_WITHIN_LOG",REAL_CONTINUOUS_WITHIN_LOG;
+"REAL_CONTINUOUS_WITHIN_RPOW",REAL_CONTINUOUS_WITHIN_RPOW;
+"REAL_CONTINUOUS_WITHIN_SIN",REAL_CONTINUOUS_WITHIN_SIN;
+"REAL_CONTINUOUS_WITHIN_SQRT",REAL_CONTINUOUS_WITHIN_SQRT;
+"REAL_CONTINUOUS_WITHIN_SQRT_COMPOSE",REAL_CONTINUOUS_WITHIN_SQRT_COMPOSE;
+"REAL_CONTINUOUS_WITHIN_SQRT_STRONG",REAL_CONTINUOUS_WITHIN_SQRT_STRONG;
+"REAL_CONTINUOUS_WITHIN_SUBSET",REAL_CONTINUOUS_WITHIN_SUBSET;
+"REAL_CONTINUOUS_WITHIN_TAN",REAL_CONTINUOUS_WITHIN_TAN;
+"REAL_CONVERGENT_IMP_BOUNDED",REAL_CONVERGENT_IMP_BOUNDED;
+"REAL_CONVEX_ADD",REAL_CONVEX_ADD;
+"REAL_CONVEX_BOUND2_LT",REAL_CONVEX_BOUND2_LT;
+"REAL_CONVEX_BOUND_LE",REAL_CONVEX_BOUND_LE;
+"REAL_CONVEX_BOUND_LT",REAL_CONVEX_BOUND_LT;
+"REAL_CONVEX_DISTANCE",REAL_CONVEX_DISTANCE;
+"REAL_CONVEX_LMUL",REAL_CONVEX_LMUL;
+"REAL_CONVEX_LOCAL_GLOBAL_MINIMUM",REAL_CONVEX_LOCAL_GLOBAL_MINIMUM;
+"REAL_CONVEX_LOWER",REAL_CONVEX_LOWER;
+"REAL_CONVEX_ON",REAL_CONVEX_ON;
+"REAL_CONVEX_ON_ASYM",REAL_CONVEX_ON_ASYM;
+"REAL_CONVEX_ON_CONTINUOUS",REAL_CONVEX_ON_CONTINUOUS;
+"REAL_CONVEX_ON_DERIVATIVES",REAL_CONVEX_ON_DERIVATIVES;
+"REAL_CONVEX_ON_DERIVATIVES_IMP",REAL_CONVEX_ON_DERIVATIVES_IMP;
+"REAL_CONVEX_ON_DERIVATIVE_INCREASING",REAL_CONVEX_ON_DERIVATIVE_INCREASING;
+"REAL_CONVEX_ON_DERIVATIVE_INCREASING_IMP",REAL_CONVEX_ON_DERIVATIVE_INCREASING_IMP;
+"REAL_CONVEX_ON_DERIVATIVE_SECANT",REAL_CONVEX_ON_DERIVATIVE_SECANT;
+"REAL_CONVEX_ON_DERIVATIVE_SECANT_IMP",REAL_CONVEX_ON_DERIVATIVE_SECANT_IMP;
+"REAL_CONVEX_ON_EXP",REAL_CONVEX_ON_EXP;
+"REAL_CONVEX_ON_JENSEN",REAL_CONVEX_ON_JENSEN;
+"REAL_CONVEX_ON_LEFT_SECANT",REAL_CONVEX_ON_LEFT_SECANT;
+"REAL_CONVEX_ON_LEFT_SECANT_MUL",REAL_CONVEX_ON_LEFT_SECANT_MUL;
+"REAL_CONVEX_ON_RIGHT_SEQUENT",REAL_CONVEX_ON_RIGHT_SEQUENT;
+"REAL_CONVEX_ON_RIGHT_SEQUENT_MUL",REAL_CONVEX_ON_RIGHT_SEQUENT_MUL;
+"REAL_CONVEX_ON_RPOW",REAL_CONVEX_ON_RPOW;
+"REAL_CONVEX_ON_SECANT_DERIVATIVE",REAL_CONVEX_ON_SECANT_DERIVATIVE;
+"REAL_CONVEX_ON_SECANT_DERIVATIVE_IMP",REAL_CONVEX_ON_SECANT_DERIVATIVE_IMP;
+"REAL_CONVEX_ON_SECOND_DERIVATIVE",REAL_CONVEX_ON_SECOND_DERIVATIVE;
+"REAL_CONVEX_ON_SUBSET",REAL_CONVEX_ON_SUBSET;
+"REAL_CONVEX_RMUL",REAL_CONVEX_RMUL;
+"REAL_COS",REAL_COS;
+"REAL_CX",REAL_CX;
+"REAL_DERIVATIVE_IVT_DECREASING",REAL_DERIVATIVE_IVT_DECREASING;
+"REAL_DERIVATIVE_IVT_INCREASING",REAL_DERIVATIVE_IVT_INCREASING;
+"REAL_DERIVATIVE_NEG_LEFT_MAXIMUM",REAL_DERIVATIVE_NEG_LEFT_MAXIMUM;
+"REAL_DERIVATIVE_NEG_RIGHT_MINIMUM",REAL_DERIVATIVE_NEG_RIGHT_MINIMUM;
+"REAL_DERIVATIVE_POS_LEFT_MINIMUM",REAL_DERIVATIVE_POS_LEFT_MINIMUM;
+"REAL_DERIVATIVE_POS_RIGHT_MAXIMUM",REAL_DERIVATIVE_POS_RIGHT_MAXIMUM;
+"REAL_DERIVATIVE_UNIQUE_ATREAL",REAL_DERIVATIVE_UNIQUE_ATREAL;
+"REAL_DERIVATIVE_ZERO_MAXMIN",REAL_DERIVATIVE_ZERO_MAXMIN;
+"REAL_DIFFERENTIABLE_ADD",REAL_DIFFERENTIABLE_ADD;
+"REAL_DIFFERENTIABLE_AT",REAL_DIFFERENTIABLE_AT;
+"REAL_DIFFERENTIABLE_ATREAL_WITHIN",REAL_DIFFERENTIABLE_ATREAL_WITHIN;
+"REAL_DIFFERENTIABLE_AT_ACS",REAL_DIFFERENTIABLE_AT_ACS;
+"REAL_DIFFERENTIABLE_AT_ASN",REAL_DIFFERENTIABLE_AT_ASN;
+"REAL_DIFFERENTIABLE_AT_ATN",REAL_DIFFERENTIABLE_AT_ATN;
+"REAL_DIFFERENTIABLE_AT_COS",REAL_DIFFERENTIABLE_AT_COS;
+"REAL_DIFFERENTIABLE_AT_EXP",REAL_DIFFERENTIABLE_AT_EXP;
+"REAL_DIFFERENTIABLE_AT_LOG",REAL_DIFFERENTIABLE_AT_LOG;
+"REAL_DIFFERENTIABLE_AT_RPOW",REAL_DIFFERENTIABLE_AT_RPOW;
+"REAL_DIFFERENTIABLE_AT_SIN",REAL_DIFFERENTIABLE_AT_SIN;
+"REAL_DIFFERENTIABLE_AT_SQRT",REAL_DIFFERENTIABLE_AT_SQRT;
+"REAL_DIFFERENTIABLE_AT_TAN",REAL_DIFFERENTIABLE_AT_TAN;
+"REAL_DIFFERENTIABLE_BOUND",REAL_DIFFERENTIABLE_BOUND;
+"REAL_DIFFERENTIABLE_CARATHEODORY_ATREAL",REAL_DIFFERENTIABLE_CARATHEODORY_ATREAL;
+"REAL_DIFFERENTIABLE_CARATHEODORY_WITHINREAL",REAL_DIFFERENTIABLE_CARATHEODORY_WITHINREAL;
+"REAL_DIFFERENTIABLE_COMPOSE_ATREAL",REAL_DIFFERENTIABLE_COMPOSE_ATREAL;
+"REAL_DIFFERENTIABLE_COMPOSE_WITHIN",REAL_DIFFERENTIABLE_COMPOSE_WITHIN;
+"REAL_DIFFERENTIABLE_CONST",REAL_DIFFERENTIABLE_CONST;
+"REAL_DIFFERENTIABLE_DIV_ATREAL",REAL_DIFFERENTIABLE_DIV_ATREAL;
+"REAL_DIFFERENTIABLE_DIV_WITHIN",REAL_DIFFERENTIABLE_DIV_WITHIN;
+"REAL_DIFFERENTIABLE_EQ",REAL_DIFFERENTIABLE_EQ;
+"REAL_DIFFERENTIABLE_ID",REAL_DIFFERENTIABLE_ID;
+"REAL_DIFFERENTIABLE_IMP_CONTINUOUS_ATREAL",REAL_DIFFERENTIABLE_IMP_CONTINUOUS_ATREAL;
+"REAL_DIFFERENTIABLE_IMP_CONTINUOUS_WITHINREAL",REAL_DIFFERENTIABLE_IMP_CONTINUOUS_WITHINREAL;
+"REAL_DIFFERENTIABLE_INV_ATREAL",REAL_DIFFERENTIABLE_INV_ATREAL;
+"REAL_DIFFERENTIABLE_INV_WITHIN",REAL_DIFFERENTIABLE_INV_WITHIN;
+"REAL_DIFFERENTIABLE_MUL_ATREAL",REAL_DIFFERENTIABLE_MUL_ATREAL;
+"REAL_DIFFERENTIABLE_MUL_WITHIN",REAL_DIFFERENTIABLE_MUL_WITHIN;
+"REAL_DIFFERENTIABLE_NEG",REAL_DIFFERENTIABLE_NEG;
+"REAL_DIFFERENTIABLE_ON_ADD",REAL_DIFFERENTIABLE_ON_ADD;
+"REAL_DIFFERENTIABLE_ON_COMPOSE",REAL_DIFFERENTIABLE_ON_COMPOSE;
+"REAL_DIFFERENTIABLE_ON_CONST",REAL_DIFFERENTIABLE_ON_CONST;
+"REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE",REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE;
+"REAL_DIFFERENTIABLE_ON_DIV",REAL_DIFFERENTIABLE_ON_DIV;
+"REAL_DIFFERENTIABLE_ON_ID",REAL_DIFFERENTIABLE_ON_ID;
+"REAL_DIFFERENTIABLE_ON_IMP_DIFFERENTIABLE_ATREAL",REAL_DIFFERENTIABLE_ON_IMP_DIFFERENTIABLE_ATREAL;
+"REAL_DIFFERENTIABLE_ON_IMP_DIFFERENTIABLE_WITHIN",REAL_DIFFERENTIABLE_ON_IMP_DIFFERENTIABLE_WITHIN;
+"REAL_DIFFERENTIABLE_ON_IMP_REAL_CONTINUOUS_ON",REAL_DIFFERENTIABLE_ON_IMP_REAL_CONTINUOUS_ON;
+"REAL_DIFFERENTIABLE_ON_INV",REAL_DIFFERENTIABLE_ON_INV;
+"REAL_DIFFERENTIABLE_ON_MUL",REAL_DIFFERENTIABLE_ON_MUL;
+"REAL_DIFFERENTIABLE_ON_NEG",REAL_DIFFERENTIABLE_ON_NEG;
+"REAL_DIFFERENTIABLE_ON_POW",REAL_DIFFERENTIABLE_ON_POW;
+"REAL_DIFFERENTIABLE_ON_REAL_OPEN",REAL_DIFFERENTIABLE_ON_REAL_OPEN;
+"REAL_DIFFERENTIABLE_ON_SUB",REAL_DIFFERENTIABLE_ON_SUB;
+"REAL_DIFFERENTIABLE_ON_SUBSET",REAL_DIFFERENTIABLE_ON_SUBSET;
+"REAL_DIFFERENTIABLE_ON_SUM",REAL_DIFFERENTIABLE_ON_SUM;
+"REAL_DIFFERENTIABLE_POW_ATREAL",REAL_DIFFERENTIABLE_POW_ATREAL;
+"REAL_DIFFERENTIABLE_POW_WITHIN",REAL_DIFFERENTIABLE_POW_WITHIN;
+"REAL_DIFFERENTIABLE_SUB",REAL_DIFFERENTIABLE_SUB;
+"REAL_DIFFERENTIABLE_TRANSFORM",REAL_DIFFERENTIABLE_TRANSFORM;
+"REAL_DIFFERENTIABLE_TRANSFORM_ATREAL",REAL_DIFFERENTIABLE_TRANSFORM_ATREAL;
+"REAL_DIFFERENTIABLE_TRANSFORM_WITHIN",REAL_DIFFERENTIABLE_TRANSFORM_WITHIN;
+"REAL_DIFFERENTIABLE_WITHIN",REAL_DIFFERENTIABLE_WITHIN;
+"REAL_DIFFERENTIABLE_WITHIN_ACS",REAL_DIFFERENTIABLE_WITHIN_ACS;
+"REAL_DIFFERENTIABLE_WITHIN_ASN",REAL_DIFFERENTIABLE_WITHIN_ASN;
+"REAL_DIFFERENTIABLE_WITHIN_ATN",REAL_DIFFERENTIABLE_WITHIN_ATN;
+"REAL_DIFFERENTIABLE_WITHIN_COS",REAL_DIFFERENTIABLE_WITHIN_COS;
+"REAL_DIFFERENTIABLE_WITHIN_EXP",REAL_DIFFERENTIABLE_WITHIN_EXP;
+"REAL_DIFFERENTIABLE_WITHIN_LOG",REAL_DIFFERENTIABLE_WITHIN_LOG;
+"REAL_DIFFERENTIABLE_WITHIN_SIN",REAL_DIFFERENTIABLE_WITHIN_SIN;
+"REAL_DIFFERENTIABLE_WITHIN_SQRT",REAL_DIFFERENTIABLE_WITHIN_SQRT;
+"REAL_DIFFERENTIABLE_WITHIN_SUBSET",REAL_DIFFERENTIABLE_WITHIN_SUBSET;
+"REAL_DIFFERENTIABLE_WITHIN_TAN",REAL_DIFFERENTIABLE_WITHIN_TAN;
+"REAL_DIFFSQ",REAL_DIFFSQ;
+"REAL_DIFF_CHAIN_ATREAL",REAL_DIFF_CHAIN_ATREAL;
+"REAL_DIFF_CHAIN_WITHIN",REAL_DIFF_CHAIN_WITHIN;
+"REAL_DINI",REAL_DINI;
+"REAL_DIV",REAL_DIV;
+"REAL_DIV_1",REAL_DIV_1;
+"REAL_DIV_EQ_0",REAL_DIV_EQ_0;
+"REAL_DIV_LMUL",REAL_DIV_LMUL;
+"REAL_DIV_POW2",REAL_DIV_POW2;
+"REAL_DIV_POW2_ALT",REAL_DIV_POW2_ALT;
+"REAL_DIV_REFL",REAL_DIV_REFL;
+"REAL_DIV_RMUL",REAL_DIV_RMUL;
+"REAL_DIV_SQRT",REAL_DIV_SQRT;
+"REAL_DOMINATED_CONVERGENCE",REAL_DOMINATED_CONVERGENCE;
+"REAL_DOWN",REAL_DOWN;
+"REAL_DOWN2",REAL_DOWN2;
+"REAL_ENTIRE",REAL_ENTIRE;
+"REAL_EQ_ADD_LCANCEL",REAL_EQ_ADD_LCANCEL;
+"REAL_EQ_ADD_LCANCEL_0",REAL_EQ_ADD_LCANCEL_0;
+"REAL_EQ_ADD_RCANCEL",REAL_EQ_ADD_RCANCEL;
+"REAL_EQ_ADD_RCANCEL_0",REAL_EQ_ADD_RCANCEL_0;
+"REAL_EQ_AFFINITY",REAL_EQ_AFFINITY;
+"REAL_EQ_IMP_LE",REAL_EQ_IMP_LE;
+"REAL_EQ_INTEGERS",REAL_EQ_INTEGERS;
+"REAL_EQ_INTEGERS_IMP",REAL_EQ_INTEGERS_IMP;
+"REAL_EQ_INV2",REAL_EQ_INV2;
+"REAL_EQ_LCANCEL_IMP",REAL_EQ_LCANCEL_IMP;
+"REAL_EQ_LDIV_EQ",REAL_EQ_LDIV_EQ;
+"REAL_EQ_MUL_LCANCEL",REAL_EQ_MUL_LCANCEL;
+"REAL_EQ_MUL_RCANCEL",REAL_EQ_MUL_RCANCEL;
+"REAL_EQ_NEG2",REAL_EQ_NEG2;
+"REAL_EQ_RCANCEL_IMP",REAL_EQ_RCANCEL_IMP;
+"REAL_EQ_RDIV_EQ",REAL_EQ_RDIV_EQ;
+"REAL_EQ_SQUARE_ABS",REAL_EQ_SQUARE_ABS;
+"REAL_EQ_SUB_LADD",REAL_EQ_SUB_LADD;
+"REAL_EQ_SUB_RADD",REAL_EQ_SUB_RADD;
+"REAL_EXISTS",REAL_EXISTS;
+"REAL_EXP",REAL_EXP;
+"REAL_EXP_0",REAL_EXP_0;
+"REAL_EXP_ADD",REAL_EXP_ADD;
+"REAL_EXP_ADD_MUL",REAL_EXP_ADD_MUL;
+"REAL_EXP_BOUND_LEMMA",REAL_EXP_BOUND_LEMMA;
+"REAL_EXP_EQ_1",REAL_EXP_EQ_1;
+"REAL_EXP_INJ",REAL_EXP_INJ;
+"REAL_EXP_LE_X",REAL_EXP_LE_X;
+"REAL_EXP_LOG",REAL_EXP_LOG;
+"REAL_EXP_LT_1",REAL_EXP_LT_1;
+"REAL_EXP_MONO_IMP",REAL_EXP_MONO_IMP;
+"REAL_EXP_MONO_LE",REAL_EXP_MONO_LE;
+"REAL_EXP_MONO_LT",REAL_EXP_MONO_LT;
+"REAL_EXP_N",REAL_EXP_N;
+"REAL_EXP_NEG",REAL_EXP_NEG;
+"REAL_EXP_NEG_MUL",REAL_EXP_NEG_MUL;
+"REAL_EXP_NEG_MUL2",REAL_EXP_NEG_MUL2;
+"REAL_EXP_NZ",REAL_EXP_NZ;
+"REAL_EXP_POS_LE",REAL_EXP_POS_LE;
+"REAL_EXP_POS_LT",REAL_EXP_POS_LT;
+"REAL_EXP_SUB",REAL_EXP_SUB;
+"REAL_EXP_SUM",REAL_EXP_SUM;
+"REAL_FLOOR_ADD",REAL_FLOOR_ADD;
+"REAL_FLOOR_EQ",REAL_FLOOR_EQ;
+"REAL_FLOOR_LE",REAL_FLOOR_LE;
+"REAL_FLOOR_LT",REAL_FLOOR_LT;
+"REAL_FLOOR_REFL",REAL_FLOOR_REFL;
+"REAL_FRAC_ADD",REAL_FRAC_ADD;
+"REAL_FRAC_EQ",REAL_FRAC_EQ;
+"REAL_FRAC_EQ_0",REAL_FRAC_EQ_0;
+"REAL_FRAC_POS_LT",REAL_FRAC_POS_LT;
+"REAL_FRAC_ZERO",REAL_FRAC_ZERO;
+"REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS",REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS;
+"REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR",REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR;
+"REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG",REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG;
+"REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG",REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG;
+"REAL_HALF",REAL_HALF;
+"REAL_HREAL_LEMMA1",REAL_HREAL_LEMMA1;
+"REAL_HREAL_LEMMA2",REAL_HREAL_LEMMA2;
+"REAL_IMP_CNJ",REAL_IMP_CNJ;
+"REAL_INDEFINITE_INTEGRAL_CONTINUOUS_LEFT",REAL_INDEFINITE_INTEGRAL_CONTINUOUS_LEFT;
+"REAL_INDEFINITE_INTEGRAL_CONTINUOUS_RIGHT",REAL_INDEFINITE_INTEGRAL_CONTINUOUS_RIGHT;
+"REAL_INFSUM",REAL_INFSUM;
+"REAL_INFSUM_0",REAL_INFSUM_0;
+"REAL_INFSUM_ADD",REAL_INFSUM_ADD;
+"REAL_INFSUM_COMPLEX",REAL_INFSUM_COMPLEX;
+"REAL_INFSUM_EQ",REAL_INFSUM_EQ;
+"REAL_INFSUM_LMUL",REAL_INFSUM_LMUL;
+"REAL_INFSUM_NEG",REAL_INFSUM_NEG;
+"REAL_INFSUM_RESTRICT",REAL_INFSUM_RESTRICT;
+"REAL_INFSUM_RMUL",REAL_INFSUM_RMUL;
+"REAL_INFSUM_SUB",REAL_INFSUM_SUB;
+"REAL_INFSUM_UNIQUE",REAL_INFSUM_UNIQUE;
+"REAL_INF_ASCLOSE",REAL_INF_ASCLOSE;
+"REAL_INF_BOUNDS",REAL_INF_BOUNDS;
+"REAL_INF_LE_FINITE",REAL_INF_LE_FINITE;
+"REAL_INF_LT_FINITE",REAL_INF_LT_FINITE;
+"REAL_INF_UNIQUE",REAL_INF_UNIQUE;
+"REAL_INTEGRABLE_0",REAL_INTEGRABLE_0;
+"REAL_INTEGRABLE_ADD",REAL_INTEGRABLE_ADD;
+"REAL_INTEGRABLE_AFFINITY",REAL_INTEGRABLE_AFFINITY;
+"REAL_INTEGRABLE_COMBINE",REAL_INTEGRABLE_COMBINE;
+"REAL_INTEGRABLE_CONST",REAL_INTEGRABLE_CONST;
+"REAL_INTEGRABLE_CONTINUOUS",REAL_INTEGRABLE_CONTINUOUS;
+"REAL_INTEGRABLE_DECREASING",REAL_INTEGRABLE_DECREASING;
+"REAL_INTEGRABLE_DECREASING_PRODUCT",REAL_INTEGRABLE_DECREASING_PRODUCT;
+"REAL_INTEGRABLE_DECREASING_PRODUCT_UNIV",REAL_INTEGRABLE_DECREASING_PRODUCT_UNIV;
+"REAL_INTEGRABLE_EQ",REAL_INTEGRABLE_EQ;
+"REAL_INTEGRABLE_INCREASING",REAL_INTEGRABLE_INCREASING;
+"REAL_INTEGRABLE_INCREASING_PRODUCT",REAL_INTEGRABLE_INCREASING_PRODUCT;
+"REAL_INTEGRABLE_INCREASING_PRODUCT_UNIV",REAL_INTEGRABLE_INCREASING_PRODUCT_UNIV;
+"REAL_INTEGRABLE_INTEGRAL",REAL_INTEGRABLE_INTEGRAL;
+"REAL_INTEGRABLE_LINEAR",REAL_INTEGRABLE_LINEAR;
+"REAL_INTEGRABLE_LMUL",REAL_INTEGRABLE_LMUL;
+"REAL_INTEGRABLE_NEG",REAL_INTEGRABLE_NEG;
+"REAL_INTEGRABLE_ON",REAL_INTEGRABLE_ON;
+"REAL_INTEGRABLE_ON_EMPTY",REAL_INTEGRABLE_ON_EMPTY;
+"REAL_INTEGRABLE_ON_LITTLE_SUBINTERVALS",REAL_INTEGRABLE_ON_LITTLE_SUBINTERVALS;
+"REAL_INTEGRABLE_ON_NULL",REAL_INTEGRABLE_ON_NULL;
+"REAL_INTEGRABLE_ON_OPEN_INTERVAL",REAL_INTEGRABLE_ON_OPEN_INTERVAL;
+"REAL_INTEGRABLE_ON_REFL",REAL_INTEGRABLE_ON_REFL;
+"REAL_INTEGRABLE_ON_SUBINTERVAL",REAL_INTEGRABLE_ON_SUBINTERVAL;
+"REAL_INTEGRABLE_ON_SUPERSET",REAL_INTEGRABLE_ON_SUPERSET;
+"REAL_INTEGRABLE_REFLECT",REAL_INTEGRABLE_REFLECT;
+"REAL_INTEGRABLE_RESTRICT_INTER",REAL_INTEGRABLE_RESTRICT_INTER;
+"REAL_INTEGRABLE_RESTRICT_UNIV",REAL_INTEGRABLE_RESTRICT_UNIV;
+"REAL_INTEGRABLE_RMUL",REAL_INTEGRABLE_RMUL;
+"REAL_INTEGRABLE_SPIKE",REAL_INTEGRABLE_SPIKE;
+"REAL_INTEGRABLE_SPIKE_FINITE",REAL_INTEGRABLE_SPIKE_FINITE;
+"REAL_INTEGRABLE_SPIKE_INTERIOR",REAL_INTEGRABLE_SPIKE_INTERIOR;
+"REAL_INTEGRABLE_SPIKE_SET",REAL_INTEGRABLE_SPIKE_SET;
+"REAL_INTEGRABLE_SPIKE_SET_EQ",REAL_INTEGRABLE_SPIKE_SET_EQ;
+"REAL_INTEGRABLE_STRADDLE",REAL_INTEGRABLE_STRADDLE;
+"REAL_INTEGRABLE_STRETCH",REAL_INTEGRABLE_STRETCH;
+"REAL_INTEGRABLE_SUB",REAL_INTEGRABLE_SUB;
+"REAL_INTEGRABLE_SUBINTERVAL",REAL_INTEGRABLE_SUBINTERVAL;
+"REAL_INTEGRABLE_SUM",REAL_INTEGRABLE_SUM;
+"REAL_INTEGRABLE_UNIFORM_LIMIT",REAL_INTEGRABLE_UNIFORM_LIMIT;
+"REAL_INTEGRAL",REAL_INTEGRAL;
+"REAL_INTEGRAL_0",REAL_INTEGRAL_0;
+"REAL_INTEGRAL_ABS_BOUND_INTEGRAL",REAL_INTEGRAL_ABS_BOUND_INTEGRAL;
+"REAL_INTEGRAL_ADD",REAL_INTEGRAL_ADD;
+"REAL_INTEGRAL_COMBINE",REAL_INTEGRAL_COMBINE;
+"REAL_INTEGRAL_CONST",REAL_INTEGRAL_CONST;
+"REAL_INTEGRAL_EMPTY",REAL_INTEGRAL_EMPTY;
+"REAL_INTEGRAL_EQ",REAL_INTEGRAL_EQ;
+"REAL_INTEGRAL_EQ_0",REAL_INTEGRAL_EQ_0;
+"REAL_INTEGRAL_EQ_HAS_INTEGRAL",REAL_INTEGRAL_EQ_HAS_INTEGRAL;
+"REAL_INTEGRAL_HAS_REAL_DERIVATIVE",REAL_INTEGRAL_HAS_REAL_DERIVATIVE;
+"REAL_INTEGRAL_LBOUND",REAL_INTEGRAL_LBOUND;
+"REAL_INTEGRAL_LE",REAL_INTEGRAL_LE;
+"REAL_INTEGRAL_LINEAR",REAL_INTEGRAL_LINEAR;
+"REAL_INTEGRAL_LMUL",REAL_INTEGRAL_LMUL;
+"REAL_INTEGRAL_NEG",REAL_INTEGRAL_NEG;
+"REAL_INTEGRAL_NULL",REAL_INTEGRAL_NULL;
+"REAL_INTEGRAL_OPEN_INTERVAL",REAL_INTEGRAL_OPEN_INTERVAL;
+"REAL_INTEGRAL_POS",REAL_INTEGRAL_POS;
+"REAL_INTEGRAL_REAL_MEASURE",REAL_INTEGRAL_REAL_MEASURE;
+"REAL_INTEGRAL_REAL_MEASURE_UNIV",REAL_INTEGRAL_REAL_MEASURE_UNIV;
+"REAL_INTEGRAL_REFL",REAL_INTEGRAL_REFL;
+"REAL_INTEGRAL_REFLECT",REAL_INTEGRAL_REFLECT;
+"REAL_INTEGRAL_RESTRICT",REAL_INTEGRAL_RESTRICT;
+"REAL_INTEGRAL_RESTRICT_INTER",REAL_INTEGRAL_RESTRICT_INTER;
+"REAL_INTEGRAL_RESTRICT_UNIV",REAL_INTEGRAL_RESTRICT_UNIV;
+"REAL_INTEGRAL_RMUL",REAL_INTEGRAL_RMUL;
+"REAL_INTEGRAL_SPIKE",REAL_INTEGRAL_SPIKE;
+"REAL_INTEGRAL_SPIKE_SET",REAL_INTEGRAL_SPIKE_SET;
+"REAL_INTEGRAL_SUB",REAL_INTEGRAL_SUB;
+"REAL_INTEGRAL_SUBSET_LE",REAL_INTEGRAL_SUBSET_LE;
+"REAL_INTEGRAL_SUM",REAL_INTEGRAL_SUM;
+"REAL_INTEGRAL_UBOUND",REAL_INTEGRAL_UBOUND;
+"REAL_INTEGRAL_UNIQUE",REAL_INTEGRAL_UNIQUE;
+"REAL_INTERVAL_EQ_EMPTY",REAL_INTERVAL_EQ_EMPTY;
+"REAL_INTERVAL_INTERVAL",REAL_INTERVAL_INTERVAL;
+"REAL_INTERVAL_NE_EMPTY",REAL_INTERVAL_NE_EMPTY;
+"REAL_INTERVAL_OPEN_SUBSET_CLOSED",REAL_INTERVAL_OPEN_SUBSET_CLOSED;
+"REAL_INTERVAL_SING",REAL_INTERVAL_SING;
+"REAL_INTERVAL_TRANSLATION",REAL_INTERVAL_TRANSLATION;
+"REAL_INV",REAL_INV;
+"REAL_INV_0",REAL_INV_0;
+"REAL_INV_1",REAL_INV_1;
+"REAL_INV_1_LE",REAL_INV_1_LE;
+"REAL_INV_1_LT",REAL_INV_1_LT;
+"REAL_INV_DIV",REAL_INV_DIV;
+"REAL_INV_EQ",REAL_INV_EQ;
+"REAL_INV_EQ_0",REAL_INV_EQ_0;
+"REAL_INV_EQ_1",REAL_INV_EQ_1;
+"REAL_INV_INV",REAL_INV_INV;
+"REAL_INV_LE_1",REAL_INV_LE_1;
+"REAL_INV_LT_1",REAL_INV_LT_1;
+"REAL_INV_MUL",REAL_INV_MUL;
+"REAL_INV_NEG",REAL_INV_NEG;
+"REAL_INV_POW",REAL_INV_POW;
+"REAL_INV_RPOW",REAL_INV_RPOW;
+"REAL_IVT_DECREASING",REAL_IVT_DECREASING;
+"REAL_IVT_INCREASING",REAL_IVT_INCREASING;
+"REAL_LEBESGUE_MEASURABLE",REAL_LEBESGUE_MEASURABLE;
+"REAL_LEBESGUE_MEASURABLE_CLOSED",REAL_LEBESGUE_MEASURABLE_CLOSED;
+"REAL_LEBESGUE_MEASURABLE_COMPACT",REAL_LEBESGUE_MEASURABLE_COMPACT;
+"REAL_LEBESGUE_MEASURABLE_COMPL",REAL_LEBESGUE_MEASURABLE_COMPL;
+"REAL_LEBESGUE_MEASURABLE_COUNTABLE_INTERS",REAL_LEBESGUE_MEASURABLE_COUNTABLE_INTERS;
+"REAL_LEBESGUE_MEASURABLE_COUNTABLE_INTERS_EXPLICIT",REAL_LEBESGUE_MEASURABLE_COUNTABLE_INTERS_EXPLICIT;
+"REAL_LEBESGUE_MEASURABLE_COUNTABLE_UNIONS",REAL_LEBESGUE_MEASURABLE_COUNTABLE_UNIONS;
+"REAL_LEBESGUE_MEASURABLE_COUNTABLE_UNIONS_EXPLICIT",REAL_LEBESGUE_MEASURABLE_COUNTABLE_UNIONS_EXPLICIT;
+"REAL_LEBESGUE_MEASURABLE_DIFF",REAL_LEBESGUE_MEASURABLE_DIFF;
+"REAL_LEBESGUE_MEASURABLE_EMPTY",REAL_LEBESGUE_MEASURABLE_EMPTY;
+"REAL_LEBESGUE_MEASURABLE_IFF_MEASURABLE",REAL_LEBESGUE_MEASURABLE_IFF_MEASURABLE;
+"REAL_LEBESGUE_MEASURABLE_INTER",REAL_LEBESGUE_MEASURABLE_INTER;
+"REAL_LEBESGUE_MEASURABLE_INTERS",REAL_LEBESGUE_MEASURABLE_INTERS;
+"REAL_LEBESGUE_MEASURABLE_INTERVAL",REAL_LEBESGUE_MEASURABLE_INTERVAL;
+"REAL_LEBESGUE_MEASURABLE_ON_SUBINTERVALS",REAL_LEBESGUE_MEASURABLE_ON_SUBINTERVALS;
+"REAL_LEBESGUE_MEASURABLE_OPEN",REAL_LEBESGUE_MEASURABLE_OPEN;
+"REAL_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED",REAL_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED;
+"REAL_LEBESGUE_MEASURABLE_PREIMAGE_OPEN",REAL_LEBESGUE_MEASURABLE_PREIMAGE_OPEN;
+"REAL_LEBESGUE_MEASURABLE_UNION",REAL_LEBESGUE_MEASURABLE_UNION;
+"REAL_LEBESGUE_MEASURABLE_UNIONS",REAL_LEBESGUE_MEASURABLE_UNIONS;
+"REAL_LEBESGUE_MEASURABLE_UNIV",REAL_LEBESGUE_MEASURABLE_UNIV;
+"REAL_LET_ADD",REAL_LET_ADD;
+"REAL_LET_ADD2",REAL_LET_ADD2;
+"REAL_LET_ANTISYM",REAL_LET_ANTISYM;
+"REAL_LET_TOTAL",REAL_LET_TOTAL;
+"REAL_LET_TRANS",REAL_LET_TRANS;
+"REAL_LE_01",REAL_LE_01;
+"REAL_LE_ABS_SINH",REAL_LE_ABS_SINH;
+"REAL_LE_ADD",REAL_LE_ADD;
+"REAL_LE_ADD2",REAL_LE_ADD2;
+"REAL_LE_ADDL",REAL_LE_ADDL;
+"REAL_LE_ADDR",REAL_LE_ADDR;
+"REAL_LE_AFFINITY",REAL_LE_AFFINITY;
+"REAL_LE_ANTISYM",REAL_LE_ANTISYM;
+"REAL_LE_BETWEEN",REAL_LE_BETWEEN;
+"REAL_LE_CASES_INTEGERS",REAL_LE_CASES_INTEGERS;
+"REAL_LE_DIV",REAL_LE_DIV;
+"REAL_LE_DIV2_EQ",REAL_LE_DIV2_EQ;
+"REAL_LE_DOUBLE",REAL_LE_DOUBLE;
+"REAL_LE_FLOOR",REAL_LE_FLOOR;
+"REAL_LE_INF",REAL_LE_INF;
+"REAL_LE_INF_FINITE",REAL_LE_INF_FINITE;
+"REAL_LE_INF_SUBSET",REAL_LE_INF_SUBSET;
+"REAL_LE_INTEGERS",REAL_LE_INTEGERS;
+"REAL_LE_INV",REAL_LE_INV;
+"REAL_LE_INV2",REAL_LE_INV2;
+"REAL_LE_INV_EQ",REAL_LE_INV_EQ;
+"REAL_LE_LADD",REAL_LE_LADD;
+"REAL_LE_LADD_IMP",REAL_LE_LADD_IMP;
+"REAL_LE_LCANCEL_IMP",REAL_LE_LCANCEL_IMP;
+"REAL_LE_LDIV_EQ",REAL_LE_LDIV_EQ;
+"REAL_LE_LINV",REAL_LE_LINV;
+"REAL_LE_LMUL",REAL_LE_LMUL;
+"REAL_LE_LMUL_EQ",REAL_LE_LMUL_EQ;
+"REAL_LE_LNEG",REAL_LE_LNEG;
+"REAL_LE_LSQRT",REAL_LE_LSQRT;
+"REAL_LE_LT",REAL_LE_LT;
+"REAL_LE_MAX",REAL_LE_MAX;
+"REAL_LE_MIN",REAL_LE_MIN;
+"REAL_LE_MUL",REAL_LE_MUL;
+"REAL_LE_MUL2",REAL_LE_MUL2;
+"REAL_LE_MUL_EQ",REAL_LE_MUL_EQ;
+"REAL_LE_NEG",REAL_LE_NEG;
+"REAL_LE_NEG2",REAL_LE_NEG2;
+"REAL_LE_NEGL",REAL_LE_NEGL;
+"REAL_LE_NEGR",REAL_LE_NEGR;
+"REAL_LE_NEGTOTAL",REAL_LE_NEGTOTAL;
+"REAL_LE_POW2",REAL_LE_POW2;
+"REAL_LE_POW_2",REAL_LE_POW_2;
+"REAL_LE_RADD",REAL_LE_RADD;
+"REAL_LE_RCANCEL_IMP",REAL_LE_RCANCEL_IMP;
+"REAL_LE_RDIV_EQ",REAL_LE_RDIV_EQ;
+"REAL_LE_REFL",REAL_LE_REFL;
+"REAL_LE_REVERSE_INTEGERS",REAL_LE_REVERSE_INTEGERS;
+"REAL_LE_RINV",REAL_LE_RINV;
+"REAL_LE_RMUL",REAL_LE_RMUL;
+"REAL_LE_RMUL_EQ",REAL_LE_RMUL_EQ;
+"REAL_LE_RNEG",REAL_LE_RNEG;
+"REAL_LE_ROOT",REAL_LE_ROOT;
+"REAL_LE_RSQRT",REAL_LE_RSQRT;
+"REAL_LE_SETDIST",REAL_LE_SETDIST;
+"REAL_LE_SETDIST_EQ",REAL_LE_SETDIST_EQ;
+"REAL_LE_SQUARE",REAL_LE_SQUARE;
+"REAL_LE_SQUARE_ABS",REAL_LE_SQUARE_ABS;
+"REAL_LE_SUB_LADD",REAL_LE_SUB_LADD;
+"REAL_LE_SUB_RADD",REAL_LE_SUB_RADD;
+"REAL_LE_SUP_FINITE",REAL_LE_SUP_FINITE;
+"REAL_LE_TOTAL",REAL_LE_TOTAL;
+"REAL_LE_TRANS",REAL_LE_TRANS;
+"REAL_LE_X_SINH",REAL_LE_X_SINH;
+"REAL_LIM",REAL_LIM;
+"REAL_LIM_SEQUENTIALLY",REAL_LIM_SEQUENTIALLY;
+"REAL_LNEG_UNIQ",REAL_LNEG_UNIQ;
+"REAL_LSQRT_LE",REAL_LSQRT_LE;
+"REAL_LTE_ADD",REAL_LTE_ADD;
+"REAL_LTE_ADD2",REAL_LTE_ADD2;
+"REAL_LTE_ANTISYM",REAL_LTE_ANTISYM;
+"REAL_LTE_TOTAL",REAL_LTE_TOTAL;
+"REAL_LTE_TRANS",REAL_LTE_TRANS;
+"REAL_LT_01",REAL_LT_01;
+"REAL_LT_ADD",REAL_LT_ADD;
+"REAL_LT_ADD1",REAL_LT_ADD1;
+"REAL_LT_ADD2",REAL_LT_ADD2;
+"REAL_LT_ADDL",REAL_LT_ADDL;
+"REAL_LT_ADDNEG",REAL_LT_ADDNEG;
+"REAL_LT_ADDNEG2",REAL_LT_ADDNEG2;
+"REAL_LT_ADDR",REAL_LT_ADDR;
+"REAL_LT_ADD_SUB",REAL_LT_ADD_SUB;
+"REAL_LT_AFFINITY",REAL_LT_AFFINITY;
+"REAL_LT_ANTISYM",REAL_LT_ANTISYM;
+"REAL_LT_BETWEEN",REAL_LT_BETWEEN;
+"REAL_LT_DIV",REAL_LT_DIV;
+"REAL_LT_DIV2_EQ",REAL_LT_DIV2_EQ;
+"REAL_LT_GT",REAL_LT_GT;
+"REAL_LT_IMP_LE",REAL_LT_IMP_LE;
+"REAL_LT_IMP_NE",REAL_LT_IMP_NE;
+"REAL_LT_IMP_NZ",REAL_LT_IMP_NZ;
+"REAL_LT_INF_FINITE",REAL_LT_INF_FINITE;
+"REAL_LT_INTEGERS",REAL_LT_INTEGERS;
+"REAL_LT_INV",REAL_LT_INV;
+"REAL_LT_INV2",REAL_LT_INV2;
+"REAL_LT_INV_EQ",REAL_LT_INV_EQ;
+"REAL_LT_LADD",REAL_LT_LADD;
+"REAL_LT_LADD_IMP",REAL_LT_LADD_IMP;
+"REAL_LT_LCANCEL_IMP",REAL_LT_LCANCEL_IMP;
+"REAL_LT_LDIV_EQ",REAL_LT_LDIV_EQ;
+"REAL_LT_LE",REAL_LT_LE;
+"REAL_LT_LINV",REAL_LT_LINV;
+"REAL_LT_LMUL",REAL_LT_LMUL;
+"REAL_LT_LMUL_EQ",REAL_LT_LMUL_EQ;
+"REAL_LT_LNEG",REAL_LT_LNEG;
+"REAL_LT_LSQRT",REAL_LT_LSQRT;
+"REAL_LT_MAX",REAL_LT_MAX;
+"REAL_LT_MIN",REAL_LT_MIN;
+"REAL_LT_MUL",REAL_LT_MUL;
+"REAL_LT_MUL2",REAL_LT_MUL2;
+"REAL_LT_MUL_EQ",REAL_LT_MUL_EQ;
+"REAL_LT_NEG",REAL_LT_NEG;
+"REAL_LT_NEG2",REAL_LT_NEG2;
+"REAL_LT_NEGTOTAL",REAL_LT_NEGTOTAL;
+"REAL_LT_POW2",REAL_LT_POW2;
+"REAL_LT_RADD",REAL_LT_RADD;
+"REAL_LT_RCANCEL_IMP",REAL_LT_RCANCEL_IMP;
+"REAL_LT_RDIV_EQ",REAL_LT_RDIV_EQ;
+"REAL_LT_REFL",REAL_LT_REFL;
+"REAL_LT_RINV",REAL_LT_RINV;
+"REAL_LT_RMUL",REAL_LT_RMUL;
+"REAL_LT_RMUL_EQ",REAL_LT_RMUL_EQ;
+"REAL_LT_RNEG",REAL_LT_RNEG;
+"REAL_LT_RSQRT",REAL_LT_RSQRT;
+"REAL_LT_SQUARE",REAL_LT_SQUARE;
+"REAL_LT_SQUARE_ABS",REAL_LT_SQUARE_ABS;
+"REAL_LT_SUB_LADD",REAL_LT_SUB_LADD;
+"REAL_LT_SUB_RADD",REAL_LT_SUB_RADD;
+"REAL_LT_SUP_FINITE",REAL_LT_SUP_FINITE;
+"REAL_LT_TOTAL",REAL_LT_TOTAL;
+"REAL_LT_TRANS",REAL_LT_TRANS;
+"REAL_MAX_ACI",REAL_MAX_ACI;
+"REAL_MAX_ASSOC",REAL_MAX_ASSOC;
+"REAL_MAX_LE",REAL_MAX_LE;
+"REAL_MAX_LT",REAL_MAX_LT;
+"REAL_MAX_MAX",REAL_MAX_MAX;
+"REAL_MAX_MIN",REAL_MAX_MIN;
+"REAL_MAX_SUP",REAL_MAX_SUP;
+"REAL_MAX_SYM",REAL_MAX_SYM;
+"REAL_MEASURABLE",REAL_MEASURABLE;
+"REAL_MEASURABLE_ALMOST",REAL_MEASURABLE_ALMOST;
+"REAL_MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_ABSOLUTELY_INTEGRABLE",REAL_MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_ABSOLUTELY_INTEGRABLE;
+"REAL_MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE",REAL_MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE;
+"REAL_MEASURABLE_COMPACT",REAL_MEASURABLE_COMPACT;
+"REAL_MEASURABLE_COUNTABLE_INTERS",REAL_MEASURABLE_COUNTABLE_INTERS;
+"REAL_MEASURABLE_COUNTABLE_UNIONS",REAL_MEASURABLE_COUNTABLE_UNIONS;
+"REAL_MEASURABLE_COUNTABLE_UNIONS_BOUNDED",REAL_MEASURABLE_COUNTABLE_UNIONS_BOUNDED;
+"REAL_MEASURABLE_COUNTABLE_UNIONS_STRONG",REAL_MEASURABLE_COUNTABLE_UNIONS_STRONG;
+"REAL_MEASURABLE_DIFF",REAL_MEASURABLE_DIFF;
+"REAL_MEASURABLE_EMPTY",REAL_MEASURABLE_EMPTY;
+"REAL_MEASURABLE_IMP_REAL_LEBESGUE_MEASURABLE",REAL_MEASURABLE_IMP_REAL_LEBESGUE_MEASURABLE;
+"REAL_MEASURABLE_INNER_OUTER",REAL_MEASURABLE_INNER_OUTER;
+"REAL_MEASURABLE_INTER",REAL_MEASURABLE_INTER;
+"REAL_MEASURABLE_MEASURABLE",REAL_MEASURABLE_MEASURABLE;
+"REAL_MEASURABLE_NESTED_UNIONS",REAL_MEASURABLE_NESTED_UNIONS;
+"REAL_MEASURABLE_ON_0",REAL_MEASURABLE_ON_0;
+"REAL_MEASURABLE_ON_ABS",REAL_MEASURABLE_ON_ABS;
+"REAL_MEASURABLE_ON_ADD",REAL_MEASURABLE_ON_ADD;
+"REAL_MEASURABLE_ON_CASES",REAL_MEASURABLE_ON_CASES;
+"REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS",REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS;
+"REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS_0",REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS_0;
+"REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET",REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET;
+"REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET_0",REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET_0;
+"REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS_OPEN_INTERVAL",REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS_OPEN_INTERVAL;
+"REAL_MEASURABLE_ON_CONST",REAL_MEASURABLE_ON_CONST;
+"REAL_MEASURABLE_ON_DECREASING",REAL_MEASURABLE_ON_DECREASING;
+"REAL_MEASURABLE_ON_DECREASING_UNIV",REAL_MEASURABLE_ON_DECREASING_UNIV;
+"REAL_MEASURABLE_ON_DIV",REAL_MEASURABLE_ON_DIV;
+"REAL_MEASURABLE_ON_INCREASING",REAL_MEASURABLE_ON_INCREASING;
+"REAL_MEASURABLE_ON_INCREASING_UNIV",REAL_MEASURABLE_ON_INCREASING_UNIV;
+"REAL_MEASURABLE_ON_INV",REAL_MEASURABLE_ON_INV;
+"REAL_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET",REAL_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET;
+"REAL_MEASURABLE_ON_LIMIT",REAL_MEASURABLE_ON_LIMIT;
+"REAL_MEASURABLE_ON_LMUL",REAL_MEASURABLE_ON_LMUL;
+"REAL_MEASURABLE_ON_MAX",REAL_MEASURABLE_ON_MAX;
+"REAL_MEASURABLE_ON_MEASURABLE_SUBSET",REAL_MEASURABLE_ON_MEASURABLE_SUBSET;
+"REAL_MEASURABLE_ON_MIN",REAL_MEASURABLE_ON_MIN;
+"REAL_MEASURABLE_ON_MUL",REAL_MEASURABLE_ON_MUL;
+"REAL_MEASURABLE_ON_NEG",REAL_MEASURABLE_ON_NEG;
+"REAL_MEASURABLE_ON_NEG_EQ",REAL_MEASURABLE_ON_NEG_EQ;
+"REAL_MEASURABLE_ON_PREIMAGE_CLOSED",REAL_MEASURABLE_ON_PREIMAGE_CLOSED;
+"REAL_MEASURABLE_ON_PREIMAGE_CLOSED_INTERVAL",REAL_MEASURABLE_ON_PREIMAGE_CLOSED_INTERVAL;
+"REAL_MEASURABLE_ON_PREIMAGE_OPEN",REAL_MEASURABLE_ON_PREIMAGE_OPEN;
+"REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_GE",REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_GE;
+"REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_GT",REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_GT;
+"REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_LE",REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_LE;
+"REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_LT",REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_LT;
+"REAL_MEASURABLE_ON_PREIMAGE_OPEN_INTERVAL",REAL_MEASURABLE_ON_PREIMAGE_OPEN_INTERVAL;
+"REAL_MEASURABLE_ON_RESTRICT",REAL_MEASURABLE_ON_RESTRICT;
+"REAL_MEASURABLE_ON_RMUL",REAL_MEASURABLE_ON_RMUL;
+"REAL_MEASURABLE_ON_SIMPLE_FUNCTION_LIMIT",REAL_MEASURABLE_ON_SIMPLE_FUNCTION_LIMIT;
+"REAL_MEASURABLE_ON_SPIKE_SET",REAL_MEASURABLE_ON_SPIKE_SET;
+"REAL_MEASURABLE_ON_SUB",REAL_MEASURABLE_ON_SUB;
+"REAL_MEASURABLE_ON_UNIV",REAL_MEASURABLE_ON_UNIV;
+"REAL_MEASURABLE_OPEN",REAL_MEASURABLE_OPEN;
+"REAL_MEASURABLE_REAL_INTEGRABLE",REAL_MEASURABLE_REAL_INTEGRABLE;
+"REAL_MEASURABLE_REAL_INTERVAL",REAL_MEASURABLE_REAL_INTERVAL;
+"REAL_MEASURABLE_REAL_MEASURE_EQ_0",REAL_MEASURABLE_REAL_MEASURE_EQ_0;
+"REAL_MEASURABLE_REAL_MEASURE_POS_LT",REAL_MEASURABLE_REAL_MEASURE_POS_LT;
+"REAL_MEASURABLE_REAL_NEGLIGIBLE_SYMDIFF",REAL_MEASURABLE_REAL_NEGLIGIBLE_SYMDIFF;
+"REAL_MEASURABLE_SCALING",REAL_MEASURABLE_SCALING;
+"REAL_MEASURABLE_SCALING_EQ",REAL_MEASURABLE_SCALING_EQ;
+"REAL_MEASURABLE_TRANSLATION",REAL_MEASURABLE_TRANSLATION;
+"REAL_MEASURABLE_UNION",REAL_MEASURABLE_UNION;
+"REAL_MEASURABLE_UNIONS",REAL_MEASURABLE_UNIONS;
+"REAL_MEASURE_DIFF_SUBSET",REAL_MEASURE_DIFF_SUBSET;
+"REAL_MEASURE_DISJOINT_UNION",REAL_MEASURE_DISJOINT_UNION;
+"REAL_MEASURE_DISJOINT_UNIONS",REAL_MEASURE_DISJOINT_UNIONS;
+"REAL_MEASURE_DISJOINT_UNIONS_IMAGE",REAL_MEASURE_DISJOINT_UNIONS_IMAGE;
+"REAL_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG",REAL_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG;
+"REAL_MEASURE_EMPTY",REAL_MEASURE_EMPTY;
+"REAL_MEASURE_EQ_0",REAL_MEASURE_EQ_0;
+"REAL_MEASURE_MEASURE",REAL_MEASURE_MEASURE;
+"REAL_MEASURE_POS_LE",REAL_MEASURE_POS_LE;
+"REAL_MEASURE_REAL_INTEGRAL",REAL_MEASURE_REAL_INTEGRAL;
+"REAL_MEASURE_REAL_INTEGRAL_UNIV",REAL_MEASURE_REAL_INTEGRAL_UNIV;
+"REAL_MEASURE_REAL_INTERVAL",REAL_MEASURE_REAL_INTERVAL;
+"REAL_MEASURE_REAL_NEGLIGIBLE_SYMDIFF",REAL_MEASURE_REAL_NEGLIGIBLE_SYMDIFF;
+"REAL_MEASURE_REAL_NEGLIGIBLE_UNION",REAL_MEASURE_REAL_NEGLIGIBLE_UNION;
+"REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS",REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS;
+"REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE",REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE;
+"REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE_STRONG",REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE_STRONG;
+"REAL_MEASURE_SCALING",REAL_MEASURE_SCALING;
+"REAL_MEASURE_SUBSET",REAL_MEASURE_SUBSET;
+"REAL_MEASURE_TRANSLATION",REAL_MEASURE_TRANSLATION;
+"REAL_MEASURE_UNION",REAL_MEASURE_UNION;
+"REAL_MEASURE_UNIONS_LE",REAL_MEASURE_UNIONS_LE;
+"REAL_MEASURE_UNIONS_LE_IMAGE",REAL_MEASURE_UNIONS_LE_IMAGE;
+"REAL_MEASURE_UNION_LE",REAL_MEASURE_UNION_LE;
+"REAL_MEASURE_UNIQUE",REAL_MEASURE_UNIQUE;
+"REAL_MIN_ACI",REAL_MIN_ACI;
+"REAL_MIN_ASSOC",REAL_MIN_ASSOC;
+"REAL_MIN_INF",REAL_MIN_INF;
+"REAL_MIN_LE",REAL_MIN_LE;
+"REAL_MIN_LT",REAL_MIN_LT;
+"REAL_MIN_MAX",REAL_MIN_MAX;
+"REAL_MIN_MIN",REAL_MIN_MIN;
+"REAL_MIN_SYM",REAL_MIN_SYM;
+"REAL_MONOTONE_CONVERGENCE_DECREASING",REAL_MONOTONE_CONVERGENCE_DECREASING;
+"REAL_MONOTONE_CONVERGENCE_INCREASING",REAL_MONOTONE_CONVERGENCE_INCREASING;
+"REAL_MONOTONE_CONVERGENCE_INCREASING_AE",REAL_MONOTONE_CONVERGENCE_INCREASING_AE;
+"REAL_MUL",REAL_MUL;
+"REAL_MUL_2",REAL_MUL_2;
+"REAL_MUL_AC",REAL_MUL_AC;
+"REAL_MUL_ASSOC",REAL_MUL_ASSOC;
+"REAL_MUL_COS_COS",REAL_MUL_COS_COS;
+"REAL_MUL_COS_SIN",REAL_MUL_COS_SIN;
+"REAL_MUL_CX",REAL_MUL_CX;
+"REAL_MUL_LID",REAL_MUL_LID;
+"REAL_MUL_LINV",REAL_MUL_LINV;
+"REAL_MUL_LINV_UNIQ",REAL_MUL_LINV_UNIQ;
+"REAL_MUL_LNEG",REAL_MUL_LNEG;
+"REAL_MUL_LZERO",REAL_MUL_LZERO;
+"REAL_MUL_POS_LE",REAL_MUL_POS_LE;
+"REAL_MUL_POS_LT",REAL_MUL_POS_LT;
+"REAL_MUL_RID",REAL_MUL_RID;
+"REAL_MUL_RINV",REAL_MUL_RINV;
+"REAL_MUL_RINV_UNIQ",REAL_MUL_RINV_UNIQ;
+"REAL_MUL_RNEG",REAL_MUL_RNEG;
+"REAL_MUL_RZERO",REAL_MUL_RZERO;
+"REAL_MUL_SIN_COS",REAL_MUL_SIN_COS;
+"REAL_MUL_SIN_SIN",REAL_MUL_SIN_SIN;
+"REAL_MUL_SUM",REAL_MUL_SUM;
+"REAL_MUL_SUM_NUMSEG",REAL_MUL_SUM_NUMSEG;
+"REAL_MUL_SYM",REAL_MUL_SYM;
+"REAL_MVT",REAL_MVT;
+"REAL_MVT_CAUCHY",REAL_MVT_CAUCHY;
+"REAL_MVT_SIMPLE",REAL_MVT_SIMPLE;
+"REAL_MVT_VERY_SIMPLE",REAL_MVT_VERY_SIMPLE;
+"REAL_NEG",REAL_NEG;
+"REAL_NEGLIGIBLE_COUNTABLE",REAL_NEGLIGIBLE_COUNTABLE;
+"REAL_NEGLIGIBLE_COUNTABLE_UNIONS",REAL_NEGLIGIBLE_COUNTABLE_UNIONS;
+"REAL_NEGLIGIBLE_DIFF",REAL_NEGLIGIBLE_DIFF;
+"REAL_NEGLIGIBLE_EMPTY",REAL_NEGLIGIBLE_EMPTY;
+"REAL_NEGLIGIBLE_FINITE",REAL_NEGLIGIBLE_FINITE;
+"REAL_NEGLIGIBLE_FRONTIER_INTERVAL",REAL_NEGLIGIBLE_FRONTIER_INTERVAL;
+"REAL_NEGLIGIBLE_INSERT",REAL_NEGLIGIBLE_INSERT;
+"REAL_NEGLIGIBLE_INTER",REAL_NEGLIGIBLE_INTER;
+"REAL_NEGLIGIBLE_ON_INTERVALS",REAL_NEGLIGIBLE_ON_INTERVALS;
+"REAL_NEGLIGIBLE_OUTER",REAL_NEGLIGIBLE_OUTER;
+"REAL_NEGLIGIBLE_OUTER_LE",REAL_NEGLIGIBLE_OUTER_LE;
+"REAL_NEGLIGIBLE_REAL_INTERVAL",REAL_NEGLIGIBLE_REAL_INTERVAL;
+"REAL_NEGLIGIBLE_SING",REAL_NEGLIGIBLE_SING;
+"REAL_NEGLIGIBLE_SUBSET",REAL_NEGLIGIBLE_SUBSET;
+"REAL_NEGLIGIBLE_TRANSLATION",REAL_NEGLIGIBLE_TRANSLATION;
+"REAL_NEGLIGIBLE_TRANSLATION_EQ",REAL_NEGLIGIBLE_TRANSLATION_EQ;
+"REAL_NEGLIGIBLE_TRANSLATION_REV",REAL_NEGLIGIBLE_TRANSLATION_REV;
+"REAL_NEGLIGIBLE_UNION",REAL_NEGLIGIBLE_UNION;
+"REAL_NEGLIGIBLE_UNIONS",REAL_NEGLIGIBLE_UNIONS;
+"REAL_NEGLIGIBLE_UNION_EQ",REAL_NEGLIGIBLE_UNION_EQ;
+"REAL_NEGNEG",REAL_NEGNEG;
+"REAL_NEG_0",REAL_NEG_0;
+"REAL_NEG_ADD",REAL_NEG_ADD;
+"REAL_NEG_EQ",REAL_NEG_EQ;
+"REAL_NEG_EQ_0",REAL_NEG_EQ_0;
+"REAL_NEG_GE0",REAL_NEG_GE0;
+"REAL_NEG_GT0",REAL_NEG_GT0;
+"REAL_NEG_LE0",REAL_NEG_LE0;
+"REAL_NEG_LMUL",REAL_NEG_LMUL;
+"REAL_NEG_LT0",REAL_NEG_LT0;
+"REAL_NEG_MINUS1",REAL_NEG_MINUS1;
+"REAL_NEG_MUL2",REAL_NEG_MUL2;
+"REAL_NEG_NEG",REAL_NEG_NEG;
+"REAL_NEG_RMUL",REAL_NEG_RMUL;
+"REAL_NEG_SUB",REAL_NEG_SUB;
+"REAL_NORM",REAL_NORM;
+"REAL_NORM_POS",REAL_NORM_POS;
+"REAL_NOT_EQ",REAL_NOT_EQ;
+"REAL_NOT_LE",REAL_NOT_LE;
+"REAL_NOT_LT",REAL_NOT_LT;
+"REAL_OF_INT_OF_REAL",REAL_OF_INT_OF_REAL;
+"REAL_OF_NUM_ADD",REAL_OF_NUM_ADD;
+"REAL_OF_NUM_BINOM",REAL_OF_NUM_BINOM;
+"REAL_OF_NUM_EQ",REAL_OF_NUM_EQ;
+"REAL_OF_NUM_GE",REAL_OF_NUM_GE;
+"REAL_OF_NUM_GT",REAL_OF_NUM_GT;
+"REAL_OF_NUM_LE",REAL_OF_NUM_LE;
+"REAL_OF_NUM_LT",REAL_OF_NUM_LT;
+"REAL_OF_NUM_MAX",REAL_OF_NUM_MAX;
+"REAL_OF_NUM_MIN",REAL_OF_NUM_MIN;
+"REAL_OF_NUM_MUL",REAL_OF_NUM_MUL;
+"REAL_OF_NUM_POW",REAL_OF_NUM_POW;
+"REAL_OF_NUM_SUB",REAL_OF_NUM_SUB;
+"REAL_OF_NUM_SUC",REAL_OF_NUM_SUC;
+"REAL_OF_NUM_SUM",REAL_OF_NUM_SUM;
+"REAL_OF_NUM_SUM_NUMSEG",REAL_OF_NUM_SUM_NUMSEG;
+"REAL_OPEN",REAL_OPEN;
+"REAL_OPEN_CLOSED_INTERVAL",REAL_OPEN_CLOSED_INTERVAL;
+"REAL_OPEN_DIFF",REAL_OPEN_DIFF;
+"REAL_OPEN_EMPTY",REAL_OPEN_EMPTY;
+"REAL_OPEN_EXISTS_RATIONAL",REAL_OPEN_EXISTS_RATIONAL;
+"REAL_OPEN_HALFSPACE_GT",REAL_OPEN_HALFSPACE_GT;
+"REAL_OPEN_HALFSPACE_LT",REAL_OPEN_HALFSPACE_LT;
+"REAL_OPEN_IN",REAL_OPEN_IN;
+"REAL_OPEN_INTER",REAL_OPEN_INTER;
+"REAL_OPEN_INTERS",REAL_OPEN_INTERS;
+"REAL_OPEN_RATIONAL",REAL_OPEN_RATIONAL;
+"REAL_OPEN_REAL_CLOSED",REAL_OPEN_REAL_CLOSED;
+"REAL_OPEN_REAL_INTERVAL",REAL_OPEN_REAL_INTERVAL;
+"REAL_OPEN_SET_EXISTS_RATIONAL",REAL_OPEN_SET_EXISTS_RATIONAL;
+"REAL_OPEN_SET_RATIONAL",REAL_OPEN_SET_RATIONAL;
+"REAL_OPEN_SUBREAL_OPEN",REAL_OPEN_SUBREAL_OPEN;
+"REAL_OPEN_UNION",REAL_OPEN_UNION;
+"REAL_OPEN_UNIONS",REAL_OPEN_UNIONS;
+"REAL_OPEN_UNIV",REAL_OPEN_UNIV;
+"REAL_PARTIAL_SUMS_LE_INFSUM",REAL_PARTIAL_SUMS_LE_INFSUM;
+"REAL_POLYFUN_EQ_0",REAL_POLYFUN_EQ_0;
+"REAL_POLYFUN_EQ_CONST",REAL_POLYFUN_EQ_CONST;
+"REAL_POLYFUN_FINITE_ROOTS",REAL_POLYFUN_FINITE_ROOTS;
+"REAL_POLYFUN_ROOTBOUND",REAL_POLYFUN_ROOTBOUND;
+"REAL_POLY_CLAUSES",REAL_POLY_CLAUSES;
+"REAL_POLY_NEG_CLAUSES",REAL_POLY_NEG_CLAUSES;
+"REAL_POS",REAL_POS;
+"REAL_POS_NZ",REAL_POS_NZ;
+"REAL_POW",REAL_POW;
+"REAL_POW2_ABS",REAL_POW2_ABS;
+"REAL_POWER_SERIES_CONV_IMP_ABSCONV",REAL_POWER_SERIES_CONV_IMP_ABSCONV;
+"REAL_POW_1",REAL_POW_1;
+"REAL_POW_1_LE",REAL_POW_1_LE;
+"REAL_POW_1_LT",REAL_POW_1_LT;
+"REAL_POW_2",REAL_POW_2;
+"REAL_POW_ADD",REAL_POW_ADD;
+"REAL_POW_DIV",REAL_POW_DIV;
+"REAL_POW_EQ",REAL_POW_EQ;
+"REAL_POW_EQ_0",REAL_POW_EQ_0;
+"REAL_POW_EQ_1",REAL_POW_EQ_1;
+"REAL_POW_EQ_1_IMP",REAL_POW_EQ_1_IMP;
+"REAL_POW_EQ_ABS",REAL_POW_EQ_ABS;
+"REAL_POW_EQ_EQ",REAL_POW_EQ_EQ;
+"REAL_POW_EQ_ODD",REAL_POW_EQ_ODD;
+"REAL_POW_EQ_ODD_EQ",REAL_POW_EQ_ODD_EQ;
+"REAL_POW_INV",REAL_POW_INV;
+"REAL_POW_LBOUND",REAL_POW_LBOUND;
+"REAL_POW_LE",REAL_POW_LE;
+"REAL_POW_LE2",REAL_POW_LE2;
+"REAL_POW_LE2_ODD",REAL_POW_LE2_ODD;
+"REAL_POW_LE2_ODD_EQ",REAL_POW_LE2_ODD_EQ;
+"REAL_POW_LE2_REV",REAL_POW_LE2_REV;
+"REAL_POW_LE_1",REAL_POW_LE_1;
+"REAL_POW_LT",REAL_POW_LT;
+"REAL_POW_LT2",REAL_POW_LT2;
+"REAL_POW_LT2_ODD",REAL_POW_LT2_ODD;
+"REAL_POW_LT2_ODD_EQ",REAL_POW_LT2_ODD_EQ;
+"REAL_POW_LT2_REV",REAL_POW_LT2_REV;
+"REAL_POW_LT_1",REAL_POW_LT_1;
+"REAL_POW_MONO",REAL_POW_MONO;
+"REAL_POW_MONO_INV",REAL_POW_MONO_INV;
+"REAL_POW_MONO_LT",REAL_POW_MONO_LT;
+"REAL_POW_MUL",REAL_POW_MUL;
+"REAL_POW_NEG",REAL_POW_NEG;
+"REAL_POW_NZ",REAL_POW_NZ;
+"REAL_POW_ONE",REAL_POW_ONE;
+"REAL_POW_POW",REAL_POW_POW;
+"REAL_POW_ROOT",REAL_POW_ROOT;
+"REAL_POW_SUB",REAL_POW_SUB;
+"REAL_POW_ZERO",REAL_POW_ZERO;
+"REAL_RNEG_UNIQ",REAL_RNEG_UNIQ;
+"REAL_ROLLE",REAL_ROLLE;
+"REAL_ROLLE_SIMPLE",REAL_ROLLE_SIMPLE;
+"REAL_ROOT_DIV",REAL_ROOT_DIV;
+"REAL_ROOT_INV",REAL_ROOT_INV;
+"REAL_ROOT_LE",REAL_ROOT_LE;
+"REAL_ROOT_MUL",REAL_ROOT_MUL;
+"REAL_ROOT_POW",REAL_ROOT_POW;
+"REAL_ROOT_RPOW",REAL_ROOT_RPOW;
+"REAL_RSQRT_LE",REAL_RSQRT_LE;
+"REAL_SECOND_MEAN_VALUE_THEOREM",REAL_SECOND_MEAN_VALUE_THEOREM;
+"REAL_SECOND_MEAN_VALUE_THEOREM_BONNET",REAL_SECOND_MEAN_VALUE_THEOREM_BONNET;
+"REAL_SECOND_MEAN_VALUE_THEOREM_BONNET_FULL",REAL_SECOND_MEAN_VALUE_THEOREM_BONNET_FULL;
+"REAL_SECOND_MEAN_VALUE_THEOREM_FULL",REAL_SECOND_MEAN_VALUE_THEOREM_FULL;
+"REAL_SECOND_MEAN_VALUE_THEOREM_GEN",REAL_SECOND_MEAN_VALUE_THEOREM_GEN;
+"REAL_SECOND_MEAN_VALUE_THEOREM_GEN_FULL",REAL_SECOND_MEAN_VALUE_THEOREM_GEN_FULL;
+"REAL_SEGMENT",REAL_SEGMENT;
+"REAL_SEGMENT_INTERVAL",REAL_SEGMENT_INTERVAL;
+"REAL_SEGMENT_SEGMENT",REAL_SEGMENT_SEGMENT;
+"REAL_SEQ_OFFSET",REAL_SEQ_OFFSET;
+"REAL_SEQ_OFFSET_REV",REAL_SEQ_OFFSET_REV;
+"REAL_SERIES",REAL_SERIES;
+"REAL_SERIES_0",REAL_SERIES_0;
+"REAL_SERIES_ABSCONV_IMP_CONV",REAL_SERIES_ABSCONV_IMP_CONV;
+"REAL_SERIES_ADD",REAL_SERIES_ADD;
+"REAL_SERIES_CAUCHY",REAL_SERIES_CAUCHY;
+"REAL_SERIES_CAUCHY_UNIFORM",REAL_SERIES_CAUCHY_UNIFORM;
+"REAL_SERIES_COMPARISON",REAL_SERIES_COMPARISON;
+"REAL_SERIES_COMPARISON_UNIFORM",REAL_SERIES_COMPARISON_UNIFORM;
+"REAL_SERIES_DIFFS",REAL_SERIES_DIFFS;
+"REAL_SERIES_DIRICHLET",REAL_SERIES_DIRICHLET;
+"REAL_SERIES_FINITE",REAL_SERIES_FINITE;
+"REAL_SERIES_FINITE_SUPPORT",REAL_SERIES_FINITE_SUPPORT;
+"REAL_SERIES_FROM",REAL_SERIES_FROM;
+"REAL_SERIES_GOESTOZERO",REAL_SERIES_GOESTOZERO;
+"REAL_SERIES_LMUL",REAL_SERIES_LMUL;
+"REAL_SERIES_NEG",REAL_SERIES_NEG;
+"REAL_SERIES_RATIO",REAL_SERIES_RATIO;
+"REAL_SERIES_RESTRICT",REAL_SERIES_RESTRICT;
+"REAL_SERIES_RMUL",REAL_SERIES_RMUL;
+"REAL_SERIES_SUB",REAL_SERIES_SUB;
+"REAL_SERIES_SUBSET",REAL_SERIES_SUBSET;
+"REAL_SERIES_SUM",REAL_SERIES_SUM;
+"REAL_SERIES_TRIVIAL",REAL_SERIES_TRIVIAL;
+"REAL_SERIES_UNIQUE",REAL_SERIES_UNIQUE;
+"REAL_SGN",REAL_SGN;
+"REAL_SGN_0",REAL_SGN_0;
+"REAL_SGN_ABS",REAL_SGN_ABS;
+"REAL_SGN_CASES",REAL_SGN_CASES;
+"REAL_SGN_DIV",REAL_SGN_DIV;
+"REAL_SGN_EQ",REAL_SGN_EQ;
+"REAL_SGN_IM_COMPLEX_DIV",REAL_SGN_IM_COMPLEX_DIV;
+"REAL_SGN_INEQS",REAL_SGN_INEQS;
+"REAL_SGN_INV",REAL_SGN_INV;
+"REAL_SGN_MUL",REAL_SGN_MUL;
+"REAL_SGN_NEG",REAL_SGN_NEG;
+"REAL_SGN_RE_COMPLEX_DIV",REAL_SGN_RE_COMPLEX_DIV;
+"REAL_SIN",REAL_SIN;
+"REAL_SOS_EQ_0",REAL_SOS_EQ_0;
+"REAL_STEINHAUS",REAL_STEINHAUS;
+"REAL_STONE_WEIERSTRASS",REAL_STONE_WEIERSTRASS;
+"REAL_STONE_WEIERSTRASS_ALT",REAL_STONE_WEIERSTRASS_ALT;
+"REAL_SUB",REAL_SUB;
+"REAL_SUB_0",REAL_SUB_0;
+"REAL_SUB_ABS",REAL_SUB_ABS;
+"REAL_SUB_ADD",REAL_SUB_ADD;
+"REAL_SUB_ADD2",REAL_SUB_ADD2;
+"REAL_SUB_ARG",REAL_SUB_ARG;
+"REAL_SUB_COS",REAL_SUB_COS;
+"REAL_SUB_INV",REAL_SUB_INV;
+"REAL_SUB_LDISTRIB",REAL_SUB_LDISTRIB;
+"REAL_SUB_LE",REAL_SUB_LE;
+"REAL_SUB_LNEG",REAL_SUB_LNEG;
+"REAL_SUB_LT",REAL_SUB_LT;
+"REAL_SUB_LZERO",REAL_SUB_LZERO;
+"REAL_SUB_NEG2",REAL_SUB_NEG2;
+"REAL_SUB_POLYFUN",REAL_SUB_POLYFUN;
+"REAL_SUB_POLYFUN_ALT",REAL_SUB_POLYFUN_ALT;
+"REAL_SUB_POW",REAL_SUB_POW;
+"REAL_SUB_POW_L1",REAL_SUB_POW_L1;
+"REAL_SUB_POW_R1",REAL_SUB_POW_R1;
+"REAL_SUB_RDISTRIB",REAL_SUB_RDISTRIB;
+"REAL_SUB_REFL",REAL_SUB_REFL;
+"REAL_SUB_RNEG",REAL_SUB_RNEG;
+"REAL_SUB_RZERO",REAL_SUB_RZERO;
+"REAL_SUB_SIN",REAL_SUB_SIN;
+"REAL_SUB_SUB",REAL_SUB_SUB;
+"REAL_SUB_SUB2",REAL_SUB_SUB2;
+"REAL_SUB_TAN",REAL_SUB_TAN;
+"REAL_SUB_TRIANGLE",REAL_SUB_TRIANGLE;
+"REAL_SUMMABLE",REAL_SUMMABLE;
+"REAL_SUMMABLE_0",REAL_SUMMABLE_0;
+"REAL_SUMMABLE_ADD",REAL_SUMMABLE_ADD;
+"REAL_SUMMABLE_COMPARISON",REAL_SUMMABLE_COMPARISON;
+"REAL_SUMMABLE_COMPLEX",REAL_SUMMABLE_COMPLEX;
+"REAL_SUMMABLE_EQ",REAL_SUMMABLE_EQ;
+"REAL_SUMMABLE_EQ_COFINITE",REAL_SUMMABLE_EQ_COFINITE;
+"REAL_SUMMABLE_EQ_EVENTUALLY",REAL_SUMMABLE_EQ_EVENTUALLY;
+"REAL_SUMMABLE_FROM_ELSEWHERE",REAL_SUMMABLE_FROM_ELSEWHERE;
+"REAL_SUMMABLE_GP",REAL_SUMMABLE_GP;
+"REAL_SUMMABLE_IFF",REAL_SUMMABLE_IFF;
+"REAL_SUMMABLE_IFF_COFINITE",REAL_SUMMABLE_IFF_COFINITE;
+"REAL_SUMMABLE_IFF_EVENTUALLY",REAL_SUMMABLE_IFF_EVENTUALLY;
+"REAL_SUMMABLE_IMP_BOUNDED",REAL_SUMMABLE_IMP_BOUNDED;
+"REAL_SUMMABLE_IMP_REAL_SUMS_BOUNDED",REAL_SUMMABLE_IMP_REAL_SUMS_BOUNDED;
+"REAL_SUMMABLE_IMP_TOZERO",REAL_SUMMABLE_IMP_TOZERO;
+"REAL_SUMMABLE_LMUL",REAL_SUMMABLE_LMUL;
+"REAL_SUMMABLE_NEG",REAL_SUMMABLE_NEG;
+"REAL_SUMMABLE_RESTRICT",REAL_SUMMABLE_RESTRICT;
+"REAL_SUMMABLE_RMUL",REAL_SUMMABLE_RMUL;
+"REAL_SUMMABLE_SUB",REAL_SUMMABLE_SUB;
+"REAL_SUMMABLE_SUBSET",REAL_SUMMABLE_SUBSET;
+"REAL_SUMMABLE_TRIVIAL",REAL_SUMMABLE_TRIVIAL;
+"REAL_SUMS",REAL_SUMS;
+"REAL_SUMS_COMPLEX",REAL_SUMS_COMPLEX;
+"REAL_SUMS_EQ",REAL_SUMS_EQ;
+"REAL_SUMS_FINITE_DIFF",REAL_SUMS_FINITE_DIFF;
+"REAL_SUMS_FINITE_UNION",REAL_SUMS_FINITE_UNION;
+"REAL_SUMS_GP",REAL_SUMS_GP;
+"REAL_SUMS_IFF",REAL_SUMS_IFF;
+"REAL_SUMS_IM",REAL_SUMS_IM;
+"REAL_SUMS_INFSUM",REAL_SUMS_INFSUM;
+"REAL_SUMS_LE2",REAL_SUMS_LE2;
+"REAL_SUMS_OFFSET",REAL_SUMS_OFFSET;
+"REAL_SUMS_OFFSET_REV",REAL_SUMS_OFFSET_REV;
+"REAL_SUMS_RE",REAL_SUMS_RE;
+"REAL_SUMS_REINDEX",REAL_SUMS_REINDEX;
+"REAL_SUMS_SUMMABLE",REAL_SUMS_SUMMABLE;
+"REAL_SUM_INTEGRAL_BOUNDS_DECREASING",REAL_SUM_INTEGRAL_BOUNDS_DECREASING;
+"REAL_SUM_INTEGRAL_BOUNDS_INCREASING",REAL_SUM_INTEGRAL_BOUNDS_INCREASING;
+"REAL_SUM_INTEGRAL_LBOUND_DECREASING",REAL_SUM_INTEGRAL_LBOUND_DECREASING;
+"REAL_SUM_INTEGRAL_LBOUND_INCREASING",REAL_SUM_INTEGRAL_LBOUND_INCREASING;
+"REAL_SUM_INTEGRAL_UBOUND_DECREASING",REAL_SUM_INTEGRAL_UBOUND_DECREASING;
+"REAL_SUM_INTEGRAL_UBOUND_INCREASING",REAL_SUM_INTEGRAL_UBOUND_INCREASING;
+"REAL_SUP_ASCLOSE",REAL_SUP_ASCLOSE;
+"REAL_SUP_BOUNDS",REAL_SUP_BOUNDS;
+"REAL_SUP_EQ_INF",REAL_SUP_EQ_INF;
+"REAL_SUP_LE",REAL_SUP_LE;
+"REAL_SUP_LE_FINITE",REAL_SUP_LE_FINITE;
+"REAL_SUP_LE_SUBSET",REAL_SUP_LE_SUBSET;
+"REAL_SUP_LT_FINITE",REAL_SUP_LT_FINITE;
+"REAL_SUP_UNIQUE",REAL_SUP_UNIQUE;
+"REAL_TAN",REAL_TAN;
+"REAL_TAYLOR",REAL_TAYLOR;
+"REAL_TAYLOR_MVT_NEG",REAL_TAYLOR_MVT_NEG;
+"REAL_TAYLOR_MVT_POS",REAL_TAYLOR_MVT_POS;
+"REAL_TENDSTO",REAL_TENDSTO;
+"REAL_TIETZE_PERIODIC_INTERVAL",REAL_TIETZE_PERIODIC_INTERVAL;
+"REAL_TRUNCATE",REAL_TRUNCATE;
+"REAL_TRUNCATE_POS",REAL_TRUNCATE_POS;
+"REAL_UNIFORMLY_CONTINUOUS_IMP_REAL_CONTINUOUS",REAL_UNIFORMLY_CONTINUOUS_IMP_REAL_CONTINUOUS;
+"REAL_UNIFORMLY_CONTINUOUS_ON",REAL_UNIFORMLY_CONTINUOUS_ON;
+"REAL_UNIFORMLY_CONTINUOUS_ON_ADD",REAL_UNIFORMLY_CONTINUOUS_ON_ADD;
+"REAL_UNIFORMLY_CONTINUOUS_ON_COMPOSE",REAL_UNIFORMLY_CONTINUOUS_ON_COMPOSE;
+"REAL_UNIFORMLY_CONTINUOUS_ON_CONST",REAL_UNIFORMLY_CONTINUOUS_ON_CONST;
+"REAL_UNIFORMLY_CONTINUOUS_ON_ID",REAL_UNIFORMLY_CONTINUOUS_ON_ID;
+"REAL_UNIFORMLY_CONTINUOUS_ON_LMUL",REAL_UNIFORMLY_CONTINUOUS_ON_LMUL;
+"REAL_UNIFORMLY_CONTINUOUS_ON_NEG",REAL_UNIFORMLY_CONTINUOUS_ON_NEG;
+"REAL_UNIFORMLY_CONTINUOUS_ON_RMUL",REAL_UNIFORMLY_CONTINUOUS_ON_RMUL;
+"REAL_UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY",REAL_UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY;
+"REAL_UNIFORMLY_CONTINUOUS_ON_SUB",REAL_UNIFORMLY_CONTINUOUS_ON_SUB;
+"REAL_UNIFORMLY_CONTINUOUS_ON_SUBSET",REAL_UNIFORMLY_CONTINUOUS_ON_SUBSET;
+"REAL_UNIFORMLY_CONTINUOUS_ON_SUM",REAL_UNIFORMLY_CONTINUOUS_ON_SUM;
+"REAL_VARIATION_AFFINITY",REAL_VARIATION_AFFINITY;
+"REAL_VARIATION_AFFINITY2",REAL_VARIATION_AFFINITY2;
+"REAL_VARIATION_COMBINE",REAL_VARIATION_COMBINE;
+"REAL_VARIATION_CONTINUOUS",REAL_VARIATION_CONTINUOUS;
+"REAL_VARIATION_CONTINUOUS_LEFT",REAL_VARIATION_CONTINUOUS_LEFT;
+"REAL_VARIATION_CONTINUOUS_RIGHT",REAL_VARIATION_CONTINUOUS_RIGHT;
+"REAL_VARIATION_GE_ABS_FUNCTION",REAL_VARIATION_GE_ABS_FUNCTION;
+"REAL_VARIATION_GE_FUNCTION",REAL_VARIATION_GE_FUNCTION;
+"REAL_VARIATION_MINUS_FUNCTION_MONOTONE",REAL_VARIATION_MINUS_FUNCTION_MONOTONE;
+"REAL_VARIATION_MONOTONE",REAL_VARIATION_MONOTONE;
+"REAL_VARIATION_NEG",REAL_VARIATION_NEG;
+"REAL_VARIATION_POS_LE",REAL_VARIATION_POS_LE;
+"REAL_VARIATION_REFLECT",REAL_VARIATION_REFLECT;
+"REAL_VARIATION_REFLECT2",REAL_VARIATION_REFLECT2;
+"REAL_VARIATION_REFLECT_INTERVAL",REAL_VARIATION_REFLECT_INTERVAL;
+"REAL_VARIATION_TRANSLATION",REAL_VARIATION_TRANSLATION;
+"REAL_VARIATION_TRANSLATION2",REAL_VARIATION_TRANSLATION2;
+"REAL_VARIATION_TRANSLATION_INTERVAL",REAL_VARIATION_TRANSLATION_INTERVAL;
+"REAL_VARIATION_TRIANGLE",REAL_VARIATION_TRIANGLE;
+"REAL_VSUM",REAL_VSUM;
+"REAL_WLOG_LE",REAL_WLOG_LE;
+"REAL_WLOG_LT",REAL_WLOG_LT;
+"RECTIFIABLE_PATH_DIFFERENTIABLE",RECTIFIABLE_PATH_DIFFERENTIABLE;
+"RECTIFIABLE_PATH_IMP_PATH",RECTIFIABLE_PATH_IMP_PATH;
+"RECTIFIABLE_PATH_JOIN",RECTIFIABLE_PATH_JOIN;
+"RECTIFIABLE_PATH_JOIN_EQ",RECTIFIABLE_PATH_JOIN_EQ;
+"RECTIFIABLE_PATH_JOIN_IMP",RECTIFIABLE_PATH_JOIN_IMP;
+"RECTIFIABLE_PATH_LINEPATH",RECTIFIABLE_PATH_LINEPATH;
+"RECTIFIABLE_PATH_REVERSEPATH",RECTIFIABLE_PATH_REVERSEPATH;
+"RECTIFIABLE_PATH_SUBPATH",RECTIFIABLE_PATH_SUBPATH;
+"RECTIFIABLE_VALID_PATH",RECTIFIABLE_VALID_PATH;
+"RECURSION_CASEWISE",RECURSION_CASEWISE;
+"RECURSION_CASEWISE_PAIRWISE",RECURSION_CASEWISE_PAIRWISE;
+"RECURSION_SUPERADMISSIBLE",RECURSION_SUPERADMISSIBLE;
+"REDUCED_LABELLING",REDUCED_LABELLING;
+"REDUCED_LABELLING_0",REDUCED_LABELLING_0;
+"REDUCED_LABELLING_1",REDUCED_LABELLING_1;
+"REDUCED_LABELLING_SUC",REDUCED_LABELLING_SUC;
+"REDUCED_LABELLING_UNIQUE",REDUCED_LABELLING_UNIQUE;
+"REDUCE_LABELLING_0",REDUCE_LABELLING_0;
+"REFLECT_ALONG_0",REFLECT_ALONG_0;
+"REFLECT_ALONG_1D",REFLECT_ALONG_1D;
+"REFLECT_ALONG_ADD",REFLECT_ALONG_ADD;
+"REFLECT_ALONG_BASIS",REFLECT_ALONG_BASIS;
+"REFLECT_ALONG_EQ_0",REFLECT_ALONG_EQ_0;
+"REFLECT_ALONG_EQ_SELF",REFLECT_ALONG_EQ_SELF;
+"REFLECT_ALONG_INVOLUTION",REFLECT_ALONG_INVOLUTION;
+"REFLECT_ALONG_LINEAR_IMAGE",REFLECT_ALONG_LINEAR_IMAGE;
+"REFLECT_ALONG_MUL",REFLECT_ALONG_MUL;
+"REFLECT_ALONG_REFL",REFLECT_ALONG_REFL;
+"REFLECT_ALONG_SCALE",REFLECT_ALONG_SCALE;
+"REFLECT_ALONG_ZERO",REFLECT_ALONG_ZERO;
+"REFLECT_INTERVAL",REFLECT_INTERVAL;
+"REFLECT_REAL_INTERVAL",REFLECT_REAL_INTERVAL;
+"REFL_CLAUSE",REFL_CLAUSE;
+"RELATIVE_BOUNDARY_OF_CONVEX_HULL",RELATIVE_BOUNDARY_OF_CONVEX_HULL;
+"RELATIVE_BOUNDARY_OF_POLYHEDRON",RELATIVE_BOUNDARY_OF_POLYHEDRON;
+"RELATIVE_BOUNDARY_OF_TRIANGLE",RELATIVE_BOUNDARY_OF_TRIANGLE;
+"RELATIVE_BOUNDARY_RETRACT_OF_PUNCTURED_AFFINE_HULL",RELATIVE_BOUNDARY_RETRACT_OF_PUNCTURED_AFFINE_HULL;
+"RELATIVE_FRONTIER_BALL",RELATIVE_FRONTIER_BALL;
+"RELATIVE_FRONTIER_CBALL",RELATIVE_FRONTIER_CBALL;
+"RELATIVE_FRONTIER_CLOSURE",RELATIVE_FRONTIER_CLOSURE;
+"RELATIVE_FRONTIER_CONVEX_HULL_CASES",RELATIVE_FRONTIER_CONVEX_HULL_CASES;
+"RELATIVE_FRONTIER_CONVEX_HULL_EXPLICIT",RELATIVE_FRONTIER_CONVEX_HULL_EXPLICIT;
+"RELATIVE_FRONTIER_CONVEX_INTER_AFFINE",RELATIVE_FRONTIER_CONVEX_INTER_AFFINE;
+"RELATIVE_FRONTIER_EMPTY",RELATIVE_FRONTIER_EMPTY;
+"RELATIVE_FRONTIER_EQ_EMPTY",RELATIVE_FRONTIER_EQ_EMPTY;
+"RELATIVE_FRONTIER_FRONTIER",RELATIVE_FRONTIER_FRONTIER;
+"RELATIVE_FRONTIER_INJECTIVE_LINEAR_IMAGE",RELATIVE_FRONTIER_INJECTIVE_LINEAR_IMAGE;
+"RELATIVE_FRONTIER_NONEMPTY_INTERIOR",RELATIVE_FRONTIER_NONEMPTY_INTERIOR;
+"RELATIVE_FRONTIER_NOT_SING",RELATIVE_FRONTIER_NOT_SING;
+"RELATIVE_FRONTIER_OF_CONVEX_HULL",RELATIVE_FRONTIER_OF_CONVEX_HULL;
+"RELATIVE_FRONTIER_OF_POLYHEDRON",RELATIVE_FRONTIER_OF_POLYHEDRON;
+"RELATIVE_FRONTIER_OF_POLYHEDRON_ALT",RELATIVE_FRONTIER_OF_POLYHEDRON_ALT;
+"RELATIVE_FRONTIER_OF_TRIANGLE",RELATIVE_FRONTIER_OF_TRIANGLE;
+"RELATIVE_FRONTIER_RETRACT_OF_PUNCTURED_AFFINE_HULL",RELATIVE_FRONTIER_RETRACT_OF_PUNCTURED_AFFINE_HULL;
+"RELATIVE_FRONTIER_SING",RELATIVE_FRONTIER_SING;
+"RELATIVE_FRONTIER_TRANSLATION",RELATIVE_FRONTIER_TRANSLATION;
+"RELATIVE_INTERIOR",RELATIVE_INTERIOR;
+"RELATIVE_INTERIOR_AFFINE",RELATIVE_INTERIOR_AFFINE;
+"RELATIVE_INTERIOR_CONVEX_CONTAINS_SAME_RAY",RELATIVE_INTERIOR_CONVEX_CONTAINS_SAME_RAY;
+"RELATIVE_INTERIOR_CONVEX_HULL_EXPLICIT",RELATIVE_INTERIOR_CONVEX_HULL_EXPLICIT;
+"RELATIVE_INTERIOR_CONVEX_INTER_AFFINE",RELATIVE_INTERIOR_CONVEX_INTER_AFFINE;
+"RELATIVE_INTERIOR_CONVEX_PROLONG",RELATIVE_INTERIOR_CONVEX_PROLONG;
+"RELATIVE_INTERIOR_EMPTY",RELATIVE_INTERIOR_EMPTY;
+"RELATIVE_INTERIOR_EQ",RELATIVE_INTERIOR_EQ;
+"RELATIVE_INTERIOR_EQ_CLOSURE",RELATIVE_INTERIOR_EQ_CLOSURE;
+"RELATIVE_INTERIOR_EQ_EMPTY",RELATIVE_INTERIOR_EQ_EMPTY;
+"RELATIVE_INTERIOR_INJECTIVE_LINEAR_IMAGE",RELATIVE_INTERIOR_INJECTIVE_LINEAR_IMAGE;
+"RELATIVE_INTERIOR_INTERIOR",RELATIVE_INTERIOR_INTERIOR;
+"RELATIVE_INTERIOR_LINEAR_IMAGE_CONVEX",RELATIVE_INTERIOR_LINEAR_IMAGE_CONVEX;
+"RELATIVE_INTERIOR_MAXIMAL",RELATIVE_INTERIOR_MAXIMAL;
+"RELATIVE_INTERIOR_NONEMPTY_INTERIOR",RELATIVE_INTERIOR_NONEMPTY_INTERIOR;
+"RELATIVE_INTERIOR_OF_POLYHEDRON",RELATIVE_INTERIOR_OF_POLYHEDRON;
+"RELATIVE_INTERIOR_OPEN",RELATIVE_INTERIOR_OPEN;
+"RELATIVE_INTERIOR_OPEN_IN",RELATIVE_INTERIOR_OPEN_IN;
+"RELATIVE_INTERIOR_PCROSS",RELATIVE_INTERIOR_PCROSS;
+"RELATIVE_INTERIOR_POLYHEDRON_EXPLICIT",RELATIVE_INTERIOR_POLYHEDRON_EXPLICIT;
+"RELATIVE_INTERIOR_PROLONG",RELATIVE_INTERIOR_PROLONG;
+"RELATIVE_INTERIOR_SEGMENT",RELATIVE_INTERIOR_SEGMENT;
+"RELATIVE_INTERIOR_SING",RELATIVE_INTERIOR_SING;
+"RELATIVE_INTERIOR_SUBSET",RELATIVE_INTERIOR_SUBSET;
+"RELATIVE_INTERIOR_TRANSLATION",RELATIVE_INTERIOR_TRANSLATION;
+"RELATIVE_INTERIOR_UNBOUNDED_CONVEX_CONTAINS_RAY",RELATIVE_INTERIOR_UNBOUNDED_CONVEX_CONTAINS_RAY;
+"RELATIVE_INTERIOR_UNBOUNDED_CONVEX_CONTAINS_RAYS",RELATIVE_INTERIOR_UNBOUNDED_CONVEX_CONTAINS_RAYS;
+"RELATIVE_INTERIOR_UNIQUE",RELATIVE_INTERIOR_UNIQUE;
+"RELATIVE_INTERIOR_UNIV",RELATIVE_INTERIOR_UNIV;
+"REPLICATE",REPLICATE;
+"REP_ABS_PAIR",REP_ABS_PAIR;
+"REST",REST;
+"RETRACTION",RETRACTION;
+"RETRACTION_ARC",RETRACTION_ARC;
+"RETRACTION_IDEMPOTENT",RETRACTION_IDEMPOTENT;
+"RETRACTION_IMP_QUOTIENT_MAP",RETRACTION_IMP_QUOTIENT_MAP;
+"RETRACTION_REFL",RETRACTION_REFL;
+"RETRACTION_SUBSET",RETRACTION_SUBSET;
+"RETRACTION_o",RETRACTION_o;
+"RETRACT_FIXPOINT_PROPERTY",RETRACT_FIXPOINT_PROPERTY;
+"RETRACT_OF_CLOSED",RETRACT_OF_CLOSED;
+"RETRACT_OF_COHOMOTOPICALLY_TRIVIAL",RETRACT_OF_COHOMOTOPICALLY_TRIVIAL;
+"RETRACT_OF_COHOMOTOPICALLY_TRIVIAL_NULL",RETRACT_OF_COHOMOTOPICALLY_TRIVIAL_NULL;
+"RETRACT_OF_COMPACT",RETRACT_OF_COMPACT;
+"RETRACT_OF_CONNECTED",RETRACT_OF_CONNECTED;
+"RETRACT_OF_CONTRACTIBLE",RETRACT_OF_CONTRACTIBLE;
+"RETRACT_OF_EMPTY",RETRACT_OF_EMPTY;
+"RETRACT_OF_HOMOTOPICALLY_TRIVIAL",RETRACT_OF_HOMOTOPICALLY_TRIVIAL;
+"RETRACT_OF_HOMOTOPICALLY_TRIVIAL_NULL",RETRACT_OF_HOMOTOPICALLY_TRIVIAL_NULL;
+"RETRACT_OF_IMP_EXTENSIBLE",RETRACT_OF_IMP_EXTENSIBLE;
+"RETRACT_OF_IMP_SUBSET",RETRACT_OF_IMP_SUBSET;
+"RETRACT_OF_INJECTIVE_LINEAR_IMAGE",RETRACT_OF_INJECTIVE_LINEAR_IMAGE;
+"RETRACT_OF_LINEAR_IMAGE_EQ",RETRACT_OF_LINEAR_IMAGE_EQ;
+"RETRACT_OF_LOCALLY_COMPACT",RETRACT_OF_LOCALLY_COMPACT;
+"RETRACT_OF_LOCALLY_CONNECTED",RETRACT_OF_LOCALLY_CONNECTED;
+"RETRACT_OF_LOCALLY_PATH_CONNECTED",RETRACT_OF_LOCALLY_PATH_CONNECTED;
+"RETRACT_OF_PATH_CONNECTED",RETRACT_OF_PATH_CONNECTED;
+"RETRACT_OF_PCROSS",RETRACT_OF_PCROSS;
+"RETRACT_OF_REFL",RETRACT_OF_REFL;
+"RETRACT_OF_SIMPLY_CONNECTED",RETRACT_OF_SIMPLY_CONNECTED;
+"RETRACT_OF_SING",RETRACT_OF_SING;
+"RETRACT_OF_SUBSET",RETRACT_OF_SUBSET;
+"RETRACT_OF_TRANS",RETRACT_OF_TRANS;
+"RETRACT_OF_TRANSLATION",RETRACT_OF_TRANSLATION;
+"RETRACT_OF_TRANSLATION_EQ",RETRACT_OF_TRANSLATION_EQ;
+"REVERSE",REVERSE;
+"REVERSEPATH_JOINPATHS",REVERSEPATH_JOINPATHS;
+"REVERSEPATH_LINEAR_IMAGE",REVERSEPATH_LINEAR_IMAGE;
+"REVERSEPATH_LINEPATH",REVERSEPATH_LINEPATH;
+"REVERSEPATH_REVERSEPATH",REVERSEPATH_REVERSEPATH;
+"REVERSEPATH_SUBPATH",REVERSEPATH_SUBPATH;
+"REVERSEPATH_TRANSLATION",REVERSEPATH_TRANSLATION;
+"REVERSE_APPEND",REVERSE_APPEND;
+"REVERSE_REVERSE",REVERSE_REVERSE;
+"RE_ADD",RE_ADD;
+"RE_CACS",RE_CACS;
+"RE_CACS_BOUND",RE_CACS_BOUND;
+"RE_CACS_BOUNDS",RE_CACS_BOUNDS;
+"RE_CASN",RE_CASN;
+"RE_CASN_BOUND",RE_CASN_BOUND;
+"RE_CASN_BOUNDS",RE_CASN_BOUNDS;
+"RE_CATN_BOUNDS",RE_CATN_BOUNDS;
+"RE_CCOS",RE_CCOS;
+"RE_CEXP",RE_CEXP;
+"RE_CLOG",RE_CLOG;
+"RE_CLOG_POS_LE",RE_CLOG_POS_LE;
+"RE_CLOG_POS_LT",RE_CLOG_POS_LT;
+"RE_CLOG_POS_LT_IMP",RE_CLOG_POS_LT_IMP;
+"RE_CMUL",RE_CMUL;
+"RE_CNJ",RE_CNJ;
+"RE_COMPLEX_DIV_EQ_0",RE_COMPLEX_DIV_EQ_0;
+"RE_COMPLEX_DIV_GE_0",RE_COMPLEX_DIV_GE_0;
+"RE_COMPLEX_DIV_GT_0",RE_COMPLEX_DIV_GT_0;
+"RE_COMPLEX_DIV_LEMMA",RE_COMPLEX_DIV_LEMMA;
+"RE_COMPLEX_DIV_LE_0",RE_COMPLEX_DIV_LE_0;
+"RE_COMPLEX_DIV_LT_0",RE_COMPLEX_DIV_LT_0;
+"RE_CSIN",RE_CSIN;
+"RE_CSQRT",RE_CSQRT;
+"RE_CX",RE_CX;
+"RE_DEF",RE_DEF;
+"RE_DIV_CX",RE_DIV_CX;
+"RE_II",RE_II;
+"RE_LINEPATH_CX",RE_LINEPATH_CX;
+"RE_MUL_CX",RE_MUL_CX;
+"RE_MUL_II",RE_MUL_II;
+"RE_NEG",RE_NEG;
+"RE_POS_SEGMENT",RE_POS_SEGMENT;
+"RE_POW_2",RE_POW_2;
+"RE_SUB",RE_SUB;
+"RE_VSUM",RE_VSUM;
+"RE_WINDING_NUMBER",RE_WINDING_NUMBER;
+"RIEMANN_MAPPING_THEOREM",RIEMANN_MAPPING_THEOREM;
+"RIGHT_ADD_DISTRIB",RIGHT_ADD_DISTRIB;
+"RIGHT_AND_EXISTS_THM",RIGHT_AND_EXISTS_THM;
+"RIGHT_AND_FORALL_THM",RIGHT_AND_FORALL_THM;
+"RIGHT_EXISTS_AND_THM",RIGHT_EXISTS_AND_THM;
+"RIGHT_EXISTS_IMP_THM",RIGHT_EXISTS_IMP_THM;
+"RIGHT_FORALL_IMP_THM",RIGHT_FORALL_IMP_THM;
+"RIGHT_FORALL_OR_THM",RIGHT_FORALL_OR_THM;
+"RIGHT_IMP_EXISTS_THM",RIGHT_IMP_EXISTS_THM;
+"RIGHT_IMP_FORALL_THM",RIGHT_IMP_FORALL_THM;
+"RIGHT_INVERSE_LINEAR",RIGHT_INVERSE_LINEAR;
+"RIGHT_INVERTIBLE_TRANSP",RIGHT_INVERTIBLE_TRANSP;
+"RIGHT_OR_DISTRIB",RIGHT_OR_DISTRIB;
+"RIGHT_OR_EXISTS_THM",RIGHT_OR_EXISTS_THM;
+"RIGHT_OR_FORALL_THM",RIGHT_OR_FORALL_THM;
+"RIGHT_SUB_DISTRIB",RIGHT_SUB_DISTRIB;
+"RIGID_TRANSFORMATION_BETWEEN_2",RIGID_TRANSFORMATION_BETWEEN_2;
+"RIGID_TRANSFORMATION_BETWEEN_3",RIGID_TRANSFORMATION_BETWEEN_3;
+"RIGID_TRANSFORMATION_BETWEEN_CONGRUENT_SETS",RIGID_TRANSFORMATION_BETWEEN_CONGRUENT_SETS;
+"RIGID_TRANSFORMATION_BETWEEN_CONGRUENT_SETS_STRONG",RIGID_TRANSFORMATION_BETWEEN_CONGRUENT_SETS_STRONG;
+"ROLLE",ROLLE;
+"ROOT_0",ROOT_0;
+"ROOT_1",ROOT_1;
+"ROOT_2",ROOT_2;
+"ROOT_EXP_LOG",ROOT_EXP_LOG;
+"ROOT_INJ",ROOT_INJ;
+"ROOT_MONO_LE",ROOT_MONO_LE;
+"ROOT_MONO_LE_EQ",ROOT_MONO_LE_EQ;
+"ROOT_MONO_LT",ROOT_MONO_LT;
+"ROOT_MONO_LT_EQ",ROOT_MONO_LT_EQ;
+"ROOT_POS_LE",ROOT_POS_LE;
+"ROOT_POS_LT",ROOT_POS_LT;
+"ROOT_UNIQUE",ROOT_UNIQUE;
+"ROOT_WORKS",ROOT_WORKS;
+"ROTATE2D_0",ROTATE2D_0;
+"ROTATE2D_2PI",ROTATE2D_2PI;
+"ROTATE2D_ADD",ROTATE2D_ADD;
+"ROTATE2D_ADD_VECTORS",ROTATE2D_ADD_VECTORS;
+"ROTATE2D_COMPLEX",ROTATE2D_COMPLEX;
+"ROTATE2D_EQ",ROTATE2D_EQ;
+"ROTATE2D_EQ_0",ROTATE2D_EQ_0;
+"ROTATE2D_NPI",ROTATE2D_NPI;
+"ROTATE2D_PI",ROTATE2D_PI;
+"ROTATE2D_PI2",ROTATE2D_PI2;
+"ROTATE2D_POLAR",ROTATE2D_POLAR;
+"ROTATE2D_SUB",ROTATE2D_SUB;
+"ROTATE2D_SUB_ARG",ROTATE2D_SUB_ARG;
+"ROTATE2D_ZERO",ROTATE2D_ZERO;
+"ROTATION_EXISTS",ROTATION_EXISTS;
+"ROTATION_EXISTS_1",ROTATION_EXISTS_1;
+"ROTATION_LOWDIM_HORIZONTAL",ROTATION_LOWDIM_HORIZONTAL;
+"ROTATION_MATRIX_2",ROTATION_MATRIX_2;
+"ROTATION_MATRIX_EXISTS_BASIS",ROTATION_MATRIX_EXISTS_BASIS;
+"ROTATION_MATRIX_ROTATE2D",ROTATION_MATRIX_ROTATE2D;
+"ROTATION_MATRIX_ROTATE2D_EQ",ROTATION_MATRIX_ROTATE2D_EQ;
+"ROTATION_RIGHTWARD_LINE",ROTATION_RIGHTWARD_LINE;
+"ROTATION_ROTATE2D",ROTATION_ROTATE2D;
+"ROTATION_ROTATE2D_EXISTS",ROTATION_ROTATE2D_EXISTS;
+"ROTATION_ROTATE2D_EXISTS_GEN",ROTATION_ROTATE2D_EXISTS_GEN;
+"ROTATION_ROTATE2D_EXISTS_ORTHOGONAL",ROTATION_ROTATE2D_EXISTS_ORTHOGONAL;
+"ROTATION_ROTATE2D_EXISTS_ORTHOGONAL_ORIENTED",ROTATION_ROTATE2D_EXISTS_ORTHOGONAL_ORIENTED;
+"ROTHE",ROTHE;
+"ROTOINVERSION_MATRIX_REFLECT_ALONG",ROTOINVERSION_MATRIX_REFLECT_ALONG;
+"ROWS_TRANSP",ROWS_TRANSP;
+"ROW_TRANSP",ROW_TRANSP;
+"RPOW_1_LE",RPOW_1_LE;
+"RPOW_ADD",RPOW_ADD;
+"RPOW_ADD_ALT",RPOW_ADD_ALT;
+"RPOW_EQ_0",RPOW_EQ_0;
+"RPOW_INV",RPOW_INV;
+"RPOW_LE2",RPOW_LE2;
+"RPOW_LNEG",RPOW_LNEG;
+"RPOW_LT2",RPOW_LT2;
+"RPOW_MONO",RPOW_MONO;
+"RPOW_MONO_INV",RPOW_MONO_INV;
+"RPOW_MUL",RPOW_MUL;
+"RPOW_NEG",RPOW_NEG;
+"RPOW_ONE",RPOW_ONE;
+"RPOW_POS_LE",RPOW_POS_LE;
+"RPOW_POS_LT",RPOW_POS_LT;
+"RPOW_POW",RPOW_POW;
+"RPOW_RPOW",RPOW_RPOW;
+"RPOW_SQRT",RPOW_SQRT;
+"RPOW_ZERO",RPOW_ZERO;
+"RSUM_BOUND",RSUM_BOUND;
+"RSUM_COMPONENT_LE",RSUM_COMPONENT_LE;
+"RSUM_DIFF_BOUND",RSUM_DIFF_BOUND;
+"SAME_DISTANCES_TO_AFFINE_HULL",SAME_DISTANCES_TO_AFFINE_HULL;
+"SCALING_LINEAR",SCALING_LINEAR;
+"SCHAUDER",SCHAUDER;
+"SCHAUDER_PROJECTION",SCHAUDER_PROJECTION;
+"SCHAUDER_UNIV",SCHAUDER_UNIV;
+"SCHOTTKY",SCHOTTKY;
+"SCHWARZ_LEMMA",SCHWARZ_LEMMA;
+"SCHWARZ_REFLECTION",SCHWARZ_REFLECTION;
+"SECOND_CARTAN_THM_DIM_1",SECOND_CARTAN_THM_DIM_1;
+"SECOND_MEAN_VALUE_THEOREM",SECOND_MEAN_VALUE_THEOREM;
+"SECOND_MEAN_VALUE_THEOREM_BONNET",SECOND_MEAN_VALUE_THEOREM_BONNET;
+"SECOND_MEAN_VALUE_THEOREM_BONNET_FULL",SECOND_MEAN_VALUE_THEOREM_BONNET_FULL;
+"SECOND_MEAN_VALUE_THEOREM_FULL",SECOND_MEAN_VALUE_THEOREM_FULL;
+"SECOND_MEAN_VALUE_THEOREM_GEN",SECOND_MEAN_VALUE_THEOREM_GEN;
+"SECOND_MEAN_VALUE_THEOREM_GEN_FULL",SECOND_MEAN_VALUE_THEOREM_GEN_FULL;
+"SEGMENTS_SUBSET_CONVEX_HULL",SEGMENTS_SUBSET_CONVEX_HULL;
+"SEGMENT_1",SEGMENT_1;
+"SEGMENT_AS_BALL",SEGMENT_AS_BALL;
+"SEGMENT_BOUND",SEGMENT_BOUND;
+"SEGMENT_CLOSED_OPEN",SEGMENT_CLOSED_OPEN;
+"SEGMENT_CONVEX_HULL",SEGMENT_CONVEX_HULL;
+"SEGMENT_EDGE_OF",SEGMENT_EDGE_OF;
+"SEGMENT_EQ",SEGMENT_EQ;
+"SEGMENT_EQ_EMPTY",SEGMENT_EQ_EMPTY;
+"SEGMENT_EQ_SING",SEGMENT_EQ_SING;
+"SEGMENT_FACE_OF",SEGMENT_FACE_OF;
+"SEGMENT_FURTHEST_LE",SEGMENT_FURTHEST_LE;
+"SEGMENT_HORIZONTAL",SEGMENT_HORIZONTAL;
+"SEGMENT_IMAGE_INTERVAL",SEGMENT_IMAGE_INTERVAL;
+"SEGMENT_OPEN_SUBSET_CLOSED",SEGMENT_OPEN_SUBSET_CLOSED;
+"SEGMENT_REAL_SEGMENT",SEGMENT_REAL_SEGMENT;
+"SEGMENT_REFL",SEGMENT_REFL;
+"SEGMENT_SCALAR_MULTIPLE",SEGMENT_SCALAR_MULTIPLE;
+"SEGMENT_SYM",SEGMENT_SYM;
+"SEGMENT_TO_CLOSEST_POINT",SEGMENT_TO_CLOSEST_POINT;
+"SEGMENT_TO_POINT_EXISTS",SEGMENT_TO_POINT_EXISTS;
+"SEGMENT_TRANSLATION",SEGMENT_TRANSLATION;
+"SEGMENT_VERTICAL",SEGMENT_VERTICAL;
+"SELECT_AX",SELECT_AX;
+"SELECT_REFL",SELECT_REFL;
+"SELECT_UNIQUE",SELECT_UNIQUE;
+"SELF_ADJOINT_COMPOSE",SELF_ADJOINT_COMPOSE;
+"SELF_ADJOINT_HAS_EIGENVECTOR",SELF_ADJOINT_HAS_EIGENVECTOR;
+"SELF_ADJOINT_HAS_EIGENVECTOR_BASIS",SELF_ADJOINT_HAS_EIGENVECTOR_BASIS;
+"SELF_ADJOINT_HAS_EIGENVECTOR_BASIS_OF_SUBSPACE",SELF_ADJOINT_HAS_EIGENVECTOR_BASIS_OF_SUBSPACE;
+"SELF_ADJOINT_HAS_EIGENVECTOR_IN_SUBSPACE",SELF_ADJOINT_HAS_EIGENVECTOR_IN_SUBSPACE;
+"SELF_ADJOINT_ORTHOGONAL_EIGENVECTORS",SELF_ADJOINT_ORTHOGONAL_EIGENVECTORS;
+"SEPARABLE",SEPARABLE;
+"SEPARATE_CLOSED_COMPACT",SEPARATE_CLOSED_COMPACT;
+"SEPARATE_CLOSED_CONES",SEPARATE_CLOSED_CONES;
+"SEPARATE_COMPACT_CLOSED",SEPARATE_COMPACT_CLOSED;
+"SEPARATE_POINT_CLOSED",SEPARATE_POINT_CLOSED;
+"SEPARATING_HYPERPLANE_CLOSED_0",SEPARATING_HYPERPLANE_CLOSED_0;
+"SEPARATING_HYPERPLANE_CLOSED_0_INSET",SEPARATING_HYPERPLANE_CLOSED_0_INSET;
+"SEPARATING_HYPERPLANE_CLOSED_COMPACT",SEPARATING_HYPERPLANE_CLOSED_COMPACT;
+"SEPARATING_HYPERPLANE_CLOSED_POINT",SEPARATING_HYPERPLANE_CLOSED_POINT;
+"SEPARATING_HYPERPLANE_CLOSED_POINT_INSET",SEPARATING_HYPERPLANE_CLOSED_POINT_INSET;
+"SEPARATING_HYPERPLANE_COMPACT_CLOSED",SEPARATING_HYPERPLANE_COMPACT_CLOSED;
+"SEPARATING_HYPERPLANE_COMPACT_CLOSED_NONZERO",SEPARATING_HYPERPLANE_COMPACT_CLOSED_NONZERO;
+"SEPARATING_HYPERPLANE_COMPACT_COMPACT",SEPARATING_HYPERPLANE_COMPACT_COMPACT;
+"SEPARATING_HYPERPLANE_POLYHEDRA",SEPARATING_HYPERPLANE_POLYHEDRA;
+"SEPARATING_HYPERPLANE_RELATIVE_INTERIORS",SEPARATING_HYPERPLANE_RELATIVE_INTERIORS;
+"SEPARATING_HYPERPLANE_SETS",SEPARATING_HYPERPLANE_SETS;
+"SEPARATING_HYPERPLANE_SET_0",SEPARATING_HYPERPLANE_SET_0;
+"SEPARATING_HYPERPLANE_SET_0_INSPAN",SEPARATING_HYPERPLANE_SET_0_INSPAN;
+"SEPARATING_HYPERPLANE_SET_POINT_INAFF",SEPARATING_HYPERPLANE_SET_POINT_INAFF;
+"SEPARATION_CLOSURES",SEPARATION_CLOSURES;
+"SEPARATION_HAUSDORFF",SEPARATION_HAUSDORFF;
+"SEPARATION_NORMAL",SEPARATION_NORMAL;
+"SEPARATION_NORMAL_COMPACT",SEPARATION_NORMAL_COMPACT;
+"SEPARATION_T0",SEPARATION_T0;
+"SEPARATION_T1",SEPARATION_T1;
+"SEPARATION_T2",SEPARATION_T2;
+"SEQITERATE_CLAUSES",SEQITERATE_CLAUSES;
+"SEQITERATE_ITERATE",SEQITERATE_ITERATE;
+"SEQUENCE_CAUCHY_WLOG",SEQUENCE_CAUCHY_WLOG;
+"SEQUENCE_INFINITE_LEMMA",SEQUENCE_INFINITE_LEMMA;
+"SEQUENCE_UNIQUE_LIMPT",SEQUENCE_UNIQUE_LIMPT;
+"SEQUENTIALLY",SEQUENTIALLY;
+"SEQ_HARMONIC",SEQ_HARMONIC;
+"SEQ_MONO_LEMMA",SEQ_MONO_LEMMA;
+"SEQ_OFFSET",SEQ_OFFSET;
+"SEQ_OFFSET_NEG",SEQ_OFFSET_NEG;
+"SEQ_OFFSET_REV",SEQ_OFFSET_REV;
+"SERIES_0",SERIES_0;
+"SERIES_ABSCONV_IMP_CONV",SERIES_ABSCONV_IMP_CONV;
+"SERIES_ADD",SERIES_ADD;
+"SERIES_AND_DERIVATIVE_COMPARISON",SERIES_AND_DERIVATIVE_COMPARISON;
+"SERIES_AND_DERIVATIVE_COMPARISON_COMPLEX",SERIES_AND_DERIVATIVE_COMPARISON_COMPLEX;
+"SERIES_AND_DERIVATIVE_COMPARISON_LOCAL",SERIES_AND_DERIVATIVE_COMPARISON_LOCAL;
+"SERIES_CAUCHY",SERIES_CAUCHY;
+"SERIES_CAUCHY_UNIFORM",SERIES_CAUCHY_UNIFORM;
+"SERIES_CMUL",SERIES_CMUL;
+"SERIES_COMPARISON",SERIES_COMPARISON;
+"SERIES_COMPARISON_COMPLEX",SERIES_COMPARISON_COMPLEX;
+"SERIES_COMPARISON_UNIFORM",SERIES_COMPARISON_UNIFORM;
+"SERIES_COMPARISON_UNIFORM_COMPLEX",SERIES_COMPARISON_UNIFORM_COMPLEX;
+"SERIES_COMPLEX_DIV",SERIES_COMPLEX_DIV;
+"SERIES_COMPLEX_LMUL",SERIES_COMPLEX_LMUL;
+"SERIES_COMPLEX_RMUL",SERIES_COMPLEX_RMUL;
+"SERIES_COMPONENT",SERIES_COMPONENT;
+"SERIES_DIFFERENTIABLE_COMPARISON_COMPLEX",SERIES_DIFFERENTIABLE_COMPARISON_COMPLEX;
+"SERIES_DIFFS",SERIES_DIFFS;
+"SERIES_DIRICHLET",SERIES_DIRICHLET;
+"SERIES_DIRICHLET_BILINEAR",SERIES_DIRICHLET_BILINEAR;
+"SERIES_DIRICHLET_COMPLEX",SERIES_DIRICHLET_COMPLEX;
+"SERIES_DIRICHLET_COMPLEX_EXPLICIT",SERIES_DIRICHLET_COMPLEX_EXPLICIT;
+"SERIES_DIRICHLET_COMPLEX_GEN",SERIES_DIRICHLET_COMPLEX_GEN;
+"SERIES_DIRICHLET_COMPLEX_VERY_EXPLICIT",SERIES_DIRICHLET_COMPLEX_VERY_EXPLICIT;
+"SERIES_FINITE",SERIES_FINITE;
+"SERIES_FINITE_SUPPORT",SERIES_FINITE_SUPPORT;
+"SERIES_FROM",SERIES_FROM;
+"SERIES_GOESTOZERO",SERIES_GOESTOZERO;
+"SERIES_INJECTIVE_IMAGE",SERIES_INJECTIVE_IMAGE;
+"SERIES_INJECTIVE_IMAGE_STRONG",SERIES_INJECTIVE_IMAGE_STRONG;
+"SERIES_LIFT_ABSCONV_IMP_CONV",SERIES_LIFT_ABSCONV_IMP_CONV;
+"SERIES_LINEAR",SERIES_LINEAR;
+"SERIES_NEG",SERIES_NEG;
+"SERIES_RATIO",SERIES_RATIO;
+"SERIES_REARRANGE",SERIES_REARRANGE;
+"SERIES_REARRANGE_EQ",SERIES_REARRANGE_EQ;
+"SERIES_RESTRICT",SERIES_RESTRICT;
+"SERIES_SUB",SERIES_SUB;
+"SERIES_SUBSET",SERIES_SUBSET;
+"SERIES_TRIVIAL",SERIES_TRIVIAL;
+"SERIES_UNIQUE",SERIES_UNIQUE;
+"SERIES_VSUM",SERIES_VSUM;
+"SETCODE_BOUNDS",SETCODE_BOUNDS;
+"SETDIST_CLOSED_COMPACT",SETDIST_CLOSED_COMPACT;
+"SETDIST_CLOSEST_POINT",SETDIST_CLOSEST_POINT;
+"SETDIST_CLOSURE",SETDIST_CLOSURE;
+"SETDIST_COMPACT_CLOSED",SETDIST_COMPACT_CLOSED;
+"SETDIST_DIFFERENCES",SETDIST_DIFFERENCES;
+"SETDIST_EMPTY",SETDIST_EMPTY;
+"SETDIST_EQ_0_BOUNDED",SETDIST_EQ_0_BOUNDED;
+"SETDIST_EQ_0_CLOSED_COMPACT",SETDIST_EQ_0_CLOSED_COMPACT;
+"SETDIST_EQ_0_COMPACT_CLOSED",SETDIST_EQ_0_COMPACT_CLOSED;
+"SETDIST_EQ_0_SING",SETDIST_EQ_0_SING;
+"SETDIST_LE_DIST",SETDIST_LE_DIST;
+"SETDIST_LINEAR_IMAGE",SETDIST_LINEAR_IMAGE;
+"SETDIST_LIPSCHITZ",SETDIST_LIPSCHITZ;
+"SETDIST_POS_LE",SETDIST_POS_LE;
+"SETDIST_REFL",SETDIST_REFL;
+"SETDIST_SINGS",SETDIST_SINGS;
+"SETDIST_SUBSET_LEFT",SETDIST_SUBSET_LEFT;
+"SETDIST_SUBSET_RIGHT",SETDIST_SUBSET_RIGHT;
+"SETDIST_SYM",SETDIST_SYM;
+"SETDIST_TRANSLATION",SETDIST_TRANSLATION;
+"SETDIST_TRIANGLE",SETDIST_TRIANGLE;
+"SETDIST_UNIQUE",SETDIST_UNIQUE;
+"SETSPEC",SETSPEC;
+"SETVARIATION_EQUAL_LEMMA",SETVARIATION_EQUAL_LEMMA;
+"SET_CASES",SET_CASES;
+"SET_OF_LIST_APPEND",SET_OF_LIST_APPEND;
+"SET_OF_LIST_EQ_EMPTY",SET_OF_LIST_EQ_EMPTY;
+"SET_OF_LIST_MAP",SET_OF_LIST_MAP;
+"SET_OF_LIST_OF_SET",SET_OF_LIST_OF_SET;
+"SET_PAIR_THM",SET_PAIR_THM;
+"SET_PROVE_CASES",SET_PROVE_CASES;
+"SET_RECURSION_LEMMA",SET_RECURSION_LEMMA;
+"SET_VARIATION",SET_VARIATION;
+"SET_VARIATION_0",SET_VARIATION_0;
+"SET_VARIATION_ELEMENTARY_LEMMA",SET_VARIATION_ELEMENTARY_LEMMA;
+"SET_VARIATION_EQ",SET_VARIATION_EQ;
+"SET_VARIATION_GE_FUNCTION",SET_VARIATION_GE_FUNCTION;
+"SET_VARIATION_LBOUND",SET_VARIATION_LBOUND;
+"SET_VARIATION_LBOUND_ON_INTERVAL",SET_VARIATION_LBOUND_ON_INTERVAL;
+"SET_VARIATION_MONOTONE",SET_VARIATION_MONOTONE;
+"SET_VARIATION_ON_DIVISION",SET_VARIATION_ON_DIVISION;
+"SET_VARIATION_ON_ELEMENTARY",SET_VARIATION_ON_ELEMENTARY;
+"SET_VARIATION_ON_INTERVAL",SET_VARIATION_ON_INTERVAL;
+"SET_VARIATION_ON_NULL",SET_VARIATION_ON_NULL;
+"SET_VARIATION_POS_LE",SET_VARIATION_POS_LE;
+"SET_VARIATION_REFLECT2",SET_VARIATION_REFLECT2;
+"SET_VARIATION_TRANSLATION2",SET_VARIATION_TRANSLATION2;
+"SET_VARIATION_TRIANGLE",SET_VARIATION_TRIANGLE;
+"SET_VARIATION_UBOUND",SET_VARIATION_UBOUND;
+"SET_VARIATION_UBOUND_ON_INTERVAL",SET_VARIATION_UBOUND_ON_INTERVAL;
+"SET_VARIATION_WORKS_ON_INTERVAL",SET_VARIATION_WORKS_ON_INTERVAL;
+"SHIFTPATH_LINEAR_IMAGE",SHIFTPATH_LINEAR_IMAGE;
+"SHIFTPATH_SHIFTPATH",SHIFTPATH_SHIFTPATH;
+"SHIFTPATH_TRANSLATION",SHIFTPATH_TRANSLATION;
+"SHIFTPATH_TRIVIAL",SHIFTPATH_TRIVIAL;
+"SIGMA_COMPACT",SIGMA_COMPACT;
+"SIGN_COMPOSE",SIGN_COMPOSE;
+"SIGN_I",SIGN_I;
+"SIGN_IDEMPOTENT",SIGN_IDEMPOTENT;
+"SIGN_INVERSE",SIGN_INVERSE;
+"SIGN_NZ",SIGN_NZ;
+"SIGN_SWAP",SIGN_SWAP;
+"SIMPLEX",SIMPLEX;
+"SIMPLEX_DIM_GE",SIMPLEX_DIM_GE;
+"SIMPLEX_EMPTY",SIMPLEX_EMPTY;
+"SIMPLEX_EXPLICIT",SIMPLEX_EXPLICIT;
+"SIMPLEX_EXTREMAL_LE",SIMPLEX_EXTREMAL_LE;
+"SIMPLEX_EXTREMAL_LE_EXISTS",SIMPLEX_EXTREMAL_LE_EXISTS;
+"SIMPLEX_EXTREME_POINTS",SIMPLEX_EXTREME_POINTS;
+"SIMPLEX_FACE_OF_SIMPLEX",SIMPLEX_FACE_OF_SIMPLEX;
+"SIMPLEX_FURTHEST_LE",SIMPLEX_FURTHEST_LE;
+"SIMPLEX_FURTHEST_LE_EXISTS",SIMPLEX_FURTHEST_LE_EXISTS;
+"SIMPLEX_FURTHEST_LT",SIMPLEX_FURTHEST_LT;
+"SIMPLEX_IMP_POLYTOPE",SIMPLEX_IMP_POLYTOPE;
+"SIMPLEX_MINUS_1",SIMPLEX_MINUS_1;
+"SIMPLEX_TOP_FACE",SIMPLEX_TOP_FACE;
+"SIMPLE_CLOSED_PATH_ABS_WINDING_NUMBER_INSIDE",SIMPLE_CLOSED_PATH_ABS_WINDING_NUMBER_INSIDE;
+"SIMPLE_CLOSED_PATH_NORM_WINDING_NUMBER_INSIDE",SIMPLE_CLOSED_PATH_NORM_WINDING_NUMBER_INSIDE;
+"SIMPLE_CLOSED_PATH_WINDING_NUMBER_CASES",SIMPLE_CLOSED_PATH_WINDING_NUMBER_CASES;
+"SIMPLE_CLOSED_PATH_WINDING_NUMBER_INSIDE",SIMPLE_CLOSED_PATH_WINDING_NUMBER_INSIDE;
+"SIMPLE_CLOSED_PATH_WINDING_NUMBER_POS",SIMPLE_CLOSED_PATH_WINDING_NUMBER_POS;
+"SIMPLE_IMAGE",SIMPLE_IMAGE;
+"SIMPLE_IMAGE_GEN",SIMPLE_IMAGE_GEN;
+"SIMPLE_PATH_ASSOC",SIMPLE_PATH_ASSOC;
+"SIMPLE_PATH_CASES",SIMPLE_PATH_CASES;
+"SIMPLE_PATH_CIRCLEPATH",SIMPLE_PATH_CIRCLEPATH;
+"SIMPLE_PATH_ENDLESS",SIMPLE_PATH_ENDLESS;
+"SIMPLE_PATH_EQ_ARC",SIMPLE_PATH_EQ_ARC;
+"SIMPLE_PATH_IMP_ARC",SIMPLE_PATH_IMP_ARC;
+"SIMPLE_PATH_IMP_PATH",SIMPLE_PATH_IMP_PATH;
+"SIMPLE_PATH_JOIN_IMP",SIMPLE_PATH_JOIN_IMP;
+"SIMPLE_PATH_JOIN_LOOP",SIMPLE_PATH_JOIN_LOOP;
+"SIMPLE_PATH_JOIN_LOOP_EQ",SIMPLE_PATH_JOIN_LOOP_EQ;
+"SIMPLE_PATH_LINEAR_IMAGE_EQ",SIMPLE_PATH_LINEAR_IMAGE_EQ;
+"SIMPLE_PATH_LINEPATH",SIMPLE_PATH_LINEPATH;
+"SIMPLE_PATH_LINEPATH_EQ",SIMPLE_PATH_LINEPATH_EQ;
+"SIMPLE_PATH_PARTCIRCLEPATH",SIMPLE_PATH_PARTCIRCLEPATH;
+"SIMPLE_PATH_REVERSEPATH",SIMPLE_PATH_REVERSEPATH;
+"SIMPLE_PATH_SHIFTPATH",SIMPLE_PATH_SHIFTPATH;
+"SIMPLE_PATH_SUBPATH",SIMPLE_PATH_SUBPATH;
+"SIMPLE_PATH_SUBPATH_EQ",SIMPLE_PATH_SUBPATH_EQ;
+"SIMPLE_PATH_SYM",SIMPLE_PATH_SYM;
+"SIMPLE_PATH_TRANSLATION_EQ",SIMPLE_PATH_TRANSLATION_EQ;
+"SIMPLICIAL_COMPLEX_IMP_TRIANGULATION",SIMPLICIAL_COMPLEX_IMP_TRIANGULATION;
+"SIMPLY_CONNECTED_EMPTY",SIMPLY_CONNECTED_EMPTY;
+"SIMPLY_CONNECTED_EQ_BIHOLOMORPHIC_TO_DISC",SIMPLY_CONNECTED_EQ_BIHOLOMORPHIC_TO_DISC;
+"SIMPLY_CONNECTED_EQ_CONTINUOUS_LOG",SIMPLY_CONNECTED_EQ_CONTINUOUS_LOG;
+"SIMPLY_CONNECTED_EQ_CONTINUOUS_SQRT",SIMPLY_CONNECTED_EQ_CONTINUOUS_SQRT;
+"SIMPLY_CONNECTED_EQ_CONTRACTIBLE_CIRCLEMAP",SIMPLY_CONNECTED_EQ_CONTRACTIBLE_CIRCLEMAP;
+"SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ALL",SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ALL;
+"SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY",SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY;
+"SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_SOME",SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_SOME;
+"SIMPLY_CONNECTED_EQ_CONTRACTIBLE_PATH",SIMPLY_CONNECTED_EQ_CONTRACTIBLE_PATH;
+"SIMPLY_CONNECTED_EQ_EMPTY_INSIDE",SIMPLY_CONNECTED_EQ_EMPTY_INSIDE;
+"SIMPLY_CONNECTED_EQ_FRONTIER_PROPERTIES",SIMPLY_CONNECTED_EQ_FRONTIER_PROPERTIES;
+"SIMPLY_CONNECTED_EQ_GLOBAL_PRIMITIVE",SIMPLY_CONNECTED_EQ_GLOBAL_PRIMITIVE;
+"SIMPLY_CONNECTED_EQ_HOLOMORPHIC_LOG",SIMPLY_CONNECTED_EQ_HOLOMORPHIC_LOG;
+"SIMPLY_CONNECTED_EQ_HOLOMORPHIC_SQRT",SIMPLY_CONNECTED_EQ_HOLOMORPHIC_SQRT;
+"SIMPLY_CONNECTED_EQ_HOMEOMORPHIC_TO_DISC",SIMPLY_CONNECTED_EQ_HOMEOMORPHIC_TO_DISC;
+"SIMPLY_CONNECTED_EQ_HOMOTOPIC_CIRCLEMAPS",SIMPLY_CONNECTED_EQ_HOMOTOPIC_CIRCLEMAPS;
+"SIMPLY_CONNECTED_EQ_HOMOTOPIC_PATHS",SIMPLY_CONNECTED_EQ_HOMOTOPIC_PATHS;
+"SIMPLY_CONNECTED_EQ_INJECTIVE_HOLOMORPHIC_SQRT",SIMPLY_CONNECTED_EQ_INJECTIVE_HOLOMORPHIC_SQRT;
+"SIMPLY_CONNECTED_EQ_PATH_INTEGRAL_ZERO",SIMPLY_CONNECTED_EQ_PATH_INTEGRAL_ZERO;
+"SIMPLY_CONNECTED_EQ_UNBOUNDED_COMPLEMENT_COMPONENTS",SIMPLY_CONNECTED_EQ_UNBOUNDED_COMPLEMENT_COMPONENTS;
+"SIMPLY_CONNECTED_EQ_WINDING_NUMBER_ZERO",SIMPLY_CONNECTED_EQ_WINDING_NUMBER_ZERO;
+"SIMPLY_CONNECTED_IMP_CONNECTED",SIMPLY_CONNECTED_IMP_CONNECTED;
+"SIMPLY_CONNECTED_IMP_HOLOMORPHIC_LOG",SIMPLY_CONNECTED_IMP_HOLOMORPHIC_LOG;
+"SIMPLY_CONNECTED_IMP_HOLOMORPHIC_SQRT",SIMPLY_CONNECTED_IMP_HOLOMORPHIC_SQRT;
+"SIMPLY_CONNECTED_IMP_PATH_CONNECTED",SIMPLY_CONNECTED_IMP_PATH_CONNECTED;
+"SIMPLY_CONNECTED_IMP_WINDING_NUMBER_ZERO",SIMPLY_CONNECTED_IMP_WINDING_NUMBER_ZERO;
+"SIMPLY_CONNECTED_INJECTIVE_LINEAR_IMAGE",SIMPLY_CONNECTED_INJECTIVE_LINEAR_IMAGE;
+"SIMPLY_CONNECTED_INSIDE_SIMPLE_PATH",SIMPLY_CONNECTED_INSIDE_SIMPLE_PATH;
+"SIMPLY_CONNECTED_INTER",SIMPLY_CONNECTED_INTER;
+"SIMPLY_CONNECTED_PCROSS",SIMPLY_CONNECTED_PCROSS;
+"SIMPLY_CONNECTED_PCROSS_EQ",SIMPLY_CONNECTED_PCROSS_EQ;
+"SIMPLY_CONNECTED_RETRACTION_GEN",SIMPLY_CONNECTED_RETRACTION_GEN;
+"SIMPLY_CONNECTED_SPHERE",SIMPLY_CONNECTED_SPHERE;
+"SIMPLY_CONNECTED_SPHERE_EQ",SIMPLY_CONNECTED_SPHERE_EQ;
+"SIMPLY_CONNECTED_TRANSLATION",SIMPLY_CONNECTED_TRANSLATION;
+"SIMPLY_CONNECTED_UNION",SIMPLY_CONNECTED_UNION;
+"SINCOS_PRINCIPAL_VALUE",SINCOS_PRINCIPAL_VALUE;
+"SINCOS_TOTAL_2PI",SINCOS_TOTAL_2PI;
+"SINCOS_TOTAL_PI",SINCOS_TOTAL_PI;
+"SINCOS_TOTAL_PI2",SINCOS_TOTAL_PI2;
+"SING",SING;
+"SING_GSPEC",SING_GSPEC;
+"SING_SUBSET",SING_SUBSET;
+"SIN_0",SIN_0;
+"SIN_ACS",SIN_ACS;
+"SIN_ACS_NZ",SIN_ACS_NZ;
+"SIN_ADD",SIN_ADD;
+"SIN_ASN",SIN_ASN;
+"SIN_ATN",SIN_ATN;
+"SIN_BOUND",SIN_BOUND;
+"SIN_BOUNDS",SIN_BOUNDS;
+"SIN_CIRCLE",SIN_CIRCLE;
+"SIN_COS",SIN_COS;
+"SIN_COS_EQ",SIN_COS_EQ;
+"SIN_COS_INJ",SIN_COS_INJ;
+"SIN_COS_SQRT",SIN_COS_SQRT;
+"SIN_DOUBLE",SIN_DOUBLE;
+"SIN_EQ",SIN_EQ;
+"SIN_EQ_0",SIN_EQ_0;
+"SIN_EQ_0_PI",SIN_EQ_0_PI;
+"SIN_EQ_1",SIN_EQ_1;
+"SIN_EQ_MINUS1",SIN_EQ_MINUS1;
+"SIN_HASZERO",SIN_HASZERO;
+"SIN_HASZERO_MINIMAL",SIN_HASZERO_MINIMAL;
+"SIN_INJ_PI",SIN_INJ_PI;
+"SIN_INTEGER_2PI",SIN_INTEGER_2PI;
+"SIN_INTEGER_PI",SIN_INTEGER_PI;
+"SIN_MONO_LE",SIN_MONO_LE;
+"SIN_MONO_LE_EQ",SIN_MONO_LE_EQ;
+"SIN_MONO_LT",SIN_MONO_LT;
+"SIN_MONO_LT_EQ",SIN_MONO_LT_EQ;
+"SIN_NEARZERO",SIN_NEARZERO;
+"SIN_NEG",SIN_NEG;
+"SIN_NONTRIVIAL",SIN_NONTRIVIAL;
+"SIN_NPI",SIN_NPI;
+"SIN_PERIODIC",SIN_PERIODIC;
+"SIN_PERIODIC_PI",SIN_PERIODIC_PI;
+"SIN_PI",SIN_PI;
+"SIN_PI2",SIN_PI2;
+"SIN_PI6",SIN_PI6;
+"SIN_PI6_STRADDLE",SIN_PI6_STRADDLE;
+"SIN_PIMUL_EQ_0",SIN_PIMUL_EQ_0;
+"SIN_POS_PI",SIN_POS_PI;
+"SIN_POS_PI2",SIN_POS_PI2;
+"SIN_POS_PI_LE",SIN_POS_PI_LE;
+"SIN_POS_PI_REV",SIN_POS_PI_REV;
+"SIN_SUB",SIN_SUB;
+"SIN_TAN",SIN_TAN;
+"SIN_TOTAL_POS",SIN_TOTAL_POS;
+"SIN_ZERO",SIN_ZERO;
+"SIN_ZERO_PI",SIN_ZERO_PI;
+"SKOLEM_THM",SKOLEM_THM;
+"SLICE_BALL",SLICE_BALL;
+"SLICE_CBALL",SLICE_CBALL;
+"SLICE_DIFF",SLICE_DIFF;
+"SLICE_EMPTY",SLICE_EMPTY;
+"SLICE_INTER",SLICE_INTER;
+"SLICE_INTERVAL",SLICE_INTERVAL;
+"SLICE_SUBSET",SLICE_SUBSET;
+"SLICE_UNION",SLICE_UNION;
+"SLICE_UNIONS",SLICE_UNIONS;
+"SLICE_UNIV",SLICE_UNIV;
+"SND",SND;
+"SNDCART_ADD",SNDCART_ADD;
+"SNDCART_CMUL",SNDCART_CMUL;
+"SNDCART_NEG",SNDCART_NEG;
+"SNDCART_PASTECART",SNDCART_PASTECART;
+"SNDCART_SUB",SNDCART_SUB;
+"SNDCART_VEC",SNDCART_VEC;
+"SNDCART_VSUM",SNDCART_VSUM;
+"SND_DEF",SND_DEF;
+"SPANNING_SUBSET_INDEPENDENT",SPANNING_SUBSET_INDEPENDENT;
+"SPANNING_SURJECTIVE_IMAGE",SPANNING_SURJECTIVE_IMAGE;
+"SPANS_IMAGE",SPANS_IMAGE;
+"SPAN_0",SPAN_0;
+"SPAN_2",SPAN_2;
+"SPAN_3",SPAN_3;
+"SPAN_ADD",SPAN_ADD;
+"SPAN_ADD_EQ",SPAN_ADD_EQ;
+"SPAN_BREAKDOWN",SPAN_BREAKDOWN;
+"SPAN_BREAKDOWN_EQ",SPAN_BREAKDOWN_EQ;
+"SPAN_CARD_GE_DIM",SPAN_CARD_GE_DIM;
+"SPAN_CLAUSES",SPAN_CLAUSES;
+"SPAN_CONVEX_CONE_ALLSIGNS",SPAN_CONVEX_CONE_ALLSIGNS;
+"SPAN_DELETE_0",SPAN_DELETE_0;
+"SPAN_EMPTY",SPAN_EMPTY;
+"SPAN_EQ",SPAN_EQ;
+"SPAN_EQ_DIM",SPAN_EQ_DIM;
+"SPAN_EQ_INSERT",SPAN_EQ_INSERT;
+"SPAN_EQ_SELF",SPAN_EQ_SELF;
+"SPAN_EXPLICIT",SPAN_EXPLICIT;
+"SPAN_FINITE",SPAN_FINITE;
+"SPAN_IMAGE_SCALE",SPAN_IMAGE_SCALE;
+"SPAN_INC",SPAN_INC;
+"SPAN_INDUCT",SPAN_INDUCT;
+"SPAN_INDUCT_ALT",SPAN_INDUCT_ALT;
+"SPAN_INSERT_0",SPAN_INSERT_0;
+"SPAN_LINEAR_IMAGE",SPAN_LINEAR_IMAGE;
+"SPAN_MBASIS",SPAN_MBASIS;
+"SPAN_MONO",SPAN_MONO;
+"SPAN_MUL",SPAN_MUL;
+"SPAN_MUL_EQ",SPAN_MUL_EQ;
+"SPAN_NEG",SPAN_NEG;
+"SPAN_NEG_EQ",SPAN_NEG_EQ;
+"SPAN_NOT_UNIV_ORTHOGONAL",SPAN_NOT_UNIV_ORTHOGONAL;
+"SPAN_NOT_UNIV_SUBSET_HYPERPLANE",SPAN_NOT_UNIV_SUBSET_HYPERPLANE;
+"SPAN_OF_SUBSPACE",SPAN_OF_SUBSPACE;
+"SPAN_OPEN",SPAN_OPEN;
+"SPAN_PCROSS",SPAN_PCROSS;
+"SPAN_PCROSS_SUBSET",SPAN_PCROSS_SUBSET;
+"SPAN_SING",SPAN_SING;
+"SPAN_SPAN",SPAN_SPAN;
+"SPAN_STDBASIS",SPAN_STDBASIS;
+"SPAN_SUB",SPAN_SUB;
+"SPAN_SUBSET_SUBSPACE",SPAN_SUBSET_SUBSPACE;
+"SPAN_SUBSPACE",SPAN_SUBSPACE;
+"SPAN_SUMS",SPAN_SUMS;
+"SPAN_SUPERSET",SPAN_SUPERSET;
+"SPAN_TRANS",SPAN_TRANS;
+"SPAN_UNION",SPAN_UNION;
+"SPAN_UNION_SUBSET",SPAN_UNION_SUBSET;
+"SPAN_UNIV",SPAN_UNIV;
+"SPAN_VSUM",SPAN_VSUM;
+"SPECIAL_HYPERPLANE_SPAN",SPECIAL_HYPERPLANE_SPAN;
+"SPHERE_1",SPHERE_1;
+"SPHERE_EMPTY",SPHERE_EMPTY;
+"SPHERE_EQ_EMPTY",SPHERE_EQ_EMPTY;
+"SPHERE_EQ_SING",SPHERE_EQ_SING;
+"SPHERE_LINEAR_IMAGE",SPHERE_LINEAR_IMAGE;
+"SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE",SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE;
+"SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE_GEN",SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE_GEN;
+"SPHERE_SING",SPHERE_SING;
+"SPHERE_SUBSET_CBALL",SPHERE_SUBSET_CBALL;
+"SPHERE_TRANSLATION",SPHERE_TRANSLATION;
+"SPHERE_UNION_BALL",SPHERE_UNION_BALL;
+"SPLIT_INSIDE_SIMPLE_CLOSED_CURVE",SPLIT_INSIDE_SIMPLE_CLOSED_CURVE;
+"SQNORM_PASTECART",SQNORM_PASTECART;
+"SQRT_0",SQRT_0;
+"SQRT_1",SQRT_1;
+"SQRT_DIV",SQRT_DIV;
+"SQRT_EQ_0",SQRT_EQ_0;
+"SQRT_EVEN_POW2",SQRT_EVEN_POW2;
+"SQRT_INJ",SQRT_INJ;
+"SQRT_INV",SQRT_INV;
+"SQRT_LT_0",SQRT_LT_0;
+"SQRT_MONO_LE",SQRT_MONO_LE;
+"SQRT_MONO_LE_EQ",SQRT_MONO_LE_EQ;
+"SQRT_MONO_LT",SQRT_MONO_LT;
+"SQRT_MONO_LT_EQ",SQRT_MONO_LT_EQ;
+"SQRT_MUL",SQRT_MUL;
+"SQRT_POS_LE",SQRT_POS_LE;
+"SQRT_POS_LT",SQRT_POS_LT;
+"SQRT_POW2",SQRT_POW2;
+"SQRT_POW_2",SQRT_POW_2;
+"SQRT_UNIQUE",SQRT_UNIQUE;
+"SQRT_WORKS",SQRT_WORKS;
+"SQUARE_BOUND_LEMMA",SQUARE_BOUND_LEMMA;
+"SQUARE_CONTINUOUS",SQUARE_CONTINUOUS;
+"STARLIKE_CLOSURE",STARLIKE_CLOSURE;
+"STARLIKE_COMPACT_PROJECTIVE",STARLIKE_COMPACT_PROJECTIVE;
+"STARLIKE_CONVEX_SUBSET",STARLIKE_CONVEX_SUBSET;
+"STARLIKE_CONVEX_TWEAK_BOUNDARY_POINTS",STARLIKE_CONVEX_TWEAK_BOUNDARY_POINTS;
+"STARLIKE_IMP_CONNECTED",STARLIKE_IMP_CONNECTED;
+"STARLIKE_IMP_CONTRACTIBLE",STARLIKE_IMP_CONTRACTIBLE;
+"STARLIKE_IMP_CONTRACTIBLE_GEN",STARLIKE_IMP_CONTRACTIBLE_GEN;
+"STARLIKE_IMP_PATH_CONNECTED",STARLIKE_IMP_PATH_CONNECTED;
+"STARLIKE_IMP_SIMPLY_CONNECTED",STARLIKE_IMP_SIMPLY_CONNECTED;
+"STARLIKE_LINEAR_IMAGE",STARLIKE_LINEAR_IMAGE;
+"STARLIKE_LINEAR_IMAGE_EQ",STARLIKE_LINEAR_IMAGE_EQ;
+"STARLIKE_NEGLIGIBLE",STARLIKE_NEGLIGIBLE;
+"STARLIKE_NEGLIGIBLE_BOUNDED_MEASURABLE",STARLIKE_NEGLIGIBLE_BOUNDED_MEASURABLE;
+"STARLIKE_NEGLIGIBLE_LEMMA",STARLIKE_NEGLIGIBLE_LEMMA;
+"STARLIKE_NEGLIGIBLE_STRONG",STARLIKE_NEGLIGIBLE_STRONG;
+"STARLIKE_PCROSS",STARLIKE_PCROSS;
+"STARLIKE_PCROSS_EQ",STARLIKE_PCROSS_EQ;
+"STARLIKE_TRANSLATION_EQ",STARLIKE_TRANSLATION_EQ;
+"STARLIKE_UNIV",STARLIKE_UNIV;
+"STD_SIMPLEX",STD_SIMPLEX;
+"STEINHAUS",STEINHAUS;
+"STEINHAUS_LEBESGUE",STEINHAUS_LEBESGUE;
+"STEINHAUS_TRIVIAL",STEINHAUS_TRIVIAL;
+"STONE_WEIERSTRASS",STONE_WEIERSTRASS;
+"STONE_WEIERSTRASS_ALT",STONE_WEIERSTRASS_ALT;
+"STONE_WEIERSTRASS_REAL_POLYNOMIAL_FUNCTION",STONE_WEIERSTRASS_REAL_POLYNOMIAL_FUNCTION;
+"STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION",STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION;
+"STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION_AFFINE",STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION_AFFINE;
+"STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION_SUBSPACE",STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION_SUBSPACE;
+"STRETCH_GALOIS",STRETCH_GALOIS;
+"SUB",SUB;
+"SUBADDITIVE_CONTENT_DIVISION",SUBADDITIVE_CONTENT_DIVISION;
+"SUBPATH_LINEAR_IMAGE",SUBPATH_LINEAR_IMAGE;
+"SUBPATH_REFL",SUBPATH_REFL;
+"SUBPATH_REVERSEPATH",SUBPATH_REVERSEPATH;
+"SUBPATH_SCALING_LEMMA",SUBPATH_SCALING_LEMMA;
+"SUBPATH_TO_FRONTIER",SUBPATH_TO_FRONTIER;
+"SUBPATH_TO_FRONTIER_EXPLICIT",SUBPATH_TO_FRONTIER_EXPLICIT;
+"SUBPATH_TO_FRONTIER_STRONG",SUBPATH_TO_FRONTIER_STRONG;
+"SUBPATH_TRANSLATION",SUBPATH_TRANSLATION;
+"SUBPATH_TRIVIAL",SUBPATH_TRIVIAL;
+"SUBSEQUENCE_DIAGONALIZATION_LEMMA",SUBSEQUENCE_DIAGONALIZATION_LEMMA;
+"SUBSET",SUBSET;
+"SUBSET_ANTISYM",SUBSET_ANTISYM;
+"SUBSET_ANTISYM_EQ",SUBSET_ANTISYM_EQ;
+"SUBSET_BALL",SUBSET_BALL;
+"SUBSET_BALLS",SUBSET_BALLS;
+"SUBSET_CARD_EQ",SUBSET_CARD_EQ;
+"SUBSET_CBALL",SUBSET_CBALL;
+"SUBSET_CLOSURE",SUBSET_CLOSURE;
+"SUBSET_CONTINUOUS_IMAGE_SEGMENT_1",SUBSET_CONTINUOUS_IMAGE_SEGMENT_1;
+"SUBSET_DELETE",SUBSET_DELETE;
+"SUBSET_DIFF",SUBSET_DIFF;
+"SUBSET_DROP_IMAGE",SUBSET_DROP_IMAGE;
+"SUBSET_EMPTY",SUBSET_EMPTY;
+"SUBSET_FACE_OF_SIMPLEX",SUBSET_FACE_OF_SIMPLEX;
+"SUBSET_HULL",SUBSET_HULL;
+"SUBSET_HYPERPLANES",SUBSET_HYPERPLANES;
+"SUBSET_IMAGE",SUBSET_IMAGE;
+"SUBSET_INSERT",SUBSET_INSERT;
+"SUBSET_INSERT_DELETE",SUBSET_INSERT_DELETE;
+"SUBSET_INTER",SUBSET_INTER;
+"SUBSET_INTERIOR",SUBSET_INTERIOR;
+"SUBSET_INTERS",SUBSET_INTERS;
+"SUBSET_INTERVAL",SUBSET_INTERVAL;
+"SUBSET_INTERVAL_1",SUBSET_INTERVAL_1;
+"SUBSET_INTERVAL_IMP",SUBSET_INTERVAL_IMP;
+"SUBSET_INTER_ABSORPTION",SUBSET_INTER_ABSORPTION;
+"SUBSET_LE_DIM",SUBSET_LE_DIM;
+"SUBSET_LIFT_IMAGE",SUBSET_LIFT_IMAGE;
+"SUBSET_NUMSEG",SUBSET_NUMSEG;
+"SUBSET_OF_FACE_OF",SUBSET_OF_FACE_OF;
+"SUBSET_PATH_IMAGE_JOIN",SUBSET_PATH_IMAGE_JOIN;
+"SUBSET_PCROSS",SUBSET_PCROSS;
+"SUBSET_PRED",SUBSET_PRED;
+"SUBSET_PSUBSET_TRANS",SUBSET_PSUBSET_TRANS;
+"SUBSET_REAL_INTERVAL",SUBSET_REAL_INTERVAL;
+"SUBSET_REFL",SUBSET_REFL;
+"SUBSET_RELATIVE_INTERIOR",SUBSET_RELATIVE_INTERIOR;
+"SUBSET_RESTRICT",SUBSET_RESTRICT;
+"SUBSET_SECOND_COUNTABLE",SUBSET_SECOND_COUNTABLE;
+"SUBSET_SEGMENT",SUBSET_SEGMENT;
+"SUBSET_SEGMENT_OPEN_CLOSED",SUBSET_SEGMENT_OPEN_CLOSED;
+"SUBSET_TRANS",SUBSET_TRANS;
+"SUBSET_UNION",SUBSET_UNION;
+"SUBSET_UNIONS",SUBSET_UNIONS;
+"SUBSET_UNION_ABSORPTION",SUBSET_UNION_ABSORPTION;
+"SUBSET_UNIV",SUBSET_UNIV;
+"SUBSPACE_0",SUBSPACE_0;
+"SUBSPACE_ADD",SUBSPACE_ADD;
+"SUBSPACE_BOUNDED_EQ_TRIVIAL",SUBSPACE_BOUNDED_EQ_TRIVIAL;
+"SUBSPACE_CONVEX_CONE_SYMMETRIC",SUBSPACE_CONVEX_CONE_SYMMETRIC;
+"SUBSPACE_HYPERPLANE",SUBSPACE_HYPERPLANE;
+"SUBSPACE_IMP_AFFINE",SUBSPACE_IMP_AFFINE;
+"SUBSPACE_IMP_CONIC",SUBSPACE_IMP_CONIC;
+"SUBSPACE_IMP_CONVEX",SUBSPACE_IMP_CONVEX;
+"SUBSPACE_IMP_CONVEX_CONE",SUBSPACE_IMP_CONVEX_CONE;
+"SUBSPACE_IMP_NONEMPTY",SUBSPACE_IMP_NONEMPTY;
+"SUBSPACE_INTER",SUBSPACE_INTER;
+"SUBSPACE_INTERS",SUBSPACE_INTERS;
+"SUBSPACE_ISOMORPHISM",SUBSPACE_ISOMORPHISM;
+"SUBSPACE_KERNEL",SUBSPACE_KERNEL;
+"SUBSPACE_LINEAR_FIXED_POINTS",SUBSPACE_LINEAR_FIXED_POINTS;
+"SUBSPACE_LINEAR_IMAGE",SUBSPACE_LINEAR_IMAGE;
+"SUBSPACE_LINEAR_IMAGE_EQ",SUBSPACE_LINEAR_IMAGE_EQ;
+"SUBSPACE_LINEAR_PREIMAGE",SUBSPACE_LINEAR_PREIMAGE;
+"SUBSPACE_MUL",SUBSPACE_MUL;
+"SUBSPACE_NEG",SUBSPACE_NEG;
+"SUBSPACE_ORTHOGONAL_TO_VECTOR",SUBSPACE_ORTHOGONAL_TO_VECTOR;
+"SUBSPACE_ORTHOGONAL_TO_VECTORS",SUBSPACE_ORTHOGONAL_TO_VECTORS;
+"SUBSPACE_PCROSS",SUBSPACE_PCROSS;
+"SUBSPACE_PCROSS_EQ",SUBSPACE_PCROSS_EQ;
+"SUBSPACE_SPAN",SUBSPACE_SPAN;
+"SUBSPACE_SPECIAL_HYPERPLANE",SUBSPACE_SPECIAL_HYPERPLANE;
+"SUBSPACE_SUB",SUBSPACE_SUB;
+"SUBSPACE_SUBSTANDARD",SUBSPACE_SUBSTANDARD;
+"SUBSPACE_SUMS",SUBSPACE_SUMS;
+"SUBSPACE_TRANSLATION_SELF",SUBSPACE_TRANSLATION_SELF;
+"SUBSPACE_TRANSLATION_SELF_EQ",SUBSPACE_TRANSLATION_SELF_EQ;
+"SUBSPACE_TRIVIAL",SUBSPACE_TRIVIAL;
+"SUBSPACE_UNION_CHAIN",SUBSPACE_UNION_CHAIN;
+"SUBSPACE_UNIV",SUBSPACE_UNIV;
+"SUBSPACE_VSUM",SUBSPACE_VSUM;
+"SUBTOPOLOGY_SUPERSET",SUBTOPOLOGY_SUPERSET;
+"SUBTOPOLOGY_TOPSPACE",SUBTOPOLOGY_TOPSPACE;
+"SUBTOPOLOGY_UNIV",SUBTOPOLOGY_UNIV;
+"SUB_0",SUB_0;
+"SUB_ADD",SUB_ADD;
+"SUB_ADD_LCANCEL",SUB_ADD_LCANCEL;
+"SUB_ADD_RCANCEL",SUB_ADD_RCANCEL;
+"SUB_ELIM_THM",SUB_ELIM_THM;
+"SUB_ELIM_THM'",SUB_ELIM_THM';
+"SUB_EQ_0",SUB_EQ_0;
+"SUB_PRESUC",SUB_PRESUC;
+"SUB_REFL",SUB_REFL;
+"SUB_SUC",SUB_SUC;
+"SUC_DEF",SUC_DEF;
+"SUC_INJ",SUC_INJ;
+"SUC_SUB1",SUC_SUB1;
+"SUMMABLE_0",SUMMABLE_0;
+"SUMMABLE_ADD",SUMMABLE_ADD;
+"SUMMABLE_BILINEAR_PARTIAL_PRE",SUMMABLE_BILINEAR_PARTIAL_PRE;
+"SUMMABLE_CAUCHY",SUMMABLE_CAUCHY;
+"SUMMABLE_CMUL",SUMMABLE_CMUL;
+"SUMMABLE_COMPARISON",SUMMABLE_COMPARISON;
+"SUMMABLE_COMPLEX_DIV",SUMMABLE_COMPLEX_DIV;
+"SUMMABLE_COMPLEX_LMUL",SUMMABLE_COMPLEX_LMUL;
+"SUMMABLE_COMPLEX_RMUL",SUMMABLE_COMPLEX_RMUL;
+"SUMMABLE_COMPONENT",SUMMABLE_COMPONENT;
+"SUMMABLE_EQ",SUMMABLE_EQ;
+"SUMMABLE_EQ_COFINITE",SUMMABLE_EQ_COFINITE;
+"SUMMABLE_EQ_EVENTUALLY",SUMMABLE_EQ_EVENTUALLY;
+"SUMMABLE_FROM_ELSEWHERE",SUMMABLE_FROM_ELSEWHERE;
+"SUMMABLE_GP",SUMMABLE_GP;
+"SUMMABLE_IFF",SUMMABLE_IFF;
+"SUMMABLE_IFF_COFINITE",SUMMABLE_IFF_COFINITE;
+"SUMMABLE_IFF_EVENTUALLY",SUMMABLE_IFF_EVENTUALLY;
+"SUMMABLE_IMP_BOUNDED",SUMMABLE_IMP_BOUNDED;
+"SUMMABLE_IMP_SUMS_BOUNDED",SUMMABLE_IMP_SUMS_BOUNDED;
+"SUMMABLE_IMP_TOZERO",SUMMABLE_IMP_TOZERO;
+"SUMMABLE_LINEAR",SUMMABLE_LINEAR;
+"SUMMABLE_NEG",SUMMABLE_NEG;
+"SUMMABLE_REARRANGE",SUMMABLE_REARRANGE;
+"SUMMABLE_REINDEX",SUMMABLE_REINDEX;
+"SUMMABLE_RESTRICT",SUMMABLE_RESTRICT;
+"SUMMABLE_SUB",SUMMABLE_SUB;
+"SUMMABLE_SUBSET",SUMMABLE_SUBSET;
+"SUMMABLE_SUBSET_ABSCONV",SUMMABLE_SUBSET_ABSCONV;
+"SUMMABLE_SUBSET_COMPLEX",SUMMABLE_SUBSET_COMPLEX;
+"SUMMABLE_TRIVIAL",SUMMABLE_TRIVIAL;
+"SUMS_0",SUMS_0;
+"SUMS_CNJ",SUMS_CNJ;
+"SUMS_COMPLEX_0",SUMS_COMPLEX_0;
+"SUMS_EQ",SUMS_EQ;
+"SUMS_FINITE_DIFF",SUMS_FINITE_DIFF;
+"SUMS_FINITE_UNION",SUMS_FINITE_UNION;
+"SUMS_GP",SUMS_GP;
+"SUMS_IFF",SUMS_IFF;
+"SUMS_INFSUM",SUMS_INFSUM;
+"SUMS_INTERVALS",SUMS_INTERVALS;
+"SUMS_LIM",SUMS_LIM;
+"SUMS_OFFSET",SUMS_OFFSET;
+"SUMS_OFFSET_REV",SUMS_OFFSET_REV;
+"SUMS_REINDEX",SUMS_REINDEX;
+"SUMS_SUMMABLE",SUMS_SUMMABLE;
+"SUM_0",SUM_0;
+"SUM_1",SUM_1;
+"SUM_2",SUM_2;
+"SUM_3",SUM_3;
+"SUM_4",SUM_4;
+"SUM_ABS",SUM_ABS;
+"SUM_ABS_BOUND",SUM_ABS_BOUND;
+"SUM_ABS_LE",SUM_ABS_LE;
+"SUM_ABS_NUMSEG",SUM_ABS_NUMSEG;
+"SUM_ADD",SUM_ADD;
+"SUM_ADD_GEN",SUM_ADD_GEN;
+"SUM_ADD_NUMSEG",SUM_ADD_NUMSEG;
+"SUM_ADD_SPLIT",SUM_ADD_SPLIT;
+"SUM_BERNSTEIN",SUM_BERNSTEIN;
+"SUM_BIJECTION",SUM_BIJECTION;
+"SUM_BOUND",SUM_BOUND;
+"SUM_BOUND_GEN",SUM_BOUND_GEN;
+"SUM_BOUND_LT",SUM_BOUND_LT;
+"SUM_BOUND_LT_ALL",SUM_BOUND_LT_ALL;
+"SUM_BOUND_LT_GEN",SUM_BOUND_LT_GEN;
+"SUM_CASES",SUM_CASES;
+"SUM_CASES_1",SUM_CASES_1;
+"SUM_CLAUSES",SUM_CLAUSES;
+"SUM_CLAUSES_LEFT",SUM_CLAUSES_LEFT;
+"SUM_CLAUSES_NUMSEG",SUM_CLAUSES_NUMSEG;
+"SUM_CLAUSES_RIGHT",SUM_CLAUSES_RIGHT;
+"SUM_CLOSED",SUM_CLOSED;
+"SUM_COMBINE_L",SUM_COMBINE_L;
+"SUM_COMBINE_R",SUM_COMBINE_R;
+"SUM_CONST",SUM_CONST;
+"SUM_CONST_NUMSEG",SUM_CONST_NUMSEG;
+"SUM_CONTENT_AREA_OVER_THIN_DIVISION",SUM_CONTENT_AREA_OVER_THIN_DIVISION;
+"SUM_DELETE",SUM_DELETE;
+"SUM_DELETE_CASES",SUM_DELETE_CASES;
+"SUM_DELTA",SUM_DELTA;
+"SUM_DIFF",SUM_DIFF;
+"SUM_DIFFS",SUM_DIFFS;
+"SUM_DIFFS_ALT",SUM_DIFFS_ALT;
+"SUM_EQ",SUM_EQ;
+"SUM_EQ_0",SUM_EQ_0;
+"SUM_EQ_0_NUMSEG",SUM_EQ_0_NUMSEG;
+"SUM_EQ_GENERAL",SUM_EQ_GENERAL;
+"SUM_EQ_GENERAL_INVERSES",SUM_EQ_GENERAL_INVERSES;
+"SUM_EQ_NUMSEG",SUM_EQ_NUMSEG;
+"SUM_EQ_SUPERSET",SUM_EQ_SUPERSET;
+"SUM_GP",SUM_GP;
+"SUM_GP_BASIC",SUM_GP_BASIC;
+"SUM_GP_MULTIPLIED",SUM_GP_MULTIPLIED;
+"SUM_GP_OFFSET",SUM_GP_OFFSET;
+"SUM_GROUP",SUM_GROUP;
+"SUM_IMAGE",SUM_IMAGE;
+"SUM_IMAGE_GEN",SUM_IMAGE_GEN;
+"SUM_IMAGE_LE",SUM_IMAGE_LE;
+"SUM_IMAGE_NONZERO",SUM_IMAGE_NONZERO;
+"SUM_INCL_EXCL",SUM_INCL_EXCL;
+"SUM_INJECTION",SUM_INJECTION;
+"SUM_INTEGRAL_BOUNDS_DECREASING",SUM_INTEGRAL_BOUNDS_DECREASING;
+"SUM_INTEGRAL_BOUNDS_INCREASING",SUM_INTEGRAL_BOUNDS_INCREASING;
+"SUM_INTEGRAL_LBOUND_DECREASING",SUM_INTEGRAL_LBOUND_DECREASING;
+"SUM_INTEGRAL_LBOUND_INCREASING",SUM_INTEGRAL_LBOUND_INCREASING;
+"SUM_INTEGRAL_UBOUND_DECREASING",SUM_INTEGRAL_UBOUND_DECREASING;
+"SUM_INTEGRAL_UBOUND_INCREASING",SUM_INTEGRAL_UBOUND_INCREASING;
+"SUM_LE",SUM_LE;
+"SUM_LE_INCLUDED",SUM_LE_INCLUDED;
+"SUM_LE_NUMSEG",SUM_LE_NUMSEG;
+"SUM_LMUL",SUM_LMUL;
+"SUM_LT",SUM_LT;
+"SUM_LT_ALL",SUM_LT_ALL;
+"SUM_MULTICOUNT",SUM_MULTICOUNT;
+"SUM_MULTICOUNT_GEN",SUM_MULTICOUNT_GEN;
+"SUM_NEG",SUM_NEG;
+"SUM_OFFSET",SUM_OFFSET;
+"SUM_OFFSET_0",SUM_OFFSET_0;
+"SUM_OVER_PERMUTATIONS_INSERT",SUM_OVER_PERMUTATIONS_INSERT;
+"SUM_OVER_PERMUTATIONS_NUMSEG",SUM_OVER_PERMUTATIONS_NUMSEG;
+"SUM_OVER_TAGGED_DIVISION_LEMMA",SUM_OVER_TAGGED_DIVISION_LEMMA;
+"SUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA",SUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA;
+"SUM_PAIR",SUM_PAIR;
+"SUM_PARTIAL_PRE",SUM_PARTIAL_PRE;
+"SUM_PARTIAL_SUC",SUM_PARTIAL_SUC;
+"SUM_PERMUTATIONS_COMPOSE_L",SUM_PERMUTATIONS_COMPOSE_L;
+"SUM_PERMUTATIONS_COMPOSE_R",SUM_PERMUTATIONS_COMPOSE_R;
+"SUM_PERMUTATIONS_INVERSE",SUM_PERMUTATIONS_INVERSE;
+"SUM_PERMUTE",SUM_PERMUTE;
+"SUM_PERMUTE_NUMSEG",SUM_PERMUTE_NUMSEG;
+"SUM_POS_BOUND",SUM_POS_BOUND;
+"SUM_POS_EQ_0",SUM_POS_EQ_0;
+"SUM_POS_EQ_0_NUMSEG",SUM_POS_EQ_0_NUMSEG;
+"SUM_POS_LE",SUM_POS_LE;
+"SUM_POS_LE_NUMSEG",SUM_POS_LE_NUMSEG;
+"SUM_POS_LT",SUM_POS_LT;
+"SUM_RESTRICT",SUM_RESTRICT;
+"SUM_RESTRICT_SET",SUM_RESTRICT_SET;
+"SUM_RMUL",SUM_RMUL;
+"SUM_SING",SUM_SING;
+"SUM_SING_NUMSEG",SUM_SING_NUMSEG;
+"SUM_SUB",SUM_SUB;
+"SUM_SUBSET",SUM_SUBSET;
+"SUM_SUBSET_SIMPLE",SUM_SUBSET_SIMPLE;
+"SUM_SUB_NUMSEG",SUM_SUB_NUMSEG;
+"SUM_SUM_PRODUCT",SUM_SUM_PRODUCT;
+"SUM_SUM_RESTRICT",SUM_SUM_RESTRICT;
+"SUM_SUPERSET",SUM_SUPERSET;
+"SUM_SUPPORT",SUM_SUPPORT;
+"SUM_SWAP",SUM_SWAP;
+"SUM_SWAP_NUMSEG",SUM_SWAP_NUMSEG;
+"SUM_TRIV_NUMSEG",SUM_TRIV_NUMSEG;
+"SUM_UNION",SUM_UNION;
+"SUM_UNIONS_NONZERO",SUM_UNIONS_NONZERO;
+"SUM_UNION_EQ",SUM_UNION_EQ;
+"SUM_UNION_LZERO",SUM_UNION_LZERO;
+"SUM_UNION_NONZERO",SUM_UNION_NONZERO;
+"SUM_UNION_RZERO",SUM_UNION_RZERO;
+"SUM_VSUM",SUM_VSUM;
+"SUM_ZERO_EXISTS",SUM_ZERO_EXISTS;
+"SUP",SUP;
+"SUPERADMISSIBLE_COND",SUPERADMISSIBLE_COND;
+"SUPERADMISSIBLE_CONST",SUPERADMISSIBLE_CONST;
+"SUPERADMISSIBLE_MATCH_GUARDED_PATTERN",SUPERADMISSIBLE_MATCH_GUARDED_PATTERN;
+"SUPERADMISSIBLE_MATCH_SEQPATTERN",SUPERADMISSIBLE_MATCH_SEQPATTERN;
+"SUPERADMISSIBLE_MATCH_UNGUARDED_PATTERN",SUPERADMISSIBLE_MATCH_UNGUARDED_PATTERN;
+"SUPERADMISSIBLE_T",SUPERADMISSIBLE_T;
+"SUPERADMISSIBLE_TAIL",SUPERADMISSIBLE_TAIL;
+"SUPPORTING_HYPERPLANE_CLOSED_POINT",SUPPORTING_HYPERPLANE_CLOSED_POINT;
+"SUPPORTING_HYPERPLANE_COMPACT_POINT_INF",SUPPORTING_HYPERPLANE_COMPACT_POINT_INF;
+"SUPPORTING_HYPERPLANE_COMPACT_POINT_SUP",SUPPORTING_HYPERPLANE_COMPACT_POINT_SUP;
+"SUPPORTING_HYPERPLANE_RELATIVE_BOUNDARY",SUPPORTING_HYPERPLANE_RELATIVE_BOUNDARY;
+"SUPPORTING_HYPERPLANE_RELATIVE_FRONTIER",SUPPORTING_HYPERPLANE_RELATIVE_FRONTIER;
+"SUPPORT_CLAUSES",SUPPORT_CLAUSES;
+"SUPPORT_DELTA",SUPPORT_DELTA;
+"SUPPORT_EMPTY",SUPPORT_EMPTY;
+"SUPPORT_SUBSET",SUPPORT_SUBSET;
+"SUPPORT_SUPPORT",SUPPORT_SUPPORT;
+"SUP_EQ",SUP_EQ;
+"SUP_FINITE",SUP_FINITE;
+"SUP_FINITE_LEMMA",SUP_FINITE_LEMMA;
+"SUP_INSERT",SUP_INSERT;
+"SUP_INSERT_FINITE",SUP_INSERT_FINITE;
+"SUP_SING",SUP_SING;
+"SUP_UNIQUE_FINITE",SUP_UNIQUE_FINITE;
+"SURA_BURA_CLOSED",SURA_BURA_CLOSED;
+"SURA_BURA_COMPACT",SURA_BURA_COMPACT;
+"SURJ",SURJ;
+"SURJECTIVE_EXISTS_THM",SURJECTIVE_EXISTS_THM;
+"SURJECTIVE_FORALL_THM",SURJECTIVE_FORALL_THM;
+"SURJECTIVE_IFF_INJECTIVE",SURJECTIVE_IFF_INJECTIVE;
+"SURJECTIVE_IFF_INJECTIVE_GEN",SURJECTIVE_IFF_INJECTIVE_GEN;
+"SURJECTIVE_IMAGE",SURJECTIVE_IMAGE;
+"SURJECTIVE_IMAGE_EQ",SURJECTIVE_IMAGE_EQ;
+"SURJECTIVE_IMAGE_THM",SURJECTIVE_IMAGE_THM;
+"SURJECTIVE_INVERSE",SURJECTIVE_INVERSE;
+"SURJECTIVE_INVERSE_o",SURJECTIVE_INVERSE_o;
+"SURJECTIVE_MAP",SURJECTIVE_MAP;
+"SURJECTIVE_ON_IMAGE",SURJECTIVE_ON_IMAGE;
+"SURJECTIVE_ON_RIGHT_INVERSE",SURJECTIVE_ON_RIGHT_INVERSE;
+"SURJECTIVE_RIGHT_INVERSE",SURJECTIVE_RIGHT_INVERSE;
+"SURJECTIVE_SCALING",SURJECTIVE_SCALING;
+"SUSSMANN_OPEN_MAPPING",SUSSMANN_OPEN_MAPPING;
+"SWAPSEQ_COMPOSE",SWAPSEQ_COMPOSE;
+"SWAPSEQ_ENDSWAP",SWAPSEQ_ENDSWAP;
+"SWAPSEQ_EVEN_EVEN",SWAPSEQ_EVEN_EVEN;
+"SWAPSEQ_I",SWAPSEQ_I;
+"SWAPSEQ_IDENTITY_EVEN",SWAPSEQ_IDENTITY_EVEN;
+"SWAPSEQ_INVERSE",SWAPSEQ_INVERSE;
+"SWAPSEQ_INVERSE_EXISTS",SWAPSEQ_INVERSE_EXISTS;
+"SWAPSEQ_SWAP",SWAPSEQ_SWAP;
+"SWAP_COMMON",SWAP_COMMON;
+"SWAP_COMMON'",SWAP_COMMON';
+"SWAP_EXISTS_THM",SWAP_EXISTS_THM;
+"SWAP_FORALL_THM",SWAP_FORALL_THM;
+"SWAP_GALOIS",SWAP_GALOIS;
+"SWAP_GENERAL",SWAP_GENERAL;
+"SWAP_IDEMPOTENT",SWAP_IDEMPOTENT;
+"SWAP_INDEPENDENT",SWAP_INDEPENDENT;
+"SWAP_REFL",SWAP_REFL;
+"SWAP_SYM",SWAP_SYM;
+"SYLVESTER_DETERMINANT_IDENTITY",SYLVESTER_DETERMINANT_IDENTITY;
+"SYMDIFF_PARITY_LEMMA",SYMDIFF_PARITY_LEMMA;
+"SYMMETRIC_CLOSURE",SYMMETRIC_CLOSURE;
+"SYMMETRIC_INTERIOR",SYMMETRIC_INTERIOR;
+"SYMMETRIC_LINEAR_IMAGE",SYMMETRIC_LINEAR_IMAGE;
+"SYMMETRIC_MATRIX",SYMMETRIC_MATRIX;
+"SYMMETRIC_MATRIX_DIAGONALIZABLE_EXPLICIT",SYMMETRIC_MATRIX_DIAGONALIZABLE_EXPLICIT;
+"SYMMETRIC_MATRIX_EQ_DIAGONALIZABLE",SYMMETRIC_MATRIX_EQ_DIAGONALIZABLE;
+"SYMMETRIC_MATRIX_IMP_DIAGONALIZABLE",SYMMETRIC_MATRIX_IMP_DIAGONALIZABLE;
+"SYMMETRIC_MATRIX_MUL",SYMMETRIC_MATRIX_MUL;
+"SYMMETRIC_MATRIX_ORTHOGONAL_EIGENVECTORS",SYMMETRIC_MATRIX_ORTHOGONAL_EIGENVECTORS;
+"SYMMETRIX_MATRIX_CONJUGATE",SYMMETRIX_MATRIX_CONJUGATE;
+"SYMMETRY_LEMMA",SYMMETRY_LEMMA;
+"TAGGED_DIVISION_FINER",TAGGED_DIVISION_FINER;
+"TAGGED_DIVISION_OF",TAGGED_DIVISION_OF;
+"TAGGED_DIVISION_OF_ALT",TAGGED_DIVISION_OF_ALT;
+"TAGGED_DIVISION_OF_ANOTHER",TAGGED_DIVISION_OF_ANOTHER;
+"TAGGED_DIVISION_OF_EMPTY",TAGGED_DIVISION_OF_EMPTY;
+"TAGGED_DIVISION_OF_FINITE",TAGGED_DIVISION_OF_FINITE;
+"TAGGED_DIVISION_OF_NONTRIVIAL",TAGGED_DIVISION_OF_NONTRIVIAL;
+"TAGGED_DIVISION_OF_SELF",TAGGED_DIVISION_OF_SELF;
+"TAGGED_DIVISION_OF_TRIVIAL",TAGGED_DIVISION_OF_TRIVIAL;
+"TAGGED_DIVISION_OF_UNION_SELF",TAGGED_DIVISION_OF_UNION_SELF;
+"TAGGED_DIVISION_SPLIT_LEFT_INJ",TAGGED_DIVISION_SPLIT_LEFT_INJ;
+"TAGGED_DIVISION_SPLIT_RIGHT_INJ",TAGGED_DIVISION_SPLIT_RIGHT_INJ;
+"TAGGED_DIVISION_UNION",TAGGED_DIVISION_UNION;
+"TAGGED_DIVISION_UNIONS",TAGGED_DIVISION_UNIONS;
+"TAGGED_DIVISION_UNIONS_EXISTS",TAGGED_DIVISION_UNIONS_EXISTS;
+"TAGGED_DIVISION_UNION_IMAGE_SND",TAGGED_DIVISION_UNION_IMAGE_SND;
+"TAGGED_DIVISION_UNION_INTERVAL",TAGGED_DIVISION_UNION_INTERVAL;
+"TAGGED_PARTIAL_DIVISION_COMMON_POINT_BOUND",TAGGED_PARTIAL_DIVISION_COMMON_POINT_BOUND;
+"TAGGED_PARTIAL_DIVISION_COMMON_TAGS",TAGGED_PARTIAL_DIVISION_COMMON_TAGS;
+"TAGGED_PARTIAL_DIVISION_OF_SUBSET",TAGGED_PARTIAL_DIVISION_OF_SUBSET;
+"TAGGED_PARTIAL_DIVISION_OF_TRIVIAL",TAGGED_PARTIAL_DIVISION_OF_TRIVIAL;
+"TAGGED_PARTIAL_DIVISION_OF_UNION_SELF",TAGGED_PARTIAL_DIVISION_OF_UNION_SELF;
+"TAGGED_PARTIAL_DIVISION_SUBSET",TAGGED_PARTIAL_DIVISION_SUBSET;
+"TAG_IN_INTERVAL",TAG_IN_INTERVAL;
+"TAN_0",TAN_0;
+"TAN_ABS_GE_X",TAN_ABS_GE_X;
+"TAN_ADD",TAN_ADD;
+"TAN_ATN",TAN_ATN;
+"TAN_BOUND_PI2",TAN_BOUND_PI2;
+"TAN_COT",TAN_COT;
+"TAN_DOUBLE",TAN_DOUBLE;
+"TAN_MONO_LE",TAN_MONO_LE;
+"TAN_MONO_LE_EQ",TAN_MONO_LE_EQ;
+"TAN_MONO_LT",TAN_MONO_LT;
+"TAN_MONO_LT_EQ",TAN_MONO_LT_EQ;
+"TAN_NEG",TAN_NEG;
+"TAN_NPI",TAN_NPI;
+"TAN_PERIODIC_NPI",TAN_PERIODIC_NPI;
+"TAN_PERIODIC_PI",TAN_PERIODIC_PI;
+"TAN_PI",TAN_PI;
+"TAN_PI4",TAN_PI4;
+"TAN_POS_PI2",TAN_POS_PI2;
+"TAN_POS_PI2_LE",TAN_POS_PI2_LE;
+"TAN_SEC",TAN_SEC;
+"TAN_SUB",TAN_SUB;
+"TAN_TOTAL",TAN_TOTAL;
+"TAN_TOTAL_LEMMA",TAN_TOTAL_LEMMA;
+"TAN_TOTAL_POS",TAN_TOTAL_POS;
+"TARSKI_SET",TARSKI_SET;
+"TAYLOR_CCOS",TAYLOR_CCOS;
+"TAYLOR_CCOS_RAW",TAYLOR_CCOS_RAW;
+"TAYLOR_CEXP",TAYLOR_CEXP;
+"TAYLOR_CSIN",TAYLOR_CSIN;
+"TAYLOR_CSIN_RAW",TAYLOR_CSIN_RAW;
+"TENDSTO_LIM",TENDSTO_LIM;
+"TENDSTO_REAL",TENDSTO_REAL;
+"TIETZE",TIETZE;
+"TIETZE_CLOSED_INTERVAL",TIETZE_CLOSED_INTERVAL;
+"TIETZE_CLOSED_INTERVAL_1",TIETZE_CLOSED_INTERVAL_1;
+"TIETZE_OPEN_INTERVAL",TIETZE_OPEN_INTERVAL;
+"TIETZE_OPEN_INTERVAL_1",TIETZE_OPEN_INTERVAL_1;
+"TIETZE_STEP",TIETZE_STEP;
+"TIETZE_UNBOUNDED",TIETZE_UNBOUNDED;
+"TIETZE_UNBOUNDED_1",TIETZE_UNBOUNDED_1;
+"TL",TL;
+"TOPOLOGICAL_SORT",TOPOLOGICAL_SORT;
+"TOPOLOGY_EQ",TOPOLOGY_EQ;
+"TOPSPACE_EUCLIDEAN",TOPSPACE_EUCLIDEAN;
+"TOPSPACE_EUCLIDEANREAL",TOPSPACE_EUCLIDEANREAL;
+"TOPSPACE_EUCLIDEANREAL_SUBTOPOLOGY",TOPSPACE_EUCLIDEANREAL_SUBTOPOLOGY;
+"TOPSPACE_EUCLIDEAN_SUBTOPOLOGY",TOPSPACE_EUCLIDEAN_SUBTOPOLOGY;
+"TOPSPACE_SUBTOPOLOGY",TOPSPACE_SUBTOPOLOGY;
+"TRACE_0",TRACE_0;
+"TRACE_ADD",TRACE_ADD;
+"TRACE_CONJUGATE",TRACE_CONJUGATE;
+"TRACE_I",TRACE_I;
+"TRACE_MUL_SYM",TRACE_MUL_SYM;
+"TRACE_SUB",TRACE_SUB;
+"TRACE_TRANSP",TRACE_TRANSP;
+"TRANSITIVE_STEPWISE_LE",TRANSITIVE_STEPWISE_LE;
+"TRANSITIVE_STEPWISE_LE_EQ",TRANSITIVE_STEPWISE_LE_EQ;
+"TRANSITIVE_STEPWISE_LT",TRANSITIVE_STEPWISE_LT;
+"TRANSITIVE_STEPWISE_LT_EQ",TRANSITIVE_STEPWISE_LT_EQ;
+"TRANSLATION_DIFF",TRANSLATION_DIFF;
+"TRANSLATION_EQ_IMP",TRANSLATION_EQ_IMP;
+"TRANSLATION_GALOIS",TRANSLATION_GALOIS;
+"TRANSLATION_UNIV",TRANSLATION_UNIV;
+"TRANSP_COLUMNVECTOR",TRANSP_COLUMNVECTOR;
+"TRANSP_COMPONENT",TRANSP_COMPONENT;
+"TRANSP_DIAGONAL_MATRIX",TRANSP_DIAGONAL_MATRIX;
+"TRANSP_EQ",TRANSP_EQ;
+"TRANSP_MAT",TRANSP_MAT;
+"TRANSP_MATRIX_ADD",TRANSP_MATRIX_ADD;
+"TRANSP_MATRIX_CMUL",TRANSP_MATRIX_CMUL;
+"TRANSP_MATRIX_NEG",TRANSP_MATRIX_NEG;
+"TRANSP_MATRIX_SUB",TRANSP_MATRIX_SUB;
+"TRANSP_ROWVECTOR",TRANSP_ROWVECTOR;
+"TRANSP_TRANSP",TRANSP_TRANSP;
+"TREAL_ADD_ASSOC",TREAL_ADD_ASSOC;
+"TREAL_ADD_LDISTRIB",TREAL_ADD_LDISTRIB;
+"TREAL_ADD_LID",TREAL_ADD_LID;
+"TREAL_ADD_LINV",TREAL_ADD_LINV;
+"TREAL_ADD_SYM",TREAL_ADD_SYM;
+"TREAL_ADD_SYM_EQ",TREAL_ADD_SYM_EQ;
+"TREAL_ADD_WELLDEF",TREAL_ADD_WELLDEF;
+"TREAL_ADD_WELLDEFR",TREAL_ADD_WELLDEFR;
+"TREAL_EQ_AP",TREAL_EQ_AP;
+"TREAL_EQ_IMP_LE",TREAL_EQ_IMP_LE;
+"TREAL_EQ_REFL",TREAL_EQ_REFL;
+"TREAL_EQ_SYM",TREAL_EQ_SYM;
+"TREAL_EQ_TRANS",TREAL_EQ_TRANS;
+"TREAL_INV_0",TREAL_INV_0;
+"TREAL_INV_WELLDEF",TREAL_INV_WELLDEF;
+"TREAL_LE_ANTISYM",TREAL_LE_ANTISYM;
+"TREAL_LE_LADD_IMP",TREAL_LE_LADD_IMP;
+"TREAL_LE_MUL",TREAL_LE_MUL;
+"TREAL_LE_REFL",TREAL_LE_REFL;
+"TREAL_LE_TOTAL",TREAL_LE_TOTAL;
+"TREAL_LE_TRANS",TREAL_LE_TRANS;
+"TREAL_LE_WELLDEF",TREAL_LE_WELLDEF;
+"TREAL_MUL_ASSOC",TREAL_MUL_ASSOC;
+"TREAL_MUL_LID",TREAL_MUL_LID;
+"TREAL_MUL_LINV",TREAL_MUL_LINV;
+"TREAL_MUL_SYM",TREAL_MUL_SYM;
+"TREAL_MUL_SYM_EQ",TREAL_MUL_SYM_EQ;
+"TREAL_MUL_WELLDEF",TREAL_MUL_WELLDEF;
+"TREAL_MUL_WELLDEFR",TREAL_MUL_WELLDEFR;
+"TREAL_NEG_WELLDEF",TREAL_NEG_WELLDEF;
+"TREAL_OF_NUM_ADD",TREAL_OF_NUM_ADD;
+"TREAL_OF_NUM_EQ",TREAL_OF_NUM_EQ;
+"TREAL_OF_NUM_LE",TREAL_OF_NUM_LE;
+"TREAL_OF_NUM_MUL",TREAL_OF_NUM_MUL;
+"TREAL_OF_NUM_WELLDEF",TREAL_OF_NUM_WELLDEF;
+"TRIANGLE_LEMMA",TRIANGLE_LEMMA;
+"TRIANGLE_LINEAR_HAS_CHAIN_INTEGRAL",TRIANGLE_LINEAR_HAS_CHAIN_INTEGRAL;
+"TRIANGLE_PATH_INTEGRALS_CONVEX_PRIMITIVE",TRIANGLE_PATH_INTEGRALS_CONVEX_PRIMITIVE;
+"TRIANGLE_PATH_INTEGRALS_STARLIKE_PRIMITIVE",TRIANGLE_PATH_INTEGRALS_STARLIKE_PRIMITIVE;
+"TRIANGLE_POINTS_CLOSER",TRIANGLE_POINTS_CLOSER;
+"TRIANGULATION_INTER_SIMPLEX",TRIANGULATION_INTER_SIMPLEX;
+"TRIANGULATION_SIMPLICIAL_COMPLEX",TRIANGULATION_SIMPLICIAL_COMPLEX;
+"TRIANGULATION_UNION",TRIANGULATION_UNION;
+"TRIVIAL_LIMIT_AT",TRIVIAL_LIMIT_AT;
+"TRIVIAL_LIMIT_ATREAL",TRIVIAL_LIMIT_ATREAL;
+"TRIVIAL_LIMIT_AT_INFINITY",TRIVIAL_LIMIT_AT_INFINITY;
+"TRIVIAL_LIMIT_AT_NEGINFINITY",TRIVIAL_LIMIT_AT_NEGINFINITY;
+"TRIVIAL_LIMIT_AT_POSINFINITY",TRIVIAL_LIMIT_AT_POSINFINITY;
+"TRIVIAL_LIMIT_SEQUENTIALLY",TRIVIAL_LIMIT_SEQUENTIALLY;
+"TRIVIAL_LIMIT_WITHIN",TRIVIAL_LIMIT_WITHIN;
+"TRIVIAL_LIMIT_WITHINREAL_WITHIN",TRIVIAL_LIMIT_WITHINREAL_WITHIN;
+"TRIVIAL_LIMIT_WITHINREAL_WITHINCOMPLEX",TRIVIAL_LIMIT_WITHINREAL_WITHINCOMPLEX;
+"TRIVIAL_LIMIT_WITHIN_CONVEX",TRIVIAL_LIMIT_WITHIN_CONVEX;
+"TRIVIAL_LIMIT_WITHIN_REALINTERVAL",TRIVIAL_LIMIT_WITHIN_REALINTERVAL;
+"TRIV_AND_EXISTS_THM",TRIV_AND_EXISTS_THM;
+"TRIV_EXISTS_AND_THM",TRIV_EXISTS_AND_THM;
+"TRIV_EXISTS_IMP_THM",TRIV_EXISTS_IMP_THM;
+"TRIV_FORALL_IMP_THM",TRIV_FORALL_IMP_THM;
+"TRIV_FORALL_OR_THM",TRIV_FORALL_OR_THM;
+"TRIV_OR_FORALL_THM",TRIV_OR_FORALL_THM;
+"TRUTH",TRUTH;
+"TUBE_LEMMA",TUBE_LEMMA;
+"TWO",TWO;
+"T_DEF",T_DEF;
+"UNBOUNDED_COMPONENTS_COMPLEMENT_ABSOLUTE_RETRACT",UNBOUNDED_COMPONENTS_COMPLEMENT_ABSOLUTE_RETRACT;
+"UNBOUNDED_CONVEX_CLOSED_CONTAINS_RAY",UNBOUNDED_CONVEX_CLOSED_CONTAINS_RAY;
+"UNBOUNDED_CONVEX_CLOSED_CONTAINS_RAYS",UNBOUNDED_CONVEX_CLOSED_CONTAINS_RAYS;
+"UNBOUNDED_HALFSPACE_COMPONENT_GE",UNBOUNDED_HALFSPACE_COMPONENT_GE;
+"UNBOUNDED_HALFSPACE_COMPONENT_GT",UNBOUNDED_HALFSPACE_COMPONENT_GT;
+"UNBOUNDED_HALFSPACE_COMPONENT_LE",UNBOUNDED_HALFSPACE_COMPONENT_LE;
+"UNBOUNDED_HALFSPACE_COMPONENT_LT",UNBOUNDED_HALFSPACE_COMPONENT_LT;
+"UNBOUNDED_INTER_COBOUNDED",UNBOUNDED_INTER_COBOUNDED;
+"UNBOUNDED_OUTSIDE",UNBOUNDED_OUTSIDE;
+"UNCOUNTABLE_CONNECTED",UNCOUNTABLE_CONNECTED;
+"UNCOUNTABLE_CONTAINS_LIMIT_POINT",UNCOUNTABLE_CONTAINS_LIMIT_POINT;
+"UNCOUNTABLE_CONVEX",UNCOUNTABLE_CONVEX;
+"UNCOUNTABLE_EUCLIDEAN",UNCOUNTABLE_EUCLIDEAN;
+"UNCOUNTABLE_HAS_CONDENSATION_POINT",UNCOUNTABLE_HAS_CONDENSATION_POINT;
+"UNCOUNTABLE_INTERVAL",UNCOUNTABLE_INTERVAL;
+"UNCOUNTABLE_NONEMPTY_INTERIOR",UNCOUNTABLE_NONEMPTY_INTERIOR;
+"UNCOUNTABLE_OPEN",UNCOUNTABLE_OPEN;
+"UNCOUNTABLE_PATH_CONNECTED",UNCOUNTABLE_PATH_CONNECTED;
+"UNCOUNTABLE_REAL",UNCOUNTABLE_REAL;
+"UNCOUNTABLE_SEGMENT",UNCOUNTABLE_SEGMENT;
+"UNCURRY_DEF",UNCURRY_DEF;
+"UNICOHERENT_UNIV",UNICOHERENT_UNIV;
+"UNIFORMLY_CAUCHY_IMP_UNIFORMLY_CONVERGENT",UNIFORMLY_CAUCHY_IMP_UNIFORMLY_CONVERGENT;
+"UNIFORMLY_CONTINUOUS_EXTENDS_TO_CLOSURE",UNIFORMLY_CONTINUOUS_EXTENDS_TO_CLOSURE;
+"UNIFORMLY_CONTINUOUS_HOMEOMORPHISM_UNIV_TRIVIAL",UNIFORMLY_CONTINUOUS_HOMEOMORPHISM_UNIV_TRIVIAL;
+"UNIFORMLY_CONTINUOUS_IMP_CAUCHY_CONTINUOUS",UNIFORMLY_CONTINUOUS_IMP_CAUCHY_CONTINUOUS;
+"UNIFORMLY_CONTINUOUS_IMP_CONTINUOUS",UNIFORMLY_CONTINUOUS_IMP_CONTINUOUS;
+"UNIFORMLY_CONTINUOUS_ON_ADD",UNIFORMLY_CONTINUOUS_ON_ADD;
+"UNIFORMLY_CONTINUOUS_ON_CLOSURE",UNIFORMLY_CONTINUOUS_ON_CLOSURE;
+"UNIFORMLY_CONTINUOUS_ON_CMUL",UNIFORMLY_CONTINUOUS_ON_CMUL;
+"UNIFORMLY_CONTINUOUS_ON_COMPLEX_LMUL",UNIFORMLY_CONTINUOUS_ON_COMPLEX_LMUL;
+"UNIFORMLY_CONTINUOUS_ON_COMPLEX_MUL",UNIFORMLY_CONTINUOUS_ON_COMPLEX_MUL;
+"UNIFORMLY_CONTINUOUS_ON_COMPLEX_RMUL",UNIFORMLY_CONTINUOUS_ON_COMPLEX_RMUL;
+"UNIFORMLY_CONTINUOUS_ON_COMPOSE",UNIFORMLY_CONTINUOUS_ON_COMPOSE;
+"UNIFORMLY_CONTINUOUS_ON_CONST",UNIFORMLY_CONTINUOUS_ON_CONST;
+"UNIFORMLY_CONTINUOUS_ON_DIST_CLOSEST_POINT",UNIFORMLY_CONTINUOUS_ON_DIST_CLOSEST_POINT;
+"UNIFORMLY_CONTINUOUS_ON_EQ",UNIFORMLY_CONTINUOUS_ON_EQ;
+"UNIFORMLY_CONTINUOUS_ON_ID",UNIFORMLY_CONTINUOUS_ON_ID;
+"UNIFORMLY_CONTINUOUS_ON_LIFT_SETDIST",UNIFORMLY_CONTINUOUS_ON_LIFT_SETDIST;
+"UNIFORMLY_CONTINUOUS_ON_MUL",UNIFORMLY_CONTINUOUS_ON_MUL;
+"UNIFORMLY_CONTINUOUS_ON_NEG",UNIFORMLY_CONTINUOUS_ON_NEG;
+"UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY",UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY;
+"UNIFORMLY_CONTINUOUS_ON_SUB",UNIFORMLY_CONTINUOUS_ON_SUB;
+"UNIFORMLY_CONTINUOUS_ON_SUBSET",UNIFORMLY_CONTINUOUS_ON_SUBSET;
+"UNIFORMLY_CONTINUOUS_ON_VMUL",UNIFORMLY_CONTINUOUS_ON_VMUL;
+"UNIFORMLY_CONTINUOUS_ON_VSUM",UNIFORMLY_CONTINUOUS_ON_VSUM;
+"UNIFORMLY_CONVERGENT_EQ_CAUCHY",UNIFORMLY_CONVERGENT_EQ_CAUCHY;
+"UNIFORM_LIM_ADD",UNIFORM_LIM_ADD;
+"UNIFORM_LIM_BILINEAR",UNIFORM_LIM_BILINEAR;
+"UNIFORM_LIM_COMPLEX_DIV",UNIFORM_LIM_COMPLEX_DIV;
+"UNIFORM_LIM_COMPLEX_INV",UNIFORM_LIM_COMPLEX_INV;
+"UNIFORM_LIM_COMPLEX_MUL",UNIFORM_LIM_COMPLEX_MUL;
+"UNIFORM_LIM_SUB",UNIFORM_LIM_SUB;
+"UNION",UNION;
+"UNIONS",UNIONS;
+"UNIONS_0",UNIONS_0;
+"UNIONS_1",UNIONS_1;
+"UNIONS_2",UNIONS_2;
+"UNIONS_COMPONENTS",UNIONS_COMPONENTS;
+"UNIONS_CONNECTED_COMPONENT",UNIONS_CONNECTED_COMPONENT;
+"UNIONS_DIFF",UNIONS_DIFF;
+"UNIONS_GSPEC",UNIONS_GSPEC;
+"UNIONS_IMAGE",UNIONS_IMAGE;
+"UNIONS_INSERT",UNIONS_INSERT;
+"UNIONS_INTERS",UNIONS_INTERS;
+"UNIONS_MAXIMAL_SETS",UNIONS_MAXIMAL_SETS;
+"UNIONS_MONO",UNIONS_MONO;
+"UNIONS_MONO_IMAGE",UNIONS_MONO_IMAGE;
+"UNIONS_PATH_COMPONENT",UNIONS_PATH_COMPONENT;
+"UNIONS_PRED",UNIONS_PRED;
+"UNIONS_SUBSET",UNIONS_SUBSET;
+"UNIONS_UNION",UNIONS_UNION;
+"UNION_ACI",UNION_ACI;
+"UNION_ASSOC",UNION_ASSOC;
+"UNION_COMM",UNION_COMM;
+"UNION_EMPTY",UNION_EMPTY;
+"UNION_FL",UNION_FL;
+"UNION_IDEMPOT",UNION_IDEMPOT;
+"UNION_INSEG",UNION_INSEG;
+"UNION_INTERIOR_SUBSET",UNION_INTERIOR_SUBSET;
+"UNION_LE_ADD_C",UNION_LE_ADD_C;
+"UNION_OVER_INTER",UNION_OVER_INTER;
+"UNION_SEGMENT",UNION_SEGMENT;
+"UNION_SUBSET",UNION_SUBSET;
+"UNION_UNIV",UNION_UNIV;
+"UNION_WITH_INSIDE",UNION_WITH_INSIDE;
+"UNION_WITH_OUTSIDE",UNION_WITH_OUTSIDE;
+"UNIQUE_SKOLEM_ALT",UNIQUE_SKOLEM_ALT;
+"UNIQUE_SKOLEM_THM",UNIQUE_SKOLEM_THM;
+"UNIT_INTERVAL_CONVEX_HULL",UNIT_INTERVAL_CONVEX_HULL;
+"UNIT_INTERVAL_NONEMPTY",UNIT_INTERVAL_NONEMPTY;
+"UNIV",UNIV;
+"UNIV_GSPEC",UNIV_GSPEC;
+"UNIV_NOT_EMPTY",UNIV_NOT_EMPTY;
+"UNIV_PCROSS_UNIV",UNIV_PCROSS_UNIV;
+"UNIV_SECOND_COUNTABLE",UNIV_SECOND_COUNTABLE;
+"UNIV_SECOND_COUNTABLE_SEQUENCE",UNIV_SECOND_COUNTABLE_SEQUENCE;
+"UNIV_SUBSET",UNIV_SUBSET;
+"UNWINDING_2PI",UNWINDING_2PI;
+"UNWIND_THM1",UNWIND_THM1;
+"UNWIND_THM2",UNWIND_THM2;
+"UPPER_BOUND_FINITE_SET",UPPER_BOUND_FINITE_SET;
+"UPPER_BOUND_FINITE_SET_REAL",UPPER_BOUND_FINITE_SET_REAL;
+"URYSOHN",URYSOHN;
+"URYSOHN_LOCAL",URYSOHN_LOCAL;
+"URYSOHN_LOCAL_STRONG",URYSOHN_LOCAL_STRONG;
+"URYSOHN_STRONG",URYSOHN_STRONG;
+"VALID_PATH_CIRCLEPATH",VALID_PATH_CIRCLEPATH;
+"VALID_PATH_COMPOSE",VALID_PATH_COMPOSE;
+"VALID_PATH_IMP_PATH",VALID_PATH_IMP_PATH;
+"VALID_PATH_JOIN",VALID_PATH_JOIN;
+"VALID_PATH_JOIN_EQ",VALID_PATH_JOIN_EQ;
+"VALID_PATH_LINEPATH",VALID_PATH_LINEPATH;
+"VALID_PATH_PARTCIRCLEPATH",VALID_PATH_PARTCIRCLEPATH;
+"VALID_PATH_REVERSEPATH",VALID_PATH_REVERSEPATH;
+"VALID_PATH_SHIFTPATH",VALID_PATH_SHIFTPATH;
+"VALID_PATH_SUBPATH",VALID_PATH_SUBPATH;
+"VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION",VALID_PATH_VECTOR_POLYNOMIAL_FUNCTION;
+"VARIATION_EQUAL_LEMMA",VARIATION_EQUAL_LEMMA;
+"VECTOR_1",VECTOR_1;
+"VECTOR_2",VECTOR_2;
+"VECTOR_3",VECTOR_3;
+"VECTOR_4",VECTOR_4;
+"VECTOR_ADD_AC",VECTOR_ADD_AC;
+"VECTOR_ADD_ASSOC",VECTOR_ADD_ASSOC;
+"VECTOR_ADD_COMPONENT",VECTOR_ADD_COMPONENT;
+"VECTOR_ADD_LDISTRIB",VECTOR_ADD_LDISTRIB;
+"VECTOR_ADD_LID",VECTOR_ADD_LID;
+"VECTOR_ADD_LINV",VECTOR_ADD_LINV;
+"VECTOR_ADD_RDISTRIB",VECTOR_ADD_RDISTRIB;
+"VECTOR_ADD_RID",VECTOR_ADD_RID;
+"VECTOR_ADD_RINV",VECTOR_ADD_RINV;
+"VECTOR_ADD_SUB",VECTOR_ADD_SUB;
+"VECTOR_ADD_SYM",VECTOR_ADD_SYM;
+"VECTOR_AFFINITY_EQ",VECTOR_AFFINITY_EQ;
+"VECTOR_CHOOSE_DIST",VECTOR_CHOOSE_DIST;
+"VECTOR_CHOOSE_SIZE",VECTOR_CHOOSE_SIZE;
+"VECTOR_COMPONENTWISE",VECTOR_COMPONENTWISE;
+"VECTOR_DERIVATIVE_AT",VECTOR_DERIVATIVE_AT;
+"VECTOR_DERIVATIVE_CIRCLEPATH",VECTOR_DERIVATIVE_CIRCLEPATH;
+"VECTOR_DERIVATIVE_CONST_AT",VECTOR_DERIVATIVE_CONST_AT;
+"VECTOR_DERIVATIVE_LINEPATH_AT",VECTOR_DERIVATIVE_LINEPATH_AT;
+"VECTOR_DERIVATIVE_LINEPATH_WITHIN",VECTOR_DERIVATIVE_LINEPATH_WITHIN;
+"VECTOR_DERIVATIVE_PARTCIRCLEPATH",VECTOR_DERIVATIVE_PARTCIRCLEPATH;
+"VECTOR_DERIVATIVE_UNIQUE_AT",VECTOR_DERIVATIVE_UNIQUE_AT;
+"VECTOR_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL",VECTOR_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL;
+"VECTOR_DERIVATIVE_WITHIN_CLOSED_INTERVAL",VECTOR_DERIVATIVE_WITHIN_CLOSED_INTERVAL;
+"VECTOR_DERIVATIVE_WITHIN_INTERIOR",VECTOR_DERIVATIVE_WITHIN_INTERIOR;
+"VECTOR_DERIVATIVE_WORKS",VECTOR_DERIVATIVE_WORKS;
+"VECTOR_DIFF_CHAIN_AT",VECTOR_DIFF_CHAIN_AT;
+"VECTOR_DIFF_CHAIN_WITHIN",VECTOR_DIFF_CHAIN_WITHIN;
+"VECTOR_EQ",VECTOR_EQ;
+"VECTOR_EQ_ADDR",VECTOR_EQ_ADDR;
+"VECTOR_EQ_AFFINITY",VECTOR_EQ_AFFINITY;
+"VECTOR_EQ_DOT_SPAN",VECTOR_EQ_DOT_SPAN;
+"VECTOR_EQ_LDOT",VECTOR_EQ_LDOT;
+"VECTOR_EQ_NEG2",VECTOR_EQ_NEG2;
+"VECTOR_EQ_RDOT",VECTOR_EQ_RDOT;
+"VECTOR_EXPAND_1",VECTOR_EXPAND_1;
+"VECTOR_EXPAND_2",VECTOR_EXPAND_2;
+"VECTOR_EXPAND_3",VECTOR_EXPAND_3;
+"VECTOR_EXPAND_4",VECTOR_EXPAND_4;
+"VECTOR_IN_ORTHOGONAL_BASIS",VECTOR_IN_ORTHOGONAL_BASIS;
+"VECTOR_IN_ORTHOGONAL_SPANNINGSET",VECTOR_IN_ORTHOGONAL_SPANNINGSET;
+"VECTOR_IN_ORTHONORMAL_BASIS",VECTOR_IN_ORTHONORMAL_BASIS;
+"VECTOR_MATRIX_MUL_TRANSP",VECTOR_MATRIX_MUL_TRANSP;
+"VECTOR_MUL_ASSOC",VECTOR_MUL_ASSOC;
+"VECTOR_MUL_COMPONENT",VECTOR_MUL_COMPONENT;
+"VECTOR_MUL_EQ_0",VECTOR_MUL_EQ_0;
+"VECTOR_MUL_LCANCEL",VECTOR_MUL_LCANCEL;
+"VECTOR_MUL_LCANCEL_IMP",VECTOR_MUL_LCANCEL_IMP;
+"VECTOR_MUL_LID",VECTOR_MUL_LID;
+"VECTOR_MUL_LNEG",VECTOR_MUL_LNEG;
+"VECTOR_MUL_LZERO",VECTOR_MUL_LZERO;
+"VECTOR_MUL_RCANCEL",VECTOR_MUL_RCANCEL;
+"VECTOR_MUL_RCANCEL_IMP",VECTOR_MUL_RCANCEL_IMP;
+"VECTOR_MUL_RNEG",VECTOR_MUL_RNEG;
+"VECTOR_MUL_RZERO",VECTOR_MUL_RZERO;
+"VECTOR_NEG_0",VECTOR_NEG_0;
+"VECTOR_NEG_COMPONENT",VECTOR_NEG_COMPONENT;
+"VECTOR_NEG_EQ_0",VECTOR_NEG_EQ_0;
+"VECTOR_NEG_MINUS1",VECTOR_NEG_MINUS1;
+"VECTOR_NEG_NEG",VECTOR_NEG_NEG;
+"VECTOR_NEG_SUB",VECTOR_NEG_SUB;
+"VECTOR_ONE",VECTOR_ONE;
+"VECTOR_POLYNOMIAL_FUNCTION_ADD",VECTOR_POLYNOMIAL_FUNCTION_ADD;
+"VECTOR_POLYNOMIAL_FUNCTION_CMUL",VECTOR_POLYNOMIAL_FUNCTION_CMUL;
+"VECTOR_POLYNOMIAL_FUNCTION_COMPONENT",VECTOR_POLYNOMIAL_FUNCTION_COMPONENT;
+"VECTOR_POLYNOMIAL_FUNCTION_CONST",VECTOR_POLYNOMIAL_FUNCTION_CONST;
+"VECTOR_POLYNOMIAL_FUNCTION_ID",VECTOR_POLYNOMIAL_FUNCTION_ID;
+"VECTOR_POLYNOMIAL_FUNCTION_MUL",VECTOR_POLYNOMIAL_FUNCTION_MUL;
+"VECTOR_POLYNOMIAL_FUNCTION_NEG",VECTOR_POLYNOMIAL_FUNCTION_NEG;
+"VECTOR_POLYNOMIAL_FUNCTION_SUB",VECTOR_POLYNOMIAL_FUNCTION_SUB;
+"VECTOR_POLYNOMIAL_FUNCTION_VSUM",VECTOR_POLYNOMIAL_FUNCTION_VSUM;
+"VECTOR_SUB",VECTOR_SUB;
+"VECTOR_SUB_ADD",VECTOR_SUB_ADD;
+"VECTOR_SUB_ADD2",VECTOR_SUB_ADD2;
+"VECTOR_SUB_COMPONENT",VECTOR_SUB_COMPONENT;
+"VECTOR_SUB_EQ",VECTOR_SUB_EQ;
+"VECTOR_SUB_LDISTRIB",VECTOR_SUB_LDISTRIB;
+"VECTOR_SUB_LZERO",VECTOR_SUB_LZERO;
+"VECTOR_SUB_PROJECT_ORTHOGONAL",VECTOR_SUB_PROJECT_ORTHOGONAL;
+"VECTOR_SUB_RADD",VECTOR_SUB_RADD;
+"VECTOR_SUB_RDISTRIB",VECTOR_SUB_RDISTRIB;
+"VECTOR_SUB_REFL",VECTOR_SUB_REFL;
+"VECTOR_SUB_RZERO",VECTOR_SUB_RZERO;
+"VECTOR_VARIATION_AFFINITY",VECTOR_VARIATION_AFFINITY;
+"VECTOR_VARIATION_AFFINITY2",VECTOR_VARIATION_AFFINITY2;
+"VECTOR_VARIATION_COMBINE",VECTOR_VARIATION_COMBINE;
+"VECTOR_VARIATION_CONST",VECTOR_VARIATION_CONST;
+"VECTOR_VARIATION_CONST_EQ",VECTOR_VARIATION_CONST_EQ;
+"VECTOR_VARIATION_CONTINUOUS",VECTOR_VARIATION_CONTINUOUS;
+"VECTOR_VARIATION_CONTINUOUS_LEFT",VECTOR_VARIATION_CONTINUOUS_LEFT;
+"VECTOR_VARIATION_CONTINUOUS_RIGHT",VECTOR_VARIATION_CONTINUOUS_RIGHT;
+"VECTOR_VARIATION_EQ",VECTOR_VARIATION_EQ;
+"VECTOR_VARIATION_GE_DROP_FUNCTION",VECTOR_VARIATION_GE_DROP_FUNCTION;
+"VECTOR_VARIATION_GE_NORM_FUNCTION",VECTOR_VARIATION_GE_NORM_FUNCTION;
+"VECTOR_VARIATION_INTEGRAL_NORM_DERIVATIVE",VECTOR_VARIATION_INTEGRAL_NORM_DERIVATIVE;
+"VECTOR_VARIATION_MINUS_FUNCTION_MONOTONE",VECTOR_VARIATION_MINUS_FUNCTION_MONOTONE;
+"VECTOR_VARIATION_MONOTONE",VECTOR_VARIATION_MONOTONE;
+"VECTOR_VARIATION_NEG",VECTOR_VARIATION_NEG;
+"VECTOR_VARIATION_ON_DIVISION",VECTOR_VARIATION_ON_DIVISION;
+"VECTOR_VARIATION_ON_NULL",VECTOR_VARIATION_ON_NULL;
+"VECTOR_VARIATION_POS_LE",VECTOR_VARIATION_POS_LE;
+"VECTOR_VARIATION_REFLECT",VECTOR_VARIATION_REFLECT;
+"VECTOR_VARIATION_REFLECT2",VECTOR_VARIATION_REFLECT2;
+"VECTOR_VARIATION_REFLECT_INTERVAL",VECTOR_VARIATION_REFLECT_INTERVAL;
+"VECTOR_VARIATION_TRANSLATION",VECTOR_VARIATION_TRANSLATION;
+"VECTOR_VARIATION_TRANSLATION2",VECTOR_VARIATION_TRANSLATION2;
+"VECTOR_VARIATION_TRANSLATION_INTERVAL",VECTOR_VARIATION_TRANSLATION_INTERVAL;
+"VECTOR_VARIATION_TRIANGLE",VECTOR_VARIATION_TRIANGLE;
+"VEC_COMPONENT",VEC_COMPONENT;
+"VEC_EQ",VEC_EQ;
+"VSUM",VSUM;
+"VSUM_0",VSUM_0;
+"VSUM_1",VSUM_1;
+"VSUM_2",VSUM_2;
+"VSUM_3",VSUM_3;
+"VSUM_4",VSUM_4;
+"VSUM_ADD",VSUM_ADD;
+"VSUM_ADD_GEN",VSUM_ADD_GEN;
+"VSUM_ADD_NUMSEG",VSUM_ADD_NUMSEG;
+"VSUM_ADD_SPLIT",VSUM_ADD_SPLIT;
+"VSUM_BIJECTION",VSUM_BIJECTION;
+"VSUM_CASES",VSUM_CASES;
+"VSUM_CASES_1",VSUM_CASES_1;
+"VSUM_CLAUSES",VSUM_CLAUSES;
+"VSUM_CLAUSES_LEFT",VSUM_CLAUSES_LEFT;
+"VSUM_CLAUSES_NUMSEG",VSUM_CLAUSES_NUMSEG;
+"VSUM_CLAUSES_RIGHT",VSUM_CLAUSES_RIGHT;
+"VSUM_CMUL_NUMSEG",VSUM_CMUL_NUMSEG;
+"VSUM_COMBINE_L",VSUM_COMBINE_L;
+"VSUM_COMBINE_R",VSUM_COMBINE_R;
+"VSUM_COMPLEX_LMUL",VSUM_COMPLEX_LMUL;
+"VSUM_COMPLEX_RMUL",VSUM_COMPLEX_RMUL;
+"VSUM_COMPONENT",VSUM_COMPONENT;
+"VSUM_CONST",VSUM_CONST;
+"VSUM_CONST_NUMSEG",VSUM_CONST_NUMSEG;
+"VSUM_CONTENT_NULL",VSUM_CONTENT_NULL;
+"VSUM_CX",VSUM_CX;
+"VSUM_CX_NUMSEG",VSUM_CX_NUMSEG;
+"VSUM_DELETE",VSUM_DELETE;
+"VSUM_DELETE_CASES",VSUM_DELETE_CASES;
+"VSUM_DELTA",VSUM_DELTA;
+"VSUM_DIFF",VSUM_DIFF;
+"VSUM_DIFFS",VSUM_DIFFS;
+"VSUM_DIFFS_ALT",VSUM_DIFFS_ALT;
+"VSUM_DIFF_LEMMA",VSUM_DIFF_LEMMA;
+"VSUM_EQ",VSUM_EQ;
+"VSUM_EQ_0",VSUM_EQ_0;
+"VSUM_EQ_GENERAL",VSUM_EQ_GENERAL;
+"VSUM_EQ_GENERAL_INVERSES",VSUM_EQ_GENERAL_INVERSES;
+"VSUM_EQ_NUMSEG",VSUM_EQ_NUMSEG;
+"VSUM_EQ_SUPERSET",VSUM_EQ_SUPERSET;
+"VSUM_GP",VSUM_GP;
+"VSUM_GP_BASIC",VSUM_GP_BASIC;
+"VSUM_GP_MULTIPLIED",VSUM_GP_MULTIPLIED;
+"VSUM_GP_OFFSET",VSUM_GP_OFFSET;
+"VSUM_GROUP",VSUM_GROUP;
+"VSUM_IMAGE",VSUM_IMAGE;
+"VSUM_IMAGE_GEN",VSUM_IMAGE_GEN;
+"VSUM_IMAGE_NONZERO",VSUM_IMAGE_NONZERO;
+"VSUM_INCL_EXCL",VSUM_INCL_EXCL;
+"VSUM_INJECTION",VSUM_INJECTION;
+"VSUM_LMUL",VSUM_LMUL;
+"VSUM_NEG",VSUM_NEG;
+"VSUM_NONZERO_IMAGE_LEMMA",VSUM_NONZERO_IMAGE_LEMMA;
+"VSUM_NORM",VSUM_NORM;
+"VSUM_NORM_ALLSUBSETS_BOUND",VSUM_NORM_ALLSUBSETS_BOUND;
+"VSUM_NORM_BOUND",VSUM_NORM_BOUND;
+"VSUM_NORM_LE",VSUM_NORM_LE;
+"VSUM_NORM_TRIANGLE",VSUM_NORM_TRIANGLE;
+"VSUM_OFFSET",VSUM_OFFSET;
+"VSUM_OFFSET_0",VSUM_OFFSET_0;
+"VSUM_OVER_TAGGED_DIVISION_LEMMA",VSUM_OVER_TAGGED_DIVISION_LEMMA;
+"VSUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA",VSUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA;
+"VSUM_PAIR",VSUM_PAIR;
+"VSUM_PAIR_0",VSUM_PAIR_0;
+"VSUM_PARTIAL_PRE",VSUM_PARTIAL_PRE;
+"VSUM_PARTIAL_SUC",VSUM_PARTIAL_SUC;
+"VSUM_REAL",VSUM_REAL;
+"VSUM_RESTRICT",VSUM_RESTRICT;
+"VSUM_RESTRICT_SET",VSUM_RESTRICT_SET;
+"VSUM_RMUL",VSUM_RMUL;
+"VSUM_SING",VSUM_SING;
+"VSUM_SING_NUMSEG",VSUM_SING_NUMSEG;
+"VSUM_SUB",VSUM_SUB;
+"VSUM_SUB_NUMSEG",VSUM_SUB_NUMSEG;
+"VSUM_SUC",VSUM_SUC;
+"VSUM_SUPERSET",VSUM_SUPERSET;
+"VSUM_SWAP",VSUM_SWAP;
+"VSUM_SWAP_NUMSEG",VSUM_SWAP_NUMSEG;
+"VSUM_TRIV_NUMSEG",VSUM_TRIV_NUMSEG;
+"VSUM_UNION",VSUM_UNION;
+"VSUM_UNIONS_NONZERO",VSUM_UNIONS_NONZERO;
+"VSUM_UNION_LZERO",VSUM_UNION_LZERO;
+"VSUM_UNION_NONZERO",VSUM_UNION_NONZERO;
+"VSUM_UNION_RZERO",VSUM_UNION_RZERO;
+"VSUM_VMUL",VSUM_VMUL;
+"VSUM_VSUM_PRODUCT",VSUM_VSUM_PRODUCT;
+"WF",WF;
+"WF_DCHAIN",WF_DCHAIN;
+"WF_EQ",WF_EQ;
+"WF_EREC",WF_EREC;
+"WF_FALSE",WF_FALSE;
+"WF_FINITE",WF_FINITE;
+"WF_IND",WF_IND;
+"WF_INT_MEASURE",WF_INT_MEASURE;
+"WF_INT_MEASURE_2",WF_INT_MEASURE_2;
+"WF_LEX",WF_LEX;
+"WF_LEX_DEPENDENT",WF_LEX_DEPENDENT;
+"WF_MEASURE",WF_MEASURE;
+"WF_MEASURE_GEN",WF_MEASURE_GEN;
+"WF_POINTWISE",WF_POINTWISE;
+"WF_REC",WF_REC;
+"WF_REC_CASES",WF_REC_CASES;
+"WF_REC_CASES'",WF_REC_CASES';
+"WF_REC_INVARIANT",WF_REC_INVARIANT;
+"WF_REC_TAIL",WF_REC_TAIL;
+"WF_REC_TAIL_GENERAL",WF_REC_TAIL_GENERAL;
+"WF_REC_TAIL_GENERAL'",WF_REC_TAIL_GENERAL';
+"WF_REC_WF",WF_REC_WF;
+"WF_REC_num",WF_REC_num;
+"WF_REFL",WF_REFL;
+"WF_SUBSET",WF_SUBSET;
+"WF_UREC",WF_UREC;
+"WF_UREC_WF",WF_UREC_WF;
+"WF_num",WF_num;
+"WINDING_NUMBER",WINDING_NUMBER;
+"WINDING_NUMBER_AHLFORS",WINDING_NUMBER_AHLFORS;
+"WINDING_NUMBER_AHLFORS_FULL",WINDING_NUMBER_AHLFORS_FULL;
+"WINDING_NUMBER_AHLFORS_LEMMA",WINDING_NUMBER_AHLFORS_LEMMA;
+"WINDING_NUMBER_AROUND_INSIDE",WINDING_NUMBER_AROUND_INSIDE;
+"WINDING_NUMBER_AS_CONTINUOUS_LOGARITHM",WINDING_NUMBER_AS_CONTINUOUS_LOGARITHM;
+"WINDING_NUMBER_BIG_MEETS",WINDING_NUMBER_BIG_MEETS;
+"WINDING_NUMBER_CIRCLEPATH",WINDING_NUMBER_CIRCLEPATH;
+"WINDING_NUMBER_COMPOSE_CEXP",WINDING_NUMBER_COMPOSE_CEXP;
+"WINDING_NUMBER_CONSTANT",WINDING_NUMBER_CONSTANT;
+"WINDING_NUMBER_EQ",WINDING_NUMBER_EQ;
+"WINDING_NUMBER_EQUAL",WINDING_NUMBER_EQUAL;
+"WINDING_NUMBER_EQ_1",WINDING_NUMBER_EQ_1;
+"WINDING_NUMBER_FROM_INNERPATH",WINDING_NUMBER_FROM_INNERPATH;
+"WINDING_NUMBER_HOMOTOPIC_LOOPS",WINDING_NUMBER_HOMOTOPIC_LOOPS;
+"WINDING_NUMBER_HOMOTOPIC_LOOPS_EQ",WINDING_NUMBER_HOMOTOPIC_LOOPS_EQ;
+"WINDING_NUMBER_HOMOTOPIC_LOOPS_NULL_EQ",WINDING_NUMBER_HOMOTOPIC_LOOPS_NULL_EQ;
+"WINDING_NUMBER_HOMOTOPIC_PATHS",WINDING_NUMBER_HOMOTOPIC_PATHS;
+"WINDING_NUMBER_HOMOTOPIC_PATHS_EQ",WINDING_NUMBER_HOMOTOPIC_PATHS_EQ;
+"WINDING_NUMBER_HOMOTOPIC_PATHS_NULL_EQ",WINDING_NUMBER_HOMOTOPIC_PATHS_NULL_EQ;
+"WINDING_NUMBER_HOMOTOPIC_PATHS_NULL_EXPLICIT_EQ",WINDING_NUMBER_HOMOTOPIC_PATHS_NULL_EXPLICIT_EQ;
+"WINDING_NUMBER_IVT_ABS",WINDING_NUMBER_IVT_ABS;
+"WINDING_NUMBER_IVT_NEG",WINDING_NUMBER_IVT_NEG;
+"WINDING_NUMBER_IVT_POS",WINDING_NUMBER_IVT_POS;
+"WINDING_NUMBER_JOIN",WINDING_NUMBER_JOIN;
+"WINDING_NUMBER_JOIN_POS_COMBINED",WINDING_NUMBER_JOIN_POS_COMBINED;
+"WINDING_NUMBER_LE_HALF",WINDING_NUMBER_LE_HALF;
+"WINDING_NUMBER_LINEPATH_POS_LT",WINDING_NUMBER_LINEPATH_POS_LT;
+"WINDING_NUMBER_LOOPS_LINEAR_EQ",WINDING_NUMBER_LOOPS_LINEAR_EQ;
+"WINDING_NUMBER_LT_1",WINDING_NUMBER_LT_1;
+"WINDING_NUMBER_LT_HALF",WINDING_NUMBER_LT_HALF;
+"WINDING_NUMBER_LT_HALF_LINEPATH",WINDING_NUMBER_LT_HALF_LINEPATH;
+"WINDING_NUMBER_NEARBY_LOOPS_EQ",WINDING_NUMBER_NEARBY_LOOPS_EQ;
+"WINDING_NUMBER_NEARBY_PATHS_EQ",WINDING_NUMBER_NEARBY_PATHS_EQ;
+"WINDING_NUMBER_OFFSET",WINDING_NUMBER_OFFSET;
+"WINDING_NUMBER_PARTCIRCLEPATH_POS_LT",WINDING_NUMBER_PARTCIRCLEPATH_POS_LT;
+"WINDING_NUMBER_PATHS_LINEAR_EQ",WINDING_NUMBER_PATHS_LINEAR_EQ;
+"WINDING_NUMBER_POS_LE",WINDING_NUMBER_POS_LE;
+"WINDING_NUMBER_POS_LT",WINDING_NUMBER_POS_LT;
+"WINDING_NUMBER_POS_LT_LEMMA",WINDING_NUMBER_POS_LT_LEMMA;
+"WINDING_NUMBER_POS_MEETS",WINDING_NUMBER_POS_MEETS;
+"WINDING_NUMBER_REVERSEPATH",WINDING_NUMBER_REVERSEPATH;
+"WINDING_NUMBER_SHIFTPATH",WINDING_NUMBER_SHIFTPATH;
+"WINDING_NUMBER_SPLIT_LINEPATH",WINDING_NUMBER_SPLIT_LINEPATH;
+"WINDING_NUMBER_STRONG",WINDING_NUMBER_STRONG;
+"WINDING_NUMBER_SUBPATH_COMBINE",WINDING_NUMBER_SUBPATH_COMBINE;
+"WINDING_NUMBER_SUBPATH_CONTINUOUS",WINDING_NUMBER_SUBPATH_CONTINUOUS;
+"WINDING_NUMBER_TRIANGLE",WINDING_NUMBER_TRIANGLE;
+"WINDING_NUMBER_TRIVIAL",WINDING_NUMBER_TRIVIAL;
+"WINDING_NUMBER_UNIQUE",WINDING_NUMBER_UNIQUE;
+"WINDING_NUMBER_UNIQUE_LOOP",WINDING_NUMBER_UNIQUE_LOOP;
+"WINDING_NUMBER_VALID_PATH",WINDING_NUMBER_VALID_PATH;
+"WINDING_NUMBER_ZERO_ATINFINITY",WINDING_NUMBER_ZERO_ATINFINITY;
+"WINDING_NUMBER_ZERO_IN_OUTSIDE",WINDING_NUMBER_ZERO_IN_OUTSIDE;
+"WINDING_NUMBER_ZERO_OUTSIDE",WINDING_NUMBER_ZERO_OUTSIDE;
+"WINDING_NUMBER_ZERO_POINT",WINDING_NUMBER_ZERO_POINT;
+"WITHIN",WITHIN;
+"WITHINREAL_UNIV",WITHINREAL_UNIV;
+"WITHIN_UNIV",WITHIN_UNIV;
+"WITHIN_WITHIN",WITHIN_WITHIN;
+"WLOG_LE",WLOG_LE;
+"WLOG_LINEAR_INJECTIVE_IMAGE",WLOG_LINEAR_INJECTIVE_IMAGE;
+"WLOG_LINEAR_INJECTIVE_IMAGE_2",WLOG_LINEAR_INJECTIVE_IMAGE_2;
+"WLOG_LINEAR_INJECTIVE_IMAGE_2_ALT",WLOG_LINEAR_INJECTIVE_IMAGE_2_ALT;
+"WLOG_LINEAR_INJECTIVE_IMAGE_ALT",WLOG_LINEAR_INJECTIVE_IMAGE_ALT;
+"WLOG_LT",WLOG_LT;
+"WO",WO;
+"WOSET",WOSET;
+"WOSET_ANTISYM",WOSET_ANTISYM;
+"WOSET_FLEQ",WOSET_FLEQ;
+"WOSET_POSET",WOSET_POSET;
+"WOSET_REFL",WOSET_REFL;
+"WOSET_TOTAL",WOSET_TOTAL;
+"WOSET_TOTAL_LE",WOSET_TOTAL_LE;
+"WOSET_TOTAL_LT",WOSET_TOTAL_LT;
+"WOSET_TRANS",WOSET_TRANS;
+"WOSET_TRANS_LE",WOSET_TRANS_LE;
+"WOSET_TRANS_LESS",WOSET_TRANS_LESS;
+"WOSET_WELL",WOSET_WELL;
+"WOSET_WELL_CONTRAPOS",WOSET_WELL_CONTRAPOS;
+"ZBOT",ZBOT;
+"ZCONSTR",ZCONSTR;
+"ZCONSTR_ZBOT",ZCONSTR_ZBOT;
+"ZERO_DEF",ZERO_DEF;
+"ZIP",ZIP;
+"ZIP_DEF",ZIP_DEF;
+"ZL",ZL;
+"ZL_SUBSETS",ZL_SUBSETS;
+"ZL_SUBSETS_UNIONS",ZL_SUBSETS_UNIONS;
+"ZL_SUBSETS_UNIONS_NONEMPTY",ZL_SUBSETS_UNIONS_NONEMPTY;
+"ZRECSPACE_CASES",ZRECSPACE_CASES;
+"ZRECSPACE_INDUCT",ZRECSPACE_INDUCT;
+"ZRECSPACE_RULES",ZRECSPACE_RULES;
+"_FALSITY_",_FALSITY_;
+"_FUNCTION",_FUNCTION;
+"_GUARDED_PATTERN",_GUARDED_PATTERN;
+"_MATCH",_MATCH;
+"_SEQPATTERN",_SEQPATTERN;
+"_UNGUARDED_PATTERN",_UNGUARDED_PATTERN;
+"absolutely_integrable_on",absolutely_integrable_on;
+"absolutely_real_integrable_on",absolutely_real_integrable_on;
+"acs",acs;
+"add_c",add_c;
+"adjoint",adjoint;
+"admissible",admissible;
+"aff_dim",aff_dim;
+"affine",affine;
+"affine_dependent",affine_dependent;
+"analytic_on",analytic_on;
+"arc",arc;
+"asn",asn;
+"at",at;
+"at_infinity",at_infinity;
+"at_neginfinity",at_neginfinity;
+"at_posinfinity",at_posinfinity;
+"atn",atn;
+"atreal",atreal;
+"ball",ball;
+"basis",basis;
+"bernstein",bernstein;
+"between",between;
+"bilinear",bilinear;
+"binarysum",binarysum;
+"binom",binom;
+"bitset",bitset;
+"bool_INDUCT",bool_INDUCT;
+"bool_RECURSION",bool_RECURSION;
+"bounded",bounded;
+"cacs",cacs;
+"cart_tybij",cart_tybij;
+"casn",casn;
+"catn",catn;
+"cauchy",cauchy;
+"cball",cball;
+"ccos",ccos;
+"cexp",cexp;
+"chain",chain;
+"char_INDUCT",char_INDUCT;
+"char_RECURSION",char_RECURSION;
+"circlepath",circlepath;
+"clog",clog;
+"closed",closed;
+"closed_in",closed_in;
+"closed_interval",closed_interval;
+"closed_path",closed_path;
+"closed_real_interval",closed_real_interval;
+"closed_real_segment",closed_real_segment;
+"closed_segment",closed_segment;
+"closest_point",closest_point;
+"closure",closure;
+"cnj",cnj;
+"codeset",codeset;
+"cofactor",cofactor;
+"collinear",collinear;
+"column",column;
+"columns",columns;
+"columnvector",columnvector;
+"compact",compact;
+"complete",complete;
+"complex",complex;
+"complex_add",complex_add;
+"complex_derivative",complex_derivative;
+"complex_differentiable",complex_differentiable;
+"complex_div",complex_div;
+"complex_integer",complex_integer;
+"complex_inv",complex_inv;
+"complex_mul",complex_mul;
+"complex_neg",complex_neg;
+"complex_norm",complex_norm;
+"complex_pow",complex_pow;
+"complex_sub",complex_sub;
+"components",components;
+"condensation_point_of",condensation_point_of;
+"cong",cong;
+"conic",conic;
+"connected",connected;
+"connected_component",connected_component;
+"content",content;
+"continuous",continuous;
+"continuous_at",continuous_at;
+"continuous_atreal",continuous_atreal;
+"continuous_on",continuous_on;
+"continuous_within",continuous_within;
+"continuous_withinreal",continuous_withinreal;
+"contractible",contractible;
+"convex",convex;
+"convex_cone",convex_cone;
+"convex_on",convex_on;
+"coplanar",coplanar;
+"cos",cos;
+"covering_space",covering_space;
+"cpow",cpow;
+"cproduct",cproduct;
+"csin",csin;
+"csqrt",csqrt;
+"ctan",ctan;
+"dependent",dependent;
+"dest_int_rep",dest_int_rep;
+"det",det;
+"diagonal_matrix",diagonal_matrix;
+"diameter",diameter;
+"differentiable",differentiable;
+"differentiable_on",differentiable_on;
+"dim",dim;
+"dimindex",dimindex;
+"dist",dist;
+"division_of",division_of;
+"division_points",division_points;
+"dot",dot;
+"drop",drop;
+"dropout",dropout;
+"edge_of",edge_of;
+"epigraph",epigraph;
+"eq_c",eq_c;
+"equiintegrable_on",equiintegrable_on;
+"euclidean",euclidean;
+"euclideanreal",euclideanreal;
+"evenperm",evenperm;
+"eventually",eventually;
+"exp",exp;
+"exposed_face_of",exposed_face_of;
+"extreme_point_of",extreme_point_of;
+"face_of",face_of;
+"facet_of",facet_of;
+"fine",fine;
+"finite_image_tybij",finite_image_tybij;
+"finite_index",finite_index;
+"finite_sum_tybij",finite_sum_tybij;
+"fl",fl;
+"frechet_derivative",frechet_derivative;
+"from",from;
+"frontier",frontier;
+"fstcart",fstcart;
+"gauge",gauge;
+"ge_c",ge_c;
+"geom_mul",geom_mul;
+"grade",grade;
+"gt_c",gt_c;
+"has_bounded_real_variation_on",has_bounded_real_variation_on;
+"has_bounded_setvariation_on",has_bounded_setvariation_on;
+"has_bounded_variation_on",has_bounded_variation_on;
+"has_complex_derivative",has_complex_derivative;
+"has_derivative",has_derivative;
+"has_derivative_at",has_derivative_at;
+"has_derivative_within",has_derivative_within;
+"has_integral",has_integral;
+"has_integral_alt",has_integral_alt;
+"has_integral_compact_interval",has_integral_compact_interval;
+"has_integral_def",has_integral_def;
+"has_measure",has_measure;
+"has_path_integral",has_path_integral;
+"has_real_derivative",has_real_derivative;
+"has_real_integral",has_real_integral;
+"has_real_measure",has_real_measure;
+"has_vector_derivative",has_vector_derivative;
+"higher_complex_derivative",higher_complex_derivative;
+"higher_complex_derivative_alt",higher_complex_derivative_alt;
+"higher_real_derivative",higher_real_derivative;
+"holomorphic_on",holomorphic_on;
+"homeomorphic",homeomorphic;
+"homeomorphism",homeomorphism;
+"homotopic_loops",homotopic_loops;
+"homotopic_paths",homotopic_paths;
+"homotopic_with",homotopic_with;
+"homotopy_equivalent",homotopy_equivalent;
+"hreal_add",hreal_add;
+"hreal_add_th",hreal_add_th;
+"hreal_inv",hreal_inv;
+"hreal_inv_th",hreal_inv_th;
+"hreal_le",hreal_le;
+"hreal_le_th",hreal_le_th;
+"hreal_mul",hreal_mul;
+"hreal_mul_th",hreal_mul_th;
+"hreal_of_num",hreal_of_num;
+"hreal_of_num_th",hreal_of_num_th;
+"hull",hull;
+"ii",ii;
+"in_direction",in_direction;
+"independent",independent;
+"indicator",indicator;
+"inf",inf;
+"infnorm",infnorm;
+"infsum",infsum;
+"inner",inner;
+"inseg",inseg;
+"inside",inside;
+"int_abs",int_abs;
+"int_abs_th",int_abs_th;
+"int_abstr",int_abstr;
+"int_add",int_add;
+"int_add_th",int_add_th;
+"int_congruent",int_congruent;
+"int_coprime",int_coprime;
+"int_divides",int_divides;
+"int_eq",int_eq;
+"int_gcd",int_gcd;
+"int_ge",int_ge;
+"int_gt",int_gt;
+"int_le",int_le;
+"int_lt",int_lt;
+"int_max",int_max;
+"int_max_th",int_max_th;
+"int_min",int_min;
+"int_min_th",int_min_th;
+"int_mod",int_mod;
+"int_mul",int_mul;
+"int_mul_th",int_mul_th;
+"int_neg",int_neg;
+"int_neg_th",int_neg_th;
+"int_of_num",int_of_num;
+"int_of_num_th",int_of_num_th;
+"int_pow",int_pow;
+"int_pow_th",int_pow_th;
+"int_rep",int_rep;
+"int_sgn",int_sgn;
+"int_sgn_th",int_sgn_th;
+"int_sub",int_sub;
+"int_sub_th",int_sub_th;
+"int_tybij",int_tybij;
+"integer",integer;
+"integrable_on",integrable_on;
+"integral",integral;
+"interior",interior;
+"interval",interval;
+"interval_bij",interval_bij;
+"interval_lowerbound",interval_lowerbound;
+"interval_upperbound",interval_upperbound;
+"inverse",inverse;
+"invertible",invertible;
+"is_int",is_int;
+"is_interval",is_interval;
+"is_nadd",is_nadd;
+"is_nadd_0",is_nadd_0;
+"is_realinterval",is_realinterval;
+"istopology",istopology;
+"iterate",iterate;
+"jacobian",jacobian;
+"joinpaths",joinpaths;
+"kle",kle;
+"ksimplex",ksimplex;
+"lambda",lambda;
+"lambdas",lambdas;
+"le_c",le_c;
+"lebesgue_measurable",lebesgue_measurable;
+"lemma",lemma;
+"less",less;
+"lift",lift;
+"lifted",lifted;
+"lim",lim;
+"limit_point_of",limit_point_of;
+"linear",linear;
+"linepath",linepath;
+"linseg",linseg;
+"list_CASES",list_CASES;
+"list_INDUCT",list_INDUCT;
+"list_RECURSION",list_RECURSION;
+"list_of_set",list_of_set;
+"locally",locally;
+"log_def",log_def;
+"lt_c",lt_c;
+"mat",mat;
+"matrix",matrix;
+"matrix_add",matrix_add;
+"matrix_cmul",matrix_cmul;
+"matrix_inv",matrix_inv;
+"matrix_mul",matrix_mul;
+"matrix_neg",matrix_neg;
+"matrix_sub",matrix_sub;
+"matrix_vector_mul",matrix_vector_mul;
+"mbasis",mbasis;
+"measurable",measurable;
+"measurable_on",measurable_on;
+"measure",measure;
+"midpoint",midpoint;
+"minimal",minimal;
+"mk_pair_def",mk_pair_def;
+"moebius_function",moebius_function;
+"monoidal",monoidal;
+"mul_c",mul_c;
+"multivec",multivec;
+"multivector",multivector;
+"multivector_tybij",multivector_tybij;
+"multivector_tybij_th",multivector_tybij_th;
+"nadd_abs",nadd_abs;
+"nadd_add",nadd_add;
+"nadd_eq",nadd_eq;
+"nadd_inv",nadd_inv;
+"nadd_le",nadd_le;
+"nadd_mul",nadd_mul;
+"nadd_of_num",nadd_of_num;
+"nadd_rep",nadd_rep;
+"nadd_rinv",nadd_rinv;
+"negligible",negligible;
+"net_tybij",net_tybij;
+"netlimit",netlimit;
+"neutral",neutral;
+"nsum",nsum;
+"num_Axiom",num_Axiom;
+"num_CASES",num_CASES;
+"num_FINITE",num_FINITE;
+"num_FINITE_AVOID",num_FINITE_AVOID;
+"num_INDUCTION",num_INDUCTION;
+"num_INFINITE",num_INFINITE;
+"num_MAX",num_MAX;
+"num_RECURSION",num_RECURSION;
+"num_RECURSION_STD",num_RECURSION_STD;
+"num_WF",num_WF;
+"num_WOP",num_WOP;
+"num_congruent",num_congruent;
+"num_coprime",num_coprime;
+"num_divides",num_divides;
+"num_gcd",num_gcd;
+"num_mod",num_mod;
+"num_of_int",num_of_int;
+"numseg",numseg;
+"o_ASSOC",o_ASSOC;
+"o_DEF",o_DEF;
+"o_THM",o_THM;
+"one",one;
+"one_Axiom",one_Axiom;
+"one_DEF",one_DEF;
+"one_INDUCT",one_INDUCT;
+"one_RECURSION",one_RECURSION;
+"one_axiom",one_axiom;
+"one_tydef",one_tydef;
+"onorm",onorm;
+"open_def",open_def;
+"open_in",open_in;
+"open_interval",open_interval;
+"open_real_interval",open_real_interval;
+"open_real_segment",open_real_segment;
+"open_segment",open_segment;
+"operative",operative;
+"option_INDUCT",option_INDUCT;
+"option_RECURSION",option_RECURSION;
+"ordinal",ordinal;
+"orthogonal",orthogonal;
+"orthogonal_matrix",orthogonal_matrix;
+"orthogonal_transformation",orthogonal_transformation;
+"outer",outer;
+"outermorphism",outermorphism;
+"outside",outside;
+"pair_INDUCT",pair_INDUCT;
+"pair_RECURSION",pair_RECURSION;
+"pairwise",pairwise;
+"partcirclepath",partcirclepath;
+"pastecart",pastecart;
+"path",path;
+"path_component",path_component;
+"path_connected",path_connected;
+"path_image",path_image;
+"path_integrable_on",path_integrable_on;
+"path_integral",path_integral;
+"path_length",path_length;
+"pathfinish",pathfinish;
+"pathstart",pathstart;
+"permutation",permutation;
+"permutes",permutes;
+"pi",pi;
+"piecewise_differentiable_on",piecewise_differentiable_on;
+"polyhedron",polyhedron;
+"polytope",polytope;
+"poset",poset;
+"prod_tybij",prod_tybij;
+"product",product;
+"pushin",pushin;
+"rank",rank;
+"rational",rational;
+"real",real;
+"real_INFINITE",real_INFINITE;
+"real_abs",real_abs;
+"real_add",real_add;
+"real_add_th",real_add_th;
+"real_bounded",real_bounded;
+"real_closed",real_closed;
+"real_compact",real_compact;
+"real_continuous",real_continuous;
+"real_continuous_at",real_continuous_at;
+"real_continuous_atreal",real_continuous_atreal;
+"real_continuous_on",real_continuous_on;
+"real_continuous_within",real_continuous_within;
+"real_continuous_withinreal",real_continuous_withinreal;
+"real_convex_on",real_convex_on;
+"real_derivative",real_derivative;
+"real_differentiable",real_differentiable;
+"real_differentiable_on",real_differentiable_on;
+"real_div",real_div;
+"real_ge",real_ge;
+"real_gt",real_gt;
+"real_infsum",real_infsum;
+"real_integrable_on",real_integrable_on;
+"real_integral",real_integral;
+"real_interval",real_interval;
+"real_inv",real_inv;
+"real_inv_th",real_inv_th;
+"real_le",real_le;
+"real_le_th",real_le_th;
+"real_lebesgue_measurable",real_lebesgue_measurable;
+"real_lt",real_lt;
+"real_max",real_max;
+"real_measurable",real_measurable;
+"real_measurable_on",real_measurable_on;
+"real_measure",real_measure;
+"real_min",real_min;
+"real_mod",real_mod;
+"real_mul",real_mul;
+"real_mul_th",real_mul_th;
+"real_neg",real_neg;
+"real_neg_th",real_neg_th;
+"real_negligible",real_negligible;
+"real_of_num",real_of_num;
+"real_of_num_th",real_of_num_th;
+"real_open",real_open;
+"real_polynomial_function_CASES",real_polynomial_function_CASES;
+"real_polynomial_function_INDUCT",real_polynomial_function_INDUCT;
+"real_polynomial_function_RULES",real_polynomial_function_RULES;
+"real_pow",real_pow;
+"real_segment",real_segment;
+"real_sgn",real_sgn;
+"real_sub",real_sub;
+"real_summable",real_summable;
+"real_sums",real_sums;
+"real_uniformly_continuous_on",real_uniformly_continuous_on;
+"real_variation",real_variation;
+"reallim",reallim;
+"rectifiable_path",rectifiable_path;
+"reduced",reduced;
+"reflect_along",reflect_along;
+"relative_frontier",relative_frontier;
+"relative_interior",relative_interior;
+"retract_of",retract_of;
+"retraction",retraction;
+"reversepath",reversepath;
+"reversion",reversion;
+"root",root;
+"rotate2d",rotate2d;
+"rotation_matrix",rotation_matrix;
+"rotoinversion_matrix",rotoinversion_matrix;
+"row",row;
+"rows",rows;
+"rowvector",rowvector;
+"rpow",rpow;
+"segment",segment;
+"seqiterate",seqiterate;
+"seqiterate_EXISTS",seqiterate_EXISTS;
+"sequentially",sequentially;
+"set_of_list",set_of_list;
+"set_variation",set_variation;
+"setcode",setcode;
+"setdist",setdist;
+"shiftpath",shiftpath;
+"sign",sign;
+"simple_path",simple_path;
+"simplex",simplex;
+"simplicial_complex",simplicial_complex;
+"simply_connected",simply_connected;
+"sin",sin;
+"sindex",sindex;
+"slice",slice;
+"sndcart",sndcart;
+"span",span;
+"sphere",sphere;
+"sqrt",sqrt;
+"starlike",starlike;
+"string_INFINITE",string_INFINITE;
+"subpath",subpath;
+"subspace",subspace;
+"subtopology",subtopology;
+"sum",sum;
+"sum_CASES",sum_CASES;
+"sum_DISTINCT",sum_DISTINCT;
+"sum_INDUCT",sum_INDUCT;
+"sum_INJECTIVE",sum_INJECTIVE;
+"sum_RECURSION",sum_RECURSION;
+"summable",summable;
+"sums",sums;
+"sup",sup;
+"superadmissible",superadmissible;
+"support",support;
+"swap",swap;
+"swapseq_CASES",swapseq_CASES;
+"swapseq_INDUCT",swapseq_INDUCT;
+"swapseq_RULES",swapseq_RULES;
+"tagged_division_of",tagged_division_of;
+"tagged_partial_division_of",tagged_partial_division_of;
+"tailadmissible",tailadmissible;
+"tan",tan;
+"tan_def",tan_def;
+"tendsto",tendsto;
+"tendsto_real",tendsto_real;
+"topology_tybij",topology_tybij;
+"topology_tybij_th",topology_tybij_th;
+"topspace",topspace;
+"toset",toset;
+"trace",trace;
+"transp",transp;
+"treal_add",treal_add;
+"treal_eq",treal_eq;
+"treal_inv",treal_inv;
+"treal_le",treal_le;
+"treal_mul",treal_mul;
+"treal_neg",treal_neg;
+"treal_of_num",treal_of_num;
+"triangulation",triangulation;
+"trivial_limit",trivial_limit;
+"uniformly_continuous_on",uniformly_continuous_on;
+"unwinding",unwinding;
+"valid_path",valid_path;
+"vec",vec;
+"vector",vector;
+"vector_add",vector_add;
+"vector_derivative",vector_derivative;
+"vector_matrix_mul",vector_matrix_mul;
+"vector_mul",vector_mul;
+"vector_neg",vector_neg;
+"vector_norm",vector_norm;
+"vector_polynomial_function",vector_polynomial_function;
+"vector_sub",vector_sub;
+"vector_variation",vector_variation;
+"vsum",vsum;
+"winding_number",winding_number;
+"within",within;
+"woset",woset
+];;
diff --git a/Multivariate/complexes.ml b/Multivariate/complexes.ml
new file mode 100644 (file)
index 0000000..615b0df
--- /dev/null
@@ -0,0 +1,1944 @@
+(* ========================================================================= *)
+(* The type "real^2" regarded as the complex numbers.                        *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(*              (c) Copyright, Valentina Bruno 2010                          *)
+(* ========================================================================= *)
+
+needs "Multivariate/integration.ml";;
+
+new_type_abbrev("complex",`:real^2`);;
+
+let prioritize_complex() =
+  overload_interface("--",`vector_neg:complex->complex`);
+  overload_interface("+",`vector_add:complex->complex->complex`);
+  overload_interface("-",`vector_sub:complex->complex->complex`);
+  overload_interface("*",`complex_mul:complex->complex->complex`);
+  overload_interface("/",`complex_div:complex->complex->complex`);
+  overload_interface("pow",`complex_pow:complex->num->complex`);
+  overload_interface("inv",`complex_inv:complex->complex`);;
+
+prioritize_complex();;
+
+(* ------------------------------------------------------------------------- *)
+(* Real and imaginary parts of a number.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let RE_DEF = new_definition
+  `Re(z:complex) = z$1`;;
+
+let IM_DEF = new_definition
+  `Im(z:complex) = z$2`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Real injection and imaginary unit.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let complex = new_definition
+ `complex(x,y) = vector[x;y]:complex`;;
+
+let CX_DEF = new_definition
+ `Cx(a) = complex(a,&0)`;;
+
+let ii = new_definition
+  `ii = complex(&0,&1)`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex multiplication.                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let complex_mul = new_definition
+  `w * z = complex(Re(w) * Re(z) - Im(w) * Im(z),
+                   Re(w) * Im(z) + Im(w) * Re(z))`;;
+
+let complex_inv = new_definition
+  `inv(z) = complex(Re(z) / (Re(z) pow 2 + Im(z) pow 2),
+                    --(Im(z)) / (Re(z) pow 2 + Im(z) pow 2))`;;
+
+let complex_div = new_definition
+  `w / z = w * inv(z)`;;
+
+let complex_pow = define
+  `(x pow 0 = Cx(&1)) /\
+   (!n. x pow (SUC n) = x * x pow n)`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Various handy rewrites.                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let RE = prove
+ (`(Re(complex(x,y)) = x)`,
+  REWRITE_TAC[RE_DEF; complex; VECTOR_2]);;
+
+let IM = prove
+ (`Im(complex(x,y)) = y`,
+  REWRITE_TAC[IM_DEF; complex; VECTOR_2]);;
+
+let COMPLEX_EQ = prove
+ (`!w z. (w = z) <=> (Re(w) = Re(z)) /\ (Im(w) = Im(z))`,
+  SIMP_TAC[CART_EQ; FORALL_2; DIMINDEX_2; RE_DEF; IM_DEF]);;
+
+let COMPLEX = prove
+ (`!z. complex(Re(z),Im(z)) = z`,
+  REWRITE_TAC[COMPLEX_EQ; RE; IM]);;
+
+let COMPLEX_EQ_0 = prove
+ (`z = Cx(&0) <=> Re(z) pow 2 + Im(z) pow 2 = &0`,
+  REWRITE_TAC[COMPLEX_EQ; CX_DEF; RE; IM] THEN
+  EQ_TAC THEN SIMP_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+   `!x y:real. x + y = &0 ==> &0 <= x /\ &0 <= y ==> x = &0 /\ y = &0`)) THEN
+  REWRITE_TAC[REAL_POW_2; REAL_LE_SQUARE; REAL_ENTIRE]);;
+
+let FORALL_COMPLEX = prove
+ (`(!z. P z) <=> (!x y. P(complex(x,y)))`,
+  MESON_TAC[COMPLEX]);;
+
+let EXISTS_COMPLEX = prove
+ (`(?z. P z) <=> (?x y. P(complex(x,y)))`,
+  MESON_TAC[COMPLEX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Pseudo-definitions of other general vector concepts over R^2.             *)
+(* ------------------------------------------------------------------------- *)
+
+let complex_neg = prove
+ (`--z = complex(--(Re(z)),--(Im(z)))`,
+  REWRITE_TAC[COMPLEX_EQ; RE; IM] THEN REWRITE_TAC[RE_DEF; IM_DEF] THEN
+  SIMP_TAC[VECTOR_NEG_COMPONENT; DIMINDEX_2; ARITH]);;
+
+let complex_add = prove
+ (`w + z = complex(Re(w) + Re(z),Im(w) + Im(z))`,
+  REWRITE_TAC[COMPLEX_EQ; RE; IM] THEN REWRITE_TAC[RE_DEF; IM_DEF] THEN
+  SIMP_TAC[VECTOR_ADD_COMPONENT; DIMINDEX_2; ARITH]);;
+
+let complex_sub = VECTOR_ARITH `(w:complex) - z = w + --z`;;
+
+let complex_norm = prove
+ (`norm(z) = sqrt(Re(z) pow 2 + Im(z) pow 2)`,
+  REWRITE_TAC[vector_norm; dot; RE_DEF; IM_DEF; SUM_2; DIMINDEX_2] THEN
+  AP_TERM_TAC THEN REAL_ARITH_TAC);;
+
+let COMPLEX_SQNORM = prove
+ (`norm(z) pow 2 = Re(z) pow 2 + Im(z) pow 2`,
+  REWRITE_TAC[NORM_POW_2; dot; RE_DEF; IM_DEF; SUM_2; DIMINDEX_2] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Crude tactic to automate very simple algebraic equivalences.              *)
+(* ------------------------------------------------------------------------- *)
+
+let SIMPLE_COMPLEX_ARITH_TAC =
+  REWRITE_TAC[COMPLEX_EQ; RE; IM; CX_DEF;
+              complex_add; complex_neg; complex_sub; complex_mul;
+              complex_inv; complex_div] THEN
+  CONV_TAC REAL_FIELD;;
+
+let SIMPLE_COMPLEX_ARITH tm = prove(tm,SIMPLE_COMPLEX_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic algebraic properties that can be proved automatically by this.      *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_ADD_SYM = prove
+ (`!x y. x + y = y + x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_ADD_ASSOC = prove
+ (`!x y z. x + y + z = (x + y) + z`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_ADD_LID = prove
+ (`!x. Cx(&0) + x = x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_ADD_LINV = prove
+ (`!x. --x + x = Cx(&0)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_MUL_SYM = prove
+ (`!x y. x * y = y * x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_MUL_ASSOC = prove
+ (`!x y z. x * y * z = (x * y) * z`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_MUL_LID = prove
+ (`!x. Cx(&1) * x = x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_ADD_LDISTRIB = prove
+ (`!x y z. x * (y + z) = x * y + x * z`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_ADD_AC = prove
+ (`(m + n = n + m) /\ ((m + n) + p = m + n + p) /\ (m + n + p = n + m + p)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_MUL_AC = prove
+ (`(m * n = n * m) /\ ((m * n) * p = m * n * p) /\ (m * n * p = n * m * p)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_ADD_RID = prove
+ (`!x. x + Cx(&0) = x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_MUL_RID = prove
+ (`!x. x * Cx(&1) = x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_ADD_RINV = prove
+ (`!x. x + --x = Cx(&0)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_ADD_RDISTRIB = prove
+ (`!x y z. (x + y) * z = x * z + y * z`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_EQ_ADD_LCANCEL = prove
+ (`!x y z. (x + y = x + z) <=> (y = z)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_EQ_ADD_RCANCEL = prove
+ (`!x y z. (x + z = y + z) <=> (x = y)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_MUL_RZERO = prove
+ (`!x. x * Cx(&0) = Cx(&0)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_MUL_LZERO = prove
+ (`!x. Cx(&0) * x = Cx(&0)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_NEG_NEG = prove
+ (`!x. --(--x) = x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_MUL_RNEG = prove
+ (`!x y. x * --y = --(x * y)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_MUL_LNEG = prove
+ (`!x y. --x * y = --(x * y)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_NEG_ADD = prove
+ (`!x y. --(x + y) = --x + --y`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_NEG_0 = prove
+ (`--Cx(&0) = Cx(&0)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_EQ_ADD_LCANCEL_0 = prove
+ (`!x y. (x + y = x) <=> (y = Cx(&0))`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_EQ_ADD_RCANCEL_0 = prove
+ (`!x y. (x + y = y) <=> (x = Cx(&0))`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_LNEG_UNIQ = prove
+ (`!x y. (x + y = Cx(&0)) <=> (x = --y)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_RNEG_UNIQ = prove
+ (`!x y. (x + y = Cx(&0)) <=> (y = --x)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_NEG_LMUL = prove
+ (`!x y. --(x * y) = --x * y`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_NEG_RMUL = prove
+ (`!x y. --(x * y) = x * --y`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_NEG_MUL2 = prove
+ (`!x y. --x * --y = x * y`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_ADD = prove
+ (`!x y. x - y + y = x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_ADD2 = prove
+ (`!x y. y + x - y = x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_REFL = prove
+ (`!x. x - x = Cx(&0)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_0 = prove
+ (`!x y. (x - y = Cx(&0)) <=> (x = y)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_NEG_EQ_0 = prove
+ (`!x. (--x = Cx(&0)) <=> (x = Cx(&0))`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_NEG_SUB = prove
+ (`!x y. --(x - y) = y - x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_ADD_SUB = prove
+ (`!x y. (x + y) - x = y`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_NEG_EQ = prove
+ (`!x y. (--x = y) <=> (x = --y)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_NEG_MINUS1 = prove
+ (`!x. --x = --Cx(&1) * x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_SUB = prove
+ (`!x y. x - y - x = --y`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_ADD2_SUB2 = prove
+ (`!a b c d. (a + b) - (c + d) = a - c + b - d`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_LZERO = prove
+ (`!x. Cx(&0) - x = --x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_RZERO = prove
+ (`!x. x - Cx(&0) = x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_LNEG = prove
+ (`!x y. --x - y = --(x + y)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_RNEG = prove
+ (`!x y. x - --y = x + y`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_NEG2 = prove
+ (`!x y. --x - --y = y - x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_TRIANGLE = prove
+ (`!a b c. a - b + b - c = a - c`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_EQ_SUB_LADD = prove
+ (`!x y z. (x = y - z) <=> (x + z = y)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_EQ_SUB_RADD = prove
+ (`!x y z. (x - y = z) <=> (x = z + y)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_SUB2 = prove
+ (`!x y. x - (x - y) = y`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_ADD_SUB2 = prove
+ (`!x y. x - (x + y) = --y`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_DIFFSQ = prove
+ (`!x y. (x + y) * (x - y) = x * x - y * y`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_EQ_NEG2 = prove
+ (`!x y. (--x = --y) <=> (x = y)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_LDISTRIB = prove
+ (`!x y z. x * (y - z) = x * y - x * z`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_SUB_RDISTRIB = prove
+ (`!x y z. (x - y) * z = x * z - y * z`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_MUL_2 = prove
+ (`!x. Cx(&2) * x = x + x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Sometimes here we need to tweak non-zeroness assertions.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let II_NZ = prove
+ (`~(ii = Cx(&0))`,
+  REWRITE_TAC[ii] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_MUL_LINV = prove
+ (`!z. ~(z = Cx(&0)) ==> (inv(z) * z = Cx(&1))`,
+  REWRITE_TAC[COMPLEX_EQ_0] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_ENTIRE = prove
+ (`!x y. (x * y = Cx(&0)) <=> (x = Cx(&0)) \/ (y = Cx(&0))`,
+  REWRITE_TAC[COMPLEX_EQ_0] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_MUL_RINV = prove
+ (`!z. ~(z = Cx(&0)) ==> (z * inv(z) = Cx(&1))`,
+  REWRITE_TAC[COMPLEX_EQ_0] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_DIV_REFL = prove
+ (`!x. ~(x = Cx(&0)) ==> (x / x = Cx(&1))`,
+  REWRITE_TAC[COMPLEX_EQ_0] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homomorphic embedding properties for Cx mapping.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let CX_INJ = prove
+ (`!x y. (Cx(x) = Cx(y)) <=> (x = y)`,
+  REWRITE_TAC[CX_DEF; COMPLEX_EQ; RE; IM]);;
+
+let CX_NEG = prove
+ (`!x. Cx(--x) = --(Cx(x))`,
+  REWRITE_TAC[CX_DEF; complex_neg; RE; IM; REAL_NEG_0]);;
+
+let CX_ADD = prove
+ (`!x y. Cx(x + y) = Cx(x) + Cx(y)`,
+  REWRITE_TAC[CX_DEF; complex_add; RE; IM; REAL_ADD_LID]);;
+
+let CX_SUB = prove
+ (`!x y. Cx(x - y) = Cx(x) - Cx(y)`,
+  REWRITE_TAC[complex_sub; real_sub; CX_ADD; CX_NEG]);;
+
+let CX_INV = prove
+ (`!x. Cx(inv x) = inv(Cx x)`,
+  GEN_TAC THEN REWRITE_TAC[CX_DEF; complex_inv; RE; IM; COMPLEX_EQ] THEN
+  ASM_CASES_TAC `x = &0` THEN ASM_REWRITE_TAC[] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  POP_ASSUM MP_TAC THEN CONV_TAC REAL_FIELD);;
+
+let CX_MUL = prove
+ (`!x y. Cx(x * y) = Cx(x) * Cx(y)`,
+  REWRITE_TAC[CX_DEF; complex_mul; RE; IM; REAL_MUL_LZERO; REAL_MUL_RZERO] THEN
+  REWRITE_TAC[REAL_SUB_RZERO; REAL_ADD_RID]);;
+
+let CX_POW = prove
+ (`!x n. Cx(x pow n) = Cx(x) pow n`,
+  GEN_TAC THEN INDUCT_TAC THEN
+  ASM_REWRITE_TAC[complex_pow; real_pow; CX_MUL]);;
+
+let CX_DIV = prove
+ (`!x y. Cx(x / y) = Cx(x) / Cx(y)`,
+  REWRITE_TAC[complex_div; real_div; CX_MUL; CX_INV]);;
+
+let CX_ABS = prove
+ (`!x. Cx(abs x) = Cx(norm(Cx(x)))`,
+  REWRITE_TAC[CX_DEF; complex_norm; COMPLEX_EQ; RE; IM] THEN
+  REWRITE_TAC[REAL_POW_2; REAL_MUL_LZERO; REAL_ADD_RID] THEN
+  REWRITE_TAC[GSYM REAL_POW_2; POW_2_SQRT_ABS]);;
+
+let COMPLEX_NORM_CX = prove
+ (`!x. norm(Cx(x)) = abs(x)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_ABS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some "linear" things hold for Re and Im too.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let RE_CX = prove
+ (`!x. Re(Cx x) = x`,
+  REWRITE_TAC[RE; CX_DEF]);;
+
+let RE_NEG = prove
+ (`!x. Re(--x) = --Re(x)`,
+  REWRITE_TAC[complex_neg; RE]);;
+
+let RE_ADD = prove
+ (`!x y. Re(x + y) = Re(x) + Re(y)`,
+  REWRITE_TAC[complex_add; RE]);;
+
+let RE_SUB = prove
+ (`!x y. Re(x - y) = Re(x) - Re(y)`,
+  REWRITE_TAC[complex_sub; real_sub; RE_ADD; RE_NEG]);;
+
+let IM_CX = prove
+ (`!x. Im(Cx x) = &0`,
+  REWRITE_TAC[IM; CX_DEF]);;
+
+let IM_NEG = prove
+ (`!x. Im(--x) = --Im(x)`,
+  REWRITE_TAC[complex_neg; IM]);;
+
+let IM_ADD = prove
+ (`!x y. Im(x + y) = Im(x) + Im(y)`,
+  REWRITE_TAC[complex_add; IM]);;
+
+let IM_SUB = prove
+ (`!x y. Im(x - y) = Im(x) - Im(y)`,
+  REWRITE_TAC[complex_sub; real_sub; IM_ADD; IM_NEG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* An "expansion" theorem into the traditional notation.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_EXPAND = prove
+ (`!z. z = Cx(Re z) + ii * Cx(Im z)`,
+  REWRITE_TAC[ii] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_TRAD = prove
+ (`!x y. complex(x,y) = Cx(x) + ii * Cx(y)`,
+  REWRITE_TAC[ii] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real and complex parts of ii and multiples.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let RE_II = prove
+ (`Re ii = &0`,
+  REWRITE_TAC[ii] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+let IM_II = prove
+ (`Im ii = &1`,
+  REWRITE_TAC[ii] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+let RE_MUL_II = prove
+ (`!z. Re(z * ii) = --(Im z) /\ Re(ii * z) = --(Im z)`,
+  REWRITE_TAC[ii] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+let IM_MUL_II = prove
+ (`!z. Im(z * ii) = Re z /\ Im(ii * z) = Re z`,
+  REWRITE_TAC[ii] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_NORM_II = prove
+ (`norm ii = &1`,
+  REWRITE_TAC[complex_norm; RE_II; IM_II] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[SQRT_1]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Limited "multiplicative" theorems for Re and Im.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let RE_CMUL = prove
+ (`!a z. Re(a % z) = a * Re z`,
+  SIMP_TAC[RE_DEF; VECTOR_MUL_COMPONENT; DIMINDEX_2; ARITH]);;
+
+let IM_CMUL = prove
+ (`!a z. Im(a % z) = a * Im z`,
+  SIMP_TAC[IM_DEF; VECTOR_MUL_COMPONENT; DIMINDEX_2; ARITH]);;
+
+let RE_MUL_CX = prove
+ (`!x z. Re(Cx(x) * z) = x * Re z /\
+         Re(z * Cx(x)) = Re z * x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let IM_MUL_CX = prove
+ (`!x z. Im(Cx(x) * z) = x * Im z /\
+         Im(z * Cx(x)) = Im z * x`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let RE_DIV_CX = prove
+ (`!z x. Re(z / Cx(x)) = Re(z) / x`,
+  REWRITE_TAC[complex_div; real_div; GSYM CX_INV; RE_MUL_CX]);;
+
+let IM_DIV_CX = prove
+ (`!z x. Im(z / Cx(x)) = Im(z) / x`,
+  REWRITE_TAC[complex_div; real_div; GSYM CX_INV; IM_MUL_CX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Syntax constructors etc. for complex constants.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let is_complex_const =
+  let cx_tm = `Cx` in
+  fun tm ->
+    is_comb tm &
+    let l,r = dest_comb tm in l = cx_tm & is_ratconst r;;
+
+let dest_complex_const =
+  let cx_tm = `Cx` in
+  fun tm ->
+    let l,r = dest_comb tm in
+    if l = cx_tm then rat_of_term r
+    else failwith "dest_complex_const";;
+
+let mk_complex_const =
+  let cx_tm = `Cx` in
+  fun r ->
+    mk_comb(cx_tm,term_of_rat r);;
+
+(* ------------------------------------------------------------------------- *)
+(* Conversions for arithmetic on complex constants.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_RAT_EQ_CONV =
+  GEN_REWRITE_CONV I [CX_INJ] THENC REAL_RAT_EQ_CONV;;
+
+let COMPLEX_RAT_MUL_CONV =
+  GEN_REWRITE_CONV I [GSYM CX_MUL] THENC RAND_CONV REAL_RAT_MUL_CONV;;
+
+let COMPLEX_RAT_ADD_CONV =
+  GEN_REWRITE_CONV I [GSYM CX_ADD] THENC RAND_CONV REAL_RAT_ADD_CONV;;
+
+let COMPLEX_RAT_POW_CONV =
+  let x_tm = `x:real`
+  and n_tm = `n:num` in
+  let pth = SYM(SPECL [x_tm; n_tm] CX_POW) in
+  fun tm ->
+    let lop,r = dest_comb tm in
+    let op,bod = dest_comb lop in
+    let th1 = INST [rand bod,x_tm; r,n_tm] pth in
+    let tm1,tm2 = dest_comb(concl th1) in
+    if rand tm1 <> tm then failwith "COMPLEX_RAT_POW_CONV" else
+    let tm3,tm4 = dest_comb tm2 in
+    TRANS th1 (AP_TERM tm3 (REAL_RAT_REDUCE_CONV tm4));;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex polynomial normalizer.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_POLY_CLAUSES = prove
+ (`(!x y z. x + (y + z) = (x + y) + z) /\
+   (!x y. x + y = y + x) /\
+   (!x. Cx(&0) + x = x) /\
+   (!x y z. x * (y * z) = (x * y) * z) /\
+   (!x y. x * y = y * x) /\
+   (!x. Cx(&1) * x = x) /\
+   (!x. Cx(&0) * x = Cx(&0)) /\
+   (!x y z. x * (y + z) = x * y + x * z) /\
+   (!x. x pow 0 = Cx(&1)) /\
+   (!x n. x pow (SUC n) = x * x pow n)`,
+  REWRITE_TAC[complex_pow] THEN SIMPLE_COMPLEX_ARITH_TAC)
+and COMPLEX_POLY_NEG_CLAUSES = prove
+ (`(!x. --x = Cx(-- &1) * x) /\
+   (!x y. x - y = x + Cx(-- &1) * y)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_POLY_NEG_CONV,COMPLEX_POLY_ADD_CONV,COMPLEX_POLY_SUB_CONV,
+    COMPLEX_POLY_MUL_CONV,COMPLEX_POLY_POW_CONV,COMPLEX_POLY_CONV =
+  SEMIRING_NORMALIZERS_CONV COMPLEX_POLY_CLAUSES COMPLEX_POLY_NEG_CLAUSES
+   (is_complex_const,
+    COMPLEX_RAT_ADD_CONV,COMPLEX_RAT_MUL_CONV,COMPLEX_RAT_POW_CONV)
+   (<);;
+
+(* ------------------------------------------------------------------------- *)
+(* Extend it to handle "inv" and division, by constants after normalization. *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_RAT_INV_CONV =
+  REWR_CONV(GSYM CX_INV) THENC RAND_CONV REAL_RAT_INV_CONV;;
+
+let COMPLEX_POLY_CONV =
+  let neg_tm = `(--):complex->complex`
+  and inv_tm = `inv:complex->complex`
+  and add_tm = `(+):complex->complex->complex`
+  and sub_tm = `(-):complex->complex->complex`
+  and mul_tm = `(*):complex->complex->complex`
+  and div_tm = `(/):complex->complex->complex`
+  and pow_tm = `(pow):complex->num->complex`
+  and div_conv = REWR_CONV complex_div in
+  let rec COMPLEX_POLY_CONV tm =
+    if not(is_comb tm) or is_ratconst tm then REFL tm else
+    let lop,r = dest_comb tm in
+    if lop = neg_tm then
+      let th1 = AP_TERM lop (COMPLEX_POLY_CONV r) in
+      TRANS th1 (COMPLEX_POLY_NEG_CONV (rand(concl th1)))
+    else if lop = inv_tm then
+      let th1 = AP_TERM lop (COMPLEX_POLY_CONV r) in
+      TRANS th1 (TRY_CONV COMPLEX_RAT_INV_CONV (rand(concl th1)))
+    else if not(is_comb lop) then REFL tm else
+    let op,l = dest_comb lop in
+    if op = pow_tm then
+      let th1 = AP_THM (AP_TERM op (COMPLEX_POLY_CONV l)) r in
+      TRANS th1 (TRY_CONV COMPLEX_POLY_POW_CONV (rand(concl th1)))
+    else if op = add_tm or op = mul_tm or op = sub_tm then
+      let th1 = MK_COMB(AP_TERM op (COMPLEX_POLY_CONV l),
+                        COMPLEX_POLY_CONV r) in
+      let fn = if op = add_tm then COMPLEX_POLY_ADD_CONV
+               else if op = mul_tm then COMPLEX_POLY_MUL_CONV
+               else COMPLEX_POLY_SUB_CONV in
+      TRANS th1 (fn (rand(concl th1)))
+    else if op = div_tm then
+      let th1 = div_conv tm in
+      TRANS th1 (COMPLEX_POLY_CONV (rand(concl th1)))
+    else REFL tm in
+  COMPLEX_POLY_CONV;;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex number version of usual ring procedure.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_RING,complex_ideal_cofactors =
+  let COMPLEX_INTEGRAL = prove
+   (`(!x. Cx(&0) * x = Cx(&0)) /\
+     (!x y z. (x + y = x + z) <=> (y = z)) /\
+     (!w x y z. (w * y + x * z = w * z + x * y) <=> (w = x) \/ (y = z))`,
+    REWRITE_TAC[COMPLEX_ENTIRE; SIMPLE_COMPLEX_ARITH
+     `(w * y + x * z = w * z + x * y) <=>
+      (w - x) * (y - z) = Cx(&0)`] THEN
+    SIMPLE_COMPLEX_ARITH_TAC)
+  and COMPLEX_RABINOWITSCH = prove
+   (`!x y:complex. ~(x = y) <=> ?z. (x - y) * z = Cx(&1)`,
+    REPEAT GEN_TAC THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM COMPLEX_SUB_0] THEN
+    MESON_TAC[COMPLEX_MUL_RINV; COMPLEX_MUL_LZERO;
+              SIMPLE_COMPLEX_ARITH `~(Cx(&1) = Cx(&0))`])
+  and COMPLEX_IIII = prove
+   (`ii * ii + Cx(&1) = Cx(&0)`,
+    REWRITE_TAC[ii; CX_DEF; complex_mul; complex_add; RE; IM] THEN
+    AP_TERM_TAC THEN BINOP_TAC THEN REAL_ARITH_TAC) in
+  let ring,ideal =
+    RING_AND_IDEAL_CONV
+        (dest_complex_const,mk_complex_const,COMPLEX_RAT_EQ_CONV,
+         `(--):complex->complex`,`(+):complex->complex->complex`,
+         `(-):complex->complex->complex`,`(inv):complex->complex`,
+         `(*):complex->complex->complex`,`(/):complex->complex->complex`,
+         `(pow):complex->num->complex`,
+         COMPLEX_INTEGRAL,COMPLEX_RABINOWITSCH,COMPLEX_POLY_CONV)
+  and ii_tm = `ii` and iiii_tm = concl COMPLEX_IIII in
+  (fun tm -> if free_in ii_tm tm then
+             MP (ring (mk_imp(iiii_tm,tm))) COMPLEX_IIII
+             else ring tm),
+  ideal;;
+
+(* ------------------------------------------------------------------------- *)
+(* Most basic properties of inverses.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_INV_0 = prove
+ (`inv(Cx(&0)) = Cx(&0)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_INV_1 = prove
+ (`inv(Cx(&1)) = Cx(&1)`,
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let COMPLEX_INV_MUL = prove
+ (`!w z. inv(w * z) = inv(w) * inv(z)`,
+  REPEAT GEN_TAC THEN
+  MAP_EVERY ASM_CASES_TAC [`w = Cx(&0)`; `z = Cx(&0)`] THEN
+  ASM_REWRITE_TAC[COMPLEX_INV_0; COMPLEX_MUL_LZERO; COMPLEX_MUL_RZERO] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[complex_mul; complex_inv; RE; IM; COMPLEX_EQ; CX_DEF] THEN
+  REWRITE_TAC[GSYM REAL_SOS_EQ_0] THEN CONV_TAC REAL_FIELD);;
+
+let COMPLEX_POW_INV = prove
+ (`!x n. (inv x) pow n = inv(x pow n)`,
+  GEN_TAC THEN INDUCT_TAC THEN
+  ASM_REWRITE_TAC[complex_pow; COMPLEX_INV_1; COMPLEX_INV_MUL]);;
+
+let COMPLEX_INV_INV = prove
+ (`!x:complex. inv(inv x) = x`,
+  GEN_TAC THEN ASM_CASES_TAC `x = Cx(&0)` THEN
+  ASM_REWRITE_TAC[COMPLEX_INV_0] THEN
+  POP_ASSUM MP_TAC THEN
+  MAP_EVERY (fun t -> MP_TAC(SPEC t COMPLEX_MUL_RINV))
+   [`x:complex`; `inv(x):complex`] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let COMPLEX_INV_DIV = prove
+ (`!w z:complex. inv(w / z) = z / w`,
+  REWRITE_TAC[complex_div; COMPLEX_INV_MUL; COMPLEX_INV_INV] THEN
+  REWRITE_TAC[COMPLEX_MUL_AC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* And also field procedure.                                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_EQ_MUL_LCANCEL = prove
+ (`!x y z. (x * y = x * z) <=> (x = Cx(&0)) \/ (y = z)`,
+  CONV_TAC COMPLEX_RING);;
+
+let COMPLEX_EQ_MUL_RCANCEL = prove
+ (`!x y z. (x * z = y * z) <=> (x = y) \/ (z = Cx(&0))`,
+  CONV_TAC COMPLEX_RING);;
+
+let COMPLEX_FIELD =
+  let prenex_conv =
+    TOP_DEPTH_CONV BETA_CONV THENC
+    PURE_REWRITE_CONV[FORALL_SIMP; EXISTS_SIMP; complex_div;
+               COMPLEX_INV_INV; COMPLEX_INV_MUL; GSYM COMPLEX_POW_INV] THENC
+    NNFC_CONV THENC DEPTH_BINOP_CONV `(/\)` CONDS_CELIM_CONV THENC
+    PRENEX_CONV
+  and setup_conv = NNF_CONV THENC WEAK_CNF_CONV THENC CONJ_CANON_CONV
+  and is_inv =
+    let inv_tm = `inv:complex->complex`
+    and is_div = is_binop `(/):complex->complex->complex` in
+    fun tm -> (is_div tm or (is_comb tm & rator tm = inv_tm)) &
+              not(is_ratconst(rand tm)) in
+  let BASIC_COMPLEX_FIELD tm =
+    let is_freeinv t = is_inv t & free_in t tm in
+    let itms = setify(map rand (find_terms is_freeinv tm)) in
+    let hyps = map (fun t -> SPEC t COMPLEX_MUL_RINV) itms in
+    let tm' = itlist (fun th t -> mk_imp(concl th,t)) hyps tm in
+    let th1 = setup_conv tm' in
+    let cjs = conjuncts(rand(concl th1)) in
+    let ths = map COMPLEX_RING cjs in
+    let th2 = EQ_MP (SYM th1) (end_itlist CONJ ths) in
+    rev_itlist (C MP) hyps th2 in
+  fun tm ->
+    let th0 = prenex_conv tm in
+    let tm0 = rand(concl th0) in
+    let avs,bod = strip_forall tm0 in
+    let th1 = setup_conv bod in
+    let ths = map BASIC_COMPLEX_FIELD (conjuncts(rand(concl th1))) in
+    EQ_MP (SYM th0) (GENL avs (EQ_MP (SYM th1) (end_itlist CONJ ths)));;
+
+(* ------------------------------------------------------------------------- *)
+(* More trivial lemmas.                                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_DIV_1 = prove
+ (`!z. z / Cx(&1) = z`,
+  CONV_TAC COMPLEX_FIELD);;
+
+let COMPLEX_DIV_LMUL = prove
+ (`!x y. ~(y = Cx(&0)) ==> y * x / y = x`,
+  CONV_TAC COMPLEX_FIELD);;
+
+let COMPLEX_DIV_RMUL = prove
+ (`!x y. ~(y = Cx(&0)) ==> x / y * y = x`,
+  CONV_TAC COMPLEX_FIELD);;
+
+let COMPLEX_INV_EQ_0 = prove
+ (`!x. inv x = Cx(&0) <=> x = Cx(&0)`,
+  GEN_TAC THEN ASM_CASES_TAC `x = Cx(&0)` THEN
+  ASM_REWRITE_TAC[COMPLEX_INV_0] THEN POP_ASSUM MP_TAC THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let COMPLEX_INV_NEG = prove
+ (`!x:complex. inv(--x) = --(inv x)`,
+  GEN_TAC THEN ASM_CASES_TAC `x = Cx(&0)` THEN
+  ASM_REWRITE_TAC[COMPLEX_INV_0; COMPLEX_NEG_0] THEN
+  POP_ASSUM MP_TAC THEN CONV_TAC COMPLEX_FIELD);;
+
+let COMPLEX_NEG_INV = prove
+ (`!x:complex. --(inv x) = inv(--x)`,
+  REWRITE_TAC[COMPLEX_INV_NEG]);;
+
+let COMPLEX_INV_EQ_1 = prove
+ (`!x. inv x = Cx(&1) <=> x = Cx(&1)`,
+  GEN_TAC THEN ASM_CASES_TAC `x = Cx(&0)` THEN
+  ASM_REWRITE_TAC[COMPLEX_INV_0] THEN POP_ASSUM MP_TAC THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let COMPLEX_DIV_EQ_0 = prove
+ (`!w z. w / z = Cx(&0) <=> w = Cx(&0) \/ z = Cx(&0)`,
+  REWRITE_TAC[complex_div; COMPLEX_INV_EQ_0; COMPLEX_ENTIRE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Powers.                                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_POW_ADD = prove
+ (`!x m n. x pow (m + n) = x pow m * x pow n`,
+  GEN_TAC THEN INDUCT_TAC THEN
+  ASM_REWRITE_TAC[ADD_CLAUSES; complex_pow;
+                  COMPLEX_MUL_LID; COMPLEX_MUL_ASSOC]);;
+
+let COMPLEX_POW_POW = prove
+ (`!x m n. (x pow m) pow n = x pow (m * n)`,
+  GEN_TAC THEN GEN_TAC THEN INDUCT_TAC THEN
+  ASM_REWRITE_TAC[complex_pow; MULT_CLAUSES; COMPLEX_POW_ADD]);;
+
+let COMPLEX_POW_1 = prove
+ (`!x. x pow 1 = x`,
+  REWRITE_TAC[num_CONV `1`] THEN REWRITE_TAC[complex_pow; COMPLEX_MUL_RID]);;
+
+let COMPLEX_POW_2 = prove
+ (`!x. x pow 2 = x * x`,
+  REWRITE_TAC[num_CONV `2`] THEN REWRITE_TAC[complex_pow; COMPLEX_POW_1]);;
+
+let COMPLEX_POW_NEG = prove
+ (`!x n. (--x) pow n = if EVEN n then x pow n else --(x pow n)`,
+  GEN_TAC THEN INDUCT_TAC THEN
+  ASM_REWRITE_TAC[complex_pow; EVEN] THEN
+  ASM_CASES_TAC `EVEN n` THEN
+  ASM_REWRITE_TAC[COMPLEX_MUL_RNEG; COMPLEX_MUL_LNEG; COMPLEX_NEG_NEG]);;
+
+let COMPLEX_POW_ONE = prove
+ (`!n. Cx(&1) pow n = Cx(&1)`,
+  INDUCT_TAC THEN ASM_REWRITE_TAC[complex_pow; COMPLEX_MUL_LID]);;
+
+let COMPLEX_POW_MUL = prove
+ (`!x y n. (x * y) pow n = (x pow n) * (y pow n)`,
+  GEN_TAC THEN GEN_TAC THEN INDUCT_TAC THEN
+  ASM_REWRITE_TAC[complex_pow; COMPLEX_MUL_LID; COMPLEX_MUL_AC]);;
+
+let COMPLEX_POW_DIV = prove
+ (`!x y n. (x / y) pow n = (x pow n) / (y pow n)`,
+  REWRITE_TAC[complex_div; COMPLEX_POW_MUL; COMPLEX_POW_INV]);;
+
+let COMPLEX_POW_II_2 = prove
+ (`ii pow 2 = --Cx(&1)`,
+  REWRITE_TAC[ii; COMPLEX_POW_2; complex_mul; CX_DEF; RE; IM; complex_neg] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let COMPLEX_POW_EQ_0 = prove
+ (`!x n. (x pow n = Cx(&0)) <=> (x = Cx(&0)) /\ ~(n = 0)`,
+  GEN_TAC THEN INDUCT_TAC THEN
+  ASM_REWRITE_TAC[NOT_SUC; complex_pow; COMPLEX_ENTIRE] THENL
+   [SIMPLE_COMPLEX_ARITH_TAC; CONV_TAC TAUT]);;
+
+let COMPLEX_POW_ZERO = prove
+ (`!n. Cx(&0) pow n = if n = 0 then Cx(&1) else Cx(&0)`,
+  INDUCT_TAC THEN REWRITE_TAC[complex_pow; COMPLEX_MUL_LZERO; NOT_SUC]);;
+
+let COMPLEX_INV_II = prove
+ (`inv ii = --ii`,
+  CONV_TAC COMPLEX_FIELD);;
+
+let COMPLEX_DIV_POW = prove
+ (`!x:complex n k:num.
+      ~(x= Cx(&0)) /\ k <= n /\ ~(k = 0)
+      ==> x pow (n-k) = x pow n / x pow k`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN `x:complex pow (n - k) * x pow k =
+  x pow n / x pow k * x pow k` (fun th-> ASM_MESON_TAC
+  [th;COMPLEX_POW_EQ_0;COMPLEX_EQ_MUL_RCANCEL])
+  THEN ASM_SIMP_TAC[GSYM COMPLEX_POW_ADD;SUB_ADD] THEN
+  MP_TAC (MESON [COMPLEX_POW_EQ_0;ASSUME `~(k = 0)`; ASSUME `~(x = Cx(&0))`]
+  `~(x pow k = Cx(&0))`) THEN ASM_SIMP_TAC[COMPLEX_DIV_RMUL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Norms (aka "moduli").                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_VEC_0 = prove
+ (`vec 0 = Cx(&0)`,
+  SIMP_TAC[CART_EQ; VEC_COMPONENT; CX_DEF; complex;
+           DIMINDEX_2; FORALL_2; VECTOR_2]);;
+
+let COMPLEX_NORM_ZERO = prove
+ (`!z. (norm z = &0) <=> (z = Cx(&0))`,
+  REWRITE_TAC[NORM_EQ_0; COMPLEX_VEC_0]);;
+
+let COMPLEX_NORM_NUM = prove
+ (`!n. norm(Cx(&n)) = &n`,
+  REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_NUM]);;
+
+let COMPLEX_NORM_0 = prove
+ (`norm(Cx(&0)) = &0`,
+  MESON_TAC[COMPLEX_NORM_ZERO]);;
+
+let COMPLEX_NORM_NZ = prove
+ (`!z. &0 < norm(z) <=> ~(z = Cx(&0))`,
+  REWRITE_TAC[NORM_POS_LT; COMPLEX_VEC_0]);;
+
+let COMPLEX_NORM_MUL = prove
+ (`!w z. norm(w * z) = norm(w) * norm(z)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[complex_norm; complex_mul; RE; IM] THEN
+  SIMP_TAC[GSYM SQRT_MUL; REAL_POW_2; REAL_LE_ADD; REAL_LE_SQUARE] THEN
+  AP_TERM_TAC THEN REAL_ARITH_TAC);;
+
+let COMPLEX_NORM_POW = prove
+ (`!z n. norm(z pow n) = norm(z) pow n`,
+  GEN_TAC THEN INDUCT_TAC THEN
+  ASM_REWRITE_TAC[complex_pow; real_pow; COMPLEX_NORM_NUM; COMPLEX_NORM_MUL]);;
+
+let COMPLEX_NORM_INV = prove
+ (`!z. norm(inv z) = inv(norm z)`,
+  GEN_TAC THEN REWRITE_TAC[complex_norm; complex_inv; RE; IM] THEN
+  REWRITE_TAC[REAL_POW_2; real_div] THEN
+  REWRITE_TAC[REAL_ARITH `(r * d) * r * d + (--i * d) * --i * d =
+                          (r * r + i * i) * d * d:real`] THEN
+  ASM_CASES_TAC `Re z * Re z + Im z * Im z = &0` THENL
+   [ASM_REWRITE_TAC[REAL_INV_0; SQRT_0; REAL_MUL_LZERO]; ALL_TAC] THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC REAL_MUL_RINV_UNIQ THEN
+  SIMP_TAC[GSYM SQRT_MUL; REAL_LE_MUL; REAL_LE_INV_EQ; REAL_LE_ADD;
+           REAL_LE_SQUARE] THEN
+  ONCE_REWRITE_TAC[AC REAL_MUL_AC
+   `a * a * b * b:real = (a * b) * (a * b)`] THEN
+  ASM_SIMP_TAC[REAL_MUL_RINV; REAL_MUL_LID; SQRT_1]);;
+
+let COMPLEX_NORM_DIV = prove
+ (`!w z. norm(w / z) = norm(w) / norm(z)`,
+  REWRITE_TAC[complex_div; real_div; COMPLEX_NORM_INV; COMPLEX_NORM_MUL]);;
+
+let COMPLEX_NORM_TRIANGLE_SUB = prove
+ (`!w z. norm(w) <= norm(w + z) + norm(z)`,
+  MESON_TAC[NORM_TRIANGLE; NORM_NEG; COMPLEX_ADD_ASSOC;
+            COMPLEX_ADD_RINV; COMPLEX_ADD_RID]);;
+
+let COMPLEX_NORM_ABS_NORM = prove
+ (`!w z. abs(norm w - norm z) <= norm(w - z)`,
+  REPEAT GEN_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `a - b <= x /\ b - a <= x ==> abs(a - b) <= x:real`) THEN
+  MESON_TAC[COMPLEX_NEG_SUB; NORM_NEG; REAL_LE_SUB_RADD; complex_sub;
+            COMPLEX_NORM_TRIANGLE_SUB]);;
+
+let COMPLEX_POW_EQ_1 = prove
+ (`!z n. z pow n = Cx(&1) ==> norm(z) = &1 \/ n = 0`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o AP_TERM `norm:complex->real`) THEN
+  SIMP_TAC[COMPLEX_NORM_POW; COMPLEX_NORM_CX; REAL_POW_EQ_1; REAL_ABS_NUM] THEN
+  SIMP_TAC[REAL_ABS_NORM] THEN CONV_TAC TAUT);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex conjugate.                                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let cnj = new_definition
+  `cnj(z) = complex(Re(z),--(Im(z)))`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Conjugation is an automorphism.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let CNJ_INJ = prove
+ (`!w z. (cnj(w) = cnj(z)) <=> (w = z)`,
+  REWRITE_TAC[cnj; COMPLEX_EQ; RE; IM; REAL_EQ_NEG2]);;
+
+let CNJ_CNJ = prove
+ (`!z. cnj(cnj z) = z`,
+  REWRITE_TAC[cnj; COMPLEX_EQ; RE; IM; REAL_NEG_NEG]);;
+
+let CNJ_CX = prove
+ (`!x. cnj(Cx x) = Cx x`,
+  REWRITE_TAC[cnj; COMPLEX_EQ; CX_DEF; REAL_NEG_0; RE; IM]);;
+
+let COMPLEX_NORM_CNJ = prove
+ (`!z. norm(cnj z) = norm(z)`,
+  REWRITE_TAC[complex_norm; cnj; REAL_POW_2] THEN
+  REWRITE_TAC[REAL_MUL_LNEG; REAL_MUL_RNEG; RE; IM; REAL_NEG_NEG]);;
+
+let CNJ_NEG = prove
+ (`!z. cnj(--z) = --(cnj z)`,
+  REWRITE_TAC[cnj; complex_neg; COMPLEX_EQ; RE; IM]);;
+
+let CNJ_INV = prove
+ (`!z. cnj(inv z) = inv(cnj z)`,
+  REWRITE_TAC[cnj; complex_inv; COMPLEX_EQ; RE; IM] THEN
+  REWRITE_TAC[real_div; REAL_NEG_NEG; REAL_POW_2;
+              REAL_MUL_LNEG; REAL_MUL_RNEG]);;
+
+let CNJ_ADD = prove
+ (`!w z. cnj(w + z) = cnj(w) + cnj(z)`,
+  REWRITE_TAC[cnj; complex_add; COMPLEX_EQ; RE; IM] THEN
+  REWRITE_TAC[REAL_NEG_ADD; REAL_MUL_LNEG; REAL_MUL_RNEG; REAL_NEG_NEG]);;
+
+let CNJ_SUB = prove
+ (`!w z. cnj(w - z) = cnj(w) - cnj(z)`,
+  REWRITE_TAC[complex_sub; CNJ_ADD; CNJ_NEG]);;
+
+let CNJ_MUL = prove
+ (`!w z. cnj(w * z) = cnj(w) * cnj(z)`,
+  REWRITE_TAC[cnj; complex_mul; COMPLEX_EQ; RE; IM] THEN
+  REWRITE_TAC[REAL_NEG_ADD; REAL_MUL_LNEG; REAL_MUL_RNEG; REAL_NEG_NEG]);;
+
+let CNJ_DIV = prove
+ (`!w z. cnj(w / z) = cnj(w) / cnj(z)`,
+  REWRITE_TAC[complex_div; CNJ_MUL; CNJ_INV]);;
+
+let CNJ_POW = prove
+ (`!z n. cnj(z pow n) = cnj(z) pow n`,
+  GEN_TAC THEN INDUCT_TAC THEN
+  ASM_REWRITE_TAC[complex_pow; CNJ_MUL; CNJ_CX]);;
+
+let RE_CNJ = prove
+ (`!z. Re(cnj z) = Re z`,
+  REWRITE_TAC[cnj; RE]);;
+
+let IM_CNJ = prove
+ (`!z. Im(cnj z) = --Im z`,
+  REWRITE_TAC[cnj; IM]);;
+
+let CNJ_EQ_CX = prove
+ (`!x z. cnj z = Cx x <=> z = Cx x`,
+  REWRITE_TAC[COMPLEX_EQ; RE_CNJ; IM_CNJ; RE_CX; IM_CX] THEN
+  CONV_TAC REAL_RING);;
+
+let CNJ_EQ_0 = prove
+ (`!z. cnj z = Cx(&0) <=> z = Cx(&0)`,
+  REWRITE_TAC[CNJ_EQ_CX]);;
+
+let COMPLEX_ADD_CNJ = prove
+ (`(!z. z + cnj z = Cx(&2 * Re z)) /\ (!z. cnj z + z = Cx(&2 * Re z))`,
+  REWRITE_TAC[COMPLEX_EQ; RE_CX; IM_CX; RE_ADD; IM_ADD; RE_CNJ; IM_CNJ] THEN
+  REAL_ARITH_TAC);;
+
+let CNJ_II = prove
+ (`cnj ii = --ii`,
+  REWRITE_TAC[cnj; ii; RE; IM; complex_neg; REAL_NEG_0]);;
+
+let CX_RE_CNJ = prove
+ (`!z. Cx(Re z) = (z + cnj z) / Cx(&2)`,
+  REWRITE_TAC[COMPLEX_EQ; RE_DIV_CX; IM_DIV_CX; RE_CX; IM_CX] THEN
+  REWRITE_TAC[RE_ADD; IM_ADD; RE_CNJ; IM_CNJ] THEN REAL_ARITH_TAC);;
+
+let CX_IM_CNJ = prove
+ (`!z. Cx(Im z) = --ii * (z - cnj z) / Cx(&2)`,
+  REWRITE_TAC[COMPLEX_EQ; RE_DIV_CX; IM_DIV_CX; RE_CX; IM_CX;
+              COMPLEX_MUL_LNEG; RE_NEG; IM_NEG; RE_MUL_II; IM_MUL_II] THEN
+  REWRITE_TAC[RE_SUB; IM_SUB; RE_CNJ; IM_CNJ] THEN REAL_ARITH_TAC);;
+
+let FORALL_CNJ = prove
+ (`(!z. P(cnj z)) <=> (!z. P z)`,
+  MESON_TAC[CNJ_CNJ]);;
+
+let EXISTS_CNJ = prove
+ (`(?z. P(cnj z)) <=> (?z. P z)`,
+  MESON_TAC[CNJ_CNJ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Slightly ad hoc theorems relating multiplication, inverse and conjugation *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_NORM_POW_2 = prove
+ (`!z. Cx(norm z) pow 2 = z * cnj z`,
+  GEN_TAC THEN REWRITE_TAC [GSYM CX_POW; COMPLEX_SQNORM] THEN
+  REWRITE_TAC [cnj; complex_mul; CX_DEF; RE; IM; COMPLEX_EQ] THEN
+  CONV_TAC REAL_RING);;
+
+let COMPLEX_MUL_CNJ = prove
+ (`!z. cnj z * z = Cx(norm(z)) pow 2 /\ z * cnj z = Cx(norm(z)) pow 2`,
+  GEN_TAC THEN REWRITE_TAC[COMPLEX_MUL_SYM] THEN
+  REWRITE_TAC[cnj; complex_mul; RE; IM; GSYM CX_POW; COMPLEX_SQNORM] THEN
+  REWRITE_TAC[CX_DEF] THEN AP_TERM_TAC THEN BINOP_TAC THEN
+  CONV_TAC REAL_RING);;
+
+let COMPLEX_INV_CNJ = prove
+ (`!z. inv z = cnj z / Cx(norm z) pow 2`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THENL
+   [ASM_REWRITE_TAC[CNJ_CX; complex_div; COMPLEX_INV_0; COMPLEX_MUL_LZERO];
+    MATCH_MP_TAC(COMPLEX_FIELD
+     `x * y = z /\ ~(x = Cx(&0)) /\ ~(z = Cx(&0)) ==> inv x = y / z`) THEN
+    ASM_REWRITE_TAC[COMPLEX_MUL_CNJ; GSYM CX_POW; CX_INJ; REAL_POW_EQ_0] THEN
+    ASM_REWRITE_TAC[COMPLEX_NORM_ZERO; ARITH]]);;
+
+let COMPLEX_DIV_CNJ = prove
+ (`!a b. a / b = (a * cnj b) / Cx(norm b) pow 2`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[complex_div; GSYM COMPLEX_MUL_ASSOC] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC LAND_CONV [COMPLEX_INV_CNJ] THEN
+  REWRITE_TAC[complex_div]);;
+
+let RE_COMPLEX_DIV_EQ_0 = prove
+ (`!a b. Re(a / b) = &0 <=> Re(a * cnj b) = &0`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[COMPLEX_DIV_CNJ] THEN
+  REWRITE_TAC[complex_div; GSYM CX_POW; GSYM CX_INV] THEN
+  REWRITE_TAC[RE_MUL_CX; REAL_INV_EQ_0; REAL_POW_EQ_0; ARITH;
+              REAL_ENTIRE; COMPLEX_NORM_ZERO] THEN
+  ASM_CASES_TAC `b = Cx(&0)` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[CNJ_CX; COMPLEX_MUL_RZERO; RE_CX]);;
+
+let IM_COMPLEX_DIV_EQ_0 = prove
+ (`!a b. Im(a / b) = &0 <=> Im(a * cnj b) = &0`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[COMPLEX_DIV_CNJ] THEN
+  REWRITE_TAC[complex_div; GSYM CX_POW; GSYM CX_INV] THEN
+  REWRITE_TAC[IM_MUL_CX; REAL_INV_EQ_0; REAL_POW_EQ_0; ARITH;
+              REAL_ENTIRE; COMPLEX_NORM_ZERO] THEN
+  ASM_CASES_TAC `b = Cx(&0)` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[CNJ_CX; COMPLEX_MUL_RZERO; IM_CX]);;
+
+let RE_COMPLEX_DIV_GT_0 = prove
+ (`!a b. &0 < Re(a / b) <=> &0 < Re(a * cnj b)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[COMPLEX_DIV_CNJ] THEN
+  REWRITE_TAC[complex_div; GSYM CX_POW; GSYM CX_INV] THEN
+  REWRITE_TAC[RE_MUL_CX; REAL_INV_EQ_0; REAL_POW_EQ_0; ARITH;
+              REAL_ENTIRE; COMPLEX_NORM_ZERO] THEN
+  ASM_CASES_TAC `b = Cx(&0)` THEN
+  ASM_REWRITE_TAC[CNJ_CX; COMPLEX_MUL_RZERO; RE_CX; REAL_MUL_LZERO] THEN
+  REWRITE_TAC[REAL_ARITH `&0 < a * x <=> &0 * x < a * x`] THEN
+  ASM_SIMP_TAC[REAL_LT_RMUL_EQ; REAL_LT_INV_EQ; REAL_POW_LT; ARITH;
+               COMPLEX_NORM_NZ]);;
+
+let IM_COMPLEX_DIV_GT_0 = prove
+ (`!a b. &0 < Im(a / b) <=> &0 < Im(a * cnj b)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[COMPLEX_DIV_CNJ] THEN
+  REWRITE_TAC[complex_div; GSYM CX_POW; GSYM CX_INV] THEN
+  REWRITE_TAC[IM_MUL_CX; REAL_INV_EQ_0; REAL_POW_EQ_0; ARITH;
+              REAL_ENTIRE; COMPLEX_NORM_ZERO] THEN
+  ASM_CASES_TAC `b = Cx(&0)` THEN
+  ASM_REWRITE_TAC[CNJ_CX; COMPLEX_MUL_RZERO; IM_CX; REAL_MUL_LZERO] THEN
+  REWRITE_TAC[REAL_ARITH `&0 < a * x <=> &0 * x < a * x`] THEN
+  ASM_SIMP_TAC[REAL_LT_RMUL_EQ; REAL_LT_INV_EQ; REAL_POW_LT; ARITH;
+               COMPLEX_NORM_NZ]);;
+
+let RE_COMPLEX_DIV_GE_0 = prove
+ (`!a b. &0 <= Re(a / b) <=> &0 <= Re(a * cnj b)`,
+  REWRITE_TAC[REAL_ARITH `&0 <= x <=> &0 < x \/ x = &0`] THEN
+  REWRITE_TAC[RE_COMPLEX_DIV_GT_0; RE_COMPLEX_DIV_EQ_0]);;
+
+let IM_COMPLEX_DIV_GE_0 = prove
+ (`!a b. &0 <= Im(a / b) <=> &0 <= Im(a * cnj b)`,
+  REWRITE_TAC[REAL_ARITH `&0 <= x <=> &0 < x \/ x = &0`] THEN
+  REWRITE_TAC[IM_COMPLEX_DIV_GT_0; IM_COMPLEX_DIV_EQ_0]);;
+
+let RE_COMPLEX_DIV_LE_0 = prove
+ (`!a b. Re(a / b) <= &0 <=> Re(a * cnj b) <= &0`,
+  REWRITE_TAC[GSYM REAL_NOT_LT; RE_COMPLEX_DIV_GT_0]);;
+
+let IM_COMPLEX_DIV_LE_0 = prove
+ (`!a b. Im(a / b) <= &0 <=> Im(a * cnj b) <= &0`,
+  REWRITE_TAC[GSYM REAL_NOT_LT; IM_COMPLEX_DIV_GT_0]);;
+
+let RE_COMPLEX_DIV_LT_0 = prove
+ (`!a b. Re(a / b) < &0 <=> Re(a * cnj b) < &0`,
+  REWRITE_TAC[GSYM REAL_NOT_LE; RE_COMPLEX_DIV_GE_0]);;
+
+let IM_COMPLEX_DIV_LT_0 = prove
+ (`!a b. Im(a / b) < &0 <=> Im(a * cnj b) < &0`,
+  REWRITE_TAC[GSYM REAL_NOT_LE; IM_COMPLEX_DIV_GE_0]);;
+
+let IM_COMPLEX_INV_GE_0 = prove
+ (`!z. &0 <= Im(inv z) <=> Im(z) <= &0`,
+  GEN_TAC THEN MP_TAC(ISPECL [`Cx(&1)`; `z:complex`] IM_COMPLEX_DIV_GE_0) THEN
+  REWRITE_TAC[complex_div; COMPLEX_MUL_LID; IM_CNJ] THEN REAL_ARITH_TAC);;
+
+let IM_COMPLEX_INV_LE_0 = prove
+ (`!z. Im(inv z) <= &0 <=> &0 <= Im(z)`,
+  MESON_TAC[IM_COMPLEX_INV_GE_0; COMPLEX_INV_INV]);;
+
+let IM_COMPLEX_INV_GT_0 = prove
+ (`!z. &0 < Im(inv z) <=> Im(z) < &0`,
+  REWRITE_TAC[REAL_ARITH `&0 < a <=> ~(a <= &0)`; IM_COMPLEX_INV_LE_0] THEN
+  REAL_ARITH_TAC);;
+
+let IM_COMPLEX_INV_LT_0 = prove
+ (`!z. Im(inv z) < &0 <=> &0 < Im(z)`,
+  REWRITE_TAC[REAL_ARITH `a < &0 <=> ~(&0 <= a)`; IM_COMPLEX_INV_GE_0] THEN
+  REAL_ARITH_TAC);;
+
+let IM_COMPLEX_INV_EQ_0 = prove
+ (`!z. Im(inv z) = &0 <=> Im(z) = &0`,
+  SIMP_TAC[GSYM REAL_LE_ANTISYM; IM_COMPLEX_INV_LE_0; IM_COMPLEX_INV_GE_0] THEN
+  REAL_ARITH_TAC);;
+
+let REAL_SGN_RE_COMPLEX_DIV = prove
+ (`!w z. real_sgn(Re(w / z)) = real_sgn(Re(w * cnj z))`,
+  REWRITE_TAC[real_sgn; RE_COMPLEX_DIV_GT_0; RE_COMPLEX_DIV_GE_0;
+              REAL_ARITH `x < &0 <=> ~(&0 <= x)`]);;
+
+let REAL_SGN_IM_COMPLEX_DIV = prove
+ (`!w z. real_sgn(Im(w / z)) = real_sgn(Im(w * cnj z))`,
+  REWRITE_TAC[real_sgn; IM_COMPLEX_DIV_GT_0; IM_COMPLEX_DIV_GE_0;
+              REAL_ARITH `x < &0 <=> ~(&0 <= x)`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Norm versus components for complex numbers.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_NORM_GE_RE_IM = prove
+ (`!z. abs(Re(z)) <= norm(z) /\ abs(Im(z)) <= norm(z)`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM POW_2_SQRT_ABS] THEN
+  REWRITE_TAC[complex_norm] THEN
+  CONJ_TAC THEN
+  MATCH_MP_TAC SQRT_MONO_LE THEN
+  ASM_SIMP_TAC[REAL_LE_ADDR; REAL_LE_ADDL; REAL_POW_2; REAL_LE_SQUARE]);;
+
+let COMPLEX_NORM_LE_RE_IM = prove
+ (`!z. norm(z) <= abs(Re z) + abs(Im z)`,
+  GEN_TAC THEN MP_TAC(ISPEC `z:complex` NORM_LE_L1) THEN
+  REWRITE_TAC[DIMINDEX_2; SUM_2; RE_DEF; IM_DEF]);;
+
+let COMPLEX_L1_LE_NORM = prove
+ (`!z. sqrt(&2) / &2 * (abs(Re z) + abs(Im z)) <= norm z`,
+  GEN_TAC THEN MATCH_MP_TAC REAL_LE_LCANCEL_IMP THEN EXISTS_TAC `sqrt(&2)` THEN
+  SIMP_TAC[REAL_ARITH `x * x / &2 * y = (x pow 2) / &2 * y`;
+           SQRT_POW_2; REAL_POS; SQRT_POS_LT; REAL_OF_NUM_LT; ARITH] THEN
+  MP_TAC(ISPEC `z:complex` L1_LE_NORM) THEN
+  REWRITE_TAC[DIMINDEX_2; SUM_2; RE_DEF; IM_DEF] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex square roots.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let csqrt = new_definition
+  `csqrt(z) = if Im(z) = &0 then
+                if &0 <= Re(z) then complex(sqrt(Re(z)),&0)
+                else complex(&0,sqrt(--Re(z)))
+              else complex(sqrt((norm(z) + Re(z)) / &2),
+                           (Im(z) / abs(Im(z))) *
+                           sqrt((norm(z) - Re(z)) / &2))`;;
+
+
+let CSQRT = prove
+ (`!z. csqrt(z) pow 2 = z`,
+  GEN_TAC THEN REWRITE_TAC[COMPLEX_POW_2; csqrt] THEN COND_CASES_TAC THENL
+   [COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[CX_DEF; complex_mul; RE; IM; REAL_MUL_RZERO; REAL_MUL_LZERO;
+      REAL_SUB_LZERO; REAL_SUB_RZERO; REAL_ADD_LID; COMPLEX_EQ] THEN
+    REWRITE_TAC[REAL_NEG_EQ; GSYM REAL_POW_2] THEN
+    ASM_SIMP_TAC[SQRT_POW_2; REAL_ARITH `~(&0 <= x) ==> &0 <= --x`];
+    ALL_TAC] THEN
+  REWRITE_TAC[complex_mul; RE; IM] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH
+   `(s * s - (i * s') * (i * s') = s * s - (i * i) * (s' * s')) /\
+    (s * i * s' + (i * s')* s = &2 * i * s * s')`] THEN
+  REWRITE_TAC[GSYM REAL_POW_2] THEN
+  SUBGOAL_THEN `&0 <= norm(z) + Re(z) /\ &0 <= norm(z) - Re(z)`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(SPEC `z:complex` COMPLEX_NORM_GE_RE_IM) THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_LE_DIV; REAL_POS; GSYM SQRT_MUL; SQRT_POW_2] THEN
+  REWRITE_TAC[COMPLEX_EQ; RE; IM] THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[REAL_POW_DIV; REAL_POW2_ABS;
+                 REAL_POW_EQ_0; REAL_DIV_REFL] THEN
+    REWRITE_TAC[real_div; REAL_MUL_LID; GSYM REAL_SUB_RDISTRIB] THEN
+    REWRITE_TAC[REAL_ARITH `(m + r) - (m - r) = r * &2`] THEN
+    REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[REAL_MUL_RID]; ALL_TAC] THEN
+  REWRITE_TAC[real_div] THEN
+  ONCE_REWRITE_TAC[AC REAL_MUL_AC
+    `(a * b) * a' * b = (a * a') * (b * b:real)`] THEN
+  REWRITE_TAC[REAL_DIFFSQ] THEN
+  REWRITE_TAC[complex_norm; GSYM REAL_POW_2] THEN
+  SIMP_TAC[SQRT_POW_2; REAL_LE_ADD;
+           REWRITE_RULE[GSYM REAL_POW_2] REAL_LE_SQUARE] THEN
+  REWRITE_TAC[REAL_ADD_SUB; GSYM REAL_POW_MUL] THEN
+  REWRITE_TAC[POW_2_SQRT_ABS] THEN
+  REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_INV; REAL_ABS_NUM] THEN
+  ONCE_REWRITE_TAC[AC REAL_MUL_AC
+    `&2 * (i * a') * a * h = i * (&2 * h) * a * a'`] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[REAL_MUL_LID; GSYM real_div] THEN
+  ASM_SIMP_TAC[REAL_DIV_REFL; REAL_ABS_ZERO; REAL_MUL_RID]);;
+
+let CX_SQRT = prove
+ (`!x. &0 <= x ==> Cx(sqrt x) = csqrt(Cx x)`,
+  SIMP_TAC[csqrt; IM_CX; RE_CX; COMPLEX_EQ; RE; IM]);;
+
+let CSQRT_CX = prove
+ (`!x. &0 <= x ==> csqrt(Cx x) = Cx(sqrt x)`,
+  SIMP_TAC[CX_SQRT]);;
+
+let CSQRT_0 = prove
+ (`csqrt(Cx(&0)) = Cx(&0)`,
+  SIMP_TAC[CSQRT_CX; REAL_POS; SQRT_0]);;
+
+let CSQRT_1 = prove
+ (`csqrt(Cx(&1)) = Cx(&1)`,
+  SIMP_TAC[CSQRT_CX; REAL_POS; SQRT_1]);;
+
+let CSQRT_PRINCIPAL = prove
+ (`!z. &0 < Re(csqrt(z)) \/ Re(csqrt(z)) = &0 /\ &0 <= Im(csqrt(z))`,
+  GEN_TAC THEN REWRITE_TAC[csqrt] THEN
+  REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[RE; IM]) THENL
+   [FIRST_ASSUM(MP_TAC o MATCH_MP SQRT_POS_LE) THEN REAL_ARITH_TAC;
+    DISJ2_TAC THEN REWRITE_TAC[real_ge] THEN MATCH_MP_TAC SQRT_POS_LE THEN
+    ASM_REAL_ARITH_TAC;
+    DISJ1_TAC THEN MATCH_MP_TAC SQRT_POS_LT THEN
+    MATCH_MP_TAC(REAL_ARITH `abs(y) < x ==> &0 < (x + y) / &2`) THEN
+    REWRITE_TAC[complex_norm] THEN REWRITE_TAC[GSYM POW_2_SQRT_ABS] THEN
+    MATCH_MP_TAC SQRT_MONO_LT THEN
+    REWRITE_TAC[REAL_POW_2; REAL_LE_SQUARE; REAL_LT_ADDR] THEN
+    REWRITE_TAC[REAL_ARITH `&0 < x <=> &0 <= x /\ ~(x = &0)`] THEN
+    ASM_REWRITE_TAC[REAL_LE_SQUARE; REAL_ENTIRE]]);;
+
+let RE_CSQRT = prove
+ (`!z. &0 <= Re(csqrt z)`,
+  MP_TAC CSQRT_PRINCIPAL THEN MATCH_MP_TAC MONO_FORALL THEN REAL_ARITH_TAC);;
+
+let CSQRT_UNIQUE = prove
+ (`!s z. s pow 2 = z /\ (&0 < Re s \/ Re s = &0 /\ &0 <= Im s)
+         ==> csqrt z = s`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+  MP_TAC(SPEC `(s:complex) pow 2` CSQRT) THEN
+  SIMP_TAC[COMPLEX_RING `a pow 2 = b pow 2 <=> a = b \/ a = --b:complex`] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[COMPLEX_RING `--z = z <=> z = Cx(&0)`] THEN
+  FIRST_ASSUM(MP_TAC o AP_TERM `Re`) THEN
+  FIRST_X_ASSUM(MP_TAC o AP_TERM `Im`) THEN
+  REWRITE_TAC[RE_NEG; IM_NEG; COMPLEX_EQ; RE_CX; IM_CX] THEN
+  MP_TAC(SPEC `(s:complex) pow 2` CSQRT_PRINCIPAL) THEN
+  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC);;
+
+let POW_2_CSQRT = prove
+ (`!z. &0 < Re z \/ Re(z) = &0 /\ &0 <= Im(z) ==> csqrt(z pow 2) = z`,
+  MESON_TAC[CSQRT_UNIQUE]);;
+
+let CSQRT_EQ_0 = prove
+ (`!z. csqrt z = Cx(&0) <=> z = Cx(&0)`,
+  GEN_TAC THEN MP_TAC (SPEC `z:complex` CSQRT) THEN CONV_TAC COMPLEX_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* A few more complex-specific cases of vector notions.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_CMUL = prove
+ (`!c x. c % x = Cx(c) * x`,
+  SIMP_TAC[CART_EQ; VECTOR_MUL_COMPONENT; CX_DEF; complex;
+           complex_mul; DIMINDEX_2; FORALL_2; IM_DEF; RE_DEF; VECTOR_2] THEN
+  REAL_ARITH_TAC);;
+
+let LINEAR_COMPLEX_MUL = prove
+ (`!c. linear (\x. c * x)`,
+   REWRITE_TAC[linear; COMPLEX_CMUL] THEN CONV_TAC COMPLEX_RING);;
+
+let BILINEAR_COMPLEX_MUL = prove
+ (`bilinear( * )`,
+  REWRITE_TAC[bilinear; linear; COMPLEX_CMUL] THEN  CONV_TAC COMPLEX_RING);;
+
+let LINEAR_CNJ = prove
+ (`linear cnj`,
+  REWRITE_TAC[linear; COMPLEX_CMUL; CNJ_ADD; CNJ_MUL; CNJ_CX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex-specific theorems about sums.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let RE_VSUM = prove
+ (`!f s. FINITE s ==> Re(vsum s f) = sum s (\x. Re(f x))`,
+  SIMP_TAC[RE_DEF; VSUM_COMPONENT; DIMINDEX_2; ARITH]);;
+
+let IM_VSUM = prove
+ (`!f s. FINITE s ==> Im(vsum s f) = sum s (\x. Im(f x))`,
+  SIMP_TAC[IM_DEF; VSUM_COMPONENT; DIMINDEX_2; ARITH]);;
+
+let VSUM_COMPLEX_LMUL = prove
+ (`!c f s. FINITE(s) ==> vsum s (\x. c * f x) = c * vsum s f`,
+  GEN_TAC THEN GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; COMPLEX_VEC_0; COMPLEX_MUL_RZERO] THEN
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let VSUM_COMPLEX_RMUL = prove
+ (`!c f s. FINITE(s) ==> vsum s (\x. f x * c) = vsum s f * c`,
+  ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN REWRITE_TAC[VSUM_COMPLEX_LMUL]);;
+
+let VSUM_CX = prove
+ (`!f:A->real s. FINITE s ==> vsum s (\a. Cx(f a)) = Cx(sum s f)`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES; COMPLEX_VEC_0; CX_ADD]);;
+
+let CNJ_VSUM = prove
+ (`!f s. FINITE s ==> cnj(vsum s f) = vsum s (\x. cnj(f x))`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; CNJ_ADD; CNJ_CX; COMPLEX_VEC_0]);;
+
+let VSUM_CX_NUMSEG = prove
+ (`!f m n. vsum (m..n) (\a. Cx(f a)) = Cx(sum (m..n) f)`,
+  SIMP_TAC[VSUM_CX; FINITE_NUMSEG]);;
+
+let COMPLEX_SUB_POW = prove
+ (`!x y n.
+        1 <= n ==> x pow n - y pow n =
+                   (x - y) * vsum(0..n-1) (\i. x pow i * y pow (n - 1 - i))`,
+  SIMP_TAC[GSYM VSUM_COMPLEX_LMUL; FINITE_NUMSEG] THEN
+  REWRITE_TAC[COMPLEX_RING
+   `(x - y) * (a * b):complex = (x * a) * b - a * (y * b)`] THEN
+  SIMP_TAC[GSYM complex_pow; ADD1; ARITH_RULE
+    `1 <= n /\ x <= n - 1
+     ==> n - 1 - x = n - (x + 1) /\ SUC(n - 1 - x) = n - x`] THEN
+  REWRITE_TAC[VSUM_DIFFS_ALT; LE_0] THEN
+  SIMP_TAC[SUB_0; SUB_ADD; SUB_REFL;
+           complex_pow; COMPLEX_MUL_LID; COMPLEX_MUL_RID]);;
+
+let COMPLEX_SUB_POW_R1 = prove
+ (`!x n. 1 <= n
+         ==> x pow n - Cx(&1) = (x - Cx(&1)) * vsum(0..n-1) (\i. x pow i)`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o SPECL [`x:complex`; `Cx(&1)`] o
+    MATCH_MP COMPLEX_SUB_POW) THEN
+  REWRITE_TAC[COMPLEX_POW_ONE; COMPLEX_MUL_RID]);;
+
+let COMPLEX_SUB_POW_L1 = prove
+ (`!x n. 1 <= n
+         ==> Cx(&1) - x pow n = (Cx(&1) - x) * vsum(0..n-1) (\i. x pow i)`,
+  ONCE_REWRITE_TAC[GSYM COMPLEX_NEG_SUB] THEN
+  SIMP_TAC[COMPLEX_SUB_POW_R1] THEN REWRITE_TAC[COMPLEX_MUL_LNEG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The complex numbers that are real (zero imaginary part).                  *)
+(* ------------------------------------------------------------------------- *)
+
+let real = new_definition
+ `real z <=> Im z = &0`;;
+
+let REAL = prove
+ (`!z. real z <=> Cx(Re z) = z`,
+  REWRITE_TAC[COMPLEX_EQ; real; CX_DEF; RE; IM] THEN REAL_ARITH_TAC);;
+
+let REAL_CNJ = prove
+ (`!z. real z <=> cnj z = z`,
+  REWRITE_TAC[real; cnj; COMPLEX_EQ; RE; IM] THEN REAL_ARITH_TAC);;
+
+let REAL_IMP_CNJ = prove
+ (`!z. real z ==> cnj z = z`,
+  REWRITE_TAC[REAL_CNJ]);;
+
+let REAL_EXISTS = prove
+ (`!z. real z <=> ?x. z = Cx x`,
+  MESON_TAC[REAL; real; IM_CX]);;
+
+let FORALL_REAL = prove
+ (`(!z. real z ==> P z) <=> (!x. P(Cx x))`,
+  MESON_TAC[REAL_EXISTS]);;
+
+let EXISTS_REAL = prove
+ (`(?z. real z /\ P z) <=> (?x. P(Cx x))`,
+  MESON_TAC[REAL_EXISTS]);;
+
+let REAL_CX = prove
+ (`!x. real(Cx x)`,
+  REWRITE_TAC[REAL_CNJ; CNJ_CX]);;
+
+let REAL_MUL_CX = prove
+ (`!x z. real(Cx x * z) <=> x = &0 \/ real z`,
+  REWRITE_TAC[real; IM_MUL_CX; REAL_ENTIRE]);;
+
+let REAL_ADD = prove
+ (`!w z. real w /\ real z ==> real(w + z)`,
+  SIMP_TAC[REAL_CNJ; CNJ_ADD]);;
+
+let REAL_NEG = prove
+ (`!z. real z ==> real(--z)`,
+  SIMP_TAC[REAL_CNJ; CNJ_NEG]);;
+
+let REAL_SUB = prove
+ (`!w z. real w /\ real z ==> real(w - z)`,
+  SIMP_TAC[REAL_CNJ; CNJ_SUB]);;
+
+let REAL_MUL = prove
+ (`!w z. real w /\ real z ==> real(w * z)`,
+  SIMP_TAC[REAL_CNJ; CNJ_MUL]);;
+
+let REAL_POW = prove
+ (`!z n. real z ==> real(z pow n)`,
+  SIMP_TAC[REAL_CNJ; CNJ_POW]);;
+
+let REAL_INV = prove
+ (`!z. real z ==> real(inv z)`,
+  SIMP_TAC[REAL_CNJ; CNJ_INV]);;
+
+let REAL_INV_EQ = prove
+ (`!z. real(inv z) = real z`,
+  MESON_TAC[REAL_INV; COMPLEX_INV_INV]);;
+
+let REAL_DIV = prove
+ (`!w z. real w /\ real z ==> real(w / z)`,
+  SIMP_TAC[REAL_CNJ; CNJ_DIV]);;
+
+let REAL_VSUM = prove
+ (`!f s. FINITE s /\ (!a. a IN s ==> real(f a)) ==> real(vsum s f)`,
+  SIMP_TAC[CNJ_VSUM; REAL_CNJ]);;
+
+let REAL_SEGMENT = prove
+ (`!a b x. x IN segment[a,b] /\ real a /\ real b ==> real x`,
+  SIMP_TAC[segment; IN_ELIM_THM; real; COMPLEX_EQ; LEFT_AND_EXISTS_THM;
+           LEFT_IMP_EXISTS_THM; IM_ADD; IM_CMUL] THEN
+  REAL_ARITH_TAC);;
+
+let IN_SEGMENT_CX = prove
+ (`!a b x. Cx(x) IN segment[Cx(a),Cx(b)] <=>
+                a <= x /\ x <= b \/ b <= x /\ x <= a`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[segment; IN_ELIM_THM] THEN
+  REWRITE_TAC[COMPLEX_CMUL; GSYM CX_ADD; CX_INJ; GSYM CX_MUL] THEN
+  ASM_CASES_TAC `a:real = b` THENL
+   [ASM_REWRITE_TAC[REAL_ARITH `(&1 - u) * b + u * b = b`] THEN
+    ASM_CASES_TAC `x:real = b` THEN ASM_REWRITE_TAC[REAL_LE_ANTISYM] THEN
+    EXISTS_TAC `&0` THEN REWRITE_TAC[REAL_POS];
+    ALL_TAC] THEN
+  EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `u:real`
+     (CONJUNCTS_THEN2 STRIP_ASSUME_TAC SUBST1_TAC)) THEN
+    REWRITE_TAC[REAL_ARITH `a <= (&1 - u) * a + u * b <=> &0 <= u * (b - a)`;
+      REAL_ARITH `b <= (&1 - u) * a + u * b <=> &0 <= (&1 - u) * (a - b)`;
+      REAL_ARITH `(&1 - u) * a + u * b <= a <=> &0 <= u * (a - b)`;
+      REAL_ARITH `(&1 - u) * a + u * b <= b <=> &0 <= (&1 - u) * (b - a)`] THEN
+    DISJ_CASES_TAC(REAL_ARITH `a <= b \/ b <= a`) THENL
+     [DISJ1_TAC; DISJ2_TAC] THEN
+    CONJ_TAC THEN MATCH_MP_TAC REAL_LE_MUL THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  STRIP_TAC THENL
+   [SUBGOAL_THEN `&0 < b - a` ASSUME_TAC THENL
+     [ASM_REAL_ARITH_TAC;
+      EXISTS_TAC `(x - a:real) / (b - a)`];
+    SUBGOAL_THEN `&0 < a - b` ASSUME_TAC THENL
+     [ASM_REAL_ARITH_TAC;
+      EXISTS_TAC `(a - x:real) / (a - b)`]] THEN
+  (CONJ_TAC THENL
+    [ALL_TAC; UNDISCH_TAC `~(a:real = b)` THEN CONV_TAC REAL_FIELD]) THEN
+  ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let IN_SEGMENT_CX_GEN = prove
+ (`!a b x.
+        x IN segment[Cx a,Cx b] <=>
+        Im(x) = &0 /\ (a <= Re x /\ Re x <= b \/ b <= Re x /\ Re x <= a)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM real] THEN
+  ASM_CASES_TAC `real x` THENL
+   [FIRST_X_ASSUM(SUBST1_TAC o SYM o REWRITE_RULE[REAL]) THEN
+    REWRITE_TAC[IN_SEGMENT_CX; REAL_CX; RE_CX] THEN REAL_ARITH_TAC;
+    ASM_MESON_TAC[REAL_SEGMENT; REAL_CX]]);;
+
+let RE_POS_SEGMENT = prove
+ (`!a b x. x IN segment[a,b] /\ &0 < Re a /\ &0 < Re b ==> &0 < Re x`,
+  SIMP_TAC[segment; IN_ELIM_THM; real; COMPLEX_EQ; LEFT_AND_EXISTS_THM;
+           LEFT_IMP_EXISTS_THM; RE_ADD; RE_CMUL] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(REAL_ARITH
+    `&0 <= x /\ &0 <= y /\ ~(x = &0 /\ y = &0) ==> &0 < x + y`) THEN
+  ASM_SIMP_TAC[REAL_LE_MUL; REAL_SUB_LE; REAL_LT_IMP_LE; REAL_ENTIRE] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let CONVEX_REAL = prove
+ (`convex real`,
+  REWRITE_TAC[convex; IN; COMPLEX_CMUL] THEN
+  SIMP_TAC[REAL_ADD; REAL_MUL; REAL_CX]);;
+
+let IMAGE_CX = prove
+ (`!s. IMAGE Cx s = {z | real z /\ Re(z) IN s}`,
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_IMAGE] THEN MESON_TAC[RE_CX; REAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Useful bound-type theorems for real quantities.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_NORM = prove
+ (`!z. real z ==> norm(z) = abs(Re z)`,
+  SIMP_TAC[real; complex_norm] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[POW_2_SQRT_ABS; REAL_ADD_RID]);;
+
+let REAL_NORM_POS = prove
+ (`!z. real z /\ &0 <= Re z ==> norm(z) = Re(z)`,
+  SIMP_TAC[REAL_NORM] THEN REAL_ARITH_TAC);;
+
+let COMPLEX_NORM_VSUM_SUM_RE = prove
+ (`!f s. FINITE s /\ (!x. x IN s ==> real(f x) /\ &0 <= Re(f x))
+         ==> norm(vsum s f) = sum s (\x. Re(f x))`,
+  SIMP_TAC[GSYM RE_VSUM] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_NORM_POS THEN
+  ASM_SIMP_TAC[REAL_VSUM; RE_VSUM; SUM_POS_LE]);;
+
+let COMPLEX_NORM_VSUM_BOUND = prove
+ (`!s f:A->complex g:A->complex.
+        FINITE s /\ (!x. x IN s ==> real(g x) /\ norm(f x) <= Re(g x))
+        ==> norm(vsum s f) <= norm(vsum s g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum s (\x. norm((f:A->complex) x))` THEN
+  ASM_SIMP_TAC[VSUM_NORM] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum s (\x. Re((g:A->complex) x))` THEN
+  ASM_SIMP_TAC[SUM_LE] THEN
+  MATCH_MP_TAC(REAL_ARITH `x:real = y ==> y <= x`) THEN
+  MATCH_MP_TAC COMPLEX_NORM_VSUM_SUM_RE THEN
+  ASM_MESON_TAC[REAL_LE_TRANS; NORM_POS_LE]);;
+
+let COMPLEX_NORM_VSUM_BOUND_SUBSET = prove
+ (`!f:A->complex g:A->complex s t.
+        FINITE s /\ t SUBSET s /\
+        (!x. x IN s ==> real(g x) /\ norm(f x) <= Re(g x))
+        ==> norm(vsum t f) <= norm(vsum s g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `norm(vsum t (g:A->complex))` THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[COMPLEX_NORM_VSUM_BOUND; SUBSET; FINITE_SUBSET];ALL_TAC] THEN
+  SUBGOAL_THEN
+   `norm(vsum t (g:A->complex)) = sum t (\x. Re(g x)) /\
+    norm(vsum s g) = sum s (\x. Re(g x))`
+   (CONJUNCTS_THEN SUBST1_TAC)
+  THENL
+   [CONJ_TAC THEN MATCH_MP_TAC COMPLEX_NORM_VSUM_SUM_RE;
+    MATCH_MP_TAC SUM_SUBSET THEN REWRITE_TAC[IN_DIFF]] THEN
+  ASM_MESON_TAC[REAL_LE_TRANS; NORM_POS_LE; FINITE_SUBSET; SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Geometric progression.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let VSUM_GP_BASIC = prove
+ (`!x n. (Cx(&1) - x) * vsum(0..n) (\i. x pow i) = Cx(&1) - x pow (SUC n)`,
+  GEN_TAC THEN INDUCT_TAC THEN REWRITE_TAC[VSUM_CLAUSES_NUMSEG] THEN
+  REWRITE_TAC[complex_pow; COMPLEX_MUL_RID; LE_0] THEN
+  ASM_REWRITE_TAC[COMPLEX_ADD_LDISTRIB; complex_pow] THEN
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let VSUM_GP_MULTIPLIED = prove
+ (`!x m n. m <= n
+           ==> ((Cx(&1) - x) * vsum(m..n) (\i. x pow i) =
+                x pow m - x pow (SUC n))`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[VSUM_OFFSET_0; COMPLEX_POW_ADD; FINITE_NUMSEG;
+               COMPLEX_MUL_ASSOC; VSUM_GP_BASIC; VSUM_COMPLEX_RMUL] THEN
+  REWRITE_TAC[COMPLEX_SUB_RDISTRIB; GSYM COMPLEX_POW_ADD; COMPLEX_MUL_LID] THEN
+  ASM_SIMP_TAC[ARITH_RULE `m <= n ==> (SUC(n - m) + m = SUC n)`]);;
+
+let VSUM_GP = prove
+ (`!x m n.
+        vsum(m..n) (\i. x pow i) =
+                if n < m then Cx(&0)
+                else if x = Cx(&1) then Cx(&((n + 1) - m))
+                else (x pow m - x pow (SUC n)) / (Cx(&1) - x)`,
+  REPEAT GEN_TAC THEN
+  DISJ_CASES_TAC(ARITH_RULE `n < m \/ ~(n < m) /\ m <= n:num`) THEN
+  ASM_SIMP_TAC[VSUM_TRIV_NUMSEG; COMPLEX_VEC_0] THEN COND_CASES_TAC THENL
+   [ASM_REWRITE_TAC[COMPLEX_POW_ONE; VSUM_CONST_NUMSEG; COMPLEX_MUL_RID];
+    ALL_TAC] THEN
+  REWRITE_TAC[COMPLEX_CMUL; COMPLEX_MUL_RID] THEN
+  MATCH_MP_TAC(COMPLEX_FIELD
+   `~(z = Cx(&1)) /\ (Cx(&1) - z) * x = y ==> x = y / (Cx(&1) - z)`) THEN
+  ASM_SIMP_TAC[COMPLEX_DIV_LMUL; COMPLEX_SUB_0; VSUM_GP_MULTIPLIED]);;
+
+let VSUM_GP_OFFSET = prove
+ (`!x m n. vsum(m..m+n) (\i. x pow i) =
+                if x = Cx(&1) then Cx(&n) + Cx(&1)
+                else x pow m * (Cx(&1) - x pow (SUC n)) / (Cx(&1) - x)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[VSUM_GP; ARITH_RULE `~(m + n < m:num)`] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [REWRITE_TAC[REAL_OF_NUM_ADD; GSYM CX_ADD] THEN
+    AP_TERM_TAC THEN AP_TERM_TAC THEN ARITH_TAC;
+    REWRITE_TAC[complex_div; complex_pow; COMPLEX_POW_ADD] THEN
+    SIMPLE_COMPLEX_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basics about polynomial functions: extremal behaviour and root counts.    *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_SUB_POLYFUN = prove
+ (`!a x y n.
+   1 <= n
+   ==> vsum(0..n) (\i. a i * x pow i) - vsum(0..n) (\i. a i * y pow i) =
+       (x - y) *
+       vsum(0..n-1) (\j. vsum(j+1..n) (\i. a i * y pow (i - j - 1)) * x pow j)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[GSYM VSUM_SUB_NUMSEG; GSYM COMPLEX_SUB_LDISTRIB] THEN
+  GEN_REWRITE_TAC LAND_CONV [MATCH_MP VSUM_CLAUSES_LEFT (SPEC_ALL LE_0)] THEN
+  REWRITE_TAC[COMPLEX_SUB_REFL; complex_pow; COMPLEX_MUL_RZERO;
+      COMPLEX_ADD_LID] THEN
+  SIMP_TAC[COMPLEX_SUB_POW; ADD_CLAUSES] THEN
+  ONCE_REWRITE_TAC[COMPLEX_RING `a * x * s:complex = x * a * s`] THEN
+  SIMP_TAC[VSUM_COMPLEX_LMUL; FINITE_NUMSEG] THEN AP_TERM_TAC THEN
+  SIMP_TAC[GSYM VSUM_COMPLEX_LMUL; GSYM VSUM_COMPLEX_RMUL; FINITE_NUMSEG;
+           VSUM_VSUM_PRODUCT; FINITE_NUMSEG] THEN
+  MATCH_MP_TAC VSUM_EQ_GENERAL_INVERSES THEN
+  REPEAT(EXISTS_TAC `\(x:num,y:num). (y,x)`) THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; IN_ELIM_PAIR_THM; IN_NUMSEG] THEN
+  REWRITE_TAC[ARITH_RULE `a - b - c:num = a - (b + c)`; ADD_SYM] THEN
+  REWRITE_TAC[COMPLEX_MUL_AC] THEN ARITH_TAC);;
+
+let COMPLEX_SUB_POLYFUN_ALT = prove
+ (`!a x y n.
+    1 <= n
+    ==> vsum(0..n) (\i. a i * x pow i) - vsum(0..n) (\i. a i * y pow i) =
+        (x - y) *
+        vsum(0..n-1) (\j. vsum(0..n-j-1) (\k. a(j+k+1) * y pow k) * x pow j)`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[COMPLEX_SUB_POLYFUN] THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC VSUM_EQ_NUMSEG THEN X_GEN_TAC `j:num` THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC VSUM_EQ_GENERAL_INVERSES THEN
+  MAP_EVERY EXISTS_TAC
+   [`\i. i - (j + 1)`; `\k. j + k + 1`] THEN
+  REWRITE_TAC[IN_NUMSEG] THEN REPEAT STRIP_TAC THEN
+  TRY(BINOP_TAC THEN AP_TERM_TAC) THEN ASM_ARITH_TAC);;
+
+let COMPLEX_POLYFUN_LINEAR_FACTOR = prove
+ (`!a c n. ?b. !z. vsum(0..n) (\i. c(i) * z pow i) =
+                   (z - a) * vsum(0..n-1) (\i. b(i) * z pow i) +
+                    vsum(0..n) (\i. c(i) * a pow i)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM COMPLEX_EQ_SUB_RADD] THEN
+  ASM_CASES_TAC `n = 0` THENL
+   [EXISTS_TAC `\i:num. Cx(&0)` THEN
+    ASM_SIMP_TAC[VSUM_SING; NUMSEG_SING; complex_pow; COMPLEX_MUL_LZERO] THEN
+    REWRITE_TAC[COMPLEX_SUB_REFL; GSYM COMPLEX_VEC_0; VSUM_0] THEN
+    REWRITE_TAC[COMPLEX_VEC_0; COMPLEX_MUL_RZERO];
+    ASM_SIMP_TAC[COMPLEX_SUB_POLYFUN; LE_1] THEN
+    EXISTS_TAC `\j. vsum (j + 1..n) (\i. c i * a pow (i - j - 1))` THEN
+    REWRITE_TAC[]]);;
+
+let COMPLEX_POLYFUN_LINEAR_FACTOR_ROOT = prove
+ (`!a c n. vsum(0..n) (\i. c(i) * a pow i) = Cx(&0)
+           ==> ?b. !z. vsum(0..n) (\i. c(i) * z pow i) =
+                      (z - a) * vsum(0..n-1) (\i. b(i) * z pow i)`,
+  MESON_TAC[COMPLEX_POLYFUN_LINEAR_FACTOR; COMPLEX_ADD_RID]);;
+
+let COMPLEX_POLYFUN_EXTREMAL_LEMMA = prove
+ (`!c n e. &0 < e
+           ==> ?M. !z. M <= norm(z)
+                       ==> norm(vsum(0..n) (\i. c(i) * z pow i))
+                               <= e * norm(z) pow (n + 1)`,
+  GEN_TAC THEN INDUCT_TAC THEN SIMP_TAC[VSUM_CLAUSES_NUMSEG; LE_0] THEN
+  REPEAT STRIP_TAC THENL
+   [REWRITE_TAC[ADD_CLAUSES; complex_pow; REAL_POW_1; COMPLEX_MUL_RID] THEN
+    EXISTS_TAC `norm(c 0:complex) / e` THEN ASM_SIMP_TAC[REAL_LE_LDIV_EQ] THEN
+    REWRITE_TAC[REAL_MUL_AC];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o C MATCH_MP (REAL_ARITH `&0 < &1 / &2`)) THEN
+  DISCH_THEN(X_CHOOSE_TAC `M:real`) THEN
+  EXISTS_TAC `max M ((&1 / &2 + norm(c(n+1):complex)) / e)` THEN
+  X_GEN_TAC `z:complex` THEN REWRITE_TAC[REAL_MAX_LE] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `a + norm(y) <= b ==> norm(x) <= a ==> norm(x + y) <= b`) THEN
+  SIMP_TAC[ADD1; COMPLEX_NORM_MUL; COMPLEX_NORM_POW;
+           GSYM REAL_ADD_RDISTRIB; ARITH_RULE `(n + 1) + 1 = 1 + n + 1`] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [REAL_POW_ADD] THEN
+  REWRITE_TAC[REAL_MUL_ASSOC] THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM REAL_LE_LDIV_EQ; REAL_POW_LE; NORM_POS_LE; REAL_POW_1]);;
+
+let COMPLEX_POLYFUN_EXTREMAL = prove
+ (`!c n. (!k. k IN 1..n ==> c(k) = Cx(&0)) \/
+         !B. eventually (\z. norm(vsum(0..n) (\i. c(i) * z pow i)) >= B)
+                        at_infinity`,
+  GEN_TAC THEN MATCH_MP_TAC num_WF THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `n = 0` THEN
+  ASM_REWRITE_TAC[NUMSEG_CLAUSES; ARITH; NOT_IN_EMPTY] THEN
+  MP_TAC(ARITH_RULE `0 <= n`) THEN SIMP_TAC[GSYM NUMSEG_RREC] THEN
+  DISCH_THEN(K ALL_TAC) THEN ASM_CASES_TAC `c(n:num) = Cx(&0)` THENL
+   [FIRST_X_ASSUM(MP_TAC o SPEC `n - 1`) THEN
+    ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+    ASM_SIMP_TAC[GSYM NUMSEG_RREC; LE_1] THEN
+    SIMP_TAC[IN_INSERT; VSUM_CLAUSES; FINITE_NUMSEG; IN_NUMSEG] THEN
+    ASM_REWRITE_TAC[COMPLEX_MUL_LZERO; COMPLEX_ADD_LID; COND_ID] THEN
+    ASM_MESON_TAC[];
+    DISJ2_TAC THEN MP_TAC(ISPECL
+      [`c:num->complex`; `n - 1`; `norm(c(n:num):complex) / &2`]
+      COMPLEX_POLYFUN_EXTREMAL_LEMMA) THEN ASM_SIMP_TAC[SUB_ADD; LE_1] THEN
+    ASM_SIMP_TAC[COMPLEX_NORM_NZ; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+    SIMP_TAC[IN_INSERT; VSUM_CLAUSES; FINITE_NUMSEG; IN_NUMSEG] THEN
+    ASM_SIMP_TAC[ARITH_RULE `~(n = 0) ==> ~(n <= n - 1)`] THEN
+    DISCH_THEN(X_CHOOSE_TAC `M:real`) THEN X_GEN_TAC `B:real` THEN
+    REWRITE_TAC[EVENTUALLY_AT_INFINITY] THEN EXISTS_TAC
+     `max M (max (&1) ((abs B + &1) / (norm(c(n:num):complex) / &2)))` THEN
+    X_GEN_TAC `z:complex` THEN REWRITE_TAC[real_ge; REAL_MAX_LE] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(NORM_ARITH
+     `abs b + &1 <= norm(y) - a ==> norm(x) <= a ==> b <= norm(y + x)`) THEN
+    REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_POW] THEN
+    REWRITE_TAC[REAL_ARITH `c * x - c / &2 * x = x * c / &2`] THEN
+    ASM_SIMP_TAC[GSYM REAL_LE_LDIV_EQ; COMPLEX_NORM_NZ; REAL_LT_DIV;
+                 REAL_OF_NUM_LT; ARITH] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `norm(z:complex) pow 1` THEN
+    CONJ_TAC THENL [ASM_REWRITE_TAC[REAL_POW_1]; ALL_TAC] THEN
+    MATCH_MP_TAC REAL_POW_MONO THEN ASM_SIMP_TAC[LE_1]]);;
+
+let COMPLEX_POLYFUN_ROOTBOUND = prove
+ (`!n c. ~(!i. i IN 0..n ==> c(i) = Cx(&0))
+         ==> FINITE {z | vsum(0..n) (\i. c(i) * z pow i) = Cx(&0)} /\
+             CARD {z | vsum(0..n) (\i. c(i) * z pow i) = Cx(&0)} <= n`,
+  REWRITE_TAC[TAUT `~a ==> b <=> a \/ b`] THEN INDUCT_TAC THEN GEN_TAC THENL
+   [SIMP_TAC[NUMSEG_SING; VSUM_SING; IN_SING; complex_pow] THEN
+    ASM_CASES_TAC `c 0 = Cx(&0)` THEN ASM_REWRITE_TAC[COMPLEX_MUL_RID] THEN
+    REWRITE_TAC[EMPTY_GSPEC; FINITE_RULES; CARD_CLAUSES; LE_REFL];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `{z | vsum(0..SUC n) (\i. c(i) * z pow i) = Cx(&0)} = {}` THEN
+  ASM_REWRITE_TAC[FINITE_RULES; CARD_CLAUSES; LE_0] THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `a:complex` MP_TAC o
+    GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP COMPLEX_POLYFUN_LINEAR_FACTOR_ROOT) THEN
+  DISCH_THEN(X_CHOOSE_TAC `b:num->complex`) THEN
+  ASM_REWRITE_TAC[COMPLEX_ENTIRE; COMPLEX_SUB_0; SUC_SUB1; SET_RULE
+   `{z | z = a \/ P z} = a INSERT {z | P z}`] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `b:num->complex`) THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[CARD_CLAUSES; FINITE_RULES] THENL
+   [DISJ1_TAC; ASM_ARITH_TAC] THEN
+  MP_TAC(SPECL [`c:num->complex`; `SUC n`] COMPLEX_POLYFUN_EXTREMAL) THEN
+  ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MP_TAC o SPEC `Cx(&0)`) THEN
+  ASM_SIMP_TAC[SUC_SUB1; COMPLEX_MUL_LZERO] THEN
+  SIMP_TAC[COMPLEX_POW_ZERO; COND_RAND; COMPLEX_MUL_RZERO] THEN
+  ASM_SIMP_TAC[VSUM_0; GSYM COMPLEX_VEC_0; VSUM_DELTA; IN_NUMSEG; LE_0] THEN
+  REWRITE_TAC[COMPLEX_VEC_0; COMPLEX_MUL_RZERO; COMPLEX_NORM_NUM] THEN
+  REWRITE_TAC[COMPLEX_MUL_RID; real_ge; EVENTUALLY_AT_INFINITY] THEN
+  REPEAT STRIP_TAC THENL [ASM_MESON_TAC[LE_1]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `&1`) THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  MATCH_MP_TAC(TAUT `~a ==> a ==> b`) THEN
+  REWRITE_TAC[NOT_EXISTS_THM; NOT_FORALL_THM] THEN X_GEN_TAC `b:real` THEN
+  MP_TAC(SPEC `b:real` (INST_TYPE [`:2`,`:N`] VECTOR_CHOOSE_SIZE)) THEN
+  ASM_MESON_TAC[NORM_POS_LE; REAL_LE_TOTAL; REAL_LE_TRANS]);;
+
+let COMPLEX_POLYFUN_FINITE_ROOTS = prove
+ (`!n c. FINITE {x | vsum(0..n) (\i. c i * x pow i) = Cx(&0)} <=>
+         ?i. i IN 0..n /\ ~(c i = Cx(&0))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[TAUT `a /\ ~b <=> ~(a ==> b)`] THEN
+  REWRITE_TAC[GSYM NOT_FORALL_THM] THEN EQ_TAC THEN
+  SIMP_TAC[COMPLEX_POLYFUN_ROOTBOUND] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  SIMP_TAC[COMPLEX_MUL_LZERO] THEN SIMP_TAC[GSYM COMPLEX_VEC_0; VSUM_0] THEN
+  REWRITE_TAC[SET_RULE `{x | T} = (:complex)`; GSYM INFINITE;
+              EUCLIDEAN_SPACE_INFINITE]);;
+
+let COMPLEX_POLYFUN_EQ_0 = prove
+ (`!n c. (!z. vsum(0..n) (\i. c i * z pow i) = Cx(&0)) <=>
+         (!i. i IN 0..n ==> c i = Cx(&0))`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+   [GEN_REWRITE_TAC I [TAUT `p <=> ~ ~p`] THEN DISCH_THEN(MP_TAC o MATCH_MP
+     COMPLEX_POLYFUN_ROOTBOUND) THEN
+    ASM_REWRITE_TAC[EUCLIDEAN_SPACE_INFINITE; GSYM INFINITE; DE_MORGAN_THM;
+                    SET_RULE `{x | T} = (:complex)`];
+    ASM_SIMP_TAC[IN_NUMSEG; LE_0; COMPLEX_MUL_LZERO] THEN
+    REWRITE_TAC[GSYM COMPLEX_VEC_0; VSUM_0]]);;
+
+let COMPLEX_POLYFUN_EQ_CONST = prove
+ (`!n c k. (!z. vsum(0..n) (\i. c i * z pow i) = k) <=>
+           c 0 = k /\ (!i. i IN 1..n ==> c i = Cx(&0))`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `!x. vsum(0..n) (\i. (if i = 0 then c 0 - k else c i) * x pow i) =
+        Cx(&0)` THEN
+  CONJ_TAC THENL
+   [SIMP_TAC[VSUM_CLAUSES_LEFT; LE_0; complex_pow; COMPLEX_MUL_RID] THEN
+    REWRITE_TAC[COMPLEX_RING `(c - k) + s = Cx(&0) <=> c + s = k`] THEN
+    AP_TERM_TAC THEN ABS_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    AP_TERM_TAC THEN MATCH_MP_TAC VSUM_EQ THEN GEN_TAC THEN
+    REWRITE_TAC[IN_NUMSEG] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[ARITH];
+    REWRITE_TAC[COMPLEX_POLYFUN_EQ_0; IN_NUMSEG; LE_0] THEN
+    GEN_REWRITE_TAC LAND_CONV [MESON[]
+     `(!n. P n) <=> P 0 /\ (!n. ~(n = 0) ==> P n)`] THEN
+    SIMP_TAC[LE_0; COMPLEX_SUB_0] THEN MESON_TAC[LE_1]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex products.                                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let cproduct = new_definition
+  `cproduct = iterate (( * ):complex->complex->complex)`;;
+
+let NEUTRAL_COMPLEX_MUL = prove
+ (`neutral(( * ):complex->complex->complex) = Cx(&1)`,
+  REWRITE_TAC[neutral] THEN MATCH_MP_TAC SELECT_UNIQUE THEN
+  MESON_TAC[COMPLEX_MUL_LID; COMPLEX_MUL_RID]);;
+
+let MONOIDAL_COMPLEX_MUL = prove
+ (`monoidal(( * ):complex->complex->complex)`,
+  REWRITE_TAC[monoidal; NEUTRAL_COMPLEX_MUL] THEN SIMPLE_COMPLEX_ARITH_TAC);;
+
+let CPRODUCT_CLAUSES = prove
+ (`(!f. cproduct {} f = Cx(&1)) /\
+   (!x f s. FINITE(s)
+            ==> (cproduct (x INSERT s) f =
+                 if x IN s then cproduct s f else f(x) * cproduct s f))`,
+  REWRITE_TAC[cproduct; GSYM NEUTRAL_COMPLEX_MUL] THEN
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+  MATCH_MP_TAC ITERATE_CLAUSES THEN REWRITE_TAC[MONOIDAL_COMPLEX_MUL]);;
+
+let CPRODUCT_EQ_0 = prove
+ (`!f s. FINITE s ==> (cproduct s f = Cx(&0) <=> ?x. x IN s /\ f(x) = Cx(&0))`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[CPRODUCT_CLAUSES; COMPLEX_ENTIRE; IN_INSERT; CX_INJ; REAL_OF_NUM_EQ;
+           ARITH; NOT_IN_EMPTY] THEN
+  MESON_TAC[]);;
+
+let CPRODUCT_INV = prove
+ (`!f s. FINITE s ==> cproduct s (\x. inv(f x)) = inv(cproduct s f)`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[CPRODUCT_CLAUSES; COMPLEX_INV_1; COMPLEX_INV_MUL]);;
+
+let CPRODUCT_MUL = prove
+ (`!f g s. FINITE s
+           ==> cproduct s (\x. f x * g x) = cproduct s f * cproduct s g`,
+  GEN_TAC THEN GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[CPRODUCT_CLAUSES; COMPLEX_MUL_AC; COMPLEX_MUL_LID]);;
+
+let CPRODUCT_EQ_1 = prove
+ (`!f s. (!x:A. x IN s ==> (f(x) = Cx(&1))) ==> (cproduct s f = Cx(&1))`,
+  REWRITE_TAC[cproduct; GSYM NEUTRAL_COMPLEX_MUL] THEN
+  SIMP_TAC[ITERATE_EQ_NEUTRAL; MONOIDAL_COMPLEX_MUL]);;
+
+let CPRODUCT_1 = prove
+ (`!s. cproduct s (\n. Cx(&1)) = Cx(&1)`,
+  SIMP_TAC[CPRODUCT_EQ_1]);;
+
+let CPRODUCT_POW = prove
+ (`!f s n. FINITE s
+           ==> cproduct s (\x. f x pow n) = (cproduct s f) pow n`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  DISCH_TAC THEN INDUCT_TAC THEN
+  ASM_SIMP_TAC[complex_pow; CPRODUCT_MUL; CPRODUCT_1]);;
+
+let NORM_CPRODUCT = prove
+ (`!f s. FINITE s ==> norm(cproduct s f) = product s (\x. norm(f x))`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[CPRODUCT_CLAUSES; COMPLEX_NORM_CX; REAL_ABS_NUM;
+           CPRODUCT_MUL; PRODUCT_CLAUSES; COMPLEX_NORM_MUL]);;
+
+let CPRODUCT_EQ = prove
+ (`!f g s. (!x. x IN s ==> (f x = g x)) ==> cproduct s f = cproduct s g`,
+  REWRITE_TAC[cproduct] THEN MATCH_MP_TAC ITERATE_EQ THEN
+  REWRITE_TAC[MONOIDAL_COMPLEX_MUL]);;
diff --git a/Multivariate/convex.ml b/Multivariate/convex.ml
new file mode 100644 (file)
index 0000000..05ebcdf
--- /dev/null
@@ -0,0 +1,11398 @@
+(* ========================================================================= *)
+(* Convex sets, functions and related things.                                *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(*                 (c) Copyright, Lars Schewe 2007                           *)
+(*              (c) Copyright, Valentina Bruno 2010                          *)
+(* ========================================================================= *)
+
+needs "Multivariate/topology.ml";;
+
+(* ------------------------------------------------------------------------- *)
+(* Some miscelleneous things that are convenient to prove here.              *)
+(* ------------------------------------------------------------------------- *)
+
+let TRANSLATION_GALOIS = prove
+ (`!s t a:real^N. s = IMAGE (\x. a + x) t <=> t = IMAGE (\x. --a + x) s`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_o; o_DEF] THEN
+  REWRITE_TAC[VECTOR_ARITH `--a + a + x:real^N = x`;
+              VECTOR_ARITH `a + --a + x:real^N = x`] THEN
+  REWRITE_TAC[IMAGE_ID]);;
+
+let TRANSLATION_EQ_IMP = prove
+ (`!P:(real^N->bool)->bool.
+        (!a s. P(IMAGE (\x. a + x) s) <=> P s) <=>
+        (!a s. P s ==> P (IMAGE (\x. a + x) s))`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `s:real^N->bool`] THEN
+  EQ_TAC THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN FIRST_X_ASSUM
+   (MP_TAC o SPECL [`--a:real^N`; `IMAGE (\x:real^N. a + x) s`]) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID;
+                  VECTOR_ARITH `--a + a + x:real^N = x`]);;
+
+let DIM_HYPERPLANE = prove
+ (`!a:real^N. ~(a = vec 0) ==> dim {x | a dot x = &0} = dimindex(:N) - 1`,
+  GEOM_BASIS_MULTIPLE_TAC 1 `a:real^N` THEN
+  SIMP_TAC[VECTOR_MUL_EQ_0; DE_MORGAN_THM; DOT_LMUL; DOT_BASIS;
+           DIMINDEX_GE_1; LE_REFL; REAL_ENTIRE; DIM_SPECIAL_HYPERPLANE]);;
+
+let LOWDIM_EQ_HYPERPLANE = prove
+ (`!s. dim s = dimindex(:N) - 1
+       ==> ?a:real^N. ~(a = vec 0) /\ span s = {x | a dot x = &0}`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `s:real^N->bool` LOWDIM_SUBSET_HYPERPLANE) THEN
+  ASM_SIMP_TAC[DIMINDEX_GE_1; ARITH_RULE `1 <= a ==> a - 1 < a`] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPEC `a:real^N` SUBSPACE_HYPERPLANE) THEN
+  ONCE_REWRITE_TAC[GSYM SPAN_EQ_SELF] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC DIM_EQ_SPAN THEN
+  ASM_SIMP_TAC[DIM_HYPERPLANE; LE_REFL] THEN
+  ASM_MESON_TAC[SUBSET_TRANS; SPAN_INC]);;
+
+let DIM_EQ_HYPERPLANE = prove
+ (`!s. dim s = dimindex(:N) - 1 <=>
+       ?a:real^N. ~(a = vec 0) /\ span s = {x | a dot x = &0}`,
+  MESON_TAC[DIM_HYPERPLANE; LOWDIM_EQ_HYPERPLANE; DIM_SPAN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Affine set and affine hull.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let affine = new_definition
+  `affine s <=> !x y u v. x IN s /\ y IN s /\ (u + v = &1)
+                          ==> (u % x + v % y) IN s`;;
+
+let AFFINE_ALT = prove
+ (`affine s <=> !x y u. x IN s /\ y IN s ==> ((&1 - u) % x + u % y) IN s`,
+  REWRITE_TAC[affine] THEN
+  MESON_TAC[REAL_ARITH `(u + v = &1) <=> (u = &1 - v)`]);;
+
+let AFFINE_SCALING = prove
+ (`!s c. affine s ==> affine (IMAGE (\x. c % x) s)`,
+  REWRITE_TAC[affine; IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+   `u % c % x + v % c % y = c % (u % x + v % y)`] THEN
+  ASM_MESON_TAC[]);;
+
+let AFFINE_SCALING_EQ = prove
+ (`!s c. ~(c = &0) ==> (affine (IMAGE (\x. c % x) s) <=> affine s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REWRITE_TAC[AFFINE_SCALING] THEN
+  DISCH_THEN(MP_TAC o SPEC `inv c` o MATCH_MP AFFINE_SCALING) THEN
+  ASM_SIMP_TAC[GSYM IMAGE_o; o_DEF; VECTOR_MUL_ASSOC;
+               REAL_MUL_LINV; VECTOR_MUL_LID; IMAGE_ID]);;
+
+let AFFINE_NEGATIONS = prove
+ (`!s. affine s ==> affine (IMAGE (--) s)`,
+  REWRITE_TAC[affine; IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+   `u % --x + v % --y = --(u % x + v % y)`] THEN
+  ASM_MESON_TAC[]);;
+
+let AFFINE_SUMS = prove
+ (`!s t. affine s /\ affine t ==> affine {x + y | x IN s /\ y IN t}`,
+  REWRITE_TAC[affine; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+    `u % (a + b) + v % (c + d) = (u % a + v % c) + (u % b + v % d)`] THEN
+  ASM_MESON_TAC[]);;
+
+let AFFINE_DIFFERENCES = prove
+ (`!s t. affine s /\ affine t ==> affine {x - y | x IN s /\ y IN t}`,
+  REWRITE_TAC[affine; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+    `u % (a - b) + v % (c - d) = (u % a + v % c) - (u % b + v % d)`] THEN
+  ASM_MESON_TAC[]);;
+
+let AFFINE_TRANSLATION_EQ = prove
+ (`!a:real^N s. affine (IMAGE (\x. a + x) s) <=> affine s`,
+  REWRITE_TAC[AFFINE_ALT; IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[IN_IMAGE; UNWIND_THM1; VECTOR_ARITH
+   `(&1 - u) % (a + x) + u % (a + y) = a + z <=> (&1 - u) % x + u % y = z`]);;
+
+add_translation_invariants [AFFINE_TRANSLATION_EQ];;
+
+let AFFINE_TRANSLATION = prove
+ (`!s a:real^N. affine s ==> affine (IMAGE (\x. a + x) s)`,
+  REWRITE_TAC[AFFINE_TRANSLATION_EQ]);;
+
+let AFFINE_AFFINITY = prove
+ (`!s a:real^N c.
+        affine s ==> affine (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; AFFINE_TRANSLATION; AFFINE_SCALING]);;
+
+let AFFINE_LINEAR_IMAGE = prove
+ (`!f s. affine s /\ linear f ==> affine(IMAGE f s)`,
+  REWRITE_TAC[affine; FORALL_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[IN_IMAGE; linear] THEN MESON_TAC[]);;
+
+let AFFINE_LINEAR_IMAGE_EQ = prove
+ (`!f s. linear f /\ (!x y. f x = f y ==> x = y)
+         ==> (affine (IMAGE f s) <=> affine s)`,
+  MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE AFFINE_LINEAR_IMAGE));;
+
+add_linear_invariants [AFFINE_LINEAR_IMAGE_EQ];;
+
+let AFFINE_EMPTY = prove
+ (`affine {}`,
+  REWRITE_TAC[affine; NOT_IN_EMPTY]);;
+
+let AFFINE_SING = prove
+ (`!x. affine {x}`,
+  SIMP_TAC[AFFINE_ALT; IN_SING] THEN
+  REWRITE_TAC[GSYM VECTOR_ADD_RDISTRIB] THEN
+  REWRITE_TAC[REAL_SUB_ADD; VECTOR_MUL_LID]);;
+
+let AFFINE_UNIV = prove
+ (`affine(UNIV:real^N->bool)`,
+  REWRITE_TAC[affine; IN_UNIV]);;
+
+let AFFINE_HYPERPLANE = prove
+ (`!a b. affine {x | a dot x = b}`,
+  REWRITE_TAC[affine; IN_ELIM_THM; DOT_RADD; DOT_RMUL] THEN
+  CONV_TAC REAL_RING);;
+
+let AFFINE_STANDARD_HYPERPLANE = prove
+ (`!a b k. affine {x:real^N | x$k = b}`,
+  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`; `b:real`] AFFINE_HYPERPLANE) THEN
+  ASM_SIMP_TAC[DOT_BASIS]);;
+
+let AFFINE_INTERS = prove
+ (`(!s. s IN f ==> affine s) ==> affine(INTERS f)`,
+  REWRITE_TAC[affine; IN_INTERS] THEN MESON_TAC[]);;
+
+let AFFINE_INTER = prove
+ (`!s t. affine s /\ affine t ==> affine(s INTER t)`,
+  REWRITE_TAC[affine; IN_INTER] THEN MESON_TAC[]);;
+
+let AFFINE_AFFINE_HULL = prove
+ (`!s. affine(affine hull s)`,
+  SIMP_TAC[P_HULL; AFFINE_INTERS]);;
+
+let AFFINE_HULL_EQ = prove
+ (`!s. (affine hull s = s) <=> affine s`,
+  SIMP_TAC[HULL_EQ; AFFINE_INTERS]);;
+
+let IS_AFFINE_HULL = prove
+ (`!s. affine s <=> ?t. s = affine hull t`,
+  GEN_TAC THEN MATCH_MP_TAC IS_HULL THEN SIMP_TAC[AFFINE_INTERS]);;
+
+let AFFINE_HULL_UNIV = prove
+ (`affine hull (:real^N) = (:real^N)`,
+  REWRITE_TAC[AFFINE_HULL_EQ; AFFINE_UNIV]);;
+
+let AFFINE_HULLS_EQ = prove
+ (`!s t. s SUBSET affine hull t /\ t SUBSET affine hull s
+         ==> affine hull s = affine hull t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HULLS_EQ THEN
+  ASM_SIMP_TAC[AFFINE_INTERS]);;
+
+let AFFINE_HULL_TRANSLATION = prove
+ (`!a s. affine hull (IMAGE (\x. a + x) s) =
+         IMAGE (\x. a + x) (affine hull s)`,
+  REWRITE_TAC[hull] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [AFFINE_HULL_TRANSLATION];;
+
+let AFFINE_HULL_LINEAR_IMAGE = prove
+ (`!f s. linear f
+         ==> affine hull (IMAGE f s) = IMAGE f (affine hull s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  CONJ_TAC THEN MATCH_MP_TAC HULL_INDUCT THEN
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN SIMP_TAC[FUN_IN_IMAGE; HULL_INC] THEN
+  REWRITE_TAC[affine; IN_ELIM_THM] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THENL
+   [FIRST_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP LINEAR_CMUL th)]) THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP LINEAR_ADD th)]) THEN
+    REWRITE_TAC[IN_IMAGE] THEN
+    MESON_TAC[REWRITE_RULE[affine] AFFINE_AFFINE_HULL];
+    ASM_SIMP_TAC[LINEAR_ADD; LINEAR_CMUL] THEN
+    MESON_TAC[REWRITE_RULE[affine] AFFINE_AFFINE_HULL]]);;
+
+add_linear_invariants [AFFINE_HULL_LINEAR_IMAGE];;
+
+let IN_AFFINE_HULL_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s x.
+        linear f /\ x IN affine hull s ==> (f x) IN affine hull (IMAGE f s)`,
+  SIMP_TAC[AFFINE_HULL_LINEAR_IMAGE] THEN SET_TAC[]);;
+
+let SAME_DISTANCES_TO_AFFINE_HULL = prove
+ (`!s a b:real^N.
+        (!x. x IN s ==> dist(x,a) = dist(x,b))
+        ==> (!x. x IN affine hull s ==> dist(x,a) = dist(x,b))`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC HULL_INDUCT THEN
+  ASM_REWRITE_TAC[AFFINE_ALT; IN_ELIM_THM] THEN
+  REWRITE_TAC[dist; NORM_EQ_SQUARE; NORM_POS_LE; VECTOR_ARITH
+   `((&1 - u) % x + u % y) - a:real^N = (&1 - u) % (x - a) + u % (y - a)`] THEN
+  REWRITE_TAC[NORM_POW_2; DOT_LMUL; DOT_RMUL; VECTOR_ARITH
+   `(x + y) dot (x + y):real^N = (x dot x + y dot y) + &2 * x dot y`] THEN
+  SIMP_TAC[DOT_LSUB; DOT_RSUB; DOT_SYM] THEN CONV_TAC REAL_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some convenient lemmas about common affine combinations.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let IN_AFFINE_ADD_MUL = prove
+ (`!s a x:real^N d. affine s /\ a IN s /\ (a + x) IN s ==> (a + d % x) IN s`,
+  REWRITE_TAC[affine] THEN REPEAT STRIP_TAC THEN
+  SUBST1_TAC(VECTOR_ARITH `a + d % x:real^N = (&1 - d) % a + d % (a + x)`) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let IN_AFFINE_ADD_MUL_DIFF = prove
+ (`!s a x y z:real^N.
+        affine s /\ x IN s /\ y IN s /\ z IN s ==> (x + a % (y - z)) IN s`,
+  REWRITE_TAC[affine] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `x + a % (y - z):real^N =
+    &1 / &2 % ((&1 - &2 * a) % x + (&2 * a) % y) +
+    &1 / &2 % ((&1 + &2 * a) % x + (-- &2 * a) % z)`] THEN
+  FIRST_ASSUM MATCH_MP_TAC THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  CONJ_TAC THEN FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  REAL_ARITH_TAC);;
+
+let IN_AFFINE_MUL_DIFF_ADD = prove
+ (`!s a x y z:real^N.
+        affine s /\ x IN s /\ y IN s /\ z IN s ==> a % (x - y) + z IN s`,
+  ONCE_REWRITE_TAC[VECTOR_ADD_SYM] THEN
+  SIMP_TAC[IN_AFFINE_ADD_MUL_DIFF]);;
+
+let IN_AFFINE_SUB_MUL_DIFF = prove
+ (`!s a x y z:real^N.
+        affine s /\ x IN s /\ y IN s /\ z IN s ==> x - a % (y - z) IN s`,
+  REWRITE_TAC[VECTOR_ARITH `x - a % (y - z):real^N = x + a % (z - y)`] THEN
+  SIMP_TAC[IN_AFFINE_ADD_MUL_DIFF]);;
+
+let AFFINE_DIFFS_SUBSPACE = prove
+ (`!s:real^N->bool a.
+        affine s /\ a IN s ==> subspace {x - a | x IN s}`,
+  REWRITE_TAC[subspace; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  REWRITE_TAC[VECTOR_ARITH `vec 0:real^N = x - a <=> x = a`;
+              VECTOR_ARITH `x - a + y - a:real^N = z - a <=>
+                            z = (a + &1 % (x - a)) + &1 % (y - a)`;
+              VECTOR_ARITH `c % (x - a):real^N = y - a <=>
+                            y = a + c % (x - a)`] THEN
+  MESON_TAC[IN_AFFINE_ADD_MUL_DIFF]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Explicit formulations for affine combinations.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let AFFINE_VSUM = prove
+ (`!s k u x:A->real^N.
+        FINITE k /\ affine s /\ sum k u = &1 /\ (!i. i IN k ==> x i IN s)
+        ==> vsum k (\i. u i % x i) IN s`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[NOT_IN_EMPTY; GSYM NOT_EXISTS_THM; MEMBER_NOT_EMPTY] THEN
+    ASM_CASES_TAC `k:A->bool = {}` THEN ASM_REWRITE_TAC[SUM_CLAUSES] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `a:real^N`] AFFINE_DIFFS_SUBSPACE) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`{x - a:real^N | x IN s}`;
+                 `(\i. u i % (x i - a)):A->real^N`;
+                 `k:A->bool`] SUBSPACE_VSUM) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC SUBSPACE_MUL THEN ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    ASM_SIMP_TAC[VSUM_SUB; IN_ELIM_THM; VECTOR_SUB_LDISTRIB; VSUM_RMUL] THEN
+    REWRITE_TAC[VECTOR_ARITH `x - &1 % a:real^N = y - a <=> x = y`] THEN
+    ASM_MESON_TAC[]]);;
+
+let AFFINE_INDEXED = prove
+ (`!s:real^N->bool.
+        affine s <=>
+            !k u x. (!i:num. 1 <= i /\ i <= k ==> x(i) IN s) /\
+                    (sum (1..k) u = &1)
+                    ==> vsum (1..k) (\i. u(i) % x(i)) IN s`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC AFFINE_VSUM THEN
+    ASM_REWRITE_TAC[IN_NUMSEG; FINITE_NUMSEG];
+    DISCH_TAC THEN REWRITE_TAC[affine] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`; `u:real`; `v:real`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `2`) THEN
+    DISCH_THEN(MP_TAC o SPEC `\n. if n = 1 then u else v:real`) THEN
+    DISCH_THEN(MP_TAC o SPEC `\n. if n = 1 then x else y:real^N`) THEN
+    REWRITE_TAC[num_CONV `2`; SUM_CLAUSES_NUMSEG; VSUM_CLAUSES_NUMSEG;
+      NUMSEG_SING; VSUM_SING; SUM_SING] THEN REWRITE_TAC[ARITH] THEN
+    ASM_MESON_TAC[]]);;
+
+let AFFINE_HULL_INDEXED = prove
+ (`!s. affine hull s =
+        {y:real^N | ?k u x. (!i. 1 <= i /\ i <= k ==> x i IN s) /\
+                            (sum (1..k) u = &1) /\
+                            (vsum (1..k) (\i. u i % x i) = y)}`,
+  GEN_TAC THEN MATCH_MP_TAC HULL_UNIQUE THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC [`1`; `\i:num. &1`; `\i:num. x:real^N`] THEN
+    ASM_SIMP_TAC[FINITE_RULES; IN_SING; SUM_SING; VECTOR_MUL_LID; VSUM_SING;
+                 REAL_POS; NUMSEG_SING];
+    ALL_TAC;
+    REWRITE_TAC[AFFINE_INDEXED; SUBSET; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+    MESON_TAC[]] THEN
+  REWRITE_TAC[affine; IN_ELIM_THM] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`; `u:real`; `v:real`] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN MAP_EVERY X_GEN_TAC
+   [`k1:num`; `u1:num->real`; `x1:num->real^N`;
+    `k2:num`; `u2:num->real`; `x2:num->real^N`] THEN
+  STRIP_TAC THEN EXISTS_TAC `k1 + k2:num` THEN
+  EXISTS_TAC `\i:num. if i <= k1 then u * u1(i) else v * u2(i - k1):real` THEN
+  EXISTS_TAC `\i:num. if i <= k1 then x1(i) else x2(i - k1):real^N` THEN
+  ASM_SIMP_TAC[NUMSEG_ADD_SPLIT; ARITH_RULE `1 <= x + 1 /\ x < x + 1`;
+   IN_NUMSEG; SUM_UNION; VSUM_UNION; FINITE_NUMSEG; DISJOINT_NUMSEG;
+   ARITH_RULE `k1 + 1 <= i ==> ~(i <= k1)`] THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[ADD_SYM] NUMSEG_OFFSET_IMAGE] THEN
+  ASM_SIMP_TAC[SUM_IMAGE; VSUM_IMAGE; EQ_ADD_LCANCEL; FINITE_NUMSEG] THEN
+  ASM_SIMP_TAC[o_DEF; ADD_SUB2; SUM_LMUL; VSUM_LMUL; GSYM VECTOR_MUL_ASSOC;
+               FINITE_NUMSEG; REAL_MUL_RID] THEN
+  ASM_MESON_TAC[REAL_LE_MUL; ARITH_RULE
+    `i <= k1 + k2 /\ ~(i <= k1) ==> 1 <= i - k1 /\ i - k1 <= k2`]);;
+
+let AFFINE = prove
+ (`!V:real^N->bool.
+     affine V <=>
+         !(s:real^N->bool) (u:real^N->real).
+             FINITE s /\ ~(s = {}) /\ s SUBSET V /\ sum s u = &1
+             ==> vsum s (\x. u x % x) IN V`,
+  GEN_TAC THEN EQ_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC AFFINE_VSUM THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    REWRITE_TAC[affine] THEN DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`; `u:real`; `v:real`] THEN
+    STRIP_TAC THEN ASM_CASES_TAC `x:real^N = y` THENL
+     [FIRST_X_ASSUM SUBST_ALL_TAC THEN
+      ASM_REWRITE_TAC[GSYM VECTOR_ADD_RDISTRIB;VECTOR_MUL_LID];ALL_TAC] THEN
+     FIRST_X_ASSUM(MP_TAC o SPEC `{x:real^N,y}`) THEN
+    DISCH_THEN(MP_TAC o SPEC `\w. if w = x:real^N then u else v:real`) THEN
+    ASM_SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES; FINITE_RULES; NUMSEG_SING;
+                 VSUM_SING; SUM_SING;SUBSET;IN_INSERT;NOT_IN_EMPTY] THEN
+    ASM SET_TAC[]]);;
+
+let AFFINE_EXPLICIT = prove
+ (`!s:real^N->bool.
+        affine s <=>
+            !t u. FINITE t /\ t SUBSET s /\ sum t u = &1
+                  ==> vsum t (\x. u(x) % x) IN s`,
+  GEN_TAC THEN REWRITE_TAC[AFFINE] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `t:real^N->bool` THEN REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN ABS_TAC THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[SUM_CLAUSES] THEN CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let AFFINE_HULL_EXPLICIT = prove
+ (`!(p:real^N -> bool).
+        affine hull p =
+         {y | ?s u. FINITE s /\ ~(s = {}) /\ s SUBSET p /\
+                    sum s u = &1 /\ vsum s (\v. u v % v) = y}`,
+  GEN_TAC THEN MATCH_MP_TAC HULL_UNIQUE THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET;IN_ELIM_THM] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC [`{x:real^N}`;`\v:real^N. &1:real`] THEN
+    ASM_SIMP_TAC[FINITE_RULES;IN_SING;SUM_SING;VSUM_SING;VECTOR_MUL_LID] THEN
+    SET_TAC[];
+    REWRITE_TAC[affine;IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+    EXISTS_TAC `(s UNION s'):real^N->bool` THEN
+    EXISTS_TAC
+      `\a:real^N. (\b:real^N.if (b IN s) then (u * (u' b)) else &0) a +
+                  (\b:real^N.if (b IN s') then v * (u'' b) else &0) a` THEN
+    REPEAT CONJ_TAC THENL
+     [ASM_REWRITE_TAC[FINITE_UNION];
+      ASM SET_TAC[];
+      ASM_REWRITE_TAC[UNION_SUBSET];
+      ASM_SIMP_TAC[REWRITE_RULE[REAL_ARITH `a + b = c + d <=> c = a + b - d`]
+                   SUM_INCL_EXCL; GSYM SUM_RESTRICT_SET;
+                   SET_RULE `{a | a IN (s:A->bool) /\ a IN s'} = s INTER s'`;
+                   SUM_ADD;SUM_LMUL;REAL_MUL_RID;
+                   FINITE_INTER;INTER_IDEMPOT] THEN
+    ASM_REWRITE_TAC[SET_RULE `(a INTER b) INTER a = a INTER b`;
+                    SET_RULE `(a INTER b) INTER b = a INTER b`;
+                    REAL_ARITH `(a + b) + (c + d) - (e + b) = (a + d) + c - e`;
+                    REAL_ARITH `a + b - c = a <=> b = c`] THEN
+    AP_TERM_TAC THEN REWRITE_TAC[INTER_COMM];
+    ASM_SIMP_TAC[REWRITE_RULE
+                  [VECTOR_ARITH `(a:real^N) + b = c + d <=> c = a + b - d`]
+                  VSUM_INCL_EXCL;GSYM VSUM_RESTRICT_SET;
+                 SET_RULE `{a | a IN (s:A->bool) /\ a IN s'} = s INTER s'`;
+                 VSUM_ADD;FINITE_INTER;INTER_IDEMPOT;VECTOR_ADD_RDISTRIB;
+                 GSYM VECTOR_MUL_ASSOC;VSUM_LMUL;
+                 MESON[] `(if P then a else b) % (x:real^N) =
+                          (if P then a % x else b % x)`;
+                 VECTOR_MUL_LZERO;GSYM VSUM_RESTRICT_SET] THEN
+    ASM_REWRITE_TAC[SET_RULE `(a INTER b) INTER a = a INTER b`;
+                    SET_RULE `(a INTER b) INTER b = a INTER b`;
+                    VECTOR_ARITH
+                     `((a:real^N) + b) + (c + d) - (e + b) = (a + d) + c - e`;
+                    VECTOR_ARITH `(a:real^N) + b - c = a <=> b = c`] THEN
+    AP_TERM_TAC THEN REWRITE_TAC[INTER_COMM]];
+    ASM_CASES_TAC `(p:real^N->bool) = {}` THENL
+      [FIRST_X_ASSUM SUBST_ALL_TAC THEN
+       REWRITE_TAC[SUBSET_EMPTY;EMPTY_SUBSET] THEN ASM SET_TAC[];
+       ALL_TAC] THEN
+    REWRITE_TAC[AFFINE; SUBSET; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+    ASM SET_TAC[]]);;
+
+let AFFINE_HULL_EXPLICIT_ALT = prove
+ (`!(p:real^N -> bool).
+        affine hull p =
+         {y | ?s u. FINITE s /\ s SUBSET p /\
+                    sum s u = &1 /\ vsum s (\v. u v % v) = y}`,
+  GEN_TAC THEN REWRITE_TAC[AFFINE_HULL_EXPLICIT] THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  GEN_TAC THEN REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+  EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  POP_ASSUM MP_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  SIMP_TAC[SUM_CLAUSES; REAL_OF_NUM_EQ; ARITH_EQ]);;
+
+let AFFINE_HULL_FINITE = prove
+ (`!s:real^N->bool.
+        affine hull s = {y | ?u. sum s u = &1 /\ vsum s (\v. u v % v) = y}`,
+  GEN_TAC THEN GEN_REWRITE_TAC I [EXTENSION] THEN
+  REWRITE_TAC[AFFINE_HULL_EXPLICIT; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+   [MAP_EVERY X_GEN_TAC [`t:real^N->bool`; `f:real^N->real`] THEN
+    STRIP_TAC THEN
+    EXISTS_TAC `\x:real^N. if x IN t then f x else &0` THEN
+    REWRITE_TAC[COND_RAND; COND_RATOR; VECTOR_MUL_LZERO] THEN
+    REWRITE_TAC[GSYM SUM_RESTRICT_SET; GSYM VSUM_RESTRICT_SET] THEN
+    ASM_SIMP_TAC[SET_RULE `t SUBSET s ==> {x | x IN s /\ x IN t} = t`];
+    X_GEN_TAC `f:real^N->real` THEN
+    ASM_CASES_TAC `s:real^N->bool = {}` THEN
+    ASM_REWRITE_TAC[SUM_CLAUSES; REAL_OF_NUM_EQ; ARITH] THEN STRIP_TAC THEN
+    EXISTS_TAC `support (+) (f:real^N->real) s` THEN
+    EXISTS_TAC `f:real^N->real` THEN
+    MP_TAC(ASSUME `sum s (f:real^N->real) = &1`) THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [sum] THEN
+    REWRITE_TAC[iterate] THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[NEUTRAL_REAL_ADD; REAL_OF_NUM_EQ; ARITH] THEN
+    DISCH_THEN(K ALL_TAC) THEN
+    UNDISCH_TAC `sum s (f:real^N->real) = &1` THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [GSYM SUM_SUPPORT] THEN
+    ASM_CASES_TAC `support (+) (f:real^N->real) s = {}` THEN
+    ASM_SIMP_TAC[SUM_CLAUSES; REAL_OF_NUM_EQ; ARITH] THEN
+    DISCH_TAC THEN REWRITE_TAC[SUPPORT_SUBSET] THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [GSYM th]) THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_SUPERSET THEN
+    REWRITE_TAC[SUPPORT_SUBSET] THEN
+    REWRITE_TAC[support; IN_ELIM_THM; NEUTRAL_REAL_ADD] THEN
+    MESON_TAC[VECTOR_MUL_LZERO]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Stepping theorems and hence small special cases.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let AFFINE_HULL_EMPTY = prove
+ (`affine hull {} = {}`,
+  MATCH_MP_TAC HULL_UNIQUE THEN
+  REWRITE_TAC[SUBSET_REFL; AFFINE_EMPTY; EMPTY_SUBSET]);;
+
+let AFFINE_HULL_EQ_EMPTY = prove
+ (`!s. (affine hull s = {}) <=> (s = {})`,
+  GEN_TAC THEN EQ_TAC THEN
+  MESON_TAC[SUBSET_EMPTY; HULL_SUBSET; AFFINE_HULL_EMPTY]);;
+
+let AFFINE_HULL_FINITE_STEP_GEN = prove
+ (`!P:real^N->real->bool.
+        ((?u. (!x. x IN {} ==> P x (u x)) /\
+              sum {} u = w /\ vsum {} (\x. u(x) % x) = y) <=>
+         w = &0 /\ y = vec 0) /\
+        (FINITE(s:real^N->bool) /\
+         (!y. a IN s /\ P a y ==> P a (y / &2)) /\
+         (!x y. a IN s /\ P a x /\ P a y ==> P a (x + y))
+         ==> ((?u. (!x. x IN (a INSERT s) ==> P x (u x)) /\
+                   sum (a INSERT s) u = w /\
+                   vsum (a INSERT s) (\x. u(x) % x) = y) <=>
+              ?v u. P a v /\ (!x. x IN s ==> P x (u x)) /\
+                    sum s u = w - v /\
+                    vsum s (\x. u(x) % x) = y - v % a))`,
+  GEN_TAC THEN SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES; NOT_IN_EMPTY] THEN
+  CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN DISCH_TAC THEN
+  ASM_CASES_TAC `(a:real^N) IN s` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_SIMP_TAC[SET_RULE `a IN s ==> a INSERT s = s`] THEN EQ_TAC THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+     [X_GEN_TAC `u:real^N->real` THEN STRIP_TAC THEN
+      EXISTS_TAC `(u:real^N->real) a / &2` THEN
+      EXISTS_TAC `\x:real^N. if x = a then u x / &2 else u x`;
+      MAP_EVERY X_GEN_TAC [`v:real`; `u:real^N->real`] THEN
+      STRIP_TAC THEN
+      EXISTS_TAC `\x:real^N. if x = a then u x + v else u x`] THEN
+    ASM_SIMP_TAC[] THEN (CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC]) THEN
+    ONCE_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+    ASM_SIMP_TAC[VSUM_CASES; SUM_CASES] THEN
+    ASM_SIMP_TAC[GSYM DELETE; SUM_DELETE; VSUM_DELETE] THEN
+    ASM_SIMP_TAC[SET_RULE `a IN s ==> {x | x IN s /\ x = a} = {a}`] THEN
+    REWRITE_TAC[SUM_SING; VSUM_SING] THEN
+    (CONJ_TAC THENL [REAL_ARITH_TAC; VECTOR_ARITH_TAC]);
+    EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+     [X_GEN_TAC `u:real^N->real` THEN STRIP_TAC THEN
+      EXISTS_TAC `(u:real^N->real) a` THEN
+      EXISTS_TAC `u:real^N->real` THEN ASM_SIMP_TAC[IN_INSERT] THEN
+      REPEAT(FIRST_X_ASSUM(SUBST1_TAC o SYM)) THEN
+      CONJ_TAC THENL [REAL_ARITH_TAC; VECTOR_ARITH_TAC];
+      MAP_EVERY X_GEN_TAC [`v:real`; `u:real^N->real`] THEN
+      STRIP_TAC THEN
+      EXISTS_TAC `\x:real^N. if x = a then v:real else u x` THEN
+      ASM_SIMP_TAC[IN_INSERT] THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[]; ALL_TAC] THEN
+      ONCE_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+      ASM_SIMP_TAC[VSUM_CASES; SUM_CASES] THEN
+      ASM_SIMP_TAC[GSYM DELETE; SUM_DELETE; VSUM_DELETE] THEN
+      ASM_SIMP_TAC[SET_RULE `~(a IN s) ==> {x | x IN s /\ x = a} = {}`] THEN
+      ASM_SIMP_TAC[SET_RULE `~(a IN s) ==> s DELETE a = s`] THEN
+      REWRITE_TAC[SUM_CLAUSES; VSUM_CLAUSES] THEN
+      CONJ_TAC THENL [REAL_ARITH_TAC; VECTOR_ARITH_TAC]]]);;
+
+let AFFINE_HULL_FINITE_STEP = prove
+ (`((?u. sum {} u = w /\ vsum {} (\x. u(x) % x) = y) <=>
+    w = &0 /\ y = vec 0) /\
+   (FINITE(s:real^N->bool)
+    ==> ((?u. sum (a INSERT s) u = w /\
+              vsum (a INSERT s) (\x. u(x) % x) = y) <=>
+         ?v u.  sum s u = w - v /\
+                vsum s (\x. u(x) % x) = y - v % a))`,
+  MATCH_ACCEPT_TAC (REWRITE_RULE[]
+   (ISPEC `\x:real^N y:real. T` AFFINE_HULL_FINITE_STEP_GEN)));;
+
+let AFFINE_HULL_2 = prove
+ (`!a b. affine hull {a,b} =
+         {u % a + v % b | u + v = &1}`,
+  SIMP_TAC[AFFINE_HULL_FINITE; FINITE_INSERT; FINITE_RULES] THEN
+  SIMP_TAC[AFFINE_HULL_FINITE_STEP; FINITE_INSERT; FINITE_RULES] THEN
+  REWRITE_TAC[REAL_ARITH `x - y = z:real <=> x = y + z`;
+              VECTOR_ARITH `x - y = z:real^N <=> x = y + z`] THEN
+  REWRITE_TAC[VECTOR_ADD_RID; REAL_ADD_RID] THEN SET_TAC[]);;
+
+let AFFINE_HULL_2_ALT = prove
+ (`!a b. affine hull {a,b} = {a + u % (b - a) | u IN (:real)}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[AFFINE_HULL_2] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[IN_ELIM_THM; IN_UNIV; ARITH_RULE `u + v = &1 <=> v = &1 - u`;
+    FORALL_UNWIND_THM2; UNWIND_THM2] THEN
+  CONJ_TAC THEN X_GEN_TAC `u:real` THEN EXISTS_TAC `&1 - u` THEN
+  VECTOR_ARITH_TAC);;
+
+let AFFINE_HULL_3 = prove
+ (`affine hull {a,b,c} =
+    { u % a + v % b + w % c | u + v + w = &1}`,
+  SIMP_TAC[AFFINE_HULL_FINITE; FINITE_INSERT; FINITE_RULES] THEN
+  SIMP_TAC[AFFINE_HULL_FINITE_STEP; FINITE_INSERT; FINITE_RULES] THEN
+  REWRITE_TAC[REAL_ARITH `x - y = z:real <=> x = y + z`;
+              VECTOR_ARITH `x - y = z:real^N <=> x = y + z`] THEN
+  REWRITE_TAC[VECTOR_ADD_RID; REAL_ADD_RID] THEN SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some relations between affine hull and subspaces.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let AFFINE_HULL_INSERT_SUBSET_SPAN = prove
+ (`!a:real^N s.
+     affine hull (a INSERT s) SUBSET {a + v | v | v IN span {x - a | x IN s}}`,
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC I [SUBSET] THEN
+  REWRITE_TAC[AFFINE_HULL_EXPLICIT; SPAN_EXPLICIT; IN_ELIM_THM] THEN
+  REWRITE_TAC[SIMPLE_IMAGE; CONJ_ASSOC; FINITE_SUBSET_IMAGE] THEN
+  REWRITE_TAC[MESON[]
+   `(?s u. (?t. P t /\ s = f t) /\ Q s u) <=>
+    (?t u. P t /\ Q (f t) u)`] THEN
+  REWRITE_TAC[MESON[]
+   `(?v. (?s u. P s /\ f s u = v) /\ (x = g a v)) <=>
+    (?s u. ~(P s ==> ~(g a (f s u) = x)))`] THEN
+  SIMP_TAC[VSUM_IMAGE; VECTOR_ARITH `x - a:real^N = y - a <=> x = y`] THEN
+  REWRITE_TAC[o_DEF] THEN X_GEN_TAC `y:real^N` THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`t:real^N->bool`; `u:real^N->real`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC (SUBST1_TAC o SYM)) THEN
+  MAP_EVERY EXISTS_TAC
+   [`t DELETE (a:real^N)`; `\x. (u:real^N->real)(x + a)`] THEN
+  ASM_SIMP_TAC[FINITE_DELETE; VECTOR_SUB_ADD; SET_RULE
+   `t SUBSET (a INSERT s) ==> t DELETE a SUBSET s`] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `a + vsum t (\x. u x % (x - a)):real^N` THEN CONJ_TAC THENL
+   [AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_SUPERSET THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ] THEN SET_TAC[];
+    ASM_SIMP_TAC[VECTOR_SUB_LDISTRIB; FINITE_DELETE; VSUM_SUB] THEN
+    ASM_REWRITE_TAC[VSUM_RMUL] THEN
+    REWRITE_TAC[VECTOR_ARITH `a + x - &1 % a:real^N = x`]]);;
+
+let AFFINE_HULL_INSERT_SPAN = prove
+ (`!a:real^N s.
+        ~(a IN s)
+        ==> affine hull (a INSERT s) =
+            {a + v | v | v IN span {x - a | x IN s}}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[AFFINE_HULL_INSERT_SUBSET_SPAN] THEN REWRITE_TAC[SUBSET] THEN
+  REWRITE_TAC[AFFINE_HULL_EXPLICIT; SPAN_EXPLICIT; IN_ELIM_THM] THEN
+  REWRITE_TAC[SIMPLE_IMAGE; CONJ_ASSOC; FINITE_SUBSET_IMAGE] THEN
+  REWRITE_TAC[MESON[]
+   `(?s u. (?t. P t /\ s = f t) /\ Q s u) <=>
+    (?t u. P t /\ Q (f t) u)`] THEN
+  REWRITE_TAC[MESON[]
+   `(?v. (?s u. P s /\ f s u = v) /\ (x = g a v)) <=>
+    (?s u. ~(P s ==> ~(g a (f s u) = x)))`] THEN
+  SIMP_TAC[VSUM_IMAGE; VECTOR_ARITH `x - a:real^N = y - a <=> x = y`] THEN
+  REWRITE_TAC[o_DEF] THEN X_GEN_TAC `y:real^N` THEN
+  REWRITE_TAC[NOT_IMP; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`t:real^N->bool`; `u:real^N->real`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC (SUBST1_TAC o SYM)) THEN
+  MAP_EVERY EXISTS_TAC
+   [`(a:real^N) INSERT t`;
+    `\x. if x = a then &1 - sum t (\x. u(x - a))
+         else (u:real^N->real)(x - a)`] THEN
+  ASM_SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES] THEN
+  ASM_CASES_TAC `(a:real^N) IN t` THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+  ASM_SIMP_TAC[FINITE_INSERT; NOT_INSERT_EMPTY;
+               SET_RULE `s SUBSET t ==> (a INSERT s) SUBSET (a INSERT t)`] THEN
+  SUBGOAL_THEN `!x:real^N. x IN t ==> ~(x = a)` MP_TAC THENL
+   [ASM SET_TAC[]; SIMP_TAC[] THEN DISCH_THEN(K ALL_TAC)] THEN
+  CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_SIMP_TAC[VECTOR_SUB_LDISTRIB; FINITE_DELETE; VSUM_SUB] THEN
+  ASM_REWRITE_TAC[VSUM_RMUL] THEN VECTOR_ARITH_TAC);;
+
+let AFFINE_HULL_SPAN = prove
+ (`!a:real^N s.
+        a IN s
+        ==> (affine hull s =
+             {a + v | v | v IN span {x - a | x | x IN (s DELETE a)}})`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`a:real^N`; `s DELETE (a:real^N)`]
+    AFFINE_HULL_INSERT_SPAN) THEN
+  ASM_REWRITE_TAC[IN_DELETE] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN AP_TERM_TAC THEN ASM SET_TAC[]);;
+
+let DIFFS_AFFINE_HULL_SPAN = prove
+ (`!a:real^N s.
+        a IN s ==> {x - a | x IN affine hull s} = span {x - a | x IN s}`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP AFFINE_HULL_SPAN) THEN
+  REWRITE_TAC[SIMPLE_IMAGE; GSYM IMAGE_o; o_DEF; VECTOR_ADD_SUB; IMAGE_ID] THEN
+  SIMP_TAC[IMAGE_DELETE_INJ;
+           VECTOR_ARITH `x - a:real^N = y - a <=> x = y`] THEN
+  REWRITE_TAC[VECTOR_SUB_REFL; SPAN_DELETE_0]);;
+
+let AFFINE_HULL_SING = prove
+ (`!a. affine hull {a} = {a}`,
+  SIMP_TAC[AFFINE_HULL_INSERT_SPAN; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[SET_RULE `{f x | x | F} = {}`; SPAN_EMPTY] THEN
+  REWRITE_TAC[SET_RULE `{f x | x IN {a}} = {f a}`; VECTOR_ADD_RID]);;
+
+let AFFINE_HULL_EQ_SING = prove
+ (`!s a:real^N. affine hull s = {a} <=> s = {a}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[AFFINE_HULL_EMPTY] THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[AFFINE_HULL_SING] THEN
+  MATCH_MP_TAC(SET_RULE `~(s = {}) /\ s SUBSET {a} ==> s = {a}`) THEN
+  ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[HULL_SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Convexity.                                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let convex = new_definition
+  `convex s <=>
+        !x y u v. x IN s /\ y IN s /\ &0 <= u /\ &0 <= v /\ (u + v = &1)
+                  ==> (u % x + v % y) IN s`;;
+
+let CONVEX_ALT = prove
+ (`convex s <=> !x y u. x IN s /\ y IN s /\ &0 <= u /\ u <= &1
+                        ==> ((&1 - u) % x + u % y) IN s`,
+  REWRITE_TAC[convex] THEN
+  MESON_TAC[REAL_ARITH `&0 <= u /\ &0 <= v /\ (u + v = &1)
+                        ==> v <= &1 /\ (u = &1 - v)`;
+            REAL_ARITH `u <= &1 ==> &0 <= &1 - u /\ ((&1 - u) + u = &1)`]);;
+
+let IN_CONVEX_SET = prove
+ (`!s a b u.
+        convex s /\ a IN s /\ b IN s /\ &0 <= u /\ u <= &1
+        ==> ((&1 - u) % a + u % b) IN s`,
+  MESON_TAC[CONVEX_ALT]);;
+
+let CONVEX_EMPTY = prove
+ (`convex {}`,
+  REWRITE_TAC[convex; NOT_IN_EMPTY]);;
+
+let CONVEX_SING = prove
+ (`!a. convex {a}`,
+  SIMP_TAC[convex; IN_SING; GSYM VECTOR_ADD_RDISTRIB; VECTOR_MUL_LID]);;
+
+let CONVEX_UNIV = prove
+ (`convex(UNIV:real^N->bool)`,
+  REWRITE_TAC[convex; IN_UNIV]);;
+
+let CONVEX_INTERS = prove
+ (`(!s. s IN f ==> convex s) ==> convex(INTERS f)`,
+  REWRITE_TAC[convex; IN_INTERS] THEN MESON_TAC[]);;
+
+let CONVEX_INTER = prove
+ (`!s t. convex s /\ convex t ==> convex(s INTER t)`,
+  REWRITE_TAC[convex; IN_INTER] THEN MESON_TAC[]);;
+
+let CONVEX_HULLS_EQ = prove
+ (`!s t. s SUBSET convex hull t /\ t SUBSET convex hull s
+         ==> convex hull s = convex hull t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HULLS_EQ THEN
+  ASM_SIMP_TAC[CONVEX_INTERS]);;
+
+let CONVEX_HALFSPACE_LE = prove
+ (`!a b. convex {x | a dot x <= b}`,
+  REWRITE_TAC[convex; IN_ELIM_THM; DOT_RADD; DOT_RMUL] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `(u + v) * b` THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[REAL_ADD_RDISTRIB; REAL_LE_ADD2; REAL_LE_LMUL];
+    ASM_MESON_TAC[REAL_MUL_LID; REAL_LE_REFL]]);;
+
+let CONVEX_HALFSPACE_COMPONENT_LE = prove
+ (`!a k. convex {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`] CONVEX_HALFSPACE_LE) THEN
+  ASM_SIMP_TAC[DOT_BASIS]);;
+
+let CONVEX_HALFSPACE_GE = prove
+ (`!a b. convex {x:real^N | a dot x >= b}`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `{x:real^N | a dot x >= b} = {x | --a dot x <= --b}`
+   (fun th -> REWRITE_TAC[th; CONVEX_HALFSPACE_LE]) THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; DOT_LNEG] THEN REAL_ARITH_TAC);;
+
+let CONVEX_HALFSPACE_COMPONENT_GE = prove
+ (`!a k. convex {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`] CONVEX_HALFSPACE_GE) THEN
+  ASM_SIMP_TAC[DOT_BASIS]);;
+
+let CONVEX_HYPERPLANE = prove
+ (`!a b. convex {x:real^N | a dot x = b}`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN
+   `{x:real^N | a dot x = b} = {x | a dot x <= b} INTER {x | a dot x >= b}`
+   (fun th -> SIMP_TAC[th; CONVEX_INTER;
+                       CONVEX_HALFSPACE_LE; CONVEX_HALFSPACE_GE]) THEN
+  REWRITE_TAC[EXTENSION; IN_INTER; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let CONVEX_STANDARD_HYPERPLANE = prove
+ (`!k a. convex {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`] CONVEX_HYPERPLANE) THEN
+  ASM_SIMP_TAC[DOT_BASIS]);;
+
+let CONVEX_HALFSPACE_LT = prove
+ (`!a b. convex {x | a dot x < b}`,
+  REWRITE_TAC[convex; IN_ELIM_THM; DOT_RADD; DOT_RMUL] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_CONVEX_BOUND_LT THEN
+  ASM_REWRITE_TAC[]);;
+
+let CONVEX_HALFSPACE_COMPONENT_LT = prove
+ (`!a k. convex {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`] CONVEX_HALFSPACE_LT) THEN
+  ASM_SIMP_TAC[DOT_BASIS]);;
+
+let CONVEX_HALFSPACE_GT = prove
+ (`!a b. convex {x | a dot x > b}`,
+  REWRITE_TAC[REAL_ARITH `ax > b <=> --ax < --b`] THEN
+  REWRITE_TAC[GSYM DOT_LNEG; CONVEX_HALFSPACE_LT]);;
+
+let CONVEX_HALFSPACE_COMPONENT_GT = prove
+ (`!a k. convex {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`] CONVEX_HALFSPACE_GT) THEN
+  ASM_SIMP_TAC[DOT_BASIS]);;
+
+let CONVEX_POSITIVE_ORTHANT = prove
+ (`convex {x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
+                          ==> &0 <= x$i}`,
+  SIMP_TAC[convex; IN_ELIM_THM; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+           REAL_LE_MUL; REAL_LE_ADD]);;
+
+let LIMPT_OF_CONVEX = prove
+ (`!s x:real^N.
+        convex s /\ x IN s ==> (x limit_point_of s <=> ~(s = {x}))`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s = {x:real^N}` THEN ASM_REWRITE_TAC[LIMPT_SING] THEN
+  SUBGOAL_THEN `?y:real^N. y IN s /\ ~(y = x)` STRIP_ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[LIMPT_APPROACHABLE] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  ABBREV_TAC `u = min (&1 / &2) (e / &2 / norm(y - x:real^N))` THEN
+  SUBGOAL_THEN `&0 < u /\ u < &1` STRIP_ASSUME_TAC THENL
+   [EXPAND_TAC "u" THEN REWRITE_TAC[REAL_LT_MIN; REAL_MIN_LT] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; NORM_POS_LT; VECTOR_SUB_EQ];
+    ALL_TAC] THEN
+  EXISTS_TAC `(&1 - u) % x + u % y:real^N` THEN REPEAT CONJ_TAC THENL
+   [FIRST_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [CONVEX_ALT]) THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE];
+    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ; VECTOR_ARITH
+     `(&1 - u) % x + u % y:real^N = x <=> u % (y - x) = vec 0`] THEN
+    ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[dist; NORM_MUL; VECTOR_ARITH
+     `((&1 - u) % x + u % y) - x:real^N = u % (y - x)`] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < u ==> abs u = u`] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= e / &2 /\ &0 < e ==> x < e`) THEN
+    ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let TRIVIAL_LIMIT_WITHIN_CONVEX = prove
+ (`!s x:real^N.
+        convex s /\ x IN s ==> (trivial_limit(at x within s) <=> s = {x})`,
+  SIMP_TAC[TRIVIAL_LIMIT_WITHIN; LIMPT_OF_CONVEX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some invariance theorems for convex sets.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_TRANSLATION_EQ = prove
+ (`!a:real^N s. convex (IMAGE (\x. a + x) s) <=> convex s`,
+  REWRITE_TAC[CONVEX_ALT; IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[IN_IMAGE; UNWIND_THM1; VECTOR_ARITH
+   `(&1 - u) % (a + x) + u % (a + y) = a + z <=> (&1 - u) % x + u % y = z`]);;
+
+add_translation_invariants [CONVEX_TRANSLATION_EQ];;
+
+let CONVEX_TRANSLATION = prove
+ (`!s a:real^N. convex s ==> convex (IMAGE (\x. a + x) s)`,
+  REWRITE_TAC[CONVEX_TRANSLATION_EQ]);;
+
+let CONVEX_LINEAR_IMAGE = prove
+ (`!f s. convex s /\ linear f ==> convex(IMAGE f s)`,
+  REWRITE_TAC[convex; FORALL_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[IN_IMAGE; linear] THEN MESON_TAC[]);;
+
+let CONVEX_LINEAR_IMAGE_EQ = prove
+ (`!f s. linear f /\ (!x y. f x = f y ==> x = y)
+         ==> (convex (IMAGE f s) <=> convex s)`,
+  MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE CONVEX_LINEAR_IMAGE));;
+
+add_linear_invariants [CONVEX_LINEAR_IMAGE_EQ];;
+
+(* ------------------------------------------------------------------------- *)
+(* Explicit expressions for convexity in terms of arbitrary sums.            *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_VSUM = prove
+ (`!s k u x:A->real^N.
+        FINITE k /\ convex s /\ sum k u = &1 /\
+        (!i. i IN k ==> &0 <= u i /\ x i IN s)
+        ==> vsum k (\i. u i % x i) IN s`,
+  GEN_TAC THEN ASM_CASES_TAC `convex(s:real^N->bool)` THEN
+  ASM_REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES; FORALL_IN_INSERT] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  MAP_EVERY X_GEN_TAC [`i:A`; `k:A->bool`] THEN
+  GEN_REWRITE_TAC (BINOP_CONV o DEPTH_CONV) [RIGHT_IMP_FORALL_THM] THEN
+  REWRITE_TAC[IMP_IMP] THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`u:A->real`; `x:A->real^N`] THEN
+  ASM_CASES_TAC `(u:A->real) i = &1` THENL
+   [ASM_REWRITE_TAC[REAL_ARITH `&1 + a  = &1 <=> a = &0`] THEN
+    STRIP_TAC THEN
+    SUBGOAL_THEN `vsum k (\i:A. u i % x(i):real^N) = vec 0`
+     (fun th -> ASM_SIMP_TAC[th; VECTOR_ADD_RID; VECTOR_MUL_LID]) THEN
+    MATCH_MP_TAC VSUM_EQ_0 THEN REWRITE_TAC[VECTOR_MUL_EQ_0] THEN
+    REPEAT STRIP_TAC THEN DISJ1_TAC THEN
+    ASM_MESON_TAC[SUM_POS_EQ_0];
+    STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `\j:A. u(j) / (&1 - u(i))`) THEN
+    ASM_REWRITE_TAC[real_div] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[SUM_LMUL; VSUM_LMUL; GSYM VECTOR_MUL_ASSOC] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM real_div] THEN
+    SUBGOAL_THEN `&0 < &1 - u(i:A)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[SUM_POS_LE; REAL_ADD_SYM; REAL_ARITH
+       `&0 <= a /\ &0 <= b /\ b + a = &1 /\ ~(a = &1) ==> &0 < &1 - a`];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; REAL_LT_IMP_LE] THEN
+    ASM_SIMP_TAC[REAL_EQ_LDIV_EQ; REAL_MUL_LID; REAL_EQ_SUB_LADD] THEN
+    DISCH_TAC THEN ONCE_REWRITE_TAC[VECTOR_ADD_SYM] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [convex]) THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`vsum k (\j. (u j / (&1 - u(i:A))) % x(j) :real^N)`;
+      `x(i:A):real^N`; `&1 - u(i:A)`; `u(i:A):real`]) THEN
+    REWRITE_TAC[real_div] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[GSYM VECTOR_MUL_ASSOC; VSUM_LMUL] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; REAL_LT_IMP_NZ] THEN
+    REWRITE_TAC[VECTOR_MUL_LID] THEN DISCH_THEN MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; VSUM_LMUL] THEN
+    CONJ_TAC THENL [FIRST_X_ASSUM MATCH_MP_TAC; REAL_ARITH_TAC] THEN
+    ASM_MESON_TAC[REAL_ADD_SYM]]);;
+
+let CONVEX_VSUM_STRONG = prove
+ (`!s k u x:A->real^N.
+        FINITE k /\
+        convex s /\
+        sum k u = &1 /\
+        (!i. i IN k ==> &0 <= u i /\ (u i = &0 \/ x i IN s))
+        ==> vsum k (\i. u i % x i) IN s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `vsum k (\i. u i % (x:A->real^N) i) =
+    vsum {i | i IN k /\ ~(u i = &0)} (\i. u i % x i)`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC VSUM_SUPERSET THEN REWRITE_TAC[VECTOR_MUL_EQ_0] THEN
+    SET_TAC[];
+    MATCH_MP_TAC CONVEX_VSUM THEN
+    ASM_SIMP_TAC[FINITE_RESTRICT; IN_ELIM_THM] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_SUPERSET THEN ASM SET_TAC[]]);;
+
+let CONVEX_INDEXED = prove
+ (`!s:real^N->bool.
+        convex s <=>
+            !k u x. (!i:num. 1 <= i /\ i <= k ==> &0 <= u(i) /\ x(i) IN s) /\
+                    (sum (1..k) u = &1)
+                    ==> vsum (1..k) (\i. u(i) % x(i)) IN s`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC CONVEX_VSUM THEN
+    ASM_REWRITE_TAC[IN_NUMSEG; FINITE_NUMSEG];
+    DISCH_TAC THEN REWRITE_TAC[convex] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`; `u:real`; `v:real`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `2`) THEN
+    DISCH_THEN(MP_TAC o SPEC `\n. if n = 1 then u else v:real`) THEN
+    DISCH_THEN(MP_TAC o SPEC `\n. if n = 1 then x else y:real^N`) THEN
+    REWRITE_TAC[num_CONV `2`; SUM_CLAUSES_NUMSEG; VSUM_CLAUSES_NUMSEG;
+      NUMSEG_SING; VSUM_SING; SUM_SING] THEN REWRITE_TAC[ARITH] THEN
+    ASM_MESON_TAC[]]);;
+
+let CONVEX_EXPLICIT = prove
+ (`!s:real^N->bool.
+        convex s <=>
+        !t u. FINITE t /\ t SUBSET s /\ (!x. x IN t ==> &0 <= u x) /\
+              sum t u = &1
+              ==> vsum t (\x. u(x) % x) IN s`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC CONVEX_VSUM THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    DISCH_TAC THEN REWRITE_TAC[convex] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`; `u:real`; `v:real`] THEN
+    ASM_CASES_TAC `x:real^N = y` THENL
+     [ASM_SIMP_TAC[GSYM VECTOR_ADD_RDISTRIB; VECTOR_MUL_LID]; ALL_TAC] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `{x:real^N,y}`) THEN
+    DISCH_THEN(MP_TAC o SPEC `\z:real^N. if z = x then u else v:real`) THEN
+    ASM_SIMP_TAC[FINITE_INSERT; FINITE_RULES; SUM_CLAUSES; VSUM_CLAUSES;
+                 NOT_IN_EMPTY] THEN
+    ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; REAL_ADD_RID; SUBSET] THEN
+    REWRITE_TAC[VECTOR_ADD_RID] THEN ASM_MESON_TAC[]]);;
+
+let CONVEX = prove
+ (`!V:real^N->bool.
+     convex V <=>
+         !(s:real^N->bool) (u:real^N->real).
+             FINITE s /\ ~(s = {}) /\ s SUBSET V /\
+             (!x. x IN s ==> &0 <= u x) /\ sum s u = &1
+             ==> vsum s (\x. u x % x) IN V`,
+  GEN_TAC THEN REWRITE_TAC[CONVEX_EXPLICIT] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `t:real^N->bool` THEN REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN ABS_TAC THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[SUM_CLAUSES] THEN CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let CONVEX_FINITE = prove
+ (`!s:real^N->bool.
+        FINITE s
+        ==> (convex s <=>
+                !u. (!x. x IN s ==> &0 <= u x) /\
+                    sum s u = &1
+                    ==> vsum s (\x. u(x) % x) IN s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CONVEX_EXPLICIT] THEN
+  EQ_TAC THENL [ASM_MESON_TAC[SUBSET_REFL]; ALL_TAC] THEN
+  DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`t:real^N->bool`; `u:real^N->real`] THEN
+  STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `\x:real^N. if x IN t then u x else &0`) THEN
+  ASM_SIMP_TAC[GSYM SUM_RESTRICT_SET] THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_LZERO; REAL_LE_REFL; GSYM VSUM_RESTRICT_SET] THEN
+  ASM_SIMP_TAC[COND_ID; SET_RULE `t SUBSET s ==> {x | x IN s /\ x IN t} = t`]);;
+
+let AFFINE_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        affine s /\ affine t ==> affine(s PCROSS t)`,
+  REWRITE_TAC[affine; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  SIMP_TAC[FORALL_IN_PCROSS; GSYM PASTECART_CMUL; PASTECART_ADD] THEN
+  SIMP_TAC[PASTECART_IN_PCROSS]);;
+
+let AFFINE_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        affine(s PCROSS t) <=> s = {} \/ t = {} \/ affine s /\ affine t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; AFFINE_EMPTY] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; AFFINE_EMPTY] THEN
+  EQ_TAC THEN REWRITE_TAC[AFFINE_PCROSS] THEN REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL [`fstcart:real^(M,N)finite_sum->real^M`;
+      `(s:real^M->bool) PCROSS (t:real^N->bool)`] AFFINE_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_FSTCART];
+    MP_TAC(ISPECL [`sndcart:real^(M,N)finite_sum->real^N`;
+      `(s:real^M->bool) PCROSS (t:real^N->bool)`] AFFINE_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_SNDCART]] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; EXISTS_PASTECART; PASTECART_IN_PCROSS;
+              FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  ASM SET_TAC[]);;
+
+let CONVEX_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        convex s /\ convex t ==> convex(s PCROSS t)`,
+  REWRITE_TAC[convex; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  SIMP_TAC[FORALL_IN_PCROSS; GSYM PASTECART_CMUL; PASTECART_ADD] THEN
+  SIMP_TAC[PASTECART_IN_PCROSS]);;
+
+let CONVEX_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        convex(s PCROSS t) <=> s = {} \/ t = {} \/ convex s /\ convex t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; CONVEX_EMPTY] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; CONVEX_EMPTY] THEN
+  EQ_TAC THEN REWRITE_TAC[CONVEX_PCROSS] THEN REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL [`fstcart:real^(M,N)finite_sum->real^M`;
+      `(s:real^M->bool) PCROSS (t:real^N->bool)`] CONVEX_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_FSTCART];
+    MP_TAC(ISPECL [`sndcart:real^(M,N)finite_sum->real^N`;
+      `(s:real^M->bool) PCROSS (t:real^N->bool)`] CONVEX_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_SNDCART]] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; EXISTS_PASTECART; PASTECART_IN_PCROSS;
+              FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Conic sets and conic hull.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let conic = new_definition
+  `conic s <=> !x c. x IN s /\ &0 <= c ==> (c % x) IN s`;;
+
+let SUBSPACE_IMP_CONIC = prove
+ (`!s. subspace s ==> conic s`,
+  SIMP_TAC[subspace; conic]);;
+
+let CONIC_EMPTY = prove
+ (`conic {}`,
+  REWRITE_TAC[conic; NOT_IN_EMPTY]);;
+
+let CONIC_UNIV = prove
+ (`conic (UNIV:real^N->bool)`,
+  REWRITE_TAC[conic; IN_UNIV]);;
+
+let CONIC_INTERS = prove
+ (`(!s. s IN f ==> conic s) ==> conic(INTERS f)`,
+  REWRITE_TAC[conic; IN_INTERS] THEN MESON_TAC[]);;
+
+let CONIC_LINEAR_IMAGE = prove
+ (`!f s. conic s /\ linear f ==> conic(IMAGE f s)`,
+  REWRITE_TAC[conic; IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[IN_IMAGE] THEN MESON_TAC[LINEAR_CMUL]);;
+
+let CONIC_LINEAR_IMAGE_EQ = prove
+ (`!f s. linear f /\ (!x y. f x = f y ==> x = y)
+         ==> (conic (IMAGE f s) <=> conic s)`,
+  MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE CONIC_LINEAR_IMAGE));;
+
+add_linear_invariants [CONIC_LINEAR_IMAGE_EQ];;
+
+let CONIC_CONIC_HULL = prove
+ (`!s. conic(conic hull s)`,
+  SIMP_TAC[P_HULL; CONIC_INTERS]);;
+
+let CONIC_HULL_EQ = prove
+ (`!s. (conic hull s = s) <=> conic s`,
+  SIMP_TAC[HULL_EQ; CONIC_INTERS]);;
+
+let CONIC_NEGATIONS = prove
+ (`!s. conic s ==> conic (IMAGE (--) s)`,
+  REWRITE_TAC[conic; RIGHT_FORALL_IMP_THM; IMP_CONJ; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[IN_IMAGE; VECTOR_MUL_RNEG] THEN MESON_TAC[]);;
+
+let CONIC_SPAN = prove
+ (`!s. conic(span s)`,
+  SIMP_TAC[SUBSPACE_IMP_CONIC; SUBSPACE_SPAN]);;
+
+let CONIC_HULL_EXPLICIT = prove
+ (`!s:real^N->bool. conic hull s = {c % x | &0 <= c /\ x IN s}`,
+  GEN_TAC THEN MATCH_MP_TAC HULL_UNIQUE THEN
+  REWRITE_TAC[conic; SUBSET; RIGHT_FORALL_IMP_THM; IMP_CONJ] THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; IN_ELIM_THM] THEN
+  REPEAT CONJ_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC [`&1`; `x:real^N`] THEN
+    ASM_SIMP_TAC[REAL_POS; VECTOR_MUL_LID];
+    REWRITE_TAC[VECTOR_MUL_ASSOC] THEN MESON_TAC[REAL_LE_MUL];
+    MESON_TAC[]]);;
+
+let CONIC_HULL_LINEAR_IMAGE = prove
+ (`!f s. linear f ==> conic hull (IMAGE f s) = IMAGE f (conic hull s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[CONIC_HULL_EXPLICIT] THEN
+  REWRITE_TAC[SET_RULE `IMAGE f {c % x | P c x} = {f(c % x) | P c x}`] THEN
+  REWRITE_TAC[SET_RULE `{c % x | &0 <= c /\ x IN IMAGE f s} =
+                        {c % f(x) | &0 <= c /\ x IN s}`] THEN
+  DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP LINEAR_CMUL th]));;
+
+add_linear_invariants [CONIC_HULL_LINEAR_IMAGE];;
+
+let CONVEX_CONIC_HULL = prove
+ (`!s:real^N->bool. convex s ==> convex (conic hull s)`,
+  REWRITE_TAC[CONIC_HULL_EXPLICIT] THEN
+  REWRITE_TAC[CONVEX_ALT; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN REWRITE_TAC[IN_ELIM_THM; IMP_IMP] THEN
+  X_GEN_TAC `s:real^N->bool` THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`c:real`; `x:real^N`] THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`d:real`; `y:real^N`] THEN STRIP_TAC THEN
+  X_GEN_TAC `u:real` THEN STRIP_TAC THEN REWRITE_TAC[VECTOR_MUL_ASSOC] THEN
+  ASM_CASES_TAC `(&1 - u) * c = &0` THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_LID] THEN
+    ASM_MESON_TAC[REAL_LE_MUL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `&0 < (&1 - u) * c + u * d` ASSUME_TAC THENL
+   [MATCH_MP_TAC REAL_LTE_ADD THEN ASM_REWRITE_TAC[REAL_LT_LE] THEN
+    CONJ_TAC THEN MATCH_MP_TAC REAL_LE_MUL THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  EXISTS_TAC `(&1 - u) * c + u * d:real` THEN
+  EXISTS_TAC `((&1 - u) * c) / ((&1 - u) * c + u * d) % x +
+              (u * d) / ((&1 - u) * c + u * d) % y:real^N` THEN
+  REWRITE_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_DIV_LMUL; REAL_LT_IMP_NZ] THEN
+  ASM_SIMP_TAC[REAL_LE_ADD; REAL_LE_MUL; REAL_SUB_LE] THEN
+  ASM_SIMP_TAC[REAL_FIELD
+   `&0 < u + v ==> u / (u + v) = &1 - (v / (u + v))`] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ] THEN
+  ASM_SIMP_TAC[REAL_MUL_LZERO; REAL_LE_MUL; REAL_MUL_LID; REAL_LE_ADDL;
+               REAL_SUB_LE]);;
+
+let CONIC_HALFSPACE_LE = prove
+ (`!a. conic {x | a dot x <= &0}`,
+  REWRITE_TAC[conic; IN_ELIM_THM; DOT_RMUL] THEN
+  REWRITE_TAC[REAL_ARITH `a <= &0 <=> &0 <= --a`] THEN
+  SIMP_TAC[GSYM REAL_MUL_RNEG; REAL_LE_MUL]);;
+
+let CONIC_HALFSPACE_GE = prove
+ (`!a. conic {x | a dot x >= &0}`,
+  SIMP_TAC[conic; IN_ELIM_THM; DOT_RMUL; real_ge; REAL_LE_MUL]);;
+
+let CONIC_HULL_EMPTY = prove
+ (`conic hull {} = {}`,
+  MATCH_MP_TAC HULL_UNIQUE THEN
+  REWRITE_TAC[SUBSET_REFL; CONIC_EMPTY; EMPTY_SUBSET]);;
+
+let CONIC_CONTAINS_0 = prove
+ (`!s:real^N->bool. conic s ==> (vec 0 IN s <=> ~(s = {}))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+  DISCH_THEN(X_CHOOSE_TAC `x:real^N`) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [conic]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`x:real^N`; `&0`]) THEN
+  ASM_REWRITE_TAC[REAL_POS; VECTOR_MUL_LZERO]);;
+
+let CONIC_HULL_EQ_EMPTY = prove
+ (`!s. (conic hull s = {}) <=> (s = {})`,
+  GEN_TAC THEN EQ_TAC THEN
+  MESON_TAC[SUBSET_EMPTY; HULL_SUBSET; CONIC_HULL_EMPTY]);;
+
+let CONIC_SUMS = prove
+ (`!s t. conic s /\ conic t ==> conic {x + y:real^N | x IN s /\ y IN t}`,
+  REWRITE_TAC[conic; IN_ELIM_THM] THEN
+  MESON_TAC[VECTOR_ADD_LDISTRIB]);;
+
+let CONIC_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        conic s /\ conic t ==> conic(s PCROSS t)`,
+  REWRITE_TAC[conic; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  SIMP_TAC[FORALL_IN_PCROSS; GSYM PASTECART_CMUL; PASTECART_ADD] THEN
+  SIMP_TAC[PASTECART_IN_PCROSS]);;
+
+let CONIC_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        conic(s PCROSS t) <=> s = {} \/ t = {} \/ conic s /\ conic t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; CONIC_EMPTY] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; CONIC_EMPTY] THEN
+  EQ_TAC THEN REWRITE_TAC[CONIC_PCROSS] THEN REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL [`fstcart:real^(M,N)finite_sum->real^M`;
+      `(s:real^M->bool) PCROSS (t:real^N->bool)`] CONIC_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_FSTCART];
+    MP_TAC(ISPECL [`sndcart:real^(M,N)finite_sum->real^N`;
+      `(s:real^M->bool) PCROSS (t:real^N->bool)`] CONIC_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_SNDCART]] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; EXISTS_PASTECART; PASTECART_IN_PCROSS;
+              FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  ASM SET_TAC[]);;
+
+let CONIC_POSITIVE_ORTHANT = prove
+ (`conic {x:real^N | !i. 1 <= i /\ i <= dimindex(:N) ==> &0 <= x$i}`,
+  SIMP_TAC[conic; IN_ELIM_THM; REAL_LE_MUL; VECTOR_MUL_COMPONENT]);;
+
+let SEPARATE_CLOSED_CONES = prove
+ (`!c d:real^N->bool.
+        conic c /\ closed c /\ conic d /\ closed d /\ c INTER d SUBSET {vec 0}
+        ==> ?e. &0 < e /\
+                !x y. x IN c /\ y IN d
+                      ==> dist(x,y) >= e * max (norm x) (norm y)`,
+  SUBGOAL_THEN
+   `!c d:real^N->bool.
+        conic c /\ closed c /\ conic d /\ closed d /\ c INTER d SUBSET {vec 0}
+        ==> ?e. &0 < e /\
+                !x y. x IN c /\ y IN d ==> dist(x,y)
+                      >= e * norm x`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[real_ge] THEN
+    MP_TAC(ISPECL [`c INTER sphere(vec 0:real^N,&1)`; `d:real^N->bool`]
+      SEPARATE_COMPACT_CLOSED) THEN
+    ASM_SIMP_TAC[CLOSED_INTER_COMPACT; COMPACT_SPHERE] THEN ANTS_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `c INTER d SUBSET {a} ==> ~(a IN s) ==> (c INTER s) INTER d = {}`)) THEN
+      REWRITE_TAC[IN_SPHERE_0; NORM_0] THEN REAL_ARITH_TAC;
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN
+      REWRITE_TAC[IN_INTER; IN_SPHERE_0] THEN STRIP_TAC THEN
+      ASM_REWRITE_TAC[] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+      ASM_CASES_TAC `x:real^N = vec 0` THEN
+      ASM_REWRITE_TAC[DIST_POS_LE; REAL_MUL_RZERO; NORM_0] THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL
+       [`inv(norm x) % x:real^N`; `inv(norm(x:real^N)) % y:real^N`]) THEN
+      REWRITE_TAC[dist; NORM_MUL; GSYM VECTOR_SUB_LDISTRIB] THEN
+      REWRITE_TAC[REAL_ARITH `abs x * a = a * abs x`] THEN
+      REWRITE_TAC[REAL_ABS_INV; GSYM real_div; REAL_ABS_NORM] THEN
+      ASM_SIMP_TAC[REAL_LE_RDIV_EQ; NORM_POS_LT] THEN
+      DISCH_THEN MATCH_MP_TAC THEN
+      ASM_SIMP_TAC[REAL_DIV_REFL; NORM_EQ_0] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[conic]) THEN
+      CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_SIMP_TAC[REAL_LE_INV_EQ; NORM_POS_LE]];
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM(fun th ->
+      MP_TAC(SPECL [`c:real^N->bool`; `d:real^N->bool`] th) THEN
+      MP_TAC(SPECL [`d:real^N->bool`; `c:real^N->bool`] th)) THEN
+    ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[INTER_COMM] THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; real_ge] THEN
+    X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+    X_GEN_TAC `e:real` THEN STRIP_TAC THEN
+    EXISTS_TAC `min d e:real` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+    REWRITE_TAC[real_max] THEN COND_CASES_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THENL
+     [EXISTS_TAC `d * norm(y:real^N)` THEN ONCE_REWRITE_TAC[DIST_SYM];
+      EXISTS_TAC `e * norm(x:real^N)`] THEN
+    ASM_SIMP_TAC[] THEN MATCH_MP_TAC REAL_LE_RMUL THEN NORM_ARITH_TAC]);;
+
+let CONTINUOUS_ON_COMPACT_SURFACE_PROJECTION = prove
+ (`!s:real^N->bool v d:real^N->real.
+        compact s /\ s SUBSET (v DELETE (vec 0)) /\ conic v /\
+        (!x k. x IN v DELETE (vec 0) ==> (&0 < k /\ (k % x) IN s <=> d x = k))
+        ==> (\x. d x % x) continuous_on (v DELETE (vec 0))`,
+  let lemma = prove
+   (`!s:real^N->real^N p srf:real^N->bool pnc.
+          compact srf /\ srf SUBSET pnc /\
+          IMAGE s pnc SUBSET srf /\ (!x. x IN srf ==> s x = x) /\
+          p continuous_on pnc /\
+          (!x. x IN pnc ==> s(p x) = s x /\ p(s x) = p x)
+          ==> s continuous_on pnc`,
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_EQ THEN
+    EXISTS_TAC `(s:real^N->real^N) o (p:real^N->real^N)` THEN
+    CONJ_TAC THENL [ASM_SIMP_TAC[o_DEF]; ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `IMAGE (p:real^N->real^N) pnc = IMAGE p srf` SUBST1_TAC THENL
+     [ASM SET_TAC[];
+      MATCH_MP_TAC CONTINUOUS_ON_INVERSE THEN ASM_REWRITE_TAC[] THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ASM SET_TAC[]]]) in
+  REWRITE_TAC[conic; IN_DELETE; SUBSET] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC lemma THEN
+  MAP_EVERY EXISTS_TAC [`\x:real^N. inv(norm x) % x`; `s:real^N->bool`] THEN
+  ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> q /\ p /\ r`] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_MUL THEN SIMP_TAC[o_DEF; CONTINUOUS_ON_ID] THEN
+    MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
+    SIMP_TAC[IN_DELETE; NORM_EQ_0; SIMP_RULE[o_DEF] CONTINUOUS_ON_LIFT_NORM];
+    REWRITE_TAC[IN_UNIV; IN_DELETE]] THEN
+  CONJ_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `&1`]) THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_LID; REAL_LT_01; IN_DELETE] THEN
+    ASM_MESON_TAC[VECTOR_MUL_LID; SUBSET; IN_DELETE];
+    ALL_TAC] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN CONJ_TAC THENL
+   [FIRST_ASSUM(MP_TAC o SPECL
+     [`inv(norm x) % x:real^N`; `norm x * (d:real^N->real) x`]) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `(d:real^N->real) x`]) THEN
+    ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_INV_EQ_0; NORM_EQ_0] THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[REAL_LE_INV_EQ; NORM_POS_LE; REAL_LT_MUL; NORM_POS_LT] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; NORM_EQ_0; REAL_FIELD
+     `~(n = &0) ==> (n * d) * inv n = d`];
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `(d:real^N->real) x`]) THEN
+    ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[NORM_MUL; VECTOR_MUL_ASSOC; REAL_INV_MUL] THEN
+    ASM_SIMP_TAC[real_abs; REAL_LT_IMP_LE] THEN
+    ASM_SIMP_TAC[REAL_FIELD `&0 < x ==> (inv(x) * y) * x = y`]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Affine dependence and consequential theorems (from Lars Schewe).          *)
+(* ------------------------------------------------------------------------- *)
+
+let affine_dependent = new_definition
+ `affine_dependent (s:real^N -> bool) <=>
+        ?x. x IN s /\ x IN (affine hull (s DELETE x))`;;
+
+let AFFINE_DEPENDENT_EXPLICIT = prove
+ (`!p. affine_dependent (p:real^N -> bool) <=>
+            (?s u. FINITE s /\ s SUBSET p /\
+                   sum s u = &0 /\
+                   (?v. v IN s /\ ~(u v = &0)) /\
+                   vsum s (\v. u v % v) = (vec 0):real^N)`,
+  X_GEN_TAC `p:real^N->bool` THEN EQ_TAC THENL
+   [REWRITE_TAC[affine_dependent;AFFINE_HULL_EXPLICIT;
+                IN_ELIM_THM] THEN
+    REPEAT STRIP_TAC THEN
+    EXISTS_TAC `(x:real^N) INSERT s` THEN
+    EXISTS_TAC `\v:real^N.if v = x then -- &1 else u v` THEN
+      ASM_SIMP_TAC[FINITE_INSERT;SUM_CLAUSES;VSUM_CLAUSES;INSERT_SUBSET] THEN
+      REPEAT CONJ_TAC THENL
+      [ASM SET_TAC[];
+       COND_CASES_TAC THENL [ASM SET_TAC[];ALL_TAC] THEN
+         ASM_SIMP_TAC[SUM_CASES; SUM_CLAUSES; SET_RULE
+          `~((x:real^N) IN s) ==> {v | v IN s /\ v = x} = {} /\
+                                  {v | v IN s /\ ~(v = x)} = s`] THEN
+         REAL_ARITH_TAC;
+       SET_TAC[REAL_ARITH `~(-- &1 = &0)`];
+       MP_TAC (SET_RULE `s SUBSET p DELETE (x:real^N) ==> ~(x IN s)`) THEN
+       ASM_REWRITE_TAC[] THEN
+       DISCH_TAC THEN
+       ASM_SIMP_TAC[VECTOR_ARITH
+        `(-- &1 % (x:real^N)) + a = vec 0 <=> a = x`] THEN
+       MATCH_MP_TAC EQ_TRANS THEN
+       EXISTS_TAC `vsum s (\v:real^N. u v % v)` THEN
+       CONJ_TAC THENL [
+       MATCH_MP_TAC VSUM_EQ THEN
+         ASM_SIMP_TAC[] THEN
+         ASM SET_TAC[];
+       ASM_REWRITE_TAC[]]];
+       ALL_TAC] THEN
+    REWRITE_TAC[affine_dependent;AFFINE_HULL_EXPLICIT;IN_ELIM_THM] THEN
+    REPEAT STRIP_TAC THEN
+    EXISTS_TAC `v:real^N` THEN
+    CONJ_TAC THENL [ASM SET_TAC[];ALL_TAC] THEN
+    EXISTS_TAC `s DELETE (v:real^N)` THEN
+    EXISTS_TAC `\x:real^N. -- (&1 / (u v)) * u x` THEN
+    ASM_SIMP_TAC[FINITE_DELETE;SUM_DELETE;VSUM_DELETE_CASES] THEN
+    ASM_SIMP_TAC[SUM_LMUL;GSYM VECTOR_MUL_ASSOC;VSUM_LMUL;
+            VECTOR_MUL_RZERO;VECTOR_ARITH `vec 0 - -- a % x = a % x:real^N`;
+            REAL_MUL_RZERO;REAL_ARITH `&0 - -- a * b = a * b`] THEN
+    ASM_SIMP_TAC[REAL_FIELD `~(x = &0) ==> &1 / x * x = &1`;
+                 VECTOR_MUL_ASSOC;VECTOR_MUL_LID] THEN
+    CONJ_TAC THENL [ALL_TAC;ASM SET_TAC[]] THEN
+    ASM_SIMP_TAC[SET_RULE `v IN s ==> (s DELETE v = {} <=> s = {v})`] THEN
+    ASM_CASES_TAC `s = {v:real^N}` THEN
+    ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    FIND_ASSUM MP_TAC `sum {v:real^N} u = &0` THEN
+    REWRITE_TAC[SUM_SING]
+    THEN ASM_REWRITE_TAC[]);;
+
+let AFFINE_DEPENDENT_EXPLICIT_FINITE = prove
+ (`!s. FINITE(s:real^N -> bool)
+       ==> (affine_dependent s <=>
+            ?u. sum s u = &0 /\
+                (?v. v IN s /\ ~(u v = &0)) /\
+                vsum s (\v. u v % v) = vec 0)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[AFFINE_DEPENDENT_EXPLICIT] THEN
+  EQ_TAC THENL [ALL_TAC; ASM_MESON_TAC[SUBSET_REFL]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool`
+   (X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `\x:real^N. if x IN t then u(x) else &0` THEN
+  REWRITE_TAC[COND_RAND; COND_RATOR; VECTOR_MUL_LZERO] THEN
+  ASM_SIMP_TAC[GSYM SUM_RESTRICT_SET; GSYM VSUM_RESTRICT_SET] THEN
+  ASM_SIMP_TAC[SET_RULE `t SUBSET s ==> {x | x IN s /\ x IN t} = t`] THEN
+  ASM SET_TAC[]);;
+
+let AFFINE_DEPENDENT_TRANSLATION_EQ = prove
+ (`!a s. affine_dependent (IMAGE (\x. a + x) s) <=> affine_dependent s`,
+  REWRITE_TAC[affine_dependent] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [AFFINE_DEPENDENT_TRANSLATION_EQ];;
+
+let AFFINE_DEPENDENT_TRANSLATION = prove
+ (`!s a. affine_dependent s ==> affine_dependent (IMAGE (\x. a + x) s)`,
+  REWRITE_TAC[AFFINE_DEPENDENT_TRANSLATION_EQ]);;
+
+let AFFINE_DEPENDENT_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (affine_dependent(IMAGE f s) <=> affine_dependent s)`,
+  REWRITE_TAC[affine_dependent] THEN GEOM_TRANSFORM_TAC[]);;
+
+add_linear_invariants [AFFINE_DEPENDENT_LINEAR_IMAGE_EQ];;
+
+let AFFINE_DEPENDENT_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+        affine_dependent(s)
+        ==> affine_dependent(IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[affine_dependent; EXISTS_IN_IMAGE] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^M` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `IMAGE (f:real^M->real^N) s DELETE f a = IMAGE f (s DELETE a)`
+   (fun t -> ASM_SIMP_TAC[FUN_IN_IMAGE; AFFINE_HULL_LINEAR_IMAGE; t]) THEN
+  ASM SET_TAC[]);;
+
+let AFFINE_DEPENDENT_MONO = prove
+ (`!s t:real^N->bool. affine_dependent s /\ s SUBSET t ==> affine_dependent t`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[affine_dependent] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `x:real^N` THEN MATCH_MP_TAC MONO_AND THEN CONJ_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HULL_MONO o SPEC `x:real^N` o MATCH_MP
+   (SET_RULE `!x. s SUBSET t ==> (s DELETE x) SUBSET (t DELETE x)`)) THEN
+  ASM SET_TAC[]);;
+
+let AFFINE_INDEPENDENT_EMPTY = prove
+ (`~(affine_dependent {})`,
+  REWRITE_TAC[affine_dependent; NOT_IN_EMPTY]);;
+
+let AFFINE_INDEPENDENT_1 = prove
+ (`!a:real^N. ~(affine_dependent {a})`,
+  REWRITE_TAC[affine_dependent; EXISTS_IN_INSERT; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[SET_RULE `{a} DELETE a = {}`; AFFINE_HULL_EMPTY; NOT_IN_EMPTY]);;
+
+let AFFINE_INDEPENDENT_2 = prove
+ (`!a b:real^N. ~(affine_dependent {a,b})`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `b:real^N = a` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; AFFINE_INDEPENDENT_1];
+    REWRITE_TAC[affine_dependent; EXISTS_IN_INSERT; NOT_IN_EMPTY] THEN
+    ASM_SIMP_TAC[SET_RULE
+     `~(a = b) ==> {a,b} DELETE a = {b} /\ {a,b} DELETE b = {a}`] THEN
+    ASM_REWRITE_TAC[AFFINE_HULL_SING; IN_SING]]);;
+
+let AFFINE_INDEPENDENT_SUBSET = prove
+ (`!s t. ~affine_dependent t /\ s SUBSET t ==> ~affine_dependent s`,
+  REWRITE_TAC[IMP_CONJ_ALT; CONTRAPOS_THM] THEN
+  REWRITE_TAC[GSYM IMP_CONJ_ALT; AFFINE_DEPENDENT_MONO]);;
+
+let AFFINE_INDEPENDENT_DELETE = prove
+ (`!s a. ~affine_dependent s ==> ~affine_dependent(s DELETE a)`,
+  REPEAT GEN_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] AFFINE_INDEPENDENT_SUBSET) THEN
+  SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Coplanarity, and collinearity in terms of affine hull.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let coplanar = new_definition
+ `coplanar s <=> ?u v w. s SUBSET affine hull {u,v,w}`;;
+
+let COLLINEAR_AFFINE_HULL = prove
+ (`!s:real^N->bool. collinear s <=> ?u v. s SUBSET affine hull {u,v}`,
+  GEN_TAC THEN REWRITE_TAC[collinear; AFFINE_HULL_2] THEN EQ_TAC THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[REAL_ARITH `u + v = &1 <=> &1 - u = v`; UNWIND_THM1] THENL
+   [X_GEN_TAC `u:real^N` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `s:real^N->bool = {}` THEN
+    ASM_REWRITE_TAC[NOT_IN_EMPTY] 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 EXISTS_TAC `x + u:real^N` THEN X_GEN_TAC `y:real^N` THEN
+    DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `y:real^N`]) THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH `x - y:real^N = z <=> x = y + z`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `c:real` SUBST1_TAC) THEN
+    EXISTS_TAC `&1 + c` THEN VECTOR_ARITH_TAC;
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+    EXISTS_TAC `b - a:real^N` THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(fun th ->
+      MP_TAC(SPEC `y:real^N` th) THEN MP_TAC(SPEC `x:real^N` th)) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `r:real` THEN DISCH_THEN SUBST1_TAC THEN
+    X_GEN_TAC `s:real` THEN DISCH_THEN SUBST1_TAC THEN
+    EXISTS_TAC `s - r:real` THEN VECTOR_ARITH_TAC]);;
+
+let COLLINEAR_IMP_COPLANAR = prove
+ (`!s. collinear s ==> coplanar s`,
+  REWRITE_TAC[coplanar; COLLINEAR_AFFINE_HULL] THEN MESON_TAC[INSERT_AC]);;
+
+let COPLANAR_SMALL = prove
+ (`!s. FINITE s /\ CARD s <= 3 ==> coplanar s`,
+  GEN_TAC THEN REWRITE_TAC[ARITH_RULE `s <= 3 <=> s <= 2 \/ s = 3`] THEN
+  REWRITE_TAC[LEFT_OR_DISTRIB; GSYM HAS_SIZE] THEN
+  DISCH_THEN(DISJ_CASES_THEN MP_TAC) THEN
+  SIMP_TAC[COLLINEAR_IMP_COPLANAR; COLLINEAR_SMALL] THEN
+  CONV_TAC(LAND_CONV HAS_SIZE_CONV) THEN REWRITE_TAC[coplanar] THEN
+  REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[HULL_INC; SUBSET]);;
+
+let COPLANAR_EMPTY = prove
+ (`coplanar {}`,
+  SIMP_TAC[COLLINEAR_IMP_COPLANAR; COLLINEAR_EMPTY]);;
+
+let COPLANAR_SING = prove
+ (`!a. coplanar {a}`,
+  SIMP_TAC[COLLINEAR_IMP_COPLANAR; COLLINEAR_SING]);;
+
+let COPLANAR_2 = prove
+ (`!a b. coplanar {a,b}`,
+  SIMP_TAC[COLLINEAR_IMP_COPLANAR; COLLINEAR_2]);;
+
+let COPLANAR_3 = prove
+ (`!a b c. coplanar {a,b,c}`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC COPLANAR_SMALL THEN
+  SIMP_TAC[CARD_CLAUSES; FINITE_INSERT; FINITE_RULES] THEN ARITH_TAC);;
+
+let COLLINEAR_AFFINE_HULL_COLLINEAR = prove
+ (`!s. collinear(affine hull s) <=> collinear s`,
+  REWRITE_TAC[COLLINEAR_AFFINE_HULL] THEN
+  MESON_TAC[HULL_HULL; HULL_MONO; HULL_INC; SUBSET]);;
+
+let COPLANAR_AFFINE_HULL_COPLANAR = prove
+ (`!s. coplanar(affine hull s) <=> coplanar s`,
+  REWRITE_TAC[coplanar] THEN
+  MESON_TAC[HULL_HULL; HULL_MONO; HULL_INC; SUBSET]);;
+
+let COPLANAR_TRANSLATION_EQ = prove
+ (`!a:real^N s. coplanar(IMAGE (\x. a + x) s) <=> coplanar s`,
+  REWRITE_TAC[coplanar] THEN GEOM_TRANSLATE_TAC[]);;
+
+let COPLANAR_TRANSLATION = prove
+ (`!a:real^N s. coplanar s ==> coplanar(IMAGE (\x. a + x) s)`,
+  REWRITE_TAC[COPLANAR_TRANSLATION_EQ]);;
+
+add_translation_invariants [COPLANAR_TRANSLATION_EQ];;
+
+let COPLANAR_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s. coplanar s /\ linear f ==> coplanar(IMAGE f s)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[coplanar; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`; `c:real^M`] THEN STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC
+  [`(f:real^M->real^N) a`; `(f:real^M->real^N) b`; `(f:real^M->real^N) c`] THEN
+  REWRITE_TAC[SET_RULE `{f a,f b,f c} = IMAGE f {a,b,c}`] THEN
+  ASM_SIMP_TAC[AFFINE_HULL_LINEAR_IMAGE; IMAGE_SUBSET]);;
+
+let COPLANAR_LINEAR_IMAGE_EQ = prove
+ (`!f s. linear f /\ (!x y. f x = f y ==> x = y)
+         ==> (coplanar (IMAGE f s) <=> coplanar s)`,
+  MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE COPLANAR_LINEAR_IMAGE));;
+
+add_linear_invariants [COPLANAR_LINEAR_IMAGE_EQ];;
+
+let COPLANAR_SUBSET = prove
+ (`!s t. coplanar t /\ s SUBSET t ==> coplanar s`,
+  REWRITE_TAC[coplanar] THEN SET_TAC[]);;
+
+let AFFINE_HULL_3_IMP_COLLINEAR = prove
+ (`!a b c. c IN affine hull {a,b} ==> collinear {a,b,c}`,
+  ONCE_REWRITE_TAC[GSYM COLLINEAR_AFFINE_HULL_COLLINEAR] THEN
+  SIMP_TAC[HULL_REDUNDANT_EQ; INSERT_AC] THEN
+  REWRITE_TAC[COLLINEAR_AFFINE_HULL_COLLINEAR; COLLINEAR_2]);;
+
+let COLLINEAR_3_AFFINE_HULL = prove
+ (`!a b c:real^N.
+        ~(a = b) ==> (collinear {a,b,c} <=> c IN affine hull {a,b})`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN SIMP_TAC[AFFINE_HULL_3_IMP_COLLINEAR] THEN
+  REWRITE_TAC[collinear] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(fun th -> MP_TAC(SPECL [`b:real^N`; `a:real^N`] th) THEN
+                        MP_TAC(SPECL [`c:real^N`; `a:real^N`] th)) THEN
+  REWRITE_TAC[IN_INSERT; AFFINE_HULL_2; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[VECTOR_ARITH `a - b:real^N = c <=> a = b + c`] THEN
+  X_GEN_TAC `x:real` THEN DISCH_TAC THEN X_GEN_TAC `y:real` THEN
+  ASM_CASES_TAC `y = &0` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_RID] THEN DISCH_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  MAP_EVERY EXISTS_TAC [`&1 - x / y`; `x / y:real`] THEN
+  CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_DIV_RMUL] THEN VECTOR_ARITH_TAC);;
+
+let COLLINEAR_3_EQ_AFFINE_DEPENDENT = prove
+ (`!a b c:real^N.
+        collinear{a,b,c} <=>
+                a = b \/ a = c \/ b = c \/ affine_dependent {a,b,c}`,
+  REPEAT GEN_TAC THEN
+  MAP_EVERY (fun t ->
+    ASM_CASES_TAC t THENL [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC])
+   [`a:real^N = b`; `a:real^N = c`; `b:real^N = c`] THEN
+  ASM_REWRITE_TAC[affine_dependent] THEN EQ_TAC THENL
+   [ASM_SIMP_TAC[COLLINEAR_3_AFFINE_HULL] THEN DISCH_TAC THEN
+    EXISTS_TAC `c:real^N` THEN REWRITE_TAC[IN_INSERT];
+    REWRITE_TAC[EXISTS_IN_INSERT; NOT_IN_EMPTY] THEN STRIP_TAC THENL
+     [ONCE_REWRITE_TAC[SET_RULE `{a,b,c} = {b,c,a}`];
+      ONCE_REWRITE_TAC[SET_RULE `{a,b,c} = {c,a,b}`];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[COLLINEAR_3_AFFINE_HULL]] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+   `x IN s ==> s SUBSET t ==> x IN t`)) THEN
+  MATCH_MP_TAC HULL_MONO THEN ASM SET_TAC[]);;
+
+let AFFINE_DEPENDENT_IMP_COLLINEAR_3 = prove
+ (`!a b c:real^N. affine_dependent {a,b,c} ==> collinear{a,b,c}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[affine_dependent] THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; RIGHT_OR_DISTRIB] THEN
+  REWRITE_TAC[EXISTS_OR_THM; UNWIND_THM2; COLLINEAR_AFFINE_HULL] THEN
+  STRIP_TAC THENL
+   [MAP_EVERY EXISTS_TAC [`b:real^N`; `c:real^N`];
+    MAP_EVERY EXISTS_TAC [`a:real^N`; `c:real^N`];
+    MAP_EVERY EXISTS_TAC [`a:real^N`; `b:real^N`]] THEN
+  SIMP_TAC[INSERT_SUBSET; EMPTY_SUBSET; HULL_INC; IN_INSERT] THEN
+  POP_ASSUM MP_TAC THEN
+  MATCH_MP_TAC(SET_RULE `s SUBSET t ==> a IN s ==> a IN t`) THEN
+  MATCH_MP_TAC HULL_MONO THEN SET_TAC[]);;
+
+let COLLINEAR_3_IN_AFFINE_HULL = prove
+ (`!v0 v1 x:real^N.
+        ~(v1 = v0)
+        ==> (collinear {v0,v1,x} <=> x IN affine hull {v0,v1})`,
+  REPEAT GEN_TAC THEN GEOM_ORIGIN_TAC `v0:real^N` THEN
+  REWRITE_TAC[COLLINEAR_LEMMA; AFFINE_HULL_2] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID; IN_ELIM_THM] THEN
+  ASM_CASES_TAC `x:real^N = vec 0` THEN ASM_REWRITE_TAC[] THENL
+   [MAP_EVERY EXISTS_TAC [`&1`; `&0`] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    VECTOR_ARITH_TAC;
+    MESON_TAC[REAL_ARITH `u + v = &1 <=> u = &1 - v`]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A general lemma.                                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_CONNECTED = prove
+ (`!s:real^N->bool. convex s ==> connected s`,
+  REWRITE_TAC[CONVEX_ALT; connected; SUBSET; EXTENSION; IN_INTER;
+              IN_UNION; NOT_IN_EMPTY; NOT_FORALL_THM; NOT_EXISTS_THM] THEN
+  GEN_TAC THEN DISCH_TAC THEN REPEAT GEN_TAC THEN
+  MAP_EVERY (K(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC))) (1--4) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_THEN `x1:real^N` STRIP_ASSUME_TAC)
+                         (X_CHOOSE_THEN `x2:real^N` STRIP_ASSUME_TAC)) THEN
+  MP_TAC(ISPECL [`\u. (&1 - u) % x1 + u % (x2:real^N)`;
+                 `&0`; `&1`; `e1:real^N->bool`; `e2:real^N->bool`]
+         (REWRITE_RULE[GSYM open_def] CONNECTED_REAL_LEMMA)) THEN
+  ASM_REWRITE_TAC[NOT_IMP; REAL_SUB_RZERO; VECTOR_MUL_LID; VECTOR_MUL_LZERO;
+                  REAL_SUB_REFL; VECTOR_ADD_RID; VECTOR_ADD_LID; REAL_POS] THEN
+  REPEAT(CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]]) THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[dist] THEN
+  REWRITE_TAC[NORM_MUL; VECTOR_ARITH
+   `((&1 - a) % x + a % y) - ((&1 - b) % x + b % y) = (a - b) % (y - x)`] THEN
+  MP_TAC(ISPEC `(x2 - x1):real^N` NORM_POS_LE) THEN
+  REWRITE_TAC[REAL_LE_LT] THEN STRIP_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[REAL_MUL_RZERO; REAL_LT_01]] THEN
+  EXISTS_TAC `e / norm((x2 - x1):real^N)` THEN
+  ASM_SIMP_TAC[REAL_LT_RDIV_EQ; REAL_LT_DIV]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Various topological facts are queued up here, just because they rely on   *)
+(* CONNECTED_UNIV, which is a trivial consequence of CONVEX_UNIV. It would   *)
+(* be fairly easy to prove it earlier and move these back to the topology.ml *)
+(* file, which is a bit tidier intellectually.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let CONNECTED_UNIV = prove
+ (`connected (UNIV:real^N->bool)`,
+  SIMP_TAC[CONVEX_CONNECTED; CONVEX_UNIV]);;
+
+let CONNECTED_COMPONENT_UNIV = prove
+ (`!x. connected_component(:real^N) x = (:real^N)`,
+  MESON_TAC[CONNECTED_CONNECTED_COMPONENT_SET; CONNECTED_UNIV; IN_UNIV]);;
+
+let CONNECTED_COMPONENT_EQ_UNIV = prove
+ (`!s x. connected_component s x = (:real^N) <=> s = (:real^N)`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN SIMP_TAC[CONNECTED_COMPONENT_UNIV] THEN
+  MATCH_MP_TAC(SET_RULE `s SUBSET t ==> s = UNIV ==> t = UNIV`) THEN
+  REWRITE_TAC[CONNECTED_COMPONENT_SUBSET]);;
+
+let CLOPEN = prove
+ (`!s. closed s /\ open s <=> s = {} \/ s = (:real^N)`,
+  GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[CLOSED_EMPTY; OPEN_EMPTY; CLOSED_UNIV; OPEN_UNIV] THEN
+  MATCH_MP_TAC(REWRITE_RULE[CONNECTED_CLOPEN] CONNECTED_UNIV) THEN
+  ASM_REWRITE_TAC[SUBTOPOLOGY_UNIV; GSYM OPEN_IN; GSYM CLOSED_IN]);;
+
+let COMPACT_OPEN = prove
+ (`!s:real^N->bool. compact s /\ open s <=> s = {}`,
+  MESON_TAC[COMPACT_EMPTY; OPEN_EMPTY; COMPACT_IMP_CLOSED; CLOPEN;
+            COMPACT_IMP_BOUNDED; NOT_BOUNDED_UNIV]);;
+
+let FRONTIER_NOT_EMPTY = prove
+ (`!s. ~(s = {}) /\ ~(s = (:real^N)) ==> ~(frontier s = {})`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(:real^N)`; `s:real^N->bool`] CONNECTED_INTER_FRONTIER) THEN
+  REWRITE_TAC[CONNECTED_UNIV] THEN ASM SET_TAC[]);;
+
+let FRONTIER_EQ_EMPTY = prove
+ (`!s. frontier s = {} <=> s = {} \/ s = (:real^N)`,
+  MESON_TAC[FRONTIER_NOT_EMPTY; FRONTIER_EMPTY; FRONTIER_UNIV]);;
+
+let EQ_INTERVAL = prove
+ (`(!a b c d:real^N.
+        interval[a,b] = interval[c,d] <=>
+        interval[a,b] = {} /\ interval[c,d] = {} \/ a = c /\ b = d) /\
+   (!a b c d:real^N.
+        interval[a,b] = interval(c,d) <=>
+        interval[a,b] = {} /\ interval(c,d) = {}) /\
+   (!a b c d:real^N.
+        interval(a,b) = interval[c,d] <=>
+        interval(a,b) = {} /\ interval[c,d] = {}) /\
+   (!a b c d:real^N.
+        interval(a,b) = interval(c,d) <=>
+        interval(a,b) = {} /\ interval(c,d) = {} \/ a = c /\ b = d)`,
+  REPEAT CONJ_TAC THEN REPEAT GEN_TAC THEN
+  (EQ_TAC THENL [ALL_TAC; STRIP_TAC THEN ASM_REWRITE_TAC[]]) THEN
+  MATCH_MP_TAC(MESON[]
+   `(p = {} /\ q = {} ==> r) /\ (~(p = {}) /\ ~(q = {}) ==> p = q ==> r)
+    ==> p = q ==> r`) THEN
+  SIMP_TAC[] THENL
+   [REWRITE_TAC[INTERVAL_NE_EMPTY; CART_EQ] THEN
+    REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+    SIMP_TAC[SUBSET_INTERVAL; GSYM REAL_LE_ANTISYM];
+    STRIP_TAC THEN MATCH_MP_TAC(MESON[CLOPEN]
+     `closed s /\ open t /\ ~(s = {}) /\ ~(s = UNIV) ==> ~(s = t)`) THEN
+    ASM_REWRITE_TAC[CLOSED_INTERVAL; OPEN_INTERVAL; NOT_INTERVAL_UNIV];
+    STRIP_TAC THEN MATCH_MP_TAC(MESON[CLOPEN]
+     `closed s /\ open t /\ ~(s = {}) /\ ~(s = UNIV) ==> ~(t = s)`) THEN
+    ASM_REWRITE_TAC[CLOSED_INTERVAL; OPEN_INTERVAL; NOT_INTERVAL_UNIV];
+    REWRITE_TAC[INTERVAL_NE_EMPTY; CART_EQ] THEN
+    REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+    SIMP_TAC[SUBSET_INTERVAL; GSYM REAL_LE_ANTISYM]]);;
+
+let CLOSED_INTERVAL_EQ = prove
+ (`(!a b:real^N. closed(interval[a,b])) /\
+   (!a b:real^N. closed(interval(a,b)) <=> interval(a,b) = {})`,
+  REWRITE_TAC[CLOSED_INTERVAL] THEN
+  REPEAT GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[CLOSED_EMPTY] THEN
+  MP_TAC(ISPEC `interval(a:real^N,b)` CLOPEN) THEN
+  ASM_REWRITE_TAC[OPEN_INTERVAL] THEN
+  MESON_TAC[BOUNDED_INTERVAL; NOT_BOUNDED_UNIV]);;
+
+let OPEN_INTERVAL_EQ = prove
+ (`(!a b:real^N. open(interval[a,b]) <=> interval[a,b] = {}) /\
+   (!a b:real^N. open(interval(a,b)))`,
+  REWRITE_TAC[OPEN_INTERVAL] THEN
+  REPEAT GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[CLOSED_EMPTY] THEN
+  MP_TAC(ISPEC `interval[a:real^N,b]` CLOPEN) THEN
+  ASM_REWRITE_TAC[CLOSED_INTERVAL] THEN
+  MESON_TAC[BOUNDED_INTERVAL; NOT_BOUNDED_UNIV]);;
+
+let COMPACT_INTERVAL_EQ = prove
+ (`(!a b:real^N. compact(interval[a,b])) /\
+   (!a b:real^N. compact(interval(a,b)) <=> interval(a,b) = {})`,
+  REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED; BOUNDED_INTERVAL] THEN
+  REWRITE_TAC[CLOSED_INTERVAL_EQ]);;
+
+let CONNECTED_CHAIN = prove
+ (`!f:(real^N->bool)->bool.
+        (!s. s IN f ==> compact s /\ connected s) /\
+        (!s t. s IN f /\ t IN f ==> s SUBSET t \/ t SUBSET s)
+        ==> connected(INTERS f)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THEN
+  ASM_REWRITE_TAC[INTERS_0; CONNECTED_UNIV] THEN
+  ABBREV_TAC `c:real^N->bool = INTERS f` THEN
+  SUBGOAL_THEN `compact(c:real^N->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "c" THEN MATCH_MP_TAC COMPACT_INTERS THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[CONNECTED_CLOSED_SET; COMPACT_IMP_CLOSED; NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N->bool`; `b:real^N->bool`] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`a:real^N->bool`; `b:real^N->bool`] SEPARATION_NORMAL) THEN
+  ASM_REWRITE_TAC[NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `v:real^N->bool`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `?k:real^N->bool. k IN f` STRIP_ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `?n:real^N->bool. open n /\ k SUBSET n` MP_TAC THENL
+   [ASM_MESON_TAC[BOUNDED_SUBSET_BALL; COMPACT_IMP_BOUNDED; OPEN_BALL];
+    REWRITE_TAC[UNIONS_SUBSET] THEN STRIP_TAC] THEN
+  MP_TAC(ISPEC `k:real^N->bool` COMPACT_IMP_HEINE_BOREL) THEN
+  ASM_SIMP_TAC[] THEN DISCH_THEN(MP_TAC o SPEC
+   `(u UNION v:real^N->bool) INSERT {n DIFF s | s IN f}`) THEN
+  REWRITE_TAC[SIMPLE_IMAGE; FORALL_IN_INSERT; FORALL_IN_IMAGE] THEN
+  ASM_SIMP_TAC[OPEN_UNION; OPEN_DIFF; COMPACT_IMP_CLOSED; NOT_IMP] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[UNIONS_INSERT] THEN REWRITE_TAC[SUBSET] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN ONCE_REWRITE_TAC[IN_UNION] THEN
+    ASM_CASES_TAC `(x:real^N) IN c` THENL [ASM SET_TAC[]; DISJ2_TAC] THEN
+    REWRITE_TAC[UNIONS_IMAGE; IN_ELIM_THM] THEN
+    UNDISCH_TAC `~((x:real^N) IN c)` THEN
+    SUBST1_TAC(SYM(ASSUME `INTERS f:real^N->bool = c`)) THEN
+    REWRITE_TAC[IN_INTERS; NOT_FORALL_THM] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:(real^N->bool)->bool` MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[SUBSET_INSERT_DELETE] THEN
+  SUBGOAL_THEN `FINITE(g DELETE (u UNION v:real^N->bool))` MP_TAC THENL
+   [ASM_REWRITE_TAC[FINITE_DELETE];
+    REWRITE_TAC[TAUT `p ==> ~q <=> ~(p /\ q)`]] THEN
+  REWRITE_TAC[FINITE_SUBSET_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f':(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `?j:real^N->bool. j IN f /\
+                     UNIONS(IMAGE (\s. n DIFF s) f') SUBSET (n DIFF j)`
+  STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `f':(real^N->bool)->bool = {}` THEN
+    ASM_REWRITE_TAC[IMAGE_CLAUSES; UNIONS_0; EMPTY_SUBSET] THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?j:real^N->bool. j IN f' /\
+                       UNIONS(IMAGE (\s. n DIFF s) f') SUBSET (n DIFF j)`
+    MP_TAC THENL [ALL_TAC; ASM_MESON_TAC[SUBSET]] THEN
+    SUBGOAL_THEN
+     `!s t:real^N->bool. s IN f' /\ t IN f' ==> s SUBSET t \/ t SUBSET s`
+    MP_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+    UNDISCH_TAC `~(f':(real^N->bool)->bool = {})` THEN
+    UNDISCH_TAC `FINITE(f':(real^N->bool)->bool)` THEN
+    SPEC_TAC(`f':(real^N->bool)->bool`,`f':(real^N->bool)->bool`) THEN
+    MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[] THEN
+    REWRITE_TAC[EXISTS_IN_INSERT; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[FORALL_IN_INSERT] THEN POP_ASSUM_LIST(K ALL_TAC) THEN
+    MAP_EVERY X_GEN_TAC [`i:real^N->bool`; `f:(real^N->bool)->bool`] THEN
+    ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THEN
+    ASM_REWRITE_TAC[IMAGE_CLAUSES; UNIONS_INSERT; NOT_IN_EMPTY;
+                    UNIONS_0; UNION_EMPTY; SUBSET_REFL] THEN
+    DISCH_THEN(fun th -> REPEAT DISCH_TAC THEN MP_TAC th) THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `j:real^N->bool` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `(n DIFF j) SUBSET (n DIFF i) \/
+                  (n DIFF i:real^N->bool) SUBSET (n DIFF j)`
+    STRIP_ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `j:real^N->bool` o CONJUNCT2) THEN
+      ASM SET_TAC[];
+      DISJ1_TAC THEN ASM SET_TAC[];
+      DISJ2_TAC THEN EXISTS_TAC `j:real^N->bool` THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(j INTER k:real^N->bool) SUBSET (u UNION v)` ASSUME_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `k SUBSET (u UNION v) UNION (n DIFF j)
+      ==> (j INTER k) SUBSET (u UNION v)`) THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `UNIONS g :real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC
+     `UNIONS((u UNION v:real^N->bool) INSERT (g DELETE (u UNION v)))` THEN
+    CONJ_TAC THENL [MATCH_MP_TAC SUBSET_UNIONS THEN SET_TAC[]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[UNIONS_INSERT] THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `connected(j INTER k:real^N->bool)` MP_TAC THENL
+   [ASM_MESON_TAC[SET_RULE `s SUBSET t ==> s INTER t = s`; INTER_COMM];
+    REWRITE_TAC[connected] THEN
+    MAP_EVERY EXISTS_TAC [`u:real^N->bool`; `v:real^N->bool`] THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[]]);;
+
+let CONNECTED_CHAIN_GEN = prove
+ (`!f:(real^N->bool)->bool.
+       (!s. s IN f ==> closed s /\ connected s) /\
+       (?s. s IN f /\ compact s) /\
+       (!s t. s IN f /\ t IN f ==> s SUBSET t \/ t SUBSET s)
+       ==> connected(INTERS f)`,
+  GEN_TAC THEN DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `s:real^N->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `INTERS f = INTERS(IMAGE (\t:real^N->bool. s INTER t) f)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; INTERS_IMAGE] THEN ASM SET_TAC[];
+    MATCH_MP_TAC CONNECTED_CHAIN THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+    ASM_SIMP_TAC[COMPACT_INTER_CLOSED] THEN
+    CONJ_TAC THENL [X_GEN_TAC `t:real^N->bool`; ASM SET_TAC[]] THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN `s INTER t:real^N->bool = s \/ s INTER t = t`
+     (DISJ_CASES_THEN SUBST1_TAC) THEN
+    ASM SET_TAC[]]);;
+
+let CONNECTED_NEST = prove
+ (`!s. (!n. compact(s n) /\ connected(s n)) /\
+       (!m n. m <= n ==> s n SUBSET s m)
+       ==> connected(INTERS {s n | n IN (:num)})`,
+  GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC CONNECTED_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[]);;
+
+let CONNECTED_NEST_GEN = prove
+ (`!s. (!n. closed(s n) /\ connected(s n)) /\ (?n. compact(s n)) /\
+       (!m n. m <= n ==> s n SUBSET s m)
+       ==> connected(INTERS {s n | n IN (:num)})`,
+  GEN_TAC THEN
+  DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC) THEN
+  MATCH_MP_TAC CONNECTED_CHAIN_GEN THEN
+  ASM_SIMP_TAC[FORALL_IN_GSPEC; IN_UNIV; IMP_CONJ; RIGHT_FORALL_IMP_THM;
+               EXISTS_IN_GSPEC] THEN
+  MATCH_MP_TAC WLOG_LE THEN ASM_MESON_TAC[]);;
+
+let EQ_BALLS = prove
+ (`(!a a':real^N r r'.
+      ball(a,r) = ball(a',r') <=> a = a' /\ r = r' \/ r <= &0 /\ r' <= &0) /\
+   (!a a':real^N r r'.
+      ball(a,r) = cball(a',r') <=> r <= &0 /\ r' < &0) /\
+   (!a a':real^N r r'.
+      cball(a,r) = ball(a',r') <=> r < &0 /\ r' <= &0) /\
+   (!a a':real^N r r'.
+      cball(a,r) = cball(a',r') <=> a = a' /\ r = r' \/ r < &0 /\ r' < &0)`,
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT STRIP_TAC THEN
+  (EQ_TAC THENL
+    [ALL_TAC; REWRITE_TAC[EXTENSION; IN_BALL; IN_CBALL] THEN NORM_ARITH_TAC])
+  THENL
+   [REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ; SUBSET_BALLS] THEN NORM_ARITH_TAC;
+    ONCE_REWRITE_TAC[EQ_SYM_EQ];
+    ALL_TAC;
+    REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ; SUBSET_BALLS] THEN NORM_ARITH_TAC] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (MESON[CLOPEN; BOUNDED_BALL; NOT_BOUNDED_UNIV]
+    `s = t ==> closed s /\ open t /\ bounded t ==> s = {} /\ t = {}`)) THEN
+  REWRITE_TAC[OPEN_BALL; CLOSED_CBALL; BOUNDED_BALL;
+              BALL_EQ_EMPTY; CBALL_EQ_EMPTY] THEN
+  REAL_ARITH_TAC);;
+
+let FINITE_CBALL = prove
+ (`!a:real^N r. FINITE(cball(a,r)) <=> r <= &0`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `r < &0` THEN
+  ASM_SIMP_TAC[CBALL_EMPTY; REAL_LT_IMP_LE; FINITE_EMPTY] THEN
+  ASM_CASES_TAC `r = &0` THEN
+  ASM_REWRITE_TAC[CBALL_TRIVIAL; FINITE_SING; REAL_LE_REFL] THEN
+  EQ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP EMPTY_INTERIOR_FINITE) THEN
+  REWRITE_TAC[INTERIOR_CBALL; BALL_EQ_EMPTY] THEN ASM_REAL_ARITH_TAC);;
+
+let FINITE_BALL = prove
+ (`!a:real^N r. FINITE(ball(a,r)) <=> r <= &0`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `r <= &0` THEN
+  ASM_SIMP_TAC[BALL_EMPTY; REAL_LT_IMP_LE; FINITE_EMPTY] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        FINITE_IMP_NOT_OPEN)) THEN
+  REWRITE_TAC[OPEN_BALL; BALL_EQ_EMPTY] THEN ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Convex functions into the reals.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix ("convex_on",(12,"right"));;
+
+let convex_on = new_definition
+  `f convex_on s <=>
+        !x y u v. x IN s /\ y IN s /\ &0 <= u /\ &0 <= v /\ (u + v = &1)
+                  ==> f(u % x + v % y) <= u * f(x) + v * f(y)`;;
+
+let CONVEX_ON_SUBSET = prove
+ (`!f s t. f convex_on t /\ s SUBSET t ==> f convex_on s`,
+  REWRITE_TAC[convex_on; SUBSET] THEN MESON_TAC[]);;
+
+let CONVEX_ADD = prove
+ (`!s f g. f convex_on s /\ g convex_on s ==> (\x. f(x) + g(x)) convex_on s`,
+  REWRITE_TAC[convex_on; AND_FORALL_THM] THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL ORELSE GEN_TAC) THEN
+  MATCH_MP_TAC(TAUT
+    `(b /\ c ==> d) ==> (a ==> b) /\ (a ==> c) ==> a ==> d`) THEN
+  REAL_ARITH_TAC);;
+
+let CONVEX_CMUL = prove
+ (`!s c f. &0 <= c /\ f convex_on s ==> (\x. c * f(x)) convex_on s`,
+  SIMP_TAC[convex_on; REAL_LE_LMUL;
+           REAL_ARITH `u * c * fx + v * c * fy = c * (u * fx + v * fy)`]);;
+
+let CONVEX_MAX = prove
+ (`!f g s. f convex_on s /\ g convex_on s
+           ==> (\x. max (f x) (g x)) convex_on s`,
+  REWRITE_TAC[convex_on; REAL_MAX_LE] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(fun th ->
+    W(MP_TAC o PART_MATCH (lhand o rand) th o lhand o snd)) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+  MATCH_MP_TAC REAL_LE_ADD2 THEN CONJ_TAC THEN
+  MATCH_MP_TAC REAL_LE_LMUL THEN ASM_REAL_ARITH_TAC);;
+
+let CONVEX_LOWER = prove
+ (`!f s x y. f convex_on s /\
+             x IN s /\ y IN s /\ &0 <= u /\ &0 <= v /\ (u + v = &1)
+             ==> f(u % x + v % y) <= max (f(x)) (f(y))`,
+  REWRITE_TAC[convex_on] THEN REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
+  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC (RAND_CONV o LAND_CONV) [SYM th]) THEN
+  REWRITE_TAC[REAL_ADD_RDISTRIB] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  ASM_MESON_TAC[REAL_LE_ADD2; REAL_LE_LMUL; REAL_MAX_MAX]);;
+
+let CONVEX_LOWER_SEGMENT = prove
+ (`!f s a b x:real^N.
+        f convex_on s /\ a IN s /\ b IN s /\ x IN segment[a,b]
+        ==> f(x) <= max (f a) (f b)`,
+  REWRITE_TAC[IN_SEGMENT] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONVEX_LOWER THEN
+  EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC);;
+
+let CONVEX_LOCAL_GLOBAL_MINIMUM = prove
+ (`!f s t x:real^N.
+       f convex_on s /\ x IN t /\ open t /\ t SUBSET s /\
+       (!y. y IN t ==> f(x) <= f(y))
+       ==> !y. y IN s ==> f(x) <= f(y)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `&0 < dist(x:real^N,y)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[DIST_POS_LT; REAL_LT_REFL]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPECL [`&1`; `e / dist(x:real^N,y)`] REAL_DOWN2) THEN
+  ANTS_TAC THENL [ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_01]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [convex_on]) THEN
+  DISCH_THEN(MP_TAC o
+    SPECL [`x:real^N`; `y:real^N`; `&1 - u`; `u:real`]) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[REAL_SUB_ADD; REAL_SUB_LE; REAL_LT_IMP_LE] THEN
+    ASM_MESON_TAC[CENTRE_IN_BALL; SUBSET];
+    ALL_TAC] THEN
+  REWRITE_TAC[REAL_NOT_LE] THEN MATCH_MP_TAC REAL_LTE_TRANS THEN
+  EXISTS_TAC `(&1 - u) * f(x) + u * f(x:real^N):real` THEN
+  ASM_SIMP_TAC[REAL_LT_LADD; REAL_LT_LMUL] THEN
+  REWRITE_TAC[REAL_ARITH `(&1 - x) * a + x * a = a`] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+  REWRITE_TAC[IN_BALL; dist] THEN
+  REWRITE_TAC[VECTOR_ARITH `x - ((&1 - u) % x + u % y):real^N =
+                            u % (x - y)`] THEN
+  REWRITE_TAC[NORM_MUL; GSYM dist] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ;
+               REAL_ARITH `&0 < x /\ x < b ==> abs x < b`]);;
+
+let CONVEX_DISTANCE = prove
+ (`!s a. (\x. dist(a,x)) convex_on s`,
+  REWRITE_TAC[convex_on; dist] THEN REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o LAND_CONV)
+   [GSYM VECTOR_MUL_LID] THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `(u + v) % z - (u % x + v % y) = u % (z - x) + v % (z - y)`] THEN
+  ASM_MESON_TAC[NORM_TRIANGLE; NORM_MUL; REAL_ABS_REFL]);;
+
+let CONVEX_NORM = prove
+ (`!s:real^N->bool. norm convex_on s`,
+  GEN_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `vec 0:real^N`] CONVEX_DISTANCE) THEN
+  REWRITE_TAC[DIST_0; ETA_AX]);;
+
+let CONVEX_ON_COMPOSE_LINEAR = prove
+ (`!f g:real^M->real^N s.
+        f convex_on (IMAGE g s) /\ linear g ==> (f o g) convex_on s`,
+  REWRITE_TAC[convex_on; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; o_THM] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; GSYM CONJ_ASSOC] THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP LINEAR_ADD th]) THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP LINEAR_CMUL th]) THEN
+  ASM_SIMP_TAC[]);;
+
+let CONVEX_ON_TRANSLATION = prove
+ (`!f a:real^N.
+        f convex_on (IMAGE (\x. a + x) s) <=> (\x. f(a + x)) convex_on s`,
+  REWRITE_TAC[convex_on; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; o_THM] THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `u % (a + x) + v % (a + y):real^N = (u + v) % a + u % x + v % y`] THEN
+  SIMP_TAC[VECTOR_MUL_LID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Open and closed balls are convex and hence connected.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_BALL = prove
+ (`!x:real^N e. convex(ball(x,e))`,
+  let lemma = REWRITE_RULE[convex_on; IN_UNIV]
+   (ISPEC `(:real^N)` CONVEX_DISTANCE) in
+  REWRITE_TAC[convex; IN_BALL] THEN REPEAT STRIP_TAC THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) lemma o lhand o snd) THEN
+  ASM_MESON_TAC[REAL_LET_TRANS; REAL_CONVEX_BOUND_LT]);;
+
+let CONNECTED_BALL = prove
+ (`!x:real^N e. connected(ball(x,e))`,
+  SIMP_TAC[CONVEX_CONNECTED; CONVEX_BALL]);;
+
+let CONVEX_CBALL = prove
+ (`!x:real^N e. convex(cball(x,e))`,
+  REWRITE_TAC[convex; IN_CBALL; dist] THEN MAP_EVERY X_GEN_TAC
+   [`x:real^N`; `e:real`; `y:real^N`; `z:real^N`; `u:real`; `v:real`] THEN
+  STRIP_TAC THEN ONCE_REWRITE_TAC[VECTOR_ARITH `a - b = &1 % a - b`] THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `(a + b) % x - (a % y + b % z) = a % (x - y) + b % (x - z)`] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `norm(u % (x - y)) + norm(v % (x - z):real^N)` THEN
+  REWRITE_TAC[NORM_TRIANGLE; NORM_MUL] THEN
+  MATCH_MP_TAC REAL_CONVEX_BOUND_LE THEN ASM_REWRITE_TAC[REAL_ABS_POS] THEN
+  ASM_SIMP_TAC[REAL_ARITH
+   `&0 <= u /\ &0 <= v /\ (u + v = &1) ==> (abs(u) + abs(v) = &1)`]);;
+
+let CONNECTED_CBALL = prove
+ (`!x:real^N e. connected(cball(x,e))`,
+  SIMP_TAC[CONVEX_CONNECTED; CONVEX_CBALL]);;
+
+let FRONTIER_OF_CONNECTED_COMPONENT_SUBSET = prove
+ (`!s c x:real^N. frontier(connected_component s x) SUBSET frontier s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[frontier; SUBSET; IN_DIFF] THEN
+  X_GEN_TAC `y:real^N` THEN REPEAT STRIP_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `y IN s ==> s SUBSET t ==> y IN t`)) THEN
+    MATCH_MP_TAC SUBSET_CLOSURE THEN REWRITE_TAC[CONNECTED_COMPONENT_SUBSET];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERIOR]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `ball(y:real^N,e) SUBSET connected_component s y`
+    ASSUME_TAC THENL
+     [MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+      ASM_REWRITE_TAC[CONNECTED_BALL; CENTRE_IN_BALL];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CLOSURE_APPROACHABLE]) THEN
+      DISCH_THEN(MP_TAC o SPEC `e:real`) THEN
+      ASM_REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] (GSYM IN_BALL)] THEN
+      STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o check (is_neg o concl)) THEN
+      REWRITE_TAC[IN_INTERIOR] THEN EXISTS_TAC `e:real` THEN
+      MP_TAC(ISPECL [`s:real^N->bool`; `x:real^N`; `y:real^N`]
+        CONNECTED_COMPONENT_OVERLAP) THEN
+      MATCH_MP_TAC(TAUT `p /\ (q ==> r) ==> (p <=> q) ==> r`) THEN
+      ASM_SIMP_TAC[] THEN ASM SET_TAC[]]]);;
+
+let FRONTIER_OF_COMPONENTS_SUBSET = prove
+ (`!s c:real^N->bool.
+        c IN components s ==> frontier c SUBSET frontier s`,
+  SIMP_TAC[components; FORALL_IN_GSPEC;
+           FRONTIER_OF_CONNECTED_COMPONENT_SUBSET]);;
+
+let FRONTIER_OF_COMPONENTS_CLOSED_COMPLEMENT = prove
+ (`!s c. closed s /\ c IN components ((:real^N) DIFF s)
+         ==> frontier c SUBSET s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP FRONTIER_OF_COMPONENTS_SUBSET) THEN
+  REWRITE_TAC[FRONTIER_COMPLEMENT] THEN
+  ASM_MESON_TAC[FRONTIER_SUBSET_EQ; SUBSET_TRANS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A couple of lemmas about components (see Newman IV, 3.3 and 3.4).         *)
+(* ------------------------------------------------------------------------- *)
+
+let CONNECTED_UNION_CLOPEN_IN_COMPLEMENT = prove
+ (`!s t u:real^N->bool.
+        connected s /\ connected u /\ s SUBSET u /\
+        open_in (subtopology euclidean (u DIFF s)) t /\
+        closed_in (subtopology euclidean (u DIFF s)) t
+        ==> connected (s UNION t)`,
+  MAP_EVERY X_GEN_TAC
+   [`c:real^N->bool`; `h:real^N->bool`; `s:real^N->bool`] THEN
+  STRIP_TAC THEN
+  REWRITE_TAC[CONNECTED_CLOSED_IN_EQ; NOT_EXISTS_THM] THEN
+  MATCH_MP_TAC(MESON[]
+   `!Q. (!x y. P x y <=> P y x) /\
+        (!x y. P x y ==> Q x \/ Q y) /\
+        (!x y. P x y /\ Q x ==> F)
+        ==> (!x y. ~(P x y))`) THEN
+  EXISTS_TAC `\x:real^N->bool. c SUBSET x` THEN
+  CONJ_TAC THENL [MESON_TAC[INTER_COMM; UNION_COMM]; ALL_TAC] THEN
+  REWRITE_TAC[] THEN CONJ_TAC THEN
+  MAP_EVERY X_GEN_TAC [`h1:real^N->bool`; `h2:real^N->bool`] THENL
+   [STRIP_TAC THEN UNDISCH_TAC `connected(c:real^N->bool)` THEN
+    REWRITE_TAC[CONNECTED_CLOSED_IN; NOT_EXISTS_THM] THEN
+    DISCH_THEN(MP_TAC o
+      SPECL [`c INTER h1:real^N->bool`; `c INTER h2:real^N->bool`]) THEN
+    MATCH_MP_TAC(TAUT
+     `(p /\ q) /\ (~r ==> s) ==> ~(p /\ q /\ r) ==> s`) THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN CONJ_TAC THENL
+     [UNDISCH_TAC
+        `closed_in(subtopology euclidean (c UNION h)) (h1:real^N->bool)`;
+      UNDISCH_TAC
+        `closed_in(subtopology euclidean (c UNION h)) (h2:real^N->bool)`] THEN
+    REWRITE_TAC[CLOSED_IN_CLOSED] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    ASM SET_TAC[];
+    STRIP_TAC THEN
+    FIRST_ASSUM(ASSUME_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [open_in]) THEN
+    SUBGOAL_THEN `(h2:real^N->bool) SUBSET h` ASSUME_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    UNDISCH_TAC `connected(s:real^N->bool)` THEN
+    REWRITE_TAC[CONNECTED_CLOPEN] THEN
+    DISCH_THEN(MP_TAC o SPEC `h2:real^N->bool`) THEN REWRITE_TAC[NOT_IMP] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    SUBGOAL_THEN `s:real^N->bool = (s DIFF c) UNION (c UNION h)`
+    SUBST1_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC OPEN_IN_SUBTOPOLOGY_UNION THEN
+      MATCH_MP_TAC(TAUT `q /\ (q ==> p) ==> p /\ q`) THEN CONJ_TAC THENL
+       [REWRITE_TAC[OPEN_IN_CLOSED_IN_EQ; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN
+        CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+        SUBGOAL_THEN `(c UNION h) DIFF h2:real^N->bool = h1`
+         (fun th -> ASM_REWRITE_TAC[th]) THEN ASM SET_TAC[];
+        DISCH_TAC THEN MATCH_MP_TAC OPEN_IN_TRANS THEN
+        EXISTS_TAC `h:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+        UNDISCH_TAC
+         `open_in(subtopology euclidean (c UNION h)) (h2:real^N->bool)` THEN
+        REWRITE_TAC[OPEN_IN_OPEN] THEN MATCH_MP_TAC MONO_EXISTS THEN
+        ASM SET_TAC[]];
+      MATCH_MP_TAC CLOSED_IN_SUBTOPOLOGY_UNION THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC CLOSED_IN_TRANS THEN EXISTS_TAC `h:real^N->bool` THEN
+      ASM_REWRITE_TAC[] THEN
+      UNDISCH_TAC
+       `closed_in(subtopology euclidean (c UNION h)) (h2:real^N->bool)` THEN
+      REWRITE_TAC[CLOSED_IN_CLOSED] THEN MATCH_MP_TAC MONO_EXISTS THEN
+      ASM SET_TAC[]]]);;
+
+let COMPONENT_COMPLEMENT_CONNECTED = prove
+ (`!s u c:real^N->bool.
+        connected s /\ connected u /\ s SUBSET u /\ c IN components (u DIFF s)
+        ==> connected(u DIFF c)`,
+  MAP_EVERY X_GEN_TAC
+   [`a:real^N->bool`; `s:real^N->bool`; `c:real^N->bool`] THEN
+  STRIP_TAC THEN UNDISCH_TAC `connected(a:real^N->bool)` THEN
+  REWRITE_TAC[CONNECTED_CLOSED_IN_EQ; NOT_EXISTS_THM] THEN
+  DISCH_TAC THEN MAP_EVERY X_GEN_TAC
+   [`h3:real^N->bool`; `h4:real^N->bool`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+   [`a INTER h3:real^N->bool`; `a INTER h4:real^N->bool`]) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP IN_COMPONENTS_NONEMPTY) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP IN_COMPONENTS_SUBSET) THEN
+  EVERY_ASSUM(fun th -> try
+        MP_TAC(CONJUNCT1(GEN_REWRITE_RULE I [closed_in] th))
+        with Failure _ -> ALL_TAC) THEN
+  REWRITE_TAC[TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN REPEAT DISCH_TAC THEN
+  REPEAT CONJ_TAC THENL
+   [UNDISCH_TAC `closed_in (subtopology euclidean (s DIFF c))
+                           (h3:real^N->bool)` THEN
+    REWRITE_TAC[CLOSED_IN_CLOSED] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    ASM SET_TAC[];
+    UNDISCH_TAC `closed_in (subtopology euclidean (s DIFF c))
+                           (h4:real^N->bool)` THEN
+    REWRITE_TAC[CLOSED_IN_CLOSED] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    ASM SET_TAC[];
+    ASM SET_TAC[];
+    ASM SET_TAC[];
+    DISCH_TAC THEN
+    MP_TAC(ISPECL [`s DIFF a:real^N->bool`; `c UNION h3:real^N->bool`;
+               `c:real^N->bool`] COMPONENTS_MAXIMAL) THEN
+    ASM_REWRITE_TAC[NOT_IMP; GSYM CONJ_ASSOC] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CONNECTED_UNION_CLOPEN_IN_COMPLEMENT THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+    REPEAT CONJ_TAC THENL
+     [ASM_MESON_TAC[IN_COMPONENTS_CONNECTED];
+      ASM SET_TAC[];
+      REWRITE_TAC[OPEN_IN_CLOSED_IN_EQ; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN
+      CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      SUBGOAL_THEN `s DIFF c DIFF h3:real^N->bool = h4` SUBST1_TAC THEN
+      ASM SET_TAC[]];
+    DISCH_TAC THEN
+    MP_TAC(ISPECL [`s DIFF a:real^N->bool`; `c UNION h4:real^N->bool`;
+               `c:real^N->bool`] COMPONENTS_MAXIMAL) THEN
+    ASM_REWRITE_TAC[NOT_IMP; GSYM CONJ_ASSOC] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CONNECTED_UNION_CLOPEN_IN_COMPLEMENT THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+    REPEAT CONJ_TAC THENL
+     [ASM_MESON_TAC[IN_COMPONENTS_CONNECTED];
+      ASM SET_TAC[];
+      REWRITE_TAC[OPEN_IN_CLOSED_IN_EQ; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN
+      CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      SUBGOAL_THEN `s DIFF c DIFF h4:real^N->bool = h3` SUBST1_TAC THEN
+      ASM SET_TAC[]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Sura-Bura's result about components of closed sets.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let SURA_BURA_COMPACT = prove
+ (`!s c:real^N->bool.
+        compact s /\ c IN components s
+        ==> c = INTERS {t | c SUBSET t /\
+                            open_in (subtopology euclidean s) t /\
+                            closed_in (subtopology euclidean s) t}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [components]) THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `x:real^N` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(fun th -> SUBST1_TAC th THEN ASSUME_TAC(SYM th)) THEN
+  MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+  SUBGOAL_THEN `(x:real^N) IN c` ASSUME_TAC THENL
+   [ASM_MESON_TAC[CONNECTED_COMPONENT_REFL; IN]; ALL_TAC] THEN
+  SUBGOAL_THEN `(c:real^N->bool) SUBSET s` ASSUME_TAC THENL
+   [ASM_MESON_TAC[CONNECTED_COMPONENT_SUBSET]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN CONJ_TAC THENL
+   [ASM_REWRITE_TAC[];
+    MATCH_MP_TAC(SET_RULE `s IN t ==> INTERS t SUBSET s`) THEN
+    REWRITE_TAC[IN_ELIM_THM; CONNECTED_COMPONENT_SUBSET;
+                OPEN_IN_SUBTOPOLOGY_REFL; CLOSED_IN_SUBTOPOLOGY_REFL] THEN
+    REWRITE_TAC[TOPSPACE_EUCLIDEAN; SUBSET_UNIV]] THEN
+  W(fun (asl,w) -> ABBREV_TAC(mk_eq(`k:real^N->bool`,rand w))) THEN
+  SUBGOAL_THEN `closed(k:real^N->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "k" THEN MATCH_MP_TAC CLOSED_INTERS THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    ASM_MESON_TAC[CLOSED_IN_CLOSED_TRANS; COMPACT_IMP_CLOSED];
+    ALL_TAC] THEN
+  REWRITE_TAC[CONNECTED_CLOSED_IN_EQ; NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`k1:real^N->bool`; `k2:real^N->bool`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`k1:real^N->bool`; `k2:real^N->bool`] SEPARATION_NORMAL) THEN
+  ASM_REWRITE_TAC[NOT_EXISTS_THM; NOT_IMP] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[CLOSED_IN_CLOSED_TRANS; COMPACT_IMP_CLOSED]; ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`v1:real^N->bool`; `v2:real^N->bool`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`s DIFF (v1 UNION v2):real^N->bool`;
+                 `{t:real^N->bool | connected_component s x SUBSET t /\
+                                    open_in (subtopology euclidean s) t /\
+                                    closed_in (subtopology euclidean s) t}`]
+        COMPACT_IMP_FIP) THEN
+  ASM_SIMP_TAC[NOT_IMP; COMPACT_DIFF; OPEN_UNION; IN_ELIM_THM] THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[CLOSED_IN_CLOSED_TRANS; COMPACT_IMP_CLOSED];
+    ONCE_REWRITE_TAC[SUBSET] THEN REWRITE_TAC[IN_ELIM_THM];
+    ASM SET_TAC[]] THEN
+  X_GEN_TAC `f:(real^N->bool)->bool` THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?c0:real^N->bool.
+        c SUBSET c0 /\ c0 SUBSET (v1 UNION v2) /\
+        open_in (subtopology euclidean s) c0 /\
+        closed_in (subtopology euclidean s) c0`
+  STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THENL
+     [EXISTS_TAC `s:real^N->bool` THEN
+      ASM_REWRITE_TAC[TOPSPACE_EUCLIDEAN; SUBSET_UNIV;
+                OPEN_IN_SUBTOPOLOGY_REFL; CLOSED_IN_SUBTOPOLOGY_REFL] THEN
+      UNDISCH_TAC
+       `(s DIFF (v1 UNION v2)) INTER INTERS f :real^N->bool = {}` THEN
+      ASM_REWRITE_TAC[INTERS_0; INTER_UNIV] THEN SET_TAC[];
+      EXISTS_TAC `INTERS f :real^N->bool` THEN REPEAT CONJ_TAC THENL
+       [ASM SET_TAC[];
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `(s DIFF u) INTER t = {}
+          ==> t SUBSET s
+              ==> t SUBSET u`)) THEN
+        MATCH_MP_TAC(SET_RULE
+         `~(f = {}) /\ (!s. s IN f ==> s SUBSET t) ==> INTERS f SUBSET t`) THEN
+        ASM_MESON_TAC[CLOSED_IN_SUBSET; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY];
+        MATCH_MP_TAC OPEN_IN_INTERS THEN ASM_SIMP_TAC[];
+        MATCH_MP_TAC CLOSED_IN_INTERS THEN ASM_SIMP_TAC[]]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `connected(c:real^N->bool)` MP_TAC THENL
+   [ASM_MESON_TAC[CONNECTED_CONNECTED_COMPONENT]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `closed_in (subtopology euclidean c0) (c0 INTER v1 :real^N->bool) /\
+    closed_in (subtopology euclidean c0) (c0 INTER v2 :real^N->bool)`
+  MP_TAC THENL
+   [CONJ_TAC THEN
+    MATCH_MP_TAC(MESON[]
+     `closed_in top (c INTER closure v) /\
+      c INTER closure v = c INTER v
+      ==> closed_in top (c INTER v)`) THEN
+    (CONJ_TAC THENL
+      [MESON_TAC[CLOSED_IN_CLOSED; CLOSED_CLOSURE]; ALL_TAC]) THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `c0 SUBSET vv ==> c0 INTER (vv INTER v') = c0 INTER v
+        ==> c0 INTER v' = c0 INTER v`)) THEN
+    REWRITE_TAC[ONCE_REWRITE_RULE[INTER_COMM] UNION_OVER_INTER;
+                UNION_OVER_INTER] THEN
+    SIMP_TAC[SET_RULE `s SUBSET t ==> s INTER t = s`; CLOSURE_SUBSET] THENL
+     [ALL_TAC; ONCE_REWRITE_TAC[UNION_COMM]] THEN
+    MATCH_MP_TAC(SET_RULE `t = {} ==> s UNION (u INTER t) = s`) THEN
+    ASM_SIMP_TAC[OPEN_INTER_CLOSURE_EQ_EMPTY] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[CLOSED_IN_CLOSED] THEN DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `u1:real^N->bool` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `u2:real^N->bool` STRIP_ASSUME_TAC)) THEN
+  SUBGOAL_THEN `closed(c0:real^N->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[CLOSED_IN_CLOSED_TRANS; COMPACT_IMP_CLOSED]; ALL_TAC] THEN
+  REWRITE_TAC[CONNECTED_CLOSED] THEN MAP_EVERY EXISTS_TAC
+   [`c0 INTER u1:real^N->bool`; `c0 INTER u2:real^N->bool`] THEN
+  ASM_SIMP_TAC[CLOSED_INTER] THEN
+  REPLICATE_TAC 2 (CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN CONJ_TAC THENL
+   [STRIP_TAC THEN
+    SUBGOAL_THEN `c SUBSET (c0 INTER v2 :real^N->bool)` MP_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN `k SUBSET (c0 INTER v2 :real^N->bool)` ASSUME_TAC THENL
+     [ALL_TAC; ASM SET_TAC[]];
+    STRIP_TAC THEN
+    SUBGOAL_THEN `c SUBSET (c0 INTER v1 :real^N->bool)` ASSUME_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN `k SUBSET (c0 INTER v1 :real^N->bool)` ASSUME_TAC THENL
+     [ALL_TAC; ASM SET_TAC[]]] THEN
+  (UNDISCH_THEN `k1 UNION k2 :real^N->bool = k` (K ALL_TAC) THEN
+   EXPAND_TAC "k" THEN
+   MATCH_MP_TAC(SET_RULE `s IN t ==> INTERS t SUBSET s`) THEN
+   REWRITE_TAC[IN_ELIM_THM] THEN REPEAT CONJ_TAC THENL
+    [ASM SET_TAC[];
+     MATCH_MP_TAC OPEN_IN_INTER_OPEN THEN ASM_REWRITE_TAC[];
+     ASM_REWRITE_TAC[] THEN
+     MATCH_MP_TAC CLOSED_IN_INTER_CLOSED THEN ASM_REWRITE_TAC[]]));;
+
+let SURA_BURA_CLOSED = prove
+ (`!s c:real^N->bool.
+        closed s /\ c IN components s /\ compact c
+        ==> c = INTERS {k | c SUBSET k /\ compact k /\
+                            open_in (subtopology euclidean s) k}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!u:real^N->bool.
+        open u /\ c SUBSET u
+        ==> ?k. c SUBSET k /\ k SUBSET u /\ compact k /\
+                open_in (subtopology euclidean s) k`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[SUBSET] THEN X_GEN_TAC `x:real^N` THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`{x:real^N}`; `c:real^N->bool`] SEPARATION_NORMAL) THEN
+    ASM_SIMP_TAC[COMPACT_IMP_CLOSED; CLOSED_SING] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[LEFT_IMP_EXISTS_THM]] THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `v:real^N->bool`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `v:real^N->bool`) THEN
+    ASM_REWRITE_TAC[IN_INTERS; NOT_FORALL_THM; IN_ELIM_THM; NOT_IMP] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM SET_TAC[]] THEN
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?f. FINITE f /\ c SUBSET UNIONS f /\
+        (!d:real^N->bool. d IN f ==> open d) /\
+        (!d:real^N->bool. d IN f ==> bounded d) /\
+        (!d. d IN f ==> closure d SUBSET u)`
+  STRIP_ASSUME_TAC THENL
+   [FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_IMP_HEINE_BOREL) THEN
+    DISCH_THEN(MP_TAC o SPEC
+     `{ ball(x:real^N,e) | x IN c /\ &0 < e /\ cball(x,e) SUBSET u}`) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[FORALL_IN_GSPEC; UNIONS_GSPEC; OPEN_BALL] THEN
+      REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN X_GEN_TAC `x:real^N` THEN
+      DISCH_TAC THEN EXISTS_TAC `x:real^N` THEN ASM_REWRITE_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
+      ANTS_TAC THENL [ASM SET_TAC[]; MATCH_MP_TAC MONO_EXISTS] THEN
+      REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[CENTRE_IN_BALL] THEN
+      ASM SET_TAC[];
+      MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN STRIP_TAC THEN
+      ASM_SIMP_TAC[] THEN REPEAT CONJ_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+       (SET_RULE `t SUBSET s ==> (!x. x IN s ==> P x)
+                    ==> (!x. x IN t ==> P x)`)) THEN
+      SIMP_TAC[FORALL_IN_GSPEC; OPEN_BALL; BOUNDED_BALL; CLOSURE_BALL]];
+    ALL_TAC] THEN
+  ABBREV_TAC `v:real^N->bool = UNIONS f` THEN
+  SUBGOAL_THEN `bounded(v:real^N->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "v" THEN MATCH_MP_TAC BOUNDED_UNIONS THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `compact(closure v:real^N->bool)` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[COMPACT_CLOSURE]; ALL_TAC] THEN
+  SUBGOAL_THEN `(closure v:real^N->bool) SUBSET u` ASSUME_TAC THENL
+   [EXPAND_TAC "v" THEN ASM_SIMP_TAC[CLOSURE_UNIONS] THEN
+    ASM_REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `open(v:real^N->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "v" THEN MATCH_MP_TAC OPEN_UNIONS THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`closure v INTER s:real^N->bool`; `c:real^N->bool`]
+   SURA_BURA_COMPACT) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[COMPACT_INTER_CLOSED] THEN
+    REWRITE_TAC[IN_COMPONENTS_MAXIMAL] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_COMPONENTS_MAXIMAL]) THEN
+    ASM_MESON_TAC[SUBSET_INTER; SUBSET_TRANS; CLOSURE_SUBSET];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!t:real^N->bool.
+        c SUBSET t /\
+        open_in (subtopology euclidean (closure v INTER s)) t /\
+        closed_in (subtopology euclidean (closure v INTER s)) t <=>
+        c SUBSET t /\ t SUBSET (closure v INTER s) /\ compact t /\
+        open_in (subtopology euclidean (closure v INTER s)) t`
+   (fun th -> REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
+     [MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[CLOSED_IN_SUBSET; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY];
+        STRIP_TAC THEN REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN
+        CONJ_TAC THENL
+         [ASM_MESON_TAC[BOUNDED_SUBSET; COMPACT_IMP_BOUNDED;
+                        COMPACT_INTER_CLOSED];
+          MATCH_MP_TAC CLOSED_IN_CLOSED_TRANS THEN
+          EXISTS_TAC `closure v INTER s:real^N->bool` THEN
+          ASM_MESON_TAC[COMPACT_IMP_CLOSED; CLOSED_INTER]]];
+      MATCH_MP_TAC CLOSED_CLOSED_IN_TRANS THEN
+      ASM_SIMP_TAC[COMPACT_IMP_CLOSED; CLOSED_INTER]];
+    DISCH_THEN(ASSUME_TAC o SYM)] THEN
+  MP_TAC(ISPECL
+   [`(closure v INTER s) DIFF v:real^N->bool`;
+    `{t:real^N->bool | c SUBSET t /\
+                       t SUBSET (closure v INTER s) /\ compact t /\
+           open_in (subtopology euclidean (closure v INTER s)) t}`]
+        COMPACT_IMP_FIP) THEN
+  ASM_SIMP_TAC[COMPACT_DIFF; COMPACT_INTER_CLOSED] THEN
+  MATCH_MP_TAC(TAUT
+   `p /\ r /\ (~q ==> s) ==> (p /\ q ==> ~r) ==> s`) THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN REPEAT CONJ_TAC THENL
+   [MESON_TAC[COMPACT_IMP_CLOSED];
+    ASM SET_TAC[];
+    REWRITE_TAC[NOT_FORALL_THM; LEFT_IMP_EXISTS_THM]] THEN
+  X_GEN_TAC `g:(real^N->bool)->bool` THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [SUBSET] THEN
+  REWRITE_TAC[IN_ELIM_THM; NOT_IMP] THEN
+  ASM_CASES_TAC `g:(real^N->bool)->bool = {}` THENL
+   [ASM_REWRITE_TAC[FINITE_EMPTY; NOT_IN_EMPTY; INTERS_0; INTER_UNIV] THEN
+    REWRITE_TAC[SET_RULE `s DIFF t = {} <=> s SUBSET t`] THEN
+    STRIP_TAC THEN EXISTS_TAC `closure v INTER s :real^N->bool` THEN
+    REPEAT CONJ_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_COMPONENTS_MAXIMAL]) THEN
+      MP_TAC(ISPEC `v:real^N->bool` CLOSURE_SUBSET) THEN ASM SET_TAC[];
+      ASM SET_TAC[];
+      ASM_SIMP_TAC[COMPACT_INTER_CLOSED];
+      SUBGOAL_THEN `closure v INTER s :real^N->bool = s INTER v`
+      SUBST1_TAC THENL
+       [MP_TAC(ISPEC `v:real^N->bool` CLOSURE_SUBSET) THEN ASM SET_TAC[];
+        ASM_SIMP_TAC[OPEN_IN_OPEN_INTER]]];
+    STRIP_TAC THEN
+    EXISTS_TAC `INTERS g :real^N->bool` THEN REPEAT CONJ_TAC THENL
+     [ASM SET_TAC[];
+      MP_TAC(ISPEC `v:real^N->bool` CLOSURE_SUBSET) THEN ASM SET_TAC[];
+      MATCH_MP_TAC COMPACT_INTERS THEN ASM_MESON_TAC[];
+      SUBGOAL_THEN
+       `open_in (subtopology euclidean (closure v INTER s))
+                (INTERS g:real^N->bool)`
+      MP_TAC THENL
+       [MATCH_MP_TAC OPEN_IN_INTERS THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+       `(s DIFF t) INTER u = {} ==> u SUBSET s ==> u SUBSET t`)) THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; DISCH_TAC] THEN
+      REWRITE_TAC[OPEN_IN_OPEN] THEN
+      DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+      ASM_REWRITE_TAC[] THEN
+      EXISTS_TAC `(v:real^N->bool) INTER t` THEN ASM_SIMP_TAC[OPEN_INTER] THEN
+      MP_TAC(ISPEC `v:real^N->bool` CLOSURE_SUBSET) THEN ASM SET_TAC[]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Condition for an open map's image to contain a ball.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let BALL_SUBSET_OPEN_MAP_IMAGE = prove
+ (`!f:real^M->real^N s a r.
+        bounded s /\ f continuous_on closure s /\ open(IMAGE f (interior s)) /\
+        a IN s /\ &0 < r /\ (!z. z IN frontier s ==> r <= norm(f z - f a))
+        ==> ball(f(a),r) SUBSET IMAGE f s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`ball((f:real^M->real^N) a,r)`;
+                 `(:real^N) DIFF IMAGE (f:real^M->real^N) s`]
+    CONNECTED_INTER_FRONTIER) THEN
+  REWRITE_TAC[CONNECTED_BALL] THEN MATCH_MP_TAC(SET_RULE
+   `~(b INTER s = {}) /\ b INTER f = {} ==>
+    (~(b INTER (UNIV DIFF s) = {}) /\ ~(b DIFF (UNIV DIFF s) = {})
+     ==> ~(b INTER f = {}))
+    ==> b SUBSET s`) THEN
+  REWRITE_TAC[FRONTIER_COMPLEMENT] THEN CONJ_TAC THENL
+   [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+    EXISTS_TAC `(f:real^M->real^N) a` THEN
+    ASM_REWRITE_TAC[CENTRE_IN_BALL] THEN ASM SET_TAC[];
+    REWRITE_TAC[SET_RULE `s INTER t = {} <=> !x. x IN t ==> ~(x IN s)`] THEN
+    REWRITE_TAC[IN_BALL; REAL_NOT_LT]] THEN
+  MP_TAC(ISPECL[`frontier(IMAGE (f:real^M->real^N) s)`; `(f:real^M->real^N) a`]
+    DISTANCE_ATTAINS_INF) THEN
+  REWRITE_TAC[FRONTIER_CLOSED; FRONTIER_EQ_EMPTY] THEN ANTS_TAC THENL
+   [SIMP_TAC[DE_MORGAN_THM] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC(MESON[NOT_BOUNDED_UNIV] `bounded s ==> ~(s = UNIV)`) THEN
+    MATCH_MP_TAC BOUNDED_SUBSET THEN
+    EXISTS_TAC `IMAGE (f:real^M->real^N) (closure s)` THEN
+    SIMP_TAC[IMAGE_SUBSET; CLOSURE_SUBSET] THEN
+    MATCH_MP_TAC COMPACT_IMP_BOUNDED THEN
+    MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+    ASM_REWRITE_TAC[COMPACT_CLOSURE];
+    DISCH_THEN(X_CHOOSE_THEN `w:real^N` STRIP_ASSUME_TAC)] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [frontier]) THEN
+  REWRITE_TAC[IN_DIFF] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[CLOSURE_SEQUENTIAL] THEN
+  DISCH_THEN(X_CHOOSE_THEN `y:num->real^N`
+   (CONJUNCTS_THEN2 MP_TAC ASSUME_TAC)) THEN
+  REWRITE_TAC[IN_IMAGE; SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `z:num->real^M` THEN REWRITE_TAC[FORALL_AND_THM] THEN
+  ONCE_REWRITE_TAC[GSYM FUN_EQ_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM COMPACT_CLOSURE]) THEN
+  REWRITE_TAC[compact] THEN
+  DISCH_THEN(MP_TAC o SPEC `z:num->real^M`) THEN
+  ASM_SIMP_TAC[REWRITE_RULE[SUBSET] CLOSURE_SUBSET; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`y:real^M`; `r:num->num`] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `(((\n. (f:real^M->real^N)(z n)) o (r:num->num)) --> w) sequentially`
+  MP_TAC THENL
+   [MATCH_MP_TAC LIM_SUBSEQUENCE THEN ASM_REWRITE_TAC[];
+    ONCE_REWRITE_TAC[GSYM o_DEF] THEN REWRITE_TAC[GSYM o_ASSOC]] THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN `!n. ((z:num->real^M) o (r:num->num)) n IN s` MP_TAC THENL
+   [ASM_REWRITE_TAC[o_THM];
+    UNDISCH_THEN `((\n. (f:real^M->real^N) ((z:num->real^M) n)) --> w)
+                  sequentially` (K ALL_TAC) THEN
+    UNDISCH_THEN `!n. (z:num->real^M) n IN s` (K ALL_TAC)] THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ o rev) THEN
+  SPEC_TAC(`(z:num->real^M) o (r:num->num)`, `z:num->real^M`) THEN
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `w = (f:real^M->real^N) y` SUBST_ALL_TAC THENL
+   [MATCH_MP_TAC(ISPEC `sequentially` LIM_UNIQUE) THEN
+    EXISTS_TAC `(f:real^M->real^N) o (z:num->real^M)` THEN
+    ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_CLOSURE_SEQUENTIALLY];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `norm(f y - (f:real^M->real^N) a)` THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC; ASM_MESON_TAC[dist; NORM_SUB]] THEN
+  ASM_REWRITE_TAC[frontier; IN_DIFF] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o check (is_neg o concl)) THEN
+  REWRITE_TAC[interior; IN_ELIM_THM] THEN
+  EXISTS_TAC `IMAGE (f:real^M->real^N) (interior s)` THEN
+  ASM_SIMP_TAC[IMAGE_SUBSET; INTERIOR_SUBSET] THEN ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Arithmetic operations on sets preserve convexity.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_SCALING = prove
+ (`!s c. convex s ==> convex (IMAGE (\x. c % x) s)`,
+  REWRITE_TAC[convex; IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+   `u % c % x + v % c % y = c % (u % x + v % y)`] THEN
+  ASM_MESON_TAC[]);;
+
+let CONVEX_SCALING_EQ = prove
+ (`!s c. ~(c = &0) ==> (convex (IMAGE (\x. c % x) s) <=> convex s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REWRITE_TAC[CONVEX_SCALING] THEN
+  DISCH_THEN(MP_TAC o SPEC `inv c` o MATCH_MP CONVEX_SCALING) THEN
+  ASM_SIMP_TAC[GSYM IMAGE_o; o_DEF; VECTOR_MUL_ASSOC;
+               REAL_MUL_LINV; VECTOR_MUL_LID; IMAGE_ID]);;
+
+let CONVEX_NEGATIONS = prove
+ (`!s. convex s ==> convex (IMAGE (--) s)`,
+  REWRITE_TAC[convex; IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+   `u % --x + v % --y = --(u % x + v % y)`] THEN
+  ASM_MESON_TAC[]);;
+
+let CONVEX_SUMS = prove
+ (`!s t. convex s /\ convex t ==> convex {x + y | x IN s /\ y IN t}`,
+  REWRITE_TAC[convex; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+    `u % (a + b) + v % (c + d) = (u % a + v % c) + (u % b + v % d)`] THEN
+  ASM_MESON_TAC[]);;
+
+let CONVEX_DIFFERENCES = prove
+ (`!s t. convex s /\ convex t ==> convex {x - y | x IN s /\ y IN t}`,
+  REWRITE_TAC[convex; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+    `u % (a - b) + v % (c - d) = (u % a + v % c) - (u % b + v % d)`] THEN
+  ASM_MESON_TAC[]);;
+
+let CONVEX_AFFINITY = prove
+ (`!s a:real^N c.
+        convex s ==> convex (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; CONVEX_TRANSLATION; CONVEX_SCALING]);;
+
+let CONVEX_LINEAR_PREIMAGE = prove
+ (`!f:real^M->real^N.
+     linear f /\ convex s ==> convex {x | f(x) IN s}`,
+  REWRITE_TAC[CONVEX_ALT; IN_ELIM_THM] THEN
+  SIMP_TAC[LINEAR_ADD; LINEAR_CMUL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Convex hull.                                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_CONVEX_HULL = prove
+ (`!s. convex(convex hull s)`,
+  SIMP_TAC[P_HULL; CONVEX_INTERS]);;
+
+let CONVEX_HULL_EQ = prove
+ (`!s. (convex hull s = s) <=> convex s`,
+  SIMP_TAC[HULL_EQ; CONVEX_INTERS]);;
+
+let IS_CONVEX_HULL = prove
+ (`!s. convex s <=> ?t. s = convex hull t`,
+  GEN_TAC THEN MATCH_MP_TAC IS_HULL THEN SIMP_TAC[CONVEX_INTERS]);;
+
+let CONVEX_HULL_UNIV = prove
+ (`convex hull (:real^N) = (:real^N)`,
+  REWRITE_TAC[CONVEX_HULL_EQ; CONVEX_UNIV]);;
+
+let BOUNDED_CONVEX_HULL = prove
+ (`!s:real^N->bool. bounded s ==> bounded(convex hull s)`,
+  GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [bounded] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC BOUNDED_SUBSET THEN EXISTS_TAC `cball(vec 0:real^N,B)` THEN
+  SIMP_TAC[BOUNDED_CBALL; SUBSET_HULL; CONVEX_CBALL] THEN
+  ASM_REWRITE_TAC[IN_CBALL; SUBSET; dist; VECTOR_SUB_LZERO; NORM_NEG]);;
+
+let BOUNDED_CONVEX_HULL_EQ = prove
+ (`!s. bounded(convex hull s) <=> bounded s`,
+  MESON_TAC[BOUNDED_CONVEX_HULL; HULL_SUBSET; BOUNDED_SUBSET]);;
+
+let FINITE_IMP_BOUNDED_CONVEX_HULL = prove
+ (`!s. FINITE s ==> bounded(convex hull s)`,
+  SIMP_TAC[BOUNDED_CONVEX_HULL; FINITE_IMP_BOUNDED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Stepping theorems for convex hulls of finite sets.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_HULL_EMPTY = prove
+ (`convex hull {} = {}`,
+  MATCH_MP_TAC HULL_UNIQUE THEN
+  REWRITE_TAC[SUBSET_REFL; CONVEX_EMPTY; EMPTY_SUBSET]);;
+
+let CONVEX_HULL_EQ_EMPTY = prove
+ (`!s. (convex hull s = {}) <=> (s = {})`,
+  GEN_TAC THEN EQ_TAC THEN
+  MESON_TAC[SUBSET_EMPTY; HULL_SUBSET; CONVEX_HULL_EMPTY]);;
+
+let CONVEX_HULL_SING = prove
+ (`!a. convex hull {a} = {a}`,
+  REWRITE_TAC[CONVEX_HULL_EQ; CONVEX_SING]);;
+
+let CONVEX_HULL_EQ_SING = prove
+ (`!s a:real^N. convex hull s = {a} <=> s = {a}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[CONVEX_HULL_EMPTY] THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[CONVEX_HULL_SING] THEN
+  MATCH_MP_TAC(SET_RULE `~(s = {}) /\ s SUBSET {a} ==> s = {a}`) THEN
+  ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[HULL_SUBSET]);;
+
+let CONVEX_HULL_INSERT = prove
+ (`!s a. ~(s = {})
+         ==> (convex hull (a INSERT s) =
+                {x:real^N | ?u v b. &0 <= u /\ &0 <= v /\ (u + v = &1) /\
+                                    b IN (convex hull s) /\
+                                    (x = u % a + v % b)})`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HULL_MINIMAL THEN CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_INSERT] THEN
+      X_GEN_TAC `x:real^N` THEN STRIP_TAC THENL
+       [MAP_EVERY EXISTS_TAC [`&1`; `&0`];
+        MAP_EVERY EXISTS_TAC [`&0`; `&1`]] THEN
+      ASM_REWRITE_TAC[VECTOR_MUL_LID; VECTOR_MUL_LZERO] THEN
+      ASM_REWRITE_TAC[VECTOR_ADD_LID; VECTOR_ADD_RID] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      ASM_MESON_TAC[MEMBER_NOT_EMPTY; HULL_SUBSET; SUBSET];
+      ALL_TAC];
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[convex] CONVEX_CONVEX_HULL) THEN
+    ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[HULL_SUBSET; SUBSET; IN_INSERT; HULL_MONO]] THEN
+  REWRITE_TAC[convex; IN_ELIM_THM] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`x:real^N`; `y:real^N`; `u:real`; `v:real`; `u1:real`; `v1:real`;
+    `b1:real^N`; `u2:real`; `v2:real`; `b2:real^N`] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY EXISTS_TAC [`u * u1 + v * u2`; `u * v1 + v * v2`] THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `u % (u1 % a + v1 % b1) + v % (u2 % a + v2 % b2) =
+    (u * u1 + v * u2) % a + (u * v1) % b1 + (v * v2) % b2`] THEN
+  ASM_SIMP_TAC[REAL_LE_ADD; REAL_LE_MUL] THEN
+  ASM_REWRITE_TAC[REAL_MUL_RID; REAL_ARITH
+   `(u * u1 + v * u2) + (u * v1 + v * v2) =
+    u * (u1 + v1) + v * (u2 + v2)`] THEN
+  ASM_CASES_TAC `u * v1 + v * v2 = &0` THENL
+   [FIRST_X_ASSUM(MP_TAC o MATCH_MP (REAL_ARITH
+     `(a + b = &0) ==> &0 <= a /\ &0 <= b ==> (a = &0) /\ (b = &0)`)) THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; REAL_ADD_LID; VECTOR_MUL_LZERO;
+                 VECTOR_ADD_RID] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  EXISTS_TAC `(u * v1) / (u * v1 + v * v2) % b1 +
+              (v * v2) / (u * v1 + v * v2) % b2 :real^N` THEN
+  ASM_SIMP_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC; REAL_DIV_LMUL] THEN
+  MATCH_MP_TAC(REWRITE_RULE[convex] CONVEX_CONVEX_HULL) THEN
+  ASM_SIMP_TAC[REAL_LE_DIV; REAL_LE_MUL; REAL_LE_ADD] THEN
+  ASM_SIMP_TAC[real_div; GSYM REAL_ADD_RDISTRIB; REAL_MUL_RINV]);;
+
+let CONVEX_HULL_INSERT_ALT = prove
+ (`!s a:real^N.
+      convex hull (a INSERT s) =
+      if s = {} then {a}
+      else {(&1 - u) % a + u % x | &0 <= u /\ u <= &1 /\ x IN convex hull s}`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[CONVEX_HULL_SING] THEN
+  ASM_SIMP_TAC[CONVEX_HULL_INSERT] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c /\ d <=> b /\ c /\ a /\ d`] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM2; REAL_SUB_LE;
+              REAL_ARITH `u + v = &1 <=> u = &1 - v`] THEN
+  SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Explicit expression for convex hull.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_HULL_INDEXED = prove
+ (`!s. convex hull s =
+        {y:real^N | ?k u x. (!i. 1 <= i /\ i <= k ==> &0 <= u i /\ x i IN s) /\
+                            (sum (1..k) u = &1) /\
+                            (vsum (1..k) (\i. u i % x i) = y)}`,
+  GEN_TAC THEN MATCH_MP_TAC HULL_UNIQUE THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC [`1`; `\i:num. &1`; `\i:num. x:real^N`] THEN
+    ASM_SIMP_TAC[FINITE_RULES; IN_SING; SUM_SING; VECTOR_MUL_LID; VSUM_SING;
+                 REAL_POS; NUMSEG_SING];
+    ALL_TAC;
+    REWRITE_TAC[CONVEX_INDEXED; SUBSET; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+    MESON_TAC[]] THEN
+  REWRITE_TAC[convex; IN_ELIM_THM] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`; `u:real`; `v:real`] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN MAP_EVERY X_GEN_TAC
+   [`k1:num`; `u1:num->real`; `x1:num->real^N`;
+    `k2:num`; `u2:num->real`; `x2:num->real^N`] THEN
+  STRIP_TAC THEN EXISTS_TAC `k1 + k2:num` THEN
+  EXISTS_TAC `\i:num. if i <= k1 then u * u1(i) else v * u2(i - k1):real` THEN
+  EXISTS_TAC `\i:num. if i <= k1 then x1(i) else x2(i - k1):real^N` THEN
+  ASM_SIMP_TAC[NUMSEG_ADD_SPLIT; ARITH_RULE `1 <= x + 1 /\ x < x + 1`;
+   IN_NUMSEG; SUM_UNION; VSUM_UNION; FINITE_NUMSEG; DISJOINT_NUMSEG;
+   ARITH_RULE `k1 + 1 <= i ==> ~(i <= k1)`] THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[ADD_SYM] NUMSEG_OFFSET_IMAGE] THEN
+  ASM_SIMP_TAC[SUM_IMAGE; VSUM_IMAGE; EQ_ADD_LCANCEL; FINITE_NUMSEG] THEN
+  ASM_SIMP_TAC[o_DEF; ADD_SUB2; SUM_LMUL; VSUM_LMUL; GSYM VECTOR_MUL_ASSOC;
+               FINITE_NUMSEG; REAL_MUL_RID] THEN
+  ASM_MESON_TAC[REAL_LE_MUL; ARITH_RULE
+    `i <= k1 + k2 /\ ~(i <= k1) ==> 1 <= i - k1 /\ i - k1 <= k2`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Another formulation from Lars Schewe.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_HULL_EXPLICIT = prove
+  (`!p. convex hull p =
+        {y:real^N | ?s u. FINITE s /\ s SUBSET p /\
+             (!x. x IN s ==> &0 <= u x) /\
+             sum s u = &1 /\ vsum s (\v. u v % v) = y}`,
+   REWRITE_TAC[CONVEX_HULL_INDEXED;EXTENSION;IN_ELIM_THM] THEN
+   REPEAT STRIP_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [MAP_EVERY  EXISTS_TAC [`IMAGE (x':num->real^N) (1..k)`;
+                           `\v:real^N.sum {i | i IN (1..k) /\ x' i = v} u`]
+    THEN ASM_SIMP_TAC[FINITE_IMAGE;FINITE_NUMSEG;IN_IMAGE] THEN
+    REPEAT STRIP_TAC THENL
+    [REWRITE_TAC[IMAGE;SUBSET;IN_ELIM_THM;IN_NUMSEG] THEN
+       ASM_MESON_TAC[];
+     MATCH_MP_TAC SUM_POS_LE THEN
+       ASM_SIMP_TAC[FINITE_NUMSEG;FINITE_RESTRICT;IN_ELIM_THM;IN_NUMSEG];
+     ASM_SIMP_TAC[GSYM SUM_IMAGE_GEN;FINITE_IMAGE;FINITE_NUMSEG];
+     FIRST_X_ASSUM (fun th -> REWRITE_TAC[GSYM th]) THEN
+     ASM_SIMP_TAC[GSYM VSUM_IMAGE_GEN;FINITE_IMAGE;
+                  FINITE_NUMSEG;VSUM_VMUL;FINITE_RESTRICT] THEN
+       MP_TAC (ISPECL [`x':num->real^N`;`\i:num.u i % (x' i):real^N`;`(1..k)`]
+                      (GSYM VSUM_IMAGE_GEN)) THEN
+       ASM_SIMP_TAC[FINITE_NUMSEG]];ALL_TAC] THEN
+   STRIP_ASSUME_TAC (ASM_REWRITE_RULE [ASSUME `FINITE (s:real^N->bool)`]
+    (ISPEC `s:real^N->bool` FINITE_INDEX_NUMSEG)) THEN
+   MAP_EVERY EXISTS_TAC [`CARD (s:real^N->bool)`;
+                         `(u:real^N->real) o (f:num->real^N)`;
+                         `(f:num->real^N)`] THEN
+   REPEAT STRIP_TAC THENL
+   [REWRITE_TAC[o_DEF] THEN FIRST_ASSUM MATCH_MP_TAC THEN
+      FIRST_ASSUM SUBST1_TAC THEN
+      REWRITE_TAC[IN_IMAGE;IN_NUMSEG] THEN
+      ASM_MESON_TAC[];
+    MATCH_MP_TAC (REWRITE_RULE [SUBSET]
+      (ASSUME `(s:real^N->bool) SUBSET p`)) THEN
+      FIRST_ASSUM SUBST1_TAC THEN
+      REWRITE_TAC[IN_IMAGE;IN_NUMSEG] THEN
+      ASM_MESON_TAC[];
+    MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `sum (s:real^N->bool) u` THEN
+      CONJ_TAC THENL [ALL_TAC;ASM_REWRITE_TAC[]] THEN
+      GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV)
+       [ASSUME `(s:real^N->bool) = IMAGE f (1..CARD s)`] THEN
+      MATCH_MP_TAC (GSYM SUM_IMAGE) THEN
+      ASM_MESON_TAC[];
+    REWRITE_TAC[MESON [o_THM;FUN_EQ_THM]
+     `(\i:num. (u o f) i % f i) = (\v:real^N. u v % v) o f`] THEN
+      MATCH_MP_TAC EQ_TRANS THEN
+      EXISTS_TAC `vsum (s:real^N->bool) (\v. u v % v)` THEN
+      CONJ_TAC THENL [ALL_TAC;ASM_REWRITE_TAC[]] THEN
+      GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV)
+       [ASSUME `(s:real^N->bool) = IMAGE f (1..CARD s)`] THEN
+      MATCH_MP_TAC (GSYM VSUM_IMAGE) THEN
+      ASM SET_TAC[FINITE_NUMSEG]]);;
+
+let CONVEX_HULL_FINITE = prove
+ (`!s:real^N->bool.
+        convex hull s =
+          {y | ?u. (!x. x IN s ==> &0 <= u x) /\
+                   sum s u = &1 /\
+                   vsum s (\x. u x % x) = y}`,
+  GEN_TAC THEN GEN_REWRITE_TAC I [EXTENSION] THEN
+  REWRITE_TAC[CONVEX_HULL_EXPLICIT; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+   [MAP_EVERY X_GEN_TAC [`t:real^N->bool`; `f:real^N->real`] THEN
+    STRIP_TAC THEN
+    EXISTS_TAC `\x:real^N. if x IN t then f x else &0` THEN
+    REWRITE_TAC[COND_RAND; COND_RATOR; VECTOR_MUL_LZERO] THEN
+    REWRITE_TAC[GSYM SUM_RESTRICT_SET; GSYM VSUM_RESTRICT_SET] THEN
+    ASM_SIMP_TAC[SET_RULE `t SUBSET s ==> {x | x IN s /\ x IN t} = t`] THEN
+    REWRITE_TAC[REAL_LE_REFL; COND_ID];
+    X_GEN_TAC `f:real^N->real` THEN
+    ASM_CASES_TAC `s:real^N->bool = {}` THEN
+    ASM_REWRITE_TAC[SUM_CLAUSES; REAL_OF_NUM_EQ; ARITH] THEN STRIP_TAC THEN
+    EXISTS_TAC `support (+) (f:real^N->real) s` THEN
+    EXISTS_TAC `f:real^N->real` THEN
+    MP_TAC(ASSUME `sum s (f:real^N->real) = &1`) THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [sum] THEN
+    REWRITE_TAC[iterate] THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[NEUTRAL_REAL_ADD; REAL_OF_NUM_EQ; ARITH] THEN
+    DISCH_THEN(K ALL_TAC) THEN
+    UNDISCH_TAC `sum s (f:real^N->real) = &1` THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [GSYM SUM_SUPPORT] THEN
+    ASM_CASES_TAC `support (+) (f:real^N->real) s = {}` THEN
+    ASM_SIMP_TAC[SUM_CLAUSES; REAL_OF_NUM_EQ; ARITH] THEN
+    DISCH_TAC THEN REWRITE_TAC[SUPPORT_SUBSET] THEN CONJ_TAC THENL
+     [ASM_SIMP_TAC[support; IN_ELIM_THM]; ALL_TAC] THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [GSYM th]) THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_SUPERSET THEN
+    REWRITE_TAC[SUPPORT_SUBSET] THEN
+    REWRITE_TAC[support; IN_ELIM_THM; NEUTRAL_REAL_ADD] THEN
+    MESON_TAC[VECTOR_MUL_LZERO]]);;
+
+let CONVEX_HULL_UNION_EXPLICIT = prove
+ (`!s t:real^N->bool.
+        convex s /\ convex t
+        ==> convex hull (s UNION t) =
+             s UNION t UNION
+             {(&1 - u) % x + u % y | x IN s /\ y IN t /\ &0 <= u /\ u <= &1}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [REWRITE_TAC[CONVEX_HULL_EXPLICIT] THEN GEN_REWRITE_TAC I [SUBSET] THEN
+    REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`y:real^N`; `u:real^N->bool`; `f:real^N->real`] THEN
+    REPLICATE_TAC 3 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    SUBST1_TAC(SET_RULE `u:real^N->bool = (u INTER s) UNION (u DIFF s)`) THEN
+    ASM_SIMP_TAC[SUM_UNION; VSUM_UNION; FINITE_INTER; FINITE_DIFF;
+                 SET_RULE `DISJOINT (u INTER s) (u DIFF s)`] THEN
+    ASM_CASES_TAC `sum (u INTER s) (f:real^N->real) = &0` THENL
+     [SUBGOAL_THEN `!x. x IN (u INTER s) ==> (f:real^N->real) x = &0`
+      ASSUME_TAC THENL
+       [ASM_MESON_TAC[SUM_POS_EQ_0; FINITE_INTER; IN_INTER];
+        ASM_SIMP_TAC[VECTOR_MUL_LZERO; VSUM_0] THEN
+        REWRITE_TAC[VECTOR_ADD_LID; REAL_ADD_LID] THEN
+        DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (SUBST1_TAC o SYM)) THEN
+        REWRITE_TAC[IN_UNION] THEN DISJ2_TAC THEN DISJ1_TAC THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [CONVEX_EXPLICIT]) THEN
+        ASM_SIMP_TAC[FINITE_DIFF; IN_DIFF] THEN ASM SET_TAC[]];
+      ALL_TAC] THEN
+    ASM_CASES_TAC `sum (u DIFF s) (f:real^N->real) = &0` THENL
+     [SUBGOAL_THEN `!x. x IN (u DIFF s) ==> (f:real^N->real) x = &0`
+      ASSUME_TAC THENL
+       [ASM_MESON_TAC[SUM_POS_EQ_0; FINITE_DIFF; IN_DIFF];
+        ASM_SIMP_TAC[VECTOR_MUL_LZERO; VSUM_0] THEN
+        REWRITE_TAC[VECTOR_ADD_RID; REAL_ADD_RID] THEN
+        DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (SUBST1_TAC o SYM)) THEN
+        REWRITE_TAC[IN_UNION] THEN DISJ1_TAC THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [CONVEX_EXPLICIT]) THEN
+        ASM_SIMP_TAC[FINITE_INTER; IN_INTER] THEN ASM SET_TAC[]];
+      ALL_TAC] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (SUBST1_TAC o SYM)) THEN
+    REWRITE_TAC[IN_UNION; IN_ELIM_THM] THEN DISJ2_TAC THEN DISJ2_TAC THEN
+    MAP_EVERY EXISTS_TAC
+     [`vsum(u INTER s) (\v:real^N. (f v / sum(u INTER s) f) % v)`;
+      `sum(u DIFF s) (f:real^N->real)`;
+      `vsum(u DIFF s) (\v:real^N. (f v / sum(u DIFF s) f) % v)`] THEN
+    REPEAT CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [CONVEX_EXPLICIT]) THEN
+      ASM_SIMP_TAC[INTER_SUBSET; FINITE_INTER; SUM_POS_LE; REAL_LE_DIV;
+                   IN_INTER; real_div; SUM_RMUL; REAL_MUL_RINV];
+      FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [CONVEX_EXPLICIT]) THEN
+      ASM_SIMP_TAC[SUBSET_DIFF; FINITE_DIFF; SUM_POS_LE; REAL_LE_DIV;
+                   IN_DIFF; real_div; SUM_RMUL; REAL_MUL_RINV] THEN
+      ASM SET_TAC[];
+      ASM_SIMP_TAC[SUM_POS_LE; IN_DIFF; FINITE_DIFF];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+       `a + b = &1 ==> &0 <= a ==> b <= &1`)) THEN
+      ASM_SIMP_TAC[SUM_POS_LE; IN_INTER; FINITE_INTER];
+      ASM_SIMP_TAC[GSYM VSUM_LMUL; FINITE_INTER; FINITE_DIFF] THEN
+      SIMP_TAC[VECTOR_MUL_ASSOC; REAL_ARITH `a * b / c:real = a / c * b`] THEN
+      FIRST_ASSUM(SUBST1_TAC o MATCH_MP (REAL_ARITH
+       `a + b = &1 ==> &1 - b = a`)) THEN
+      ASM_SIMP_TAC[REAL_DIV_REFL; REAL_MUL_LID]];
+    REWRITE_TAC[GSYM UNION_ASSOC] THEN ONCE_REWRITE_TAC[UNION_SUBSET] THEN
+    REWRITE_TAC[HULL_SUBSET] THEN REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `u:real`; `y:real^N`] THEN STRIP_TAC THEN
+    MATCH_MP_TAC(REWRITE_RULE[CONVEX_ALT] CONVEX_CONVEX_HULL) THEN
+    ASM_SIMP_TAC[HULL_INC; IN_UNION]]);;
+
+let CONVEX_HULL_UNION_NONEMPTY_EXPLICIT = prove
+ (`!s t:real^N->bool.
+        convex s /\ ~(s = {}) /\ convex t /\ ~(t = {})
+        ==> convex hull (s UNION t) =
+             {(&1 - u) % x + u % y | x IN s /\ y IN t /\ &0 <= u /\ u <= &1}`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[CONVEX_HULL_UNION_EXPLICIT] THEN
+  SIMP_TAC[SET_RULE `s UNION t UNION u = u <=> s SUBSET u /\ t SUBSET u`] THEN
+  CONJ_TAC THEN REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN X_GEN_TAC `z:real^N` THEN
+  DISCH_TAC THENL
+   [MAP_EVERY EXISTS_TAC [`z:real^N`; `&0`] THEN
+    REWRITE_TAC[REAL_SUB_RZERO; VECTOR_MUL_LID; REAL_POS; VECTOR_MUL_LZERO;
+                VECTOR_ADD_RID] THEN
+    ASM SET_TAC[];
+    SUBGOAL_THEN `?a:real^N. a IN s` MP_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC [`&1`; `z:real^N`] THEN
+    ASM_REWRITE_TAC[REAL_POS; REAL_LE_REFL] THEN VECTOR_ARITH_TAC]);;
+
+let CONVEX_HULL_UNION_UNIONS = prove
+ (`!f s:real^N->bool.
+        convex(UNIONS f) /\ ~(f = {})
+        ==> convex hull (s UNION UNIONS f) =
+            UNIONS {convex hull (s UNION t) | t IN f}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC HULL_MONO THEN ASM SET_TAC[]] THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_SIMP_TAC[UNION_EMPTY; HULL_P; UNIONS_SUBSET] THEN
+    X_GEN_TAC `u:real^N->bool` THEN DISCH_TAC THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `convex hull u:real^N->bool` THEN
+    REWRITE_TAC[HULL_SUBSET] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `UNIONS f :real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[UNION_EMPTY] THEN
+    SUBGOAL_THEN `?u:real^N->bool. u IN f` CHOOSE_TAC THENL
+     [ASM_REWRITE_TAC[MEMBER_NOT_EMPTY]; ALL_TAC] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `convex hull (s UNION u:real^N->bool)` THEN
+    ASM_SIMP_TAC[HULL_MONO; SUBSET_UNION] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [HULL_UNION_LEFT] THEN
+  ASM_SIMP_TAC[CONVEX_HULL_UNION_NONEMPTY_EXPLICIT; CONVEX_HULL_EQ_EMPTY;
+               CONVEX_CONVEX_HULL] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_UNIONS] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`a:real`; `u:real^N->bool`] THEN DISCH_TAC THEN
+  X_GEN_TAC `y:real^N` THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[IN_UNIONS; EXISTS_IN_GSPEC] THEN
+  EXISTS_TAC `u:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[CONVEX_ALT] CONVEX_CONVEX_HULL) THEN
+  ASM_MESON_TAC[HULL_MONO; IN_UNION; SUBSET; HULL_INC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A stepping theorem for that expansion.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_HULL_FINITE_STEP = prove
+ (`((?u. (!x. x IN {} ==> &0 <= u x) /\
+         sum {} u = w /\
+         vsum {} (\x. u(x) % x) = y) <=> w = &0 /\ y = vec 0) /\
+   (FINITE(s:real^N->bool)
+    ==> ((?u. (!x. x IN (a INSERT s) ==> &0 <= u x) /\
+              sum (a INSERT s) u = w /\
+              vsum (a INSERT s) (\x. u(x) % x) = y) <=>
+         ?v. &0 <= v /\
+             ?u. (!x. x IN s ==> &0 <= u x) /\
+              sum s u = w - v /\
+              vsum s (\x. u(x) % x) = y - v % a))`,
+  MP_TAC(ISPEC `\x:real^N y:real. &0 <= y` AFFINE_HULL_FINITE_STEP_GEN) THEN
+  SIMP_TAC[REAL_ARITH `&0 <= x / &2 <=> &0 <= x`; REAL_LE_ADD] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence some special cases.                                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_HULL_2 = prove
+ (`!a b. convex hull {a,b} =
+         {u % a + v % b | &0 <= u /\ &0 <= v /\ u + v = &1}`,
+  SIMP_TAC[CONVEX_HULL_FINITE; FINITE_INSERT; FINITE_RULES] THEN
+  SIMP_TAC[CONVEX_HULL_FINITE_STEP; FINITE_INSERT; FINITE_RULES] THEN
+  REWRITE_TAC[REAL_ARITH `x - y = z:real <=> x = y + z`;
+              VECTOR_ARITH `x - y = z:real^N <=> x = y + z`] THEN
+  REWRITE_TAC[VECTOR_ADD_RID; REAL_ADD_RID] THEN SET_TAC[]);;
+
+let CONVEX_HULL_2_ALT = prove
+ (`!a b. convex hull {a,b} = {a + u % (b - a) | &0 <= u /\ u <= &1}`,
+  ONCE_REWRITE_TAC[SET_RULE `{a,b} = {b,a}`] THEN
+  REWRITE_TAC[CONVEX_HULL_2; EXTENSION; IN_ELIM_THM] THEN
+  REWRITE_TAC[REAL_ADD_ASSOC; CONJ_ASSOC] THEN
+  REWRITE_TAC[TAUT `(a /\ x + y = &1) /\ b <=> x + y = &1 /\ a /\ b`] THEN
+  REWRITE_TAC[REAL_ARITH `x + y = &1 <=> y = &1 - x`; UNWIND_THM2] THEN
+  REPEAT GEN_TAC THEN REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+  BINOP_TAC THENL [REAL_ARITH_TAC; VECTOR_ARITH_TAC]);;
+
+let CONVEX_HULL_3 = prove
+ (`convex hull {a,b,c} =
+    { u % a + v % b + w % c |
+      &0 <= u /\ &0 <= v /\ &0 <= w /\ u + v + w = &1}`,
+  SIMP_TAC[CONVEX_HULL_FINITE; FINITE_INSERT; FINITE_RULES] THEN
+  SIMP_TAC[CONVEX_HULL_FINITE_STEP; FINITE_INSERT; FINITE_RULES] THEN
+  REWRITE_TAC[REAL_ARITH `x - y = z:real <=> x = y + z`;
+              VECTOR_ARITH `x - y = z:real^N <=> x = y + z`] THEN
+  REWRITE_TAC[VECTOR_ADD_RID; REAL_ADD_RID] THEN SET_TAC[]);;
+
+let CONVEX_HULL_3_ALT = prove
+ (`!a b c. convex hull {a,b,c} =
+                {a + u % (b - a) + v % (c - a) |
+                   &0 <= u /\ &0 <= v /\ u + v <= &1}`,
+  ONCE_REWRITE_TAC[SET_RULE `{a,b,c} = {b,c,a}`] THEN
+  REWRITE_TAC[CONVEX_HULL_3; EXTENSION; IN_ELIM_THM] THEN
+  REWRITE_TAC[REAL_ADD_ASSOC; CONJ_ASSOC] THEN
+  REWRITE_TAC[TAUT `(a /\ x + y = &1) /\ b <=> x + y = &1 /\ a /\ b`] THEN
+  REWRITE_TAC[REAL_ARITH `x + y = &1 <=> y = &1 - x`; UNWIND_THM2] THEN
+  REPEAT GEN_TAC THEN REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+  BINOP_TAC THENL [REAL_ARITH_TAC; VECTOR_ARITH_TAC]);;
+
+let CONVEX_HULL_SUMS = prove
+ (`!s t:real^N->bool.
+        convex hull {x + y | x IN s /\ y IN t} =
+        {x + y | x IN convex hull s /\ y IN convex hull t}`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HULL_MINIMAL THEN
+    SIMP_TAC[CONVEX_SUMS; CONVEX_CONVEX_HULL] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN MESON_TAC[HULL_INC];
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [CONVEX_HULL_INDEXED] THEN
+    REWRITE_TAC[IN_ELIM_THM; LEFT_AND_EXISTS_THM] THEN
+    REWRITE_TAC[RIGHT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC
+     [`k1:num`; `u1:num->real`; `x1:num->real^N`;
+      `k2:num`; `u2:num->real`; `x2:num->real^N`] THEN
+    STRIP_TAC THEN
+    SUBGOAL_THEN
+     `x + y:real^N =
+      vsum(1..k1) (\i. vsum(1..k2) (\j. u1 i % u2 j % (x1 i + x2 j)))`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[VECTOR_ADD_LDISTRIB; VSUM_ADD_NUMSEG] THEN
+      ASM_SIMP_TAC[VSUM_LMUL; VSUM_RMUL; VECTOR_MUL_LID];
+      REWRITE_TAC[VSUM_LMUL] THEN MATCH_MP_TAC CONVEX_VSUM THEN
+      ASM_SIMP_TAC[FINITE_NUMSEG; CONVEX_CONVEX_HULL; IN_NUMSEG] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC CONVEX_VSUM THEN
+      ASM_SIMP_TAC[FINITE_NUMSEG; CONVEX_CONVEX_HULL; IN_NUMSEG] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC HULL_INC THEN ASM SET_TAC[]]]);;
+
+let AFFINE_HULL_PCROSS,CONVEX_HULL_PCROSS = (CONJ_PAIR o prove)
+ (`(!s:real^M->bool t:real^N->bool.
+        affine hull (s PCROSS t) =
+        (affine hull s) PCROSS (affine hull t)) /\
+   (!s:real^M->bool t:real^N->bool.
+        convex hull (s PCROSS t) =
+        (convex hull s) PCROSS (convex hull t))`,
+  let lemma1 = prove
+   (`!u v x y:real^M z:real^N.
+       u + v = &1
+          ==> pastecart z (u % x + v % y) =
+              u % pastecart z x + v % pastecart z y /\
+              pastecart (u % x + v % y) z =
+              u % pastecart x z + v % pastecart y z`,
+    REWRITE_TAC[PASTECART_ADD; GSYM PASTECART_CMUL] THEN
+    SIMP_TAC[GSYM VECTOR_ADD_RDISTRIB; VECTOR_MUL_LID])
+  and lemma2 = prove
+   (`INTERS {{x | pastecart x y IN u} | y IN t} =
+     {x | !y. y IN t ==> pastecart x y IN u}`,
+    REWRITE_TAC[INTERS_GSPEC; EXTENSION; IN_ELIM_THM] THEN SET_TAC[]) in
+  CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HULL_MINIMAL THEN
+      SIMP_TAC[AFFINE_PCROSS; AFFINE_AFFINE_HULL; HULL_SUBSET; PCROSS_MONO];
+      REWRITE_TAC[SUBSET; FORALL_IN_PCROSS] THEN
+      REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+      MATCH_MP_TAC HULL_INDUCT THEN CONJ_TAC THENL
+       [X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+        MATCH_MP_TAC HULL_INDUCT THEN CONJ_TAC THENL
+         [X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+          SUBGOAL_THEN `pastecart (x:real^M) (y:real^N) IN s PCROSS t` MP_TAC
+          THENL [ASM_REWRITE_TAC[PASTECART_IN_PCROSS]; ALL_TAC] THEN
+          REWRITE_TAC[HULL_INC];
+          ALL_TAC];
+        REWRITE_TAC[GSYM lemma2] THEN MATCH_MP_TAC AFFINE_INTERS THEN
+        REWRITE_TAC[FORALL_IN_GSPEC]] THEN
+      SIMP_TAC[affine; IN_ELIM_THM; lemma1;
+               ONCE_REWRITE_RULE[affine] AFFINE_AFFINE_HULL]];
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HULL_MINIMAL THEN
+      SIMP_TAC[CONVEX_PCROSS; CONVEX_CONVEX_HULL; HULL_SUBSET; PCROSS_MONO];
+      REWRITE_TAC[SUBSET; FORALL_IN_PCROSS] THEN
+      REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+      MATCH_MP_TAC HULL_INDUCT THEN CONJ_TAC THENL
+       [X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+        MATCH_MP_TAC HULL_INDUCT THEN CONJ_TAC THENL
+         [X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+          SUBGOAL_THEN `pastecart (x:real^M) (y:real^N) IN s PCROSS t` MP_TAC
+          THENL [ASM_REWRITE_TAC[PASTECART_IN_PCROSS]; ALL_TAC] THEN
+          REWRITE_TAC[HULL_INC];
+          ALL_TAC];
+        REWRITE_TAC[GSYM lemma2] THEN MATCH_MP_TAC CONVEX_INTERS THEN
+        REWRITE_TAC[FORALL_IN_GSPEC]] THEN
+      SIMP_TAC[convex; IN_ELIM_THM; lemma1;
+               ONCE_REWRITE_RULE[convex] CONVEX_CONVEX_HULL]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relations among closure notions and corresponding hulls.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let SUBSPACE_IMP_AFFINE = prove
+ (`!s. subspace s ==> affine s`,
+  REWRITE_TAC[subspace; affine] THEN MESON_TAC[]);;
+
+let AFFINE_IMP_CONVEX = prove
+ (`!s. affine s ==> convex s`,
+  REWRITE_TAC[affine; convex] THEN MESON_TAC[]);;
+
+let SUBSPACE_IMP_CONVEX = prove
+ (`!s. subspace s ==> convex s`,
+  MESON_TAC[SUBSPACE_IMP_AFFINE; AFFINE_IMP_CONVEX]);;
+
+let AFFINE_HULL_SUBSET_SPAN = prove
+ (`!s. (affine hull s) SUBSET (span s)`,
+  GEN_TAC THEN REWRITE_TAC[span] THEN MATCH_MP_TAC HULL_ANTIMONO THEN
+  REWRITE_TAC[SUBSET; IN; SUBSPACE_IMP_AFFINE]);;
+
+let CONVEX_HULL_SUBSET_SPAN = prove
+ (`!s. (convex hull s) SUBSET (span s)`,
+  GEN_TAC THEN REWRITE_TAC[span] THEN MATCH_MP_TAC HULL_ANTIMONO THEN
+  REWRITE_TAC[SUBSET; IN; SUBSPACE_IMP_CONVEX]);;
+
+let CONVEX_HULL_SUBSET_AFFINE_HULL = prove
+ (`!s. (convex hull s) SUBSET (affine hull s)`,
+  GEN_TAC THEN REWRITE_TAC[span] THEN MATCH_MP_TAC HULL_ANTIMONO THEN
+  REWRITE_TAC[SUBSET; IN; AFFINE_IMP_CONVEX]);;
+
+let COLLINEAR_CONVEX_HULL_COLLINEAR = prove
+ (`!s:real^N->bool. collinear(convex hull s) <=> collinear s`,
+  MESON_TAC[COLLINEAR_SUBSET; HULL_SUBSET; SUBSET_TRANS;
+            COLLINEAR_AFFINE_HULL_COLLINEAR; CONVEX_HULL_SUBSET_AFFINE_HULL]);;
+
+let AFFINE_SPAN = prove
+ (`!s. affine(span s)`,
+  SIMP_TAC[SUBSPACE_IMP_AFFINE; SUBSPACE_SPAN]);;
+
+let CONVEX_SPAN = prove
+ (`!s. convex(span s)`,
+  SIMP_TAC[SUBSPACE_IMP_CONVEX; SUBSPACE_SPAN]);;
+
+let AFFINE_EQ_SUBSPACE = prove
+ (`!s:real^N->bool. vec 0 IN s ==> (affine s <=> subspace s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN ASM_SIMP_TAC[subspace; affine] THEN
+  DISCH_TAC THEN MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN
+  CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`c:real`; `x:real^N`] THEN STRIP_TAC THEN
+    SUBST1_TAC(VECTOR_ARITH `c % x:real^N = c % x + (&1 - c) % vec 0`) THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+    DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
+    STRIP_TAC THEN SUBST1_TAC(VECTOR_ARITH
+     `x + y:real^N = &2 % (&1 / &2 % x + &1 / &2 % y)`) THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC]);;
+
+let AFFINE_IMP_SUBSPACE = prove
+ (`!s. affine s /\ vec 0 IN s ==> subspace s`,
+  SIMP_TAC[GSYM AFFINE_EQ_SUBSPACE]);;
+
+let AFFINE_HULL_EQ_SPAN = prove
+ (`!s:real^N->bool. (vec 0) IN affine hull s ==> affine hull s = span s`,
+  GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[AFFINE_HULL_SUBSET_SPAN] THEN
+  REWRITE_TAC[SUBSET] THEN MATCH_MP_TAC SPAN_INDUCT THEN
+  ASM_REWRITE_TAC[SUBSET; subspace; IN_ELIM_THM; HULL_INC] THEN
+  REPEAT STRIP_TAC THENL
+   [SUBST1_TAC(VECTOR_ARITH
+     `x + y:real^N = &2 % (&1 / &2 % x + &1 / &2 % y) + --(&1) % vec 0`) THEN
+    MATCH_MP_TAC(REWRITE_RULE[affine] AFFINE_AFFINE_HULL) THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[affine] AFFINE_AFFINE_HULL) THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[];
+    SUBST1_TAC(VECTOR_ARITH
+     `c % x:real^N = c % x + (&1 - c) % vec 0`) THEN
+    MATCH_MP_TAC(REWRITE_RULE[affine] AFFINE_AFFINE_HULL) THEN
+    ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC]);;
+
+let CLOSED_AFFINE = prove
+ (`!s:real^N->bool. affine s ==> closed s`,
+  GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[CLOSED_EMPTY] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+  SUBGOAL_THEN `affine (IMAGE (\x:real^N. --a + x) s)
+                ==> closed (IMAGE (\x:real^N. --a + x) s)`
+  MP_TAC THENL
+   [DISCH_THEN(fun th -> MATCH_MP_TAC CLOSED_SUBSPACE THEN MP_TAC th) THEN
+    MATCH_MP_TAC EQ_IMP THEN MATCH_MP_TAC AFFINE_EQ_SUBSPACE THEN
+    REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `a:real^N` THEN
+    ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC;
+    REWRITE_TAC[AFFINE_TRANSLATION_EQ; CLOSED_TRANSLATION_EQ]]);;
+
+let CLOSED_AFFINE_HULL = prove
+ (`!s. closed(affine hull s)`,
+  SIMP_TAC[CLOSED_AFFINE; AFFINE_AFFINE_HULL]);;
+
+let CLOSURE_SUBSET_AFFINE_HULL = prove
+ (`!s. closure s SUBSET affine hull s`,
+  GEN_TAC THEN MATCH_MP_TAC CLOSURE_MINIMAL THEN
+  REWRITE_TAC[CLOSED_AFFINE_HULL; HULL_SUBSET]);;
+
+let AFFINE_HULL_CLOSURE = prove
+ (`!s:real^N->bool. affine hull (closure s) = affine hull s`,
+  GEN_TAC THEN MATCH_MP_TAC HULL_UNIQUE THEN
+  REWRITE_TAC[CLOSURE_SUBSET_AFFINE_HULL; AFFINE_AFFINE_HULL] THEN
+  X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN
+  MATCH_MP_TAC HULL_MINIMAL THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[CLOSURE_SUBSET; SUBSET]);;
+
+let AFFINE_HULL_EQ_SPAN_EQ = prove
+ (`!s:real^N->bool. (affine hull s = span s) <=> (vec 0) IN affine hull s`,
+  GEN_TAC THEN EQ_TAC THEN SIMP_TAC[SPAN_0; AFFINE_HULL_EQ_SPAN]);;
+
+let AFFINE_DEPENDENT_IMP_DEPENDENT = prove
+ (`!s. affine_dependent s ==> dependent s`,
+  REWRITE_TAC[affine_dependent; dependent] THEN
+  MESON_TAC[SUBSET; AFFINE_HULL_SUBSET_SPAN]);;
+
+let DEPENDENT_AFFINE_DEPENDENT_CASES = prove
+ (`!s:real^N->bool.
+        dependent s <=> affine_dependent s \/ (vec 0) IN affine hull s`,
+  REWRITE_TAC[DEPENDENT_EXPLICIT; AFFINE_DEPENDENT_EXPLICIT;
+              AFFINE_HULL_EXPLICIT_ALT; IN_ELIM_THM] THEN
+  GEN_TAC THEN ONCE_REWRITE_TAC[OR_EXISTS_THM] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `t:real^N->bool` THEN
+  ASM_CASES_TAC `FINITE(t:real^N->bool)` THEN ASM_REWRITE_TAC[] THEN
+  EQ_TAC THEN DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN
+   (X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC))
+  THENL
+   [ASM_CASES_TAC `sum t (u:real^N->real) = &0` THENL
+     [ASM_MESON_TAC[]; ALL_TAC] THEN
+    DISJ2_TAC THEN EXISTS_TAC `\v:real^N. inv(sum t u) * u v` THEN
+    ASM_SIMP_TAC[SUM_LMUL; VSUM_LMUL; GSYM VECTOR_MUL_ASSOC] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_RZERO; REAL_MUL_LINV];
+    EXISTS_TAC `u:real^N->real` THEN ASM_MESON_TAC[];
+    EXISTS_TAC `u:real^N->real` THEN
+    ASM_REWRITE_TAC[SET_RULE
+     `(?v. v IN t /\ ~p v) <=> ~(!v. v IN t ==> p v)`] THEN
+    DISCH_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `x = &1 ==> x = &0 ==> F`)) THEN
+    ASM_MESON_TAC[SUM_EQ_0]]);;
+
+let DEPENDENT_IMP_AFFINE_DEPENDENT = prove
+ (`!a:real^N s. dependent {x - a | x IN s} /\ ~(a IN s)
+                ==> affine_dependent(a INSERT s)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[DEPENDENT_EXPLICIT; AFFINE_DEPENDENT_EXPLICIT] THEN
+  REWRITE_TAC[SIMPLE_IMAGE; CONJ_ASSOC; FINITE_SUBSET_IMAGE] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN REWRITE_TAC[GSYM CONJ_ASSOC] THEN
+  GEN_REWRITE_TAC LAND_CONV [SWAP_EXISTS_THM] THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [SWAP_EXISTS_THM] THEN
+  REWRITE_TAC[TAUT `a /\ x = IMAGE f s /\ b <=> x = IMAGE f s /\ a /\ b`] THEN
+  REWRITE_TAC[UNWIND_THM2; EXISTS_IN_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->real` (X_CHOOSE_THEN `t:real^N->bool`
+    STRIP_ASSUME_TAC)) THEN
+  FIRST_X_ASSUM(MP_TAC o check (is_eq o concl)) THEN
+  ASM_SIMP_TAC[VSUM_IMAGE; VECTOR_ARITH `x - a:real^N = y - a <=> x = y`] THEN
+  ASM_SIMP_TAC[o_DEF; VECTOR_SUB_LDISTRIB; VSUM_SUB; VSUM_RMUL] THEN
+  STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC
+   [`(a:real^N) INSERT t`;
+    `\x. if x = a then --sum t (\x. u (x - a))
+         else (u:real^N->real) (x - a)`] THEN
+  ASM_REWRITE_TAC[FINITE_INSERT; SUBSET_REFL] THEN
+  ASM_SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC(REAL_ARITH `x = y ==> --x + y = &0`) THEN
+    MATCH_MP_TAC SUM_EQ THEN ASM_MESON_TAC[];
+    EXISTS_TAC `x:real^N` THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[];
+    MATCH_MP_TAC(VECTOR_ARITH
+     `!s. s - t % a = vec 0 /\ s = u ==> --t % a + u = vec 0`) THEN
+    EXISTS_TAC `vsum t (\x:real^N. u(x - a) % x)` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC VSUM_EQ THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[] THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]]);;
+
+let AFFINE_DEPENDENT_BIGGERSET = prove
+ (`!s:real^N->bool.
+        (FINITE s ==> CARD s >= dimindex(:N) + 2) ==> affine_dependent s`,
+  GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[CARD_CLAUSES; ARITH_RULE `~(0 >= n + 2)`; FINITE_RULES] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP (SET_RULE
+   `x IN s ==> s = x INSERT (s DELETE x)`)) THEN
+  SIMP_TAC[FINITE_INSERT; CARD_CLAUSES; IN_DELETE] THEN
+  REWRITE_TAC[ARITH_RULE `SUC x >= n + 2 <=> x > n`] THEN DISCH_TAC THEN
+  MATCH_MP_TAC DEPENDENT_IMP_AFFINE_DEPENDENT THEN
+  REWRITE_TAC[IN_DELETE] THEN MATCH_MP_TAC DEPENDENT_BIGGERSET THEN
+  REWRITE_TAC[SET_RULE `{x - a:real^N | x | x IN s /\ ~(x = a)} =
+                        IMAGE (\x. x - a) (s DELETE a)`] THEN
+  ASM_SIMP_TAC[FINITE_IMAGE_INJ_EQ;
+               VECTOR_ARITH `x - a = y - a <=> x:real^N = y`;
+               CARD_IMAGE_INJ]);;
+
+let AFFINE_DEPENDENT_BIGGERSET_GENERAL = prove
+ (`!s:real^N->bool. (FINITE s ==> CARD s >= dim s + 2) ==> affine_dependent s`,
+  GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[CARD_CLAUSES; ARITH_RULE `~(0 >= n + 2)`; FINITE_RULES] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP (SET_RULE
+   `x IN s ==> s = x INSERT (s DELETE x)`)) THEN
+  SIMP_TAC[FINITE_INSERT; CARD_CLAUSES; IN_DELETE] THEN
+  REWRITE_TAC[ARITH_RULE `SUC x >= n + 2 <=> x > n`] THEN DISCH_TAC THEN
+  MATCH_MP_TAC DEPENDENT_IMP_AFFINE_DEPENDENT THEN
+  REWRITE_TAC[IN_DELETE] THEN
+  MATCH_MP_TAC DEPENDENT_BIGGERSET_GENERAL THEN
+  REWRITE_TAC[SET_RULE `{x - a:real^N | x | x IN s /\ ~(x = a)} =
+                        IMAGE (\x. x - a) (s DELETE a)`] THEN
+  ASM_SIMP_TAC[FINITE_IMAGE_INJ_EQ; FINITE_DELETE;
+               VECTOR_ARITH `x - a = y - a <=> x:real^N = y`;
+               CARD_IMAGE_INJ] THEN
+  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o check(is_imp o concl)) THEN
+  ASM_REWRITE_TAC[FINITE_DELETE] THEN
+  MATCH_MP_TAC(ARITH_RULE `c:num <= b ==> (a > b ==> a > c)`) THEN
+  MATCH_MP_TAC SUBSET_LE_DIM THEN REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  SIMP_TAC[SPAN_SUB; SPAN_SUPERSET; IN_INSERT]);;
+
+let AFFINE_INDEPENDENT_IMP_FINITE = prove
+ (`!s:real^N->bool. ~(affine_dependent s) ==> FINITE s`,
+  MESON_TAC[AFFINE_DEPENDENT_BIGGERSET]);;
+
+let AFFINE_INDEPENDENT_CARD_LE = prove
+ (`!s:real^N->bool. ~(affine_dependent s) ==> CARD s <= dimindex(:N) + 1`,
+  REWRITE_TAC[ARITH_RULE `s <= n + 1 <=> ~(n + 2 <= s)`; CONTRAPOS_THM] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC AFFINE_DEPENDENT_BIGGERSET THEN
+  ASM_REWRITE_TAC[GE]);;
+
+let AFFINE_INDEPENDENT_CONVEX_AFFINE_HULL = prove
+ (`!s t:real^N->bool.
+        ~affine_dependent s /\ t SUBSET s
+        ==> convex hull t = affine hull t INTER convex hull s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  SUBGOAL_THEN `FINITE(t:real^N->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+  MATCH_MP_TAC(SET_RULE
+   `ct SUBSET a /\ ct SUBSET cs /\ a INTER cs SUBSET ct
+    ==> ct = a INTER cs`) THEN
+  ASM_SIMP_TAC[HULL_MONO; CONVEX_HULL_SUBSET_AFFINE_HULL] THEN
+  REWRITE_TAC[SUBSET; IN_INTER; CONVEX_HULL_FINITE; AFFINE_HULL_FINITE] THEN
+  X_GEN_TAC `y:real^N` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `v:real^N->real` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `u:real^N->real` THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV
+    [AFFINE_DEPENDENT_EXPLICIT]) THEN
+  REWRITE_TAC[NOT_EXISTS_THM] THEN
+  DISCH_THEN(MP_TAC o SPECL [`s:real^N->bool`;
+        `\x:real^N. if x IN t then v x - u x:real else v x`]) THEN
+  ASM_REWRITE_TAC[SUBSET_REFL] THEN REWRITE_TAC[MESON[]
+   `(if p then a else b) % x = if p then a % x else b % x`] THEN
+  ASM_SIMP_TAC[VSUM_CASES; SUM_CASES; SET_RULE
+   `t SUBSET s ==> {x | x IN s /\ x IN t} = t`] THEN
+  ASM_SIMP_TAC[GSYM DIFF; SUM_DIFF; VSUM_DIFF; VECTOR_SUB_RDISTRIB;
+               SUM_SUB; VSUM_SUB] THEN
+  REWRITE_TAC[REAL_ARITH `a - b + b - a = &0`; NOT_EXISTS_THM;
+              VECTOR_ARITH `a - b + b - a:real^N = vec 0`] THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+  ASM_REWRITE_TAC[REAL_SUB_0] THEN ASM SET_TAC[]);;
+
+let DISJOINT_AFFINE_HULL = prove
+ (`!s t u:real^N->bool.
+        ~affine_dependent s /\ t SUBSET s /\ u SUBSET s /\ DISJOINT t u
+        ==> DISJOINT (affine hull t) (affine hull u)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  SUBGOAL_THEN `FINITE(t:real^N->bool) /\ FINITE (u:real^N->bool)` ASSUME_TAC
+  THENL [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+  REWRITE_TAC[IN_DISJOINT; AFFINE_HULL_FINITE; IN_ELIM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `y:real^N` MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `a:real^N->real` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `b:real^N->real` STRIP_ASSUME_TAC)) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV
+    [AFFINE_DEPENDENT_EXPLICIT]) THEN
+  REWRITE_TAC[NOT_EXISTS_THM] THEN
+  MAP_EVERY EXISTS_TAC
+   [`s:real^N->bool`;
+    `\x:real^N. if x IN t then a x else if x IN u then --(b x) else &0`] THEN
+  ASM_REWRITE_TAC[SUBSET_REFL] THEN REWRITE_TAC[MESON[]
+   `(if p then a else b) % x = if p then a % x else b % x`] THEN
+  ASM_SIMP_TAC[SUM_CASES; SUBSET_REFL; VSUM_CASES; GSYM DIFF; SUM_DIFF;
+      VSUM_DIFF; SET_RULE `t SUBSET s ==> {x | x IN s /\ x IN t} = t`] THEN
+  ASM_SIMP_TAC[SUM_0; VSUM_0; VECTOR_MUL_LZERO; SUM_NEG; VSUM_NEG;
+    VECTOR_MUL_LNEG; SET_RULE `DISJOINT t u ==> ~(x IN t /\ x IN u)`] THEN
+  REWRITE_TAC[EMPTY_GSPEC; SUM_CLAUSES; VSUM_CLAUSES] THEN
+  CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+  CONJ_TAC THENL [ALL_TAC; VECTOR_ARITH_TAC] THEN
+  UNDISCH_TAC `sum t (a:real^N->real) = &1` THEN
+  ASM_CASES_TAC `!x:real^N. x IN t ==> a x = &0` THEN
+  ASM_SIMP_TAC[SUM_EQ_0; REAL_OF_NUM_EQ; ARITH_EQ] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN ASM SET_TAC[]);;
+
+let AFFINE_INDEPENDENT_SPAN_EQ = prove
+ (`!s. ~(affine_dependent s) /\ CARD s = dimindex(:N) + 1
+       ==> affine hull s = (:real^N)`,
+  MATCH_MP_TAC SET_PROVE_CASES THEN
+  REWRITE_TAC[CARD_CLAUSES; ARITH_RULE `~(0 = n + 1)`] THEN
+  SIMP_TAC[IMP_CONJ; AFFINE_INDEPENDENT_IMP_FINITE; MESON[HAS_SIZE]
+   `FINITE s ==> (CARD s = n <=> s HAS_SIZE n)`] THEN
+  X_GEN_TAC `orig:real^N` THEN GEOM_ORIGIN_TAC `orig:real^N` THEN
+  SIMP_TAC[AFFINE_HULL_EQ_SPAN; IN_INSERT; SPAN_INSERT_0; HULL_INC] THEN
+  SIMP_TAC[HAS_SIZE; CARD_CLAUSES; FINITE_INSERT; IMP_CONJ] THEN
+  REWRITE_TAC[ARITH_RULE `SUC n = m + 1 <=> n = m`; GSYM UNIV_SUBSET] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CARD_GE_DIM_INDEPENDENT THEN
+  ASM_REWRITE_TAC[DIM_UNIV; SUBSET_UNIV; LE_REFL; independent] THEN
+  UNDISCH_TAC `~affine_dependent((vec 0:real^N) INSERT s)` THEN
+  REWRITE_TAC[CONTRAPOS_THM] THEN DISCH_TAC THEN
+  MATCH_MP_TAC DEPENDENT_IMP_AFFINE_DEPENDENT THEN
+  ASM_REWRITE_TAC[VECTOR_SUB_RZERO; SET_RULE `{x | x IN s} = s`]);;
+
+let AFFINE_INDEPENDENT_SPAN_GT = prove
+ (`!s:real^N->bool.
+        ~(affine_dependent s) /\ dimindex(:N) < CARD s
+        ==> affine hull s = (:real^N)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC AFFINE_INDEPENDENT_SPAN_EQ THEN
+  ASM_REWRITE_TAC[] THEN
+  MP_TAC(SPEC `s:real^N->bool` AFFINE_DEPENDENT_BIGGERSET) THEN
+  ASM_SIMP_TAC[AFFINE_INDEPENDENT_IMP_FINITE] THEN ASM_ARITH_TAC);;
+
+let EMPTY_INTERIOR_AFFINE_HULL = prove
+ (`!s:real^N->bool.
+        FINITE s /\ CARD(s) <= dimindex(:N)
+        ==> interior(affine hull s) = {}`,
+  REWRITE_TAC[IMP_CONJ] THEN  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[AFFINE_HULL_EMPTY; INTERIOR_EMPTY] THEN
+  SUBGOAL_THEN
+   `!x s:real^N->bool n.
+        ~(x IN s) /\ (x INSERT s) HAS_SIZE n /\ n <= dimindex(:N)
+        ==> interior(affine hull(x INSERT s)) = {}`
+   (fun th -> MESON_TAC[th; HAS_SIZE; FINITE_INSERT]) THEN
+  X_GEN_TAC `orig:real^N` THEN GEOM_ORIGIN_TAC `orig:real^N` THEN
+  SIMP_TAC[AFFINE_HULL_EQ_SPAN; IN_INSERT; SPAN_INSERT_0; HULL_INC] THEN
+  REWRITE_TAC[HAS_SIZE; FINITE_INSERT; IMP_CONJ] THEN
+  SIMP_TAC[CARD_CLAUSES] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EMPTY_INTERIOR_LOWDIM THEN
+  MATCH_MP_TAC LET_TRANS THEN EXISTS_TAC `CARD(s:real^N->bool)` THEN
+  ASM_SIMP_TAC[DIM_LE_CARD; DIM_SPAN] THEN ASM_ARITH_TAC);;
+
+let EMPTY_INTERIOR_CONVEX_HULL = prove
+ (`!s:real^N->bool.
+        FINITE s /\ CARD(s) <= dimindex(:N)
+        ==> interior(convex hull s) = {}`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(SET_RULE `!t. s SUBSET t /\ t = {} ==> s = {}`) THEN
+  EXISTS_TAC `interior(affine hull s):real^N->bool` THEN
+  SIMP_TAC[SUBSET_INTERIOR; CONVEX_HULL_SUBSET_AFFINE_HULL] THEN
+  ASM_SIMP_TAC[EMPTY_INTERIOR_AFFINE_HULL]);;
+
+let AFFINE_DEPENDENT_CHOOSE = prove
+ (`!s a:real^N.
+       ~(affine_dependent s)
+       ==> (affine_dependent(a INSERT s) <=> ~(a IN s) /\ a IN affine hull s)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `(a:real^N) IN s` THEN
+  ASM_SIMP_TAC[SET_RULE `a IN s ==> a INSERT s = s`] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  EQ_TAC THENL
+   [UNDISCH_TAC `~(affine_dependent(s:real^N->bool))` THEN
+    ASM_SIMP_TAC[AFFINE_DEPENDENT_EXPLICIT_FINITE; AFFINE_HULL_FINITE;
+                 FINITE_INSERT; IN_ELIM_THM; SUM_CLAUSES; VSUM_CLAUSES] THEN
+    DISCH_TAC THEN REWRITE_TAC[EXISTS_IN_INSERT] THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^N->real` MP_TAC) THEN
+    ASM_CASES_TAC `(u:real^N->real) a = &0` THEN ASM_REWRITE_TAC[] THENL
+     [REWRITE_TAC[REAL_ADD_LID; VECTOR_MUL_LZERO; VECTOR_ADD_LID] THEN
+      DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_EXISTS_THM]) THEN
+      DISCH_THEN(MP_TAC o SPEC `u:real^N->real`) THEN ASM_REWRITE_TAC[];
+      ONCE_REWRITE_TAC[REAL_ARITH `ua + sa = &0 <=> sa = --ua`;
+                   VECTOR_ARITH `va + sa:real^N = vec 0 <=> sa = --va`] THEN
+      STRIP_TAC THEN EXISTS_TAC `(\x. --(inv(u a)) * u x):real^N->real` THEN
+      ASM_SIMP_TAC[SUM_LMUL; GSYM VECTOR_MUL_ASSOC; VSUM_LMUL] THEN
+      ASM_REWRITE_TAC[VECTOR_MUL_ASSOC; GSYM VECTOR_MUL_LNEG] THEN
+      REWRITE_TAC[REAL_ARITH `--a * --b:real = a * b`] THEN
+      ASM_SIMP_TAC[REAL_MUL_LINV; VECTOR_MUL_LID]];
+    DISCH_TAC THEN REWRITE_TAC[affine_dependent] THEN
+    EXISTS_TAC `a:real^N` THEN
+    ASM_SIMP_TAC[IN_INSERT; SET_RULE
+     `~(a IN s) ==> (a INSERT s) DELETE a = s`]]);;
+
+let AFFINE_INDEPENDENT_INSERT = prove
+ (`!s a:real^N.
+        ~(affine_dependent s) /\ ~(a IN affine hull s)
+        ==> ~(affine_dependent(a INSERT s))`,
+  SIMP_TAC[AFFINE_DEPENDENT_CHOOSE]);;
+
+let AFFINE_HULL_EXPLICIT_UNIQUE = prove
+ (`!s:real^N->bool u u'.
+      ~(affine_dependent s) /\
+      sum s u = &1 /\ sum s u' = &1 /\
+      vsum s (\x. u x % x) = vsum s (\x. u' x % x)
+      ==> !x. x IN s ==> u x = u' x`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP AFFINE_DEPENDENT_EXPLICIT_FINITE) THEN
+  ASM_REWRITE_TAC[NOT_EXISTS_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `(\x. u x - u' x):real^N->real`) THEN
+  ASM_SIMP_TAC[VSUM_SUB; SUM_SUB; REAL_SUB_REFL; VECTOR_SUB_RDISTRIB;
+               VECTOR_SUB_REFL; VECTOR_SUB_EQ; REAL_SUB_0] THEN
+  MESON_TAC[]);;
+
+let INDEPENDENT_IMP_AFFINE_DEPENDENT_0 = prove
+ (`!s. independent s ==> ~(affine_dependent(vec 0 INSERT s))`,
+  REWRITE_TAC[independent; DEPENDENT_AFFINE_DEPENDENT_CASES] THEN
+  SIMP_TAC[DE_MORGAN_THM; AFFINE_INDEPENDENT_INSERT]);;
+
+let AFFINE_INDEPENDENT_STDBASIS = prove
+ (`~(affine_dependent
+      ((vec 0:real^N) INSERT {basis i | 1 <= i /\ i <= dimindex (:N)}))`,
+  SIMP_TAC[INDEPENDENT_IMP_AFFINE_DEPENDENT_0; INDEPENDENT_STDBASIS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Nonempty affine sets are translates of (unique) subspaces.                *)
+(* ------------------------------------------------------------------------- *)
+
+let AFFINE_TRANSLATION_SUBSPACE = prove
+ (`!t:real^N->bool.
+        affine t /\ ~(t = {}) <=> ?a s. subspace s /\ t = IMAGE (\x. a + x) s`,
+  GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[SUBSPACE_IMP_NONEMPTY; IMAGE_EQ_EMPTY;
+               AFFINE_TRANSLATION; SUBSPACE_IMP_AFFINE] THEN
+  FIRST_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
+  ONCE_REWRITE_TAC[TRANSLATION_GALOIS] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  REWRITE_TAC[UNWIND_THM2] THEN MATCH_MP_TAC AFFINE_IMP_SUBSPACE THEN
+  ASM_REWRITE_TAC[AFFINE_TRANSLATION_EQ; IN_IMAGE] THEN
+  EXISTS_TAC `a:real^N` THEN ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC);;
+
+let AFFINE_TRANSLATION_UNIQUE_SUBSPACE = prove
+ (`!t:real^N->bool.
+        affine t /\ ~(t = {}) <=>
+        ?!s. ?a. subspace s /\ t = IMAGE (\x. a + x) s`,
+  GEN_TAC THEN REWRITE_TAC[AFFINE_TRANSLATION_SUBSPACE] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!a a' s s'. P s a /\ P s' a' ==> s = s')
+    ==> ((?a s. P s a) <=> (?!s. ?a. P s a))`) THEN
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[TRANSLATION_GALOIS] THEN
+  DISCH_THEN SUBST1_TAC THEN CONV_TAC SYM_CONV THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; VECTOR_ADD_ASSOC] THEN
+  MATCH_MP_TAC SUBSPACE_TRANSLATION_SELF THEN ASM_REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `--a' + a:real^N = --(a' - a)`] THEN
+  MATCH_MP_TAC SUBSPACE_NEG THEN ASM_REWRITE_TAC[] THEN
+  UNDISCH_TAC `t = IMAGE (\x:real^N. a' + x) s'` THEN
+  DISCH_THEN(MP_TAC o AP_TERM `\s. (a':real^N) IN s`) THEN
+  REWRITE_TAC[IN_IMAGE; VECTOR_ARITH `a:real^N = a + x <=> x = vec 0`] THEN
+  ASM_SIMP_TAC[UNWIND_THM2; SUBSPACE_0] THEN
+  REWRITE_TAC[IN_IMAGE; VECTOR_ARITH `a':real^N = a + x <=> x = a' - a`] THEN
+  REWRITE_TAC[UNWIND_THM2]);;
+
+let AFFINE_TRANSLATION_SUBSPACE_EXPLICIT = prove
+ (`!t:real^N->bool a.
+        affine t /\ a IN t
+        ==> subspace {x - a | x IN t} /\
+            t = IMAGE (\x. a + x) {x - a | x IN t}`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[AFFINE_DIFFS_SUBSPACE] THEN
+  ASM_REWRITE_TAC[SIMPLE_IMAGE; GSYM IMAGE_o] THEN
+  REWRITE_TAC[o_DEF; VECTOR_SUB_ADD2; IMAGE_ID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* If we take a slice out of a set, we can do it perpendicularly,            *)
+(* with the normal vector to the slice parallel to the affine hull.          *)
+(* ------------------------------------------------------------------------- *)
+
+let AFFINE_PARALLEL_SLICE = prove
+  (`!s a:real^N b.
+       affine s
+       ==> s INTER {x | a dot x <= b} = {} \/ s SUBSET {x | a dot x <= b} \/
+           ?a' b'. ~(a' = vec 0) /\
+
+                   s INTER {x | a' dot x <= b'} = s INTER {x | a dot x <= b} /\
+                   s INTER {x | a' dot x = b'} = s INTER {x | a dot x = b} /\
+                   !w. w IN s ==> (w + a') IN s`,
+   REPEAT STRIP_TAC THEN
+   ASM_CASES_TAC `s INTER {x:real^N | a dot x = b} = {}` THENL
+    [MATCH_MP_TAC(TAUT `~(~p /\ ~q) ==> p \/ q \/ r`) THEN
+     REPEAT STRIP_TAC THEN SUBGOAL_THEN
+      `?u v:real^N. u IN s /\ v IN s /\
+                    a dot u <= b /\ ~(a dot v <= b)`
+     STRIP_ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+     SUBGOAL_THEN `(a:real^N) dot u < b` ASSUME_TAC THENL
+      [ASM_REWRITE_TAC[REAL_LT_LE] THEN ASM SET_TAC[]; ALL_TAC] THEN
+     RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LE]) THEN
+     FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+     REWRITE_TAC[NOT_IN_EMPTY; IN_INTER; NOT_FORALL_THM; IN_ELIM_THM] THEN
+     EXISTS_TAC
+      `u + (b - a dot u) / (a dot v - a dot u) % (v - u):real^N` THEN
+     ASM_SIMP_TAC[IN_AFFINE_ADD_MUL_DIFF] THEN
+     REWRITE_TAC[DOT_RADD; DOT_RMUL; DOT_RSUB] THEN
+     REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD;
+     FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+     DISCH_THEN(X_CHOOSE_THEN `z:real^N` MP_TAC) THEN
+     REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN POP_ASSUM MP_TAC THEN
+     GEN_GEOM_ORIGIN_TAC `z:real^N` ["a"; "a'"; "b'"; "w"] THEN
+     REPEAT STRIP_TAC THEN FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+     REWRITE_TAC[VECTOR_ADD_RID; FORALL_IN_IMAGE] THEN
+     REWRITE_TAC[DOT_RADD; REAL_ARITH `a + x <= a <=> x <= &0`] THEN
+     SUBGOAL_THEN `subspace(s:real^N->bool) /\ span s = s`
+     STRIP_ASSUME_TAC THENL
+      [ASM_MESON_TAC[AFFINE_IMP_SUBSPACE; SPAN_EQ_SELF]; ALL_TAC] THEN
+     MP_TAC(ISPECL [`s:real^N->bool`; `a:real^N`]
+           ORTHOGONAL_SUBSPACE_DECOMP_EXISTS) THEN
+     ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; orthogonal] THEN
+     MAP_EVERY X_GEN_TAC [`a':real^N`; `a'':real^N`] THEN
+     ASM_CASES_TAC `a':real^N = vec 0` THENL
+      [ASM_REWRITE_TAC[VECTOR_ADD_LID] THEN
+       ASM_CASES_TAC `a'':real^N = a` THEN ASM_REWRITE_TAC[] THEN
+       SIMP_TAC[SUBSET; IN_ELIM_THM; REAL_LE_REFL];
+       ALL_TAC] THEN
+     STRIP_TAC THEN REPEAT DISJ2_TAC THEN
+     EXISTS_TAC `a':real^N` THEN ASM_REWRITE_TAC[] THEN
+     EXISTS_TAC `(a':real^N) dot z` THEN
+     REPEAT(CONJ_TAC THENL
+      [MATCH_MP_TAC(SET_RULE
+        `(!x. x IN s ==> (p x <=> q x))
+         ==> s INTER {x | p x} = s INTER {x | q x}`) THEN
+       ASM_SIMP_TAC[DOT_LADD] THEN REAL_ARITH_TAC;
+       ALL_TAC]) THEN
+     X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN REWRITE_TAC[IN_IMAGE] THEN
+     EXISTS_TAC `x + a':real^N` THEN
+     ASM_SIMP_TAC[SUBSPACE_ADD; VECTOR_ADD_ASSOC]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Affine dimension.                                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let MAXIMAL_AFFINE_INDEPENDENT_SUBSET = prove
+ (`!s b:real^N->bool.
+        b SUBSET s /\ ~(affine_dependent b) /\
+        (!b'. b SUBSET b' /\ b' SUBSET s /\ ~(affine_dependent b') ==> b' = b)
+        ==> s SUBSET (affine hull b)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(SET_RULE `(!a. a IN t /\ ~(a IN s) ==> F) ==> t SUBSET s`) THEN
+  X_GEN_TAC `a:real^N` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(a:real^N) INSERT b`) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP
+   (ONCE_REWRITE_RULE[GSYM CONTRAPOS_THM] HULL_INC)) THEN
+  ASM_SIMP_TAC[AFFINE_INDEPENDENT_INSERT; INSERT_SUBSET] THEN
+  ASM SET_TAC[]);;
+
+let MAXIMAL_AFFINE_INDEPENDENT_SUBSET_AFFINE = prove
+ (`!s b:real^N->bool.
+        affine s /\ b SUBSET s /\ ~(affine_dependent b) /\
+        (!b'. b SUBSET b' /\ b' SUBSET s /\ ~(affine_dependent b') ==> b' = b)
+        ==> affine hull b = s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[HULL_MONO; HULL_P];
+    ASM_MESON_TAC[MAXIMAL_AFFINE_INDEPENDENT_SUBSET]]);;
+
+let EXTEND_TO_AFFINE_BASIS = prove
+ (`!s u:real^N->bool.
+        ~(affine_dependent s) /\ s SUBSET u
+        ==> ?t. ~(affine_dependent t) /\ s SUBSET t /\ t SUBSET u /\
+                affine hull t = affine hull u`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPEC `\n. ?t:real^N->bool. ~(affine_dependent t) /\ s SUBSET t /\
+                                    t SUBSET u /\ CARD t = n`
+   num_MAX) THEN
+  DISCH_THEN(MP_TAC o fst o EQ_IMP_RULE) THEN REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[SUBSET_REFL; AFFINE_INDEPENDENT_CARD_LE]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `n:num` (CONJUNCTS_THEN2 MP_TAC ASSUME_TAC)) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[HULL_MONO; HULL_P]; ALL_TAC] THEN
+  MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[AFFINE_AFFINE_HULL] THEN
+  MATCH_MP_TAC MAXIMAL_AFFINE_INDEPENDENT_SUBSET THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `c:real^N->bool` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `CARD(c:real^N->bool)`) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `c:real^N->bool`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; DISCH_TAC] THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC CARD_SUBSET_LE THEN
+  ASM_MESON_TAC[AFFINE_INDEPENDENT_IMP_FINITE]);;
+
+let AFFINE_BASIS_EXISTS = prove
+ (`!s:real^N->bool.
+      ?b. ~(affine_dependent b) /\ b SUBSET s /\
+          affine hull b = affine hull s`,
+  GEN_TAC THEN
+  MP_TAC(ISPECL [`{}:real^N->bool`; `s:real^N->bool`]
+    EXTEND_TO_AFFINE_BASIS) THEN
+  REWRITE_TAC[AFFINE_INDEPENDENT_EMPTY; EMPTY_SUBSET]);;
+
+let aff_dim = new_definition
+  `aff_dim s =
+        @d:int. ?b. affine hull b = affine hull s /\ ~(affine_dependent b) /\
+                    &(CARD b) = d + &1`;;
+
+let AFF_DIM = prove
+ (`!s. ?b. affine hull b = affine hull s /\
+           ~(affine_dependent b) /\
+           aff_dim s = &(CARD b) - &1`,
+  GEN_TAC THEN
+  REWRITE_TAC[aff_dim; INT_ARITH `y:int = x + &1 <=> x = y - &1`] THEN
+  CONV_TAC SELECT_CONV THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; EXISTS_REFL] THEN
+  MESON_TAC[AFFINE_BASIS_EXISTS]);;
+
+let AFF_DIM_EMPTY = prove
+ (`aff_dim {} = -- &1`,
+  REWRITE_TAC[aff_dim; AFFINE_HULL_EMPTY; AFFINE_HULL_EQ_EMPTY] THEN
+  REWRITE_TAC[UNWIND_THM2; AFFINE_INDEPENDENT_EMPTY; CARD_CLAUSES] THEN
+  REWRITE_TAC[INT_ARITH `&0 = d + &1 <=> d:int = -- &1`; SELECT_REFL]);;
+
+let AFF_DIM_AFFINE_HULL = prove
+ (`!s. aff_dim(affine hull s) = aff_dim s`,
+  REWRITE_TAC[aff_dim; HULL_HULL]);;
+
+let AFF_DIM_TRANSLATION_EQ = prove
+ (`!a:real^N s. aff_dim (IMAGE (\x. a + x) s) = aff_dim s`,
+  REWRITE_TAC[aff_dim] THEN GEOM_TRANSLATE_TAC[] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> ~(a /\ b ==> ~c)`] THEN
+  SIMP_TAC[AFFINE_INDEPENDENT_IMP_FINITE; CARD_IMAGE_INJ;
+           VECTOR_ARITH `a + x:real^N = a + y <=> x = y`]);;
+
+add_translation_invariants [AFF_DIM_TRANSLATION_EQ];;
+
+let AFFINE_INDEPENDENT_CARD_DIM_DIFFS = prove
+ (`!s a:real^N.
+        ~affine_dependent s /\ a IN s
+        ==> CARD s = dim {x - a | x IN s} + 1`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  MATCH_MP_TAC(ARITH_RULE `~(s = 0) /\ v = s - 1 ==> s = v + 1`) THEN
+  ASM_SIMP_TAC[CARD_EQ_0] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC DIM_UNIQUE THEN
+  EXISTS_TAC `{b - a:real^N |b| b IN (s DELETE a)}` THEN REPEAT CONJ_TAC THENL
+   [SET_TAC[];
+    REWRITE_TAC[SIMPLE_IMAGE; SUBSET; FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN ASM_CASES_TAC `x:real^N = a` THENL
+     [ASM_REWRITE_TAC[VECTOR_SUB_REFL; SPAN_0];
+      MATCH_MP_TAC SPAN_SUPERSET THEN ASM SET_TAC[]];
+    UNDISCH_TAC `~affine_dependent(s:real^N->bool)` THEN
+    REWRITE_TAC[independent; CONTRAPOS_THM] THEN DISCH_TAC THEN
+    SUBGOAL_THEN `s = (a:real^N) INSERT (s DELETE a)` SUBST1_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC DEPENDENT_IMP_AFFINE_DEPENDENT THEN
+    ASM_REWRITE_TAC[IN_DELETE];
+    REWRITE_TAC[SIMPLE_IMAGE] THEN MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN
+    SIMP_TAC[VECTOR_ARITH `x - a:real^N = y - a <=> x = y`] THEN
+    ASM_SIMP_TAC[HAS_SIZE; FINITE_DELETE; CARD_DELETE]]);;
+
+let AFF_DIM_DIM_AFFINE_DIFFS = prove
+ (`!a:real^N s. affine s /\ a IN s ==> aff_dim s = &(dim {x - a | x IN s})`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `s:real^N->bool` AFF_DIM) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` MP_TAC) THEN
+  ASM_CASES_TAC `b:real^N->bool = {}` THENL
+   [ASM_MESON_TAC[AFFINE_HULL_EQ_EMPTY; NOT_IN_EMPTY]; ALL_TAC] THEN
+  STRIP_TAC THEN
+  ASM_REWRITE_TAC[INT_EQ_SUB_RADD; INT_OF_NUM_ADD; INT_OF_NUM_EQ] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `c:real^N`) THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `dim {x - c:real^N | x IN b} + 1` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC AFFINE_INDEPENDENT_CARD_DIM_DIFFS THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `dim {x - c:real^N | x IN affine hull b} + 1` THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[DIFFS_AFFINE_HULL_SPAN; DIM_SPAN]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+  SUBGOAL_THEN `affine hull s:real^N->bool = s` SUBST1_TAC THENL
+   [ASM_MESON_TAC[AFFINE_HULL_EQ]; ALL_TAC] THEN
+  SUBGOAL_THEN `(c:real^N) IN s` ASSUME_TAC THENL
+   [ASM_MESON_TAC[AFFINE_HULL_EQ; HULL_INC]; ALL_TAC] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  SIMP_TAC[VECTOR_ARITH `x - c:real^N = y - a <=> y = x + &1 % (a - c)`] THEN
+  ASM_MESON_TAC[IN_AFFINE_ADD_MUL_DIFF]);;
+
+let AFF_DIM_DIM_0 = prove
+ (`!s:real^N->bool. vec 0 IN affine hull s ==> aff_dim s = &(dim s)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`vec 0:real^N`; `affine hull s:real^N->bool`]
+    AFF_DIM_DIM_AFFINE_DIFFS) THEN
+  ASM_REWRITE_TAC[AFFINE_AFFINE_HULL; VECTOR_SUB_RZERO] THEN
+  REWRITE_TAC[AFF_DIM_AFFINE_HULL; SET_RULE `{x | x IN s} = s`] THEN
+  ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; DIM_SPAN]);;
+
+let AFF_DIM_DIM_SUBSPACE = prove
+ (`!s:real^N->bool. subspace s ==> aff_dim s = &(dim s)`,
+  MESON_TAC[AFF_DIM_DIM_0; SUBSPACE_0; HULL_INC]);;
+
+let AFF_DIM_LINEAR_IMAGE_LE = prove
+ (`!f:real^M->real^N s. linear f ==> aff_dim(IMAGE f s) <= aff_dim s`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+  ASM_SIMP_TAC[AFFINE_HULL_LINEAR_IMAGE] THEN
+  MP_TAC(ISPEC `s:real^M->bool` AFFINE_AFFINE_HULL) THEN
+  SPEC_TAC(`affine hull s:real^M->bool`,`s:real^M->bool`) THEN
+  GEN_TAC THEN DISCH_TAC THEN ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[IMAGE_CLAUSES; AFF_DIM_EMPTY; INT_LE_REFL] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^M`) THEN
+  SUBGOAL_THEN `dim {x - f(a) |x| x IN IMAGE (f:real^M->real^N) s} <=
+                dim {x - a | x IN s}`
+  MP_TAC THENL
+   [REWRITE_TAC[SET_RULE `{f x | x IN IMAGE g s} = {f (g x) | x IN s}`] THEN
+    ASM_SIMP_TAC[GSYM LINEAR_SUB] THEN REWRITE_TAC[SIMPLE_IMAGE] THEN
+    ONCE_REWRITE_TAC[GSYM o_DEF] THEN REWRITE_TAC[IMAGE_o] THEN
+    MATCH_MP_TAC DIM_LINEAR_IMAGE_LE THEN ASM_REWRITE_TAC[];
+    MATCH_MP_TAC EQ_IMP THEN REWRITE_TAC[GSYM INT_OF_NUM_LE] THEN
+    BINOP_TAC THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC AFF_DIM_DIM_AFFINE_DIFFS THEN
+    ASM_SIMP_TAC[AFFINE_LINEAR_IMAGE; FUN_IN_IMAGE]]);;
+
+let AFF_DIM_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> aff_dim(IMAGE f s) = aff_dim s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM INT_LE_ANTISYM] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[AFF_DIM_LINEAR_IMAGE_LE]; ALL_TAC] THEN
+  MP_TAC(ISPEC `f:real^M->real^N` LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+  ASM_REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^M` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC INT_LE_TRANS THEN EXISTS_TAC
+   `aff_dim(IMAGE (g:real^N->real^M) (IMAGE (f:real^M->real^N) s))` THEN
+  CONJ_TAC THENL
+   [ASM_REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID; INT_LE_REFL];
+    MATCH_MP_TAC AFF_DIM_LINEAR_IMAGE_LE THEN ASM_REWRITE_TAC[]]);;
+
+add_linear_invariants [AFF_DIM_INJECTIVE_LINEAR_IMAGE];;
+
+let AFF_DIM_AFFINE_INDEPENDENT = prove
+ (`!b:real^N->bool.
+        ~(affine_dependent b) ==> aff_dim b = &(CARD b) - &1`,
+  GEN_TAC THEN ASM_CASES_TAC `b:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[CARD_CLAUSES; AFF_DIM_EMPTY] THEN INT_ARITH_TAC;
+    ALL_TAC] THEN
+  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_TAC THEN
+  MP_TAC(ISPECL [`b:real^N->bool`; `a:real^N`]
+   AFFINE_INDEPENDENT_CARD_DIM_DIFFS) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[GSYM INT_OF_NUM_ADD; INT_ARITH `(a + b) - b:int = a`] THEN
+  MP_TAC(ISPECL [`a:real^N`; `affine hull b:real^N->bool`]
+   AFF_DIM_DIM_AFFINE_DIFFS) THEN
+  ASM_SIMP_TAC[AFFINE_AFFINE_HULL; HULL_INC; AFF_DIM_AFFINE_HULL] THEN
+  DISCH_THEN(K ALL_TAC) THEN AP_TERM_TAC THEN
+  ASM_MESON_TAC[DIFFS_AFFINE_HULL_SPAN; DIM_SPAN]);;
+
+let AFF_DIM_UNIQUE = prove
+ (`!s b:real^N->bool.
+        affine hull b = affine hull s /\ ~(affine_dependent b)
+        ==> aff_dim s = &(CARD b) - &1`,
+  MESON_TAC[AFF_DIM_AFFINE_HULL; AFF_DIM_AFFINE_INDEPENDENT]);;
+
+let AFF_DIM_SING = prove
+ (`!a:real^N. aff_dim {a} = &0`,
+  GEN_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `&(CARD {a:real^N}) - &1:int` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC AFF_DIM_AFFINE_INDEPENDENT THEN
+    REWRITE_TAC[AFFINE_INDEPENDENT_1];
+    SIMP_TAC[CARD_CLAUSES; FINITE_RULES; ARITH; NOT_IN_EMPTY; INT_SUB_REFL]]);;
+
+let AFF_DIM_LE_CARD = prove
+ (`!s:real^N->bool. FINITE s ==> aff_dim s <= &(CARD s) - &1`,
+  MATCH_MP_TAC SET_PROVE_CASES THEN
+  SIMP_TAC[AFF_DIM_EMPTY; CARD_CLAUSES] THEN CONV_TAC INT_REDUCE_CONV THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN
+  SIMP_TAC[AFF_DIM_DIM_0; IN_INSERT; HULL_INC] THEN
+  SIMP_TAC[CARD_IMAGE_INJ; VECTOR_ARITH `a + x:real^N = a + y <=> x = y`] THEN
+  SIMP_TAC[DIM_INSERT_0; INT_LE_SUB_LADD; CARD_CLAUSES; FINITE_INSERT] THEN
+  REWRITE_TAC[INT_OF_NUM_ADD; INT_OF_NUM_LE; ADD1; LE_ADD_RCANCEL] THEN
+  SIMP_TAC[DIM_LE_CARD]);;
+
+let AFF_DIM_GE = prove
+ (`!s:real^N->bool. -- &1 <= aff_dim s`,
+  GEN_TAC THEN MP_TAC(ISPEC `s:real^N->bool` AFF_DIM) THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[INT_LE_SUB_LADD; INT_ADD_LINV; INT_POS]);;
+
+let AFF_DIM_SUBSET = prove
+ (`!s t:real^N->bool. s SUBSET t ==> aff_dim s <= aff_dim t`,
+  MATCH_MP_TAC SET_PROVE_CASES THEN REWRITE_TAC[AFF_DIM_GE; AFF_DIM_EMPTY] THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(vec 0:real^N) IN t` ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  ASM_SIMP_TAC[AFF_DIM_DIM_0; IN_INSERT; HULL_INC; INT_OF_NUM_LE; DIM_SUBSET]);;
+
+let AFF_DIM_LE_DIM = prove
+ (`!s:real^N->bool. aff_dim s <= &(dim s)`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM DIM_SPAN] THEN
+  ASM_SIMP_TAC[GSYM AFF_DIM_DIM_SUBSPACE; SUBSPACE_SPAN] THEN
+  MATCH_MP_TAC AFF_DIM_SUBSET THEN REWRITE_TAC[SPAN_INC]);;
+
+let AFF_DIM_CONVEX_HULL = prove
+ (`!s:real^N->bool. aff_dim(convex hull s) = aff_dim s`,
+  GEN_TAC THEN MATCH_MP_TAC(INT_ARITH
+   `!c:int. c = a /\ a <= b /\ b <= c ==> b = a`) THEN
+  EXISTS_TAC `aff_dim(affine hull s:real^N->bool)` THEN
+  SIMP_TAC[AFF_DIM_AFFINE_HULL; AFF_DIM_SUBSET; HULL_SUBSET;
+           CONVEX_HULL_SUBSET_AFFINE_HULL]);;
+
+let AFF_DIM_CLOSURE = prove
+ (`!s:real^N->bool. aff_dim(closure s) = aff_dim s`,
+  GEN_TAC THEN MATCH_MP_TAC(INT_ARITH
+   `!h. h = s /\ s <= c /\ c <= h ==> c:int = s`) THEN
+  EXISTS_TAC `aff_dim(affine hull s:real^N->bool)` THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[AFF_DIM_AFFINE_HULL];
+    MATCH_MP_TAC AFF_DIM_SUBSET THEN REWRITE_TAC[CLOSURE_SUBSET];
+    MATCH_MP_TAC AFF_DIM_SUBSET THEN
+    MATCH_MP_TAC CLOSURE_MINIMAL THEN
+    REWRITE_TAC[CLOSED_AFFINE_HULL; HULL_SUBSET]]);;
+
+let AFF_DIM_2 = prove
+ (`!a b:real^N. aff_dim {a,b} = if a = b then &0 else &1`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THENL
+   [ASM_REWRITE_TAC[INSERT_AC; AFF_DIM_SING]; ALL_TAC] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `&(CARD {a:real^N,b}) - &1:int` THEN
+  ASM_SIMP_TAC[AFF_DIM_AFFINE_INDEPENDENT; AFFINE_INDEPENDENT_2] THEN
+  ASM_SIMP_TAC[CARD_CLAUSES; FINITE_RULES; IN_INSERT; NOT_IN_EMPTY] THEN
+  CONV_TAC NUM_REDUCE_CONV THEN INT_ARITH_TAC);;
+
+let AFF_DIM_EQ_MINUS1 = prove
+ (`!s:real^N->bool. aff_dim s = -- &1 <=> s = {}`,
+  GEN_TAC THEN EQ_TAC THEN SIMP_TAC[AFF_DIM_EMPTY] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+  MATCH_MP_TAC(INT_ARITH `&0:int <= n ==> ~(n = -- &1)`) THEN
+  MATCH_MP_TAC INT_LE_TRANS THEN EXISTS_TAC `aff_dim {a:real^N}` THEN
+  ASM_SIMP_TAC[AFF_DIM_SUBSET; SING_SUBSET] THEN
+  REWRITE_TAC[AFF_DIM_SING; INT_LE_REFL]);;
+
+let AFF_DIM_POS_LE = prove
+ (`!s:real^N->bool. &0 <= aff_dim s <=> ~(s = {})`,
+  GEN_TAC THEN REWRITE_TAC[GSYM AFF_DIM_EQ_MINUS1] THEN
+  MP_TAC(ISPEC `s:real^N->bool` AFF_DIM_GE) THEN INT_ARITH_TAC);;
+
+let AFF_DIM_EQ_0 = prove
+ (`!s:real^N->bool. aff_dim s = &0 <=> ?a. s = {a}`,
+  GEN_TAC THEN EQ_TAC THEN SIMP_TAC[AFF_DIM_SING; LEFT_IMP_EXISTS_THM] THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THEN ASM_REWRITE_TAC[AFF_DIM_EMPTY] THEN
+  CONV_TAC INT_REDUCE_CONV THEN DISCH_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
+  MATCH_MP_TAC(SET_RULE
+   `(!b. ~(b = a) /\ {a,b} SUBSET s ==> F) ==> a IN s ==> s = {a}`) THEN
+  X_GEN_TAC `b:real^N` THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP AFF_DIM_SUBSET) THEN
+  MP_TAC(ISPECL [`a:real^N`; `b:real^N`] AFF_DIM_2) THEN
+  ASM_SIMP_TAC[] THEN INT_ARITH_TAC);;
+
+let CONNECTED_IMP_PERFECT_AFF_DIM = prove
+ (`!s x:real^N.
+        connected s /\ ~(aff_dim s = &0) /\ x IN s ==> x limit_point_of s`,
+  REWRITE_TAC[AFF_DIM_EQ_0; CONNECTED_IMP_PERFECT]);;
+
+let AFF_DIM_UNIV = prove
+ (`aff_dim(:real^N) = &(dimindex(:N))`,
+  SIMP_TAC[AFF_DIM_DIM_SUBSPACE; SUBSPACE_UNIV; DIM_UNIV]);;
+
+let AFF_DIM_EQ_AFFINE_HULL = prove
+ (`!s t:real^N->bool.
+        s SUBSET t /\ aff_dim t <= aff_dim s
+        ==> affine hull s = affine hull t`,
+  MATCH_MP_TAC SET_PROVE_CASES THEN
+  SIMP_TAC[AFF_DIM_EMPTY; AFF_DIM_EQ_MINUS1; AFF_DIM_GE;
+           INT_ARITH `a:int <= x ==> (x <= a <=> x = a)`] THEN
+  X_GEN_TAC `a:real^N` THEN GEOM_ORIGIN_TAC `a:real^N` THEN
+  SIMP_TAC[INSERT_SUBSET; IMP_CONJ; AFF_DIM_DIM_0; IN_INSERT; DIM_EQ_SPAN;
+           HULL_INC; AFFINE_HULL_EQ_SPAN; INT_OF_NUM_LE]);;
+
+let AFF_DIM_SUMS_INTER = prove
+ (`!s t:real^N->bool.
+        affine s /\ affine t /\ ~(s INTER t = {})
+        ==> aff_dim {x + y | x IN s /\ y IN t} =
+                (aff_dim s + aff_dim t) - aff_dim(s INTER t)`,
+  REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> c ==> a /\ b ==> d`] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; LEFT_IMP_EXISTS_THM] THEN
+  GEN_REWRITE_TAC BINDER_CONV [SWAP_FORALL_THM] THEN
+  GEN_REWRITE_TAC I [SWAP_FORALL_THM] THEN X_GEN_TAC `a:real^N` THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN
+  REWRITE_TAC[VECTOR_ARITH `(a + x) + (a + y):real^N = &2 % a + (x + y)`] THEN
+  ONCE_REWRITE_TAC[SET_RULE `{a + x + y:real^N | x IN s /\ y IN t} =
+                            IMAGE (\x. a + x) {x + y | x IN s /\ y IN t}`] THEN
+  REWRITE_TAC[AFF_DIM_TRANSLATION_EQ; IN_INTER] THEN
+  MAP_EVERY X_GEN_TAC [`s:real^N->bool`; `t:real^N->bool`] THEN STRIP_TAC THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `(vec 0:real^N) IN {x + y | x IN s /\ y IN t}` ASSUME_TAC THENL
+   [REWRITE_TAC[IN_ELIM_THM] THEN REPEAT(EXISTS_TAC `vec 0:real^N`) THEN
+    ASM_REWRITE_TAC[VECTOR_ADD_LID];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[AFF_DIM_DIM_0; HULL_INC; IN_INTER] THEN
+  REWRITE_TAC[INT_EQ_SUB_LADD; INT_OF_NUM_ADD; INT_OF_NUM_EQ] THEN
+  MATCH_MP_TAC DIM_SUMS_INTER THEN ASM_SIMP_TAC[AFFINE_IMP_SUBSPACE]);;
+
+let AFF_DIM_PSUBSET = prove
+ (`!s t. (affine hull s) PSUBSET (affine hull t) ==> aff_dim s < aff_dim t`,
+  ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+  SIMP_TAC[PSUBSET; AFF_DIM_SUBSET; INT_LT_LE] THEN
+  MESON_TAC[INT_EQ_IMP_LE; AFF_DIM_EQ_AFFINE_HULL; HULL_HULL]);;
+
+let AFF_DIM_EQ_FULL = prove
+ (`!s. aff_dim s = &(dimindex(:N)) <=> affine hull s = (:real^N)`,
+  GEN_TAC THEN EQ_TAC THENL
+   [DISCH_TAC THEN ONCE_REWRITE_TAC[GSYM AFFINE_HULL_UNIV] THEN
+    MATCH_MP_TAC AFF_DIM_EQ_AFFINE_HULL THEN
+    ASM_REWRITE_TAC[SUBSET_UNIV; AFF_DIM_UNIV; INT_LE_REFL];
+    ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+    SIMP_TAC[AFF_DIM_UNIV]]);;
+
+let AFF_DIM_LE_UNIV = prove
+ (`!s:real^N->bool. aff_dim s <= &(dimindex(:N))`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM AFF_DIM_UNIV] THEN
+  MATCH_MP_TAC AFF_DIM_SUBSET THEN REWRITE_TAC[SUBSET_UNIV]);;
+
+let AFFINE_INDEPENDENT_IFF_CARD = prove
+ (`!s:real^N->bool.
+        ~affine_dependent s <=> FINITE s /\ aff_dim s = &(CARD s) - &1`,
+  GEN_TAC THEN EQ_TAC THEN
+  SIMP_TAC[AFF_DIM_AFFINE_INDEPENDENT; AFFINE_INDEPENDENT_IMP_FINITE] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[] THEN DISCH_TAC THEN
+  X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC
+   (ISPEC `s:real^N->bool` AFFINE_BASIS_EXISTS) THEN
+  MATCH_MP_TAC(ARITH_RULE `!b:int. a <= b - &1 /\ b < s ==> ~(a = s - &1)`) THEN
+  EXISTS_TAC `&(CARD(b:real^N->bool)):int` THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[AFF_DIM_LE_CARD; FINITE_SUBSET; AFF_DIM_AFFINE_HULL];
+    REWRITE_TAC[INT_OF_NUM_LT] THEN MATCH_MP_TAC CARD_PSUBSET THEN
+    ASM_REWRITE_TAC[PSUBSET] THEN ASM_MESON_TAC[]]);;
+
+let AFFINE_HULL_CONVEX_INTER_NONEMPTY_INTERIOR = prove
+ (`!s t:real^N->bool.
+        convex s /\ ~(s INTER interior t = {})
+        ==> affine hull (s INTER t) = affine hull s`,
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; RIGHT_AND_EXISTS_THM;
+              LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`s:real^N->bool`; `t:real^N->bool`; `a:real^N`] THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN REWRITE_TAC[IN_INTER] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  SIMP_TAC[HULL_MONO; INTER_SUBSET] THEN
+  SIMP_TAC[SUBSET_HULL; AFFINE_AFFINE_HULL] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP (SIMP_RULE[SUBSET] INTERIOR_SUBSET)) THEN
+  ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC; IN_INTER] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERIOR_CBALL]) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; SUBSET; IN_CBALL_0] THEN
+  X_GEN_TAC `e:real` THEN STRIP_TAC THEN REWRITE_TAC[EXTENSION; IN_UNIV] THEN
+  X_GEN_TAC `x:real^N` THEN ASM_CASES_TAC `x:real^N = vec 0` THEN
+  ASM_SIMP_TAC[SPAN_SUPERSET; IN_INTER] THEN DISCH_TAC THEN
+  ABBREV_TAC `k = min (&1 / &2) (e / norm(x:real^N))` THEN
+  SUBGOAL_THEN `&0 < k /\ k < &1` STRIP_ASSUME_TAC THENL
+   [EXPAND_TAC "k" THEN
+    ASM_SIMP_TAC[REAL_LT_MIN; REAL_LT_DIV; NORM_POS_LT; REAL_MIN_LT] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `x:real^N = inv k % k % x` SUBST1_TAC THENL
+   [ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; VECTOR_MUL_LID;
+                 REAL_LT_IMP_NZ];
+    ALL_TAC] THEN
+  MATCH_MP_TAC SPAN_MUL THEN MATCH_MP_TAC SPAN_SUPERSET THEN
+  REWRITE_TAC[IN_INTER] THEN CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[VECTOR_ARITH
+     `k % x:real^N = (&1 - k) % vec 0 + k % x`] THEN
+    MATCH_MP_TAC IN_CONVEX_SET THEN ASM_SIMP_TAC[REAL_LT_IMP_LE];
+    FIRST_X_ASSUM MATCH_MP_TAC THEN EXPAND_TAC "k" THEN
+    ASM_SIMP_TAC[NORM_MUL; GSYM REAL_LE_RDIV_EQ; NORM_POS_LT] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let AFFINE_HULL_CONVEX_INTER_OPEN = prove
+ (`!s t:real^N->bool.
+        convex s /\ open t /\ ~(s INTER t = {})
+        ==> affine hull (s INTER t) = affine hull s`,
+  ASM_SIMP_TAC[AFFINE_HULL_CONVEX_INTER_NONEMPTY_INTERIOR; INTERIOR_OPEN]);;
+
+let AFFINE_HULL_AFFINE_INTER_NONEMPTY_INTERIOR = prove
+ (`!s t:real^N->bool.
+        affine s /\ ~(s INTER interior t = {})
+        ==> affine hull (s INTER t) = s`,
+  SIMP_TAC[AFFINE_HULL_CONVEX_INTER_NONEMPTY_INTERIOR; AFFINE_IMP_CONVEX;
+           HULL_P]);;
+
+let AFFINE_HULL_AFFINE_INTER_OPEN = prove
+ (`!s t:real^N->bool.
+        affine s /\ open t /\ ~(s INTER t = {})
+        ==> affine hull (s INTER t) = s`,
+  SIMP_TAC[AFFINE_HULL_AFFINE_INTER_NONEMPTY_INTERIOR; INTERIOR_OPEN]);;
+
+let CONVEX_AND_AFFINE_INTER_OPEN = prove
+ (`!s t u:real^N->bool.
+        convex s /\ affine t /\ open u /\
+        s INTER u = t INTER u /\ ~(s INTER u = {})
+        ==> affine hull s = t`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(MESON[] `!u v. x = u /\ u = v /\ v = y ==> x = y`) THEN
+  MAP_EVERY EXISTS_TAC
+   [`affine hull (s INTER u:real^N->bool)`;
+    `affine hull t:real^N->bool`] THEN
+  REPEAT CONJ_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC AFFINE_HULL_CONVEX_INTER_OPEN THEN
+    ASM_REWRITE_TAC[];
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC AFFINE_HULL_CONVEX_INTER_OPEN THEN
+    ASM_SIMP_TAC[AFFINE_IMP_CONVEX] THEN ASM SET_TAC[];
+    ASM_REWRITE_TAC[AFFINE_HULL_EQ]]);;
+
+let AFFINE_HULL_CONVEX_INTER_OPEN_IN = prove
+ (`!s t:real^N->bool.
+        convex s /\ open_in (subtopology euclidean (affine hull s)) t /\
+        ~(s INTER t = {})
+        ==> affine hull (s INTER t) = affine hull s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_IN_OPEN]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+  ASM_SIMP_TAC[SET_RULE `s SUBSET t ==> s INTER t INTER u = s INTER u`;
+               HULL_SUBSET] THEN
+  MATCH_MP_TAC AFFINE_HULL_CONVEX_INTER_OPEN THEN ASM SET_TAC[]);;
+
+let AFFINE_HULL_AFFINE_INTER_OPEN_IN = prove
+ (`!s t:real^N->bool.
+        affine s /\ open_in (subtopology euclidean s) t /\ ~(s INTER t = {})
+        ==> affine hull (s INTER t) = s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`affine hull s:real^N->bool`; `t:real^N->bool`]
+        AFFINE_HULL_CONVEX_INTER_OPEN_IN) THEN
+  ASM_SIMP_TAC[HULL_HULL; AFFINE_IMP_CONVEX; AFFINE_AFFINE_HULL; HULL_P]);;
+
+let AFFINE_HULL_CONVEX_INTER_OPEN_IN = prove
+ (`!s t:real^N->bool.
+        convex s /\ open_in (subtopology euclidean (affine hull s)) t /\
+        ~(s INTER t = {})
+        ==> affine hull (s INTER t) = affine hull s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_IN_OPEN]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+  ASM_SIMP_TAC[SET_RULE `s SUBSET t ==> s INTER t INTER u = s INTER u`;
+               HULL_SUBSET] THEN
+  MATCH_MP_TAC AFFINE_HULL_CONVEX_INTER_OPEN THEN ASM SET_TAC[]);;
+
+let AFFINE_HULL_AFFINE_INTER_OPEN_IN = prove
+ (`!s t:real^N->bool.
+        affine s /\ open_in (subtopology euclidean s) t /\ ~(s INTER t = {})
+        ==> affine hull (s INTER t) = s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`affine hull s:real^N->bool`; `t:real^N->bool`]
+        AFFINE_HULL_CONVEX_INTER_OPEN_IN) THEN
+  ASM_SIMP_TAC[HULL_HULL; AFFINE_IMP_CONVEX; AFFINE_AFFINE_HULL; HULL_P]);;
+
+let AFFINE_HULL_OPEN_IN = prove
+ (`!s t:real^N->bool.
+        open_in (subtopology euclidean (affine hull t)) s /\ ~(s = {})
+        ==> affine hull s = affine hull t`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_IN_OPEN]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC AFFINE_HULL_AFFINE_INTER_OPEN THEN
+  REWRITE_TAC[AFFINE_AFFINE_HULL] THEN ASM SET_TAC[]);;
+
+let AFFINE_HULL_OPEN = prove
+ (`!s. open s /\ ~(s = {}) ==> affine hull s = (:real^N)`,
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  SUBST1_TAC(SET_RULE `s = (:real^N) INTER s`) THEN
+  ASM_SIMP_TAC[AFFINE_HULL_CONVEX_INTER_OPEN; CONVEX_UNIV] THEN
+  REWRITE_TAC[AFFINE_HULL_UNIV]);;
+
+let AFFINE_HULL_NONEMPTY_INTERIOR = prove
+ (`!s. ~(interior s = {}) ==> affine hull s = (:real^N)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(SET_RULE `!s. s SUBSET t /\ s = UNIV ==> t = UNIV`) THEN
+  EXISTS_TAC `affine hull (interior s:real^N->bool)` THEN
+  SIMP_TAC[HULL_MONO; INTERIOR_SUBSET] THEN
+  ASM_SIMP_TAC[AFFINE_HULL_OPEN; OPEN_INTERIOR]);;
+
+let AFF_DIM_OPEN = prove
+ (`!s:real^N->bool. open s /\ ~(s = {}) ==> aff_dim s = &(dimindex(:N))`,
+  SIMP_TAC[AFF_DIM_EQ_FULL; AFFINE_HULL_OPEN]);;
+
+let AFF_DIM_NONEMPTY_INTERIOR = prove
+ (`!s:real^N->bool. ~(interior s = {}) ==> aff_dim s = &(dimindex(:N))`,
+  SIMP_TAC[AFF_DIM_EQ_FULL; AFFINE_HULL_NONEMPTY_INTERIOR]);;
+
+let SPAN_OPEN = prove
+ (`!s. open s /\ ~(s = {}) ==> span s = (:real^N)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(SET_RULE `!s. s SUBSET t /\ s = UNIV ==> t = UNIV`) THEN
+  EXISTS_TAC `affine hull s:real^N->bool` THEN
+  ASM_SIMP_TAC[AFFINE_HULL_OPEN; AFFINE_HULL_SUBSET_SPAN]);;
+
+let DIM_OPEN = prove
+ (`!s:real^N->bool. open s /\ ~(s = {}) ==> dim s = dimindex(:N)`,
+  SIMP_TAC[DIM_EQ_FULL; SPAN_OPEN]);;
+
+let AFF_DIM_INSERT = prove
+ (`!a:real^N s.
+        aff_dim (a INSERT s) =
+        if a IN affine hull s then aff_dim s else aff_dim s + &1`,
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN MATCH_MP_TAC SET_PROVE_CASES THEN
+  SIMP_TAC[AFF_DIM_EMPTY; AFF_DIM_SING; AFFINE_HULL_EMPTY; NOT_IN_EMPTY] THEN
+  CONV_TAC INT_REDUCE_CONV THEN REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
+  MAP_EVERY X_GEN_TAC [`b:real^N`; `s:real^N->bool`; `a:real^N`] THEN
+  GEOM_ORIGIN_TAC `b:real^N` THEN
+  SIMP_TAC[AFFINE_HULL_EQ_SPAN; AFF_DIM_DIM_0; HULL_INC; IN_INSERT] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `s:real^N->bool`] THEN
+  DISCH_THEN(K ALL_TAC) THEN
+  SPEC_TAC(`(vec 0:real^N) INSERT s`,`s:real^N->bool`) THEN
+  SIMP_TAC[DIM_INSERT; INT_OF_NUM_ADD] THEN MESON_TAC[]);;
+
+let AFFINE_BOUNDED_EQ_TRIVIAL = prove
+ (`!s:real^N->bool.
+        affine s ==> (bounded s <=> s = {} \/ ?a. s = {a})`,
+  GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[BOUNDED_EMPTY] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N` MP_TAC) THEN
+  GEOM_ORIGIN_TAC `b:real^N` THEN SIMP_TAC[AFFINE_EQ_SUBSPACE] THEN
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[SUBSPACE_BOUNDED_EQ_TRIVIAL] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP SUBSPACE_0) THEN SET_TAC[]);;
+
+let AFFINE_BOUNDED_EQ_LOWDIM = prove
+ (`!s:real^N->bool.
+        affine s ==> (bounded s <=> aff_dim s <= &0)`,
+  SIMP_TAC[AFF_DIM_GE; INT_ARITH
+   `--(&1):int <= x ==> (x <= &0 <=> x = --(&1) \/ x = &0)`] THEN
+  SIMP_TAC[AFF_DIM_EQ_0; AFF_DIM_EQ_MINUS1; AFFINE_BOUNDED_EQ_TRIVIAL]);;
+
+let COLLINEAR_AFF_DIM = prove
+ (`!s:real^N->bool. collinear s <=> aff_dim s <= &1`,
+  GEN_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[COLLINEAR_AFFINE_HULL; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN STRIP_TAC THEN
+    MATCH_MP_TAC INT_LE_TRANS THEN EXISTS_TAC `aff_dim{u:real^N,v}` THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[AFF_DIM_SUBSET; AFF_DIM_AFFINE_HULL];
+      MATCH_MP_TAC INT_LE_TRANS THEN
+      EXISTS_TAC `&(CARD{u:real^N,v}) - &1:int` THEN
+      SIMP_TAC[AFF_DIM_LE_CARD; FINITE_INSERT; FINITE_EMPTY] THEN
+      REWRITE_TAC[INT_ARITH `x - &1:int <= &1 <=> x <= &2`; INT_OF_NUM_LE] THEN
+      SIMP_TAC[CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN ARITH_TAC];
+    ONCE_REWRITE_TAC[GSYM COLLINEAR_AFFINE_HULL_COLLINEAR;
+                     GSYM AFF_DIM_AFFINE_HULL] THEN
+    MP_TAC(ISPEC `s:real^N->bool` AFFINE_BASIS_EXISTS) THEN
+    DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` (STRIP_ASSUME_TAC o GSYM)) THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+     [AFFINE_INDEPENDENT_IFF_CARD]) THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_REWRITE_TAC[COLLINEAR_AFFINE_HULL_COLLINEAR;
+                    AFF_DIM_AFFINE_HULL] THEN
+    REWRITE_TAC[INT_ARITH `x - &1:int <= &1 <=> x <= &2`; INT_OF_NUM_LE] THEN
+    ASM_SIMP_TAC[COLLINEAR_SMALL]]);;
+
+let HOMEOMORPHIC_AFFINE_SETS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        affine s /\ affine t /\ aff_dim s = aff_dim t ==> s homeomorphic t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[AFF_DIM_EMPTY; AFF_DIM_EQ_MINUS1; HOMEOMORPHIC_EMPTY] THEN
+  POP_ASSUM MP_TAC THEN
+  GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_SIMP_TAC[AFF_DIM_EMPTY; AFF_DIM_EQ_MINUS1; HOMEOMORPHIC_EMPTY] THEN
+  POP_ASSUM MP_TAC THEN REWRITE_TAC
+   [GSYM MEMBER_NOT_EMPTY; LEFT_IMP_EXISTS_THM; RIGHT_IMP_FORALL_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^N`] THEN
+  GEOM_ORIGIN_TAC `a:real^M` THEN GEOM_ORIGIN_TAC `b:real^N` THEN
+  SIMP_TAC[AFFINE_EQ_SUBSPACE; AFF_DIM_DIM_0; HULL_INC; INT_OF_NUM_EQ] THEN
+  MESON_TAC[HOMEOMORPHIC_SUBSPACES]);;
+
+let AFF_DIM_OPEN_IN = prove
+ (`!s t:real^N->bool.
+        ~(s = {}) /\ open_in (subtopology euclidean t) s /\ affine t
+        ==> aff_dim s = aff_dim t`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[IMP_CONJ; GSYM MEMBER_NOT_EMPTY; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `a:real^N` THEN GEOM_ORIGIN_TAC `a:real^N` THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN
+  SUBGOAL_THEN `(vec 0:real^N) IN t` ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  ASM_SIMP_TAC[AFF_DIM_DIM_0; HULL_INC; AFFINE_EQ_SUBSPACE] THEN
+  DISCH_TAC THEN AP_TERM_TAC THEN
+  ASM_SIMP_TAC[GSYM LE_ANTISYM; DIM_SUBSET] THEN
+  SUBGOAL_THEN `?e. &0 < e /\ cball(vec 0:real^N,e) INTER t SUBSET s`
+  MP_TAC THENL
+   [FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [OPEN_IN_OPEN]) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `vec 0:real^N` o
+      GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+    ASM SET_TAC[];
+    REWRITE_TAC[SUBSET; IN_INTER; IN_CBALL_0] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC)] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ORTHONORMAL_BASIS_SUBSPACE) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `IMAGE (\x:real^N. e % x) b`]
+   INDEPENDENT_CARD_LE_DIM) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN
+  ASM_SIMP_TAC[CARD_IMAGE_INJ; VECTOR_MUL_LCANCEL; REAL_LT_IMP_NZ] THEN
+  ANTS_TAC THENL [REWRITE_TAC[SUBSET]; MESON_TAC[]] THEN CONJ_TAC THENL
+   [REWRITE_TAC[FORALL_IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[NORM_MUL] THEN
+    CONJ_TAC THENL [ASM_REAL_ARITH_TAC; MATCH_MP_TAC SUBSPACE_MUL] THEN
+    ASM SET_TAC[];
+    MATCH_MP_TAC INDEPENDENT_INJECTIVE_IMAGE THEN
+    ASM_SIMP_TAC[VECTOR_MUL_LCANCEL; REAL_LT_IMP_NZ; LINEAR_SCALING]]);;
+
+let DIM_OPEN_IN = prove
+ (`!s t:real^N->bool.
+        ~(s = {}) /\ open_in (subtopology euclidean t) s /\ subspace t
+        ==> dim s = dim t`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN
+  ASM_SIMP_TAC[GSYM LE_ANTISYM; DIM_SUBSET] THEN
+  REWRITE_TAC[GSYM INT_OF_NUM_LE] THEN
+  MATCH_MP_TAC INT_LE_TRANS THEN EXISTS_TAC `aff_dim(s:real^N->bool)` THEN
+  REWRITE_TAC[AFF_DIM_LE_DIM] THEN ASM_SIMP_TAC[GSYM AFF_DIM_DIM_SUBSPACE] THEN
+  MATCH_MP_TAC INT_EQ_IMP_LE THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC AFF_DIM_OPEN_IN THEN ASM_SIMP_TAC[SUBSPACE_IMP_AFFINE]);;
+
+let AFF_DIM_CONVEX_INTER_NONEMPTY_INTERIOR = prove
+ (`!s t:real^N->bool.
+        convex s /\ ~(s INTER interior t = {})
+        ==> aff_dim(s INTER t) = aff_dim s`,
+  ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+  ASM_SIMP_TAC[AFFINE_HULL_CONVEX_INTER_NONEMPTY_INTERIOR] THEN
+  REWRITE_TAC[AFF_DIM_AFFINE_HULL]);;
+
+let AFF_DIM_CONVEX_INTER_OPEN = prove
+ (`!s t:real^N->bool.
+        convex s /\ open t /\ ~(s INTER t = {})
+        ==> aff_dim(s INTER t) = aff_dim s`,
+  ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+  ASM_SIMP_TAC[AFFINE_HULL_CONVEX_INTER_OPEN] THEN
+  REWRITE_TAC[AFF_DIM_AFFINE_HULL]);;
+
+let AFFINE_HULL_HALFSPACE_LT = prove
+ (`!a b. affine hull {x | a dot x < b} =
+         if a = vec 0 /\ b <= &0 then {} else (:real^N)`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THEN
+  ASM_SIMP_TAC[AFFINE_HULL_EQ_EMPTY; HALFSPACE_EQ_EMPTY_LT;
+               AFFINE_HULL_OPEN; OPEN_HALFSPACE_LT]);;
+
+let AFFINE_HULL_HALFSPACE_LE = prove
+ (`!a b. affine hull {x | a dot x <= b} =
+         if a = vec 0 /\ b < &0 then {} else (:real^N)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THENL
+   [ASM_SIMP_TAC[DOT_LZERO; SET_RULE `{x | p} = if p then UNIV else {}`] THEN
+    COND_CASES_TAC THEN ASM_SIMP_TAC[AFFINE_HULL_EMPTY; AFFINE_HULL_UNIV] THEN
+    COND_CASES_TAC THEN REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+    ASM_SIMP_TAC[GSYM CLOSURE_HALFSPACE_LT; AFFINE_HULL_CLOSURE] THEN
+    ASM_REWRITE_TAC[AFFINE_HULL_HALFSPACE_LT]]);;
+
+let AFFINE_HULL_HALFSPACE_GT = prove
+ (`!a b. affine hull {x | a dot x > b} =
+         if a = vec 0 /\ b >= &0 then {} else (:real^N)`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THEN
+  ASM_SIMP_TAC[AFFINE_HULL_EQ_EMPTY; HALFSPACE_EQ_EMPTY_GT;
+               AFFINE_HULL_OPEN; OPEN_HALFSPACE_GT]);;
+
+let AFFINE_HULL_HALFSPACE_GE = prove
+ (`!a b. affine hull {x | a dot x >= b} =
+         if a = vec 0 /\ b > &0 then {} else (:real^N)`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`--a:real^N`; `--b:real`] AFFINE_HULL_HALFSPACE_LE) THEN
+  SIMP_TAC[real_ge; DOT_LNEG; REAL_LE_NEG2; VECTOR_NEG_EQ_0] THEN
+  REWRITE_TAC[REAL_ARITH `--b < &0 <=> b > &0`]);;
+
+let AFF_DIM_HALFSPACE_LT = prove
+ (`!a:real^N b.
+        aff_dim {x | a dot x < b} =
+        if a = vec 0 /\ b <= &0 then --(&1) else &(dimindex(:N))`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+  SIMP_TAC[AFFINE_HULL_HALFSPACE_LT] THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[AFF_DIM_EMPTY; AFF_DIM_UNIV]);;
+
+let AFF_DIM_HALFSPACE_LE = prove
+ (`!a:real^N b.
+        aff_dim {x | a dot x <= b} =
+        if a = vec 0 /\ b < &0 then --(&1) else &(dimindex(:N))`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+  SIMP_TAC[AFFINE_HULL_HALFSPACE_LE] THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[AFF_DIM_EMPTY; AFF_DIM_UNIV]);;
+
+let AFF_DIM_HALFSPACE_GT = prove
+ (`!a:real^N b.
+        aff_dim {x | a dot x > b} =
+        if a = vec 0 /\ b >= &0 then --(&1) else &(dimindex(:N))`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+  SIMP_TAC[AFFINE_HULL_HALFSPACE_GT] THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[AFF_DIM_EMPTY; AFF_DIM_UNIV]);;
+
+let AFF_DIM_HALFSPACE_GE = prove
+ (`!a:real^N b.
+        aff_dim {x | a dot x >= b} =
+        if a = vec 0 /\ b > &0 then --(&1) else &(dimindex(:N))`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+  SIMP_TAC[AFFINE_HULL_HALFSPACE_GE] THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[AFF_DIM_EMPTY; AFF_DIM_UNIV]);;
+
+let CHOOSE_AFFINE_SUBSET = prove
+ (`!s:real^N->bool d.
+        affine s /\ --(&1) <= d /\ d <= aff_dim s
+        ==> ?t. affine t /\ t SUBSET s /\ aff_dim t = d`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `d:int = --(&1)` THENL
+   [STRIP_TAC THEN EXISTS_TAC `{}:real^N->bool` THEN
+    ASM_REWRITE_TAC[EMPTY_SUBSET; AFFINE_EMPTY; AFF_DIM_EMPTY];
+    ASM_SIMP_TAC[INT_ARITH
+     `~(d:int = --(&1)) ==> (--(&1) <= d <=> &0 <= d)`] THEN
+    POP_ASSUM(K ALL_TAC)] THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[AFF_DIM_EMPTY] THEN INT_ARITH_TAC;
+    POP_ASSUM MP_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM MEMBER_NOT_EMPTY] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` MP_TAC) THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN
+  SIMP_TAC[IMP_CONJ; AFF_DIM_DIM_SUBSPACE; AFFINE_EQ_SUBSPACE] THEN
+  REPEAT GEN_TAC THEN DISCH_TAC THEN DISCH_TAC THEN
+  REWRITE_TAC[GSYM INT_OF_NUM_EXISTS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `n:num` SUBST1_TAC) THEN
+  REWRITE_TAC[INT_OF_NUM_LE] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `n:num`]
+        CHOOSE_SUBSPACE_OF_SUBSPACE) THEN
+  ASM_SIMP_TAC[SPAN_OF_SUBSPACE] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real^N->bool` THEN
+  ASM_SIMP_TAC[AFF_DIM_DIM_SUBSPACE; SUBSPACE_IMP_AFFINE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Existence of a rigid transform between congruent sets.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let RIGID_TRANSFORMATION_BETWEEN_CONGRUENT_SETS = prove
+ (`!x:A->real^N y:A->real^N s.
+        (!i j. i IN s /\ j IN s ==> dist(x i,x j) = dist(y i,y j))
+        ==> ?a f. orthogonal_transformation f /\
+                  !i. i IN s ==> y i = a + f(x i)`,
+  let lemma = prove
+   (`!x:(real^N)^M y:(real^N)^M.
+          (!i j. 1 <= i /\ i <= dimindex(:M) /\
+                 1 <= j /\ j <= dimindex(:M)
+                 ==> dist(x$i,x$j) = dist(y$i,y$j))
+          ==> ?a f. orthogonal_transformation f /\
+                    !i. 1 <= i /\ i <= dimindex(:M)
+                        ==> y$i = a + f(x$i)`,
+    REPEAT STRIP_TAC THEN
+    ABBREV_TAC `(X:real^M^N) = lambda i j. (x:real^N^M)$j$i - x$1$i` THEN
+    ABBREV_TAC `(Y:real^M^N) = lambda i j. (y:real^N^M)$j$i - y$1$i` THEN
+    SUBGOAL_THEN `transp(X:real^M^N) ** X = transp(Y:real^M^N) ** Y`
+    ASSUME_TAC THENL
+     [REWRITE_TAC[MATRIX_MUL_LTRANSP_DOT_COLUMN] THEN
+      MAP_EVERY EXPAND_TAC ["X"; "Y"] THEN
+      SIMP_TAC[CART_EQ; column; LAMBDA_BETA; dot] THEN
+      REWRITE_TAC[GSYM VECTOR_SUB_COMPONENT; GSYM dot] THEN
+      REWRITE_TAC[DOT_NORM_SUB; VECTOR_ARITH
+       `(x - a) - (y - a):real^N = x - y`] THEN
+      ASM_SIMP_TAC[GSYM dist; DIMINDEX_GE_1; LE_REFL];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?M:real^N^N. orthogonal_matrix M /\ (Y:real^M^N) = M ** (X:real^M^N)`
+    (CHOOSE_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THENL
+     [ALL_TAC;
+      GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [CART_EQ] THEN
+      MAP_EVERY EXPAND_TAC ["X"; "Y"] THEN
+      SIMP_TAC[LAMBDA_BETA; matrix_mul] THEN
+      REWRITE_TAC[REAL_ARITH `x - y:real = z <=> x = y + z`] THEN STRIP_TAC THEN
+      EXISTS_TAC `(y:real^N^M)$1 - (M:real^N^N) ** (x:real^N^M)$1` THEN
+      EXISTS_TAC `\x:real^N. (M:real^N^N) ** x` THEN
+      ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_MATRIX;
+                   MATRIX_OF_MATRIX_VECTOR_MUL; MATRIX_VECTOR_MUL_LINEAR] THEN
+      SIMP_TAC[CART_EQ; matrix_vector_mul; LAMBDA_BETA;
+               VECTOR_ADD_COMPONENT] THEN
+      ASM_SIMP_TAC[REAL_SUB_LDISTRIB; SUM_SUB_NUMSEG] THEN
+      REWRITE_TAC[VECTOR_SUB_COMPONENT; REAL_ARITH
+       `a + y - b:real = a - z + y <=> z = b`] THEN
+      SIMP_TAC[LAMBDA_BETA]] THEN
+    MP_TAC(ISPEC `transp(X:real^M^N) ** X`
+      SYMMETRIC_MATRIX_DIAGONALIZABLE_EXPLICIT) THEN
+    REWRITE_TAC[MATRIX_TRANSP_MUL; TRANSP_TRANSP; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`P:real^M^M`; `d:num->real`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(fun th -> MP_TAC th THEN ASM_REWRITE_TAC[] THEN MP_TAC th) THEN
+    REWRITE_TAC[MATRIX_MUL_ASSOC; GSYM MATRIX_TRANSP_MUL] THEN
+    REWRITE_TAC[GSYM MATRIX_MUL_ASSOC; LEFT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[IMP_IMP] THEN
+    GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [CART_EQ] THEN
+    SIMP_TAC[MATRIX_MUL_LTRANSP_DOT_COLUMN; LAMBDA_BETA] THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`\i. column i ((X:real^M^N) ** (P:real^M^M))`;
+                   `\i. column i ((Y:real^M^N) ** (P:real^M^M))`;
+                   `1..dimindex(:M)`]
+                  ORTHOGONAL_TRANSFORMATION_BETWEEN_ORTHOGONAL_SETS) THEN
+    REWRITE_TAC[IN_NUMSEG] THEN ANTS_TAC THENL
+     [ASM_SIMP_TAC[pairwise; IN_NUMSEG; NORM_EQ; orthogonal]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `f:real^N->real^N` (STRIP_ASSUME_TAC o GSYM)) THEN
+    EXISTS_TAC `matrix(f:real^N->real^N)` THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_MATRIX]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!M:real^M^N. M = M ** (P:real^M^M) ** transp P`
+     (fun th -> GEN_REWRITE_TAC BINOP_CONV [th])
+    THENL
+     [ASM_MESON_TAC[orthogonal_matrix; MATRIX_MUL_RID];
+      REWRITE_TAC[MATRIX_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC] THEN
+    REWRITE_TAC[GSYM MATRIX_MUL_ASSOC] THEN
+    ASM_SIMP_TAC[MATRIX_EQUAL_COLUMNS] THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [orthogonal_transformation]) THEN
+    DISCH_THEN(ASSUME_TAC o GSYM o MATCH_MP MATRIX_WORKS o CONJUNCT1) THEN
+    ASM_REWRITE_TAC[] THEN
+    SIMP_TAC[CART_EQ; matrix_vector_mul; column; LAMBDA_BETA] THEN
+    X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+    GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [matrix_mul] THEN
+    ASM_SIMP_TAC[LAMBDA_BETA]) in
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:A->bool = {}` THENL
+   [REPEAT STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `\x:real^N. x`] THEN
+    ASM_REWRITE_TAC[NOT_IN_EMPTY; ORTHOGONAL_TRANSFORMATION_ID];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `m:A`) THEN DISCH_TAC] THEN
+  SUBGOAL_THEN
+    `?r. IMAGE r (1..dimindex(:(N,1)finite_sum)) SUBSET s /\
+         affine hull (IMAGE (y o r) (1..dimindex(:(N,1)finite_sum))) =
+         affine hull (IMAGE (y:A->real^N) s)`
+  MP_TAC THENL
+   [REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+    SIMP_TAC[IMAGE_o; TAUT `p /\ q <=> ~(p ==> ~q)`;
+             HULL_MONO; IMAGE_SUBSET] THEN REWRITE_TAC[NOT_IMP] THEN
+    MP_TAC(ISPEC `IMAGE (y:A->real^N) s` AFFINE_BASIS_EXISTS) THEN
+    DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [AFFINE_INDEPENDENT_IFF_CARD]) THEN
+    STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [FINITE_INDEX_NUMSEG]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `f:num->real^N` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `CARD(b:real^N->bool) <= dimindex(:(N,1)finite_sum)`
+    ASSUME_TAC THENL
+     [REWRITE_TAC[GSYM INT_OF_NUM_LE] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (INT_ARITH
+       `a:int = c - &1 ==> a + &1 <= n ==> c <= n`)) THEN
+      REWRITE_TAC[DIMINDEX_FINITE_SUM; DIMINDEX_1; GSYM INT_OF_NUM_ADD] THEN
+      REWRITE_TAC[INT_LE_RADD; AFF_DIM_LE_UNIV];
+      ALL_TAC] THEN
+    UNDISCH_TAC `b SUBSET IMAGE (y:A->real^N) s` THEN
+    ONCE_ASM_REWRITE_TAC[] THEN REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[IN_IMAGE] THEN
+    GEN_REWRITE_TAC (LAND_CONV o DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[SKOLEM_THM; IN_NUMSEG] THEN
+    DISCH_THEN(X_CHOOSE_THEN `r:num->A` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\i. if i <= CARD(b:real^N->bool) then r i else (m:A)` THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    UNDISCH_THEN `affine hull b:real^N->bool = affine hull IMAGE y (s:A->bool)`
+     (SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[GSYM SUBSET] THEN MATCH_MP_TAC HULL_MONO THEN
+    ONCE_ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_NUMSEG] THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN REWRITE_TAC[GSYM IMAGE_o] THEN
+    REWRITE_TAC[IN_IMAGE; IN_NUMSEG] THEN EXISTS_TAC `i:num` THEN
+    ASM_REWRITE_TAC[o_THM] THEN ASM_MESON_TAC[LE_TRANS];
+    REWRITE_TAC[SUBSET; IN_NUMSEG; FORALL_IN_IMAGE] THEN
+    STRIP_TAC THEN MP_TAC(ISPECL
+     [`(lambda i. x(r i:A)):real^N^(N,1)finite_sum`;
+      `(lambda i. y(r i:A)):real^N^(N,1)finite_sum`] lemma) THEN
+    ASM_SIMP_TAC[LAMBDA_BETA] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^N->real^N` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `k:A` THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `!z. z IN
+          affine hull IMAGE (y o (r:num->A)) (1..dimindex(:(N,1)finite_sum))
+          ==> dist(z,y k) = dist(z,a + (f:real^N->real^N)(x k))`
+    MP_TAC THENL
+     [MATCH_MP_TAC SAME_DISTANCES_TO_AFFINE_HULL THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; o_THM; IN_NUMSEG] THEN
+      X_GEN_TAC `j:num` THEN STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+      EXISTS_TAC `dist(x(r(j:num)),(x:A->real^N) k)` THEN CONJ_TAC THENL
+       [CONV_TAC SYM_CONV THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[];
+        REWRITE_TAC[dist] THEN ASM_SIMP_TAC[NORM_ARITH
+         `(a + x) - (a + y):real^N = x - y`] THEN
+        ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION; LINEAR_SUB]];
+      ASM_SIMP_TAC[NORM_ARITH
+       `a:real^N = b <=> dist(a:real^N,a) = dist(a,b)`] THEN
+      DISCH_THEN MATCH_MP_TAC THEN  MATCH_MP_TAC HULL_INC THEN
+      REWRITE_TAC[IN_IMAGE; IN_NUMSEG] THEN ASM_MESON_TAC[]]]);;
+
+let RIGID_TRANSFORMATION_BETWEEN_CONGRUENT_SETS_STRONG = prove
+ (`!x:A->real^N y:A->real^N s t.
+        t SUBSET s /\ affine hull (IMAGE y t) = affine hull (IMAGE y s) /\
+        (!i j. i IN s /\ j IN t ==> dist(x i,x j) = dist(y i,y j))
+        ==> ?a f. orthogonal_transformation f /\
+                  !i. i IN s ==> y i = a + f(x i)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`x:A->real^N`; `y:A->real^N`; `t:A->bool`]
+        RIGID_TRANSFORMATION_BETWEEN_CONGRUENT_SETS) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^N->real^N` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `i:A` THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `!z. z IN affine hull (IMAGE (y:A->real^N) t)
+        ==> dist(z,y i) = dist(z,a + (f:real^N->real^N)(x i))`
+  MP_TAC THENL
+   [MATCH_MP_TAC SAME_DISTANCES_TO_AFFINE_HULL THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; o_THM; IN_NUMSEG] THEN
+    X_GEN_TAC `j:A` THEN STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `dist(a + f(x(j:A):real^N):real^N,a + f(x i))` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+    REWRITE_TAC[NORM_ARITH `dist(a + x:real^N,a + y) = dist(x,y)`] THEN
+    ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_ISOMETRY; DIST_SYM];
+    ASM_SIMP_TAC[NORM_ARITH
+     `a:real^N = b <=> dist(a:real^N,a) = dist(a,b)`] THEN
+    DISCH_THEN MATCH_MP_TAC THEN  MATCH_MP_TAC HULL_INC THEN
+    REWRITE_TAC[IN_IMAGE] THEN ASM_MESON_TAC[]]);;
+
+let RIGID_TRANSFORMATION_BETWEEN_3 = prove
+ (`!a b c a' b' c':real^N.
+        dist(a,b) = dist(a',b') /\
+        dist(b,c) = dist(b',c') /\
+        dist(c,a) = dist(c',a')
+        ==> ?k f. orthogonal_transformation f /\
+                  a' = k + f a /\ b' = k + f b /\ c' = k + f c`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`FST:real^N#real^N->real^N`; `SND:real^N#real^N->real^N`;
+    `{(a:real^N,a':real^N), (b,b'), (c,c')}`]
+        RIGID_TRANSFORMATION_BETWEEN_CONGRUENT_SETS) THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_INSERT] THEN
+  REWRITE_TAC[NOT_IN_EMPTY; IMP_IMP] THEN DISCH_THEN MATCH_MP_TAC THEN
+  ASM_MESON_TAC[DIST_REFL; DIST_SYM]);;
+
+let RIGID_TRANSFORMATION_BETWEEN_2 = prove
+ (`!a b a' b':real^N.
+        dist(a,b) = dist(a',b')
+        ==> ?k f. orthogonal_transformation f /\
+                  a' = k + f a /\ b' = k + f b`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`a:real^N`; `b:real^N`; `a:real^N`;
+                 `a':real^N`; `b':real^N`; `a':real^N`]
+        RIGID_TRANSFORMATION_BETWEEN_3) THEN
+  ASM_MESON_TAC[DIST_EQ_0; DIST_SYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Caratheodory's theorem.                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_HULL_CARATHEODORY_AFF_DIM = prove
+ (`!p. convex hull p =
+        {y:real^N | ?s u. FINITE s /\ s SUBSET p /\
+                          &(CARD s) <= aff_dim p + &1 /\
+                          (!x. x IN s ==> &0 <= u x) /\
+                          sum s u = &1 /\ vsum s (\v. u v % v) = y}`,
+  GEN_TAC THEN REWRITE_TAC[CONVEX_HULL_EXPLICIT] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN X_GEN_TAC `y:real^N` THEN
+  EQ_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+  MATCH_MP_TAC(TAUT `!q. (p ==> q) /\ (q ==> r) ==> (p ==> r)`) THEN
+  EXISTS_TAC `?n s u. CARD s = n /\
+                      FINITE s /\ s SUBSET p /\
+                      (!x. x IN s ==> &0 <= u x) /\
+                      sum s u = &1 /\ vsum s (\v. u v % v) = (y:real^N)` THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [num_WOP] THEN
+  DISCH_THEN(X_CHOOSE_THEN `n:num` MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  GEN_REWRITE_TAC I [GSYM INT_NOT_LT] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `n - 1`) THEN REWRITE_TAC[NOT_IMP] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC(ARITH_RULE `~(n = 0) ==> n - 1 < n`) THEN
+    DISCH_THEN SUBST_ALL_TAC THEN
+    UNDISCH_TAC `aff_dim(p:real^N->bool) + &1 < &0` THEN
+    REWRITE_TAC[INT_ARITH `p + &1:int < &0 <=> ~(-- &1 <= p)`] THEN
+    REWRITE_TAC[AFF_DIM_GE];
+    ALL_TAC] THEN
+  MP_TAC(ISPEC `s:real^N->bool` AFF_DIM_AFFINE_INDEPENDENT) THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `~(aff_dim(s:real^N->bool) = &n - &1)` ASSUME_TAC THENL
+   [FIRST_ASSUM(MP_TAC o MATCH_MP AFF_DIM_SUBSET) THEN
+
+    UNDISCH_TAC `aff_dim(p:real^N->bool) + &1 < &n` THEN
+    INT_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[AFFINE_DEPENDENT_EXPLICIT_FINITE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `w:real^N->real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `?t. (!v:real^N. v IN s ==> u(v) + t * w(v) >= &0) /\
+        ?a. a IN s /\ u(a) + t * w(a) = &0`
+  STRIP_ASSUME_TAC THENL
+   [ABBREV_TAC
+     `i = IMAGE (\v. u(v) / --w(v)) {v:real^N | v IN s /\ w v < &0}` THEN
+    EXISTS_TAC `inf i` THEN MP_TAC(SPEC `i:real->bool` INF_FINITE) THEN
+    ANTS_TAC THENL
+     [EXPAND_TAC "i" THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; FINITE_RESTRICT; IMAGE_EQ_EMPTY] THEN
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+      MP_TAC(ISPECL [`w:real^N->real`; `s:real^N->bool`] SUM_ZERO_EXISTS) THEN
+      ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    ABBREV_TAC `t = inf i` THEN
+    EXPAND_TAC "i" THEN REWRITE_TAC[FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[IN_IMAGE; IN_ELIM_THM] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_THEN `a:real^N`
+      STRIP_ASSUME_TAC) MP_TAC) THEN
+    SIMP_TAC[REAL_LE_RDIV_EQ; REAL_ARITH `x < &0 ==> &0 < --x`; real_ge] THEN
+    REWRITE_TAC[REAL_ARITH `t * --w <= u <=> &0 <= u + t * w`] THEN
+    STRIP_TAC THEN CONJ_TAC THENL
+     [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+      DISJ_CASES_TAC(REAL_ARITH `(w:real^N->real) x < &0 \/ &0 <= w x`) THEN
+      ASM_SIMP_TAC[] THEN MATCH_MP_TAC REAL_LE_ADD THEN ASM_SIMP_TAC[] THEN
+      MATCH_MP_TAC REAL_LE_MUL THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC REAL_LE_DIV THEN ASM_SIMP_TAC[] THEN
+      MATCH_MP_TAC(REAL_ARITH `w < &0 ==> &0 <= --w`) THEN ASM_REWRITE_TAC[];
+      EXISTS_TAC `a:real^N` THEN ASM_REWRITE_TAC[] THEN
+      UNDISCH_TAC `w(a:real^N) < &0` THEN CONV_TAC REAL_FIELD];
+    ALL_TAC] THEN
+  MAP_EVERY EXISTS_TAC
+   [`s DELETE (a:real^N)`; `(\v. u(v) + t * w(v)):real^N->real`] THEN
+  ASM_SIMP_TAC[SUM_DELETE; VSUM_DELETE; CARD_DELETE; FINITE_DELETE] THEN
+  ASM_SIMP_TAC[SUM_ADD; VECTOR_ADD_RDISTRIB; VSUM_ADD] THEN
+  ASM_SIMP_TAC[GSYM VECTOR_MUL_ASSOC; SUM_LMUL; VSUM_LMUL] THEN
+  REPEAT CONJ_TAC THENL
+   [ASM SET_TAC[]; ASM SET_TAC[real_ge]; REAL_ARITH_TAC; VECTOR_ARITH_TAC]);;
+
+let CARATHEODORY_AFF_DIM = prove
+ (`!p. convex hull p =
+        {x:real^N | ?s. FINITE s /\ s SUBSET p /\
+                         &(CARD s) <= aff_dim p + &1 /\
+                        x IN convex hull s}`,
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN REPEAT GEN_TAC THEN EQ_TAC THENL
+   [GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+     [CONVEX_HULL_CARATHEODORY_AFF_DIM] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    ASM_MESON_TAC[HULL_SUBSET; CONVEX_EXPLICIT; CONVEX_CONVEX_HULL];
+    MESON_TAC[SUBSET; HULL_MONO]]);;
+
+let CONVEX_HULL_CARATHEODORY = prove
+ (`!p. convex hull p =
+        {y:real^N | ?s u. FINITE s /\ s SUBSET p /\
+                          CARD(s) <= dimindex(:N) + 1 /\
+                          (!x. x IN s ==> &0 <= u x) /\
+                          sum s u = &1 /\ vsum s (\v. u v % v) = y}`,
+
+  GEN_TAC THEN REWRITE_TAC[EXTENSION] THEN X_GEN_TAC `y:real^N` THEN
+  EQ_TAC THENL
+   [REWRITE_TAC[CONVEX_HULL_CARATHEODORY_AFF_DIM; IN_ELIM_THM] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    STRIP_TAC THEN
+    ASM_REWRITE_TAC[GSYM INT_OF_NUM_LE; GSYM INT_OF_NUM_ADD] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (INT_ARITH
+     `a:int <= x + &1 ==> x <= y ==> a <= y + &1`)) THEN
+    REWRITE_TAC[AFF_DIM_LE_UNIV];
+    REWRITE_TAC[CONVEX_HULL_EXPLICIT; IN_ELIM_THM] THEN MESON_TAC[]]);;
+
+let CARATHEODORY = prove
+ (`!p. convex hull p =
+        {x:real^N | ?s. FINITE s /\ s SUBSET p /\
+                        CARD(s) <= dimindex(:N) + 1 /\
+                        x IN convex hull s}`,
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN REPEAT GEN_TAC THEN EQ_TAC THENL
+   [GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+     [CONVEX_HULL_CARATHEODORY] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    ASM_MESON_TAC[HULL_SUBSET; CONVEX_EXPLICIT; CONVEX_CONVEX_HULL];
+    MESON_TAC[SUBSET; HULL_MONO]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some results on decomposing convex hulls, e.g. simplicial subdivision.    *)
+(* ------------------------------------------------------------------------- *)
+
+let AFFINE_HULL_INTER,CONVEX_HULL_INTER = (CONJ_PAIR o prove)
+ (`(!s t:real^N->bool.
+        ~(affine_dependent(s UNION t))
+        ==> affine hull s INTER affine hull t = affine hull (s INTER t)) /\
+   (!s t:real^N->bool.
+        ~(affine_dependent (s UNION t))
+        ==> convex hull s INTER convex hull t = convex hull (s INTER t))`,
+  CONJ_TAC THEN
+  (REPEAT STRIP_TAC THEN
+   FIRST_ASSUM(MP_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+   REWRITE_TAC[FINITE_UNION] THEN STRIP_TAC THEN
+   MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[SUBSET_INTER] THEN
+   SIMP_TAC[HULL_MONO; INTER_SUBSET] THEN
+   REWRITE_TAC[SUBSET; AFFINE_HULL_FINITE; CONVEX_HULL_FINITE;
+               IN_ELIM_THM; IN_INTER] THEN
+   X_GEN_TAC `y:real^N` THEN DISCH_THEN(CONJUNCTS_THEN2
+    (X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC)
+    (X_CHOOSE_THEN `v:real^N->real` STRIP_ASSUME_TAC)) THEN
+   FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV
+     [AFFINE_DEPENDENT_EXPLICIT]) THEN
+   REWRITE_TAC[NOT_EXISTS_THM] THEN
+   DISCH_THEN(MP_TAC o SPEC `(s UNION t):real^N->bool`) THEN
+   ASM_REWRITE_TAC[SUBSET_REFL] THEN
+   DISCH_THEN(MP_TAC o SPEC
+    `\x:real^N. (if x IN s then u x else &0) -
+                (if x IN t then v x else &0)`) THEN
+   ASM_SIMP_TAC[SUM_SUB; FINITE_UNION; VSUM_SUB; VECTOR_SUB_RDISTRIB] THEN
+   REWRITE_TAC[MESON[]
+    `(if p then a else b) % x = (if p then a % x else b % x)`] THEN
+   ASM_SIMP_TAC[SUM_CASES; VSUM_CASES; VECTOR_MUL_LZERO; FINITE_UNION] THEN
+   ASM_REWRITE_TAC[SUM_0; VSUM_0;
+     SET_RULE `{x | x IN (s UNION t) /\ x IN s} = s`;
+     SET_RULE `{x | x IN (s UNION t) /\ x IN t} = t`] THEN
+   MATCH_MP_TAC(TAUT `a /\ c /\ (~b ==> d) ==> ~(a /\ b /\ c) ==> d`) THEN
+   REPEAT CONJ_TAC THENL [REAL_ARITH_TAC; VECTOR_ARITH_TAC; ALL_TAC] THEN
+   DISCH_TAC THEN EXISTS_TAC `u:real^N->real` THEN ASM_SIMP_TAC[] THEN
+   CONJ_TAC THEN MATCH_MP_TAC EQ_TRANS THENL
+    [EXISTS_TAC `sum s (u:real^N->real)`;
+     EXISTS_TAC `vsum s (\x. (u:real^N->real) x % x)`] THEN
+   (CONJ_TAC THENL [ALL_TAC; FIRST_X_ASSUM ACCEPT_TAC]) THEN
+   CONV_TAC SYM_CONV THENL
+    [MATCH_MP_TAC SUM_EQ_SUPERSET; MATCH_MP_TAC VSUM_EQ_SUPERSET] THEN
+   ASM_SIMP_TAC[FINITE_INTER; INTER_SUBSET; IN_INTER] THEN
+   X_GEN_TAC `x:real^N` THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+   ASM_REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISCH_TAC THEN
+   FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_EXISTS_THM]) THEN
+   DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+   ASM_REWRITE_TAC[REAL_SUB_RZERO] THEN ASM SET_TAC[]));;
+
+let AFFINE_HULL_INTERS = prove
+ (`!s:(real^N->bool)->bool.
+        ~(affine_dependent(UNIONS s))
+        ==> affine hull (INTERS s) = INTERS {affine hull t | t IN s}`,
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(fun th ->
+   MP_TAC th THEN MP_TAC(MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE th)) THEN
+  SPEC_TAC(`s:(real^N->bool)->bool`,`s:(real^N->bool)->bool`) THEN
+  REWRITE_TAC[FINITE_UNIONS; IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[UNIONS_0; INTERS_0; UNIONS_INSERT; INTERS_INSERT;
+              SET_RULE `{f x | x IN {}} = {}`; AFFINE_HULL_UNIV] THEN
+  MAP_EVERY X_GEN_TAC [`s:real^N->bool`; `f:(real^N->bool)->bool`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[FORALL_IN_INSERT] THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [UNDISCH_TAC `~affine_dependent((s UNION UNIONS f):real^N->bool)` THEN
+    REWRITE_TAC[CONTRAPOS_THM] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] AFFINE_DEPENDENT_MONO) THEN
+    SET_TAC[];
+    DISCH_TAC] THEN
+  ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THENL
+   [ASM_REWRITE_TAC[INTERS_0; INTER_UNIV; IN_SING] THEN
+    REWRITE_TAC[SET_RULE `{f x | x = a} = {f a}`; INTERS_1];
+    ALL_TAC] THEN
+  W(MP_TAC o PART_MATCH (rhs o rand) AFFINE_HULL_INTER o lhand o snd) THEN
+  ANTS_TAC THENL
+   [UNDISCH_TAC `~affine_dependent((s UNION UNIONS f):real^N->bool)` THEN
+    REWRITE_TAC[CONTRAPOS_THM] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] AFFINE_DEPENDENT_MONO) THEN
+    UNDISCH_TAC `~(f:(real^N->bool)->bool = {})` THEN SET_TAC[];
+    DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  REWRITE_TAC[SET_RULE
+   `{f x | x IN (a INSERT s)} = (f a) INSERT {f x | x IN s}`] THEN
+  ASM_REWRITE_TAC[INTERS_INSERT]);;
+
+let CONVEX_HULL_INTERS = prove
+ (`!s:(real^N->bool)->bool.
+        ~(affine_dependent(UNIONS s))
+        ==> convex hull (INTERS s) = INTERS {convex hull t | t IN s}`,
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(fun th ->
+   MP_TAC th THEN MP_TAC(MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE th)) THEN
+  SPEC_TAC(`s:(real^N->bool)->bool`,`s:(real^N->bool)->bool`) THEN
+  REWRITE_TAC[FINITE_UNIONS; IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[UNIONS_0; INTERS_0; UNIONS_INSERT; INTERS_INSERT;
+              SET_RULE `{f x | x IN {}} = {}`; CONVEX_HULL_UNIV] THEN
+  MAP_EVERY X_GEN_TAC [`s:real^N->bool`; `f:(real^N->bool)->bool`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[FORALL_IN_INSERT] THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [UNDISCH_TAC `~affine_dependent((s UNION UNIONS f):real^N->bool)` THEN
+    REWRITE_TAC[CONTRAPOS_THM] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] AFFINE_DEPENDENT_MONO) THEN
+    SET_TAC[];
+    DISCH_TAC] THEN
+  ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THENL
+   [ASM_REWRITE_TAC[INTERS_0; INTER_UNIV; IN_SING] THEN
+    REWRITE_TAC[SET_RULE `{f x | x = a} = {f a}`; INTERS_1];
+    ALL_TAC] THEN
+  W(MP_TAC o PART_MATCH (rhs o rand) CONVEX_HULL_INTER o lhand o snd) THEN
+  ANTS_TAC THENL
+   [UNDISCH_TAC `~affine_dependent((s UNION UNIONS f):real^N->bool)` THEN
+    REWRITE_TAC[CONTRAPOS_THM] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] AFFINE_DEPENDENT_MONO) THEN
+    UNDISCH_TAC `~(f:(real^N->bool)->bool = {})` THEN SET_TAC[];
+    DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  REWRITE_TAC[SET_RULE
+   `{f x | x IN (a INSERT s)} = (f a) INSERT {f x | x IN s}`] THEN
+  ASM_REWRITE_TAC[INTERS_INSERT]);;
+
+let IN_CONVEX_HULL_EXCHANGE = prove
+ (`!s a x:real^N.
+        a IN convex hull s /\ x IN convex hull s
+        ==> ?b. b IN s /\ x IN convex hull (a INSERT (s DELETE b))`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `(a:real^N) IN s` THENL
+   [EXISTS_TAC `a:real^N` THEN ASM_SIMP_TAC[INSERT_DELETE]; ALL_TAC] THEN
+  ASM_CASES_TAC `FINITE(s:real^N->bool) /\ CARD s <= dimindex(:N) + 1` THENL
+   [ALL_TAC;
+    UNDISCH_TAC `(x:real^N) IN convex hull s` THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [CARATHEODORY] THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM; IN_ELIM_THM] THEN
+    X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN
+    ASM_CASES_TAC `t:real^N->bool = s` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN `?b:real^N. b IN s /\ ~(b IN t)` MP_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:real^N` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    UNDISCH_TAC `(x:real^N) IN convex hull t` THEN
+    SPEC_TAC(`x:real^N`,`x:real^N`) THEN REWRITE_TAC[GSYM SUBSET] THEN
+    MATCH_MP_TAC HULL_MONO THEN ASM SET_TAC[]] THEN
+  MP_TAC(ASSUME `(a:real^N) IN convex hull s`) THEN
+  MP_TAC(ASSUME `(x:real^N) IN convex hull s`) THEN
+  REWRITE_TAC[CONVEX_HULL_FINITE; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `v:real^N->real` THEN STRIP_TAC THEN
+  X_GEN_TAC `u:real^N->real` THEN STRIP_TAC THEN
+  ASM_CASES_TAC `?b. b IN s /\ (v:real^N->real) b = &0` THENL
+   [FIRST_X_ASSUM(fun th -> MP_TAC th THEN MATCH_MP_TAC MONO_EXISTS) THEN
+    X_GEN_TAC `b:real^N` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    EXISTS_TAC `\x:real^N. if x = a then &0 else v x` THEN
+    ASM_SIMP_TAC[FORALL_IN_INSERT; REAL_LE_REFL] THEN
+    ASM_SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES; FINITE_DELETE] THEN
+    ASM_REWRITE_TAC[IN_DELETE] THEN
+    ASM_SIMP_TAC[SUM_DELETE; VSUM_DELETE; COND_ID] THEN
+    ONCE_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+    ASM_SIMP_TAC[SUM_CASES; VSUM_CASES; REAL_LE_REFL; COND_ID] THEN
+    REWRITE_TAC[VECTOR_MUL_LZERO; SUM_0; VSUM_0] THEN
+    ASM_SIMP_TAC[SET_RULE `~(a IN s) ==> {x | x IN s /\ ~(x = a)} = s`] THEN
+    CONJ_TAC THENL [REAL_ARITH_TAC; VECTOR_ARITH_TAC];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_EXISTS_THM]) THEN
+  REWRITE_TAC[TAUT `~(a /\ b) <=> a ==> ~b`] THEN DISCH_TAC THEN
+  MP_TAC(ISPEC `IMAGE (\b. (u:real^N->real) b / v b) s` SUP_FINITE) THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_MESON_TAC[CONVEX_HULL_EMPTY; NOT_IN_EMPTY]; ALL_TAC] THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; IMAGE_EQ_EMPTY; FORALL_IN_IMAGE] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[IN_IMAGE] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `b:real^N` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `!b. b IN s ==> &0 < (v:real^N->real) b` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[REAL_LT_LE]; ALL_TAC] THEN
+  SUBGOAL_THEN `&0 < (u:real^N->real) b /\ &0 < v b` STRIP_ASSUME_TAC THENL
+   [ASM_SIMP_TAC[REAL_LT_LE] THEN
+    UNDISCH_TAC `!x. x IN s ==> (u:real^N->real) x / v x <= u b / v b` THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_SIMP_TAC[REAL_LE_LDIV_EQ] THEN
+    REWRITE_TAC[real_div; REAL_MUL_LZERO] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 <= x ==> (x <= &0 <=> x = &0)`] THEN
+    DISCH_TAC THEN UNDISCH_TAC `sum s (u:real^N->real) = &1` THEN
+    MATCH_MP_TAC(REAL_ARITH `x = &0 ==> x = &1 ==> F`) THEN
+    ASM_SIMP_TAC[SUM_EQ_0];
+    ALL_TAC] THEN
+  EXISTS_TAC `(\x. if x = a then v b / u b else v x - (v b / u b) * u x):
+              real^N->real` THEN
+  ASM_SIMP_TAC[FORALL_IN_INSERT; REAL_LE_DIV; REAL_LT_IMP_LE] THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+  ASM_SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES; FINITE_DELETE] THEN
+  ASM_SIMP_TAC[SUM_DELETE; VSUM_DELETE; IN_DELETE] THEN
+  ASM_SIMP_TAC[SUM_CASES; VSUM_CASES; FINITE_DELETE] THEN
+  ASM_SIMP_TAC[SET_RULE `~(a IN s) ==> {x | x IN s /\ ~(x = a)} = s`;
+               SET_RULE `~(a IN s) ==> {x | x IN s /\ x = a} = {}`] THEN
+  REWRITE_TAC[VSUM_CLAUSES; SUM_CLAUSES] THEN
+  ASM_CASES_TAC `b:real^N = a` THENL [ASM_MESON_TAC[]; ASM_REWRITE_TAC[]] THEN
+  ASM_SIMP_TAC[VECTOR_SUB_RDISTRIB; VSUM_SUB; SUM_SUB] THEN
+  REWRITE_TAC[GSYM VECTOR_MUL_ASSOC; VECTOR_ADD_LID; REAL_ADD_LID] THEN
+  ASM_SIMP_TAC[SUM_LMUL; VSUM_LMUL] THEN REWRITE_TAC[VECTOR_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_DIV_RMUL; REAL_LT_IMP_NZ] THEN REPEAT CONJ_TAC THENL
+   [ALL_TAC; REAL_ARITH_TAC; VECTOR_ARITH_TAC] THEN
+  X_GEN_TAC `c:real^N` THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  STRIP_TAC THEN ASM_CASES_TAC `(u:real^N->real) c = &0` THENL
+   [ASM_SIMP_TAC[REAL_MUL_RZERO; REAL_SUB_RZERO]; ALL_TAC] THEN
+  REWRITE_TAC[REAL_SUB_LE] THEN
+  ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; REAL_LT_LE] THEN
+  ONCE_REWRITE_TAC[GSYM REAL_INV_DIV] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_LE]);;
+
+let IN_CONVEX_HULL_EXCHANGE_UNIQUE = prove
+ (`!s t t' a x:real^N.
+        ~(affine_dependent s) /\
+        a IN convex hull s /\
+        t SUBSET s /\ t' SUBSET s /\
+        x IN convex hull (a INSERT t) /\
+        x IN convex hull (a INSERT t')
+        ==> x IN convex hull (a INSERT (t INTER t'))`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `(a:real^N) IN s` THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[SET_RULE
+     `a INSERT (s INTER t) = (a INSERT s) INTER (a INSERT t)`] THEN
+    W(MP_TAC o PART_MATCH (rand o rand)  CONVEX_HULL_INTER o rand o snd) THEN
+    ANTS_TAC THENL
+     [UNDISCH_TAC `~(affine_dependent(s:real^N->bool))` THEN
+      REWRITE_TAC[CONTRAPOS_THM] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] AFFINE_DEPENDENT_MONO);
+      DISCH_THEN(SUBST1_TAC o SYM)] THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  REWRITE_TAC[CONVEX_HULL_FINITE; IN_ELIM_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_THEN `b:real^N->real` STRIP_ASSUME_TAC)
+    MP_TAC) THEN
+  REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  SUBGOAL_THEN `~((a:real^N) IN t) /\ ~(a IN t')` STRIP_ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `FINITE(t:real^N->bool) /\ FINITE(t':real^N->bool)`
+  STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+  ASM_SIMP_TAC[AFFINE_HULL_FINITE_STEP_GEN; REAL_LE_ADD;
+               REAL_ARITH `&0 <= a / &2 <=> &0 <= a`] THEN
+  REWRITE_TAC[IMP_CONJ; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`u':real`; `u:real^N->real`] THEN REPEAT DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`v':real`; `v:real^N->real`] THEN REPEAT DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV
+    [AFFINE_DEPENDENT_EXPLICIT]) THEN
+  REWRITE_TAC[NOT_EXISTS_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `s:real^N->bool`) THEN
+  ASM_REWRITE_TAC[SUBSET_REFL] THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `\x:real^N. (if x IN t then u x else &0) - (if x IN t' then v x else &0) +
+               (u' - v') * b x`) THEN
+  ASM_SIMP_TAC[SUM_ADD; VSUM_ADD; SUM_LMUL; VSUM_LMUL; VECTOR_ADD_RDISTRIB] THEN
+  ASM_SIMP_TAC[SUM_SUB; VSUM_SUB; VECTOR_SUB_RDISTRIB] THEN
+  REWRITE_TAC[MESON[]
+   `(if p then a else b) % x = (if p then a % x else b % x)`] THEN
+  ASM_SIMP_TAC[SUM_CASES; VSUM_CASES; VECTOR_MUL_LZERO; SUM_0; VSUM_0] THEN
+  ASM_SIMP_TAC[SET_RULE `t SUBSET s ==> {x | x IN s /\ x IN t} = t`] THEN
+  ASM_SIMP_TAC[SUM_ADD; SUM_LMUL; VSUM_ADD; VSUM_LMUL; VECTOR_ADD_RDISTRIB;
+               GSYM VECTOR_MUL_ASSOC] THEN
+  MATCH_MP_TAC(TAUT `a /\ c /\ (~b ==> d) ==> ~(a /\ b /\ c) ==> d`) THEN
+  REPEAT CONJ_TAC THENL [REAL_ARITH_TAC; VECTOR_ARITH_TAC; ALL_TAC] THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN
+   `(!x. x IN s ==> (if x IN t then u x else &0) <=
+                    (if x IN t' then v x else &0)) \/
+    (!x:real^N. x IN s ==> (if x IN t' then v x else &0) <=
+                           (if x IN t then u x else &0))`
+  (DISJ_CASES_THEN(LABEL_TAC "*")) THENL
+   [MP_TAC(REAL_ARITH `&0 <= (u' - v') \/ &0 <= (v' - u')`) THEN
+    MATCH_MP_TAC MONO_OR THEN CONJ_TAC THEN
+    DISCH_TAC THEN X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_EXISTS_THM]) THEN
+    DISCH_THEN(MP_TAC o SPEC `y:real^N`) THEN ASM_REWRITE_TAC[] THENL
+     [MATCH_MP_TAC(REAL_ARITH `&0 <= c ==> a - b + c = &0 ==> a <= b`);
+      MATCH_MP_TAC(REAL_ARITH `&0 <= --c ==> a - b + c = &0 ==> b <= a`)] THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; GSYM REAL_MUL_LNEG; REAL_NEG_SUB];
+    EXISTS_TAC `(\x. if x = a then u' else u x):real^N->real`;
+    EXISTS_TAC `(\x. if x = a then v' else v x):real^N->real`] THEN
+  ASM_SIMP_TAC[FORALL_IN_INSERT] THEN
+  (CONJ_TAC THENL [ASM_MESON_TAC[IN_INTER]; ALL_TAC]) THEN
+  ASM_SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES; FINITE_INTER] THEN
+  ASM_REWRITE_TAC[IN_INTER] THEN
+  REWRITE_TAC[REAL_ARITH `u' + u = &1 <=> u = &1 - u'`;
+              VECTOR_ARITH `u' + u:real^N = y <=> u = y - u'`] THEN
+  (CONJ_TAC THEN
+   FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [GSYM th]) THEN
+   CONV_TAC SYM_CONV THENL
+    [MATCH_MP_TAC SUM_EQ_SUPERSET; MATCH_MP_TAC VSUM_EQ_SUPERSET]) THEN
+  ASM_SIMP_TAC[FINITE_INTER; INTER_SUBSET; IN_INTER] THEN
+  (CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+  X_GEN_TAC `y:real^N` THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISCH_TAC THEN
+  REMOVE_THEN "*" (MP_TAC o SPEC `y:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN ASM SET_TAC[]);;
+
+let CONVEX_HULL_EXCHANGE_UNION = prove
+ (`!s a:real^N.
+        a IN convex hull s
+        ==> convex hull s =
+            UNIONS {convex hull (a INSERT (s DELETE b)) |b| b IN s}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN REWRITE_TAC[UNIONS_IMAGE] THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+    ASM_MESON_TAC[IN_CONVEX_HULL_EXCHANGE];
+    REWRITE_TAC[SUBSET; FORALL_IN_UNIONS; FORALL_IN_GSPEC;
+                IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[GSYM SUBSET] THEN
+    ASM_SIMP_TAC[SUBSET_HULL; CONVEX_CONVEX_HULL] THEN
+    ASM_REWRITE_TAC[INSERT_SUBSET] THEN
+    MESON_TAC[HULL_INC; SUBSET; IN_DELETE]]);;
+
+let CONVEX_HULL_EXCHANGE_INTER = prove
+ (`!s a:real^N t t'.
+         ~affine_dependent s /\
+         a IN convex hull s /\
+         t SUBSET s /\
+         t' SUBSET s
+         ==> (convex hull (a INSERT t)) INTER (convex hull (a INSERT t')) =
+             convex hull (a INSERT (t INTER t'))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; IN_INTER] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC IN_CONVEX_HULL_EXCHANGE_UNIQUE THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[];
+    REWRITE_TAC[SUBSET_INTER] THEN CONJ_TAC THEN
+    MATCH_MP_TAC HULL_MONO THEN SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Representing affine hull as hyperplane or finite intersection of them.    *)
+(* ------------------------------------------------------------------------- *)
+
+let AFF_DIM_EQ_HYPERPLANE = prove
+ (`!s. aff_dim s = &(dimindex(:N)) - &1 <=>
+       ?a b. ~(a = vec 0) /\ affine hull s = {x:real^N | a dot x = b}`,
+  GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[AFF_DIM_EMPTY; INT_ARITH `--a:int = b - a <=> b = &0`] THEN
+    SIMP_TAC[INT_OF_NUM_EQ; LE_1; DIMINDEX_GE_1; AFFINE_HULL_EMPTY] THEN
+    REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY; NOT_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(MP_TAC o SPEC `(b / (a dot a)) % a:real^N`) THEN
+    ASM_SIMP_TAC[DOT_RMUL; REAL_DIV_RMUL; DOT_EQ_0];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `c:real^N` THEN
+    GEN_GEOM_ORIGIN_TAC `c:real^N` ["a"] THEN
+    SIMP_TAC[AFF_DIM_DIM_0; HULL_INC] THEN
+    SIMP_TAC[INT_OF_NUM_SUB; DIMINDEX_GE_1; INT_OF_NUM_EQ] THEN
+    SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC; DIM_EQ_HYPERPLANE] THEN
+    REPEAT STRIP_TAC THEN AP_TERM_TAC THEN
+    GEN_REWRITE_TAC I [FUN_EQ_THM] THEN X_GEN_TAC `a:real^N` THEN
+    REWRITE_TAC[] THEN ASM_CASES_TAC `a:real^N = vec 0` THEN
+    ASM_REWRITE_TAC[DOT_RADD; REAL_ARITH `a + b:real = c <=> b = c - a`] THEN
+    EQ_TAC THEN STRIP_TAC THENL
+     [EXISTS_TAC `(a:real^N) dot c` THEN ASM_REWRITE_TAC[REAL_SUB_REFL];
+      ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o AP_TERM `\s. (vec 0:real^N) IN s`) THEN
+      ASM_SIMP_TAC[SPAN_SUPERSET; IN_ELIM_THM; DOT_RZERO]]]);;
+
+let AFF_DIM_HYPERPLANE = prove
+ (`!a b. ~(a = vec 0)
+         ==> aff_dim {x:real^N | a dot x = b} = &(dimindex(:N)) - &1`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[AFF_DIM_EQ_HYPERPLANE] THEN
+  MAP_EVERY EXISTS_TAC [`a:real^N`; `b:real`] THEN
+  ASM_REWRITE_TAC[AFFINE_HULL_EQ; AFFINE_HYPERPLANE]);;
+
+let BOUNDED_HYPERPLANE_EQ_TRIVIAL = prove
+ (`!a b. bounded {x:real^N | a dot x = b} <=>
+         if a = vec 0 then ~(b = &0) else dimindex(:N) = 1`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THEN
+  ASM_REWRITE_TAC[DOT_LZERO] THENL
+   [ASM_CASES_TAC `b = &0` THEN
+    ASM_REWRITE_TAC[EMPTY_GSPEC; BOUNDED_EMPTY] THEN
+    REWRITE_TAC[NOT_BOUNDED_UNIV; SET_RULE `{x | T} = UNIV`];
+    ASM_SIMP_TAC[AFFINE_BOUNDED_EQ_LOWDIM; AFF_DIM_HYPERPLANE;
+                 AFFINE_HYPERPLANE] THEN
+    REWRITE_TAC[INT_ARITH `a - &1:int <= &0 <=> a <= &1`; INT_OF_NUM_LE] THEN
+    MATCH_MP_TAC(ARITH_RULE `1 <= n ==> (n <= 1 <=> n = 1)`) THEN
+    REWRITE_TAC[DIMINDEX_GE_1]]);;
+
+let AFFINE_HULL_FINITE_INTERSECTION_HYPERPLANES = prove
+ (`!s:real^N->bool.
+        ?f. FINITE f /\
+            &(CARD f) + aff_dim s = &(dimindex(:N)) /\
+            affine hull s = INTERS f /\
+            (!h. h IN f ==> ?a b. ~(a = vec 0) /\ h = {x | a dot x = b})`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+  MP_TAC(ISPEC `s:real^N->bool` AFFINE_BASIS_EXISTS) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  MP_TAC(ISPECL [`b:real^N->bool`; `(:real^N)`] EXTEND_TO_AFFINE_BASIS) THEN
+  ASM_REWRITE_TAC[SUBSET_UNIV; AFFINE_HULL_UNIV] THEN
+  DISCH_THEN(X_CHOOSE_THEN `c:real^N->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `FINITE(c:real^N->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[AFFINE_INDEPENDENT_IMP_FINITE]; ALL_TAC] THEN
+  REWRITE_TAC[GSYM AFF_DIM_UNIV] THEN FIRST_ASSUM(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[AFF_DIM_AFFINE_HULL] THEN
+  ASM_SIMP_TAC[AFF_DIM_AFFINE_INDEPENDENT; CARD_DIFF] THEN
+  REWRITE_TAC[INT_ARITH `f + b - &1:int = c - &1 <=> f = c - b`] THEN
+  ASM_SIMP_TAC[INT_OF_NUM_SUB; CARD_SUBSET; GSYM CARD_DIFF; INT_OF_NUM_EQ] THEN
+  ASM_CASES_TAC `c:real^N->bool = b` THENL
+   [EXISTS_TAC `{}:(real^N->bool)->bool` THEN
+    ASM_REWRITE_TAC[CARD_CLAUSES; FINITE_RULES; NOT_IN_EMPTY; INTERS_0;
+                    DIFF_EQ_EMPTY] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  EXISTS_TAC `{affine hull (c DELETE a) |a| (a:real^N) IN (c DIFF b)}` THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN REWRITE_TAC[SIMPLE_IMAGE] THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FINITE_DIFF] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CARD_IMAGE_INJ THEN ASM_SIMP_TAC[FINITE_DIFF] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN REWRITE_TAC[IN_DIFF] THEN
+    STRIP_TAC THEN ASM_CASES_TAC `x:real^N = y` THEN ASM_REWRITE_TAC[] THEN
+    UNDISCH_TAC `~affine_dependent(c:real^N->bool)` THEN
+    REWRITE_TAC[affine_dependent] THEN EXISTS_TAC `x:real^N` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC HULL_INC THEN ASM SET_TAC[];
+    ONCE_REWRITE_TAC[GSYM o_DEF] THEN REWRITE_TAC[IMAGE_o] THEN
+    ONCE_REWRITE_TAC[GSYM SIMPLE_IMAGE] THEN
+    W(MP_TAC o PART_MATCH (rhs o rand) AFFINE_HULL_INTERS o rand o snd) THEN
+    ANTS_TAC THENL
+     [MATCH_MP_TAC AFFINE_INDEPENDENT_SUBSET THEN
+      EXISTS_TAC `c:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_UNIONS; FORALL_IN_IMAGE;
+                  IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN SET_TAC[];
+      DISCH_THEN(SUBST1_TAC o SYM) THEN AP_TERM_TAC THEN
+      GEN_REWRITE_TAC I [EXTENSION] THEN
+      REWRITE_TAC[IN_INTERS; FORALL_IN_IMAGE] THEN ASM SET_TAC[]];
+    REWRITE_TAC[GSYM AFF_DIM_EQ_HYPERPLANE] THEN
+    ASM_SIMP_TAC[IN_DIFF; AFFINE_INDEPENDENT_DELETE;
+                 AFF_DIM_AFFINE_INDEPENDENT; CARD_DELETE] THEN
+    REWRITE_TAC[GSYM AFF_DIM_UNIV] THEN FIRST_ASSUM(SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[AFF_DIM_AFFINE_HULL] THEN
+    ASM_SIMP_TAC[AFF_DIM_AFFINE_INDEPENDENT; CARD_DIFF] THEN
+    REPEAT STRIP_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    MATCH_MP_TAC(GSYM INT_OF_NUM_SUB) THEN
+    MATCH_MP_TAC(ARITH_RULE `~(c = 0) ==> 1 <= c`) THEN
+    ASM_SIMP_TAC[CARD_EQ_0] THEN ASM SET_TAC[]]);;
+
+let AFFINE_HYPERPLANE_SUMS_EQ_UNIV = prove
+ (`!a b s.
+        affine s /\
+        ~(s INTER {v | a dot v = b} = {}) /\
+        ~(s DIFF {v | a dot v = b} = {})
+        ==> {x + y | x IN s /\ y IN {v | a dot v = b}} = (:real^N)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THENL
+   [ASM_REWRITE_TAC[DOT_LZERO] THEN SET_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> b ==> a /\ c ==> d`] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM MEMBER_NOT_EMPTY] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; IN_ELIM_THM] THEN X_GEN_TAC `c:real^N` THEN
+  ONCE_REWRITE_TAC[SET_RULE
+   `{x + y:real^N | x IN s /\ P y} =
+        {z | ?x y. x IN s /\ P y /\ z = x + y}`] THEN
+  GEOM_ORIGIN_TAC `c:real^N` THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[DOT_RADD; REAL_ARITH `b dot c + a = d <=> a = d - b dot c`] THEN
+  REWRITE_TAC[IN_INTER; IN_ELIM_THM; DOT_RZERO] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (SUBST1_TAC o SYM)) THEN
+  ASM_SIMP_TAC[AFFINE_EQ_SUBSPACE; HULL_INC] THEN STRIP_TAC THEN
+  REWRITE_TAC[VECTOR_ARITH `c + z:real^N = (c + x) + (c + y) <=>
+                            z = c + x + y`] THEN
+  REWRITE_TAC[SET_RULE
+   `{z | ?x y. x IN s /\ P y /\ z = c + x + y} =
+    IMAGE (\x. c + x) {x + y:real^N | x IN s /\ y IN {v | P v}}`] THEN
+  MATCH_MP_TAC(SET_RULE
+   `!f. (!x. g(f x) = x) /\ s = UNIV ==> IMAGE g s = UNIV`) THEN
+  EXISTS_TAC `\x:real^N. x - c` THEN
+  REWRITE_TAC[VECTOR_ARITH `c + x - c:real^N = x`] THEN
+  MATCH_MP_TAC(MESON[SPAN_EQ_SELF] `subspace s /\ span s = t ==> s = t`) THEN
+  CONJ_TAC THENL
+   [ASM_SIMP_TAC[SUBSPACE_SUMS; SUBSPACE_HYPERPLANE];
+    ALL_TAC] THEN
+  REWRITE_TAC[GSYM DIM_EQ_FULL] THEN
+  REWRITE_TAC[GSYM LE_ANTISYM; DIM_SUBSET_UNIV] THEN
+  MATCH_MP_TAC(ARITH_RULE `m - 1 < n ==> m <= n`) THEN
+  MATCH_MP_TAC LET_TRANS THEN EXISTS_TAC `dim {x:real^N | a dot x = &0}` THEN
+  CONJ_TAC THENL [ASM_SIMP_TAC[DIM_HYPERPLANE; LE_REFL]; ALL_TAC] THEN
+  MATCH_MP_TAC DIM_PSUBSET THEN
+  ASM_SIMP_TAC[snd(EQ_IMP_RULE(SPEC_ALL SPAN_EQ_SELF));
+               SUBSPACE_SUMS; SUBSPACE_HYPERPLANE] THEN
+  REWRITE_TAC[PSUBSET; SUBSET; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN CONJ_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `x:real^N`] THEN
+    ASM_SIMP_TAC[SUBSPACE_0; VECTOR_ADD_LID];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    REWRITE_TAC[NOT_FORALL_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `x:real^N` THEN SIMP_TAC[IN_DIFF; IN_ELIM_THM] THEN
+    DISCH_TAC THEN MAP_EVERY EXISTS_TAC [`x:real^N`; `vec 0:real^N`] THEN
+    ASM_REWRITE_TAC[DOT_RZERO; VECTOR_ADD_RID]]);;
+
+let AFF_DIM_AFFINE_INTER_HYPERPLANE = prove
+ (`!a b s:real^N->bool.
+        affine s
+        ==> aff_dim(s INTER {x | a dot x = b}) =
+                if s INTER {v | a dot v = b} = {} then -- &1
+                else if s SUBSET {v | a dot v = b} then aff_dim s
+                else aff_dim s - &1`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THENL
+   [ASM_REWRITE_TAC[DOT_LZERO] THEN ASM_CASES_TAC `b = &0` THEN
+    ASM_REWRITE_TAC[EMPTY_GSPEC; INTER_EMPTY; AFF_DIM_EMPTY] THEN
+    SIMP_TAC[SET_RULE `{x | T} = UNIV`; IN_UNIV; INTER_UNIV; SUBSET_UNIV] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[AFF_DIM_EMPTY];
+    STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[AFF_DIM_EMPTY] THEN
+    COND_CASES_TAC THENL [AP_TERM_TAC THEN ASM SET_TAC[]; ALL_TAC] THEN
+    MP_TAC(ISPECL [`s:real^N->bool`; `{x:real^N | a dot x = b}`]
+        AFF_DIM_SUMS_INTER) THEN
+    ASM_SIMP_TAC[AFFINE_HYPERPLANE; AFF_DIM_HYPERPLANE] THEN
+    ASM_SIMP_TAC[AFFINE_HYPERPLANE_SUMS_EQ_UNIV; AFF_DIM_UNIV;
+                 SET_RULE `~(s SUBSET t) ==> ~(s DIFF t = {})`] THEN
+    SPEC_TAC(`aff_dim (s INTER {x:real^N | a dot x = b})`,`i:int`) THEN
+    INT_ARITH_TAC]);;
+
+let AFF_DIM_LT_FULL = prove
+ (`!s. aff_dim s < &(dimindex(:N)) <=> ~(affine hull s = (:real^N))`,
+  GEN_TAC THEN REWRITE_TAC[GSYM AFF_DIM_EQ_FULL] THEN
+  MP_TAC(ISPEC `s:real^N->bool` AFF_DIM_LE_UNIV) THEN ARITH_TAC);;
+
+let AFF_LOWDIM_SUBSET_HYPERPLANE = prove
+ (`!s:real^N->bool.
+        aff_dim s < &(dimindex(:N))
+        ==> ?a b. ~(a = vec 0) /\ s SUBSET {x | a dot x = b}`,
+  MATCH_MP_TAC SET_PROVE_CASES THEN CONJ_TAC THENL
+   [DISCH_TAC THEN EXISTS_TAC `basis 1:real^N` THEN
+    SIMP_TAC[EMPTY_SUBSET; BASIS_NONZERO; LE_REFL; DIMINDEX_GE_1];
+    MAP_EVERY X_GEN_TAC [`c:real^N`; `s:real^N->bool`] THEN
+    CONV_TAC(ONCE_DEPTH_CONV(GEN_ALPHA_CONV `a:real^N`)) THEN
+    GEN_GEOM_ORIGIN_TAC `c:real^N` ["a"] THEN
+    SIMP_TAC[AFF_DIM_DIM_0; HULL_INC; IN_INSERT; INT_OF_NUM_LT] THEN
+    REPEAT GEN_TAC THEN DISCH_TAC THEN
+    DISCH_THEN(MP_TAC o MATCH_MP LOWDIM_SUBSET_HYPERPLANE) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real^N` THEN
+    STRIP_TAC THEN EXISTS_TAC `(u:real^N) dot c` THEN
+    ASM_REWRITE_TAC[DOT_RADD; REAL_EQ_ADD_LCANCEL_0] THEN
+    ASM_MESON_TAC[SPAN_INC; SUBSET_TRANS]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* An additional lemma about hyperplanes.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let SUBSET_HYPERPLANES = prove
+ (`!a b a' b'.
+        {x | a dot x = b} SUBSET {x | a' dot x = b'} <=>
+        {x | a dot x = b} = {} \/ {x | a' dot x = b'} = (:real^N) \/
+        {x | a dot x = b} = {x | a' dot x = b'}`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `{x:real^N | a dot x = b} = {}` THEN
+  ASM_REWRITE_TAC[EMPTY_SUBSET] THEN
+  ASM_CASES_TAC `{x | a' dot x = b'} = (:real^N)` THEN
+  ASM_REWRITE_TAC[SUBSET_UNIV] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE
+   [HYPERPLANE_EQ_EMPTY; HYPERPLANE_EQ_UNIV]) THEN
+  REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+  ASM_CASES_TAC `{x:real^N | a dot x = b} SUBSET {x | a' dot x = b'}` THEN
+  ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPECL [`{x:real^N | a dot x = b}`; `{x:real^N | a' dot x = b'}`]
+        AFF_DIM_PSUBSET) THEN
+  ASM_SIMP_TAC[PSUBSET;
+               REWRITE_RULE[GSYM AFFINE_HULL_EQ] AFFINE_HYPERPLANE] THEN
+  ASM_CASES_TAC `{x:real^N | a dot x = b} = {x | a' dot x = b'}` THEN
+  ASM_REWRITE_TAC[SUBSET_REFL] THEN ASM_CASES_TAC `a':real^N = vec 0` THENL
+   [ASM_CASES_TAC `b' = &0` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[DOT_LZERO] THEN SET_TAC[];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `a:real^N = vec 0` THENL
+   [ASM_CASES_TAC `b = &0` THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+    ASM_REWRITE_TAC[DOT_LZERO] THEN SET_TAC[];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[AFF_DIM_HYPERPLANE; INT_LT_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Openness and compactness are preserved by convex hull operation.          *)
+(* ------------------------------------------------------------------------- *)
+
+let OPEN_CONVEX_HULL = prove
+ (`!s:real^N->bool. open s ==> open(convex hull s)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[CONVEX_HULL_EXPLICIT; OPEN_CONTAINS_CBALL] THEN
+  REWRITE_TAC[IN_ELIM_THM; SUBSET; LEFT_IMP_EXISTS_THM] THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `t:real^N->bool`; `u:real^N->real`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `?b. !x:real^N. x IN t ==> &0 < b(x) /\ cball(x,b(x)) SUBSET s`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM SKOLEM_THM] THEN ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+  ABBREV_TAC `i = IMAGE (b:real^N->real) t` THEN
+  EXISTS_TAC `inf i` THEN MP_TAC(SPEC `i:real->bool` INF_FINITE) THEN
+  EXPAND_TAC "i" THEN ASM_REWRITE_TAC[FORALL_IN_IMAGE; IN_IMAGE] THEN
+  ANTS_TAC THENL
+   [EXPAND_TAC "i" THEN CONJ_TAC THENL
+     [ASM_SIMP_TAC[FINITE_IMAGE]; ALL_TAC] THEN
+    REWRITE_TAC[IMAGE_EQ_EMPTY] THEN
+    ASM_MESON_TAC[SUM_CLAUSES; REAL_ARITH `~(&1 = &0)`];
+    ALL_TAC] THEN
+  STRIP_TAC THEN CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  X_GEN_TAC `y:real^N` THEN REWRITE_TAC[IN_CBALL; dist] THEN
+  DISCH_TAC THEN EXISTS_TAC `IMAGE (\v:real^N. v + (y - a)) t` THEN
+  EXISTS_TAC `\v. (u:real^N->real)(v - (y - a))` THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE; SUM_IMAGE; VSUM_IMAGE;
+               VECTOR_ARITH `v + a:real^N = w + a <=> v = w`] THEN
+  ASM_REWRITE_TAC[o_DEF; VECTOR_ARITH `(v + a) - a:real^N = v`] THEN
+  ASM_REWRITE_TAC[VECTOR_ADD_LDISTRIB; ETA_AX] THEN
+  ASM_SIMP_TAC[VSUM_ADD; VSUM_RMUL] THEN
+  CONJ_TAC THENL [ALL_TAC; VECTOR_ARITH_TAC] THEN
+  X_GEN_TAC `z:real^N` THEN STRIP_TAC THEN
+  SUBGOAL_THEN `z + (y - a) IN cball(z:real^N,b z)`
+   (fun th -> ASM_MESON_TAC[th; SUBSET]) THEN
+  REWRITE_TAC[IN_CBALL; dist; NORM_ARITH
+   `norm(z - (z + a - y)) = norm(y - a)`] THEN
+  ASM_MESON_TAC[REAL_LE_TRANS]);;
+
+let COMPACT_CONVEX_COMBINATIONS = prove
+ (`!s t. compact s /\ compact t
+         ==> compact { (&1 - u) % x + u % y :real^N |
+                      &0 <= u /\ u <= &1 /\ x IN s /\ y IN t}`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+   `{ (&1 - u) % x + u % y :real^N | &0 <= u /\ u <= &1 /\ x IN s /\ y IN t} =
+    IMAGE (\z. (&1 - drop(fstcart z)) % fstcart(sndcart z) +
+               drop(fstcart z) % sndcart(sndcart z))
+          { pastecart u w | u IN interval[vec 0,vec 1] /\
+                            w IN { pastecart x y | x IN s /\ y IN t} }`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_IMAGE] THEN
+    X_GEN_TAC `x:real^N` THEN
+    REWRITE_TAC[RIGHT_AND_EXISTS_THM; LEFT_AND_EXISTS_THM] THEN
+    CONV_TAC(ONCE_DEPTH_CONV UNWIND_CONV) THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    REWRITE_TAC[IN_INTERVAL_1; GSYM EXISTS_DROP; DROP_VEC] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+  ASM_SIMP_TAC[COMPACT_PCROSS; GSYM PCROSS; COMPACT_INTERVAL] THEN
+  MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN
+  X_GEN_TAC `z:real^(1,(N,N)finite_sum)finite_sum` THEN
+  DISCH_THEN(K ALL_TAC) THEN REWRITE_TAC[PCROSS] THEN
+  MATCH_MP_TAC CONTINUOUS_ADD THEN CONJ_TAC THEN
+  MATCH_MP_TAC CONTINUOUS_MUL THEN REWRITE_TAC[o_DEF; LIFT_SUB; LIFT_DROP] THEN
+  CONJ_TAC THEN TRY(MATCH_MP_TAC CONTINUOUS_SUB) THEN
+  REWRITE_TAC[CONTINUOUS_CONST] THEN
+  MATCH_MP_TAC LINEAR_CONTINUOUS_AT THEN
+  REWRITE_TAC[LINEAR_FSTCART; LINEAR_SNDCART; ETA_AX] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC LINEAR_COMPOSE THEN
+  REWRITE_TAC[LINEAR_FSTCART; LINEAR_SNDCART]);;
+
+let COMPACT_CONVEX_HULL = prove
+ (`!s:real^N->bool. compact s ==> compact(convex hull s)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[CARATHEODORY] THEN
+  SPEC_TAC(`dimindex(:N) + 1`,`n:num`) THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[SUBSET_EMPTY] THEN
+    CONV_TAC(ONCE_DEPTH_CONV UNWIND_CONV) THEN
+    REWRITE_TAC[CONVEX_HULL_EMPTY; NOT_IN_EMPTY] THEN
+    REWRITE_TAC[SET_RULE `{x | F} = {}`; COMPACT_EMPTY];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `w:real^N`) THEN INDUCT_TAC THENL
+   [SUBGOAL_THEN
+     `{x:real^N | ?t. FINITE t /\ t SUBSET s /\ CARD t <= 0 /\
+                      x IN convex hull t} = {}`
+     (fun th -> REWRITE_TAC[th; COMPACT_EMPTY]) THEN
+    REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; LE; IN_ELIM_THM] THEN
+    MESON_TAC[CARD_EQ_0; CONVEX_HULL_EMPTY; NOT_IN_EMPTY];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `n = 0` THENL
+   [ASM_REWRITE_TAC[ARITH_RULE `s <= SUC 0 <=> s = 0 \/ s = 1`] THEN
+    UNDISCH_TAC `compact(s:real^N->bool)` THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+    REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+    REWRITE_TAC[TAUT `a /\ b /\ (c \/ d) /\ e <=>
+                      (a /\ c) /\ (b /\ e) \/ (a /\ d) /\ (b /\ e)`] THEN
+    REWRITE_TAC[GSYM HAS_SIZE; num_CONV `1`; HAS_SIZE_CLAUSES] THEN
+    REWRITE_TAC[EXISTS_OR_THM; LEFT_AND_EXISTS_THM; RIGHT_AND_EXISTS_THM] THEN
+    CONV_TAC(TOP_DEPTH_CONV UNWIND_CONV) THEN
+    REWRITE_TAC[NOT_IN_EMPTY; CONVEX_HULL_EMPTY] THEN
+    REWRITE_TAC[CONVEX_HULL_SING] THEN SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `{x:real^N | ?t. FINITE t /\ t SUBSET s /\ CARD t <= SUC n /\
+                    x IN convex hull t} =
+    { (&1 - u) % x + u % y :real^N |
+                      &0 <= u /\ u <= &1 /\ x IN s /\
+                      y IN {x | ?t. FINITE t /\ t SUBSET s /\
+                                    CARD t <= n /\ x IN convex hull t}}`
+   (fun th -> ASM_SIMP_TAC[th; COMPACT_CONVEX_COMBINATIONS]) THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN EQ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM; RIGHT_AND_EXISTS_THM;
+                LEFT_AND_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N`; `c:real`; `v:real^N`;
+                         `t:real^N->bool`] THEN
+    STRIP_TAC THEN EXISTS_TAC `(u:real^N) INSERT t` THEN
+    ASM_REWRITE_TAC[FINITE_INSERT; INSERT_SUBSET] THEN
+    ASM_SIMP_TAC[CARD_CLAUSES] THEN CONJ_TAC THENL
+     [ASM_ARITH_TAC; ALL_TAC] THEN
+    MATCH_MP_TAC IN_CONVEX_SET THEN
+    ASM_REWRITE_TAC[CONVEX_CONVEX_HULL] THEN CONJ_TAC THEN
+    ASM_MESON_TAC[HULL_SUBSET; SUBSET; IN_INSERT; HULL_MONO]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+  ASM_CASES_TAC `CARD(t:real^N->bool) <= n` THENL
+   [MAP_EVERY EXISTS_TAC [`w:real^N`; `&1`; `x:real^N`] THEN
+    ASM_REWRITE_TAC[REAL_POS; REAL_LE_REFL] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[]; VECTOR_ARITH_TAC];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(t:real^N->bool) HAS_SIZE (SUC n)` MP_TAC THENL
+   [ASM_REWRITE_TAC[HAS_SIZE] THEN ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[HAS_SIZE_CLAUSES] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` (X_CHOOSE_THEN `u:real^N->bool`
+    STRIP_ASSUME_TAC)) THEN
+  FIRST_X_ASSUM SUBST_ALL_TAC THEN
+  UNDISCH_TAC `(x:real^N) IN convex hull (a INSERT u)` THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[FINITE_INSERT]) THEN
+  ASM_CASES_TAC `(u:real^N->bool) = {}` THENL
+   [ASM_REWRITE_TAC[CONVEX_HULL_SING; IN_SING] THEN
+    DISCH_THEN SUBST_ALL_TAC THEN
+    MAP_EVERY EXISTS_TAC [`a:real^N`; `&1`; `a:real^N`] THEN
+    ASM_REWRITE_TAC[REAL_POS; REAL_LE_REFL] THEN
+    CONJ_TAC THENL [ALL_TAC; VECTOR_ARITH_TAC] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    EXISTS_TAC `{a:real^N}` THEN SIMP_TAC[FINITE_RULES] THEN
+    REWRITE_TAC[CONVEX_HULL_SING; IN_SING] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    SIMP_TAC[CARD_CLAUSES; FINITE_RULES; NOT_IN_EMPTY] THEN
+    UNDISCH_TAC `~(n = 0)` THEN ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[CONVEX_HULL_INSERT; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`c:real`; `d:real`; `z:real^N`] THEN STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`a:real^N`; `d:real`; `z:real^N`] THEN
+  FIRST_X_ASSUM(SUBST_ALL_TAC o MATCH_MP (REAL_ARITH
+   `c + d = &1 ==> c = (&1 - d)`)) THEN
+  ASM_REWRITE_TAC[REAL_ARITH `d <= &1 <=> &0 <= &1 - d`] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  EXISTS_TAC `u:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  UNDISCH_TAC `CARD ((a:real^N) INSERT u) <= SUC n` THEN
+  ASM_SIMP_TAC[CARD_CLAUSES; LE_SUC]);;
+
+let FINITE_IMP_COMPACT_CONVEX_HULL = prove
+ (`!s:real^N->bool. FINITE s ==> compact(convex hull s)`,
+  SIMP_TAC[FINITE_IMP_COMPACT; COMPACT_CONVEX_HULL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Extremal points of a simplex are some vertices.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let DIST_INCREASES_ONLINE = prove
+ (`!a b d. ~(d = vec 0)
+           ==> dist(a,b + d) > dist(a,b) \/ dist(a,b - d) > dist(a,b)`,
+  REWRITE_TAC[dist; vector_norm; real_gt; GSYM NORM_POS_LT] THEN
+  SIMP_TAC[SQRT_MONO_LT_EQ; DOT_POS_LE; SQRT_LT_0] THEN
+  REWRITE_TAC[DOT_RSUB; DOT_RADD; DOT_LSUB; DOT_LADD] THEN REAL_ARITH_TAC);;
+
+let NORM_INCREASES_ONLINE = prove
+ (`!a:real^N d. ~(d = vec 0)
+                ==> norm(a + d) > norm(a) \/ norm(a - d) > norm(a)`,
+  MP_TAC(ISPEC `vec 0 :real^N` DIST_INCREASES_ONLINE) THEN
+  REWRITE_TAC[dist; VECTOR_SUB_LZERO; NORM_NEG]);;
+
+let SIMPLEX_FURTHEST_LT = prove
+ (`!a:real^N s.
+        FINITE s
+        ==> !x. x IN (convex hull s) /\ ~(x IN s)
+                ==> ?y. y IN (convex hull s) /\ norm(x - a) < norm(y - a)`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[CONVEX_HULL_EMPTY; NOT_IN_EMPTY] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `s:real^N->bool`] THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[CONVEX_HULL_SING; IN_SING] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[CONVEX_HULL_INSERT] THEN
+  STRIP_TAC THEN X_GEN_TAC `y:real^N` THEN
+  REWRITE_TAC[IN_ELIM_THM; LEFT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`u:real`; `v:real`; `b:real^N`] THEN
+  ASM_CASES_TAC `y:real^N IN (convex hull s)` THENL
+   [REWRITE_TAC[IN_INSERT; DE_MORGAN_THM] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `y:real^N`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `c:real^N` THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`&0`; `&1`; `c:real^N`] THEN
+    ASM_REWRITE_TAC[REAL_ADD_LID; REAL_POS] THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_CASES_TAC `u = &0` THENL
+   [ASM_SIMP_TAC[REAL_ADD_LID; VECTOR_MUL_LZERO; VECTOR_ADD_LID] THEN
+    ASM_MESON_TAC[VECTOR_MUL_LID];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `v = &0` THENL
+   [ASM_SIMP_TAC[REAL_ADD_RID; VECTOR_MUL_LZERO; VECTOR_ADD_RID] THEN
+    ASM_CASES_TAC `u = &1` THEN ASM_REWRITE_TAC[VECTOR_MUL_LID] THEN
+    ASM_CASES_TAC `y = a:real^N` THEN ASM_REWRITE_TAC[IN_INSERT] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[IN_INSERT; DE_MORGAN_THM] THEN STRIP_TAC THEN
+  MP_TAC(SPECL [`u:real`; `v:real`] REAL_DOWN2) THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[REAL_LT_LE]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `w:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`a:real^N`; `y:real^N`; `w % (x - b):real^N`]
+                DIST_INCREASES_ONLINE) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ] THEN
+    REWRITE_TAC[VECTOR_ARITH `(x - y = vec 0) <=> (x = y)`] THEN
+    DISCH_THEN SUBST_ALL_TAC THEN
+    UNDISCH_TAC `~(y:real^N IN convex hull s)` THEN
+    ASM_REWRITE_TAC[GSYM VECTOR_ADD_RDISTRIB; VECTOR_MUL_LID];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[dist; real_gt] THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `((u % x + v % b) + w % (x - b) = (u + w) % x + (v - w) % b) /\
+    ((u % x + v % b) - w % (x - b) = (u - w) % x + (v + w) % b)`] THEN
+  STRIP_TAC THENL
+   [MAP_EVERY EXISTS_TAC
+     [`(u + w) % x + (v - w) % b:real^N`; `u + w`; `v - w`; `b:real^N`];
+    MAP_EVERY EXISTS_TAC
+     [`(u - w) % x + (v + w) % b:real^N`; `u - w`; `v + w`; `b:real^N`]] THEN
+  ONCE_REWRITE_TAC[NORM_SUB] THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[REAL_LE_ADD; REAL_LT_IMP_LE; REAL_SUB_LE] THEN
+  UNDISCH_TAC `u + v = &1` THEN REAL_ARITH_TAC);;
+
+let SIMPLEX_FURTHEST_LE = prove
+ (`!a:real^N s.
+        FINITE s /\ ~(s = {})
+        ==> ?y. y IN s /\
+                !x. x IN (convex hull s) ==> norm(x - a) <= norm(y - a)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  MP_TAC(ISPEC `convex hull (s:real^N->bool)` DISTANCE_ATTAINS_SUP) THEN
+  DISCH_THEN(MP_TAC o SPEC `a:real^N`) THEN ANTS_TAC THENL
+   [ASM_SIMP_TAC[FINITE_IMP_COMPACT_CONVEX_HULL] THEN
+    ASM_MESON_TAC[SUBSET_EMPTY; HULL_SUBSET];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[DIST_SYM] THEN REWRITE_TAC[dist] THEN
+  ASM_MESON_TAC[SIMPLEX_FURTHEST_LT; REAL_NOT_LE]);;
+
+let SIMPLEX_FURTHEST_LE_EXISTS = prove
+ (`!a:real^N s.
+        FINITE s
+        ==> !x. x IN (convex hull s)
+                ==> ?y. y IN s /\ norm(x - a) <= norm(y - a)`,
+  MESON_TAC[NOT_IN_EMPTY; CONVEX_HULL_EMPTY; SIMPLEX_FURTHEST_LE]);;
+
+let SIMPLEX_EXTREMAL_LE = prove
+ (`!s:real^N->bool.
+        FINITE s /\ ~(s = {})
+         ==> ?u v. u IN s /\ v IN s /\
+                   !x y. x IN convex hull s /\ y IN convex hull s
+                         ==> norm(x - y) <= norm(u - v)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `convex hull (s:real^N->bool)` COMPACT_SUP_MAXDISTANCE) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[FINITE_IMP_COMPACT_CONVEX_HULL] THEN
+    ASM_MESON_TAC[SUBSET_EMPTY; HULL_SUBSET];
+    ALL_TAC] THEN
+  REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+  SIMP_TAC[] THEN ASM_MESON_TAC[SIMPLEX_FURTHEST_LT; REAL_NOT_LE; NORM_SUB]);;
+
+let SIMPLEX_EXTREMAL_LE_EXISTS = prove
+ (`!s:real^N->bool x y. FINITE s /\ x IN convex hull s /\ y IN convex hull s
+                        ==> ?u v. u IN s /\ v IN s /\
+                                  norm(x - y) <= norm(u - v)`,
+  MESON_TAC[NOT_IN_EMPTY; CONVEX_HULL_EMPTY; SIMPLEX_EXTREMAL_LE]);;
+
+let DIAMETER_CONVEX_HULL = prove
+ (`!s:real^N->bool. diameter(convex hull s) = diameter s`,
+  let lemma = prove
+   (`!a b s. (!x. x IN s ==> dist(a,x) <= b)
+             ==> (!x. x IN convex hull s ==> dist(a,x) <= b)`,
+    REPEAT GEN_TAC THEN DISCH_TAC THEN
+    MATCH_MP_TAC HULL_INDUCT THEN ASM_REWRITE_TAC[GSYM cball; CONVEX_CBALL]) in
+  GEN_TAC THEN REWRITE_TAC[diameter; CONVEX_HULL_EQ_EMPTY] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC SUP_EQ THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN X_GEN_TAC `b:real` THEN
+  EQ_TAC THENL [MESON_TAC[SUBSET; HULL_SUBSET]; ALL_TAC] THEN
+  MATCH_MP_TAC(TAUT `!b. (a ==> b) /\ (b ==> c) ==> a ==> c`) THEN
+  EXISTS_TAC `!x:real^N y. x IN s /\ y IN convex hull s ==> norm(x - y) <= b`
+  THEN CONJ_TAC THENL
+   [MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:real^N` THEN
+    ASM_CASES_TAC `(x:real^N) IN s` THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[GSYM dist; lemma];
+    ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `y:real^N` THEN
+    ASM_CASES_TAC `(y:real^N) IN convex hull s` THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[GSYM(ONCE_REWRITE_RULE[DIST_SYM] dist); lemma]]);;
+
+let DIAMETER_SIMPLEX = prove
+ (`!s:real^N->bool.
+        ~(s = {})
+        ==> diameter(convex hull s) = sup { dist(x,y) | x IN s /\ y IN s}`,
+  REWRITE_TAC[DIAMETER_CONVEX_HULL] THEN SIMP_TAC[diameter; dist]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Closest point of a convex set is unique, with a continuous projection.    *)
+(* ------------------------------------------------------------------------- *)
+
+let CLOSER_POINTS_LEMMA = prove
+ (`!y:real^N z.
+        y dot z > &0
+        ==> ?u. &0 < u /\
+                !v. &0 < v /\ v <= u ==> norm(v % z - y) < norm y`,
+  REWRITE_TAC[NORM_LT; DOT_LSUB; DOT_RSUB; DOT_LMUL; DOT_RMUL;
+              REAL_SUB_LDISTRIB; real_gt] THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[REAL_ARITH `(a - b) - (c - d) < d <=> a < b + c`] THEN
+  STRIP_TAC THEN SUBST1_TAC(VECTOR_ARITH `(z:real^N) dot y = y dot z`) THEN
+  SIMP_TAC[GSYM REAL_ADD_LDISTRIB; REAL_LT_LMUL_EQ] THEN
+  EXISTS_TAC `(y dot (z:real^N)) / (z dot z)` THEN
+  SUBGOAL_THEN `&0 < z dot (z:real^N)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[DOT_POS_LT; DOT_RZERO; REAL_LT_REFL]; ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_LE_RDIV_EQ] THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 < y /\ x <= y ==> x < y + y`; REAL_LT_MUL]);;
+
+let CLOSER_POINT_LEMMA = prove
+ (`!x y z. (y - x) dot (z - x) > &0
+           ==> ?u. &0 < u /\ u <= &1 /\ dist(x + u % (z - x),y) < dist(x,y)`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP CLOSER_POINTS_LEMMA) THEN
+  ONCE_REWRITE_TAC[DIST_SYM] THEN REWRITE_TAC[dist; NORM_LT] THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `(y - (x + z)) dot (y - (x + z)) = (z - (y - x)) dot (z - (y - x))`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `min u (&1)` THEN
+  ASM_SIMP_TAC[REAL_LT_MIN; REAL_MIN_LE; REAL_LT_01; REAL_LE_REFL]);;
+
+let ANY_CLOSEST_POINT_DOT = prove
+ (`!s a x y:real^N.
+        convex s /\ closed s /\ x IN s /\ y IN s /\
+        (!z. z IN s ==> dist(a,x) <= dist(a,z))
+        ==> (a - x) dot (y - x) <= &0`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_ARITH `x <= &0 <=> ~(x > &0)`] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CLOSER_POINT_LEMMA) THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[REAL_NOT_LT] THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[VECTOR_ARITH `x + u % (y - x) = (&1 - u) % x + u % y`] THEN
+  MATCH_MP_TAC IN_CONVEX_SET THEN ASM_SIMP_TAC[REAL_LT_IMP_LE]);;
+
+let ANY_CLOSEST_POINT_UNIQUE = prove
+ (`!s a x y:real^N.
+        convex s /\ closed s /\ x IN s /\ y IN s /\
+        (!z. z IN s ==> dist(a,x) <= dist(a,z)) /\
+        (!z. z IN s ==> dist(a,y) <= dist(a,z))
+        ==> x = y`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+  REWRITE_TAC[GSYM NORM_LE_0; NORM_LE_SQUARE] THEN
+  SUBGOAL_THEN `(a - x:real^N) dot (y - x) <= &0 /\ (a - y) dot (x - y) <= &0`
+  MP_TAC THENL [ASM_MESON_TAC[ANY_CLOSEST_POINT_DOT]; ALL_TAC] THEN
+  REWRITE_TAC[NORM_LT; DOT_LSUB; DOT_RSUB] THEN REAL_ARITH_TAC);;
+
+let CLOSEST_POINT_UNIQUE = prove
+ (`!s a x:real^N.
+        convex s /\ closed s /\ x IN s /\
+        (!z. z IN s ==> dist(a,x) <= dist(a,z))
+        ==> x = closest_point s a`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ANY_CLOSEST_POINT_UNIQUE THEN
+  MAP_EVERY EXISTS_TAC [`s:real^N->bool`; `a:real^N`] THEN
+  ASM_MESON_TAC[CLOSEST_POINT_EXISTS; MEMBER_NOT_EMPTY]);;
+
+let CLOSEST_POINT_DOT = prove
+ (`!s a x:real^N.
+        convex s /\ closed s /\ x IN s
+        ==> (a - closest_point s a) dot (x - closest_point s a) <= &0`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ANY_CLOSEST_POINT_DOT THEN
+  EXISTS_TAC `s:real^N->bool` THEN
+  ASM_MESON_TAC[CLOSEST_POINT_EXISTS; MEMBER_NOT_EMPTY]);;
+
+let CLOSEST_POINT_LT = prove
+ (`!s a x. convex s /\ closed s /\ x IN s /\ ~(x = closest_point s a)
+           ==> dist(a,closest_point s a) < dist(a,x)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[GSYM REAL_NOT_LE; CONTRAPOS_THM] THEN
+  DISCH_TAC THEN MATCH_MP_TAC CLOSEST_POINT_UNIQUE THEN
+  ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[CLOSEST_POINT_LE; REAL_LE_TRANS]);;
+
+let CLOSEST_POINT_LIPSCHITZ = prove
+ (`!s x y:real^N.
+        convex s /\ closed s /\ ~(s = {})
+        ==> dist(closest_point s x,closest_point s y) <= dist(x,y)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[dist; NORM_LE] THEN
+  SUBGOAL_THEN
+   `(x - closest_point s x :real^N) dot
+    (closest_point s y - closest_point s x) <= &0 /\
+    (y - closest_point s y) dot
+    (closest_point s x - closest_point s y) <= &0`
+  MP_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC ANY_CLOSEST_POINT_DOT THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_MESON_TAC[CLOSEST_POINT_EXISTS];
+    MP_TAC(ISPEC `(x - closest_point s x :real^N) - (y - closest_point s y)`
+                 DOT_POS_LE) THEN
+    REWRITE_TAC[NORM_LT; DOT_LSUB; DOT_RSUB; DOT_SYM] THEN REAL_ARITH_TAC]);;
+
+let CONTINUOUS_AT_CLOSEST_POINT = prove
+ (`!s x. convex s /\ closed s /\ ~(s = {})
+         ==> (closest_point s) continuous (at x)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[continuous_at] THEN
+  ASM_MESON_TAC[CLOSEST_POINT_LIPSCHITZ; REAL_LET_TRANS]);;
+
+let CONTINUOUS_ON_CLOSEST_POINT = prove
+ (`!s t. convex s /\ closed s /\ ~(s = {})
+         ==> (closest_point s) continuous_on t`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON; CONTINUOUS_AT_CLOSEST_POINT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relating closest points and orthogonality.                                *)
+(* ------------------------------------------------------------------------- *)
+
+let ANY_CLOSEST_POINT_AFFINE_ORTHOGONAL = prove
+ (`!s a b:real^N.
+        affine s /\ b IN s /\ (!x. x IN s ==> dist(a,b) <= dist(a,x))
+        ==> (!x. x IN s ==> orthogonal (x - b) (a - b))`,
+  REPEAT GEN_TAC THEN GEOM_ORIGIN_TAC `b:real^N` THEN
+  REWRITE_TAC[DIST_0; VECTOR_SUB_RZERO; orthogonal; dist; NORM_LE] THEN
+  REWRITE_TAC[DOT_LSUB] THEN REWRITE_TAC[DOT_RSUB] THEN
+  REWRITE_TAC[DOT_SYM; REAL_ARITH `a <= a - y - (y - x) <=> &2 * y <= x`] THEN
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `x:real^N = vec 0` THEN
+  ASM_REWRITE_TAC[DOT_RZERO] THEN FIRST_X_ASSUM(fun th ->
+   MP_TAC(SPEC `vec 0 + --((a dot x) / (x dot x)) % (x - vec 0:real^N)` th) THEN
+   MP_TAC(SPEC `vec 0 + (a dot x) / (x dot x) % (x - vec 0:real^N)` th)) THEN
+  ASM_SIMP_TAC[IN_AFFINE_ADD_MUL_DIFF] THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; VECTOR_ADD_LID; DOT_RMUL] THEN
+  REWRITE_TAC[DOT_LMUL; IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+   `&2 * x * a <= b * c * z /\ &2 * --x * a <= --b * --c * z
+    ==> &2 * abs(x * a) <= b * c * z`)) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[REAL_NOT_LE; REAL_DIV_RMUL; DOT_EQ_0] THEN
+  MATCH_MP_TAC(REAL_ARITH `~(x = &0) ==> x < &2 * abs x`) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM DOT_EQ_0]) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD);;
+
+let ORTHOGONAL_ANY_CLOSEST_POINT = prove
+ (`!s a b:real^N.
+        b IN s /\ (!x. x IN s ==> orthogonal (x - b) (a - b))
+        ==> (!x. x IN s ==> dist(a,b) <= dist(a,x))`,
+  REPEAT GEN_TAC THEN GEOM_ORIGIN_TAC `b:real^N` THEN
+  REWRITE_TAC[dist; NORM_LE; orthogonal; VECTOR_SUB_RZERO] THEN
+  SIMP_TAC[DOT_LSUB; DOT_RSUB; DOT_SYM] THEN
+  REWRITE_TAC[DOT_POS_LE; REAL_ARITH `a <= a - &0 - (&0 - x) <=> &0 <= x`]);;
+
+let CLOSEST_POINT_AFFINE_ORTHOGONAL = prove
+ (`!s a:real^N x.
+        affine s /\ ~(s = {}) /\ x IN s
+        ==> orthogonal (x - closest_point s a) (a - closest_point s a)`,
+  GEN_TAC THEN REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  DISCH_TAC THEN DISCH_TAC THEN GEN_TAC THEN
+  MATCH_MP_TAC ANY_CLOSEST_POINT_AFFINE_ORTHOGONAL THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CLOSEST_POINT_EXISTS THEN
+  ASM_SIMP_TAC[CLOSED_AFFINE]);;
+
+let CLOSEST_POINT_AFFINE_ORTHOGONAL_EQ = prove
+ (`!s a b:real^N.
+        affine s /\ b IN s
+        ==> (closest_point s a = b <=>
+             !x. x IN s ==> orthogonal (x - b) (a - b))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ASM_MESON_TAC[CLOSEST_POINT_AFFINE_ORTHOGONAL; MEMBER_NOT_EMPTY];
+    DISCH_TAC THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC CLOSEST_POINT_UNIQUE THEN
+    ASM_SIMP_TAC[CLOSED_AFFINE; AFFINE_IMP_CONVEX] THEN
+    MATCH_MP_TAC ORTHOGONAL_ANY_CLOSEST_POINT THEN ASM_REWRITE_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Various point-to-set separating/supporting hyperplane theorems.           *)
+(* ------------------------------------------------------------------------- *)
+
+let SUPPORTING_HYPERPLANE_COMPACT_POINT_SUP = prove
+ (`!a c s:real^N->bool.
+        compact s /\ ~(s = {})
+        ==> ?b y. y IN s /\ a dot (y - c) = b /\
+                  (!x. x IN s ==> a dot (x - c) <= b)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\x:real^N. a dot (x - c)`; `s:real^N->bool`]
+        CONTINUOUS_ATTAINS_SUP) THEN
+  ASM_REWRITE_TAC[] THEN
+  ANTS_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+  SUBGOAL_THEN `(\x:real^N. a dot (x - c)) = (\x. a dot x) o (\x. x - c)`
+  SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+  REWRITE_TAC[o_ASSOC] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  SIMP_TAC[CONTINUOUS_ON_LIFT_DOT; CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST;
+           CONTINUOUS_ON_ID]);;
+
+let SUPPORTING_HYPERPLANE_COMPACT_POINT_INF = prove
+ (`!a c s:real^N->bool.
+        compact s /\ ~(s = {})
+        ==> ?b y. y IN s /\ a dot (y - c) = b /\
+                  (!x. x IN s ==> a dot (x - c) >= b)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`--a:real^N`; `c:real^N`; `s:real^N->bool`]
+    SUPPORTING_HYPERPLANE_COMPACT_POINT_SUP) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real`
+   (fun th -> EXISTS_TAC `--b:real` THEN MP_TAC th)) THEN
+  REWRITE_TAC[DOT_LNEG; REAL_ARITH `x >= -- b <=> --x <= b`] THEN
+  REWRITE_TAC[REAL_NEG_EQ]);;
+
+let SUPPORTING_HYPERPLANE_CLOSED_POINT = prove
+ (`!s z:real^N. convex s /\ closed s /\ ~(s = {}) /\ ~(z IN s)
+                ==> ?a b y. a dot z < b /\ y IN s /\ (a dot y = b) /\
+                            (!x. x IN s ==> a dot x >= b)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `z:real^N`] DISTANCE_ATTAINS_INF) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `y - z:real^N` THEN EXISTS_TAC `(y - z:real^N) dot y` THEN
+  EXISTS_TAC `y:real^N` THEN ONCE_REWRITE_TAC[GSYM REAL_SUB_LT] THEN
+  ASM_REWRITE_TAC[GSYM DOT_RSUB; DOT_POS_LT; VECTOR_SUB_EQ] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN X_GEN_TAC `x:real^N` THEN
+  DISCH_TAC THEN SUBGOAL_THEN
+   `!u. &0 <= u /\ u <= &1 ==> dist(z:real^N,y) <= dist(z,(&1 - u) % y + u % x)`
+  MP_TAC THENL [ASM_MESON_TAC[CONVEX_ALT]; ALL_TAC] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+  REWRITE_TAC[real_ge; REAL_NOT_LE; NOT_FORALL_THM; NOT_IMP] THEN
+  GEN_REWRITE_TAC LAND_CONV [REAL_ARITH `x < y <=> y - x > &0`] THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `(a - b) dot x - (a - b) dot y = (b - a) dot (y - x)`] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CLOSER_POINT_LEMMA) THEN
+  REWRITE_TAC[VECTOR_ARITH `y + u % (x - y) = (&1 - u) % y + u % x`] THEN
+  MESON_TAC[REAL_LT_IMP_LE]);;
+
+let SEPARATING_HYPERPLANE_CLOSED_POINT_INSET = prove
+ (`!s z:real^N. convex s /\ closed s /\ ~(s = {}) /\ ~(z IN s)
+                ==> ?a b. a IN s /\
+                          (a - z) dot z < b /\
+                          (!x. x IN s ==> (a - z) dot x > b)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `z:real^N`] DISTANCE_ATTAINS_INF) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `y:real^N` THEN ASM_REWRITE_TAC[] THEN
+  EXISTS_TAC `(y - z:real^N) dot z + norm(y - z) pow 2 / &2` THEN
+  SUBGOAL_THEN `&0 < norm(y - z:real^N)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[NORM_POS_LT; VECTOR_SUB_EQ]; ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_LT_ADDR; REAL_LT_DIV; REAL_POW_LT;
+               REAL_OF_NUM_LT; ARITH] THEN
+  REWRITE_TAC[NORM_POW_2; REAL_ARITH `a > b + c <=> c < a - b`] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  SIMP_TAC[REAL_LT_LDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN
+  ONCE_REWRITE_TAC[GSYM REAL_SUB_LT] THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `((y - z) dot x - (y - z) dot z) * &2 - (y - z) dot (y - z) =
+    &2 * ((y - z) dot (x - y)) + (y - z) dot (y - z)`] THEN
+  MATCH_MP_TAC(REAL_ARITH `~(--x > &0) /\ &0 < y ==> &0 < &2 * x + y`) THEN
+  ASM_SIMP_TAC[GSYM NORM_POW_2; REAL_POW_LT] THEN
+  REWRITE_TAC[GSYM DOT_LNEG; VECTOR_NEG_SUB] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CLOSER_POINT_LEMMA) THEN
+  REWRITE_TAC[NOT_EXISTS_THM] THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+  GEN_TAC THEN REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[REAL_NOT_LT] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[VECTOR_ARITH `y + u % (x - y) = (&1 - u) % y + u % x`] THEN
+  ASM_MESON_TAC[CONVEX_ALT; REAL_LT_IMP_LE]);;
+
+let SEPARATING_HYPERPLANE_CLOSED_0_INSET = prove
+ (`!s:real^N->bool.
+        convex s /\ closed s /\ ~(s = {}) /\ ~(vec 0 IN s)
+        ==> ?a b. a IN s /\ ~(a = vec 0) /\ &0 < b /\
+                  (!x. x IN s ==> a dot x > b)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP SEPARATING_HYPERPLANE_CLOSED_POINT_INSET) THEN
+  REWRITE_TAC[DOT_RZERO; real_gt] THEN
+  REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+  SIMP_TAC[VECTOR_SUB_RZERO] THEN ASM_MESON_TAC[]);;
+
+let SEPARATING_HYPERPLANE_CLOSED_POINT = prove
+ (`!s z:real^N. convex s /\ closed s /\ ~(z IN s)
+                ==> ?a b. a dot z < b /\ (!x. x IN s ==> a dot x > b)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [MAP_EVERY EXISTS_TAC [`--z:real^N`; `&1`] THEN
+    SIMP_TAC[DOT_LNEG; REAL_ARITH `&0 <= x ==> --x < &1`; DOT_POS_LE] THEN
+    ASM_MESON_TAC[NOT_IN_EMPTY];
+    ALL_TAC] THEN
+  ASM_MESON_TAC[SEPARATING_HYPERPLANE_CLOSED_POINT_INSET]);;
+
+let SEPARATING_HYPERPLANE_CLOSED_0 = prove
+ (`!s:real^N->bool.
+        convex s /\ closed s /\ ~(vec 0 IN s)
+        ==> ?a b. ~(a = vec 0) /\ &0 < b /\ (!x. x IN s ==> a dot x > b)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [EXISTS_TAC `basis 1:real^N` THEN EXISTS_TAC `&1` THEN
+    ASM_REWRITE_TAC[NOT_IN_EMPTY; REAL_LT_01; GSYM NORM_POS_LT] THEN
+    ASM_SIMP_TAC[NORM_BASIS; DIMINDEX_GE_1; LE_REFL; REAL_LT_01];
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP SEPARATING_HYPERPLANE_CLOSED_POINT) THEN
+    REWRITE_TAC[DOT_RZERO; real_gt] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    ASM_MESON_TAC[MEMBER_NOT_EMPTY; DOT_LZERO; REAL_LT_ANTISYM]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Now set-to-set for closed/compact sets.                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let SEPARATING_HYPERPLANE_CLOSED_COMPACT = prove
+ (`!s t. convex s /\ closed s /\
+         convex t /\ compact t /\ ~(t = {}) /\ DISJOINT s t
+         ==> ?a:real^N b. (!x. x IN s ==> a dot x < b) /\
+                          (!x. x IN t ==> a dot x > b)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_IMP_BOUNDED) THEN
+    REWRITE_TAC[BOUNDED_POS] THEN
+    DISCH_THEN(X_CHOOSE_THEN `b:real` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `?z:real^N. norm(z) = b + &1` CHOOSE_TAC THENL
+     [ASM_SIMP_TAC[VECTOR_CHOOSE_SIZE; REAL_ARITH `&0 < b ==> &0 <= b + &1`];
+      ALL_TAC] THEN
+    MP_TAC(SPECL [`t:real^N->bool`; `z:real^N`]
+       SEPARATING_HYPERPLANE_CLOSED_POINT) THEN
+    ANTS_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+    ASM_SIMP_TAC[COMPACT_IMP_CLOSED] THEN
+    ASM_MESON_TAC[REAL_ARITH `~(b + &1 <= b)`];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`{x - y:real^N | x IN s /\ y IN t}`; `vec 0 :real^N`]
+                SEPARATING_HYPERPLANE_CLOSED_POINT) THEN
+  ASM_SIMP_TAC[CLOSED_COMPACT_DIFFERENCES; CONVEX_DIFFERENCES] THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[IN_ELIM_THM] THEN ONCE_REWRITE_TAC[EQ_SYM_EQ] THEN
+    REWRITE_TAC[VECTOR_SUB_EQ] THEN
+    ASM_MESON_TAC[DISJOINT; NOT_IN_EMPTY; IN_INTER; EXTENSION];
+    ALL_TAC] THEN
+  SIMP_TAC[DOT_RZERO; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  GEN_REWRITE_TAC LAND_CONV [SWAP_FORALL_THM] THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [SWAP_FORALL_THM] THEN
+  ONCE_REWRITE_TAC[IMP_CONJ] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[LEFT_FORALL_IMP_THM; EXISTS_REFL; DOT_RSUB] THEN
+  REWRITE_TAC[real_gt; REAL_LT_SUB_LADD] THEN DISCH_TAC THEN
+  EXISTS_TAC `--a:real^N` THEN
+  MP_TAC(SPEC `IMAGE (\x:real^N. a dot x) t` SUP) THEN
+  ABBREV_TAC `k = sup (IMAGE (\x:real^N. a dot x) t)` THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; IMAGE_EQ_EMPTY] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[REAL_ARITH `b + x < y ==> x <= y - b`; MEMBER_NOT_EMPTY];
+    ALL_TAC] THEN
+  STRIP_TAC THEN EXISTS_TAC `--(k + b / &2)` THEN
+  REWRITE_TAC[DOT_LNEG; REAL_LT_NEG2] THEN REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH;
+               REAL_ARITH `&0 < b /\ x <= k ==> x < k + b`] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `k - b / &2`) THEN
+  ASM_SIMP_TAC[REAL_ARITH `k <= k - b2 <=> ~(&0 < b2)`; REAL_LT_DIV;
+     REAL_OF_NUM_LT; ARITH; NOT_FORALL_THM; LEFT_IMP_EXISTS_THM; NOT_IMP] THEN
+  X_GEN_TAC `y:real^N` THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `!b. (b2 + b2 = b) /\ b + ay < ax ==> ~(ay <= k - b2) ==> k + b2 < ax`) THEN
+  ASM_MESON_TAC[REAL_HALF]);;
+
+let SEPARATING_HYPERPLANE_COMPACT_CLOSED = prove
+ (`!s t. convex s /\ compact s /\ ~(s = {}) /\
+         convex t /\ closed t /\ DISJOINT s t
+         ==> ?a:real^N b. (!x. x IN s ==> a dot x < b) /\
+                          (!x. x IN t ==> a dot x > b)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`t:real^N->bool`; `s:real^N->bool`]
+      SEPARATING_HYPERPLANE_CLOSED_COMPACT) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[DISJOINT_SYM]; ALL_TAC] THEN
+  REWRITE_TAC[real_gt] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` (X_CHOOSE_THEN `b:real`
+    STRIP_ASSUME_TAC)) THEN
+  MAP_EVERY EXISTS_TAC [`--a:real^N`; `--b:real`] THEN
+  ASM_REWRITE_TAC[REAL_LT_NEG2; DOT_LNEG]);;
+
+let SEPARATING_HYPERPLANE_COMPACT_CLOSED_NONZERO = prove
+ (`!s t:real^N->bool.
+           convex s /\ compact s /\ ~(s = {}) /\
+           convex t /\ closed t /\ DISJOINT s t
+           ==> ?a b. ~(a = vec 0) /\
+                     (!x. x IN s ==> a dot x < b) /\
+                     (!x. x IN t ==> a dot x > b)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `t:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN STRIP_TAC THEN
+    EXISTS_TAC `basis 1:real^N` THEN
+    SUBGOAL_THEN
+     `bounded(IMAGE (\x:real^N. lift(basis 1 dot x)) s)`
+    MP_TAC THENL
+     [MATCH_MP_TAC COMPACT_IMP_BOUNDED THEN
+      MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+      ASM_SIMP_TAC[REWRITE_RULE[o_DEF] CONTINUOUS_ON_LIFT_DOT];
+      REWRITE_TAC[BOUNDED_POS_LT; FORALL_IN_IMAGE; NORM_LIFT] THEN
+      SIMP_TAC[BASIS_NONZERO; DIMINDEX_GE_1; LE_REFL] THEN
+      MESON_TAC[REAL_ARITH `abs x < b ==> x < b`]];
+    STRIP_TAC THEN
+    MP_TAC(ISPECL [`s:real^N->bool`; `t:real^N->bool`]
+        SEPARATING_HYPERPLANE_COMPACT_CLOSED) THEN
+    ASM_REWRITE_TAC[] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    ASM_CASES_TAC `a:real^N = vec 0` THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[DOT_LZERO; real_gt] THEN
+    ASM_MESON_TAC[REAL_LT_ANTISYM; MEMBER_NOT_EMPTY]]);;
+
+let SEPARATING_HYPERPLANE_COMPACT_COMPACT = prove
+ (`!s t:real^N->bool.
+           convex s /\ compact s /\ convex t /\ compact t /\ DISJOINT s t
+           ==> ?a b. ~(a = vec 0) /\
+                     (!x. x IN s ==> a dot x < b) /\
+                     (!x. x IN t ==> a dot x > b)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN STRIP_TAC THEN
+    EXISTS_TAC `--basis 1:real^N` THEN
+    SUBGOAL_THEN
+     `bounded(IMAGE (\x:real^N. lift(basis 1 dot x)) t)`
+    MP_TAC THENL
+     [MATCH_MP_TAC COMPACT_IMP_BOUNDED THEN
+      MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+      ASM_SIMP_TAC[REWRITE_RULE[o_DEF] CONTINUOUS_ON_LIFT_DOT];
+      REWRITE_TAC[BOUNDED_POS_LT; FORALL_IN_IMAGE; NORM_LIFT] THEN
+      SIMP_TAC[VECTOR_NEG_EQ_0; BASIS_NONZERO; DIMINDEX_GE_1; LE_REFL] THEN
+      DISCH_THEN(X_CHOOSE_THEN `b:real` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `--b:real` THEN REWRITE_TAC[DOT_LNEG] THEN
+      REWRITE_TAC[REAL_ARITH `--x > --y <=> x < y`] THEN
+      ASM_MESON_TAC[REAL_ARITH `abs x < b ==> x < b`]];
+    STRIP_TAC THEN
+    MATCH_MP_TAC SEPARATING_HYPERPLANE_COMPACT_CLOSED_NONZERO THEN
+    ASM_SIMP_TAC[COMPACT_IMP_CLOSED]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* General case without assuming closure and getting non-strict separation.  *)
+(* ------------------------------------------------------------------------- *)
+
+let SEPARATING_HYPERPLANE_SET_0_INSPAN = prove
+ (`!s:real^N->bool.
+        convex s /\ ~(s = {}) /\ ~(vec 0 IN s)
+        ==> ?a b. a IN span s /\ ~(a = vec 0) /\
+                  !x. x IN s ==> &0 <= a dot x`,
+  REPEAT STRIP_TAC THEN
+  ABBREV_TAC `k = \c:real^N. {x | &0 <= c dot x}` THEN
+  SUBGOAL_THEN
+   `~((span s INTER frontier(cball(vec 0:real^N,&1))) INTER
+      (INTERS (IMAGE k (s:real^N->bool))) = {})`
+  MP_TAC THENL
+   [ALL_TAC;
+    SIMP_TAC[EXTENSION; NOT_IN_EMPTY; IN_INTER; IN_INTERS; NOT_FORALL_THM;
+             FORALL_IN_IMAGE; FRONTIER_CBALL; REAL_LT_01] THEN
+    EXPAND_TAC "k" THEN REWRITE_TAC[IN_SPHERE_0; IN_ELIM_THM; NORM_NEG] THEN
+    MESON_TAC[NORM_EQ_0; REAL_ARITH `~(&1 = &0)`; DOT_SYM]] THEN
+  MATCH_MP_TAC COMPACT_IMP_FIP THEN
+  SIMP_TAC[COMPACT_CBALL; COMPACT_FRONTIER; FORALL_IN_IMAGE;
+           CLOSED_INTER_COMPACT; CLOSED_SPAN] THEN
+  CONJ_TAC THENL
+   [EXPAND_TAC "k" THEN REWRITE_TAC[GSYM real_ge; CLOSED_HALFSPACE_GE];
+    ALL_TAC] THEN
+  REWRITE_TAC[FINITE_SUBSET_IMAGE] THEN GEN_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `c:real^N->bool` MP_TAC) THEN
+  ASM_CASES_TAC `c:real^N->bool = {}` THENL
+   [ASM_SIMP_TAC[INTERS_0; INTER_UNIV; IMAGE_CLAUSES] THEN
+    DISCH_THEN(K ALL_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+    SUBGOAL_THEN `~(a:real^N = vec 0)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[]; ALL_TAC] THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    EXISTS_TAC `inv(norm a) % a:real^N` THEN
+    ASM_SIMP_TAC[IN_INTER; FRONTIER_CBALL; SPAN_CLAUSES; IN_SPHERE_0] THEN
+    REWRITE_TAC[DIST_0; NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+    ASM_SIMP_TAC[REAL_MUL_LINV; NORM_EQ_0];
+    ALL_TAC] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPEC `convex hull (c:real^N->bool)`
+      SEPARATING_HYPERPLANE_CLOSED_0_INSET) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[CONVEX_HULL_EQ_EMPTY] THEN
+    ASM_MESON_TAC[CONVEX_CONVEX_HULL; SUBSET; SUBSET_HULL; HULL_SUBSET;
+                  FINITE_IMP_COMPACT_CONVEX_HULL; COMPACT_IMP_CLOSED];
+    ALL_TAC] THEN
+  REWRITE_TAC[DOT_RZERO; real_gt] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` (X_CHOOSE_THEN `b:real`
+    STRIP_ASSUME_TAC)) THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER; IN_INTERS; FORALL_IN_IMAGE] THEN
+  EXPAND_TAC "k" THEN SIMP_TAC[IN_ELIM_THM; FRONTIER_CBALL; REAL_LT_01] THEN
+  REWRITE_TAC[dist; VECTOR_SUB_LZERO; NORM_NEG] THEN
+  EXISTS_TAC `inv(norm(a)) % a:real^N` THEN REWRITE_TAC[DOT_RMUL] THEN
+  SUBGOAL_THEN `(a:real^N) IN s` ASSUME_TAC THENL
+   [ASM_MESON_TAC[SUBSET; HULL_MINIMAL]; ASM_SIMP_TAC[SPAN_CLAUSES]] THEN
+  REWRITE_TAC[IN_SPHERE_0; VECTOR_SUB_LZERO; NORM_NEG; NORM_MUL] THEN
+  REWRITE_TAC[REAL_ABS_INV; REAL_ABS_NORM] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM real_div] THEN
+  ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_EQ_LDIV_EQ; NORM_POS_LT] THEN
+  REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID] THEN
+  ASM_MESON_TAC[REAL_LT_IMP_LE; REAL_LE_TRANS; HULL_SUBSET; SUBSET; DOT_SYM]);;
+
+let SEPARATING_HYPERPLANE_SET_POINT_INAFF = prove
+ (`!s z:real^N.
+        convex s /\ ~(s = {}) /\ ~(z IN s)
+        ==> ?a b. (z + a) IN affine hull (z INSERT s) /\ ~(a = vec 0) /\
+                  a dot z <= b /\ (!x. x IN s ==> a dot x >= b)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `IMAGE (\x:real^N. --z + x) s`
+     SEPARATING_HYPERPLANE_SET_0_INSPAN) THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; CONVEX_TRANSLATION; IMAGE_EQ_EMPTY] THEN
+  REWRITE_TAC[IN_IMAGE; VECTOR_ARITH `vec 0:real^N = --z + x <=> x = z`] THEN
+  ASM_SIMP_TAC[UNWIND_THM2; AFFINE_HULL_INSERT_SPAN; IN_ELIM_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+  REWRITE_TAC[GSYM SIMPLE_IMAGE; VECTOR_ARITH `--x + y:real^N = y - x`] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  EXISTS_TAC `(a:real^N) dot z` THEN REWRITE_TAC[REAL_LE_REFL] THEN
+  ASM_REWRITE_TAC[REAL_ARITH `x >= y <=> &0 <= x - y`; GSYM DOT_RSUB]);;
+
+let SEPARATING_HYPERPLANE_SET_0 = prove
+ (`!s:real^N->bool.
+        convex s /\ ~(vec 0 IN s)
+        ==> ?a b. ~(a = vec 0) /\ !x. x IN s ==> &0 <= a dot x`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN
+    MESON_TAC[BASIS_NONZERO; LE_REFL; DIMINDEX_GE_1];
+    ASM_MESON_TAC[SEPARATING_HYPERPLANE_SET_0_INSPAN]]);;
+
+let SEPARATING_HYPERPLANE_SETS = prove
+ (`!s t. convex s /\ convex t /\ ~(s = {}) /\ ~(t = {}) /\ DISJOINT s t
+         ==> ?a:real^N b. ~(a = vec 0) /\
+                          (!x. x IN s ==> a dot x <= b) /\
+                          (!x. x IN t ==> a dot x >= b)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `{y - x:real^N | y IN t /\ x IN s}`
+                SEPARATING_HYPERPLANE_SET_0) THEN
+  ASM_SIMP_TAC[CONVEX_DIFFERENCES] THEN ANTS_TAC THENL
+   [REWRITE_TAC[IN_ELIM_THM] THEN ONCE_REWRITE_TAC[EQ_SYM_EQ] THEN
+    REWRITE_TAC[VECTOR_SUB_EQ] THEN
+    ASM_MESON_TAC[DISJOINT; NOT_IN_EMPTY; IN_INTER; EXTENSION];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+  SIMP_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  GEN_REWRITE_TAC LAND_CONV [SWAP_FORALL_THM] THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [SWAP_FORALL_THM] THEN
+  ONCE_REWRITE_TAC[IMP_CONJ] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[LEFT_FORALL_IMP_THM; EXISTS_REFL; DOT_RSUB; REAL_SUB_LE] THEN
+  DISCH_TAC THEN
+  MP_TAC(SPEC `IMAGE (\x:real^N. a dot x) s` SUP) THEN
+  ABBREV_TAC `k = sup (IMAGE (\x:real^N. a dot x) s)` THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; IMAGE_EQ_EMPTY; real_ge] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[MEMBER_NOT_EMPTY]; ASM_MESON_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More convexity generalities.                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_CLOSURE = prove
+ (`!s:real^N->bool. convex s ==> convex(closure s)`,
+  REWRITE_TAC[convex; CLOSURE_SEQUENTIAL] THEN
+  GEN_TAC THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`; `u:real`; `v:real`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `a:num->real^N`) MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `b:num->real^N`) MP_TAC) THEN
+  STRIP_TAC THEN EXISTS_TAC `\n:num. u % a(n) + v % b(n) :real^N` THEN
+  ASM_SIMP_TAC[LIM_ADD; LIM_CMUL]);;
+
+let CONVEX_INTERIOR = prove
+ (`!s:real^N->bool. convex s ==> convex(interior s)`,
+  REWRITE_TAC[CONVEX_ALT; IN_INTERIOR; SUBSET; IN_BALL; dist] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `d:real`) MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `e:real`) STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `min d e` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+  X_GEN_TAC `z:real^N` THEN STRIP_TAC THEN
+  SUBST1_TAC(VECTOR_ARITH `z:real^N =
+   (&1 - u) % (z - u % (y - x)) + u % (z + (&1 - u) % (y - x))`) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[VECTOR_ARITH `x - (z - u % (y - x)) =
+                                ((&1 - u) % x + u % y) - z:real^N`;
+                VECTOR_ARITH `y - (z + (&1 - u) % (y - x)) =
+                                ((&1 - u) % x + u % y) - z:real^N`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Moving and scaling convex hulls.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_HULL_TRANSLATION = prove
+ (`!a:real^N s.
+       convex hull (IMAGE (\x. a + x) s) = IMAGE (\x. a + x) (convex hull s)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC HULL_IMAGE THEN
+  REWRITE_TAC[CONVEX_TRANSLATION_EQ; CONVEX_CONVEX_HULL] THEN
+  REWRITE_TAC[VECTOR_ARITH `a + x:real^N = y <=> x = y - a`; EXISTS_REFL] THEN
+  VECTOR_ARITH_TAC);;
+
+add_translation_invariants [CONVEX_HULL_TRANSLATION];;
+
+let CONVEX_HULL_SCALING = prove
+ (`!s:real^N->bool c.
+       convex hull (IMAGE (\x. c % x) s) = IMAGE (\x. c % x) (convex hull s)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `c = &0` THENL
+   [ASM_SIMP_TAC[IMAGE_CONST; VECTOR_MUL_LZERO; CONVEX_HULL_EQ_EMPTY] THEN
+    COND_CASES_TAC THEN REWRITE_TAC[CONVEX_HULL_EMPTY; CONVEX_HULL_SING];
+    ALL_TAC] THEN
+  MATCH_MP_TAC HULL_IMAGE THEN
+  ASM_SIMP_TAC[CONVEX_SCALING_EQ; CONVEX_CONVEX_HULL] THEN
+  REWRITE_TAC[VECTOR_ARITH `c % x = c % y <=> c % (x - y) = vec 0`] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ] THEN
+  X_GEN_TAC `x:real^N` THEN EXISTS_TAC `inv c % x:real^N` THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; VECTOR_MUL_LID]);;
+
+let CONVEX_HULL_AFFINITY = prove
+ (`!s a:real^N c.
+        convex hull (IMAGE (\x. a + c % x) s) =
+        IMAGE (\x. a + c % x) (convex hull s)`,
+  REPEAT GEN_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; CONVEX_HULL_TRANSLATION; CONVEX_HULL_SCALING]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Convex set as intersection of halfspaces.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_HALFSPACE_INTERSECTION = prove
+ (`!s. closed(s:real^N->bool) /\ convex s
+       ==> s = INTERS {h | s SUBSET h /\ ?a b. h = {x | a dot x <= b}}`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN REWRITE_TAC[IN_INTERS] THEN
+  X_GEN_TAC `x:real^N` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  REWRITE_TAC[MESON[] `(!t. (P t /\ ?a b. t = x a b) ==> Q t) <=>
+                       (!a b. P(x a b) ==> Q(x a b))`] THEN
+  EQ_TAC THENL [SET_TAC[]; ALL_TAC] THEN STRIP_TAC THEN
+  MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `x:real^N`]
+    SEPARATING_HYPERPLANE_CLOSED_POINT) THEN
+  ASM_REWRITE_TAC[NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`--a:real^N`; `--b:real`]) THEN
+  ASM_SIMP_TAC[SUBSET; IN_ELIM_THM; DOT_LNEG; NOT_IMP] THEN
+  ASM_SIMP_TAC[REAL_LE_NEG2; REAL_LT_NEG2; REAL_NOT_LE;
+               REAL_ARITH `a > b ==> b <= a`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Radon's theorem (from Lars Schewe).                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let RADON_EX_LEMMA = prove
+ (`!(c:real^N->bool).
+        FINITE c /\ affine_dependent c
+        ==> (?u. sum c u = &0 /\ (?v. v IN c /\ ~(u v = &0)) /\
+                                      vsum c (\v. u v % v) = (vec 0):real^N)`,
+  REWRITE_TAC[AFFINE_DEPENDENT_EXPLICIT] THEN
+  REPEAT STRIP_TAC THEN
+  EXISTS_TAC `\v:real^N. if v IN s then u v else &0` THEN
+  ASM_SIMP_TAC[GSYM SUM_RESTRICT_SET] THEN
+  ASM_SIMP_TAC[COND_RAND;COND_RATOR;
+               VECTOR_MUL_LZERO;GSYM VSUM_RESTRICT_SET] THEN
+  ASM_SIMP_TAC[SET_RULE `s SUBSET c ==> {x | x IN c /\ x IN s} = s`] THEN
+  EXISTS_TAC `v:real^N` THEN
+  ASM_REWRITE_TAC[] THEN ASM SET_TAC[]);;
+
+let RADON_S_LEMMA = prove
+ (`!(s:A->bool) f.
+        FINITE s /\ sum s f = &0
+        ==> sum {x | x IN s /\ &0 < f x} f =
+            -- sum {x | x IN s /\ f x < &0} f`,
+  REWRITE_TAC[REAL_ARITH `a = --b <=> a + b = &0`] THEN
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[FINITE_RESTRICT;GSYM SUM_UNION;
+    REWRITE_RULE [REAL_ARITH `&0 < f x ==> ~(f x < &0)`]
+     (SET_RULE `(!x:A. &0 < f x ==> ~(f x < &0))
+                ==>  DISJOINT {x | x IN s /\ &0 < f x}
+                              {x | x IN s /\ f x < &0}`)] THEN
+  MATCH_MP_TAC (REAL_ARITH `!a b.a = &0 /\ a + b = &0 ==> b = &0`) THEN
+  EXISTS_TAC `sum {x:A | x IN s /\ f x = &0} f` THEN
+  CONJ_TAC THENL
+  [ASM_SIMP_TAC[SUM_RESTRICT_SET] THEN REWRITE_TAC[COND_ID;SUM_0];
+   ALL_TAC] THEN
+  SUBGOAL_THEN `DISJOINT {x:A | x IN s /\ f x = &0}
+                         ({x | x IN s /\ &0 < f x} UNION
+                          {x | x IN s /\ f x < &0})` ASSUME_TAC THENL
+  [REWRITE_TAC[DISJOINT;UNION;INTER;IN_ELIM_THM;EXTENSION;NOT_IN_EMPTY] THEN
+   REAL_ARITH_TAC;
+   ALL_TAC] THEN
+   ASM_SIMP_TAC[FINITE_UNION;FINITE_RESTRICT;GSYM SUM_UNION] THEN
+  FIRST_X_ASSUM (SUBST1_TAC o GSYM) THEN
+  MATCH_MP_TAC (MESON[] `a = b ==> sum a f = sum b f`) THEN
+  REWRITE_TAC[EXTENSION;IN_ELIM_THM;UNION] THEN
+  MESON_TAC[REAL_LT_TOTAL]);;
+
+let RADON_V_LEMMA = prove
+ (`!(s:A->bool) f g.
+        FINITE s /\ vsum s f = vec 0 /\ (!x. g x = &0 ==> f x = vec 0)
+        ==> (vsum {x | x IN s /\ &0 < g x} f) :real^N =
+             -- vsum {x | x IN s /\ g x < &0} f`,
+  REWRITE_TAC[VECTOR_ARITH `a:real^N = --b <=> a + b = vec 0`] THEN
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[FINITE_RESTRICT;GSYM VSUM_UNION;
+               REWRITE_RULE [REAL_ARITH `&0 < f x ==> ~(f x < &0)`]
+                 (SET_RULE `(!x:A. &0 < f x ==> ~(f x < &0))
+                            ==>  DISJOINT {x | x IN s /\ &0 < f x}
+                                          {x | x IN s /\ f x < &0}`)] THEN
+  MATCH_MP_TAC (VECTOR_ARITH
+    `!a b. (a:real^N) = vec 0 /\ a + b = vec 0 ==> b = vec 0`) THEN
+  EXISTS_TAC `(vsum {x:A | x IN s /\ g x = &0} f):real^N` THEN
+  CONJ_TAC THENL
+   [ASM_SIMP_TAC[VSUM_RESTRICT_SET;COND_ID;VSUM_0];ALL_TAC] THEN
+    SUBGOAL_THEN `DISJOINT {x:A | x IN s /\ g x = &0}
+                           ({x | x IN s /\ &0 < g x} UNION
+                            {x | x IN s /\ g x < &0})` ASSUME_TAC THENL
+     [REWRITE_TAC[DISJOINT;UNION;INTER;IN_ELIM_THM;EXTENSION;NOT_IN_EMPTY] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+  ASM_SIMP_TAC[FINITE_UNION;FINITE_RESTRICT;GSYM VSUM_UNION] THEN
+  FIRST_X_ASSUM (SUBST1_TAC o GSYM) THEN
+  MATCH_MP_TAC (MESON[] `a = b ==> vsum a f = vsum b f`) THEN
+  REWRITE_TAC[EXTENSION;IN_ELIM_THM;UNION] THEN
+  MESON_TAC[REAL_LT_TOTAL]);;
+
+let RADON_PARTITION = prove
+ (`!(c:real^N->bool).
+        FINITE c /\ affine_dependent c
+        ==> ?(m:real^N->bool) (p:real^N->bool).
+                (DISJOINT m p) /\
+                (m UNION p = c) /\
+                ~(DISJOINT (convex hull m) (convex hull p))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC (ISPEC `c:real^N->bool` RADON_EX_LEMMA) THEN
+  ASM_REWRITE_TAC[] THEN
+  REPEAT STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`{v:real^N | v IN c /\ u v <= &0}`;
+                        `{v:real^N | v IN c /\ u v > &0}`] THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[DISJOINT;INTER;
+               IN_ELIM_THM;REAL_ARITH `x <= &0 <=> ~(x > &0)`] THEN
+    SET_TAC[];
+    REWRITE_TAC[UNION;IN_ELIM_THM;REAL_ARITH `x <= &0 <=> ~(x > &0)`] THEN
+    SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~(sum {x:real^N | x IN c /\ u x > &0} u = &0)` ASSUME_TAC THENL
+   [MATCH_MP_TAC (REAL_ARITH `a > &0 ==> ~(a = &0)`) THEN
+    REWRITE_TAC[REAL_ARITH `a > &0 <=> &0 < a`]        THEN
+    MATCH_MP_TAC (REWRITE_RULE[SUM_0] (ISPEC `\x. &0` SUM_LT_ALL)) THEN
+    ASM_SIMP_TAC[FINITE_RESTRICT;IN_ELIM_THM;EXTENSION;NOT_IN_EMPTY] THEN
+    REWRITE_TAC[MESON[]`~(!x. ~(P x /\ Q x)) = ?x. P x /\ Q x`] THEN
+       ASM_CASES_TAC `&0 < u (v:real^N)` THENL
+    [ASM SET_TAC[];ALL_TAC] THEN
+    POP_ASSUM MP_TAC THEN POP_ASSUM (K ALL_TAC) THEN POP_ASSUM MP_TAC THEN
+    REWRITE_TAC[IMP_IMP;REAL_ARITH `~(a = &0) /\ ~(&0 < a) <=> a < &0`] THEN
+    DISCH_TAC THEN
+    REWRITE_TAC[MESON[REAL_NOT_LT]
+     `(?x:real^N. P x /\ &0 < u x) <=> (!x. P x ==> u x <= &0) ==> F`]  THEN
+    DISCH_TAC THEN
+       MP_TAC (ISPECL [`u:real^N->real`;`\x:real^N. &0`;`c:real^N->bool`]
+                      SUM_LT) THEN
+    ASM_REWRITE_TAC[SUM_0;REAL_ARITH `~(&0 < &0)`] THEN
+    ASM_MESON_TAC[];ALL_TAC] THEN
+  REWRITE_TAC[SET_RULE `~DISJOINT a b <=> ?y. y IN a /\ y IN b`] THEN
+  EXISTS_TAC `&1 / (sum {x:real^N | x IN c /\ u x > &0} u) %
+              vsum {x:real^N | x IN c /\ u x > &0} (\x. u x % x)` THEN
+  REWRITE_TAC[CONVEX_HULL_EXPLICIT;IN_ELIM_THM] THEN
+  CONJ_TAC THENL
+  [MAP_EVERY EXISTS_TAC [`{v:real^N | v IN c /\ u v < &0}`;
+                         `\y:real^N.
+                         &1 / (sum {x:real^N | x IN c /\ u x > &0} u) *
+                           (--(u y))`] THEN
+   ASM_SIMP_TAC[FINITE_RESTRICT;SUBSET;IN_ELIM_THM] THEN
+   REPEAT CONJ_TAC THENL
+    [REAL_ARITH_TAC;
+     REPEAT STRIP_TAC THEN
+     MATCH_MP_TAC REAL_LE_MUL THEN
+     CONJ_TAC THENL [ALL_TAC;
+                     ASM_REWRITE_TAC[REAL_NEG_GE0;REAL_LE_LT]] THEN
+     MATCH_MP_TAC REAL_LE_DIV THEN
+     REWRITE_TAC[REAL_LE_01] THEN
+     MATCH_MP_TAC SUM_POS_LE THEN
+     ASM_SIMP_TAC[FINITE_RESTRICT;IN_ELIM_THM] THEN
+     REAL_ARITH_TAC;
+     ASM_SIMP_TAC[FINITE_RESTRICT;SUM_LMUL] THEN
+     MATCH_MP_TAC (REAL_FIELD `!a. ~(a = &0) /\ a * b = a * c ==> b = c`) THEN
+     EXISTS_TAC `sum {x:real^N | x IN c /\ u x > &0} u` THEN
+     REWRITE_TAC[SUM_LMUL] THEN
+     ASM_SIMP_TAC[REAL_FIELD `~(a = &0) ==> a * &1 / a * b = b`]  THEN
+     REWRITE_TAC[SUM_NEG;REAL_MUL_RID] THEN
+     REWRITE_TAC[REAL_ARITH `a > &0 <=> &0 < a`] THEN
+     MATCH_MP_TAC (GSYM RADON_S_LEMMA) THEN
+     ASM_REWRITE_TAC[];
+     ALL_TAC] THEN
+    REWRITE_TAC[GSYM VECTOR_MUL_ASSOC;VSUM_LMUL;VECTOR_MUL_LCANCEL] THEN
+    REWRITE_TAC[VECTOR_MUL_LNEG;VSUM_NEG] THEN
+    DISJ2_TAC THEN
+    MATCH_MP_TAC (REWRITE_RULE[REAL_ARITH `&0 < a <=>  a > &0`]
+     (GSYM RADON_V_LEMMA)) THEN
+    ASM_REWRITE_TAC[] THEN
+    MESON_TAC[VECTOR_MUL_LZERO];ALL_TAC] THEN
+  MAP_EVERY EXISTS_TAC [`{v:real^N | v IN c /\ u v > &0}`;
+                        `\y:real^N.
+                           &1 / (sum {x:real^N | x IN c /\ u x > &0} u) *
+                           (u y)`] THEN
+  ASM_SIMP_TAC[FINITE_RESTRICT;SUBSET;IN_ELIM_THM] THEN
+  REPEAT CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LE_MUL THEN
+    CONJ_TAC THENL [ALL_TAC;
+                    ASM_SIMP_TAC[REAL_ARITH `a > &0 ==> &0 <= a`]] THEN
+    MATCH_MP_TAC REAL_LE_DIV THEN
+    REWRITE_TAC[REAL_LE_01] THEN
+    MATCH_MP_TAC SUM_POS_LE THEN
+    ASM_SIMP_TAC[FINITE_RESTRICT;IN_ELIM_THM] THEN
+    REAL_ARITH_TAC;
+    ASM_SIMP_TAC[FINITE_RESTRICT;SUM_LMUL] THEN
+    MATCH_MP_TAC (REAL_FIELD `!a. ~(a = &0) /\ a * b = a * c ==> b = c`) THEN
+    EXISTS_TAC `sum {x:real^N | x IN c /\ u x > &0} u` THEN
+    REWRITE_TAC[SUM_LMUL] THEN
+    ASM_SIMP_TAC[REAL_FIELD `~(a = &0) ==> a * &1 / a * b = b`]  THEN
+    REWRITE_TAC[SUM_NEG;REAL_MUL_RID] THEN
+    REWRITE_TAC[REAL_ARITH `a > &0 <=> &0 < a`] THEN
+    MATCH_MP_TAC (GSYM RADON_S_LEMMA) THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[GSYM VECTOR_MUL_ASSOC;VSUM_LMUL;VECTOR_MUL_LCANCEL] THEN
+  REWRITE_TAC[VECTOR_MUL_LNEG;VSUM_NEG] THEN
+  DISJ2_TAC THEN
+  MATCH_MP_TAC (REWRITE_RULE[REAL_ARITH `&0 < a <=>  a > &0`]
+    (GSYM RADON_V_LEMMA)) THEN
+  ASM_REWRITE_TAC[] THEN
+  MESON_TAC[VECTOR_MUL_LZERO]);;
+
+let RADON = prove
+ (`!(c:real^N->bool).
+        affine_dependent c
+        ==> ?(m:real^N->bool) (p:real^N->bool).
+                m SUBSET c /\
+                p SUBSET c /\
+                DISJOINT m p /\
+                ~(DISJOINT (convex hull m) (convex hull p))`,
+  REPEAT STRIP_TAC THEN MP_TAC
+    (ISPEC `c:real^N->bool` AFFINE_DEPENDENT_EXPLICIT) THEN
+  ASM_SIMP_TAC[] THEN REPEAT STRIP_TAC THEN MP_TAC
+  (ISPEC `s:real^N->bool` RADON_PARTITION) THEN
+  ANTS_TAC THENL
+  [ASM_SIMP_TAC[AFFINE_DEPENDENT_EXPLICIT] THEN
+     MAP_EVERY EXISTS_TAC [`s:real^N->bool`;`u:real^N->real`] THEN
+     ASM SET_TAC[];ALL_TAC] THEN
+  DISCH_THEN STRIP_ASSUME_TAC THEN
+  MAP_EVERY EXISTS_TAC [`m:real^N->bool`;`p:real^N->bool`] THEN
+  ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Helly's theorem.                                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let HELLY_INDUCT = prove
+ (`!n f. f HAS_SIZE n /\ n >= dimindex(:N) + 1 /\
+         (!s:real^N->bool. s IN f ==> convex s) /\
+         (!t. t SUBSET f /\ CARD(t) = dimindex(:N) + 1
+              ==> ~(INTERS t = {}))
+         ==> ~(INTERS f = {})`,
+  INDUCT_TAC THEN REWRITE_TAC[ARITH_RULE `~(0 >= n + 1)`] THEN GEN_TAC THEN
+  POP_ASSUM(LABEL_TAC "*") THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HAS_SIZE_SUC]) THEN
+  STRIP_TAC THEN RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN
+  FIRST_X_ASSUM(DISJ_CASES_TAC o MATCH_MP (ARITH_RULE
+    `SUC n >= m + 1 ==> m = n \/ n >= m + 1`))
+  THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN
+    ASM_SIMP_TAC[CARD_CLAUSES; SUBSET_REFL] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?X. !s:real^N->bool. s IN f ==> X(s) IN INTERS (f DELETE s)`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM SKOLEM_THM; MEMBER_NOT_EMPTY; RIGHT_EXISTS_IMP_THM] THEN
+    GEN_TAC THEN STRIP_TAC THEN REMOVE_THEN "*" MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[FINITE_DELETE; CARD_DELETE] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ASM_CASES_TAC
+   `?s t:real^N->bool. s IN f /\ t IN f /\ ~(s = t) /\ X s:real^N = X t`
+  THENL
+   [FIRST_X_ASSUM(CHOOSE_THEN STRIP_ASSUME_TAC) THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    EXISTS_TAC `(X:(real^N->bool)->real^N) t` THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC ONCE_DEPTH_CONV
+     [MATCH_MP
+       (SET_RULE`~(s = t)
+               ==> INTERS f = INTERS(f DELETE s) INTER INTERS(f DELETE t)`)
+       th]) THEN
+    REWRITE_TAC[IN_INTER] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  MP_TAC(ISPEC `IMAGE (X:(real^N->bool)->real^N) f` RADON_PARTITION) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[FINITE_IMAGE] THEN
+    MATCH_MP_TAC AFFINE_DEPENDENT_BIGGERSET THEN
+    ASM_SIMP_TAC[FINITE_IMAGE] THEN
+    MATCH_MP_TAC(ARITH_RULE
+     `!f n. n >= d + 1 /\ f = SUC n /\ c = f ==> c >= d + 2`) THEN
+    MAP_EVERY EXISTS_TAC [`CARD(f:(real^N->bool)->bool)`; `n:num`] THEN
+    REPEAT(CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC]) THEN
+    MATCH_MP_TAC CARD_IMAGE_INJ THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[SET_RULE
+   `P /\ m UNION p = s /\ Q <=>
+    m SUBSET s /\ p SUBSET s /\ m UNION p = s /\ P /\ Q`] THEN
+  REWRITE_TAC[SUBSET_IMAGE; DISJOINT] THEN
+  REWRITE_TAC[MESON[]
+   `(?m p. (?u. P u /\ m = t u) /\ (?u. P u /\ p = t u) /\ Q m p) ==> r <=>
+    (!u v. P u /\ P v /\ Q (t u) (t v) ==> r)`] THEN
+  MAP_EVERY X_GEN_TAC [`g:(real^N->bool)->bool`; `h:(real^N->bool)->bool`] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  SUBGOAL_THEN `(f:(real^N->bool)->bool) = h UNION g` SUBST1_TAC THENL
+   [MATCH_MP_TAC SUBSET_ANTISYM THEN ASM_REWRITE_TAC[UNION_SUBSET] THEN
+    REWRITE_TAC[SUBSET; IN_UNION] THEN X_GEN_TAC `s:real^N->bool` THEN
+    DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+    DISCH_THEN(MP_TAC o ISPEC `X:(real^N->bool)->real^N` o
+      MATCH_MP FUN_IN_IMAGE) THEN
+    FIRST_X_ASSUM(fun th ->
+      GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM th]) THEN
+    ONCE_REWRITE_TAC[DISJ_SYM] THEN REWRITE_TAC[IN_UNION; IN_IMAGE] THEN
+    MATCH_MP_TAC MONO_OR THEN ASM_MESON_TAC[SUBSET];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(SET_RULE
+   `g SUBSET INTERS g' /\ h SUBSET INTERS h'
+    ==> ~(g INTER h = {}) ==> ~(INTERS(g' UNION h') = {})`) THEN
+  FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP (SET_RULE
+   `IMAGE X s INTER IMAGE X t = {} ==> s INTER t = {}`)) THEN
+  CONJ_TAC THEN MATCH_MP_TAC HULL_MINIMAL THEN
+  (CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[SUBSET; CONVEX_INTERS]]) THEN
+  REWRITE_TAC[SUBSET; IN_INTERS; FORALL_IN_IMAGE] THEN ASM SET_TAC[]);;
+
+let HELLY = prove
+ (`!f:(real^N->bool)->bool.
+        FINITE f /\ CARD(f) >= dimindex(:N) + 1 /\
+        (!s. s IN f ==> convex s) /\
+        (!t. t SUBSET f /\ CARD(t) = dimindex(:N) + 1 ==> ~(INTERS t = {}))
+        ==> ~(INTERS f = {})`,
+  GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC HELLY_INDUCT THEN
+  ASM_REWRITE_TAC[HAS_SIZE] THEN ASM_MESON_TAC[]);;
+
+let HELLY_ALT = prove
+ (`!f:(real^N->bool)->bool.
+        FINITE f /\
+        (!s. s IN f ==> convex s) /\
+        (!t. t SUBSET f /\ CARD(t) <= dimindex(:N) + 1 ==> ~(INTERS t = {}))
+        ==> ~(INTERS f = {})`,
+  GEN_TAC THEN STRIP_TAC THEN
+  ASM_CASES_TAC `CARD(f:(real^N->bool)->bool) < dimindex(:N) + 1` THEN
+  ASM_SIMP_TAC[SUBSET_REFL; LT_IMP_LE] THEN MATCH_MP_TAC HELLY THEN
+  ASM_SIMP_TAC[GE; GSYM NOT_LT] THEN ASM_MESON_TAC[LE_REFL]);;
+
+let HELLY_CLOSED_ALT = prove
+ (`!f:(real^N->bool)->bool.
+        (!s. s IN f ==> convex s /\ closed s) /\ (?s. s IN f /\ bounded s) /\
+        (!t. t SUBSET f /\ FINITE t /\ CARD(t) <= dimindex(:N) + 1
+             ==> ~(INTERS t = {}))
+        ==> ~(INTERS f = {})`,
+  GEN_TAC THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  MATCH_MP_TAC CLOSED_FIP THEN ASM_SIMP_TAC[] THEN
+  X_GEN_TAC `g:(real^N->bool)->bool` THEN STRIP_TAC THEN
+  MATCH_MP_TAC HELLY_ALT THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ASM SET_TAC[];
+    ASM_MESON_TAC[SUBSET_TRANS; FINITE_SUBSET]]);;
+
+let HELLY_COMPACT_ALT = prove
+ (`!f:(real^N->bool)->bool.
+        (!s. s IN f ==> convex s /\ compact s) /\
+        (!t. t SUBSET f /\ FINITE t /\ CARD(t) <= dimindex(:N) + 1
+             ==> ~(INTERS t = {}))
+        ==> ~(INTERS f = {})`,
+  GEN_TAC THEN STRIP_TAC THEN
+  ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THEN
+  ASM_REWRITE_TAC[INTERS_0; UNIV_NOT_EMPTY] THEN
+  MATCH_MP_TAC HELLY_CLOSED_ALT THEN
+  ASM_SIMP_TAC[COMPACT_IMP_CLOSED] THEN
+  ASM_MESON_TAC[MEMBER_NOT_EMPTY; COMPACT_IMP_BOUNDED]);;
+
+let HELLY_CLOSED = prove
+ (`!f:(real^N->bool)->bool.
+        (FINITE f ==> CARD f >= dimindex (:N) + 1) /\
+        (!s. s IN f ==> convex s /\ closed s) /\ (?s. s IN f /\ bounded s) /\
+        (!t. t SUBSET f /\ FINITE t /\ CARD(t) = dimindex(:N) + 1
+             ==> ~(INTERS t = {}))
+        ==> ~(INTERS f = {})`,
+  GEN_TAC THEN REWRITE_TAC[GE] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  MATCH_MP_TAC HELLY_CLOSED_ALT THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `g:(real^N->bool)->bool` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`dimindex(:N) + 1`; `g:(real^N->bool)->bool`;
+                 `f:(real^N->bool)->bool`] CHOOSE_SUBSET_BETWEEN) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC(SET_RULE `!s. s SUBSET t /\ ~(s = {}) ==> ~(t = {})`) THEN
+  EXISTS_TAC `INTERS h: real^N->bool` THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; FIRST_X_ASSUM MATCH_MP_TAC] THEN
+  ASM_MESON_TAC[HAS_SIZE]);;
+
+let HELLY_COMPACT = prove
+ (`!f:(real^N->bool)->bool.
+        (FINITE f ==> CARD f >= dimindex (:N) + 1) /\
+        (!s. s IN f ==> convex s /\ compact s) /\
+        (!t. t SUBSET f /\ FINITE t /\ CARD(t) = dimindex(:N) + 1
+             ==> ~(INTERS t = {}))
+        ==> ~(INTERS f = {})`,
+  GEN_TAC THEN STRIP_TAC THEN
+  ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THEN
+  ASM_REWRITE_TAC[INTERS_0; UNIV_NOT_EMPTY] THEN
+  MATCH_MP_TAC HELLY_CLOSED THEN
+  ASM_SIMP_TAC[COMPACT_IMP_CLOSED] THEN
+  ASM_MESON_TAC[MEMBER_NOT_EMPTY; COMPACT_IMP_BOUNDED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Kirchberger's theorem                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let KIRCHBERGER = prove
+ (`!s t:real^N->bool.
+        compact s /\ compact t /\
+        (!s' t'. s' SUBSET s /\ t' SUBSET t /\ FINITE s' /\ FINITE t' /\
+                 CARD(s') + CARD(t') <= dimindex(:N) + 2
+                 ==> ?a b. (!x. x IN s' ==> a dot x < b) /\
+                           (!x. x IN t' ==> a dot x > b))
+        ==> ?a b. ~(a = vec 0) /\
+                  (!x. x IN s ==> a dot x < b) /\
+                  (!x. x IN t ==> a dot x > b)`,
+  let lemma = prove
+   (`(!x. x IN convex hull s ==> a dot x < b) /\
+     (!x. x IN convex hull t ==> a dot x > b) <=>
+     (!x. x IN s ==> a dot x < b) /\ (!x. x IN t ==> a dot x > b)`,
+    REWRITE_TAC[SET_RULE `(!x. x IN s ==> P x) <=> s SUBSET {x | P x}`] THEN
+    SIMP_TAC[SUBSET_HULL; CONVEX_HALFSPACE_LT; CONVEX_HALFSPACE_GT])
+  and KIRCH_LEMMA = prove
+   (`!s t:real^N->bool.
+          FINITE s /\ FINITE t /\
+          (!s' t'. s' SUBSET s /\ t' SUBSET t /\
+                   CARD(s') + CARD(t') <= dimindex(:N) + 2
+                   ==> ?a b. (!x. x IN s' ==> a dot x < b) /\
+                             (!x. x IN t' ==> a dot x > b))
+          ==> ?a b. (!x. x IN s ==> a dot x < b) /\
+                    (!x. x IN t ==> a dot x > b)`,
+    REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+     [`IMAGE (\r. {z:real^(N,1)finite_sum |
+                          fstcart z dot r < drop(sndcart z)}) s UNION
+       IMAGE (\r. {z:real^(N,1)finite_sum |
+                          fstcart z dot r > drop(sndcart z)}) t`]
+     HELLY_ALT) THEN
+    REWRITE_TAC[FORALL_SUBSET_UNION; IN_UNION; IMP_CONJ] THEN
+    REWRITE_TAC[RIGHT_FORALL_IMP_THM; FORALL_SUBSET_IMAGE] THEN
+    ASM_SIMP_TAC[FINITE_UNION; FINITE_IMAGE; INTERS_UNION] THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; INTERS_IMAGE; IN_INTER;
+                EXISTS_PASTECART; IN_ELIM_PASTECART_THM;
+                FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    REWRITE_TAC[TAUT `p \/ q ==> r <=> (p ==> r) /\ (q ==> r)`] THEN
+    REWRITE_TAC[FORALL_AND_THM; FORALL_IN_IMAGE; RIGHT_IMP_FORALL_THM] THEN
+    REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC; GSYM EXISTS_DROP] THEN
+    DISCH_THEN MATCH_MP_TAC THEN REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+     [REWRITE_TAC[REAL_ARITH `a > b <=> --a < --b`; GSYM DOT_RNEG] THEN
+      REWRITE_TAC[convex; IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC] THEN
+      SIMP_TAC[PASTECART_ADD; GSYM PASTECART_CMUL; IN_ELIM_PASTECART_THM] THEN
+      SIMP_TAC[DOT_LADD; DOT_LMUL; DROP_ADD; DROP_CMUL; GSYM FORALL_DROP] THEN
+      REWRITE_TAC[REAL_ARITH `--(a * x + b * y):real = a * --x + b * --y`] THEN
+      REPEAT STRIP_TAC THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP (REAL_ARITH
+       `u + v = &1
+        ==> &0 <= u /\ &0 <= v
+           ==> u = &0 /\ v = &1 \/ u = &1 /\ v = &0 \/ &0 < u /\ &0 < v`)) THEN
+      ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+      ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID;
+                      REAL_ADD_LID; REAL_ADD_RID] THEN
+      MATCH_MP_TAC REAL_LT_ADD2 THEN ASM_SIMP_TAC[REAL_LT_LMUL_EQ];
+      REWRITE_TAC[DIMINDEX_FINITE_SUM; DIMINDEX_1;
+                  ARITH_RULE `(n + 1) + 1 = n + 2`] THEN
+      MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `v:real^N->bool`] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+      SUBGOAL_THEN `FINITE(u:real^N->bool) /\ FINITE(v:real^N->bool)`
+      STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+      W(MP_TAC o PART_MATCH (lhs o rand) CARD_UNION o lhand o lhand o snd) THEN
+      ASM_SIMP_TAC[FINITE_IMAGE] THEN ANTS_TAC THENL
+       [REWRITE_TAC[SET_RULE `IMAGE f s INTER IMAGE g t = {} <=>
+                              !x y. x IN s /\ y IN t ==> ~(f x = g y)`] THEN
+        MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+        REWRITE_TAC[EXTENSION; FORALL_PASTECART; IN_ELIM_PASTECART_THM] THEN
+        DISCH_THEN(MP_TAC o SPEC `vec 0:real^N`) THEN
+        REWRITE_TAC[GSYM FORALL_DROP; DOT_LZERO] THEN
+        DISCH_THEN(MP_TAC o SPEC `&1`) THEN REAL_ARITH_TAC;
+        DISCH_THEN SUBST1_TAC] THEN
+      DISCH_THEN(fun th -> FIRST_X_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(ARITH_RULE
+       `a = a' /\ b = b' ==> a + b <= n + 2 ==> a' + b' <= n + 2`) THEN
+      CONJ_TAC THEN MATCH_MP_TAC CARD_IMAGE_INJ THEN
+      ASM_REWRITE_TAC[EXTENSION; FORALL_PASTECART; IN_ELIM_PASTECART_THM] THEN
+      SIMP_TAC[GSYM FORALL_DROP; real_gt; VECTOR_EQ_LDOT;
+        MESON[REAL_LT_TOTAL; REAL_LT_REFL]
+         `((!y:real. a < y <=> b < y) <=> a = b) /\
+          ((!y:real. y < a <=> y < b) <=> a = b)`]]) in
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM lemma] THEN
+  MATCH_MP_TAC SEPARATING_HYPERPLANE_COMPACT_COMPACT THEN
+  ASM_SIMP_TAC[CONVEX_CONVEX_HULL; COMPACT_CONVEX_HULL;
+               CONVEX_HULL_EQ_EMPTY] THEN
+  SUBGOAL_THEN
+   `!s' t'. (s':real^N->bool) SUBSET s /\ t' SUBSET t /\
+            FINITE s' /\ CARD(s') <= dimindex(:N) + 1 /\
+            FINITE t' /\ CARD(t') <= dimindex(:N) + 1
+            ==> DISJOINT (convex hull s') (convex hull t')`
+  MP_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`s':real^N->bool`; `t':real^N->bool`] KIRCH_LEMMA) THEN
+    ANTS_TAC THENL
+     [ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[SUBSET; FINITE_SUBSET];
+      ONCE_REWRITE_TAC[GSYM lemma] THEN SET_TAC[REAL_LT_ANTISYM; real_gt]];
+    POP_ASSUM_LIST(K ALL_TAC) THEN STRIP_TAC THEN
+    REWRITE_TAC[SET_RULE `DISJOINT s t <=> !x. x IN s /\ x IN t ==> F`] THEN
+    X_GEN_TAC `x:real^N` THEN ONCE_REWRITE_TAC[CARATHEODORY] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+      (X_CHOOSE_THEN `s':real^N->bool` STRIP_ASSUME_TAC)
+      (X_CHOOSE_THEN `t':real^N->bool` STRIP_ASSUME_TAC)) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`s':real^N->bool`; `t':real^N->bool`]) THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Convex hull is "preserved" by a linear function.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_HULL_LINEAR_IMAGE = prove
+ (`!f s. linear f ==> convex hull (IMAGE f s) = IMAGE f (convex hull s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  CONJ_TAC THEN MATCH_MP_TAC HULL_INDUCT THEN
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN SIMP_TAC[FUN_IN_IMAGE; HULL_INC] THEN
+  REWRITE_TAC[convex; IN_ELIM_THM] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THENL
+   [FIRST_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP LINEAR_CMUL th)]) THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP LINEAR_ADD th)]) THEN
+    REWRITE_TAC[IN_IMAGE] THEN
+    MESON_TAC[REWRITE_RULE[convex] CONVEX_CONVEX_HULL];
+    ASM_SIMP_TAC[LINEAR_ADD; LINEAR_CMUL] THEN
+    MESON_TAC[REWRITE_RULE[convex] CONVEX_CONVEX_HULL]]);;
+
+add_linear_invariants [CONVEX_HULL_LINEAR_IMAGE];;
+
+let IN_CONVEX_HULL_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s x.
+        linear f /\ x IN convex hull s ==> (f x) IN convex hull (IMAGE f s)`,
+  SIMP_TAC[CONVEX_HULL_LINEAR_IMAGE] THEN SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Convexity of general and special intervals.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let IS_INTERVAL_CONVEX = prove
+ (`!s:real^N->bool. is_interval s ==> convex s`,
+  REWRITE_TAC[is_interval; convex] THEN
+  REPEAT STRIP_TAC THEN FIRST_ASSUM MATCH_MP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`x:real^N`; `y:real^N`] THEN
+  ASM_SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  GEN_TAC THEN STRIP_TAC THEN
+  DISJ_CASES_TAC(SPECL [`(x:real^N)$i`; `(y:real^N)$i`] REAL_LE_TOTAL) THENL
+   [DISJ1_TAC; DISJ2_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `&1 * a <= b /\ b <= &1 * c ==> a <= b /\ b <= c`) THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  ASM_SIMP_TAC[GSYM VECTOR_MUL_COMPONENT;
+               VECTOR_ADD_RDISTRIB; VECTOR_ADD_COMPONENT] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; REAL_LE_LMUL;
+               REAL_LE_LADD; REAL_LE_RADD]);;
+
+let IS_INTERVAL_CONNECTED = prove
+ (`!s:real^N->bool. is_interval s ==> connected s`,
+  MESON_TAC[IS_INTERVAL_CONVEX; CONVEX_CONNECTED]);;
+
+let IS_INTERVAL_CONNECTED_1 = prove
+ (`!s:real^1->bool. is_interval s <=> connected s`,
+  GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[IS_INTERVAL_CONNECTED] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  REWRITE_TAC[IS_INTERVAL_1; connected; NOT_FORALL_THM; LEFT_IMP_EXISTS_THM;
+              NOT_IMP; FORALL_LIFT; LIFT_DROP] THEN
+  MAP_EVERY X_GEN_TAC [`a:real`; `b:real`; `x:real`] THEN STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC
+   [`{z:real^1 | basis 1 dot z < x}`; `{z:real^1 | basis 1 dot z > x}`] THEN
+  REWRITE_TAC[OPEN_HALFSPACE_LT; OPEN_HALFSPACE_GT] THEN
+  SIMP_TAC[SUBSET; EXTENSION; IN_UNION; IN_INTER; GSYM drop; NOT_FORALL_THM;
+   real_gt; NOT_IN_EMPTY; IN_ELIM_THM; DOT_BASIS; DIMINDEX_1; ARITH] THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[REAL_LT_TOTAL; LIFT_DROP];
+    REAL_ARITH_TAC;
+    EXISTS_TAC `lift a`;
+    EXISTS_TAC `lift b`] THEN
+  ASM_REWRITE_TAC[REAL_LT_LE; LIFT_DROP] THEN ASM_MESON_TAC[]);;
+
+let CONVEX_INTERVAL = prove
+ (`!a b:real^N. convex(interval [a,b]) /\ convex(interval (a,b))`,
+  SIMP_TAC[IS_INTERVAL_CONVEX; IS_INTERVAL_INTERVAL]);;
+
+let CONNECTED_INTERVAL = prove
+ (`(!a b:real^N. connected(interval[a,b])) /\
+   (!a b:real^N. connected(interval(a,b)))`,
+  SIMP_TAC[CONVEX_CONNECTED; CONVEX_INTERVAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* On real^1, is_interval, convex and connected are all equivalent.          *)
+(* ------------------------------------------------------------------------- *)
+
+let IS_INTERVAL_CONVEX_1 = prove
+ (`!s:real^1->bool. is_interval s <=> convex s`,
+  MESON_TAC[IS_INTERVAL_CONVEX; CONVEX_CONNECTED; IS_INTERVAL_CONNECTED_1]);;
+
+let CONVEX_CONNECTED_1 = prove
+ (`!s:real^1->bool. convex s <=> connected s`,
+  REWRITE_TAC[GSYM IS_INTERVAL_CONVEX_1; GSYM IS_INTERVAL_CONNECTED_1]);;
+
+let CONNECTED_CONVEX_1 = prove
+ (`!s:real^1->bool. connected s <=> convex s`,
+  REWRITE_TAC[GSYM IS_INTERVAL_CONVEX_1; GSYM IS_INTERVAL_CONNECTED_1]);;
+
+let CONNECTED_COMPACT_INTERVAL_1 = prove
+ (`!s:real^1->bool. connected s /\ compact s <=> ?a b. s = interval[a,b]`,
+  REWRITE_TAC[GSYM IS_INTERVAL_CONNECTED_1; IS_INTERVAL_COMPACT]);;
+
+let CONVEX_CONNECTED_1_GEN = prove
+ (`!s:real^N->bool.
+        dimindex(:N) = 1 ==> (convex s <=> connected s)`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[GSYM DIMINDEX_1] THEN
+  DISCH_THEN(ACCEPT_TAC o C GEOM_EQUAL_DIMENSION_RULE CONVEX_CONNECTED_1));;
+
+let CONNECTED_CONVEX_1_GEN = prove
+ (`!s:real^N->bool.
+        dimindex(:N) = 1 ==> (convex s <=> connected s)`,
+  SIMP_TAC[CONVEX_CONNECTED_1_GEN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Jung's theorem.                                                           *)
+(* Proof taken from http://cstheory.wordpress.com/2010/08/07/jungs-theorem/  *)
+(* ------------------------------------------------------------------------- *)
+
+let JUNG = prove
+ (`!s:real^N->bool r.
+        bounded s /\
+        sqrt(&(dimindex(:N)) / &(2 * dimindex(:N) + 2)) * diameter s <= r
+        ==> ?a. s SUBSET cball(a,r)`,
+  let lemma = prove
+   (`&0 < x /\ x <= y ==> (x - &1) / x <= (y - &1) / y`,
+    SIMP_TAC[REAL_LE_LDIV_EQ] THEN REPEAT STRIP_TAC THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `x / y * z:real = (x * z) / y`] THEN
+    SUBGOAL_THEN `&0 < y` ASSUME_TAC THENL
+     [ASM_REAL_ARITH_TAC; ASM_SIMP_TAC[REAL_LE_RDIV_EQ]] THEN
+    ASM_REAL_ARITH_TAC) in
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `&0 <= r` ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+        REAL_LE_TRANS)) THEN
+    MATCH_MP_TAC REAL_LE_MUL THEN ASM_SIMP_TAC[DIAMETER_POS_LE] THEN
+    SIMP_TAC[SQRT_POS_LE; REAL_LE_DIV; REAL_POS];
+    ALL_TAC] THEN
+  MP_TAC(ISPEC `IMAGE (\x:real^N. cball(x,r)) s` HELLY_COMPACT_ALT) THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; COMPACT_CBALL; CONVEX_CBALL] THEN
+  REWRITE_TAC[TAUT `p /\ q /\ r ==> s <=> q /\ p ==> r ==> s`] THEN
+  REWRITE_TAC[FORALL_FINITE_SUBSET_IMAGE] THEN
+  REWRITE_TAC[INTERS_IMAGE; GSYM MEMBER_NOT_EMPTY] THEN
+  REWRITE_TAC[SUBSET; IN_CBALL; IN_ELIM_THM] THEN
+  ANTS_TAC THENL [ALL_TAC; MESON_TAC[DIST_SYM]] THEN
+  X_GEN_TAC `t:real^N->bool` THEN REWRITE_TAC[GSYM SUBSET] THEN
+  STRIP_TAC THEN
+  ASM_SIMP_TAC[CARD_IMAGE_INJ; EQ_BALLS; GSYM REAL_NOT_LE] THEN
+  UNDISCH_TAC `FINITE(t:real^N->bool)` THEN
+  SUBGOAL_THEN `bounded(t:real^N->bool)` MP_TAC THENL
+   [ASM_MESON_TAC[BOUNDED_SUBSET]; ALL_TAC] THEN
+  UNDISCH_TAC `&0 <= r` THEN
+  SUBGOAL_THEN
+   `sqrt(&(dimindex(:N)) / &(2 * dimindex(:N) + 2)) *
+    diameter(t:real^N->bool) <= r`
+  MP_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+        REAL_LE_TRANS)) THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN
+    ASM_SIMP_TAC[DIAMETER_SUBSET; SQRT_POS_LE; REAL_POS; REAL_LE_DIV];
+    POP_ASSUM_LIST(K ALL_TAC) THEN
+    SPEC_TAC(`t:real^N->bool`,`s:real^N->bool`) THEN
+    REPEAT STRIP_TAC] THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN
+  MP_TAC(ISPEC `{d | &0 <= d /\ ?a:real^N. s SUBSET cball(a,d)}` INF) THEN
+  ABBREV_TAC `d = inf {d | &0 <= d /\ ?a:real^N. s SUBSET cball(a,d)}` THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN ANTS_TAC THENL
+   [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+    ASM_MESON_TAC[BOUNDED_SUBSET_CBALL; REAL_LT_IMP_LE];
+    DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "P") (LABEL_TAC "M"))] THEN
+  SUBGOAL_THEN `&0 <= d` ASSUME_TAC THENL
+   [ASM_MESON_TAC[REAL_LE_REFL]; ALL_TAC] THEN
+  SUBGOAL_THEN `?a:real^N. s SUBSET cball(a,d)` MP_TAC THENL
+   [SUBGOAL_THEN
+     `!n. ?a:real^N. s SUBSET cball(a,d + inv(&n + &1))`
+    MP_TAC THENL
+     [X_GEN_TAC `n:num` THEN
+      REMOVE_THEN "M" (MP_TAC o SPEC `d + inv(&n + &1)`) THEN
+      REWRITE_TAC[REAL_ARITH `d + i <= d <=> ~(&0 < i)`] THEN
+      REWRITE_TAC[REAL_LT_INV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+      REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; REAL_NOT_LE] THEN
+      MESON_TAC[SUBSET_CBALL; REAL_LT_IMP_LE; SUBSET_TRANS];
+      ALL_TAC] THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+    X_GEN_TAC `aa:num->real^N` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `?t. compact t /\ !n. (aa:num->real^N) n IN t` MP_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `vec 0:real^N` o
+        MATCH_MP BOUNDED_SUBSET_CBALL) THEN
+      REWRITE_TAC[LEFT_IMP_EXISTS_THM; SUBSET; IN_CBALL_0] THEN
+      X_GEN_TAC `B:real` THEN STRIP_TAC THEN
+      EXISTS_TAC `cball(vec 0:real^N,B + d + &1)` THEN
+      REWRITE_TAC[COMPACT_CBALL; IN_CBALL_0] THEN X_GEN_TAC `n:num` THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; IN_CBALL]) THEN
+      MATCH_MP_TAC(NORM_ARITH
+       `(?x:real^N. norm(x) <= B /\ dist(a,x) <= d) ==> norm(a) <= B + d`) THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+      MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `d + inv(&n + &1)` THEN
+      ASM_SIMP_TAC[REAL_LE_LADD] THEN
+      MATCH_MP_TAC REAL_INV_LE_1 THEN REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[compact; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `t:real^N->bool` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    DISCH_THEN(MP_TAC o SPEC `aa:num->real^N`) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+    DISCH_THEN(X_CHOOSE_THEN `r:num->num` STRIP_ASSUME_TAC) THEN
+    REWRITE_TAC[SUBSET; IN_CBALL] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN
+    MP_TAC(SPEC `(dist(a:real^N,x) - d) / &2` REAL_ARCH_INV) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIM_SEQUENTIALLY]) THEN
+    DISCH_THEN(MP_TAC o SPEC `(dist(a:real^N,x) - d) / &2`) THEN
+    ASM_SIMP_TAC[REAL_SUB_LT; REAL_HALF; o_THM] 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 GEN_REWRITE_RULE BINDER_CONV [SUBSET]) THEN
+    DISCH_THEN(MP_TAC o SPECL [`(r:num->num)(N1 + N2)`; `x:real^N`]) THEN
+    ASM_REWRITE_TAC[IN_CBALL; REAL_NOT_LE] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `N1 + N2:num`) THEN
+    ASM_REWRITE_TAC[LE_ADD] THEN
+    SUBGOAL_THEN `inv(&(r (N1 + N2:num)) + &1) < (dist(a:real^N,x) - d) / &2`
+    MP_TAC THENL [ALL_TAC; NORM_ARITH_TAC] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `inv(&N2)` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[REAL_LT_INV_EQ]; ALL_TAC] THEN
+    REWRITE_TAC[REAL_OF_NUM_LE; REAL_OF_NUM_ADD] THEN
+    MATCH_MP_TAC(ARITH_RULE
+      `N1 + N2 <= r(N1 + N2) ==> N2 <= r(N1 + N2) + 1`) THEN
+    ASM_MESON_TAC[MONOTONE_BIGGER];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+  ONCE_REWRITE_TAC[DIST_SYM] THEN
+  REWRITE_TAC[GSYM IN_CBALL; GSYM SUBSET] THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] SUBSET_TRANS) THEN
+  MATCH_MP_TAC SUBSET_CBALL THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+   `a * s <= r ==> d <= a * s ==> d <= r`)) THEN
+  UNDISCH_THEN `&0 <= r` (K ALL_TAC) THEN REMOVE_THEN "M" (K ALL_TAC) THEN
+  FIRST_X_ASSUM(K ALL_TAC o SYM) THEN REMOVE_THEN "P" MP_TAC THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+  ABBREV_TAC `n = CARD(s:real^N->bool)` THEN
+  SUBGOAL_THEN `(s:real^N->bool) HAS_SIZE n` MP_TAC THENL
+   [ASM_REWRITE_TAC[HAS_SIZE]; ALL_TAC] THEN
+  UNDISCH_THEN `CARD(s:real^N->bool) = n` (K ALL_TAC) THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ o rev) THEN
+  SPEC_TAC(`d:real`,`r:real`) THEN GEN_TAC THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN SIMP_TAC[HAS_SIZE] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+  ABBREV_TAC `t = {x:real^N | x IN s /\ norm(x) = r}` THEN
+  SUBGOAL_THEN `FINITE(t:real^N->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "t" THEN ASM_SIMP_TAC[FINITE_RESTRICT]; ALL_TAC] THEN
+  SUBGOAL_THEN `(vec 0:real^N) IN convex hull t` MP_TAC THENL
+   [MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+    MP_TAC(ISPEC `convex hull t:real^N->bool`
+      SEPARATING_HYPERPLANE_CLOSED_0) THEN
+    ASM_SIMP_TAC[CONVEX_CONVEX_HULL; NOT_IMP; COMPACT_CONVEX_HULL;
+                 FINITE_IMP_COMPACT; COMPACT_IMP_CLOSED] THEN
+    REWRITE_TAC[NOT_EXISTS_THM; TAUT `~(p /\ q) <=> p ==> ~q`] THEN
+    X_GEN_TAC `v:real^N` THEN
+    ABBREV_TAC `k = CARD(s:real^N->bool)` THEN
+    SUBGOAL_THEN `(s:real^N->bool) HAS_SIZE k` MP_TAC THENL
+     [ASM_REWRITE_TAC[HAS_SIZE]; ALL_TAC] THEN
+    UNDISCH_THEN `CARD(s:real^N->bool) = k` (K ALL_TAC) THEN
+    POP_ASSUM_LIST(MP_TAC o end_itlist CONJ o rev) THEN
+    GEOM_BASIS_MULTIPLE_TAC 1 `v:real^N` THEN X_GEN_TAC `m:real` THEN
+    GEN_REWRITE_TAC LAND_CONV [REAL_ARITH `&0 <= x <=> x = &0 \/ &0 < x`] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[VECTOR_MUL_EQ_0] THEN
+    ASM_SIMP_TAC[BASIS_NONZERO; DIMINDEX_GE_1; LE_REFL; REAL_LT_IMP_NZ] THEN
+    REPEAT GEN_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[HAS_SIZE] THEN
+    DISCH_THEN(SUBST_ALL_TAC o SYM) THEN X_GEN_TAC `b:real` THEN DISCH_TAC THEN
+    ASM_SIMP_TAC[DOT_LMUL; DOT_BASIS; DIMINDEX_GE_1; LE_REFL] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[real_gt; GSYM REAL_LT_LDIV_EQ] THEN
+    SUBGOAL_THEN `&0 < b / m` MP_TAC THENL
+     [ASM_SIMP_TAC[REAL_LT_DIV];
+      UNDISCH_THEN `&0 < b` (K ALL_TAC) THEN
+      SPEC_TAC(`b / m:real`,`b:real`)] THEN
+    X_GEN_TAC `b:real` THEN DISCH_TAC THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `!x:real^N e. &0 < e /\ e < b /\ x IN t ==> norm(x - e % basis 1) < r`
+    ASSUME_TAC THENL
+     [MAP_EVERY X_GEN_TAC [`x:real^N`; `e:real`] THEN STRIP_TAC THEN
+      SUBGOAL_THEN `r = norm(x:real^N)` SUBST1_TAC THENL
+       [ASM SET_TAC[]; REWRITE_TAC[NORM_LT; dot]] THEN
+      SIMP_TAC[SUM_CLAUSES_LEFT; DIMINDEX_GE_1] THEN
+      SIMP_TAC[VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT;
+               BASIS_COMPONENT; DIMINDEX_GE_1; LE_REFL;
+               ARITH_RULE `2 <= n ==> 1 <= n /\ ~(n = 1)`; ARITH] THEN
+      REWRITE_TAC[REAL_MUL_RZERO; REAL_SUB_RZERO; REAL_LT_RADD] THEN
+      REWRITE_TAC[GSYM REAL_POW_2; GSYM REAL_LT_SQUARE_ABS] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `!b. &0 < e /\ e < b /\ b < x ==> abs(x - e * &1) < abs x`) THEN
+      EXISTS_TAC `b:real` THEN ASM_REWRITE_TAC[] THEN
+      ASM_MESON_TAC[HULL_INC];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?d. &0 < d /\
+          !x:real^N a. x IN (s DIFF t) /\ norm(a) < d ==> norm(x - a) < r`
+    STRIP_ASSUME_TAC THENL
+     [ASM_CASES_TAC `s DIFF t:real^N->bool = {}` THENL
+       [ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN MESON_TAC[REAL_LT_01]; ALL_TAC] THEN
+      EXISTS_TAC `inf (IMAGE (\x:real^N. r - norm x) (s DIFF t))` THEN
+      SUBGOAL_THEN `FINITE(s DIFF t:real^N->bool)` ASSUME_TAC THENL
+       [ASM_MESON_TAC[FINITE_DIFF]; ALL_TAC] THEN
+      ASM_SIMP_TAC[REAL_LT_INF_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE] THEN SIMP_TAC
+       [NORM_ARITH `norm a < r - norm x ==> norm(x - a:real^N) < r`] THEN
+      EXPAND_TAC "t" THEN REWRITE_TAC[IN_DIFF; IN_ELIM_THM; REAL_SUB_LT] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; IN_CBALL_0]) THEN
+      ASM_MESON_TAC[REAL_LT_LE];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?a. !x. x IN s ==> norm(x - a:real^N) < r`
+    STRIP_ASSUME_TAC THENL
+     [EXISTS_TAC `min (b / &2) (d / &2) % basis 1:real^N` THEN
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+      ASM_CASES_TAC `(x:real^N) IN t` THENL
+       [MATCH_MP_TAC(ASSUME
+         `!x:real^N e. &0 < e /\ e < b /\ x IN t
+                       ==> norm (x - e % basis 1) < r`) THEN
+        ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+        MATCH_MP_TAC(ASSUME
+         `!x:real^N a. x IN s DIFF t /\ norm a < d ==> norm (x - a) < r`) THEN
+        ASM_SIMP_TAC[IN_DIFF; NORM_MUL; LE_REFL; NORM_BASIS;
+                     DIMINDEX_GE_1] THEN
+        ASM_REAL_ARITH_TAC];
+      SUBGOAL_THEN `&0 < r` ASSUME_TAC THENL
+       [ASM_MESON_TAC[MEMBER_NOT_EMPTY; NORM_ARITH
+         `norm(x:real^N) < r ==> &0 < r`];
+        ALL_TAC] THEN
+      UNDISCH_THEN
+        `!x a:real^N. &0 <= x /\ s SUBSET cball (a,x) ==> r <= x` (MP_TAC o
+        SPECL [`max (&0) (r - inf (IMAGE (\x:real^N. r - norm(x - a)) s))`;
+               `a:real^N`]) THEN
+      ASM_SIMP_TAC[REAL_ARITH `&0 < r ==> (r <= max (&0) a <=> r <= a)`] THEN
+      REWRITE_TAC[SUBSET; IN_CBALL; REAL_ARITH `a <= max a b`] THEN
+      REWRITE_TAC[NOT_IMP; REAL_ARITH `~(r <= r - x) <=> &0 < x`] THEN
+      ASM_SIMP_TAC[REAL_LT_INF_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+      ASM_REWRITE_TAC[FORALL_IN_IMAGE; REAL_SUB_LT] THEN
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH `d <= b ==> d <= max a b`) THEN
+      ONCE_REWRITE_TAC[REAL_ARITH `a <= b - c <=> c <= b - a`] THEN
+      ASM_SIMP_TAC[REAL_INF_LE_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+      REWRITE_TAC[EXISTS_IN_IMAGE; ONCE_REWRITE_RULE[NORM_SUB] dist] THEN
+      ASM_MESON_TAC[REAL_LE_REFL]];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[CONVEX_HULL_EMPTY; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[CONVEX_HULL_FINITE; IN_ELIM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `l:real^N->real` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sqrt((&(dimindex (:N)) / &(2 * dimindex (:N) + 2)) *
+                   diameter(s:real^N->bool) pow 2)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_LE_RSQRT;
+    ASM_SIMP_TAC[SQRT_MUL; DIAMETER_POS_LE; REAL_POW_LE; REAL_LE_DIV;
+                 REAL_POS; POW_2_SQRT; REAL_LE_REFL]] THEN
+
+  SUBGOAL_THEN
+   `sum t (\y:real^N. &2 * r pow 2) <=
+    sum t (\y. (&1 - l y) * diameter(s:real^N->bool) pow 2)`
+  MP_TAC THENL
+   [MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum (t DELETE x) (\x:real^N. l(x)) *
+                diameter(s:real^N->bool) pow 2` THEN CONJ_TAC THENL
+     [ALL_TAC; ASM_SIMP_TAC[SUM_DELETE; ETA_AX; REAL_LE_REFL]] THEN
+    REWRITE_TAC[GSYM SUM_RMUL] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum (t DELETE x) (\y:real^N. l y * norm(y - x) pow 2)` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[FINITE_DELETE; IN_DELETE] THEN
+      X_GEN_TAC `y:real^N` THEN STRIP_TAC THEN MATCH_MP_TAC REAL_LE_LMUL THEN
+      ASM_SIMP_TAC[] THEN MATCH_MP_TAC REAL_POW_LE2 THEN
+      REWRITE_TAC[NORM_POS_LE] THEN
+      MATCH_MP_TAC DIAMETER_BOUNDED_BOUND THEN ASM SET_TAC[]] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum t (\y:real^N. l y * norm (y - x) pow 2)` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC REAL_EQ_IMP_LE THEN MATCH_MP_TAC SUM_EQ_SUPERSET THEN
+      ASM_REWRITE_TAC[FINITE_DELETE] THEN
+      CONJ_TAC THENL [SET_TAC[]; REWRITE_TAC[IN_DELETE]] THEN
+      SIMP_TAC[TAUT `p /\ ~(p /\ ~q) <=> p /\ q`] THEN
+      REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN REAL_ARITH_TAC] THEN
+    REWRITE_TAC[NORM_POW_2; VECTOR_ARITH
+     `(y - x:real^N) dot (y - x) = (x dot x + y dot y) - &2 * x dot y`] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum t (\y:real^N. l y * (&2 * r pow 2 - &2 * (x dot y)))` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC REAL_EQ_IMP_LE THEN MATCH_MP_TAC SUM_EQ THEN
+      UNDISCH_TAC `(x:real^N) IN t` THEN EXPAND_TAC "t" THEN
+      REWRITE_TAC[IN_DELETE; IN_ELIM_THM] THEN
+      SIMP_TAC[NORM_EQ_SQUARE; NORM_POW_2] THEN REAL_ARITH_TAC] THEN
+    REWRITE_TAC[REAL_ARITH `x * (&2 * y - &2 * z) = &2 * (x * y - x * z)`] THEN
+    REWRITE_TAC[SUM_LMUL] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
+    REWRITE_TAC[REAL_POS] THEN
+    ASM_SIMP_TAC[SUM_SUB; FINITE_DELETE; SUM_RMUL] THEN
+    REWRITE_TAC[GSYM DOT_RMUL] THEN
+    ASM_SIMP_TAC[GSYM DOT_RSUM; DOT_RZERO] THEN REAL_ARITH_TAC;
+    ASM_SIMP_TAC[SUM_CONST; SUM_RMUL; SUM_SUB] THEN
+    REWRITE_TAC[REAL_OF_NUM_MUL; MULT_CLAUSES] THEN
+    GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [REAL_MUL_SYM] THEN
+    SUBGOAL_THEN `&0 < &(CARD(t:real^N->bool) * 2)` ASSUME_TAC THENL
+     [REWRITE_TAC[REAL_OF_NUM_LT; ARITH_RULE `0 < n * 2 <=> ~(n = 0)`] THEN
+      ASM_SIMP_TAC[CARD_EQ_0];
+      ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+      REWRITE_TAC[REAL_ARITH `(a * b) / c:real = a / c * b`] THEN
+      MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[REAL_LE_POW_2] THEN
+      REWRITE_TAC[ARITH_RULE `2 * n + 2 = (n + 1) * 2`; GSYM REAL_OF_NUM_MUL;
+                  real_div; REAL_INV_MUL; REAL_MUL_ASSOC] THEN
+      MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[GSYM real_div] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      SUBGOAL_THEN `&(dimindex(:N)) = &(dimindex(:N) + 1) - &1`
+      SUBST1_TAC THENL
+       [REWRITE_TAC[GSYM REAL_OF_NUM_ADD] THEN REAL_ARITH_TAC;
+        MATCH_MP_TAC lemma THEN
+        ASM_SIMP_TAC[REAL_OF_NUM_LE; REAL_OF_NUM_LT; CARD_EQ_0;
+                     ARITH_RULE `0 < n <=> ~(n = 0)`] THEN
+        MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `CARD(s:real^N->bool)` THEN
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CARD_SUBSET THEN
+        ASM SET_TAC[]]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Convex cones and corresponding hulls.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let convex_cone = new_definition
+ `convex_cone s <=> ~(s = {}) /\ convex s /\ conic s`;;
+
+let CONVEX_CONE = prove
+ (`!s:real^N->bool.
+     convex_cone s <=>
+        vec 0 IN s /\
+        (!x y. x IN s /\ y IN s ==> (x + y) IN s) /\
+        (!x c. x IN s /\ &0 <= c ==> (c % x) IN s)`,
+  GEN_TAC THEN REWRITE_TAC[convex_cone; GSYM conic] THEN
+  ASM_CASES_TAC `conic(s:real^N->bool)` THEN
+  ASM_SIMP_TAC[CONIC_CONTAINS_0] THEN AP_TERM_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[conic]) THEN
+  REWRITE_TAC[convex] THEN EQ_TAC THEN
+  ASM_SIMP_TAC[REAL_SUB_LE] THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+   [`&2 % (x:real^N)`; `&2 % (y:real^N)`; `&1 / &2`; `&1 / &2`]) THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  ASM_SIMP_TAC[VECTOR_MUL_LID; REAL_POS]);;
+
+let CONVEX_CONE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        convex_cone s /\ linear f ==> convex_cone(IMAGE f s)`,
+  SIMP_TAC[convex_cone; CONVEX_LINEAR_IMAGE; IMAGE_EQ_EMPTY;
+           CONIC_LINEAR_IMAGE]);;
+
+let CONVEX_CONE_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (convex_cone(IMAGE f s) <=> convex_cone s)`,
+  REWRITE_TAC[convex_cone] THEN
+  MESON_TAC[IMAGE_EQ_EMPTY; CONVEX_LINEAR_IMAGE_EQ; CONIC_LINEAR_IMAGE_EQ]);;
+
+add_linear_invariants [CONVEX_CONE_LINEAR_IMAGE_EQ];;
+
+let CONVEX_CONE_HALFSPACE_GE = prove
+ (`!a. convex_cone {x | a dot x >= &0}`,
+  SIMP_TAC[CONVEX_CONE; real_ge; IN_ELIM_THM; DOT_RZERO; DOT_RADD; DOT_RMUL;
+           REAL_LE_ADD; REAL_LE_MUL; REAL_LE_REFL]);;
+
+let CONVEX_CONE_HALFSPACE_LE = prove
+ (`!a. convex_cone {x | a dot x <= &0}`,
+  REWRITE_TAC[REAL_ARITH `x <= &0 <=> &0 <= --x`; GSYM DOT_LNEG] THEN
+  REWRITE_TAC[GSYM real_ge; CONVEX_CONE_HALFSPACE_GE]);;
+
+let CONVEX_CONE_CONTAINS_0 = prove
+ (`!s:real^N->bool. convex_cone s ==> vec 0 IN s`,
+  SIMP_TAC[CONVEX_CONE]);;
+
+let CONVEX_CONE_INTERS = prove
+ (`!f. (!s:real^N->bool. s IN f ==> convex_cone s) ==> convex_cone(INTERS f)`,
+  SIMP_TAC[convex_cone; CONIC_INTERS; CONVEX_INTERS] THEN
+  REWRITE_TAC[GSYM convex_cone] THEN GEN_TAC THEN DISCH_TAC THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `vec 0:real^N` THEN
+  ASM_SIMP_TAC[IN_INTERS; CONVEX_CONE_CONTAINS_0]);;
+
+let CONVEX_CONE_CONVEX_CONE_HULL = prove
+ (`!s. convex_cone(convex_cone hull s)`,
+  SIMP_TAC[P_HULL; CONVEX_CONE_INTERS]);;
+
+let CONVEX_CONVEX_CONE_HULL = prove
+ (`!s. convex(convex_cone hull s)`,
+  MESON_TAC[CONVEX_CONE_CONVEX_CONE_HULL; convex_cone]);;
+
+let CONIC_CONVEX_CONE_HULL = prove
+ (`!s. conic(convex_cone hull s)`,
+  MESON_TAC[CONVEX_CONE_CONVEX_CONE_HULL; convex_cone]);;
+
+let CONVEX_CONE_HULL_NONEMPTY = prove
+ (`!s. ~(convex_cone hull s = {})`,
+  MESON_TAC[CONVEX_CONE_CONVEX_CONE_HULL; convex_cone]);;
+
+let CONVEX_CONE_HULL_CONTAINS_0 = prove
+ (`!s. vec 0 IN convex_cone hull s`,
+  MESON_TAC[CONVEX_CONE_CONVEX_CONE_HULL; CONVEX_CONE]);;
+
+let CONVEX_CONE_HULL_ADD = prove
+ (`!s x y:real^N.
+        x IN convex_cone hull s /\ y IN convex_cone hull s
+        ==> x + y IN convex_cone hull s`,
+  MESON_TAC[CONVEX_CONE; CONVEX_CONE_CONVEX_CONE_HULL]);;
+
+let CONVEX_CONE_HULL_MUL = prove
+ (`!s c x:real^N.
+        &0 <= c /\ x IN convex_cone hull s
+        ==> (c % x) IN convex_cone hull s`,
+  MESON_TAC[CONVEX_CONE; CONVEX_CONE_CONVEX_CONE_HULL]);;
+
+let CONVEX_CONE_SUMS = prove
+ (`!s t. convex_cone s /\ convex_cone t
+         ==> convex_cone {x + y:real^N | x IN s /\ y IN t}`,
+  SIMP_TAC[convex_cone; CONIC_SUMS; CONVEX_SUMS] THEN SET_TAC[]);;
+
+let CONVEX_CONE_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        convex_cone s /\ convex_cone t ==> convex_cone(s PCROSS t)`,
+  SIMP_TAC[convex_cone; CONVEX_PCROSS; CONIC_PCROSS; PCROSS_EQ_EMPTY]);;
+
+let CONVEX_CONE_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        convex_cone(s PCROSS t) <=> convex_cone s /\ convex_cone t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THENL
+   [ASM_REWRITE_TAC[PCROSS_EMPTY; convex_cone]; ALL_TAC] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[PCROSS_EMPTY; convex_cone]; ALL_TAC] THEN
+  EQ_TAC THEN REWRITE_TAC[CONVEX_CONE_PCROSS] THEN REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL [`fstcart:real^(M,N)finite_sum->real^M`;
+     `(s:real^M->bool) PCROSS (t:real^N->bool)`] CONVEX_CONE_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_FSTCART];
+    MP_TAC(ISPECL [`sndcart:real^(M,N)finite_sum->real^N`;
+     `(s:real^M->bool) PCROSS (t:real^N->bool)`] CONVEX_CONE_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_SNDCART]] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; EXISTS_PASTECART; PASTECART_IN_PCROSS;
+              FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  ASM SET_TAC[]);;
+
+let CONVEX_CONE_HULL_UNION = prove
+ (`!s t. convex_cone hull(s UNION t) =
+         {x + y:real^N | x IN convex_cone hull s /\ y IN convex_cone hull t}`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HULL_MINIMAL THEN
+    SIMP_TAC[CONVEX_CONE_SUMS; CONVEX_CONE_CONVEX_CONE_HULL] THEN
+    REWRITE_TAC[SUBSET; IN_UNION; IN_ELIM_THM] THEN
+    X_GEN_TAC `x:real^N` THEN STRIP_TAC THENL
+     [MAP_EVERY EXISTS_TAC [`x:real^N`; `vec 0:real^N`] THEN
+      ASM_SIMP_TAC[HULL_INC; CONVEX_CONE_HULL_CONTAINS_0; VECTOR_ADD_RID];
+      MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `x:real^N`] THEN
+      ASM_SIMP_TAC[HULL_INC; CONVEX_CONE_HULL_CONTAINS_0; VECTOR_ADD_LID]];
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC CONVEX_CONE_HULL_ADD THEN
+    ASM_MESON_TAC[HULL_MONO; SUBSET_UNION; SUBSET]]);;
+
+let CONVEX_CONE_SING = prove
+ (`convex_cone {vec 0}`,
+  SIMP_TAC[CONVEX_CONE; IN_SING; VECTOR_ADD_LID; VECTOR_MUL_RZERO]);;
+
+let CONVEX_HULL_SUBSET_CONVEX_CONE_HULL = prove
+ (`!s. convex hull s SUBSET convex_cone hull s`,
+  GEN_TAC THEN MATCH_MP_TAC HULL_ANTIMONO THEN
+  SIMP_TAC[convex_cone; SUBSET; IN]);;
+
+let CONIC_HULL_SUBSET_CONVEX_CONE_HULL = prove
+ (`!s. conic hull s SUBSET convex_cone hull s`,
+  GEN_TAC THEN MATCH_MP_TAC HULL_ANTIMONO THEN
+  SIMP_TAC[convex_cone; SUBSET; IN]);;
+
+let CONVEX_CONE_HULL_SEPARATE_NONEMPTY = prove
+ (`!s:real^N->bool.
+    ~(s = {})
+    ==> convex_cone hull s = conic hull (convex hull s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THEN
+  MATCH_MP_TAC HULL_MINIMAL THEN
+  REWRITE_TAC[CONIC_CONVEX_CONE_HULL; CONVEX_HULL_SUBSET_CONVEX_CONE_HULL] THEN
+  ASM_SIMP_TAC[CONVEX_CONIC_HULL; CONVEX_CONVEX_HULL; CONIC_CONIC_HULL;
+               convex_cone; CONIC_HULL_EQ_EMPTY; CONVEX_HULL_EQ_EMPTY] THEN
+  ASM_MESON_TAC[HULL_SUBSET; SUBSET_REFL; SUBSET_TRANS]);;
+
+let CONVEX_CONE_HULL_EMPTY = prove
+ (`convex_cone hull {} = {vec 0}`,
+  MATCH_MP_TAC HULL_UNIQUE THEN
+  REWRITE_TAC[CONVEX_CONE_CONTAINS_0; EMPTY_SUBSET; CONVEX_CONE_SING;
+              SET_RULE `{a} SUBSET s <=> a IN s`; CONVEX_CONE_CONTAINS_0]);;
+
+let CONVEX_CONE_HULL_SEPARATE = prove
+ (`!s:real^N->bool.
+    convex_cone hull s = vec 0 INSERT conic hull (convex hull s)`,
+  GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[CONVEX_CONE_HULL_EMPTY; CONVEX_HULL_EMPTY; CONIC_HULL_EMPTY] THEN
+  ASM_SIMP_TAC[CONVEX_CONE_HULL_SEPARATE_NONEMPTY] THEN
+  MATCH_MP_TAC(SET_RULE `a IN s ==> s = a INSERT s`) THEN
+  ASM_SIMP_TAC[CONIC_CONTAINS_0; CONIC_CONIC_HULL] THEN
+  ASM_REWRITE_TAC[CONIC_HULL_EQ_EMPTY; CONVEX_HULL_EQ_EMPTY]);;
+
+let CONVEX_CONE_HULL_CONVEX_HULL_NONEMPTY = prove
+ (`!s:real^N->bool.
+        ~(s = {})
+        ==> convex_cone hull s = {c % x | &0 <= c /\ x IN convex hull s}`,
+  SIMP_TAC[CONVEX_CONE_HULL_SEPARATE_NONEMPTY; CONIC_HULL_EXPLICIT]);;
+
+let CONVEX_CONE_HULL_CONVEX_HULL = prove
+ (`!s:real^N->bool.
+        convex_cone hull s =
+        vec 0 INSERT {c % x | &0 <= c /\ x IN convex hull s}`,
+  REWRITE_TAC[CONVEX_CONE_HULL_SEPARATE; CONIC_HULL_EXPLICIT]);;
+
+let CONVEX_CONE_HULL_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f
+        ==> convex_cone hull (IMAGE f s) = IMAGE f (convex_cone hull s)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:real^M-> bool = {}` THEN
+  ASM_SIMP_TAC[CONVEX_CONE_HULL_SEPARATE_NONEMPTY; IMAGE_EQ_EMPTY;
+               CONVEX_HULL_LINEAR_IMAGE; CONIC_HULL_LINEAR_IMAGE] THEN
+  REWRITE_TAC[IMAGE_CLAUSES; CONVEX_CONE_HULL_EMPTY] THEN
+  MATCH_MP_TAC(SET_RULE `f x = y ==> {y} = {f x}`) THEN
+  ASM_MESON_TAC[LINEAR_0]);;
+
+add_linear_invariants [CONVEX_CONE_HULL_LINEAR_IMAGE];;
+
+let SUBSPACE_IMP_CONVEX_CONE = prove
+ (`!s. subspace s ==> convex_cone s`,
+  SIMP_TAC[subspace; CONVEX_CONE]);;
+
+let CONVEX_CONE_SPAN = prove
+ (`!s. convex_cone(span s)`,
+  SIMP_TAC[convex_cone; CONVEX_SPAN; CONIC_SPAN; GSYM MEMBER_NOT_EMPTY] THEN
+  MESON_TAC[SPAN_0]);;
+
+let CONVEX_CONE_NEGATIONS = prove
+ (`!s. convex_cone s ==> convex_cone (IMAGE (--) s)`,
+  SIMP_TAC[convex_cone; IMAGE_EQ_EMPTY; CONIC_NEGATIONS; CONVEX_NEGATIONS]);;
+
+let SUBSPACE_CONVEX_CONE_SYMMETRIC = prove
+ (`!s:real^N->bool.
+        subspace s <=> convex_cone s /\ (!x. x IN s ==> --x IN s)`,
+  GEN_TAC THEN REWRITE_TAC[subspace; CONVEX_CONE] THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_SIMP_TAC[] THENL
+   [ASM_MESON_TAC[VECTOR_ARITH `--x:real^N = -- &1 % x`];
+    MAP_EVERY X_GEN_TAC [`c:real`; `x:real^N`] THEN DISCH_TAC THEN
+    DISJ_CASES_TAC(SPEC `c:real` REAL_LE_NEGTOTAL) THEN ASM_SIMP_TAC[] THEN
+    ASM_MESON_TAC[VECTOR_ARITH `c % x:real^N = --(--c % x)`]]);;
+
+let SPAN_CONVEX_CONE_ALLSIGNS = prove
+ (`!s:real^N->bool. span s = convex_cone hull (s UNION IMAGE (--) s)`,
+  GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SPAN_SUBSET_SUBSPACE THEN CONJ_TAC THENL
+     [MESON_TAC[HULL_SUBSET; SUBSET_UNION; SUBSET_TRANS]; ALL_TAC] THEN
+    REWRITE_TAC[SUBSPACE_CONVEX_CONE_SYMMETRIC;
+                CONVEX_CONE_CONVEX_CONE_HULL] THEN
+    MATCH_MP_TAC HULL_INDUCT THEN CONJ_TAC THENL
+     [X_GEN_TAC `x:real^N` THEN REWRITE_TAC[IN_UNION; IN_IMAGE] THEN
+      DISCH_TAC THEN MATCH_MP_TAC HULL_INC THEN
+      REWRITE_TAC[IN_UNION; IN_IMAGE] THEN ASM_MESON_TAC[VECTOR_NEG_NEG];
+      SUBGOAL_THEN `!s. {x:real^N | (--x) IN s} = IMAGE (--) s`
+       (fun th -> SIMP_TAC[th; CONVEX_CONE_NEGATIONS;
+                           CONVEX_CONE_CONVEX_CONE_HULL]) THEN
+      GEN_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+      REWRITE_TAC[IN_ELIM_THM] THEN MESON_TAC[VECTOR_NEG_NEG]];
+    MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_CONE_SPAN] THEN
+    REWRITE_TAC[UNION_SUBSET; SPAN_INC] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    MESON_TAC[SPAN_SUPERSET; SPAN_NEG]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Epigraphs of convex functions.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let epigraph = new_definition
+  `epigraph s (f:real^N->real) =
+       {xy:real^((N,1)finite_sum) |
+             fstcart xy IN s /\ f(fstcart xy) <= drop(sndcart xy)}`;;
+
+let IN_EPIGRAPH = prove
+ (`!x y. (pastecart x (lift y)) IN epigraph s f <=> x IN s /\ f(x) <= y`,
+  REWRITE_TAC[epigraph; IN_ELIM_THM; FSTCART_PASTECART; SNDCART_PASTECART;
+              LIFT_DROP]);;
+
+let CONVEX_EPIGRAPH = prove
+ (`!f s. f convex_on s /\ convex s <=> convex(epigraph s f)`,
+  REWRITE_TAC[convex; convex_on; IN_ELIM_THM; SNDCART_ADD; SNDCART_CMUL;
+   epigraph; FSTCART_ADD; FSTCART_CMUL; FORALL_PASTECART; FSTCART_PASTECART;
+   SNDCART_PASTECART] THEN
+  REWRITE_TAC[GSYM FORALL_DROP; DROP_ADD; DROP_CMUL] THEN
+  MESON_TAC[REAL_LE_REFL; REAL_LE_ADD2; REAL_LE_LMUL; REAL_LE_TRANS]);;
+
+let CONVEX_EPIGRAPH_CONVEX = prove
+ (`!f s. convex s ==> (f convex_on s <=> convex(epigraph s f))`,
+  REWRITE_TAC[GSYM CONVEX_EPIGRAPH] THEN CONV_TAC TAUT);;
+
+let CONVEX_ON_EPIGRAPH_SLICE_LE = prove
+ (`!f:real^N->real s a.
+        f convex_on s /\ convex s ==> convex {x | x IN s /\ f(x) <= a}`,
+  SIMP_TAC[convex_on; convex; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(fun th ->
+    W(MP_TAC o PART_MATCH (lhand o rand) th o lhand o snd)) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+  MATCH_MP_TAC REAL_CONVEX_BOUND_LE THEN ASM_REWRITE_TAC[]);;
+
+let CONVEX_ON_EPIGRAPH_SLICE_LT = prove
+ (`!f:real^N->real s a.
+        f convex_on s /\ convex s ==> convex {x | x IN s /\ f(x) < a}`,
+  SIMP_TAC[convex_on; convex; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(fun th ->
+    W(MP_TAC o PART_MATCH (lhand o rand) th o lhand o snd)) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LET_TRANS) THEN
+  MATCH_MP_TAC REAL_CONVEX_BOUND_LT THEN ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Use this to derive general bound property of convex function.             *)
+(* ------------------------------------------------------------------------- *)
+
+let FORALL_OF_PASTECART = prove
+ (`(!p. P (fstcart o p) (sndcart o p)) <=> (!x:A->B^M y:A->B^N. P x y)`,
+  EQ_TAC THENL [ALL_TAC; MESON_TAC[]] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `\a:A. pastecart (x a :B^M) (y a :B^N)`) THEN
+  REWRITE_TAC[o_DEF; FSTCART_PASTECART; SNDCART_PASTECART; ETA_AX]);;
+
+let FORALL_OF_DROP = prove
+ (`(!v. P (drop o v)) <=> (!x:A->real. P x)`,
+  EQ_TAC THENL [ALL_TAC; MESON_TAC[]] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `\a:A. lift(x a)`) THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX]);;
+
+let CONVEX_ON_JENSEN = prove
+ (`!f:real^N->real s.
+        convex s
+        ==> (f convex_on s <=>
+                !k u x.
+                   (!i:num. 1 <= i /\ i <= k ==> &0 <= u(i) /\ x(i) IN s) /\
+                   (sum (1..k) u = &1)
+                   ==> f(vsum (1..k) (\i. u(i) % x(i)))
+                           <= sum (1..k) (\i. u(i) * f(x(i))))`,
+  let lemma = prove
+   (`(!x. P x ==> (Q x = R x)) ==> (!x. P x) ==> ((!x. Q x) <=> (!x. R x))`,
+    MESON_TAC[]) in
+  REPEAT STRIP_TAC THEN FIRST_ASSUM
+   (fun th -> REWRITE_TAC[MATCH_MP CONVEX_EPIGRAPH_CONVEX th]) THEN
+  REWRITE_TAC[CONVEX_INDEXED; epigraph] THEN
+  SIMP_TAC[IN_ELIM_THM; SNDCART_ADD; SNDCART_CMUL; FINITE_NUMSEG;
+           FSTCART_ADD; FSTCART_CMUL; FORALL_PASTECART; DROP_CMUL;
+           FSTCART_PASTECART; SNDCART_PASTECART;
+           FSTCART_VSUM; SNDCART_VSUM; DROP_VSUM; o_DEF] THEN
+  REWRITE_TAC[GSYM(ISPEC `fstcart` o_THM); GSYM(ISPEC `sndcart` o_THM)] THEN
+  REWRITE_TAC[GSYM(ISPEC `drop` o_THM)] THEN
+  REWRITE_TAC[FORALL_OF_PASTECART; FORALL_OF_DROP] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONVEX_INDEXED]) THEN
+  REPEAT(MATCH_MP_TAC lemma THEN GEN_TAC) THEN SIMP_TAC[] THEN
+  REWRITE_TAC[TAUT `a ==> b /\ c <=> (a ==> b) /\ (a ==> c)`] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN DISCH_THEN(K ALL_TAC) THEN
+  EQ_TAC THEN SIMP_TAC[REAL_LE_REFL] THEN
+  DISCH_THEN(fun th -> REPEAT STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REAL_ARITH `a <= b ==> x <= a ==> x <= b`) THEN
+  ASM_SIMP_TAC[SUM_LE_NUMSEG; REAL_LE_LMUL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Another intermediate value theorem formulation.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let IVT_INCREASING_COMPONENT_ON_1 = prove
+ (`!f:real^1->real^N a b y k.
+        drop a <= drop b /\ 1 <= k /\ k <= dimindex(:N) /\
+        f continuous_on interval[a,b] /\
+        f(a)$k <= y /\ y <= f(b)$k
+        ==> ?x. x IN interval[a,b] /\ f(x)$k = y`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`IMAGE (f:real^1->real^N) (interval[a,b])`]
+        CONNECTED_IVT_COMPONENT) THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE] THEN DISCH_THEN MATCH_MP_TAC THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; EXISTS_IN_IMAGE] THEN
+  ASM_SIMP_TAC[CONNECTED_CONTINUOUS_IMAGE; CONVEX_CONNECTED;
+               CONVEX_INTERVAL] THEN
+  EXISTS_TAC `a:real^1` THEN ASM_REWRITE_TAC[IN_INTERVAL_1; REAL_LE_REFL] THEN
+  EXISTS_TAC `b:real^1` THEN ASM_REWRITE_TAC[IN_INTERVAL_1; REAL_LE_REFL]);;
+
+let IVT_INCREASING_COMPONENT_1 = prove
+ (`!f:real^1->real^N a b y k.
+        drop a <= drop b /\ 1 <= k /\ k <= dimindex(:N) /\
+        (!x. x IN interval[a,b] ==> f continuous at x) /\
+        f(a)$k <= y /\ y <= f(b)$k
+        ==> ?x. x IN interval[a,b] /\ f(x)$k = y`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC IVT_INCREASING_COMPONENT_ON_1 THEN
+  ASM_SIMP_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON]);;
+
+let IVT_DECREASING_COMPONENT_ON_1 = prove
+ (`!f:real^1->real^N a b y k.
+        drop a <= drop b /\ 1 <= k /\ k <= dimindex(:N) /\
+        f continuous_on interval[a,b] /\
+        f(b)$k <= y /\ y <= f(a)$k
+        ==> ?x. x IN interval[a,b] /\ f(x)$k = y`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_EQ_NEG2] THEN
+  ASM_SIMP_TAC[GSYM VECTOR_NEG_COMPONENT] THEN
+  MATCH_MP_TAC IVT_INCREASING_COMPONENT_ON_1 THEN
+  ASM_SIMP_TAC[VECTOR_NEG_COMPONENT; CONTINUOUS_ON_NEG; REAL_LE_NEG2]);;
+
+let IVT_DECREASING_COMPONENT_1 = prove
+ (`!f:real^1->real^N a b y k.
+        drop a <= drop b /\ 1 <= k /\ k <= dimindex(:N) /\
+        (!x. x IN interval[a,b] ==> f continuous at x) /\
+        f(b)$k <= y /\ y <= f(a)$k
+        ==> ?x. x IN interval[a,b] /\ f(x)$k = y`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC IVT_DECREASING_COMPONENT_ON_1 THEN
+  ASM_SIMP_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A bound within a convex hull, and so an interval.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_ON_CONVEX_HULL_BOUND = prove
+ (`!f s b. f convex_on (convex hull s) /\
+           (!x:real^N. x IN s ==> f(x) <= b)
+           ==> !x. x IN convex hull s ==> f(x) <= b`,
+  REPEAT GEN_TAC THEN SIMP_TAC[CONVEX_ON_JENSEN; CONVEX_CONVEX_HULL] THEN
+  STRIP_TAC THEN GEN_TAC THEN REWRITE_TAC[CONVEX_HULL_INDEXED] THEN
+  REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`k:num`; `u:num->real`; `v:num->real^N`] THEN
+  DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum(1..k) (\i. u i * f(v i :real^N))` THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[SUBSET; HULL_SUBSET];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `sum(1..k) (\i. u i * b)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_LE_NUMSEG THEN ASM_SIMP_TAC[REAL_LE_LMUL];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[SUM_LMUL] THEN
+  ASM_MESON_TAC[REAL_LE_REFL; REAL_MUL_RID]);;
+
+let UNIT_INTERVAL_CONVEX_HULL = prove
+ (`interval [vec 0,vec 1:real^N] =
+     convex hull
+       {x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
+                           ==> ((x$i = &0) \/ (x$i = &1))}`,
+  let lemma = prove
+   (`FINITE {i | 1 <= i /\ i <= n /\ P(i)} /\
+     CARD {i | 1 <= i /\ i <= n /\ P(i)} <= n`,
+    CONJ_TAC THENL
+     [MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `1..n`;
+      GEN_REWRITE_TAC RAND_CONV [ARITH_RULE `x = (x + 1) - 1`] THEN
+      REWRITE_TAC[GSYM CARD_NUMSEG] THEN MATCH_MP_TAC CARD_SUBSET] THEN
+    SIMP_TAC[FINITE_NUMSEG; IN_NUMSEG; SUBSET; IN_ELIM_THM]) in
+  MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC HULL_MINIMAL THEN
+    REWRITE_TAC[CONVEX_INTERVAL; SUBSET; IN_INTERVAL; IN_ELIM_THM] THEN
+    SIMP_TAC[VEC_COMPONENT] THEN MESON_TAC[REAL_LE_REFL; REAL_POS]] THEN
+  SUBGOAL_THEN
+   `!n x:real^N.
+        x IN interval[vec 0,vec 1] /\
+        n <= dimindex(:N) /\
+        CARD {i | 1 <= i /\ i <= dimindex(:N) /\ ~(x$i = &0)} <= n
+        ==> x IN convex hull
+                  {x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
+                                  ==> ((x$i = &0) \/ (x$i = &1))}`
+  MP_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[SUBSET] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN EXISTS_TAC `dimindex(:N)` THEN
+    ASM_REWRITE_TAC[LE_REFL; lemma]] THEN
+  INDUCT_TAC THEN X_GEN_TAC `x:real^N` THENL
+   [SIMP_TAC[LE; lemma; CARD_EQ_0] THEN
+    GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV)
+     [EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY; BETA_THM] THEN
+    REWRITE_TAC[TAUT `~(a /\ b /\ c) <=> a /\ b ==> ~c`] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `x = vec 0:real^N` SUBST1_TAC THENL
+     [ASM_SIMP_TAC[CART_EQ; VEC_COMPONENT]; ALL_TAC] THEN
+    MATCH_MP_TAC(REWRITE_RULE[SUBSET] HULL_SUBSET) THEN
+    SIMP_TAC[IN_ELIM_THM; VEC_COMPONENT];
+    ALL_TAC] THEN
+  ASM_CASES_TAC
+   `{i | 1 <= i /\ i <= dimindex(:N) /\ ~((x:real^N)$i = &0)} = {}`
+  THENL
+   [DISCH_THEN(K ALL_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+    GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV)
+     [EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY; BETA_THM] THEN
+    REWRITE_TAC[TAUT `~(a /\ b /\ c) <=> a /\ b ==> ~c`] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `x = vec 0:real^N` SUBST1_TAC THENL
+     [ASM_SIMP_TAC[CART_EQ; VEC_COMPONENT]; ALL_TAC] THEN
+    MATCH_MP_TAC(REWRITE_RULE[SUBSET] HULL_SUBSET) THEN
+    SIMP_TAC[IN_ELIM_THM; VEC_COMPONENT];
+    ALL_TAC] THEN
+  MP_TAC(ISPEC
+   `IMAGE (\i. x$i)
+      {i | 1 <= i /\ i <= dimindex(:N) /\ ~((x:real^N)$i = &0)}`
+   INF_FINITE) THEN
+  ABBREV_TAC `xi = inf
+   (IMAGE (\i. x$i)
+     {i | 1 <= i /\ i <= dimindex(:N) /\ ~((x:real^N)$i = &0)})` THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; IMAGE_EQ_EMPTY; lemma] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [IN_IMAGE; IN_ELIM_THM] THEN
+  REWRITE_TAC[] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `i:num` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM SUBST_ALL_TAC THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `&0 <= (x:real^N)$i /\ x$i <= &1` STRIP_ASSUME_TAC THENL
+   [UNDISCH_TAC `x:real^N IN interval [vec 0,vec 1]` THEN
+    ASM_SIMP_TAC[IN_INTERVAL; VEC_COMPONENT];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+   `x <= &1 ==> (x = &1) \/ x < &1`))
+  THENL
+   [SUBGOAL_THEN
+     `x = lambda i. if (x:real^N)$i = &0 then &0 else &1`
+    SUBST1_TAC THENL
+     [UNDISCH_TAC `x:real^N IN interval [vec 0,vec 1]` THEN
+      ASM_SIMP_TAC[CART_EQ; IN_INTERVAL; VEC_COMPONENT; LAMBDA_BETA] THEN
+      ASM_MESON_TAC[REAL_LE_ANTISYM];
+      ALL_TAC] THEN
+    MATCH_MP_TAC(REWRITE_RULE[SUBSET] HULL_SUBSET) THEN
+    SIMP_TAC[IN_ELIM_THM; LAMBDA_BETA] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `x:real^N =
+        x$i % (lambda j. if x$j = &0 then &0 else &1) +
+        (&1 - x$i) %
+        (lambda j. if x$j = &0 then &0 else (x$j - x$i) / (&1 - x$i))`
+  SUBST1_TAC THENL
+   [SIMP_TAC[CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+             LAMBDA_BETA; VEC_COMPONENT] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[REAL_MUL_RZERO; REAL_ADD_LID] THEN
+    ASM_SIMP_TAC[REAL_DIV_LMUL; ARITH_RULE `x < &1 ==> ~(&1 - x = &0)`] THEN
+    REPEAT STRIP_TAC THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC(REWRITE_RULE[convex] CONVEX_CONVEX_HULL) THEN
+  ASM_SIMP_TAC[REAL_ARITH `x < &1 ==> &0 <= &1 - x`;
+               REAL_ARITH `x + &1 - x = &1`] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC(REWRITE_RULE[SUBSET] HULL_SUBSET) THEN
+    SIMP_TAC[LAMBDA_BETA; IN_ELIM_THM] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[ARITH_RULE `SUC k <= n ==> k <= n`] THEN CONJ_TAC THENL
+   [SIMP_TAC[IN_INTERVAL; LAMBDA_BETA; VEC_COMPONENT] THEN
+    GEN_TAC THEN STRIP_TAC THEN
+    COND_CASES_TAC THEN REWRITE_TAC[REAL_LE_REFL; REAL_POS] THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ;
+                 REAL_ARITH `x < &1 ==> &0 < &1 - x`] THEN
+    ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_SUB_LE; REAL_MUL_LID] THEN
+    ASM_SIMP_TAC[REAL_ARITH `a - b <= &1 - b <=> a <= &1`] THEN
+    UNDISCH_TAC `x:real^N IN interval [vec 0,vec 1]` THEN
+    ASM_SIMP_TAC[CART_EQ; IN_INTERVAL; VEC_COMPONENT; LAMBDA_BETA];
+    ALL_TAC] THEN
+  MATCH_MP_TAC LE_TRANS THEN
+  EXISTS_TAC
+   `CARD({i | 1 <= i /\ i <= dimindex(:N) /\ ~((x:real^N)$i = &0)}
+         DELETE i)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CARD_SUBSET THEN REWRITE_TAC[lemma; FINITE_DELETE] THEN
+    REWRITE_TAC[SUBSET; IN_DELETE; IN_ELIM_THM] THEN
+    GEN_TAC THEN REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    ASM_SIMP_TAC[LAMBDA_BETA] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[CONTRAPOS_THM] THEN
+    SIMP_TAC[real_div; REAL_SUB_REFL; REAL_MUL_LZERO];
+    SIMP_TAC[lemma; CARD_DELETE] THEN COND_CASES_TAC THEN
+    ASM_SIMP_TAC[ARITH_RULE `x <= SUC n ==> x - 1 <= n`] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_ELIM_THM]) THEN
+    ASM_MESON_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Representation of any interval as a finite convex hull.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let CLOSED_INTERVAL_AS_CONVEX_HULL = prove
+ (`!a b:real^N. ?s. FINITE s /\ interval[a,b] = convex hull s`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `interval[a:real^N,b] = {}` THENL
+   [ASM_MESON_TAC[CONVEX_HULL_EMPTY; FINITE_EMPTY]; ALL_TAC] THEN
+  ASM_SIMP_TAC[CLOSED_INTERVAL_IMAGE_UNIT_INTERVAL] THEN
+  SUBGOAL_THEN
+   `?s:real^N->bool. FINITE s /\ interval[vec 0,vec 1] = convex hull s`
+  STRIP_ASSUME_TAC THENL
+   [EXISTS_TAC
+     `{x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
+                      ==> ((x$i = &0) \/ (x$i = &1))}` THEN
+    REWRITE_TAC[UNIT_INTERVAL_CONVEX_HULL] THEN
+    MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC
+     `IMAGE (\s. (lambda i. if i IN s then &1 else &0):real^N)
+            {t | t SUBSET (1..dimindex(:N))}` THEN
+    ASM_SIMP_TAC[FINITE_POWERSET; FINITE_IMAGE; FINITE_NUMSEG] THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_IMAGE] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN EXISTS_TAC
+     `{i | 1 <= i /\ i <= dimindex(:N) /\ ((x:real^N)$i = &1)}` THEN
+    SIMP_TAC[CART_EQ; IN_ELIM_THM; IN_NUMSEG; LAMBDA_BETA] THEN
+    ASM_MESON_TAC[];
+    EXISTS_TAC `IMAGE (\x:real^N. a + x)
+                      (IMAGE (\x. (lambda i. ((b:real^N)$i - a$i) * x$i))
+                             (s:real^N->bool))` THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; CONVEX_HULL_TRANSLATION] THEN
+    AP_TERM_TAC THEN MATCH_MP_TAC(GSYM CONVEX_HULL_LINEAR_IMAGE) THEN
+    SIMP_TAC[linear; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT;
+             VECTOR_MUL_COMPONENT] THEN
+    REPEAT STRIP_TAC THEN REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Bounded convex function on open set is continuous.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_ON_BOUNDED_CONTINUOUS = prove
+ (`!f:real^N->real s b.
+        open s /\ f convex_on s /\ (!x. x IN s ==> abs(f x) <= b)
+        ==> (lift o f) continuous_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  REWRITE_TAC[CONTINUOUS_AT_LIFT_RANGE] THEN
+  ABBREV_TAC `B = abs(b) + &1` THEN
+  SUBGOAL_THEN `&0 < B /\ !x:real^N. x IN s ==> abs(f x) <= B`
+  STRIP_ASSUME_TAC THENL
+   [EXPAND_TAC "B" THEN CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+    ASM_MESON_TAC[REAL_ARITH `x <= b ==> x <= abs b + &1`];
+    ALL_TAC] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  REWRITE_TAC[REAL_ARITH `abs(x - y) < e <=> x - y < e /\ y - x < e`] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN REWRITE_TAC[SUBSET; IN_CBALL] THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `min (k / &2) (e / (&2 * B) * k)` THEN
+  ASM_SIMP_TAC[REAL_LT_MIN; REAL_LT_DIV; REAL_LT_MUL;
+               REAL_OF_NUM_LT; ARITH] THEN
+  X_GEN_TAC `y:real^N` THEN
+  ASM_CASES_TAC `y:real^N = x` THEN ASM_REWRITE_TAC[REAL_SUB_REFL] THEN
+  STRIP_TAC THEN
+  ABBREV_TAC `t = k / norm(y - x:real^N)` THEN
+  SUBGOAL_THEN `&2 < t` ASSUME_TAC THENL
+   [EXPAND_TAC "t" THEN
+    ASM_SIMP_TAC[REAL_LT_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_OF_NUM_LT; ARITH];
+    ALL_TAC] THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP (REAL_ARITH
+   `&2 < t ==> &0 < t /\ ~(t = &0) /\ &0 < t - &1 /\
+               &0 < &1 + t /\ ~(&1 + t = &0)`)) THEN
+  SUBGOAL_THEN `y:real^N IN s` ASSUME_TAC THENL
+   [FIRST_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[dist] THEN
+    ONCE_REWRITE_TAC[NORM_SUB] THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `x < k / &2 ==> k / &2 <= k ==> x <= k`)) THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN
+    UNDISCH_TAC `&0 < k` THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [ABBREV_TAC `w:real^N = x + t % (y - x)` THEN
+    SUBGOAL_THEN `w:real^N IN s` STRIP_ASSUME_TAC THENL
+     [FIRST_ASSUM MATCH_MP_TAC THEN EXPAND_TAC "w" THEN
+      REWRITE_TAC[dist; VECTOR_ARITH `x - (x + t) = --t:real^N`] THEN
+      EXPAND_TAC "t" THEN REWRITE_TAC[NORM_NEG; NORM_MUL; REAL_ABS_DIV] THEN
+      REWRITE_TAC[REAL_ABS_NORM; real_div; GSYM REAL_MUL_ASSOC] THEN
+      ASM_SIMP_TAC[REAL_MUL_LINV; REAL_LT_IMP_NZ; NORM_POS_LT; VECTOR_SUB_EQ;
+        REAL_MUL_RID; REAL_ARITH `&0 < x ==> abs(x) <= x`];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `(&1 / t) % w + (t - &1) / t % x = y:real^N` ASSUME_TAC THENL
+     [EXPAND_TAC "w" THEN
+      REWRITE_TAC[VECTOR_ARITH
+       `b % (x + c % (y - x)) + a % x =
+        (a + b - b * c) % x + (b * c) % y`] THEN
+      ASM_SIMP_TAC[REAL_DIV_RMUL; VECTOR_MUL_LID] THEN
+      ASM_SIMP_TAC[real_div; REAL_MUL_RINV; REAL_SUB_REFL;
+                   VECTOR_MUL_LZERO; VECTOR_ADD_LID;
+                   REAL_ARITH `(a - &1) * b + &1 * b - &1 = a * b - &1`];
+      ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [convex_on]) THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`w:real^N`; `x:real^N`; `&1 / t`; `(t - &1) / t`]) THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LT_DIV; REAL_LT_01] THEN
+    REWRITE_TAC[real_div; GSYM REAL_ADD_RDISTRIB] THEN
+    ASM_SIMP_TAC[REAL_SUB_ADD2; REAL_MUL_RINV] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `a * fw + (b - &1) * fx < e
+      ==> fy <= a * fw + b * fx ==> fy - fx < e`) THEN
+    ASM_SIMP_TAC[real_div; REAL_SUB_RDISTRIB; REAL_MUL_RINV; REAL_MUL_LID;
+                 REAL_ARITH `a * x + y - a * y - y = a * (x - y)`] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[GSYM real_div; REAL_LT_LDIV_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `!b. abs(x) <= b /\ abs(y) <= b /\ &2 * b < z ==> x - y < z`) THEN
+    EXISTS_TAC `B:real` THEN ASM_SIMP_TAC[] THEN EXPAND_TAC "t" THEN
+    REWRITE_TAC[real_div; REAL_MUL_ASSOC] THEN REWRITE_TAC[GSYM real_div] THEN
+    ASM_SIMP_TAC[REAL_LT_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_LT_MUL; REAL_OF_NUM_LT; ARITH] THEN
+    REWRITE_TAC[real_div; REAL_ARITH `(a * b) * inv c = (b * inv c) * a`] THEN
+    ASM_REWRITE_TAC[GSYM real_div];
+
+    ABBREV_TAC `w:real^N = x - t % (y - x)` THEN
+    SUBGOAL_THEN `w:real^N IN s` STRIP_ASSUME_TAC THENL
+     [FIRST_ASSUM MATCH_MP_TAC THEN EXPAND_TAC "w" THEN
+      REWRITE_TAC[dist; VECTOR_ARITH `x - (x - t) = t:real^N`] THEN
+      EXPAND_TAC "t" THEN REWRITE_TAC[NORM_MUL; REAL_ABS_DIV] THEN
+      REWRITE_TAC[REAL_ABS_NORM; real_div; GSYM REAL_MUL_ASSOC] THEN
+      ASM_SIMP_TAC[REAL_MUL_LINV; REAL_LT_IMP_NZ; NORM_POS_LT; VECTOR_SUB_EQ;
+        REAL_MUL_RID; REAL_ARITH `&0 < x ==> abs(x) <= x`];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `(&1 / (&1 + t)) % w + t / (&1 + t) % y = x:real^N`
+    ASSUME_TAC THENL
+     [EXPAND_TAC "w" THEN
+      REWRITE_TAC[VECTOR_ARITH
+       `b % (x - c % (y - x)) + a % y =
+        (b * (&1 + c)) % x + (a - b * c) % y`] THEN
+      ASM_SIMP_TAC[REAL_DIV_RMUL; VECTOR_MUL_LID] THEN
+      REWRITE_TAC[real_div; REAL_MUL_AC; REAL_MUL_LID; REAL_MUL_RID] THEN
+      REWRITE_TAC[REAL_SUB_REFL; VECTOR_MUL_LZERO; VECTOR_ADD_RID];
+      ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [convex_on]) THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`w:real^N`; `y:real^N`; `&1 / (&1 + t)`; `t / (&1 + t)`]) THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LT_DIV; REAL_LT_01] THEN
+    REWRITE_TAC[real_div; GSYM REAL_ADD_RDISTRIB] THEN
+    ASM_SIMP_TAC[REAL_SUB_ADD2; REAL_MUL_RINV] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `a * fw + (b - &1) * fx < e
+      ==> fy <= a * fw + b * fx ==> fy - fx < e`) THEN
+    SUBGOAL_THEN `t * inv(&1 + t) - &1 = --(inv(&1 + t))` SUBST1_TAC THENL
+     [REWRITE_TAC[REAL_ARITH `(a * b - &1 = --b) <=> ((&1 + a) * b = &1)`] THEN
+      ASM_SIMP_TAC[REAL_MUL_RINV];
+      ALL_TAC] THEN
+    REWRITE_TAC[REAL_ARITH `(&1 * a) * x + --a * y = a * (x - y)`] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[GSYM real_div; REAL_LT_LDIV_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `!b. abs(x) <= b /\ abs(y) <= b /\ &2 * b < z ==> x - y < z`) THEN
+    EXISTS_TAC `B:real` THEN ASM_SIMP_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x < e * k ==> x < e * (&1 + k)`) THEN
+    EXPAND_TAC "t" THEN REWRITE_TAC[real_div; REAL_MUL_ASSOC] THEN
+    REWRITE_TAC[GSYM real_div] THEN
+    ASM_SIMP_TAC[REAL_LT_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_LT_MUL; REAL_OF_NUM_LT; ARITH] THEN
+    REWRITE_TAC[real_div; REAL_ARITH `(a * b) * inv c = (b * inv c) * a`] THEN
+    ASM_REWRITE_TAC[GSYM real_div]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Upper bound on a ball implies upper and lower bounds.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_BOUNDS_LEMMA = prove
+ (`!f x:real^N e.
+        f convex_on cball(x,e) /\
+        (!y. y IN cball(x,e) ==> f(y) <= b)
+        ==> !y. y IN cball(x,e) ==> abs(f(y)) <= b + &2 * abs(f(x))`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `&0 <= e` THENL
+   [ALL_TAC;
+    REWRITE_TAC[IN_CBALL] THEN ASM_MESON_TAC[DIST_POS_LE; REAL_LE_TRANS]] THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [convex_on]) THEN
+  DISCH_THEN(MP_TAC o SPECL
+   [`y:real^N`; `&2 % x - y:real^N`; `&1 / &2`; `&1 / &2`]) THEN
+  REWRITE_TAC[GSYM VECTOR_ADD_LDISTRIB; GSYM REAL_ADD_LDISTRIB] THEN
+  REWRITE_TAC[VECTOR_ARITH `y + x - y = x:real^N`] THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  ABBREV_TAC `z = &2 % x - y:real^N` THEN
+  SUBGOAL_THEN `z:real^N IN cball(x,e)` ASSUME_TAC THENL
+   [UNDISCH_TAC `y:real^N IN cball(x,e)`  THEN
+    EXPAND_TAC "z" THEN REWRITE_TAC[dist; IN_CBALL] THEN
+    REWRITE_TAC[VECTOR_ARITH `x - (&2 % x - y) = y - x`] THEN
+    REWRITE_TAC[NORM_SUB];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LID] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  REWRITE_TAC[real_div; REAL_MUL_LID] THEN REWRITE_TAC[GSYM real_div] THEN
+  ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN
+  FIRST_X_ASSUM(fun th ->
+    MAP_EVERY (MP_TAC o C SPEC th) [`y:real^N`; `z:real^N`]) THEN
+  ASM_REWRITE_TAC[CENTRE_IN_CBALL] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence a convex function on an open set is continuous.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_ON_CONTINUOUS = prove
+ (`!f s:real^N->bool. open s /\ f convex_on s ==> lift o f continuous_on s`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT] THEN
+  X_GEN_TAC `x:real^N` 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` STRIP_ASSUME_TAC) THEN
+  ABBREV_TAC `d = e / &(dimindex(:N))` THEN
+  SUBGOAL_THEN `&0 < d` ASSUME_TAC THENL
+   [EXPAND_TAC "d" THEN MATCH_MP_TAC REAL_LT_DIV THEN
+    ASM_REWRITE_TAC[REAL_OF_NUM_LT; DIMINDEX_GE_1;
+                    ARITH_RULE `0 < d <=> 1 <= d`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?b. !y:real^N. y IN interval[(x - lambda i. d),(x + lambda i. d)]
+                   ==> f(y) <= b`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPECL [`x - (lambda i. d):real^N`; `x + (lambda i. d):real^N`]
+        CLOSED_INTERVAL_AS_CONVEX_HULL) THEN
+    DISCH_THEN(X_CHOOSE_THEN `c:real^N->bool` STRIP_ASSUME_TAC) THEN
+    ASM_REWRITE_TAC[] THEN ASM_CASES_TAC `c = {}:real^N->bool` THEN
+    ASM_REWRITE_TAC[CONVEX_HULL_EMPTY; NOT_IN_EMPTY] THEN
+    MP_TAC(ISPEC `IMAGE (f:real^N->real) c` SUP_FINITE) THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; IMAGE_EQ_EMPTY; FORALL_IN_IMAGE] THEN
+    ABBREV_TAC `k = sup(IMAGE (f:real^N->real) c)` THEN
+    STRIP_TAC THEN EXISTS_TAC `k:real` THEN
+    MATCH_MP_TAC CONVEX_ON_CONVEX_HULL_BOUND THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONVEX_ON_SUBSET THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `cball (x:real^N,e)` THEN
+    ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [SYM th]) THEN
+    REWRITE_TAC[SUBSET; IN_INTERVAL; IN_CBALL] THEN
+    SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_SUB_COMPONENT; LAMBDA_BETA] THEN
+    X_GEN_TAC `z:real^N` THEN
+    REWRITE_TAC[REAL_ARITH `x - d <= z /\ z <= x + d <=> abs(x - z) <= d`] THEN
+    DISCH_TAC THEN REWRITE_TAC[dist] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+     `sum(1..dimindex(:N)) (\i. abs((x - z:real^N)$i))` THEN
+    REWRITE_TAC[NORM_LE_L1] THEN
+    MATCH_MP_TAC SUM_BOUND_GEN THEN
+    REWRITE_TAC[FINITE_NUMSEG; NUMSEG_EMPTY; CARD_NUMSEG] THEN
+    ASM_SIMP_TAC[IN_NUMSEG; NOT_LT; DIMINDEX_GE_1; ADD_SUB;
+                 VECTOR_SUB_COMPONENT];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `cball(x:real^N,d) SUBSET cball(x,e)` ASSUME_TAC THENL
+   [REWRITE_TAC[SUBSET; IN_CBALL] THEN GEN_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `d <= e ==> x <= d ==> x <= e`) THEN
+    EXPAND_TAC "d" THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; DIMINDEX_GE_1;
+                 ARITH_RULE `0 < x <=> 1 <= x`] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM REAL_MUL_RID] THEN
+    ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_OF_NUM_LE; DIMINDEX_GE_1];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!y:real^N. y IN cball(x,d) ==> abs(f(y)) <= b + &2 * abs(f(x))`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC CONVEX_BOUNDS_LEMMA THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[CONVEX_ON_SUBSET; SUBSET_TRANS]; ALL_TAC] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    UNDISCH_TAC `y:real^N IN cball(x,d)` THEN REWRITE_TAC[IN_CBALL] THEN
+    REWRITE_TAC[IN_INTERVAL; IN_CBALL; dist] THEN DISCH_TAC THEN
+    SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_SUB_COMPONENT; LAMBDA_BETA] THEN
+    REWRITE_TAC[REAL_ARITH `x - d <= z /\ z <= x + d <=> abs(x - z) <= d`] THEN
+    SIMP_TAC[GSYM VECTOR_SUB_COMPONENT] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `norm(x - y:real^N)` THEN
+    ASM_SIMP_TAC[COMPONENT_LE_NORM];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(lift o f) continuous_on (ball(x:real^N,d))` MP_TAC THENL
+   [MATCH_MP_TAC CONVEX_ON_BOUNDED_CONTINUOUS THEN REWRITE_TAC[OPEN_BALL] THEN
+    EXISTS_TAC `b + &2 * abs(f(x:real^N))` THEN
+    ASM_MESON_TAC[SUBSET; CONVEX_ON_SUBSET; SUBSET_TRANS; BALL_SUBSET_CBALL];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; OPEN_BALL; CENTRE_IN_BALL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Characterizations of convex functions in terms of sequents.               *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_ON_LEFT_SECANT_MUL,CONVEX_ON_RIGHT_SECANT_MUL = (CONJ_PAIR o prove)
+ (`(!f s:real^N->bool.
+        f convex_on s <=>
+          !a b x. a IN s /\ b IN s /\ x IN segment[a,b]
+                  ==> (f x - f a) * norm(b - a) <= (f b - f a) * norm(x - a)) /\
+   (!f s:real^N->bool.
+        f convex_on s <=>
+          !a b x. a IN s /\ b IN s /\ x IN segment[a,b]
+                  ==> (f b - f a) * norm(b - x) <= (f b - f x) * norm(b - a))`,
+  CONJ_TAC THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[convex_on] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `a:real^N` THEN REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `b:real^N` THEN REWRITE_TAC[] THEN
+  ASM_CASES_TAC `(a:real^N) IN s` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `(b:real^N) IN s` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[IN_SEGMENT; LEFT_IMP_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `u:real` THEN REWRITE_TAC[] THEN
+  REWRITE_TAC[TAUT `a /\ x = y <=> x = y /\ a`;
+              TAUT `a /\ x = y /\ b <=> x = y /\ a /\ b`] THEN
+  REWRITE_TAC[REAL_ARITH `v + u = &1 <=> v = &1 - u`] THEN
+  REWRITE_TAC[FORALL_UNWIND_THM2; IMP_CONJ] THEN
+  REWRITE_TAC[REAL_SUB_LE] THEN
+  ASM_CASES_TAC `&0 <= u` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `u <= &1` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[VECTOR_ARITH `((&1 - u) % a + u % b) - a:real^N = u % (b - a)`;
+   VECTOR_ARITH `b - ((&1 - u) % a + u % b):real^N = (&1 - u) % (b - a)`] THEN
+  REWRITE_TAC[NORM_MUL; REAL_MUL_ASSOC] THEN
+  (ASM_CASES_TAC `b:real^N = a` THENL
+   [ASM_REWRITE_TAC[VECTOR_SUB_REFL; REAL_SUB_REFL;
+                    VECTOR_ARITH `(&1 - u) % a + u % a:real^N = a`] THEN
+    REAL_ARITH_TAC;
+    ASM_SIMP_TAC[REAL_LE_RMUL_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    ASM_SIMP_TAC[REAL_ARITH
+     `&0 <= u /\ u <= &1 ==> abs u = u /\ abs(&1 - u) = &1 - u`] THEN
+    REAL_ARITH_TAC]));;
+
+let CONVEX_ON_LEFT_SECANT,CONVEX_ON_RIGHT_SECANT = (CONJ_PAIR o prove)
+ (`(!f s:real^N->bool.
+      f convex_on s <=>
+        !a b x. a IN s /\ b IN s /\ x IN segment(a,b)
+                ==> (f x - f a) / norm(x - a) <= (f b - f a) / norm(b - a)) /\
+   (!f s:real^N->bool.
+      f convex_on s <=>
+        !a b x. a IN s /\ b IN s /\ x IN segment(a,b)
+                ==> (f b - f a) / norm(b - a) <= (f b - f x) / norm(b - x))`,
+  CONJ_TAC THEN REPEAT GEN_TAC THENL
+   [REWRITE_TAC[CONVEX_ON_LEFT_SECANT_MUL];
+    REWRITE_TAC[CONVEX_ON_RIGHT_SECANT_MUL]] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `a:real^N` THEN REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `b:real^N` THEN REWRITE_TAC[] THEN
+  ASM_CASES_TAC `(a:real^N) IN s` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `(b:real^N) IN s` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `a:real^N = b` THEN
+  ASM_REWRITE_TAC[SEGMENT_REFL; NOT_IN_EMPTY; REAL_SUB_REFL; VECTOR_SUB_REFL;
+                  NORM_0; REAL_MUL_LZERO; REAL_MUL_RZERO; REAL_LE_REFL] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `x:real^N` THEN REWRITE_TAC[] THEN
+  REWRITE_TAC[open_segment; IN_DIFF; IN_INSERT; NOT_IN_EMPTY] THEN
+  MAP_EVERY ASM_CASES_TAC [`x:real^N = a`; `x:real^N = b`] THEN
+  ASM_REWRITE_TAC[REAL_LE_REFL; REAL_SUB_REFL; VECTOR_SUB_REFL; NORM_0;
+                  REAL_MUL_LZERO; REAL_MUL_RZERO] THEN
+  ASM_SIMP_TAC[REAL_LE_RDIV_EQ; GSYM REAL_LE_LDIV_EQ; NORM_POS_LT;
+               VECTOR_SUB_EQ] THEN
+  AP_TERM_TAC THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Starlike sets and more stuff about line segments.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let starlike = new_definition
+ `starlike s <=> ?a. a IN s /\ !x. x IN s ==> segment[a,x] SUBSET s`;;
+
+let CONVEX_CONTAINS_SEGMENT = prove
+ (`!s. convex s <=> !a b. a IN s /\ b IN s ==> segment[a,b] SUBSET s`,
+  REWRITE_TAC[CONVEX_ALT; segment; SUBSET; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let CONVEX_CONTAINS_SEGMENT_EQ = prove
+ (`!s:real^N->bool.
+        convex s <=> !a b. segment[a,b] SUBSET s <=> a IN s /\ b IN s`,
+  REWRITE_TAC[CONVEX_CONTAINS_SEGMENT; SUBSET] THEN
+  MESON_TAC[ENDS_IN_SEGMENT]);;
+
+let CONVEX_CONTAINS_SEGMENT_IMP = prove
+ (`!s a b. convex s ==> (segment[a,b] SUBSET s <=> a IN s /\ b IN s)`,
+  SIMP_TAC[CONVEX_CONTAINS_SEGMENT_EQ]);;
+
+let CONVEX_IMP_STARLIKE = prove
+ (`!s. convex s /\ ~(s = {}) ==> starlike s`,
+  REWRITE_TAC[CONVEX_CONTAINS_SEGMENT; starlike; GSYM MEMBER_NOT_EMPTY] THEN
+  MESON_TAC[]);;
+
+let SEGMENT_CONVEX_HULL = prove
+ (`!a b. segment[a,b] = convex hull {a,b}`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[CONVEX_HULL_INSERT; CONVEX_HULL_SING; NOT_INSERT_EMPTY] THEN
+  REWRITE_TAC[IN_SING; RIGHT_EXISTS_AND_THM; UNWIND_THM2] THEN
+  REWRITE_TAC[segment; EXTENSION; IN_ELIM_THM] THEN
+  REWRITE_TAC[REAL_ARITH `u + v = &1 <=> u = &1 - v`] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c /\ d <=> c /\ a /\ b /\ d`] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN REWRITE_TAC[UNWIND_THM2] THEN
+  REWRITE_TAC[REAL_LE_SUB_LADD; REAL_ADD_LID] THEN MESON_TAC[]);;
+
+let SEGMENT_FURTHEST_LE = prove
+ (`!a b x y:real^N.
+        x IN segment[a,b] ==> norm(y - x) <= norm(y - a) \/
+                              norm(y - x) <= norm(y - b)`,
+  REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`y:real^N`; `{a:real^N,b}`] SIMPLEX_FURTHEST_LE) THEN
+  ASM_REWRITE_TAC[FINITE_INSERT; FINITE_RULES; NOT_INSERT_EMPTY] THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN
+  ASM_MESON_TAC[NORM_SUB]);;
+
+let SEGMENT_BOUND = prove
+ (`!a b x:real^N.
+        x IN segment[a,b] ==> norm(x - a) <= norm(b - a) /\
+                              norm(x - b) <= norm(b - a)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`a:real^N`; `b:real^N`; `x:real^N`] SEGMENT_FURTHEST_LE) THENL
+   [DISCH_THEN(MP_TAC o SPEC `a:real^N`);
+    DISCH_THEN(MP_TAC o SPEC `b:real^N`)] THEN
+  REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+  ASM_MESON_TAC[NORM_POS_LE; REAL_LE_TRANS; NORM_SUB]);;
+
+let BETWEEN_IN_CONVEX_HULL = prove
+ (`!x a b:real^N. between x (a,b) <=> x IN convex hull {a,b}`,
+  REWRITE_TAC[BETWEEN_IN_SEGMENT; SEGMENT_CONVEX_HULL]);;
+
+let STARLIKE_LINEAR_IMAGE = prove
+ (`!f s. starlike s /\ linear f ==> starlike(IMAGE f s)`,
+  REWRITE_TAC[starlike; FORALL_IN_IMAGE; EXISTS_IN_IMAGE] THEN
+  SIMP_TAC[CLOSED_SEGMENT_LINEAR_IMAGE] THEN SET_TAC[]);;
+
+let STARLIKE_LINEAR_IMAGE_EQ = prove
+ (`!f s. linear f /\ (!x y. f x = f y ==> x = y)
+         ==> (starlike (IMAGE f s) <=> starlike s)`,
+  MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE STARLIKE_LINEAR_IMAGE));;
+
+add_linear_invariants [STARLIKE_LINEAR_IMAGE_EQ];;
+
+let STARLIKE_TRANSLATION_EQ = prove
+ (`!a s. starlike (IMAGE (\x. a + x) s) <=> starlike s`,
+  REWRITE_TAC[starlike] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [STARLIKE_TRANSLATION_EQ];;
+
+let BETWEEN_LINEAR_IMAGE_EQ = prove
+ (`!f x y z. linear f /\ (!x y. f x = f y ==> x = y)
+             ==> (between (f x) (f y,f z) <=> between x (y,z))`,
+  SIMP_TAC[BETWEEN_IN_SEGMENT; CLOSED_SEGMENT_LINEAR_IMAGE] THEN SET_TAC[]);;
+
+add_linear_invariants [BETWEEN_LINEAR_IMAGE_EQ];;
+
+let BETWEEN_TRANSLATION = prove
+ (`!a x y. between (a + x) (a + y,a + z) <=> between x (y,z)`,
+  REWRITE_TAC[between] THEN NORM_ARITH_TAC);;
+
+add_translation_invariants [STARLIKE_TRANSLATION_EQ];;
+
+let STARLIKE_CLOSURE = prove
+ (`!s:real^N->bool. starlike s ==> starlike(closure s)`,
+  GEN_TAC THEN REWRITE_TAC[starlike; SUBSET; segment; FORALL_IN_GSPEC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[REWRITE_RULE[SUBSET] CLOSURE_SUBSET] THEN
+  X_GEN_TAC `x:real^N` THEN REWRITE_TAC[SUBSET; CLOSURE_APPROACHABLE] THEN
+  DISCH_TAC THEN X_GEN_TAC `u:real` THEN STRIP_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 `y:real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(&1 - u) % a + u % y:real^N` THEN
+  ASM_SIMP_TAC[dist; NORM_MUL; VECTOR_ARITH
+   `(v % a + u % y) - (v % a + u % z):real^N = u % (y - z)`] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+        REAL_LET_TRANS)) THEN
+  REWRITE_TAC[dist; REAL_ARITH `u * n <= n <=> &0 <= n * (&1 - u)`] THEN
+  MATCH_MP_TAC REAL_LE_MUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let STARLIKE_UNIV = prove
+ (`starlike(:real^N)`,
+  MESON_TAC[CONVEX_IMP_STARLIKE; CONVEX_UNIV;
+            BOUNDED_EMPTY; NOT_BOUNDED_UNIV]);;
+
+let STARLIKE_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        starlike s /\ starlike t ==> starlike(s PCROSS t)`,
+  SIMP_TAC[starlike; EXISTS_IN_PCROSS; SUBSET; IN_SEGMENT] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+  REWRITE_TAC[FORALL_IN_PCROSS; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[FORALL_UNWIND_THM2; IMP_IMP] THEN
+  REWRITE_TAC[GSYM PASTECART_CMUL; PASTECART_ADD] THEN
+  REWRITE_TAC[PASTECART_IN_PCROSS] THEN MESON_TAC[]);;
+
+let STARLIKE_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        starlike(s PCROSS t) <=> starlike s /\ starlike t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THENL
+   [ASM_REWRITE_TAC[PCROSS_EMPTY] THEN MESON_TAC[starlike; NOT_IN_EMPTY];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[PCROSS_EMPTY] THEN MESON_TAC[starlike; NOT_IN_EMPTY];
+    ALL_TAC] THEN
+  EQ_TAC THEN REWRITE_TAC[STARLIKE_PCROSS] THEN REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL [`fstcart:real^(M,N)finite_sum->real^M`;
+     `(s:real^M->bool) PCROSS (t:real^N->bool)`] STARLIKE_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_FSTCART];
+    MP_TAC(ISPECL [`sndcart:real^(M,N)finite_sum->real^N`;
+     `(s:real^M->bool) PCROSS (t:real^N->bool)`] STARLIKE_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_SNDCART]] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; EXISTS_PASTECART; PASTECART_IN_PCROSS;
+              FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  ASM SET_TAC[]);;
+
+let BETWEEN_DIST_LT = prove
+ (`!r a b c:real^N.
+        dist(c,a) < r /\ dist(c,b) < r /\ between x (a,b) ==> dist(c,x) < r`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `convex hull {a,b} SUBSET ball(c:real^N,r)` MP_TAC THENL
+   [MATCH_MP_TAC HULL_MINIMAL THEN
+    ASM_REWRITE_TAC[CONVEX_BALL; INSERT_SUBSET; EMPTY_SUBSET; IN_BALL];
+    ASM_SIMP_TAC[SUBSET; GSYM BETWEEN_IN_CONVEX_HULL; IN_BALL]]);;
+
+let BETWEEN_DIST_LE = prove
+ (`!r a b c:real^N.
+      dist(c,a) <= r /\ dist(c,b) <= r /\ between x (a,b) ==> dist(c,x) <= r`,
+
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `convex hull {a,b} SUBSET cball(c:real^N,r)` MP_TAC THENL
+   [MATCH_MP_TAC HULL_MINIMAL THEN
+    ASM_REWRITE_TAC[CONVEX_CBALL; INSERT_SUBSET; EMPTY_SUBSET; IN_CBALL];
+    ASM_SIMP_TAC[SUBSET; GSYM BETWEEN_IN_CONVEX_HULL; IN_CBALL]]);;
+
+let BETWEEN_NORM_LT = prove
+ (`!r a b x:real^N.
+        norm a < r /\ norm b < r /\ between x (a,b) ==> norm x < r`,
+  REWRITE_TAC[GSYM(CONJUNCT2(SPEC_ALL DIST_0)); BETWEEN_DIST_LT]);;
+
+let BETWEEN_NORM_LE = prove
+ (`!r a b x:real^N.
+        norm a <= r /\ norm b <= r /\ between x (a,b) ==> norm x <= r`,
+  REWRITE_TAC[GSYM(CONJUNCT2(SPEC_ALL DIST_0)); BETWEEN_DIST_LE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Shrinking towards the interior of a convex set.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let IN_INTERIOR_CONVEX_SHRINK = prove
+ (`!s e x c:real^N.
+     convex s /\ c IN interior s /\
+     x IN s /\ &0 < e /\ e <= &1
+     ==> x - e % (x - c) IN interior s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERIOR]) THEN
+  REWRITE_TAC[IN_INTERIOR; SUBSET; IN_BALL; dist] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `e * d:real` THEN ASM_SIMP_TAC[REAL_LT_MUL] THEN
+  X_GEN_TAC `y':real^N` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(&1 / e) % y' - ((&1 - e) / e) % x:real^N`) THEN
+  ANTS_TAC THENL
+   [UNDISCH_TAC `norm (x - e % (x - c) - y':real^N) < e * d` THEN
+    SUBGOAL_THEN `x - e % (x - c) - y':real^N =
+                  e % (c - (&1 / e % y' - (&1 - e) / e % x))`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[VECTOR_SUB_LDISTRIB; VECTOR_MUL_ASSOC;
+                   REAL_DIV_LMUL; REAL_LT_IMP_NZ] THEN VECTOR_ARITH_TAC;
+      ASM_SIMP_TAC[NORM_MUL; REAL_LT_LMUL_EQ; real_abs; REAL_LT_IMP_LE]];
+    DISCH_TAC THEN
+    SUBGOAL_THEN `y' = (&1 - (&1 - e)) % (&1 / e % y' - (&1 - e) / e % x) +
+                       (&1 - e) % x:real^N`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[REAL_ARITH `&1 - (&1 - e) = e`; VECTOR_SUB_LDISTRIB;
+                   VECTOR_MUL_ASSOC; REAL_DIV_LMUL; REAL_LT_IMP_NZ] THEN
+      VECTOR_ARITH_TAC;
+      FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [CONVEX_ALT]) THEN
+      ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC]]);;
+
+let IN_INTERIOR_CLOSURE_CONVEX_SHRINK = prove
+ (`!s e x c:real^N.
+     convex s /\ c IN interior s /\
+     x IN closure s /\ &0 < e /\ e <= &1
+     ==> x - e % (x - c) IN interior s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERIOR]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `?y:real^N. y IN s /\ norm(y - x) * (&1 - e) < e * d`
+  STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `(x:real^N) IN s` THENL
+     [EXISTS_TAC `x:real^N` THEN
+      ASM_SIMP_TAC[REAL_LT_MUL; VECTOR_SUB_REFL; NORM_0; REAL_MUL_LZERO];
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [closure]) THEN
+    ASM_REWRITE_TAC[IN_UNION; IN_ELIM_THM; LIMPT_APPROACHABLE; dist] THEN
+    FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+     `e <= &1 ==> e = &1 \/ e < &1`)) THEN
+    ASM_SIMP_TAC[REAL_SUB_REFL; GSYM REAL_LT_RDIV_EQ; REAL_SUB_LT] THENL
+     [DISCH_THEN(MP_TAC o SPEC `&1`) THEN
+      REWRITE_TAC[REAL_MUL_RZERO; REAL_LT_01];
+      DISCH_THEN(MP_TAC o SPEC `(e * d) / (&1 - e)`)] THEN
+    ASM_SIMP_TAC[REAL_LT_RDIV_EQ; REAL_SUB_LT; REAL_MUL_LZERO; REAL_LT_MUL;
+                 REAL_MUL_LID] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN MESON_TAC[];
+    ALL_TAC] THEN
+  ABBREV_TAC `z:real^N = c + ((&1 - e) / e) % (x - y)` THEN
+  SUBGOAL_THEN `x - e % (x - c):real^N = y - e % (y - z)` SUBST1_TAC THENL
+   [EXPAND_TAC "z" THEN
+    REWRITE_TAC[VECTOR_SUB_LDISTRIB; VECTOR_ADD_LDISTRIB] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_DIV_LMUL; REAL_LT_IMP_NZ] THEN
+    VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC IN_INTERIOR_CONVEX_SHRINK THEN ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[SUBSET] o
+     MATCH_MP SUBSET_INTERIOR) THEN
+  SIMP_TAC[INTERIOR_OPEN; OPEN_BALL] THEN
+  REWRITE_TAC[IN_BALL; dist] THEN EXPAND_TAC "z" THEN
+  REWRITE_TAC[NORM_ARITH `norm(c - (c + x)) = norm(x)`] THEN
+  REWRITE_TAC[NORM_MUL; REAL_ABS_DIV] THEN
+  ASM_SIMP_TAC[real_abs; REAL_LT_IMP_LE; REAL_SUB_LE] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  REWRITE_TAC[real_div; REAL_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[GSYM real_div; REAL_LT_LDIV_EQ] THEN
+  ASM_MESON_TAC[REAL_MUL_SYM; NORM_SUB]);;
+
+let IN_INTERIOR_CLOSURE_CONVEX_SEGMENT = prove
+ (`!s a b:real^N.
+        convex s /\ a IN interior s /\ b IN closure s
+        ==> segment(a,b) SUBSET interior s`,
+  REWRITE_TAC[SUBSET; IN_SEGMENT] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+   `(&1 - u) % a + u % b:real^N = b - (&1 - u) % (b - a)`] THEN
+  MATCH_MP_TAC IN_INTERIOR_CLOSURE_CONVEX_SHRINK THEN
+  ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relative interior of a set.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let relative_interior = new_definition
+ `relative_interior s =
+   {x | ?t. open_in (subtopology euclidean (affine hull s)) t /\
+            x IN t /\ t SUBSET s}`;;
+
+let relative_frontier = new_definition
+ `relative_frontier s = closure s DIFF relative_interior s`;;
+
+let RELATIVE_INTERIOR = prove
+ (`!s. relative_interior s =
+          {x | x IN s /\
+               ?t. open t /\ x IN t /\ t INTER (affine hull s) SUBSET s}`,
+  REWRITE_TAC[EXTENSION; relative_interior; IN_ELIM_THM] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_IN_OPEN; LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[TAUT `(a /\ b) /\ c /\ d <=> b /\ a /\ c /\ d`] THEN
+  REWRITE_TAC[UNWIND_THM2; SUBSET; IN_INTER; RIGHT_AND_EXISTS_THM] THEN
+  AP_TERM_TAC THEN ABS_TAC THEN MESON_TAC[HULL_INC]);;
+
+let RELATIVE_INTERIOR_EQ = prove
+ (`!s. relative_interior s = s <=>
+       open_in(subtopology euclidean (affine hull s)) s`,
+  GEN_TAC THEN REWRITE_TAC[EXTENSION; relative_interior; IN_ELIM_THM] THEN
+  GEN_REWRITE_TAC RAND_CONV [OPEN_IN_SUBOPEN] THEN MESON_TAC[SUBSET]);;
+
+let RELATIVE_INTERIOR_OPEN_IN = prove
+ (`!s. open_in(subtopology euclidean (affine hull s)) s
+       ==> relative_interior s = s`,
+  REWRITE_TAC[RELATIVE_INTERIOR_EQ]);;
+
+let RELATIVE_INTERIOR_EMPTY = prove
+ (`relative_interior {} = {}`,
+  SIMP_TAC[RELATIVE_INTERIOR_OPEN_IN; OPEN_IN_EMPTY]);;
+
+let RELATIVE_FRONTIER_EMPTY = prove
+ (`relative_frontier {} = {}`,
+  REWRITE_TAC[relative_frontier; CLOSURE_EMPTY; EMPTY_DIFF]);;
+
+let RELATIVE_INTERIOR_AFFINE = prove
+ (`!s:real^N->bool. affine s ==> relative_interior s = s`,
+  SIMP_TAC[RELATIVE_INTERIOR_EQ; OPEN_IN_SUBTOPOLOGY_REFL; HULL_P] THEN
+  REWRITE_TAC[TOPSPACE_EUCLIDEAN; SUBSET_UNIV]);;
+
+let RELATIVE_INTERIOR_UNIV = prove
+ (`!s. relative_interior(affine hull s) = affine hull s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC RELATIVE_INTERIOR_OPEN_IN THEN
+  REWRITE_TAC[HULL_HULL; OPEN_IN_SUBTOPOLOGY_REFL] THEN
+  REWRITE_TAC[TOPSPACE_EUCLIDEAN; SUBSET_UNIV]);;
+
+let OPEN_IN_RELATIVE_INTERIOR = prove
+ (`!s. open_in (subtopology euclidean (affine hull s))
+               (relative_interior s)`,
+  GEN_TAC THEN REWRITE_TAC[relative_interior] THEN
+  GEN_REWRITE_TAC I [OPEN_IN_SUBOPEN] THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let RELATIVE_INTERIOR_SUBSET = prove
+ (`!s. (relative_interior s) SUBSET s`,
+  REWRITE_TAC[SUBSET; relative_interior; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let SUBSET_RELATIVE_INTERIOR = prove
+ (`!s t. s SUBSET t /\ affine hull s = affine hull t
+         ==> (relative_interior s) SUBSET (relative_interior t)`,
+  REWRITE_TAC[relative_interior; SUBSET; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let RELATIVE_INTERIOR_MAXIMAL = prove
+ (`!s t. t SUBSET s /\
+         open_in(subtopology euclidean (affine hull s)) t
+         ==> t SUBSET (relative_interior s)`,
+  REWRITE_TAC[relative_interior; SUBSET; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let RELATIVE_INTERIOR_UNIQUE = prove
+ (`!s t. t SUBSET s /\
+         open_in(subtopology euclidean (affine hull s)) t /\
+         (!t'. t' SUBSET s /\
+               open_in(subtopology euclidean (affine hull s)) t'
+               ==> t' SUBSET t)
+         ==> (relative_interior s = t)`,
+  MESON_TAC[SUBSET_ANTISYM; RELATIVE_INTERIOR_MAXIMAL; RELATIVE_INTERIOR_SUBSET;
+            OPEN_IN_RELATIVE_INTERIOR]);;
+
+let IN_RELATIVE_INTERIOR = prove
+ (`!x:real^N s.
+        x IN relative_interior s <=>
+        x IN s /\ ?e. &0 < e /\ (ball(x,e) INTER (affine hull s)) SUBSET s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[relative_interior; IN_ELIM_THM] THEN
+  REWRITE_TAC[OPEN_IN_OPEN; LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[TAUT `(a /\ b) /\ c /\ d <=> b /\ a /\ c /\ d`] THEN
+  REWRITE_TAC[UNWIND_THM2; SUBSET; IN_INTER] THEN EQ_TAC THENL
+   [ASM_MESON_TAC[SUBSET; OPEN_CONTAINS_BALL];
+    STRIP_TAC THEN EXISTS_TAC `ball(x:real^N,e)` THEN
+    ASM_SIMP_TAC[OPEN_BALL; CENTRE_IN_BALL; HULL_INC]]);;
+
+let IN_RELATIVE_INTERIOR_CBALL = prove
+ (`!x:real^N s.
+        x IN relative_interior s <=>
+        x IN s /\ ?e. &0 < e /\ (cball(x,e) INTER affine hull s) SUBSET s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[IN_RELATIVE_INTERIOR] THEN
+  AP_TERM_TAC THEN EQ_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THENL
+   [EXISTS_TAC `e / &2` THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `ball(x:real^N,e) INTER affine hull s` THEN
+    ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[SUBSET; IN_INTER; IN_BALL; IN_CBALL] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`];
+    EXISTS_TAC `e:real` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `cball(x:real^N,e) INTER affine hull s` THEN
+    ASM_REWRITE_TAC[] THEN
+    SIMP_TAC[SUBSET; IN_INTER; IN_BALL; IN_CBALL; REAL_LT_IMP_LE]]);;
+
+let OPEN_IN_SUBSET_RELATIVE_INTERIOR = prove
+ (`!s t. open_in(subtopology euclidean (affine hull t)) s
+         ==> (s SUBSET relative_interior t <=> s SUBSET t)`,
+  MESON_TAC[RELATIVE_INTERIOR_MAXIMAL; RELATIVE_INTERIOR_SUBSET;
+            SUBSET_TRANS]);;
+
+let RELATIVE_INTERIOR_TRANSLATION = prove
+ (`!a:real^N s.
+        relative_interior (IMAGE (\x. a + x) s) =
+        IMAGE (\x. a + x) (relative_interior s)`,
+  REWRITE_TAC[relative_interior; OPEN_IN_OPEN] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [RELATIVE_INTERIOR_TRANSLATION];;
+
+let RELATIVE_FRONTIER_TRANSLATION = prove
+ (`!a:real^N s.
+        relative_frontier (IMAGE (\x. a + x) s) =
+        IMAGE (\x. a + x) (relative_frontier s)`,
+  REWRITE_TAC[relative_frontier] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [RELATIVE_FRONTIER_TRANSLATION];;
+
+let RELATIVE_INTERIOR_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> relative_interior(IMAGE f s) = IMAGE f (relative_interior s)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[relative_interior; AFFINE_HULL_LINEAR_IMAGE] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> c /\ a /\ b`] THEN
+  REWRITE_TAC[EXISTS_SUBSET_IMAGE] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_INJECTIVE_LINEAR_IMAGE) THEN
+  ASM_REWRITE_TAC[] THEN ASM SET_TAC[]);;
+
+add_linear_invariants [RELATIVE_INTERIOR_INJECTIVE_LINEAR_IMAGE];;
+
+let RELATIVE_FRONTIER_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> relative_frontier(IMAGE f s) = IMAGE f (relative_frontier s)`,
+  REWRITE_TAC[relative_frontier] THEN GEOM_TRANSFORM_TAC[]);;
+
+add_linear_invariants [RELATIVE_FRONTIER_INJECTIVE_LINEAR_IMAGE];;
+
+let RELATIVE_INTERIOR_EQ_EMPTY = prove
+ (`!s:real^N->bool.
+        convex s ==> (relative_interior s = {} <=> s = {})`,
+  SUBGOAL_THEN
+   `!s:real^N->bool.
+        vec 0 IN s /\ convex s ==> ~(relative_interior s = {})`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    GEN_TAC THEN DISCH_TAC THEN
+    ASM_CASES_TAC `s:real^N->bool = {}` THEN
+    ASM_REWRITE_TAC[RELATIVE_INTERIOR_EMPTY] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE (\x:real^N. --a + x) s`) THEN
+    REWRITE_TAC[CONVEX_TRANSLATION_EQ; RELATIVE_INTERIOR_TRANSLATION] THEN
+    ASM_REWRITE_TAC[IMAGE_EQ_EMPTY; IN_IMAGE] THEN
+    DISCH_THEN MATCH_MP_TAC THEN EXISTS_TAC `a:real^N` THEN
+    ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC] THEN
+  GEN_TAC THEN STRIP_TAC THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_RELATIVE_INTERIOR] THEN
+  ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC] THEN
+  X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC
+   (ISPEC `s:real^N->bool` BASIS_EXISTS) THEN
+  SUBGOAL_THEN `span(s:real^N->bool) = span b` SUBST_ALL_TAC THENL
+   [ASM_SIMP_TAC[SPAN_EQ] THEN ASM_MESON_TAC[SPAN_INC; SUBSET_TRANS];
+    ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN
+  ABBREV_TAC `n = dim(s:real^N->bool)` THEN
+  SUBGOAL_THEN
+   `!c. (!v. v IN b ==> &0 <= c(v)) /\ sum b c <= &1
+        ==> vsum b (\v:real^N. c(v) % v) IN s`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN SUBGOAL_THEN
+     `vsum (vec 0 INSERT b :real^N->bool)
+           (\v. (if v = vec 0 then &1 - sum b c else c v) % v) IN s`
+    MP_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [CONVEX_EXPLICIT]) THEN
+      ASM_SIMP_TAC[INSERT_SUBSET; FINITE_INSERT; SUM_CLAUSES;
+                   INDEPENDENT_NONZERO; IN_INSERT] THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[REAL_SUB_LE]; ALL_TAC] THEN
+      REWRITE_TAC[REAL_ARITH `&1 - x + y = &1 <=> x = y`] THEN
+      MATCH_MP_TAC SUM_EQ THEN ASM_MESON_TAC[INDEPENDENT_NONZERO];
+      MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+      ASM_SIMP_TAC[VSUM_CLAUSES; INDEPENDENT_NONZERO] THEN
+      REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+      MATCH_MP_TAC VSUM_EQ THEN ASM_MESON_TAC[INDEPENDENT_NONZERO]];
+    ALL_TAC] THEN
+  ABBREV_TAC `a:real^N = vsum b (\v. inv(&2 * &n + &1) % v)` THEN
+  EXISTS_TAC `a:real^N` THEN CONJ_TAC THENL
+   [EXPAND_TAC "a" THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[SUM_CONST; REAL_LE_INV_EQ; REAL_ARITH `&0 < &2 * &n + &1`;
+                 GSYM real_div; REAL_LT_IMP_LE; REAL_LE_LDIV_EQ] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`b:real^N->bool`; `inv(&2 * &n + &1)`]
+        BASIS_COORDINATES_CONTINUOUS) THEN
+  ASM_REWRITE_TAC[REAL_LT_INV_EQ] THEN
+  ANTS_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[SUBSET; IN_INTER; IMP_CONJ_ALT] THEN
+  ASM_SIMP_TAC[SPAN_FINITE; LEFT_IMP_EXISTS_THM; IN_ELIM_THM] THEN
+  GEN_TAC THEN X_GEN_TAC `u:real^N->real` THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[IN_BALL; dist] THEN
+  EXPAND_TAC "a" THEN ASM_SIMP_TAC[GSYM VSUM_SUB] THEN
+  DISCH_THEN(fun th -> FIRST_X_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+  REWRITE_TAC[GSYM VECTOR_SUB_RDISTRIB] THEN
+  DISCH_THEN(fun th -> FIRST_X_ASSUM(MP_TAC o C MATCH_MP th)) THEN
+  REWRITE_TAC[REAL_ARITH `abs(x - y) < x <=> &0 < y /\ abs(y) < &2 * x`] THEN
+  SIMP_TAC[REAL_LT_IMP_LE] THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `&(CARD(b:real^N->bool)) * &2 * inv(&2 * &n + &1)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_BOUND THEN
+    ASM_SIMP_TAC[REAL_ARITH `abs x < a ==> x <= a`];
+    ASM_REWRITE_TAC[REAL_MUL_ASSOC] THEN REWRITE_TAC[GSYM real_div] THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_ARITH `&0 < &2 * &n + &1`] THEN
+    REAL_ARITH_TAC]);;
+
+let RELATIVE_INTERIOR_INTERIOR = prove
+ (`!s. affine hull s = (:real^N)
+       ==> relative_interior s = interior s`,
+  SIMP_TAC[relative_interior; interior; SUBTOPOLOGY_UNIV; OPEN_IN]);;
+
+let RELATIVE_INTERIOR_OPEN = prove
+ (`!s:real^N->bool. open s ==> relative_interior s = s`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[RELATIVE_INTERIOR_EMPTY] THEN
+  ASM_SIMP_TAC[RELATIVE_INTERIOR_INTERIOR; AFFINE_HULL_OPEN; INTERIOR_EQ]);;
+
+let RELATIVE_INTERIOR_NONEMPTY_INTERIOR = prove
+ (`!s. ~(interior s = {}) ==> relative_interior s = interior s`,
+  MESON_TAC[RELATIVE_INTERIOR_INTERIOR; AFFINE_HULL_NONEMPTY_INTERIOR]);;
+
+let RELATIVE_FRONTIER_NONEMPTY_INTERIOR = prove
+ (`!s. ~(interior s = {}) ==> relative_frontier s = frontier s`,
+  SIMP_TAC[relative_frontier; frontier; RELATIVE_INTERIOR_NONEMPTY_INTERIOR]);;
+
+let RELATIVE_FRONTIER_FRONTIER = prove
+ (`!s. affine hull s = (:real^N) ==> relative_frontier s = frontier s`,
+  SIMP_TAC[relative_frontier; frontier; RELATIVE_INTERIOR_INTERIOR]);;
+
+let AFFINE_HULL_CONVEX_HULL = prove
+ (`!s. affine hull (convex hull s) = affine hull s`,
+  GEN_TAC THEN MATCH_MP_TAC HULL_UNIQUE THEN
+  REWRITE_TAC[AFFINE_AFFINE_HULL; CONVEX_HULL_SUBSET_AFFINE_HULL] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HULL_MINIMAL THEN
+  ASM_MESON_TAC[SUBSET_TRANS; HULL_SUBSET]);;
+
+let INTERIOR_SIMPLEX_NONEMPTY = prove
+ (`!s:real^N->bool.
+        independent s /\ s HAS_SIZE (dimindex(:N))
+        ==> ?a. a IN interior(convex hull (vec 0 INSERT s))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `convex hull (vec 0 INSERT s):real^N->bool`
+    RELATIVE_INTERIOR_EQ_EMPTY) THEN
+  ASM_SIMP_TAC[AFFINE_HULL_CONVEX_HULL] THEN
+  REWRITE_TAC[CONVEX_HULL_EQ_EMPTY; CONVEX_CONVEX_HULL; NOT_INSERT_EMPTY] THEN
+  REWRITE_TAC[MEMBER_NOT_EMPTY] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN MATCH_MP_TAC RELATIVE_INTERIOR_INTERIOR THEN
+  SIMP_TAC[AFFINE_HULL_EQ_SPAN; IN_INSERT; HULL_INC] THEN
+  MATCH_MP_TAC(SET_RULE `!s. s SUBSET t /\ s = UNIV ==> t = UNIV`) THEN
+  EXISTS_TAC `span s:real^N->bool` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SPAN_MONO THEN MATCH_MP_TAC(SET_RULE
+     `(a INSERT s) SUBSET P hull (a INSERT s)
+      ==> s SUBSET P hull (a INSERT s)`) THEN REWRITE_TAC[HULL_SUBSET];
+    MATCH_MP_TAC(SET_RULE `UNIV SUBSET s ==> s = UNIV`) THEN
+    MATCH_MP_TAC CARD_GE_DIM_INDEPENDENT THEN
+    ASM_REWRITE_TAC[DIM_UNIV; SUBSET_UNIV] THEN
+    ASM_MESON_TAC[LE_REFL;HAS_SIZE]]);;
+
+let INTERIOR_SUBSET_RELATIVE_INTERIOR = prove
+ (`!s. interior s SUBSET relative_interior s`,
+  REWRITE_TAC[SUBSET; IN_INTERIOR; IN_RELATIVE_INTERIOR; IN_INTER] THEN
+  MESON_TAC[CENTRE_IN_BALL]);;
+
+let CONVEX_RELATIVE_INTERIOR = prove
+ (`!s:real^N->bool. convex s ==> convex(relative_interior s)`,
+  REWRITE_TAC[CONVEX_ALT; IN_RELATIVE_INTERIOR; IN_INTER;
+              SUBSET; IN_BALL; dist] THEN
+  GEN_TAC THEN DISCH_TAC THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[TAUT `(a /\ b) /\ (c /\ d) /\ e ==> f <=>
+                    a /\ c /\ e ==> b /\ d ==> f`] THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+  MATCH_MP_TAC(MESON[] `(!d e. P d /\ Q e ==> R(min d e))
+                        ==> (?e. P e) /\ (?e. Q e) ==> (?e. R e)`) THEN
+  REPEAT GEN_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+  X_GEN_TAC `z:real^N` THEN STRIP_TAC THEN
+  SUBST1_TAC(VECTOR_ARITH `z:real^N =
+   (&1 - u) % (z - u % (y - x)) + u % (z + (&1 - u) % (y - x))`) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(CONJUNCTS_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[GSYM IMP_CONJ_ALT] THEN MATCH_MP_TAC MONO_AND THEN
+  CONJ_TAC THEN DISCH_THEN MATCH_MP_TAC THEN
+  (CONJ_TAC THENL
+    [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+      `norm x < e ==> norm x = y ==> y < e`)) THEN
+     AP_TERM_TAC THEN VECTOR_ARITH_TAC;
+     REWRITE_TAC[VECTOR_ARITH `a - b % c:real^N = a + --b % c`] THEN
+     MATCH_MP_TAC IN_AFFINE_ADD_MUL_DIFF THEN
+     ASM_SIMP_TAC[AFFINE_AFFINE_HULL; HULL_INC]]));;
+
+let IN_RELATIVE_INTERIOR_CONVEX_SHRINK = prove
+ (`!s e x c:real^N.
+     convex s /\ c IN relative_interior s /\
+     x IN s /\ &0 < e /\ e <= &1
+     ==> x - e % (x - c) IN relative_interior s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_RELATIVE_INTERIOR]) THEN
+  REWRITE_TAC[IN_RELATIVE_INTERIOR; SUBSET; IN_INTER; IN_BALL; dist] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN CONJ_TAC THENL
+   [REWRITE_TAC[VECTOR_ARITH
+     `x - e % (x - c):real^N = (&1 - e) % x + e % c`] THEN
+    FIRST_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [convex]) THEN
+    ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  EXISTS_TAC `e * d: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 `(&1 / e) % y' - ((&1 - e) / e) % x:real^N`) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [UNDISCH_TAC `norm (x - e % (x - c) - y':real^N) < e * d` THEN
+      SUBGOAL_THEN `x - e % (x - c) - y':real^N =
+                    e % (c - (&1 / e % y' - (&1 - e) / e % x))`
+      SUBST1_TAC THENL
+       [ASM_SIMP_TAC[VECTOR_SUB_LDISTRIB; VECTOR_MUL_ASSOC;
+                     REAL_DIV_LMUL; REAL_LT_IMP_NZ] THEN VECTOR_ARITH_TAC;
+        ASM_SIMP_TAC[NORM_MUL; REAL_LT_LMUL_EQ; real_abs; REAL_LT_IMP_LE]];
+      REWRITE_TAC[real_div; REAL_SUB_RDISTRIB] THEN
+      ASM_SIMP_TAC[REAL_MUL_RINV; REAL_LT_IMP_NZ] THEN
+      REWRITE_TAC[VECTOR_ARITH `a % y - (b - c) % x:real^N =
+                                (c - b) % x + a % y`] THEN
+      MATCH_MP_TAC(REWRITE_RULE[AFFINE_ALT] AFFINE_AFFINE_HULL) THEN
+      ASM_SIMP_TAC[HULL_INC]];
+    DISCH_TAC THEN
+    SUBGOAL_THEN `y' = (&1 - (&1 - e)) % (&1 / e % y' - (&1 - e) / e % x) +
+                       (&1 - e) % x:real^N`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[REAL_ARITH `&1 - (&1 - e) = e`; VECTOR_SUB_LDISTRIB;
+                   VECTOR_MUL_ASSOC; REAL_DIV_LMUL; REAL_LT_IMP_NZ] THEN
+      VECTOR_ARITH_TAC;
+      FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [CONVEX_ALT]) THEN
+      ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC]]);;
+
+let IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SHRINK = prove
+ (`!s e x c:real^N.
+     convex s /\ c IN relative_interior s /\
+     x IN closure s /\ &0 < e /\ e <= &1
+     ==> x - e % (x - c) IN relative_interior s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_RELATIVE_INTERIOR]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `?y:real^N. y IN s /\ norm(y - x) * (&1 - e) < e * d`
+  STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `(x:real^N) IN s` THENL
+     [EXISTS_TAC `x:real^N` THEN
+      ASM_SIMP_TAC[REAL_LT_MUL; VECTOR_SUB_REFL; NORM_0; REAL_MUL_LZERO];
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [closure]) THEN
+    ASM_REWRITE_TAC[IN_UNION; IN_ELIM_THM; LIMPT_APPROACHABLE; dist] THEN
+    FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+     `e <= &1 ==> e = &1 \/ e < &1`)) THEN
+    ASM_SIMP_TAC[REAL_SUB_REFL; GSYM REAL_LT_RDIV_EQ; REAL_SUB_LT] THENL
+     [DISCH_THEN(MP_TAC o SPEC `&1`) THEN
+      REWRITE_TAC[REAL_MUL_RZERO; REAL_LT_01];
+      DISCH_THEN(MP_TAC o SPEC `(e * d) / (&1 - e)`)] THEN
+    ASM_SIMP_TAC[REAL_LT_RDIV_EQ; REAL_SUB_LT; REAL_MUL_LZERO; REAL_LT_MUL;
+                 REAL_MUL_LID] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN MESON_TAC[];
+    ALL_TAC] THEN
+  ABBREV_TAC `z:real^N = c + ((&1 - e) / e) % (x - y)` THEN
+  SUBGOAL_THEN `x - e % (x - c):real^N = y - e % (y - z)` SUBST1_TAC THENL
+   [EXPAND_TAC "z" THEN
+    REWRITE_TAC[VECTOR_SUB_LDISTRIB; VECTOR_ADD_LDISTRIB] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_DIV_LMUL; REAL_LT_IMP_NZ] THEN
+    VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC IN_RELATIVE_INTERIOR_CONVEX_SHRINK THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `dist(c:real^N,z) < d` ASSUME_TAC THENL
+   [EXPAND_TAC "z" THEN
+    REWRITE_TAC[NORM_ARITH `dist(c:real^N,c + x) = norm x`] THEN
+    REWRITE_TAC[NORM_MUL; REAL_ABS_DIV] THEN ONCE_REWRITE_TAC[NORM_SUB] THEN
+    REWRITE_TAC[REAL_ARITH `a / b * c:real = (c * a) / b`] THEN
+    ASM_SIMP_TAC[real_abs; REAL_SUB_LE; REAL_LT_IMP_LE; REAL_LT_LDIV_EQ] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(z:real^N) IN affine hull s` ASSUME_TAC THENL
+   [EXPAND_TAC "z" THEN MATCH_MP_TAC IN_AFFINE_ADD_MUL_DIFF THEN
+    ASM_SIMP_TAC[AFFINE_AFFINE_HULL; HULL_INC] THEN
+    MATCH_MP_TAC(SET_RULE `!t. x IN t /\ t = s ==> x IN s`) THEN
+    EXISTS_TAC `closure(affine hull s):real^N->bool` THEN
+    SIMP_TAC[CLOSURE_EQ; CLOSED_AFFINE_HULL] THEN
+    ASM_MESON_TAC[SUBSET_CLOSURE; HULL_INC; SUBSET];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[IN_RELATIVE_INTERIOR] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[IN_BALL; IN_INTER; SUBSET]; ALL_TAC] THEN
+  EXISTS_TAC `d - dist(c:real^N,z)` THEN ASM_REWRITE_TAC[REAL_SUB_LT] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ_ALT] SUBSET_TRANS)) THEN
+  REWRITE_TAC[SUBSET; IN_INTER] THEN GEN_TAC THEN
+  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN
+  UNDISCH_TAC `dist(c:real^N,z) < d` THEN REWRITE_TAC[IN_BALL] THEN
+  NORM_ARITH_TAC);;
+
+let IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SEGMENT = prove
+ (`!s a b:real^N.
+        convex s /\ a IN relative_interior s /\ b IN closure s
+        ==> segment(a,b) SUBSET relative_interior s`,
+  REWRITE_TAC[SUBSET; IN_SEGMENT] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+   `(&1 - u) % a + u % b:real^N = b - (&1 - u) % (b - a)`] THEN
+  MATCH_MP_TAC IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SHRINK THEN
+  ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC);;
+
+let RELATIVE_INTERIOR_SING = prove
+ (`!a. relative_interior {a} = {a}`,
+  GEN_TAC THEN MATCH_MP_TAC(SET_RULE
+   `s SUBSET {a} /\ ~(s = {}) ==> s = {a}`) THEN
+  SIMP_TAC[RELATIVE_INTERIOR_SUBSET; RELATIVE_INTERIOR_EQ_EMPTY;
+           CONVEX_SING] THEN
+  SET_TAC[]);;
+
+let RELATIVE_FRONTIER_SING = prove
+ (`!a:real^N. relative_frontier {a} = {}`,
+  REWRITE_TAC[relative_frontier; RELATIVE_INTERIOR_SING; CLOSURE_SING] THEN
+  SET_TAC[]);;
+
+let RELATIVE_FRONTIER_CBALL = prove
+ (`!a:real^N r. relative_frontier(cball(a,r)) =
+                if r = &0 then {} else sphere(a,r)`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  ASM_SIMP_TAC[CBALL_SING; RELATIVE_FRONTIER_SING] THEN
+  ASM_CASES_TAC `r < &0` THEN
+  ASM_SIMP_TAC[CBALL_EMPTY; SPHERE_EMPTY; RELATIVE_FRONTIER_EMPTY] THEN
+  SUBGOAL_THEN `&0 < r` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_SIMP_TAC[RELATIVE_FRONTIER_NONEMPTY_INTERIOR; INTERIOR_CBALL;
+               BALL_EQ_EMPTY; GSYM REAL_NOT_LT; FRONTIER_CBALL]);;
+
+let RELATIVE_FRONTIER_BALL = prove
+ (`!a:real^N r. relative_frontier(ball(a,r)) =
+                if r = &0 then {} else sphere(a,r)`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  ASM_SIMP_TAC[BALL_EMPTY; REAL_LE_REFL; RELATIVE_FRONTIER_EMPTY] THEN
+  ASM_CASES_TAC `r < &0` THEN
+  ASM_SIMP_TAC[BALL_EMPTY; REAL_LT_IMP_LE; SPHERE_EMPTY;
+               RELATIVE_FRONTIER_EMPTY] THEN
+  SUBGOAL_THEN `&0 < r` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_SIMP_TAC[RELATIVE_FRONTIER_NONEMPTY_INTERIOR; INTERIOR_OPEN; OPEN_BALL;
+               BALL_EQ_EMPTY; GSYM REAL_NOT_LT; FRONTIER_BALL]);;
+
+let STARLIKE_CONVEX_TWEAK_BOUNDARY_POINTS = prove
+ (`!s t:real^N->bool.
+        convex s /\ ~(s = {}) /\
+        relative_interior s SUBSET t /\ t SUBSET closure s
+        ==> starlike t`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `~(relative_interior s:real^N->bool = {})` MP_TAC THENL
+   [ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY]; REWRITE_TAC[starlike]] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `a:real^N` THEN
+  REPEAT STRIP_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC(SET_RULE
+   `a IN s /\ b IN s /\ segment[a,b] DIFF {a,b} SUBSET s
+    ==> segment[a:real^N,b] SUBSET s`) THEN
+  ASM_REWRITE_TAC[GSYM open_segment] THEN
+  ASM_MESON_TAC[IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SEGMENT; SUBSET]);;
+
+let RELATIVE_INTERIOR_PROLONG = prove
+ (`!s x y:real^N.
+        x IN relative_interior s /\ y IN s
+        ==> ?t. &1 < t /\ (y + t % (x - y)) IN s`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[IN_RELATIVE_INTERIOR_CBALL; IN_ELIM_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_THEN `e:real`
+  STRIP_ASSUME_TAC)) THEN
+  ASM_CASES_TAC `y:real^N = x` THENL
+   [ASM_REWRITE_TAC[VECTOR_ARITH `y + t % (x - x):real^N = y`] THEN
+    EXISTS_TAC `&2` THEN CONV_TAC REAL_RAT_REDUCE_CONV;
+    EXISTS_TAC `&1 + e / norm(x - y:real^N)` THEN
+    ASM_SIMP_TAC[REAL_LT_ADDR; REAL_LT_DIV; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    REWRITE_TAC[VECTOR_ARITH
+     `y + (&1 + e) % (x - y):real^N = x + e % (x - y)`] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o REWRITE_RULE[SUBSET]) THEN
+    ASM_SIMP_TAC[AFFINE_AFFINE_HULL; IN_INTER; IN_AFFINE_ADD_MUL_DIFF;
+                 HULL_INC; IN_CBALL] THEN
+    REWRITE_TAC[NORM_ARITH `dist(x:real^N,x + y) = norm y`] THEN
+    REWRITE_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM] THEN
+    ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let RELATIVE_INTERIOR_CONVEX_PROLONG = prove
+ (`!s. convex s
+       ==> relative_interior s =
+           {x:real^N | x IN s /\
+                       !y. y IN s ==> ?t. &1 < t /\ (y + t % (x - y)) IN s}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN EQ_TAC THENL
+   [SIMP_TAC[RELATIVE_INTERIOR_PROLONG] THEN
+    MESON_TAC[SUBSET; RELATIVE_INTERIOR_SUBSET];
+    STRIP_TAC THEN
+    SUBGOAL_THEN `?y:real^N. y IN relative_interior s` STRIP_ASSUME_TAC THENL
+     [ASM_SIMP_TAC[MEMBER_NOT_EMPTY; RELATIVE_INTERIOR_EQ_EMPTY] THEN
+      ASM SET_TAC[];
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `y:real^N`) THEN ANTS_TAC THENL
+     [ASM_MESON_TAC[RELATIVE_INTERIOR_SUBSET; SUBSET]; ALL_TAC] THEN
+    ASM_CASES_TAC `y:real^N = x` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`s:real^N->bool`; `y:real^N`; `y + t % (x - y):real^N`]
+        IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SEGMENT) THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[SUBSET; CLOSURE_SUBSET]; ALL_TAC] THEN
+    REWRITE_TAC[SUBSET] THEN DISCH_THEN MATCH_MP_TAC THEN
+    REWRITE_TAC[IN_SEGMENT; IN_ELIM_THM] THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH `y:real^N = y + x <=> x = vec 0`;
+      VECTOR_ARITH `(&1 - u) % y + u % (y + t % (x - y)):real^N =
+                    y + t % u % (x - y)`] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ] THEN
+    CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    EXISTS_TAC `inv t:real` THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; REAL_LT_INV_EQ;
+      REAL_INV_LT_1; REAL_LT_IMP_NZ; REAL_ARITH `&1 < x ==> &0 < x`] THEN
+    VECTOR_ARITH_TAC]);;
+
+let RELATIVE_INTERIOR_EQ_CLOSURE = prove
+ (`!s:real^N->bool.
+        relative_interior s = closure s <=> affine s`,
+  GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[RELATIVE_INTERIOR_EMPTY; CLOSURE_EMPTY; AFFINE_EMPTY] THEN
+  EQ_TAC THEN
+  SIMP_TAC[RELATIVE_INTERIOR_AFFINE; CLOSURE_CLOSED; CLOSED_AFFINE] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE
+   `relative_interior s = closure s
+    ==> relative_interior s SUBSET s /\ s SUBSET closure s
+        ==> relative_interior s = s /\ closure s = s`)) THEN
+  REWRITE_TAC[RELATIVE_INTERIOR_SUBSET; CLOSURE_SUBSET] THEN
+  REWRITE_TAC[RELATIVE_INTERIOR_EQ; CLOSURE_EQ; GSYM AFFINE_HULL_EQ] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+   `~(s = {}) ==> s = {} \/ s = a ==> a = s`)) THEN
+  MP_TAC(ISPEC `affine hull s:real^N->bool` CONNECTED_CLOPEN) THEN
+  SIMP_TAC[AFFINE_IMP_CONVEX; CONVEX_CONNECTED; AFFINE_AFFINE_HULL] THEN
+  DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC CLOSED_SUBSET THEN ASM_REWRITE_TAC[HULL_SUBSET]);;
+
+let RAY_TO_RELATIVE_FRONTIER = prove
+ (`!s a l:real^N.
+        bounded s /\ a IN relative_interior s /\
+        (a + l) IN affine hull s /\ ~(l = vec 0)
+        ==> ?d. &0 < d /\
+                (a + d % l) IN relative_frontier s /\
+                !e. &0 <= e /\ e < d ==> (a + e % l) IN relative_interior s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[relative_frontier] THEN
+  MP_TAC(ISPEC
+   `{d | &0 < d /\ ~((a + d % l:real^N) IN relative_interior(s))}` INF) THEN
+  ABBREV_TAC
+   `d = inf {d | &0 < d /\ ~((a + d % l:real^N) IN relative_interior(s))}` THEN
+  SUBGOAL_THEN
+   `?e. &0 < e /\ !d. &0 <= d /\ d < e
+                      ==> (a + d % l:real^N) IN relative_interior s`
+   (X_CHOOSE_THEN `k:real` (LABEL_TAC "0"))
+  THENL
+   [MP_TAC(ISPEC `s:real^N->bool` OPEN_IN_RELATIVE_INTERIOR) THEN
+    REWRITE_TAC[open_in; GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `a:real^N` o CONJUNCT2) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `e / norm(l:real^N)` THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT] THEN X_GEN_TAC `x:real` THEN
+    STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN CONJ_TAC THENL
+     [MATCH_MP_TAC IN_AFFINE_ADD_MUL THEN
+      ASM_REWRITE_TAC[AFFINE_AFFINE_HULL] THEN
+      ASM_MESON_TAC[SUBSET; HULL_SUBSET; RELATIVE_INTERIOR_SUBSET];
+      REWRITE_TAC[NORM_ARITH `dist(a + x:real^N,a) = norm x`] THEN
+      ASM_SIMP_TAC[NORM_MUL; GSYM REAL_LT_RDIV_EQ; NORM_POS_LT] THEN
+      ASM_REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[REAL_NOT_LT; REAL_LT_IMP_LE]] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `a:real^N` o
+       MATCH_MP BOUNDED_SUBSET_BALL) THEN
+    REWRITE_TAC[SUBSET; IN_BALL] THEN
+    DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `B / norm(l:real^N)` THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP
+     (REWRITE_RULE[SUBSET] RELATIVE_INTERIOR_SUBSET)) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE BINDER_CONV
+     [GSYM CONTRAPOS_THM]) THEN
+    REWRITE_TAC[REAL_NOT_LT] THEN DISCH_THEN MATCH_MP_TAC THEN
+    REWRITE_TAC[NORM_ARITH `dist(a:real^N,a + x) = norm x`] THEN
+    ASM_SIMP_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM;
+                 REAL_DIV_RMUL; NORM_EQ_0] THEN
+    ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "1") (LABEL_TAC "2")) THEN
+    EXISTS_TAC `d:real` THEN
+    MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `k:real` THEN
+      ASM_MESON_TAC[REAL_NOT_LT; REAL_LT_IMP_LE];
+      DISCH_TAC] THEN
+    MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+     [REWRITE_TAC[REAL_LE_LT] THEN
+      ASM_MESON_TAC[VECTOR_ARITH `a + &0 % l:real^N = a`;
+                    REAL_NOT_LT; REAL_LT_IMP_LE];
+      DISCH_TAC] THEN
+    REWRITE_TAC[IN_DIFF] THEN CONJ_TAC THENL
+     [REWRITE_TAC[CLOSURE_APPROACHABLE] THEN
+      X_GEN_TAC `x:real` THEN DISCH_TAC THEN
+      EXISTS_TAC `a + (d - min d (x / &2 / norm(l:real^N))) % l` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC(REWRITE_RULE[SUBSET] RELATIVE_INTERIOR_SUBSET) THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN
+        CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+        MATCH_MP_TAC(REAL_ARITH `&0 < x /\ &0 < d ==> d - min d x < d`) THEN
+        ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; NORM_POS_LT];
+        REWRITE_TAC[NORM_ARITH `dist(a + x:real^N,a + y) = norm(x - y)`] THEN
+        REWRITE_TAC[GSYM VECTOR_SUB_RDISTRIB; NORM_MUL] THEN
+        ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; NORM_POS_LT] THEN
+        MATCH_MP_TAC(REAL_ARITH
+         `&0 < x /\ x < y /\ &0 < d ==> abs((d - min d x) - d) < y`) THEN
+        REWRITE_TAC[REAL_ARITH `x / &2 / y < x / y <=> &0 < x / y`] THEN
+        ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; NORM_POS_LT]];
+      DISCH_TAC THEN
+      MP_TAC(ISPEC `s:real^N->bool` OPEN_IN_RELATIVE_INTERIOR) THEN
+      REWRITE_TAC[open_in; GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+      DISCH_THEN(MP_TAC o SPEC `a + d % l:real^N` o CONJUNCT2) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(X_CHOOSE_THEN `e:real`
+       (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "3"))) THEN
+      REMOVE_THEN "2" (MP_TAC o SPEC `d + e / norm(l:real^N)`) THEN
+      ASM_SIMP_TAC[NOT_IMP; REAL_ARITH `~(d + l <= d) <=> &0 < l`;
+                   REAL_LT_DIV; NORM_POS_LT] THEN
+      X_GEN_TAC `x:real` THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+      ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+      REWRITE_TAC[REAL_NOT_LE] THEN DISCH_TAC THEN
+      ASM_CASES_TAC `x < d` THEN ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+      REMOVE_THEN "3" MATCH_MP_TAC THEN CONJ_TAC THENL
+       [MATCH_MP_TAC IN_AFFINE_ADD_MUL THEN
+        ASM_REWRITE_TAC[AFFINE_AFFINE_HULL] THEN
+        ASM_MESON_TAC[SUBSET; HULL_SUBSET; RELATIVE_INTERIOR_SUBSET];
+        REWRITE_TAC[NORM_ARITH `dist(a + x:real^N,a + y) = norm(x - y)`] THEN
+        REWRITE_TAC[GSYM VECTOR_SUB_RDISTRIB; NORM_MUL] THEN
+        ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; NORM_POS_LT] THEN
+        ASM_REAL_ARITH_TAC]]]);;
+
+let RAY_TO_FRONTIER = prove
+ (`!s a l:real^N.
+        bounded s /\ a IN interior s /\ ~(l = vec 0)
+        ==> ?d. &0 < d /\ (a + d % l) IN frontier s /\
+                !e. &0 <= e /\ e < d ==> (a + e % l) IN interior s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[frontier] THEN
+  SUBGOAL_THEN `interior s:real^N->bool = relative_interior s` SUBST1_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[GSYM relative_frontier] THEN
+    MATCH_MP_TAC RAY_TO_RELATIVE_FRONTIER THEN ASM_REWRITE_TAC[]] THEN
+  ASM_MESON_TAC[NOT_IN_EMPTY; RELATIVE_INTERIOR_NONEMPTY_INTERIOR; IN_UNIV;
+                AFFINE_HULL_NONEMPTY_INTERIOR]);;
+
+let RELATIVE_FRONTIER_NOT_SING = prove
+ (`!s a:real^N. bounded s ==> ~(relative_frontier s = {a})`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[RELATIVE_FRONTIER_EMPTY; NOT_INSERT_EMPTY] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `z:real^N`) THEN
+  ASM_CASES_TAC `s = {z:real^N}` THEN
+  ASM_REWRITE_TAC[RELATIVE_FRONTIER_SING; NOT_INSERT_EMPTY] THEN
+  SUBGOAL_THEN `?w:real^N. w IN s /\ ~(w = z)` STRIP_ASSUME_TAC THENL
+   [ASM SET_TAC[]; REPEAT STRIP_TAC] THEN
+  SUBGOAL_THEN
+    `~((w:real^N) IN relative_frontier s /\ z IN relative_frontier s)`
+  MP_TAC THENL [ASM SET_TAC[]; DISCH_TAC] THEN
+  MAP_EVERY UNDISCH_TAC
+   [`relative_frontier s = {a:real^N}`; `bounded(s:real^N->bool)`;
+    `~(w:real^N = z)`; `(z:real^N) IN s`; `(w:real^N) IN s`;
+    `~((w:real^N) IN relative_frontier s /\ z IN relative_frontier s)`] THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN REWRITE_TAC[DE_MORGAN_THM] THEN
+  MAP_EVERY (fun t -> SPEC_TAC(t,t)) [`z:real^N`; `w:real^N`] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!w z. Q w z <=> Q z w) /\ (!w z. P z ==> Q w z)
+    ==> !w z. P w \/ P z ==> Q w z`) THEN
+  CONJ_TAC THENL [MESON_TAC[]; REPEAT GEN_TAC] THEN
+  DISCH_THEN(fun th -> REPEAT STRIP_TAC THEN MP_TAC th) THEN
+  REWRITE_TAC[relative_frontier; IN_DIFF] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[SUBSET; CLOSURE_SUBSET]; DISCH_TAC] THEN
+  MP_TAC(GEN `d:real`
+   (ISPECL [`s:real^N->bool`; `z:real^N`; `d % (w - z):real^N`]
+   RAY_TO_RELATIVE_FRONTIER)) THEN
+  ASM_SIMP_TAC[VECTOR_SUB_EQ; IN_AFFINE_ADD_MUL_DIFF; AFFINE_AFFINE_HULL;
+               HULL_INC; VECTOR_MUL_EQ_0] THEN
+  DISCH_THEN(fun th -> MP_TAC(SPEC `&1` th) THEN MP_TAC(SPEC `--(&1)` th)) THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[IN_SING] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` (STRIP_ASSUME_TAC o GSYM)) THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_RCANCEL; VECTOR_MUL_ASSOC; VECTOR_SUB_EQ;
+                  VECTOR_ARITH `a + x:real^N = a + y <=> x = y`] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let RELATIVE_INTERIOR_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        relative_interior(s PCROSS t) =
+        relative_interior s PCROSS relative_interior t`,
+  REPEAT STRIP_TAC THEN MAP_EVERY ASM_CASES_TAC
+   [`s:real^M->bool = {}`; `t:real^N->bool = {}`] THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; RELATIVE_INTERIOR_EMPTY] THEN
+  REWRITE_TAC[relative_interior; AFFINE_HULL_PCROSS] THEN
+  REWRITE_TAC[EXTENSION; FORALL_PASTECART; IN_ELIM_THM;
+              PASTECART_IN_PCROSS] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `y:real^N`] THEN EQ_TAC THENL
+   [ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> r /\ q /\ p`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^(M,N)finite_sum->bool`
+     (CONJUNCTS_THEN ASSUME_TAC)) THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP PASTECART_IN_INTERIOR_SUBTOPOLOGY) THEN
+    REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN
+    REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    W(MP_TAC o PART_MATCH (funpow 3 rand) SUBSET_PCROSS o snd) THEN
+    ASM SET_TAC[];
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `v:real^M->bool` STRIP_ASSUME_TAC)
+     (X_CHOOSE_THEN `w:real^N->bool` STRIP_ASSUME_TAC)) THEN
+    EXISTS_TAC `(v:real^M->bool) PCROSS (w:real^N->bool)` THEN
+    ASM_SIMP_TAC[PASTECART_IN_PCROSS; SUBSET_PCROSS; OPEN_IN_PCROSS]]);;
+
+let RELATIVE_FRONTIER_EQ_EMPTY = prove
+ (`!s:real^N->bool. relative_frontier s = {} <=> affine s`,
+  GEN_TAC THEN REWRITE_TAC[relative_frontier] THEN
+  REWRITE_TAC[GSYM RELATIVE_INTERIOR_EQ_CLOSURE] THEN
+  MP_TAC(ISPEC `s:real^N->bool` RELATIVE_INTERIOR_SUBSET) THEN
+  MP_TAC(ISPEC `s:real^N->bool` CLOSURE_SUBSET) THEN SET_TAC[]);;
+
+let DIAMETER_BOUNDED_BOUND_LT = prove
+ (`!s x y:real^N.
+        bounded s /\ x IN relative_interior s /\ y IN closure s /\
+        ~(diameter s = &0)
+        ==> norm(x - y) < diameter s`,
+  let lemma = prove
+   (`!s x y:real^N.
+          bounded s /\ x IN relative_interior s /\ y IN s /\
+          ~(diameter s = &0)
+          ==> norm(x - y) < diameter s`,
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM
+     (MP_TAC o GEN_REWRITE_RULE I [IN_RELATIVE_INTERIOR_CBALL]) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_THEN `e:real`
+     STRIP_ASSUME_TAC)) THEN
+    ASM_SIMP_TAC[REAL_LT_LE; DIAMETER_BOUNDED_BOUND] THEN
+    ASM_CASES_TAC `y:real^N = x` THEN
+    ASM_SIMP_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+    DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    DISCH_THEN(MP_TAC o SPEC `x + e / norm(x - y) % (x - y):real^N`) THEN
+    REWRITE_TAC[NOT_IMP; IN_INTER] THEN REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[IN_CBALL; NORM_ARITH `dist(x:real^M,x + y) = norm y`] THEN
+      ASM_SIMP_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM; REAL_DIV_RMUL;
+                   NORM_EQ_0; VECTOR_SUB_EQ] THEN ASM_REAL_ARITH_TAC;
+      MATCH_MP_TAC IN_AFFINE_ADD_MUL_DIFF THEN
+      ASM_SIMP_TAC[HULL_INC; AFFINE_AFFINE_HULL];
+      DISCH_TAC THEN MP_TAC(ISPECL
+       [`s:real^N->bool`; `x + e / norm(x - y) % (x - y):real^N`; `y:real^N`]
+          DIAMETER_BOUNDED_BOUND) THEN
+      ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+      REWRITE_TAC[VECTOR_ARITH
+       `(x + e % (x - y)) - y:real^N = (&1 + e) % (x - y)`] THEN
+      SIMP_TAC[NORM_MUL; REAL_ARITH `~(a * n <= n) <=> &0 < n * (a - &1)`] THEN
+      MATCH_MP_TAC REAL_LT_MUL THEN
+      ASM_REWRITE_TAC[NORM_POS_LT; VECTOR_SUB_EQ] THEN
+      MATCH_MP_TAC(REAL_ARITH `&0 < e ==> &0 < abs(&1 + e) - &1`) THEN
+      MATCH_MP_TAC REAL_LT_DIV THEN
+      ASM_REWRITE_TAC[NORM_POS_LT; VECTOR_SUB_EQ]]) in
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`closure s:real^N->bool`; `x:real^N`; `y:real^N`]
+        lemma) THEN
+  ASM_SIMP_TAC[DIAMETER_CLOSURE; BOUNDED_CLOSURE] THEN
+  DISCH_THEN MATCH_MP_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+   (SET_RULE `x IN s ==> s SUBSET t ==> x IN t`)) THEN
+  MATCH_MP_TAC SUBSET_RELATIVE_INTERIOR THEN
+  REWRITE_TAC[CLOSURE_SUBSET; AFFINE_HULL_CLOSURE]);;
+
+let DIAMETER_ATTAINED_RELATIVE_FRONTIER = prove
+ (`!s:real^N->bool.
+        bounded s /\ ~(diameter s = &0)
+        ==> ?x y. x IN relative_frontier s /\
+                  y IN relative_frontier s /\
+                  norm(x - y) = diameter s`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[DIAMETER_EMPTY; relative_frontier] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `closure s:real^N->bool` DIAMETER_COMPACT_ATTAINED) THEN
+  ASM_SIMP_TAC[COMPACT_CLOSURE; CLOSURE_EQ_EMPTY; DIAMETER_CLOSURE] THEN
+  REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[IN_DIFF] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `s:real^N->bool` DIAMETER_BOUNDED_BOUND_LT) THENL
+   [DISCH_THEN(MP_TAC o SPECL [`x:real^N`; `y:real^N`]);
+    DISCH_THEN(MP_TAC o SPECL [`y:real^N`; `x:real^N`])] THEN
+  ASM_MESON_TAC[REAL_LT_REFL; NORM_SUB]);;
+
+let DIAMETER_RELATIVE_FRONTIER = prove
+ (`!s:real^N->bool.
+        bounded s /\ ~(?a. s = {a})
+        ==> diameter(relative_frontier s) = diameter s`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[RELATIVE_FRONTIER_EMPTY] THEN
+  REWRITE_TAC[relative_frontier] THEN
+  ASM_SIMP_TAC[GSYM DIAMETER_CLOSURE; GSYM REAL_LE_ANTISYM] THEN
+  ASM_SIMP_TAC[SUBSET_DIFF; DIAMETER_SUBSET; BOUNDED_CLOSURE] THEN
+  ASM_SIMP_TAC[DIAMETER_CLOSURE] THEN
+  MP_TAC(ISPEC `s:real^N->bool` DIAMETER_ATTAINED_RELATIVE_FRONTIER) THEN
+  ASM_SIMP_TAC[DIAMETER_EQ_0; relative_frontier] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN MATCH_MP_TAC DIAMETER_BOUNDED_BOUND THEN
+  ASM_SIMP_TAC[BOUNDED_CLOSURE; BOUNDED_DIFF]);;
+
+let DIAMETER_ATTAINED_FRONTIER = prove
+ (`!s:real^N->bool.
+        bounded s /\ ~(diameter s = &0)
+        ==> ?x y. x IN frontier s /\ y IN frontier s /\
+                  norm(x - y) = diameter s`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP DIAMETER_ATTAINED_RELATIVE_FRONTIER) THEN
+  REWRITE_TAC[frontier; relative_frontier; IN_DIFF] THEN
+  MESON_TAC[REWRITE_RULE[SUBSET] INTERIOR_SUBSET_RELATIVE_INTERIOR]);;
+
+let DIAMETER_FRONTIER = prove
+ (`!s:real^N->bool. bounded s ==> diameter(frontier s) = diameter s`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `?a:real^N. s = {a}` THENL
+   [ASM_MESON_TAC[FRONTIER_SING]; ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `!r. r <= f /\ f <= s /\ r = s ==> f = s`) THEN
+  EXISTS_TAC `diameter(closure s DIFF relative_interior s:real^N->bool)` THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_SIMP_TAC[GSYM DIAMETER_CLOSURE] THEN MATCH_MP_TAC DIAMETER_SUBSET THEN
+    ASM_SIMP_TAC[BOUNDED_FRONTIER] THEN REWRITE_TAC[frontier] THEN
+    MP_TAC(ISPEC `s:real^N->bool` INTERIOR_SUBSET_RELATIVE_INTERIOR) THEN
+    SET_TAC[];
+    ASM_SIMP_TAC[GSYM DIAMETER_CLOSURE] THEN MATCH_MP_TAC DIAMETER_SUBSET THEN
+    ASM_SIMP_TAC[BOUNDED_CLOSURE; frontier; SUBSET_DIFF];
+    ASM_SIMP_TAC[DIAMETER_RELATIVE_FRONTIER; GSYM relative_frontier]]);;
+
+let DIAMETER_SPHERE = prove
+ (`!a:real^N r. diameter(sphere(a,r)) = if r < &0 then &0 else &2 * r`,
+  REWRITE_TAC[GSYM FRONTIER_CBALL] THEN
+  ASM_SIMP_TAC[DIAMETER_FRONTIER; BOUNDED_CBALL; DIAMETER_CBALL]);;
+
+let CLOSEST_POINT_IN_RELATIVE_INTERIOR = prove
+ (`!s x:real^N.
+        closed s /\ ~(s = {}) /\ x IN affine hull s
+        ==> ((closest_point s x) IN relative_interior s <=>
+             x IN relative_interior s)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `(x:real^N) IN s` THEN
+  ASM_SIMP_TAC[CLOSEST_POINT_SELF] THEN
+  MATCH_MP_TAC(TAUT `~q /\ ~p ==> (p <=> q)`) THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[RELATIVE_INTERIOR_SUBSET; SUBSET]; STRIP_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_RELATIVE_INTERIOR_CBALL]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `~(closest_point s (x:real^N) = x)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `x:real^N`;
+   `closest_point s x -
+    (min (&1) (e / norm(closest_point s x - x))) %
+    (closest_point s x - x):real^N`]
+    CLOSEST_POINT_LE) THEN
+  ASM_REWRITE_TAC[dist; NOT_IMP; VECTOR_ARITH
+   `x - (y - e % (y - x)):real^N = (&1 - e) % (x - y)`] THEN
+  CONJ_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    REWRITE_TAC[IN_CBALL; IN_INTER] THEN CONJ_TAC THENL
+     [REWRITE_TAC[NORM_ARITH `dist(a:real^N,a - x) = norm x`] THEN
+      REWRITE_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM] THEN
+      ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+      MATCH_MP_TAC(REAL_ARITH `&0 <= a ==> abs(min (&1) a) <= a`) THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LE_DIV; NORM_POS_LE];
+      MATCH_MP_TAC IN_AFFINE_SUB_MUL_DIFF THEN
+      ASM_SIMP_TAC[AFFINE_AFFINE_HULL; HULL_INC]];
+    REWRITE_TAC[NORM_MUL; REAL_ARITH
+     `~(n <= a * n) <=> &0 < (&1 - a) * n`] THEN
+    MATCH_MP_TAC REAL_LT_MUL THEN
+    ASM_SIMP_TAC[NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `&0 < e /\ e <= &1 ==> &0 < &1 - abs(&1 - e)`) THEN
+    REWRITE_TAC[REAL_MIN_LE; REAL_LT_MIN; REAL_LT_01; REAL_LE_REFL] THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; VECTOR_SUB_EQ]]);;
+
+let CLOSEST_POINT_IN_RELATIVE_FRONTIER = prove
+ (`!s x:real^N.
+        closed s /\ ~(s = {}) /\ x IN affine hull s DIFF relative_interior s
+        ==> closest_point s x IN relative_frontier s`,
+  SIMP_TAC[relative_frontier; IN_DIFF; CLOSEST_POINT_IN_RELATIVE_INTERIOR] THEN
+  MESON_TAC[CLOSURE_SUBSET; CLOSEST_POINT_IN_SET; SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Interior, relative interior and closure interrelations.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_CLOSURE_INTERIOR = prove
+ (`!s:real^N->bool.
+        convex s /\ ~(interior s = {})
+        ==> closure(interior s) = closure s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  SIMP_TAC[SUBSET_CLOSURE; INTERIOR_SUBSET] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN REWRITE_TAC[SUBSET] THEN
+  X_GEN_TAC `b:real^N` THEN DISCH_TAC THEN ASM_CASES_TAC `b:real^N = a` THENL
+   [ASM_MESON_TAC[CLOSURE_SUBSET; SUBSET]; ALL_TAC] THEN
+  REWRITE_TAC[closure; IN_UNION; IN_ELIM_THM] THEN DISJ2_TAC THEN
+  REWRITE_TAC[LIMPT_APPROACHABLE] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  EXISTS_TAC `b - min (e / &2 / norm(b - a)) (&1) % (b - a):real^N` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC IN_INTERIOR_CLOSURE_CONVEX_SHRINK THEN
+    ASM_REWRITE_TAC[REAL_MIN_LE; REAL_LT_MIN; REAL_LE_REFL; REAL_LT_01];
+    REWRITE_TAC[VECTOR_ARITH `b - x:real^N = b <=> x = vec 0`] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < x ==> ~(min x (&1) = &0)`);
+    REWRITE_TAC[NORM_ARITH `dist(b - x:real^N,b) = norm x`] THEN
+    REWRITE_TAC[NORM_MUL] THEN MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `e / &2 / norm(b - a:real^N) * norm(b - a)` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+      MATCH_MP_TAC(REAL_ARITH `&0 < x ==> abs(min x (&1)) <= x`);
+      ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_POS_LT; REAL_LT_IMP_NZ;
+                   VECTOR_SUB_EQ] THEN
+      ASM_REAL_ARITH_TAC]] THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; REAL_OF_NUM_LT;
+                 VECTOR_SUB_EQ; ARITH]);;
+
+let EMPTY_INTERIOR_SUBSET_HYPERPLANE = prove
+ (`!s. convex s /\ interior s = {}
+       ==> ?a:real^N b. ~(a = vec 0) /\ s SUBSET {x | a dot x = b}`,
+  let lemma = prove
+   (`!s. convex s /\ (vec 0) IN s /\ interior s = {}
+         ==> ?a:real^N b. ~(a = vec 0) /\ s SUBSET {x | a dot x = b}`,
+    GEN_TAC THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN
+    SUBGOAL_THEN `~(relative_interior(s:real^N->bool) = {})` MP_TAC THENL
+     [ASM_MESON_TAC[RELATIVE_INTERIOR_EQ_EMPTY; MEMBER_NOT_EMPTY]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[CONTRAPOS_THM] THEN MATCH_MP_TAC EQ_IMP THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC RELATIVE_INTERIOR_INTERIOR THEN
+    ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC] THEN
+    ONCE_REWRITE_TAC[GSYM SPAN_UNIV] THEN MATCH_MP_TAC DIM_EQ_SPAN THEN
+    REWRITE_TAC[SUBSET_UNIV; DIM_UNIV; GSYM NOT_LT] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP LOWDIM_SUBSET_HYPERPLANE) THEN
+    DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_EXISTS_THM]) THEN
+    DISCH_THEN(MP_TAC o SPEC `a:real^N`) THEN
+    ASM_REWRITE_TAC[NOT_EXISTS_THM] THEN EXISTS_TAC `&0` THEN
+    ASM_MESON_TAC[SUBSET_TRANS; SPAN_INC]) in
+  GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_MESON_TAC[EMPTY_SUBSET; BASIS_NONZERO; LE_REFL; DIMINDEX_GE_1];
+    ALL_TAC] THEN
+  STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+  MP_TAC(ISPEC `IMAGE (\x:real^N. --a + x) s` lemma) THEN
+  ASM_REWRITE_TAC[CONVEX_TRANSLATION_EQ; INTERIOR_TRANSLATION;
+                  IMAGE_EQ_EMPTY; IN_IMAGE; UNWIND_THM2;
+                  VECTOR_ARITH `vec 0:real^N = --a + x <=> x = a`] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^N` THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM; DOT_RADD] THEN
+  MESON_TAC[REAL_ARITH `a + x:real = b <=> x = b - a`]);;
+
+let CONVEX_INTERIOR_CLOSURE = prove
+ (`!s:real^N->bool. convex s ==> interior(closure s) = interior s`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `interior(s:real^N->bool) = {}` THENL
+   [MP_TAC(ISPEC `s:real^N->bool` EMPTY_INTERIOR_SUBSET_HYPERPLANE) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real`] THEN STRIP_TAC THEN
+    MATCH_MP_TAC(SET_RULE `!t. s SUBSET t /\ t = {} ==> s = {}`) THEN
+    EXISTS_TAC `interior {x:real^N | a dot x = b}` THEN CONJ_TAC THENL
+     [ALL_TAC;  ASM_SIMP_TAC[INTERIOR_HYPERPLANE]] THEN
+    MATCH_MP_TAC SUBSET_INTERIOR THEN MATCH_MP_TAC CLOSURE_MINIMAL THEN
+    ASM_REWRITE_TAC[CLOSED_HYPERPLANE];
+    ALL_TAC] THEN
+  FIRST_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
+  MATCH_MP_TAC SUBSET_ANTISYM THEN
+  SIMP_TAC[SUBSET_INTERIOR; CLOSURE_SUBSET] THEN
+  REWRITE_TAC[SUBSET] THEN X_GEN_TAC `b:real^N` THEN DISCH_TAC THEN
+  MP_TAC(ASSUME `(b:real^N) IN interior(closure s)`) THEN
+  GEN_REWRITE_TAC LAND_CONV [IN_INTERIOR_CBALL] THEN
+  REWRITE_TAC[SUBSET; IN_CBALL; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `e:real` THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_CASES_TAC `b:real^N = a` THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(MP_TAC o SPEC `b + e / norm(b - a) % (b - a):real^N`) THEN
+  ASM_SIMP_TAC[NORM_ARITH `dist(b:real^N,b + e) = norm e`; NORM_MUL;
+    REAL_ABS_DIV; REAL_ABS_NORM; REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ;
+    REAL_ARITH `&0 < e ==> abs e <= e`] THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN
+   `b = (b + e / norm(b - a) % (b - a)) -
+        e / norm(b - a) / (&1 + e / norm(b - a)) %
+        ((b + e / norm(b - a) % (b - a)) - a):real^N`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[VECTOR_ARITH
+     `b = (b + e % (b - a)) - d % ((b + e % (b - a)) - a) <=>
+      (e - d * (&1 + e)) % (b - a) = vec 0`] THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_EQ; VECTOR_MUL_EQ_0];
+    MATCH_MP_TAC IN_INTERIOR_CLOSURE_CONVEX_SHRINK] THEN
+  ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LT_DIV; NORM_POS_LT;
+               VECTOR_SUB_EQ; REAL_ARITH `&0 < x ==> &0 < &1 + x`;
+               REAL_ARITH `&0 < x ==> ~(&1 + x = &0)`;
+               REAL_MUL_LID; REAL_ADD_RDISTRIB; REAL_DIV_RMUL;
+               REAL_LT_IMP_NZ; REAL_LE_ADDL; NORM_POS_LE; REAL_SUB_REFL]);;
+
+let FRONTIER_CLOSURE_CONVEX = prove
+ (`!s:real^N->bool. convex s ==> frontier(closure s) = frontier s`,
+  SIMP_TAC[frontier; CLOSURE_CLOSURE; CONVEX_INTERIOR_CLOSURE]);;
+
+let CONVEX_CLOSURE_RELATIVE_INTERIOR = prove
+ (`!s:real^N->bool.
+        convex s ==> closure(relative_interior s) = closure s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  SIMP_TAC[SUBSET_CLOSURE; RELATIVE_INTERIOR_SUBSET] THEN
+  ASM_CASES_TAC `relative_interior(s:real^N->bool) = {}` THENL
+   [ASM_MESON_TAC[RELATIVE_INTERIOR_EQ_EMPTY; SUBSET_REFL]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN REWRITE_TAC[SUBSET] THEN
+  X_GEN_TAC `b:real^N` THEN DISCH_TAC THEN ASM_CASES_TAC `b:real^N = a` THENL
+   [ASM_MESON_TAC[CLOSURE_SUBSET; SUBSET]; ALL_TAC] THEN
+  REWRITE_TAC[closure; IN_UNION; IN_ELIM_THM] THEN DISJ2_TAC THEN
+  REWRITE_TAC[LIMPT_APPROACHABLE] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  EXISTS_TAC `b - min (e / &2 / norm(b - a)) (&1) % (b - a):real^N` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SHRINK THEN
+    ASM_REWRITE_TAC[REAL_MIN_LE; REAL_LT_MIN; REAL_LE_REFL; REAL_LT_01];
+    REWRITE_TAC[VECTOR_ARITH `b - x:real^N = b <=> x = vec 0`] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < x ==> ~(min x (&1) = &0)`);
+    REWRITE_TAC[NORM_ARITH `dist(b - x:real^N,b) = norm x`] THEN
+    REWRITE_TAC[NORM_MUL] THEN MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `e / &2 / norm(b - a:real^N) * norm(b - a)` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+      MATCH_MP_TAC(REAL_ARITH `&0 < x ==> abs(min x (&1)) <= x`);
+      ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_POS_LT; REAL_LT_IMP_NZ;
+                   VECTOR_SUB_EQ] THEN
+      ASM_REAL_ARITH_TAC]] THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; REAL_OF_NUM_LT;
+                 VECTOR_SUB_EQ; ARITH]);;
+
+let AFFINE_HULL_RELATIVE_INTERIOR = prove
+ (`!s. convex s
+       ==> affine hull (relative_interior s) = affine hull s`,
+  MESON_TAC[CONVEX_CLOSURE_RELATIVE_INTERIOR; AFFINE_HULL_CLOSURE]);;
+
+let CONVEX_RELATIVE_INTERIOR_CLOSURE = prove
+ (`!s:real^N->bool.
+        convex s ==> relative_interior(closure s) = relative_interior s`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[CLOSURE_EMPTY; RELATIVE_INTERIOR_EMPTY] THEN
+  SUBGOAL_THEN `?a:real^N. a IN relative_interior s` STRIP_ASSUME_TAC THENL
+   [ASM_SIMP_TAC[MEMBER_NOT_EMPTY; RELATIVE_INTERIOR_EQ_EMPTY];
+    ALL_TAC] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[SUBSET] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[IN_RELATIVE_INTERIOR; AFFINE_HULL_CLOSURE; SUBSET] THEN
+    MESON_TAC[CLOSURE_SUBSET; SUBSET]] THEN
+  X_GEN_TAC `b:real^N` THEN DISCH_TAC THEN
+  MP_TAC(ASSUME `(b:real^N) IN relative_interior(closure s)`) THEN
+  GEN_REWRITE_TAC LAND_CONV [IN_RELATIVE_INTERIOR_CBALL] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[SUBSET; IN_CBALL; IN_INTER; LEFT_IMP_EXISTS_THM;
+              AFFINE_HULL_CLOSURE] THEN
+  X_GEN_TAC `e:real` THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_CASES_TAC `b:real^N = a` THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(MP_TAC o SPEC `b + e / norm(b - a) % (b - a):real^N`) THEN
+  ASM_SIMP_TAC[NORM_ARITH `dist(b:real^N,b + e) = norm e`; NORM_MUL;
+    REAL_ABS_DIV; REAL_ABS_NORM; REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ;
+    REAL_ARITH `&0 < e ==> abs e <= e`] THEN
+  ANTS_TAC THENL
+   [MATCH_MP_TAC IN_AFFINE_ADD_MUL_DIFF THEN
+    ASM_MESON_TAC[SUBSET; AFFINE_AFFINE_HULL; RELATIVE_INTERIOR_SUBSET;
+                  CLOSURE_SUBSET_AFFINE_HULL; HULL_INC];
+    ALL_TAC] THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN
+   `b = (b + e / norm(b - a) % (b - a)) -
+        e / norm(b - a) / (&1 + e / norm(b - a)) %
+        ((b + e / norm(b - a) % (b - a)) - a):real^N`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[VECTOR_ARITH
+     `b = (b + e % (b - a)) - d % ((b + e % (b - a)) - a) <=>
+      (e - d * (&1 + e)) % (b - a) = vec 0`] THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_EQ; VECTOR_MUL_EQ_0];
+    MATCH_MP_TAC IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SHRINK] THEN
+  ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LT_DIV; NORM_POS_LT;
+               VECTOR_SUB_EQ; REAL_ARITH `&0 < x ==> &0 < &1 + x`;
+               REAL_ARITH `&0 < x ==> ~(&1 + x = &0)`;
+               REAL_MUL_LID; REAL_ADD_RDISTRIB; REAL_DIV_RMUL;
+               REAL_LT_IMP_NZ; REAL_LE_ADDL; NORM_POS_LE; REAL_SUB_REFL]);;
+
+let RELATIVE_FRONTIER_CLOSURE = prove
+ (`!s. convex s ==> relative_frontier(closure s) = relative_frontier s`,
+  SIMP_TAC[relative_frontier; CLOSURE_CLOSURE;
+           CONVEX_RELATIVE_INTERIOR_CLOSURE]);;
+
+let CONNECTED_INTER_RELATIVE_FRONTIER = prove
+ (`!s t:real^N->bool.
+        connected s /\ s SUBSET affine hull t /\
+        ~(s INTER t = {}) /\ ~(s DIFF t = {})
+        ==> ~(s INTER relative_frontier t = {})`,
+  REWRITE_TAC[relative_frontier] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONNECTED_OPEN_IN]) THEN
+  REWRITE_TAC[] THEN MAP_EVERY EXISTS_TAC
+   [`s INTER relative_interior t:real^N->bool`;
+    `s DIFF closure t:real^N->bool`] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC OPEN_IN_SUBTOPOLOGY_INTER_SUBSET THEN
+    EXISTS_TAC `affine hull t:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC OPEN_IN_INTER THEN
+    REWRITE_TAC[OPEN_IN_RELATIVE_INTERIOR; OPEN_IN_SUBTOPOLOGY_REFL] THEN
+    REWRITE_TAC[TOPSPACE_EUCLIDEAN; SUBSET_UNIV];
+    ONCE_REWRITE_TAC[SET_RULE `s DIFF t = s INTER (UNIV DIFF t)`] THEN
+    MATCH_MP_TAC OPEN_IN_OPEN_INTER THEN
+    REWRITE_TAC[GSYM closed; CLOSED_CLOSURE];
+    ASM SET_TAC[];
+    MATCH_MP_TAC(SET_RULE
+     `i SUBSET t /\ t SUBSET c ==> (s INTER i) INTER (s DIFF c) = {}`) THEN
+    REWRITE_TAC[RELATIVE_INTERIOR_SUBSET; CLOSURE_SUBSET];
+    MP_TAC(ISPEC `t:real^N->bool` CLOSURE_SUBSET) THEN ASM SET_TAC[];
+    MP_TAC(ISPEC `t:real^N->bool` RELATIVE_INTERIOR_SUBSET) THEN
+    ASM SET_TAC[]]);;
+
+let CLOSED_RELATIVE_FRONTIER = prove
+ (`!s:real^N->bool. closed(relative_frontier s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[relative_frontier] THEN
+  MATCH_MP_TAC CLOSED_IN_CLOSED_TRANS THEN
+  EXISTS_TAC `affine hull s:real^N->bool` THEN
+  REWRITE_TAC[CLOSED_AFFINE_HULL] THEN MATCH_MP_TAC CLOSED_IN_DIFF THEN
+  REWRITE_TAC[OPEN_IN_RELATIVE_INTERIOR] THEN
+  MATCH_MP_TAC CLOSED_SUBSET THEN REWRITE_TAC[CLOSED_CLOSURE] THEN
+  MATCH_MP_TAC(SET_RULE
+   `s SUBSET closure t /\ closure t = t ==> s SUBSET t`) THEN
+  SIMP_TAC[SUBSET_CLOSURE; HULL_SUBSET; CLOSURE_EQ; CLOSED_AFFINE_HULL]);;
+
+let CLOSED_RELATIVE_BOUNDARY = prove
+ (`!s. closed s ==> closed(s DIFF relative_interior s)`,
+  MESON_TAC[CLOSED_RELATIVE_FRONTIER; relative_frontier; CLOSURE_CLOSED]);;
+
+let COMPACT_RELATIVE_BOUNDARY = prove
+ (`!s. compact s ==> compact(s DIFF relative_interior s)`,
+  SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; CLOSED_RELATIVE_BOUNDARY;
+           BOUNDED_DIFF]);;
+
+let BOUNDED_RELATIVE_FRONTIER = prove
+ (`!s:real^N->bool. bounded s ==> bounded(relative_frontier s)`,
+  REWRITE_TAC[relative_frontier] THEN
+  MESON_TAC[BOUNDED_CLOSURE; BOUNDED_SUBSET; SUBSET_DIFF]);;
+
+let COMPACT_RELATIVE_FRONTIER_BOUNDED = prove
+ (`!s:real^N->bool. bounded s ==> compact(relative_frontier s)`,
+  SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; CLOSED_RELATIVE_FRONTIER;
+           BOUNDED_RELATIVE_FRONTIER]);;
+
+let COMPACT_RELATIVE_FRONTIER = prove
+ (`!s:real^N->bool. compact s ==> compact(relative_frontier s)`,
+  SIMP_TAC[COMPACT_RELATIVE_FRONTIER_BOUNDED; COMPACT_IMP_BOUNDED]);;
+
+let CONVEX_SAME_RELATIVE_INTERIOR_CLOSURE = prove
+ (`!s t. convex s /\ convex t
+         ==> (relative_interior s = relative_interior t <=>
+              closure s = closure t)`,
+  MESON_TAC[CONVEX_CLOSURE_RELATIVE_INTERIOR;
+            CONVEX_RELATIVE_INTERIOR_CLOSURE]);;
+
+let CONVEX_SAME_RELATIVE_INTERIOR_CLOSURE_STRADDLE = prove
+ (`!s t. convex s /\ convex t
+         ==> (relative_interior s = relative_interior t <=>
+              relative_interior s SUBSET t /\ t SUBSET closure s)`,
+  MESON_TAC[CONVEX_CLOSURE_RELATIVE_INTERIOR;
+            CONVEX_RELATIVE_INTERIOR_CLOSURE; SUBSET_CLOSURE;
+                SUBSET_ANTISYM; RELATIVE_INTERIOR_SUBSET;
+                CLOSURE_SUBSET; CLOSURE_CLOSURE]);;
+
+let RELATIVE_INTERIOR_LINEAR_IMAGE_CONVEX = prove
+ (`!f:real^M->real^N s.
+        linear f /\ convex s
+        ==> relative_interior(IMAGE f s) = IMAGE f (relative_interior s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [SUBGOAL_THEN
+     `relative_interior (IMAGE f (relative_interior s)) =
+      relative_interior (IMAGE (f:real^M->real^N) s)`
+     (fun th -> REWRITE_TAC[SYM th; RELATIVE_INTERIOR_SUBSET]) THEN
+    ASM_SIMP_TAC[CONVEX_SAME_RELATIVE_INTERIOR_CLOSURE_STRADDLE;
+                 CONVEX_RELATIVE_INTERIOR; CONVEX_LINEAR_IMAGE] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `IMAGE (f:real^M->real^N) (relative_interior s)` THEN
+      SIMP_TAC[RELATIVE_INTERIOR_SUBSET; IMAGE_SUBSET];
+      MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC
+        `IMAGE (f:real^M->real^N) (closure(relative_interior s))` THEN
+      ASM_SIMP_TAC[CLOSURE_LINEAR_IMAGE_SUBSET] THEN
+      ASM_SIMP_TAC[CONVEX_CLOSURE_RELATIVE_INTERIOR] THEN
+      MATCH_MP_TAC IMAGE_SUBSET THEN REWRITE_TAC[CLOSURE_SUBSET]];
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN X_GEN_TAC `z:real^M` THEN
+    DISCH_TAC THEN
+    ASM_SIMP_TAC[RELATIVE_INTERIOR_CONVEX_PROLONG; CONVEX_LINEAR_IMAGE] THEN
+    REWRITE_TAC[IN_ELIM_THM; FORALL_IN_IMAGE] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC FUN_IN_IMAGE THEN
+      ASM_MESON_TAC[SUBSET; RELATIVE_INTERIOR_SUBSET];
+      ALL_TAC] THEN
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`s:real^M->bool`; `z:real^M`; `x:real^M`]
+        RELATIVE_INTERIOR_PROLONG) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real` THEN
+    MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o ISPEC `f:real^M->real^N` o MATCH_MP FUN_IN_IMAGE) THEN
+    ASM_MESON_TAC[LINEAR_ADD; LINEAR_SUB; LINEAR_CMUL]]);;
+
+let CLOSURE_INTERS_CONVEX = prove
+ (`!f:(real^N->bool)->bool.
+        (!s. s IN f ==> convex s) /\
+        ~(INTERS(IMAGE relative_interior f) = {})
+        ==> closure(INTERS f) = INTERS(IMAGE closure f)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[CLOSURE_INTERS_SUBSET] THEN
+  REWRITE_TAC[SUBSET; IN_INTERS; FORALL_IN_IMAGE] THEN
+  X_GEN_TAC `b:real^N` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  REWRITE_TAC[INTERS_IMAGE; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+  REWRITE_TAC[CLOSURE_APPROACHABLE] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `b:real^N = a` THENL
+   [EXISTS_TAC `a:real^N` THEN ASM_REWRITE_TAC[DIST_REFL; IN_INTERS] THEN
+    ASM_MESON_TAC[SUBSET; RELATIVE_INTERIOR_SUBSET];
+    ALL_TAC] THEN
+  EXISTS_TAC `b - min (&1 / &2) (e / &2 / norm(b - a)) % (b - a):real^N` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[NORM_ARITH `dist(b - a:real^N,b) = norm a`; NORM_MUL] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `&0 < a /\ &0 < x /\ x < y ==> abs(min a x) < y`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV2_EQ; REAL_HALF; REAL_LT_DIV; NORM_POS_LT;
+                 VECTOR_SUB_EQ] THEN
+    ASM_REAL_ARITH_TAC] THEN
+  REWRITE_TAC[IN_INTERS] THEN X_GEN_TAC `s:real^N->bool` THEN DISCH_TAC THEN
+  MATCH_MP_TAC
+   (MESON[RELATIVE_INTERIOR_SUBSET; SUBSET]
+         `!x. x IN relative_interior s ==> x IN s`) THEN
+  MATCH_MP_TAC IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SHRINK THEN
+  ASM_SIMP_TAC[REAL_LT_MIN; REAL_HALF; REAL_LT_DIV; NORM_POS_LT;
+               VECTOR_SUB_EQ] THEN
+  REAL_ARITH_TAC);;
+
+let CLOSURE_INTERS_CONVEX_OPEN = prove
+ (`!f:(real^N->bool)->bool.
+        (!s. s IN f ==> convex s /\ open s)
+        ==> closure(INTERS f) =
+                if INTERS f = {} then {}
+                else INTERS(IMAGE closure f)`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[CLOSURE_EMPTY] THEN
+  MATCH_MP_TAC CLOSURE_INTERS_CONVEX THEN ASM_SIMP_TAC[] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+   `~(s = {}) ==> s = t ==> ~(t = {})`)) THEN
+  AP_TERM_TAC THEN MATCH_MP_TAC(SET_RULE
+   `(!x. x IN s ==> f x = x) ==> s = IMAGE f s`) THEN
+  ASM_SIMP_TAC[RELATIVE_INTERIOR_OPEN; INTERIOR_EQ]);;
+
+let CLOSURE_INTER_CONVEX = prove
+ (`!s t:real^N->bool.
+        convex s /\ convex t /\
+        ~(relative_interior s INTER relative_interior t = {})
+        ==> closure(s INTER t) = closure(s) INTER closure(t)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `{s:real^N->bool,t}` CLOSURE_INTERS_CONVEX) THEN
+  ASM_SIMP_TAC[IMAGE_CLAUSES; INTERS_2] THEN
+  ASM_REWRITE_TAC[FORALL_IN_INSERT; NOT_IN_EMPTY]);;
+
+let CLOSURE_INTER_CONVEX_OPEN = prove
+ (`!s t. convex s /\ open s /\ convex t /\ open t
+         ==> closure(s INTER t) =
+                if s INTER t = {} then {} else closure(s) INTER closure(t)`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[CLOSURE_EMPTY] THEN
+  MATCH_MP_TAC CLOSURE_INTER_CONVEX THEN
+  ASM_SIMP_TAC[RELATIVE_INTERIOR_OPEN]);;
+
+let CLOSURE_CONVEX_INTER_SUPERSET = prove
+ (`!s t:real^N->bool.
+        convex s /\ ~(interior s = {}) /\ interior s SUBSET closure t
+        ==> closure(s INTER t) = closure s`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  SIMP_TAC[SUBSET_CLOSURE; INTER_SUBSET; SUBSET_INTER] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `closure(interior s):real^N->bool` THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[CONVEX_CLOSURE_INTERIOR; SUBSET_REFL];
+    ASM_SIMP_TAC[GSYM CLOSURE_OPEN_INTER_SUPERSET; OPEN_INTERIOR] THEN
+    MATCH_MP_TAC SUBSET_CLOSURE THEN
+    MP_TAC(ISPEC `s:real^N->bool` INTERIOR_SUBSET) THEN SET_TAC[]]);;
+
+let CLOSURE_DYADIC_RATIONALS_IN_CONVEX_SET = prove
+ (`!s:real^N->bool.
+        convex s /\ ~(interior s = {})
+        ==> closure(s INTER
+                    { inv(&2 pow n) % x | n,x |
+                      !i. 1 <= i /\ i <= dimindex(:N) ==> integer(x$i) }) =
+            closure s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSURE_CONVEX_INTER_SUPERSET THEN
+  ASM_REWRITE_TAC[CLOSURE_DYADIC_RATIONALS; SUBSET_UNIV]);;
+
+let CLOSURE_RATIONALS_IN_CONVEX_SET = prove
+ (`!s:real^N->bool.
+      convex s /\ ~(interior s = {})
+      ==> closure(s INTER
+                  { x | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i) }) =
+          closure s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSURE_CONVEX_INTER_SUPERSET THEN
+  ASM_REWRITE_TAC[CLOSURE_RATIONAL_COORDINATES; SUBSET_UNIV]);;
+
+let RELATIVE_INTERIOR_CONVEX_INTER_AFFINE = prove
+ (`!s t:real^N->bool.
+        convex s /\ affine t /\ ~(interior s INTER t = {})
+        ==> relative_interior(s INTER t) = interior s INTER t`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; RIGHT_AND_EXISTS_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` MP_TAC) THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN REWRITE_TAC[IN_INTER] THEN
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `(vec 0:real^N) IN t` THEN
+  ASM_SIMP_TAC[AFFINE_EQ_SUBSPACE] THEN STRIP_TAC THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN X_GEN_TAC `x:real^N` THEN
+  MP_TAC(ISPECL [`t:real^N->bool`; `s:real^N->bool`]
+        (ONCE_REWRITE_RULE[INTER_COMM]
+           AFFINE_HULL_AFFINE_INTER_NONEMPTY_INTERIOR)) THEN
+  ASM_SIMP_TAC[SUBSPACE_IMP_AFFINE; IN_RELATIVE_INTERIOR_CBALL] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[IN_INTER; IN_INTERIOR_CBALL]] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  ASM_CASES_TAC `(x:real^N) IN t` THEN ASM_REWRITE_TAC[] THEN
+  SIMP_TAC[SUBSET; IN_INTER] THEN
+  ASM_CASES_TAC `(x:real^N) IN s` THENL
+   [ASM_REWRITE_TAC[]; ASM_MESON_TAC[CENTRE_IN_CBALL; REAL_LT_IMP_LE]] THEN
+  EQ_TAC THENL [REWRITE_TAC[IN_CBALL]; MESON_TAC[]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  ASM_CASES_TAC `x:real^N = vec 0` THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERIOR_CBALL]) THEN
+    ASM_REWRITE_TAC[SUBSET; IN_CBALL];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`s:real^N->bool`; `vec 0:real^N`; `(&1 + e / norm x) % x:real^N`]
+   IN_INTERIOR_CLOSURE_CONVEX_SEGMENT) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [MATCH_MP_TAC(REWRITE_RULE[SUBSET] CLOSURE_SUBSET) THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[SUBSPACE_MUL] THEN
+    REWRITE_TAC[VECTOR_ADD_RDISTRIB; VECTOR_MUL_LID;
+                NORM_ARITH `dist(a:real^N,a + x) = norm x`] THEN
+    ASM_SIMP_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM;
+                 REAL_DIV_RMUL; NORM_EQ_0] THEN
+    ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[SUBSET; IN_INTERIOR_CBALL; IN_CBALL] THEN
+    DISCH_THEN MATCH_MP_TAC THEN REWRITE_TAC[IN_SEGMENT] THEN
+    CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+    REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+    EXISTS_TAC `inv(&1 + e / norm(x:real^N))` THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_LT_DIV; NORM_POS_LT; VECTOR_MUL_LID;
+                 REAL_LT_INV_EQ; REAL_MUL_LINV; REAL_INV_LT_1; REAL_ARITH
+                 `&0 < x ==> &1 < &1 + x /\ &0 < &1 + x /\ ~(&1 + x = &0)`]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homeomorphism of all convex compact sets with same affine dimension, and  *)
+(* in particular all those with nonempty interior.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPACT_FRONTIER_LINE_LEMMA = prove
+ (`!s x. compact s /\ (vec 0 IN s) /\ ~(x = vec 0 :real^N)
+         ==> ?u. &0 <= u /\ (u % x) IN frontier s /\
+                 !v. u < v ==> ~((v % x) IN s)`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_IMP_BOUNDED) THEN
+  REWRITE_TAC[BOUNDED_POS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+    [`{y:real^N | ?u. &0 <= u /\ u <= b / norm(x) /\ (y = u % x)} INTER s`;
+     `vec 0:real^N`]
+   DISTANCE_ATTAINS_SUP) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [ALL_TAC;
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `vec 0:real^N` THEN
+      ASM_REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN
+      EXISTS_TAC `&0` THEN
+      ASM_SIMP_TAC[VECTOR_MUL_LZERO; REAL_LE_REFL; REAL_LT_IMP_LE;
+                   REAL_LT_DIV; NORM_POS_LT]] THEN
+    MATCH_MP_TAC COMPACT_INTER THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN
+     `{y:real^N | ?u. &0 <= u /\ u <= b / norm(x) /\ (y = u % x)} =
+      IMAGE (\u. drop u % x) (interval [vec 0,lambda i. b / norm(x:real^N)])`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_IMAGE; IN_INTERVAL] THEN
+      SIMP_TAC[LAMBDA_BETA] THEN
+      SIMP_TAC[DIMINDEX_1; ARITH_RULE `1 <= i /\ i <= 1 <=> (i = 1)`] THEN
+      REWRITE_TAC[GSYM drop; LEFT_FORALL_IMP_THM; EXISTS_REFL; DROP_VEC] THEN
+      REWRITE_TAC[EXISTS_LIFT; LIFT_DROP] THEN MESON_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+    REWRITE_TAC[COMPACT_INTERVAL] THEN
+    MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC CONTINUOUS_VMUL THEN
+    REWRITE_TAC[o_DEF; LIFT_DROP; CONTINUOUS_AT_ID];
+    ALL_TAC] THEN
+  REWRITE_TAC[IN_INTER; IN_ELIM_THM; LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[TAUT `(a /\ b /\ c) /\ d <=> c /\ a /\ b /\ d`] THEN
+  SIMP_TAC[LEFT_IMP_EXISTS_THM] THEN ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+  GEN_REWRITE_TAC (BINDER_CONV o ONCE_DEPTH_CONV) [SWAP_FORALL_THM] THEN
+  SIMP_TAC[IMP_CONJ] THEN
+  REWRITE_TAC[LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN
+  REWRITE_TAC[IMP_IMP] THEN REWRITE_TAC[LEFT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real` THEN
+  REWRITE_TAC[dist; VECTOR_SUB_LZERO; NORM_NEG; NORM_MUL] THEN
+  ASM_SIMP_TAC[REAL_LE_RMUL_EQ; NORM_POS_LT] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  ASM_SIMP_TAC[real_abs] THEN REPEAT STRIP_TAC THENL
+   [REWRITE_TAC[FRONTIER_STRADDLE] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    CONJ_TAC THENL
+     [EXISTS_TAC `u % x :real^N` THEN ASM_REWRITE_TAC[DIST_REFL];
+      ALL_TAC] THEN
+    EXISTS_TAC `(u + (e / &2) / norm(x)) % x :real^N` THEN
+    REWRITE_TAC[dist; VECTOR_ARITH `u % x - (u + a) % x = --(a % x)`] THEN
+    ASM_SIMP_TAC[NORM_NEG; NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM; NORM_EQ_0;
+                 REAL_DIV_RMUL; REAL_ABS_NUM; REAL_LT_LDIV_EQ; REAL_OF_NUM_LT;
+                 ARITH; REAL_ARITH `abs e < e * &2 <=> &0 < e`] THEN
+    DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `u + (e / &2) / norm(x:real^N)`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(REAL_ARITH
+     `&0 < e /\ &0 <= u /\ u + e <= b
+      ==> ~(&0 <= u + e /\ u + e <= b ==> u + e <= u)`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH; NORM_POS_LT] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(u + (e / &2) / norm(x:real^N)) % x`) THEN
+    ASM_SIMP_TAC[NORM_MUL; GSYM REAL_LE_RDIV_EQ; NORM_POS_LT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `v:real`) THEN
+  ASM_REWRITE_TAC[GSYM REAL_NOT_LT] THEN ASM_REWRITE_TAC[REAL_NOT_LT] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[REAL_LET_TRANS; REAL_LT_IMP_LE]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `v % x:real^N`) THEN
+  ASM_SIMP_TAC[NORM_MUL; GSYM REAL_LE_RDIV_EQ; NORM_POS_LT] THEN
+  REAL_ARITH_TAC);;
+
+let STARLIKE_COMPACT_PROJECTIVE = prove
+ (`!s:real^N->bool a.
+        compact s /\ a IN relative_interior s /\
+        (!x. x IN s ==> segment(a,x) SUBSET relative_interior s)
+        ==> s DIFF relative_interior s homeomorphic
+            sphere(a,&1) INTER affine hull s /\
+            s homeomorphic cball(a,&1) INTER affine hull s`,
+  REPEAT GEN_TAC THEN GEOM_ORIGIN_TAC `a:real^N` THEN
+  REWRITE_TAC[SUBSET; IMP_IMP; RIGHT_IMP_FORALL_THM] THEN
+  GEN_TAC THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x:real^N u. x IN s /\ &0 <= u /\ u < &1
+                 ==> (u % x) IN relative_interior s`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[REAL_ARITH `&0 <= u <=> u = &0 \/ &0 < u`] THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+    ASM_CASES_TAC `x:real^N = vec 0` THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_RZERO] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[IN_SEGMENT] THEN
+    REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN ASM_MESON_TAC[];
+    FIRST_X_ASSUM(K ALL_TAC o SPECL [`x:real^N`; `x:real^N`])] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP (REWRITE_RULE[SUBSET]
+    RELATIVE_INTERIOR_SUBSET)) THEN
+  ABBREV_TAC `proj = \x:real^N. inv(norm(x)) % x` THEN
+  SUBGOAL_THEN
+   `!x:real^N y. (proj(x) = proj(y):real^N) /\ (norm x = norm y) <=> (x = y)`
+  ASSUME_TAC THENL
+   [REPEAT GEN_TAC THEN EQ_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+    ASM_CASES_TAC `y:real^N = vec 0` THEN
+    ASM_SIMP_TAC[NORM_EQ_0; NORM_0] THEN
+    ASM_CASES_TAC `x:real^N = vec 0` THENL
+     [ASM_MESON_TAC[NORM_EQ_0]; ALL_TAC] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    EXPAND_TAC "proj" THEN REWRITE_TAC[] THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH
+     `a % x = a % y <=> a % (x - y):real^N = vec 0`] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; REAL_INV_EQ_0; NORM_EQ_0; VECTOR_SUB_EQ];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(!x. x IN affine hull s ==> proj x IN affine hull s) /\
+    (!x. ~(x = vec 0) ==> norm(proj x) = &1) /\
+    (!x:real^N. proj x = vec 0 <=> x = vec 0)`
+  STRIP_ASSUME_TAC THENL
+   [EXPAND_TAC "proj" THEN REWRITE_TAC[NORM_MUL; VECTOR_MUL_EQ_0] THEN
+    REWRITE_TAC[REAL_INV_EQ_0; NORM_EQ_0; REAL_ABS_INV; REAL_ABS_NORM] THEN
+    SIMP_TAC[REAL_MUL_LINV; NORM_EQ_0] THEN REPEAT STRIP_TAC THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_ADD_LID] THEN
+    MATCH_MP_TAC IN_AFFINE_ADD_MUL THEN
+    ASM_SIMP_TAC[AFFINE_AFFINE_HULL; VECTOR_ADD_LID; HULL_INC];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(proj:real^N->real^N) continuous_on (UNIV DELETE vec 0)`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN
+    REWRITE_TAC[IN_DELETE; IN_UNIV] THEN EXPAND_TAC "proj" THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_MUL THEN
+    ASM_SIMP_TAC[CONTINUOUS_AT_ID] THEN
+    REWRITE_TAC[GSYM(ISPEC `lift` o_DEF);
+                GSYM(ISPEC `inv:real->real` o_DEF)] THEN
+    MATCH_MP_TAC CONTINUOUS_AT_INV THEN
+    ASM_REWRITE_TAC[NORM_EQ_0; VECTOR_SUB_EQ; CONTINUOUS_AT_LIFT_NORM];
+    ALL_TAC] THEN
+  ABBREV_TAC `usph = {x:real^N | x IN affine hull s /\ norm x = &1}` THEN
+  SUBGOAL_THEN ` sphere(vec 0:real^N,&1) INTER affine hull s = usph`
+  SUBST1_TAC THENL
+   [EXPAND_TAC "usph" THEN REWRITE_TAC[EXTENSION; IN_INTER; IN_SPHERE_0] THEN
+    SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x. x IN affine hull s /\ ~(x = vec 0)
+        ==> (proj:real^N->real^N) x IN usph`
+  ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `?surf. homeomorphism (s DIFF relative_interior s,usph)
+                                     (proj:real^N->real^N,surf)`
+  MP_TAC THENL
+   [MATCH_MP_TAC HOMEOMORPHISM_COMPACT THEN
+    ASM_SIMP_TAC[COMPACT_RELATIVE_BOUNDARY] THEN REPEAT CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+      ASM SET_TAC[];
+      MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+       [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_DIFF] THEN
+        EXPAND_TAC "usph" THEN REWRITE_TAC[IN_ELIM_THM] THEN
+        ASM_MESON_TAC[HULL_INC];
+        MAP_EVERY EXPAND_TAC ["proj"; "usph"] THEN
+        REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN X_GEN_TAC `x:real^N` THEN
+        ASM_CASES_TAC `x:real^N = vec 0` THEN
+        ASM_REWRITE_TAC[NORM_0; REAL_OF_NUM_EQ; ARITH_EQ] THEN STRIP_TAC THEN
+        MP_TAC(ISPECL [`s:real^N->bool`; `vec 0:real^N`; `x:real^N`]
+            RAY_TO_RELATIVE_FRONTIER) THEN
+        REWRITE_TAC[relative_frontier] THEN
+        ASM_SIMP_TAC[COMPACT_IMP_BOUNDED; CLOSURE_CLOSED; COMPACT_IMP_CLOSED;
+                     VECTOR_ADD_LID] THEN
+        DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+        EXPAND_TAC "proj" THEN REWRITE_TAC[IN_IMAGE] THEN
+        EXISTS_TAC `d % x:real^N` THEN ASM_REWRITE_TAC[NORM_MUL] THEN
+        ASM_SIMP_TAC[REAL_MUL_RID; real_abs; REAL_LT_IMP_LE] THEN
+        ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; REAL_LT_IMP_NZ;
+                     VECTOR_MUL_LID]];
+      MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
+      REWRITE_TAC[IN_DIFF] THEN STRIP_TAC THEN
+      ASM_CASES_TAC `x:real^N = vec 0` THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      ASM_CASES_TAC `y:real^N = vec 0` THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      UNDISCH_TAC `(proj:real^N->real^N) x = proj y` THEN
+      EXPAND_TAC "proj" THEN
+      REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC (REAL_ARITH
+       `norm(x:real^N) = norm(y:real^N) \/
+        norm x < norm y \/ norm y < norm x`)
+      THENL
+       [ASM_REWRITE_TAC[VECTOR_MUL_LCANCEL; REAL_INV_EQ_0; NORM_EQ_0];
+        DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+         [`y:real^N`; `norm(x:real^N) / norm(y:real^N)`]);
+        DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+         [`x:real^N`; `norm(y:real^N) / norm(x:real^N)`])] THEN
+      ASM_SIMP_TAC[REAL_LE_DIV; NORM_POS_LE; REAL_LT_LDIV_EQ; NORM_POS_LT;
+                   REAL_MUL_LID] THEN
+      ASM_REWRITE_TAC[real_div; GSYM VECTOR_MUL_ASSOC] THENL
+       [FIRST_X_ASSUM(SUBST1_TAC o SYM); ALL_TAC] THEN
+      ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; NORM_EQ_0] THEN
+      ASM_REWRITE_TAC[VECTOR_MUL_LID]];
+    DISCH_THEN(fun th ->
+      CONJ_TAC THENL
+       [MESON_TAC[homeomorphic; th];
+        ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+        MATCH_MP_TAC HOMEOMORPHIC_COMPACT THEN
+        SIMP_TAC[COMPACT_INTER_CLOSED; CLOSED_AFFINE_HULL; COMPACT_CBALL] THEN
+        MP_TAC th]) THEN
+    REWRITE_TAC[HOMEOMORPHISM; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `surf:real^N->real^N` THEN STRIP_TAC THEN
+    EXISTS_TAC `\x:real^N. norm(x) % (surf:real^N->real^N)(proj(x))` THEN
+    REWRITE_TAC[]] THEN
+  UNDISCH_THEN
+   `(proj:real^N->real^N) continuous_on s DIFF relative_interior s`
+   (K ALL_TAC) THEN
+  REWRITE_TAC[] THEN CONJ_TAC THENL
+   [REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; IN_INTER] THEN
+    X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
+    ASM_CASES_TAC `x = vec 0:real^N` THENL
+     [ASM_REWRITE_TAC[CONTINUOUS_WITHIN; VECTOR_MUL_LZERO; NORM_0] THEN
+      MATCH_MP_TAC LIM_NULL_VMUL_BOUNDED THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_IMP_BOUNDED) THEN
+      REWRITE_TAC[BOUNDED_POS] THEN MATCH_MP_TAC MONO_EXISTS THEN
+      REPEAT STRIP_TAC THENL
+       [REWRITE_TAC[LIM_WITHIN; o_THM; DIST_0; NORM_LIFT; REAL_ABS_NORM] THEN
+        MESON_TAC[];
+        REWRITE_TAC[EVENTUALLY_WITHIN] THEN EXISTS_TAC `&1` THEN
+        REWRITE_TAC[REAL_LT_01; IN_INTER; DIST_0; NORM_POS_LT] THEN
+        ASM SET_TAC[]];
+      MATCH_MP_TAC CONTINUOUS_WITHIN_SUBSET THEN
+      EXISTS_TAC `affine hull s:real^N->bool` THEN
+      REWRITE_TAC[INTER_SUBSET] THEN MATCH_MP_TAC CONTINUOUS_MUL THEN
+      SIMP_TAC[CONTINUOUS_LIFT_NORM_COMPOSE; CONTINUOUS_WITHIN_ID; o_DEF] THEN
+      SUBGOAL_THEN
+       `((surf:real^N->real^N) o (proj:real^N->real^N)) continuous_on
+        (affine hull s DELETE vec 0)`
+      MP_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        ASM_REWRITE_TAC[] THEN CONJ_TAC THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN
+        SIMP_TAC[SUBSET; IN_DELETE; IN_UNIV; FORALL_IN_IMAGE] THEN
+        EXPAND_TAC "usph" THEN ASM_SIMP_TAC[IN_ELIM_THM];
+        SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+        DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_SIMP_TAC[IN_DELETE] THEN
+        REWRITE_TAC[CONTINUOUS_WITHIN; o_DEF] THEN MATCH_MP_TAC EQ_IMP THEN
+        MATCH_MP_TAC LIM_TRANSFORM_WITHIN_SET THEN
+        REWRITE_TAC[EVENTUALLY_AT] THEN EXISTS_TAC `norm(x:real^N)` THEN
+        ASM_REWRITE_TAC[IN_DELETE; IN_INTER; IN_CBALL; NORM_POS_LT] THEN
+        X_GEN_TAC `y:real^N` THEN
+        ASM_CASES_TAC `(y:real^N) IN affine hull s` THEN ASM_REWRITE_TAC[] THEN
+        CONV_TAC NORM_ARITH]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!a x. &0 < a ==> (proj:real^N->real^N)(a % x) = proj x`
+  ASSUME_TAC THENL
+   [REPEAT GEN_TAC THEN EXPAND_TAC "proj" THEN
+    REWRITE_TAC[NORM_MUL; REAL_INV_MUL; VECTOR_MUL_ASSOC] THEN
+    SIMP_TAC[REAL_FIELD `&0 < a ==> (inv(a) * x) * a = x`; real_abs;
+             REAL_LT_IMP_LE];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
+    ASM_CASES_TAC `y:real^N = vec 0` THENL
+     [ASM_SIMP_TAC[VECTOR_MUL_LZERO; VECTOR_MUL_EQ_0; NORM_0; NORM_EQ_0] THEN
+      ASM SET_TAC[];
+      ALL_TAC] THEN
+    ASM_CASES_TAC `x:real^N = vec 0` THENL
+     [CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN
+      ASM_SIMP_TAC[VECTOR_MUL_LZERO; VECTOR_MUL_EQ_0; NORM_0; NORM_EQ_0] THEN
+      ASM SET_TAC[];
+      ALL_TAC] THEN
+    REWRITE_TAC[IN_INTER; IN_CBALL_0] THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(fun th -> MP_TAC th THEN
+             MP_TAC(AP_TERM `proj:real^N->real^N` th)) THEN
+    ASM_SIMP_TAC[NORM_POS_LT; VECTOR_MUL_RCANCEL] THEN ASM SET_TAC[]] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTER; IN_CBALL_0] THEN
+    X_GEN_TAC `x:real^N` THEN ASM_CASES_TAC `x:real^N = vec 0` THEN
+    ASM_REWRITE_TAC[NORM_0; VECTOR_MUL_LZERO; IN_INTER] THEN
+    REWRITE_TAC[IN_CBALL_0; REAL_LE_LT] THEN STRIP_TAC  THENL
+     [MATCH_MP_TAC(REWRITE_RULE[SUBSET] RELATIVE_INTERIOR_SUBSET) THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[NORM_POS_LE] THEN
+      ASM SET_TAC[];
+      ASM_REWRITE_TAC[VECTOR_MUL_LID] THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  REWRITE_TAC[SUBSET; IN_IMAGE; IN_CBALL_0; IN_INTER] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `x:real^N = vec 0` THENL
+   [EXISTS_TAC `vec 0:real^N` THEN
+    ASM_SIMP_TAC[NORM_0; VECTOR_MUL_LZERO; HULL_INC; REAL_POS];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x. x IN usph ==> ~((surf:real^N->real^N) x = vec 0)`
+  ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  EXISTS_TAC `inv(norm(surf(proj x:real^N):real^N)) % x:real^N` THEN
+  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [GSYM th]) THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC] THEN
+  ASM (CONV_TAC o GEN_SIMPLIFY_CONV TOP_DEPTH_SQCONV (basic_ss []) 5)
+   [NORM_POS_LT; REAL_LT_INV_EQ; HULL_INC; REAL_LT_MUL; NORM_MUL;
+    REAL_ABS_INV; REAL_ABS_NORM] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC(REAL_FIELD `~(y = &0) ==> x = (inv y * x) * y`) THEN
+    ASM_SIMP_TAC[NORM_EQ_0; HULL_INC];
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM (CONV_TAC o GEN_SIMPLIFY_CONV TOP_DEPTH_SQCONV (basic_ss []) 5)
+     [GSYM real_div; REAL_LE_LDIV_EQ; NORM_POS_LT; HULL_INC; REAL_MUL_LID] THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`x:real^N`; `norm(surf(proj x:real^N):real^N) / norm(x:real^N)`]) THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; NORM_POS_LE; REAL_LT_LDIV_EQ; NORM_POS_LT] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[REAL_NOT_LT; REAL_MUL_LID] THEN DISCH_THEN MATCH_MP_TAC THEN
+    SUBGOAL_THEN
+     `norm(surf(proj x)) / norm x % x:real^N = surf(proj x:real^N)`
+    SUBST1_TAC THENL
+     [FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC I [GSYM th]) THEN
+      ASM (CONV_TAC o GEN_SIMPLIFY_CONV TOP_DEPTH_SQCONV (basic_ss []) 5)
+       [NORM_POS_LT; REAL_LT_INV_EQ; HULL_INC; REAL_LT_MUL; NORM_MUL;
+        REAL_ABS_INV; REAL_ABS_NORM; REAL_ABS_DIV; REAL_LT_DIV;
+        REAL_DIV_RMUL; NORM_EQ_0];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `IMAGE f s SUBSET t DIFF u ==> x IN s ==> ~(f x IN u)`)) THEN
+      ASM_SIMP_TAC[HULL_INC]];
+    GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_ADD_LID] THEN
+    MATCH_MP_TAC IN_AFFINE_ADD_MUL THEN
+    ASM_SIMP_TAC[AFFINE_AFFINE_HULL; VECTOR_ADD_LID; HULL_INC]]);;
+
+let HOMEOMORPHIC_CONVEX_COMPACT_SETS,
+    HOMEOMORPHIC_RELATIVE_FRONTIERS_CONVEX_BOUNDED_SETS = (CONJ_PAIR o prove)
+ (`(!s:real^M->bool t:real^N->bool.
+        convex s /\ compact s /\ convex t /\ compact t /\ aff_dim s = aff_dim t
+        ==> s homeomorphic t) /\
+   (!s:real^M->bool t:real^N->bool.
+        convex s /\ bounded s /\ convex t /\ bounded t /\ aff_dim s = aff_dim t
+        ==> relative_frontier s homeomorphic relative_frontier t)`,
+  let lemma = prove
+   (`!s:real^M->bool t:real^N->bool.
+          convex s /\ compact s /\ convex t /\ compact t /\
+          aff_dim s = aff_dim t
+          ==> (s DIFF relative_interior s) homeomorphic
+              (t DIFF relative_interior t) /\
+              s homeomorphic t`,
+    REPEAT GEN_TAC THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    ASM_CASES_TAC `relative_interior t:real^N->bool = {}` THENL
+     [UNDISCH_TAC `relative_interior t:real^N->bool = {}` THEN
+      ASM_SIMP_TAC[AFF_DIM_EMPTY; AFF_DIM_EQ_MINUS1;
+                   EMPTY_DIFF; HOMEOMORPHIC_EMPTY; RELATIVE_INTERIOR_EQ_EMPTY];
+       FIRST_X_ASSUM(X_CHOOSE_THEN `b:real^N` MP_TAC o
+          GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY])] THEN
+    CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN
+    ASM_CASES_TAC `relative_interior s:real^M->bool = {}` THENL
+     [UNDISCH_TAC `relative_interior s:real^M->bool = {}` THEN
+      ASM_SIMP_TAC[AFF_DIM_EMPTY; AFF_DIM_EQ_MINUS1;
+                   EMPTY_DIFF; HOMEOMORPHIC_EMPTY; RELATIVE_INTERIOR_EQ_EMPTY];
+      FIRST_X_ASSUM(X_CHOOSE_THEN `a:real^M` MP_TAC o
+          GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY])] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN
+    GEOM_ORIGIN_TAC `b:real^N` THEN REPEAT GEN_TAC THEN
+    GEOM_ORIGIN_TAC `a:real^M` THEN REPEAT GEN_TAC THEN
+    REPEAT DISCH_TAC THEN
+    MP_TAC(ISPECL [`s:real^M->bool`; `vec 0:real^M`]
+          STARLIKE_COMPACT_PROJECTIVE) THEN
+    MP_TAC(ISPECL [`t:real^N->bool`; `vec 0:real^N`]
+          STARLIKE_COMPACT_PROJECTIVE) THEN
+    ASM_SIMP_TAC[IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SEGMENT;
+                 REWRITE_RULE[SUBSET] CLOSURE_SUBSET] THEN
+    DISCH_THEN(fun th -> MATCH_MP_TAC MONO_AND THEN MP_TAC th) THEN
+    MATCH_MP_TAC MONO_AND THEN CONJ_TAC THEN
+    DISCH_THEN(fun th ->
+     MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] HOMEOMORPHIC_TRANS) THEN
+     MP_TAC(ONCE_REWRITE_RULE[HOMEOMORPHIC_SYM] th)) THEN
+    MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ] HOMEOMORPHIC_TRANS) THEN
+    REPEAT(FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP (REWRITE_RULE[SUBSET]
+          RELATIVE_INTERIOR_SUBSET))) THEN
+    FIRST_X_ASSUM(MP_TAC o SYM) THEN
+    ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC; AFF_DIM_DIM_0] THEN
+    REWRITE_TAC[INT_OF_NUM_EQ] THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`span s:real^M->bool`; `span t:real^N->bool`]
+            ISOMETRIES_SUBSPACES) THEN
+    ASM_REWRITE_TAC[SUBSPACE_SPAN; DIM_SPAN; homeomorphic; HOMEOMORPHISM] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^M->real^N` THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^M` THEN
+    SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTER; IN_CBALL_0; IN_SPHERE_0] THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON] THEN ASM SET_TAC[]) in
+  SIMP_TAC[lemma; relative_frontier] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`closure s:real^M->bool`; `closure t:real^N->bool`] lemma) THEN
+  ASM_SIMP_TAC[CONVEX_CLOSURE; COMPACT_CLOSURE; AFF_DIM_CLOSURE] THEN
+  ASM_SIMP_TAC[CONVEX_RELATIVE_INTERIOR_CLOSURE]);;
+
+let HOMEOMORPHIC_CONVEX_COMPACT = prove
+ (`!s:real^N->bool t:real^N->bool.
+        convex s /\ compact s /\ ~(interior s = {}) /\
+        convex t /\ compact t /\ ~(interior t = {})
+        ==> s homeomorphic t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMEOMORPHIC_CONVEX_COMPACT_SETS THEN
+  ASM_SIMP_TAC[AFF_DIM_NONEMPTY_INTERIOR]);;
+
+let HOMEOMORPHIC_CONVEX_COMPACT_CBALL = prove
+ (`!s:real^N->bool b:real^N e.
+        convex s /\ compact s /\ ~(interior s = {}) /\ &0 < e
+        ==> s homeomorphic cball(b,e)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMEOMORPHIC_CONVEX_COMPACT THEN
+  ASM_REWRITE_TAC[COMPACT_CBALL; INTERIOR_CBALL; CONVEX_CBALL] THEN
+  ASM_REWRITE_TAC[BALL_EQ_EMPTY; REAL_NOT_LE]);;
+
+let HOMEOMORPHIC_CLOSED_INTERVALS = prove
+ (`!a b:real^N c d:real^N.
+        ~(interval(a,b) = {}) /\ ~(interval(c,d) = {})
+        ==> interval[a,b] homeomorphic interval[c,d]`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMEOMORPHIC_CONVEX_COMPACT THEN
+  REWRITE_TAC[CONVEX_INTERVAL; COMPACT_INTERVAL] THEN
+  ASM_REWRITE_TAC[INTERIOR_CLOSED_INTERVAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More about affine dimension of special sets.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let AFF_DIM_NONEMPTY_INTERIOR_EQ = prove
+ (`!s:real^N->bool.
+        convex s ==> (aff_dim s = &(dimindex (:N)) <=> ~(interior s = {}))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  ASM_SIMP_TAC[AFF_DIM_NONEMPTY_INTERIOR] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `s:real^N->bool` EMPTY_INTERIOR_SUBSET_HYPERPLANE) THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP AFF_DIM_SUBSET) THEN
+  ASM_SIMP_TAC[AFF_DIM_HYPERPLANE] THEN INT_ARITH_TAC);;
+
+let AFF_DIM_BALL = prove
+ (`!a:real^N r.
+        aff_dim(ball(a,r)) = if &0 < r then &(dimindex(:N)) else --(&1)`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THENL
+   [MATCH_MP_TAC AFF_DIM_OPEN THEN
+    ASM_REWRITE_TAC[OPEN_BALL; BALL_EQ_EMPTY; REAL_NOT_LE];
+    RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LT; GSYM BALL_EQ_EMPTY]) THEN
+    ASM_REWRITE_TAC[AFF_DIM_EMPTY]]);;
+
+let AFF_DIM_CBALL = prove
+ (`!a:real^N r.
+        aff_dim(cball(a,r)) =
+            if &0 < r then &(dimindex(:N))
+            else if r = &0 then &0 else --(&1)`,
+  REPEAT GEN_TAC THEN REPEAT COND_CASES_TAC THENL
+   [MATCH_MP_TAC AFF_DIM_NONEMPTY_INTERIOR THEN
+    ASM_REWRITE_TAC[INTERIOR_CBALL; BALL_EQ_EMPTY] THEN ASM_REAL_ARITH_TAC;
+    ASM_SIMP_TAC[CBALL_SING; AFF_DIM_SING];
+    MATCH_MP_TAC(MESON[AFF_DIM_EMPTY] `s = {} ==> aff_dim s = --(&1)`) THEN
+    REWRITE_TAC[CBALL_EQ_EMPTY] THEN ASM_REAL_ARITH_TAC]);;
+
+let AFF_DIM_INTERVAL = prove
+ (`(!a b:real^N.
+        aff_dim(interval[a,b]) =
+                if interval[a,b] = {} then --(&1)
+                else &(CARD {i | 1 <= i /\ i <= dimindex(:N) /\ a$i < b$i})) /\
+   (!a b:real^N.
+         aff_dim(interval(a,b)) =
+                if interval(a,b) = {} then --(&1)
+                else &(dimindex(:N)))`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  ASM_SIMP_TAC[AFF_DIM_EMPTY; AFF_DIM_OPEN; OPEN_INTERVAL] THEN
+  POP_ASSUM MP_TAC THEN GEOM_ORIGIN_TAC `a:real^N` THEN
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[VECTOR_ADD_COMPONENT; VEC_COMPONENT; REAL_LT_LADD] THEN
+  ASM_SIMP_TAC[AFF_DIM_DIM_0; HULL_INC; ENDS_IN_INTERVAL] THEN AP_TERM_TAC THEN
+  ONCE_REWRITE_TAC[GSYM DIM_SPAN] THEN MATCH_MP_TAC DIM_UNIQUE THEN EXISTS_TAC
+   `{basis i:real^N | 1 <= i /\ i <= dimindex(:N) /\ &0 < (b:real^N)$i}` THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY; VEC_COMPONENT]) THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    SUBGOAL_THEN `basis i:real^N = inv(b$i) % (b:real^N)$i % basis i`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; REAL_LT_IMP_NZ] THEN
+      REWRITE_TAC[VECTOR_MUL_LID];
+      MATCH_MP_TAC SPAN_MUL THEN MATCH_MP_TAC SPAN_SUPERSET THEN
+      SIMP_TAC[IN_INTERVAL; VECTOR_MUL_COMPONENT; BASIS_COMPONENT] THEN
+      X_GEN_TAC `j:num` THEN REWRITE_TAC[VEC_COMPONENT] THEN
+      COND_CASES_TAC THEN
+      ASM_SIMP_TAC[REAL_MUL_RZERO; REAL_MUL_RID; REAL_LE_REFL]];
+    MATCH_MP_TAC SPAN_SUBSET_SUBSPACE THEN
+    REWRITE_TAC[SUBSPACE_SPAN; SUBSET; IN_INTERVAL; VEC_COMPONENT] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM BASIS_EXPANSION] THEN
+    MATCH_MP_TAC SPAN_VSUM THEN REWRITE_TAC[FINITE_NUMSEG] THEN
+    X_GEN_TAC `i:num` THEN REWRITE_TAC[IN_NUMSEG] THEN STRIP_TAC THEN
+    ASM_CASES_TAC `&0 < (b:real^N)$i` THENL
+     [MATCH_MP_TAC SPAN_MUL THEN MATCH_MP_TAC SPAN_SUPERSET THEN ASM SET_TAC[];
+      SUBGOAL_THEN `(x:real^N)$i = &0`
+        (fun th -> REWRITE_TAC[th; VECTOR_MUL_LZERO; SPAN_0]) THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `i:num`)) THEN
+      ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC];
+    MATCH_MP_TAC PAIRWISE_ORTHOGONAL_INDEPENDENT THEN
+    REWRITE_TAC[SET_RULE `~(a IN {f x | P x}) <=> !x. P x ==> ~(f x = a)`] THEN
+    SIMP_TAC[BASIS_NONZERO; pairwise; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    SIMP_TAC[FORALL_IN_GSPEC; BASIS_INJ_EQ; ORTHOGONAL_BASIS_BASIS];
+    GEN_REWRITE_TAC LAND_CONV [SIMPLE_IMAGE_GEN] THEN
+    MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN
+    SIMP_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC; BASIS_INJ_EQ;
+             HAS_SIZE] THEN
+    SIMP_TAC[CONJ_ASSOC; GSYM IN_NUMSEG; FINITE_RESTRICT; FINITE_NUMSEG]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Deducing convexity from midpoint convexity in common cases.               *)
+(* ------------------------------------------------------------------------- *)
+
+let MIDPOINT_CONVEX_DYADIC_RATIONALS = prove
+ (`!f:real^N->real s.
+        (!x y. x IN s /\ y IN s
+               ==> midpoint(x,y) IN s /\
+                   f(midpoint(x,y)) <= (f(x) + f(y)) / &2)
+        ==> !n m p x y.
+                x IN s /\ y IN s /\ m + p = 2 EXP n
+                ==> (&m / &2 pow n % x + &p / &2 pow n % y) IN s /\
+                    f(&m / &2 pow n % x + &p / &2 pow n % y)
+                    <= &m / &2 pow n * f x + &p / &2 pow n * f y`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN INDUCT_TAC THENL
+   [REWRITE_TAC[ARITH_RULE
+     `m + p = 2 EXP 0 <=> m = 0 /\ p = 1 \/ m = 1 /\ p = 0`] THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_LID; VECTOR_MUL_LZERO;
+                  VECTOR_ADD_LID; VECTOR_ADD_RID] THEN
+    REAL_ARITH_TAC;
+    MATCH_MP_TAC WLOG_LE THEN CONJ_TAC THENL
+     [REWRITE_TAC[VECTOR_ADD_SYM; REAL_ADD_SYM; ADD_SYM] THEN MESON_TAC[];
+      ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`m:num`; `p:num`] THEN DISCH_TAC THEN
+    REPEAT GEN_TAC THEN REWRITE_TAC[EXP; real_pow] THEN STRIP_TAC THEN
+    REWRITE_TAC[real_div; REAL_INV_MUL] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `x * inv(&2) * y = inv(&2) * x * y`] THEN
+    ONCE_REWRITE_TAC[GSYM REAL_MUL_ASSOC; GSYM VECTOR_MUL_ASSOC] THEN
+    REWRITE_TAC[GSYM REAL_ADD_LDISTRIB; GSYM VECTOR_ADD_LDISTRIB] THEN
+    SUBGOAL_THEN `2 EXP n <= p` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+    SUBGOAL_THEN `&p * inv(&2 pow n) = &(p - 2 EXP n) * inv(&2 pow n) + &1`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[GSYM REAL_OF_NUM_SUB; GSYM REAL_OF_NUM_POW] THEN
+      ASM_SIMP_TAC[REAL_SUB_RDISTRIB; REAL_MUL_RINV; REAL_LT_IMP_NZ;
+                   REAL_LT_POW2] THEN REAL_ARITH_TAC;
+      REWRITE_TAC[VECTOR_ADD_RDISTRIB; REAL_ADD_RDISTRIB] THEN
+      REWRITE_TAC[VECTOR_MUL_LID; REAL_MUL_LID] THEN
+      REWRITE_TAC[VECTOR_ADD_ASSOC; REAL_ADD_ASSOC] THEN
+      REWRITE_TAC[GSYM midpoint; GSYM real_div] THEN FIRST_X_ASSUM(fun th ->
+        W(MP_TAC o PART_MATCH (lhand o rand) th o lhand o snd)) THEN
+      FIRST_X_ASSUM(fun th ->
+        W(MP_TAC o PART_MATCH (lhand o rand) th o funpow 3 lhand o  snd)) THEN
+      ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+       [ASM_ARITH_TAC; SIMP_TAC[] THEN REAL_ARITH_TAC]]]);;
+
+let CONTINUOUS_MIDPOINT_CONVEX = prove
+ (`!f:real^N->real s.
+        (lift o f) continuous_on s /\ convex s /\
+        (!x y. x IN s /\ y IN s ==> f(midpoint(x,y)) <= (f(x) + f(y)) / &2)
+         ==> f convex_on s`,
+  REWRITE_TAC[midpoint] THEN REPEAT STRIP_TAC THEN REWRITE_TAC[convex_on] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN REWRITE_TAC[GSYM IMP_CONJ_ALT] THEN
+  X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+  REWRITE_TAC[REAL_ARITH `u + v = &1 <=> v = &1 - u`; IMP_CONJ] THEN
+  REWRITE_TAC[FORALL_UNWIND_THM2; REAL_SUB_LE] THEN
+  REWRITE_TAC[FORALL_DROP; GSYM DROP_VEC; IMP_IMP; GSYM IN_INTERVAL_1] THEN
+  MP_TAC(ISPEC `interval[vec 0:real^1,vec 1]`
+        CLOSURE_DYADIC_RATIONALS_IN_CONVEX_SET) THEN
+  SIMP_TAC[CONVEX_INTERVAL; INTERIOR_CLOSED_INTERVAL;
+           CLOSURE_CLOSED; CLOSED_INTERVAL; UNIT_INTERVAL_NONEMPTY] THEN
+  REWRITE_TAC[DIMINDEX_1; FORALL_1; GSYM drop] THEN
+  DISCH_THEN(fun th -> SUBST1_TAC(SYM th) THEN ASSUME_TAC th) THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a <= b <=> a - b <= &0`] THEN
+  MATCH_MP_TAC CONTINUOUS_LE_ON_CLOSURE THEN
+  REWRITE_TAC[IN_INTER; IMP_CONJ_ALT; FORALL_IN_GSPEC] THEN
+  FIRST_X_ASSUM SUBST1_TAC THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_CMUL; GSYM FORALL_DROP; DROP_VEC] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[o_DEF; LIFT_SUB; LIFT_ADD; LIFT_CMUL] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUB THEN CONJ_TAC THENL
+     [REPLICATE_TAC 2 (ONCE_REWRITE_TAC[GSYM o_DEF]) THEN
+      REWRITE_TAC[o_ASSOC] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      CONJ_TAC THENL
+       [ALL_TAC;
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1; GSYM FORALL_DROP;
+                    DROP_VEC] THEN REPEAT STRIP_TAC THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [convex]) THEN
+        ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC];
+      ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_ADD THEN CONJ_TAC THEN
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+    SIMP_TAC[o_DEF; LIFT_DROP; CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST;
+             LIFT_SUB; CONTINUOUS_ON_SUB];
+    MAP_EVERY X_GEN_TAC [`n:num`; `i:real`] THEN
+    ASM_SIMP_TAC[REAL_LE_MUL_EQ; REAL_LT_INV_EQ; REAL_LT_POW2] THEN
+    ASM_CASES_TAC `&0 <= i` THEN ASM_SIMP_TAC[INTEGER_POS] THEN
+    DISCH_THEN(X_CHOOSE_THEN `m:num` SUBST_ALL_TAC) THEN
+    REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] (GSYM real_div)] THEN
+    SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LT_POW2; REAL_MUL_LID] THEN
+    GEN_REWRITE_TAC (LAND_CONV o DEPTH_CONV)
+     [REAL_OF_NUM_POW; REAL_OF_NUM_LE] THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`f:real^N->real`; `s:real^N->bool`]
+        MIDPOINT_CONVEX_DYADIC_RATIONALS) THEN
+    ANTS_TAC THENL
+     [ASM_SIMP_TAC[midpoint] THEN REWRITE_TAC[VECTOR_ADD_LDISTRIB] THEN
+      REPEAT STRIP_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [convex]) THEN
+      ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+      DISCH_THEN(MP_TAC o SPECL
+       [`n:num`; `m:num`; `2 EXP n - m`; `x:real^N`; `y:real^N`]) THEN
+      ASM_REWRITE_TAC[] THEN
+      ANTS_TAC THENL [ASM_ARITH_TAC; DISCH_THEN(MP_TAC o CONJUNCT2)] THEN
+      ASM_SIMP_TAC[GSYM REAL_OF_NUM_SUB; GSYM REAL_OF_NUM_POW] THEN
+      ASM_SIMP_TAC[REAL_LT_POW2; REAL_FIELD
+       `&0 < y ==> (y - x) / y = &1 - x / y`] THEN
+      REAL_ARITH_TAC]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Slightly shaper separating/supporting hyperplane results.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let SEPARATING_HYPERPLANE_RELATIVE_INTERIORS = prove
+ (`!s t. convex s /\ convex t /\
+         ~(s = {} /\ t = (:real^N) \/ s = (:real^N) /\ t = {}) /\
+         DISJOINT (relative_interior s) (relative_interior t)
+         ==> ?a b. ~(a = vec 0) /\
+                   (!x. x IN s ==> a dot x <= b) /\
+                   (!x. x IN t ==> a dot x >= b)`,
+  REPEAT GEN_TAC THEN MAP_EVERY ASM_CASES_TAC
+   [`s:real^N->bool = {}`; `t:real^N->bool = {}`] THEN
+  ASM_REWRITE_TAC[NOT_IN_EMPTY; UNIV_NOT_EMPTY; CONVEX_EMPTY;
+                  RELATIVE_INTERIOR_EMPTY] THEN
+  STRIP_TAC THENL
+   [EXISTS_TAC `basis 1:real^N` THEN
+    SIMP_TAC[BASIS_NONZERO; DIMINDEX_GE_1; LE_REFL];
+    FIRST_X_ASSUM(X_CHOOSE_TAC `x:real^N` o MATCH_MP (SET_RULE
+     `~(s = UNIV) ==> ?a. ~(a IN s)`)) THEN
+    MP_TAC(ISPECL [`t:real^N->bool`; `x:real^N`]
+        SEPARATING_HYPERPLANE_SET_POINT_INAFF) THEN
+    ASM_MESON_TAC[];
+    FIRST_X_ASSUM(X_CHOOSE_TAC `x:real^N` o MATCH_MP (SET_RULE
+     `~(s = UNIV) ==> ?a. ~(a IN s)`)) THEN
+    MP_TAC(ISPECL [`s:real^N->bool`; `x:real^N`]
+        SEPARATING_HYPERPLANE_SET_POINT_INAFF) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; real_ge] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real`] THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`--a:real^N`; `--b:real`] THEN
+    ASM_REWRITE_TAC[VECTOR_NEG_EQ_0; DOT_LNEG; REAL_LE_NEG2];
+    MP_TAC(ISPECL [`relative_interior s:real^N->bool`;
+                   `relative_interior t:real^N->bool`]
+          SEPARATING_HYPERPLANE_SETS) THEN
+    ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY; CONVEX_RELATIVE_INTERIOR] THEN
+    SIMP_TAC[real_ge] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `a:real^N` THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `b:real` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    CONJ_TAC THEN MATCH_MP_TAC
+    (MESON[CONVEX_CLOSURE_RELATIVE_INTERIOR; CLOSURE_SUBSET; SUBSET]
+      `convex s /\ (!x. x IN closure(relative_interior s) ==> P x)
+       ==> !x. x IN s ==> P x`) THEN
+    ASM_REWRITE_TAC[] THENL
+     [MATCH_MP_TAC CONTINUOUS_LE_ON_CLOSURE;
+      MATCH_MP_TAC CONTINUOUS_GE_ON_CLOSURE] THEN
+    ASM_REWRITE_TAC[CONTINUOUS_ON_LIFT_DOT]]);;
+
+let SUPPORTING_HYPERPLANE_RELATIVE_BOUNDARY = prove
+ (`!s x:real^N.
+        convex s /\ x IN s /\ ~(x IN relative_interior s)
+        ==> ?a. ~(a = vec 0) /\
+                (!y. y IN s ==> a dot x <= a dot y) /\
+                (!y. y IN relative_interior s ==> a dot x < a dot y)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`relative_interior s:real^N->bool`; `x:real^N`]
+        SEPARATING_HYPERPLANE_SET_POINT_INAFF) THEN
+  ASM_SIMP_TAC[CONVEX_SING; CONVEX_RELATIVE_INTERIOR;
+               RELATIVE_INTERIOR_EQ_EMPTY; real_ge] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+  REWRITE_TAC[FORALL_IN_INSERT; NOT_IN_EMPTY] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real` STRIP_ASSUME_TAC) THEN ASM_SIMP_TAC[] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`lift o (\x:real^N. a dot x)`;
+                   `relative_interior s:real^N->bool`;
+                   `y:real^N`; `(a:real^N) dot x`; `1`]
+      CONTINUOUS_ON_CLOSURE_COMPONENT_GE) THEN
+    REWRITE_TAC[CONTINUOUS_ON_LIFT_DOT; GSYM drop; o_THM; LIFT_DROP] THEN
+    ASM_SIMP_TAC[CONVEX_CLOSURE_RELATIVE_INTERIOR] THEN
+    ASM_MESON_TAC[CLOSURE_SUBSET; REAL_LE_TRANS; SUBSET];
+    DISCH_TAC] THEN
+  X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+  REWRITE_TAC[REAL_LT_LE] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[REAL_LE_TRANS]; ALL_TAC] THEN
+  DISCH_TAC THEN UNDISCH_TAC `(y:real^N) IN relative_interior s` THEN
+  REWRITE_TAC[IN_RELATIVE_INTERIOR_CBALL] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; SUBSET; IN_INTER; IN_CBALL] THEN
+  X_GEN_TAC `e:real` THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(MP_TAC o SPEC `y + --(e / norm(a)) % ((x + a) - x):real^N`) THEN
+  REWRITE_TAC[NOT_IMP] THEN REPEAT CONJ_TAC THENL
+   [SIMP_TAC[NORM_ARITH `dist(y:real^N,y + e) = norm e`; VECTOR_ADD_SUB] THEN
+    REWRITE_TAC[NORM_MUL; REAL_ABS_NEG; REAL_ABS_DIV; REAL_ABS_NORM] THEN
+    ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0] THEN ASM_REAL_ARITH_TAC;
+    MATCH_MP_TAC IN_AFFINE_ADD_MUL_DIFF THEN
+    ASM_SIMP_TAC[AFFINE_AFFINE_HULL; HULL_INC] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `x IN s ==> s SUBSET t ==> x IN t`)) THEN
+    MATCH_MP_TAC HULL_MONO THEN
+    ASM_REWRITE_TAC[INSERT_SUBSET; RELATIVE_INTERIOR_SUBSET];
+    REWRITE_TAC[VECTOR_ADD_SUB] THEN DISCH_TAC THEN
+    UNDISCH_TAC `!y:real^N. y IN s ==> a dot x <= a dot y` THEN
+    DISCH_THEN(MP_TAC o SPEC `y + --(e / norm(a)) % a:real^N`) THEN
+    ASM_REWRITE_TAC[DOT_RMUL; DOT_RNEG; DOT_RADD] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < x * y ==> ~(a <= a + --x * y)`) THEN
+    ASM_SIMP_TAC[REAL_LT_MUL; REAL_LT_DIV; NORM_POS_LT; DOT_POS_LT]]);;
+
+let SUPPORTING_HYPERPLANE_RELATIVE_FRONTIER = prove
+ (`!s x:real^N.
+        convex s /\ x IN closure s /\ ~(x IN relative_interior s)
+        ==> ?a. ~(a = vec 0) /\
+                (!y. y IN closure s ==> a dot x <= a dot y) /\
+                (!y. y IN relative_interior s ==> a dot x < a dot y)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`closure s:real^N->bool`; `x:real^N`]
+    SUPPORTING_HYPERPLANE_RELATIVE_BOUNDARY) THEN
+  ASM_SIMP_TAC[CONVEX_CLOSURE; CONVEX_RELATIVE_INTERIOR_CLOSURE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Containment of rays in unbounded convex sets.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let UNBOUNDED_CONVEX_CLOSED_CONTAINS_RAY = prove
+ (`!s a:real^N.
+        convex s /\ ~bounded s /\ closed s /\ a IN s
+        ==> ?l. ~(l = vec 0) /\ !t. &0 <= t ==> (a + t % l) IN s`,
+  GEN_GEOM_ORIGIN_TAC `a:real^N` ["l"] THEN
+  REWRITE_TAC[VECTOR_ADD_LID] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [BOUNDED_POS]) THEN
+  REWRITE_TAC[NOT_EXISTS_THM; TAUT `~(p /\ q) <=> p ==> ~q`] THEN
+  DISCH_THEN(MP_TAC o GEN `n:num` o SPEC `&n + &1:real`) THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; REAL_ARITH `&0 < &n + &1`] THEN
+  REWRITE_TAC[REAL_NOT_LE; SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `x:num->real^N` THEN REWRITE_TAC[FORALL_AND_THM] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `!n. ~((x:num->real^N) n = vec 0)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[NORM_ARITH `~(&n + &1 < norm(vec 0:real^N))`]; ALL_TAC] THEN
+  MP_TAC(ISPEC `sphere(vec 0:real^N,&1)` compact) THEN
+  REWRITE_TAC[COMPACT_SPHERE] THEN
+  DISCH_THEN(MP_TAC o SPEC `\n. inv(norm(x n)) % (x:num->real^N) n`) THEN
+  ASM_SIMP_TAC[IN_SPHERE_0; NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM;
+               REAL_MUL_LINV; NORM_EQ_0; o_DEF] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `l:real^N` THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:num->num` STRIP_ASSUME_TAC) THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[NORM_ARITH `~(norm(vec 0:real^N) = &1)`]; ALL_TAC] THEN
+  X_GEN_TAC `t:real` THEN DISCH_TAC THEN
+  MATCH_MP_TAC CLOSED_CONTAINS_SEQUENTIAL_LIMIT THEN
+  SUBGOAL_THEN
+   `?N:num. !n. N <= n ==> t / norm(x n:real^N) <= &1`
+  STRIP_ASSUME_TAC THENL
+   [ASM_SIMP_TAC[REAL_LE_LDIV_EQ; NORM_POS_LT] THEN
+    MP_TAC(SPEC `t:real` REAL_ARCH_SIMPLE) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN
+    REWRITE_TAC[GSYM REAL_OF_NUM_LE; REAL_MUL_LID] THEN
+    ASM_MESON_TAC[REAL_ARITH `t <= m /\ m <= n /\ n + &1 < x ==> t <= x`];
+    EXISTS_TAC `\n:num. t / norm((x:num->real^N)(r(N + n))) % x(r(N + n))` THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [X_GEN_TAC `n:num` THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONVEX_ALT]) THEN
+      DISCH_THEN(MP_TAC o SPEC `vec 0:real^N`) THEN
+      ASM_REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+      DISCH_THEN MATCH_MP_TAC THEN ASM_SIMP_TAC[REAL_LE_DIV; NORM_POS_LE] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      FIRST_ASSUM(MP_TAC o SPEC `N + n:num` o MATCH_MP MONOTONE_BIGGER) THEN
+      ARITH_TAC;
+      REWRITE_TAC[real_div; GSYM VECTOR_MUL_ASSOC] THEN
+      MATCH_MP_TAC LIM_CMUL THEN ONCE_REWRITE_TAC[ADD_SYM] THEN
+      FIRST_ASSUM(MP_TAC o SPEC `N:num` o MATCH_MP SEQ_OFFSET) THEN
+      ASM_REWRITE_TAC[]]]);;
+
+let CONVEX_CLOSED_CONTAINS_SAME_RAY = prove
+ (`!s a b l:real^N.
+        convex s /\ closed s /\ b IN s /\ (!t. &0 <= t ==> (a + t % l) IN s)
+        ==> !t. &0 <= t ==> (b + t % l) IN s`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o SPEC `&0`) THEN
+  REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_RID] THEN DISCH_TAC THEN
+  MATCH_MP_TAC(ISPEC `sequentially` LIM_IN_CLOSED_SET) THEN
+  EXISTS_TAC `\n. (&1 - t / (&n + &1)) % b +
+                  t / (&n + &1) % (a + (&n + &1) % l):real^N` THEN
+  ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN CONJ_TAC THENL
+   [REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+    MP_TAC(SPEC `t:real` REAL_ARCH_SIMPLE) 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(MATCH_MP_TAC o GEN_REWRITE_RULE I [CONVEX_ALT]) THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; REAL_ARITH `&0 <= &n + &1`] THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM REAL_OF_NUM_LE]) THEN ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[VECTOR_ARITH
+     `(&1 - u) % b + u % c:real^N = b + u % (c - b)`] THEN
+    MATCH_MP_TAC LIM_ADD THEN REWRITE_TAC[LIM_CONST] THEN
+    REWRITE_TAC[VECTOR_ADD_LDISTRIB; VECTOR_SUB_LDISTRIB] THEN
+    SIMP_TAC[VECTOR_MUL_ASSOC; REAL_FIELD `t / (&n + &1) * (&n + &1) = t`] THEN
+    SIMP_TAC[VECTOR_ARITH `(v % a + b) - v % c:real^N = b + v % (a - c)`] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_ADD_RID] THEN
+    MATCH_MP_TAC LIM_ADD THEN REWRITE_TAC[LIM_CONST] THEN
+    REWRITE_TAC[real_div; VECTOR_ARITH `(x * y) % a:real^N = y % x % a`] THEN
+    MATCH_MP_TAC LIM_NULL_VMUL_BOUNDED THEN
+    EXISTS_TAC `norm(t % (a - b):real^N)` THEN
+    REWRITE_TAC[REAL_LE_REFL; EVENTUALLY_TRUE; o_DEF] THEN
+    MP_TAC(MATCH_MP SEQ_OFFSET SEQ_HARMONIC) THEN
+    SIMP_TAC[REAL_OF_NUM_ADD]]);;
+
+let UNBOUNDED_CONVEX_CLOSED_CONTAINS_RAYS = prove
+ (`!s:real^N->bool.
+        convex s /\ ~bounded s /\ closed s
+        ==> ?l. ~(l = vec 0) /\ !a t. a IN s /\ &0 <= t ==> (a + t % l) IN s`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[BOUNDED_EMPTY] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM MEMBER_NOT_EMPTY]) THEN
+  ASM_MESON_TAC[UNBOUNDED_CONVEX_CLOSED_CONTAINS_RAY;
+                CONVEX_CLOSED_CONTAINS_SAME_RAY]);;
+
+let RELATIVE_INTERIOR_UNBOUNDED_CONVEX_CONTAINS_RAY = prove
+ (`!s a:real^N.
+        convex s /\ ~bounded s /\ a IN relative_interior s
+        ==> ?l. ~(l = vec 0) /\
+                !t. &0 <= t ==> (a + t % l) IN relative_interior s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`closure s:real^N->bool`; `a:real^N`]
+        UNBOUNDED_CONVEX_CLOSED_CONTAINS_RAY) THEN
+  ASM_SIMP_TAC[CONVEX_CLOSURE; CLOSED_CLOSURE] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[BOUNDED_SUBSET; SUBSET; CLOSURE_SUBSET;
+                  RELATIVE_INTERIOR_SUBSET];
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `l:real^N` THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+      `a + t % l:real^N =
+       (a + (&2 * t) % l) - inv(&2) % ((a + (&2 * t) % l) - a)`] THEN
+    REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SHRINK THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC]);;
+
+let RELATIVE_INTERIOR_CONVEX_CONTAINS_SAME_RAY = prove
+ (`!s a b l:real^N.
+        convex s /\ b IN relative_interior s /\
+        (!t. &0 <= t ==> (a + t % l) IN relative_interior s)
+        ==> !t. &0 <= t ==> (b + t % l) IN relative_interior s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`closure s:real^N->bool`; `a:real^N`; `b:real^N`; `l:real^N`]
+        CONVEX_CLOSED_CONTAINS_SAME_RAY) THEN
+  ASM_SIMP_TAC[CONVEX_CLOSURE; CLOSED_CLOSURE] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[BOUNDED_SUBSET; SUBSET; CLOSURE_SUBSET;
+                  RELATIVE_INTERIOR_SUBSET];
+    DISCH_TAC THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+      `a + t % l:real^N =
+       (a + (&2 * t) % l) - inv(&2) % ((a + (&2 * t) % l) - a)`] THEN
+    REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SHRINK THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC]);;
+
+let RELATIVE_INTERIOR_UNBOUNDED_CONVEX_CONTAINS_RAYS = prove
+ (`!s:real^N->bool.
+        convex s /\ ~bounded s
+        ==> ?l. ~(l = vec 0) /\
+                !a t. a IN relative_interior s /\ &0 <= t
+                      ==> (a + t % l) IN relative_interior s`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `relative_interior s:real^N->bool = {}` THENL
+   [ASM_MESON_TAC[RELATIVE_INTERIOR_EQ_EMPTY; BOUNDED_EMPTY]; ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM MEMBER_NOT_EMPTY]) THEN
+  ASM_MESON_TAC[RELATIVE_INTERIOR_UNBOUNDED_CONVEX_CONTAINS_RAY;
+                RELATIVE_INTERIOR_CONVEX_CONTAINS_SAME_RAY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Explicit formulas for interior and relative interior of convex hull.      *)
+(* ------------------------------------------------------------------------- *)
+
+let EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL = prove
+ (`!s. FINITE s
+       ==> {y:real^N | ?u. (!x. x IN s ==> &0 < u x /\ u x < &1) /\
+                           sum s u = &1 /\
+                           vsum s (\x. u x % x) = y}
+       SUBSET relative_interior(convex hull s)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[SUM_CLAUSES; REAL_OF_NUM_EQ; ARITH_EQ] THEN
+  REWRITE_TAC[EMPTY_GSPEC; EMPTY_SUBSET] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC RELATIVE_INTERIOR_MAXIMAL THEN
+  REWRITE_TAC[AFFINE_HULL_CONVEX_HULL] THEN CONJ_TAC THENL
+   [REWRITE_TAC[CONVEX_HULL_FINITE; SUBSET; IN_ELIM_THM] THEN
+    GEN_TAC THEN MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[REAL_LT_IMP_LE];
+    ALL_TAC] THEN
+  REWRITE_TAC[open_in; IN_ELIM_THM] THEN CONJ_TAC THENL
+   [REWRITE_TAC[AFFINE_HULL_FINITE; SUBSET; IN_ELIM_THM] THEN
+    GEN_TAC THEN MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[REAL_LT_IMP_LE];
+    ALL_TAC] THEN
+  X_GEN_TAC `y:real^N` THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC) THEN
+  ABBREV_TAC `e = inf (IMAGE (\x:real^N. min (&1 - u x) (u x)) s)` THEN
+  SUBGOAL_THEN `&0 < e` ASSUME_TAC THENL
+   [EXPAND_TAC "e" THEN
+    ASM_SIMP_TAC[REAL_LT_INF_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+    ASM_SIMP_TAC[REAL_LT_MIN; REAL_SUB_LT; FORALL_IN_IMAGE];
+    ALL_TAC] THEN
+  MP_TAC(ISPEC `IMAGE (\z:real^N. z - y) (affine hull s)` BASIS_EXISTS) THEN
+  REWRITE_TAC[SUBSET_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool`
+   (CONJUNCTS_THEN2 (X_CHOOSE_THEN `c:real^N->bool` (STRIP_ASSUME_TAC o GSYM))
+                    MP_TAC)) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; HAS_SIZE] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  ASM_SIMP_TAC[SPAN_FINITE; IN_ELIM_THM] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM] THEN
+  DISCH_THEN(X_CHOOSE_TAC `compo:real^N->real^N->real`) THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC o
+    MATCH_MP BASIS_COORDINATES_LIPSCHITZ) THEN
+  SUBGOAL_THEN
+   `!i. i IN b ==> ?u. sum s u = &0 /\ vsum s (\x:real^N. u x % x) = i`
+  MP_TAC THENL
+   [EXPAND_TAC "b" THEN REWRITE_TAC[FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `(x:real^N) IN affine hull s` MP_TAC THENL
+     [ASM SET_TAC[]; REWRITE_TAC[AFFINE_HULL_FINITE; IN_ELIM_THM]] THEN
+    DISCH_THEN(X_CHOOSE_THEN `v:real^N->real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(\x. v x - u x):real^N->real` THEN
+    ASM_SIMP_TAC[SUM_SUB; VSUM_SUB; VECTOR_SUB_RDISTRIB] THEN
+    REWRITE_TAC[REAL_SUB_REFL; VECTOR_SUB_RZERO];
+    GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV)
+     [RIGHT_IMP_EXISTS_THM; SKOLEM_THM; FORALL_AND_THM;
+                TAUT `(a ==> b /\ c) <=> (a ==> b) /\ (a ==> c)`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `w:real^N->real^N->real` STRIP_ASSUME_TAC)] THEN
+  EXISTS_TAC `e / B /
+              (&1 + sum (b:real^N->bool)
+                   (\i. abs(sup(IMAGE (abs o w i) (s:real^N->bool)))))` THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 <= x ==> &0 < &1 + x`;
+               SUM_POS_LE; REAL_ABS_POS] THEN
+  X_GEN_TAC `z:real^N` THEN STRIP_TAC THEN
+  EXISTS_TAC
+   `\x:real^N. u x + sum (b:real^N->bool)
+                         (\i. compo (z:real^N) i * w i x)` THEN
+  REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[SUM_ADD; REAL_ARITH `&1 + x = &1 <=> x = &0`] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) SUM_SWAP o lhand o snd) THEN
+    ASM_REWRITE_TAC[FINITE_NUMSEG] THEN DISCH_THEN SUBST1_TAC THEN
+    MATCH_MP_TAC SUM_EQ_0 THEN
+    ASM_SIMP_TAC[SUM_LMUL; ETA_AX; REAL_MUL_RZERO; SUM_0];
+    ASM_SIMP_TAC[VSUM_ADD; VECTOR_ADD_RDISTRIB] THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH `y + w:real^N = z <=> w = z - y`] THEN
+    ASM_SIMP_TAC[GSYM VSUM_LMUL; GSYM VSUM_RMUL; GSYM VECTOR_MUL_ASSOC] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) VSUM_SWAP o lhand o snd) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
+    ASM_SIMP_TAC[VSUM_LMUL] THEN MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `vsum b (\v:real^N. compo (z:real^N) v % v)` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_SIMP_TAC[]] THEN
+    MATCH_MP_TAC VSUM_EQ THEN ASM_SIMP_TAC[]] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `abs(x) < min u (&1 - u) ==> &0 < u + x /\ u + x < &1`) THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC
+    `B * norm(z - y:real^N) * sum (b:real^N->bool)
+                   (\i. abs(sup(IMAGE (abs o w i) (s:real^N->bool))))` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[GSYM SUM_LMUL] THEN MATCH_MP_TAC SUM_ABS_LE THEN
+    ASM_REWRITE_TAC[REAL_ABS_MUL; REAL_MUL_ASSOC] THEN
+    X_GEN_TAC `i:real^N` THEN STRIP_TAC THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+    REWRITE_TAC[REAL_ABS_POS] THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPECL [`(compo:real^N->real^N->real) z`;
+                                  `i:real^N`]) THEN
+      ASM_SIMP_TAC[];
+      MATCH_MP_TAC(REAL_ARITH `x <= a ==> x <= abs a`) THEN
+      ASM_SIMP_TAC[REAL_LE_SUP_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+      REWRITE_TAC[EXISTS_IN_IMAGE; o_THM] THEN ASM_MESON_TAC[REAL_LE_REFL]];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `&0 <= x /\ x * (&1 + e) < d ==> x * e < d`) THEN
+  REWRITE_TAC[NORM_POS_LE] THEN
+  ASM_SIMP_TAC[NORM_POS_LE; GSYM REAL_LT_RDIV_EQ;
+               REAL_ARITH `&0 <= x ==> &0 < &1 + x`;
+               SUM_POS_LE; REAL_ABS_POS] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (NORM_ARITH
+   `dist(z:real^N,y) < k ==> k <= d ==> norm(z - y) < d`)) THEN
+  ASM_SIMP_TAC[REAL_LE_DIV2_EQ; REAL_ARITH `&0 <= x ==> &0 < &1 + x`;
+               SUM_POS_LE; REAL_ABS_POS] THEN
+  EXPAND_TAC "e" THEN
+  ASM_SIMP_TAC[REAL_INF_LE_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE] THEN EXISTS_TAC `x:real^N` THEN
+  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL_MINIMAL = prove
+ (`!s. FINITE s
+       ==> {y:real^N | ?u. (!x. x IN s ==> &0 < u x) /\
+                           sum s u = &1 /\
+                           vsum s (\x. u x % x) = y}
+       SUBSET relative_interior(convex hull s)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[SUM_CLAUSES; REAL_OF_NUM_EQ; ARITH_EQ] THEN
+  REWRITE_TAC[EMPTY_GSPEC; EMPTY_SUBSET] 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
+  ASM_CASES_TAC `s = {a:real^N}` THENL
+   [ASM_REWRITE_TAC[SUM_SING; VSUM_SING; FORALL_IN_INSERT; NOT_IN_EMPTY] THEN
+    REWRITE_TAC[RELATIVE_INTERIOR_SING; CONVEX_HULL_SING] THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_SING] THEN
+    MESON_TAC[VECTOR_MUL_LID];
+    FIRST_ASSUM(MP_TAC o MATCH_MP
+      EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] SUBSET_TRANS) THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN X_GEN_TAC `w:real^N` THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real^N->real` THEN
+    STRIP_TAC THEN ASM_SIMP_TAC[] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `?y:real^N. y IN s /\ ~(y = x)` STRIP_ASSUME_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN `sum {x,y} u <= sum s (u:real^N->real)` MP_TAC THENL
+     [MATCH_MP_TAC SUM_SUBSET_SIMPLE THEN
+      ASM_SIMP_TAC[AFFINE_INDEPENDENT_IMP_FINITE; REAL_LT_IMP_LE; IN_DIFF] THEN
+      ASM SET_TAC[];
+      ASM_SIMP_TAC[SUM_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN
+      ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+      MATCH_MP_TAC(REAL_ARITH `&0 < y ==> x + y + &0 <= &1 ==> x < &1`) THEN
+      ASM_SIMP_TAC[]]]);;
+
+let RELATIVE_INTERIOR_CONVEX_HULL_EXPLICIT = prove
+ (`!s. ~(affine_dependent s)
+       ==> relative_interior(convex hull s) =
+             {y:real^N | ?u. (!x. x IN s ==> &0 < u x) /\
+                             sum s u = &1 /\
+                             vsum s (\x. u x % x) = y}`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN
+  ASM_SIMP_TAC[EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL_MINIMAL] THEN
+  ASM_CASES_TAC `?a:real^N. s = {a}` THENL
+   [FIRST_X_ASSUM(CHOOSE_THEN SUBST1_TAC) THEN
+    ASM_REWRITE_TAC[SUM_SING; VSUM_SING; CONVEX_HULL_SING;
+                    RELATIVE_INTERIOR_SING] THEN
+    REWRITE_TAC[IN_ELIM_THM; SUBSET; IN_SING] THEN
+    REPEAT STRIP_TAC THEN EXISTS_TAC `\x:real^N. &1` THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_LID; REAL_LT_01];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(SET_RULE
+   `relative_interior s SUBSET s /\
+    (!x. x IN s /\ ~(x IN t) ==> ~(x IN relative_interior s))
+    ==> relative_interior s SUBSET t`) THEN
+  REWRITE_TAC[RELATIVE_INTERIOR_SUBSET] THEN
+  X_GEN_TAC `y:real^N` THEN REWRITE_TAC[IN_RELATIVE_INTERIOR] THEN
+  REWRITE_TAC[AFFINE_HULL_CONVEX_HULL; IN_ELIM_THM; NOT_EXISTS_THM] THEN
+  REWRITE_TAC[CONVEX_HULL_FINITE; IN_ELIM_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC)
+   (MP_TAC o SPEC `u:real^N->real`)) THEN
+  ASM_REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; IN_RELATIVE_INTERIOR; DE_MORGAN_THM;
+                  SUBSET; IN_ELIM_THM; IN_BALL; IN_INTER] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN DISJ2_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "*"))) THEN
+  SUBGOAL_THEN `(u:real^N->real) a = &0` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[REAL_ARITH `&0 <= x /\ ~(&0 < x) ==> x = &0`]; ALL_TAC] THEN
+  SUBGOAL_THEN `?b:real^N. b IN s /\ ~(b = a)` STRIP_ASSUME_TAC THENL
+   [ASM SET_TAC[];ALL_TAC] THEN
+  SUBGOAL_THEN `?d. &0 < d /\ norm(d % (a - b):real^N) < e`
+  STRIP_ASSUME_TAC THENL
+   [EXISTS_TAC `e / &2 / norm(a - b:real^N)` THEN
+    ASM_SIMP_TAC[NORM_MUL; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH; NORM_POS_LT;
+                 REAL_ABS_DIV; REAL_ABS_NORM; REAL_ABS_NUM;
+                 REAL_DIV_RMUL; REAL_LT_IMP_NZ; VECTOR_SUB_EQ] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REMOVE_THEN "*" (MP_TAC o SPEC `y - d % (a - b):real^N`) THEN
+  ASM_REWRITE_TAC[NORM_ARITH `dist(a:real^N,a - b) = norm b`] THEN
+  REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC IN_AFFINE_SUB_MUL_DIFF THEN
+    ASM_SIMP_TAC[HULL_INC; AFFINE_AFFINE_HULL] THEN
+    REWRITE_TAC[AFFINE_HULL_FINITE; IN_ELIM_THM] THEN
+    EXISTS_TAC `u:real^N->real` THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:real^N->real` STRIP_ASSUME_TAC) THEN
+  UNDISCH_TAC `~(affine_dependent(s:real^N->bool))` THEN
+  ASM_SIMP_TAC[AFFINE_DEPENDENT_EXPLICIT_FINITE] THEN
+  EXISTS_TAC `\x:real^N. (v x - u x) -
+                   (if x = a then --d else if x = b then d else &0)` THEN
+  REWRITE_TAC[VECTOR_SUB_RDISTRIB; MESON[]
+   `(if p then a else b) % x = (if p then a % x else b % x)`] THEN
+  ASM_SIMP_TAC[SUM_SUB; VSUM_SUB] THEN
+  ASM_SIMP_TAC[VSUM_CASES; SUM_CASES; FINITE_RESTRICT; IN_ELIM_THM] THEN
+  ASM_SIMP_TAC[SET_RULE `a IN s ==> {x | x IN s /\ x = a} = {a}`;
+   SET_RULE `b IN s /\ ~(b = a)
+             ==> {x | (x IN s /\ ~(x = a)) /\ x = b} = {b}`] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_LZERO; SUM_0; VSUM_0; SUM_SING; VSUM_SING] THEN
+  CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+  CONJ_TAC THENL [ALL_TAC; VECTOR_ARITH_TAC] THEN
+  EXISTS_TAC `a:real^N` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `a:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let EXPLICIT_SUBSET_INTERIOR_CONVEX_HULL = prove
+ (`!s. FINITE s /\ affine hull s = (:real^N)
+       ==> {y | ?u. (!x. x IN s ==> &0 < u x /\ u x < &1) /\
+                    sum s u = &1 /\
+                    vsum s (\x. u x % x) = y}
+           SUBSET interior(convex hull s)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o
+    MATCH_MP EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL) THEN
+  ASM_SIMP_TAC[RELATIVE_INTERIOR_INTERIOR; AFFINE_HULL_CONVEX_HULL]);;
+
+let EXPLICIT_SUBSET_INTERIOR_CONVEX_HULL_MINIMAL = prove
+ (`!s. FINITE s /\ affine hull s = (:real^N)
+       ==> {y | ?u. (!x. x IN s ==> &0 < u x) /\
+                    sum s u = &1 /\
+                    vsum s (\x. u x % x) = y}
+           SUBSET interior(convex hull s)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o
+    MATCH_MP EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL_MINIMAL) THEN
+  ASM_SIMP_TAC[RELATIVE_INTERIOR_INTERIOR; AFFINE_HULL_CONVEX_HULL]);;
+
+let INTERIOR_CONVEX_HULL_EXPLICIT_MINIMAL = prove
+ (`!s:real^N->bool.
+        ~(affine_dependent s)
+        ==> interior(convex hull s) =
+             if CARD(s) <= dimindex(:N) then {}
+              else {y | ?u. (!x. x IN s ==> &0 < u x) /\
+                            sum s u = &1 /\
+                            vsum s (\x. u x % x) = y}`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[EMPTY_INTERIOR_CONVEX_HULL] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `relative_interior(convex hull s):real^N->bool` THEN
+  CONJ_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC RELATIVE_INTERIOR_INTERIOR THEN
+    REWRITE_TAC[AFFINE_HULL_CONVEX_HULL] THEN
+    MATCH_MP_TAC AFFINE_INDEPENDENT_SPAN_GT THEN
+    ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC;
+    ASM_SIMP_TAC[RELATIVE_INTERIOR_CONVEX_HULL_EXPLICIT]]);;
+
+let INTERIOR_CONVEX_HULL_EXPLICIT = prove
+ (`!s:real^N->bool.
+        ~(affine_dependent s)
+        ==> interior(convex hull s) =
+             if CARD(s) <= dimindex(:N) then {}
+              else {y | ?u. (!x. x IN s ==> &0 < u x /\ u x < &1) /\
+                            sum s u = &1 /\
+                            vsum s (\x. u x % x) = y}`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[INTERIOR_CONVEX_HULL_EXPLICIT_MINIMAL] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+ REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN X_GEN_TAC `v:real^N` THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `u:real^N->real` THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  MP_TAC(ISPEC `s:real^N->bool` CHOOSE_SUBSET) THEN
+  ASM_SIMP_TAC[AFFINE_INDEPENDENT_IMP_FINITE] THEN
+  DISCH_THEN(MP_TAC o SPEC `2`) THEN ANTS_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (ARITH_RULE
+     `~(c <= n) ==> 1 <= n ==> 2 <= c`)) THEN
+    REWRITE_TAC[DIMINDEX_GE_1];
+    ALL_TAC] THEN
+  CONV_TAC(ONCE_DEPTH_CONV HAS_SIZE_CONV) THEN
+  REWRITE_TAC[SUBSET] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` (CONJUNCTS_THEN2 ASSUME_TAC
+    MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` (X_CHOOSE_THEN `b:real^N`
+        STRIP_ASSUME_TAC)) THEN
+  SUBGOAL_THEN `?y:real^N. y IN s /\ ~(y = x)` STRIP_ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `sum {x,y} u <= sum s (u:real^N->real)` MP_TAC THENL
+   [MATCH_MP_TAC SUM_SUBSET_SIMPLE THEN
+    ASM_SIMP_TAC[AFFINE_INDEPENDENT_IMP_FINITE; REAL_LT_IMP_LE; IN_DIFF] THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[SUM_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN
+  ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+  MATCH_MP_TAC(REAL_ARITH `&0 < y ==> x + y + &0 <= &1 ==> x < &1`) THEN
+  ASM_SIMP_TAC[]);;
+
+let INTERIOR_CONVEX_HULL_3_MINIMAL = prove
+ (`!a b c:real^2.
+        ~collinear{a,b,c}
+        ==> interior(convex hull {a,b,c}) =
+                {v | ?x y z. &0 < x /\
+                             &0 < y /\
+                             &0 < z /\
+                             x + y + z = &1 /\
+                             x % a + y % b + z % c = v}`,
+  REWRITE_TAC[COLLINEAR_3_EQ_AFFINE_DEPENDENT; DE_MORGAN_THM] THEN
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[INTERIOR_CONVEX_HULL_EXPLICIT_MINIMAL] THEN
+  ASM_SIMP_TAC[CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN
+  CONV_TAC(LAND_CONV(RATOR_CONV(LAND_CONV(ONCE_DEPTH_CONV(REWRITE_CONV
+   [IN_INSERT; NOT_IN_EMPTY]))))) THEN
+  ASM_REWRITE_TAC[DIMINDEX_2; ARITH] THEN
+  SIMP_TAC[FINITE_INSERT; FINITE_UNION; FINITE_EMPTY; RIGHT_EXISTS_AND_THM;
+           AFFINE_HULL_FINITE_STEP_GEN; REAL_LT_ADD; REAL_HALF] THEN
+  REWRITE_TAC[REAL_ARITH `&1 - a - b - c = &0 <=> a + b + c = &1`;
+         VECTOR_ARITH `y - a - b - c:real^N = vec 0 <=> a + b + c = y`]);;
+
+let INTERIOR_CONVEX_HULL_3 = prove
+ (`!a b c:real^2.
+        ~collinear{a,b,c}
+        ==> interior(convex hull {a,b,c}) =
+                {v | ?x y z. &0 < x /\ x < &1 /\
+                             &0 < y /\ y < &1 /\
+                             &0 < z /\ z < &1 /\
+                             x + y + z = &1 /\
+                             x % a + y % b + z % c = v}`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[INTERIOR_CONVEX_HULL_3_MINIMAL] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN GEN_TAC THEN
+  REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN EQ_TAC THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Similar results for closure and (relative or absolute) frontier.          *)
+(* ------------------------------------------------------------------------- *)
+
+let CLOSURE_CONVEX_HULL = prove
+ (`!s. compact s ==> closure(convex hull s) = convex hull s`,
+  SIMP_TAC[CLOSURE_CLOSED; COMPACT_IMP_CLOSED; COMPACT_CONVEX_HULL]);;
+
+let RELATIVE_FRONTIER_CONVEX_HULL_EXPLICIT = prove
+ (`!s:real^N->bool.
+        ~(affine_dependent s)
+        ==> relative_frontier(convex hull s) =
+                {y | ?u. (!x. x IN s ==> &0 <= u x) /\
+                         (?x. x IN s /\ u x = &0) /\
+                         sum s u = &1 /\
+                         vsum s (\x. u x % x) = y}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[relative_frontier; UNIONS_GSPEC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  ASM_SIMP_TAC[CLOSURE_CONVEX_HULL; FINITE_IMP_COMPACT] THEN
+  ASM_SIMP_TAC[CONVEX_HULL_FINITE; RELATIVE_INTERIOR_CONVEX_HULL_EXPLICIT] THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN X_GEN_TAC `y:real^N` THEN
+  REWRITE_TAC[IN_DIFF; IN_ELIM_THM] THEN EQ_TAC THENL
+   [DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC) ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_EXISTS_THM]) THEN
+    DISCH_THEN(MP_TAC o SPEC `u:real^N->real`) THEN
+    ASM_REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN
+    DISCH_THEN(CHOOSE_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 <= x ==> (~(&0 < x) <=> x = &0)`] THEN
+    DISCH_TAC THEN EXISTS_TAC `u:real^N->real` THEN
+    ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[];
+    DISCH_THEN(X_CHOOSE_THEN `u:real^N->real`
+     (REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC)) THEN
+    CONJ_TAC THENL
+     [EXISTS_TAC `u:real^N->real` THEN ASM_SIMP_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `v:real^N->real` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV
+     [AFFINE_DEPENDENT_EXPLICIT]) THEN
+    REWRITE_TAC[] THEN MAP_EVERY EXISTS_TAC
+     [`s:real^N->bool`; `(\x. u x - v x):real^N->real`] THEN
+    ASM_SIMP_TAC[SUBSET_REFL; VECTOR_SUB_RDISTRIB; SUM_SUB; VSUM_SUB] THEN
+    REWRITE_TAC[REAL_SUB_0; VECTOR_SUB_EQ] THEN ASM_MESON_TAC[REAL_LT_REFL]]);;
+
+let FRONTIER_CONVEX_HULL_EXPLICIT = prove
+ (`!s:real^N->bool.
+        ~(affine_dependent s)
+        ==> frontier(convex hull s) =
+                {y | ?u. (!x. x IN s ==> &0 <= u x) /\
+                         (dimindex(:N) < CARD s ==> ?x. x IN s /\ u x = &0) /\
+                         sum s u = &1 /\
+                         vsum s (\x. u x % x) = y}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[frontier] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  DISJ_CASES_TAC
+   (ARITH_RULE `CARD(s:real^N->bool) <= dimindex(:N) \/
+                dimindex(:N) < CARD(s:real^N->bool)`)
+  THENL
+   [ASM_SIMP_TAC[GSYM NOT_LE; INTERIOR_CONVEX_HULL_EXPLICIT] THEN
+    ASM_SIMP_TAC[CLOSURE_CONVEX_HULL; FINITE_IMP_COMPACT; DIFF_EMPTY] THEN
+    REWRITE_TAC[CONVEX_HULL_FINITE];
+    ASM_SIMP_TAC[GSYM RELATIVE_FRONTIER_CONVEX_HULL_EXPLICIT] THEN
+    REWRITE_TAC[relative_frontier] THEN AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC RELATIVE_INTERIOR_INTERIOR THEN
+    MATCH_MP_TAC(SET_RULE `!s. s SUBSET t /\ s = UNIV ==> t = UNIV`) THEN
+    EXISTS_TAC `affine hull s:real^N->bool` THEN
+    ASM_SIMP_TAC[AFFINE_INDEPENDENT_SPAN_GT; HULL_MONO; HULL_SUBSET]]);;
+
+let RELATIVE_FRONTIER_CONVEX_HULL_CASES = prove
+ (`!s:real^N->bool.
+        ~(affine_dependent s)
+        ==> relative_frontier(convex hull s) =
+                UNIONS { convex hull (s DELETE a) |a| a IN s }`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[UNIONS_GSPEC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  ASM_SIMP_TAC[RELATIVE_FRONTIER_CONVEX_HULL_EXPLICIT] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; CONVEX_HULL_FINITE] THEN
+  X_GEN_TAC `y:real^N` THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `u:real^N->real` MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN EXISTS_TAC `u:real^N->real` THEN
+    ASM_SIMP_TAC[IN_DELETE; SUM_DELETE; VSUM_DELETE; REAL_SUB_RZERO] THEN
+    VECTOR_ARITH_TAC;
+    REWRITE_TAC[IN_DELETE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `a:real^N` (CONJUNCTS_THEN2 ASSUME_TAC
+     (X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC))) THEN
+    EXISTS_TAC `(\x. if x = a then &0 else u x):real^N->real` THEN
+    ASM_SIMP_TAC[COND_RAND; COND_RATOR; REAL_LE_REFL; COND_ID] THEN
+    CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+    ASM_SIMP_TAC[SUM_CASES; VSUM_CASES; VECTOR_MUL_LZERO] THEN
+    ASM_SIMP_TAC[GSYM DELETE; SUM_0; VSUM_0; REAL_ADD_LID; VECTOR_ADD_LID]]);;
+
+let FRONTIER_CONVEX_HULL_CASES = prove
+ (`!s:real^N->bool.
+        ~(affine_dependent s)
+        ==> frontier(convex hull s) =
+                if CARD(s) <= dimindex(:N) then convex hull s
+                else UNIONS { convex hull (s DELETE a) |a| a IN s }`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  ASM_SIMP_TAC[frontier; CLOSURE_CONVEX_HULL; FINITE_IMP_COMPACT] THEN
+  COND_CASES_TAC THENL
+   [ASM_SIMP_TAC[INTERIOR_CONVEX_HULL_EXPLICIT; DIFF_EMPTY]; ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM RELATIVE_FRONTIER_CONVEX_HULL_CASES] THEN
+  ASM_SIMP_TAC[relative_frontier; frontier;
+               CLOSURE_CONVEX_HULL; FINITE_IMP_COMPACT] THEN
+  AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[NOT_LE]) THEN
+  MATCH_MP_TAC RELATIVE_INTERIOR_INTERIOR THEN
+  MATCH_MP_TAC(SET_RULE `!s. s SUBSET t /\ s = UNIV ==> t = UNIV`) THEN
+  EXISTS_TAC `affine hull s:real^N->bool` THEN
+  ASM_SIMP_TAC[AFFINE_INDEPENDENT_SPAN_GT; HULL_MONO; HULL_SUBSET]);;
+
+let IN_FRONTIER_CONVEX_HULL = prove
+ (`!s x:real^N.
+        FINITE s /\ CARD s <= dimindex(:N) + 1 /\ x IN s
+        ==> x IN frontier(convex hull s)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `affine_dependent(s:real^N->bool)` THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [affine_dependent]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+    ASM_SIMP_TAC[frontier; CLOSURE_CONVEX_HULL; FINITE_IMP_COMPACT] THEN
+    ASM_SIMP_TAC[HULL_INC; IN_DIFF] THEN MATCH_MP_TAC(SET_RULE
+     `!t. s SUBSET t /\ t = {} ==> ~(x IN s)`) THEN
+    EXISTS_TAC `interior(affine hull s):real^N->bool` THEN
+    SIMP_TAC[SUBSET_INTERIOR; CONVEX_HULL_SUBSET_AFFINE_HULL] THEN
+    SUBGOAL_THEN `s = (a:real^N) INSERT (s DELETE a)` SUBST1_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    ASM_SIMP_TAC[HULL_REDUNDANT] THEN
+    MATCH_MP_TAC EMPTY_INTERIOR_AFFINE_HULL THEN
+    ASM_SIMP_TAC[FINITE_DELETE; CARD_DELETE] THEN ASM_ARITH_TAC;
+    ASM_SIMP_TAC[FRONTIER_CONVEX_HULL_CASES] THEN
+    COND_CASES_TAC THEN ASM_SIMP_TAC[HULL_INC] THEN
+    REWRITE_TAC[UNIONS_GSPEC; IN_ELIM_THM] THEN
+    SUBGOAL_THEN `?y:real^N. y IN s /\ ~(y = x)` MP_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `x IN s ==> ~(s = {x}) ==> ?y. y IN s /\ ~(y = x)`)) THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_LE]) THEN
+      ASM_SIMP_TAC[CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN
+      REWRITE_TAC[NOT_LT; NOT_IN_EMPTY; ARITH_SUC; DIMINDEX_GE_1];
+      MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN STRIP_TAC THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC HULL_INC THEN ASM SET_TAC[]]]);;
+
+let NOT_IN_INTERIOR_CONVEX_HULL = prove
+ (`!s x:real^N.
+        FINITE s /\ CARD s <= dimindex(:N) + 1 /\ x IN s
+        ==> ~(x IN interior(convex hull s))`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP IN_FRONTIER_CONVEX_HULL) THEN
+  SIMP_TAC[frontier; IN_DIFF]);;
+
+let INTERIOR_CONVEX_HULL_EQ_EMPTY = prove
+ (`!s:real^N->bool.
+        s HAS_SIZE (dimindex(:N) + 1)
+        ==> (interior(convex hull s) = {} <=> affine_dependent s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_SIZE] THEN STRIP_TAC THEN
+  ASM_CASES_TAC `affine_dependent(s:real^N->bool)` THENL
+   [ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+      [affine_dependent]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+    ASM_SIMP_TAC[frontier; CLOSURE_CONVEX_HULL; FINITE_IMP_COMPACT] THEN
+    ASM_SIMP_TAC[HULL_INC; IN_DIFF] THEN MATCH_MP_TAC(SET_RULE
+     `!t. s SUBSET t /\ t = {} ==> s = {}`) THEN
+    EXISTS_TAC `interior(affine hull s):real^N->bool` THEN
+    SIMP_TAC[SUBSET_INTERIOR; CONVEX_HULL_SUBSET_AFFINE_HULL] THEN
+    SUBGOAL_THEN `s = (a:real^N) INSERT (s DELETE a)` SUBST1_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    ASM_SIMP_TAC[HULL_REDUNDANT] THEN
+    MATCH_MP_TAC EMPTY_INTERIOR_AFFINE_HULL THEN
+    ASM_SIMP_TAC[FINITE_DELETE; CARD_DELETE] THEN ASM_ARITH_TAC;
+    ASM_SIMP_TAC[INTERIOR_CONVEX_HULL_EXPLICIT_MINIMAL] THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; ARITH_RULE `~(n + 1 <= n)`] THEN
+    EXISTS_TAC `vsum s (\x:real^N. inv(&(dimindex(:N)) + &1) % x)` THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    EXISTS_TAC `\x:real^N. inv(&(dimindex(:N)) + &1)` THEN
+    ASM_SIMP_TAC[REAL_LT_INV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+    ASM_SIMP_TAC[SUM_CONST; GSYM REAL_OF_NUM_ADD] THEN
+    CONV_TAC REAL_FIELD]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Similar things in special case (could use above as lemmas here instead).  *)
+(* ------------------------------------------------------------------------- *)
+
+let SIMPLEX_EXPLICIT = prove
+ (`!s:real^N->bool.
+        FINITE s /\ ~(vec 0 IN s)
+        ==> convex hull (vec 0 INSERT s) =
+            { y | ?u. (!x. x IN s ==> &0 <= u x) /\
+                      sum s u <= &1 /\
+                      vsum s (\x. u x % x) = y}`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[CONVEX_HULL_FINITE; FINITE_INSERT] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN X_GEN_TAC `y:real^N` THEN
+  ASM_SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES; IN_INSERT] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+  EQ_TAC THEN DISCH_THEN(X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC) THENL
+   [EXISTS_TAC `u:real^N->real` THEN ASM_SIMP_TAC[REAL_LE_REFL] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `vec 0:real^N`) THEN REWRITE_TAC[] THEN
+    ASM_REAL_ARITH_TAC;
+    EXISTS_TAC `\x:real^N. if x = vec 0 then &1 - sum (s:real^N->bool) u
+                           else u(x)` THEN
+    ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [X_GEN_TAC `x:real^N` THEN ASM_CASES_TAC `x:real^N = vec 0` THEN
+      ASM_REWRITE_TAC[REAL_SUB_LE];
+      MATCH_MP_TAC(REAL_ARITH `s = t ==> &1 - s + t = &1`) THEN
+      MATCH_MP_TAC SUM_EQ THEN ASM_MESON_TAC[];
+      FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+      MATCH_MP_TAC VSUM_EQ THEN ASM_MESON_TAC[]]]);;
+
+let STD_SIMPLEX = prove
+ (`convex hull (vec 0 INSERT { basis i | 1 <= i /\ i <= dimindex(:N)}) =
+        {x:real^N | (!i. 1 <= i /\ i <= dimindex(:N) ==> &0 <= x$i) /\
+                    sum (1..dimindex(:N)) (\i. x$i) <= &1 }`,
+  W(MP_TAC o PART_MATCH (lhs o rand) SIMPLEX_EXPLICIT o lhs o snd) THEN ANTS_TAC THENL
+   [REWRITE_TAC[SIMPLE_IMAGE; GSYM IN_NUMSEG] THEN
+    SIMP_TAC[FINITE_IMAGE; FINITE_NUMSEG; IN_IMAGE] THEN
+    REWRITE_TAC[IN_NUMSEG] THEN MESON_TAC[BASIS_NONZERO];
+    ALL_TAC] THEN
+  DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[EXTENSION] THEN
+  ONCE_REWRITE_TAC[IN_ELIM_THM] THEN X_GEN_TAC `x:real^N` THEN
+  REWRITE_TAC[SIMPLE_IMAGE; GSYM IN_NUMSEG] THEN
+  SUBGOAL_THEN `!u. sum (IMAGE (basis:num->real^N) (1..dimindex(:N))) u =
+                        sum (1..dimindex(:N)) (u o basis)`
+   (fun th -> REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN MATCH_MP_TAC SUM_IMAGE THEN REWRITE_TAC[IN_NUMSEG] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC; BASIS_INJ];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!u. vsum (IMAGE (basis:num->real^N) (1..dimindex(:N))) u =
+                        vsum (1..dimindex(:N)) ((u:real^N->real^N) o basis)`
+   (fun th -> REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN MATCH_MP_TAC VSUM_IMAGE THEN REWRITE_TAC[IN_NUMSEG] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC; BASIS_INJ; FINITE_NUMSEG];
+    ALL_TAC] THEN
+  REWRITE_TAC[o_DEF; BASIS_EXPANSION_UNIQUE; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[IN_NUMSEG] THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC) THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `x <= &1 ==> x = y ==> y <= &1`)) THEN
+    MATCH_MP_TAC SUM_EQ THEN ASM_SIMP_TAC[IN_NUMSEG];
+    STRIP_TAC THEN EXISTS_TAC `\y:real^N. y dot x` THEN
+    ASM_SIMP_TAC[DOT_BASIS]]);;
+
+let INTERIOR_STD_SIMPLEX = prove
+ (`interior
+    (convex hull (vec 0 INSERT { basis i | 1 <= i /\ i <= dimindex(:N)})) =
+        {x:real^N | (!i. 1 <= i /\ i <= dimindex(:N) ==> &0 < x$i) /\
+                    sum (1..dimindex(:N)) (\i. x$i) < &1 }`,
+  REWRITE_TAC[EXTENSION; IN_INTERIOR; IN_ELIM_THM; STD_SIMPLEX] THEN
+  REWRITE_TAC[SUBSET; IN_BALL; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    FIRST_ASSUM(MP_TAC o SPEC `x:real^N`) THEN REWRITE_TAC[DIST_REFL] THEN
+    ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_SIMP_TAC[REAL_LT_LE] THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `x - (e / &2) % basis k:real^N`) THEN
+      REWRITE_TAC[NORM_ARITH `dist(x,x - e) = norm(e)`; NORM_MUL] THEN
+      ASM_SIMP_TAC[NORM_BASIS; REAL_ARITH `&0 < e ==> abs(e / &2) * &1 < e`;
+                   VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+      DISCH_THEN(MP_TAC o SPEC `k:num` o CONJUNCT1) THEN ASM_REWRITE_TAC[] THEN
+      ASM_SIMP_TAC[BASIS_COMPONENT] THEN UNDISCH_TAC `&0 < e` THEN
+      REAL_ARITH_TAC;
+      FIRST_X_ASSUM(MP_TAC o SPEC `x + (e / &2) % basis 1:real^N`) THEN
+      REWRITE_TAC[NORM_ARITH `dist(x,x + e) = norm(e)`; NORM_MUL] THEN
+      ASM_SIMP_TAC[NORM_BASIS; LE_REFL; DIMINDEX_GE_1] THEN
+      ASM_SIMP_TAC[REAL_ARITH `&0 < e ==> abs(e / &2) * &1 < e`] THEN
+      DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+      MATCH_MP_TAC(REAL_ARITH `x < y ==> y <= &1 ==> ~(x = &1)`) THEN
+      MATCH_MP_TAC SUM_LT THEN REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+      ONCE_REWRITE_TAC[TAUT `(a /\ b) /\ c <=> ~(a /\ b ==> ~c)`] THEN
+      SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+               BASIS_COMPONENT] THEN
+      CONJ_TAC THENL
+       [GEN_TAC THEN COND_CASES_TAC;
+        EXISTS_TAC `1` THEN REWRITE_TAC[LE_REFL; DIMINDEX_GE_1]] THEN
+      ASM_REAL_ARITH_TAC];
+    STRIP_TAC THEN
+    EXISTS_TAC
+     `min (inf(IMAGE (\i. (x:real^N)$i) (1..dimindex(:N))))
+          ((&1 - sum (1..dimindex(:N)) (\i. x$i)) / &(dimindex(:N)))` THEN
+    ASM_SIMP_TAC[REAL_LT_MIN] THEN
+    SIMP_TAC[REAL_LT_INF_FINITE; FINITE_IMAGE; FINITE_NUMSEG;
+             IMAGE_EQ_EMPTY; NUMSEG_EMPTY; GSYM NOT_LE; DIMINDEX_GE_1] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE] THEN
+    ASM_SIMP_TAC[REAL_LT_RDIV_EQ; REAL_OF_NUM_LT;
+                 ARITH_RULE `0 < x <=> 1 <= x`; DIMINDEX_GE_1] THEN
+    ASM_REWRITE_TAC[IN_NUMSEG; REAL_MUL_LZERO; REAL_SUB_LT] THEN
+    REPEAT(POP_ASSUM(K ALL_TAC)) THEN X_GEN_TAC `y:real^N` THEN
+    MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+     [MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `k:num` THEN
+      DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+      ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(REAL_ARITH `abs(xk - yk) <= d ==> d < xk ==> &0 <= yk`);
+      GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o RAND_CONV o RAND_CONV)
+       [GSYM CARD_NUMSEG_1] THEN
+      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+      SIMP_TAC[GSYM SUM_CONST; FINITE_NUMSEG] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `s2 <= s0 + s1 ==> s0 < &1 - s1 ==> s2 <= &1`) THEN
+      REWRITE_TAC[GSYM SUM_ADD_NUMSEG] THEN
+      MATCH_MP_TAC SUM_LE_NUMSEG THEN REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH `abs(y - x) <= z ==> x <= z + y`)] THEN
+    ASM_SIMP_TAC[GSYM VECTOR_SUB_COMPONENT; dist] THEN
+    MATCH_MP_TAC COMPONENT_LE_NORM THEN ASM_REWRITE_TAC[]]);;
diff --git a/Multivariate/cross.ml b/Multivariate/cross.ml
new file mode 100644 (file)
index 0000000..e7538b9
--- /dev/null
@@ -0,0 +1,279 @@
+(* ========================================================================= *)
+(* Cross products in real^3.                                                 *)
+(* ========================================================================= *)
+
+needs "Multivariate/topology.ml";;
+
+prioritize_vector();;
+
+(* ------------------------------------------------------------------------- *)
+(* The definition.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("cross",(20,"right"));;
+
+let cross = new_definition
+ `(a:real^3) cross (b:real^3) =
+    vector [a$2 * b$3 - a$3 * b$2;
+            a$3 * b$1 - a$1 * b$3;
+            a$1 * b$2 - a$2 * b$1] :real^3`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Some simple automation.                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let VEC3_TAC =
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; FORALL_3; SUM_3; DIMINDEX_3; VECTOR_3;
+           vector_add; vec; dot; cross; orthogonal; basis; DET_3;
+           vector_neg; vector_sub; vector_mul; ARITH] THEN
+  CONV_TAC REAL_RING;;
+
+let VEC3_RULE tm = prove(tm,VEC3_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic lemmas.                                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let ORTHOGONAL_CROSS = prove
+ (`!x y. orthogonal (x cross y) x /\ orthogonal (x cross y) y /\
+         orthogonal x (x cross y) /\ orthogonal y (x cross y)`,
+  VEC3_TAC);;
+
+let CROSS_LZERO = prove
+ (`!x. (vec 0) cross x = vec 0`,
+  VEC3_TAC);;
+
+let CROSS_RZERO = prove
+ (`!x. x cross (vec 0) = vec 0`,
+  VEC3_TAC);;
+
+let CROSS_SKEW = prove
+ (`!x y. (x cross y) = --(y cross x)`,
+  VEC3_TAC);;
+
+let CROSS_REFL = prove
+ (`!x. x cross x = vec 0`,
+  VEC3_TAC);;
+
+let CROSS_LADD = prove
+ (`!x y z. (x + y) cross z = (x cross z) + (y cross z)`,
+  VEC3_TAC);;
+
+let CROSS_RADD = prove
+ (`!x y z. x cross (y + z) = (x cross y) + (x cross z)`,
+  VEC3_TAC);;
+
+let CROSS_LMUL = prove
+ (`!c x y. (c % x) cross y = c % (x cross y)`,
+  VEC3_TAC);;
+
+let CROSS_RMUL = prove
+ (`!c x y. x cross (c % y) = c % (x cross y)`,
+  VEC3_TAC);;
+
+let CROSS_LNEG = prove
+ (`!x y. (--x) cross y = --(x cross y)`,
+  VEC3_TAC);;
+
+let CROSS_RNEG = prove
+ (`!x y. x cross (--y) = --(x cross y)`,
+  VEC3_TAC);;
+
+let CROSS_LSUB = prove
+ (`!x y z. (x - y) cross z = x cross z - y cross z`,
+  VEC3_TAC);;
+
+let CROSS_RSUB = prove
+ (`!x y z. x cross (y - z) = x cross y - x cross z`,
+  VEC3_TAC);;
+
+let CROSS_JACOBI = prove
+ (`!x y z.
+    x cross (y cross z) + y cross (z cross x) + z cross (x cross y) = vec 0`,
+  VEC3_TAC);;
+
+let CROSS_LAGRANGE = prove
+ (`!x y z. x cross (y cross z) = (x dot z) % y - (x dot y) % z`,
+  VEC3_TAC);;
+
+let CROSS_TRIPLE = prove
+ (`!x y z.  (x cross y) dot z = (y cross z) dot x`,
+  VEC3_TAC);;
+
+let DOT_CROSS_SELF = prove
+ (`(!x y. x dot (x cross y) = &0) /\
+   (!x y. x dot (y cross x) = &0) /\
+   (!x y. (x cross y) dot y = &0) /\
+   (!x y. (y cross x) dot y = &0)`,
+  VEC3_TAC);;
+
+let CROSS_COMPONENTS = prove
+ (`!x y. (x cross y)$1 = x$2 * y$3 - y$2 * x$3 /\
+         (x cross y)$2 = x$3 * y$1 - y$3 * x$1 /\
+         (x cross y)$3 = x$1 * y$2 - y$1 * x$2`,
+  VEC3_TAC);;
+
+let CROSS_BASIS = prove
+ (`(basis 1) cross (basis 2) = basis 3 /\
+   (basis 2) cross (basis 1) = --(basis 3) /\
+   (basis 2) cross (basis 3) = basis 1 /\
+   (basis 3) cross (basis 2) = --(basis 1) /\
+   (basis 3) cross (basis 1) = basis 2 /\
+   (basis 1) cross (basis 3) = --(basis 2)`,
+  VEC3_TAC);;
+
+let CROSS_BASIS_NONZERO = prove
+ (`!u. ~(u = vec 0)
+       ==> ~(u cross basis 1 = vec 0) \/
+           ~(u cross basis 2 = vec 0) \/
+           ~(u cross basis 3 = vec 0)`,
+  VEC3_TAC);;
+
+let CROSS_DOT_CANCEL = prove
+ (`!x y z.
+     x dot y = x dot z /\ x cross y = x cross z /\ ~(x = vec 0) ==> y = z`,
+  ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN REWRITE_TAC[GSYM DOT_EQ_0] THEN
+  VEC3_TAC);;
+
+let NORM_CROSS_DOT = prove
+ (`!x y. norm(x cross y) pow 2 + (x dot y) pow 2 = (norm(x) * norm y) pow 2`,
+  REWRITE_TAC[REAL_POW_MUL; NORM_POW_2] THEN VEC3_TAC);;
+
+let DOT_CROSS_DET = prove
+ (`!x y z. x dot (y cross z) = det(vector[x;y;z]:real^3^3)`,
+  VEC3_TAC);;
+
+let CROSS_CROSS_DET = prove
+ (`!w x y z. (w cross x) cross (y cross z) =
+                det(vector[w;x;z]:real^3^3) % y -
+                det(vector[w;x;y]:real^3^3) % z`,
+  VEC3_TAC);;
+
+let DOT_CROSS = prove
+ (`!w x y z. (w cross x) dot (y cross z) =
+                (w dot y) * (x dot z) - (w dot z) * (x dot y)`,
+  VEC3_TAC);;
+
+let NORM_CROSS = prove
+ (`!x y. norm(x cross y) pow 2 =
+           norm(x) pow 2 * norm(y) pow 2 - (x dot y) pow 2`,
+  REWRITE_TAC[NORM_POW_2] THEN VEC3_TAC);;
+
+let CROSS_EQ_0 = prove
+ (`!x y. x cross y = vec 0 <=> collinear{vec 0,x,y}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM NORM_EQ_0] THEN
+  ONCE_REWRITE_TAC[REAL_RING `x = &0 <=> x pow 2 = &0`] THEN
+  REWRITE_TAC[NORM_CROSS; REAL_SUB_0; GSYM REAL_POW_MUL] THEN
+  REWRITE_TAC[GSYM REAL_EQ_SQUARE_ABS; GSYM NORM_CAUCHY_SCHWARZ_EQUAL] THEN
+  SIMP_TAC[real_abs; REAL_LE_MUL; NORM_POS_LE; EQ_SYM_EQ]);;
+
+let CROSS_0 = prove
+ (`(!x. vec 0 cross x = vec 0) /\
+   (!x. x cross vec 0 = vec 0)`,
+  VEC3_TAC);;
+
+let CROSS_EQ_SELF = prove
+ (`(!x y. x cross y = x <=> x = vec 0) /\
+   (!x y. x cross y = y <=> y = vec 0)`,
+  MESON_TAC[ORTHOGONAL_CROSS; CROSS_0; ORTHOGONAL_REFL]);;
+
+let NORM_AND_CROSS_EQ_0 = prove
+ (`!x y. x dot y = &0 /\ x cross y = vec 0 <=> x = vec 0 \/ y = vec 0`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `x:real^3 = vec 0` THEN
+  ASM_REWRITE_TAC[CROSS_0; DOT_LZERO] THEN ASM_CASES_TAC `y:real^3 = vec 0` THEN
+  ASM_REWRITE_TAC[CROSS_0; DOT_RZERO] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_REWRITE_TAC[GSYM DOT_EQ_0; DOT_CROSS; REAL_MUL_LZERO] THEN
+  ASM_REWRITE_TAC[REAL_SUB_RZERO; REAL_ENTIRE; DOT_EQ_0]);;
+
+let BILINEAR_CROSS = prove
+ (`bilinear(cross)`,
+  REWRITE_TAC[linear; bilinear; CROSS_LADD; CROSS_RADD;
+              CROSS_LMUL; CROSS_RMUL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Preservation by rotation, or other orthogonal transformation up to sign.  *)
+(* ------------------------------------------------------------------------- *)
+
+let CROSS_MATRIX_MUL = prove
+ (`!A x y. transp A ** ((A ** x) cross (A ** y)) = det A % (x cross y)`,
+  SIMP_TAC[CART_EQ; DIMINDEX_3; FORALL_3; SUM_3; matrix_vector_mul;
+           CROSS_COMPONENTS; LAMBDA_BETA; ARITH; transp; DET_3;
+           VECTOR_MUL_COMPONENT] THEN
+  REAL_ARITH_TAC);;
+
+let CROSS_ORTHOGONAL_MATRIX = prove
+ (`!A x y. orthogonal_matrix A
+           ==> (A ** x) cross (A ** y) = det A % (A ** (x cross y))`,
+  MP_TAC CROSS_MATRIX_MUL THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  REWRITE_TAC[orthogonal_matrix] THEN
+  DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+  DISCH_THEN(MP_TAC o AP_TERM `matrix_vector_mul (A:real^3^3)`) THEN
+  ASM_REWRITE_TAC[MATRIX_VECTOR_MUL_ASSOC; MATRIX_VECTOR_MUL_LID] THEN
+  DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[MATRIX_VECTOR_MUL_RMUL]);;
+
+let CROSS_ROTATION_MATRIX = prove
+ (`!A x y. rotation_matrix A
+           ==> (A ** x) cross (A ** y) =  A ** (x cross y)`,
+  SIMP_TAC[rotation_matrix; CROSS_ORTHOGONAL_MATRIX; VECTOR_MUL_LID]);;
+
+let CROSS_ROTOINVERSION_MATRIX = prove
+ (`!A x y. rotoinversion_matrix A
+           ==> (A ** x) cross (A ** y) =  --(A ** (x cross y))`,
+  SIMP_TAC[rotoinversion_matrix; CROSS_ORTHOGONAL_MATRIX; VECTOR_MUL_LID;
+           VECTOR_MUL_LNEG]);;
+
+let CROSS_ORTHOGONAL_TRANSFORMATION = prove
+ (`!f x y.
+        orthogonal_transformation f
+        ==> (f x) cross (f y) = det(matrix f) % f(x cross y)`,
+  GEN_TAC THEN
+  MP_TAC(ISPEC `matrix(f:real^3->real^3)` CROSS_ORTHOGONAL_MATRIX) THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_MATRIX;
+                  ORTHOGONAL_TRANSFORMATION_LINEAR];
+    ASM_SIMP_TAC[MATRIX_WORKS; ORTHOGONAL_TRANSFORMATION_LINEAR]]);;
+
+let CROSS_LINEAR_IMAGE = prove
+ (`!f x y. linear f /\ (!x. norm(f x) = norm x) /\ det(matrix f) = &1
+           ==> (f x) cross (f y) = f(x cross y)`,
+  SIMP_TAC[ORTHOGONAL_TRANSFORMATION; CONJ_ASSOC; VECTOR_MUL_LID;
+           CROSS_ORTHOGONAL_TRANSFORMATION]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Continuity.                                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_CROSS = prove
+ (`!net:(A)net f g.
+        f continuous net /\ g continuous net
+        ==> (\x. (f x) cross (g x)) continuous net`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[CONTINUOUS_COMPONENTWISE_LIFT] THEN
+  REWRITE_TAC[cross; VECTOR_3; DIMINDEX_3; FORALL_3; LIFT_SUB] THEN
+  REPEAT CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_SUB THEN
+  REWRITE_TAC[LIFT_CMUL] THEN CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_MUL THEN
+  ASM_SIMP_TAC[o_DEF; CONTINUOUS_LIFT_COMPONENT_COMPOSE]);;
+
+let CONTINUOUS_ON_CROSS = prove
+ (`!f:real^N->real^3 g s.
+        f continuous_on s /\ g continuous_on s
+        ==> (\x. (f x) cross (g x)) continuous_on s`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_CROSS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Prove a weaker variant for more convenient interface with functions       *)
+(* intended to work in 1 dimension.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let CROSS_LINEAR_IMAGE_WEAK = prove
+ (`!f x y. linear f /\ (!x. norm(f x) = norm x) /\
+           (2 <= dimindex(:3) ==> det(matrix f) = &1)
+           ==> (f x) cross (f y) = f(x cross y)`,
+  REWRITE_TAC[DIMINDEX_3; ARITH] THEN
+  SIMP_TAC[ORTHOGONAL_TRANSFORMATION; CONJ_ASSOC; VECTOR_MUL_LID;
+           CROSS_ORTHOGONAL_TRANSFORMATION]);;
+
+add_linear_invariants [CROSS_LINEAR_IMAGE_WEAK];;
diff --git a/Multivariate/derivatives.ml b/Multivariate/derivatives.ml
new file mode 100644 (file)
index 0000000..56dd6a6
--- /dev/null
@@ -0,0 +1,2620 @@
+(* ========================================================================= *)
+(* Multivariate calculus in Euclidean space.                                 *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(* ========================================================================= *)
+
+needs "Multivariate/dimension.ml";;
+
+(* ------------------------------------------------------------------------- *)
+(* Derivatives. The definition is slightly tricky since we make it work over *)
+(* nets of a particular form. This lets us prove theorems generally and use  *)
+(* "at a" or "at a within s" for restriction to a set (1-sided on R etc.)    *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix ("has_derivative",(12,"right"));;
+
+let has_derivative = new_definition
+  `(f has_derivative f') net <=>
+        linear f' /\
+        ((\y. inv(norm(y - netlimit net)) %
+              (f(y) -
+               (f(netlimit net) + f'(y - netlimit net)))) --> vec 0) net`;;
+
+(* ------------------------------------------------------------------------- *)
+(* These are the only cases we'll care about, probably.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let has_derivative_within = prove
+ (`!f:real^M->real^N f' x s.
+    (f has_derivative f') (at x within s) <=>
+         linear f' /\
+         ((\y. inv(norm(y - x)) % (f(y) - (f(x) + f'(y - x)))) --> vec 0)
+         (at x within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_derivative] THEN AP_TERM_TAC THEN
+  ASM_CASES_TAC `trivial_limit(at (x:real^M) within s)` THENL
+   [ASM_REWRITE_TAC[LIM]; ASM_SIMP_TAC[NETLIMIT_WITHIN]]);;
+
+let has_derivative_at = prove
+ (`!f:real^M->real^N f' x.
+    (f has_derivative f') (at x) <=>
+         linear f' /\
+         ((\y. inv(norm(y - x)) % (f(y) - (f(x) + f'(y - x)))) --> vec 0)
+         (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[has_derivative_within]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More explicit epsilon-delta forms.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_WITHIN = prove
+ (`(f has_derivative f')(at x within s) <=>
+        linear f' /\
+        !e. &0 < e
+            ==> ?d. &0 < d /\
+                    !x'. x' IN s /\
+                         &0 < norm(x' - x) /\ norm(x' - x) < d
+                         ==> norm(f(x') - f(x) - f'(x' - x)) /
+                             norm(x' - x) < e`,
+  SIMP_TAC[has_derivative_within; LIM_WITHIN] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[dist; VECTOR_ARITH `(x' - (x + d)) = x' - x - d:real^N`] THEN
+  REWRITE_TAC[real_div; VECTOR_SUB_RZERO; NORM_MUL] THEN
+  REWRITE_TAC[REAL_MUL_AC; REAL_ABS_INV; REAL_ABS_NORM]);;
+
+let HAS_DERIVATIVE_AT = prove
+ (`(f has_derivative f')(at x) <=>
+        linear f' /\
+        !e. &0 < e
+            ==> ?d. &0 < d /\
+                    !x'. &0 < norm(x' - x) /\ norm(x' - x) < d
+                         ==> norm(f(x') - f(x) - f'(x' - x)) /
+                             norm(x' - x) < e`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[HAS_DERIVATIVE_WITHIN; IN_UNIV]);;
+
+let HAS_DERIVATIVE_AT_WITHIN = prove
+ (`!f x s. (f has_derivative f') (at x)
+           ==> (f has_derivative f') (at x within s)`,
+  REWRITE_TAC[HAS_DERIVATIVE_WITHIN; HAS_DERIVATIVE_AT] THEN MESON_TAC[]);;
+
+let HAS_DERIVATIVE_WITHIN_OPEN = prove
+ (`!f f' a s.
+         a IN s /\ open s
+         ==> ((f has_derivative f') (at a within s) <=>
+              (f has_derivative f') (at a))`,
+  SIMP_TAC[has_derivative_within; has_derivative_at; LIM_WITHIN_OPEN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Combining theorems.                                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_LINEAR = prove
+ (`!f net. linear f ==> (f has_derivative f) net`,
+  REWRITE_TAC[has_derivative; linear] THEN
+  SIMP_TAC[VECTOR_ARITH `x - y = x + --(&1) % y`] THEN
+  REWRITE_TAC[VECTOR_ARITH `x + --(&1) % (y + x + --(&1) % y) = vec 0`] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; LIM_CONST]);;
+
+let HAS_DERIVATIVE_ID = prove
+ (`!net. ((\x. x) has_derivative (\h. h)) net`,
+  SIMP_TAC[HAS_DERIVATIVE_LINEAR; LINEAR_ID]);;
+
+let HAS_DERIVATIVE_CONST = prove
+ (`!c net. ((\x. c) has_derivative (\h. vec 0)) net`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_derivative; linear] THEN
+  REWRITE_TAC[VECTOR_ADD_RID; VECTOR_SUB_REFL; VECTOR_MUL_RZERO; LIM_CONST]);;
+
+let HAS_DERIVATIVE_LIFT_COMPONENT = prove
+ (`!net:(real^N)net. ((\x. lift(x$i)) has_derivative (\x. lift(x$i))) net`,
+  GEN_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_LINEAR THEN
+  REWRITE_TAC[linear; VECTOR_MUL_COMPONENT; VECTOR_ADD_COMPONENT] THEN
+  REWRITE_TAC[LIFT_ADD; LIFT_CMUL]);;
+
+let HAS_DERIVATIVE_CMUL = prove
+ (`!f f' net c. (f has_derivative f') net
+                ==> ((\x. c % f(x)) has_derivative (\h. c % f'(h))) net`,
+  REPEAT GEN_TAC THEN SIMP_TAC[has_derivative; LINEAR_COMPOSE_CMUL] THEN
+  DISCH_THEN(MP_TAC o SPEC `c:real` o MATCH_MP LIM_CMUL o CONJUNCT2) THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO] THEN
+  MATCH_MP_TAC EQ_IMP THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN
+  AP_TERM_TAC THEN ABS_TAC THEN VECTOR_ARITH_TAC);;
+
+let HAS_DERIVATIVE_CMUL_EQ = prove
+ (`!f f' net c.
+       ~(c = &0)
+       ==> (((\x. c % f(x)) has_derivative (\h. c % f'(h))) net <=>
+            (f has_derivative f') net)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_DERIVATIVE_CMUL) THENL
+   [DISCH_THEN(MP_TAC o SPEC `inv(c):real`);
+    DISCH_THEN(MP_TAC o SPEC `c:real`)] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; VECTOR_MUL_LID; ETA_AX]);;
+
+let HAS_DERIVATIVE_NEG = prove
+ (`!f f' net. (f has_derivative f') net
+            ==> ((\x. --(f(x))) has_derivative (\h. --(f'(h)))) net`,
+  ONCE_REWRITE_TAC[VECTOR_NEG_MINUS1] THEN
+  SIMP_TAC[HAS_DERIVATIVE_CMUL]);;
+
+let HAS_DERIVATIVE_NEG_EQ = prove
+ (`!f f' net. ((\x. --(f(x))) has_derivative (\h. --(f'(h)))) net <=>
+              (f has_derivative f') net`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_DERIVATIVE_NEG) THEN
+  REWRITE_TAC[VECTOR_NEG_NEG; ETA_AX]);;
+
+let HAS_DERIVATIVE_ADD = prove
+ (`!f f' g g' net.
+        (f has_derivative f') net /\ (g has_derivative g') net
+        ==> ((\x. f(x) + g(x)) has_derivative (\h. f'(h) + g'(h))) net`,
+  REPEAT GEN_TAC THEN SIMP_TAC[has_derivative; LINEAR_COMPOSE_ADD] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (TAUT `(a /\ b) /\ (c /\ d) ==> b /\ d`)) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LIM_ADD) THEN REWRITE_TAC[VECTOR_ADD_LID] THEN
+  MATCH_MP_TAC EQ_IMP THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN
+  AP_TERM_TAC THEN ABS_TAC THEN VECTOR_ARITH_TAC);;
+
+let HAS_DERIVATIVE_SUB = prove
+ (`!f f' g g' net.
+        (f has_derivative f') net /\ (g has_derivative g') net
+        ==> ((\x. f(x) - g(x)) has_derivative (\h. f'(h) - g'(h))) net`,
+  SIMP_TAC[VECTOR_SUB; HAS_DERIVATIVE_ADD; HAS_DERIVATIVE_NEG]);;
+
+let HAS_DERIVATIVE_VSUM = prove
+ (`!f net s.
+     FINITE s /\
+     (!a. a IN s ==> ((f a) has_derivative (f' a)) net)
+     ==> ((\x. vsum s (\a. f a x)) has_derivative (\h. vsum s (\a. f' a h)))
+          net`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; HAS_DERIVATIVE_CONST] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_ADD THEN
+  REWRITE_TAC[ETA_AX] THEN ASM_SIMP_TAC[IN_INSERT]);;
+
+let HAS_DERIVATIVE_VSUM_NUMSEG = prove
+ (`!f net m n.
+     (!i. m <= i /\ i <= n ==> ((f i) has_derivative (f' i)) net)
+     ==> ((\x. vsum (m..n) (\i. f i x)) has_derivative
+          (\h. vsum (m..n) (\i. f' i h))) net`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_VSUM THEN
+  ASM_REWRITE_TAC[IN_NUMSEG; FINITE_NUMSEG]);;
+
+let HAS_DERIVATIVE_COMPONENTWISE_WITHIN = prove
+ (`!f:real^M->real^N f' a s.
+        (f has_derivative f') (at a within s) <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> ((\x. lift(f(x)$i)) has_derivative (\x. lift(f'(x)$i)))
+                (at a within s)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[has_derivative_within] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+   [LINEAR_COMPONENTWISE; LIM_COMPONENTWISE_LIFT] THEN
+  SIMP_TAC[AND_FORALL_THM; TAUT `(p ==> q) /\ (p ==> r) <=> p ==> q /\ r`] THEN
+  REWRITE_TAC[GSYM LIFT_ADD; GSYM LIFT_CMUL; GSYM LIFT_SUB] THEN
+  REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; VEC_COMPONENT;
+              VECTOR_SUB_COMPONENT; LIFT_NUM]);;
+
+let HAS_DERIVATIVE_COMPONENTWISE_AT = prove
+ (`!f:real^M->real^N f' a.
+        (f has_derivative f') (at a) <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> ((\x. lift(f(x)$i)) has_derivative (\x. lift(f'(x)$i))) (at a)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  MATCH_ACCEPT_TAC HAS_DERIVATIVE_COMPONENTWISE_WITHIN);;
+
+(* ------------------------------------------------------------------------- *)
+(* Somewhat different results for derivative of scalar multiplier.           *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_VMUL_COMPONENT = prove
+ (`!c:real^M->real^N c' k v:real^P.
+        1 <= k /\ k <= dimindex(:N) /\ (c has_derivative c') net
+        ==> ((\x. c(x)$k % v) has_derivative (\x. c'(x)$k % v)) net`,
+  SIMP_TAC[has_derivative; LINEAR_VMUL_COMPONENT] THEN
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[GSYM VECTOR_ADD_RDISTRIB; GSYM VECTOR_SUB_RDISTRIB] THEN
+  SUBST1_TAC(VECTOR_ARITH `vec 0 = &0 % (v:real^P)`) THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC] THEN MATCH_MP_TAC LIM_VMUL THEN
+  ASM_SIMP_TAC[GSYM VECTOR_SUB_COMPONENT; GSYM VECTOR_ADD_COMPONENT] THEN
+  ASM_SIMP_TAC[GSYM VECTOR_MUL_COMPONENT] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIM]) THEN REWRITE_TAC[LIM] THEN
+  REWRITE_TAC[dist; LIFT_NUM; VECTOR_SUB_RZERO; o_THM; NORM_LIFT] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; REAL_ABS_MUL; NORM_MUL] THEN
+  ASM_MESON_TAC[REAL_LET_TRANS; COMPONENT_LE_NORM;
+                REAL_LE_LMUL; REAL_ABS_POS]);;
+
+let HAS_DERIVATIVE_VMUL_DROP = prove
+ (`!c c' v. (c has_derivative c') net
+            ==> ((\x. drop(c(x)) % v) has_derivative (\x. drop(c'(x)) % v)) net`,
+  SIMP_TAC[drop; LE_REFL; DIMINDEX_1; HAS_DERIVATIVE_VMUL_COMPONENT]);;
+
+let HAS_DERIVATIVE_LIFT_DOT = prove
+ (`!f:real^M->real^N f'.
+     (f has_derivative f') net
+     ==> ((\x. lift(v dot f(x))) has_derivative (\t. lift(v dot (f' t)))) net`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_derivative] THEN
+  REWRITE_TAC[GSYM LIFT_SUB; GSYM LIFT_ADD; GSYM LIFT_CMUL] THEN
+  REWRITE_TAC[GSYM DOT_RADD; GSYM DOT_RSUB; GSYM DOT_RMUL] THEN
+  SUBGOAL_THEN
+   `(\t. lift (v dot (f':real^M->real^N) t)) = (\y. lift(v dot y)) o f'`
+  SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+  SIMP_TAC[LINEAR_COMPOSE; LINEAR_LIFT_DOT] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LIM_LIFT_DOT o CONJUNCT2) THEN
+  SIMP_TAC[o_DEF; DOT_RZERO; LIFT_NUM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Limit transformation for derivatives.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_TRANSFORM_WITHIN = prove
+ (`!f f' g x s d.
+       &0 < d /\ x IN s /\
+       (!x'. x' IN s /\ dist (x',x) < d ==> f x' = g x') /\
+       (f has_derivative f') (at x within s)
+       ==> (g has_derivative f') (at x within s)`,
+  REPEAT GEN_TAC THEN SIMP_TAC[has_derivative_within; IMP_CONJ] THEN
+  REPLICATE_TAC 4 DISCH_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+    LIM_TRANSFORM_WITHIN) THEN
+  EXISTS_TAC `d:real` THEN ASM_SIMP_TAC[DIST_REFL]);;
+
+let HAS_DERIVATIVE_TRANSFORM_AT = prove
+ (`!f f' g x d.
+       &0 < d /\ (!x'. dist (x',x) < d ==> f x' = g x') /\
+       (f has_derivative f') (at x)
+       ==> (g has_derivative f') (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  MESON_TAC[HAS_DERIVATIVE_TRANSFORM_WITHIN; IN_UNIV]);;
+
+let HAS_DERIVATIVE_TRANSFORM_WITHIN_OPEN = prove
+ (`!f g:real^M->real^N s x.
+        open s /\ x IN s /\
+        (!y. y IN s ==> f y = g y) /\
+        (f has_derivative f') (at x)
+        ==> (g has_derivative f') (at x)`,
+  REPEAT GEN_TAC THEN SIMP_TAC[has_derivative_at; IMP_CONJ] THEN
+  REPLICATE_TAC 4 DISCH_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE
+    [TAUT `a /\ b /\ c /\ d ==> e <=> a /\ b /\ c ==> d ==> e`]
+    LIM_TRANSFORM_WITHIN_OPEN) THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_SIMP_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Differentiability.                                                        *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix ("differentiable",(12,"right"));;
+parse_as_infix ("differentiable_on",(12,"right"));;
+
+let differentiable = new_definition
+  `f differentiable net <=> ?f'. (f has_derivative f') net`;;
+
+let differentiable_on = new_definition
+  `f differentiable_on s <=> !x. x IN s ==> f differentiable (at x within s)`;;
+
+let HAS_DERIVATIVE_IMP_DIFFERENTIABLE = prove
+ (`!f f' net. (f has_derivative f') net ==> f differentiable net`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[]);;
+
+let DIFFERENTIABLE_AT_WITHIN = prove
+ (`!f s x. f differentiable (at x)
+           ==> f differentiable (at x within s)`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[HAS_DERIVATIVE_AT_WITHIN]);;
+
+let DIFFERENTIABLE_WITHIN_OPEN = prove
+ (`!f a s.
+         a IN s /\ open s
+         ==> (f differentiable (at a within s) <=> (f differentiable (at a)))`,
+  SIMP_TAC[differentiable; HAS_DERIVATIVE_WITHIN_OPEN]);;
+
+let DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON = prove
+ (`!f s. (!x. x IN s ==> f differentiable at x) ==> f differentiable_on s`,
+  REWRITE_TAC[differentiable_on] THEN MESON_TAC[DIFFERENTIABLE_AT_WITHIN]);;
+
+let DIFFERENTIABLE_ON_EQ_DIFFERENTIABLE_AT = prove
+ (`!f s. open s ==> (f differentiable_on s <=>
+                     !x. x IN s ==> f differentiable at x)`,
+  SIMP_TAC[differentiable_on; DIFFERENTIABLE_WITHIN_OPEN]);;
+
+let DIFFERENTIABLE_TRANSFORM_WITHIN = prove
+ (`!f g x s d.
+       &0 < d /\ x IN s /\
+       (!x'. x' IN s /\ dist (x',x) < d ==> f x' = g x') /\
+       f differentiable (at x within s)
+       ==> g differentiable (at x within s)`,
+  REWRITE_TAC[differentiable] THEN
+  MESON_TAC[HAS_DERIVATIVE_TRANSFORM_WITHIN]);;
+
+let DIFFERENTIABLE_TRANSFORM_AT = prove
+ (`!f g x d.
+       &0 < d /\
+       (!x'. dist (x',x) < d ==> f x' = g x') /\
+       f differentiable at x
+       ==> g differentiable at x`,
+  REWRITE_TAC[differentiable] THEN
+  MESON_TAC[HAS_DERIVATIVE_TRANSFORM_AT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Frechet derivative and Jacobian matrix.                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let frechet_derivative = new_definition
+  `frechet_derivative f net = @f'. (f has_derivative f') net`;;
+
+let FRECHET_DERIVATIVE_WORKS = prove
+ (`!f net. f differentiable net <=>
+           (f has_derivative (frechet_derivative f net)) net`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[frechet_derivative] THEN
+  CONV_TAC(RAND_CONV SELECT_CONV) THEN REWRITE_TAC[differentiable]);;
+
+let LINEAR_FRECHET_DERIVATIVE = prove
+ (`!f net. f differentiable net ==> linear(frechet_derivative f net)`,
+  SIMP_TAC[FRECHET_DERIVATIVE_WORKS; has_derivative]);;
+
+let jacobian = new_definition
+  `jacobian f net = matrix(frechet_derivative f net)`;;
+
+let JACOBIAN_WORKS = prove
+ (`!f net. f differentiable net <=>
+           (f has_derivative (\h. jacobian f net ** h)) net`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL [ALL_TAC; MESON_TAC[differentiable]] THEN
+  REWRITE_TAC[FRECHET_DERIVATIVE_WORKS] THEN
+  SIMP_TAC[jacobian; MATRIX_WORKS; has_derivative] THEN SIMP_TAC[ETA_AX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Differentiability implies continuity.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_MUL_NORM_WITHIN = prove
+ (`!f a s. (f --> vec 0) (at a within s)
+           ==> ((\x. norm(x - a) % f(x)) --> vec 0) (at a within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[LIM_WITHIN] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN
+  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[dist; VECTOR_SUB_RZERO] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `min d (&1)` THEN ASM_REWRITE_TAC[REAL_LT_MIN; REAL_LT_01] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[NORM_MUL; REAL_ABS_NORM] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
+  ASM_SIMP_TAC[REAL_LT_MUL2; NORM_POS_LE]);;
+
+let DIFFERENTIABLE_IMP_CONTINUOUS_WITHIN = prove
+ (`!f:real^M->real^N s.
+        f differentiable (at x within s) ==> f continuous (at x within s)`,
+  REWRITE_TAC[differentiable; has_derivative_within; CONTINUOUS_WITHIN] THEN
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `f':real^M->real^N` MP_TAC) THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o MATCH_MP LIM_MUL_NORM_WITHIN) THEN
+  SUBGOAL_THEN
+   `((f':real^M->real^N) o (\y. y - x)) continuous (at x within s)`
+  MP_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_WITHIN_COMPOSE THEN
+    ASM_SIMP_TAC[LINEAR_CONTINUOUS_WITHIN] THEN
+    SIMP_TAC[CONTINUOUS_SUB; CONTINUOUS_CONST; CONTINUOUS_WITHIN_ID];
+    ALL_TAC] THEN
+  REWRITE_TAC[CONTINUOUS_WITHIN; o_DEF] THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_ASSOC; IMP_IMP; IN_UNIV] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LIM_ADD) THEN
+  SIMP_TAC[LIM_WITHIN; GSYM DIST_NZ; REAL_MUL_RINV; NORM_EQ_0;
+           VECTOR_ARITH `(x - y = vec 0) <=> (x = y)`;
+           VECTOR_MUL_LID; VECTOR_SUB_REFL] THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP LINEAR_0) THEN
+  REWRITE_TAC[dist; VECTOR_SUB_RZERO] THEN
+  REWRITE_TAC[VECTOR_ARITH `(a + b - (c + a)) - (vec 0 + vec 0) = b - c`]);;
+
+let DIFFERENTIABLE_IMP_CONTINUOUS_AT = prove
+ (`!f:real^M->real^N x. f differentiable (at x) ==> f continuous (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[DIFFERENTIABLE_IMP_CONTINUOUS_WITHIN]);;
+
+let DIFFERENTIABLE_IMP_CONTINUOUS_ON = prove
+ (`!f:real^M->real^N s. f differentiable_on s ==> f continuous_on s`,
+  SIMP_TAC[differentiable_on; CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+           DIFFERENTIABLE_IMP_CONTINUOUS_WITHIN]);;
+
+let HAS_DERIVATIVE_WITHIN_SUBSET = prove
+ (`!f s t x. (f has_derivative f') (at x within s) /\ t SUBSET s
+             ==> (f has_derivative f') (at x within t)`,
+   REWRITE_TAC[has_derivative_within] THEN MESON_TAC[LIM_WITHIN_SUBSET]);;
+
+let DIFFERENTIABLE_WITHIN_SUBSET = prove
+ (`!f:real^M->real^N s t.
+      f differentiable (at x within t) /\ s SUBSET t
+      ==> f differentiable (at x within s)`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[HAS_DERIVATIVE_WITHIN_SUBSET]);;
+
+let DIFFERENTIABLE_ON_SUBSET = prove
+ (`!f:real^M->real^N s t.
+      f differentiable_on t /\ s SUBSET t ==> f differentiable_on s`,
+  REWRITE_TAC[differentiable_on] THEN
+  MESON_TAC[SUBSET; DIFFERENTIABLE_WITHIN_SUBSET]);;
+
+let DIFFERENTIABLE_ON_EMPTY = prove
+ (`!f. f differentiable_on {}`,
+  REWRITE_TAC[differentiable_on; NOT_IN_EMPTY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Several results are easier using a "multiplied-out" variant.              *)
+(* (I got this idea from Dieudonne's proof of the chain rule).               *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_WITHIN_ALT = prove
+ (`!f:real^M->real^N f' s x.
+     (f has_derivative f') (at x within s) <=>
+            linear f' /\
+            !e. &0 < e
+                ==> ?d. &0 < d /\
+                        !y. y IN s /\ norm(y - x) < d
+                            ==> norm(f(y) - f(x) - f'(y - x)) <=
+                                e * norm(y - x)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_derivative_within; LIM_WITHIN] THEN
+  ASM_REWRITE_TAC[dist; VECTOR_SUB_RZERO] THEN
+  ASM_CASES_TAC `linear(f':real^M->real^N)` THEN
+  ASM_REWRITE_TAC[NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [REAL_MUL_SYM] THEN
+  SIMP_TAC[GSYM real_div; REAL_LT_LDIV_EQ] THEN
+  REWRITE_TAC[VECTOR_ARITH `a - (b + c) = a - b - c :real^M`] THEN
+  EQ_TAC THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `y:real^M` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `&0 < norm(y - x :real^M)` THENL
+     [ASM_SIMP_TAC[REAL_LT_IMP_LE]; ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [NORM_POS_LT]) THEN
+    ASM_SIMP_TAC[VECTOR_SUB_EQ; VECTOR_SUB_REFL; NORM_0; REAL_MUL_RZERO;
+                 VECTOR_ARITH `vec 0 - x = --x`; NORM_NEG] THEN
+    ASM_MESON_TAC[LINEAR_0; NORM_0; REAL_LE_REFL];
+    FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) 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 STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `y:real^M` THEN STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `e / &2 * norm(y - x :real^M)` THEN
+    ASM_SIMP_TAC[REAL_LT_RMUL_EQ; REAL_LT_LDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN
+    UNDISCH_TAC `&0 < e` THEN REAL_ARITH_TAC]);;
+
+let HAS_DERIVATIVE_AT_ALT = prove
+ (`!f:real^M->real^N f' x.
+     (f has_derivative f') (at x) <=>
+        linear f' /\
+        !e. &0 < e
+            ==> ?d. &0 < d /\
+                    !y. norm(y - x) < d
+                        ==> norm(f(y) - f(x) - f'(y - x)) <= e * norm(y - x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[HAS_DERIVATIVE_WITHIN_ALT; IN_UNIV]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The chain rule.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let DIFF_CHAIN_WITHIN = prove
+ (`!f:real^M->real^N g:real^N->real^P f' g' x s.
+        (f has_derivative f') (at x within s) /\
+        (g has_derivative g') (at (f x) within (IMAGE f s))
+        ==> ((g o f) has_derivative (g' o f'))(at x within s)`,
+  REPEAT GEN_TAC THEN SIMP_TAC[HAS_DERIVATIVE_WITHIN_ALT; LINEAR_COMPOSE] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  FIRST_ASSUM(X_CHOOSE_TAC `B1:real` o MATCH_MP LINEAR_BOUNDED_POS) THEN
+  DISCH_THEN(fun th -> X_GEN_TAC `e:real` THEN DISCH_TAC THEN MP_TAC th) THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (fun th -> ASSUME_TAC th THEN X_CHOOSE_TAC `B2:real` (MATCH_MP
+              LINEAR_BOUNDED_POS th)) MP_TAC) THEN
+  FIRST_X_ASSUM(fun th -> MP_TAC th THEN MP_TAC(SPEC `e / &2 / B2` th)) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN DISCH_TAC THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &2 / (&1 + B1)`) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH; REAL_LT_ADD] THEN
+  DISCH_THEN(X_CHOOSE_THEN `de:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `&1`) THEN
+  REWRITE_TAC[REAL_LT_01; REAL_MUL_LID] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d2:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPECL [`d1:real`; `d2:real`] REAL_DOWN2) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_ADD; REAL_LT_01] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d0:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPECL [`d0:real`; `de / (B1 + &1)`] REAL_DOWN2) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_ADD; REAL_LT_01] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `y:real^M` THEN
+  DISCH_TAC THEN UNDISCH_TAC
+   `!y. y IN s /\ norm(y - x) < d2
+        ==> norm ((f:real^M->real^N) y - f x - f'(y - x)) <= norm(y - x)` THEN
+  DISCH_THEN(MP_TAC o SPEC `y:real^M`) THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[REAL_LT_TRANS]; DISCH_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `y:real^M`) THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[REAL_LT_TRANS]; DISCH_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(f:real^M->real^N) y`) THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [ASM_MESON_TAC[IN_IMAGE]; ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC
+     `norm(f'(y - x)) + norm((f:real^M->real^N) y - f x - f'(y - x))` THEN
+    REWRITE_TAC[NORM_TRIANGLE_SUB] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `B1 * norm(y - x) + norm(y - x :real^M)` THEN
+    ASM_SIMP_TAC[REAL_LE_ADD2] THEN
+    REWRITE_TAC[REAL_ARITH `a * x + x = x * (a + &1)`] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_LT_ADD; REAL_LT_01] THEN
+    ASM_MESON_TAC[REAL_LT_TRANS];
+    DISCH_TAC] THEN
+  REWRITE_TAC[o_THM] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `norm((g:real^N->real^P)(f(y:real^M)) - g(f x) - g'(f y - f x)) +
+              norm((g(f y) - g(f x) - g'(f'(y - x))) -
+                   (g(f y) - g(f x) - g'(f y - f x)))` THEN
+  REWRITE_TAC[NORM_TRIANGLE_SUB] THEN
+  REWRITE_TAC[VECTOR_ARITH `(a - b - c1) - (a - b - c2) = c2 - c1:real^M`] THEN
+  ASM_SIMP_TAC[GSYM LINEAR_SUB] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+    `a <= d ==> b <= ee - d ==> a + b <= ee`)) THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `B2 * norm((f:real^M->real^N) y - f x - f'(y - x))` THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `B2 * e / &2 / B2 * norm(y - x :real^M)` THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL; REAL_LT_IMP_LE] THEN REWRITE_TAC[real_div] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH
+   `b * ((e * h) * b') * x <= e * x - d <=>
+    d <= e * (&1 - h * b' * b) * x`] THEN
+  ASM_SIMP_TAC[REAL_MUL_LINV; REAL_LT_IMP_NZ] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM real_div] THEN
+  ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LT_ADD; REAL_LT_01] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+   `norm(f'(y - x)) + norm((f:real^M->real^N) y - f x - f'(y - x))` THEN
+  REWRITE_TAC[NORM_TRIANGLE_SUB] THEN MATCH_MP_TAC(REAL_ARITH
+   `u <= x * b /\ v <= b ==> u + v <= b * (&1 + x)`) THEN
+  ASM_REWRITE_TAC[]);;
+
+let DIFF_CHAIN_AT = prove
+ (`!f:real^M->real^N g:real^N->real^P f' g' x.
+        (f has_derivative f') (at x) /\
+        (g has_derivative g') (at (f x))
+        ==> ((g o f) has_derivative (g' o f')) (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  ASM_MESON_TAC[DIFF_CHAIN_WITHIN; LIM_WITHIN_SUBSET; SUBSET_UNIV;
+                HAS_DERIVATIVE_WITHIN_SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Composition rules stated just for differentiability.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let DIFFERENTIABLE_LINEAR = prove
+ (`!net f:real^M->real^N. linear f ==> f differentiable net`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[HAS_DERIVATIVE_LINEAR]);;
+
+let DIFFERENTIABLE_CONST = prove
+ (`!c net. (\z. c) differentiable net`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[HAS_DERIVATIVE_CONST]);;
+
+let DIFFERENTIABLE_ID = prove
+ (`!net. (\z. z) differentiable net`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[HAS_DERIVATIVE_ID]);;
+
+let DIFFERENTIABLE_LIFT_COMPONENT = prove
+ (`!net:(real^N)net. (\x. lift(x$i)) differentiable net`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[HAS_DERIVATIVE_LIFT_COMPONENT]);;
+
+let DIFFERENTIABLE_CMUL = prove
+ (`!net f c. f differentiable net ==> (\x. c % f(x)) differentiable net`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[HAS_DERIVATIVE_CMUL]);;
+
+let DIFFERENTIABLE_NEG = prove
+ (`!f net. f differentiable net ==> (\z. --(f z)) differentiable net`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[HAS_DERIVATIVE_NEG]);;
+
+let DIFFERENTIABLE_ADD = prove
+ (`!f g net.
+        f differentiable net /\
+        g differentiable net
+        ==> (\z. f z + g z) differentiable net`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[HAS_DERIVATIVE_ADD]);;
+
+let DIFFERENTIABLE_SUB = prove
+ (`!f g net.
+        f differentiable net /\
+        g differentiable net
+        ==> (\z. f z - g z) differentiable net`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[HAS_DERIVATIVE_SUB]);;
+
+let DIFFERENTIABLE_VSUM = prove
+ (`!f net s.
+     FINITE s /\
+     (!a. a IN s ==> (f a) differentiable net)
+     ==> (\x. vsum s (\a. f a x)) differentiable net`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[differentiable] THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV)
+   [RIGHT_IMP_EXISTS_THM; SKOLEM_THM; RIGHT_AND_EXISTS_THM] THEN
+  DISCH_THEN(CHOOSE_THEN (MP_TAC o MATCH_MP HAS_DERIVATIVE_VSUM)) THEN
+  MESON_TAC[]);;
+
+let DIFFERENTIABLE_VSUM_NUMSEG = prove
+ (`!f net m n.
+     FINITE s /\
+     (!i. m <= i /\ i <= n ==> (f i) differentiable net)
+     ==> (\x. vsum (m..n) (\a. f a x)) differentiable net`,
+  SIMP_TAC[DIFFERENTIABLE_VSUM; FINITE_NUMSEG; IN_NUMSEG]);;
+
+let DIFFERENTIABLE_CHAIN_AT = prove
+ (`!f g x.
+    f differentiable (at x) /\
+    g differentiable (at(f x))
+    ==> (g o f) differentiable (at x)`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[DIFF_CHAIN_AT]);;
+
+let DIFFERENTIABLE_CHAIN_WITHIN = prove
+ (`!f g x s.
+    f differentiable (at x within s) /\
+    g differentiable (at(f x) within IMAGE f s)
+    ==> (g o f) differentiable (at x within s)`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[DIFF_CHAIN_WITHIN]);;
+
+let DIFFERENTIABLE_COMPONENTWISE_WITHIN = prove
+ (`!f:real^M->real^N a s.
+        f differentiable (at a within s) <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> (\x. lift(f(x)$i)) differentiable (at a within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[differentiable] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+   [HAS_DERIVATIVE_COMPONENTWISE_WITHIN] THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_TAC `g':real^M->real^N`) THEN
+    EXISTS_TAC `\i x. lift((g':real^M->real^N) x$i)` THEN ASM_REWRITE_TAC[];
+    DISCH_THEN(X_CHOOSE_TAC `g':num->real^M->real^1`) THEN
+    EXISTS_TAC `(\x. lambda i. drop((g':num->real^M->real^1) i x))
+                :real^M->real^N` THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; LIFT_DROP; ETA_AX]]);;
+
+let DIFFERENTIABLE_COMPONENTWISE_AT = prove
+ (`!f:real^M->real^N a.
+        f differentiable (at a) <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> (\x. lift(f(x)$i)) differentiable (at a)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  MATCH_ACCEPT_TAC DIFFERENTIABLE_COMPONENTWISE_WITHIN);;
+
+(* ------------------------------------------------------------------------- *)
+(* Similarly for "differentiable_on".                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let DIFFERENTIABLE_ON_LINEAR = prove
+ (`!f:real^M->real^N s. linear f ==> f differentiable_on s`,
+  SIMP_TAC[differentiable_on; DIFFERENTIABLE_LINEAR]);;
+
+let DIFFERENTIABLE_ON_CONST = prove
+ (`!s c. (\z. c) differentiable_on s`,
+  REWRITE_TAC[differentiable_on; DIFFERENTIABLE_CONST]);;
+
+let DIFFERENTIABLE_ON_ID = prove
+ (`!s. (\z. z) differentiable_on s`,
+  REWRITE_TAC[differentiable_on; DIFFERENTIABLE_ID]);;
+
+let DIFFERENTIABLE_ON_COMPOSE = prove
+ (`!f g s. f differentiable_on s /\ g differentiable_on (IMAGE f s)
+           ==> (g o f) differentiable_on s`,
+  SIMP_TAC[differentiable_on; FORALL_IN_IMAGE] THEN
+  MESON_TAC[DIFFERENTIABLE_CHAIN_WITHIN]);;
+
+let DIFFERENTIABLE_ON_NEG = prove
+ (`!f s. f differentiable_on s ==> (\z. --(f z)) differentiable_on s`,
+  SIMP_TAC[differentiable_on; DIFFERENTIABLE_NEG]);;
+
+let DIFFERENTIABLE_ON_ADD = prove
+ (`!f g s.
+        f differentiable_on s /\ g differentiable_on s
+        ==> (\z. f z + g z) differentiable_on s`,
+  SIMP_TAC[differentiable_on; DIFFERENTIABLE_ADD]);;
+
+let DIFFERENTIABLE_ON_SUB = prove
+ (`!f g s.
+        f differentiable_on s /\ g differentiable_on s
+        ==> (\z. f z - g z) differentiable_on s`,
+  SIMP_TAC[differentiable_on; DIFFERENTIABLE_SUB]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Uniqueness of derivative.                                                 *)
+(*                                                                           *)
+(* The general result is a bit messy because we need approachability of the  *)
+(* limit point from any direction. But OK for nontrivial intervals etc.      *)
+(* ------------------------------------------------------------------------- *)
+
+let FRECHET_DERIVATIVE_UNIQUE_WITHIN = prove
+ (`!f:real^M->real^N f' f'' x s.
+     (f has_derivative f') (at x within s) /\
+     (f has_derivative f'') (at x within s) /\
+     (!i e. 1 <= i /\ i <= dimindex(:M) /\ &0 < e
+            ==> ?d. &0 < abs(d) /\ abs(d) < e /\ (x + d % basis i) IN s)
+     ==> f' = f''`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_derivative] THEN
+  ONCE_REWRITE_TAC[CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `(x:real^M) limit_point_of s` ASSUME_TAC THENL
+   [REWRITE_TAC[LIMPT_APPROACHABLE] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`1`; `e:real`]) THEN
+    ASM_REWRITE_TAC[DIMINDEX_GE_1; LE_REFL] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(x:real^M) + d % basis 1` THEN
+    ASM_REWRITE_TAC[dist] THEN ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+    ASM_SIMP_TAC[VECTOR_ADD_SUB; NORM_MUL; NORM_BASIS; DIMINDEX_GE_1; LE_REFL;
+                 VECTOR_MUL_EQ_0; REAL_MUL_RID; DE_MORGAN_THM; REAL_ABS_NZ;
+                 BASIS_NONZERO];
+    ALL_TAC] THEN
+  DISCH_THEN(CONJUNCTS_THEN (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP LIM_SUB) THEN
+  SUBGOAL_THEN `netlimit(at x within s) = x:real^M` SUBST_ALL_TAC THENL
+   [ASM_MESON_TAC[NETLIMIT_WITHIN; TRIVIAL_LIMIT_WITHIN]; ALL_TAC] THEN
+  REWRITE_TAC[GSYM VECTOR_SUB_LDISTRIB; NORM_MUL] THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `fx - (fa + f'') - (fx - (fa + f')):real^M = f' - f''`] THEN
+  DISCH_TAC THEN MATCH_MP_TAC LINEAR_EQ_STDBASIS THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+  GEN_REWRITE_TAC I [TAUT `p = ~ ~p`] THEN
+  PURE_REWRITE_TAC[GSYM NORM_POS_LT] THEN DISCH_TAC THEN ABBREV_TAC
+   `e = norm((f':real^M->real^N) (basis i) - f''(basis i :real^M))` THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIM_WITHIN]) THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN
+  ASM_REWRITE_TAC[dist; VECTOR_SUB_RZERO] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`i:num`; `d:real`]) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `c:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(x:real^M) + c % basis i`) THEN
+  ASM_REWRITE_TAC[VECTOR_ADD_SUB; NORM_MUL] THEN
+  ASM_SIMP_TAC[NORM_BASIS; REAL_MUL_RID] THEN
+  ASM_SIMP_TAC[LINEAR_CMUL; GSYM VECTOR_SUB_LDISTRIB; NORM_MUL] THEN
+  REWRITE_TAC[REAL_ABS_INV; REAL_ABS_ABS] THEN
+  ASM_SIMP_TAC[REAL_MUL_LINV; REAL_LT_IMP_NZ; REAL_MUL_ASSOC] THEN
+  REWRITE_TAC[REAL_MUL_LID; REAL_LT_REFL]);;
+
+let FRECHET_DERIVATIVE_UNIQUE_AT = prove
+ (`!f:real^M->real^N f' f'' x.
+     (f has_derivative f') (at x) /\ (f has_derivative f'') (at x)
+     ==> f' = f''`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC FRECHET_DERIVATIVE_UNIQUE_WITHIN THEN
+  MAP_EVERY EXISTS_TAC
+   [`f:real^M->real^N`; `x:real^M`; `(:real^M)`] THEN
+  ASM_REWRITE_TAC[IN_UNIV; WITHIN_UNIV] THEN
+  MESON_TAC[REAL_ARITH `&0 < e ==> &0 < abs(e / &2) /\ abs(e / &2) < e`]);;
+
+let HAS_FRECHET_DERIVATIVE_UNIQUE_AT = prove
+ (`!f:real^M->real^N f' x.
+        (f has_derivative f') (at x)
+        ==> frechet_derivative f (at x) = f'`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC FRECHET_DERIVATIVE_UNIQUE_AT THEN
+  MAP_EVERY EXISTS_TAC [`f:real^M->real^N`; `x:real^M`] THEN
+  ASM_REWRITE_TAC[frechet_derivative] THEN CONV_TAC SELECT_CONV THEN
+  ASM_MESON_TAC[]);;
+
+let FRECHET_DERIVATIVE_CONST_AT = prove
+ (`!c:real^N a:real^M. frechet_derivative (\x. c) (at a) = \h. vec 0`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC HAS_FRECHET_DERIVATIVE_UNIQUE_AT THEN
+  REWRITE_TAC[HAS_DERIVATIVE_CONST]);;
+
+let FRECHET_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL = prove
+ (`!f:real^M->real^N f' f'' x a b.
+     (!i. 1 <= i /\ i <= dimindex(:M) ==> a$i < b$i) /\
+     x IN interval[a,b] /\
+     (f has_derivative f') (at x within interval[a,b]) /\
+     (f has_derivative f'') (at x within interval[a,b])
+     ==> f' = f''`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC FRECHET_DERIVATIVE_UNIQUE_WITHIN THEN
+  MAP_EVERY EXISTS_TAC
+   [`f:real^M->real^N`; `x:real^M`; `interval[a:real^M,b]`] THEN
+  ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`i:num`; `e:real`] THEN STRIP_TAC  THEN
+  MATCH_MP_TAC(MESON[] `(?a. P a \/ P(--a)) ==> (?a:real. P a)`) THEN
+  EXISTS_TAC `(min ((b:real^M)$i - (a:real^M)$i) e) / &2` THEN
+  REWRITE_TAC[REAL_ABS_NEG; GSYM LEFT_OR_DISTRIB] THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+   [UNDISCH_TAC `&0 < e` THEN FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
+    ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  UNDISCH_TAC `(x:real^M) IN interval[a,b]` THEN REWRITE_TAC[IN_INTERVAL] THEN
+  DISCH_TAC THEN
+  ASM_SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+               BASIS_COMPONENT] THEN
+  SUBGOAL_THEN
+   `!P. (!j. 1 <= j /\ j <= dimindex(:M) ==> P j) <=>
+        P i /\
+        (!j. 1 <= j /\ j <= dimindex(:M) /\ ~(j = i) ==> P j)`
+   (fun th -> ONCE_REWRITE_TAC[th])
+  THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_MUL_RZERO; REAL_ADD_RID; REAL_MUL_RID] THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `i:num`)) THEN
+  UNDISCH_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let FRECHET_DERIVATIVE_UNIQUE_WITHIN_OPEN_INTERVAL = prove
+ (`!f:real^M->real^N f' f'' x a b.
+     x IN interval(a,b) /\
+     (f has_derivative f') (at x within interval(a,b)) /\
+     (f has_derivative f'') (at x within interval(a,b))
+     ==> f' = f''`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC FRECHET_DERIVATIVE_UNIQUE_WITHIN THEN
+  MAP_EVERY EXISTS_TAC
+   [`f:real^M->real^N`; `x:real^M`; `interval(a:real^M,b)`] THEN
+  ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`i:num`; `e:real`] THEN STRIP_TAC  THEN
+  MATCH_MP_TAC(MESON[] `(?a. P a \/ P(--a)) ==> (?a:real. P a)`) THEN
+  EXISTS_TAC `(min ((b:real^M)$i - (a:real^M)$i) e) / &3` THEN
+  REWRITE_TAC[REAL_ABS_NEG; GSYM LEFT_OR_DISTRIB] THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+   [UNDISCH_TAC `&0 < e` THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `i:num`) THEN
+    ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  UNDISCH_TAC `(x:real^M) IN interval(a,b)` THEN REWRITE_TAC[IN_INTERVAL] THEN
+  DISCH_TAC THEN
+  ASM_SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+               BASIS_COMPONENT] THEN
+  SUBGOAL_THEN
+   `!P. (!j. 1 <= j /\ j <= dimindex(:M) ==> P j) <=>
+        P i /\
+        (!j. 1 <= j /\ j <= dimindex(:M) /\ ~(j = i) ==> P j)`
+   (fun th -> ONCE_REWRITE_TAC[th])
+  THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_MUL_RZERO; REAL_ADD_RID; REAL_MUL_RID] THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `i:num`)) THEN
+  UNDISCH_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let FRECHET_DERIVATIVE_AT = prove
+ (`!f:real^M->real^N f' x.
+     (f has_derivative f') (at x) ==> (f' = frechet_derivative f (at x))`,
+  MESON_TAC[has_derivative; FRECHET_DERIVATIVE_WORKS;
+            differentiable; FRECHET_DERIVATIVE_UNIQUE_AT]);;
+
+let FRECHET_DERIVATIVE_WITHIN_CLOSED_INTERVAL = prove
+ (`!f:real^M->real^N f' x a b.
+     (!i. 1 <= i /\ i <= dimindex(:M) ==> a$i < b$i) /\
+     x IN interval[a,b] /\
+     (f has_derivative f') (at x within interval[a,b])
+     ==> frechet_derivative f (at x within interval[a,b]) = f'`,
+  ASM_MESON_TAC[has_derivative; FRECHET_DERIVATIVE_WORKS;
+        differentiable; FRECHET_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Component of the differential must be zero if it exists at a local        *)
+(* maximum or minimum for that corresponding component. Start with slightly  *)
+(* sharper forms that fix the sign of the derivative on the boundary.        *)
+(* ------------------------------------------------------------------------- *)
+
+let DIFFERENTIAL_COMPONENT_POS_AT_MINIMUM = prove
+ (`!f:real^M->real^N f' x s k e.
+        1 <= k /\ k <= dimindex(:N) /\
+        x IN s /\ convex s /\ (f has_derivative f') (at x within s) /\
+        &0 < e /\ (!w. w IN s INTER ball(x,e) ==> (f x)$k <= (f w)$k)
+        ==> !y. y IN s ==> &0 <= (f'(y - x))$k`,
+  REWRITE_TAC[has_derivative_within] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `y:real^M = x` THENL
+   [ASM_MESON_TAC[VECTOR_SUB_REFL; LINEAR_0; VEC_COMPONENT; REAL_LE_REFL];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIM_WITHIN]) THEN
+  DISCH_THEN(MP_TAC o SPEC
+    `--((f':real^M->real^N)(y - x)$k) / norm(y - x)`) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; VECTOR_SUB_EQ;
+               NOT_EXISTS_THM; REAL_ARITH `&0 < --x <=> x < &0`] THEN
+  X_GEN_TAC `d:real` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ABBREV_TAC `de = min (&1) ((min d e) / &2 / norm(y - x:real^M))` THEN
+  DISCH_THEN(MP_TAC o SPEC `x + de % (y - x):real^M`) THEN
+  REWRITE_TAC[dist; VECTOR_ADD_SUB; NOT_IMP; GSYM CONJ_ASSOC] THEN
+  SUBGOAL_THEN `norm(de % (y - x):real^M) < min d e` MP_TAC THENL
+   [ASM_SIMP_TAC[NORM_MUL; GSYM REAL_LT_RDIV_EQ;
+                 NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    EXPAND_TAC "de" THEN MATCH_MP_TAC(REAL_ARITH
+     `&0 < de / x ==> abs(min (&1) (de / &2 / x)) < de / x`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_MIN; NORM_POS_LT; VECTOR_SUB_EQ];
+    REWRITE_TAC[REAL_LT_MIN] THEN STRIP_TAC] THEN
+  SUBGOAL_THEN `&0 < de /\ de <= &1` STRIP_ASSUME_TAC THENL
+   [EXPAND_TAC "de" THEN CONJ_TAC THENL [ALL_TAC; REAL_ARITH_TAC] THEN
+    ASM_SIMP_TAC[REAL_LT_MIN; REAL_LT_01; REAL_HALF; REAL_LT_DIV;
+                 NORM_POS_LT; VECTOR_SUB_EQ];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REWRITE_TAC[VECTOR_ARITH
+     `x + a % (y - x):real^N = (&1 - a) % x + a % y`] THEN
+    MATCH_MP_TAC IN_CONVEX_SET THEN ASM_SIMP_TAC[REAL_LT_IMP_LE];
+    DISCH_TAC] THEN
+  ASM_REWRITE_TAC[] THEN REWRITE_TAC[NORM_MUL] THEN
+  ASM_SIMP_TAC[REAL_LT_MUL; REAL_ARITH `&0 < x ==> &0 < abs x`;
+               NORM_POS_LT; VECTOR_SUB_EQ; VECTOR_SUB_RZERO] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `abs(y$k) <= norm(y) /\ ~(abs(y$k) < e) ==> ~(norm y < e)`) THEN
+  ASM_SIMP_TAC[COMPONENT_LE_NORM] THEN REWRITE_TAC[VECTOR_MUL_COMPONENT] THEN
+  REWRITE_TAC[REAL_ABS_INV; REAL_ABS_MUL; REAL_ABS_NORM; REAL_ABS_ABS] THEN
+  REWRITE_TAC[REAL_NOT_LT; REAL_INV_MUL; REAL_ARITH
+   `d <= (a * inv b) * c <=> d <= (c * a) / b`] THEN
+  ASM_SIMP_TAC[REAL_LE_DIV2_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+  ASM_SIMP_TAC[GSYM real_div; REAL_LE_RDIV_EQ; VECTOR_SUB_COMPONENT;
+    VECTOR_ADD_COMPONENT; REAL_ARITH `&0 < x ==> &0 < abs x`] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `fx <= fy /\ a = --b /\ b < &0 ==> a <= abs(fy - (fx + b))`) THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP LINEAR_CMUL th]) THEN
+  ASM_SIMP_TAC[real_abs; VECTOR_MUL_COMPONENT; REAL_LT_IMP_LE] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `x * y < &0 <=> &0 < x * --y`] THEN
+  ASM_SIMP_TAC[REAL_LT_MUL_EQ] THEN
+  CONJ_TAC THENL [FIRST_X_ASSUM MATCH_MP_TAC; ASM_REAL_ARITH_TAC] THEN
+  ASM_REWRITE_TAC[IN_INTER; IN_BALL; NORM_ARITH
+   `dist(x:real^M,x + e) = norm e`]);;
+
+let DIFFERENTIAL_COMPONENT_NEG_AT_MAXIMUM = prove
+ (`!f:real^M->real^N f' x s k e.
+        1 <= k /\ k <= dimindex(:N) /\
+        x IN s /\ convex s /\ (f has_derivative f') (at x within s) /\
+        &0 < e /\ (!w. w IN s INTER ball(x,e) ==> (f w)$k <= (f x)$k)
+        ==> !y. y IN s ==> (f'(y - x))$k <= &0`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`\x. --((f:real^M->real^N) x)`;  `\x. --((f':real^M->real^N) x)`;
+    `x:real^M`; `s:real^M->bool`; `k:num`; `e:real`]
+        DIFFERENTIAL_COMPONENT_POS_AT_MINIMUM) THEN
+  ASM_SIMP_TAC[HAS_DERIVATIVE_NEG] THEN
+  ASM_SIMP_TAC[REAL_LE_NEG2; VECTOR_NEG_COMPONENT; REAL_NEG_GE0]);;
+
+let DROP_DIFFERENTIAL_POS_AT_MINIMUM = prove
+ (`!f:real^N->real^1 f' x s e.
+        x IN s /\ convex s /\ (f has_derivative f') (at x within s) /\
+        &0 < e /\ (!w. w IN s INTER ball(x,e) ==> drop(f x) <= drop(f w))
+        ==> !y. y IN s ==> &0 <= drop(f'(y - x))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[drop] THEN STRIP_TAC THEN
+  MATCH_MP_TAC DIFFERENTIAL_COMPONENT_POS_AT_MINIMUM THEN
+  MAP_EVERY EXISTS_TAC [`f:real^N->real^1`; `e:real`] THEN
+  ASM_REWRITE_TAC[DIMINDEX_1; LE_REFL]);;
+
+let DROP_DIFFERENTIAL_NEG_AT_MAXIMUM = prove
+ (`!f:real^N->real^1 f' x s e.
+        x IN s /\ convex s /\ (f has_derivative f') (at x within s) /\
+        &0 < e /\ (!w. w IN s INTER ball(x,e) ==> drop(f w) <= drop(f x))
+        ==> !y. y IN s ==> drop(f'(y - x)) <= &0`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[drop] THEN STRIP_TAC THEN
+  MATCH_MP_TAC DIFFERENTIAL_COMPONENT_NEG_AT_MAXIMUM THEN
+  MAP_EVERY EXISTS_TAC [`f:real^N->real^1`; `e:real`] THEN
+  ASM_REWRITE_TAC[DIMINDEX_1; LE_REFL]);;
+
+let DIFFERENTIAL_COMPONENT_ZERO_AT_MAXMIN = prove
+ (`!f:real^M->real^N f' x s k.
+        1 <= k /\ k <= dimindex(:N) /\
+        x IN s /\ open s /\ (f has_derivative f') (at x) /\
+        ((!w. w IN s ==> (f w)$k <= (f x)$k) \/
+         (!w. w IN s ==> (f x)$k <= (f w)$k))
+        ==> !h. (f' h)$k = &0`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[SUBSET] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM DISJ_CASES_TAC THENL
+   [MP_TAC(ISPECL [`f:real^M->real^N`; `f':real^M->real^N`;
+                   `x:real^M`; `cball(x:real^M,e)`; `k:num`; `e:real`]
+        DIFFERENTIAL_COMPONENT_NEG_AT_MAXIMUM);
+    MP_TAC(ISPECL [`f:real^M->real^N`; `f':real^M->real^N`;
+                   `x:real^M`; `cball(x:real^M,e)`; `k:num`; `e:real`]
+        DIFFERENTIAL_COMPONENT_POS_AT_MINIMUM)] THEN
+  ASM_SIMP_TAC[HAS_DERIVATIVE_AT_WITHIN; CENTRE_IN_CBALL;
+               CONVEX_CBALL; REAL_LT_IMP_LE; IN_INTER] THEN
+  DISCH_THEN(LABEL_TAC "*") THEN X_GEN_TAC `h:real^M` THEN
+  FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [has_derivative_at]) THEN
+  (ASM_CASES_TAC `h:real^M = vec 0` THENL
+    [ASM_MESON_TAC[LINEAR_0; VEC_COMPONENT]; ALL_TAC]) THEN
+  REMOVE_THEN "*" (fun th ->
+    MP_TAC(SPEC `x + e / norm h % h:real^M` th) THEN
+    MP_TAC(SPEC `x - e / norm h % h:real^M` th)) THEN
+  REWRITE_TAC[IN_CBALL; NORM_ARITH
+   `dist(x:real^N,x - e) = norm e /\ dist(x:real^N,x + e) = norm e`] THEN
+  REWRITE_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM] THEN
+  ASM_SIMP_TAC[real_abs; REAL_DIV_RMUL; NORM_EQ_0; REAL_LT_IMP_LE;
+               REAL_LE_REFL] THEN
+  REWRITE_TAC[VECTOR_ARITH `x - e - x:real^N = --e /\ (x + e) - x = e`] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP LINEAR_NEG th]) THEN
+  REWRITE_TAC[IMP_IMP; REAL_ARITH `&0 <= --x /\ &0 <= x <=> x = &0`;
+    VECTOR_NEG_COMPONENT; REAL_ARITH `--x <= &0 /\ x <= &0 <=> x = &0`] THEN
+  DISCH_THEN(MP_TAC o AP_TERM `(*) (norm(h:real^M) / e)`) THEN
+  REWRITE_TAC[GSYM VECTOR_MUL_COMPONENT] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP LINEAR_CMUL th)]) THEN
+  REWRITE_TAC[REAL_MUL_RZERO; VECTOR_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_FIELD `~(x = &0) /\ ~(y = &0) ==> x / y * y / x = &1`;
+               NORM_EQ_0; REAL_LT_IMP_NZ; VECTOR_MUL_LID]);;
+
+let DIFFERENTIAL_ZERO_MAXMIN_COMPONENT = prove
+ (`!f:real^M->real^N x e k.
+        1 <= k /\ k <= dimindex(:N) /\ &0 < e /\
+        ((!y. y IN ball(x,e) ==> (f y)$k <= (f x)$k) \/
+         (!y. y IN ball(x,e) ==> (f x)$k <= (f y)$k)) /\
+        f differentiable (at x)
+        ==> (jacobian f (at x) $ k = vec 0)`,
+  REWRITE_TAC[JACOBIAN_WORKS] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`f:real^M->real^N`; `\h. jacobian (f:real^M->real^N) (at x) ** h`;
+    `x:real^M`; `ball(x:real^M,e)`; `k:num`]
+      DIFFERENTIAL_COMPONENT_ZERO_AT_MAXMIN) THEN
+  ASM_REWRITE_TAC[CENTRE_IN_BALL; OPEN_BALL] THEN
+  ASM_SIMP_TAC[MATRIX_VECTOR_MUL_COMPONENT; FORALL_DOT_EQ_0]);;
+
+let DIFFERENTIAL_ZERO_MAXMIN = prove
+ (`!f:real^N->real^1 f' x s.
+        x IN s /\ open s /\ (f has_derivative f') (at x) /\
+        ((!y. y IN s ==> drop(f y) <= drop(f x)) \/
+         (!y. y IN s ==> drop(f x) <= drop(f y)))
+        ==> (f' = \v. vec 0)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^N->real^1`; `f':real^N->real^1`;
+                 `x:real^N`; `s:real^N->bool`; `1:num`]
+        DIFFERENTIAL_COMPONENT_ZERO_AT_MAXMIN) THEN
+  ASM_REWRITE_TAC[GSYM drop; DIMINDEX_1; LE_REFL] THEN
+  REWRITE_TAC[GSYM LIFT_EQ; LIFT_NUM; FUN_EQ_THM; LIFT_DROP]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The traditional Rolle theorem in one dimension.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let ROLLE = prove
+ (`!f:real^1->real^1 f' a b.
+        drop a < drop b /\ (f a = f b) /\
+        f continuous_on interval[a,b] /\
+        (!x. x IN interval(a,b) ==> (f has_derivative f'(x)) (at x))
+        ==> ?x. x IN interval(a,b) /\ (f'(x) = \v. vec 0)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `b:real^1`]
+        CONTINUOUS_IVT_LOCAL_EXTREMUM) THEN
+  ASM_SIMP_TAC[SEGMENT_1; REAL_LT_IMP_LE] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[REAL_LT_REFL]; MATCH_MP_TAC MONO_EXISTS] THEN
+  X_GEN_TAC `c:real^1` THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC DIFFERENTIAL_ZERO_MAXMIN THEN MAP_EVERY EXISTS_TAC
+   [`f:real^1->real^1`; `c:real^1`; `interval(a:real^1,b)`] THEN
+  ASM_MESON_TAC[INTERVAL_OPEN_SUBSET_CLOSED; SUBSET; OPEN_INTERVAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* One-dimensional mean value theorem.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let MVT = prove
+ (`!f:real^1->real^1 f' a b.
+        drop a < drop b /\
+        f continuous_on interval[a,b] /\
+        (!x. x IN interval(a,b) ==> (f has_derivative f'(x)) (at x))
+        ==> ?x. x IN interval(a,b) /\ (f(b) - f(a) = f'(x) (b - a))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`\x. f(x) - (drop(f b - f a) / drop(b - a)) % x`;
+                `\k:real^1 x:real^1.
+                    f'(k)(x) - (drop(f b - f a) / drop(b - a)) % x`;
+                `a:real^1`; `b:real^1`]
+               ROLLE) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ASM_SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[VECTOR_ARITH
+       `(fa - k % a = fb - k % b) <=> (fb - fa = k % (b - a))`];
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_SUB THEN
+      ASM_SIMP_TAC[HAS_DERIVATIVE_CMUL; HAS_DERIVATIVE_ID; ETA_AX]];
+    MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[FUN_EQ_THM] THEN
+    X_GEN_TAC `x:real^1` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `b - a:real^1`))] THEN
+  SIMP_TAC[VECTOR_SUB_EQ; GSYM DROP_EQ; DROP_SUB; DROP_CMUL] THEN
+  ASM_SIMP_TAC[REAL_DIV_RMUL; REAL_SUB_LT; REAL_LT_IMP_NZ]);;
+
+let MVT_SIMPLE = prove
+ (`!f:real^1->real^1 f' a b.
+        drop a < drop b /\
+        (!x. x IN interval[a,b]
+             ==> (f has_derivative f'(x)) (at x within interval[a,b]))
+        ==> ?x. x IN interval(a,b) /\ (f(b) - f(a) = f'(x) (b - a))`,
+  MP_TAC MVT THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC DIFFERENTIABLE_IMP_CONTINUOUS_ON THEN
+    ASM_MESON_TAC[differentiable_on; differentiable];
+    ASM_MESON_TAC[HAS_DERIVATIVE_WITHIN_OPEN; OPEN_INTERVAL;
+                  HAS_DERIVATIVE_WITHIN_SUBSET; INTERVAL_OPEN_SUBSET_CLOSED;
+                  SUBSET]]);;
+
+let MVT_VERY_SIMPLE = prove
+ (`!f:real^1->real^1 f' a b.
+        drop a <= drop b /\
+        (!x. x IN interval[a,b]
+             ==> (f has_derivative f'(x)) (at x within interval[a,b]))
+        ==> ?x. x IN interval[a,b] /\ (f(b) - f(a) = f'(x) (b - a))`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `b:real^1 = a` THENL
+   [ASM_REWRITE_TAC[VECTOR_SUB_REFL] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `a:real^1`) THEN
+    REWRITE_TAC[INTERVAL_SING; IN_SING; has_derivative; UNWIND_THM2] THEN
+    MESON_TAC[LINEAR_0];
+    ASM_REWRITE_TAC[REAL_LE_LT; DROP_EQ] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP MVT_SIMPLE) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN
+    SIMP_TAC[REWRITE_RULE[SUBSET] INTERVAL_OPEN_SUBSET_CLOSED]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A nice generalization (see Havin's proof of 5.19 from Rudin's book).      *)
+(* ------------------------------------------------------------------------- *)
+
+let MVT_GENERAL = prove
+ (`!f:real^1->real^N f' a b.
+        drop a < drop b /\
+        f continuous_on interval[a,b] /\
+        (!x. x IN interval(a,b) ==> (f has_derivative f'(x)) (at x))
+        ==> ?x. x IN interval(a,b) /\
+                norm(f(b) - f(a)) <= norm(f'(x) (b - a))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`(lift o (\y. (f(b) - f(a)) dot y)) o (f:real^1->real^N)`;
+                `\x t. lift((f(b:real^1) - f(a)) dot
+                      ((f':real^1->real^1->real^N) x t))`;
+                `a:real^1`; `b:real^1`]  MVT) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[CONTINUOUS_ON_LIFT_DOT; CONTINUOUS_ON_COMPOSE] THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[o_DEF] THEN
+    MATCH_MP_TAC HAS_DERIVATIVE_LIFT_DOT THEN ASM_SIMP_TAC[ETA_AX];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x:real^1` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_REWRITE_TAC[o_THM; GSYM LIFT_SUB; GSYM DOT_RSUB; LIFT_EQ] THEN
+  DISCH_TAC THEN ASM_CASES_TAC `(f:real^1->real^N) b = f a` THENL
+   [ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0; NORM_POS_LE]; ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_LCANCEL_IMP THEN
+  EXISTS_TAC `norm((f:real^1->real^N) b - f a)` THEN
+  ASM_REWRITE_TAC[NORM_POS_LT; VECTOR_SUB_EQ; GSYM REAL_POW_2] THEN
+  ASM_REWRITE_TAC[NORM_POW_2; NORM_CAUCHY_SCHWARZ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Still more general bound theorem.                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let DIFFERENTIABLE_BOUND = prove
+ (`!f:real^M->real^N f' s B.
+        convex s /\
+        (!x. x IN s ==> (f has_derivative f'(x)) (at x within s)) /\
+        (!x. x IN s ==> onorm(f'(x)) <= B)
+        ==> !x y. x IN s /\ y IN s ==> norm(f(x) - f(y)) <= B * norm(x - y)`,
+  ONCE_REWRITE_TAC[NORM_SUB] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+    `!x y. x IN s ==> norm((f':real^M->real^M->real^N)(x) y) <= B * norm(y)`
+  ASSUME_TAC THENL
+   [ASM_MESON_TAC[ONORM; has_derivative; REAL_LE_TRANS; NORM_POS_LE;
+                  REAL_LE_RMUL]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!u. u IN interval[vec 0,vec 1] ==> (x + drop u % (y - x) :real^M) IN s`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[IN_INTERVAL; FORALL_DIMINDEX_1; drop] THEN
+    SIMP_TAC[VEC_COMPONENT; LE_REFL; DIMINDEX_1] THEN
+    REWRITE_TAC[VECTOR_ARITH `x + u % (y - x) = (&1 - u) % x + u % y`] THEN
+    ASM_MESON_TAC[CONVEX_ALT];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!u. u IN interval(vec 0,vec 1) ==> (x + drop u % (y - x) :real^M) IN s`
+  ASSUME_TAC THENL
+   [ASM_MESON_TAC[SUBSET; INTERVAL_OPEN_SUBSET_CLOSED]; ALL_TAC] THEN
+  MP_TAC(SPECL
+   [`(f:real^M->real^N) o (\u. x + drop u % (y - x))`;
+    `\u. (f':real^M->real^M->real^N) (x + drop u % (y - x)) o
+         (\u. vec 0 + drop u % (y - x))`;
+    `vec 0:real^1`; `vec 1:real^1`] MVT_GENERAL) THEN
+  REWRITE_TAC[o_THM; DROP_VEC; VECTOR_ARITH `x + &1 % (y - x) = y`;
+              VECTOR_MUL_LZERO; VECTOR_SUB_RZERO; VECTOR_ADD_RID] THEN
+  REWRITE_TAC[VECTOR_MUL_LID] THEN ANTS_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[VECTOR_ADD_LID; REAL_LE_TRANS]] THEN
+  REWRITE_TAC[REAL_LT_01] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST; CONTINUOUS_ON_VMUL;
+             o_DEF; LIFT_DROP; CONTINUOUS_ON_ID] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:real^M->bool` THEN
+    ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    ASM_MESON_TAC[DIFFERENTIABLE_IMP_CONTINUOUS_WITHIN; differentiable;
+                  CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN];
+    ALL_TAC] THEN
+  X_GEN_TAC `a:real^1` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `a IN interval(vec 0:real^1,vec 1) /\
+                open(interval(vec 0:real^1,vec 1))`
+  MP_TAC THENL [ASM_MESON_TAC[OPEN_INTERVAL]; ALL_TAC] THEN
+  DISCH_THEN(fun th -> ONCE_REWRITE_TAC[GSYM(MATCH_MP
+    HAS_DERIVATIVE_WITHIN_OPEN th)]) THEN
+  MATCH_MP_TAC DIFF_CHAIN_WITHIN THEN
+  ASM_SIMP_TAC[HAS_DERIVATIVE_ADD; HAS_DERIVATIVE_CONST;
+               HAS_DERIVATIVE_VMUL_DROP; HAS_DERIVATIVE_ID] THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_WITHIN_SUBSET THEN
+  EXISTS_TAC `s:real^M->bool` THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  ASM_MESON_TAC[INTERVAL_OPEN_SUBSET_CLOSED; SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In particular.                                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_ZERO_CONSTANT = prove
+ (`!f:real^M->real^N s.
+        convex s /\
+        (!x. x IN s ==> (f has_derivative (\h. vec 0)) (at x within s))
+        ==> ?c. !x. x IN s ==> f(x) = c`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `(\x h. vec 0):real^M->real^M->real^N`;
+                 `s:real^M->bool`; `&0`] DIFFERENTIABLE_BOUND) THEN
+  ASM_REWRITE_TAC[REAL_MUL_LZERO; ONORM_CONST; NORM_0; REAL_LE_REFL] THEN
+  SIMP_TAC[NORM_LE_0; VECTOR_SUB_EQ] THEN MESON_TAC[]);;
+
+let HAS_DERIVATIVE_ZERO_UNIQUE = prove
+ (`!f s a c. convex s /\ a IN s /\ f a = c /\
+             (!x. x IN s ==> (f has_derivative (\h. vec 0)) (at x within s))
+             ==> !x. x IN s ==> f x = c`,
+  MESON_TAC[HAS_DERIVATIVE_ZERO_CONSTANT]);;
+
+let HAS_DERIVATIVE_ZERO_CONNECTED_CONSTANT = prove
+ (`!f:real^M->real^N s.
+        open s /\ connected s /\
+        (!x. x IN s ==> (f has_derivative (\h. vec 0)) (at x))
+        ==> ?c. !x. x IN s ==> f(x) = c`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^M`) THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONNECTED_CLOPEN]) THEN
+  DISCH_THEN(MP_TAC o SPEC `{x | x IN s /\ (f:real^M->real^N) x = f a}`) THEN
+  ANTS_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN CONJ_TAC THENL
+   [SIMP_TAC[open_in; SUBSET; IN_ELIM_THM] THEN
+    X_GEN_TAC `x:real^M` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN
+    REWRITE_TAC[SUBSET; IN_BALL] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPECL [`f:real^M->real^N`; `ball(x:real^M,e)`]
+        HAS_DERIVATIVE_ZERO_CONSTANT) THEN
+    REWRITE_TAC[IN_BALL; CONVEX_BALL] THEN
+    ASM_MESON_TAC[HAS_DERIVATIVE_AT_WITHIN; DIST_SYM; DIST_REFL];
+    MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE_CONSTANT THEN
+    MATCH_MP_TAC DIFFERENTIABLE_IMP_CONTINUOUS_ON THEN
+    ASM_SIMP_TAC[DIFFERENTIABLE_ON_EQ_DIFFERENTIABLE_AT] THEN
+    ASM_MESON_TAC[differentiable]]);;
+
+let HAS_DERIVATIVE_ZERO_CONNECTED_UNIQUE = prove
+ (`!f s a c. open s /\ connected s /\ a IN s /\ f a = c /\
+             (!x. x IN s ==> (f has_derivative (\h. vec 0)) (at x))
+             ==> !x. x IN s ==> f x = c`,
+  MESON_TAC[HAS_DERIVATIVE_ZERO_CONNECTED_CONSTANT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Differentiability of inverse function (most basic form).                  *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_INVERSE_BASIC = prove
+ (`!f:real^M->real^N g f' g' t y.
+        (f has_derivative f') (at (g y)) /\ linear g' /\ (g' o f' = I) /\
+        g continuous (at y) /\
+        open t /\ y IN t /\ (!z. z IN t ==> (f(g(z)) = z))
+        ==> (g has_derivative g') (at y)`,
+  REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(X_CHOOSE_TAC `C:real` o MATCH_MP LINEAR_BOUNDED_POS) THEN
+  SUBGOAL_THEN
+   `!e. &0 < e ==> ?d. &0 < d /\
+                       !z. norm(z - y) < d
+                           ==> norm((g:real^N->real^M)(z) - g(y) - g'(z - y))
+                               <= e * norm(g(z) - g(y))`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HAS_DERIVATIVE_AT_ALT]) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `e / C`)) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d0:real`
+     (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(ASSUME_TAC o GEN `z:real^N` o SPEC `(g:real^N->real^M) z`) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [continuous_at]) THEN
+    DISCH_THEN(MP_TAC o SPEC `d0:real`) THEN ASM_REWRITE_TAC[dist] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `y:real^N` o
+      GEN_REWRITE_RULE I [open_def]) THEN
+    ASM_REWRITE_TAC[dist] 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
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `z:real^N` THEN DISCH_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `C * (e / C) * norm((g:real^N->real^M) z - g y)` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      ASM_SIMP_TAC[REAL_MUL_ASSOC; REAL_LE_RMUL; REAL_DIV_LMUL;
+                   REAL_EQ_IMP_LE; REAL_LT_IMP_NZ; NORM_POS_LE]] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `C * norm(f((g:real^N->real^M) z) - y - f'(g z - g y))` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[REAL_LT_TRANS; REAL_LE_LMUL_EQ]] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC
+     `norm(g'(f((g:real^N->real^M) z) - y - f'(g z - g y)):real^M)` THEN
+    ASM_REWRITE_TAC[] THEN ASM_SIMP_TAC[LINEAR_SUB] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM NORM_NEG] THEN
+    REWRITE_TAC[VECTOR_ARITH
+     `--(gz:real^N - gy - (z - y)) = z - y - (gz - gy)`] THEN
+    ASM_MESON_TAC[REAL_LE_REFL; REAL_LT_TRANS];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?B d. &0 < B /\ &0 < d /\
+          !z. norm(z - y) < d
+              ==> norm((g:real^N->real^M)(z) - g(y)) <= B * norm(z - y)`
+  STRIP_ASSUME_TAC THENL
+   [EXISTS_TAC `&2 * C` THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `&1 / &2`) THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+    ASM_SIMP_TAC[REAL_LT_MUL; REAL_OF_NUM_LT; ARITH] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `z:real^N` THEN
+    MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH
+        `norm(dg) <= norm(dg') + norm(dg - dg') /\
+         ((&2 * (&1 - h)) * norm(dg) = &1 * norm(dg)) /\
+         norm(dg') <= c * norm(d)
+         ==> norm(dg - dg') <= h * norm(dg)
+             ==> norm(dg) <= (&2 * c) * norm(d)`) THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[NORM_TRIANGLE_SUB];
+    ALL_TAC] THEN
+  REWRITE_TAC[HAS_DERIVATIVE_AT_ALT] THEN ASM_REWRITE_TAC[] 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] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d':real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPECL [`d:real`; `d':real`] REAL_DOWN2) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `z:real^N` THEN
+  DISCH_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `e / B * norm ((g:real^N->real^M) z - g y)` THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[REAL_LT_TRANS]; ALL_TAC] THEN
+  ASM_SIMP_TAC[real_div; GSYM REAL_MUL_ASSOC; REAL_LE_LMUL_EQ] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM real_div; REAL_LE_LDIV_EQ] THEN
+  ASM_MESON_TAC[REAL_MUL_SYM; REAL_LT_TRANS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Simply rewrite that based on the domain point x.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_INVERSE_BASIC_X = prove
+ (`!f:real^M->real^N g f' g' t x.
+        (f has_derivative f') (at x) /\ linear g' /\ (g' o f' = I) /\
+        g continuous (at (f(x))) /\ (g(f(x)) = x) /\
+        open t /\ f(x) IN t /\ (!y. y IN t ==> (f(g(y)) = y))
+        ==> (g has_derivative g') (at (f(x)))`,
+  MESON_TAC[HAS_DERIVATIVE_INVERSE_BASIC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* This is the version in Dieudonne', assuming continuity of f and g.        *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_INVERSE_DIEUDONNE = prove
+ (`!f:real^M->real^N g s.
+        open s /\ open (IMAGE f s) /\
+        f continuous_on s /\ g continuous_on (IMAGE f s) /\
+        (!x. x IN s ==> (g(f(x)) = x))
+        ==> !f' g' x. x IN s /\ (f has_derivative f') (at x) /\
+                      linear g' /\ (g' o f' = I)
+                      ==> (g has_derivative g') (at (f(x)))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_INVERSE_BASIC_X THEN
+  EXISTS_TAC `f':real^M->real^N` THEN
+  EXISTS_TAC `IMAGE (f:real^M->real^N) s` THEN
+  ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; IN_IMAGE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Here's the simplest way of not assuming much about g.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_INVERSE = prove
+ (`!f:real^M->real^N g f' g' s x.
+        compact s /\ x IN s /\ f(x) IN interior(IMAGE f s) /\
+        f continuous_on s /\ (!x. x IN s ==> (g(f(x)) = x)) /\
+        (f has_derivative f') (at x) /\ linear g' /\ (g' o f' = I)
+        ==> (g has_derivative g') (at (f(x)))`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_INVERSE_BASIC_X THEN
+  EXISTS_TAC `f':real^M->real^N` THEN
+  EXISTS_TAC `interior(IMAGE (f:real^M->real^N) s)` THEN
+  ASM_MESON_TAC[CONTINUOUS_ON_INTERIOR; CONTINUOUS_ON_INVERSE;
+    OPEN_INTERIOR; IN_IMAGE; INTERIOR_SUBSET; SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Proving surjectivity via Brouwer fixpoint theorem.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let BROUWER_SURJECTIVE = prove
+ (`!f:real^N->real^N s t.
+        compact t /\ convex t /\ ~(t = {}) /\ f continuous_on t /\
+        (!x y. x IN s /\ y IN t ==> x + (y - f(y)) IN t)
+        ==> !x. x IN s ==> ?y. y IN t /\ (f(y) = x)`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH
+   `((f:real^N->real^N)(y) = x) <=> (x + (y - f(y)) = y)`] THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST; CONTINUOUS_ON_SUB;
+               BROUWER; SUBSET; FORALL_IN_IMAGE; CONTINUOUS_ON_ID]);;
+
+let BROUWER_SURJECTIVE_CBALL = prove
+ (`!f:real^N->real^N s a e.
+        &0 < e /\
+        f continuous_on cball(a,e) /\
+        (!x y. x IN s /\ y IN cball(a,e) ==> x + (y - f(y)) IN cball(a,e))
+        ==> !x. x IN s ==> ?y. y IN cball(a,e) /\ (f(y) = x)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC BROUWER_SURJECTIVE THEN
+  ASM_REWRITE_TAC[COMPACT_CBALL; CONVEX_CBALL] THEN
+  ASM_SIMP_TAC[CBALL_EQ_EMPTY; REAL_LT_IMP_LE; REAL_NOT_LT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* See Sussmann: "Multidifferential calculus", Theorem 2.1.1                 *)
+(* ------------------------------------------------------------------------- *)
+
+let SUSSMANN_OPEN_MAPPING = prove
+ (`!f:real^M->real^N f' g' s x.
+        open s /\ f continuous_on s /\
+        x IN s /\ (f has_derivative f') (at x) /\ linear g' /\ (f' o g' = I)
+        ==> !t. t SUBSET s /\ x IN interior(t)
+                ==> f(x) IN interior(IMAGE f t)`,
+  REWRITE_TAC[HAS_DERIVATIVE_AT_ALT] THEN
+  REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(MATCH_MP LINEAR_BOUNDED_POS (ASSUME `linear(g':real^N->real^M)`)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `&1 / (&2 * B)`) THEN
+  ASM_SIMP_TAC[REAL_LT_MUL; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e0:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERIOR_CBALL]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `e1:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPECL [`e0 / B`; `e1 / B`] REAL_DOWN2) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`\y. (f:real^M->real^N)(x + g'(y - f(x)))`;
+    `cball((f:real^M->real^N) x,e / &2)`; `(f:real^M->real^N) x`; `e:real`]
+   BROUWER_SURJECTIVE_CBALL) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
+        REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+        ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        ASM_SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST;
+                     CONTINUOUS_ON_ID; LINEAR_CONTINUOUS_ON];
+        ALL_TAC] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+      EXISTS_TAC `cball(x:real^M,e1)` THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_TRANS]; ALL_TAC] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN X_GEN_TAC `y:real^N` THEN
+      REWRITE_TAC[IN_CBALL; dist] THEN
+      REWRITE_TAC[VECTOR_ARITH `x - (x + y) = --y:real^N`] THEN
+      GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [NORM_SUB] THEN
+      DISCH_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `B * norm(y - (f:real^M->real^N) x)` THEN
+      ASM_REWRITE_TAC[NORM_NEG] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+      ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ] THEN
+      ASM_MESON_TAC[REAL_LE_TRANS; REAL_LT_IMP_LE];
+      ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`y:real^N`; `z:real^N`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x + g'(z - (f:real^M->real^N) x)`) THEN
+    ASM_REWRITE_TAC[VECTOR_ADD_SUB] THEN ANTS_TAC THENL
+     [MATCH_MP_TAC REAL_LET_TRANS THEN
+      EXISTS_TAC `B * norm(z - (f:real^M->real^N) x)` THEN
+      ASM_REWRITE_TAC[NORM_NEG] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+      ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ] THEN
+      ASM_MESON_TAC[IN_CBALL; dist; NORM_SUB; REAL_LET_TRANS];
+      ALL_TAC] THEN
+    REWRITE_TAC[VECTOR_ARITH `a - b - (c - b) = a - c:real^N`] THEN
+    DISCH_TAC THEN REWRITE_TAC[IN_CBALL; dist] THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+     `f0 - (y + z - f1) = (f1 - z) + (f0 - y):real^N`] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+     `norm(f(x + g'(z - (f:real^M->real^N) x)) - z) + norm(f x - y)` THEN
+    REWRITE_TAC[NORM_TRIANGLE] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `x <= a ==> y <= b - a ==> x + y <= b`)) THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `e / &2` THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[IN_CBALL; dist]; ALL_TAC] THEN
+    REWRITE_TAC[REAL_ARITH `e / &2 <= e - x <=> x <= e / &2`] THEN
+    REWRITE_TAC[real_div; REAL_INV_MUL; REAL_MUL_ASSOC] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    SIMP_TAC[REAL_ARITH `(&1 / &2 * b) * x <= e * &1 / &2 <=> x * b <= e`] THEN
+    ASM_SIMP_TAC[GSYM real_div; REAL_LE_LDIV_EQ] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `B * norm(z - (f:real^M->real^N) x)` THEN
+    ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[REAL_LE_LMUL_EQ; REAL_MUL_SYM; IN_CBALL; dist; DIST_SYM];
+    ALL_TAC] THEN
+  REWRITE_TAC[IN_INTERIOR] THEN
+  DISCH_THEN(fun th -> EXISTS_TAC `e / &2` THEN MP_TAC th) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH; SUBSET] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `y:real^N` THEN
+  MATCH_MP_TAC MONO_IMP THEN
+  REWRITE_TAC[REWRITE_RULE[SUBSET] BALL_SUBSET_CBALL] THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real^N` (STRIP_ASSUME_TAC o GSYM)) THEN
+  ASM_REWRITE_TAC[IN_IMAGE] THEN
+  EXISTS_TAC `x + g'(z - (f:real^M->real^N) x)` THEN REWRITE_TAC[] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[SUBSET]) THEN
+  REWRITE_TAC[IN_CBALL; dist; VECTOR_ARITH `x - (x + y) = --y:real^N`] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `B * norm(z - (f:real^M->real^N) x)` THEN
+  ASM_REWRITE_TAC[NORM_NEG] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ] THEN
+  ASM_MESON_TAC[IN_CBALL; dist; NORM_SUB; REAL_LT_IMP_LE; REAL_LE_TRANS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence the following eccentric variant of the inverse function theorem.    *)
+(* This has no continuity assumptions, but we do need the inverse function.  *)
+(* We could put f' o g = I but this happens to fit with the minimal linear   *)
+(* algebra theory I've set up so far.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_INVERSE_STRONG = prove
+ (`!f:real^N->real^N g f' g' s x.
+        open s /\ x IN s /\ f continuous_on s /\
+        (!x. x IN s ==> (g(f(x)) = x)) /\
+        (f has_derivative f') (at x) /\ (f' o g' = I)
+        ==> (g has_derivative g') (at (f(x)))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_INVERSE_BASIC_X THEN
+  SUBGOAL_THEN `linear (g':real^N->real^N) /\ (g' o f' = I)`
+  STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[has_derivative; RIGHT_INVERSE_LINEAR; LINEAR_INVERSE_LEFT];
+    ALL_TAC] THEN
+  EXISTS_TAC `f':real^N->real^N` THEN
+  EXISTS_TAC `interior (IMAGE (f:real^N->real^N) s)` THEN
+  ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[];
+    REWRITE_TAC[OPEN_INTERIOR];
+    ASM_MESON_TAC[INTERIOR_OPEN; SUSSMANN_OPEN_MAPPING; LINEAR_INVERSE_LEFT;
+                  SUBSET_REFL; has_derivative];
+    ASM_MESON_TAC[IN_IMAGE; SUBSET; INTERIOR_SUBSET]] THEN
+  REWRITE_TAC[continuous_at] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `!t. t SUBSET s /\ x IN interior(t)
+        ==> (f:real^N->real^N)(x) IN interior(IMAGE f t)`
+  MP_TAC THENL
+   [ASM_MESON_TAC[SUSSMANN_OPEN_MAPPING; LINEAR_INVERSE_LEFT; has_derivative];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `ball(x:real^N,e) INTER s`) THEN ANTS_TAC THENL
+   [ASM_SIMP_TAC[IN_INTER; OPEN_BALL; INTERIOR_OPEN; OPEN_INTER;
+                 INTER_SUBSET; CENTRE_IN_BALL];
+    ALL_TAC] THEN
+  REWRITE_TAC[IN_INTERIOR] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+  ASM_CASES_TAC `&0 < d` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[SUBSET; IN_BALL; IN_IMAGE; IN_INTER] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `y:real^N` THEN
+  REWRITE_TAC[DIST_SYM] THEN MATCH_MP_TAC MONO_IMP THEN
+  ASM_MESON_TAC[DIST_SYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A rewrite based on the other domain.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_INVERSE_STRONG_X = prove
+ (`!f:real^N->real^N g f' g' s y.
+        open s /\ (g y) IN s /\ f continuous_on s /\
+        (!x. x IN s ==> (g(f(x)) = x)) /\
+        (f has_derivative f') (at (g y)) /\ (f' o g' = I) /\
+        f(g y) = y
+        ==> (g has_derivative g') (at y)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [SYM th]) THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_INVERSE_STRONG THEN
+  MAP_EVERY EXISTS_TAC [`f':real^N->real^N`; `s:real^N->bool`] THEN
+  ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* On a region.                                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_INVERSE_ON = prove
+ (`!f:real^N->real^N s.
+        open s /\
+        (!x. x IN s ==> (f has_derivative f'(x)) (at x) /\ (g(f(x)) = x) /\
+                        (f'(x) o g'(x) = I))
+        ==> !x. x IN s ==> (g has_derivative g'(x)) (at (f(x)))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_INVERSE_STRONG THEN
+  EXISTS_TAC `(f':real^N->real^N->real^N) x` THEN
+  EXISTS_TAC `s:real^N->bool` THEN
+  ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT;
+                DIFFERENTIABLE_IMP_CONTINUOUS_AT; differentiable]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Invertible derivative continous at a point implies local injectivity.     *)
+(* It's only for this we need continuity of the derivative, except of course *)
+(* if we want the fact that the inverse derivative is also continuous. So if *)
+(* we know for some other reason that the inverse function exists, it's OK.  *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_LOCALLY_INJECTIVE = prove
+ (`!f:real^M->real^N f' g' s a.
+        a IN s /\ open s /\ linear g' /\ (g' o f'(a) = I) /\
+        (!x. x IN s ==> (f has_derivative f'(x)) (at x)) /\
+        (!e. &0 < e
+             ==> ?d. &0 < d /\
+                     !x. dist(a,x) < d ==> onorm(\v. f'(x) v - f'(a) v) < e)
+        ==> ?t. a IN t /\ open t /\
+                !x x'. x IN t /\ x' IN t /\ (f x' = f x) ==> (x' = x)`,
+  REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `&0 < onorm(g':real^N->real^M)` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[ONORM_POS_LT] THEN ASM_MESON_TAC[VEC_EQ; ARITH_EQ];
+    ALL_TAC] THEN
+  ABBREV_TAC `k = &1 / onorm(g':real^N->real^M) / &2` THEN
+  SUBGOAL_THEN
+   `?d. &0 < d /\ ball(a,d) SUBSET s /\
+        !x. x IN ball(a,d)
+            ==> onorm(\v. (f':real^M->real^M->real^N)(x) v - f'(a) v) < k`
+  STRIP_ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o SPEC `k:real`) THEN EXPAND_TAC "k" THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_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
+    REWRITE_TAC[SUBSET; IN_BALL] THEN DISCH_THEN(X_CHOOSE_TAC `d2:real`) THEN
+    EXISTS_TAC `min d1 d2` THEN ASM_REWRITE_TAC[REAL_LT_MIN; IN_BALL] THEN
+    ASM_MESON_TAC[REAL_LT_TRANS];
+    ALL_TAC] THEN
+  EXISTS_TAC `ball(a:real^M,d)` THEN
+  ASM_SIMP_TAC[OPEN_BALL; CENTRE_IN_BALL] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `x':real^M`] THEN STRIP_TAC THEN
+  ABBREV_TAC `ph = \w. w - g'(f(w) - (f:real^M->real^N)(x))` THEN
+  SUBGOAL_THEN `norm((ph:real^M->real^M) x' - ph x) <= norm(x' - x) / &2`
+  MP_TAC THENL
+   [ALL_TAC;
+    EXPAND_TAC "ph" THEN ASM_REWRITE_TAC[VECTOR_SUB_REFL] THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP LINEAR_0 th]) THEN
+    ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+    REWRITE_TAC[VECTOR_SUB_RZERO; GSYM NORM_LE_0] THEN REAL_ARITH_TAC] THEN
+  SUBGOAL_THEN
+   `!u v:real^M. u IN ball(a,d) /\ v IN ball(a,d)
+                 ==> norm(ph u - ph v :real^M) <= norm(u - v) / &2`
+   (fun th -> ASM_SIMP_TAC[th]) THEN
+  REWRITE_TAC[real_div] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  MATCH_MP_TAC DIFFERENTIABLE_BOUND THEN
+  REWRITE_TAC[CONVEX_BALL; OPEN_BALL] THEN
+  EXISTS_TAC `\x v. v - g'((f':real^M->real^M->real^N) x v)` THEN
+  CONJ_TAC THEN X_GEN_TAC `u:real^M` THEN DISCH_TAC THEN REWRITE_TAC[] THENL
+   [EXPAND_TAC "ph" THEN
+    MATCH_MP_TAC HAS_DERIVATIVE_SUB THEN REWRITE_TAC[HAS_DERIVATIVE_ID] THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP LINEAR_SUB th]) THEN
+    GEN_REWRITE_TAC (RATOR_CONV o BINDER_CONV) [GSYM VECTOR_SUB_RZERO] THEN
+    MATCH_MP_TAC HAS_DERIVATIVE_SUB THEN REWRITE_TAC[HAS_DERIVATIVE_CONST] THEN
+    ONCE_REWRITE_TAC[GSYM o_DEF] THEN MATCH_MP_TAC DIFF_CHAIN_WITHIN THEN
+    ONCE_REWRITE_TAC[ETA_AX] THEN
+    ASM_MESON_TAC[HAS_DERIVATIVE_LINEAR; SUBSET; HAS_DERIVATIVE_AT_WITHIN];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(\w. w - g'((f':real^M->real^M->real^N) u w)) =
+     g' o (\w. f' a w - f' u w)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[FUN_EQ_THM; o_THM] THEN ASM_MESON_TAC[LINEAR_SUB];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `linear(\w. f' a w - (f':real^M->real^M->real^N) u w)`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC LINEAR_COMPOSE_SUB THEN ONCE_REWRITE_TAC[ETA_AX] THEN
+    ASM_MESON_TAC[has_derivative; SUBSET; CENTRE_IN_BALL];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC
+   `onorm(g':real^N->real^M) *
+    onorm(\w. f' a w - (f':real^M->real^M->real^N) u w)` THEN
+  ASM_SIMP_TAC[ONORM_COMPOSE] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ] THEN
+  REWRITE_TAC[real_div; REAL_ARITH `inv(&2) * x = (&1 * x) * inv(&2)`] THEN
+  ASM_REWRITE_TAC[GSYM real_div] THEN
+  SUBGOAL_THEN `onorm(\w. (f':real^M->real^M->real^N) a w - f' u w) =
+                onorm(\w. f' u w - f' a w)`
+   (fun th -> ASM_SIMP_TAC[th; REAL_LT_IMP_LE]) THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [GSYM VECTOR_NEG_SUB] THEN
+  MATCH_MP_TAC ONORM_NEG THEN ONCE_REWRITE_TAC[GSYM VECTOR_NEG_SUB] THEN
+  ASM_SIMP_TAC[LINEAR_COMPOSE_NEG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Uniformly convergent sequence of derivatives.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_SEQUENCE_LIPSCHITZ = prove
+ (`!s f:num->real^M->real^N f' g'.
+        convex s /\
+        (!n x. x IN s ==> ((f n) has_derivative (f' n x)) (at x within s)) /\
+        (!e. &0 < e
+             ==> ?N. !n x h. n >= N /\ x IN s
+                             ==> norm(f' n x h - g' x h) <= e * norm(h))
+        ==> !e. &0 < e
+                ==> ?N. !m n x y. m >= N /\ n >= N /\ x IN s /\ y IN s
+                                  ==> norm((f m x - f n x) - (f m y - f n y))
+                                      <= e * norm(x - y)`,
+  REPEAT STRIP_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 DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN
+  ASM_CASES_TAC `m:num >= N` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `n:num >= N` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC DIFFERENTIABLE_BOUND THEN
+  EXISTS_TAC `\x h. (f':num->real^M->real^M->real^N) m x h - f' n x h` THEN
+  ASM_SIMP_TAC[HAS_DERIVATIVE_SUB; ETA_AX] THEN
+  X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `!h. norm((f':num->real^M->real^M->real^N) m x h - f' n x h) <= e * norm(h)`
+  MP_TAC THEN RULE_ASSUM_TAC(REWRITE_RULE[HAS_DERIVATIVE_WITHIN_ALT]) THEN
+  ASM_SIMP_TAC[ONORM; LINEAR_COMPOSE_SUB; ETA_AX] THEN
+  X_GEN_TAC `h:real^M` THEN SUBST1_TAC(VECTOR_ARITH
+   `(f':num->real^M->real^M->real^N) m x h - f' n x h =
+    (f' m x h - g' x h) + --(f' n x h - g' x h)`) THEN
+  MATCH_MP_TAC NORM_TRIANGLE_LE THEN
+  ASM_SIMP_TAC[NORM_NEG; REAL_ARITH
+   `a <= e / &2 * h /\ b <= e / &2 * h ==> a + b <= e * h`]);;
+
+let HAS_DERIVATIVE_SEQUENCE = prove
+ (`!s f:num->real^M->real^N f' g'.
+        convex s /\
+        (!n x. x IN s ==> ((f n) has_derivative (f' n x)) (at x within s)) /\
+        (!e. &0 < e
+             ==> ?N. !n x h. n >= N /\ x IN s
+                             ==> norm(f' n x h - g' x h) <= e * norm(h)) /\
+        (?x l. x IN s /\ ((\n. f n x) --> l) sequentially)
+        ==> ?g. !x. x IN s
+                    ==> ((\n. f n x) --> g x) sequentially /\
+                        (g has_derivative g'(x)) (at x within s)`,
+  REPEAT GEN_TAC THEN
+  REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "O") MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `x0:real^M` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_TAC "A"
+   `!e. &0 < e
+        ==> ?N. !m n x y. m >= N /\ n >= N /\ x IN s /\ y IN s
+                          ==> norm(((f:num->real^M->real^N) m x - f n x) -
+                                   (f m y - f n y))
+                               <= e * norm(x - y)`
+   [MATCH_MP_TAC HAS_DERIVATIVE_SEQUENCE_LIPSCHITZ THEN
+    ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]] THEN
+  SUBGOAL_THEN
+   `?g:real^M->real^N. !x. x IN s ==> ((\n. f n x) --> g x) sequentially`
+  MP_TAC THENL
+   [REWRITE_TAC[GSYM SKOLEM_THM; RIGHT_EXISTS_IMP_THM] THEN
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    GEN_REWRITE_TAC I [CONVERGENT_EQ_CAUCHY] THEN
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP CONVERGENT_IMP_CAUCHY) THEN
+    REWRITE_TAC[cauchy; dist] THEN DISCH_THEN(LABEL_TAC "B") THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `x:real^M = x0` THEN ASM_SIMP_TAC[] THEN
+    REMOVE_THEN "B" (MP_TAC o SPEC `e / &2`) THEN
+    ASM_REWRITE_TAC[REAL_HALF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `N1:num` STRIP_ASSUME_TAC) THEN
+    REMOVE_THEN "A" (MP_TAC o SPEC `e / &2 / norm(x - x0:real^M)`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; REAL_HALF; VECTOR_SUB_EQ] THEN
+    DISCH_THEN(X_CHOOSE_TAC `N2:num`) THEN
+    EXISTS_TAC `N1 + N2:num` THEN REPEAT GEN_TAC THEN
+    DISCH_THEN(CONJUNCTS_THEN (STRIP_ASSUME_TAC o MATCH_MP
+      (ARITH_RULE `m >= N1 + N2:num ==> m >= N1 /\ m >= N2`))) THEN
+    SUBST1_TAC(VECTOR_ARITH
+     `(f:num->real^M->real^N) m x - f n x =
+      (f m x - f n x - (f m x0 - f n x0)) + (f m x0 - f n x0)`) THEN
+    MATCH_MP_TAC NORM_TRIANGLE_LT THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+      [`m:num`; `n:num`; `x:real^M`; `x0:real^M`]) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`m:num`; `n:num`]) THEN
+    ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN SIMP_TAC[] THEN
+  DISCH_THEN(LABEL_TAC "B") THEN X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+  REWRITE_TAC[HAS_DERIVATIVE_WITHIN_ALT] THEN
+  SUBGOAL_TAC "C"
+   `!e. &0 < e
+        ==> ?N. !n x y. n >= N /\ x IN s /\ y IN s
+                        ==> norm(((f:num->real^M->real^N) n x - f n y) -
+                                 (g x - g y))
+                             <= e * norm(x - y)`
+   [X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    REMOVE_THEN "A" (MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `n:num` THEN
+    DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`u:real^M`; `v:real^M`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN `m:num` o SPECL
+      [`m:num`; `u:real^M`; `v:real^M`]) THEN
+    DISCH_TAC THEN MATCH_MP_TAC(ISPEC `sequentially` LIM_NORM_UBOUND) THEN
+    EXISTS_TAC
+      `\m. ((f:num->real^M->real^N) n u - f n v) - (f m u - f m v)` THEN
+    REWRITE_TAC[eventually; TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+    ASM_SIMP_TAC[SEQUENTIALLY; LIM_SUB; LIM_CONST] THEN EXISTS_TAC `N:num` THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+     `(x - y) - (u - v) = (x - u) - (y -  v):real^N`] THEN
+    ASM_MESON_TAC[GE_REFL]] THEN
+  CONJ_TAC THENL
+   [SUBGOAL_TAC "D"
+    `!u. ((\n. (f':num->real^M->real^M->real^N) n x u) --> g' x u) sequentially`
+     [REWRITE_TAC[LIM_SEQUENTIALLY; dist] THEN REPEAT STRIP_TAC THEN
+      ASM_CASES_TAC `u = vec 0:real^M` THENL
+       [REMOVE_THEN "O" (MP_TAC o SPEC `e:real`);
+        REMOVE_THEN "O" (MP_TAC o SPEC `e / &2 / norm(u:real^M)`)] THEN
+      ASM_SIMP_TAC[NORM_POS_LT; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+      MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+      DISCH_THEN(MP_TAC o SPECL [`x:real^M`; `u:real^M`]) THEN
+      DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+      ASM_SIMP_TAC[GE; NORM_0; REAL_MUL_RZERO; NORM_LE_0] THEN
+      ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0] THEN
+      UNDISCH_TAC `&0 < e` THEN REAL_ARITH_TAC] THEN
+    REWRITE_TAC[linear] THEN ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+    CONJ_TAC THENL
+     [MAP_EVERY X_GEN_TAC [`u:real^M`; `v:real^M`];
+      MAP_EVERY X_GEN_TAC [`c:real`; `u:real^M`]] THEN
+    MATCH_MP_TAC(ISPEC `sequentially` LIM_UNIQUE) THENL
+     [EXISTS_TAC
+       `\n. (f':num->real^M->real^M->real^N) n x (u + v) -
+            (f' n x u + f' n x v)`;
+      EXISTS_TAC
+       `\n. (f':num->real^M->real^M->real^N) n x (c % u) -
+            c % f' n x u`] THEN
+    ASM_SIMP_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; LIM_SUB; LIM_ADD; LIM_CMUL] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[has_derivative_within; linear]) THEN
+    ASM_SIMP_TAC[VECTOR_SUB_REFL; LIM_CONST];
+    ALL_TAC] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MAP_EVERY (fun s -> REMOVE_THEN s (MP_TAC o SPEC `e / &3`)) ["C"; "O"] THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N1:num` (LABEL_TAC "C")) THEN
+  DISCH_THEN(X_CHOOSE_THEN `N2:num` (LABEL_TAC "A")) THEN
+  REMOVE_THEN "C" (MP_TAC o GEN `y:real^M` o
+   SPECL [`N1 + N2:num`; `x:real^M`; `y - x:real^M`]) THEN
+  REMOVE_THEN "A" (MP_TAC o GEN `y:real^M` o
+   SPECL [`N1 + N2:num`; `y:real^M`; `x:real^M`]) THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`N1 + N2:num`; `x:real^M`]) THEN
+  ASM_REWRITE_TAC[ARITH_RULE `m + n >= m:num /\ m + n >= n`] THEN
+  REWRITE_TAC[HAS_DERIVATIVE_WITHIN_ALT] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &3` o CONJUNCT2) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(LABEL_TAC "D1") THEN DISCH_THEN(LABEL_TAC "D2") THEN
+  EXISTS_TAC `d1:real` THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `y:real^M` THEN
+  DISCH_TAC THEN REMOVE_THEN "D2" (MP_TAC o SPEC `y:real^M`) THEN
+  REMOVE_THEN "D1" (MP_TAC o SPEC `y:real^M`) THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[REAL_LT_TRANS; NORM_SUB]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `y:real^M`) THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[REAL_LT_TRANS; NORM_SUB]; ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `d <= a + b + c
+    ==> a <= e / &3 * n ==> b <= e / &3 * n ==> c <= e / &3 * n
+        ==> d <= e * n`) THEN
+  GEN_REWRITE_TAC (funpow 2 RAND_CONV o LAND_CONV) [NORM_SUB] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `(norm(x + y + z) = norm(a)) /\
+    norm(x + y + z) <= norm(x) + norm(y + z) /\
+    norm(y + z) <= norm(y) + norm(z)
+    ==> norm(a) <= norm(x) + norm(y) + norm(z)`) THEN
+  REWRITE_TAC[NORM_TRIANGLE] THEN AP_TERM_TAC THEN VECTOR_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Can choose to line up antiderivatives if we want.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_ANTIDERIVATIVE_SEQUENCE = prove
+ (`!s f:num->real^M->real^N f' g'.
+        convex s /\
+        (!n x. x IN s ==> ((f n) has_derivative (f' n x)) (at x within s)) /\
+        (!e. &0 < e
+             ==> ?N. !n x h. n >= N /\ x IN s
+                             ==> norm(f' n x h - g' x h) <= e * norm(h))
+        ==> ?g. !x. x IN s ==> (g has_derivative g'(x)) (at x within s)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `(s:real^M->bool) = {}` THEN
+  ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^M`) THEN
+  MP_TAC(ISPECL
+       [`s:real^M->bool`;
+        `\n x. (f:num->real^M->real^N) n x + (f 0 a -  f n a)`;
+        `f':num->real^M->real^M->real^N`;
+        `g':real^M->real^M->real^N`]
+      HAS_DERIVATIVE_SEQUENCE) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+  CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `(f':num->real^M->real^M->real^N) n x =
+                  \h. f' n x h + vec 0`
+    SUBST1_TAC THENL [SIMP_TAC[FUN_EQ_THM] THEN VECTOR_ARITH_TAC; ALL_TAC] THEN
+    MATCH_MP_TAC HAS_DERIVATIVE_ADD THEN
+    ASM_SIMP_TAC[HAS_DERIVATIVE_CONST; ETA_AX];
+    MAP_EVERY EXISTS_TAC [`a:real^M`; `f 0 (a:real^M) :real^N`] THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH `a + b - a = b:real^N`; LIM_CONST]]);;
+
+let HAS_ANTIDERIVATIVE_LIMIT = prove
+ (`!s g':real^M->real^M->real^N.
+        convex s /\
+        (!e. &0 < e
+             ==> ?f f'. !x. x IN s
+                            ==> (f has_derivative (f' x)) (at x within s) /\
+                                (!h. norm(f' x h - g' x h) <= e * norm(h)))
+        ==> ?g. !x. x IN s ==> (g has_derivative g'(x)) (at x within s)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN `n:num` o SPEC `inv(&n + &1)`) THEN
+  REWRITE_TAC[REAL_LT_INV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+  REWRITE_TAC[SKOLEM_THM] THEN DISCH_TAC THEN
+  MATCH_MP_TAC HAS_ANTIDERIVATIVE_SEQUENCE THEN
+  UNDISCH_TAC `convex(s:real^M->bool)` THEN SIMP_TAC[] THEN
+  DISCH_THEN(K ALL_TAC) THEN POP_ASSUM MP_TAC THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:num->real^M->real^N` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f':num->real^M->real^M->real^N` THEN
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REAL_ARCH_INV]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN STRIP_TAC THEN
+  X_GEN_TAC `n:num` THEN REWRITE_TAC[GE] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `h:real^M`] THEN STRIP_TAC THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `inv(&n + &1) * norm(h:real^M)` THEN
+  ASM_SIMP_TAC[] THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+  REWRITE_TAC[NORM_POS_LE] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `inv(&N)` THEN ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+  MATCH_MP_TAC REAL_LE_INV2 THEN
+  REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+  ASM_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Differentiation of a series.                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_SERIES = prove
+ (`!s f:num->real^M->real^N f' g' k.
+        convex s /\
+        (!n x. x IN s ==> ((f n) has_derivative (f' n x)) (at x within s)) /\
+        (!e. &0 < e
+             ==> ?N. !n x h. n >= N /\ x IN s
+                             ==> norm(vsum(k INTER (0..n)) (\i. f' i x h) -
+                                      g' x h) <= e * norm(h)) /\
+        (?x l. x IN s /\ ((\n. f n x) sums l) k)
+        ==> ?g. !x. x IN s ==> ((\n. f n x) sums (g x)) k /\
+                               (g has_derivative g'(x)) (at x within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[sums] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_SEQUENCE THEN EXISTS_TAC
+   `\n:num x:real^M h:real^M. vsum(k INTER (0..n)) (\n. f' n x h):real^N` THEN
+  ASM_SIMP_TAC[ETA_AX; FINITE_INTER_NUMSEG; HAS_DERIVATIVE_VSUM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Derivative with composed bilinear function.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_BILINEAR_WITHIN = prove
+ (`!h:real^M->real^N->real^P f g f' g' x:real^Q s.
+        (f has_derivative f') (at x within s) /\
+        (g has_derivative g') (at x within s) /\
+        bilinear h
+        ==> ((\x. h (f x) (g x)) has_derivative
+             (\d. h (f x) (g' d) + h (f' d) (g x))) (at x within s)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_TAC "contg" `((g:real^Q->real^N) --> g(x)) (at x within s)`
+   [REWRITE_TAC[GSYM CONTINUOUS_WITHIN] THEN
+    ASM_MESON_TAC[differentiable; DIFFERENTIABLE_IMP_CONTINUOUS_WITHIN]] THEN
+  UNDISCH_TAC `((f:real^Q->real^M) has_derivative f') (at x within s)` THEN
+  REWRITE_TAC[has_derivative_within] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "df")) THEN
+  SUBGOAL_TAC "contf"
+   `((\y. (f:real^Q->real^M)(x) + f'(y - x)) --> f(x)) (at x within s)`
+   [GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_ADD_RID] THEN
+    MATCH_MP_TAC LIM_ADD THEN REWRITE_TAC[LIM_CONST] THEN
+    SUBGOAL_THEN `vec 0 = (f':real^Q->real^M)(x - x)` SUBST1_TAC THENL
+     [ASM_MESON_TAC[LINEAR_0; VECTOR_SUB_REFL]; ALL_TAC] THEN
+    ASM_SIMP_TAC[LIM_LINEAR; LIM_SUB; LIM_CONST; LIM_WITHIN_ID]] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [has_derivative_within]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "dg")) THEN
+  CONJ_TAC THENL
+   [FIRST_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [bilinear]) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[linear]) THEN ASM_REWRITE_TAC[linear] THEN
+    REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`at (x:real^Q) within s`; `h:real^M->real^N->real^P`]
+         LIM_BILINEAR) THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+  REMOVE_THEN "contg" MP_TAC THEN REMOVE_THEN "df" MP_TAC THEN
+  REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN
+  REMOVE_THEN "dg" MP_TAC THEN REMOVE_THEN "contf" MP_TAC THEN
+  ONCE_REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN
+  REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP LIM_ADD) THEN
+  SUBGOAL_THEN
+   `((\y:real^Q. inv(norm(y - x)) %
+                 (h:real^M->real^N->real^P) (f'(y - x)) (g'(y - x)))
+    --> vec 0) (at x within s)`
+  MP_TAC THENL
+   [FIRST_ASSUM(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC o MATCH_MP
+                BILINEAR_BOUNDED_POS) THEN
+    X_CHOOSE_THEN `C:real` STRIP_ASSUME_TAC
+     (MATCH_MP LINEAR_BOUNDED_POS (ASSUME `linear (f':real^Q->real^M)`)) THEN
+    X_CHOOSE_THEN `D:real` STRIP_ASSUME_TAC
+     (MATCH_MP LINEAR_BOUNDED_POS (ASSUME `linear (g':real^Q->real^N)`)) THEN
+    REWRITE_TAC[LIM_WITHIN; dist; VECTOR_SUB_RZERO] THEN
+    X_GEN_TAC `e:real` THEN STRIP_TAC THEN EXISTS_TAC `e / (B * C * D)` THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; NORM_MUL; REAL_LT_MUL] THEN
+    X_GEN_TAC `x':real^Q` THEN
+    REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_NORM; REAL_ABS_INV] THEN
+    STRIP_TAC THEN MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `inv(norm(x' - x :real^Q)) *
+                B * (C * norm(x' - x)) * (D * norm(x' - x))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_LE_LMUL THEN SIMP_TAC[REAL_LE_INV_EQ; NORM_POS_LE] THEN
+      ASM_MESON_TAC[REAL_LE_LMUL; REAL_LT_IMP_LE; REAL_LE_MUL2; NORM_POS_LE;
+                    REAL_LE_TRANS];
+      ONCE_REWRITE_TAC[AC REAL_MUL_AC
+       `i * b * (c * x) * (d * x) = (i * x) * x * (b * c * d)`] THEN
+      ASM_SIMP_TAC[REAL_MUL_LINV; REAL_LT_IMP_NZ; REAL_MUL_LID] THEN
+      ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_LT_MUL]];
+    REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP LIM_ADD) THEN
+    REWRITE_TAC (map (C MATCH_MP (ASSUME `bilinear(h:real^M->real^N->real^P)`))
+     [BILINEAR_RZERO; BILINEAR_LZERO; BILINEAR_LADD; BILINEAR_RADD;
+      BILINEAR_LMUL; BILINEAR_RMUL; BILINEAR_LSUB; BILINEAR_RSUB]) THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN
+    BINOP_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN VECTOR_ARITH_TAC]);;
+
+let HAS_DERIVATIVE_BILINEAR_AT = prove
+ (`!h:real^M->real^N->real^P f g f' g' x:real^Q.
+        (f has_derivative f') (at x) /\
+        (g has_derivative g') (at x) /\
+        bilinear h
+        ==> ((\x. h (f x) (g x)) has_derivative
+             (\d. h (f x) (g' d) + h (f' d) (g x))) (at x)`,
+  REWRITE_TAC[has_derivative_at] THEN
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[GSYM has_derivative_within; HAS_DERIVATIVE_BILINEAR_WITHIN]);;
+
+let BILINEAR_DIFFERENTIABLE_AT_COMPOSE = prove
+ (`!f:real^M->real^N g:real^M->real^P h:real^N->real^P->real^Q a.
+        f differentiable at a /\ g differentiable at a /\ bilinear h
+        ==> (\x. h (f x) (g x)) differentiable at a`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[FRECHET_DERIVATIVE_WORKS] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_DERIVATIVE_BILINEAR_AT) THEN
+  REWRITE_TAC[GSYM FRECHET_DERIVATIVE_WORKS; differentiable] THEN
+  MESON_TAC[]);;
+
+let BILINEAR_DIFFERENTIABLE_WITHIN_COMPOSE = prove
+ (`!f:real^M->real^N g:real^M->real^P h:real^N->real^P->real^Q x s.
+        f differentiable at x within s /\ g differentiable at x within s /\
+        bilinear h
+        ==> (\x. h (f x) (g x)) differentiable at x within s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[FRECHET_DERIVATIVE_WORKS] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_DERIVATIVE_BILINEAR_WITHIN) THEN
+  REWRITE_TAC[GSYM FRECHET_DERIVATIVE_WORKS; differentiable] THEN
+  MESON_TAC[]);;
+
+let BILINEAR_DIFFERENTIABLE_ON_COMPOSE = prove
+ (`!f:real^M->real^N g:real^M->real^P h:real^N->real^P->real^Q s.
+        f differentiable_on s /\ g differentiable_on s /\ bilinear h
+        ==> (\x. h (f x) (g x)) differentiable_on s`,
+  REWRITE_TAC[differentiable_on] THEN
+  MESON_TAC[BILINEAR_DIFFERENTIABLE_WITHIN_COMPOSE]);;
+
+let DIFFERENTIABLE_AT_LIFT_DOT2 = prove
+ (`!f:real^M->real^N g x.
+        f differentiable at x /\ g differentiable at x
+        ==> (\x. lift(f x dot g x)) differentiable at x`,
+  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_DIFFERENTIABLE_AT_COMPOSE) BILINEAR_DOT)) THEN REWRITE_TAC[]);;
+
+let DIFFERENTIABLE_WITHIN_LIFT_DOT2 = prove
+ (`!f:real^M->real^N g x s.
+        f differentiable (at x within s) /\ g differentiable (at x within s)
+        ==> (\x. lift(f x dot g x)) differentiable (at x within 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_DIFFERENTIABLE_WITHIN_COMPOSE) BILINEAR_DOT)) THEN REWRITE_TAC[]);;
+
+let DIFFERENTIABLE_ON_LIFT_DOT2 = prove
+ (`!f:real^M->real^N g s.
+        f differentiable_on s /\ g differentiable_on s
+        ==> (\x. lift(f x dot g x)) differentiable_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_DIFFERENTIABLE_ON_COMPOSE) BILINEAR_DOT)) THEN REWRITE_TAC[]);;
+
+let HAS_DERIVATIVE_MUL_WITHIN = prove
+ (`!f f' g:real^M->real^N g' a s.
+        ((lift o f) has_derivative (lift o f')) (at a within s) /\
+        (g has_derivative g') (at a within s)
+        ==> ((\x. f x % g x) has_derivative
+             (\h. f a % g' h + f' h % g a)) (at a within s)`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[BILINEAR_DROP_MUL]
+   (ISPEC `\x y:real^M. drop x % y` HAS_DERIVATIVE_BILINEAR_WITHIN))) THEN
+  REWRITE_TAC[o_DEF; DROP_CMUL; LIFT_DROP]);;
+
+let HAS_DERIVATIVE_MUL_AT = prove
+ (`!f f' g:real^M->real^N g' a.
+        ((lift o f) has_derivative (lift o f')) (at a) /\
+        (g has_derivative g') (at a)
+        ==> ((\x. f x % g x) has_derivative
+             (\h. f a % g' h + f' h % g a)) (at a)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[HAS_DERIVATIVE_MUL_WITHIN]);;
+
+let HAS_DERIVATIVE_SQNORM_AT = prove
+ (`!a:real^N.
+    ((\x. lift(norm x pow 2)) has_derivative (\x. &2 % lift(a dot x))) (at a)`,
+  GEN_TAC THEN MP_TAC(ISPECL
+   [`\x y:real^N. lift(x dot y)`;
+    `\x:real^N. x`; `\x:real^N. x`; `\x:real^N. x`; `\x:real^N. x`;
+    `a:real^N`] HAS_DERIVATIVE_BILINEAR_AT) THEN
+  REWRITE_TAC[HAS_DERIVATIVE_ID; BILINEAR_DOT; NORM_POW_2] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; DOT_SYM] THEN VECTOR_ARITH_TAC);;
+
+let DIFFERENTIABLE_MUL_WITHIN = prove
+ (`!f g:real^M->real^N a s.
+        (lift o f) differentiable (at a within s) /\
+        g differentiable (at a within s)
+        ==> (\x. f x % g x) differentiable (at a within s)`,
+  REPEAT GEN_TAC THEN MP_TAC(ISPECL
+   [`lift o (f:real^M->real)`; `g:real^M->real^N`; `\x y:real^N. drop x % y`;
+    `a:real^M`; `s:real^M->bool`] BILINEAR_DIFFERENTIABLE_WITHIN_COMPOSE) THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP; BILINEAR_DROP_MUL]);;
+
+let DIFFERENTIABLE_MUL_AT = prove
+ (`!f g:real^M->real^N a.
+        (lift o f) differentiable (at a) /\ g differentiable (at a)
+        ==> (\x. f x % g x) differentiable (at a)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[DIFFERENTIABLE_MUL_WITHIN]);;
+
+let DIFFERENTIABLE_SQNORM_AT = prove
+ (`!a:real^N. (\x. lift(norm x pow 2)) differentiable (at a)`,
+  REWRITE_TAC[differentiable] THEN MESON_TAC[HAS_DERIVATIVE_SQNORM_AT]);;
+
+let DIFFERENTIABLE_ON_MUL = prove
+ (`!f g:real^M->real^N s.
+        (lift o f) differentiable_on s /\ g differentiable_on s
+        ==> (\x. f x % g x) differentiable_on s`,
+  REPEAT GEN_TAC THEN MP_TAC(ISPECL
+   [`lift o (f:real^M->real)`; `g:real^M->real^N`; `\x y:real^N. drop x % y`;
+    `s:real^M->bool`] BILINEAR_DIFFERENTIABLE_ON_COMPOSE) THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP; BILINEAR_DROP_MUL]);;
+
+let DIFFERENTIABLE_ON_SQNORM = prove
+ (`!s:real^N->bool. (\x. lift(norm x pow 2)) differentiable_on s`,
+  SIMP_TAC[DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON;
+            DIFFERENTIABLE_SQNORM_AT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Considering derivative R(^1)->R^n as a vector.                            *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix ("has_vector_derivative",(12,"right"));;
+
+let has_vector_derivative = new_definition
+ `(f has_vector_derivative f') net <=>
+        (f has_derivative (\x. drop(x) % f')) net`;;
+
+let vector_derivative = new_definition
+ `vector_derivative (f:real^1->real^N) net =
+        @f'. (f has_vector_derivative f') net`;;
+
+let VECTOR_DERIVATIVE_WORKS = prove
+ (`!net f:real^1->real^N.
+        f differentiable net <=>
+        (f has_vector_derivative (vector_derivative f net)) net`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[vector_derivative] THEN
+  CONV_TAC(RAND_CONV SELECT_CONV) THEN
+  SIMP_TAC[FRECHET_DERIVATIVE_WORKS; has_vector_derivative] THEN EQ_TAC THENL
+   [ALL_TAC; MESON_TAC[FRECHET_DERIVATIVE_WORKS; differentiable]] THEN
+  DISCH_TAC THEN EXISTS_TAC `column 1 (jacobian (f:real^1->real^N) net)` THEN
+  FIRST_ASSUM MP_TAC THEN MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN
+  AP_TERM_TAC THEN REWRITE_TAC[jacobian] THEN
+  MATCH_MP_TAC LINEAR_FROM_REALS THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[has_derivative]) THEN ASM_REWRITE_TAC[]);;
+
+let VECTOR_DERIVATIVE_UNIQUE_AT = prove
+ (`!f:real^1->real^N x f' f''.
+     (f has_vector_derivative f') (at x) /\
+     (f has_vector_derivative f'') (at x)
+     ==> f' = f''`,
+  REWRITE_TAC[has_vector_derivative; drop] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^1->real^N`;
+                 `\x. drop x % (f':real^N)`; `\x. drop x % (f'':real^N)`;
+                `x:real^1`] FRECHET_DERIVATIVE_UNIQUE_AT) THEN
+  ASM_SIMP_TAC[DIMINDEX_1; LE_ANTISYM; drop] THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN DISCH_THEN(MP_TAC o SPEC `vec 1:real^1`) THEN
+  SIMP_TAC[VEC_COMPONENT; DIMINDEX_1; ARITH; VECTOR_MUL_LID]);;
+
+let HAS_VECTOR_DERIVATIVE_UNIQUE_AT = prove
+ (`!f:real^1->real^N f' x.
+        (f has_vector_derivative f') (at x)
+        ==> vector_derivative f (at x) = f'`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC VECTOR_DERIVATIVE_UNIQUE_AT THEN
+  MAP_EVERY EXISTS_TAC [`f:real^1->real^N`; `x:real^1`] THEN
+  ASM_REWRITE_TAC[vector_derivative] THEN CONV_TAC SELECT_CONV THEN
+  ASM_MESON_TAC[]);;
+
+let VECTOR_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL = prove
+ (`!f:real^1->real^N a b x f' f''.
+        drop a < drop b /\
+        x IN interval [a,b] /\
+        (f has_vector_derivative f') (at x within interval [a,b]) /\
+        (f has_vector_derivative f'') (at x within interval [a,b])
+        ==> f' = f''`,
+  REWRITE_TAC[has_vector_derivative; drop] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^1->real^N`;
+                 `\x. drop x % (f':real^N)`; `\x. drop x % (f'':real^N)`;
+                `x:real^1`; `a:real^1`; `b:real^1`]
+         FRECHET_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL) THEN
+  ASM_SIMP_TAC[DIMINDEX_1; LE_ANTISYM; drop] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN REWRITE_TAC[FUN_EQ_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `vec 1:real^1`) THEN
+  SIMP_TAC[VEC_COMPONENT; DIMINDEX_1; ARITH; VECTOR_MUL_LID]);;
+
+let VECTOR_DERIVATIVE_AT = prove
+ (`(f has_vector_derivative f') (at x) ==> vector_derivative f (at x) = f'`,
+  ASM_MESON_TAC[VECTOR_DERIVATIVE_UNIQUE_AT;
+  VECTOR_DERIVATIVE_WORKS; differentiable; has_vector_derivative]);;
+
+let VECTOR_DERIVATIVE_WITHIN_CLOSED_INTERVAL = prove
+ (`!f:real^1->real^N f' x a b.
+         drop a < drop b /\ x IN interval[a,b] /\
+         (f has_vector_derivative f') (at x within interval [a,b])
+         ==> vector_derivative f (at x within interval [a,b]) = f'`,
+  ASM_MESON_TAC[VECTOR_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL;
+    VECTOR_DERIVATIVE_WORKS; differentiable; has_vector_derivative]);;
+
+let HAS_VECTOR_DERIVATIVE_WITHIN_SUBSET = prove
+ (`!f s t x. (f has_vector_derivative f') (at x within s) /\ t SUBSET s
+             ==> (f has_vector_derivative f') (at x within t)`,
+  REWRITE_TAC[has_vector_derivative; HAS_DERIVATIVE_WITHIN_SUBSET]);;
+
+let HAS_VECTOR_DERIVATIVE_CONST = prove
+ (`!c net. ((\x. c) has_vector_derivative vec 0) net`,
+  REWRITE_TAC[has_vector_derivative] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; HAS_DERIVATIVE_CONST]);;
+
+let VECTOR_DERIVATIVE_CONST_AT = prove
+ (`!c:real^N a. vector_derivative (\x. c) (at a) = vec 0`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_UNIQUE_AT THEN
+  REWRITE_TAC[HAS_VECTOR_DERIVATIVE_CONST]);;
+
+let HAS_VECTOR_DERIVATIVE_ID = prove
+ (`!net. ((\x. x) has_vector_derivative (vec 1)) net`,
+  REWRITE_TAC[has_vector_derivative] THEN
+  SUBGOAL_THEN `(\x. drop x % vec 1) = (\x. x)`
+   (fun th -> REWRITE_TAC[HAS_DERIVATIVE_ID; th]) THEN
+  REWRITE_TAC[FUN_EQ_THM; GSYM DROP_EQ; DROP_CMUL; DROP_VEC] THEN
+  REAL_ARITH_TAC);;
+
+let HAS_VECTOR_DERIVATIVE_CMUL = prove
+ (`!f f' net c. (f has_vector_derivative f') net
+                ==> ((\x. c % f(x)) has_vector_derivative (c % f')) net`,
+  SIMP_TAC[has_vector_derivative] THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `a % b % x = b % a % x`] THEN
+  SIMP_TAC[HAS_DERIVATIVE_CMUL]);;
+
+let HAS_VECTOR_DERIVATIVE_CMUL_EQ = prove
+ (`!f f' net c.
+       ~(c = &0)
+       ==> (((\x. c % f(x)) has_vector_derivative (c % f')) net <=>
+            (f has_vector_derivative f') net)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_VECTOR_DERIVATIVE_CMUL) THENL
+   [DISCH_THEN(MP_TAC o SPEC `inv(c):real`);
+    DISCH_THEN(MP_TAC o SPEC `c:real`)] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; VECTOR_MUL_LID; ETA_AX]);;
+
+let HAS_VECTOR_DERIVATIVE_NEG = prove
+ (`!f f' net. (f has_vector_derivative f') net
+            ==> ((\x. --(f(x))) has_vector_derivative (--f')) net`,
+  SIMP_TAC[has_vector_derivative; VECTOR_MUL_RNEG; HAS_DERIVATIVE_NEG]);;
+
+let HAS_VECTOR_DERIVATIVE_NEG_EQ = prove
+ (`!f f' net. ((\x. --(f(x))) has_vector_derivative --f') net <=>
+              (f has_vector_derivative f') net`,
+  SIMP_TAC[has_vector_derivative; HAS_DERIVATIVE_NEG_EQ; VECTOR_MUL_RNEG]);;
+
+let HAS_VECTOR_DERIVATIVE_ADD = prove
+ (`!f f' g g' net.
+        (f has_vector_derivative f') net /\ (g has_vector_derivative g') net
+        ==> ((\x. f(x) + g(x)) has_vector_derivative (f' + g')) net`,
+  SIMP_TAC[has_vector_derivative; VECTOR_ADD_LDISTRIB; HAS_DERIVATIVE_ADD]);;
+
+let HAS_VECTOR_DERIVATIVE_SUB = prove
+ (`!f f' g g' net.
+        (f has_vector_derivative f') net /\ (g has_vector_derivative g') net
+        ==> ((\x. f(x) - g(x)) has_vector_derivative (f' - g')) net`,
+  SIMP_TAC[has_vector_derivative; VECTOR_SUB_LDISTRIB; HAS_DERIVATIVE_SUB]);;
+
+let HAS_VECTOR_DERIVATIVE_BILINEAR_WITHIN = prove
+ (`!h:real^M->real^N->real^P f g f' g' x s.
+        (f has_vector_derivative f') (at x within s) /\
+        (g has_vector_derivative g') (at x within s) /\
+        bilinear h
+        ==> ((\x. h (f x) (g x)) has_vector_derivative
+             (h (f x) g' + h f' (g x))) (at x within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_vector_derivative] THEN
+  DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HAS_DERIVATIVE_BILINEAR_WITHIN) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[bilinear; linear]) THEN
+  ASM_REWRITE_TAC[VECTOR_ADD_LDISTRIB]);;
+
+let HAS_VECTOR_DERIVATIVE_BILINEAR_AT = prove
+ (`!h:real^M->real^N->real^P f g f' g' x.
+        (f has_vector_derivative f') (at x) /\
+        (g has_vector_derivative g') (at x) /\
+        bilinear h
+        ==> ((\x. h (f x) (g x)) has_vector_derivative
+             (h (f x) g' + h f' (g x))) (at x)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_vector_derivative] THEN
+  DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HAS_DERIVATIVE_BILINEAR_AT) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[bilinear; linear]) THEN
+  ASM_REWRITE_TAC[VECTOR_ADD_LDISTRIB]);;
+
+let HAS_VECTOR_DERIVATIVE_AT_WITHIN = prove
+ (`!f x s. (f has_vector_derivative f') (at x)
+           ==> (f has_vector_derivative f') (at x within s)`,
+  SIMP_TAC[has_vector_derivative; HAS_DERIVATIVE_AT_WITHIN]);;
+
+let HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN = prove
+ (`!f f' g x s d.
+       &0 < d /\ x IN s /\
+       (!x'. x' IN s /\ dist (x',x) < d ==> f x' = g x') /\
+       (f has_vector_derivative f') (at x within s)
+       ==> (g has_vector_derivative f') (at x within s)`,
+  REWRITE_TAC[has_vector_derivative; HAS_DERIVATIVE_TRANSFORM_WITHIN]);;
+
+let HAS_VECTOR_DERIVATIVE_TRANSFORM_AT = prove
+ (`!f f' g x d.
+       &0 < d /\ (!x'. dist (x',x) < d ==> f x' = g x') /\
+       (f has_vector_derivative f') (at x)
+       ==> (g has_vector_derivative f') (at x)`,
+  REWRITE_TAC[has_vector_derivative; HAS_DERIVATIVE_TRANSFORM_AT]);;
+
+let HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN_OPEN = prove
+ (`!f g s x.
+        open s /\ x IN s /\
+        (!y. y IN s ==> f y = g y) /\
+        (f has_vector_derivative f') (at x)
+        ==> (g has_vector_derivative f') (at x)`,
+  REWRITE_TAC[has_vector_derivative; HAS_DERIVATIVE_TRANSFORM_WITHIN_OPEN]);;
+
+let VECTOR_DIFF_CHAIN_AT = prove
+ (`!f g f' g' x.
+         (f has_vector_derivative f') (at x) /\
+         (g has_vector_derivative g') (at (f x))
+         ==> ((g o f) has_vector_derivative (drop f' % g')) (at x)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_vector_derivative] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP DIFF_CHAIN_AT) THEN
+  REWRITE_TAC[o_DEF; DROP_CMUL; GSYM VECTOR_MUL_ASSOC]);;
+
+let VECTOR_DIFF_CHAIN_WITHIN = prove
+ (`!f g f' g' s x.
+         (f has_vector_derivative f') (at x within s) /\
+         (g has_vector_derivative g') (at (f x) within IMAGE f s)
+         ==> ((g o f) has_vector_derivative (drop f' % g')) (at x within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_vector_derivative] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP DIFF_CHAIN_WITHIN) THEN
+  REWRITE_TAC[o_DEF; DROP_CMUL; GSYM VECTOR_MUL_ASSOC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Various versions of Kachurovskii's theorem.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_ON_DERIVATIVE_SECANT_IMP = prove
+ (`!f f' s x y:real^N.
+        f convex_on s /\ segment[x,y] SUBSET s /\
+        ((lift o f) has_derivative (lift o f')) (at x within s)
+        ==> f'(y - x) <= f y - f x`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(x:real^N) IN s /\ (y:real^N) IN s` ASSUME_TAC THENL
+   [ASM_MESON_TAC[SUBSET; ENDS_IN_SEGMENT]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [has_derivative_within]) THEN
+  REWRITE_TAC[LIM_WITHIN; DIST_0; o_THM] THEN
+  REWRITE_TAC[GSYM LIFT_ADD; GSYM LIFT_SUB; GSYM LIFT_CMUL; NORM_LIFT] THEN
+  STRIP_TAC THEN ASM_CASES_TAC `y:real^N = x` THENL
+   [FIRST_X_ASSUM(MP_TAC o MATCH_MP LINEAR_0) THEN
+    REWRITE_TAC[o_THM; VECTOR_SUB_REFL; GSYM DROP_EQ; DROP_VEC; LIFT_DROP] THEN
+    ASM_SIMP_TAC[REAL_SUB_REFL; REAL_LE_REFL; VECTOR_SUB_REFL];
+    ALL_TAC] THEN
+  ABBREV_TAC `e = (f':real^N->real)(y - x) - (f y - f x)` THEN
+  ASM_CASES_TAC `&0 < e` THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2 / norm(y - x:real^N)`) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_HALF; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ABBREV_TAC `u = min (&1 / &2) (d / &2 / norm (y - x:real^N))` THEN
+  SUBGOAL_THEN `&0 < u /\ u < &1` STRIP_ASSUME_TAC THENL
+   [EXPAND_TAC "u" THEN REWRITE_TAC[REAL_LT_MIN; REAL_MIN_LT] THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; REAL_HALF; VECTOR_SUB_EQ] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  ABBREV_TAC `z:real^N = (&1 - u) % x + u % y` THEN
+  SUBGOAL_THEN `(z:real^N) IN segment(x,y)` MP_TAC THENL
+   [ASM_MESON_TAC[IN_SEGMENT]; ALL_TAC] THEN
+  SIMP_TAC[open_segment; IN_DIFF; IN_INSERT; NOT_IN_EMPTY; DE_MORGAN_THM] THEN
+  STRIP_TAC THEN DISCH_THEN(MP_TAC o SPEC `z:real^N`) THEN
+  SUBGOAL_THEN `(z:real^N) IN s` ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[DIST_POS_LT] THEN
+    EXPAND_TAC "z" THEN REWRITE_TAC[dist; NORM_MUL; VECTOR_ARITH
+     `((&1 - u) % x + u % y) - x:real^N = u % (y - x)`] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONVEX_ON_LEFT_SECANT]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`x:real^N`; `y:real^N`; `z:real^N`]) THEN
+  ASM_REWRITE_TAC[open_segment; IN_DIFF; IN_INSERT; NOT_IN_EMPTY] THEN
+  SIMP_TAC[REAL_ARITH `inv y * (z - (x + d)):real = (z - x) / y - d / y`] THEN
+  REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+   `z <= y / n /\ abs(z - d) < e / n ==> d <= (y + e) / n`)) THEN
+  SUBGOAL_THEN
+   `(f':real^N->real)(z - x) / norm(z - x) = f'(y - x) / norm(y - x)`
+  SUBST1_TAC THENL
+   [EXPAND_TAC "z" THEN
+    REWRITE_TAC[VECTOR_ARITH
+     `((&1 - u) % x + u % y) - x:real^N = u % (y - x)`] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP LINEAR_CMUL) THEN
+    DISCH_THEN(MP_TAC o SPECL [`u:real`; `y - x:real^N`]) THEN
+    ASM_REWRITE_TAC[GSYM LIFT_CMUL; o_THM; LIFT_EQ] THEN
+    DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[NORM_MUL] THEN
+    ASM_SIMP_TAC[real_abs; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[real_div; REAL_INV_MUL; REAL_MUL_ASSOC] THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
+    REWRITE_TAC[GSYM real_div] THEN MATCH_MP_TAC REAL_DIV_LMUL THEN
+    ASM_REAL_ARITH_TAC;
+    ASM_SIMP_TAC[REAL_LE_DIV2_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let CONVEX_ON_SECANT_DERIVATIVE_IMP = prove
+ (`!f f' s x y:real^N.
+        f convex_on s /\ segment[x,y] SUBSET s /\
+        ((lift o f) has_derivative (lift o f')) (at y within s)
+        ==> f y - f x <= f'(y - x)`,
+  ONCE_REWRITE_TAC[SEGMENT_SYM] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`f:real^N->real`; `f':real^N->real`; `s:real^N->bool`;
+    `y:real^N`; `x:real^N`] CONVEX_ON_DERIVATIVE_SECANT_IMP) THEN
+  ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[SEGMENT_SYM] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `f' = --f'' ==> f' <= x - y ==> y - x <= f''`) THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM VECTOR_NEG_SUB] THEN
+  GEN_REWRITE_TAC I [GSYM LIFT_EQ] THEN REWRITE_TAC[LIFT_NEG] THEN
+  SPEC_TAC(`y - x:real^N`,`z:real^N`) THEN
+  MATCH_MP_TAC(REWRITE_RULE[RIGHT_FORALL_IMP_THM] LINEAR_NEG) THEN
+  REWRITE_TAC[GSYM o_DEF] THEN ASM_MESON_TAC[has_derivative]);;
+
+let CONVEX_ON_DERIVATIVES_IMP = prove
+ (`!f f'x f'y s x y:real^N.
+        f convex_on s /\ segment[x,y] SUBSET s /\
+        ((lift o f) has_derivative (lift o f'x)) (at x within s) /\
+        ((lift o f) has_derivative (lift o f'y)) (at y within s)
+        ==> f'x(y - x) <= f'y(y - x)`,
+  ASM_MESON_TAC[CONVEX_ON_DERIVATIVE_SECANT_IMP;
+                CONVEX_ON_SECANT_DERIVATIVE_IMP;
+                SEGMENT_SYM; REAL_LE_TRANS]);;
+
+let CONVEX_ON_DERIVATIVE_SECANT,CONVEX_ON_DERIVATIVES =
+ (CONJ_PAIR o prove)
+ (`(!f f' s:real^N->bool.
+        convex s /\
+        (!x. x IN s ==> ((lift o f) has_derivative (lift o f'(x)))
+                        (at x within s))
+        ==> (f convex_on s <=>
+             !x y. x IN s /\ y IN s ==> f'(x)(y - x) <= f y - f x)) /\
+   (!f f' s:real^N->bool.
+        convex s /\
+        (!x. x IN s ==> ((lift o f) has_derivative (lift o f'(x)))
+                        (at x within s))
+        ==> (f convex_on s <=>
+             !x y. x IN s /\ y IN s ==> f'(x)(y - x) <= f'(y)(y - x)))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[TAUT `(a ==> b) /\ (a ==> c) <=> a ==> b /\ c`] THEN
+  STRIP_TAC THEN MATCH_MP_TAC(TAUT
+   `(a ==> b) /\ (b ==> c) /\ (c ==> a) ==> (a <=> b) /\ (a <=> c)`) THEN
+  REPEAT CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC CONVEX_ON_DERIVATIVE_SECANT_IMP THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_SIMP_TAC[ETA_AX] THEN
+    ASM_MESON_TAC[CONVEX_CONTAINS_SEGMENT];
+    DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(fun th ->
+     MP_TAC(ISPECL [`x:real^N`; `y:real^N`] th) THEN
+     MP_TAC(ISPECL [`y:real^N`; `x:real^N`] th)) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(REAL_ARITH
+     `f''' = --f'' ==> f''' <= x - y ==> f' <= y - x ==> f' <= f''`) THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM VECTOR_NEG_SUB] THEN
+    GEN_REWRITE_TAC I [GSYM LIFT_EQ] THEN REWRITE_TAC[LIFT_NEG] THEN
+    SPEC_TAC(`y - x:real^N`,`z:real^N`) THEN
+    MATCH_MP_TAC(REWRITE_RULE[RIGHT_FORALL_IMP_THM] LINEAR_NEG) THEN
+    REWRITE_TAC[GSYM o_DEF] THEN REWRITE_TAC[GSYM I_DEF; I_O_ID] THEN
+    ASM_MESON_TAC[has_derivative];
+    ALL_TAC] THEN
+  DISCH_TAC THEN REWRITE_TAC[convex_on] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+  REWRITE_TAC[TAUT `a /\ b /\ c /\ d /\ e <=> e /\ a /\ b /\ c /\ d`] THEN
+  REWRITE_TAC[IMP_CONJ; REAL_ARITH `u + v = &1 <=> u = &1 - v`] THEN
+  REWRITE_TAC[FORALL_UNWIND_THM2; REAL_SUB_LE] THEN X_GEN_TAC `u:real` THEN
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `u = &0` THEN
+  ASM_SIMP_TAC[REAL_SUB_RZERO; VECTOR_MUL_LZERO; VECTOR_MUL_LID; REAL_LE_REFL;
+               REAL_MUL_LZERO; REAL_MUL_LID; VECTOR_ADD_RID; REAL_ADD_RID] THEN
+  ASM_CASES_TAC `u = &1` THEN
+  ASM_SIMP_TAC[REAL_SUB_REFL; VECTOR_MUL_LZERO; VECTOR_MUL_LID; REAL_LE_REFL;
+               REAL_MUL_LZERO; REAL_MUL_LID; VECTOR_ADD_LID; REAL_ADD_LID] THEN
+  SUBGOAL_THEN `&0 < u /\ u < &1` STRIP_ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[REAL_LT_LE]; ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`lift o (f:real^N->real) o (\u. (&1 - drop u) % a + drop u % b)`;
+    `\x:real^1. lift o f'((&1 - drop x) % a + drop x % b) o
+     (\u. --(drop u) % a + drop u % b:real^N)`] MVT_VERY_SIMPLE) THEN
+  DISCH_THEN(fun th ->
+    MP_TAC(ISPECL [`vec 0:real^1`; `lift u`] th) THEN
+    MP_TAC(ISPECL [`lift u`; `vec 1:real^1`] th)) THEN
+  ASM_REWRITE_TAC[LIFT_DROP; o_THM] THEN
+  ASM_SIMP_TAC[DROP_VEC; VECTOR_MUL_LZERO; REAL_SUB_RZERO; REAL_LT_IMP_LE;
+               VECTOR_ADD_RID; VECTOR_MUL_LID; VECTOR_SUB_RZERO] THEN
+  MATCH_MP_TAC(TAUT
+   `(a1 /\ a2) /\ (b1 ==> b2 ==> c) ==> (a1 ==> b1) ==> (a2 ==> b2) ==> c`) THEN
+  CONJ_TAC THENL
+   [CONJ_TAC THEN X_GEN_TAC `v:real^1` THEN DISCH_TAC THEN
+    (REWRITE_TAC[o_ASSOC] THEN MATCH_MP_TAC DIFF_CHAIN_WITHIN THEN
+     REWRITE_TAC[] THEN CONJ_TAC THENL
+      [MATCH_MP_TAC HAS_DERIVATIVE_ADD THEN CONJ_TAC THENL
+        [ONCE_REWRITE_TAC[VECTOR_ARITH `(&1 - a) % x:real^N = x + --a % x`;
+                          VECTOR_ARITH `--u % a:real^N = vec 0 + --u % a`] THEN
+         MATCH_MP_TAC HAS_DERIVATIVE_ADD THEN
+         REWRITE_TAC[HAS_DERIVATIVE_CONST];
+         ALL_TAC] THEN
+       MATCH_MP_TAC HAS_DERIVATIVE_LINEAR THEN
+       REWRITE_TAC[linear; DROP_ADD; DROP_CMUL] THEN VECTOR_ARITH_TAC;
+       MATCH_MP_TAC HAS_DERIVATIVE_WITHIN_SUBSET THEN
+       EXISTS_TAC `s:real^N->bool` THEN CONJ_TAC THENL
+        [FIRST_X_ASSUM MATCH_MP_TAC;
+         REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN GEN_TAC THEN DISCH_TAC] THEN
+       FIRST_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [CONVEX_ALT]) THEN
+       RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; LIFT_DROP; DROP_VEC]) THEN
+       ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC]);
+    REWRITE_TAC[REAL_SUB_REFL; VECTOR_MUL_LZERO; VECTOR_ADD_LID] THEN
+    REWRITE_TAC[EXISTS_LIFT; LIFT_DROP; IN_INTERVAL_1; DROP_VEC] THEN
+    REWRITE_TAC[GSYM LIFT_SUB; LIFT_EQ] THEN
+    REWRITE_TAC[DROP_SUB; DROP_VEC; LIFT_DROP] THEN
+    REWRITE_TAC[VECTOR_ARITH `--u % a + u % b:real^N = u % (b - a)`] THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM; RIGHT_IMP_FORALL_THM] THEN
+    MAP_EVERY X_GEN_TAC [`w:real`; `v:real`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+    ONCE_REWRITE_TAC[TAUT `a ==> b /\ c ==> d <=> b ==> a ==> c ==> d`] THEN
+    STRIP_TAC THEN REWRITE_TAC[IMP_IMP] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (MP_TAC o AP_TERM `(*) (u:real)`)
+                               (MP_TAC o AP_TERM `(*) (&1 - u:real)`)) THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `f1 <= f2 /\ (xa <= xb ==> a <= b)
+      ==> xa = f1 ==> xb = f2 ==> a <= b`) THEN
+    CONJ_TAC THENL [ALL_TAC; REAL_ARITH_TAC] THEN
+    SUBGOAL_THEN
+     `((&1 - v) % a + v % b:real^N) IN s /\
+      ((&1 - w) % a + w % b:real^N) IN s`
+    STRIP_ASSUME_TAC THENL
+     [CONJ_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [CONVEX_ALT]) THEN
+      ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `linear(lift o (f'((&1 - v) % a + v % b:real^N):real^N->real)) /\
+      linear(lift o (f'((&1 - w) % a + w % b:real^N):real^N->real))`
+    MP_TAC THENL [ASM_MESON_TAC[has_derivative]; ALL_TAC] THEN
+    DISCH_THEN(CONJUNCTS_THEN(MP_TAC o MATCH_MP LINEAR_CMUL)) THEN
+    ASM_REWRITE_TAC[o_THM; GSYM LIFT_NEG; GSYM LIFT_CMUL; LIFT_EQ] THEN
+    REPEAT DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `(&1 - u) * u * x = u * (&1 - u) * x`] THEN
+    REPEAT(MATCH_MP_TAC REAL_LE_LMUL THEN
+           CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`(&1 - v) % a + v % b:real^N`; `(&1 - w) % a + w % b:real^N`]) THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH
+     `((&1 - v) % a + v % b) - ((&1 - w) % a + w % b):real^N =
+      (v - w) % (b - a)`] THEN
+    ASM_CASES_TAC `v:real = w` THEN ASM_SIMP_TAC[REAL_LE_REFL] THEN
+    SUBGOAL_THEN `&0 < w - v` (fun th -> SIMP_TAC[th; REAL_LE_LMUL_EQ]) THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let CONVEX_ON_SECANT_DERIVATIVE = prove
+ (`!f f' s:real^N->bool.
+        convex s /\
+        (!x. x IN s ==> ((lift o f) has_derivative (lift o f'(x)))
+                        (at x within s))
+        ==> (f convex_on s <=>
+             !x y. x IN s /\ y IN s ==> f y - f x <= f'(y)(y - x))`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP CONVEX_ON_DERIVATIVE_SECANT) THEN
+  GEN_REWRITE_TAC RAND_CONV [SWAP_FORALL_THM] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `x:real^N` THEN REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `y:real^N` THEN REWRITE_TAC[] THEN
+  MAP_EVERY ASM_CASES_TAC [`(x:real^N) IN s`; `(y:real^N) IN s`] THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `f' = --f'' ==> (f' <= y - x <=> x - y <= f'')`) THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM VECTOR_NEG_SUB] THEN
+  GEN_REWRITE_TAC I [GSYM LIFT_EQ] THEN REWRITE_TAC[LIFT_NEG] THEN
+  SPEC_TAC(`x - y:real^N`,`z:real^N`) THEN
+  MATCH_MP_TAC(REWRITE_RULE[RIGHT_FORALL_IMP_THM] LINEAR_NEG) THEN
+  REWRITE_TAC[GSYM o_DEF] THEN
+  REWRITE_TAC[GSYM I_DEF; I_O_ID] THEN ASM_MESON_TAC[has_derivative]);;
diff --git a/Multivariate/determinants.ml b/Multivariate/determinants.ml
new file mode 100644 (file)
index 0000000..4033193
--- /dev/null
@@ -0,0 +1,3136 @@
+(* ========================================================================= *)
+(* Determinant and trace of a square matrix.                                 *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(* ========================================================================= *)
+
+needs "Multivariate/vectors.ml";;
+needs "Library/permutations.ml";;
+needs "Library/floor.ml";;
+needs "Library/products.ml";;
+
+prioritize_real();;
+
+(* ------------------------------------------------------------------------- *)
+(* Trace of a matrix (this is relatively easy).                              *)
+(* ------------------------------------------------------------------------- *)
+
+let trace = new_definition
+  `(trace:real^N^N->real) A = sum(1..dimindex(:N)) (\i. A$i$i)`;;
+
+let TRACE_0 = prove
+ (`trace(mat 0) = &0`,
+  SIMP_TAC[trace; mat; LAMBDA_BETA; SUM_0]);;
+
+let TRACE_I = prove
+ (`trace(mat 1 :real^N^N) = &(dimindex(:N))`,
+  SIMP_TAC[trace; mat; LAMBDA_BETA; SUM_CONST_NUMSEG; REAL_MUL_RID] THEN
+  AP_TERM_TAC THEN ARITH_TAC);;
+
+let TRACE_ADD = prove
+ (`!A B:real^N^N. trace(A + B) = trace(A) + trace(B)`,
+  SIMP_TAC[trace; matrix_add; SUM_ADD_NUMSEG; LAMBDA_BETA]);;
+
+let TRACE_SUB = prove
+ (`!A B:real^N^N. trace(A - B) = trace(A) - trace(B)`,
+  SIMP_TAC[trace; matrix_sub; SUM_SUB_NUMSEG; LAMBDA_BETA]);;
+
+let TRACE_MUL_SYM = prove
+ (`!A B:real^N^N. trace(A ** B) = trace(B ** A)`,
+  REPEAT GEN_TAC THEN SIMP_TAC[trace; matrix_mul; LAMBDA_BETA] THEN
+  GEN_REWRITE_TAC RAND_CONV [SUM_SWAP_NUMSEG] THEN REWRITE_TAC[REAL_MUL_SYM]);;
+
+let TRACE_TRANSP = prove
+ (`!A:real^N^N. trace(transp A) = trace A`,
+  SIMP_TAC[trace; transp; LAMBDA_BETA]);;
+
+let TRACE_CONJUGATE = prove
+ (`!A:real^N^N U:real^N^N.
+        invertible U ==> trace(matrix_inv U ** A ** U) = trace A`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[TRACE_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM MATRIX_MUL_ASSOC; MATRIX_INV; MATRIX_MUL_RID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Definition of determinant.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let det = new_definition
+ `det(A:real^N^N) =
+        sum { p | p permutes 1..dimindex(:N) }
+            (\p. sign(p) * product (1..dimindex(:N)) (\i. A$i$(p i)))`;;
+
+(* ------------------------------------------------------------------------- *)
+(* A few general lemmas we need below.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let IN_DIMINDEX_SWAP = prove
+ (`!m n j. 1 <= m /\ m <= dimindex(:N) /\
+             1 <= n /\ n <= dimindex(:N) /\
+             1 <= j /\ j <= dimindex(:N)
+           ==> 1 <= swap(m,n) j /\ swap(m,n) j <= dimindex(:N)`,
+  REWRITE_TAC[swap] THEN ARITH_TAC);;
+
+let LAMBDA_BETA_PERM = prove
+ (`!p i. p permutes 1..dimindex(:N) /\ 1 <= i /\ i <= dimindex(:N)
+         ==> ((lambda) g :A^N) $ p(i) = g(p i)`,
+  ASM_MESON_TAC[LAMBDA_BETA; PERMUTES_IN_IMAGE; IN_NUMSEG]);;
+
+let PRODUCT_PERMUTE = prove
+ (`!f p s. p permutes s ==> product s f = product s (f o p)`,
+  REWRITE_TAC[product] THEN MATCH_MP_TAC ITERATE_PERMUTE THEN
+  REWRITE_TAC[MONOIDAL_REAL_MUL]);;
+
+let PRODUCT_PERMUTE_NUMSEG = prove
+ (`!f p m n. p permutes m..n ==> product(m..n) f = product(m..n) (f o p)`,
+  MESON_TAC[PRODUCT_PERMUTE; FINITE_NUMSEG]);;
+
+let REAL_MUL_SUM = prove
+ (`!s t f g.
+        FINITE s /\ FINITE t
+        ==> sum s f * sum t g = sum s (\i. sum t (\j. f(i) * g(j)))`,
+  SIMP_TAC[SUM_LMUL] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN SIMP_TAC[SUM_LMUL]);;
+
+let REAL_MUL_SUM_NUMSEG = prove
+ (`!m n p q. sum(m..n) f * sum(p..q) g =
+             sum(m..n) (\i. sum(p..q) (\j. f(i) * g(j)))`,
+  SIMP_TAC[REAL_MUL_SUM; FINITE_NUMSEG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic determinant properties.                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let DET_CMUL = prove
+ (`!A:real^N^N c. det(c %% A) = c pow dimindex(:N) * det A`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[det; MATRIX_CMUL_COMPONENT; PRODUCT_MUL; FINITE_NUMSEG] THEN
+  SIMP_TAC[PRODUCT_CONST_NUMSEG_1; GSYM SUM_LMUL] THEN
+  REWRITE_TAC[REAL_MUL_AC]);;
+
+let DET_NEG = prove
+ (`!A:real^N^N. det(--A) = --(&1) pow dimindex(:N) * det A`,
+  REWRITE_TAC[MATRIX_NEG_MINUS1; DET_CMUL]);;
+
+let DET_TRANSP = prove
+ (`!A:real^N^N. det(transp A) = det A`,
+  GEN_TAC THEN REWRITE_TAC[det] THEN
+  GEN_REWRITE_TAC LAND_CONV [SUM_PERMUTATIONS_INVERSE] THEN
+  MATCH_MP_TAC SUM_EQ THEN
+  SIMP_TAC[FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN X_GEN_TAC `p:num->num` THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN BINOP_TAC THENL
+   [ASM_MESON_TAC[SIGN_INVERSE; PERMUTATION_PERMUTES; FINITE_NUMSEG];
+    ALL_TAC] THEN
+  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+    [GSYM(MATCH_MP PERMUTES_IMAGE th)]) THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `product(1..dimindex(:N))
+       ((\i. (transp A:real^N^N)$i$inverse p(i)) o p)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC PRODUCT_IMAGE THEN
+    ASM_MESON_TAC[FINITE_NUMSEG; PERMUTES_INJECTIVE; PERMUTES_INVERSE];
+    MATCH_MP_TAC PRODUCT_EQ THEN REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+    SIMP_TAC[transp; LAMBDA_BETA; o_THM] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP PERMUTES_INVERSES_o) THEN
+    SIMP_TAC[FUN_EQ_THM; I_THM; o_THM] THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[PERMUTES_IN_NUMSEG; LAMBDA_BETA_PERM; LAMBDA_BETA]]);;
+
+let DET_LOWERTRIANGULAR = prove
+ (`!A:real^N^N.
+        (!i j. 1 <= i /\ i <= dimindex(:N) /\
+               1 <= j /\ j <= dimindex(:N) /\ i < j ==> A$i$j = &0)
+        ==> det(A) = product(1..dimindex(:N)) (\i. A$i$i)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[det] THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `sum {I}
+     (\p. sign p * product(1..dimindex(:N)) (\i. (A:real^N^N)$i$p(i)))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC; REWRITE_TAC[SUM_SING; SIGN_I; REAL_MUL_LID; I_THM]] THEN
+  MATCH_MP_TAC SUM_SUPERSET THEN
+  SIMP_TAC[IN_SING; FINITE_RULES; SUBSET; IN_ELIM_THM; PERMUTES_I] THEN
+  X_GEN_TAC `p:num->num` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[PRODUCT_EQ_0_NUMSEG; REAL_ENTIRE; SIGN_NZ] THEN
+  MP_TAC(SPECL [`p:num->num`; `1..dimindex(:N)`] PERMUTES_NUMSET_LE) THEN
+  ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG; NOT_LT]);;
+
+let DET_UPPERTRIANGULAR = prove
+ (`!A:real^N^N.
+        (!i j. 1 <= i /\ i <= dimindex(:N) /\
+               1 <= j /\ j <= dimindex(:N) /\ j < i ==> A$i$j = &0)
+        ==> det(A) = product(1..dimindex(:N)) (\i. A$i$i)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[det] THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `sum {I}
+     (\p. sign p * product(1..dimindex(:N)) (\i. (A:real^N^N)$i$p(i)))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC; REWRITE_TAC[SUM_SING; SIGN_I; REAL_MUL_LID; I_THM]] THEN
+  MATCH_MP_TAC SUM_SUPERSET THEN
+  SIMP_TAC[IN_SING; FINITE_RULES; SUBSET; IN_ELIM_THM; PERMUTES_I] THEN
+  X_GEN_TAC `p:num->num` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[PRODUCT_EQ_0_NUMSEG; REAL_ENTIRE; SIGN_NZ] THEN
+  MP_TAC(SPECL [`p:num->num`; `1..dimindex(:N)`] PERMUTES_NUMSET_GE) THEN
+  ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG; NOT_LT]);;
+
+let DET_DIAGONAL = prove
+ (`!A:real^N^N.
+        (!i j. 1 <= i /\ i <= dimindex(:N) /\
+               1 <= j /\ j <= dimindex(:N) /\ ~(i = j) ==> A$i$j = &0)
+        ==> det(A) = product(1..dimindex(:N)) (\i. A$i$i)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC DET_LOWERTRIANGULAR THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[LT_REFL]);;
+
+let DET_I = prove
+ (`det(mat 1 :real^N^N) = &1`,
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `product(1..dimindex(:N)) (\i. (mat 1:real^N^N)$i$i)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC DET_LOWERTRIANGULAR;
+    MATCH_MP_TAC PRODUCT_EQ_1_NUMSEG] THEN
+  SIMP_TAC[mat; LAMBDA_BETA] THEN MESON_TAC[LT_REFL]);;
+
+let DET_0 = prove
+ (`det(mat 0 :real^N^N) = &0`,
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `product(1..dimindex(:N)) (\i. (mat 0:real^N^N)$i$i)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC DET_LOWERTRIANGULAR;
+    REWRITE_TAC[PRODUCT_EQ_0_NUMSEG] THEN EXISTS_TAC `1`] THEN
+  SIMP_TAC[mat; LAMBDA_BETA; COND_ID; DIMINDEX_GE_1; LE_REFL]);;
+
+let DET_PERMUTE_ROWS = prove
+ (`!A:real^N^N p.
+        p permutes 1..dimindex(:N)
+        ==> det(lambda i. A$p(i)) = sign(p) * det(A)`,
+  REWRITE_TAC[det] THEN SIMP_TAC[LAMBDA_BETA] THEN REPEAT STRIP_TAC THEN
+  SIMP_TAC[GSYM SUM_LMUL; FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV
+    [MATCH_MP SUM_PERMUTATIONS_COMPOSE_R th]) THEN
+  MATCH_MP_TAC SUM_EQ THEN
+  SIMP_TAC[FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN X_GEN_TAC `q:num->num` THEN
+  REWRITE_TAC[IN_ELIM_THM; REAL_MUL_ASSOC] THEN DISCH_TAC THEN BINOP_TAC THENL
+   [ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_MESON_TAC[SIGN_COMPOSE; PERMUTATION_PERMUTES; FINITE_NUMSEG];
+    ALL_TAC] THEN
+  MP_TAC(MATCH_MP PERMUTES_INVERSE (ASSUME `p permutes 1..dimindex(:N)`)) THEN
+  DISCH_THEN(fun th -> GEN_REWRITE_TAC LAND_CONV
+    [MATCH_MP PRODUCT_PERMUTE_NUMSEG th]) THEN
+  MATCH_MP_TAC PRODUCT_EQ THEN REWRITE_TAC[IN_NUMSEG; FINITE_NUMSEG] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[o_THM] THEN
+  ASM_MESON_TAC[PERMUTES_INVERSES]);;
+
+let DET_PERMUTE_COLUMNS = prove
+ (`!A:real^N^N p.
+        p permutes 1..dimindex(:N)
+        ==> det((lambda i j. A$i$p(j)):real^N^N) = sign(p) * det(A)`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (funpow 2 RAND_CONV) [GSYM DET_TRANSP] THEN
+  FIRST_ASSUM(fun th -> ONCE_REWRITE_TAC
+   [GSYM(MATCH_MP DET_PERMUTE_ROWS th)]) THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM DET_TRANSP] THEN AP_TERM_TAC THEN
+  ASM_SIMP_TAC[CART_EQ; transp; LAMBDA_BETA; LAMBDA_BETA_PERM]);;
+
+let DET_IDENTICAL_ROWS = prove
+ (`!A:real^N^N i j. 1 <= i /\ i <= dimindex(:N) /\
+                    1 <= j /\ j <= dimindex(:N) /\ ~(i = j) /\
+                    row i A = row j A
+                    ==> det A = &0`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`A:real^N^N`; `swap(i:num,j:num)`] DET_PERMUTE_ROWS) THEN
+  ASM_SIMP_TAC[PERMUTES_SWAP; IN_NUMSEG; SIGN_SWAP] THEN
+  MATCH_MP_TAC(REAL_ARITH `a = b ==> b = -- &1 * a ==> a = &0`) THEN
+  AP_TERM_TAC THEN FIRST_X_ASSUM(MP_TAC o SYM) THEN
+  SIMP_TAC[row; CART_EQ; LAMBDA_BETA] THEN
+  REWRITE_TAC[swap] THEN ASM_MESON_TAC[]);;
+
+let DET_IDENTICAL_COLUMNS = prove
+ (`!A:real^N^N i j. 1 <= i /\ i <= dimindex(:N) /\
+                    1 <= j /\ j <= dimindex(:N) /\ ~(i = j) /\
+                    column i A = column j A
+                    ==> det A = &0`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM DET_TRANSP] THEN
+  MATCH_MP_TAC DET_IDENTICAL_ROWS THEN ASM_MESON_TAC[ROW_TRANSP]);;
+
+let DET_ZERO_ROW = prove
+ (`!A:real^N^N i.
+       1 <= i /\ i <= dimindex(:N) /\ row i A = vec 0  ==> det A = &0`,
+  SIMP_TAC[det; row; CART_EQ; LAMBDA_BETA; VEC_COMPONENT] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ_0 THEN
+  REWRITE_TAC[IN_ELIM_THM; REAL_ENTIRE; SIGN_NZ] THEN REPEAT STRIP_TAC THEN
+  SIMP_TAC[PRODUCT_EQ_0; FINITE_NUMSEG; IN_NUMSEG] THEN
+  ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG]);;
+
+let DET_ZERO_COLUMN = prove
+ (`!A:real^N^N i.
+       1 <= i /\ i <= dimindex(:N) /\ column i A = vec 0  ==> det A = &0`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM DET_TRANSP] THEN
+  MATCH_MP_TAC DET_ZERO_ROW THEN ASM_MESON_TAC[ROW_TRANSP]);;
+
+let DET_ROW_ADD = prove
+ (`!a b c k.
+         1 <= k /\ k <= dimindex(:N)
+         ==> det((lambda i. if i = k then a + b else c i):real^N^N) =
+             det((lambda i. if i = k then a else c i):real^N^N) +
+             det((lambda i. if i = k then b else c i):real^N^N)`,
+  SIMP_TAC[det; LAMBDA_BETA; GSYM SUM_ADD;
+           FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ THEN
+  SIMP_TAC[FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+  X_GEN_TAC `p:num->num` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  DISCH_TAC THEN REWRITE_TAC[GSYM REAL_ADD_LDISTRIB] THEN AP_TERM_TAC THEN
+  SUBGOAL_THEN `1..dimindex(:N) = k INSERT ((1..dimindex(:N)) DELETE k)`
+  SUBST1_TAC THENL [ASM_MESON_TAC[INSERT_DELETE; IN_NUMSEG]; ALL_TAC] THEN
+  SIMP_TAC[PRODUCT_CLAUSES; FINITE_DELETE; FINITE_NUMSEG; IN_DELETE] THEN
+  MATCH_MP_TAC(REAL_RING
+   `c = a + b /\ y = x:real /\ z = x ==> c * x = a * y + b * z`) THEN
+  REWRITE_TAC[VECTOR_ADD_COMPONENT] THEN
+  CONJ_TAC THEN MATCH_MP_TAC PRODUCT_EQ THEN
+  SIMP_TAC[IN_DELETE; FINITE_DELETE; FINITE_NUMSEG]);;
+
+let DET_ROW_MUL = prove
+ (`!a b c k.
+        1 <= k /\ k <= dimindex(:N)
+        ==> det((lambda i. if i = k then c % a else b i):real^N^N) =
+            c * det((lambda i. if i = k then a else b i):real^N^N)`,
+  SIMP_TAC[det; LAMBDA_BETA; GSYM SUM_LMUL;
+           FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ THEN
+  SIMP_TAC[FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+  X_GEN_TAC `p:num->num` THEN REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `1..dimindex(:N) = k INSERT ((1..dimindex(:N)) DELETE k)`
+  SUBST1_TAC THENL [ASM_MESON_TAC[INSERT_DELETE; IN_NUMSEG]; ALL_TAC] THEN
+  SIMP_TAC[PRODUCT_CLAUSES; FINITE_DELETE; FINITE_NUMSEG; IN_DELETE] THEN
+  MATCH_MP_TAC(REAL_RING
+   `cp = c * p /\ p1 = p2:real ==> s * cp * p1 = c * s * p * p2`) THEN
+  REWRITE_TAC[VECTOR_MUL_COMPONENT] THEN MATCH_MP_TAC PRODUCT_EQ THEN
+  SIMP_TAC[IN_DELETE; FINITE_DELETE; FINITE_NUMSEG]);;
+
+let DET_ROW_OPERATION = prove
+ (`!A:real^N^N i.
+        1 <= i /\ i <= dimindex(:N) /\
+        1 <= j /\ j <= dimindex(:N) /\ ~(i = j)
+        ==> det(lambda k. if k = i then row i A + c % row j A else row k A) =
+            det A`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[DET_ROW_ADD; DET_ROW_MUL] THEN
+  MATCH_MP_TAC(REAL_RING `a = b /\ d = &0 ==> a + c * d = b`) THEN
+  CONJ_TAC THENL
+   [AP_TERM_TAC THEN ASM_SIMP_TAC[LAMBDA_BETA; CART_EQ] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+    ASM_SIMP_TAC[row; LAMBDA_BETA; CART_EQ];
+    MATCH_MP_TAC DET_IDENTICAL_ROWS THEN
+    MAP_EVERY EXISTS_TAC [`i:num`; `j:num`] THEN
+    ASM_SIMP_TAC[row; LAMBDA_BETA; CART_EQ]]);;
+
+let DET_ROW_SPAN = prove
+ (`!A:real^N^N i x.
+        1 <= i /\ i <= dimindex(:N) /\
+        x IN span {row j A | 1 <= j /\ j <= dimindex(:N) /\ ~(j = i)}
+        ==> det(lambda k. if k = i then row i A + x else row k A) =
+            det A`,
+  GEN_TAC THEN GEN_TAC THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN REPEAT DISCH_TAC THEN
+  MATCH_MP_TAC SPAN_INDUCT_ALT THEN CONJ_TAC THENL
+   [AP_TERM_TAC THEN SIMP_TAC[CART_EQ; LAMBDA_BETA; VECTOR_ADD_RID] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[row; LAMBDA_BETA];
+    ALL_TAC] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `j:num`) (SUBST_ALL_TAC o SYM)) THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH
+     `a + c % x + y:real^N = (a + y) + c % x`] THEN
+  ABBREV_TAC `z = row i (A:real^N^N) + y` THEN
+  ASM_SIMP_TAC[DET_ROW_MUL; DET_ROW_ADD] THEN
+  MATCH_MP_TAC(REAL_RING `d = &0 ==> a + c * d = a`) THEN
+  MATCH_MP_TAC DET_IDENTICAL_ROWS THEN
+  MAP_EVERY EXISTS_TAC [`i:num`; `j:num`] THEN
+  ASM_SIMP_TAC[row; LAMBDA_BETA; CART_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* May as well do this, though it's a bit unsatisfactory since it ignores    *)
+(* exact duplicates by considering the rows/columns as a set.                *)
+(* ------------------------------------------------------------------------- *)
+
+let DET_DEPENDENT_ROWS = prove
+ (`!A:real^N^N. dependent(rows A) ==> det A = &0`,
+  GEN_TAC THEN
+  REWRITE_TAC[dependent; rows; IN_ELIM_THM; LEFT_AND_EXISTS_THM] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN GEN_TAC THEN X_GEN_TAC `i:num` THEN
+  STRIP_TAC THEN FIRST_X_ASSUM SUBST_ALL_TAC THEN
+  ASM_CASES_TAC
+   `?i j. 1 <= i /\ i <= dimindex(:N) /\
+          1 <= j /\ j <= dimindex(:N) /\ ~(i = j) /\
+          row i (A:real^N^N) = row j A`
+  THENL [ASM_MESON_TAC[DET_IDENTICAL_ROWS]; ALL_TAC] THEN
+  MP_TAC(SPECL [`A:real^N^N`; `i:num`; `--(row i (A:real^N^N))`]
+    DET_ROW_SPAN) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN MATCH_MP_TAC SPAN_NEG THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN]) THEN
+    MATCH_MP_TAC(TAUT `a = b ==> a ==> b`) THEN
+    REWRITE_TAC[IN] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    REWRITE_TAC[EXTENSION; IN_DELETE; IN_ELIM_THM] THEN ASM_MESON_TAC[];
+    DISCH_THEN(SUBST1_TAC o SYM) THEN MATCH_MP_TAC DET_ZERO_ROW THEN
+    EXISTS_TAC `i:num` THEN
+    ASM_SIMP_TAC[row; LAMBDA_BETA; CART_EQ; VECTOR_ADD_COMPONENT;
+                 VECTOR_NEG_COMPONENT; VEC_COMPONENT] THEN
+    REAL_ARITH_TAC]);;
+
+let DET_DEPENDENT_COLUMNS = prove
+ (`!A:real^N^N. dependent(columns A) ==> det A = &0`,
+  MESON_TAC[DET_DEPENDENT_ROWS; ROWS_TRANSP; DET_TRANSP]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Multilinearity and the multiplication formula.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let DET_LINEAR_ROW_VSUM = prove
+ (`!a c s k.
+         FINITE s /\ 1 <= k /\ k <= dimindex(:N)
+         ==> det((lambda i. if i = k then vsum s a else c i):real^N^N) =
+             sum s
+               (\j. det((lambda i. if i = k then a(j) else c i):real^N^N))`,
+  GEN_TAC THEN GEN_TAC THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; SUM_CLAUSES; DET_ROW_ADD] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC DET_ZERO_ROW THEN EXISTS_TAC `k:num` THEN
+  ASM_SIMP_TAC[row; LAMBDA_BETA; CART_EQ; VEC_COMPONENT]);;
+
+let BOUNDED_FUNCTIONS_BIJECTIONS_1 = prove
+ (`!p. p IN {(y,g) | y IN s /\
+                     g IN {f | (!i. 1 <= i /\ i <= k ==> f i IN s) /\
+                               (!i. ~(1 <= i /\ i <= k) ==> f i = i)}}
+       ==> (\(y,g) i. if i = SUC k then y else g(i)) p IN
+             {f | (!i. 1 <= i /\ i <= SUC k ==> f i IN s) /\
+                  (!i. ~(1 <= i /\ i <= SUC k) ==> f i = i)} /\
+           (\h. h(SUC k),(\i. if i = SUC k then i else h(i)))
+            ((\(y,g) i. if i = SUC k then y else g(i)) p) = p`,
+  REWRITE_TAC[FORALL_PAIR_THM; IN_ELIM_PAIR_THM] THEN
+  CONV_TAC(REDEPTH_CONV GEN_BETA_CONV) THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  MAP_EVERY X_GEN_TAC [`y:num`; `h:num->num`] THEN REPEAT STRIP_TAC THENL
+   [ASM_MESON_TAC[LE];
+    ASM_MESON_TAC[LE; ARITH_RULE `~(1 <= i /\ i <= SUC k) ==> ~(i = SUC k)`];
+    REWRITE_TAC[PAIR_EQ; FUN_EQ_THM] THEN
+    ASM_MESON_TAC[ARITH_RULE `~(SUC k <= k)`]]);;
+
+let BOUNDED_FUNCTIONS_BIJECTIONS_2 = prove
+ (`!h. h IN {f | (!i. 1 <= i /\ i <= SUC k ==> f i IN s) /\
+                 (!i. ~(1 <= i /\ i <= SUC k) ==> f i = i)}
+       ==> (\h. h(SUC k),(\i. if i = SUC k then i else h(i))) h IN
+           {(y,g) | y IN s /\
+                     g IN {f | (!i. 1 <= i /\ i <= k ==> f i IN s) /\
+                               (!i. ~(1 <= i /\ i <= k) ==> f i = i)}} /\
+           (\(y,g) i. if i = SUC k then y else g(i))
+              ((\h. h(SUC k),(\i. if i = SUC k then i else h(i))) h) = h`,
+  REWRITE_TAC[IN_ELIM_PAIR_THM] THEN
+  CONV_TAC(REDEPTH_CONV GEN_BETA_CONV) THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  X_GEN_TAC `h:num->num` THEN REPEAT STRIP_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN ARITH_TAC;
+    ASM_MESON_TAC[ARITH_RULE `i <= k ==> i <= SUC k /\ ~(i = SUC k)`];
+    ASM_MESON_TAC[ARITH_RULE `i <= SUC k /\ ~(i = SUC k) ==> i <= k`];
+    REWRITE_TAC[FUN_EQ_THM] THEN ASM_MESON_TAC[LE_REFL]]);;
+
+let FINITE_BOUNDED_FUNCTIONS = prove
+ (`!s k. FINITE s
+         ==> FINITE {f | (!i. 1 <= i /\ i <= k ==> f(i) IN s) /\
+                         (!i. ~(1 <= i /\ i <= k) ==> f(i) = i)}`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN GEN_TAC THEN DISCH_TAC THEN
+  INDUCT_TAC THENL
+   [REWRITE_TAC[ARITH_RULE `~(1 <= i /\ i <= 0)`] THEN
+    SIMP_TAC[GSYM FUN_EQ_THM; SET_RULE `{x | x = y} = {y}`; FINITE_RULES];
+    ALL_TAC] THEN
+  UNDISCH_TAC `FINITE(s:num->bool)` THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[TAUT `a ==> b ==> c <=> b /\ a ==> c`] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP FINITE_PRODUCT) THEN
+  DISCH_THEN(MP_TAC o ISPEC `\(y:num,g) i. if i = SUC k then y else g(i)` o
+                      MATCH_MP FINITE_IMAGE) THEN
+  MATCH_MP_TAC(TAUT `a = b ==> a ==> b`) THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE] THEN
+  X_GEN_TAC `h:num->num` THEN EQ_TAC THENL
+   [STRIP_TAC THEN ASM_SIMP_TAC[BOUNDED_FUNCTIONS_BIJECTIONS_1]; ALL_TAC] THEN
+  DISCH_TAC THEN EXISTS_TAC
+    `(\h. h(SUC k),(\i. if i = SUC k then i else h(i))) h` THEN
+  PURE_ONCE_REWRITE_TAC[CONJ_SYM] THEN CONV_TAC (RAND_CONV SYM_CONV) THEN
+  MATCH_MP_TAC BOUNDED_FUNCTIONS_BIJECTIONS_2 THEN ASM_REWRITE_TAC[]);;
+
+let DET_LINEAR_ROWS_VSUM_LEMMA = prove
+ (`!s k a c.
+         FINITE s /\ k <= dimindex(:N)
+         ==> det((lambda i. if i <= k then vsum s (a i) else c i):real^N^N) =
+             sum {f | (!i. 1 <= i /\ i <= k ==> f(i) IN s) /\
+                      !i. ~(1 <= i /\ i <= k) ==> f(i) = i}
+                 (\f. det((lambda i. if i <= k then a i (f i) else c i)
+                          :real^N^N))`,
+  let lemma = prove
+   (`(lambda i. if i <= 0 then x(i) else y(i)) = (lambda i. y i)`,
+    SIMP_TAC[CART_EQ; ARITH; LAMBDA_BETA; ARITH_RULE
+                 `1 <= k ==> ~(k <= 0)`]) in
+  ONCE_REWRITE_TAC[IMP_CONJ] THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN GEN_TAC THEN DISCH_TAC THEN
+  INDUCT_TAC THENL
+   [REWRITE_TAC[lemma; LE_0] THEN GEN_TAC THEN
+    REWRITE_TAC[ARITH_RULE `~(1 <= i /\ i <= 0)`] THEN
+    REWRITE_TAC[GSYM FUN_EQ_THM; SET_RULE `{x | x = y} = {y}`] THEN
+    REWRITE_TAC[SUM_SING];
+    ALL_TAC] THEN
+  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o check (is_imp o concl)) THEN
+  ASM_SIMP_TAC[ARITH_RULE `SUC k <= n ==> k <= n`] THEN REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [LE] THEN
+  REWRITE_TAC[TAUT
+   `(if a \/ b then c else d) = (if a then c else if b then c else d)`] THEN
+  ASM_SIMP_TAC[DET_LINEAR_ROW_VSUM; ARITH_RULE `1 <= SUC k`] THEN
+  ONCE_REWRITE_TAC[TAUT
+    `(if a then b else if c then d else e) =
+     (if c then (if a then b else d) else (if a then b else e))`] THEN
+  ASM_SIMP_TAC[ARITH_RULE `i <= k ==> ~(i = SUC k)`] THEN
+  ASM_SIMP_TAC[SUM_SUM_PRODUCT; FINITE_BOUNDED_FUNCTIONS] THEN
+  MATCH_MP_TAC SUM_EQ_GENERAL_INVERSES THEN
+  EXISTS_TAC `\(y:num,g) i. if i = SUC k then y else g(i)` THEN
+  EXISTS_TAC `\h. h(SUC k),(\i. if i = SUC k then i else h(i))` THEN
+  CONJ_TAC THENL [ACCEPT_TAC BOUNDED_FUNCTIONS_BIJECTIONS_2; ALL_TAC] THEN
+  X_GEN_TAC `p:num#(num->num)` THEN
+  DISCH_THEN(STRIP_ASSUME_TAC o MATCH_MP BOUNDED_FUNCTIONS_BIJECTIONS_1) THEN
+  ASM_REWRITE_TAC[] THEN
+  SPEC_TAC(`p:num#(num->num)`,`q:num#(num->num)`) THEN
+  REWRITE_TAC[FORALL_PAIR_THM] THEN
+  CONV_TAC(ONCE_DEPTH_CONV GEN_BETA_CONV) THEN
+  MAP_EVERY X_GEN_TAC [`y:num`; `g:num->num`] THEN AP_TERM_TAC THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN
+  REPEAT STRIP_TAC THEN REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+  ASM_MESON_TAC[LE; ARITH_RULE `~(SUC k <= k)`]);;
+
+let DET_LINEAR_ROWS_VSUM = prove
+ (`!s a.
+         FINITE s
+         ==> det((lambda i. vsum s (a i)):real^N^N) =
+             sum {f | (!i. 1 <= i /\ i <= dimindex(:N) ==> f(i) IN s) /\
+                      !i. ~(1 <= i /\ i <= dimindex(:N)) ==> f(i) = i}
+                 (\f. det((lambda i. a i (f i)):real^N^N))`,
+  let lemma = prove
+   (`(lambda i. if i <= dimindex(:N) then x(i) else y(i)):real^N^N =
+     (lambda i. x(i))`,
+    SIMP_TAC[CART_EQ; LAMBDA_BETA]) in
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`s:num->bool`; `dimindex(:N)`] DET_LINEAR_ROWS_VSUM_LEMMA) THEN
+  ASM_REWRITE_TAC[LE_REFL; lemma] THEN SIMP_TAC[]);;
+
+let MATRIX_MUL_VSUM_ALT = prove
+ (`!A:real^N^N B:real^N^N. A ** B =
+                  lambda i. vsum (1..dimindex(:N)) (\k. A$i$k % B$k)`,
+  SIMP_TAC[matrix_mul; CART_EQ; LAMBDA_BETA; VECTOR_MUL_COMPONENT;
+           VSUM_COMPONENT]);;
+
+let DET_ROWS_MUL = prove
+ (`!a c. det((lambda i. c(i) % a(i)):real^N^N) =
+         product(1..dimindex(:N)) (\i. c(i)) *
+         det((lambda i. a(i)):real^N^N)`,
+  REPEAT GEN_TAC THEN SIMP_TAC[det; LAMBDA_BETA] THEN
+  SIMP_TAC[GSYM SUM_LMUL; FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+  MATCH_MP_TAC SUM_EQ THEN SIMP_TAC[FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+  X_GEN_TAC `p:num->num` THEN REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN
+  MATCH_MP_TAC(REAL_RING `b = c * d ==> s * b = c * s * d`) THEN
+  SIMP_TAC[GSYM PRODUCT_MUL_NUMSEG] THEN
+  MATCH_MP_TAC PRODUCT_EQ_NUMSEG THEN
+  ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG; VECTOR_MUL_COMPONENT]);;
+
+let DET_MUL = prove
+ (`!A B:real^N^N. det(A ** B) = det(A) * det(B)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[MATRIX_MUL_VSUM_ALT] THEN
+  SIMP_TAC[DET_LINEAR_ROWS_VSUM; FINITE_NUMSEG] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `sum {p | p permutes 1..dimindex(:N)}
+            (\f. det (lambda i. (A:real^N^N)$i$f i % (B:real^N^N)$f i))` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[DET_ROWS_MUL] THEN
+    MATCH_MP_TAC SUM_SUPERSET THEN
+    SIMP_TAC[FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN CONJ_TAC THENL
+     [MESON_TAC[permutes; IN_NUMSEG]; ALL_TAC] THEN
+    X_GEN_TAC `f:num->num` THEN REWRITE_TAC[permutes; IN_NUMSEG] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+    REWRITE_TAC[REAL_ENTIRE] THEN DISJ2_TAC THEN
+    MATCH_MP_TAC DET_IDENTICAL_ROWS THEN
+    MP_TAC(ISPECL [`1..dimindex(:N)`; `f:num->num`]
+       SURJECTIVE_IFF_INJECTIVE) THEN
+    ASM_REWRITE_TAC[SUBSET; IN_NUMSEG; FINITE_NUMSEG; FORALL_IN_IMAGE] THEN
+    MATCH_MP_TAC(TAUT `(~b ==> c) /\ (b ==> ~a) ==> (a <=> b) ==> c`) THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[NOT_FORALL_THM] THEN
+      REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+      SIMP_TAC[CART_EQ; LAMBDA_BETA; row; NOT_IMP];
+      ALL_TAC] THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN `!x y. (f:num->num)(x) = f(y) ==> x = y` ASSUME_TAC THENL
+     [REPEAT GEN_TAC THEN
+      ASM_CASES_TAC `1 <= x /\ x <= dimindex(:N)` THEN
+      ASM_CASES_TAC `1 <= y /\ y <= dimindex(:N)` THEN
+      ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  SIMP_TAC[det; REAL_MUL_SUM; FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+  MATCH_MP_TAC SUM_EQ THEN SIMP_TAC[FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+  X_GEN_TAC `p:num->num` THEN REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN
+  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV
+    [MATCH_MP SUM_PERMUTATIONS_COMPOSE_R (MATCH_MP PERMUTES_INVERSE th)]) THEN
+  MATCH_MP_TAC SUM_EQ THEN SIMP_TAC[FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+  X_GEN_TAC `q:num->num` THEN REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN
+  REWRITE_TAC[o_THM] THEN ONCE_REWRITE_TAC[AC REAL_MUL_AC
+   `(p * x) * (q * y) = (p * q) * (x * y)`] THEN
+  BINOP_TAC THENL
+   [SUBGOAL_THEN `sign(q o inverse p) = sign(p:num->num) * sign(q:num->num)`
+     (fun t -> SIMP_TAC[REAL_MUL_ASSOC; SIGN_IDEMPOTENT; REAL_MUL_LID; t]) THEN
+    ASM_MESON_TAC[SIGN_COMPOSE; PERMUTES_INVERSE; PERMUTATION_PERMUTES;
+                  FINITE_NUMSEG; SIGN_INVERSE; REAL_MUL_SYM];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV)
+   [MATCH_MP PRODUCT_PERMUTE_NUMSEG (ASSUME `p permutes 1..dimindex(:N)`)] THEN
+  SIMP_TAC[GSYM PRODUCT_MUL; FINITE_NUMSEG] THEN
+  MATCH_MP_TAC PRODUCT_EQ_NUMSEG THEN
+  ASM_SIMP_TAC[LAMBDA_BETA; LAMBDA_BETA_PERM; o_THM] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `(A:real^N^N)$i$p(i) * (B:real^N^N)$p(i)$q(i)` THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[VECTOR_MUL_COMPONENT; PERMUTES_IN_IMAGE; IN_NUMSEG];
+    ASM_MESON_TAC[PERMUTES_INVERSES]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relation to invertibility.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let INVERTIBLE_DET_NZ = prove
+ (`!A:real^N^N. invertible(A) <=> ~(det A = &0)`,
+  GEN_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[INVERTIBLE_RIGHT_INVERSE; LEFT_IMP_EXISTS_THM] THEN
+    GEN_TAC THEN DISCH_THEN(MP_TAC o AP_TERM `det:real^N^N->real`) THEN
+    REWRITE_TAC[DET_MUL; DET_I] THEN CONV_TAC REAL_RING;
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  REWRITE_TAC[INVERTIBLE_RIGHT_INVERSE] THEN
+  REWRITE_TAC[MATRIX_RIGHT_INVERTIBLE_INDEPENDENT_ROWS] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`c:num->real`; `i:num`] THEN STRIP_TAC THEN
+  MP_TAC(SPECL [`A:real^N^N`; `i:num`; `--(row i (A:real^N^N))`]
+    DET_ROW_SPAN) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN
+      `--(row i (A:real^N^N)) =
+       vsum ((1..dimindex(:N)) DELETE i) (\j. inv(c i) % c j % row j A)`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[VSUM_DELETE_CASES; FINITE_NUMSEG; IN_NUMSEG; VSUM_LMUL] THEN
+      ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV] THEN VECTOR_ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC SPAN_VSUM THEN
+    REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG; FINITE_DELETE; IN_DELETE] THEN
+    X_GEN_TAC `j:num` THEN STRIP_TAC THEN REPEAT(MATCH_MP_TAC SPAN_MUL) THEN
+    MATCH_MP_TAC(CONJUNCT1 SPAN_CLAUSES) THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN MATCH_MP_TAC DET_ZERO_ROW THEN
+  EXISTS_TAC `i:num` THEN
+  ASM_SIMP_TAC[row; CART_EQ; LAMBDA_BETA; VEC_COMPONENT;
+               VECTOR_ARITH `x + --x:real^N = vec 0`]);;
+
+let DET_EQ_0 = prove
+ (`!A:real^N^N. det(A) = &0 <=> ~invertible(A)`,
+  REWRITE_TAC[INVERTIBLE_DET_NZ]);;
+
+let MATRIX_MUL_LINV = prove
+ (`!A:real^N^N. ~(det A = &0) ==> matrix_inv A ** A = mat 1`,
+  SIMP_TAC[MATRIX_INV; DET_EQ_0]);;
+
+let MATRIX_MUL_RINV = prove
+ (`!A:real^N^N. ~(det A = &0) ==> A ** matrix_inv A = mat 1`,
+  SIMP_TAC[MATRIX_INV; DET_EQ_0]);;
+
+let DET_MATRIX_EQ_0 = prove
+ (`!f:real^N->real^N.
+        linear f
+        ==> (det(matrix f) = &0 <=>
+             ~(?g. linear g /\ f o g = I /\ g o f = I))`,
+  SIMP_TAC[DET_EQ_0; MATRIX_INVERTIBLE]);;
+
+let DET_MATRIX_EQ_0_LEFT = prove
+ (`!f:real^N->real^N.
+        linear f
+        ==> (det(matrix f) = &0 <=>
+             ~(?g. linear g /\ g o f = I))`,
+   SIMP_TAC[DET_MATRIX_EQ_0] THEN MESON_TAC[LINEAR_INVERSE_LEFT]);;
+
+let DET_MATRIX_EQ_0_RIGHT = prove
+ (`!f:real^N->real^N.
+        linear f
+        ==> (det(matrix f) = &0 <=>
+             ~(?g. linear g /\ f o g = I))`,
+   SIMP_TAC[DET_MATRIX_EQ_0] THEN MESON_TAC[LINEAR_INVERSE_LEFT]);;
+
+let DET_EQ_0_RANK = prove
+ (`!A:real^N^N. det A = &0 <=> rank A < dimindex(:N)`,
+  REWRITE_TAC[DET_EQ_0; INVERTIBLE_LEFT_INVERSE; GSYM FULL_RANK_INJECTIVE;
+              MATRIX_LEFT_INVERTIBLE_INJECTIVE] THEN
+  GEN_TAC THEN MP_TAC(ISPEC `A:real^N^N` RANK_BOUND) THEN
+  ARITH_TAC);;
+
+let HOMOGENEOUS_LINEAR_EQUATIONS_DET = prove
+ (`!A:real^N^N. (?x. ~(x = vec 0) /\ A ** x = vec 0) <=> det A = &0`,
+  GEN_TAC THEN
+  REWRITE_TAC[MATRIX_NONFULL_LINEAR_EQUATIONS_EQ; DET_EQ_0_RANK] THEN
+  MATCH_MP_TAC(ARITH_RULE `r <= MIN N N ==> (~(r = N) <=> r < N)`) THEN
+  REWRITE_TAC[RANK_BOUND]);;
+
+let INVERTIBLE_MATRIX_MUL = prove
+ (`!A:real^N^N B:real^N^N.
+        invertible(A ** B) <=> invertible A /\ invertible B`,
+  REWRITE_TAC[INVERTIBLE_DET_NZ; DET_MUL; DE_MORGAN_THM; REAL_ENTIRE]);;
+
+let MATRIX_INV_MUL = prove
+ (`!A:real^N^N B:real^N^N.
+        invertible A /\ invertible B
+        ==> matrix_inv(A ** B) = matrix_inv B ** matrix_inv A`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MATRIX_INV_UNIQUE THEN
+  ONCE_REWRITE_TAC[MATRIX_MUL_ASSOC] THEN
+  GEN_REWRITE_TAC (BINOP_CONV o LAND_CONV o LAND_CONV)
+   [GSYM MATRIX_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[MATRIX_MUL_LINV; DET_EQ_0; MATRIX_MUL_RID; MATRIX_MUL_RINV]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Cramer's rule.                                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let CRAMER_LEMMA_TRANSP = prove
+ (`!A:real^N^N x:real^N.
+        1 <= k /\ k <= dimindex(:N)
+        ==> det((lambda i. if i = k
+                           then vsum(1..dimindex(:N)) (\i. x$i % row i A)
+                           else row i A):real^N^N) =
+            x$k * det A`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `1..dimindex(:N) = k INSERT ((1..dimindex(:N)) DELETE k)`
+  SUBST1_TAC THENL [ASM_MESON_TAC[INSERT_DELETE; IN_NUMSEG]; ALL_TAC] THEN
+  SIMP_TAC[VSUM_CLAUSES; FINITE_NUMSEG; FINITE_DELETE; IN_DELETE] THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `(x:real^N)$k % row k (A:real^N^N) + s =
+    (x$k - &1) % row k A + row k A + s`] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) DET_ROW_ADD o lhand o snd) THEN
+  ASM_SIMP_TAC[DET_ROW_MUL] THEN DISCH_THEN(K ALL_TAC) THEN
+  MATCH_MP_TAC(REAL_RING `d = d' /\ e = d' ==> (c - &1) * d + e = c * d'`) THEN
+  CONJ_TAC THENL
+   [AP_TERM_TAC THEN ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[LAMBDA_BETA; row];
+    MATCH_MP_TAC DET_ROW_SPAN THEN ASM_REWRITE_TAC[] THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC SPAN_VSUM THEN
+    REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG; FINITE_DELETE; IN_DELETE] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC SPAN_MUL THEN
+    MATCH_MP_TAC(CONJUNCT1 SPAN_CLAUSES) THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[]]);;
+
+let CRAMER_LEMMA = prove
+ (`!A:real^N^N x:real^N.
+        1 <= k /\ k <= dimindex(:N)
+        ==> det((lambda i j. if j = k then (A**x)$i else A$i$j):real^N^N) =
+            x$k * det(A)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[MATRIX_MUL_VSUM] THEN
+  FIRST_ASSUM(MP_TAC o SYM o SPECL [`transp(A:real^N^N)`; `x:real^N`] o
+              MATCH_MP CRAMER_LEMMA_TRANSP) THEN
+  REWRITE_TAC[DET_TRANSP] THEN DISCH_THEN SUBST1_TAC THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM DET_TRANSP] THEN AP_TERM_TAC THEN
+  ASM_SIMP_TAC[CART_EQ; transp; LAMBDA_BETA; MATRIX_MUL_VSUM; row; column;
+        COND_COMPONENT; VECTOR_MUL_COMPONENT; VSUM_COMPONENT]);;
+
+let CRAMER = prove
+ (`!A:real^N^N x b.
+        ~(det(A) = &0)
+        ==> (A ** x = b <=>
+             x = lambda k.
+                   det((lambda i j. if j = k then b$i else A$i$j):real^N^N) /
+                   det(A))`,
+  GEN_TAC THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN GEN_TAC THEN MATCH_MP_TAC(MESON[]
+   `(?x. p(x)) /\ (!x. p(x) ==> x = a) ==> !x. p(x) <=> x = a`) THEN
+  CONJ_TAC THENL
+   [MP_TAC(SPEC `A:real^N^N` INVERTIBLE_DET_NZ) THEN
+    ASM_MESON_TAC[invertible; MATRIX_VECTOR_MUL_ASSOC; MATRIX_VECTOR_MUL_LID];
+    GEN_TAC THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+    ASM_SIMP_TAC[CART_EQ; CRAMER_LEMMA; LAMBDA_BETA; REAL_FIELD
+    `~(z = &0) ==> (x = y / z <=> x * z = y)`]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Variants of Cramer's rule for matrix-matrix multiplication.               *)
+(* ------------------------------------------------------------------------- *)
+
+let CRAMER_MATRIX_LEFT = prove
+ (`!A:real^N^N X:real^N^N B:real^N^N.
+        ~(det A = &0)
+        ==> (X ** A = B <=>
+             X = lambda k l.
+                   det((lambda i j. if j = l then B$k$i else A$j$i):real^N^N) /
+                   det A)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[CART_EQ] THEN
+  ASM_SIMP_TAC[MATRIX_MUL_COMPONENT; CRAMER; DET_TRANSP] THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN
+  REPLICATE_TAC 2 (AP_TERM_TAC THEN ABS_TAC THEN AP_TERM_TAC) THEN
+  AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; transp]);;
+
+let CRAMER_MATRIX_RIGHT = prove
+ (`!A:real^N^N X:real^N^N B:real^N^N.
+        ~(det A = &0)
+        ==> (A ** X = B <=>
+             X = lambda k l.
+                   det((lambda i j. if j = k then B$i$l else A$i$j):real^N^N) /
+                   det A)`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM TRANSP_EQ] THEN
+  REWRITE_TAC[MATRIX_TRANSP_MUL] THEN
+  ASM_SIMP_TAC[CRAMER_MATRIX_LEFT; DET_TRANSP] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM TRANSP_EQ] THEN
+  REWRITE_TAC[TRANSP_TRANSP] THEN AP_TERM_TAC THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; transp] THEN
+  REPEAT(GEN_TAC THEN STRIP_TAC) THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; transp]);;
+
+let CRAMER_MATRIX_RIGHT_INVERSE = prove
+ (`!A:real^N^N A':real^N^N.
+        A ** A' = mat 1 <=>
+        ~(det A = &0) /\
+        A' = lambda k l.
+                det((lambda i j. if j = k then if i = l then &1 else &0
+                                 else A$i$j):real^N^N) /
+                det A`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `det(A:real^N^N) = &0` THENL
+   [ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o AP_TERM `det:real^N^N->real`) THEN
+    ASM_REWRITE_TAC[DET_MUL; DET_I] THEN REAL_ARITH_TAC;
+    ASM_SIMP_TAC[CRAMER_MATRIX_RIGHT] THEN AP_TERM_TAC THEN
+    SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN
+    REPEAT(GEN_TAC THEN STRIP_TAC) THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA; mat]]);;
+
+let CRAMER_MATRIX_LEFT_INVERSE = prove
+ (`!A:real^N^N A':real^N^N.
+        A' ** A = mat 1 <=>
+        ~(det A = &0) /\
+        A' = lambda k l.
+                det((lambda i j. if j = l then if i = k then &1 else &0
+                                 else A$j$i):real^N^N) /
+                det A`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `det(A:real^N^N) = &0` THENL
+   [ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o AP_TERM `det:real^N^N->real`) THEN
+    ASM_REWRITE_TAC[DET_MUL; DET_I] THEN REAL_ARITH_TAC;
+    ASM_SIMP_TAC[CRAMER_MATRIX_LEFT] THEN AP_TERM_TAC THEN
+    SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN
+    REPEAT(GEN_TAC THEN STRIP_TAC) THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA; mat] THEN MESON_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Cofactors and their relationship to inverse matrices.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let cofactor = new_definition
+  `(cofactor:real^N^N->real^N^N) A =
+        lambda i j. det((lambda k l. if k = i /\ l = j then &1
+                                     else if k = i \/ l = j then &0
+                                     else A$k$l):real^N^N)`;;
+
+let COFACTOR_TRANSP = prove
+ (`!A:real^N^N. cofactor(transp A) = transp(cofactor A)`,
+  SIMP_TAC[cofactor; CART_EQ; LAMBDA_BETA; transp] THEN REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM DET_TRANSP] THEN
+  AP_TERM_TAC THEN SIMP_TAC[cofactor; CART_EQ; LAMBDA_BETA; transp] THEN
+  MESON_TAC[]);;
+
+let COFACTOR_COLUMN = prove
+ (`!A:real^N^N.
+        cofactor A =
+        lambda i j. det((lambda k l. if l = j then if k = i then &1 else &0
+                                     else A$k$l):real^N^N)`,
+  GEN_TAC THEN CONV_TAC SYM_CONV THEN
+  SIMP_TAC[cofactor; CART_EQ; LAMBDA_BETA] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+  REWRITE_TAC[det] THEN MATCH_MP_TAC SUM_EQ THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN GEN_TAC THEN
+  DISCH_TAC THEN AP_TERM_TAC THEN
+  ASM_CASES_TAC `(p:num->num) i = j` THENL
+   [MATCH_MP_TAC PRODUCT_EQ THEN
+    X_GEN_TAC `k:num` THEN SIMP_TAC[IN_NUMSEG; LAMBDA_BETA] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `(p:num->num) k IN 1..dimindex(:N)` MP_TAC THENL
+     [ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG];
+      SIMP_TAC[LAMBDA_BETA; IN_NUMSEG] THEN STRIP_TAC] THEN
+    ASM_CASES_TAC `(p:num->num) k = j` THEN ASM_REWRITE_TAC[] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[];
+    MATCH_MP_TAC(REAL_ARITH `s = &0 /\ t = &0 ==> s = t`) THEN
+    ASM_SIMP_TAC[PRODUCT_EQ_0; FINITE_NUMSEG] THEN CONJ_TAC THEN
+    EXISTS_TAC `inverse (p:num->num) j` THEN
+    ASM_SIMP_TAC[IN_NUMSEG; LAMBDA_BETA] THEN
+    (SUBGOAL_THEN `inverse(p:num->num) j IN 1..dimindex(:N)` MP_TAC THENL
+      [ASM_MESON_TAC[PERMUTES_IN_IMAGE; PERMUTES_INVERSE; IN_NUMSEG];
+       SIMP_TAC[LAMBDA_BETA; IN_NUMSEG] THEN STRIP_TAC] THEN
+     SUBGOAL_THEN `(p:num->num)(inverse p j) = j` SUBST1_TAC THENL
+      [ASM_MESON_TAC[PERMUTES_INVERSES; IN_NUMSEG];
+       ASM_SIMP_TAC[LAMBDA_BETA] THEN
+        ASM_MESON_TAC[PERMUTES_INVERSE_EQ]])]);;
+
+let COFACTOR_ROW = prove
+ (`!A:real^N^N.
+        cofactor A =
+        lambda i j. det((lambda k l. if k = i then if l = j then &1 else &0
+                                     else A$k$l):real^N^N)`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM TRANSP_EQ] THEN
+  REWRITE_TAC[GSYM COFACTOR_TRANSP] THEN
+  SIMP_TAC[COFACTOR_COLUMN; CART_EQ; LAMBDA_BETA; transp] THEN
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM DET_TRANSP] THEN
+  AP_TERM_TAC THEN SIMP_TAC[cofactor; CART_EQ; LAMBDA_BETA; transp]);;
+
+let MATRIX_RIGHT_INVERSE_COFACTOR = prove
+ (`!A:real^N^N A':real^N^N.
+        A ** A' = mat 1 <=>
+        ~(det A = &0) /\ A' = inv(det A) %% transp(cofactor A)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[CRAMER_MATRIX_RIGHT_INVERSE] THEN
+  ASM_CASES_TAC `det(A:real^N^N) = &0` THEN ASM_REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN SIMP_TAC[CART_EQ; LAMBDA_BETA; MATRIX_CMUL_COMPONENT] THEN
+  X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+  X_GEN_TAC `l:num` THEN STRIP_TAC THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] real_div] THEN AP_TERM_TAC THEN
+  ASM_SIMP_TAC[transp; COFACTOR_COLUMN; LAMBDA_BETA] THEN
+  AP_TERM_TAC THEN SIMP_TAC[CART_EQ; LAMBDA_BETA]);;
+
+let MATRIX_LEFT_INVERSE_COFACTOR = prove
+ (`!A:real^N^N A':real^N^N.
+        A' ** A = mat 1 <=>
+        ~(det A = &0) /\ A' = inv(det A) %% transp(cofactor A)`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[MATRIX_LEFT_RIGHT_INVERSE] THEN
+  REWRITE_TAC[MATRIX_RIGHT_INVERSE_COFACTOR]);;
+
+let MATRIX_INV_COFACTOR = prove
+ (`!A. ~(det A = &0) ==> matrix_inv A = inv(det A) %% transp(cofactor A)`,
+  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP MATRIX_MUL_LINV) THEN
+  SIMP_TAC[MATRIX_LEFT_INVERSE_COFACTOR]);;
+
+let COFACTOR_MATRIX_INV = prove
+ (`!A:real^N^N. ~(det A = &0) ==> cofactor A = det(A) %% transp(matrix_inv A)`,
+  SIMP_TAC[MATRIX_INV_COFACTOR; TRANSP_MATRIX_CMUL; TRANSP_TRANSP] THEN
+  SIMP_TAC[MATRIX_CMUL_ASSOC; REAL_MUL_RINV; MATRIX_CMUL_LID]);;
+
+let COFACTOR_I = prove
+ (`cofactor(mat 1:real^N^N) = mat 1`,
+  SIMP_TAC[COFACTOR_MATRIX_INV; DET_I; REAL_OF_NUM_EQ; ARITH_EQ] THEN
+  REWRITE_TAC[MATRIX_INV_I; MATRIX_CMUL_LID; TRANSP_MAT]);;
+
+let DET_COFACTOR_EXPANSION = prove
+ (`!A:real^N^N i.
+        1 <= i /\ i <= dimindex(:N)
+        ==> det A = sum (1..dimindex(:N))
+                        (\j. A$i$j * (cofactor A)$i$j)`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[COFACTOR_COLUMN; LAMBDA_BETA; det] THEN
+  REWRITE_TAC[GSYM SUM_LMUL] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) SUM_SWAP o rand o snd) THEN
+  ANTS_TAC THENL [SIMP_TAC[FINITE_PERMUTATIONS; FINITE_NUMSEG]; ALL_TAC] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  MATCH_MP_TAC SUM_EQ THEN REWRITE_TAC[FORALL_IN_GSPEC] THEN
+  GEN_TAC THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a * s * p:real = s * a * p`] THEN
+  REWRITE_TAC[SUM_LMUL] THEN AP_TERM_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC
+   `sum (1..dimindex (:N))
+        (\j. (A:real^N^N)$i$j *
+             product
+              (inverse p j INSERT ((1..dimindex(:N)) DELETE (inverse p j)))
+              (\k. if k = inverse p j then if k = i then &1 else &0
+                   else A$k$(p k)))` THEN
+  CONJ_TAC THENL
+   [SIMP_TAC[PRODUCT_CLAUSES; FINITE_DELETE; FINITE_PERMUTATIONS;
+             FINITE_NUMSEG; IN_DELETE] THEN
+    SUBGOAL_THEN `!j. inverse (p:num->num) j = i <=> j = p i`
+     (fun th -> REWRITE_TAC[th])
+    THENL [ASM_MESON_TAC[PERMUTES_INVERSES; IN_NUMSEG]; ALL_TAC] THEN
+    REWRITE_TAC[REAL_ARITH
+     `x * (if p then &1 else &0) * y = if p then x * y else &0`] THEN
+    SIMP_TAC[SUM_DELTA] THEN COND_CASES_TAC THENL
+     [ALL_TAC; ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG]] THEN
+    SUBGOAL_THEN
+     `1..dimindex(:N) = i INSERT ((1..dimindex(:N)) DELETE i)`
+     (fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [th])
+    THENL
+     [ASM_SIMP_TAC[IN_NUMSEG; SET_RULE `s = x INSERT (s DELETE x) <=> x IN s`];
+      SIMP_TAC[PRODUCT_CLAUSES; FINITE_DELETE; FINITE_NUMSEG; IN_DELETE] THEN
+      AP_TERM_TAC THEN MATCH_MP_TAC(MESON[PRODUCT_EQ]
+       `s = t /\ (!x. x IN t ==> f x = g x) ==> product s f = product t g`) THEN
+      SIMP_TAC[IN_DELETE] THEN ASM_MESON_TAC[PERMUTES_INVERSES; IN_NUMSEG]];
+    MATCH_MP_TAC SUM_EQ_NUMSEG THEN X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+    REWRITE_TAC[] THEN AP_TERM_TAC THEN MATCH_MP_TAC(MESON[PRODUCT_EQ]
+     `s = t /\ (!x. x IN t ==> f x = g x) ==> product s f = product t g`) THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[SET_RULE `x INSERT (s DELETE x) = s <=> x IN s`] THEN
+      ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG; PERMUTES_INVERSE];
+      X_GEN_TAC `k:num` THEN REWRITE_TAC[IN_NUMSEG] THEN STRIP_TAC THEN
+      SUBGOAL_THEN `(p:num->num) k IN 1..dimindex(:N)` MP_TAC THENL
+       [ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG]; ALL_TAC] THEN
+      SIMP_TAC[LAMBDA_BETA; IN_NUMSEG] THEN
+      ASM_MESON_TAC[PERMUTES_INVERSES; IN_NUMSEG]]]);;
+
+let MATRIX_MUL_RIGHT_COFACTOR = prove
+ (`!A:real^N^N. A ** transp(cofactor A) = det(A) %% mat 1`,
+  GEN_TAC THEN
+  SIMP_TAC[CART_EQ; MATRIX_CMUL_COMPONENT; mat;
+           matrix_mul; LAMBDA_BETA; transp] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  X_GEN_TAC `i':num` THEN STRIP_TAC THEN
+  COND_CASES_TAC THEN
+  ASM_SIMP_TAC[GSYM DET_COFACTOR_EXPANSION; REAL_MUL_RID] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `det((lambda k l. if k = i' then (A:real^N^N)$i$l
+                               else A$k$l):real^N^N)` THEN
+  CONJ_TAC THENL
+   [MP_TAC(GEN `A:real^N^N`
+     (ISPECL [`A:real^N^N`; `i':num`] DET_COFACTOR_EXPANSION)) THEN
+    ASM_REWRITE_TAC[] THEN ASM_SIMP_TAC[] THEN DISCH_THEN(K ALL_TAC) THEN
+    MATCH_MP_TAC SUM_EQ THEN X_GEN_TAC `j:num` THEN
+    REWRITE_TAC[IN_NUMSEG] THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[LAMBDA_BETA] THEN AP_TERM_TAC THEN
+    ASM_SIMP_TAC[cofactor; LAMBDA_BETA] THEN AP_TERM_TAC THEN
+    SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN ASM_MESON_TAC[];
+    REWRITE_TAC[REAL_MUL_RZERO] THEN MATCH_MP_TAC DET_IDENTICAL_ROWS THEN
+    MAP_EVERY EXISTS_TAC [`i:num`;` i':num`] THEN
+    ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA; row]]);;
+
+let MATRIX_MUL_LEFT_COFACTOR = prove
+ (`!A:real^N^N. transp(cofactor A) ** A = det(A) %% mat 1`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM TRANSP_EQ] THEN
+  REWRITE_TAC[MATRIX_TRANSP_MUL] THEN
+  ONCE_REWRITE_TAC[GSYM COFACTOR_TRANSP] THEN
+  REWRITE_TAC[MATRIX_MUL_RIGHT_COFACTOR; TRANSP_MATRIX_CMUL] THEN
+  REWRITE_TAC[DET_TRANSP; TRANSP_MAT]);;
+
+let COFACTOR_CMUL = prove
+ (`!A:real^N^N c. cofactor(c %% A) = c pow (dimindex(:N) - 1) %% cofactor A`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[CART_EQ; cofactor; LAMBDA_BETA; MATRIX_CMUL_COMPONENT] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+  REWRITE_TAC[det; GSYM SUM_LMUL] THEN
+  MATCH_MP_TAC SUM_EQ THEN REWRITE_TAC[FORALL_IN_GSPEC] THEN
+  X_GEN_TAC `p:num->num` THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a * b * c:real = b * a * c`] THEN
+  AP_TERM_TAC THEN
+  SUBGOAL_THEN
+   `1..dimindex (:N) = i INSERT ((1..dimindex (:N)) DELETE i)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_INSERT; IN_NUMSEG; IN_DELETE] THEN ASM_ARITH_TAC;
+    SIMP_TAC[PRODUCT_CLAUSES; FINITE_DELETE; FINITE_NUMSEG; IN_DELETE]] THEN
+  SUBGOAL_THEN
+   `1 <= (p:num->num) i /\ p i <= dimindex(:N)`
+  ASSUME_TAC THENL
+   [FIRST_ASSUM(MP_TAC o MATCH_MP PERMUTES_IMAGE) THEN
+    REWRITE_TAC[EXTENSION; IN_IMAGE; IN_NUMSEG] THEN ASM SET_TAC[];
+    ASM_SIMP_TAC[LAMBDA_BETA]] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_RZERO] THEN
+  SUBGOAL_THEN
+   `dimindex(:N) - 1 = CARD((1..dimindex(:N)) DELETE i)`
+  SUBST1_TAC THENL
+   [ASM_SIMP_TAC[CARD_DELETE; FINITE_NUMSEG; IN_NUMSEG; CARD_NUMSEG_1];
+    ASM_SIMP_TAC[REAL_MUL_LID; GSYM PRODUCT_CONST; FINITE_NUMSEG;
+                 FINITE_DELETE; GSYM PRODUCT_MUL]] THEN
+  MATCH_MP_TAC PRODUCT_EQ THEN
+  X_GEN_TAC `k:num` THEN REWRITE_TAC[IN_DELETE; IN_NUMSEG] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `1 <= (p:num->num) k /\ p k <= dimindex(:N)`
+  ASSUME_TAC THENL
+   [FIRST_ASSUM(MP_TAC o MATCH_MP PERMUTES_IMAGE) THEN
+    REWRITE_TAC[EXTENSION; IN_IMAGE; IN_NUMSEG] THEN ASM SET_TAC[];
+    ASM_SIMP_TAC[LAMBDA_BETA] THEN REAL_ARITH_TAC]);;
+
+let COFACTOR_0 = prove
+ (`cofactor(mat 0:real^N^N) = if dimindex(:N) = 1 then mat 1 else mat 0`,
+  MP_TAC(ISPECL [`mat 1:real^N^N`; `&0`] COFACTOR_CMUL) THEN
+  REWRITE_TAC[MATRIX_CMUL_LZERO; COFACTOR_I; REAL_POW_ZERO] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  SIMP_TAC[DIMINDEX_GE_1; ARITH_RULE `1 <= n ==> (n - 1 = 0 <=> n = 1)`] THEN
+  COND_CASES_TAC THEN REWRITE_TAC[MATRIX_CMUL_LZERO; MATRIX_CMUL_LID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Explicit formulas for low dimensions.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let PRODUCT_1 = prove
+ (`product(1..1) f = f(1)`,
+  REWRITE_TAC[PRODUCT_SING_NUMSEG]);;
+
+let PRODUCT_2 = prove
+ (`!t. product(1..2) t = t(1) * t(2)`,
+  REWRITE_TAC[num_CONV `2`; PRODUCT_CLAUSES_NUMSEG] THEN
+  REWRITE_TAC[PRODUCT_SING_NUMSEG; ARITH; REAL_MUL_ASSOC]);;
+
+let PRODUCT_3 = prove
+ (`!t. product(1..3) t = t(1) * t(2) * t(3)`,
+  REWRITE_TAC[num_CONV `3`; num_CONV `2`; PRODUCT_CLAUSES_NUMSEG] THEN
+  REWRITE_TAC[PRODUCT_SING_NUMSEG; ARITH; REAL_MUL_ASSOC]);;
+
+let PRODUCT_4 = prove
+ (`!t. product(1..4) t = t(1) * t(2) * t(3) * t(4)`,
+  REWRITE_TAC[num_CONV `4`; num_CONV `3`; num_CONV `2`;
+              PRODUCT_CLAUSES_NUMSEG] THEN
+  REWRITE_TAC[PRODUCT_SING_NUMSEG; ARITH; REAL_MUL_ASSOC]);;
+
+let DET_1 = prove
+ (`!A:real^1^1. det A = A$1$1`,
+  REWRITE_TAC[det; DIMINDEX_1; PERMUTES_SING; NUMSEG_SING] THEN
+  REWRITE_TAC[SUM_SING; SET_RULE `{x | x = a} = {a}`; PRODUCT_SING] THEN
+  REWRITE_TAC[SIGN_I; I_THM] THEN REAL_ARITH_TAC);;
+
+let DET_2 = prove
+ (`!A:real^2^2. det A = A$1$1 * A$2$2 - A$1$2 * A$2$1`,
+  GEN_TAC THEN REWRITE_TAC[det; DIMINDEX_2] THEN
+  CONV_TAC(LAND_CONV(RATOR_CONV(ONCE_DEPTH_CONV NUMSEG_CONV))) THEN
+  SIMP_TAC[SUM_OVER_PERMUTATIONS_INSERT; FINITE_INSERT; FINITE_EMPTY;
+           ARITH_EQ; IN_INSERT; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[PERMUTES_EMPTY; SUM_SING; SET_RULE `{x | x = a} = {a}`] THEN
+  REWRITE_TAC[SWAP_REFL; I_O_ID] THEN
+  REWRITE_TAC[GSYM(NUMSEG_CONV `1..2`); SUM_2] THEN
+  SIMP_TAC[SUM_CLAUSES; FINITE_INSERT; FINITE_EMPTY;
+           ARITH_EQ; IN_INSERT; NOT_IN_EMPTY] THEN
+  SIMP_TAC[SIGN_COMPOSE; PERMUTATION_SWAP] THEN
+  REWRITE_TAC[SIGN_SWAP; ARITH] THEN REWRITE_TAC[PRODUCT_2] THEN
+  REWRITE_TAC[o_THM; swap; ARITH] THEN REAL_ARITH_TAC);;
+
+let DET_3 = prove
+ (`!A:real^3^3.
+        det(A) = A$1$1 * A$2$2 * A$3$3 +
+                 A$1$2 * A$2$3 * A$3$1 +
+                 A$1$3 * A$2$1 * A$3$2 -
+                 A$1$1 * A$2$3 * A$3$2 -
+                 A$1$2 * A$2$1 * A$3$3 -
+                 A$1$3 * A$2$2 * A$3$1`,
+  GEN_TAC THEN REWRITE_TAC[det; DIMINDEX_3] THEN
+  CONV_TAC(LAND_CONV(RATOR_CONV(ONCE_DEPTH_CONV NUMSEG_CONV))) THEN
+  SIMP_TAC[SUM_OVER_PERMUTATIONS_INSERT; FINITE_INSERT; FINITE_EMPTY;
+           ARITH_EQ; IN_INSERT; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[PERMUTES_EMPTY; SUM_SING; SET_RULE `{x | x = a} = {a}`] THEN
+  REWRITE_TAC[SWAP_REFL; I_O_ID] THEN
+  REWRITE_TAC[GSYM(NUMSEG_CONV `1..3`); SUM_3] THEN
+  SIMP_TAC[SUM_CLAUSES; FINITE_INSERT; FINITE_EMPTY;
+           ARITH_EQ; IN_INSERT; NOT_IN_EMPTY] THEN
+  SIMP_TAC[SIGN_COMPOSE; PERMUTATION_SWAP] THEN
+  REWRITE_TAC[SIGN_SWAP; ARITH] THEN REWRITE_TAC[PRODUCT_3] THEN
+  REWRITE_TAC[o_THM; swap; ARITH] THEN REAL_ARITH_TAC);;
+
+let DET_4 = prove
+ (`!A:real^4^4.
+        det(A) = A$1$1 * A$2$2 * A$3$3 * A$4$4 +
+                 A$1$1 * A$2$3 * A$3$4 * A$4$2 +
+                 A$1$1 * A$2$4 * A$3$2 * A$4$3 +
+                 A$1$2 * A$2$1 * A$3$4 * A$4$3 +
+                 A$1$2 * A$2$3 * A$3$1 * A$4$4 +
+                 A$1$2 * A$2$4 * A$3$3 * A$4$1 +
+                 A$1$3 * A$2$1 * A$3$2 * A$4$4 +
+                 A$1$3 * A$2$2 * A$3$4 * A$4$1 +
+                 A$1$3 * A$2$4 * A$3$1 * A$4$2 +
+                 A$1$4 * A$2$1 * A$3$3 * A$4$2 +
+                 A$1$4 * A$2$2 * A$3$1 * A$4$3 +
+                 A$1$4 * A$2$3 * A$3$2 * A$4$1 -
+                 A$1$1 * A$2$2 * A$3$4 * A$4$3 -
+                 A$1$1 * A$2$3 * A$3$2 * A$4$4 -
+                 A$1$1 * A$2$4 * A$3$3 * A$4$2 -
+                 A$1$2 * A$2$1 * A$3$3 * A$4$4 -
+                 A$1$2 * A$2$3 * A$3$4 * A$4$1 -
+                 A$1$2 * A$2$4 * A$3$1 * A$4$3 -
+                 A$1$3 * A$2$1 * A$3$4 * A$4$2 -
+                 A$1$3 * A$2$2 * A$3$1 * A$4$4 -
+                 A$1$3 * A$2$4 * A$3$2 * A$4$1 -
+                 A$1$4 * A$2$1 * A$3$2 * A$4$3 -
+                 A$1$4 * A$2$2 * A$3$3 * A$4$1 -
+                 A$1$4 * A$2$3 * A$3$1 * A$4$2`,
+  let lemma = prove
+   (`(sum {3,4} f = f 3 + f 4) /\
+     (sum {2,3,4} f = f 2 + f 3 + f 4)`,
+    SIMP_TAC[SUM_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN
+    REWRITE_TAC[ARITH_EQ; IN_INSERT; NOT_IN_EMPTY] THEN REAL_ARITH_TAC) in
+  GEN_TAC THEN REWRITE_TAC[det; DIMINDEX_4] THEN
+  CONV_TAC(LAND_CONV(RATOR_CONV(ONCE_DEPTH_CONV NUMSEG_CONV))) THEN
+  SIMP_TAC[SUM_OVER_PERMUTATIONS_INSERT; FINITE_INSERT; FINITE_EMPTY;
+           ARITH_EQ; IN_INSERT; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[PERMUTES_EMPTY; SUM_SING; SET_RULE `{x | x = a} = {a}`] THEN
+  REWRITE_TAC[SWAP_REFL; I_O_ID] THEN
+  REWRITE_TAC[GSYM(NUMSEG_CONV `1..4`); SUM_4; lemma] THEN
+  SIMP_TAC[SIGN_COMPOSE; PERMUTATION_SWAP; PERMUTATION_COMPOSE] THEN
+  REWRITE_TAC[SIGN_SWAP; ARITH] THEN REWRITE_TAC[PRODUCT_4] THEN
+  REWRITE_TAC[o_THM; swap; ARITH] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Existence of the characteristic polynomial.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let CHARACTERISTIC_POLYNOMIAL = prove
+ (`!A:real^N^N.
+        ?a. a(dimindex(:N)) = &1 /\
+            !x. det(x %% mat 1 - A) =
+                sum (0..dimindex(:N)) (\i. a i * x pow i)`,
+  GEN_TAC THEN REWRITE_TAC[det] THEN
+  SUBGOAL_THEN
+   `!p n. IMAGE p (1..dimindex(:N)) SUBSET 1..dimindex(:N) /\
+          n <= dimindex(:N)
+          ==> ?a. a n = (if !i. 1 <= i /\ i <= n ==> p i = i then &1 else &0) /\
+                  !x. product (1..n) (\i. (x %% mat 1 - A:real^N^N)$i$p i) =
+                      sum (0..n) (\i. a i * x pow i)`
+  MP_TAC THENL
+   [GEN_TAC THEN REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    DISCH_TAC THEN INDUCT_TAC THEN
+    REWRITE_TAC[PRODUCT_CLAUSES_NUMSEG] THEN
+    REWRITE_TAC[LE_0; ARITH_EQ; ARITH_RULE `1 <= SUC n`] THENL
+     [EXISTS_TAC `\i. if i = 0 then &1 else &0` THEN
+      SIMP_TAC[real_pow; REAL_MUL_LID; ARITH_RULE `1 <= i ==> ~(i <= 0)`;
+               SUM_CLAUSES_NUMSEG];
+      DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o check (is_imp o concl)) THEN
+      ASM_SIMP_TAC[ARITH_RULE `SUC n <= N ==> n <= N`] THEN
+      DISCH_THEN(X_CHOOSE_THEN `a:num->real` STRIP_ASSUME_TAC) THEN
+      ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[MATRIX_SUB_COMPONENT; MATRIX_CMUL_COMPONENT] THEN
+      ASSUME_TAC(ARITH_RULE `1 <= SUC n`) THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; IN_NUMSEG] THEN
+      DISCH_THEN(MP_TAC o SPEC `SUC n`) THEN ASM_REWRITE_TAC[] THEN
+      STRIP_TAC THEN ASM_SIMP_TAC[MAT_COMPONENT] THEN
+      ASM_CASES_TAC `p(SUC n) = SUC n` THEN ASM_REWRITE_TAC[] THENL
+       [ALL_TAC;
+        EXISTS_TAC `\i. if i <= n
+                        then --((A:real^N^N)$(SUC n)$(p(SUC n))) * a i
+                        else &0` THEN
+        SIMP_TAC[SUM_CLAUSES_NUMSEG; LE_0; ARITH_RULE `~(SUC n <= n)`] THEN
+        CONJ_TAC THENL
+         [COND_CASES_TAC THEN REWRITE_TAC[] THEN
+          FIRST_X_ASSUM(MP_TAC o SPEC `SUC n`) THEN
+          ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC;
+          REWRITE_TAC[REAL_MUL_LZERO; REAL_ADD_RID; GSYM SUM_RMUL] THEN
+          GEN_TAC THEN MATCH_MP_TAC SUM_EQ_NUMSEG THEN REWRITE_TAC[] THEN
+          REAL_ARITH_TAC]] THEN
+      REWRITE_TAC[REAL_SUB_LDISTRIB; REAL_MUL_RID] THEN
+      REWRITE_TAC[GSYM SUM_RMUL] THEN EXISTS_TAC
+      `\i. (if i = 0 then &0 else a(i - 1)) -
+           (if i = SUC n then &0 else (A:real^N^N)$(SUC n)$(SUC n) * a i)` THEN
+      ASM_REWRITE_TAC[NOT_SUC; LE; SUC_SUB1; REAL_SUB_RZERO] THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[LE_REFL]; ALL_TAC] THEN
+      REWRITE_TAC[REAL_SUB_RDISTRIB; SUM_SUB_NUMSEG] THEN
+      GEN_TAC THEN BINOP_TAC THENL
+       [SIMP_TAC[SUM_CLAUSES_LEFT; ARITH_RULE `0 <= SUC n`] THEN
+        REWRITE_TAC[ADD1; SUM_OFFSET; ARITH_RULE `~(i + 1 = 0)`; ADD_SUB] THEN
+        REWRITE_TAC[REAL_MUL_LZERO; REAL_POW_ADD; REAL_POW_1; REAL_ADD_LID];
+        SIMP_TAC[SUM_CLAUSES_NUMSEG; LE_0; REAL_MUL_LZERO; REAL_ADD_RID] THEN
+        SIMP_TAC[ARITH_RULE `i <= n ==> ~(i = SUC n)`]] THEN
+      MATCH_MP_TAC SUM_EQ_NUMSEG THEN REWRITE_TAC[REAL_ADD_LID; REAL_MUL_AC]];
+    GEN_REWRITE_TAC LAND_CONV [SWAP_FORALL_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `dimindex(:N)`) THEN REWRITE_TAC[LE_REFL] THEN
+    GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `a:(num->num)->num->real` THEN DISCH_TAC] THEN
+  EXISTS_TAC
+   `\i:num. sum {p | p permutes 1..dimindex(:N)} (\p. sign p * a p i)` THEN
+  REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MP_TAC(ISPECL
+     [`\p:num->num. sign p * a p (dimindex(:N))`;
+      `{p | p permutes 1..dimindex(:N)}`;
+      `I:num->num`] SUM_DELETE) THEN
+    SIMP_TAC[IN_ELIM_THM; PERMUTES_I; FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+    MATCH_MP_TAC(REAL_ARITH `k = &1 /\ s' = &0 ==> s' = s - k ==> s = &1`) THEN
+    CONJ_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `I:num->num`) THEN
+      SIMP_TAC[IMAGE_I; SUBSET_REFL; SIGN_I; I_THM; REAL_MUL_LID];
+      MATCH_MP_TAC SUM_EQ_0 THEN X_GEN_TAC `p:num->num` THEN
+      REWRITE_TAC[IN_ELIM_THM; IN_DELETE] THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `p:num->num`) THEN ANTS_TAC THENL
+       [ASM_MESON_TAC[PERMUTES_IMAGE; SUBSET_REFL]; ALL_TAC] THEN
+      COND_CASES_TAC THEN SIMP_TAC[REAL_MUL_RZERO] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [permutes]) THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [FUN_EQ_THM]) THEN
+      REWRITE_TAC[IN_NUMSEG; I_THM] THEN ASM_MESON_TAC[]];
+    X_GEN_TAC `x:real` THEN REWRITE_TAC[GSYM SUM_RMUL] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) SUM_SWAP o rand o snd) THEN
+    SIMP_TAC[FINITE_PERMUTATIONS; FINITE_NUMSEG] THEN
+    DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC SUM_EQ THEN
+    X_GEN_TAC `p:num->num` THEN REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN
+    REWRITE_TAC[GSYM REAL_MUL_ASSOC; SUM_LMUL] THEN AP_TERM_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `p:num->num`) THEN ANTS_TAC THENL
+     [ASM_MESON_TAC[PERMUTES_IMAGE; SUBSET_REFL]; SIMP_TAC[]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Grassmann-Plucker relations for n = 2, n = 3 and n = 4.                   *)
+(* I have a proof of the general n case but the proof is a bit long and the  *)
+(* result doesn't seem generally useful enough to go in the main theories.   *)
+(* ------------------------------------------------------------------------- *)
+
+let GRASSMANN_PLUCKER_2 = prove
+ (`!x1 x2 y1 y2:real^2.
+        det(vector[x1;x2]) * det(vector[y1;y2]) =
+          det(vector[y1;x2]) * det(vector[x1;y2]) +
+          det(vector[y2;x2]) * det(vector[y1;x1])`,
+  REWRITE_TAC[DET_2; VECTOR_2] THEN REAL_ARITH_TAC);;
+
+let GRASSMANN_PLUCKER_3 = prove
+ (`!x1 x2 x3 y1 y2 y3:real^3.
+        det(vector[x1;x2;x3]) * det(vector[y1;y2;y3]) =
+          det(vector[y1;x2;x3]) * det(vector[x1;y2;y3]) +
+          det(vector[y2;x2;x3]) * det(vector[y1;x1;y3]) +
+          det(vector[y3;x2;x3]) * det(vector[y1;y2;x1])`,
+  REWRITE_TAC[DET_3; VECTOR_3] THEN REAL_ARITH_TAC);;
+
+let GRASSMANN_PLUCKER_4 = prove
+ (`!x1 x2 x3 x4:real^4 y1 y2 y3 y4:real^4.
+        det(vector[x1;x2;x3;x4]) * det(vector[y1;y2;y3;y4]) =
+          det(vector[y1;x2;x3;x4]) * det(vector[x1;y2;y3;y4]) +
+          det(vector[y2;x2;x3;x4]) * det(vector[y1;x1;y3;y4]) +
+          det(vector[y3;x2;x3;x4]) * det(vector[y1;y2;x1;y4]) +
+          det(vector[y4;x2;x3;x4]) * det(vector[y1;y2;y3;x1])`,
+  REWRITE_TAC[DET_4; VECTOR_4] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Determinants of integer matrices.                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let INTEGER_PRODUCT = prove
+ (`!f s. (!x. x IN s ==> integer(f x)) ==> integer(product s f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PRODUCT_CLOSED THEN
+  ASM_REWRITE_TAC[INTEGER_CLOSED]);;
+
+let INTEGER_SIGN = prove
+ (`!p. integer(sign p)`,
+  SIMP_TAC[sign; COND_RAND; INTEGER_CLOSED; COND_ID]);;
+
+let INTEGER_DET = prove
+ (`!M:real^N^N.
+        (!i j. 1 <= i /\ i <= dimindex(:N) /\
+               1 <= j /\ j <= dimindex(:N)
+               ==> integer(M$i$j))
+        ==> integer(det M)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[det] THEN
+  MATCH_MP_TAC INTEGER_SUM THEN X_GEN_TAC `p:num->num` THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN
+  MATCH_MP_TAC INTEGER_MUL THEN REWRITE_TAC[INTEGER_SIGN] THEN
+  MATCH_MP_TAC INTEGER_PRODUCT THEN REWRITE_TAC[IN_NUMSEG] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_MESON_TAC[IN_NUMSEG; permutes]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Diagonal matrices (for arbitrary rectangular matrix, not just square).    *)
+(* ------------------------------------------------------------------------- *)
+
+let diagonal_matrix = new_definition
+ `diagonal_matrix(A:real^N^M) <=>
+        !i j. 1 <= i /\ i <= dimindex(:M) /\
+              1 <= j /\ j <= dimindex(:N) /\
+              ~(i = j)
+              ==> A$i$j = &0`;;
+
+let TRANSP_DIAGONAL_MATRIX = prove
+ (`!A:real^N^N. diagonal_matrix A ==> transp A = A`,
+  GEN_TAC THEN REWRITE_TAC[diagonal_matrix; CART_EQ; TRANSP_COMPONENT] THEN
+  STRIP_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN X_GEN_TAC `j:num` THEN
+  STRIP_TAC THEN ASM_CASES_TAC `i:num = j` THEN ASM_SIMP_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Orthogonality of a transformation and matrix.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let orthogonal_transformation = new_definition
+ `orthogonal_transformation(f:real^N->real^N) <=>
+        linear f /\ !v w. f(v) dot f(w) = v dot w`;;
+
+let ORTHOGONAL_TRANSFORMATION = prove
+ (`!f. orthogonal_transformation f <=> linear f /\ !v. norm(f v) = norm(v)`,
+  GEN_TAC THEN REWRITE_TAC[orthogonal_transformation] THEN EQ_TAC THENL
+   [MESON_TAC[vector_norm]; SIMP_TAC[DOT_NORM] THEN MESON_TAC[LINEAR_ADD]]);;
+
+let ORTHOGONAL_TRANSFORMATION_COMPOSE = prove
+ (`!f g. orthogonal_transformation f /\ orthogonal_transformation g
+         ==> orthogonal_transformation(f o g)`,
+  SIMP_TAC[orthogonal_transformation; LINEAR_COMPOSE; o_THM]);;
+
+let orthogonal_matrix = new_definition
+ `orthogonal_matrix(Q:real^N^N) <=>
+      transp(Q) ** Q = mat 1 /\ Q ** transp(Q) = mat 1`;;
+
+let ORTHOGONAL_MATRIX = prove
+ (`orthogonal_matrix(Q:real^N^N) <=> transp(Q) ** Q = mat 1`,
+  MESON_TAC[MATRIX_LEFT_RIGHT_INVERSE; orthogonal_matrix]);;
+
+let ORTHOGONAL_MATRIX_ALT = prove
+ (`!A:real^N^N. orthogonal_matrix A <=> A ** transp A = mat 1`,
+  MESON_TAC[MATRIX_LEFT_RIGHT_INVERSE; orthogonal_matrix]);;
+
+let ORTHOGONAL_MATRIX_ID = prove
+ (`orthogonal_matrix(mat 1)`,
+  REWRITE_TAC[orthogonal_matrix; TRANSP_MAT; MATRIX_MUL_LID]);;
+
+let ORTHOGONAL_MATRIX_MUL = prove
+ (`!A B. orthogonal_matrix A /\ orthogonal_matrix B
+         ==> orthogonal_matrix(A ** B)`,
+  REWRITE_TAC[orthogonal_matrix; MATRIX_TRANSP_MUL] THEN
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM MATRIX_MUL_ASSOC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [MATRIX_MUL_ASSOC] THEN
+  ASM_REWRITE_TAC[MATRIX_MUL_LID; MATRIX_MUL_RID]);;
+
+let ORTHOGONAL_TRANSFORMATION_MATRIX = prove
+ (`!f:real^N->real^N.
+     orthogonal_transformation f <=> linear f /\ orthogonal_matrix(matrix f)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[orthogonal_transformation; ORTHOGONAL_MATRIX] THEN
+    STRIP_TAC THEN ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`basis i:real^N`; `basis j:real^N`]) THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP MATRIX_WORKS th)]) THEN
+    REWRITE_TAC[DOT_MATRIX_VECTOR_MUL] THEN
+    ABBREV_TAC `A = transp (matrix f) ** matrix(f:real^N->real^N)` THEN
+    ASM_SIMP_TAC[matrix_mul; columnvector; rowvector; basis; LAMBDA_BETA;
+             SUM_DELTA; DIMINDEX_1; LE_REFL; dot; IN_NUMSEG; mat;
+             MESON[REAL_MUL_LID; REAL_MUL_LZERO; REAL_MUL_RID; REAL_MUL_RZERO]
+              `(if b then &1 else &0) * x = (if b then x else &0) /\
+               x * (if b then &1 else &0) = (if b then x else &0)`];
+    REWRITE_TAC[orthogonal_matrix; ORTHOGONAL_TRANSFORMATION; NORM_EQ] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP MATRIX_WORKS th)]) THEN
+    ASM_REWRITE_TAC[DOT_MATRIX_VECTOR_MUL] THEN
+    SIMP_TAC[DOT_MATRIX_PRODUCT; MATRIX_MUL_LID]]);;
+
+let ORTHOGONAL_MATRIX_TRANSFORMATION = prove
+ (`!A:real^N^N. orthogonal_matrix A <=> orthogonal_transformation(\x. A ** x)`,
+  REWRITE_TAC[ORTHOGONAL_TRANSFORMATION_MATRIX; MATRIX_VECTOR_MUL_LINEAR] THEN
+  REWRITE_TAC[MATRIX_OF_MATRIX_VECTOR_MUL]);;
+
+let ORTHOGONAL_MATRIX_MATRIX = prove
+ (`!f:real^N->real^N.
+    orthogonal_transformation f ==> orthogonal_matrix(matrix f)`,
+  SIMP_TAC[ORTHOGONAL_TRANSFORMATION_MATRIX]);;
+
+let DET_ORTHOGONAL_MATRIX = prove
+ (`!Q. orthogonal_matrix Q ==> det(Q) = &1 \/ det(Q) = -- &1`,
+  GEN_TAC THEN REWRITE_TAC[REAL_RING `x = &1 \/ x = -- &1 <=> x * x = &1`] THEN
+  GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o RAND_CONV) [GSYM DET_TRANSP] THEN
+  SIMP_TAC[GSYM DET_MUL; orthogonal_matrix; DET_I]);;
+
+let ORTHOGONAL_MATRIX_TRANSP = prove
+ (`!A:real^N^N. orthogonal_matrix(transp A) <=> orthogonal_matrix A`,
+  REWRITE_TAC[orthogonal_matrix; TRANSP_TRANSP; CONJ_ACI]);;
+
+let MATRIX_MUL_LTRANSP_DOT_COLUMN = prove
+ (`!A:real^N^M. transp A ** A = (lambda i j. (column i A) dot (column j A))`,
+  SIMP_TAC[matrix_mul; CART_EQ; LAMBDA_BETA; transp; dot; column]);;
+
+let MATRIX_MUL_RTRANSP_DOT_ROW = prove
+ (`!A:real^N^M. A ** transp A = (lambda i j. (row i A) dot (row j A))`,
+  SIMP_TAC[matrix_mul; CART_EQ; LAMBDA_BETA; transp; dot; row]);;
+
+let ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS = prove
+ (`!A:real^N^N.
+        orthogonal_matrix A <=>
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> norm(column i A) = &1) /\
+        (!i j. 1 <= i /\ i <= dimindex(:N) /\
+               1 <= j /\ j <= dimindex(:N) /\ ~(i = j)
+               ==> orthogonal (column i A) (column j A))`,
+  REWRITE_TAC[ORTHOGONAL_MATRIX] THEN
+  SIMP_TAC[MATRIX_MUL_LTRANSP_DOT_COLUMN; CART_EQ; mat; LAMBDA_BETA] THEN
+  REWRITE_TAC[orthogonal; NORM_EQ_1] THEN MESON_TAC[]);;
+
+let ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS = prove
+ (`!A:real^N^N.
+        orthogonal_matrix A <=>
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> norm(row i A) = &1) /\
+        (!i j. 1 <= i /\ i <= dimindex(:N) /\
+               1 <= j /\ j <= dimindex(:N) /\ ~(i = j)
+               ==> orthogonal (row i A) (row j A))`,
+  ONCE_REWRITE_TAC[GSYM ORTHOGONAL_MATRIX_TRANSP] THEN
+  SIMP_TAC[ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS; COLUMN_TRANSP]);;
+
+let ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_INDEXED = prove
+ (`!A:real^N^N.
+        orthogonal_matrix A <=>
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> norm(row i A) = &1) /\
+        pairwise (\i j. orthogonal (row i A) (row j A)) (1..dimindex(:N))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[ORTHOGONAL_MATRIX_ALT] THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; pairwise; MAT_COMPONENT] THEN
+  SIMP_TAC[MATRIX_MUL_RTRANSP_DOT_ROW; IN_NUMSEG; LAMBDA_BETA] THEN
+  REWRITE_TAC[NORM_EQ_SQUARE; REAL_POS] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[orthogonal] THEN
+  MESON_TAC[]);;
+
+let ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_PAIRWISE = prove
+ (`!A:real^N^N.
+        orthogonal_matrix A <=>
+        CARD(rows A) = dimindex(:N) /\
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> norm(row i A) = &1) /\
+        pairwise orthogonal (rows A)`,
+  REWRITE_TAC[rows; ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_INDEXED] THEN
+  GEN_TAC THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+  REWRITE_TAC[PAIRWISE_IMAGE; GSYM numseg] THEN
+  MATCH_MP_TAC(TAUT `(p ==> (q <=> r /\ s)) ==> (p /\ q <=> r /\ p /\ s)`) THEN
+  DISCH_TAC THEN GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o RAND_CONV)
+    [GSYM CARD_NUMSEG_1] THEN
+  SIMP_TAC[CARD_IMAGE_EQ_INJ; FINITE_NUMSEG] THEN
+  REWRITE_TAC[pairwise; IN_NUMSEG] THEN
+  ASM_MESON_TAC[ORTHOGONAL_REFL; NORM_ARITH `~(norm(vec 0:real^N) = &1)`]);;
+
+let ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_SPAN = prove
+ (`!A:real^N^N.
+        orthogonal_matrix A <=>
+        span(rows A) = (:real^N) /\
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> norm(row i A) = &1) /\
+        pairwise orthogonal (rows A)`,
+  GEN_TAC THEN REWRITE_TAC[ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_PAIRWISE] THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
+   [MATCH_MP_TAC(SET_RULE `UNIV SUBSET s ==> s = UNIV`) THEN
+    MATCH_MP_TAC CARD_GE_DIM_INDEPENDENT THEN
+    ASM_REWRITE_TAC[DIM_UNIV; SUBSET_UNIV; LE_REFL];
+    CONV_TAC SYM_CONV THEN REWRITE_TAC[GSYM DIM_UNIV] THEN
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN REWRITE_TAC[DIM_SPAN] THEN
+    MATCH_MP_TAC DIM_EQ_CARD] THEN
+  MATCH_MP_TAC PAIRWISE_ORTHOGONAL_INDEPENDENT THEN
+  ASM_REWRITE_TAC[rows; IN_ELIM_THM] THEN
+  ASM_MESON_TAC[NORM_ARITH `~(norm(vec 0:real^N) = &1)`]);;
+
+let ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_INDEXED = prove
+ (`!A:real^N^N.
+      orthogonal_matrix A <=>
+      (!i. 1 <= i /\ i <= dimindex(:N) ==> norm(column i A) = &1) /\
+      pairwise (\i j. orthogonal (column i A) (column j A)) (1..dimindex(:N))`,
+  ONCE_REWRITE_TAC[GSYM ORTHOGONAL_MATRIX_TRANSP] THEN
+  REWRITE_TAC[ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_INDEXED] THEN
+  SIMP_TAC[ROW_TRANSP; ROWS_TRANSP; pairwise; IN_NUMSEG]);;
+
+let ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_PAIRWISE = prove
+ (`!A:real^N^N.
+        orthogonal_matrix A <=>
+        CARD(columns A) = dimindex(:N) /\
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> norm(column i A) = &1) /\
+        pairwise orthogonal (columns A)`,
+  ONCE_REWRITE_TAC[GSYM ORTHOGONAL_MATRIX_TRANSP] THEN
+  REWRITE_TAC[ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_PAIRWISE] THEN
+  SIMP_TAC[ROW_TRANSP; ROWS_TRANSP]);;
+
+let ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_SPAN = prove
+ (`!A:real^N^N.
+        orthogonal_matrix A <=>
+        span(columns A) = (:real^N) /\
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> norm(column i A) = &1) /\
+        pairwise orthogonal (columns A)`,
+  ONCE_REWRITE_TAC[GSYM ORTHOGONAL_MATRIX_TRANSP] THEN
+  REWRITE_TAC[ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_SPAN] THEN
+  SIMP_TAC[ROW_TRANSP; ROWS_TRANSP]);;
+
+let ORTHOGONAL_MATRIX_2 = prove
+ (`!A:real^2^2. orthogonal_matrix A <=>
+                A$1$1 pow 2 + A$2$1 pow 2 = &1 /\
+                A$1$2 pow 2 + A$2$2 pow 2 = &1 /\
+                A$1$1 * A$1$2 + A$2$1 * A$2$2 = &0`,
+  SIMP_TAC[orthogonal_matrix; CART_EQ; matrix_mul; LAMBDA_BETA;
+           TRANSP_COMPONENT; MAT_COMPONENT] THEN
+  REWRITE_TAC[DIMINDEX_2; FORALL_2; SUM_2] THEN
+  CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC REAL_RING);;
+
+let ORTHOGONAL_MATRIX_2_ALT = prove
+ (`!A:real^2^2. orthogonal_matrix A <=>
+                A$1$1 pow 2 + A$2$1 pow 2 = &1 /\
+                (A$1$1 = A$2$2 /\ A$1$2 = --(A$2$1) \/
+                 A$1$1 = --(A$2$2) /\ A$1$2 = A$2$1)`,
+  REWRITE_TAC[ORTHOGONAL_MATRIX_2] THEN CONV_TAC REAL_RING);;
+
+let ORTHOGONAL_MATRIX_INV = prove
+ (`!A:real^N^N. orthogonal_matrix A ==> matrix_inv A = transp A`,
+  MESON_TAC[orthogonal_matrix; MATRIX_INV_UNIQUE]);;
+
+let ORTHOGONAL_TRANSFORMATION_ORTHOGONAL_EIGENVECTORS = prove
+ (`!f:real^N->real^N v w a b.
+        orthogonal_transformation f /\ f v = a % v /\ f w = b % w /\ ~(a = b)
+        ==> orthogonal v w`,
+  REWRITE_TAC[orthogonal_transformation] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(fun th ->
+    MP_TAC(SPECL [`v:real^N`; `v:real^N`] th) THEN
+    MP_TAC(SPECL [`v:real^N`; `w:real^N`] th) THEN
+    MP_TAC(SPECL [`w:real^N`; `w:real^N`] th)) THEN
+  ASM_REWRITE_TAC[DOT_LMUL; DOT_RMUL; orthogonal] THEN
+  REWRITE_TAC[REAL_MUL_ASSOC; REAL_RING `x * y = y <=> x = &1 \/ y = &0`] THEN
+  REWRITE_TAC[DOT_EQ_0] THEN
+  ASM_CASES_TAC `v:real^N = vec 0` THEN ASM_REWRITE_TAC[DOT_LZERO] THEN
+  ASM_CASES_TAC `w:real^N = vec 0` THEN ASM_REWRITE_TAC[DOT_RZERO] THEN
+  ASM_CASES_TAC `(v:real^N) dot w = &0` THEN ASM_REWRITE_TAC[] THEN
+  UNDISCH_TAC `~(a:real = b)` THEN CONV_TAC REAL_RING);;
+
+let ORTHOGONAL_MATRIX_ORTHOGONAL_EIGENVECTORS = prove
+ (`!A:real^N^N v w a b.
+        orthogonal_matrix A /\ A ** v = a % v /\ A ** w = b % w /\ ~(a = b)
+        ==> orthogonal v w`,
+  REWRITE_TAC[ORTHOGONAL_MATRIX_TRANSFORMATION;
+              ORTHOGONAL_TRANSFORMATION_ORTHOGONAL_EIGENVECTORS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Linearity of scaling, and hence isometry, that preserves origin.          *)
+(* ------------------------------------------------------------------------- *)
+
+let SCALING_LINEAR = prove
+ (`!f:real^M->real^N c.
+        (f(vec 0) = vec 0) /\ (!x y. dist(f x,f y) = c * dist(x,y))
+        ==> linear(f)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `!v w. ((f:real^M->real^N) v) dot (f w) = c pow 2 * (v dot w)`
+  ASSUME_TAC THENL
+   [FIRST_ASSUM(MP_TAC o GEN `v:real^M` o
+      SPECL [`v:real^M`; `vec 0 :real^M`]) THEN
+    REWRITE_TAC[dist] THEN ASM_REWRITE_TAC[VECTOR_SUB_RZERO] THEN
+    DISCH_TAC THEN ASM_REWRITE_TAC[DOT_NORM_NEG; GSYM dist] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[linear; VECTOR_EQ] THEN
+  ASM_REWRITE_TAC[DOT_LADD; DOT_RADD; DOT_LMUL; DOT_RMUL] THEN
+  REAL_ARITH_TAC);;
+
+let ISOMETRY_LINEAR = prove
+ (`!f:real^M->real^N.
+        (f(vec 0) = vec 0) /\ (!x y. dist(f x,f y) = dist(x,y))
+        ==> linear(f)`,
+  MESON_TAC[SCALING_LINEAR; REAL_MUL_LID]);;
+
+let ISOMETRY_IMP_AFFINITY = prove
+ (`!f:real^M->real^N.
+        (!x y. dist(f x,f y) = dist(x,y))
+        ==> ?h. linear h /\ !x. f(x) = f(vec 0) + h(x)`,
+  REPEAT STRIP_TAC THEN
+  EXISTS_TAC `\x. (f:real^M->real^N) x - f(vec 0)` THEN
+  REWRITE_TAC[VECTOR_ARITH `a + (x - a):real^N = x`] THEN
+  MATCH_MP_TAC ISOMETRY_LINEAR THEN REWRITE_TAC[VECTOR_SUB_REFL] THEN
+  ASM_REWRITE_TAC[NORM_ARITH `dist(x - a:real^N,y - a) = dist(x,y)`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence another formulation of orthogonal transformation.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let ORTHOGONAL_TRANSFORMATION_ISOMETRY = prove
+ (`!f:real^N->real^N.
+        orthogonal_transformation f <=>
+        (f(vec 0) = vec 0) /\ (!x y. dist(f x,f y) = dist(x,y))`,
+  GEN_TAC THEN REWRITE_TAC[ORTHOGONAL_TRANSFORMATION] THEN EQ_TAC THENL
+   [MESON_TAC[LINEAR_0; LINEAR_SUB; dist]; STRIP_TAC] THEN
+  ASM_SIMP_TAC[ISOMETRY_LINEAR] THEN X_GEN_TAC `x:real^N` THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `vec 0:real^N`]) THEN
+  ASM_REWRITE_TAC[dist; VECTOR_SUB_RZERO]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Can extend an isometry from unit sphere.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let ISOMETRY_SPHERE_EXTEND = prove
+ (`!f:real^N->real^N.
+        (!x. norm(x) = &1 ==> norm(f x) = &1) /\
+        (!x y. norm(x) = &1 /\ norm(y) = &1 ==> dist(f x,f y) = dist(x,y))
+        ==> ?g. orthogonal_transformation g /\
+                (!x. norm(x) = &1 ==> g(x) = f(x))`,
+  let lemma = prove
+   (`!x:real^N y:real^N x':real^N y':real^N x0 y0 x0' y0'.
+          x = norm(x) % x0 /\ y = norm(y) % y0 /\
+          x' = norm(x) % x0' /\ y' = norm(y) % y0' /\
+          norm(x0) = &1 /\ norm(x0') = &1 /\ norm(y0) = &1 /\ norm(y0') = &1 /\
+          norm(x0' - y0') = norm(x0 - y0)
+          ==> norm(x' - y') = norm(x - y)`,
+    REPEAT GEN_TAC THEN
+    MAP_EVERY ABBREV_TAC [`a = norm(x:real^N)`; `b = norm(y:real^N)`] THEN
+    REPLICATE_TAC 4 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    ASM_REWRITE_TAC[] THEN REWRITE_TAC[NORM_EQ; NORM_EQ_1] THEN
+    REWRITE_TAC[DOT_LSUB; DOT_RSUB; DOT_LMUL; DOT_RMUL] THEN
+    REWRITE_TAC[DOT_SYM] THEN CONV_TAC REAL_RING) in
+  REPEAT STRIP_TAC THEN
+  EXISTS_TAC `\x. if x = vec 0 then vec 0
+                  else norm(x) % (f:real^N->real^N)(inv(norm x) % x)` THEN
+  REWRITE_TAC[ORTHOGONAL_TRANSFORMATION_ISOMETRY] THEN
+  SIMP_TAC[VECTOR_MUL_LID; REAL_INV_1] THEN CONJ_TAC THENL
+   [ALL_TAC; MESON_TAC[NORM_0; REAL_ARITH `~(&1 = &0)`]] THEN
+  REPEAT GEN_TAC THEN REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+  REWRITE_TAC[dist; VECTOR_SUB_LZERO; VECTOR_SUB_RZERO; NORM_NEG; NORM_MUL;
+              REAL_ABS_NORM] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM REAL_EQ_RDIV_EQ; NORM_POS_LT] THEN
+  ASM_SIMP_TAC[REAL_DIV_REFL; REAL_LT_IMP_NZ; NORM_EQ_0] THEN
+  TRY(FIRST_X_ASSUM MATCH_MP_TAC) THEN
+  REWRITE_TAC[NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+  ASM_SIMP_TAC[REAL_MUL_LINV; NORM_EQ_0] THEN
+  MATCH_MP_TAC lemma THEN MAP_EVERY EXISTS_TAC
+   [`inv(norm x) % x:real^N`; `inv(norm y) % y:real^N`;
+    `(f:real^N->real^N) (inv (norm x) % x)`;
+    `(f:real^N->real^N) (inv (norm y) % y)`] THEN
+  REWRITE_TAC[NORM_MUL; VECTOR_MUL_ASSOC; REAL_ABS_INV; REAL_ABS_NORM] THEN
+  ASM_SIMP_TAC[REAL_MUL_LINV; REAL_MUL_RINV; NORM_EQ_0] THEN
+  ASM_REWRITE_TAC[GSYM dist; VECTOR_MUL_LID] THEN
+  REPEAT CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[NORM_MUL; VECTOR_MUL_ASSOC; REAL_ABS_INV; REAL_ABS_NORM] THEN
+  ASM_SIMP_TAC[REAL_MUL_LINV; REAL_MUL_RINV; NORM_EQ_0]);;
+
+let ORTHOGONAL_TRANSFORMATION_LINEAR = prove
+ (`!f:real^N->real^N. orthogonal_transformation f ==> linear f`,
+  SIMP_TAC[orthogonal_transformation]);;
+
+let ORTHOGONAL_TRANSFORMATION_INJECTIVE = prove
+ (`!f:real^N->real^N.
+        orthogonal_transformation f ==> !x y. f x = f y ==> x = y`,
+  SIMP_TAC[LINEAR_INJECTIVE_0; ORTHOGONAL_TRANSFORMATION; GSYM NORM_EQ_0]);;
+
+let ORTHOGONAL_TRANSFORMATION_SURJECTIVE = prove
+ (`!f:real^N->real^N.
+        orthogonal_transformation f ==> !y. ?x. f x = y`,
+  MESON_TAC[LINEAR_INJECTIVE_IMP_SURJECTIVE;
+            ORTHOGONAL_TRANSFORMATION_INJECTIVE; orthogonal_transformation]);;
+
+let ORTHOGONAL_TRANSFORMATION_INVERSE_o = prove
+ (`!f:real^N->real^N.
+        orthogonal_transformation f
+        ==> ?g. orthogonal_transformation g /\ g o f = I /\ f o g = I`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP ORTHOGONAL_TRANSFORMATION_LINEAR) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP ORTHOGONAL_TRANSFORMATION_INJECTIVE) THEN
+  MP_TAC(ISPEC `f:real^N->real^N` LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `g:real^N->real^N` THEN  STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^N->real^N`; `g:real^N->real^N`]
+    LINEAR_INVERSE_LEFT) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  ASM_REWRITE_TAC[ORTHOGONAL_TRANSFORMATION] THEN X_GEN_TAC `v:real^N` THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `norm((f:real^N->real^N)((g:real^N->real^N) v))` THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION]; ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[FUN_EQ_THM; o_THM; I_THM]) THEN
+  ASM_REWRITE_TAC[]);;
+
+let ORTHOGONAL_TRANSFORMATION_INVERSE = prove
+ (`!f:real^N->real^N.
+        orthogonal_transformation f
+        ==> ?g. orthogonal_transformation g /\
+                (!x. g(f x) = x) /\ (!y. f(g y) = y)`,
+  GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP ORTHOGONAL_TRANSFORMATION_INVERSE_o) THEN
+  REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM]);;
+
+let ORTHOGONAL_TRANSFORMATION_ID = prove
+ (`orthogonal_transformation(\x. x)`,
+  REWRITE_TAC[orthogonal_transformation; LINEAR_ID]);;
+
+let ORTHOGONAL_TRANSFORMATION_I = prove
+ (`orthogonal_transformation I`,
+  REWRITE_TAC[I_DEF; ORTHOGONAL_TRANSFORMATION_ID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* We can find an orthogonal matrix taking any unit vector to any other.     *)
+(* ------------------------------------------------------------------------- *)
+
+let FINITE_INDEX_NUMSEG_SPECIAL = prove
+ (`!s a:A.
+        FINITE s /\ a IN s
+        ==> ?f. (!i j. i IN 1..CARD s /\ j IN 1..CARD s /\ f i = f j
+                       ==> i = j) /\
+                s = IMAGE f (1..CARD s) /\
+                f 1 = a`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [FINITE_INDEX_NUMSEG]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:num->A` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `?k. k IN 1..CARD(s:A->bool) /\ (a:A) = f k`
+  STRIP_ASSUME_TAC THENL[ASM SET_TAC[]; ALL_TAC] THEN
+  EXISTS_TAC `(f:num->A) o swap(1,k)` THEN
+  SUBGOAL_THEN `1 IN 1..CARD(s:A->bool)` ASSUME_TAC THENL
+   [REWRITE_TAC[IN_NUMSEG; LE_REFL; ARITH_RULE `1 <= x <=> ~(x = 0)`] THEN
+    ASM_SIMP_TAC[CARD_EQ_0; ARITH_EQ] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[o_THM; swap] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  UNDISCH_THEN `s = IMAGE (f:num->A) (1..CARD(s:A->bool))`
+   (fun th -> GEN_REWRITE_TAC LAND_CONV [th]) THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; o_THM] THEN
+  X_GEN_TAC `b:A` THEN EQ_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `i:num` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `swap(1,k) i` THEN
+  REWRITE_TAC[swap] THEN ASM_MESON_TAC[swap]);;
+
+let ORTHOGONAL_MATRIX_EXISTS_BASIS = prove
+ (`!a:real^N.
+        norm(a) = &1
+        ==> ?A. orthogonal_matrix A /\ A**(basis 1) = a`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP VECTOR_IN_ORTHONORMAL_BASIS) THEN
+  REWRITE_TAC[HAS_SIZE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `a:real^N`]
+   FINITE_INDEX_NUMSEG_SPECIAL) THEN ASM_REWRITE_TAC[IN_NUMSEG] THEN
+  REWRITE_TAC[TAUT `a /\ b ==> c <=> c \/ ~a \/ ~b`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:num->real^N`
+   (CONJUNCTS_THEN2 ASSUME_TAC (CONJUNCTS_THEN2 (ASSUME_TAC o SYM)
+     ASSUME_TAC))) THEN
+  EXISTS_TAC `(lambda i j. ((f j):real^N)$i):real^N^N` THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; matrix_vector_mul; BASIS_COMPONENT;
+           IN_NUMSEG] THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN SIMP_TAC[REAL_MUL_RZERO; SUM_DELTA] THEN
+  ASM_REWRITE_TAC[IN_NUMSEG; REAL_MUL_RID; LE_REFL; DIMINDEX_GE_1] THEN
+  REWRITE_TAC[ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS] THEN
+  SIMP_TAC[column; LAMBDA_BETA] THEN CONJ_TAC THENL
+   [X_GEN_TAC `i:num` THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `norm((f:num->real^N) i)` THEN CONJ_TAC THENL
+     [AP_TERM_TAC THEN ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA];
+      ASM_MESON_TAC[IN_IMAGE; IN_NUMSEG]];
+    MAP_EVERY X_GEN_TAC [`i:num`; `j:num`] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `orthogonal ((f:num->real^N) i) (f j)` MP_TAC THENL
+     [ASM_MESON_TAC[pairwise; IN_IMAGE; IN_NUMSEG]; ALL_TAC] THEN
+    MATCH_MP_TAC EQ_IMP THEN BINOP_TAC THEN
+    ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA]]);;
+
+let ORTHOGONAL_TRANSFORMATION_EXISTS_1 = prove
+ (`!a b:real^N.
+        norm(a) = &1 /\ norm(b) = &1
+        ==> ?f. orthogonal_transformation f /\ f a = b`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `b:real^N` ORTHOGONAL_MATRIX_EXISTS_BASIS) THEN
+  MP_TAC(ISPEC `a:real^N` ORTHOGONAL_MATRIX_EXISTS_BASIS) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `A:real^N^N` (STRIP_ASSUME_TAC o GSYM)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real^N^N` (STRIP_ASSUME_TAC o GSYM)) THEN
+  EXISTS_TAC `\x:real^N. ((B:real^N^N) ** transp(A:real^N^N)) ** x` THEN
+  REWRITE_TAC[ORTHOGONAL_TRANSFORMATION_MATRIX; MATRIX_VECTOR_MUL_LINEAR;
+              MATRIX_OF_MATRIX_VECTOR_MUL] THEN
+  ASM_SIMP_TAC[ORTHOGONAL_MATRIX_MUL; ORTHOGONAL_MATRIX_TRANSP] THEN
+  REWRITE_TAC[GSYM MATRIX_VECTOR_MUL_ASSOC] THEN AP_TERM_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[ORTHOGONAL_MATRIX]) THEN
+  ASM_REWRITE_TAC[MATRIX_VECTOR_MUL_ASSOC; MATRIX_VECTOR_MUL_LID]);;
+
+let ORTHOGONAL_TRANSFORMATION_EXISTS = prove
+ (`!a b:real^N.
+        norm(a) = norm(b) ==> ?f. orthogonal_transformation f /\ f a = b`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `b:real^N = vec 0` THEN
+  ASM_SIMP_TAC[NORM_0; NORM_EQ_0] THENL
+   [MESON_TAC[ORTHOGONAL_TRANSFORMATION_ID]; ALL_TAC] THEN
+  ASM_CASES_TAC `a:real^N = vec 0` THENL
+   [ASM_MESON_TAC[NORM_0; NORM_EQ_0]; ALL_TAC] THEN
+  DISCH_TAC THEN
+  MP_TAC(ISPECL [`inv(norm a) % a:real^N`; `inv(norm b) % b:real^N`]
+                ORTHOGONAL_TRANSFORMATION_EXISTS_1) THEN
+  REWRITE_TAC[NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+  ASM_SIMP_TAC[NORM_EQ_0; REAL_MUL_LINV] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^N->real^N` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP LINEAR_CMUL o
+              MATCH_MP ORTHOGONAL_TRANSFORMATION_LINEAR) THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+    `a % x:real^N = a % y <=> a % (x - y) = vec 0`] THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; REAL_INV_EQ_0; NORM_EQ_0; VECTOR_SUB_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Or indeed, taking any subspace to another of suitable dimension.          *)
+(* ------------------------------------------------------------------------- *)
+
+let ORTHOGONAL_TRANSFORMATION_INTO_SUBSPACE = prove
+ (`!s t:real^N->bool.
+        subspace s /\ subspace t /\ dim s <= dim t
+        ==> ?f. orthogonal_transformation f /\ IMAGE f s SUBSET t`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `t:real^N->bool` ORTHONORMAL_BASIS_SUBSPACE) THEN
+  MP_TAC(ISPEC `s:real^N->bool` ORTHONORMAL_BASIS_SUBSPACE) THEN
+  ASM_REWRITE_TAC[HAS_SIZE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `c:real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`c:real^N->bool`; `(:real^N)`] ORTHONORMAL_EXTENSION) THEN
+  MP_TAC(ISPECL [`b:real^N->bool`; `(:real^N)`] ORTHONORMAL_EXTENSION) THEN
+  ASM_REWRITE_TAC[UNION_UNIV; SPAN_UNIV; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `b':real^N->bool` THEN STRIP_TAC THEN
+  X_GEN_TAC `c':real^N->bool` THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `independent(b UNION b':real^N->bool) /\
+    independent(c UNION c':real^N->bool)`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC PAIRWISE_ORTHOGONAL_INDEPENDENT THEN
+    ASM_REWRITE_TAC[IN_UNION] THEN
+    ASM_MESON_TAC[NORM_ARITH `~(norm(vec 0:real^N) = &1)`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `FINITE(b UNION b':real^N->bool) /\
+                FINITE(c UNION c':real^N->bool)`
+  MP_TAC THENL
+   [ASM_SIMP_TAC[PAIRWISE_ORTHOGONAL_IMP_FINITE];
+    REWRITE_TAC[FINITE_UNION] THEN STRIP_TAC] THEN
+  SUBGOAL_THEN
+   `?f:real^N->real^N.
+        (!x y. x IN b UNION b' /\ y IN b UNION b' ==> (f x = f y <=> x = y)) /\
+        IMAGE f b SUBSET c /\
+        IMAGE f (b UNION b') SUBSET c UNION c'`
+   (X_CHOOSE_THEN `fb:real^N->real^N` STRIP_ASSUME_TAC)
+  THENL
+   [MP_TAC(ISPECL [`b:real^N->bool`; `c:real^N->bool`]
+        CARD_LE_INJ) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; INJECTIVE_ON_ALT] THEN
+    X_GEN_TAC `f:real^N->real^N` THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`b':real^N->bool`;
+                   `(c UNION c') DIFF IMAGE (f:real^N->real^N) b`]
+        CARD_LE_INJ) THEN
+    ANTS_TAC THENL
+     [ASM_SIMP_TAC[FINITE_UNION; FINITE_DIFF] THEN
+      W(MP_TAC o PART_MATCH (lhs o rand) CARD_DIFF o rand o snd) THEN
+      ASM_REWRITE_TAC[FINITE_UNION] THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; DISCH_THEN SUBST1_TAC] THEN
+      MATCH_MP_TAC(ARITH_RULE `a + b:num = c ==> a <= c - b`) THEN
+      W(MP_TAC o PART_MATCH (lhs o rand) CARD_IMAGE_INJ o
+        rand o lhs o snd) THEN
+      ANTS_TAC THENL [ASM_MESON_TAC[]; DISCH_THEN SUBST1_TAC] THEN
+      W(MP_TAC o PART_MATCH (rhs o rand) CARD_UNION o lhs o snd) THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; DISCH_THEN(SUBST1_TAC o SYM)] THEN
+      GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [UNION_COMM] THEN
+      MATCH_MP_TAC(MESON[LE_ANTISYM]
+       `(FINITE s /\ CARD s <= CARD t) /\
+        (FINITE t /\ CARD t <= CARD s) ==> CARD s = CARD t`) THEN
+      CONJ_TAC THEN MATCH_MP_TAC INDEPENDENT_SPAN_BOUND THEN
+      ASM_REWRITE_TAC[FINITE_UNION; SUBSET_UNIV];
+      DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^N` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `\x. if x IN b then (f:real^N->real^N) x else g x` THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`fb:real^N->real^N`; `b UNION b':real^N->bool`]
+    LINEAR_INDEPENDENT_EXTEND) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^N->real^N` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ASM_REWRITE_TAC[ORTHOGONAL_TRANSFORMATION];
+    REWRITE_TAC[SYM(ASSUME `span b:real^N->bool = s`)] THEN
+    ASM_SIMP_TAC[GSYM SPAN_LINEAR_IMAGE] THEN
+    REWRITE_TAC[SYM(ASSUME `span c:real^N->bool = t`)] THEN
+    MATCH_MP_TAC SPAN_MONO THEN ASM SET_TAC[]] THEN
+  SUBGOAL_THEN
+   `!v. v IN UNIV ==> norm((f:real^N->real^N) v) = norm v`
+   (fun th -> ASM_MESON_TAC[th; IN_UNIV]) THEN
+  UNDISCH_THEN `span (b UNION b') = (:real^N)` (SUBST1_TAC o SYM) THEN
+  ASM_SIMP_TAC[SPAN_FINITE; FINITE_UNION; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`z:real^N`; `u:real^N->real`] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_SIMP_TAC[LINEAR_VSUM; FINITE_UNION] THEN
+  REWRITE_TAC[o_DEF; NORM_EQ_SQUARE; NORM_POS_LE; GSYM NORM_POW_2] THEN
+  ASM_SIMP_TAC[LINEAR_CMUL] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand)
+    NORM_VSUM_PYTHAGOREAN o rand o snd) THEN
+  W(MP_TAC o PART_MATCH (lhand o rand)
+    NORM_VSUM_PYTHAGOREAN o lhand o rand o snd) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pairwise]) THEN
+  ASM_SIMP_TAC[pairwise; ORTHOGONAL_CLAUSES; FINITE_UNION] THEN ANTS_TAC THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[ORTHOGONAL_MUL] THEN
+    REPEAT DISJ2_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM SET_TAC[];
+    REPEAT(DISCH_THEN SUBST1_TAC) THEN ASM_SIMP_TAC[NORM_MUL] THEN
+    MATCH_MP_TAC SUM_EQ THEN ASM SET_TAC[]]);;
+
+let ORTHOGONAL_TRANSFORMATION_ONTO_SUBSPACE = prove
+ (`!s t:real^N->bool.
+        subspace s /\ subspace t /\ dim s = dim t
+        ==> ?f. orthogonal_transformation f /\ IMAGE f s = t`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `t:real^N->bool`]
+        ORTHOGONAL_TRANSFORMATION_INTO_SUBSPACE) THEN
+  ASM_REWRITE_TAC[LE_REFL] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `f:real^N->real^N` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `span(IMAGE (f:real^N->real^N) s) = span t` MP_TAC THENL
+   [MATCH_MP_TAC DIM_EQ_SPAN THEN ASM_REWRITE_TAC[] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) DIM_INJECTIVE_LINEAR_IMAGE o
+      rand o snd) THEN
+    ASM_MESON_TAC[LE_REFL; orthogonal_transformation;
+                  ORTHOGONAL_TRANSFORMATION_INJECTIVE];
+    ASM_SIMP_TAC[SPAN_LINEAR_IMAGE; ORTHOGONAL_TRANSFORMATION_LINEAR] THEN
+    ASM_SIMP_TAC[SPAN_OF_SUBSPACE]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Rotation, reflection, rotoinversion.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let rotation_matrix = new_definition
+ `rotation_matrix Q <=> orthogonal_matrix Q /\ det(Q) = &1`;;
+
+let rotoinversion_matrix = new_definition
+ `rotoinversion_matrix Q <=> orthogonal_matrix Q /\ det(Q) = -- &1`;;
+
+let ORTHOGONAL_ROTATION_OR_ROTOINVERSION = prove
+ (`!Q. orthogonal_matrix Q <=> rotation_matrix Q \/ rotoinversion_matrix Q`,
+  MESON_TAC[rotation_matrix; rotoinversion_matrix; DET_ORTHOGONAL_MATRIX]);;
+
+let ROTATION_MATRIX_2 = prove
+ (`!A:real^2^2. rotation_matrix A <=>
+                A$1$1 pow 2 + A$2$1 pow 2 = &1 /\
+                A$1$1 = A$2$2 /\ A$1$2 = --(A$2$1)`,
+  REWRITE_TAC[rotation_matrix; ORTHOGONAL_MATRIX_2; DET_2] THEN
+  CONV_TAC REAL_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* Slightly stronger results giving rotation, but only in >= 2 dimensions.   *)
+(* ------------------------------------------------------------------------- *)
+
+let ROTATION_MATRIX_EXISTS_BASIS = prove
+ (`!a:real^N.
+        2 <= dimindex(:N) /\ norm(a) = &1
+        ==> ?A. rotation_matrix A /\ A**(basis 1) = a`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `A:real^N^N` STRIP_ASSUME_TAC o
+   MATCH_MP ORTHOGONAL_MATRIX_EXISTS_BASIS) THEN
+  FIRST_ASSUM(DISJ_CASES_TAC o GEN_REWRITE_RULE I
+   [ORTHOGONAL_ROTATION_OR_ROTOINVERSION])
+  THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  EXISTS_TAC `transp(lambda i. if i = dimindex(:N) then -- &1 % transp A$i
+                               else (transp A:real^N^N)$i):real^N^N` THEN
+  REWRITE_TAC[rotation_matrix; DET_TRANSP] THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[ORTHOGONAL_MATRIX_TRANSP];
+    SIMP_TAC[DET_ROW_MUL; DIMINDEX_GE_1; LE_REFL] THEN
+    MATCH_MP_TAC(REAL_ARITH `x = -- &1 ==> -- &1 * x = &1`) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [rotoinversion_matrix]) THEN
+    DISCH_THEN(SUBST1_TAC o SYM o CONJUNCT2) THEN
+    GEN_REWRITE_TAC RAND_CONV [GSYM DET_TRANSP] THEN
+    AP_TERM_TAC THEN SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN MESON_TAC[];
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    SIMP_TAC[matrix_vector_mul; LAMBDA_BETA; CART_EQ; transp;
+             BASIS_COMPONENT] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH
+      `x * (if p then &1 else &0) = if p then x else &0`] THEN
+    ASM_SIMP_TAC[ARITH_RULE `2 <= n ==> ~(1 = n)`; LAMBDA_BETA]] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+   [GSYM ORTHOGONAL_MATRIX_TRANSP]) THEN
+  SPEC_TAC(`transp(A:real^N^N)`,`B:real^N^N`) THEN GEN_TAC THEN
+  SUBGOAL_THEN `!i. 1 <= i /\ i <= dimindex(:N)
+                    ==> row i ((lambda i. if i = dimindex(:N) then -- &1 % B$i
+                                else (B:real^N^N)$i):real^N^N) =
+                        if i = dimindex(:N) then --(row i B) else row i B`
+  ASSUME_TAC THENL
+   [SIMP_TAC[row; LAMBDA_BETA; LAMBDA_ETA; VECTOR_MUL_LID; VECTOR_MUL_LNEG];
+    ASM_SIMP_TAC[ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS] THEN
+    ASM_MESON_TAC[ORTHOGONAL_LNEG; ORTHOGONAL_RNEG; NORM_NEG]]);;
+
+let ROTATION_EXISTS_1 = prove
+ (`!a b:real^N.
+        2 <= dimindex(:N) /\ norm(a) = &1 /\ norm(b) = &1
+        ==> ?f. orthogonal_transformation f /\ det(matrix f) = &1 /\ f a = b`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `b:real^N` ROTATION_MATRIX_EXISTS_BASIS) THEN
+  MP_TAC(ISPEC `a:real^N` ROTATION_MATRIX_EXISTS_BASIS) THEN
+  ASM_REWRITE_TAC[rotation_matrix] THEN
+  DISCH_THEN(X_CHOOSE_THEN `A:real^N^N`
+   (CONJUNCTS_THEN2 STRIP_ASSUME_TAC (ASSUME_TAC o SYM))) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real^N^N`
+   (CONJUNCTS_THEN2 STRIP_ASSUME_TAC (ASSUME_TAC o SYM))) THEN
+  EXISTS_TAC `\x:real^N. ((B:real^N^N) ** transp(A:real^N^N)) ** x` THEN
+  REWRITE_TAC[ORTHOGONAL_TRANSFORMATION_MATRIX; MATRIX_VECTOR_MUL_LINEAR;
+              MATRIX_OF_MATRIX_VECTOR_MUL; DET_MUL; DET_TRANSP] THEN
+  ASM_SIMP_TAC[ORTHOGONAL_MATRIX_MUL; ORTHOGONAL_MATRIX_TRANSP] THEN
+  REWRITE_TAC[GSYM MATRIX_VECTOR_MUL_ASSOC; REAL_MUL_LID] THEN AP_TERM_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[ORTHOGONAL_MATRIX]) THEN
+  ASM_REWRITE_TAC[MATRIX_VECTOR_MUL_ASSOC; MATRIX_VECTOR_MUL_LID]);;
+
+let ROTATION_EXISTS = prove
+ (`!a b:real^N.
+        2 <= dimindex(:N) /\ norm(a) = norm(b)
+        ==> ?f. orthogonal_transformation f /\ det(matrix f) = &1 /\ f a = b`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `b:real^N = vec 0` THEN
+  ASM_SIMP_TAC[NORM_0; NORM_EQ_0] THENL
+   [MESON_TAC[ORTHOGONAL_TRANSFORMATION_ID; MATRIX_ID; DET_I]; ALL_TAC] THEN
+  ASM_CASES_TAC `a:real^N = vec 0` THENL
+   [ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_ID; MATRIX_ID; DET_I; NORM_0;
+                  NORM_EQ_0]; ALL_TAC] THEN
+  DISCH_TAC THEN
+  MP_TAC(ISPECL [`inv(norm a) % a:real^N`; `inv(norm b) % b:real^N`]
+                ROTATION_EXISTS_1) THEN
+  REWRITE_TAC[NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+  ASM_SIMP_TAC[NORM_EQ_0; REAL_MUL_LINV] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^N->real^N` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP LINEAR_CMUL o
+              MATCH_MP ORTHOGONAL_TRANSFORMATION_LINEAR) THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+   `a % x:real^N = a % y <=> a % (x - y) = vec 0`] THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; REAL_INV_EQ_0; NORM_EQ_0; VECTOR_SUB_EQ]);;
+
+let ROTATION_RIGHTWARD_LINE = prove
+ (`!a:real^N k.
+        1 <= k /\ k <= dimindex(:N)
+        ==> ?b f. orthogonal_transformation f /\
+                  (2 <= dimindex(:N) ==> det(matrix f) = &1) /\
+                  f(b % basis k) = a /\
+                  &0 <= b`,
+  REPEAT STRIP_TAC THEN EXISTS_TAC `norm(a:real^N)` THEN
+  ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; BASIS_COMPONENT; LE_REFL; DIMINDEX_GE_1;
+               REAL_MUL_RID; NORM_POS_LE; LT_IMP_LE; LTE_ANTISYM] THEN
+  REWRITE_TAC[ARITH_RULE `2 <= n <=> 1 <= n /\ ~(n = 1)`; DIMINDEX_GE_1] THEN
+  ASM_CASES_TAC `dimindex(:N) = 1` THEN ASM_REWRITE_TAC[] THENL
+   [MATCH_MP_TAC ORTHOGONAL_TRANSFORMATION_EXISTS;
+    MATCH_MP_TAC ROTATION_EXISTS] THEN
+   ASM_SIMP_TAC[NORM_MUL; NORM_BASIS; LE_REFL; DIMINDEX_GE_1] THEN
+   REWRITE_TAC[REAL_ABS_NORM; REAL_MUL_RID] THEN
+   MATCH_MP_TAC(ARITH_RULE `~(n = 1) /\ 1 <= n ==> 2 <= n`) THEN
+   ASM_REWRITE_TAC[DIMINDEX_GE_1]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In 3 dimensions, a rotation is indeed about an "axis".                    *)
+(* ------------------------------------------------------------------------- *)
+
+let EULER_ROTATION_THEOREM = prove
+ (`!A:real^3^3. rotation_matrix A ==> ?v:real^3. ~(v = vec 0) /\ A ** v = v`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `A - mat 1:real^3^3` HOMOGENEOUS_LINEAR_EQUATIONS_DET) THEN
+  REWRITE_TAC[MATRIX_VECTOR_MUL_SUB_RDISTRIB;
+              VECTOR_SUB_EQ; MATRIX_VECTOR_MUL_LID] THEN
+  DISCH_THEN SUBST1_TAC THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[rotation_matrix; orthogonal_matrix; DET_3] THEN
+  SIMP_TAC[CART_EQ; FORALL_3; MAT_COMPONENT; DIMINDEX_3; LAMBDA_BETA; ARITH;
+           MATRIX_SUB_COMPONENT; MAT_COMPONENT; SUM_3;
+           matrix_mul; transp; matrix_vector_mul] THEN
+  CONV_TAC REAL_RING);;
+
+let EULER_ROTOINVERSION_THEOREM = prove
+ (`!A:real^3^3.
+     rotoinversion_matrix A ==> ?v:real^3. ~(v = vec 0) /\ A ** v = --v`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[VECTOR_ARITH `a:real^N = --v <=> a + v = vec 0`] THEN
+  MP_TAC(ISPEC `A + mat 1:real^3^3` HOMOGENEOUS_LINEAR_EQUATIONS_DET) THEN
+  REWRITE_TAC[MATRIX_VECTOR_MUL_ADD_RDISTRIB; MATRIX_VECTOR_MUL_LID] THEN
+  DISCH_THEN SUBST1_TAC THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[rotoinversion_matrix; orthogonal_matrix; DET_3] THEN
+  SIMP_TAC[CART_EQ; FORALL_3; MAT_COMPONENT; DIMINDEX_3; LAMBDA_BETA; ARITH;
+           MATRIX_ADD_COMPONENT; MAT_COMPONENT; SUM_3;
+           matrix_mul; transp; matrix_vector_mul] THEN
+  CONV_TAC REAL_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* We can always rotate so that a hyperplane is "horizontal".                *)
+(* ------------------------------------------------------------------------- *)
+
+let ROTATION_LOWDIM_HORIZONTAL = prove
+ (`!s:real^N->bool.
+        dim s < dimindex(:N)
+        ==> ?f. orthogonal_transformation f /\ det(matrix f) = &1 /\
+               (IMAGE f s) SUBSET {z | z$(dimindex(:N)) = &0}`,
+  GEN_TAC THEN ASM_CASES_TAC `dim(s:real^N->bool) = 0` THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[DIM_EQ_0]) THEN DISCH_TAC THEN
+    EXISTS_TAC `\x:real^N. x` THEN
+    REWRITE_TAC[ORTHOGONAL_TRANSFORMATION_ID; MATRIX_ID; DET_I] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `s SUBSET {a} ==> a IN t ==> IMAGE (\x. x) s SUBSET t`)) THEN
+    SIMP_TAC[IN_ELIM_THM; VEC_COMPONENT; LE_REFL; DIMINDEX_GE_1];
+    DISCH_TAC] THEN
+  SUBGOAL_THEN `2 <= dimindex(:N)` ASSUME_TAC THENL
+   [ASM_ARITH_TAC; ALL_TAC] THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC o MATCH_MP
+    LOWDIM_SUBSET_HYPERPLANE) THEN
+  MP_TAC(ISPECL [`a:real^N`; `norm(a:real^N) % basis(dimindex(:N)):real^N`]
+        ROTATION_EXISTS) THEN
+  ASM_SIMP_TAC[NORM_MUL; NORM_BASIS; LE_REFL; DIMINDEX_GE_1] THEN
+  REWRITE_TAC[REAL_ABS_NORM; REAL_MUL_RID] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^N->real^N` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[FORALL_IN_IMAGE; SUBSET; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `(f:real^N->real^N) x dot (f a) = &0` MP_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[orthogonal_transformation]) THEN
+    ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[DOT_SYM] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    ASM_SIMP_TAC[SPAN_SUPERSET; IN_ELIM_THM];
+    ASM_SIMP_TAC[DOT_BASIS; LE_REFL; DIMINDEX_GE_1; DOT_RMUL] THEN
+    ASM_REWRITE_TAC[REAL_ENTIRE; NORM_EQ_0]]);;
+
+let ORTHOGONAL_TRANSFORMATION_LOWDIM_HORIZONTAL = prove
+ (`!s:real^N->bool.
+        dim s < dimindex(:N)
+        ==> ?f. orthogonal_transformation f /\
+               (IMAGE f s) SUBSET {z | z$(dimindex(:N)) = &0}`,
+  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP ROTATION_LOWDIM_HORIZONTAL) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[]);;
+
+let ORTHOGONAL_TRANSFORMATION_BETWEEN_ORTHOGONAL_SETS = prove
+ (`!v:num->real^N w k.
+        pairwise (\i j. orthogonal (v i) (v j)) k /\
+        pairwise (\i j. orthogonal (w i) (w j)) k /\
+        (!i. i IN k ==> norm(v i) = norm(w i))
+        ==> ?f. orthogonal_transformation f /\
+                (!i. i IN k ==> f(v i) = w i)`,
+  let lemma1 = prove
+   (`!v:num->real^N n.
+          pairwise (\i j. orthogonal (v i) (v j)) (1..n) /\
+          (!i. 1 <= i /\ i <= n ==> norm(v i) = &1)
+          ==> ?f. orthogonal_transformation f /\
+                  (!i. 1 <= i /\ i <= n ==> f(basis i) = v i)`,
+    REWRITE_TAC[pairwise; IN_NUMSEG; GSYM CONJ_ASSOC] THEN
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `pairwise orthogonal (IMAGE (v:num->real^N) (1..n))`
+    ASSUME_TAC THENL
+     [REWRITE_TAC[PAIRWISE_IMAGE] THEN ASM_SIMP_TAC[pairwise; IN_NUMSEG];
+      ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          PAIRWISE_ORTHOGONAL_INDEPENDENT)) THEN
+    REWRITE_TAC[SET_RULE
+     `~(a IN IMAGE f s) <=> !x. x IN s ==> ~(f x = a)`] THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[IN_NUMSEG] THEN
+      ASM_MESON_TAC[NORM_0; REAL_ARITH `~(&1 = &0)`];
+      DISCH_THEN(MP_TAC o CONJUNCT2 o MATCH_MP INDEPENDENT_BOUND)] THEN
+    SUBGOAL_THEN
+     `!i j. 1 <= i /\ i <= n /\ 1 <= j /\ j <= n /\ ~(i = j)
+            ==> ~(v i:real^N = v j)`
+    ASSUME_TAC THENL
+     [ASM_MESON_TAC[ORTHOGONAL_REFL; NORM_0; REAL_ARITH `~(&1 = &0)`];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `CARD(IMAGE (v:num->real^N) (1..n)) = n` ASSUME_TAC THENL
+     [W(MP_TAC o PART_MATCH (lhs o rand) CARD_IMAGE_INJ o lhs o snd) THEN
+      ASM_REWRITE_TAC[CARD_NUMSEG_1; IN_NUMSEG; FINITE_NUMSEG] THEN
+      ASM_MESON_TAC[];
+      ASM_REWRITE_TAC[] THEN DISCH_TAC] THEN
+    SUBGOAL_THEN
+     `?w:num->real^N.
+          pairwise (\i j. orthogonal (w i) (w j)) (1..dimindex(:N)) /\
+          (!i. 1 <= i /\ i <= dimindex(:N) ==> norm(w i) = &1) /\
+          (!i. 1 <= i /\ i <= n ==> w i = v i)`
+    STRIP_ASSUME_TAC THENL
+     [ALL_TAC;
+      EXISTS_TAC
+       `(\x. vsum(1..dimindex(:N)) (\i. x$i % w i)):real^N->real^N` THEN
+      SIMP_TAC[BASIS_COMPONENT; IN_NUMSEG; COND_RATOR; COND_RAND] THEN
+      REWRITE_TAC[VECTOR_MUL_LID; VECTOR_MUL_LZERO; VSUM_DELTA] THEN
+      ASM_SIMP_TAC[IN_NUMSEG] THEN CONJ_TAC THENL
+       [ALL_TAC; ASM_MESON_TAC[LE_TRANS]] THEN
+      REWRITE_TAC[ORTHOGONAL_TRANSFORMATION_MATRIX] THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC LINEAR_COMPOSE_VSUM THEN
+        REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+        REWRITE_TAC[linear; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+        REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[matrix; column; ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS] THEN
+      SIMP_TAC[LAMBDA_BETA; LAMBDA_ETA; BASIS_COMPONENT; IN_NUMSEG] THEN
+      SIMP_TAC[COND_RATOR; COND_RAND; VECTOR_MUL_LZERO; VSUM_DELTA] THEN
+      SIMP_TAC[IN_NUMSEG; orthogonal; dot; LAMBDA_BETA; NORM_EQ_SQUARE] THEN
+      REWRITE_TAC[VECTOR_MUL_LID; GSYM dot; GSYM NORM_EQ_SQUARE] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[pairwise; IN_NUMSEG; orthogonal]) THEN
+      ASM_SIMP_TAC[]] THEN
+    FIRST_ASSUM(MP_TAC o SPEC `(:real^N)` o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ] ORTHONORMAL_EXTENSION)) THEN
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE; IN_NUMSEG; UNION_UNIV; SPAN_UNIV] THEN
+    DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`n+1..dimindex(:N)`; `t:real^N->bool`]
+          CARD_EQ_BIJECTION) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[FINITE_NUMSEG] THEN
+      MP_TAC(ISPECL [`(:real^N)`; `IMAGE v (1..n) UNION t:real^N->bool`]
+          BASIS_CARD_EQ_DIM) THEN
+      ASM_REWRITE_TAC[SUBSET_UNIV] THEN ANTS_TAC THENL
+       [MATCH_MP_TAC PAIRWISE_ORTHOGONAL_INDEPENDENT THEN
+        ASM_REWRITE_TAC[IN_UNION; DE_MORGAN_THM; IN_NUMSEG] THEN
+        ASM_REWRITE_TAC[FORALL_IN_IMAGE; IN_NUMSEG; SET_RULE
+         `~(x IN s) <=> !y. y IN s ==> ~(y = x)`] THEN
+        ASM_MESON_TAC[NORM_0; REAL_ARITH `~(&1 = &0)`];
+        ALL_TAC] THEN
+      ASM_SIMP_TAC[FINITE_UNION; IMP_CONJ; FINITE_IMAGE; CARD_UNION;
+                   SET_RULE `t INTER s = {} <=> DISJOINT s t`] THEN
+      DISCH_TAC THEN DISCH_TAC THEN REWRITE_TAC[CARD_NUMSEG; DIM_UNIV] THEN
+      ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[CONJ_ASSOC; SET_RULE
+     `(!x. x IN s ==> f x IN t) /\ (!y. y IN t ==> ?x. x IN s /\ f x = y) <=>
+      t = IMAGE f s`] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC; LEFT_IMP_EXISTS_THM; IN_NUMSEG] THEN
+    X_GEN_TAC `w:num->real^N` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC MP_TAC) THEN
+    REWRITE_TAC[ARITH_RULE `n + 1 <= x <=> n < x`; CONJ_ASSOC] THEN
+    ONCE_REWRITE_TAC[TAUT `p /\ q ==> r <=> p /\ ~r ==> ~q`] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC] THEN STRIP_TAC THEN
+    REWRITE_TAC[TAUT `p /\ ~r ==> ~q <=> p /\ q ==> r`] THEN
+    EXISTS_TAC `\i. if i <= n then (v:num->real^N) i else w i` THEN
+    SIMP_TAC[] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[FORALL_IN_IMAGE; IN_NUMSEG]) THEN
+    CONJ_TAC THENL
+     [ALL_TAC; ASM_MESON_TAC[ARITH_RULE `~(i <= n) ==> n + 1 <= i`]] THEN
+    REWRITE_TAC[pairwise] THEN MATCH_MP_TAC WLOG_LT THEN REWRITE_TAC[] THEN
+    CONJ_TAC THENL [MESON_TAC[ORTHOGONAL_SYM]; ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`i:num`; `j:num`] THEN DISCH_TAC THEN
+    ASM_CASES_TAC `j:num <= n` THEN ASM_REWRITE_TAC[IN_NUMSEG] THENL
+     [COND_CASES_TAC THEN ASM_SIMP_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN
+    ASM_CASES_TAC `i:num <= n` THEN ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+    UNDISCH_TAC
+     `pairwise orthogonal
+        (IMAGE (v:num->real^N) (1..n) UNION IMAGE w (n+1..dimindex (:N)))` THEN
+    REWRITE_TAC[pairwise] THEN ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `(w:num->real^N) j`) THENL
+     [DISCH_THEN(MP_TAC o SPEC `(v:num->real^N) i`);
+      DISCH_THEN(MP_TAC o SPEC `(w:num->real^N) i`)] THEN
+    ASM_REWRITE_TAC[IN_UNION; IN_IMAGE; IN_NUMSEG] THEN
+    DISCH_THEN MATCH_MP_TAC THENL
+     [CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+      CONJ_TAC THENL
+       [ASM_MESON_TAC[ARITH_RULE `~(x <= n) ==> n + 1 <= x`]; ALL_TAC];
+      ASM_MESON_TAC[ARITH_RULE `~(x <= n) ==> n + 1 <= x /\ n < x`]] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [DISJOINT]) THEN
+    REWRITE_TAC[SET_RULE `IMAGE w t INTER IMAGE v s = {} <=>
+      !i j. i IN s /\ j IN t ==> ~(v i = w j)`] THEN
+    DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[IN_NUMSEG] THEN
+    ASM_ARITH_TAC) in
+  let lemma2 = prove
+   (`!v:num->real^N w k.
+          pairwise (\i j. orthogonal (v i) (v j)) k /\
+          pairwise (\i j. orthogonal (w i) (w j)) k /\
+          (!i. i IN k ==> norm(v i) = norm(w i)) /\
+          (!i. i IN k ==> ~(v i = vec 0) /\ ~(w i = vec 0))
+          ==> ?f. orthogonal_transformation f /\
+                  (!i. i IN k ==> f(v i) = w i)`,
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `FINITE(k:num->bool)` MP_TAC THENL
+     [SUBGOAL_THEN `pairwise orthogonal (IMAGE (v:num->real^N) k)`
+      ASSUME_TAC THENL
+       [REWRITE_TAC[PAIRWISE_IMAGE] THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[pairwise]) THEN ASM_SIMP_TAC[pairwise];
+        ALL_TAC] THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        PAIRWISE_ORTHOGONAL_INDEPENDENT)) THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP INDEPENDENT_IMP_FINITE) THEN
+      MATCH_MP_TAC EQ_IMP THEN MATCH_MP_TAC FINITE_IMAGE_INJ_EQ THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[pairwise]) THEN
+      ASM_MESON_TAC[ORTHOGONAL_REFL];
+      ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o GEN_REWRITE_RULE I [FINITE_INDEX_NUMSEG]) THEN
+    ONCE_REWRITE_TAC[TAUT `p /\ q /\ r ==> s <=> p /\ q /\ ~s ==> ~r`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:num->num` MP_TAC) THEN
+    REWRITE_TAC[IN_NUMSEG] THEN GEN_REWRITE_TAC I [IMP_CONJ] THEN
+    DISCH_THEN(fun th -> DISCH_THEN SUBST_ALL_TAC THEN ASSUME_TAC th) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE
+     [PAIRWISE_IMAGE; FORALL_IN_IMAGE; IN_NUMSEG]) THEN
+    MP_TAC(ISPECL
+     [`\i. inv(norm(w(n i))) % (w:num->real^N) ((n:num->num) i)`;
+      `CARD(k:num->bool)`] lemma1) THEN
+    MP_TAC(ISPECL
+     [`\i. inv(norm(v(n i))) % (v:num->real^N) ((n:num->num) i)`;
+      `CARD(k:num->bool)`] lemma1) THEN
+    ASM_SIMP_TAC[NORM_MUL; REAL_MUL_LINV; NORM_EQ_0; REAL_ABS_INV;
+                 REAL_ABS_NORM; pairwise; orthogonal; IN_NUMSEG] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[pairwise; orthogonal; IN_NUMSEG]) THEN
+    ASM_SIMP_TAC[DOT_LMUL; DOT_RMUL; REAL_ENTIRE; FORALL_IN_IMAGE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `f:real^N->real^N` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^N` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPEC `f:real^N->real^N` ORTHOGONAL_TRANSFORMATION_INVERSE) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `f':real^N->real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(g:real^N->real^N) o (f':real^N->real^N)` THEN
+    ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_COMPOSE; IN_NUMSEG] THEN
+    X_GEN_TAC `i:num` THEN DISCH_TAC THEN REWRITE_TAC[o_THM] THEN
+    MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+     `(g:real^N->real^N) (norm((w:num->real^N)(n(i:num))) % basis i)` THEN
+    CONJ_TAC THENL
+     [AP_TERM_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[]
+       `(!x. f'(f x) = x) ==> f x = y ==> f' y = x`));
+      ALL_TAC] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[orthogonal_transformation]) THEN
+    ASM_SIMP_TAC[LINEAR_CMUL; VECTOR_MUL_ASSOC] THEN
+    ASM_SIMP_TAC[REAL_MUL_RINV; NORM_EQ_0; VECTOR_MUL_LID]) in
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`v:num->real^N`; `w:num->real^N`;
+    `{i | i IN k /\ ~((v:num->real^N) i = vec 0)}`] lemma2) THEN
+  ASM_SIMP_TAC[IN_ELIM_THM; CONJ_ASSOC] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[NORM_EQ_0]] THEN
+    CONJ_TAC THEN MATCH_MP_TAC PAIRWISE_MONO THEN EXISTS_TAC `k:num->bool` THEN
+    ASM_REWRITE_TAC[] THEN SET_TAC[];
+    MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[orthogonal_transformation] THEN
+    GEN_TAC THEN STRIP_TAC THEN X_GEN_TAC `i:num` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `(v:num->real^N) i = vec 0` THEN ASM_SIMP_TAC[] THEN
+    ASM_MESON_TAC[LINEAR_0; NORM_EQ_0]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Reflection of a vector about 0 along a line.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let reflect_along = new_definition
+ `reflect_along v (x:real^N) = x - (&2 * (x dot v) / (v dot v)) % v`;;
+
+let REFLECT_ALONG_ADD = prove
+ (`!v x y:real^N.
+      reflect_along v (x + y) = reflect_along v x + reflect_along v y`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[reflect_along; VECTOR_ARITH
+   `x - a % v + y - b % v:real^N = (x + y) - (a + b) % v`] THEN
+  AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[DOT_LADD] THEN REAL_ARITH_TAC);;
+
+let REFLECT_ALONG_MUL = prove
+ (`!v a x:real^N. reflect_along v (a % x) = a % reflect_along v x`,
+  REWRITE_TAC[reflect_along; DOT_LMUL; REAL_ARITH
+   `&2 * (a * x) / y = a * &2 * x / y`] THEN
+  REWRITE_TAC[VECTOR_SUB_LDISTRIB; VECTOR_MUL_ASSOC]);;
+
+let LINEAR_REFLECT_ALONG = prove
+ (`!v:real^N. linear(reflect_along v)`,
+  REWRITE_TAC[linear; REFLECT_ALONG_ADD; REFLECT_ALONG_MUL]);;
+
+let REFLECT_ALONG_0 = prove
+ (`!v:real^N. reflect_along v (vec 0) = vec 0`,
+  REWRITE_TAC[MATCH_MP LINEAR_0 (SPEC_ALL LINEAR_REFLECT_ALONG)]);;
+
+let REFLECT_ALONG_REFL = prove
+ (`!v:real^N. reflect_along v v = --v`,
+  GEN_TAC THEN ASM_CASES_TAC `v:real^N = vec 0` THEN
+  ASM_REWRITE_TAC[VECTOR_NEG_0; REFLECT_ALONG_0] THEN
+  REWRITE_TAC[reflect_along] THEN
+  ASM_SIMP_TAC[REAL_DIV_REFL; DOT_EQ_0] THEN VECTOR_ARITH_TAC);;
+
+let REFLECT_ALONG_INVOLUTION = prove
+ (`!v x:real^N. reflect_along v (reflect_along v x) = x`,
+  REWRITE_TAC[reflect_along; DOT_LSUB; VECTOR_MUL_EQ_0; VECTOR_ARITH
+   `x - a % v - b % v:real^N = x <=> (a + b) % v = vec 0`] THEN
+  REWRITE_TAC[DOT_LMUL; GSYM DOT_EQ_0] THEN CONV_TAC REAL_FIELD);;
+
+let REFLECT_ALONG_EQ_0 = prove
+ (`!v x:real^N. reflect_along v x = vec 0 <=> x = vec 0`,
+  MESON_TAC[REFLECT_ALONG_0; REFLECT_ALONG_INVOLUTION]);;
+
+let ORTHGOONAL_TRANSFORMATION_REFLECT_ALONG = prove
+ (`!v:real^N. orthogonal_transformation(reflect_along v)`,
+  GEN_TAC THEN ASM_CASES_TAC `v:real^N = vec 0` THENL
+   [GEN_REWRITE_TAC RAND_CONV [GSYM ETA_AX] THEN
+    ASM_REWRITE_TAC[reflect_along; VECTOR_MUL_RZERO; VECTOR_SUB_RZERO;
+                    ORTHOGONAL_TRANSFORMATION_ID];
+    REWRITE_TAC[ORTHOGONAL_TRANSFORMATION] THEN
+    REWRITE_TAC[LINEAR_REFLECT_ALONG; NORM_EQ] THEN
+    REWRITE_TAC[reflect_along; VECTOR_ARITH
+      `(a - b:real^N) dot (a - b) = (a dot a + b dot b) - &2 * a dot b`] THEN
+    REWRITE_TAC[DOT_LMUL; DOT_RMUL] THEN X_GEN_TAC `w:real^N` THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [GSYM DOT_EQ_0]) THEN
+    CONV_TAC REAL_FIELD]);;
+
+let REFLECT_ALONG_EQ_SELF = prove
+ (`!v x:real^N. reflect_along v x = x <=> orthogonal v x`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[reflect_along; orthogonal] THEN
+  REWRITE_TAC[VECTOR_ARITH `x - a:real^N = x <=> a = vec 0`] THEN
+  REWRITE_TAC[VECTOR_MUL_EQ_0] THEN
+  ASM_CASES_TAC `v:real^N = vec 0` THEN ASM_SIMP_TAC[DOT_LZERO; DOT_SYM] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [GSYM DOT_EQ_0]) THEN
+  CONV_TAC REAL_FIELD);;
+
+let REFLECT_ALONG_ZERO = prove
+ (`!x:real^N. reflect_along (vec 0) = I`,
+  REWRITE_TAC[FUN_EQ_THM; I_THM; REFLECT_ALONG_EQ_SELF; ORTHOGONAL_0]);;
+
+let REFLECT_ALONG_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N v x.
+        linear f /\ (!x. norm(f x) = norm x)
+        ==> reflect_along (f v) (f x) = f(reflect_along v x)`,
+  REWRITE_TAC[reflect_along] THEN
+  SIMP_TAC[PRESERVES_NORM_PRESERVES_DOT; LINEAR_SUB; LINEAR_CMUL]);;
+
+add_linear_invariants [REFLECT_ALONG_LINEAR_IMAGE];;
+
+let REFLECT_ALONG_SCALE = prove
+ (`!c v x:real^N. ~(c = &0) ==> reflect_along (c % v) x = reflect_along v x`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `v:real^N = vec 0` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_RZERO; REFLECT_ALONG_ZERO] THEN
+  REWRITE_TAC[reflect_along; VECTOR_MUL_ASSOC] THEN
+  AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[DOT_RMUL] THEN REWRITE_TAC[DOT_LMUL] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [GSYM DOT_EQ_0]) THEN
+  POP_ASSUM MP_TAC THEN CONV_TAC REAL_FIELD);;
+
+let REFLECT_ALONG_1D = prove
+ (`!v x:real^N.
+        dimindex(:N) = 1 ==> reflect_along v x = if v = vec 0 then x else --x`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[reflect_along; dot; SUM_1; CART_EQ; FORALL_1] THEN
+  REWRITE_TAC[VEC_COMPONENT; COND_RATOR; COND_RAND] THEN
+  SIMP_TAC[VECTOR_NEG_COMPONENT; VECTOR_MUL_COMPONENT;
+           VECTOR_SUB_COMPONENT; REAL_MUL_RZERO] THEN
+  CONV_TAC REAL_FIELD);;
+
+let REFLECT_ALONG_BASIS = prove
+ (`!x:real^N k.
+        1 <= k /\ k <= dimindex(:N)
+        ==> reflect_along (basis k) x = x - (&2 * x$k) % basis k`,
+  SIMP_TAC[reflect_along; DOT_BASIS; BASIS_COMPONENT; REAL_DIV_1]);;
+
+let MATRIX_REFLECT_ALONG_BASIS = prove
+ (`!k. 1 <= k /\ k <= dimindex(:N)
+       ==> matrix(reflect_along (basis k)):real^N^N =
+           lambda i j. if i = k /\ j = k then --(&1)
+                       else if i = j then &1
+                       else &0`,
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; matrix; REFLECT_ALONG_BASIS;
+           VECTOR_SUB_COMPONENT; BASIS_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+  ASM_CASES_TAC `i:num = j` THEN ASM_REWRITE_TAC[] THEN
+  REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN ASM_REAL_ARITH_TAC);;
+
+let ROTOINVERSION_MATRIX_REFLECT_ALONG = prove
+ (`!v:real^N. ~(v = vec 0) ==> rotoinversion_matrix(matrix(reflect_along v))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[rotoinversion_matrix] THEN
+  CONJ_TAC THENL
+   [ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_MATRIX;
+                ORTHGOONAL_TRANSFORMATION_REFLECT_ALONG];
+    ALL_TAC] THEN
+  ABBREV_TAC `w:real^N = inv(norm v) % v` THEN
+  SUBGOAL_THEN `reflect_along (v:real^N) = reflect_along w` SUBST1_TAC THENL
+   [EXPAND_TAC "w" THEN REWRITE_TAC[FUN_EQ_THM] THEN
+    ASM_SIMP_TAC[REFLECT_ALONG_SCALE; REAL_INV_EQ_0; NORM_EQ_0];
+    SUBGOAL_THEN `norm(w:real^N) = &1` MP_TAC THENL
+     [EXPAND_TAC "w" THEN SIMP_TAC[NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+      MATCH_MP_TAC REAL_MUL_LINV THEN ASM_REWRITE_TAC[NORM_EQ_0];
+      POP_ASSUM_LIST(K ALL_TAC) THEN SPEC_TAC(`w:real^N`,`v:real^N`)]] THEN
+  X_GEN_TAC `v:real^N` THEN ASM_CASES_TAC `v:real^N = vec 0` THEN
+  ASM_REWRITE_TAC[NORM_0; REAL_OF_NUM_EQ; ARITH_EQ] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`v:real^N`; `basis 1:real^N`]
+        ORTHOGONAL_TRANSFORMATION_EXISTS) THEN
+  ASM_SIMP_TAC[NORM_BASIS; DIMINDEX_GE_1; LE_REFL] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:real^N->real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `matrix(reflect_along v) =
+    transp(matrix(f:real^N->real^N)) ** matrix(reflect_along (f v)) ** matrix f`
+  SUBST1_TAC THENL
+   [UNDISCH_THEN `(f:real^N->real^N) v = basis 1` (K ALL_TAC) THEN
+    REWRITE_TAC[MATRIX_EQ; GSYM MATRIX_VECTOR_MUL_ASSOC] THEN
+    ASM_SIMP_TAC[MATRIX_WORKS; LINEAR_REFLECT_ALONG;
+                 ORTHOGONAL_TRANSFORMATION_LINEAR] THEN
+    X_GEN_TAC `x:real^N` THEN MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `(transp(matrix(f:real^N->real^N)) ** matrix f) **
+                (reflect_along v x:real^N)` THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[ORTHOGONAL_MATRIX; MATRIX_VECTOR_MUL_LID;
+                ORTHOGONAL_TRANSFORMATION_MATRIX];
+      REWRITE_TAC[GSYM MATRIX_VECTOR_MUL_ASSOC] THEN
+      ASM_SIMP_TAC[MATRIX_WORKS; ORTHOGONAL_TRANSFORMATION_LINEAR] THEN
+      AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN
+      MATCH_MP_TAC REFLECT_ALONG_LINEAR_IMAGE THEN
+      ASM_REWRITE_TAC[GSYM ORTHOGONAL_TRANSFORMATION]];
+    ASM_REWRITE_TAC[DET_MUL; DET_TRANSP] THEN
+    MATCH_MP_TAC(REAL_RING
+     `(x = &1 \/ x = -- &1) /\ y = a ==> x * y * x = a`) THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[DET_ORTHOGONAL_MATRIX; ORTHOGONAL_TRANSFORMATION_MATRIX];
+      ALL_TAC] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) DET_UPPERTRIANGULAR o lhand o snd) THEN
+    SIMP_TAC[MATRIX_REFLECT_ALONG_BASIS; DIMINDEX_GE_1; LE_REFL] THEN
+    SIMP_TAC[LAMBDA_BETA; ARITH_RULE
+     `j < i ==> ~(i = j) /\ ~(i = 1 /\ j = 1)`] THEN
+    DISCH_THEN(K ALL_TAC) THEN
+    SIMP_TAC[PRODUCT_CLAUSES_LEFT; DIMINDEX_GE_1] THEN
+    MATCH_MP_TAC(REAL_RING `x = &1 ==> a * x = a`) THEN
+    MATCH_MP_TAC PRODUCT_EQ_1 THEN
+    REWRITE_TAC[IN_NUMSEG] THEN REPEAT STRIP_TAC THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC]);;
+
+let DET_MATRIX_REFLECT_ALONG = prove
+ (`!v:real^N. det(matrix(reflect_along v)) =
+                if v = vec 0 then &1 else --(&1)`,
+  GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[REFLECT_ALONG_ZERO] THEN
+  REWRITE_TAC[MATRIX_I; DET_I] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ROTOINVERSION_MATRIX_REFLECT_ALONG) THEN
+  SIMP_TAC[rotoinversion_matrix]);;
+
+(* ------------------------------------------------------------------------- *)
+(* All orthogonal transformations are a composition of reflections.          *)
+(* ------------------------------------------------------------------------- *)
+
+let ORTHOGONAL_TRANSFORMATION_GENERATED_BY_REFLECTIONS = prove
+ (`!f:real^N->real^N n.
+        orthogonal_transformation f /\
+        dimindex(:N) <= dim {x | f x = x} + n
+        ==> ?l. LENGTH l <= n /\ ALL (\v. ~(v = vec 0)) l /\
+                f = ITLIST (\v h. reflect_along v o h) l I`,
+  ONCE_REWRITE_TAC[GSYM SWAP_FORALL_THM] THEN INDUCT_TAC THENL
+   [REWRITE_TAC[CONJUNCT1 LE; LENGTH_EQ_NIL; ADD_CLAUSES; UNWIND_THM2] THEN
+    SIMP_TAC[DIM_SUBSET_UNIV; ARITH_RULE `a:num <= b ==> (b <= a <=> a = b)`;
+             ITLIST; DIM_EQ_FULL; orthogonal_transformation] THEN
+    SIMP_TAC[SPAN_OF_SUBSPACE; SUBSPACE_LINEAR_FIXED_POINTS; IMP_CONJ] THEN
+    REWRITE_TAC[EXTENSION; IN_UNIV; IN_ELIM_THM] THEN
+    SIMP_TAC[FUN_EQ_THM; I_THM; ALL];
+    REPEAT STRIP_TAC THEN ASM_CASES_TAC `!x:real^N. f x = x` THENL
+     [EXISTS_TAC `[]:(real^N) list` THEN
+      ASM_REWRITE_TAC[ITLIST; FUN_EQ_THM; I_THM; ALL; LENGTH; LE_0];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM])] THEN
+    DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+    ABBREV_TAC `v:real^N = inv(&2) % (f a - a)` THEN FIRST_X_ASSUM
+      (MP_TAC o SPEC `reflect_along v o (f:real^N->real^N)`) THEN
+    ASM_SIMP_TAC[ORTHGOONAL_TRANSFORMATION_REFLECT_ALONG;
+                 ORTHOGONAL_TRANSFORMATION_COMPOSE] THEN
+    ANTS_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (ARITH_RULE
+       `a <= d + SUC n ==> d < d' ==> a <= d' + n`)) THEN
+      MATCH_MP_TAC DIM_PSUBSET THEN REWRITE_TAC[PSUBSET_ALT] THEN
+      SUBGOAL_THEN
+       `!y:real^N. dist(y,f a) = dist(y,a) ==> reflect_along v y = y`
+      ASSUME_TAC THENL
+       [REWRITE_TAC[dist; NORM_EQ_SQUARE; NORM_POS_LE; NORM_POW_2] THEN
+        REWRITE_TAC[VECTOR_ARITH
+         `(y - b:real^N) dot (y - b) =
+          (y dot y + b dot b) - &2 * y dot b`] THEN
+        REWRITE_TAC[REAL_ARITH `(y + aa) - &2 * a = (y + bb) - &2 * b <=>
+                                a - b = inv(&2) * (aa - bb)`] THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[orthogonal_transformation]) THEN
+        ASM_REWRITE_TAC[REAL_SUB_REFL; REAL_MUL_RZERO] THEN
+        EXPAND_TAC "v" THEN REWRITE_TAC[GSYM DOT_RSUB; reflect_along] THEN
+        SIMP_TAC[DOT_RMUL; real_div; REAL_MUL_LZERO; REAL_MUL_RZERO] THEN
+        REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_SUB_RZERO];
+        ALL_TAC] THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC SPAN_MONO THEN SIMP_TAC[SUBSET; IN_ELIM_THM; o_THM] THEN
+        ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_ISOMETRY];
+        ALL_TAC] THEN
+      EXISTS_TAC `a:real^N` THEN
+      ASM_SIMP_TAC[SUBSPACE_LINEAR_FIXED_POINTS; SPAN_OF_SUBSPACE;
+                   ORTHOGONAL_TRANSFORMATION_LINEAR; IN_ELIM_THM] THEN
+      MATCH_MP_TAC SPAN_SUPERSET THEN REWRITE_TAC[IN_ELIM_THM; o_THM] THEN
+      MATCH_MP_TAC EQ_TRANS THEN
+      EXISTS_TAC `reflect_along (v:real^N) (midpoint(f a,a) + v)` THEN
+      CONJ_TAC THENL
+       [AP_TERM_TAC;
+        REWRITE_TAC[REFLECT_ALONG_ADD] THEN
+        ASM_SIMP_TAC[DIST_MIDPOINT; REFLECT_ALONG_REFL]] THEN
+      EXPAND_TAC "v" THEN REWRITE_TAC[midpoint] THEN VECTOR_ARITH_TAC;
+      DISCH_THEN(X_CHOOSE_THEN `l:(real^N)list` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `CONS (v:real^N) l` THEN
+      ASM_REWRITE_TAC[ALL; LENGTH; LE_SUC; VECTOR_SUB_EQ; ITLIST] THEN
+      EXPAND_TAC "v" THEN ASM_REWRITE_TAC[VECTOR_MUL_EQ_0] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[VECTOR_SUB_EQ] THEN
+      FIRST_X_ASSUM(MP_TAC o AP_TERM
+       `(o)(reflect_along (v:real^N)):(real^N->real^N)->(real^N->real^N)`) THEN
+      REWRITE_TAC[FUN_EQ_THM; o_THM; REFLECT_ALONG_INVOLUTION]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Extract scaling, translation and linear invariance theorems.              *)
+(* For the linear case, chain through some basic consequences automatically, *)
+(* e.g. norm-preserving and linear implies injective.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let SCALING_THEOREMS v =
+  let th1 = UNDISCH(snd(EQ_IMP_RULE(ISPEC v NORM_POS_LT))) in
+  let t = rand(concl th1) in
+  end_itlist CONJ (map (C MP th1 o SPEC t) (!scaling_theorems));;
+
+let TRANSLATION_INVARIANTS x =
+  end_itlist CONJ (mapfilter (ISPEC x) (!invariant_under_translation));;
+
+let USABLE_CONCLUSION f ths th =
+  let ith = PURE_REWRITE_RULE[RIGHT_FORALL_IMP_THM] (ISPEC f th) in
+  let bod = concl ith in
+  let cjs = conjuncts(fst(dest_imp bod)) in
+  let ths = map (fun t -> find(fun th -> aconv (concl th) t) ths) cjs in
+  GEN_ALL(MP ith (end_itlist CONJ ths));;
+
+let LINEAR_INVARIANTS =
+  let sths = (CONJUNCTS o prove)
+   (`(!f:real^M->real^N.
+         linear f /\ (!x. norm(f x) = norm x)
+         ==> (!x y. f x = f y ==> x = y)) /\
+     (!f:real^N->real^N.
+         linear f /\ (!x. norm(f x) = norm x) ==> (!y. ?x. f x = y)) /\
+     (!f:real^N->real^N. linear f /\ (!x y. f x = f y ==> x = y)
+                         ==> (!y. ?x. f x = y)) /\
+     (!f:real^N->real^N. linear f /\ (!y. ?x. f x = y)
+                         ==> (!x y. f x = f y ==> x = y))`,
+    CONJ_TAC THENL
+     [ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+      SIMP_TAC[GSYM LINEAR_SUB; GSYM NORM_EQ_0];
+      MESON_TAC[ORTHOGONAL_TRANSFORMATION_SURJECTIVE;
+                ORTHOGONAL_TRANSFORMATION_INJECTIVE; ORTHOGONAL_TRANSFORMATION;
+                LINEAR_SURJECTIVE_IFF_INJECTIVE]]) in
+  fun f ths ->
+    let ths' = ths @ mapfilter (USABLE_CONCLUSION f ths) sths in
+    end_itlist CONJ
+     (mapfilter (USABLE_CONCLUSION f ths') (!invariant_under_linear));;
+
+(* ------------------------------------------------------------------------- *)
+(* Tactic to pick WLOG a particular point as the origin. The conversion form *)
+(* assumes it's the outermost universal variable; the tactic is more general *)
+(* and allows any free or outer universally quantified variable. The list    *)
+(* "avoid" is the points not to translate. There is also a tactic to help in *)
+(* proving new translation theorems, which uses similar machinery.           *)
+(* ------------------------------------------------------------------------- *)
+
+let GEOM_ORIGIN_CONV,GEOM_TRANSLATE_CONV =
+  let pth = prove
+   (`!a:real^N. a = a + vec 0 /\
+                {} = IMAGE (\x. a + x) {} /\
+                {} = IMAGE (IMAGE (\x. a + x)) {} /\
+                (:real^N) = IMAGE (\x. a + x) (:real^N) /\
+                (:real^N->bool) = IMAGE (IMAGE (\x. a + x)) (:real^N->bool) /\
+                [] = MAP (\x. a + x) []`,
+    REWRITE_TAC[IMAGE_CLAUSES; VECTOR_ADD_RID; MAP] THEN
+    REWRITE_TAC[SET_RULE `UNIV = IMAGE f UNIV <=> !y. ?x. f x = y`] THEN
+    REWRITE_TAC[SURJECTIVE_IMAGE] THEN
+    REWRITE_TAC[VECTOR_ARITH `a + y:real^N = x <=> y = x - a`; EXISTS_REFL])
+  and qth = prove
+   (`!a:real^N.
+        ((!P. (!x. P x) <=> (!x. P (a + x))) /\
+         (!P. (?x. P x) <=> (?x. P (a + x))) /\
+         (!Q. (!s. Q s) <=> (!s. Q(IMAGE (\x. a + x) s))) /\
+         (!Q. (?s. Q s) <=> (?s. Q(IMAGE (\x. a + x) s))) /\
+         (!Q. (!s. Q s) <=> (!s. Q(IMAGE (IMAGE (\x. a + x)) s))) /\
+         (!Q. (?s. Q s) <=> (?s. Q(IMAGE (IMAGE (\x. a + x)) s))) /\
+         (!P. (!g:real^1->real^N. P g) <=> (!g. P ((\x. a + x) o g))) /\
+         (!P. (?g:real^1->real^N. P g) <=> (?g. P ((\x. a + x) o g))) /\
+         (!P. (!g:num->real^N. P g) <=> (!g. P ((\x. a + x) o g))) /\
+         (!P. (?g:num->real^N. P g) <=> (?g. P ((\x. a + x) o g))) /\
+         (!Q. (!l. Q l) <=> (!l. Q(MAP (\x. a + x) l))) /\
+         (!Q. (?l. Q l) <=> (?l. Q(MAP (\x. a + x) l)))) /\
+        ((!P. {x | P x} = IMAGE (\x. a + x) {x | P(a + x)}) /\
+         (!Q. {s | Q s} =
+              IMAGE (IMAGE (\x. a + x)) {s | Q(IMAGE (\x. a + x) s)}) /\
+         (!R. {l | R l} = IMAGE (MAP (\x. a + x)) {l | R(MAP (\x. a + x) l)}))`,
+    GEN_TAC THEN MATCH_MP_TAC QUANTIFY_SURJECTION_HIGHER_THM THEN
+    X_GEN_TAC `y:real^N` THEN EXISTS_TAC `y - a:real^N` THEN
+    VECTOR_ARITH_TAC) in
+  let GEOM_ORIGIN_CONV avoid tm =
+    let x,tm0 = dest_forall tm in
+    let th0 = ISPEC x pth in
+    let x' = genvar(type_of x) in
+    let ith = ISPEC x' qth in
+    let th1 = PARTIAL_EXPAND_QUANTS_CONV avoid (ASSUME(concl ith)) tm0 in
+    let th2 = CONV_RULE(RAND_CONV(SUBS_CONV(CONJUNCTS th0))) th1 in
+    let th3 = INST[x,x'] (PROVE_HYP ith th2) in
+    let ths = TRANSLATION_INVARIANTS x in
+    let thr = REFL x in
+    let th4 = GEN_REWRITE_RULE (RAND_CONV o REDEPTH_CONV)
+      [BETA_THM;ADD_ASSUM(concl thr) ths] th3 in
+    let th5 = MK_FORALL x (PROVE_HYP thr th4) in
+    GEN_REWRITE_RULE (RAND_CONV o TRY_CONV) [FORALL_SIMP] th5
+  and GEOM_TRANSLATE_CONV avoid a tm =
+    let cth = CONJUNCT2(ISPEC a pth)
+    and vth = ISPEC a qth in
+    let th1 = PARTIAL_EXPAND_QUANTS_CONV avoid (ASSUME(concl vth)) tm in
+    let th2 = CONV_RULE(RAND_CONV(SUBS_CONV(CONJUNCTS cth))) th1 in
+    let th3 = PROVE_HYP vth th2 in
+    let ths = TRANSLATION_INVARIANTS a in
+    let thr = REFL a in
+    let th4 = GEN_REWRITE_RULE (RAND_CONV o REDEPTH_CONV)
+        [BETA_THM;ADD_ASSUM(concl thr) ths] th3 in
+    PROVE_HYP thr th4 in
+  GEOM_ORIGIN_CONV,GEOM_TRANSLATE_CONV;;
+
+let GEN_GEOM_ORIGIN_TAC x avoid (asl,w as gl) =
+  let avs,bod = strip_forall w
+  and avs' = subtract (frees w) (freesl(map (concl o snd) asl)) in
+  (MAP_EVERY X_GEN_TAC avs THEN
+   MAP_EVERY (fun t -> SPEC_TAC(t,t)) (rev(subtract (avs@avs') [x])) THEN
+   SPEC_TAC(x,x) THEN CONV_TAC(GEOM_ORIGIN_CONV avoid)) gl;;
+
+let GEOM_ORIGIN_TAC x = GEN_GEOM_ORIGIN_TAC x [];;
+
+let GEOM_TRANSLATE_TAC avoid (asl,w) =
+  let a,bod = dest_forall w in
+  let n = length(fst(strip_forall bod)) in
+  (X_GEN_TAC a THEN
+   CONV_TAC(funpow n BINDER_CONV (LAND_CONV(GEOM_TRANSLATE_CONV avoid a))) THEN
+   REWRITE_TAC[]) (asl,w);;
+
+(* ------------------------------------------------------------------------- *)
+(* Rename existential variables in conclusion to fresh genvars.              *)
+(* ------------------------------------------------------------------------- *)
+
+let EXISTS_GENVAR_RULE =
+  let rec rule vs th =
+    match vs with
+      [] -> th
+    | v::ovs -> let x,bod = dest_exists(concl th) in
+                let th1 = rule ovs (ASSUME bod) in
+                let th2 = SIMPLE_CHOOSE x (SIMPLE_EXISTS x th1) in
+                PROVE_HYP th (CONV_RULE (GEN_ALPHA_CONV v) th2) in
+  fun th -> rule (map (genvar o type_of) (fst(strip_exists(concl th)))) th;;
+
+(* ------------------------------------------------------------------------- *)
+(* Rotate so that WLOG some point is a +ve multiple of basis vector k.       *)
+(* For general N, it's better to use k = 1 so the side-condition can be      *)
+(* discharged. For dimensions 1, 2 and 3 anything will work automatically.   *)
+(* Could generalize by asking the user to prove theorem 1 <= k <= N.         *)
+(* ------------------------------------------------------------------------- *)
+
+let GEOM_BASIS_MULTIPLE_RULE =
+  let pth = prove
+   (`!f. orthogonal_transformation (f:real^N->real^N)
+         ==> (vec 0 = f(vec 0) /\
+              {} = IMAGE f {} /\
+              {} = IMAGE (IMAGE f) {} /\
+              (:real^N) = IMAGE f (:real^N) /\
+              (:real^N->bool) = IMAGE (IMAGE f) (:real^N->bool) /\
+              [] = MAP f []) /\
+             ((!P. (!x. P x) <=> (!x. P (f x))) /\
+              (!P. (?x. P x) <=> (?x. P (f x))) /\
+              (!Q. (!s. Q s) <=> (!s. Q (IMAGE f s))) /\
+              (!Q. (?s. Q s) <=> (?s. Q (IMAGE f s))) /\
+              (!Q. (!s. Q s) <=> (!s. Q (IMAGE (IMAGE f) s))) /\
+              (!Q. (?s. Q s) <=> (?s. Q (IMAGE (IMAGE f) s))) /\
+              (!P. (!g:real^1->real^N. P g) <=> (!g. P (f o g))) /\
+              (!P. (?g:real^1->real^N. P g) <=> (?g. P (f o g))) /\
+              (!P. (!g:num->real^N. P g) <=> (!g. P (f o g))) /\
+              (!P. (?g:num->real^N. P g) <=> (?g. P (f o g))) /\
+              (!Q. (!l. Q l) <=> (!l. Q(MAP f l))) /\
+              (!Q. (?l. Q l) <=> (?l. Q(MAP f l)))) /\
+             ((!P. {x | P x} = IMAGE f {x | P(f x)}) /\
+              (!Q. {s | Q s} = IMAGE (IMAGE f) {s | Q(IMAGE f s)}) /\
+              (!R. {l | R l} = IMAGE (MAP f) {l | R(MAP f l)}))`,
+    REPEAT GEN_TAC THEN DISCH_TAC THEN
+    FIRST_ASSUM(ASSUME_TAC o
+          MATCH_MP ORTHOGONAL_TRANSFORMATION_SURJECTIVE) THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[IMAGE_CLAUSES; MAP] THEN
+      FIRST_ASSUM(ASSUME_TAC o MATCH_MP ORTHOGONAL_TRANSFORMATION_LINEAR) THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[LINEAR_0]; ALL_TAC] THEN
+      REWRITE_TAC[SET_RULE `UNIV = IMAGE f UNIV <=> !y. ?x. f x = y`] THEN
+      ASM_REWRITE_TAC[SURJECTIVE_IMAGE];
+      MATCH_MP_TAC QUANTIFY_SURJECTION_HIGHER_THM THEN ASM_REWRITE_TAC[]])
+  and oth = prove
+   (`!f:real^N->real^N.
+        orthogonal_transformation f /\
+        (2 <= dimindex(:N) ==> det(matrix f) = &1)
+        ==> linear f /\
+            (!x y. f x = f y ==> x = y) /\
+            (!y. ?x. f x = y) /\
+            (!x. norm(f x) = norm x) /\
+            (2 <= dimindex(:N) ==> det(matrix f) = &1)`,
+    GEN_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_LINEAR];
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_INJECTIVE];
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_SURJECTIVE];
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION]])
+  and arithconv = REWRITE_CONV[DIMINDEX_1; DIMINDEX_2; DIMINDEX_3;
+                               ARITH_RULE `1 <= 1`; DIMINDEX_GE_1] THENC
+                  NUM_REDUCE_CONV in
+  fun k tm ->
+    let x,bod = dest_forall tm in
+    let th0 = ISPECL [x; mk_small_numeral k] ROTATION_RIGHTWARD_LINE in
+    let th1 = EXISTS_GENVAR_RULE
+     (MP th0 (EQT_ELIM(arithconv(lhand(concl th0))))) in
+    let [a;f],tm1 = strip_exists(concl th1) in
+    let th_orth,th2 = CONJ_PAIR(ASSUME tm1) in
+    let th_det,th2a = CONJ_PAIR th2 in
+    let th_works,th_zero = CONJ_PAIR th2a in
+    let thc,thq = CONJ_PAIR(PROVE_HYP th2 (UNDISCH(ISPEC f pth))) in
+    let th3 = CONV_RULE(RAND_CONV(SUBS_CONV(GSYM th_works::CONJUNCTS thc)))
+               (EXPAND_QUANTS_CONV(ASSUME(concl thq)) bod) in
+    let th4 = PROVE_HYP thq th3 in
+    let thps = CONJUNCTS(MATCH_MP oth (CONJ th_orth th_det)) in
+    let th5 = LINEAR_INVARIANTS f thps in
+    let th6 = PROVE_HYP th_orth
+     (GEN_REWRITE_RULE (RAND_CONV o REDEPTH_CONV) [BETA_THM; th5] th4) in
+    let ntm = mk_forall(a,mk_imp(concl th_zero,rand(concl th6))) in
+    let th7 = MP(SPEC a (ASSUME ntm)) th_zero in
+    let th8 = DISCH ntm (EQ_MP (SYM th6) th7) in
+    if intersect (frees(concl th8)) [a;f] = [] then
+      let th9 = PROVE_HYP th1 (itlist SIMPLE_CHOOSE [a;f] th8) in
+      let th10 = DISCH ntm (GEN x (UNDISCH th9)) in
+      let a' = variant (frees(concl th10))
+                (mk_var(fst(dest_var x),snd(dest_var a))) in
+      CONV_RULE(LAND_CONV (GEN_ALPHA_CONV a')) th10
+    else
+      let mtm = list_mk_forall([a;f],mk_imp(hd(hyp th8),rand(concl th6))) in
+      let th9 = EQ_MP (SYM th6) (UNDISCH(SPECL [a;f] (ASSUME mtm))) in
+      let th10 = itlist SIMPLE_CHOOSE [a;f] (DISCH mtm th9) in
+      let th11 = GEN x (PROVE_HYP th1 th10) in
+      MATCH_MP MONO_FORALL th11;;
+
+let GEOM_BASIS_MULTIPLE_TAC k l (asl,w as gl) =
+  let avs,bod = strip_forall w
+  and avs' = subtract (frees w) (freesl(map (concl o snd) asl)) in
+  (MAP_EVERY X_GEN_TAC avs THEN
+   MAP_EVERY (fun t -> SPEC_TAC(t,t)) (rev(subtract (avs@avs') [l])) THEN
+   SPEC_TAC(l,l) THEN
+   W(MATCH_MP_TAC o GEOM_BASIS_MULTIPLE_RULE k o snd)) gl;;
+
+(* ------------------------------------------------------------------------- *)
+(* Create invariance theorems automatically, in simple cases. If there are   *)
+(* any nested quantifiers, this will need surjectivity. It's often possible  *)
+(* to prove a stronger theorem by more delicate manual reasoning, so this    *)
+(* isn't used nearly as often as GEOM_TRANSLATE_CONV / GEOM_TRANSLATE_TAC.   *)
+(* As a small step, some ad-hoc rewrites analogous to FORALL_IN_IMAGE are    *)
+(* tried if the first step doesn't finish the goal, but it's very ad hoc.    *)
+(* ------------------------------------------------------------------------- *)
+
+let GEOM_TRANSFORM_TAC =
+  let cth0 = prove
+   (`!f:real^M->real^N.
+          linear f
+          ==> vec 0 = f(vec 0) /\
+              {} = IMAGE f {} /\
+              {} = IMAGE (IMAGE f) {}`,
+    REWRITE_TAC[IMAGE_CLAUSES] THEN MESON_TAC[LINEAR_0])
+  and cth1 = prove
+   (`!f:real^M->real^N.
+          (!y. ?x. f x = y)
+          ==> (:real^N) = IMAGE f (:real^M) /\
+              (:real^N->bool) = IMAGE (IMAGE f) (:real^M->bool)`,
+    REWRITE_TAC[SET_RULE `UNIV = IMAGE f UNIV <=> !y. ?x. f x = y`] THEN
+    REWRITE_TAC[SURJECTIVE_IMAGE])
+  and sths = (CONJUNCTS o prove)
+   (`(!f:real^M->real^N.
+         linear f /\ (!x. norm(f x) = norm x)
+         ==> (!x y. f x = f y ==> x = y)) /\
+     (!f:real^N->real^N.
+         linear f /\ (!x. norm(f x) = norm x) ==> (!y. ?x. f x = y)) /\
+     (!f:real^N->real^N. linear f /\ (!x y. f x = f y ==> x = y)
+                         ==> (!y. ?x. f x = y)) /\
+     (!f:real^N->real^N. linear f /\ (!y. ?x. f x = y)
+                         ==> (!x y. f x = f y ==> x = y))`,
+    CONJ_TAC THENL
+     [ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+      SIMP_TAC[GSYM LINEAR_SUB; GSYM NORM_EQ_0];
+      MESON_TAC[ORTHOGONAL_TRANSFORMATION_SURJECTIVE;
+                ORTHOGONAL_TRANSFORMATION_INJECTIVE; ORTHOGONAL_TRANSFORMATION;
+                LINEAR_SURJECTIVE_IFF_INJECTIVE]])
+  and aths = (CONJUNCTS o prove)
+   (`(!f s P. (!y. y IN IMAGE f s ==> P y) <=> (!x. x IN s ==> P(f x))) /\
+     (!f s P. (!u. u IN IMAGE (IMAGE f) s ==> P u) <=>
+              (!t. t IN s ==> P(IMAGE f t))) /\
+     (!f s P. (?y. y IN IMAGE f s /\ P y) <=> (?x. x IN s /\ P(f x))) /\
+     (!f s P. (?u. u IN IMAGE (IMAGE f) s /\ P u) <=>
+              (?t. t IN s /\ P(IMAGE f t)))`,
+    SET_TAC[]) in
+  fun avoid (asl,w as gl) ->
+    let f,wff = dest_forall w in
+    let vs,bod = strip_forall wff in
+    let ant,cons = dest_imp bod in
+    let hths = CONJUNCTS(ASSUME ant) in
+    let fths = hths @ mapfilter (USABLE_CONCLUSION f hths) sths in
+    let cths = mapfilter (USABLE_CONCLUSION f fths) [cth0; cth1]
+    and vconv =
+      try let vth = USABLE_CONCLUSION f fths QUANTIFY_SURJECTION_HIGHER_THM in
+          PROVE_HYP vth o PARTIAL_EXPAND_QUANTS_CONV avoid (ASSUME(concl vth))
+      with Failure _ -> ALL_CONV
+    and bths = LINEAR_INVARIANTS f fths in
+    (MAP_EVERY X_GEN_TAC (f::vs) THEN DISCH_TAC THEN
+     GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) cths THEN
+     CONV_TAC(LAND_CONV vconv) THEN
+     GEN_REWRITE_TAC (LAND_CONV o REDEPTH_CONV) [bths] THEN
+     REWRITE_TAC[] THEN
+     REWRITE_TAC(mapfilter (ADD_ASSUM ant o ISPEC f) aths) THEN
+     GEN_REWRITE_TAC (LAND_CONV o REDEPTH_CONV) [bths] THEN
+     REWRITE_TAC[]) gl;;
+
+(* ------------------------------------------------------------------------- *)
+(* Scale so that a chosen vector has size 1. Generates a conjunction of      *)
+(* two formulas, one for the zero case (which one hopes is trivial) and      *)
+(* one just like the original goal but with a norm(...) = 1 assumption.      *)
+(* ------------------------------------------------------------------------- *)
+
+let GEOM_NORMALIZE_RULE =
+  let pth = prove
+   (`!a:real^N. ~(a = vec 0)
+                ==> vec 0 = norm(a) % vec 0 /\
+                    a = norm(a) % inv(norm a) % a /\
+                    {} = IMAGE (\x. norm(a) % x) {} /\
+                    {} = IMAGE (IMAGE (\x. norm(a) % x)) {} /\
+                    (:real^N) = IMAGE (\x. norm(a) % x) (:real^N) /\
+                    (:real^N->bool) =
+                    IMAGE (IMAGE (\x. norm(a) % x)) (:real^N->bool) /\
+                    [] = MAP (\x. norm(a) % x) []`,
+    REWRITE_TAC[IMAGE_CLAUSES; VECTOR_MUL_ASSOC; VECTOR_MUL_RZERO; MAP] THEN
+    SIMP_TAC[NORM_EQ_0; REAL_MUL_RINV; VECTOR_MUL_LID] THEN
+    GEN_TAC THEN DISCH_TAC THEN
+    REWRITE_TAC[SET_RULE `UNIV = IMAGE f UNIV <=> !y. ?x. f x = y`] THEN
+    ASM_REWRITE_TAC[SURJECTIVE_IMAGE] THEN
+    X_GEN_TAC `y:real^N` THEN EXISTS_TAC `inv(norm(a:real^N)) % y:real^N` THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; NORM_EQ_0; REAL_MUL_RINV; VECTOR_MUL_LID])
+  and qth = prove
+   (`!a:real^N.
+        ~(a = vec 0)
+        ==> ((!P. (!r:real. P r) <=> (!r. P(norm a * r))) /\
+             (!P. (?r:real. P r) <=> (?r. P(norm a * r))) /\
+             (!P. (!x:real^N. P x) <=> (!x. P (norm(a) % x))) /\
+             (!P. (?x:real^N. P x) <=> (?x. P (norm(a) % x))) /\
+             (!Q. (!s:real^N->bool. Q s) <=>
+                  (!s. Q(IMAGE (\x. norm(a) % x) s))) /\
+             (!Q. (?s:real^N->bool. Q s) <=>
+                  (?s. Q(IMAGE (\x. norm(a) % x) s))) /\
+             (!Q. (!s:(real^N->bool)->bool. Q s) <=>
+                  (!s. Q(IMAGE (IMAGE (\x. norm(a) % x)) s))) /\
+             (!Q. (?s:(real^N->bool)->bool. Q s) <=>
+                  (?s. Q(IMAGE (IMAGE (\x. norm(a) % x)) s))) /\
+             (!P. (!g:real^1->real^N. P g) <=>
+                  (!g. P ((\x. norm(a) % x) o g))) /\
+             (!P. (?g:real^1->real^N. P g) <=>
+                  (?g. P ((\x. norm(a) % x) o g))) /\
+             (!P. (!g:num->real^N. P g) <=>
+                  (!g. P ((\x. norm(a) % x) o g))) /\
+             (!P. (?g:num->real^N. P g) <=>
+                  (?g. P ((\x. norm(a) % x) o g))) /\
+             (!Q. (!l. Q l) <=> (!l. Q(MAP (\x:real^N. norm(a) % x) l))) /\
+             (!Q. (?l. Q l) <=> (?l. Q(MAP (\x:real^N. norm(a) % x) l)))) /\
+            ((!P. {x:real^N | P x} =
+                  IMAGE (\x. norm(a) % x) {x | P(norm(a) % x)}) /\
+             (!Q. {s:real^N->bool | Q s} =
+                  IMAGE (IMAGE (\x. norm(a) % x))
+                       {s | Q(IMAGE (\x. norm(a) % x) s)}) /\
+             (!R. {l:(real^N)list | R l} =
+                  IMAGE (MAP (\x:real^N. norm(a) % x))
+                        {l | R(MAP (\x:real^N. norm(a) % x) l)}))`,
+    GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC(TAUT
+     `(a /\ b) /\ c /\ d ==> (a /\ b /\ c) /\ d`) THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[NORM_EQ_0; REAL_FIELD `~(x = &0) ==> x * inv x * a = a`];
+      MP_TAC(ISPEC `\x:real^N. norm(a:real^N) % x`
+        (INST_TYPE [`:real^1`,`:C`] QUANTIFY_SURJECTION_HIGHER_THM)) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_MP_TAC THEN
+      ASM_SIMP_TAC[SURJECTIVE_SCALING; NORM_EQ_0]])
+  and lth = prove
+   (`(!b:real^N. ~(b = vec 0) ==> (P(b) <=> Q(inv(norm b) % b)))
+     ==> P(vec 0) /\ (!b. norm(b) = &1 ==> Q b) ==> (!b. P b)`,
+    REPEAT STRIP_TAC THEN
+    ASM_CASES_TAC `b:real^N = vec 0` THEN ASM_SIMP_TAC[] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM;
+                 REAL_MUL_LINV; NORM_EQ_0]) in
+  fun avoid tm ->
+    let x,tm0 = dest_forall tm in
+    let cth = UNDISCH(ISPEC x pth)
+    and vth = UNDISCH(ISPEC x qth) in
+    let th1 = ONCE_REWRITE_CONV[cth] tm0 in
+    let th2 = CONV_RULE (RAND_CONV
+     (PARTIAL_EXPAND_QUANTS_CONV avoid vth)) th1 in
+    let th3 = SCALING_THEOREMS x in
+    let th3' = (end_itlist CONJ (map
+       (fun th -> let avs,_ = strip_forall(concl th) in
+                  let gvs = map (genvar o type_of) avs in
+                  GENL gvs (SPECL gvs th))
+       (CONJUNCTS th3))) in
+    let th4 = GEN_REWRITE_RULE (RAND_CONV o REDEPTH_CONV)
+               [BETA_THM; th3'] th2 in
+    MATCH_MP lth (GEN x (DISCH_ALL th4));;
+
+let GEN_GEOM_NORMALIZE_TAC x avoid (asl,w as gl) =
+  let avs,bod = strip_forall w
+  and avs' = subtract (frees w) (freesl(map (concl o snd) asl)) in
+  (MAP_EVERY X_GEN_TAC avs THEN
+   MAP_EVERY (fun t -> SPEC_TAC(t,t)) (rev(subtract (avs@avs') [x])) THEN
+   SPEC_TAC(x,x) THEN
+   W(MATCH_MP_TAC o GEOM_NORMALIZE_RULE avoid o snd)) gl;;
+
+let GEOM_NORMALIZE_TAC x = GEN_GEOM_NORMALIZE_TAC x [];;
+
+(* ------------------------------------------------------------------------- *)
+(* Add invariance theorems for collinearity.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let COLLINEAR_TRANSLATION_EQ = prove
+ (`!a s. collinear (IMAGE (\x. a + x) s) <=> collinear s`,
+  REWRITE_TAC[collinear] THEN GEOM_TRANSLATE_TAC["u"]);;
+
+add_translation_invariants [COLLINEAR_TRANSLATION_EQ];;
+
+let COLLINEAR_TRANSLATION = prove
+ (`!s a. collinear s ==> collinear (IMAGE (\x. a + x) s)`,
+  REWRITE_TAC[COLLINEAR_TRANSLATION_EQ]);;
+
+let COLLINEAR_LINEAR_IMAGE = prove
+ (`!f s. collinear s /\ linear f ==> collinear(IMAGE f s)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[collinear; IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  ASM_MESON_TAC[LINEAR_SUB; LINEAR_CMUL]);;
+
+let COLLINEAR_LINEAR_IMAGE_EQ = prove
+ (`!f s. linear f /\ (!x y. f x = f y ==> x = y)
+         ==> (collinear (IMAGE f s) <=> collinear s)`,
+  MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE COLLINEAR_LINEAR_IMAGE));;
+
+add_linear_invariants [COLLINEAR_LINEAR_IMAGE_EQ];;
+
+(* ------------------------------------------------------------------------- *)
+(* Take a theorem "th" with outer universal quantifiers involving real^N     *)
+(* and a theorem "dth" asserting |- dimindex(:M) <= dimindex(:N) and         *)
+(* return a theorem replacing type :N by :M in th. Neither N or M need be a  *)
+(* type variable.                                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let GEOM_DROP_DIMENSION_RULE =
+  let oth = prove
+   (`!f:real^M->real^N.
+          linear f /\ (!x. norm(f x) = norm x)
+          ==> linear f /\
+              (!x y. f x = f y ==> x = y) /\
+              (!x. norm(f x) = norm x)`,
+    MESON_TAC[PRESERVES_NORM_INJECTIVE])
+  and cth = prove
+   (`linear(f:real^M->real^N)
+     ==> vec 0 = f(vec 0) /\
+         {} = IMAGE f {} /\
+         {} = IMAGE (IMAGE f) {} /\
+         [] = MAP f []`,
+    REWRITE_TAC[IMAGE_CLAUSES; MAP; GSYM LINEAR_0]) in
+  fun dth th ->
+    let ath = GEN_ALL th
+    and eth = MATCH_MP ISOMETRY_UNIV_UNIV dth
+    and avoid = variables(concl th) in
+    let f,bod = dest_exists(concl eth) in
+    let fimage = list_mk_icomb "IMAGE" [f]
+    and fmap = list_mk_icomb "MAP" [f]
+    and fcompose = list_mk_icomb "o" [f] in
+    let fimage2 = list_mk_icomb "IMAGE" [fimage] in
+    let lin,iso = CONJ_PAIR(ASSUME bod) in
+    let olduniv = rand(rand(concl dth))
+    and newuniv = rand(lhand(concl dth)) in
+    let oldty = fst(dest_fun_ty(type_of olduniv))
+    and newty = fst(dest_fun_ty(type_of newuniv)) in
+    let newvar v =
+       let n,t = dest_var v in
+       variant avoid (mk_var(n,tysubst[newty,oldty] t)) in
+    let newterm v =
+      try let v' = newvar v in
+          tryfind (fun f -> mk_comb(f,v')) [f;fimage;fmap;fcompose;fimage2]
+      with Failure _ -> v in
+    let specrule th =
+      let v = fst(dest_forall(concl th)) in SPEC (newterm v) th in
+    let sth = SUBS(CONJUNCTS(MATCH_MP cth lin)) ath in
+    let fth = SUBS[SYM(MATCH_MP LINEAR_0 lin)] (repeat specrule sth) in
+    let thps = CONJUNCTS(MATCH_MP oth (ASSUME bod)) in
+    let th5 = LINEAR_INVARIANTS f thps in
+    let th6 = GEN_REWRITE_RULE REDEPTH_CONV [th5] fth in
+    let th7 = PROVE_HYP eth (SIMPLE_CHOOSE f th6) in
+    GENL (map newvar (fst(strip_forall(concl ath)))) th7;;
+
+(* ------------------------------------------------------------------------- *)
+(* Transfer theorems automatically between same-dimension spaces.            *)
+(* Given dth = A |- dimindex(:M) = dimindex(:N)                              *)
+(* and a theorem th involving variables of type real^N                       *)
+(* returns a corresponding theorem mapped to type real^M with assumptions A. *)
+(* ------------------------------------------------------------------------- *)
+
+let GEOM_EQUAL_DIMENSION_RULE =
+  let bth = prove
+   (`dimindex(:M) = dimindex(:N)
+     ==> ?f:real^M->real^N.
+             (linear f /\ (!y. ?x. f x = y)) /\
+             (!x. norm(f x) = norm x)`,
+    REWRITE_TAC[SET_RULE `(!y. ?x. f x = y) <=> IMAGE f UNIV = UNIV`] THEN
+    DISCH_TAC THEN REWRITE_TAC[GSYM CONJ_ASSOC] THEN
+    MATCH_MP_TAC ISOMETRY_UNIV_SUBSPACE THEN
+    REWRITE_TAC[SUBSPACE_UNIV; DIM_UNIV] THEN FIRST_ASSUM ACCEPT_TAC)
+  and pth = prove
+   (`!f:real^M->real^N.
+        linear f /\ (!y. ?x. f x = y)
+         ==> (vec 0 = f(vec 0) /\
+              {} = IMAGE f {} /\
+              {} = IMAGE (IMAGE f) {} /\
+              (:real^N) = IMAGE f (:real^M) /\
+              (:real^N->bool) = IMAGE (IMAGE f) (:real^M->bool) /\
+              [] = MAP f []) /\
+             ((!P. (!x. P x) <=> (!x. P (f x))) /\
+              (!P. (?x. P x) <=> (?x. P (f x))) /\
+              (!Q. (!s. Q s) <=> (!s. Q (IMAGE f s))) /\
+              (!Q. (?s. Q s) <=> (?s. Q (IMAGE f s))) /\
+              (!Q. (!s. Q s) <=> (!s. Q (IMAGE (IMAGE f) s))) /\
+              (!Q. (?s. Q s) <=> (?s. Q (IMAGE (IMAGE f) s))) /\
+              (!P. (!g:real^1->real^N. P g) <=> (!g. P (f o g))) /\
+              (!P. (?g:real^1->real^N. P g) <=> (?g. P (f o g))) /\
+              (!P. (!g:num->real^N. P g) <=> (!g. P (f o g))) /\
+              (!P. (?g:num->real^N. P g) <=> (?g. P (f o g))) /\
+              (!Q. (!l. Q l) <=> (!l. Q(MAP f l))) /\
+              (!Q. (?l. Q l) <=> (?l. Q(MAP f l)))) /\
+             ((!P. {x | P x} = IMAGE f {x | P(f x)}) /\
+              (!Q. {s | Q s} = IMAGE (IMAGE f) {s | Q(IMAGE f s)}) /\
+              (!R. {l | R l} = IMAGE (MAP f) {l | R(MAP f l)}))`,
+    GEN_TAC THEN
+    SIMP_TAC[SET_RULE `UNIV = IMAGE f UNIV <=> (!y. ?x. f x = y)`;
+             SURJECTIVE_IMAGE] THEN
+    MATCH_MP_TAC MONO_AND THEN
+    REWRITE_TAC[QUANTIFY_SURJECTION_HIGHER_THM] THEN
+    REWRITE_TAC[IMAGE_CLAUSES; MAP] THEN MESON_TAC[LINEAR_0]) in
+  fun dth th ->
+    let eth = EXISTS_GENVAR_RULE (MATCH_MP bth dth) in
+    let f,bod = dest_exists(concl eth) in
+    let lsth,neth = CONJ_PAIR(ASSUME bod) in
+    let cth,qth = CONJ_PAIR(MATCH_MP pth lsth) in
+    let th1 = CONV_RULE
+     (EXPAND_QUANTS_CONV qth THENC SUBS_CONV(CONJUNCTS cth)) th in
+    let ith = LINEAR_INVARIANTS f (neth::CONJUNCTS lsth) in
+    let th2 = GEN_REWRITE_RULE (RAND_CONV o REDEPTH_CONV) [BETA_THM;ith] th1 in
+    let th3 = GEN f (DISCH bod th2) in
+    MP (CONV_RULE (REWR_CONV LEFT_FORALL_IMP_THM) th3) eth;;
diff --git a/Multivariate/dimension.ml b/Multivariate/dimension.ml
new file mode 100644 (file)
index 0000000..d45401d
--- /dev/null
@@ -0,0 +1,6177 @@
+(* ========================================================================= *)
+(* Results connected with topological dimension.                             *)
+(*                                                                           *)
+(* At the moment this is just Brouwer's fixpoint theorem. The proof is from  *)
+(* Kuhn: "some combinatorial lemmas in topology", IBM J. v4. (1960) p. 518   *)
+(* See "http://www.research.ibm.com/journal/rd/045/ibmrd0405K.pdf".          *)
+(*                                                                           *)
+(* The script below is quite messy, but at least we avoid formalizing any    *)
+(* topological machinery; we don't even use barycentric subdivision; this is *)
+(* the big advantage of Kuhn's proof over the usual Sperner's lemma one.     *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(* ========================================================================= *)
+
+needs "Multivariate/topology.ml";;
+needs "Multivariate/paths.ml";;
+
+let BROUWER_COMPACTNESS_LEMMA = prove
+ (`!f:real^M->real^N s.
+        compact s /\ f continuous_on s /\ ~(?x. x IN s /\ (f x = vec 0))
+        ==> ?d. &0 < d /\ !x. x IN s ==> d <= norm(f x)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`norm o (f:real^M->real^N)`; `s:real^M->bool`]
+                CONTINUOUS_ATTAINS_INF) THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THENL
+   [MESON_TAC[REAL_LT_01]; ALL_TAC] THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_COMPOSE; o_ASSOC; CONTINUOUS_ON_LIFT_NORM] THEN
+  REWRITE_TAC[o_THM] THEN ASM_MESON_TAC[NORM_POS_LT]);;
+
+let KUHN_LABELLING_LEMMA = prove
+ (`!f:real^N->real^N P Q.
+        (!x. P x ==> P (f x))
+        ==> (!x. P x ==> (!i. Q i ==> &0 <= x$i /\ x$i <= &1))
+            ==> ?l. (!x i. l x i <= 1) /\
+                    (!x i. P x /\ Q i /\ (x$i = &0) ==> (l x i = 0)) /\
+                    (!x i. P x /\ Q i /\ (x$i = &1) ==> (l x i = 1)) /\
+                    (!x i. P x /\ Q i /\ (l x i = 0) ==> x$i <= f(x)$i) /\
+                    (!x i. P x /\ Q i /\ (l x i = 1) ==> f(x)$i <= x$i)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[AND_FORALL_THM;  GSYM SKOLEM_THM] THEN
+  REWRITE_TAC[ARITH_RULE `n <= 1 <=> (n = 0) \/ (n = 1)`;
+              RIGHT_OR_DISTRIB; EXISTS_OR_THM; UNWIND_THM2; ARITH_EQ] THEN
+  MESON_TAC[REAL_ARITH
+   `!x y. &0 <= x /\ x <= &1 /\ &0 <= y /\ y <= &1
+          ==> ~(x = &1) /\ x <= y \/ ~(x = &0) /\ y <= x`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The key "counting" observation, somewhat abstracted.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let KUHN_COUNTING_LEMMA = prove
+ (`!face:F->S->bool faces simplices comp comp' bnd.
+        FINITE faces /\ FINITE simplices /\
+        (!f. f IN faces /\ bnd f
+             ==> (CARD {s | s IN simplices /\ face f s} = 1)) /\
+        (!f. f IN faces /\ ~bnd f
+             ==> (CARD {s | s IN simplices /\ face f s} = 2)) /\
+        (!s. s IN simplices /\ comp s
+             ==> (CARD {f | f IN faces /\ face f s /\ comp' f} = 1)) /\
+        (!s. s IN simplices /\ ~comp s
+             ==> (CARD {f | f IN faces /\ face f s /\ comp' f} = 0) \/
+                 (CARD {f | f IN faces /\ face f s /\ comp' f} = 2))
+        ==> ODD(CARD {f | f IN faces /\ comp' f /\ bnd f})
+            ==> ODD(CARD {s | s IN simplices /\ comp s})`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `sum simplices
+     (\s:S. &(CARD {f:F | f IN faces /\ face f s /\ comp' f})) =
+    sum simplices
+     (\s. &(CARD {f | f IN {f | f IN faces /\ comp' f /\ bnd f} /\
+                      face f s})) +
+    sum simplices
+     (\s. &(CARD {f | f IN {f | f IN faces /\ comp' f /\ ~(bnd f)} /\
+                      face f s}))`
+  MP_TAC THENL
+   [ASM_SIMP_TAC[GSYM SUM_ADD] THEN MATCH_MP_TAC SUM_EQ THEN
+    ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+    REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_EQ] THEN
+    MATCH_MP_TAC CARD_UNION_EQ THEN ASM_SIMP_TAC[FINITE_RESTRICT] THEN
+    REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INTER; IN_UNION; NOT_IN_EMPTY] THEN
+    CONJ_TAC THEN GEN_TAC THEN CONV_TAC TAUT;
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`\s f. (face:F->S->bool) f s`; `simplices:S->bool`;
+    `{f:F | f IN faces /\ comp' f /\ bnd f}`; `1`] SUM_MULTICOUNT) THEN
+  MP_TAC(ISPECL
+   [`\s f. (face:F->S->bool) f s`; `simplices:S->bool`;
+    `{f:F | f IN faces /\ comp' f /\ ~(bnd f)}`; `2`] SUM_MULTICOUNT) THEN
+  REWRITE_TAC[] THEN
+  REPEAT(ANTS_TAC THENL
+   [ASM_SIMP_TAC[FINITE_RESTRICT] THEN GEN_TAC THEN
+    DISCH_THEN(fun th -> FIRST_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+    SIMP_TAC[IN_ELIM_THM];
+    DISCH_THEN SUBST1_TAC]) THEN
+  SUBGOAL_THEN
+   `sum simplices
+     (\s:S. &(CARD {f:F | f IN faces /\ face f s /\ comp' f})) =
+    sum {s | s IN simplices /\ comp s}
+        (\s:S. &(CARD {f:F | f IN faces /\ face f s /\ comp' f})) +
+    sum {s | s IN simplices /\ ~(comp s)}
+        (\s:S. &(CARD {f:F | f IN faces /\ face f s /\ comp' f}))`
+  SUBST1_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_UNION_EQ THEN
+    ASM_REWRITE_TAC[] THEN REWRITE_TAC[EXTENSION; NOT_IN_EMPTY] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_INTER; IN_UNION] THEN
+    CONJ_TAC THEN GEN_TAC THEN CONV_TAC TAUT;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `sum {s | s IN simplices /\ comp s}
+        (\s:S. &(CARD {f:F | f IN faces /\ face f s /\ comp' f})) =
+    sum {s | s IN simplices /\ comp s} (\s. &1)`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC SUM_EQ THEN ASM_SIMP_TAC[FINITE_RESTRICT] THEN
+    GEN_TAC THEN REWRITE_TAC[REAL_OF_NUM_EQ] THEN
+    DISCH_THEN(fun th -> FIRST_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+    SIMP_TAC[IN_ELIM_THM];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `sum {s | s IN simplices /\ ~(comp s)}
+        (\s:S. &(CARD {f:F | f IN faces /\ face f s /\ comp' f})) =
+    sum {s | s IN simplices /\ ~(comp s) /\
+             (CARD {f | f IN faces /\ face f s /\ comp' f} = 0)}
+        (\s:S. &(CARD {f:F | f IN faces /\ face f s /\ comp' f})) +
+    sum {s | s IN simplices /\ ~(comp s) /\
+             (CARD {f | f IN faces /\ face f s /\ comp' f} = 2)}
+        (\s:S. &(CARD {f:F | f IN faces /\ face f s /\ comp' f}))`
+  SUBST1_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_UNION_EQ THEN
+    ASM_SIMP_TAC[FINITE_RESTRICT] THEN
+    REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_INTER; IN_UNION] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[IN_ELIM_THM] THEN MESON_TAC[ARITH_RULE `~(2 = 0)`];
+      ALL_TAC] THEN
+    X_GEN_TAC `s:S` THEN UNDISCH_TAC
+     `!s:S. s IN simplices /\ ~comp s
+            ==> (CARD {f:F | f IN faces /\ face f s /\ comp' f} = 0) \/
+                (CARD {f | f IN faces /\ face f s /\ comp' f} = 2)` THEN
+    DISCH_THEN(MP_TAC o SPEC `s:S`) THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN CONV_TAC TAUT;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n. sum {s | s IN simplices /\ ~(comp s) /\
+             (CARD {f | f IN faces /\ face f s /\ comp' f} = n)}
+            (\s:S. &(CARD {f:F | f IN faces /\ face f s /\ comp' f})) =
+        sum {s | s IN simplices /\ ~(comp s) /\
+             (CARD {f | f IN faces /\ face f s /\ comp' f} = n)}
+            (\s:S. &n)`
+   (fun th -> REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN MATCH_MP_TAC SUM_EQ THEN ASM_SIMP_TAC[FINITE_RESTRICT] THEN
+    SIMP_TAC[IN_ELIM_THM];
+    ALL_TAC] THEN
+  REWRITE_TAC[SUM_0] THEN ASM_SIMP_TAC[SUM_CONST; FINITE_RESTRICT] THEN
+  REWRITE_TAC[REAL_OF_NUM_MUL; REAL_OF_NUM_ADD; REAL_OF_NUM_EQ] THEN
+  REWRITE_TAC[ADD_CLAUSES; MULT_CLAUSES] THEN
+  FIRST_X_ASSUM(CHOOSE_THEN SUBST1_TAC o GEN_REWRITE_RULE I [ODD_EXISTS]) THEN
+  DISCH_THEN(MP_TAC o AP_TERM `ODD`) THEN
+  REWRITE_TAC[ODD_ADD; ODD_MULT; ARITH_ODD; ODD]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The odd/even result for faces of complete vertices, generalized.          *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_SIZE_1_EXISTS = prove
+ (`!s. s HAS_SIZE 1 <=> ?!x. x IN s`,
+  REPEAT GEN_TAC THEN CONV_TAC(LAND_CONV HAS_SIZE_CONV) THEN
+  REWRITE_TAC[EXTENSION; IN_SING] THEN MESON_TAC[]);;
+
+let HAS_SIZE_2_EXISTS = prove
+ (`!s. s HAS_SIZE 2 <=> ?x y. ~(x = y) /\ !z. z IN s <=> (z = x) \/ (z = y)`,
+  REPEAT GEN_TAC THEN CONV_TAC(LAND_CONV HAS_SIZE_CONV) THEN
+  REWRITE_TAC[EXTENSION; IN_INSERT; NOT_IN_EMPTY] THEN MESON_TAC[]);;
+
+let IMAGE_LEMMA_0 = prove
+ (`!f:A->B s n.
+      {a | a IN s /\ (IMAGE f (s DELETE a) = t DELETE b)} HAS_SIZE n
+      ==> {s' | ?a. a IN s /\ (s' = s DELETE a) /\ (IMAGE f s' = t DELETE b)}
+          HAS_SIZE n`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `{s' | ?a. a IN s /\ (s' = s DELETE a) /\ (IMAGE f s' = t DELETE b)} =
+    IMAGE (\a. s DELETE a)
+          {a | a IN s /\ (IMAGE (f:A->B) (s DELETE a) = t DELETE b)}`
+  SUBST1_TAC THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_IMAGE] THEN MESON_TAC[];
+    MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_DELETE] THEN MESON_TAC[]]);;
+
+let IMAGE_LEMMA_1 = prove
+ (`!f:A->B s t b.
+        FINITE s /\ FINITE t /\ (CARD s = CARD t) /\
+        (IMAGE f s = t) /\ b IN t
+        ==> (CARD {s' | ?a. a IN s /\ (s' = s DELETE a) /\
+                            (IMAGE f s' = t DELETE b)} = 1)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_SIZE_CARD THEN
+  MATCH_MP_TAC IMAGE_LEMMA_0 THEN REWRITE_TAC[HAS_SIZE_1_EXISTS] THEN
+  SUBGOAL_THEN `!x y. x IN s /\ y IN s /\ ((f:A->B) x = f y) ==> (x = y)`
+  ASSUME_TAC THENL [ASM_MESON_TAC[IMAGE_IMP_INJECTIVE_GEN]; ALL_TAC] THEN
+  REWRITE_TAC[EXISTS_UNIQUE_THM; IN_ELIM_THM] THEN CONJ_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+  REWRITE_TAC[IN_IMAGE] THENL
+   [DISCH_THEN(fun th -> MP_TAC(SPEC `b:B` th) THEN MP_TAC th) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_TAC THEN MATCH_MP_TAC MONO_EXISTS THEN
+    REWRITE_TAC[EXTENSION; IN_IMAGE; IN_DELETE] THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[];
+    REWRITE_TAC[EXTENSION; IN_IMAGE; IN_DELETE] THEN ASM_MESON_TAC[]]);;
+
+let IMAGE_LEMMA_2 = prove
+ (`!f:A->B s t b.
+        FINITE s /\ FINITE t /\ (CARD s = CARD t) /\
+        (IMAGE f s) SUBSET t /\ ~(IMAGE f s = t) /\ b IN t
+        ==> (CARD {s' | ?a. a IN s /\ (s' = s DELETE a) /\
+                            (IMAGE f s' = t DELETE b)} = 0) \/
+            (CARD {s' | ?a. a IN s /\ (s' = s DELETE a) /\
+                            (IMAGE f s' = t DELETE b)} = 2)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC
+   `{a | a IN s /\ (IMAGE (f:A->B) (s DELETE a) = t DELETE b)} = {}`
+  THENL [DISJ1_TAC; DISJ2_TAC] THEN MATCH_MP_TAC HAS_SIZE_CARD THEN
+  MATCH_MP_TAC IMAGE_LEMMA_0 THEN
+  ASM_REWRITE_TAC[HAS_SIZE_0; HAS_SIZE_2_EXISTS] 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 `a1:A` THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `(f:A->B) a1 IN (t DELETE b)` ASSUME_TAC THENL
+   [REWRITE_TAC[IN_DELETE] THEN
+    ASM_MESON_TAC[SUBSET; IN_IMAGE; INSERT_DELETE; IMAGE_CLAUSES];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+  DISCH_THEN(MP_TAC o SPEC `(f:A->B) a1`) THEN ASM_REWRITE_TAC[IN_IMAGE] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a2:A` THEN
+  REWRITE_TAC[IN_DELETE] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `!x y. x IN (s DELETE a1) /\ y IN (s DELETE a1) /\ ((f:A->B) x = f y)
+          ==> (x = y)`
+  MP_TAC THENL
+   [MATCH_MP_TAC IMAGE_IMP_INJECTIVE_GEN THEN EXISTS_TAC `t DELETE (b:B)` THEN
+    ASM_SIMP_TAC[CARD_DELETE; FINITE_DELETE];
+    REWRITE_TAC[IN_DELETE] THEN DISCH_TAC] THEN
+  X_GEN_TAC `a:A` THEN ASM_CASES_TAC `a:A = a1` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `(a:A) IN s` THEN ASM_REWRITE_TAC[] THENL
+   [ALL_TAC; ASM_MESON_TAC[]] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `(f:A->B) a = f a1` THEN CONJ_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[IN_DELETE]] THEN
+  FIRST_X_ASSUM(fun t -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [SYM t]) THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_DELETE] THEN EQ_TAC THENL
+   [DISCH_THEN(MP_TAC o SPEC `(f:A->B) a`); ALL_TAC] THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Combine this with the basic counting lemma.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let KUHN_COMPLETE_LEMMA = prove
+ (`!face:(A->bool)->(A->bool)->bool simplices rl bnd n.
+        FINITE simplices /\
+        (!f s. face f s <=> ?a. a IN s /\ (f = s DELETE a)) /\
+        (!s. s IN simplices ==> s HAS_SIZE (n + 2) /\
+                                (IMAGE rl s) SUBSET 0..n+1) /\
+        (!f. f IN {f | ?s. s IN simplices /\ face f s} /\ bnd f
+             ==> (CARD {s | s IN simplices /\ face f s} = 1)) /\
+        (!f. f IN {f | ?s. s IN simplices /\ face f s} /\ ~bnd f
+             ==> (CARD {s | s IN simplices /\ face f s} = 2))
+        ==> ODD(CARD {f | f IN {f | ?s. s IN simplices /\ face f s} /\
+                          (IMAGE rl f = 0..n) /\ bnd f})
+            ==> ODD(CARD {s | s IN simplices /\ (IMAGE rl s = 0..n+1)})`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!P f:A->bool s.
+       s IN simplices
+       ==> (f IN {f | ?s. s IN simplices /\ (?a. a IN s /\ (f = s DELETE a))} /\
+            (?a. a IN s /\ (f = s DELETE a)) /\ P f <=>
+           (?a. a IN s /\ (f = s DELETE a) /\ P f))`
+  ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[IN_ELIM_THM] THEN MESON_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `0..n = (0..n+1) DELETE (n+1)` SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_NUMSEG; IN_DELETE] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC KUHN_COUNTING_LEMMA THEN
+  EXISTS_TAC `face:(A->bool)->(A->bool)->bool` THEN
+  REPEAT CONJ_TAC THEN TRY(FIRST_ASSUM ACCEPT_TAC) THEN
+  ASM_SIMP_TAC[] THENL
+   [SUBGOAL_THEN
+     `{f:A->bool | ?s. s IN simplices /\ (?a. a IN s /\ (f = s DELETE a))} =
+      UNIONS (IMAGE (\s. {f | ?a. a IN s /\ (f = s DELETE a)}) simplices)`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[EXTENSION; UNIONS_IMAGE; IN_ELIM_THM]; ALL_TAC] THEN
+    ASM_SIMP_TAC[FINITE_UNIONS; FINITE_IMAGE] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE] THEN X_GEN_TAC `s:A->bool` THEN
+    DISCH_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC `{t:A->bool | t SUBSET s}` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC FINITE_POWERSET THEN ASM_MESON_TAC[HAS_SIZE];
+      SIMP_TAC[SUBSET; IN_ELIM_THM; LEFT_IMP_EXISTS_THM; IN_DELETE]];
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC IMAGE_LEMMA_1;
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC IMAGE_LEMMA_2] THEN
+  ASM_REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG; LE_0; LE_REFL] THEN
+  REWRITE_TAC[CARD_NUMSEG; ARITH_RULE `((n + 1) + 1) - 0 = n + 2`] THEN
+  ASM_MESON_TAC[HAS_SIZE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* We use the following notion of ordering rather than pointwise indexing.   *)
+(* ------------------------------------------------------------------------- *)
+
+let kle = new_definition
+  `kle n x y <=> ?k. k SUBSET 1..n /\
+                     (!j. y(j) = x(j) + (if j IN k then 1 else 0))`;;
+
+let KLE_REFL = prove
+ (`!n x. kle n x x`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[kle] THEN EXISTS_TAC `{}:num->bool` THEN
+  REWRITE_TAC[ADD_CLAUSES; NOT_IN_EMPTY; EMPTY_SUBSET]);;
+
+let KLE_ANTISYM = prove
+ (`!n x y. kle n x y /\ kle n y x <=> (x = y)`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL [REWRITE_TAC[kle]; MESON_TAC[KLE_REFL]] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  ASM_REWRITE_TAC[FUN_EQ_THM] THEN
+  MESON_TAC[ARITH_RULE `(x = (x + a) + b) ==> (x = x + a:num)`]);;
+
+let POINTWISE_MINIMAL,POINTWISE_MAXIMAL = (CONJ_PAIR o prove)
+ (`(!s:(num->num)->bool.
+        FINITE s
+        ==> ~(s = {}) /\
+            (!x y. x IN s /\ y IN s
+                   ==> (!j. x(j) <= y(j)) \/ (!j. y(j) <= x(j)))
+            ==> ?a. a IN s /\ !x. x IN s ==> !j. a(j) <= x(j)) /\
+   (!s:(num->num)->bool.
+        FINITE s
+        ==> ~(s = {}) /\
+            (!x y. x IN s /\ y IN s
+                   ==> (!j. x(j) <= y(j)) \/ (!j. y(j) <= x(j)))
+            ==> ?a. a IN s /\ !x. x IN s ==> !j. x(j) <= a(j))`,
+  CONJ_TAC THEN
+  (MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[NOT_INSERT_EMPTY] THEN
+   MAP_EVERY X_GEN_TAC [`a:num->num`; `s:(num->num)->bool`] THEN
+   ASM_CASES_TAC `s:(num->num)->bool = {}` THEN ASM_REWRITE_TAC[] THENL
+    [REWRITE_TAC[IN_SING] THEN MESON_TAC[LE_REFL]; ALL_TAC] THEN
+   DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+   DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+   ANTS_TAC THENL [ASM_MESON_TAC[IN_INSERT]; ALL_TAC] THEN
+   DISCH_THEN(X_CHOOSE_THEN `b:num->num` STRIP_ASSUME_TAC) THEN
+   FIRST_X_ASSUM(MP_TAC o SPECL [`a:num->num`; `b:num->num`]) THEN
+   ASM_REWRITE_TAC[IN_INSERT] THEN ASM_MESON_TAC[LE_CASES; LE_TRANS]));;
+
+let KLE_IMP_POINTWISE = prove
+ (`!n x y. kle n x y ==> !j. x(j) <= y(j)`,
+  REWRITE_TAC[kle] THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[LE_ADD]);;
+
+let POINTWISE_ANTISYM = prove
+ (`!x y:num->num. (!j. x(j) <= y(j)) /\ (!j. y(j) <= x(j)) <=> (x = y)`,
+  REWRITE_TAC[AND_FORALL_THM; FUN_EQ_THM; LE_ANTISYM]);;
+
+let KLE_TRANS = prove
+ (`!x y z n. kle n x y /\ kle n y z /\ (kle n x z \/ kle n z x)
+             ==> kle n x z`,
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `x:num->num = z` (fun th -> REWRITE_TAC[KLE_REFL; th]) THEN
+  REWRITE_TAC[FUN_EQ_THM; GSYM LE_ANTISYM; FORALL_AND_THM] THEN
+  ASM_MESON_TAC[KLE_IMP_POINTWISE; LE_TRANS]);;
+
+let KLE_STRICT = prove
+ (`!n x y. kle n x y /\ ~(x = y)
+           ==> (!j. x(j) <= y(j)) /\ (?k. 1 <= k /\ k <= n /\ x(k) < y(k))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[kle] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:num->bool` MP_TAC) THEN
+  ASM_CASES_TAC `k:num->bool = {}` THENL
+   [ASM_REWRITE_TAC[NOT_IN_EMPTY; ADD_CLAUSES; GSYM FUN_EQ_THM; ETA_AX];
+    STRIP_TAC THEN ASM_REWRITE_TAC[LE_ADD] 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 `i:num` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[ARITH_RULE `n < n + 1`] THEN
+    ASM_MESON_TAC[SUBSET; IN_NUMSEG]]);;
+
+let KLE_MINIMAL = prove
+ (`!s n. FINITE s /\ ~(s = {}) /\
+         (!x y. x IN s /\ y IN s ==> kle n x y \/ kle n y x)
+         ==> ?a. a IN s /\ !x. x IN s ==> kle n a x`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?a:num->num. a IN s /\ !x. x IN s ==> !j. a(j) <= x(j)`
+  MP_TAC THENL
+   [MATCH_MP_TAC(REWRITE_RULE[IMP_IMP] POINTWISE_MINIMAL); ALL_TAC] THEN
+  ASM_MESON_TAC[POINTWISE_ANTISYM; KLE_IMP_POINTWISE]);;
+
+let KLE_MAXIMAL = prove
+ (`!s n. FINITE s /\ ~(s = {}) /\
+         (!x y. x IN s /\ y IN s ==> kle n x y \/ kle n y x)
+         ==> ?a. a IN s /\ !x. x IN s ==> kle n x a`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?a:num->num. a IN s /\ !x. x IN s ==> !j. x(j) <= a(j)`
+  MP_TAC THENL
+   [MATCH_MP_TAC(REWRITE_RULE[IMP_IMP] POINTWISE_MAXIMAL); ALL_TAC] THEN
+  ASM_MESON_TAC[POINTWISE_ANTISYM; KLE_IMP_POINTWISE]);;
+
+let KLE_STRICT_SET = prove
+ (`!n x y. kle n x y /\ ~(x = y) ==> 1 <= CARD {k | k IN 1..n /\ x(k) < y(k)}`,
+  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP KLE_STRICT) THEN
+  DISCH_THEN(X_CHOOSE_THEN `i:num` STRIP_ASSUME_TAC o CONJUNCT2) THEN
+  MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `CARD {i:num}` THEN CONJ_TAC THENL
+   [SIMP_TAC[CARD_CLAUSES; FINITE_RULES; ARITH; NOT_IN_EMPTY];
+    MATCH_MP_TAC CARD_SUBSET THEN SIMP_TAC[FINITE_RESTRICT; FINITE_NUMSEG] THEN
+    SIMP_TAC[IN_ELIM_THM; IN_NUMSEG; SUBSET; IN_SING] THEN ASM_MESON_TAC[]]);;
+
+let KLE_RANGE_COMBINE = prove
+ (`!n x y m1 m2.
+        kle n x y /\ kle n y z /\ (kle n x z \/ kle n z x) /\
+        m1 <= CARD {k | k IN 1..n /\ x(k) < y(k)} /\
+        m2 <= CARD {k | k IN 1..n /\ y(k) < z(k)}
+        ==> kle n x z /\ m1 + m2 <= CARD {k | k IN 1..n /\ x(k) < z(k)}`,
+  REPEAT GEN_TAC THEN DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[KLE_TRANS]; DISCH_TAC] THEN
+  MATCH_MP_TAC LE_TRANS THEN
+  EXISTS_TAC `CARD {k | k IN 1..n /\ x(k):num < y(k)} +
+              CARD {k | k IN 1..n /\ y(k) < z(k)}` THEN
+  ASM_SIMP_TAC[LE_ADD2] THEN MATCH_MP_TAC EQ_IMP_LE THEN
+  MATCH_MP_TAC CARD_UNION_EQ THEN
+  SIMP_TAC[FINITE_RESTRICT; FINITE_NUMSEG] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INTER; IN_UNION; NOT_IN_EMPTY] THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_MESON_TAC[KLE_IMP_POINTWISE; ARITH_RULE
+     `x <= y:num /\ y <= z ==> (x < y \/ y < z <=> x < z)`]] THEN
+  X_GEN_TAC `i:num` THEN UNDISCH_TAC `kle n x z` THEN
+  REWRITE_TAC[kle] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `i IN 1..n` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(ARITH_RULE `d <= 1 ==> ~(a < x /\ x < a + d)`) THEN
+  COND_CASES_TAC THEN REWRITE_TAC[ARITH]);;
+
+let KLE_RANGE_COMBINE_L = prove
+ (`!n x y m.
+        kle n x y /\ kle n y z /\ (kle n x z \/ kle n z x) /\
+        m <= CARD {k | k IN 1..n /\ y(k) < z(k)}
+        ==> kle n x z /\ m <= CARD {k | k IN 1..n /\ x(k) < z(k)}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `x:num->num = y` THEN ASM_SIMP_TAC[] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  SUBGOAL_THEN `kle n x z /\ 1 + m <= CARD {k | k IN 1 .. n /\ x k < z k}`
+   (fun th -> MESON_TAC[th; ARITH_RULE `1 + m <= x ==> m <= x`]) THEN
+  MATCH_MP_TAC KLE_RANGE_COMBINE THEN EXISTS_TAC `y:num->num` THEN
+  ASM_SIMP_TAC[KLE_STRICT_SET]);;
+
+let KLE_RANGE_COMBINE_R = prove
+ (`!n x y m.
+        kle n x y /\ kle n y z /\ (kle n x z \/ kle n z x) /\
+        m <= CARD {k | k IN 1..n /\ x(k) < y(k)}
+        ==> kle n x z /\ m <= CARD {k | k IN 1..n /\ x(k) < z(k)}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `y:num->num = z` THEN ASM_SIMP_TAC[] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  SUBGOAL_THEN `kle n x z /\ m + 1 <= CARD {k | k IN 1 .. n /\ x k < z k}`
+   (fun th -> MESON_TAC[th; ARITH_RULE `m + 1 <= x ==> m <= x`]) THEN
+  MATCH_MP_TAC KLE_RANGE_COMBINE THEN EXISTS_TAC `y:num->num` THEN
+  ASM_SIMP_TAC[KLE_STRICT_SET]);;
+
+let KLE_RANGE_INDUCT = prove
+ (`!n m s. s HAS_SIZE (SUC m)
+           ==> (!x y. x IN s /\ y IN s ==> kle n x y \/ kle n y x)
+               ==> ?x y. x IN s /\ y IN s /\ kle n x y /\
+                         m <= CARD {k | k IN 1..n /\ x(k) < y(k)}`,
+  GEN_TAC THEN INDUCT_TAC THENL
+   [GEN_TAC THEN REWRITE_TAC[ARITH; LE_0] THEN
+    CONV_TAC(LAND_CONV HAS_SIZE_CONV) THEN MESON_TAC[IN_SING; KLE_REFL];
+    ALL_TAC] THEN
+  X_GEN_TAC `s:(num->num)->bool` THEN
+  ONCE_REWRITE_TAC[HAS_SIZE_SUC] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`s:(num->num)->bool`; `n:num`] KLE_MINIMAL) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[HAS_SIZE_SUC; HAS_SIZE]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:num->num` THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `s DELETE (a:num->num)`) THEN
+  REPEAT(ANTS_TAC THENL [ASM_MESON_TAC[IN_DELETE]; ALL_TAC]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `x:num->num` MP_TAC) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:num->num` THEN
+  REWRITE_TAC[IN_DELETE] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[ARITH_RULE `SUC m = 1 + m`] THEN
+  MATCH_MP_TAC KLE_RANGE_COMBINE THEN EXISTS_TAC `x:num->num` THEN
+  ASM_SIMP_TAC[KLE_STRICT_SET]);;
+
+let KLE_SUC = prove
+ (`!n x y. kle n x y ==> kle (n + 1) x y`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[kle] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  REWRITE_TAC[SUBSET; IN_NUMSEG] THEN
+  MESON_TAC[ARITH_RULE `k <= n ==> k <= n + 1`]);;
+
+let KLE_TRANS_1 = prove
+ (`!n x y. kle n x y ==> !j. x j <= y j /\ y j <= x j + 1`,
+  SIMP_TAC[kle; LEFT_IMP_EXISTS_THM] THEN
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ARITH_TAC);;
+
+let KLE_TRANS_2 = prove
+ (`!a b c. kle n a b /\ kle n b c /\ (!j. c j <= a j + 1)
+           ==> kle n a c`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  REWRITE_TAC[kle] THEN
+  DISCH_THEN(X_CHOOSE_THEN `kk1:num->bool` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `kk2:num->bool` STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(fun th ->
+    EXISTS_TAC `(kk1:num->bool) UNION kk2` THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[UNION_SUBSET; IN_UNION] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+  ASM_CASES_TAC `(i:num) IN kk1` THEN ASM_CASES_TAC `(i:num) IN kk2` THEN
+  ASM_REWRITE_TAC[] THEN ARITH_TAC);;
+
+let KLE_BETWEEN_R = prove
+ (`!a b c x. kle n a b /\ kle n b c /\ kle n a x /\ kle n c x
+             ==> kle n b x`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC KLE_TRANS_2 THEN
+  EXISTS_TAC `c:num->num` THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[KLE_TRANS_1; ARITH_RULE
+   `x <= c + 1 /\ c <= b ==> x <= b + 1`]);;
+
+let KLE_BETWEEN_L = prove
+ (`!a b c x. kle n a b /\ kle n b c /\ kle n x a /\ kle n x c
+             ==> kle n x b`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC KLE_TRANS_2 THEN
+  EXISTS_TAC `a:num->num` THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[KLE_TRANS_1; ARITH_RULE
+   `c <= x + 1 /\ b <= c ==> b <= x + 1`]);;
+
+let KLE_ADJACENT = prove
+ (`!a b x k.
+        1 <= k /\ k <= n /\ (!j. b(j) = if j = k then a(j) + 1 else a(j)) /\
+        kle n a x /\ kle n x b
+        ==> (x = a) \/ (x = b)`,
+  REPEAT STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o MATCH_MP KLE_IMP_POINTWISE)) THEN
+  ASM_REWRITE_TAC[FUN_EQ_THM; IMP_IMP; AND_FORALL_THM] THEN
+  ASM_CASES_TAC `(x:num->num) k = a k` THENL
+   [DISCH_THEN(fun th -> DISJ1_TAC THEN MP_TAC th);
+    DISCH_THEN(fun th -> DISJ2_TAC THEN MP_TAC th)] THEN
+  MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[LE_ANTISYM] THEN
+  ASM_MESON_TAC[ARITH_RULE
+   `a <= x /\ x <= a + 1 /\ ~(x = a) ==> (x = a + 1)`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Kuhn's notion of a simplex (my reformulation to avoid so much indexing).  *)
+(* ------------------------------------------------------------------------- *)
+
+let ksimplex = new_definition
+ `ksimplex p n s <=>
+        s HAS_SIZE (n + 1) /\
+        (!x j. x IN s ==> x(j) <= p) /\
+        (!x j. x IN s /\ ~(1 <= j /\ j <= n) ==> (x j = p)) /\
+        (!x y. x IN s /\ y IN s ==> kle n x y \/ kle n y x)`;;
+
+let KSIMPLEX_EXTREMA = prove
+ (`!p n s.
+        ksimplex p n s
+        ==> ?a b. a IN s /\ b IN s /\
+                  (!x. x IN s ==> kle n a x /\ kle n x b) /\
+                  (!i. b(i) = if 1 <= i /\ i <= n then a(i) + 1 else a(i))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[ksimplex] THEN ASM_CASES_TAC `n = 0` THENL
+   [ASM_REWRITE_TAC[ARITH_RULE `1 <= i /\ i <= 0 <=> F`; GSYM FUN_EQ_THM] THEN
+    REWRITE_TAC[ADD_CLAUSES; ETA_AX] THEN
+    CONV_TAC(LAND_CONV(LAND_CONV HAS_SIZE_CONV)) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+    ASM_REWRITE_TAC[IN_SING] THEN MESON_TAC[KLE_REFL];
+    ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`s:(num->num)->bool`; `n:num`] KLE_MINIMAL) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[HAS_SIZE; HAS_SIZE_SUC; ADD1]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:num->num` THEN STRIP_TAC THEN
+  MP_TAC(SPECL [`s:(num->num)->bool`; `n:num`] KLE_MAXIMAL) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[HAS_SIZE; HAS_SIZE_SUC; ADD1]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:num->num` THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[] THEN
+  MP_TAC(SPECL [`n:num`; `n:num`; `s:(num->num)->bool`] KLE_RANGE_INDUCT) THEN
+  ASM_REWRITE_TAC[ADD1] THEN
+  DISCH_THEN(X_CHOOSE_THEN `c:num->num` (X_CHOOSE_THEN `d:num->num`
+    STRIP_ASSUME_TAC)) THEN
+  SUBGOAL_THEN `{k | k IN 1 .. n /\ a k :num < b k} = 1..n` MP_TAC THENL
+   [MATCH_MP_TAC CARD_SUBSET_LE THEN
+    ASM_REWRITE_TAC[CARD_NUMSEG; ADD_SUB; FINITE_NUMSEG; SUBSET_RESTRICT] THEN
+    SUBGOAL_THEN `kle n a b /\ n <= CARD {k | k IN 1..n /\ a(k) < b(k)}`
+     (fun th -> REWRITE_TAC[th]) THEN
+    MATCH_MP_TAC KLE_RANGE_COMBINE_L THEN EXISTS_TAC `c:num->num` THEN
+    ASM_SIMP_TAC[] THEN
+    SUBGOAL_THEN `kle n c b /\ n <= CARD {k | k IN 1 .. n /\ c k < b k}`
+     (fun th -> REWRITE_TAC[th]) THEN
+    MATCH_MP_TAC KLE_RANGE_COMBINE_R THEN EXISTS_TAC `d:num->num` THEN
+    ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `kle n a b` MP_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [kle]) THEN
+  ASM_REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_NUMSEG] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[ADD_CLAUSES; LT_REFL] THEN
+  ASM_MESON_TAC[SUBSET; IN_NUMSEG]);;
+
+let KSIMPLEX_EXTREMA_STRONG = prove
+ (`!p n s.
+        ksimplex p n s /\ ~(n = 0)
+        ==> ?a b. a IN s /\ b IN s /\ ~(a = b) /\
+                  (!x. x IN s ==> kle n a x /\ kle n x b) /\
+                  (!i. b(i) = if 1 <= i /\ i <= n then a(i) + 1 else a(i))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP KSIMPLEX_EXTREMA) THEN
+  REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST_ALL_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `1`) THEN
+  ASM_REWRITE_TAC[LE_REFL; ARITH_RULE `1 <= n <=> ~(n = 0)`] THEN ARITH_TAC);;
+
+let KSIMPLEX_SUCCESSOR = prove
+ (`!a p n s.
+        ksimplex p n s /\ a IN s
+        ==> (!x. x IN s ==> kle n x a) \/
+            (?y. y IN s /\ ?k. 1 <= k /\ k <= n /\
+                               !j. y(j) = if j = k then a(j) + 1 else a(j))`,
+  REWRITE_TAC[ksimplex] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[TAUT `a \/ b <=> ~a ==> b`] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN DISCH_TAC THEN
+  MP_TAC(SPECL [`{x | x IN s /\ ~kle n x a}`; `n:num`] KLE_MINIMAL) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN
+  ASM_SIMP_TAC[FINITE_RESTRICT] THEN
+  ASM_SIMP_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:num->num` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `1 <= CARD {k | k IN 1..n /\ a(k):num < b(k)}` MP_TAC THENL
+   [MATCH_MP_TAC KLE_STRICT_SET THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(DISJ_CASES_THEN MP_TAC o MATCH_MP (ARITH_RULE
+   `1 <= n ==> (n = 1) \/ 2 <= n`))
+  THENL
+   [DISCH_TAC THEN
+    MP_TAC(HAS_SIZE_CONV `{k | k IN 1 .. n /\ a k :num < b k} HAS_SIZE 1`) THEN
+    ASM_SIMP_TAC[HAS_SIZE; FINITE_RESTRICT; FINITE_NUMSEG] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:num` THEN
+    REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_SING; IN_NUMSEG] THEN
+    DISCH_THEN(fun th -> CONJ_TAC THENL [MESON_TAC[th]; MP_TAC th]) THEN
+    DISCH_THEN(fun th -> CONJ_TAC THENL [MESON_TAC[th]; MP_TAC th]) THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+    SUBGOAL_THEN `kle n a b` MP_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [kle]) THEN
+    ASM_REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_NUMSEG] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[ADD_CLAUSES; LT_REFL] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[ADD_CLAUSES; LT_REFL] THEN
+    ASM_MESON_TAC[SUBSET; IN_NUMSEG; ARITH_RULE `~(a + 1 = a)`;
+                  ARITH_RULE `a < a + 1`];
+    ALL_TAC] THEN
+  DISCH_TAC THEN
+  MP_TAC(SPECL [`n:num`; `PRE(CARD {x | x IN s /\ ~(kle n x a)})`;
+                `{x | x IN s /\ ~(kle n x a)}`] KLE_RANGE_INDUCT) THEN
+  ASM_SIMP_TAC[HAS_SIZE; FINITE_RESTRICT; CARD_EQ_0; GSYM MEMBER_NOT_EMPTY;
+    ARITH_RULE `(n = SUC(PRE n)) <=> ~(n = 0)`] THEN
+  REPEAT(ANTS_TAC THENL
+   [REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[]; ALL_TAC]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `c:num->num`
+   (X_CHOOSE_THEN `d:num->num` MP_TAC)) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2
+   (STRIP_ASSUME_TAC o REWRITE_RULE[IN_ELIM_THM]) MP_TAC)) THEN
+  DISCH_TAC THEN
+  MP_TAC(SPECL [`n:num`; `PRE(CARD {x | x IN s /\ kle n x a})`;
+                `{x | x IN s /\ kle n x a}`] KLE_RANGE_INDUCT) THEN
+  ASM_SIMP_TAC[HAS_SIZE; FINITE_RESTRICT; CARD_EQ_0; GSYM MEMBER_NOT_EMPTY;
+    ARITH_RULE `(n = SUC(PRE n)) <=> ~(n = 0)`] THEN
+  REPEAT(ANTS_TAC THENL
+   [REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[KLE_REFL]; ALL_TAC]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:num->num`
+    (X_CHOOSE_THEN `f:num->num` MP_TAC)) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2
+   (STRIP_ASSUME_TAC o REWRITE_RULE[IN_ELIM_THM]) MP_TAC)) THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN `kle n e d /\ n + 1 <= CARD {k | k IN 1..n /\ e(k) < d(k)}`
+  MP_TAC THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_THEN(K ALL_TAC) THEN
+    DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+    REWRITE_TAC[ARITH_RULE `~(n + 1 <= x) <=> x <= n`] THEN
+    MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `CARD(1..n)` THEN
+    SIMP_TAC[CARD_SUBSET; SUBSET_RESTRICT; FINITE_RESTRICT; FINITE_NUMSEG] THEN
+    REWRITE_TAC[CARD_NUMSEG; ADD_SUB; LE_REFL]] THEN
+  SUBGOAL_THEN
+   `(CARD {x | x IN s /\ kle n x a} - 1) +
+    2 + (CARD {x | x IN s /\ ~kle n x a} - 1) = n + 1`
+   (SUBST1_TAC o SYM)
+  THENL
+   [MATCH_MP_TAC(ARITH_RULE
+     `~(a = 0) /\ ~(b = 0) /\ (a + b = n + 1)
+       ==> ((a - 1) + 2 + (b - 1) = n + 1)`) THEN
+    ASM_SIMP_TAC[CARD_EQ_0; FINITE_RESTRICT; GSYM MEMBER_NOT_EMPTY] THEN
+    REPEAT (CONJ_TAC THENL
+     [REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[]; ALL_TAC]) THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM o CONJUNCT2) THEN
+    MATCH_MP_TAC CARD_UNION_EQ THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_INTER; IN_UNION; IN_ELIM_THM] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC KLE_RANGE_COMBINE THEN EXISTS_TAC `a:num->num` THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_TRANS]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_TRANS]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_TRANS]; ALL_TAC] THEN CONJ_TAC THENL
+   [W(fun(asl,w) -> SUBGOAL_THEN(mk_conj(`kle n e a`,w))
+     (fun th -> REWRITE_TAC[th])) THEN
+    MATCH_MP_TAC KLE_RANGE_COMBINE_R THEN EXISTS_TAC `f:num->num` THEN
+    ASM_REWRITE_TAC[ARITH_RULE `k - 1 = PRE k`];
+    ALL_TAC] THEN
+  W(fun(asl,w) -> SUBGOAL_THEN(mk_conj(`kle n a d`,w))
+     (fun th -> REWRITE_TAC[th])) THEN
+  MATCH_MP_TAC KLE_RANGE_COMBINE THEN EXISTS_TAC `b:num->num` THEN
+  ASM_REWRITE_TAC[ARITH_RULE `k - 1 = PRE k`] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_TRANS]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_TRANS]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_TRANS]; ALL_TAC] THEN
+  W(fun(asl,w) -> SUBGOAL_THEN(mk_conj(`kle n b d`,w))
+     (fun th -> REWRITE_TAC[th])) THEN
+  MATCH_MP_TAC KLE_RANGE_COMBINE_L THEN EXISTS_TAC `c:num->num` THEN
+  ASM_REWRITE_TAC[ARITH_RULE `k - 1 = PRE k`] THEN ASM_MESON_TAC[KLE_TRANS]);;
+
+let KSIMPLEX_PREDECESSOR = prove
+ (`!a p n s.
+        ksimplex p n s /\ a IN s
+        ==> (!x. x IN s ==> kle n a x) \/
+            (?y. y IN s /\ ?k. 1 <= k /\ k <= n /\
+                               !j. a(j) = if j = k then y(j) + 1 else y(j))`,
+  REWRITE_TAC[ksimplex] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[TAUT `a \/ b <=> ~a ==> b`] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN DISCH_TAC THEN
+  MP_TAC(SPECL [`{x | x IN s /\ ~kle n a x}`; `n:num`] KLE_MAXIMAL) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN
+  ASM_SIMP_TAC[FINITE_RESTRICT] THEN
+  ASM_SIMP_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:num->num` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `1 <= CARD {k | k IN 1..n /\ b(k):num < a(k)}` MP_TAC THENL
+   [MATCH_MP_TAC KLE_STRICT_SET THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(DISJ_CASES_THEN MP_TAC o MATCH_MP (ARITH_RULE
+   `1 <= n ==> (n = 1) \/ 2 <= n`))
+  THENL
+   [DISCH_TAC THEN
+    MP_TAC(HAS_SIZE_CONV `{k | k IN 1 .. n /\ b k :num < a k} HAS_SIZE 1`) THEN
+    ASM_SIMP_TAC[HAS_SIZE; FINITE_RESTRICT; FINITE_NUMSEG] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:num` THEN
+    REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_SING; IN_NUMSEG] THEN
+    DISCH_THEN(fun th -> CONJ_TAC THENL [MESON_TAC[th]; MP_TAC th]) THEN
+    DISCH_THEN(fun th -> CONJ_TAC THENL [MESON_TAC[th]; MP_TAC th]) THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+    SUBGOAL_THEN `kle n b a` MP_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [kle]) THEN
+    ASM_REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_NUMSEG] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[ADD_CLAUSES; LT_REFL] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[ADD_CLAUSES; LT_REFL] THEN
+    ASM_MESON_TAC[SUBSET; IN_NUMSEG; ARITH_RULE `~(a + 1 = a)`;
+                  ARITH_RULE `a < a + 1`];
+    ALL_TAC] THEN
+  DISCH_TAC THEN
+  MP_TAC(SPECL [`n:num`; `PRE(CARD {x | x IN s /\ ~(kle n a x)})`;
+                `{x | x IN s /\ ~(kle n a x)}`] KLE_RANGE_INDUCT) THEN
+  ASM_SIMP_TAC[HAS_SIZE; FINITE_RESTRICT; CARD_EQ_0; GSYM MEMBER_NOT_EMPTY;
+    ARITH_RULE `(n = SUC(PRE n)) <=> ~(n = 0)`] THEN
+  REPEAT(ANTS_TAC THENL
+   [REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[]; ALL_TAC]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:num->num`
+   (X_CHOOSE_THEN `c:num->num` MP_TAC)) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2
+   (STRIP_ASSUME_TAC o REWRITE_RULE[IN_ELIM_THM]) MP_TAC)) THEN
+  DISCH_TAC THEN
+  MP_TAC(SPECL [`n:num`; `PRE(CARD {x | x IN s /\ kle n a x})`;
+                `{x | x IN s /\ kle n a x}`] KLE_RANGE_INDUCT) THEN
+  ASM_SIMP_TAC[HAS_SIZE; FINITE_RESTRICT; CARD_EQ_0; GSYM MEMBER_NOT_EMPTY;
+    ARITH_RULE `(n = SUC(PRE n)) <=> ~(n = 0)`] THEN
+  REPEAT(ANTS_TAC THENL
+   [REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[KLE_REFL]; ALL_TAC]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:num->num`
+    (X_CHOOSE_THEN `e:num->num` MP_TAC)) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2
+   (STRIP_ASSUME_TAC o REWRITE_RULE[IN_ELIM_THM]) MP_TAC)) THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN `kle n d e /\ n + 1 <= CARD {k | k IN 1..n /\ d(k) < e(k)}`
+  MP_TAC THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_THEN(K ALL_TAC) THEN
+    DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+    REWRITE_TAC[ARITH_RULE `~(n + 1 <= x) <=> x <= n`] THEN
+    MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `CARD(1..n)` THEN
+    SIMP_TAC[CARD_SUBSET; SUBSET_RESTRICT; FINITE_RESTRICT; FINITE_NUMSEG] THEN
+    REWRITE_TAC[CARD_NUMSEG; ADD_SUB; LE_REFL]] THEN
+  SUBGOAL_THEN
+   `((CARD {x | x IN s /\ ~kle n a x} - 1) + 2) +
+    (CARD {x | x IN s /\ kle n a x} - 1) = n + 1`
+   (SUBST1_TAC o SYM)
+  THENL
+   [MATCH_MP_TAC(ARITH_RULE
+     `~(a = 0) /\ ~(b = 0) /\ (a + b = n + 1)
+       ==> (((b - 1) + 2) + (a - 1) = n + 1)`) THEN
+    ASM_SIMP_TAC[CARD_EQ_0; FINITE_RESTRICT; GSYM MEMBER_NOT_EMPTY] THEN
+    REPEAT (CONJ_TAC THENL
+     [REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[]; ALL_TAC]) THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM o CONJUNCT2) THEN
+    MATCH_MP_TAC CARD_UNION_EQ THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_INTER; IN_UNION; IN_ELIM_THM] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC KLE_RANGE_COMBINE THEN EXISTS_TAC `a:num->num` THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_TRANS]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_TRANS]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_TRANS]; ALL_TAC] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    W(fun(asl,w) -> SUBGOAL_THEN(mk_conj(`kle n a e`,w))
+     (fun th -> REWRITE_TAC[th])) THEN
+    MATCH_MP_TAC KLE_RANGE_COMBINE_L THEN EXISTS_TAC `f:num->num` THEN
+    ASM_REWRITE_TAC[ARITH_RULE `k - 1 = PRE k`]] THEN
+  W(fun(asl,w) -> SUBGOAL_THEN(mk_conj(`kle n d a`,w))
+     (fun th -> REWRITE_TAC[th])) THEN
+  MATCH_MP_TAC KLE_RANGE_COMBINE THEN EXISTS_TAC `b:num->num` THEN
+  ASM_REWRITE_TAC[ARITH_RULE `k - 1 = PRE k`] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_TRANS]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_TRANS]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_TRANS]; ALL_TAC] THEN
+  W(fun(asl,w) -> SUBGOAL_THEN(mk_conj(`kle n d b`,w))
+     (fun th -> REWRITE_TAC[th])) THEN
+  MATCH_MP_TAC KLE_RANGE_COMBINE_R THEN EXISTS_TAC `c:num->num` THEN
+  ASM_REWRITE_TAC[ARITH_RULE `k - 1 = PRE k`] THEN ASM_MESON_TAC[KLE_TRANS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The lemmas about simplices that we need.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let FINITE_SIMPLICES = prove
+ (`!p n. FINITE {s | ksimplex p n s}`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC FINITE_SUBSET THEN
+  EXISTS_TAC `{s | s SUBSET {f | (!i. i IN 1..n ==> f(i) IN 0..p) /\
+                                 (!i. ~(i IN 1..n) ==> (f(i) = p))}}` THEN
+  ASM_SIMP_TAC[FINITE_POWERSET; FINITE_FUNSPACE; FINITE_NUMSEG] THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM; ksimplex] THEN
+  ASM_SIMP_TAC[IN_NUMSEG; LE_0]);;
+
+let SIMPLEX_TOP_FACE = prove
+ (`0 < p /\
+   (!x. x IN f ==> (x(n + 1) = p))
+   ==> ((?s a. ksimplex p (n + 1) s /\ a IN s /\ (f = s DELETE a)) <=>
+        ksimplex p n f)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[ksimplex; LEFT_IMP_EXISTS_THM] THEN
+    REPEAT GEN_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[IN_DELETE] THEN
+    REPEAT CONJ_TAC THENL
+     [UNDISCH_TAC `(s:(num->num)->bool) HAS_SIZE ((n + 1) + 1)` THEN
+      SIMP_TAC[HAS_SIZE; CARD_DELETE; FINITE_DELETE] THEN
+      ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ARITH_TAC;
+      REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[];
+      GEN_TAC THEN X_GEN_TAC `j:num` THEN
+      ONCE_REWRITE_TAC[ARITH_RULE
+       `(1 <= j /\ j <= n) <=> (1 <= j /\ j <= n + 1) /\ ~(j = (n + 1))`] THEN
+      ASM_MESON_TAC[IN_DELETE];
+      REPEAT STRIP_TAC THEN
+      SUBGOAL_THEN `kle (n + 1) x y \/ kle (n + 1) y x` MP_TAC THENL
+       [ASM_MESON_TAC[]; ALL_TAC] THEN
+      MATCH_MP_TAC MONO_OR THEN CONJ_TAC THEN
+      (REWRITE_TAC[kle] THEN
+       MATCH_MP_TAC MONO_EXISTS THEN
+       REWRITE_TAC[GSYM ADD1; NUMSEG_CLAUSES; ARITH_RULE `1 <= SUC n`] THEN
+       X_GEN_TAC `k:num->bool` THEN SIMP_TAC[] THEN
+       REWRITE_TAC[SUBSET; IN_INSERT] THEN
+       ASM_CASES_TAC `(SUC n) IN k` THENL
+        [ALL_TAC; ASM_MESON_TAC[]] THEN
+       DISCH_THEN(MP_TAC o SPEC `n + 1` o CONJUNCT2) THEN
+       ASM_REWRITE_TAC[GSYM ADD1] THEN
+       ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_THEN(K ALL_TAC) THEN
+       MATCH_MP_TAC(ARITH_RULE `(x = p) /\ (y = p) ==> ~(x = SUC y)`) THEN
+       CONJ_TAC THEN ASM_MESON_TAC[ADD1; IN_DELETE])];
+    ALL_TAC] THEN
+  DISCH_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP KSIMPLEX_EXTREMA) THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:num->num` (X_CHOOSE_THEN `b:num->num`
+    STRIP_ASSUME_TAC)) THEN
+  ABBREV_TAC `c = \i. if i = (n + 1) then p - 1 else a(i)` THEN
+  MAP_EVERY EXISTS_TAC [`(c:num->num) INSERT f`; `c:num->num`] THEN
+  REWRITE_TAC[IN_INSERT; DELETE_INSERT] THEN
+  SUBGOAL_THEN `~((c:num->num) IN f)` ASSUME_TAC THENL
+   [DISCH_TAC THEN UNDISCH_TAC `!x:num->num. x IN f ==> (x (n + 1) = p)` THEN
+    DISCH_THEN(MP_TAC o SPEC `c:num->num`) THEN ASM_REWRITE_TAC[] THEN
+    EXPAND_TAC "c" THEN REWRITE_TAC[] THEN UNDISCH_TAC `0 < p` THEN ARITH_TAC;
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [ALL_TAC; UNDISCH_TAC `~((c:num->num) IN f)` THEN SET_TAC[]] THEN
+  UNDISCH_TAC `ksimplex p n f` THEN REWRITE_TAC[ksimplex] THEN
+  REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THENL
+   [SIMP_TAC[HAS_SIZE; FINITE_RULES; CARD_CLAUSES] THEN ASM_REWRITE_TAC[ADD1];
+    EXPAND_TAC "c" THEN REWRITE_TAC[IN_INSERT] THEN
+    SIMP_TAC[TAUT `(a \/ b ==> c) <=> (a ==> c) /\ (b ==> c)`] THEN
+    ASM_MESON_TAC[ARITH_RULE `p - 1 <= p`];
+    EXPAND_TAC "c" THEN REWRITE_TAC[IN_INSERT; TAUT
+      `(a \/ b) /\ c ==> d <=> (a /\ c ==> d) /\ (b /\ c ==> d)`] THEN
+    DISCH_TAC THEN REPEAT GEN_TAC THEN CONJ_TAC THENL
+     [DISCH_THEN(CONJUNCTS_THEN2 SUBST1_TAC MP_TAC); ALL_TAC] THEN
+    ASM_MESON_TAC[LE_REFL; ARITH_RULE `1 <= n + 1`;
+                  ARITH_RULE `j <= n ==> j <= n + 1`];
+    ALL_TAC] THEN
+  DISCH_TAC THEN REWRITE_TAC[IN_INSERT] THEN
+  SUBGOAL_THEN `!x. x IN f ==> kle (n + 1) c x`
+    (fun th -> ASM_MESON_TAC[th; KLE_SUC; KLE_REFL]) THEN
+  X_GEN_TAC `x:num->num` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `kle (n + 1) a x` MP_TAC THENL
+   [ASM_MESON_TAC[KLE_SUC]; ALL_TAC] THEN
+  EXPAND_TAC "c" THEN REWRITE_TAC[kle] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:num->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(n + 1) INSERT k` THEN
+  ASM_REWRITE_TAC[INSERT_SUBSET; IN_NUMSEG] THEN
+  ASM_REWRITE_TAC[LE_REFL; ARITH_RULE `1 <= n + 1`] THEN
+  X_GEN_TAC `j:num` THEN REWRITE_TAC[IN_INSERT] THEN
+  ASM_CASES_TAC `j = n + 1` THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `~(n + 1 IN k)`
+   (fun th -> ASM_MESON_TAC[th; ARITH_RULE `0 < p ==> (p = (p - 1) + 1)`]) THEN
+  DISCH_TAC THEN UNDISCH_TAC `!x:num->num. x IN f ==> (x (n + 1) = p)` THEN
+  DISCH_THEN(fun th -> MP_TAC(SPEC `x:num->num` th) THEN
+                       MP_TAC(SPEC `a:num->num` th)) THEN
+  ASM_REWRITE_TAC[] THEN MESON_TAC[ARITH_RULE `~(p + 1 = p)`]);;
+
+let KSIMPLEX_FIX_PLANE = prove
+ (`!p q n j s a a0 a1.
+        ksimplex p n s /\ a IN s /\
+        1 <= j /\ j <= n /\ (!x. x IN (s DELETE a) ==> (x j = q)) /\
+        a0 IN s /\ a1 IN s /\
+        (!i. a1 i = (if 1 <= i /\ i <= n then a0 i + 1 else a0 i))
+        ==> (a = a0) \/ (a = a1)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(TAUT `(~a /\ ~b ==> F) ==> a \/ b`) THEN STRIP_TAC THEN
+  UNDISCH_TAC `!x:num->num. x IN s DELETE a ==> (x j = q)` THEN
+  DISCH_THEN(fun th ->
+   MP_TAC(SPEC `a0:num->num` th) THEN MP_TAC(SPEC `a1:num->num` th)) THEN
+  ASM_REWRITE_TAC[IN_DELETE] THEN ARITH_TAC);;
+
+let KSIMPLEX_FIX_PLANE_0 = prove
+ (`!p n j s a a0 a1.
+        ksimplex p n s /\ a IN s /\
+        1 <= j /\ j <= n /\ (!x. x IN (s DELETE a) ==> (x j = 0)) /\
+        a0 IN s /\ a1 IN s /\
+        (!i. a1 i = (if 1 <= i /\ i <= n then a0 i + 1 else a0 i))
+        ==> (a = a1)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(a = a0) \/ (a = a1:num->num)` MP_TAC THENL
+   [MATCH_MP_TAC KSIMPLEX_FIX_PLANE THEN
+    MAP_EVERY EXISTS_TAC
+     [`p:num`; `0`; `n:num`; `j:num`; `s:(num->num)->bool`] THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `a0:num->num = a1` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(TAUT `~a ==> (a \/ b ==> b)`) THEN
+  DISCH_THEN SUBST_ALL_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `a1:num->num`) THEN
+  ASM_REWRITE_TAC[IN_DELETE] THEN ARITH_TAC);;
+
+let KSIMPLEX_FIX_PLANE_P = prove
+ (`!p n j s a a0 a1.
+        ksimplex p n s /\ a IN s /\
+        1 <= j /\ j <= n /\ (!x. x IN (s DELETE a) ==> (x j = p)) /\
+        a0 IN s /\ a1 IN s /\
+        (!i. a1 i = (if 1 <= i /\ i <= n then a0 i + 1 else a0 i))
+        ==> (a = a0)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(a = a0) \/ (a = a1:num->num)` MP_TAC THENL
+   [MATCH_MP_TAC KSIMPLEX_FIX_PLANE THEN
+    MAP_EVERY EXISTS_TAC
+     [`p:num`; `p:num`; `n:num`; `j:num`; `s:(num->num)->bool`] THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `a0:num->num = a1` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(TAUT `~b ==> (a \/ b ==> a)`) THEN
+  DISCH_THEN SUBST_ALL_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `a0:num->num`) THEN
+  ASM_REWRITE_TAC[IN_DELETE] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ksimplex]) THEN
+  DISCH_THEN(MP_TAC o SPEC `a1:num->num` o CONJUNCT1 o CONJUNCT2) THEN
+  DISCH_THEN(MP_TAC o SPEC `j:num`) THEN ASM_REWRITE_TAC[] THEN ARITH_TAC);;
+
+let KSIMPLEX_REPLACE_0 = prove
+ (`ksimplex p n s /\ a IN s /\ ~(n = 0) /\
+   (?j. 1 <= j /\ j <= n /\ !x. x IN (s DELETE a) ==> (x j = 0))
+   ==> (CARD
+         {s' | ksimplex p n s' /\ ?b. b IN s' /\ (s' DELETE b = s DELETE a)} =
+        1)`,
+  let lemma = prove
+   (`!a a'. (s' DELETE a' = s DELETE a) /\ (a' = a) /\ a' IN s' /\ a IN s
+            ==> (s' = s)`,
+    SET_TAC[]) in
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_SIZE_CARD THEN
+  REWRITE_TAC[HAS_SIZE_1_EXISTS] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  SUBGOAL_THEN
+   `!s' a'. ksimplex p n s' /\ a' IN s' /\ (s' DELETE a' = s DELETE a)
+            ==> (s' = s)`
+   (fun th -> ASM_MESON_TAC[th]) THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`p:num`; `n:num`; `s:(num->num)->bool`]
+       KSIMPLEX_EXTREMA_STRONG) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a0:num->num` (X_CHOOSE_THEN `a1:num->num`
+    STRIP_ASSUME_TAC)) THEN
+  MP_TAC(SPECL [`p:num`; `n:num`; `s':(num->num)->bool`]
+       KSIMPLEX_EXTREMA_STRONG) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b0:num->num` (X_CHOOSE_THEN `b1:num->num`
+    STRIP_ASSUME_TAC)) THEN
+  SUBGOAL_THEN `a:num->num = a1` SUBST_ALL_TAC THENL
+   [MATCH_MP_TAC KSIMPLEX_FIX_PLANE_0 THEN MAP_EVERY EXISTS_TAC
+     [`p:num`; `n:num`; `j:num`; `s:(num->num)->bool`; `a0:num->num`] THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `a':num->num = b1` SUBST_ALL_TAC THENL
+   [MATCH_MP_TAC KSIMPLEX_FIX_PLANE_0 THEN MAP_EVERY EXISTS_TAC
+     [`p:num`; `n:num`; `j:num`; `s':(num->num)->bool`; `b0:num->num`] THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC lemma THEN
+  MAP_EVERY EXISTS_TAC [`a1:num->num`; `b1:num->num`] THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `b0:num->num = a0` MP_TAC THENL
+   [ONCE_REWRITE_TAC[GSYM KLE_ANTISYM] THEN ASM_MESON_TAC[IN_DELETE];
+    ASM_REWRITE_TAC[FUN_EQ_THM] THEN MESON_TAC[]]);;
+
+let KSIMPLEX_REPLACE_1 = prove
+ (`ksimplex p n s /\ a IN s /\ ~(n = 0) /\
+   (?j. 1 <= j /\ j <= n /\ !x. x IN (s DELETE a) ==> (x j = p))
+   ==> (CARD
+         {s' | ksimplex p n s' /\ ?b. b IN s' /\ (s' DELETE b = s DELETE a)} =
+        1)`,
+  let lemma = prove
+   (`!a a'. (s' DELETE a' = s DELETE a) /\ (a' = a) /\ a' IN s' /\ a IN s
+            ==> (s' = s)`,
+    SET_TAC[]) in
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_SIZE_CARD THEN
+  REWRITE_TAC[HAS_SIZE_1_EXISTS] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  SUBGOAL_THEN
+   `!s' a'. ksimplex p n s' /\ a' IN s' /\ (s' DELETE a' = s DELETE a)
+            ==> (s' = s)`
+   (fun th -> ASM_MESON_TAC[th]) THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`p:num`; `n:num`; `s:(num->num)->bool`]
+       KSIMPLEX_EXTREMA_STRONG) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a0:num->num` (X_CHOOSE_THEN `a1:num->num`
+    STRIP_ASSUME_TAC)) THEN
+  MP_TAC(SPECL [`p:num`; `n:num`; `s':(num->num)->bool`]
+       KSIMPLEX_EXTREMA_STRONG) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b0:num->num` (X_CHOOSE_THEN `b1:num->num`
+    STRIP_ASSUME_TAC)) THEN
+  SUBGOAL_THEN `a:num->num = a0` SUBST_ALL_TAC THENL
+   [MATCH_MP_TAC KSIMPLEX_FIX_PLANE_P THEN MAP_EVERY EXISTS_TAC
+     [`p:num`; `n:num`; `j:num`; `s:(num->num)->bool`; `a1:num->num`] THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `a':num->num = b0` SUBST_ALL_TAC THENL
+   [MATCH_MP_TAC KSIMPLEX_FIX_PLANE_P THEN MAP_EVERY EXISTS_TAC
+     [`p:num`; `n:num`; `j:num`; `s':(num->num)->bool`; `b1:num->num`] THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC lemma THEN
+  MAP_EVERY EXISTS_TAC [`a0:num->num`; `b0:num->num`] THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `b1:num->num = a1` MP_TAC THENL
+   [ONCE_REWRITE_TAC[GSYM KLE_ANTISYM] THEN ASM_MESON_TAC[IN_DELETE];
+    ASM_REWRITE_TAC[FUN_EQ_THM] THEN MATCH_MP_TAC MONO_FORALL THEN
+    MESON_TAC[EQ_ADD_RCANCEL]]);;
+
+let KSIMPLEX_REPLACE_2 = prove
+ (`ksimplex p n s /\ a IN s /\ ~(n = 0) /\
+   ~(?j. 1 <= j /\ j <= n /\ !x. x IN (s DELETE a) ==> (x j = 0)) /\
+   ~(?j. 1 <= j /\ j <= n /\ !x. x IN (s DELETE a) ==> (x j = p))
+   ==> (CARD
+         {s' | ksimplex p n s' /\ ?b. b IN s' /\ (s' DELETE b = s DELETE a)} =
+        2)`,
+  let lemma = prove
+   (`!a a'. (s' DELETE a' = s DELETE a) /\ (a' = a) /\ a' IN s' /\ a IN s
+            ==> (s' = s)`,
+    SET_TAC[])
+  and lemma_1 = prove
+   (`a IN s /\ ~(b = a) ==> ~(s = b INSERT (s DELETE a))`,
+    SET_TAC[]) in
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`p:num`; `n:num`; `s:(num->num)->bool`]
+       KSIMPLEX_EXTREMA_STRONG) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a0:num->num` (X_CHOOSE_THEN `a1:num->num`
+   STRIP_ASSUME_TAC)) THEN
+  ASM_CASES_TAC `a:num->num = a0` THENL
+   [FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    MP_TAC(SPECL [`a0:num->num`; `p:num`; `n:num`; `s:(num->num)->bool`]
+                 KSIMPLEX_SUCCESSOR) THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(TAUT `~a /\ (b ==> c) ==> a \/ b ==> c`) THEN CONJ_TAC THENL
+     [DISCH_THEN(MP_TAC o SPEC `a1:num->num`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(MP_TAC o SPEC `1` o MATCH_MP KLE_IMP_POINTWISE) THEN
+      ASM_REWRITE_TAC[ARITH_RULE `1 <= n <=> ~(n = 0)`; ARITH] THEN ARITH_TAC;
+      ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `a2:num->num`
+     (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(X_CHOOSE_THEN `k:num` STRIP_ASSUME_TAC) THEN
+    ABBREV_TAC `a3 = \j:num. if j = k then a1 j + 1 else a1 j` THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [FUN_EQ_THM]) THEN
+    REWRITE_TAC[] THEN DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THEN
+    MATCH_MP_TAC HAS_SIZE_CARD THEN CONV_TAC HAS_SIZE_CONV THEN
+    MAP_EVERY EXISTS_TAC
+     [`s:(num->num)->bool`; `a3 INSERT (s DELETE (a0:num->num))`] THEN
+    SUBGOAL_THEN `~((a3:num->num) IN s)` ASSUME_TAC THENL
+     [DISCH_TAC THEN SUBGOAL_THEN `kle n a3 a1` MP_TAC THENL
+       [ASM_MESON_TAC[]; ALL_TAC] THEN
+      DISCH_THEN(MP_TAC o SPEC `k:num` o MATCH_MP KLE_IMP_POINTWISE) THEN
+      ASM_REWRITE_TAC[LE_REFL] THEN ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN `~(a3:num->num = a0) /\ ~(a3 = a1)` STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN `~(a2:num->num = a0)` ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[FUN_EQ_THM] THEN MESON_TAC[ARITH_RULE `~(x + 1 = x)`];
+      ALL_TAC] THEN
+    CONJ_TAC THENL [MATCH_MP_TAC lemma_1 THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN `!x. x IN (s DELETE a0) ==> kle n a2 x` ASSUME_TAC THENL
+     [GEN_TAC THEN REWRITE_TAC[IN_DELETE] THEN STRIP_TAC THEN
+      SUBGOAL_THEN `kle n a2 x \/ kle n x a2` MP_TAC THENL
+       [ASM_MESON_TAC[ksimplex]; ALL_TAC] THEN
+      MATCH_MP_TAC(TAUT `(~b ==> ~a) ==> b \/ a ==> b`) THEN
+      DISCH_TAC THEN SUBGOAL_THEN `kle n a0 x` MP_TAC THENL
+       [ASM_MESON_TAC[]; ALL_TAC] THEN REPEAT STRIP_TAC THEN
+      SUBGOAL_THEN `(x:num->num = a0) \/ (x = a2)`
+       (fun th -> ASM_MESON_TAC[KLE_REFL; th]) THEN
+      MATCH_MP_TAC KLE_ADJACENT THEN
+      EXISTS_TAC `k:num` THEN ASM_REWRITE_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `ksimplex p n (a3 INSERT (s DELETE a0))` ASSUME_TAC THENL
+     [MP_TAC(ASSUME `ksimplex p n s`) THEN REWRITE_TAC[ksimplex] THEN
+      MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+       [SIMP_TAC[HAS_SIZE; FINITE_INSERT; FINITE_DELETE; CARD_CLAUSES;
+                 CARD_DELETE] THEN
+        ASM_REWRITE_TAC[IN_DELETE] THEN STRIP_TAC THEN ARITH_TAC;
+        ALL_TAC] THEN
+      MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+       [DISCH_TAC THEN REWRITE_TAC[IN_INSERT; IN_DELETE] THEN
+        SUBGOAL_THEN `!j. (a3:num->num) j <= p`
+         (fun th -> ASM_MESON_TAC[th]) THEN
+        X_GEN_TAC `j:num` THEN ONCE_ASM_REWRITE_TAC[] THEN COND_CASES_TAC THENL
+         [ALL_TAC; ASM_MESON_TAC[]] THEN
+        FIRST_X_ASSUM SUBST_ALL_TAC THEN
+        UNDISCH_TAC
+         `~(?j. 1 <= j /\ j <= n /\
+                (!x. x IN s DELETE a0 ==> (x j = (p:num))))` THEN
+        REWRITE_TAC[NOT_EXISTS_THM] THEN DISCH_THEN(MP_TAC o SPEC `k:num`) THEN
+        REWRITE_TAC[ASSUME `1 <= k`; ASSUME `k:num <= n`; NOT_FORALL_THM] THEN
+        DISCH_THEN(X_CHOOSE_THEN `a4:num->num` MP_TAC) THEN
+        REWRITE_TAC[IN_DELETE; NOT_IMP] THEN STRIP_TAC THEN
+        UNDISCH_TAC `!x. x IN s DELETE a0 ==> kle n a2 x` THEN
+        DISCH_THEN(MP_TAC o SPEC `a4:num->num`) THEN
+        ASM_REWRITE_TAC[IN_DELETE] THEN
+        DISCH_THEN(MP_TAC o MATCH_MP KLE_IMP_POINTWISE) THEN
+        ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `k:num`) THEN
+        ASM_REWRITE_TAC[] THEN
+        UNDISCH_TAC `~((a4:num->num) k = p)` THEN
+        SUBGOAL_THEN `(a4:num->num) k <= p` MP_TAC THENL
+         [ASM_MESON_TAC[ksimplex]; ARITH_TAC];
+        ALL_TAC] THEN
+      MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+       [REWRITE_TAC[IN_INSERT; IN_DELETE] THEN REPEAT STRIP_TAC THENL
+         [ALL_TAC; ASM_MESON_TAC[]] THEN
+        FIRST_X_ASSUM SUBST_ALL_TAC THEN
+        ONCE_ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[];
+        ALL_TAC] THEN
+      DISCH_TAC THEN REWRITE_TAC[IN_INSERT; IN_DELETE] THEN
+      SUBGOAL_THEN `!x. x IN s /\ ~(x = a0) ==> kle n x a3`
+       (fun th -> ASM_MESON_TAC[th; KLE_REFL]) THEN
+      X_GEN_TAC `x:num->num` THEN STRIP_TAC THEN
+      SUBGOAL_THEN `kle n a2 x /\ kle n x a1` MP_TAC THENL
+       [ASM_MESON_TAC[IN_DELETE]; ALL_TAC] THEN
+      REWRITE_TAC[IMP_CONJ] THEN
+      DISCH_THEN(MP_TAC o SPEC `k:num` o MATCH_MP KLE_IMP_POINTWISE) THEN
+      DISCH_TAC THEN REWRITE_TAC[kle] THEN
+      DISCH_THEN(X_CHOOSE_THEN `kk:num->bool` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `(k:num) INSERT kk` THEN
+      REWRITE_TAC[INSERT_SUBSET; IN_NUMSEG] THEN
+      CONJ_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+      X_GEN_TAC `j:num` THEN
+      FIRST_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [th]) THEN
+      REWRITE_TAC[IN_INSERT] THEN ASM_CASES_TAC `j:num = k` THENL
+       [ALL_TAC; ASM_MESON_TAC[]] THEN
+      FIRST_X_ASSUM SUBST_ALL_TAC THEN REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (ARITH_RULE
+       `a2 <= x ==> !a0. x <= a1 /\ (a1 = a0 + 1) /\ (a2 = a0 + 1)
+             ==> (a1 + 1 = x + 1)`)) THEN
+      EXISTS_TAC `(a0:num->num) k` THEN
+      ASM_MESON_TAC[KLE_IMP_POINTWISE];
+      ALL_TAC] THEN
+    GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_INSERT; NOT_IN_EMPTY] THEN
+    X_GEN_TAC `s':(num->num)->bool` THEN EQ_TAC THENL
+     [ALL_TAC;
+      DISCH_THEN(DISJ_CASES_THEN SUBST_ALL_TAC) THENL
+       [ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[] THEN EXISTS_TAC `a3:num->num` THEN
+      REWRITE_TAC[IN_INSERT; DELETE_INSERT] THEN
+      UNDISCH_TAC `~((a3:num->num) IN s)` THEN SET_TAC[]] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `a':num->num` STRIP_ASSUME_TAC) THEN
+    MP_TAC(SPECL [`p:num`; `n:num`; `s':(num->num)->bool`]
+                 KSIMPLEX_EXTREMA_STRONG) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `a_min:num->num` (X_CHOOSE_THEN `a_max:num->num`
+      STRIP_ASSUME_TAC)) THEN
+    SUBGOAL_THEN `(a':num->num = a_min) \/ (a' = a_max)` MP_TAC THENL
+     [MATCH_MP_TAC KSIMPLEX_FIX_PLANE THEN MAP_EVERY EXISTS_TAC
+       [`p:num`; `(a2:num->num) k`; `n:num`;
+        `k:num`; `s':(num->num)->bool`] THEN
+      REPEAT CONJ_TAC THEN TRY(FIRST_ASSUM MATCH_ACCEPT_TAC) THEN
+      X_GEN_TAC `x:num->num` THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+      SUBGOAL_THEN `kle n a2 x /\ kle n x a1` MP_TAC THENL
+       [ASM_MESON_TAC[IN_DELETE]; ALL_TAC] THEN
+      DISCH_THEN(CONJUNCTS_THEN (MP_TAC o SPEC `k:num` o MATCH_MP
+        KLE_IMP_POINTWISE)) THEN
+      ASM_REWRITE_TAC[] THEN ARITH_TAC;
+      ALL_TAC] THEN
+    DISCH_THEN(DISJ_CASES_THEN SUBST_ALL_TAC) THENL
+     [DISJ1_TAC THEN MATCH_MP_TAC lemma THEN
+      MAP_EVERY EXISTS_TAC [`a0:num->num`; `a_min:num->num`] THEN
+      ASM_REWRITE_TAC[] THEN
+      SUBGOAL_THEN `a_max:num->num = a1` MP_TAC THENL
+       [SUBGOAL_THEN `a1:num->num IN (s' DELETE a_min) /\
+                      a_max:num->num IN (s DELETE a0)`
+        MP_TAC THENL
+         [ASM_MESON_TAC[IN_DELETE]; ASM_MESON_TAC[KLE_ANTISYM; IN_DELETE]];
+        ALL_TAC] THEN
+      ASM_REWRITE_TAC[FUN_EQ_THM] THEN MATCH_MP_TAC MONO_FORALL THEN
+      MESON_TAC[EQ_ADD_RCANCEL];
+      DISJ2_TAC THEN MATCH_MP_TAC lemma THEN
+      MAP_EVERY EXISTS_TAC [`a3:num->num`; `a_max:num->num`] THEN
+      ASM_REWRITE_TAC[IN_INSERT] THEN CONJ_TAC THENL
+       [UNDISCH_TAC `~(a3:num->num IN s)` THEN SET_TAC[]; ALL_TAC] THEN
+      SUBGOAL_THEN `a_min:num->num = a2` MP_TAC THENL
+       [SUBGOAL_THEN `a2:num->num IN (s' DELETE a_max) /\
+                      a_min:num->num IN (s DELETE a0)`
+        MP_TAC THENL
+         [ASM_MESON_TAC[IN_DELETE]; ASM_MESON_TAC[KLE_ANTISYM; IN_DELETE]];
+        ALL_TAC] THEN
+      ASM_REWRITE_TAC[FUN_EQ_THM] THEN MATCH_MP_TAC MONO_FORALL THEN
+      MESON_TAC[EQ_ADD_RCANCEL]];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `a:num->num = a1` THENL
+   [FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    MP_TAC(SPECL [`a1:num->num`; `p:num`; `n:num`; `s:(num->num)->bool`]
+                 KSIMPLEX_PREDECESSOR) THEN
+    ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC(TAUT `~a /\ (b ==> c) ==> a \/ b ==> c`) THEN CONJ_TAC THENL
+     [DISCH_THEN(MP_TAC o SPEC `a0:num->num`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(MP_TAC o SPEC `1` o MATCH_MP KLE_IMP_POINTWISE) THEN
+      ASM_REWRITE_TAC[ARITH_RULE `1 <= n <=> ~(n = 0)`; ARITH] THEN ARITH_TAC;
+      ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `a2:num->num`
+     (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(X_CHOOSE_THEN `k:num` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `!x. x IN (s DELETE a1) ==> kle n x a2` ASSUME_TAC THENL
+     [GEN_TAC THEN REWRITE_TAC[IN_DELETE] THEN STRIP_TAC THEN
+      SUBGOAL_THEN `kle n a2 x \/ kle n x a2` MP_TAC THENL
+       [ASM_MESON_TAC[ksimplex]; ALL_TAC] THEN
+      MATCH_MP_TAC(TAUT `(~b ==> ~a) ==> a \/ b ==> b`) THEN
+      DISCH_TAC THEN SUBGOAL_THEN `kle n x a1` MP_TAC THENL
+       [ASM_MESON_TAC[]; ALL_TAC] THEN REPEAT STRIP_TAC THEN
+      SUBGOAL_THEN `(x:num->num = a2) \/ (x = a1)`
+       (fun th -> ASM_MESON_TAC[KLE_REFL; th]) THEN
+      MATCH_MP_TAC KLE_ADJACENT THEN EXISTS_TAC `k:num` THEN
+      REPEAT CONJ_TAC THEN FIRST_X_ASSUM MATCH_ACCEPT_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN `~(a2:num->num = a1)` ASSUME_TAC THENL
+     [REWRITE_TAC[FUN_EQ_THM] THEN ASM_MESON_TAC[ARITH_RULE `~(x + 1 = x)`];
+      ALL_TAC] THEN
+    ABBREV_TAC `a3 = \j:num. if j = k then a0 j - 1 else a0 j` THEN
+    SUBGOAL_THEN `!j:num. a0(j) = if j = k then a3(j) + 1 else a3 j`
+    ASSUME_TAC THENL
+     [X_GEN_TAC `j:num` THEN EXPAND_TAC "a3" THEN REWRITE_TAC[] THEN
+      COND_CASES_TAC THEN
+      REWRITE_TAC[ARITH_RULE `(a = a - 1 + 1) <=> ~(a = 0)`] THEN
+      FIRST_X_ASSUM SUBST_ALL_TAC THEN DISCH_TAC THEN
+      UNDISCH_TAC `!j:num. a1 j = (if j = k then a2 j + 1 else a2 j)` THEN
+      DISCH_THEN(MP_TAC o SPEC `k:num`) THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[ARITH_RULE `(0 + 1 = x + 1) <=> (x = 0)`] THEN DISCH_TAC THEN
+      UNDISCH_TAC
+       `~(?j. 1 <= j /\ j <= n /\ (!x. x IN s DELETE a1 ==> (x j = 0)))` THEN
+      REWRITE_TAC[NOT_EXISTS_THM] THEN EXISTS_TAC `k:num` THEN
+      ASM_MESON_TAC[KLE_IMP_POINTWISE; LE];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `~(kle n a0 a3)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[KLE_IMP_POINTWISE; ARITH_RULE `~(a + 1 <= a)`];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `~(a3:num->num IN s)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN `kle n a3 a2` ASSUME_TAC THENL
+     [SUBGOAL_THEN `kle n a0 a1` MP_TAC THENL
+       [ASM_MESON_TAC[]; ALL_TAC] THEN
+      REWRITE_TAC[kle] 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
+      ONCE_REWRITE_TAC[
+        ASSUME `!j:num. a0 j = (if j = k then a3 j + 1 else a3 j)`;
+        ASSUME `!j:num. a1 j = (if j = k then a2 j + 1 else a2 j)`] THEN
+      REPEAT(COND_CASES_TAC THEN REWRITE_TAC[]) THEN ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN `kle n a3 a0` ASSUME_TAC THENL
+     [REWRITE_TAC[kle] THEN EXISTS_TAC `{k:num}` THEN
+      ASM_REWRITE_TAC[SUBSET; IN_SING; IN_NUMSEG] THEN
+      ASM_MESON_TAC[ADD_CLAUSES];
+      ALL_TAC] THEN
+    MATCH_MP_TAC HAS_SIZE_CARD THEN CONV_TAC HAS_SIZE_CONV THEN
+    MAP_EVERY EXISTS_TAC
+     [`s:(num->num)->bool`; `a3 INSERT (s DELETE (a1:num->num))`] THEN
+    SUBGOAL_THEN `~(a3:num->num = a1) /\ ~(a3 = a0)` STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[]; ALL_TAC] THEN
+    CONJ_TAC THENL [MATCH_MP_TAC lemma_1 THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN `ksimplex p n (a3 INSERT (s DELETE a1))` ASSUME_TAC THENL
+     [MP_TAC(ASSUME `ksimplex p n s`) THEN REWRITE_TAC[ksimplex] THEN
+      MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+       [SIMP_TAC[HAS_SIZE; FINITE_INSERT; FINITE_DELETE; CARD_CLAUSES;
+                 CARD_DELETE] THEN
+        ASM_REWRITE_TAC[IN_DELETE] THEN STRIP_TAC THEN ARITH_TAC;
+        ALL_TAC] THEN
+      MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+       [DISCH_TAC THEN REWRITE_TAC[IN_INSERT; IN_DELETE] THEN
+        SUBGOAL_THEN `!j. (a3:num->num) j <= p`
+         (fun th -> ASM_MESON_TAC[th]) THEN
+        X_GEN_TAC `j:num` THEN
+        FIRST_X_ASSUM(MP_TAC o SPECL [`a0:num->num`; `j:num`]) THEN
+        ASM_REWRITE_TAC[] THEN COND_CASES_TAC THEN ARITH_TAC;
+        ALL_TAC] THEN
+      MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+       [REWRITE_TAC[IN_INSERT; IN_DELETE] THEN REPEAT STRIP_TAC THENL
+         [ALL_TAC; ASM_MESON_TAC[]] THEN
+        FIRST_X_ASSUM SUBST_ALL_TAC THEN
+        EXPAND_TAC "a3" THEN REWRITE_TAC[] THEN ASM_MESON_TAC[];
+        ALL_TAC] THEN
+      DISCH_TAC THEN REWRITE_TAC[IN_INSERT; IN_DELETE] THEN
+      SUBGOAL_THEN `!x. x IN s /\ ~(x = a1) ==> kle n a3 x`
+       (fun th -> ASM_MESON_TAC[th; KLE_REFL]) THEN
+      X_GEN_TAC `x:num->num` THEN STRIP_TAC THEN
+      MATCH_MP_TAC KLE_BETWEEN_L THEN
+      MAP_EVERY EXISTS_TAC [`a0:num->num`; `a2:num->num`] THEN
+      ASM_MESON_TAC[IN_DELETE];
+      ALL_TAC] THEN
+    GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_INSERT; NOT_IN_EMPTY] THEN
+    X_GEN_TAC `s':(num->num)->bool` THEN EQ_TAC THENL
+     [ALL_TAC;
+      DISCH_THEN(DISJ_CASES_THEN SUBST_ALL_TAC) THENL
+       [ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[] THEN EXISTS_TAC `a3:num->num` THEN
+      REWRITE_TAC[IN_INSERT; DELETE_INSERT] THEN
+      UNDISCH_TAC `~((a3:num->num) IN s)` THEN SET_TAC[]] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `a':num->num` STRIP_ASSUME_TAC) THEN
+    MP_TAC(SPECL [`p:num`; `n:num`; `s':(num->num)->bool`]
+                 KSIMPLEX_EXTREMA_STRONG) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `a_min:num->num` (X_CHOOSE_THEN `a_max:num->num`
+      STRIP_ASSUME_TAC)) THEN
+    SUBGOAL_THEN `(a':num->num = a_min) \/ (a' = a_max)` MP_TAC THENL
+     [MATCH_MP_TAC KSIMPLEX_FIX_PLANE THEN MAP_EVERY EXISTS_TAC
+       [`p:num`; `(a2:num->num) k`; `n:num`;
+        `k:num`; `s':(num->num)->bool`] THEN
+      REPEAT CONJ_TAC THEN TRY(FIRST_ASSUM MATCH_ACCEPT_TAC) THEN
+      X_GEN_TAC `x:num->num` THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+      SUBGOAL_THEN `kle n a0 x /\ kle n x a2` MP_TAC THENL
+       [ASM_MESON_TAC[IN_DELETE]; ALL_TAC] THEN
+      DISCH_THEN(CONJUNCTS_THEN (MP_TAC o SPEC `k:num` o MATCH_MP
+        KLE_IMP_POINTWISE)) THEN
+      SUBGOAL_THEN `(a2:num->num) k <= a0 k`
+        (fun th -> MP_TAC th THEN ARITH_TAC) THEN
+      UNDISCH_TAC `!j:num. a1 j = (if j = k then a2 j + 1 else a2 j)` THEN
+      DISCH_THEN(MP_TAC o SPEC `k:num`) THEN ASM_REWRITE_TAC[] THEN ARITH_TAC;
+      ALL_TAC] THEN
+    DISCH_THEN(DISJ_CASES_THEN SUBST_ALL_TAC) THENL
+     [DISJ2_TAC THEN MATCH_MP_TAC lemma THEN
+      MAP_EVERY EXISTS_TAC [`a3:num->num`; `a_min:num->num`] THEN
+      ASM_REWRITE_TAC[IN_INSERT] THEN CONJ_TAC THENL
+       [UNDISCH_TAC `~(a3:num->num IN s)` THEN SET_TAC[]; ALL_TAC] THEN
+      SUBGOAL_THEN `a_max:num->num = a2` MP_TAC THENL
+       [SUBGOAL_THEN `a2:num->num IN (s' DELETE a_min) /\
+                      a_max:num->num IN (s DELETE a1)`
+        MP_TAC THENL
+         [ASM_MESON_TAC[IN_DELETE]; ASM_MESON_TAC[KLE_ANTISYM; IN_DELETE]];
+        ALL_TAC] THEN
+      SUBGOAL_THEN
+       `!j. a2 j = if 1 <= j /\ j <= n then a3 j + 1 else a3 j`
+       (fun th -> ASM_REWRITE_TAC[th; FUN_EQ_THM])
+      THENL
+       [ALL_TAC;
+        MATCH_MP_TAC MONO_FORALL THEN MESON_TAC[EQ_ADD_RCANCEL]] THEN
+      UNDISCH_TAC `!j:num. a1 j = (if j = k then a2 j + 1 else a2 j)` THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_FORALL THEN
+      MESON_TAC[EQ_ADD_RCANCEL];
+      DISJ1_TAC THEN MATCH_MP_TAC lemma THEN
+      MAP_EVERY EXISTS_TAC [`a1:num->num`; `a_max:num->num`] THEN
+      REPEAT CONJ_TAC THEN TRY(FIRST_ASSUM ACCEPT_TAC) THEN
+      SUBGOAL_THEN `a_min:num->num = a0` MP_TAC THENL
+       [SUBGOAL_THEN `a0:num->num IN (s' DELETE a_max) /\
+                      a_min:num->num IN (s DELETE a1)`
+        MP_TAC THENL
+         [ASM_MESON_TAC[IN_DELETE]; ASM_MESON_TAC[KLE_ANTISYM; IN_DELETE]];
+        ALL_TAC] THEN
+      UNDISCH_THEN `!j:num. a1 j = (if j = k then a2 j + 1 else a2 j)`
+       (K ALL_TAC) THEN
+      ASM_REWRITE_TAC[FUN_EQ_THM] THEN MATCH_MP_TAC MONO_FORALL THEN
+      MESON_TAC[EQ_ADD_RCANCEL]];
+    ALL_TAC] THEN
+  MP_TAC(SPECL [`a:num->num`; `p:num`; `n:num`; `s:(num->num)->bool`]
+        KSIMPLEX_PREDECESSOR) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(TAUT `~a /\ (b ==> c) ==> a \/ b ==> c`) THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[KLE_ANTISYM]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:num->num`
+   (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:num` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPECL [`a:num->num`; `p:num`; `n:num`; `s:(num->num)->bool`]
+        KSIMPLEX_SUCCESSOR) THEN
+  REWRITE_TAC[ASSUME `ksimplex p n s`; ASSUME `a:num->num IN s`] THEN
+  MATCH_MP_TAC(TAUT `~a /\ (b ==> c) ==> a \/ b ==> c`) THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[KLE_ANTISYM]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:num->num`
+   (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `l:num` STRIP_ASSUME_TAC) THEN
+  ABBREV_TAC `a' = \j:num. if j = l then u(j) + 1 else u(j)` THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [FUN_EQ_THM]) THEN
+  REWRITE_TAC[] THEN DISCH_THEN(ASSUME_TAC o GSYM) THEN
+  SUBGOAL_THEN `~(k:num = l)` ASSUME_TAC THENL
+   [DISCH_TAC THEN
+    UNDISCH_TAC `!j:num. v j = (if j = l then a j + 1 else a j)` THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `l:num`) THEN
+    REWRITE_TAC[] THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ksimplex]) THEN
+    DISCH_THEN(MP_TAC o last o CONJUNCTS) THEN
+    DISCH_THEN(MP_TAC o SPECL [`u:num->num`; `v:num->num`]) THEN
+    ASM_REWRITE_TAC[] THEN
+    ASM_REWRITE_TAC[kle] THEN
+    DISCH_THEN(DISJ_CASES_THEN (CHOOSE_THEN (MP_TAC o SPEC `l:num` o
+      CONJUNCT2))) THEN
+    ASM_REWRITE_TAC[] THEN COND_CASES_TAC THEN ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~(a':num->num = a)` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[FUN_EQ_THM] THEN DISCH_THEN(MP_TAC o SPEC `k:num`) THEN
+    ASM_REWRITE_TAC[] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~((a':num->num) IN s)` ASSUME_TAC THENL
+   [DISCH_TAC THEN FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ksimplex]) THEN
+    DISCH_THEN(MP_TAC o SPECL [`a:num->num`; `a':num->num`] o
+      last o CONJUNCTS) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(DISJ_CASES_THEN (MP_TAC o MATCH_MP KLE_IMP_POINTWISE)) THENL
+     [DISCH_THEN(MP_TAC o SPEC `k:num`) THEN ASM_REWRITE_TAC[] THEN ARITH_TAC;
+      DISCH_THEN(MP_TAC o SPEC `l:num`) THEN ASM_REWRITE_TAC[] THEN
+      ARITH_TAC];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `kle n u a /\ kle n u a' /\ kle n a v /\ kle n a' v`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[kle] THEN REPEAT CONJ_TAC THENL
+     [EXISTS_TAC `{k:num}`;
+      EXISTS_TAC `{l:num}`;
+      EXISTS_TAC `{l:num}`;
+      EXISTS_TAC `{k:num}`] THEN
+    ASM_REWRITE_TAC[IN_SING; SUBSET; IN_NUMSEG] THEN
+    ASM_MESON_TAC[ADD_CLAUSES];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!x. kle n u x /\ kle n x v
+                    ==> ((x = u) \/ (x = a) \/ (x = a') \/ (x = v))`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `x:num->num` THEN
+    DISCH_THEN(CONJUNCTS_THEN (MP_TAC o MATCH_MP KLE_IMP_POINTWISE)) THEN
+    ASM_REWRITE_TAC[FUN_EQ_THM; IMP_IMP; AND_FORALL_THM] THEN
+    ONCE_REWRITE_TAC[COND_RAND] THEN
+    ASM_CASES_TAC `(x:num->num) k = u k` THEN
+    ASM_CASES_TAC `(x:num->num) l = u l` THENL
+     [DISCH_THEN(fun th -> DISJ1_TAC THEN MP_TAC th);
+      DISCH_THEN(fun th -> DISJ2_TAC THEN DISJ2_TAC THEN DISJ1_TAC THEN
+                           MP_TAC th);
+      DISCH_THEN(fun th -> DISJ2_TAC THEN DISJ1_TAC THEN MP_TAC th);
+      DISCH_THEN(fun th -> REPEAT DISJ2_TAC THEN MP_TAC th)] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `j:num` THEN
+    REPEAT(COND_CASES_TAC THEN
+           ASM_REWRITE_TAC[LE_ANTISYM;
+       ARITH_RULE `x <= u + 1 /\ u <= x <=> (x = u) \/ (x = u + 1)`]);
+    ALL_TAC] THEN
+  SUBGOAL_THEN `kle n u v` ASSUME_TAC THENL
+   [ASM_MESON_TAC[KLE_TRANS; ksimplex]; ALL_TAC] THEN
+  SUBGOAL_THEN `ksimplex p n (a' INSERT (s DELETE a))` ASSUME_TAC THENL
+   [MP_TAC(ASSUME `ksimplex p n s`) THEN REWRITE_TAC[ksimplex] THEN
+    MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+     [SIMP_TAC[HAS_SIZE; FINITE_INSERT; FINITE_DELETE; CARD_CLAUSES;
+               CARD_DELETE; IN_DELETE] THEN
+      ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+     [REWRITE_TAC[IN_INSERT; IN_DELETE] THEN
+      SIMP_TAC[TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN
+      REWRITE_TAC[RIGHT_FORALL_IMP_THM; LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(fun th -> X_GEN_TAC `j:num` THEN MP_TAC th) THEN
+      COND_CASES_TAC THEN ASM_SIMP_TAC[] THEN
+      DISCH_THEN(MP_TAC o SPEC `v:num->num`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(MP_TAC o SPEC `l:num`) THEN ASM_REWRITE_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+     [REWRITE_TAC[IN_INSERT; IN_DELETE] THEN
+      REWRITE_TAC[TAUT `(a \/ b) /\ c <=> a /\ c \/ b /\ c`] THEN
+      SIMP_TAC[TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN
+      REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+      REWRITE_TAC[EXISTS_REFL; LEFT_FORALL_IMP_THM] THEN
+      ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    REWRITE_TAC[IN_INSERT; IN_DELETE] THEN
+    SUBGOAL_THEN
+     `!x. x IN s /\ kle n v x ==> kle n a' x`
+    ASSUME_TAC THENL
+     [X_GEN_TAC `x:num->num` THEN STRIP_TAC THEN
+      MATCH_MP_TAC KLE_BETWEEN_R THEN
+      MAP_EVERY EXISTS_TAC [`u:num->num`; `v:num->num`] THEN
+      ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[ksimplex; KLE_TRANS];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!x. x IN s /\ kle n x u ==> kle n x a'`
+    ASSUME_TAC THENL
+     [X_GEN_TAC `x:num->num` THEN STRIP_TAC THEN
+      MATCH_MP_TAC KLE_BETWEEN_L THEN
+      MAP_EVERY EXISTS_TAC [`u:num->num`; `v:num->num`] THEN
+      ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[ksimplex; KLE_TRANS];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!x. x IN s /\ ~(x = a) ==> kle n a' x \/ kle n x a'`
+     (fun th -> MESON_TAC[th; KLE_REFL; ASSUME `(a:num->num) IN s`]) THEN
+    X_GEN_TAC `x:num->num` THEN STRIP_TAC THEN
+    ASM_CASES_TAC `kle n v x` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    ASM_CASES_TAC `kle n x u` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN `(x:num->num = u) \/ (x = a) \/ (x = a') \/ (x = v)`
+     (fun th -> ASM_MESON_TAC[th; KLE_REFL]) THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[ksimplex];
+    ALL_TAC] THEN
+  MATCH_MP_TAC HAS_SIZE_CARD THEN CONV_TAC HAS_SIZE_CONV THEN
+  MAP_EVERY EXISTS_TAC
+   [`s:(num->num)->bool`; `a' INSERT (s DELETE (a:num->num))`] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_DELETE; IN_INSERT] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  X_GEN_TAC `s':(num->num)->bool` THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN EQ_TAC THENL
+   [ALL_TAC;
+    DISCH_THEN(DISJ_CASES_THEN SUBST1_TAC) THENL
+     [ASM_MESON_TAC[]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[] THEN EXISTS_TAC `a':num->num` THEN
+    REWRITE_TAC[EXTENSION; IN_INSERT; IN_DELETE] THEN ASM_MESON_TAC[]] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `a'':num->num` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `(a:num->num) IN s' \/ a' IN s'` MP_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC MONO_OR THEN CONJ_TAC THEN DISCH_TAC THEN
+    MP_TAC(ASSUME `s' DELETE a'' = s DELETE (a:num->num)`) THEN
+    REWRITE_TAC[EXTENSION] THEN
+    DISCH_THEN(fun th -> MP_TAC th THEN MP_TAC th) THENL
+     [DISCH_THEN(MP_TAC o SPEC `a:num->num`);
+      DISCH_THEN(MP_TAC o SPEC `a':num->num`)] THEN
+    REWRITE_TAC[IN_DELETE] THEN ASM_REWRITE_TAC[IN_INSERT; IN_DELETE] THEN
+    DISCH_THEN(SUBST_ALL_TAC o SYM) THEN ASM_MESON_TAC[]] THEN
+  SUBGOAL_THEN `~(u:num->num = v)` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[FUN_EQ_THM] THEN DISCH_THEN(MP_TAC o SPEC `l:num`) THEN
+    ASM_REWRITE_TAC[] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~(kle n v u)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[KLE_ANTISYM]; ALL_TAC] THEN
+  SUBGOAL_THEN `~(u:num->num = a)` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[FUN_EQ_THM] THEN DISCH_THEN(MP_TAC o SPEC `k:num`) THEN
+    ASM_REWRITE_TAC[] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~(v:num->num = a)` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[FUN_EQ_THM] THEN DISCH_THEN(MP_TAC o SPEC `l:num`) THEN
+    ASM_REWRITE_TAC[] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `u:num->num IN s' /\ v IN s'` STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[EXTENSION; IN_DELETE]; ALL_TAC] THEN
+  ASM_CASES_TAC
+   `!x. x IN s' ==> kle n x u \/ kle n v x`
+  THENL
+   [ALL_TAC;
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `w:num->num` MP_TAC) THEN
+    REWRITE_TAC[NOT_IMP; DE_MORGAN_THM] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `(w:num->num = u) \/ (w = a) \/ (w = a') \/ (w = v)`
+     (fun th -> ASM_MESON_TAC[KLE_REFL; th]) THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[ksimplex]] THEN
+  MP_TAC(SPECL [`u:num->num`; `p:num`; `n:num`; `s':(num->num)->bool`]
+               KSIMPLEX_SUCCESSOR) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[EXTENSION; IN_DELETE]; ALL_TAC] THEN
+  DISCH_THEN(DISJ_CASES_THEN2 (MP_TAC o SPEC `v:num->num`) MP_TAC) THENL
+   [ASM_MESON_TAC[EXTENSION; IN_DELETE]; ALL_TAC] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_THEN(K ALL_TAC) THEN
+  UNDISCH_TAC `!x. x IN s' ==> kle n x u \/ kle n v x` THEN
+  REWRITE_TAC[NOT_EXISTS_THM] THEN MATCH_MP_TAC MONO_FORALL THEN
+  X_GEN_TAC `w:num->num` THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(DISJ_CASES_THEN(MP_TAC o MATCH_MP KLE_IMP_POINTWISE)) THEN
+  ASM_REWRITE_TAC[] THENL
+   [MESON_TAC[ARITH_RULE `~(i + 1 <= i)`]; ALL_TAC] THEN
+  DISCH_THEN(fun th -> MP_TAC(SPEC `k:num` th) THEN
+                       MP_TAC(SPEC `l:num` th)) THEN
+  ASM_REWRITE_TAC[] THEN
+  REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN TRY ARITH_TAC THEN
+  UNDISCH_TAC `~(k:num = l)` THEN ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence another step towards concreteness.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let KUHN_SIMPLEX_LEMMA = prove
+ (`!p n. (!s. ksimplex p (n + 1) s ==> (IMAGE rl s SUBSET 0..n+1)) /\
+         ODD(CARD{f | (?s a. ksimplex p (n + 1) s /\
+                             a IN s /\
+                             (f = s DELETE a)) /\
+                      (IMAGE rl f = 0 .. n) /\
+                      ((?j. 1 <= j /\ j <= n + 1 /\
+                            !x. x IN f ==> (x j = 0)) \/
+                       (?j. 1 <= j /\ j <= n + 1 /\
+                            !x. x IN f ==> (x j = p)))})
+         ==>  ODD(CARD {s | s IN {s | ksimplex p (n + 1) s} /\
+                            (IMAGE rl s = 0..n+1)})`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+   `ODD(CARD {f | f IN {f | ?s. s IN {s | ksimplex p (n + 1) s} /\
+                             (?a. a IN s /\ (f = s DELETE a))} /\
+               (IMAGE rl f = 0..n) /\
+               ((?j. 1 <= j /\ j <= n + 1 /\ !x. x IN f ==> (x j = 0)) \/
+                (?j. 1 <= j /\ j <= n + 1 /\ !x. x IN f ==> (x j = p)))})`
+  MP_TAC THENL
+   [ASM_REWRITE_TAC[IN_ELIM_THM; RIGHT_AND_EXISTS_THM]; ALL_TAC] THEN
+  MATCH_MP_TAC KUHN_COMPLETE_LEMMA THEN  REWRITE_TAC[FINITE_SIMPLICES] THEN
+  ASM_REWRITE_TAC[IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+  CONV_TAC(LAND_CONV(ONCE_DEPTH_CONV SYM_CONV)) THEN ASM_REWRITE_TAC[] THENL
+   [ASM_MESON_TAC[ksimplex; ARITH_RULE `(n + 1) + 1 = n + 2`];
+    ASM_SIMP_TAC[];
+    MATCH_MP_TAC KSIMPLEX_REPLACE_0;
+    MATCH_MP_TAC KSIMPLEX_REPLACE_1;
+    MATCH_MP_TAC KSIMPLEX_REPLACE_2] THEN
+  ASM_MESON_TAC[ARITH_RULE `~(n + 1 = 0)`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Reduced labelling.                                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let reduced = new_definition
+ `reduced label n (x:num->num) =
+     @k. k <= n /\
+         (!i. 1 <= i /\ i < k + 1 ==> (label x i = 0)) /\
+         ((k = n) \/ ~(label x (k + 1) = 0))`;;
+
+let REDUCED_LABELLING = prove
+ (`!label x n.
+      reduced label n x <= n /\
+      (!i. 1 <= i /\ i < reduced label n x + 1 ==> (label x i = 0)) /\
+      ((reduced label n x = n) \/ ~(label x (reduced label n x + 1) = 0))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[reduced] THEN CONV_TAC SELECT_CONV THEN
+  MP_TAC(SPEC `\j. j <= n /\ ~(label (x:num->num) (j + 1) = 0) \/ (n = j)`
+     num_WOP) THEN
+  REWRITE_TAC[] THEN
+  MATCH_MP_TAC(TAUT `a /\ (b ==> c) ==> (a <=> b) ==> c`) THEN
+  CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:num` THEN
+  ASM_CASES_TAC `k = n:num` THEN ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[LE_REFL] THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `i - 1`) THEN
+  SIMP_TAC[LT_IMP_LE] THEN
+  ASM_SIMP_TAC[ARITH_RULE `1 <= i /\ i < n + 1 ==> i - 1 < n`] THEN
+  ASM_SIMP_TAC[ARITH_RULE `1 <= i /\ i < n + 1 ==> ~(n = i - 1)`] THEN
+  ASM_SIMP_TAC[SUB_ADD] THEN POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+  ARITH_TAC);;
+
+let REDUCED_LABELLING_UNIQUE = prove
+ (`!label x n.
+      r <= n /\
+      (!i. 1 <= i /\ i < r + 1 ==> (label x i = 0)) /\
+      ((r = n) \/ ~(label x (r + 1) = 0))
+      ==> (reduced label n x = r)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC(SPECL
+        [`label:(num->num)->(num->num)`; `x:num->num`; `n:num`]
+        REDUCED_LABELLING) THEN
+  MATCH_MP_TAC(ARITH_RULE `~(a < b) /\ ~(b < a:num) ==> (a = b)`) THEN
+  ASM_MESON_TAC[ARITH_RULE `s < r:num /\ r <= n ==> ~(s = n)`;
+                ARITH_RULE `s < r ==> 1 <= s + 1 /\ s + 1 < r + 1`]);;
+
+let REDUCED_LABELLING_0 = prove
+ (`!label n x j.
+        1 <= j /\ j <= n /\ (label x j = 0)
+        ==> ~(reduced label n x = j - 1)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`label:(num->num)->num->num`; `x:num->num`; `n:num`]
+               REDUCED_LABELLING) THEN
+  ASM_SIMP_TAC[SUB_ADD; ARITH_RULE `1 <= j /\ j <= n ==> ~(j - 1 = n)`]);;
+
+let REDUCED_LABELLING_1 = prove
+ (`!label n x j.
+        1 <= j /\ j <= n /\ ~(label x j = 0)
+        ==> reduced label n x < j`,
+  REWRITE_TAC[GSYM NOT_LE] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`label:(num->num)->num->num`; `x:num->num`; `n:num`]
+               REDUCED_LABELLING) THEN
+  DISCH_THEN(MP_TAC o SPEC `j:num` o CONJUNCT1 o CONJUNCT2) THEN
+  ASM_REWRITE_TAC[ARITH_RULE `y < x + 1 <=> (y <= x)`]);;
+
+let REDUCED_LABELLING_SUC = prove
+ (`!lab n x.
+        ~(reduced lab (n + 1) x = n + 1)
+        ==> (reduced lab (n + 1) x = reduced lab n x)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC REDUCED_LABELLING_UNIQUE THEN
+  ASM_MESON_TAC[REDUCED_LABELLING; ARITH_RULE
+   `x <= n + 1 /\ ~(x = n + 1) ==> x <= n`]);;
+
+let COMPLETE_FACE_TOP = prove
+ (`!lab f n.
+         (!x j. x IN f /\ 1 <= j /\ j <= n + 1 /\ (x j = 0)
+                ==> (lab x j = 0)) /\
+         (!x j. x IN f /\ 1 <= j /\ j <= n + 1 /\ (x j = p)
+                ==> (lab x j = 1))
+         ==> ((IMAGE (reduced lab (n + 1)) f = 0..n) /\
+              ((?j. 1 <= j /\ j <= n + 1 /\ !x. x IN f ==> (x j = 0)) \/
+               (?j. 1 <= j /\ j <= n + 1 /\ !x. x IN f ==> (x j = p))) <=>
+              (IMAGE (reduced lab (n + 1)) f = 0..n) /\
+              (!x. x IN f ==> (x (n + 1) = p)))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ALL_TAC; MESON_TAC[ARITH_RULE `1 <= n + 1`; LE_REFL]] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THENL
+   [DISCH_THEN(MP_TAC o SPEC `j - 1`) THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_THEN(K ALL_TAC) THEN
+    ASM_SIMP_TAC[IN_IMAGE; IN_NUMSEG; LE_0; NOT_EXISTS_THM;
+                 ARITH_RULE `j <= n + 1 ==> j - 1 <= n`] THEN
+    ASM_MESON_TAC[REDUCED_LABELLING_0];
+    DISCH_THEN(MP_TAC o SPEC `j:num`) THEN
+    REWRITE_TAC[IN_IMAGE; IN_NUMSEG; LE_0; NOT_LE] THEN
+    ASM_SIMP_TAC[ARITH_RULE `j <= n + 1 ==> ((j <= n) <=> ~(j = n + 1))`] THEN
+    ASM_MESON_TAC[REDUCED_LABELLING_1; ARITH_RULE `~(1 = 0)`; LT_REFL]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence we get just about the nice induction.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let KUHN_INDUCTION = prove
+ (`!p n. 0 < p /\
+         (!x j. (!j. x(j) <= p) /\ 1 <= j /\ j <= n + 1 /\ (x j = 0)
+                ==> (lab x j = 0)) /\
+         (!x j. (!j. x(j) <= p) /\ 1 <= j /\ j <= n + 1 /\ (x j = p)
+                ==> (lab x j = 1))
+         ==> ODD(CARD {f | ksimplex p n f /\
+                           (IMAGE (reduced lab n) f = 0..n)})
+             ==> ODD(CARD {s | ksimplex p (n + 1) s /\
+                           (IMAGE (reduced lab (n + 1)) s = 0..n+1)})`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[IN_ELIM_THM] KUHN_SIMPLEX_LEMMA) THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_NUMSEG; LE_0] THEN
+    MESON_TAC[ARITH_RULE `x <= n ==> x <= n + 1`; REDUCED_LABELLING];
+    ALL_TAC] THEN
+  FIRST_ASSUM(fun th -> MP_TAC th THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC) THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [EXTENSION] THEN
+  X_GEN_TAC `f:(num->num)->bool` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  ASM_CASES_TAC
+   `(!x j. x IN f /\ 1 <= j /\ j <= n + 1 /\ (x j = 0) ==> (lab x j = 0)) /\
+    (!x j. x IN f /\ 1 <= j /\ j <= n + 1 /\ (x j = p) ==> (lab x j = 1))`
+  THENL
+   [ALL_TAC;
+    MATCH_MP_TAC(TAUT `~a /\ ~b ==> (a /\ c <=> b /\ d)`) THEN
+    CONJ_TAC THEN FIRST_X_ASSUM(MP_TAC o check (is_neg o concl)) THEN
+    REWRITE_TAC[CONTRAPOS_THM] THEN REWRITE_TAC[ksimplex] THEN
+    ASM_MESON_TAC[IN_DELETE]] THEN
+  ASM_SIMP_TAC[COMPLETE_FACE_TOP] THEN
+  ASM_CASES_TAC `!x. x IN f ==> (x(n + 1):num = p)` THENL
+   [ALL_TAC;
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o CONJUNCT1) THEN
+    REWRITE_TAC[ksimplex] THEN
+    ASM_MESON_TAC[ARITH_RULE `~(n + 1 <= n)`]] THEN
+  ASM_SIMP_TAC[SIMPLEX_TOP_FACE] THEN
+  ASM_CASES_TAC `ksimplex p n f` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `k:num` THEN REWRITE_TAC[] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `x:num->num` THEN REWRITE_TAC[] THEN
+  ASM_CASES_TAC `(x:num->num) IN f` THEN ASM_REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC REDUCED_LABELLING_SUC THEN
+  MATCH_MP_TAC(ARITH_RULE `a:num < b ==> ~(a = b)`) THEN
+  MATCH_MP_TAC REDUCED_LABELLING_1 THEN
+  REWRITE_TAC[LE_REFL; ARITH_RULE `1 <= n + 1`] THEN
+  MATCH_MP_TAC(ARITH_RULE `(n = 1) ==> ~(n = 0)`) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[LE_REFL; ARITH_RULE `1 <= n + 1`] THEN
+  ASM_MESON_TAC[ksimplex]);;
+
+(* ------------------------------------------------------------------------- *)
+(* And so we get the final combinatorial result.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let KSIMPLEX_0 = prove
+ (`ksimplex p 0 s <=> (s = {(\x. p)})`,
+  REWRITE_TAC[ksimplex; ADD_CLAUSES] THEN
+  CONV_TAC(LAND_CONV(LAND_CONV HAS_SIZE_CONV)) THEN
+  REWRITE_TAC[ARITH_RULE `1 <= j /\ j <= 0 <=> F`] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b <=> ~(a ==> ~b)`] THEN
+  SIMP_TAC[LEFT_IMP_EXISTS_THM] THEN REWRITE_TAC[IN_SING] THEN
+  SIMP_TAC[RIGHT_FORALL_IMP_THM] THEN REWRITE_TAC[KLE_REFL] THEN
+  REWRITE_TAC[LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN
+  REWRITE_TAC[AND_FORALL_THM; ARITH_RULE
+   `x <= y:num /\ (x = y) <=> (x = y)`] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN
+  REWRITE_TAC[GSYM FUN_EQ_THM] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  REWRITE_TAC[UNWIND_THM2]);;
+
+let REDUCE_LABELLING_0 = prove
+ (`!lab x. reduced lab 0 x = 0`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC REDUCED_LABELLING_UNIQUE THEN
+  REWRITE_TAC[LE_REFL] THEN ARITH_TAC);;
+
+let KUHN_COMBINATORIAL = prove
+ (`!lab p n.
+         0 < p /\
+         (!x j. (!j. x(j) <= p) /\ 1 <= j /\ j <= n /\ (x j = 0)
+                ==> (lab x j = 0)) /\
+         (!x j. (!j. x(j) <= p) /\ 1 <= j /\ j <= n  /\ (x j = p)
+                ==> (lab x j = 1))
+         ==> ODD(CARD {s | ksimplex p n s /\
+                           (IMAGE (reduced lab n) s = 0..n)})`,
+  GEN_TAC THEN GEN_TAC THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN DISCH_TAC THEN
+  INDUCT_TAC THENL
+   [DISCH_THEN(K ALL_TAC) THEN
+    SUBGOAL_THEN `{s | ksimplex p 0 s /\ (IMAGE (reduced lab 0) s = 0 .. 0)} =
+                  {{(\x. p)}}`
+     (fun th -> SIMP_TAC[CARD_CLAUSES; NOT_IN_EMPTY;
+                         FINITE_RULES; th; ARITH]) THEN
+    GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_ELIM_THM; KSIMPLEX_0; IN_SING] THEN
+    GEN_TAC THEN MATCH_MP_TAC(TAUT `(a ==> b) ==> (a /\ b <=> a)`) THEN
+    DISCH_THEN SUBST_ALL_TAC THEN
+    REWRITE_TAC[NUMSEG_SING; EXTENSION; IN_SING; IN_IMAGE] THEN
+    REWRITE_TAC[REDUCE_LABELLING_0] THEN MESON_TAC[];
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o check (is_imp o concl)) THEN
+    ANTS_TAC THENL
+     [ASM_MESON_TAC[ARITH_RULE `j <= n ==> j <= SUC n`];
+      ALL_TAC] THEN
+    REWRITE_TAC[ADD1] THEN MATCH_MP_TAC KUHN_INDUCTION THEN
+    ASM_REWRITE_TAC[GSYM ADD1]]);;
+
+let KUHN_LEMMA = prove
+ (`!n p label.
+        0 < p /\ 0 < n /\
+        (!x. (!i. 1 <= i /\ i <= n ==> x(i) <= p)
+             ==> !i. 1 <= i /\ i <= n ==> (label x i = 0) \/ (label x i = 1)) /\
+        (!x. (!i. 1 <= i /\ i <= n ==> x(i) <= p)
+             ==> !i. 1 <= i /\ i <= n /\ (x i = 0) ==> (label x i = 0)) /\
+        (!x. (!i. 1 <= i /\ i <= n ==> x(i) <= p)
+             ==> !i. 1 <= i /\ i <= n /\ (x i = p) ==> (label x i = 1))
+        ==> ?q. (!i. 1 <= i /\ i <= n ==> q(i) < p) /\
+                (!i. 1 <= i /\ i <= n
+                     ==> ?r s. (!j. 1 <= j /\ j <= n
+                                    ==> q(j) <= r(j) /\ r(j) <= q(j) + 1) /\
+                               (!j. 1 <= j /\ j <= n
+                                    ==> q(j) <= s(j) /\ s(j) <= q(j) + 1) /\
+                               ~(label r i = label s i))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`label:(num->num)->num->num`; `p:num`; `n:num`]
+               KUHN_COMBINATORIAL) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  ASM_CASES_TAC
+   `{s | ksimplex p n s /\ (IMAGE (reduced label n) s = 0 .. n)} = {}`
+  THENL [ASM_REWRITE_TAC[CARD_CLAUSES; ARITH]; ALL_TAC] THEN
+  DISCH_THEN(K ALL_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:(num->num)->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPECL [`p:num`; `n:num`; `s:(num->num)->bool`]
+               KSIMPLEX_EXTREMA_STRONG) THEN
+  ASM_REWRITE_TAC[GSYM LT_NZ] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:num->num` THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:num->num` STRIP_ASSUME_TAC) THEN
+  CONJ_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THENL
+   [MATCH_MP_TAC(ARITH_RULE `x + 1 <= y ==> x < y`) THEN
+    MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `(b:num->num) i` THEN
+    CONJ_TAC THENL [ASM_REWRITE_TAC[LE_REFL]; ALL_TAC] THEN
+    ASM_MESON_TAC[ksimplex];
+    ALL_TAC] THEN
+  UNDISCH_TAC `IMAGE (reduced label n) s = 0 .. n` THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE] THEN
+  DISCH_THEN(fun th ->
+    MP_TAC(SPEC `i - 1` th) THEN MP_TAC(SPEC `i:num` th)) THEN
+  ASM_REWRITE_TAC[IN_NUMSEG; LE_0] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:num->num` (STRIP_ASSUME_TAC o GSYM)) THEN
+  ASM_SIMP_TAC[ARITH_RULE `1 <= i /\ i <= n ==> i - 1 <= n`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:num->num` (STRIP_ASSUME_TAC o GSYM)) THEN
+  MAP_EVERY EXISTS_TAC [`u:num->num`; `v:num->num`] THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[KLE_IMP_POINTWISE]; ALL_TAC] THEN
+  MP_TAC(SPECL [`label:(num->num)->num->num`; `u:num->num`; `n:num`]
+                REDUCED_LABELLING) THEN
+  MP_TAC(SPECL [`label:(num->num)->num->num`; `v:num->num`; `n:num`]
+                REDUCED_LABELLING) THEN
+  ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[ARITH_RULE `1 <= i /\ i <= n ==> ~(i - 1 = n)`] THEN
+  ASM_SIMP_TAC[SUB_ADD] THEN ASM_MESON_TAC[ARITH_RULE `i < i + 1`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The main result for the unit cube.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let BROUWER_CUBE = prove
+ (`!f:real^N->real^N.
+        f continuous_on (interval [vec 0,vec 1]) /\
+        IMAGE f (interval [vec 0,vec 1]) SUBSET (interval [vec 0,vec 1])
+        ==> ?x. x IN interval[vec 0,vec 1] /\ (f x = x)`,
+  REPEAT STRIP_TAC THEN ABBREV_TAC `n = dimindex(:N)` THEN
+  SUBGOAL_THEN `1 <= n /\ 0 < n /\ ~(n = 0)` STRIP_ASSUME_TAC THENL
+   [EXPAND_TAC "n" THEN REWRITE_TAC[DIMINDEX_NONZERO; DIMINDEX_GE_1] THEN
+    ASM_MESON_TAC[LT_NZ; DIMINDEX_NONZERO];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC I [TAUT `p <=> ~ ~ p`] THEN
+  PURE_REWRITE_TAC[NOT_EXISTS_THM; TAUT `~(a /\ b) <=> a ==> ~b`] THEN
+  DISCH_TAC THEN SUBGOAL_THEN
+   `?d. &0 < d /\ !x:real^N. x IN interval[vec 0,vec 1] ==> d <= norm(f x - x)`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC BROUWER_COMPACTNESS_LEMMA THEN
+    ASM_SIMP_TAC[COMPACT_INTERVAL; CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST;
+                 CONTINUOUS_ON_ID] THEN
+    ASM_MESON_TAC[VECTOR_SUB_EQ];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN
+  FREEZE_THEN(fun th -> DISCH_THEN(MP_TAC o MATCH_MP th))
+        (SPEC `f:real^N->real^N` KUHN_LABELLING_LEMMA) THEN
+  DISCH_THEN(MP_TAC o SPEC `\i. 1 <= i /\ i <= n`) THEN
+  ANTS_TAC THENL [ASM_SIMP_TAC[IN_INTERVAL; VEC_COMPONENT]; ALL_TAC] THEN
+  REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `label:real^N->num->num` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `!x y i. x IN interval[vec 0,vec 1] /\ y IN interval[vec 0,vec 1] /\
+            1 <= i /\ i <= n /\ ~(label (x:real^N) i :num = label y i)
+            ==> abs((f(x) - x)$i) <= norm(f(y) - f(x)) + norm(y - x)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `abs(((f:real^N->real^N)(y) - f(x))$i) + abs((y - x)$i)` THEN
+    ASM_SIMP_TAC[REAL_LE_ADD2; COMPONENT_LE_NORM] THEN
+    ASM_SIMP_TAC[VECTOR_SUB_COMPONENT] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `!x y fx fy d. (x <= fx /\ fy <= y \/ fx <= x /\ y <= fy)
+             ==> abs(fx - x) <= abs(fy - fx) + abs(y - x)`) THEN
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP (ARITH_RULE
+     `~(a = b)
+      ==> a <= 1 /\ b <= 1 ==> (a = 0) /\ (b = 1) \/ (a = 1) /\ (b = 0)`)) THEN
+    ASM_SIMP_TAC[] THEN STRIP_TAC THEN ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?e. &0 < e /\
+        !x y z i. x IN interval[vec 0,vec 1] /\
+                  y IN interval[vec 0,vec 1] /\
+                  z IN interval[vec 0,vec 1] /\
+                  1 <= i /\ i <= n /\
+                  norm(x - z) < e /\ norm(y - z) < e /\
+                  ~(label (x:real^N) i :num = label y i)
+                  ==> abs((f(z) - z)$i) < d / &n`
+  MP_TAC THENL
+   [SUBGOAL_THEN
+     `(f:real^N->real^N) uniformly_continuous_on interval[vec 0,vec 1]`
+    MP_TAC THENL
+     [ASM_SIMP_TAC[COMPACT_UNIFORMLY_CONTINUOUS; COMPACT_INTERVAL];
+      ALL_TAC] THEN
+    REWRITE_TAC[uniformly_continuous_on] THEN
+    DISCH_THEN(MP_TAC o SPEC `d / &n / &8`) THEN
+    SUBGOAL_THEN `&0 < d / &n / &8` ASSUME_TAC THENL
+     [ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; LT_MULT; ARITH];
+      ALL_TAC] THEN
+    ASM_REWRITE_TAC[dist] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `min (e / &2) (d / &n / &8)` THEN
+    ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_LT_MIN; REAL_HALF] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`; `z:real^N`; `i:num`] THEN
+    STRIP_TAC THEN
+    ASM_SIMP_TAC[VECTOR_SUB_COMPONENT] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `!x fx n1 n2 n3 n4 d4.
+        abs(fx - x) <= n1 + n2 /\
+        abs(fx - fz) <= n3 /\ abs(x - z) <= n4 /\
+        n1 < d4 /\ n2 < &2 * d4 /\ n3 < d4 /\ n4 < d4 /\ (&8 * d4 = d)
+        ==> abs(fz - z) < d`) THEN
+    MAP_EVERY EXISTS_TAC
+     [`(x:real^N)$i`; `(f:real^N->real^N)(x)$i`;
+      `norm((f:real^N->real^N) y - f x)`; `norm(y - x:real^N)`;
+      `norm((f:real^N->real^N) x - f z)`;
+      `norm(x - z:real^N)`; `d / &n / &8`] THEN
+    ASM_SIMP_TAC[GSYM VECTOR_SUB_COMPONENT; COMPONENT_LE_NORM] THEN
+    SIMP_TAC[REAL_DIV_LMUL; REAL_OF_NUM_EQ; ARITH] THEN
+    REPEAT CONJ_TAC THENL
+     [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC REAL_LET_TRANS THEN
+      EXISTS_TAC `norm(x - z:real^N) + norm(y - z)` THEN
+      ASM_SIMP_TAC[REAL_ARITH `a < e / &2 /\ b < e / &2 /\
+                               (&2 * (e / &2) = e) ==> a + b < e`;
+                   REAL_DIV_LMUL; REAL_OF_NUM_EQ; ARITH_EQ] THEN
+      REWRITE_TAC[GSYM dist] THEN MESON_TAC[DIST_TRIANGLE; DIST_SYM];
+      MATCH_MP_TAC REAL_LET_TRANS THEN
+      EXISTS_TAC `norm(x - z:real^N) + norm(y - z)` THEN
+      ASM_SIMP_TAC[REAL_ARITH `a < e /\ b < e ==> a + b < &2 * e`] THEN
+      REWRITE_TAC[GSYM dist] THEN MESON_TAC[DIST_TRIANGLE; DIST_SYM];
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(REAL_ARITH
+        `a < e / &2 /\ &0 < e /\ (&2 * (e / &2) = e) ==> a < e`) THEN
+      ASM_REWRITE_TAC[] THEN
+      SIMP_TAC[REAL_DIV_LMUL; REAL_OF_NUM_EQ; ARITH_EQ]];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  X_CHOOSE_THEN `p:num` MP_TAC (SPEC `&1 + &n / e` REAL_ARCH_SIMPLE) THEN
+  DISJ_CASES_TAC(ARITH_RULE `(p = 0) \/ 0 < p`) THENL
+   [DISCH_THEN(fun th -> DISCH_THEN(K ALL_TAC) THEN MP_TAC th) THEN
+    ASM_REWRITE_TAC[LT_REFL; REAL_NOT_LE] THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT;
+                 REAL_ARITH `&0 < x ==> &0 < &1 + x`];
+    ALL_TAC] THEN
+  DISCH_TAC THEN ASM_REWRITE_TAC[NOT_FORALL_THM] THEN
+  MP_TAC(SPECL [`n:num`; `p:num`;
+            `\v:(num->num). label((lambda i. &(v i) / &p):real^N):num->num`]
+               KUHN_LEMMA) THEN
+  ASM_REWRITE_TAC[ARITH_RULE `(x = 0) \/ (x = 1) <=> x <= 1`] THEN
+  ANTS_TAC THENL
+   [REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; IN_INTERVAL; VEC_COMPONENT] THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT] THEN
+    ASM_SIMP_TAC[REAL_DIV_REFL; REAL_MUL_LZERO; REAL_MUL_LID;
+                 REAL_LT_IMP_NZ; REAL_OF_NUM_LT] THEN
+    ASM_REWRITE_TAC[LE_0; REAL_OF_NUM_LE] THEN
+    REWRITE_TAC[real_div; REAL_MUL_LZERO];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `q:num->num` STRIP_ASSUME_TAC) THEN
+  GEN_REWRITE_TAC BINDER_CONV [SWAP_EXISTS_THM] THEN
+  GEN_REWRITE_TAC I [SWAP_EXISTS_THM] THEN
+  ABBREV_TAC `z:real^N = lambda i. &(q i) / &p` THEN EXISTS_TAC `z:real^N` THEN
+  REWRITE_TAC[TAUT `~(a ==> b) <=> ~b /\ a`] THEN
+  GEN_REWRITE_TAC BINDER_CONV [SWAP_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+  GEN_REWRITE_TAC I [SWAP_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+  SUBGOAL_THEN `z:real^N IN interval[vec 0,vec 1]` ASSUME_TAC THENL
+   [EXPAND_TAC "z" THEN
+    SIMP_TAC[IN_INTERVAL; LAMBDA_BETA; VEC_COMPONENT] THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT] THEN
+    REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+    ASM_SIMP_TAC[LE_0; LT_IMP_LE];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `?i. 1 <= i /\ i <= n /\ d / &n <= abs((f z - z:real^N)$i)`
+  MP_TAC THENL
+   [SUBGOAL_THEN `d <= norm(f z - z:real^N)` MP_TAC THENL
+     [ASM_SIMP_TAC[]; ALL_TAC] THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[NOT_EXISTS_THM; TAUT `~(a /\ b /\ c) <=> a /\ b ==> ~c`] THEN
+    REWRITE_TAC[REAL_NOT_LE] THEN DISCH_TAC THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC
+     `sum(1..dimindex(:N)) (\i. abs((f z - z:real^N)$i))` THEN
+    REWRITE_TAC[NORM_LE_L1] THEN MATCH_MP_TAC SUM_BOUND_LT_GEN THEN
+    REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG; NUMSEG_EMPTY; CARD_NUMSEG] THEN
+    ASM_REWRITE_TAC[NOT_LT; ADD_SUB];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `i:num` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[REAL_NOT_LT] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:num->num` (X_CHOOSE_THEN `s:num->num`
+    STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `(lambda i. &(r i) / &p) :real^N` THEN
+  EXISTS_TAC `(lambda i. &(s i) / &p) :real^N` THEN
+  ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [SIMP_TAC[IN_INTERVAL; LAMBDA_BETA; VEC_COMPONENT] THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT] THEN
+    REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+    ASM_MESON_TAC[LE_0; ARITH_RULE `r <= q + 1 /\ q < p ==> r <= p`];
+    SIMP_TAC[IN_INTERVAL; LAMBDA_BETA; VEC_COMPONENT] THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT] THEN
+    REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+    ASM_MESON_TAC[LE_0; ARITH_RULE `r <= q + 1 /\ q < p ==> r <= p`];
+    ALL_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC(MATCH_MP (REAL_ARITH `a <= b ==> b < e ==> a < e`)
+                        (SPEC_ALL NORM_LE_L1)) THEN
+  MATCH_MP_TAC SUM_BOUND_LT_GEN THEN
+  REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG; NUMSEG_EMPTY; CARD_NUMSEG] THEN
+  ASM_REWRITE_TAC[NOT_LT; ADD_SUB] THEN EXPAND_TAC "z" THEN
+  EXPAND_TAC "n" THEN SIMP_TAC[VECTOR_SUB_COMPONENT; LAMBDA_BETA] THEN
+  ASM_REWRITE_TAC[real_div; GSYM REAL_SUB_RDISTRIB] THEN
+  REWRITE_TAC[GSYM real_div; REAL_ABS_DIV; REAL_ABS_NUM] THEN
+  ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_OF_NUM_LT] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `&1` THEN
+  ASM_SIMP_TAC[REAL_ARITH `q <= r /\ r <= q + &1 ==> abs(r - q) <= &1`;
+               REAL_OF_NUM_LE; REAL_OF_NUM_ADD] THEN
+  GEN_REWRITE_TAC BINOP_CONV [GSYM REAL_INV_INV] THEN
+  MATCH_MP_TAC REAL_LT_INV2 THEN
+  REWRITE_TAC[REAL_INV_DIV; REAL_INV_MUL] THEN
+  ASM_SIMP_TAC[GSYM real_div; REAL_LT_LDIV_EQ; REAL_LT_RDIV_EQ;
+               REAL_OF_NUM_LT; ARITH] THEN
+  ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_OF_NUM_LT] THEN
+  REWRITE_TAC[REAL_INV_1; REAL_MUL_LID] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_LDIV_EQ; REAL_ARITH `&1 + x <= y ==> x < y`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Retractions.                                                              *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("retract_of",(12,"right"));;
+
+let retraction = new_definition
+  `retraction (s,t) (r:real^N->real^N) <=>
+        t SUBSET s /\ r continuous_on s /\ (IMAGE r s SUBSET t) /\
+        (!x. x IN t ==> (r x = x))`;;
+
+let retract_of = new_definition
+  `t retract_of s <=> ?r. retraction (s,t) r`;;
+
+let RETRACTION = prove
+ (`!s t r. retraction (s,t) r <=>
+           t SUBSET s /\
+           r continuous_on s /\
+           IMAGE r s = t /\
+           (!x. x IN t ==> r x = x)`,
+  REWRITE_TAC[retraction] THEN SET_TAC[]);;
+
+let RETRACT_OF_IMP_EXTENSIBLE = prove
+ (`!f:real^M->real^N u s t.
+        s retract_of t /\ f continuous_on s /\ IMAGE f s SUBSET u
+        ==> ?g. g continuous_on t /\ IMAGE g t SUBSET u /\
+                (!x. x IN s ==> g x = f x)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [retract_of]) THEN
+  REWRITE_TAC[RETRACTION; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `r:real^M->real^M` THEN STRIP_TAC THEN
+  EXISTS_TAC `(f:real^M->real^N) o (r:real^M->real^M)` THEN
+  REWRITE_TAC[IMAGE_o; o_THM] THEN
+  CONJ_TAC THENL [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE; ASM SET_TAC[]] THEN
+  ASM_MESON_TAC[]);;
+
+let RETRACTION_IDEMPOTENT = prove
+ (`!r s t. retraction (s,t) r ==> !x. x IN s ==> (r(r(x)) = r(x))`,
+  REWRITE_TAC[retraction; SUBSET; FORALL_IN_IMAGE] THEN MESON_TAC[]);;
+
+let IDEMPOTENT_IMP_RETRACTION = prove
+ (`!f:real^N->real^N s.
+        f continuous_on s /\ IMAGE f s SUBSET s /\
+        (!x. x IN s ==> f(f x) = f x)
+        ==> retraction (s,IMAGE f s) f`,
+  REWRITE_TAC[retraction] THEN SET_TAC[]);;
+
+let RETRACTION_SUBSET = prove
+ (`!r s s' t. retraction (s,t) r /\ t SUBSET s' /\ s' SUBSET s
+              ==> retraction (s',t) r`,
+  SIMP_TAC[retraction] THEN
+  MESON_TAC[IMAGE_SUBSET; SUBSET_TRANS; CONTINUOUS_ON_SUBSET]);;
+
+let RETRACT_OF_SUBSET = prove
+ (`!s s' t. t retract_of s /\ t SUBSET s' /\ s' SUBSET s
+            ==> t retract_of s'`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[retract_of; LEFT_AND_EXISTS_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN MESON_TAC[RETRACTION_SUBSET]);;
+
+let RETRACT_OF_TRANSLATION = prove
+ (`!a t s:real^N->bool.
+        t retract_of s
+        ==> (IMAGE (\x. a + x) t) retract_of (IMAGE (\x. a + x) s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[retract_of; retraction] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real^N->real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(\x:real^N. a + x) o r o (\x:real^N. --a + x)` THEN
+  ASM_SIMP_TAC[IMAGE_SUBSET; FORALL_IN_IMAGE] THEN REPEAT CONJ_TAC THENL
+   [REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+     SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID]) THEN
+    ASM_REWRITE_TAC[GSYM IMAGE_o; o_DEF; VECTOR_ARITH `--a + a + x:real^N = x`;
+                    IMAGE_ID];
+    REWRITE_TAC[IMAGE_o] THEN MATCH_MP_TAC IMAGE_SUBSET THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o ONCE_DEPTH_CONV)
+     [GSYM IMAGE_o] THEN
+    ASM_REWRITE_TAC[o_DEF; VECTOR_ARITH `--a + a + x:real^N = x`; IMAGE_ID];
+    ASM_SIMP_TAC[o_DEF; VECTOR_ARITH `--a + a + x:real^N = x`]]);;
+
+let RETRACT_OF_TRANSLATION_EQ = prove
+ (`!a t s:real^N->bool.
+        (IMAGE (\x. a + x) t) retract_of (IMAGE (\x. a + x) s) <=>
+        t retract_of s`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[RETRACT_OF_TRANSLATION] THEN
+  DISCH_THEN(MP_TAC o SPEC `--a:real^N` o MATCH_MP RETRACT_OF_TRANSLATION) THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID;
+              VECTOR_ARITH `--a + a + x:real^N = x`]);;
+
+add_translation_invariants [RETRACT_OF_TRANSLATION_EQ];;
+
+let RETRACT_OF_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y) /\ t retract_of s
+        ==> (IMAGE f t) retract_of (IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[retract_of; retraction] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real^M->real^M` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPEC `f:real^M->real^N` LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+  ASM_REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^M` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(f:real^M->real^N) o r o (g:real^N->real^M)` THEN
+  UNDISCH_THEN `!x y. (f:real^M->real^N) x = f y ==> x = y` (K ALL_TAC) THEN
+  ASM_SIMP_TAC[IMAGE_SUBSET; FORALL_IN_IMAGE] THEN REPEAT CONJ_TAC THENL
+   [REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+           ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON]) THEN
+    ASM_REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID];
+    REWRITE_TAC[IMAGE_o] THEN MATCH_MP_TAC IMAGE_SUBSET THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o ONCE_DEPTH_CONV)
+     [GSYM IMAGE_o] THEN
+    ASM_REWRITE_TAC[o_DEF; IMAGE_ID];
+    ASM_SIMP_TAC[o_DEF]]);;
+
+let RETRACT_OF_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+        ==> ((IMAGE f t) retract_of (IMAGE f s) <=> t retract_of s)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN EQ_TAC THENL
+   [DISCH_TAC; ASM_MESON_TAC[RETRACT_OF_INJECTIVE_LINEAR_IMAGE]] THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `h:real^N->real^M` STRIP_ASSUME_TAC o
+        MATCH_MP LINEAR_BIJECTIVE_LEFT_RIGHT_INVERSE) THEN
+  SUBGOAL_THEN
+   `!s. s = IMAGE (h:real^N->real^M) (IMAGE (f:real^M->real^N) s)`
+   (fun th -> ONCE_REWRITE_TAC[th]) THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC RETRACT_OF_INJECTIVE_LINEAR_IMAGE THEN
+  ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]);;
+
+add_linear_invariants [RETRACT_OF_LINEAR_IMAGE_EQ];;
+
+let RETRACTION_REFL = prove
+ (`!s. retraction (s,s) (\x. x)`,
+  REWRITE_TAC[retraction; IMAGE_ID; SUBSET_REFL; CONTINUOUS_ON_ID]);;
+
+let RETRACT_OF_REFL = prove
+ (`!s. s retract_of s`,
+  REWRITE_TAC[retract_of] THEN MESON_TAC[RETRACTION_REFL]);;
+
+let RETRACT_OF_IMP_SUBSET = prove
+ (`!s t. s retract_of t ==> s SUBSET t`,
+  SIMP_TAC[retract_of; retraction] THEN MESON_TAC[]);;
+
+let RETRACT_OF_EMPTY = prove
+ (`(!s:real^N->bool. {} retract_of s <=> s = {}) /\
+   (!s:real^N->bool. s retract_of {} <=> s = {})`,
+  REWRITE_TAC[retract_of; retraction; SUBSET_EMPTY; IMAGE_CLAUSES] THEN
+  CONJ_TAC THEN X_GEN_TAC `s:real^N->bool` THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[NOT_IN_EMPTY; IMAGE_EQ_EMPTY; CONTINUOUS_ON_EMPTY;
+                  SUBSET_REFL]);;
+
+let RETRACT_OF_SING = prove
+ (`!s x:real^N. {x} retract_of s <=> x IN s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[retract_of; RETRACTION] THEN EQ_TAC THENL
+   [SET_TAC[]; ALL_TAC] THEN
+  DISCH_TAC THEN EXISTS_TAC `(\y. x):real^N->real^N` THEN
+  REWRITE_TAC[CONTINUOUS_ON_CONST] THEN ASM SET_TAC[]);;
+
+let RETRACTION_o = prove
+ (`!f g s t u:real^N->bool.
+        retraction (s,t) f /\ retraction (t,u) g
+        ==> retraction (s,u) (g o f)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[retraction] THEN REPEAT STRIP_TAC THENL
+   [ASM SET_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+    REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[];
+    REWRITE_TAC[o_THM] THEN ASM SET_TAC[]]);;
+
+let RETRACT_OF_TRANS = prove
+ (`!s t u:real^N->bool.
+        s retract_of t /\ t retract_of u ==> s retract_of u`,
+  REWRITE_TAC[retract_of] THEN MESON_TAC[RETRACTION_o]);;
+
+let CLOSED_IN_RETRACT = prove
+ (`!s t:real^N->bool.
+        s retract_of t ==> closed_in (subtopology euclidean t) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[retract_of; retraction] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real^N->real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `s = {x:real^N | x IN t /\ lift(norm(r x - x)) = vec 0}`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[GSYM DROP_EQ; DROP_VEC; LIFT_DROP; NORM_EQ_0] THEN
+    REWRITE_TAC[VECTOR_SUB_EQ] THEN ASM SET_TAC[];
+    MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE_CONSTANT THEN
+    MATCH_MP_TAC CONTINUOUS_ON_LIFT_NORM_COMPOSE THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUB THEN ASM_SIMP_TAC[CONTINUOUS_ON_ID]]);;
+
+let RETRACT_OF_CONTRACTIBLE = prove
+ (`!s t:real^N->bool. contractible t /\ s retract_of t ==> contractible s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[contractible; retract_of] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (X_CHOOSE_TAC `r:real^N->real^N`)) THEN
+  SIMP_TAC[HOMOTOPIC_WITH; PCROSS; LEFT_IMP_EXISTS_THM] THEN
+  FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [retraction]) THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `h:real^(1,N)finite_sum->real^N`] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; FORALL_IN_IMAGE]) THEN
+  STRIP_TAC THEN MAP_EVERY EXISTS_TAC
+   [`(r:real^N->real^N) a`;
+    `(r:real^N->real^N) o (h:real^(1,N)finite_sum->real^N)`] THEN
+  ASM_SIMP_TAC[o_THM; IMAGE_o; SUBSET] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP(REWRITE_RULE[IMP_CONJ]
+           CONTINUOUS_ON_SUBSET)) THEN ASM SET_TAC[];
+    ASM SET_TAC[]]);;
+
+let RETRACT_OF_COMPACT = prove
+ (`!s t:real^N->bool. compact t /\ s retract_of t ==> compact s`,
+  REWRITE_TAC[retract_of; RETRACTION] THEN
+  MESON_TAC[COMPACT_CONTINUOUS_IMAGE]);;
+
+let RETRACT_OF_CLOSED = prove
+ (`!s t. closed t /\ s retract_of t ==> closed t`,
+  MESON_TAC[CLOSED_IN_CLOSED_EQ; CLOSED_IN_RETRACT]);;
+
+let RETRACT_OF_CONNECTED = prove
+ (`!s t:real^N->bool. connected t /\ s retract_of t ==> connected s`,
+  REWRITE_TAC[retract_of; RETRACTION] THEN
+  MESON_TAC[CONNECTED_CONTINUOUS_IMAGE]);;
+
+let RETRACT_OF_PATH_CONNECTED = prove
+ (`!s t:real^N->bool. path_connected t /\ s retract_of t ==> path_connected s`,
+  REWRITE_TAC[retract_of; RETRACTION] THEN
+  MESON_TAC[PATH_CONNECTED_CONTINUOUS_IMAGE]);;
+
+let RETRACT_OF_SIMPLY_CONNECTED = prove
+ (`!s t:real^N->bool.
+       simply_connected t /\ s retract_of t ==> simply_connected s`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ]
+   (REWRITE_RULE[CONJ_ASSOC] SIMPLY_CONNECTED_RETRACTION_GEN)) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [retract_of]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `r:real^N->real^N` THEN
+  REWRITE_TAC[RETRACTION] THEN STRIP_TAC THEN EXISTS_TAC `\x:real^N. x` THEN
+  ASM_REWRITE_TAC[IMAGE_ID; CONTINUOUS_ON_ID]);;
+
+let RETRACT_OF_HOMOTOPICALLY_TRIVIAL = prove
+ (`!s t:real^N->bool u:real^M->bool.
+        t retract_of s /\
+        (!f g. f continuous_on u /\ IMAGE f u SUBSET s /\
+               g continuous_on u /\ IMAGE g u SUBSET s
+               ==> homotopic_with (\x. T) (u,s)  f g)
+        ==> (!f g. f continuous_on u /\ IMAGE f u SUBSET t /\
+                   g continuous_on u /\ IMAGE g u SUBSET t
+                   ==> homotopic_with (\x. T) (u,t) f g)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q /\ r /\ s <=> p /\ q /\ T /\ r /\ s /\ T`] THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ]
+    HOMOTOPICALLY_TRIVIAL_RETRACTION_GEN) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [retract_of]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `r:real^N->real^N` THEN
+  REWRITE_TAC[RETRACTION] THEN STRIP_TAC THEN EXISTS_TAC `\x:real^N. x` THEN
+  ASM_REWRITE_TAC[CONTINUOUS_ON_ID; IMAGE_ID]);;
+
+let RETRACT_OF_HOMOTOPICALLY_TRIVIAL_NULL = prove
+ (`!s t:real^N->bool u:real^M->bool.
+        t retract_of s /\
+        (!f. f continuous_on u /\ IMAGE f u SUBSET s
+             ==> ?c. homotopic_with (\x. T) (u,s) f (\x. c))
+        ==> (!f. f continuous_on u /\ IMAGE f u SUBSET t
+                 ==> ?c. homotopic_with (\x. T) (u,t) f (\x. c))`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q <=> p /\ q /\ T`] THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ]
+    HOMOTOPICALLY_TRIVIAL_RETRACTION_NULL_GEN) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [retract_of]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `r:real^N->real^N` THEN
+  REWRITE_TAC[RETRACTION] THEN STRIP_TAC THEN EXISTS_TAC `\x:real^N. x` THEN
+  ASM_REWRITE_TAC[CONTINUOUS_ON_ID; IMAGE_ID]);;
+
+let RETRACT_OF_COHOMOTOPICALLY_TRIVIAL = prove
+ (`!s t:real^N->bool u:real^M->bool.
+        t retract_of s /\
+        (!f g. f continuous_on s /\ IMAGE f s SUBSET u /\
+               g continuous_on s /\ IMAGE g s SUBSET u
+               ==> homotopic_with (\x. T) (s,u)  f g)
+        ==> (!f g. f continuous_on t /\ IMAGE f t SUBSET u /\
+                   g continuous_on t /\ IMAGE g t SUBSET u
+                   ==> homotopic_with (\x. T) (t,u) f g)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q /\ r /\ s <=> p /\ q /\ T /\ r /\ s /\ T`] THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ]
+    COHOMOTOPICALLY_TRIVIAL_RETRACTION_GEN) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [retract_of]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `r:real^N->real^N` THEN
+  REWRITE_TAC[RETRACTION] THEN STRIP_TAC THEN EXISTS_TAC `\x:real^N. x` THEN
+  ASM_REWRITE_TAC[CONTINUOUS_ON_ID; IMAGE_ID]);;
+
+let RETRACT_OF_COHOMOTOPICALLY_TRIVIAL_NULL = prove
+ (`!s t:real^N->bool u:real^M->bool.
+        t retract_of s /\
+        (!f. f continuous_on s /\ IMAGE f s SUBSET u
+             ==> ?c. homotopic_with (\x. T) (s,u) f (\x. c))
+        ==> (!f. f continuous_on t /\ IMAGE f t SUBSET u
+                 ==> ?c. homotopic_with (\x. T) (t,u) f (\x. c))`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q <=> p /\ q /\ T`] THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ]
+    COHOMOTOPICALLY_TRIVIAL_RETRACTION_NULL_GEN) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [retract_of]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `r:real^N->real^N` THEN
+  REWRITE_TAC[RETRACTION] THEN STRIP_TAC THEN EXISTS_TAC `\x:real^N. x` THEN
+  ASM_REWRITE_TAC[CONTINUOUS_ON_ID; IMAGE_ID]);;
+
+let RETRACTION_IMP_QUOTIENT_MAP = prove
+ (`!r s t:real^N->bool.
+    retraction (s,t) r
+    ==> !u. u SUBSET t
+            ==> (open_in (subtopology euclidean s) {x | x IN s /\ r x IN u} <=>
+                 open_in (subtopology euclidean t) u)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[RETRACTION] THEN STRIP_TAC THEN
+  MATCH_MP_TAC CONTINUOUS_RIGHT_INVERSE_IMP_QUOTIENT_MAP THEN
+  EXISTS_TAC `\x:real^N. x` THEN
+  ASM_REWRITE_TAC[CONTINUOUS_ON_ID; SUBSET_REFL; IMAGE_ID]);;
+
+let RETRACT_OF_LOCALLY_CONNECTED = prove
+ (`!s t:real^N->bool.
+        s retract_of t /\ locally connected t ==> locally connected s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[retract_of] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM o el 2 o CONJUNCTS o GEN_REWRITE_RULE I
+   [RETRACTION]) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LOCALLY_CONNECTED_QUOTIENT_IMAGE) THEN
+  MATCH_MP_TAC RETRACTION_IMP_QUOTIENT_MAP THEN
+  ASM_MESON_TAC[RETRACTION]);;
+
+let RETRACT_OF_LOCALLY_PATH_CONNECTED = prove
+ (`!s t:real^N->bool.
+        s retract_of t /\ locally path_connected t
+        ==> locally path_connected s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[retract_of] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM o el 2 o CONJUNCTS o GEN_REWRITE_RULE I
+   [RETRACTION]) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ]
+    LOCALLY_PATH_CONNECTED_QUOTIENT_IMAGE) THEN
+  MATCH_MP_TAC RETRACTION_IMP_QUOTIENT_MAP THEN
+  ASM_MESON_TAC[RETRACTION]);;
+
+let RETRACT_OF_LOCALLY_COMPACT = prove
+ (`!s t:real^N->bool.
+        locally compact s /\ t retract_of s ==> locally compact t`,
+  MESON_TAC[CLOSED_IN_RETRACT; LOCALLY_COMPACT_CLOSED_IN]);;
+
+let ABSOLUTE_RETRACTION_CONVEX_CLOSED_RELATIVE = prove
+ (`!s:real^N->bool t.
+        convex s /\ closed s /\ ~(s = {}) /\ s SUBSET t
+        ==> ?r. retraction (t,s) r /\
+                !x. x IN (affine hull s) DIFF (relative_interior s)
+                    ==> r(x) IN relative_frontier s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[retraction] THEN
+  EXISTS_TAC `closest_point(s:real^N->bool)` THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_CLOSEST_POINT; CLOSEST_POINT_SELF] THEN
+  ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; CLOSEST_POINT_IN_SET] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSEST_POINT_IN_RELATIVE_FRONTIER THEN
+  ASM_MESON_TAC[SUBSET; RELATIVE_INTERIOR_SUBSET]);;
+
+let ABSOLUTE_RETRACTION_CONVEX_CLOSED = prove
+ (`!s:real^N->bool t.
+        convex s /\ closed s /\ ~(s = {}) /\ s SUBSET t
+        ==> ?r. retraction (t,s) r /\
+                (!x. ~(x IN s) ==> r(x) IN frontier s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[retraction] THEN
+  EXISTS_TAC `closest_point(s:real^N->bool)` THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_CLOSEST_POINT; CLOSEST_POINT_SELF] THEN
+  ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; CLOSEST_POINT_IN_SET] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSEST_POINT_IN_FRONTIER THEN
+  ASM_MESON_TAC[SUBSET; INTERIOR_SUBSET]);;
+
+let ABSOLUTE_RETRACT_CONVEX_CLOSED = prove
+ (`!s:real^N->bool t.
+        convex s /\ closed s /\ ~(s = {}) /\ s SUBSET t
+        ==> s retract_of t`,
+  REWRITE_TAC[retract_of] THEN MESON_TAC[ABSOLUTE_RETRACTION_CONVEX_CLOSED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A neighbourhood retract is an ANR for Euclidean space.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let NEIGHBOURHOOD_RETRACT_IMP_ANR = prove
+ (`!s:real^M->bool s':real^N->bool t u.
+        s retract_of t /\ open t /\ s homeomorphic s' /\ s' SUBSET u
+        ==> ?t'. open_in (subtopology euclidean u) t' /\ s' retract_of t'`,
+  MAP_EVERY X_GEN_TAC
+   [`X:real^M->bool`; `Y:real^N->bool`; `U:real^M->bool`;
+    `K:real^N->bool`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `locally compact (Y:real^N->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[RETRACT_OF_LOCALLY_COMPACT;
+                  OPEN_IMP_LOCALLY_COMPACT; HOMEOMORPHIC_LOCAL_COMPACTNESS];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?W:real^N->bool.
+        open_in (subtopology euclidean K) W /\
+        closed_in (subtopology euclidean W) Y`
+  STRIP_ASSUME_TAC THENL
+   [FIRST_ASSUM(X_CHOOSE_THEN `W:real^N->bool` STRIP_ASSUME_TAC o
+        MATCH_MP LOCALLY_COMPACT_CLOSED_IN_OPEN) THEN
+    EXISTS_TAC `K INTER W:real^N->bool` THEN
+    ASM_SIMP_TAC[OPEN_IN_OPEN_INTER; CLOSED_IN_CLOSED] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CLOSED_IN_CLOSED]) THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homeomorphic]) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN MAP_EVERY X_GEN_TAC
+   [`f:real^M->real^N`; `g:real^N->real^M`] THEN
+  REWRITE_TAC[homeomorphism] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`g:real^N->real^M`; `W:real^N->bool`; `Y:real^N->bool`]
+        TIETZE_UNBOUNDED) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^N->real^M` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `{x | x IN W /\ (h:real^N->real^M) x IN U}` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC OPEN_IN_TRANS THEN EXISTS_TAC `W:real^N->bool` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN THEN
+    EXISTS_TAC `(:real^M)` THEN
+    ASM_REWRITE_TAC[SUBTOPOLOGY_UNIV; GSYM OPEN_IN; SUBSET_UNIV];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [retract_of]) THEN
+  REWRITE_TAC[retraction; retract_of; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `r:real^M->real^M` THEN STRIP_TAC THEN
+  EXISTS_TAC `(f:real^M->real^N) o r o (h:real^N->real^M)` THEN
+  SUBGOAL_THEN
+   `(W:real^N->bool) SUBSET K /\ Y SUBSET W`
+  STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[OPEN_IN_IMP_SUBSET; CLOSED_IN_IMP_SUBSET]; ALL_TAC] THEN
+  REWRITE_TAC[IMAGE_o; o_THM] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC) THEN
+  REWRITE_TAC[IMAGE_o] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+  ASM SET_TAC[]);;
+
+let NEIGHBOURHOOD_RETRACT_IMP_ANR_UNIV = prove
+ (`!s:real^M->bool s':real^N->bool t.
+        s retract_of t /\ open t /\ s homeomorphic s'
+        ==> ?t'. open t' /\ s' retract_of t'`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[OPEN_IN] THEN
+  ONCE_REWRITE_TAC[GSYM SUBTOPOLOGY_UNIV] THEN
+  MATCH_MP_TAC NEIGHBOURHOOD_RETRACT_IMP_ANR THEN
+  ASM_MESON_TAC[SUBSET_UNIV]);;
+
+let HOMEOMORPHIC_ANRNESS = prove
+ (`!s:real^M->bool t:real^N->bool.
+      s homeomorphic t
+      ==> ((?u. open u /\ s retract_of u) <=> (?u. open u /\ t retract_of u))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+   [MP_TAC(ISPECL [`s:real^M->bool`; `t:real^N->bool`]
+        NEIGHBOURHOOD_RETRACT_IMP_ANR_UNIV);
+    MP_TAC(ISPECL [`t:real^N->bool`; `s:real^M->bool`]
+        NEIGHBOURHOOD_RETRACT_IMP_ANR_UNIV)] THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_MP_TAC THEN
+  ASM_MESON_TAC[HOMEOMORPHIC_SYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Likewise for ARs, at least given closedness.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let ABSOLUTE_RETRACT_IMP_AR_GEN = prove
+ (`!s:real^M->bool s':real^N->bool t u.
+      s retract_of t /\ convex t /\ closed t /\ ~(t = {}) /\
+      s homeomorphic s' /\ closed_in (subtopology euclidean u) s'
+      ==> s' retract_of u`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homeomorphic]) THEN
+  REWRITE_TAC[homeomorphism; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`f:real^M->real^N`; `g:real^N->real^M`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`g:real^N->real^M`; `u:real^N->bool`; `s':real^N->bool`]
+        TIETZE_UNBOUNDED) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `h:real^N->real^M` THEN STRIP_TAC THEN
+  SUBGOAL_THEN `s retract_of (:real^M)` MP_TAC THENL
+   [MATCH_MP_TAC RETRACT_OF_TRANS THEN EXISTS_TAC `t:real^M->bool` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC ABSOLUTE_RETRACT_CONVEX_CLOSED THEN
+    ASM_REWRITE_TAC[SUBSET_UNIV];
+    REWRITE_TAC[retract_of; retraction; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `r:real^M->real^M` THEN STRIP_TAC THEN
+    EXISTS_TAC `(f:real^M->real^N) o r o (h:real^N->real^M)` THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN
+    ASM_REWRITE_TAC[IMAGE_o; o_THM] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC) THEN
+    REWRITE_TAC[IMAGE_o] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      CONTINUOUS_ON_SUBSET)) THEN
+    ASM SET_TAC[]]);;
+
+let ABSOLUTE_RETRACT_IMP_AR = prove
+ (`!s s'. s retract_of (:real^M) /\ s homeomorphic s' /\ closed s'
+          ==> s' retract_of (:real^N)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ABSOLUTE_RETRACT_IMP_AR_GEN THEN
+  MAP_EVERY EXISTS_TAC [`s:real^M->bool`; `(:real^M)`] THEN
+  ASM_REWRITE_TAC[SUBTOPOLOGY_UNIV; GSYM CLOSED_IN] THEN
+  REWRITE_TAC[CONVEX_UNIV; CLOSED_UNIV; UNIV_NOT_EMPTY]);;
+
+let HOMEOMORPHIC_COMPACT_ARNESS = prove
+ (`!s s'. s homeomorphic s'
+          ==> (compact s /\ s retract_of (:real^M) <=>
+               compact s' /\ s' retract_of (:real^N))`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `compact(s:real^M->bool) /\ compact(s':real^N->bool)` THENL
+   [ALL_TAC; ASM_MESON_TAC[HOMEOMORPHIC_COMPACTNESS]] THEN
+  ASM_REWRITE_TAC[] THEN EQ_TAC THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] ABSOLUTE_RETRACT_IMP_AR) THEN
+  ASM_MESON_TAC[HOMEOMORPHIC_SYM; COMPACT_IMP_CLOSED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More retract properties including connection of complements.              *)
+(* ------------------------------------------------------------------------- *)
+
+let ABSOLUTE_RETRACT_HOMEOMORPHIC_CONVEX_COMPACT = prove
+ (`!s:real^N->bool t u:real^M->bool.
+        s homeomorphic u /\ ~(s = {}) /\ s SUBSET t /\ convex u /\ compact u
+        ==> s retract_of t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC RETRACT_OF_SUBSET THEN
+  EXISTS_TAC `(:real^N)` THEN ASM_REWRITE_TAC[SUBSET_UNIV] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HOMEOMORPHIC_COMPACT_ARNESS) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HOMEOMORPHIC_COMPACTNESS) THEN
+  ASM_SIMP_TAC[] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC ABSOLUTE_RETRACT_CONVEX_CLOSED THEN
+  ASM_MESON_TAC[COMPACT_IMP_CLOSED; HOMEOMORPHIC_EMPTY; SUBSET_UNIV]);;
+
+let ABSOLUTE_RETRACT_PATH_IMAGE_ARC = prove
+ (`!g s:real^N->bool.
+        arc g /\ path_image g SUBSET s ==> (path_image g) retract_of s`,
+  REPEAT STRIP_TAC THEN MP_TAC
+   (ISPECL [`path_image g:real^N->bool`; `s:real^N->bool`;
+            `interval[vec 0:real^1,vec 1:real^1]`]
+        ABSOLUTE_RETRACT_HOMEOMORPHIC_CONVEX_COMPACT) THEN
+  DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[PATH_IMAGE_NONEMPTY] THEN
+  REWRITE_TAC[COMPACT_INTERVAL; CONVEX_INTERVAL] THEN
+  ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+  MATCH_MP_TAC HOMEOMORPHIC_COMPACT THEN
+  EXISTS_TAC `g:real^1->real^N` THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[arc; path; path_image]) THEN
+  ASM_REWRITE_TAC[COMPACT_INTERVAL; path_image]);;
+
+let RELATIVE_BOUNDARY_RETRACT_OF_PUNCTURED_AFFINE_HULL = prove
+ (`!s a:real^N.
+        convex s /\ compact s /\ a IN relative_interior s
+        ==> (s DIFF relative_interior s) retract_of
+            ((affine hull s) DELETE a)`,
+  REPEAT GEN_TAC THEN GEOM_ORIGIN_TAC `a:real^N` THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `vec 0:real^N`]
+    RAY_TO_RELATIVE_FRONTIER) THEN
+  REWRITE_TAC[relative_frontier] THEN
+  ASM_SIMP_TAC[VECTOR_ADD_LID; RIGHT_IMP_EXISTS_THM; COMPACT_IMP_BOUNDED;
+               CLOSURE_CLOSED; COMPACT_IMP_CLOSED] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[TAUT `p ==> q /\ r <=> (p ==> q) /\ (p ==> r)`] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN
+  X_GEN_TAC `dd:real^N->real` THEN STRIP_TAC THEN
+  REWRITE_TAC[retract_of; retraction] THEN
+  EXISTS_TAC `\x:real^N. dd x % x` THEN REPEAT CONJ_TAC THENL
+   [MP_TAC(ISPECL [`affine:(real^N->bool)->bool`; `s:real^N->bool`]
+        HULL_SUBSET) THEN ASM SET_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ON_COMPACT_SURFACE_PROJECTION THEN
+    EXISTS_TAC `s DIFF relative_interior s:real^N->bool` THEN
+    ASM_SIMP_TAC[COMPACT_RELATIVE_BOUNDARY] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC(SET_RULE
+       `s SUBSET t /\ z IN s' ==> s DIFF s' SUBSET t DELETE z`) THEN
+      ASM_REWRITE_TAC[HULL_SUBSET];
+      MATCH_MP_TAC(MESON[AFFINE_EQ_SUBSPACE; SUBSPACE_IMP_CONIC]
+       `affine s /\ vec 0 IN s ==> conic s`) THEN
+      REWRITE_TAC[AFFINE_AFFINE_HULL] THEN
+      ASM_MESON_TAC[HULL_INC; SUBSET; RELATIVE_INTERIOR_SUBSET];
+      MAP_EVERY X_GEN_TAC [`x:real^N`; `k:real`] THEN
+      REWRITE_TAC[IN_DELETE; IN_DIFF] THEN STRIP_TAC THEN EQ_TAC THENL
+       [STRIP_TAC; ASM_MESON_TAC[IN_DIFF]] THEN
+      MATCH_MP_TAC(REAL_ARITH `~(a < b) /\ ~(b < a) ==> a = b`) THEN
+      CONJ_TAC THEN DISCH_TAC THENL
+       [ALL_TAC; ASM_MESON_TAC[REAL_LT_IMP_LE]] THEN
+      MP_TAC(ISPECL [`s:real^N->bool`; `vec 0:real^N`; `k % x:real^N`]
+        IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SEGMENT) THEN
+      ASM_SIMP_TAC[COMPACT_IMP_CLOSED; CLOSURE_CLOSED] THEN
+      REWRITE_TAC[SUBSET; IN_SEGMENT; NOT_FORALL_THM] THEN
+      EXISTS_TAC `dd(x) % x:real^N` THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_DIFF]) THEN ASM_SIMP_TAC[] THEN
+      ONCE_REWRITE_TAC[EQ_SYM_EQ] THEN
+      ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ] THEN
+      EXISTS_TAC `(dd:real^N->real) x / k` THEN
+      ASM_SIMP_TAC[REAL_LT_DIV; VECTOR_MUL_RZERO; VECTOR_ADD_LID;
+                   REAL_LT_LDIV_EQ; VECTOR_MUL_ASSOC; REAL_MUL_LID;
+                   REAL_DIV_RMUL; REAL_LT_IMP_NZ]];
+    ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_DELETE; IN_UNIV];
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+    SUBGOAL_THEN `x IN affine hull s /\ ~(x:real^N = vec 0)`
+    STRIP_ASSUME_TAC THENL
+      [MP_TAC(ISPECL [`affine:(real^N->bool)->bool`; `s:real^N->bool`]
+        HULL_SUBSET) THEN ASM SET_TAC[];
+       REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`)) THEN
+       ASM_REWRITE_TAC[IN_DIFF] THEN REPEAT STRIP_TAC] THEN
+    SUBGOAL_THEN `(dd:real^N->real) x = &1`
+     (fun th -> REWRITE_TAC[th; VECTOR_MUL_LID]) THEN
+    MATCH_MP_TAC(REAL_ARITH `~(d < &1) /\ ~(&1 < d) ==> d = &1`) THEN
+    CONJ_TAC THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`s:real^N->bool`; `vec 0:real^N`]
+        IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SEGMENT)
+    THENL
+     [DISCH_THEN(MP_TAC o SPEC `x:real^N`);
+      DISCH_THEN(MP_TAC o SPEC `(dd x) % x:real^N`)] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_DIFF]) THEN
+    ASM_SIMP_TAC[CLOSURE_CLOSED; COMPACT_IMP_CLOSED] THEN
+    REWRITE_TAC[SUBSET; IN_SEGMENT; NOT_FORALL_THM; NOT_IMP] THEN
+    REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THENL
+     [EXISTS_TAC `dd x % x:real^N` THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[];
+      EXISTS_TAC `x:real^N` THEN
+      ASM_SIMP_TAC[VECTOR_ARITH `vec 0 = a % x <=> a % x:real^N = vec 0`] THEN
+      ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ] THEN
+      EXISTS_TAC `inv((dd:real^N->real) x)` THEN
+      ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; REAL_LT_IMP_NZ] THEN
+      ASM_SIMP_TAC[VECTOR_MUL_LID; REAL_LT_INV_EQ; REAL_INV_LT_1]]]);;
+
+let RELATIVE_FRONTIER_RETRACT_OF_PUNCTURED_AFFINE_HULL = prove
+ (`!s a:real^N.
+        convex s /\ bounded s /\ a IN relative_interior s
+        ==> relative_frontier s retract_of (affine hull s) DELETE a`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`closure s:real^N->bool`; `a:real^N`]
+        RELATIVE_BOUNDARY_RETRACT_OF_PUNCTURED_AFFINE_HULL) THEN
+  ASM_SIMP_TAC[COMPACT_CLOSURE; CONVEX_CLOSURE; relative_frontier;
+               CONVEX_RELATIVE_INTERIOR_CLOSURE; AFFINE_HULL_CLOSURE]);;
+
+let ANR_RELATIVE_FRONTIER_CONVEX = prove
+ (`!s:real^N->bool.
+        bounded s /\ convex s
+        ==> ?t. open t /\ (relative_frontier s) retract_of t`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[RELATIVE_FRONTIER_EMPTY] THENL
+   [ASM_MESON_TAC[RETRACT_OF_REFL; OPEN_EMPTY]; ALL_TAC] THEN
+  SUBGOAL_THEN `~(relative_interior s:real^N->bool = {})` MP_TAC THENL
+   [ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY]; ALL_TAC] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+  EXISTS_TAC `{x | x IN (:real^N) /\
+                   closest_point (affine hull s) x IN
+                   ((:real^N) DELETE a)}` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[OPEN_IN] THEN ONCE_REWRITE_TAC[GSYM SUBTOPOLOGY_UNIV] THEN
+    MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN THEN
+    EXISTS_TAC `(:real^N)` THEN
+    SIMP_TAC[OPEN_IN_DELETE; OPEN_IN_REFL; SUBSET_UNIV; ETA_AX];
+    MATCH_MP_TAC RETRACT_OF_TRANS THEN
+    EXISTS_TAC `(affine hull s) DELETE (a:real^N)` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC RELATIVE_FRONTIER_RETRACT_OF_PUNCTURED_AFFINE_HULL THEN
+      ASM_REWRITE_TAC[];
+      REWRITE_TAC[retract_of; retraction] THEN
+      EXISTS_TAC `closest_point (affine hull s:real^N->bool)` THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_DELETE] THEN
+      ASM_SIMP_TAC[IN_ELIM_THM; IN_UNIV; CLOSEST_POINT_SELF;
+                   CLOSEST_POINT_IN_SET; AFFINE_HULL_EQ_EMPTY;
+                   CLOSED_AFFINE_HULL]]] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_CLOSEST_POINT THEN
+  ASM_SIMP_TAC[AFFINE_IMP_CONVEX; AFFINE_AFFINE_HULL;
+               CLOSED_AFFINE_HULL; AFFINE_HULL_EQ_EMPTY]);;
+
+let FRONTIER_RETRACT_OF_PUNCTURED_UNIVERSE = prove
+ (`!s a. convex s /\ bounded s /\ a IN interior s
+         ==> (frontier s) retract_of ((:real^N) DELETE a)`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP (SET_RULE
+   `a IN s ==> ~(s = {})`)) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `a:real^N`]
+        RELATIVE_FRONTIER_RETRACT_OF_PUNCTURED_AFFINE_HULL) THEN
+  ASM_SIMP_TAC[RELATIVE_FRONTIER_NONEMPTY_INTERIOR;
+               RELATIVE_INTERIOR_NONEMPTY_INTERIOR;
+               AFFINE_HULL_NONEMPTY_INTERIOR]);;
+
+let SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE_GEN = prove
+ (`!a r b:real^N.
+      b IN ball(a,r) ==> sphere(a,r) retract_of ((:real^N) DELETE b)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM FRONTIER_CBALL] THEN
+  MATCH_MP_TAC FRONTIER_RETRACT_OF_PUNCTURED_UNIVERSE THEN
+  ASM_REWRITE_TAC[CONVEX_CBALL; BOUNDED_CBALL; INTERIOR_CBALL]);;
+
+let SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE = prove
+ (`!a r. &0 < r ==> sphere(a,r) retract_of ((:real^N) DELETE a)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE_GEN THEN
+  ASM_REWRITE_TAC[CENTRE_IN_BALL]);;
+
+let RETRACT_OF_PCROSS = prove
+ (`!s:real^M->bool s' t:real^N->bool t'.
+        s retract_of s' /\ t retract_of t'
+        ==> (s PCROSS t) retract_of (s' PCROSS t')`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[PCROSS] THEN
+  REWRITE_TAC[retract_of; retraction; SUBSET; FORALL_IN_IMAGE] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `f:real^M->real^M` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `g:real^N->real^N` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `\z. pastecart ((f:real^M->real^M) (fstcart z))
+                            ((g:real^N->real^N) (sndcart z))` THEN
+  REWRITE_TAC[FORALL_PASTECART; IN_ELIM_PASTECART_THM] THEN
+  ASM_SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+  CONJ_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+   CONTINUOUS_ON_SUBSET)) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+  SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART]);;
+
+let LOCALLY_PATH_CONNECTED_SPHERE_GEN = prove
+ (`!s:real^N->bool.
+       bounded s /\ convex s ==> locally path_connected (relative_frontier s)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `relative_interior(s:real^N->bool) = {}` THENL
+   [UNDISCH_TAC `relative_interior(s:real^N->bool) = {}` THEN
+    ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY] THEN
+    REWRITE_TAC[LOCALLY_EMPTY; RELATIVE_FRONTIER_EMPTY];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+    MATCH_MP_TAC RETRACT_OF_LOCALLY_PATH_CONNECTED THEN
+    EXISTS_TAC `(affine hull s) DELETE (a:real^N)` THEN
+    ASM_SIMP_TAC[RELATIVE_FRONTIER_RETRACT_OF_PUNCTURED_AFFINE_HULL] THEN
+    MATCH_MP_TAC LOCALLY_OPEN_SUBSET THEN
+    EXISTS_TAC `affine hull s:real^N->bool` THEN
+    SIMP_TAC[OPEN_IN_DELETE; OPEN_IN_REFL] THEN
+    SIMP_TAC[CONVEX_IMP_LOCALLY_PATH_CONNECTED; AFFINE_IMP_CONVEX;
+             AFFINE_AFFINE_HULL]]);;
+
+let LOCALLY_CONNECTED_SPHERE_GEN = prove
+ (`!s:real^N->bool.
+       bounded s /\ convex s ==> locally connected (relative_frontier s)`,
+  SIMP_TAC[LOCALLY_PATH_CONNECTED_SPHERE_GEN;
+           LOCALLY_PATH_CONNECTED_IMP_LOCALLY_CONNECTED]);;
+
+let LOCALLY_PATH_CONNECTED_SPHERE = prove
+ (`!a:real^N r. locally path_connected (sphere(a,r))`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPEC `cball(a:real^N,r)` LOCALLY_PATH_CONNECTED_SPHERE_GEN) THEN
+  MP_TAC(ISPECL [`a:real^N`; `r:real`] RELATIVE_FRONTIER_CBALL) THEN
+  COND_CASES_TAC THEN
+  ASM_SIMP_TAC[SPHERE_SING; LOCALLY_SING; PATH_CONNECTED_SING;
+               BOUNDED_CBALL; CONVEX_CBALL]);;
+
+let LOCALLY_CONNECTED_SPHERE = prove
+ (`!a:real^N r. locally connected(sphere(a,r))`,
+  SIMP_TAC[LOCALLY_PATH_CONNECTED_SPHERE;
+           LOCALLY_PATH_CONNECTED_IMP_LOCALLY_CONNECTED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Extending a function into an ANR.                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let NEIGHBOURHOOD_EXTENSION_INTO_ANR_LOCAL = prove
+ (`!f:real^M->real^N c s t u.
+        f continuous_on c /\ IMAGE f c SUBSET t /\ open u /\ t retract_of u /\
+        closed_in (subtopology euclidean s) c
+        ==> ?v g. c SUBSET v /\ open_in (subtopology euclidean s) v /\
+                  g continuous_on v /\ IMAGE g v SUBSET t /\
+                  !x. x IN c ==> g x = f x`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `s:real^M->bool`; `c:real^M->bool`]
+        TIETZE_UNBOUNDED) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `g:real^M->real^N` THEN STRIP_TAC THEN
+  EXISTS_TAC `{x | x IN s /\ (g:real^M->real^N) x IN u}` THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [retract_of]) THEN
+  REWRITE_TAC[retraction] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real^N->real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(r:real^N->real^N) o (g:real^M->real^N)` THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN
+  REPEAT CONJ_TAC THENL
+   [ASM SET_TAC[];
+    MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE THEN ASM_REWRITE_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN ASM SET_TAC[];
+    REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[];
+    REWRITE_TAC[o_THM] THEN ASM SET_TAC[]]);;
+
+let NEIGHBOURHOOD_EXTENSION_INTO_ANR = prove
+ (`!f:real^M->real^N s t u.
+        f continuous_on s /\ IMAGE f s SUBSET t /\ open u /\ t retract_of u /\
+        closed s
+        ==> ?v g. s SUBSET v /\ open v /\ g continuous_on v /\
+                  IMAGE g v SUBSET t /\ !x. x IN s ==> g x = f x`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL
+   [`f:real^M->real^N`; `s:real^M->bool`; `(:real^M)`; `t:real^N->bool`;
+    `u:real^N->bool`] NEIGHBOURHOOD_EXTENSION_INTO_ANR_LOCAL) THEN
+  REWRITE_TAC[GSYM OPEN_IN; GSYM CLOSED_IN; SUBTOPOLOGY_UNIV]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Borsuk homotopy extension thorem. It's only this late so we can use the   *)
+(* concept of retraction, essentially that the range is an ANR.              *)
+(* ------------------------------------------------------------------------- *)
+
+let BORSUK_HOMOTOPY_EXTENSION = prove
+ (`!f:real^M->real^N g s t u v.
+        closed s /\ closed t /\ u retract_of v /\ open v /\
+        f continuous_on t /\ IMAGE f t SUBSET u /\
+        g continuous_on s /\ IMAGE g s SUBSET u /\
+        homotopic_with (\x. T) (s,u) f g
+        ==> ?g'. g' continuous_on t /\ IMAGE g' t SUBSET u /\
+                 !x. x IN s ==> g'(x) = g(x)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopic_with]) THEN
+  REWRITE_TAC[PCROSS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^(1,M)finite_sum->real^N`
+    STRIP_ASSUME_TAC) THEN
+  ABBREV_TAC `B = {pastecart (vec 0:real^1) (x:real^M) | x IN t} UNION
+                  {pastecart u x | u IN interval[vec 0,vec 1] /\ x IN s}` THEN
+  SUBGOAL_THEN `closed(B:real^(1,M)finite_sum->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "B" THEN MATCH_MP_TAC CLOSED_UNION THEN
+    REWRITE_TAC[SET_RULE `{pastecart (vec 0) (x:real^M) | x IN t} =
+                          {pastecart u x | u IN {vec 0} /\ x IN t}`] THEN
+    ASM_SIMP_TAC[REWRITE_RULE[PCROSS] CLOSED_PCROSS;
+                 CLOSED_SING; CLOSED_INTERVAL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?k:real^(1,M)finite_sum->real^N.
+        k continuous_on (:real^(1,M)finite_sum) /\
+        (!x. x IN t ==> k(pastecart (vec 0) x) = f(x)) /\
+        (!u x. u IN interval[vec 0,vec 1] /\ x IN s
+               ==> k(pastecart u x) = h(pastecart u x))`
+  STRIP_ASSUME_TAC THENL
+   [SUBGOAL_THEN
+     `?k:real^(1,M)finite_sum->real^N.
+        k continuous_on B /\
+        (!x. x IN t ==> k(pastecart (vec 0) x) = f(x)) /\
+        (!u x. u IN interval[vec 0,vec 1] /\ x IN s
+               ==> k(pastecart u x) = h(pastecart u x))`
+    STRIP_ASSUME_TAC THENL
+     [EXISTS_TAC `\z. if fstcart z = vec 0 then f(sndcart z)
+                      else (h:real^(1,M)finite_sum->real^N) z` THEN
+      REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+      CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+      EXPAND_TAC "B" THEN MATCH_MP_TAC CONTINUOUS_ON_CASES THEN
+      REWRITE_TAC[SET_RULE `{pastecart (vec 0) (x:real^M) | x IN t} =
+                            {pastecart u x | u IN {vec 0} /\ x IN t}`] THEN
+      ASM_SIMP_TAC[REWRITE_RULE[PCROSS] CLOSED_PCROSS;
+                   CLOSED_SING; CLOSED_INTERVAL] THEN
+      REWRITE_TAC[TAUT `(a \/ b /\ c ==> d) <=> (a ==> d) /\ (b ==> c ==> d)`;
+        IMP_CONJ; FORALL_AND_THM; FORALL_IN_GSPEC; IN_ELIM_PASTECART_THM] THEN
+      ASM_SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART; IN_SING] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `t:real^M->bool` THEN
+      ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+      SIMP_TAC[SNDCART_PASTECART];
+      MP_TAC(ISPECL
+       [`k:real^(1,M)finite_sum->real^N`; `(:real^(1,M)finite_sum)`;
+        `B:real^(1,M)finite_sum->bool`]
+       TIETZE_UNBOUNDED) THEN
+      ASM_REWRITE_TAC[SUBTOPOLOGY_UNIV; GSYM CLOSED_IN] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN
+      X_GEN_TAC `g:real^(1,M)finite_sum->real^N` THEN STRIP_TAC THEN
+      ASM_REWRITE_TAC[] THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP RETRACT_OF_IMP_SUBSET) THEN
+  ABBREV_TAC
+   `V = {x | x IN UNIV /\ (k:real^(1,M)finite_sum->real^N) x IN v}` THEN
+  SUBGOAL_THEN `open(V:real^(1,M)finite_sum->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "V" THEN MATCH_MP_TAC CONTINUOUS_OPEN_PREIMAGE THEN
+    ASM_REWRITE_TAC[OPEN_UNIV];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(B:real^(1,M)finite_sum->bool) SUBSET V` ASSUME_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["B"; "V"] THEN REWRITE_TAC[UNION_SUBSET] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+    ASM_SIMP_TAC[IN_ELIM_THM; IN_UNIV] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ABBREV_TAC `s' = {x | ?u. u IN interval[vec 0,vec 1] /\
+                            ~((pastecart (u:real^1) (x:real^M)) IN V)}` THEN
+  SUBGOAL_THEN `closed(s':real^M->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "s'" THEN
+    REWRITE_TAC[SET_RULE `~(x IN s) <=> x IN (UNIV DIFF s)`] THEN
+    MATCH_MP_TAC CLOSED_COMPACT_PROJECTION THEN
+    ASM_REWRITE_TAC[GSYM OPEN_CLOSED; COMPACT_INTERVAL];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`s:real^M->bool`; `s':real^M->bool`;
+                 `vec 1:real^1`; `vec 0:real^1`] URYSOHN) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  ONCE_REWRITE_TAC[SEGMENT_SYM] THEN
+  REWRITE_TAC[SEGMENT_1; DROP_VEC; REAL_POS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^M->real^1` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [retract_of]) THEN
+  REWRITE_TAC[retraction; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `r:real^N->real^N` THEN STRIP_TAC THEN
+  EXISTS_TAC
+   `(r:real^N->real^N) o
+    (\x. (k:real^(1,M)finite_sum->real^N) (pastecart (a x) x))` THEN
+  REWRITE_TAC[o_THM; IMAGE_o] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+   [GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+      REWRITE_TAC[CONTINUOUS_ON_ID] THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNIV];
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNIV]];
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    ASM SET_TAC[]]);;
+
+let NULLHOMOTOPIC_INTO_ANR_EXTENSION = prove
+ (`!f:real^M->real^N s t u.
+        closed s /\ f continuous_on s /\ ~(s = {}) /\
+        IMAGE f s SUBSET t /\ open u /\ t retract_of u
+        ==> ((?c. homotopic_with (\x. T) (s,t) f (\x. c)) <=>
+             (?g. g continuous_on (:real^M) /\
+                  IMAGE g (:real^M) SUBSET t /\
+                  !x. x IN s ==> g x = f x))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN STRIP_TAC THENL
+   [MATCH_MP_TAC BORSUK_HOMOTOPY_EXTENSION THEN
+    ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN
+    MAP_EVERY EXISTS_TAC [`(\x. c):real^M->real^N`; `u:real^N->bool`] THEN
+    ASM_REWRITE_TAC[CLOSED_UNIV; CONTINUOUS_ON_CONST] THEN
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET) THEN
+    ASM SET_TAC[];
+    MP_TAC(ISPECL [`g:real^M->real^N`; `(:real^M)`; `t:real^N->bool`]
+         NULLHOMOTOPIC_FROM_CONTRACTIBLE) THEN
+    ASM_REWRITE_TAC[CONTRACTIBLE_UNIV] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^N` THEN
+    DISCH_TAC THEN MATCH_MP_TAC HOMOTOPIC_WITH_EQ THEN
+    MAP_EVERY EXISTS_TAC [`g:real^M->real^N`; `(\x. c):real^M->real^N`] THEN
+    ASM_SIMP_TAC[] THEN MATCH_MP_TAC HOMOTOPIC_WITH_SUBSET_LEFT THEN
+    EXISTS_TAC `(:real^M)` THEN ASM_REWRITE_TAC[SUBSET_UNIV]]);;
+
+let NULLHOMOTOPIC_INTO_RELATIVE_FRONTIER_EXTENSION = prove
+ (`!f:real^M->real^N s t.
+        closed s /\ f continuous_on s /\ ~(s = {}) /\
+        IMAGE f s SUBSET relative_frontier t /\ convex t /\ bounded t
+        ==> ((?c. homotopic_with (\x. T) (s,relative_frontier t) f (\x. c)) <=>
+             (?g. g continuous_on (:real^M) /\
+                  IMAGE g (:real^M) SUBSET relative_frontier t /\
+                  !x. x IN s ==> g x = f x))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC NULLHOMOTOPIC_INTO_ANR_EXTENSION THEN
+  MP_TAC(ISPEC `t:real^N->bool` ANR_RELATIVE_FRONTIER_CONVEX) THEN
+  ASM_REWRITE_TAC[]);;
+
+let NULLHOMOTOPIC_INTO_SPHERE_EXTENSION = prove
+ (`!f:real^M->real^N s a r.
+     closed s /\ f continuous_on s /\ ~(s = {}) /\ IMAGE f s SUBSET sphere(a,r)
+     ==> ((?c. homotopic_with (\x. T) (s,sphere(a,r)) f (\x. c)) <=>
+          (?g. g continuous_on (:real^M) /\
+               IMAGE g (:real^M) SUBSET sphere(a,r) /\
+               !x. x IN s ==> g x = f x))`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`a:real^N`; `r:real`] RELATIVE_FRONTIER_CBALL) THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [ASM_SIMP_TAC[SPHERE_SING] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC(TAUT `p /\ q ==> (p <=> q)`) THEN CONJ_TAC THENL
+     [EXISTS_TAC `a:real^N` THEN SIMP_TAC[HOMOTOPIC_WITH; PCROSS] THEN
+      EXISTS_TAC `\y:real^(1,M)finite_sum. (a:real^N)`;
+      EXISTS_TAC `(\x. a):real^M->real^N`] THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST] THEN ASM SET_TAC[];
+    DISCH_THEN(SUBST1_TAC o SYM) THEN STRIP_TAC THEN
+    MATCH_MP_TAC NULLHOMOTOPIC_INTO_RELATIVE_FRONTIER_EXTENSION THEN
+    ASM_REWRITE_TAC[CONVEX_CBALL; BOUNDED_CBALL]]);;
+
+let ABSOLUTE_RETRACT_CONTRACTIBLE_ANR = prove
+ (`!s t. closed s /\ contractible s /\ ~(s = {}) /\ s retract_of t /\ open t
+         ==> s retract_of (:real^N)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [contractible]) THEN
+  ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+  REWRITE_TAC[retract_of; retraction; SUBSET_UNIV] THEN
+  MATCH_MP_TAC BORSUK_HOMOTOPY_EXTENSION THEN
+  MAP_EVERY EXISTS_TAC [`(\x. a):real^N->real^N`; `t:real^N->bool`] THEN
+  ASM_SIMP_TAC[CLOSED_UNIV; IMAGE_ID] THEN
+  REWRITE_TAC[SUBSET_REFL; CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET) THEN
+  ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Preservation of fixpoints under (more general notion of) retraction.      *)
+(* ------------------------------------------------------------------------- *)
+
+let INVERTIBLE_FIXPOINT_PROPERTY = prove
+ (`!s:real^M->bool t:real^N->bool i r.
+     i continuous_on t /\ IMAGE i t SUBSET s /\
+     r continuous_on s /\ IMAGE r s SUBSET t /\
+     (!y. y IN t ==> (r(i(y)) = y))
+     ==> (!f. f continuous_on s /\ IMAGE f s SUBSET s
+              ==> ?x. x IN s /\ (f x = x))
+         ==> !g. g continuous_on t /\ IMAGE g t SUBSET t
+                 ==> ?y. y IN t /\ (g y = y)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC
+   `(i:real^N->real^M) o (g:real^N->real^N) o (r:real^M->real^N)`) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; CONTINUOUS_ON_COMPOSE; IMAGE_SUBSET;
+                  SUBSET_TRANS; IMAGE_o];
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; FORALL_IN_IMAGE]) THEN
+    REWRITE_TAC[o_THM] THEN ASM_MESON_TAC[]]);;
+
+let HOMEOMORPHIC_FIXPOINT_PROPERTY = prove
+ (`!s t. s homeomorphic t
+         ==> ((!f. f continuous_on s /\ IMAGE f s SUBSET s
+                   ==> ?x. x IN s /\ (f x = x)) <=>
+              (!g. g continuous_on t /\ IMAGE g t SUBSET t
+                   ==> ?y. y IN t /\ (g y = y)))`,
+  REWRITE_TAC[homeomorphic; homeomorphism] THEN REPEAT STRIP_TAC THEN
+  EQ_TAC THEN MATCH_MP_TAC INVERTIBLE_FIXPOINT_PROPERTY THEN
+  ASM_MESON_TAC[SUBSET_REFL]);;
+
+let RETRACT_FIXPOINT_PROPERTY = prove
+ (`!s t:real^N->bool.
+        t retract_of s /\
+        (!f. f continuous_on s /\ IMAGE f s SUBSET s
+             ==> ?x. x IN s /\ (f x = x))
+        ==> !g. g continuous_on t /\ IMAGE g t SUBSET t
+                ==> ?y. y IN t /\ (g y = y)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  MATCH_MP_TAC INVERTIBLE_FIXPOINT_PROPERTY THEN
+  EXISTS_TAC `\x:real^N. x` THEN REWRITE_TAC[CONTINUOUS_ON_ID] THEN
+  POP_ASSUM MP_TAC THEN REWRITE_TAC[retract_of] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN REWRITE_TAC[retraction] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* So the Brouwer theorem for any set with nonempty interior.                *)
+(* ------------------------------------------------------------------------- *)
+
+let BROUWER_WEAK = prove
+ (`!f:real^N->real^N s.
+        compact s /\ convex s /\ ~(interior s = {}) /\
+        f continuous_on s /\ IMAGE f s SUBSET s
+        ==> ?x. x IN s /\ f x = x`,
+  GEN_TAC THEN ONCE_REWRITE_TAC
+   [TAUT `a /\ b /\ c /\ d ==> e <=> a /\ b /\ c ==> d ==> e`] THEN
+  GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`interval[vec 0:real^N,vec 1]`; `s:real^N->bool`]
+                HOMEOMORPHIC_CONVEX_COMPACT) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[CONVEX_INTERVAL; COMPACT_INTERVAL] THEN
+    REWRITE_TAC[INTERIOR_CLOSED_INTERVAL; INTERVAL_EQ_EMPTY] THEN
+    MESON_TAC[VEC_COMPONENT; REAL_ARITH `~(&1 <= &0)`];
+    DISCH_THEN(MP_TAC o MATCH_MP HOMEOMORPHIC_FIXPOINT_PROPERTY) THEN
+    REWRITE_TAC[BROUWER_CUBE] THEN SIMP_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* And in particular for a closed ball.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let BROUWER_BALL = prove
+ (`!f:real^N->real^N a e.
+        &0 < e /\
+        f continuous_on cball(a,e) /\ IMAGE f (cball(a,e)) SUBSET (cball(a,e))
+        ==> ?x. x IN cball(a,e) /\ (f x = x)`,
+  ASM_SIMP_TAC[BROUWER_WEAK; CONVEX_CBALL; COMPACT_CBALL; INTERIOR_CBALL;
+               REAL_LT_IMP_LE; REAL_NOT_LE; BALL_EQ_EMPTY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Still more general form; could derive this directly without using the     *)
+(* rather involved HOMEOMORPHIC_CONVEX_COMPACT theorem, just using           *)
+(* a scaling and translation to put the set inside the unit cube.            *)
+(* ------------------------------------------------------------------------- *)
+
+let BROUWER = prove
+ (`!f:real^N->real^N s.
+        compact s /\ convex s /\ ~(s = {}) /\
+        f continuous_on s /\ IMAGE f s SUBSET s
+        ==> ?x. x IN s /\ f x = x`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?e. &0 < e /\ s SUBSET cball(vec 0:real^N,e)`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[SUBSET; IN_CBALL; NORM_ARITH `dist(vec 0,x) = norm(x)`] THEN
+    ASM_MESON_TAC[BOUNDED_POS; COMPACT_IMP_BOUNDED];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?x:real^N. x IN cball(vec 0,e) /\ (f o closest_point s) x = x`
+  MP_TAC THENL
+   [MATCH_MP_TAC BROUWER_BALL THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [REWRITE_TAC[ETA_AX] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      ASM_SIMP_TAC[CONTINUOUS_ON_CLOSEST_POINT; COMPACT_IMP_CLOSED] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:real^N->bool` THEN
+      ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE];
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN X_GEN_TAC `x:real^N` THEN
+      REPEAT STRIP_TAC THEN
+      REPEAT(FIRST_X_ASSUM(MATCH_MP_TAC o REWRITE_RULE[SUBSET])) THEN
+      REWRITE_TAC[o_THM; IN_IMAGE] THEN
+      EXISTS_TAC `closest_point s x:real^N` THEN
+      ASM_SIMP_TAC[COMPACT_IMP_CLOSED; CLOSEST_POINT_IN_SET]] THEN
+    ASM_SIMP_TAC[COMPACT_IMP_CLOSED; CLOSEST_POINT_IN_SET];
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x:real^N` THEN
+    REWRITE_TAC[o_THM] THEN STRIP_TAC THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; FORALL_IN_IMAGE]) THEN
+    ASM_MESON_TAC[CLOSEST_POINT_SELF;
+                  CLOSEST_POINT_IN_SET; COMPACT_IMP_CLOSED]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* So we get the no-retraction theorem, first for a ball, then more general. *)
+(* ------------------------------------------------------------------------- *)
+
+let NO_RETRACTION_CBALL = prove
+ (`!a:real^N e. &0 < e ==> ~(sphere(a,e) retract_of cball(a,e))`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP(REWRITE_RULE[IMP_CONJ]
+    RETRACT_FIXPOINT_PROPERTY)) THEN
+  ASM_SIMP_TAC[BROUWER_BALL] THEN REWRITE_TAC[NOT_FORALL_THM] THEN
+  EXISTS_TAC `\x:real^N. &2 % a - x` THEN REWRITE_TAC[NOT_IMP] THEN
+  SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST] THEN
+  ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_SPHERE] THEN
+  SIMP_TAC[dist; VECTOR_ARITH `a - (&2 % a - x) = --(a - x)`; NORM_NEG] THEN
+  REWRITE_TAC[VECTOR_ARITH `(&2 % a - y = y) <=> (a - y = vec 0)`] THEN
+  ASM_MESON_TAC[NORM_0; REAL_LT_REFL]);;
+
+let FRONTIER_SUBSET_RETRACTION = prove
+ (`!s:real^N->bool t r.
+        bounded s /\
+        frontier s SUBSET t /\
+        r continuous_on (closure s) /\
+        IMAGE r s SUBSET t /\
+        (!x. x IN t ==> r x = x)
+        ==> s SUBSET t`,
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  REWRITE_TAC[SET_RULE `~(s SUBSET t) <=> ?x. x IN s /\ ~(x IN t)`] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; LEFT_IMP_EXISTS_THM] THEN
+  REPLICATE_TAC 3 GEN_TAC THEN X_GEN_TAC `a:real^N` THEN REPEAT STRIP_TAC THEN
+  ABBREV_TAC `q = \z:real^N. if z IN closure s then r(z) else z` THEN
+  SUBGOAL_THEN
+    `(q:real^N->real^N) continuous_on
+      closure(s) UNION closure((:real^N) DIFF s)`
+  MP_TAC THENL
+   [EXPAND_TAC "q" THEN MATCH_MP_TAC CONTINUOUS_ON_CASES THEN
+    ASM_REWRITE_TAC[CLOSED_CLOSURE; CONTINUOUS_ON_ID] THEN
+    REWRITE_TAC[TAUT `p /\ ~p <=> F`] THEN X_GEN_TAC `z:real^N` THEN
+    REWRITE_TAC[CLOSURE_COMPLEMENT; IN_DIFF; IN_UNIV] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; frontier; IN_DIFF]) THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `closure(s) UNION closure((:real^N) DIFF s) = (:real^N)`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `s SUBSET closure s /\ t SUBSET closure t /\ s UNION t = UNIV
+      ==> closure s UNION closure t = UNIV`) THEN
+    REWRITE_TAC[CLOSURE_SUBSET] THEN SET_TAC[];
+    DISCH_TAC] THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC o SPEC `a:real^N` o
+    MATCH_MP BOUNDED_SUBSET_BALL o MATCH_MP BOUNDED_CLOSURE) THEN
+  SUBGOAL_THEN `!x. ~((q:real^N->real^N) x = a)` ASSUME_TAC THENL
+   [GEN_TAC THEN EXPAND_TAC "q" THEN COND_CASES_TAC THENL
+     [ASM_CASES_TAC `(x:real^N) IN s` THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      SUBGOAL_THEN `(x:real^N) IN t` (fun th -> ASM_MESON_TAC[th]) THEN
+      UNDISCH_TAC `frontier(s:real^N->bool) SUBSET t` THEN
+      REWRITE_TAC[SUBSET; frontier; IN_DIFF] THEN
+      DISCH_THEN MATCH_MP_TAC THEN ASM_MESON_TAC[SUBSET; INTERIOR_SUBSET];
+      ASM_MESON_TAC[SUBSET; INTERIOR_SUBSET; CLOSURE_SUBSET]];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`a:real^N`; `B:real`] NO_RETRACTION_CBALL) THEN
+  ASM_REWRITE_TAC[retract_of; GSYM FRONTIER_CBALL] THEN
+  EXISTS_TAC `(\y. a + B / norm(y - a) % (y - a)) o (q:real^N->real^N)` THEN
+  REWRITE_TAC[retraction; FRONTIER_SUBSET_EQ; CLOSED_CBALL] THEN
+  REWRITE_TAC[FRONTIER_CBALL; SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[IN_SPHERE; DIST_0] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNIV]; ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_ADD THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+    SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST] THEN
+    REWRITE_TAC[o_DEF; real_div; LIFT_CMUL] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CMUL THEN
+    MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+    SUBGOAL_THEN `(\x:real^N. lift(norm(x - a))) = (lift o norm) o (\x. x - a)`
+    SUBST1_TAC THENL [REWRITE_TAC[FUN_EQ_THM; o_THM]; ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST] THEN
+    REWRITE_TAC[CONTINUOUS_ON_LIFT_NORM];
+    REWRITE_TAC[o_THM; NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM;
+                NORM_ARITH `dist(a,a + b) = norm b`] THEN
+    ASM_SIMP_TAC[REAL_DIV_RMUL; VECTOR_SUB_EQ; NORM_EQ_0] THEN
+    ASM_REAL_ARITH_TAC;
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN REWRITE_TAC[o_THM] THEN
+    EXPAND_TAC "q" THEN REWRITE_TAC[] THEN COND_CASES_TAC THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; IN_BALL]) THEN
+      ASM_MESON_TAC[REAL_LT_REFL];
+      REWRITE_TAC[NORM_ARITH `norm(x - a) = dist(a,x)`] THEN
+      ASM_SIMP_TAC[REAL_DIV_REFL; REAL_LT_IMP_NZ; VECTOR_MUL_LID] THEN
+      VECTOR_ARITH_TAC]]);;
+
+let NO_RETRACTION_FRONTIER_BOUNDED = prove
+ (`!s:real^N->bool.
+        bounded s /\ ~(interior s = {}) ==> ~((frontier s) retract_of s)`,
+  GEN_TAC THEN STRIP_TAC THEN REWRITE_TAC[retract_of; retraction] THEN
+  REWRITE_TAC[FRONTIER_SUBSET_EQ] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real^N->real^N` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `frontier s:real^N->bool`;
+                 `r:real^N->real^N`] FRONTIER_SUBSET_RETRACTION) THEN
+  ASM_SIMP_TAC[CLOSURE_CLOSED; SUBSET_REFL] THEN REWRITE_TAC[frontier] THEN
+  MP_TAC(ISPEC `s:real^N->bool` INTERIOR_SUBSET) THEN ASM SET_TAC[]);;
+
+let COMPACT_SUBSET_FRONTIER_RETRACTION = prove
+ (`!f:real^N->real^N s.
+        compact s /\ f continuous_on s /\ (!x. x IN frontier s ==> f x = x)
+        ==> s SUBSET IMAGE f s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s UNION (IMAGE f s):real^N->bool`; `vec 0:real^N`]
+    BOUNDED_SUBSET_BALL) THEN
+  ASM_SIMP_TAC[BOUNDED_UNION; COMPACT_IMP_BOUNDED;
+               COMPACT_CONTINUOUS_IMAGE; UNION_SUBSET] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+  ABBREV_TAC `g = \x:real^N. if x IN s then f(x) else x` THEN
+  SUBGOAL_THEN `(g:real^N->real^N) continuous_on (:real^N)` ASSUME_TAC THENL
+   [SUBGOAL_THEN `(:real^N) = s UNION closure((:real^N) DIFF s)` SUBST1_TAC
+    THENL
+     [MATCH_MP_TAC(SET_RULE `UNIV DIFF s SUBSET t ==> UNIV = s UNION t`) THEN
+      REWRITE_TAC[CLOSURE_SUBSET];
+      ALL_TAC] THEN
+    EXPAND_TAC "g" THEN MATCH_MP_TAC CONTINUOUS_ON_CASES THEN
+    ASM_SIMP_TAC[CLOSED_CLOSURE; CONTINUOUS_ON_ID; COMPACT_IMP_CLOSED] THEN
+    REWRITE_TAC[CLOSURE_COMPLEMENT; IN_DIFF; IN_UNIV] THEN
+    REWRITE_TAC[TAUT `p /\ ~p <=> F`] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[frontier; IN_DIFF] THEN
+    ASM_SIMP_TAC[CLOSURE_CLOSED; COMPACT_IMP_CLOSED];
+    ALL_TAC] THEN
+  REWRITE_TAC[SUBSET] THEN X_GEN_TAC `p:real^N` THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `?h:real^N->real^N.
+        retraction (UNIV DELETE p,sphere(vec 0,r)) h`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM retract_of] THEN
+    MATCH_MP_TAC SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE_GEN THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`vec 0:real^N`; `r:real`] NO_RETRACTION_CBALL) THEN
+  ASM_REWRITE_TAC[retract_of; NOT_EXISTS_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `(h:real^N->real^N) o (g:real^N->real^N)`) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+  REWRITE_TAC[retraction] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [retraction]) THEN
+  SIMP_TAC[SUBSET; IN_SPHERE; IN_CBALL; REAL_EQ_IMP_LE] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; IN_DELETE; IN_UNIV; o_THM] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x. x IN cball (vec 0,r) ==> ~((g:real^N->real^N) x = p)`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN EXPAND_TAC "g" THEN
+    COND_CASES_TAC THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[] THEN REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_UNIV; IN_DELETE];
+    SUBGOAL_THEN `(g:real^N->real^N) x = x` (fun th -> ASM_SIMP_TAC[th]) THEN
+    EXPAND_TAC "g" THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[IN_BALL; REAL_LT_REFL; SUBSET]]);;
+
+let NOT_ABSOLUTE_RETRACT_COBOUNDED = prove
+ (`!s. bounded s /\ ((:real^N) DIFF s) retract_of (:real^N) ==> s = {}`,
+  GEN_TAC THEN DISCH_TAC THEN
+  MATCH_MP_TAC(SET_RULE `(!x. x IN s ==> F) ==> s = {}`) THEN
+  X_GEN_TAC `a:real^N` THEN POP_ASSUM MP_TAC THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `vec 0:real^N` o
+    MATCH_MP BOUNDED_SUBSET_BALL) THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o SPEC `vec 0:real^N` o MATCH_MP NO_RETRACTION_CBALL) THEN
+  REWRITE_TAC[] THEN MATCH_MP_TAC RETRACT_OF_SUBSET THEN
+  EXISTS_TAC `(:real^N)` THEN SIMP_TAC[SUBSET_UNIV; SPHERE_SUBSET_CBALL] THEN
+  MATCH_MP_TAC RETRACT_OF_TRANS THEN EXISTS_TAC `(:real^N) DIFF s` THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC RETRACT_OF_SUBSET THEN
+  EXISTS_TAC `(:real^N) DELETE (vec 0)` THEN
+  ASM_SIMP_TAC[SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE] THEN
+  CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+  REWRITE_TAC[SUBSET; IN_BALL; IN_SPHERE; IN_DIFF; IN_UNIV] THEN
+  MESON_TAC[REAL_LT_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Similarly we get noncontractibility of a non-trivial sphere.              *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTRACTIBLE_SPHERE = prove
+ (`!a:real^N r. contractible(sphere(a,r)) <=> r <= &0`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[contractible; GSYM REAL_NOT_LT] THEN
+  REWRITE_TAC[NULLHOMOTOPIC_FROM_SPHERE_EXTENSION] THEN
+  ASM_CASES_TAC `&0 < r` THEN ASM_REWRITE_TAC[] THENL
+   [FIRST_ASSUM(MP_TAC o ISPEC `a:real^N` o MATCH_MP NO_RETRACTION_CBALL) THEN
+    SIMP_TAC[retract_of; retraction; SPHERE_SUBSET_CBALL];
+    RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LT]) THEN
+    EXISTS_TAC `\x:real^N. x` THEN REWRITE_TAC[CONTINUOUS_ON_ID; IMAGE_ID] THEN
+    REWRITE_TAC[SUBSET; IN_CBALL; IN_SPHERE; IN_ELIM_THM] THEN
+    POP_ASSUM MP_TAC THEN NORM_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* We also get fixpoint properties for suitable ANRs.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let BROUWER_INESSENTIAL_ANR = prove
+ (`!f:real^N->real^N s t.
+        compact s /\ ~(s = {}) /\ s retract_of t /\ open t /\
+        f continuous_on s /\ IMAGE f s SUBSET s /\
+        (?a. homotopic_with (\x. T) (s,s) f (\x. a))
+        ==> ?x. x IN s /\ f x = x`,
+  ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(X_CHOOSE_TAC `r:real` o SPEC `vec 0:real^N` o
+    MATCH_MP BOUNDED_SUBSET_CBALL o MATCH_MP COMPACT_IMP_BOUNDED) THEN
+  MP_TAC(ISPECL
+   [`(\x. a):real^N->real^N`; `f:real^N->real^N`;
+    `s:real^N->bool`; `cball(vec 0:real^N,r)`; `s:real^N->bool`;
+    `t:real^N->bool`] BORSUK_HOMOTOPY_EXTENSION) THEN
+  ASM_SIMP_TAC[COMPACT_IMP_CLOSED; CONTINUOUS_ON_CONST; CLOSED_CBALL] THEN
+  FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^N` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`g:real^N->real^N`; `cball(vec 0:real^N,r)`]
+        BROUWER) THEN
+  ASM_SIMP_TAC[COMPACT_CBALL; CONVEX_CBALL; CBALL_EQ_EMPTY] THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 < r ==> ~(r < &0)`] THEN ASM SET_TAC[]);;
+
+let BROUWER_CONTRACTIBLE_ANR = prove
+ (`!f:real^N->real^N s t.
+        compact s /\ contractible s /\ ~(s = {}) /\ s retract_of t /\ open t /\
+        f continuous_on s /\ IMAGE f s SUBSET s
+        ==> ?x. x IN s /\ f x = x`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC BROUWER_INESSENTIAL_ANR THEN
+  EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC NULLHOMOTOPIC_FROM_CONTRACTIBLE THEN ASM_REWRITE_TAC[]);;
+
+let FIXED_POINT_INESSENTIAL_SPHERE_MAP = prove
+ (`!f a:real^N r c.
+     &0 < r /\ homotopic_with (\x. T) (sphere(a,r),sphere(a,r)) f (\x. c)
+     ==> ?x. x IN sphere(a,r) /\ f x = x`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC BROUWER_INESSENTIAL_ANR THEN
+  EXISTS_TAC `(:real^N) DELETE a` THEN
+  ASM_SIMP_TAC[SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE] THEN
+  SIMP_TAC[SPHERE_EQ_EMPTY; COMPACT_SPHERE; OPEN_DELETE; OPEN_UNIV] THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_CONTINUOUS) THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET) THEN
+  ASM_SIMP_TAC[REAL_NOT_LT; REAL_LT_IMP_LE] THEN ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some other related fixed-point theorems.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let SCHAUDER_PROJECTION = prove
+ (`!s:real^N->bool e.
+        compact s /\ &0 < e
+        ==> ?t f. FINITE t /\ t SUBSET s /\
+                  f continuous_on s /\ IMAGE f s SUBSET (convex hull t) /\
+                  (!x. x IN s ==> norm(f x - x) < e)`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM
+   (MP_TAC o SPEC `e:real` o MATCH_MP COMPACT_IMP_TOTALLY_BOUNDED) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  ABBREV_TAC `g = \p x:real^N. max (&0) (e - norm(x - p))` THEN
+  SUBGOAL_THEN
+   `!x. x IN s ==> &0 < sum t (\p. (g:real^N->real^N->real) p x)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_POS_LT THEN
+    ASM_REWRITE_TAC[] THEN EXPAND_TAC "g" THEN
+    REWRITE_TAC[REAL_ARITH `&0 <= max (&0) b`] THEN
+    REWRITE_TAC[REAL_ARITH `&0 < max (&0) b <=> &0 < b`; REAL_SUB_LT] THEN
+    UNDISCH_TAC `s SUBSET UNIONS (IMAGE (\x:real^N. ball(x,e)) t)` THEN
+    REWRITE_TAC[SUBSET; UNIONS_IMAGE; IN_BALL; IN_ELIM_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[dist; NORM_SUB];
+    ALL_TAC] THEN
+  EXISTS_TAC
+   `(\x. inv(sum t (\p. g p x)) % vsum t (\p. g p x % p)):real^N->real^N` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_MUL THEN REWRITE_TAC[o_DEF] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_NZ; LIFT_SUM; o_DEF];
+      ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_VSUM THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `y:real^N` THEN DISCH_TAC THENL
+     [ALL_TAC; MATCH_MP_TAC CONTINUOUS_ON_MUL] THEN
+    REWRITE_TAC[o_DEF; CONTINUOUS_ON_CONST] THEN
+    EXPAND_TAC "g" THEN
+    (SUBGOAL_THEN
+      `(\x. lift (max (&0) (e - norm (x - y:real^N)))) =
+       (\x. (lambda i. max (lift(&0)$i) (lift(e - norm (x - y))$i)))`
+     SUBST1_TAC THENL
+      [SIMP_TAC[CART_EQ; LAMBDA_BETA; FUN_EQ_THM] THEN
+       REWRITE_TAC[DIMINDEX_1; FORALL_1; GSYM drop; LIFT_DROP];
+       MATCH_MP_TAC CONTINUOUS_ON_MAX] THEN
+     REWRITE_TAC[CONTINUOUS_ON_CONST; LIFT_SUB] THEN
+     MATCH_MP_TAC CONTINUOUS_ON_SUB THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+     REWRITE_TAC[ONCE_REWRITE_RULE[NORM_SUB] (GSYM dist)] THEN
+     REWRITE_TAC[REWRITE_RULE[o_DEF] CONTINUOUS_ON_LIFT_DIST]);
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; GSYM VSUM_LMUL; VECTOR_MUL_ASSOC] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN MATCH_MP_TAC CONVEX_VSUM THEN
+    ASM_SIMP_TAC[HULL_INC; CONVEX_CONVEX_HULL; SUM_LMUL] THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_NZ; REAL_MUL_LINV] THEN
+    X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN MATCH_MP_TAC REAL_LE_MUL THEN
+    ASM_SIMP_TAC[REAL_LE_INV_EQ; REAL_LT_IMP_LE] THEN
+    EXPAND_TAC "g" THEN REAL_ARITH_TAC;
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    REWRITE_TAC[] THEN ONCE_REWRITE_TAC[NORM_SUB] THEN
+    REWRITE_TAC[REWRITE_RULE[dist] (GSYM IN_BALL)] THEN
+    REWRITE_TAC[GSYM VSUM_LMUL; VECTOR_MUL_ASSOC] THEN
+    MATCH_MP_TAC CONVEX_VSUM_STRONG THEN
+    ASM_REWRITE_TAC[CONVEX_BALL; SUM_LMUL; REAL_ENTIRE] THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_NZ; REAL_MUL_LINV; REAL_LT_INV_EQ;
+                 REAL_LE_MUL_EQ] THEN
+    X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+    EXPAND_TAC "g" THEN REWRITE_TAC[IN_BALL; dist; NORM_SUB] THEN
+    REAL_ARITH_TAC]);;
+
+let SCHAUDER = prove
+ (`!f s t:real^N->bool.
+        convex s /\ ~(s = {}) /\ t SUBSET s /\ compact t /\
+        f continuous_on s /\ IMAGE f s SUBSET t
+        ==> ?x. x IN s /\ f x = x`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN
+  DISCH_TAC THEN
+  MP_TAC(ISPECL [`\x:real^N. f x - x`; `convex hull t:real^N->bool`]
+   BROUWER_COMPACTNESS_LEMMA) THEN
+  SUBGOAL_THEN `(t:real^N->bool) SUBSET convex hull t` ASSUME_TAC THENL
+   [REWRITE_TAC[HULL_SUBSET]; ALL_TAC] THEN
+  SUBGOAL_THEN `(convex hull t:real^N->bool) SUBSET s` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[SUBSET_HULL] THEN ASM SET_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[COMPACT_CONVEX_HULL; VECTOR_SUB_EQ] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+    REWRITE_TAC[CONTINUOUS_ON_ID; ETA_AX] THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC)] THEN
+  MP_TAC(ISPECL [`convex hull t:real^N->bool`; `e:real`]
+     SCHAUDER_PROJECTION) THEN
+  ASM_SIMP_TAC[NOT_EXISTS_THM; COMPACT_CONVEX_HULL] THEN
+  MAP_EVERY X_GEN_TAC [`k:real^N->bool`; `g:real^N->real^N`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `(convex hull k:real^N->bool) SUBSET s` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[SUBSET_HULL] THEN ASM SET_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`(g:real^N->real^N) o (f:real^N->real^N)`; `convex hull k:real^N->bool`]
+   BROUWER) THEN
+  ASM_SIMP_TAC[COMPACT_CONVEX_HULL; FINITE_IMP_COMPACT] THEN
+  REWRITE_TAC[CONVEX_CONVEX_HULL; NOT_IMP; GSYM CONJ_ASSOC; o_THM] THEN
+  SUBGOAL_THEN `~(k:real^N->bool = {})` ASSUME_TAC THENL
+   [ASM_MESON_TAC[IMAGE_EQ_EMPTY; SUBSET_EMPTY; CONVEX_HULL_EQ_EMPTY];
+    ASM_REWRITE_TAC[CONVEX_HULL_EQ_EMPTY]] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN ASM SET_TAC[];
+    REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[];
+    DISCH_THEN(X_CHOOSE_THEN `x:real^N` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(f:real^N->real^N) x`) THEN
+    ASM_REWRITE_TAC[NOT_IMP; NORM_ARITH
+      `norm(x - y:real^N) < e <=> ~(e <= norm(y - x))`] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; FIRST_X_ASSUM MATCH_MP_TAC] THEN
+    UNDISCH_TAC `(x:real^N) IN convex hull k` THEN
+    SPEC_TAC(`x:real^N`,`x:real^N`) THEN REWRITE_TAC[GSYM SUBSET] THEN
+    ASM_SIMP_TAC[SUBSET_HULL; CONVEX_CONVEX_HULL]]);;
+
+let SCHAUDER_UNIV = prove
+ (`!f:real^N->real^N.
+        f continuous_on (:real^N) /\ bounded (IMAGE f (:real^N))
+        ==> ?x. f x = x`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^N->real^N`; `(:real^N)`;
+                 `closure(IMAGE (f:real^N->real^N) (:real^N))`] SCHAUDER) THEN
+  ASM_REWRITE_TAC[UNIV_NOT_EMPTY; CONVEX_UNIV; COMPACT_CLOSURE; IN_UNIV] THEN
+  REWRITE_TAC[SUBSET_UNIV; CLOSURE_SUBSET]);;
+
+let ROTHE = prove
+ (`!f s:real^N->bool.
+        closed s /\ convex s /\ ~(s = {}) /\
+        f continuous_on s /\ bounded(IMAGE f s) /\
+        IMAGE f (frontier s) SUBSET s
+        ==> ?x. x IN s /\ f x = x`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `(:real^N)`]
+    ABSOLUTE_RETRACTION_CONVEX_CLOSED) THEN
+  ASM_REWRITE_TAC[retraction; SUBSET_UNIV] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real^N->real^N` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`(r:real^N->real^N) o (f:real^N->real^N)`; `s:real^N->bool`;
+    `IMAGE (r:real^N->real^N) (closure(IMAGE (f:real^N->real^N) s))`]
+   SCHAUDER) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[CLOSURE_SUBSET; IMAGE_SUBSET; IMAGE_o] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+      ASM_REWRITE_TAC[COMPACT_CLOSURE];
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE] THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNIV];
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `y:real^N` THEN
+    REWRITE_TAC[o_THM] THEN STRIP_TAC THEN ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Bijections between intervals.                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let interval_bij = new_definition
+ `interval_bij (a:real^N,b:real^N) (u:real^N,v:real^N) (x:real^N) =
+    (lambda i. u$i + (x$i - a$i) / (b$i - a$i) * (v$i - u$i)):real^N`;;
+
+let INTERVAL_BIJ_AFFINE = prove
+ (`interval_bij (a,b) (u,v) =
+        \x. (lambda i. (v$i - u$i) / (b$i - a$i) * x$i) +
+            (lambda i. u$i - (v$i - u$i) / (b$i - a$i) * a$i)`,
+  SIMP_TAC[FUN_EQ_THM; CART_EQ; VECTOR_ADD_COMPONENT; LAMBDA_BETA;
+           interval_bij] THEN
+  REAL_ARITH_TAC);;
+
+let CONTINUOUS_INTERVAL_BIJ = prove
+ (`!a b u v x. (interval_bij (a:real^N,b:real^N) (u:real^N,v:real^N))
+                  continuous at x`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[INTERVAL_BIJ_AFFINE] THEN
+  MATCH_MP_TAC CONTINUOUS_ADD THEN REWRITE_TAC[CONTINUOUS_CONST] THEN
+  MATCH_MP_TAC LINEAR_CONTINUOUS_AT THEN
+  SIMP_TAC[linear; CART_EQ; LAMBDA_BETA;
+           VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  REAL_ARITH_TAC);;
+
+let CONTINUOUS_ON_INTERVAL_BIJ = prove
+ (`!a b u v s. interval_bij (a,b) (u,v) continuous_on s`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN
+  REWRITE_TAC[CONTINUOUS_INTERVAL_BIJ]);;
+
+let IN_INTERVAL_INTERVAL_BIJ = prove
+ (`!a b u v x:real^N.
+        x IN interval[a,b] /\ ~(interval[u,v] = {})
+        ==> (interval_bij (a,b) (u,v) x) IN interval[u,v]`,
+  SIMP_TAC[IN_INTERVAL; interval_bij; LAMBDA_BETA; INTERVAL_NE_EMPTY] THEN
+  REWRITE_TAC[REAL_ARITH `u <= u + x <=> &0 <= x`;
+              REAL_ARITH `u + x <= v <=> x <= &1 * (v - u)`] THEN
+  REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC REAL_LE_MUL THEN CONJ_TAC THEN
+    TRY(MATCH_MP_TAC REAL_LE_DIV) THEN
+    ASM_SIMP_TAC[REAL_SUB_LE] THEN ASM_MESON_TAC[REAL_LE_TRANS];
+    MATCH_MP_TAC REAL_LE_RMUL THEN ASM_SIMP_TAC[REAL_SUB_LE] THEN
+    SUBGOAL_THEN `(a:real^N)$i <= (b:real^N)$i` MP_TAC THENL
+     [ASM_MESON_TAC[REAL_LE_TRANS]; ALL_TAC] THEN
+    GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN STRIP_TAC THENL
+     [ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_SUB_LT] THEN
+      ASM_SIMP_TAC[REAL_ARITH `a <= x /\ x <= b ==> x - a <= &1 * (b - a)`];
+      ASM_REWRITE_TAC[real_div; REAL_SUB_REFL; REAL_INV_0] THEN
+      REAL_ARITH_TAC]]);;
+
+let INTERVAL_BIJ_BIJ = prove
+ (`!a b u v x:real^N.
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i < b$i /\ u$i < v$i)
+        ==> interval_bij (a,b) (u,v) (interval_bij (u,v) (a,b) x) = x`,
+  SIMP_TAC[interval_bij; CART_EQ; LAMBDA_BETA; REAL_ADD_SUB] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[AND_FORALL_THM] THEN
+  MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN MATCH_MP_TAC MONO_IMP THEN
+  REWRITE_TAC[] THEN CONV_TAC REAL_FIELD);;
+
+(* ------------------------------------------------------------------------- *)
+(* Fashoda meet theorem.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let INFNORM_2 = prove
+ (`infnorm (x:real^2) = max (abs(x$1)) (abs(x$2))`,
+  REWRITE_TAC[infnorm; INFNORM_SET_IMAGE; NUMSEG_CONV `1..2`; DIMINDEX_2] THEN
+  REWRITE_TAC[IMAGE_CLAUSES; GSYM REAL_MAX_SUP]);;
+
+let INFNORM_EQ_1_2 = prove
+ (`infnorm (x:real^2) = &1 <=>
+        abs(x$1) <= &1 /\ abs(x$2) <= &1 /\
+        (x$1 = -- &1 \/ x$1 = &1 \/ x$2 = -- &1 \/ x$2 = &1)`,
+  REWRITE_TAC[INFNORM_2] THEN REAL_ARITH_TAC);;
+
+let INFNORM_EQ_1_IMP = prove
+ (`infnorm (x:real^2) = &1 ==> abs(x$1) <= &1 /\ abs(x$2) <= &1`,
+  SIMP_TAC[INFNORM_EQ_1_2]);;
+
+let FASHODA_UNIT = prove
+ (`!f:real^1->real^2 g:real^1->real^2.
+        IMAGE f (interval[--vec 1,vec 1]) SUBSET interval[--vec 1,vec 1] /\
+        IMAGE g (interval[--vec 1,vec 1]) SUBSET interval[--vec 1,vec 1] /\
+        f continuous_on interval[--vec 1,vec 1] /\
+        g continuous_on interval[--vec 1,vec 1] /\
+        f(--vec 1)$1 = -- &1 /\ f(vec 1)$1 = &1 /\
+        g(--vec 1)$2 = -- &1 /\ g(vec 1)$2 = &1
+        ==> ?s t. s IN interval[--vec 1,vec 1] /\
+                  t IN interval[--vec 1,vec 1] /\
+                  f(s) = g(t)`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC I [TAUT `p <=> ~ ~p`] THEN
+  DISCH_THEN(MP_TAC o REWRITE_RULE[NOT_EXISTS_THM]) THEN
+  REWRITE_TAC[TAUT `~(a /\ b /\ c) <=> a /\ b ==> ~c`] THEN DISCH_TAC THEN
+  ABBREV_TAC `sqprojection = \z:real^2. inv(infnorm z) % z` THEN
+  ABBREV_TAC `(negatex:real^2->real^2) = \x. vector[--(x$1); x$2]` THEN
+  SUBGOAL_THEN `!z:real^2. infnorm(negatex z:real^2) = infnorm z` ASSUME_TAC
+  THENL
+   [EXPAND_TAC "negatex" THEN SIMP_TAC[VECTOR_2; INFNORM_2] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!z. ~(z = vec 0) ==> infnorm((sqprojection:real^2->real^2) z) = &1`
+  ASSUME_TAC THENL
+   [EXPAND_TAC "sqprojection" THEN
+    REWRITE_TAC[INFNORM_MUL; REAL_ABS_INFNORM; REAL_ABS_INV] THEN
+    SIMP_TAC[REAL_MUL_LINV; INFNORM_EQ_0];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`(\w. (negatex:real^2->real^2)
+                       (sqprojection(f(lift(w$1)) - g(lift(w$2)):real^2)))
+                  :real^2->real^2`;
+                 `interval[--vec 1,vec 1]:real^2->bool`]
+         BROUWER_WEAK) THEN
+  REWRITE_TAC[NOT_IMP; COMPACT_INTERVAL; CONVEX_INTERVAL] THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[INTERIOR_CLOSED_INTERVAL; INTERVAL_NE_EMPTY] THEN
+    SIMP_TAC[VEC_COMPONENT; VECTOR_NEG_COMPONENT] THEN REAL_ARITH_TAC;
+    MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_COMPOSE) THEN CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN EXPAND_TAC "negatex" THEN
+      SIMP_TAC[linear; VECTOR_2; CART_EQ; FORALL_2; DIMINDEX_2;
+               VECTOR_MUL_COMPONENT; VECTOR_NEG_COMPONENT;
+               VECTOR_ADD_COMPONENT; ARITH] THEN
+      REAL_ARITH_TAC] THEN
+    MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_COMPOSE) THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_SUB THEN CONJ_TAC THEN
+      MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_COMPOSE) THEN
+      SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT; DIMINDEX_2; ARITH] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+      EXISTS_TAC `interval[--vec 1:real^1,vec 1]`;
+      MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN
+      EXPAND_TAC "sqprojection" THEN REWRITE_TAC[FORALL_IN_IMAGE] THEN
+      X_GEN_TAC `x:real^2` THEN STRIP_TAC THEN
+      MATCH_MP_TAC CONTINUOUS_MUL THEN REWRITE_TAC[CONTINUOUS_AT_ID] THEN
+      GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_AT_INV THEN
+      REWRITE_TAC[CONTINUOUS_AT_LIFT_INFNORM; INFNORM_EQ_0; VECTOR_SUB_EQ] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL])] THEN
+    ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1] THEN
+    SIMP_TAC[IN_INTERVAL; DIMINDEX_2; FORALL_2; VEC_COMPONENT; ARITH;
+             VECTOR_NEG_COMPONENT; DROP_NEG; DROP_VEC; LIFT_DROP];
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `x:real^2` THEN STRIP_TAC THEN
+    SIMP_TAC[IN_INTERVAL; DIMINDEX_2; FORALL_2; REAL_BOUNDS_LE;
+             VECTOR_NEG_COMPONENT; VEC_COMPONENT; ARITH] THEN
+    MATCH_MP_TAC INFNORM_EQ_1_IMP THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[VECTOR_SUB_EQ] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL]) THEN
+    ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1] THEN
+    SIMP_TAC[IN_INTERVAL; DIMINDEX_2; FORALL_2; VEC_COMPONENT; ARITH;
+             VECTOR_NEG_COMPONENT; DROP_NEG; DROP_VEC; LIFT_DROP];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `x:real^2` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `infnorm(x:real^2) = &1` MP_TAC THENL
+   [FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV)
+     [SYM th]) THEN
+    ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[VECTOR_SUB_EQ] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[IN_INTERVAL_1] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL]) THEN
+    SIMP_TAC[IN_INTERVAL; DIMINDEX_2; FORALL_2; VEC_COMPONENT; ARITH;
+             VECTOR_NEG_COMPONENT; DROP_NEG; DROP_VEC; LIFT_DROP];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(!x i. 1 <= i /\ i <= 2 /\ ~(x = vec 0)
+           ==> (&0 < ((sqprojection:real^2->real^2) x)$i <=> &0 < x$i)) /\
+    (!x i. 1 <= i /\ i <= 2 /\ ~(x = vec 0)
+           ==> ((sqprojection x)$i < &0 <=> x$i < &0))`
+  STRIP_ASSUME_TAC THENL
+   [EXPAND_TAC "sqprojection" THEN
+    SIMP_TAC[VECTOR_MUL_COMPONENT; DIMINDEX_2; ARITH] THEN
+    REWRITE_TAC[GSYM(ONCE_REWRITE_RULE[REAL_MUL_SYM] real_div)] THEN
+    SIMP_TAC[REAL_LT_LDIV_EQ; REAL_LT_RDIV_EQ; INFNORM_POS_LT] THEN
+    REWRITE_TAC[REAL_MUL_LZERO];
+    ALL_TAC] THEN
+  REWRITE_TAC[INFNORM_EQ_1_2; CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC
+   (REPEAT_TCL DISJ_CASES_THEN (fun th -> ASSUME_TAC th THEN MP_TAC th))) THEN
+  MAP_EVERY EXPAND_TAC ["x"; "negatex"] THEN REWRITE_TAC[VECTOR_2] THENL
+   [DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH `--x = -- &1 ==> &0 < x`));
+    DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH `--x = &1 ==> x < &0`));
+    DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH `x = -- &1 ==> x < &0`));
+    DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH `x = &1 ==> &0 < x`))] THEN
+  W(fun (_,w) -> FIRST_X_ASSUM(fun th ->
+   MP_TAC(PART_MATCH (lhs o rand) th (lhand w)))) THEN
+  (ANTS_TAC THENL
+    [REWRITE_TAC[VECTOR_SUB_EQ; ARITH] THEN
+     FIRST_X_ASSUM MATCH_MP_TAC THEN
+     FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL]) THEN
+     ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1] THEN
+     SIMP_TAC[IN_INTERVAL; DIMINDEX_2; FORALL_2; VEC_COMPONENT; ARITH;
+              VECTOR_NEG_COMPONENT; DROP_NEG; DROP_VEC; LIFT_DROP] THEN
+     REAL_ARITH_TAC;
+     DISCH_THEN SUBST1_TAC]) THEN
+  ASM_SIMP_TAC[VECTOR_SUB_COMPONENT; DIMINDEX_2; ARITH;
+               LIFT_NEG; LIFT_NUM]
+  THENL
+   [MATCH_MP_TAC(REAL_ARITH
+     `abs(x$1) <= &1 /\ abs(x$2) <= &1 ==> ~(&0 < -- &1 - x$1)`);
+    MATCH_MP_TAC(REAL_ARITH
+     `abs(x$1) <= &1 /\ abs(x$2) <= &1 ==> ~(&1 - x$1 < &0)`);
+    MATCH_MP_TAC(REAL_ARITH
+     `abs(x$1) <= &1 /\ abs(x$2) <= &1 ==> ~(x$2 - -- &1 < &0)`);
+    MATCH_MP_TAC(REAL_ARITH
+     `abs(x$1) <= &1 /\ abs(x$2) <= &1 ==> ~(&0 < x$2 - &1)`)] THEN
+  (SUBGOAL_THEN `!z:real^2. abs(z$1) <= &1 /\ abs(z$2) <= &1 <=>
+                           z IN interval[--vec 1,vec 1]`
+    (fun th -> REWRITE_TAC[th]) THENL
+    [SIMP_TAC[IN_INTERVAL; DIMINDEX_2; FORALL_2; VEC_COMPONENT; ARITH;
+              VECTOR_NEG_COMPONENT; DROP_NEG; DROP_VEC; LIFT_DROP] THEN
+     REAL_ARITH_TAC;
+     ALL_TAC]) THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+   `IMAGE f s SUBSET t ==> x IN s ==> f x IN t`)) THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_NEG; DROP_VEC; LIFT_DROP] THEN
+  ASM_REWRITE_TAC[REAL_BOUNDS_LE]);;
+
+let FASHODA_UNIT_PATH = prove
+ (`!f:real^1->real^2 g:real^1->real^2.
+        path f /\ path g /\
+        path_image f SUBSET interval[--vec 1,vec 1] /\
+        path_image g SUBSET interval[--vec 1,vec 1] /\
+        (pathstart f)$1 = -- &1 /\ (pathfinish f)$1 = &1 /\
+        (pathstart g)$2 = -- &1 /\ (pathfinish g)$2 = &1
+        ==> ?z. z IN path_image f /\ z IN path_image g`,
+  SIMP_TAC[path; path_image; pathstart; pathfinish] THEN REPEAT STRIP_TAC THEN
+  ABBREV_TAC `iscale = \z:real^1. inv(&2) % (z + vec 1)` THEN
+  MP_TAC(ISPECL
+   [`(f:real^1->real^2) o (iscale:real^1->real^1)`;
+    `(g:real^1->real^2) o (iscale:real^1->real^1)`]
+   FASHODA_UNIT) THEN
+  SUBGOAL_THEN
+   `IMAGE (iscale:real^1->real^1) (interval[--vec 1,vec 1])
+    SUBSET interval[vec 0,vec 1]`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN EXPAND_TAC "iscale" THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_NEG; DROP_VEC; DROP_CMUL; DROP_ADD] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(iscale:real^1->real^1) continuous_on interval [--vec 1,vec 1]`
+  ASSUME_TAC THENL
+   [EXPAND_TAC "iscale" THEN
+    SIMP_TAC[CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID; CONTINUOUS_ON_ADD;
+             CONTINUOUS_ON_CONST];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[IMAGE_o] THEN ANTS_TAC THENL
+   [REPLICATE_TAC 2 (CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+    REPLICATE_TAC 2 (CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN ASM_REWRITE_TAC[] THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+      ALL_TAC]) THEN
+    EXPAND_TAC "iscale" THEN REWRITE_TAC[o_THM] THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH `inv(&2) % (--x + x) = vec 0`;
+                    VECTOR_ARITH `inv(&2) % (x + x) = x`];
+    REWRITE_TAC[o_THM; LEFT_IMP_EXISTS_THM; IN_IMAGE] THEN ASM SET_TAC[]]);;
+
+let FASHODA = prove
+ (`!f g a b:real^2.
+        path f /\ path g /\
+        path_image f SUBSET interval[a,b] /\
+        path_image g SUBSET interval[a,b] /\
+        (pathstart f)$1 = a$1 /\ (pathfinish f)$1 = b$1 /\
+        (pathstart g)$2 = a$2 /\ (pathfinish g)$2 = b$2
+        ==> ?z. z IN path_image f /\ z IN path_image g`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `~(interval[a:real^2,b] = {})` MP_TAC THENL
+   [FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `s SUBSET t ==> ~(s = {}) ==> ~(t = {})`)) THEN
+    REWRITE_TAC[PATH_IMAGE_NONEMPTY];
+    ALL_TAC] THEN
+  REWRITE_TAC[INTERVAL_NE_EMPTY; DIMINDEX_2; FORALL_2] THEN STRIP_TAC THEN
+  MP_TAC(ASSUME `(a:real^2)$1 <= (b:real^2)$1`) THEN
+  REWRITE_TAC[REAL_ARITH `a <= b <=> b = a \/ a < b`] THEN STRIP_TAC THENL
+   [SUBGOAL_THEN
+      `?z:real^2. z IN path_image g /\ z$2 = (pathstart f:real^2)$2`
+    MP_TAC THENL
+     [MATCH_MP_TAC CONNECTED_IVT_COMPONENT THEN
+      MAP_EVERY EXISTS_TAC [`pathstart(g:real^1->real^2)`;
+                            `pathfinish(g:real^1->real^2)`] THEN
+      ASM_SIMP_TAC[CONNECTED_PATH_IMAGE; PATHSTART_IN_PATH_IMAGE; REAL_LE_REFL;
+                   PATHFINISH_IN_PATH_IMAGE; DIMINDEX_2; ARITH] THEN
+      UNDISCH_TAC `path_image f SUBSET interval[a:real^2,b]` THEN
+      REWRITE_TAC[SUBSET; path_image; IN_INTERVAL_1; FORALL_IN_IMAGE] THEN
+      DISCH_THEN(MP_TAC o SPEC `vec 0:real^1`) THEN SIMP_TAC[pathstart] THEN
+      SIMP_TAC[DROP_VEC; REAL_POS; IN_INTERVAL; FORALL_2; DIMINDEX_2];
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `z:real^2` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN SIMP_TAC[path_image; IN_IMAGE] THEN
+    EXISTS_TAC `vec 0:real^1` THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS] THEN
+    ASM_REWRITE_TAC[CART_EQ; FORALL_2; DIMINDEX_2; pathstart] THEN
+    SUBGOAL_THEN
+     `(z:real^2) IN interval[a,b] /\ f(vec 0:real^1) IN interval[a,b]`
+    MP_TAC THENL
+     [ASM_MESON_TAC[SUBSET; path_image; IN_IMAGE; PATHSTART_IN_PATH_IMAGE;
+                    pathstart];
+      ASM_REWRITE_TAC[IN_INTERVAL; FORALL_2; DIMINDEX_2] THEN REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  MP_TAC(ASSUME `(a:real^2)$2 <= (b:real^2)$2`) THEN
+  REWRITE_TAC[REAL_ARITH `a <= b <=> b = a \/ a < b`] THEN STRIP_TAC THENL
+   [SUBGOAL_THEN
+      `?z:real^2. z IN path_image f /\ z$1 = (pathstart g:real^2)$1`
+    MP_TAC THENL
+     [MATCH_MP_TAC CONNECTED_IVT_COMPONENT THEN
+      MAP_EVERY EXISTS_TAC [`pathstart(f:real^1->real^2)`;
+                            `pathfinish(f:real^1->real^2)`] THEN
+      ASM_SIMP_TAC[CONNECTED_PATH_IMAGE; PATHSTART_IN_PATH_IMAGE; REAL_LE_REFL;
+                   PATHFINISH_IN_PATH_IMAGE; DIMINDEX_2; ARITH] THEN
+      UNDISCH_TAC `path_image g SUBSET interval[a:real^2,b]` THEN
+      REWRITE_TAC[SUBSET; path_image; IN_INTERVAL_1; FORALL_IN_IMAGE] THEN
+      DISCH_THEN(MP_TAC o SPEC `vec 0:real^1`) THEN SIMP_TAC[pathstart] THEN
+      SIMP_TAC[DROP_VEC; REAL_POS; IN_INTERVAL; FORALL_2; DIMINDEX_2];
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `z:real^2` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN SIMP_TAC[path_image; IN_IMAGE] THEN
+    EXISTS_TAC `vec 0:real^1` THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS] THEN
+    ASM_REWRITE_TAC[CART_EQ; FORALL_2; DIMINDEX_2; pathstart] THEN
+    SUBGOAL_THEN
+     `(z:real^2) IN interval[a,b] /\ g(vec 0:real^1) IN interval[a,b]`
+    MP_TAC THENL
+     [ASM_MESON_TAC[SUBSET; path_image; IN_IMAGE; PATHSTART_IN_PATH_IMAGE;
+                    pathstart];
+      ASM_REWRITE_TAC[IN_INTERVAL; FORALL_2; DIMINDEX_2] THEN REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`interval_bij (a,b) (--vec 1,vec 1) o (f:real^1->real^2)`;
+    `interval_bij (a,b) (--vec 1,vec 1) o (g:real^1->real^2)`]
+   FASHODA_UNIT_PATH) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[path; path_image; pathstart; pathfinish]) THEN
+  ASM_REWRITE_TAC[path; path_image; pathstart; pathfinish; o_THM] THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[CONTINUOUS_ON_COMPOSE; CONTINUOUS_ON_INTERVAL_BIJ] THEN
+    REWRITE_TAC[IMAGE_o] THEN REPLICATE_TAC 2 (CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET] THEN ONCE_REWRITE_TAC[FORALL_IN_IMAGE] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC IN_INTERVAL_INTERVAL_BIJ THEN
+      SIMP_TAC[INTERVAL_NE_EMPTY; VECTOR_NEG_COMPONENT; VEC_COMPONENT] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM SET_TAC[];
+      ALL_TAC]) THEN
+    ASM_SIMP_TAC[interval_bij; LAMBDA_BETA; DIMINDEX_2; ARITH] THEN
+    ASM_SIMP_TAC[REAL_DIV_REFL; REAL_LT_IMP_NZ; REAL_SUB_LT] THEN
+    REWRITE_TAC[real_div; REAL_SUB_REFL; REAL_MUL_LZERO] THEN
+    SIMP_TAC[VECTOR_NEG_COMPONENT; VEC_COMPONENT; DIMINDEX_2; ARITH] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real^2`
+   (fun th -> EXISTS_TAC `interval_bij (--vec 1,vec 1) (a,b) (z:real^2)` THEN
+              MP_TAC th)) THEN
+  MATCH_MP_TAC MONO_AND THEN CONJ_TAC THEN REWRITE_TAC[IMAGE_o] THEN
+  MATCH_MP_TAC(SET_RULE
+   `(!x. x IN s ==> g(f(x)) = x) ==> x IN IMAGE f s ==> g x IN s`) THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTERVAL_BIJ_BIJ THEN
+  ASM_SIMP_TAC[FORALL_2; DIMINDEX_2; VECTOR_NEG_COMPONENT; VEC_COMPONENT;
+               ARITH] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some slightly ad hoc lemmas I use below                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let SEGMENT_VERTICAL = prove
+ (`!a:real^2 b:real^2 x:real^2.
+      a$1 = b$1
+      ==> (x IN segment[a,b] <=>
+           x$1 = a$1 /\ x$1 = b$1 /\
+           (a$2 <= x$2 /\ x$2 <= b$2 \/ b$2 <= x$2 /\ x$2 <= a$2))`,
+  GEOM_ORIGIN_TAC `a:real^2` THEN
+  REWRITE_TAC[VECTOR_ADD_COMPONENT; VEC_COMPONENT; REAL_LE_LADD;
+              REAL_EQ_ADD_LCANCEL] THEN
+  REPEAT GEN_TAC THEN DISCH_THEN(ASSUME_TAC o SYM) THEN
+  SUBST1_TAC(SYM(ISPEC `b:real^2` BASIS_EXPANSION)) THEN
+  ASM_REWRITE_TAC[DIMINDEX_2; VSUM_2; VECTOR_MUL_LZERO; VECTOR_ADD_LID] THEN
+  SUBST1_TAC(VECTOR_ARITH `vec 0:real^2 = &0 % basis 2`) THEN
+  REWRITE_TAC[SEGMENT_SCALAR_MULTIPLE; IN_ELIM_THM; CART_EQ] THEN
+  REWRITE_TAC[DIMINDEX_2; FORALL_2; VECTOR_MUL_COMPONENT] THEN
+  SIMP_TAC[BASIS_COMPONENT; DIMINDEX_2; ARITH;
+           REAL_MUL_RZERO; REAL_MUL_RID] THEN MESON_TAC[]);;
+
+let SEGMENT_HORIZONTAL = prove
+ (`!a:real^2 b:real^2 x:real^2.
+      a$2 = b$2
+      ==> (x IN segment[a,b] <=>
+           x$2 = a$2 /\ x$2 = b$2 /\
+           (a$1 <= x$1 /\ x$1 <= b$1 \/ b$1 <= x$1 /\ x$1 <= a$1))`,
+  GEOM_ORIGIN_TAC `a:real^2` THEN
+  REWRITE_TAC[VECTOR_ADD_COMPONENT; VEC_COMPONENT; REAL_LE_LADD;
+              REAL_EQ_ADD_LCANCEL] THEN
+  REPEAT GEN_TAC THEN DISCH_THEN(ASSUME_TAC o SYM) THEN
+  SUBST1_TAC(SYM(ISPEC `b:real^2` BASIS_EXPANSION)) THEN
+  ASM_REWRITE_TAC[DIMINDEX_2; VSUM_2; VECTOR_MUL_LZERO; VECTOR_ADD_RID] THEN
+  SUBST1_TAC(VECTOR_ARITH `vec 0:real^2 = &0 % basis 1`) THEN
+  REWRITE_TAC[SEGMENT_SCALAR_MULTIPLE; IN_ELIM_THM; CART_EQ] THEN
+  REWRITE_TAC[DIMINDEX_2; FORALL_2; VECTOR_MUL_COMPONENT] THEN
+  SIMP_TAC[BASIS_COMPONENT; DIMINDEX_2; ARITH;
+           REAL_MUL_RZERO; REAL_MUL_RID] THEN MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Useful Fashoda corollary pointed out to me by Tom Hales.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let FASHODA_INTERLACE = prove
+ (`!f g a b:real^2.
+        path f /\ path g /\
+        path_image f SUBSET interval[a,b] /\
+        path_image g SUBSET interval[a,b] /\
+        (pathstart f)$2 = a$2 /\ (pathfinish f)$2 = a$2 /\
+        (pathstart g)$2 = a$2 /\ (pathfinish g)$2 = a$2 /\
+        (pathstart f)$1 < (pathstart g)$1 /\
+        (pathstart g)$1 < (pathfinish f)$1 /\
+        (pathfinish f)$1 < (pathfinish g)$1
+        ==> ?z. z IN path_image f /\ z IN path_image g`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `~(interval[a:real^2,b] = {})` MP_TAC THENL
+   [FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `s SUBSET t ==> ~(s = {}) ==> ~(t = {})`)) THEN
+    REWRITE_TAC[PATH_IMAGE_NONEMPTY];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `pathstart (f:real^1->real^2) IN interval[a,b] /\
+    pathfinish f IN interval[a,b] /\
+    pathstart g IN interval[a,b] /\
+    pathfinish g IN interval[a,b]`
+  MP_TAC THENL
+   [ASM_MESON_TAC[SUBSET; PATHSTART_IN_PATH_IMAGE; PATHFINISH_IN_PATH_IMAGE];
+    ALL_TAC] THEN
+  REWRITE_TAC[INTERVAL_NE_EMPTY; IN_INTERVAL; FORALL_2; DIMINDEX_2] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL
+   [`linepath(vector[a$1 - &2;a$2 - &2],vector[(pathstart f)$1;a$2 - &2]) ++
+     linepath(vector[(pathstart f)$1;(a:real^2)$2 - &2],pathstart f) ++
+     (f:real^1->real^2) ++
+     linepath(pathfinish f,vector[(pathfinish f)$1;a$2 - &2]) ++
+     linepath(vector[(pathfinish f)$1;a$2 - &2],
+              vector[(b:real^2)$1 + &2;a$2 - &2])`;
+    `linepath(vector[(pathstart g)$1; (pathstart g)$2 - &3],pathstart g) ++
+     (g:real^1->real^2) ++
+     linepath(pathfinish g,vector[(pathfinish g)$1;(a:real^2)$2 - &1]) ++
+     linepath(vector[(pathfinish g)$1;a$2 - &1],vector[b$1 + &1;a$2 - &1]) ++
+     linepath(vector[b$1 + &1;a$2 - &1],vector[(b:real^2)$1 + &1;b$2 + &3])`;
+    `vector[(a:real^2)$1 - &2; a$2 - &3]:real^2`;
+    `vector[(b:real^2)$1 + &2; b$2 + &3]:real^2`]
+   FASHODA) THEN
+  ASM_SIMP_TAC[PATH_JOIN; PATHSTART_JOIN; PATHFINISH_JOIN; PATH_IMAGE_JOIN;
+               PATHSTART_LINEPATH; PATHFINISH_LINEPATH; PATH_LINEPATH] THEN
+  REWRITE_TAC[VECTOR_2] THEN ANTS_TAC THENL
+   [CONJ_TAC THEN
+    REPEAT(MATCH_MP_TAC
+            (SET_RULE `s SUBSET u /\ t SUBSET u ==> (s UNION t) SUBSET u`) THEN
+           CONJ_TAC) THEN
+    TRY(REWRITE_TAC[PATH_IMAGE_LINEPATH] THEN
+        MATCH_MP_TAC(REWRITE_RULE[CONVEX_CONTAINS_SEGMENT]
+           (CONJUNCT1 (SPEC_ALL CONVEX_INTERVAL))) THEN
+        ASM_REWRITE_TAC[IN_INTERVAL; FORALL_2; DIMINDEX_2; VECTOR_2] THEN
+        ASM_REAL_ARITH_TAC) THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `interval[a:real^2,b:real^2]` THEN
+    ASM_REWRITE_TAC[SUBSET_REFL] THEN
+    REWRITE_TAC[SUBSET_INTERVAL; FORALL_2; DIMINDEX_2; VECTOR_2] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `z:real^2` THEN
+  REWRITE_TAC[PATH_IMAGE_LINEPATH] THEN
+  SUBGOAL_THEN
+   `!f s:real^2->bool. path_image f UNION s =
+                       path_image f UNION (s DIFF {pathstart f,pathfinish f})`
+   (fun th -> ONCE_REWRITE_TAC[th] THEN
+              REWRITE_TAC[GSYM UNION_ASSOC] THEN
+              ONCE_REWRITE_TAC[SET_RULE `(s UNION t) UNION u =
+                                         u UNION t UNION s`] THEN
+              ONCE_REWRITE_TAC[th])
+  THENL
+   [REWRITE_TAC[EXTENSION; IN_UNION; IN_DIFF; IN_INSERT; NOT_IN_EMPTY] THEN
+    ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; PATHFINISH_IN_PATH_IMAGE];
+    ALL_TAC] THEN
+  REWRITE_TAC[IN_UNION; IN_DIFF; GSYM DISJ_ASSOC; LEFT_OR_DISTRIB;
+              RIGHT_OR_DISTRIB; GSYM CONJ_ASSOC;
+              SET_RULE `~(z IN {x,y}) <=> ~(z = x) /\ ~(z = y)`] THEN
+  DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN MP_TAC) THEN
+  ASM_SIMP_TAC[SEGMENT_VERTICAL; SEGMENT_HORIZONTAL; VECTOR_2] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  UNDISCH_TAC `path_image (f:real^1->real^2) SUBSET interval [a,b]` THEN
+  REWRITE_TAC[SUBSET] THEN DISCH_THEN(MP_TAC o SPEC `z:real^2`) THEN
+  UNDISCH_TAC `path_image (g:real^1->real^2) SUBSET interval [a,b]` THEN
+  REWRITE_TAC[SUBSET] THEN DISCH_THEN(MP_TAC o SPEC `z:real^2`) THEN
+  ASM_REWRITE_TAC[IN_INTERVAL; FORALL_2; DIMINDEX_2] THEN
+  REPEAT(DISCH_THEN(fun th -> if is_imp(concl th) then ALL_TAC else
+    ASSUME_TAC th)) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN TRY REAL_ARITH_TAC THEN
+  REWRITE_TAC[CART_EQ; FORALL_2; DIMINDEX_2] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complement in dimension N >= 2 of set homeomorphic to any interval in     *)
+(* any dimension is (path-)connected. This naively generalizes the argument  *)
+(* in Ryuji Maehara's paper "The Jordan curve theorem via the Brouwer        *)
+(* fixed point theorem", American Mathematical Monthly 1984.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let UNBOUNDED_COMPONENTS_COMPLEMENT_ABSOLUTE_RETRACT = prove
+ (`!s c. compact s /\ s retract_of (:real^N) /\
+         c IN components((:real^N) DIFF s)
+         ==> ~bounded c`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; components; FORALL_IN_GSPEC] THEN
+  GEN_TAC THEN DISCH_TAC THEN DISCH_TAC THEN X_GEN_TAC `y:real^N` THEN
+  REWRITE_TAC[IN_DIFF; IN_UNIV] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `open((:real^N) DIFF s)` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[GSYM closed; COMPACT_IMP_CLOSED]; ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [retract_of]) THEN
+  REWRITE_TAC[retraction; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `r:real^N->real^N` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`connected_component ((:real^N) DIFF s) y`;
+                 `s:real^N->bool`;
+                 `r:real^N->real^N`]
+                FRONTIER_SUBSET_RETRACTION) THEN
+  ASM_SIMP_TAC[NOT_IMP; INTERIOR_OPEN; OPEN_CONNECTED_COMPONENT] THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[frontier] THEN
+    ASM_SIMP_TAC[INTERIOR_OPEN; OPEN_CONNECTED_COMPONENT] THEN
+    REWRITE_TAC[SUBSET; IN_DIFF] THEN X_GEN_TAC `z:real^N` THEN
+    ASM_CASES_TAC `(z:real^N) IN s` THEN ASM_REWRITE_TAC[] THEN
+    ASM_SIMP_TAC[IN_CLOSURE_CONNECTED_COMPONENT; IN_UNIV; IN_DIFF] THEN
+    CONV_TAC TAUT;
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNIV];
+    ASM SET_TAC[];
+    MATCH_MP_TAC(SET_RULE
+     `~(c = {}) /\ c SUBSET (:real^N) DIFF s ==> ~(c SUBSET s)`) THEN
+    REWRITE_TAC[CONNECTED_COMPONENT_SUBSET; CONNECTED_COMPONENT_EQ_EMPTY] THEN
+    ASM_REWRITE_TAC[IN_UNIV; IN_DIFF]]);;
+
+let CONNECTED_COMPLEMENT_ABSOLUTE_RETRACT = prove
+ (`!s. 2 <= dimindex(:N) /\ compact s /\ s retract_of (:real^N)
+       ==> connected((:real^N) DIFF s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CONNECTED_EQ_CONNECTED_COMPONENT_EQ] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC COBOUNDED_UNIQUE_UNBOUNDED_COMPONENT THEN
+  ASM_SIMP_TAC[SET_RULE`UNIV DIFF (UNIV DIFF s) = s`; COMPACT_IMP_BOUNDED] THEN
+  CONJ_TAC THEN
+  MATCH_MP_TAC UNBOUNDED_COMPONENTS_COMPLEMENT_ABSOLUTE_RETRACT THEN
+  EXISTS_TAC `s:real^N->bool` THEN
+  ASM_REWRITE_TAC[IN_COMPONENTS] THEN ASM_MESON_TAC[]);;
+
+let PATH_CONNECTED_COMPLEMENT_ABSOLUTE_RETRACT = prove
+ (`!s:real^N->bool.
+        2 <= dimindex(:N) /\ compact s /\ s retract_of (:real^N)
+        ==> path_connected((:real^N) DIFF s)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN FIRST_ASSUM
+   (MP_TAC o MATCH_MP CONNECTED_COMPLEMENT_ABSOLUTE_RETRACT) THEN
+  MATCH_MP_TAC EQ_IMP THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC PATH_CONNECTED_EQ_CONNECTED THEN
+  REWRITE_TAC[GSYM closed] THEN
+  ASM_MESON_TAC[HOMEOMORPHIC_COMPACTNESS; COMPACT_INTERVAL;
+                COMPACT_IMP_CLOSED]);;
+
+let CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT = prove
+ (`!s:real^N->bool t:real^M->bool.
+        2 <= dimindex(:N) /\ s homeomorphic t /\ convex t /\ compact t
+        ==> connected((:real^N) DIFF s)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[DIFF_EMPTY; CONNECTED_UNIV] THEN
+  MATCH_MP_TAC CONNECTED_COMPLEMENT_ABSOLUTE_RETRACT THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[HOMEOMORPHIC_COMPACTNESS]; ALL_TAC] THEN
+  MATCH_MP_TAC ABSOLUTE_RETRACT_HOMEOMORPHIC_CONVEX_COMPACT THEN
+  EXISTS_TAC `t:real^M->bool` THEN ASM_REWRITE_TAC[SUBSET_UNIV]);;
+
+let PATH_CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT = prove
+ (`!s:real^N->bool t:real^M->bool.
+        2 <= dimindex(:N) /\ s homeomorphic t /\ convex t /\ compact t
+        ==> path_connected((:real^N) DIFF s)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN FIRST_ASSUM
+   (MP_TAC o MATCH_MP CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT) THEN
+  MATCH_MP_TAC EQ_IMP THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC PATH_CONNECTED_EQ_CONNECTED THEN
+  REWRITE_TAC[GSYM closed] THEN
+  ASM_MESON_TAC[HOMEOMORPHIC_COMPACTNESS; COMPACT_INTERVAL;
+                COMPACT_IMP_CLOSED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In particular, apply all these to the special case of an arc.             *)
+(* ------------------------------------------------------------------------- *)
+
+let RETRACTION_ARC = prove
+ (`!p. arc p
+       ==> ?f. f continuous_on (:real^N) /\
+               IMAGE f (:real^N) SUBSET path_image p /\
+               (!x. x IN path_image p ==> f x = x)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(:real^N)` o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        ABSOLUTE_RETRACT_PATH_IMAGE_ARC)) THEN
+  REWRITE_TAC[SUBSET_UNIV; retract_of; retraction]);;
+
+let PATH_CONNECTED_ARC_COMPLEMENT = prove
+ (`!p. 2 <= dimindex(:N) /\ arc p
+       ==> path_connected((:real^N) DIFF path_image p)`,
+  REWRITE_TAC[arc; path] THEN REPEAT STRIP_TAC THEN SIMP_TAC[path_image] THEN
+  MP_TAC(ISPECL [`path_image p:real^N->bool`; `interval[vec 0:real^1,vec 1]`]
+        PATH_CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT) THEN
+  ASM_REWRITE_TAC[CONVEX_INTERVAL; COMPACT_INTERVAL; path_image] THEN
+  DISCH_THEN MATCH_MP_TAC THEN ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+  MATCH_MP_TAC HOMEOMORPHIC_COMPACT THEN
+  EXISTS_TAC `p:real^1->real^N` THEN ASM_REWRITE_TAC[COMPACT_INTERVAL]);;
+
+let CONNECTED_ARC_COMPLEMENT = prove
+ (`!p. 2 <= dimindex(:N) /\ arc p
+       ==> connected((:real^N) DIFF path_image p)`,
+  SIMP_TAC[PATH_CONNECTED_ARC_COMPLEMENT; PATH_CONNECTED_IMP_CONNECTED]);;
+
+let INSIDE_ARC_EMPTY = prove
+ (`!p:real^1->real^N. arc p ==> inside(path_image p) = {}`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `dimindex(:N) = 1` THENL
+   [MATCH_MP_TAC INSIDE_CONVEX THEN
+    ASM_SIMP_TAC[CONVEX_CONNECTED_1_GEN; CONNECTED_PATH_IMAGE; ARC_IMP_PATH];
+    MATCH_MP_TAC INSIDE_BOUNDED_COMPLEMENT_CONNECTED_EMPTY THEN
+    ASM_SIMP_TAC[BOUNDED_PATH_IMAGE; ARC_IMP_PATH] THEN
+    MATCH_MP_TAC CONNECTED_ARC_COMPLEMENT THEN
+    ASM_REWRITE_TAC[ARITH_RULE `2 <= n <=> 1 <= n /\ ~(n = 1)`] THEN
+    REWRITE_TAC[DIMINDEX_GE_1]]);;
+
+let INSIDE_SIMPLE_CURVE_IMP_CLOSED = prove
+ (`!g x:real^N.
+        simple_path g /\ x IN inside(path_image g)
+        ==> pathfinish g = pathstart g`,
+  MESON_TAC[ARC_SIMPLE_PATH; INSIDE_ARC_EMPTY; NOT_IN_EMPTY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The Jordan curve theorem, again approximately following Maehara.          *)
+(* ------------------------------------------------------------------------- *)
+
+let JORDAN_CURVE_THEOREM = prove
+ (`!c:real^1->real^2.
+        simple_path c /\ pathfinish c = pathstart c
+        ==> ?ins out.
+                 ~(ins = {}) /\ open ins /\ connected ins /\
+                 ~(out = {}) /\ open out /\ connected out /\
+                 bounded ins /\ ~bounded out /\
+                 ins INTER out = {} /\
+                 ins UNION out = (:real^2) DIFF path_image c /\
+                 frontier ins = path_image c /\
+                 frontier out = path_image c`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `path_image(c:real^1->real^2)` DIAMETER_BOUNDED_BOUND) THEN
+  MP_TAC(ISPEC `path_image(c:real^1->real^2)` DIAMETER_COMPACT_ATTAINED) THEN
+  ASM_SIMP_TAC[COMPACT_PATH_IMAGE; PATH_IMAGE_NONEMPTY; SIMPLE_PATH_IMP_PATH;
+               COMPACT_IMP_BOUNDED; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^2`; `b:real^2`] THEN
+  ABBREV_TAC `m:real^2 = midpoint(a,b)` THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN REWRITE_TAC[IMP_IMP] THEN
+  GEOM_ORIGIN_TAC `m:real^2` THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[midpoint; VECTOR_ARITH
+   `inv(&2) % (a + b):real^N = vec 0 <=> a = --b`] THEN
+  ASM_CASES_TAC `a:real^2 = --b` THEN ASM_REWRITE_TAC[] THEN
+  POP_ASSUM(K ALL_TAC) THEN
+  REWRITE_TAC[NORM_ARITH `norm(--b - b) = &2 * norm(b)`] THEN
+  ASM_CASES_TAC
+   `diameter(path_image(c:real^1->real^2)) = &2 * norm(b:real^2)` THEN
+  ASM_REWRITE_TAC[] THEN POP_ASSUM(K ALL_TAC) THEN
+  GEOM_NORMALIZE_TAC `b:real^2` THEN CONJ_TAC THENL
+   [REWRITE_TAC[NORM_0; REAL_MUL_RZERO] THEN
+    REWRITE_TAC[NORM_ARITH `norm(x - y) <= &0 <=> x = y`] THEN
+    REWRITE_TAC[simple_path; path_image; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE] THEN
+    SUBGOAL_THEN
+      `(vec 0:real^1) IN interval[vec 0,vec 1] /\
+       lift(&1 / &2) IN interval[vec 0,vec 1] /\
+       ~(lift(&1 / &2) = vec 0) /\ ~(lift(&1 / &2) = vec 1)`
+      (fun th -> MESON_TAC[th]) THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP; GSYM DROP_EQ] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  GEOM_BASIS_MULTIPLE_TAC 1 `b:real^2` THEN
+  GEN_TAC THEN DISCH_TAC THEN
+  SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_2; ARITH] THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 <= b ==> (abs b * &1 = &1 <=> b = &1)`] THEN
+  DISCH_TAC THEN POP_ASSUM_LIST(K ALL_TAC) THEN
+  REWRITE_TAC[VECTOR_MUL_LID; REAL_MUL_RID; GSYM CONJ_ASSOC] THEN
+  X_GEN_TAC `c:real^1->real^2` THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `(!z:real^2. z IN path_image c /\ z$1 = -- &1 <=> z = --basis 1) /\
+    (!z:real^2. z IN path_image c /\ z$1 = &1 <=> z = basis 1)`
+  (CONJUNCTS_THEN2 (LABEL_TAC "touchleft") (LABEL_TAC "touchright")) THENL
+   [CONJ_TAC THEN X_GEN_TAC `z:real^2` THEN EQ_TAC THEN
+    ASM_SIMP_TAC[BASIS_COMPONENT; VECTOR_NEG_COMPONENT; DIMINDEX_2; ARITH] THEN
+    STRIP_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o ISPECL [`basis 1:real^2`; `z:real^2`]);
+      FIRST_X_ASSUM(MP_TAC o ISPECL [`--basis 1:real^2`; `z:real^2`])] THEN
+    ASM_REWRITE_TAC[NORM_LE_SQUARE; DOT_2; VECTOR_SUB_COMPONENT] THEN
+    ASM_SIMP_TAC[BASIS_COMPONENT; DIMINDEX_2; ARITH; VECTOR_NEG_COMPONENT;
+                 CART_EQ; FORALL_2] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[REAL_ARITH
+     `&4 + (&0 - x) * (&0 - x) <= &4 <=> x pow 2 <= &0`] THEN
+    ONCE_REWRITE_TAC[REAL_RING `z = &0 <=> z * z = &0`] THEN
+    SIMP_TAC[REAL_POW_2; REAL_LE_SQUARE; GSYM REAL_LE_ANTISYM];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!z:real^2. z IN path_image c ==> abs(z$1) <= &1`
+  (LABEL_TAC "xbound") THENL
+   [X_GEN_TAC `z:real^2` THEN STRIP_TAC THEN
+    REWRITE_TAC[REAL_ABS_BOUNDS] THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o ISPECL [`basis 1:real^2`; `z:real^2`]);
+      FIRST_X_ASSUM(MP_TAC o ISPECL [`z:real^2`; `--basis 1:real^2`])] THEN
+    ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[REAL_NOT_LE] THEN DISCH_TAC THEN MATCH_MP_TAC(REAL_ARITH
+     `abs(z$1) <= norm z /\ &2 < z$1 ==> &2 < norm z`) THEN
+    SIMP_TAC[COMPONENT_LE_NORM; DIMINDEX_2; ARITH] THEN
+    SIMP_TAC[VECTOR_SUB_COMPONENT; VECTOR_NEG_COMPONENT;
+             BASIS_COMPONENT; DIMINDEX_2; ARITH] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!z:real^2. z IN path_image c ==> abs(z$2) <= &9 / &5`
+  (LABEL_TAC "ybound") THENL
+   [REPEAT STRIP_TAC THEN FIRST_X_ASSUM(fun th ->
+     MP_TAC(ISPECL [`basis 1:real^2`; `z:real^2`] th) THEN
+     MP_TAC(ISPECL [`--basis 1:real^2`; `z:real^2`] th)) THEN
+    SUBST1_TAC(REAL_ARITH `&9 / &5 = abs(&9 / &5)`) THEN
+    ASM_REWRITE_TAC[NORM_LE_SQUARE; REAL_LE_SQUARE_ABS] THEN
+    SIMP_TAC[DOT_2; VECTOR_SUB_COMPONENT; BASIS_COMPONENT;
+             DIMINDEX_2; ARITH; VECTOR_NEG_COMPONENT] THEN
+    MP_TAC(ISPEC `(z:real^2)$1` REAL_LE_SQUARE) THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!z:real^2. z IN path_image c ==> abs(z$2) < &2`
+  (LABEL_TAC "ybounds") THENL
+   [ASM_MESON_TAC[REAL_ARITH `x <= &9 / &5 ==> x < &2`]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?t. t$1 = &0 /\ t IN path_image c /\
+        !z:real^2. z$1 = &0 /\ z IN path_image c ==> z$2 <= t$2`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPECL
+     [`\z:real^2. z$2`; `{z:real^2 | z$1 = &0} INTER path_image c`]
+     CONTINUOUS_ATTAINS_SUP) THEN
+    SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT; DIMINDEX_2; ARITH; o_DEF] THEN
+    REWRITE_TAC[IN_INTER; IN_ELIM_THM; GSYM CONJ_ASSOC] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[CLOSED_INTER_COMPACT; COMPACT_PATH_IMAGE;
+                 CLOSED_STANDARD_HYPERPLANE; SIMPLE_PATH_IMP_PATH] THEN
+    ONCE_REWRITE_TAC[INTER_COMM] THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN
+    MATCH_MP_TAC CONNECTED_IVT_COMPONENT THEN
+    ASM_SIMP_TAC[CONNECTED_PATH_IMAGE; SIMPLE_PATH_IMP_PATH] THEN
+    MAP_EVERY EXISTS_TAC [`--basis 1:real^2`; `basis 1:real^2`] THEN
+    ASM_SIMP_TAC[BASIS_COMPONENT; DIMINDEX_2; ARITH; VECTOR_NEG_COMPONENT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(abs((t:real^2)$2) <= &9 / &5 /\ abs(t$2) < &2) /\
+    t IN interval[--vector[&1; &9 / &5],vector[&1; &9 / &5]] /\
+    t IN interval[--vector[&1; &2],vector[&1; &2]]`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[IN_INTERVAL; FORALL_2; DIMINDEX_2; VECTOR_2;
+                    VECTOR_NEG_COMPONENT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?U D. arc U /\ arc D /\
+          pathstart U = --basis 1 /\ pathfinish U = basis 1 /\
+          pathstart D = basis 1 /\ pathfinish D = --basis 1 /\
+          (t:real^2) IN path_image U /\
+          (path_image U) INTER (path_image D) = {--basis 1,basis 1} /\
+          path_image (c:real^1->real^2) = path_image(U) UNION path_image(D)`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPECL [`c:real^1->real^2`; `--basis 1:real^2`; `basis 1:real^2`]
+        EXISTS_DOUBLE_ARC) THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH `--b = b <=> b = vec 0`] THEN
+    ASM_SIMP_TAC[BASIS_NONZERO; DIMINDEX_GE_1; LE_REFL] THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`U:real^1->real^2`; `D:real^1->real^2`] THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+    UNDISCH_TAC `(t:real^2) IN path_image U UNION path_image D` THEN
+    ASM_SIMP_TAC[PATH_IMAGE_JOIN; ARC_IMP_PATH; IN_UNION] THEN STRIP_TAC THENL
+     [MAP_EVERY EXISTS_TAC [`U:real^1->real^2`; `D:real^1->real^2`] THEN
+      ASM_REWRITE_TAC[];
+      MAP_EVERY EXISTS_TAC
+       [`reversepath D:real^1->real^2`; `reversepath U:real^1->real^2`] THEN
+      ONCE_REWRITE_TAC[INTER_COMM] THEN
+      ASM_SIMP_TAC[PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+        PATH_IMAGE_JOIN; PATH_IMAGE_REVERSEPATH; SIMPLE_PATH_JOIN_LOOP;
+        ARC_REVERSEPATH] THEN
+      ASM SET_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `path_image U INTER path_image D SUBSET {--basis 1:real^2, basis 1}`
+  ASSUME_TAC THENL [ASM_REWRITE_TAC[SUBSET_REFL]; ALL_TAC] THEN
+  SUBGOAL_THEN `simple_path(U ++ D:real^1->real^2)` ASSUME_TAC THENL
+   [MATCH_MP_TAC SIMPLE_PATH_JOIN_LOOP THEN ASM_REWRITE_TAC[SUBSET_REFL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `path_image(U ++ D:real^1->real^2) = path_image(U) UNION path_image(D)`
+  ASSUME_TAC THENL
+   [ASM_SIMP_TAC[PATH_IMAGE_JOIN; ARC_IMP_PATH]; ALL_TAC] THEN
+  UNDISCH_THEN `path_image c :real^2->bool = path_image U UNION path_image D`
+  SUBST_ALL_TAC THEN POP_ASSUM_LIST(MAP_EVERY
+     (fun th -> if free_in `c:real^1->real^2` (concl th) then ALL_TAC
+                else ASSUME_TAC th) o rev) THEN
+  SUBGOAL_THEN
+   `path_image(U:real^1->real^2) UNION path_image(D) SUBSET
+    interval[--vector[&1; &9 / &5],vector[&1; &9 / &5]] /\
+    path_image(U) UNION path_image(D) SUBSET
+    interval[--vector[&1; &2],vector[&1; &2]]`
+  MP_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `p SUBSET s /\ s SUBSET t ==> p SUBSET s /\ p SUBSET t`) THEN
+    ASM_SIMP_TAC[SUBSET_INTERVAL; SUBSET; DIMINDEX_2; FORALL_2; VECTOR_2;
+                 VECTOR_NEG_COMPONENT; IN_INTERVAL; REAL_BOUNDS_LE] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV;
+    REWRITE_TAC[UNION_SUBSET] THEN STRIP_TAC] THEN
+  SUBGOAL_THEN
+   `?p. p$1 = &0 /\ p IN path_image U /\
+        !z:real^2. z$1 = &0 /\ z IN path_image U ==> p$2 <= z$2`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPECL
+     [`\z:real^2. z$2`; `{z:real^2 | z$1 = &0} INTER path_image U`]
+     CONTINUOUS_ATTAINS_INF) THEN
+    SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT; DIMINDEX_2; ARITH; o_DEF] THEN
+    REWRITE_TAC[IN_INTER; IN_ELIM_THM; GSYM CONJ_ASSOC] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[CLOSED_INTER_COMPACT; COMPACT_PATH_IMAGE;
+                 CLOSED_STANDARD_HYPERPLANE; ARC_IMP_PATH] THEN
+    ONCE_REWRITE_TAC[INTER_COMM] THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN
+    MATCH_MP_TAC CONNECTED_IVT_COMPONENT THEN
+    ASM_SIMP_TAC[CONNECTED_PATH_IMAGE; ARC_IMP_PATH] THEN
+    MAP_EVERY EXISTS_TAC [`pathstart U:real^2`; `pathfinish U:real^2`] THEN
+    REWRITE_TAC[PATHSTART_IN_PATH_IMAGE; PATHFINISH_IN_PATH_IMAGE] THEN
+    ASM_SIMP_TAC[BASIS_COMPONENT; DIMINDEX_2; ARITH; VECTOR_NEG_COMPONENT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(p:real^2)$2 <= (t:real^2)$2` ASSUME_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(abs((p:real^2)$2) <= &9 / &5 /\ abs(p$2) < &2) /\
+    p IN interval[--vector[&1; &9 / &5],vector[&1; &9 / &5]] /\
+    p IN interval[--vector[&1; &2],vector[&1; &2]]`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[IN_UNION]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[IN_INTERVAL; FORALL_2; DIMINDEX_2; VECTOR_2;
+                    VECTOR_NEG_COMPONENT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`U:real^1->real^2`; `t:real^2`; `p:real^2`]
+        EXISTS_SUBPATH_OF_ARC_NOENDS) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(SET_RULE
+     `~(a = c) /\ ~(a = d) /\ ~(b = c) /\ ~(b = d)
+      ==> {a,b} INTER {c,d} = {}`) THEN
+    REPEAT CONJ_TAC THEN DISCH_THEN(MP_TAC o AP_TERM `\z:real^2. z$1`) THEN
+    ASM_SIMP_TAC[VECTOR_NEG_COMPONENT; BASIS_COMPONENT; DIMINDEX_2; ARITH] THEN
+    REAL_ARITH_TAC;
+    DISCH_THEN(X_CHOOSE_THEN `h:real^1->real^2` STRIP_ASSUME_TAC)] THEN
+  SUBGOAL_THEN
+   `~((t:real^2) IN path_image D) /\ ~(p IN path_image D)`
+  STRIP_ASSUME_TAC THENL
+   [REPEAT CONJ_TAC THEN
+    UNDISCH_TAC
+     `path_image U INTER path_image D SUBSET {--basis 1:real^2, basis 1}` THEN
+    MATCH_MP_TAC(SET_RULE
+     `(t IN s ==> t IN u) /\ ~(t IN v)
+      ==> u SUBSET v ==> ~(t IN s)`) THEN
+    ASM_SIMP_TAC[IN_INTER] THEN REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+    DISCH_THEN(DISJ_CASES_THEN (MP_TAC o AP_TERM `\z:real^2. z$1`)) THEN
+    ASM_SIMP_TAC[VECTOR_NEG_COMPONENT; BASIS_COMPONENT; DIMINDEX_2; ARITH] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?q. q$2 <= (p:real^2)$2 /\ q$1 = &0 /\ q IN path_image D /\
+        !z:real^2. z$2 <= p$2 /\ z$1 = &0 /\ z IN path_image D ==> z$2 <= q$2`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPECL
+     [`\z:real^2. z$2`;
+      `{z:real^2 | z$2 <= (p:real^2)$2} INTER
+       {z:real^2 | z$1 = &0} INTER path_image D`]
+     CONTINUOUS_ATTAINS_SUP) THEN
+    SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT; DIMINDEX_2; ARITH; o_DEF] THEN
+    REWRITE_TAC[IN_INTER; IN_ELIM_THM; GSYM CONJ_ASSOC] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[CLOSED_INTER_COMPACT; COMPACT_PATH_IMAGE;
+                 CLOSED_STANDARD_HYPERPLANE; ARC_IMP_PATH] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[GSYM INTER_ASSOC] THEN MATCH_MP_TAC CLOSED_INTER_COMPACT THEN
+      ASM_SIMP_TAC[COMPACT_PATH_IMAGE; ARC_IMP_PATH] THEN
+      ASM_SIMP_TAC[CLOSED_INTER; CLOSED_STANDARD_HYPERPLANE;
+                   CLOSED_HALFSPACE_COMPONENT_LE];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`reversepath D:real^1->real^2`;
+      `linepath(--(&2 % basis 2):real^2,p) ++ reversepath h ++
+       linepath(t,&2 % basis 2)`;
+      `--vector[&1; &2]:real^2`; `vector[&1; &2]:real^2`]
+     FASHODA) THEN
+    ASM_SIMP_TAC[ARC_IMP_PATH; PATH_REVERSEPATH; PATH_JOIN; PATH_IMAGE_JOIN;
+                 PATHSTART_JOIN; PATHFINISH_JOIN; PATHSTART_LINEPATH;
+                 PATHFINISH_LINEPATH; PATH_LINEPATH; PATH_IMAGE_REVERSEPATH;
+                 PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH] THEN
+    ANTS_TAC THENL
+     [ASM_SIMP_TAC[UNION_SUBSET; PATH_IMAGE_LINEPATH; SEGMENT_CONVEX_HULL;
+                SUBSET_HULL; CONVEX_INTERVAL; INSERT_SUBSET; EMPTY_SUBSET] THEN
+      SIMP_TAC[IN_INTERVAL; DIMINDEX_2; FORALL_2; VECTOR_NEG_COMPONENT;
+               VECTOR_MUL_COMPONENT; VECTOR_2; BASIS_COMPONENT; ARITH] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER; IN_ELIM_THM] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `z:real^2` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    ASM_REWRITE_TAC[IN_UNION; PATH_IMAGE_LINEPATH] THEN STRIP_TAC THENL
+     [MP_TAC(ISPECL [`--(&2 % basis 2):real^2`; `p:real^2`; `z:real^2`]
+        SEGMENT_VERTICAL) THEN
+      ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; BASIS_COMPONENT; DIMINDEX_2; ARITH;
+                   VECTOR_NEG_COMPONENT] THEN
+      ASM_REAL_ARITH_TAC;
+      UNDISCH_TAC
+       `path_image(h:real^1->real^2) SUBSET
+        path_image U DIFF {pathstart U, pathfinish U}` THEN
+      ASM_REWRITE_TAC[SUBSET] THEN
+      DISCH_THEN(MP_TAC o SPEC `z:real^2`) THEN ASM SET_TAC[];
+      MP_TAC(ISPECL [`t:real^2`; `&2 % basis 2:real^2`; `z:real^2`]
+        SEGMENT_VERTICAL) THEN
+      ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; BASIS_COMPONENT; DIMINDEX_2; ARITH;
+                   VECTOR_NEG_COMPONENT] THEN
+      ASM_CASES_TAC `z:real^2 = t` THENL
+       [ASM_MESON_TAC[]; UNDISCH_TAC `~(z:real^2 = t)`] THEN
+      ASM_REWRITE_TAC[CART_EQ; FORALL_2; DIMINDEX_2] THEN
+      ASM_CASES_TAC `(z:real^2)$1 = &0` THEN
+      ASM_REWRITE_TAC[REAL_MUL_RZERO] THEN
+      SUBGOAL_THEN `(z:real^2)$2 <= (t:real^2)$2` MP_TAC THENL
+       [ASM SET_TAC[]; ASM_REAL_ARITH_TAC]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?b. b$1 = &0 /\ b IN path_image D /\
+        !z:real^2. z$1 = &0 /\ z IN path_image D ==> b$2 <= z$2`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPECL
+     [`\z:real^2. z$2`; `{z:real^2 | z$1 = &0} INTER path_image D`]
+     CONTINUOUS_ATTAINS_INF) THEN
+    SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT; DIMINDEX_2; ARITH; o_DEF] THEN
+    REWRITE_TAC[IN_INTER; IN_ELIM_THM; GSYM CONJ_ASSOC] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[CLOSED_INTER_COMPACT; COMPACT_PATH_IMAGE;
+                 CLOSED_STANDARD_HYPERPLANE; ARC_IMP_PATH] THEN
+    ONCE_REWRITE_TAC[INTER_COMM] THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN
+    MATCH_MP_TAC CONNECTED_IVT_COMPONENT THEN
+    ASM_SIMP_TAC[CONNECTED_PATH_IMAGE; ARC_IMP_PATH] THEN
+    MAP_EVERY EXISTS_TAC [`pathfinish D:real^2`; `pathstart D:real^2`] THEN
+    REWRITE_TAC[PATHSTART_IN_PATH_IMAGE; PATHFINISH_IN_PATH_IMAGE] THEN
+    ASM_SIMP_TAC[BASIS_COMPONENT; DIMINDEX_2; ARITH; VECTOR_NEG_COMPONENT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`D:real^1->real^2`; `q:real^2`; `b:real^2`]
+        EXISTS_SUBPATH_OF_ARC_NOENDS) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(SET_RULE
+     `~(a = c) /\ ~(a = d) /\ ~(b = c) /\ ~(b = d)
+      ==> {a,b} INTER {c,d} = {}`) THEN
+    REPEAT CONJ_TAC THEN DISCH_THEN(MP_TAC o AP_TERM `\z:real^2. z$1`) THEN
+    ASM_SIMP_TAC[VECTOR_NEG_COMPONENT; BASIS_COMPONENT; DIMINDEX_2; ARITH] THEN
+    REAL_ARITH_TAC;
+    DISCH_THEN(X_CHOOSE_THEN `l:real^1->real^2` STRIP_ASSUME_TAC)] THEN
+  SUBGOAL_THEN
+   `~((q:real^2) IN path_image U) /\ ~(b IN path_image U)`
+  STRIP_ASSUME_TAC THENL
+   [REPEAT CONJ_TAC THEN
+    UNDISCH_TAC
+     `path_image U INTER path_image D SUBSET {--basis 1:real^2, basis 1}` THEN
+    MATCH_MP_TAC(SET_RULE
+     `(t IN s ==> t IN u) /\ ~(t IN v)
+      ==> u SUBSET v ==> ~(t IN s)`) THEN
+    ASM_SIMP_TAC[IN_INTER] THEN REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+    DISCH_THEN(DISJ_CASES_THEN (MP_TAC o AP_TERM `\z:real^2. z$1`)) THEN
+    ASM_SIMP_TAC[VECTOR_NEG_COMPONENT; BASIS_COMPONENT; DIMINDEX_2; ARITH] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~(p:real^2 = q)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `(q:real^2)$2 < (p:real^2)$2` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[REAL_LT_LE] THEN DISCH_TAC THEN
+    UNDISCH_TAC `~(p:real^2 = q)` THEN
+    ASM_REWRITE_TAC[DIMINDEX_2; FORALL_2; CART_EQ];
+    ALL_TAC] THEN
+  ABBREV_TAC `y:real^2 = midpoint(p,q)` THEN
+  EXISTS_TAC
+   `connected_component ((:real^2) DIFF path_image(U ++ D)) y` THEN
+  EXISTS_TAC
+   `connected_component ((:real^2) DIFF path_image(U ++ D))
+                        (&2 % basis 2)` THEN
+  REWRITE_TAC[CONNECTED_COMPONENT_EQ_EMPTY; CONNECTED_CONNECTED_COMPONENT] THEN
+  ABBREV_TAC `K = (:real^2) DIFF path_image(U ++ D)` THEN
+  SUBGOAL_THEN `open(K:real^2->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "K" THEN REWRITE_TAC[GSYM closed] THEN
+    ASM_SIMP_TAC[COMPACT_PATH_IMAGE; SIMPLE_PATH_IMP_PATH;
+                 COMPACT_IMP_CLOSED];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[OPEN_CONNECTED_COMPONENT] THEN
+  ABBREV_TAC `n:real^2 = &2 % basis 2` THEN
+  SUBGOAL_THEN `(y:real^2)$1 = &0 /\ (n:real^2)$1 = &0` STRIP_ASSUME_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["y"; "n"] THEN
+    SIMP_TAC[BASIS_COMPONENT; VECTOR_MUL_COMPONENT; DIMINDEX_2; ARITH] THEN
+    REWRITE_TAC[midpoint; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+    ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(y:real^2)$2 = ((p:real^2)$2 + (q:real^2)$2) / &2`
+  ASSUME_TAC THENL
+   [EXPAND_TAC "y" THEN
+    REWRITE_TAC[midpoint; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(n:real^2)$2 = &2` ASSUME_TAC THENL
+   [EXPAND_TAC "n" THEN
+    SIMP_TAC[BASIS_COMPONENT; VECTOR_MUL_COMPONENT; DIMINDEX_2; ARITH] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(b:real^2)$2 <= (q:real^2)$2` ASSUME_TAC THENL
+   [ASM_MESON_TAC[IN_UNION]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `((abs((q:real^2)$2) <= &9 / &5 /\ abs(q$2) < &2) /\
+     q IN interval[--vector[&1; &9 / &5],vector[&1; &9 / &5]] /\
+     q IN interval[--vector[&1; &2],vector[&1; &2]]) /\
+    ((abs((b:real^2)$2) <= &9 / &5 /\ abs(b$2) < &2) /\
+     b IN interval[--vector[&1; &9 / &5],vector[&1; &9 / &5]] /\
+     b IN interval[--vector[&1; &2],vector[&1; &2]])`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN
+    (CONJ_TAC THENL [ASM_MESON_TAC[IN_UNION]; ALL_TAC]) THEN
+    ASM_REWRITE_TAC[IN_INTERVAL; FORALL_2; DIMINDEX_2; VECTOR_2;
+                    VECTOR_NEG_COMPONENT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `path_image(h:real^1->real^2) SUBSET
+     interval[--vector[&1; &9 / &5],vector[&1; &9 / &5]] /\
+    path_image h SUBSET
+     interval[--vector[&1; &2],vector[&1; &2]] /\
+    path_image l SUBSET
+     interval[--vector[&1; &9 / &5],vector[&1; &9 / &5]] /\
+    path_image(l:real^1->real^2) SUBSET
+     interval[--vector[&1; &2],vector[&1; &2]] /\
+    ~(basis 1 IN  path_image h) /\
+    ~(basis 1 IN  path_image l) /\
+    ~(--basis 1 IN  path_image h) /\
+    ~(--basis 1 IN  path_image l)`
+  STRIP_ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(n:real^2) IN interval[--vector[&1; &2],vector[&1; &2]] /\
+    (--n) IN interval[--vector[&1; &2],vector[&1; &2]]`
+  STRIP_ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[IN_INTERVAL; DIMINDEX_2; FORALL_2; VECTOR_2;
+                    VECTOR_NEG_COMPONENT] THEN CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(q:real^2)$2 < (y:real^2)$2 /\ (y:real^2)$2 < (p:real^2)$2 /\
+    (q:real^2)$2 <= (y:real^2)$2 /\ (y:real^2)$2 <= (p:real^2)$2`
+  STRIP_ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[SYM(ASSUME
+   `path_image(U ++ D):real^2->bool = path_image U UNION path_image D`)] THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `(y:real^2) IN K` ASSUME_TAC THENL
+   [EXPAND_TAC "K" THEN REWRITE_TAC[IN_UNIV; IN_DIFF] THEN
+    ASM_REWRITE_TAC[IN_UNION; DE_MORGAN_THM] THEN ASM_MESON_TAC[REAL_NOT_LE];
+    ASM_REWRITE_TAC[]] THEN
+  SUBGOAL_THEN `(n:real^2) IN K` ASSUME_TAC THENL
+   [EXPAND_TAC "K" THEN ASM_REWRITE_TAC[IN_DIFF; IN_UNIV] THEN
+    ASM_MESON_TAC[REAL_ARITH `~(abs x < x)`];
+    ASM_REWRITE_TAC[]] THEN
+  MATCH_MP_TAC(TAUT `(a /\ b ==> c) /\ b /\ a /\ d ==> a /\ b /\ c /\ d`) THEN
+  CONJ_TAC THENL [MESON_TAC[CONNECTED_COMPONENT_NONOVERLAP]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(y:real^2) IN interval[--vector [&1; &9 / &5],vector [&1; &9 / &5]] /\
+    (y:real^2) IN interval[--vector [&1; &2],vector [&1; &2]]`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[IN_INTERVAL; FORALL_2; DIMINDEX_2; VECTOR_2;
+                VECTOR_NEG_COMPONENT] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `((:real^2) DIFF interval[--vector [&1; &9 / &5],vector [&1; &9 / &5]])
+    SUBSET connected_component K n /\
+    ((:real^2) DIFF interval[--vector [&1; &2],vector [&1; &2]])
+    SUBSET connected_component K n`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `i SUBSET j /\ UNIV DIFF i SUBSET s
+      ==> UNIV DIFF i SUBSET s /\ UNIV DIFF j SUBSET s`) THEN
+    REWRITE_TAC[SUBSET_INTERVAL; DIMINDEX_2; FORALL_2; VECTOR_2;
+                VECTOR_NEG_COMPONENT] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+    SIMP_TAC[CONNECTED_COMPLEMENT_BOUNDED_CONVEX; LE_REFL; DIMINDEX_2;
+             BOUNDED_INTERVAL; CONVEX_INTERVAL] THEN
+    EXPAND_TAC "K" THEN
+    ASM_REWRITE_TAC[SET_RULE `UNIV DIFF s SUBSET UNIV DIFF t <=> t SUBSET s`;
+                    UNION_SUBSET] THEN
+    ASM_REWRITE_TAC[IN_UNIV; IN_DIFF; IN_INTERVAL; FORALL_2; DIMINDEX_2;
+                    VECTOR_2; VECTOR_NEG_COMPONENT] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~bounded(connected_component K (n:real^2))` ASSUME_TAC THENL
+   [MATCH_MP_TAC COBOUNDED_IMP_UNBOUNDED THEN
+    MATCH_MP_TAC BOUNDED_SUBSET THEN
+    EXISTS_TAC `interval[--vector[&1; &2]:real^2,vector [&1; &2]]` THEN
+    ONCE_REWRITE_TAC[SET_RULE
+     `UNIV DIFF s SUBSET t <=> UNIV DIFF t SUBSET s`] THEN
+    ASM_REWRITE_TAC[BOUNDED_INTERVAL];
+    ASM_REWRITE_TAC[]] THEN
+  SUBGOAL_THEN `bounded(connected_component K (y:real^2))` ASSUME_TAC THENL
+   [REWRITE_TAC[bounded] THEN EXISTS_TAC `&4` THEN
+    X_GEN_TAC `z:real^2` THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN
+    ASM_SIMP_TAC[GSYM OPEN_PATH_CONNECTED_COMPONENT] THEN
+    REWRITE_TAC[path_component; IN] THEN
+    DISCH_THEN(X_CHOOSE_THEN `i:real^1->real^2` STRIP_ASSUME_TAC) THEN
+    STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`i:real^1->real^2`; `interval[--vector[&1; &2]:real^2,vector[&1; &2]]`]
+     EXISTS_PATH_SUBPATH_TO_FRONTIER_CLOSED) THEN
+    ASM_REWRITE_TAC[CLOSED_INTERVAL; NOT_IMP; SUBSET_INTER;
+                    GSYM CONJ_ASSOC] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[IN_INTERVAL; VECTOR_2; DIMINDEX_2; FORALL_2;
+                  VECTOR_NEG_COMPONENT; GSYM REAL_ABS_BOUNDS] THEN
+      STRIP_TAC THEN UNDISCH_TAC `&4 < norm(z:real^2)` THEN
+      REWRITE_TAC[REAL_NOT_LT] THEN
+      W(MP_TAC o PART_MATCH lhand NORM_LE_L1 o lhand o snd) THEN
+      REWRITE_TAC[DIMINDEX_2; SUM_2] THEN ASM_REAL_ARITH_TAC;
+      REWRITE_TAC[IN_DIFF; FRONTIER_CLOSED_INTERVAL; IN_INTERVAL;
+                  FORALL_2; DIMINDEX_2; VECTOR_2; VECTOR_NEG_COMPONENT] THEN
+      DISCH_THEN(X_CHOOSE_THEN `j:real^1->real^2` MP_TAC) THEN
+      REPEAT(DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC)) THEN
+      ASM_REWRITE_TAC[REAL_LT_LE; REAL_ARITH `x:real = i$j <=> i$j = x`] THEN
+      REWRITE_TAC[GSYM DE_MORGAN_THM; GSYM DISJ_ASSOC] THEN DISCH_TAC] THEN
+    SUBGOAL_THEN `path_image(j:real^1->real^2) SUBSET K` ASSUME_TAC THENL
+     [ASM_MESON_TAC[SUBSET_TRANS]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `~(pathfinish(j):real^2 = basis 1) /\ ~(pathfinish(j):real^2 = --basis 1)`
+    STRIP_ASSUME_TAC THENL
+     [REPEAT STRIP_TAC THEN UNDISCH_THEN
+       `path_image(j:real^1->real^2) SUBSET K`
+       (MP_TAC o SPEC `pathfinish(j):real^2` o REWRITE_RULE[SUBSET]) THEN
+      ASM_REWRITE_TAC[PATHFINISH_IN_PATH_IMAGE] THEN
+      EXPAND_TAC "K" THEN ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; IN_UNION];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?e:real^1->real^2.
+        path e /\ pathstart e = y /\
+        ((pathfinish e)$2 = -- &2 \/ (pathfinish e)$2 = &2) /\
+        path_image e SUBSET K /\
+        path_image e SUBSET interval[--vector [&1; &2],vector [&1; &2]]`
+    MP_TAC THENL
+     [FIRST_X_ASSUM(DISJ_CASES_THEN STRIP_ASSUME_TAC) THENL
+       [UNDISCH_TAC `~((pathfinish j):real^2 = --basis 1)` THEN
+        SIMP_TAC[CART_EQ; DIMINDEX_2; FORALL_2; BASIS_COMPONENT;
+                 VECTOR_NEG_COMPONENT; ARITH] THEN ASM_REWRITE_TAC[] THEN
+        DISCH_THEN(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+         `~(x = -- &0) ==> x < &0 \/ &0 < x`)) THENL
+         [EXISTS_TAC `(j:real^1->real^2) ++
+                      linepath(pathfinish j,--vector [&1; &2])` THEN
+          ASM_SIMP_TAC[PATH_JOIN; PATHSTART_JOIN; PATHFINISH_JOIN;
+            PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+            PATH_IMAGE_JOIN] THEN
+          REWRITE_TAC[VECTOR_2; VECTOR_NEG_COMPONENT] THEN
+          REWRITE_TAC[UNION_SUBSET; PATH_IMAGE_LINEPATH] THEN
+          ONCE_REWRITE_TAC[AC CONJ_ACI
+            `(a /\ b) /\ c /\ d <=> (a /\ c) /\ b /\ d`] THEN
+          CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN EXPAND_TAC "K" THEN
+          MATCH_MP_TAC(SET_RULE
+           `(!x. x IN s ==> x IN t /\ ~(x IN u))
+            ==> s SUBSET (UNIV DIFF u) /\ s SUBSET t`) THEN
+          X_GEN_TAC `x:real^2` THEN DISCH_TAC THEN
+          MP_TAC(ISPECL [`pathfinish(j:real^1->real^2)`;
+                         `--vector[&1; &2]:real^2`;
+                         `x:real^2`] SEGMENT_VERTICAL) THEN
+          ASM_SIMP_TAC[VECTOR_NEG_COMPONENT; VECTOR_2; IN_INTERVAL;
+                       FORALL_2; DIMINDEX_2] THEN
+          DISCH_TAC THEN CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+          DISCH_TAC THEN
+          UNDISCH_THEN
+           `!z:real^2. z IN path_image U UNION path_image D /\ z$1 = -- &1 <=>
+                       z = --basis 1`
+           (MP_TAC o SPEC `x:real^2`) THEN
+          ASM_REWRITE_TAC[] THEN
+          ASM_SIMP_TAC[CART_EQ; DIMINDEX_2; FORALL_2; BASIS_COMPONENT;
+                         VECTOR_NEG_COMPONENT; ARITH; REAL_NEG_0] THEN
+          ASM_REAL_ARITH_TAC;
+          EXISTS_TAC `(j:real^1->real^2) ++
+                      linepath(pathfinish j,vector [-- &1; &2])` THEN
+          ASM_SIMP_TAC[PATH_JOIN; PATHSTART_JOIN; PATHFINISH_JOIN;
+            PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+            PATH_IMAGE_JOIN] THEN
+          REWRITE_TAC[VECTOR_2; VECTOR_NEG_COMPONENT] THEN
+          REWRITE_TAC[UNION_SUBSET; PATH_IMAGE_LINEPATH] THEN
+          ONCE_REWRITE_TAC[AC CONJ_ACI
+            `(a /\ b) /\ c /\ d <=> (a /\ c) /\ b /\ d`] THEN
+          CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN EXPAND_TAC "K" THEN
+          MATCH_MP_TAC(SET_RULE
+           `(!x. x IN s ==> x IN t /\ ~(x IN u))
+            ==> s SUBSET (UNIV DIFF u) /\ s SUBSET t`) THEN
+          X_GEN_TAC `x:real^2` THEN DISCH_TAC THEN
+          MP_TAC(ISPECL [`pathfinish(j:real^1->real^2)`;
+                         `vector[-- &1; &2]:real^2`;
+                         `x:real^2`] SEGMENT_VERTICAL) THEN
+          ASM_SIMP_TAC[VECTOR_NEG_COMPONENT; VECTOR_2; IN_INTERVAL;
+                       FORALL_2; DIMINDEX_2] THEN
+          DISCH_TAC THEN CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+          DISCH_TAC THEN
+          UNDISCH_THEN
+           `!z:real^2. z IN path_image U UNION path_image D /\ z$1 = -- &1 <=>
+                       z = --basis 1`
+           (MP_TAC o SPEC `x:real^2`) THEN
+          ASM_REWRITE_TAC[] THEN
+          ASM_SIMP_TAC[CART_EQ; DIMINDEX_2; FORALL_2; BASIS_COMPONENT;
+                         VECTOR_NEG_COMPONENT; ARITH; REAL_NEG_0] THEN
+          ASM_REAL_ARITH_TAC];
+        UNDISCH_TAC `~((pathfinish j):real^2 = basis 1)` THEN
+        SIMP_TAC[CART_EQ; DIMINDEX_2; FORALL_2; BASIS_COMPONENT;
+                 VECTOR_NEG_COMPONENT; ARITH] THEN ASM_REWRITE_TAC[] THEN
+        DISCH_THEN(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+         `~(x = &0) ==> x < &0 \/ &0 < x`)) THENL
+         [EXISTS_TAC `(j:real^1->real^2) ++
+                      linepath(pathfinish j,vector [&1; -- &2])` THEN
+          ASM_SIMP_TAC[PATH_JOIN; PATHSTART_JOIN; PATHFINISH_JOIN;
+            PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+            PATH_IMAGE_JOIN] THEN
+          REWRITE_TAC[VECTOR_2; VECTOR_NEG_COMPONENT] THEN
+          REWRITE_TAC[UNION_SUBSET; PATH_IMAGE_LINEPATH] THEN
+          ONCE_REWRITE_TAC[AC CONJ_ACI
+            `(a /\ b) /\ c /\ d <=> (a /\ c) /\ b /\ d`] THEN
+          CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN EXPAND_TAC "K" THEN
+          MATCH_MP_TAC(SET_RULE
+           `(!x. x IN s ==> x IN t /\ ~(x IN u))
+            ==> s SUBSET (UNIV DIFF u) /\ s SUBSET t`) THEN
+          X_GEN_TAC `x:real^2` THEN DISCH_TAC THEN
+          MP_TAC(ISPECL [`pathfinish(j:real^1->real^2)`;
+                         `vector[&1; -- &2]:real^2`;
+                         `x:real^2`] SEGMENT_VERTICAL) THEN
+          ASM_SIMP_TAC[VECTOR_NEG_COMPONENT; VECTOR_2; IN_INTERVAL;
+                       FORALL_2; DIMINDEX_2] THEN
+          DISCH_TAC THEN CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+          DISCH_TAC THEN
+          UNDISCH_THEN
+           `!z:real^2. z IN path_image U UNION path_image D /\ z$1 = &1 <=>
+                       z = basis 1`
+           (MP_TAC o SPEC `x:real^2`) THEN
+          ASM_REWRITE_TAC[] THEN
+          ASM_SIMP_TAC[CART_EQ; DIMINDEX_2; FORALL_2; BASIS_COMPONENT;
+                         VECTOR_NEG_COMPONENT; ARITH; REAL_NEG_0] THEN
+          ASM_REAL_ARITH_TAC;
+          EXISTS_TAC `(j:real^1->real^2) ++
+                      linepath(pathfinish j,vector [&1; &2])` THEN
+          ASM_SIMP_TAC[PATH_JOIN; PATHSTART_JOIN; PATHFINISH_JOIN;
+            PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+            PATH_IMAGE_JOIN] THEN
+          REWRITE_TAC[VECTOR_2; VECTOR_NEG_COMPONENT] THEN
+          REWRITE_TAC[UNION_SUBSET; PATH_IMAGE_LINEPATH] THEN
+          ONCE_REWRITE_TAC[AC CONJ_ACI
+            `(a /\ b) /\ c /\ d <=> (a /\ c) /\ b /\ d`] THEN
+          CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN EXPAND_TAC "K" THEN
+          MATCH_MP_TAC(SET_RULE
+           `(!x. x IN s ==> x IN t /\ ~(x IN u))
+            ==> s SUBSET (UNIV DIFF u) /\ s SUBSET t`) THEN
+          X_GEN_TAC `x:real^2` THEN DISCH_TAC THEN
+          MP_TAC(ISPECL [`pathfinish(j:real^1->real^2)`;
+                         `vector[&1; &2]:real^2`;
+                         `x:real^2`] SEGMENT_VERTICAL) THEN
+          ASM_SIMP_TAC[VECTOR_NEG_COMPONENT; VECTOR_2; IN_INTERVAL;
+                       FORALL_2; DIMINDEX_2] THEN
+          DISCH_TAC THEN CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+          DISCH_TAC THEN
+          UNDISCH_THEN
+           `!z:real^2. z IN path_image U UNION path_image D /\ z$1 = &1 <=>
+                       z = basis 1`
+           (MP_TAC o SPEC `x:real^2`) THEN
+          ASM_REWRITE_TAC[] THEN
+          ASM_SIMP_TAC[CART_EQ; DIMINDEX_2; FORALL_2; BASIS_COMPONENT;
+                         VECTOR_NEG_COMPONENT; ARITH; REAL_NEG_0] THEN
+          ASM_REAL_ARITH_TAC];
+        EXISTS_TAC `j:real^1->real^2` THEN ASM_REWRITE_TAC[];
+        EXISTS_TAC `j:real^1->real^2` THEN ASM_REWRITE_TAC[]];
+      FIRST_X_ASSUM(K ALL_TAC o check (is_disj o concl))] THEN
+    STRIP_TAC THENL
+     [MP_TAC(ISPECL [`reversepath(D:real^1->real^2)`;
+                     `reversepath e ++ linepath(y,p) ++ reversepath h ++
+                      linepath(t:real^2,vector[t$1;&2])`;
+                     `--vector[&1; &2]:real^2`; `vector[&1; &2]:real^2`]
+             FASHODA) THEN
+      ASM_SIMP_TAC
+       [PATH_REVERSEPATH; ARC_IMP_PATH; PATH_JOIN;
+        PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+        PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH; PATH_IMAGE_JOIN;
+        PATHSTART_JOIN; PATHFINISH_JOIN; PATH_IMAGE_REVERSEPATH] THEN
+      SIMP_TAC[VECTOR_2; VECTOR_NEG_COMPONENT; BASIS_COMPONENT;
+               DIMINDEX_2; ARITH; NOT_IMP; GSYM CONJ_ASSOC] THEN
+      CONJ_TAC THENL
+       [ASM_SIMP_TAC[UNION_SUBSET; PATH_IMAGE_LINEPATH; SEGMENT_CONVEX_HULL;
+          SUBSET_HULL; CONVEX_INTERVAL; INSERT_SUBSET; EMPTY_SUBSET] THEN
+        REWRITE_TAC[IN_INTERVAL; DIMINDEX_2; FORALL_2; VECTOR_NEG_COMPONENT;
+                    VECTOR_2] THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV;
+        DISCH_THEN(X_CHOOSE_THEN `x:real^2`
+         (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+        REWRITE_TAC[DE_MORGAN_THM; IN_UNION] THEN REPEAT CONJ_TAC THENL
+         [ASM SET_TAC[];
+          REWRITE_TAC[PATH_IMAGE_LINEPATH] THEN DISCH_TAC THEN
+          MP_TAC(ISPECL [`y:real^2`; `p:real^2`; `x:real^2`]
+            SEGMENT_VERTICAL) THEN
+          ASM_REWRITE_TAC[] THEN
+          UNDISCH_THEN
+           `!z:real^2. z$2 <= (p:real^2)$2 /\ z$1 = &0 /\ z IN path_image D
+                       ==> z$2 <= (q:real^2)$2`
+           (MP_TAC o SPEC `x:real^2`) THEN
+          ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+          DISCH_TAC THEN
+          UNDISCH_THEN
+           `path_image(h:real^1->real^2) SUBSET
+            (path_image U) DIFF {pathstart U, pathfinish U}`
+           (MP_TAC o SPEC `x:real^2` o REWRITE_RULE[SUBSET]) THEN
+          ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+          REWRITE_TAC[PATH_IMAGE_LINEPATH] THEN DISCH_TAC THEN
+          MP_TAC(ISPECL [`t:real^2`; `vector[&0;&2]:real^2`; `x:real^2`]
+            SEGMENT_VERTICAL) THEN
+          ASM_REWRITE_TAC[VECTOR_2] THEN
+          DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+          ASM_CASES_TAC `x:real^2 = t` THENL
+           [ASM_MESON_TAC[]; UNDISCH_TAC `~(x:real^2 = t)`] THEN
+          ASM_REWRITE_TAC[CART_EQ; DIMINDEX_2; FORALL_2] THEN
+          UNDISCH_THEN
+           `!z:real^2. z$1 = &0 /\ z IN path_image U UNION path_image D
+                       ==> z$2 <= (t:real^2)$2`
+           (MP_TAC o SPEC `x:real^2`) THEN
+          ASM_REWRITE_TAC[IN_UNION] THEN ASM_REAL_ARITH_TAC]];
+      MP_TAC(ISPECL [`U:real^1->real^2`;
+                     `linepath(vector[b$1; -- &2],b) ++
+                      reversepath l ++
+                      linepath(q:real^2,y) ++ e`;
+                     `--vector[&1; &2]:real^2`; `vector[&1; &2]:real^2`]
+             FASHODA) THEN
+      ASM_SIMP_TAC
+       [PATH_REVERSEPATH; ARC_IMP_PATH; PATH_JOIN;
+        PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+        PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH; PATH_IMAGE_JOIN;
+        PATHSTART_JOIN; PATHFINISH_JOIN; PATH_IMAGE_REVERSEPATH] THEN
+      SIMP_TAC[VECTOR_2; VECTOR_NEG_COMPONENT; BASIS_COMPONENT;
+               DIMINDEX_2; ARITH; NOT_IMP; GSYM CONJ_ASSOC] THEN
+      CONJ_TAC THENL
+       [ASM_SIMP_TAC[UNION_SUBSET; PATH_IMAGE_LINEPATH; SEGMENT_CONVEX_HULL;
+          SUBSET_HULL; CONVEX_INTERVAL; INSERT_SUBSET; EMPTY_SUBSET] THEN
+        REWRITE_TAC[IN_INTERVAL; DIMINDEX_2; FORALL_2; VECTOR_NEG_COMPONENT;
+                    VECTOR_2] THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV;
+        DISCH_THEN(X_CHOOSE_THEN `x:real^2`
+         (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+        REWRITE_TAC[DE_MORGAN_THM; IN_UNION] THEN REPEAT CONJ_TAC THENL
+         [REWRITE_TAC[PATH_IMAGE_LINEPATH] THEN DISCH_TAC THEN
+          MP_TAC(ISPECL [`vector[&0; -- &2]:real^2`; `b:real^2`; `x:real^2`]
+            SEGMENT_VERTICAL) THEN
+          ASM_REWRITE_TAC[VECTOR_2] THEN
+          DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+          ASM_CASES_TAC `x:real^2 = b` THENL
+           [ASM_MESON_TAC[]; UNDISCH_TAC `~(x:real^2 = b)`] THEN
+          ASM_REWRITE_TAC[CART_EQ; DIMINDEX_2; FORALL_2] THEN
+          UNDISCH_THEN
+           `!z:real^2. z$1 = &0 /\ z IN path_image U ==> (p:real^2)$2 <= z$2`
+           (MP_TAC o SPEC `x:real^2`) THEN
+          ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+          DISCH_TAC THEN UNDISCH_THEN
+           `path_image(l:real^1->real^2) SUBSET
+            (path_image D) DIFF {pathstart D, pathfinish D}`
+           (MP_TAC o SPEC `x:real^2` o REWRITE_RULE[SUBSET]) THEN
+          ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+          REWRITE_TAC[PATH_IMAGE_LINEPATH] THEN DISCH_TAC THEN
+          MP_TAC(ISPECL [`q:real^2`; `y:real^2`; `x:real^2`]
+            SEGMENT_VERTICAL) THEN
+          ASM_REWRITE_TAC[] THEN
+          UNDISCH_THEN
+           `!z:real^2. z$1 = &0 /\ z IN path_image U ==> (p:real^2)$2 <= z$2`
+           (MP_TAC o SPEC `x:real^2`) THEN
+          ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+          ASM SET_TAC[]]]];
+    ASM_REWRITE_TAC[]] THEN
+  SUBGOAL_THEN
+    `!x:real^2. x IN K /\ ~bounded(connected_component K x)
+                ==> connected_component K x = connected_component K n`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `z:real^2` THEN DISCH_TAC THEN
+    MATCH_MP_TAC COBOUNDED_UNIQUE_UNBOUNDED_COMPONENT THEN
+    ASM_REWRITE_TAC[DIMINDEX_2; LE_REFL] THEN EXPAND_TAC "K" THEN
+    REWRITE_TAC[SET_RULE `UNIV DIFF (UNIV DIFF s) = s`] THEN
+    ASM_SIMP_TAC[COMPACT_PATH_IMAGE; COMPACT_IMP_BOUNDED;
+                 SIMPLE_PATH_IMP_PATH];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x:real^2. x IN K
+               ==> frontier(connected_component K x) =
+                   path_image U UNION path_image D`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `x:real^2` THEN DISCH_TAC THEN REWRITE_TAC[frontier] THEN
+    ASM_SIMP_TAC[OPEN_CONNECTED_COMPONENT; INTERIOR_OPEN] THEN
+    MATCH_MP_TAC(SET_RULE `s SUBSET t /\ ~(s PSUBSET t) ==> s = t`) THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET; IN_DIFF] THEN X_GEN_TAC `w:real^2` THEN
+      ASM_CASES_TAC `(w:real^2) IN K` THENL [ALL_TAC; ASM SET_TAC[]] THEN
+      ASM_SIMP_TAC[IN_CLOSURE_CONNECTED_COMPONENT] THEN CONV_TAC TAUT;
+      DISCH_TAC] THEN
+    SUBGOAL_THEN
+     `?A:real^1->real^2.
+         arc A /\
+         (closure (connected_component K x) DIFF connected_component K x)
+         SUBSET path_image A /\
+         path_image A SUBSET path_image(U) UNION path_image(D)`
+    STRIP_ASSUME_TAC THENL
+     [SUBST1_TAC(SYM(ASSUME
+       `path_image(U ++ D:real^1->real^2) =
+        path_image U UNION path_image D`)) THEN
+      MATCH_MP_TAC EXISTS_ARC_PSUBSET_SIMPLE_PATH THEN
+      ASM_REWRITE_TAC[] THEN
+      ASM_SIMP_TAC[CLOSED_DIFF; CLOSED_CLOSURE; OPEN_CONNECTED_COMPONENT];
+      ALL_TAC] THEN
+    MP_TAC(ISPEC `A:real^1->real^2` RETRACTION_ARC) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `rr:real^2->real^2` STRIP_ASSUME_TAC) THEN
+    ASM_CASES_TAC `bounded(connected_component K (x:real^2))` THENL
+     [MP_TAC(ISPECL [`connected_component K (x:real^2)`;
+                     `path_image(A:real^1->real^2)`;
+                     `rr:real^2->real^2`]
+                FRONTIER_SUBSET_RETRACTION) THEN
+      ASM_REWRITE_TAC[NOT_IMP; GSYM CONJ_ASSOC] THEN
+      ASM_SIMP_TAC[frontier; INTERIOR_OPEN; OPEN_CONNECTED_COMPONENT] THEN
+      CONJ_TAC THENL
+       [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNIV]; ALL_TAC] THEN
+      CONJ_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[SUBSET]] THEN
+      DISCH_THEN(MP_TAC o SPEC `x:real^2`) THEN
+      GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [IN] THEN
+      ASM_REWRITE_TAC[CONNECTED_COMPONENT_REFL_EQ] THEN DISCH_TAC THEN
+      UNDISCH_TAC `(x:real^2) IN K` THEN
+      UNDISCH_TAC `path_image(A:real^1->real^2) SUBSET
+                   path_image U UNION path_image D` THEN
+      REWRITE_TAC[SUBSET] THEN EXPAND_TAC "K" THEN
+      REWRITE_TAC[IN_UNIV; IN_DIFF] THEN
+      DISCH_THEN(MP_TAC o SPEC `x:real^2`) THEN ASM_REWRITE_TAC[];
+      MP_TAC(ISPECL [`(:real^2) DIFF (connected_component K (x:real^2))`;
+                     `path_image(A:real^1->real^2)`;
+                     `rr:real^2->real^2`]
+                FRONTIER_SUBSET_RETRACTION) THEN
+      ASM_REWRITE_TAC[FRONTIER_COMPLEMENT; NOT_IMP; GSYM CONJ_ASSOC] THEN
+      UNDISCH_THEN
+       `!x:real^2. x IN K /\ ~bounded (connected_component K x)
+                   ==> connected_component K x = connected_component K n`
+       (MP_TAC o SPEC `x:real^2`) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST_ALL_TAC THEN REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC BOUNDED_SUBSET THEN
+        EXISTS_TAC `interval[--vector[&1; &2]:real^2,vector [&1; &2]]` THEN
+        ONCE_REWRITE_TAC[SET_RULE
+         `UNIV DIFF s SUBSET t <=> UNIV DIFF t SUBSET s`] THEN
+        ASM_REWRITE_TAC[BOUNDED_INTERVAL];
+        REWRITE_TAC[frontier] THEN FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP
+         (SET_RULE `s DIFF t SUBSET u ==> t' = t ==> s DIFF t' SUBSET u`)) THEN
+        MATCH_MP_TAC INTERIOR_OPEN THEN
+        MATCH_MP_TAC OPEN_CONNECTED_COMPONENT THEN ASM_REWRITE_TAC[];
+        MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `(:real^2)` THEN
+        ASM_REWRITE_TAC[SUBSET_UNIV];
+        MATCH_MP_TAC(SET_RULE
+         `IMAGE f UNIV SUBSET s ==> IMAGE f t SUBSET s`) THEN
+        ASM_REWRITE_TAC[];
+        UNDISCH_TAC
+         `path_image(A:real^1->real^2) SUBSET
+          path_image U UNION path_image D` THEN
+        MATCH_MP_TAC(SET_RULE
+         `!y. y IN c /\ ~(y IN p) ==> a SUBSET p ==> ~(c SUBSET a)`) THEN
+        EXISTS_TAC `y:real^2` THEN REWRITE_TAC[IN_DIFF; IN_UNIV] THEN
+        CONJ_TAC THENL
+         [DISCH_THEN(MP_TAC o MATCH_MP CONNECTED_COMPONENT_EQ) THEN
+          DISCH_THEN SUBST_ALL_TAC THEN ASM_MESON_TAC[];
+          UNDISCH_TAC `(y:real^2) IN K` THEN EXPAND_TAC "K" THEN
+          REWRITE_TAC[IN_UNIV; IN_DIFF] THEN ASM_REWRITE_TAC[]]]];
+    ALL_TAC] THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[UNION_SUBSET; CONNECTED_COMPONENT_SUBSET] THEN
+  REWRITE_TAC[SUBSET; IN_UNION; IN_ELIM_THM] THEN X_GEN_TAC `x:real^2` THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN
+    MP_TAC(MATCH_MP CONNECTED_COMPONENT_REFL th)) THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM IN] THEN
+  ASM_CASES_TAC
+   `connected_component K (x:real^2) = connected_component K y` THEN
+  ASM_REWRITE_TAC[] THEN SIMP_TAC[] THEN
+  ASM_CASES_TAC
+   `connected_component K (x:real^2) = connected_component K n` THEN
+  ASM_REWRITE_TAC[] THEN SIMP_TAC[] THEN DISCH_TAC THEN
+  MATCH_MP_TAC(TAUT `F ==> p`) THEN
+  SUBGOAL_THEN `bounded(connected_component K (x:real^2))` ASSUME_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  ABBREV_TAC
+   `bp = (linepath(n:real^2,t) ++ h) ++
+         linepath(p,q) ++
+         (l ++ linepath(b,--n))` THEN
+  SUBGOAL_THEN
+   `path_image bp SUBSET
+    ((path_image U UNION path_image D) DIFF {--basis 1:real^2,basis 1}) UNION
+    (connected_component K n) UNION (connected_component K y)`
+  (LABEL_TAC "*") THENL
+   [EXPAND_TAC "bp" THEN
+    REPEAT(MATCH_MP_TAC SUBSET_PATH_IMAGE_JOIN THEN CONJ_TAC) THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC(SET_RULE
+       `(path_image(linepath(n,t)) DELETE t) SUBSET nn /\
+        t IN uu DIFF kk
+        ==> path_image(linepath(n,t)) SUBSET
+            ((uu UNION dd) DIFF kk) UNION nn UNION yy`) THEN
+      ASM_REWRITE_TAC[IN_DIFF; IN_INSERT; NOT_IN_EMPTY] THEN CONJ_TAC THENL
+       [ALL_TAC;
+        SIMP_TAC[CART_EQ; FORALL_2; DIMINDEX_2; BASIS_COMPONENT;
+                 VECTOR_NEG_COMPONENT; ARITH; REAL_NEG_0] THEN
+        ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV] THEN
+      MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+      SIMP_TAC[CONVEX_CONNECTED; PATH_IMAGE_LINEPATH;
+               CONVEX_SEMIOPEN_SEGMENT; IN_DELETE; ENDS_IN_SEGMENT] THEN
+      CONJ_TAC THENL
+       [DISCH_THEN(MP_TAC o AP_TERM `\z:real^2. z$2`) THEN
+        ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[SUBSET; IN_DELETE] THEN X_GEN_TAC `w:real^2` THEN
+      STRIP_TAC THEN
+      MP_TAC(ISPECL [`n:real^2`; `t:real^2`; `w:real^2`] SEGMENT_VERTICAL) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+      UNDISCH_TAC `~(w:real^2 = t)` THEN
+      ASM_REWRITE_TAC[CART_EQ; FORALL_2; DIMINDEX_2; IMP_IMP] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+       `~(w = t) /\ (&2 <= w /\ w <= t \/ t <= w /\ w <= &2)
+        ==> abs(t) < &2 ==> t < w`)) THEN
+      MATCH_MP_TAC(TAUT `a /\ (~c ==> ~b) ==> (a ==> b) ==> c`) THEN
+      CONJ_TAC THENL
+       [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[IN_UNION];
+        EXPAND_TAC "K" THEN
+        ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; REAL_NOT_LT] THEN ASM_MESON_TAC[]];
+      MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `path_image U DIFF {pathstart U:real^2, pathfinish U}` THEN
+      ASM_REWRITE_TAC[] THEN CONV_TAC SET_RULE;
+      MATCH_MP_TAC(SET_RULE
+       `(p IN uu /\ q IN dd /\ ~(p IN kk) /\ ~(q IN kk)) /\
+        (path_image(linepath(p,q)) DIFF {p,q}) SUBSET yy
+        ==> path_image(linepath(p,q)) SUBSET
+            ((uu UNION dd) DIFF kk) UNION nn UNION yy`) THEN
+      ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN CONJ_TAC THENL
+       [SIMP_TAC[CART_EQ; FORALL_2; DIMINDEX_2; BASIS_COMPONENT;
+                 VECTOR_NEG_COMPONENT; ARITH; REAL_NEG_0] THEN
+        ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV;
+        ALL_TAC] THEN
+      MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+      REWRITE_TAC[PATH_IMAGE_LINEPATH; GSYM open_segment] THEN
+      REWRITE_TAC[CONNECTED_SEGMENT] THEN EXPAND_TAC "y" THEN
+      REWRITE_TAC[MIDPOINT_IN_SEGMENT] THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[open_segment; SUBSET; IN_DIFF; IN_INSERT; NOT_IN_EMPTY] THEN
+      X_GEN_TAC `w:real^2` THEN REWRITE_TAC[DE_MORGAN_THM] THEN STRIP_TAC THEN
+      MP_TAC(ISPECL [`p:real^2`; `q:real^2`; `w:real^2`] SEGMENT_VERTICAL) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+      MAP_EVERY UNDISCH_TAC [`~(w:real^2 = p)`; `~(w:real^2 = q)`] THEN
+      ASM_REWRITE_TAC[CART_EQ; FORALL_2; DIMINDEX_2; IMP_IMP] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+       `(~(w = q) /\ ~(w = p)) /\
+        (p <= w /\ w <= q \/ q <= w /\ w <= p)
+        ==> q < p ==> q < w /\ w < p`)) THEN
+      ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+      MAP_EVERY (C UNDISCH_THEN (MP_TAC o SPEC `w:real^2`))
+       [`!z:real^2. z$2 <= (p:real^2)$2 /\ z$1 = &0 /\ z IN path_image D
+                    ==> z$2 <= (q:real^2)$2`;
+       `!z:real^2. z$1 = &0 /\ z IN path_image U ==> (p:real^2)$2 <= z$2`] THEN
+      ASM_REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN
+      EXPAND_TAC "K" THEN ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; IN_UNION] THEN
+      MATCH_MP_TAC(TAUT `~p ==> ~(~p /\ q) ==> ~q`) THEN ASM_REAL_ARITH_TAC;
+      MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `path_image D DIFF {pathstart D:real^2, pathfinish D}` THEN
+      ASM_REWRITE_TAC[] THEN CONV_TAC SET_RULE;
+      MATCH_MP_TAC(SET_RULE
+       `(path_image(linepath(b,n)) DELETE b) SUBSET nn /\
+        b IN dd DIFF kk
+        ==> path_image(linepath(b,n)) SUBSET
+            ((uu UNION dd) DIFF kk) UNION nn UNION yy`) THEN
+      ASM_REWRITE_TAC[IN_DIFF; IN_INSERT; NOT_IN_EMPTY] THEN CONJ_TAC THENL
+       [ALL_TAC;
+        SIMP_TAC[CART_EQ; FORALL_2; DIMINDEX_2; BASIS_COMPONENT;
+                 VECTOR_NEG_COMPONENT; ARITH; REAL_NEG_0] THEN
+        ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV] THEN
+      SUBGOAL_THEN
+       `connected_component K (n:real^2) = connected_component K (--n)`
+      SUBST1_TAC THENL
+       [CONV_TAC SYM_CONV THEN
+        MATCH_MP_TAC CONNECTED_COMPONENT_EQ THEN
+        MATCH_MP_TAC(REWRITE_RULE[SUBSET]
+         (ASSUME `(:real^2) DIFF
+                  interval[--vector [&1; &9 / &5],vector [&1; &9 / &5]] SUBSET
+                  connected_component K n`)) THEN
+        ASM_REWRITE_TAC[IN_UNIV; IN_DIFF; IN_INTERVAL; DIMINDEX_2; FORALL_2;
+                        VECTOR_NEG_COMPONENT; VECTOR_2] THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV;
+        ALL_TAC] THEN
+      MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+      SIMP_TAC[CONVEX_CONNECTED; PATH_IMAGE_LINEPATH;
+               CONVEX_SEMIOPEN_SEGMENT; IN_DELETE; ENDS_IN_SEGMENT] THEN
+      CONJ_TAC THENL
+       [DISCH_THEN(MP_TAC o AP_TERM `\z:real^2. z$2`) THEN
+        ASM_REWRITE_TAC[VECTOR_NEG_COMPONENT] THEN ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[SUBSET; IN_DELETE] THEN X_GEN_TAC `w:real^2` THEN
+      STRIP_TAC THEN
+      MP_TAC(ISPECL [`b:real^2`; `--n:real^2`; `w:real^2`]
+         SEGMENT_VERTICAL) THEN
+      ASM_REWRITE_TAC[VECTOR_NEG_COMPONENT; REAL_NEG_0] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+      UNDISCH_TAC `~(w:real^2 = b)` THEN
+      ASM_REWRITE_TAC[CART_EQ; FORALL_2; DIMINDEX_2; IMP_IMP] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+       `~(w = b) /\ (b <= w /\ w <= -- &2 \/ -- &2 <= w /\ w <= b)
+        ==> abs(b) < &2 ==> w < b`)) THEN
+      MATCH_MP_TAC(TAUT `a /\ (~c ==> ~b) ==> (a ==> b) ==> c`) THEN
+      CONJ_TAC THENL
+       [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[IN_UNION];
+        EXPAND_TAC "K" THEN
+        ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; IN_UNION; REAL_NOT_LT] THEN
+        ASM_CASES_TAC `(w:real^2) IN path_image D` THEN
+        ASM_REWRITE_TAC[] THENL [ASM_MESON_TAC[]; DISCH_TAC] THEN
+        UNDISCH_TAC `!z. z$1 = &0 /\ z IN path_image U
+                         ==> (p:real^2)$2 <= (z:real^2)$2` THEN
+        DISCH_THEN(MP_TAC o SPEC `w:real^2`) THEN ASM_REWRITE_TAC[] THEN
+        MATCH_MP_TAC(REAL_ARITH
+         `!q. b <= q /\ q < p ==> p <= w ==> b <= w`) THEN
+        EXISTS_TAC `(q:real^2)$2` THEN ASM_MESON_TAC[]]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `path(bp:real^1->real^2)` ASSUME_TAC THENL
+   [EXPAND_TAC "bp" THEN
+    REPEAT(MATCH_MP_TAC PATH_JOIN_IMP THEN REPEAT CONJ_TAC THEN
+           ASM_REWRITE_TAC[PATHSTART_LINEPATH; PATHFINISH_LINEPATH]) THEN
+    ASM_REWRITE_TAC[PATH_LINEPATH; PATHSTART_JOIN; PATHFINISH_JOIN;
+                    PATHSTART_LINEPATH; PATHFINISH_LINEPATH];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(?d1. &0 < d1 /\
+          cball(--basis 1,d1) SUBSET ((:real^2) DIFF path_image bp)) /\
+    (?d2. &0 < d2 /\
+          cball(basis 1,d2) SUBSET ((:real^2) DIFF path_image bp))`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+            (fst(EQ_IMP_RULE(SPEC_ALL OPEN_CONTAINS_CBALL)))) THEN
+    REWRITE_TAC[GSYM closed; IN_DIFF; IN_UNIV] THEN
+    (CONJ_TAC THENL
+      [ASM_MESON_TAC[COMPACT_IMP_CLOSED; COMPACT_PATH_IMAGE]; ALL_TAC]) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `bp SUBSET s ==> ~(x IN s) ==> ~(x IN bp)`)) THEN
+    ASM_REWRITE_TAC[IN_UNION; IN_DIFF; IN_INSERT] THEN
+    MATCH_MP_TAC(SET_RULE
+     `(!x. connected_component k x SUBSET k) /\ ~(a IN k) /\ ~(b IN k)
+      ==> ~(a IN connected_component k x \/
+            b IN connected_component k y)`) THEN
+    REWRITE_TAC[CONNECTED_COMPONENT_SUBSET] THEN
+    EXPAND_TAC "K" THEN REWRITE_TAC[IN_UNIV; IN_DIFF] THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `--(basis 1) IN frontier(connected_component K (x:real^2)) /\
+    (basis 1) IN frontier(connected_component K x)`
+  MP_TAC THENL [ASM_SIMP_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[frontier] THEN
+  ASM_SIMP_TAC[OPEN_CONNECTED_COMPONENT; INTERIOR_OPEN] THEN
+  REWRITE_TAC[IN_DIFF] THEN
+  DISCH_THEN(CONJUNCTS_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC)) THEN
+  REWRITE_TAC[CLOSURE_APPROACHABLE] THEN
+  DISCH_THEN(MP_TAC o SPEC `d2:real`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `w2:real^2` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(MP_TAC o SPEC `d1:real`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `w1:real^2` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `(w1:real^2) IN interval[--vector [&1; &2],vector [&1; &2]] /\
+    (w2:real^2) IN interval[--vector [&1; &2],vector [&1; &2]]`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC(SET_RULE
+     `!n j. j SUBSET i /\ (:real^N) DIFF j SUBSET n /\ ~(w IN n)
+            ==> w IN i`) THEN
+    EXISTS_TAC `connected_component K (n:real^2)` THEN
+    EXISTS_TAC
+     `interval[--vector [&1; &9 / &5]:real^2,vector [&1; &9 / &5]]` THEN
+    ASM_REWRITE_TAC[SUBSET_INTERVAL; DIMINDEX_2; FORALL_2; VECTOR_2;
+                    VECTOR_NEG_COMPONENT] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ASM_MESON_TAC[CONNECTED_COMPONENT_EQ];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?br. path br /\
+         path_image br SUBSET connected_component K x /\
+         pathstart br = w1 /\ pathfinish br = (w2:real^2)`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPEC `connected_component K (x:real^2)` path_connected) THEN
+    ASM_SIMP_TAC[PATH_CONNECTED_EQ_CONNECTED; OPEN_CONNECTED_COMPONENT] THEN
+    REWRITE_TAC[CONNECTED_CONNECTED_COMPONENT] THEN
+    DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `pathstart bp = n:real^2 /\ pathfinish bp = (--n:real^2)`
+  STRIP_ASSUME_TAC THENL
+   [EXPAND_TAC "bp" THEN REWRITE_TAC[PATHSTART_JOIN; PATHFINISH_JOIN] THEN
+    REWRITE_TAC[PATHSTART_LINEPATH; PATHFINISH_LINEPATH];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`linepath(--basis 1:real^2,w1) ++ br ++ linepath(w2,basis 1)`;
+    `reversepath bp:real^1->real^2`;
+    `--vector[&1; &2]:real^2`; `vector[&1; &2]:real^2`]
+   FASHODA) THEN
+  ASM_SIMP_TAC[PATH_JOIN; PATH_LINEPATH; PATH_REVERSEPATH;
+               PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+               PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+               PATHSTART_JOIN; PATHFINISH_JOIN;
+               PATH_IMAGE_JOIN; PATH_IMAGE_REVERSEPATH] THEN
+  SUBST1_TAC(SYM(ASSUME `&2 % basis 2:real^2 = n`)) THEN
+  SIMP_TAC[BASIS_COMPONENT; VECTOR_2; VECTOR_NEG_COMPONENT; DIMINDEX_2; ARITH;
+           VECTOR_MUL_COMPONENT] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[NOT_IMP; UNION_SUBSET; GSYM CONJ_ASSOC] THEN
+  REWRITE_TAC[PATH_IMAGE_LINEPATH; SEGMENT_CONVEX_HULL] THEN
+  SIMP_TAC[SUBSET_HULL; CONVEX_INTERVAL] THEN
+  ASM_REWRITE_TAC[SET_RULE `{a,b} SUBSET s <=> a IN s /\ b IN s`] THEN
+  SIMP_TAC[IN_INTERVAL; DIMINDEX_2; FORALL_2; VECTOR_2;
+           BASIS_COMPONENT; ARITH; VECTOR_NEG_COMPONENT] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `connected_component K (x:real^2)` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(SET_RULE
+     `!n j. j SUBSET i /\ (:real^N) DIFF j SUBSET n /\ c INTER n = {}
+            ==> c SUBSET i`) THEN
+    EXISTS_TAC `connected_component K (n:real^2)` THEN
+    EXISTS_TAC
+     `interval[--vector [&1; &9 / &5]:real^2,vector [&1; &9 / &5]]` THEN
+    ASM_REWRITE_TAC[SUBSET_INTERVAL; DIMINDEX_2; FORALL_2; VECTOR_2;
+                    VECTOR_NEG_COMPONENT] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ASM_REWRITE_TAC[CONNECTED_COMPONENT_NONOVERLAP];
+    EXPAND_TAC "bp" THEN
+    REPEAT(MATCH_MP_TAC SUBSET_PATH_IMAGE_JOIN THEN CONJ_TAC) THEN
+    ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[PATH_IMAGE_LINEPATH; SEGMENT_CONVEX_HULL] THEN
+    SIMP_TAC[SUBSET_HULL; CONVEX_INTERVAL] THEN
+    ASM_REWRITE_TAC[SET_RULE `{a,b} SUBSET s <=> a IN s /\ b IN s`] THEN
+    SUBST1_TAC(SYM(ASSUME `&2 % basis 2:real^2 = n`)) THEN
+    SIMP_TAC[BASIS_COMPONENT; VECTOR_2; VECTOR_NEG_COMPONENT; DIMINDEX_2; ARITH;
+             VECTOR_MUL_COMPONENT; IN_INTERVAL; FORALL_2] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `w:real^2` (CONJUNCTS_THEN2 MP_TAC ASSUME_TAC)) THEN
+  REWRITE_TAC[IN_UNION; DE_MORGAN_THM] THEN REPEAT CONJ_TAC THENL
+   [UNDISCH_TAC `cball(--basis 1,d1) SUBSET (:real^2) DIFF path_image bp` THEN
+    REWRITE_TAC[SUBSET; IN_DIFF; IN_UNIV] THEN
+    DISCH_THEN(MP_TAC o SPEC `w:real^2`) THEN
+    ASM_REWRITE_TAC[CONTRAPOS_THM] THEN
+    SPEC_TAC(`w:real^2`,`u:real^2`) THEN REWRITE_TAC[GSYM SUBSET] THEN
+    SIMP_TAC[SUBSET_HULL; CONVEX_CBALL] THEN
+    REWRITE_TAC[SET_RULE `{a,b} SUBSET s <=> a IN s /\ b IN s`] THEN
+    ASM_SIMP_TAC[CENTRE_IN_CBALL; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[IN_CBALL] THEN ASM_MESON_TAC[REAL_LT_IMP_LE; DIST_SYM];
+    ALL_TAC;
+    UNDISCH_TAC `cball(basis 1,d2) SUBSET (:real^2) DIFF path_image bp` THEN
+    REWRITE_TAC[SUBSET; IN_DIFF; IN_UNIV] THEN
+    DISCH_THEN(MP_TAC o SPEC `w:real^2`) THEN
+    ASM_REWRITE_TAC[CONTRAPOS_THM] THEN
+    SPEC_TAC(`w:real^2`,`u:real^2`) THEN REWRITE_TAC[GSYM SUBSET] THEN
+    SIMP_TAC[SUBSET_HULL; CONVEX_CBALL] THEN
+    REWRITE_TAC[SET_RULE `{a,b} SUBSET s <=> a IN s /\ b IN s`] THEN
+    ASM_SIMP_TAC[CENTRE_IN_CBALL; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[IN_CBALL] THEN ASM_MESON_TAC[REAL_LT_IMP_LE; DIST_SYM]] THEN
+  FIRST_X_ASSUM(MP_TAC o C MATCH_MP (ASSUME `(w:real^2) IN path_image bp`) o
+                GEN_REWRITE_RULE I [SUBSET]) THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+   `br SUBSET k ==> s INTER k = {} ==> w IN s ==> ~(w IN br)`)) THEN
+  MATCH_MP_TAC(SET_RULE
+   `xx SUBSET (UNIV DIFF du) /\ nn INTER xx = {} /\ yy INTER xx = {}
+    ==> ((du DIFF ee) UNION nn UNION yy) INTER xx = {}`) THEN
+  ASM_REWRITE_TAC[CONNECTED_COMPONENT_NONOVERLAP] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `K:real^2->bool` THEN
+  REWRITE_TAC[CONNECTED_COMPONENT_SUBSET] THEN
+  EXPAND_TAC "K" THEN MATCH_MP_TAC(SET_RULE `s = t ==> s SUBSET t`) THEN
+  AP_TERM_TAC THEN ASM_REWRITE_TAC[]);;
+
+let JORDAN_DISCONNECTED = prove
+ (`!c. simple_path c /\ pathfinish c = pathstart c
+       ==> ~connected((:real^2) DIFF path_image c)`,
+  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[connected] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP JORDAN_CURVE_THEOREM) THEN
+  REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM SET_TAC[]);;
+
+let JORDAN_INSIDE_OUTSIDE = prove
+ (`!c:real^1->real^2.
+        simple_path c /\ pathfinish c = pathstart c
+        ==> ~(inside(path_image c) = {}) /\
+            open(inside(path_image c)) /\
+            connected(inside(path_image c)) /\
+            ~(outside(path_image c) = {}) /\
+            open(outside(path_image c)) /\
+            connected(outside(path_image c)) /\
+            bounded(inside(path_image c)) /\
+            ~bounded(outside(path_image c)) /\
+            inside(path_image c) INTER outside(path_image c) = {} /\
+            inside(path_image c) UNION outside(path_image c) =
+            (:real^2) DIFF path_image c /\
+            frontier(inside(path_image c)) = path_image c /\
+            frontier(outside(path_image c)) = path_image c`,
+  GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP JORDAN_CURVE_THEOREM) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`ins:real^2->bool`; `out:real^2->bool`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `inside(path_image c) :real^2->bool = ins /\
+                outside(path_image c):real^2->bool = out `
+   (fun th -> ASM_REWRITE_TAC[th]) THEN
+  MATCH_MP_TAC INSIDE_OUTSIDE_UNIQUE THEN ASM_SIMP_TAC[JORDAN_DISCONNECTED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Splitting the inside of a closed curve into two with a cut across it.     *)
+(* The hardest part, that there is no third component inside the original    *)
+(* curve, is taken from Whyburn's, "Topological Analysis" (1.4 on p31).      *)
+(* ------------------------------------------------------------------------- *)
+
+let SPLIT_INSIDE_SIMPLE_CLOSED_CURVE = prove
+ (`!c1 c2 c a b:real^2.
+        ~(a = b) /\
+        simple_path c1 /\ pathstart c1 = a /\ pathfinish c1 = b /\
+        simple_path c2 /\ pathstart c2 = a /\ pathfinish c2 = b /\
+        simple_path c /\ pathstart c = a /\ pathfinish c = b /\
+        path_image c1 INTER path_image c2 = {a,b} /\
+        path_image c1 INTER path_image c = {a,b} /\
+        path_image c2 INTER path_image c = {a,b} /\
+        ~(path_image c INTER inside(path_image c1 UNION path_image c2) = {})
+        ==> inside(path_image c1 UNION path_image c) INTER
+            inside(path_image c2 UNION path_image c) = {} /\
+            inside(path_image c1 UNION path_image c) UNION
+            inside(path_image c2 UNION path_image c) UNION
+            (path_image c DIFF {a,b}) =
+            inside(path_image c1 UNION path_image c2)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MAP_EVERY (MP_TAC o C ISPEC JORDAN_INSIDE_OUTSIDE)
+   [`(c1 ++ reversepath c2):real^1->real^2`;
+    `(c1 ++ reversepath c):real^1->real^2`;
+    `(c2 ++ reversepath c):real^1->real^2`] THEN
+  ASM_SIMP_TAC[PATHSTART_JOIN; PATHFINISH_JOIN;
+               PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+               SIMPLE_PATH_JOIN_LOOP; SIMPLE_PATH_IMP_ARC;
+               PATH_IMAGE_JOIN; SIMPLE_PATH_IMP_PATH; PATH_IMAGE_REVERSEPATH;
+               SIMPLE_PATH_REVERSEPATH; ARC_REVERSEPATH;
+               SUBSET_REFL] THEN
+  REPLICATE_TAC 3 STRIP_TAC THEN
+  SUBGOAL_THEN
+   `path_image(c:real^1->real^2) INTER
+    outside(path_image c1 UNION path_image c2) = {}`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `connected(path_image(c:real^1->real^2) DIFF
+                {pathstart c,pathfinish c})`
+    MP_TAC THENL [ASM_SIMP_TAC[CONNECTED_SIMPLE_PATH_ENDLESS]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[connected] THEN
+    MAP_EVERY EXISTS_TAC
+     [`inside(path_image c1 UNION path_image c2):real^2->bool`;
+      `outside(path_image c1 UNION path_image c2):real^2->bool`] THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `outside(path_image c1 UNION path_image c2) SUBSET
+    outside(path_image c1 UNION path_image (c:real^1->real^2)) /\
+    outside(path_image c1 UNION path_image c2) SUBSET
+    outside(path_image c2 UNION path_image c)`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THENL
+     [ALL_TAC; GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [UNION_COMM]] THEN
+    MATCH_MP_TAC OUTSIDE_UNION_OUTSIDE_UNION THEN ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[UNION_COMM] THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `path_image(c1:real^1->real^2) INTER
+    inside(path_image c2 UNION path_image c) = {}`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `frontier(outside(path_image c1 UNION path_image c2)):real^2->bool =
+      frontier(outside(path_image c2 UNION path_image c))`
+    MP_TAC THENL
+     [AP_TERM_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN ASM_REWRITE_TAC[] THEN
+      GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [UNION_COMM] THEN
+      MATCH_MP_TAC OUTSIDE_UNION_OUTSIDE_UNION THEN
+      MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+      SUBGOAL_THEN
+       `connected(path_image(c1:real^1->real^2) DIFF
+                  {pathstart c1,pathfinish c1})`
+      MP_TAC THENL [ASM_SIMP_TAC[CONNECTED_SIMPLE_PATH_ENDLESS]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[connected] THEN
+      MAP_EVERY EXISTS_TAC
+       [`inside(path_image c2 UNION path_image c):real^2->bool`;
+        `outside(path_image c2 UNION path_image c):real^2->bool`] THEN
+      ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+      MP_TAC(ISPEC `c:real^1->real^2` NONEMPTY_SIMPLE_PATH_ENDLESS) THEN
+      ASM_REWRITE_TAC[] THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `path_image(c2:real^1->real^2) INTER
+    inside(path_image c1 UNION path_image c) = {}`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `frontier(outside(path_image c1 UNION path_image c2)):real^2->bool =
+      frontier(outside(path_image c1 UNION path_image c))`
+    MP_TAC THENL
+     [AP_TERM_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC OUTSIDE_UNION_OUTSIDE_UNION THEN
+      MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+      SUBGOAL_THEN
+       `connected(path_image(c2:real^1->real^2) DIFF
+                  {pathstart c2,pathfinish c2})`
+      MP_TAC THENL [ASM_SIMP_TAC[CONNECTED_SIMPLE_PATH_ENDLESS]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[connected] THEN
+      MAP_EVERY EXISTS_TAC
+       [`inside(path_image c1 UNION path_image c):real^2->bool`;
+        `outside(path_image c1 UNION path_image c):real^2->bool`] THEN
+      ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+      MP_TAC(ISPEC `c:real^1->real^2` NONEMPTY_SIMPLE_PATH_ENDLESS) THEN
+      ASM_REWRITE_TAC[] THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `inside(path_image c1 UNION path_image (c:real^1->real^2)) SUBSET
+    inside(path_image c1 UNION path_image c2) /\
+    inside(path_image c2 UNION path_image (c:real^1->real^2)) SUBSET
+    inside(path_image c1 UNION path_image c2)`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN REWRITE_TAC[INSIDE_OUTSIDE] THEN
+    REWRITE_TAC[SET_RULE `UNIV DIFF t SUBSET UNIV DIFF s <=> s SUBSET t`] THENL
+     [ALL_TAC; GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [UNION_COMM]] THEN
+    MATCH_MP_TAC(SET_RULE
+     `out1 SUBSET out2 /\ c2 DIFF (c1 UNION c) SUBSET out2
+      ==> (c1 UNION c2) UNION out1 SUBSET (c1 UNION c) UNION out2`) THEN
+    ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[OUTSIDE_INSIDE] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `inside(path_image c1 UNION path_image c :real^2->bool) SUBSET
+    outside(path_image c2 UNION path_image c) /\
+    inside(path_image c2 UNION path_image c) SUBSET
+    outside(path_image c1 UNION path_image c)`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[SUBSET] THEN CONJ_TAC THEN
+    X_GEN_TAC `x:real^2` THEN DISCH_TAC THENL
+     [SUBGOAL_THEN `?z:real^2. z IN path_image c1 /\
+                               z IN outside(path_image c2 UNION path_image c)`
+      (CHOOSE_THEN (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THENL
+       [REWRITE_TAC[OUTSIDE_INSIDE; IN_DIFF; IN_UNION; IN_UNIV] THEN
+        MP_TAC(ISPEC `c1:real^1->real^2` NONEMPTY_SIMPLE_PATH_ENDLESS) THEN
+        ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+        ALL_TAC] THEN
+      DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+      REWRITE_TAC[OUTSIDE; IN_ELIM_THM; CONTRAPOS_THM] THEN
+      MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+      MATCH_MP_TAC CONNECTED_COMPONENT_EQ THEN REWRITE_TAC[IN] THEN
+      MP_TAC(ASSUME
+       `open(outside(path_image c2 UNION path_image c):real^2->bool)`) THEN
+      REWRITE_TAC[OPEN_CONTAINS_BALL] THEN
+      DISCH_THEN(MP_TAC o SPEC `z:real^2`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+      MP_TAC(ASSUME
+       `frontier(inside(path_image c1 UNION path_image c):real^2->bool) =
+        path_image c1 UNION path_image c`) THEN
+      GEN_REWRITE_TAC LAND_CONV [EXTENSION] THEN
+      DISCH_THEN(MP_TAC o SPEC `z:real^2`) THEN REWRITE_TAC[frontier] THEN
+      ASM_SIMP_TAC[IN_UNION; IN_DIFF; CLOSURE_APPROACHABLE; IN_ELIM_THM] THEN
+      DISCH_THEN(MP_TAC o SPEC `e:real` o CONJUNCT1) THEN
+      ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `w:real^2` THEN STRIP_TAC THEN
+      MATCH_MP_TAC CONNECTED_COMPONENT_TRANS THEN EXISTS_TAC `w:real^2` THEN
+      REWRITE_TAC[connected_component] THEN CONJ_TAC THENL
+       [EXISTS_TAC
+         `outside(path_image c2 UNION path_image c:real^2->bool)` THEN
+        ASM_REWRITE_TAC[SET_RULE `s SUBSET UNIV DIFF t <=> s INTER t = {}`;
+                        OUTSIDE_NO_OVERLAP] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+        ASM_REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] IN_BALL];
+        EXISTS_TAC `inside(path_image c1 UNION path_image c:real^2->bool)` THEN
+        ASM_REWRITE_TAC[] THEN
+        MATCH_MP_TAC(SET_RULE
+         `inside(c1 UNION c) INTER (c1 UNION c) = {} /\
+          c2 INTER inside(c1 UNION c) = {}
+          ==> inside(c1 UNION c) SUBSET UNIV DIFF (c2 UNION c)`) THEN
+        ASM_REWRITE_TAC[INSIDE_NO_OVERLAP]];
+      SUBGOAL_THEN `?z:real^2. z IN path_image c2 /\
+                               z IN outside(path_image c1 UNION path_image c)`
+      (CHOOSE_THEN (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THENL
+       [REWRITE_TAC[OUTSIDE_INSIDE; IN_DIFF; IN_UNION; IN_UNIV] THEN
+        MP_TAC(ISPEC `c2:real^1->real^2` NONEMPTY_SIMPLE_PATH_ENDLESS) THEN
+        ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+        ALL_TAC] THEN
+      DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+      REWRITE_TAC[OUTSIDE; IN_ELIM_THM; CONTRAPOS_THM] THEN
+      MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+      MATCH_MP_TAC CONNECTED_COMPONENT_EQ THEN REWRITE_TAC[IN] THEN
+      MP_TAC(ASSUME
+       `open(outside(path_image c1 UNION path_image c):real^2->bool)`) THEN
+      REWRITE_TAC[OPEN_CONTAINS_BALL] THEN
+      DISCH_THEN(MP_TAC o SPEC `z:real^2`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+      MP_TAC(ASSUME
+       `frontier(inside(path_image c2 UNION path_image c):real^2->bool) =
+        path_image c2 UNION path_image c`) THEN
+      GEN_REWRITE_TAC LAND_CONV [EXTENSION] THEN
+      DISCH_THEN(MP_TAC o SPEC `z:real^2`) THEN REWRITE_TAC[frontier] THEN
+      ASM_SIMP_TAC[IN_UNION; IN_DIFF; CLOSURE_APPROACHABLE; IN_ELIM_THM] THEN
+      DISCH_THEN(MP_TAC o SPEC `e:real` o CONJUNCT1) THEN
+      ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `w:real^2` THEN STRIP_TAC THEN
+      MATCH_MP_TAC CONNECTED_COMPONENT_TRANS THEN EXISTS_TAC `w:real^2` THEN
+      REWRITE_TAC[connected_component] THEN CONJ_TAC THENL
+       [EXISTS_TAC
+         `outside(path_image c1 UNION path_image c:real^2->bool)` THEN
+        ASM_REWRITE_TAC[SET_RULE `s SUBSET UNIV DIFF t <=> s INTER t = {}`;
+                        OUTSIDE_NO_OVERLAP] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+        ASM_REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] IN_BALL];
+        EXISTS_TAC `inside(path_image c2 UNION path_image c:real^2->bool)` THEN
+        ASM_REWRITE_TAC[] THEN
+        MATCH_MP_TAC(SET_RULE
+         `inside(c2 UNION c) INTER (c2 UNION c) = {} /\
+          c1 INTER inside(c2 UNION c) = {}
+          ==> inside(c2 UNION c) SUBSET UNIV DIFF (c1 UNION c)`) THEN
+        ASM_REWRITE_TAC[INSIDE_NO_OVERLAP]]];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `!u. s SUBSET u /\ t INTER u = {} ==> s INTER t = {}`) THEN
+    EXISTS_TAC `outside(path_image c2 UNION path_image c):real^2->bool` THEN
+    ASM_REWRITE_TAC[INSIDE_INTER_OUTSIDE];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x:real^2. ~(x IN path_image c) /\
+               x IN inside(path_image c1 UNION path_image c2) /\
+               ~(x IN inside(path_image c1 UNION path_image c)) /\
+               ~(x IN inside(path_image c2 UNION path_image c)) ==> F`
+  ASSUME_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  X_GEN_TAC `z:real^2` THEN STRIP_TAC THEN
+  SUBGOAL_THEN `~((z:real^2) IN (path_image c1 UNION path_image c2))`
+  MP_TAC THENL
+   [ASM_MESON_TAC[INSIDE_NO_OVERLAP; NOT_IN_EMPTY; IN_INTER];
+    PURE_REWRITE_TAC[IN_UNION; DE_MORGAN_THM] THEN STRIP_TAC] THEN
+  MAP_EVERY (MP_TAC o C ISPEC INSIDE_UNION_OUTSIDE)
+   [`path_image c1 UNION path_image c:real^2->bool`;
+    `path_image c2 UNION path_image c:real^2->bool`] THEN
+  PURE_REWRITE_TAC[IMP_IMP] THEN REWRITE_TAC[EXTENSION; IN_UNION] THEN
+  REWRITE_TAC[AND_FORALL_THM] THEN DISCH_THEN(MP_TAC o SPEC `z:real^2`) THEN
+  ASM_REWRITE_TAC[IN_UNIV; IN_DIFF; IN_UNION] THEN STRIP_TAC THEN
+  MP_TAC(ASSUME
+   `~(outside(path_image c1 UNION path_image c2:real^2->bool) = {})`) THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM MEMBER_NOT_EMPTY] THEN
+  DISCH_THEN(X_CHOOSE_TAC `w:real^2`) THEN
+  SUBGOAL_THEN `(w:real^2) IN outside(path_image c1 UNION path_image c) /\
+                w IN outside(path_image c2 UNION path_image c)`
+  STRIP_ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `~((w:real^2) IN (path_image c1 UNION path_image c2)) /\
+    ~(w IN path_image c1 UNION path_image c)`
+  MP_TAC THENL
+   [ASM_MESON_TAC[OUTSIDE_NO_OVERLAP; NOT_IN_EMPTY; IN_INTER];
+    PURE_REWRITE_TAC[IN_UNION; CONJ_ACI; DE_MORGAN_THM] THEN STRIP_TAC] THEN
+  MAP_EVERY (MP_TAC o C ISPEC INSIDE_INTER_OUTSIDE)
+   [`path_image c1 UNION path_image c2:real^2->bool`;
+    `path_image c1 UNION path_image c:real^2->bool`;
+    `path_image c2 UNION path_image c:real^2->bool`] THEN
+  PURE_REWRITE_TAC[IMP_IMP] THEN
+  REWRITE_TAC[EXTENSION; IN_INTER; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[AND_FORALL_THM] THEN DISCH_THEN(MP_TAC o SPEC `w:real^2`) THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+  MP_TAC(ISPEC
+   `outside(path_image c2 UNION path_image c):real^2->bool`
+   CONNECTED_OPEN_ARC_CONNECTED) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(MP_TAC o SPECL [`z:real^2`; `w:real^2`]) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g1:real^1->real^2` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPEC
+   `outside(path_image c1 UNION path_image c):real^2->bool`
+   CONNECTED_OPEN_ARC_CONNECTED) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(MP_TAC o SPECL [`z:real^2`; `w:real^2`]) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g2:real^1->real^2` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `?h. arc h /\ pathstart h = (z:real^2) /\
+        path_image h DELETE pathfinish h SUBSET
+        inside(path_image c1 UNION path_image c2) INTER
+        outside(path_image c1 UNION path_image c) INTER
+        outside(path_image c2 UNION path_image c) /\
+        pathfinish h IN path_image c1 /\
+        ~(pathfinish h IN path_image c2)`
+  (X_CHOOSE_THEN `gzx:real^1->real^2` STRIP_ASSUME_TAC) THENL
+   [MP_TAC(ISPECL
+     [`g1:real^1->real^2`;
+      `inside(path_image c1 UNION path_image c2) INTER
+       outside(path_image c1 UNION path_image c) INTER
+       outside(path_image c2 UNION path_image c):real^2->bool`]
+          SUBPATH_TO_FRONTIER) THEN
+    ASM_SIMP_TAC[ARC_IMP_PATH; IN_INTER; INTERIOR_INTER; INTERIOR_OPEN] THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^1` STRIP_ASSUME_TAC) THEN
+    ABBREV_TAC `h:real^1->real^2 = subpath (vec 0) u g1` THEN
+    EXISTS_TAC `h:real^1->real^2` THEN ASM_REWRITE_TAC[] THEN
+    EXPAND_TAC "h" THEN
+    REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+    MATCH_MP_TAC(TAUT `b /\ (c ==> a) /\ c ==> a /\ b /\ c`) THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[pathstart]; ALL_TAC] THEN CONJ_TAC THENL
+     [DISCH_TAC THEN MATCH_MP_TAC ARC_SIMPLE_PATH_SUBPATH THEN
+      ASM_SIMP_TAC[ENDS_IN_UNIT_INTERVAL; ARC_IMP_SIMPLE_PATH] THEN
+      DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+      MP_TAC(ISPEC `path_image c1 UNION path_image c2:real^2->bool`
+       INSIDE_NO_OVERLAP) THEN
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+      EXISTS_TAC `pathstart(g1:real^1->real^2)` THEN
+      ASM_REWRITE_TAC[IN_INTER] THEN
+      REWRITE_TAC[IN_UNION] THEN DISJ1_TAC THEN ASM_MESON_TAC[pathstart];
+      ALL_TAC] THEN
+    UNDISCH_TAC
+     `(pathfinish h:real^2) IN
+      frontier
+      (inside (path_image c1 UNION path_image c2) INTER
+       outside (path_image c1 UNION path_image c) INTER
+       outside (path_image c2 UNION path_image c))` THEN
+    EXPAND_TAC "h" THEN REWRITE_TAC[PATHFINISH_SUBPATH] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[SUBSET]
+      FRONTIER_INTER_SUBSET)) THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ASSUME
+     `(path_image g1:real^2->bool) SUBSET
+      outside(path_image c2 UNION path_image c)`) THEN
+    DISCH_THEN(MP_TAC o SPEC `(g1:real^1->real^2) u` o
+      REWRITE_RULE[SUBSET]) THEN
+    GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o ONCE_DEPTH_CONV) [path_image] THEN
+    REWRITE_TAC[IN_IMAGE] THEN ANTS_TAC THENL [ASM_MESON_TAC[]; DISCH_TAC] THEN
+    MP_TAC(ISPEC `path_image c2 UNION path_image c:real^2->bool`
+        OUTSIDE_NO_OVERLAP) THEN
+    GEN_REWRITE_TAC LAND_CONV [EXTENSION] THEN
+    DISCH_THEN(MP_TAC o SPEC `(g1:real^1->real^2) u`) THEN
+    ASM_REWRITE_TAC[IN_INTER; IN_UNION; NOT_IN_EMPTY; DE_MORGAN_THM] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(DISJ_CASES_THEN2 ACCEPT_TAC MP_TAC) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[SUBSET]
+      FRONTIER_INTER_SUBSET)) THEN ASM_REWRITE_TAC[] THEN
+    ASM_REWRITE_TAC[IN_UNION];
+    ABBREV_TAC `x:real^2 = pathfinish gzx`] THEN
+  SUBGOAL_THEN
+   `?h. arc h /\ pathstart h = (w:real^2) /\
+        path_image h DELETE pathfinish h SUBSET
+        outside(path_image c1 UNION path_image c2) /\
+        pathfinish h IN path_image c1 /\
+        ~(pathfinish h IN path_image c2)`
+  (X_CHOOSE_THEN `gwx:real^1->real^2` STRIP_ASSUME_TAC) THENL
+   [MP_TAC(ISPECL
+     [`reversepath g1:real^1->real^2`;
+      `outside(path_image c1 UNION path_image c2):real^2->bool`]
+          SUBPATH_TO_FRONTIER) THEN
+    ASM_SIMP_TAC[ARC_IMP_PATH; IN_INTER; INTERIOR_INTER; INTERIOR_OPEN;
+       PATH_REVERSEPATH; PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH] THEN
+    ANTS_TAC THENL
+     [ASM_MESON_TAC[INSIDE_INTER_OUTSIDE; IN_INTER; NOT_IN_EMPTY];
+      ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^1` STRIP_ASSUME_TAC) THEN
+    ABBREV_TAC `h:real^1->real^2 = subpath (vec 0) u (reversepath g1)` THEN
+    EXISTS_TAC `h:real^1->real^2` THEN ASM_REWRITE_TAC[] THEN
+    EXPAND_TAC "h" THEN
+    REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+    MATCH_MP_TAC(TAUT `b /\ (c ==> a) /\ c ==> a /\ b /\ c`) THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[pathstart; PATHSTART_REVERSEPATH]; ALL_TAC] THEN
+    CONJ_TAC THENL
+     [DISCH_TAC THEN MATCH_MP_TAC ARC_SIMPLE_PATH_SUBPATH THEN
+      ASM_SIMP_TAC[ENDS_IN_UNIT_INTERVAL; ARC_IMP_SIMPLE_PATH;
+                   SIMPLE_PATH_REVERSEPATH] THEN
+      DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+      MP_TAC(ISPEC `path_image c1 UNION path_image c2:real^2->bool`
+       OUTSIDE_NO_OVERLAP) THEN
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+      EXISTS_TAC `pathstart(reversepath g1:real^1->real^2)` THEN
+      ASM_REWRITE_TAC[IN_INTER] THEN CONJ_TAC THENL
+       [ASM_REWRITE_TAC[PATHSTART_REVERSEPATH];
+       REWRITE_TAC[IN_UNION] THEN DISJ1_TAC THEN ASM_MESON_TAC[pathstart]];
+      ALL_TAC] THEN
+    UNDISCH_TAC
+     `(pathfinish h:real^2) IN path_image c1 UNION path_image c2` THEN
+    EXPAND_TAC "h" THEN REWRITE_TAC[PATHFINISH_SUBPATH] THEN
+    MP_TAC(ASSUME
+     `(path_image g1:real^2->bool) SUBSET
+      outside(path_image c2 UNION path_image c)`) THEN
+    DISCH_THEN(MP_TAC o SPEC `reversepath (g1:real^1->real^2) u` o
+      REWRITE_RULE[SUBSET]) THEN
+    ANTS_TAC THENL
+     [ONCE_REWRITE_TAC[GSYM PATH_IMAGE_REVERSEPATH] THEN
+      REWRITE_TAC[path_image; IN_IMAGE] THEN ASM_MESON_TAC[];
+      DISCH_TAC] THEN
+    MP_TAC(ISPEC `path_image c2 UNION path_image c:real^2->bool`
+        OUTSIDE_NO_OVERLAP) THEN
+    GEN_REWRITE_TAC LAND_CONV [EXTENSION] THEN
+    DISCH_THEN(MP_TAC o SPEC `reversepath (g1:real^1->real^2) u`) THEN
+    ASM_REWRITE_TAC[IN_INTER; IN_UNION; NOT_IN_EMPTY; DE_MORGAN_THM] THEN
+    CONV_TAC TAUT;
+    ABBREV_TAC `x':real^2 = pathfinish gwx`] THEN
+  SUBGOAL_THEN
+   `?h. arc h /\ pathstart h = (z:real^2) /\
+        path_image h DELETE pathfinish h SUBSET
+        inside(path_image c1 UNION path_image c2) INTER
+        outside(path_image c1 UNION path_image c) INTER
+        outside(path_image c2 UNION path_image c) /\
+        pathfinish h IN path_image c2 /\
+        ~(pathfinish h IN path_image c1)`
+  (X_CHOOSE_THEN `gzy:real^1->real^2` STRIP_ASSUME_TAC) THENL
+   [MP_TAC(ISPECL
+     [`g2:real^1->real^2`;
+      `inside(path_image c1 UNION path_image c2) INTER
+       outside(path_image c1 UNION path_image c) INTER
+       outside(path_image c2 UNION path_image c):real^2->bool`]
+          SUBPATH_TO_FRONTIER) THEN
+    ASM_SIMP_TAC[ARC_IMP_PATH; IN_INTER; INTERIOR_INTER; INTERIOR_OPEN] THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^1` STRIP_ASSUME_TAC) THEN
+    ABBREV_TAC `h:real^1->real^2 = subpath (vec 0) u g2` THEN
+    EXISTS_TAC `h:real^1->real^2` THEN ASM_REWRITE_TAC[] THEN
+    EXPAND_TAC "h" THEN
+    REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+    MATCH_MP_TAC(TAUT `b /\ (c ==> a) /\ c ==> a /\ b /\ c`) THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[pathstart]; ALL_TAC] THEN CONJ_TAC THENL
+     [DISCH_TAC THEN MATCH_MP_TAC ARC_SIMPLE_PATH_SUBPATH THEN
+      ASM_SIMP_TAC[ENDS_IN_UNIT_INTERVAL; ARC_IMP_SIMPLE_PATH] THEN
+      DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+      MP_TAC(ISPEC `path_image c1 UNION path_image c2:real^2->bool`
+       INSIDE_NO_OVERLAP) THEN
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+      EXISTS_TAC `pathstart(g2:real^1->real^2)` THEN
+      ASM_REWRITE_TAC[IN_INTER] THEN
+      REWRITE_TAC[IN_UNION] THEN DISJ1_TAC THEN ASM_MESON_TAC[pathstart];
+      ALL_TAC] THEN
+    UNDISCH_TAC
+     `(pathfinish h:real^2) IN
+      frontier
+      (inside (path_image c1 UNION path_image c2) INTER
+       outside (path_image c1 UNION path_image c) INTER
+       outside (path_image c2 UNION path_image c))` THEN
+    EXPAND_TAC "h" THEN REWRITE_TAC[PATHFINISH_SUBPATH] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[SUBSET]
+      FRONTIER_INTER_SUBSET)) THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ASSUME
+     `(path_image g2:real^2->bool) SUBSET
+      outside(path_image c1 UNION path_image c)`) THEN
+    DISCH_THEN(MP_TAC o SPEC `(g2:real^1->real^2) u` o
+      REWRITE_RULE[SUBSET]) THEN
+    GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o ONCE_DEPTH_CONV) [path_image] THEN
+    REWRITE_TAC[IN_IMAGE] THEN ANTS_TAC THENL [ASM_MESON_TAC[]; DISCH_TAC] THEN
+    MP_TAC(ISPEC `path_image c1 UNION path_image c:real^2->bool`
+        OUTSIDE_NO_OVERLAP) THEN
+    GEN_REWRITE_TAC LAND_CONV [EXTENSION] THEN
+    DISCH_THEN(MP_TAC o SPEC `(g2:real^1->real^2) u`) THEN
+    ASM_REWRITE_TAC[IN_INTER; IN_UNION; NOT_IN_EMPTY; DE_MORGAN_THM] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(DISJ_CASES_THEN2 ACCEPT_TAC MP_TAC) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[SUBSET]
+      FRONTIER_INTER_SUBSET)) THEN ASM_REWRITE_TAC[] THEN
+    ASM_REWRITE_TAC[IN_UNION];
+    ABBREV_TAC `y:real^2 = pathfinish gzy`] THEN
+  SUBGOAL_THEN
+   `?h. arc h /\ pathstart h = (w:real^2) /\
+        path_image h DELETE pathfinish h SUBSET
+        outside(path_image c1 UNION path_image c2) /\
+        pathfinish h IN path_image c2 /\
+        ~(pathfinish h IN path_image c1)`
+  (X_CHOOSE_THEN `gwy:real^1->real^2` STRIP_ASSUME_TAC) THENL
+   [MP_TAC(ISPECL
+     [`reversepath g2:real^1->real^2`;
+      `outside(path_image c1 UNION path_image c2):real^2->bool`]
+          SUBPATH_TO_FRONTIER) THEN
+    ASM_SIMP_TAC[ARC_IMP_PATH; IN_INTER; INTERIOR_INTER; INTERIOR_OPEN;
+       PATH_REVERSEPATH; PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH] THEN
+    ANTS_TAC THENL
+     [ASM_MESON_TAC[INSIDE_INTER_OUTSIDE; IN_INTER; NOT_IN_EMPTY];
+      ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^1` STRIP_ASSUME_TAC) THEN
+    ABBREV_TAC `h:real^1->real^2 = subpath (vec 0) u (reversepath g2)` THEN
+    EXISTS_TAC `h:real^1->real^2` THEN ASM_REWRITE_TAC[] THEN
+    EXPAND_TAC "h" THEN
+    REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+    MATCH_MP_TAC(TAUT `b /\ (c ==> a) /\ c ==> a /\ b /\ c`) THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[pathstart; PATHSTART_REVERSEPATH]; ALL_TAC] THEN
+    CONJ_TAC THENL
+     [DISCH_TAC THEN MATCH_MP_TAC ARC_SIMPLE_PATH_SUBPATH THEN
+      ASM_SIMP_TAC[ENDS_IN_UNIT_INTERVAL; ARC_IMP_SIMPLE_PATH;
+                   SIMPLE_PATH_REVERSEPATH] THEN
+      DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+      MP_TAC(ISPEC `path_image c1 UNION path_image c2:real^2->bool`
+       OUTSIDE_NO_OVERLAP) THEN
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+      EXISTS_TAC `pathstart(reversepath g2:real^1->real^2)` THEN
+      ASM_REWRITE_TAC[IN_INTER] THEN CONJ_TAC THENL
+       [ASM_REWRITE_TAC[PATHSTART_REVERSEPATH];
+       REWRITE_TAC[IN_UNION] THEN DISJ2_TAC THEN ASM_MESON_TAC[pathstart]];
+      ALL_TAC] THEN
+    UNDISCH_TAC
+     `(pathfinish h:real^2) IN path_image c1 UNION path_image c2` THEN
+    EXPAND_TAC "h" THEN REWRITE_TAC[PATHFINISH_SUBPATH] THEN
+    MP_TAC(ASSUME
+     `(path_image g2:real^2->bool) SUBSET
+      outside(path_image c1 UNION path_image c)`) THEN
+    DISCH_THEN(MP_TAC o SPEC `reversepath (g2:real^1->real^2) u` o
+      REWRITE_RULE[SUBSET]) THEN
+    ANTS_TAC THENL
+     [ONCE_REWRITE_TAC[GSYM PATH_IMAGE_REVERSEPATH] THEN
+      REWRITE_TAC[path_image; IN_IMAGE] THEN ASM_MESON_TAC[];
+      DISCH_TAC] THEN
+    MP_TAC(ISPEC `path_image c1 UNION path_image c:real^2->bool`
+        OUTSIDE_NO_OVERLAP) THEN
+    GEN_REWRITE_TAC LAND_CONV [EXTENSION] THEN
+    DISCH_THEN(MP_TAC o SPEC `reversepath (g2:real^1->real^2) u`) THEN
+    ASM_REWRITE_TAC[IN_INTER; IN_UNION; NOT_IN_EMPTY; DE_MORGAN_THM] THEN
+    CONV_TAC TAUT;
+    ABBREV_TAC `y':real^2 = pathfinish gwy`] THEN
+  MP_TAC(ISPECL [`reversepath gzx:real^1->real^2`; `gzy:real^1->real^2`]
+        ARC_CONNECTED_TRANS) THEN
+  ASM_SIMP_TAC[ARC_REVERSEPATH; PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+               PATH_IMAGE_REVERSEPATH; NOT_IMP] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `xy:real^1->real^2` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `(path_image xy DIFF {x:real^2,y}) SUBSET
+    inside(path_image c1 UNION path_image c2) INTER
+    outside(path_image c1 UNION path_image c) INTER
+    outside(path_image c2 UNION path_image c)`
+  ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `~(((path_image xy):real^2->bool) INTER
+      inside(path_image c1 UNION path_image c2) INTER
+      outside(path_image c1 UNION path_image c) INTER
+      outside(path_image c2 UNION path_image c) = {})`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `!x y. ~(s DIFF {x,y} = {}) /\ s DIFF {x,y} SUBSET t
+            ==> ~(s INTER t = {})`) THEN
+    MAP_EVERY EXISTS_TAC [`x:real^2`; `y:real^2`] THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[NONEMPTY_SIMPLE_PATH_ENDLESS; ARC_IMP_SIMPLE_PATH];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`reversepath gwy:real^1->real^2`; `gwx:real^1->real^2`]
+        ARC_CONNECTED_TRANS) THEN
+  ASM_SIMP_TAC[ARC_REVERSEPATH; PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+               PATH_IMAGE_REVERSEPATH; NOT_IMP] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `y'x':real^1->real^2` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `(path_image y'x' DIFF {x':real^2,y'}) SUBSET
+    outside(path_image c1 UNION path_image c2)`
+  ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?xy'. arc xy' /\
+          pathstart xy' = x /\ pathfinish xy' = (y':real^2) /\
+          (path_image xy' DELETE x) SUBSET
+          (inside (path_image c1 UNION path_image c2) INTER
+           outside (path_image c1 UNION path_image c) INTER
+           outside (path_image c2 UNION path_image c)) UNION
+          (path_image c2 DIFF {a,b}) /\
+          ~(path_image xy' INTER
+           inside(path_image c1 UNION path_image c2) INTER
+           outside(path_image c1 UNION path_image c) INTER
+           outside(path_image c2 UNION path_image c) = {})`
+  STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `y':real^2 = y` THENL
+     [UNDISCH_THEN `y':real^2 = y` SUBST_ALL_TAC THEN
+      EXISTS_TAC `xy:real^1->real^2` THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(SET_RULE
+       `!y. p DIFF {x,y} SUBSET i /\ y IN j
+            ==> p DELETE x SUBSET (i UNION j)`) THEN
+      EXISTS_TAC `y:real^2` THEN ASM_REWRITE_TAC[IN_DIFF] THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`c2:real^1->real^2`; `y:real^2`; `y':real^2`]
+         EXISTS_SUBARC_OF_ARC_NOENDS) THEN
+    ASM_SIMP_TAC[SIMPLE_PATH_IMP_ARC; NOT_IMP] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `yy':real^1->real^2` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `xy ++ yy':real^1->real^2` THEN
+    ASM_REWRITE_TAC[PATHSTART_JOIN; PATHFINISH_JOIN] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC ARC_JOIN THEN ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+      ASM_SIMP_TAC[PATH_IMAGE_JOIN; ARC_IMP_PATH] THEN
+      ASM_SIMP_TAC[SET_RULE
+       `~(a INTER c = {}) ==> ~((a UNION b) INTER c = {})`] THEN
+      MATCH_MP_TAC(SET_RULE
+       `s SUBSET (y INSERT t) ==> s DELETE y SUBSET t`) THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `~((path_image y'x':real^2->bool) INTER
+      outside(path_image c1 UNION path_image c2) = {})`
+  ASSUME_TAC THENL
+   [MP_TAC(ISPEC `y'x':real^1->real^2` NONEMPTY_SIMPLE_PATH_ENDLESS) THEN
+    ASM_SIMP_TAC[ARC_IMP_SIMPLE_PATH] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?y'x. arc y'x /\
+          pathstart y'x = y' /\ pathfinish y'x = (x:real^2) /\
+          ~(path_image y'x INTER
+            outside(path_image c1 UNION path_image c2) = {}) /\
+          (path_image y'x DELETE y') SUBSET
+          outside(path_image c1 UNION path_image c2) UNION
+          (path_image c1 DIFF {a,b})`
+  STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `x':real^2 = x` THENL
+     [UNDISCH_THEN `x':real^2 = x` SUBST_ALL_TAC THEN
+      EXISTS_TAC `y'x':real^1->real^2` THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(SET_RULE
+       `!y. p DIFF {x,y} SUBSET i /\ y IN j
+            ==> p DELETE x SUBSET (i UNION j)`) THEN
+      EXISTS_TAC `x:real^2` THEN ASM_REWRITE_TAC[IN_DIFF] THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`c1:real^1->real^2`; `x':real^2`; `x:real^2`]
+         EXISTS_SUBARC_OF_ARC_NOENDS) THEN
+    ASM_SIMP_TAC[SIMPLE_PATH_IMP_ARC; NOT_IMP] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `x'x:real^1->real^2` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `y'x' ++ x'x:real^1->real^2` THEN
+    ASM_REWRITE_TAC[PATHSTART_JOIN; PATHFINISH_JOIN] THEN
+    ASM_SIMP_TAC[PATH_IMAGE_JOIN; ARC_IMP_PATH] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC ARC_JOIN THEN ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+      ASM SET_TAC[];
+      ASM SET_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?j. simple_path j /\ pathstart j = x /\ pathfinish j = (x:real^2) /\
+        ~(path_image j INTER
+          inside(path_image c1 UNION path_image c2) = {}) /\
+        ~(path_image j INTER
+          outside(path_image c1 UNION path_image c2) = {}) /\
+        path_image j SUBSET
+        (inside(path_image c1 UNION path_image c2) INTER
+         outside(path_image c1 UNION path_image c) INTER
+         outside(path_image c2 UNION path_image c)) UNION
+        outside(path_image c1 UNION path_image c2) UNION
+        ((path_image c1 UNION path_image c2) DIFF {a,b})`
+  STRIP_ASSUME_TAC THENL
+   [EXISTS_TAC `xy' ++ y'x:real^1->real^2` THEN
+    ASM_REWRITE_TAC[PATHSTART_JOIN; PATHFINISH_JOIN] THEN
+    ASM_SIMP_TAC[PATH_IMAGE_JOIN; ARC_IMP_PATH] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC SIMPLE_PATH_JOIN_LOOP THEN ASM_REWRITE_TAC[] THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `xy DELETE x SUBSET s
+      ==> !t. yx DELETE y SUBSET t /\ s INTER t = {}
+              ==> xy INTER yx SUBSET {x,y}`)) THEN
+    EXISTS_TAC `outside(path_image c1 UNION path_image c2) UNION
+                path_image c1 DIFF {a:real^2, b}` THEN
+    ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPEC `path_image c1 UNION path_image c2:real^2->bool`
+        INSIDE_NO_OVERLAP) THEN
+    MP_TAC(ISPEC `path_image c1 UNION path_image c2:real^2->bool`
+        INSIDE_INTER_OUTSIDE) THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~((a:real^2) IN path_image j)` ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `s SUBSET t ==> ~(a IN t) ==> ~(a IN s)`)) THEN
+    MATCH_MP_TAC(SET_RULE
+     `~(a IN s) /\ ~(a IN t)
+      ==> ~(a IN ((s INTER s' INTER s'') UNION t UNION (u DIFF {a,b})))`) THEN
+    MAP_EVERY (MP_TAC o ISPEC `path_image c1 UNION path_image c2:real^2->bool`)
+      [OUTSIDE_NO_OVERLAP; INSIDE_NO_OVERLAP] THEN
+    REWRITE_TAC[IMP_IMP] THEN MATCH_MP_TAC MONO_AND THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?u v. ~(u = {}) /\ open u /\ connected u /\
+          ~(v = {}) /\ open v /\ connected v /\
+          u INTER v = {} /\ u UNION v = (:real^2) DIFF path_image j /\
+          frontier u = path_image j /\ frontier v = path_image j /\
+          a IN u`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPEC `j:real^1->real^2` JORDAN_CURVE_THEOREM) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`u:real^2->bool`; `v:real^2->bool`] THEN
+    STRIP_TAC THEN
+    SUBGOAL_THEN `(a:real^2) IN u \/ (a:real^2) IN v` MP_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    STRIP_TAC THENL
+     [MAP_EVERY EXISTS_TAC [`u:real^2->bool`; `v:real^2->bool`];
+      MAP_EVERY EXISTS_TAC [`v:real^2->bool`; `u:real^2->bool`]] THEN
+    ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[INTER_COMM; UNION_COMM] THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `~(v INTER inside(path_image c1 UNION path_image c2) = {}) /\
+    ~((v:real^2->bool) INTER outside(path_image c1 UNION path_image c2) = {})`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THENL
+     [UNDISCH_TAC
+       `~((path_image j:real^2->bool) INTER
+          inside(path_image c1 UNION path_image c2) = {})` THEN
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+      SUBST1_TAC(SYM(ASSUME `frontier v:real^2->bool = path_image j`)) THEN
+      DISCH_THEN(X_CHOOSE_THEN `p:real^2` MP_TAC) THEN
+      DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+      REWRITE_TAC[frontier; IN_DIFF; CLOSURE_APPROACHABLE] THEN
+      MP_TAC(GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL] (ASSUME
+       `open(inside(path_image c1 UNION path_image c2):real^2->bool)`)) THEN
+      DISCH_THEN(MP_TAC o SPEC `p:real^2`) THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+      ASM_REWRITE_TAC[SUBSET; IN_BALL] THEN ASM_MESON_TAC[];
+      UNDISCH_TAC
+       `~((path_image j:real^2->bool) INTER
+          outside(path_image c1 UNION path_image c2) = {})` THEN
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+      SUBST1_TAC(SYM(ASSUME `frontier v:real^2->bool = path_image j`)) THEN
+      DISCH_THEN(X_CHOOSE_THEN `p:real^2` MP_TAC) THEN
+      DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+      REWRITE_TAC[frontier; IN_DIFF; CLOSURE_APPROACHABLE] THEN
+      MP_TAC(GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL] (ASSUME
+       `open(outside(path_image c1 UNION path_image c2):real^2->bool)`)) THEN
+      DISCH_THEN(MP_TAC o SPEC `p:real^2`) THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+      ASM_REWRITE_TAC[SUBSET; IN_BALL] THEN ASM_MESON_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `~((v:real^2->bool) INTER (path_image c1 UNION path_image c2) = {})`
+  MP_TAC THENL
+   [MP_TAC(ASSUME `connected(v:real^2->bool)`) THEN
+    REWRITE_TAC[connected; CONTRAPOS_THM] THEN DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC
+     [`inside(path_image c1 UNION path_image c2):real^2->bool`;
+      `outside(path_image c1 UNION path_image c2):real^2->bool`] THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    GEN_REWRITE_TAC LAND_CONV [GSYM MEMBER_NOT_EMPTY]] THEN
+  REWRITE_TAC[IN_INTER; IN_UNION] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:real^2` (CONJUNCTS_THEN ASSUME_TAC)) THEN
+  SUBGOAL_THEN `~(p:real^2 = a)` ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  FIRST_X_ASSUM DISJ_CASES_TAC THENL
+   [SUBGOAL_THEN
+     `~((u:real^2->bool) INTER inside(path_image c1 UNION path_image c) = {})`
+    ASSUME_TAC THENL
+     [MP_TAC(ASSUME `open(u:real^2->bool)`) THEN
+      REWRITE_TAC[OPEN_CONTAINS_BALL; SUBSET; IN_BALL] THEN
+      DISCH_THEN(MP_TAC o SPEC `a:real^2`) THEN ASM_REWRITE_TAC[] THEN
+      ONCE_REWRITE_TAC[DIST_SYM] THEN
+      SUBGOAL_THEN
+       `(a:real^2) IN frontier(inside(path_image c1 UNION path_image c))`
+      MP_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[frontier; IN_DIFF]] THEN
+      REWRITE_TAC[CLOSURE_APPROACHABLE; GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+      MESON_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `~((v:real^2->bool) INTER inside(path_image c1 UNION path_image c) = {})`
+    ASSUME_TAC THENL
+     [MP_TAC(ASSUME `open(v:real^2->bool)`) THEN
+      REWRITE_TAC[OPEN_CONTAINS_BALL; SUBSET; IN_BALL] THEN
+      DISCH_THEN(MP_TAC o SPEC `p:real^2`) THEN ASM_REWRITE_TAC[] THEN
+      ONCE_REWRITE_TAC[DIST_SYM] THEN
+      SUBGOAL_THEN
+       `(p:real^2) IN frontier(inside(path_image c1 UNION path_image c))`
+      MP_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[frontier; IN_DIFF]] THEN
+      REWRITE_TAC[CLOSURE_APPROACHABLE; GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+      MESON_TAC[];
+      ALL_TAC] THEN
+    MP_TAC(ASSUME
+     `connected(inside(path_image c1 UNION path_image c):real^2->bool)`) THEN
+    REWRITE_TAC[connected] THEN
+    MAP_EVERY EXISTS_TAC [`u:real^2->bool`; `v:real^2->bool`] THEN
+    ASM_REWRITE_TAC[GSYM INTER_ASSOC; INTER_EMPTY] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `j SUBSET t ==> s INTER t = {} ==> s SUBSET UNIV DIFF j`)) THEN
+    MATCH_MP_TAC(SET_RULE
+     `!x. s INTER t2 = {} /\ u SUBSET t2 /\
+          x INTER v = {} /\ s SUBSET x
+          ==> s INTER
+              (t1 INTER t2 INTER t3 UNION u UNION (v DIFF w)) = {}`) THEN
+    EXISTS_TAC `inside(path_image c1 UNION path_image c2:real^2->bool)` THEN
+    ASM_REWRITE_TAC[INSIDE_INTER_OUTSIDE; INSIDE_NO_OVERLAP];
+    SUBGOAL_THEN
+     `~((u:real^2->bool) INTER inside(path_image c2 UNION path_image c) = {})`
+    ASSUME_TAC THENL
+     [MP_TAC(ASSUME `open(u:real^2->bool)`) THEN
+      REWRITE_TAC[OPEN_CONTAINS_BALL; SUBSET; IN_BALL] THEN
+      DISCH_THEN(MP_TAC o SPEC `a:real^2`) THEN ASM_REWRITE_TAC[] THEN
+      ONCE_REWRITE_TAC[DIST_SYM] THEN
+      SUBGOAL_THEN
+       `(a:real^2) IN frontier(inside(path_image c2 UNION path_image c))`
+      MP_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[frontier; IN_DIFF]] THEN
+      REWRITE_TAC[CLOSURE_APPROACHABLE; GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+      MESON_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `~((v:real^2->bool) INTER inside(path_image c2 UNION path_image c) = {})`
+    ASSUME_TAC THENL
+     [MP_TAC(ASSUME `open(v:real^2->bool)`) THEN
+      REWRITE_TAC[OPEN_CONTAINS_BALL; SUBSET; IN_BALL] THEN
+      DISCH_THEN(MP_TAC o SPEC `p:real^2`) THEN ASM_REWRITE_TAC[] THEN
+      ONCE_REWRITE_TAC[DIST_SYM] THEN
+      SUBGOAL_THEN
+       `(p:real^2) IN frontier(inside(path_image c2 UNION path_image c))`
+      MP_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[frontier; IN_DIFF]] THEN
+      REWRITE_TAC[CLOSURE_APPROACHABLE; GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+      MESON_TAC[];
+      ALL_TAC] THEN
+    MP_TAC(ASSUME
+     `connected(inside(path_image c2 UNION path_image c):real^2->bool)`) THEN
+    REWRITE_TAC[connected] THEN
+    MAP_EVERY EXISTS_TAC [`u:real^2->bool`; `v:real^2->bool`] THEN
+    ASM_REWRITE_TAC[GSYM INTER_ASSOC; INTER_EMPTY] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `j SUBSET t ==> s INTER t = {} ==> s SUBSET UNIV DIFF j`)) THEN
+    MATCH_MP_TAC(SET_RULE
+     `!x. s INTER t3 = {} /\ u SUBSET t3 /\
+          x INTER v = {} /\ s SUBSET x
+          ==> s INTER
+              (t1 INTER t2 INTER t3 UNION u UNION (v DIFF w)) = {}`) THEN
+    EXISTS_TAC `inside(path_image c1 UNION path_image c2:real^2->bool)` THEN
+    ASM_REWRITE_TAC[INSIDE_INTER_OUTSIDE; INSIDE_NO_OVERLAP]]);;
diff --git a/Multivariate/flyspeck.ml b/Multivariate/flyspeck.ml
new file mode 100644 (file)
index 0000000..ee46b82
--- /dev/null
@@ -0,0 +1,7029 @@
+(* ========================================================================= *)
+(* Results intended for Flyspeck.                                            *)
+(* ========================================================================= *)
+
+needs "Multivariate/polytope.ml";;
+needs "Multivariate/realanalysis.ml";;
+needs "Multivariate/geom.ml";;
+needs "Multivariate/cross.ml";;
+
+prioritize_vector();;
+
+(* ------------------------------------------------------------------------- *)
+(* Not really Flyspeck-specific but needs both angles and cross products.    *)
+(* ------------------------------------------------------------------------- *)
+
+let NORM_CROSS = prove
+ (`!x y. norm(x cross y) = norm(x) * norm(y) * sin(vector_angle x y)`,
+  REPEAT GEN_TAC THEN
+  MATCH_MP_TAC REAL_POW_EQ THEN EXISTS_TAC `2` THEN
+  SIMP_TAC[NORM_POS_LE; SIN_VECTOR_ANGLE_POS; REAL_LE_MUL; ARITH_EQ] THEN
+  MP_TAC(SPECL [`x:real^3`; `y:real^3`] NORM_CROSS_DOT) THEN
+  REWRITE_TAC[VECTOR_ANGLE] THEN
+  MP_TAC(SPEC `vector_angle (x:real^3) y` SIN_CIRCLE) THEN
+  CONV_TAC REAL_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* Other miscelleneous lemmas.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let COPLANAR_INSERT_0_NEG = prove
+ (`coplanar(vec 0 INSERT --x INSERT s) <=> coplanar(vec 0 INSERT x INSERT s)`,
+  REWRITE_TAC[coplanar; INSERT_SUBSET] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> ~(a ==> ~(b /\ c))`] THEN
+  SIMP_TAC[AFFINE_HULL_EQ_SPAN; SPAN_NEG_EQ]);;
+
+let COPLANAR_IMP_NEGLIGIBLE = prove
+ (`!s:real^3->bool. coplanar s ==> negligible s`,
+  REWRITE_TAC[coplanar] THEN
+  MESON_TAC[NEGLIGIBLE_AFFINE_HULL_3; NEGLIGIBLE_SUBSET]);;
+
+let NOT_COPLANAR_0_4_IMP_INDEPENDENT = prove
+ (`!v1 v2 v3:real^N. ~coplanar {vec 0,v1,v2,v3} ==> independent {v1,v2,v3}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[independent; CONTRAPOS_THM] THEN
+  REWRITE_TAC[dependent] THEN
+  SUBGOAL_THEN
+   `!v1 v2 v3:real^N. v1 IN span {v2,v3} ==> coplanar{vec 0,v1,v2,v3}`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[coplanar] THEN
+    MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `v2:real^N`; `v3:real^N`] THEN
+    SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC; IN_INSERT] THEN
+    REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET] THEN
+    ASM_SIMP_TAC[SPAN_SUPERSET; IN_INSERT] THEN
+    POP_ASSUM MP_TAC THEN SPEC_TAC(`v1:real^N`,`v1:real^N`) THEN
+    REWRITE_TAC[GSYM SUBSET] THEN MATCH_MP_TAC SPAN_MONO THEN SET_TAC[];
+    REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM SUBST_ALL_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPECL [`v1:real^N`; `v2:real^N`; `v3:real^N`]);
+      FIRST_X_ASSUM(MP_TAC o SPECL [`v2:real^N`; `v3:real^N`; `v1:real^N`]);
+      FIRST_X_ASSUM(MP_TAC o SPECL [`v3:real^N`; `v1:real^N`; `v2:real^N`])]
+    THEN REWRITE_TAC[INSERT_AC] THEN DISCH_THEN MATCH_MP_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `a IN s ==> s SUBSET t ==> a IN t`)) THEN
+    MATCH_MP_TAC SPAN_MONO THEN SET_TAC[]]);;
+
+let NOT_COPLANAR_NOT_COLLINEAR = prove
+ (`!v1 v2 v3 w:real^N. ~coplanar {v1, v2, v3, w} ==> ~collinear {v1, v2, v3}`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[COLLINEAR_AFFINE_HULL; coplanar; CONTRAPOS_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x:real^N` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `y:real^N` THEN
+  REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET] THEN STRIP_TAC THEN
+  EXISTS_TAC `w:real^N` THEN ASM_SIMP_TAC[HULL_INC; IN_INSERT] THEN
+  REPEAT CONJ_TAC THEN
+  MATCH_MP_TAC(SET_RULE `!t. t SUBSET s /\ x IN t ==> x IN s`) THEN
+  EXISTS_TAC `affine hull {x:real^N,y}` THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC HULL_MONO THEN SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some special scaling theorems.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let SUBSET_AFFINE_HULL_SPECIAL_SCALE = prove
+ (`!a x s t.
+        ~(a = &0)
+        ==> (vec 0 INSERT (a % x) INSERT s SUBSET affine hull t <=>
+             vec 0 INSERT x INSERT s SUBSET affine hull t)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[INSERT_SUBSET] THEN
+  MATCH_MP_TAC(TAUT `(a ==> (b <=> c)) ==> (a /\ b <=> a /\ c)`) THEN
+  ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; SPAN_MUL_EQ]);;
+
+let COLLINEAR_SPECIAL_SCALE = prove
+ (`!a x y. ~(a = &0) ==> (collinear {vec 0,a % x,y} <=> collinear{vec 0,x,y})`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[COLLINEAR_AFFINE_HULL] THEN
+  ASM_SIMP_TAC[SUBSET_AFFINE_HULL_SPECIAL_SCALE]);;
+
+let COLLINEAR_SCALE_ALL = prove
+ (`!a b v w. ~(a = &0) /\ ~(b = &0)
+             ==> (collinear {vec 0,a % v,b % w} <=> collinear {vec 0,v,w})`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[COLLINEAR_SPECIAL_SCALE] THEN
+  ONCE_REWRITE_TAC[SET_RULE `{a,b,c} = {a,c,b}`] THEN
+  ASM_SIMP_TAC[COLLINEAR_SPECIAL_SCALE]);;
+
+let COPLANAR_SPECIAL_SCALE = prove
+ (`!a x y z.
+    ~(a = &0) ==> (coplanar {vec 0,a % x,y,z} <=> coplanar {vec 0,x,y,z})`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[coplanar] THEN
+  ASM_SIMP_TAC[SUBSET_AFFINE_HULL_SPECIAL_SCALE]);;
+
+let COPLANAR_SCALE_ALL = prove
+ (`!a b c x y z.
+        ~(a = &0) /\ ~(b = &0) /\ ~(c = &0)
+        ==> (coplanar {vec 0,a % x,b % y,c % z} <=> coplanar {vec 0,x,y,z})`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[COPLANAR_SPECIAL_SCALE] THEN
+  ONCE_REWRITE_TAC[SET_RULE `{a,b,c,d} = {a,c,d,b}`] THEN
+  ASM_SIMP_TAC[COPLANAR_SPECIAL_SCALE] THEN
+  ONCE_REWRITE_TAC[SET_RULE `{a,b,c,d} = {a,c,d,b}`] THEN
+  ASM_SIMP_TAC[COPLANAR_SPECIAL_SCALE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Specialized lemmas about "dropout".                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let DROPOUT_BASIS_3 = prove
+ (`(dropout 3:real^3->real^2) (basis 1) = basis 1 /\
+   (dropout 3:real^3->real^2) (basis 2) = basis 2 /\
+   (dropout 3:real^3->real^2) (basis 3) = vec 0`,
+  SIMP_TAC[LAMBDA_BETA; dropout; basis; CART_EQ; DIMINDEX_2; DIMINDEX_3; ARITH;
+           VEC_COMPONENT; LT_IMP_LE; ARITH_RULE `i <= 2 ==> i + 1 <= 3`;
+           ARITH_RULE `1 <= i + 1`] THEN
+  ARITH_TAC);;
+
+let COLLINEAR_BASIS_3 = prove
+ (`collinear {vec 0,basis 3,x} <=> (dropout 3:real^3->real^2) x = vec 0`,
+  SIMP_TAC[CART_EQ; FORALL_2; FORALL_3; DIMINDEX_2; DIMINDEX_3;
+           dropout; LAMBDA_BETA; BASIS_COMPONENT; ARITH; REAL_MUL_RID;
+           VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RZERO; UNWIND_THM1;
+           COLLINEAR_LEMMA] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; GSYM EXISTS_REFL] THEN REAL_ARITH_TAC);;
+
+let OPEN_DROPOUT_3 = prove
+ (`!P. open {x | P x} ==> open {x | P((dropout 3:real^3->real^2) x)}`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`dropout 3:real^3->real^2`; `{x:real^2 | P x}`]
+   CONTINUOUS_OPEN_PREIMAGE_UNIV) THEN
+  ASM_REWRITE_TAC[IN_ELIM_THM] THEN DISCH_THEN MATCH_MP_TAC THEN
+  GEN_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_AT THEN
+  SIMP_TAC[LINEAR_DROPOUT; DIMINDEX_2; DIMINDEX_3; ARITH]);;
+
+let SLICE_DROPOUT_3 = prove
+ (`!P t. slice 3 t {x | P((dropout 3:real^3->real^2) x)} = {x | P x}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[slice] THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_ELIM_THM; IN_INTER] THEN
+  X_GEN_TAC `y:real^2` THEN EQ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  DISCH_TAC THEN EXISTS_TAC `(pushin 3 t:real^2->real^3) y` THEN
+  ASM_SIMP_TAC[DIMINDEX_2; DIMINDEX_3; DROPOUT_PUSHIN; ARITH] THEN
+  SIMP_TAC[pushin; LAMBDA_BETA; LT_REFL; DIMINDEX_3; ARITH]);;
+
+let NOT_COPLANAR_IMP_NOT_COLLINEAR_DROPOUT_3 = prove
+ (`!x y:real^3.
+        ~coplanar {vec 0,basis 3, x, y}
+        ==> ~collinear {vec 0,dropout 3 x:real^2,dropout 3 y}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[COLLINEAR_AFFINE_HULL; coplanar] THEN
+  REWRITE_TAC[CONTRAPOS_THM; INSERT_SUBSET; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^2`; `v:real^2`] THEN
+  REWRITE_TAC[EMPTY_SUBSET] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [AFFINE_HULL_2]) THEN
+  REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real`;`b:real`] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `?r s. a * r + b * s = -- &1` STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `a = &0` THENL
+     [UNDISCH_TAC `a + b = &1` THEN
+      ASM_SIMP_TAC[REAL_MUL_LZERO; REAL_ADD_LID; REAL_MUL_LID; EXISTS_REFL];
+      ASM_SIMP_TAC[REAL_FIELD
+       `~(a = &0) ==> (a * r + x = y <=> r = (y - x) / a)`] THEN
+      MESON_TAC[]];
+    ALL_TAC] THEN
+  EXISTS_TAC `vector[(u:real^2)$1; u$2; r]:real^3` THEN
+  EXISTS_TAC `vector[(v:real^2)$1; v$2; s]:real^3` THEN
+  EXISTS_TAC `basis 3:real^3` THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REWRITE_TAC[AFFINE_HULL_3; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY EXISTS_TAC [`a / &2`;`b / &2`; `&1 / &2`] THEN
+    ASM_REWRITE_TAC[REAL_ARITH
+      `a / &2 + b / &2 + &1 / &2 = &1 <=> a + b = &1`] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CART_EQ]) THEN
+    SIMP_TAC[CART_EQ; DIMINDEX_2; DIMINDEX_3; FORALL_2; FORALL_3;
+             VEC_COMPONENT; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+             VECTOR_3; BASIS_COMPONENT; ARITH] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SYM)) THEN CONV_TAC REAL_RING;
+    ALL_TAC] THEN
+  SIMP_TAC[AFFINE_HULL_EQ_SPAN] THEN DISCH_TAC THEN
+  SIMP_TAC[SPAN_SUPERSET; IN_INSERT] THEN
+  SUBGOAL_THEN
+    `!x. (dropout 3:real^3->real^2) x IN span {u,v}
+         ==> x IN span {vector [u$1; u$2; r], vector [v$1; v$2; s], basis 3}`
+    (fun th -> ASM_MESON_TAC[th]) THEN
+  GEN_TAC THEN REWRITE_TAC[SPAN_2; SPAN_3] THEN
+  SIMP_TAC[IN_ELIM_THM; IN_UNIV; CART_EQ; DIMINDEX_2; DIMINDEX_3;
+           FORALL_2; FORALL_3; dropout; VECTOR_ADD_COMPONENT; LAMBDA_BETA;
+           VECTOR_MUL_COMPONENT; VECTOR_3; BASIS_COMPONENT; ARITH] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[REAL_MUL_RZERO; REAL_ADD_RID] THEN
+  REWRITE_TAC[REAL_ARITH `x = a + b + c * &1 <=> c = x - a - b`] THEN
+  REWRITE_TAC[EXISTS_REFL]);;
+
+let SLICE_312 = prove
+ (`!s:real^3->bool. slice 1 t s = {y:real^2 | vector[t;y$1;y$2] IN s}`,
+  SIMP_TAC[EXTENSION; IN_SLICE; DIMINDEX_2; DIMINDEX_3; ARITH] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN
+  SIMP_TAC[CART_EQ; pushin; LAMBDA_BETA; FORALL_3; DIMINDEX_3; ARITH;
+           VECTOR_3]);;
+
+let SLICE_123 = prove
+ (`!s:real^3->bool. slice 3 t s = {y:real^2 | vector[y$1;y$2;t] IN s}`,
+  SIMP_TAC[EXTENSION; IN_SLICE; DIMINDEX_2; DIMINDEX_3; ARITH] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN
+  SIMP_TAC[CART_EQ; pushin; LAMBDA_BETA; FORALL_3; DIMINDEX_3; ARITH;
+           VECTOR_3]);;
+
+(* ------------------------------------------------------------------------- *)
+(* "Padding" injection from real^2 -> real^3 with zero last coordinate.      *)
+(* ------------------------------------------------------------------------- *)
+
+let pad2d3d = new_definition
+ `(pad2d3d:real^2->real^3) x = lambda i. if i < 3 then x$i else &0`;;
+
+let FORALL_PAD2D3D_THM = prove
+ (`!P. (!y:real^3. y$3 = &0 ==> P y) <=> (!x. P(pad2d3d x))`,
+  GEN_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[pad2d3d] THEN
+    SIMP_TAC[LAMBDA_BETA; DIMINDEX_3; ARITH; LT_REFL];
+    FIRST_X_ASSUM(MP_TAC o SPEC `(lambda i. (y:real^3)$i):real^2`) THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+    SIMP_TAC[CART_EQ; pad2d3d; DIMINDEX_3; ARITH; LAMBDA_BETA; DIMINDEX_2;
+             ARITH_RULE `i < 3 <=> i <= 2`] THEN
+    REWRITE_TAC[ARITH_RULE `i <= 3 <=> i <= 2 \/ i = 3`] THEN
+    ASM_MESON_TAC[]]);;
+
+let QUANTIFY_PAD2D3D_THM = prove
+ (`(!P. (!y:real^3. y$3 = &0 ==> P y) <=> (!x. P(pad2d3d x))) /\
+   (!P. (?y:real^3. y$3 = &0 /\ P y) <=> (?x. P(pad2d3d x)))`,
+  REWRITE_TAC[MESON[] `(?y. P y) <=> ~(!x. ~P x)`] THEN
+  REWRITE_TAC[GSYM FORALL_PAD2D3D_THM] THEN MESON_TAC[]);;
+
+let LINEAR_PAD2D3D = prove
+ (`linear pad2d3d`,
+  REWRITE_TAC[linear; pad2d3d] THEN
+  SIMP_TAC[CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+           LAMBDA_BETA; DIMINDEX_2; DIMINDEX_3; ARITH;
+           ARITH_RULE `i < 3 ==> i <= 2`] THEN
+  REPEAT STRIP_TAC THEN REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+  REAL_ARITH_TAC);;
+
+let INJECTIVE_PAD2D3D = prove
+ (`!x y. pad2d3d x = pad2d3d y ==> x = y`,
+  SIMP_TAC[CART_EQ; pad2d3d; LAMBDA_BETA; DIMINDEX_3; DIMINDEX_2] THEN
+  REWRITE_TAC[ARITH_RULE `i < 3 <=> i <= 2`] THEN
+  MESON_TAC[ARITH_RULE `i <= 2 ==> i <= 3`]);;
+
+let NORM_PAD2D3D = prove
+ (`!x. norm(pad2d3d x) = norm x`,
+  SIMP_TAC[NORM_EQ; DOT_2; DOT_3; pad2d3d; LAMBDA_BETA;
+           DIMINDEX_2; DIMINDEX_3; ARITH] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Apply 3D->2D conversion to a goal. Take care to preserve variable names.  *)
+(* ------------------------------------------------------------------------- *)
+
+let PAD2D3D_QUANTIFY_CONV =
+  let gv = genvar `:real^2` in
+  let pth = CONV_RULE (BINOP_CONV(BINDER_CONV(RAND_CONV(GEN_ALPHA_CONV gv))))
+                      QUANTIFY_PAD2D3D_THM in
+  let conv1 = GEN_REWRITE_CONV I [pth]
+  and dest_quant tm = try dest_forall tm with Failure _ -> dest_exists tm in
+  fun tm ->
+    let th = conv1 tm in
+    let name = fst(dest_var(fst(dest_quant tm))) in
+    let ty = snd(dest_var(fst(dest_quant(rand(concl th))))) in
+    CONV_RULE(RAND_CONV(GEN_ALPHA_CONV(mk_var(name,ty)))) th;;
+
+let PAD2D3D_TAC =
+  let pad2d3d_tm = `pad2d3d`
+  and pths = [LINEAR_PAD2D3D; INJECTIVE_PAD2D3D; NORM_PAD2D3D]
+  and cth = prove
+   (`{} = IMAGE pad2d3d {} /\
+     vec 0 = pad2d3d(vec 0)`,
+    REWRITE_TAC[IMAGE_CLAUSES] THEN MESON_TAC[LINEAR_PAD2D3D; LINEAR_0]) in
+  let lasttac =
+    GEN_REWRITE_TAC REDEPTH_CONV [LINEAR_INVARIANTS pad2d3d_tm pths] in
+  fun gl -> (GEN_REWRITE_TAC ONCE_DEPTH_CONV [cth] THEN
+             CONV_TAC(DEPTH_CONV PAD2D3D_QUANTIFY_CONV) THEN
+             lasttac) gl;;
+
+(* ------------------------------------------------------------------------- *)
+(* The notion of a plane, and using it to characterize coplanarity.          *)
+(* ------------------------------------------------------------------------- *)
+
+let plane = new_definition
+  `plane x = (?u v w. ~(collinear {u,v,w}) /\ x = affine hull {u,v,w})`;;
+
+let PLANE_TRANSLATION_EQ = prove
+ (`!a:real^N s. plane(IMAGE (\x. a + x) s) <=> plane s`,
+  REWRITE_TAC[plane] THEN GEOM_TRANSLATE_TAC[]);;
+
+let PLANE_TRANSLATION = prove
+ (`!a:real^N s. plane s ==> plane(IMAGE (\x. a + x) s)`,
+  REWRITE_TAC[PLANE_TRANSLATION_EQ]);;
+
+add_translation_invariants [PLANE_TRANSLATION_EQ];;
+
+let PLANE_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N p.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (plane(IMAGE f p) <=> plane p)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[plane] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `?u. u IN IMAGE f (:real^M) /\
+        ?v. v IN IMAGE f (:real^M) /\
+            ?w. w IN IMAGE (f:real^M->real^N) (:real^M) /\
+                ~collinear {u, v, w} /\ IMAGE f p = affine hull {u, v, w}` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[RIGHT_AND_EXISTS_THM; IN_IMAGE; IN_UNIV] THEN
+    REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+    EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `{u,v,w} SUBSET IMAGE (f:real^M->real^N) p` MP_TAC THENL
+     [ASM_REWRITE_TAC[HULL_SUBSET]; SET_TAC[]];
+    REWRITE_TAC[EXISTS_IN_IMAGE; IN_UNIV] THEN
+    REWRITE_TAC[SET_RULE `{f a,f b,f c} = IMAGE f {a,b,c}`] THEN
+    ASM_SIMP_TAC[AFFINE_HULL_LINEAR_IMAGE] THEN
+    REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN BINOP_TAC THENL
+     [ASM_MESON_TAC[COLLINEAR_LINEAR_IMAGE_EQ]; ASM SET_TAC[]]]);;
+
+let PLANE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N p.
+        linear f /\ plane p /\ (!x y. f x = f y ==> x = y)
+        ==> plane(IMAGE f p)`,
+  MESON_TAC[PLANE_LINEAR_IMAGE_EQ]);;
+
+add_linear_invariants [PLANE_LINEAR_IMAGE_EQ];;
+
+let AFFINE_PLANE = prove
+ (`!p. plane p ==> affine p`,
+  SIMP_TAC[plane; LEFT_IMP_EXISTS_THM; AFFINE_AFFINE_HULL]);;
+
+let ROTATION_PLANE_HORIZONTAL = prove
+ (`!s. plane s
+       ==>  ?a f. orthogonal_transformation f /\ det(matrix f) = &1 /\
+                  IMAGE f (IMAGE (\x. a + x) s) = {z:real^3 | z$3 = &0}`,
+  let lemma = prove
+   (`span {z:real^3 | z$3 = &0} = {z:real^3 | z$3 = &0}`,
+    REWRITE_TAC[SPAN_EQ_SELF; subspace; IN_ELIM_THM] THEN
+    SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; VEC_COMPONENT;
+             DIMINDEX_3; ARITH] THEN REAL_ARITH_TAC) in
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [plane]) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^3`; `b:real^3`; `c:real^3`] THEN
+  MAP_EVERY (fun t ->
+    ASM_CASES_TAC t THENL [ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC];
+                           ALL_TAC])
+   [`a:real^3 = b`; `a:real^3 = c`; `b:real^3 = c`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC) THEN
+  ASM_SIMP_TAC[AFFINE_HULL_INSERT_SPAN; IN_INSERT; NOT_IN_EMPTY] THEN
+  EXISTS_TAC `--a:real^3` THEN
+  REWRITE_TAC[SET_RULE `IMAGE (\x:real^3. --a + x) {a + x | x | x IN s} =
+                        IMAGE (\x. --a + a + x) s`] THEN
+  REWRITE_TAC[VECTOR_ARITH `--a + a + x:real^3 = x`; IMAGE_ID] THEN
+  REWRITE_TAC[SET_RULE `{x - a:real^x | x = b \/ x = c} = {b - a,c - a}`] THEN
+  MP_TAC(ISPEC `span{b - a:real^3,c - a}`
+    ROTATION_LOWDIM_HORIZONTAL) THEN
+  REWRITE_TAC[DIMINDEX_3] THEN ANTS_TAC THENL
+   [MATCH_MP_TAC LET_TRANS THEN
+    EXISTS_TAC `CARD{b - a:real^3,c - a}` THEN
+    SIMP_TAC[DIM_SPAN; DIM_LE_CARD; FINITE_RULES] THEN
+    SIMP_TAC[CARD_CLAUSES; FINITE_RULES] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^3->real^3` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP ORTHOGONAL_TRANSFORMATION_LINEAR) THEN
+  ASM_SIMP_TAC[GSYM SPAN_LINEAR_IMAGE] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM lemma] THEN
+  MATCH_MP_TAC DIM_EQ_SPAN THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[IMAGE_SUBSET; SPAN_INC; SUBSET_TRANS]; ALL_TAC] THEN
+  MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `2` THEN CONJ_TAC THENL
+   [MP_TAC(ISPECL [`{z:real^3 | z$3 = &0}`; `(:real^3)`] DIM_EQ_SPAN) THEN
+    REWRITE_TAC[SUBSET_UNIV; DIM_UNIV; DIMINDEX_3; lemma] THEN
+    MATCH_MP_TAC(TAUT `~r /\ (~p ==> q) ==> (q ==> r) ==> p`) THEN
+    REWRITE_TAC[ARITH_RULE `~(x <= 2) <=> 3 <= x`] THEN
+    REWRITE_TAC[EXTENSION; SPAN_UNIV; IN_ELIM_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `vector[&0;&0;&1]:real^3`) THEN
+    REWRITE_TAC[IN_UNIV; VECTOR_3] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `dim {b - a:real^3,c - a}` THEN
+  CONJ_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[LE_REFL; DIM_INJECTIVE_LINEAR_IMAGE;
+             ORTHOGONAL_TRANSFORMATION_INJECTIVE]] THEN
+  MP_TAC(ISPEC `{b - a:real^3,c - a}` INDEPENDENT_BOUND_GENERAL) THEN
+  SIMP_TAC[CARD_CLAUSES; FINITE_RULES; IN_SING; NOT_IN_EMPTY] THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH `b - a:real^3 = c - a <=> b = c`; ARITH] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE (RAND_CONV o RAND_CONV)
+    [SET_RULE `{a,b,c} = {b,a,c}`]) THEN
+  REWRITE_TAC[] THEN ONCE_REWRITE_TAC[COLLINEAR_3] THEN
+  REWRITE_TAC[independent; CONTRAPOS_THM; dependent] THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; RIGHT_OR_DISTRIB] THEN
+  REWRITE_TAC[EXISTS_OR_THM; UNWIND_THM2] THEN
+  ASM_SIMP_TAC[SET_RULE `~(a = b) ==> {a,b} DELETE b = {a}`;
+               SET_RULE `~(a = b) ==> {a,b} DELETE a = {b}`;
+               VECTOR_ARITH `b - a:real^3 = c - a <=> b = c`] THEN
+  REWRITE_TAC[SPAN_BREAKDOWN_EQ; SPAN_EMPTY; IN_SING] THEN
+  ONCE_REWRITE_TAC[VECTOR_SUB_EQ] THEN MESON_TAC[COLLINEAR_LEMMA; INSERT_AC]);;
+
+let ROTATION_HORIZONTAL_PLANE = prove
+ (`!p. plane p
+       ==>  ?a f. orthogonal_transformation f /\ det(matrix f) = &1 /\
+                  IMAGE (\x. a + x) (IMAGE f {z:real^3 | z$3 = &0}) = p`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP ROTATION_PLANE_HORIZONTAL) THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^3`
+   (X_CHOOSE_THEN `f:real^3->real^3` STRIP_ASSUME_TAC)) THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `g:real^3->real^3` STRIP_ASSUME_TAC o MATCH_MP
+    ORTHOGONAL_TRANSFORMATION_INVERSE) THEN
+  MAP_EVERY EXISTS_TAC [`--a:real^3`; `g:real^3->real^3`] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID;
+                  VECTOR_ARITH `--a + a + x:real^3 = x`] THEN
+  MATCH_MP_TAC(REAL_RING `!f. f * g = &1 /\ f = &1 ==> g = &1`) THEN
+  EXISTS_TAC `det(matrix(f:real^3->real^3))` THEN
+  REWRITE_TAC[GSYM DET_MUL] THEN
+  ASM_SIMP_TAC[GSYM MATRIX_COMPOSE; ORTHOGONAL_TRANSFORMATION_LINEAR] THEN
+  ASM_REWRITE_TAC[o_DEF; MATRIX_ID; DET_I]);;
+
+let COPLANAR = prove
+ (`2 <= dimindex(:N)
+   ==> !s:real^N->bool. coplanar s <=> ?x. plane x /\ s SUBSET x`,
+  DISCH_TAC THEN GEN_TAC THEN REWRITE_TAC[coplanar; plane] THEN
+  CONV_TAC SYM_CONV THEN REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[MESON[]
+   `(?x u v w. p x u v w) <=> (?u v w x. p x u v w)`] THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC; RIGHT_EXISTS_AND_THM; UNWIND_THM2] THEN
+  EQ_TAC THENL [MESON_TAC[]; REWRITE_TAC[LEFT_IMP_EXISTS_THM]] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`; `w:real^N`] THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `s SUBSET {u + x:real^N | x | x IN span {y - u | y IN {v,w}}}`
+  MP_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ] SUBSET_TRANS)) THEN
+    REWRITE_TAC[AFFINE_HULL_INSERT_SUBSET_SPAN];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+  DISCH_THEN(MP_TAC o ISPEC `\x:real^N. x - u` o MATCH_MP IMAGE_SUBSET) THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; VECTOR_ADD_SUB; IMAGE_ID; SIMPLE_IMAGE] THEN
+  REWRITE_TAC[IMAGE_CLAUSES] THEN
+  MP_TAC(ISPECL [`{v - u:real^N,w - u}`; `2`] LOWDIM_EXPAND_BASIS) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN MATCH_MP_TAC LE_TRANS THEN
+    EXISTS_TAC `CARD{v - u:real^N,w - u}` THEN
+    SIMP_TAC[DIM_LE_CARD; FINITE_INSERT; FINITE_RULES] THEN
+    SIMP_TAC[CARD_CLAUSES; FINITE_RULES] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool`
+   (CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC)) THEN
+  CONV_TAC(LAND_CONV HAS_SIZE_CONV) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC SUBST_ALL_TAC) THEN
+  UNDISCH_TAC `span {v - u, w - u} SUBSET span {a:real^N, b}` THEN
+  REWRITE_TAC[GSYM IMP_CONJ_ALT] THEN
+  DISCH_THEN(ASSUME_TAC o MATCH_MP SUBSET_TRANS) THEN
+  MAP_EVERY EXISTS_TAC [`u:real^N`; `u + a:real^N`; `u + b:real^N`] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[COLLINEAR_3; COLLINEAR_LEMMA;
+                VECTOR_ARITH `--x = vec 0 <=> x = vec 0`;
+                VECTOR_ARITH `u - (u + a):real^N = --a`;
+                VECTOR_ARITH `(u + b) - (u + a):real^N = b - a`] THEN
+    REWRITE_TAC[DE_MORGAN_THM; VECTOR_SUB_EQ;
+      VECTOR_ARITH `b - a = c % -- a <=> (c - &1) % a + &1 % b = vec 0`] THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[IN_INSERT; INDEPENDENT_NONZERO]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_TAC `u:real`) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [independent]) THEN
+    REWRITE_TAC[DEPENDENT_EXPLICIT] THEN
+    MAP_EVERY EXISTS_TAC [`{a:real^N,b}`;
+                          `\x:real^N. if x = a then u - &1 else &1`] THEN
+    REWRITE_TAC[FINITE_INSERT; FINITE_RULES; SUBSET_REFL] THEN
+    CONJ_TAC THENL
+     [EXISTS_TAC `b:real^N` THEN ASM_REWRITE_TAC[IN_INSERT] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    SIMP_TAC[VSUM_CLAUSES; FINITE_RULES] THEN
+    ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; VECTOR_ADD_RID];
+    ALL_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AFFINE_HULL_INSERT_SPAN o rand o snd) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+    REWRITE_TAC[VECTOR_ARITH `u = u + a <=> a = vec 0`] THEN
+    ASM_MESON_TAC[INDEPENDENT_NONZERO; IN_INSERT];
+    ALL_TAC] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `\x:real^N. u + x` o MATCH_MP IMAGE_SUBSET) THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID;
+              ONCE_REWRITE_RULE[VECTOR_ADD_SYM] VECTOR_SUB_ADD] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] SUBSET_TRANS) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[SIMPLE_IMAGE; IMAGE_CLAUSES; VECTOR_ADD_SUB] THEN
+  SET_TAC[]);;
+
+let COPLANAR_DET_EQ_0 = prove
+ (`!v0 v1 (v2: real^3) v3.
+        coplanar {v0,v1,v2,v3} <=>
+        det(vector[v1 - v0; v2 - v0; v3 - v0]) = &0`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[DET_EQ_0_RANK; RANK_ROW] THEN
+  REWRITE_TAC[rows; row; LAMBDA_ETA] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+  REWRITE_TAC[GSYM numseg; DIMINDEX_3] THEN
+  CONV_TAC(ONCE_DEPTH_CONV NUMSEG_CONV) THEN
+  SIMP_TAC[IMAGE_CLAUSES; coplanar; VECTOR_3] THEN EQ_TAC THENL
+   [REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^3`; `b:real^3`; `c:real^3`] THEN
+    W(MP_TAC o PART_MATCH lhand AFFINE_HULL_INSERT_SUBSET_SPAN o
+        rand o lhand o snd) THEN
+    REWRITE_TAC[GSYM IMP_CONJ_ALT] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP SUBSET_TRANS) THEN
+    DISCH_THEN(MP_TAC o ISPEC `\x:real^3. x - a` o MATCH_MP IMAGE_SUBSET) THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    REWRITE_TAC[IMAGE_CLAUSES; GSYM IMAGE_o; o_DEF; VECTOR_ADD_SUB; IMAGE_ID;
+                SIMPLE_IMAGE] THEN
+    REWRITE_TAC[INSERT_SUBSET] THEN STRIP_TAC THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM DIM_SPAN] THEN MATCH_MP_TAC LET_TRANS THEN
+    EXISTS_TAC `CARD {b - a:real^3,c - a}` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC SPAN_CARD_GE_DIM;
+      SIMP_TAC[CARD_CLAUSES; FINITE_RULES] THEN ARITH_TAC] THEN
+    REWRITE_TAC[FINITE_INSERT; FINITE_RULES] THEN
+    GEN_REWRITE_TAC RAND_CONV [GSYM SPAN_SPAN] THEN
+    MATCH_MP_TAC SPAN_MONO THEN REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET] THEN
+    MP_TAC(VECTOR_ARITH `!x y:real^3. x - y = (x - a) - (y - a)`) THEN
+    DISCH_THEN(fun th -> REPEAT CONJ_TAC THEN
+      GEN_REWRITE_TAC LAND_CONV [th]) THEN
+    MATCH_MP_TAC SPAN_SUB THEN ASM_REWRITE_TAC[];
+    DISCH_TAC THEN
+    MP_TAC(ISPECL [`{v1 - v0,v2 - v0,v3 - v0}:real^3->bool`; `2`]
+                  LOWDIM_EXPAND_BASIS) THEN
+    ASM_REWRITE_TAC[ARITH_RULE `n <= 2 <=> n < 3`; DIMINDEX_3; ARITH] THEN
+    DISCH_THEN(X_CHOOSE_THEN `t:real^3->bool`
+     (CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC)) THEN
+    CONV_TAC(LAND_CONV HAS_SIZE_CONV) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^3`; `b:real^3`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC SUBST_ALL_TAC) THEN
+    SIMP_TAC[COPLANAR; DIMINDEX_3; ARITH; plane] THEN
+    MAP_EVERY EXISTS_TAC [`v0:real^3`; `v0 + a:real^3`; `v0 + b:real^3`] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) AFFINE_HULL_INSERT_SPAN o
+      rand o snd) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+      REWRITE_TAC[VECTOR_ARITH `u = u + a <=> a = vec 0`] THEN
+      ASM_MESON_TAC[INDEPENDENT_NONZERO; IN_INSERT];
+      ALL_TAC] THEN
+    DISCH_THEN SUBST1_TAC THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    REWRITE_TAC[SIMPLE_IMAGE; IMAGE_CLAUSES; IMAGE_ID; VECTOR_ADD_SUB] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC
+     `IMAGE (\v:real^3. v0 + v) (span{v1 - v0, v2 - v0, v3 - v0})` THEN
+    ASM_SIMP_TAC[IMAGE_SUBSET] THEN
+    REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; IN_IMAGE] THEN CONJ_TAC THENL
+     [EXISTS_TAC `vec 0:real^3` THEN REWRITE_TAC[SPAN_0] THEN VECTOR_ARITH_TAC;
+      REWRITE_TAC[VECTOR_ARITH `v1:real^N = v0 + x <=> x = v1 - v0`] THEN
+      REWRITE_TAC[UNWIND_THM2] THEN REPEAT CONJ_TAC THEN
+      MATCH_MP_TAC SPAN_SUPERSET THEN REWRITE_TAC[IN_INSERT]]]);;
+
+let COPLANAR_CROSS_DOT = prove
+ (`!v w x y. coplanar {v,w,x,y} <=> ((w - v) cross (x - v)) dot (y - v) = &0`,
+  REWRITE_TAC[COPLANAR_DET_EQ_0; GSYM DOT_CROSS_DET] THEN
+  MESON_TAC[CROSS_TRIPLE; DOT_SYM]);;
+
+let PLANE_AFFINE_HULL_3 = prove
+ (`!a b c:real^N. plane(affine hull {a,b,c}) <=> ~collinear{a,b,c}`,
+  REWRITE_TAC[plane] THEN MESON_TAC[COLLINEAR_AFFINE_HULL_COLLINEAR]);;
+
+let AFFINE_HULL_3_GENERATED = prove
+ (`!s u v w:real^N.
+        s SUBSET affine hull {u,v,w} /\ ~collinear s
+        ==> affine hull {u,v,w} = affine hull s`,
+  REWRITE_TAC[COLLINEAR_AFF_DIM; INT_NOT_LE] THEN REPEAT STRIP_TAC THEN
+  CONV_TAC SYM_CONV THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM HULL_HULL] THEN
+  MATCH_MP_TAC AFF_DIM_EQ_AFFINE_HULL THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC INT_LE_TRANS THEN EXISTS_TAC `&2:int` THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_INT_ARITH_TAC] THEN
+  REWRITE_TAC[AFF_DIM_AFFINE_HULL] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) AFF_DIM_LE_CARD o lhand o snd) THEN
+  REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] INT_LE_TRANS) THEN
+  REWRITE_TAC[INT_LE_SUB_RADD; INT_OF_NUM_ADD; INT_OF_NUM_LE] THEN
+  SIMP_TAC[CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Additional WLOG tactic to rotate any plane p to {z | z$3 = &0}.           *)
+(* ------------------------------------------------------------------------- *)
+
+let GEOM_HORIZONTAL_PLANE_RULE =
+  let ifn = MATCH_MP
+   (TAUT `(p ==> (x <=> x')) /\ (~p ==> (x <=> T)) ==> (x' ==> x)`)
+  and pth = prove
+   (`!a f. orthogonal_transformation (f:real^N->real^N)
+           ==> ((!P. (!x. P x) <=> (!x. P (a + f x))) /\
+                (!P. (?x. P x) <=> (?x. P (a + f x))) /\
+                (!Q. (!s. Q s) <=> (!s. Q (IMAGE (\x. a + x) (IMAGE f s)))) /\
+                (!Q. (?s. Q s) <=> (?s. Q (IMAGE (\x. a + x) (IMAGE f s))))) /\
+               (!P. {x | P x} =
+                    IMAGE (\x. a + x) (IMAGE f {x | P(a + f x)}))`,
+    REPEAT GEN_TAC THEN DISCH_TAC THEN
+    MP_TAC(ISPEC `(\x. a + x) o (f:real^N->real^N)`
+      QUANTIFY_SURJECTION_THM) THEN REWRITE_TAC[o_THM; IMAGE_o] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_SURJECTIVE;
+                  VECTOR_ARITH `a + (x - a:real^N) = x`])
+  and cth = prove
+   (`!a f. {} = IMAGE (\x:real^3. a + x) (IMAGE f {})`,
+    REWRITE_TAC[IMAGE_CLAUSES])
+  and oth = prove
+   (`!f:real^3->real^3.
+        orthogonal_transformation f /\ det(matrix f) = &1
+        ==> linear f /\
+            (!x y. f x = f y ==> x = y) /\
+            (!y. ?x. f x = y) /\
+            (!x. norm(f x) = norm x) /\
+            (2 <= dimindex(:3) ==> det(matrix f) = &1)`,
+    GEN_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_LINEAR];
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_INJECTIVE];
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_SURJECTIVE];
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION]])
+  and fth = MESON[]
+   `(!a f. q a f ==> (p <=> p' a f))
+    ==> ((?a f. q a f) ==> (p <=> !a f. q a f ==> p' a f))` in
+  fun tm ->
+    let x,bod = dest_forall tm in
+    let th1 = EXISTS_GENVAR_RULE
+      (UNDISCH(ISPEC x ROTATION_HORIZONTAL_PLANE)) in
+    let [a;f],tm1 = strip_exists(concl th1) in
+    let [th_orth;th_det;th_im] = CONJUNCTS(ASSUME tm1) in
+    let th2 = PROVE_HYP th_orth (UNDISCH(ISPECL [a;f] pth)) in
+    let th3 = (EXPAND_QUANTS_CONV(ASSUME(concl th2)) THENC
+               SUBS_CONV[GSYM th_im; ISPECL [a;f] cth]) bod in
+    let th4 = PROVE_HYP th2 th3 in
+    let th5 = TRANSLATION_INVARIANTS a in
+    let th6 = GEN_REWRITE_RULE (RAND_CONV o REDEPTH_CONV)
+                [ASSUME(concl th5)] th4 in
+    let th7 = PROVE_HYP th5 th6 in
+    let th8s = CONJUNCTS(MATCH_MP oth (CONJ th_orth th_det)) in
+    let th9 = LINEAR_INVARIANTS f th8s in
+    let th10 = GEN_REWRITE_RULE (RAND_CONV o REDEPTH_CONV) [th9] th7 in
+    let th11 = if intersect (frees(concl th10)) [a;f] = []
+               then PROVE_HYP th1 (itlist SIMPLE_CHOOSE [a;f] th10)
+               else MP (MATCH_MP fth (GENL [a;f] (DISCH_ALL th10))) th1 in
+    let th12 = REWRITE_CONV[ASSUME(mk_neg(hd(hyp th11)))] bod in
+    let th13 = ifn(CONJ (DISCH_ALL th11) (DISCH_ALL th12)) in
+    let th14 = MATCH_MP MONO_FORALL (GEN x th13) in
+    GEN_REWRITE_RULE (TRY_CONV o LAND_CONV) [FORALL_SIMP] th14;;
+
+let GEOM_HORIZONTAL_PLANE_TAC p =
+  W(fun (asl,w) ->
+        let avs,bod = strip_forall w
+        and avs' = subtract (frees w) (freesl(map (concl o snd) asl)) in
+        let avs,bod = strip_forall w in
+        MAP_EVERY X_GEN_TAC avs THEN
+        MAP_EVERY (fun t -> SPEC_TAC(t,t)) (rev(subtract (avs@avs') [p])) THEN
+        SPEC_TAC(p,p) THEN
+        W(MATCH_MP_TAC o GEOM_HORIZONTAL_PLANE_RULE o snd));;
+
+(* ------------------------------------------------------------------------- *)
+(* Affsign and its special cases, with invariance theorems.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let lin_combo = new_definition
+  `lin_combo V f = vsum V (\v. f v % (v:real^N))`;;
+
+let affsign = new_definition
+  `affsign sgn s t (v:real^A) <=>
+     (?f. (v = lin_combo (s UNION t) f) /\
+          (!w. t w ==> sgn (f w)) /\
+          (sum (s UNION t) f = &1))`;;
+
+let sgn_gt = new_definition `sgn_gt = (\t. (&0 < t))`;;
+let sgn_ge = new_definition `sgn_ge = (\t. (&0 <= t))`;;
+let sgn_lt = new_definition `sgn_lt = (\t. (t < &0))`;;
+let sgn_le = new_definition `sgn_le = (\t. (t <= &0))`;;
+
+let aff_gt_def = new_definition `aff_gt = affsign sgn_gt`;;
+let aff_ge_def = new_definition `aff_ge = affsign sgn_ge`;;
+let aff_lt_def = new_definition `aff_lt = affsign sgn_lt`;;
+let aff_le_def = new_definition `aff_le = affsign sgn_le`;;
+
+let AFFSIGN = prove
+ (`affsign sgn s t =
+        {y | ?f. y = vsum (s UNION t) (\v. f v % v) /\
+                (!w. w IN t ==> sgn(f w)) /\
+                sum (s UNION t) f = &1}`,
+  REWRITE_TAC[FUN_EQ_THM; affsign; lin_combo; IN_ELIM_THM] THEN
+  REWRITE_TAC[IN]);;
+
+let AFFSIGN_ALT = prove
+ (`affsign sgn s t =
+        {y | ?f. (!w. w IN (s UNION t) ==> w IN t ==> sgn(f w)) /\
+                 sum (s UNION t) f = &1 /\
+                 vsum (s UNION t) (\v. f v % v) = y}`,
+  REWRITE_TAC[SET_RULE `(w IN (s UNION t) ==> w IN t ==> P w) <=>
+                        (w IN t ==> P w)`] THEN
+  REWRITE_TAC[AFFSIGN; EXTENSION; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let IN_AFFSIGN = prove
+ (`y IN affsign sgn s t <=>
+        ?u. (!x. x IN t ==> sgn(u x)) /\
+            sum (s UNION t) u = &1 /\
+            vsum (s UNION t) (\x. u(x) % x) = y`,
+  REWRITE_TAC[AFFSIGN; IN_ELIM_THM] THEN SET_TAC[]);;
+
+let AFFSIGN_DISJOINT_DIFF = prove
+ (`!s t. affsign sgn s t = affsign sgn (s DIFF t) t`,
+  REWRITE_TAC[AFFSIGN; SET_RULE `(s DIFF t) UNION t = s UNION t`]);;
+
+let AFF_GE_DISJOINT_DIFF = prove
+ (`!s t. aff_ge s t = aff_ge (s DIFF t) t`,
+  REWRITE_TAC[aff_ge_def] THEN MATCH_ACCEPT_TAC AFFSIGN_DISJOINT_DIFF);;
+
+let AFFSIGN_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N sgn s t v.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (affsign sgn (IMAGE f s) (IMAGE f t) =
+             IMAGE f (affsign sgn s t))`,
+  let lemma0 = prove
+   (`vsum s (\x. u x % x) = vsum {x | x IN s /\ ~(u x = &0)} (\x. u x % x)`,
+    MATCH_MP_TAC VSUM_SUPERSET THEN SIMP_TAC[SUBSET; IN_ELIM_THM] THEN
+    REWRITE_TAC[TAUT `p /\ ~(p /\ ~q) <=> p /\ q`] THEN
+    SIMP_TAC[o_THM; VECTOR_MUL_LZERO]) in
+  let lemma1 = prove
+   (`!f:real^M->real^N s.
+           linear f /\ (!x y. f x = f y ==> x = y)
+           ==> (sum(IMAGE f s) u = &1 /\ vsum(IMAGE f s) (\x. u x % x) = y <=>
+                sum s (u o f) = &1 /\ f(vsum s (\x. (u o f) x % x)) = y)`,
+    REPEAT STRIP_TAC THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) SUM_IMAGE o funpow 3 lhand o snd) THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[]; DISCH_THEN SUBST1_TAC] THEN
+    MATCH_MP_TAC(MESON[] `(p ==> z = x) ==> (p /\ x = y <=> p /\ z = y)`) THEN
+    DISCH_TAC THEN ONCE_REWRITE_TAC[lemma0] THEN
+    SUBGOAL_THEN
+     `{y | y IN IMAGE (f:real^M->real^N) s /\ ~(u y = &0)} =
+      IMAGE f {x | x IN s /\ ~(u(f x) = &0)}`
+    SUBST1_TAC THENL [ASM SET_TAC[]; CONV_TAC SYM_CONV] THEN
+    SUBGOAL_THEN `FINITE {x | x IN s /\ ~(u((f:real^M->real^N) x) = &0)}`
+    ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE
+       (LAND_CONV o RATOR_CONV o RATOR_CONV) [sum]) THEN
+      ONCE_REWRITE_TAC[ITERATE_EXPAND_CASES] THEN
+      REWRITE_TAC[GSYM sum; support; NEUTRAL_REAL_ADD; o_THM] THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_OF_NUM_EQ; ARITH_EQ];
+      W(MP_TAC o PART_MATCH (lhs o rand) VSUM_IMAGE o lhand o snd) THEN
+      ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+      DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[o_DEF] THEN
+      ASM_SIMP_TAC[LINEAR_VSUM; o_DEF; GSYM LINEAR_CMUL]]) in
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[EXTENSION; IN_AFFSIGN] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN REWRITE_TAC[IN_IMAGE; IN_AFFSIGN] THEN
+  REWRITE_TAC[GSYM IMAGE_UNION] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP lemma1 th]) THEN
+  X_GEN_TAC `y:real^N` THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `vsum (s UNION t) (\x. (u o (f:real^M->real^N)) x % x)` THEN
+    ASM_REWRITE_TAC[] THEN
+    EXISTS_TAC `(u:real^N->real) o (f:real^M->real^N)` THEN
+    ASM_REWRITE_TAC[] THEN ASM_REWRITE_TAC[o_THM];
+    MP_TAC(ISPEC `f:real^M->real^N` LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+    ASM_REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^M` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `x:real^M`
+     (CONJUNCTS_THEN2 SUBST1_TAC MP_TAC)) THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^M->real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(u:real^M->real) o (g:real^N->real^M)` THEN
+    ASM_REWRITE_TAC[o_DEF; ETA_AX]]);;
+
+let AFF_GE_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> aff_ge (IMAGE f s) (IMAGE f t) = IMAGE f (aff_ge s t)`,
+  REWRITE_TAC[aff_ge_def; AFFSIGN_INJECTIVE_LINEAR_IMAGE]);;
+
+let AFF_GT_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> aff_gt (IMAGE f s) (IMAGE f t) = IMAGE f (aff_gt s t)`,
+  REWRITE_TAC[aff_gt_def; AFFSIGN_INJECTIVE_LINEAR_IMAGE]);;
+
+let AFF_LE_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> aff_le (IMAGE f s) (IMAGE f t) = IMAGE f (aff_le s t)`,
+  REWRITE_TAC[aff_le_def; AFFSIGN_INJECTIVE_LINEAR_IMAGE]);;
+
+let AFF_LT_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> aff_lt (IMAGE f s) (IMAGE f t) = IMAGE f (aff_lt s t)`,
+  REWRITE_TAC[aff_lt_def; AFFSIGN_INJECTIVE_LINEAR_IMAGE]);;
+
+add_linear_invariants
+  [AFFSIGN_INJECTIVE_LINEAR_IMAGE;
+   AFF_GE_INJECTIVE_LINEAR_IMAGE;
+   AFF_GT_INJECTIVE_LINEAR_IMAGE;
+   AFF_LE_INJECTIVE_LINEAR_IMAGE;
+   AFF_LT_INJECTIVE_LINEAR_IMAGE];;
+
+let IN_AFFSIGN_TRANSLATION = prove
+ (`!sgn s t a v:real^N.
+        affsign sgn s t v
+        ==> affsign sgn (IMAGE (\x. a + x) s) (IMAGE (\x. a + x) t) (a + v)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[affsign; lin_combo] THEN
+  ONCE_REWRITE_TAC[SET_RULE `(!x. s x ==> p x) <=> (!x. x IN s ==> p x)`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:real^N->real`
+   (CONJUNCTS_THEN2 SUBST_ALL_TAC STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `\x. (f:real^N->real)(x - a)` THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_UNION] THEN REPEAT CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE; ETA_AX;
+                    VECTOR_ARITH `(a + x) - a:real^N = x`];
+    W(MP_TAC o PART_MATCH (lhs o rand) SUM_IMAGE o lhs o snd) THEN
+    SIMP_TAC[VECTOR_ARITH `a + x:real^N = a + y <=> x = y`] THEN
+    ASM_REWRITE_TAC[o_DEF; VECTOR_ADD_SUB; ETA_AX]] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `a + vsum {x | x IN s UNION t /\ ~(f x = &0)} (\v:real^N. f v % v)` THEN
+  CONJ_TAC THENL
+   [AP_TERM_TAC THEN MATCH_MP_TAC VSUM_SUPERSET THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0; SUBSET; IN_ELIM_THM] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `vsum (IMAGE (\x:real^N. a + x)
+                          {x | x IN s UNION t /\ ~(f x = &0)})
+                   (\v. f(v - a) % v)` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_SUPERSET THEN
+    CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; VECTOR_MUL_EQ_0] THEN
+    REWRITE_TAC[VECTOR_ADD_SUB] THEN SET_TAC[]] THEN
+  SUBGOAL_THEN `FINITE {x:real^N | x IN s UNION t /\ ~(f x = &0)}`
+  ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE
+     (LAND_CONV o RATOR_CONV o RATOR_CONV) [sum]) THEN
+    ONCE_REWRITE_TAC[ITERATE_EXPAND_CASES] THEN
+    REWRITE_TAC[GSYM sum; support; NEUTRAL_REAL_ADD] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_OF_NUM_EQ; ARITH_EQ];
+    ALL_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) VSUM_IMAGE o rhs o snd) THEN
+  ASM_SIMP_TAC[VECTOR_ARITH `a + x:real^N = a + y <=> x = y`] THEN
+  DISCH_THEN(K ALL_TAC) THEN REWRITE_TAC[o_DEF; VECTOR_ADD_SUB] THEN
+  ASM_SIMP_TAC[VECTOR_ADD_LDISTRIB; VSUM_ADD] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[VSUM_RMUL] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_MUL_LID] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC SUM_SUPERSET THEN SET_TAC[]);;
+
+let AFFSIGN_TRANSLATION = prove
+ (`!a:real^N sgn s t.
+        affsign sgn (IMAGE (\x. a + x) s) (IMAGE (\x. a + x) t) =
+        IMAGE (\x. a + x) (affsign sgn s t)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; IN] THEN GEN_TAC THEN
+    DISCH_THEN(MP_TAC o SPEC `--a:real^N` o
+      MATCH_MP IN_AFFSIGN_TRANSLATION) THEN
+    REWRITE_TAC[GSYM IMAGE_o; o_DEF; VECTOR_ARITH `--a + a + x:real^N = x`;
+                IMAGE_ID] THEN
+    DISCH_TAC THEN REWRITE_TAC[IMAGE; IN_ELIM_THM] THEN
+    EXISTS_TAC `--a + x:real^N` THEN ASM_REWRITE_TAC[IN] THEN VECTOR_ARITH_TAC;
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN GEN_TAC THEN REWRITE_TAC[IN] THEN
+    DISCH_THEN(MP_TAC o SPEC `a:real^N` o MATCH_MP IN_AFFSIGN_TRANSLATION) THEN
+    REWRITE_TAC[]]);;
+
+let AFF_GE_TRANSLATION = prove
+ (`!a:real^N s t.
+        aff_ge (IMAGE (\x. a + x) s) (IMAGE (\x. a + x) t) =
+        IMAGE (\x. a + x) (aff_ge s t)`,
+  REWRITE_TAC[aff_ge_def; AFFSIGN_TRANSLATION]);;
+
+let AFF_GT_TRANSLATION = prove
+ (`!a:real^N s t.
+        aff_gt (IMAGE (\x. a + x) s) (IMAGE (\x. a + x) t) =
+        IMAGE (\x. a + x) (aff_gt s t)`,
+  REWRITE_TAC[aff_gt_def; AFFSIGN_TRANSLATION]);;
+
+let AFF_LE_TRANSLATION = prove
+ (`!a:real^N s t.
+        aff_le (IMAGE (\x. a + x) s) (IMAGE (\x. a + x) t) =
+        IMAGE (\x. a + x) (aff_le s t)`,
+  REWRITE_TAC[aff_le_def; AFFSIGN_TRANSLATION]);;
+
+let AFF_LT_TRANSLATION = prove
+ (`!a:real^N s t.
+        aff_lt (IMAGE (\x. a + x) s) (IMAGE (\x. a + x) t) =
+        IMAGE (\x. a + x) (aff_lt s t)`,
+  REWRITE_TAC[aff_lt_def; AFFSIGN_TRANSLATION]);;
+
+add_translation_invariants
+  [AFFSIGN_TRANSLATION;
+   AFF_GE_TRANSLATION;
+   AFF_GT_TRANSLATION;
+   AFF_LE_TRANSLATION;
+   AFF_LT_TRANSLATION];;
+
+(* ------------------------------------------------------------------------- *)
+(* Automate special cases of affsign.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let AFF_TAC =
+  REWRITE_TAC[DISJOINT_INSERT; DISJOINT_EMPTY] THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; DE_MORGAN_THM] THEN
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[aff_ge_def; aff_gt_def; aff_le_def; aff_lt_def;
+              sgn_ge; sgn_gt; sgn_le; sgn_lt; AFFSIGN_ALT] THEN
+  REWRITE_TAC[SET_RULE `(x INSERT s) UNION t = x INSERT (s UNION t)`] THEN
+  REWRITE_TAC[UNION_EMPTY] THEN
+  SIMP_TAC[FINITE_INSERT; FINITE_UNION; AFFINE_HULL_FINITE_STEP_GEN;
+           FINITE_EMPTY; RIGHT_EXISTS_AND_THM; REAL_LT_ADD;
+           REAL_LE_ADD; REAL_ARITH `&0 <= a / &2 <=> &0 <= a`;
+           REAL_ARITH `&0 < a / &2 <=> &0 < a`;
+           REAL_ARITH `a / &2 <= &0 <=> a <= &0`;
+           REAL_ARITH `a / &2 < &0 <=> a < &0`;
+           REAL_ARITH `a < &0 /\ b < &0 ==> a + b < &0`;
+           REAL_ARITH `a < &0 /\ b <= &0 ==> a + b <= &0`] THEN
+  ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; real_ge] THEN
+  REWRITE_TAC[REAL_ARITH `x - y:real = z <=> x = y + z`;
+              VECTOR_ARITH `x - y:real^N = z <=> x = y + z`] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM; REAL_ADD_RID; VECTOR_ADD_RID] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `&1 = x <=> x = &1`] THEN
+  REWRITE_TAC[] THEN SET_TAC[];;
+
+let AFF_GE_1_1 = prove
+ (`!x v w.
+        DISJOINT {x} {v}
+        ==> aff_ge {x} {v} =
+             {y | ?t1 t2.
+                     &0 <= t2 /\
+                     t1 + t2 = &1 /\
+                     y = t1 % x + t2 % v }`,
+  AFF_TAC);;
+
+let AFF_GE_1_2 = prove
+ (`!x v w.
+        DISJOINT {x} {v,w}
+        ==> aff_ge {x} {v,w} =
+             {y | ?t1 t2 t3.
+
+                     &0 <= t2 /\ &0 <= t3 /\
+
+                     t1 + t2 + t3 = &1 /\
+                     y = t1 % x + t2 % v + t3 % w}`,
+  AFF_TAC);;
+
+let AFF_GE_2_1 = prove
+ (`!x v w.
+        DISJOINT {x,v} {w}
+        ==> aff_ge {x,v} {w} =
+             {y | ?t1 t2 t3.
+                     &0 <= t3 /\
+                     t1 + t2 + t3 = &1 /\
+                     y = t1 % x + t2 % v + t3 % w}`,
+  AFF_TAC);;
+
+let AFF_GT_1_1 = prove
+ (`!x v w.
+        DISJOINT {x} {v}
+        ==> aff_gt {x} {v} =
+             {y | ?t1 t2.
+                     &0 < t2 /\
+                     t1 + t2 = &1 /\
+                     y = t1 % x + t2 % v}`,
+  AFF_TAC);;
+
+let AFF_GT_1_2 = prove
+ (`!x v w.
+        DISJOINT {x} {v,w}
+        ==> aff_gt {x} {v,w} =
+             {y | ?t1 t2 t3.
+                     &0 < t2 /\ &0 < t3 /\
+                     t1 + t2 + t3 = &1 /\
+                     y = t1 % x + t2 % v + t3 % w}`,
+  AFF_TAC);;
+
+let AFF_GT_2_1 = prove
+ (`!x v w.
+        DISJOINT {x,v} {w}
+        ==> aff_gt {x,v} {w} =
+             {y | ?t1 t2 t3.
+                     &0 < t3 /\
+                     t1 + t2 + t3 = &1 /\
+                     y = t1 % x + t2 % v + t3 % w}`,
+  AFF_TAC);;
+
+let AFF_GT_3_1 = prove
+ (`!v w x y.
+        DISJOINT {v,w,x} {y}
+        ==> aff_gt {v,w,x} {y} =
+             {z | ?t1 t2 t3 t4.
+                     &0 < t4 /\
+                     t1 + t2 + t3 + t4 = &1 /\
+                     z = t1 % v + t2 % w + t3 % x + t4 % y}`,
+  AFF_TAC);;
+
+let AFF_LT_1_1 = prove
+ (`!x v.
+        DISJOINT {x} {v}
+        ==> aff_lt {x} {v} =
+             {y | ?t1 t2.
+                     t2 < &0 /\
+                     t1 + t2 = &1 /\
+                     y = t1 % x + t2 % v}`,
+  AFF_TAC);;
+
+let AFF_LT_2_1 = prove
+ (`!x v w.
+        DISJOINT {x,v} {w}
+        ==> aff_lt {x,v} {w} =
+             {y | ?t1 t2 t3.
+                     t3 < &0 /\
+                     t1 + t2 + t3 = &1 /\
+                     y = t1 % x + t2 % v + t3 % w}`,
+  AFF_TAC);;
+
+let AFF_GE_1_2_0 = prove
+ (`!v w.
+        ~(v = vec 0) /\ ~(w = vec 0)
+        ==> aff_ge {vec 0} {v,w} = {a % v + b % w | &0 <= a /\ &0 <= b}`,
+  SIMP_TAC[AFF_GE_1_2;
+           SET_RULE `DISJOINT {a} {b,c} <=> ~(b = a) /\ ~(c = a)`] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+  ONCE_REWRITE_TAC[MESON[]
+   `(?a b c. P b c /\ Q b c /\ R a b c /\ S b c) <=>
+    (?b c. P b c /\ Q b c /\ S b c /\ ?a. R a b c)`] THEN
+  REWRITE_TAC[REAL_ARITH `t + s:real = &1 <=> t = &1 - s`; EXISTS_REFL] THEN
+  SET_TAC[]);;
+
+let AFF_GE_1_1_0 = prove
+ (`!v. ~(v = vec 0) ==> aff_ge {vec 0} {v} = {a % v | &0 <= a}`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [SET_RULE `{a} = {a,a}`] THEN
+  ASM_SIMP_TAC[AFF_GE_1_2_0; GSYM VECTOR_ADD_RDISTRIB] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+  MESON_TAC[REAL_LE_ADD; REAL_ARITH
+   `&0 <= a ==> &0 <= a / &2 /\ a / &2 + a / &2 = a`]);;
+
+let AFF_GE_2_1_0 = prove
+ (`!v w. DISJOINT {vec 0, v} {w}
+         ==> aff_ge {vec 0, v} {w} = {s % v + t % w |s,t| &0 <= t}`,
+  SIMP_TAC[AFF_GE_2_1; VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> q /\ p /\ r`] THEN
+  ONCE_REWRITE_TAC[MESON[] `(?a b c. P a b c) <=> (?c b a. P a b c)`] THEN
+  REWRITE_TAC[REAL_ARITH `t + u = &1 <=> t = &1 - u`; UNWIND_THM2] THEN
+  SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Properties of affsign variants.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_AFFSIGN = prove
+ (`!sgn. (!x y u. sgn(x) /\ sgn(y) /\ &0 <= u /\ u <= &1
+                  ==> sgn((&1 - u) * x + u * y))
+         ==> !s t:real^N->bool. convex(affsign sgn s t)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[AFFSIGN; CONVEX_ALT] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`; `u:real`] THEN
+  REWRITE_TAC[IN_ELIM_THM; IMP_CONJ; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  X_GEN_TAC `f:real^N->real` THEN STRIP_TAC THEN
+  X_GEN_TAC `g:real^N->real` THEN STRIP_TAC THEN
+  EXISTS_TAC `\x:real^N. (&1 - u) * f x + u * g x` THEN
+  ASM_REWRITE_TAC[VECTOR_ADD_RDISTRIB] THEN REPEAT CONJ_TAC THENL
+   [CONV_TAC SYM_CONV THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) VSUM_ADD_GEN o lhand o snd) THEN
+    REWRITE_TAC[GSYM VECTOR_MUL_ASSOC; VSUM_LMUL] THEN
+    DISCH_THEN MATCH_MP_TAC;
+    ASM_MESON_TAC[];
+    W(MP_TAC o PART_MATCH (lhs o rand) SUM_ADD_GEN o lhand o snd) THEN
+    ASM_REWRITE_TAC[GSYM VECTOR_MUL_ASSOC; SUM_LMUL] THEN
+    REWRITE_TAC[REAL_MUL_RID; REAL_SUB_ADD] THEN DISCH_THEN MATCH_MP_TAC] THEN
+  (CONJ_TAC THENL
+    [MP_TAC(ASSUME `sum (s UNION t:real^N->bool) f = &1`);
+     MP_TAC(ASSUME `sum (s UNION t:real^N->bool) g = &1`)]) THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [sum] THEN
+  ONCE_REWRITE_TAC[iterate] THEN
+  REWRITE_TAC[support; NEUTRAL_REAL_ADD] THEN
+  COND_CASES_TAC THEN REWRITE_TAC[REAL_OF_NUM_EQ; ARITH_EQ] THEN
+  DISCH_THEN(K ALL_TAC) THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] FINITE_SUBSET)) THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN GEN_TAC THEN
+  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[CONTRAPOS_THM] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_MUL_RZERO; REAL_MUL_RZERO]);;
+
+let CONVEX_AFF_GE = prove
+ (`!s t. convex(aff_ge s t)`,
+  REWRITE_TAC[aff_ge_def; sgn_ge] THEN MATCH_MP_TAC CONVEX_AFFSIGN THEN
+  SIMP_TAC[REAL_LE_MUL; REAL_LE_ADD; REAL_SUB_LE]);;
+
+let CONVEX_AFF_LE = prove
+ (`!s t. convex(aff_le s t)`,
+  REWRITE_TAC[aff_le_def; sgn_le] THEN MATCH_MP_TAC CONVEX_AFFSIGN THEN
+  REWRITE_TAC[REAL_ARITH `x <= &0 <=> &0 <= --x`; REAL_NEG_ADD; GSYM
+    REAL_MUL_RNEG] THEN
+  SIMP_TAC[REAL_LE_MUL; REAL_LE_ADD; REAL_SUB_LE]);;
+
+let CONVEX_AFF_GT = prove
+ (`!s t. convex(aff_gt s t)`,
+  REWRITE_TAC[aff_gt_def; sgn_gt] THEN MATCH_MP_TAC CONVEX_AFFSIGN THEN
+  REWRITE_TAC[REAL_ARITH `&0 <= x <=> x = &0 \/ &0 < x`;
+              REAL_ARITH `x <= &1 <=> x = &1 \/ x < &1`] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[REAL_MUL_LZERO; REAL_ADD_LID; REAL_ADD_RID; REAL_MUL_LID] THEN
+  ASM_SIMP_TAC[REAL_LT_ADD; REAL_LT_MUL; REAL_SUB_LT]);;
+
+let CONVEX_AFF_LT = prove
+ (`!s t. convex(aff_lt s t)`,
+  REWRITE_TAC[aff_lt_def; sgn_lt] THEN MATCH_MP_TAC CONVEX_AFFSIGN THEN
+  REWRITE_TAC[REAL_ARITH `x < &0 <=> &0 < --x`; REAL_NEG_ADD; GSYM
+    REAL_MUL_RNEG] THEN
+  REWRITE_TAC[REAL_ARITH `&0 <= x <=> x = &0 \/ &0 < x`;
+              REAL_ARITH `x <= &1 <=> x = &1 \/ x < &1`] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[REAL_MUL_LZERO; REAL_ADD_LID; REAL_ADD_RID; REAL_MUL_LID] THEN
+  ASM_SIMP_TAC[REAL_LT_ADD; REAL_LT_MUL; REAL_SUB_LT]);;
+
+let AFFSIGN_SUBSET_AFFINE_HULL = prove
+ (`!sgn s t. (affsign sgn s t) SUBSET (affine hull (s UNION t))`,
+  REWRITE_TAC[AFFINE_HULL_FINITE; AFFSIGN] THEN SET_TAC[]);;
+
+let AFF_GE_SUBSET_AFFINE_HULL = prove
+ (`!s t. (aff_ge s t) SUBSET (affine hull (s UNION t))`,
+  REWRITE_TAC[aff_ge_def; AFFSIGN_SUBSET_AFFINE_HULL]);;
+
+let AFF_LE_SUBSET_AFFINE_HULL = prove
+ (`!s t. (aff_le s t) SUBSET (affine hull (s UNION t))`,
+  REWRITE_TAC[aff_le_def; AFFSIGN_SUBSET_AFFINE_HULL]);;
+
+let AFF_GT_SUBSET_AFFINE_HULL = prove
+ (`!s t. (aff_gt s t) SUBSET (affine hull (s UNION t))`,
+  REWRITE_TAC[aff_gt_def; AFFSIGN_SUBSET_AFFINE_HULL]);;
+
+let AFF_LT_SUBSET_AFFINE_HULL = prove
+ (`!s t. (aff_lt s t) SUBSET (affine hull (s UNION t))`,
+  REWRITE_TAC[aff_lt_def; AFFSIGN_SUBSET_AFFINE_HULL]);;
+
+let AFFSIGN_EQ_AFFINE_HULL = prove
+ (`!sgn s t. affsign sgn s {} = affine hull s`,
+  REWRITE_TAC[AFFSIGN; AFFINE_HULL_FINITE] THEN
+  REWRITE_TAC[UNION_EMPTY; NOT_IN_EMPTY] THEN SET_TAC[]);;
+
+let AFF_GE_EQ_AFFINE_HULL = prove
+ (`!s t. aff_ge s {} = affine hull s`,
+  REWRITE_TAC[aff_ge_def; AFFSIGN_EQ_AFFINE_HULL]);;
+
+let AFF_LE_EQ_AFFINE_HULL = prove
+ (`!s t. aff_le s {} = affine hull s`,
+  REWRITE_TAC[aff_le_def; AFFSIGN_EQ_AFFINE_HULL]);;
+
+let AFF_GT_EQ_AFFINE_HULL = prove
+ (`!s t. aff_gt s {} = affine hull s`,
+  REWRITE_TAC[aff_gt_def; AFFSIGN_EQ_AFFINE_HULL]);;
+
+let AFF_LT_EQ_AFFINE_HULL = prove
+ (`!s t. aff_lt s {} = affine hull s`,
+  REWRITE_TAC[aff_lt_def; AFFSIGN_EQ_AFFINE_HULL]);;
+
+let AFFSIGN_SUBSET_AFFSIGN = prove
+ (`!sgn1 sgn2 s t.
+        (!x. sgn1 x ==> sgn2 x) ==> affsign sgn1 s t SUBSET affsign sgn2 s t`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[AFFSIGN; SUBSET; IN_ELIM_THM] THEN
+  GEN_TAC THEN MATCH_MP_TAC MONO_EXISTS THEN ASM_MESON_TAC[]);;
+
+let AFF_GT_SUBSET_AFF_GE = prove
+ (`!s t. aff_gt s t SUBSET aff_ge s t`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[aff_gt_def; aff_ge_def] THEN
+  MATCH_MP_TAC AFFSIGN_SUBSET_AFFSIGN THEN
+  SIMP_TAC[sgn_gt; sgn_ge; REAL_LT_IMP_LE]);;
+
+let AFFSIGN_MONO_LEFT = prove
+ (`!sgn s s' t:real^N->bool.
+        s SUBSET s' ==> affsign sgn s t SUBSET affsign sgn s' t`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[AFFSIGN; SUBSET; IN_ELIM_THM] THEN
+  X_GEN_TAC `y:real^N` THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\x:real^N. if x IN s UNION t then u x else &0` THEN
+  REWRITE_TAC[COND_RAND; COND_RATOR; VECTOR_MUL_LZERO] THEN
+  REWRITE_TAC[GSYM SUM_RESTRICT_SET; GSYM VSUM_RESTRICT_SET] THEN
+  ASM_SIMP_TAC[SET_RULE
+   `s SUBSET s' ==> {x | x IN s' UNION t /\ x IN s UNION t} = s UNION t`] THEN
+  ASM SET_TAC[]);;
+
+let AFFSIGN_MONO_SHUFFLE = prove
+ (`!sgn s t s' t'.
+        s' UNION t' = s UNION t /\ t' SUBSET t
+        ==> affsign sgn s t SUBSET affsign sgn s' t'`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[AFFSIGN; SUBSET; IN_ELIM_THM] THEN
+  GEN_TAC THEN MATCH_MP_TAC MONO_EXISTS THEN
+  ASM_REWRITE_TAC[] THEN ASM SET_TAC[]);;
+
+let AFF_GT_MONO_LEFT = prove
+ (`!s s' t. s SUBSET s' ==> aff_gt s t SUBSET aff_gt s' t`,
+  REWRITE_TAC[aff_gt_def; AFFSIGN_MONO_LEFT]);;
+
+let AFF_GE_MONO_LEFT = prove
+ (`!s s' t. s SUBSET s' ==> aff_ge s t SUBSET aff_ge s' t`,
+  REWRITE_TAC[aff_ge_def; AFFSIGN_MONO_LEFT]);;
+
+let AFF_LT_MONO_LEFT = prove
+ (`!s s' t. s SUBSET s' ==> aff_lt s t SUBSET aff_lt s' t`,
+  REWRITE_TAC[aff_lt_def; AFFSIGN_MONO_LEFT]);;
+
+let AFF_LE_MONO_LEFT = prove
+ (`!s s' t. s SUBSET s' ==> aff_le s t SUBSET aff_le s' t`,
+  REWRITE_TAC[aff_le_def; AFFSIGN_MONO_LEFT]);;
+
+let AFFSIGN_MONO_RIGHT = prove
+ (`!sgn s t t':real^N->bool.
+        sgn(&0) /\ t SUBSET t' /\ DISJOINT s t'
+        ==> affsign sgn s t SUBSET affsign sgn s t'`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[AFFSIGN; SUBSET; IN_ELIM_THM] THEN
+  X_GEN_TAC `y:real^N` THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\x:real^N. if x IN s UNION t then u x else &0` THEN
+  REWRITE_TAC[COND_RAND; COND_RATOR; VECTOR_MUL_LZERO] THEN
+  REWRITE_TAC[GSYM SUM_RESTRICT_SET; GSYM VSUM_RESTRICT_SET] THEN
+  ASM_SIMP_TAC[SET_RULE
+   `t SUBSET t' ==> {x | x IN s UNION t' /\ x IN s UNION t} = s UNION t`] THEN
+  ASM SET_TAC[]);;
+
+let AFF_GE_MONO_RIGHT = prove
+ (`!s t t'. t SUBSET t' /\ DISJOINT s t' ==> aff_ge s t SUBSET aff_ge s t'`,
+  SIMP_TAC[aff_ge_def; AFFSIGN_MONO_RIGHT; sgn_ge; REAL_POS]);;
+
+let AFF_LE_MONO_RIGHT = prove
+ (`!s t t'. t SUBSET t' /\ DISJOINT s t' ==> aff_le s t SUBSET aff_le s t'`,
+  SIMP_TAC[aff_le_def; AFFSIGN_MONO_RIGHT; sgn_le; REAL_LE_REFL]);;
+
+let AFFINE_HULL_SUBSET_AFFSIGN = prove
+ (`!sgn s t:real^N->bool.
+        sgn(&0) /\ DISJOINT s t
+        ==> affine hull s SUBSET affsign sgn s t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `affsign sgn (s:real^N->bool) {}` THEN CONJ_TAC THENL
+   [REWRITE_TAC[AFFSIGN_EQ_AFFINE_HULL; SUBSET_REFL];
+    MATCH_MP_TAC AFFSIGN_MONO_RIGHT THEN ASM SET_TAC[]]);;
+
+let AFFINE_HULL_SUBSET_AFF_GE = prove
+ (`!s t. DISJOINT s t ==> affine hull s SUBSET aff_ge s t`,
+  SIMP_TAC[aff_ge_def; sgn_ge; REAL_LE_REFL; AFFINE_HULL_SUBSET_AFFSIGN]);;
+
+let AFF_GE_AFF_GT_DECOMP = prove
+ (`!s:real^N->bool.
+        FINITE s /\ FINITE t /\ DISJOINT s t
+        ==> aff_ge s t = aff_gt s t UNION
+                         UNIONS {aff_ge s (t DELETE a) | a | a IN t}`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(SET_RULE
+   `t' SUBSET t /\ (!a. a IN s ==> f(a) SUBSET t) /\
+    (!y. y IN t ==> y IN t' \/ ?a. a IN s /\ y IN f(a))
+    ==> t = t' UNION UNIONS {f a | a IN s}`) THEN
+  REWRITE_TAC[AFF_GT_SUBSET_AFF_GE] THEN
+  ASM_SIMP_TAC[DELETE_SUBSET; AFF_GE_MONO_RIGHT] THEN
+  REWRITE_TAC[aff_ge_def; aff_gt_def; AFFSIGN; sgn_ge; sgn_gt] THEN
+  X_GEN_TAC `y:real^N` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC) THEN
+  ASM_CASES_TAC `!x:real^N. x IN t ==> &0 < u x` THENL
+   [DISJ1_TAC THEN EXISTS_TAC `u:real^N->real` THEN ASM_REWRITE_TAC[];
+    DISJ2_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM]) THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 <= x ==> (&0 < x <=> ~(x = &0))`] THEN
+    REWRITE_TAC[NOT_IMP] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `a:real^N` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    EXISTS_TAC `u:real^N->real` THEN
+    ASM_SIMP_TAC[SET_RULE
+     `a IN t /\ DISJOINT s t
+      ==> s UNION (t DELETE a) = (s UNION t) DELETE a`] THEN
+    ASM_SIMP_TAC[IN_DELETE; SUM_DELETE; VSUM_DELETE; REAL_SUB_RZERO;
+                 FINITE_UNION; IN_UNION] THEN
+    REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_SUB_RZERO]]);;
+
+let AFFSIGN_SPECIAL_SCALE = prove
+ (`!sgn s t a v.
+        FINITE s /\ FINITE t /\
+        ~(vec 0 IN t) /\ ~(v IN t) /\ ~((a % v) IN t) /\
+        (!x. sgn x ==> sgn(x / &2)) /\
+        (!x y. sgn x /\ sgn y ==> sgn(x + y)) /\
+        &0 < a
+        ==> affsign sgn (vec 0 INSERT (a % v) INSERT s) t =
+            affsign sgn (vec 0 INSERT v INSERT s) t`,
+  REWRITE_TAC[EXTENSION] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[AFFSIGN_ALT; IN_ELIM_THM; INSERT_UNION_EQ] THEN
+  ASM_SIMP_TAC[FINITE_INSERT; FINITE_UNION; AFFINE_HULL_FINITE_STEP_GEN;
+               RIGHT_EXISTS_AND_THM] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_SUB_RZERO] THEN
+  GEN_REWRITE_TAC BINOP_CONV [SWAP_EXISTS_THM] THEN
+  GEN_REWRITE_TAC (BINOP_CONV o BINDER_CONV) [SWAP_EXISTS_THM] THEN
+  REWRITE_TAC[LEFT_EXISTS_AND_THM; RIGHT_EXISTS_AND_THM] THEN
+  REWRITE_TAC[REAL_ARITH `x = &1 - v - v' <=> v = &1 - (x + v')`] THEN
+  REWRITE_TAC[EXISTS_REFL] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP(MESON[REAL_LT_IMP_NZ; REAL_DIV_LMUL]
+   `!a. &0 < a ==> (!y. ?x. a * x = y)`)) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP QUANTIFY_SURJECTION_THM) THEN
+  DISCH_THEN(CONV_TAC o RAND_CONV o EXPAND_QUANTS_CONV) THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC; REAL_MUL_SYM]);;
+
+let AFF_GE_SPECIAL_SCALE = prove
+ (`!s t a v.
+        FINITE s /\ FINITE t /\
+        ~(vec 0 IN t) /\ ~(v IN t) /\ ~((a % v) IN t) /\
+        &0 < a
+        ==> aff_ge (vec 0 INSERT (a % v) INSERT s) t =
+            aff_ge (vec 0 INSERT v INSERT s) t`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[aff_ge_def] THEN
+  MATCH_MP_TAC AFFSIGN_SPECIAL_SCALE THEN
+  ASM_REWRITE_TAC[sgn_ge] THEN REAL_ARITH_TAC);;
+
+let AFF_LE_SPECIAL_SCALE = prove
+ (`!s t a v.
+        FINITE s /\ FINITE t /\
+        ~(vec 0 IN t) /\ ~(v IN t) /\ ~((a % v) IN t) /\
+        &0 < a
+        ==> aff_le (vec 0 INSERT (a % v) INSERT s) t =
+            aff_le (vec 0 INSERT v INSERT s) t`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[aff_le_def] THEN
+  MATCH_MP_TAC AFFSIGN_SPECIAL_SCALE THEN
+  ASM_REWRITE_TAC[sgn_le] THEN REAL_ARITH_TAC);;
+
+let AFF_GT_SPECIAL_SCALE = prove
+ (`!s t a v.
+        FINITE s /\ FINITE t /\
+        ~(vec 0 IN t) /\ ~(v IN t) /\ ~((a % v) IN t) /\
+        &0 < a
+        ==> aff_gt (vec 0 INSERT (a % v) INSERT s) t =
+            aff_gt (vec 0 INSERT v INSERT s) t`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[aff_gt_def] THEN
+  MATCH_MP_TAC AFFSIGN_SPECIAL_SCALE THEN
+  ASM_REWRITE_TAC[sgn_gt] THEN REAL_ARITH_TAC);;
+
+let AFF_LT_SPECIAL_SCALE = prove
+ (`!s t a v.
+        FINITE s /\ FINITE t /\
+        ~(vec 0 IN t) /\ ~(v IN t) /\ ~((a % v) IN t) /\
+        &0 < a
+        ==> aff_lt (vec 0 INSERT (a % v) INSERT s) t =
+            aff_lt (vec 0 INSERT v INSERT s) t`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[aff_lt_def] THEN
+  MATCH_MP_TAC AFFSIGN_SPECIAL_SCALE THEN
+  ASM_REWRITE_TAC[sgn_lt] THEN REAL_ARITH_TAC);;
+
+let AFF_GE_SCALE_LEMMA = prove
+ (`!a u v:real^N.
+        &0 < a /\ ~(v = vec 0)
+        ==> aff_ge {vec 0} {a % u,v} = aff_ge {vec 0} {u,v}`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `u:real^N = vec 0` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_RZERO] THEN
+  ASM_SIMP_TAC[AFF_GE_1_2_0; VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ;
+   SET_RULE `DISJOINT {a} {b,c} <=> ~(b = a) /\ ~(c = a)`] THEN
+  REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ; SUBSET; FORALL_IN_GSPEC] THEN
+  CONJ_TAC THEN MAP_EVERY X_GEN_TAC [`b:real`; `c:real`] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THENL
+   [EXISTS_TAC `a * b:real`; EXISTS_TAC `b / a:real`] THEN
+  EXISTS_TAC `c:real` THEN
+  ASM_SIMP_TAC[REAL_LE_DIV; REAL_LE_MUL; REAL_LT_IMP_LE] THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC] THEN
+  REPLICATE_TAC 2 (AP_THM_TAC THEN AP_TERM_TAC) THEN
+  UNDISCH_TAC `&0 < a` THEN CONV_TAC REAL_FIELD);;
+
+let AFFSIGN_0 = prove
+ (`!sgn s t.
+        FINITE s /\ FINITE t /\ (vec 0) IN (s DIFF t)
+        ==> affsign sgn s t =
+             { vsum (s UNION t) (\v. f v % v) |f|
+               !x:real^N. x IN t ==> sgn(f x)}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[AFFSIGN] THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP (SET_RULE
+   `x IN s DIFF t ==> s UNION t = x INSERT ((s UNION t) DELETE x)`)) THEN
+  ASM_SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES; FINITE_UNION; FINITE_DELETE] THEN
+  REWRITE_TAC[IN_DELETE; VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; SUBSET; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`y:real^N`; `f:real^N->real`] THEN
+    STRIP_TAC THEN EXISTS_TAC `f:real^N->real` THEN ASM_REWRITE_TAC[];
+    X_GEN_TAC `f:real^N->real` THEN DISCH_TAC THEN
+    EXISTS_TAC
+     `\x:real^N. if x = vec 0
+                 then &1 - sum ((s UNION t) DELETE vec 0) (\x. f x)
+                 else f x` THEN
+    MP_TAC(SET_RULE
+     `!x:real^N. x IN (s UNION t) DELETE vec 0 ==> ~(x = vec 0)`) THEN
+    SIMP_TAC[ETA_AX; REAL_SUB_ADD] THEN DISCH_THEN(K ALL_TAC) THEN
+    ASM SET_TAC[]]);;
+
+let AFF_GE_0_AFFINE_MULTIPLE_CONVEX = prove
+ (`!s t:real^N->bool.
+        FINITE s /\ FINITE t /\ vec 0 IN (s DIFF t) /\ ~(t = {})
+        ==> aff_ge s t =
+               {x + c % y | x IN affine hull (s DIFF t) /\
+                            y IN convex hull t /\ &0 <= c}`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[aff_ge_def; AFFSIGN_0; sgn_ge] THEN
+  ONCE_REWRITE_TAC[SET_RULE `s UNION t = (s DIFF t) UNION t`] THEN
+  ASM_SIMP_TAC[VSUM_UNION; FINITE_DIFF;
+               SET_RULE `DISJOINT (s DIFF t) t`] THEN
+  ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC] THEN
+  ASM_SIMP_TAC[SPAN_FINITE; FINITE_DIFF; CONVEX_HULL_FINITE] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN CONJ_TAC THENL
+   [X_GEN_TAC `f:real^N->real` THEN DISCH_TAC THEN
+    EXISTS_TAC `vsum (s DIFF t) (\x:real^N. f x % x)` THEN
+    ASM_CASES_TAC `sum t (f:real^N->real) = &0` THENL
+     [MP_TAC(ISPECL [`f:real^N->real`; `t:real^N->bool`] SUM_POS_EQ_0) THEN
+      ASM_SIMP_TAC[VECTOR_MUL_LZERO; REAL_MUL_LZERO; VSUM_0] THEN
+      DISCH_TAC THEN EXISTS_TAC `&0` THEN
+      REWRITE_TAC[VECTOR_MUL_LZERO; REAL_LE_REFL] THEN
+      REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN CONJ_TAC THENL
+       [EXISTS_TAC `f:real^N->real` THEN REWRITE_TAC[]; ALL_TAC] THEN
+      ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+      REWRITE_TAC[RIGHT_EXISTS_AND_THM; GSYM EXISTS_REFL] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+      DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+      EXISTS_TAC `\x:real^N. if x = a then &1 else &0` THEN
+      ASM_REWRITE_TAC[SUM_DELTA] THEN MESON_TAC[REAL_POS];
+      EXISTS_TAC `sum t (f:real^N->real)` THEN
+      EXISTS_TAC `inv(sum t (f:real^N->real)) % vsum t (\v. f v % v)` THEN
+      REPEAT CONJ_TAC THENL
+       [EXISTS_TAC `f:real^N->real` THEN REWRITE_TAC[];
+        EXISTS_TAC `\x:real^N. f x / sum t (f:real^N->real)` THEN
+        ASM_SIMP_TAC[REAL_LE_DIV; SUM_POS_LE] THEN
+        ONCE_REWRITE_TAC[REAL_ARITH `x / y:real = inv y * x`] THEN
+        ASM_SIMP_TAC[GSYM VECTOR_MUL_ASSOC; SUM_LMUL; VSUM_LMUL] THEN
+        ASM_SIMP_TAC[REAL_MUL_LINV];
+        ASM_SIMP_TAC[SUM_POS_LE];
+        AP_TERM_TAC THEN ASM_CASES_TAC `sum t (f:real^N->real) = &0` THEN
+        ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; VECTOR_MUL_LID]]];
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `c:real`; `y:real^N`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `u:real^N->real` (SUBST1_TAC o SYM)) MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `v:real^N->real`MP_TAC) ASSUME_TAC) THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN
+    EXISTS_TAC `(\x. if x IN t then c * v x else u x):real^N->real` THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; VSUM_LMUL; GSYM VECTOR_MUL_ASSOC] THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN MATCH_MP_TAC VSUM_EQ THEN
+    SIMP_TAC[IN_DIFF]]);;
+
+let AFF_GE_0_MULTIPLE_AFFINE_CONVEX = prove
+ (`!s t:real^N->bool.
+        FINITE s /\ FINITE t /\ vec 0 IN (s DIFF t) /\ ~(t = {})
+        ==> aff_ge s t =
+               affine hull (s DIFF t) UNION
+               {c % (x + y) | x IN affine hull (s DIFF t) /\
+                              y IN convex hull t /\ &0 <= c}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[UNION_SUBSET] THEN REPEAT CONJ_TAC THENL
+   [ASM_SIMP_TAC[AFF_GE_0_AFFINE_MULTIPLE_CONVEX;
+                 AFFINE_HULL_EQ_SPAN; HULL_INC] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `c:real`; `y:real^N`] THEN STRIP_TAC THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_UNION] THEN ASM_CASES_TAC `c = &0` THENL
+     [DISJ1_TAC THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_RID];
+      DISJ2_TAC THEN MAP_EVERY EXISTS_TAC
+       [`c:real`; `inv(c) % x:real^N`; `y:real^N`] THEN
+      ASM_SIMP_TAC[SPAN_MUL; VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC;
+                   REAL_MUL_RINV; VECTOR_MUL_LID]];
+    REWRITE_TAC[aff_ge_def] THEN ONCE_REWRITE_TAC[AFFSIGN_DISJOINT_DIFF] THEN
+    REWRITE_TAC[GSYM aff_ge_def] THEN
+    MATCH_MP_TAC AFFINE_HULL_SUBSET_AFF_GE THEN SET_TAC[];
+    ASM_SIMP_TAC[AFF_GE_0_AFFINE_MULTIPLE_CONVEX;
+                 AFFINE_HULL_EQ_SPAN; HULL_INC] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+    MAP_EVERY X_GEN_TAC [`c:real`; `x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN MAP_EVERY EXISTS_TAC
+     [`c % x:real^N`; `c:real`; `y:real^N`] THEN
+    ASM_SIMP_TAC[SPAN_MUL; VECTOR_ADD_LDISTRIB]]);;
+
+let AFF_GE_0_AFFINE_CONVEX_CONE = prove
+ (`!s t:real^N->bool.
+        FINITE s /\ FINITE t /\ vec 0 IN (s DIFF t)
+        ==> aff_ge s t =
+               {x + y | x IN affine hull (s DIFF t) /\
+                        y IN convex_cone hull t}`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `t:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[AFF_GE_EQ_AFFINE_HULL; CONVEX_CONE_HULL_EMPTY] THEN
+    REWRITE_TAC[IN_SING; DIFF_EMPTY] THEN
+    REWRITE_TAC[SET_RULE `{x + y:real^N | P x /\ y = a} = {x + a | P x}`] THEN
+    REWRITE_TAC[VECTOR_ADD_RID] THEN SET_TAC[];
+    ASM_SIMP_TAC[CONVEX_CONE_HULL_CONVEX_HULL_NONEMPTY;
+                  AFF_GE_0_AFFINE_MULTIPLE_CONVEX] THEN
+   SET_TAC[]]);;
+
+let AFF_GE_0_N = prove
+ (`!s:real^N->bool.
+        FINITE s /\ ~(vec 0 IN s)
+        ==> aff_ge {vec 0} s =
+                {y | ?u. (!x. x IN s ==> &0 <= u x) /\
+                         y = vsum s (\x. u x % x)}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[aff_ge_def] THEN
+  ASM_SIMP_TAC[AFFSIGN_0; IN_DIFF; IN_INSERT; NOT_IN_EMPTY;
+               FINITE_INSERT; FINITE_EMPTY] THEN
+  ASM_SIMP_TAC[EXTENSION; sgn_ge; IN_ELIM_THM; INSERT_UNION; UNION_EMPTY] THEN
+  ASM_SIMP_TAC[VSUM_CLAUSES; VECTOR_MUL_RZERO; VECTOR_ADD_LID]);;
+
+let AFF_GE_0_CONVEX_HULL = prove
+ (`!s:real^N->bool.
+        FINITE s /\ ~(s = {}) /\ ~(vec 0 IN s)
+        ==> aff_ge {vec 0} s = {t % y | &0 <= t /\ y IN convex hull s}`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[AFF_GE_0_AFFINE_MULTIPLE_CONVEX; IN_DIFF;
+               FINITE_INSERT; FINITE_EMPTY; IN_INSERT] THEN
+  ASM_SIMP_TAC[SET_RULE `~(a IN s) ==> {a} DIFF s = {a}`] THEN
+  REWRITE_TAC[AFFINE_HULL_SING; IN_SING] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN MESON_TAC[VECTOR_ADD_LID]);;
+
+let AFF_GE_0_CONVEX_HULL_ALT = prove
+ (`!s:real^N->bool.
+        FINITE s /\ ~(vec 0 IN s)
+        ==> aff_ge {vec 0} s =
+            vec 0 INSERT {t % y | &0 < t /\ y IN convex hull s}`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[AFF_GE_EQ_AFFINE_HULL; CONVEX_HULL_EMPTY] THEN
+    REWRITE_TAC[AFFINE_HULL_SING; NOT_IN_EMPTY] THEN SET_TAC[];
+    ASM_SIMP_TAC[AFF_GE_0_CONVEX_HULL; EXTENSION; IN_ELIM_THM; IN_INSERT] THEN
+    X_GEN_TAC `y:real^N` THEN ASM_CASES_TAC `y:real^N = vec 0` THEN
+    ASM_REWRITE_TAC[] THENL
+     [EXISTS_TAC `&0` THEN ASM_REWRITE_TAC[REAL_POS; VECTOR_MUL_LZERO] THEN
+      ASM_REWRITE_TAC[MEMBER_NOT_EMPTY; CONVEX_HULL_EQ_EMPTY];
+      AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `t:real` THEN
+      AP_TERM_TAC THEN ABS_TAC THEN
+      ASM_CASES_TAC `t = &0` THEN
+      ASM_REWRITE_TAC[VECTOR_MUL_LZERO; REAL_LT_REFL] THEN
+      ASM_REWRITE_TAC[REAL_LT_LE]]]);;
+
+let AFF_GE_0_CONVEX_CONE_NEGATIONS = prove
+ (`!s t:real^N->bool.
+        FINITE s /\ FINITE t /\ vec 0 IN (s DIFF t)
+        ==> aff_ge s t =
+            convex_cone hull (s UNION t UNION IMAGE (--) (s DIFF t))`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[AFF_GE_0_AFFINE_CONVEX_CONE] THEN
+  ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC] THEN
+  REWRITE_TAC[SPAN_CONVEX_CONE_ALLSIGNS; GSYM CONVEX_CONE_HULL_UNION] THEN
+  AP_TERM_TAC THEN SET_TAC[]);;
+
+let CONVEX_HULL_AFF_GE = prove
+ (`!s. convex hull s = aff_ge {} s`,
+  SIMP_TAC[aff_ge_def; AFFSIGN; CONVEX_HULL_FINITE; sgn_ge; UNION_EMPTY] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN REPEAT GEN_TAC THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN MESON_TAC[]);;
+
+let POLYHEDRON_AFF_GE = prove
+ (`!s t:real^N->bool. FINITE s /\ FINITE t ==> polyhedron(aff_ge s t)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[aff_ge_def] THEN
+  ONCE_REWRITE_TAC[AFFSIGN_DISJOINT_DIFF] THEN
+  REWRITE_TAC[GSYM aff_ge_def] THEN
+  SUBGOAL_THEN `FINITE(s DIFF t) /\ FINITE(t:real^N->bool) /\
+                DISJOINT (s DIFF t) t`
+  MP_TAC THENL [ASM_SIMP_TAC[FINITE_DIFF] THEN ASM SET_TAC[]; ALL_TAC] THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN
+  SPEC_TAC(`s DIFF t:real^N->bool`,`s:real^N->bool`) THEN
+  MATCH_MP_TAC SET_PROVE_CASES THEN CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM CONVEX_HULL_AFF_GE] THEN
+    MATCH_MP_TAC POLYTOPE_IMP_POLYHEDRON THEN REWRITE_TAC[polytope] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `s:real^N->bool`] THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(vec 0:real^N) IN ((vec 0 INSERT s) DIFF t)` ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  ASM_SIMP_TAC[AFF_GE_0_CONVEX_CONE_NEGATIONS; FINITE_INSERT] THEN
+  MATCH_MP_TAC POLYHEDRON_CONVEX_CONE_HULL THEN
+  ASM_SIMP_TAC[FINITE_INSERT; FINITE_UNION; FINITE_DIFF; FINITE_IMAGE]);;
+
+let CLOSED_AFF_GE = prove
+ (`!s t:real^N->bool. FINITE s /\ FINITE t ==> closed(aff_ge s t)`,
+  SIMP_TAC[POLYHEDRON_AFF_GE; POLYHEDRON_IMP_CLOSED]);;
+
+let CONIC_AFF_GE_0 = prove
+ (`!s:real^N->bool. FINITE s /\ ~(vec 0 IN s) ==> conic(aff_ge {vec 0} s)`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[AFF_GE_0_N; conic] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN GEN_TAC THEN X_GEN_TAC `c:real` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\v. c * (u:real^N->real) v` THEN
+  REWRITE_TAC[GSYM VECTOR_MUL_ASSOC; VSUM_LMUL] THEN
+  ASM_MESON_TAC[REAL_LE_MUL]);;
+
+let ANGLES_ADD_AFF_GE = prove
+ (`!u v w x:real^N.
+        ~(v = u) /\ ~(w = u) /\ ~(x = u) /\ x IN aff_ge {u} {v,w}
+        ==> angle(v,u,x) + angle(x,u,w) = angle(v,u,w)`,
+  GEOM_ORIGIN_TAC `u:real^N` THEN REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ASM_SIMP_TAC[AFF_GE_1_2_0] THEN
+  REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real`; `b:real`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  SUBGOAL_THEN `a = &0 /\ b = &0 \/ &0 < a + b` STRIP_ASSUME_TAC THENL
+   [ASM_REAL_ARITH_TAC;
+    ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_LID];
+    ALL_TAC] THEN
+  DISCH_TAC THEN MP_TAC(ISPECL
+   [`v:real^N`; `w:real^N`; `inv(a + b) % x:real^N`; `vec 0:real^N`]
+   ANGLES_ADD_BETWEEN) THEN
+  ASM_REWRITE_TAC[angle; VECTOR_SUB_RZERO] THEN
+  ASM_SIMP_TAC[VECTOR_ANGLE_RMUL; VECTOR_ANGLE_LMUL;
+    REAL_INV_EQ_0; REAL_LE_INV_EQ; REAL_LT_IMP_NZ; REAL_LT_IMP_LE] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  REWRITE_TAC[BETWEEN_IN_SEGMENT; CONVEX_HULL_2; SEGMENT_CONVEX_HULL] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  MAP_EVERY EXISTS_TAC [`a / (a + b):real`; `b / (a + b):real`] THEN
+  ASM_SIMP_TAC[REAL_LE_DIV; REAL_LT_IMP_LE; VECTOR_ADD_LDISTRIB] THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC; real_div; REAL_MUL_AC] THEN
+  UNDISCH_TAC `&0 < a + b` THEN CONV_TAC REAL_FIELD);;
+
+let AFF_GE_2_1_0_DROPOUT_3 = prove
+ (`!w z:real^3.
+        ~collinear{vec 0,basis 3,z}
+        ==> (w IN aff_ge {vec 0,basis 3} {z} <=>
+             (dropout 3 w) IN aff_ge {vec 0:real^2} {dropout 3 z})`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `z:real^3 = vec 0` THENL
+   [ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC]; ALL_TAC] THEN
+  ASM_CASES_TAC `z:real^3 = basis 3` THENL
+   [ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC]; ALL_TAC] THEN
+  REWRITE_TAC[COLLINEAR_BASIS_3] THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[AFF_GE_2_1_0; SET_RULE `DISJOINT s {a} <=> ~(a IN s)`;
+               IN_INSERT; NOT_IN_EMPTY; AFF_GE_1_1_0] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!t. ((?s. P s t) <=> Q t)) ==> ((?s t. P s t) <=> (?t. Q t))`) THEN
+  X_GEN_TAC `t:real` THEN EQ_TAC THENL
+   [STRIP_TAC THEN
+    ASM_REWRITE_TAC[DROPOUT_ADD; DROPOUT_MUL; DROPOUT_BASIS_3] THEN
+    VECTOR_ARITH_TAC;
+    STRIP_TAC THEN EXISTS_TAC `(w:real^3)$3 - t * (z:real^3)$3` THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CART_EQ]) THEN
+    ASM_REWRITE_TAC[CART_EQ; FORALL_2; FORALL_3; DIMINDEX_2; DIMINDEX_3] THEN
+    REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+    SIMP_TAC[dropout; LAMBDA_BETA; DIMINDEX_2; ARITH; BASIS_COMPONENT;
+             DIMINDEX_3] THEN
+    CONV_TAC REAL_RING]);;
+
+let AFF_GE_2_1_0_SEMIALGEBRAIC = prove
+ (`!x y z:real^3.
+        ~collinear {vec 0,x,y} /\ ~collinear {vec 0,x,z}
+        ==> (z IN aff_ge {vec 0,x} {y} <=>
+             (x cross y) cross x cross z = vec 0 /\
+             &0 <= (x cross z) dot (x cross y))`,
+  let lemma0 = prove
+   (`~(y = vec 0) ==> ((?s. x = s % y) <=> y cross x = vec 0)`,
+    REWRITE_TAC[CROSS_EQ_0] THEN SIMP_TAC[COLLINEAR_LEMMA_ALT])
+  and lemma1 = prove
+   (`!x y:real^N.
+          ~(y = vec 0)
+          ==> ((?t. &0 <= t /\ x = t % y) <=>
+               (?t. x = t % y) /\ &0 <= x dot y)`,
+    REPEAT STRIP_TAC THEN REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN
+    AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `t:real` THEN
+    ASM_CASES_TAC `x:real^N = t % y` THEN
+    ASM_SIMP_TAC[DOT_LMUL; REAL_LE_MUL_EQ; DOT_POS_LT]) in
+  REPEAT GEN_TAC THEN
+  MAP_EVERY (fun t -> ASM_CASES_TAC t THENL
+   [ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC]; ALL_TAC])
+   [`x:real^3 = vec 0`; `y:real^3 = vec 0`; `y:real^3 = x`] THEN
+  STRIP_TAC THEN
+  ASM_SIMP_TAC[AFF_GE_2_1_0; IN_ELIM_THM; SET_RULE
+    `DISJOINT {a,b} {c} <=> ~(a = c) /\ ~(b = c)`] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; VECTOR_ARITH
+    `a:real^N = b + c <=> a - c = b`] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM CROSS_EQ_0]) THEN
+  ASM_SIMP_TAC[lemma0; lemma1; CROSS_RMUL; CROSS_RSUB; VECTOR_SUB_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Special case of aff_ge {x} {y}, i.e. rays or half-lines.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let HALFLINE_REFL = prove
+ (`!x. aff_ge {x} {x} = {x}`,
+  ONCE_REWRITE_TAC[AFF_GE_DISJOINT_DIFF] THEN
+  ASM_REWRITE_TAC[DIFF_EQ_EMPTY; GSYM CONVEX_HULL_AFF_GE; CONVEX_HULL_SING]);;
+
+let HALFLINE_EXPLICIT = prove
+ (`!x y:real^N.
+        aff_ge {x} {y} =
+          {z | ?t1 t2. &0 <= t2 /\ t1 + t2 = &1 /\ z = t1 % x + t2 % y}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `x:real^N = y` THENL
+   [ASM_REWRITE_TAC[HALFLINE_REFL]; AFF_TAC] THEN
+  REWRITE_TAC[REAL_ARITH `x + y = &1 <=> x = &1 - y`] THEN
+  REWRITE_TAC[VECTOR_ARITH `(&1 - x) % v + x % v:real^N = v`;
+    MESON[] `(?x y. P y /\ x = f y /\ Q x y) <=> (?y. P y /\ Q (f y) y)`] THEN
+  REWRITE_TAC[IN_ELIM_THM; IN_SING; EXTENSION] THEN MESON_TAC[REAL_POS]);;
+
+let HALFLINE = prove
+ (`!x y:real^N.
+        aff_ge {x} {y} =
+          {z | ?t. &0 <= t /\ z = (&1 - t) % x + t % y}`,
+  REWRITE_TAC[HALFLINE_EXPLICIT;  REAL_ARITH `x + y = &1 <=> x = &1 - y`] THEN
+  SET_TAC[]);;
+
+let CLOSED_HALFLINE = prove
+ (`!x y. closed(aff_ge {x} {y})`,
+  SIMP_TAC[CLOSED_AFF_GE; FINITE_SING]);;
+
+let SEGMENT_SUBSET_HALFLINE = prove
+ (`!x y. segment[x,y] SUBSET aff_ge {x} {y}`,
+  REWRITE_TAC[SEGMENT_CONVEX_HULL; CONVEX_HULL_2; HALFLINE_EXPLICIT] THEN
+  SET_TAC[]);;
+
+let ENDS_IN_HALFLINE = prove
+ (`(!x y. x IN aff_ge {x} {y}) /\ (!x y. y IN aff_ge {x} {y})`,
+  MESON_TAC[SEGMENT_SUBSET_HALFLINE; SUBSET; ENDS_IN_SEGMENT]);;
+
+let HALFLINE_SUBSET_AFFINE_HULL = prove
+ (`!x y. aff_ge {x} {y} SUBSET affine hull {x,y}`,
+  REWRITE_TAC[AFF_GE_SUBSET_AFFINE_HULL; SET_RULE `{x,y} = {x} UNION {y}`]);;
+
+let HALFLINE_INTER_COMPACT_SEGMENT = prove
+ (`!s a b:real^N.
+        compact s /\ convex s /\ a IN s
+        ==> ?c. aff_ge {a} {b} INTER s = segment[a,c]`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `b:real^N = a` THENL
+   [EXISTS_TAC `a:real^N` THEN
+    ASM_REWRITE_TAC[SEGMENT_REFL; HALFLINE_REFL] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?u v:real^N. aff_ge {a} {b} INTER s = segment[u,v]`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC COMPACT_CONVEX_COLLINEAR_SEGMENT THEN
+    ASM_SIMP_TAC[CLOSED_INTER_COMPACT; CLOSED_AFF_GE; FINITE_SING] THEN
+    ASM_SIMP_TAC[CONVEX_INTER; CONVEX_AFF_GE] THEN CONJ_TAC THENL
+     [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+      ASM_MESON_TAC[ENDS_IN_HALFLINE];
+      MATCH_MP_TAC COLLINEAR_SUBSET THEN
+      EXISTS_TAC `affine hull {a:real^N,b}` THEN
+      REWRITE_TAC[COLLINEAR_AFFINE_HULL_COLLINEAR; COLLINEAR_2] THEN
+      MATCH_MP_TAC(SET_RULE `s SUBSET u ==> (s INTER t) SUBSET u`) THEN
+      REWRITE_TAC[HALFLINE_SUBSET_AFFINE_HULL]];
+    ASM_CASES_TAC `u:real^N = a` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    ASM_CASES_TAC `v:real^N = a` THENL
+     [ASM_MESON_TAC[SEGMENT_SYM]; ALL_TAC] THEN
+    SUBGOAL_THEN `u IN aff_ge {a:real^N} {b} /\ v IN aff_ge {a} {b}`
+    MP_TAC THENL [ASM_MESON_TAC[IN_INTER; ENDS_IN_SEGMENT]; ALL_TAC] THEN
+    GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [HALFLINE; IN_ELIM_THM] THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `s:real` MP_TAC) (X_CHOOSE_THEN `t:real` MP_TAC)) THEN
+    MAP_EVERY ASM_CASES_TAC [`s = &0`; `t = &0`] THEN
+    ASM_REWRITE_TAC[REAL_SUB_RZERO; VECTOR_MUL_LID; VECTOR_MUL_LZERO;
+                    VECTOR_ADD_RID] THEN
+    ASM_REWRITE_TAC[REAL_LE_LT] THEN REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `(a:real^N) IN segment[u,v]` MP_TAC THENL
+     [ASM_MESON_TAC[IN_INTER; ENDS_IN_HALFLINE]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[IN_SEGMENT; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `u:real` THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    REWRITE_TAC[VECTOR_ARITH
+     `a = (&1 - u) % ((&1 - s) % a + s % b) + u % ((&1 - t) % a + t % b) <=>
+      ((&1 - u) * s + u * t) % (b - a):real^N = vec 0`] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ] THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; REAL_SUB_LE; REAL_LT_IMP_LE; REAL_ARITH
+     `&0 <= x /\ &0 <= y ==> (x + y = &0 <=> x = &0 /\ y = &0)`] THEN
+    ASM_SIMP_TAC[REAL_ENTIRE; REAL_LT_IMP_NZ] THEN REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Definition and properties of conv0.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let conv0 = new_definition `conv0 S:real^A->bool = affsign sgn_gt {} S`;;
+
+let CONV0_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f s. linear f /\ (!x y. f x = f y ==> x = y)
+         ==> conv0(IMAGE f s) = IMAGE f (conv0 s)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o GSYM o MATCH_MP AFFSIGN_INJECTIVE_LINEAR_IMAGE) THEN
+  ASM_REWRITE_TAC[conv0; IMAGE_CLAUSES]);;
+
+add_linear_invariants [CONV0_INJECTIVE_LINEAR_IMAGE];;
+
+let CONV0_TRANSLATION = prove
+ (`!a s. conv0(IMAGE (\x. a + x) s) = IMAGE (\x. a + x) (conv0 s)`,
+  REWRITE_TAC[conv0; GSYM AFFSIGN_TRANSLATION; IMAGE_CLAUSES]);;
+
+add_translation_invariants [CONV0_TRANSLATION];;
+
+let CONV0_SUBSET_CONVEX_HULL = prove
+ (`!s. conv0 s SUBSET convex hull s`,
+  REWRITE_TAC[conv0; AFFSIGN; sgn_gt; CONVEX_HULL_FINITE; UNION_EMPTY] THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+  REPEAT GEN_TAC THEN MATCH_MP_TAC MONO_EXISTS THEN
+  MESON_TAC[REAL_LT_IMP_LE]);;
+
+let CONV0_AFF_GT = prove
+ (`!s. conv0 s = aff_gt {} s`,
+  REWRITE_TAC[conv0; aff_gt_def]);;
+
+let CONVEX_HULL_CONV0_DECOMP = prove
+ (`!s:real^N->bool.
+        FINITE s
+        ==> convex hull s = conv0 s UNION
+                            UNIONS {convex hull (s DELETE a) | a | a IN s}`,
+  REWRITE_TAC[CONV0_AFF_GT; CONVEX_HULL_AFF_GE] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC AFF_GE_AFF_GT_DECOMP THEN
+  ASM_REWRITE_TAC[FINITE_EMPTY] THEN SET_TAC[]);;
+
+let CONVEX_CONV0 = prove
+ (`!s. convex(conv0 s)`,
+  REWRITE_TAC[CONV0_AFF_GT; CONVEX_AFF_GT]);;
+
+let BOUNDED_CONV0 = prove
+ (`!s:real^N->bool. bounded s ==> bounded(conv0 s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC BOUNDED_SUBSET THEN
+  EXISTS_TAC `convex hull s:real^N->bool` THEN
+  ASM_SIMP_TAC[BOUNDED_CONVEX_HULL; CONV0_SUBSET_CONVEX_HULL]);;
+
+let MEASURABLE_CONV0 = prove
+ (`!s. bounded s ==> measurable(conv0 s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_CONVEX THEN
+  ASM_SIMP_TAC[CONVEX_CONV0; BOUNDED_CONV0]);;
+
+let NEGLIGIBLE_CONVEX_HULL_DIFF_CONV0 = prove
+ (`!s:real^N->bool.
+        FINITE s /\ CARD s <= dimindex(:N) + 1
+        ==> negligible(convex hull s DIFF conv0 s)`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[CONVEX_HULL_CONV0_DECOMP] THEN
+  REWRITE_TAC[SET_RULE `(s UNION t) DIFF s = t DIFF s`] THEN
+  MATCH_MP_TAC NEGLIGIBLE_DIFF THEN MATCH_MP_TAC NEGLIGIBLE_UNIONS THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN ASM_SIMP_TAC[FINITE_IMAGE] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC NEGLIGIBLE_CONVEX_HULL THEN
+  ASM_SIMP_TAC[FINITE_DELETE; CARD_DELETE] THEN ASM_ARITH_TAC);;
+
+let MEASURE_CONV0_CONVEX_HULL = prove
+ (`!s:real^N->bool.
+        FINITE s /\ CARD s <= dimindex(:N) + 1
+        ==> measure(conv0 s) = measure(convex hull s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_NEGLIGIBLE_SYMDIFF THEN
+  ASM_SIMP_TAC[MEASURABLE_CONVEX_HULL; FINITE_IMP_BOUNDED] THEN
+  MATCH_MP_TAC NEGLIGIBLE_UNION THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_CONVEX_HULL_DIFF_CONV0] THEN
+  ASM_SIMP_TAC[CONV0_SUBSET_CONVEX_HULL; NEGLIGIBLE_EMPTY;
+               SET_RULE `s SUBSET t ==> s DIFF t = {}`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Orthonormal triples of vectors in 3D.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let orthonormal = new_definition
+  `orthonormal e1 e2 e3 <=>
+     e1 dot e1 = &1 /\ e2 dot e2 = &1 /\ e3 dot e3 = &1 /\
+     e1 dot e2 = &0 /\ e1 dot e3 = &0 /\ e2 dot e3 = &0 /\
+     &0 < (e1 cross e2) dot e3`;;
+
+let ORTHONORMAL_LINEAR_IMAGE = prove
+ (`!f. linear(f) /\ (!x. norm(f x) = norm x) /\
+       (2 <= dimindex(:3) ==> det(matrix f) = &1)
+       ==> !e1 e2 e3. orthonormal (f e1) (f e2) (f e3) <=>
+                      orthonormal e1 e2 e3`,
+  SIMP_TAC[DIMINDEX_3; ARITH; CONJ_ASSOC; GSYM ORTHOGONAL_TRANSFORMATION] THEN
+  SIMP_TAC[orthonormal; CROSS_ORTHOGONAL_TRANSFORMATION] THEN
+  SIMP_TAC[orthogonal_transformation; VECTOR_MUL_LID]);;
+
+add_linear_invariants [ORTHONORMAL_LINEAR_IMAGE];;
+
+let ORTHONORMAL_PERMUTE = prove
+ (`!e1 e2 e3. orthonormal e1 e2 e3 ==> orthonormal e2 e3 e1`,
+  REWRITE_TAC[orthonormal] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[GSYM CROSS_TRIPLE] THEN ASM_REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[DOT_SYM] THEN ASM_REWRITE_TAC[]);;
+
+let ORTHONORMAL_CROSS = prove
+ (`!e1 e2 e3.
+        orthonormal e1 e2 e3
+        ==> e2 cross e3 = e1 /\ e3 cross e1 = e2 /\ e1 cross e2 = e3`,
+  SUBGOAL_THEN
+   `!e1 e2 e3. orthonormal e1 e2 e3 ==> e3 cross e1 = e2`
+   (fun th -> MESON_TAC[th; ORTHONORMAL_PERMUTE]) THEN
+  GEOM_BASIS_MULTIPLE_TAC 1 `e1:real^3` THEN X_GEN_TAC `k:real` THEN
+  REWRITE_TAC[orthonormal; DOT_LMUL; DOT_RMUL] THEN
+  SIMP_TAC[DOT_BASIS_BASIS; DIMINDEX_3; ARITH; REAL_MUL_RID] THEN
+  REWRITE_TAC[REAL_RING `k * k = &1 <=> k = &1 \/ k = -- &1`] THEN
+  ASM_CASES_TAC `k = -- &1` THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_CASES_TAC `k = &1` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LID; REAL_MUL_LID; REAL_MUL_RID] THEN
+  SIMP_TAC[cross; DOT_3; VECTOR_3; CART_EQ; FORALL_3; DIMINDEX_3;
+           BASIS_COMPONENT; DIMINDEX_3; ARITH; REAL_POS] THEN
+  REWRITE_TAC[REAL_MUL_LZERO; REAL_SUB_RZERO; REAL_ADD_RID;
+              REAL_MUL_LID] THEN
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `(e2:real^3)$1 = &0` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `(e3:real^3)$1 = &0` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[REAL_MUL_RZERO; REAL_SUB_RZERO; REAL_ADD_LID] THEN
+  REWRITE_TAC[REAL_SUB_LZERO; REAL_MUL_RID] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `(u = &1 /\ v = &1 /\ w = &0 ==> a = b /\ --c = d \/ a = --b /\ c = d) /\
+    (a = --b /\ c = d ==> x <= &0)
+    ==> (u = &1 /\ v = &1 /\ w = &0 /\ &0 < x
+         ==> a:real = b /\ --c:real = d)`) THEN
+  CONJ_TAC THENL [CONV_TAC REAL_RING; ALL_TAC] THEN
+  DISCH_THEN(CONJUNCTS_THEN SUBST1_TAC) THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `&0 <= x * x /\ &0 <= y * y ==> --x * x + y * -- y <= &0`) THEN
+  REWRITE_TAC[REAL_LE_SQUARE]);;
+
+let ORTHONORMAL_IMP_NONZERO = prove
+ (`!e1 e2 e3. orthonormal e1 e2 e3
+              ==> ~(e1 = vec 0) /\ ~(e2 = vec 0) /\ ~(e3 = vec 0)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  REWRITE_TAC[DE_MORGAN_THM] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[orthonormal; DOT_LZERO] THEN REAL_ARITH_TAC);;
+
+let ORTHONORMAL_IMP_DISTINCT = prove
+ (`!e1 e2 e3. orthonormal e1 e2 e3 ==> ~(e1 = e2) /\ ~(e1 = e3) /\ ~(e2 = e3)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  REWRITE_TAC[DE_MORGAN_THM] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[orthonormal; DOT_LZERO] THEN REAL_ARITH_TAC);;
+
+let ORTHONORMAL_IMP_INDEPENDENT = prove
+ (`!e1 e2 e3. orthonormal e1 e2 e3 ==> independent {e1,e2,e3}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PAIRWISE_ORTHOGONAL_INDEPENDENT THEN
+  CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[ORTHONORMAL_IMP_NONZERO]] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[orthonormal]) THEN
+  REWRITE_TAC[pairwise; IN_INSERT; NOT_IN_EMPTY] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[orthogonal] THEN
+  ASM_MESON_TAC[DOT_SYM]);;
+
+let ORTHONORMAL_IMP_SPANNING = prove
+ (`!e1 e2 e3. orthonormal e1 e2 e3 ==> span {e1,e2,e3} = (:real^3)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(:real^3)`; `{e1:real^3,e2,e3}`] CARD_EQ_DIM) THEN
+  ASM_SIMP_TAC[ORTHONORMAL_IMP_INDEPENDENT; SUBSET_UNIV] THEN
+  REWRITE_TAC[DIM_UNIV; DIMINDEX_3; HAS_SIZE; FINITE_INSERT; FINITE_EMPTY] THEN
+  SIMP_TAC[CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY; IN_INSERT] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP ORTHONORMAL_IMP_DISTINCT) THEN
+  ASM_REWRITE_TAC[NOT_IN_EMPTY; ARITH] THEN SET_TAC[]);;
+
+let ORTHONORMAL_IMP_INDEPENDENT_EXPLICIT_0 = prove
+ (`!e1 e2 e3 t1 t2 t3.
+        orthonormal e1 e2 e3
+        ==> (t1 % e1 + t2 % e2 + t3 % e3 = vec 0 <=>
+             t1 = &0 /\ t2 = &0 /\ t3 = &0)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INDEPENDENT_3 THEN
+  ASM_MESON_TAC[ORTHONORMAL_IMP_INDEPENDENT; ORTHONORMAL_IMP_DISTINCT]);;
+
+let ORTHONORMAL_IMP_INDEPENDENT_EXPLICIT = prove
+ (`!e1 e2 e3 s1 s2 s3 t1 t2 t3.
+        orthonormal e1 e2 e3
+        ==> (s1 % e1 + s2 % e2 + s3 % e3 = t1 % e1 + t2 % e2 + t3 % e3 <=>
+             s1 = t1 /\ s2 = t2 /\ s3 = t3)`,
+  SIMP_TAC[ORTHONORMAL_IMP_INDEPENDENT_EXPLICIT_0; REAL_SUB_0; VECTOR_ARITH
+   `a % x + b % y + c % z:real^3 = a' % x + b' % y + c' % z <=>
+    (a - a') % x + (b - b') % y + (c - c') % z = vec 0`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Flyspeck arcV is the same as angle even in degenerate cases.              *)
+(* ------------------------------------------------------------------------- *)
+
+let arcV = new_definition
+  `arcV u v w = acs (( (v - u) dot (w - u))/((norm (v-u)) * (norm (w-u))))`;;
+
+let ARCV_ANGLE = prove
+ (`!u v w:real^N. arcV u v w = angle(v,u,w)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[arcV; angle; vector_angle] THEN
+  REWRITE_TAC[VECTOR_SUB_EQ] THEN
+  ASM_CASES_TAC `v:real^N = u` THEN
+  ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0; DOT_LZERO] THEN
+  REWRITE_TAC[real_div; REAL_MUL_LZERO; ACS_0] THEN
+  ASM_CASES_TAC `w:real^N = u` THEN
+  ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0; DOT_RZERO] THEN
+  REWRITE_TAC[real_div; REAL_MUL_LZERO; ACS_0]);;
+
+let ARCV_LINEAR_IMAGE_EQ = prove
+ (`!f a b c.
+        linear f /\ (!x. norm(f x) = norm x)
+        ==> arcV (f a) (f b) (f c) = arcV a b c`,
+  REWRITE_TAC[ARCV_ANGLE; ANGLE_LINEAR_IMAGE_EQ]);;
+
+add_linear_invariants [ARCV_LINEAR_IMAGE_EQ];;
+
+let ARCV_TRANSLATION_EQ = prove
+ (`!a b c d. arcV (a + b) (a + c) (a + d) = arcV b c d`,
+  REWRITE_TAC[ARCV_ANGLE; ANGLE_TRANSLATION_EQ]);;
+
+add_translation_invariants [ARCV_TRANSLATION_EQ];;
+
+(* ------------------------------------------------------------------------- *)
+(* Azimuth angle.                                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let AZIM_EXISTS = prove
+ (`!v w w1 w2.
+          ?theta. &0 <= theta /\ theta < &2 * pi /\
+                  ?h1 h2.
+                     !e1 e2 e3.
+                        orthonormal e1 e2 e3 /\
+                        dist(w,v) % e3 = w - v /\
+                        ~(w = v)
+                        ==> ?psi r1 r2.
+                                w1 - v = (r1 * cos psi) % e1 +
+                                         (r1 * sin psi) % e2 +
+                                         h1 % (w - v) /\
+                                w2 - v = (r2 * cos (psi + theta)) % e1 +
+                                         (r2 * sin (psi + theta)) % e2 +
+                                         h2 % (w - v) /\
+                                (~collinear {v, w, w1} ==> &0 < r1) /\
+                                (~collinear {v, w, w2} ==> &0 < r2)`,
+  let lemma = prove
+   (`cos(p) % e + sin(p) % rotate2d (pi / &2) e = rotate2d p e`,
+    SIMP_TAC[CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+      FORALL_2; rotate2d; LAMBDA_BETA; DIMINDEX_2; ARITH; VECTOR_2] THEN
+    REWRITE_TAC[SIN_PI2; COS_PI2] THEN REAL_ARITH_TAC) in
+  GEN_GEOM_ORIGIN_TAC `v:real^3` ["e1"; "e2"; "e3"] THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; DIST_0] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+  GEN_REWRITE_TAC I [SWAP_EXISTS_THM] THEN
+  EXISTS_TAC `(w dot (w1:real^3)) / (w dot w)` THEN
+  GEN_REWRITE_TAC I [SWAP_EXISTS_THM] THEN
+  EXISTS_TAC `(w dot (w2:real^3)) / (w dot w)` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `w:real^3` THEN
+  X_GEN_TAC `w:real` THEN GEN_REWRITE_TAC LAND_CONV
+   [REAL_ARITH `&0 <= w <=> w = &0 \/ &0 < w`] THEN
+  STRIP_TAC THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_MUL_RZERO; NORM_0] THEN
+    EXISTS_TAC `&0` THEN MP_TAC PI_POS THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SIMP_TAC[DOT_LMUL; NORM_MUL; DIMINDEX_3; ARITH; DOT_RMUL; DOT_BASIS;
+           VECTOR_MUL_COMPONENT; NORM_BASIS; BASIS_COMPONENT] THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RID] THEN
+  ASM_SIMP_TAC[REAL_FIELD `&0 < w ==> (w * x) / (w * w) * w = x`;
+               REAL_ARITH `&0 < w ==> abs w = w`] THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+    `a % x:real^3 = a % y <=> a % (x - y) = vec 0`] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ; BASIS_NONZERO;
+               DIMINDEX_3; ARITH; VECTOR_SUB_EQ] THEN
+  REWRITE_TAC[MESON[] `(!e3. p e3 /\ e3 = a ==> q e3) <=> p a ==> q a`] THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `x:real^3 = a + b + c <=> x - c = a + b`] THEN
+  REPEAT GEN_TAC THEN
+  ABBREV_TAC `v1:real^3 = w1 - (w1$3) % basis 3` THEN
+  ABBREV_TAC `v2:real^3 = w2 - (w2$3) % basis 3` THEN
+  SUBGOAL_THEN
+   `(collinear{vec 0, w % basis 3, w1} <=>
+     w1 - w1$3 % basis 3:real^3 = vec 0) /\
+    (collinear{vec 0, w % basis 3, w2} <=>
+     w2 - w2$3 % basis 3:real^3 = vec 0)`
+   (fun th -> REWRITE_TAC[th])
+  THENL
+   [ASM_SIMP_TAC[COLLINEAR_LEMMA; VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ;
+                 BASIS_NONZERO; DIMINDEX_3; ARITH] THEN
+    MAP_EVERY EXPAND_TAC ["v1"; "v2"] THEN
+    SIMP_TAC[CART_EQ; VEC_COMPONENT; VECTOR_ADD_COMPONENT; FORALL_3;
+             VECTOR_MUL_COMPONENT; BASIS_COMPONENT; DIMINDEX_3; ARITH;
+             VECTOR_SUB_COMPONENT; REAL_MUL_RZERO; REAL_MUL_RID;
+             REAL_SUB_RZERO] THEN
+    REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+    CONV_TAC(BINOP_CONV(BINOP_CONV(ONCE_DEPTH_CONV SYM_CONV))) THEN
+    ASM_SIMP_TAC[GSYM REAL_EQ_RDIV_EQ; EXISTS_REFL] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `(v1:real^3)$3 = &0 /\ (v2:real^3)$3 = &0` MP_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["v1"; "v2"] THEN
+    REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT; VECTOR_SUB_EQ] THEN
+    SIMP_TAC[BASIS_COMPONENT; DIMINDEX_3; ARITH] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MAP_EVERY (fun t -> SPEC_TAC(t,t)) [`v2:real^3`; `v1:real^3`] THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN REWRITE_TAC[orthonormal] THEN
+  SIMP_TAC[DOT_BASIS; BASIS_COMPONENT; DIMINDEX_3; ARITH] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c /\ d /\ e /\ f <=>
+                         d /\ e /\ a /\ b /\ c /\ f`] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  PAD2D3D_TAC THEN REPEAT STRIP_TAC THEN
+  SIMP_TAC[cross; VECTOR_3; pad2d3d; LAMBDA_BETA; DIMINDEX_3; ARITH] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  ASM_CASES_TAC `v1:real^2 = vec 0` THEN ASM_REWRITE_TAC[NORM_POS_LT] THENL
+   [MP_TAC(ISPECL [`basis 1:real^2`; `v2:real^2`]
+      ROTATION_ROTATE2D_EXISTS_GEN) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`e1:real^2`; `basis 1:real^2`]
+      ROTATION_ROTATE2D_EXISTS_GEN) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `p:real` THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`&0`; `norm(v2:real^2)`] THEN
+    ASM_REWRITE_TAC[NORM_POS_LT] THEN
+    REWRITE_TAC[REAL_MUL_LZERO; VECTOR_MUL_LZERO; VECTOR_ADD_RID] THEN
+    SUBGOAL_THEN `norm(e1:real^2) = &1 /\ norm(e2:real^2) = &1`
+    STRIP_ASSUME_TAC THENL [ASM_REWRITE_TAC[NORM_EQ_1]; ALL_TAC] THEN
+    SUBGOAL_THEN `e2 = rotate2d (pi / &2) e1` SUBST1_TAC THENL
+     [MATCH_MP_TAC ROTATION_ROTATE2D_EXISTS_ORTHOGONAL_ORIENTED THEN
+      ASM_REWRITE_TAC[NORM_EQ_1; orthogonal];
+      ALL_TAC] THEN
+    REWRITE_TAC[GSYM VECTOR_MUL_ASSOC; GSYM VECTOR_ADD_LDISTRIB] THEN
+    REWRITE_TAC[lemma] THEN ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
+    REWRITE_TAC[ROTATE2D_ADD] THEN ASM_REWRITE_TAC[VECTOR_MUL_LID] THEN
+    MATCH_MP_TAC VECTOR_MUL_LCANCEL_IMP THEN
+    EXISTS_TAC `norm(basis 1:real^2)` THEN
+    ASM_SIMP_TAC[NORM_EQ_0; BASIS_NONZERO; DIMINDEX_2; ARITH] THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [SYM th]) THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH `a % b % x:real^2 = b % a % x`] THEN
+    AP_TERM_TAC THEN
+    SIMP_TAC[GSYM(MATCH_MP LINEAR_CMUL (SPEC_ALL LINEAR_ROTATE2D))] THEN
+    AP_TERM_TAC THEN
+    ASM_SIMP_TAC[LINEAR_CMUL; LINEAR_ROTATE2D; VECTOR_MUL_LID];
+    MP_TAC(ISPECL [`v1:real^2`; `v2:real^2`] ROTATION_ROTATE2D_EXISTS_GEN) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`e1:real^2`; `v1:real^2`] ROTATION_ROTATE2D_EXISTS_GEN) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `p:real` THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`norm(v1:real^2)`; `norm(v2:real^2)`] THEN
+    ASM_REWRITE_TAC[NORM_POS_LT] THEN
+    SUBGOAL_THEN `norm(e1:real^2) = &1 /\ norm(e2:real^2) = &1`
+    STRIP_ASSUME_TAC THENL [ASM_REWRITE_TAC[NORM_EQ_1]; ALL_TAC] THEN
+    SUBGOAL_THEN `e2 = rotate2d (pi / &2) e1` SUBST1_TAC THENL
+     [MATCH_MP_TAC ROTATION_ROTATE2D_EXISTS_ORTHOGONAL_ORIENTED THEN
+      ASM_REWRITE_TAC[NORM_EQ_1; orthogonal];
+      ALL_TAC] THEN
+    REWRITE_TAC[GSYM VECTOR_MUL_ASSOC; GSYM VECTOR_ADD_LDISTRIB] THEN
+    REWRITE_TAC[lemma] THEN ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
+    REWRITE_TAC[ROTATE2D_ADD] THEN ASM_REWRITE_TAC[VECTOR_MUL_LID] THEN
+    MATCH_MP_TAC VECTOR_MUL_LCANCEL_IMP THEN EXISTS_TAC `norm(v1:real^2)` THEN
+    ASM_REWRITE_TAC[NORM_EQ_0] THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [SYM th]) THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH `a % b % x:real^2 = b % a % x`] THEN
+    AP_TERM_TAC THEN
+    SIMP_TAC[GSYM(MATCH_MP LINEAR_CMUL (SPEC_ALL LINEAR_ROTATE2D))] THEN
+    AP_TERM_TAC THEN
+    ASM_SIMP_TAC[LINEAR_CMUL; LINEAR_ROTATE2D; VECTOR_MUL_LID]]);;
+
+let azim_spec =
+   (REWRITE_RULE[SKOLEM_THM]
+    (REWRITE_RULE[RIGHT_EXISTS_IMP_THM] AZIM_EXISTS));;
+
+let azim_def = new_definition
+  `azim v w w1 w2 =
+        if collinear {v,w,w1} \/ collinear {v,w,w2} then &0
+        else @theta. &0 <= theta /\ theta < &2 * pi /\
+                     ?h1 h2.
+                         !e1 e2 e3.
+                            orthonormal e1 e2 e3 /\
+                            dist(w,v) % e3 = w - v /\
+                            ~(w = v)
+                            ==> ?psi r1 r2.
+                                    w1 - v = (r1 * cos psi) % e1 +
+                                             (r1 * sin psi) % e2 +
+                                             h1 % (w - v) /\
+                                    w2 - v = (r2 * cos (psi + theta)) % e1 +
+                                             (r2 * sin (psi + theta)) % e2 +
+                                             h2 % (w - v) /\
+                                    &0 < r1 /\ &0 < r2`;;
+
+let azim = prove
+ (`!v w w1 w2:real^3.
+        &0 <= azim v w w1 w2 /\ azim v w w1 w2 < &2 * pi /\
+        ?h1 h2.
+           !e1 e2 e3.
+              orthonormal e1 e2 e3 /\
+              dist(w,v) % e3 = w - v /\
+              ~(w = v)
+              ==> ?psi r1 r2.
+                      w1 - v = (r1 * cos psi) % e1 +
+                               (r1 * sin psi) % e2 +
+                               h1 % (w - v) /\
+                      w2 - v = (r2 * cos (psi + azim v w w1 w2)) % e1 +
+                               (r2 * sin (psi + azim v w w1 w2)) % e2 +
+                               h2 % (w - v) /\
+                      (~collinear {v, w, w1} ==> &0 < r1) /\
+                      (~collinear {v, w, w2} ==> &0 < r2)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[azim_def] THEN
+  COND_CASES_TAC THENL
+   [ALL_TAC;
+    RULE_ASSUM_TAC(REWRITE_RULE[DE_MORGAN_THM]) THEN ASM_REWRITE_TAC[] THEN
+    CONV_TAC SELECT_CONV THEN
+    MP_TAC(ISPECL [`v:real^3`; `w:real^3`; `w1:real^3`; `w2:real^3`]
+        AZIM_EXISTS) THEN
+    ASM_REWRITE_TAC[]] THEN
+  SIMP_TAC[PI_POS; REAL_LT_MUL; REAL_OF_NUM_LT; ARITH; REAL_LE_REFL] THEN
+  FIRST_X_ASSUM DISJ_CASES_TAC THENL
+   [MP_TAC(ISPECL [`v:real^3`; `w:real^3`; `w2:real^3`; `w1:real^3`]
+     AZIM_EXISTS) THEN
+    DISCH_THEN(CHOOSE_THEN(MP_TAC o CONJUNCT2 o CONJUNCT2)) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`h2:real`; `h1:real`] THEN
+    DISCH_TAC THEN MAP_EVERY EXISTS_TAC [`h1:real`; `h2:real`] THEN
+    MAP_EVERY X_GEN_TAC [`e1:real^3`; `e2:real^3`; `e3:real^3`] THEN
+    STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`e1:real^3`; `e2:real^3`; `e3:real^3`]) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `psi:real` THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM; REAL_ADD_RID] THEN
+    MAP_EVERY X_GEN_TAC [`r2:real`; `r1:real`] THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`&0`; `r2:real`];
+    MP_TAC(ISPECL [`v:real^3`; `w:real^3`; `w1:real^3`; `w2:real^3`]
+       AZIM_EXISTS) THEN
+    DISCH_THEN(CHOOSE_THEN(MP_TAC o CONJUNCT2 o CONJUNCT2)) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`h1:real`; `h2:real`] THEN
+    DISCH_TAC THEN MAP_EVERY EXISTS_TAC [`h1:real`; `h2:real`] THEN
+    MAP_EVERY X_GEN_TAC [`e1:real^3`; `e2:real^3`; `e3:real^3`] THEN
+    STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`e1:real^3`; `e2:real^3`; `e3:real^3`]) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `psi:real` THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM; REAL_ADD_RID] THEN
+    MAP_EVERY X_GEN_TAC [`r1:real`; `r2:real`] THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`r1:real`; `&0`]] THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV
+   [SET_RULE `{v,w,x} = {w,v,x}`]) THEN
+  ONCE_REWRITE_TAC[COLLINEAR_3] THEN ASM_REWRITE_TAC[] THEN
+  UNDISCH_THEN `dist(w:real^3,v) % e3 = w - v` (SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[GSYM DOT_CAUCHY_SCHWARZ_EQUAL] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[orthonormal]) THEN
+  ASM_REWRITE_TAC[DOT_LADD; DOT_RADD; DOT_LMUL; DOT_RMUL; REAL_MUL_RZERO] THEN
+  ONCE_REWRITE_TAC[DOT_SYM] THEN ASM_REWRITE_TAC[REAL_MUL_RZERO] THEN
+  REWRITE_TAC[REAL_ADD_LID; REAL_ADD_RID; REAL_MUL_RID] THEN
+  REWRITE_TAC[REAL_ARITH `(r * c) * (r * c):real = r pow 2 * c pow 2`] THEN
+  REWRITE_TAC[REAL_ARITH `r * c + r * s + f:real = r * (s + c) + f`] THEN
+  REWRITE_TAC[SIN_CIRCLE] THEN REWRITE_TAC[REAL_RING
+   `(d * h * d) pow 2 = (d * d) * (r * &1 + h * d * h * d) <=>
+    d = &0 \/ r = &0`] THEN
+  ASM_REWRITE_TAC[DIST_EQ_0; REAL_POW_EQ_0; ARITH] THEN
+  DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[REAL_MUL_LZERO; DOT_LZERO]);;
+
+let AZIM_UNIQUE = prove
+ (`!v w w1 w2 h1 h2 r1 r2 e1 e2 e3 psi theta.
+        &0 <= theta /\
+        theta < &2 * pi /\
+        orthonormal e1 e2 e3 /\
+        dist(w,v) % e3 = w - v /\
+        ~(w = v) /\
+        &0 < r1 /\ &0 < r2 /\
+        w1 - v = (r1 * cos psi) % e1 +
+                 (r1 * sin psi) % e2 +
+                 h1 % (w - v) /\
+        w2 - v = (r2 * cos (psi + theta)) % e1 +
+                 (r2 * sin (psi + theta)) % e2 +
+                 h2 % (w - v)
+        ==> azim v w w1 w2 = theta`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `~collinear{v:real^3,w,w2} /\ ~collinear {v,w,w1}`
+  STRIP_ASSUME_TAC THENL
+   [ONCE_REWRITE_TAC[SET_RULE `{a,b,c} = {b,a,c}`] THEN
+    ONCE_REWRITE_TAC[COLLINEAR_3] THEN REWRITE_TAC[COLLINEAR_LEMMA] THEN
+    ASM_REWRITE_TAC[] THEN ASM_REWRITE_TAC[VECTOR_SUB_EQ] THEN
+    UNDISCH_THEN `dist(w:real^3,v) % e3 = w - v` (SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC; VECTOR_ARITH
+     `a + b + c % x:real^N = d % x <=> a + b + (c - d) % x = vec 0`] THEN
+    ASM_SIMP_TAC[ORTHONORMAL_IMP_INDEPENDENT_EXPLICIT_0] THEN
+    ASM_SIMP_TAC[CONJ_ASSOC; REAL_LT_IMP_NZ; SIN_CIRCLE; REAL_RING
+     `s pow 2 + c pow 2 = &1 ==> (r * c = &0 /\ r * s = &0 <=> r = &0)`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(azim v w w1 w2 - theta) / (&2 * pi) = &0` MP_TAC THENL
+   [ALL_TAC; MP_TAC PI_POS THEN CONV_TAC REAL_FIELD] THEN
+  MATCH_MP_TAC REAL_EQ_INTEGERS_IMP THEN
+  ASM_SIMP_TAC[REAL_SUB_RZERO; REAL_ABS_DIV; REAL_ABS_MUL; REAL_ABS_NUM;
+       REAL_ABS_PI; REAL_LT_LDIV_EQ; REAL_LT_MUL; REAL_OF_NUM_LT; ARITH;
+       PI_POS; INTEGER_CLOSED; REAL_MUL_LID] THEN
+  MP_TAC(ISPECL [`v:real^3`; `w:real^3`; `w1:real^3`; `w2:real^3`] azim) THEN
+  ASM_REWRITE_TAC[] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ASM_SIMP_TAC[REAL_ARITH
+   `&0 <= x /\ x < k /\ &0 <= y /\ y < k ==> abs(x - y) < k`] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`k1:real`; `k2:real`] THEN
+  DISCH_THEN(MP_TAC o SPECL [`e1:real^3`; `e2:real^3`; `e3:real^3`]) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`phi:real`; `s1:real`; `s2:real`] THEN
+  UNDISCH_THEN `dist(w:real^3,v) % e3 = w - v` (SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[ORTHONORMAL_IMP_INDEPENDENT_EXPLICIT] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c /\ d <=> (c /\ d) /\ a /\ b`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN (MP_TAC o MATCH_MP (REAL_FIELD
+   `r * c = r' * c' /\ r * s = r' * s' /\ u:real = v
+    ==> s pow 2 + c pow 2 = &1 /\ s' pow 2 + c' pow 2 = &1 /\
+        &0 < r /\ (r pow 2 = r' pow 2 ==> r = r')
+        ==> s = s' /\ c = c'`))) THEN
+  ASM_REWRITE_TAC[SIN_CIRCLE; GSYM REAL_EQ_SQUARE_ABS] THEN
+  ASM_SIMP_TAC[REAL_ARITH
+   `&0 < x /\ &0 < y ==> (abs x = abs y <=> x = y)`] THEN
+  REWRITE_TAC[SIN_COS_EQ] THEN
+  REWRITE_TAC[REAL_ARITH
+   `psi + theta = (phi + az) + x:real <=> psi = phi + x + (az - theta)`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `m:real` STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[REAL_EQ_ADD_LCANCEL] THEN
+  REWRITE_TAC[REAL_ARITH
+   `&2 * m * pi + x = &2 * n * pi <=> x = (n - m) * &2 * pi`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `n:real` STRIP_ASSUME_TAC) THEN
+  ASM_SIMP_TAC[PI_POS; REAL_FIELD `&0 < pi ==> (x * &2 * pi) / (&2 * pi) = x`;
+               INTEGER_CLOSED]);;
+
+let AZIM_TRANSLATION = prove
+ (`!a v w w1 w2. azim (a + v) (a + w) (a + w1) (a + w2) = azim v w w1 w2`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[azim_def] THEN
+  REWRITE_TAC[VECTOR_ARITH `(a + w) - (a + v):real^3 = w - v`;
+              VECTOR_ARITH `a + w:real^3 = a + v <=> w = v`;
+              NORM_ARITH `dist(a + v,a + w) = dist(v,w)`] THEN
+  REWRITE_TAC[SET_RULE
+   `{a + x,a + y,a + z} = IMAGE (\x:real^3. a + x) {x,y,z}`] THEN
+  REWRITE_TAC[COLLINEAR_TRANSLATION_EQ]);;
+
+add_translation_invariants [AZIM_TRANSLATION];;
+
+let AZIM_LINEAR_IMAGE = prove
+ (`!f. linear f /\ (!x. norm(f x) = norm x) /\
+       (2 <= dimindex(:3) ==> det(matrix f) = &1)
+       ==> !v w w1 w2. azim (f v) (f w) (f w1) (f w2) = azim v w w1 w2`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[azim_def] THEN
+  ASM_SIMP_TAC[GSYM LINEAR_SUB; dist] THEN
+  MP_TAC(ISPEC `f:real^3->real^3` QUANTIFY_SURJECTION_THM) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION;
+                  ORTHOGONAL_TRANSFORMATION_SURJECTIVE];
+    ALL_TAC] THEN
+  DISCH_THEN(CONV_TAC o LAND_CONV o EXPAND_QUANTS_CONV) THEN
+  ASM_SIMP_TAC[ORTHONORMAL_LINEAR_IMAGE] THEN
+  ASM_SIMP_TAC[GSYM LINEAR_CMUL; GSYM LINEAR_ADD] THEN
+  SUBGOAL_THEN `!x y. (f:real^3->real^3) x = f y <=> x = y` ASSUME_TAC THENL
+   [ASM_MESON_TAC[PRESERVES_NORM_INJECTIVE]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[SET_RULE `{f x,f y,f z} = IMAGE f {x,y,z}`] THEN
+  ASM_SIMP_TAC[COLLINEAR_LINEAR_IMAGE_EQ]);;
+
+add_linear_invariants [AZIM_LINEAR_IMAGE];;
+
+let AZIM_DEGENERATE = prove
+ (`(!v w w1 w2. v = w ==> azim v w w1 w2 = &0) /\
+   (!v w w1 w2. collinear{v,w,w1} ==> azim v w w1 w2 = &0) /\
+   (!v w w1 w2. collinear{v,w,w2} ==> azim v w w1 w2 = &0)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[azim_def] THEN
+  ASM_REWRITE_TAC[] THEN REWRITE_TAC[INSERT_AC; COLLINEAR_2]);;
+
+let AZIM_REFL_ALT = prove
+ (`!v x y. azim v v x y = &0`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC(last(CONJUNCTS AZIM_DEGENERATE)) THEN
+  REWRITE_TAC[COLLINEAR_2; INSERT_AC]);;
+
+let AZIM_SPECIAL_SCALE = prove
+ (`!a v w1 w2.
+        &0 < a
+        ==> azim (vec 0) (a % v) w1 w2 = azim (vec 0) v w1 w2`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[azim_def] THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; DIST_0] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP(MESON[REAL_LT_IMP_NZ; REAL_DIV_LMUL]
+   `!a. &0 < a ==> (!y. ?x. a * x = y)`)) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP QUANTIFY_SURJECTION_THM) THEN
+  DISCH_THEN(CONV_TAC o RAND_CONV o
+    PARTIAL_EXPAND_QUANTS_CONV ["psi"; "r1"; "r2"]) THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC; REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ] THEN
+  ASM_SIMP_TAC[NORM_MUL; REAL_ARITH `&0 < a ==> abs a = a`] THEN
+  REWRITE_TAC[GSYM VECTOR_MUL_ASSOC] THEN
+  REWRITE_TAC[VECTOR_ARITH `a % x:real^3 = a % y <=> a % (x - y) = vec 0`] THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_NZ; VECTOR_MUL_EQ_0] THEN
+  REWRITE_TAC[VECTOR_SUB_EQ] THEN
+  ASM_SIMP_TAC[COLLINEAR_SPECIAL_SCALE; REAL_LT_IMP_NZ]);;
+
+let AZIM_SCALE_ALL = prove
+ (`!a v w1 w2.
+        &0 < a /\ &0 < b /\ &0 < c
+        ==> azim (vec 0) (a % v) (b % w1) (c % w2) = azim (vec 0) v w1 w2`,
+  let lemma = MESON[REAL_LT_IMP_NZ; REAL_DIV_LMUL]
+   `!a. &0 < a ==> (!y. ?x. a * x = y)` in
+  let SCALE_QUANT_TAC side asm avoid =
+    MP_TAC(MATCH_MP lemma (ASSUME asm)) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP QUANTIFY_SURJECTION_THM) THEN
+    DISCH_THEN(CONV_TAC o side o PARTIAL_EXPAND_QUANTS_CONV avoid) in
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[azim_def; COLLINEAR_SCALE_ALL; REAL_LT_IMP_NZ] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[VECTOR_SUB_RZERO] THEN
+  ASM_SIMP_TAC[DIST_0; NORM_MUL; GSYM VECTOR_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 < a ==> abs a = a`; VECTOR_MUL_LCANCEL] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ] THEN
+  SCALE_QUANT_TAC RAND_CONV `&0 < a`  ["psi"; "r1"; "r2"] THEN
+  SCALE_QUANT_TAC LAND_CONV `&0 < b`  ["psi"; "h2"; "r2"] THEN
+  SCALE_QUANT_TAC LAND_CONV `&0 < c`  ["psi"; "h1"; "r1"] THEN
+  ASM_SIMP_TAC[GSYM VECTOR_MUL_ASSOC; GSYM VECTOR_ADD_LDISTRIB;
+               VECTOR_MUL_LCANCEL; REAL_LT_IMP_NZ; REAL_LT_MUL_EQ] THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC; REAL_MUL_AC]);;
+
+let AZIM_ARG = prove
+ (`!x y:real^3. azim (vec 0) (basis 3) x y = Arg(dropout 3 y / dropout 3 x)`,
+  let lemma = prove
+   (`(r * cos t) % basis 1 + (r * sin t) % basis 2 = Cx r * cexp(ii * Cx t)`,
+    REWRITE_TAC[CEXP_EULER; COMPLEX_BASIS; GSYM CX_SIN; GSYM CX_COS;
+                COMPLEX_CMUL; CX_MUL] THEN
+    CONV_TAC COMPLEX_RING) in
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `collinear {vec 0:real^3,basis 3,x}` THENL
+   [ASM_SIMP_TAC[AZIM_DEGENERATE] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[COLLINEAR_BASIS_3]) THEN
+    ASM_REWRITE_TAC[COMPLEX_VEC_0; complex_div; COMPLEX_INV_0;
+                    COMPLEX_MUL_RZERO; ARG_0];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `collinear {vec 0:real^3,basis 3,y}` THENL
+   [ASM_SIMP_TAC[AZIM_DEGENERATE] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[COLLINEAR_BASIS_3]) THEN
+    ASM_REWRITE_TAC[COMPLEX_VEC_0; complex_div; COMPLEX_MUL_LZERO; ARG_0];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`vec 0:real^3`; `basis 3:real^3`; `x:real^3`; `y:real^3`]
+        azim) THEN
+  ABBREV_TAC `a = azim (vec 0) (basis 3) x (y:real^3)` THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; VECTOR_SUB_RZERO; DIST_0] THEN
+  MAP_EVERY X_GEN_TAC [`h1:real`; `h2:real`] THEN
+  DISCH_THEN(MP_TAC o SPECL
+   [`basis 1:real^3`; `basis 2:real^3`; `basis 3:real^3`]) THEN
+  SIMP_TAC[orthonormal; DOT_BASIS_BASIS; CROSS_BASIS; DIMINDEX_3; NORM_BASIS;
+    ARITH; VECTOR_MUL_LID; BASIS_NONZERO; REAL_LT_01; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`psi:real`; `r1:real`; `r2:real`] THEN
+  DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THEN
+  REWRITE_TAC[DROPOUT_ADD; DROPOUT_MUL; DROPOUT_BASIS_3] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_RID; lemma] THEN
+  REWRITE_TAC[complex_div; COMPLEX_INV_MUL] THEN
+  ONCE_REWRITE_TAC[COMPLEX_RING
+   `(a * b) * (c * d):complex = (a * c) * b * d`] THEN
+  REWRITE_TAC[GSYM complex_div; GSYM CX_DIV; GSYM CEXP_SUB] THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC ARG_UNIQUE THEN
+  EXISTS_TAC `r2 / r1:real` THEN ASM_SIMP_TAC[REAL_LT_DIV] THEN
+  AP_TERM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[CX_ADD] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let REAL_CONTINUOUS_AT_AZIM_SHARP = prove
+ (`!v w w1 w2.
+        ~collinear{v,w,w1} /\ ~(w2 IN aff_ge {v,w} {w1})
+        ==> (azim v w w1) real_continuous at w2`,
+  GEOM_ORIGIN_TAC `v:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `w:real^3` THEN
+  X_GEN_TAC `w:real` THEN ASM_CASES_TAC `w = &0` THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_LE_LT; COLLINEAR_SPECIAL_SCALE] THEN
+  DISCH_TAC THEN REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AFF_GE_SPECIAL_SCALE o
+    rand o rand o lhand o snd) THEN
+  ASM_REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY; IN_SING] THEN ANTS_TAC THENL
+   [POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[DE_MORGAN_THM] THEN
+    DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THENL
+     [ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC];
+      ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC];
+      ASM_SIMP_TAC[COLLINEAR_LEMMA_ALT; BASIS_NONZERO; DIMINDEX_3; ARITH] THEN
+      MESON_TAC[]];
+    DISCH_THEN SUBST1_TAC THEN DISCH_TAC] THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; AZIM_ARG] THEN
+  MATCH_MP_TAC(REWRITE_RULE[o_DEF]
+    REAL_CONTINUOUS_CONTINUOUS_AT_COMPOSE) THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[complex_div] THEN MATCH_MP_TAC CONTINUOUS_COMPLEX_MUL THEN
+    REWRITE_TAC[CONTINUOUS_CONST; ETA_AX] THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_AT; LINEAR_DROPOUT; DIMINDEX_3; DIMINDEX_2;
+             ARITH];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_CONTINUOUS_AT_WITHIN THEN
+  MATCH_MP_TAC REAL_CONTINUOUS_AT_ARG THEN
+  MP_TAC(ISPECL [`w2:real^3`; `w1:real^3`] AFF_GE_2_1_0_DROPOUT_3) THEN
+  ASM_REWRITE_TAC[] THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o
+    GEN_REWRITE_RULE RAND_CONV [COLLINEAR_BASIS_3])) THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) w2`,`v2:real^2`) THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) w1`,`v1:real^2`) THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN
+  GEOM_BASIS_MULTIPLE_TAC 1 `v1:complex` THEN
+  X_GEN_TAC `w:real` THEN ASM_CASES_TAC `w = &0` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+  GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN ASM_REWRITE_TAC[] THEN
+  DISCH_TAC THEN X_GEN_TAC `z:complex` THEN
+  DISCH_THEN(K ALL_TAC) THEN
+  REWRITE_TAC[CONTRAPOS_THM; COMPLEX_BASIS; COMPLEX_CMUL] THEN
+  REWRITE_TAC[COMPLEX_MUL_RID; RE_DIV_CX; IM_DIV_CX; real] THEN
+  ASM_SIMP_TAC[REAL_DIV_EQ_0; REAL_LE_RDIV_EQ; REAL_MUL_LZERO] THEN
+  STRIP_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AFF_GE_1_1_0 o rand o snd) THEN
+  ASM_REWRITE_TAC[COMPLEX_VEC_0; CX_INJ] THEN DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN EXISTS_TAC `Re z / w` THEN
+  ASM_SIMP_TAC[REAL_LE_DIV; REAL_LT_IMP_LE; COMPLEX_EQ] THEN
+  ASM_SIMP_TAC[COMPLEX_CMUL; CX_DIV; COMPLEX_DIV_RMUL; CX_INJ] THEN
+  REWRITE_TAC[RE_CX; IM_CX]);;
+
+let REAL_CONTINUOUS_AT_AZIM = prove
+ (`!v w w1 w2. ~coplanar{v,w,w1,w2} ==> (azim v w w1) real_continuous at w2`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_CONTINUOUS_AT_AZIM_SHARP THEN
+  CONJ_TAC THENL
+   [ASM_MESON_TAC[NOT_COPLANAR_NOT_COLLINEAR; INSERT_AC];
+    DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[SUBSET]
+       AFF_GE_SUBSET_AFFINE_HULL)) THEN
+    POP_ASSUM MP_TAC THEN REWRITE_TAC[coplanar; CONTRAPOS_THM] THEN
+    REWRITE_TAC[SET_RULE `{a,b} UNION {c} = {a,b,c}`] THEN
+    DISCH_TAC THEN MAP_EVERY EXISTS_TAC
+     [`v:real^3`; `w:real^3`; `w1:real^3`] THEN
+    SIMP_TAC[SET_RULE `{a,b,c,d} SUBSET s <=> {a,b,c} SUBSET s /\ d IN s`] THEN
+    ASM_REWRITE_TAC[HULL_SUBSET]]);;
+
+let AZIM_REFL = prove
+ (`!v0 v1 w. azim v0 v1 w w = &0`,
+  GEOM_ORIGIN_TAC `v0:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `v1:real^3` THEN
+  GEN_TAC THEN
+  GEN_REWRITE_TAC LAND_CONV [REAL_ARITH `&0 <= x <=> x = &0 \/ &0 < x`] THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[VECTOR_MUL_LZERO; AZIM_DEGENERATE] THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; AZIM_ARG; ARG_EQ_0] THEN
+  X_GEN_TAC `w:real^3` THEN
+  ASM_CASES_TAC `(dropout 3 :real^3->real^2) w = Cx(&0)` THEN
+  ASM_SIMP_TAC[COMPLEX_DIV_REFL; REAL_CX; RE_CX; REAL_POS] THEN
+  ASM_SIMP_TAC[complex_div; COMPLEX_MUL_LZERO; REAL_CX; RE_CX; REAL_POS]);;
+
+let AZIM_EQ = prove
+ (`!v0 v1 w x y.
+        ~collinear{v0,v1,w} /\ ~collinear{v0,v1,x} /\ ~collinear{v0,v1,y}
+        ==> (azim v0 v1 w x = azim v0 v1 w y <=> y IN aff_gt {v0,v1} {x})`,
+  GEOM_ORIGIN_TAC `v0:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `v1:real^3` THEN
+  GEN_TAC THEN
+  GEN_REWRITE_TAC LAND_CONV [REAL_ARITH `&0 <= x <=> x = &0 \/ &0 < x`] THEN
+  STRIP_TAC THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; REAL_LT_IMP_NZ; COLLINEAR_SPECIAL_SCALE] THEN
+  REPEAT STRIP_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AFF_GT_SPECIAL_SCALE o
+    rand o rand o snd) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[IN_INSERT; FINITE_INSERT; FINITE_EMPTY; NOT_IN_EMPTY] THEN
+    REPEAT CONJ_TAC THEN DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+    TRY(RULE_ASSUM_TAC(REWRITE_RULE[INSERT_AC; COLLINEAR_2]) THEN
+        FIRST_X_ASSUM CONTR_TAC) THEN
+    UNDISCH_TAC `~collinear {vec 0:real^3, basis 3, v1 % basis 3}` THEN
+    REWRITE_TAC[COLLINEAR_LEMMA] THEN MESON_TAC[];
+    DISCH_THEN SUBST1_TAC] THEN
+  REWRITE_TAC[AZIM_ARG] THEN CONV_TAC(LAND_CONV SYM_CONV) THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) ARG_EQ o lhand o snd) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[COLLINEAR_BASIS_3]) THEN
+  ASM_REWRITE_TAC[complex_div; COMPLEX_ENTIRE; COMPLEX_INV_EQ_0] THEN
+  ASM_REWRITE_TAC[GSYM complex_div; GSYM COMPLEX_VEC_0] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  ASM_SIMP_TAC[GSYM COMPLEX_VEC_0; COMPLEX_FIELD
+    `~(w = Cx(&0)) ==> (y / w = x * u / w <=> y = x * u)`] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AFF_GT_2_1 o rand o rand o snd) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[SET_RULE `DISJOINT {a,b} {x} <=> ~(x = a) /\ ~(x = b)`] THEN
+    ASM_MESON_TAC[DROPOUT_BASIS_3; DROPOUT_0];
+    DISCH_THEN SUBST1_TAC] THEN
+  REWRITE_TAC[IN_ELIM_THM; VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+  ONCE_REWRITE_TAC[MESON[]
+   `(?a b c. p c /\ q a b c /\ r b c) <=>
+    (?c. p c /\ ?b. r b c /\ ?a. q a b c)`] THEN
+  SIMP_TAC[REAL_ARITH `a + b + c = &1 <=> a = &1 - b - c`; EXISTS_REFL] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `t:real` THEN REWRITE_TAC[] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[GSYM COMPLEX_CMUL] THEN
+  SIMP_TAC[CART_EQ; FORALL_2; FORALL_3; DIMINDEX_2; DIMINDEX_3;
+           dropout; LAMBDA_BETA; BASIS_COMPONENT; ARITH; REAL_MUL_RID;
+           VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RZERO; UNWIND_THM1;
+           VECTOR_ADD_COMPONENT; REAL_ADD_LID; RIGHT_EXISTS_AND_THM] THEN
+  REWRITE_TAC[REAL_ARITH `y:real = t + z <=> t = y - z`; EXISTS_REFL]);;
+
+let AZIM_EQ_ALT = prove
+ (`!v0 v1 w x y.
+        ~collinear{v0,v1,w} /\ ~collinear{v0,v1,x} /\ ~collinear{v0,v1,y}
+        ==> (azim v0 v1 w x = azim v0 v1 w y <=> x IN aff_gt {v0,v1} {y})`,
+  ASM_SIMP_TAC[GSYM AZIM_EQ] THEN MESON_TAC[]);;
+
+let AZIM_EQ_0 = prove
+ (`!v0 v1 w x.
+        ~collinear{v0,v1,w} /\ ~collinear{v0,v1,x}
+        ==> (azim v0 v1 w x = &0 <=> w IN aff_gt {v0,v1} {x})`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `azim v0 v1 w x = azim v0 v1 w w` THEN CONJ_TAC THENL
+   [REWRITE_TAC[AZIM_REFL];
+    ASM_SIMP_TAC[AZIM_EQ]]);;
+
+let AZIM_EQ_0_ALT = prove
+ (`!v0 v1 w x.
+        ~collinear{v0,v1,w} /\ ~collinear{v0,v1,x}
+        ==> (azim v0 v1 w x = &0 <=> x IN aff_gt {v0,v1} {w})`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `azim v0 v1 w x = azim v0 v1 w w` THEN CONJ_TAC THENL
+   [REWRITE_TAC[AZIM_REFL];
+    ASM_SIMP_TAC[AZIM_EQ_ALT]]);;
+
+let AZIM_EQ_0_GE = prove
+ (`!v0 v1 w x.
+        ~collinear{v0,v1,w} /\ ~collinear{v0,v1,x}
+        ==> (azim v0 v1 w x = &0 <=> w IN aff_ge {v0,v1} {x})`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `v1:real^3 = v0` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; STRIP_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AFF_GE_AFF_GT_DECOMP o
+      rand o rand o snd) THEN
+  ANTS_TAC THENL
+   [SIMP_TAC[FINITE_INSERT; FINITE_EMPTY; DISJOINT_INSERT; DISJOINT_EMPTY] THEN
+    REWRITE_TAC[IN_SING] THEN
+    CONJ_TAC THEN DISCH_THEN SUBST_ALL_TAC THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[COLLINEAR_2; INSERT_AC]) THEN
+    FIRST_ASSUM CONTR_TAC;
+    DISCH_THEN SUBST1_TAC] THEN
+  ASM_SIMP_TAC[AZIM_EQ_0] THEN
+  REWRITE_TAC[SIMPLE_IMAGE; IMAGE_CLAUSES; UNIONS_1] THEN
+  REWRITE_TAC[SET_RULE `{x} DELETE x = {}`] THEN
+  REWRITE_TAC[AFF_GE_EQ_AFFINE_HULL; IN_UNION] THEN
+  ASM_SIMP_TAC[GSYM COLLINEAR_3_AFFINE_HULL]);;
+
+let AZIM_COMPL_EQ_0 = prove
+ (`!z w w1 w2.
+        ~collinear {z,w,w1} /\ ~collinear {z,w,w2} /\ azim z w w1 w2 = &0
+        ==> azim z w w2 w1 = &0`,
+  REWRITE_TAC[IMP_CONJ] THEN
+  GEOM_ORIGIN_TAC `z:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `w:real^3` THEN
+  X_GEN_TAC `w:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `w = &0` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  DISCH_TAC THEN REPEAT GEN_TAC THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; COLLINEAR_SPECIAL_SCALE; AZIM_ARG] THEN
+  REWRITE_TAC[ARG_EQ_0; real; IM_COMPLEX_DIV_EQ_0; RE_COMPLEX_DIV_GE_0] THEN
+  REWRITE_TAC[complex_mul; RE; IM; cnj] THEN REAL_ARITH_TAC);;
+
+let AZIM_COMPL = prove
+ (`!z w w1 w2.
+        ~collinear {z,w,w1} /\ ~collinear {z,w,w2}
+        ==> azim z w w2 w1 = if azim z w w1 w2 = &0 then &0
+                             else &2 * pi - azim z w w1 w2`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THENL
+   [ASM_MESON_TAC[AZIM_COMPL_EQ_0]; ALL_TAC] THEN
+  DISCH_THEN(fun th -> POP_ASSUM MP_TAC THEN MP_TAC th) THEN
+  GEOM_ORIGIN_TAC `z:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `w:real^3` THEN
+  X_GEN_TAC `w:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `w = &0` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  DISCH_TAC THEN REPEAT GEN_TAC THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; COLLINEAR_SPECIAL_SCALE; AZIM_ARG] THEN
+  REWRITE_TAC[COLLINEAR_BASIS_3] THEN REWRITE_TAC[ARG_EQ_0] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `(dropout 3:real^3->real^2) w2 /
+                (dropout 3:real^3->real^2) w1` ARG_INV) THEN
+  ASM_REWRITE_TAC[COMPLEX_INV_DIV]);;
+
+let AZIM_EQ_PI_SYM = prove
+ (`!z w w1 w2.
+        ~collinear {z, w, w1} /\ ~collinear {z, w, w2}
+        ==> (azim z w w1 w2 = pi <=> azim z w w2 w1 = pi)`,
+  REPEAT STRIP_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AZIM_COMPL o lhand o rand o snd) THEN
+  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let AZIM_EQ_0_SYM = prove
+ (`!z w w1 w2.
+        ~collinear {z, w, w1} /\ ~collinear {z, w, w2}
+        ==> (azim z w w1 w2 = &0 <=> azim z w w2 w1 = &0)`,
+  MESON_TAC[AZIM_COMPL_EQ_0]);;
+
+let AZIM_EQ_0_GE_ALT = prove
+ (`!v0 v1 w x.
+        ~collinear{v0,v1,w} /\ ~collinear{v0,v1,x}
+        ==> (azim v0 v1 w x = &0 <=> x IN aff_ge {v0,v1} {w})`,
+  ASM_MESON_TAC[AZIM_EQ_0_SYM; AZIM_EQ_0_GE]);;
+
+let AZIM_EQ_PI = prove
+ (`!v0 v1 w x.
+        ~collinear{v0,v1,w} /\ ~collinear{v0,v1,x}
+        ==> (azim v0 v1 w x = pi <=> w IN aff_lt {v0,v1} {x})`,
+  GEOM_ORIGIN_TAC `v0:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `v1:real^3` THEN
+  GEN_TAC THEN
+  GEN_REWRITE_TAC LAND_CONV [REAL_ARITH `&0 <= x <=> x = &0 \/ &0 < x`] THEN
+  STRIP_TAC THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; REAL_LT_IMP_NZ;
+               COLLINEAR_SPECIAL_SCALE] THEN
+  REPEAT STRIP_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AFF_LT_SPECIAL_SCALE o
+    rand o rand o snd) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[IN_INSERT; FINITE_INSERT; FINITE_EMPTY; NOT_IN_EMPTY] THEN
+    REPEAT CONJ_TAC THEN DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+    TRY(RULE_ASSUM_TAC(REWRITE_RULE[INSERT_AC; COLLINEAR_2]) THEN
+        FIRST_X_ASSUM CONTR_TAC) THEN
+    UNDISCH_TAC `~collinear {vec 0:real^3, basis 3, v1 % basis 3}` THEN
+    REWRITE_TAC[COLLINEAR_LEMMA] THEN MESON_TAC[];
+    DISCH_THEN SUBST1_TAC] THEN
+  REWRITE_TAC[AZIM_ARG] THEN CONV_TAC(LAND_CONV SYM_CONV) THEN
+  CONV_TAC(LAND_CONV SYM_CONV) THEN REWRITE_TAC[ARG_EQ_PI] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+  `(dropout 3 (w:real^3)) IN aff_lt {vec 0:real^2} {dropout 3 (x:real^3)}` THEN
+  CONJ_TAC THENL
+   [REPEAT(POP_ASSUM MP_TAC) THEN REWRITE_TAC[COLLINEAR_BASIS_3] THEN
+    SPEC_TAC(`(dropout 3:real^3->real^2) x`,`y:complex`) THEN
+    SPEC_TAC(`(dropout 3:real^3->real^2) w`,`v:complex`) THEN
+    GEOM_BASIS_MULTIPLE_TAC 1 `v:complex` THEN
+    X_GEN_TAC `v:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+    ASM_CASES_TAC `v = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+    REWRITE_TAC[COMPLEX_CMUL; COMPLEX_BASIS; COMPLEX_VEC_0] THEN
+    SIMP_TAC[ARG_DIV_CX; COMPLEX_MUL_RID] THEN
+    REWRITE_TAC[real; RE_DIV_CX; IM_DIV_CX; CX_INJ] THEN
+    ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_EQ_LDIV_EQ; REAL_MUL_LZERO] THEN
+    REPEAT STRIP_TAC THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) AFF_LT_1_1 o rand o rand o snd) THEN
+    ASM_REWRITE_TAC[DISJOINT_INSERT; DISJOINT_EMPTY; IN_SING] THEN
+    DISCH_THEN SUBST1_TAC THEN
+    REWRITE_TAC[COMPLEX_CMUL; IN_ELIM_THM; COMPLEX_MUL_RZERO] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    REWRITE_TAC[REAL_ARITH `t1 + t2 = &1 <=> t1 = &1 - t2`] THEN
+    REWRITE_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM2; COMPLEX_ADD_LID] THEN
+    EQ_TAC THENL
+     [REWRITE_TAC[GSYM real; REAL] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 (SUBST1_TAC o SYM) ASSUME_TAC) THEN
+      EXISTS_TAC `v / Re y` THEN REWRITE_TAC[GSYM CX_MUL; CX_INJ] THEN
+      CONJ_TAC THENL
+       [ALL_TAC; REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD];
+      DISCH_THEN(X_CHOOSE_THEN `t:real`
+       (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+      ASM_SIMP_TAC[CX_INJ; REAL_ARITH `x < &0 ==> ~(x = &0)`; COMPLEX_FIELD
+        `~(t = Cx(&0)) ==> (v = t * y <=> y = v / t)`] THEN
+      DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[GSYM CX_DIV] THEN
+      REWRITE_TAC[RE_CX; IM_CX]] THEN
+    REWRITE_TAC[REAL_ARITH `x < &0 <=> &0 < --x`] THEN
+    REWRITE_TAC[real_div; GSYM REAL_MUL_RNEG; GSYM REAL_INV_NEG] THEN
+    MATCH_MP_TAC REAL_LT_MUL THEN ASM_REWRITE_TAC[REAL_LT_INV_EQ] THEN
+    ASM_REAL_ARITH_TAC;
+    W(MP_TAC o PART_MATCH (lhs o rand) AFF_LT_2_1 o rand o rand o snd) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[SET_RULE `DISJOINT {a,b} {x} <=> ~(x = a) /\ ~(x = b)`] THEN
+      CONJ_TAC THEN DISCH_THEN SUBST_ALL_TAC THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[COLLINEAR_2; INSERT_AC]) THEN
+      FIRST_ASSUM CONTR_TAC;
+      DISCH_THEN SUBST1_TAC] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) AFF_LT_1_1 o rand o lhand o snd) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[SET_RULE `DISJOINT {a} {x} <=> ~(x = a)`] THEN
+      ASM_MESON_TAC[COLLINEAR_BASIS_3];
+      DISCH_THEN SUBST1_TAC] THEN
+    REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID; IN_ELIM_THM] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `s + t = &1 <=> s = &1- t`] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    REWRITE_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM2] THEN
+    GEN_REWRITE_TAC (RAND_CONV o BINDER_CONV) [SWAP_EXISTS_THM] THEN
+    REWRITE_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM2] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN AP_TERM_TAC THEN
+    REWRITE_TAC[FUN_EQ_THM; RIGHT_EXISTS_AND_THM] THEN X_GEN_TAC `t:real` THEN
+    AP_TERM_TAC THEN
+    SIMP_TAC[CART_EQ; FORALL_2; FORALL_3; DIMINDEX_2; DIMINDEX_3;
+             dropout; LAMBDA_BETA; BASIS_COMPONENT; ARITH; REAL_MUL_RID;
+             VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RZERO; UNWIND_THM1;
+             VECTOR_ADD_COMPONENT; REAL_ADD_LID; RIGHT_EXISTS_AND_THM] THEN
+    REWRITE_TAC[REAL_ARITH `x:real = t + y <=> t = x - y`] THEN
+    REWRITE_TAC[EXISTS_REFL]]);;
+
+let AZIM_EQ_PI_ALT = prove
+ (`!v0 v1 w x.
+        ~collinear{v0,v1,w} /\ ~collinear{v0,v1,x}
+        ==> (azim v0 v1 w x = pi <=> x IN aff_lt {v0,v1} {w})`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP AZIM_EQ_PI_SYM) THEN
+  ASM_SIMP_TAC[AZIM_EQ_PI]);;
+
+let AZIM_EQ_0_PI_IMP_COPLANAR = prove
+ (`!v0 v1 w1 w2.
+        azim v0 v1 w1 w2 = &0 \/ azim v0 v1 w1 w2 = pi
+        ==> coplanar {v0,v1,w1,w2}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `collinear {v0:real^3,v1,w1}` THENL
+   [MP_TAC(ISPECL [`v0:real^3`; `v1:real^3`; `w1:real^3`; `w2:real^3`]
+                NOT_COPLANAR_NOT_COLLINEAR) THEN
+    ASM_REWRITE_TAC[] THEN CONV_TAC TAUT;
+    POP_ASSUM MP_TAC] THEN
+  ASM_CASES_TAC `collinear {v0:real^3,v1,w2}` THENL
+   [MP_TAC(ISPECL [`v0:real^3`; `v1:real^3`; `w2:real^3`; `w1:real^3`]
+                NOT_COPLANAR_NOT_COLLINEAR) THEN
+    ASM_REWRITE_TAC[] THEN REWRITE_TAC[INSERT_AC] THEN CONV_TAC TAUT;
+    POP_ASSUM MP_TAC] THEN
+  MAP_EVERY (fun t -> SPEC_TAC(t,t))
+   [`w2:real^3`; `w1:real^3`; `v1:real^3`; `v0:real^3`] THEN
+  GEOM_ORIGIN_TAC `v0:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `v1:real^3` THEN
+  X_GEN_TAC `w:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `w = &0` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  SIMP_TAC[AZIM_SPECIAL_SCALE] THEN
+  ASM_SIMP_TAC[AZIM_ARG; COLLINEAR_SPECIAL_SCALE] THEN
+  REWRITE_TAC[COLLINEAR_BASIS_3; ARG_EQ_0_PI] THEN
+  REWRITE_TAC[real; IM_COMPLEX_DIV_EQ_0] THEN
+  REWRITE_TAC[complex_mul; cnj; IM; RE] THEN
+  REWRITE_TAC[REAL_ARITH `x * --y + a * b = &0 <=> x * y = a * b`] THEN
+  REWRITE_TAC[RE_DEF; IM_DEF] THEN DISCH_TAC THEN REPEAT GEN_TAC THEN
+  DISCH_TAC THEN DISCH_TAC THEN
+  SIMP_TAC[dropout; LAMBDA_BETA; DIMINDEX_3; ARITH; DIMINDEX_2] THEN
+  DISCH_TAC THEN REWRITE_TAC[coplanar] THEN
+  MAP_EVERY EXISTS_TAC [`vec 0:real^3`; `w % basis 3:real^3`; `w1:real^3`] THEN
+  ONCE_REWRITE_TAC[SET_RULE `{a,b,c,d} = d INSERT {a,b,c}`] THEN
+  ONCE_REWRITE_TAC[INSERT_SUBSET] THEN REWRITE_TAC[HULL_SUBSET] THEN
+  SIMP_TAC[AFFINE_HULL_EQ_SPAN; IN_INSERT; HULL_INC] THEN
+  REWRITE_TAC[SPAN_BREAKDOWN_EQ; SPAN_EMPTY; IN_SING] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_SUB_RZERO] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  SIMP_TAC[CART_EQ; DIMINDEX_2; FORALL_2; FORALL_3; dropout; LAMBDA_BETA;
+           DIMINDEX_2; DIMINDEX_3; ARITH; VEC_COMPONENT; ARITH;
+           VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT; BASIS_COMPONENT] THEN
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[REAL_MUL_RZERO; REAL_SUB_RZERO] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+  ASM_SIMP_TAC[EXISTS_REFL; REAL_FIELD
+   `&0 < w ==> (x - k * w * &1 - y = &0 <=> k = (x - y) / w)`] THEN
+  SUBGOAL_THEN `~((w1:real^3)$2 = &0) \/ ~((w2:real^3)$1 = &0)`
+  STRIP_ASSUME_TAC THENL
+   [REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_RING;
+    EXISTS_TAC `(w2:real^3)$2 / (w1:real^3)$2` THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD;
+    EXISTS_TAC `(w2:real^3)$1 / (w1:real^3)$1` THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD]);;
+
+let AZIM_SAME_WITHIN_AFF_GE = prove
+ (`!a u v w z.
+        v IN aff_ge {a} {u,w} /\ ~collinear{a,u,v} /\ ~collinear{a,u,w}
+        ==> azim a u v z = azim a u w z`,
+  GEOM_ORIGIN_TAC `a:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `u:real^3` THEN
+  X_GEN_TAC `u:real` THEN ASM_CASES_TAC `u = &0` THEN
+  ASM_SIMP_TAC[AZIM_DEGENERATE; VECTOR_MUL_LZERO; REAL_LE_LT] THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; COLLINEAR_SPECIAL_SCALE] THEN
+  DISCH_TAC THEN REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `w:real^3 = vec 0` THENL
+   [ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC]; ALL_TAC] THEN
+  ASM_SIMP_TAC[AFF_GE_SCALE_LEMMA] THEN
+  REWRITE_TAC[COLLINEAR_BASIS_3; AZIM_ARG] THEN
+  ASM_SIMP_TAC[AFF_GE_1_2_0; BASIS_NONZERO; ARITH; DIMINDEX_3;
+   SET_RULE `DISJOINT {a} {b,c} <=> ~(b = a) /\ ~(c = a)`] THEN
+  REWRITE_TAC[IMP_CONJ; LEFT_IMP_EXISTS_THM; IN_ELIM_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real`; `b:real`] THEN DISCH_TAC THEN DISCH_TAC THEN
+  DISCH_THEN(MP_TAC o AP_TERM `dropout 3:real^3->real^2`) THEN
+  REWRITE_TAC[DROPOUT_ADD; DROPOUT_MUL; DROPOUT_BASIS_3] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+  DISCH_THEN SUBST1_TAC THEN REPEAT DISCH_TAC THEN
+  REWRITE_TAC[COMPLEX_CMUL] THEN
+  REWRITE_TAC[complex_div; COMPLEX_INV_MUL; GSYM CX_INV] THEN
+  ONCE_REWRITE_TAC[COMPLEX_RING `a * b * c:complex = b * a * c`] THEN
+  MATCH_MP_TAC ARG_MUL_CX THEN REWRITE_TAC[REAL_LT_INV_EQ] THEN
+  ASM_REWRITE_TAC[REAL_LT_LE] THEN ASM_MESON_TAC[VECTOR_MUL_LZERO]);;
+
+let AZIM_SAME_WITHIN_AFF_GE_ALT = prove
+ (`!a u v w z.
+        v IN aff_ge {a} {u,w} /\ ~collinear{a,u,v} /\ ~collinear{a,u,w}
+        ==> azim a u z v = azim a u z w`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AZIM_SAME_WITHIN_AFF_GE) THEN
+  ASM_CASES_TAC `collinear {a:real^3,u,z}` THEN
+  ASM_SIMP_TAC[AZIM_DEGENERATE] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AZIM_COMPL o lhand o snd) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AZIM_COMPL o rand o snd) THEN
+  ASM_SIMP_TAC[]);;
+
+let COLLINEAR_WITHIN_AFF_GE_COLLINEAR = prove
+ (`!a u v w:real^N.
+        v IN aff_ge {a} {u,w} /\ collinear{a,u,w} ==> collinear{a,v,w}`,
+  GEOM_ORIGIN_TAC `a:real^N` THEN REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `w:real^N = vec 0` THENL
+   [ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC]; ALL_TAC] THEN
+  ASM_CASES_TAC `u:real^N = vec 0` THENL
+   [ONCE_REWRITE_TAC[AFF_GE_DISJOINT_DIFF] THEN
+    ASM_REWRITE_TAC[SET_RULE `{a} DIFF {a,b} = {}`] THEN
+    REWRITE_TAC[GSYM CONVEX_HULL_AFF_GE] THEN
+    ONCE_REWRITE_TAC[SET_RULE `{z,v,w} = {z,w,v}`] THEN
+    ASM_SIMP_TAC[COLLINEAR_3_AFFINE_HULL] THEN
+    MESON_TAC[CONVEX_HULL_SUBSET_AFFINE_HULL; SUBSET];
+    ONCE_REWRITE_TAC[SET_RULE `{z,v,w} = {z,w,v}`] THEN
+    ASM_REWRITE_TAC[COLLINEAR_LEMMA_ALT] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (X_CHOOSE_TAC `a:real`)) THEN
+    ASM_SIMP_TAC[AFF_GE_1_2_0; SET_RULE
+     `DISJOINT {a} {b,c} <=> ~(b = a) /\ ~(c = a)`] THEN
+    REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`b:real`; `c:real`] THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[GSYM VECTOR_ADD_RDISTRIB; VECTOR_MUL_ASSOC] THEN
+    MESON_TAC[]]);;
+
+let AZIM_EQ_IMP = prove
+ (`!v0 v1 w x y.
+     ~collinear {v0, v1, w} /\
+     ~collinear {v0, v1, y} /\
+     x IN aff_gt {v0, v1} {y}
+     ==> azim v0 v1 w x = azim v0 v1 w y`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `v1:real^3 = v0` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_CASES_TAC `collinear {v0:real^3,v1,x}` THENL
+   [ALL_TAC; ASM_SIMP_TAC[AZIM_EQ_ALT]] THEN
+  UNDISCH_TAC `collinear {v0:real^3,v1,x}` THEN
+  MATCH_MP_TAC(TAUT
+   `(s /\ p ==> r) ==> p ==> ~q /\ ~r /\ s ==> t`) THEN
+  ASM_SIMP_TAC[COLLINEAR_3_IN_AFFINE_HULL] THEN
+  ASM_CASES_TAC `y:real^3 = v0` THEN
+  ASM_SIMP_TAC[HULL_INC; IN_INSERT] THEN
+  ASM_CASES_TAC `y:real^3 = v1` THEN
+  ASM_SIMP_TAC[HULL_INC; IN_INSERT] THEN
+  ASM_SIMP_TAC[AFF_GT_2_1; SET_RULE
+   `DISJOINT {a,b} {c} <=> ~(c = a) /\ ~(c = b)`] THEN
+  REWRITE_TAC[AFFINE_HULL_2; IN_ELIM_THM; LEFT_AND_EXISTS_THM] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`t1:real`; `t2:real`; `t3:real`; `s1:real`; `s2:real`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o AP_TERM `(%) (inv t3) :real^3->real^3`) THEN
+  ASM_SIMP_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC; REAL_MUL_LINV;
+               REAL_LT_IMP_NZ; VECTOR_ARITH
+                `x:real^N = y + z + &1 % w <=> w = x - (y + z)`] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  EXISTS_TAC `inv t3 * s1 - inv t3 * t1:real` THEN
+  EXISTS_TAC `inv t3 * s2 - inv t3 * t2:real` THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[REAL_FIELD
+     `&0 < t ==> (inv t * a - inv t * b + inv t * c - inv t * d = &1 <=>
+                  (a + c) - (b + d) = t)`] THEN
+    ASM_REAL_ARITH_TAC;
+    VECTOR_ARITH_TAC]);;
+
+let AZIM_EQ_0_GE_IMP = prove
+ (`!v0 v1 w x. x IN aff_ge {v0, v1} {w} ==> azim v0 v1 w x = &0`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `collinear {v0:real^3,v1,w}` THEN
+  ASM_SIMP_TAC[AZIM_DEGENERATE] THEN
+  ASM_CASES_TAC `collinear {v0:real^3,v1,x}` THEN
+  ASM_SIMP_TAC[AZIM_DEGENERATE] THEN ASM_MESON_TAC[AZIM_EQ_0_GE_ALT]);;
+
+let REAL_SGN_SIN_AZIM = prove
+ (`!v w x y. real_sgn(sin(azim v w x y)) =
+             real_sgn(((w - v) cross (x - v)) dot (y - v))`,
+  GEOM_ORIGIN_TAC `v:real^3` THEN REWRITE_TAC[VECTOR_SUB_RZERO] THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `w:real^3` THEN
+  X_GEN_TAC `w:real` THEN ASM_CASES_TAC `w = &0` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LZERO; CROSS_LZERO; DOT_LZERO; REAL_SGN_0;
+                  AZIM_REFL_ALT; SIN_0] THEN
+  ASM_REWRITE_TAC[REAL_LE_LT] THEN REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; CROSS_LMUL; DOT_LMUL] THEN
+  REWRITE_TAC[REAL_SGN_MUL] THEN
+  GEN_REWRITE_TAC (RAND_CONV o LAND_CONV) [real_sgn] THEN
+  ASM_REWRITE_TAC[REAL_MUL_LID; AZIM_ARG] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `real_sgn(Im(dropout 3 (y:real^3) / dropout 3 (x:real^3)))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[REAL_SGN_IM_COMPLEX_DIV] THEN AP_TERM_TAC THEN
+    SIMP_TAC[CART_EQ; DIMINDEX_3; FORALL_3; cross; VECTOR_3; DOT_3; dropout;
+             LAMBDA_BETA; ARITH; cnj; complex_mul; RE_DEF; IM_DEF; DIMINDEX_2;
+             complex; VECTOR_2; BASIS_COMPONENT] THEN REAL_ARITH_TAC] THEN
+
+  SPEC_TAC(`(dropout 3:real^3->real^2) x`,`z:complex`) THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) y`,`w:complex`) THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN GEOM_BASIS_MULTIPLE_TAC 1 `z:complex` THEN
+  REWRITE_TAC[COMPLEX_CMUL; COMPLEX_BASIS; COMPLEX_MUL_RID] THEN
+  X_GEN_TAC `x:real` THEN DISCH_TAC THEN X_GEN_TAC `z:complex` THEN
+  ASM_CASES_TAC `x = &0` THENL
+   [ASM_REWRITE_TAC[complex_div; COMPLEX_INV_0; COMPLEX_MUL_RZERO] THEN
+    REWRITE_TAC[ARG_0; SIN_0; IM_CX; REAL_SGN_0];
+    SUBGOAL_THEN `&0 < x` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]] THEN
+  ASM_SIMP_TAC[ARG_DIV_CX; IM_DIV_CX; REAL_SGN_DIV] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [real_sgn] THEN
+  ASM_REWRITE_TAC[REAL_DIV_1] THEN ASM_CASES_TAC `z = Cx(&0)` THEN
+  ASM_REWRITE_TAC[IM_CX; ARG_0; SIN_0] THEN
+  GEN_REWRITE_TAC (funpow 3 RAND_CONV) [ARG] THEN
+  REWRITE_TAC[IM_MUL_CX; REAL_SGN_MUL] THEN
+  GEN_REWRITE_TAC (RAND_CONV o LAND_CONV) [real_sgn] THEN
+  ASM_REWRITE_TAC[COMPLEX_NORM_NZ; REAL_MUL_LID] THEN
+  REWRITE_TAC[IM_CEXP; RE_MUL_II; IM_MUL_II; RE_CX; REAL_SGN_MUL] THEN
+  GEN_REWRITE_TAC (RAND_CONV o LAND_CONV) [real_sgn] THEN
+  REWRITE_TAC[REAL_EXP_POS_LT; REAL_MUL_LID]);;
+
+let AZIM_IN_UPPER_HALFSPACE = prove
+ (`!v w x y. azim v w x y <= pi <=>
+             &0 <= ((w - v) cross (x - v)) dot (y - v)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `&0 <= sin(azim v w x y)` THEN CONJ_TAC THENL
+   [EQ_TAC THEN SIMP_TAC[SIN_POS_PI_LE; azim] THEN
+    MP_TAC(ISPEC `azim v w x y - pi` SIN_POS_PI) THEN
+    REWRITE_TAC[SIN_SUB; SIN_PI; COS_PI; azim;
+                REAL_ARITH `x - pi < pi <=> x < &2 * pi`] THEN
+    REAL_ARITH_TAC;
+    ONCE_REWRITE_TAC[GSYM REAL_SGN_INEQS] THEN
+    REWRITE_TAC[REAL_SGN_SIN_AZIM]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Dihedral angle and relation to azimuth angle.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let dihV = new_definition
+  `dihV w0 w1 w2 w3 =
+     let va = w2 - w0 in
+     let vb = w3 - w0 in
+     let vc = w1 - w0 in
+     let vap = ( vc dot vc) % va - ( va dot vc) % vc in
+     let vbp = ( vc dot vc) % vb - ( vb dot vc) % vc in
+     arcV (vec 0) vap vbp`;;
+
+let DIHV = prove
+ (`dihV (w0:real^N) w1 w2 w3 =
+     let va = w2 - w0 in
+     let vb = w3 - w0 in
+     let vc = w1 - w0 in
+     let vap = (vc dot vc) % va - (va dot vc) % vc in
+     let vbp = (vc dot vc) % vb - (vb dot vc) % vc in
+     angle(vap,vec 0,vbp)`,
+  REWRITE_TAC[dihV; ARCV_ANGLE]);;
+
+let DIHV_TRANSLATION_EQ = prove
+ (`!a w0 w1 w2 w3:real^N.
+        dihV (a + w0) (a + w1) (a + w2) (a + w3) = dihV w0 w1 w2 w3`,
+  REWRITE_TAC[DIHV; VECTOR_ARITH `(a + x) - (a + y):real^N = x - y`]);;
+
+add_translation_invariants [DIHV_TRANSLATION_EQ];;
+
+let DIHV_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N w0 w1 w2 w3.
+        linear f /\ (!x. norm(f x) = norm x)
+        ==> dihV (f w0) (f w1) (f w2) (f w3) = dihV w0 w1 w2 w3`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[DIHV] THEN
+  ASM_SIMP_TAC[GSYM LINEAR_SUB] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  ASM_SIMP_TAC[PRESERVES_NORM_PRESERVES_DOT] THEN
+  ASM_SIMP_TAC[GSYM LINEAR_CMUL; GSYM LINEAR_SUB] THEN
+  REWRITE_TAC[angle; VECTOR_SUB_RZERO] THEN
+  ASM_SIMP_TAC[VECTOR_ANGLE_LINEAR_IMAGE_EQ]);;
+
+add_linear_invariants [DIHV_LINEAR_IMAGE];;
+
+let DIHV_SPECIAL_SCALE = prove
+ (`!a v w1 w2:real^N.
+        ~(a = &0)
+        ==> dihV (vec 0) (a % v) w1 w2 = dihV (vec 0) v w1 w2`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[DIHV; VECTOR_SUB_RZERO] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  REWRITE_TAC[DOT_LMUL; DOT_RMUL; GSYM VECTOR_MUL_ASSOC] THEN
+  REWRITE_TAC[VECTOR_ARITH `a % a % x - a % b % a % y:real^N =
+                            (a * a) % (x - b % y)`] THEN
+  REWRITE_TAC[angle; VECTOR_SUB_RZERO] THEN
+  REWRITE_TAC[VECTOR_ANGLE_LMUL; VECTOR_ANGLE_RMUL] THEN
+  ASM_REWRITE_TAC[REAL_LE_SQUARE; REAL_ENTIRE]);;
+
+let DIHV_RANGE = prove
+ (`!w0 w1 w2 w3. &0 <= dihV w0 w1 w2 w3 /\ dihV w0 w1 w2 w3 <= pi`,
+  REWRITE_TAC[DIHV] THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  REWRITE_TAC[ANGLE_RANGE]);;
+
+let COS_AZIM_DIHV = prove
+ (`!v w v1 v2:real^3.
+        ~collinear {v,w,v1} /\ ~collinear {v,w,v2}
+        ==> cos(azim v w v1 v2) = cos(dihV v w v1 v2)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `w:real^3 = v` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; POP_ASSUM MP_TAC] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  GEOM_ORIGIN_TAC `v:real^3` THEN GEOM_BASIS_MULTIPLE_TAC 3 `w:real^3` THEN
+  X_GEN_TAC `w:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `w = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; DIHV_SPECIAL_SCALE; REAL_LT_IMP_NZ;
+               COLLINEAR_SPECIAL_SCALE; COLLINEAR_BASIS_3] THEN
+  DISCH_TAC THEN POP_ASSUM_LIST(K ALL_TAC) THEN
+  MAP_EVERY X_GEN_TAC [`w1:real^3`; `w2:real^3`] THEN
+  DISCH_THEN(STRIP_ASSUME_TAC o CONJUNCT2) THEN
+  REWRITE_TAC[DIHV; VECTOR_SUB_RZERO] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  SIMP_TAC[DOT_BASIS_BASIS; DIMINDEX_3; ARITH] THEN
+  SIMP_TAC[DOT_BASIS; DIMINDEX_3; ARITH; VECTOR_MUL_LID] THEN
+  MP_TAC(ISPECL [`vec 0:real^3`; `basis 3:real^3`; `w1:real^3`; `w2:real^3`]
+        azim) THEN
+  ABBREV_TAC `a = azim (vec 0) (basis 3) w1 (w2:real^3)` THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; VECTOR_SUB_RZERO; DIST_0] THEN
+  MAP_EVERY X_GEN_TAC [`h1:real`; `h2:real`] THEN
+  DISCH_THEN(MP_TAC o SPECL
+   [`basis 1:real^3`; `basis 2:real^3`; `basis 3:real^3`]) THEN
+  SIMP_TAC[orthonormal; DOT_BASIS_BASIS; CROSS_BASIS; DIMINDEX_3; NORM_BASIS;
+    ARITH; VECTOR_MUL_LID; BASIS_NONZERO; REAL_LT_01; LEFT_IMP_EXISTS_THM] THEN
+  ASM_REWRITE_TAC[COLLINEAR_BASIS_3] THEN
+  MAP_EVERY X_GEN_TAC [`psi:real`; `r1:real`; `r2:real`] THEN
+  DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THEN
+  REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  SIMP_TAC[BASIS_COMPONENT; DIMINDEX_3; ARITH; REAL_MUL_RZERO] THEN
+  REWRITE_TAC[REAL_MUL_RID; REAL_ADD_LID] THEN
+  REWRITE_TAC[VECTOR_ARITH `(a + b + c) - c:real^N = a + b`] THEN
+  REWRITE_TAC[COS_ANGLE; VECTOR_SUB_RZERO] THEN
+  REWRITE_TAC[vector_norm; GSYM DOT_EQ_0; DIMINDEX_3; FORALL_3; DOT_3] THEN
+  REWRITE_TAC[VEC_COMPONENT; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  SIMP_TAC[BASIS_COMPONENT; DIMINDEX_3; ARITH; REAL_MUL_RZERO] THEN
+  REWRITE_TAC[REAL_MUL_RID; REAL_ADD_LID; REAL_ADD_RID; REAL_MUL_RZERO] THEN
+  REWRITE_TAC[REAL_ARITH `(r * c) * (r * c) + (r * s) * (r * s):real =
+                          r pow 2 * (s pow 2 + c pow 2)`] THEN
+  ASM_SIMP_TAC[SIN_CIRCLE; REAL_MUL_RID; REAL_POW_EQ_0; REAL_LT_IMP_NZ] THEN
+  ASM_SIMP_TAC[POW_2_SQRT; REAL_LT_IMP_LE] THEN
+  REWRITE_TAC[REAL_ARITH `(r1 * c1) * (r2 * c2) + (r1 * s1) * (r2 * s2):real =
+                          (r1 * r2) * (c1 * c2 + s1 * s2)`] THEN
+  ASM_SIMP_TAC[REAL_FIELD
+   `&0 < r1 /\ &0 < r2 ==> ((r1 * r2) * x) / (r1 * r2) = x`] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a:real = b + c * d <=> b - --c * d = a`] THEN
+  GEN_REWRITE_TAC (funpow 3 LAND_CONV) [GSYM COS_NEG] THEN
+  REWRITE_TAC[GSYM SIN_NEG; GSYM COS_ADD] THEN AP_TERM_TAC THEN
+  REAL_ARITH_TAC);;
+
+let AZIM_DIHV_SAME = prove
+ (`!v w v1 v2:real^3.
+        ~collinear {v,w,v1} /\ ~collinear {v,w,v2} /\
+        azim v w v1 v2 < pi
+        ==> azim v w v1 v2 = dihV v w v1 v2`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC COS_INJ_PI THEN
+  ASM_SIMP_TAC[COS_AZIM_DIHV; azim; REAL_LT_IMP_LE; DIHV_RANGE]);;
+
+let AZIM_DIHV_COMPL = prove
+ (`!v w v1 v2:real^3.
+        ~collinear {v,w,v1} /\ ~collinear {v,w,v2} /\
+        pi <= azim v w v1 v2
+        ==> azim v w v1 v2 = &2 * pi - dihV v w v1 v2`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `x = &2 * pi - y <=> y = &2 * pi - x`] THEN
+  MATCH_MP_TAC COS_INJ_PI THEN
+  REWRITE_TAC[COS_SUB; SIN_NPI; COS_NPI; REAL_MUL_LZERO] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  ASM_SIMP_TAC[COS_AZIM_DIHV; REAL_ADD_RID; REAL_MUL_LID] THEN
+  ASM_REWRITE_TAC[DIHV_RANGE] THEN MATCH_MP_TAC(REAL_ARITH
+   `p <= x /\ x < &2 * p ==> &0 <= &2 * p - x /\ &2 * p - x <= p`) THEN
+  ASM_SIMP_TAC[azim]);;
+
+let AZIM_DIVH = prove
+ (`!v w v1 v2:real^3.
+        ~collinear {v,w,v1} /\ ~collinear {v,w,v2}
+        ==> azim v w v1 v2 = if azim v w v1 v2 < pi then dihV v w v1 v2
+                             else &2 * pi - dihV v w v1 v2`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LT]) THEN
+  ASM_SIMP_TAC[AZIM_DIHV_SAME; AZIM_DIHV_COMPL]);;
+
+let AZIM_DIHV_EQ_0 = prove
+ (`!v0 v1 w1 w2.
+        ~collinear {v0,v1,w1} /\ ~collinear {v0,v1,w2}
+        ==> (azim v0 v1 w1 w2 = &0 <=> dihV v0 v1 w1 w2 = &0)`,
+  REPEAT STRIP_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AZIM_DIVH o lhs o lhs o snd) THEN
+  ASM_REWRITE_TAC[] THEN COND_CASES_TAC THEN ASM_SIMP_TAC[] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a:real = p - b <=> b = p - a`] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[REAL_ARITH `&2 * p - (&2 * p - a) = &0 <=> a = &0`] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `a < &2 * pi /\ ~(a < pi) ==> (a = &0 <=> &2 * pi - a = &0)`) THEN
+  ASM_REWRITE_TAC[azim]);;
+
+let AZIM_DIHV_EQ_PI = prove
+ (`!v0 v1 w1 w2.
+        ~collinear {v0,v1,w1} /\ ~collinear {v0,v1,w2}
+        ==> (azim v0 v1 w1 w2 = pi <=> dihV v0 v1 w1 w2 = pi)`,
+  REPEAT STRIP_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AZIM_DIVH o lhs o lhs o snd) THEN
+  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let AZIM_EQ_0_PI_EQ_COPLANAR = prove
+ (`!v0 v1 w1 w2.
+        ~collinear {v0,v1,w1} /\ ~collinear {v0,v1,w2}
+        ==> (azim v0 v1 w1 w2 = &0 \/ azim v0 v1 w1 w2 = pi <=>
+             coplanar {v0,v1,w1,w2})`,
+  REWRITE_TAC[TAUT `(a <=> b) <=> (a ==> b) /\ (b ==> a)`] THEN
+  REWRITE_TAC[AZIM_EQ_0_PI_IMP_COPLANAR] THEN
+  SIMP_TAC[GSYM IMP_CONJ_ALT; COPLANAR; DIMINDEX_3; ARITH] THEN
+  REWRITE_TAC[IMP_CONJ; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`v0:real^3`; `v1:real^3`; `v2:real^3`; `v3:real^3`; `p:real^3->bool`] THEN
+  GEOM_HORIZONTAL_PLANE_TAC `p:real^3->bool` THEN
+  REWRITE_TAC[INSERT_SUBSET; IN_ELIM_THM; IMP_CONJ; RIGHT_FORALL_IMP_THM;
+              EMPTY_SUBSET] THEN
+  SIMP_TAC[AZIM_DIHV_EQ_0; AZIM_DIHV_EQ_PI] THEN
+  REWRITE_TAC[DIHV] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  DISCH_THEN(K ALL_TAC) THEN PAD2D3D_TAC THEN
+  REWRITE_TAC[angle; VECTOR_SUB_RZERO] THEN
+  GEOM_ORIGIN_TAC `v0:real^2` THEN REWRITE_TAC[VECTOR_SUB_RZERO] THEN
+  REPEAT STRIP_TAC THEN
+  W(MP_TAC o PART_MATCH (rand o rand) COLLINEAR_VECTOR_ANGLE o snd) THEN
+  ANTS_TAC THENL
+   [REPEAT(POP_ASSUM MP_TAC); DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  REWRITE_TAC[GSYM DOT_CAUCHY_SCHWARZ_EQUAL] THEN
+  REWRITE_TAC[DOT_2; CART_EQ; FORALL_2; DIMINDEX_2; VEC_COMPONENT;
+              VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  CONV_TAC REAL_RING);;
+
+let DIHV_EQ_0_PI_EQ_COPLANAR = prove
+ (`!v0 v1 w1 w2:real^3.
+        ~collinear {v0,v1,w1} /\ ~collinear {v0,v1,w2}
+        ==> (dihV v0 v1 w1 w2 = &0 \/ dihV v0 v1 w1 w2 = pi <=>
+             coplanar {v0,v1,w1,w2})`,
+  SIMP_TAC[GSYM AZIM_DIHV_EQ_0; GSYM AZIM_DIHV_EQ_PI;
+           AZIM_EQ_0_PI_EQ_COPLANAR]);;
+
+let DIHV_SYM = prove
+ (`!v0 v1 v2 v3:real^N.
+        dihV v0 v1 v3 v2 = dihV v0 v1 v2 v3`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[DIHV] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  REWRITE_TAC[DOT_SYM; ANGLE_SYM]);;
+
+let DIHV_NEG = prove
+ (`!v0 v1 v2 v3. dihV (--v0) (--v1) (--v2) (--v3) = dihV v0 v1 v2 v3`,
+  REWRITE_TAC[DIHV; VECTOR_ARITH `--a - --b:real^N = --(a - b)`] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  REWRITE_TAC[DOT_RNEG; DOT_LNEG; REAL_NEG_NEG] THEN
+  REWRITE_TAC[VECTOR_MUL_RNEG] THEN
+  REWRITE_TAC[angle; VECTOR_ARITH `--a - --b:real^N = --(a - b)`] THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; VECTOR_ANGLE_NEG2]);;
+
+let DIHV_NEG_0 = prove
+ (`!v1 v2 v3. dihV (vec 0) (--v1) (--v2) (--v3) = dihV (vec 0) v1 v2 v3`,
+  REPEAT GEN_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM DIHV_NEG] THEN
+  REWRITE_TAC[VECTOR_NEG_0]);;
+
+let DIHV_ARCV = prove
+ (`!e u v w:real^N.
+      orthogonal (e - u) (v - u) /\ orthogonal (e - u) (w - u) /\ ~(e = u)
+      ==> dihV u e v w = arcV u v w`,
+  GEOM_ORIGIN_TAC `u:real^N` THEN
+  REWRITE_TAC[dihV; orthogonal; VECTOR_SUB_RZERO] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  SIMP_TAC[DOT_SYM; VECTOR_MUL_LZERO; VECTOR_SUB_RZERO] THEN
+  REWRITE_TAC[ARCV_ANGLE; angle; VECTOR_SUB_RZERO] THEN
+  REWRITE_TAC[VECTOR_ANGLE_LMUL; VECTOR_ANGLE_RMUL] THEN
+  SIMP_TAC[DOT_POS_LE; DOT_EQ_0]);;
+
+let AZIM_DIHV_SAME_STRONG = prove
+ (`!v w v1 v2:real^3.
+        ~collinear {v,w,v1} /\ ~collinear {v,w,v2} /\
+        azim v w v1 v2 <= pi
+        ==> azim v w v1 v2 = dihV v w v1 v2`,
+  REWRITE_TAC[REAL_LE_LT] THEN
+  MESON_TAC[AZIM_DIHV_SAME; AZIM_DIHV_EQ_PI]);;
+
+let AZIM_ARCV = prove
+ (`!e u v w:real^3.
+        orthogonal (e - u) (v - u) /\ orthogonal (e - u) (w - u) /\
+        ~collinear{u,e,v} /\ ~collinear{u,e,w} /\
+        azim u e v w <= pi
+        ==> azim u e v w = arcV u v w`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `u:real^3 = e` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[GSYM DIHV_ARCV] THEN
+  MATCH_MP_TAC AZIM_DIHV_SAME_STRONG THEN ASM_REWRITE_TAC[]);;
+
+let COLLINEAR_AZIM_0_OR_PI = prove
+ (`!u e v w. collinear {u,v,w} ==> azim u e v w = &0 \/ azim u e v w = pi`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `collinear{u:real^3,e,v}` THEN
+  ASM_SIMP_TAC[AZIM_DEGENERATE] THEN
+  ASM_CASES_TAC `collinear{u:real^3,e,w}` THEN
+  ASM_SIMP_TAC[AZIM_DEGENERATE] THEN
+  ASM_SIMP_TAC[AZIM_EQ_0_PI_EQ_COPLANAR] THEN
+  ONCE_REWRITE_TAC[SET_RULE `{u,e,v,w} = {u,v,w,e}`] THEN
+  ASM_MESON_TAC[NOT_COPLANAR_NOT_COLLINEAR]);;
+
+let REAL_CONTINUOUS_WITHIN_DIHV_COMPOSE = prove
+ (`!f:real^M->real^N g h k x s.
+      ~collinear {f x,g x,h x} /\ ~collinear {f x,g x,k x} /\
+      f continuous (at x within s) /\ g continuous (at x within s) /\
+      h continuous (at x within s) /\ k continuous (at x within s)
+      ==> (\x. dihV (f x) (g x) (h x) (k x)) real_continuous (at x within s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[dihV] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  REWRITE_TAC[ARCV_ANGLE; angle; REAL_CONTINUOUS_CONTINUOUS; o_DEF] THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO] THEN
+  MATCH_MP_TAC CONTINUOUS_WITHIN_CX_VECTOR_ANGLE_COMPOSE THEN
+  ASM_REWRITE_TAC[VECTOR_SUB_EQ; GSYM COLLINEAR_3_DOT_MULTIPLES] THEN
+  CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_SUB THEN CONJ_TAC THEN
+  MATCH_MP_TAC CONTINUOUS_MUL THEN REWRITE_TAC[o_DEF] THEN
+  ASM_SIMP_TAC[CONTINUOUS_LIFT_DOT2; o_DEF; CONTINUOUS_SUB]);;
+
+let REAL_CONTINUOUS_AT_DIHV_COMPOSE = prove
+ (`!f:real^M->real^N g h k x.
+      ~collinear {f x,g x,h x} /\ ~collinear {f x,g x,k x} /\
+      f continuous (at x) /\ g continuous (at x) /\
+      h continuous (at x) /\ k continuous (at x)
+      ==> (\x. dihV (f x) (g x) (h x) (k x)) real_continuous (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_WITHIN_DIHV_COMPOSE]);;
+
+let REAL_CONTINUOUS_WITHINREAL_DIHV_COMPOSE = prove
+ (`!f:real->real^N g h k x s.
+      ~collinear {f x,g x,h x} /\ ~collinear {f x,g x,k x} /\
+      f continuous (atreal x within s) /\ g continuous (atreal x within s) /\
+      h continuous (atreal x within s) /\ k continuous (atreal x within s)
+      ==> (\x. dihV (f x) (g x) (h x) (k x)) real_continuous
+          (atreal x within s)`,
+  REWRITE_TAC[CONTINUOUS_CONTINUOUS_WITHINREAL;
+              REAL_CONTINUOUS_REAL_CONTINUOUS_WITHINREAL] THEN
+  SIMP_TAC[o_DEF; REAL_CONTINUOUS_WITHIN_DIHV_COMPOSE; LIFT_DROP]);;
+
+let REAL_CONTINUOUS_ATREAL_DIHV_COMPOSE = prove
+ (`!f:real->real^N g h k x.
+      ~collinear {f x,g x,h x} /\ ~collinear {f x,g x,k x} /\
+      f continuous (atreal x) /\ g continuous (atreal x) /\
+      h continuous (atreal x) /\ k continuous (atreal x)
+      ==> (\x. dihV (f x) (g x) (h x) (k x)) real_continuous (atreal x)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_WITHINREAL_DIHV_COMPOSE]);;
+
+let REAL_CONTINUOUS_AT_DIHV = prove
+ (`!v w w1 w2:real^N.
+        ~collinear {v, w, w2} ==> dihV v w w1 real_continuous at w2`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN
+  REWRITE_TAC[dihV] THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC REAL_CONTINUOUS_CONTINUOUS_AT_COMPOSE THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_SUB THEN CONJ_TAC THEN
+    MATCH_MP_TAC CONTINUOUS_MUL THEN
+    SIMP_TAC[CONTINUOUS_CONST; o_DEF; CONTINUOUS_SUB; CONTINUOUS_AT_ID;
+             CONTINUOUS_LIFT_DOT2];
+    GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN
+    REWRITE_TAC[ARCV_ANGLE; angle] THEN
+    REWRITE_TAC[VECTOR_SUB_RZERO; ETA_AX] THEN
+    MATCH_MP_TAC REAL_CONTINUOUS_WITHIN_VECTOR_ANGLE THEN
+    POP_ASSUM MP_TAC THEN GEOM_ORIGIN_TAC `v:real^N` THEN
+    REWRITE_TAC[VECTOR_SUB_RZERO; CONTRAPOS_THM; VECTOR_SUB_EQ] THEN
+    MAP_EVERY X_GEN_TAC [`z:real^N`; `w:real^N`] THEN
+    ASM_CASES_TAC `w:real^N = vec 0` THEN
+    ASM_REWRITE_TAC[COLLINEAR_LEMMA_ALT] THEN DISCH_THEN(MP_TAC o AP_TERM
+     `(%) (inv((w:real^N) dot w)):real^N->real^N`) THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; DOT_EQ_0] THEN
+    MESON_TAC[VECTOR_MUL_LID]]);;
+
+let REAL_CONTINUOUS_WITHIN_AZIM_COMPOSE = prove
+ (`!f:real^M->real^3 g h k x s.
+      ~collinear {f x,g x,h x} /\ ~collinear {f x,g x,k x} /\
+      ~(k x IN aff_ge {f x,g x} {h x}) /\
+      f continuous (at x within s) /\ g continuous (at x within s) /\
+      h continuous (at x within s) /\ k continuous (at x within s)
+      ==> (\x. azim (f x) (g x) (h x) (k x)) real_continuous (at x within s)`,
+  let lemma = prove
+   (`!s t u f:real^M->real^N g h.
+          (closed s /\ closed t) /\ s UNION t = UNIV /\
+          (g continuous_on (u INTER s) /\ h continuous_on (u INTER t)) /\
+          (!x. x IN u INTER s ==> g x = f x) /\
+          (!x. x IN u INTER t ==> h x = f x)
+          ==> f continuous_on u`,
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `u:real^M->bool = (u INTER s) UNION (u INTER t)`
+    SUBST1_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_UNION_LOCAL THEN
+    REWRITE_TAC[CLOSED_IN_CLOSED] THEN REPEAT CONJ_TAC THENL
+     [EXISTS_TAC `s:real^M->bool` THEN ASM SET_TAC[];
+      EXISTS_TAC `t:real^M->bool` THEN ASM SET_TAC[];
+      ASM_MESON_TAC[CONTINUOUS_ON_EQ];
+      ASM_MESON_TAC[CONTINUOUS_ON_EQ]]) in
+  REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS; o_DEF] THEN
+  SUBGOAL_THEN
+   `(\x:real^M. Cx(azim (f x) (g x) (h x) (k x))) =
+    (\z. Cx(azim (vec 0) (fstcart z)
+                 (fstcart(sndcart z)) (sndcart(sndcart z)))) o
+    (\x. pastecart (g x - f x) (pastecart (h x - f x) (k x - f x)))`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[FUN_EQ_THM; o_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    X_GEN_TAC `y:real^M` THEN
+    SUBST1_TAC(VECTOR_ARITH `vec 0 = (f:real^M->real^3) y - f y`) THEN
+    SIMP_TAC[ONCE_REWRITE_RULE[VECTOR_ADD_SYM] AZIM_TRANSLATION; VECTOR_SUB];
+    MATCH_MP_TAC CONTINUOUS_WITHIN_COMPOSE THEN
+    ASM_SIMP_TAC[CONTINUOUS_PASTECART; CONTINUOUS_SUB]] THEN
+  MATCH_MP_TAC CONTINUOUS_AT_WITHIN THEN
+  SUBGOAL_THEN
+   `!z. ~collinear {vec 0,fstcart z,fstcart(sndcart z)} /\
+        ~collinear {vec 0,fstcart z,sndcart(sndcart z)} /\
+        ~(sndcart(sndcart z) IN aff_ge {vec 0,fstcart z} {fstcart(sndcart z)})
+        ==> (\z. Cx(azim (vec 0) (fstcart z) (fstcart(sndcart z))
+                                             (sndcart(sndcart z))))
+            continuous (at z)`
+  MATCH_MP_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART; GSYM COLLINEAR_3] THEN
+    REPEAT(CONJ_TAC THENL [ASM_MESON_TAC[INSERT_AC]; ALL_TAC]) THEN
+    SUBST1_TAC(VECTOR_ARITH `vec 0 = (f:real^M->real^3) x - f x`) THEN
+    ONCE_REWRITE_TAC[SET_RULE `{a,b} = {a} UNION {b}`] THEN
+    REWRITE_TAC[GSYM IMAGE_UNION; SET_RULE
+     `{a - b:real^3} = IMAGE (\x. x - b) {a}`] THEN
+    REWRITE_TAC[ONCE_REWRITE_RULE[VECTOR_ADD_SYM] AFF_GE_TRANSLATION;
+                VECTOR_SUB] THEN
+    ASM_REWRITE_TAC[IN_IMAGE; VECTOR_ARITH `a + x:real^3 = b + x <=> a = b`;
+                    UNWIND_THM1; SET_RULE `{a} UNION {b} = {a,b}`]] THEN
+  ONCE_REWRITE_TAC[SET_RULE
+   `(!x. ~P x /\ ~Q x /\ ~R x ==> J x) <=>
+    (!x. x IN UNIV DIFF (({x | P x} UNION {x | Q x}) UNION {x | R x})
+         ==> J x)`] THEN
+  MATCH_MP_TAC(MESON[CONTINUOUS_ON_EQ_CONTINUOUS_AT]
+   `open s /\ f continuous_on s ==> !z. z IN s ==> f continuous at z`) THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[GSYM closed] THEN
+    MATCH_MP_TAC(MESON[]
+     `!t'. s UNION t = s UNION t' /\ closed(s UNION t')
+           ==> closed(s UNION t)`) THEN
+    EXISTS_TAC
+      `{z | (fstcart z cross fstcart(sndcart z)) cross
+             fstcart z cross sndcart(sndcart z) = vec 0 /\
+            &0 <= (fstcart z cross sndcart(sndcart z)) dot
+                  (fstcart z cross fstcart(sndcart z))}` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC(SET_RULE
+       `(!x. ~(x IN s) ==> (x IN t <=> x IN t'))
+        ==> s UNION t = s UNION t'`) THEN
+      REWRITE_TAC[AFF_GE_2_1_0_SEMIALGEBRAIC; IN_UNION; IN_ELIM_THM;
+                  DE_MORGAN_THM];
+      ALL_TAC] THEN
+    MATCH_MP_TAC CLOSED_UNION THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CLOSED_UNION THEN CONJ_TAC THEN
+      REWRITE_TAC[GSYM DOT_CAUCHY_SCHWARZ_EQUAL] THEN
+      ONCE_REWRITE_TAC[GSYM REAL_SUB_0] THEN
+      REWRITE_TAC[GSYM LIFT_EQ; LIFT_NUM] THEN
+      SIMP_TAC[SET_RULE `{x | f x = a} = {x | x IN UNIV /\ f x IN {a}}`] THEN
+      MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE THEN
+      SIMP_TAC[CLOSED_UNIV; CLOSED_SING; LIFT_SUB; REAL_POW_2; LIFT_CMUL] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+      CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+      REWRITE_TAC[o_DEF] THEN REPEAT CONJ_TAC THEN
+      MATCH_MP_TAC CONTINUOUS_ON_LIFT_DOT2 THEN CONJ_TAC;
+      ONCE_REWRITE_TAC[MESON[LIFT_DROP; real_ge]
+       `&0 <= x <=> drop(lift x) >= &0`] THEN
+      REWRITE_TAC[SET_RULE
+       `{z | f z = vec 0 /\ drop(g z) >= &0} =
+        {z | z IN UNIV /\ f z IN {vec 0}} INTER
+        {z | z IN UNIV /\ g z IN {k | drop(k) >= &0}}`] THEN
+      MATCH_MP_TAC CLOSED_INTER THEN
+      CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE THEN
+      REWRITE_TAC[CLOSED_SING; drop; CLOSED_UNIV;
+                  CLOSED_HALFSPACE_COMPONENT_GE] THEN
+      REPEAT((MATCH_MP_TAC CONTINUOUS_ON_CROSS ORELSE
+              MATCH_MP_TAC CONTINUOUS_ON_LIFT_DOT2) THEN CONJ_TAC)] THEN
+    TRY(GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF]) THEN
+    SIMP_TAC[CONTINUOUS_ON_COMPOSE; LINEAR_CONTINUOUS_ON;
+             LINEAR_FSTCART; LINEAR_SNDCART];
+    MATCH_MP_TAC lemma THEN
+    MAP_EVERY EXISTS_TAC
+     [`{z | z IN UNIV /\ lift((fstcart z cross (fstcart(sndcart z))) dot
+                              (sndcart(sndcart z))) IN {x | x$1 >= &0}}`;
+      `{z | z IN UNIV /\ lift((fstcart z cross (fstcart(sndcart z))) dot
+                              (sndcart(sndcart z))) IN {x | x$1 <= &0}}`;
+      `\z. Cx(dihV (vec 0:real^3) (fstcart z)
+                   (fstcart(sndcart z)) (sndcart(sndcart z)))`;
+      `\z. Cx(&2 * pi - dihV (vec 0:real^3) (fstcart z)
+                             (fstcart(sndcart z)) (sndcart(sndcart z)))`] THEN
+    CONJ_TAC THENL
+     [CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE THEN
+      REWRITE_TAC[CLOSED_UNIV; CLOSED_HALFSPACE_COMPONENT_GE;
+                  CLOSED_HALFSPACE_COMPONENT_LE] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_LIFT_DOT2 THEN
+      (CONJ_TAC THENL [MATCH_MP_TAC CONTINUOUS_ON_CROSS; ALL_TAC]) THEN
+      ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+      SIMP_TAC[CONTINUOUS_ON_COMPOSE; LINEAR_CONTINUOUS_ON;
+               LINEAR_FSTCART; LINEAR_SNDCART];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[EXTENSION; IN_UNION; IN_UNIV; IN_ELIM_THM] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN
+      REWRITE_TAC[FORALL_PASTECART; IN_DIFF; IN_UNIV; IN_UNION; IN_INTER;
+        FSTCART_PASTECART; SNDCART_PASTECART; IN_ELIM_THM; DE_MORGAN_THM] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^3`; `y:real^3`; `z:real^3`] THEN
+      REPEAT STRIP_TAC THEN REWRITE_TAC[CX_SUB] THEN
+      TRY(MATCH_MP_TAC CONTINUOUS_SUB THEN REWRITE_TAC[CONTINUOUS_CONST]) THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      REWRITE_TAC[GSYM REAL_CONTINUOUS_CONTINUOUS] THEN
+      MATCH_MP_TAC REAL_CONTINUOUS_AT_DIHV_COMPOSE THEN
+      ASM_REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART;
+                      CONTINUOUS_CONST] THEN
+      ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+      SIMP_TAC[CONTINUOUS_AT_COMPOSE; LINEAR_CONTINUOUS_AT;
+               LINEAR_FSTCART; LINEAR_SNDCART];
+      ALL_TAC] THEN
+    REWRITE_TAC[FORALL_PASTECART; IN_DIFF; IN_UNIV; IN_UNION; IN_INTER; CX_INJ;
+        FSTCART_PASTECART; SNDCART_PASTECART; IN_ELIM_THM; DE_MORGAN_THM] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[GSYM drop; LIFT_DROP; real_ge] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^3`; `y:real^3`; `z:real^3`] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC(GSYM AZIM_DIHV_SAME_STRONG) THEN
+      ASM_REWRITE_TAC[AZIM_IN_UPPER_HALFSPACE; VECTOR_SUB_RZERO];
+      REWRITE_TAC[GSYM drop; LIFT_DROP] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^3`; `y:real^3`; `z:real^3`] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC(GSYM AZIM_DIHV_COMPL) THEN
+      ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `(x <= pi ==> x = pi) ==> pi <= x`) THEN
+      ASM_REWRITE_TAC[AZIM_IN_UPPER_HALFSPACE; VECTOR_SUB_RZERO] THEN
+      ASM_SIMP_TAC[REAL_ARITH `x <= &0 ==> (&0 <= x <=> x = &0)`] THEN
+      REWRITE_TAC[REWRITE_RULE[VECTOR_SUB_RZERO]
+         (SPEC `vec 0:real^3` (GSYM COPLANAR_CROSS_DOT))] THEN
+      ASM_SIMP_TAC[GSYM AZIM_EQ_0_PI_EQ_COPLANAR; AZIM_EQ_0_GE_ALT]]]);;
+
+let REAL_CONTINUOUS_AT_AZIM_COMPOSE = prove
+ (`!f:real^M->real^3 g h k x.
+      ~collinear {f x,g x,h x} /\ ~collinear {f x,g x,k x} /\
+      ~(k x IN aff_ge {f x,g x} {h x}) /\
+      f continuous (at x) /\ g continuous (at x) /\
+      h continuous (at x) /\ k continuous (at x)
+      ==> (\x. azim (f x) (g x) (h x) (k x)) real_continuous (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_WITHIN_AZIM_COMPOSE]);;
+
+let REAL_CONTINUOUS_WITHINREAL_AZIM_COMPOSE = prove
+ (`!f:real->real^3 g h k x s.
+      ~collinear {f x,g x,h x} /\ ~collinear {f x,g x,k x} /\
+      ~(k x IN aff_ge {f x,g x} {h x}) /\
+      f continuous (atreal x within s) /\ g continuous (atreal x within s) /\
+      h continuous (atreal x within s) /\ k continuous (atreal x within s)
+      ==> (\x. azim (f x) (g x) (h x) (k x)) real_continuous
+          (atreal x within s)`,
+  REWRITE_TAC[CONTINUOUS_CONTINUOUS_WITHINREAL;
+              REAL_CONTINUOUS_REAL_CONTINUOUS_WITHINREAL] THEN
+  SIMP_TAC[o_DEF; REAL_CONTINUOUS_WITHIN_AZIM_COMPOSE; LIFT_DROP]);;
+
+let REAL_CONTINUOUS_ATREAL_AZIM_COMPOSE = prove
+ (`!f:real->real^3 g h k x.
+      ~collinear {f x,g x,h x} /\ ~collinear {f x,g x,k x} /\
+      ~(k x IN aff_ge {f x,g x} {h x}) /\
+      f continuous (atreal x) /\ g continuous (atreal x) /\
+      h continuous (atreal x) /\ k continuous (atreal x)
+      ==> (\x. azim (f x) (g x) (h x) (k x)) real_continuous (atreal x)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_WITHINREAL_AZIM_COMPOSE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Can consider angle as defined by arcV a zenith angle.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let ZENITH_EXISTS = prove
+ (`!u v w:real^3.
+       ~(u = v) /\ ~(w = v)
+       ==> (?u' r phi e3.
+                phi = arcV v u w /\
+                r = dist(u,v) /\
+                dist(w,v) % e3 = w - v /\
+                u' dot e3 = &0 /\
+                u = v + u' + (r * cos phi) % e3)`,
+  ONCE_REWRITE_TAC[VECTOR_ARITH
+   `u:real^3 = v + u' + x <=> u - v = u' + x`] THEN
+  GEN_GEOM_ORIGIN_TAC `v:real^3` ["u'"; "e3"] THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; DIST_0] THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH
+   `u:real^3 = u' + x <=> u - u' = x`] THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `w:real^3` THEN
+  X_GEN_TAC `w:real` THEN ASM_CASES_TAC `w = &0` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LZERO; REAL_LE_LT] THEN DISCH_TAC THEN
+  SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_3; ARITH] THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 < w ==> abs w * &1 = w`] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_LCANCEL; REAL_LT_IMP_NZ] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM2] THEN
+  REWRITE_TAC[ARCV_ANGLE; angle; VECTOR_SUB_RZERO] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`u:real^3`; `w % basis 3:real^3`] VECTOR_ANGLE) THEN
+  REWRITE_TAC[DOT_RMUL; NORM_MUL] THEN
+  ASM_SIMP_TAC[REAL_ARITH
+   `&0 < w ==> n * ((abs w) * x) * y = w * n * x * y`] THEN
+  ASM_REWRITE_TAC[REAL_EQ_MUL_LCANCEL] THEN
+  SIMP_TAC[NORM_BASIS; DIMINDEX_3; ARITH; REAL_MUL_LID] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[VECTOR_ARITH `u - u':real^3 = x <=> u' = u - x`] THEN
+  ONCE_REWRITE_TAC[CONJ_SYM] THEN REWRITE_TAC[UNWIND_THM2] THEN
+  REWRITE_TAC[DOT_LSUB; DOT_RMUL; DOT_LMUL] THEN
+  SIMP_TAC[DOT_BASIS_BASIS; DIMINDEX_3; ARITH] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Spherical coordinates.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let SPHERICAL_COORDINATES = prove
+ (`!u v w u' e1 e2 e3 r phi theta.
+       ~collinear {v, w, u} /\
+       ~collinear {v, w, u'} /\
+       orthonormal e1 e2 e3 /\
+       dist(w,v) % e3 = w - v /\
+       (v + e1) IN aff_gt {v, w} {u} /\
+       r = dist(v,u') /\
+       phi = arcV v u' w /\
+       theta = azim v w u u'
+       ==> u' = v + (r * cos theta * sin phi) % e1 +
+                    (r * sin theta * sin phi) % e2 +
+                    (r * cos phi) % e3`,
+  ONCE_REWRITE_TAC[VECTOR_ARITH
+   `u':real^3 = u + v + w <=> u' - u = v + w`] THEN
+  GEN_GEOM_ORIGIN_TAC `v:real^3` ["e1"; "e2"; "e3"] THEN
+  REWRITE_TAC[VECTOR_ADD_RID; VECTOR_ADD_LID] THEN
+  REWRITE_TAC[TRANSLATION_INVARIANTS `v:real^3`] THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `w:real^3` THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; DIST_0] THEN
+  X_GEN_TAC `w:real` THEN ASM_CASES_TAC `w = &0` THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[REAL_LE_LT] THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC
+   [`u:real^3`; `v:real^3`; `e1:real^3`; `e2:real^3`; `e3:real^3`;
+    `r:real`; `phi:real`; `theta:real`] THEN
+  ASM_CASES_TAC `u:real^3 = w % basis 3` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_CASES_TAC `v:real^3 = w % basis 3` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o GSYM) THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; COLLINEAR_SPECIAL_SCALE] THEN
+  SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_3; ARITH] THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 < w ==> abs w * &1 = w`] THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LCANCEL] THEN
+  ASM_CASES_TAC `e3:real^3 = basis 3` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[ARCV_ANGLE; angle; VECTOR_SUB_RZERO] THEN
+  ASM_SIMP_TAC[VECTOR_ANGLE_RMUL; REAL_LT_IMP_LE] THEN
+  ASM_CASES_TAC `u:real^3 = vec 0` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_CASES_TAC `v:real^3 = vec 0` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_CASES_TAC `u:real^3 = basis 3` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_CASES_TAC `v:real^3 = basis 3` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`v:real^3`; `basis 3:real^3`] VECTOR_ANGLE) THEN
+  ASM_SIMP_TAC[DOT_BASIS; NORM_BASIS; DIMINDEX_3; ARITH; REAL_MUL_LID] THEN
+  DISCH_TAC THEN
+  MP_TAC(ISPECL
+   [`vec 0:real^3`; `w % basis 3:real^3`; `u:real^3`; `e1:real^3`]
+        AZIM_EQ_0_ALT) THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; COLLINEAR_SPECIAL_SCALE] THEN
+  ANTS_TAC THENL
+   [SIMP_TAC[COLLINEAR_LEMMA; BASIS_NONZERO; DIMINDEX_3; ARITH] THEN
+    STRIP_TAC THEN UNDISCH_TAC `orthonormal e1 e2 (basis 3)` THEN
+    ASM_REWRITE_TAC[orthonormal; DOT_LZERO; REAL_OF_NUM_EQ; ARITH_EQ] THEN
+    ASM_CASES_TAC `c = &0` THEN
+    ASM_SIMP_TAC[VECTOR_MUL_LZERO; CROSS_LZERO; DOT_LZERO; REAL_LT_REFL;
+                 DOT_LMUL; DOT_BASIS_BASIS; DIMINDEX_3; ARITH; REAL_MUL_RID];
+    DISCH_TAC] THEN
+  SUBGOAL_THEN
+   `dropout 3 (v:real^3):real^2 =
+    norm(dropout 3 (v:real^3):real^2) %
+    (cos theta % (dropout 3 (e1:real^3)) +
+     sin theta % (dropout 3 (e2:real^3)))`
+  MP_TAC THENL
+   [ALL_TAC;
+    SUBGOAL_THEN `norm((dropout 3:real^3->real^2) v) = r * sin phi`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[NORM_EQ_SQUARE] THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[REAL_LE_MUL; NORM_POS_LE; SIN_VECTOR_ANGLE_POS];
+        ALL_TAC] THEN
+      UNDISCH_TAC `(v:real^3)$3 = r * cos phi` THEN
+      MATCH_MP_TAC(REAL_RING
+       `x + a pow 2 = y + b pow 2 ==> a:real = b ==> x = y`) THEN
+      REWRITE_TAC[REAL_POW_MUL; GSYM REAL_ADD_LDISTRIB] THEN
+      REWRITE_TAC[SIN_CIRCLE; REAL_MUL_RID] THEN
+      UNDISCH_THEN `norm(v:real^3) = r` (SUBST1_TAC o SYM) THEN
+      REWRITE_TAC[NORM_POW_2; DOT_2; DOT_3] THEN
+      SIMP_TAC[dropout; LAMBDA_BETA; DIMINDEX_2; ARITH] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[CART_EQ; DIMINDEX_3; DIMINDEX_2; FORALL_3; FORALL_2] THEN
+    SIMP_TAC[dropout; LAMBDA_BETA; DIMINDEX_2; ARITH; VECTOR_ADD_COMPONENT;
+             VECTOR_MUL_COMPONENT; BASIS_COMPONENT; DIMINDEX_3] THEN
+    REPEAT STRIP_TAC THEN TRY REAL_ARITH_TAC THEN
+    ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [orthonormal]) THEN
+    SIMP_TAC[DOT_BASIS; DIMINDEX_3; ARITH] THEN CONV_TAC REAL_RING] THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o
+    GEN_REWRITE_RULE LAND_CONV [AZIM_ARG])) THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o
+    GEN_REWRITE_RULE RAND_CONV [COLLINEAR_BASIS_3])) THEN
+  SUBGOAL_THEN `norm((dropout 3:real^3->real^2) e1) = &1 /\
+                norm((dropout 3:real^3->real^2) e2) = &1 /\
+                dropout 3 (e2:real^3) / dropout 3 (e1:real^3) = ii`
+  MP_TAC THENL
+   [MATCH_MP_TAC(TAUT `(a /\ b) /\ (a /\ b ==> c) ==> a /\ b /\ c`) THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[NORM_EQ_1] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [orthonormal]) THEN
+      SIMP_TAC[DOT_BASIS; DIMINDEX_3; ARITH; dropout; LAMBDA_BETA;
+               DOT_2; DIMINDEX_2; DOT_3] THEN
+      CONV_TAC REAL_RING;
+      ALL_TAC] THEN
+    ASM_CASES_TAC `dropout 3 (e1:real^3) = Cx(&0)` THEN
+    ASM_SIMP_TAC[COMPLEX_NORM_CX; REAL_OF_NUM_EQ; ARITH_EQ; REAL_ABS_NUM] THEN
+    ASM_SIMP_TAC[COMPLEX_FIELD
+     `~(x = Cx(&0)) ==> (y / x = ii <=> y = ii * x)`] THEN
+    DISCH_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP ORTHONORMAL_CROSS) THEN
+    SIMP_TAC[CART_EQ; DIMINDEX_2; DIMINDEX_3; FORALL_2; FORALL_3;
+             cross; VECTOR_3; BASIS_COMPONENT; ARITH; dropout; LAMBDA_BETA;
+             complex_mul; ii; complex; RE_DEF; IM_DEF; VECTOR_2] THEN
+    CONV_TAC REAL_RING;
+    ALL_TAC] THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) e2`,`d2:real^2`) THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) e1`,`d1:real^2`) THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) v`,`z:real^2`) THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) u`,`w:real^2`) THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN
+  GEOM_BASIS_MULTIPLE_TAC 1 `w:real^2` THEN
+  X_GEN_TAC `k:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `k = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+  REWRITE_TAC[COMPLEX_CMUL; COMPLEX_BASIS; COMPLEX_VEC_0] THEN
+  SIMP_TAC[ARG_DIV_CX; COMPLEX_MUL_RID] THEN DISCH_TAC THEN REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `d1 = Cx(&1)` THENL
+   [ASM_SIMP_TAC[COMPLEX_DIV_1; COMPLEX_MUL_LID] THEN
+    REPEAT STRIP_TAC THEN MP_TAC(SPEC `z:complex` ARG) THEN
+    ASM_REWRITE_TAC[CEXP_EULER; CX_SIN; CX_COS; COMPLEX_MUL_RID] THEN
+    CONV_TAC COMPLEX_RING;
+    ASM_REWRITE_TAC[ARG_EQ_0] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [COMPLEX_EQ]) THEN
+    REWRITE_TAC[RE_CX; IM_CX;real] THEN
+    ASM_CASES_TAC `Im d1 = &0` THEN ASM_REWRITE_TAC[] THEN
+    ASM_SIMP_TAC[REAL_NORM; real] THEN REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Definition of a wedge and invariance theorems.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let wedge = new_definition
+ `wedge v0 v1 w1 w2 = {y | ~collinear {v0,v1,y} /\
+                         &0 < azim v0 v1 w1 y /\
+                         azim v0 v1 w1 y < azim v0 v1 w1 w2}`;;
+
+let WEDGE_ALT = prove
+ (`!v0 v1 w1 w2.
+        ~(v0 = v1)
+        ==> wedge v0 v1 w1 w2 = {y | ~(y IN affine hull {v0,v1}) /\
+                                     &0 < azim v0 v1 w1 y /\
+                                     azim v0 v1 w1 y < azim v0 v1 w1 w2}`,
+  SIMP_TAC[wedge; COLLINEAR_3_AFFINE_HULL]);;
+
+let WEDGE_TRANSLATION = prove
+ (`!a v w w1 w2. wedge (a + v) (a + w) (a + w1) (a + w2) =
+                 IMAGE (\x. a + x) (wedge v w w1 w2)`,
+  REPEAT GEN_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN CONJ_TAC THENL
+   [MESON_TAC[VECTOR_ARITH `a + (x - a):real^3 = x`]; ALL_TAC] THEN
+  REWRITE_TAC[wedge; IN_ELIM_THM; AZIM_TRANSLATION] THEN
+  REWRITE_TAC[SET_RULE
+   `{a + x,a + y,a + z} = IMAGE (\x:real^N. a + x) {x,y,z}`] THEN
+  REWRITE_TAC[COLLINEAR_TRANSLATION_EQ]);;
+
+add_translation_invariants [WEDGE_TRANSLATION];;
+
+let WEDGE_LINEAR_IMAGE = prove
+ (`!f. linear f /\ (!x. norm(f x) = norm x) /\
+       (2 <= dimindex(:3) ==> det(matrix f) = &1)
+       ==> !v w w1 w2. wedge (f v) (f w) (f w1) (f w2) =
+                       IMAGE f (wedge v w w1 w2)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_SURJECTIVE;
+                  ORTHOGONAL_TRANSFORMATION];
+    ALL_TAC] THEN
+  X_GEN_TAC `y:real^3` THEN REWRITE_TAC[wedge; IN_ELIM_THM] THEN
+  BINOP_TAC THEN ASM_SIMP_TAC[AZIM_LINEAR_IMAGE] THEN
+  SUBST1_TAC(SET_RULE `{f v,f w,f y} = IMAGE (f:real^3->real^3) {v,w,y}`) THEN
+  ASM_MESON_TAC[COLLINEAR_LINEAR_IMAGE_EQ; PRESERVES_NORM_INJECTIVE]);;
+
+add_linear_invariants [WEDGE_LINEAR_IMAGE];;
+
+let WEDGE_SPECIAL_SCALE = prove
+ (`!a v w1 w2.
+        &0 < a /\
+        ~collinear{vec 0,a % v,w1} /\
+        ~collinear{vec 0,a % v,w2}
+        ==> wedge (vec 0) (a % v) w1 w2 = wedge (vec 0) v w1 w2`,
+  SIMP_TAC[wedge; AZIM_SPECIAL_SCALE; COLLINEAR_SPECIAL_SCALE;
+           REAL_LT_IMP_NZ]);;
+
+let WEDGE_DEGENERATE = prove
+ (`(!z w w1 w2. z = w ==> wedge z w w1 w2 = {}) /\
+   (!z w w1 w2. collinear{z,w,w1} ==> wedge z w w1 w2 = {}) /\
+   (!z w w1 w2. collinear{z,w,w2} ==> wedge z w w1 w2 = {})`,
+  REWRITE_TAC[wedge] THEN SIMP_TAC[AZIM_DEGENERATE] THEN
+  REWRITE_TAC[REAL_LT_REFL; REAL_LT_ANTISYM; EMPTY_GSPEC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic relation between wedge and aff, so Tarski-type characterization.    *)
+(* ------------------------------------------------------------------------- *)
+
+let AFF_GT_LEMMA = prove
+ (`!v1 v2:real^N.
+        &0 < t1 /\ ~(v2 = vec 0)
+        ==> aff_gt {vec 0} {t1 % basis 1, v2} =
+                {a % basis 1 + b % v2 | &0 < a /\ &0 < b}`,
+  REWRITE_TAC[AFFSIGN_ALT; aff_gt_def; sgn_gt; IN_ELIM_THM] THEN
+  REWRITE_TAC[SET_RULE `{a} UNION {b,c} = {a,b,c}`] THEN
+  REWRITE_TAC[SET_RULE `x IN {a} <=> a = x`] THEN
+  ASM_SIMP_TAC[FINITE_INSERT; FINITE_UNION; AFFINE_HULL_FINITE_STEP_GEN;
+               RIGHT_EXISTS_AND_THM; REAL_LT_ADD; REAL_HALF; FINITE_EMPTY] THEN
+  ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[IN_INSERT; VECTOR_ARITH `vec 0 = a % x <=> a % x = vec 0`] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ; BASIS_NONZERO;
+               DIMINDEX_GE_1; LE_REFL] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_SUB_RZERO] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN X_GEN_TAC `y:real^N` THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+  REWRITE_TAC[REAL_ARITH `&1 - v - v' - v'' = &0 <=> v = &1 - v' - v''`] THEN
+  ONCE_REWRITE_TAC[MESON[] `(?a b c. P a b c) <=> (?b c a. P a b c)`] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM2] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `b:real` THEN
+  REWRITE_TAC[VECTOR_ARITH `y - a - b:real^N = vec 0 <=> y = a + b`] THEN
+  EQ_TAC THEN DISCH_THEN(X_CHOOSE_THEN `a:real` STRIP_ASSUME_TAC) THENL
+   [EXISTS_TAC `a * t1:real`; EXISTS_TAC `a / t1:real`] THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_MUL; VECTOR_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_DIV_RMUL; REAL_LT_IMP_NZ]);;
+
+let WEDGE_LUNE_GT = prove
+ (`!v0 v1 w1 w2.
+        ~collinear {v0,v1,w1} /\ ~collinear {v0,v1,w2} /\
+        &0 < azim v0 v1 w1 w2 /\ azim v0 v1 w1 w2 < pi
+        ==> wedge v0 v1 w1 w2 = aff_gt {v0,v1} {w1,w2}`,
+  let lemma = prove
+   (`!a x:real^3. (?a. x = a % basis 3) <=> dropout 3 x:real^2 = vec 0`,
+    SIMP_TAC[CART_EQ; FORALL_2; FORALL_3; DIMINDEX_2; DIMINDEX_3;
+        dropout; LAMBDA_BETA; BASIS_COMPONENT; ARITH; REAL_MUL_RID;
+        VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RZERO; UNWIND_THM1] THEN
+    MESON_TAC[]) in
+  REWRITE_TAC[wedge] THEN GEOM_ORIGIN_TAC `v0:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `v1:real^3` THEN
+  X_GEN_TAC `w:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `w = &0` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; COLLINEAR_SPECIAL_SCALE] THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`w1:real^3`; `w2:real^3`] THEN
+  REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ONCE_REWRITE_TAC[TAUT `~a /\ b /\ c <=> ~(~a ==> ~(b /\ c))`] THEN
+  ASM_SIMP_TAC[AZIM_ARG] THEN REWRITE_TAC[COLLINEAR_BASIS_3] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[COLLINEAR_BASIS_3]) THEN STRIP_TAC THEN
+  REWRITE_TAC[NOT_IMP; GSYM CONJ_ASSOC] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AFF_GT_SPECIAL_SCALE o rand o snd) THEN
+  SUBGOAL_THEN
+   `~(w1:real^3 = vec 0) /\ ~(w2:real^3 = vec 0) /\
+    ~(w1 = basis 3) /\ ~(w2 = basis 3)`
+  STRIP_ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o check (is_neg o concl))) THEN
+    ASM_REWRITE_TAC[DROPOUT_BASIS_3; DROPOUT_0; DROPOUT_MUL; VECTOR_MUL_RZERO];
+    ALL_TAC] THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY; IN_INSERT; NOT_IN_EMPTY] THEN
+    DISCH_THEN(DISJ_CASES_THEN (SUBST_ALL_TAC o SYM)) THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o check (is_neg o concl))) THEN
+    ASM_REWRITE_TAC[DROPOUT_BASIS_3; DROPOUT_0; DROPOUT_MUL; VECTOR_MUL_RZERO];
+    DISCH_THEN SUBST1_TAC] THEN
+  REWRITE_TAC[AFFSIGN_ALT; aff_gt_def; sgn_gt; IN_ELIM_THM] THEN
+  REWRITE_TAC[SET_RULE `{a,b} UNION {c,d} = {a,b,d,c}`] THEN
+  REWRITE_TAC[SET_RULE `x IN {a} <=> a = x`] THEN
+  ASM_SIMP_TAC[FINITE_INSERT; FINITE_UNION; AFFINE_HULL_FINITE_STEP_GEN;
+               RIGHT_EXISTS_AND_THM; REAL_LT_ADD; REAL_HALF; FINITE_EMPTY] THEN
+  ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_SUB_RZERO] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `{y | (dropout 3:real^3->real^2) y IN
+                   aff_gt {vec 0}
+                   {dropout 3 (w1:real^3),dropout 3 (w2:real^3)}}` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[AFFSIGN_ALT; aff_gt_def; sgn_gt; IN_ELIM_THM] THEN
+    REWRITE_TAC[SET_RULE `{a} UNION {b,c} = {a,b,c}`] THEN
+    REWRITE_TAC[SET_RULE `x IN {a} <=> a = x`] THEN
+    ASM_SIMP_TAC[FINITE_INSERT; FINITE_UNION; AFFINE_HULL_FINITE_STEP_GEN;
+               RIGHT_EXISTS_AND_THM; REAL_LT_ADD; REAL_HALF; FINITE_EMPTY] THEN
+    ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+    REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_SUB_RZERO] THEN
+    REWRITE_TAC[REAL_EQ_SUB_RADD; RIGHT_AND_EXISTS_THM] THEN
+    REWRITE_TAC[REAL_ARITH `&1 = x + v <=> v = &1 - x`] THEN
+    ONCE_REWRITE_TAC[TAUT `a /\ b /\ c /\ d <=> c /\ d /\ a /\ b`] THEN
+    ONCE_REWRITE_TAC[MESON[]
+      `(?a b c d. P a b c d) <=> (?b c d a. P a b c d)`] THEN
+    REWRITE_TAC[UNWIND_THM2] THEN
+    ONCE_REWRITE_TAC[MESON[]
+      `(?a b c. P a b c) <=> (?c b a. P a b c)`] THEN
+    REWRITE_TAC[UNWIND_THM2] THEN REWRITE_TAC[VECTOR_ARITH
+     `y - a - b - c:real^N = vec 0 <=> y - b - c = a`] THEN
+    REWRITE_TAC[LEFT_EXISTS_AND_THM; lemma] THEN
+    REWRITE_TAC[DROPOUT_SUB; DROPOUT_MUL] THEN
+    REWRITE_TAC[VECTOR_ARITH `y - a - b:real^2 = vec 0 <=> y = a + b`] THEN
+    REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN MESON_TAC[VECTOR_ADD_SYM]] THEN
+  MATCH_MP_TAC(SET_RULE
+   `{x | P x} = s ==> {y | P(dropout 3 y)} = {y | dropout 3 y IN s}`) THEN
+  MP_TAC(CONJ (ASSUME `~((dropout 3:real^3->real^2) w1 = vec 0)`)
+              (ASSUME `~((dropout 3:real^3->real^2) w2 = vec 0)`)) THEN
+  UNDISCH_TAC `Arg(dropout 3 (w2:real^3) / dropout 3 (w1:real^3)) < pi` THEN
+  UNDISCH_TAC `&0 < Arg(dropout 3 (w2:real^3) / dropout 3 (w1:real^3))` THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) w2`,`v2:complex`) THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) w1`,`v1:complex`) THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN GEOM_BASIS_MULTIPLE_TAC 1 `v1:complex` THEN
+  X_GEN_TAC `v1:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `v1 = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+  SIMP_TAC[AFF_GT_LEMMA] THEN
+  REWRITE_TAC[COMPLEX_CMUL; COMPLEX_BASIS; COMPLEX_VEC_0] THEN
+  ASM_SIMP_TAC[ARG_DIV_CX; COMPLEX_MUL_RID; CX_INJ] THEN DISCH_TAC THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN X_GEN_TAC `z:complex` THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_ELIM_THM] THEN CONJ_TAC THENL
+   [X_GEN_TAC `w:complex` THEN STRIP_TAC THEN
+    MP_TAC(SPECL [`\t. Arg(Cx t + Cx(&1 - t) * z)`;
+                  `&0`; `&1`; `Arg w`] REAL_IVT_DECREASING) THEN
+    REWRITE_TAC[REAL_POS; REAL_SUB_REFL; COMPLEX_MUL_LZERO] THEN
+    REWRITE_TAC[REAL_SUB_RZERO; COMPLEX_ADD_LID; COMPLEX_MUL_LID] THEN
+    ASM_SIMP_TAC[COMPLEX_ADD_RID; ARG_NUM; REAL_LT_IMP_LE] THEN ANTS_TAC THENL
+     [REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+      REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS; IN_REAL_INTERVAL] THEN
+      X_GEN_TAC `t:real` THEN STRIP_TAC THEN
+      ONCE_REWRITE_TAC[GSYM o_DEF] THEN REWRITE_TAC[o_ASSOC] THEN
+      MATCH_MP_TAC CONTINUOUS_WITHINREAL_COMPOSE THEN
+      REWRITE_TAC[] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ADD THEN CONJ_TAC THENL
+         [GEN_REWRITE_TAC LAND_CONV [SYM(CONJUNCT2(SPEC_ALL I_O_ID))] THEN
+          REWRITE_TAC[GSYM REAL_CONTINUOUS_CONTINUOUS] THEN
+          REWRITE_TAC[I_DEF; REAL_CONTINUOUS_WITHIN_ID];
+          MATCH_MP_TAC CONTINUOUS_COMPLEX_MUL THEN
+          REWRITE_TAC[CONTINUOUS_CONST] THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+          REWRITE_TAC[GSYM REAL_CONTINUOUS_CONTINUOUS] THEN
+          SIMP_TAC[REAL_CONTINUOUS_SUB; REAL_CONTINUOUS_CONST;
+                   REAL_CONTINUOUS_WITHIN_ID]];
+        MATCH_MP_TAC CONTINUOUS_WITHIN_SUBSET THEN
+        EXISTS_TAC `{z | &0 <= Im z}` THEN CONJ_TAC THENL
+         [MATCH_MP_TAC CONTINUOUS_WITHIN_UPPERHALF_ARG THEN
+          ASM_CASES_TAC `t = &1` THENL
+           [ASM_REWRITE_TAC[REAL_SUB_REFL] THEN CONV_TAC COMPLEX_RING;
+            ALL_TAC] THEN
+          DISCH_THEN(MP_TAC o AP_TERM `Im`) THEN
+          REWRITE_TAC[IM_ADD; IM_CX; IM_MUL_CX; REAL_ADD_LID; REAL_ENTIRE] THEN
+          ASM_REWRITE_TAC[REAL_SUB_0] THEN
+          ASM_MESON_TAC[ARG_LT_PI; REAL_LT_IMP_NZ; REAL_LT_TRANS];
+          REWRITE_TAC[FORALL_IN_IMAGE; SUBSET; IN_REAL_INTERVAL] THEN
+          REWRITE_TAC[IN_ELIM_THM; IM_ADD; IM_CX; IM_MUL_CX] THEN
+          REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_ADD_LID] THEN
+          MATCH_MP_TAC REAL_LE_MUL THEN REWRITE_TAC[GSYM ARG_LE_PI] THEN
+          ASM_REAL_ARITH_TAC]];
+      REWRITE_TAC[IN_REAL_INTERVAL] THEN
+      DISCH_THEN(X_CHOOSE_THEN `t:real` MP_TAC) THEN
+      ASM_CASES_TAC `t = &0` THENL
+       [ASM_REWRITE_TAC[REAL_SUB_RZERO; COMPLEX_ADD_LID; COMPLEX_MUL_LID] THEN
+        ASM_MESON_TAC[REAL_LT_REFL];
+        ALL_TAC] THEN
+      ASM_CASES_TAC `t = &1` THENL
+       [ASM_REWRITE_TAC[REAL_SUB_REFL; COMPLEX_MUL_LZERO] THEN
+        REWRITE_TAC[COMPLEX_ADD_RID; ARG_NUM] THEN ASM_MESON_TAC[REAL_LT_REFL];
+        ALL_TAC] THEN
+      GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [REAL_LE_LT] THEN
+      ASM_REWRITE_TAC[] THEN ABBREV_TAC `u = Cx t + Cx(&1 - t) * z` THEN
+      ASM_CASES_TAC `u = Cx(&0)` THENL
+       [ASM_MESON_TAC[ARG_0; REAL_LT_REFL]; ALL_TAC] THEN
+      STRIP_TAC THEN
+      EXISTS_TAC `norm(w:complex) / norm(u:complex) * t` THEN
+      EXISTS_TAC `norm(w:complex) / norm(u:complex) * (&1 - t)` THEN
+      ASM_SIMP_TAC[REAL_LT_MUL; REAL_LT_DIV; COMPLEX_NORM_NZ; REAL_SUB_LT] THEN
+      SIMP_TAC[CX_MUL; GSYM COMPLEX_MUL_ASSOC; GSYM COMPLEX_ADD_LDISTRIB] THEN
+      ASM_REWRITE_TAC[CX_DIV] THEN
+      ASM_SIMP_TAC[CX_INJ; COMPLEX_NORM_ZERO; COMPLEX_FIELD
+        `~(nu = Cx(&0)) ==> (w = nw / nu * u <=> nu * w = nw * u)`] THEN
+      GEN_REWRITE_TAC (BINOP_CONV o RAND_CONV) [ARG] THEN
+      ASM_REWRITE_TAC[COMPLEX_MUL_AC]];
+    MAP_EVERY X_GEN_TAC [`a:real`; `b:real`] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `Cx a + Cx b * z = complex(a + b * Re z,b * Im z)`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[COMPLEX_EQ; RE; IM; RE_ADD; IM_ADD; RE_CX; IM_CX;
+                  RE_MUL_CX; IM_MUL_CX] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[COMPLEX_EQ; IM; IM_CX] THEN
+    SUBGOAL_THEN `&0 < Im z` ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[GSYM ARG_LT_PI]; ALL_TAC] THEN
+    ASM_SIMP_TAC[ARG_ATAN_UPPERHALF; REAL_LT_MUL; REAL_LT_IMP_NZ; IM] THEN
+    REWRITE_TAC[RE; REAL_SUB_LT; ATN_BOUNDS] THEN
+    REWRITE_TAC[REAL_ARITH `pi / &2 - x < pi / &2 - y <=> y < x`] THEN
+    REWRITE_TAC[ATN_MONO_LT_EQ] THEN
+    ASM_SIMP_TAC[REAL_LT_RDIV_EQ; REAL_LT_MUL] THEN
+    ASM_SIMP_TAC[REAL_FIELD `&0 < z ==> w / z * b * z = b * w`] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let WEDGE_LUNE_GE = prove
+ (`!v0 v1 w1 w2.
+        ~collinear {v0,v1,w1} /\ ~collinear {v0,v1,w2} /\
+        &0 < azim v0 v1 w1 w2 /\ azim v0 v1 w1 w2 < pi
+        ==> {x | &0 <= azim v0 v1 w1 x /\
+                 azim v0 v1 w1 x <= azim v0 v1 w1 w2} =
+            aff_ge {v0,v1} {w1,w2}`,
+  REPEAT GEN_TAC THEN
+  MAP_EVERY (fun t -> ASM_CASES_TAC t THENL
+       [ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC] THEN NO_TAC; ALL_TAC])
+   [`v1:real^3 = v0`; `w1:real^3 = v0`; `w2:real^3 = v0`;
+    `w1:real^3 = v1`; `w2:real^3 = v1`] THEN
+  ASM_CASES_TAC `w1:real^3 = w2` THEN
+  ASM_REWRITE_TAC[AZIM_REFL; REAL_LT_REFL] THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[REAL_ARITH
+   `&0 < a
+    ==> (&0 <= x /\ x <= a <=> x = &0 \/ x = a \/ &0 < x /\ x < a)`] THEN
+  MATCH_MP_TAC(SET_RULE
+   `!c. c SUBSET {x | p x} /\ c SUBSET s /\
+        ({x | ~(~c x ==> ~p x)} UNION {x | ~(~c x ==> ~q x)} UNION
+         ({x | ~c x /\ r x} DIFF c) = s DIFF c)
+        ==> {x | p x \/ q x \/ r x} = s`) THEN
+  EXISTS_TAC `{x:real^3 | collinear {v0,v1,x}}` THEN
+  ASM_SIMP_TAC[IN_ELIM_THM; AZIM_EQ_ALT; AZIM_EQ_0_ALT;
+               GSYM wedge; WEDGE_LUNE_GT] THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_SIMP_TAC[SUBSET; IN_ELIM_THM; AZIM_DEGENERATE];
+    ASM_SIMP_TAC[COLLINEAR_3_AFFINE_HULL] THEN
+    REWRITE_TAC[SET_RULE `{x | x IN s} = s`] THEN
+    MATCH_MP_TAC AFFINE_HULL_SUBSET_AFF_GE THEN
+    ASM_REWRITE_TAC[DISJOINT_INSERT; IN_INSERT; NOT_IN_EMPTY; DISJOINT_EMPTY];
+    ALL_TAC] THEN
+  REWRITE_TAC[NOT_IMP] THEN MATCH_MP_TAC(SET_RULE
+   `(!x. ~c x ==> (p x \/ q x \/ x IN t <=> x IN e))
+    ==> {x | ~c x /\ p x} UNION {x | ~c x /\ q x} UNION (t DIFF {x | c x}) =
+        e DIFF {x | c x}`) THEN
+  X_GEN_TAC `y:real^3` THEN DISCH_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AFF_GE_AFF_GT_DECOMP o rand o
+    rand o snd) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY] THEN
+    ASM_REWRITE_TAC[DISJOINT_INSERT; IN_INSERT; NOT_IN_EMPTY; DISJOINT_EMPTY];
+    DISCH_THEN SUBST1_TAC] THEN
+  REWRITE_TAC[IN_UNION] THEN
+  REWRITE_TAC[SIMPLE_IMAGE; IMAGE_CLAUSES; UNIONS_2] THEN
+  ASM_SIMP_TAC[SET_RULE `~(w1 = w2) ==> {w1,w2} DELETE w1 = {w2}`;
+               SET_RULE `~(w1 = w2) ==> {w1,w2} DELETE w2 = {w1}`] THEN
+  REWRITE_TAC[IN_UNION; DISJ_ACI] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AFF_GE_AFF_GT_DECOMP o rand o lhand o
+    rand o snd) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY] THEN
+    ASM_REWRITE_TAC[DISJOINT_INSERT; IN_INSERT; NOT_IN_EMPTY; DISJOINT_EMPTY];
+    DISCH_THEN SUBST1_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AFF_GE_AFF_GT_DECOMP o rand o lhand o
+    rand o rand o snd) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY] THEN
+    ASM_REWRITE_TAC[DISJOINT_INSERT; IN_INSERT; NOT_IN_EMPTY; DISJOINT_EMPTY];
+    DISCH_THEN SUBST1_TAC] THEN
+  REWRITE_TAC[IN_UNION] THEN
+  REWRITE_TAC[SIMPLE_IMAGE; IMAGE_CLAUSES; UNIONS_1] THEN
+  REWRITE_TAC[SET_RULE `{a} DELETE a = {}`; AFF_GE_EQ_AFFINE_HULL] THEN
+  ASM_MESON_TAC[COLLINEAR_3_AFFINE_HULL]);;
+
+let WEDGE_LUNE = prove
+ (`!v0 v1 w1 w2.
+        ~coplanar{v0,v1,w1,w2} /\ azim v0 v1 w1 w2 < pi
+        ==> wedge v0 v1 w1 w2 = aff_gt {v0,v1} {w1,w2}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC WEDGE_LUNE_GT THEN
+  ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [MP_TAC(ISPECL [`v0:real^3`; `v1:real^3`; `w1:real^3`; `w2:real^3`]
+                NOT_COPLANAR_NOT_COLLINEAR) THEN
+    ASM_REWRITE_TAC[];
+    MP_TAC(ISPECL [`v0:real^3`; `v1:real^3`; `w2:real^3`; `w1:real^3`]
+                NOT_COPLANAR_NOT_COLLINEAR) THEN
+    ONCE_REWRITE_TAC[SET_RULE `{a,b,c,d} = {a,b,d,c}`] THEN
+    ASM_REWRITE_TAC[];
+    REWRITE_TAC[azim; REAL_LT_LE] THEN
+    ASM_MESON_TAC[AZIM_EQ_0_PI_IMP_COPLANAR]]);;
+
+let WEDGE = prove
+ (`wedge v1 v2 w1 w2 =
+        if collinear{v1,v2,w1} \/ collinear{v1,v2,w2} then {}
+        else
+          let z = v2 - v1 in
+          let u1 = w1 - v1 in
+          let u2 = w2 - v1 in
+          let n = z cross u1 in
+          let d =  n dot u2 in
+          if w2 IN (aff_ge {v1,v2} {w1}) then {}
+          else if w2 IN (aff_lt {v1,v2} {w1}) then aff_gt {v1,v2,w1} {v1 + n}
+          else if d > &0 then aff_gt {v1,v2} {w1,w2}
+          else (:real^3) DIFF aff_ge {v1,v2} {w1,w2}`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THENL
+   [FIRST_X_ASSUM DISJ_CASES_TAC THEN
+    ASM_SIMP_TAC[WEDGE_DEGENERATE];
+    POP_ASSUM MP_TAC THEN REWRITE_TAC[DE_MORGAN_THM] THEN STRIP_TAC] THEN
+  ASM_SIMP_TAC[GSYM AZIM_EQ_0_GE_ALT] THEN
+  ASM_CASES_TAC `azim v1 v2 w1 w2 = &0` THENL
+   [ASM_REWRITE_TAC[wedge] THEN
+    ASM_REWRITE_TAC[REAL_LT_ANTISYM; LET_DEF; LET_END_DEF; EMPTY_GSPEC];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM AZIM_EQ_PI_ALT] THEN
+  ASM_CASES_TAC `azim v1 v2 w1 w2 = pi` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[LET_DEF; LET_END_DEF] THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+  GEOM_ORIGIN_TAC `v1:real^3` THEN
+  REWRITE_TAC[VECTOR_ADD_RID; TRANSLATION_INVARIANTS `v1:real^3`] THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; VECTOR_ADD_LID] THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `v2:real^3` THEN
+  X_GEN_TAC `v2:real` THEN
+  GEN_REWRITE_TAC LAND_CONV [REAL_ARITH `&0 <= x <=> x = &0 \/ &0 < x`] THEN
+  (STRIP_TAC THENL
+    [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; INSERT_AC; COLLINEAR_2]; ALL_TAC]) THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; COLLINEAR_SPECIAL_SCALE; REAL_LT_IMP_NZ;
+               WEDGE_SPECIAL_SCALE] THEN
+  (REPEAT GEN_TAC THEN
+   MAP_EVERY (fun t -> ASM_CASES_TAC t THENL
+        [ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC] THEN NO_TAC; ALL_TAC])
+    [`w1:real^3 = vec 0`; `w2:real^3 = vec 0`; `w1:real^3 = basis 3`;
+     `w2:real^3 = basis 3`] THEN
+   ASM_CASES_TAC `w1:real^3 = v2 % basis 3` THENL
+    [ASM_REWRITE_TAC[COLLINEAR_LEMMA] THEN MESON_TAC[]; ALL_TAC] THEN
+   ASM_CASES_TAC `w2:real^3 = v2 % basis 3` THENL
+    [ASM_REWRITE_TAC[COLLINEAR_LEMMA] THEN MESON_TAC[]; ALL_TAC])
+  THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[EXTENSION] THEN X_GEN_TAC `y:real^3` THEN
+    MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+     `(dropout 3 (y:real^3)) IN
+      aff_gt {vec 0:real^2,dropout 3 (w1:real^3)}
+              {rotate2d (pi / &2) (dropout 3 (w1:real^3))}` THEN
+    CONJ_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE LAND_CONV [AZIM_ARG]) THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE (RAND_CONV o LAND_CONV)
+       [AZIM_ARG]) THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV
+        [COLLINEAR_BASIS_3])) THEN
+      POP_ASSUM_LIST(K ALL_TAC) THEN
+      REWRITE_TAC[wedge; IN_ELIM_THM; AZIM_ARG; COLLINEAR_BASIS_3] THEN
+      SPEC_TAC(`(dropout 3:real^3->real^2) y`,`x:real^2`) THEN
+      SPEC_TAC(`(dropout 3:real^3->real^2) w2`,`v2:real^2`) THEN
+      SPEC_TAC(`(dropout 3:real^3->real^2) w1`,`v1:real^2`) THEN
+      GEOM_BASIS_MULTIPLE_TAC 1 `v1:complex` THEN
+      X_GEN_TAC `v:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+      ASM_CASES_TAC `v = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+      REWRITE_TAC[COMPLEX_CMUL; COMPLEX_BASIS; COMPLEX_VEC_0] THEN
+      SIMP_TAC[ARG_DIV_CX; COMPLEX_MUL_RID] THEN
+      REWRITE_TAC[real; RE_DIV_CX; IM_DIV_CX; CX_INJ] THEN
+      ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_EQ_LDIV_EQ; REAL_MUL_LZERO] THEN
+      REPEAT STRIP_TAC THEN REWRITE_TAC[ARG_LT_PI; ROTATE2D_PI2] THEN
+      W(MP_TAC o PART_MATCH (lhs o rand) AFF_GT_2_1 o rand o rand o snd) THEN
+      ASM_REWRITE_TAC[DISJOINT_INSERT; DISJOINT_EMPTY; IN_SING] THEN
+      ANTS_TAC THENL
+       [CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN
+        ASM_REWRITE_TAC[COMPLEX_ENTIRE; II_NZ; CX_INJ] THEN
+        DISCH_THEN(MP_TAC o AP_TERM `Re`) THEN
+        REWRITE_TAC[RE_MUL_II; RE_CX; IM_CX] THEN ASM_REAL_ARITH_TAC;
+        DISCH_THEN SUBST1_TAC] THEN
+      REWRITE_TAC[COMPLEX_CMUL; IN_ELIM_THM; COMPLEX_MUL_RZERO] THEN
+      ONCE_REWRITE_TAC[MESON[] `(?a b c. P a b c) <=> (?b c a. P a b c)`] THEN
+      REWRITE_TAC[REAL_ARITH `t1 + t2 = &1 <=> t1 = &1 - t2`] THEN
+      REWRITE_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM2; COMPLEX_ADD_LID] THEN
+      EQ_TAC THENL
+       [DISCH_TAC THEN
+        MAP_EVERY EXISTS_TAC [`Re x / v`; `Im x / v`] THEN
+        ASM_SIMP_TAC[REAL_LT_DIV; COMPLEX_EQ; IM_ADD; RE_ADD] THEN
+        REWRITE_TAC[RE_MUL_CX; IM_MUL_CX; RE_CX; IM_CX; RE_II; IM_II] THEN
+        UNDISCH_TAC `~(v = &0)` THEN CONV_TAC REAL_FIELD;
+        REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+        MAP_EVERY X_GEN_TAC [`s:real`; `t:real`] THEN
+        STRIP_TAC THEN ASM_REWRITE_TAC[COMPLEX_EQ; IM_ADD; RE_ADD] THEN
+        REWRITE_TAC[RE_MUL_CX; IM_MUL_CX; RE_CX; IM_CX; RE_II; IM_II] THEN
+        ASM_SIMP_TAC[REAL_MUL_RZERO; REAL_MUL_LID; REAL_LT_MUL; REAL_ADD_LID;
+                     REAL_MUL_LZERO] THEN
+        MAP_EVERY UNDISCH_TAC [`&0 < v`; `&0 < t`] THEN
+        CONV_TAC REAL_FIELD];
+      ALL_TAC] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) AFF_GT_3_1 o rand o rand o snd) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[SET_RULE
+       `DISJOINT {a,b,c} {x} <=> ~(x = a) /\ ~(x = b) /\ ~(x = c)`] THEN
+      ASM_SIMP_TAC[CROSS_EQ_0; CROSS_EQ_SELF; VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ;
+                   REAL_LT_IMP_NZ; BASIS_NONZERO; DIMINDEX_3;
+                   ARITH; COLLINEAR_SPECIAL_SCALE];
+      DISCH_THEN SUBST1_TAC] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) AFF_GT_2_1 o rand o lhand o snd) THEN
+    REWRITE_TAC[ROTATE2D_PI2] THEN ANTS_TAC THENL
+     [REWRITE_TAC[SET_RULE `DISJOINT {a,b} {x} <=> ~(x = a) /\ ~(x = b)`] THEN
+      REWRITE_TAC[COMPLEX_ENTIRE; COMPLEX_RING `ii * x = x <=> x = Cx(&0)`;
+                  COMPLEX_VEC_0; II_NZ] THEN
+      ASM_REWRITE_TAC[GSYM COMPLEX_VEC_0; GSYM COLLINEAR_BASIS_3];
+      DISCH_THEN SUBST1_TAC] THEN
+    REWRITE_TAC[IN_ELIM_THM; VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+    ONCE_REWRITE_TAC[MESON[]
+     `(?a b c d. P a b c d) <=> (?d c b a. P a b c d)`] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `s + t = &1 <=> s = &1 - t`] THEN
+    REWRITE_TAC[UNWIND_THM2; RIGHT_EXISTS_AND_THM] THEN
+    ONCE_REWRITE_TAC[MESON[] `(?a b c. P a b c) <=> (?c b a. P a b c)`] THEN
+    REWRITE_TAC[UNWIND_THM2; RIGHT_EXISTS_AND_THM] THEN
+    REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+    SIMP_TAC[CART_EQ; FORALL_2; FORALL_3; DIMINDEX_2; DIMINDEX_3;
+      dropout; LAMBDA_BETA; BASIS_COMPONENT; ARITH; REAL_MUL_RID;
+      VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RZERO; UNWIND_THM1;
+      VECTOR_ADD_COMPONENT; cross; VECTOR_3;
+      REWRITE_RULE[RE_DEF; IM_DEF] RE_MUL_II;
+      REWRITE_RULE[RE_DEF; IM_DEF] IM_MUL_II;
+      REAL_ADD_LID; REAL_MUL_LZERO; REAL_SUB_REFL; REAL_ADD_RID;
+      REAL_SUB_LZERO; REAL_SUB_RZERO] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `s:real` THEN
+    REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+    ASM_SIMP_TAC[EXISTS_REFL; REAL_FIELD
+     `&0 < v ==> (x = a * v + b <=> a = (x - b) / v)`] THEN
+    REWRITE_TAC[REAL_MUL_RNEG; REAL_MUL_ASSOC] THEN EQ_TAC THEN
+    DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THENL
+     [EXISTS_TAC `t / v2:real`; EXISTS_TAC `t * v2:real`] THEN
+    ASM_SIMP_TAC[REAL_DIV_RMUL; REAL_LT_DIV; REAL_LT_IMP_NZ; REAL_LT_MUL];
+    ALL_TAC] THEN
+  REWRITE_TAC[CROSS_LMUL] THEN
+  SIMP_TAC[cross; BASIS_COMPONENT; DIMINDEX_3; ARITH; DOT_3; VECTOR_3;
+      VECTOR_MUL_COMPONENT; REAL_MUL_LZERO; REAL_SUB_RZERO; REAL_NEG_0;
+           REAL_MUL_RZERO; REAL_SUB_LZERO; REAL_MUL_LID; REAL_ADD_RID] THEN
+  REWRITE_TAC[REAL_ARITH
+  `(v * --x2) * y1 + (v * x1) * y2 > &0 <=> &0 < v * (x1 * y2 - x2 * y1)`] THEN
+  ASM_SIMP_TAC[REAL_LT_MUL_EQ; REAL_SUB_LT] THEN
+  REWRITE_TAC[AZIM_ARG; COLLINEAR_BASIS_3] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `w1$2 * w2$1 < w1$1 * w2$2 <=>
+    Arg(dropout 3 (w2:real^3) / dropout 3 (w1:real^3)) < pi`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `&0 < Im(dropout 3 (w2:real^3) / dropout 3 (w1:real^3))` THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[IM_COMPLEX_DIV_GT_0] THEN
+      REWRITE_TAC[complex_mul; cnj; RE_DEF; IM_DEF; complex] THEN
+      SIMP_TAC[dropout; VECTOR_2; LAMBDA_BETA; DIMINDEX_3; ARITH;
+               DIMINDEX_2] THEN
+      REAL_ARITH_TAC;
+      REWRITE_TAC[GSYM ARG_LT_PI] THEN ASM_MESON_TAC[ARG_LT_NZ]];
+    ALL_TAC] THEN
+  COND_CASES_TAC THENL
+   [W(MP_TAC o PART_MATCH (lhs o rand) AFF_GT_SPECIAL_SCALE o rand o snd) THEN
+    ASM_REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY; IN_INSERT; NOT_IN_EMPTY] THEN
+    DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC WEDGE_LUNE THEN
+    ASM_SIMP_TAC[GSYM AZIM_EQ_0_PI_EQ_COPLANAR; COLLINEAR_BASIS_3] THEN
+    ASM_REWRITE_TAC[AZIM_ARG];
+    ALL_TAC] THEN
+  REWRITE_TAC[wedge] THEN
+  GEN_REWRITE_TAC (funpow 3 RAND_CONV) [SET_RULE `{a,b} = {b,a}`] THEN
+  W(MP_TAC o PART_MATCH (rand o rand) WEDGE_LUNE_GE o rand o rand o snd) THEN
+  ASM_SIMP_TAC[COLLINEAR_SPECIAL_SCALE; REAL_LT_IMP_NZ; AZIM_SPECIAL_SCALE] THEN
+  ASM_REWRITE_TAC[AZIM_ARG; COLLINEAR_BASIS_3] THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[ARG_LT_NZ] THEN
+    ONCE_REWRITE_TAC[GSYM ARG_INV_EQ_0] THEN
+    ASM_REWRITE_TAC[COMPLEX_INV_DIV] THEN
+    ONCE_REWRITE_TAC[GSYM COMPLEX_INV_DIV] THEN
+    ASM_SIMP_TAC[ARG_INV; GSYM ARG_EQ_0] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[EXTENSION; IN_DIFF; IN_UNIV; IN_ELIM_THM; ARG] THEN
+  REWRITE_TAC[REAL_NOT_LE] THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) w1`,`w:complex`) THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) w2`,`z:complex`) THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN X_GEN_TAC `x3:real^3` THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) x3`,`x:complex`) THEN
+  GEN_TAC THEN REWRITE_TAC[COMPLEX_VEC_0] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[COMPLEX_VEC_0]) THEN
+  ASM_CASES_TAC `x = Cx(&0)` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_REWRITE_TAC[complex_div; COMPLEX_MUL_LZERO; REAL_NOT_LT; ARG; ARG_0];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[ARG_LT_NZ] THEN
+  MAP_EVERY UNDISCH_TAC
+   [`~(Arg (z / w) < pi)`;
+    `~(Arg (z / w) = pi)`;
+    `~(Arg (z / w) = &0)`;
+    `~(x = Cx (&0))`;
+    `~(w = Cx (&0))`;
+    `~(z = Cx (&0))`] THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN REWRITE_TAC[GSYM COMPLEX_VEC_0] THEN
+  GEOM_BASIS_MULTIPLE_TAC 1 `w:complex` THEN
+  X_GEN_TAC `w:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `w = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+  REWRITE_TAC[COMPLEX_CMUL; COMPLEX_BASIS; COMPLEX_VEC_0] THEN
+  SIMP_TAC[ARG_DIV_CX; COMPLEX_MUL_RID] THEN
+  REWRITE_TAC[real; RE_DIV_CX; IM_DIV_CX; CX_INJ] THEN
+  SIMP_TAC[complex_div; ARG_MUL_CX] THEN
+  SIMP_TAC[ARG_INV; GSYM ARG_EQ_0; ARG_INV_EQ_0] THEN
+  DISCH_TAC THEN REPEAT GEN_TAC THEN REWRITE_TAC[GSYM complex_div] THEN
+  ASM_CASES_TAC `Arg x = &0` THEN ASM_REWRITE_TAC[] THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ARG_EQ_0]) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    REWRITE_TAC[REAL] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[complex_div; CX_INJ] THEN
+    ASM_SIMP_TAC[ARG_MUL_CX; REAL_LT_LE] THEN
+    ASM_SIMP_TAC[ARG_INV; GSYM ARG_EQ_0];
+    ALL_TAC] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  SIMP_TAC[PI_POS; REAL_ARITH
+   `&0 < pi ==> (~(z = &0) /\ ~(z = pi) /\ ~(z < pi) <=> pi < z)`] THEN
+  STRIP_TAC THEN REWRITE_TAC[REAL_LT_SUB_RADD] THEN
+  DISJ_CASES_TAC(REAL_ARITH `Arg z <= Arg x \/ Arg x < Arg z`) THENL
+   [ASM_REWRITE_TAC[GSYM REAL_NOT_LE] THEN
+    ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
+    ASM_SIMP_TAC[GSYM ARG_LE_DIV_SUM] THEN
+    SIMP_TAC[ARG; REAL_LT_IMP_LE];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPECL [`x:complex`; `z:complex`] ARG_LE_DIV_SUM) THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN DISCH_THEN SUBST1_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `&0 <= x /\ ~(x = &0) /\ y = k - z ==> k < y + x + z`) THEN
+  ASM_REWRITE_TAC[ARG] THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM COMPLEX_INV_DIV] THEN
+  MATCH_MP_TAC ARG_INV THEN REWRITE_TAC[REAL] THEN
+  DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THEN
+  ABBREV_TAC `t = Re(z / x)` THEN UNDISCH_TAC `Arg x < Arg z` THEN
+  UNDISCH_TAC `z / x = Cx t` THEN
+  ASM_SIMP_TAC[COMPLEX_FIELD
+   `~(x = Cx(&0)) ==> (z / x = t <=> z = t * x)`] THEN
+  ASM_CASES_TAC `t = &0` THEN ASM_REWRITE_TAC[COMPLEX_MUL_LZERO] THEN
+  ASM_SIMP_TAC[ARG_MUL_CX; REAL_LT_LE]);;
+
+let OPEN_WEDGE = prove
+ (`!z:real^3 w w1 w2. open(wedge z w w1 w2)`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `z:real^3 = w \/  collinear{z,w,w1} \/ collinear{z,w,w2}` THENL
+   [FIRST_X_ASSUM STRIP_ASSUME_TAC THEN
+    ASM_SIMP_TAC[WEDGE_DEGENERATE; OPEN_EMPTY];
+    FIRST_X_ASSUM MP_TAC THEN REWRITE_TAC[DE_MORGAN_THM]] THEN
+  REWRITE_TAC[wedge] THEN GEOM_ORIGIN_TAC `z:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `w:real^3` THEN
+  X_GEN_TAC `w:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `w = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; COLLINEAR_SPECIAL_SCALE] THEN
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[TAUT `~a /\ b /\ c <=> ~(~a ==> ~(b /\ c))`] THEN
+  ASM_SIMP_TAC[AZIM_ARG] THEN REWRITE_TAC[COLLINEAR_BASIS_3] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[COLLINEAR_BASIS_3]) THEN
+  REWRITE_TAC[NOT_IMP; GSYM CONJ_ASSOC; DROPOUT_0] THEN
+  MATCH_MP_TAC OPEN_DROPOUT_3 THEN
+  UNDISCH_TAC `~((dropout 3:real^3->real^2) w1 = vec 0)` THEN
+  UNDISCH_TAC `~((dropout 3:real^3->real^2) w2 = vec 0)` THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) w2`,`v2:complex`) THEN
+  SPEC_TAC(`(dropout 3:real^3->real^2) w1`,`v1:complex`) THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN GEOM_BASIS_MULTIPLE_TAC 1 `v1:complex` THEN
+  X_GEN_TAC `v1:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `v1 = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+  REWRITE_TAC[COMPLEX_CMUL; COMPLEX_BASIS; COMPLEX_VEC_0] THEN
+  SIMP_TAC[ARG_DIV_CX; COMPLEX_MUL_RID] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[SET_RULE `{x | ~(x = a) /\ P x} = {x | P x} DIFF {a}`] THEN
+  MATCH_MP_TAC OPEN_DIFF THEN REWRITE_TAC[CLOSED_SING] THEN
+  MATCH_MP_TAC OPEN_ARG_LTT THEN
+  SIMP_TAC[REAL_LT_IMP_LE; REAL_LE_REFL; ARG]);;
+
+let ARG_EQ_SUBSET_HALFLINE = prove
+ (`!a. ?b. ~(b = vec 0) /\ {z | Arg z = a} SUBSET aff_ge {vec 0} {b}`,
+  GEN_TAC THEN ASM_CASES_TAC `{z | Arg z = a} SUBSET {vec 0}` THENL
+   [EXISTS_TAC `basis 1:real^2` THEN
+    SIMP_TAC[BASIS_NONZERO; DIMINDEX_2; ARITH] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       SUBSET_TRANS)) THEN SIMP_TAC[SUBSET; IN_SING; ENDS_IN_HALFLINE];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+   `~(s SUBSET {a}) ==> ?z. ~(a = z) /\ z IN s`)) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `z:complex` THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THEN
+  ASM_REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:complex` THEN
+  ASM_CASES_TAC `x:complex = vec 0` THEN ASM_REWRITE_TAC[ENDS_IN_HALFLINE] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[COMPLEX_VEC_0]) THEN ASM_SIMP_TAC[ARG_EQ] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[GSYM COMPLEX_CMUL] THEN
+  REWRITE_TAC[HALFLINE_EXPLICIT; IN_ELIM_THM; VECTOR_MUL_RZERO] THEN
+  MAP_EVERY EXISTS_TAC [`&1 - u`; `u:real`] THEN
+  ASM_SIMP_TAC[VECTOR_ADD_LID; REAL_LT_IMP_LE] THEN ASM_REAL_ARITH_TAC);;
+
+let ARG_DIV_EQ_SUBSET_HALFLINE = prove
+ (`!w a. ~(w = vec 0)
+         ==> ?b. ~(b = vec 0) /\
+                 {z | Arg(z / w) = a} SUBSET aff_ge {vec 0} {b}`,
+  REPEAT GEN_TAC THEN GEOM_BASIS_MULTIPLE_TAC 1 `w:complex` THEN
+  X_GEN_TAC `w:real` THEN ASM_CASES_TAC `w = &0` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LZERO; REAL_LE_LT] THEN DISCH_TAC THEN
+  X_GEN_TAC `a:real` THEN DISCH_THEN(K ALL_TAC) THEN
+  ASM_SIMP_TAC[ARG_DIV_CX; COMPLEX_CMUL; COMPLEX_BASIS; GSYM CX_MUL;
+               REAL_MUL_RID; ARG_EQ_SUBSET_HALFLINE]);;
+
+let COPLANAR_AZIM_EQ = prove
+ (`!v0 v1 w1 a.
+     (collinear{v0,v1,w1} ==> ~(a = &0))
+     ==> coplanar {z | azim v0 v1 w1 z = a}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `collinear{v0:real^3,v1,w1}` THENL
+   [ASM_SIMP_TAC[azim_def; EMPTY_GSPEC; COPLANAR_EMPTY]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN POP_ASSUM MP_TAC THEN
+  GEOM_ORIGIN_TAC `v0:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `v1:real^3` THEN
+  X_GEN_TAC `v1:real` THEN ASM_CASES_TAC `v1 = &0` THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_LE_LT; COLLINEAR_SPECIAL_SCALE] THEN REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; AZIM_ARG] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [COLLINEAR_BASIS_3]) THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN DISCH_THEN(X_CHOOSE_THEN `b:real^2`
+   STRIP_ASSUME_TAC o SPEC `a:real` o MATCH_MP ARG_DIV_EQ_SUBSET_HALFLINE) THEN
+  REWRITE_TAC[coplanar] THEN MAP_EVERY EXISTS_TAC
+   [`vec 0:real^3`; `pushin 3 (&0) (b:real^2):real^3`; `basis 3:real^3`] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+  REWRITE_TAC[AFFINE_HULL_3; HALFLINE; SUBSET; IN_ELIM_THM] THEN
+  DISCH_THEN(fun th -> X_GEN_TAC `x:real^3` THEN DISCH_TAC THEN
+   MP_TAC(SPEC `(dropout 3:real^3->real^2) x` th)) THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:real` STRIP_ASSUME_TAC) THEN
+  MAP_EVERY EXISTS_TAC [`&1 - v - (x:real^3)$3`; `v:real`; `(x:real^3)$3`] THEN
+  CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CART_EQ]) THEN
+  SIMP_TAC[CART_EQ; DIMINDEX_2; DIMINDEX_3; FORALL_2; FORALL_3; LAMBDA_BETA;
+           dropout; pushin; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; ARITH;
+           BASIS_COMPONENT] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Volume of a tetrahedron defined by conv0.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let delta_x = new_definition
+ `delta_x x1 x2 x3 x4 x5 x6 =
+        x1*x4*(--x1 + x2 + x3 -x4 + x5 + x6) +
+        x2*x5*(x1 - x2 + x3 + x4 -x5 + x6) +
+        x3*x6*(x1 + x2 - x3 + x4 + x5 - x6)
+        -x2*x3*x4 - x1*x3*x5 - x1*x2*x6 -x4*x5*x6:real`;;
+
+let VOLUME_OF_CLOSED_TETRAHEDRON = prove
+ (`!x1 x2 x3 x4:real^3.
+     measure(convex hull {x1,x2,x3,x4}) =
+     sqrt(delta_x (dist(x1,x2) pow 2) (dist(x1,x3) pow 2) (dist(x1,x4) pow 2)
+                  (dist(x3,x4) pow 2) (dist(x2,x4) pow 2) (dist(x2,x3) pow 2))
+      / &12`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[LET_DEF; LET_END_DEF] THEN
+  REWRITE_TAC[MEASURE_TETRAHEDRON] THEN
+  REWRITE_TAC[REAL_ARITH `x / &6 = y / &12 <=> y = &2 * x`] THEN
+  MATCH_MP_TAC SQRT_UNIQUE THEN
+  SIMP_TAC[REAL_LE_MUL; REAL_ABS_POS; REAL_POS] THEN
+  REWRITE_TAC[REAL_POW_MUL; REAL_POW2_ABS; delta_x] THEN
+  REWRITE_TAC[dist; NORM_POW_2] THEN
+  SIMP_TAC[DOT_3; VECTOR_SUB_COMPONENT; DIMINDEX_3; ARITH] THEN
+  CONV_TAC REAL_RING);;
+
+let VOLUME_OF_TETRAHEDRON = prove
+ (`!v1 v2 v3 v4:real^3.
+        measure(conv0 {v1,v2,v3,v4}) =
+            let x12 = dist(v1,v2) pow 2 in
+            let x13 = dist(v1,v3) pow 2 in
+            let x14 = dist(v1,v4) pow 2 in
+            let x23 = dist(v2,v3) pow 2 in
+            let x24 = dist(v2,v4) pow 2 in
+            let x34 = dist(v3,v4) pow 2 in
+            sqrt(delta_x x12 x13 x14 x34 x24 x23)/(&12)`,
+  REPEAT GEN_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  ASM_SIMP_TAC[GSYM VOLUME_OF_CLOSED_TETRAHEDRON] THEN
+  MATCH_MP_TAC MEASURE_CONV0_CONVEX_HULL THEN
+  SIMP_TAC[DIMINDEX_3; FINITE_INSERT; FINITE_EMPTY; CARD_CLAUSES] THEN
+  ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Circle area. Should maybe extend WLOG tactics for such scaling.           *)
+(* ------------------------------------------------------------------------- *)
+
+let AREA_UNIT_CBALL = prove
+ (`measure(cball(vec 0:real^2,&1)) = pi`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(INST_TYPE[`:1`,`:M`; `:2`,`:N`] FUBINI_SIMPLE_COMPACT) THEN
+  EXISTS_TAC `1` THEN
+  SIMP_TAC[DIMINDEX_1; DIMINDEX_2; ARITH; COMPACT_CBALL; SLICE_CBALL] THEN
+  REWRITE_TAC[VEC_COMPONENT; DROPOUT_0; REAL_SUB_RZERO] THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN REWRITE_TAC[MEASURE_EMPTY] THEN
+  SUBGOAL_THEN `!t. abs(t) <= &1 <=> t IN real_interval[-- &1,&1]`
+   (fun th -> REWRITE_TAC[th])
+  THENL [REWRITE_TAC[IN_REAL_INTERVAL] THEN REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[HAS_REAL_INTEGRAL_RESTRICT_UNIV; BALL_1] THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_EQ THEN
+  EXISTS_TAC `\t. &2 * sqrt(&1 - t pow 2)` THEN CONJ_TAC THENL
+   [X_GEN_TAC `t:real` THEN SIMP_TAC[IN_REAL_INTERVAL; MEASURE_INTERVAL] THEN
+    REWRITE_TAC[REAL_BOUNDS_LE; VECTOR_ADD_LID; VECTOR_SUB_LZERO] THEN
+    DISCH_TAC THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) CONTENT_1 o rand o snd) THEN
+    REWRITE_TAC[LIFT_DROP; DROP_NEG] THEN
+    ANTS_TAC THENL [ALL_TAC; SIMP_TAC[REAL_POW_ONE] THEN REAL_ARITH_TAC] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= x ==> --x <= x`) THEN
+    ASM_SIMP_TAC[SQRT_POS_LE; REAL_SUB_LE; GSYM REAL_LE_SQUARE_ABS;
+                 REAL_ABS_NUM];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`\x.  asn(x) + x * sqrt(&1 - x pow 2)`;
+    `\x. &2 * sqrt(&1 - x pow 2)`;
+    `-- &1`; `&1`] REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR) THEN
+  REWRITE_TAC[ASN_1; ASN_NEG_1] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[SQRT_0; REAL_MUL_RZERO; REAL_ADD_RID] THEN
+  REWRITE_TAC[REAL_ARITH `x / &2 - --(x / &2) = x`] THEN
+  DISCH_THEN MATCH_MP_TAC THEN CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_CONTINUOUS_ON_ADD THEN
+    SIMP_TAC[REAL_CONTINUOUS_ON_ASN; IN_REAL_INTERVAL; REAL_BOUNDS_LE] THEN
+    MATCH_MP_TAC REAL_CONTINUOUS_ON_MUL THEN
+    REWRITE_TAC[REAL_CONTINUOUS_ON_ID] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC REAL_CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[REAL_CONTINUOUS_ON_SUB; REAL_CONTINUOUS_ON_POW;
+             REAL_CONTINUOUS_ON_ID; REAL_CONTINUOUS_ON_CONST] THEN
+    MATCH_MP_TAC REAL_CONTINUOUS_ON_SQRT THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; IN_REAL_INTERVAL] THEN
+    REWRITE_TAC[REAL_ARITH `&0 <= &1 - x <=> x <= &1 pow 2`] THEN
+    REWRITE_TAC[GSYM REAL_LE_SQUARE_ABS; REAL_ABS_NUM] THEN
+    REAL_ARITH_TAC;
+    REWRITE_TAC[IN_REAL_INTERVAL; REAL_BOUNDS_LT] THEN REPEAT STRIP_TAC THEN
+    REAL_DIFF_TAC THEN
+    CONV_TAC NUM_REDUCE_CONV THEN
+    REWRITE_TAC[REAL_MUL_LID; REAL_POW_1; REAL_MUL_RID] THEN
+    REWRITE_TAC[REAL_SUB_LZERO; REAL_MUL_RNEG; REAL_INV_MUL] THEN
+    ASM_REWRITE_TAC[REAL_SUB_LT; ABS_SQUARE_LT_1] THEN
+    MATCH_MP_TAC(REAL_FIELD
+     `s pow 2 = &1 - x pow 2 /\ x pow 2 < &1
+      ==> (inv s + x * --(&2 * x) * inv (&2) * inv s + s) = &2 * s`) THEN
+    ASM_SIMP_TAC[ABS_SQUARE_LT_1; SQRT_POW_2; REAL_SUB_LE; REAL_LT_IMP_LE]]);;
+
+let AREA_CBALL = prove
+ (`!z:real^2 r. &0 <= r ==> measure(cball(z,r)) = pi * r pow 2`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `r = &0` THENL
+   [ASM_SIMP_TAC[CBALL_SING; REAL_POW_2; REAL_MUL_RZERO] THEN
+    MATCH_MP_TAC MEASURE_UNIQUE THEN
+    REWRITE_TAC[HAS_MEASURE_0; NEGLIGIBLE_SING];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `&0 < r` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  MP_TAC(ISPECL [`cball(vec 0:real^2,&1)`; `r:real`; `z:real^2`; `pi`]
+        HAS_MEASURE_AFFINITY) THEN
+  REWRITE_TAC[HAS_MEASURE_MEASURABLE_MEASURE; MEASURABLE_CBALL;
+              AREA_UNIT_CBALL] THEN
+  ASM_REWRITE_TAC[real_abs; DIMINDEX_2] THEN
+  DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [REAL_MUL_SYM] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[IN_CBALL_0; IN_IMAGE] THEN REWRITE_TAC[IN_CBALL] THEN
+  REWRITE_TAC[NORM_ARITH `dist(z,a + z) = norm a`; NORM_MUL] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `abs r * x <= r <=> abs r * x <= r * &1`] THEN
+  ASM_SIMP_TAC[real_abs; REAL_LE_LMUL; dist] THEN X_GEN_TAC `w:real^2` THEN
+  DISCH_TAC THEN EXISTS_TAC `inv(r) % (w - z):real^2` THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV] THEN
+  CONJ_TAC THENL [NORM_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[NORM_MUL; REAL_ABS_INV] THEN ASM_REWRITE_TAC[real_abs] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM real_div; REAL_LE_LDIV_EQ; REAL_MUL_LID] THEN
+  ONCE_REWRITE_TAC[NORM_SUB] THEN ASM_REWRITE_TAC[]);;
+
+let AREA_BALL = prove
+ (`!z:real^2 r. &0 <= r ==> measure(ball(z,r)) = pi * r pow 2`,
+  SIMP_TAC[GSYM INTERIOR_CBALL; GSYM AREA_CBALL] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_INTERIOR THEN
+  SIMP_TAC[BOUNDED_CBALL; NEGLIGIBLE_CONVEX_FRONTIER; CONVEX_CBALL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Volume of a ball.                                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let VOLUME_CBALL = prove
+ (`!z:real^3 r. &0 <= r ==> measure(cball(z,r)) = &4 / &3 * pi * r pow 3`,
+  GEOM_ORIGIN_TAC `z:real^3` THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(INST_TYPE[`:2`,`:M`; `:3`,`:N`] FUBINI_SIMPLE_COMPACT) THEN
+  EXISTS_TAC `1` THEN
+  SIMP_TAC[DIMINDEX_2; DIMINDEX_3; ARITH; COMPACT_CBALL; SLICE_CBALL] THEN
+  REWRITE_TAC[VEC_COMPONENT; DROPOUT_0; REAL_SUB_RZERO] THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN REWRITE_TAC[MEASURE_EMPTY] THEN
+  SUBGOAL_THEN `!t. abs(t) <= r <=> t IN real_interval[--r,r]`
+   (fun th -> REWRITE_TAC[th])
+  THENL [REWRITE_TAC[IN_REAL_INTERVAL] THEN REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[HAS_REAL_INTEGRAL_RESTRICT_UNIV] THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_EQ THEN
+  EXISTS_TAC `\t. pi * (r pow 2 - t pow 2)` THEN CONJ_TAC THENL
+   [X_GEN_TAC `t:real` THEN REWRITE_TAC[IN_REAL_INTERVAL; REAL_BOUNDS_LE] THEN
+    SIMP_TAC[AREA_CBALL; SQRT_POS_LE; REAL_SUB_LE; GSYM REAL_LE_SQUARE_ABS;
+             SQRT_POW_2; REAL_ARITH `abs x <= r ==> abs x <= abs r`];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`\t. pi * (r pow 2 * t - &1 / &3 * t pow 3)`;
+    `\t. pi * (r pow 2 - t pow 2)`;
+    `--r:real`; `r:real`] REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN
+    CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC REAL_RING;
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    CONV_TAC REAL_RING]);;
+
+let VOLUME_BALL = prove
+ (`!z:real^3 r. &0 <= r ==> measure(ball(z,r)) =  &4 / &3 * pi * r pow 3`,
+  SIMP_TAC[GSYM INTERIOR_CBALL; GSYM VOLUME_CBALL] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_INTERIOR THEN
+  SIMP_TAC[BOUNDED_CBALL; NEGLIGIBLE_CONVEX_FRONTIER; CONVEX_CBALL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Frustum.                                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let rconesgn = new_definition
+  `rconesgn sgn v w h =
+       {x:real^A | sgn ((x-v) dot (w-v)) (dist(x,v)*dist(w,v)*h)}`;;
+
+let rcone_gt = new_definition `rcone_gt = rconesgn ( > )`;;
+
+let rcone_ge = new_definition `rcone_ge = rconesgn ( >= )`;;
+
+let rcone_eq = new_definition `rcone_eq = rconesgn ( = )`;;
+
+let frustum = new_definition
+  `frustum v0 v1 h1 h2 a =
+     { y:real^N | rcone_gt v0 v1 a y /\
+                  let d = (y - v0) dot (v1 - v0) in
+                  let n = norm(v1 - v0) in
+                  (h1*n < d /\ d < h2*n)}`;;
+
+let frustt = new_definition `frustt v0 v1 h a = frustum v0 v1 (&0) h a`;;
+
+let FRUSTUM_DEGENERATE = prove
+ (`!v0 h1 h2 a. frustum v0 v0 h1 h2 a = {}`,
+  REWRITE_TAC[frustum; VECTOR_SUB_REFL; NORM_0; DOT_RZERO] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  REWRITE_TAC[REAL_MUL_RZERO; REAL_LT_REFL] THEN SET_TAC[]);;
+
+let CONVEX_RCONE_GT = prove
+ (`!v0 v1:real^N a. &0 <= a ==> convex(rcone_gt v0 v1 a)`,
+  REWRITE_TAC[rcone_gt; rconesgn] THEN
+  GEOM_ORIGIN_TAC `v0:real^N` THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; DIST_0] THEN
+  REWRITE_TAC[CONVEX_ALT; IN_ELIM_THM; real_gt; DOT_LADD; DOT_LMUL] THEN
+  DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`; `t:real`] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `(&1 - t) * norm(x:real^N) * norm v1 * a +
+              t * norm(y:real^N) * norm(v1:real^N) * a` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[GSYM REAL_ADD_RDISTRIB; REAL_MUL_ASSOC] THEN
+    MATCH_MP_TAC REAL_LE_RMUL THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `norm(x:real^N) = a /\ norm(y) = b ==> norm(x + y) <= a + b`) THEN
+    REWRITE_TAC[NORM_MUL] THEN CONJ_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    ASM_REAL_ARITH_TAC;
+    MATCH_MP_TAC REAL_CONVEX_BOUND2_LT THEN ASM_REAL_ARITH_TAC]);;
+
+let OPEN_RCONE_GT = prove
+ (`!v0 v1:real^N a. open(rcone_gt v0 v1 a)`,
+  REWRITE_TAC[rcone_gt; rconesgn] THEN
+  GEOM_ORIGIN_TAC `v0:real^N` THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; DIST_0] THEN
+  MP_TAC(ISPECL [`\x:real^N. lift(x dot v1 - norm x * norm v1 * a)`;
+                 `{x:real^1 | x$1 > &0}`]
+        CONTINUOUS_OPEN_PREIMAGE_UNIV) THEN
+  REWRITE_TAC[OPEN_HALFSPACE_COMPONENT_GT] THEN REWRITE_TAC[GSYM drop] THEN
+  REWRITE_TAC[IN_ELIM_THM; real_gt; REAL_SUB_LT; LIFT_DROP] THEN
+  DISCH_THEN MATCH_MP_TAC THEN GEN_TAC THEN REWRITE_TAC[LIFT_SUB] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[LIFT_CMUL] THEN
+  MATCH_MP_TAC CONTINUOUS_SUB THEN ONCE_REWRITE_TAC[DOT_SYM] THEN
+  REWRITE_TAC[REWRITE_RULE[o_DEF] CONTINUOUS_AT_LIFT_DOT] THEN
+  MATCH_MP_TAC CONTINUOUS_CMUL THEN
+  REWRITE_TAC[REWRITE_RULE[o_DEF] CONTINUOUS_AT_LIFT_NORM]);;
+
+let RCONE_GT_NEG = prove
+ (`!v0 v1:real^N a.
+        rcone_gt v0 v1 (--a) =
+         IMAGE (\x. &2 % v0 - x) ((:real^N) DIFF rcone_ge v0 v1 a)`,
+  REPEAT GEN_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MESON_TAC[VECTOR_ARITH `a - (a - b):real^N = b`];
+    REWRITE_TAC[rcone_gt; rconesgn; rcone_ge;
+                IN_ELIM_THM; IN_DIFF; IN_UNIV] THEN
+    REWRITE_TAC[NORM_ARITH `dist(&2 % x - y,x) = dist(y,x)`] THEN
+    REWRITE_TAC[VECTOR_ARITH `&2 % v - x - v:real^N = --(x - v)`] THEN
+    REWRITE_TAC[DOT_LNEG] THEN REAL_ARITH_TAC]);;
+
+let VOLUME_FRUSTT_STRONG = prove
+ (`!v0 v1:real^3 h a.
+       &0 < a
+       ==> bounded(frustt v0 v1 h a) /\
+           convex(frustt v0 v1 h a) /\
+           measurable(frustt v0 v1 h a) /\
+           measure(frustt v0 v1 h a) =
+           if v1 = v0 \/ &1 <= a \/ h < &0 then &0
+           else pi * ((h / a) pow 2 - h pow 2) * h / &3`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  REWRITE_TAC[frustt; frustum; rcone_gt; rconesgn; IN_ELIM_THM] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN GEOM_ORIGIN_TAC `v0:real^3` THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; REAL_MUL_LZERO; DIST_0; real_gt] THEN
+  GEOM_BASIS_MULTIPLE_TAC 1 `v1:real^3` THEN
+  X_GEN_TAC `b:real` THEN REPEAT(GEN_TAC ORELSE DISCH_TAC) THEN
+  FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+   `&0 <= x ==> x = &0 \/ &0 < x`)) THEN
+  ASM_REWRITE_TAC[DOT_RZERO; REAL_MUL_LZERO; REAL_MUL_RZERO; REAL_LT_REFL;
+    MEASURABLE_EMPTY; MEASURE_EMPTY; EMPTY_GSPEC; VECTOR_MUL_LZERO;
+    BOUNDED_EMPTY; CONVEX_EMPTY] THEN
+  ASM_CASES_TAC `&1 <= a` THEN ASM_REWRITE_TAC[] THENL
+   [SUBGOAL_THEN
+     `!y:real^3. ~(norm(y) * norm(b % basis 1:real^3) * a
+                   < y dot (b % basis 1))`
+     (fun th -> REWRITE_TAC[th; EMPTY_GSPEC; MEASURABLE_EMPTY;
+       BOUNDED_EMPTY; CONVEX_EMPTY; MEASURE_EMPTY]) THEN
+    REWRITE_TAC[REAL_NOT_LT] THEN X_GEN_TAC `y:real^3` THEN
+    MATCH_MP_TAC(REAL_ARITH `abs(x) <= a ==> x <= a`) THEN
+    SIMP_TAC[DOT_RMUL; NORM_MUL; REAL_ABS_MUL; DOT_BASIS; NORM_BASIS;
+             DIMINDEX_3; ARITH] THEN
+    REWRITE_TAC[REAL_ARITH
+     `b * y <= n * (b * &1) * a <=> b * &1 * y <= b * a * n`] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[REAL_ABS_POS] THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN
+    ASM_SIMP_TAC[REAL_POS; REAL_ABS_POS; COMPONENT_LE_NORM; DIMINDEX_3; ARITH];
+    ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LE]) THEN
+  SIMP_TAC[NORM_MUL; NORM_BASIS; DOT_BASIS; DOT_RMUL; DIMINDEX_3; ARITH] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `n * x * a:real = x * n * a`] THEN
+  ASM_REWRITE_TAC[real_abs; REAL_MUL_RID] THEN
+  ASM_SIMP_TAC[REAL_MUL_RID; REAL_LT_LMUL_EQ; REAL_LT_MUL_EQ; NORM_POS_LT] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0; BASIS_NONZERO; DIMINDEX_3; ARITH;
+               REAL_LT_IMP_NZ] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; NORM_LT_SQUARE] THEN
+  ASM_SIMP_TAC[REAL_POW_DIV; REAL_POW_LT; REAL_LT_RDIV_EQ] THEN
+  REWRITE_TAC[REAL_ARITH `(&0 * x < y /\ u < v) /\ &0 < y /\ y < h <=>
+                          &0 < y /\ y < h /\ u < v`] THEN
+  MATCH_MP_TAC(TAUT `a /\ b /\ (a /\ b ==> c) ==> a /\ b /\ c`) THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC BOUNDED_SUBSET THEN
+    EXISTS_TAC `ball(vec 0:real^3,h / a)` THEN
+    REWRITE_TAC[BOUNDED_BALL; IN_BALL_0; SUBSET; IN_ELIM_THM] THEN
+    REWRITE_TAC[NORM_LT_SQUARE] THEN
+    ASM_SIMP_TAC[REAL_POW_DIV; REAL_LT_RDIV_EQ; REAL_POW_LT] THEN
+    X_GEN_TAC `x:real^3` THEN STRIP_TAC THEN
+    CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+        (REWRITE_RULE[IMP_CONJ] REAL_LTE_TRANS)) THEN
+    MATCH_MP_TAC REAL_POW_LE2 THEN ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[SET_RULE `{x | P x /\ Q x /\ R x} =
+                          {x | Q x} INTER {x | P x /\ R x}`] THEN
+    REWRITE_TAC[REAL_ARITH `&0 < y <=> y > &0`] THEN
+    MATCH_MP_TAC CONVEX_INTER THEN
+    REWRITE_TAC[CONVEX_HALFSPACE_COMPONENT_LT] THEN
+    MP_TAC(ISPECL [`vec 0:real^3`; `basis 1:real^3`; `a:real`]
+        CONVEX_RCONE_GT) THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; rcone_gt; rconesgn] THEN
+    REWRITE_TAC[VECTOR_SUB_RZERO; DIST_0] THEN
+    SIMP_TAC[DOT_BASIS; NORM_BASIS; DIMINDEX_3; ARITH] THEN
+    REWRITE_TAC[real_gt; REAL_MUL_LID] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ] THEN
+    REWRITE_TAC[NORM_LT_SQUARE] THEN
+    ASM_SIMP_TAC[REAL_POW_DIV; REAL_LT_RDIV_EQ; REAL_POW_LT] THEN
+    REWRITE_TAC[REAL_MUL_LZERO];
+    ALL_TAC] THEN
+  STRIP_TAC THEN
+  MATCH_MP_TAC(INST_TYPE [`:2`,`:M`] FUBINI_SIMPLE_CONVEX_STRONG) THEN
+  EXISTS_TAC `1` THEN REWRITE_TAC[DIMINDEX_2; DIMINDEX_3; ARITH] THEN
+  ASM_REWRITE_TAC[] THEN
+  SIMP_TAC[SLICE_312; DIMINDEX_2; DIMINDEX_3; ARITH; IN_ELIM_THM;
+           VECTOR_3; DOT_3; GSYM DOT_2] THEN
+  SUBGOAL_THEN `&0 < inv(a pow 2) - &1` ASSUME_TAC THENL
+   [REWRITE_TAC[REAL_SUB_LT] THEN MATCH_MP_TAC REAL_INV_1_LT THEN
+    ASM_SIMP_TAC[REAL_POW_1_LT; REAL_LT_IMP_LE; ARITH; REAL_POW_LT];
+    ALL_TAC] THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_EQ THEN
+  EXISTS_TAC `\t. if &0 < t /\ t < h then pi * (inv(a pow 2) - &1) * t pow 2
+                  else &0` THEN
+  CONJ_TAC THENL
+   [X_GEN_TAC `t:real` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+    COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[EMPTY_GSPEC; CONJ_ASSOC;
+                    MEASURE_EMPTY; MEASURABLE_EMPTY] THEN
+    MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `measure(ball(vec 0:real^2,sqrt(inv(a pow 2) - &1) * t))` THEN
+    CONJ_TAC THENL
+     [W(MP_TAC o PART_MATCH (lhs o rand) AREA_BALL o rand o snd) THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE; SQRT_POS_LT; REAL_LT_MUL] THEN
+      ASM_SIMP_TAC[SQRT_POW_2; REAL_LT_IMP_LE; REAL_POW_MUL];
+      AP_TERM_TAC THEN REWRITE_TAC[IN_BALL_0; EXTENSION; IN_ELIM_THM] THEN
+      REWRITE_TAC[NORM_LT_SQUARE] THEN
+      ASM_SIMP_TAC[SQRT_POS_LT; SQRT_POW_2; REAL_LT_IMP_LE; REAL_LT_MUL;
+                   REAL_POW_MUL; GSYM REAL_LT_RDIV_EQ; REAL_POW_LT] THEN
+      REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  REWRITE_TAC[GSYM IN_REAL_INTERVAL; HAS_REAL_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_INTEGRAL_OPEN_INTERVAL] THEN
+  COND_CASES_TAC THENL
+   [ASM_MESON_TAC[REAL_INTERVAL_EQ_EMPTY; HAS_REAL_INTEGRAL_EMPTY];
+    RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LT])] THEN
+  MP_TAC(ISPECL
+   [`\t. pi / &3 * (inv (a pow 2) - &1) * t pow 3`;
+    `\t. pi * (inv (a pow 2) - &1) * t pow 2`;
+    `&0`; `h:real`] REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN
+    REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN
+    CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC REAL_RING;
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    UNDISCH_TAC `&0 < a` THEN CONV_TAC REAL_FIELD]);;
+
+let VOLUME_FRUSTT = prove
+ (`!v0 v1:real^3 h a.
+       &0 < a
+       ==> measurable(frustt v0 v1 h a) /\
+           measure(frustt v0 v1 h a) =
+           if v1 = v0 \/ &1 <= a \/ h < &0 then &0
+           else pi * ((h / a) pow 2 - h pow 2) * h / &3`,
+  SIMP_TAC[VOLUME_FRUSTT_STRONG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Ellipsoid.                                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let scale = new_definition
+  `scale (t:real^3) (u:real^3):real^3 =
+       vector[t$1 * u$1; t$2 * u$2; t$3 * u$3]`;;
+
+let normball = new_definition `normball x r = { y:real^A | dist(y,x) < r}`;;
+
+let ellipsoid = new_definition
+  `ellipsoid t r = IMAGE (scale t) (normball(vec 0) r)`;;
+
+let NORMBALL_BALL = prove
+ (`!z r. normball z r = ball(z,r)`,
+  REWRITE_TAC[normball; ball; DIST_SYM]);;
+
+let MEASURE_SCALE = prove
+ (`!s. measurable s
+       ==> measurable(IMAGE (scale t) s) /\
+           measure(IMAGE (scale t) s) = abs(t$1 * t$2 * t$3) * measure s`,
+  GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [HAS_MEASURE_MEASURE] THEN
+  DISCH_THEN(MP_TAC o SPEC `\i. (t:real^3)$i` o
+    MATCH_MP HAS_MEASURE_STRETCH) THEN
+  REWRITE_TAC[DIMINDEX_3; PRODUCT_3] THEN
+  SUBGOAL_THEN `(\x:real^3. (lambda k. t$k * x$k):real^3) = scale t`
+  SUBST1_TAC THENL
+   [SIMP_TAC[CART_EQ; FUN_EQ_THM; scale; LAMBDA_BETA; DIMINDEX_3;
+             VECTOR_3; ARITH; FORALL_3];
+    MESON_TAC[measurable; MEASURE_UNIQUE]]);;
+
+let MEASURE_ELLIPSOID = prove
+ (`!t r. &0 <= r
+         ==> measurable(ellipsoid t r) /\
+             measure(ellipsoid t r) =
+                abs(t$1 * t$2 * t$3) * &4 / &3 * pi * r pow 3`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM o
+    SPEC `vec 0:real^3` o MATCH_MP VOLUME_BALL) THEN
+  REWRITE_TAC[normball; ellipsoid] THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+  REWRITE_TAC[GSYM ball] THEN MATCH_MP_TAC MEASURE_SCALE THEN
+  REWRITE_TAC[MEASURABLE_BALL]);;
+
+let MEASURABLE_ELLIPSOID = prove
+ (`!t r. measurable(ellipsoid t r)`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `&0 <= r` THEN ASM_SIMP_TAC[MEASURE_ELLIPSOID] THEN
+  REWRITE_TAC[ellipsoid; NORMBALL_BALL; IMAGE; IN_BALL_0] THEN
+  ASM_SIMP_TAC[NORM_ARITH `~(&0 <= r) ==> ~(norm(x:real^3) < r)`] THEN
+  REWRITE_TAC[EMPTY_GSPEC; MEASURABLE_EMPTY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Conic cap.                                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let conic_cap = new_definition
+  `conic_cap v0 v1 r a = normball v0 r INTER rcone_gt v0 v1 a`;;
+
+let CONIC_CAP_DEGENERATE = prove
+ (`!v0 r a. conic_cap v0 v0 r a = {}`,
+  REWRITE_TAC[conic_cap; rcone_gt; rconesgn; VECTOR_SUB_REFL] THEN
+  REWRITE_TAC[DIST_REFL; DOT_RZERO; REAL_MUL_RZERO; REAL_MUL_LZERO] THEN
+  REWRITE_TAC[real_gt; REAL_LT_REFL] THEN SET_TAC[]);;
+
+let BOUNDED_CONIC_CAP = prove
+ (`!v0 v1:real^3 r a. bounded(conic_cap v0 v1 r a)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[conic_cap; NORMBALL_BALL] THEN
+  MATCH_MP_TAC BOUNDED_SUBSET THEN EXISTS_TAC `ball(v0:real^3,r)` THEN
+  REWRITE_TAC[BOUNDED_BALL] THEN SET_TAC[]);;
+
+let MEASURABLE_CONIC_CAP = prove
+ (`!v0 v1:real^3 r a. measurable(conic_cap v0 v1 r a)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[conic_cap; NORMBALL_BALL] THEN
+  MATCH_MP_TAC MEASURABLE_OPEN THEN
+  SIMP_TAC[OPEN_INTER; OPEN_RCONE_GT; OPEN_BALL] THEN
+  MATCH_MP_TAC BOUNDED_SUBSET THEN EXISTS_TAC `ball(v0:real^3,r)` THEN
+  REWRITE_TAC[BOUNDED_BALL] THEN SET_TAC[]);;
+
+let VOLUME_CONIC_CAP_STRONG = prove
+ (`!v0 v1:real^3 r a.
+       &0 < a
+       ==> bounded(conic_cap v0 v1 r a) /\
+           convex(conic_cap v0 v1 r a) /\
+           measurable(conic_cap v0 v1 r a) /\
+           measure(conic_cap v0 v1 r a) =
+             if v1 = v0 \/ &1 <= a \/ r < &0 then &0
+             else &2 / &3 * pi * (&1 - a) * r pow 3`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  REWRITE_TAC[conic_cap; rcone_gt; rconesgn; IN_ELIM_THM] THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] normball; GSYM ball] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN GEOM_ORIGIN_TAC `v0:real^3` THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; REAL_MUL_LZERO; DIST_0; real_gt] THEN
+  GEOM_BASIS_MULTIPLE_TAC 1 `v1:real^3` THEN
+  X_GEN_TAC `b:real` THEN REPEAT(GEN_TAC ORELSE DISCH_TAC) THEN
+  FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+   `&0 <= x ==> x = &0 \/ &0 < x`))
+  THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; GSYM REAL_NOT_LE; DOT_RZERO] THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE; NORM_POS_LE] THEN
+    REWRITE_TAC[EMPTY_GSPEC; INTER_EMPTY; MEASURE_EMPTY; MEASURABLE_EMPTY;
+                CONVEX_EMPTY; BOUNDED_EMPTY];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `&1 <= a` THEN ASM_REWRITE_TAC[] THENL
+   [SUBGOAL_THEN
+     `!y:real^3. ~(norm(y) * norm(b % basis 1:real^3) * a
+                   < y dot (b % basis 1))`
+     (fun th -> REWRITE_TAC[th; EMPTY_GSPEC; INTER_EMPTY; MEASURE_EMPTY;
+                         MEASURABLE_EMPTY; BOUNDED_EMPTY; CONVEX_EMPTY]) THEN
+    REWRITE_TAC[REAL_NOT_LT] THEN X_GEN_TAC `y:real^3` THEN
+    MATCH_MP_TAC(REAL_ARITH `abs(x) <= a ==> x <= a`) THEN
+    SIMP_TAC[DOT_RMUL; NORM_MUL; REAL_ABS_MUL; DOT_BASIS; NORM_BASIS;
+             DIMINDEX_3; ARITH] THEN
+    REWRITE_TAC[REAL_ARITH
+     `b * y <= n * (b * &1) * a <=> b * &1 * y <= b * a * n`] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[REAL_ABS_POS] THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN
+    ASM_SIMP_TAC[REAL_POS; REAL_ABS_POS; COMPONENT_LE_NORM; DIMINDEX_3; ARITH];
+    ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LE]) THEN
+  SIMP_TAC[DOT_RMUL; NORM_MUL; REAL_ABS_NORM; DOT_BASIS;
+           DIMINDEX_3; ARITH; NORM_BASIS] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `n * x * a:real = x * n * a`] THEN
+  ASM_REWRITE_TAC[real_abs; REAL_MUL_RID] THEN
+  ASM_SIMP_TAC[REAL_MUL_RID; REAL_LT_LMUL_EQ; REAL_LT_MUL_EQ; NORM_POS_LT] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; NORM_LT_SQUARE] THEN
+  ASM_SIMP_TAC[REAL_POW_DIV; REAL_POW_LT; REAL_LT_RDIV_EQ] THEN
+  REWRITE_TAC[INTER; REAL_MUL_LZERO; IN_BALL_0; IN_ELIM_THM] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0; BASIS_NONZERO; DIMINDEX_3; ARITH;
+               REAL_LT_IMP_NZ] THEN
+  COND_CASES_TAC THENL
+   [ASM_SIMP_TAC[NORM_ARITH `r < &0 ==> ~(norm x < r)`] THEN
+    REWRITE_TAC[EMPTY_GSPEC; MEASURE_EMPTY; MEASURABLE_EMPTY;
+                BOUNDED_EMPTY; CONVEX_EMPTY];
+    RULE_ASSUM_TAC(ONCE_REWRITE_RULE[REAL_NOT_LT])] THEN
+  MATCH_MP_TAC(TAUT `a /\ b /\ (a /\ b ==> c /\ d) ==> a /\ b /\ c /\ d`) THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC BOUNDED_SUBSET THEN
+    EXISTS_TAC `ball(vec 0:real^3,r)` THEN
+    SIMP_TAC[BOUNDED_BALL; IN_BALL_0; SUBSET; IN_ELIM_THM];
+    ONCE_REWRITE_TAC[SET_RULE
+      `{x | P x /\ Q x} = {x | P x} INTER {x | Q x}`] THEN
+    MATCH_MP_TAC CONVEX_INTER THEN
+    REWRITE_TAC[GSYM IN_BALL_0; CONVEX_BALL; SIMPLE_IMAGE; IMAGE_ID] THEN
+    MP_TAC(ISPECL [`vec 0:real^3`; `basis 1:real^3`; `a:real`]
+        CONVEX_RCONE_GT) THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; rcone_gt; rconesgn] THEN
+    REWRITE_TAC[VECTOR_SUB_RZERO; DIST_0] THEN
+    SIMP_TAC[DOT_BASIS; NORM_BASIS; DIMINDEX_3; ARITH] THEN
+    REWRITE_TAC[real_gt; REAL_MUL_LID] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ] THEN
+    REWRITE_TAC[NORM_LT_SQUARE] THEN
+    ASM_SIMP_TAC[REAL_POW_DIV; REAL_LT_RDIV_EQ; REAL_POW_LT] THEN
+    REWRITE_TAC[REAL_MUL_LZERO];
+    STRIP_TAC] THEN
+  MATCH_MP_TAC(INST_TYPE [`:2`,`:M`] FUBINI_SIMPLE_CONVEX_STRONG) THEN
+  EXISTS_TAC `1` THEN ASM_REWRITE_TAC[DIMINDEX_2; DIMINDEX_3; ARITH] THEN
+  SIMP_TAC[SLICE_312; DIMINDEX_2; DIMINDEX_3; ARITH; IN_ELIM_THM;
+           VECTOR_3; DOT_3; GSYM DOT_2] THEN
+  SUBGOAL_THEN `&0 < inv(a pow 2) - &1` ASSUME_TAC THENL
+   [REWRITE_TAC[REAL_SUB_LT] THEN MATCH_MP_TAC REAL_INV_1_LT THEN
+    ASM_SIMP_TAC[REAL_POW_1_LT; REAL_LT_IMP_LE; ARITH; REAL_POW_LT];
+    ALL_TAC] THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_EQ THEN
+  EXISTS_TAC `\t. if &0 < t /\ t < r
+                  then measure
+                    {y:real^2 | norm(vector[t; y$1; y$2]:real^3) pow 2
+                                 < r pow 2 /\
+                                (t * t + y dot y) * a pow 2 < t pow 2}
+                  else &0` THEN
+  CONJ_TAC THENL
+   [X_GEN_TAC `t:real` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+    ASM_CASES_TAC `&0 < t` THEN
+    ASM_REWRITE_TAC[EMPTY_GSPEC; MEASURE_EMPTY; MEASURABLE_EMPTY] THEN
+    ASM_CASES_TAC `t:real < r` THEN ASM_REWRITE_TAC[] THENL
+     [REWRITE_TAC[NORM_LT_SQUARE] THEN
+      SUBGOAL_THEN `&0 < r` (fun th -> REWRITE_TAC[th; NORM_POW_2]) THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN `!y. ~(norm(vector[t; (y:real^2)$1; y$2]:real^3) < r)`
+     (fun th -> REWRITE_TAC[th; EMPTY_GSPEC; MEASURE_EMPTY;
+                            MEASURABLE_EMPTY]) THEN
+    ASM_REWRITE_TAC[NORM_LT_SQUARE; DOT_3; VECTOR_3] THEN
+    GEN_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= a /\ &0 <= b /\ c <= d
+                             ==> ~(&0 < r /\ d + a + b < c)`) THEN
+    REWRITE_TAC[REAL_LE_SQUARE] THEN
+    REWRITE_TAC[REAL_POW_2] THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[GSYM IN_REAL_INTERVAL; HAS_REAL_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_INTEGRAL_OPEN_INTERVAL] THEN
+  REWRITE_TAC[NORM_POW_2; DOT_3; VECTOR_3; DOT_2] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH
+   `pi * &2 / &3 * (&1 - a) * r pow 3 =
+    pi / &3 * (inv (a pow 2) - &1) * (a * r) pow 3 +
+    (pi * &2 / &3 * (&1 - a) * r pow 3 -
+     pi / &3 * (inv (a pow 2) - &1) * (a * r) pow 3)`] THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_COMBINE THEN
+  EXISTS_TAC `a * r:real` THEN
+  REWRITE_TAC[REAL_ARITH `a * r <= r <=> &0 <= r * (&1 - a)`] THEN
+  ASM_SIMP_TAC[REAL_LE_MUL; REAL_SUB_LE; REAL_LT_IMP_LE] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HAS_REAL_INTEGRAL_EQ THEN EXISTS_TAC
+     `\t. measure(ball(vec 0:real^2,sqrt(inv(a pow 2) - &1) * t))` THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `t:real` THEN REWRITE_TAC[IN_REAL_INTERVAL] THEN
+      STRIP_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+      REWRITE_TAC[IN_BALL_0; NORM_LT_SQUARE_ALT] THEN
+      ASM_SIMP_TAC[SQRT_POS_LE; REAL_LE_MUL; SQRT_POW_2; REAL_LT_IMP_LE;
+                   REAL_POW_MUL] THEN
+      REWRITE_TAC[REAL_ARITH `x < (a - &1) * t <=> t + x < t * a`] THEN
+      ASM_SIMP_TAC[GSYM real_div; REAL_LT_RDIV_EQ; REAL_POW_LT] THEN
+      X_GEN_TAC `x:real^2` THEN REWRITE_TAC[DOT_2] THEN
+      ASM_SIMP_TAC[GSYM REAL_POW_2; GSYM REAL_LT_RDIV_EQ; REAL_POW_LT] THEN
+      MATCH_MP_TAC(REAL_ARITH `b <= a ==> (x < b <=> x < a /\ x < b)`) THEN
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_POW_LT; GSYM REAL_POW_MUL] THEN
+      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+      REWRITE_TAC[GSYM REAL_LE_SQUARE_ABS] THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC HAS_REAL_INTEGRAL_EQ THEN
+    EXISTS_TAC `\t. pi * (inv(a pow 2) - &1) * t pow 2` THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `t:real` THEN REWRITE_TAC[IN_REAL_INTERVAL] THEN
+      STRIP_TAC THEN
+      W(MP_TAC o PART_MATCH (lhs o rand) AREA_BALL o rand o snd) THEN
+      ASM_SIMP_TAC[REAL_POW_MUL; REAL_LT_IMP_LE; SQRT_POS_LT; REAL_LE_MUL;
+                   SQRT_POW_2];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`\t. pi / &3 * (inv (a pow 2) - &1) * t pow 3`;
+      `\t. pi * (inv (a pow 2) - &1) * t pow 2`;
+      `&0`; `a * r:real`] REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS) THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE] THEN ANTS_TAC THENL
+     [ASM_REWRITE_TAC[] THEN
+      REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN
+      CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC REAL_RING;
+      MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+      UNDISCH_TAC `&0 < a` THEN CONV_TAC REAL_FIELD];
+    MATCH_MP_TAC HAS_REAL_INTEGRAL_EQ THEN EXISTS_TAC
+     `\t. measure(ball(vec 0:real^2,sqrt(r pow 2 - t pow 2)))` THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `t:real` THEN REWRITE_TAC[IN_REAL_INTERVAL] THEN
+      STRIP_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+      REWRITE_TAC[IN_BALL_0; NORM_LT_SQUARE_ALT] THEN
+      SUBGOAL_THEN `&0 <= t` ASSUME_TAC THENL
+       [MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `a * r:real` THEN
+        ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE];
+        ALL_TAC] THEN
+      ASM_SIMP_TAC[SQRT_POS_LE; SQRT_POW_2; REAL_SUB_LE; REAL_POW_LE2] THEN
+      X_GEN_TAC `x:real^2` THEN REWRITE_TAC[DOT_2] THEN
+      REWRITE_TAC[REAL_ARITH `x < r - t <=> t + x < r`] THEN
+      ASM_SIMP_TAC[GSYM REAL_POW_2; GSYM REAL_LT_RDIV_EQ; REAL_POW_LT] THEN
+      MATCH_MP_TAC(REAL_ARITH `a <= b ==> (x < a <=> x < a /\ x < b)`) THEN
+      ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_POW_LT; GSYM REAL_POW_MUL] THEN
+      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+      ASM_SIMP_TAC[REAL_POW_LE2; REAL_LE_MUL; REAL_LT_IMP_LE];
+      ALL_TAC] THEN
+    MATCH_MP_TAC HAS_REAL_INTEGRAL_EQ THEN
+    EXISTS_TAC `\t. pi * (r pow 2 - t pow 2)` THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `t:real` THEN REWRITE_TAC[IN_REAL_INTERVAL] THEN
+      STRIP_TAC THEN
+      W(MP_TAC o PART_MATCH (lhs o rand) AREA_BALL o rand o snd) THEN
+      SUBGOAL_THEN `&0 <= t` ASSUME_TAC THENL
+       [MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `a * r:real` THEN
+        ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE];
+        ALL_TAC] THEN
+      ASM_SIMP_TAC[SQRT_POS_LE; SQRT_POW_2; REAL_SUB_LE; REAL_POW_LE2];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`\t. pi * (r pow 2 * t - t pow 3 / &3)`;
+      `\t. pi * (r pow 2 - t pow 2)`;
+      `a * r:real`; `r:real`] REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS) THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE] THEN ANTS_TAC THENL
+     [ASM_REWRITE_TAC[REAL_ARITH `a * r <= r <=> &0 <= r * (&1 - a)`] THEN
+      ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE; REAL_SUB_LE] THEN
+      REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN
+      CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC REAL_RING;
+      MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+      UNDISCH_TAC `&0 < a` THEN CONV_TAC REAL_FIELD]]);;
+
+let VOLUME_CONIC_CAP = prove
+ (`!v0 v1:real^3 r a.
+       &0 < a
+       ==> measurable(conic_cap v0 v1 r a) /\ measure(conic_cap v0 v1 r a) =
+           if v1 = v0 \/ &1 <= a \/ r < &0 then &0
+           else &2 / &3 * pi * (&1 - a) * r pow 3`,
+  SIMP_TAC[VOLUME_CONIC_CAP_STRONG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Negligibility of a circular cone.                                         *)
+(* This isn't exactly using the Flyspeck definition of "cone" but we use it  *)
+(* to get that later on. Could now simplify this using WLOG tactics.         *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_CIRCULAR_CONE_0_NONPARALLEL = prove
+ (`!c:real^N k. ~(c = vec 0) /\ ~(k = &0) /\ ~(k = pi)
+                ==> negligible {x | vector_angle c x = k}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `(vec 0:real^N) INSERT
+              UNIONS { {x | x IN ((:real^N) DIFF ball(vec 0,inv(&n + &1))) /\
+                            Cx(vector_angle c x) = Cx k} |
+                       n IN (:num)  }` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[SUBSET; IN_INSERT; IN_UNIONS; IN_ELIM_THM; CX_INJ] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN REWRITE_TAC[IN_UNIV] THEN
+    ASM_CASES_TAC `x:real^N = vec 0` THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[LEFT_AND_EXISTS_THM; IN_DIFF; IN_UNIV] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN REWRITE_TAC[UNWIND_THM2] THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM] THEN
+    MP_TAC(SPEC `norm(x:real^N)` REAL_ARCH_INV) THEN
+    ASM_REWRITE_TAC[NORM_POS_LT; IN_BALL_0; REAL_NOT_LT; REAL_LT_INV_EQ] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `inv(&n)` THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+    ASM_REAL_ARITH_TAC] THEN
+  REWRITE_TAC[NEGLIGIBLE_INSERT] THEN
+  MATCH_MP_TAC NEGLIGIBLE_COUNTABLE_UNIONS THEN X_GEN_TAC `n:num` THEN
+  MATCH_MP_TAC STARLIKE_NEGLIGIBLE_STRONG THEN EXISTS_TAC `c:real^N` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE_CONSTANT THEN
+    SIMP_TAC[CLOSED_DIFF; CLOSED_UNIV; OPEN_BALL] THEN
+    MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_CX_VECTOR_ANGLE) THEN
+    REWRITE_TAC[IN_DIFF; IN_BALL_0; NORM_0; IN_UNIV] THEN
+    REWRITE_TAC[REAL_LT_INV_EQ] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`a:real`; `x:real^N`] THEN
+  SIMP_TAC[IN_ELIM_THM; IN_UNIV; IN_DIFF; IN_BALL_0; REAL_NOT_LT; CX_INJ] THEN
+  REWRITE_TAC[DE_MORGAN_THM] THEN ASM_CASES_TAC `(c + x:real^N) = vec 0` THENL
+   [ASM_REWRITE_TAC[GSYM REAL_NOT_LT; REAL_LT_INV_EQ; NORM_0] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_CASES_TAC `c + a % x:real^N = vec 0` THENL
+   [ASM_REWRITE_TAC[GSYM REAL_NOT_LT; REAL_LT_INV_EQ; NORM_0] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_CASES_TAC `x:real^N = vec 0` THENL
+   [ASM_REWRITE_TAC[VECTOR_ADD_RID; VECTOR_ANGLE_REFL];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `a = &0` THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_RID; VECTOR_ANGLE_REFL];
+    ALL_TAC] THEN
+  REWRITE_TAC[TAUT `~a \/ ~b <=> a ==> ~b`] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`vec 0:real^N`; `c:real^N`; `c + a % x:real^N`;
+                 `vec 0:real^N`; `c:real^N`; `c + x:real^N`]
+                CONGRUENT_TRIANGLES_ASA_FULL) THEN
+  REWRITE_TAC[angle; VECTOR_ADD_SUB] THEN ASM_SIMP_TAC[VECTOR_SUB_RZERO] THEN
+  REWRITE_TAC[NORM_ARITH `dist(x,x + a) = norm(a)`; NORM_MUL] THEN
+  REWRITE_TAC[REAL_FIELD `a * x = x <=> a = &1 \/ x = &0`] THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 <= a /\ a < &1 ==> ~(abs a = &1)`] THEN
+  ASM_REWRITE_TAC[NORM_EQ_0; VECTOR_ANGLE_RMUL; COLLINEAR_LEMMA] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real` MP_TAC) THEN
+  DISCH_THEN(MP_TAC o AP_TERM `\x:real^N. inv(a) % x`) THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; VECTOR_ADD_LDISTRIB;
+               VECTOR_MUL_LID; REAL_MUL_LINV] THEN
+  REWRITE_TAC[VECTOR_ARITH `a % c + x = b % c <=> x = (b - a) % c`] THEN
+  DISCH_THEN SUBST_ALL_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[VECTOR_ARITH `c + a % c = (a + &1) % c`]) THEN
+  UNDISCH_TAC `vector_angle c ((inv a * u - inv a + &1) % c:real^N) = k` THEN
+  RULE_ASSUM_TAC(REWRITE_RULE
+   [VECTOR_ANGLE_RMUL; VECTOR_MUL_EQ_0; DE_MORGAN_THM]) THEN
+  ASM_REWRITE_TAC[VECTOR_ANGLE_RMUL; VECTOR_ANGLE_REFL] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let NEGLIGIBLE_CIRCULAR_CONE_0 = prove
+ (`!c:real^N k. 2 <= dimindex(:N) /\ ~(c = vec 0)
+                ==> negligible {x | vector_angle c x = k}`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `orthogonal (basis 1:real^N) (basis 2)` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[ORTHOGONAL_BASIS_BASIS; ARITH;
+                 ARITH_RULE `2 <= d ==> 1 <= d`];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `k = &0 \/ k = pi` THENL
+   [ALL_TAC; ASM_MESON_TAC[NEGLIGIBLE_CIRCULAR_CONE_0_NONPARALLEL]] THEN
+  SUBGOAL_THEN
+   `?b:real^N. ~(b = vec 0) /\
+               ~(vector_angle c b = &0) /\
+               ~(vector_angle c b = pi)`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC(MESON[] `!a b. P a \/ P b ==> ?x. P x`) THEN
+    MAP_EVERY EXISTS_TAC [`basis 1:real^N`; `basis 2:real^N`] THEN
+    REWRITE_TAC[BASIS_EQ_0] THEN
+    ASM_SIMP_TAC[ARITH_RULE `2 <= d ==> 1 <= d`; IN_NUMSEG; ARITH] THEN
+    REWRITE_TAC[GSYM DE_MORGAN_THM] THEN STRIP_TAC THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `basis 1:real^N` o
+      MATCH_MP VECTOR_ANGLE_EQ_0_LEFT)) THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `basis 1:real^N` o
+      MATCH_MP VECTOR_ANGLE_EQ_PI_LEFT)) THEN
+    DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[VECTOR_ANGLE_REFL; BASIS_EQ_0] THEN
+    ASM_SIMP_TAC[ARITH_RULE `2 <= d ==> 1 <= d`; IN_NUMSEG; ARITH] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ORTHOGONAL_VECTOR_ANGLE]) THEN
+    REWRITE_TAC[VECTOR_ANGLE_SYM] THEN MP_TAC PI_POS THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_CASES_TAC `k = &0 \/ k = pi` THENL
+   [ALL_TAC; ASM_MESON_TAC[NEGLIGIBLE_CIRCULAR_CONE_0_NONPARALLEL]] THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  FIRST_X_ASSUM(DISJ_CASES_THEN SUBST_ALL_TAC) THENL
+   [EXISTS_TAC `{x:real^N | vector_angle b x = vector_angle c b}` THEN
+    ASM_SIMP_TAC[NEGLIGIBLE_CIRCULAR_CONE_0_NONPARALLEL] THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+    MESON_TAC[VECTOR_ANGLE_EQ_0_RIGHT; VECTOR_ANGLE_SYM];
+    EXISTS_TAC `{x:real^N | vector_angle b x = pi - vector_angle c b}` THEN
+    ASM_SIMP_TAC[NEGLIGIBLE_CIRCULAR_CONE_0_NONPARALLEL;
+                 REAL_SUB_0; REAL_ARITH `p - x = p <=> x = &0`] THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+    MESON_TAC[VECTOR_ANGLE_EQ_PI_RIGHT; VECTOR_ANGLE_SYM]]);;
+
+let NEGLIGIBLE_CIRCULAR_CONE = prove
+ (`!a:real^N c k.
+      2 <= dimindex(:N) /\ ~(c = vec 0)
+      ==> negligible(a INSERT {x | vector_angle c (x - a) = k})`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[NEGLIGIBLE_INSERT] THEN
+  MATCH_MP_TAC NEGLIGIBLE_TRANSLATION_REV THEN EXISTS_TAC `--a:real^N` THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `{x:real^N | vector_angle c x = k}` THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_CIRCULAR_CONE_0] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+  REWRITE_TAC[VECTOR_ARITH `--a + x:real^N = x - a`]);;
+
+let NEGLIGIBLE_RCONE_EQ = prove
+ (`!w z:real^3 h. ~(w = z) ==> negligible(rcone_eq z w h)`,
+  REWRITE_TAC[rcone_eq; rconesgn] THEN GEOM_ORIGIN_TAC `z:real^3` THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[DIST_0; VECTOR_SUB_RZERO] THEN
+  ASM_CASES_TAC `abs(h) <= &1` THENL
+   [MP_TAC(ISPECL [`w:real^3`; `acs h`] NEGLIGIBLE_CIRCULAR_CONE_0) THEN
+    ASM_REWRITE_TAC[DIMINDEX_3; ARITH] THEN
+    REWRITE_TAC[GSYM HAS_MEASURE_0] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT]
+      HAS_MEASURE_NEGLIGIBLE_SYMDIFF) THEN
+    MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC `{vec 0:real^3}` THEN
+    REWRITE_TAC[NEGLIGIBLE_SING] THEN MATCH_MP_TAC(SET_RULE
+     `(!x. ~(x = a) ==> (x IN s <=> x IN t))
+      ==> (s DIFF t) UNION (t DIFF s) SUBSET {a}`) THEN
+    X_GEN_TAC `x:real^3` THEN DISCH_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    ASM_SIMP_TAC[vector_angle] THEN ASM_SIMP_TAC[NORM_EQ_0; REAL_FIELD
+     `~(x = &0) /\ ~(w = &0) ==> (a = x * w * b <=> a / (w * x) = b)`] THEN
+    GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [DOT_SYM] THEN
+    MATCH_MP_TAC ACS_INJ THEN ASM_REWRITE_TAC[NORM_CAUCHY_SCHWARZ_DIV];
+    MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+    EXISTS_TAC `{vec 0}:real^3->bool` THEN
+    REWRITE_TAC[NEGLIGIBLE_SING] THEN
+    REWRITE_TAC[SET_RULE `{x | P x} SUBSET {a} <=> !x. ~(x = a) ==> ~P x`] THEN
+    X_GEN_TAC `x:real^3` THEN REPEAT DISCH_TAC THEN
+    MP_TAC(ISPECL [`x:real^3`; `w:real^3`] NORM_CAUCHY_SCHWARZ_ABS) THEN
+    ASM_REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_NORM; REAL_ARITH
+     `~(x * w * h <= x * w) <=> &0 < x * w * (h - &1)`] THEN
+    REPEAT(MATCH_MP_TAC REAL_LT_MUL THEN ASM_REWRITE_TAC[NORM_POS_LT]) THEN
+    ASM_REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Area of sector of a circle delimited by Arg values.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_ARG_EQ = prove
+ (`!t. negligible {z | Arg z = t}`,
+  GEN_TAC THEN MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `{z | cexp(ii * Cx(pi / &2 + t)) dot z = &0}` THEN
+  SIMP_TAC[NEGLIGIBLE_HYPERPLANE; COMPLEX_VEC_0; CEXP_NZ] THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN X_GEN_TAC `z:complex` THEN
+  DISCH_TAC THEN MP_TAC(SPEC `z:complex` ARG) THEN ASM_REWRITE_TAC[] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[GSYM COMPLEX_CMUL; DOT_RMUL; REAL_ENTIRE] THEN
+  DISJ2_TAC THEN REWRITE_TAC[CEXP_EULER] THEN
+  REWRITE_TAC[DOT_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REWRITE_TAC[GSYM CX_SIN; GSYM CX_COS; RE_ADD; IM_ADD;
+              RE_MUL_II; IM_MUL_II; RE_CX; IM_CX] THEN
+  REWRITE_TAC[SIN_ADD; COS_ADD; SIN_PI2; COS_PI2] THEN
+  REAL_ARITH_TAC);;
+
+let MEASURABLE_CLOSED_SECTOR_LE = prove
+ (`!r t. measurable {z | norm(z) <= r /\ Arg z <= t}`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC MEASURABLE_COMPACT THEN
+  REWRITE_TAC[SET_RULE `{z | P z /\ Q z} = {z | P z} INTER {z | Q z}`] THEN
+  MATCH_MP_TAC COMPACT_INTER_CLOSED THEN REWRITE_TAC[CLOSED_ARG_LE] THEN
+  REWRITE_TAC[NORM_ARITH `norm z = dist(vec 0,z)`; GSYM cball] THEN
+  REWRITE_TAC[COMPACT_CBALL]);;
+
+let MEASURABLE_CLOSED_SECTOR_LT = prove
+ (`!r t. measurable {z | norm(z) <= r /\ Arg z < t}`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC MEASURABLE_NEGLIGIBLE_SYMDIFF THEN
+  EXISTS_TAC `{z | norm(z) <= r /\ Arg z <= t}` THEN
+  REWRITE_TAC[MEASURABLE_CLOSED_SECTOR_LE] THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `{z | Arg z = t}` THEN
+  REWRITE_TAC[NEGLIGIBLE_ARG_EQ; NEGLIGIBLE_UNION_EQ] THEN
+  REWRITE_TAC[SUBSET; IN_DIFF; IN_UNION; IN_ELIM_THM] THEN REAL_ARITH_TAC);;
+
+let MEASURABLE_CLOSED_SECTOR_LTE = prove
+ (`!r s t. measurable {z | norm(z) <= r /\ s < Arg z /\ Arg z <= t}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[SET_RULE
+   `{z | P z /\ Q z /\ R z} = {z | P z /\ R z} DIFF {z | P z /\ ~Q z}`] THEN
+  SIMP_TAC[MEASURABLE_DIFF; REAL_NOT_LT; MEASURABLE_CLOSED_SECTOR_LE]);;
+
+let MEASURE_CLOSED_SECTOR_LE = prove
+ (`!t r. &0 <= r /\ &0 <= t /\ t <= &2 * pi
+         ==> measure {x:real^2 | norm(x) <= r /\ Arg(x) <= t} =
+             t * r pow 2 / &2`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`\t. measure {z:real^2 | norm(z) <= r /\ Arg(z) <= t}`;
+    `&2 * pi`] REAL_CONTINUOUS_ADDITIVE_IMP_LINEAR_INTERVAL) THEN
+  ANTS_TAC THENL
+   [ALL_TAC;
+    DISCH_THEN(MP_TAC o SPECL [`t / (&2 * pi)`; `&2 * pi`]) THEN
+    MP_TAC(SPECL [`vec 0:real^2`; `r:real`] AREA_CBALL) THEN
+    ASM_REWRITE_TAC[cball; NORM_ARITH `dist(vec 0,z) = norm z`] THEN
+    SIMP_TAC[ARG; REAL_LT_IMP_LE] THEN DISCH_THEN(K ALL_TAC) THEN
+    SIMP_TAC[PI_POS; REAL_FIELD `&0 < p ==> t / (&2 * p) * p * r = t * r / &2`;
+             REAL_FIELD `&0 < p ==> t / (&2 * p) * &2 * p = t`] THEN
+    DISCH_THEN MATCH_MP_TAC THEN MP_TAC PI_POS THEN ASM_REAL_ARITH_TAC] THEN
+  REWRITE_TAC[] THEN REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC REALLIM_TRANSFORM_BOUND THEN
+    EXISTS_TAC `\t. r pow 2 * sin(t)` THEN REWRITE_TAC[] THEN CONJ_TAC THENL
+     [REWRITE_TAC[EVENTUALLY_WITHINREAL] THEN EXISTS_TAC `pi / &2` THEN
+      SIMP_TAC[PI_POS; REAL_LT_DIV; IN_ELIM_THM; REAL_OF_NUM_LT; ARITH] THEN
+      X_GEN_TAC `x:real` THEN REWRITE_TAC[REAL_SUB_RZERO] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+      ASM_SIMP_TAC[real_abs; MEASURE_POS_LE; MEASURABLE_CLOSED_SECTOR_LE] THEN
+      STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `measure(interval[vec 0,complex(r,r * sin x)])` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC MEASURE_SUBSET THEN
+        REWRITE_TAC[MEASURABLE_CLOSED_SECTOR_LE; MEASURABLE_INTERVAL] THEN
+        REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_INTERVAL] THEN
+        X_GEN_TAC `z:complex` THEN STRIP_TAC THEN
+        REWRITE_TAC[DIMINDEX_2; FORALL_2; VEC_COMPONENT] THEN
+        REWRITE_TAC[GSYM IM_DEF; GSYM RE_DEF; IM; RE] THEN
+        SUBST1_TAC(last(CONJUNCTS(SPEC `z:complex` ARG))) THEN
+        REWRITE_TAC[RE_MUL_CX; IM_MUL_CX; CEXP_EULER] THEN
+        REWRITE_TAC[RE_ADD; GSYM CX_COS; GSYM CX_SIN; RE_CX; IM_CX;
+                    RE_MUL_II; IM_MUL_II; IM_ADD] THEN
+        REWRITE_TAC[REAL_NEG_0; REAL_ADD_LID; REAL_ADD_RID] THEN
+        SUBGOAL_THEN `&0 <= Arg z /\ Arg z < pi / &2 /\ Arg z <= pi / &2`
+        STRIP_ASSUME_TAC THENL
+         [REWRITE_TAC[ARG] THEN ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+        REPEAT CONJ_TAC THENL
+         [MATCH_MP_TAC REAL_LE_MUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+          MATCH_MP_TAC COS_POS_PI_LE THEN ASM_REAL_ARITH_TAC;
+          MATCH_MP_TAC(REAL_ARITH `abs(a * b) <= c * &1 ==> a * b <= c`) THEN
+          REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_NORM] THEN
+          MATCH_MP_TAC REAL_LE_MUL2 THEN
+          ASM_REWRITE_TAC[NORM_POS_LE; REAL_ABS_POS; COS_BOUND];
+          MATCH_MP_TAC REAL_LE_MUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+          MATCH_MP_TAC SIN_POS_PI_LE THEN ASM_REAL_ARITH_TAC;
+          MATCH_MP_TAC REAL_LE_MUL2 THEN ASM_REWRITE_TAC[NORM_POS_LE] THEN
+          CONJ_TAC THENL
+           [MATCH_MP_TAC SIN_POS_PI_LE THEN ASM_REAL_ARITH_TAC;
+            MATCH_MP_TAC SIN_MONO_LE THEN ASM_REAL_ARITH_TAC]];
+        REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+        REWRITE_TAC[FORALL_2; PRODUCT_2; DIMINDEX_2; VEC_COMPONENT] THEN
+        REWRITE_TAC[GSYM IM_DEF; GSYM RE_DEF; IM; RE] THEN
+        REWRITE_TAC[REAL_SUB_RZERO; REAL_POW_2; REAL_MUL_ASSOC] THEN
+        SUBGOAL_THEN `&0 <= sin x` (fun th ->
+          ASM_SIMP_TAC[REAL_LE_MUL; REAL_LE_REFL; REAL_LE_MUL; th]) THEN
+        MATCH_MP_TAC SIN_POS_PI_LE THEN ASM_REAL_ARITH_TAC];
+      MATCH_MP_TAC REALLIM_ATREAL_WITHINREAL THEN
+      SUBGOAL_THEN `(\t. r pow 2 * sin t) real_continuous atreal (&0)`
+      MP_TAC THENL
+       [MATCH_MP_TAC REAL_CONTINUOUS_LMUL THEN
+        REWRITE_TAC[ETA_AX; REAL_CONTINUOUS_AT_SIN];
+        REWRITE_TAC[REAL_CONTINUOUS_ATREAL; SIN_0; REAL_MUL_RZERO]]];
+    ASM_SIMP_TAC[REAL_ARITH
+      `&0 <= x /\ &0 <= y
+       ==> (norm z <= r /\ Arg z <= x + y <=>
+            norm z <= r /\ Arg z <= x \/
+            norm z <= r /\ x < Arg z /\ Arg z <= x + y)`] THEN
+    REWRITE_TAC[SET_RULE `{z | Q z \/ R z} = {z | Q z} UNION {z | R z}`] THEN
+    SIMP_TAC[MEASURE_UNION; MEASURABLE_CLOSED_SECTOR_LE;
+             MEASURABLE_CLOSED_SECTOR_LTE] THEN
+    REWRITE_TAC[GSYM REAL_NOT_LE; SET_RULE
+     `{z | P z /\ Q z} INTER {z | P z /\ ~Q z /\ R z} = {}`] THEN
+    REWRITE_TAC[MEASURE_EMPTY; REAL_SUB_RZERO; REAL_EQ_ADD_LCANCEL] THEN
+    REWRITE_TAC[REAL_NOT_LE] THEN MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `measure {z | norm z <= r /\ x < Arg z /\ Arg z < x + y}` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC MEASURE_NEGLIGIBLE_SYMDIFF THEN
+      REWRITE_TAC[MEASURABLE_CLOSED_SECTOR_LTE] THEN
+      MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+      EXISTS_TAC `{z | Arg z = x + y}` THEN
+      REWRITE_TAC[NEGLIGIBLE_ARG_EQ; NEGLIGIBLE_UNION_EQ] THEN
+      REWRITE_TAC[SUBSET; IN_DIFF; IN_UNION; IN_ELIM_THM] THEN REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `measure {z | norm z <= r /\ &0 < Arg z /\ Arg z < y}` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC MEASURE_NEGLIGIBLE_SYMDIFF THEN
+      REWRITE_TAC[MEASURABLE_CLOSED_SECTOR_LE] THEN
+      MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+      EXISTS_TAC `{z | Arg z = &0} UNION {z | Arg z = y}` THEN
+      REWRITE_TAC[NEGLIGIBLE_ARG_EQ; NEGLIGIBLE_UNION_EQ] THEN
+      REWRITE_TAC[SUBSET; IN_DIFF; IN_UNION; IN_ELIM_THM] THEN
+      MP_TAC ARG THEN MATCH_MP_TAC MONO_FORALL THEN REAL_ARITH_TAC] THEN
+    MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+     `measure (IMAGE (rotate2d x)
+              {z | norm z <= r /\ &0 < Arg z /\ Arg z < y})` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      ASM_SIMP_TAC[MEASURE_ORTHOGONAL_IMAGE_EQ;
+                   ORTHOGONAL_TRANSFORMATION_ROTATE2D]] THEN
+    AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_SURJECTIVE;
+                    ORTHOGONAL_TRANSFORMATION_ROTATE2D]; ALL_TAC] THEN
+    X_GEN_TAC `z:complex` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    ASM_CASES_TAC `z = Cx(&0)` THENL
+     [ASM_REWRITE_TAC[Arg_DEF; ROTATE2D_0] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[NORM_ROTATE2D] THEN AP_TERM_TAC THEN EQ_TAC THENL
+     [STRIP_TAC THEN
+      SUBGOAL_THEN `z = rotate2d (--x) (rotate2d x z)` SUBST1_TAC THENL
+       [REWRITE_TAC[GSYM ROTATE2D_ADD; REAL_ADD_LINV; ROTATE2D_ZERO];
+        ALL_TAC] THEN
+      MP_TAC(ISPECL [`--x:real`; `rotate2d x z`] ARG_ROTATE2D) THEN
+      ASM_REWRITE_TAC[ROTATE2D_EQ_0] THEN
+      ANTS_TAC THENL [ASM_REAL_ARITH_TAC; DISCH_THEN SUBST1_TAC] THEN
+      ASM_REAL_ARITH_TAC;
+      STRIP_TAC THEN
+      MP_TAC(ISPECL [`x:real`; `z:complex`] ARG_ROTATE2D) THEN
+      ASM_REWRITE_TAC[ROTATE2D_EQ_0] THEN
+      ANTS_TAC THENL [ASM_REAL_ARITH_TAC; DISCH_THEN SUBST1_TAC] THEN
+      ASM_REAL_ARITH_TAC]]);;
+
+let HAS_MEASURE_OPEN_SECTOR_LT = prove
+ (`!t r. &0 <= t /\ t <= &2 * pi
+         ==> {x:real^2 | norm(x) < r /\ &0 < Arg x /\ Arg x < t}
+             has_measure (if &0 <= r then t * r pow 2 / &2 else &0)`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  ASM_SIMP_TAC[NORM_ARITH `~(&0 <= r) ==> ~(norm x < r)`;
+               EMPTY_GSPEC; HAS_MEASURE_EMPTY] THEN
+  MATCH_MP_TAC HAS_MEASURE_NEGLIGIBLE_SYMDIFF THEN
+  EXISTS_TAC `{x | norm x <= r /\ Arg x <= t}` THEN
+  REWRITE_TAC[HAS_MEASURE_MEASURABLE_MEASURE] THEN
+  ASM_SIMP_TAC[MEASURE_CLOSED_SECTOR_LE; MEASURABLE_CLOSED_SECTOR_LE] THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `{x | dist(vec 0,x) = r} UNION
+              {z | Arg z = &0} UNION {z | Arg z = t}` THEN
+  REWRITE_TAC[NEGLIGIBLE_ARG_EQ; REWRITE_RULE[sphere] NEGLIGIBLE_SPHERE;
+              NEGLIGIBLE_UNION_EQ] THEN
+  REWRITE_TAC[DIST_0; SUBSET; IN_DIFF; IN_UNION; IN_ELIM_THM] THEN
+      MP_TAC ARG THEN MATCH_MP_TAC MONO_FORALL THEN REAL_ARITH_TAC);;
+
+let MEASURE_OPEN_SECTOR_LT = prove
+ (`!t r. &0 <= t /\ t <= &2 * pi
+         ==> measure {x:real^2 | norm(x) < r /\ &0 < Arg x /\ Arg x < t} =
+             if &0 <= r then t * r pow 2 / &2 else &0`,
+  SIMP_TAC[REWRITE_RULE[HAS_MEASURE_MEASURABLE_MEASURE]
+           HAS_MEASURE_OPEN_SECTOR_LT]);;
+
+let HAS_MEASURE_OPEN_SECTOR_LT_GEN = prove
+ (`!w z.
+        ~(w = vec 0)
+        ==> {x | norm(x) < r /\ &0 < Arg(x / w) /\ Arg(x / w) < Arg(z / w)}
+            has_measure (if &0 <= r then Arg(z / w) * r pow 2 / &2 else &0)`,
+  GEOM_BASIS_MULTIPLE_TAC 1 `w:complex` THEN
+  X_GEN_TAC `w:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `w = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+  REWRITE_TAC[COMPLEX_CMUL; COMPLEX_BASIS; COMPLEX_VEC_0] THEN
+  SIMP_TAC[ARG_DIV_CX; COMPLEX_MUL_RID] THEN ASM_REWRITE_TAC[CX_INJ] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_MEASURE_OPEN_SECTOR_LT THEN
+  SIMP_TAC[ARG; REAL_LT_IMP_LE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence volume of a wedge of a ball.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_BALL_WEDGE = prove
+ (`!z:real^3 w w1 w2. measurable(ball(z,r) INTER wedge z w w1 w2)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_OPEN THEN CONJ_TAC THENL
+   [MATCH_MP_TAC BOUNDED_INTER THEN REWRITE_TAC[BOUNDED_BALL];
+    MATCH_MP_TAC OPEN_INTER THEN REWRITE_TAC[OPEN_BALL] THEN
+    ASM_SIMP_TAC[OPEN_WEDGE]]);;
+
+let VOLUME_BALL_WEDGE = prove
+ (`!z:real^3 w r w1 w2.
+        &0 <= r ==> measure(ball(z,r) INTER wedge z w w1 w2) =
+                       azim z w w1 w2 * &2 * r pow 3 / &3`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `z:real^3 = w \/  collinear{z,w,w1} \/ collinear{z,w,w2}` THENL
+   [FIRST_X_ASSUM STRIP_ASSUME_TAC THEN
+    ASM_SIMP_TAC[WEDGE_DEGENERATE; AZIM_DEGENERATE; INTER_EMPTY; REAL_MUL_LZERO;
+                 MEASURE_EMPTY];
+    FIRST_X_ASSUM MP_TAC THEN REWRITE_TAC[IMP_IMP; DE_MORGAN_THM]] THEN
+  REWRITE_TAC[wedge] THEN GEOM_ORIGIN_TAC `z:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `w:real^3` THEN
+  X_GEN_TAC `w:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `w = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; COLLINEAR_SPECIAL_SCALE] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(INST_TYPE[`:2`,`:M`; `:3`,`:N`] FUBINI_SIMPLE_OPEN) THEN
+  EXISTS_TAC `3` THEN REWRITE_TAC[DIMINDEX_2; DIMINDEX_3; ARITH] THEN
+  REPEAT CONJ_TAC THENL
+   [MESON_TAC[BOUNDED_SUBSET; INTER_SUBSET; BOUNDED_BALL];
+    REWRITE_TAC[GSYM wedge] THEN MATCH_MP_TAC OPEN_INTER THEN
+    ASM_REWRITE_TAC[OPEN_BALL; OPEN_WEDGE];
+    SIMP_TAC[SLICE_INTER; DIMINDEX_2; DIMINDEX_3; ARITH; SLICE_BALL]] THEN
+  ONCE_REWRITE_TAC[TAUT `~a /\ b /\ c <=> ~(~a ==> ~(b /\ c))`] THEN
+  ASM_SIMP_TAC[AZIM_ARG] THEN REWRITE_TAC[COLLINEAR_BASIS_3] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[COLLINEAR_BASIS_3]) THEN
+  REWRITE_TAC[NOT_IMP; GSYM CONJ_ASSOC; DROPOUT_0] THEN
+  MAP_EVERY ABBREV_TAC
+   [`v1:real^2 = dropout 3 (w1:real^3)`;
+    `v2:real^2 = dropout 3 (w2:real^3)`] THEN
+  REWRITE_TAC[SLICE_DROPOUT_3; VEC_COMPONENT; REAL_SUB_RZERO] THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN
+  ONCE_REWRITE_TAC[COND_RATOR] THEN
+  REWRITE_TAC[INTER_EMPTY] THEN REWRITE_TAC[INTER; IN_BALL_0; IN_ELIM_THM] THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN REWRITE_TAC[MEASURE_EMPTY] THEN
+  MAP_EVERY UNDISCH_TAC
+   [`~(v1:complex = vec 0)`; `~(v2:complex = vec 0)`] THEN
+  MAP_EVERY (fun t -> SPEC_TAC(t,t)) [`v2:complex`; `v1:complex`] THEN
+  UNDISCH_TAC `&0 <= r` THEN SPEC_TAC(`r:real`,`r:real`) THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; GSYM CONJ_ASSOC] THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN GEOM_BASIS_MULTIPLE_TAC 1 `v1:complex` THEN
+  X_GEN_TAC `v1:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `v1 = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+  REWRITE_TAC[COMPLEX_CMUL; COMPLEX_BASIS; COMPLEX_VEC_0] THEN
+  SIMP_TAC[ARG_DIV_CX; COMPLEX_MUL_RID; CX_INJ] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!t z. ~(z = Cx(&0)) /\ &0 < Arg z /\ Arg z < t <=>
+          &0 < Arg z /\ Arg z < t`
+   (fun th -> REWRITE_TAC[th])
+  THENL [MESON_TAC[ARG_0; REAL_LT_REFL]; ALL_TAC] THEN
+  ASM_SIMP_TAC[MEASURE_OPEN_SECTOR_LT; REAL_LE_REFL; ARG; REAL_LT_IMP_LE] THEN
+  SUBGOAL_THEN `!t. abs(t) < r <=> t IN real_interval(--r,r)`
+   (fun th -> REWRITE_TAC[th])
+  THENL [REWRITE_TAC[IN_REAL_INTERVAL] THEN REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[HAS_REAL_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_INTEGRAL_OPEN_INTERVAL] THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_EQ THEN
+  EXISTS_TAC `\t. Arg v2 * (r pow 2 - t pow 2) / &2` THEN CONJ_TAC THENL
+   [X_GEN_TAC `t:real` THEN REWRITE_TAC[IN_REAL_INTERVAL; REAL_BOUNDS_LE] THEN
+    SIMP_TAC[AREA_CBALL; SQRT_POS_LE; REAL_SUB_LE; GSYM REAL_LE_SQUARE_ABS;
+             SQRT_POW_2; REAL_ARITH `abs x <= r ==> abs x <= abs r`];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`\t. Arg v2 * (r pow 2 * t - &1 / &3 * t pow 3) / &2`;
+    `\t. Arg v2 * (r pow 2 - t pow 2) / &2`;
+    `--r:real`; `r:real`] REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN
+    CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC REAL_RING;
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    CONV_TAC REAL_RING]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence volume of lune.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_MEASURE_LUNE = prove
+ (`!z:real^3 w r w1 w2.
+        &0 <= r /\ ~(w = z) /\
+        ~collinear {z,w,w1} /\ ~collinear {z,w,w2} /\ ~(dihV z w w1 w2 = pi)
+        ==> (ball(z,r) INTER aff_gt {z,w} {w1,w2})
+            has_measure (dihV z w w1 w2 * &2 * r pow 3 / &3)`,
+  GEOM_ORIGIN_TAC `z:real^3` THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `w:real^3` THEN
+  X_GEN_TAC `w:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `w = &0` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  DISCH_TAC THEN REPEAT GEN_TAC THEN
+  ASM_SIMP_TAC[DIHV_SPECIAL_SCALE] THEN
+  MP_TAC(ISPECL [`{}:real^3->bool`; `{w1:real^3,w2:real^3}`;
+                 `w:real`; `basis 3:real^3`] AFF_GT_SPECIAL_SCALE) THEN
+  ASM_CASES_TAC `w1:real^3 = vec 0` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_CASES_TAC `w2:real^3 = vec 0` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY; IN_INSERT; NOT_IN_EMPTY] THEN
+  ASM_CASES_TAC `w1:real^3 = w % basis 3` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_CASES_TAC `w2:real^3 = w % basis 3` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_SIMP_TAC[COLLINEAR_SPECIAL_SCALE] THEN
+  ASM_CASES_TAC `w1:real^3 = basis 3` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_CASES_TAC `w2:real^3 = basis 3` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ] THEN STRIP_TAC THEN
+  ASM_CASES_TAC `azim (vec 0) (basis 3) w1 w2 = &0` THENL
+   [MP_TAC(ASSUME `azim (vec 0) (basis 3) w1 w2 = &0`) THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) AZIM_DIVH o lhs o lhand o snd) THEN
+    ASM_REWRITE_TAC[PI_POS] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[REAL_MUL_LZERO; HAS_MEASURE_0] THEN
+    MATCH_MP_TAC COPLANAR_IMP_NEGLIGIBLE THEN
+    MATCH_MP_TAC COPLANAR_SUBSET THEN
+    EXISTS_TAC `affine hull {vec 0:real^3,basis 3,w1,w2}` THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[COPLANAR_AFFINE_HULL_COPLANAR; AZIM_EQ_0_PI_IMP_COPLANAR];
+      ALL_TAC] THEN
+    MATCH_MP_TAC(SET_RULE `t SUBSET u ==> (s INTER t) SUBSET u`) THEN
+    SIMP_TAC[aff_gt_def; AFFSIGN; sgn_gt; AFFINE_HULL_FINITE;
+             FINITE_INSERT; FINITE_EMPTY] THEN
+    REWRITE_TAC[SET_RULE `{a,b} UNION {c,d} = {a,b,c,d}`] THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN GEN_TAC THEN
+    MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `&0 < azim (vec 0) (basis 3) w1 w2` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[REAL_LT_LE; azim]; ALL_TAC] THEN
+  ASM_CASES_TAC `azim (vec 0) (basis 3) w1 w2 < pi` THENL
+   [ASM_SIMP_TAC[GSYM AZIM_DIHV_SAME; GSYM WEDGE_LUNE_GT] THEN
+    ASM_SIMP_TAC[HAS_MEASURE_MEASURABLE_MEASURE; MEASURABLE_BALL_WEDGE;
+                 VOLUME_BALL_WEDGE];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `azim (vec 0) (basis 3) w1 w2 = pi` THENL
+   [MP_TAC(ISPECL [`vec 0:real^3`; `basis 3:real^3`; `w1:real^3`; `w2:real^3`]
+           AZIM_DIVH) THEN
+    ASM_REWRITE_TAC[REAL_LT_REFL] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `dihV (vec 0) (basis 3) w1 w2 = azim (vec 0) (basis 3) w2 w1`
+  SUBST1_TAC THENL
+   [W(MP_TAC o PART_MATCH (lhs o rand) AZIM_COMPL o rand o snd) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `x:real = y - z <=> z = y - x`] THEN
+    MATCH_MP_TAC AZIM_DIHV_COMPL THEN
+    ASM_REWRITE_TAC[GSYM REAL_NOT_LT];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `&0 < azim (vec 0) (basis 3) w2 w1 /\
+                azim (vec 0) (basis 3) w2 w1 < pi`
+  ASSUME_TAC THENL
+   [W(MP_TAC o PART_MATCH (lhs o rand) AZIM_COMPL o lhand o rand o snd) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
+    MP_TAC(ISPECL [`vec 0:real^3`; `basis 3:real^3`; `w1:real^3`; `w2:real^3`]
+        azim) THEN
+    REWRITE_TAC[CONJ_ASSOC] THEN DISCH_THEN(MP_TAC o CONJUNCT1) THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBST1_TAC(SET_RULE `{w1:real^3,w2} = {w2,w1}`) THEN
+  ASM_SIMP_TAC[GSYM AZIM_DIHV_SAME; GSYM WEDGE_LUNE_GT] THEN
+  ASM_SIMP_TAC[HAS_MEASURE_MEASURABLE_MEASURE; MEASURABLE_BALL_WEDGE;
+               VOLUME_BALL_WEDGE]);;
+
+let HAS_MEASURE_LUNE_SIMPLE = prove
+ (`!z:real^3 w r w1 w2.
+        &0 <= r /\ ~coplanar{z,w,w1,w2}
+        ==> (ball(z,r) INTER aff_gt {z,w} {w1,w2})
+            has_measure (dihV z w w1 w2 * &2 * r pow 3 / &3)`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `w:real^3 = z` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COPLANAR_3]; ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_MEASURE_LUNE THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(TAUT `a /\ b /\ (a /\ b ==> c) ==> a /\ b /\ c`) THEN
+  REPEAT(CONJ_TAC THENL
+   [ASM_MESON_TAC[NOT_COPLANAR_NOT_COLLINEAR; INSERT_AC]; ALL_TAC]) THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`z:real^3`; `w:real^3`; `w1:real^3`; `w2:real^3`]
+        AZIM_DIVH) THEN
+  ASM_REWRITE_TAC[REAL_ARITH `&2 * pi - pi = pi`; COND_ID] THEN
+  ASM_MESON_TAC[AZIM_EQ_0_PI_IMP_COPLANAR]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Now the volume of a solid triangle.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_BALL_AFF_GT = prove
+ (`!z r s t. measurable(ball(z,r) INTER aff_gt s t)`,
+  MESON_TAC[MEASURABLE_CONVEX; CONVEX_INTER; CONVEX_AFF_GT; CONVEX_BALL;
+            BOUNDED_INTER; BOUNDED_BALL]);;
+
+let AFF_GT_SHUFFLE = prove
+ (`!s t v:real^N.
+        FINITE s /\ FINITE t /\
+        vec 0 IN s /\ ~(vec 0 IN t) /\
+        ~(v IN s) /\ ~(--v IN s) /\ ~(v IN t)
+        ==> aff_gt (v INSERT s) t =
+            aff_gt s (v INSERT t) UNION
+            aff_gt s (--v INSERT t) UNION
+            aff_gt s t`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[aff_gt_def; AFFSIGN_ALT; sgn_gt] THEN
+  REWRITE_TAC[SET_RULE `(v INSERT s) UNION t = v INSERT (s UNION t)`;
+              SET_RULE `s UNION (v INSERT t) = v INSERT (s UNION t)`] THEN
+  ASM_SIMP_TAC[FINITE_INSERT; FINITE_UNION; AFFINE_HULL_FINITE_STEP_GEN;
+               RIGHT_EXISTS_AND_THM; REAL_LT_ADD; REAL_HALF; FINITE_EMPTY] THEN
+  REWRITE_TAC[IN_INSERT] THEN
+  ASM_SIMP_TAC[SET_RULE
+   `~(a IN s)
+    ==> ((w IN s UNION t ==> w = a \/ w IN t ==> P w) <=>
+         (w IN t ==> P w))`] THEN
+  REWRITE_TAC[SET_RULE `x IN (s UNION t)
+                        ==> x IN t ==> P x <=> x IN t ==> P  x`] THEN
+  REWRITE_TAC[EXTENSION; IN_UNION; IN_ELIM_THM] THEN
+  X_GEN_TAC `y:real^N` THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `v:real` ASSUME_TAC) THEN
+    ASM_CASES_TAC `&0 < v` THENL
+     [DISJ1_TAC THEN EXISTS_TAC `v:real` THEN ASM_REWRITE_TAC[];
+      DISJ2_TAC] THEN
+    ASM_CASES_TAC `v = &0` THENL
+     [DISJ2_TAC THEN
+      FIRST_ASSUM(fun th -> MP_TAC th THEN MATCH_MP_TAC MONO_EXISTS) THEN
+      ASM_REWRITE_TAC[REAL_SUB_RZERO; VECTOR_MUL_LZERO; VECTOR_SUB_RZERO];
+      DISJ1_TAC] THEN
+    EXISTS_TAC `--v:real` THEN CONJ_TAC THENL
+     [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    FIRST_X_ASSUM(X_CHOOSE_THEN `f:real^N->real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\x:real^N. if x = vec 0 then f(x) + &2 * v else f(x)` THEN
+    REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [ASM_MESON_TAC[];
+      ASM_SIMP_TAC[SUM_CASES_1; FINITE_UNION; IN_UNION] THEN REAL_ARITH_TAC;
+      REWRITE_TAC[VECTOR_ARITH `--a % --x:real^N = a % x`] THEN
+      FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [GSYM th]) THEN
+      MATCH_MP_TAC VSUM_EQ THEN REWRITE_TAC[] THEN
+      REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+      ASM_REWRITE_TAC[VECTOR_MUL_RZERO]];
+    DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL [MESON_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL
+     [DISCH_THEN(X_CHOOSE_THEN `a:real`
+       (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+      DISCH_THEN(X_CHOOSE_THEN `f:real^N->real` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `--a:real` THEN
+      EXISTS_TAC `\x:real^N. if x = vec 0 then &2 * a + f(vec 0) else f x` THEN
+      ASM_SIMP_TAC[SUM_CASES_1; FINITE_UNION; IN_UNION] THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+      CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+      ONCE_REWRITE_TAC[VECTOR_ARITH `y - --a % v:real^N = y - a % --v`] THEN
+      FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [SYM th]) THEN
+      MATCH_MP_TAC VSUM_EQ THEN REPEAT GEN_TAC THEN REWRITE_TAC[] THEN
+      DISCH_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[VECTOR_MUL_RZERO];
+      GEN_REWRITE_TAC RAND_CONV [SWAP_EXISTS_THM] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN
+      EXISTS_TAC `&0` THEN ASM_REWRITE_TAC[REAL_SUB_RZERO] THEN
+      VECTOR_ARITH_TAC]]);;
+
+let MEASURE_BALL_AFF_GT_SHUFFLE_LEMMA = prove
+ (`!r s t v:real^N.
+        &0 <= r /\
+        independent(v INSERT((s DELETE vec 0) UNION t)) /\
+        FINITE s /\ FINITE t /\ CARD(s UNION t) <= dimindex(:N) /\
+        vec 0 IN s /\ ~(vec 0 IN t) /\
+        ~(v IN s) /\ ~(--v IN s) /\ ~(v IN t)
+        ==> measure(ball(vec 0,r) INTER aff_gt (v INSERT s) t) =
+            measure(ball(vec 0,r) INTER aff_gt s (v INSERT t)) +
+            measure(ball(vec 0,r) INTER aff_gt s (--v INSERT t))`,
+  let lemma = prove
+   (`!s t u:real^N->bool.
+          measurable s /\ measurable t /\ s INTER t = {} /\ negligible u
+          ==> measure(s UNION t UNION u) = measure s + measure t`,
+    REPEAT STRIP_TAC THEN REWRITE_TAC[UNION_ASSOC] THEN
+    ASM_SIMP_TAC[GSYM MEASURE_DISJOINT_UNION; DISJOINT] THEN
+    MATCH_MP_TAC MEASURE_NEGLIGIBLE_SYMDIFF THEN
+    ASM_SIMP_TAC[MEASURABLE_UNION] THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ] NEGLIGIBLE_SUBSET)) THEN SET_TAC[]) in
+  REPEAT STRIP_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) AFF_GT_SHUFFLE o
+    rand o rand o lhand o snd) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[UNION_OVER_INTER] THEN MATCH_MP_TAC lemma THEN
+  ASM_REWRITE_TAC[MEASURABLE_BALL_AFF_GT] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `t INTER u = {} ==> (s INTER t) INTER (s INTER u) = {}`) THEN
+    REWRITE_TAC[aff_gt_def; AFFSIGN_ALT; sgn_gt] THEN
+    REWRITE_TAC[SET_RULE `(v INSERT s) UNION t = v INSERT (s UNION t)`;
+                SET_RULE `s UNION (v INSERT t) = v INSERT (s UNION t)`] THEN
+    ASM_SIMP_TAC[FINITE_INSERT; FINITE_UNION; AFFINE_HULL_FINITE_STEP_GEN;
+                 RIGHT_EXISTS_AND_THM; REAL_LT_ADD;
+                 REAL_HALF; FINITE_EMPTY] THEN
+    REWRITE_TAC[IN_INSERT] THEN
+    ASM_SIMP_TAC[SET_RULE
+     `~(a IN s) ==> ((w IN s UNION t ==> w = a \/ w IN t ==> P w) <=>
+                     (w IN t ==> P w))`] THEN
+    GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_INTER; NOT_IN_EMPTY; IN_ELIM_THM] THEN
+    X_GEN_TAC `y:real^N` THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `a:real`
+       (CONJUNCTS_THEN2 ASSUME_TAC
+         (X_CHOOSE_THEN `f:real^N->real` STRIP_ASSUME_TAC)))
+     (X_CHOOSE_THEN `b:real`
+       (CONJUNCTS_THEN2 ASSUME_TAC
+         (X_CHOOSE_THEN `g:real^N->real` STRIP_ASSUME_TAC)))) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INDEPENDENT_EXPLICIT]) THEN
+    REWRITE_TAC[FINITE_INSERT; FINITE_DELETE; FINITE_UNION] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(MP_TAC o SPEC
+     `\x. if x = v then a + b else (f:real^N->real) x - g x`) THEN
+    ASM_SIMP_TAC[VSUM_CLAUSES; FINITE_DELETE; FINITE_UNION] THEN
+    ASM_REWRITE_TAC[IN_DELETE; IN_UNION] THEN
+    REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THENL
+     [ALL_TAC; DISCH_THEN(MP_TAC o SPEC `v:real^N`) THEN
+      REWRITE_TAC[IN_INSERT] THEN ASM_REAL_ARITH_TAC] THEN
+    ASM_SIMP_TAC[SET_RULE
+      `~(a IN t) ==> (s DELETE a) UNION t = (s UNION t) DELETE a`] THEN
+    ASM_SIMP_TAC[VSUM_DELETE_CASES; FINITE_UNION; IN_UNION] THEN
+    REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_SUB_RZERO] THEN
+    SUBGOAL_THEN
+     `!x:real^N. (if x = v then a + b else f x - g x) % x =
+                 (if x = v then a else f x) % x -
+                 (if x = v then --b else g x) % x`
+     (fun th -> REWRITE_TAC[th])
+    THENL
+     [GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC;
+      ASM_SIMP_TAC[VSUM_SUB; FINITE_UNION]] THEN
+    MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `(a + b) % v + (y - a % v) - (y - b % --v):real^N` THEN
+    CONJ_TAC THENL [ALL_TAC; VECTOR_ARITH_TAC] THEN
+    AP_TERM_TAC THEN BINOP_TAC THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [GSYM th]) THEN
+    MATCH_MP_TAC VSUM_EQ THEN GEN_TAC THEN REWRITE_TAC[] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_UNION];
+    MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+    EXISTS_TAC `aff_gt s t :real^N->bool` THEN
+    REWRITE_TAC[INTER_SUBSET] THEN
+    MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+    EXISTS_TAC `affine hull (s UNION t:real^N->bool)` THEN
+    REWRITE_TAC[AFF_GT_SUBSET_AFFINE_HULL] THEN
+    ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; IN_UNION; HULL_INC] THEN
+    ONCE_REWRITE_TAC[GSYM SPAN_DELETE_0] THEN
+    MATCH_MP_TAC NEGLIGIBLE_LOWDIM THEN
+    MATCH_MP_TAC LET_TRANS THEN
+    EXISTS_TAC `CARD((s UNION t) DELETE (vec 0:real^N))` THEN
+    ASM_SIMP_TAC[DIM_LE_CARD; FINITE_DELETE; FINITE_UNION; DIM_SPAN] THEN
+    ASM_SIMP_TAC[CARD_DELETE; IN_UNION; FINITE_UNION] THEN
+    MATCH_MP_TAC(ARITH_RULE `1 <= n /\ x <= n ==> x - 1 < n`) THEN
+    ASM_REWRITE_TAC[DIMINDEX_GE_1]]);;
+
+let MEASURE_BALL_AFF_GT_SHUFFLE = prove
+ (`!r s t v:real^N.
+        &0 <= r /\ ~(v IN (s UNION t)) /\
+        independent(v INSERT (s UNION t))
+        ==> measure(ball(vec 0,r) INTER aff_gt (vec 0 INSERT v INSERT s) t) =
+            measure(ball(vec 0,r) INTER aff_gt (vec 0 INSERT s) (v INSERT t)) +
+            measure(ball(vec 0,r) INTER
+                    aff_gt (vec 0 INSERT s) (--v INSERT t))`,
+  REWRITE_TAC[IN_UNION; DE_MORGAN_THM] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`r:real`; `(vec 0:real^N) INSERT s`;
+                 `t:real^N->bool`; `v:real^N`]
+        MEASURE_BALL_AFF_GT_SHUFFLE_LEMMA) THEN
+  ANTS_TAC THENL [ALL_TAC; REWRITE_TAC[INSERT_AC]] THEN
+  ASM_REWRITE_TAC[IN_INSERT; FINITE_INSERT] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP INDEPENDENT_NONZERO) THEN
+  REWRITE_TAC[IN_INSERT; IN_UNION; DE_MORGAN_THM] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP INDEPENDENT_BOUND) THEN
+  REWRITE_TAC[FINITE_INSERT; FINITE_UNION] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[SET_RULE `(a INSERT s) UNION t = a INSERT (s UNION t)`] THEN
+  ASM_SIMP_TAC[CARD_CLAUSES; FINITE_UNION; IN_UNION; FINITE_INSERT] THEN
+  DISCH_TAC THEN ASM_REWRITE_TAC[VECTOR_NEG_EQ_0] THEN CONJ_TAC THENL
+   [FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ] INDEPENDENT_MONO)) THEN
+    SET_TAC[];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [independent]) THEN
+    REWRITE_TAC[dependent; CONTRAPOS_THM] THEN DISCH_TAC THEN
+    EXISTS_TAC `v:real^N` THEN REWRITE_TAC[IN_INSERT] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_NEG_NEG] THEN
+    MATCH_MP_TAC SPAN_NEG THEN MATCH_MP_TAC SPAN_SUPERSET THEN
+    ASM_REWRITE_TAC[IN_DELETE; VECTOR_ARITH `--v:real^N = v <=> v = vec 0`;
+                    IN_INSERT; IN_UNION]]);;
+
+let MEASURE_LUNE_DECOMPOSITION = prove
+ (`!v1 v2 v3:real^3.
+         &0 <= r /\ ~coplanar {vec 0, v1, v2, v3}
+         ==> measure(ball(vec 0,r) INTER aff_gt {vec 0} {v1,v2,v3}) +
+             measure(ball(vec 0,r) INTER aff_gt {vec 0} {--v1,v2,v3}) =
+             dihV (vec 0) v1 v2 v3 * &2 * r pow 3 / &3`,
+  let rec distinctpairs l =
+    match l with
+     x::t -> itlist (fun y a -> (x,y) :: a) t (distinctpairs t)
+    | [] -> [] in
+  REPEAT GEN_TAC THEN MAP_EVERY
+   (fun t -> ASM_CASES_TAC t THENL
+    [ASM_REWRITE_TAC[INSERT_AC; COPLANAR_3]; ALL_TAC])
+   (map mk_eq (distinctpairs
+    [`v3:real^3`; `v2:real^3`; `v1:real^3`; `vec 0:real^3`])) THEN
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[GSYM(REWRITE_RULE[HAS_MEASURE_MEASURABLE_MEASURE]
+    HAS_MEASURE_LUNE_SIMPLE)] THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC MEASURE_BALL_AFF_GT_SHUFFLE THEN
+  ASM_REWRITE_TAC[UNION_EMPTY; IN_INSERT; NOT_IN_EMPTY] THEN
+  ASM_SIMP_TAC[NOT_COPLANAR_0_4_IMP_INDEPENDENT]);;
+
+let SOLID_TRIANGLE_CONGRUENT_NEG = prove
+ (`!r v1 v2 v3:real^N.
+        measure(ball(vec 0,r) INTER aff_gt {vec 0} {--v1, --v2, --v3}) =
+        measure(ball(vec 0,r) INTER aff_gt {vec 0} {v1, v2, v3})`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN
+   `ball(vec 0:real^N,r) INTER aff_gt {vec 0} {--v1, --v2, --v3} =
+    IMAGE (--)
+          (ball(vec 0,r) INTER aff_gt {vec 0} {v1, v2, v3})`
+  SUBST1_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC MEASURE_ORTHOGONAL_IMAGE_EQ THEN
+    REWRITE_TAC[ORTHOGONAL_TRANSFORMATION; linear; NORM_NEG] THEN
+    CONJ_TAC THEN VECTOR_ARITH_TAC] THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  CONJ_TAC THENL [MESON_TAC[VECTOR_NEG_NEG]; ALL_TAC] THEN
+  REWRITE_TAC[IN_INTER; IN_BALL_0; NORM_NEG] THEN
+  REWRITE_TAC[AFFSIGN_ALT; aff_gt_def; sgn_gt; IN_ELIM_THM] THEN
+  REWRITE_TAC[SET_RULE `{a} UNION {b,c,d} = {a,b,d,c}`] THEN
+  REWRITE_TAC[SET_RULE `x IN {a} <=> a = x`] THEN
+  ASM_SIMP_TAC[FINITE_INSERT; FINITE_UNION; AFFINE_HULL_FINITE_STEP_GEN;
+               RIGHT_EXISTS_AND_THM; REAL_LT_ADD; REAL_HALF; FINITE_EMPTY] THEN
+  ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_SUB_RZERO] THEN
+  REWRITE_TAC[VECTOR_ARITH `vec 0:real^N = --x <=> vec 0 = x`] THEN
+  REWRITE_TAC[VECTOR_ARITH `--x - a % --w:real^N = --(x - a % w)`] THEN
+  REWRITE_TAC[VECTOR_NEG_EQ_0]);;
+
+let VOLUME_SOLID_TRIANGLE = prove
+ (`!r v0 v1 v2 v3:real^3.
+       &0 < r /\ ~coplanar{v0, v1, v2, v3}
+       ==> measure(ball(v0,r) INTER aff_gt {v0} {v1,v2,v3}) =
+                let a123 = dihV v0 v1 v2 v3 in
+                let a231 = dihV v0 v2 v3 v1 in
+                let a312 = dihV v0 v3 v1 v2 in
+                  (a123 + a231 + a312 - pi) * r pow 3 / &3`,
+  let tac convl =
+    W(MP_TAC o PART_MATCH (lhs o rand) MEASURE_BALL_AFF_GT_SHUFFLE o
+      convl o lhand o lhand o snd) THEN
+    ASM_REWRITE_TAC[UNION_EMPTY; IN_INSERT; IN_UNION; NOT_IN_EMPTY] THEN
+    REWRITE_TAC[SET_RULE `(a INSERT s) UNION t = a INSERT (s UNION t)`] THEN
+    ASM_SIMP_TAC[UNION_EMPTY; REAL_LT_IMP_LE] THEN ANTS_TAC THENL
+     [CONJ_TAC THENL
+       [DISCH_THEN(STRIP_THM_THEN SUBST_ALL_TAC) THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[INSERT_AC]) THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[COPLANAR_3]) THEN
+        FIRST_ASSUM CONTR_TAC;
+        MATCH_MP_TAC NOT_COPLANAR_0_4_IMP_INDEPENDENT THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[INSERT_AC]) THEN
+        ASM_REWRITE_TAC[INSERT_AC]];
+      DISCH_THEN SUBST1_TAC] in
+  GEN_TAC THEN GEOM_ORIGIN_TAC `v0:real^3` THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+    `measure(ball(vec 0:real^3,r) INTER aff_gt {vec 0,v1,v2,v3} {}) =
+     &4 / &3 * pi * r pow 3`
+  MP_TAC THENL
+   [MP_TAC(SPECL [`vec 0:real^3`; `r:real`] VOLUME_BALL) THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN AP_TERM_TAC THEN
+    MATCH_MP_TAC(SET_RULE `t = UNIV ==> s INTER t = s`) THEN
+    REWRITE_TAC[AFF_GT_EQ_AFFINE_HULL] THEN
+    SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC; IN_INSERT; SPAN_INSERT_0] THEN
+    REWRITE_TAC[SET_RULE `s = UNIV <=> UNIV SUBSET s`] THEN
+    MATCH_MP_TAC CARD_GE_DIM_INDEPENDENT THEN
+    ASM_SIMP_TAC[DIM_UNIV; DIMINDEX_3; SUBSET_UNIV] THEN
+    ASM_SIMP_TAC[NOT_COPLANAR_0_4_IMP_INDEPENDENT] THEN
+    SIMP_TAC[CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN
+    REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+    MAP_EVERY (fun t ->
+      ASM_CASES_TAC t THENL
+       [FIRST_X_ASSUM SUBST_ALL_TAC THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[INSERT_AC; COPLANAR_3]) THEN
+        ASM_MESON_TAC[];
+        ASM_REWRITE_TAC[]])
+     [`v3:real^3 = v2`; `v3:real^3 = v1`; `v2:real^3 = v1`] THEN
+    CONV_TAC NUM_REDUCE_CONV;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `~(coplanar {vec 0:real^3,v1,v2,v3}) /\
+    ~(coplanar {vec 0,--v1,v2,v3}) /\
+    ~(coplanar {vec 0,v1,--v2,v3}) /\
+    ~(coplanar {vec 0,--v1,--v2,v3}) /\
+    ~(coplanar {vec 0,--v1,--v2,v3}) /\
+    ~(coplanar {vec 0,--v1,v2,--v3}) /\
+    ~(coplanar {vec 0,v1,--v2,--v3}) /\
+    ~(coplanar {vec 0,--v1,--v2,--v3}) /\
+    ~(coplanar {vec 0,--v1,--v2,--v3})`
+  STRIP_ASSUME_TAC THENL
+   [REPLICATE_TAC 3
+     (REWRITE_TAC[COPLANAR_INSERT_0_NEG] THEN
+      ONCE_REWRITE_TAC[SET_RULE `{vec 0,a,b,c} = {vec 0,b,c,a}`]) THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  MAP_EVERY tac
+   [I; lhand; rand;
+    lhand o lhand; rand o lhand; lhand o rand; rand o rand] THEN
+  MP_TAC(ISPECL [`v1:real^3`; `v2:real^3`; `v3:real^3`]
+    MEASURE_LUNE_DECOMPOSITION) THEN
+  MP_TAC(ISPECL [`v2:real^3`; `v3:real^3`; `v1:real^3`]
+    MEASURE_LUNE_DECOMPOSITION) THEN
+  MP_TAC(ISPECL [`v3:real^3`; `v1:real^3`; `v2:real^3`]
+    MEASURE_LUNE_DECOMPOSITION) THEN
+  MP_TAC(ISPECL [`--v1:real^3`; `--v2:real^3`; `--v3:real^3`]
+    MEASURE_LUNE_DECOMPOSITION) THEN
+  MP_TAC(ISPECL [`--v2:real^3`; `--v3:real^3`; `--v1:real^3`]
+    MEASURE_LUNE_DECOMPOSITION) THEN
+  MP_TAC(ISPECL [`--v3:real^3`; `--v1:real^3`; `--v2:real^3`]
+    MEASURE_LUNE_DECOMPOSITION) THEN
+  ASM_REWRITE_TAC[VECTOR_NEG_NEG] THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_LE; INSERT_AC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INSERT_AC]) THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[DIHV_NEG_0] THEN
+  REWRITE_TAC[SOLID_TRIANGLE_CONGRUENT_NEG] THEN
+  REWRITE_TAC[INSERT_AC] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Volume of wedge of a frustum.                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_BOUNDED_INTER_OPEN = prove
+ (`!s t:real^N->bool.
+       measurable s /\ bounded s /\ open t ==> measurable(s INTER t)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP BOUNDED_SUBSET_OPEN_INTERVAL) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  DISCH_THEN(SUBST1_TAC o MATCH_MP (SET_RULE
+   `s SUBSET i ==> s INTER t = s INTER (t INTER i)`)) THEN
+  MATCH_MP_TAC MEASURABLE_INTER THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MEASURABLE_OPEN THEN
+  ASM_SIMP_TAC[OPEN_INTER; OPEN_INTERVAL; BOUNDED_INTER; BOUNDED_INTERVAL]);;
+
+let SLICE_SPECIAL_WEDGE = prove
+ (`!w1 w2.
+        ~collinear {vec 0, basis 3, w1} /\ ~collinear {vec 0, basis 3, w2}
+        ==> slice 3 t (wedge (vec 0) (basis 3) w1 w2) =
+            {z | &0 < Arg(z / dropout 3 w1) /\
+                 Arg(z / dropout 3 w1) < Arg(dropout 3 w2 / dropout 3 w1)}`,
+  REWRITE_TAC[wedge] THEN
+  ONCE_REWRITE_TAC[TAUT `~a /\ b /\ c <=> ~(~a ==> ~(b /\ c))`] THEN
+  ASM_SIMP_TAC[AZIM_ARG] THEN REWRITE_TAC[COLLINEAR_BASIS_3] THEN
+  REWRITE_TAC[NOT_IMP; GSYM CONJ_ASSOC; DROPOUT_0] THEN
+  MAP_EVERY ABBREV_TAC
+   [`v1:real^2 = dropout 3 (w1:real^3)`;
+    `v2:real^2 = dropout 3 (w2:real^3)`] THEN
+  REWRITE_TAC[SLICE_DROPOUT_3; VEC_COMPONENT; REAL_SUB_RZERO] THEN
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; COMPLEX_VEC_0] THEN
+  X_GEN_TAC `w:complex` THEN
+  ASM_CASES_TAC `w = Cx(&0)` THEN ASM_REWRITE_TAC[] THEN
+  ASM_REWRITE_TAC[complex_div; COMPLEX_MUL_LZERO; ARG_0; REAL_LT_REFL]);;
+
+let VOLUME_FRUSTT_WEDGE = prove
+ (`!v0 v1:real^3 w1 w2 h a.
+       &0 < a /\ ~collinear {v0,v1,w1} /\ ~collinear {v0,v1,w2}
+       ==> bounded(frustt v0 v1 h a INTER wedge v0 v1 w1 w2) /\
+           measurable(frustt v0 v1 h a INTER wedge v0 v1 w1 w2) /\
+           measure(frustt v0 v1 h a INTER wedge v0 v1 w1 w2) =
+           if &1 <= a \/ h < &0 then &0
+           else azim v0 v1 w1 w2 * ((h / a) pow 2 - h pow 2) * h / &6`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `v1:real^3 = v0` THENL
+   [ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2]; STRIP_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ b /\ (a /\ b ==> c) ==> a /\ b /\ c`) THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC BOUNDED_INTER THEN ASM_SIMP_TAC[VOLUME_FRUSTT_STRONG];
+    MATCH_MP_TAC MEASURABLE_BOUNDED_INTER_OPEN THEN
+    ASM_SIMP_TAC[VOLUME_FRUSTT_STRONG; OPEN_WEDGE];
+    ALL_TAC] THEN
+  REWRITE_TAC[frustt; frustum; rcone_gt; rconesgn; IN_ELIM_THM] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+  GEOM_ORIGIN_TAC `v0:real^3` THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; REAL_MUL_LZERO; DIST_0; real_gt] THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `v1:real^3` THEN
+  X_GEN_TAC `b:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+  ASM_CASES_TAC `b = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+  ASM_SIMP_TAC[COLLINEAR_SPECIAL_SCALE; WEDGE_SPECIAL_SCALE] THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_EQ_0] THEN
+  DISCH_TAC THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
+  ASM_CASES_TAC `&1 <= a` THEN ASM_REWRITE_TAC[] THENL
+   [SUBGOAL_THEN
+     `!y:real^3. ~(norm(y) * norm(b % basis 3:real^3) * a
+                   < y dot (b % basis 3))`
+     (fun th -> REWRITE_TAC[th; EMPTY_GSPEC; MEASURABLE_EMPTY;
+                    INTER_EMPTY; MEASURE_EMPTY]) THEN
+    REWRITE_TAC[REAL_NOT_LT] THEN X_GEN_TAC `y:real^3` THEN
+    MATCH_MP_TAC(REAL_ARITH `abs(x) <= a ==> x <= a`) THEN
+    SIMP_TAC[DOT_RMUL; NORM_MUL; REAL_ABS_MUL; DOT_BASIS; NORM_BASIS;
+             DIMINDEX_3; ARITH] THEN
+    REWRITE_TAC[REAL_ARITH
+     `b * y <= n * (b * &1) * a <=> b * &1 * y <= b * a * n`] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[REAL_ABS_POS] THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN
+    ASM_SIMP_TAC[REAL_POS; REAL_ABS_POS; COMPONENT_LE_NORM; DIMINDEX_3; ARITH];
+    ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LE]) THEN
+  SIMP_TAC[NORM_MUL; NORM_BASIS; DOT_BASIS; DOT_RMUL; DIMINDEX_3; ARITH] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `n * x * a:real = x * n * a`] THEN
+  ASM_REWRITE_TAC[real_abs; REAL_MUL_RID] THEN
+  ASM_SIMP_TAC[REAL_MUL_RID; REAL_LT_LMUL_EQ; REAL_LT_MUL_EQ; NORM_POS_LT] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0; BASIS_NONZERO; DIMINDEX_3; ARITH;
+               REAL_LT_IMP_NZ] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; NORM_LT_SQUARE] THEN
+  ASM_SIMP_TAC[REAL_POW_DIV; REAL_POW_LT; REAL_LT_RDIV_EQ] THEN
+  REWRITE_TAC[REAL_ARITH `(&0 * x < y /\ u < v) /\ &0 < y /\ y < h <=>
+                          &0 < y /\ y < h /\ u < v`] THEN
+  DISCH_TAC THEN MATCH_MP_TAC(INST_TYPE [`:2`,`:M`] FUBINI_SIMPLE_ALT) THEN
+  EXISTS_TAC `3` THEN ASM_REWRITE_TAC[DIMINDEX_2; DIMINDEX_3; ARITH] THEN
+  ASM_SIMP_TAC[WEDGE_SPECIAL_SCALE; REAL_LT_IMP_LE] THEN
+  ASM_SIMP_TAC[REAL_LT_LMUL_EQ; SLICE_INTER; DIMINDEX_2;
+               DIMINDEX_3; ARITH] THEN
+  SUBGOAL_THEN
+   `!t. slice 3 t {y:real^3 | norm y * a < y$3 /\ &0 < y$3 /\ y$3 < h} =
+        if t < h
+        then ball(vec 0:real^2,sqrt(inv(a pow 2) - &1) * t)
+        else {}`
+   (fun th -> ASM_SIMP_TAC[th; SLICE_SPECIAL_WEDGE])
+  THENL
+   [REWRITE_TAC[EXTENSION] THEN
+    MAP_EVERY X_GEN_TAC [`t:real`; `z:real^2`] THEN
+    SIMP_TAC[SLICE_123; DIMINDEX_2; DIMINDEX_3; ARITH; IN_ELIM_THM;
+             VECTOR_3; DOT_3; GSYM DOT_2] THEN
+    ASM_CASES_TAC `t < h` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN
+    REWRITE_TAC[IN_BALL_0; IN_DELETE] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `&0 <= a /\ (a < t <=> u < v) ==> (a < t /\ &0 < t <=> u < v)`) THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; NORM_POS_LE; REAL_LT_IMP_LE] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; NORM_LT_SQUARE] THEN
+    SUBGOAL_THEN `&0 < inv(a pow 2) - &1` ASSUME_TAC THENL
+     [REWRITE_TAC[REAL_SUB_LT] THEN MATCH_MP_TAC REAL_INV_1_LT THEN
+      ASM_SIMP_TAC[REAL_POW_1_LT; REAL_LT_IMP_LE; ARITH; REAL_POW_LT];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[REAL_LT_MUL; SQRT_POS_LT; REAL_POW_MUL; SQRT_POW_2;
+                 REAL_LT_IMP_LE; REAL_LT_MUL_EQ] THEN
+    ASM_SIMP_TAC[real_div; REAL_LT_MUL_EQ; REAL_LT_INV_EQ] THEN
+    ASM_CASES_TAC `&0 < t` THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[DOT_3; DOT_2; VECTOR_3; REAL_INV_POW] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [COND_RATOR; COND_RAND] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RATOR_CONV o LAND_CONV o TOP_DEPTH_CONV)
+   [COND_RATOR; COND_RAND] THEN
+  REWRITE_TAC[INTER_EMPTY; MEASURABLE_EMPTY; MEASURE_EMPTY] THEN
+  REWRITE_TAC[INTER; IN_BALL_0; IN_ELIM_THM] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[COLLINEAR_BASIS_3]) THEN
+  ASM_SIMP_TAC[REWRITE_RULE[HAS_MEASURE_MEASURABLE_MEASURE]
+                 HAS_MEASURE_OPEN_SECTOR_LT_GEN] THEN
+  REWRITE_TAC[COND_ID] THEN
+  SUBGOAL_THEN `&0 < inv(a pow 2) - &1` ASSUME_TAC THENL
+   [REWRITE_TAC[REAL_SUB_LT] THEN MATCH_MP_TAC REAL_INV_1_LT THEN
+    ASM_SIMP_TAC[REAL_POW_1_LT; REAL_LT_IMP_LE; ARITH; REAL_POW_LT];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_LE_MUL_EQ; SQRT_POS_LT] THEN
+  ASM_SIMP_TAC[AZIM_SPECIAL_SCALE; AZIM_ARG; COLLINEAR_BASIS_3] THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_EQ THEN
+  EXISTS_TAC
+   `\t. if &0 < t /\ t < h
+        then Arg(dropout 3 (w2:real^3) / dropout 3 (w1:real^3)) / &2 *
+             (inv(a pow 2) - &1) * t pow 2
+        else &0` THEN
+  CONJ_TAC THENL
+   [X_GEN_TAC `t:real` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+    ASM_CASES_TAC `t < h` THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[REAL_ARITH `&0 <= t <=> t = &0 \/ &0 < t`] THEN
+    ASM_CASES_TAC `t = &0` THEN
+    ASM_REWRITE_TAC[REAL_LT_REFL; REAL_MUL_RZERO; SQRT_0] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[REAL_MUL_RZERO] THEN
+    ASM_SIMP_TAC[REAL_POW_MUL; SQRT_POW_2; REAL_LT_IMP_LE] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[GSYM IN_REAL_INTERVAL; HAS_REAL_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_INTEGRAL_OPEN_INTERVAL] THEN
+  COND_CASES_TAC THENL
+   [ASM_MESON_TAC[REAL_INTERVAL_EQ_EMPTY; HAS_REAL_INTEGRAL_EMPTY];
+    RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LT])] THEN
+  ABBREV_TAC `g = Arg(dropout 3 (w2:real^3) / dropout 3 (w1:real^3))` THEN
+  MP_TAC(ISPECL
+   [`\t. g / &6 * (inv (a pow 2) - &1) * t pow 3`;
+    `\t. g / &2 * (inv (a pow 2) - &1) * t pow 2`;
+    `&0`; `h:real`] REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN
+    REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN
+    CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC REAL_RING;
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    UNDISCH_TAC `&0 < a` THEN CONV_TAC REAL_FIELD]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Wedge of a conic cap.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let VOLUME_CONIC_CAP_WEDGE_WEAK = prove
+ (`!v0 v1:real^3 w1 w2 r a.
+       &0 < a /\ ~collinear {v0,v1,w1} /\ ~collinear {v0,v1,w2}
+       ==> bounded(conic_cap v0 v1 r a INTER wedge v0 v1 w1 w2) /\
+           measurable(conic_cap v0 v1 r a INTER wedge v0 v1 w1 w2) /\
+           measure(conic_cap v0 v1 r a INTER wedge v0 v1 w1 w2) =
+           if &1 <= a \/ r < &0 then &0
+           else azim v0 v1 w1 w2 / &3 * (&1 - a) * r pow 3`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `v1:real^3 = v0` THENL
+   [ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC]; STRIP_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ b /\ (a /\ b ==> c) ==> a /\ b /\ c`) THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC BOUNDED_INTER THEN ASM_SIMP_TAC[VOLUME_CONIC_CAP_STRONG];
+    MATCH_MP_TAC MEASURABLE_BOUNDED_INTER_OPEN THEN
+    ASM_SIMP_TAC[VOLUME_CONIC_CAP_STRONG; OPEN_WEDGE];
+    ALL_TAC] THEN
+  REWRITE_TAC[conic_cap; rcone_gt; rconesgn; IN_ELIM_THM] THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] normball; GSYM ball] THEN
+  CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+  GEOM_ORIGIN_TAC `v0:real^3` THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; REAL_MUL_LZERO; DIST_0; real_gt] THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `v1:real^3` THEN
+  X_GEN_TAC `b:real` THEN
+  ASM_CASES_TAC `b = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+  SIMP_TAC[COLLINEAR_SPECIAL_SCALE; WEDGE_SPECIAL_SCALE] THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_EQ_0] THEN
+  DISCH_TAC THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
+  ASM_CASES_TAC `&1 <= a` THEN ASM_REWRITE_TAC[] THENL
+   [SUBGOAL_THEN
+     `!y:real^3. ~(norm(y) * norm(b % basis 3:real^3) * a
+                   < y dot (b % basis 3))`
+     (fun th -> REWRITE_TAC[th; EMPTY_GSPEC; INTER_EMPTY; MEASURE_EMPTY;
+                         MEASURABLE_EMPTY; BOUNDED_EMPTY; CONVEX_EMPTY]) THEN
+    REWRITE_TAC[REAL_NOT_LT] THEN X_GEN_TAC `y:real^3` THEN
+    MATCH_MP_TAC(REAL_ARITH `abs(x) <= a ==> x <= a`) THEN
+    SIMP_TAC[DOT_RMUL; NORM_MUL; REAL_ABS_MUL; DOT_BASIS; NORM_BASIS;
+             DIMINDEX_3; ARITH] THEN
+    REWRITE_TAC[REAL_ARITH
+     `b * y <= n * (b * &1) * a <=> b * &1 * y <= b * a * n`] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[REAL_ABS_POS] THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN
+    ASM_SIMP_TAC[REAL_POS; REAL_ABS_POS; COMPONENT_LE_NORM; DIMINDEX_3; ARITH];
+    ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LE]) THEN
+  SIMP_TAC[DOT_RMUL; NORM_MUL; REAL_ABS_NORM; DOT_BASIS;
+           DIMINDEX_3; ARITH; NORM_BASIS] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `n * x * a:real = x * n * a`] THEN
+  ASM_REWRITE_TAC[real_abs; REAL_MUL_RID] THEN
+  ASM_SIMP_TAC[REAL_MUL_RID; REAL_LT_LMUL_EQ; REAL_LT_MUL_EQ; NORM_POS_LT] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; NORM_LT_SQUARE] THEN
+  ASM_SIMP_TAC[REAL_POW_DIV; REAL_POW_LT; REAL_LT_RDIV_EQ] THEN
+  REWRITE_TAC[INTER; REAL_MUL_LZERO; IN_BALL_0; IN_ELIM_THM] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0; BASIS_NONZERO; DIMINDEX_3; ARITH;
+               REAL_LT_IMP_NZ] THEN
+  COND_CASES_TAC THENL
+   [ASM_SIMP_TAC[NORM_ARITH `r < &0 ==> ~(norm x < r)`] THEN
+    REWRITE_TAC[EMPTY_GSPEC; MEASURE_EMPTY; MEASURABLE_EMPTY;
+                BOUNDED_EMPTY; CONVEX_EMPTY];
+    RULE_ASSUM_TAC(ONCE_REWRITE_RULE[REAL_NOT_LT])] THEN
+  STRIP_TAC THEN MATCH_MP_TAC(INST_TYPE [`:2`,`:M`] FUBINI_SIMPLE_ALT) THEN
+  EXISTS_TAC `3` THEN ASM_REWRITE_TAC[DIMINDEX_2; DIMINDEX_3; ARITH] THEN
+  SUBGOAL_THEN `&0 < b` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_SIMP_TAC[WEDGE_SPECIAL_SCALE; AZIM_SPECIAL_SCALE] THEN
+  ONCE_REWRITE_TAC[SET_RULE `{x | P x /\ x IN s} = {x | P x} INTER s`] THEN
+  ASM_SIMP_TAC[REAL_LT_LMUL_EQ; SLICE_INTER; DIMINDEX_2;
+               DIMINDEX_3; ARITH] THEN
+  RULE_ASSUM_TAC
+   (REWRITE_RULE[MATCH_MP COLLINEAR_SPECIAL_SCALE (ASSUME `~(b = &0)`)]) THEN
+  SUBGOAL_THEN `&0 < inv(a pow 2) - &1` ASSUME_TAC THENL
+   [REWRITE_TAC[REAL_SUB_LT] THEN MATCH_MP_TAC REAL_INV_1_LT THEN
+    ASM_SIMP_TAC[REAL_POW_1_LT; REAL_LT_IMP_LE; ARITH; REAL_POW_LT];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!t. slice 3 t {y:real^3 | norm y < r /\ norm y * a < y$3} =
+        if &0 < t /\ t < r
+        then ball(vec 0:real^2,min (sqrt(r pow 2 - t pow 2))
+                                   (t * sqrt(inv(a pow 2) - &1)))
+        else {}`
+   (fun th -> ASM_SIMP_TAC[th; SLICE_SPECIAL_WEDGE])
+  THENL
+   [REWRITE_TAC[EXTENSION] THEN
+    MAP_EVERY X_GEN_TAC [`t:real`; `z:real^2`] THEN
+    SIMP_TAC[SLICE_123; DIMINDEX_2; DIMINDEX_3; ARITH; IN_ELIM_THM;
+             VECTOR_3; DOT_3; GSYM DOT_2] THEN
+    ASM_CASES_TAC `&0 < t` THEN ASM_REWRITE_TAC[] THENL
+     [ALL_TAC;
+      REWRITE_TAC[NOT_IN_EMPTY; DE_MORGAN_THM] THEN DISJ2_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+       `~(&0 < t) ==> &0 <= a ==> ~(a < t)`)) THEN
+      ASM_SIMP_TAC[REAL_LE_MUL; NORM_POS_LE; REAL_LT_IMP_LE]] THEN
+    ASM_CASES_TAC `t < r` THEN ASM_REWRITE_TAC[] THENL
+     [ALL_TAC;
+      REWRITE_TAC[NOT_IN_EMPTY; DE_MORGAN_THM] THEN DISJ1_TAC THEN
+      REWRITE_TAC[NORM_LT_SQUARE; DE_MORGAN_THM] THEN DISJ2_TAC THEN
+      REWRITE_TAC[DOT_3; VECTOR_3] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `r <= t /\ &0 <= a /\ &0 <= b ==> ~(a + b + t < r)`) THEN
+      REWRITE_TAC[REAL_LE_SQUARE; REAL_POW_2] THEN
+      MATCH_MP_TAC REAL_LE_MUL2 THEN ASM_REAL_ARITH_TAC] THEN
+    REWRITE_TAC[IN_BALL_0; REAL_LT_MIN] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ] THEN REWRITE_TAC[NORM_LT_SQUARE] THEN
+    SUBGOAL_THEN `&0 < r` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    SUBGOAL_THEN `t pow 2 < r pow 2` ASSUME_TAC THENL
+     [MATCH_MP_TAC REAL_POW_LT2 THEN REWRITE_TAC[ARITH] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; SQRT_POS_LT; REAL_LT_MUL; REAL_SUB_LT;
+                 SQRT_POW_2; REAL_LT_IMP_LE; REAL_POW_MUL] THEN
+    REWRITE_TAC[DOT_2; DOT_3; VECTOR_3] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `a + b + c < d <=> a + b < d - c`] THEN
+    BINOP_TAC THEN AP_TERM_TAC THEN
+    UNDISCH_TAC `&0 < a` THEN CONV_TAC REAL_FIELD;
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [COND_RATOR; COND_RAND] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RATOR_CONV o LAND_CONV o TOP_DEPTH_CONV)
+   [COND_RATOR; COND_RAND] THEN
+  REWRITE_TAC[INTER_EMPTY; MEASURABLE_EMPTY; MEASURE_EMPTY] THEN
+  REWRITE_TAC[INTER; IN_BALL_0; IN_ELIM_THM] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[COLLINEAR_BASIS_3]) THEN
+  ASM_SIMP_TAC[REWRITE_RULE[HAS_MEASURE_MEASURABLE_MEASURE]
+                 HAS_MEASURE_OPEN_SECTOR_LT_GEN] THEN
+  REWRITE_TAC[COND_ID] THEN
+  ASM_SIMP_TAC[REAL_LE_MIN; SQRT_POS_LE; REAL_LT_IMP_LE; REAL_LE_MUL;
+               REAL_POW_LE2; ARITH; REAL_SUB_LE; REAL_LT_MUL; SQRT_POS_LT] THEN
+  REWRITE_TAC[GSYM IN_REAL_INTERVAL; HAS_REAL_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_INTEGRAL_OPEN_INTERVAL] THEN
+  REWRITE_TAC[NORM_POW_2; DOT_3; VECTOR_3; DOT_2] THEN
+  ASM_SIMP_TAC[AZIM_ARG; COLLINEAR_BASIS_3] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH
+   `(&1 - a) * az / &3 * r pow 3 =
+    az / &6 * (inv (a pow 2) - &1) * (a * r) pow 3 +
+    (az * &1 / &3 * (&1 - a) * r pow 3 -
+     az / &6 * (inv (a pow 2) - &1) * (a * r) pow 3)`] THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_COMBINE THEN
+  EXISTS_TAC `a * r:real` THEN
+  REWRITE_TAC[REAL_ARITH `a * r <= r <=> &0 <= r * (&1 - a)`] THEN
+  ASM_SIMP_TAC[REAL_LE_MUL; REAL_SUB_LE; REAL_LT_IMP_LE] THEN
+  ABBREV_TAC `k = Arg(dropout 3 (w2:real^3) / dropout 3 (w1:real^3))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC HAS_REAL_INTEGRAL_EQ THEN EXISTS_TAC
+     `\t. k * t pow 2 * (inv(a pow 2) - &1) / &2` THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `t:real` THEN REWRITE_TAC[IN_REAL_INTERVAL] THEN
+      STRIP_TAC THEN AP_TERM_TAC THEN
+      SUBGOAL_THEN `t pow 2 * (inv(a pow 2) - &1) <= r pow 2 - t pow 2`
+      ASSUME_TAC THENL
+       [REWRITE_TAC[REAL_ARITH `t * (a - &1) <= r - t <=> t * a <= r`] THEN
+        ASM_SIMP_TAC[GSYM real_div; REAL_LE_LDIV_EQ; REAL_POW_LT] THEN
+        REWRITE_TAC[GSYM REAL_POW_MUL] THEN MATCH_MP_TAC REAL_POW_LE2 THEN
+        ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      SUBGOAL_THEN `t * sqrt(inv(a pow 2) - &1) <= sqrt(r pow 2 - t pow 2)`
+        (fun th -> SIMP_TAC[th; REAL_ARITH `a <= b ==> min b a = a`])
+      THENL
+       [MATCH_MP_TAC REAL_POW_LE2_REV THEN EXISTS_TAC `2` THEN
+        REWRITE_TAC[ARITH] THEN
+        SUBGOAL_THEN `&0 <= r pow 2 - t pow 2` ASSUME_TAC THENL
+         [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+           `a <= x ==> &0 <= a ==> &0 <= x`)) THEN
+          ASM_SIMP_TAC[REAL_POW_2; REAL_LE_MUL; REAL_LE_SQUARE; REAL_LT_IMP_LE];
+          ASM_SIMP_TAC[SQRT_POS_LE; REAL_POW_MUL; SQRT_POW_2;
+                       REAL_LT_IMP_LE]];
+        ASM_SIMP_TAC[REAL_POW_MUL; SQRT_POW_2; SQRT_POW_2; REAL_LT_IMP_LE] THEN
+        REAL_ARITH_TAC];
+      MP_TAC(ISPECL
+       [`\t. k / &6 * (inv (a pow 2) - &1) * t pow 3`;
+        `\t. k * t pow 2 * (inv (a pow 2) - &1) / &2`;
+        `&0`; `a * r:real`] REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS) THEN
+      ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE] THEN ANTS_TAC THENL
+       [ASM_REWRITE_TAC[] THEN
+        REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN
+        CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC REAL_RING;
+        MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+        UNDISCH_TAC `&0 < a` THEN CONV_TAC REAL_FIELD]];
+    MATCH_MP_TAC HAS_REAL_INTEGRAL_EQ THEN EXISTS_TAC
+     `\t:real. k * (r pow 2 - t pow 2) / &2` THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `t:real` THEN REWRITE_TAC[IN_REAL_INTERVAL] THEN
+      STRIP_TAC THEN AP_TERM_TAC THEN
+      SUBGOAL_THEN `&0 <= t` ASSUME_TAC THENL
+       [MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `a * r:real` THEN
+        ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE];
+        ALL_TAC] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `a <= b /\ a pow 2 = x ==> x / &2 = (min a b pow 2) / &2`) THEN
+      SUBGOAL_THEN `&0 <= r pow 2 - t pow 2` ASSUME_TAC THENL
+       [REWRITE_TAC[GSYM REAL_LE_SQUARE_ABS; REAL_SUB_LE] THEN
+        ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      ASM_SIMP_TAC[SQRT_POW_2] THEN MATCH_MP_TAC REAL_POW_LE2_REV THEN
+      EXISTS_TAC `2` THEN REWRITE_TAC[ARITH] THEN
+      ASM_SIMP_TAC[SQRT_POW_2; REAL_POW_MUL; REAL_LE_MUL; SQRT_POS_LT;
+                   REAL_LT_MUL; REAL_LT_IMP_LE; SQRT_POS_LE] THEN
+      REWRITE_TAC[REAL_ARITH `r - t <= t * (a - &1) <=> r <= t * a`] THEN
+      REWRITE_TAC[REAL_INV_POW; GSYM REAL_POW_MUL] THEN
+      MATCH_MP_TAC REAL_POW_LE2 THEN
+      ASM_SIMP_TAC[GSYM real_div; REAL_LE_RDIV_EQ] THEN
+      ASM_REAL_ARITH_TAC;
+      MP_TAC(ISPECL
+       [`\t. k / &2 * (r pow 2 * t - t pow 3 / &3)`;
+        `\t. k * (r pow 2 - t pow 2) / &2`;
+        `a * r:real`; `r:real`] REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS) THEN
+      ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE] THEN ANTS_TAC THENL
+       [ASM_REWRITE_TAC[REAL_ARITH `a * r <= r <=> &0 <= r * (&1 - a)`] THEN
+        ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE; REAL_SUB_LE] THEN
+        REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN
+        CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC REAL_RING;
+        MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+        UNDISCH_TAC `&0 < a` THEN CONV_TAC REAL_FIELD]]]);;
+
+let BOUNDED_CONIC_CAP_WEDGE = prove
+ (`!v0 v1:real^3 w1 w2 r a.
+        bounded(conic_cap v0 v1 r a INTER wedge v0 v1 w1 w2)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC BOUNDED_SUBSET THEN
+  EXISTS_TAC `conic_cap (v0:real^3) v1 r a` THEN
+  REWRITE_TAC[BOUNDED_CONIC_CAP] THEN SET_TAC[]);;
+
+let MEASURABLE_CONIC_CAP_WEDGE = prove
+ (`!v0 v1:real^3 w1 w2 r a.
+        measurable(conic_cap v0 v1 r a INTER wedge v0 v1 w1 w2)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC MEASURABLE_BOUNDED_INTER_OPEN THEN
+  REWRITE_TAC[BOUNDED_CONIC_CAP; MEASURABLE_CONIC_CAP; OPEN_WEDGE]);;
+
+let VOLUME_CONIC_CAP_COMPL = prove
+ (`!v0 v1:real^3 w1 w2 r a.
+        &0 <= r
+        ==> measure(conic_cap v0 v1 r a INTER wedge v0 v1 w1 w2) +
+            measure(conic_cap v0 v1 r (--a) INTER wedge v0 v1 w1 w2) =
+            azim v0 v1 w1 w2 * &2 * r pow 3 / &3`,
+  let lemma = prove
+   (`!f:real^N->real^N s t t' u.
+          measurable(s) /\ measurable(t) /\ measurable(u) /\
+          orthogonal_transformation f /\
+          s SUBSET u /\ t' SUBSET u /\ s INTER t' = {} /\
+          negligible(u DIFF (s UNION t')) /\
+          ((!y. ?x. f x = y) ==> IMAGE f t = t')
+          ==> measure s + measure t = measure u`,
+    REPEAT GEN_TAC THEN
+    ASM_CASES_TAC `orthogonal_transformation(f:real^N->real^N)` THEN
+    ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_SURJECTIVE] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC
+     `measure(s:real^N->bool) + measure(t':real^N->bool)` THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[MEASURE_ORTHOGONAL_IMAGE_EQ]; ALL_TAC] THEN
+    W(MP_TAC o PART_MATCH (rhs o rand) MEASURE_DISJOINT_UNION o
+      lhand o snd) THEN
+    ASM_REWRITE_TAC[DISJOINT] THEN ANTS_TAC THENL
+     [ASM_MESON_TAC[MEASURABLE_LINEAR_IMAGE; ORTHOGONAL_TRANSFORMATION_LINEAR];
+      DISCH_THEN(SUBST1_TAC o SYM)] THEN
+    MATCH_MP_TAC MEASURE_NEGLIGIBLE_SYMDIFF THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        NEGLIGIBLE_SUBSET)) THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN SET_TAC[]) in
+  REWRITE_TAC[conic_cap; rcone_gt; NORMBALL_BALL; rconesgn] THEN
+  GEOM_ORIGIN_TAC `v0:real^3` THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; DIST_0; real_gt] THEN
+  GEOM_BASIS_MULTIPLE_TAC 3 `v1:real^3` THEN
+  X_GEN_TAC `v1:real` THEN
+  GEN_REWRITE_TAC LAND_CONV [REAL_ARITH `&0 <= x <=> x = &0 \/ &0 < x`] THEN
+  STRIP_TAC THENL
+   [ASM_SIMP_TAC[VECTOR_MUL_LZERO; WEDGE_DEGENERATE; AZIM_DEGENERATE] THEN
+    REWRITE_TAC[INTER_EMPTY; MEASURE_EMPTY] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM VOLUME_BALL_WEDGE] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `collinear {vec 0:real^3,v1 % basis 3,w1}` THENL
+   [ASM_SIMP_TAC[WEDGE_DEGENERATE; AZIM_DEGENERATE] THEN
+    REWRITE_TAC[INTER_EMPTY; MEASURE_EMPTY] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM VOLUME_BALL_WEDGE] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `collinear {vec 0:real^3,v1 % basis 3,w2}` THENL
+   [ASM_SIMP_TAC[WEDGE_DEGENERATE; AZIM_DEGENERATE] THEN
+    REWRITE_TAC[INTER_EMPTY; MEASURE_EMPTY] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[WEDGE_SPECIAL_SCALE] THEN
+  MAP_EVERY UNDISCH_TAC
+   [`~collinear{vec 0:real^3,v1 % basis 3,w1}`;
+    `~collinear{vec 0:real^3,v1 % basis 3,w2}`] THEN
+  ASM_SIMP_TAC[COLLINEAR_SPECIAL_SCALE] THEN REPEAT DISCH_TAC THEN
+  REWRITE_TAC[NORM_MUL; DOT_RMUL] THEN
+  ASM_SIMP_TAC[REAL_LT_LMUL_EQ; REAL_ARITH
+    `&0 < v1 ==> n * (abs v1 * y) * a = v1 * n * y * a`] THEN
+  MATCH_MP_TAC lemma THEN
+  MP_TAC(ISPECL
+   [`vec 0:real^3`; `basis 3:real^3`; `w1:real^3`; `w2:real^3`;
+    `r:real`; `a:real`] MEASURABLE_CONIC_CAP_WEDGE) THEN
+  MP_TAC(ISPECL
+   [`vec 0:real^3`; `basis 3:real^3`; `w1:real^3`; `w2:real^3`;
+    `r:real`; `--a:real`] MEASURABLE_CONIC_CAP_WEDGE) THEN
+  REWRITE_TAC[conic_cap; rcone_gt; NORMBALL_BALL; rconesgn] THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO; DIST_0; real_gt] THEN
+  REPEAT DISCH_TAC THEN ASM_REWRITE_TAC[MEASURABLE_BALL_WEDGE] THEN
+  SIMP_TAC[NORM_BASIS; DOT_BASIS; DIMINDEX_3; ARITH; REAL_MUL_LID] THEN
+  EXISTS_TAC `(\x. vector[x$1; x$2; --(x$3)]):real^3->real^3` THEN
+  EXISTS_TAC `(ball(vec 0,r) INTER {x | norm x * a > x$3}) INTER
+              wedge (vec 0:real^3) (basis 3) w1 w2` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[ORTHOGONAL_TRANSFORMATION; linear] THEN
+    REWRITE_TAC[CART_EQ; DIMINDEX_3; FORALL_3; VECTOR_3; vector_norm; DOT_3;
+                VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+    REPEAT(GEN_TAC ORELSE CONJ_TAC ORELSE AP_TERM_TAC) THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+  CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_INTER; IN_ELIM_THM; real_gt] THEN
+    MESON_TAC[REAL_LT_ANTISYM];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+    EXISTS_TAC `rcone_eq (vec 0:real^3) (basis 3) a` THEN
+    SIMP_TAC[NEGLIGIBLE_RCONE_EQ; BASIS_NONZERO; DIMINDEX_3; ARITH] THEN
+    REWRITE_TAC[SUBSET; rcone_eq; rconesgn; VECTOR_SUB_RZERO; DIST_0] THEN
+    SIMP_TAC[DOT_BASIS; NORM_BASIS; DIMINDEX_3; ARITH] THEN
+    REWRITE_TAC[IN_DIFF; IN_ELIM_THM; IN_INTER; IN_UNION] THEN
+    GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[] THEN DISCH_TAC THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[IN_INTER; IN_BALL_0; IN_ELIM_THM; VECTOR_3] THEN
+  X_GEN_TAC `x:real^3` THEN
+  SUBGOAL_THEN `norm(vector [x$1; x$2; --(x$3)]:real^3) = norm(x:real^3)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[NORM_EQ; DOT_3; VECTOR_3] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[REAL_ARITH `n * a > --x <=> n * --a < x`] THEN
+  MATCH_MP_TAC(TAUT `(a ==> (b <=> b')) ==> (a /\ b <=> a /\ b')`) THEN
+  STRIP_TAC THEN
+  REWRITE_TAC[COLLINEAR_BASIS_3; wedge; AZIM_ARG] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  SUBGOAL_THEN `(dropout 3 :real^3->real^2) (vector [x$1; x$2; --(x$3)]) =
+                (dropout 3 :real^3->real^2) x`
+   (fun th -> REWRITE_TAC[th]) THEN
+  SIMP_TAC[CART_EQ; DIMINDEX_2; FORALL_2; dropout; LAMBDA_BETA; ARITH;
+           VECTOR_3]);;
+
+let VOLUME_CONIC_CAP_WEDGE_MEDIUM = prove
+ (`!v0 v1:real^3 w1 w2 r a.
+       &0 <= a /\ ~collinear {v0,v1,w1} /\ ~collinear {v0,v1,w2}
+       ==> bounded(conic_cap v0 v1 r a INTER wedge v0 v1 w1 w2) /\
+           measurable(conic_cap v0 v1 r a INTER wedge v0 v1 w1 w2) /\
+           measure(conic_cap v0 v1 r a INTER wedge v0 v1 w1 w2) =
+           if &1 < abs a \/ r < &0 then &0
+           else azim v0 v1 w1 w2 / &3 * (&1 - a) * r pow 3`,
+  REWRITE_TAC[BOUNDED_CONIC_CAP_WEDGE; MEASURABLE_CONIC_CAP_WEDGE] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+   `&0 <= a ==> &0 < a \/ a = &0`))
+  THENL
+   [ASM_SIMP_TAC[VOLUME_CONIC_CAP_WEDGE_WEAK] THEN
+    REWRITE_TAC[REAL_LE_LT] THEN
+    ASM_CASES_TAC `a = &1` THEN ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  COND_CASES_TAC THENL
+   [REWRITE_TAC[conic_cap; NORMBALL_BALL] THEN
+    SUBGOAL_THEN `ball(v0:real^3,r) = {}`
+     (fun th -> SIMP_TAC[th; INTER_EMPTY; MEASURE_EMPTY]) THEN
+    REWRITE_TAC[BALL_EQ_EMPTY] THEN ASM_REAL_ARITH_TAC;
+    MP_TAC(ISPECL [`v0:real^3`; `v1:real^3`; `w1:real^3`; `w2:real^3`;
+                   `r:real`; `&0`] VOLUME_CONIC_CAP_COMPL) THEN
+    REWRITE_TAC[REAL_NEG_0] THEN ASM_REAL_ARITH_TAC]);;
+
+let VOLUME_CONIC_CAP_WEDGE = prove
+ (`!v0 v1:real^3 w1 w2 r a.
+       ~collinear {v0,v1,w1} /\ ~collinear {v0,v1,w2}
+       ==> bounded(conic_cap v0 v1 r a INTER wedge v0 v1 w1 w2) /\
+           measurable(conic_cap v0 v1 r a INTER wedge v0 v1 w1 w2) /\
+           measure(conic_cap v0 v1 r a INTER wedge v0 v1 w1 w2) =
+                if &1 < a \/ r < &0 then &0
+                else azim v0 v1 w1 w2 / &3 * (&1 - max a (-- &1)) * r pow 3`,
+  REWRITE_TAC[BOUNDED_CONIC_CAP_WEDGE; MEASURABLE_CONIC_CAP_WEDGE] THEN
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `&0 <= a` THEN
+  ASM_SIMP_TAC[VOLUME_CONIC_CAP_WEDGE_MEDIUM;
+               REAL_ARITH `&0 <= a ==> abs a = a /\ max a (-- &1) = a`] THEN
+  MP_TAC(ISPECL [`v0:real^3`; `v1:real^3`; `w1:real^3`; `w2:real^3`;
+                   `r:real`; `--a:real`] VOLUME_CONIC_CAP_WEDGE_MEDIUM) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`v0:real^3`; `v1:real^3`; `w1:real^3`; `w2:real^3`;
+                 `r:real`; `a:real`] VOLUME_CONIC_CAP_COMPL) THEN
+  ASM_CASES_TAC `r < &0` THENL
+   [REWRITE_TAC[conic_cap; NORMBALL_BALL] THEN
+    SUBGOAL_THEN `ball(v0:real^3,r) = {}`
+     (fun th -> SIMP_TAC[th; INTER_EMPTY; MEASURE_EMPTY]) THEN
+    REWRITE_TAC[BALL_EQ_EMPTY] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[GSYM REAL_NOT_LT; REAL_ABS_NEG] THEN
+  ASM_SIMP_TAC[REAL_ARITH `~(&0 <= a) ==> ~(&1 < a) /\ abs a = --a`] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [ASM_SIMP_TAC[REAL_ARITH `&1 < --a ==> max a (-- &1) = -- &1`] THEN
+    REAL_ARITH_TAC;
+    ASM_SIMP_TAC[REAL_ARITH `~(&1 < --a) ==> max a (-- &1) = a`] THEN
+    REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Precise formulation of Flyspeck volume properties.                        *)
+(* ------------------------------------------------------------------------- *)
+
+(*** Might be preferable to switch
+ ***
+ *** normball z r -> ball(z,r)
+ *** rect a b -> interval(a,b)
+ ***
+ *** to fit existing libraries. But I left this alone for now,
+ *** to be absolutely sure I didn't introduce new errors.
+ *** I also maintain
+ ***
+ *** NULLSET -> negligible
+ *** vol -> measure
+ ***
+ *** as interface maps for the real^3 case.
+ ***)
+
+let cone = new_definition `cone v S:real^A->bool = affsign sgn_ge {v} S`;;
+
+(*** JRH: should we exclude v for S = {}? Make it always open ***)
+
+let cone0 = new_definition `cone0 v S:real^A->bool = affsign sgn_gt {v} S`;;
+
+(*** JRH changed from cone to cone0 ***)
+
+let solid_triangle = new_definition
+  `solid_triangle v0 S r = normball v0 r INTER cone0 v0 S`;;
+
+let rect = new_definition
+  `rect (a:real^3) (b:real^3) =
+        {(v:real^3) | !i. (a$i < v$i /\ v$i < b$i )}`;;
+
+let RECT_INTERVAL = prove
+ (`!a b. rect a b = interval(a,b)`,
+  REWRITE_TAC[rect; EXTENSION; IN_INTERVAL; IN_ELIM_THM] THEN
+  MESON_TAC[FINITE_INDEX_INRANGE]);;
+
+let RCONE_GE_GT = prove
+ (`rcone_ge z w h =
+        rcone_gt z w h UNION
+        { x | (x - z) dot (w - z) = norm(x - z) * norm(w - z) * h}`,
+  REWRITE_TAC[rcone_ge; rcone_gt; rconesgn] THEN
+  REWRITE_TAC[dist; EXTENSION; IN_UNION; NORM_SUB; IN_ELIM_THM] THEN
+  REAL_ARITH_TAC);;
+
+let RCONE_GT_GE = prove
+ (`rcone_gt z w h =
+        rcone_ge z w h DIFF
+        { x | (x - z) dot (w - z) = norm(x - z) * norm(w - z) * h}`,
+  REWRITE_TAC[rcone_ge; rcone_gt; rconesgn] THEN
+  REWRITE_TAC[dist; EXTENSION; IN_DIFF; NORM_SUB; IN_ELIM_THM] THEN
+  REAL_ARITH_TAC);;
+
+override_interface("NULLSET",`negligible:(real^3->bool)->bool`);;
+override_interface("vol",`measure:(real^3->bool)->real`);;
+
+let is_sphere= new_definition
+  `is_sphere x=(?(v:real^3)(r:real). (r> &0)/\ (x={w:real^3 | norm (w-v)= r}))`;;
+
+let c_cone = new_definition
+  `c_cone (v,w:real^3, r:real)=
+       {x:real^3 | ((x-v) dot w = norm (x-v)* norm w* r)}`;;
+
+(*** JRH added the condition ~(w = 0), or the cone is all of space ***)
+
+let circular_cone =new_definition
+  `circular_cone (V:real^3-> bool)=
+   (? (v,w:real^3)(r:real). ~(w = vec 0) /\ V = c_cone (v,w,r))`;;
+
+let NULLSET_RULES = prove
+ (`(!P. ((plane P)\/ (is_sphere P) \/ (circular_cone P)) ==> NULLSET P) /\
+   (!(s:real^3->bool) t. (NULLSET s /\ NULLSET t) ==> NULLSET (s UNION t))`,
+  SIMP_TAC[NEGLIGIBLE_UNION] THEN
+  X_GEN_TAC `s:real^3->bool` THEN STRIP_TAC THENL
+   [MATCH_MP_TAC COPLANAR_IMP_NEGLIGIBLE THEN
+    SIMP_TAC[COPLANAR; DIMINDEX_3; ARITH] THEN ASM_MESON_TAC[SUBSET_REFL];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [is_sphere]) THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[GSYM dist] THEN
+    ONCE_REWRITE_TAC[DIST_SYM] THEN
+    REWRITE_TAC[REWRITE_RULE[sphere] NEGLIGIBLE_SPHERE];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [circular_cone]) THEN
+    REWRITE_TAC[EXISTS_PAIRED_THM; c_cone] THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPECL [`w + v:real^3`; `v:real^3`; `r:real`]
+     NEGLIGIBLE_RCONE_EQ) THEN
+    ASM_REWRITE_TAC[rcone_eq; rconesgn] THEN
+    REWRITE_TAC[dist; VECTOR_ARITH `(w + v) - v:real^N = w`] THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH `w + v:real^N = v <=> w = vec 0`]]);;
+
+(*** JRH added &0 < a for frustum; otherwise it's in general unbounded ***)
+
+let primitive = new_definition `primitive (C:real^3->bool) =
+  ((?v0 v1 v2 v3 r.  (C = solid_triangle v0 {v1,v2,v3} r)) \/
+  (?v0 v1 v2 v3. (C = conv0 {v0,v1,v2,v3})) \/
+  (?v0 v1 v2 v3 h a. &0 < a /\
+                     (C = frustt v0 v1 h a INTER wedge v0 v1 v2 v3)) \/
+  (?v0 v1 v2 v3 r c. (C = conic_cap v0 v1 r c INTER wedge v0 v1 v2 v3)) \/
+  (?a b.  (C = rect a b)) \/
+  (?t r. (C = ellipsoid t r)) \/
+  (?v0 v1 v2 v3 r. (C = normball v0 r INTER wedge v0 v1 v2 v3)))`;;
+
+let MEASURABLE_RULES = prove
+ (`(!C. primitive C ==> measurable C) /\
+   (!Z. NULLSET Z ==> measurable Z) /\
+   (!X t. measurable X ==> (measurable (IMAGE (scale t) X))) /\
+   (!X v. measurable X ==> (measurable (IMAGE ((+) v) X))) /\
+   (!(s:real^3->bool) t. (measurable s /\ measurable t)
+                         ==> measurable (s UNION t)) /\
+   (!(s:real^3->bool) t. (measurable s /\ measurable t)
+                         ==> measurable (s INTER t)) /\
+   (!(s:real^3->bool) t. (measurable s /\ measurable t)
+                         ==> measurable (s DIFF t))`,
+  SIMP_TAC[MEASURABLE_UNION; MEASURABLE_INTER; MEASURABLE_DIFF] THEN
+  REWRITE_TAC[REWRITE_RULE[ETA_AX] MEASURABLE_TRANSLATION] THEN
+  SIMP_TAC[GSYM HAS_MEASURE_0; HAS_MEASURE_MEASURABLE_MEASURE] THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    MAP_EVERY X_GEN_TAC [`X:real^3->bool`; `t:real^3`] THEN
+    REWRITE_TAC[HAS_MEASURE_MEASURE] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_MEASURE_STRETCH) THEN
+    DISCH_THEN(MP_TAC o SPEC `\i. (t:real^3)$i`) THEN
+    REWRITE_TAC[HAS_MEASURE_MEASURABLE_MEASURE] THEN
+    DISCH_THEN(MP_TAC o CONJUNCT1) THEN MATCH_MP_TAC EQ_IMP THEN
+    AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    SIMP_TAC[FUN_EQ_THM; scale; CART_EQ; LAMBDA_BETA;
+             DIMINDEX_3; VECTOR_3; FORALL_3]] THEN
+  X_GEN_TAC `C:real^3->bool` THEN REWRITE_TAC[primitive] THEN
+  REWRITE_TAC[NORMBALL_BALL; RECT_INTERVAL] THEN
+  DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN MP_TAC) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+   [REPEAT STRIP_TAC THEN
+    ASM_REWRITE_TAC[solid_triangle; NORMBALL_BALL; cone0; GSYM aff_gt_def] THEN
+    REWRITE_TAC[MEASURABLE_BALL_AFF_GT];
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MEASURABLE_CONV0 THEN MATCH_MP_TAC FINITE_IMP_BOUNDED THEN
+    REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY];
+    MAP_EVERY X_GEN_TAC
+     [`v0:real^3`; `v1:real^3`; `v2:real^3`; `v3:real^3`;
+      `h:real`; `a:real`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC) THEN
+    ASM_CASES_TAC `collinear {v0:real^3, v1, v2}` THENL
+     [ASM_SIMP_TAC[WEDGE_DEGENERATE; INTER_EMPTY; MEASURABLE_EMPTY];
+      ALL_TAC] THEN
+    ASM_CASES_TAC `collinear {v0:real^3, v1, v3}` THENL
+     [ASM_SIMP_TAC[WEDGE_DEGENERATE; INTER_EMPTY; MEASURABLE_EMPTY];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[VOLUME_FRUSTT_WEDGE];
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MEASURABLE_BOUNDED_INTER_OPEN THEN
+    REWRITE_TAC[MEASURABLE_CONIC_CAP; BOUNDED_CONIC_CAP; OPEN_WEDGE];
+    SIMP_TAC[MEASURABLE_INTERVAL];
+    SIMP_TAC[MEASURABLE_ELLIPSOID];
+    SIMP_TAC[MEASURABLE_BALL_WEDGE]]);;
+
+let vol_solid_triangle = new_definition `vol_solid_triangle v0 v1 v2 v3 r =
+   let a123 = dihV v0 v1 v2 v3 in
+   let a231 = dihV v0 v2 v3 v1 in
+   let a312 = dihV v0 v3 v1 v2 in
+     (a123 + a231 + a312 - pi)*(r pow 3)/(&3)`;;
+
+let vol_frustt_wedge = new_definition `vol_frustt_wedge v0 v1 v2 v3 h a =
+       (azim v0 v1 v2 v3)*(h pow 3)*(&1/(a*a) - &1)/(&6)`;;
+
+let vol_conic_cap_wedge = new_definition `vol_conic_cap_wedge v0 v1 v2 v3 r c =
+       (azim v0 v1 v2 v3)*(&1 - c)*(r pow 3)/(&3)`;;
+
+(*** JRH corrected delta_x x12 x13 x14 x34 x24 x34 ***)
+(*** to delta_x x12 x13 x14 x34 x24 x23            ***)
+
+let vol_conv = new_definition `vol_conv v1 v2 v3 v4 =
+   let x12 = dist(v1,v2) pow 2 in
+   let x13 = dist(v1,v3) pow 2 in
+   let x14 = dist(v1,v4) pow 2 in
+   let x23 = dist(v2,v3) pow 2 in
+   let x24 = dist(v2,v4) pow 2 in
+   let x34 = dist(v3,v4) pow 2 in
+   sqrt(delta_x x12 x13 x14 x34 x24 x23)/(&12)`;;
+
+let vol_rect = new_definition `vol_rect a b =
+   if (a$1 < b$1) /\ (a$2 < b$2) /\ (a$3 < b$3) then
+   (b$3-a$3)*(b$2-a$2)*(b$1-a$1) else &0`;;
+
+let vol_ball_wedge = new_definition `vol_ball_wedge v0 v1 v2 v3 r =
+   (azim v0 v1 v2 v3)*(&2)*(r pow 3)/(&3)`;;
+
+let SDIFF = new_definition `SDIFF X Y = (X DIFF Y) UNION (Y DIFF X)`;;
+
+(*** JRH added the hypothesis "measurable" to the first one ***)
+(*** Could change the definition to make this hold anyway   ***)
+
+(*** JRH changed solid triangle hypothesis to ~coplanar{...} ***)
+(*** since the current condition is not enough in general    ***)
+
+let volume_props = prove
+ (`(!C. measurable C ==> vol C >= &0) /\
+   (!Z. NULLSET Z ==> (vol Z = &0)) /\
+   (!X Y. measurable X /\ measurable Y /\ NULLSET (SDIFF X Y)
+          ==> (vol X = vol Y)) /\
+   (!X t. (measurable X) /\ (measurable (IMAGE (scale t) X))
+          ==> (vol (IMAGE (scale t) X) = abs(t$1 * t$2 * t$3)*vol(X))) /\
+   (!X v. measurable X ==> (vol (IMAGE ((+) v) X) = vol X)) /\
+   (!v0 v1 v2 v3 r. (r > &0) /\ ~coplanar{v0,v1,v2,v3}
+                    ==> vol (solid_triangle v0 {v1,v2,v3} r) =
+                        vol_solid_triangle v0 v1 v2 v3 r) /\
+   (!v0 v1 v2 v3. vol(conv0 {v0,v1,v2,v3}) = vol_conv v0 v1 v2 v3) /\
+   (!v0 v1 v2 v3 h a. ~(collinear {v0,v1,v2}) /\ ~(collinear {v0,v1,v3}) /\
+                      (h >= &0) /\ (a > &0) /\ (a <= &1)
+                      ==> vol(frustt v0 v1 h a INTER wedge v0 v1 v2 v3) =
+                          vol_frustt_wedge v0 v1 v2 v3 h a) /\
+   (!v0 v1 v2 v3 r c.  ~(collinear {v0,v1,v2}) /\ ~(collinear {v0,v1,v3}) /\
+                       (r >= &0) /\ (c >= -- (&1)) /\ (c <= &1)
+                       ==> (vol(conic_cap v0 v1 r c INTER wedge v0 v1 v2 v3) =
+                           vol_conic_cap_wedge v0 v1 v2 v3 r c)) /\
+   (!(a:real^3) (b:real^3). vol(rect a b) = vol_rect a b) /\
+   (!v0 v1 v2 v3 r. ~(collinear {v0,v1,v2}) /\ ~(collinear {v0,v1,v3}) /\
+                    (r >= &0)
+                    ==> (vol(normball v0 r INTER wedge v0 v1 v2 v3) =
+                         vol_ball_wedge v0 v1 v2 v3 r))`,
+  SIMP_TAC[MEASURE_POS_LE; real_ge; real_gt] THEN REPEAT CONJ_TAC THENL
+   [SIMP_TAC[GSYM HAS_MEASURE_0; HAS_MEASURE_MEASURABLE_MEASURE];
+    MAP_EVERY X_GEN_TAC [`s:real^3->bool`; `t:real^3->bool`] THEN
+    STRIP_TAC THEN MATCH_MP_TAC MEASURE_NEGLIGIBLE_SYMDIFF THEN
+    ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        NEGLIGIBLE_SUBSET)) THEN
+    REWRITE_TAC[SDIFF] THEN SET_TAC[];
+    MAP_EVERY X_GEN_TAC [`X:real^3->bool`; `t:real^3`] THEN
+    REWRITE_TAC[HAS_MEASURE_MEASURE] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_MEASURE_STRETCH o CONJUNCT1) THEN
+    DISCH_THEN(MP_TAC o SPEC `\i. (t:real^3)$i`) THEN
+    REWRITE_TAC[HAS_MEASURE_MEASURABLE_MEASURE] THEN
+    DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+    REWRITE_TAC[DIMINDEX_3; PRODUCT_3] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN
+    AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    SIMP_TAC[FUN_EQ_THM; scale; CART_EQ; LAMBDA_BETA;
+             DIMINDEX_3; VECTOR_3; FORALL_3];
+    REWRITE_TAC[REWRITE_RULE[ETA_AX] MEASURE_TRANSLATION];
+    REPEAT STRIP_TAC THEN
+    REWRITE_TAC[solid_triangle; vol_solid_triangle; NORMBALL_BALL] THEN
+    REWRITE_TAC[cone0; GSYM aff_gt_def] THEN
+    MATCH_MP_TAC VOLUME_SOLID_TRIANGLE THEN ASM_REWRITE_TAC[];
+    REWRITE_TAC[vol_conv; VOLUME_OF_TETRAHEDRON];
+    SIMP_TAC[VOLUME_FRUSTT_WEDGE; vol_frustt_wedge] THEN
+    SIMP_TAC[REAL_ARITH `&0 <= h ==> ~(h < &0)`] THEN
+    SIMP_TAC[REAL_ARITH `a <= &1 ==> (&1 <= a <=> a = &1)`] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD;
+    SIMP_TAC[VOLUME_CONIC_CAP_WEDGE; vol_conic_cap_wedge] THEN
+    SIMP_TAC[REAL_ARITH `&0 <= r ==> ~(r < &0)`] THEN
+    SIMP_TAC[REAL_ARITH `c <= &1 ==> ~(&1 < c)`] THEN
+    ASM_SIMP_TAC[REAL_ARITH `-- &1 <= c ==> max c (-- &1) = c`] THEN
+    REPEAT STRIP_TAC THEN REAL_ARITH_TAC;
+    REWRITE_TAC[vol_rect; RECT_INTERVAL; MEASURE_INTERVAL] THEN
+    REWRITE_TAC[CONTENT_CLOSED_INTERVAL_CASES] THEN
+    REWRITE_TAC[DIMINDEX_3; FORALL_3; PRODUCT_3] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^3`; `b:real^3`] THEN
+    REWRITE_TAC[REAL_LE_LT] THEN
+    ASM_CASES_TAC `(a:real^3)$1 = (b:real^3)$1` THEN
+    ASM_REWRITE_TAC[REAL_LT_REFL; REAL_MUL_LZERO; REAL_MUL_RZERO;
+                    REAL_SUB_REFL; COND_ID] THEN
+    ASM_CASES_TAC `(a:real^3)$2 = (b:real^3)$2` THEN
+    ASM_REWRITE_TAC[REAL_LT_REFL; REAL_MUL_LZERO; REAL_MUL_RZERO;
+                    REAL_SUB_REFL; COND_ID] THEN
+    ASM_CASES_TAC `(a:real^3)$3 = (b:real^3)$3` THEN
+    ASM_REWRITE_TAC[REAL_LT_REFL; REAL_MUL_LZERO; REAL_MUL_RZERO;
+                    REAL_SUB_REFL; COND_ID] THEN
+    REWRITE_TAC[REAL_MUL_AC];
+    SIMP_TAC[VOLUME_BALL_WEDGE; NORMBALL_BALL; vol_ball_wedge]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Additional results on polyhedra and relation to fans.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let POLYHEDRON_COLLINEAR_FACES_STRONG = prove
+ (`!P:real^N->bool f f' p q s t.
+        polyhedron P /\ vec 0 IN relative_interior P /\
+        f face_of P /\ ~(f = P) /\ f' face_of P /\ ~(f' = P) /\
+        p IN f /\ q IN f' /\ s > &0 /\ t > &0 /\ s % p = t % q
+        ==> s = t`,
+  ONCE_REWRITE_TAC[MESON[]
+   `(!P f f' p q s t. Q P f f' p q s t) <=>
+    (!s t P f f' p q. Q P f f' p q s t)`] THEN
+  MATCH_MP_TAC REAL_WLOG_LT THEN
+  REWRITE_TAC[real_gt] THEN CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(TAUT `F ==> p`) THEN
+  FIRST_X_ASSUM(MP_TAC o AP_TERM `(%) (inv s):real^N->real^N`) THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; REAL_LT_IMP_NZ] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  REWRITE_TAC[VECTOR_MUL_LID; GSYM real_div] THEN
+  ABBREV_TAC `u:real = t / s` THEN
+  SUBGOAL_THEN `&0 < u /\ &1 < u` MP_TAC THENL
+   [EXPAND_TAC "u" THEN ASM_SIMP_TAC[REAL_LT_RDIV_EQ] THEN
+    ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID];
+    ALL_TAC] THEN
+  MAP_EVERY (C UNDISCH_THEN (K ALL_TAC))
+   [`s < t`; `&0 < s`; `&0 < t`; `t:real / s = u`] THEN
+  SPEC_TAC(`u:real`,`t:real`) THEN GEN_TAC THEN STRIP_TAC THEN
+  DISCH_THEN(ASSUME_TAC o SYM) THEN
+  SUBGOAL_THEN `?g:real^N->bool. g facet_of P /\ f' SUBSET g`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC FACE_OF_POLYHEDRON_SUBSET_FACET THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~((vec 0:real^N) IN g)` ASSUME_TAC THENL
+   [DISCH_TAC THEN
+    MP_TAC(ISPECL [`P:real^N->bool`; `g:real^N->bool`; `P:real^N->bool`]
+                   SUBSET_OF_FACE_OF) THEN
+    ASM_REWRITE_TAC[SUBSET_REFL; NOT_IMP] THEN CONJ_TAC THENL
+     [CONJ_TAC THENL [ASM_MESON_TAC[facet_of]; ASM SET_TAC[]];
+      ASM_MESON_TAC[facet_of; FACET_OF_REFL;
+                    SUBSET_ANTISYM; FACE_OF_IMP_SUBSET]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(g:real^N->bool) face_of P` MP_TAC THENL
+   [ASM_MESON_TAC[facet_of]; ALL_TAC] THEN
+  REWRITE_TAC[face_of] THEN DISCH_THEN(MP_TAC o last o CONJUNCTS) THEN
+  DISCH_THEN(MP_TAC o SPECL [`vec 0:real^N`; `t % q:real^N`; `q:real^N`]) THEN
+  ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[RELATIVE_INTERIOR_SUBSET; SUBSET];
+    ASM_MESON_TAC[FACE_OF_IMP_SUBSET; SUBSET];
+    ASM_MESON_TAC[FACE_OF_IMP_SUBSET; SUBSET];
+    ALL_TAC] THEN
+  EXPAND_TAC "p" THEN REWRITE_TAC[IN_SEGMENT] THEN CONJ_TAC THENL
+   [CONV_TAC(RAND_CONV SYM_CONV) THEN
+    ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ] THEN ASM SET_TAC[];
+    EXISTS_TAC `inv t:real` THEN
+    ASM_SIMP_TAC[REAL_LT_INV_EQ; REAL_INV_LT_1] THEN
+    EXPAND_TAC "p" THEN REWRITE_TAC[VECTOR_MUL_ASSOC] THEN
+    ASM_SIMP_TAC[REAL_MUL_LINV; REAL_LT_IMP_NZ] THEN VECTOR_ARITH_TAC]);;
+
+let POLYHEDRON_COLLINEAR_FACES = prove
+ (`!P:real^N->bool f f' p q s t.
+        polyhedron P /\ vec 0 IN interior P /\
+        f face_of P /\ ~(f = P) /\ f' face_of P /\ ~(f' = P) /\
+        p IN f /\ q IN f' /\ s > &0 /\ t > &0 /\ s % p = t % q
+        ==> s = t`,
+  MESON_TAC[POLYHEDRON_COLLINEAR_FACES_STRONG;
+            INTERIOR_SUBSET_RELATIVE_INTERIOR; SUBSET]);;
+
+let vertices = new_definition
+ `vertices s = {x:real^N | x extreme_point_of s}`;;
+
+let edges = new_definition
+ `edges s = {{v,w} | segment[v,w] edge_of s}`;;
+
+let VERTICES_TRANSLATION = prove
+ (`!a s. vertices (IMAGE (\x. a + x) s) = IMAGE (\x. a + x) (vertices s)`,
+  REWRITE_TAC[vertices] THEN GEOM_TRANSLATE_TAC[]);;
+
+let VERTICES_LINEAR_IMAGE = prove
+ (`!f s. linear f /\ (!x y. f x = f y ==> x = y)
+         ==> vertices(IMAGE f s) = IMAGE f (vertices s)`,
+  REWRITE_TAC[vertices; EXTREME_POINTS_OF_LINEAR_IMAGE]);;
+
+let EDGES_TRANSLATION = prove
+ (`!a s. edges (IMAGE (\x. a + x) s) = IMAGE (IMAGE (\x. a + x)) (edges s)`,
+  REWRITE_TAC[edges] THEN GEOM_TRANSLATE_TAC[] THEN SET_TAC[]);;
+
+let EDGES_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> edges(IMAGE f s) = IMAGE (IMAGE f) (edges s)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[edges] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; FORALL_IN_IMAGE] THEN CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+    REWRITE_TAC[IN_IMAGE] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+    REWRITE_TAC[EXISTS_IN_GSPEC] THEN
+    SUBGOAL_THEN `?v w. x = (f:real^M->real^N) v /\ y = f w` MP_TAC THENL
+     [ASM_MESON_TAC[ENDS_IN_SEGMENT; EDGE_OF_IMP_SUBSET; SUBSET; IN_IMAGE];
+      REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+      DISCH_THEN(CONJUNCTS_THEN SUBST_ALL_TAC)];
+    MAP_EVERY X_GEN_TAC [`v:real^M`; `w:real^M`] THEN DISCH_TAC THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    MAP_EVERY EXISTS_TAC [`(f:real^M->real^N) v`; `(f:real^M->real^N) w`]] THEN
+  REWRITE_TAC[IMAGE_CLAUSES] THEN
+  ASM_MESON_TAC[EDGE_OF_LINEAR_IMAGE; CLOSED_SEGMENT_LINEAR_IMAGE]);;
+
+add_translation_invariants [VERTICES_TRANSLATION; EDGES_TRANSLATION];;
+add_linear_invariants [VERTICES_LINEAR_IMAGE; EDGES_LINEAR_IMAGE];;
+
+(*** Correspondence with Flypaper:
+
+Definition 4.5:   IS_AFFINE_HULL
+                  affine / hull
+                  aff_dim
+                  AFF_DIM_EMPTY
+
+Definition 4.6 :  IN_INTERIOR
+                  IN_RELATIVE_INTERIOR
+                  CLOSURE_APPROACHABLE
+                  (Don't have definition of relative boundary, but several
+                   theorems use closure s DIFF relative_interior s.)
+
+Definition 4.7:   face_of
+                  extreme_point_of (presumably it's meant to be the point not
+                  the singleton set, which the definition literally gives)
+                  facet_of
+                  edge_of
+                  (Don't have a definition of "proper"; I just use
+                   ~(f = {}) and/or ~(f = P) as needed.)
+
+Lemma 4.18:       KREIN_MILMAN_MINKOWSKI
+
+Definition 4.8:   polyhedron
+                  vertices
+
+Lemma 4.19:       AFFINE_IMP_POLYHEDRON
+
+Lemma 4.20 (i):   FACET_OF_POLYHEDRON_EXPLICIT
+
+Lemma 4.20 (ii):  Direct consequence of RELATIVE_INTERIOR_POLYHEDRON
+
+Lemma 4.20 (iii): FACE_OF_POLYHEDRON_EXPLICIT / FACE_OF_POLYHEDRON
+
+Lemma 4.20 (iv):  FACE_OF_TRANS
+
+Lemma 4.20 (v):   EXTREME_POINT_OF_FACE
+
+Lemma 4.20 (vi):  FACE_OF_EQ
+
+Corr. 4.7:        FACE_OF_POLYHEDRON_POLYHEDRON
+
+Lemma 4.21:       POLYHEDRON_COLLINEAR_FACES
+
+Def 4.9:          vertices
+                  edges
+
+****)
+
+(* ------------------------------------------------------------------------- *)
+(* Temporary backwards-compatible fix for introduction of "sphere" and       *)
+(* "relative_frontier".                                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPACT_SPHERE =
+  REWRITE_RULE[sphere; NORM_ARITH `dist(a:real^N,b) = norm(b - a)`]
+  COMPACT_SPHERE;;
+
+let FRONTIER_CBALL = REWRITE_RULE[sphere] FRONTIER_CBALL;;
+
+let NEGLIGIBLE_SPHERE = REWRITE_RULE[sphere] NEGLIGIBLE_SPHERE;;
+
+let RELATIVE_FRONTIER_OF_POLYHEDRON = RELATIVE_BOUNDARY_OF_POLYHEDRON;;
+
+(* ------------------------------------------------------------------------- *)
+(* Fix the congruence rules as expected in Flyspeck.                         *)
+(* Should exclude 6 recent mixed real/vector limit results.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let bcs =
+  [`(p <=> p') ==> (p' ==> (q <=> q')) ==> (p ==> q <=> p' ==> q')`;
+   `(g <=> g')
+    ==> (g' ==> t = t')
+    ==> (~g' ==> e = e')
+    ==> (if g then t else e) = (if g' then t' else e')`;
+   `(!x. p x ==> f x = g x) ==> nsum {y | p y} (\i. f i) = nsum {y | p y} g`;
+   `(!i. a <= i /\ i <= b ==> f i = g i)
+    ==> nsum (a..b) (\i. f i) = nsum (a..b) g`;
+   `(!x. x IN s ==> f x = g x) ==> nsum s (\i. f i) = nsum s g`;
+   `(!x. p x ==> f x = g x) ==> sum {y | p y} (\i. f i) = sum {y | p y} g`;
+   `(!i. a <= i /\ i <= b ==> f i = g i)
+    ==> sum (a..b) (\i. f i) = sum (a..b) g`;
+   `(!x. x IN s ==> f x = g x) ==> sum s (\i. f i) = sum s g`;
+   `(!x. p x ==> f x = g x) ==> vsum {y | p y} (\i. f i) = vsum {y | p y} g`;
+   `(!i. a <= i /\ i <= b ==> f i = g i)
+    ==> vsum (a..b) (\i. f i) = vsum (a..b) g`;
+   `(!x. x IN s ==> f x = g x) ==> vsum s (\i. f i) = vsum s g`;
+   `(!x. p x ==> f x = g x)
+    ==> product {y | p y} (\i. f i) = product {y | p y} g`;
+   `(!i. a <= i /\ i <= b ==> f i = g i)
+    ==> product (a..b) (\i. f i) = product (a..b) g`;
+   `(!x. x IN s ==> f x = g x) ==> product s (\i. f i) = product s g`;
+   `(!x. ~(x = a) ==> f x = g x)
+    ==> (((\x. f x) --> l) (at a) <=> (g --> l) (at a))`;
+   `(!x. ~(x = a) ==> f x = g x)
+    ==> (((\x. f x) --> l) (at a within s) <=> (g --> l) (at a within s))`]
+and equiv t1 t2 = can (term_match [] t1) t2 & can (term_match [] t2) t1 in
+let congs' =
+  filter (fun th -> exists (equiv (concl th)) bcs) (basic_congs()) in
+set_basic_congs congs';;
diff --git a/Multivariate/geom.ml b/Multivariate/geom.ml
new file mode 100644 (file)
index 0000000..d14a463
--- /dev/null
@@ -0,0 +1,933 @@
+(* ========================================================================= *)
+(* Some geometric notions in real^N.                                         *)
+(* ========================================================================= *)
+
+needs "Multivariate/realanalysis.ml";;
+
+prioritize_vector();;
+
+(* ------------------------------------------------------------------------- *)
+(* Pythagoras's theorem is almost immediate.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let PYTHAGORAS = prove
+ (`!A B C:real^N.
+        orthogonal (A - B) (C - B)
+        ==> norm(C - A) pow 2 = norm(B - A) pow 2 + norm(C - B) pow 2`,
+  REWRITE_TAC[NORM_POW_2; orthogonal; DOT_LSUB; DOT_RSUB; DOT_SYM] THEN
+  CONV_TAC REAL_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* Angle between vectors (always 0 <= angle <= pi).                          *)
+(* ------------------------------------------------------------------------- *)
+
+let vector_angle = new_definition
+ `vector_angle x y = if x = vec 0 \/ y = vec 0 then pi / &2
+               else acs((x dot y) / (norm x * norm y))`;;
+
+let VECTOR_ANGLE_LINEAR_IMAGE_EQ = prove
+ (`!f x y. linear f /\ (!x. norm(f x) = norm x)
+           ==> (vector_angle (f x) (f y) = vector_angle x y)`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[vector_angle; GSYM NORM_EQ_0] THEN
+  ASM_MESON_TAC[PRESERVES_NORM_PRESERVES_DOT]);;
+
+add_linear_invariants [VECTOR_ANGLE_LINEAR_IMAGE_EQ];;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic properties of vector angles.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let VECTOR_ANGLE_REFL = prove
+ (`!x. vector_angle x x = if x = vec 0 then pi / &2 else &0`,
+  GEN_TAC THEN REWRITE_TAC[vector_angle; DISJ_ACI] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[GSYM NORM_POW_2; REAL_POW_2] THEN
+  ASM_SIMP_TAC[REAL_DIV_REFL; REAL_ENTIRE; NORM_EQ_0; ACS_1]);;
+
+let VECTOR_ANGLE_SYM = prove
+ (`!x y. vector_angle x y = vector_angle y x`,
+  REWRITE_TAC[vector_angle; DISJ_SYM; DOT_SYM; REAL_MUL_SYM]);;
+
+let VECTOR_ANGLE_LMUL = prove
+ (`!a x y:real^N.
+        vector_angle (a % x) y =
+                if a = &0 then pi / &2
+                else if &0 <= a then vector_angle x y
+                else pi - vector_angle x y`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[vector_angle; VECTOR_MUL_EQ_0] THEN
+  ASM_CASES_TAC `x:real^N = vec 0 \/ y:real^N = vec 0` THEN
+  ASM_REWRITE_TAC[] THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[NORM_MUL; DOT_LMUL; real_div; REAL_INV_MUL; real_abs] THEN
+  COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[REAL_INV_NEG; REAL_MUL_LNEG; REAL_MUL_RNEG] THEN
+  ASM_SIMP_TAC[REAL_FIELD
+   `~(a = &0) ==> (a * x) * (inv a * y) * z = x * y * z`] THEN
+  MATCH_MP_TAC ACS_NEG THEN
+  REWRITE_TAC[GSYM REAL_ABS_BOUNDS; GSYM REAL_INV_MUL] THEN
+  REWRITE_TAC[GSYM real_div; NORM_CAUCHY_SCHWARZ_DIV]);;
+
+let VECTOR_ANGLE_RMUL = prove
+ (`!a x y:real^N.
+        vector_angle x (a % y) =
+                if a = &0 then pi / &2
+                else if &0 <= a then vector_angle x y
+                else pi - vector_angle x y`,
+  ONCE_REWRITE_TAC[VECTOR_ANGLE_SYM] THEN
+  REWRITE_TAC[VECTOR_ANGLE_LMUL]);;
+
+let VECTOR_ANGLE_LNEG = prove
+ (`!x y. vector_angle (--x) y = pi - vector_angle x y`,
+  REWRITE_TAC[VECTOR_ARITH `--x = -- &1 % x`; VECTOR_ANGLE_LMUL] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let VECTOR_ANGLE_RNEG = prove
+ (`!x y. vector_angle x (--y) = pi - vector_angle x y`,
+  ONCE_REWRITE_TAC[VECTOR_ANGLE_SYM] THEN REWRITE_TAC[VECTOR_ANGLE_LNEG]);;
+
+let VECTOR_ANGLE_NEG2 = prove
+ (`!x y. vector_angle (--x) (--y) = vector_angle x y`,
+  REWRITE_TAC[VECTOR_ANGLE_LNEG; VECTOR_ANGLE_RNEG] THEN REAL_ARITH_TAC);;
+
+let VECTOR_ANGLE = prove
+ (`!x y:real^N. x dot y = norm(x) * norm(y) * cos(vector_angle x y)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[vector_angle] THEN
+  ASM_CASES_TAC `x:real^N = vec 0` THEN
+  ASM_REWRITE_TAC[DOT_LZERO; NORM_0; REAL_MUL_LZERO] THEN
+  ASM_CASES_TAC `y:real^N = vec 0` THEN
+  ASM_REWRITE_TAC[DOT_RZERO; NORM_0; REAL_MUL_LZERO; REAL_MUL_RZERO] THEN
+  ONCE_REWRITE_TAC[AC REAL_MUL_AC `a * b * c:real = c * a * b`] THEN
+  ASM_SIMP_TAC[GSYM REAL_EQ_LDIV_EQ; REAL_LT_MUL; NORM_POS_LT] THEN
+  MATCH_MP_TAC(GSYM COS_ACS) THEN
+  ASM_REWRITE_TAC[REAL_BOUNDS_LE; NORM_CAUCHY_SCHWARZ_DIV]);;
+
+let VECTOR_ANGLE_RANGE = prove
+ (`!x y:real^N. &0 <= vector_angle x y /\ vector_angle x y <= pi`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[vector_angle] THEN COND_CASES_TAC THENL
+   [MP_TAC PI_POS THEN REAL_ARITH_TAC; ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[DE_MORGAN_THM]) THEN MATCH_MP_TAC ACS_BOUNDS THEN
+  ASM_REWRITE_TAC[REAL_BOUNDS_LE; NORM_CAUCHY_SCHWARZ_DIV]);;
+
+let ORTHOGONAL_VECTOR_ANGLE = prove
+ (`!x y:real^N. orthogonal x y <=> vector_angle x y = pi / &2`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[orthogonal; vector_angle] THEN
+  ASM_CASES_TAC `x:real^N = vec 0` THEN ASM_REWRITE_TAC[DOT_LZERO] THEN
+  ASM_CASES_TAC `y:real^N = vec 0` THEN ASM_REWRITE_TAC[DOT_RZERO] THEN
+  EQ_TAC THENL
+   [SIMP_TAC[real_div; REAL_MUL_LZERO] THEN DISCH_TAC THEN
+    REWRITE_TAC[GSYM real_div; GSYM COS_PI2] THEN
+    MATCH_MP_TAC ACS_COS THEN MP_TAC PI_POS THEN REAL_ARITH_TAC;
+    DISCH_THEN(MP_TAC o AP_TERM `cos`) THEN
+    SIMP_TAC[COS_ACS; REAL_BOUNDS_LE; NORM_CAUCHY_SCHWARZ_DIV; COS_PI2] THEN
+    ASM_SIMP_TAC[REAL_EQ_LDIV_EQ; REAL_LT_MUL; NORM_POS_LT; REAL_MUL_LZERO]]);;
+
+let VECTOR_ANGLE_EQ_0 = prove
+ (`!x y:real^N. vector_angle x y = &0 <=>
+                ~(x = vec 0) /\ ~(y = vec 0) /\ norm(x) % y = norm(y) % x`,
+  REPEAT GEN_TAC THEN
+  MAP_EVERY ASM_CASES_TAC [`x:real^N = vec 0`; `y:real^N = vec 0`] THEN
+  ASM_SIMP_TAC[vector_angle; PI_NZ; REAL_ARITH `x / &2 = &0 <=> x = &0`] THEN
+  REWRITE_TAC[GSYM NORM_CAUCHY_SCHWARZ_EQ] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM REAL_MUL_LID] THEN
+  ASM_SIMP_TAC[GSYM REAL_EQ_LDIV_EQ; NORM_POS_LT; REAL_LT_MUL] THEN
+  MESON_TAC[ACS_1; COS_ACS; REAL_BOUNDS_LE; NORM_CAUCHY_SCHWARZ_DIV; COS_0]);;
+
+let VECTOR_ANGLE_EQ_PI = prove
+ (`!x y:real^N. vector_angle x y = pi <=>
+                ~(x = vec 0) /\ ~(y = vec 0) /\
+                norm(x) % y + norm(y) % x = vec 0`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`x:real^N`; `--y:real^N`] VECTOR_ANGLE_EQ_0) THEN
+  SIMP_TAC[VECTOR_ANGLE_RNEG; REAL_ARITH `pi - x = &0 <=> x = pi`] THEN
+  STRIP_TAC THEN
+  REWRITE_TAC[NORM_NEG; VECTOR_ARITH `--x = vec 0 <=> x = vec 0`] THEN
+  AP_TERM_TAC THEN AP_TERM_TAC THEN VECTOR_ARITH_TAC);;
+
+let VECTOR_ANGLE_EQ_0_DIST = prove
+ (`!x y:real^N. vector_angle x y = &0 <=>
+                ~(x = vec 0) /\ ~(y = vec 0) /\ norm(x + y) = norm x + norm y`,
+  REWRITE_TAC[VECTOR_ANGLE_EQ_0; GSYM NORM_TRIANGLE_EQ]);;
+
+let VECTOR_ANGLE_EQ_PI_DIST = prove
+ (`!x y:real^N. vector_angle x y = pi <=>
+                ~(x = vec 0) /\ ~(y = vec 0) /\ norm(x - y) = norm x + norm y`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`x:real^N`; `--y:real^N`] VECTOR_ANGLE_EQ_0_DIST) THEN
+  SIMP_TAC[VECTOR_ANGLE_RNEG; REAL_ARITH `pi - x = &0 <=> x = pi`] THEN
+  STRIP_TAC THEN REWRITE_TAC[NORM_NEG] THEN NORM_ARITH_TAC);;
+
+let SIN_VECTOR_ANGLE_POS = prove
+ (`!v w. &0 <= sin(vector_angle v w)`,
+  SIMP_TAC[SIN_POS_PI_LE; VECTOR_ANGLE_RANGE]);;
+
+let SIN_VECTOR_ANGLE_EQ_0 = prove
+ (`!x y. sin(vector_angle x y) = &0 <=>
+           vector_angle x y = &0 \/ vector_angle x y = pi`,
+  MESON_TAC[SIN_POS_PI; VECTOR_ANGLE_RANGE; REAL_LT_LE; SIN_0; SIN_PI]);;
+
+let ASN_SIN_VECTOR_ANGLE = prove
+ (`!x y:real^N.
+        asn(sin(vector_angle x y)) =
+          if vector_angle x y <= pi / &2 then vector_angle x y
+          else pi - vector_angle x y`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `asn(sin(pi - vector_angle (x:real^N) y))` THEN CONJ_TAC THENL
+     [AP_TERM_TAC THEN REWRITE_TAC[SIN_SUB; SIN_PI; COS_PI] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC]] THEN
+  MATCH_MP_TAC ASN_SIN THEN
+  MP_TAC(ISPECL [`x:real^N`; `y:real^N`] VECTOR_ANGLE_RANGE) THEN
+  ASM_REAL_ARITH_TAC);;
+
+let SIN_VECTOR_ANGLE_EQ = prove
+ (`!x y w z.
+        sin(vector_angle x y) = sin(vector_angle w z) <=>
+            vector_angle x y = vector_angle w z \/
+            vector_angle x y = pi - vector_angle w z`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[SIN_SUB; SIN_PI; COS_PI] THENL
+   [ALL_TAC; REAL_ARITH_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o AP_TERM `asn`) THEN
+  REWRITE_TAC[ASN_SIN_VECTOR_ANGLE] THEN REAL_ARITH_TAC);;
+
+let CONTINUOUS_WITHIN_CX_VECTOR_ANGLE_COMPOSE = prove
+ (`!f:real^M->real^N g x s.
+     ~(f x = vec 0) /\ ~(g x = vec 0) /\
+     f continuous (at x within s) /\
+     g continuous (at x within s)
+     ==> (\x. Cx(vector_angle (f x) (g x))) continuous (at x within s)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `trivial_limit(at (x:real^M) within s)` THEN
+  ASM_SIMP_TAC[CONTINUOUS_TRIVIAL_LIMIT; vector_angle] THEN
+  SUBGOAL_THEN
+   `(cacs o (\x. Cx(((f x:real^N) dot g x) / (norm(f x) * norm(g x)))))
+    continuous (at (x:real^M) within s)`
+  MP_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_WITHIN_COMPOSE THEN CONJ_TAC THENL
+     [REWRITE_TAC[CX_DIV; CX_MUL] THEN REWRITE_TAC[WITHIN_UNIV] THEN
+      MATCH_MP_TAC CONTINUOUS_COMPLEX_DIV THEN
+      ASM_SIMP_TAC[NETLIMIT_WITHIN; COMPLEX_ENTIRE; CX_INJ; NORM_EQ_0] THEN
+      REWRITE_TAC[CONTINUOUS_CX_LIFT; GSYM CX_MUL; LIFT_CMUL] THEN
+      ASM_SIMP_TAC[CONTINUOUS_LIFT_DOT2] THEN
+      MATCH_MP_TAC CONTINUOUS_MUL THEN
+      ASM_SIMP_TAC[CONTINUOUS_LIFT_NORM_COMPOSE; o_DEF];
+      MATCH_MP_TAC CONTINUOUS_WITHIN_SUBSET THEN
+      EXISTS_TAC `{z | real z /\ abs(Re z) <= &1}` THEN
+      REWRITE_TAC[CONTINUOUS_WITHIN_CACS_REAL] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_UNIV; IN_ELIM_THM] THEN
+      REWRITE_TAC[REAL_CX; RE_CX; NORM_CAUCHY_SCHWARZ_DIV]];
+    ASM_SIMP_TAC[CONTINUOUS_WITHIN; CX_ACS; o_DEF;
+                 NORM_CAUCHY_SCHWARZ_DIV] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LIM_TRANSFORM_EVENTUALLY) THEN
+    SUBGOAL_THEN
+      `eventually (\y. ~((f:real^M->real^N) y = vec 0) /\
+                       ~((g:real^M->real^N) y = vec 0))
+                  (at x within s)`
+    MP_TAC THENL
+     [REWRITE_TAC[EVENTUALLY_AND] THEN CONJ_TAC THENL
+       [UNDISCH_TAC `(f:real^M->real^N) continuous (at x within s)`;
+        UNDISCH_TAC `(g:real^M->real^N) continuous (at x within s)`] THEN
+      REWRITE_TAC[CONTINUOUS_WITHIN; tendsto] THENL
+       [DISCH_THEN(MP_TAC o SPEC `norm((f:real^M->real^N) x)`);
+        DISCH_THEN(MP_TAC o SPEC `norm((g:real^M->real^N) x)`)] THEN
+      ASM_REWRITE_TAC[NORM_POS_LT] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+      REWRITE_TAC[] THEN CONV_TAC NORM_ARITH;
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+      SIMP_TAC[CX_ACS; NORM_CAUCHY_SCHWARZ_DIV]]]);;
+
+let CONTINUOUS_AT_CX_VECTOR_ANGLE = prove
+ (`!c x:real^N. ~(x = vec 0) ==> (Cx o vector_angle c) continuous (at x)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[o_DEF; vector_angle] THEN
+  ASM_CASES_TAC `c:real^N = vec 0` THEN ASM_REWRITE_TAC[CONTINUOUS_CONST] THEN
+  MATCH_MP_TAC CONTINUOUS_TRANSFORM_AT THEN
+  MAP_EVERY EXISTS_TAC [`\x:real^N. cacs(Cx((c dot x) / (norm c * norm x)))`;
+                        `norm(x:real^N)`] THEN
+  ASM_REWRITE_TAC[NORM_POS_LT] THEN CONJ_TAC THENL
+   [X_GEN_TAC `z:real^N` THEN DISCH_TAC THEN COND_CASES_TAC THENL
+     [ASM_MESON_TAC[NORM_ARITH `~(dist(vec 0,x) < norm x)`]; ALL_TAC] THEN
+    MATCH_MP_TAC(GSYM CX_ACS) THEN REWRITE_TAC[NORM_CAUCHY_SCHWARZ_DIV];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_WITHIN_COMPOSE) THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[CX_DIV; CX_MUL] THEN REWRITE_TAC[WITHIN_UNIV] THEN
+    MATCH_MP_TAC CONTINUOUS_COMPLEX_DIV THEN
+    ASM_REWRITE_TAC[NETLIMIT_AT; COMPLEX_ENTIRE; CX_INJ; NORM_EQ_0] THEN
+    SIMP_TAC[CONTINUOUS_COMPLEX_MUL; CONTINUOUS_CONST;
+             CONTINUOUS_AT_CX_NORM; CONTINUOUS_AT_CX_DOT];
+    MATCH_MP_TAC CONTINUOUS_WITHIN_SUBSET THEN
+    EXISTS_TAC `{z | real z /\ abs(Re z) <= &1}` THEN
+    REWRITE_TAC[CONTINUOUS_WITHIN_CACS_REAL] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_UNIV; IN_ELIM_THM] THEN
+    REWRITE_TAC[REAL_CX; RE_CX; NORM_CAUCHY_SCHWARZ_DIV]]);;
+
+let CONTINUOUS_WITHIN_CX_VECTOR_ANGLE = prove
+ (`!c x:real^N s.
+     ~(x = vec 0) ==> (Cx o vector_angle c) continuous (at x within s)`,
+  SIMP_TAC[CONTINUOUS_AT_WITHIN; CONTINUOUS_AT_CX_VECTOR_ANGLE]);;
+
+let REAL_CONTINUOUS_AT_VECTOR_ANGLE = prove
+ (`!c x:real^N. ~(x = vec 0) ==> (vector_angle c) real_continuous (at x)`,
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS; CONTINUOUS_AT_CX_VECTOR_ANGLE]);;
+
+let REAL_CONTINUOUS_WITHIN_VECTOR_ANGLE = prove
+ (`!c s x:real^N. ~(x = vec 0)
+                  ==> (vector_angle c) real_continuous (at x within s)`,
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS; CONTINUOUS_WITHIN_CX_VECTOR_ANGLE]);;
+
+let CONTINUOUS_ON_CX_VECTOR_ANGLE = prove
+ (`!s. ~(vec 0 IN s) ==> (Cx o vector_angle c) continuous_on s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  ASM_MESON_TAC[CONTINUOUS_WITHIN_CX_VECTOR_ANGLE]);;
+
+let VECTOR_ANGLE_EQ = prove
+ (`!u v x y. ~(u = vec 0) /\  ~(v = vec 0) /\ ~(x = vec 0) /\ ~(y = vec 0)
+             ==> (vector_angle u v = vector_angle x y <=>
+                        (x dot y) * norm(u) * norm(v) =
+                        (u dot v) * norm(x) * norm(y))`,
+  SIMP_TAC[vector_angle; NORM_EQ_0; REAL_FIELD
+   `~(u = &0) /\ ~(v = &0) /\ ~(x = &0) /\ ~(y = &0)
+    ==> (a * u * v = b * x * y <=> a / (x * y) = b / (u * v))`] THEN
+  REPEAT STRIP_TAC THEN EQ_TAC THEN SIMP_TAC[] THEN
+  DISCH_THEN(MP_TAC o AP_TERM `cos`) THEN
+  SIMP_TAC[COS_ACS; NORM_CAUCHY_SCHWARZ_DIV; REAL_BOUNDS_LE]);;
+
+let COS_VECTOR_ANGLE_EQ = prove
+ (`!u v x y.
+        cos(vector_angle u v) = cos(vector_angle x y) <=>
+        vector_angle u v = vector_angle x y`,
+  MESON_TAC[ACS_COS; VECTOR_ANGLE_RANGE]);;
+
+let COLLINEAR_VECTOR_ANGLE = prove
+ (`!x y. ~(x = vec 0) /\ ~(y = vec 0)
+         ==> (collinear {vec 0,x,y} <=>
+                vector_angle x y = &0 \/ vector_angle x y = pi)`,
+  REWRITE_TAC[GSYM NORM_CAUCHY_SCHWARZ_EQUAL; NORM_CAUCHY_SCHWARZ_ABS_EQ;
+              VECTOR_ANGLE_EQ_0; VECTOR_ANGLE_EQ_PI] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN BINOP_TAC THEN
+  VECTOR_ARITH_TAC);;
+
+let COLLINEAR_SIN_VECTOR_ANGLE = prove
+ (`!x y. ~(x = vec 0) /\ ~(y = vec 0)
+         ==> (collinear {vec 0,x,y} <=> sin(vector_angle x y) = &0)`,
+  REWRITE_TAC[SIN_VECTOR_ANGLE_EQ_0; COLLINEAR_VECTOR_ANGLE]);;
+
+let COLLINEAR_SIN_VECTOR_ANGLE_IMP = prove
+ (`!x y. sin(vector_angle x y) = &0
+         ==> ~(x = vec 0) /\ ~(y = vec 0) /\ collinear {vec 0,x,y}`,
+  MESON_TAC[COLLINEAR_SIN_VECTOR_ANGLE; SIN_VECTOR_ANGLE_EQ_0;
+            VECTOR_ANGLE_EQ_0_DIST; VECTOR_ANGLE_EQ_PI_DIST]);;
+
+let VECTOR_ANGLE_EQ_0_RIGHT = prove
+ (`!x y z:real^N. vector_angle x y = &0
+                  ==> (vector_angle x z = vector_angle y z)`,
+  REWRITE_TAC[VECTOR_ANGLE_EQ_0] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `vector_angle (norm(x:real^N) % y) (z:real^N)` THEN CONJ_TAC THENL
+   [ASM_REWRITE_TAC[] THEN
+    ASM_REWRITE_TAC[VECTOR_ANGLE_LMUL; NORM_EQ_0; NORM_POS_LE];
+    REWRITE_TAC[VECTOR_ANGLE_LMUL] THEN
+    ASM_REWRITE_TAC[NORM_EQ_0; NORM_POS_LE]]);;
+
+let VECTOR_ANGLE_EQ_0_LEFT = prove
+ (`!x y z:real^N. vector_angle x y = &0
+                  ==> (vector_angle z x = vector_angle z y)`,
+  MESON_TAC[VECTOR_ANGLE_EQ_0_RIGHT; VECTOR_ANGLE_SYM]);;
+
+let VECTOR_ANGLE_EQ_PI_RIGHT = prove
+ (`!x y z:real^N. vector_angle x y = pi
+                  ==> (vector_angle x z = pi - vector_angle y z)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`--x:real^N`; `y:real^N`; `z:real^N`]
+   VECTOR_ANGLE_EQ_0_RIGHT) THEN
+  ASM_REWRITE_TAC[VECTOR_ANGLE_LNEG] THEN REAL_ARITH_TAC);;
+
+let VECTOR_ANGLE_EQ_PI_LEFT = prove
+ (`!x y z:real^N. vector_angle x y = pi
+                  ==> (vector_angle z x = pi - vector_angle z y)`,
+  MESON_TAC[VECTOR_ANGLE_EQ_PI_RIGHT; VECTOR_ANGLE_SYM]);;
+
+let COS_VECTOR_ANGLE = prove
+ (`!x y:real^N.
+        cos(vector_angle x y) = if x = vec 0 \/ y = vec 0 then &0
+                                else (x dot y) / (norm x * norm y)`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `x:real^N = vec 0` THENL
+   [ASM_REWRITE_TAC[vector_angle; COS_PI2]; ALL_TAC] THEN
+  ASM_CASES_TAC `y:real^N = vec 0` THENL
+   [ASM_REWRITE_TAC[vector_angle; COS_PI2]; ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_EQ_RDIV_EQ; REAL_LT_MUL; NORM_POS_LT; VECTOR_ANGLE] THEN
+  REAL_ARITH_TAC);;
+
+let SIN_VECTOR_ANGLE = prove
+ (`!x y:real^N.
+        sin(vector_angle x y) =
+            if x = vec 0 \/ y = vec 0 then &1
+            else sqrt(&1 - ((x dot y) / (norm x * norm y)) pow 2)`,
+  SIMP_TAC[SIN_COS_SQRT; SIN_VECTOR_ANGLE_POS; COS_VECTOR_ANGLE] THEN
+  REPEAT GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[SQRT_1]);;
+
+let SIN_SQUARED_VECTOR_ANGLE = prove
+ (`!x y:real^N.
+        sin(vector_angle x y) pow 2 =
+            if x = vec 0 \/ y = vec 0 then &1
+            else &1 - ((x dot y) / (norm x * norm y)) pow 2`,
+  REPEAT GEN_TAC THEN REWRITE_TAC
+   [REWRITE_RULE [REAL_ARITH `s + c = &1 <=> s = &1 - c`] SIN_CIRCLE] THEN
+  REWRITE_TAC[COS_VECTOR_ANGLE] THEN REAL_ARITH_TAC);;
+
+let VECTOR_ANGLE_COMPLEX_LMUL = prove
+ (`!a. ~(a = Cx(&0))
+       ==> vector_angle (a * x) (a * y) = vector_angle x y`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `x = Cx(&0)` THENL
+   [ASM_REWRITE_TAC[COMPLEX_MUL_RZERO; vector_angle; COMPLEX_VEC_0];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `y = Cx(&0)` THENL
+   [ASM_REWRITE_TAC[COMPLEX_MUL_RZERO; vector_angle; COMPLEX_VEC_0];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`a * x:complex`; `a * y:complex`; `x:complex`; `y:complex`]
+        VECTOR_ANGLE_EQ) THEN
+  ASM_REWRITE_TAC[COMPLEX_VEC_0; COMPLEX_ENTIRE] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL] THEN MATCH_MP_TAC(REAL_RING
+   `a pow 2 * xy:real = d ==> xy * (a * x) * (a * y) = d * x * y`) THEN
+  REWRITE_TAC[NORM_POW_2] THEN
+  REWRITE_TAC[DOT_2; complex_mul; GSYM RE_DEF; GSYM IM_DEF; RE; IM] THEN
+  REAL_ARITH_TAC);;
+
+let VECTOR_ANGLE_1 = prove
+ (`!x. vector_angle x (Cx(&1)) = acs(Re x / norm x)`,
+  GEN_TAC THEN
+  SIMP_TAC[vector_angle; COMPLEX_VEC_0; CX_INJ; REAL_OF_NUM_EQ; ARITH_EQ] THEN
+  COND_CASES_TAC THENL
+   [ASM_REWRITE_TAC[real_div; RE_CX; ACS_0; REAL_MUL_LZERO]; ALL_TAC] THEN
+  REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_NUM; REAL_MUL_RID] THEN
+  REWRITE_TAC[DOT_2; GSYM RE_DEF; GSYM IM_DEF; RE_CX; IM_CX] THEN
+  AP_TERM_TAC THEN REAL_ARITH_TAC);;
+
+let ARG_EQ_VECTOR_ANGLE_1 = prove
+ (`!z. ~(z = Cx(&0)) /\ &0 <= Im z ==> Arg z = vector_angle z (Cx(&1))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[VECTOR_ANGLE_1] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV o LAND_CONV o RAND_CONV) [ARG] THEN
+  REWRITE_TAC[RE_MUL_CX; RE_CEXP; RE_II; IM_MUL_II; IM_CX; RE_CX] THEN
+  REWRITE_TAC[REAL_MUL_LZERO; REAL_EXP_0; REAL_MUL_LID] THEN
+  ASM_SIMP_TAC[COMPLEX_NORM_ZERO; REAL_FIELD
+   `~(z = &0) ==> (z * x) / z = x`] THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC ACS_COS THEN
+  ASM_REWRITE_TAC[ARG; ARG_LE_PI]);;
+
+let VECTOR_ANGLE_ARG = prove
+ (`!w z. ~(w = Cx(&0)) /\ ~(z = Cx(&0))
+         ==> vector_angle w z = if &0 <= Im(z / w) then Arg(z / w)
+                                else &2 * pi - Arg(z / w)`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THENL
+   [SUBGOAL_THEN `z = w * (z / w) /\ w = w * Cx(&1)` MP_TAC THENL
+     [REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC COMPLEX_FIELD; ALL_TAC];
+    SUBGOAL_THEN `w = z * (w / z) /\ z = z * Cx(&1)` MP_TAC THENL
+     [REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC COMPLEX_FIELD; ALL_TAC]] THEN
+  DISCH_THEN(fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [th]) THEN
+  ASM_SIMP_TAC[VECTOR_ANGLE_COMPLEX_LMUL] THENL
+   [ONCE_REWRITE_TAC[VECTOR_ANGLE_SYM] THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC ARG_EQ_VECTOR_ANGLE_1 THEN ASM_REWRITE_TAC[] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC COMPLEX_FIELD;
+    MP_TAC(ISPEC `z / w:complex` ARG_INV) THEN ANTS_TAC THENL
+     [ASM_MESON_TAC[real; REAL_LE_REFL]; DISCH_THEN(SUBST1_TAC o SYM)] THEN
+    REWRITE_TAC[COMPLEX_INV_DIV] THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC ARG_EQ_VECTOR_ANGLE_1 THEN CONJ_TAC THENL
+     [REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC COMPLEX_FIELD;
+      ONCE_REWRITE_TAC[GSYM COMPLEX_INV_DIV] THEN
+      REWRITE_TAC[IM_COMPLEX_INV_GE_0] THEN ASM_REAL_ARITH_TAC]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Traditional geometric notion of angle (always 0 <= theta <= pi).          *)
+(* ------------------------------------------------------------------------- *)
+
+let angle = new_definition
+ `angle(a,b,c) = vector_angle (a - b) (c - b)`;;
+
+let ANGLE_LINEAR_IMAGE_EQ = prove
+ (`!f a b c.
+        linear f /\ (!x. norm(f x) = norm x)
+        ==> angle(f a,f b,f c) = angle(a,b,c)`,
+  SIMP_TAC[angle; GSYM LINEAR_SUB; VECTOR_ANGLE_LINEAR_IMAGE_EQ]);;
+
+add_linear_invariants [ANGLE_LINEAR_IMAGE_EQ];;
+
+let ANGLE_TRANSLATION_EQ = prove
+ (`!a b c d. angle(a + b,a + c,a + d) = angle(b,c,d)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[angle] THEN
+  BINOP_TAC THEN VECTOR_ARITH_TAC);;
+
+add_translation_invariants [ANGLE_TRANSLATION_EQ];;
+
+let VECTOR_ANGLE_ANGLE = prove
+ (`vector_angle x y = angle(x,vec 0,y)`,
+  REWRITE_TAC[angle; VECTOR_SUB_RZERO]);;
+
+let ANGLE_EQ_PI_DIST = prove
+ (`!A B C:real^N.
+        angle(A,B,C) = pi <=>
+        ~(A = B) /\ ~(C = B) /\ dist(A,C) = dist(A,B) + dist(B,C)`,
+  REWRITE_TAC[angle; VECTOR_ANGLE_EQ_PI_DIST] THEN NORM_ARITH_TAC);;
+
+let SIN_ANGLE_POS = prove
+ (`!A B C. &0 <= sin(angle(A,B,C))`,
+  REWRITE_TAC[angle; SIN_VECTOR_ANGLE_POS]);;
+
+let ANGLE = prove
+ (`!A B C. (A - C) dot (B - C) = dist(A,C) * dist(B,C) * cos(angle(A,C,B))`,
+  REWRITE_TAC[angle; dist; GSYM VECTOR_ANGLE]);;
+
+let ANGLE_REFL = prove
+ (`!A B. angle(A,A,B) = pi / &2 /\ angle(B,A,A) = pi / &2`,
+  REWRITE_TAC[angle; vector_angle; VECTOR_SUB_REFL]);;
+
+let ANGLE_REFL_MID = prove
+ (`!A B. ~(A = B) ==> angle(A,B,A) = &0`,
+  SIMP_TAC[angle; vector_angle; VECTOR_SUB_EQ; GSYM NORM_POW_2; ARITH;
+    GSYM REAL_POW_2; REAL_DIV_REFL; ACS_1; REAL_POW_EQ_0; NORM_EQ_0]);;
+
+let ANGLE_SYM = prove
+ (`!A B C. angle(A,B,C) = angle(C,B,A)`,
+  REWRITE_TAC[angle; vector_angle; VECTOR_SUB_EQ; DISJ_SYM;
+              REAL_MUL_SYM; DOT_SYM]);;
+
+let ANGLE_RANGE = prove
+ (`!A B C. &0 <= angle(A,B,C) /\ angle(A,B,C) <= pi`,
+  REWRITE_TAC[angle; VECTOR_ANGLE_RANGE]);;
+
+let COS_ANGLE_EQ = prove
+ (`!a b c a' b' c'.
+        cos(angle(a,b,c)) = cos(angle(a',b',c')) <=>
+        angle(a,b,c) = angle(a',b',c')`,
+  REWRITE_TAC[angle; COS_VECTOR_ANGLE_EQ]);;
+
+let ANGLE_EQ = prove
+ (`!a b c a' b' c'.
+        ~(a = b) /\ ~(c = b) /\ ~(a' = b') /\ ~(c' = b')
+        ==> (angle(a,b,c) = angle(a',b',c') <=>
+                ((a' - b') dot (c' - b')) * norm (a - b) * norm (c - b) =
+                ((a - b) dot (c - b)) * norm (a' - b') * norm (c' - b'))`,
+  SIMP_TAC[angle; VECTOR_ANGLE_EQ; VECTOR_SUB_EQ]);;
+
+let SIN_ANGLE_EQ_0 = prove
+ (`!A B C. sin(angle(A,B,C)) = &0 <=> angle(A,B,C) = &0 \/ angle(A,B,C) = pi`,
+  REWRITE_TAC[angle; SIN_VECTOR_ANGLE_EQ_0]);;
+
+let SIN_ANGLE_EQ = prove
+ (`!A B C A' B' C'. sin(angle(A,B,C)) = sin(angle(A',B',C')) <=>
+                        angle(A,B,C) = angle(A',B',C') \/
+                        angle(A,B,C) = pi - angle(A',B',C')`,
+  REWRITE_TAC[angle; SIN_VECTOR_ANGLE_EQ]);;
+
+let COLLINEAR_ANGLE = prove
+ (`!A B C. ~(A = B) /\ ~(B = C)
+           ==> (collinear {A,B,C} <=> angle(A,B,C) = &0 \/ angle(A,B,C) = pi)`,
+  ONCE_REWRITE_TAC[COLLINEAR_3] THEN
+  SIMP_TAC[COLLINEAR_VECTOR_ANGLE; VECTOR_SUB_EQ; angle]);;
+
+let COLLINEAR_SIN_ANGLE = prove
+ (`!A B C. ~(A = B) /\ ~(B = C)
+           ==> (collinear {A,B,C} <=> sin(angle(A,B,C)) = &0)`,
+  REWRITE_TAC[SIN_ANGLE_EQ_0; COLLINEAR_ANGLE]);;
+
+let COLLINEAR_SIN_ANGLE_IMP = prove
+ (`!A B C. sin(angle(A,B,C)) = &0
+           ==> ~(A = B) /\ ~(B = C) /\ collinear {A,B,C}`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[COLLINEAR_3] THEN REWRITE_TAC[angle] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP COLLINEAR_SIN_VECTOR_ANGLE_IMP) THEN
+  SIMP_TAC[VECTOR_SUB_EQ]);;
+
+let ANGLE_EQ_0_RIGHT = prove
+ (`!A B C. angle(A,B,C) = &0 ==> angle(A,B,D) = angle(C,B,D)`,
+  REWRITE_TAC[VECTOR_ANGLE_EQ_0_RIGHT; angle]);;
+
+let ANGLE_EQ_0_LEFT = prove
+ (`!A B C. angle(A,B,C) = &0 ==> angle(D,B,A) = angle(D,B,C)`,
+  MESON_TAC[ANGLE_EQ_0_RIGHT; ANGLE_SYM]);;
+
+let ANGLE_EQ_PI_RIGHT = prove
+ (`!A B C. angle(A,B,C) = pi ==> angle(A,B,D) = pi - angle(C,B,D)`,
+  REWRITE_TAC[VECTOR_ANGLE_EQ_PI_RIGHT; angle]);;
+
+let ANGLE_EQ_PI_LEFT = prove
+ (`!A B C. angle(A,B,C) = pi ==> angle(A,B,D) = pi - angle(C,B,D)`,
+  MESON_TAC[ANGLE_EQ_PI_RIGHT; ANGLE_SYM]);;
+
+let COS_ANGLE = prove
+ (`!a b c. cos(angle(a,b,c)) = if a = b \/ c = b then &0
+                               else ((a - b) dot (c - b)) /
+                                    (norm(a - b) * norm(c - b))`,
+  REWRITE_TAC[angle; COS_VECTOR_ANGLE; VECTOR_SUB_EQ]);;
+
+let SIN_ANGLE = prove
+ (`!a b c. sin(angle(a,b,c)) =
+             if a = b \/ c = b then &1
+             else sqrt(&1 - (((a - b) dot (c - b)) /
+                             (norm(a - b) * norm(c - b))) pow 2)`,
+  REWRITE_TAC[angle; SIN_VECTOR_ANGLE; VECTOR_SUB_EQ]);;
+
+let SIN_SQUARED_ANGLE = prove
+ (`!a b c. sin(angle(a,b,c)) pow 2 =
+             if a = b \/ c = b then &1
+             else &1 - (((a - b) dot (c - b)) /
+                        (norm(a - b) * norm(c - b))) pow 2`,
+  REWRITE_TAC[angle; SIN_SQUARED_VECTOR_ANGLE; VECTOR_SUB_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The law of cosines.                                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let LAW_OF_COSINES = prove
+ (`!A B C:real^N.
+        dist(B,C) pow 2 = (dist(A,B) pow 2 + dist(A,C) pow 2) -
+                          &2 * dist(A,B) * dist(A,C) * cos(angle(B,A,C))`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[angle; ONCE_REWRITE_RULE[NORM_SUB] dist; GSYM VECTOR_ANGLE;
+              NORM_POW_2] THEN
+  VECTOR_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* The law of sines.                                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let LAW_OF_SINES = prove
+ (`!A B C:real^N.
+      sin(angle(A,B,C)) * dist(B,C) = sin(angle(B,A,C)) * dist(A,C)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC REAL_POW_EQ THEN EXISTS_TAC `2` THEN
+  SIMP_TAC[SIN_ANGLE_POS; DIST_POS_LE; REAL_LE_MUL; ARITH] THEN
+  REWRITE_TAC[REAL_POW_MUL; MATCH_MP
+   (REAL_ARITH `x + y = &1 ==> x = &1 - y`) (SPEC_ALL SIN_CIRCLE)] THEN
+  ASM_CASES_TAC `A:real^N = B` THEN ASM_REWRITE_TAC[ANGLE_REFL; COS_PI2] THEN
+  RULE_ASSUM_TAC(ONCE_REWRITE_RULE[GSYM VECTOR_SUB_EQ]) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM NORM_EQ_0]) THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_RING
+   `~(a = &0) ==> a pow 2 * x = a pow 2 * y ==> x = y`)) THEN
+  ONCE_REWRITE_TAC[DIST_SYM] THEN REWRITE_TAC[GSYM dist] THEN
+  GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o ONCE_DEPTH_CONV) [DIST_SYM] THEN
+  REWRITE_TAC[REAL_RING
+   `a * (&1 - x) * b = c * (&1 - y) * d <=>
+    a * b - a * b * x = c * d - c * d * y`] THEN
+  REWRITE_TAC[GSYM REAL_POW_MUL; GSYM ANGLE] THEN
+  REWRITE_TAC[REAL_POW_MUL; dist; NORM_POW_2] THEN
+  REWRITE_TAC[DOT_LSUB; DOT_RSUB; DOT_SYM] THEN CONV_TAC REAL_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* The sum of the angles of a triangle.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let TRIANGLE_ANGLE_SUM_LEMMA = prove
+ (`!A B C:real^N. ~(A = B) /\ ~(A = C) /\ ~(B = C)
+                  ==> cos(angle(B,A,C) + angle(A,B,C) + angle(B,C,A)) = -- &1`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+  REWRITE_TAC[GSYM NORM_EQ_0] THEN
+  MP_TAC(ISPECL [`A:real^N`; `B:real^N`; `C:real^N`] LAW_OF_COSINES) THEN
+  MP_TAC(ISPECL [`B:real^N`; `A:real^N`; `C:real^N`] LAW_OF_COSINES) THEN
+  MP_TAC(ISPECL [`C:real^N`; `B:real^N`; `A:real^N`] LAW_OF_COSINES) THEN
+  MP_TAC(ISPECL [`A:real^N`; `B:real^N`; `C:real^N`] LAW_OF_SINES) THEN
+  MP_TAC(ISPECL [`B:real^N`; `A:real^N`; `C:real^N`] LAW_OF_SINES) THEN
+  MP_TAC(ISPECL [`B:real^N`; `C:real^N`; `A:real^N`] LAW_OF_SINES) THEN
+  REWRITE_TAC[COS_ADD; SIN_ADD; dist; NORM_SUB] THEN
+  MAP_EVERY (fun t -> MP_TAC(SPEC t SIN_CIRCLE))
+   [`angle(B:real^N,A,C)`; `angle(A:real^N,B,C)`; `angle(B:real^N,C,A)`] THEN
+  REWRITE_TAC[COS_ADD; SIN_ADD; ANGLE_SYM] THEN CONV_TAC REAL_RING);;
+
+let COS_MINUS1_LEMMA = prove
+ (`!x. cos(x) = -- &1 /\ &0 <= x /\ x < &3 * pi ==> x = pi`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?n. integer n /\ x = n * pi`
+   (X_CHOOSE_THEN `nn:real` (CONJUNCTS_THEN2 ASSUME_TAC SUBST_ALL_TAC)) THEN
+  REWRITE_TAC[GSYM SIN_EQ_0] THENL
+   [MP_TAC(SPEC `x:real` SIN_CIRCLE) THEN ASM_REWRITE_TAC[] THEN
+    CONV_TAC REAL_RING;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `?n. nn = &n` (X_CHOOSE_THEN `n:num` SUBST_ALL_TAC) THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REAL_MUL_POS_LE]) THEN
+    SIMP_TAC[PI_POS; REAL_ARITH `&0 < p ==> ~(p < &0) /\ ~(p = &0)`] THEN
+    ASM_MESON_TAC[INTEGER_POS; REAL_LT_LE];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_RING `n = &1 ==> n * p = p`) THEN
+  REWRITE_TAC[REAL_OF_NUM_EQ] THEN
+  MATCH_MP_TAC(ARITH_RULE `n < 3 /\ ~(n = 0) /\ ~(n = 2) ==> n = 1`) THEN
+  RULE_ASSUM_TAC(SIMP_RULE[REAL_LT_RMUL_EQ; PI_POS; REAL_OF_NUM_LT]) THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THEN DISCH_THEN SUBST_ALL_TAC THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN SIMP_TAC[COS_0; REAL_MUL_LZERO; COS_NPI] THEN
+  REAL_ARITH_TAC);;
+
+let TRIANGLE_ANGLE_SUM = prove
+ (`!A B C:real^N. ~(A = B /\ B = C /\ A = C)
+                  ==> angle(B,A,C) + angle(A,B,C) + angle(B,C,A) = pi`,
+  REPEAT GEN_TAC THEN MAP_EVERY ASM_CASES_TAC
+   [`A:real^N = B`; `B:real^N = C`; `A:real^N = C`] THEN
+  ASM_SIMP_TAC[ANGLE_REFL_MID; ANGLE_REFL; REAL_HALF; REAL_ADD_RID] THEN
+  REPEAT(FIRST_X_ASSUM SUBST_ALL_TAC) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN REWRITE_TAC[REAL_ADD_LID; REAL_HALF] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC COS_MINUS1_LEMMA THEN
+  ASM_SIMP_TAC[TRIANGLE_ANGLE_SUM_LEMMA; REAL_LE_ADD; ANGLE_RANGE] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `&0 <= x /\ x <= p /\ &0 <= y /\ y <= p /\ &0 <= z /\ z <= p /\
+    ~(x = p /\ y = p /\ z = p)
+    ==> x + y + z < &3 * p`) THEN
+  ASM_SIMP_TAC[ANGLE_RANGE] THEN REPEAT STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ANGLE_EQ_PI_DIST])) THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV
+   [GSYM VECTOR_SUB_EQ])) THEN
+  REWRITE_TAC[GSYM NORM_EQ_0; dist; NORM_SUB] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* A few more lemmas about angles.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let ANGLE_EQ_PI_OTHERS = prove
+ (`!A B C:real^N.
+        angle(A,B,C) = pi
+        ==> angle(B,C,A) = &0 /\ angle(A,C,B) = &0 /\
+            angle(B,A,C) = &0 /\ angle(C,A,B) = &0`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [ANGLE_EQ_PI_DIST]) THEN
+  MP_TAC(ISPECL [`A:real^N`; `B:real^N`; `C:real^N`] TRIANGLE_ANGLE_SUM) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+   `x + p + y = p ==> &0 <= x /\ &0 <= y ==> x = &0 /\ y = &0`)) THEN
+  SIMP_TAC[ANGLE_RANGE; ANGLE_SYM]);;
+
+let ANGLE_EQ_0_DIST = prove
+ (`!A B C:real^N. angle(A,B,C) = &0 <=>
+                  ~(A = B) /\ ~(C = B) /\
+                  (dist(A,B) = dist(A,C) + dist(C,B) \/
+                   dist(B,C) = dist(A,C) + dist(A,B))`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `A:real^N = B` THENL
+   [ASM_REWRITE_TAC[angle; VECTOR_ANGLE_EQ_0; VECTOR_SUB_EQ]; ALL_TAC] THEN
+  ASM_CASES_TAC `B:real^N = C` THENL
+   [ASM_REWRITE_TAC[angle; VECTOR_ANGLE_EQ_0; VECTOR_SUB_EQ]; ALL_TAC] THEN
+  ASM_CASES_TAC `A:real^N = C` THENL
+   [ASM_SIMP_TAC[ANGLE_REFL_MID; DIST_REFL; REAL_ADD_LID]; ALL_TAC] THEN
+  EQ_TAC THENL
+   [ALL_TAC;
+    STRIP_TAC THENL
+     [MP_TAC(ISPECL[`A:real^N`; `C:real^N`; `B:real^N`] ANGLE_EQ_PI_DIST);
+      MP_TAC(ISPECL[`B:real^N`; `A:real^N`; `C:real^N`] ANGLE_EQ_PI_DIST)] THEN
+    ASM_REWRITE_TAC[] THEN REWRITE_TAC[DIST_SYM; REAL_ADD_AC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP ANGLE_EQ_PI_OTHERS) THEN SIMP_TAC[]] THEN
+  ASM_REWRITE_TAC[angle; VECTOR_ANGLE_EQ_0; VECTOR_SUB_EQ] THEN
+  REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
+    (ISPECL [`norm(A - B:real^N)`; `norm(C - B:real^N)`]
+                REAL_LT_TOTAL)
+  THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LCANCEL; NORM_EQ_0; VECTOR_SUB_EQ;
+                    VECTOR_ARITH `c - b:real^N = a - b <=> a = c`];
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+     `norm(A - B) % (C - B) = norm(C - B) % (A - B) <=>
+      (norm(C - B) - norm(A - B)) % (A - B) = norm(A - B) % (C - A)`];
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+     `norm(A - B) % (C - B) = norm(C - B) % (A - B) <=>
+      (norm(A - B) - norm(C - B)) % (C - B) = norm(C - B) % (A - C)`]] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] NORM_CROSS_MULTIPLY)) THEN
+  ASM_SIMP_TAC[REAL_SUB_LT; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+  SIMP_TAC[GSYM DIST_TRIANGLE_EQ] THEN SIMP_TAC[DIST_SYM]);;
+
+let ANGLE_EQ_0_DIST_ABS = prove
+ (`!A B C:real^N. angle(A,B,C) = &0 <=>
+                  ~(A = B) /\ ~(C = B) /\
+                   dist(A,C) = abs(dist(A,B) - dist(C,B))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[ANGLE_EQ_0_DIST] THEN
+  AP_TERM_TAC THEN AP_TERM_TAC THEN
+  MP_TAC(ISPECL [`A:real^N`; `C:real^N`] DIST_POS_LE) THEN
+  REWRITE_TAC[DIST_SYM] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some rules for congruent triangles (not necessarily in the same real^N).  *)
+(* ------------------------------------------------------------------------- *)
+
+let CONGRUENT_TRIANGLES_SSS = prove
+ (`!A B C:real^M A' B' C':real^N.
+        dist(A,B) = dist(A',B') /\
+        dist(B,C) = dist(B',C') /\
+        dist(C,A) = dist(C',A')
+        ==> angle(A,B,C) = angle(A',B',C')`,
+  REPEAT GEN_TAC THEN MAP_EVERY ASM_CASES_TAC
+   [`dist(A':real^N,B') = &0`; `dist(B':real^N,C') = &0`] THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[DIST_EQ_0]) THEN
+  ASM_SIMP_TAC[ANGLE_REFL_MID; ANGLE_REFL] THEN
+  ONCE_REWRITE_TAC[GSYM COS_ANGLE_EQ] THEN
+  MP_TAC(ISPECL [`B:real^M`; `A:real^M`; `C:real^M`] LAW_OF_COSINES) THEN
+  MP_TAC(ISPECL [`B':real^N`; `A':real^N`; `C':real^N`] LAW_OF_COSINES) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN REWRITE_TAC[GSYM DIST_EQ_0; DIST_SYM] THEN
+  CONV_TAC REAL_FIELD);;
+
+let CONGRUENT_TRIANGLES_SAS = prove
+ (`!A B C:real^M A' B' C':real^N.
+        dist(A,B) = dist(A',B') /\
+        angle(A,B,C) = angle(A',B',C') /\
+        dist(B,C) = dist(B',C')
+        ==> dist(A,C) = dist(A',C')`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[DIST_EQ] THEN
+  MP_TAC(ISPECL [`B:real^M`; `A:real^M`; `C:real^M`] LAW_OF_COSINES) THEN
+  MP_TAC(ISPECL [`B':real^N`; `A':real^N`; `C':real^N`] LAW_OF_COSINES) THEN
+  REPEAT(DISCH_THEN SUBST1_TAC) THEN
+  REPEAT BINOP_TAC THEN ASM_MESON_TAC[DIST_SYM]);;
+
+let CONGRUENT_TRIANGLES_AAS = prove
+ (`!A B C:real^M A' B' C':real^N.
+        angle(A,B,C) = angle(A',B',C') /\
+        angle(B,C,A) = angle(B',C',A') /\
+        dist(A,B) = dist(A',B') /\
+        ~(collinear {A,B,C})
+        ==> dist(A,C) = dist(A',C') /\ dist(B,C) = dist(B',C')`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `A:real^M = B` THENL
+   [FIRST_X_ASSUM SUBST_ALL_TAC THEN REWRITE_TAC[INSERT_AC; COLLINEAR_2];
+    ALL_TAC] THEN
+  DISCH_TAC THEN SUBGOAL_THEN `~(A':real^N = B')` ASSUME_TAC THENL
+   [ASM_MESON_TAC[DIST_EQ_0]; ALL_TAC] THEN
+  SUBGOAL_THEN `angle(C:real^M,A,B) = angle(C':real^N,A',B')` ASSUME_TAC THENL
+   [MP_TAC(ISPECL [`A:real^M`; `B:real^M`; `C:real^M`] TRIANGLE_ANGLE_SUM) THEN
+    MP_TAC(ISPECL [`A':real^N`; `B':real^N`; `C':real^N`]
+      TRIANGLE_ANGLE_SUM) THEN ASM_REWRITE_TAC[IMP_IMP] THEN
+    REWRITE_TAC[ANGLE_SYM] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MP_TAC(ISPECL [`C:real^M`; `B:real^M`; `A:real^M`] LAW_OF_SINES) THEN
+    MP_TAC(ISPECL [`C':real^N`; `B':real^N`; `A':real^N`] LAW_OF_SINES) THEN
+    SUBGOAL_THEN `~(sin(angle(B':real^N,C',A')) = &0)` MP_TAC THENL
+     [ASM_MESON_TAC[COLLINEAR_SIN_ANGLE_IMP; INSERT_AC];
+      ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[ANGLE_SYM; DIST_SYM] THEN
+      ASM_REWRITE_TAC[] THEN REWRITE_TAC[ANGLE_SYM; DIST_SYM] THEN
+      CONV_TAC REAL_FIELD];
+    ASM_MESON_TAC[CONGRUENT_TRIANGLES_SAS; DIST_SYM; ANGLE_SYM]]);;
+
+let CONGRUENT_TRIANGLES_ASA = prove
+ (`!A B C:real^M A' B' C':real^N.
+        angle(A,B,C) = angle(A',B',C') /\
+        dist(A,B) = dist(A',B') /\
+        angle(B,A,C) = angle(B',A',C') /\
+        ~(collinear {A,B,C})
+        ==> dist(A,C) = dist(A',C')`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `A:real^M = B` THENL
+   [FIRST_X_ASSUM SUBST_ALL_TAC THEN REWRITE_TAC[INSERT_AC; COLLINEAR_2];
+    ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN `~(A':real^N = B')` ASSUME_TAC THENL
+   [ASM_MESON_TAC[DIST_EQ_0]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`A:real^M`; `B:real^M`; `C:real^M`] TRIANGLE_ANGLE_SUM) THEN
+  MP_TAC(ISPECL [`A':real^N`; `B':real^N`; `C':real^N`]
+    TRIANGLE_ANGLE_SUM) THEN
+  ASM_REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+    `a + b + x = pi /\ a + b + y = pi ==> x = y`)) THEN
+  ASM_MESON_TAC[CONGRUENT_TRIANGLES_AAS; DIST_SYM; ANGLE_SYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Full versions where we deduce everything from the conditions.             *)
+(* ------------------------------------------------------------------------- *)
+
+let CONGRUENT_TRIANGLES_SSS_FULL = prove
+ (`!A B C:real^M A' B' C':real^N.
+        dist(A,B) = dist(A',B') /\
+        dist(B,C) = dist(B',C') /\
+        dist(C,A) = dist(C',A')
+        ==> dist(A,B) = dist(A',B') /\
+            dist(B,C) = dist(B',C') /\
+            dist(C,A) = dist(C',A') /\
+            angle(A,B,C) = angle(A',B',C') /\
+            angle(B,C,A) = angle(B',C',A') /\
+            angle(C,A,B) = angle(C',A',B')`,
+  MESON_TAC[CONGRUENT_TRIANGLES_SSS; DIST_SYM; ANGLE_SYM]);;
+
+let CONGRUENT_TRIANGLES_SAS_FULL = prove
+ (`!A B C:real^M A' B' C':real^N.
+        dist(A,B) = dist(A',B') /\
+        angle(A,B,C) = angle(A',B',C') /\
+        dist(B,C) = dist(B',C')
+        ==> dist(A,B) = dist(A',B') /\
+            dist(B,C) = dist(B',C') /\
+            dist(C,A) = dist(C',A') /\
+            angle(A,B,C) = angle(A',B',C') /\
+            angle(B,C,A) = angle(B',C',A') /\
+            angle(C,A,B) = angle(C',A',B')`,
+  MESON_TAC[CONGRUENT_TRIANGLES_SSS; DIST_SYM; ANGLE_SYM;
+            CONGRUENT_TRIANGLES_SAS]);;
+
+let CONGRUENT_TRIANGLES_AAS_FULL = prove
+ (`!A B C:real^M A' B' C':real^N.
+        angle(A,B,C) = angle(A',B',C') /\
+        angle(B,C,A) = angle(B',C',A') /\
+        dist(A,B) = dist(A',B') /\
+        ~(collinear {A,B,C})
+        ==> dist(A,B) = dist(A',B') /\
+            dist(B,C) = dist(B',C') /\
+            dist(C,A) = dist(C',A') /\
+            angle(A,B,C) = angle(A',B',C') /\
+            angle(B,C,A) = angle(B',C',A') /\
+            angle(C,A,B) = angle(C',A',B')`,
+  MESON_TAC[CONGRUENT_TRIANGLES_SSS; DIST_SYM; ANGLE_SYM;
+            CONGRUENT_TRIANGLES_AAS]);;
+
+let CONGRUENT_TRIANGLES_ASA_FULL = prove
+ (`!A B C:real^M A' B' C':real^N.
+        angle(A,B,C) = angle(A',B',C') /\
+        dist(A,B) = dist(A',B') /\
+        angle(B,A,C) = angle(B',A',C') /\
+        ~(collinear {A,B,C})
+        ==> dist(A,B) = dist(A',B') /\
+            dist(B,C) = dist(B',C') /\
+            dist(C,A) = dist(C',A') /\
+            angle(A,B,C) = angle(A',B',C') /\
+            angle(B,C,A) = angle(B',C',A') /\
+            angle(C,A,B) = angle(C',A',B')`,
+  MESON_TAC[CONGRUENT_TRIANGLES_ASA; CONGRUENT_TRIANGLES_SAS_FULL;
+            DIST_SYM; ANGLE_SYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Between-ness.                                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let ANGLE_BETWEEN = prove
+ (`!a b x. angle(a,x,b) = pi <=> ~(x = a) /\ ~(x = b) /\ between x (a,b)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[between; ANGLE_EQ_PI_DIST] THEN
+  REWRITE_TAC[EQ_SYM_EQ]);;
+
+let BETWEEN_ANGLE = prove
+ (`!a b x. between x (a,b) <=> x = a \/ x = b \/ angle(a,x,b) = pi`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[ANGLE_BETWEEN] THEN
+  MESON_TAC[BETWEEN_REFL]);;
+
+let ANGLES_ALONG_LINE = prove
+ (`!A B C D:real^N.
+      ~(C = A) /\ ~(C = B) /\ between C (A,B)
+      ==> angle(A,C,D) + angle(B,C,D) = pi`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM ANGLE_BETWEEN] THEN
+  DISCH_THEN(SUBST1_TAC o MATCH_MP ANGLE_EQ_PI_LEFT) THEN REAL_ARITH_TAC);;
+
+let ANGLES_ADD_BETWEEN = prove
+ (`!A B C D:real^N.
+        between C (A,B) /\ ~(D = A) /\ ~(D = B)
+        ==> angle(A,D,C) + angle(C,D,B) = angle(A,D,B)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `A:real^N = B` THENL
+   [ASM_SIMP_TAC[BETWEEN_REFL_EQ] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    ASM_SIMP_TAC[ANGLE_REFL_MID; REAL_ADD_LID];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `C:real^N = A` THEN
+  ASM_SIMP_TAC[ANGLE_REFL_MID; REAL_ADD_LID] THEN
+  ASM_CASES_TAC `C:real^N = B` THEN
+  ASM_SIMP_TAC[ANGLE_REFL_MID; REAL_ADD_RID] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`A:real^N`; `B:real^N`; `C:real^N`; `D:real^N`]
+        ANGLES_ALONG_LINE) THEN
+  MP_TAC(ISPECL [`A:real^N`; `B:real^N`; `D:real^N`] TRIANGLE_ANGLE_SUM) THEN
+  MP_TAC(ISPECL [`A:real^N`; `C:real^N`; `D:real^N`] TRIANGLE_ANGLE_SUM) THEN
+  MP_TAC(ISPECL [`B:real^N`; `C:real^N`; `D:real^N`] TRIANGLE_ANGLE_SUM) THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `angle(C:real^N,A,D) = angle(B,A,D) /\
+                angle(A,B,D) = angle(C,B,D)`
+   (CONJUNCTS_THEN SUBST1_TAC)
+  THENL [ALL_TAC; REWRITE_TAC[ANGLE_SYM] THEN REAL_ARITH_TAC] THEN
+  CONJ_TAC THEN MATCH_MP_TAC ANGLE_EQ_0_RIGHT THEN
+  ASM_MESON_TAC[ANGLE_EQ_PI_OTHERS; BETWEEN_ANGLE]);;
diff --git a/Multivariate/integration.ml b/Multivariate/integration.ml
new file mode 100644 (file)
index 0000000..a8e2d5f
--- /dev/null
@@ -0,0 +1,16782 @@
+(* ========================================================================= *)
+(* Kurzweil-Henstock gauge integration in many dimensions.                   *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(* ========================================================================= *)
+
+needs "Library/products.ml";;
+needs "Library/floor.ml";;
+needs "Multivariate/derivatives.ml";;
+prioritize_real();;
+
+(* ------------------------------------------------------------------------- *)
+(* Some useful lemmas about intervals.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let INTERIOR_SUBSET_UNION_INTERVALS = prove
+ (`!s i j. (?a b:real^N. i = interval[a,b]) /\ (?c d. j = interval[c,d]) /\
+           ~(interior j = {}) /\
+           i SUBSET j UNION s /\
+           interior(i) INTER interior(j) = {}
+           ==> interior i SUBSET interior s`,
+  REPEAT STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(SUBST_ALL_TAC o check (is_var o lhs o concl))) THEN
+  MATCH_MP_TAC INTERIOR_MAXIMAL THEN REWRITE_TAC[OPEN_INTERIOR] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERIOR_CLOSED_INTERVAL]) THEN
+  SUBGOAL_THEN `interval(a:real^N,b) INTER interval[c,d] = {}` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[INTER_INTERVAL_MIXED_EQ_EMPTY];
+    MP_TAC(ISPECL [`a:real^N`; `b:real^N`] INTERVAL_OPEN_SUBSET_CLOSED) THEN
+    REWRITE_TAC[INTERIOR_CLOSED_INTERVAL] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN SET_TAC[]]);;
+
+let INTER_INTERIOR_UNIONS_INTERVALS = prove
+ (`!s f. FINITE f /\ open s /\
+         (!t. t IN f ==> ?a b:real^N. t = interval[a,b]) /\
+         (!t. t IN f ==> s INTER (interior t) = {})
+         ==> s INTER interior(UNIONS f) = {}`,
+  ONCE_REWRITE_TAC[TAUT
+    `a /\ b /\ c /\ d ==> e <=> a /\ b /\ c ==> ~e ==> ~d`] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; GSYM MEMBER_NOT_EMPTY] THEN
+  SIMP_TAC[OPEN_CONTAINS_BALL_EQ; OPEN_INTER; OPEN_INTERIOR] THEN
+  SIMP_TAC[OPEN_SUBSET_INTERIOR; OPEN_BALL; SUBSET_INTER] THEN
+  REWRITE_TAC[GSYM SUBSET_INTER] THEN
+  GEN_TAC THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN CONJ_TAC THENL
+   [REWRITE_TAC[UNIONS_0; INTER_EMPTY; SUBSET_EMPTY] THEN
+    MESON_TAC[CENTRE_IN_BALL; NOT_IN_EMPTY];
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`i:real^N->bool`; `f:(real^N->bool)->bool`] THEN
+  DISCH_TAC THEN
+  REWRITE_TAC[UNIONS_INSERT; IN_INSERT] THEN
+  REWRITE_TAC[TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN
+  REWRITE_TAC[RIGHT_OR_DISTRIB; FORALL_AND_THM; EXISTS_OR_THM] THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC; UNWIND_THM2] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(MP_TAC o SPEC `i:real^N->bool`) THEN REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` (X_CHOOSE_THEN `b:real^N`
+    SUBST_ALL_TAC)) THEN
+  FIRST_X_ASSUM(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(TAUT
+   `(r ==> s \/ p) ==> (p ==> q) ==> r ==> s \/ q`) THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN STRIP_TAC THEN
+  ASM_CASES_TAC `(x:real^N) IN interval[a,b]` THENL
+   [ALL_TAC;
+    SUBGOAL_THEN
+     `?d. &0 < d /\ ball(x,d) SUBSET ((:real^N) DIFF interval[a,b])`
+    STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[closed; OPEN_CONTAINS_BALL; CLOSED_INTERVAL;
+                    IN_DIFF; IN_UNIV];
+      ALL_TAC] THEN
+    DISJ2_TAC THEN MAP_EVERY EXISTS_TAC [`x:real^N`; `min d e`] THEN
+    ASM_REWRITE_TAC[REAL_LT_MIN; SUBSET] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET])) THEN
+    SIMP_TAC[IN_BALL; REAL_LT_MIN; IN_DIFF; IN_INTER; IN_UNIV; IN_UNION] THEN
+    ASM_MESON_TAC[]] THEN
+  ASM_CASES_TAC `(x:real^N) IN interval(a,b)` THENL
+   [DISJ1_TAC THEN
+    SUBGOAL_THEN
+     `?d. &0 < d /\ ball(x:real^N,d) SUBSET interval(a,b)`
+    STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[OPEN_CONTAINS_BALL; OPEN_INTERVAL]; ALL_TAC] THEN
+    MAP_EVERY EXISTS_TAC [`x:real^N`; `min d e`] THEN
+    ASM_REWRITE_TAC[REAL_LT_MIN; SUBSET] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET])) THEN
+    SIMP_TAC[IN_BALL; REAL_LT_MIN; IN_DIFF; IN_INTER; IN_UNIV; IN_UNION] THEN
+    ASM_MESON_TAC[INTERVAL_OPEN_SUBSET_CLOSED; SUBSET];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [IN_INTERVAL]) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL]) THEN ASM_SIMP_TAC[REAL_LT_LE] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `k:num` THEN REWRITE_TAC[GSYM REAL_LT_LE; DE_MORGAN_THM] THEN
+  STRIP_TAC THEN DISJ2_TAC THENL
+   [EXISTS_TAC `x + --e / &2 % basis k :real^N`;
+    EXISTS_TAC `x + e / &2 % basis k :real^N`] THEN
+  EXISTS_TAC `e / &2` THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+   `b1 SUBSET k INTER (i UNION s)
+    ==> b2 SUBSET b1 /\ b2 INTER i = {}
+        ==> b2 SUBSET k INTER s`)) THEN
+  (CONJ_TAC THENL
+    [REWRITE_TAC[SUBSET; IN_BALL] THEN
+     GEN_TAC THEN MATCH_MP_TAC(NORM_ARITH `norm(d) = e / &2 ==>
+        dist(x + d,y) < e / &2 ==> dist(x,y) < e`) THEN
+     ASM_SIMP_TAC[NORM_MUL; NORM_BASIS] THEN UNDISCH_TAC `&0 < e` THEN
+     REAL_ARITH_TAC;
+     ALL_TAC]) THEN
+  REWRITE_TAC[EXTENSION; IN_INTER; IN_INTERVAL; NOT_IN_EMPTY] THEN
+  X_GEN_TAC `y:real^N` THEN REWRITE_TAC[IN_BALL; dist] THEN
+  REWRITE_TAC[TAUT `~(a /\ b) <=> a ==> ~b`] THEN
+  W(MP_TAC o C ISPEC COMPONENT_LE_NORM o rand o lhand o lhand o snd) THEN
+  DISCH_THEN(MP_TAC o SPEC `k:num`) THEN ASM_REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH `x <= y /\ y < e ==> x < e`)) THEN
+  ASM_SIMP_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT;
+               VECTOR_MUL_COMPONENT; BASIS_COMPONENT] THEN
+  DISCH_THEN(fun th -> DISCH_THEN(MP_TAC o SPEC `k:num`) THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN UNDISCH_TAC `&0 < e` THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* This lemma about iterations comes up in a few places.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let ITERATE_NONZERO_IMAGE_LEMMA = prove
+ (`!op s f g a.
+      monoidal op /\ FINITE s /\
+      g(a) = neutral op /\
+      (!x y. x IN s /\ y IN s /\ f x = f y /\ ~(x = y) ==> g(f x) = neutral op)
+      ==> iterate op {f x | x | x IN s /\ ~(f x = a)} g =
+          iterate op s (g o f)`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM ITERATE_SUPPORT] THEN
+  REWRITE_TAC[support] THEN
+  ONCE_REWRITE_TAC[SET_RULE `{f x |x| x IN s /\ ~(f x = a)} =
+                             IMAGE f {x | x IN s /\ ~(f x = a)}`] THEN
+  W(fun (asl,w) -> FIRST_ASSUM(fun th ->
+   MP_TAC(PART_MATCH (rand o rand)
+       (MATCH_MP ITERATE_IMAGE th) (rand w)))) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[IN_ELIM_THM; o_THM] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP ITERATE_SUPERSET) THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FINITE_RESTRICT] THEN
+  REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; SUBSET] THEN
+  REWRITE_TAC[IN_ELIM_THM; IN_IMAGE; o_THM] THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Bounds on intervals where they exist.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let interval_upperbound = new_definition
+  `(interval_upperbound:(real^M->bool)->real^M) s =
+        lambda i. sup {a | ?x. x IN s /\ (x$i = a)}`;;
+
+let interval_lowerbound = new_definition
+  `(interval_lowerbound:(real^M->bool)->real^M) s =
+        lambda i. inf {a | ?x. x IN s /\ (x$i = a)}`;;
+
+let INTERVAL_UPPERBOUND = prove
+ (`!a b:real^N. (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= b$i)
+                ==> interval_upperbound(interval[a,b]) = b`,
+  SIMP_TAC[interval_upperbound; CART_EQ; LAMBDA_BETA] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_SUP_UNIQUE THEN
+  REWRITE_TAC[IN_ELIM_THM; IN_INTERVAL] THEN ASM_MESON_TAC[REAL_LE_REFL]);;
+
+let INTERVAL_LOWERBOUND = prove
+ (`!a b:real^N. (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= b$i)
+                ==> interval_lowerbound(interval[a,b]) = a`,
+  SIMP_TAC[interval_lowerbound; CART_EQ; LAMBDA_BETA] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INF_UNIQUE THEN
+  REWRITE_TAC[IN_ELIM_THM; IN_INTERVAL] THEN ASM_MESON_TAC[REAL_LE_REFL]);;
+
+let INTERVAL_UPPERBOUND_1 = prove
+ (`!a b. drop a <= drop b ==> interval_upperbound(interval[a,b]) = b`,
+  SIMP_TAC[INTERVAL_UPPERBOUND; DIMINDEX_1; FORALL_1; drop]);;
+
+let INTERVAL_LOWERBOUND_1 = prove
+ (`!a b. drop a <= drop b ==> interval_lowerbound(interval[a,b]) = a`,
+  SIMP_TAC[INTERVAL_LOWERBOUND; DIMINDEX_1; FORALL_1; drop]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Content (length, area, volume...) of an interval.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let content = new_definition
+   `content(s:real^M->bool) =
+       if s = {} then &0 else
+       product(1..dimindex(:M))
+              (\i. (interval_upperbound s)$i - (interval_lowerbound s)$i)`;;
+
+let CONTENT_CLOSED_INTERVAL = prove
+ (`!a b:real^N. (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= b$i)
+                ==> content(interval[a,b]) =
+                        product(1..dimindex(:N)) (\i. b$i - a$i)`,
+  SIMP_TAC[content; INTERVAL_UPPERBOUND; INTERVAL_EQ_EMPTY;
+           INTERVAL_LOWERBOUND] THEN
+  MESON_TAC[REAL_NOT_LT]);;
+
+let CONTENT_1 = prove
+ (`!a b. drop a <= drop b ==> content(interval[a,b]) = drop b - drop a`,
+  SIMP_TAC[CONTENT_CLOSED_INTERVAL; FORALL_1; drop; DIMINDEX_1] THEN
+  REWRITE_TAC[PRODUCT_SING_NUMSEG]);;
+
+let CONTENT_UNIT = prove
+ (`content(interval[vec 0:real^N,vec 1]) = &1`,
+  REWRITE_TAC[content] THEN COND_CASES_TAC THENL
+   [POP_ASSUM MP_TAC THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    SIMP_TAC[INTERVAL_NE_EMPTY; VEC_COMPONENT; REAL_POS];
+    MATCH_MP_TAC PRODUCT_EQ_1 THEN
+    SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND;
+             VEC_COMPONENT; REAL_POS; IN_NUMSEG; REAL_SUB_RZERO]]);;
+
+let CONTENT_UNIT_1 = prove
+ (`content(interval[vec 0:real^1,vec 1]) = &1`,
+  MATCH_ACCEPT_TAC CONTENT_UNIT);;
+
+let CONTENT_POS_LE = prove
+ (`!a b:real^N. &0 <= content(interval[a,b])`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[content] THEN
+  COND_CASES_TAC THEN REWRITE_TAC[REAL_LE_REFL] THEN
+  MATCH_MP_TAC PRODUCT_POS_LE_NUMSEG THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+  ASM_SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND; REAL_SUB_LE]);;
+
+let CONTENT_POS_LT = prove
+ (`!a b:real^N.
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i < b$i)
+        ==> &0 < content(interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[CONTENT_CLOSED_INTERVAL; REAL_LT_IMP_LE] THEN
+  MATCH_MP_TAC PRODUCT_POS_LT_NUMSEG THEN
+  ASM_SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND; REAL_SUB_LT;
+               REAL_LT_IMP_LE]);;
+
+let CONTENT_POS_LT_1 = prove
+ (`!a b. drop a < drop b ==> &0 < content(interval[a,b])`,
+  SIMP_TAC[CONTENT_POS_LT; FORALL_1; DIMINDEX_1; GSYM drop]);;
+
+let CONTENT_EQ_0_GEN = prove
+ (`!s:real^N->bool.
+     bounded s
+     ==> (content s = &0 <=>
+          ?i a. 1 <= i /\ i <= dimindex(:N) /\ !x. x IN s ==> x$i = a)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[content] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THENL
+   [MESON_TAC[DIMINDEX_GE_1; LE_REFL]; ALL_TAC] THEN
+  REWRITE_TAC[PRODUCT_EQ_0_NUMSEG; REAL_SUB_0] THEN DISCH_TAC THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `k:num` THEN
+  ASM_CASES_TAC `1 <= k` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `k <= dimindex(:N)` THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[interval_upperbound; interval_lowerbound; LAMBDA_BETA] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) REAL_SUP_EQ_INF o lhs o snd) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [bounded]) THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    ASM_MESON_TAC[COMPONENT_LE_NORM; REAL_LE_TRANS];
+    DISCH_THEN SUBST1_TAC THEN ASM SET_TAC[]]);;
+
+let CONTENT_EQ_0 = prove
+ (`!a b:real^N.
+        content(interval[a,b]) = &0 <=>
+        ?i. 1 <= i /\ i <= dimindex(:N) /\ b$i <= a$i`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[content; INTERVAL_EQ_EMPTY] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [ASM_MESON_TAC[REAL_LT_IMP_LE]; ALL_TAC] THEN
+  REWRITE_TAC[PRODUCT_EQ_0_NUMSEG; REAL_SUB_0] THEN
+  AP_TERM_TAC THEN ABS_TAC THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[NOT_EXISTS_THM; TAUT `~(a /\ b /\ c) <=> a /\ b ==> ~c`] THEN
+  SIMP_TAC[REAL_NOT_LT; INTERVAL_LOWERBOUND; INTERVAL_UPPERBOUND] THEN
+  MESON_TAC[REAL_NOT_LE; REAL_LE_LT]);;
+
+let CONTENT_0_SUBSET_GEN = prove
+ (`!s t:real^N->bool.
+      s SUBSET t /\ bounded t /\ content t = &0 ==> content s = &0`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  SUBGOAL_THEN `bounded(s:real^N->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[BOUNDED_SUBSET]; ALL_TAC] THEN
+  ASM_SIMP_TAC[CONTENT_EQ_0_GEN] THEN ASM SET_TAC[]);;
+
+let CONTENT_0_SUBSET = prove
+ (`!s a b:real^N.
+        s SUBSET interval[a,b] /\ content(interval[a,b]) = &0
+        ==> content s = &0`,
+  MESON_TAC[CONTENT_0_SUBSET_GEN; BOUNDED_INTERVAL]);;
+
+let CONTENT_CLOSED_INTERVAL_CASES = prove
+ (`!a b:real^N.
+        content(interval[a,b]) =
+                if !i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= b$i
+                then product(1..dimindex(:N)) (\i. b$i - a$i)
+                else &0`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THEN
+  ASM_SIMP_TAC[CONTENT_EQ_0; CONTENT_CLOSED_INTERVAL] THEN
+  ASM_MESON_TAC[REAL_LE_TOTAL]);;
+
+let CONTENT_EQ_0_INTERIOR = prove
+ (`!a b:real^N.
+        content(interval[a,b]) = &0 <=> interior(interval[a,b]) = {}`,
+  REWRITE_TAC[CONTENT_EQ_0; INTERIOR_CLOSED_INTERVAL; INTERVAL_EQ_EMPTY]);;
+
+let CONTENT_EQ_0_1 = prove
+ (`!a b:real^1.
+        content(interval[a,b]) = &0 <=> drop b <= drop a`,
+  REWRITE_TAC[CONTENT_EQ_0; drop; DIMINDEX_1; CONJ_ASSOC; LE_ANTISYM] THEN
+  MESON_TAC[]);;
+
+let CONTENT_POS_LT_EQ = prove
+ (`!a b:real^N.
+        &0 < content(interval[a,b]) <=>
+        !i. 1 <= i /\ i <= dimindex(:N) ==> a$i < b$i`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[CONTENT_POS_LT] THEN
+  REWRITE_TAC[REAL_ARITH `&0 < x <=> &0 <= x /\ ~(x = &0)`] THEN
+  REWRITE_TAC[CONTENT_POS_LE; CONTENT_EQ_0] THEN MESON_TAC[REAL_NOT_LE]);;
+
+let CONTENT_EMPTY = prove
+ (`content {} = &0`,
+  REWRITE_TAC[content]);;
+
+let CONTENT_SUBSET = prove
+ (`!a b c d:real^N.
+        interval[a,b] SUBSET interval[c,d]
+        ==> content(interval[a,b]) <= content(interval[c,d])`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [content] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[CONTENT_POS_LE] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+  REWRITE_TAC[IN_INTERVAL] THEN DISCH_THEN(fun th ->
+    MP_TAC(SPEC `a:real^N` th) THEN MP_TAC(SPEC `b:real^N` th)) THEN
+  ASM_SIMP_TAC[REAL_LE_REFL; content] THEN REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[TAUT `(if b then c else d) = (if ~b then d else c)`] THEN
+  REWRITE_TAC[INTERVAL_NE_EMPTY] THEN COND_CASES_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[REAL_LE_TRANS]] THEN
+  MATCH_MP_TAC PRODUCT_LE_NUMSEG THEN
+  ASM_SIMP_TAC[INTERVAL_LOWERBOUND; INTERVAL_UPPERBOUND] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN REWRITE_TAC[IMP_IMP; AND_FORALL_THM] THEN
+  MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+  REAL_ARITH_TAC);;
+
+let CONTENT_LT_NZ = prove
+ (`!a b. &0 < content(interval[a,b]) <=> ~(content(interval[a,b]) = &0)`,
+  REWRITE_TAC[CONTENT_POS_LT_EQ; CONTENT_EQ_0] THEN MESON_TAC[REAL_NOT_LE]);;
+
+let INTERVAL_BOUNDS_NULL_1 = prove
+ (`!a b:real^1.
+        content(interval[a,b]) = &0
+        ==> interval_upperbound(interval[a,b]) =
+            interval_lowerbound(interval[a,b])`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `interval[a:real^1,b] = {}` THENL
+   [ASM_REWRITE_TAC[interval_upperbound; interval_lowerbound] THEN
+    REWRITE_TAC[sup; inf; NOT_IN_EMPTY; EMPTY_GSPEC] THEN DISCH_TAC THEN
+    REPLICATE_TAC 2 (AP_TERM_TAC THEN ABS_TAC) THEN
+    MESON_TAC[REAL_ARITH `~(x <= x - &1) /\ ~(x + &1 <= x)`];
+    RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT]) THEN
+    ASM_SIMP_TAC[INTERVAL_UPPERBOUND_1; INTERVAL_LOWERBOUND_1] THEN
+    REWRITE_TAC[CONTENT_EQ_0_1; GSYM DROP_EQ] THEN ASM_REAL_ARITH_TAC]);;
+
+let INTERVAL_BOUNDS_EMPTY_1 = prove
+ (`interval_upperbound({}:real^1->bool) =
+   interval_lowerbound({}:real^1->bool)`,
+  MESON_TAC[INTERVAL_BOUNDS_NULL_1; CONTENT_EMPTY; EMPTY_AS_INTERVAL]);;
+
+let CONTENT_PASTECART = prove
+ (`!a b:real^M c d:real^N.
+        content(interval[pastecart a c,pastecart b d]) =
+        content(interval[a,b]) * content(interval[c,d])`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[CONTENT_CLOSED_INTERVAL_CASES; LAMBDA_BETA] THEN
+  MATCH_MP_TAC(MESON[REAL_MUL_LZERO; REAL_MUL_RZERO]
+   `(p <=> p1 /\ p2) /\ z = x * y
+    ==> (if p then z else &0) =
+        (if p1 then x else &0) * (if p2 then y else &0)`) THEN
+  CONJ_TAC THENL
+   [EQ_TAC THEN DISCH_TAC THEN TRY CONJ_TAC THEN X_GEN_TAC `i:num` THEN
+    STRIP_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
+      ASM_SIMP_TAC[pastecart; LAMBDA_BETA; DIMINDEX_FINITE_SUM] THEN
+      DISCH_THEN MATCH_MP_TAC THEN ASM_ARITH_TAC;
+      FIRST_X_ASSUM(MP_TAC o SPEC `i + dimindex(:M)`) THEN
+      ASM_SIMP_TAC[pastecart; LAMBDA_BETA; DIMINDEX_FINITE_SUM] THEN
+      ANTS_TAC THENL [ASM_ARITH_TAC; REWRITE_TAC[ADD_SUB]] THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC;
+      RULE_ASSUM_TAC(REWRITE_RULE[DIMINDEX_FINITE_SUM]) THEN
+      ASM_CASES_TAC `i <= dimindex(:M)` THENL
+       [FIRST_X_ASSUM(MP_TAC o SPEC `i:num` o CONJUNCT1);
+        FIRST_X_ASSUM(MP_TAC o SPEC `i - dimindex(:M)` o CONJUNCT2)] THEN
+      ASM_SIMP_TAC[pastecart; LAMBDA_BETA; DIMINDEX_FINITE_SUM;
+                   ARITH_RULE `i:num <= m ==> i <= m + n`] THEN
+      DISCH_THEN MATCH_MP_TAC THEN ASM_ARITH_TAC];
+    SIMP_TAC[DIMINDEX_FINITE_SUM; ARITH_RULE `1 <= n + 1`;
+             PRODUCT_ADD_SPLIT] THEN
+    BINOP_TAC THENL
+     [ALL_TAC;
+      ONCE_REWRITE_TAC[ADD_SYM] THEN REWRITE_TAC[PRODUCT_OFFSET]] THEN
+    MATCH_MP_TAC PRODUCT_EQ_NUMSEG THEN
+    SIMP_TAC[pastecart; LAMBDA_BETA; DIMINDEX_FINITE_SUM; ADD_SUB;
+             ARITH_RULE `i:num <= m ==> i <= m + n`;
+             ARITH_RULE `i:num <= n ==> i + m <= m + n`] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The notion of a gauge --- simply an open set containing the point.        *)
+(* ------------------------------------------------------------------------- *)
+
+let gauge = new_definition
+  `gauge d <=> !x. x IN d(x) /\ open(d(x))`;;
+
+let GAUGE_BALL_DEPENDENT = prove
+ (`!e. (!x. &0 < e(x)) ==> gauge(\x. ball(x,e(x)))`,
+  SIMP_TAC[gauge; OPEN_BALL; IN_BALL; DIST_REFL]);;
+
+let GAUGE_BALL = prove
+ (`!e. &0 < e ==> gauge (\x. ball(x,e))`,
+  SIMP_TAC[gauge; OPEN_BALL; IN_BALL; DIST_REFL]);;
+
+let GAUGE_TRIVIAL = prove
+ (`gauge (\x. ball(x,&1))`,
+  SIMP_TAC[GAUGE_BALL; REAL_LT_01]);;
+
+let GAUGE_INTER = prove
+ (`!d1 d2. gauge d1 /\ gauge d2 ==> gauge (\x. (d1 x) INTER (d2 x))`,
+  SIMP_TAC[gauge; IN_INTER; OPEN_INTER]);;
+
+let GAUGE_INTERS = prove
+ (`!s. FINITE s /\ (!d. d IN s ==> gauge (f d))
+       ==> gauge(\x. INTERS {f d x | d IN s})`,
+  REWRITE_TAC[gauge; IN_INTERS] THEN
+  REWRITE_TAC[SET_RULE `{f d x | d IN s} = IMAGE (\d. f d x) s`] THEN
+  SIMP_TAC[FORALL_IN_IMAGE; OPEN_INTERS; FINITE_IMAGE]);;
+
+let GAUGE_EXISTENCE_LEMMA = prove
+ (`(!x. ?d. p x ==> &0 < d /\ q d x) <=>
+   (!x. ?d. &0 < d /\ (p x ==> q d x))`,
+  MESON_TAC[REAL_LT_01]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Divisions.                                                                *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("division_of",(12,"right"));;
+
+let division_of = new_definition
+ `s division_of i <=>
+        FINITE s /\
+        (!k. k IN s
+             ==> k SUBSET i /\ ~(k = {}) /\ ?a b. k = interval[a,b]) /\
+        (!k1 k2. k1 IN s /\ k2 IN s /\ ~(k1 = k2)
+                 ==> interior(k1) INTER interior(k2) = {}) /\
+        (UNIONS s = i)`;;
+
+let DIVISION_OF = prove
+ (`s division_of i <=>
+        FINITE s /\
+        (!k. k IN s ==> ~(k = {}) /\ ?a b. k = interval[a,b]) /\
+        (!k1 k2. k1 IN s /\ k2 IN s /\ ~(k1 = k2)
+                 ==> interior(k1) INTER interior(k2) = {}) /\
+        UNIONS s = i`,
+  REWRITE_TAC[division_of] THEN SET_TAC[]);;
+
+let DIVISION_OF_FINITE = prove
+ (`!s i. s division_of i ==> FINITE s`,
+  MESON_TAC[division_of]);;
+
+let DIVISION_OF_SELF = prove
+ (`!a b. ~(interval[a,b] = {}) ==> {interval[a,b]} division_of interval[a,b]`,
+  REWRITE_TAC[division_of; FINITE_INSERT; FINITE_RULES; IN_SING; UNIONS_1] THEN
+  MESON_TAC[SUBSET_REFL]);;
+
+let DIVISION_OF_TRIVIAL = prove
+ (`!s. s division_of {} <=> s = {}`,
+  REWRITE_TAC[division_of; SUBSET_EMPTY; CONJ_ASSOC] THEN
+  REWRITE_TAC[TAUT `~(p /\ ~p)`; GSYM NOT_EXISTS_THM; MEMBER_NOT_EMPTY] THEN
+  REWRITE_TAC[AC CONJ_ACI `((a /\ b) /\ c) /\ d <=> b /\ a /\ c /\ d`] THEN
+  GEN_TAC THEN MATCH_MP_TAC(TAUT `(a ==> b) ==> (a /\ b <=> a)`) THEN
+  DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[FINITE_RULES; UNIONS_0; NOT_IN_EMPTY]);;
+
+let EMPTY_DIVISION_OF = prove
+ (`!s. {} division_of s <=> s = {}`,
+  REWRITE_TAC[division_of; UNIONS_0; FINITE_EMPTY; NOT_IN_EMPTY] THEN
+  MESON_TAC[]);;
+
+let DIVISION_OF_SING = prove
+ (`!s a. s division_of interval[a,a] <=> s = {interval[a,a]}`,
+  let lemma = prove
+   (`s SUBSET {{a}} /\ p /\ UNIONS s = {a} <=> s = {{a}} /\ p`,
+    EQ_TAC THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[SET_RULE `UNIONS {a} = a`] THEN ASM SET_TAC[]) in
+  REWRITE_TAC[division_of; INTERVAL_SING] THEN
+  REWRITE_TAC[SET_RULE `k SUBSET {a} /\ ~(k = {}) /\ p <=> k = {a} /\ p`] THEN
+  REWRITE_TAC[GSYM INTERVAL_SING] THEN
+  REWRITE_TAC[MESON[] `(k = interval[a,b] /\ ?c d. k = interval[c,d]) <=>
+                       (k = interval[a,b])`] THEN
+  REWRITE_TAC[SET_RULE `(!k. k IN s ==> k = a) <=> s SUBSET {a}`] THEN
+  REWRITE_TAC[INTERVAL_SING; lemma] THEN MESON_TAC[FINITE_RULES; IN_SING]);;
+
+let ELEMENTARY_EMPTY = prove
+ (`?p. p division_of {}`,
+  REWRITE_TAC[DIVISION_OF_TRIVIAL; EXISTS_REFL]);;
+
+let ELEMENTARY_INTERVAL = prove
+ (`!a b. ?p. p division_of interval[a,b]`,
+  MESON_TAC[DIVISION_OF_TRIVIAL; DIVISION_OF_SELF]);;
+
+let DIVISION_CONTAINS = prove
+ (`!s i. s division_of i ==> !x. x IN i ==> ?k. x IN k /\ k IN s`,
+  REWRITE_TAC[division_of; EXTENSION; IN_UNIONS] THEN MESON_TAC[]);;
+
+let FORALL_IN_DIVISION = prove
+ (`!P d i. d division_of i
+           ==> ((!x. x IN d ==> P x) <=>
+               (!a b. interval[a,b] IN d ==> P(interval[a,b])))`,
+  REWRITE_TAC[division_of] THEN MESON_TAC[]);;
+
+let FORALL_IN_DIVISION_NONEMPTY = prove
+ (`!P d i.
+         d division_of i
+         ==> ((!x. x IN d ==> P x) <=>
+              (!a b. interval [a,b] IN d /\ ~(interval[a,b] = {})
+                     ==> P (interval [a,b])))`,
+  REWRITE_TAC[division_of] THEN MESON_TAC[]);;
+
+let DIVISION_OF_SUBSET = prove
+ (`!p q:(real^N->bool)->bool.
+        p division_of (UNIONS p) /\ q SUBSET p ==> q division_of (UNIONS q)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[division_of] THEN
+  REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THENL
+   [ASM_MESON_TAC[FINITE_SUBSET]; ASM SET_TAC[]; ASM SET_TAC[]]);;
+
+let DIVISION_OF_UNION_SELF = prove
+ (`!p s. p division_of s ==> p division_of (UNIONS p)`,
+  REWRITE_TAC[division_of] THEN MESON_TAC[]);;
+
+let DIVISION_OF_CONTENT_0 = prove
+ (`!a b d. content(interval[a,b]) = &0 /\ d division_of interval[a,b]
+           ==> !k. k IN d ==> content k = &0`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+  REWRITE_TAC[GSYM REAL_LE_ANTISYM; CONTENT_POS_LE] THEN
+  ASM_MESON_TAC[CONTENT_SUBSET; division_of]);;
+
+let DIVISION_INTER = prove
+ (`!s1 s2:real^N->bool p1 p2.
+        p1 division_of s1 /\
+        p2 division_of s2
+        ==> {k1 INTER k2 | k1 IN p1 /\ k2 IN p2 /\ ~(k1 INTER k2 = {})}
+            division_of (s1 INTER s2)`,
+  let lemma = prove
+   (`{k1 INTER k2 | k1 IN p1 /\ k2 IN p2 /\ ~(k1 INTER k2 = {})} =
+        {s | s IN IMAGE (\(k1,k2). k1 INTER k2) (p1 CROSS p2) /\
+             ~(s = {})}`,
+    REWRITE_TAC[EXTENSION] THEN
+    REWRITE_TAC[IN_IMAGE; IN_ELIM_THM; EXISTS_PAIR_THM; IN_CROSS] THEN
+    MESON_TAC[]) in
+  REPEAT GEN_TAC THEN REWRITE_TAC[DIVISION_OF] THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[lemma; FINITE_RESTRICT; FINITE_CROSS; FINITE_IMAGE] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[FORALL_PAIR_THM; IN_CROSS] THEN REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[INTER_INTERVAL];
+    REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC(SET_RULE
+     `(interior x1 INTER interior x2 = {} \/
+       interior y1 INTER interior y2 = {}) /\
+      interior(x1 INTER y1) SUBSET interior(x1) /\
+      interior(x1 INTER y1) SUBSET interior(y1) /\
+      interior(x2 INTER y2) SUBSET interior(x2) /\
+      interior(x2 INTER y2) SUBSET interior(y2)
+      ==> interior(x1 INTER y1) INTER interior(x2 INTER y2) = {}`) THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    REPEAT CONJ_TAC THEN MATCH_MP_TAC SUBSET_INTERIOR THEN SET_TAC[];
+    REWRITE_TAC[SET_RULE `UNIONS {x | x IN s /\ ~(x = {})} = UNIONS s`] THEN
+    REPEAT(FIRST_X_ASSUM(SUBST_ALL_TAC o SYM)) THEN
+    GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_UNIONS; IN_IMAGE; EXISTS_PAIR_THM; IN_CROSS; IN_INTER] THEN
+    MESON_TAC[IN_INTER]]);;
+
+let DIVISION_INTER_1 = prove
+ (`!d i a b:real^N.
+        d division_of i /\ interval[a,b] SUBSET i
+        ==> { interval[a,b] INTER k | k |
+                 k IN d /\ ~(interval[a,b] INTER k = {}) }
+            division_of interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `interval[a:real^N,b] = {}` THEN
+  ASM_REWRITE_TAC[INTER_EMPTY; SET_RULE `{{} | F} = {}`;
+                  DIVISION_OF_TRIVIAL] THEN
+  MP_TAC(ISPECL [`interval[a:real^N,b]`; `i:real^N->bool`;
+                 `{interval[a:real^N,b]}`; `d:(real^N->bool)->bool`]
+                DIVISION_INTER) THEN
+  ASM_SIMP_TAC[DIVISION_OF_SELF; SET_RULE `s SUBSET t ==> s INTER t = s`] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN SET_TAC[]);;
+
+let ELEMENTARY_INTER = prove
+ (`!s t. (?p. p division_of s) /\ (?p. p division_of t)
+         ==> ?p. p division_of (s INTER t)`,
+  MESON_TAC[DIVISION_INTER]);;
+
+let ELEMENTARY_INTERS = prove
+ (`!f:(real^N->bool)->bool.
+        FINITE f /\ ~(f = {}) /\
+        (!s. s IN f ==> ?p. p division_of s)
+        ==> ?p. p division_of (INTERS f)`,
+  REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[INTERS_INSERT] THEN
+  MAP_EVERY X_GEN_TAC [`s:real^N->bool`; `s:(real^N->bool)->bool`] THEN
+  ASM_CASES_TAC `s:(real^N->bool)->bool = {}` THEN ASM_REWRITE_TAC[] THENL
+   [REWRITE_TAC[INTERS_0; INTER_UNIV; IN_SING] THEN MESON_TAC[];
+    REWRITE_TAC[IN_INSERT] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC ELEMENTARY_INTER THEN ASM_MESON_TAC[]]);;
+
+let DIVISION_DISJOINT_UNION = prove
+ (`!s1 s2:real^N->bool p1 p2.
+        p1 division_of s1 /\
+        p2 division_of s2 /\
+        interior s1 INTER interior s2 = {}
+        ==> (p1 UNION p2) division_of (s1 UNION s2)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[division_of] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[FINITE_UNION; IN_UNION; EXISTS_OR_THM; SET_RULE
+   `UNIONS {x | P x \/ Q x} = UNIONS {x | P x} UNION UNIONS {x | Q x}`] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  REPEAT STRIP_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC; ALL_TAC; ASM SET_TAC[]] THEN
+  MATCH_MP_TAC(SET_RULE
+   `!s' t'. s SUBSET s' /\ t SUBSET t' /\ s' INTER t' = {}
+            ==> s INTER t = {}`)
+  THENL
+   [MAP_EVERY EXISTS_TAC
+     [`interior s1:real^N->bool`; `interior s2:real^N->bool`];
+    MAP_EVERY EXISTS_TAC
+     [`interior s2:real^N->bool`; `interior s1:real^N->bool`]] THEN
+  REPEAT CONJ_TAC THEN TRY(MATCH_MP_TAC SUBSET_INTERIOR) THEN
+  ASM SET_TAC[]);;
+
+let PARTIAL_DIVISION_EXTEND_1 = prove
+ (`!a b c d:real^N.
+        interval[c,d] SUBSET interval[a,b] /\ ~(interval[c,d] = {})
+        ==> ?p. p division_of interval[a,b] /\
+                interval[c,d] IN p`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `interval[a:real^N,b] = {}` THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  REPEAT(FIRST_X_ASSUM(STRIP_ASSUME_TAC o
+    GEN_REWRITE_RULE I [INTERVAL_NE_EMPTY])) THEN
+  EXISTS_TAC
+   `{interval
+      [(lambda i. if i < l then (c:real^N)$i else (a:real^N)$i):real^N,
+       (lambda i. if i < l then d$i else if i = l then c$l else b$i)] |
+       l IN 1..(dimindex(:N)+1)} UNION
+    {interval
+      [(lambda i. if i < l then c$i else if i = l then d$l else a$i),
+       (lambda i. if i < l then (d:real^N)$i else (b:real^N)$i):real^N] |
+       l IN 1..(dimindex(:N)+1)}` THEN
+  MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REWRITE_TAC[IN_UNION] THEN DISJ1_TAC THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN EXISTS_TAC `dimindex(:N)+1` THEN
+    REWRITE_TAC[IN_NUMSEG; LE_REFL; ARITH_RULE `1 <= n + 1`] THEN
+    AP_TERM_TAC THEN SIMP_TAC[CONS_11; PAIR_EQ; CART_EQ; LAMBDA_BETA] THEN
+    SIMP_TAC[ARITH_RULE `i <= n ==> i < n + 1`];
+    DISCH_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET_INTERVAL]) THEN
+  ASM_REWRITE_TAC[DIVISION_OF] THEN DISCH_TAC THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[SIMPLE_IMAGE] THEN
+    SIMP_TAC[FINITE_UNION; FINITE_IMAGE; FINITE_NUMSEG];
+    REWRITE_TAC[IN_UNION; TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN
+    REWRITE_TAC[SIMPLE_IMAGE; FORALL_AND_THM; FORALL_IN_IMAGE] THEN
+    ASM_SIMP_TAC[IN_NUMSEG; INTERVAL_NE_EMPTY; LAMBDA_BETA] THEN
+    CONJ_TAC THEN X_GEN_TAC `l:num` THEN DISCH_TAC THEN
+    (CONJ_TAC THENL [ALL_TAC; MESON_TAC[]]) THEN
+    REPEAT STRIP_TAC THEN
+    REPEAT(COND_CASES_TAC THEN ASM_SIMP_TAC[]) THEN
+    ASM_MESON_TAC[REAL_LE_TRANS];
+    REWRITE_TAC[IN_UNION; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[SET_RULE
+      `(!y. y IN {f x | x IN s} \/ y IN {g x | x IN s} ==> P y) <=>
+       (!x. x IN s ==> P(f x) /\ P(g x))`] THEN
+    REWRITE_TAC[AND_FORALL_THM; IN_NUMSEG] THEN
+    REWRITE_TAC[TAUT `(a ==> b) /\ (a ==> c) <=> a ==> b /\ c`] THEN
+    REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
+    MATCH_MP_TAC WLOG_LE THEN CONJ_TAC THENL
+     [REPEAT GEN_TAC THEN
+      REWRITE_TAC[TAUT `a ==> b ==> c <=> b ==> a ==> c`] THEN
+      REWRITE_TAC[INTER_ACI; CONJ_ACI] THEN MESON_TAC[];
+      ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`l:num`; `m:num`] THEN
+    DISCH_TAC THEN STRIP_TAC THEN STRIP_TAC THEN
+    ONCE_REWRITE_TAC[TAUT `(~p ==> q) <=> (~q ==> p)`] THEN
+     REWRITE_TAC[INTERIOR_CLOSED_INTERVAL] THEN
+    REWRITE_TAC[SET_RULE `s INTER t = {} <=> !x. ~(x IN s /\ x IN t)`] THEN
+    ASM_SIMP_TAC[IN_NUMSEG; INTERVAL_NE_EMPTY; LAMBDA_BETA; IN_INTERVAL;
+                 INTERIOR_CLOSED_INTERVAL] THEN
+    REWRITE_TAC[AND_FORALL_THM] THEN
+    REWRITE_TAC[TAUT `(a ==> b) /\ (a ==> c) <=> a ==> b /\ c`] THEN
+    REWRITE_TAC[NOT_FORALL_THM] THEN REPEAT CONJ_TAC THEN
+    DISCH_THEN(X_CHOOSE_THEN `x:real^N` (LABEL_TAC "*")) THEN
+    AP_TERM_TAC THEN SIMP_TAC[CONS_11; PAIR_EQ; CART_EQ; LAMBDA_BETA] THENL
+     (let tac1 =
+        UNDISCH_TAC `l:num <= m` THEN GEN_REWRITE_TAC LAND_CONV [LE_LT] THEN
+        STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+        REMOVE_THEN "*" (MP_TAC o SPEC `l:num`) THEN
+        ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+        ASM_REWRITE_TAC[LT_REFL] THEN REAL_ARITH_TAC
+      and tac2 =
+        UNDISCH_TAC `l:num <= m` THEN GEN_REWRITE_TAC LAND_CONV [LE_LT] THEN
+        STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
+         [REMOVE_THEN "*" (MP_TAC o SPEC `l:num`) THEN ANTS_TAC THENL
+           [ASM_ARITH_TAC; ALL_TAC] THEN
+          ASM_REWRITE_TAC[LT_REFL] THEN REAL_ARITH_TAC;
+          ALL_TAC] THEN
+        FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+        CONJ_TAC THEN X_GEN_TAC `i:num` THEN ASM_CASES_TAC `i:num = l` THEN
+        ASM_REWRITE_TAC[LT_REFL] THEN FIRST_X_ASSUM SUBST_ALL_TAC THEN
+        DISCH_TAC THEN REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `l:num`)) THEN
+        ASM_REWRITE_TAC[LT_REFL] THEN REAL_ARITH_TAC in
+      [tac1; tac2; tac2; tac1]);
+    MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+     [REWRITE_TAC[IMP_CONJ; SUBSET; FORALL_IN_UNIONS; SIMPLE_IMAGE] THEN
+      REWRITE_TAC[IN_UNIONS; IN_INSERT; IN_UNION; FORALL_IN_IMAGE;
+        RIGHT_FORALL_IMP_THM; FORALL_AND_THM;
+        TAUT `(a \/ b ==> c) <=> (a ==> c) /\ (b ==> c)`] THEN
+      ASM_SIMP_TAC[IN_INTERVAL; IN_NUMSEG; LAMBDA_BETA] THEN
+      REPEAT CONJ_TAC THEN GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN
+      MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+      ASM_MESON_TAC[REAL_LE_TRANS];
+      ALL_TAC] THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `a IN s ==> (c DIFF a) SUBSET UNIONS s ==> c SUBSET UNIONS s`)) THEN
+    REWRITE_TAC[SUBSET; IN_DIFF; IN_INTERVAL] THEN X_GEN_TAC `x:real^N` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN
+    GEN_REWRITE_TAC LAND_CONV [num_WOP] THEN
+    REWRITE_TAC[TAUT `a ==> ~(b /\ ~c) <=> a /\ b ==> c`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `l:num` STRIP_ASSUME_TAC) THEN
+    REWRITE_TAC[IN_UNIONS; SIMPLE_IMAGE; EXISTS_IN_IMAGE; IN_UNION;
+                EXISTS_OR_THM; RIGHT_OR_DISTRIB] THEN
+    REWRITE_TAC[OR_EXISTS_THM] THEN EXISTS_TAC `l:num` THEN
+    ASM_SIMP_TAC[IN_NUMSEG; IN_INTERVAL; LAMBDA_BETA;
+                 ARITH_RULE `x <= n ==> x <= n + 1`] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [DE_MORGAN_THM]) THEN
+    MATCH_MP_TAC MONO_OR THEN REWRITE_TAC[REAL_NOT_LE] THEN
+    REPEAT STRIP_TAC THEN REPEAT(COND_CASES_TAC THEN ASM_SIMP_TAC[]) THEN
+    ASM_MESON_TAC[REAL_LT_IMP_LE; REAL_LE_TRANS]]);;
+
+let PARTIAL_DIVISION_EXTEND_INTERVAL = prove
+ (`!p a b:real^N.
+        p division_of (UNIONS p) /\ (UNIONS p) SUBSET interval[a,b]
+        ==> ?q. p SUBSET q /\ q division_of interval[a,b]`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `p:(real^N->bool)->bool = {}` THEN
+  ASM_REWRITE_TAC[EMPTY_SUBSET] THENL
+   [MESON_TAC[ELEMENTARY_INTERVAL]; STRIP_TAC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  SUBGOAL_THEN `!k:real^N->bool. k IN p ==> ?q. q division_of interval[a,b] /\
+                                                k IN q`
+  MP_TAC THENL
+   [X_GEN_TAC `k:real^N->bool` THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+    DISCH_THEN(MP_TAC o SPEC `k:real^N->bool` o el 1 o CONJUNCTS) THEN
+    ASM_REWRITE_TAC[] THEN STRIP_TAC THEN FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    MATCH_MP_TAC PARTIAL_DIVISION_EXTEND_1 THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM] THEN
+  DISCH_THEN(X_CHOOSE_TAC `q:(real^N->bool)->(real^N->bool)->bool`) THEN
+  SUBGOAL_THEN
+   `?d. d division_of INTERS {UNIONS(q i DELETE i) | (i:real^N->bool) IN p}`
+  MP_TAC THENL
+   [MATCH_MP_TAC ELEMENTARY_INTERS THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+    ASM_SIMP_TAC[IMAGE_EQ_EMPTY; FINITE_IMAGE] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE] THEN X_GEN_TAC `k:real^N->bool` THEN
+    DISCH_TAC THEN EXISTS_TAC `(q k) DELETE (k:real^N->bool)` THEN
+    MATCH_MP_TAC DIVISION_OF_SUBSET THEN
+    EXISTS_TAC `(q:(real^N->bool)->(real^N->bool)->bool) k` THEN
+    REWRITE_TAC[DELETE_SUBSET] THEN ASM_MESON_TAC[division_of];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_TAC `d:(real^N->bool)->bool`) THEN
+  EXISTS_TAC `(d UNION p):(real^N->bool)->bool` THEN
+  REWRITE_TAC[SUBSET_UNION] THEN
+  SUBGOAL_THEN `interval[a:real^N,b] =
+                INTERS {UNIONS (q i DELETE i) | i IN p} UNION
+                UNIONS p`
+  SUBST1_TAC THENL
+   [ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN MATCH_MP_TAC(SET_RULE
+     `~(s = {}) /\
+      (!i. i IN s ==> f i UNION i = t)
+     ==> t = INTERS (IMAGE f s) UNION (UNIONS s)`) THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `k:real^N->bool` THEN DISCH_TAC THEN
+    MATCH_MP_TAC(SET_RULE
+     `UNIONS k = s /\ i IN k ==> UNIONS (k DELETE i) UNION i = s`) THEN
+    ASM_MESON_TAC[division_of];
+    ALL_TAC] THEN
+  MATCH_MP_TAC DIVISION_DISJOINT_UNION THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC INTER_INTERIOR_UNIONS_INTERVALS THEN
+  ASM_REWRITE_TAC[OPEN_INTERIOR] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+  X_GEN_TAC `k:real^N->bool` THEN DISCH_TAC THEN
+  MATCH_MP_TAC(SET_RULE
+   `!s. u SUBSET s /\ s INTER t = {} ==> u INTER t = {}`) THEN
+  EXISTS_TAC `interior(UNIONS(q k DELETE (k:real^N->bool)))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUBSET_INTERIOR THEN
+    MATCH_MP_TAC(SET_RULE `x IN s ==> INTERS s SUBSET x`) THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[INTER_COMM] THEN
+  MATCH_MP_TAC INTER_INTERIOR_UNIONS_INTERVALS THEN
+  REWRITE_TAC[OPEN_INTERIOR; FINITE_DELETE; IN_DELETE] THEN
+  ASM_MESON_TAC[division_of]);;
+
+let ELEMENTARY_BOUNDED = prove
+ (`!s. (?p. p division_of s) ==> bounded s`,
+  REWRITE_TAC[division_of] THEN
+  ASM_MESON_TAC[BOUNDED_UNIONS; BOUNDED_INTERVAL]);;
+
+let ELEMENTARY_SUBSET_INTERVAL = prove
+ (`!s. (?p. p division_of s) ==> ?a b. s SUBSET interval[a,b]`,
+  MESON_TAC[ELEMENTARY_BOUNDED; BOUNDED_SUBSET_CLOSED_INTERVAL]);;
+
+let DIVISION_UNION_INTERVALS_EXISTS = prove
+ (`!a b c d:real^N.
+        ~(interval[a,b] = {})
+        ==> ?p. (interval[a,b] INSERT p) division_of
+                (interval[a,b] UNION interval[c,d])`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `interval[c:real^N,d] = {}` THENL
+   [ASM_REWRITE_TAC[UNION_EMPTY] THEN ASM_MESON_TAC[DIVISION_OF_SELF];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `interval[a:real^N,b] INTER interval[c,d] = {}` THENL
+   [EXISTS_TAC `{interval[c:real^N,d]}` THEN
+    ONCE_REWRITE_TAC[SET_RULE `{a,b} = {a} UNION {b}`] THEN
+    MATCH_MP_TAC DIVISION_DISJOINT_UNION THEN
+    ASM_SIMP_TAC[DIVISION_OF_SELF] THEN
+    MATCH_MP_TAC(SET_RULE
+     `interior s SUBSET s /\ interior t SUBSET t /\ s INTER t = {}
+      ==> interior s INTER interior t = {}`) THEN
+    ASM_REWRITE_TAC[INTERIOR_SUBSET];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?u v:real^N. interval[a,b] INTER interval[c,d] = interval[u,v]`
+  STRIP_ASSUME_TAC THENL [MESON_TAC[INTER_INTERVAL]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`c:real^N`; `d:real^N`; `u:real^N`; `v:real^N`]
+                PARTIAL_DIVISION_EXTEND_1) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[INTER_SUBSET]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `p DELETE interval[u:real^N,v]` THEN
+  SUBGOAL_THEN `interval[a:real^N,b] UNION interval[c,d] =
+                interval[a,b] UNION UNIONS(p DELETE interval[u,v])`
+  SUBST1_TAC THENL
+   [FIRST_ASSUM(SUBST1_TAC o SYM o last o CONJUNCTS o
+                GEN_REWRITE_RULE I [division_of]) THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[SET_RULE `x INSERT s = {x} UNION s`] THEN
+  MATCH_MP_TAC DIVISION_DISJOINT_UNION THEN
+  ASM_SIMP_TAC[DIVISION_OF_SELF] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC DIVISION_OF_SUBSET THEN
+    EXISTS_TAC `p:(real^N->bool)->bool` THEN
+    ASM_MESON_TAC[DIVISION_OF_UNION_SELF; DELETE_SUBSET];
+    ALL_TAC] THEN
+  REWRITE_TAC[GSYM INTERIOR_INTER] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `interior(interval[u:real^N,v] INTER
+              UNIONS (p DELETE interval[u,v]))` THEN
+  CONJ_TAC THENL
+   [AP_TERM_TAC THEN MATCH_MP_TAC(SET_RULE
+     `!cd. p SUBSET cd /\ uv = ab INTER cd
+           ==> (ab INTER p = uv INTER p)`) THEN
+    EXISTS_TAC `interval[c:real^N,d]` THEN
+    ASM_REWRITE_TAC[UNIONS_SUBSET; IN_DELETE] THEN
+    ASM_MESON_TAC[division_of];
+    REWRITE_TAC[INTERIOR_INTER] THEN
+    MATCH_MP_TAC INTER_INTERIOR_UNIONS_INTERVALS THEN
+    REWRITE_TAC[IN_DELETE; OPEN_INTERIOR; FINITE_DELETE] THEN
+    ASM_MESON_TAC[division_of]]);;
+
+let DIVISION_OF_UNIONS = prove
+ (`!f. FINITE f /\
+       (!p. p IN f ==> p division_of (UNIONS p)) /\
+       (!k1 k2. k1 IN UNIONS f /\ k2 IN UNIONS f /\ ~(k1 = k2)
+                ==> interior k1 INTER interior k2 = {})
+       ==> (UNIONS f) division_of UNIONS(UNIONS f)`,
+  REWRITE_TAC[division_of] THEN
+  SIMP_TAC[FINITE_UNIONS] THEN REWRITE_TAC[FORALL_IN_UNIONS] THEN
+  GEN_TAC THEN DISCH_THEN(MP_TAC o el 1 o CONJUNCTS) THEN
+  MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN SET_TAC[]);;
+
+let ELEMENTARY_UNION_INTERVAL_STRONG = prove
+ (`!p a b:real^N.
+        p division_of (UNIONS p)
+        ==> ?q. p SUBSET q /\ q division_of (interval[a,b] UNION UNIONS p)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `p:(real^N->bool)->bool = {}` THENL
+   [ASM_REWRITE_TAC[UNIONS_0; UNION_EMPTY; EMPTY_SUBSET] THEN
+    MESON_TAC[ELEMENTARY_INTERVAL];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `interval[a:real^N,b] = {}` THEN
+  ASM_REWRITE_TAC[UNION_EMPTY] THENL [ASM_MESON_TAC[SUBSET_REFL]; ALL_TAC] THEN
+  ASM_CASES_TAC `interior(interval[a:real^N,b]) = {}` THENL
+   [EXISTS_TAC `interval[a:real^N,b] INSERT p` THEN
+    REWRITE_TAC[division_of] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+    SIMP_TAC[FINITE_INSERT; UNIONS_INSERT] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `interval[a:real^N,b] SUBSET UNIONS p` THENL
+   [ASM_SIMP_TAC[SET_RULE `s SUBSET t ==> s UNION t = t`] THEN
+    ASM_MESON_TAC[SUBSET_REFL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!k:real^N->bool. k IN p
+                     ==> ?q. ~(k IN q) /\ ~(q = {}) /\
+                             (k INSERT q) division_of (interval[a,b] UNION k)`
+  MP_TAC THENL
+   [X_GEN_TAC `k:real^N->bool` THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+    DISCH_THEN(MP_TAC o SPEC `k:real^N->bool` o CONJUNCT1 o CONJUNCT2) THEN
+    ASM_REWRITE_TAC[] THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`c:real^N`; `d:real^N`] THEN
+    DISCH_THEN SUBST_ALL_TAC THEN
+    ONCE_REWRITE_TAC[UNION_COMM] THEN
+    MP_TAC(ISPECL [`c:real^N`; `d:real^N`; `a:real^N`; `b:real^N`]
+        DIVISION_UNION_INTERVALS_EXISTS) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_TAC `q:(real^N->bool)->bool`) THEN
+    EXISTS_TAC `q DELETE interval[c:real^N,d]` THEN
+    ASM_REWRITE_TAC[IN_DELETE; SET_RULE
+     `x INSERT (q DELETE x) = x INSERT q`] THEN
+    DISCH_TAC THEN
+    UNDISCH_TAC `(interval[c:real^N,d] INSERT q) division_of
+                 (interval [c,d] UNION interval [a,b])` THEN
+    ASM_SIMP_TAC[SET_RULE `s DELETE x = {} ==> x INSERT s = {x}`] THEN
+    REWRITE_TAC[division_of; UNIONS_1] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM] THEN
+  DISCH_THEN(X_CHOOSE_TAC `q:(real^N->bool)->(real^N->bool)->bool`) THEN
+  MP_TAC(ISPEC `IMAGE (UNIONS o (q:(real^N->bool)->(real^N->bool)->bool)) p`
+    ELEMENTARY_INTERS) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; IMAGE_EQ_EMPTY; FORALL_IN_IMAGE] THEN
+  ANTS_TAC THENL
+   [X_GEN_TAC `k:real^N->bool` THEN DISCH_TAC THEN
+    EXISTS_TAC `(q:(real^N->bool)->(real^N->bool)->bool) k` THEN
+    REWRITE_TAC[o_THM] THEN MATCH_MP_TAC DIVISION_OF_SUBSET THEN
+    EXISTS_TAC `(k:real^N->bool) INSERT q k` THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[DIVISION_OF_UNION_SELF]; SET_TAC[]];
+    DISCH_THEN(X_CHOOSE_TAC `r:(real^N->bool)->bool`)] THEN
+  EXISTS_TAC `p UNION r:(real^N->bool)->bool` THEN SIMP_TAC[SUBSET_UNION] THEN
+  SUBGOAL_THEN
+   `interval[a:real^N,b] UNION UNIONS p =
+    UNIONS p UNION INTERS(IMAGE (UNIONS o q) p)`
+  SUBST1_TAC THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN X_GEN_TAC `y:real^N` THEN
+    REWRITE_TAC[IN_UNION] THEN
+    ASM_CASES_TAC `(y:real^N) IN UNIONS p` THEN ASM_REWRITE_TAC[IN_INTERS] THEN
+    REWRITE_TAC[FORALL_IN_UNIONS; IMP_CONJ; FORALL_IN_IMAGE;
+                RIGHT_FORALL_IMP_THM] THEN
+    SUBGOAL_THEN
+     `!k. k IN p ==> UNIONS(k INSERT q k) = interval[a:real^N,b] UNION k`
+    MP_TAC THENL [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+    REWRITE_TAC[UNIONS_INSERT; o_THM] THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [EXTENSION] THEN
+    REWRITE_TAC[RIGHT_IMP_FORALL_THM; IN_UNION] THEN
+    ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `y:real^N`) THEN
+    UNDISCH_TAC `~((y:real^N) IN UNIONS p)` THEN
+    SIMP_TAC[IN_UNIONS; NOT_EXISTS_THM; TAUT `~(a /\ b) <=> a ==> ~b`] THEN
+    ASM_CASES_TAC `(y:real^N) IN interval[a,b]` THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC DIVISION_DISJOINT_UNION THEN
+  ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[INTER_COMM] THEN
+  MATCH_MP_TAC INTER_INTERIOR_UNIONS_INTERVALS THEN
+  ASM_REWRITE_TAC[OPEN_INTERIOR] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+  X_GEN_TAC `k:real^N->bool` THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[INTERIOR_FINITE_INTERS; FINITE_IMAGE] THEN
+  MATCH_MP_TAC(SET_RULE `(?x. x IN p /\ f x INTER s = {})
+                        ==> INTERS (IMAGE f p) INTER s = {}`) THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE; o_THM] THEN EXISTS_TAC `k:real^N->bool` THEN
+  ASM_REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[INTER_COMM] THEN
+  MATCH_MP_TAC INTER_INTERIOR_UNIONS_INTERVALS THEN
+  ASM_REWRITE_TAC[OPEN_INTERIOR] THEN REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[division_of; FINITE_INSERT; IN_INSERT];
+    ASM_MESON_TAC[division_of; FINITE_INSERT; IN_INSERT];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `k:real^N->bool`) THEN
+  ASM_REWRITE_TAC[division_of; IN_INSERT] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[]);;
+
+let ELEMENTARY_UNION_INTERVAL = prove
+ (`!p a b:real^N.
+        p division_of (UNIONS p)
+        ==> ?q. q division_of (interval[a,b] UNION UNIONS p)`,
+  MESON_TAC[ELEMENTARY_UNION_INTERVAL_STRONG]);;
+
+let ELEMENTARY_UNIONS_INTERVALS = prove
+ (`!f. FINITE f /\
+       (!s. s IN f ==> ?a b:real^N. s = interval[a,b])
+       ==> (?p. p division_of (UNIONS f))`,
+  REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[UNIONS_0; UNIONS_INSERT; ELEMENTARY_EMPTY] THEN
+  REWRITE_TAC[IN_INSERT; TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN
+  SIMP_TAC[FORALL_AND_THM; LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN
+  REPEAT GEN_TAC 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_TAC `p:(real^N->bool)->bool`) THEN
+  SUBGOAL_THEN `UNIONS f:real^N->bool = UNIONS p` SUBST1_TAC THENL
+   [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+  MATCH_MP_TAC ELEMENTARY_UNION_INTERVAL THEN ASM_MESON_TAC[division_of]);;
+
+let ELEMENTARY_UNION = prove
+ (`!s t:real^N->bool.
+        (?p. p division_of s) /\ (?p. p division_of t)
+        ==> (?p. p division_of (s UNION t))`,
+  REPEAT GEN_TAC THEN DISCH_THEN
+   (CONJUNCTS_THEN2 (X_CHOOSE_TAC `p1:(real^N->bool)->bool`)
+                    (X_CHOOSE_TAC `p2:(real^N->bool)->bool`)) THEN
+  SUBGOAL_THEN `s UNION t :real^N->bool = UNIONS p1 UNION UNIONS p2`
+  SUBST1_TAC THENL [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+  REWRITE_TAC[SET_RULE `UNIONS p1 UNION UNIONS p2 = UNIONS(p1 UNION p2)`] THEN
+  MATCH_MP_TAC ELEMENTARY_UNIONS_INTERVALS THEN
+  REWRITE_TAC[IN_UNION; FINITE_UNION] THEN
+  ASM_MESON_TAC[division_of]);;
+
+let PARTIAL_DIVISION_EXTEND = prove
+ (`!p q s t:real^N->bool.
+        p division_of s /\ q division_of t /\ s SUBSET t
+        ==> ?r. p SUBSET r /\ r division_of t`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?a b:real^N. t SUBSET interval[a,b]` MP_TAC THENL
+   [ASM_MESON_TAC[ELEMENTARY_SUBSET_INTERVAL]; ALL_TAC] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `?r1. p SUBSET r1 /\ r1 division_of interval[a:real^N,b]`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC PARTIAL_DIVISION_EXTEND_INTERVAL THEN
+    ASM_MESON_TAC[division_of; SUBSET_TRANS];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?r2:(real^N->bool)->bool.
+        r2 division_of (UNIONS(r1 DIFF p)) INTER (UNIONS q)`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC ELEMENTARY_INTER THEN
+    ASM_MESON_TAC[FINITE_DIFF; IN_DIFF; division_of;
+                  ELEMENTARY_UNIONS_INTERVALS];
+    ALL_TAC] THEN
+  EXISTS_TAC `p UNION r2:(real^N->bool)->bool` THEN
+  CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `t:real^N->bool = UNIONS p UNION (UNIONS(r1 DIFF p) INTER UNIONS q)`
+  SUBST1_TAC THENL
+   [REPEAT(FIRST_X_ASSUM(MP_TAC o last o CONJUNCTS o
+                GEN_REWRITE_RULE I [division_of])) THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN SET_TAC[];
+    MATCH_MP_TAC DIVISION_DISJOINT_UNION THEN ASM_REWRITE_TAC[] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+    MATCH_MP_TAC(SET_RULE
+     `!t'. t SUBSET t' /\ s INTER t' = {} ==> s INTER t = {}`) THEN
+    EXISTS_TAC `interior(UNIONS(r1 DIFF p)):real^N->bool` THEN
+    CONJ_TAC THENL [MATCH_MP_TAC SUBSET_INTERIOR THEN SET_TAC[]; ALL_TAC] THEN
+    REPEAT(MATCH_MP_TAC INTER_INTERIOR_UNIONS_INTERVALS THEN
+           REWRITE_TAC[OPEN_INTERIOR] THEN
+           REPEAT(CONJ_TAC THENL
+            [ASM_MESON_TAC[IN_DIFF; FINITE_DIFF; division_of]; ALL_TAC]) THEN
+           REWRITE_TAC[IN_DIFF] THEN REPEAT STRIP_TAC THEN
+           ONCE_REWRITE_TAC[INTER_COMM]) THEN
+    ASM_MESON_TAC[division_of; SUBSET]]);;
+
+let INTERVAL_SUBDIVISION = prove
+ (`!a b c:real^N.
+        c IN interval[a,b]
+        ==> IMAGE (\s. interval[(lambda i. if i IN s then c$i else a$i),
+                                (lambda i. if i IN s then b$i else c$i)])
+                  {s | s SUBSET 1..dimindex(:N)}
+            division_of interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o GEN_REWRITE_RULE I [IN_INTERVAL]) THEN
+  REWRITE_TAC[DIVISION_OF] THEN
+  SIMP_TAC[FINITE_IMAGE; FINITE_POWERSET; FINITE_NUMSEG] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; SUBSET_INTERVAL; INTERVAL_NE_EMPTY] THEN
+  REWRITE_TAC[INTERIOR_CLOSED_INTERVAL] THEN REPEAT CONJ_TAC THENL
+   [SIMP_TAC[LAMBDA_BETA] THEN ASM_MESON_TAC[REAL_LE_TRANS];
+    X_GEN_TAC `s:num->bool` THEN DISCH_TAC THEN
+    X_GEN_TAC `s':num->bool` THEN DISCH_TAC THEN
+    REWRITE_TAC[SET_RULE
+     `(~p ==> s INTER t = {}) <=> (!x. x IN s /\ x IN t ==> p)`] THEN
+    X_GEN_TAC `x:real^N` THEN REWRITE_TAC[IN_INTERVAL; AND_FORALL_THM] THEN
+    REWRITE_TAC[TAUT `(a ==> b) /\ (a ==> c) <=> a ==> b /\ c`] THEN
+    SIMP_TAC[LAMBDA_BETA] THEN
+    ASM_CASES_TAC `s':num->bool = s` THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+     `~(s' = s) ==> ?x. x IN s' /\ ~(x IN s) \/ x IN s /\ ~(x IN s')`)) THEN
+    DISCH_THEN(X_CHOOSE_THEN `k:num` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(MP_TAC o SPEC `k:num`) THEN ASM_REWRITE_TAC[] THEN
+    (ANTS_TAC THENL [ASM_MESON_TAC[SUBSET; IN_NUMSEG]; REAL_ARITH_TAC]);
+    MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THEN
+    GEN_REWRITE_TAC I [SUBSET] THENL
+     [REWRITE_TAC[FORALL_IN_UNIONS] THEN ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+      REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+      ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+      REWRITE_TAC[RIGHT_FORALL_IMP_THM; GSYM SUBSET] THEN
+      SIMP_TAC[SUBSET_INTERVAL; LAMBDA_BETA] THEN
+      ASM_MESON_TAC[REAL_LE_TRANS; REAL_LE_REFL];
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+      REWRITE_TAC[IN_UNIONS; EXISTS_IN_IMAGE; EXISTS_IN_GSPEC] THEN EXISTS_TAC
+       `{i | i IN 1..dimindex(:N) /\ (c:real^N)$i <= (x:real^N)$i}` THEN
+      CONJ_TAC THENL [SET_TAC[]; REWRITE_TAC[IN_INTERVAL]] THEN
+      SIMP_TAC[LAMBDA_BETA; IN_ELIM_THM; IN_NUMSEG] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL]) THEN
+      ASM_MESON_TAC[REAL_LE_TOTAL]]]);;
+
+let DIVISION_OF_NONTRIVIAL = prove
+ (`!s a b:real^N.
+        s division_of interval[a,b] /\ ~(content(interval[a,b]) = &0)
+        ==> {k | k IN s /\ ~(content k = &0)} division_of interval[a,b]`,
+  REPEAT GEN_TAC THEN WF_INDUCT_TAC `CARD(s:(real^N->bool)->bool)` THEN
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `{k:real^N->bool | k IN s /\ ~(content k = &0)} = s` THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [EXTENSION]) THEN
+  REWRITE_TAC[IN_ELIM_THM; NOT_FORALL_THM; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[TAUT `~(a /\ ~b <=> a) <=> a /\ b`] THEN
+  X_GEN_TAC `k:real^N->bool` THEN STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `s DELETE (k:real^N->bool)`) THEN
+  ASM_SIMP_TAC[CARD_DELETE; ARITH_RULE `n - 1 < n <=> ~(n = 0)`] THEN
+  ASM_SIMP_TAC[CARD_EQ_0] THEN ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  ANTS_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    ASM SET_TAC[]] THEN
+  REWRITE_TAC[DIVISION_OF] THEN
+  FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+  ASM_SIMP_TAC[FINITE_DELETE; IN_DELETE] THEN
+  FIRST_ASSUM(MP_TAC o C MATCH_MP (ASSUME `(k:real^N->bool) IN s`)) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`c:real^N`; `d:real^N`] THEN
+  DISCH_THEN SUBST_ALL_TAC THEN
+  MATCH_MP_TAC(SET_RULE
+    `UNIONS s = i /\ k SUBSET UNIONS(s DELETE k)
+     ==> UNIONS(s DELETE k) = i`) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(MESON[CLOSED_LIMPT; SUBSET]
+   `closed s /\ (!x. x IN k ==> x limit_point_of s) ==> k SUBSET s`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CLOSED_UNIONS THEN
+    ASM_REWRITE_TAC[FINITE_DELETE; IN_DELETE] THEN
+    ASM_MESON_TAC[CLOSED_INTERVAL];
+    ALL_TAC] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN REWRITE_TAC[LIMPT_APPROACHABLE] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN REWRITE_TAC[dist] THEN
+  SUBGOAL_THEN `?y:real^N. y IN UNIONS s /\ ~(y IN interval[c,d]) /\
+                           ~(y = x) /\ norm(y - x) < e`
+  MP_TAC THENL [ALL_TAC; SET_TAC[]] THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY UNDISCH_TAC
+   [`~(content(interval[a:real^N,b]) = &0)`;
+    `content(interval[c:real^N,d]) = &0`] THEN
+  REWRITE_TAC[CONTENT_EQ_0; NOT_EXISTS_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `i:num` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[REAL_NOT_LE] THEN
+  DISCH_TAC THEN UNDISCH_TAC `~(interval[c:real^N,d] = {})` THEN
+  REWRITE_TAC[INTERVAL_EQ_EMPTY; NOT_EXISTS_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[REAL_NOT_LT] THEN
+  ASM_SIMP_TAC[REAL_ARITH `a <= b ==> (b <= a <=> a = b)`] THEN
+  DISCH_THEN(fun th -> SUBST_ALL_TAC th THEN ASSUME_TAC th) THEN
+  UNDISCH_TAC `interval[c:real^N,d] SUBSET interval[a,b]` THEN
+  REWRITE_TAC[SUBSET] THEN DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  MP_TAC(ASSUME `(x:real^N) IN interval[c,d]`) THEN
+  GEN_REWRITE_TAC LAND_CONV [IN_INTERVAL] THEN
+  DISCH_THEN(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[REAL_ARITH `d = c ==> (c <= x /\ x <= d <=> x = c)`] THEN
+  DISCH_TAC THEN
+  MP_TAC(ASSUME `(x:real^N) IN interval[a,b]`) THEN
+  GEN_REWRITE_TAC LAND_CONV [IN_INTERVAL] THEN
+  DISCH_THEN(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+  STRIP_TAC THEN EXISTS_TAC
+   `(lambda j. if j = i then
+                 if (c:real^N)$i <= ((a:real^N)$i + (b:real^N)$i) / &2
+                 then c$i + min e (b$i - c$i) / &2
+                 else c$i - min e (c$i - a$i) / &2
+               else (x:real^N)$j):real^N` THEN
+  SIMP_TAC[IN_INTERVAL; LAMBDA_BETA; CART_EQ] THEN REPEAT CONJ_TAC THENL
+   [X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+    UNDISCH_TAC `(x:real^N) IN interval[a,b]` THEN
+    REWRITE_TAC[IN_INTERVAL] THEN DISCH_THEN(MP_TAC o SPEC `j:num`) THEN
+    ASM_REWRITE_TAC[] THEN COND_CASES_TAC THEN REWRITE_TAC[] THEN
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    ASM_REAL_ARITH_TAC;
+    DISCH_THEN(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+    ASM_REAL_ARITH_TAC;
+    DISCH_THEN(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+    ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[vector_norm; dot] THEN
+    SIMP_TAC[LAMBDA_BETA; VECTOR_SUB_COMPONENT; GSYM REAL_POW_2] THEN
+    REWRITE_TAC[REAL_ARITH
+     `((if p then x else y) - y) pow 2 = if p then (x - y) pow 2 else &0`] THEN
+    ASM_SIMP_TAC[SUM_DELTA; IN_NUMSEG; POW_2_SQRT_ABS] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let DIVISION_OF_AFFINITY = prove
+ (`!d s:real^N->bool m c.
+    IMAGE (IMAGE (\x. m % x + c)) d division_of (IMAGE (\x. m % x + c) s) <=>
+    if m = &0 then if s = {} then d = {}
+                   else ~(d = {}) /\ !k. k IN d ==> ~(k = {})
+    else d division_of s`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `m = &0` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_CASES_TAC `s:real^N->bool = {}` THEN
+    ASM_REWRITE_TAC[IMAGE_CLAUSES; DIVISION_OF_TRIVIAL; IMAGE_EQ_EMPTY] THEN
+    ASM_CASES_TAC `d:(real^N->bool)->bool = {}` THEN
+    ASM_REWRITE_TAC[IMAGE_CLAUSES; EMPTY_DIVISION_OF; UNIONS_0;
+                    IMAGE_EQ_EMPTY] THEN
+    REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_LID] THEN
+    ASM_SIMP_TAC[SET_RULE `~(s = {}) ==> IMAGE (\x. c) s = {c}`] THEN
+    ASM_CASES_TAC `!k:real^N->bool. k IN d ==> ~(k = {})` THEN
+    ASM_REWRITE_TAC[division_of] THENL
+     [ALL_TAC;
+      REWRITE_TAC[FORALL_IN_IMAGE] THEN ASM_MESON_TAC[IMAGE_EQ_EMPTY]] THEN
+    SUBGOAL_THEN
+     `IMAGE (IMAGE ((\x. c):real^N->real^N)) d = {{c}}`
+    SUBST1_TAC THENL
+     [GEN_REWRITE_TAC I [EXTENSION] THEN
+      REWRITE_TAC[IN_IMAGE; IN_SING] THEN ASM SET_TAC[];
+      SIMP_TAC[UNIONS_1; FINITE_SING; IN_SING; IMP_CONJ] THEN
+      REWRITE_TAC[SUBSET_REFL; NOT_INSERT_EMPTY] THEN
+      MESON_TAC[INTERVAL_SING]];
+    REWRITE_TAC[division_of] THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[IMAGE_EQ_EMPTY; GSYM INTERIOR_INTER] THEN
+    ASM_SIMP_TAC[FINITE_IMAGE_INJ_EQ; GSYM IMAGE_UNIONS;
+         VECTOR_ARITH `x + a:real^N = y + a <=> x = y`;
+             VECTOR_MUL_LCANCEL;
+     SET_RULE `(!x y. f x = f y <=> x = y)
+               ==> (IMAGE f s SUBSET IMAGE f t <=> s SUBSET t) /\
+                   (IMAGE f s = IMAGE f t <=> s = t) /\
+                   (IMAGE f s INTER IMAGE f t = IMAGE f (s INTER t))`] THEN
+    AP_TERM_TAC THEN BINOP_TAC THENL
+     [AP_TERM_TAC THEN ABS_TAC THEN REPLICATE_TAC 3 AP_TERM_TAC THEN
+      EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+      MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+      ASM_SIMP_TAC[IMAGE_AFFINITY_INTERVAL] THENL [ALL_TAC; MESON_TAC[]] THEN
+      FIRST_X_ASSUM(MP_TAC o AP_TERM
+       `IMAGE (\x:real^N. inv m % x + --(inv m % c))`) THEN
+      ASM_SIMP_TAC[GSYM IMAGE_o; AFFINITY_INVERSES] THEN
+      ASM_REWRITE_TAC[IMAGE_I; IMAGE_AFFINITY_INTERVAL] THEN MESON_TAC[];
+      SUBGOAL_THEN `(\x:real^N. m % x + c) = (\x. c + x) o (\x. m % x)`
+      SUBST1_TAC THENL
+       [REWRITE_TAC[FUN_EQ_THM; o_THM] THEN VECTOR_ARITH_TAC;
+        REWRITE_TAC[IMAGE_o; INTERIOR_TRANSLATION] THEN
+        ASM_SIMP_TAC[INTERIOR_INJECTIVE_LINEAR_IMAGE; LINEAR_SCALING;
+                     VECTOR_MUL_LCANCEL; IMAGE_EQ_EMPTY]]]]);;
+
+let DIVISION_OF_TRANSLATION = prove
+ (`!d s:real^N->bool.
+        IMAGE (IMAGE (\x. a + x)) d division_of (IMAGE (\x. a + x) s) <=>
+        d division_of s`,
+  ONCE_REWRITE_TAC[VECTOR_ARITH `a + x:real^N = &1 % x + a`] THEN
+  REWRITE_TAC[DIVISION_OF_AFFINITY] THEN CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let DIVISION_OF_REFLECT = prove
+ (`!d s:real^N->bool.
+        IMAGE (IMAGE (--)) d division_of IMAGE (--) s <=>
+        d division_of s`,
+  REPEAT GEN_TAC THEN SUBGOAL_THEN `(--) = \x:real^N. --(&1) % x + vec 0`
+  SUBST1_TAC THENL
+  [REWRITE_TAC[FUN_EQ_THM] THEN VECTOR_ARITH_TAC;
+   REWRITE_TAC[DIVISION_OF_AFFINITY] THEN CONV_TAC REAL_RAT_REDUCE_CONV]);;
+
+let ELEMENTARY_COMPACT = prove
+ (`!s. (?d. d division_of s) ==> compact s`,
+  REWRITE_TAC[division_of] THEN
+  MESON_TAC[COMPACT_UNIONS; COMPACT_INTERVAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Tagged (partial) divisions.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("tagged_partial_division_of",(12,"right"));;
+parse_as_infix("tagged_division_of",(12,"right"));;
+
+let tagged_partial_division_of = new_definition
+  `s tagged_partial_division_of i <=>
+        FINITE s /\
+        (!x k. (x,k) IN s
+               ==> x IN k /\ k SUBSET i /\ ?a b. k = interval[a,b]) /\
+        (!x1 k1 x2 k2. (x1,k1) IN s /\ (x2,k2) IN s /\ ~((x1,k1) = (x2,k2))
+                       ==> (interior(k1) INTER interior(k2) = {}))`;;
+
+let tagged_division_of = new_definition
+  `s tagged_division_of i <=>
+        s tagged_partial_division_of i /\ (UNIONS {k | ?x. (x,k) IN s} = i)`;;
+
+let TAGGED_DIVISION_OF_FINITE = prove
+ (`!s i. s tagged_division_of i ==> FINITE s`,
+  SIMP_TAC[tagged_division_of; tagged_partial_division_of]);;
+
+let TAGGED_DIVISION_OF = prove
+ (`s tagged_division_of i <=>
+        FINITE s /\
+        (!x k. (x,k) IN s
+               ==> x IN k /\ k SUBSET i /\ ?a b. k = interval[a,b]) /\
+        (!x1 k1 x2 k2. (x1,k1) IN s /\ (x2,k2) IN s /\ ~((x1,k1) = (x2,k2))
+                       ==> (interior(k1) INTER interior(k2) = {})) /\
+        (UNIONS {k | ?x. (x,k) IN s} = i)`,
+  REWRITE_TAC[tagged_division_of; tagged_partial_division_of; CONJ_ASSOC]);;
+
+let DIVISION_OF_TAGGED_DIVISION = prove
+ (`!s i. s tagged_division_of i ==> (IMAGE SND s) division_of i`,
+  REWRITE_TAC[TAGGED_DIVISION_OF; division_of] THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE; FORALL_PAIR_THM; PAIR_EQ] THEN
+  REWRITE_TAC[IN_IMAGE; EXISTS_PAIR_THM] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[MEMBER_NOT_EMPTY];
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[];
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_IMAGE; IN_UNIONS] THEN
+    REWRITE_TAC[FORALL_PAIR_THM; EXISTS_PAIR_THM] THEN MESON_TAC[]]);;
+
+let PARTIAL_DIVISION_OF_TAGGED_DIVISION = prove
+ (`!s i. s tagged_partial_division_of i
+         ==> (IMAGE SND s) division_of UNIONS(IMAGE SND s)`,
+  REWRITE_TAC[tagged_partial_division_of; division_of] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[FORALL_PAIR_THM; PAIR_EQ; DE_MORGAN_THM] THEN
+  GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN REPEAT DISCH_TAC THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[FINITE_IMAGE];
+    ALL_TAC;
+    ASM_MESON_TAC[]] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN CONJ_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[MEMBER_NOT_EMPTY]] THEN
+  REWRITE_TAC[SUBSET; IN_UNIONS; IN_IMAGE; EXISTS_PAIR_THM] THEN
+  CONV_TAC(ONCE_DEPTH_CONV UNWIND_CONV) THEN ASM SET_TAC[]);;
+
+let TAGGED_PARTIAL_DIVISION_SUBSET = prove
+ (`!s t i. s tagged_partial_division_of i /\ t SUBSET s
+           ==> t tagged_partial_division_of i`,
+  REWRITE_TAC[tagged_partial_division_of] THEN
+  MESON_TAC[FINITE_SUBSET; SUBSET]);;
+
+let VSUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA = prove
+ (`!d:(real^M->bool)->real^N p i.
+        p tagged_partial_division_of i /\
+        (!u v. ~(interval[u,v] = {}) /\ content(interval[u,v]) = &0
+               ==> d(interval[u,v]) = vec 0)
+        ==> vsum p (\(x,k). d k) = vsum (IMAGE SND p) d`,
+  REWRITE_TAC[CONTENT_EQ_0_INTERIOR] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(\(x:real^M,k:real^M->bool). d k:real^N) = d o SND`
+  SUBST1_TAC THENL [SIMP_TAC[FUN_EQ_THM; FORALL_PAIR_THM; o_THM]; ALL_TAC] THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_IMAGE_NONZERO THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [tagged_partial_division_of]) THEN
+  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:real^M` THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `k:real^M->bool` THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `y:real^M` THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `k':real^M->bool` THEN
+  ASM_CASES_TAC `k':real^M->bool = k` THEN
+  ASM_REWRITE_TAC[PAIR_EQ; INTER_ACI] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM MEMBER_NOT_EMPTY]) THEN
+  ASM_MESON_TAC[]);;
+
+let VSUM_OVER_TAGGED_DIVISION_LEMMA = prove
+ (`!d:(real^M->bool)->real^N p i.
+        p tagged_division_of i /\
+        (!u v. ~(interval[u,v] = {}) /\ content(interval[u,v]) = &0
+               ==> d(interval[u,v]) = vec 0)
+        ==> vsum p (\(x,k). d k) = vsum (IMAGE SND p) d`,
+  REWRITE_TAC[tagged_division_of] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC VSUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA THEN
+  EXISTS_TAC `i:real^M->bool` THEN ASM_REWRITE_TAC[]);;
+
+let SUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA = prove
+ (`!d:(real^N->bool)->real p i.
+        p tagged_partial_division_of i /\
+        (!u v. ~(interval[u,v] = {}) /\ content(interval[u,v]) = &0
+               ==> d(interval[u,v]) = &0)
+        ==> sum p (\(x,k). d k) = sum (IMAGE SND p) d`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o CONJUNCT1 o
+    REWRITE_RULE[tagged_partial_division_of]) THEN
+  ONCE_REWRITE_TAC[GSYM LIFT_EQ] THEN
+  ASM_SIMP_TAC[LIFT_SUM; FINITE_IMAGE; o_DEF; LAMBDA_PAIR_THM] THEN
+  MATCH_MP_TAC VSUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA THEN
+  ASM_SIMP_TAC[GSYM DROP_EQ; DROP_VEC; LIFT_DROP] THEN ASM_MESON_TAC[]);;
+
+let SUM_OVER_TAGGED_DIVISION_LEMMA = prove
+ (`!d:(real^N->bool)->real p i.
+        p tagged_division_of i /\
+        (!u v. ~(interval[u,v] = {}) /\ content(interval[u,v]) = &0
+               ==> d(interval[u,v]) = &0)
+        ==> sum p (\(x,k). d k) = sum (IMAGE SND p) d`,
+  REWRITE_TAC[tagged_division_of] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA THEN
+  EXISTS_TAC `i:real^N->bool` THEN ASM_REWRITE_TAC[]);;
+
+let TAG_IN_INTERVAL = prove
+ (`!p i k. p tagged_division_of i /\ (x,k) IN p ==> x IN i`,
+  REWRITE_TAC[TAGGED_DIVISION_OF] THEN SET_TAC[]);;
+
+let TAGGED_DIVISION_OF_EMPTY = prove
+ (`{} tagged_division_of {}`,
+  REWRITE_TAC[tagged_division_of; tagged_partial_division_of] THEN
+  REWRITE_TAC[FINITE_RULES; EXTENSION; NOT_IN_EMPTY; IN_UNIONS; IN_ELIM_THM]);;
+
+let TAGGED_PARTIAL_DIVISION_OF_TRIVIAL = prove
+ (`!p. p tagged_partial_division_of {} <=> p = {}`,
+  REWRITE_TAC[tagged_partial_division_of; SUBSET_EMPTY; CONJ_ASSOC] THEN
+  REWRITE_TAC[SET_RULE `x IN k /\ k = {} <=> F`] THEN
+  REWRITE_TAC[GSYM FORALL_PAIR_THM; GSYM NOT_EXISTS_THM; MEMBER_NOT_EMPTY] THEN
+  REWRITE_TAC[AC CONJ_ACI `(a /\ b) /\ c <=> b /\ a /\ c`] THEN
+  GEN_TAC THEN MATCH_MP_TAC(TAUT `(a ==> b) ==> (a /\ b <=> a)`) THEN
+  DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[FINITE_RULES; UNIONS_0; NOT_IN_EMPTY]);;
+
+let TAGGED_DIVISION_OF_TRIVIAL = prove
+ (`!p. p tagged_division_of {} <=> p = {}`,
+  REWRITE_TAC[tagged_division_of; TAGGED_PARTIAL_DIVISION_OF_TRIVIAL] THEN
+  GEN_TAC THEN MATCH_MP_TAC(TAUT `(a ==> b) ==> (a /\ b <=> a)`) THEN
+  DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[NOT_IN_EMPTY] THEN SET_TAC[]);;
+
+let TAGGED_DIVISION_OF_SELF = prove
+ (`!x a b. x IN interval[a,b]
+           ==> {(x,interval[a,b])} tagged_division_of interval[a,b]`,
+  REWRITE_TAC[TAGGED_DIVISION_OF; FINITE_INSERT; FINITE_RULES; IN_SING] THEN
+  REWRITE_TAC[FORALL_PAIR_THM; PAIR_EQ] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[SUBSET_REFL; UNWIND_THM2; SET_RULE `{k | k = a} = {a}`] THEN
+  REWRITE_TAC[UNIONS_1] THEN ASM_MESON_TAC[]);;
+
+let TAGGED_DIVISION_UNION = prove
+ (`!s1 s2:real^N->bool p1 p2.
+        p1 tagged_division_of s1 /\
+        p2 tagged_division_of s2 /\
+        interior s1 INTER interior s2 = {}
+        ==> (p1 UNION p2) tagged_division_of (s1 UNION s2)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[TAGGED_DIVISION_OF] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[FINITE_UNION; IN_UNION; EXISTS_OR_THM; SET_RULE
+   `UNIONS {x | P x \/ Q x} = UNIONS {x | P x} UNION UNIONS {x | Q x}`] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  REPEAT STRIP_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC;
+    ONCE_REWRITE_TAC[INTER_COMM]; ASM_MESON_TAC[]] THEN
+  MATCH_MP_TAC(SET_RULE
+   `!s' t'. s SUBSET s' /\ t SUBSET t' /\ s' INTER t' = {}
+            ==> s INTER t = {}`) THEN
+  MAP_EVERY EXISTS_TAC
+   [`interior s1:real^N->bool`; `interior s2:real^N->bool`] THEN
+  ASM_SIMP_TAC[] THEN CONJ_TAC THEN MATCH_MP_TAC SUBSET_INTERIOR THEN
+  ASM_MESON_TAC[]);;
+
+let TAGGED_DIVISION_UNIONS = prove
+ (`!iset pfn. FINITE iset /\
+              (!i:real^M->bool. i IN iset ==> pfn(i) tagged_division_of i) /\
+              (!i1 i2. i1 IN iset /\ i2 IN iset /\ ~(i1 = i2)
+                       ==> (interior(i1) INTER interior(i2) = {}))
+              ==> UNIONS(IMAGE pfn iset) tagged_division_of (UNIONS iset)`,
+  let lemma1 = prove
+    (`(?t. (?x. (t = f x) /\ P x) /\ Q t) <=> ?x. P x /\ Q(f x)`,
+     MESON_TAC[])
+  and lemma2 = prove
+   (`!s1 t1 s2 t2. s1 SUBSET t1 /\ s2 SUBSET t2 /\ (t1 INTER t2 = {})
+                   ==> (s1 INTER s2 = {})`,
+    SET_TAC[]) in
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[EXTENSION] tagged_division_of] THEN
+  REWRITE_TAC[tagged_partial_division_of; IN_UNIONS; IN_ELIM_THM] THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_UNIONS; IN_IMAGE] THEN
+  SIMP_TAC[FINITE_UNIONS; FINITE_IMAGE; FORALL_IN_IMAGE] THEN
+  STRIP_TAC THEN REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC; ASM_MESON_TAC[]] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[lemma1] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`i1:real^M->bool`; `i2:real^M->bool`] THEN
+  ASM_CASES_TAC `i1 = i2:real^M->bool` THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC lemma2 THEN
+  MAP_EVERY EXISTS_TAC
+   [`interior(i1:real^M->bool)`; `interior(i2:real^M->bool)`] THEN
+  ASM_MESON_TAC[SUBSET; SUBSET_INTERIOR]);;
+
+let TAGGED_PARTIAL_DIVISION_OF_UNION_SELF = prove
+ (`!p s. p tagged_partial_division_of s
+         ==> p tagged_division_of (UNIONS(IMAGE SND p))`,
+  SIMP_TAC[tagged_partial_division_of; TAGGED_DIVISION_OF] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN REPEAT CONJ_TAC THENL
+   [REPEAT STRIP_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+    REWRITE_TAC[SUBSET; IN_UNIONS; IN_IMAGE; EXISTS_PAIR_THM] THEN
+    ASM_MESON_TAC[];
+    ASM_MESON_TAC[];
+    AP_TERM_TAC THEN GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_IMAGE; EXISTS_PAIR_THM] THEN MESON_TAC[]]);;
+
+let TAGGED_DIVISION_OF_UNION_SELF = prove
+ (`!p s. p tagged_division_of s
+         ==> p tagged_division_of (UNIONS(IMAGE SND p))`,
+  SIMP_TAC[TAGGED_DIVISION_OF] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC(TAUT `(c ==> a /\ b) /\ c ==> a /\ b /\ c`) THEN CONJ_TAC THENL
+   [DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_SIMP_TAC[] THEN ASM_MESON_TAC[];
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN AP_TERM_TAC THEN
+    GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_IMAGE; EXISTS_PAIR_THM] THEN MESON_TAC[]]);;
+
+let TAGGED_DIVISION_UNION_IMAGE_SND = prove
+ (`!p s. p tagged_division_of s ==> s = UNIONS(IMAGE SND p)`,
+  MESON_TAC[TAGGED_PARTIAL_DIVISION_OF_UNION_SELF; tagged_division_of]);;
+
+let TAGGED_DIVISION_OF_ALT = prove
+ (`!p s. p tagged_division_of s <=>
+         p tagged_partial_division_of s /\
+         (!x. x IN s ==> ?t k. (t,k) IN p /\ x IN k)`,
+  REWRITE_TAC[tagged_division_of; GSYM SUBSET_ANTISYM_EQ] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_UNIONS; IN_ELIM_THM] THEN
+  REWRITE_TAC[IN_UNIONS; EXISTS_PAIR_THM; IN_ELIM_THM] THEN
+  REWRITE_TAC[tagged_partial_division_of; SUBSET] THEN MESON_TAC[]);;
+
+let TAGGED_DIVISION_OF_ANOTHER = prove
+ (`!p s s'.
+        p tagged_partial_division_of s' /\
+        (!t k. (t,k) IN p ==> k SUBSET s) /\
+        (!x. x IN s ==> ?t k. (t,k) IN p /\ x IN k)
+        ==> p tagged_division_of s`,
+  REWRITE_TAC[TAGGED_DIVISION_OF_ALT; tagged_partial_division_of] THEN
+  SET_TAC[]);;
+
+let TAGGED_PARTIAL_DIVISION_OF_SUBSET = prove
+ (`!p s t. p tagged_partial_division_of s /\ s SUBSET t
+           ==> p tagged_partial_division_of t`,
+  REWRITE_TAC[tagged_partial_division_of] THEN SET_TAC[]);;
+
+let TAGGED_DIVISION_OF_NONTRIVIAL = prove
+ (`!s a b:real^N.
+        s tagged_division_of interval[a,b] /\ ~(content(interval[a,b]) = &0)
+        ==> {(x,k) | (x,k) IN s /\ ~(content k = &0)}
+            tagged_division_of interval[a,b]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[TAGGED_DIVISION_OF_ALT] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC TAGGED_PARTIAL_DIVISION_SUBSET THEN
+    EXISTS_TAC `s:(real^N#(real^N->bool))->bool` THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[tagged_division_of]) THEN
+    ASM_REWRITE_TAC[] THEN SET_TAC[];
+    FIRST_ASSUM(MP_TAC o MATCH_MP DIVISION_OF_TAGGED_DIVISION) THEN
+    DISCH_THEN(MP_TAC o
+     MATCH_MP(REWRITE_RULE[IMP_CONJ] DIVISION_OF_NONTRIVIAL)) THEN
+    ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[division_of] THEN DISCH_THEN(MP_TAC o last o CONJUNCTS) THEN
+    REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ; SUBSET; IN_ELIM_PAIR_THM] THEN
+    REWRITE_TAC[IN_UNIONS; EXISTS_IN_IMAGE; EXISTS_PAIR_THM; IN_ELIM_THM;
+                GSYM CONJ_ASSOC] THEN
+    MESON_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Fine-ness of a partition w.r.t. a gauge.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("fine",(12,"right"));;
+
+let fine = new_definition
+  `d fine s <=> !x k. (x,k) IN s ==> k SUBSET d(x)`;;
+
+let FINE_INTER = prove
+ (`!p d1 d2. (\x. d1(x) INTER d2(x)) fine p <=> d1 fine p /\ d2 fine p`,
+  let lemma = prove
+   (`s SUBSET (t INTER u) <=> s SUBSET t /\ s SUBSET u`,SET_TAC[]) in
+  REWRITE_TAC[fine; IN_INTER; lemma] THEN MESON_TAC[]);;
+
+let FINE_INTERS = prove
+ (`!f s p. (\x. INTERS {f d x | d IN s}) fine p <=>
+           !d. d IN s ==> (f d) fine p`,
+  REWRITE_TAC[fine; SET_RULE `s SUBSET INTERS u <=> !t. t IN u ==> s SUBSET t`;
+              IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let FINE_UNION = prove
+ (`!d p1 p2. d fine p1 /\ d fine p2 ==> d fine (p1 UNION p2)`,
+  REWRITE_TAC[fine; IN_UNION] THEN MESON_TAC[]);;
+
+let FINE_UNIONS = prove
+ (`!d ps. (!p. p IN ps ==> d fine p) ==> d fine (UNIONS ps)`,
+  REWRITE_TAC[fine; IN_UNIONS] THEN MESON_TAC[]);;
+
+let FINE_SUBSET = prove
+ (`!d p q. p SUBSET q /\ d fine q ==> d fine p`,
+  REWRITE_TAC[fine; SUBSET] THEN MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Gauge integral. Define on compact intervals first, then use a limit.      *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("has_integral_compact_interval",(12,"right"));;
+parse_as_infix("has_integral",(12,"right"));;
+parse_as_infix("integrable_on",(12,"right"));;
+
+let has_integral_compact_interval = new_definition
+  `(f has_integral_compact_interval y) i <=>
+        !e. &0 < e
+            ==> ?d. gauge d /\
+                    !p. p tagged_division_of i /\ d fine p
+                        ==> norm(vsum p (\(x,k). content(k) % f(x)) - y) < e`;;
+
+let has_integral_def = new_definition
+  `(f has_integral y) i <=>
+        if ?a b. i = interval[a,b] then (f has_integral_compact_interval y) i
+        else !e. &0 < e
+                 ==> ?B. &0 < B /\
+                         !a b. ball(vec 0,B) SUBSET interval[a,b]
+                               ==> ?z. ((\x. if x IN i then f(x) else vec 0)
+                                        has_integral_compact_interval z)
+                                        (interval[a,b]) /\
+                                       norm(z - y) < e`;;
+
+let has_integral = prove
+ (`(f has_integral y) (interval[a,b]) <=>
+        !e. &0 < e
+            ==> ?d. gauge d /\
+                    !p. p tagged_division_of interval[a,b] /\ d fine p
+                        ==> norm(vsum p (\(x,k). content(k) % f(x)) - y) < e`,
+  REWRITE_TAC[has_integral_def; has_integral_compact_interval] THEN
+  MESON_TAC[]);;
+
+let has_integral_alt = prove
+ (`(f has_integral y) i <=>
+        if ?a b. i = interval[a,b] then (f has_integral y) i
+        else !e. &0 < e
+                 ==> ?B. &0 < B /\
+                         !a b. ball(vec 0,B) SUBSET interval[a,b]
+                               ==> ?z. ((\x. if x IN i then f(x) else vec 0)
+                                        has_integral z) (interval[a,b]) /\
+                                       norm(z - y) < e`,
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [has_integral_def] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [POP_ASSUM(REPEAT_TCL CHOOSE_THEN SUBST1_TAC); ALL_TAC] THEN
+  REWRITE_TAC[has_integral_compact_interval; has_integral]);;
+
+let integrable_on = new_definition
+ `f integrable_on i <=> ?y. (f has_integral y) i`;;
+
+let integral = new_definition
+ `integral i f = @y. (f has_integral y) i`;;
+
+let INTEGRABLE_INTEGRAL = prove
+ (`!f i. f integrable_on i ==> (f has_integral (integral i f)) i`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[integrable_on; integral] THEN
+  CONV_TAC(RAND_CONV SELECT_CONV) THEN REWRITE_TAC[]);;
+
+let HAS_INTEGRAL_INTEGRABLE = prove
+ (`!f i s. (f has_integral i) s ==> f integrable_on s`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[]);;
+
+let HAS_INTEGRAL_INTEGRAL = prove
+ (`!f s. f integrable_on s <=> (f has_integral (integral s f)) s`,
+  MESON_TAC[INTEGRABLE_INTEGRAL; HAS_INTEGRAL_INTEGRABLE]);;
+
+let VSUM_CONTENT_NULL = prove
+ (`!f:real^M->real^N a b p.
+        content(interval[a,b]) = &0 /\
+        p tagged_division_of interval[a,b]
+        ==> vsum p (\(x,k). content k % f x) = vec 0`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC VSUM_EQ_0 THEN
+  REWRITE_TAC[FORALL_PAIR_THM] THEN
+  MAP_EVERY X_GEN_TAC [`p:real^M`; `k:real^M->bool`] THEN
+  DISCH_TAC THEN REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISJ1_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+  DISCH_THEN(MP_TAC o CONJUNCT1 o CONJUNCT2) THEN
+  DISCH_THEN(MP_TAC o SPECL [`p:real^M`; `k:real^M->bool`]) THEN
+  ASM_MESON_TAC[CONTENT_SUBSET; CONTENT_POS_LE; REAL_ARITH
+   `&0 <= x /\ x <= y /\ y = &0 ==> x = &0`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some basic combining lemmas.                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let TAGGED_DIVISION_UNIONS_EXISTS = prove
+ (`!d iset i:real^M->bool.
+        FINITE iset /\
+        (!i. i IN iset ==> ?p. p tagged_division_of i /\ d fine p) /\
+        (!i1 i2. i1 IN iset /\ i2 IN iset /\ ~(i1 = i2)
+                 ==> (interior(i1) INTER interior(i2) = {})) /\
+        (UNIONS iset = i)
+        ==> ?p. p tagged_division_of i /\ d fine p`,
+  REPEAT GEN_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+  EXISTS_TAC `UNIONS (IMAGE(p:(real^M->bool)->((real^M#(real^M->bool))->bool))
+                      iset)` THEN
+  ASM_SIMP_TAC[TAGGED_DIVISION_UNIONS] THEN
+  ASM_MESON_TAC[FINE_UNIONS; IN_IMAGE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The set we're concerned with must be closed.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let DIVISION_OF_CLOSED = prove
+ (`!s i. s division_of i ==> closed i`,
+  REWRITE_TAC[division_of] THEN MESON_TAC[CLOSED_UNIONS; CLOSED_INTERVAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* General bisection principle for intervals; might be useful elsewhere.     *)
+(* ------------------------------------------------------------------------- *)
+
+let INTERVAL_BISECTION_STEP = prove
+ (`!P. P {} /\
+       (!s t. P s /\ P t /\ interior(s) INTER interior(t) = {}
+              ==> P(s UNION t))
+       ==> !a b:real^N.
+                ~(P(interval[a,b]))
+                ==> ?c d. ~(P(interval[c,d])) /\
+                          !i. 1 <= i /\ i <= dimindex(:N)
+                              ==> a$i <= c$i /\ c$i <= d$i /\ d$i <= b$i /\
+                                  &2 * (d$i - c$i) <= b$i - a$i`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `!i. 1 <= i /\ i <= dimindex(:N)
+                     ==> (a:real^N)$i <= (b:real^N)$i` THENL
+   [ALL_TAC;
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM INTERVAL_NE_EMPTY]) THEN
+    ASM_REWRITE_TAC[]] THEN
+  SUBGOAL_THEN
+   `!f. FINITE f /\
+        (!s:real^N->bool. s IN f ==> P s) /\
+        (!s:real^N->bool. s IN f ==> ?a b. s = interval[a,b]) /\
+        (!s t. s IN f /\ t IN f /\ ~(s = t)
+               ==> interior(s) INTER interior(t) = {})
+        ==> P(UNIONS f)`
+  ASSUME_TAC THENL
+   [ONCE_REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+    ASM_SIMP_TAC[UNIONS_0; UNIONS_INSERT; NOT_IN_EMPTY; FORALL_IN_INSERT] THEN
+    REWRITE_TAC[IMP_IMP] THEN REPEAT GEN_TAC THEN DISCH_THEN(fun th ->
+      FIRST_X_ASSUM MATCH_MP_TAC THEN STRIP_ASSUME_TAC th) THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC INTER_INTERIOR_UNIONS_INTERVALS THEN
+    ASM_REWRITE_TAC[OPEN_INTERIOR] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[IN_INSERT] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC
+   `{ interval[c,d] |
+      !i. 1 <= i /\ i <= dimindex(:N)
+          ==> ((c:real^N)$i = (a:real^N)$i) /\ (d$i = (a$i + b$i) / &2) \/
+              (c$i = (a$i + b$i) / &2) /\ ((d:real^N)$i = (b:real^N)$i)}`) THEN
+  ONCE_REWRITE_TAC[IMP_CONJ] THEN ANTS_TAC THENL
+   [MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC
+     `IMAGE (\s. closed_interval
+       [(lambda i. if i IN s then (a:real^N)$i else (a$i + b$i) / &2):real^N,
+        (lambda i. if i IN s then (a$i + b$i) / &2 else (b:real^N)$i)])
+         {s | s SUBSET (1..dimindex(:N))}` THEN
+    CONJ_TAC THENL
+     [SIMP_TAC[FINITE_POWERSET; FINITE_IMAGE; FINITE_NUMSEG]; ALL_TAC] THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_IMAGE] THEN
+    X_GEN_TAC `k:real^N->bool` THEN
+    DISCH_THEN(X_CHOOSE_THEN `c:real^N` (X_CHOOSE_THEN `d:real^N`
+      (CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC))) THEN
+    EXISTS_TAC `{i | 1 <= i /\ i <= dimindex(:N) /\
+                     ((c:real^N)$i = (a:real^N)$i)}` THEN
+    CONJ_TAC THENL [ALL_TAC; SIMP_TAC[IN_ELIM_THM; IN_NUMSEG]] THEN
+    AP_TERM_TAC THEN REWRITE_TAC[CONS_11; PAIR_EQ] THEN
+    SIMP_TAC[CART_EQ; LAMBDA_BETA; IN_ELIM_THM] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o GEN `i:num` o SPEC `i:num`)) THEN
+    REWRITE_TAC[IMP_IMP; AND_FORALL_THM] THEN
+    MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+    REWRITE_TAC[TAUT `(a ==> b) /\ (a ==> c) <=> (a ==> b /\ c)`] THEN
+    MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+    SIMP_TAC[REAL_EQ_RDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM CONTRAPOS_THM] THEN ANTS_TAC THENL
+   [UNDISCH_TAC `~P(interval[a:real^N,b])` THEN MATCH_MP_TAC EQ_IMP THEN
+    AP_TERM_TAC THEN AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN
+    GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_UNIONS; IN_ELIM_THM] THEN X_GEN_TAC `x:real^N` THEN
+    REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN
+    ONCE_REWRITE_TAC[TAUT `(a /\ b) /\ c <=> b /\ a /\ c`] THEN
+    GEN_REWRITE_TAC LAND_CONV [SWAP_EXISTS_THM] THEN
+    GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [SWAP_EXISTS_THM] THEN
+    REWRITE_TAC[UNWIND_THM2; IN_INTERVAL] THEN
+    REWRITE_TAC[AND_FORALL_THM] THEN
+    REWRITE_TAC[TAUT `(a ==> b) /\ (a ==> c) <=> (a ==> b /\ c)`] THEN
+    REWRITE_TAC[GSYM LAMBDA_SKOLEM] THEN AP_TERM_TAC THEN
+    GEN_REWRITE_TAC I [FUN_EQ_THM] THEN X_GEN_TAC `i:num` THEN
+    REWRITE_TAC[] THEN
+    MATCH_MP_TAC(TAUT `(a ==> (b <=> c)) ==> ((a ==> b) <=> (a ==> c))`) THEN
+    STRIP_TAC THEN
+    ONCE_REWRITE_TAC[TAUT `(a \/ b) /\ c <=> ~(a ==> ~c) \/ ~(b ==> ~c)`] THEN
+    SIMP_TAC[] THEN
+    REWRITE_TAC[TAUT `~(a ==> ~b) <=> a /\ b`; GSYM CONJ_ASSOC] THEN
+    REWRITE_TAC[EXISTS_OR_THM; RIGHT_EXISTS_AND_THM] THEN
+    REWRITE_TAC[LEFT_EXISTS_AND_THM; EXISTS_REFL] THEN
+    SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN
+  MATCH_MP_TAC(TAUT `b /\ (~a ==> e) /\ c ==> ~(a /\ b /\ c) ==> e`) THEN
+  CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN CONJ_TAC THENL
+   [REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+    DISCH_THEN(fun th -> REPEAT DISCH_TAC THEN MP_TAC th) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[IMP_IMP; INTERIOR_CLOSED_INTERVAL] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`c1:real^N`; `d1:real^N`; `c2:real^N`; `d2:real^N`] THEN
+  ASM_CASES_TAC `(c1 = c2:real^N) /\ (d1 = d2:real^N)` THENL
+   [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(fun th ->
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (K ALL_TAC)) THEN MP_TAC th) THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  UNDISCH_TAC `~((c1 = c2:real^N) /\ (d1 = d2:real^N))` THEN
+  REWRITE_TAC[CART_EQ; INTERIOR_CLOSED_INTERVAL] THEN
+  REWRITE_TAC[AND_FORALL_THM] THEN
+  REWRITE_TAC[TAUT `(a ==> b) /\ (a ==> c) <=> (a ==> b /\ c)`] THEN
+  REWRITE_TAC[NOT_FORALL_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `j:num` (fun th ->
+    DISCH_THEN(MP_TAC o SPEC `j:num`) THEN MP_TAC th)) THEN
+  REWRITE_TAC[NOT_IMP] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  ASM_REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[EXTENSION; IN_INTERVAL; NOT_IN_EMPTY; IN_INTER] THEN
+  SIMP_TAC[REAL_EQ_RDIV_EQ; REAL_EQ_LDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN
+  REWRITE_TAC[
+    REAL_ARITH `~((a * &2 = a + b) /\ (a + b = b * &2)) <=> ~(a = b)`;
+    REAL_ARITH `~((a + b = a * &2) /\ (b * &2 = a + b)) <=> ~(a = b)`] THEN
+  DISCH_THEN(fun th -> X_GEN_TAC `x:real^N` THEN MP_TAC th) THEN
+  REWRITE_TAC[AND_FORALL_THM] THEN
+  REWRITE_TAC[TAUT `(a ==> b) /\ (a ==> c) <=> (a ==> b /\ c)`] THEN
+  ASM_REWRITE_TAC[CONTRAPOS_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `j:num`) THEN ASM_REWRITE_TAC[] THEN
+  REAL_ARITH_TAC);;
+
+let INTERVAL_BISECTION = prove
+ (`!P. P {} /\
+       (!s t. P s /\ P t /\ interior(s) INTER interior(t) = {}
+              ==> P(s UNION t))
+       ==> !a b:real^N.
+                ~(P(interval[a,b]))
+                ==> ?x. x IN interval[a,b] /\
+                        !e. &0 < e
+                            ==> ?c d. x IN interval[c,d] /\
+                                      interval[c,d] SUBSET ball(x,e) /\
+                                      interval[c,d] SUBSET interval[a,b] /\
+                                      ~P(interval[c,d])`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?A B. (A(0) = a:real^N) /\ (B(0) = b) /\
+          !n. ~(P(interval[A(SUC n),B(SUC n)])) /\
+              !i. 1 <= i /\ i <= dimindex(:N)
+                       ==> A(n)$i <= A(SUC n)$i /\
+                           A(SUC n)$i <= B(SUC n)$i /\
+                           B(SUC n)$i <= B(n)$i /\
+                           &2 * (B(SUC n)$i - A(SUC n)$i) <= B(n)$i - A(n)$i`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPEC `P:(real^N->bool)->bool` INTERVAL_BISECTION_STEP) THEN
+    ASM_REWRITE_TAC[] THEN
+    GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[SKOLEM_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `C:real^N->real^N->real^N`
+     (X_CHOOSE_THEN `D:real^N->real^N->real^N` ASSUME_TAC)) THEN
+    MP_TAC(prove_recursive_functions_exist num_RECURSION
+     `(E 0 = a:real^N,b:real^N) /\
+      (!n. E(SUC n) = C (FST(E n)) (SND(E n)),
+                      D (FST(E n)) (SND(E n)))`) THEN
+    DISCH_THEN(X_CHOOSE_THEN `E:num->real^N#real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\n. FST((E:num->real^N#real^N) n)` THEN
+    EXISTS_TAC `\n. SND((E:num->real^N#real^N) n)` THEN
+    ASM_REWRITE_TAC[] THEN INDUCT_TAC THEN ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!e. &0 < e
+        ==> ?n:num. !x y. x IN interval[A(n),B(n)] /\ y IN interval[A(n),B(n)]
+                          ==> dist(x,y:real^N) < e`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `e:real` THEN DISCH_TAC THEN MP_TAC(SPEC
+     `sum(1..dimindex(:N)) (\i. (b:real^N)$i - (a:real^N)$i) / e`
+     REAL_ARCH_POW2) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `sum(1..dimindex(:N))(\i. abs((x - y:real^N)$i))` THEN
+    REWRITE_TAC[dist; NORM_LE_L1] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `sum(1..dimindex(:N))
+                   (\i. (B:num->real^N)(n)$i - (A:num->real^N)(n)$i)` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC SUM_LE_NUMSEG THEN SIMP_TAC[VECTOR_SUB_COMPONENT] THEN
+      REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH `a <= x /\ x <= b /\ a <= y /\ y <= b
+                               ==> abs(x - y) <= b - a`) THEN
+      UNDISCH_TAC `x IN interval[(A:num->real^N) n,B n]` THEN
+      UNDISCH_TAC `y IN interval[(A:num->real^N) n,B n]` THEN
+      REWRITE_TAC[IN_INTERVAL] THEN ASM_SIMP_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC
+     `sum(1..dimindex(:N)) (\i. (b:real^N)$i - (a:real^N)$i) /
+      &2 pow n` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      SIMP_TAC[REAL_LT_LDIV_EQ; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+      ASM_SIMP_TAC[GSYM REAL_LT_LDIV_EQ]] THEN
+    REWRITE_TAC[real_div] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    REWRITE_TAC[GSYM SUM_LMUL] THEN MATCH_MP_TAC SUM_LE_NUMSEG THEN
+    X_GEN_TAC `j:num` THEN STRIP_TAC THEN REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM real_div] THEN
+    SPEC_TAC(`n:num`,`m:num`) THEN INDUCT_TAC THEN
+    ASM_REWRITE_TAC[real_pow; REAL_DIV_1; REAL_LE_REFL] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    REWRITE_TAC[real_div; REAL_INV_MUL; REAL_MUL_ASSOC] THEN
+    SIMP_TAC[GSYM real_div; REAL_LE_RDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN
+    ASM_MESON_TAC[REAL_LE_TRANS; REAL_MUL_SYM];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `?a:real^N. !n:num. a IN interval[A(n),B(n)]` MP_TAC THENL
+   [MATCH_MP_TAC DECREASING_CLOSED_NEST THEN
+    ASM_REWRITE_TAC[CLOSED_INTERVAL] THEN CONJ_TAC THENL
+     [REWRITE_TAC[INTERVAL_EQ_EMPTY] THEN
+      ASM_MESON_TAC[REAL_NOT_LT; REAL_LE_TRANS];
+      ALL_TAC] THEN
+    REWRITE_TAC[LE_EXISTS] THEN SIMP_TAC[LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `m:num` THEN ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+    REWRITE_TAC[GSYM LEFT_IMP_EXISTS_THM; EXISTS_REFL] THEN
+    INDUCT_TAC THEN REWRITE_TAC[ADD_CLAUSES; SUBSET_REFL] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `interval[A(m + d:num):real^N,B(m + d)]` THEN
+    ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[SUBSET; IN_INTERVAL] THEN ASM_MESON_TAC[REAL_LE_TRANS];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x0:real^N` THEN
+  DISCH_TAC THEN CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_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_TAC `n:num`) THEN
+  MAP_EVERY EXISTS_TAC [`(A:num->real^N) n`; `(B:num->real^N) n`] THEN
+  ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; IN_BALL] THEN ASM_MESON_TAC[];
+    ALL_TAC;
+    SPEC_TAC(`n:num`,`p:num`) THEN INDUCT_TAC THEN ASM_REWRITE_TAC[]] THEN
+  SUBGOAL_THEN
+   `!m n. m <= n ==> interval[(A:num->real^N) n,B n] SUBSET interval[A m,B m]`
+   (fun th -> ASM_MESON_TAC[SUBSET; LE_0; th]) THEN
+  MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN
+  REPEAT(CONJ_TAC THENL [SET_TAC[]; ALL_TAC]) THEN
+  REWRITE_TAC[SUBSET_INTERVAL] THEN ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Cousin's lemma.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let FINE_DIVISION_EXISTS = prove
+ (`!g a b:real^M.
+        gauge g ==> ?p. p tagged_division_of (interval[a,b]) /\ g fine p`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `\s:real^M->bool. ?p. p tagged_division_of s /\ g fine p`
+        INTERVAL_BISECTION) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [MESON_TAC[TAGGED_DIVISION_UNION; FINE_UNION;
+              TAGGED_DIVISION_OF_EMPTY; fine; NOT_IN_EMPTY];
+    DISCH_THEN(MP_TAC o SPECL [`a:real^M`; `b:real^M`])] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM CONTRAPOS_THM] THEN
+  REWRITE_TAC[] THEN DISCH_THEN MATCH_MP_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `x:real^M` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  FIRST_ASSUM(MP_TAC o SPEC `x:real^M` o REWRITE_RULE[gauge]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[OPEN_CONTAINS_BALL; NOT_FORALL_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`c:real^M`; `d:real^M`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `{(x:real^M,interval[c:real^M,d])}`) THEN
+  ASM_SIMP_TAC[TAGGED_DIVISION_OF_SELF] THEN
+  REWRITE_TAC[fine; IN_SING; PAIR_EQ] THEN ASM_MESON_TAC[SUBSET_TRANS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic theorems about integrals.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_UNIQUE = prove
+ (`!f:real^M->real^N i k1 k2.
+        (f has_integral k1) i /\ (f has_integral k2) i ==> k1 = k2`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN
+   `!f:real^M->real^N a b k1 k2.
+       (f has_integral k1) (interval[a,b]) /\
+       (f has_integral k2) (interval[a,b])
+       ==> k1 = k2`
+  MP_TAC THENL
+   [REPEAT GEN_TAC THEN REWRITE_TAC[has_integral] THEN
+    REWRITE_TAC[AND_FORALL_THM] THEN
+    REWRITE_TAC[TAUT `(a ==> b) /\ (a ==> c) <=> a ==> b /\ c`] THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+    REWRITE_TAC[GSYM NORM_POS_LT] THEN DISCH_TAC THEN
+    DISCH_THEN(MP_TAC o SPEC `norm(k1 - k2 :real^N) / &2`) THEN
+    ASM_REWRITE_TAC[REAL_HALF] THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `d1:real^M->real^M->bool` STRIP_ASSUME_TAC)
+     (X_CHOOSE_THEN `d2:real^M->real^M->bool` STRIP_ASSUME_TAC)) THEN
+    MP_TAC(ISPEC `\x. ((d1:real^M->real^M->bool) x) INTER (d2 x)`
+                 FINE_DIVISION_EXISTS) THEN
+    ASM_SIMP_TAC[GAUGE_INTER] THEN
+    DISCH_THEN(MP_TAC o SPECL [`a:real^M`; `b:real^M`]) THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o check (is_forall o concl))) THEN
+    REWRITE_TAC[] THEN REWRITE_TAC[IMP_IMP; NOT_EXISTS_THM] THEN
+    REWRITE_TAC[AND_FORALL_THM] THEN MATCH_MP_TAC MONO_FORALL THEN
+    GEN_TAC THEN
+    MATCH_MP_TAC(TAUT
+     `(f0 ==> f1 /\ f2) /\ ~(n1 /\ n2)
+      ==> (t /\ f1 ==> n1) /\ (t /\ f2 ==> n2) ==> ~(t /\ f0)`) THEN
+    CONJ_TAC THENL [SIMP_TAC[fine; SUBSET_INTER]; ALL_TAC] THEN
+    MATCH_MP_TAC(REAL_ARITH `c <= a + b ==> ~(a < c / &2 /\ b < c / &2)`) THEN
+    MESON_TAC[NORM_SUB; NORM_TRIANGLE; VECTOR_ARITH
+     `k1 - k2:real^N = (k1 - x) + (x - k2)`];
+    ALL_TAC] THEN
+  DISCH_TAC THEN ONCE_REWRITE_TAC[has_integral_alt] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_TAC THEN MATCH_MP_TAC(NORM_ARITH
+   `~(&0 < norm(x - y)) ==> x = y`) THEN
+  DISCH_TAC THEN
+  FIRST_X_ASSUM(CONJUNCTS_THEN (MP_TAC o SPEC `norm(k1 - k2:real^N) / &2`)) THEN
+  ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B1:real` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B2:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPEC
+   `ball(vec 0,B1) UNION ball(vec 0:real^M,B2)`
+   BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+  REWRITE_TAC[BOUNDED_UNION; BOUNDED_BALL; UNION_SUBSET; NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN
+  DISCH_THEN(CONJUNCTS_THEN(ANTE_RES_THEN MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `w:real^N` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `w:real^N = z:real^N` SUBST_ALL_TAC THEN
+  ASM_MESON_TAC[NORM_ARITH
+   `~(norm(z - k1) < norm(k1 - k2) / &2 /\
+      norm(z - k2) < norm(k1 - k2) / &2)`]);;
+
+let INTEGRAL_UNIQUE = prove
+ (`!f y k.
+      (f has_integral y) k ==> integral k f = y`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[integral] THEN
+  MATCH_MP_TAC SELECT_UNIQUE THEN ASM_MESON_TAC[HAS_INTEGRAL_UNIQUE]);;
+
+let HAS_INTEGRAL_INTEGRABLE_INTEGRAL = prove
+ (`!f:real^M->real^N i s.
+        (f has_integral i) s <=> f integrable_on s /\ integral s f = i`,
+  MESON_TAC[INTEGRABLE_INTEGRAL; INTEGRAL_UNIQUE; integrable_on]);;
+
+let INTEGRAL_EQ_HAS_INTEGRAL = prove
+ (`!s f y. f integrable_on s ==> (integral s f = y <=> (f has_integral y) s)`,
+  MESON_TAC[INTEGRABLE_INTEGRAL; INTEGRAL_UNIQUE]);;
+
+let HAS_INTEGRAL_IS_0 = prove
+ (`!f:real^M->real^N s.
+        (!x. x IN s ==> (f(x) = vec 0)) ==> (f has_integral vec 0) s`,
+  SUBGOAL_THEN
+   `!f:real^M->real^N a b.
+        (!x. x IN interval[a,b] ==> (f(x) = vec 0))
+        ==> (f has_integral vec 0) (interval[a,b])`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[has_integral] THEN
+    REPEAT STRIP_TAC THEN EXISTS_TAC `\x:real^M. ball(x,&1)` THEN
+    SIMP_TAC[gauge; OPEN_BALL; CENTRE_IN_BALL; REAL_LT_01] THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_SUB_RZERO] THEN
+    UNDISCH_TAC `&0 < e` THEN MATCH_MP_TAC(TAUT `(a <=> b) ==> b ==> a`) THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN
+    REWRITE_TAC[NORM_EQ_0; VECTOR_SUB_EQ; VECTOR_ADD_LID] THEN
+    MATCH_MP_TAC VSUM_EQ_0 THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+    CONV_TAC(ONCE_DEPTH_CONV GEN_BETA_CONV) THEN
+    X_GEN_TAC `x:real^M` THEN REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `(x:real^M) IN interval[a,b]`
+     (fun th -> ASM_SIMP_TAC[th; VECTOR_MUL_RZERO]) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [tagged_division_of]) THEN
+    REWRITE_TAC[tagged_partial_division_of; SUBSET] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[has_integral_alt] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  GEN_TAC THEN DISCH_TAC THEN EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN
+  REPEAT STRIP_TAC THEN EXISTS_TAC `vec 0:real^N` THEN
+  ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[]);;
+
+let HAS_INTEGRAL_0 = prove
+ (`!s. ((\x. vec 0) has_integral vec 0) s`,
+  SIMP_TAC[HAS_INTEGRAL_IS_0]);;
+
+let HAS_INTEGRAL_0_EQ = prove
+ (`!i s. ((\x. vec 0) has_integral i) s <=> i = vec 0`,
+  MESON_TAC[HAS_INTEGRAL_UNIQUE; HAS_INTEGRAL_0]);;
+
+let HAS_INTEGRAL_LINEAR = prove
+ (`!f:real^M->real^N y s h:real^N->real^P.
+        (f has_integral y) s /\ linear h ==> ((h o f) has_integral h(y)) s`,
+  SUBGOAL_THEN
+    `!f:real^M->real^N y a b h:real^N->real^P.
+          (f has_integral y) (interval[a,b]) /\ linear h
+          ==> ((h o f) has_integral h(y)) (interval[a,b])`
+  MP_TAC THENL
+   [REPEAT GEN_TAC THEN REWRITE_TAC[has_integral] THEN STRIP_TAC THEN
+    FIRST_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
+    FIRST_X_ASSUM(MP_TAC o SPEC `e:real / B`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+    STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+    X_GEN_TAC `p:real^M#(real^M->bool)->bool` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `p:real^M#(real^M->bool)->bool`) THEN
+    ASM_SIMP_TAC[REAL_LT_RDIV_EQ] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= y ==> y < e ==> x < e`) THEN
+    FIRST_ASSUM(fun th -> W(fun (asl,w) ->
+      MP_TAC(PART_MATCH rand th (rand w)))) THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= y ==> y <= e ==> x <= e`) THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+    ASM_SIMP_TAC[LINEAR_SUB; LINEAR_VSUM; o_DEF; LAMBDA_PAIR_THM;
+                 LINEAR_CMUL; REAL_LE_REFL];
+    ALL_TAC] THEN
+  DISCH_TAC THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  ONCE_REWRITE_TAC[has_integral_alt] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_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:real`) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `M:real` THEN
+  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(h:real^N->real^P) z` THEN
+  SUBGOAL_THEN
+   `(\x. if x IN s then ((h:real^N->real^P) o (f:real^M->real^N)) x else vec 0)
+    = h o (\x. if x IN s then f x else vec 0)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[FUN_EQ_THM; o_THM] THEN ASM_MESON_TAC[LINEAR_0]; ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM LINEAR_SUB] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `B * norm(z - y:real^N)` THEN
+  ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ]);;
+
+let HAS_INTEGRAL_CMUL = prove
+ (`!(f:real^M->real^N) k s c.
+        (f has_integral k) s
+        ==> ((\x. c % f(x)) has_integral (c % k)) s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC
+   (REWRITE_RULE[o_DEF] HAS_INTEGRAL_LINEAR) THEN
+  ASM_REWRITE_TAC[linear] THEN CONJ_TAC THEN VECTOR_ARITH_TAC);;
+
+let HAS_INTEGRAL_NEG = prove
+ (`!f k s. (f has_integral k) s ==> ((\x. --(f x)) has_integral (--k)) s`,
+  ONCE_REWRITE_TAC[VECTOR_NEG_MINUS1] THEN REWRITE_TAC[HAS_INTEGRAL_CMUL]);;
+
+let HAS_INTEGRAL_ADD = prove
+ (`!f:real^M->real^N g s.
+        (f has_integral k) s /\ (g has_integral l) s
+        ==> ((\x. f(x) + g(x)) has_integral (k + l)) s`,
+  SUBGOAL_THEN
+   `!f:real^M->real^N g k l a b.
+        (f has_integral k) (interval[a,b]) /\
+        (g has_integral l) (interval[a,b])
+        ==> ((\x. f(x) + g(x)) has_integral (k + l)) (interval[a,b])`
+  ASSUME_TAC THENL
+   [REPEAT GEN_TAC THEN REWRITE_TAC[has_integral; 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(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `d1:real^M->real^M->bool` STRIP_ASSUME_TAC)
+     (X_CHOOSE_THEN `d2:real^M->real^M->bool` STRIP_ASSUME_TAC)) THEN
+    EXISTS_TAC `\x. ((d1:real^M->real^M->bool) x) INTER (d2 x)` THEN
+    ASM_SIMP_TAC[GAUGE_INTER] THEN
+    REWRITE_TAC[tagged_division_of; tagged_partial_division_of] THEN
+    SIMP_TAC[VSUM_ADD; VECTOR_ADD_LDISTRIB; LAMBDA_PAIR] THEN
+    REWRITE_TAC[GSYM LAMBDA_PAIR] THEN
+    REWRITE_TAC[GSYM tagged_partial_division_of] THEN
+    REWRITE_TAC[GSYM tagged_division_of; FINE_INTER] THEN
+    SIMP_TAC[VECTOR_ARITH `(a + b) - (c + d) = (a - c) + (b - d):real^N`] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC NORM_TRIANGLE_LT THEN
+    MATCH_MP_TAC(REAL_ARITH `x < e / &2 /\ y < e / &2 ==> x + y < e`) THEN
+    ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[has_integral_alt] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [ASM_MESON_TAC[]; ALL_TAC] 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_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B1:real` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B2:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `max B1 B2:real` THEN ASM_REWRITE_TAC[REAL_LT_MAX] THEN
+  REWRITE_TAC[BALL_MAX_UNION; UNION_SUBSET] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN
+  DISCH_THEN(CONJUNCTS_THEN(ANTE_RES_THEN MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `w:real^N` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `w + z:real^N` THEN
+  SUBGOAL_THEN
+    `(\x. if x IN s then (f:real^M->real^N) x + g x else vec 0) =
+     (\x. (if x IN s then f x else vec 0) + (if x IN s then g x else vec 0))`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[] THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM REAL_NOT_LE])) THEN
+  NORM_ARITH_TAC);;
+
+let HAS_INTEGRAL_SUB = prove
+ (`!f:real^M->real^N g s.
+        (f has_integral k) s /\ (g has_integral l) s
+        ==> ((\x. f(x) - g(x)) has_integral (k - l)) s`,
+  SIMP_TAC[VECTOR_SUB; HAS_INTEGRAL_NEG; HAS_INTEGRAL_ADD]);;
+
+let INTEGRAL_0 = prove
+ (`!s. integral s (\x. vec 0) = vec 0`,
+  MESON_TAC[INTEGRAL_UNIQUE; HAS_INTEGRAL_0]);;
+
+let INTEGRAL_ADD = prove
+ (`!f:real^M->real^N g k l s.
+        f integrable_on s /\ g integrable_on s
+        ==> integral s (\x. f x + g x) = integral s f + integral s g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_INTEGRAL_ADD THEN ASM_SIMP_TAC[INTEGRABLE_INTEGRAL]);;
+
+let INTEGRAL_CMUL = prove
+ (`!f:real^M->real^N c s.
+        f integrable_on s ==> integral s (\x. c % f(x)) = c % integral s f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_INTEGRAL_CMUL THEN ASM_SIMP_TAC[INTEGRABLE_INTEGRAL]);;
+
+let INTEGRAL_NEG = prove
+ (`!f:real^M->real^N s.
+        f integrable_on s ==> integral s (\x. --f(x)) = --integral s f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_INTEGRAL_NEG THEN ASM_SIMP_TAC[INTEGRABLE_INTEGRAL]);;
+
+let INTEGRAL_SUB = prove
+ (`!f:real^M->real^N g k l s.
+        f integrable_on s /\ g integrable_on s
+        ==> integral s (\x. f x - g x) = integral s f - integral s g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SUB THEN ASM_SIMP_TAC[INTEGRABLE_INTEGRAL]);;
+
+let INTEGRABLE_0 = prove
+ (`!s. (\x. vec 0) integrable_on s`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_0]);;
+
+let INTEGRABLE_ADD = prove
+ (`!f:real^M->real^N g s.
+        f integrable_on s /\ g integrable_on s
+        ==> (\x. f x + g x) integrable_on s`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_ADD]);;
+
+let INTEGRABLE_CMUL = prove
+ (`!f:real^M->real^N c s.
+        f integrable_on s ==> (\x. c % f(x)) integrable_on s`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_CMUL]);;
+
+let INTEGRABLE_NEG = prove
+ (`!f:real^M->real^N s.
+        f integrable_on s ==> (\x. --f(x)) integrable_on s`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_NEG]);;
+
+let INTEGRABLE_SUB = prove
+ (`!f:real^M->real^N g s.
+        f integrable_on s /\ g integrable_on s
+        ==> (\x. f x - g x) integrable_on s`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_SUB]);;
+
+let INTEGRABLE_LINEAR = prove
+ (`!f h s. f integrable_on s /\ linear h ==> (h o f) integrable_on s`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_LINEAR]);;
+
+let INTEGRAL_LINEAR = prove
+ (`!f:real^M->real^N s h:real^N->real^P.
+        f integrable_on s /\ linear h
+        ==> integral s (h o f) = h(integral s f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_UNIQUE THEN
+  MAP_EVERY EXISTS_TAC
+   [`(h:real^N->real^P) o (f:real^M->real^N)`; `s:real^M->bool`] THEN
+  CONJ_TAC THENL [ALL_TAC; MATCH_MP_TAC HAS_INTEGRAL_LINEAR] THEN
+  ASM_SIMP_TAC[GSYM HAS_INTEGRAL_INTEGRAL; INTEGRABLE_LINEAR]);;
+
+let HAS_INTEGRAL_VSUM = prove
+ (`!f:A->real^M->real^N s t.
+        FINITE t /\
+        (!a. a IN t ==> ((f a) has_integral (i a)) s)
+        ==> ((\x. vsum t (\a. f a x)) has_integral (vsum t i)) s`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; HAS_INTEGRAL_0; IN_INSERT] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_ADD THEN
+  ASM_REWRITE_TAC[ETA_AX] THEN CONJ_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[]);;
+
+let INTEGRAL_VSUM = prove
+ (`!f:A->real^M->real^N s t.
+        FINITE t /\
+        (!a. a IN t ==> (f a) integrable_on s)
+        ==> integral s (\x. vsum t (\a. f a x)) =
+                vsum t (\a. integral s (f a))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_INTEGRAL_VSUM THEN ASM_SIMP_TAC[INTEGRABLE_INTEGRAL]);;
+
+let INTEGRABLE_VSUM = prove
+ (`!f:A->real^M->real^N s t.
+        FINITE t /\
+        (!a. a IN t ==> (f a) integrable_on s)
+        ==>  (\x. vsum t (\a. f a x)) integrable_on s`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_VSUM]);;
+
+let HAS_INTEGRAL_EQ = prove
+ (`!f:real^M->real^N g k s.
+        (!x. x IN s ==> (f(x) = g(x))) /\
+        (f has_integral k) s
+        ==> (g has_integral k) s`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (MP_TAC o MATCH_MP HAS_INTEGRAL_IS_0) MP_TAC) THEN
+  REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_SUB) THEN
+  SIMP_TAC[VECTOR_ARITH `x - (x - y:real^N) = y`; ETA_AX; VECTOR_SUB_RZERO]);;
+
+let INTEGRABLE_EQ = prove
+ (`!f:real^M->real^N g s.
+        (!x. x IN s ==> (f(x) = g(x))) /\
+        f integrable_on s
+        ==> g integrable_on s`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_EQ]);;
+
+let HAS_INTEGRAL_EQ_EQ = prove
+ (`!f:real^M->real^N g k s.
+        (!x. x IN s ==> (f(x) = g(x)))
+        ==> ((f has_integral k) s <=> (g has_integral k) s)`,
+  MESON_TAC[HAS_INTEGRAL_EQ]);;
+
+let HAS_INTEGRAL_NULL = prove
+ (`!f:real^M->real^N a b.
+    content(interval[a,b]) = &0 ==> (f has_integral vec 0) (interval[a,b])`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[has_integral] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  EXISTS_TAC `\x:real^M. ball(x,&1)` THEN REWRITE_TAC[GAUGE_TRIVIAL] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[VECTOR_SUB_RZERO] THEN
+  MATCH_MP_TAC(REAL_ARITH `x = &0 /\ &0 < e ==> x < e`) THEN
+  ASM_REWRITE_TAC[NORM_EQ_0] THEN ASM_MESON_TAC[VSUM_CONTENT_NULL]);;
+
+let HAS_INTEGRAL_NULL_EQ = prove
+ (`!f a b i. content(interval[a,b]) = &0
+             ==> ((f has_integral i) (interval[a,b]) <=> i = vec 0)`,
+  ASM_MESON_TAC[INTEGRAL_UNIQUE; HAS_INTEGRAL_NULL]);;
+
+let INTEGRAL_NULL = prove
+ (`!f a b. content(interval[a,b]) = &0
+           ==> integral(interval[a,b]) f = vec 0`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  ASM_MESON_TAC[HAS_INTEGRAL_NULL]);;
+
+let INTEGRABLE_ON_NULL = prove
+ (`!f a b. content(interval[a,b]) = &0
+           ==> f integrable_on interval[a,b]`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_NULL]);;
+
+let HAS_INTEGRAL_EMPTY = prove
+ (`!f. (f has_integral vec 0) {}`,
+  MESON_TAC[HAS_INTEGRAL_NULL; CONTENT_EMPTY; EMPTY_AS_INTERVAL]);;
+
+let HAS_INTEGRAL_EMPTY_EQ = prove
+ (`!f i. (f has_integral i) {} <=> i = vec 0`,
+  MESON_TAC[HAS_INTEGRAL_UNIQUE; HAS_INTEGRAL_EMPTY]);;
+
+let INTEGRABLE_ON_EMPTY = prove
+ (`!f. f integrable_on {}`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_EMPTY]);;
+
+let INTEGRAL_EMPTY = prove
+ (`!f. integral {} f = vec 0`,
+  MESON_TAC[EMPTY_AS_INTERVAL; INTEGRAL_UNIQUE; HAS_INTEGRAL_EMPTY]);;
+
+let HAS_INTEGRAL_REFL = prove
+ (`!f a. (f has_integral vec 0) (interval[a,a])`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_NULL THEN
+  SIMP_TAC[INTERVAL_SING; INTERIOR_CLOSED_INTERVAL; CONTENT_EQ_0_INTERIOR]);;
+
+let INTEGRABLE_ON_REFL = prove
+ (`!f a. f integrable_on interval[a,a]`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_REFL]);;
+
+let INTEGRAL_REFL = prove
+ (`!f a. integral (interval[a,a]) f = vec 0`,
+  MESON_TAC[INTEGRAL_UNIQUE; HAS_INTEGRAL_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Cauchy-type criterion for integrability.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let INTEGRABLE_CAUCHY = prove
+ (`!f:real^M->real^N a b.
+    f integrable_on interval[a,b] <=>
+        !e. &0 < e
+            ==> ?d. gauge d /\
+                    !p1 p2. p1 tagged_division_of interval[a,b] /\ d fine p1 /\
+                            p2 tagged_division_of interval[a,b] /\ d fine p2
+                            ==> norm(vsum p1 (\(x,k). content k % f x) -
+                                     vsum p2 (\(x,k). content k % f x)) < e`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[integrable_on; has_integral] THEN
+  EQ_TAC THEN DISCH_TAC THENL
+   [X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(X_CHOOSE_THEN `y:real^N` (MP_TAC o SPEC `e / &2`)) THEN
+    ASM_REWRITE_TAC[REAL_HALF] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `d:real^M->real^M->bool` THEN
+    REWRITE_TAC[GSYM dist] THEN MESON_TAC[DIST_TRIANGLE_HALF_L];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN `n:num` o SPEC `inv(&n + &1)`) THEN
+  REWRITE_TAC[REAL_LT_INV_EQ; REAL_ARITH `&0 < &n + &1`; SKOLEM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:num->real^M->real^M->bool` MP_TAC) THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "*")) THEN
+  MP_TAC(GEN `n:num`
+   (ISPECL [`\x. INTERS {(d:num->real^M->real^M->bool) i x | i IN 0..n}`;
+            `a:real^M`; `b:real^M`]
+     FINE_DIVISION_EXISTS)) THEN
+  ASM_SIMP_TAC[GAUGE_INTERS; FINE_INTERS; FINITE_NUMSEG; SKOLEM_THM] THEN
+  REWRITE_TAC[IN_NUMSEG; LE_0; FORALL_AND_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:num->(real^M#(real^M->bool))->bool`
+    STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+    `cauchy (\n. vsum (p n)
+                   (\(x,k:real^M->bool). content k % (f:real^M->real^N) x))`
+  MP_TAC THENL
+   [REWRITE_TAC[cauchy] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REAL_ARCH_INV]) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN STRIP_TAC THEN
+    MATCH_MP_TAC WLOG_LE THEN CONJ_TAC THENL
+     [MESON_TAC[DIST_SYM]; ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN REWRITE_TAC[GE] THEN
+    REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `inv(&m + &1)` THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[dist] THEN ASM_MESON_TAC[LE_REFL]; ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `inv(&N)` THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+    REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+    ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[GSYM CONVERGENT_EQ_CAUCHY; LIM_SEQUENTIALLY] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `y:real^N` THEN
+  REWRITE_TAC[dist] THEN STRIP_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(SPEC `e / &2` REAL_ARCH_INV) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N1:num` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_TAC `N2:num`) THEN EXISTS_TAC
+   `(d:num->real^M->real^M->bool) (N1 + N2)` THEN
+  ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `q:(real^M#(real^M->bool))->bool` THEN STRIP_TAC THEN
+  REWRITE_TAC[GSYM dist] THEN MATCH_MP_TAC DIST_TRIANGLE_HALF_L THEN
+  EXISTS_TAC `vsum (p(N1+N2:num))
+                  (\(x,k:real^M->bool). content k % (f:real^M->real^N) x)` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[dist] THEN MATCH_MP_TAC REAL_LTE_TRANS THEN
+    EXISTS_TAC `inv(&(N1 + N2) + &1)` THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[LE_REFL]; ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `inv(&N1)` THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+    REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+    ASM_ARITH_TAC;
+    ONCE_REWRITE_TAC[DIST_SYM] THEN REWRITE_TAC[dist] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Additivity of integral on abutting intervals.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let INTERVAL_SPLIT = prove
+ (`!a b:real^N c k.
+    1 <= k /\ k <= dimindex(:N)
+    ==> interval[a,b] INTER {x | x$k <= c} =
+        interval[a,(lambda i. if i = k then min (b$k) c else b$i)] /\
+        interval[a,b] INTER {x | x$k >= c} =
+        interval[(lambda i. if i = k then max (a$k) c else a$i),b]`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_INTERVAL; IN_INTER; IN_ELIM_THM] THEN
+  ASM_SIMP_TAC[LAMBDA_BETA] THEN X_GEN_TAC `y:real^N` THEN
+  MATCH_MP_TAC(TAUT `(c ==> b) /\ (c ==> a) /\ (a /\ b ==> c)
+                     ==> (a /\ b <=> c)`) THEN
+  (CONJ_TAC THENL
+    [ASM_MESON_TAC[REAL_MAX_LE; REAL_LE_MIN; real_ge];  ALL_TAC]) THEN
+  REWRITE_TAC[LEFT_AND_FORALL_THM; real_ge] THEN CONJ_TAC THEN
+  MATCH_MP_TAC MONO_FORALL THEN ASM_MESON_TAC[REAL_MAX_LE; REAL_LE_MIN]);;
+
+let CONTENT_SPLIT = prove
+ (`!a b:real^N k.
+    1 <= k /\ k <= dimindex(:N)
+    ==> content(interval[a,b]) =
+        content(interval[a,b] INTER {x | x$k <= c}) +
+        content(interval[a,b] INTER {x | x$k >= c})`,
+  SIMP_TAC[INTERVAL_SPLIT; CONTENT_CLOSED_INTERVAL_CASES; LAMBDA_BETA] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_ARITH
+   `((a <= if p then b else c) <=> (p ==> a <= b) /\ (~p ==> a <= c)) /\
+    ((if p then b else c) <= a <=> (p ==> b <= a) /\ (~p ==> c <= a))`] THEN
+  REWRITE_TAC[REAL_LE_MIN; REAL_MAX_LE] THEN
+  REWRITE_TAC[MESON[] `(i = k ==> p i k) <=> (i = k ==> p i i)`] THEN
+  REWRITE_TAC[TAUT `(p ==> a /\ b) /\ (~p ==> a) <=> a /\ (p ==> b)`] THEN
+  REWRITE_TAC[TAUT `a ==> b /\ c <=> (a ==> b) /\ (a ==> c)`] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC THEN
+  ASM_CASES_TAC
+   `!i. 1 <= i /\ i <= dimindex(:N) ==> (a:real^N)$i <= (b:real^N)$i` THEN
+  ASM_REWRITE_TAC[REAL_ADD_RID] THEN
+  REWRITE_TAC[MESON[] `(!i. P i ==> i = k ==> Q i) <=> (P k ==> Q k)`] THEN
+  ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[REAL_ARITH `min b c = if c <= b then c else b`;
+              REAL_ARITH `max a c = if a <= c then c else a`] THEN
+  REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_ADD_LID; REAL_ADD_RID]) THEN
+  REWRITE_TAC[MESON[] `(if i = k then a k else a i) = a i`] THENL
+   [ALL_TAC; ASM_MESON_TAC[REAL_LE_TRANS; REAL_LE_TOTAL]] THEN
+  SUBGOAL_THEN `1..dimindex(:N) = k INSERT ((1..dimindex(:N)) DELETE k)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_INSERT; IN_DELETE; IN_NUMSEG] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  SIMP_TAC[PRODUCT_CLAUSES; FINITE_DELETE; FINITE_NUMSEG; IN_DELETE] THEN
+  MATCH_MP_TAC(REAL_RING
+   `p'' = p /\ p':real = p
+    ==> (b - a) * p = (c - a) * p' + (b - c) * p''`) THEN
+  CONJ_TAC THEN MATCH_MP_TAC PRODUCT_EQ THEN SIMP_TAC[IN_DELETE]);;
+
+let DIVISION_SPLIT_LEFT_INJ,DIVISION_SPLIT_RIGHT_INJ = (CONJ_PAIR o prove)
+ (`(!d i k1 k2 k c.
+        d division_of i /\ 1 <= k /\ k <= dimindex(:N) /\
+        k1 IN d /\ k2 IN d /\ ~(k1 = k2) /\
+        k1 INTER {x | x$k <= c} = k2 INTER {x | x$k <= c}
+        ==> content(k1 INTER {x:real^N | x$k <= c}) = &0) /\
+   (!d i k1 k2 k c.
+        d division_of i /\ 1 <= k /\ k <= dimindex(:N) /\
+        k1 IN d /\ k2 IN d /\ ~(k1 = k2) /\
+        k1 INTER {x | x$k >= c} = k2 INTER {x | x$k >= c}
+        ==> content(k1 INTER {x:real^N | x$k >= c}) = &0)`,
+  let lemma = prove
+   (`!a b:real^N c k.
+      1 <= k /\ k <= dimindex(:N)
+      ==> (content(interval[a,b] INTER {x | x$k <= c}) = &0 <=>
+           interior(interval[a,b] INTER {x | x$k <= c}) = {}) /\
+          (content(interval[a,b] INTER {x | x$k >= c}) = &0 <=>
+           interior(interval[a,b] INTER {x | x$k >= c}) = {})`,
+    SIMP_TAC[INTERVAL_SPLIT; CONTENT_EQ_0_INTERIOR]) in
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[CONTENT_EQ_0_INTERIOR] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (MP_TAC o CONJUNCT1) o CONJUNCT2) THEN
+  DISCH_THEN(MP_TAC o SPECL
+    [`k1:real^N->bool`; `k2:real^N->bool`]) THEN
+  ASM_REWRITE_TAC[PAIR_EQ] THEN DISCH_TAC THEN
+  DISCH_THEN(MP_TAC o SPEC `k2:real^N->bool`) THEN
+  ASM_REWRITE_TAC[] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N` (X_CHOOSE_THEN `v:real^N`
+    SUBST_ALL_TAC)) THEN
+  ASM_SIMP_TAC[lemma] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+   `s INTER t = {}
+    ==> u SUBSET s /\ u SUBSET t ==> u = {}`)) THEN
+  CONJ_TAC THEN MATCH_MP_TAC SUBSET_INTERIOR THEN ASM SET_TAC[]);;
+
+let TAGGED_DIVISION_SPLIT_LEFT_INJ = prove
+ (`!d i x1 k1 x2 k2 k c.
+        d tagged_division_of i /\ 1 <= k /\ k <= dimindex(:N) /\
+        (x1,k1) IN d /\ (x2,k2) IN d /\ ~(k1 = k2) /\
+        k1 INTER {x | x$k <= c} = k2 INTER {x | x$k <= c}
+        ==> content(k1 INTER {x:real^N | x$k <= c}) = &0`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_TAGGED_DIVISION) THEN
+  MATCH_MP_TAC DIVISION_SPLIT_LEFT_INJ THEN
+  EXISTS_TAC `IMAGE SND (d:(real^N#(real^N->bool))->bool)` THEN
+  ASM_REWRITE_TAC[IN_IMAGE] THEN ASM_MESON_TAC[SND]);;
+
+let TAGGED_DIVISION_SPLIT_RIGHT_INJ = prove
+ (`!d i x1 k1 x2 k2 k c.
+        d tagged_division_of i /\ 1 <= k /\ k <= dimindex(:N) /\
+        (x1,k1) IN d /\ (x2,k2) IN d /\ ~(k1 = k2) /\
+        k1 INTER {x | x$k >= c} = k2 INTER {x | x$k >= c}
+        ==> content(k1 INTER {x:real^N | x$k >= c}) = &0`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_TAGGED_DIVISION) THEN
+  MATCH_MP_TAC DIVISION_SPLIT_RIGHT_INJ THEN
+  EXISTS_TAC `IMAGE SND (d:(real^N#(real^N->bool))->bool)` THEN
+  ASM_REWRITE_TAC[IN_IMAGE] THEN ASM_MESON_TAC[SND]);;
+
+let DIVISION_SPLIT = prove
+ (`!p a b:real^N k c.
+     p division_of interval[a,b] /\ 1 <= k /\ k <= dimindex(:N)
+     ==> {l INTER {x | x$k <= c} |l| l IN p /\ ~(l INTER {x | x$k <= c} = {})}
+         division_of (interval[a,b] INTER {x | x$k <= c}) /\
+         {l INTER {x | x$k >= c} |l| l IN p /\ ~(l INTER {x | x$k >= c} = {})}
+         division_of (interval[a,b] INTER {x | x$k >= c})`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  SIMP_TAC[division_of; FINITE_IMAGE] THEN
+  SIMP_TAC[SET_RULE `(!x. x IN {f x | P x} ==> Q x) <=> (!x. P x ==> Q (f x))`;
+           MESON[] `(!x y. x IN s /\ y IN t /\ Q x y ==> P x y) <=>
+                    (!x. x IN s ==> !y. y IN t ==> Q x y ==> P x y)`;
+           RIGHT_FORALL_IMP_THM] THEN
+  REPEAT(MATCH_MP_TAC(TAUT
+   `(a ==> a' /\ a'') /\ (b ==> b' /\ b'')
+      ==> a /\ b ==> (a' /\ b') /\ (a'' /\ b'')`) THEN CONJ_TAC)
+  THENL
+   [ONCE_REWRITE_TAC[SET_RULE
+    `{f x |x| x IN s /\ ~(f x = {})} = {y | y IN IMAGE f s /\ ~(y = {})}`] THEN
+    SIMP_TAC[FINITE_RESTRICT; FINITE_IMAGE];
+    REWRITE_TAC[AND_FORALL_THM] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `l:real^N->bool` THEN
+    DISCH_THEN(fun th -> CONJ_TAC THEN STRIP_TAC THEN MP_TAC th) THEN
+    (ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_AND THEN
+     CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+     STRIP_TAC THEN ASM_MESON_TAC[INTERVAL_SPLIT]);
+    DISCH_THEN(fun th -> CONJ_TAC THEN MP_TAC th) THEN
+    (REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+     DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_SIMP_TAC[] THEN
+     REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+     DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_SIMP_TAC[] THEN
+     DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_SIMP_TAC[] THEN
+     ANTS_TAC THENL [ASM_MESON_TAC[PAIR_EQ]; ALL_TAC] THEN
+     MATCH_MP_TAC(SET_RULE
+      `s SUBSET s' /\ t SUBSET t'
+       ==> s' INTER t' = {} ==> s INTER t = {}`) THEN
+     CONJ_TAC THEN MATCH_MP_TAC SUBSET_INTERIOR THEN SET_TAC[]);
+   DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[INTER_UNIONS] THEN
+   ONCE_REWRITE_TAC[EXTENSION] THEN REWRITE_TAC[IN_UNIONS] THEN
+   CONJ_TAC THEN GEN_TAC THEN AP_TERM_TAC THEN
+   GEN_REWRITE_TAC I [FUN_EQ_THM] THEN GEN_TAC THEN
+   REWRITE_TAC[IN_ELIM_THM; PAIR_EQ] THEN MESON_TAC[NOT_IN_EMPTY]]);;
+
+let HAS_INTEGRAL_SPLIT = prove
+ (`!f:real^M->real^N k a b c.
+      (f has_integral i) (interval[a,b] INTER {x | x$k <= c}) /\
+      (f has_integral j) (interval[a,b] INTER {x | x$k >= c}) /\
+      1 <= k /\ k <= dimindex(:M)
+      ==> (f has_integral (i + j)) (interval[a,b])`,
+  let lemma1 = prove
+   (`(!x k. (x,k) IN {x,f k | P x k} ==> Q x k) <=>
+     (!x k. P x k ==> Q x (f k))`,
+    REWRITE_TAC[IN_ELIM_THM; PAIR_EQ] THEN
+    SET_TAC[]) in
+  let lemma2 = prove
+   (`!f:B->B s:(A#B)->bool.
+      FINITE s ==> FINITE {x,f k | (x,k) IN s /\ P x k}`,
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC `IMAGE (\(x:A,k:B). x,(f k:B)) s` THEN
+    ASM_SIMP_TAC[FINITE_IMAGE] THEN
+    REWRITE_TAC[SUBSET; FORALL_PAIR_THM; lemma1; IN_IMAGE] THEN
+    REWRITE_TAC[EXISTS_PAIR_THM; PAIR_EQ] THEN MESON_TAC[]) in
+  let lemma3 = prove
+   (`!f:real^M->real^N g:(real^M->bool)->(real^M->bool) p.
+     FINITE p
+     ==> vsum {x,g k |x,k| (x,k) IN p /\ ~(g k = {})}
+              (\(x,k). content k % f x) =
+         vsum (IMAGE (\(x,k). x,g k) p) (\(x,k). content k % f x)`,
+    REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_SUPERSET THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; lemma2] THEN
+    REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[FORALL_PAIR_THM; SUBSET; IN_IMAGE; EXISTS_PAIR_THM] THEN
+    REWRITE_TAC[IN_ELIM_THM; PAIR_EQ; VECTOR_MUL_EQ_0] THEN
+    MESON_TAC[CONTENT_EMPTY]) in
+  let lemma4 = prove
+   (`(\(x,l). content (g l) % f x) =
+     (\(x,l). content l % f x) o (\(x,l). x,g l)`,
+    REWRITE_TAC[FUN_EQ_THM; o_THM; FORALL_PAIR_THM]) in
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `1 <= k /\ k <= dimindex(:M)` THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[INTERVAL_SPLIT] THEN REWRITE_TAC[has_integral] THEN
+  ASM_SIMP_TAC[GSYM INTERVAL_SPLIT] THEN FIRST_X_ASSUM STRIP_ASSUME_TAC THEN
+  DISCH_TAC THEN X_GEN_TAC `e:real` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(CONJUNCTS_THEN2 (MP_TAC o SPEC `e / &2`) STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d2:real^M->real^M->bool`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "I2"))) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real^M->real^M->bool`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "I1"))) THEN
+  EXISTS_TAC `\x. if x$k = c then (d1(x:real^M) INTER d2(x)):real^M->bool
+                  else ball(x,abs(x$k - c)) INTER d1(x) INTER d2(x)` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[gauge] THEN GEN_TAC THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[gauge]) THEN COND_CASES_TAC THEN
+    ASM_SIMP_TAC[OPEN_INTER; IN_INTER; OPEN_BALL; IN_BALL] THEN
+    ASM_REWRITE_TAC[DIST_REFL; GSYM REAL_ABS_NZ; REAL_SUB_0];
+    ALL_TAC] THEN
+  X_GEN_TAC `p:(real^M#(real^M->bool))->bool` THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+    `(!x:real^M kk. (x,kk) IN p /\ ~(kk INTER {x:real^M | x$k <= c} = {})
+                    ==> x$k <= c) /\
+     (!x:real^M kk. (x,kk) IN p /\ ~(kk INTER {x:real^M | x$k >= c} = {})
+                    ==> x$k >= c)`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:real^M` THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `kk:real^M->bool` THEN
+    DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_LE_REFL; real_ge] THEN DISCH_THEN
+     (MP_TAC o MATCH_MP (SET_RULE `k SUBSET (a INTER b) ==> k SUBSET a`)) THEN
+    REWRITE_TAC[SUBSET; IN_BALL; dist] THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^M` MP_TAC) THEN
+    REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `u:real^M`) THEN ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[REAL_NOT_LE; REAL_NOT_LT] THEN STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `abs((x - u:real^M)$k)` THEN
+    ASM_SIMP_TAC[COMPONENT_LE_NORM] THEN
+    ASM_SIMP_TAC[VECTOR_SUB_COMPONENT] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REMOVE_THEN "I2" (MP_TAC o SPEC
+   `{(x:real^M,kk INTER {x:real^M | x$k >= c}) |x,kk|
+     (x,kk) IN p /\ ~(kk INTER {x:real^M | x$k >= c} = {})}`) THEN
+  REMOVE_THEN "I1" (MP_TAC o SPEC
+   `{(x:real^M,kk INTER {x:real^M | x$k <= c}) |x,kk|
+     (x,kk) IN p /\ ~(kk INTER {x:real^M | x$k <= c} = {})}`) THEN
+  MATCH_MP_TAC(TAUT
+   `(a /\ b) /\ (a' /\ b' ==> c) ==> (a ==> a') ==> (b ==> b') ==> c`) THEN
+  CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+    REWRITE_TAC[TAGGED_DIVISION_OF] THEN
+    REPEAT(MATCH_MP_TAC(TAUT
+     `(a ==> (a' /\ a'')) /\ (b ==> (b' /\ d) /\ (b'' /\ e))
+      ==> a /\ b ==> ((a' /\ b') /\ d) /\ ((a'' /\ b'') /\ e)`) THEN
+      CONJ_TAC) THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[lemma1] THEN REWRITE_TAC[IMP_IMP] THENL
+     [SIMP_TAC[lemma2];
+      REWRITE_TAC[AND_FORALL_THM] THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:real^M` THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `kk:real^M->bool` THEN
+      DISCH_THEN(fun th -> CONJ_TAC THEN STRIP_TAC THEN MP_TAC th) THEN
+      (ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+        [SIMP_TAC[IN_INTER; IN_ELIM_THM] THEN ASM_MESON_TAC[]; ALL_TAC]) THEN
+      (MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL [SET_TAC[]; ALL_TAC]) THEN
+      ASM_MESON_TAC[INTERVAL_SPLIT];
+      DISCH_THEN(fun th -> CONJ_TAC THEN MP_TAC th) THEN
+      (REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+       DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_SIMP_TAC[] THEN
+       REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+       DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_SIMP_TAC[] THEN
+       ANTS_TAC THENL [ASM_MESON_TAC[PAIR_EQ]; ALL_TAC] THEN
+       MATCH_MP_TAC(SET_RULE
+        `s SUBSET s' /\ t SUBSET t'
+         ==> s' INTER t' = {} ==> s INTER t = {}`) THEN
+       CONJ_TAC THEN MATCH_MP_TAC SUBSET_INTERIOR THEN SET_TAC[]);
+      ALL_TAC] THEN
+    MATCH_MP_TAC(TAUT `(a ==> b /\ c) /\ d /\ e
+                       ==> (a ==> (b /\ d) /\ (c /\ e))`) THEN
+    CONJ_TAC THENL
+     [DISCH_THEN(fun th -> CONJ_TAC THEN MP_TAC th) THEN
+      DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[INTER_UNIONS] THEN
+      ONCE_REWRITE_TAC[EXTENSION] THEN REWRITE_TAC[IN_UNIONS] THEN
+      X_GEN_TAC `x:real^M` THEN AP_TERM_TAC THEN
+      GEN_REWRITE_TAC I [FUN_EQ_THM] THEN X_GEN_TAC `kk:real^M->bool` THEN
+      REWRITE_TAC[IN_ELIM_THM; PAIR_EQ] THEN MESON_TAC[NOT_IN_EMPTY];
+      ALL_TAC] THEN
+    CONJ_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+    REWRITE_TAC[fine; lemma1] THEN
+    REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+    DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+    ASM_SIMP_TAC[] THEN SET_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+   `x < e / &2 /\ y < e / &2 ==> x + y < e`)) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP NORM_TRIANGLE_LT) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `(a - i) + (b - j) = c - (i + j) <=> a + b = c:real^N`] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+ MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC
+   `vsum p (\(x,l). content (l INTER {x:real^M | x$k <= c}) %
+                     (f:real^M->real^N) x) +
+    vsum p (\(x,l). content (l INTER {x:real^M | x$k >= c}) %
+                     (f:real^M->real^N) x)` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[GSYM VSUM_ADD] THEN MATCH_MP_TAC VSUM_EQ THEN
+    REWRITE_TAC[FORALL_PAIR_THM; GSYM VECTOR_ADD_RDISTRIB] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `l:real^M->bool`] THEN
+    DISCH_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+    DISCH_THEN(MP_TAC o SPECL [`x:real^M`; `l:real^M->bool`] o
+               el 1 o CONJUNCTS) THEN
+    ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[GSYM CONTENT_SPLIT]] THEN
+  ASM_SIMP_TAC[lemma3] THEN BINOP_TAC THEN
+  (GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [lemma4] THEN
+   MATCH_MP_TAC VSUM_IMAGE_NONZERO THEN ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+   REWRITE_TAC[PAIR_EQ] THEN
+   ASM_MESON_TAC[TAGGED_DIVISION_SPLIT_LEFT_INJ; VECTOR_MUL_LZERO;
+                 TAGGED_DIVISION_SPLIT_RIGHT_INJ]));;
+
+(* ------------------------------------------------------------------------- *)
+(* A sort of converse, integrability on subintervals.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let TAGGED_DIVISION_UNION_INTERVAL = prove
+ (`!a b:real^N p1 p2 c k.
+        1 <= k /\ k <= dimindex(:N) /\
+        p1 tagged_division_of (interval[a,b] INTER {x | x$k <= c}) /\
+        p2 tagged_division_of (interval[a,b] INTER {x | x$k >= c})
+        ==> (p1 UNION p2) tagged_division_of (interval[a,b])`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+   `interval[a,b] = (interval[a,b] INTER {x:real^N | x$k <= c}) UNION
+                    (interval[a,b] INTER {x:real^N | x$k >= c})`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `(t UNION u = UNIV) ==> s = (s INTER t) UNION (s INTER u)`) THEN
+    REWRITE_TAC[EXTENSION; IN_UNIV; IN_UNION; IN_ELIM_THM] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC TAGGED_DIVISION_UNION THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[INTERVAL_SPLIT; INTERIOR_CLOSED_INTERVAL] THEN
+  REWRITE_TAC[EXTENSION; IN_INTER; NOT_IN_EMPTY; IN_INTERVAL] THEN
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN (MP_TAC o SPEC `k:num`)) THEN
+    ASM_SIMP_TAC[LAMBDA_BETA] THEN REAL_ARITH_TAC);;
+
+let HAS_INTEGRAL_SEPARATE_SIDES = prove
+ (`!f:real^M->real^N i a b k.
+        (f has_integral i) (interval[a,b]) /\
+        1 <= k /\ k <= dimindex(:M)
+        ==> !e. &0 < e
+                ==> ?d. gauge d /\
+                        !p1 p2. p1 tagged_division_of
+                                     (interval[a,b] INTER {x | x$k <= c}) /\
+                                d fine p1 /\
+                                p2 tagged_division_of
+                                     (interval[a,b] INTER {x | x$k >= c}) /\
+                                d fine p2
+                                ==> norm((vsum p1 (\(x,k). content k % f x) +
+                                          vsum p2 (\(x,k). content k % f x)) -
+                                         i) < e`,
+  REWRITE_TAC[has_integral] THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  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 `d:real^M->real^M->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `vsum p1 (\(x,k). content k % f x) + vsum p2 (\(x,k). content k % f x) =
+    vsum (p1 UNION p2) (\(x,k:real^M->bool). content k % (f:real^M->real^N) x)`
+  SUBST1_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[TAGGED_DIVISION_UNION_INTERVAL; FINE_UNION]] THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_UNION_NONZERO THEN
+  REPEAT(FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I
+   [TAGGED_DIVISION_OF])) THEN ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `l:real^M->bool`] THEN
+  REWRITE_TAC[IN_INTER; VECTOR_MUL_EQ_0] THEN STRIP_TAC THEN DISJ1_TAC THEN
+  SUBGOAL_THEN
+   `(?a b:real^M. l = interval[a,b]) /\
+    l SUBSET (interval[a,b] INTER {x | x$k <= c}) /\
+    l SUBSET (interval[a,b] INTER {x | x$k >= c})`
+  MP_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  ASM_REWRITE_TAC[SET_RULE
+   `s SUBSET t /\ s SUBSET u <=> s SUBSET (t INTER u)`] THEN
+  ASM_SIMP_TAC[INTERVAL_SPLIT; INTER_INTERVAL] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SUBSET_INTERIOR) THEN
+  REWRITE_TAC[INTERIOR_CLOSED_INTERVAL; CONTENT_EQ_0_INTERIOR] THEN
+  MATCH_MP_TAC(SET_RULE `t = {} ==> s SUBSET t ==> s = {}`) THEN
+  REWRITE_TAC[INTERVAL_EQ_EMPTY] THEN EXISTS_TAC `k:num` THEN
+  ASM_SIMP_TAC[LAMBDA_BETA] THEN REAL_ARITH_TAC);;
+
+let INTEGRABLE_SPLIT = prove
+ (`!f:real^M->real^N a b.
+        f integrable_on (interval[a,b]) /\ 1 <= k /\ k <= dimindex(:M)
+        ==> f integrable_on (interval[a,b] INTER {x | x$k <= c}) /\
+            f integrable_on (interval[a,b] INTER {x | x$k >= c})`,
+  let lemma = prove
+   (`b - a = c
+     ==> norm(a:real^N) < e / &2 ==> norm(b) < e / &2 ==> norm(c) < e`,
+    DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[GSYM dist] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC DIST_TRIANGLE_HALF_L THEN
+    EXISTS_TAC `vec 0:real^N` THEN
+    ASM_REWRITE_TAC[dist; VECTOR_SUB_LZERO; VECTOR_SUB_RZERO; NORM_NEG]) in
+  REPEAT GEN_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [integrable_on] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; LEFT_AND_EXISTS_THM] THEN
+  X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN CONJ_TAC THEN
+  ASM_SIMP_TAC[INTERVAL_SPLIT; INTEGRABLE_CAUCHY] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `e / &2` o
+    MATCH_MP HAS_INTEGRAL_SEPARATE_SIDES) THEN
+  MAP_EVERY ABBREV_TAC
+   [`b' = (lambda i. if i = k then min ((b:real^M)$k) c else b$i):real^M`;
+    `a' = (lambda i. if i = k then max ((a:real^M)$k) c else a$i):real^M`] THEN
+  ASM_SIMP_TAC[REAL_HALF; INTERVAL_SPLIT] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real^M->real^M->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP FINE_DIVISION_EXISTS) THENL
+   [DISCH_THEN(MP_TAC o SPECL [`a':real^M`; `b:real^M`]) THEN
+    RULE_ASSUM_TAC(ONCE_REWRITE_RULE[SWAP_FORALL_THM]);
+    DISCH_THEN(MP_TAC o SPECL [`a:real^M`; `b':real^M`])] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:(real^M#(real^M->bool))->bool`
+    STRIP_ASSUME_TAC) THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(fun th ->
+    MP_TAC(SPECL [`p:(real^M#(real^M->bool))->bool`;
+                  `p1:(real^M#(real^M->bool))->bool`] th) THEN
+    MP_TAC(SPECL [`p:(real^M#(real^M->bool))->bool`;
+                  `p2:(real^M#(real^M->bool))->bool`] th)) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC lemma THEN VECTOR_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Generalized notion of additivity.                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let operative = new_definition
+ `operative op (f:(real^N->bool)->A) <=>
+    (!a b. content(interval[a,b]) = &0 ==> f(interval[a,b]) = neutral(op)) /\
+    (!a b c k. 1 <= k /\ k <= dimindex(:N)
+               ==> f(interval[a,b]) =
+                   op (f(interval[a,b] INTER {x | x$k <= c}))
+                      (f(interval[a,b] INTER {x | x$k >= c})))`;;
+
+let OPERATIVE_TRIVIAL = prove
+ (`!op f a b.
+        operative op f /\ content(interval[a,b]) = &0
+        ==> f(interval[a,b]) = neutral op`,
+  REWRITE_TAC[operative] THEN MESON_TAC[]);;
+
+let PROPERTY_EMPTY_INTERVAL = prove
+ (`!P. (!a b:real^N. content(interval[a,b]) = &0 ==> P(interval[a,b]))
+       ==> P {}`,
+  MESON_TAC[EMPTY_AS_INTERVAL; CONTENT_EMPTY]);;
+
+let OPERATIVE_EMPTY = prove
+ (`!op f:(real^N->bool)->A. operative op f ==> f {} = neutral op`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[operative] THEN
+  DISCH_THEN(ACCEPT_TAC o MATCH_MP PROPERTY_EMPTY_INTERVAL o CONJUNCT1));;
+
+(* ------------------------------------------------------------------------- *)
+(* Using additivity of lifted function to encode definedness.                *)
+(* ------------------------------------------------------------------------- *)
+
+let FORALL_OPTION = prove
+ (`(!x. P x) <=> P NONE /\ !x. P(SOME x)`,
+  MESON_TAC[cases "option"]);;
+
+let EXISTS_OPTION = prove
+ (`(?x. P x) <=> P NONE \/ ?x. P(SOME x)`,
+  MESON_TAC[cases "option"]);;
+
+let lifted = define
+ `(lifted op NONE _ = NONE) /\
+  (lifted op _ NONE = NONE) /\
+  (lifted op (SOME x) (SOME y) = SOME(op x y))`;;
+
+let NEUTRAL_LIFTED = prove
+ (`!op. monoidal op ==> neutral(lifted op) = SOME(neutral op)`,
+  REWRITE_TAC[neutral; monoidal] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SELECT_UNIQUE THEN
+  REWRITE_TAC[FORALL_OPTION; lifted; distinctness "option";
+              injectivity "option"] THEN
+  ASM_MESON_TAC[]);;
+
+let MONOIDAL_LIFTED = prove
+ (`!op. monoidal op ==> monoidal(lifted op)`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[NEUTRAL_LIFTED; monoidal] THEN
+  REWRITE_TAC[FORALL_OPTION; lifted; distinctness "option";
+              injectivity "option"] THEN
+  ASM_MESON_TAC[monoidal]);;
+
+let ITERATE_SOME = prove
+ (`!op. monoidal op
+        ==> !f s. FINITE s
+                  ==> iterate (lifted op) s (\x. SOME(f x)) =
+                      SOME(iterate op s f)`,
+  GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  ASM_SIMP_TAC[ITERATE_CLAUSES; MONOIDAL_LIFTED; NEUTRAL_LIFTED] THEN
+  REWRITE_TAC[lifted]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Two key instances of additivity.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let OPERATIVE_CONTENT = prove
+ (`operative(+) content`,
+  REWRITE_TAC[operative; NEUTRAL_REAL_ADD; CONTENT_SPLIT]);;
+
+let OPERATIVE_INTEGRAL = prove
+ (`!f:real^M->real^N.
+       operative(lifted(+))
+         (\i. if f integrable_on i then SOME(integral i f) else NONE)`,
+  SIMP_TAC[operative; NEUTRAL_LIFTED; MONOIDAL_VECTOR_ADD] THEN
+  REWRITE_TAC[NEUTRAL_VECTOR_ADD] THEN
+  REPEAT STRIP_TAC THEN REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+  REWRITE_TAC[lifted; distinctness "option"; injectivity "option"] THENL
+   [REWRITE_TAC[integral] THEN ASM_MESON_TAC[HAS_INTEGRAL_NULL_EQ];
+    RULE_ASSUM_TAC(REWRITE_RULE[integrable_on]) THEN
+    ASM_MESON_TAC[HAS_INTEGRAL_NULL];
+    REPEAT(FIRST_X_ASSUM(MP_TAC o MATCH_MP INTEGRABLE_INTEGRAL)) THEN
+    ASM_MESON_TAC[HAS_INTEGRAL_SPLIT; HAS_INTEGRAL_UNIQUE];
+    ASM_MESON_TAC[INTEGRABLE_SPLIT; integrable_on];
+    ASM_MESON_TAC[INTEGRABLE_SPLIT];
+    ASM_MESON_TAC[INTEGRABLE_SPLIT];
+    RULE_ASSUM_TAC(REWRITE_RULE[integrable_on]) THEN
+    ASM_MESON_TAC[HAS_INTEGRAL_SPLIT]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Points of division of a partition.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let division_points = new_definition
+ `division_points (k:real^N->bool) (d:(real^N->bool)->bool) =
+    {j,x | 1 <= j /\ j <= dimindex(:N) /\
+           (interval_lowerbound k)$j < x /\ x < (interval_upperbound k)$j /\
+           ?i. i IN d /\
+               ((interval_lowerbound i)$j = x \/
+                (interval_upperbound i)$j = x)}`;;
+
+let DIVISION_POINTS_FINITE = prove
+ (`!d i:real^N->bool. d division_of i ==> FINITE(division_points i d)`,
+  REWRITE_TAC[division_of; division_points] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CONJ_ASSOC; GSYM IN_NUMSEG] THEN
+  REWRITE_TAC[IN; GSYM CONJ_ASSOC] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IN] FINITE_PRODUCT_DEPENDENT) THEN
+  REWRITE_TAC[ETA_AX; FINITE_NUMSEG] THEN
+  X_GEN_TAC `j:num` THEN GEN_REWRITE_TAC LAND_CONV [GSYM IN] THEN
+  REWRITE_TAC[IN_NUMSEG] THEN STRIP_TAC THEN
+  MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC
+   `IMAGE (\i:real^N->bool. (interval_lowerbound i)$j) d UNION
+    IMAGE (\i:real^N->bool. (interval_upperbound i)$j) d` THEN
+  ASM_SIMP_TAC[FINITE_UNION; FINITE_IMAGE] THEN
+  REWRITE_TAC[SUBSET; IN_IMAGE; IN_UNION; IN_ELIM_THM] THEN MESON_TAC[IN]);;
+
+let DIVISION_POINTS_SUBSET = prove
+ (`!a b:real^N c d k.
+        d division_of interval[a,b] /\
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i < b$i) /\
+        1 <= k /\ k <= dimindex(:N) /\ a$k < c /\ c < b$k
+        ==> division_points (interval[a,b] INTER {x | x$k <= c})
+                            {l INTER {x | x$k <= c} | l |
+                             l IN d /\ ~(l INTER {x | x$k <= c} = {})}
+            SUBSET division_points (interval[a,b]) d /\
+            division_points (interval[a,b] INTER {x | x$k >= c})
+                            {l INTER {x | x$k >= c} | l |
+                             l IN d /\ ~(l INTER {x | x$k >= c} = {})}
+            SUBSET division_points (interval[a,b]) d`,
+  REPEAT STRIP_TAC THEN
+  (REWRITE_TAC[SUBSET; division_points; FORALL_PAIR_THM] THEN
+   MAP_EVERY X_GEN_TAC [`j:num`; `x:real`] THEN
+   REWRITE_TAC[IN_ELIM_PAIR_THM] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+   ASM_SIMP_TAC[INTERVAL_SPLIT; INTERVAL_LOWERBOUND; INTERVAL_UPPERBOUND;
+                REAL_LT_IMP_LE] THEN
+   ASM_SIMP_TAC[REAL_ARITH `a < c ==> max a c = c`;
+                REAL_ARITH `c < b ==> min b c = c`] THEN
+   REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+   ASM_SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND; LAMBDA_BETA;
+     REAL_LT_IMP_LE; COND_ID;
+     TAUT `(a <= if p then x else y) <=> (if p then a <= x else a <= y)`;
+     TAUT `(if p then x else y) <= a <=> (if p then x <= a else y <= a)`] THEN
+   REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+   DISCH_THEN(fun th -> CONJ_TAC THEN MP_TAC th) THENL
+    [DISCH_THEN(K ALL_TAC) THEN REPEAT(POP_ASSUM MP_TAC) THEN
+     COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+     ALL_TAC] THEN
+   REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+   MATCH_MP_TAC MONO_EXISTS THEN
+   ONCE_REWRITE_TAC[TAUT `(a /\ b) /\ c <=> b /\ a /\ c`] THEN
+   REWRITE_TAC[UNWIND_THM2] THEN SIMP_TAC[GSYM CONJ_ASSOC] THEN
+   ONCE_REWRITE_TAC[IMP_CONJ] THEN
+   FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+   MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN DISCH_TAC THEN
+   ASM_SIMP_TAC[INTERVAL_SPLIT] THEN
+   SUBGOAL_THEN
+    `!i. 1 <= i /\ i <= dimindex(:N) ==> (u:real^N)$i <= (v:real^N)$i`
+   ASSUME_TAC THENL
+    [REWRITE_TAC[GSYM INTERVAL_NE_EMPTY] THEN ASM_MESON_TAC[division_of];
+     ALL_TAC] THEN
+   REWRITE_TAC[INTERVAL_NE_EMPTY] THEN
+   DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+   ASM_SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND] THEN
+   ASM_SIMP_TAC[LAMBDA_BETA] THEN REPEAT(POP_ASSUM MP_TAC) THEN
+   COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC));;
+
+let DIVISION_POINTS_PSUBSET = prove
+ (`!a b:real^N c d k.
+        d division_of interval[a,b] /\
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i < b$i) /\
+        1 <= k /\ k <= dimindex(:N) /\ a$k < c /\ c < b$k /\
+        (?l. l IN d /\
+             (interval_lowerbound l$k = c \/ interval_upperbound l$k = c))
+        ==> division_points (interval[a,b] INTER {x | x$k <= c})
+                            {l INTER {x | x$k <= c} | l |
+                             l IN d /\ ~(l INTER {x | x$k <= c} = {})}
+            PSUBSET division_points (interval[a,b]) d /\
+            division_points (interval[a,b] INTER {x | x$k >= c})
+                            {l INTER {x | x$k >= c} | l |
+                             l IN d /\ ~(l INTER {x | x$k >= c} = {})}
+            PSUBSET division_points (interval[a,b]) d`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[PSUBSET_MEMBER; DIVISION_POINTS_SUBSET] THENL
+   [EXISTS_TAC `k,(interval_lowerbound l:real^N)$k`;
+    EXISTS_TAC `k,(interval_lowerbound l:real^N)$k`;
+    EXISTS_TAC `k,(interval_upperbound l:real^N)$k`;
+    EXISTS_TAC `k,(interval_upperbound l:real^N)$k`] THEN
+  ASM_REWRITE_TAC[division_points; IN_ELIM_PAIR_THM] THEN
+  ASM_SIMP_TAC[INTERVAL_LOWERBOUND; INTERVAL_UPPERBOUND; REAL_LT_IMP_LE] THEN
+  (CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC]) THEN
+  ASM_SIMP_TAC[INTERVAL_SPLIT; INTERVAL_LOWERBOUND; INTERVAL_UPPERBOUND;
+               REAL_LT_IMP_LE] THEN
+  ASM_SIMP_TAC[REAL_ARITH `a < c ==> max a c = c`;
+               REAL_ARITH `c < b ==> min b c = c`] THEN
+  ASM_SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND; LAMBDA_BETA;
+    REAL_LT_IMP_LE; COND_ID;
+    TAUT `(a <= if p then x else y) <=> (if p then a <= x else a <= y)`;
+    TAUT `(if p then x else y) <= a <=> (if p then x <= a else y <= a)`] THEN
+  REWRITE_TAC[REAL_LT_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Preservation by divisions and tagged divisions.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let OPERATIVE_DIVISION = prove
+ (`!op d a b f:(real^N->bool)->A.
+    monoidal op /\ operative op f /\ d division_of interval[a,b]
+    ==> iterate(op) d f = f(interval[a,b])`,
+  REPEAT GEN_TAC THEN CONV_TAC(RAND_CONV SYM_CONV) THEN WF_INDUCT_TAC
+   `CARD (division_points (interval[a,b]:real^N->bool) d)` THEN
+  POP_ASSUM(fun th -> REPEAT STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `content(interval[a:real^N,b]) = &0` THENL
+   [SUBGOAL_THEN `iterate op d (f:(real^N->bool)->A) = neutral op`
+     (fun th -> ASM_MESON_TAC[th; operative]) THEN
+    MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+     ITERATE_EQ_NEUTRAL) THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+    ASM_MESON_TAC[operative; DIVISION_OF_CONTENT_0];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM CONTENT_LT_NZ]) THEN
+  REWRITE_TAC[CONTENT_POS_LT_EQ] THEN STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  ASM_CASES_TAC `division_points (interval[a,b]:real^N->bool) d = {}` THENL
+   [DISCH_THEN(K ALL_TAC) THEN
+    SUBGOAL_THEN
+     `!i. i IN d
+          ==> ?u v:real^N. i = interval[u,v] /\
+                           !j. 1 <= j /\ j <= dimindex(:N)
+                               ==> u$j = (a:real^N)$j /\ v$j = a$j \/
+                                   u$j = (b:real^N)$j /\ v$j = b$j \/
+                                   u$j = a$j /\ v$j = b$j`
+    (LABEL_TAC "*") THENL
+     [FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+      MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN DISCH_TAC THEN
+      MAP_EVERY EXISTS_TAC [`u:real^N`; `v:real^N`] THEN REWRITE_TAC[] THEN
+      REPEAT STRIP_TAC THEN
+      FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(MP_TAC o SPEC `interval[u:real^N,v]` o CONJUNCT1) THEN
+      ASM_REWRITE_TAC[INTERVAL_NE_EMPTY] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (ASSUME_TAC o CONJUNCT1)) THEN
+      ASM_REWRITE_TAC[SUBSET_INTERVAL] THEN STRIP_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `a <= u /\ u <= v /\ v <= b /\ ~(a < u /\ u < b \/ a < v /\ v < b)
+        ==> u = a /\ v = a \/ u = b /\ v = b \/ u = a /\ v = b`) THEN
+      ASM_SIMP_TAC[] THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+      REWRITE_TAC[division_points; NOT_IN_EMPTY; FORALL_PAIR_THM] THEN
+      REWRITE_TAC[IN_ELIM_PAIR_THM] THEN DISCH_THEN(MP_TAC o SPEC `j:num`) THEN
+      ASM_REWRITE_TAC[] THEN REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+      REWRITE_TAC[NOT_EXISTS_THM] THEN ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+      DISCH_THEN(MP_TAC o SPEC `interval[u:real^N,v]`) THEN
+      ASM_SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND;
+                   REAL_LT_IMP_LE] THEN
+      DISCH_THEN(fun th ->
+        MP_TAC(SPEC `(u:real^N)$j` th) THEN
+        MP_TAC(SPEC `(v:real^N)$j` th)) THEN
+      FIRST_X_ASSUM(DISJ_CASES_THEN MP_TAC) THEN REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN `interval[a:real^N,b] IN d` MP_TAC THENL
+     [FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o last o CONJUNCTS) THEN
+      REWRITE_TAC[EXTENSION; IN_INTERVAL; IN_UNIONS] THEN
+      DISCH_THEN(MP_TAC o SPEC `inv(&2) % (a + b:real^N)`) THEN
+      MATCH_MP_TAC(TAUT `b /\ (a ==> c) ==> (a <=> b) ==> c`) THEN
+      CONJ_TAC THENL
+       [SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+        X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+        FIRST_X_ASSUM(MP_TAC o SPEC `j:num`) THEN ASM_REWRITE_TAC[] THEN
+        REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      DISCH_THEN(X_CHOOSE_THEN `i:real^N->bool`
+       (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+      REMOVE_THEN "*" (MP_TAC o SPEC `i:real^N->bool`) THEN
+      ASM_REWRITE_TAC[] THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+      MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC MP_TAC) THEN
+      SIMP_TAC[IN_INTERVAL; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+      REWRITE_TAC[IMP_IMP; AND_FORALL_THM] THEN
+      REWRITE_TAC[TAUT `(a ==> b) /\ (a ==> c) <=> a ==> b /\ c`] THEN
+      ASM_SIMP_TAC[REAL_ARITH
+       `a < b
+        ==> ((u = a /\ v = a \/ u = b /\ v = b \/ u = a /\ v = b) /\
+             u <= inv(&2) * (a + b) /\ inv(&2) * (a +  b) <= v <=>
+             u = a /\ v = b)`] THEN
+      ASM_MESON_TAC[CART_EQ];
+      ALL_TAC] THEN
+    DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+    DISCH_THEN(SUBST1_TAC o MATCH_MP (SET_RULE
+     `a IN d ==> d = a INSERT (d DELETE a)`)) THEN
+    ASM_SIMP_TAC[ITERATE_CLAUSES; FINITE_DELETE; IN_DELETE] THEN
+    SUBGOAL_THEN
+     `iterate op (d DELETE interval[a,b]) (f:(real^N->bool)->A) = neutral op`
+     (fun th -> ASM_MESON_TAC[th; monoidal]) THEN
+    MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+     ITERATE_EQ_NEUTRAL) THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `l:real^N->bool` THEN
+    REWRITE_TAC[IN_DELETE] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `content(l:real^N->bool) = &0`
+     (fun th -> ASM_MESON_TAC[th; operative]) THEN
+    REMOVE_THEN "*" (MP_TAC o SPEC `l:real^N->bool`) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC MP_TAC) THEN
+    UNDISCH_TAC `~(interval[u:real^N,v] = interval[a,b])` THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[] THEN DISCH_THEN(fun th -> AP_TERM_TAC THEN MP_TAC th) THEN
+    REWRITE_TAC[CONS_11; PAIR_EQ; CART_EQ; CONTENT_EQ_0] THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+     [TAUT `a ==> b <=> ~a \/ b`] THEN
+    REWRITE_TAC[NOT_FORALL_THM; OR_EXISTS_THM] THEN
+    REWRITE_TAC[NOT_EXISTS_THM; AND_FORALL_THM] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `j:num` THEN
+    ASM_CASES_TAC `1 <= j /\ j <= dimindex(:N)` THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `j:num`) THEN ASM_REWRITE_TAC[] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [division_points] THEN
+  REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`whatever:num#real`; `k:num`; `c:real`] THEN
+  ASM_SIMP_TAC[INTERVAL_LOWERBOUND; INTERVAL_UPPERBOUND; REAL_LT_IMP_LE] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (K ALL_TAC)) THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`a:real^N`; `b:real^N`; `c:real`; `d:(real^N->bool)->bool`;
+        `k:num`] DIVISION_POINTS_PSUBSET) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(CONJUNCTS_THEN
+   (MP_TAC o MATCH_MP (REWRITE_RULE [IMP_CONJ] CARD_PSUBSET))) THEN
+  MP_TAC(ISPECL [`d:(real^N->bool)->bool`; `a:real^N`; `b:real^N`; `k:num`;
+                 `c:real`]
+      DIVISION_SPLIT) THEN
+  ASM_SIMP_TAC[DIVISION_POINTS_FINITE] THEN
+  ASM_SIMP_TAC[INTERVAL_SPLIT] THEN
+  ASM_SIMP_TAC[REAL_ARITH `a < c ==> max a c = c`;
+               REAL_ARITH `c < b ==> min b c = c`] THEN
+  MAP_EVERY ABBREV_TAC
+   [`d1:(real^N->bool)->bool =
+     {l INTER {x | x$k <= c} | l | l IN d /\ ~(l INTER {x | x$k <= c} = {})}`;
+    `d2:(real^N->bool)->bool =
+     {l INTER {x | x$k >= c} | l | l IN d /\ ~(l INTER {x | x$k >= c} = {})}`;
+    `cb:real^N = (lambda i. if i = k then c else (b:real^N)$i)`;
+    `ca:real^N = (lambda i. if i = k then c else (a:real^N)$i)`] THEN
+  STRIP_TAC THEN STRIP_TAC THEN STRIP_TAC THEN DISCH_THEN(fun th ->
+   MP_TAC(SPECL [`a:real^N`; `cb:real^N`; `d1:(real^N->bool)->bool`] th) THEN
+   MP_TAC(SPECL [`ca:real^N`; `b:real^N`; `d2:(real^N->bool)->bool`] th)) THEN
+  ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `op (iterate op d1 (f:(real^N->bool)->A))
+                 (iterate op d2 (f:(real^N->bool)->A))` THEN
+  CONJ_TAC THENL
+   [FIRST_ASSUM(MP_TAC o CONJUNCT2 o GEN_REWRITE_RULE I [operative]) THEN
+    DISCH_THEN(MP_TAC o SPECL [`a:real^N`; `b:real^N`; `c:real`; `k:num`]) THEN
+    ASM_SIMP_TAC[INTERVAL_SPLIT] THEN
+    ASM_SIMP_TAC[REAL_ARITH `a < c ==> max a c = c`;
+                 REAL_ARITH `c < b ==> min b c = c`];
+    ALL_TAC] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC
+   `op (iterate op d (\l. f(l INTER {x | x$k <= c}):A))
+       (iterate op d (\l. f(l INTER {x:real^N | x$k >= c})))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[GSYM ITERATE_OP] THEN
+    MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+     ITERATE_EQ) THEN
+    ASM_REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION
+     (ASSUME `d division_of interval[a:real^N,b]`)] THEN
+    ASM_MESON_TAC[operative]] THEN
+  MAP_EVERY EXPAND_TAC ["d1"; "d2"] THEN BINOP_TAC THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM o_DEF] THEN
+  MATCH_MP_TAC ITERATE_NONZERO_IMAGE_LEMMA THEN ASM_REWRITE_TAC[] THEN
+  (CONJ_TAC THENL [ASM_MESON_TAC[OPERATIVE_EMPTY]; ALL_TAC] THEN
+   MAP_EVERY X_GEN_TAC [`l:real^N->bool`; `m:real^N->bool`] THEN STRIP_TAC THEN
+   MATCH_MP_TAC(MESON[OPERATIVE_TRIVIAL]
+    `operative op f /\ (?a b. l = interval[a,b]) /\ content l = &0
+     ==> f l = neutral op`) THEN
+   ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+    [ALL_TAC; ASM_MESON_TAC[DIVISION_SPLIT_LEFT_INJ;
+                                 DIVISION_SPLIT_RIGHT_INJ]] THEN
+   SUBGOAL_THEN `?a b:real^N. m = interval[a,b]` STRIP_ASSUME_TAC THENL
+    [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+   ASM_SIMP_TAC[INTERVAL_SPLIT] THEN MESON_TAC[]));;
+
+let OPERATIVE_TAGGED_DIVISION = prove
+ (`!op d a b f:(real^N->bool)->A.
+    monoidal op /\ operative op f /\ d tagged_division_of interval[a,b]
+    ==> iterate(op) d (\(x,l). f l) = f(interval[a,b])`,
+  let lemma = prove
+   (`(\(x,l). f l) = (f o SND)`,
+    REWRITE_TAC[FUN_EQ_THM; o_THM; FORALL_PAIR_THM]) in
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `iterate op (IMAGE SND (d:(real^N#(real^N->bool)->bool))) f :A` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_MESON_TAC[DIVISION_OF_TAGGED_DIVISION; OPERATIVE_DIVISION]] THEN
+  REWRITE_TAC[lemma] THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+               ITERATE_IMAGE_NONZERO) THEN
+  ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF_FINITE]; ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o CONJUNCT1 o CONJUNCT2)) THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN REWRITE_TAC[PAIR_EQ] THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_SIMP_TAC[INTER_ACI] THEN
+  ASM_MESON_TAC[CONTENT_EQ_0_INTERIOR; OPERATIVE_TRIVIAL;
+                TAGGED_DIVISION_OF]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Additivity of content.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let ADDITIVE_CONTENT_DIVISION = prove
+ (`!d a b:real^N.
+    d division_of interval[a,b]
+    ==> sum d content = content(interval[a,b])`,
+  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP
+   (MATCH_MP
+     (REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+                  OPERATIVE_DIVISION)
+     (CONJ MONOIDAL_REAL_ADD OPERATIVE_CONTENT))) THEN
+  REWRITE_TAC[sum]);;
+
+let ADDITIVE_CONTENT_TAGGED_DIVISION = prove
+ (`!d a b:real^N.
+    d tagged_division_of interval[a,b]
+    ==> sum d (\(x,l). content l) = content(interval[a,b])`,
+  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP
+   (MATCH_MP
+     (REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+                  OPERATIVE_TAGGED_DIVISION)
+     (CONJ MONOIDAL_REAL_ADD OPERATIVE_CONTENT))) THEN
+  REWRITE_TAC[sum]);;
+
+let SUBADDITIVE_CONTENT_DIVISION = prove
+ (`!d s a b:real^M.
+        d division_of s /\ s SUBSET interval[a,b]
+        ==> sum d content <= content(interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`d:(real^M->bool)->bool`; `a:real^M`; `b:real^M`]
+        PARTIAL_DIVISION_EXTEND_INTERVAL) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[UNIONS_SUBSET] THEN
+    ASM_MESON_TAC[division_of; DIVISION_OF_UNION_SELF; SUBSET_TRANS];
+    DISCH_THEN(X_CHOOSE_THEN `p:(real^M->bool)->bool` STRIP_ASSUME_TAC) THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum (p:(real^M->bool)->bool) content` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC SUM_SUBSET_SIMPLE THEN
+      ASM_MESON_TAC[division_of; CONTENT_POS_LE; IN_DIFF];
+      ASM_MESON_TAC[ADDITIVE_CONTENT_DIVISION; REAL_LE_REFL]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Finally, the integral of a constant!                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_CONST = prove
+ (`!a b:real^M c:real^N.
+    ((\x. c) has_integral (content(interval[a,b]) % c)) (interval[a,b])`,
+  REWRITE_TAC[has_integral] THEN REPEAT STRIP_TAC THEN
+  EXISTS_TAC `\x:real^M. ball(x,&1)` THEN REWRITE_TAC[GAUGE_TRIVIAL] THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  FIRST_X_ASSUM(fun th ->
+  ONCE_REWRITE_TAC[GSYM(MATCH_MP ADDITIVE_CONTENT_TAGGED_DIVISION th)]) THEN
+  ASM_SIMP_TAC[VSUM_VMUL; GSYM VSUM_SUB] THEN
+  REWRITE_TAC[LAMBDA_PAIR_THM; VECTOR_SUB_REFL] THEN
+  ASM_REWRITE_TAC[GSYM LAMBDA_PAIR_THM; VSUM_0; NORM_0]);;
+
+let INTEGRABLE_CONST = prove
+ (`!a b:real^M c:real^N. (\x. c) integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[integrable_on] THEN
+  EXISTS_TAC `content(interval[a:real^M,b]) % c:real^N` THEN
+  REWRITE_TAC[HAS_INTEGRAL_CONST]);;
+
+let INTEGRAL_CONST = prove
+ (`!a b c. integral (interval[a,b]) (\x. c) = content(interval[a,b]) % c`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  REWRITE_TAC[HAS_INTEGRAL_CONST]);;
+
+let INTEGRAL_PASTECART_CONST = prove
+ (`!a b:real^M c d:real^N k:real^P.
+     integral (interval[pastecart a c,pastecart b d]) (\x. k) =
+     integral (interval[a,b])
+              (\x. integral (interval[c,d]) (\y. k))`,
+  REWRITE_TAC[INTEGRAL_CONST; CONTENT_PASTECART; VECTOR_MUL_ASSOC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Bounds on the norm of Riemann sums and the integral itself.               *)
+(* ------------------------------------------------------------------------- *)
+
+let DSUM_BOUND = prove
+ (`!p a b:real^M c:real^N e.
+       p division_of interval[a,b] /\ norm(c) <= e
+       ==> norm(vsum p (\l. content l % c)) <= e * content(interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) VSUM_NORM o lhand o snd) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(REAL_ARITH
+   `y <= e ==> x <= y ==> x <= e`) THEN
+  REWRITE_TAC[LAMBDA_PAIR_THM; NORM_MUL] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum p (\k:real^M->bool. content k * e)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+    X_GEN_TAC `l:real^M->bool` THEN DISCH_TAC THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN SIMP_TAC[REAL_ABS_POS; NORM_POS_LE] THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= x ==> abs(x) <= x`) THEN
+    ASM_MESON_TAC[DIVISION_OF; CONTENT_POS_LE];
+    REWRITE_TAC[SUM_RMUL; ETA_AX] THEN
+    ASM_MESON_TAC[ADDITIVE_CONTENT_DIVISION; REAL_LE_REFL; REAL_MUL_SYM]]);;
+
+let RSUM_BOUND = prove
+ (`!p a b f:real^M->real^N e.
+       p tagged_division_of interval[a,b] /\
+       (!x. x IN interval[a,b] ==> norm(f x) <= e)
+       ==> norm(vsum p (\(x,k). content k % f x))
+            <= e * content(interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) VSUM_NORM o lhand o snd) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(REAL_ARITH
+   `y <= e ==> x <= y ==> x <= e`) THEN
+  REWRITE_TAC[LAMBDA_PAIR_THM; NORM_MUL] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum p (\(x:real^M,k:real^M->bool). content k * e)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `l:real^M->bool`] THEN DISCH_TAC THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN SIMP_TAC[REAL_ABS_POS; NORM_POS_LE] THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[TAGGED_DIVISION_OF; CONTENT_POS_LE; REAL_ABS_REFL;
+                    REAL_LE_REFL];
+      ASM_MESON_TAC[TAG_IN_INTERVAL]];
+    FIRST_ASSUM(fun th -> REWRITE_TAC
+     [GSYM(MATCH_MP ADDITIVE_CONTENT_TAGGED_DIVISION th)]) THEN
+    REWRITE_TAC[GSYM SUM_LMUL; LAMBDA_PAIR_THM] THEN
+    REWRITE_TAC[REAL_MUL_AC; REAL_LE_REFL]]);;
+
+let RSUM_DIFF_BOUND = prove
+ (`!p a b f g:real^M->real^N.
+       p tagged_division_of interval[a,b] /\
+       (!x. x IN interval[a,b] ==> norm(f x - g x) <= e)
+       ==> norm(vsum p (\(x,k). content k % f x) -
+                vsum p (\(x,k). content k % g x))
+           <= e * content(interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC
+   `norm(vsum p (\(x,k).
+      content(k:real^M->bool) % ((f:real^M->real^N) x - g x)))` THEN
+  CONJ_TAC THENL
+   [ASM_SIMP_TAC[GSYM VSUM_SUB; VECTOR_SUB_LDISTRIB] THEN
+    REWRITE_TAC[LAMBDA_PAIR_THM; REAL_LE_REFL];
+    ASM_SIMP_TAC[RSUM_BOUND]]);;
+
+let HAS_INTEGRAL_BOUND = prove
+ (`!f:real^M->real^N a b i B.
+        &0 <= B /\
+        (f has_integral i) (interval[a,b]) /\
+        (!x. x IN interval[a,b] ==> norm(f x) <= B)
+        ==> norm i <= B * content(interval[a,b])`,
+  let lemma = prove
+   (`norm(s) <= B ==> ~(norm(s - i) < norm(i) - B)`,
+    MATCH_MP_TAC(REAL_ARITH `n1 <= n + n2 ==> n <= B ==> ~(n2 < n1 - B)`) THEN
+    ONCE_REWRITE_TAC[NORM_SUB] THEN REWRITE_TAC[NORM_TRIANGLE_SUB]) in
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `&0 < content(interval[a:real^M,b])` THENL
+   [ALL_TAC;
+    SUBGOAL_THEN `i:real^N = vec 0` SUBST1_TAC THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; NORM_0; CONTENT_POS_LE] THEN
+    ASM_MESON_TAC[HAS_INTEGRAL_NULL_EQ; CONTENT_LT_NZ]] THEN
+  ONCE_REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [has_integral]) THEN
+  DISCH_THEN(MP_TAC o SPEC
+    `norm(i:real^N) - B * content(interval[a:real^M,b])`) THEN
+  ASM_REWRITE_TAC[REAL_SUB_LT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPECL [`d:real^M->real^M->bool`; `a:real^M`; `b:real^M`]
+        FINE_DIVISION_EXISTS) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN
+   (X_CHOOSE_THEN `p:(real^M#(real^M->bool)->bool)` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `p:(real^M#(real^M->bool)->bool)`) THEN
+  ASM_MESON_TAC[lemma; RSUM_BOUND]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Similar theorems about relationship among components.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let RSUM_COMPONENT_LE = prove
+ (`!p a b f:real^M->real^N g:real^M->real^N.
+       p tagged_division_of interval[a,b] /\ 1 <= i /\ i <= dimindex(:N) /\
+       (!x. x IN interval[a,b] ==> (f x)$i <= (g x)$i)
+       ==> vsum p (\(x,k). content k % f x)$i <=
+           vsum p (\(x,k). content k % g x)$i`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[VSUM_COMPONENT] THEN
+  MATCH_MP_TAC SUM_LE THEN
+  ASM_SIMP_TAC[FORALL_PAIR_THM; VECTOR_MUL_COMPONENT] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+  ASM_MESON_TAC[SUBSET; REAL_LE_LMUL; CONTENT_POS_LE]);;
+
+let HAS_INTEGRAL_COMPONENT_LE = prove
+ (`!f:real^M->real^N g:real^M->real^N s i j k.
+        1 <= k /\ k <= dimindex(:N) /\
+        (f has_integral i) s /\ (g has_integral j) s /\
+        (!x. x IN s ==> (f x)$k <= (g x)$k)
+        ==> i$k <= j$k`,
+  SUBGOAL_THEN
+   `!f:real^M->real^N g:real^M->real^N a b i j k.
+        1 <= k /\ k <= dimindex(:N) /\
+        (f has_integral i) (interval[a,b]) /\
+        (g has_integral j) (interval[a,b]) /\
+        (!x. x IN interval[a,b] ==> (f x)$k <= (g x)$k)
+        ==> i$k <= j$k`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `~(&0 < i - j) ==> i <= j`) THEN DISCH_TAC THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `((i:real^N)$k - (j:real^N)$k) / &3` o
+       GEN_REWRITE_RULE I [has_integral])) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d1:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `d2:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `?p. p tagged_division_of interval[a:real^M,b] /\
+                      d1 fine p /\ d2 fine p`
+    STRIP_ASSUME_TAC THENL
+     [REWRITE_TAC[GSYM FINE_INTER] THEN MATCH_MP_TAC FINE_DIVISION_EXISTS THEN
+      ASM_SIMP_TAC[GAUGE_INTER];
+      ALL_TAC] THEN
+    REPEAT
+     (FIRST_X_ASSUM(MP_TAC o SPEC `p:real^M#(real^M->bool)->bool`) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o MATCH_MP REAL_LT_IMP_LE) THEN
+      DISCH_THEN(MP_TAC o SPEC `k:num` o MATCH_MP NORM_BOUND_COMPONENT_LE) THEN
+      ASM_SIMP_TAC[VECTOR_SUB_COMPONENT]) THEN
+    SUBGOAL_THEN
+     `vsum p (\(x,l:real^M->bool). content l % (f:real^M->real^N) x)$k <=
+      vsum p (\(x,l). content l % (g:real^M->real^N) x)$k`
+    MP_TAC THENL
+     [MATCH_MP_TAC RSUM_COMPONENT_LE THEN ASM_MESON_TAC[];
+      UNDISCH_TAC `&0 < (i:real^N)$k - (j:real^N)$k` THEN
+      SPEC_TAC(`vsum p (\(x:real^M,l:real^M->bool).
+                                content l % (f x):real^N)$k`,
+               `fs:real`) THEN
+      SPEC_TAC(`vsum p (\(x:real^M,l:real^M->bool).
+                                content l % (g x):real^N)$k`,
+               `gs:real`) THEN
+      REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[has_integral_alt] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  STRIP_TAC THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC
+   `((i:real^N)$k - (j:real^N)$k) / &2`)) THEN
+  ASM_REWRITE_TAC[REAL_HALF; REAL_SUB_LT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B1:real` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B2:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPEC
+   `ball(vec 0,B1) UNION ball(vec 0:real^M,B2)`
+   BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+  REWRITE_TAC[BOUNDED_UNION; BOUNDED_BALL; UNION_SUBSET; NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN
+  DISCH_THEN(CONJUNCTS_THEN(ANTE_RES_THEN MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `w:real^N` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `(z:real^N)$k <= (w:real^N)$k` MP_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN
+    MAP_EVERY EXISTS_TAC
+     [`(\x. if x IN s then f x else vec 0):real^M->real^N`;
+      `(\x. if x IN s then g x else vec 0):real^M->real^N`;
+      `a:real^M`; `b:real^M`] THEN
+    ASM_MESON_TAC[REAL_LE_REFL];
+    MP_TAC(ISPECL [`w - j:real^N`; `k:num`] COMPONENT_LE_NORM) THEN
+    MP_TAC(ISPECL [`z - i:real^N`; `k:num`] COMPONENT_LE_NORM) THEN
+    ASM_REWRITE_TAC[] THEN
+    SIMP_TAC[VECTOR_SUB_COMPONENT; ASSUME `1 <= k`;
+              ASSUME `k <= dimindex(:N)`] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM REAL_NOT_LE])) THEN
+    NORM_ARITH_TAC]);;
+
+let INTEGRAL_COMPONENT_LE = prove
+ (`!f:real^M->real^N g:real^M->real^N s k.
+        1 <= k /\ k <= dimindex(:N) /\
+        f integrable_on s /\ g integrable_on s /\
+        (!x. x IN s ==> (f x)$k <= (g x)$k)
+        ==> (integral s f)$k <= (integral s g)$k`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_COMPONENT_LE THEN
+  ASM_MESON_TAC[INTEGRABLE_INTEGRAL]);;
+
+let HAS_INTEGRAL_DROP_LE = prove
+ (`!f:real^M->real^1 g:real^M->real^1 s i j.
+        (f has_integral i) s /\ (g has_integral j) s /\
+        (!x. x IN s ==> drop(f x) <= drop(g x))
+        ==> drop i <= drop j`,
+  REWRITE_TAC[drop] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMPONENT_LE THEN
+  REWRITE_TAC[DIMINDEX_1; LE_REFL] THEN ASM_MESON_TAC[]);;
+
+let INTEGRAL_DROP_LE = prove
+ (`!f:real^M->real^1 g:real^M->real^1 s.
+        f integrable_on s /\ g integrable_on s /\
+        (!x. x IN s ==> drop(f x) <= drop(g x))
+        ==> drop(integral s f) <= drop(integral s g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_DROP_LE THEN
+  ASM_MESON_TAC[INTEGRABLE_INTEGRAL]);;
+
+let HAS_INTEGRAL_COMPONENT_POS = prove
+ (`!f:real^M->real^N s i k.
+        1 <= k /\ k <= dimindex(:N) /\
+        (f has_integral i) s /\
+        (!x. x IN s ==> &0 <= (f x)$k)
+        ==> &0 <= i$k`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(\x. vec 0):real^M->real^N`; `f:real^M->real^N`;
+                 `s:real^M->bool`; `vec 0:real^N`;
+                 `i:real^N`; `k:num`] HAS_INTEGRAL_COMPONENT_LE) THEN
+  ASM_SIMP_TAC[VEC_COMPONENT; HAS_INTEGRAL_0]);;
+
+let INTEGRAL_COMPONENT_POS = prove
+ (`!f:real^M->real^N s k.
+        1 <= k /\ k <= dimindex(:N) /\
+        f integrable_on s /\
+        (!x. x IN s ==> &0 <= (f x)$k)
+        ==> &0 <= (integral s f)$k`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_COMPONENT_POS THEN
+  ASM_MESON_TAC[INTEGRABLE_INTEGRAL]);;
+
+let HAS_INTEGRAL_DROP_POS = prove
+ (`!f:real^M->real^1 s i.
+        (f has_integral i) s /\
+        (!x. x IN s ==> &0 <= drop(f x))
+        ==> &0 <= drop i`,
+  REWRITE_TAC[drop] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMPONENT_POS THEN
+  REWRITE_TAC[DIMINDEX_1; LE_REFL] THEN ASM_MESON_TAC[]);;
+
+let INTEGRAL_DROP_POS = prove
+ (`!f:real^M->real^1 s.
+        f integrable_on s /\
+        (!x. x IN s ==> &0 <= drop(f x))
+        ==> &0 <= drop(integral s f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_DROP_POS THEN
+  ASM_MESON_TAC[INTEGRABLE_INTEGRAL]);;
+
+let HAS_INTEGRAL_COMPONENT_NEG = prove
+ (`!f:real^M->real^N s i k.
+        1 <= k /\ k <= dimindex(:N) /\
+        (f has_integral i) s /\
+        (!x. x IN s ==> (f x)$k <= &0)
+        ==> i$k <= &0`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `(\x. vec 0):real^M->real^N`;
+                 `s:real^M->bool`; `i:real^N`; `vec 0:real^N`;
+                 `k:num`] HAS_INTEGRAL_COMPONENT_LE) THEN
+  ASM_SIMP_TAC[VEC_COMPONENT; HAS_INTEGRAL_0]);;
+
+let HAS_INTEGRAL_DROP_NEG = prove
+ (`!f:real^M->real^1 s i.
+        (f has_integral i) s /\
+        (!x. x IN s ==> drop(f x) <= &0)
+        ==> drop i <= &0`,
+  REWRITE_TAC[drop] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMPONENT_NEG THEN
+  REWRITE_TAC[DIMINDEX_1; LE_REFL] THEN ASM_MESON_TAC[]);;
+
+let HAS_INTEGRAL_COMPONENT_LBOUND = prove
+ (`!f:real^M->real^N a b i k.
+        (f has_integral i) (interval[a,b]) /\ 1 <= k /\ k <= dimindex(:N) /\
+        (!x. x IN interval[a,b] ==> B <= f(x)$k)
+        ==> B * content(interval[a,b]) <= i$k`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(\x. lambda i. B):real^M->real^N`; `f:real^M->real^N`;
+                 `interval[a:real^M,b]`;
+                 `content(interval[a:real^M,b]) % (lambda i. B):real^N`;
+                 `i:real^N`; `k:num`]
+                HAS_INTEGRAL_COMPONENT_LE) THEN
+  ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; LAMBDA_BETA; HAS_INTEGRAL_CONST] THEN
+  REWRITE_TAC[REAL_MUL_AC]);;
+
+let HAS_INTEGRAL_COMPONENT_UBOUND = prove
+ (`!f:real^M->real^N a b i k.
+        (f has_integral i) (interval[a,b]) /\ 1 <= k /\ k <= dimindex(:N) /\
+        (!x. x IN interval[a,b] ==> f(x)$k <= B)
+        ==> i$k <= B * content(interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `(\x. lambda i. B):real^M->real^N`;
+                 `interval[a:real^M,b]`; `i:real^N`;
+                 `content(interval[a:real^M,b]) % (lambda i. B):real^N`;
+                 `k:num`]
+                HAS_INTEGRAL_COMPONENT_LE) THEN
+  ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; LAMBDA_BETA; HAS_INTEGRAL_CONST] THEN
+  REWRITE_TAC[REAL_MUL_AC]);;
+
+let INTEGRAL_COMPONENT_LBOUND = prove
+ (`!f:real^M->real^N a b k.
+        f integrable_on interval[a,b] /\ 1 <= k /\ k <= dimindex(:N) /\
+        (!x. x IN interval[a,b] ==> B <= f(x)$k)
+        ==> B * content(interval[a,b]) <= (integral(interval[a,b]) f)$k`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_COMPONENT_LBOUND THEN
+  EXISTS_TAC `f:real^M->real^N` THEN
+  ASM_REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL]);;
+
+let INTEGRAL_COMPONENT_UBOUND = prove
+ (`!f:real^M->real^N a b k.
+        f integrable_on interval[a,b] /\ 1 <= k /\ k <= dimindex(:N) /\
+        (!x. x IN interval[a,b] ==> f(x)$k <= B)
+        ==> (integral(interval[a,b]) f)$k <= B * content(interval[a,b])`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_COMPONENT_UBOUND THEN
+  EXISTS_TAC `f:real^M->real^N` THEN
+  ASM_REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Uniform limit of integrable functions is integrable.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let INTEGRABLE_UNIFORM_LIMIT = prove
+ (`!f a b. (!e. &0 < e
+                ==> ?g. (!x. x IN interval[a,b] ==> norm(f x - g x) <= e) /\
+                        g integrable_on interval[a,b] )
+           ==> (f:real^M->real^N) integrable_on interval[a,b]`,
+  let lemma = prove
+   (`x <= norm(a + b) + c ==> x <= norm(a) + norm(b) + c`,
+    MESON_TAC[REAL_ADD_AC; NORM_TRIANGLE; REAL_LE_TRANS; REAL_LE_RADD]) in
+  let (lemma1,lemma2) = (CONJ_PAIR o prove)
+   (`(norm(s2 - s1) <= e / &2 /\
+      norm(s1 - i1) < e / &4 /\ norm(s2 - i2) < e / &4
+      ==> norm(i1 - i2) < e) /\
+     (norm(sf - sg) <= e / &3
+      ==> norm(i - s) < e / &3 ==> norm(sg - i) < e / &3 ==> norm(sf - s) < e)`,
+    CONJ_TAC THENL
+     [REWRITE_TAC[CONJ_ASSOC] THEN
+      GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o ONCE_DEPTH_CONV) [NORM_SUB] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `w <= x + y + z + &0
+        ==> (x <= e / &2 /\ y < e / &4) /\ z < e / &4 ==> w < e`);
+      MATCH_MP_TAC(REAL_ARITH
+      `w <= x + y + z + &0
+      ==> x <= e / &3 ==> y < e / &3 ==> z < e / &3 ==> w < e`)] THEN
+    REPEAT(MATCH_MP_TAC lemma) THEN REWRITE_TAC[REAL_ADD_RID] THEN
+    MATCH_MP_TAC REAL_EQ_IMP_LE THEN AP_TERM_TAC THEN VECTOR_ARITH_TAC) in
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `&0 < content(interval[a:real^M,b])` THENL
+   [ALL_TAC;
+    ASM_MESON_TAC[HAS_INTEGRAL_NULL; CONTENT_LT_NZ; integrable_on]] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN `n:num` o SPEC `inv(&n + &1)`) THEN
+  REWRITE_TAC[REAL_LT_INV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+  REWRITE_TAC[FORALL_AND_THM; SKOLEM_THM; integrable_on] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:num->real^M->real^N` (CONJUNCTS_THEN2
+   ASSUME_TAC (X_CHOOSE_TAC `i:num->real^N`))) THEN
+  SUBGOAL_THEN `cauchy(i:num->real^N)` MP_TAC THENL
+   [REWRITE_TAC[cauchy] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    MP_TAC(SPEC `e / &4 / content(interval[a:real^M,b])`
+        REAL_ARCH_INV) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN STRIP_TAC THEN
+    MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN REWRITE_TAC[GE] THEN
+    STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE BINDER_CONV [has_integral]) THEN
+    ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &4`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+    DISCH_THEN(fun th -> MP_TAC(SPEC `m:num` th) THEN
+      MP_TAC(SPEC `n:num` th)) THEN
+    DISCH_THEN(X_CHOOSE_THEN `gn:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `gm:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`(\x. gm(x) INTER gn(x)):real^M->real^M->bool`;
+                   `a:real^M`; `b:real^M`] FINE_DIVISION_EXISTS) THEN
+    ASM_SIMP_TAC[GAUGE_INTER; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `p:(real^M#(real^M->bool))->bool` THEN STRIP_TAC THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `p:(real^M#(real^M->bool))->bool`)) THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[CONV_RULE(REWR_CONV FINE_INTER) th]) THEN
+    SUBGOAL_THEN `norm(vsum p (\(x,k:real^M->bool). content k % g (n:num) x) -
+                       vsum p (\(x:real^M,k). content k % g m x :real^N))
+                  <= e / &2`
+    MP_TAC THENL [ALL_TAC; ASM_REWRITE_TAC[dist] THEN MESON_TAC[lemma1]] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `&2 / &N * content(interval[a:real^M,b])` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC RSUM_DIFF_BOUND;
+      ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ] THEN
+      ASM_REAL_ARITH_TAC] THEN
+    ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(fun th -> MP_TAC(SPECL [`n:num`; `x:real^M`] th) THEN
+      MP_TAC(SPECL [`m:num`; `x:real^M`] th)) THEN
+    ASM_REWRITE_TAC[IMP_IMP] THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o LAND_CONV) [NORM_SUB] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP REAL_LE_ADD2) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP NORM_TRIANGLE_LE) THEN
+    MATCH_MP_TAC(REAL_ARITH `u = v /\ a <= inv(x) /\ b <= inv(x) ==>
+                                u <= a + b ==> v <= &2 / x`) THEN
+    CONJ_TAC THENL [AP_TERM_TAC THEN VECTOR_ARITH_TAC; ALL_TAC] THEN
+    CONJ_TAC THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+    REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+    ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[GSYM CONVERGENT_EQ_CAUCHY] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `s:real^N` THEN DISCH_TAC THEN
+  REWRITE_TAC[has_integral] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e / &3` o GEN_REWRITE_RULE I
+   [LIM_SEQUENTIALLY]) THEN
+  ASM_SIMP_TAC[dist; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_TAC `N1:num`) THEN
+  MP_TAC(SPEC `e / &3 / content(interval[a:real^M,b])` REAL_ARCH_INV) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N2:num` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE BINDER_CONV [has_integral]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`N1 + N2:num`; `e / &3`]) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^M->real^M->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `p:real^M#(real^M->bool)->bool` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `p:real^M#(real^M->bool)->bool`) THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o C MATCH_MP (ARITH_RULE `N1:num <= N1 + N2`)) THEN
+  MATCH_MP_TAC lemma2 THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `inv(&(N1 + N2) + &1) * content(interval[a:real^M,b])` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC RSUM_DIFF_BOUND THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+   `x < a ==> y <= x ==> y <= a`)) THEN
+  MATCH_MP_TAC REAL_LE_INV2 THEN
+  REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+  ASM_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Negligible sets.                                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let indicator = new_definition
+  `indicator s :real^M->real^1 = \x. if x IN s then vec 1 else vec 0`;;
+
+let DROP_INDICATOR = prove
+ (`!s x. drop(indicator s x) = if x IN s then &1 else &0`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[indicator] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[DROP_VEC]);;
+
+let DROP_INDICATOR_POS_LE = prove
+ (`!s x. &0 <= drop(indicator s x)`,
+  REWRITE_TAC[DROP_INDICATOR] THEN REAL_ARITH_TAC);;
+
+let DROP_INDICATOR_LE_1 = prove
+ (`!s x. drop(indicator s x) <= &1`,
+  REWRITE_TAC[DROP_INDICATOR] THEN REAL_ARITH_TAC);;
+
+let DROP_INDICATOR_ABS_LE_1 = prove
+ (`!s x. abs(drop(indicator s x)) <= &1`,
+  REWRITE_TAC[DROP_INDICATOR] THEN REAL_ARITH_TAC);;
+
+let negligible = new_definition
+ `negligible s <=> !a b. (indicator s has_integral (vec 0)) (interval[a,b])`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Negligibility of hyperplane.                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let VSUM_NONZERO_IMAGE_LEMMA = prove
+ (`!s f:A->B g:B->real^N a.
+        FINITE s /\ g(a) = vec 0 /\
+        (!x y. x IN s /\ y IN s /\ f x = f y /\ ~(x = y) ==> g(f x) = vec 0)
+       ==> vsum {f x |x| x IN s /\ ~(f x = a)} g =
+           vsum s (g o f)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `FINITE {(f:A->B) x |x| x IN s /\ ~(f x = a)}`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `IMAGE (f:A->B) s` THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; SUBSET; IN_IMAGE; IN_ELIM_THM] THEN MESON_TAC[];
+    ASM_SIMP_TAC[VSUM] THEN MATCH_MP_TAC ITERATE_NONZERO_IMAGE_LEMMA THEN
+    ASM_REWRITE_TAC[NEUTRAL_VECTOR_ADD; MONOIDAL_VECTOR_ADD]]);;
+
+let INTERVAL_DOUBLESPLIT = prove
+ (`1 <= k /\ k <= dimindex(:N)
+      ==> interval[a,b] INTER {x:real^N | abs(x$k - c) <= e} =
+          interval[(lambda i. if i = k then max (a$k) (c - e) else a$i),
+                   (lambda i. if i = k then min (b$k) (c + e) else b$i)]`,
+   REWRITE_TAC[REAL_ARITH `abs(x - c) <= e <=> x >= c - e /\ x <= c + e`] THEN
+   REWRITE_TAC[SET_RULE `s INTER {x | P x /\ Q x} =
+                        (s INTER {x | Q x}) INTER {x | P x}`] THEN
+   SIMP_TAC[INTERVAL_SPLIT]);;
+
+let DIVISION_DOUBLESPLIT = prove
+ (`!p a b:real^N k c e.
+        p division_of interval[a,b] /\ 1 <= k /\ k <= dimindex(:N)
+        ==> {l INTER {x | abs(x$k - c) <= e} |l|
+                l IN p /\ ~(l INTER {x | abs(x$k - c) <= e} = {})}
+            division_of (interval[a,b] INTER {x | abs(x$k - c) <= e})`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `c + e:real` o MATCH_MP DIVISION_SPLIT) THEN
+  DISCH_THEN(MP_TAC o CONJUNCT1) THEN
+  ASM_SIMP_TAC[INTERVAL_SPLIT] THEN
+  FIRST_ASSUM MP_TAC THEN REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (TAUT
+   `(a /\ b /\ c) /\ d ==> d /\ b /\ c`)) THEN
+  DISCH_THEN(MP_TAC o CONJUNCT2 o SPEC `c - e:real` o
+    MATCH_MP DIVISION_SPLIT) THEN
+  ASM_SIMP_TAC[INTERVAL_DOUBLESPLIT; INTERVAL_SPLIT] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[REAL_ARITH `abs(x - c) <= e <=> x >= c - e /\ x <= c + e`] THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN
+  GEN_TAC THEN REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN REWRITE_TAC[GSYM CONJ_ASSOC] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c /\ d <=> c /\ a /\ b /\ d`] THEN
+  REWRITE_TAC[UNWIND_THM2] THEN AP_TERM_TAC THEN ABS_TAC THEN SET_TAC[]);;
+
+let CONTENT_DOUBLESPLIT = prove
+ (`!a b:real^N k c e.
+        &0 < e /\ 1 <= k /\ k <= dimindex(:N)
+        ==> ?d. &0 < d /\
+                content(interval[a,b] INTER {x | abs(x$k - c) <= d}) < e`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `content(interval[a:real^N,b]) = &0` THENL
+   [EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `content(interval[a:real^N,b])` THEN
+    CONJ_TAC THENL [FIRST_X_ASSUM(K ALL_TAC o SYM); ASM_REWRITE_TAC[]] THEN
+    ASM_SIMP_TAC[INTERVAL_DOUBLESPLIT] THEN MATCH_MP_TAC CONTENT_SUBSET THEN
+    ASM_SIMP_TAC[GSYM INTERVAL_DOUBLESPLIT] THEN SET_TAC[];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [CONTENT_EQ_0]) THEN
+  REWRITE_TAC[NOT_EXISTS_THM; TAUT `~(a /\ b /\ c) <=> a /\ b ==> ~c`] THEN
+  REWRITE_TAC[REAL_NOT_LE] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `&0 < product ((1..dimindex (:N)) DELETE k)
+                              (\i. (b:real^N)$i - (a:real^N)$i)`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC PRODUCT_POS_LT THEN
+    ASM_SIMP_TAC[FINITE_DELETE; FINITE_NUMSEG; IN_DELETE; IN_NUMSEG;
+                 REAL_SUB_LT];
+    ALL_TAC] THEN
+  ABBREV_TAC `d = e / &3 / product ((1..dimindex (:N)) DELETE k)
+                                   (\i. (b:real^N)$i - (a:real^N)$i)` THEN
+  EXISTS_TAC `d:real` THEN SUBGOAL_THEN `&0 < d` ASSUME_TAC THENL
+   [EXPAND_TAC "d" THEN MATCH_MP_TAC REAL_LT_DIV THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[content; INTERVAL_DOUBLESPLIT] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(ASSUME_TAC o GEN_REWRITE_RULE I [INTERVAL_NE_EMPTY]) THEN
+  SUBGOAL_THEN `1..dimindex(:N) = k INSERT ((1..dimindex(:N)) DELETE k)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_INSERT; IN_DELETE; IN_NUMSEG] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  SIMP_TAC[PRODUCT_CLAUSES; FINITE_NUMSEG; FINITE_DELETE; IN_DELETE] THEN
+  ASM_SIMP_TAC[INTERVAL_LOWERBOUND; INTERVAL_UPPERBOUND; REAL_LT_IMP_LE;
+                LAMBDA_BETA; IN_DELETE; IN_NUMSEG] THEN
+  SUBGOAL_THEN
+   `product ((1..dimindex (:N)) DELETE k)
+     (\j. ((lambda i. if i = k then min (b$k) (c + d) else b$i):real^N)$j -
+          ((lambda i. if i = k then max (a$k) (c - d) else a$i):real^N)$j) =
+    product ((1..dimindex (:N)) DELETE k)
+            (\i. (b:real^N)$i - (a:real^N)$i)`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC PRODUCT_EQ THEN
+    SIMP_TAC[IN_DELETE; IN_NUMSEG; LAMBDA_BETA];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `&2 * d` THEN
+  CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH `&0 < d /\ &3 * d <= x ==> &2 * d < x`) THEN
+  ASM_REWRITE_TAC[] THEN EXPAND_TAC "d" THEN REAL_ARITH_TAC);;
+
+let NEGLIGIBLE_STANDARD_HYPERPLANE = prove
+ (`!c k. 1 <= k /\ k <= dimindex(:N) ==> negligible {x:real^N | x$k = c}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[negligible; has_integral] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[VECTOR_SUB_RZERO] THEN
+  MP_TAC(ISPECL [`a:real^N`; `b:real^N`; `k:num`; `c:real`; `e:real`]
+        CONTENT_DOUBLESPLIT) THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+  EXISTS_TAC `\x:real^N. ball(x,d)` THEN ASM_SIMP_TAC[GAUGE_BALL] THEN
+  ABBREV_TAC `i = indicator {x:real^N | x$k = c}` THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `vsum p (\(x,l). content l % i x) =
+    vsum p (\(x,l). content(l INTER {x:real^N | abs(x$k - c) <= d}) %
+                    (i:real^N->real^1) x)`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC VSUM_EQ THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `l:real^N->bool`] THEN
+    DISCH_TAC THEN EXPAND_TAC "i" THEN REWRITE_TAC[indicator] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[VECTOR_MUL_RZERO] THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+    DISCH_THEN(MP_TAC o SPECL [`x:real^N`; `l:real^N->bool`]) THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(SET_RULE `s SUBSET t ==> l SUBSET s ==> l = l INTER t`) THEN
+    REWRITE_TAC[SUBSET; IN_BALL; IN_ELIM_THM; dist] THEN
+    UNDISCH_THEN `(x:real^N)$k = c` (SUBST1_TAC o SYM) THEN
+    ASM_SIMP_TAC[GSYM VECTOR_SUB_COMPONENT] THEN
+    ONCE_REWRITE_TAC[NORM_SUB] THEN
+    ASM_MESON_TAC[COMPONENT_LE_NORM; REAL_LE_TRANS; REAL_LT_IMP_LE];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC
+   `norm(vsum p (\(x:real^N,l).
+          content(l INTER {x:real^N | abs(x$k - c) <= d}) %
+         vec 1:real^1))` THEN
+  CONJ_TAC THENL
+   [FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+    ASM_SIMP_TAC[VSUM_REAL; NORM_LIFT] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ x <= y ==> abs(x) <= abs(y)`) THEN
+    REWRITE_TAC[o_DEF; LAMBDA_PAIR_THM; DROP_CMUL] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC SUM_POS_LE; MATCH_MP_TAC SUM_LE] THEN
+    ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `l:real^N->bool`] THEN STRIP_TAC THENL
+     [MATCH_MP_TAC REAL_LE_MUL; MATCH_MP_TAC REAL_LE_LMUL] THEN
+    EXPAND_TAC "i" THEN REWRITE_TAC[DROP_VEC] THEN
+    REWRITE_TAC[DROP_INDICATOR_POS_LE; DROP_INDICATOR_LE_1] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+    DISCH_THEN(MP_TAC o SPECL [`x:real^N`; `l:real^N->bool`] o
+        el 1 o CONJUNCTS) THEN
+    ASM_REWRITE_TAC[] THEN
+    STRIP_TAC THEN ASM_SIMP_TAC[INTERVAL_DOUBLESPLIT; CONTENT_POS_LE];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`(\l. content (l INTER {x | abs (x$k - c) <= d}) % vec 1):
+                  (real^N->bool)->real^1`;
+                 `p:real^N#(real^N->bool)->bool`;
+                 `interval[a:real^N,b]`]
+        VSUM_OVER_TAGGED_DIVISION_LEMMA) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN STRIP_TAC THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISJ1_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `!x. x = &0 /\ &0 <= y /\ y <= x ==> y = &0`) THEN
+    EXISTS_TAC `content(interval[u:real^N,v])` THEN
+    CONJ_TAC THEN POP_ASSUM MP_TAC THEN REWRITE_TAC[] THEN
+    DISCH_THEN(K ALL_TAC) THEN
+    ASM_SIMP_TAC[CONTENT_POS_LE; INTERVAL_DOUBLESPLIT] THEN
+    MATCH_MP_TAC CONTENT_SUBSET THEN
+    ASM_SIMP_TAC[GSYM INTERVAL_DOUBLESPLIT] THEN SET_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  MP_TAC(ISPECL
+     [`IMAGE SND (p:real^N#(real^N->bool)->bool)`;
+      `\l. l INTER {x:real^N | abs (x$k - c) <= d}`;
+      `\l:real^N->bool. content l % vec 1 :real^1`;
+      `{}:real^N->bool`] VSUM_NONZERO_IMAGE_LEMMA) THEN
+    REWRITE_TAC[o_DEF] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_TAGGED_DIVISION) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL [ASM_MESON_TAC[DIVISION_OF_FINITE]; ALL_TAC] THEN
+    REWRITE_TAC[CONTENT_EMPTY; VECTOR_MUL_LZERO] THEN
+    ONCE_REWRITE_TAC[IMP_CONJ] THEN
+    REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN DISCH_TAC THEN
+    X_GEN_TAC `m:real^N->bool` THEN STRIP_TAC THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISJ1_TAC THEN
+    SIMP_TAC[INTERVAL_DOUBLESPLIT; ASSUME `1 <= k`;
+             ASSUME `k <= dimindex(:N)`] THEN
+    REWRITE_TAC[CONTENT_EQ_0_INTERIOR] THEN
+    ASM_SIMP_TAC[GSYM INTERVAL_DOUBLESPLIT] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+    DISCH_THEN(MP_TAC o SPECL [`interval[u:real^N,v]`; `m:real^N->bool`] o
+      el 2 o CONJUNCTS) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(SET_RULE
+      `u SUBSET s /\ u SUBSET t ==> s INTER t = {} ==> u = {}`) THEN
+    CONJ_TAC THEN MATCH_MP_TAC SUBSET_INTERIOR THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[o_DEF] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC
+   `&1 * content(interval[a,b] INTER {x:real^N | abs (x$k - c) <= d})` THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_REWRITE_TAC[REAL_MUL_LID]] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP(REWRITE_RULE[IMP_CONJ]
+    DIVISION_DOUBLESPLIT)) THEN
+  DISCH_THEN(MP_TAC o SPECL [`k:num`; `c:real`; `d:real`]) THEN
+  ASM_SIMP_TAC[INTERVAL_DOUBLESPLIT] THEN DISCH_TAC THEN
+  MATCH_MP_TAC DSUM_BOUND THEN
+  ASM_SIMP_TAC[NORM_REAL; VEC_COMPONENT; DIMINDEX_1; LE_REFL] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* A technical lemma about "refinement" of division.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let TAGGED_DIVISION_FINER = prove
+ (`!p a b:real^N d. p tagged_division_of interval[a,b] /\ gauge d
+             ==> ?q. q tagged_division_of interval[a,b] /\ d fine q /\
+                     !x k. (x,k) IN p /\ k SUBSET d(x) ==> (x,k) IN q`,
+  let lemma1 = prove
+   (`{k | ?x. (x,k) IN p} = IMAGE SND p`,
+    REWRITE_TAC[EXTENSION; EXISTS_PAIR_THM; IN_IMAGE; IN_ELIM_THM] THEN
+    MESON_TAC[]) in
+  SUBGOAL_THEN
+   `!a b:real^N d p.
+       FINITE p
+       ==> p tagged_partial_division_of interval[a,b] /\ gauge d
+           ==> ?q. q tagged_division_of (UNIONS {k | ?x. x,k IN p}) /\
+                   d fine q /\
+                   !x k. (x,k) IN p /\ k SUBSET d(x) ==> (x,k) IN q`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    GEN_REWRITE_TAC LAND_CONV [tagged_division_of] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (SUBST1_TAC o SYM)) THEN
+    FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[IMP_IMP]) THEN
+    ASM_MESON_TAC[tagged_partial_division_of]] THEN
+  GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN CONJ_TAC THENL
+   [DISCH_THEN(K ALL_TAC) THEN
+    REWRITE_TAC[SET_RULE `UNIONS {k | ?x. x,k IN {}} = {}`] THEN
+    EXISTS_TAC `{}:real^N#(real^N->bool)->bool` THEN
+    REWRITE_TAC[fine; NOT_IN_EMPTY; TAGGED_DIVISION_OF_EMPTY];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC I [FORALL_PAIR_THM] THEN MAP_EVERY X_GEN_TAC
+   [`x:real^N`; `k:real^N->bool`; `p:real^N#(real^N->bool)->bool`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN MATCH_MP_TAC TAGGED_PARTIAL_DIVISION_SUBSET THEN
+    EXISTS_TAC `(x:real^N,k:real^N->bool) INSERT p` THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `q1:real^N#(real^N->bool)->bool`
+    STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `UNIONS {l:real^N->bool | ?y:real^N. (y,l) IN (x,k) INSERT p} =
+    k UNION UNIONS {l | ?y. (y,l) IN p}`
+  SUBST1_TAC THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN REWRITE_TAC[IN_UNION; IN_UNIONS] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_INSERT; PAIR_EQ] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `?u v:real^N. k = interval[u,v]` MP_TAC THENL
+   [ASM_MESON_TAC[IN_INSERT; tagged_partial_division_of]; ALL_TAC] THEN
+  DISCH_THEN(REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC) THEN
+  ASM_CASES_TAC `interval[u,v] SUBSET ((d:real^N->real^N->bool) x)` THENL
+   [EXISTS_TAC `{(x:real^N,interval[u:real^N,v])} UNION q1` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC TAGGED_DIVISION_UNION THEN ASM_REWRITE_TAC[] THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC TAGGED_DIVISION_OF_SELF THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+         [tagged_partial_division_of]) THEN
+        REWRITE_TAC[IN_INSERT; PAIR_EQ] THEN MESON_TAC[];
+        ALL_TAC];
+      CONJ_TAC THENL
+       [MATCH_MP_TAC FINE_UNION THEN ASM_REWRITE_TAC[] THEN
+        REWRITE_TAC[fine; IN_SING; PAIR_EQ] THEN ASM_MESON_TAC[];
+        ALL_TAC] THEN
+      ASM_REWRITE_TAC[IN_INSERT; PAIR_EQ; IN_UNION; IN_SING] THEN
+      ASM_MESON_TAC[]];
+    FIRST_ASSUM(MP_TAC o SPECL [`u:real^N`; `v:real^N`] o MATCH_MP
+      FINE_DIVISION_EXISTS) THEN
+    DISCH_THEN(X_CHOOSE_THEN `q2:real^N#(real^N->bool)->bool`
+      STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `q2 UNION q1:real^N#(real^N->bool)->bool` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC TAGGED_DIVISION_UNION THEN ASM_REWRITE_TAC[];
+      ASM_SIMP_TAC[FINE_UNION] THEN
+      ASM_REWRITE_TAC[IN_INSERT; PAIR_EQ; IN_UNION; IN_SING] THEN
+      ASM_MESON_TAC[]]] THEN
+  (MATCH_MP_TAC INTER_INTERIOR_UNIONS_INTERVALS THEN
+   REWRITE_TAC[lemma1; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+   FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+      [tagged_partial_division_of]) THEN
+   REWRITE_TAC[IN_INSERT; FINITE_INSERT; PAIR_EQ] THEN
+   STRIP_TAC THEN ASM_SIMP_TAC[FINITE_IMAGE] THEN CONJ_TAC THENL
+    [REWRITE_TAC[INTERIOR_CLOSED_INTERVAL; OPEN_INTERVAL]; ALL_TAC] THEN
+   CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+   REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+   ASM_MESON_TAC[]));;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence the main theorem about negligible sets.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_NEGLIGIBLE = prove
+ (`!f:real^M->real^N s t.
+        negligible s /\ (!x. x IN (t DIFF s) ==> f x = vec 0)
+        ==> (f has_integral (vec 0)) t`,
+  let lemma = prove
+   (`!f:B->real g:A#B->real s t.
+          FINITE s /\ FINITE t /\
+          (!x y. (x,y) IN t ==> &0 <= g(x,y)) /\
+          (!y. y IN s ==> ?x. (x,y) IN t /\ f(y) <= g(x,y))
+          ==> sum s f <= sum t g`,
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_LE_INCLUDED THEN
+    EXISTS_TAC `SND:A#B->B` THEN
+    REWRITE_TAC[EXISTS_PAIR_THM; FORALL_PAIR_THM] THEN
+    ASM_MESON_TAC[]) in
+  SUBGOAL_THEN
+   `!f:real^M->real^N s a b.
+        negligible s /\ (!x. ~(x IN s) ==> f x = vec 0)
+        ==> (f has_integral (vec 0)) (interval[a,b])`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[IN_DIFF] THEN REPEAT STRIP_TAC THEN
+    ONCE_REWRITE_TAC[has_integral_alt] THEN COND_CASES_TAC THENL
+     [MATCH_MP_TAC HAS_INTEGRAL_EQ THEN
+      EXISTS_TAC `\x. if x IN t then (f:real^M->real^N) x else vec 0` THEN
+      SIMP_TAC[] THEN
+      FIRST_X_ASSUM(CHOOSE_THEN(CHOOSE_THEN SUBST_ALL_TAC)) THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    GEN_TAC THEN DISCH_TAC THEN EXISTS_TAC `&1` THEN
+    REWRITE_TAC[REAL_LT_01] THEN
+    REPEAT STRIP_TAC THEN EXISTS_TAC `vec 0:real^N` THEN
+    ASM_REWRITE_TAC[NORM_0; VECTOR_SUB_REFL] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    EXISTS_TAC `s:real^M->bool` THEN ASM_MESON_TAC[]] THEN
+  REWRITE_TAC[negligible; has_integral; RIGHT_FORALL_IMP_THM] THEN
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  MAP_EVERY(fun t -> MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC t)
+   [`a:real^M`; `b:real^M`] THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO] THEN DISCH_TAC THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN `n:num` o
+      SPEC `e / &2 / ((&n + &1) * &2 pow n)`) THEN
+  REWRITE_TAC[real_div; REAL_MUL_POS_LT] THEN REWRITE_TAC[GSYM real_div] THEN
+  ASM_SIMP_TAC[REAL_LT_INV_EQ; REAL_LT_MUL; REAL_POW_LT; REAL_OF_NUM_LT;
+           FORALL_AND_THM; ARITH; REAL_ARITH `&0 < &n + &1`; SKOLEM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:num->real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\x. (d:num->real^M->real^M->bool)
+                  (num_of_int(int_of_real(floor(norm(f x:real^N))))) x` THEN
+  CONJ_TAC THENL [REWRITE_TAC[gauge] THEN ASM_MESON_TAC[gauge]; ALL_TAC] THEN
+  X_GEN_TAC `p:real^M#(real^M->bool)->bool` THEN STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  ASM_CASES_TAC `p:real^M#(real^M->bool)->bool = {}` THEN
+  ASM_REWRITE_TAC[VSUM_CLAUSES; NORM_0] THEN
+  MP_TAC(SPEC `sup(IMAGE (\(x,k:real^M->bool). norm((f:real^M->real^N) x)) p)`
+    REAL_ARCH_SIMPLE) THEN
+  ASM_SIMP_TAC[REAL_SUP_LE_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM] THEN
+  DISCH_THEN(X_CHOOSE_TAC `N:num`) THEN
+  MP_TAC(GEN `i:num`
+   (ISPECL [`p:real^M#(real^M->bool)->bool`; `a:real^M`; `b:real^M`;
+                `(d:num->real^M->real^M->bool) i`]
+                TAGGED_DIVISION_FINER)) THEN
+  ASM_REWRITE_TAC[SKOLEM_THM; RIGHT_IMP_EXISTS_THM; FORALL_AND_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `q:num->real^M#(real^M->bool)->bool`
+        STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC
+   `sum(0..N+1) (\i. (&i + &1) *
+                     norm(vsum (q i) (\(x:real^M,k:real^M->bool).
+                                            content k % indicator s x)))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `sum (0..N+1) (\i. e / &2 / &2 pow i)` THEN CONJ_TAC THENL
+     [ALL_TAC;
+      REWRITE_TAC[real_div; SUM_LMUL; GSYM REAL_POW_INV] THEN
+      REWRITE_TAC[SUM_GP; LT] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      REWRITE_TAC[REAL_ARITH `(e * &1 / &2) * (&1 - x) / (&1 / &2) < e <=>
+                                &0 < e * x`] THEN
+      ASM_SIMP_TAC[REAL_LT_MUL; REAL_POW_LT; REAL_ARITH `&0 < &1 / &2`]] THEN
+    MATCH_MP_TAC SUM_LE_NUMSEG THEN REPEAT STRIP_TAC THEN
+    REWRITE_TAC[] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+    REWRITE_TAC[real_div] THEN ONCE_REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
+    REWRITE_TAC[GSYM REAL_INV_MUL] THEN REWRITE_TAC[GSYM real_div] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN MATCH_MP_TAC REAL_LT_IMP_LE THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]] THEN
+  FIRST_ASSUM(ASSUME_TAC o GEN `i:num` o
+    MATCH_MP TAGGED_DIVISION_OF_FINITE o SPEC `i:num`) THEN
+  ASM_SIMP_TAC[VSUM_REAL; NORM_LIFT] THEN
+  REWRITE_TAC[o_DEF; LAMBDA_PAIR_THM; DROP_CMUL] THEN
+  REWRITE_TAC[real_abs] THEN
+  SUBGOAL_THEN
+   `!i:num. &0 <= sum (q i) (\(x:real^M,y:real^M->bool).
+              content y * drop (indicator s x))`
+  ASSUME_TAC THENL
+   [REPEAT GEN_TAC THEN MATCH_MP_TAC SUM_POS_LE THEN
+    ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_MUL THEN
+    REWRITE_TAC[DROP_INDICATOR_POS_LE] THEN
+    ASM_MESON_TAC[TAGGED_DIVISION_OF; CONTENT_POS_LE];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[GSYM SUM_LMUL] THEN
+  REWRITE_TAC[LAMBDA_PAIR_THM] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) VSUM_NORM o lhand o snd) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REAL_ARITH `x <= y ==> n <= x ==> n <= y`) THEN
+  ASM_SIMP_TAC[SUM_SUM_PRODUCT; FINITE_NUMSEG] THEN
+  MATCH_MP_TAC lemma THEN
+  ASM_SIMP_TAC[FINITE_PRODUCT_DEPENDENT; FORALL_PAIR_THM; FINITE_NUMSEG] THEN
+  REWRITE_TAC[IN_ELIM_PAIR_THM] THEN CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_MUL THEN
+    CONJ_TAC THENL [REAL_ARITH_TAC; MATCH_MP_TAC REAL_LE_MUL] THEN
+    REWRITE_TAC[DROP_INDICATOR_POS_LE] THEN
+    ASM_MESON_TAC[TAGGED_DIVISION_OF; CONTENT_POS_LE];
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`x:real^M`; `k:real^M->bool`]) THEN
+  ASM_REWRITE_TAC[] THEN ABBREV_TAC
+   `n = num_of_int(int_of_real(floor(norm((f:real^M->real^N) x))))` THEN
+  SUBGOAL_THEN `&n <= norm((f:real^M->real^N) x) /\
+                norm(f x) < &n + &1`
+  STRIP_ASSUME_TAC THENL
+   [SUBGOAL_THEN `&n = floor(norm((f:real^M->real^N) x))`
+     (fun th -> MESON_TAC[th; FLOOR]) THEN
+    EXPAND_TAC "n" THEN
+    MP_TAC(ISPEC `norm((f:real^M->real^N) x)` FLOOR_POS) THEN
+    REWRITE_TAC[NORM_POS_LE; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `m:num` THEN DISCH_THEN SUBST1_TAC THEN
+    REWRITE_TAC[GSYM int_of_num; NUM_OF_INT_OF_NUM];
+    ALL_TAC] THEN
+  DISCH_TAC THEN EXISTS_TAC `n:num` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[IN_NUMSEG; LE_0] THEN
+    REWRITE_TAC[GSYM REAL_OF_NUM_LE; GSYM REAL_OF_NUM_ADD] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `norm((f:real^M->real^N) x)` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= n ==> x <= n + &1`) THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `(x:real^M) IN s` THEN ASM_SIMP_TAC[indicator] THEN
+  REWRITE_TAC[DROP_VEC; REAL_MUL_RZERO; NORM_0;
+              VECTOR_MUL_RZERO; REAL_LE_REFL] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  REWRITE_TAC[DROP_VEC; REAL_MUL_RID; NORM_MUL] THEN
+  SUBGOAL_THEN `&0 <= content(k:real^M->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[TAGGED_DIVISION_OF; CONTENT_POS_LE]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[real_abs] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_LE]);;
+
+let HAS_INTEGRAL_SPIKE = prove
+ (`!f:real^M->real^N g s t.
+        negligible s /\ (!x. x IN (t DIFF s) ==> g x = f x) /\
+        (f has_integral y) t
+        ==> (g has_integral y) t`,
+  SUBGOAL_THEN
+   `!f:real^M->real^N g s a b y.
+        negligible s /\ (!x. x IN (interval[a,b] DIFF s) ==> g x = f x)
+        ==> (f has_integral y) (interval[a,b])
+            ==> (g has_integral y) (interval[a,b])`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+     `((\x. (f:real^M->real^N)(x) + (g(x) - f(x))) has_integral (y + vec 0))
+      (interval[a,b])`
+    MP_TAC THENL
+     [ALL_TAC;
+      REWRITE_TAC[VECTOR_ARITH `f + g - f = g /\ f + vec 0 = f`; ETA_AX]] THEN
+    MATCH_MP_TAC HAS_INTEGRAL_ADD THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC HAS_INTEGRAL_NEGLIGIBLE THEN
+    EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[VECTOR_SUB_EQ] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ONCE_REWRITE_TAC[has_integral_alt] THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[] THENL
+   [FIRST_X_ASSUM(CHOOSE_THEN(CHOOSE_THEN SUBST_ALL_TAC)) THEN ASM_MESON_TAC[];
+    ALL_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
+  REPEAT(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
+  FIRST_X_ASSUM MATCH_MP_TAC THEN EXISTS_TAC `s:real^M->bool` THEN
+  ASM_REWRITE_TAC[] THEN ASM SET_TAC[]);;
+
+let HAS_INTEGRAL_SPIKE_EQ = prove
+ (`!f:real^M->real^N g s t y.
+        negligible s /\ (!x. x IN (t DIFF s) ==> g x = f x)
+        ==> ((f has_integral y) t <=> (g has_integral y) t)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPIKE THENL
+   [EXISTS_TAC `f:real^M->real^N`; EXISTS_TAC `g:real^M->real^N`] THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[NORM_SUB]);;
+
+let INTEGRABLE_SPIKE = prove
+ (`!f:real^M->real^N g s t.
+        negligible s /\ (!x. x IN (t DIFF s) ==> g x = f x)
+        ==> f integrable_on t ==> g integrable_on  t`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[integrable_on] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+  MP_TAC(SPEC_ALL HAS_INTEGRAL_SPIKE) THEN ASM_REWRITE_TAC[]);;
+
+let INTEGRAL_SPIKE = prove
+ (`!f:real^M->real^N g s t y.
+        negligible s /\ (!x. x IN (t DIFF s) ==> g x = f x)
+        ==> integral t f = integral t g`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[integral] THEN
+  AP_TERM_TAC THEN ABS_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_SPIKE_EQ THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some other trivialities about negligible sets.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_SUBSET = prove
+ (`!s:real^N->bool t:real^N->bool.
+        negligible s /\ t SUBSET s ==> negligible t`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[negligible] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPIKE THEN
+  MAP_EVERY EXISTS_TAC [`(\x. vec 0):real^N->real^1`; `s:real^N->bool`] THEN
+  ASM_REWRITE_TAC[HAS_INTEGRAL_0] THEN
+  REWRITE_TAC[indicator] THEN ASM SET_TAC[]);;
+
+let NEGLIGIBLE_DIFF = prove
+ (`!s t:real^N->bool. negligible s ==> negligible(s DIFF t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[SUBSET_DIFF]);;
+
+let NEGLIGIBLE_INTER = prove
+ (`!s t. negligible s \/ negligible t ==> negligible(s INTER t)`,
+  MESON_TAC[NEGLIGIBLE_SUBSET; INTER_SUBSET]);;
+
+let NEGLIGIBLE_UNION = prove
+ (`!s t:real^N->bool.
+        negligible s /\ negligible t ==> negligible (s UNION t)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN FIRST_ASSUM MP_TAC THEN
+  REWRITE_TAC[negligible; AND_FORALL_THM] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `a:real^N` THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `b:real^N` THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_ADD) THEN
+  REWRITE_TAC[VECTOR_ADD_LID] THEN MATCH_MP_TAC EQ_IMP THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPIKE_EQ THEN
+  EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+  SIMP_TAC[indicator; IN_UNION; IN_DIFF; VECTOR_ADD_LID]);;
+
+let NEGLIGIBLE_UNION_EQ = prove
+ (`!s t:real^N->bool.
+        negligible (s UNION t) <=> negligible s /\ negligible t`,
+  MESON_TAC[NEGLIGIBLE_UNION; SUBSET_UNION; NEGLIGIBLE_SUBSET]);;
+
+let NEGLIGIBLE_SING = prove
+ (`!a:real^N. negligible {a}`,
+  GEN_TAC THEN MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `{x | (x:real^N)$1 = (a:real^N)$1}` THEN
+  SIMP_TAC[NEGLIGIBLE_STANDARD_HYPERPLANE; LE_REFL; DIMINDEX_GE_1] THEN
+  SET_TAC[]);;
+
+let NEGLIGIBLE_INSERT = prove
+ (`!a:real^N s. negligible(a INSERT s) <=> negligible s`,
+  ONCE_REWRITE_TAC[SET_RULE `a INSERT s = {a} UNION s`] THEN
+  REWRITE_TAC[NEGLIGIBLE_UNION_EQ; NEGLIGIBLE_SING]);;
+
+let NEGLIGIBLE_EMPTY = prove
+ (`negligible {}`,
+  MESON_TAC[EMPTY_SUBSET; NEGLIGIBLE_SUBSET; NEGLIGIBLE_SING]);;
+
+let NEGLIGIBLE_FINITE = prove
+ (`!s. FINITE s ==> negligible s`,
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[NEGLIGIBLE_EMPTY; NEGLIGIBLE_INSERT]);;
+
+let NEGLIGIBLE_UNIONS = prove
+ (`!s. FINITE s /\ (!t. t IN s ==> negligible t)
+       ==> negligible(UNIONS s)`,
+  REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[UNIONS_0; UNIONS_INSERT; NEGLIGIBLE_EMPTY; IN_INSERT] THEN
+  SIMP_TAC[NEGLIGIBLE_UNION]);;
+
+let NEGLIGIBLE = prove
+ (`!s:real^N->bool. negligible s <=> !t. (indicator s has_integral vec 0) t`,
+  GEN_TAC THEN EQ_TAC THENL
+   [ALL_TAC; REWRITE_TAC[negligible] THEN SIMP_TAC[]] THEN
+  DISCH_TAC THEN GEN_TAC THEN ONCE_REWRITE_TAC[has_integral_alt] THEN
+  COND_CASES_TAC THENL [ASM_MESON_TAC[negligible]; ALL_TAC] THEN
+  GEN_TAC THEN DISCH_TAC THEN EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN
+  REPEAT STRIP_TAC THEN EXISTS_TAC `vec 0:real^1` THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `s INTER t:real^N->bool`]
+        NEGLIGIBLE_SUBSET) THEN
+  ASM_REWRITE_TAC[INTER_SUBSET; negligible; VECTOR_SUB_REFL; NORM_0] THEN
+  REWRITE_TAC[indicator; IN_INTER] THEN
+  SIMP_TAC[TAUT `(if p /\ q then r else s) =
+                 (if q then if p then r else s else s)`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Finite or empty cases of the spike theorem are quite commonly needed.     *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_SPIKE_FINITE = prove
+ (`!f:real^M->real^N g s t y.
+        FINITE s /\ (!x. x IN (t DIFF s) ==> g x = f x) /\
+        (f has_integral y) t
+        ==> (g has_integral y) t`,
+  MESON_TAC[HAS_INTEGRAL_SPIKE; NEGLIGIBLE_FINITE]);;
+
+let HAS_INTEGRAL_SPIKE_FINITE_EQ = prove
+ (`!f:real^M->real^N g s y.
+        FINITE s /\ (!x. x IN (t DIFF s) ==> g x = f x)
+        ==> ((f has_integral y) t <=> (g has_integral y) t)`,
+  MESON_TAC[HAS_INTEGRAL_SPIKE_FINITE]);;
+
+let INTEGRABLE_SPIKE_FINITE = prove
+ (`!f:real^M->real^N g s.
+        FINITE s /\ (!x. x IN (t DIFF s) ==> g x = f x)
+        ==> f integrable_on t
+            ==> g integrable_on  t`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[integrable_on] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+  MP_TAC(SPEC_ALL HAS_INTEGRAL_SPIKE_FINITE) THEN ASM_REWRITE_TAC[]);;
+
+let INTEGRAL_EQ = prove
+ (`!f:real^M->real^N g s.
+        (!x. x IN s ==> f x = g x) ==> integral s f = integral s g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_SPIKE THEN
+  EXISTS_TAC `{}:real^M->bool` THEN ASM_SIMP_TAC[NEGLIGIBLE_EMPTY; IN_DIFF]);;
+
+let INTEGRAL_EQ_0 = prove
+ (`!f:real^M->real^N s. (!x. x IN s ==> f x = vec 0) ==> integral s f = vec 0`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `integral s ((\x. vec 0):real^M->real^N)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC INTEGRAL_EQ THEN ASM_REWRITE_TAC[];
+    REWRITE_TAC[INTEGRAL_0]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In particular, the boundary of an interval is negligible.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_FRONTIER_INTERVAL = prove
+ (`!a b:real^N. negligible(interval[a,b] DIFF interval(a,b))`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `UNIONS (IMAGE (\k. {x:real^N | x$k = (a:real^N)$k} UNION
+                                 {x:real^N | x$k = (b:real^N)$k})
+                            (1..dimindex(:N)))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC NEGLIGIBLE_UNIONS THEN
+    SIMP_TAC[FINITE_IMAGE; FINITE_NUMSEG; FORALL_IN_IMAGE] THEN
+    SIMP_TAC[IN_NUMSEG; NEGLIGIBLE_UNION_EQ; NEGLIGIBLE_STANDARD_HYPERPLANE];
+    REWRITE_TAC[SUBSET; IN_DIFF; IN_INTERVAL; IN_UNIONS; EXISTS_IN_IMAGE] THEN
+    REWRITE_TAC[IN_NUMSEG; IN_UNION; IN_ELIM_THM; REAL_LT_LE] THEN
+    MESON_TAC[]]);;
+
+let HAS_INTEGRAL_SPIKE_INTERIOR = prove
+ (`!f:real^M->real^N g a b y.
+        (!x. x IN interval(a,b) ==> g x = f x) /\
+        (f has_integral y) (interval[a,b])
+        ==> (g has_integral y) (interval[a,b])`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN DISCH_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+                           HAS_INTEGRAL_SPIKE) THEN
+  EXISTS_TAC `interval[a:real^M,b] DIFF interval(a,b)` THEN
+  REWRITE_TAC[NEGLIGIBLE_FRONTIER_INTERVAL] THEN ASM SET_TAC[]);;
+
+let HAS_INTEGRAL_SPIKE_INTERIOR_EQ = prove
+ (`!f:real^M->real^N g a b y.
+        (!x. x IN interval(a,b) ==> g x = f x)
+        ==> ((f has_integral y) (interval[a,b]) <=>
+             (g has_integral y) (interval[a,b]))`,
+  MESON_TAC[HAS_INTEGRAL_SPIKE_INTERIOR]);;
+
+let INTEGRABLE_SPIKE_INTERIOR = prove
+ (`!f:real^M->real^N g a b.
+        (!x. x IN interval(a,b) ==> g x = f x)
+        ==> f integrable_on (interval[a,b])
+            ==> g integrable_on  (interval[a,b])`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[integrable_on] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+  MP_TAC(SPEC_ALL HAS_INTEGRAL_SPIKE_INTERIOR) THEN ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Integrability of continuous functions.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let NEUTRAL_AND = prove
+ (`neutral(/\) = T`,
+  REWRITE_TAC[neutral; FORALL_BOOL_THM] THEN MESON_TAC[]);;
+
+let MONOIDAL_AND = prove
+ (`monoidal(/\)`,
+  REWRITE_TAC[monoidal; NEUTRAL_AND; CONJ_ACI]);;
+
+let ITERATE_AND = prove
+ (`!p s. FINITE s ==> (iterate(/\) s p <=> !x. x IN s ==> p x)`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  ASM_SIMP_TAC[MONOIDAL_AND; NEUTRAL_AND; ITERATE_CLAUSES] THEN SET_TAC[]);;
+
+let OPERATIVE_DIVISION_AND = prove
+ (`!P d a b. operative(/\) P /\ d division_of interval[a,b]
+             ==> ((!i. i IN d ==> P i) <=> P(interval[a,b]))`,
+  REPEAT GEN_TAC THEN DISCH_THEN(ASSUME_TAC o CONJ MONOIDAL_AND) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP OPERATIVE_DIVISION) THEN
+  ASM_MESON_TAC[ITERATE_AND; DIVISION_OF_FINITE]);;
+
+let OPERATIVE_APPROXIMABLE = prove
+ (`!f:real^M->real^N e.
+        &0 <= e
+        ==> operative(/\)
+               (\i. ?g. (!x. x IN i ==> norm (f x - g x) <= e) /\
+                        g integrable_on i)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[operative; NEUTRAL_AND] THEN CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN EXISTS_TAC `f:real^M->real^N` THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0; integrable_on] THEN
+    ASM_MESON_TAC[HAS_INTEGRAL_NULL];
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^M`; `v:real^M`; `c:real`; `k:num`] THEN
+  STRIP_TAC THEN EQ_TAC THENL
+   [ASM_MESON_TAC[INTEGRABLE_SPLIT; IN_INTER]; ALL_TAC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `g1:real^M->real^N` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `g2:real^M->real^N` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `\x. if x$k = c then (f:real^M->real^N)(x) else
+                  if x$k <= c then g1(x) else g2(x)` THEN
+  CONJ_TAC THENL
+   [GEN_TAC THEN STRIP_TAC THEN REWRITE_TAC[] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTER; IN_ELIM_THM]) THEN
+    ASM_MESON_TAC[REAL_ARITH `x <= c \/ x >= c`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(\x:real^M. if x$k = c then f x else if x$k <= c then g1 x else g2 x)
+    integrable_on (interval[u,v] INTER {x | x$k <= c}) /\
+    (\x. if x$k = c then f x :real^N else if x$k <= c then g1 x else g2 x)
+    integrable_on (interval[u,v] INTER {x | x$k >= c})`
+  MP_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[integrable_on] THEN ASM_MESON_TAC[HAS_INTEGRAL_SPLIT]] THEN
+  CONJ_TAC THENL
+   [UNDISCH_TAC
+     `(g1:real^M->real^N) integrable_on (interval[u,v] INTER {x | x$k <= c})`;
+    UNDISCH_TAC
+    `(g2:real^M->real^N) integrable_on (interval[u,v] INTER {x | x$k >= c})`
+   ] THEN
+  ASM_SIMP_TAC[INTERVAL_SPLIT] THEN MATCH_MP_TAC INTEGRABLE_SPIKE THEN
+  ASM_SIMP_TAC[GSYM INTERVAL_SPLIT] THEN
+  EXISTS_TAC `{x:real^M | x$k = c}` THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_STANDARD_HYPERPLANE; IN_DIFF; IN_INTER; IN_ELIM_THM;
+               REAL_ARITH `x >= c /\ ~(x = c) ==> ~(x <= c)`] THEN
+  EXISTS_TAC `e:real` THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[IN_INTER; IN_ELIM_THM]);;
+
+let APPROXIMABLE_ON_DIVISION = prove
+ (`!f:real^M->real^N d a b.
+        &0 <= e /\
+        (d division_of interval[a,b]) /\
+        (!i. i IN d
+             ==> ?g. (!x. x IN i ==> norm (f x - g x) <= e) /\
+                     g integrable_on i)
+        ==> ?g. (!x. x IN interval[a,b] ==> norm (f x - g x) <= e) /\
+                g integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(/\)`; `d:(real^M->bool)->bool`;
+                 `a:real^M`; `b:real^M`;
+                 `\i. ?g:real^M->real^N.
+                       (!x. x IN i ==> norm (f x - g x) <= e) /\
+                       g integrable_on i`]
+                OPERATIVE_DIVISION) THEN
+  ASM_SIMP_TAC[OPERATIVE_APPROXIMABLE; MONOIDAL_AND] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  ASM_SIMP_TAC[ITERATE_AND]);;
+
+let INTEGRABLE_CONTINUOUS = prove
+ (`!f:real^M->real^N a b.
+        f continuous_on interval[a,b] ==> f integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_UNIFORM_LIMIT THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MATCH_MP_TAC APPROXIMABLE_ON_DIVISION THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    COMPACT_UNIFORMLY_CONTINUOUS)) THEN
+  REWRITE_TAC[COMPACT_INTERVAL; uniformly_continuous_on] THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[dist] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `?p. p tagged_division_of interval[a:real^M,b] /\ (\x. ball(x,d)) fine p`
+  STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[FINE_DIVISION_EXISTS; GAUGE_BALL]; ALL_TAC] THEN
+  EXISTS_TAC `IMAGE SND (p:real^M#(real^M->bool)->bool)` THEN
+  ASM_SIMP_TAC[DIVISION_OF_TAGGED_DIVISION] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `l:real^M->bool`] THEN
+  DISCH_TAC THEN EXISTS_TAC `\y:real^M. (f:real^M->real^N) x` THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+  DISCH_THEN(MP_TAC o
+    SPECL [`x:real^M`; `l:real^M->bool`] o el 1 o CONJUNCTS) THEN
+  ASM_REWRITE_TAC[SUBSET] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+  REWRITE_TAC[SUBSET; IN_BALL; dist] THEN
+   FIRST_X_ASSUM SUBST_ALL_TAC THEN REPEAT STRIP_TAC THENL
+   [ASM_MESON_TAC[REAL_LT_IMP_LE; NORM_SUB];
+    REWRITE_TAC[integrable_on] THEN
+    EXISTS_TAC `content(interval[a':real^M,b']) % (f:real^M->real^N) x` THEN
+    REWRITE_TAC[HAS_INTEGRAL_CONST]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Specialization of additivity to one dimension.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let OPERATIVE_1_LT = prove
+ (`!op. monoidal op
+        ==> !f. operative op f <=>
+                (!a b. drop b <= drop a ==> f(interval[a,b]) = neutral op) /\
+                (!a b c. drop a < drop c /\ drop c < drop b
+                         ==> op (f(interval[a,c])) (f(interval[c,b])) =
+                             f(interval[a,b]))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[operative; CONTENT_EQ_0_1] THEN
+  MATCH_MP_TAC(TAUT `(a ==> (b <=> c)) ==> (a /\ b <=> a /\ c)`) THEN
+  DISCH_TAC THEN REWRITE_TAC[FORALL_1; DIMINDEX_1] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `a:real^1` THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `b:real^1` THEN
+  EQ_TAC THEN DISCH_TAC THENL
+   [X_GEN_TAC `c:real^1` THEN FIRST_ASSUM(SUBST1_TAC o SPEC `drop c`) THEN
+    DISCH_TAC THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP REAL_LT_TRANS) THEN
+    ASM_SIMP_TAC[INTERVAL_SPLIT; DIMINDEX_1; LE_REFL; REAL_LT_IMP_LE] THEN
+    BINOP_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    REWRITE_TAC[CONS_11; PAIR_EQ] THEN
+    SIMP_TAC[FORALL_1; CART_EQ; DIMINDEX_1; LAMBDA_BETA; LE_REFL] THEN
+    REWRITE_TAC[GSYM drop] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  X_GEN_TAC `d:real` THEN ABBREV_TAC `c = lift d` THEN
+  SUBGOAL_THEN `d = drop c` SUBST1_TAC THENL
+   [ASM_MESON_TAC[LIFT_DROP]; ALL_TAC] THEN
+  SIMP_TAC[INTERVAL_SPLIT; LE_REFL; drop; DIMINDEX_1] THEN
+  REWRITE_TAC[GSYM drop] THEN
+  DISJ_CASES_TAC(REAL_ARITH `drop c <= drop a \/ drop a < drop c`) THENL
+   [SUBGOAL_THEN
+     `content(interval[a:real^1,
+        (lambda i. if i = 1 then min (drop b) (drop c) else b$i)]) = &0 /\
+      interval[(lambda i. if i = 1 then max (drop a) (drop c) else a$i),b] =
+      interval[a,b]`
+    (CONJUNCTS_THEN2 MP_TAC SUBST1_TAC) THENL
+     [CONJ_TAC THENL
+       [SIMP_TAC[CONTENT_EQ_0_1];
+        AP_TERM_TAC THEN REWRITE_TAC[CONS_11; PAIR_EQ]] THEN
+      SIMP_TAC[drop; CART_EQ; FORALL_1; LAMBDA_BETA; DIMINDEX_1; LE_REFL] THEN
+      UNDISCH_TAC `drop c <= drop a` THEN REWRITE_TAC[drop] THEN
+      REAL_ARITH_TAC;
+      REWRITE_TAC[CONTENT_EQ_0_1] THEN
+      DISCH_THEN(ANTE_RES_THEN SUBST1_TAC) THEN ASM_MESON_TAC[monoidal]];
+    ALL_TAC] THEN
+  DISJ_CASES_TAC(REAL_ARITH `drop b <= drop c \/ drop c < drop b`) THENL
+   [SUBGOAL_THEN
+     `interval[a,(lambda i. if i = 1 then min (drop b) (drop c) else b$i)] =
+      interval[a,b] /\
+      content(interval
+        [(lambda i. if i = 1 then max (drop a) (drop c) else a$i),b]) = &0`
+      (CONJUNCTS_THEN2 SUBST1_TAC MP_TAC) THENL
+     [CONJ_TAC THENL
+       [AP_TERM_TAC THEN REWRITE_TAC[CONS_11; PAIR_EQ];
+        SIMP_TAC[CONTENT_EQ_0_1]] THEN
+      SIMP_TAC[drop; CART_EQ; FORALL_1; LAMBDA_BETA; DIMINDEX_1; LE_REFL] THEN
+      UNDISCH_TAC `drop b <= drop c` THEN REWRITE_TAC[drop] THEN
+      REAL_ARITH_TAC;
+      REWRITE_TAC[CONTENT_EQ_0_1] THEN
+      DISCH_THEN(ANTE_RES_THEN SUBST1_TAC) THEN ASM_MESON_TAC[monoidal]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(lambda i. if i = 1 then min (drop b) (drop c) else b$i) = c /\
+    (lambda i. if i = 1 then max (drop a) (drop c) else a$i) = c`
+   (fun th -> REWRITE_TAC[th] THEN ASM_MESON_TAC[]) THEN
+  SIMP_TAC[CART_EQ; FORALL_1; DIMINDEX_1; LE_REFL; LAMBDA_BETA] THEN
+  REWRITE_TAC[GSYM drop] THEN ASM_REAL_ARITH_TAC);;
+
+let OPERATIVE_1_LE = prove
+ (`!op. monoidal op
+        ==> !f. operative op f <=>
+                (!a b. drop b <= drop a ==> f(interval[a,b]) = neutral op) /\
+                (!a b c. drop a <= drop c /\ drop c <= drop b
+                         ==> op (f(interval[a,c])) (f(interval[c,b])) =
+                             f(interval[a,b]))`,
+  GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN EQ_TAC THENL
+   [ALL_TAC; ASM_SIMP_TAC[OPERATIVE_1_LT] THEN MESON_TAC[REAL_LT_IMP_LE]] THEN
+  REWRITE_TAC[operative; CONTENT_EQ_0_1] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[FORALL_1; DIMINDEX_1] THEN
+  MAP_EVERY (fun t -> MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC t)
+   [`a:real^1`; `b:real^1`] THEN DISCH_TAC THEN
+  X_GEN_TAC `c:real^1` THEN FIRST_ASSUM(SUBST1_TAC o SPEC `drop c`) THEN
+  DISCH_TAC THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP REAL_LE_TRANS) THEN
+  ASM_SIMP_TAC[INTERVAL_SPLIT; DIMINDEX_1; LE_REFL] THEN
+  BINOP_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[CONS_11; PAIR_EQ] THEN
+  SIMP_TAC[FORALL_1; CART_EQ; DIMINDEX_1; LAMBDA_BETA; LE_REFL] THEN
+  REWRITE_TAC[GSYM drop] THEN ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Special case of additivity we need for the FCT.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let ADDITIVE_TAGGED_DIVISION_1 = prove
+ (`!f:real^1->real^N p a b.
+        drop a <= drop b /\
+        p tagged_division_of interval[a,b]
+        ==> vsum p
+             (\(x,k). f(interval_upperbound k) - f(interval_lowerbound k)) =
+            f b - f a`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`(+):real^N->real^N->real^N`;
+    `p:(real^1#(real^1->bool)->bool)`;
+    `a:real^1`; `b:real^1`;
+    `(\k. if k = {} then vec 0
+          else f(interval_upperbound k) - f(interval_lowerbound k)):
+     ((real^1->bool)->real^N)`] OPERATIVE_TAGGED_DIVISION) THEN
+  ASM_SIMP_TAC[MONOIDAL_VECTOR_ADD; OPERATIVE_1_LT; NEUTRAL_VECTOR_ADD;
+               INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1] THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[INTERVAL_EQ_EMPTY_1; REAL_ARITH `a <= b ==> ~(b < a)`;
+                 REAL_LT_IMP_LE; CONTENT_EQ_0_1;
+                 INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1] THEN
+    SIMP_TAC[REAL_ARITH `b <= a ==> (b < a <=> ~(b = a))`] THEN
+    SIMP_TAC[DROP_EQ; TAUT
+      `(if ~p then x else y) = (if p then y else x)`] THEN
+    SIMP_TAC[INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1; REAL_LE_REFL] THEN
+    REWRITE_TAC[VECTOR_SUB_REFL; COND_ID; EQ_SYM_EQ] THEN
+    REPEAT GEN_TAC THEN DISCH_TAC THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP REAL_LT_TRANS) THEN
+    ASM_SIMP_TAC[INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1;
+                 REAL_ARITH `b < a ==> ~(a < b)`; REAL_LT_IMP_LE] THEN
+    MESON_TAC[VECTOR_ARITH `(c - a) + (b - c):real^N = b - a`];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[INTERVAL_EQ_EMPTY_1; GSYM REAL_NOT_LE] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  ASM_SIMP_TAC[GSYM VSUM] THEN MATCH_MP_TAC VSUM_EQ THEN
+  REWRITE_TAC[FORALL_PAIR_THM] THEN
+  ASM_MESON_TAC[TAGGED_DIVISION_OF; MEMBER_NOT_EMPTY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A useful lemma allowing us to factor out the content size.                *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_FACTOR_CONTENT = prove
+ (`!f:real^M->real^N i a b.
+      (f has_integral i) (interval[a,b]) <=>
+      (!e. &0 < e
+           ==> ?d. gauge d /\
+                   (!p. p tagged_division_of interval[a,b] /\ d fine p
+                        ==> norm (vsum p (\(x,k). content k % f x) - i)
+                            <= e * content(interval[a,b])))`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `content(interval[a:real^M,b]) = &0` THENL
+   [MP_TAC(SPECL [`f:real^M->real^N`; `a:real^M`; `b:real^M`]
+     VSUM_CONTENT_NULL) THEN
+    ASM_SIMP_TAC[HAS_INTEGRAL_NULL_EQ; VECTOR_SUB_LZERO; NORM_NEG] THEN
+    DISCH_TAC THEN REWRITE_TAC[REAL_MUL_RZERO; NORM_LE_0] THEN
+    ASM_MESON_TAC[FINE_DIVISION_EXISTS; GAUGE_TRIVIAL; REAL_LT_01];
+    ALL_TAC] THEN
+  REWRITE_TAC[has_integral] THEN EQ_TAC THEN DISCH_TAC THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o SPEC `e * content(interval[a:real^M,b])`) THEN
+    ASM_SIMP_TAC[REAL_LT_MUL; CONTENT_LT_NZ] THEN MESON_TAC[REAL_LT_IMP_LE];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2 / content(interval[a:real^M,b])`) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; CONTENT_LT_NZ; REAL_OF_NUM_LT; ARITH] THEN
+  ASM_SIMP_TAC[REAL_DIV_RMUL] THEN
+  ASM_MESON_TAC[REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Attempt a systematic general set of "offset" results for components.      *)
+(* ------------------------------------------------------------------------- *)
+
+let GAUGE_MODIFY = prove
+ (`!f:real^M->real^N.
+      (!s. open s ==> open {x | f(x) IN s})
+      ==> !d. gauge d ==> gauge (\x y. d (f x) (f y))`,
+  GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN
+  SIMP_TAC[gauge; IN] THEN DISCH_TAC THEN
+  X_GEN_TAC `x:real^M` THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(f:real^M->real^N) x`) THEN
+  DISCH_THEN(ANTE_RES_THEN MP_TAC o CONJUNCT2) THEN
+  MATCH_MP_TAC EQ_IMP THEN
+  AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+  REWRITE_TAC[IN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Integrabibility on subintervals.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let OPERATIVE_INTEGRABLE = prove
+ (`!f. operative (/\) (\i. f integrable_on i)`,
+  GEN_TAC THEN REWRITE_TAC[operative; NEUTRAL_AND] THEN CONJ_TAC THENL
+   [REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_NULL_EQ];
+    REPEAT STRIP_TAC THEN EQ_TAC THEN ASM_SIMP_TAC[INTEGRABLE_SPLIT] THEN
+    REWRITE_TAC[integrable_on] THEN ASM_MESON_TAC[HAS_INTEGRAL_SPLIT]]);;
+
+let INTEGRABLE_SUBINTERVAL = prove
+ (`!f:real^M->real^N a b c d.
+        f integrable_on interval[a,b] /\
+        interval[c,d] SUBSET interval[a,b]
+        ==> f integrable_on interval[c,d]`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `interval[c:real^M,d] = {}` THENL
+   [ASM_REWRITE_TAC[integrable_on] THEN
+    MESON_TAC[HAS_INTEGRAL_NULL; CONTENT_EMPTY; EMPTY_AS_INTERVAL];
+    ASM_MESON_TAC[OPERATIVE_INTEGRABLE; OPERATIVE_DIVISION_AND;
+                  PARTIAL_DIVISION_EXTEND_1]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Combining adjacent intervals in 1 dimension.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_COMBINE = prove
+ (`!f i:real^N j a b c.
+        drop a <= drop c /\ drop c <= drop b /\
+        (f has_integral i) (interval[a,c]) /\
+        (f has_integral j) (interval[c,b])
+        ==> (f has_integral (i + j)) (interval[a,b])`,
+  REPEAT STRIP_TAC THEN MP_TAC
+   ((CONJUNCT2 o GEN_REWRITE_RULE I
+     [MATCH_MP OPERATIVE_1_LE(MATCH_MP MONOIDAL_LIFTED MONOIDAL_VECTOR_ADD)])
+    (ISPEC `f:real^1->real^N` OPERATIVE_INTEGRAL)) THEN
+  DISCH_THEN(MP_TAC o SPECL [`a:real^1`; `b:real^1`; `c:real^1`]) THEN
+  ASM_REWRITE_TAC[] THEN
+  REPEAT(COND_CASES_TAC THEN
+   ASM_REWRITE_TAC[lifted; distinctness "option"; injectivity "option"]) THEN
+  ASM_MESON_TAC[INTEGRABLE_INTEGRAL; HAS_INTEGRAL_UNIQUE; integrable_on;
+                INTEGRAL_UNIQUE]);;
+
+let INTEGRAL_COMBINE = prove
+ (`!f:real^1->real^N a b c.
+        drop a <= drop c /\ drop c <= drop b /\ f integrable_on (interval[a,b])
+        ==> integral(interval[a,c]) f + integral(interval[c,b]) f =
+            integral(interval[a,b]) f`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC INTEGRAL_UNIQUE THEN MATCH_MP_TAC HAS_INTEGRAL_COMBINE THEN
+  EXISTS_TAC `c:real^1` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THEN
+  MATCH_MP_TAC INTEGRABLE_INTEGRAL THEN
+  MATCH_MP_TAC INTEGRABLE_SUBINTERVAL THEN
+  MAP_EVERY EXISTS_TAC [`a:real^1`; `b:real^1`] THEN
+  ASM_REWRITE_TAC[SUBSET_INTERVAL_1; REAL_LE_REFL]);;
+
+let INTEGRABLE_COMBINE = prove
+ (`!f a b c.
+        drop a <= drop c /\ drop c <= drop b /\
+        f integrable_on interval[a,c] /\
+        f integrable_on interval[c,b]
+        ==> f integrable_on interval[a,b]`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_COMBINE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Reduce integrability to "local" integrability.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let INTEGRABLE_ON_LITTLE_SUBINTERVALS = prove
+ (`!f:real^M->real^N a b.
+        (!x. x IN interval[a,b]
+             ==> ?d. &0 < d /\
+                     !u v. x IN interval[u,v] /\
+                           interval[u,v] SUBSET ball(x,d) /\
+                           interval[u,v] SUBSET interval[a,b]
+                           ==> f integrable_on interval[u,v])
+        ==> f integrable_on interval[a,b]`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; GAUGE_EXISTENCE_LEMMA] THEN
+  REWRITE_TAC[SKOLEM_THM; FORALL_AND_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real^M->real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`\x:real^M. ball(x,d x)`; `a:real^M`; `b:real^M`]
+                FINE_DIVISION_EXISTS) THEN
+  ASM_SIMP_TAC[GAUGE_BALL_DEPENDENT; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `p:real^M#(real^M->bool)->bool` THEN STRIP_TAC THEN
+  MP_TAC(MATCH_MP (REWRITE_RULE[IMP_CONJ] OPERATIVE_DIVISION_AND)
+         (ISPEC `f:real^M->real^N` OPERATIVE_INTEGRABLE)) THEN
+  DISCH_THEN(MP_TAC o SPECL
+   [`IMAGE SND (p:real^M#(real^M->bool)->bool)`; `a:real^M`; `b:real^M`]) THEN
+  ASM_SIMP_TAC[DIVISION_OF_TAGGED_DIVISION] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[FORALL_PAIR_THM] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o el 1 o CONJUNCTS o
+   GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+  REWRITE_TAC[IMP_IMP; AND_FORALL_THM] THEN
+  DISCH_THEN(MP_TAC o SPECL [`x:real^M`; `k:real^M->bool`]) THEN
+  ASM_REWRITE_TAC[] THEN  ASM_MESON_TAC[SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Second FCT or existence of antiderivative.                                *)
+(* ------------------------------------------------------------------------- *)
+
+let INTEGRAL_HAS_VECTOR_DERIVATIVE = prove
+ (`!f:real^1->real^N a b.
+     (f continuous_on interval[a,b])
+     ==> !x. x IN interval[a,b]
+             ==> ((\u. integral (interval[a,u]) f) has_vector_derivative f(x))
+                 (at x within interval[a,b])`,
+  REWRITE_TAC[IN_INTERVAL_1] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[has_vector_derivative; HAS_DERIVATIVE_WITHIN_ALT] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[linear; DROP_ADD; DROP_CMUL] THEN
+    CONJ_TAC THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    COMPACT_UNIFORMLY_CONTINUOUS)) THEN
+  REWRITE_TAC[COMPACT_INTERVAL; uniformly_continuous_on] THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN REWRITE_TAC[dist] THEN
+  X_GEN_TAC `d:real` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `y:real^1` THEN STRIP_TAC THEN
+  REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB] THEN
+  DISJ_CASES_TAC(REAL_ARITH `drop x <= drop y \/ drop y <= drop x`) THENL
+   [ASM_SIMP_TAC[REAL_ARITH `x <= y ==> abs(y - x) = y - x`];
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+     `fy - fx - (x - y) % c = --(fx - fy - (y - x) % c)`] THEN
+    ASM_SIMP_TAC[NORM_NEG; REAL_ARITH `x <= y ==> abs(x - y) = y - x`]] THEN
+  ASM_SIMP_TAC[GSYM CONTENT_1] THEN MATCH_MP_TAC HAS_INTEGRAL_BOUND THEN
+  EXISTS_TAC `(\u. f(u) - f(x)):real^1->real^N` THEN
+  (ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LT_IMP_LE THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN
+    REWRITE_TAC[IN_INTERVAL_1; NORM_REAL; DROP_SUB; GSYM drop] THEN
+    REAL_ARITH_TAC] THEN
+   MATCH_MP_TAC HAS_INTEGRAL_SUB THEN REWRITE_TAC[HAS_INTEGRAL_CONST]) THENL
+    [SUBGOAL_THEN
+      `integral(interval[a,x]) f + integral(interval[x,y]) f =
+       integral(interval[a,y]) f /\
+       ((f:real^1->real^N) has_integral integral(interval[x,y]) f)
+        (interval[x,y])`
+      (fun th -> MESON_TAC[th;
+          VECTOR_ARITH `a + b = c:real^N ==> c - a = b`]);
+     SUBGOAL_THEN
+      `integral(interval[a,y]) f + integral(interval[y,x]) f =
+       integral(interval[a,x]) f /\
+       ((f:real^1->real^N) has_integral integral(interval[y,x]) f)
+        (interval[y,x])`
+       (fun th -> MESON_TAC[th;
+         VECTOR_ARITH `a + b = c:real^N ==> c - a = b`])] THEN
+   (CONJ_TAC THENL
+     [MATCH_MP_TAC INTEGRAL_COMBINE;
+      MATCH_MP_TAC INTEGRABLE_INTEGRAL] THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC INTEGRABLE_SUBINTERVAL THEN
+    MAP_EVERY EXISTS_TAC [`a:real^1`; `b:real^1`] THEN
+    ASM_SIMP_TAC[INTEGRABLE_CONTINUOUS; SUBSET_INTERVAL_1] THEN
+    ASM_REAL_ARITH_TAC));;
+
+let ANTIDERIVATIVE_CONTINUOUS = prove
+ (`!f:real^1->real^N a b.
+     (f continuous_on interval[a,b])
+     ==> ?g. !x. x IN interval[a,b]
+                 ==> (g has_vector_derivative f(x))
+                     (at x within interval[a,b])`,
+  MESON_TAC[INTEGRAL_HAS_VECTOR_DERIVATIVE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* General "twiddling" for interval-to-interval function image.              *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_TWIDDLE = prove
+ (`!f:real^N->real^P (g:real^M->real^N) h r i a b.
+      &0 < r /\
+      (!x. h(g x) = x) /\ (!x. g(h x) = x) /\ (!x. g continuous at x) /\
+      (!u v. ?w z. IMAGE g (interval[u,v]) = interval[w,z]) /\
+      (!u v. ?w z. IMAGE h (interval[u,v]) = interval[w,z]) /\
+      (!u v. content(IMAGE g (interval[u,v])) = r * content(interval[u,v])) /\
+      (f has_integral i) (interval[a,b])
+      ==> ((\x. f(g x)) has_integral (inv r) % i) (IMAGE h (interval[a,b]))`,
+  let lemma0 = prove
+   (`(!x k. (x,k) IN IMAGE (\(x,k). f x,g k) p ==> P x k) <=>
+     (!x k. (x,k) IN p ==> P (f x) (g k))`,
+    REWRITE_TAC[IN_IMAGE; EXISTS_PAIR_THM; PAIR_EQ] THEN MESON_TAC[])
+  and lemma1 = prove
+   (`{k | ?x. (x,k) IN p} = IMAGE SND p`,
+    REWRITE_TAC[EXTENSION; EXISTS_PAIR_THM; IN_IMAGE; IN_ELIM_THM] THEN
+    MESON_TAC[])
+  and lemma2 = prove
+   (`SND o (\(x,k). f x,g k) = g o SND`,
+    REWRITE_TAC[FUN_EQ_THM; FORALL_PAIR_THM; o_DEF]) in
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `interval[a:real^N,b] = {}` THEN
+  ASM_SIMP_TAC[IMAGE_CLAUSES; HAS_INTEGRAL_EMPTY_EQ; VECTOR_MUL_RZERO] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[has_integral] THEN
+  ASM_REWRITE_TAC[has_integral_def; has_integral_compact_interval] THEN
+  DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e * r:real`) THEN
+  ASM_SIMP_TAC[REAL_LT_MUL] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real^N->real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\x y:real^M. (d:real^N->real^N->bool) (g x) (g y)` THEN
+  CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [gauge]) THEN
+    SIMP_TAC[gauge; IN; FORALL_AND_THM] THEN
+    STRIP_TAC THEN X_GEN_TAC `x:real^M` THEN
+    SUBGOAL_THEN `(\y:real^M. (d:real^N->real^N->bool) (g x) (g y)) =
+                  {y | g y IN (d (g x))}` SUBST1_TAC
+    THENL [SET_TAC[]; ASM_SIMP_TAC[CONTINUOUS_OPEN_PREIMAGE_UNIV]];
+    ALL_TAC] THEN
+  X_GEN_TAC `p:real^M#(real^M->bool)->bool` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC
+   `IMAGE (\(x,k). (g:real^M->real^N) x, IMAGE g k) p`) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [ALL_TAC;
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+      REWRITE_TAC[fine; lemma0] THEN
+      STRIP_TAC THEN REPEAT GEN_TAC THEN DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN
+      ASM SET_TAC[]] THEN
+    SUBGOAL_THEN
+     `interval[a,b] = IMAGE ((g:real^M->real^N) o h) (interval[a,b])`
+    SUBST1_TAC THENL [SIMP_TAC[o_DEF] THEN ASM SET_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN `?u v. IMAGE (h:real^N->real^M) (interval[a,b]) =
+                        interval[u,v]`
+    (REPEAT_TCL CHOOSE_THEN
+      (fun th -> SUBST_ALL_TAC th THEN ASSUME_TAC th)) THENL
+      [ASM_MESON_TAC[]; ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+    REWRITE_TAC[TAGGED_DIVISION_OF; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[lemma0] THEN REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+    REPEAT GEN_TAC THEN STRIP_TAC THEN CONJ_TAC THENL
+     [ASM_SIMP_TAC[FINITE_IMAGE]; ALL_TAC] THEN
+    CONJ_TAC THENL
+     [MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN
+      DISCH_TAC THEN
+      UNDISCH_TAC
+       `!x:real^M k.
+             x,k IN p
+             ==> x IN k /\
+                 k SUBSET interval[u,v] /\
+                 ?w z. k = interval[w,z]` THEN
+      DISCH_THEN(MP_TAC o SPECL [`x:real^M`; `k:real^M->bool`]) THEN
+      ASM_REWRITE_TAC[] THEN
+      REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THENL
+       [SET_TAC[];
+        REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[];
+        STRIP_TAC THEN ASM_REWRITE_TAC[]];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      ASM_REWRITE_TAC[IMAGE_o] THEN FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+      REWRITE_TAC[lemma1; GSYM IMAGE_o; lemma2] THEN
+      REWRITE_TAC[IMAGE_o; GSYM IMAGE_UNIONS; ETA_AX]] THEN
+    MAP_EVERY X_GEN_TAC [`x1:real^M`; `k1:real^M->bool`] THEN DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`x2:real^M`; `k2:real^M->bool`] THEN STRIP_TAC THEN
+    UNDISCH_TAC
+     `!x1:real^M k1:real^M->bool.
+             x1,k1 IN p
+             ==> (!x2 k2.
+                      x2,k2 IN p /\ ~(x1,k1 = x2,k2)
+                      ==> interior k1 INTER interior k2 = {})` THEN
+    DISCH_THEN(MP_TAC o SPECL [`x1:real^M`; `k1:real^M->bool`]) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o SPECL [`x2:real^M`; `k2:real^M->bool`]) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [ASM_MESON_TAC[PAIR_EQ]; ALL_TAC] THEN
+    MATCH_MP_TAC(SET_RULE
+     `interior(IMAGE f s) SUBSET IMAGE f (interior s) /\
+      interior(IMAGE f t) SUBSET IMAGE f (interior t) /\
+      (!x y. f x = f y ==> x = y)
+      ==> interior s INTER interior t = {}
+          ==> interior(IMAGE f s) INTER interior(IMAGE f t) = {}`) THEN
+    REPEAT CONJ_TAC THEN TRY(MATCH_MP_TAC INTERIOR_IMAGE_SUBSET) THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  W(fun (asl,w) -> MP_TAC(PART_MATCH (lhand o rand) VSUM_IMAGE
+                (lhand(rand(lhand(lhand w)))))) THEN
+  ANTS_TAC THENL
+   [FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+    ASM_REWRITE_TAC[FORALL_PAIR_THM; PAIR_EQ] THEN
+    REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    MATCH_MP_TAC MONO_AND THEN CONJ_TAC THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[o_DEF; LAMBDA_PAIR_THM] THEN
+  DISCH_TAC THEN MATCH_MP_TAC REAL_LT_LCANCEL_IMP THEN
+  EXISTS_TAC `abs r` THEN ASM_SIMP_TAC[REAL_ARITH `&0 < x ==> &0 < abs x`] THEN
+  REWRITE_TAC[GSYM NORM_MUL] THEN ASM_SIMP_TAC[real_abs; REAL_LT_IMP_LE] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+   `x < a * b ==> x = y ==> y < b * a`)) THEN
+  AP_TERM_TAC THEN REWRITE_TAC[VECTOR_SUB_LDISTRIB] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; REAL_LT_IMP_NZ] THEN
+  REWRITE_TAC[VECTOR_MUL_LID; GSYM VSUM_LMUL] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN MATCH_MP_TAC VSUM_EQ THEN
+  REWRITE_TAC[FORALL_PAIR_THM; VECTOR_MUL_ASSOC] THEN
+  REPEAT STRIP_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  ASM_MESON_TAC[TAGGED_DIVISION_OF]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Special case of a basic affine transformation.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let INTERVAL_IMAGE_AFFINITY_INTERVAL = prove
+ (`!a b m c. ?u v. IMAGE (\x. m % x + c) (interval[a,b]) = interval[u,v]`,
+  REWRITE_TAC[IMAGE_AFFINITY_INTERVAL] THEN
+  MESON_TAC[EMPTY_AS_INTERVAL]);;
+
+let CONTENT_IMAGE_AFFINITY_INTERVAL = prove
+ (`!a b:real^N m c.
+        content(IMAGE (\x. m % x + c) (interval[a,b])) =
+        (abs m) pow (dimindex(:N)) * content(interval[a,b])`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[IMAGE_AFFINITY_INTERVAL] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[CONTENT_EMPTY; REAL_MUL_RZERO] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN COND_CASES_TAC THEN
+  W(fun (asl,w) -> MP_TAC(PART_MATCH (lhand o rand) CONTENT_CLOSED_INTERVAL
+                (lhs w))) THEN
+  (ANTS_TAC THENL
+    [X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+     FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
+     ASM_SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+                  REAL_LE_RADD; REAL_LE_LMUL] THEN
+     ONCE_REWRITE_TAC[REAL_ARITH `m * b <= m * a <=> --m * a <= --m * b`] THEN
+     ASM_SIMP_TAC[REAL_ARITH `~(&0 <= x) ==> &0 <= --x`; REAL_LE_LMUL];
+     ALL_TAC]) THEN
+  DISCH_THEN SUBST1_TAC THEN
+  ONCE_REWRITE_TAC[GSYM PRODUCT_CONST_NUMSEG_1] THEN
+  ASM_SIMP_TAC[CONTENT_CLOSED_INTERVAL; GSYM PRODUCT_MUL_NUMSEG] THEN
+  MATCH_MP_TAC PRODUCT_EQ THEN
+  SIMP_TAC[IN_NUMSEG; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let HAS_INTEGRAL_AFFINITY = prove
+ (`!f:real^M->real^N i a b m c.
+        (f has_integral i) (interval[a,b]) /\ ~(m = &0)
+        ==> ((\x. f(m % x + c)) has_integral
+             (inv(abs(m) pow dimindex(:M)) % i))
+            (IMAGE (\x. inv m % x + --(inv(m) % c)) (interval[a,b]))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_TWIDDLE THEN
+  ASM_SIMP_TAC[INTERVAL_IMAGE_AFFINITY_INTERVAL; GSYM REAL_ABS_NZ;
+        REAL_POW_LT; PRODUCT_EQ_0_NUMSEG; CONTENT_IMAGE_AFFINITY_INTERVAL] THEN
+  ASM_SIMP_TAC[CONTINUOUS_CMUL; CONTINUOUS_AT_ID; CONTINUOUS_CONST;
+               CONTINUOUS_ADD] THEN
+  REWRITE_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC; VECTOR_MUL_RNEG] THEN
+  ASM_SIMP_TAC[REAL_MUL_LINV; REAL_MUL_RINV] THEN
+  CONJ_TAC THEN VECTOR_ARITH_TAC);;
+
+let INTEGRABLE_AFFINITY = prove
+ (`!f:real^M->real^N a b m c.
+        f integrable_on interval[a,b] /\ ~(m = &0)
+        ==> (\x. f(m % x + c)) integrable_on
+            (IMAGE (\x. inv m % x + --(inv(m) % c)) (interval[a,b]))`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_AFFINITY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Special case of stretching coordinate axes separately.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTENT_IMAGE_STRETCH_INTERVAL = prove
+ (`!a b:real^N m.
+        content(IMAGE (\x. lambda k. m k * x$k) (interval[a,b]):real^N->bool) =
+        abs(product(1..dimindex(:N)) m) * content(interval[a,b])`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[content; IMAGE_EQ_EMPTY] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_MUL_RZERO] THEN
+  ASM_REWRITE_TAC[IMAGE_STRETCH_INTERVAL] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+  ASM_SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND; LAMBDA_BETA;
+               REAL_ARITH `min a b <= max a b`] THEN
+  ASM_REWRITE_TAC[REAL_ARITH `max a b - min a b = abs(b - a)`;
+                  GSYM REAL_SUB_LDISTRIB; REAL_ABS_MUL] THEN
+  ASM_SIMP_TAC[PRODUCT_MUL; FINITE_NUMSEG;
+               REAL_ARITH `a <= b ==> abs(b - a) = b - a`] THEN
+  ASM_SIMP_TAC[PRODUCT_ABS; FINITE_NUMSEG]);;
+
+let HAS_INTEGRAL_STRETCH = prove
+ (`!f:real^M->real^N i m a b.
+        (f has_integral i) (interval[a,b]) /\
+        (!k. 1 <= k /\ k <= dimindex(:M) ==>  ~(m k = &0))
+        ==> ((\x:real^M. f(lambda k. m k * x$k)) has_integral
+             (inv(abs(product(1..dimindex(:M)) m)) % i))
+            (IMAGE (\x. lambda k. inv(m k) * x$k) (interval[a,b]))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_TWIDDLE THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN
+  ASM_SIMP_TAC[REAL_MUL_ASSOC; REAL_MUL_LINV; REAL_MUL_RINV; REAL_MUL_LID] THEN
+  ASM_REWRITE_TAC[GSYM REAL_ABS_NZ; PRODUCT_EQ_0_NUMSEG] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN CONJ_TAC THENL
+   [GEN_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_AT THEN
+    SIMP_TAC[linear; LAMBDA_BETA; CART_EQ; VECTOR_ADD_COMPONENT;
+             VECTOR_MUL_COMPONENT] THEN REAL_ARITH_TAC;
+    REWRITE_TAC[CONTENT_IMAGE_STRETCH_INTERVAL] THEN
+    REWRITE_TAC[IMAGE_STRETCH_INTERVAL] THEN MESON_TAC[EMPTY_AS_INTERVAL]]);;
+
+let INTEGRABLE_STRETCH = prove
+ (`!f:real^M->real^N m a b.
+        f integrable_on interval[a,b] /\
+        (!k. 1 <= k /\ k <= dimindex(:M) ==>  ~(m k = &0))
+        ==> (\x:real^M. f(lambda k. m k * x$k)) integrable_on
+            (IMAGE (\x. lambda k. inv(m k) * x$k) (interval[a,b]))`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_STRETCH]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Even more special cases.                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_REFLECT_LEMMA = prove
+ (`!f:real^M->real^N i a b.
+     (f has_integral i) (interval[a,b])
+     ==> ((\x. f(--x)) has_integral i) (interval[--b,--a])`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o C CONJ (REAL_ARITH `~(-- &1 = &0)`)) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_AFFINITY) THEN
+  DISCH_THEN(MP_TAC o SPEC `vec 0:real^M`) THEN
+  REWRITE_TAC[IMAGE_AFFINITY_INTERVAL] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[REAL_ABS_NEG; REAL_ABS_NUM; REAL_POW_ONE] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_NEG_0] THEN
+  REWRITE_TAC[REAL_INV_NEG; REAL_INV_1] THEN
+  REWRITE_TAC[VECTOR_ARITH `-- &1 % x + vec 0 = --x`] THEN
+  REWRITE_TAC[VECTOR_MUL_LID] THEN MATCH_MP_TAC EQ_IMP THEN
+  AP_TERM_TAC THEN POP_ASSUM(K ALL_TAC) THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN CONV_TAC SYM_CONV THEN
+  POP_ASSUM MP_TAC THEN REWRITE_TAC[INTERVAL_EQ_EMPTY] THEN
+  REWRITE_TAC[TAUT `a /\ b /\ c <=> ~(a /\ b ==> ~c)`] THEN
+  SIMP_TAC[VECTOR_NEG_COMPONENT; REAL_LT_NEG2]);;
+
+let HAS_INTEGRAL_REFLECT = prove
+ (`!f:real^M->real^N i a b.
+     ((\x. f(--x)) has_integral i) (interval[--b,--a]) <=>
+     (f has_integral i) (interval[a,b])`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_REFLECT_LEMMA) THEN
+  REWRITE_TAC[VECTOR_NEG_NEG; ETA_AX]);;
+
+let INTEGRABLE_REFLECT = prove
+ (`!f:real^M->real^N a b.
+     (\x. f(--x)) integrable_on (interval[--b,--a]) <=>
+     f integrable_on (interval[a,b])`,
+  REWRITE_TAC[integrable_on; HAS_INTEGRAL_REFLECT]);;
+
+let INTEGRAL_REFLECT = prove
+ (`!f:real^M->real^N a b.
+     integral (interval[--b,--a]) (\x. f(--x)) =
+     integral (interval[a,b]) f`,
+  REWRITE_TAC[integral; HAS_INTEGRAL_REFLECT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Technical lemmas about how many non-trivial intervals of a division a     *)
+(* point can be in (we sometimes need this for bounding sums).               *)
+(* ------------------------------------------------------------------------- *)
+
+let DIVISION_COMMON_POINT_BOUND = prove
+ (`!d s:real^N->bool x.
+        d division_of s
+        ==> CARD {k | k IN d /\ ~(content k = &0) /\ x IN k}
+            <= 2 EXP (dimindex(:N))`,
+  let lemma = prove
+   (`!f s. (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+           FINITE s /\ CARD(IMAGE f s) <= n
+           ==> CARD(s) <= n`,
+    MESON_TAC[CARD_IMAGE_INJ]) in
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `!k. k IN d ==> ?a b:real^N. interval[a,b] = k` MP_TAC THENL
+   [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`A:(real^N->bool)->real^N`; `B:(real^N->bool)->real^N`] THEN
+  STRIP_TAC THEN MATCH_MP_TAC(ISPEC
+   `\d. (lambda i. (x:real^N)$i = (A:(real^N->bool)->real^N)(d)$i):bool^N`
+   lemma) THEN
+  REPEAT CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC FINITE_RESTRICT THEN ASM_MESON_TAC[division_of];
+    MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `CARD(:bool^N)` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CARD_SUBSET THEN REWRITE_TAC[SUBSET_UNIV] THEN
+      SIMP_TAC[FINITE_CART_UNIV; FINITE_BOOL];
+      SIMP_TAC[FINITE_BOOL; CARD_CART_UNIV; CARD_BOOL; LE_REFL]]] THEN
+  MAP_EVERY X_GEN_TAC [`k:real^N->bool`; `l:real^N->bool`] THEN
+  SIMP_TAC[IN_ELIM_THM; CART_EQ; LAMBDA_BETA] THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`k:real^N->bool`; `l:real^N->bool`] o
+        el 2 o CONJUNCTS) THEN
+  ASM_REWRITE_TAC[GSYM INTERIOR_INTER] THEN
+  MATCH_MP_TAC(TAUT `~q ==> (~p ==> q) ==> p`) THEN
+  MAP_EVERY UNDISCH_TAC
+   [`(x:real^N) IN k`; `(x:real^N) IN l`;
+    `~(content(k:real^N->bool) = &0)`;
+    `~(content(l:real^N->bool) = &0)`] THEN
+  SUBGOAL_THEN
+   `k = interval[A k:real^N,B k] /\ l = interval[A l,B l]`
+   (CONJUNCTS_THEN SUBST1_TAC)
+  THENL [ASM_MESON_TAC[]; REWRITE_TAC[INTER_INTERVAL]] THEN
+  REWRITE_TAC[CONTENT_EQ_0_INTERIOR; INTERIOR_CLOSED_INTERVAL] THEN
+  SIMP_TAC[IN_INTERVAL; INTERVAL_NE_EMPTY; LAMBDA_BETA] THEN
+  REPEAT DISCH_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `i:num`)) THEN ASM_REWRITE_TAC[] THEN
+  REAL_ARITH_TAC);;
+
+let TAGGED_PARTIAL_DIVISION_COMMON_POINT_BOUND = prove
+ (`!p s:real^N->bool y.
+        p tagged_partial_division_of s
+        ==> CARD {(x,k) | (x,k) IN p /\ y IN k /\ ~(content k = &0)}
+            <= 2 EXP (dimindex(:N))`,
+  let lemma = prove
+   (`!f s. (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+           FINITE s /\ CARD(IMAGE f s) <= n
+           ==> CARD(s) <= n`,
+    MESON_TAC[CARD_IMAGE_INJ]) in
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(ISPEC `SND` lemma) THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[IMP_CONJ; FORALL_IN_GSPEC; RIGHT_FORALL_IMP_THM; PAIR_EQ] THEN
+    MAP_EVERY X_GEN_TAC [`x1:real^N`; `k1:real^N->bool`] THEN
+    REPEAT DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`x2:real^N`; `k2:real^N->bool`] THEN
+    REPEAT DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [tagged_partial_division_of]) THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`x1:real^N`; `k1:real^N->bool`; `x2:real^N`; `k2:real^N->bool`] o
+     CONJUNCT2 o CONJUNCT2) THEN
+    ASM_REWRITE_TAC[PAIR_EQ] THEN
+    MATCH_MP_TAC(TAUT `~q ==> (~p ==> q) ==> p`) THEN
+    REWRITE_TAC[INTER_ACI] THEN
+    ASM_MESON_TAC[CONTENT_EQ_0_INTERIOR; tagged_partial_division_of];
+    MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC `p:real^N#(real^N->bool)->bool` THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[tagged_partial_division_of]; SET_TAC[]];
+    FIRST_ASSUM(MP_TAC o MATCH_MP PARTIAL_DIVISION_OF_TAGGED_DIVISION) THEN
+    DISCH_THEN(MP_TAC o SPEC `y:real^N` o
+      MATCH_MP DIVISION_COMMON_POINT_BOUND) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LE_TRANS) THEN
+    MATCH_MP_TAC CARD_SUBSET THEN CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+      REWRITE_TAC[IN_ELIM_THM; IN_IMAGE; EXISTS_PAIR_THM] THEN MESON_TAC[];
+      MATCH_MP_TAC FINITE_RESTRICT THEN MATCH_MP_TAC FINITE_IMAGE THEN
+      ASM_MESON_TAC[tagged_partial_division_of]]]);;
+
+let TAGGED_PARTIAL_DIVISION_COMMON_TAGS = prove
+ (`!p s:real^N->bool x.
+        p tagged_partial_division_of s
+        ==> CARD {(x,k) | k | (x,k) IN p /\ ~(content k = &0)}
+            <= 2 EXP (dimindex(:N))`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o SPEC `x:real^N` o
+   MATCH_MP TAGGED_PARTIAL_DIVISION_COMMON_POINT_BOUND) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LE_TRANS) THEN
+  MATCH_MP_TAC CARD_SUBSET THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_ELIM_PAIR_THM] THEN
+    ASM_MESON_TAC[tagged_partial_division_of];
+    MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC `p:real^N#(real^N->bool)->bool` THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[tagged_partial_division_of]; SET_TAC[]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Integrating characteristic function of an interval.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_RESTRICT_OPEN_SUBINTERVAL = prove
+ (`!f:real^M->real^N a b c d i.
+        (f has_integral i) (interval[c,d]) /\
+        interval[c,d] SUBSET interval[a,b]
+        ==> ((\x. if x IN interval(c,d) then f x else vec 0) has_integral i)
+             (interval[a,b])`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `interval[c:real^M,d] = {}` THENL
+   [FIRST_ASSUM(MP_TAC o AP_TERM
+     `interior:(real^M->bool)->(real^M->bool)`) THEN
+    SIMP_TAC[INTERIOR_CLOSED_INTERVAL; INTERIOR_EMPTY] THEN
+    ASM_SIMP_TAC[NOT_IN_EMPTY; HAS_INTEGRAL_0_EQ; HAS_INTEGRAL_EMPTY_EQ];
+    ALL_TAC] THEN
+  ABBREV_TAC `g:real^M->real^N =
+                 \x. if x IN interval(c,d) then f x else vec 0` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o check(is_neg o concl)) THEN
+  REWRITE_TAC[TAUT `a ==> b ==> c <=> b /\ a ==> c`] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP PARTIAL_DIVISION_EXTEND_1) THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:(real^M->bool)->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`lifted((+):real^N->real^N->real^N)`;
+    `p:(real^M->bool)->bool`;
+    `a:real^M`; `b:real^M`;
+    `\i. if (g:real^M->real^N) integrable_on i
+         then SOME (integral i g) else NONE`]
+   OPERATIVE_DIVISION) THEN
+  ASM_SIMP_TAC[OPERATIVE_INTEGRAL; MONOIDAL_LIFTED; MONOIDAL_VECTOR_ADD] THEN
+  SUBGOAL_THEN
+   `iterate (lifted (+)) p
+     (\i. if (g:real^M->real^N) integrable_on i
+          then SOME (integral i g) else NONE) =
+    SOME i`
+  SUBST1_TAC THENL
+   [ALL_TAC;
+    COND_CASES_TAC THEN
+    REWRITE_TAC[distinctness "option"; injectivity "option"] THEN
+    ASM_MESON_TAC[INTEGRABLE_INTEGRAL]] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP (SET_RULE
+   `x IN s ==> s = x INSERT (s DELETE x)`)) THEN
+  ASM_SIMP_TAC[ITERATE_CLAUSES; MONOIDAL_LIFTED; MONOIDAL_VECTOR_ADD;
+               FINITE_DELETE; IN_DELETE] THEN
+  SUBGOAL_THEN `(g:real^M->real^N) integrable_on interval[c,d]`
+  ASSUME_TAC THENL
+   [FIRST_ASSUM(MP_TAC o MATCH_MP HAS_INTEGRAL_INTEGRABLE) THEN
+    MATCH_MP_TAC INTEGRABLE_SPIKE_INTERIOR THEN
+    EXPAND_TAC "g" THEN SIMP_TAC[];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `iterate (lifted (+)) (p DELETE interval[c,d])
+      (\i. if (g:real^M->real^N) integrable_on i
+           then SOME (integral i g) else NONE) = SOME(vec 0)`
+  SUBST1_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[lifted; VECTOR_ADD_RID] THEN AP_TERM_TAC THEN
+    MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+    MATCH_MP_TAC HAS_INTEGRAL_SPIKE_INTERIOR THEN
+    EXISTS_TAC `f:real^M->real^N` THEN
+    EXPAND_TAC "g" THEN ASM_SIMP_TAC[]] THEN
+  SIMP_TAC[GSYM NEUTRAL_VECTOR_ADD; GSYM NEUTRAL_LIFTED;
+           MONOIDAL_VECTOR_ADD] THEN
+  MATCH_MP_TAC(MATCH_MP ITERATE_EQ_NEUTRAL
+        (MATCH_MP MONOIDAL_LIFTED(SPEC_ALL MONOIDAL_VECTOR_ADD))) THEN
+  SIMP_TAC[NEUTRAL_LIFTED; NEUTRAL_VECTOR_ADD; MONOIDAL_VECTOR_ADD] THEN
+  X_GEN_TAC `k:real^M->bool` THEN REWRITE_TAC[IN_DELETE] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `((g:real^M->real^N) has_integral (vec 0)) k`
+   (fun th -> MESON_TAC[th; integrable_on; INTEGRAL_UNIQUE]) THEN
+  SUBGOAL_THEN `?u v:real^M. k = interval[u,v]` MP_TAC THENL
+   [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+  DISCH_THEN(REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC) THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPIKE_INTERIOR THEN
+  EXISTS_TAC `(\x. vec 0):real^M->real^N` THEN
+  REWRITE_TAC[HAS_INTEGRAL_0] THEN X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+  DISCH_THEN(MP_TAC o el 2 o CONJUNCTS) THEN
+  DISCH_THEN(MP_TAC o SPECL
+   [`interval[c:real^M,d]`; `interval[u:real^M,v]`]) THEN
+  ASM_REWRITE_TAC[INTERIOR_CLOSED_INTERVAL] THEN
+  EXPAND_TAC "g" THEN REWRITE_TAC[] THEN COND_CASES_TAC THEN ASM SET_TAC[]);;
+
+let HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVAL = prove
+ (`!f:real^M->real^N a b c d i.
+        (f has_integral i) (interval[c,d]) /\
+        interval[c,d] SUBSET interval[a,b]
+        ==> ((\x. if x IN interval[c,d] then f x else vec 0) has_integral i)
+             (interval[a,b])`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_RESTRICT_OPEN_SUBINTERVAL) THEN
+  MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+    HAS_INTEGRAL_SPIKE) THEN
+  EXISTS_TAC `interval[c:real^M,d] DIFF interval(c,d)` THEN
+  REWRITE_TAC[NEGLIGIBLE_FRONTIER_INTERVAL] THEN REWRITE_TAC[IN_DIFF] THEN
+  MP_TAC(ISPECL [`c:real^M`; `d:real^M`] INTERVAL_OPEN_SUBSET_CLOSED) THEN
+  SET_TAC[]);;
+
+let HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVALS_EQ = prove
+ (`!f:real^M->real^N a b c d i.
+        interval[c,d] SUBSET interval[a,b]
+        ==> (((\x. if x IN interval[c,d] then f x else vec 0) has_integral i)
+              (interval[a,b]) <=>
+             (f has_integral i) (interval[c,d]))`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `interval[c:real^M,d] = {}` THENL
+   [ASM_REWRITE_TAC[NOT_IN_EMPTY; HAS_INTEGRAL_0_EQ; HAS_INTEGRAL_EMPTY_EQ];
+    ALL_TAC] THEN
+  EQ_TAC THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVAL] THEN
+  SUBGOAL_THEN `(f:real^M->real^N) integrable_on interval[c,d]` MP_TAC THENL
+   [MATCH_MP_TAC INTEGRABLE_EQ THEN
+    EXISTS_TAC `\x. if x IN interval[c:real^M,d]
+                    then f x:real^N else vec 0` THEN
+    SIMP_TAC[] THEN MATCH_MP_TAC INTEGRABLE_SUBINTERVAL THEN
+    ASM_MESON_TAC[integrable_on];
+    ALL_TAC] THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP INTEGRABLE_INTEGRAL) THEN
+  MP_TAC(ASSUME `interval[c:real^M,d] SUBSET interval[a,b]`) THEN
+  REWRITE_TAC[IMP_IMP] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVAL) THEN
+  ASM_MESON_TAC[HAS_INTEGRAL_UNIQUE; INTEGRABLE_INTEGRAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence we can apply the limit process uniformly to all integrals.          *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL = prove
+ (`!f:real^M->real^N i s.
+     (f has_integral i) s <=>
+        !e. &0 < e
+            ==> ?B. &0 < B /\
+                    !a b. ball(vec 0,B) SUBSET interval[a,b]
+                          ==> ?z. ((\x. if x IN s then f(x) else vec 0)
+                                   has_integral z) (interval[a,b]) /\
+                                  norm(z - i) < e`,
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [has_integral_alt] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  POP_ASSUM(X_CHOOSE_THEN `a:real^M` (X_CHOOSE_THEN `b:real^M`
+   SUBST_ALL_TAC)) THEN
+  MP_TAC(ISPECL [`a:real^M`; `b:real^M`] (CONJUNCT1 BOUNDED_INTERVAL)) THEN
+  REWRITE_TAC[BOUNDED_POS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN EQ_TAC THENL
+   [DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    EXISTS_TAC `B + &1` THEN ASM_SIMP_TAC[REAL_LT_ADD; REAL_LT_01] THEN
+    MAP_EVERY X_GEN_TAC [`c:real^M`; `d:real^M`] THEN
+    REWRITE_TAC[SUBSET; IN_BALL; NORM_ARITH `dist(vec 0,x) = norm x`] THEN
+    DISCH_TAC THEN EXISTS_TAC `i:real^N` THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0] THEN
+    MATCH_MP_TAC HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVAL THEN
+    ASM_MESON_TAC[SUBSET; REAL_ARITH `n <= B ==> n < B + &1`];
+    ALL_TAC] THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN `?y. ((f:real^M->real^N) has_integral y) (interval[a,b])`
+  MP_TAC THENL
+   [SUBGOAL_THEN
+     `?c d. interval[a,b] SUBSET interval[c,d] /\
+            (\x. if x IN interval[a,b] then (f:real^M->real^N) x
+                 else vec 0) integrable_on interval[c,d]`
+    STRIP_ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o C MATCH_MP REAL_LT_01) THEN
+      DISCH_THEN(X_CHOOSE_THEN `C:real` STRIP_ASSUME_TAC) THEN
+      ABBREV_TAC `c:real^M = lambda i. --(max B C)` THEN
+      ABBREV_TAC `d:real^M = lambda i. max B C` THEN
+      MAP_EVERY EXISTS_TAC [`c:real^M`; `d:real^M`] THEN CONJ_TAC THENL
+       [REWRITE_TAC[SUBSET] THEN X_GEN_TAC `x:real^M` THEN
+        DISCH_TAC THEN REWRITE_TAC[IN_INTERVAL] THEN
+        X_GEN_TAC `k:num` THEN MAP_EVERY EXPAND_TAC ["c"; "d"] THEN
+        SIMP_TAC[LAMBDA_BETA; REAL_BOUNDS_LE] THEN STRIP_TAC THEN
+        MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `norm(x:real^M)` THEN
+        ASM_SIMP_TAC[COMPONENT_LE_NORM] THEN
+        MATCH_MP_TAC(REAL_ARITH `x <= B ==> x <= max B C`) THEN
+        ASM_SIMP_TAC[];
+        ALL_TAC] THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL [`c:real^M`; `d:real^M`]) THEN ANTS_TAC THENL
+       [REWRITE_TAC[SUBSET; IN_BALL; NORM_ARITH `dist(vec 0,x) = norm x`] THEN
+        X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN REWRITE_TAC[IN_INTERVAL] THEN
+        X_GEN_TAC `k:num` THEN MAP_EVERY EXPAND_TAC ["c"; "d"] THEN
+        SIMP_TAC[LAMBDA_BETA; REAL_BOUNDS_LE] THEN STRIP_TAC THEN
+        MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `norm(x:real^M)` THEN
+        ASM_SIMP_TAC[COMPONENT_LE_NORM] THEN
+        MATCH_MP_TAC(REAL_ARITH `x < C ==> x <= max B C`) THEN
+        ASM_SIMP_TAC[];
+        ALL_TAC] THEN
+      MESON_TAC[integrable_on];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [integrable_on]) THEN
+      ASM_SIMP_TAC[HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVALS_EQ]];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_TAC `y:real^N`) THEN
+  SUBGOAL_THEN `i:real^N = y` ASSUME_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(NORM_ARITH `~(&0 < norm(y - i)) ==> i = y`) THEN
+  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `norm(y - i:real^N)`) THEN
+  ASM_REWRITE_TAC[NOT_EXISTS_THM] THEN X_GEN_TAC `C:real` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN
+  ABBREV_TAC `c:real^M = lambda i. --(max B C)` THEN
+  ABBREV_TAC `d:real^M = lambda i. max B C` THEN
+  MAP_EVERY EXISTS_TAC [`c:real^M`; `d:real^M`] THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; IN_BALL; NORM_ARITH `dist(vec 0,x) = norm x`] THEN
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN REWRITE_TAC[IN_INTERVAL] THEN
+    X_GEN_TAC `k:num` THEN MAP_EVERY EXPAND_TAC ["c"; "d"] THEN
+    SIMP_TAC[LAMBDA_BETA; REAL_BOUNDS_LE] THEN STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `norm(x:real^M)` THEN
+    ASM_SIMP_TAC[COMPONENT_LE_NORM] THEN
+    MATCH_MP_TAC(REAL_ARITH `x < C ==> x <= max B C`) THEN
+    ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `interval[a:real^M,b] SUBSET interval[c,d]` ASSUME_TAC THENL
+   [REWRITE_TAC[SUBSET] THEN X_GEN_TAC `x:real^M` THEN
+    DISCH_TAC THEN REWRITE_TAC[IN_INTERVAL] THEN
+    X_GEN_TAC `k:num` THEN MAP_EVERY EXPAND_TAC ["c"; "d"] THEN
+    SIMP_TAC[LAMBDA_BETA; REAL_BOUNDS_LE] THEN STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `norm(x:real^M)` THEN
+    ASM_SIMP_TAC[COMPONENT_LE_NORM] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= B ==> x <= max B C`) THEN
+    ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVALS_EQ] THEN
+  ASM_MESON_TAC[REAL_LT_REFL; HAS_INTEGRAL_UNIQUE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence a general restriction property.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_RESTRICT = prove
+ (`!f:real^M->real^N s t i.
+        s SUBSET t
+        ==> (((\x. if x IN s then f x else vec 0) has_integral i) t <=>
+             (f has_integral i) s)`,
+  REWRITE_TAC[SUBSET] THEN REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[HAS_INTEGRAL] THEN REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[MESON[] `(if p then if q then x else y else y) =
+                            (if q then if p then x else y else y)`] THEN
+  ASM_SIMP_TAC[]);;
+
+let INTEGRAL_RESTRICT = prove
+ (`!f:real^M->real^N s t.
+        s SUBSET t
+        ==> integral t (\x. if x IN s then f x else vec 0) =
+            integral s f`,
+  SIMP_TAC[integral; HAS_INTEGRAL_RESTRICT]);;
+
+let INTEGRABLE_RESTRICT = prove
+ (`!f:real^M->real^N s t.
+        s SUBSET t
+        ==> ((\x. if x IN s then f x else vec 0) integrable_on t <=>
+             f integrable_on s)`,
+  SIMP_TAC[integrable_on; HAS_INTEGRAL_RESTRICT]);;
+
+let HAS_INTEGRAL_RESTRICT_UNIV = prove
+ (`!f:real^M->real^N s i.
+        ((\x. if x IN s then f x else vec 0) has_integral i) (:real^M) <=>
+         (f has_integral i) s`,
+  SIMP_TAC[HAS_INTEGRAL_RESTRICT; SUBSET_UNIV]);;
+
+let INTEGRAL_RESTRICT_UNIV = prove
+ (`!f:real^M->real^N s.
+        integral (:real^M) (\x. if x IN s then f x else vec 0) =
+        integral s f`,
+  REWRITE_TAC[integral; HAS_INTEGRAL_RESTRICT_UNIV]);;
+
+let INTEGRABLE_RESTRICT_UNIV = prove
+ (`!f s. (\x. if x IN s then f x else vec 0) integrable_on (:real^M) <=>
+         f integrable_on s`,
+  REWRITE_TAC[integrable_on; HAS_INTEGRAL_RESTRICT_UNIV]);;
+
+let HAS_INTEGRAL_RESTRICT_INTER = prove
+ (`!f:real^M->real^N s t.
+        ((\x. if x IN s then f x else vec 0) has_integral i) t <=>
+        (f has_integral i) (s INTER t)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM HAS_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[IN_INTER] THEN AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN MESON_TAC[]);;
+
+let INTEGRAL_RESTRICT_INTER = prove
+ (`!f:real^M->real^N s t.
+        integral t (\x. if x IN s then f x else vec 0) =
+        integral (s INTER t) f`,
+  REWRITE_TAC[integral; HAS_INTEGRAL_RESTRICT_INTER]);;
+
+let INTEGRABLE_RESTRICT_INTER = prove
+ (`!f:real^M->real^N s t.
+        (\x. if x IN s then f x else vec 0) integrable_on t <=>
+        f integrable_on (s INTER t)`,
+  REWRITE_TAC[integrable_on; HAS_INTEGRAL_RESTRICT_INTER]);;
+
+let HAS_INTEGRAL_ON_SUPERSET = prove
+ (`!f s t.
+        (!x. ~(x IN s) ==> f x = vec 0) /\ s SUBSET t /\ (f has_integral i) s
+        ==> (f has_integral i) t`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[SUBSET] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ONCE_REWRITE_TAC[GSYM HAS_INTEGRAL_RESTRICT_UNIV] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_THM_TAC THEN
+  AP_TERM_TAC THEN ABS_TAC THEN ASM_MESON_TAC[]);;
+
+let INTEGRABLE_ON_SUPERSET = prove
+ (`!f s t.
+        (!x. ~(x IN s) ==> f x = vec 0) /\ s SUBSET t /\ f integrable_on s
+        ==> f integrable_on t`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_ON_SUPERSET]);;
+
+let NEGLIGIBLE_ON_INTERVALS = prove
+ (`!s. negligible s <=> !a b:real^N. negligible(s INTER interval[a,b])`,
+  GEN_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC `s:real^N->bool` THEN
+    ASM_REWRITE_TAC[] THEN SET_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[negligible] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  FIRST_ASSUM(ASSUME_TAC o SPECL [`a:real^N`; `b:real^N`]) THEN
+  MATCH_MP_TAC HAS_INTEGRAL_NEGLIGIBLE THEN
+  EXISTS_TAC `s INTER interval[a:real^N,b]` THEN
+  ASM_REWRITE_TAC[] THEN SIMP_TAC[indicator; IN_DIFF; IN_INTER] THEN
+  MESON_TAC[]);;
+
+let HAS_INTEGRAL_SPIKE_SET_EQ = prove
+ (`!f:real^M->real^N s t y.
+        negligible(s DIFF t UNION t DIFF s)
+        ==> ((f has_integral y) s <=> (f has_integral y) t)`,
+  REPEAT STRIP_TAC THEN  ONCE_REWRITE_TAC[GSYM HAS_INTEGRAL_RESTRICT_UNIV] THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPIKE_EQ THEN
+  EXISTS_TAC `s DIFF t UNION t DIFF s:real^M->bool` THEN
+  ASM_REWRITE_TAC[] THEN SET_TAC[]);;
+
+let HAS_INTEGRAL_SPIKE_SET = prove
+ (`!f:real^M->real^N s t y.
+        negligible(s DIFF t UNION t DIFF s) /\
+        (f has_integral y) s
+        ==> (f has_integral y) t`,
+  MESON_TAC[HAS_INTEGRAL_SPIKE_SET_EQ]);;
+
+let INTEGRABLE_SPIKE_SET = prove
+ (`!f:real^M->real^N s t.
+        negligible(s DIFF t UNION t DIFF s)
+        ==> f integrable_on s ==> f integrable_on t`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_SPIKE_SET_EQ]);;
+
+let INTEGRABLE_SPIKE_SET_EQ = prove
+ (`!f:real^M->real^N s t.
+        negligible(s DIFF t UNION t DIFF s)
+        ==> (f integrable_on s <=> f integrable_on t)`,
+  MESON_TAC[INTEGRABLE_SPIKE_SET; UNION_COMM]);;
+
+let INTEGRAL_SPIKE_SET = prove
+ (`!f:real^M->real^N g s t.
+        negligible(s DIFF t UNION t DIFF s)
+        ==> integral s f = integral t f`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[integral] THEN
+  AP_TERM_TAC THEN ABS_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_SPIKE_SET_EQ THEN
+  ASM_MESON_TAC[]);;
+
+let HAS_INTEGRAL_INTERIOR = prove
+ (`!f:real^M->real^N y s.
+        negligible(frontier s)
+        ==> ((f has_integral y) (interior s) <=> (f has_integral y) s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_SPIKE_SET_EQ THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    NEGLIGIBLE_SUBSET)) THEN
+  REWRITE_TAC[frontier] THEN
+  MP_TAC(ISPEC `s:real^M->bool` INTERIOR_SUBSET) THEN
+  MP_TAC(ISPEC `s:real^M->bool` CLOSURE_SUBSET) THEN
+  SET_TAC[]);;
+
+let HAS_INTEGRAL_CLOSURE = prove
+ (`!f:real^M->real^N y s.
+        negligible(frontier s)
+        ==> ((f has_integral y) (closure s) <=> (f has_integral y) s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_SPIKE_SET_EQ THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    NEGLIGIBLE_SUBSET)) THEN
+  REWRITE_TAC[frontier] THEN
+  MP_TAC(ISPEC `s:real^M->bool` INTERIOR_SUBSET) THEN
+  MP_TAC(ISPEC `s:real^M->bool` CLOSURE_SUBSET) THEN
+  SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More lemmas that are useful later.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_SUBSET_COMPONENT_LE = prove
+ (`!f:real^M->real^N s t i j k.
+        s SUBSET t /\ (f has_integral i) s /\ (f has_integral j) t /\
+        1 <= k /\ k <= dimindex(:N) /\
+        (!x. x IN t ==> &0 <= f(x)$k)
+        ==> i$k <= j$k`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM HAS_INTEGRAL_RESTRICT_UNIV] THEN
+  STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_COMPONENT_LE THEN
+  MAP_EVERY EXISTS_TAC
+   [`(\x. if x IN s then f x else vec 0):real^M->real^N`;
+    `(\x. if x IN t then f x else vec 0):real^M->real^N`;
+    `(:real^M)`] THEN
+  ASM_REWRITE_TAC[] THEN
+  REPEAT STRIP_TAC THEN
+  REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_LE_REFL]) THEN
+  ASM_SIMP_TAC[VEC_COMPONENT] THEN ASM SET_TAC[]);;
+
+let INTEGRAL_SUBSET_COMPONENT_LE = prove
+ (`!f:real^M->real^N s t k.
+        s SUBSET t /\ f integrable_on s /\ f integrable_on t /\
+        1 <= k /\ k <= dimindex(:N) /\
+        (!x. x IN t ==> &0 <= f(x)$k)
+        ==> (integral s f)$k <= (integral t f)$k`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_SUBSET_COMPONENT_LE THEN
+  ASM_MESON_TAC[INTEGRABLE_INTEGRAL]);;
+
+let HAS_INTEGRAL_SUBSET_DROP_LE = prove
+ (`!f:real^M->real^1 s t i j.
+        s SUBSET t /\ (f has_integral i) s /\ (f has_integral j) t /\
+        (!x. x IN t ==> &0 <= drop(f x))
+        ==> drop i <= drop j`,
+  REWRITE_TAC[drop] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SUBSET_COMPONENT_LE THEN
+  REWRITE_TAC[DIMINDEX_1; LE_REFL] THEN ASM_MESON_TAC[]);;
+
+let INTEGRAL_SUBSET_DROP_LE = prove
+ (`!f:real^M->real^1 s t.
+        s SUBSET t /\ f integrable_on s /\ f integrable_on t /\
+        (!x. x IN t ==> &0 <= drop(f(x)))
+        ==> drop(integral s f) <= drop(integral t f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_SUBSET_DROP_LE THEN
+  ASM_MESON_TAC[INTEGRABLE_INTEGRAL]);;
+
+let HAS_INTEGRAL_ALT = prove
+ (`!f:real^M->real^N s i.
+        (f has_integral i) s <=>
+            (!a b. (\x. if x IN s then f x else vec 0)
+                   integrable_on interval[a,b]) /\
+            (!e. &0 < e
+                 ==> ?B. &0 < B /\
+                         !a b. ball (vec 0,B) SUBSET interval[a,b]
+                               ==> norm(integral(interval[a,b])
+                                          (\x. if x IN s then f x else vec 0) -
+                                        i) < e)`,
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [HAS_INTEGRAL] THEN
+  SPEC_TAC(`\x. if x IN s then (f:real^M->real^N) x else vec 0`,
+           `f:real^M->real^N`) THEN
+  GEN_TAC THEN EQ_TAC THENL
+   [ALL_TAC; MESON_TAC[INTEGRAL_UNIQUE; integrable_on]] THEN
+  DISCH_TAC THEN CONJ_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[INTEGRAL_UNIQUE]] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN
+  POP_ASSUM(MP_TAC o C MATCH_MP REAL_LT_01) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC INTEGRABLE_SUBINTERVAL THEN
+  EXISTS_TAC `(lambda i. min ((a:real^M)$i) (--B)):real^M` THEN
+  EXISTS_TAC `(lambda i. max ((b:real^M)$i) B):real^M` THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o SPECL
+     [`(lambda i. min ((a:real^M)$i) (--B)):real^M`;
+      `(lambda i. max ((b:real^M)$i) B):real^M`]) THEN
+    ANTS_TAC THENL [ALL_TAC; MESON_TAC[integrable_on]];
+    SIMP_TAC[SUBSET; IN_INTERVAL; IN_BALL; LAMBDA_BETA;
+             REAL_MIN_LE; REAL_LE_MAX]] THEN
+  SIMP_TAC[SUBSET; IN_BALL; IN_INTERVAL; LAMBDA_BETA] THEN
+  GEN_TAC THEN REWRITE_TAC[NORM_ARITH `dist(vec 0,x) = norm x`] THEN
+  DISCH_TAC THEN X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH
+    `abs(x) <= B ==> min a (--B) <= x /\ x <= max b B`) THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `norm(x:real^M)` THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_LE; COMPONENT_LE_NORM]);;
+
+let INTEGRABLE_ALT = prove
+ (`!f:real^M->real^N s.
+        f integrable_on s <=>
+          (!a b. (\x. if x IN s then f x else vec 0) integrable_on
+                 interval[a,b]) /\
+          (!e. &0 < e
+               ==> ?B. &0 < B /\
+                       !a b c d.
+                          ball(vec 0,B) SUBSET interval[a,b] /\
+                          ball(vec 0,B) SUBSET interval[c,d]
+                          ==> norm(integral (interval[a,b])
+                                    (\x. if x IN s then f x else vec 0) -
+                                   integral (interval[c,d])
+                                    (\x. if x IN s then f x else vec 0)) < e)`,
+  REPEAT GEN_TAC THEN
+  GEN_REWRITE_TAC LAND_CONV [integrable_on] THEN
+  ONCE_REWRITE_TAC[HAS_INTEGRAL_ALT] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+  MATCH_MP_TAC(TAUT `(a ==> (b <=> c)) ==> (a /\ b <=> a /\ c)`) THEN
+  DISCH_TAC THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_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 `B:real` THEN
+    MESON_TAC[NORM_ARITH `norm(a - y) < e / &2 /\ norm(b - y) < e / &2
+                          ==> norm(a - b) < e`];
+    ALL_TAC] THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN
+   `cauchy (\n. integral (interval[(lambda i. --(&n)),(lambda i. &n)])
+                         (\x. if x IN s then (f:real^M->real^N) x else vec 0))`
+  MP_TAC THENL
+   [REWRITE_TAC[cauchy] 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 `B:real` STRIP_ASSUME_TAC) THEN
+    MP_TAC(SPEC `B:real` REAL_ARCH_SIMPLE) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN DISCH_TAC THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[dist] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[SUBSET; IN_BALL; NORM_ARITH `dist(vec 0,x) = norm x`] THEN
+    CONJ_TAC;
+    REWRITE_TAC[GSYM CONVERGENT_EQ_CAUCHY] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `i:real^N` THEN
+    REWRITE_TAC[LIM_SEQUENTIALLY] THEN DISCH_THEN(LABEL_TAC "C") THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    REMOVE_THEN "C" (MP_TAC o SPEC `e / &2`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `N:num` ASSUME_TAC) THEN
+    MP_TAC(SPEC `max (&N) B` REAL_ARCH_SIMPLE) THEN
+    REWRITE_TAC[REAL_MAX_LE; REAL_OF_NUM_LE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:num` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `&n` THEN CONJ_TAC THENL
+     [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `n:num`) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `norm(i1 - i2) < e / &2 ==> dist(i1,i) < e / &2 ==> norm(i2 - i) < e`) THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN CONJ_TAC THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `ball(vec 0:real^M,&n)` THEN
+    ASM_SIMP_TAC[SUBSET_BALL] THEN
+    REWRITE_TAC[SUBSET; IN_BALL; NORM_ARITH `dist(vec 0,x) = norm x`]] THEN
+  X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+  SIMP_TAC[IN_INTERVAL; LAMBDA_BETA] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
+  REWRITE_TAC[REAL_BOUNDS_LE] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `norm(x:real^M)` THEN ASM_SIMP_TAC[COMPONENT_LE_NORM] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN REWRITE_TAC[GSYM REAL_OF_NUM_GE] THEN
+  REAL_ARITH_TAC);;
+
+let INTEGRABLE_ALT_SUBSET = prove
+ (`!f:real^M->real^N s.
+        f integrable_on s <=>
+          (!a b. (\x. if x IN s then f x else vec 0) integrable_on
+                 interval[a,b]) /\
+          (!e. &0 < e
+               ==> ?B. &0 < B /\
+                       !a b c d.
+                          ball(vec 0,B) SUBSET interval[a,b] /\
+                          interval[a,b] SUBSET interval[c,d]
+                          ==> norm(integral (interval[a,b])
+                                    (\x. if x IN s then f x else vec 0) -
+                                   integral (interval[c,d])
+                                    (\x. if x IN s then f x else vec 0)) < e)`,
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [INTEGRABLE_ALT] THEN
+  ABBREV_TAC `g:real^M->real^N = \x. if x IN s then f x else vec 0` THEN
+  POP_ASSUM(K ALL_TAC) THEN
+  MATCH_MP_TAC(TAUT `(a ==> (b <=> c)) ==> (a /\ b <=> a /\ c)`) THEN
+  DISCH_TAC THEN EQ_TAC THENL [MESON_TAC[SUBSET_TRANS]; ALL_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
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `B:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`; `c:real^M`; `d:real^M`] THEN
+  STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+   [`(lambda i. max ((a:real^M)$i) ((c:real^M)$i)):real^M`;
+    `(lambda i. min ((b:real^M)$i) ((d:real^M)$i)):real^M`]) THEN
+  ASM_REWRITE_TAC[GSYM INTER_INTERVAL; SUBSET_INTER] THEN
+  DISCH_THEN(fun th ->
+    MP_TAC(ISPECL [`a:real^M`; `b:real^M`] th) THEN
+    MP_TAC(ISPECL [`c:real^M`; `d:real^M`] th)) THEN
+  ASM_REWRITE_TAC[INTER_SUBSET] THEN NORM_ARITH_TAC);;
+
+let INTEGRABLE_ON_SUBINTERVAL = prove
+ (`!f:real^M->real^N s a b.
+        f integrable_on s /\ interval[a,b] SUBSET s
+        ==> f integrable_on interval[a,b]`,
+  REPEAT GEN_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [INTEGRABLE_ALT] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (MP_TAC o CONJUNCT1) ASSUME_TAC) THEN
+  DISCH_THEN(MP_TAC o SPECL [`a:real^M`; `b:real^M`]) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] INTEGRABLE_EQ) THEN
+  ASM SET_TAC[]);;
+
+let INTEGRAL_SPLIT = prove
+ (`!f:real^M->real^N a b t k.
+        f integrable_on interval[a,b] /\ 1 <= k /\ k <= dimindex(:M)
+        ==> integral (interval[a,b]) f =
+                integral(interval
+                 [a,(lambda i. if i = k then min (b$k) t else b$i)]) f +
+                integral(interval
+                 [(lambda i. if i = k then max (a$k) t else a$i),b]) f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPLIT THEN
+  MAP_EVERY EXISTS_TAC [`k:num`; `t:real`] THEN
+  ASM_SIMP_TAC[INTERVAL_SPLIT; GSYM HAS_INTEGRAL_INTEGRAL] THEN
+  CONJ_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+  EXISTS_TAC `interval[a:real^M,b]` THEN
+  ASM_SIMP_TAC[SUBSET_INTERVAL; LAMBDA_BETA] THEN
+  REPEAT STRIP_TAC THEN TRY COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC);;
+
+let INTEGRAL_SPLIT_SIGNED = prove
+ (`!f:real^M->real^N a b t k.
+        1 <= k /\ k <= dimindex(:M) /\ a$k <= t /\ a$k <= b$k /\
+        f integrable_on
+        interval[a,(lambda i. if i = k then max (b$k) t else b$i)]
+        ==> integral (interval[a,b]) f =
+                integral(interval
+                 [a,(lambda i. if i = k then t else b$i)]) f +
+                (if b$k < t then -- &1 else &1) %
+                integral(interval
+                 [(lambda i. if i = k then min (b$k) t else a$i),
+                  (lambda i. if i = k then max (b$k) t else b$i)]) f`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [MP_TAC(ISPECL
+    [`f:real^M->real^N`;
+     `a:real^M`;
+     `(lambda i. if i = k then t else (b:real^M)$i):real^M`;
+     `(b:real^M)$k`; `k:num`]
+        INTEGRAL_SPLIT) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+       (REWRITE_RULE[IMP_CONJ] INTEGRABLE_ON_SUBINTERVAL)) THEN
+      ASM_SIMP_TAC[SUBSET_INTERVAL; LAMBDA_BETA] THEN
+      REPEAT STRIP_TAC THEN TRY COND_CASES_TAC THEN
+      ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+      DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC(VECTOR_ARITH
+       `x = y /\ w = z
+        ==> x:real^N = (y + z) + --(&1) % w`) THEN
+      CONJ_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+      REWRITE_TAC[CONS_11; PAIR_EQ; CART_EQ] THEN TRY CONJ_TAC THEN
+      ASM_SIMP_TAC[LAMBDA_BETA] THEN
+      GEN_TAC THEN STRIP_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[] THEN
+      ASM_REAL_ARITH_TAC];
+    MP_TAC(ISPECL
+    [`f:real^M->real^N`;
+     `a:real^M`;
+     `b:real^M`;
+     `t:real`; `k:num`]
+        INTEGRAL_SPLIT) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+       (REWRITE_RULE[IMP_CONJ] INTEGRABLE_ON_SUBINTERVAL)) THEN
+      ASM_SIMP_TAC[SUBSET_INTERVAL; LAMBDA_BETA] THEN
+      REPEAT STRIP_TAC THEN TRY COND_CASES_TAC THEN
+      ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+      DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[VECTOR_MUL_LID] THEN
+      BINOP_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+      REWRITE_TAC[CONS_11; PAIR_EQ; CART_EQ] THEN TRY CONJ_TAC THEN
+      ASM_SIMP_TAC[LAMBDA_BETA] THEN
+      GEN_TAC THEN STRIP_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[] THEN
+      ASM_REAL_ARITH_TAC]]);;
+
+let INTEGRAL_INTERVALS_INCLUSION_EXCLUSION = prove
+ (`!f:real^M->real^N a b c d.
+        f integrable_on interval[a,b] /\
+        c IN interval[a,b] /\ d IN interval[a,b]
+        ==> integral(interval[a,d]) f =
+                vsum {s | s SUBSET 1..dimindex(:M)}
+                    (\s. --(&1) pow CARD {i | i IN s /\ d$i < c$i} %
+                         integral
+                          (interval[(lambda i. if i IN s
+                                               then min (c$i) (d$i)
+                                               else (a:real^M)$i),
+                                    (lambda i. if i IN s
+                                               then max (c$i) (d$i)
+                                               else c$i)]) f)`,
+  let lemma1 = prove
+   (`!f:(num->bool)->real^N n.
+          vsum {s | s SUBSET 1..SUC n} f =
+          vsum {s | s SUBSET 1..n} f +
+          vsum {s | s SUBSET 1..n} (\s. f(SUC n INSERT s))`,
+    REPEAT STRIP_TAC THEN
+    REWRITE_TAC[NUMSEG_CLAUSES; ARITH_RULE `1 <= SUC n`; POWERSET_CLAUSES] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) VSUM_UNION o lhs o snd) THEN
+    ANTS_TAC THENL
+     [ASM_SIMP_TAC[FINITE_IMAGE; FINITE_POWERSET; FINITE_NUMSEG] THEN
+      REWRITE_TAC[SET_RULE
+       `DISJOINT s (IMAGE f t) <=> !x. x IN t ==> ~(f x IN s)`] THEN
+      GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[IN_ELIM_THM; SUBSET] THEN
+      DISCH_THEN(MP_TAC o SPEC `SUC n`) THEN
+      REWRITE_TAC[IN_INSERT; IN_NUMSEG] THEN ARITH_TAC;
+      DISCH_THEN SUBST1_TAC THEN AP_TERM_TAC THEN
+      MATCH_MP_TAC(REWRITE_RULE[o_DEF] VSUM_IMAGE) THEN
+      SIMP_TAC[FINITE_POWERSET; FINITE_NUMSEG] THEN
+      MAP_EVERY X_GEN_TAC [`s:num->bool`; `t:num->bool`] THEN
+      REWRITE_TAC[IN_ELIM_THM] THEN MATCH_MP_TAC(SET_RULE
+       `~(a IN i)
+        ==> s SUBSET i /\ t SUBSET i /\ a INSERT s = a INSERT t
+            ==> s = t`) THEN
+      REWRITE_TAC[IN_NUMSEG] THEN ARITH_TAC]) in
+  let lemma2 = prove
+   (`!f:real^M->real^N m a:real^M c:real^M d:real^M.
+          f integrable_on (:real^M) /\ m <= dimindex(:M) /\
+          (!i. m < i /\ i <= dimindex(:M) ==> a$i = c$i \/ d$i = c$i) /\
+          (!i. m < i /\ i <= dimindex(:M) ==> a$i = c$i ==> a$i = d$i) /\
+          (!i. 1 <= i /\ i <= dimindex(:M) ==> a$i <= c$i /\ a$i <= d$i)
+          ==> integral(interval[a,d]) f =
+                  vsum {s | s SUBSET 1..m}
+                      (\s. --(&1) pow CARD {i | i IN s /\ d$i < c$i} %
+                           integral
+                            (interval[(lambda i. if i IN s
+                                                 then min (c$i) (d$i)
+                                                 else (a:real^M)$i),
+                                      (lambda i. if i IN s
+                                                 then max (c$i) (d$i)
+                                                 else c$i)]) f)`,
+    GEN_TAC THEN INDUCT_TAC THENL
+     [REWRITE_TAC[NUMSEG_CLAUSES; ARITH; SUBSET_EMPTY; SING_GSPEC] THEN
+      REWRITE_TAC[VSUM_SING; NOT_IN_EMPTY; EMPTY_GSPEC; CARD_CLAUSES] THEN
+      REWRITE_TAC[real_pow; LAMBDA_ETA; VECTOR_MUL_LID] THEN
+      REWRITE_TAC[ARITH_RULE `0 < i <=> 1 <= i`] THEN REPEAT STRIP_TAC THEN
+      ASM_CASES_TAC
+       `?k. 1 <= k /\ k <= dimindex(:M) /\ (a:real^M)$k = (c:real^M)$k`
+      THENL
+       [MATCH_MP_TAC(MESON[] `i = vec 0 /\ j = vec 0 ==> i:real^N = j`) THEN
+        CONJ_TAC THEN MATCH_MP_TAC INTEGRAL_NULL THEN
+        REWRITE_TAC[CONTENT_EQ_0] THEN ASM_MESON_TAC[];
+        SUBGOAL_THEN `d:real^M = c:real^M` (fun th -> REWRITE_TAC[th]) THEN
+        REWRITE_TAC[CART_EQ] THEN ASM_MESON_TAC[]];
+      ALL_TAC] THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[lemma1] THEN
+    SUBGOAL_THEN
+     `!s. s SUBSET 1..m
+          ==> --(&1) pow CARD {i | i IN SUC m INSERT s /\ d$i < c$i} =
+              (if (d:real^M)$(SUC m) < (c:real^M)$(SUC m) then -- &1 else &1) *
+              --(&1) pow CARD {i | i IN s /\ d$i < c$i}`
+     (fun th -> SIMP_TAC[th; IN_ELIM_THM]) THENL
+     [X_GEN_TAC `s:num->bool` THEN DISCH_TAC THEN
+      SUBGOAL_THEN `FINITE(s:num->bool)` ASSUME_TAC THENL
+       [ASM_MESON_TAC[FINITE_NUMSEG; FINITE_SUBSET]; ALL_TAC] THEN
+      COND_CASES_TAC THENL
+       [ASM_SIMP_TAC[CARD_CLAUSES; FINITE_RESTRICT; SET_RULE
+         `P a ==> {x | x IN a INSERT s /\ P x} =
+                  a INSERT {x | x IN s /\ P x}`] THEN
+        REWRITE_TAC[IN_ELIM_THM] THEN COND_CASES_TAC THEN
+        ASM_REWRITE_TAC[real_pow] THEN
+        SUBGOAL_THEN `~(SUC m IN 1..m)` (fun th -> ASM SET_TAC[th]) THEN
+        REWRITE_TAC[IN_NUMSEG] THEN ARITH_TAC;
+        ASM_SIMP_TAC[REAL_MUL_LID; SET_RULE
+         `~(P a) ==> {x | x IN a INSERT s /\ P x} = {x | x IN s /\ P x}`]];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`f:real^M->real^N`; `a:real^M`; `d:real^M`; `(c:real^M)$SUC m`; `SUC m`]
+         INTEGRAL_SPLIT_SIGNED) THEN
+    ANTS_TAC THENL
+     [ASM_MESON_TAC[ARITH_RULE `1 <= SUC n`; INTEGRABLE_ON_SUBINTERVAL;
+                    SUBSET_UNIV];
+      DISCH_THEN SUBST1_TAC] THEN
+    REWRITE_TAC[VSUM_LMUL; GSYM VECTOR_MUL_ASSOC] THEN
+    BINOP_TAC THENL [ALL_TAC; AP_TERM_TAC] THENL
+     [FIRST_X_ASSUM(MP_TAC o SPECL
+       [`a:real^M`;
+        `c:real^M`;
+        `(lambda i. if i = SUC m then (c:real^M)$SUC m
+                    else (d:real^M)$i):real^M`]);
+      FIRST_X_ASSUM(MP_TAC o SPECL
+       [`(lambda i. if i = SUC m
+                    then min ((d:real^M)$SUC m) ((c:real^M)$SUC m)
+                    else (a:real^M)$i):real^M`;
+        `(lambda i. if i = SUC m
+                    then max ((d:real^M)$SUC m) ((c:real^M)$SUC m)
+                    else (c:real^M)$i):real^M`;
+        `(lambda i. if i = SUC m
+                    then max ((d:real^M)$SUC m) ((c:real^M)$SUC m)
+                    else d$i):real^M`])] THEN
+    (ANTS_TAC THENL
+      [ASM_REWRITE_TAC[] THEN
+       CONJ_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+       CONJ_TAC THENL
+        [X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+         SUBGOAL_THEN `1 <= i` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+         ASM_SIMP_TAC[LAMBDA_BETA] THEN
+         COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+         FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC;
+         ALL_TAC] THEN
+       CONJ_TAC THENL
+        [X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+         SUBGOAL_THEN `1 <= i` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+         ASM_SIMP_TAC[LAMBDA_BETA] THEN
+         COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+         ASM_MESON_TAC[ARITH_RULE `m < i <=> i = SUC m \/ SUC m < i`];
+         X_GEN_TAC `i:num` THEN STRIP_TAC THEN ASM_SIMP_TAC[LAMBDA_BETA] THEN
+         COND_CASES_TAC THEN ASM_SIMP_TAC[] THEN TRY REAL_ARITH_TAC THEN
+         FIRST_X_ASSUM SUBST_ALL_TAC THEN ASM_REWRITE_TAC[] THEN
+         ASM_MESON_TAC[]];
+       DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC VSUM_EQ THEN
+       X_GEN_TAC `s:num->bool` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+       DISCH_TAC THEN BINOP_TAC THENL
+        [AP_TERM_TAC THEN AP_TERM_TAC THEN
+         REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+         X_GEN_TAC `i:num` THEN
+         ASM_CASES_TAC `(i:num) IN s` THEN ASM_REWRITE_TAC[] THEN
+         SUBGOAL_THEN `i IN 1..m` MP_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+         REWRITE_TAC[IN_NUMSEG] THEN STRIP_TAC THEN
+         SUBGOAL_THEN `i <= dimindex(:M)` ASSUME_TAC THENL
+          [ASM_ARITH_TAC; ALL_TAC] THEN
+         ASM_SIMP_TAC[LAMBDA_BETA] THEN
+         COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC;
+         AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+         REWRITE_TAC[CONS_11; PAIR_EQ] THEN
+         SIMP_TAC[CART_EQ; LAMBDA_BETA; AND_FORALL_THM] THEN
+         X_GEN_TAC `i:num` THEN
+         ASM_CASES_TAC `1 <= i /\ i <= dimindex(:M)` THEN
+         ASM_REWRITE_TAC[] THEN
+         ASM_CASES_TAC `(i:num) IN s` THEN ASM_REWRITE_TAC[IN_INSERT] THEN
+         COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN TRY REAL_ARITH_TAC THEN
+         SUBGOAL_THEN `~(SUC m IN 1..m)` (fun th -> ASM SET_TAC[th]) THEN
+         REWRITE_TAC[IN_NUMSEG] THEN ARITH_TAC]])) in
+  REWRITE_TAC[IN_INTERVAL] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`\x. if x IN interval[a,b] then (f:real^M->real^N) x else vec 0`;
+    `dimindex(:M)`; `a:real^M`; `c:real^M`; `d:real^M`]
+   lemma2) THEN
+  ASM_SIMP_TAC[LTE_ANTISYM; INTEGRABLE_RESTRICT_UNIV; LE_REFL] THEN
+  MATCH_MP_TAC EQ_IMP THEN BINOP_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC VSUM_EQ THEN X_GEN_TAC `s:num->bool` THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN AP_TERM_TAC] THEN
+  MATCH_MP_TAC INTEGRAL_EQ THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(SET_RULE
+   `i SUBSET j ==> !x. x IN i ==> (if x IN j then f x else b) = f x`) THEN
+  ASM_SIMP_TAC[SUBSET_INTERVAL; REAL_LE_REFL; LAMBDA_BETA] THEN
+  DISCH_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `i:num`)) THEN
+  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let INTEGRAL_INTERVALS_DIFF_INCLUSION_EXCLUSION = prove
+ (`!f:real^M->real^N a b c d.
+        f integrable_on interval[a,b] /\
+        c IN interval[a,b] /\ d IN interval[a,b]
+        ==> integral(interval[a,d]) f - integral(interval[a,c]) f =
+                vsum {s | ~(s = {}) /\ s SUBSET 1..dimindex(:M)}
+                    (\s. --(&1) pow CARD {i | i IN s /\ d$i < c$i} %
+                         integral
+                          (interval[(lambda i. if i IN s
+                                               then min (c$i) (d$i)
+                                               else (a:real^M)$i),
+                                    (lambda i. if i IN s
+                                               then max (c$i) (d$i)
+                                               else c$i)]) f)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(SUBST1_TAC o
+   MATCH_MP INTEGRAL_INTERVALS_INCLUSION_EXCLUSION) THEN
+  REWRITE_TAC[SET_RULE `{s | ~(s = a) /\ P s} = {s | P s} DELETE a`] THEN
+  SIMP_TAC[VSUM_DELETE; FINITE_POWERSET; FINITE_NUMSEG; EMPTY_SUBSET;
+           IN_ELIM_THM] THEN
+  REWRITE_TAC[NOT_IN_EMPTY; EMPTY_GSPEC; CARD_CLAUSES; LAMBDA_ETA] THEN
+  REWRITE_TAC[real_pow; VECTOR_MUL_LID]);;
+
+let INTEGRAL_INTERVALS_INCLUSION_EXCLUSION_RIGHT = prove
+ (`!f:real^M->real^N a b c.
+        f integrable_on interval[a,b] /\ c IN interval[a,b]
+        ==> integral(interval[a,c]) f =
+                vsum {s | s SUBSET 1..dimindex (:M)}
+                     (\s. --(&1) pow CARD s %
+                          integral
+                           (interval[(lambda i. if i IN s then c$i else a$i),
+                                     b])
+                           f)`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`f:real^M->real^N`; `a:real^M`; `b:real^M`; `b:real^M`; `c:real^M`]
+        INTEGRAL_INTERVALS_INCLUSION_EXCLUSION) THEN
+  ASM_REWRITE_TAC[ENDS_IN_INTERVAL] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[ENDS_IN_INTERVAL; MEMBER_NOT_EMPTY]; ALL_TAC] THEN
+  DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC VSUM_EQ THEN
+  X_GEN_TAC `s:num->bool` THEN REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN
+  ASM_CASES_TAC `?k. k IN s /\ (c:real^M)$k = (b:real^M)$k` THENL
+   [FIRST_X_ASSUM(X_CHOOSE_THEN `k:num` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `1 <= k /\ k <= dimindex(:M)` STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[IN_NUMSEG; SUBSET]; ALL_TAC] THEN
+    MATCH_MP_TAC(MESON[] `a:real^N = vec 0 /\ b = vec 0 ==> a = b`) THEN
+    CONJ_TAC THEN REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISJ2_TAC THEN
+    MATCH_MP_TAC INTEGRAL_NULL THEN REWRITE_TAC[CONTENT_EQ_0] THEN
+    EXISTS_TAC `k:num` THEN ASM_SIMP_TAC[LAMBDA_BETA] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL]) THEN BINOP_TAC THENL
+   [AP_TERM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+    ASM_MESON_TAC[REAL_LT_LE; SUBSET; IN_NUMSEG];
+    AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN
+    ASM_SIMP_TAC[CART_EQ; PAIR_EQ; LAMBDA_BETA] THEN
+    CONJ_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+    REAL_ARITH_TAC]);;
+
+let INTEGRAL_INTERVALS_INCLUSION_EXCLUSION_LEFT = prove
+ (`!f:real^M->real^N a b c.
+        f integrable_on interval[a,b] /\ c IN interval[a,b]
+        ==> integral(interval[c,b]) f =
+                vsum {s | s SUBSET 1..dimindex (:M)}
+                     (\s. --(&1) pow CARD s %
+                          integral
+                           (interval[a,(lambda i. if i IN s then c$i else b$i)])
+                           f)`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`\x. (f:real^M->real^N) (--x)`;
+    `--b:real^M`;
+    `--a:real^M`;
+    `--c:real^M`]
+        INTEGRAL_INTERVALS_INCLUSION_EXCLUSION_RIGHT) THEN
+  REWRITE_TAC[REAL_ARITH `min (--a) (--b) = --(max a b)`;
+              REAL_ARITH `max (--a) (--b) = --(min a b)`;
+              VECTOR_NEG_COMPONENT] THEN
+  SUBGOAL_THEN
+   `!P x y. (lambda i. if P i then --(x i) else --(y i)):real^M =
+            --(lambda i. if P i then x i else y i)`
+   (fun th -> REWRITE_TAC[th])
+  THENL
+   [SIMP_TAC[CART_EQ; VECTOR_NEG_COMPONENT; LAMBDA_BETA] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[INTEGRAL_REFLECT; INTEGRABLE_REFLECT;
+                  IN_INTERVAL_REFLECT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A straddling criterion for integrability.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let INTEGRABLE_STRADDLE_INTERVAL = prove
+ (`!f:real^N->real^1 a b.
+        (!e. &0 < e
+             ==> ?g h i j. (g has_integral i) (interval[a,b]) /\
+                           (h has_integral j) (interval[a,b]) /\
+                           norm(i - j) < e /\
+                           !x. x IN interval[a,b]
+                               ==> drop(g x) <= drop(f x) /\
+                                   drop(f x) <= drop(h x))
+        ==> f integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[INTEGRABLE_CAUCHY] 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; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`g:real^N->real^1`; `h:real^N->real^1`; `i:real^1`; `j:real^1`] THEN
+  REWRITE_TAC[has_integral] THEN REWRITE_TAC[IMP_CONJ] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &3`) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real^N->real^N->bool` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &3`) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d2:real^N->real^N->bool` STRIP_ASSUME_TAC) THEN
+  DISCH_TAC THEN DISCH_TAC THEN
+  EXISTS_TAC `(\x. d1 x INTER d2 x):real^N->real^N->bool` THEN
+  ASM_SIMP_TAC[GAUGE_INTER; FINE_INTER] THEN
+  MAP_EVERY X_GEN_TAC
+   [`p1:(real^N#(real^N->bool))->bool`;
+    `p2:(real^N#(real^N->bool))->bool`] THEN
+  REPEAT STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(fun th ->
+   MP_TAC(SPEC `p1:(real^N#(real^N->bool))->bool` th) THEN
+   MP_TAC(SPEC `p2:(real^N#(real^N->bool))->bool` th))) THEN
+  EVERY_ASSUM(fun th -> try ASSUME_TAC(MATCH_MP TAGGED_DIVISION_OF_FINITE th)
+                        with Failure _ -> ALL_TAC) THEN
+  ASM_SIMP_TAC[VSUM_REAL] THEN REWRITE_TAC[o_DEF; LAMBDA_PAIR_THM] THEN
+  SUBST1_TAC(SYM(ISPEC `i:real^1` (CONJUNCT1 LIFT_DROP))) THEN
+  SUBST1_TAC(SYM(ISPEC `j:real^1` (CONJUNCT1 LIFT_DROP))) THEN
+  REWRITE_TAC[GSYM LIFT_SUB; DROP_CMUL; NORM_LIFT] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `g1 - h2 <= f1 - f2 /\ f1 - f2 <= h1 - g2 /\
+    abs(i - j) < e / &3
+    ==> abs(g2 - i) < e / &3
+        ==> abs(g1 - i) < e / &3
+            ==> abs(h2 - j) < e / &3
+                ==> abs(h1 - j) < e / &3
+                    ==> abs(f1 - f2) < e`) THEN
+  ASM_REWRITE_TAC[GSYM DROP_SUB; GSYM NORM_LIFT; LIFT_DROP] THEN CONJ_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH `x <= x' /\ y' <= y ==> x - y <= x' - y'`) THEN
+  CONJ_TAC THEN MATCH_MP_TAC SUM_LE THEN
+  REWRITE_TAC[FORALL_PAIR_THM] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
+  ASM_MESON_TAC[TAGGED_DIVISION_OF; CONTENT_POS_LE; SUBSET]);;
+
+let INTEGRABLE_STRADDLE = prove
+ (`!f:real^N->real^1 s.
+        (!e. &0 < e
+             ==> ?g h i j. (g has_integral i) s /\
+                           (h has_integral j) s /\
+                           norm(i - j) < e /\
+                           !x. x IN s
+                               ==> drop(g x) <= drop(f x) /\
+                                   drop(f x) <= drop(h x))
+        ==> f integrable_on s`,
+  let lemma = prove
+   (`&0 <= drop x /\ drop x <= drop y ==> norm x <= norm y`,
+    REWRITE_TAC[NORM_REAL; GSYM drop] THEN REAL_ARITH_TAC) in
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!a b. (\x. if x IN s then (f:real^N->real^1) x else vec 0)
+          integrable_on interval[a,b]`
+  ASSUME_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[HAS_INTEGRAL_ALT]) THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+    MATCH_MP_TAC INTEGRABLE_STRADDLE_INTERVAL THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `e / &4`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC
+     [`g:real^N->real^1`; `h:real^N->real^1`; `i:real^1`; `j:real^1`] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (MP_TAC o SPEC `e / &4`) MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (MP_TAC o SPEC `e / &4`) STRIP_ASSUME_TAC) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+    DISCH_THEN(X_CHOOSE_THEN `B2:real`
+     (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "H"))) THEN
+    DISCH_THEN(X_CHOOSE_THEN `B1:real`
+     (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "G"))) THEN
+    MAP_EVERY EXISTS_TAC
+     [`\x. if x IN s then (g:real^N->real^1) x else vec 0`;
+      `\x. if x IN s then (h:real^N->real^1) x else vec 0`;
+      `integral(interval[a:real^N,b])
+         (\x. if x IN s then (g:real^N->real^1) x else vec 0:real^1)`;
+      `integral(interval[a:real^N,b])
+         (\x. if x IN s then (h:real^N->real^1) x else vec 0:real^1)`] THEN
+    ASM_SIMP_TAC[INTEGRABLE_INTEGRAL] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[REAL_LE_REFL]] THEN
+    ABBREV_TAC `c:real^N = lambda i. min ((a:real^N)$i) (--(max B1 B2))` THEN
+    ABBREV_TAC `d:real^N = lambda i. max ((b:real^N)$i) (max B1 B2)` THEN
+    REMOVE_THEN "H" (MP_TAC o SPECL [`c:real^N`; `d:real^N`]) THEN
+    REMOVE_THEN "G" (MP_TAC o SPECL [`c:real^N`; `d:real^N`]) THEN
+    MATCH_MP_TAC(TAUT
+        `(a /\ c) /\ (b /\ d ==> e) ==> (a ==> b) ==> (c ==> d) ==> e`) THEN
+    CONJ_TAC THENL
+     [CONJ_TAC THEN MAP_EVERY EXPAND_TAC ["c"; "d"] THEN
+      SIMP_TAC[SUBSET; IN_BALL; IN_INTERVAL; LAMBDA_BETA] THEN
+      GEN_TAC THEN REWRITE_TAC[NORM_ARITH `dist(vec 0,x) = norm x`] THEN
+      DISCH_TAC THEN X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH
+        `abs(x) <= B ==> min a (--B) <= x /\ x <= max b B`) THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `norm(x:real^N)` THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE; COMPONENT_LE_NORM; REAL_LE_MAX];
+      ALL_TAC] THEN
+    MATCH_MP_TAC(NORM_ARITH
+       `norm(i - j) < e / &4 /\
+        norm(ah - ag) <= norm(ch - cg)
+        ==> norm(cg - i) < e / &4 /\
+            norm(ch - j) < e / &4
+            ==> norm(ag - ah) < e`) THEN
+    ASM_REWRITE_TAC[] THEN ASM_SIMP_TAC[GSYM INTEGRAL_SUB] THEN
+    MATCH_MP_TAC lemma THEN CONJ_TAC THENL
+     [MATCH_MP_TAC(INST_TYPE [`:N`,`:M`] HAS_INTEGRAL_DROP_POS) THEN
+      MAP_EVERY EXISTS_TAC
+       [`(\x. (if x IN s then h x else vec 0) - (if x IN s then g x else vec 0))
+         :real^N->real^1`;
+        `interval[a:real^N,b]`] THEN
+      ASM_SIMP_TAC[INTEGRABLE_INTEGRAL; HAS_INTEGRAL_SUB] THEN
+      ASM_SIMP_TAC[INTEGRABLE_SUB; INTEGRABLE_INTEGRAL] THEN
+      REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+      ASM_SIMP_TAC[DROP_SUB; DROP_VEC; REAL_SUB_LE; REAL_POS] THEN
+      ASM_MESON_TAC[REAL_LE_TRANS];
+      ALL_TAC] THEN
+    MATCH_MP_TAC(INST_TYPE [`:N`,`:M`] HAS_INTEGRAL_SUBSET_DROP_LE) THEN
+    MAP_EVERY EXISTS_TAC
+     [`(\x. (if x IN s then h x else vec 0) - (if x IN s then g x else vec 0))
+       :real^N->real^1`;
+      `interval[a:real^N,b]`; `interval[c:real^N,d]`] THEN
+    ASM_SIMP_TAC[INTEGRABLE_SUB; INTEGRABLE_INTEGRAL] THEN CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET_INTERVAL] THEN DISCH_TAC THEN
+      MAP_EVERY EXPAND_TAC ["c"; "d"] THEN
+      SIMP_TAC[LAMBDA_BETA] THEN REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+    ASM_SIMP_TAC[DROP_SUB; DROP_VEC; REAL_SUB_LE; REAL_POS] THEN
+    ASM_MESON_TAC[REAL_LE_TRANS];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[INTEGRABLE_ALT] THEN ASM_REWRITE_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
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; HAS_INTEGRAL_ALT] THEN
+  MAP_EVERY X_GEN_TAC
+   [`g:real^N->real^1`; `h:real^N->real^1`; `i:real^1`; `j:real^1`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `e / &3`)) THEN
+  FIRST_X_ASSUM(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `e / &3`)) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B1:real`
+    (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "G"))) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B2:real`
+    (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "H"))) THEN
+  EXISTS_TAC `max B1 B2` THEN
+  ASM_REWRITE_TAC[REAL_LT_MAX; BALL_MAX_UNION; UNION_SUBSET] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`; `c:real^N`; `d:real^N`] THEN
+  STRIP_TAC THEN REWRITE_TAC[ABS_DROP; DROP_SUB] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `!ga gc ha hc i j.
+        ga <= fa /\ fa <= ha /\
+        gc <= fc /\ fc <= hc /\
+        abs(ga - i) < e / &3 /\
+        abs(gc - i) < e / &3 /\
+        abs(ha - j) < e / &3 /\
+        abs(hc - j) < e / &3 /\
+        abs(i - j) < e / &3
+        ==> abs(fa - fc) < e`) THEN
+  MAP_EVERY EXISTS_TAC
+   [`drop(integral(interval[a:real^N,b]) (\x. if x IN s then g x else vec 0))`;
+    `drop(integral(interval[c:real^N,d]) (\x. if x IN s then g x else vec 0))`;
+    `drop(integral(interval[a:real^N,b]) (\x. if x IN s then h x else vec 0))`;
+    `drop(integral(interval[c:real^N,d]) (\x. if x IN s then h x else vec 0))`;
+    `drop i`; `drop j`] THEN
+  REWRITE_TAC[GSYM DROP_SUB; GSYM ABS_DROP] THEN ASM_SIMP_TAC[] THEN
+  REPEAT CONJ_TAC THEN MATCH_MP_TAC INTEGRAL_DROP_LE THEN
+  ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[REAL_LE_REFL]);;
+
+let HAS_INTEGRAL_STRADDLE_NULL = prove
+ (`!f g:real^N->real^1 s.
+        (!x. x IN s ==> &0 <= drop(f x) /\ drop(f x) <= drop(g x)) /\
+        (g has_integral (vec 0)) s
+        ==> (f has_integral (vec 0)) s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[HAS_INTEGRAL_INTEGRABLE_INTEGRAL] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC INTEGRABLE_STRADDLE THEN
+    GEN_TAC THEN DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC
+     [`(\x. vec 0):real^N->real^1`; `g:real^N->real^1`;
+      `vec 0:real^1`; `vec 0:real^1`] THEN
+    ASM_REWRITE_TAC[DROP_VEC; HAS_INTEGRAL_0; VECTOR_SUB_REFL; NORM_0];
+    DISCH_TAC THEN ONCE_REWRITE_TAC[GSYM DROP_EQ] THEN
+    REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC(ISPECL [`f:real^N->real^1`; `g:real^N->real^1`]
+        HAS_INTEGRAL_DROP_LE);
+      MATCH_MP_TAC(ISPECL [`(\x. vec 0):real^N->real^1`; `f:real^N->real^1`]
+        HAS_INTEGRAL_DROP_LE)] THEN
+    EXISTS_TAC `s:real^N->bool` THEN
+    ASM_SIMP_TAC[GSYM HAS_INTEGRAL_INTEGRAL; DROP_VEC; HAS_INTEGRAL_0]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Adding integrals over several sets.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_UNION = prove
+ (`!f:real^M->real^N i j s t.
+        (f has_integral i) s /\ (f has_integral j) t /\ negligible(s INTER t)
+        ==> (f has_integral (i + j)) (s UNION t)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM HAS_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPIKE THEN
+  EXISTS_TAC `(\x. if x IN (s INTER t) then &2 % f(x)
+                   else if x IN (s UNION t) then f(x)
+                   else vec 0):real^M->real^N` THEN
+  EXISTS_TAC `s INTER t:real^M->bool` THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_UNION; IN_INTER; IN_UNIV] THEN
+  CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP HAS_INTEGRAL_ADD) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN
+  MAP_EVERY ASM_CASES_TAC [`(x:real^M) IN s`; `(x:real^M) IN t`] THEN
+  ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC);;
+
+let INTEGRAL_UNION = prove
+ (`!f:real^M->real^N s t.
+        f integrable_on s /\ f integrable_on t /\ negligible(s INTER t)
+        ==> integral (s UNION t) f = integral s f + integral t f`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_INTEGRAL_UNION THEN
+  ASM_REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL]);;
+
+let HAS_INTEGRAL_UNIONS = prove
+ (`!f:real^M->real^N i t.
+        FINITE t /\
+        (!s. s IN t ==> (f has_integral (i s)) s) /\
+        (!s s'. s IN t /\ s' IN t /\ ~(s = s') ==> negligible(s INTER s'))
+        ==> (f has_integral (vsum t i)) (UNIONS t)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM HAS_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HAS_INTEGRAL_VSUM) THEN REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+                HAS_INTEGRAL_SPIKE) THEN
+  EXISTS_TAC
+   `UNIONS (IMAGE (\(a,b). a INTER b :real^M->bool)
+                  {a,b | a IN t /\ b IN {y | y IN t /\ ~(a = y)}})` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC NEGLIGIBLE_UNIONS THEN CONJ_TAC THENL
+     [MATCH_MP_TAC FINITE_IMAGE THEN MATCH_MP_TAC FINITE_PRODUCT_DEPENDENT THEN
+      ASM_SIMP_TAC[FINITE_RESTRICT];
+      REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM; IN_ELIM_PAIR_THM] THEN
+      ASM_SIMP_TAC[IN_ELIM_THM]];
+    X_GEN_TAC `x:real^M` THEN REWRITE_TAC[IN_UNIV; IN_DIFF] THEN
+    ASM_CASES_TAC `(x:real^M) IN UNIONS t` THEN ASM_REWRITE_TAC[] THENL
+     [ALL_TAC;
+      RULE_ASSUM_TAC(REWRITE_RULE[SET_RULE
+       `~(x IN UNIONS t) <=> !s. s IN t ==> ~(x IN s)`]) THEN
+      ASM_SIMP_TAC[VSUM_0]] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_UNIONS]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `a:real^M->bool` STRIP_ASSUME_TAC) THEN
+    REWRITE_TAC[IN_UNIONS; EXISTS_IN_IMAGE; EXISTS_PAIR_THM] THEN
+    REWRITE_TAC[IN_ELIM_PAIR_THM; NOT_EXISTS_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `a:real^M->bool`) THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM; IN_INTER] THEN
+    ASM_SIMP_TAC[MESON[]
+     `x IN a /\ a IN t
+      ==> ((!b. ~((b IN t /\ ~(a = b)) /\ x IN b)) <=>
+           (!b. b IN t ==> (x IN b <=> b = a)))`] THEN
+    ASM_REWRITE_TAC[VSUM_DELTA]]);;
+
+let HAS_INTEGRAL_DIFF = prove
+ (`!f:real^M->real^N i j s t.
+    (f has_integral i) s /\
+    (f has_integral j) t /\
+    negligible (t DIFF s)
+    ==> (f has_integral (i - j)) (s DIFF t)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM HAS_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPIKE THEN
+  EXISTS_TAC `(\x. if x IN (t DIFF s) then --(f x)
+                   else if x IN (s DIFF t) then f x
+                   else vec 0):real^M->real^N` THEN
+  EXISTS_TAC `t DIFF s:real^M->bool` THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_UNION; IN_INTER; IN_UNIV] THEN
+  CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP HAS_INTEGRAL_SUB) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN
+  MAP_EVERY ASM_CASES_TAC [`(x:real^M) IN s`; `(x:real^M) IN t`] THEN
+  ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC);;
+
+let INTEGRAL_DIFF = prove
+ (`!f:real^M->real^N s t.
+        f integrable_on s /\ f integrable_on t /\ negligible(t DIFF s)
+        ==> integral (s DIFF t) f = integral s f - integral t f`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_INTEGRAL_DIFF THEN
+  ASM_REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In particular adding integrals over a division, maybe not of an interval. *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_COMBINE_DIVISION = prove
+ (`!f:real^M->real^N s d i.
+        d division_of s /\
+        (!k. k IN d ==> (f has_integral (i k)) k)
+        ==> (f has_integral (vsum d i)) s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM o last o CONJUNCTS o
+              GEN_REWRITE_RULE I [division_of]) THEN
+  MATCH_MP_TAC HAS_INTEGRAL_UNIONS THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[DIVISION_OF_FINITE]; ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`k1:real^M->bool`; `k2:real^M->bool`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `?u v:real^M x y:real^M.
+                k1 = interval[u,v] /\ k2 = interval[x,y]`
+   (REPEAT_TCL CHOOSE_THEN (CONJUNCTS_THEN SUBST_ALL_TAC))
+  THENL [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o el 2 o CONJUNCTS o
+              GEN_REWRITE_RULE I [division_of]) THEN
+  DISCH_THEN(MP_TAC o SPECL
+   [`interval[u:real^M,v]`; `interval[x:real^M,y]`]) THEN
+  ASM_REWRITE_TAC[INTERIOR_CLOSED_INTERVAL] THEN DISCH_TAC THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `(interval[u,v:real^M] DIFF interval(u,v)) UNION
+              (interval[x,y] DIFF interval(x,y))` THEN
+  SIMP_TAC[NEGLIGIBLE_FRONTIER_INTERVAL; NEGLIGIBLE_UNION] THEN
+  ASM SET_TAC[]);;
+
+let INTEGRAL_COMBINE_DIVISION_BOTTOMUP = prove
+ (`!f:real^M->real^N d s.
+        d division_of s /\ (!k. k IN d ==> f integrable_on k)
+        ==> integral s f = vsum d (\i. integral i f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMBINE_DIVISION THEN
+  ASM_REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL]);;
+
+let HAS_INTEGRAL_COMBINE_DIVISION_TOPDOWN = prove
+ (`!f:real^M->real^N s d k.
+        f integrable_on s /\ d division_of k /\ k SUBSET s
+        ==> (f has_integral (vsum d (\i. integral i f))) k`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMBINE_DIVISION THEN
+  ASM_REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[division_of; SUBSET_TRANS]);;
+
+let INTEGRAL_COMBINE_DIVISION_TOPDOWN = prove
+ (`!f:real^M->real^N d s.
+        f integrable_on s /\ d division_of s
+        ==> integral s f = vsum d (\i. integral i f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMBINE_DIVISION_TOPDOWN THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[SUBSET_REFL]);;
+
+let INTEGRABLE_COMBINE_DIVISION = prove
+ (`!f d s.
+        d division_of s /\ (!i. i IN d ==> f integrable_on i)
+        ==> f integrable_on s`,
+  REWRITE_TAC[integrable_on] THEN MESON_TAC[HAS_INTEGRAL_COMBINE_DIVISION]);;
+
+let INTEGRABLE_ON_SUBDIVISION = prove
+ (`!f:real^M->real^N s d i.
+        d division_of i /\
+        f integrable_on s /\ i SUBSET s
+        ==> f integrable_on i`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_COMBINE_DIVISION THEN
+  EXISTS_TAC `d:(real^M->bool)->bool` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+  ASM_MESON_TAC[division_of; UNIONS_SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Also tagged divisions.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_COMBINE_TAGGED_DIVISION = prove
+ (`!f:real^M->real^N s p i.
+        p tagged_division_of s /\
+        (!x k. (x,k) IN p ==> (f has_integral (i k)) k)
+        ==> (f has_integral (vsum p (\(x,k). i k))) s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x:real^M k:real^M->bool.
+      (x,k) IN p ==> ((f:real^M->real^N) has_integral integral k f) k`
+  ASSUME_TAC THENL
+   [ASM_MESON_TAC[HAS_INTEGRAL_INTEGRAL; integrable_on]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `((f:real^M->real^N) has_integral
+     (vsum (IMAGE SND (p:real^M#(real^M->bool)->bool))
+           (\k. integral k f))) s`
+  MP_TAC THENL
+   [MATCH_MP_TAC HAS_INTEGRAL_COMBINE_DIVISION THEN
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM] THEN
+    ASM_SIMP_TAC[DIVISION_OF_TAGGED_DIVISION];
+    ALL_TAC] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN
+  AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `vsum p (\(x:real^M,k:real^M->bool). integral k f:real^N)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC VSUM_EQ THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+    ASM_MESON_TAC[HAS_INTEGRAL_UNIQUE];
+    MATCH_MP_TAC VSUM_OVER_TAGGED_DIVISION_LEMMA THEN
+    EXISTS_TAC `s:real^M->bool` THEN ASM_SIMP_TAC[INTEGRAL_NULL]]);;
+
+let INTEGRAL_COMBINE_TAGGED_DIVISION_BOTTOMUP = prove
+ (`!f:real^M->real^N p a b.
+        p tagged_division_of interval[a,b] /\
+        (!x k. (x,k) IN p ==> f integrable_on k)
+        ==> integral (interval[a,b]) f = vsum p (\(x,k). integral k f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMBINE_TAGGED_DIVISION THEN
+  ASM_REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL]);;
+
+let HAS_INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN = prove
+ (`!f:real^M->real^N a b p.
+        f integrable_on interval[a,b] /\ p tagged_division_of interval[a,b]
+        ==> (f has_integral (vsum p (\(x,k). integral k f))) (interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMBINE_TAGGED_DIVISION THEN
+  ASM_REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL] THEN
+  ASM_MESON_TAC[INTEGRABLE_SUBINTERVAL; TAGGED_DIVISION_OF]);;
+
+let INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN = prove
+ (`!f:real^M->real^N a b p.
+        f integrable_on interval[a,b] /\ p tagged_division_of interval[a,b]
+        ==> integral (interval[a,b]) f = vsum p (\(x,k). integral k f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN THEN
+  ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Henstock's lemma.                                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let HENSTOCK_LEMMA_PART1 = prove
+ (`!f:real^M->real^N a b d e.
+        f integrable_on interval[a,b] /\
+        &0 < e /\ gauge d /\
+        (!p. p tagged_division_of interval[a,b] /\ d fine p
+             ==> norm (vsum p (\(x,k). content k % f x) -
+                       integral(interval[a,b]) f) < e)
+        ==> !p. p tagged_partial_division_of interval[a,b] /\ d fine p
+                            ==> norm(vsum p (\(x,k). content k % f x -
+                                                     integral k f)) <= e`,
+  let lemma = prove
+   (`(!k. &0 < k ==> x <= e + k) ==> x <= e`,
+    DISCH_THEN(MP_TAC o SPEC `(x - e) / &2`) THEN REAL_ARITH_TAC) in
+  REPEAT GEN_TAC THEN STRIP_TAC THEN GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC lemma THEN X_GEN_TAC `k:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL
+    [`IMAGE SND (p:(real^M#(real^M->bool))->bool)`; `a:real^M`; `b:real^M`]
+    PARTIAL_DIVISION_EXTEND_INTERVAL) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [ASM_MESON_TAC[PARTIAL_DIVISION_OF_TAGGED_DIVISION]; ALL_TAC] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_UNIONS] THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[FORALL_PAIR_THM] THEN
+    ASM_MESON_TAC[tagged_partial_division_of; SUBSET];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `FINITE(p:(real^M#(real^M->bool))->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[tagged_partial_division_of]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `q:(real^M->bool)->bool` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP(SET_RULE
+   `s SUBSET t ==> t = s UNION (t DIFF s)`)) THEN
+  ABBREV_TAC `r = q DIFF IMAGE SND (p:(real^M#(real^M->bool))->bool)` THEN
+  SUBGOAL_THEN `IMAGE SND (p:(real^M#(real^M->bool))->bool) INTER r = {}`
+  ASSUME_TAC THENL [EXPAND_TAC "r" THEN SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN SUBST_ALL_TAC THEN
+  SUBGOAL_THEN `FINITE(r:(real^M->bool)->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[division_of; FINITE_UNION]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!i. i IN r
+        ==> ?p. p tagged_division_of i /\ d fine p /\
+                norm(vsum p (\(x,j). content j % f x) -
+                     integral i (f:real^M->real^N))
+                < k / (&(CARD(r:(real^M->bool)->bool)) + &1)`
+  MP_TAC THENL
+   [X_GEN_TAC `i:real^M->bool` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `(i:real^M->bool) SUBSET interval[a,b]` ASSUME_TAC THENL
+     [ASM_MESON_TAC[division_of; IN_UNION]; ALL_TAC] THEN
+    SUBGOAL_THEN `?u v:real^M. i = interval[u,v]`
+     (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+    THENL [ASM_MESON_TAC[division_of; IN_UNION]; ALL_TAC] THEN
+    SUBGOAL_THEN `(f:real^M->real^N) integrable_on interval[u,v]` MP_TAC THENL
+     [ASM_MESON_TAC[INTEGRABLE_SUBINTERVAL]; ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP INTEGRABLE_INTEGRAL) THEN
+    REWRITE_TAC[has_integral] THEN
+    DISCH_THEN(MP_TAC o SPEC `k / (&(CARD(r:(real^M->bool)->bool)) + &1)`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < &n + &1`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `dd:real^M->real^M->bool` MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    MP_TAC(ISPECL [`d:real^M->real^M->bool`; `dd:real^M->real^M->bool`]
+      GAUGE_INTER) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP FINE_DIVISION_EXISTS) THEN
+    DISCH_THEN(MP_TAC o SPECL [`u:real^M`; `v:real^M`]) THEN
+    REWRITE_TAC[FINE_INTER] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  REWRITE_TAC[TAUT `(a ==> b /\ c) <=> (a ==> b) /\ (a ==> c)`] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `q:(real^M->bool)->(real^M#(real^M->bool))->bool`
+    STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC
+    `p UNION UNIONS {q (i:real^M->bool) | i IN r}
+     :(real^M#(real^M->bool))->bool`) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC FINE_UNION THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC FINE_UNIONS THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      ASM_REWRITE_TAC[FORALL_IN_IMAGE]] THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM o last o CONJUNCTS o
+                GEN_REWRITE_RULE I [division_of]) THEN
+    REWRITE_TAC[UNIONS_UNION] THEN
+    MATCH_MP_TAC TAGGED_DIVISION_UNION THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[TAGGED_PARTIAL_DIVISION_OF_UNION_SELF]; ALL_TAC] THEN
+    CONJ_TAC THENL
+     [ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      MATCH_MP_TAC TAGGED_DIVISION_UNIONS THEN
+      FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+      SIMP_TAC[FINITE_UNION; IN_UNION] THEN ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC INTER_INTERIOR_UNIONS_INTERVALS THEN
+    REWRITE_TAC[OPEN_INTERIOR] THEN
+    REPEAT(CONJ_TAC THENL
+            [ASM_MESON_TAC[division_of; FINITE_UNION; IN_UNION]; ALL_TAC]) THEN
+    X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN
+    ONCE_REWRITE_TAC[INTER_COMM] THEN
+    MATCH_MP_TAC INTER_INTERIOR_UNIONS_INTERVALS THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM; OPEN_INTERIOR] THEN
+    REPEAT(CONJ_TAC THENL
+     [ASM_MESON_TAC[tagged_partial_division_of; FINITE_IMAGE]; ALL_TAC]) THEN
+    REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+    DISCH_THEN(MATCH_MP_TAC o el 2 o CONJUNCTS) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+    REWRITE_TAC[NOT_IN_EMPTY; GSYM NOT_EXISTS_THM] THEN
+    ASM_REWRITE_TAC[EXISTS_PAIR_THM; IN_IMAGE; IN_INTER; IN_UNION] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `vsum (p UNION UNIONS {q i | i IN r}) (\(x,k). content k % f x) =
+    vsum p (\(x:real^M,k:real^M->bool). content k % f x:real^N) +
+    vsum (UNIONS {q i | (i:real^M->bool) IN r}) (\(x,k). content k % f x)`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC VSUM_UNION_NONZERO THEN ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+    ASM_SIMP_TAC[FINITE_UNIONS; FINITE_IMAGE; FORALL_IN_IMAGE] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF_FINITE]; ALL_TAC] THEN
+    REWRITE_TAC[IN_INTER] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+    REWRITE_TAC[IMP_CONJ; FORALL_IN_UNIONS; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[FORALL_PAIR_THM; FORALL_IN_IMAGE; RIGHT_FORALL_IMP_THM] THEN
+    X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `l:real^M->bool`] THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN `(l:real^M->bool) SUBSET k` ASSUME_TAC THENL
+     [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+    DISCH_THEN(MP_TAC o SPECL [`k:real^M->bool`; `l:real^M->bool`] o
+               el 2 o CONJUNCTS) THEN
+    ANTS_TAC THENL
+     [ASM_REWRITE_TAC[IN_UNION; IN_IMAGE; EXISTS_PAIR_THM] THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+      DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+      REWRITE_TAC[NOT_IN_EMPTY; GSYM NOT_EXISTS_THM] THEN
+      ASM_REWRITE_TAC[EXISTS_PAIR_THM; IN_IMAGE; IN_INTER; IN_UNION] THEN
+      ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[SUBSET_INTERIOR; SET_RULE `s SUBSET t ==> t INTER s = s`] THEN
+    SUBGOAL_THEN `?u v:real^M. l = interval[u,v]`
+     (fun th -> REPEAT_TCL CHOOSE_THEN SUBST1_TAC th THEN
+                SIMP_TAC[VECTOR_MUL_LZERO; GSYM CONTENT_EQ_0_INTERIOR]) THEN
+    ASM_MESON_TAC[tagged_partial_division_of];
+    ALL_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) VSUM_UNIONS_NONZERO o
+    rand o lhand o rand o lhand o lhand o snd) THEN
+  ANTS_TAC THENL
+   [ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN ASM_SIMP_TAC[FINITE_IMAGE] THEN
+    REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; RIGHT_FORALL_IMP_THM] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF; IN_UNION]; ALL_TAC] THEN
+    X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN
+    X_GEN_TAC `l:real^M->bool` THEN DISCH_TAC THEN
+    DISCH_TAC THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `m:real^M->bool`] THEN
+    DISCH_TAC THEN DISCH_TAC THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISJ1_TAC THEN
+    SUBGOAL_THEN `?u v:real^M. m = interval[u,v]`
+     (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+    THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF; IN_UNION]; ALL_TAC] THEN
+    REWRITE_TAC[CONTENT_EQ_0_INTERIOR] THEN
+    MATCH_MP_TAC(SET_RULE `!t. s SUBSET t /\ t = {} ==> s = {}`) THEN
+    EXISTS_TAC `interior(k INTER l:real^M->bool)` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC SUBSET_INTERIOR THEN REWRITE_TAC[SUBSET_INTER] THEN
+      ASM_MESON_TAC[TAGGED_DIVISION_OF];
+      ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+    REWRITE_TAC[INTERIOR_INTER] THEN
+    DISCH_THEN(MATCH_MP_TAC o SPECL [`k:real^M->bool`; `l:real^M->bool`] o
+               el 2 o CONJUNCTS) THEN
+    REWRITE_TAC[IN_IMAGE; EXISTS_PAIR_THM; IN_UNION] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN SUBST1_TAC THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) VSUM_IMAGE_NONZERO o
+    rand o lhand o rand o lhand o lhand o snd) THEN
+  ASM_REWRITE_TAC[o_DEF] THEN ANTS_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`k:real^M->bool`; `l:real^M->bool`] THEN
+    STRIP_TAC THEN MATCH_MP_TAC VSUM_EQ_0 THEN
+    REWRITE_TAC[FORALL_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `m:real^M->bool`] THEN DISCH_TAC THEN
+    MP_TAC(ASSUME `!i:real^M->bool. i IN r ==> q i tagged_division_of i`) THEN
+    DISCH_THEN(fun th -> MP_TAC(SPEC `l:real^M->bool` th) THEN
+                         ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+                         MP_TAC(SPEC `k:real^M->bool` th) THEN
+                         ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC]) THEN
+    ASM_REWRITE_TAC[tagged_division_of] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  SUBGOAL_THEN
+   `vsum p (\(x,k). content k % (f:real^M->real^N) x - integral k f) =
+    vsum p (\(x,k). content k % f x) - vsum p (\(x,k). integral k f)`
+  SUBST1_TAC THENL [ASM_SIMP_TAC[GSYM VSUM_SUB; LAMBDA_PAIR_THM]; ALL_TAC] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `!ir. ip + ir = i /\
+         norm(cr - ir) < k
+         ==> norm((cp + cr) - i) < e ==> norm(cp - ip) <= e + k`) THEN
+  EXISTS_TAC `vsum r (\k. integral k (f:real^M->real^N))` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `vsum (IMAGE SND (p:(real^M#(real^M->bool))->bool) UNION r)
+                     (\k. integral k (f:real^M->real^N))` THEN
+    CONJ_TAC THENL
+     [ALL_TAC; ASM_MESON_TAC[INTEGRAL_COMBINE_DIVISION_TOPDOWN]] THEN
+    MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `vsum (IMAGE SND (p:(real^M#(real^M->bool))->bool))
+                     (\k. integral k (f:real^M->real^N)) +
+                vsum r (\k. integral k f)` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_UNION_NONZERO THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; NOT_IN_EMPTY]] THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN
+    SUBGOAL_THEN `(\(x:real^M,k). integral k (f:real^M->real^N)) =
+                  (\k. integral k f) o SND`
+    SUBST1_TAC THENL
+     [SIMP_TAC[o_THM; FUN_EQ_THM; FORALL_PAIR_THM]; ALL_TAC] THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_IMAGE_NONZERO THEN
+    ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC
+     [`x:real^M`; `l:real^M->bool`; `y:real^M`; `m:real^M->bool`] THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+    FIRST_X_ASSUM(MP_TAC o
+      GEN_REWRITE_RULE I [tagged_partial_division_of]) THEN
+    DISCH_THEN(CONJUNCTS_THEN MP_TAC o CONJUNCT2) THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`x:real^M`; `l:real^M->bool`; `y:real^M`; `l:real^M->bool`]) THEN
+    ASM_REWRITE_TAC[INTER_IDEMPOT] THEN DISCH_TAC THEN
+    DISCH_THEN(MP_TAC o SPECL [`x:real^M`; `l:real^M->bool`]) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC o last o CONJUNCTS) THEN
+    MATCH_MP_TAC INTEGRAL_UNIQUE THEN MATCH_MP_TAC HAS_INTEGRAL_NULL THEN
+    ASM_REWRITE_TAC[CONTENT_EQ_0_INTERIOR];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM VSUM_SUB] THEN MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `sum (r:(real^M->bool)->bool) (\x. k / (&(CARD r) + &1))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC VSUM_NORM_LE THEN ASM_SIMP_TAC[REAL_LT_IMP_LE];
+    ASM_SIMP_TAC[SUM_CONST] THEN
+    REWRITE_TAC[real_div; REAL_MUL_ASSOC] THEN
+    SIMP_TAC[GSYM real_div; REAL_LT_LDIV_EQ; REAL_ARITH `&0 < &x + &1`] THEN
+    REWRITE_TAC[REAL_ARITH `a * k < k * b <=> &0 < k * (b - a)`] THEN
+    MATCH_MP_TAC REAL_LT_MUL THEN ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC]);;
+
+let HENSTOCK_LEMMA_PART2 = prove
+ (`!f:real^M->real^N a b d e.
+        f integrable_on interval[a,b] /\
+        &0 < e /\ gauge d /\
+        (!p. p tagged_division_of interval[a,b] /\ d fine p
+             ==> norm (vsum p (\(x,k). content k % f x) -
+                       integral(interval[a,b]) f) < e)
+        ==> !p. p tagged_partial_division_of interval[a,b] /\ d fine p
+                            ==> sum p (\(x,k). norm(content k % f x -
+                                                    integral k f))
+                                <= &2 * &(dimindex(:N)) * e`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[LAMBDA_PAIR] THEN
+  MATCH_MP_TAC VSUM_NORM_ALLSUBSETS_BOUND THEN
+  REWRITE_TAC[LAMBDA_PAIR_THM] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[tagged_partial_division_of]; ALL_TAC] THEN
+  X_GEN_TAC `q:(real^M#(real^M->bool))->bool` THEN DISCH_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+    HENSTOCK_LEMMA_PART1) THEN
+  MAP_EVERY EXISTS_TAC
+   [`a:real^M`; `b:real^M`; `d:real^M->real^M->bool`] THEN
+  ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[FINE_SUBSET; TAGGED_PARTIAL_DIVISION_SUBSET]);;
+
+let HENSTOCK_LEMMA = prove
+ (`!f:real^M->real^N a b.
+        f integrable_on interval[a,b]
+        ==> !e. &0 < e
+                ==> ?d. gauge d /\
+                        !p. p tagged_partial_division_of interval[a,b] /\
+                            d fine p
+                            ==> sum p (\(x,k). norm(content k % f x -
+                                                    integral k f)) < e`,
+  MP_TAC HENSTOCK_LEMMA_PART2 THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN X_GEN_TAC `e:real` THEN
+                       STRIP_TAC THEN MP_TAC th) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP INTEGRABLE_INTEGRAL) THEN
+  GEN_REWRITE_TAC LAND_CONV [has_integral] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / (&2 * (&(dimindex(:N)) + &1))`) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < &2 * (&n + &1)`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(MP_TAC o SPECL
+   [`d:real^M->real^M->bool`; `e / (&2 * (&(dimindex(:N)) + &1))`]) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < &2 * (&n + &1)`] THEN
+  DISCH_THEN(fun th -> EXISTS_TAC `d:real^M->real^M->bool` THEN MP_TAC th) 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(REAL_ARITH `d < e ==> x <= d ==> x < e`) THEN
+  REWRITE_TAC[real_div; REAL_INV_MUL; REAL_INV_INV; REAL_MUL_ASSOC] THEN
+  SIMP_TAC[GSYM real_div; REAL_LT_LDIV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+  UNDISCH_TAC `&0 < e` THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Monotone convergence (bounded interval first).                            *)
+(* ------------------------------------------------------------------------- *)
+
+let MONOTONE_CONVERGENCE_INTERVAL = prove
+ (`!f:num->real^N->real^1 g a b.
+        (!k. (f k) integrable_on interval[a,b]) /\
+        (!k x. x IN interval[a,b] ==> drop(f k x) <= drop(f (SUC k) x)) /\
+        (!x. x IN interval[a,b] ==> ((\k. f k x) --> g x) sequentially) /\
+        bounded {integral (interval[a,b]) (f k) | k IN (:num)}
+        ==> g integrable_on interval[a,b] /\
+            ((\k. integral (interval[a,b]) (f k))
+             --> integral (interval[a,b]) g) sequentially`,
+  let lemma = prove
+   (`{(x,y) | P x y} = {p | P (FST p) (SND p)}`,
+    REWRITE_TAC[EXTENSION; FORALL_PAIR_THM; IN_ELIM_PAIR_THM; IN_ELIM_THM]) in
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  ASM_CASES_TAC `content(interval[a:real^N,b]) = &0` THENL
+   [ASM_SIMP_TAC[INTEGRAL_NULL; INTEGRABLE_ON_NULL; LIM_CONST];
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM CONTENT_LT_NZ])] THEN
+  SUBGOAL_THEN
+   `!x:real^N k:num. x IN interval[a,b] ==> drop(f k x) <= drop(g x)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC(ISPEC `sequentially` LIM_DROP_LBOUND) THEN
+    EXISTS_TAC `\k. (f:num->real^N->real^1) k x` THEN
+    ASM_SIMP_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; EVENTUALLY_SEQUENTIALLY] THEN
+    EXISTS_TAC `k:num` THEN SPEC_TAC(`k:num`,`k:num`) THEN
+    MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN REWRITE_TAC[REAL_LE_TRANS] THEN
+    ASM_SIMP_TAC[REAL_LE_REFL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?i. ((\k. integral (interval[a,b]) (f k:real^N->real^1)) --> i)
+        sequentially`
+  CHOOSE_TAC THENL
+   [MATCH_MP_TAC BOUNDED_INCREASING_CONVERGENT THEN ASM_REWRITE_TAC[] THEN
+    GEN_TAC THEN MATCH_MP_TAC INTEGRAL_DROP_LE THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!k. drop(integral(interval[a,b]) ((f:num->real^N->real^1) k)) <= drop i`
+  ASSUME_TAC THENL
+    [GEN_TAC THEN MATCH_MP_TAC(ISPEC `sequentially` LIM_DROP_LBOUND) THEN
+     EXISTS_TAC `\k. integral(interval[a,b]) ((f:num->real^N->real^1) k)` THEN
+     ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; EVENTUALLY_SEQUENTIALLY] THEN
+     EXISTS_TAC `k:num` THEN SPEC_TAC(`k:num`,`k:num`) THEN
+     MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN
+     ASM_REWRITE_TAC[REAL_LE_REFL; REAL_LE_TRANS] THEN
+     GEN_TAC THEN MATCH_MP_TAC INTEGRAL_DROP_LE THEN ASM_REWRITE_TAC[];
+     ALL_TAC] THEN
+  SUBGOAL_THEN
+   `((g:real^N->real^1) has_integral i) (interval[a,b])`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[has_integral] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE BINDER_CONV
+     [HAS_INTEGRAL_INTEGRAL]) THEN
+    REWRITE_TAC[has_integral] THEN
+    DISCH_THEN(MP_TAC o GEN `k:num` o
+      SPECL [`k:num`; `e / &2 pow (k + 2)`]) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+    GEN_REWRITE_TAC LAND_CONV [SKOLEM_THM] THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM; FORALL_AND_THM] THEN
+    X_GEN_TAC `b:num->real^N->real^N->bool` THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `?r. !k. r:num <= k
+               ==> &0 <= drop i - drop(integral(interval[a:real^N,b]) (f k)) /\
+                   drop i - drop(integral(interval[a,b]) (f k)) < e / &4`
+    STRIP_ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIM_SEQUENTIALLY]) THEN
+      DISCH_THEN(MP_TAC o SPEC `e / &4`) THEN
+      ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+      MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+      MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[ABS_DROP; dist; DROP_SUB] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `x <= y ==> abs(x - y) < e ==> &0 <= y - x /\ y - x < e`) THEN
+      ASM_REWRITE_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!x. x IN interval[a:real^N,b]
+          ==> ?n. r:num <= n /\
+                  !k. n <= k ==> &0 <= drop(g x) - drop(f k x) /\
+                                 drop(g x) - drop(f k x) <
+                                   e / (&4 * content(interval[a,b]))`
+    MP_TAC THENL
+     [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE (BINDER_CONV o RAND_CONV)
+        [LIM_SEQUENTIALLY]) THEN
+      DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_SIMP_TAC[REAL_SUB_LE] THEN
+      DISCH_THEN(MP_TAC o SPEC `e / (&4 * content(interval[a:real^N,b]))`) THEN
+      ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_MUL; REAL_OF_NUM_LT; ARITH] THEN
+      REWRITE_TAC[dist; ABS_DROP; DROP_SUB] THEN
+      ASM_SIMP_TAC[REAL_ARITH `f <= g ==> abs(f - g) = g - f`] THEN
+      DISCH_THEN(X_CHOOSE_TAC `N:num`) THEN
+      EXISTS_TAC `N + r:num` THEN CONJ_TAC THENL [ARITH_TAC; ALL_TAC] THEN
+      ASM_MESON_TAC[ARITH_RULE `N + r:num <= k ==> N <= k`];
+      ALL_TAC] THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[SKOLEM_THM] THEN
+    REWRITE_TAC[FORALL_AND_THM; TAUT
+     `a ==> b /\ c <=> (a ==> b) /\ (a ==> c)`] THEN
+    REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP] THEN
+    DISCH_THEN(X_CHOOSE_THEN `m:real^N->num` STRIP_ASSUME_TAC) THEN
+    ABBREV_TAC `d:real^N->real^N->bool = \x. b(m x:num) x` THEN
+    EXISTS_TAC `d:real^N->real^N->bool` THEN CONJ_TAC THENL
+     [EXPAND_TAC "d" THEN REWRITE_TAC[gauge] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE BINDER_CONV [gauge]) THEN
+      SIMP_TAC[];
+      ALL_TAC] THEN
+    X_GEN_TAC `p:(real^N#(real^N->bool))->bool` THEN STRIP_TAC THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `!b c. norm(a - b) <= e / &4 /\
+            norm(b - c) < e / &2 /\
+            norm(c - d) < e / &4
+            ==> norm(a - d) < e`) THEN
+    EXISTS_TAC `vsum p (\(x:real^N,k:real^N->bool).
+                  content k % (f:num->real^N->real^1) (m x) x)` THEN
+    EXISTS_TAC `vsum p (\(x:real^N,k:real^N->bool).
+                  integral k ((f:num->real^N->real^1) (m x)))` THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+    SUBGOAL_THEN `?s:num. !t:real^N#(real^N->bool). t IN p ==> m(FST t) <= s`
+    MP_TAC THENL [ASM_SIMP_TAC[UPPER_BOUND_FINITE_SET]; ALL_TAC] THEN
+    REWRITE_TAC[FORALL_PAIR_THM] THEN DISCH_THEN(X_CHOOSE_TAC `s:num`) THEN
+    REPEAT CONJ_TAC THENL
+     [ASM_SIMP_TAC[GSYM VSUM_SUB] THEN REWRITE_TAC[LAMBDA_PAIR_THM] THEN
+      REWRITE_TAC[GSYM VECTOR_SUB_LDISTRIB] THEN
+      W(MP_TAC o PART_MATCH (lhand o rand) VSUM_NORM o lhand o snd) THEN
+      ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(REAL_ARITH `y <= e ==> x <= y ==> x <= e`) THEN
+      REWRITE_TAC[LAMBDA_PAIR_THM] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC
+       `sum p (\(x:real^N,k:real^N->bool).
+                 content k * e / (&4 * content (interval[a:real^N,b])))` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+        MAP_EVERY X_GEN_TAC [`x:real^N`; `k:real^N->bool`] THEN
+        DISCH_TAC THEN REWRITE_TAC[NORM_MUL; GSYM VECTOR_SUB_LDISTRIB] THEN
+        MATCH_MP_TAC REAL_LE_MUL2 THEN
+        REWRITE_TAC[REAL_ABS_POS; NORM_POS_LE] THEN
+        REWRITE_TAC[ABS_DROP; DROP_SUB] THEN
+        REWRITE_TAC[REAL_ARITH `abs(x) <= x <=> &0 <= x`] THEN CONJ_TAC THENL
+         [ASM_MESON_TAC[CONTENT_POS_LE; TAGGED_DIVISION_OF]; ALL_TAC] THEN
+        MATCH_MP_TAC(REAL_ARITH
+         `&0 <= g - f /\ g - f < e ==> abs(g - f) <= e`) THEN
+        CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+        REWRITE_TAC[LE_REFL] THEN ASM_MESON_TAC[TAGGED_DIVISION_OF; SUBSET];
+        ALL_TAC] THEN
+      REWRITE_TAC[LAMBDA_PAIR; SUM_RMUL] THEN REWRITE_TAC[LAMBDA_PAIR_THM] THEN
+      FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP
+       ADDITIVE_CONTENT_TAGGED_DIVISION th]) THEN
+      MATCH_MP_TAC REAL_EQ_IMP_LE THEN
+      UNDISCH_TAC `&0 < content(interval[a:real^N,b])` THEN
+      CONV_TAC REAL_FIELD;
+      ASM_SIMP_TAC[GSYM VSUM_SUB] THEN REWRITE_TAC[LAMBDA_PAIR_THM] THEN
+      MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC
+        `norm(vsum (0..s)
+               (\j. vsum {(x:real^N,k:real^N->bool) | (x,k) IN p /\ m(x) = j}
+                         (\(x,k). content k % f (m x) x :real^1 -
+                                  integral k (f (m x)))))` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC REAL_EQ_IMP_LE THEN REWRITE_TAC[lemma] THEN
+        AP_TERM_TAC THEN MATCH_MP_TAC(GSYM VSUM_GROUP) THEN
+        ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_NUMSEG; LE_0] THEN
+        ASM_REWRITE_TAC[FORALL_PAIR_THM];
+        ALL_TAC] THEN
+      MATCH_MP_TAC REAL_LET_TRANS THEN
+      EXISTS_TAC `sum (0..s) (\i. e / &2 pow (i + 2))` THEN CONJ_TAC THENL
+       [ALL_TAC;
+        REWRITE_TAC[real_div; GSYM REAL_POW_INV; SUM_LMUL] THEN
+        REWRITE_TAC[REAL_POW_ADD; SUM_RMUL] THEN REWRITE_TAC[SUM_GP] THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV THEN
+        ASM_SIMP_TAC[REAL_LT_LMUL_EQ; CONJUNCT1 LT] THEN
+        REWRITE_TAC[real_div; GSYM REAL_MUL_ASSOC] THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV THEN
+        MATCH_MP_TAC(REAL_ARITH `&0 < x * y ==> (&1 - x) * y < y`) THEN
+        MATCH_MP_TAC REAL_LT_MUL THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+        MATCH_MP_TAC REAL_POW_LT THEN CONV_TAC REAL_RAT_REDUCE_CONV] THEN
+      MATCH_MP_TAC VSUM_NORM_LE THEN REWRITE_TAC[FINITE_NUMSEG] THEN
+      X_GEN_TAC `t:num` THEN REWRITE_TAC[IN_NUMSEG; LE_0] THEN DISCH_TAC THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+       `norm(vsum {x:real^N,k:real^N->bool | x,k IN p /\ m x:num = t}
+                  (\(x,k). content k % f t x - integral k (f t)):real^1)` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC REAL_EQ_IMP_LE THEN AP_TERM_TAC THEN
+        MATCH_MP_TAC VSUM_EQ THEN SIMP_TAC[FORALL_PAIR_THM; IN_ELIM_PAIR_THM];
+        ALL_TAC] THEN
+      MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+        HENSTOCK_LEMMA_PART1) THEN
+      MAP_EVERY EXISTS_TAC
+       [`a:real^N`; `b:real^N`; `(b(t:num)):real^N->real^N->bool`] THEN
+      ASM_REWRITE_TAC[] THEN
+      ASM_SIMP_TAC[REAL_LT_DIV; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC TAGGED_PARTIAL_DIVISION_SUBSET THEN
+        EXISTS_TAC `p:(real^N#(real^N->bool))->bool` THEN
+        SIMP_TAC[SUBSET; FORALL_PAIR_THM; IN_ELIM_PAIR_THM] THEN
+        ASM_MESON_TAC[tagged_division_of];
+        ALL_TAC] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+      EXPAND_TAC "d" THEN REWRITE_TAC[fine; IN_ELIM_PAIR_THM] THEN MESON_TAC[];
+
+      MP_TAC(ISPECL [`(f:num->real^N->real^1) s`; `a:real^N`; `b:real^N`;
+                     `p:(real^N#(real^N->bool))->bool`]
+                    INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN) THEN
+      MP_TAC(ISPECL [`(f:num->real^N->real^1) r`; `a:real^N`; `b:real^N`;
+                     `p:(real^N#(real^N->bool))->bool`]
+                    INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN) THEN
+      ASM_SIMP_TAC[ABS_DROP; DROP_SUB; DROP_VSUM; GSYM DROP_EQ] THEN
+      REWRITE_TAC[o_DEF; LAMBDA_PAIR_THM] THEN MATCH_MP_TAC(REAL_ARITH
+       `sr <= sx /\ sx <= ss /\ ks <= i /\ &0 <= i - kr /\ i - kr < e
+        ==> kr = sr ==> ks = ss ==> abs(sx - i) < e`) THEN
+      ASM_SIMP_TAC[LE_REFL] THEN CONJ_TAC THEN MATCH_MP_TAC SUM_LE THEN
+      ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^N`; `i:real^N->bool`] THEN DISCH_TAC THEN
+      (SUBGOAL_THEN `i SUBSET interval[a:real^N,b]` ASSUME_TAC THENL
+        [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+       SUBGOAL_THEN `?u v:real^N. i = interval[u,v]`
+        (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+       THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC]) THEN
+      MATCH_MP_TAC INTEGRAL_DROP_LE THEN
+      REPEAT(CONJ_TAC THENL
+       [ASM_MESON_TAC[INTEGRABLE_SUBINTERVAL]; ALL_TAC]) THEN
+      X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+      MP_TAC(ISPEC
+        `\m n:num. drop (f m (y:real^N)) <= drop (f n y)`
+        TRANSITIVE_STEPWISE_LE) THEN
+      REWRITE_TAC[REAL_LE_TRANS; REAL_LE_REFL] THEN
+      (ANTS_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC]) THEN
+      DISCH_THEN MATCH_MP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_MESON_TAC[TAGGED_DIVISION_OF; SUBSET]];
+    ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[integrable_on]; ALL_TAC] THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP INTEGRAL_UNIQUE) THEN
+  ASM_REWRITE_TAC[]);;
+
+let MONOTONE_CONVERGENCE_INCREASING = prove
+ (`!f:num->real^N->real^1 g s.
+        (!k. (f k) integrable_on s) /\
+        (!k x. x IN s ==> drop(f k x) <= drop(f (SUC k) x)) /\
+        (!x. x IN s ==> ((\k. f k x) --> g x) sequentially) /\
+        bounded {integral s (f k) | k IN (:num)}
+        ==> g integrable_on s /\
+            ((\k. integral s (f k)) --> integral s g) sequentially`,
+  SUBGOAL_THEN
+   `!f:num->real^N->real^1 g s.
+        (!k x. x IN s ==> &0 <= drop(f k x)) /\
+        (!k. (f k) integrable_on s) /\
+        (!k x. x IN s ==> drop(f k x) <= drop(f (SUC k) x)) /\
+        (!x. x IN s ==> ((\k. f k x) --> g x) sequentially) /\
+        bounded {integral s (f k) | k IN (:num)}
+        ==> g integrable_on s /\
+            ((\k. integral s (f k)) --> integral s g) sequentially`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REPEAT GEN_TAC THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o ISPECL
+     [`\n x:real^N. f(SUC n) x - f 0 x:real^1`;
+      `\x. (g:real^N->real^1) x - f 0 x`; `s:real^N->bool`]) THEN
+    REWRITE_TAC[] THEN ANTS_TAC THEN REPEAT CONJ_TAC THENL
+     [REPEAT STRIP_TAC THEN REWRITE_TAC[DROP_SUB; REAL_SUB_LE] THEN
+      MP_TAC(ISPEC
+        `\m n:num. drop (f m (x:real^N)) <= drop (f n x)`
+        TRANSITIVE_STEPWISE_LE) THEN
+      REWRITE_TAC[REAL_LE_TRANS; REAL_LE_REFL] THEN ASM_MESON_TAC[LE_0];
+      GEN_TAC THEN MATCH_MP_TAC INTEGRABLE_SUB THEN ASM_REWRITE_TAC[ETA_AX];
+      REPEAT STRIP_TAC THEN REWRITE_TAC[DROP_SUB; REAL_SUB_LE] THEN
+      ASM_SIMP_TAC[REAL_ARITH `x - a <= y - a <=> x <= y`];
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC LIM_SUB THEN SIMP_TAC[LIM_CONST] THEN
+      REWRITE_TAC[ADD1] THEN
+      MATCH_MP_TAC(ISPECL[`f:num->real^1`; `l:real^1`; `1`] SEQ_OFFSET) THEN
+      ASM_SIMP_TAC[];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [bounded]) THEN
+      ASM_SIMP_TAC[INTEGRAL_SUB; ETA_AX; bounded] THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; IN_UNIV] THEN
+      DISCH_THEN(X_CHOOSE_THEN `B:real`
+        (fun th -> EXISTS_TAC `B + norm(integral s (f 0:real^N->real^1))` THEN
+                   X_GEN_TAC `k:num` THEN MP_TAC(SPEC `SUC k` th))) THEN
+      NORM_ARITH_TAC;
+      ASM_SIMP_TAC[INTEGRAL_SUB; ETA_AX; IMP_CONJ] THEN
+      SUBGOAL_THEN `(f 0:real^N->real^1) integrable_on s` MP_TAC THENL
+       [ASM_REWRITE_TAC[]; ONCE_REWRITE_TAC[IMP_IMP]] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP INTEGRABLE_ADD) THEN
+      REWRITE_TAC[ETA_AX; VECTOR_ARITH `f + (g - f):real^N = g`] THEN
+      DISCH_TAC THEN ASM_SIMP_TAC[INTEGRAL_SUB; ETA_AX] THEN
+      MP_TAC(ISPECL [`sequentially`; `integral s (f 0:real^N->real^1)`]
+                    LIM_CONST) THEN
+      REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP LIM_ADD) THEN
+      REWRITE_TAC[ETA_AX; VECTOR_ARITH `f + (g - f):real^N = g`] THEN
+      REWRITE_TAC[ADD1] THEN
+      SIMP_TAC[ISPECL[`f:num->real^1`; `l:real^1`; `1`] SEQ_OFFSET_REV]]] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x:real^N k:num. x IN s ==> drop(f k x) <= drop(g x)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC(ISPEC `sequentially` LIM_DROP_LBOUND) THEN
+    EXISTS_TAC `\k. (f:num->real^N->real^1) k x` THEN
+    ASM_SIMP_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; EVENTUALLY_SEQUENTIALLY] THEN
+    EXISTS_TAC `k:num` THEN SPEC_TAC(`k:num`,`k:num`) THEN
+    MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN REWRITE_TAC[REAL_LE_TRANS] THEN
+    ASM_SIMP_TAC[REAL_LE_REFL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?i. ((\k. integral s (f k:real^N->real^1)) --> i)
+        sequentially`
+  CHOOSE_TAC THENL
+   [MATCH_MP_TAC BOUNDED_INCREASING_CONVERGENT THEN ASM_REWRITE_TAC[] THEN
+    GEN_TAC THEN MATCH_MP_TAC INTEGRAL_DROP_LE THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!k. drop(integral s ((f:num->real^N->real^1) k)) <= drop i`
+  ASSUME_TAC THENL
+    [GEN_TAC THEN MATCH_MP_TAC(ISPEC `sequentially` LIM_DROP_LBOUND) THEN
+     EXISTS_TAC `\k. integral(s) ((f:num->real^N->real^1) k)` THEN
+     ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; EVENTUALLY_SEQUENTIALLY] THEN
+     EXISTS_TAC `k:num` THEN SPEC_TAC(`k:num`,`k:num`) THEN
+     MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN
+     ASM_REWRITE_TAC[REAL_LE_REFL; REAL_LE_TRANS] THEN
+     GEN_TAC THEN MATCH_MP_TAC INTEGRAL_DROP_LE THEN ASM_REWRITE_TAC[];
+     ALL_TAC] THEN
+  SUBGOAL_THEN `((g:real^N->real^1) has_integral i) s` ASSUME_TAC THENL
+   [ALL_TAC;
+    CONJ_TAC THENL [ASM_MESON_TAC[integrable_on]; ALL_TAC] THEN
+    FIRST_ASSUM(SUBST1_TAC o MATCH_MP INTEGRAL_UNIQUE) THEN
+    ASM_REWRITE_TAC[]] THEN
+  REWRITE_TAC[HAS_INTEGRAL_ALT] THEN
+  MP_TAC(ISPECL
+   [`\k x. if x IN s then (f:num->real^N->real^1) k x else vec 0`;
+    `\x. if x IN s then (g:real^N->real^1) x else vec 0`]
+   (MATCH_MP(MESON[] `(!a b c d. P a b c d ==> Q a b c d)
+                      ==> !a b. (!c d. P a b c d) ==> (!c d. Q a b c d)`)
+            MONOTONE_CONVERGENCE_INTERVAL)) THEN
+  ANTS_TAC THENL
+   [REPEAT GEN_TAC THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+     [FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE BINDER_CONV [INTEGRABLE_ALT]) THEN
+      SIMP_TAC[];
+      DISCH_TAC] THEN
+    CONJ_TAC THENL
+     [REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[REAL_LE_REFL];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[LIM_CONST];
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [bounded]) THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+    REWRITE_TAC[bounded; FORALL_IN_IMAGE; IN_UNIV] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `k:num` THEN
+    REWRITE_TAC[ABS_DROP] THEN MATCH_MP_TAC(REAL_ARITH
+     `&0 <= y /\ y <= x ==> abs(x) <= a ==> abs(y) <= a`) THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC INTEGRAL_DROP_POS THEN ASM_REWRITE_TAC[] THEN
+      REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+      ASM_SIMP_TAC[REAL_LE_REFL; DROP_VEC];
+      ALL_TAC] THEN
+    GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM INTEGRAL_RESTRICT_UNIV] THEN
+    MATCH_MP_TAC INTEGRAL_SUBSET_DROP_LE THEN
+    ASM_REWRITE_TAC[SUBSET_UNIV; IN_UNIV] THEN
+    ASM_REWRITE_TAC[INTEGRABLE_RESTRICT_UNIV; ETA_AX] THEN
+    GEN_TAC THEN COND_CASES_TAC THEN
+    ASM_SIMP_TAC[REAL_LE_REFL; DROP_VEC; REAL_LE_REFL];
+    ALL_TAC] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC THEN ASM_REWRITE_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 / &4`) THEN
+  ASM_SIMP_TAC[dist; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N:num` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE BINDER_CONV
+   [HAS_INTEGRAL_INTEGRAL]) THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [HAS_INTEGRAL_ALT] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(MP_TAC o SPECL [`N:num`; `e / &4`]) THEN
+  ASM_SIMP_TAC[dist; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `B:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`a:real^N`; `b:real^N`]) THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(MP_TAC o C MATCH_MP (ARITH_RULE `N:num <= N`)) THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (NORM_ARITH
+   `norm(x - y) < e / &4 /\ norm(z - x) < e / &4
+    ==> norm(z - y) < e / &2`)) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE (BINDER_CONV o BINDER_CONV)
+        [LIM_SEQUENTIALLY]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`a:real^N`; `b:real^N`; `e / &2`]) THEN
+  ASM_REWRITE_TAC[dist; REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `M:num` (MP_TAC o SPEC `M + N:num`)) THEN
+  REWRITE_TAC[LE_ADD; ABS_DROP; DROP_SUB] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `f1 <= f2 /\ f2 <= i
+    ==> abs(f2 - g) < e / &2 ==> abs(f1 - i) < e / &2 ==> abs(g - i) < e`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC INTEGRAL_DROP_LE THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_LE_REFL] THEN
+    MP_TAC(ISPEC
+        `\m n:num. drop (f m (x:real^N)) <= drop (f n x)`
+        TRANSITIVE_STEPWISE_LE) THEN
+    REWRITE_TAC[REAL_LE_REFL; REAL_LE_TRANS] THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    DISCH_THEN MATCH_MP_TAC THEN ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `drop(integral s ((f:num->real^N->real^1) (M + N)))` THEN
+  ASM_REWRITE_TAC[] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM INTEGRAL_RESTRICT_UNIV] THEN
+  MATCH_MP_TAC INTEGRAL_SUBSET_DROP_LE THEN
+  ASM_REWRITE_TAC[SUBSET_UNIV; IN_UNIV] THEN
+  ASM_REWRITE_TAC[INTEGRABLE_RESTRICT_UNIV; ETA_AX] THEN
+  GEN_TAC THEN COND_CASES_TAC THEN
+  ASM_SIMP_TAC[REAL_LE_REFL; DROP_VEC; REAL_LE_REFL]);;
+
+let MONOTONE_CONVERGENCE_DECREASING = prove
+ (`!f:num->real^N->real^1 g s.
+        (!k. (f k) integrable_on s) /\
+        (!k x. x IN s ==> drop(f (SUC k) x) <= drop(f k x)) /\
+        (!x. x IN s ==> ((\k. f k x) --> g x) sequentially) /\
+        bounded {integral s (f k) | k IN (:num)}
+        ==> g integrable_on s /\
+            ((\k. integral s (f k)) --> integral s g) sequentially`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  MP_TAC(ISPECL
+   [`(\k x. --(f k x)):num->real^N->real^1`;
+    `(\x. --(g x)):real^N->real^1`; `s:real^N->bool`]
+        MONOTONE_CONVERGENCE_INCREASING) THEN
+  FIRST_ASSUM MP_TAC THEN
+  MATCH_MP_TAC(TAUT `(a ==> b) /\ (c ==> d) ==> a ==> (b ==> c) ==> d`) THEN
+  REWRITE_TAC[] THEN CONJ_TAC THENL
+   [REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THENL
+     [MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+      DISCH_THEN(MP_TAC o MATCH_MP INTEGRABLE_NEG) THEN REWRITE_TAC[];
+      SIMP_TAC[DROP_NEG; REAL_LE_NEG2];
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC LIM_NEG THEN ASM_SIMP_TAC[];
+      ALL_TAC] THEN
+    DISCH_TAC THEN MATCH_MP_TAC BOUNDED_SUBSET THEN
+    EXISTS_TAC `IMAGE (\x. --x)
+                      {integral s (f k:real^N->real^1) | k IN (:num)}` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC BOUNDED_LINEAR_IMAGE THEN
+      ASM_SIMP_TAC[LINEAR_COMPOSE_NEG; LINEAR_ID];
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN REWRITE_TAC[GSYM IMAGE_o] THEN
+      REWRITE_TAC[SUBSET; IN_IMAGE] THEN
+      GEN_TAC THEN MATCH_MP_TAC MONO_EXISTS THEN
+      REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[o_THM] THEN
+      MATCH_MP_TAC INTEGRAL_NEG THEN ASM_REWRITE_TAC[]];
+    ALL_TAC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (MP_TAC o MATCH_MP INTEGRABLE_NEG) (MP_TAC o MATCH_MP LIM_NEG)) THEN
+  REWRITE_TAC[VECTOR_NEG_NEG; ETA_AX] THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN
+  BINOP_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN TRY GEN_TAC THEN
+  MATCH_MP_TAC(VECTOR_ARITH `x:real^N = --y ==> --x = y`) THEN
+  MATCH_MP_TAC INTEGRAL_NEG THEN ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More lemmas about existence and bounds between integrals.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let INTEGRAL_NORM_BOUND_INTEGRAL = prove
+ (`!f:real^M->real^N g s.
+        f integrable_on s /\ g integrable_on s /\
+        (!x. x IN s ==> norm(f x) <= drop(g x))
+        ==> norm(integral s f) <= drop(integral s g)`,
+  let lemma = prove
+   (`(!e. &0 < e ==> x < y + e) ==> x <= y`,
+    DISCH_THEN(MP_TAC o SPEC `x - y:real`) THEN REAL_ARITH_TAC) in
+  SUBGOAL_THEN
+   `!f:real^M->real^N g a b.
+        f integrable_on interval[a,b] /\ g integrable_on interval[a,b] /\
+        (!x. x IN interval[a,b] ==> norm(f x) <= drop(g x))
+        ==> norm(integral(interval[a,b]) f) <= drop(integral(interval[a,b]) g)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC lemma THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    UNDISCH_TAC `(f:real^M->real^N) integrable_on interval[a,b]` THEN
+    DISCH_THEN(MP_TAC o MATCH_MP INTEGRABLE_INTEGRAL) THEN
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP INTEGRABLE_INTEGRAL) THEN
+    REWRITE_TAC[has_integral] THEN DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
+    ASM_REWRITE_TAC[REAL_HALF; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `d1:real^M->real^M->bool` THEN STRIP_TAC THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
+    ASM_REWRITE_TAC[REAL_HALF; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `d2:real^M->real^M->bool` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    MP_TAC(ISPECL [`d1:real^M->real^M->bool`; `d2:real^M->real^M->bool`]
+                  GAUGE_INTER) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP FINE_DIVISION_EXISTS) THEN
+    DISCH_THEN(MP_TAC o SPECL [`a:real^M`; `b:real^M`]) THEN
+    REWRITE_TAC[FINE_INTER; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `p:(real^M#(real^M->bool))->bool` THEN STRIP_TAC THEN
+    DISCH_THEN(MP_TAC o SPEC `p:(real^M#(real^M->bool))->bool`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `p:(real^M#(real^M->bool))->bool`) THEN
+    ASM_REWRITE_TAC[ABS_DROP; DROP_SUB] THEN MATCH_MP_TAC(NORM_ARITH
+     `norm(sg) <= dsa
+      ==> abs(dsa - dia) < e / &2 ==> norm(sg - ig) < e / &2
+          ==> norm(ig) < dia + e`) THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+    ASM_SIMP_TAC[DROP_VSUM] THEN MATCH_MP_TAC VSUM_NORM_LE THEN
+    ASM_REWRITE_TAC[o_DEF; FORALL_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+    REWRITE_TAC[NORM_MUL; DROP_CMUL] THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN REWRITE_TAC[REAL_ABS_POS; NORM_POS_LE] THEN
+    REWRITE_TAC[REAL_ARITH `abs x <= x <=> &0 <= x`] THEN
+    ASM_MESON_TAC[CONTENT_POS_LE; TAGGED_DIVISION_OF; SUBSET];
+    ALL_TAC] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN (fun th ->
+     ASSUME_TAC(CONJUNCT1(GEN_REWRITE_RULE I [INTEGRABLE_ALT] th)) THEN
+     MP_TAC(MATCH_MP INTEGRABLE_INTEGRAL th))) THEN
+  ONCE_REWRITE_TAC[HAS_INTEGRAL] THEN
+  DISCH_THEN(LABEL_TAC "A") THEN DISCH_TAC THEN MATCH_MP_TAC lemma THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  REMOVE_THEN "A" (MP_TAC o SPEC `e / &2`) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B1:real`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "F"))) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B2:real`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "A"))) THEN
+  MP_TAC(ISPEC `ball(vec 0,max B1 B2):real^M->bool`
+    BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+  REWRITE_TAC[BOUNDED_BALL; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[BALL_MAX_UNION; UNION_SUBSET] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN
+  DISCH_THEN(CONJUNCTS_THEN(ANTE_RES_THEN MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real^1` (CONJUNCTS_THEN2 ASSUME_TAC
+     (fun th -> DISCH_THEN(X_CHOOSE_THEN `w:real^N`
+                (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN MP_TAC th))) THEN
+  ASM_REWRITE_TAC[ABS_DROP; DROP_SUB] THEN MATCH_MP_TAC(NORM_ARITH
+     `norm(sg) <= dsa
+      ==> abs(dsa - dia) < e / &2 ==> norm(sg - ig) < e / &2
+          ==> norm(ig) < dia + e`) THEN
+  REPEAT(FIRST_X_ASSUM(SUBST1_TAC o SYM o MATCH_MP INTEGRAL_UNIQUE)) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  REPEAT STRIP_TAC THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[NORM_0; DROP_VEC; REAL_LE_REFL]);;
+
+let INTEGRAL_NORM_BOUND_INTEGRAL_COMPONENT = prove
+ (`!f:real^M->real^N g:real^M->real^P s k.
+        1 <= k /\ k <= dimindex(:P) /\
+        f integrable_on s /\ g integrable_on s /\
+        (!x. x IN s ==> norm(f x) <= (g x)$k)
+        ==> norm(integral s f) <= (integral s g)$k`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `drop(integral s ((\y. lift(y$k)) o (g:real^M->real^P)))` THEN
+  SUBGOAL_THEN `linear(\y:real^P. lift(y$k))` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[linear; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+                 LIFT_ADD; LIFT_CMUL];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+    ASM_SIMP_TAC[o_THM; LIFT_DROP] THEN MATCH_MP_TAC INTEGRABLE_LINEAR THEN
+    ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `integral s ((\y. lift (y$k)) o (g:real^M->real^P)) =
+        (\y. lift (y$k)) (integral s g)`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC INTEGRAL_LINEAR THEN ASM_REWRITE_TAC[];
+    REWRITE_TAC[LIFT_DROP; REAL_LE_REFL]]);;
+
+let HAS_INTEGRAL_NORM_BOUND_INTEGRAL_COMPONENT = prove
+ (`!f:real^M->real^N g:real^M->real^P s i j k.
+        1 <= k /\ k <= dimindex(:P) /\
+        (f has_integral i) s /\ (g has_integral j) s /\
+        (!x. x IN s ==> norm(f x) <= (g x)$k)
+        ==> norm(i) <= j$k`,
+  REPEAT STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(fun th ->
+   SUBST1_TAC(SYM(MATCH_MP INTEGRAL_UNIQUE th)) THEN
+   ASSUME_TAC(MATCH_MP HAS_INTEGRAL_INTEGRABLE th))) THEN
+  MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL_COMPONENT THEN
+  ASM_REWRITE_TAC[]);;
+
+let INTEGRABLE_ON_ALL_INTERVALS_INTEGRABLE_BOUND = prove
+ (`!f:real^M->real^N g s.
+        (!a b. (\x. if x IN s then f x else vec 0)
+               integrable_on interval[a,b]) /\
+        (!x. x IN s ==> norm(f x) <= drop(g x)) /\
+        g integrable_on s
+        ==> f integrable_on s`,
+  let lemma = prove
+   (`!f:real^M->real^N g.
+          (!a b. f integrable_on interval[a,b]) /\
+          (!x. norm(f x) <= drop(g x)) /\
+          g integrable_on (:real^M)
+          ==> f integrable_on (:real^M)`,
+    REPEAT GEN_TAC THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    ONCE_REWRITE_TAC[INTEGRABLE_ALT_SUBSET] THEN
+    ASM_REWRITE_TAC[IN_UNIV; ETA_AX] 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
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `B:real` THEN
+    MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN
+    REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+    DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH `a <= b ==> b < c ==> a < c`) THEN
+    ONCE_REWRITE_TAC[NORM_SUB] THEN
+    ASM_SIMP_TAC[GSYM INTEGRAL_DIFF; NEGLIGIBLE_EMPTY;
+                 SET_RULE `s SUBSET t ==> s DIFF t = {}`] THEN
+    REWRITE_TAC[ABS_DROP] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= y ==> x <= abs y`) THEN
+    MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+    ASM_MESON_TAC[integrable_on; HAS_INTEGRAL_DIFF; NEGLIGIBLE_EMPTY;
+                 SET_RULE `s SUBSET t ==> s DIFF t = {}`]) in
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ONCE_REWRITE_TAC[GSYM INTEGRABLE_RESTRICT_UNIV] THEN
+  DISCH_TAC THEN MATCH_MP_TAC lemma THEN
+  EXISTS_TAC `(\x. if x IN s then g x else vec 0):real^M->real^1` THEN
+  ASM_REWRITE_TAC[] THEN
+  GEN_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[NORM_0; DROP_VEC; REAL_POS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Interval functions of bounded variation on a set.                         *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("has_bounded_setvariation_on",(12,"right"));;
+
+let set_variation = new_definition
+ `set_variation s (f:(real^M->bool)->real^N) =
+        sup { sum d (\k. norm(f k)) | ?t. d division_of t /\ t SUBSET s}`;;
+
+let has_bounded_setvariation_on = new_definition
+  `(f:(real^M->bool)->real^N) has_bounded_setvariation_on s <=>
+        ?B. !d t. d division_of t /\ t SUBSET s
+                  ==> sum d (\k. norm(f k)) <= B`;;
+
+let HAS_BOUNDED_SETVARIATION_ON = prove
+ (`!f:(real^M->bool)->real^N s.
+        f  has_bounded_setvariation_on s <=>
+        ?B. &0 < B /\ !d t. d division_of t /\ t SUBSET s
+                            ==> sum d (\k. norm(f k)) <= B`,
+  REWRITE_TAC[has_bounded_setvariation_on] THEN
+  MESON_TAC[REAL_ARITH `&0 < abs B + &1 /\ (x <= B ==> x <= abs B + &1)`]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_EQ = prove
+ (`!f g:(real^M->bool)->real^N s.
+        (!a b. ~(interval[a,b] = {}) /\ interval[a,b] SUBSET s
+               ==> f(interval[a,b]) = g(interval[a,b])) /\
+        f has_bounded_setvariation_on s
+        ==> g has_bounded_setvariation_on s`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[has_bounded_setvariation_on] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `B:real` THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `d:(real^M->bool)->bool` THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `t:real^M->bool` THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REAL_ARITH `x = y ==> x <= B ==> y <= B`) THEN
+  MATCH_MP_TAC SUM_EQ THEN FIRST_ASSUM(fun th ->
+  GEN_REWRITE_TAC I [MATCH_MP FORALL_IN_DIVISION_NONEMPTY th]) THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[] THEN AP_TERM_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_MESON_TAC[division_of; SUBSET_TRANS]);;
+
+let SET_VARIATION_EQ = prove
+ (`!f g:(real^M->bool)->real^N s.
+        (!a b. ~(interval[a,b] = {}) /\ interval[a,b] SUBSET s
+               ==> f(interval[a,b]) = g(interval[a,b]))
+        ==> set_variation s f = set_variation s g`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[set_variation] THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC(SET_RULE
+   `(!x. P x ==> f x = g x) ==> {f x | P x} = {g x | P x}`) THEN
+  X_GEN_TAC `d:(real^M->bool)->bool` THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^M->bool` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC SUM_EQ THEN FIRST_ASSUM(fun th ->
+  GEN_REWRITE_TAC I [MATCH_MP FORALL_IN_DIVISION_NONEMPTY th]) THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[] THEN AP_TERM_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_MESON_TAC[division_of; SUBSET_TRANS]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_COMPONENTWISE = prove
+ (`!f:(real^M->bool)->real^N s.
+        f has_bounded_setvariation_on s <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> (\k. lift(f k$i)) has_bounded_setvariation_on s`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[has_bounded_setvariation_on; NORM_LIFT] THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN EXISTS_TAC `B:real` THEN
+    MAP_EVERY X_GEN_TAC [`d:(real^M->bool)->bool`; `t:real^M->bool`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+      [`d:(real^M->bool)->bool`; `t:real^M->bool`]) THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_LE_TRANS) THEN
+    MATCH_MP_TAC SUM_LE THEN ASM_SIMP_TAC[COMPONENT_LE_NORM] THEN
+    ASM_MESON_TAC[DIVISION_OF_FINITE];
+    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 `B:num->real` THEN DISCH_TAC THEN
+    EXISTS_TAC `sum (1..dimindex(:N)) B` THEN
+    MAP_EVERY X_GEN_TAC [`d:(real^M->bool)->bool`; `t:real^M->bool`] THEN
+    STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum d (\k. sum (1..dimindex(:N))
+                           (\i. abs(((f:(real^M->bool)->real^N) k)$i)))` THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+    ASM_SIMP_TAC[SUM_LE; NORM_LE_L1] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) SUM_SWAP o lhand o snd) THEN
+    ASM_SIMP_TAC[FINITE_NUMSEG] THEN DISCH_THEN SUBST1_TAC THEN
+    MATCH_MP_TAC SUM_LE_NUMSEG THEN ASM_MESON_TAC[]]);;
+
+let SETVARIATION_EQUAL_LEMMA = prove
+ (`!mf:((real^M->bool)->real^N)->((real^M->bool)->real^N) ms ms'.
+        (!s. ms'(ms s) = s /\ ms(ms' s) = s) /\
+        (!f a b. ~(interval[a,b] = {})
+                 ==> mf f (ms (interval[a,b])) = f (interval[a,b]) /\
+                     ?a' b'. ~(interval[a',b'] = {}) /\
+                             ms' (interval[a,b]) = interval[a',b']) /\
+        (!t u. t SUBSET u ==> ms t SUBSET ms u /\ ms' t SUBSET ms' u) /\
+        (!d t. d division_of t
+               ==> (IMAGE ms d) division_of ms t /\
+                   (IMAGE ms' d) division_of ms' t)
+   ==> (!f s. (mf f) has_bounded_setvariation_on (ms s) <=>
+              f has_bounded_setvariation_on s) /\
+       (!f s. set_variation (ms s) (mf f) = set_variation s f)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  REWRITE_TAC[has_bounded_setvariation_on; set_variation] THEN
+  MATCH_MP_TAC(MESON[]
+   `((!f s. s1 f s = s2 f s) ==> P) /\
+    (!f s. s1 f s = s2 f s)
+    ==> P /\ (!f s. sup (s1 f s) = sup (s2 f s))`) THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+    REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN MESON_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN REPEAT GEN_TAC THEN EQ_TAC THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
+   [EXISTS_TAC `IMAGE (ms':(real^M->bool)->real^M->bool) d`;
+    EXISTS_TAC `IMAGE (ms:(real^M->bool)->real^M->bool) d`] THEN
+  (CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+   W(MP_TAC o PART_MATCH (lhand o rand) SUM_IMAGE o rand o snd) THEN
+   ANTS_TAC THENL [ASM_MESON_TAC[]; DISCH_THEN SUBST1_TAC]) THEN
+  MATCH_MP_TAC SUM_EQ THEN REWRITE_TAC[o_THM] THEN FIRST_ASSUM
+   (fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION_NONEMPTY th]) THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN STRIP_TAC THEN
+  AP_TERM_TAC THEN ASM_SIMP_TAC[] THEN
+  SUBGOAL_THEN `?a' b':real^M. ~(interval[a',b'] = {}) /\
+                        ms' (interval[a:real^M,b]) = interval[a',b']`
+  STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_ELEMENTARY = prove
+ (`!f:(real^M->bool)->real^N s.
+        (?d. d division_of s)
+        ==> (f has_bounded_setvariation_on s <=>
+             ?B. !d. d division_of s ==> sum d (\k. norm(f k)) <= B)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  REWRITE_TAC[has_bounded_setvariation_on] THEN EQ_TAC THEN
+  MATCH_MP_TAC MONO_EXISTS THENL [MESON_TAC[SUBSET_REFL]; ALL_TAC] THEN
+  GEN_TAC THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`d:(real^M->bool)->bool`; `t:real^M->bool`] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(X_CHOOSE_TAC `d':(real^M->bool)->bool`) THEN
+  MP_TAC(ISPECL [`d:(real^M->bool)->bool`; `d':(real^M->bool)->bool`;
+             `t:real^M->bool`; `s:real^M->bool`] PARTIAL_DIVISION_EXTEND) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_TAC `d'':(real^M->bool)->bool`) THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum d'' (\k:real^M->bool. norm(f k:real^N))` THEN
+  ASM_SIMP_TAC[] THEN MATCH_MP_TAC SUM_SUBSET_SIMPLE THEN
+  ASM_REWRITE_TAC[NORM_POS_LE] THEN ASM_MESON_TAC[DIVISION_OF_FINITE]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_INTERVAL = prove
+ (`!f:(real^M->bool)->real^N a b.
+        f has_bounded_setvariation_on interval[a,b] <=>
+        ?B. !d. d division_of interval[a,b] ==> sum d (\k. norm(f k)) <= B`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC HAS_BOUNDED_SETVARIATION_ON_ELEMENTARY THEN
+  REWRITE_TAC[ELEMENTARY_INTERVAL]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_UNIV = prove
+ (`!f:(real^M->bool)->real^N.
+        f has_bounded_setvariation_on (:real^M) <=>
+        ?B. !d. d division_of UNIONS d ==> sum d (\k. norm(f k)) <= B`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[has_bounded_setvariation_on; SUBSET_UNIV] THEN
+  MESON_TAC[DIVISION_OF_UNION_SELF]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_SUBSET = prove
+ (`!f:(real^M->bool)->real^N s t.
+        f has_bounded_setvariation_on s /\ t SUBSET s
+        ==> f has_bounded_setvariation_on t`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[has_bounded_setvariation_on] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN ASM_MESON_TAC[SUBSET_TRANS]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_IMP_BOUNDED_ON_SUBINTERVALS = prove
+ (`!f:(real^M->bool)->real^N s.
+        f has_bounded_setvariation_on s
+        ==> bounded { f(interval[c,d]) | interval[c,d] SUBSET s}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_setvariation_on; bounded] THEN
+  DISCH_THEN(X_CHOOSE_TAC `B:real`) THEN
+  EXISTS_TAC `max (abs B) (norm((f:(real^M->bool)->real^N) {}))` THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN
+  MAP_EVERY X_GEN_TAC [`c:real^M`; `d:real^M`] THEN DISCH_TAC THEN
+  ASM_CASES_TAC `interval[c:real^M,d] = {}` THEN
+  ASM_REWRITE_TAC[REAL_ARITH `a <= max b a`] THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+   [`{interval[c:real^M,d]}`; `interval[c:real^M,d]`]) THEN
+  ASM_SIMP_TAC[DIVISION_OF_SELF; SUM_SING] THEN REAL_ARITH_TAC);;
+
+let HAS_BOUNDED_SETVARIATION_ON_NORM = prove
+ (`!f:(real^M->bool)->real^N s.
+        f has_bounded_setvariation_on s
+        ==> (\x. lift(norm(f x))) has_bounded_setvariation_on s`,
+  REWRITE_TAC[has_bounded_setvariation_on; NORM_REAL; GSYM drop] THEN
+  REWRITE_TAC[REAL_ABS_NORM; LIFT_DROP]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_COMPOSE_LINEAR = prove
+ (`!f:(real^M->bool)->real^N g:real^N->real^P s.
+        f has_bounded_setvariation_on s /\ linear g
+        ==> (g o f) has_bounded_setvariation_on s`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[HAS_BOUNDED_SETVARIATION_ON] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `B:real`) ASSUME_TAC) THEN
+  FIRST_X_ASSUM(X_CHOOSE_TAC `C:real` o MATCH_MP LINEAR_BOUNDED_POS) THEN
+  EXISTS_TAC `B * C:real` THEN ASM_SIMP_TAC[REAL_LT_MUL] THEN
+  MAP_EVERY X_GEN_TAC [`d:(real^M->bool)->bool`; `t:real^M->bool`] THEN
+  STRIP_TAC THEN REWRITE_TAC[o_THM] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum d (\k. C * norm((f:(real^M->bool)->real^N) k))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_LE THEN ASM_MESON_TAC[DIVISION_OF_FINITE];
+    GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
+    REWRITE_TAC[SUM_LMUL] THEN ASM_SIMP_TAC[REAL_LE_LMUL_EQ] THEN
+    ASM_MESON_TAC[]]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_0 = prove
+ (`!s:real^N->bool. (\x. vec 0) has_bounded_setvariation_on s`,
+  REWRITE_TAC[has_bounded_setvariation_on; NORM_0; SUM_0] THEN
+  MESON_TAC[REAL_LE_REFL]);;
+
+let SET_VARIATION_0 = prove
+ (`!s:real^N->bool. set_variation s (\x. vec 0) = &0`,
+  GEN_TAC THEN REWRITE_TAC[set_variation; NORM_0; SUM_0] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM SUP_SING] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_SING] THEN
+  MESON_TAC[ELEMENTARY_EMPTY; EMPTY_SUBSET]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_CMUL = prove
+ (`!f:(real^M->bool)->real^N c s.
+        f has_bounded_setvariation_on s
+        ==> (\x. c % f x) has_bounded_setvariation_on s`,
+  REPEAT GEN_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT; o_DEF]
+     HAS_BOUNDED_SETVARIATION_ON_COMPOSE_LINEAR) THEN
+  REWRITE_TAC[linear] THEN VECTOR_ARITH_TAC);;
+
+let HAS_BOUNDED_SETVARIATION_ON_NEG = prove
+ (`!f:(real^M->bool)->real^N s.
+        f has_bounded_setvariation_on s
+        ==> (\x. --(f x)) has_bounded_setvariation_on s`,
+  REWRITE_TAC[VECTOR_ARITH `--x:real^N = -- &1 % x`] THEN
+  REWRITE_TAC[HAS_BOUNDED_SETVARIATION_ON_CMUL]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_ADD = prove
+ (`!f:(real^M->bool)->real^N g s.
+        f has_bounded_setvariation_on s /\
+        g has_bounded_setvariation_on s
+        ==> (\x. f x + g x) has_bounded_setvariation_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_setvariation_on] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `C:real` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `B + C:real` THEN
+  MAP_EVERY X_GEN_TAC [`d:(real^M->bool)->bool`; `t:real^M->bool`] THEN
+  STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum d (\k. norm((f:(real^M->bool)->real^N) k)) +
+              sum d (\k. norm((g:(real^M->bool)->real^N) k))` THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[REAL_LE_ADD2]] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  ASM_SIMP_TAC[GSYM SUM_ADD] THEN
+  MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[NORM_TRIANGLE]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_SUB = prove
+ (`!f:(real^M->bool)->real^N g s.
+        f has_bounded_setvariation_on s /\
+        g has_bounded_setvariation_on s
+        ==> (\x. f x - g x) has_bounded_setvariation_on s`,
+  REWRITE_TAC[VECTOR_ARITH `x - y:real^N = x + --y`] THEN
+  SIMP_TAC[HAS_BOUNDED_SETVARIATION_ON_ADD; HAS_BOUNDED_SETVARIATION_ON_NEG]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_NULL = prove
+ (`!f:(real^M->bool)->real^N s.
+        (!a b. content(interval[a,b]) = &0 ==> f(interval[a,b]) = vec 0) /\
+        content s = &0 /\ bounded s
+        ==> f has_bounded_setvariation_on s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[has_bounded_setvariation_on] THEN
+  EXISTS_TAC `&0` THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH `x = &0 ==> x <= &0`) THEN
+  MATCH_MP_TAC SUM_EQ_0 THEN REWRITE_TAC[NORM_EQ_0] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  MATCH_MP_TAC CONTENT_0_SUBSET_GEN THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[division_of; SUBSET_TRANS]);;
+
+let SET_VARIATION_ELEMENTARY_LEMMA = prove
+ (`!f:(real^M->bool)->real^N s.
+        (?d. d division_of s)
+        ==> ((!d t. d division_of t /\ t SUBSET s
+                    ==> sum d (\k. norm(f k)) <= b) <=>
+             (!d. d division_of s ==> sum d (\k. norm(f k)) <= b))`,
+  REPEAT GEN_TAC THEN DISCH_THEN(X_CHOOSE_TAC `d1:(real^M->bool)->bool`) THEN
+  EQ_TAC THENL [MESON_TAC[SUBSET_REFL]; ALL_TAC] THEN
+  DISCH_TAC THEN X_GEN_TAC `d2:(real^M->bool)->bool` THEN
+  X_GEN_TAC `t:real^M->bool` THEN STRIP_TAC THEN MP_TAC(ISPECL
+   [`d2:(real^M->bool)->bool`; `d1:(real^M->bool)->bool`;
+    `t:real^M->bool`; `s:real^M->bool`] PARTIAL_DIVISION_EXTEND) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_TAC `d3:(real^M->bool)->bool`) THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum d3 (\k:real^M->bool. norm(f k:real^N))` THEN
+  ASM_SIMP_TAC[] THEN MATCH_MP_TAC SUM_SUBSET_SIMPLE THEN
+  ASM_REWRITE_TAC[NORM_POS_LE] THEN ASM_MESON_TAC[DIVISION_OF_FINITE]);;
+
+let SET_VARIATION_ON_ELEMENTARY = prove
+ (`!f:(real^M->bool)->real^N s.
+        (?d. d division_of s)
+        ==> set_variation s f =
+             sup { sum d (\k. norm(f k)) | d division_of s}`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[set_variation; sup] THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; LEFT_IMP_EXISTS_THM] THEN
+  ASM_SIMP_TAC[SET_VARIATION_ELEMENTARY_LEMMA]);;
+
+let SET_VARIATION_ON_INTERVAL = prove
+ (`!f:(real^M->bool)->real^N a b.
+        set_variation (interval[a,b]) f =
+        sup { sum d (\k. norm(f k)) | d division_of interval[a,b]}`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC SET_VARIATION_ON_ELEMENTARY THEN
+  REWRITE_TAC[ELEMENTARY_INTERVAL]);;
+
+let HAS_BOUNDED_SETVARIATION_WORKS = prove
+ (`!f:(real^M->bool)->real^N s.
+        f has_bounded_setvariation_on s
+        ==> (!d t. d division_of t /\ t SUBSET s
+                   ==> sum d (\k. norm(f k)) <= set_variation s f) /\
+            (!B. (!d t. d division_of t /\ t SUBSET s
+                        ==> sum d (\k. norm (f k)) <= B)
+                 ==> set_variation s f <= B)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_setvariation_on] THEN
+  DISCH_TAC THEN
+  MP_TAC(ISPEC `{ sum d (\k. norm((f:(real^M->bool)->real^N) k)) |
+                  ?t. d division_of t /\ t SUBSET s}`
+         SUP) THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[set_variation] THEN DISCH_THEN MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+  MAP_EVERY EXISTS_TAC [`&0`; `{}:(real^M->bool)->bool`] THEN
+  REWRITE_TAC[SUM_CLAUSES] THEN EXISTS_TAC `{}:real^M->bool` THEN
+  SIMP_TAC[division_of; EMPTY_SUBSET; NOT_IN_EMPTY; FINITE_EMPTY; UNIONS_0]);;
+
+let HAS_BOUNDED_SETVARIATION_WORKS_ON_ELEMENTARY = prove
+ (`!f:(real^M->bool)->real^N s.
+        f has_bounded_setvariation_on s /\ (?d. d division_of s)
+        ==> (!d. d division_of s
+                 ==> sum d (\k. norm(f k)) <= set_variation s f) /\
+            (!B. (!d. d division_of s ==> sum d (\k. norm(f k)) <= B)
+                 ==> set_variation s f <= B)`,
+  SIMP_TAC[GSYM SET_VARIATION_ELEMENTARY_LEMMA] THEN
+  MESON_TAC[HAS_BOUNDED_SETVARIATION_WORKS]);;
+
+let HAS_BOUNDED_SETVARIATION_WORKS_ON_INTERVAL = prove
+ (`!f:(real^M->bool)->real^N a b.
+      f has_bounded_setvariation_on interval[a,b]
+      ==> (!d. d division_of interval[a,b]
+               ==> sum d (\k. norm(f k)) <= set_variation (interval[a,b]) f) /\
+          (!B. (!d. d division_of interval[a,b]
+                    ==> sum d (\k. norm(f k)) <= B)
+               ==> set_variation (interval[a,b]) f <= B)`,
+  SIMP_TAC[HAS_BOUNDED_SETVARIATION_WORKS_ON_ELEMENTARY; ELEMENTARY_INTERVAL]);;
+
+let SET_VARIATION_UBOUND = prove
+ (`!f:(real^M->bool)->real^N s B.
+        f has_bounded_setvariation_on s /\
+        (!d t. d division_of t /\ t SUBSET s ==> sum d (\k. norm(f k)) <= B)
+        ==> set_variation s f <= B`,
+  MESON_TAC[HAS_BOUNDED_SETVARIATION_WORKS]);;
+
+let SET_VARIATION_UBOUND_ON_INTERVAL = prove
+ (`!f:(real^M->bool)->real^N a b B.
+        f has_bounded_setvariation_on interval[a,b] /\
+        (!d. d division_of interval[a,b] ==> sum d (\k. norm(f k)) <= B)
+        ==> set_variation (interval[a,b]) f <= B`,
+  SIMP_TAC[GSYM SET_VARIATION_ELEMENTARY_LEMMA; ELEMENTARY_INTERVAL] THEN
+  MESON_TAC[SET_VARIATION_UBOUND]);;
+
+let SET_VARIATION_LBOUND = prove
+ (`!f:(real^M->bool)->real^N s B.
+        f has_bounded_setvariation_on s /\
+        (?d t. d division_of t /\ t SUBSET s /\ B <= sum d (\k. norm(f k)))
+        ==> B <= set_variation s f`,
+  MESON_TAC[HAS_BOUNDED_SETVARIATION_WORKS; REAL_LE_TRANS]);;
+
+let SET_VARIATION_LBOUND_ON_INTERVAL = prove
+ (`!f:(real^M->bool)->real^N a b B.
+        f has_bounded_setvariation_on interval[a,b] /\
+        (?d. d division_of interval[a,b] /\ B <= sum d (\k. norm(f k)))
+        ==> B <= set_variation (interval[a,b]) f`,
+  MESON_TAC[HAS_BOUNDED_SETVARIATION_WORKS_ON_INTERVAL; REAL_LE_TRANS]);;
+
+let SET_VARIATION = prove
+ (`!f:(real^M->bool)->real^N s d t.
+        f has_bounded_setvariation_on s /\ d division_of t /\ t SUBSET s
+        ==> sum d (\k. norm(f k)) <= set_variation s f`,
+  MESON_TAC[HAS_BOUNDED_SETVARIATION_WORKS]);;
+
+let SET_VARIATION_WORKS_ON_INTERVAL = prove
+ (`!f:(real^M->bool)->real^N a b d.
+        f has_bounded_setvariation_on interval[a,b] /\
+        d division_of interval[a,b]
+        ==> sum d (\k. norm(f k)) <= set_variation (interval[a,b]) f`,
+  MESON_TAC[HAS_BOUNDED_SETVARIATION_WORKS_ON_INTERVAL]);;
+
+let SET_VARIATION_POS_LE = prove
+ (`!f:(real^M->bool)->real^N s.
+        f has_bounded_setvariation_on s ==> &0 <= set_variation s f`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] SET_VARIATION)) THEN
+  DISCH_THEN(MP_TAC o SPECL[`{}:(real^M->bool)->bool`; `{}:real^M->bool`]) THEN
+  REWRITE_TAC[EMPTY_SUBSET; SUM_CLAUSES; DIVISION_OF_TRIVIAL]);;
+
+let SET_VARIATION_GE_FUNCTION = prove
+ (`!f:(real^M->bool)->real^N s a b.
+        f has_bounded_setvariation_on s /\
+        interval[a,b] SUBSET s /\ ~(interval[a,b] = {})
+        ==> norm(f(interval[a,b])) <= set_variation s f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SET_VARIATION_LBOUND THEN
+  ASM_REWRITE_TAC[] THEN EXISTS_TAC `{interval[a:real^M,b]}` THEN
+  EXISTS_TAC `interval[a:real^M,b]` THEN
+  ASM_REWRITE_TAC[SUM_SING; REAL_LE_REFL] THEN
+  ASM_SIMP_TAC[DIVISION_OF_SELF]);;
+
+let SET_VARIATION_ON_NULL = prove
+ (`!f:(real^M->bool)->real^N s.
+        (!a b. content(interval[a,b]) = &0 ==> f(interval[a,b]) = vec 0) /\
+        content s = &0 /\ bounded s
+        ==> set_variation s f = &0`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SET_VARIATION_UBOUND THEN
+    ASM_SIMP_TAC[HAS_BOUNDED_SETVARIATION_ON_NULL] THEN
+    REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `x = &0 ==> x <= &0`) THEN
+    MATCH_MP_TAC SUM_EQ_0 THEN REWRITE_TAC[NORM_EQ_0] THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    MATCH_MP_TAC CONTENT_0_SUBSET_GEN THEN
+    EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[division_of; SUBSET_TRANS];
+    MATCH_MP_TAC SET_VARIATION_POS_LE THEN
+    ASM_SIMP_TAC[HAS_BOUNDED_SETVARIATION_ON_NULL]]);;
+
+let SET_VARIATION_TRIANGLE = prove
+ (`!f:(real^M->bool)->real^N g s.
+        f has_bounded_setvariation_on s /\
+        g has_bounded_setvariation_on s
+        ==> set_variation s (\x. f x + g x)
+             <= set_variation s f + set_variation s g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SET_VARIATION_UBOUND THEN
+  ASM_SIMP_TAC[HAS_BOUNDED_SETVARIATION_ON_ADD] THEN
+  MAP_EVERY X_GEN_TAC [`d:(real^M->bool)->bool`; `t:real^M->bool`] THEN
+  STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum d (\k. norm((f:(real^M->bool)->real^N) k)) +
+              sum d (\k. norm((g:(real^M->bool)->real^N) k))` THEN
+  CONJ_TAC THENL
+   [FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+    ASM_SIMP_TAC[GSYM SUM_ADD] THEN
+    MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[NORM_TRIANGLE];
+    MATCH_MP_TAC REAL_LE_ADD2 THEN
+    CONJ_TAC THEN MATCH_MP_TAC SET_VARIATION THEN ASM_MESON_TAC[]]);;
+
+let OPERATIVE_LIFTED_SETVARIATION = prove
+ (`!f:(real^M->bool)->real^N.
+        operative(+) f
+        ==> operative (lifted(+))
+                      (\i. if f has_bounded_setvariation_on i
+                           then SOME(set_variation i f) else NONE)`,
+  let lemma1 = prove
+   (`!f:(real^M->bool)->real B1 B2 k a b.
+      1 <= k /\ k <= dimindex(:M) /\
+      (!a b. content(interval[a,b]) = &0 ==> f(interval[a,b]) = &0) /\
+      (!a b c. f(interval[a,b]) <=
+               f(interval[a,b] INTER {x | x$k <= c}) +
+               f(interval[a,b] INTER {x | x$k >= c})) /\
+      (!d. d division_of (interval[a,b] INTER {x | x$k <= c})
+           ==> sum d f <= B1) /\
+      (!d. d division_of (interval[a,b] INTER {x | x$k >= c})
+           ==> sum d f <= B2)
+      ==> !d. d division_of interval[a,b] ==> sum d f <= B1 + B2`,
+    REPEAT GEN_TAC THEN
+    REPLICATE_TAC 4 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "L") (LABEL_TAC "R")) THEN
+    GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC
+     `sum {l INTER {x:real^M | x$k <= c} | l | l IN d /\
+                                        ~(l INTER {x | x$k <= c} = {})} f +
+      sum {l INTER {x | x$k >= c} | l | l IN d /\
+                                        ~(l INTER {x | x$k >= c} = {})} f` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC REAL_LE_ADD2 THEN CONJ_TAC THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[DIVISION_SPLIT]] THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+    W(fun (asl,w) ->
+         MP_TAC(PART_MATCH (lhs o rand) SUM_IMAGE_NONZERO (lhand(rand w))) THEN
+         MP_TAC(PART_MATCH (lhs o rand) SUM_IMAGE_NONZERO (rand(rand w)))) THEN
+    MATCH_MP_TAC(TAUT
+     `(a1 /\ a2) /\ (b1 /\ b2 ==> c)
+      ==> (a1 ==> b1) ==> (a2 ==> b2) ==> c`) THEN
+    CONJ_TAC THENL
+     [ASM_SIMP_TAC[FINITE_RESTRICT; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+      REWRITE_TAC[FORALL_IN_GSPEC; IMP_CONJ] THEN
+      FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+      REPEAT STRIP_TAC THEN ASM_SIMP_TAC[INTERVAL_SPLIT] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[GSYM INTERVAL_SPLIT] THENL
+       [MATCH_MP_TAC DIVISION_SPLIT_RIGHT_INJ;
+        MATCH_MP_TAC DIVISION_SPLIT_LEFT_INJ] THEN
+      ASM_MESON_TAC[];
+      DISCH_THEN(CONJUNCTS_THEN SUBST1_TAC)] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC
+     `sum d (f o (\l. l INTER {x | x$k <= c})) +
+      sum d (f o (\l. l INTER {x:real^M | x$k >= c}))` THEN
+    CONJ_TAC THENL
+     [ASM_SIMP_TAC[GSYM SUM_ADD] THEN MATCH_MP_TAC SUM_LE THEN
+      ASM_REWRITE_TAC[o_THM] THEN
+      FIRST_ASSUM(fun th -> ASM_REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]);
+      MATCH_MP_TAC(REAL_ARITH `x = y /\ w = z ==> x + w <= y + z`) THEN
+      CONJ_TAC THEN MATCH_MP_TAC SUM_SUPERSET THEN
+      REWRITE_TAC[SET_RULE `{x | x IN s /\ P x} SUBSET s`] THEN
+      REWRITE_TAC[SET_RULE `(x IN s /\ ~(x IN {x | x IN s /\ ~P x}) ==> Q x) <=>
+                            (x IN s ==> P x ==> Q x)`] THEN
+      SIMP_TAC[o_THM] THEN ASM_MESON_TAC[EMPTY_AS_INTERVAL; CONTENT_EMPTY]])
+  and lemma2 = prove
+   (`!f:(real^M->bool)->real B k.
+      1 <= k /\ k <= dimindex(:M) /\
+      (!a b. content(interval[a,b]) = &0 ==> f(interval[a,b]) = &0) /\
+      (!d. d division_of interval[a,b] ==> sum d f <= B)
+      ==> !d1 d2. d1 division_of (interval[a,b] INTER {x | x$k <= c}) /\
+                  d2 division_of (interval[a,b] INTER {x | x$k >= c})
+                  ==> sum d1 f + sum d2 f <= B`,
+    REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `d1 UNION d2:(real^M->bool)->bool`) THEN
+    ANTS_TAC THENL
+     [SUBGOAL_THEN
+       `interval[a,b] = (interval[a,b] INTER {x:real^M | x$k <= c}) UNION
+                        (interval[a,b] INTER {x:real^M | x$k >= c})`
+      SUBST1_TAC THENL
+       [MATCH_MP_TAC(SET_RULE
+         `(!x. x IN t \/ x IN u) ==> (s = s INTER t UNION s INTER u)`) THEN
+        REWRITE_TAC[IN_ELIM_THM] THEN REAL_ARITH_TAC;
+        MATCH_MP_TAC DIVISION_DISJOINT_UNION THEN ASM_REWRITE_TAC[] THEN
+        REWRITE_TAC[GSYM INTERIOR_INTER] THEN
+        MATCH_MP_TAC(SET_RULE
+         `!t. interior s SUBSET interior t /\ interior t = {}
+              ==> interior s = {}`) THEN
+        EXISTS_TAC `{x:real^M | x$k = c}` THEN CONJ_TAC THENL
+         [ALL_TAC; REWRITE_TAC[INTERIOR_STANDARD_HYPERPLANE]] THEN
+        MATCH_MP_TAC SUBSET_INTERIOR THEN
+        REWRITE_TAC[SUBSET; IN_INTER; IN_ELIM_THM] THEN REAL_ARITH_TAC];
+      MATCH_MP_TAC(REAL_ARITH `x = y ==> x <= b ==> y <= b`) THEN
+      MATCH_MP_TAC SUM_UNION_NONZERO THEN
+      REPEAT(CONJ_TAC THENL [ASM_MESON_TAC[DIVISION_OF_FINITE]; ALL_TAC]) THEN
+      X_GEN_TAC `k:real^M->bool` THEN REWRITE_TAC[IN_INTER] THEN STRIP_TAC THEN
+      SUBGOAL_THEN `?u v:real^M. k = interval[u,v]`
+        (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+      THENL [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN MATCH_MP_TAC CONTENT_0_SUBSET_GEN THEN
+      EXISTS_TAC `interval[a,b] INTER {x:real^M | x$k = c}` THEN CONJ_TAC THENL
+       [MATCH_MP_TAC SUBSET_TRANS THEN
+        EXISTS_TAC `(interval[a,b] INTER {x:real^M | x$k <= c}) INTER
+                    (interval[a,b] INTER {x:real^M | x$k >= c})` THEN
+        CONJ_TAC THENL
+         [ONCE_REWRITE_TAC[SUBSET_INTER] THEN ASM_MESON_TAC[division_of];
+          REWRITE_TAC[SET_RULE
+            `(s INTER t) INTER (s INTER u) = s INTER t INTER u`] THEN
+          SIMP_TAC[SUBSET; IN_INTER; IN_ELIM_THM] THEN REAL_ARITH_TAC];
+        SIMP_TAC[BOUNDED_INTER; BOUNDED_INTERVAL] THEN
+        GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+         [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
+        ASM_SIMP_TAC[GSYM INTER_ASSOC; INTERVAL_SPLIT] THEN
+        REWRITE_TAC[CONTENT_EQ_0] THEN EXISTS_TAC `k:num` THEN
+        ASM_SIMP_TAC[LAMBDA_BETA] THEN REAL_ARITH_TAC]]) in
+  REWRITE_TAC[operative; NEUTRAL_VECTOR_ADD] THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (ASSUME_TAC o GSYM)) THEN
+  ASM_SIMP_TAC[HAS_BOUNDED_SETVARIATION_ON_NULL; BOUNDED_INTERVAL;
+   MONOIDAL_REAL_ADD; SET_VARIATION_ON_NULL; NEUTRAL_LIFTED;
+   NEUTRAL_REAL_ADD] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`; `c:real`; `k:num`] THEN
+  STRIP_TAC THEN ASM_CASES_TAC
+   `(f:(real^M->bool)->real^N) has_bounded_setvariation_on interval[a,b]` THEN
+  ASM_REWRITE_TAC[] THENL
+   [SUBGOAL_THEN
+     `(f:(real^M->bool)->real^N) has_bounded_setvariation_on
+      interval[a,b] INTER {x | x$k <= c} /\
+      (f:(real^M->bool)->real^N) has_bounded_setvariation_on
+      interval[a,b] INTER {x | x$k >= c}`
+    ASSUME_TAC THENL
+     [CONJ_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+       (REWRITE_RULE[IMP_CONJ] HAS_BOUNDED_SETVARIATION_ON_SUBSET)) THEN
+      REWRITE_TAC[INTER_SUBSET];
+      ALL_TAC] THEN
+    ASM_REWRITE_TAC[lifted] THEN AP_TERM_TAC THEN
+    REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC SET_VARIATION_UBOUND_ON_INTERVAL THEN ASM_REWRITE_TAC[] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC
+       (REWRITE_RULE[IMP_IMP; RIGHT_IMP_FORALL_THM] lemma1) THEN
+      MAP_EVERY EXISTS_TAC [`k:num`; `a:real^M`; `b:real^M`] THEN
+      ASM_SIMP_TAC[NORM_0] THEN CONJ_TAC THENL
+       [REPEAT GEN_TAC THEN
+        MATCH_MP_TAC(NORM_ARITH
+          `x:real^N = y + z ==> norm(x) <= norm y + norm z`) THEN
+        ASM_SIMP_TAC[];
+        FIRST_X_ASSUM(fun th -> MP_TAC th THEN MATCH_MP_TAC MONO_AND) THEN
+        ASM_SIMP_TAC[INTERVAL_SPLIT; SET_VARIATION_WORKS_ON_INTERVAL]];
+      ONCE_REWRITE_TAC[REAL_ARITH `x + y <= z <=> x <= z - y`] THEN
+      ASM_SIMP_TAC[INTERVAL_SPLIT] THEN
+      MATCH_MP_TAC SET_VARIATION_UBOUND_ON_INTERVAL THEN
+      ASM_SIMP_TAC[GSYM INTERVAL_SPLIT] THEN
+      X_GEN_TAC `d1:(real^M->bool)->bool` THEN STRIP_TAC THEN
+      ONCE_REWRITE_TAC[REAL_ARITH `x <= y - z <=> z <= y - x`] THEN
+      ASM_SIMP_TAC[INTERVAL_SPLIT] THEN
+      MATCH_MP_TAC SET_VARIATION_UBOUND_ON_INTERVAL THEN
+      ASM_SIMP_TAC[GSYM INTERVAL_SPLIT] THEN
+      X_GEN_TAC `d2:(real^M->bool)->bool` THEN STRIP_TAC THEN
+      REWRITE_TAC[REAL_ARITH `x <= y - z <=> z + x <= y`] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC
+       (REWRITE_RULE[IMP_IMP; RIGHT_IMP_FORALL_THM] lemma2) THEN
+      EXISTS_TAC `k:num` THEN
+      ASM_SIMP_TAC[NORM_0; SET_VARIATION_WORKS_ON_INTERVAL]];
+    REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[lifted]) THEN
+    FIRST_X_ASSUM(MP_TAC o check (is_neg o concl)) THEN
+    MATCH_MP_TAC(TAUT `p ==> ~p ==> q`) THEN
+    REWRITE_TAC[HAS_BOUNDED_SETVARIATION_ON_INTERVAL] THEN
+    EXISTS_TAC `set_variation (interval[a,b] INTER {x | x$k <= c})
+                              (f:(real^M->bool)->real^N) +
+                set_variation (interval[a,b] INTER {x | x$k >= c}) f` THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC
+       (REWRITE_RULE[IMP_IMP; RIGHT_IMP_FORALL_THM] lemma1) THEN
+      MAP_EVERY EXISTS_TAC [`k:num`; `a:real^M`; `b:real^M`] THEN
+      ASM_SIMP_TAC[NORM_0] THEN REPEAT CONJ_TAC THENL
+       [REPEAT GEN_TAC THEN
+        MATCH_MP_TAC(NORM_ARITH
+          `x:real^N = y + z ==> norm(x) <= norm y + norm z`) THEN
+        ASM_SIMP_TAC[];
+        UNDISCH_TAC
+         `(f:(real^M->bool)->real^N) has_bounded_setvariation_on
+          (interval[a,b] INTER {x | x$k <= c})` THEN
+        ASM_SIMP_TAC[INTERVAL_SPLIT; SET_VARIATION_WORKS_ON_INTERVAL];
+        UNDISCH_TAC
+         `(f:(real^M->bool)->real^N) has_bounded_setvariation_on
+          (interval[a,b] INTER {x | x$k >= c})` THEN
+        ASM_SIMP_TAC[INTERVAL_SPLIT; SET_VARIATION_WORKS_ON_INTERVAL]]]);;
+
+let HAS_BOUNDED_SETVARIATION_ON_DIVISION = prove
+ (`!f:(real^M->bool)->real^N a b d.
+        operative (+) f /\ d division_of interval[a,b]
+        ==> ((!k. k IN d ==> f has_bounded_setvariation_on k) <=>
+             f has_bounded_setvariation_on interval[a,b])`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC OPERATIVE_DIVISION_AND THEN
+  ASM_REWRITE_TAC[operative; NEUTRAL_AND] THEN CONJ_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[operative; NEUTRAL_VECTOR_ADD]) THEN
+    ASM_SIMP_TAC[HAS_BOUNDED_SETVARIATION_ON_NULL; BOUNDED_INTERVAL];
+    FIRST_ASSUM(MP_TAC o MATCH_MP OPERATIVE_LIFTED_SETVARIATION) THEN
+    REWRITE_TAC[operative] THEN DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+    REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+    REPEAT(COND_CASES_TAC THEN
+           ASM_REWRITE_TAC[lifted; distinctness "option"])]);;
+
+let SET_VARIATION_ON_DIVISION = prove
+ (`!f:(real^M->bool)->real^N a b d.
+        operative (+) f /\ d division_of interval[a,b] /\
+        f has_bounded_setvariation_on interval[a,b]
+        ==> sum d (\k. set_variation k f) = set_variation (interval[a,b]) f`,
+  let lemma0 = prove
+   (`!op x y. lifted op (SOME x) y = SOME z <=> ?w. y = SOME w /\ op x w = z`,
+    GEN_TAC THEN GEN_TAC THEN MATCH_MP_TAC option_INDUCT THEN
+    REWRITE_TAC[lifted; distinctness "option"; injectivity "option"] THEN
+    MESON_TAC[]) in
+  let lemma = prove
+   (`!P op f s z.
+          monoidal op /\ FINITE s /\
+          iterate(lifted op) s (\i. if P i then SOME(f i) else NONE) = SOME z
+          ==> iterate op s f = z`,
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REPEAT GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN
+    MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+    ASM_SIMP_TAC[ITERATE_CLAUSES; MONOIDAL_LIFTED; NEUTRAL_LIFTED] THEN
+    REWRITE_TAC[injectivity "option"] THEN REPEAT GEN_TAC THEN
+    STRIP_TAC THEN GEN_TAC THEN COND_CASES_TAC THEN
+    REWRITE_TAC[lifted; distinctness "option"] THEN ASM_MESON_TAC[lemma0]) in
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP OPERATIVE_LIFTED_SETVARIATION) THEN
+  DISCH_THEN(MP_TAC o SPECL[`d:(real^M->bool)->bool`; `a:real^M`; `b:real^M`] o
+    MATCH_MP (REWRITE_RULE [TAUT `a /\ b /\ c ==> d <=> b ==> a /\ c ==> d`]
+        OPERATIVE_DIVISION)) THEN
+  ASM_SIMP_TAC[MONOIDAL_LIFTED; MONOIDAL_REAL_ADD] THEN
+  MP_TAC(ISPECL
+   [`\k. (f:(real^M->bool)->real^N) has_bounded_setvariation_on k`;
+    `(+):real->real->real`;
+    `\k. set_variation k (f:(real^M->bool)->real^N)`;
+    `d:(real^M->bool)->bool`;
+    `set_variation (interval[a,b]) (f:(real^M->bool)->real^N)`]
+   lemma) THEN
+  FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  ASM_REWRITE_TAC[sum; MONOIDAL_REAL_ADD]);;
+
+let SET_VARIATION_MONOTONE = prove
+ (`!f:(real^M->bool)->real^N s t.
+        f has_bounded_setvariation_on s /\ t SUBSET s
+        ==> set_variation t f <= set_variation s f`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[set_variation] THEN
+  MATCH_MP_TAC REAL_SUP_LE_SUBSET THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+    MAP_EVERY EXISTS_TAC [`&0`; `{}:(real^M->bool)->bool`] THEN
+    REWRITE_TAC[SUM_CLAUSES] THEN EXISTS_TAC `{}:real^M->bool` THEN
+    REWRITE_TAC[EMPTY_SUBSET; DIVISION_OF_TRIVIAL];
+    MATCH_MP_TAC(SET_RULE
+     `(!d. P d ==> Q d) ==> {f d | P d} SUBSET {f d | Q d}`) THEN
+    ASM_MESON_TAC[SUBSET_TRANS];
+    REWRITE_TAC[FORALL_IN_GSPEC; LEFT_IMP_EXISTS_THM] THEN
+    ASM_REWRITE_TAC[GSYM has_bounded_setvariation_on]]);;
+
+let HAS_BOUNDED_SETVARIATION_REFLECT2_EQ,SET_VARIATION_REFLECT2 =
+ (CONJ_PAIR o prove)
+ (`(!f:(real^M->bool)->real^N s.
+        (\k. f(IMAGE (--) k)) has_bounded_setvariation_on (IMAGE (--) s) <=>
+        f has_bounded_setvariation_on s) /\
+   (!f:(real^M->bool)->real^N s.
+        set_variation (IMAGE (--) s) (\k. f(IMAGE (--) k)) =
+        set_variation s f)`,
+  MATCH_MP_TAC SETVARIATION_EQUAL_LEMMA THEN
+  EXISTS_TAC `IMAGE ((--):real^M->real^M)` THEN
+  SIMP_TAC[IMAGE_SUBSET; GSYM IMAGE_o; o_DEF] THEN
+  REWRITE_TAC[VECTOR_NEG_NEG; IMAGE_ID; REFLECT_INTERVAL] THEN
+  SIMP_TAC[ETA_AX; DIVISION_OF_REFLECT] THEN
+  SIMP_TAC[EQ_INTERVAL; TAUT `~q /\ (p /\ q \/ r) <=> ~q /\ r`] THEN
+  REWRITE_TAC[TAUT `p /\ q /\ r <=> r /\ q /\ p`] THEN
+  REWRITE_TAC[UNWIND_THM1; CONTRAPOS_THM] THEN
+  REWRITE_TAC[INTERVAL_EQ_EMPTY; VECTOR_NEG_COMPONENT; REAL_LT_NEG2]);;
+
+let HAS_BOUNDED_SETVARIATION_TRANSLATION2_EQ, SET_VARIATION_TRANSLATION2 =
+ (CONJ_PAIR o prove)
+ (`(!a f:(real^M->bool)->real^N s.
+          (\k. f(IMAGE (\x. a + x) k))
+          has_bounded_setvariation_on (IMAGE (\x. --a + x) s) <=>
+          f has_bounded_setvariation_on s) /\
+   (!a f:(real^M->bool)->real^N s.
+          set_variation (IMAGE (\x. --a + x) s) (\k. f(IMAGE (\x. a + x) k)) =
+          set_variation s f)`,
+  GEN_REWRITE_TAC I [AND_FORALL_THM] THEN X_GEN_TAC `a:real^M` THEN
+  MATCH_MP_TAC SETVARIATION_EQUAL_LEMMA THEN
+  EXISTS_TAC `\s. IMAGE (\x:real^M. a + x) s` THEN
+  SIMP_TAC[IMAGE_SUBSET; GSYM IMAGE_o; o_DEF] THEN
+  REWRITE_TAC[VECTOR_ARITH `a + --a + x:real^N = x`; IMAGE_ID;
+              VECTOR_ARITH `--a + a + x:real^N = x`] THEN
+  REWRITE_TAC[GSYM INTERVAL_TRANSLATION] THEN
+  SIMP_TAC[EQ_INTERVAL; TAUT `~q /\ (p /\ q \/ r) <=> ~q /\ r`] THEN
+  REWRITE_TAC[TAUT `p /\ q /\ r <=> r /\ q /\ p`] THEN
+  REWRITE_TAC[UNWIND_THM1; CONTRAPOS_THM] THEN
+  REWRITE_TAC[INTERVAL_EQ_EMPTY; VECTOR_ADD_COMPONENT; REAL_LT_LADD] THEN
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [ETA_AX] THEN
+  ASM_SIMP_TAC[DIVISION_OF_TRANSLATION]);;
+
+let HAS_BOUNDED_SETVARIATION_TRANSLATION = prove
+ (`!f:(real^M->bool)->real^N s a.
+        f has_bounded_setvariation_on s
+        ==> (\k. f(IMAGE (\x. a + x) k))
+            has_bounded_setvariation_on (IMAGE (\x. --a + x) s)`,
+  REWRITE_TAC[HAS_BOUNDED_SETVARIATION_TRANSLATION2_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Absolute integrability (this is the same as Lebesgue integrability).      *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("absolutely_integrable_on",(12,"right"));;
+
+let absolutely_integrable_on = new_definition
+ `f absolutely_integrable_on s <=>
+        f integrable_on s /\ (\x. lift(norm(f x))) integrable_on s`;;
+
+let ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE = prove
+ (`!f s. f absolutely_integrable_on s ==> f integrable_on s`,
+  SIMP_TAC[absolutely_integrable_on]);;
+
+let ABSOLUTELY_INTEGRABLE_LE = prove
+ (`!f:real^M->real^N s.
+        f absolutely_integrable_on s
+        ==> norm(integral s f) <= drop(integral s (\x. lift(norm(f x))))`,
+  REWRITE_TAC[absolutely_integrable_on] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+  ASM_REWRITE_TAC[LIFT_DROP; REAL_LE_REFL]);;
+
+let ABSOLUTELY_INTEGRABLE_0 = prove
+ (`!s. (\x. vec 0) absolutely_integrable_on s`,
+  REWRITE_TAC[absolutely_integrable_on; NORM_0; LIFT_NUM; INTEGRABLE_0]);;
+
+let ABSOLUTELY_INTEGRABLE_CMUL = prove
+ (`!f s c. f absolutely_integrable_on s
+           ==> (\x. c % f(x)) absolutely_integrable_on s`,
+  SIMP_TAC[absolutely_integrable_on; INTEGRABLE_CMUL; NORM_MUL; LIFT_CMUL]);;
+
+let ABSOLUTELY_INTEGRABLE_NEG = prove
+ (`!f s. f absolutely_integrable_on s
+         ==> (\x. --f(x)) absolutely_integrable_on s`,
+  SIMP_TAC[absolutely_integrable_on; INTEGRABLE_NEG; NORM_NEG]);;
+
+let ABSOLUTELY_INTEGRABLE_NORM = prove
+ (`!f s. f absolutely_integrable_on s
+         ==> (\x. lift(norm(f x))) absolutely_integrable_on s`,
+  SIMP_TAC[absolutely_integrable_on; NORM_LIFT; REAL_ABS_NORM]);;
+
+let ABSOLUTELY_INTEGRABLE_ABS_1 = prove
+ (`!f s. f absolutely_integrable_on s
+         ==> (\x. lift(abs(drop(f x)))) absolutely_integrable_on s`,
+  REWRITE_TAC[GSYM NORM_LIFT; LIFT_DROP; ABSOLUTELY_INTEGRABLE_NORM]);;
+
+let ABSOLUTELY_INTEGRABLE_ON_SUBINTERVAL = prove
+ (`!f:real^M->real^N s a b.
+        f absolutely_integrable_on s /\ interval[a,b] SUBSET s
+        ==> f absolutely_integrable_on interval[a,b]`,
+  REWRITE_TAC[absolutely_integrable_on] THEN
+  MESON_TAC[INTEGRABLE_ON_SUBINTERVAL]);;
+
+let ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION = prove
+ (`!f:real^M->real^N s.
+        f absolutely_integrable_on s
+        ==> (\k. integral k f) has_bounded_setvariation_on s`,
+  REWRITE_TAC[has_bounded_setvariation_on] THEN REPEAT STRIP_TAC THEN
+  EXISTS_TAC
+   `drop(integral (s:real^M->bool) (\x. lift(norm(f x:real^N))))` THEN
+  X_GEN_TAC `d:(real^M->bool)->bool` THEN
+  X_GEN_TAC `t:real^M->bool` THEN STRIP_TAC THEN
+  SUBGOAL_THEN `(UNIONS d:real^M->bool) SUBSET s` ASSUME_TAC THENL
+   [ASM_MESON_TAC[SUBSET_TRANS; division_of]; ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC
+   `drop(integral (UNIONS d) (\x. lift(norm((f:real^M->real^N) x))))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC INTEGRAL_SUBSET_DROP_LE THEN
+    ASM_REWRITE_TAC[LIFT_DROP; NORM_POS_LE] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC INTEGRABLE_ON_SUBDIVISION THEN
+      EXISTS_TAC `s:real^M->bool` THEN
+      EXISTS_TAC `d:(real^M->bool)->bool` THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[DIVISION_OF_SUBSET; division_of]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+    MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_NORM THEN ASM_REWRITE_TAC[]] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC
+   `drop(vsum d (\i. integral i (\x:real^M. lift(norm(f x:real^N)))))` THEN
+  CONJ_TAC THENL
+   [FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+    ASM_SIMP_TAC[DROP_VSUM] THEN MATCH_MP_TAC SUM_LE THEN
+    ASM_REWRITE_TAC[o_THM] THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+    MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN DISCH_TAC THEN
+    MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_LE THEN
+    MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_ON_SUBINTERVAL THEN
+    EXISTS_TAC `s:real^M->bool` THEN ASM_MESON_TAC[division_of; SUBSET_TRANS];
+    MATCH_MP_TAC REAL_EQ_IMP_LE THEN AP_TERM_TAC THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC INTEGRAL_COMBINE_DIVISION_TOPDOWN THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[DIVISION_OF_UNION_SELF]] THEN
+    MATCH_MP_TAC INTEGRABLE_ON_SUBDIVISION THEN
+    MAP_EVERY EXISTS_TAC [`s:real^M->bool`; `d:(real^M->bool)->bool`] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[DIVISION_OF_UNION_SELF]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+    MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_NORM THEN ASM_REWRITE_TAC[]]);;
+
+let lemma = prove
+ (`!f:A->real^N g s e.
+        sum s (\x. norm(f x - g x)) < e
+        ==> FINITE s
+            ==> abs(sum s (\x. norm(f x)) - sum s (\x. norm(g x))) < e`,
+  REPEAT GEN_TAC THEN SIMP_TAC[GSYM SUM_SUB] THEN
+  DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+  MATCH_MP_TAC(REAL_ARITH `x <= y ==> y < e ==> x < e`) THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) SUM_ABS o lhand o snd) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REAL_ARITH `y <= z ==> x <= y ==> x <= z`) THEN
+  MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[] THEN
+  REPEAT STRIP_TAC THEN NORM_ARITH_TAC);;
+
+let BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE_INTERVAL = prove
+ (`!f:real^M->real^N a b.
+        f integrable_on interval[a,b] /\
+        (\k. integral k f) has_bounded_setvariation_on interval[a,b]
+        ==> f absolutely_integrable_on interval[a,b]`,
+  REWRITE_TAC[HAS_BOUNDED_SETVARIATION_ON_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[absolutely_integrable_on] THEN
+  MP_TAC(ISPEC `IMAGE (\d. sum d (\k. norm(integral k (f:real^M->real^N))))
+                      {d | d division_of interval[a,b] }`
+         SUP) THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; IMAGE_EQ_EMPTY] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+  ABBREV_TAC
+   `i = sup (IMAGE (\d. sum d (\k. norm(integral k (f:real^M->real^N))))
+                      {d | d division_of interval[a,b] })` THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[ELEMENTARY_INTERVAL] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+  STRIP_TAC THEN REWRITE_TAC[integrable_on] THEN EXISTS_TAC `lift i` THEN
+  REWRITE_TAC[has_integral] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `i - e / &2`) THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 < e ==> ~(i <= i - e / &2)`] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; REAL_NOT_LE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `d:(real^M->bool)->bool` THEN STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  SUBGOAL_THEN
+   `!x. ?e. &0 < e /\
+            !i. i IN d /\ ~(x IN i) ==> ball(x:real^M,e) INTER i = {}`
+  MP_TAC THENL
+   [X_GEN_TAC `x:real^M` THEN MP_TAC(ISPECL
+     [`UNIONS {i:real^M->bool | i IN d /\ ~(x IN i)}`; `x:real^M`]
+     SEPARATE_POINT_CLOSED) THEN
+    ANTS_TAC THENL
+     [CONJ_TAC THENL [ALL_TAC; SET_TAC[]] THEN
+      MATCH_MP_TAC CLOSED_UNIONS THEN
+      ASM_SIMP_TAC[FINITE_RESTRICT; IN_ELIM_THM; IMP_CONJ] THEN
+      FIRST_ASSUM(fun t -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION t]) THEN
+      REWRITE_TAC[CLOSED_INTERVAL];
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real` THEN
+    SIMP_TAC[FORALL_IN_UNIONS; EXTENSION; IN_INTER; NOT_IN_EMPTY; IN_BALL] THEN
+    REWRITE_TAC[IN_ELIM_THM; DE_MORGAN_THM; REAL_NOT_LT] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM; FORALL_AND_THM] THEN
+  X_GEN_TAC `k:real^M->real` THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `e / &2` o MATCH_MP HENSTOCK_LEMMA) THEN
+  ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\x:real^M. g(x) INTER ball(x,k x)` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC GAUGE_INTER THEN ASM_REWRITE_TAC[] THEN
+    ASM_REWRITE_TAC[gauge; CENTRE_IN_BALL; OPEN_BALL];
+    ALL_TAC] THEN
+  REWRITE_TAC[FINE_INTER] THEN X_GEN_TAC `p:(real^M#(real^M->bool))->bool` THEN
+  STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  ABBREV_TAC
+   `p' = {(x:real^M,k:real^M->bool) |
+                ?i l. x IN i /\ i IN d /\ (x,l) IN p /\ k = i INTER l}` THEN
+  SUBGOAL_THEN `g fine (p':(real^M#(real^M->bool))->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "p'" THEN
+    MP_TAC(ASSUME `g fine (p:(real^M#(real^M->bool))->bool)`) THEN
+    REWRITE_TAC[fine; IN_ELIM_PAIR_THM] THEN
+    MESON_TAC[SET_RULE `k SUBSET l ==> (i INTER k) SUBSET l`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `p' tagged_division_of interval[a:real^M,b]` ASSUME_TAC THENL
+   [REWRITE_TAC[TAGGED_DIVISION_OF] THEN EXPAND_TAC "p'" THEN
+    REWRITE_TAC[IN_ELIM_PAIR_THM] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+    MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+     [DISCH_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN
+      EXISTS_TAC
+       `IMAGE (\(k,(x,l)). x,k INTER l)
+              {k,xl | k IN (d:(real^M->bool)->bool) /\
+                      xl IN (p:(real^M#(real^M->bool))->bool)}` THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; FINITE_PRODUCT] THEN
+      EXPAND_TAC "p'" THEN REWRITE_TAC[SUBSET; FORALL_PAIR_THM] THEN
+      REWRITE_TAC[IN_ELIM_PAIR_THM; IN_IMAGE; EXISTS_PAIR_THM; PAIR_EQ] THEN
+      MESON_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+     [DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN
+      REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+      MAP_EVERY X_GEN_TAC [`i:real^M->bool`; `l:real^M->bool`] THEN
+      STRIP_TAC THEN FIRST_X_ASSUM SUBST_ALL_TAC THEN
+      ASM_SIMP_TAC[IN_INTER] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC(SET_RULE `l SUBSET s ==> (k INTER l) SUBSET s`) THEN
+        ASM_MESON_TAC[];
+        ALL_TAC] THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^M`; `l:real^M->bool`]) THEN
+      ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+      DISCH_THEN(MP_TAC o SPEC `i:real^M->bool` o el 1 o CONJUNCTS) THEN
+      ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+      ASM_REWRITE_TAC[INTER_INTERVAL] THEN MESON_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+     [DISCH_TAC THEN MAP_EVERY X_GEN_TAC
+       [`x1:real^M`; `k1:real^M->bool`; `x2:real^M`; `k2:real^M->bool`] THEN
+      DISCH_THEN(CONJUNCTS_THEN2
+       (X_CHOOSE_THEN `i1:real^M->bool` (X_CHOOSE_THEN `l1:real^M->bool`
+          STRIP_ASSUME_TAC)) MP_TAC) THEN
+      FIRST_X_ASSUM SUBST_ALL_TAC THEN
+      DISCH_THEN(CONJUNCTS_THEN2
+       (X_CHOOSE_THEN `i2:real^M->bool` (X_CHOOSE_THEN `l2:real^M->bool`
+          STRIP_ASSUME_TAC)) ASSUME_TAC) THEN
+      FIRST_X_ASSUM SUBST_ALL_TAC THEN
+      MATCH_MP_TAC(SET_RULE
+       `(interior(i1) INTER interior(i2) = {} \/
+         interior(l1) INTER interior(l2) = {}) /\
+        interior(i1 INTER l1) SUBSET interior(i1) /\
+        interior(i2 INTER l2) SUBSET interior(i2) /\
+        interior(i1 INTER l1) SUBSET interior(l1) /\
+        interior(i2 INTER l2) SUBSET interior(l2)
+        ==> interior(i1 INTER l1) INTER interior(i2 INTER l2) = {}`) THEN
+      SIMP_TAC[SUBSET_INTERIOR; INTER_SUBSET] THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL
+       [`x1:real^M`; `l1:real^M->bool`; `x2:real^M`; `l2:real^M->bool`]) THEN
+      ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+      DISCH_THEN(MP_TAC o el 2 o CONJUNCTS) THEN
+      DISCH_THEN(MP_TAC o SPECL [`i1:real^M->bool`; `i2:real^M->bool`]) THEN
+      ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o check(is_neg o concl)) THEN
+      ASM_REWRITE_TAC[PAIR_EQ] THEN MESON_TAC[];
+      ALL_TAC] THEN
+    DISCH_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+     [REWRITE_TAC[UNIONS_SUBSET; IN_ELIM_THM] THEN
+      REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(SET_RULE `i SUBSET s ==> (i INTER k) SUBSET s`) THEN
+      ASM_MESON_TAC[division_of];
+      ALL_TAC] THEN
+    REWRITE_TAC[SUBSET] THEN X_GEN_TAC `y:real^M` THEN DISCH_TAC THEN
+    REWRITE_TAC[IN_UNIONS; IN_ELIM_THM] THEN
+    REWRITE_TAC[LEFT_AND_EXISTS_THM; GSYM CONJ_ASSOC] THEN
+    REWRITE_TAC[MESON[]
+     `p /\ q /\ r /\ x = t /\ P x <=> x = t /\ p /\ q /\ r /\ P t`] THEN
+    ONCE_REWRITE_TAC[MESON[]
+     `(?a b c d. P a b c d) <=> (?d b c a. P a b c d)`] THEN
+    REWRITE_TAC[IN_INTER; UNWIND_THM2] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+    DISCH_THEN(MP_TAC o SPEC `y:real^M`) THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[IN_UNIONS; IN_ELIM_THM; LEFT_AND_EXISTS_THM] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `l:real^M->bool` THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x:real^M` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o last o CONJUNCTS o
+        GEN_REWRITE_RULE I [division_of]) THEN
+    REWRITE_TAC[EXTENSION] THEN DISCH_THEN(MP_TAC o SPEC `y:real^M`) THEN
+    ASM_REWRITE_TAC[IN_UNIONS] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^M->bool` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^M`; `k:real^M->bool`]) THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM CONTRAPOS_THM] THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_MP_TAC THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    EXISTS_TAC `y:real^M` THEN ASM_REWRITE_TAC[INTER; IN_ELIM_THM] THEN
+    UNDISCH_TAC `(\x:real^M. ball (x,k x)) fine p` THEN
+    REWRITE_TAC[fine; SUBSET] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `p':(real^M#(real^M->bool))->bool`) THEN
+  ASM_REWRITE_TAC[] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[tagged_division_of]; ALL_TAC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  REWRITE_TAC[LAMBDA_PAIR] THEN DISCH_THEN(MP_TAC o MATCH_MP lemma) THEN
+  ASM_SIMP_TAC[DROP_VSUM; o_DEF; SUM_SUB; DROP_SUB; ABS_DROP] THEN
+  REWRITE_TAC[LAMBDA_PAIR_THM; DROP_CMUL; NORM_MUL; LIFT_DROP] THEN
+  MATCH_MP_TAC(REAL_ARITH
+    `!sni. i - e / &2 < sni /\
+           sni' <= i /\ sni <= sni' /\ sf' = sf
+              ==> abs(sf' - sni') < e / &2
+                  ==> abs(sf - i) < e`) THEN
+  EXISTS_TAC `sum d (\k. norm (integral k (f:real^M->real^N)))` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MP_TAC(ISPECL [`\k. norm(integral k (f:real^M->real^N))`;
+                   `p':(real^M#(real^M->bool))->bool`;
+                   `interval[a:real^M,b]`] SUM_OVER_TAGGED_DIVISION_LEMMA) THEN
+    ASM_SIMP_TAC[INTEGRAL_NULL; NORM_0] THEN DISCH_THEN SUBST1_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[DIVISION_OF_TAGGED_DIVISION];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `p' = {x:real^M,(i INTER l:real^M->bool) |
+            (x,l) IN p /\ i IN d /\ ~(i INTER l = {})}`
+  (LABEL_TAC "p'") THENL
+   [EXPAND_TAC "p'" THEN GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[FORALL_PAIR_THM; IN_ELIM_PAIR_THM] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN
+    REWRITE_TAC[PAIR_EQ; GSYM CONJ_ASSOC] THEN
+    GEN_REWRITE_TAC RAND_CONV [SWAP_EXISTS_THM] THEN
+    AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+    X_GEN_TAC `i:real^M->bool` THEN REWRITE_TAC[] THEN
+    CONV_TAC(RAND_CONV UNWIND_CONV) THEN
+    AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+    X_GEN_TAC `l:real^M->bool` THEN REWRITE_TAC[] THEN
+    ASM_CASES_TAC `k:real^M->bool = i INTER l` THEN ASM_REWRITE_TAC[] THEN
+    ASM_REWRITE_TAC[IN_INTER; GSYM MEMBER_NOT_EMPTY] THEN
+    EQ_TAC THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(X_CHOOSE_THEN `y:real^M` STRIP_ASSUME_TAC) THEN
+    ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^M`; `i:real^M->bool`]) THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM CONTRAPOS_THM] THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_MP_TAC THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    EXISTS_TAC `y:real^M` THEN ASM_REWRITE_TAC[INTER; IN_ELIM_THM] THEN
+    UNDISCH_TAC `(\x:real^M. ball (x,k x)) fine p` THEN
+    REWRITE_TAC[fine; SUBSET] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [MP_TAC(ISPECL
+     [`\y. norm(integral y (f:real^M->real^N))`;
+      `p':(real^M#(real^M->bool))->bool`;
+      `interval[a:real^M,b]`]
+     SUM_OVER_TAGGED_DIVISION_LEMMA) THEN
+    ASM_SIMP_TAC[INTEGRAL_NULL; NORM_0] THEN DISCH_THEN SUBST1_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum {i INTER l | i IN d /\
+                 (l IN IMAGE SND (p:(real^M#(real^M->bool))->bool))}
+                    (\k. norm(integral k (f:real^M->real^N)))` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC REAL_EQ_IMP_LE THEN MATCH_MP_TAC SUM_SUPERSET THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+        REWRITE_TAC[FORALL_PAIR_THM] THEN
+        REWRITE_TAC[IN_ELIM_THM; IN_IMAGE; PAIR_EQ; EXISTS_PAIR_THM] THEN
+        MESON_TAC[];
+        ALL_TAC] THEN
+      REWRITE_TAC[IN_ELIM_THM; LEFT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+      MAP_EVERY X_GEN_TAC
+       [`kk:real^M->bool`; `i:real^M->bool`; `l:real^M->bool`] THEN
+      ASM_CASES_TAC `kk:real^M->bool = i INTER l` THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[IN_IMAGE; EXISTS_PAIR_THM; UNWIND_THM1] THEN
+      DISCH_THEN(CONJUNCTS_THEN2
+       (CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_TAC `x:real^M`)) MP_TAC) THEN
+      REWRITE_TAC[IN_ELIM_THM; PAIR_EQ; NOT_EXISTS_THM] THEN
+      DISCH_THEN(MP_TAC o SPECL
+       [`x:real^M`; `x:real^M`; `i:real^M->bool`; `l:real^M->bool`]) THEN
+      ASM_SIMP_TAC[INTEGRAL_EMPTY; NORM_0]] THEN
+    SUBGOAL_THEN
+     `{k INTER l | k IN d /\ l IN IMAGE SND (p:(real^M#(real^M->bool))->bool)} =
+      IMAGE (\(k,l). k INTER l) {k,l | k IN d /\ l IN IMAGE SND p}`
+    SUBST1_TAC THENL
+     [GEN_REWRITE_TAC I [EXTENSION] THEN
+      REWRITE_TAC[IN_ELIM_THM; IN_IMAGE; EXISTS_PAIR_THM; FORALL_PAIR_THM] THEN
+      REWRITE_TAC[PAIR_EQ] THEN
+      CONV_TAC(REDEPTH_CONV UNWIND_CONV) THEN MESON_TAC[];
+      ALL_TAC] THEN
+    W(MP_TAC o PART_MATCH (lhand o rand) SUM_IMAGE_NONZERO o rand o snd) THEN
+    ANTS_TAC THENL
+     [ASSUME_TAC(MATCH_MP DIVISION_OF_TAGGED_DIVISION
+        (ASSUME `p tagged_division_of interval[a:real^M,b]`)) THEN
+      ASM_SIMP_TAC[FINITE_PRODUCT; FINITE_IMAGE] THEN
+      REWRITE_TAC[FORALL_PAIR_THM; IN_ELIM_PAIR_THM] THEN
+      MAP_EVERY X_GEN_TAC
+       [`l1:real^M->bool`; `k1:real^M->bool`;
+        `l2:real^M->bool`; `k2:real^M->bool`] THEN
+      REWRITE_TAC[PAIR_EQ] THEN STRIP_TAC THEN
+      SUBGOAL_THEN `interior(l2 INTER k2:real^M->bool) = {}` MP_TAC THENL
+       [ALL_TAC;
+        MP_TAC(ASSUME `d division_of interval[a:real^M,b]`) THEN
+        REWRITE_TAC[division_of] THEN
+        DISCH_THEN(MP_TAC o SPEC `l2:real^M->bool` o el 1 o CONJUNCTS) THEN
+        ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+        MP_TAC(ASSUME
+         `(IMAGE SND (p:(real^M#(real^M->bool))->bool))
+                division_of interval[a:real^M,b]`) THEN
+        REWRITE_TAC[division_of] THEN
+        DISCH_THEN(MP_TAC o SPEC `k2:real^M->bool` o el 1 o CONJUNCTS) THEN
+        ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+        ASM_REWRITE_TAC[INTER_INTERVAL] THEN DISCH_TAC THEN
+        REWRITE_TAC[NORM_EQ_0] THEN
+        MATCH_MP_TAC INTEGRAL_NULL THEN
+        ASM_REWRITE_TAC[CONTENT_EQ_0_INTERIOR]] THEN
+      MATCH_MP_TAC(SET_RULE
+       `(interior(k1) INTER interior(k2) = {} \/
+         interior(l1) INTER interior(l2) = {}) /\
+        interior(l1 INTER k1) SUBSET interior(k1) /\
+        interior(l2 INTER k2) SUBSET interior(k2) /\
+        interior(l1 INTER k1) SUBSET interior(l1) /\
+        interior(l2 INTER k2) SUBSET interior(l2) /\
+        interior(l1 INTER k1) = interior(l2 INTER k2)
+        ==> interior(l2 INTER k2) = {}`) THEN
+      SIMP_TAC[SUBSET_INTERIOR; INTER_SUBSET] THEN ASM_REWRITE_TAC[] THEN
+      MP_TAC(ASSUME `d division_of interval[a:real^M,b]`) THEN
+      REWRITE_TAC[division_of] THEN DISCH_THEN(MP_TAC o el 2 o CONJUNCTS) THEN
+      DISCH_THEN(MP_TAC o SPECL [`l1:real^M->bool`; `l2:real^M->bool`]) THEN
+      ASM_REWRITE_TAC[] THEN
+      MP_TAC(ASSUME
+       `(IMAGE SND (p:(real^M#(real^M->bool))->bool))
+              division_of interval[a:real^M,b]`) THEN
+      REWRITE_TAC[division_of] THEN DISCH_THEN(MP_TAC o el 2 o CONJUNCTS) THEN
+      DISCH_THEN(MP_TAC o SPECL [`k1:real^M->bool`; `k2:real^M->bool`]) THEN
+      ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    DISCH_THEN SUBST1_TAC THEN
+    GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM ETA_AX] THEN
+    GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [LAMBDA_PAIR_THM] THEN
+    ASM_SIMP_TAC[GSYM SUM_SUM_PRODUCT; FINITE_IMAGE] THEN
+    MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN REWRITE_TAC[o_DEF] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC
+     `sum { k INTER l |
+             l IN IMAGE SND (p:(real^M#(real^M->bool))->bool)}
+          (\k. norm(integral k (f:real^M->real^N)))` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      W(MP_TAC o PART_MATCH (lhs o rand) SUM_IMAGE_NONZERO o lhand o snd) THEN
+      ANTS_TAC THENL [ALL_TAC; SIMP_TAC[o_DEF; REAL_LE_REFL]] THEN
+      ASM_SIMP_TAC[FINITE_IMAGE] THEN
+      MAP_EVERY X_GEN_TAC [`k1:real^M->bool`; `k2:real^M->bool`] THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      SUBGOAL_THEN `interior(k INTER k2:real^M->bool) = {}` MP_TAC THENL
+       [ALL_TAC;
+        MP_TAC(MATCH_MP DIVISION_OF_TAGGED_DIVISION
+         (ASSUME `p tagged_division_of interval[a:real^M,b]`)) THEN
+        MP_TAC(ASSUME `d division_of interval[a:real^M,b]`) THEN
+        REWRITE_TAC[division_of] THEN
+        DISCH_THEN(MP_TAC o SPEC `k:real^M->bool` o el 1 o CONJUNCTS) THEN
+        ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+        DISCH_THEN(MP_TAC o SPEC `k2:real^M->bool` o el 1 o CONJUNCTS) THEN
+        ASM_REWRITE_TAC[INTER_INTERVAL; GSYM CONTENT_EQ_0_INTERIOR] THEN
+        STRIP_TAC THEN ASM_REWRITE_TAC[INTER_INTERVAL] THEN
+        SIMP_TAC[GSYM CONTENT_EQ_0_INTERIOR; INTEGRAL_NULL; NORM_0]] THEN
+      MATCH_MP_TAC(SET_RULE
+       `interior(k INTER k2) SUBSET interior(k1 INTER k2) /\
+        interior(k1 INTER k2) = {}
+        ==> interior(k INTER k2) = {}`) THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC SUBSET_INTERIOR THEN ASM SET_TAC[]; ALL_TAC] THEN
+      MP_TAC(MATCH_MP DIVISION_OF_TAGGED_DIVISION
+         (ASSUME `p tagged_division_of interval[a:real^M,b]`)) THEN
+      REWRITE_TAC[division_of] THEN
+      DISCH_THEN(MP_TAC o el 2 o CONJUNCTS) THEN
+      REWRITE_TAC[INTERIOR_INTER] THEN DISCH_THEN MATCH_MP_TAC THEN
+      ASM_REWRITE_TAC[]] THEN
+    SUBGOAL_THEN `?u v:real^M. k = interval[u,v]`
+     (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+    THENL [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+    SUBGOAL_THEN `interval[u:real^M,v] SUBSET interval[a,b]` ASSUME_TAC THENL
+     [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+    ABBREV_TAC `d' =
+        {interval[u,v] INTER l |l|
+                l IN IMAGE SND (p:(real^M#(real^M->bool))->bool) /\
+                ~(interval[u,v] INTER l = {})}` THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC
+     `sum d' (\k. norm (integral k (f:real^M->real^N)))` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC REAL_EQ_IMP_LE THEN CONV_TAC SYM_CONV THEN
+      MATCH_MP_TAC SUM_SUPERSET THEN
+      EXPAND_TAC "d'" THEN REWRITE_TAC[SUBSET; SET_RULE
+       `a IN {f x |x| x IN s /\ ~(f x = b)} <=>
+        a IN {f x | x IN s} /\ ~(a = b)`] THEN
+      SIMP_TAC[IMP_CONJ; INTEGRAL_EMPTY; NORM_0]] THEN
+    SUBGOAL_THEN `d' division_of interval[u:real^M,v]` ASSUME_TAC THENL
+     [EXPAND_TAC "d'" THEN MATCH_MP_TAC DIVISION_INTER_1 THEN
+      EXISTS_TAC `interval[a:real^M,b]` THEN
+      ASM_SIMP_TAC[DIVISION_OF_TAGGED_DIVISION];
+      ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `norm(vsum d' (\i. integral i (f:real^M->real^N)))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_EQ_IMP_LE THEN AP_TERM_TAC THEN
+      MATCH_MP_TAC INTEGRAL_COMBINE_DIVISION_TOPDOWN THEN
+      ASM_MESON_TAC[INTEGRABLE_ON_SUBINTERVAL];
+      ALL_TAC] THEN
+    MATCH_MP_TAC VSUM_NORM_LE THEN
+    REWRITE_TAC[REAL_LE_REFL] THEN ASM_MESON_TAC[division_of];
+    ALL_TAC] THEN
+  REMOVE_THEN "p'" SUBST_ALL_TAC THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `sum {x,i INTER l | (x,l) IN p /\ i IN d}
+                  (\(x,k:real^M->bool).
+                      abs(content k) * norm((f:real^M->real^N) x))` THEN
+  CONJ_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_SUPERSET THEN
+    CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+    REWRITE_TAC[FORALL_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `i:real^M->bool`] THEN
+    ASM_CASES_TAC `i:real^M->bool = {}` THEN
+    ASM_SIMP_TAC[CONTENT_EMPTY; REAL_ABS_NUM; REAL_MUL_LZERO] THEN
+    MATCH_MP_TAC(TAUT `(a <=> b) ==> a /\ ~b ==> c`) THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+    REWRITE_TAC[PAIR_EQ] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `{x,i INTER l | x,l IN (p:(real^M#(real^M->bool))->bool) /\ i IN d} =
+    IMAGE (\((x,l),k). x,k INTER l) {m,k | m IN p /\ k IN d}`
+  SUBST1_TAC THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_IMAGE; EXISTS_PAIR_THM; FORALL_PAIR_THM] THEN
+    REWRITE_TAC[PAIR_EQ] THEN
+    CONV_TAC(REDEPTH_CONV UNWIND_CONV) THEN MESON_TAC[];
+    ALL_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) SUM_IMAGE_NONZERO o lhand o snd) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[FINITE_PRODUCT] THEN
+    REWRITE_TAC[FORALL_PAIR_THM; IN_ELIM_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC
+     [`x1:real^M`; `l1:real^M->bool`; `k1:real^M->bool`;
+      `x2:real^M`; `l2:real^M->bool`; `k2:real^M->bool`] THEN
+    REWRITE_TAC[PAIR_EQ] THEN
+    ASM_CASES_TAC `x1:real^M = x2` THEN ASM_REWRITE_TAC[] THEN
+    STRIP_TAC THEN
+    REWRITE_TAC[REAL_ENTIRE] THEN DISJ1_TAC THEN
+    REWRITE_TAC[REAL_ABS_ZERO] THEN
+    SUBGOAL_THEN `interior(k2 INTER l2:real^M->bool) = {}` MP_TAC THENL
+     [ALL_TAC;
+      FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+      DISCH_THEN(MP_TAC o SPEC `k2:real^M->bool` o el 1 o CONJUNCTS) THEN
+      ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      MP_TAC(ASSUME `p tagged_division_of interval[a:real^M,b]`) THEN
+      REWRITE_TAC[TAGGED_DIVISION_OF] THEN
+      DISCH_THEN(MP_TAC o el 1 o CONJUNCTS) THEN
+      DISCH_THEN(MP_TAC o SPECL [`x2:real^M`; `l2:real^M->bool`]) THEN
+      ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+      ASM_REWRITE_TAC[INTER_INTERVAL; CONTENT_EQ_0_INTERIOR]] THEN
+    MATCH_MP_TAC(SET_RULE
+     `(interior(k1) INTER interior(k2) = {} \/
+       interior(l1) INTER interior(l2) = {}) /\
+      interior(k1 INTER l1) SUBSET interior(k1) /\
+      interior(k2 INTER l2) SUBSET interior(k2) /\
+      interior(k1 INTER l1) SUBSET interior(l1) /\
+      interior(k2 INTER l2) SUBSET interior(l2) /\
+      interior(k1 INTER l1) = interior(k2 INTER l2)
+      ==> interior(k2 INTER l2) = {}`) THEN
+    SIMP_TAC[SUBSET_INTERIOR; INTER_SUBSET] THEN ASM_REWRITE_TAC[] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+    DISCH_THEN(MP_TAC o el 2 o CONJUNCTS) THEN
+    DISCH_THEN(MP_TAC o SPECL [`k1:real^M->bool`; `k2:real^M->bool`]) THEN
+    MP_TAC(ASSUME `p tagged_division_of interval[a:real^M,b]`) THEN
+    REWRITE_TAC[TAGGED_DIVISION_OF] THEN
+    DISCH_THEN(MP_TAC o el 2 o CONJUNCTS) THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`x2:real^M`; `l1:real^M->bool`; `x2:real^M`; `l2:real^M->bool`]) THEN
+    ASM_REWRITE_TAC[PAIR_EQ] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM ETA_AX] THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [LAMBDA_PAIR_THM] THEN
+  ASM_SIMP_TAC[GSYM SUM_SUM_PRODUCT] THEN
+  MATCH_MP_TAC SUM_EQ THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `l:real^M->bool`] THEN
+  DISCH_TAC THEN REWRITE_TAC[o_THM; SUM_RMUL] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN
+  SUBGOAL_THEN `?u v:real^M. l = interval[u,v]`
+   (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+  THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `sum d (\k. content(k INTER interval[u:real^M,v]))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_EQ THEN REWRITE_TAC[real_abs] THEN
+    X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `?w z:real^M. k = interval[w,z]`
+      (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+    THENL [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+    REWRITE_TAC[INTER_INTERVAL; CONTENT_POS_LE];
+    ALL_TAC] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `sum {k INTER interval[u:real^M,v] | k IN d} content` THEN
+  CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_IMAGE_NONZERO THEN
+    ASM_REWRITE_TAC[] THEN
+    MAP_EVERY X_GEN_TAC [`k1:real^M->bool`; `k2:real^M->bool`] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `interior(k2 INTER interval[u:real^M,v]) = {}` MP_TAC THENL
+     [ALL_TAC;
+      FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+      DISCH_THEN(MP_TAC o SPEC `k2:real^M->bool` o el 1 o CONJUNCTS) THEN
+      ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      ASM_REWRITE_TAC[INTER_INTERVAL; CONTENT_EQ_0_INTERIOR]] THEN
+    MATCH_MP_TAC(SET_RULE
+     `interior(k2 INTER i) SUBSET interior(k1 INTER k2) /\
+      interior(k1 INTER k2) = {}
+      ==> interior(k2 INTER i) = {}`) THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC SUBSET_INTERIOR THEN ASM SET_TAC[]; ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+    DISCH_THEN(MP_TAC o el 2 o CONJUNCTS) THEN
+    REWRITE_TAC[INTERIOR_INTER] THEN DISCH_THEN MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `interval[u:real^M,v] SUBSET interval[a,b]` ASSUME_TAC THENL
+   [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `sum {k INTER interval[u:real^M,v] |k|
+                      k IN d /\ ~(k INTER interval[u,v] = {})} content` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_SUPERSET THEN
+    REWRITE_TAC[SUBSET; SET_RULE
+     `a IN {f x |x| x IN s /\ ~(f x = b)} <=>
+      a IN {f x | x IN s} /\ ~(a = b)`] THEN
+    SIMP_TAC[IMP_CONJ; CONTENT_EMPTY];
+    ALL_TAC] THEN
+  MATCH_MP_TAC ADDITIVE_CONTENT_DIVISION THEN
+  ONCE_REWRITE_TAC[INTER_COMM] THEN MATCH_MP_TAC DIVISION_INTER_1 THEN
+  EXISTS_TAC `interval[a:real^M,b]` THEN ASM_REWRITE_TAC[]);;
+
+let BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE = prove
+ (`!f:real^M->real^N.
+        f integrable_on UNIV /\
+        (\k. integral k f) has_bounded_setvariation_on (:real^M)
+        ==> f absolutely_integrable_on UNIV`,
+  REWRITE_TAC[HAS_BOUNDED_SETVARIATION_ON_UNIV] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[absolutely_integrable_on] THEN
+  MP_TAC(ISPEC `IMAGE (\d. sum d (\k. norm(integral k (f:real^M->real^N))))
+                      {d | d division_of (UNIONS d) }`
+         SUP) THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; IMAGE_EQ_EMPTY] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+  ABBREV_TAC
+   `i = sup (IMAGE (\d. sum d (\k. norm(integral k (f:real^M->real^N))))
+                      {d | d division_of (UNIONS d) })` THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+    EXISTS_TAC `{}:(real^M->bool)->bool` THEN
+    REWRITE_TAC[UNIONS_0; DIVISION_OF_TRIVIAL];
+    ALL_TAC] THEN
+  STRIP_TAC THEN REWRITE_TAC[integrable_on] THEN EXISTS_TAC `lift i` THEN
+  REWRITE_TAC[HAS_INTEGRAL_ALT; IN_UNIV] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN
+    MP_TAC(ISPECL [`f:real^M->real^N`; `a:real^M`; `b:real^M`]
+      (REWRITE_RULE[HAS_BOUNDED_SETVARIATION_ON_INTERVAL]
+       BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE_INTERVAL)) THEN
+    ANTS_TAC THENL [ALL_TAC; SIMP_TAC[absolutely_integrable_on]] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN EXISTS_TAC `(:real^M)` THEN
+      ASM_REWRITE_TAC[SUBSET_UNIV];
+      ALL_TAC] THEN
+    EXISTS_TAC `B:real` THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[DIVISION_OF_UNION_SELF];
+    ALL_TAC] THEN
+  DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `i - e`) THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 < e ==> ~(i <= i - e)`] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; REAL_NOT_LE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `d:(real^M->bool)->bool` THEN STRIP_TAC THEN
+  SUBGOAL_THEN `bounded(UNIONS d:real^M->bool)` MP_TAC THENL
+   [ASM_MESON_TAC[ELEMENTARY_BOUNDED]; ALL_TAC] THEN
+  REWRITE_TAC[BOUNDED_POS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `K:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `K + &1` THEN ASM_SIMP_TAC[REAL_LT_ADD; REAL_LT_01] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN DISCH_TAC THEN
+  REWRITE_TAC[ABS_DROP; DROP_SUB; LIFT_DROP] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `!s1. i - e < s1 /\ s1 <= s /\ s < i + e ==> abs(s - i) < e`) THEN
+  EXISTS_TAC `sum (d:(real^M->bool)->bool) (\k. norm (integral k
+                    (f:real^M->real^N)))` THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum d
+      (\k. drop(integral k (\x. lift(norm((f:real^M->real^N) x)))))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC SUM_LE THEN
+      FIRST_ASSUM(fun t -> ASM_REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION t]) THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_LE THEN
+      ASM_REWRITE_TAC[absolutely_integrable_on] THEN
+      MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+      EXISTS_TAC `(:real^M)` THEN ASM_REWRITE_TAC[SUBSET_UNIV];
+      ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `drop(integral (UNIONS d)
+                      (\x. lift(norm((f:real^M->real^N) x))))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC(MESON[REAL_LE_REFL; LIFT_DROP]
+       `lift x = y ==> x <= drop y`) THEN
+      ASM_SIMP_TAC[LIFT_SUM; o_DEF; LIFT_DROP] THEN CONV_TAC SYM_CONV THEN
+      MATCH_MP_TAC INTEGRAL_COMBINE_DIVISION_BOTTOMUP THEN
+      FIRST_ASSUM(fun t -> ASM_REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION t]);
+      ALL_TAC] THEN
+    MATCH_MP_TAC INTEGRAL_SUBSET_DROP_LE THEN
+    ASM_REWRITE_TAC[LIFT_DROP; NORM_POS_LE] THEN
+    MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+     [MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `ball(vec 0:real^M,K + &1)` THEN
+      ASM_REWRITE_TAC[] THEN REWRITE_TAC[SUBSET; IN_BALL] THEN
+      ASM_SIMP_TAC[NORM_ARITH `norm(x) <= K ==> dist(vec 0,x) < K + &1`];
+      ALL_TAC] THEN
+    DISCH_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_SUBDIVISION THEN
+    EXISTS_TAC `interval[a:real^M,b]` THEN
+    EXISTS_TAC `d:(real^M->bool)->bool` THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`a:real^M`; `b:real^M`]) THEN
+  REWRITE_TAC[HAS_INTEGRAL_INTEGRAL; has_integral] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real^M->real^M->bool` MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "*")) THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `a:real^M`; `b:real^M`]
+                HENSTOCK_LEMMA) THEN
+  ANTS_TAC THENL
+   [MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+    EXISTS_TAC `(:real^M)` THEN ASM_REWRITE_TAC[SUBSET_UNIV];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d2:real^M->real^M->bool` MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "+")) THEN
+  SUBGOAL_THEN `?p. p tagged_division_of interval[a:real^M,b] /\
+                    d1 fine p /\ d2 fine p`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM FINE_INTER] THEN MATCH_MP_TAC FINE_DIVISION_EXISTS THEN
+    ASM_SIMP_TAC[GAUGE_INTER];
+    ALL_TAC] THEN
+  REMOVE_THEN "*" (MP_TAC o SPEC `p:(real^M#(real^M->bool)->bool)`) THEN
+  REMOVE_THEN "+" (MP_TAC o SPEC `p:(real^M#(real^M->bool)->bool)`) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[tagged_division_of]; ALL_TAC] THEN
+  REWRITE_TAC[ABS_DROP; DROP_SUB] THEN
+  REWRITE_TAC[LAMBDA_PAIR] THEN DISCH_THEN(MP_TAC o MATCH_MP lemma) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  ASM_SIMP_TAC[DROP_VSUM; o_DEF; SUM_SUB] THEN
+  REWRITE_TAC[LAMBDA_PAIR_THM; DROP_CMUL; NORM_MUL; LIFT_DROP] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `sf' = sf /\ si <= i
+    ==> abs(sf - si) < e / &2
+        ==> abs(sf' - di) < e / &2
+            ==> di < i + e`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_EQ THEN REWRITE_TAC[FORALL_PAIR_THM; real_abs] THEN
+    ASM_MESON_TAC[CONTENT_POS_LE; TAGGED_DIVISION_OF];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `sum p (\(x:real^M,k). norm(integral k f)) =
+    sum (IMAGE SND p) (\k. norm(integral k (f:real^M->real^N)))`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC SUM_OVER_TAGGED_DIVISION_LEMMA THEN
+    EXISTS_TAC `interval[a:real^M,b]` THEN ASM_REWRITE_TAC[] THEN
+    SIMP_TAC[INTEGRAL_NULL; NORM_0];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  MATCH_MP_TAC PARTIAL_DIVISION_OF_TAGGED_DIVISION THEN
+  EXISTS_TAC `interval[a:real^M,b]` THEN ASM_MESON_TAC[tagged_division_of]);;
+
+let ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION_UNIV_EQ = prove
+ (`!f:real^M->real^N.
+        f absolutely_integrable_on (:real^M) <=>
+        f integrable_on (:real^M) /\
+        (\k. integral k f) has_bounded_setvariation_on (:real^M)`,
+  GEN_TAC THEN EQ_TAC THEN
+  SIMP_TAC[ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION;
+           BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE;
+           ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE]);;
+
+let ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION_EQ = prove
+ (`!f:real^M->real^N a b.
+        f absolutely_integrable_on interval[a,b] <=>
+        f integrable_on interval[a,b] /\
+        (\k. integral k f) has_bounded_setvariation_on interval[a,b]`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  SIMP_TAC[ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION;
+           BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE_INTERVAL;
+           ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE]);;
+
+let ABSOLUTELY_INTEGRABLE_SET_VARIATION = prove
+ (`!f:real^M->real^N a b.
+        f absolutely_integrable_on interval[a,b]
+        ==> set_variation (interval[a,b]) (\k. integral k f) =
+                 drop(integral (interval[a,b]) (\x. lift(norm(f x))))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[set_variation] THEN
+  MATCH_MP_TAC REAL_SUP_UNIQUE THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; EXISTS_IN_GSPEC] THEN CONJ_TAC THENL
+   [X_GEN_TAC `d:(real^M->bool)->bool` THEN
+    DISCH_THEN(X_CHOOSE_THEN `s:real^M->bool` STRIP_ASSUME_TAC) THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `drop(integral s (\x. lift(norm((f:real^M->real^N) x))))` THEN
+    CONJ_TAC THENL
+     [MP_TAC(ISPECL [`\x. lift(norm((f:real^M->real^N) x))`;
+                     `d:(real^M->bool)->bool`; `s:real^M->bool`]
+        INTEGRAL_COMBINE_DIVISION_TOPDOWN) THEN
+      ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+       [RULE_ASSUM_TAC(REWRITE_RULE[absolutely_integrable_on]) THEN
+        ASM_REWRITE_TAC[] THEN
+        MATCH_MP_TAC INTEGRABLE_ON_SUBDIVISION THEN
+        EXISTS_TAC `interval[a:real^M,b]` THEN ASM_MESON_TAC[];
+        DISCH_THEN SUBST1_TAC] THEN
+      FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+      ASM_SIMP_TAC[DROP_VSUM] THEN MATCH_MP_TAC SUM_LE THEN
+      ASM_REWRITE_TAC[o_THM] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+      REWRITE_TAC[LIFT_DROP; REAL_LE_REFL; GSYM absolutely_integrable_on] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[division_of]) THEN
+      ASM_MESON_TAC[ABSOLUTELY_INTEGRABLE_ON_SUBINTERVAL; SUBSET_TRANS];
+      MATCH_MP_TAC INTEGRAL_SUBSET_DROP_LE THEN
+      ASM_REWRITE_TAC[LIFT_DROP; NORM_POS_LE] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[absolutely_integrable_on]) THEN
+      ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC INTEGRABLE_ON_SUBDIVISION THEN
+      EXISTS_TAC `interval[a:real^M,b]` THEN ASM_MESON_TAC[]];
+    X_GEN_TAC `B:real` THEN ONCE_REWRITE_TAC[GSYM REAL_SUB_LT] THEN
+    ABBREV_TAC `e = drop(integral (interval [a,b])
+                                  (\x. lift(norm((f:real^M->real^N) x)))) -
+                    B` THEN
+    DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE) THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2` o MATCH_MP HENSTOCK_LEMMA) THEN
+    ASM_REWRITE_TAC[REAL_HALF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d1:real^M->real^M->bool`
+     (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "F"))) THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [absolutely_integrable_on]) THEN
+    DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+    REWRITE_TAC[HAS_INTEGRAL_INTEGRAL; has_integral] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d2:real^M->real^M->bool`
+     (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "A"))) THEN
+    MP_TAC(ISPECL
+     [`\x. (d1:real^M->real^M->bool) x INTER d2 x`;
+      `a:real^M`; `b:real^M`]
+     FINE_DIVISION_EXISTS) THEN
+    ASM_SIMP_TAC[GAUGE_INTER; FINE_INTER] THEN
+    DISCH_THEN(X_CHOOSE_THEN `p:real^M#(real^M->bool)->bool`
+        STRIP_ASSUME_TAC) THEN
+    REMOVE_THEN "A" (MP_TAC o SPEC  `p:real^M#(real^M->bool)->bool`) THEN
+    REMOVE_THEN "F" (MP_TAC o SPEC  `p:real^M#(real^M->bool)->bool`) THEN
+    ASM_REWRITE_TAC[] THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[tagged_division_of]; ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`\x. lift(norm((f:real^M->real^N) x))`;
+      `a:real^M`; `b:real^M`; `p:real^M#(real^M->bool)->bool`]
+      INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN) THEN
+    ANTS_TAC THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[absolutely_integrable_on]) THEN
+      ASM_REWRITE_TAC[];
+      DISCH_THEN SUBST_ALL_TAC] THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN
+     `abs(sum p (\(x,k). content k * norm((f:real^M->real^N) x)) -
+          sum p (\(x,k:real^M->bool). norm(integral k f))) < e / &2`
+    MP_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+        REAL_LET_TRANS)) THEN
+      ASM_SIMP_TAC[GSYM SUM_SUB] THEN MATCH_MP_TAC SUM_ABS_LE THEN
+      ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC(NORM_ARITH
+       `x = norm u ==> abs(x - norm v) <= norm(u - v:real^N)`) THEN
+      REWRITE_TAC[NORM_MUL; real_abs] THEN
+      ASM_MESON_TAC[CONTENT_POS_LE; TAGGED_DIVISION_OF];
+      ALL_TAC] THEN
+    ONCE_REWRITE_TAC[GSYM NORM_LIFT] THEN
+    ASM_SIMP_TAC[LIFT_SUB; LIFT_SUM] THEN
+    REWRITE_TAC[LAMBDA_PAIR_THM; o_DEF; LIFT_CMUL; IMP_IMP] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (NORM_ARITH
+     `norm(x - y:real^N) < e / &2 /\ norm(x - z) < e / &2
+      ==> norm(y - z) < e`)) THEN
+    REWRITE_TAC[NORM_1; DROP_SUB] THEN
+    DISCH_THEN(MP_TAC o SPEC `B:real` o MATCH_MP
+     (REAL_ARITH `!B. abs(x - y) < e ==> y - B = e ==> &0 < x - B`)) THEN
+    ASM_REWRITE_TAC[] THEN ASM_SIMP_TAC[DROP_VSUM; REAL_SUB_LT] THEN
+    REWRITE_TAC[o_DEF; LAMBDA_PAIR_THM; LIFT_DROP] THEN DISCH_TAC THEN
+    EXISTS_TAC `IMAGE SND (p:real^M#(real^M->bool)->bool)` THEN CONJ_TAC THENL
+     [EXISTS_TAC `interval[a:real^M,b]` THEN
+      ASM_SIMP_TAC[DIVISION_OF_TAGGED_DIVISION; SUBSET_REFL];
+      FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        SUM_OVER_TAGGED_DIVISION_LEMMA)) THEN
+      DISCH_THEN(fun th ->
+       W(MP_TAC o PART_MATCH (rand o rand) th o rand o snd)) THEN
+      SIMP_TAC[INTEGRAL_NULL; NORM_0] THEN
+      DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[]]]);;
+
+let ABSOLUTELY_INTEGRABLE_RESTRICT_UNIV = prove
+ (`!f s. (\x. if x IN s then f x else vec 0)
+              absolutely_integrable_on (:real^M) <=>
+         f absolutely_integrable_on s`,
+  REWRITE_TAC[absolutely_integrable_on; INTEGRABLE_RESTRICT_UNIV;
+              COND_RAND; NORM_0; LIFT_NUM]);;
+
+let ABSOLUTELY_INTEGRABLE_CONST = prove
+ (`!a b c. (\x. c) absolutely_integrable_on interval[a,b]`,
+  REWRITE_TAC[absolutely_integrable_on; INTEGRABLE_CONST]);;
+
+let ABSOLUTELY_INTEGRABLE_ADD = prove
+ (`!f:real^M->real^N g s.
+        f absolutely_integrable_on s /\
+        g absolutely_integrable_on s
+        ==> (\x. f(x) + g(x)) absolutely_integrable_on s`,
+  SUBGOAL_THEN
+   `!f:real^M->real^N g.
+        f absolutely_integrable_on (:real^M) /\
+        g absolutely_integrable_on (:real^M)
+        ==> (\x. f(x) + g(x)) absolutely_integrable_on (:real^M)`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[GSYM ABSOLUTELY_INTEGRABLE_RESTRICT_UNIV] THEN
+    REPEAT GEN_TAC THEN DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN
+    REWRITE_TAC[] THEN MATCH_MP_TAC EQ_IMP THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN
+    GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[VECTOR_ADD_LID]] THEN
+  REPEAT STRIP_TAC THEN
+  EVERY_ASSUM(STRIP_ASSUME_TAC o
+   GEN_REWRITE_RULE I [absolutely_integrable_on]) THEN
+  MATCH_MP_TAC BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE THEN
+  ASM_SIMP_TAC[INTEGRABLE_ADD] THEN
+  MP_TAC(ISPECL [`g:real^M->real^N`; `(:real^M)`]
+     ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION) THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `(:real^M)`]
+     ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION) THEN
+  ASM_REWRITE_TAC[HAS_BOUNDED_SETVARIATION_ON_UNIV] THEN
+  DISCH_THEN(X_CHOOSE_TAC `B1:real`) THEN
+  DISCH_THEN(X_CHOOSE_TAC `B2:real`) THEN EXISTS_TAC `B1 + B2:real` THEN
+  X_GEN_TAC `d:(real^M->bool)->bool` THEN DISCH_TAC THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `d:(real^M->bool)->bool`)) THEN
+  ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+   `a <= B1 ==> x <= a + B2 ==> x <= B1 + B2`)) THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+   `b <= B2 ==> x <= a + b ==> x <= a + B2`)) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  ASM_SIMP_TAC[GSYM SUM_ADD] THEN MATCH_MP_TAC SUM_LE THEN
+  FIRST_ASSUM(fun t -> ASM_REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION t]) THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN STRIP_TAC THEN
+  MATCH_MP_TAC(NORM_ARITH `x = y + z ==> norm(x) <= norm(y) + norm(z)`) THEN
+  MATCH_MP_TAC INTEGRAL_ADD THEN CONJ_TAC THEN
+  MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+  EXISTS_TAC `(:real^M)` THEN ASM_REWRITE_TAC[SUBSET_UNIV]);;
+
+let ABSOLUTELY_INTEGRABLE_SUB = prove
+ (`!f:real^M->real^N g s.
+        f absolutely_integrable_on s /\
+        g absolutely_integrable_on s
+        ==> (\x. f(x) - g(x)) absolutely_integrable_on s`,
+  REWRITE_TAC[VECTOR_SUB] THEN
+  SIMP_TAC[ABSOLUTELY_INTEGRABLE_ADD; ABSOLUTELY_INTEGRABLE_NEG]);;
+
+let ABSOLUTELY_INTEGRABLE_LINEAR = prove
+ (`!f:real^M->real^N h:real^N->real^P s.
+        f absolutely_integrable_on s /\ linear h
+        ==> (h o f) absolutely_integrable_on s`,
+  SUBGOAL_THEN
+   `!f:real^M->real^N h:real^N->real^P.
+        f absolutely_integrable_on (:real^M) /\ linear h
+        ==> (h o f) absolutely_integrable_on (:real^M)`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[GSYM ABSOLUTELY_INTEGRABLE_RESTRICT_UNIV] THEN
+    REPEAT GEN_TAC THEN DISCH_THEN(fun th ->
+     ANTE_RES_THEN MP_TAC th THEN
+     ASSUME_TAC(MATCH_MP LINEAR_0 (CONJUNCT2 th))) THEN
+    ASM_REWRITE_TAC[o_DEF; COND_RAND]] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE THEN
+  FIRST_ASSUM(MP_TAC o
+    MATCH_MP ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[absolutely_integrable_on]) THEN
+  ASM_SIMP_TAC[INTEGRABLE_LINEAR; HAS_BOUNDED_SETVARIATION_ON_UNIV] THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC o MATCH_MP
+              LINEAR_BOUNDED_POS) THEN
+  DISCH_THEN(X_CHOOSE_TAC `b:real`) THEN EXISTS_TAC `B * b:real` THEN
+  X_GEN_TAC `d:(real^M->bool)->bool` THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `B * sum d (\k. norm(integral k (f:real^M->real^N)))` THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL_EQ] THEN REWRITE_TAC[GSYM SUM_LMUL] THEN
+  MATCH_MP_TAC SUM_LE THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  FIRST_ASSUM(fun t -> ASM_REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION t]) THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `norm(h(integral (interval[a,b]) (f:real^M->real^N)):real^P)` THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_EQ_IMP_LE THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC INTEGRAL_UNIQUE THEN MATCH_MP_TAC HAS_INTEGRAL_LINEAR THEN
+  ASM_REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL] THEN
+  MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+  EXISTS_TAC `(:real^M)` THEN ASM_REWRITE_TAC[SUBSET_UNIV]);;
+
+let ABSOLUTELY_INTEGRABLE_VSUM = prove
+ (`!f:A->real^M->real^N s t.
+        FINITE t /\
+        (!a. a IN t ==> (f a) absolutely_integrable_on s)
+        ==>  (\x. vsum t (\a. f a x)) absolutely_integrable_on s`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; ABSOLUTELY_INTEGRABLE_0; IN_INSERT;
+           ABSOLUTELY_INTEGRABLE_ADD; ETA_AX]);;
+
+let ABSOLUTELY_INTEGRABLE_ABS = prove
+ (`!f:real^M->real^N s.
+        f absolutely_integrable_on s
+        ==> (\x. (lambda i. abs(f(x)$i)):real^N) absolutely_integrable_on s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `(\x. (lambda i. abs(f(x)$i))):real^M->real^N =
+    (\x. vsum (1..dimindex(:N))
+        (\i. (((\y. (lambda j. if j = i then drop y else &0)) o
+               (\x. lift(norm((lambda j. if j = i then x$i else &0):real^N))) o
+               (f:real^M->real^N)) x)))`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `x:real^M` THEN
+    GEN_REWRITE_TAC I [CART_EQ] THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; VSUM_COMPONENT; o_THM] THEN
+    GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
+    ASM_SIMP_TAC[SUM_DELTA; IN_NUMSEG; LIFT_DROP] THEN
+    GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
+    REWRITE_TAC[vector_norm; dot] THEN MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `sqrt(sum (1..dimindex(:N))
+                         (\k. if k = i then ((f:real^M->real^N) x)$i pow 2
+                              else &0))` THEN
+    CONJ_TAC THENL
+     [ASM_REWRITE_TAC[SUM_DELTA; IN_NUMSEG; POW_2_SQRT_ABS]; ALL_TAC] THEN
+    AP_TERM_TAC THEN MATCH_MP_TAC SUM_EQ THEN
+    SIMP_TAC[IN_NUMSEG; LAMBDA_BETA] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_POW_2];
+    ALL_TAC] THEN
+  MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_VSUM THEN
+  REWRITE_TAC[IN_NUMSEG; FINITE_NUMSEG] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[ETA_AX] THEN
+  MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_LINEAR THEN CONJ_TAC THENL
+   [ALL_TAC;
+    SIMP_TAC[linear; CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+             LAMBDA_BETA] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[DROP_ADD; REAL_ADD_LID; DROP_CMUL; REAL_MUL_RZERO]] THEN
+  REWRITE_TAC[o_DEF] THEN MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_NORM THEN
+  SUBGOAL_THEN
+    `(\x. lambda j. if j = i then (f x:real^N)$i else &0):real^M->real^N =
+     (\x. lambda j. if j = i then x$i else &0) o f`
+  SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+  MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_LINEAR THEN ASM_REWRITE_TAC[] THEN
+  SIMP_TAC[linear; CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+             LAMBDA_BETA] THEN
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[REAL_MUL_RZERO; REAL_ADD_LID] THEN
+  FIRST_X_ASSUM SUBST_ALL_TAC THEN
+  ASM_SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT]);;
+
+let ABSOLUTELY_INTEGRABLE_MAX = prove
+ (`!f:real^M->real^N g:real^M->real^N s.
+        f absolutely_integrable_on s /\ g absolutely_integrable_on s
+        ==> (\x. (lambda i. max (f(x)$i) (g(x)$i)):real^N)
+            absolutely_integrable_on s`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ABSOLUTELY_INTEGRABLE_SUB) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP ABSOLUTELY_INTEGRABLE_ABS) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ABSOLUTELY_INTEGRABLE_ADD) THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP ABSOLUTELY_INTEGRABLE_ADD) THEN
+  DISCH_THEN(MP_TAC o SPEC `inv(&2)` o
+     MATCH_MP ABSOLUTELY_INTEGRABLE_CMUL) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; CART_EQ] THEN
+  SIMP_TAC[LAMBDA_BETA; VECTOR_MUL_COMPONENT; VECTOR_SUB_COMPONENT;
+           VECTOR_ADD_COMPONENT] THEN
+  REPEAT STRIP_TAC THEN REAL_ARITH_TAC);;
+
+let ABSOLUTELY_INTEGRABLE_MAX_1 = prove
+ (`!f:real^M->real g:real^M->real s.
+        (\x. lift(f x)) absolutely_integrable_on s /\
+        (\x. lift(g x)) absolutely_integrable_on s
+        ==> (\x. lift(max (f x) (g x))) absolutely_integrable_on s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(\x. (lambda i. max (lift(f x)$i) (lift(g x)$i)):real^1)
+                absolutely_integrable_on (s:real^M->bool)`
+  MP_TAC THENL [ASM_SIMP_TAC[ABSOLUTELY_INTEGRABLE_MAX]; ALL_TAC] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; CART_EQ] THEN SIMP_TAC[LAMBDA_BETA; lift]);;
+
+let ABSOLUTELY_INTEGRABLE_MIN = prove
+ (`!f:real^M->real^N g:real^M->real^N s.
+        f absolutely_integrable_on s /\ g absolutely_integrable_on s
+        ==> (\x. (lambda i. min (f(x)$i) (g(x)$i)):real^N)
+            absolutely_integrable_on s`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ABSOLUTELY_INTEGRABLE_SUB) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP ABSOLUTELY_INTEGRABLE_ABS) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ABSOLUTELY_INTEGRABLE_ADD) THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP ABSOLUTELY_INTEGRABLE_SUB) THEN
+  DISCH_THEN(MP_TAC o SPEC `inv(&2)` o
+     MATCH_MP ABSOLUTELY_INTEGRABLE_CMUL) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; CART_EQ] THEN
+  SIMP_TAC[LAMBDA_BETA; VECTOR_MUL_COMPONENT; VECTOR_SUB_COMPONENT;
+           VECTOR_ADD_COMPONENT] THEN
+  REPEAT STRIP_TAC THEN REAL_ARITH_TAC);;
+
+let ABSOLUTELY_INTEGRABLE_MIN_1 = prove
+ (`!f:real^M->real g:real^M->real s.
+        (\x. lift(f x)) absolutely_integrable_on s /\
+        (\x. lift(g x)) absolutely_integrable_on s
+        ==> (\x. lift(min (f x) (g x))) absolutely_integrable_on s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(\x. (lambda i. min (lift(f x)$i) (lift(g x)$i)):real^1)
+                absolutely_integrable_on (s:real^M->bool)`
+  MP_TAC THENL [ASM_SIMP_TAC[ABSOLUTELY_INTEGRABLE_MIN]; ALL_TAC] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; CART_EQ] THEN SIMP_TAC[LAMBDA_BETA; lift]);;
+
+let ABSOLUTELY_INTEGRABLE_ABS_EQ = prove
+ (`!f:real^M->real^N s.
+        f absolutely_integrable_on s <=>
+          f integrable_on s /\
+          (\x. (lambda i. abs(f(x)$i)):real^N) integrable_on s`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  SIMP_TAC[ABSOLUTELY_INTEGRABLE_ABS;
+           ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE] THEN
+  SUBGOAL_THEN
+   `!f:real^M->real^N.
+        f integrable_on (:real^M) /\
+        (\x. (lambda i. abs(f(x)$i)):real^N) integrable_on (:real^M)
+        ==> f absolutely_integrable_on (:real^M)`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[GSYM ABSOLUTELY_INTEGRABLE_RESTRICT_UNIV;
+                     GSYM INTEGRABLE_RESTRICT_UNIV] THEN
+    DISCH_THEN(fun th -> FIRST_X_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+    MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN MATCH_MP_TAC EQ_IMP THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN
+    REWRITE_TAC[CART_EQ] THEN REPEAT STRIP_TAC THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; COND_COMPONENT; VEC_COMPONENT] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_ABS_0]] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE THEN
+  ASM_REWRITE_TAC[HAS_BOUNDED_SETVARIATION_ON_UNIV] THEN
+  EXISTS_TAC
+   `sum (1..dimindex(:N))
+        (\i. integral (:real^M)
+              (\x. (lambda j. abs ((f:real^M->real^N) x$j)):real^N)$i)` THEN
+  X_GEN_TAC `d:(real^M->bool)->bool` THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum d (\k. sum (1..dimindex(:N))
+      (\i. integral k
+              (\x. (lambda j. abs ((f:real^M->real^N) x$j)):real^N)$i))` THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_LE THEN
+    FIRST_ASSUM(fun t -> ASM_REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION t]) THEN
+    MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN DISCH_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum (1..dimindex(:N))
+             (\i. abs((integral (interval[a,b]) (f:real^M->real^N))$i))` THEN
+    REWRITE_TAC[NORM_LE_L1] THEN MATCH_MP_TAC SUM_LE_NUMSEG THEN
+    X_GEN_TAC `k:num` THEN STRIP_TAC THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= y /\ --x <= y ==> abs(x) <= y`) THEN
+    ASM_SIMP_TAC[GSYM VECTOR_NEG_COMPONENT] THEN
+    SUBGOAL_THEN `(f:real^M->real^N) integrable_on interval[a,b] /\
+        (\x. (lambda i. abs (f x$i)):real^N) integrable_on interval[a,b]`
+    STRIP_ASSUME_TAC THENL
+     [CONJ_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+      EXISTS_TAC `(:real^M)` THEN ASM_REWRITE_TAC[SUBSET_UNIV];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[GSYM INTEGRAL_NEG] THEN
+    CONJ_TAC THEN MATCH_MP_TAC INTEGRAL_COMPONENT_LE THEN
+    ASM_SIMP_TAC[INTEGRABLE_NEG; LAMBDA_BETA] THEN
+    ASM_SIMP_TAC[VECTOR_NEG_COMPONENT] THEN
+    REPEAT STRIP_TAC THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) SUM_SWAP o lhand o snd) THEN
+  ASM_REWRITE_TAC[FINITE_NUMSEG] THEN DISCH_THEN SUBST_ALL_TAC THEN
+  MATCH_MP_TAC SUM_LE_NUMSEG THEN X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+  REWRITE_TAC[] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC
+   `(integral (UNIONS d)
+              (\x. (lambda j. abs ((f:real^M->real^N) x$j)):real^N))$k` THEN
+  CONJ_TAC THENL
+   [ASM_SIMP_TAC[GSYM VSUM_COMPONENT] THEN
+    MATCH_MP_TAC REAL_EQ_IMP_LE THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC INTEGRAL_COMBINE_DIVISION_TOPDOWN THEN
+    ASM_REWRITE_TAC[];
+    MATCH_MP_TAC INTEGRAL_SUBSET_COMPONENT_LE THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; SUBSET_UNIV; REAL_ABS_POS]] THEN
+  MATCH_MP_TAC INTEGRABLE_ON_SUBDIVISION THEN
+  MAP_EVERY EXISTS_TAC [`(:real^M)`; `d:(real^M->bool)->bool`] THEN
+  ASM_REWRITE_TAC[SUBSET_UNIV]);;
+
+let NONNEGATIVE_ABSOLUTELY_INTEGRABLE = prove
+ (`!f:real^M->real^N s.
+        (!x i. x IN s /\ 1 <= i /\ i <= dimindex(:N)
+               ==> &0 <= f(x)$i) /\
+        f integrable_on s
+        ==> f absolutely_integrable_on s`,
+  SIMP_TAC[ABSOLUTELY_INTEGRABLE_ABS_EQ] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_EQ THEN
+  EXISTS_TAC `f:real^M->real^N` THEN
+  ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA; real_abs]);;
+
+let ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND = prove
+ (`!f:real^M->real^N g s.
+        (!x. x IN s ==> norm(f x) <= drop(g x)) /\
+        f integrable_on s /\ g integrable_on s
+        ==> f absolutely_integrable_on s`,
+  SUBGOAL_THEN
+   `!f:real^M->real^N g.
+        (!x. norm(f x) <= drop(g x)) /\
+        f integrable_on (:real^M) /\ g integrable_on (:real^M)
+        ==> f absolutely_integrable_on (:real^M)`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[GSYM INTEGRABLE_RESTRICT_UNIV; GSYM
+                     ABSOLUTELY_INTEGRABLE_RESTRICT_UNIV] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    EXISTS_TAC `(\x. if x IN s then g x else vec 0):real^M->real^1` THEN
+    ASM_REWRITE_TAC[] THEN GEN_TAC THEN COND_CASES_TAC THEN
+    ASM_SIMP_TAC[REAL_LE_REFL; NORM_0; DROP_VEC]] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE THEN
+  ASM_REWRITE_TAC[HAS_BOUNDED_SETVARIATION_ON_UNIV] THEN
+  EXISTS_TAC `drop(integral(:real^M) g)` THEN
+  X_GEN_TAC `d:(real^M->bool)->bool` THEN DISCH_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum d (\k. drop(integral k (g:real^M->real^1)))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[] THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+    REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN ASM_REWRITE_TAC[] THEN
+    CONJ_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+    EXISTS_TAC `(:real^M)` THEN ASM_REWRITE_TAC[SUBSET_UNIV];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `drop(integral (UNIONS d:real^M->bool) g)` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC(REAL_ARITH `x = y ==> y <= x`) THEN
+    ASM_SIMP_TAC[GSYM LIFT_EQ; LIFT_DROP; LIFT_SUM; o_DEF] THEN
+    MATCH_MP_TAC INTEGRAL_COMBINE_DIVISION_BOTTOMUP THEN
+    FIRST_ASSUM(fun th -> ASM_REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+    EXISTS_TAC `(:real^M)` THEN ASM_REWRITE_TAC[SUBSET_UNIV];
+    MATCH_MP_TAC INTEGRAL_SUBSET_DROP_LE THEN
+    ASM_REWRITE_TAC[SUBSET_UNIV; IN_UNIV] THEN CONJ_TAC THENL
+     [ALL_TAC; ASM_MESON_TAC[NORM_ARITH `norm(x) <= y ==> &0 <= y`]] THEN
+    MATCH_MP_TAC INTEGRABLE_ON_SUBDIVISION THEN
+    MAP_EVERY EXISTS_TAC [`(:real^M)`; `d:(real^M->bool)->bool`] THEN
+    ASM_REWRITE_TAC[SUBSET_UNIV]]);;
+
+let ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_BOUND = prove
+ (`!f:real^M->real^N g:real^M->real^P s.
+        (!x. x IN s ==> norm(f x) <= norm(g x)) /\
+        f integrable_on s /\ g absolutely_integrable_on s
+        ==> f absolutely_integrable_on s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I
+    [absolutely_integrable_on]) THEN
+  MP_TAC(ISPECL
+   [`f:real^M->real^N`; `(\x. lift(norm((g:real^M->real^P) x)))`;
+    `s:real^M->bool`] ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND) THEN
+  ASM_REWRITE_TAC[LIFT_DROP]);;
+
+let ABSOLUTELY_INTEGRABLE_INF_1 = prove
+ (`!fs s:real^N->bool k:A->bool.
+        FINITE k /\ ~(k = {}) /\
+        (!i. i IN k ==> (\x. lift(fs x i)) absolutely_integrable_on s)
+        ==> (\x. lift(inf (IMAGE (fs x) k))) absolutely_integrable_on s`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[IMAGE_CLAUSES] THEN
+  SIMP_TAC[INF_INSERT_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+  MAP_EVERY X_GEN_TAC [`a:A`; `k:A->bool`] THEN
+  ASM_CASES_TAC `k:A->bool = {}` THEN ASM_REWRITE_TAC[] THEN
+  SIMP_TAC[IN_SING; LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_MIN_1 THEN
+  CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INSERT] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[IN_INSERT]);;
+
+let ABSOLUTELY_INTEGRABLE_SUP_1 = prove
+ (`!fs s:real^N->bool k:A->bool.
+        FINITE k /\ ~(k = {}) /\
+        (!i. i IN k ==> (\x. lift(fs x i)) absolutely_integrable_on s)
+        ==> (\x. lift(sup (IMAGE (fs x) k))) absolutely_integrable_on s`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[IMAGE_CLAUSES] THEN
+  SIMP_TAC[SUP_INSERT_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+  MAP_EVERY X_GEN_TAC [`a:A`; `k:A->bool`] THEN
+  ASM_CASES_TAC `k:A->bool = {}` THEN ASM_REWRITE_TAC[] THEN
+  SIMP_TAC[IN_SING; LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_MAX_1 THEN
+  CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INSERT] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[IN_INSERT]);;
+
+let ABSOLUTELY_INTEGRABLE_CONTINUOUS = prove
+ (`!f:real^M->real^N a b.
+        f continuous_on interval[a,b]
+        ==> f absolutely_integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND THEN
+  SUBGOAL_THEN `compact(IMAGE (f:real^M->real^N) (interval[a,b]))` MP_TAC THENL
+   [ASM_SIMP_TAC[COMPACT_CONTINUOUS_IMAGE; COMPACT_INTERVAL]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP COMPACT_IMP_BOUNDED) THEN
+  REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\x:real^M. lift(B)` THEN
+  ASM_SIMP_TAC[INTEGRABLE_CONST; LIFT_DROP; INTEGRABLE_CONTINUOUS]);;
+
+let INTEGRABLE_MIN_CONST_1 = prove
+ (`!f s t.
+        &0 <= t /\ (!x. x IN s ==> &0 <= f x) /\
+        (\x:real^N. lift(f x)) integrable_on s
+        ==> (\x. lift(min (f x) t)) integrable_on s`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC INTEGRABLE_ON_ALL_INTERVALS_INTEGRABLE_BOUND THEN
+  EXISTS_TAC `\x:real^N. lift(f x)` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [REPEAT GEN_TAC THEN
+    MP_TAC(ISPECL
+     [`\x:real^N. if x IN s then f x else &0`;
+      `(\x. t):real^N->real`;
+      `interval[a:real^N,b]`] ABSOLUTELY_INTEGRABLE_MIN_1) THEN
+    REWRITE_TAC[] THEN ANTS_TAC THENL
+     [SIMP_TAC[ABSOLUTELY_INTEGRABLE_CONTINUOUS; CONTINUOUS_ON_CONST] THEN
+      MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_ON_SUBINTERVAL THEN
+      EXISTS_TAC `(:real^N)` THEN REWRITE_TAC[SUBSET_UNIV] THEN
+      REWRITE_TAC[COND_RAND; LIFT_DROP; LIFT_NUM] THEN
+      REWRITE_TAC[ABSOLUTELY_INTEGRABLE_RESTRICT_UNIV] THEN
+      MATCH_MP_TAC NONNEGATIVE_ABSOLUTELY_INTEGRABLE THEN
+      ASM_SIMP_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+      ASM_REWRITE_TAC[IMP_IMP; DIMINDEX_1; FORALL_1; LIFT_DROP; GSYM drop];
+      DISCH_THEN(MP_TAC o MATCH_MP ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE) THEN
+      MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+      REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      REWRITE_TAC[GSYM DROP_EQ; DROP_VEC; LIFT_DROP] THEN ASM_REAL_ARITH_TAC];
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN
+    ASM_REWRITE_TAC[NORM_REAL; GSYM drop; LIFT_DROP] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_UBOUND = prove
+ (`!f:real^M->real^N g:real^M->real^N s.
+        (!x i. x IN s /\ 1 <= i /\ i <= dimindex(:N) ==> f(x)$i <= g(x)$i) /\
+        f integrable_on s /\ g absolutely_integrable_on s
+        ==> f absolutely_integrable_on s`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+   `(\x. (g:real^M->real^N)(x) - (g(x) - f(x))) absolutely_integrable_on s`
+  MP_TAC THENL
+   [MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_SUB THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC NONNEGATIVE_ABSOLUTELY_INTEGRABLE THEN
+    ASM_REWRITE_TAC[REAL_SUB_LE; VECTOR_SUB_COMPONENT] THEN
+    MATCH_MP_TAC INTEGRABLE_SUB THEN
+    ASM_SIMP_TAC[ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE];
+    REWRITE_TAC[VECTOR_ARITH `x - (x - y):real^N = y`; ETA_AX]]);;
+
+let ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_LBOUND = prove
+ (`!f:real^M->real^N g:real^M->real^N s.
+        (!x i. x IN s /\ 1 <= i /\ i <= dimindex(:N) ==> f(x)$i <= g(x)$i) /\
+        f absolutely_integrable_on s /\ g integrable_on s
+        ==> g absolutely_integrable_on s`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+   `(\x. (f:real^M->real^N)(x) + (g(x) - f(x))) absolutely_integrable_on s`
+  MP_TAC THENL
+   [MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_ADD THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC NONNEGATIVE_ABSOLUTELY_INTEGRABLE THEN
+    ASM_REWRITE_TAC[REAL_SUB_LE; VECTOR_SUB_COMPONENT] THEN
+    MATCH_MP_TAC INTEGRABLE_SUB THEN
+    ASM_SIMP_TAC[ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE];
+    REWRITE_TAC[VECTOR_ARITH `y + (x - y):real^N = x`; ETA_AX]]);;
+
+let ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_DROP_UBOUND = prove
+ (`!f:real^M->real^1 g:real^M->real^1 s.
+        (!x. x IN s ==> drop(f(x)) <= drop(g(x))) /\
+        f integrable_on s /\ g absolutely_integrable_on s
+        ==> f absolutely_integrable_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC
+    ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_UBOUND THEN
+  EXISTS_TAC `g:real^M->real^1` THEN
+  ASM_REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_REWRITE_TAC[IMP_IMP; FORALL_1; DIMINDEX_1; GSYM drop]);;
+
+let ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_DROP_LBOUND = prove
+ (`!f:real^M->real^1 g:real^M->real^1 s.
+        (!x. x IN s ==> drop(f(x)) <= drop(g(x))) /\
+        f absolutely_integrable_on s /\ g integrable_on s
+        ==> g absolutely_integrable_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC
+    ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_LBOUND THEN
+  EXISTS_TAC `f:real^M->real^1` THEN
+  ASM_REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_REWRITE_TAC[IMP_IMP; FORALL_1; DIMINDEX_1; GSYM drop]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relating vector integrals to integrals of components.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_INTEGRAL_COMPONENTWISE = prove
+ (`!f:real^M->real^N s y.
+        (f has_integral y) s <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> ((\x. lift((f x)$i)) has_integral (lift(y$i))) s`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o ISPEC `\u:real^N. lift(u$i)` o
+        MATCH_MP (REWRITE_RULE[IMP_CONJ] HAS_INTEGRAL_LINEAR)) THEN
+    REWRITE_TAC[o_DEF] THEN DISCH_THEN MATCH_MP_TAC THEN
+    REWRITE_TAC[LINEAR_LIFT_COMPONENT];
+    GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM BASIS_EXPANSION] THEN
+    GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV o BINDER_CONV)
+     [GSYM BASIS_EXPANSION] THEN
+    MATCH_MP_TAC HAS_INTEGRAL_VSUM THEN
+    REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o ISPEC `\v. drop(v) % (basis i:real^N)` o
+        MATCH_MP (REWRITE_RULE[IMP_CONJ] HAS_INTEGRAL_LINEAR)) THEN
+    SIMP_TAC[o_DEF; LIFT_DROP; LINEAR_VMUL_DROP; LINEAR_ID]]);;
+
+let INTEGRABLE_COMPONENTWISE = prove
+ (`!f:real^M->real^N s.
+        f integrable_on s <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> (\x. lift((f x)$i)) integrable_on s`,
+   REPEAT GEN_TAC THEN REWRITE_TAC[integrable_on] THEN
+   GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+    [HAS_INTEGRAL_COMPONENTWISE] THEN
+   REWRITE_TAC[GSYM LAMBDA_SKOLEM; GSYM EXISTS_LIFT]);;
+
+let LIFT_INTEGRAL_COMPONENT = prove
+ (`!f:real^M->real^N.
+        f integrable_on s
+        ==> lift((integral s f)$k) = integral s (\x. lift((f x)$k))`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?j. 1 <= j /\ j <= dimindex(:N) /\ !z:real^N. z$k = z$j`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP INTEGRABLE_INTEGRAL) THEN
+  GEN_REWRITE_TAC LAND_CONV [HAS_INTEGRAL_COMPONENTWISE] THEN
+  ASM_SIMP_TAC[]);;
+
+let INTEGRAL_COMPONENT = prove
+ (`!f:real^M->real^N.
+        f integrable_on s
+        ==> (integral s f)$k = drop(integral s (\x. lift((f x)$k)))`,
+  SIMP_TAC[GSYM LIFT_INTEGRAL_COMPONENT; LIFT_DROP]);;
+
+let ABSOLUTELY_INTEGRABLE_COMPONENTWISE = prove
+ (`!f:real^M->real^N s.
+     f absolutely_integrable_on s <=>
+     (!i. 1 <= i /\ i <= dimindex(:N)
+          ==> (\x. lift(f x$i)) absolutely_integrable_on s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[absolutely_integrable_on] THEN
+  MATCH_MP_TAC(MESON[]
+   `(p <=> !i. a i ==> P i) /\
+    (p /\ (!i. a i ==> P i) ==> (q <=> (!i. a i ==> Q i)))
+    ==> (p /\ q <=> (!i. a i ==> P i /\ Q i))`) THEN
+  CONJ_TAC THENL [REWRITE_TAC[GSYM INTEGRABLE_COMPONENTWISE]; ALL_TAC] THEN
+  REPEAT(STRIP_TAC ORELSE EQ_TAC) THENL
+   [SUBGOAL_THEN
+     `(\x. lift((f:real^M->real^N) x$i)) absolutely_integrable_on s`
+    MP_TAC THENL [ALL_TAC; SIMP_TAC[absolutely_integrable_on]] THEN
+    MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND THEN
+    EXISTS_TAC `\x. lift(norm((f:real^M->real^N) x))` THEN
+    ASM_SIMP_TAC[ABS_DROP; LIFT_DROP; COMPONENT_LE_NORM];
+    SUBGOAL_THEN
+     `(f:real^M->real^N) absolutely_integrable_on s`
+    MP_TAC THENL [ALL_TAC; SIMP_TAC[absolutely_integrable_on]] THEN
+    MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND THEN
+    EXISTS_TAC
+     `\x. vsum (1..dimindex(:N))
+               (\i. lift(norm(lift((f:real^M->real^N)(x)$i))))` THEN
+    ASM_SIMP_TAC[INTEGRABLE_VSUM; IN_NUMSEG; FINITE_NUMSEG] THEN
+    SIMP_TAC[DROP_VSUM; FINITE_NUMSEG; o_DEF; LIFT_DROP] THEN
+    REWRITE_TAC[NORM_LIFT; NORM_LE_L1]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Dominated convergence.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let DOMINATED_CONVERGENCE = prove
+ (`!f:num->real^M->real^N g h s.
+        (!k. (f k) integrable_on s) /\ h integrable_on s /\
+        (!k x. x IN s ==> norm(f k x) <= drop(h x)) /\
+        (!x. x IN s ==> ((\k. f k x) --> g x) sequentially)
+        ==> g integrable_on s /\
+            ((\k. integral s (f k)) --> integral s g) sequentially`,
+  SUBGOAL_THEN
+    `!f:num->real^M->real^1 g h s.
+        (!k. (f k) integrable_on s) /\ h integrable_on s /\
+        (!k x. x IN s ==> norm(f k x) <= drop(h x)) /\
+        (!x. x IN s ==> ((\k. f k x) --> g x) sequentially)
+        ==> g integrable_on s /\
+            ((\k. integral s (f k)) --> integral s g) sequentially`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REPEAT GEN_TAC THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `!j. 1 <= j /\ j <= dimindex(:N)
+          ==> (\x. lift((g x)$j)) integrable_on s /\
+              ((\k. integral s (\x. lift (((f:num->real^M->real^N) k x)$j)))
+               --> integral s (\x. lift ((g x:real^N)$j))) sequentially`
+    STRIP_ASSUME_TAC THENL
+     [REPEAT GEN_TAC THEN STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      EXISTS_TAC `h:real^M->real^1` THEN ASM_REWRITE_TAC[] THEN
+      REPEAT CONJ_TAC THENL
+       [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE BINDER_CONV
+          [INTEGRABLE_COMPONENTWISE]) THEN
+        ASM_SIMP_TAC[];
+        MAP_EVERY X_GEN_TAC [`i:num`; `x:real^M`] THEN DISCH_TAC THEN
+        MATCH_MP_TAC REAL_LE_TRANS THEN
+        EXISTS_TAC `norm((f:num->real^M->real^N) i x)` THEN
+        ASM_SIMP_TAC[NORM_LIFT; COMPONENT_LE_NORM];
+        X_GEN_TAC `x:real^M` THEN STRIP_TAC THEN
+        FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+        GEN_REWRITE_TAC LAND_CONV [LIM_COMPONENTWISE_LIFT] THEN
+        ASM_SIMP_TAC[]];
+      MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+       [GEN_REWRITE_TAC I [INTEGRABLE_COMPONENTWISE] THEN ASM_SIMP_TAC[];
+        DISCH_TAC THEN  ONCE_REWRITE_TAC[LIM_COMPONENTWISE_LIFT] THEN
+        ASM_SIMP_TAC[LIFT_INTEGRAL_COMPONENT]]]] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(MATCH_MP MONO_FORALL (GEN `m:num`
+   (ISPECL [`\k:num x:real^M. lift(inf {drop(f j x) | j IN m..(m+k)})`;
+            `\x:real^M. lift(inf {drop(f j x) | m:num <= j})`;
+            `s:real^M->bool`]
+           MONOTONE_CONVERGENCE_DECREASING))) THEN
+  REWRITE_TAC[LIFT_DROP] THEN ANTS_TAC THENL
+   [X_GEN_TAC `m:num` THEN REPEAT CONJ_TAC THENL
+     [GEN_TAC THEN MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_INF_1 THEN
+      REWRITE_TAC[FINITE_NUMSEG; NUMSEG_EMPTY; NOT_LT; LE_ADD] THEN
+      ASM_REWRITE_TAC[LIFT_DROP; ETA_AX] THEN
+      REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND THEN
+      EXISTS_TAC `h:real^M->real^1` THEN ASM_REWRITE_TAC[];
+
+      REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      MATCH_MP_TAC REAL_LE_INF_SUBSET THEN
+      REWRITE_TAC[IMAGE_EQ_EMPTY; NUMSEG_EMPTY; NOT_LT; LE_ADD] THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC IMAGE_SUBSET THEN
+        REWRITE_TAC[SUBSET_NUMSEG] THEN ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE] THEN
+      MATCH_MP_TAC LOWER_BOUND_FINITE_SET_REAL THEN
+      REWRITE_TAC[FINITE_NUMSEG];
+
+      X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+      REWRITE_TAC[LIM_SEQUENTIALLY] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+      REWRITE_TAC[dist; ABS_DROP; LIFT_DROP; DROP_SUB] THEN
+      MP_TAC(SPEC `{drop((f:num->real^M->real^1) j x) | m <= j}` INF) THEN
+      ABBREV_TAC `i = inf {drop((f:num->real^M->real^1) j x) | m <= j}` THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; EXISTS_IN_IMAGE; IMAGE_EQ_EMPTY] THEN
+      REWRITE_TAC[IN_ELIM_THM; EXTENSION; NOT_IN_EMPTY] THEN ANTS_TAC THENL
+       [CONJ_TAC THENL [MESON_TAC[LE_REFL]; ALL_TAC] THEN
+        EXISTS_TAC `--drop(h(x:real^M))` THEN X_GEN_TAC `j:num` THEN
+        FIRST_X_ASSUM(MP_TAC o SPECL [`j:num`; `x:real^M`]) THEN
+        ASM_REWRITE_TAC[ABS_DROP] THEN REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `i + e:real`)) THEN
+      ASM_SIMP_TAC[REAL_ARITH `&0 < e ==> ~(i + e <= i)`] THEN
+      REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; REAL_NOT_LE] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `M:num` THEN STRIP_TAC THEN
+      X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+      FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+       `y < i + e ==> i <= ix /\ ix <= y ==> abs(ix - i) < e`)) THEN
+      CONJ_TAC THENL
+       [EXPAND_TAC "i" THEN MATCH_MP_TAC REAL_LE_INF_SUBSET THEN
+        REWRITE_TAC[IMAGE_EQ_EMPTY; SET_RULE `{x | x IN s} = s`] THEN
+        REWRITE_TAC[NUMSEG_EMPTY; NOT_LT; LE_ADD] THEN
+        ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN CONJ_TAC THENL
+         [MATCH_MP_TAC IMAGE_SUBSET THEN
+          REWRITE_TAC[SUBSET; IN_NUMSEG; IN_ELIM_THM] THEN ARITH_TAC;
+          REWRITE_TAC[FORALL_IN_IMAGE; IN_ELIM_THM] THEN ASM_MESON_TAC[]];
+        ALL_TAC] THEN
+      W(MP_TAC o C SPEC INF o rand o lhand o snd) THEN ANTS_TAC THENL
+       [REWRITE_TAC[IMAGE_EQ_EMPTY; SET_RULE `{x | x IN s} = s`] THEN
+        REWRITE_TAC[NUMSEG_EMPTY; NOT_LT; LE_ADD] THEN
+        REWRITE_TAC[FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+        EXISTS_TAC `i:real` THEN GEN_TAC THEN REWRITE_TAC[IN_NUMSEG] THEN
+        DISCH_THEN(fun th -> FIRST_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+        ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE] THEN
+      DISCH_THEN(MATCH_MP_TAC o CONJUNCT1) THEN
+      REWRITE_TAC[IN_ELIM_THM; IN_NUMSEG] THEN
+      ASM_ARITH_TAC;
+
+      REWRITE_TAC[bounded] THEN
+      EXISTS_TAC `drop(integral s (h:real^M->real^1))` THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; IN_UNIV] THEN
+      X_GEN_TAC `p:num` THEN MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+      ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+        ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+        MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_INF_1 THEN
+        REWRITE_TAC[FINITE_NUMSEG; NUMSEG_EMPTY; NOT_LT; LE_ADD] THEN
+        ASM_REWRITE_TAC[LIFT_DROP; ETA_AX] THEN REPEAT STRIP_TAC THEN
+        MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND THEN
+        EXISTS_TAC `h:real^M->real^1` THEN ASM_REWRITE_TAC[];
+        ALL_TAC] THEN
+      X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+      REWRITE_TAC[ABS_DROP; LIFT_DROP] THEN
+      MATCH_MP_TAC REAL_ABS_INF_LE THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; IMAGE_EQ_EMPTY] THEN
+      ASM_SIMP_TAC[NUMSEG_EMPTY; NOT_LT; LE_ADD; GSYM ABS_DROP]];
+    REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC] THEN
+  MP_TAC(MATCH_MP MONO_FORALL (GEN `m:num`
+   (ISPECL [`\k:num x:real^M. lift(sup {drop(f j x) | j IN m..(m+k)})`;
+            `\x:real^M. lift(sup {drop(f j x) | m:num <= j})`;
+            `s:real^M->bool`]
+           MONOTONE_CONVERGENCE_INCREASING))) THEN
+  REWRITE_TAC[LIFT_DROP] THEN ANTS_TAC THENL
+   [X_GEN_TAC `m:num` THEN REPEAT CONJ_TAC THENL
+     [GEN_TAC THEN MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_SUP_1 THEN
+      REWRITE_TAC[FINITE_NUMSEG; NUMSEG_EMPTY; NOT_LT; LE_ADD] THEN
+      ASM_REWRITE_TAC[LIFT_DROP; ETA_AX] THEN
+      REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND THEN
+      EXISTS_TAC `h:real^M->real^1` THEN ASM_REWRITE_TAC[];
+
+      REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      MATCH_MP_TAC REAL_SUP_LE_SUBSET THEN
+      REWRITE_TAC[IMAGE_EQ_EMPTY; NUMSEG_EMPTY; NOT_LT; LE_ADD] THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC IMAGE_SUBSET THEN
+        REWRITE_TAC[SUBSET_NUMSEG] THEN ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE] THEN
+      MATCH_MP_TAC UPPER_BOUND_FINITE_SET_REAL THEN
+      REWRITE_TAC[FINITE_NUMSEG];
+
+      X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+      REWRITE_TAC[LIM_SEQUENTIALLY] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+      REWRITE_TAC[dist; ABS_DROP; LIFT_DROP; DROP_SUB] THEN
+      MP_TAC(SPEC `{drop((f:num->real^M->real^1) j x) | m <= j}` SUP) THEN
+      ABBREV_TAC `i = sup {drop((f:num->real^M->real^1) j x) | m <= j}` THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; EXISTS_IN_IMAGE; IMAGE_EQ_EMPTY] THEN
+      REWRITE_TAC[IN_ELIM_THM; EXTENSION; NOT_IN_EMPTY] THEN ANTS_TAC THENL
+       [CONJ_TAC THENL [MESON_TAC[LE_REFL]; ALL_TAC] THEN
+        EXISTS_TAC `drop(h(x:real^M))` THEN X_GEN_TAC `j:num` THEN
+        FIRST_X_ASSUM(MP_TAC o SPECL [`j:num`; `x:real^M`]) THEN
+        ASM_REWRITE_TAC[ABS_DROP] THEN REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `i - e:real`)) THEN
+      ASM_SIMP_TAC[REAL_ARITH `&0 < e ==> ~(i <= i - e)`] THEN
+      REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; REAL_NOT_LE] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `M:num` THEN STRIP_TAC THEN
+      X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+      FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+       `i - e < y ==> ix <= i /\ y <= ix ==> abs(ix - i) < e`)) THEN
+      CONJ_TAC THENL
+       [EXPAND_TAC "i" THEN MATCH_MP_TAC REAL_SUP_LE_SUBSET THEN
+        REWRITE_TAC[IMAGE_EQ_EMPTY; SET_RULE `{x | x IN s} = s`] THEN
+        REWRITE_TAC[NUMSEG_EMPTY; NOT_LT; LE_ADD] THEN
+        ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN CONJ_TAC THENL
+         [MATCH_MP_TAC IMAGE_SUBSET THEN
+          REWRITE_TAC[SUBSET; IN_NUMSEG; IN_ELIM_THM] THEN ARITH_TAC;
+          REWRITE_TAC[FORALL_IN_IMAGE; IN_ELIM_THM] THEN ASM_MESON_TAC[]];
+        ALL_TAC] THEN
+      W(MP_TAC o C SPEC SUP o rand o rand o snd) THEN ANTS_TAC THENL
+       [REWRITE_TAC[IMAGE_EQ_EMPTY; SET_RULE `{x | x IN s} = s`] THEN
+        REWRITE_TAC[NUMSEG_EMPTY; NOT_LT; LE_ADD] THEN
+        REWRITE_TAC[FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+        EXISTS_TAC `i:real` THEN GEN_TAC THEN REWRITE_TAC[IN_NUMSEG] THEN
+        DISCH_THEN(fun th -> FIRST_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+        ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE] THEN
+      DISCH_THEN(MATCH_MP_TAC o CONJUNCT1) THEN
+      REWRITE_TAC[IN_ELIM_THM; IN_NUMSEG] THEN
+      ASM_ARITH_TAC;
+
+      REWRITE_TAC[bounded] THEN
+      EXISTS_TAC `drop(integral s (h:real^M->real^1))` THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; IN_UNIV] THEN
+      X_GEN_TAC `p:num` THEN MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+      ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+        ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+        MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_SUP_1 THEN
+        REWRITE_TAC[FINITE_NUMSEG; NUMSEG_EMPTY; NOT_LT; LE_ADD] THEN
+        ASM_REWRITE_TAC[LIFT_DROP; ETA_AX] THEN REPEAT STRIP_TAC THEN
+        MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND THEN
+        EXISTS_TAC `h:real^M->real^1` THEN ASM_REWRITE_TAC[];
+        ALL_TAC] THEN
+      X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+      REWRITE_TAC[ABS_DROP; LIFT_DROP] THEN
+      MATCH_MP_TAC REAL_ABS_SUP_LE THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; IMAGE_EQ_EMPTY] THEN
+      ASM_SIMP_TAC[NUMSEG_EMPTY; NOT_LT; LE_ADD; GSYM ABS_DROP]];
+    REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC] THEN
+  MP_TAC(ISPECL
+   [`\k:num x:real^M. lift(inf {drop(f j x) | k <= j})`;
+    `g:real^M->real^1`;
+    `s:real^M->bool`]
+           MONOTONE_CONVERGENCE_INCREASING) THEN
+  ASM_REWRITE_TAC[LIFT_DROP] THEN ANTS_TAC THENL
+   [ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN CONJ_TAC THENL
+     [REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_INF_SUBSET THEN
+      REWRITE_TAC[IMAGE_EQ_EMPTY; SET_RULE `{x | x IN s} = s`] THEN
+      REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY; NOT_LE] THEN
+      CONJ_TAC THENL [MESON_TAC[LT_REFL]; ALL_TAC] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC IMAGE_SUBSET THEN
+        REWRITE_TAC[SUBSET; IN_NUMSEG; IN_ELIM_THM] THEN ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+      EXISTS_TAC `--drop(h(x:real^M))` THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH `abs(x) <= a ==> --a <= x`) THEN
+      ASM_SIMP_TAC[GSYM ABS_DROP];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+      DISCH_THEN(fun th -> X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+                 MP_TAC(SPEC `e / &2` th)) THEN
+      ASM_REWRITE_TAC[REAL_HALF] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `M:num` THEN
+      REWRITE_TAC[dist; ABS_DROP; DROP_SUB; LIFT_DROP] THEN
+      STRIP_TAC THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_INF_ASCLOSE THEN
+      REWRITE_TAC[IMAGE_EQ_EMPTY; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+      CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[LE_TRANS; REAL_LT_IMP_LE]] THEN
+      REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_ELIM_THM; NOT_FORALL_THM] THEN
+      MESON_TAC[LE_REFL];
+      ALL_TAC] THEN
+    REWRITE_TAC[bounded; FORALL_IN_IMAGE; IN_ELIM_THM; IN_UNIV] THEN
+    EXISTS_TAC `drop(integral s (h:real^M->real^1))` THEN
+    X_GEN_TAC `p:num` THEN MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    REWRITE_TAC[ABS_DROP; LIFT_DROP] THEN
+    MATCH_MP_TAC REAL_ABS_INF_LE THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; IMAGE_EQ_EMPTY] THEN
+    ASM_SIMP_TAC[GSYM ABS_DROP; IN_ELIM_THM] THEN
+    REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_ELIM_THM; NOT_FORALL_THM] THEN
+    MESON_TAC[LE_REFL];
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "A"))] THEN
+  MP_TAC(ISPECL
+   [`\k:num x:real^M. lift(sup {drop(f j x) | k <= j})`;
+    `g:real^M->real^1`;
+    `s:real^M->bool`]
+           MONOTONE_CONVERGENCE_DECREASING) THEN
+  ASM_REWRITE_TAC[LIFT_DROP] THEN ANTS_TAC THENL
+   [ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN CONJ_TAC THENL
+     [REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_SUP_LE_SUBSET THEN
+      REWRITE_TAC[IMAGE_EQ_EMPTY; SET_RULE `{x | x IN s} = s`] THEN
+      REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY; NOT_LE] THEN
+      CONJ_TAC THENL [MESON_TAC[LT_REFL]; ALL_TAC] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC IMAGE_SUBSET THEN
+        REWRITE_TAC[SUBSET; IN_NUMSEG; IN_ELIM_THM] THEN ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+      EXISTS_TAC `drop(h(x:real^M))` THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH `abs(x) <= a ==> x <= a`) THEN
+      ASM_SIMP_TAC[GSYM ABS_DROP];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+      DISCH_THEN(fun th -> X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+                 MP_TAC(SPEC `e / &2` th)) THEN
+      ASM_REWRITE_TAC[REAL_HALF] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `M:num` THEN
+      REWRITE_TAC[dist; ABS_DROP; DROP_SUB; LIFT_DROP] THEN
+      STRIP_TAC THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_SUP_ASCLOSE THEN
+      REWRITE_TAC[IMAGE_EQ_EMPTY; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+      CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[LE_TRANS; REAL_LT_IMP_LE]] THEN
+      REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_ELIM_THM; NOT_FORALL_THM] THEN
+      MESON_TAC[LE_REFL];
+      ALL_TAC] THEN
+    REWRITE_TAC[bounded; FORALL_IN_IMAGE; IN_ELIM_THM; IN_UNIV] THEN
+    EXISTS_TAC `drop(integral s (h:real^M->real^1))` THEN
+    X_GEN_TAC `p:num` THEN MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    REWRITE_TAC[ABS_DROP; LIFT_DROP] THEN
+    MATCH_MP_TAC REAL_ABS_SUP_LE THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; IMAGE_EQ_EMPTY] THEN
+    ASM_SIMP_TAC[GSYM ABS_DROP; IN_ELIM_THM] THEN
+    REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_ELIM_THM; NOT_FORALL_THM] THEN
+    MESON_TAC[LE_REFL];
+    DISCH_THEN(LABEL_TAC "B")] THEN
+  ASM_REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  REMOVE_THEN "A" (MP_TAC o REWRITE_RULE[LIM_SEQUENTIALLY]) THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N1:num` (LABEL_TAC "N1")) THEN
+  REMOVE_THEN "B" (MP_TAC o REWRITE_RULE[LIM_SEQUENTIALLY]) THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N2:num` (LABEL_TAC "N2")) THEN
+  EXISTS_TAC `N1 + N2:num` THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+  REMOVE_THEN "N1" (MP_TAC o SPEC `n:num`) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[ARITH_RULE `N1 + N2 <= n ==> N1:num <= n`]; ALL_TAC] THEN
+  REMOVE_THEN "N2" (MP_TAC o SPEC `n:num`) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[ARITH_RULE `N1 + N2 <= n ==> N2:num <= n`]; ALL_TAC] THEN
+  REWRITE_TAC[dist; ABS_DROP; DROP_SUB; LIFT_DROP] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `i0 <= i /\ i <= i1
+    ==> abs(i1 - g) < e ==> abs(i0 - g) < e ==> abs(i - g) < e`) THEN
+  CONJ_TAC THEN MATCH_MP_TAC INTEGRAL_DROP_LE THEN
+  ASM_REWRITE_TAC[LIFT_DROP] THEN X_GEN_TAC `x:real^M` THEN DISCH_TAC THENL
+   [W(MP_TAC o C SPEC INF o rand o lhand o snd) THEN
+    REWRITE_TAC[] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    REWRITE_TAC[IMAGE_EQ_EMPTY; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_ELIM_THM; NOT_FORALL_THM] THEN
+      CONJ_TAC THENL [MESON_TAC[LE_REFL]; ALL_TAC] THEN
+      EXISTS_TAC `--drop(h(x:real^M))` THEN GEN_TAC THEN DISCH_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH `abs(x) <= a ==> --a <= x`) THEN
+      REWRITE_TAC[GSYM ABS_DROP] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REWRITE_TAC[];
+      DISCH_THEN(MATCH_MP_TAC o CONJUNCT1) THEN REWRITE_TAC[LE_REFL]];
+    W(MP_TAC o C SPEC SUP o rand o rand o snd) THEN
+    REWRITE_TAC[] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    REWRITE_TAC[IMAGE_EQ_EMPTY; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_ELIM_THM; NOT_FORALL_THM] THEN
+      CONJ_TAC THENL [MESON_TAC[LE_REFL]; ALL_TAC] THEN
+      EXISTS_TAC `drop(h(x:real^M))` THEN GEN_TAC THEN DISCH_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH `abs(x) <= a ==> x <= a`) THEN
+      REWRITE_TAC[GSYM ABS_DROP] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REWRITE_TAC[];
+      DISCH_THEN(MATCH_MP_TAC o CONJUNCT1) THEN REWRITE_TAC[LE_REFL]]]);;
+
+let DOMINATED_CONVERGENCE_INTEGRABLE = prove
+ (`!f:num->real^M->real^N g h s.
+         (!k. f k absolutely_integrable_on s) /\
+         h integrable_on s /\
+         (!k x. x IN s ==> norm(g x) <= drop(h x)) /\
+         (!x. x IN s ==> ((\k. f k x) --> g x) sequentially)
+         ==> g integrable_on s`,
+  let lemma = prove
+   (`!f:num->real^N->real^1 g h s.
+          (!k. f k absolutely_integrable_on s) /\
+          h integrable_on s /\
+          (!x. x IN s ==> norm(g x) <= drop(h x)) /\
+          (!x. x IN s ==> ((\k. f k x) --> g x) sequentially)
+          ==> g integrable_on s`,
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `(h:real^N->real^1) absolutely_integrable_on s`
+    ASSUME_TAC THENL
+     [MATCH_MP_TAC NONNEGATIVE_ABSOLUTELY_INTEGRABLE THEN
+      ASM_REWRITE_TAC[DIMINDEX_1; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+      REWRITE_TAC[DIMINDEX_1; FORALL_1; GSYM drop; IMP_IMP] THEN
+      ASM_MESON_TAC[REAL_LE_TRANS; NORM_POS_LE];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`\n:num x:real^N.
+         lift(min (max (--(drop(h x))) (drop(f n x))) (drop(h x)))`;
+      `g:real^N->real^1`;
+      `h:real^N->real^1`;
+      `s:real^N->bool`] DOMINATED_CONVERGENCE) THEN
+    ANTS_TAC THENL [ASM_REWRITE_TAC[]; SIMP_TAC[]] THEN REPEAT CONJ_TAC THENL
+     [X_GEN_TAC `n:num` THEN
+      MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+      MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_MIN_1 THEN
+      ASM_REWRITE_TAC[LIFT_DROP; ETA_AX] THEN
+      MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_MAX_1 THEN
+      ASM_SIMP_TAC[LIFT_NEG; LIFT_DROP; ETA_AX; ABSOLUTELY_INTEGRABLE_NEG];
+      MAP_EVERY X_GEN_TAC [`n:num`; `x:real^N`] THEN DISCH_TAC THEN
+      REWRITE_TAC[LIFT_DROP; ABS_DROP] THEN
+      SUBGOAL_THEN `&0 <= drop((h:real^N->real^1) x)` MP_TAC THENL
+       [ASM_MESON_TAC[REAL_LE_TRANS; NORM_POS_LE]; REAL_ARITH_TAC];
+      X_GEN_TAC `x:real^N` THEN REWRITE_TAC[IN_DIFF] THEN STRIP_TAC THEN
+      UNDISCH_TAC
+       `!x. x IN s ==> ((\n. (f:num->real^N->real^1) n x) --> g x)
+                          sequentially` THEN
+      DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[tendsto] THEN 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(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+      X_GEN_TAC `n:num` THEN REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN
+      ASM_REWRITE_TAC[dist; ABS_DROP; DROP_SUB; LIFT_DROP] THEN
+      REAL_ARITH_TAC]) in
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  ONCE_REWRITE_TAC[ABSOLUTELY_INTEGRABLE_COMPONENTWISE;
+                   INTEGRABLE_COMPONENTWISE] THEN
+  DISCH_TAC THEN X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+  MATCH_MP_TAC lemma THEN
+  EXISTS_TAC `\i x. lift(((f:num->real^M->real^N) i x)$k)` THEN
+  EXISTS_TAC `h:real^M->real^1` THEN ASM_SIMP_TAC[] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[COMPONENT_LE_NORM; NORM_LIFT; REAL_LE_TRANS];
+    RULE_ASSUM_TAC(ONCE_REWRITE_RULE[LIM_COMPONENTWISE_LIFT]) THEN
+    RULE_ASSUM_TAC BETA_RULE THEN ASM_SIMP_TAC[]]);;
+
+let DOMINATED_CONVERGENCE_ABSOLUTELY_INTEGRABLE = prove
+ (`!f:num->real^M->real^N g h s.
+         (!k. f k absolutely_integrable_on s) /\
+         h integrable_on s /\
+         (!k x. x IN s ==> norm(g x) <= drop(h x)) /\
+         (!x. x IN s ==> ((\k. f k x) --> g x) sequentially)
+         ==> g absolutely_integrable_on s`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND THEN
+  EXISTS_TAC `h:real^M->real^1` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC DOMINATED_CONVERGENCE_INTEGRABLE THEN
+  EXISTS_TAC `f:num->real^M->real^N` THEN
+  EXISTS_TAC `h:real^M->real^1` THEN ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A few more properties of negligible sets.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_ON_UNIV = prove
+ (`!s. negligible s <=> (indicator s has_integral vec 0) (:real^N)`,
+  GEN_TAC THEN EQ_TAC THENL [SIMP_TAC[NEGLIGIBLE]; ALL_TAC] THEN
+  DISCH_TAC THEN REWRITE_TAC[negligible] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  SUBGOAL_THEN `indicator s integrable_on interval[a:real^N,b]`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+    EXISTS_TAC `(:real^N)` THEN ASM_MESON_TAC[SUBSET_UNIV; integrable_on];
+    ASM_SIMP_TAC[GSYM INTEGRAL_EQ_HAS_INTEGRAL] THEN
+    REWRITE_TAC[GSYM DROP_EQ; GSYM REAL_LE_ANTISYM] THEN
+    CONJ_TAC THENL
+     [FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP INTEGRAL_UNIQUE) THEN
+      MATCH_MP_TAC INTEGRAL_SUBSET_DROP_LE;
+      REWRITE_TAC[DROP_VEC] THEN MATCH_MP_TAC INTEGRAL_DROP_POS] THEN
+    ASM_REWRITE_TAC[SUBSET_UNIV; DROP_INDICATOR_POS_LE] THEN
+    ASM_MESON_TAC[integrable_on]]);;
+
+let NEGLIGIBLE_COUNTABLE_UNIONS = prove
+ (`!s:num->real^N->bool.
+        (!n. negligible(s n)) ==> negligible(UNIONS {s(n) | n IN (:num)})`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n. indicator(UNIONS {(s:num->real^N->bool)(m) | m <= n})`;
+             `indicator(UNIONS {(s:num->real^N->bool)(m) | m IN (:num)})`;
+                 `(:real^N)`] MONOTONE_CONVERGENCE_INCREASING) THEN
+  SUBGOAL_THEN
+   `!n. negligible(UNIONS {(s:num->real^N->bool)(m) | m <= n})`
+  ASSUME_TAC THENL
+   [GEN_TAC THEN MATCH_MP_TAC NEGLIGIBLE_UNIONS THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; FINITE_NUMSEG_LE; FORALL_IN_IMAGE];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n:num. (indicator (UNIONS {s m | m <= n})) integrable_on (:real^N)`
+  ASSUME_TAC THENL
+   [ASM_MESON_TAC[NEGLIGIBLE_ON_UNIV; integrable_on]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n:num. integral (:real^N) (indicator (UNIONS {s m | m <= n})) = vec 0`
+  ASSUME_TAC THENL
+   [ASM_MESON_TAC[NEGLIGIBLE_ON_UNIV; INTEGRAL_UNIQUE]; ALL_TAC] THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_ON_UNIV; LIM_CONST_EQ;
+               TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+  ANTS_TAC THENL [ALL_TAC; MESON_TAC[INTEGRAL_EQ_HAS_INTEGRAL]] THEN
+  REPEAT CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`k:num`; `x:real^N`] THEN DISCH_TAC THEN
+    REWRITE_TAC[indicator] THEN
+    SUBGOAL_THEN
+     `x IN UNIONS {(s:num->real^N->bool) m | m <= k}
+      ==> x IN UNIONS {s m | m <= SUC k}`
+    MP_TAC THENL
+     [SPEC_TAC(`x:real^N`,`x:real^N`) THEN
+      REWRITE_TAC[GSYM SUBSET] THEN MATCH_MP_TAC SUBSET_UNIONS THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN MATCH_MP_TAC IMAGE_SUBSET THEN
+      REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN ARITH_TAC;
+      REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+      REWRITE_TAC[DROP_VEC; REAL_LE_REFL; REAL_POS]];
+    X_GEN_TAC `x:real^N` THEN DISCH_THEN(K ALL_TAC) THEN
+    MATCH_MP_TAC LIM_EVENTUALLY THEN
+    REWRITE_TAC[EVENTUALLY_SEQUENTIALLY; indicator] THEN
+    ASM_CASES_TAC `x IN UNIONS {(s:num->real^N->bool) m | m IN (:num)}` THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [UNIONS_GSPEC]) THEN
+      REWRITE_TAC[IN_ELIM_THM; IN_UNIV] THEN MATCH_MP_TAC MONO_EXISTS THEN
+      X_GEN_TAC `m:num` THEN DISCH_TAC THEN
+      X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+      REWRITE_TAC[UNIONS_GSPEC; IN_ELIM_THM] THEN ASM_MESON_TAC[];
+      EXISTS_TAC `0` THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+      ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE (RAND_CONV o RAND_CONV)
+        [UNIONS_GSPEC]) THEN
+      REWRITE_TAC[UNIONS_GSPEC; IN_ELIM_THM; IN_UNIV] THEN MESON_TAC[]];
+    REWRITE_TAC[SET_RULE `{c | x | x IN UNIV} = {c}`;
+                BOUNDED_INSERT; BOUNDED_EMPTY]]);;
+
+let HAS_INTEGRAL_NEGLIGIBLE_EQ = prove
+ (`!f:real^M->real^N s.
+        (!x i. x IN s /\ 1 <= i /\ i <= dimindex(:N) ==> &0 <= f(x)$i)
+        ==> ((f has_integral vec 0) s <=>
+             negligible {x | x IN s /\ ~(f x = vec 0)})`,
+  let lemma = prove
+   (`!f:real^N->real^1 s.
+          (!x. x IN s ==> &0 <= drop(f x)) /\ (f has_integral vec 0) s
+          ==> negligible {x | x IN s /\ ~(f x = vec 0)}`,
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC
+     `UNIONS {{x | x IN s /\ norm((f:real^N->real^1) x) >= &1 / (&n + &1)} |
+              n IN (:num)}` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC NEGLIGIBLE_COUNTABLE_UNIONS THEN
+      X_GEN_TAC `n:num` THEN REWRITE_TAC[NEGLIGIBLE_ON_UNIV; indicator] THEN
+      MATCH_MP_TAC HAS_INTEGRAL_STRADDLE_NULL THEN
+      EXISTS_TAC `(\x. if x IN s then (&n + &1) % f(x) else vec 0):
+                  real^N->real^1` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[IN_UNIV; IN_ELIM_THM; real_ge] THEN
+        X_GEN_TAC `x:real^N` THEN COND_CASES_TAC THEN
+        ASM_SIMP_TAC[DROP_VEC; DROP_CMUL; REAL_POS] THENL
+         [ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+          ASM_SIMP_TAC[GSYM REAL_LE_LDIV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+          MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ a <= abs x ==> a <= x`) THEN
+          ASM_SIMP_TAC[GSYM ABS_DROP];
+          COND_CASES_TAC THEN REWRITE_TAC[DROP_VEC; REAL_POS; DROP_CMUL] THEN
+          ASM_SIMP_TAC[REAL_POS; REAL_LE_MUL; REAL_LE_ADD]];
+        REWRITE_TAC[HAS_INTEGRAL_RESTRICT_UNIV] THEN
+        SUBST1_TAC(VECTOR_ARITH `vec 0:real^1 = (&n + &1) % vec 0`) THEN
+        MATCH_MP_TAC HAS_INTEGRAL_CMUL THEN ASM_REWRITE_TAC[]];
+      REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN X_GEN_TAC `x:real^N` THEN
+      REWRITE_TAC[GSYM NORM_POS_LT] THEN ONCE_REWRITE_TAC[REAL_ARCH_INV] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_THEN `n:num`
+        STRIP_ASSUME_TAC)) THEN
+      REWRITE_TAC[IN_UNIONS; EXISTS_IN_GSPEC] THEN
+      EXISTS_TAC `n - 1` THEN ASM_SIMP_TAC[IN_UNIV; IN_ELIM_THM; real_ge] THEN
+      ASM_SIMP_TAC[REAL_OF_NUM_ADD; SUB_ADD; LE_1] THEN
+      ASM_SIMP_TAC[real_div; REAL_MUL_LID; REAL_LT_IMP_LE]]) in
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC HAS_INTEGRAL_NEGLIGIBLE THEN
+    EXISTS_TAC `{x | x IN s /\ ~((f:real^M->real^N) x = vec 0)}` THEN
+    ASM_REWRITE_TAC[IN_DIFF; IN_ELIM_THM] THEN MESON_TAC[]] THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `UNIONS {{x | x IN s /\ ~(((f:real^M->real^N) x)$k = &0)} |
+                      k IN 1..dimindex(:N)}` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC NEGLIGIBLE_UNIONS THEN
+    SIMP_TAC[SIMPLE_IMAGE; FINITE_IMAGE; FINITE_NUMSEG; FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `k:num` THEN REWRITE_TAC[IN_NUMSEG] THEN STRIP_TAC THEN
+    REWRITE_TAC[GSYM LIFT_EQ; LIFT_NUM] THEN MATCH_MP_TAC lemma THEN
+    ASM_SIMP_TAC[LIFT_DROP] THEN
+    FIRST_X_ASSUM(MP_TAC o ISPEC `\y:real^N. lift(y$k)` o
+      MATCH_MP(REWRITE_RULE[IMP_CONJ] HAS_INTEGRAL_LINEAR)) THEN
+    REWRITE_TAC[o_DEF; VEC_COMPONENT; LIFT_NUM] THEN
+    DISCH_THEN MATCH_MP_TAC THEN REWRITE_TAC[linear] THEN
+    SIMP_TAC[LIFT_ADD; VECTOR_ADD_COMPONENT; LIFT_CMUL; VECTOR_MUL_COMPONENT];
+    REWRITE_TAC[SUBSET; IN_UNIONS; EXISTS_IN_GSPEC; CART_EQ; IN_NUMSEG] THEN
+    REWRITE_TAC[VEC_COMPONENT; IN_ELIM_THM] THEN MESON_TAC[]]);;
+
+let NEGLIGIBLE_COUNTABLE = prove
+ (`!s:real^N->bool. COUNTABLE s ==> negligible s`,
+  let lemma = prove
+   (`IMAGE f s = UNIONS {{f x} | x IN s}`,
+    REWRITE_TAC[EXTENSION; IN_IMAGE; IN_UNIONS; IN_SING; IN_ELIM_THM] THEN
+    MESON_TAC[IN_SING]) in
+  GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[NEGLIGIBLE_EMPTY] THEN
+  POP_ASSUM MP_TAC THEN REWRITE_TAC[GSYM IMP_CONJ_ALT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:num->real^N` SUBST1_TAC o
+    MATCH_MP COUNTABLE_AS_IMAGE) THEN
+  ONCE_REWRITE_TAC[lemma] THEN MATCH_MP_TAC NEGLIGIBLE_COUNTABLE_UNIONS THEN
+  REWRITE_TAC[NEGLIGIBLE_SING]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Beppo Levi theorem.                                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let BEPPO_LEVI_INCREASING = prove
+ (`!f:num->real^N->real^1 s.
+        (!k. (f k) integrable_on s) /\
+        (!k x. x IN s ==> drop(f k x) <= drop(f (SUC k) x)) /\
+        bounded {integral s (f k) | k IN (:num)}
+        ==> ?g k. negligible k /\
+                  !x. x IN (s DIFF k) ==> ((\k. f k x) --> g x) sequentially`,
+  SUBGOAL_THEN
+   `!f:num->real^N->real^1 s.
+        (!k x. x IN s ==> &0 <= drop(f k x)) /\
+        (!k. (f k) integrable_on s) /\
+        (!k x. x IN s ==> drop(f k x) <= drop(f (SUC k) x)) /\
+        bounded {integral s (f k) | k IN (:num)}
+        ==> ?g k. negligible k /\
+                  !x. x IN (s DIFF k) ==> ((\k. f k x) --> g x) sequentially`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REPEAT GEN_TAC THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o ISPECL
+     [`\n x:real^N. f(n:num) x - f 0 x:real^1`; `s:real^N->bool`]) THEN
+    REWRITE_TAC[] THEN ANTS_TAC THEN REPEAT CONJ_TAC THENL
+     [REPEAT STRIP_TAC THEN REWRITE_TAC[DROP_SUB; REAL_SUB_LE] THEN
+      MP_TAC(ISPEC
+        `\m n:num. drop (f m (x:real^N)) <= drop (f n x)`
+        TRANSITIVE_STEPWISE_LE) THEN
+      REWRITE_TAC[REAL_LE_TRANS; REAL_LE_REFL] THEN ASM_MESON_TAC[LE_0];
+      GEN_TAC THEN MATCH_MP_TAC INTEGRABLE_SUB THEN ASM_REWRITE_TAC[ETA_AX];
+      REPEAT STRIP_TAC THEN REWRITE_TAC[DROP_SUB; REAL_SUB_LE] THEN
+      ASM_SIMP_TAC[REAL_ARITH `x - a <= y - a <=> x <= y`];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [bounded]) THEN
+      ASM_SIMP_TAC[INTEGRAL_SUB; ETA_AX; bounded] THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; IN_UNIV] THEN
+      DISCH_THEN(X_CHOOSE_THEN `B:real`
+        (fun th -> EXISTS_TAC `B + norm(integral s (f 0:real^N->real^1))` THEN
+                   X_GEN_TAC `k:num` THEN MP_TAC(SPEC `k:num` th))) THEN
+      NORM_ARITH_TAC;
+      ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+      GEN_TAC THEN
+      DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^1` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `(\x. g x + f 0 x):real^N->real^1` THEN
+      ASM_REWRITE_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[LIM_SEQUENTIALLY; dist] THEN
+      REWRITE_TAC[VECTOR_ARITH `a - b - c:real^1 = a - (c + b)`]]] THEN
+  REPEAT STRIP_TAC THEN
+  ABBREV_TAC
+   `g = \i n:num x:real^N. lift(min (drop(f n x) / (&i + &1)) (&1))` THEN
+  SUBGOAL_THEN
+   `!i n. ((g:num->num->real^N->real^1) i n) integrable_on s`
+  ASSUME_TAC THENL
+   [REPEAT GEN_TAC THEN EXPAND_TAC "g" THEN
+    MATCH_MP_TAC INTEGRABLE_MIN_CONST_1 THEN
+    ASM_SIMP_TAC[REAL_POS; REAL_LE_DIV; REAL_LE_ADD] THEN
+    REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] real_div] THEN
+    ASM_SIMP_TAC[LIFT_CMUL; LIFT_DROP; INTEGRABLE_CMUL; ETA_AX];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!i:num k:num x:real^N. x IN s ==> drop(g i k x) <= drop(g i (SUC k) x)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN EXPAND_TAC "g" THEN REWRITE_TAC[LIFT_DROP] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= y ==> min x a <= min y a`) THEN
+    ASM_SIMP_TAC[REAL_LE_DIV2_EQ; REAL_ARITH `&0 < &n + &1`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!i:num k:num x:real^N. x IN s ==> norm(g i k x:real^1) <= &1`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN EXPAND_TAC "g" THEN
+    REWRITE_TAC[LIFT_DROP; NORM_REAL; GSYM drop] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= x ==> abs(min x (&1)) <= &1`) THEN
+    ASM_SIMP_TAC[REAL_POS; REAL_LE_DIV; REAL_LE_ADD];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!i:num x:real^N. x IN s ==> ?h:real^1. ((\n. g i n x) --> h) sequentially`
+  MP_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`\n. drop(g (i:num) (n:num) (x:real^N))`; `&1`]
+     CONVERGENT_BOUNDED_MONOTONE) THEN
+    REWRITE_TAC[] THEN ANTS_TAC THENL
+     [ASM_SIMP_TAC[GSYM ABS_DROP] THEN DISJ1_TAC THEN
+      MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN
+      ASM_SIMP_TAC[REAL_LE_REFL; REAL_LE_TRANS] THEN REAL_ARITH_TAC;
+      DISCH_THEN(X_CHOOSE_THEN `l:real` (fun th ->
+        EXISTS_TAC `lift l` THEN MP_TAC th)) THEN
+      REWRITE_TAC[LIM_SEQUENTIALLY; DIST_REAL; GSYM drop; LIFT_DROP]];
+    GEN_REWRITE_TAC (LAND_CONV o REDEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM]] THEN
+  X_GEN_TAC `h:num->real^N->real^1` THEN STRIP_TAC THEN
+  MP_TAC(GEN `i:num `(ISPECL
+   [`g(i:num):num->real^N->real^1`; `h(i:num):real^N->real^1`;
+    `s:real^N->bool`] MONOTONE_CONVERGENCE_INCREASING)) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MONO_FORALL) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [GEN_TAC THEN REWRITE_TAC[bounded] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [bounded]) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `K:real` THEN
+    REWRITE_TAC[FORALL_IN_GSPEC] THEN REWRITE_TAC[IN_UNIV] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `k:num` THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_LE_TRANS) THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `norm a = drop a /\ x <= drop a ==> x <= norm a`) THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[NORM_REAL; GSYM drop; REAL_ABS_REFL] THEN
+      MATCH_MP_TAC INTEGRAL_DROP_POS THEN ASM_SIMP_TAC[];
+      MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+      ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+      EXPAND_TAC "g" THEN REWRITE_TAC[NORM_REAL; GSYM drop; LIFT_DROP] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `&0 <= x /\ x <= y ==> abs(min x (&1)) <= y`) THEN
+      ASM_SIMP_TAC[REAL_LE_ADD; REAL_POS; REAL_LE_DIV] THEN
+      SIMP_TAC[REAL_LE_LDIV_EQ; REAL_ARITH `&0 < &i + &1`] THEN
+      REWRITE_TAC[REAL_ARITH `a <= a * (x + &1) <=> &0 <= a * x`] THEN
+      ASM_SIMP_TAC[REAL_LE_MUL; REAL_POS]];
+    REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC] THEN
+  ABBREV_TAC
+   `Z =
+    {x:real^N | x IN s /\ ~(?l:real^1. ((\k. f k x) --> l) sequentially)}` THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN EXISTS_TAC `Z:real^N->bool` THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; GSYM SKOLEM_THM; RIGHT_EXISTS_IMP_THM] THEN
+  CONJ_TAC THENL
+   [ALL_TAC; EXPAND_TAC "Z" THEN REWRITE_TAC[IN_ELIM_THM] THEN SET_TAC[]] THEN
+  MP_TAC(ISPECL
+   [`h:num->real^N->real^1`;
+    `(\x. if x IN Z then vec 1 else vec 0):real^N->real^1`;
+    `s:real^N->bool`]
+        MONOTONE_CONVERGENCE_DECREASING) THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `!i x:real^N. x IN s ==> drop(h (SUC i) x) <= drop(h i x)`
+  ASSUME_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`i:num`; `x:real^N`] THEN DISCH_TAC THEN
+    MATCH_MP_TAC(ISPEC `sequentially` LIM_DROP_LE) THEN
+    EXISTS_TAC `\n. (g:num->num->real^N->real^1) (SUC i) n x` THEN
+    EXISTS_TAC `\n. (g:num->num->real^N->real^1) i n x` THEN
+    ASM_SIMP_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+    MATCH_MP_TAC ALWAYS_EVENTUALLY THEN X_GEN_TAC `n:num` THEN
+    EXPAND_TAC "g" THEN REWRITE_TAC[LIFT_DROP] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= y ==> min x a <= min y a`) THEN
+    REWRITE_TAC[real_div] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
+    ASM_SIMP_TAC[] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+    REWRITE_TAC[GSYM REAL_OF_NUM_SUC] THEN REAL_ARITH_TAC;
+    ASM_REWRITE_TAC[]] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [BOUNDED_POS]) THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `!i. norm(integral s ((h:num->real^N->real^1) i)) <= B / (&i + &1)`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `i:num` THEN
+    MATCH_MP_TAC(ISPEC `sequentially` LIM_NORM_UBOUND) THEN
+    EXISTS_TAC `\k. integral s ((g:num->num->real^N->real^1) i k)` THEN
+    ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+    MATCH_MP_TAC ALWAYS_EVENTUALLY THEN X_GEN_TAC `n:num` THEN
+    REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC
+     `drop(integral s (\x. inv(&i + &1) % (f:num->real^N->real^1) n x))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+      ASM_SIMP_TAC[INTEGRABLE_CMUL; ETA_AX] THEN
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN EXPAND_TAC "g" THEN
+      REWRITE_TAC[NORM_REAL; GSYM drop; LIFT_DROP; DROP_CMUL] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `&0 <= x /\ x <= y ==> abs(min x (&1)) <= y`) THEN
+      ASM_SIMP_TAC[REAL_LE_ADD; REAL_POS; REAL_LE_DIV] THEN
+      REAL_ARITH_TAC;
+      ASM_SIMP_TAC[INTEGRAL_CMUL; ETA_AX; DROP_CMUL] THEN
+      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+      ASM_SIMP_TAC[GSYM real_div; REAL_LE_DIV2_EQ;
+                   REAL_ARITH `&0 < &n + &1`] THEN
+      MATCH_MP_TAC(REAL_ARITH `abs x <= a ==> x <= a`) THEN
+      ASM_REWRITE_TAC[GSYM ABS_DROP]];
+    ALL_TAC] THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[bounded; FORALL_IN_GSPEC] THEN CONJ_TAC THENL
+     [ALL_TAC;
+      EXISTS_TAC `B:real` THEN X_GEN_TAC `i:num` THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `B / (&i + &1)` THEN ASM_REWRITE_TAC[] THEN
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_ARITH `&0 < &i + &1`] THEN
+      REWRITE_TAC[REAL_ARITH `B <= B * (i + &1) <=> &0 <= i * B`] THEN
+      ASM_SIMP_TAC[REAL_LE_MUL; REAL_POS; REAL_LT_IMP_LE]] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `(x:real^N) IN Z` THEN ASM_REWRITE_TAC[] THENL
+     [MATCH_MP_TAC LIM_EVENTUALLY THEN
+      UNDISCH_TAC `(x:real^N) IN Z` THEN EXPAND_TAC "Z" THEN
+      REWRITE_TAC[IN_ELIM_THM] THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+      MP_TAC(GEN `B:real` (ISPECL
+        [`\n. drop(f (n:num) (x:real^N))`; `B:real`]
+        CONVERGENT_BOUNDED_MONOTONE)) THEN
+      REWRITE_TAC[LEFT_FORALL_IMP_THM; LEFT_EXISTS_AND_THM] THEN
+      MATCH_MP_TAC(TAUT
+       `q /\ ~r /\ (q ==> ~p ==> s)
+        ==> (p /\ (q \/ q') ==> r) ==> s`) THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN
+        ASM_SIMP_TAC[REAL_LE_REFL; REAL_LE_TRANS] THEN REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      CONJ_TAC THENL
+       [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_EXISTS_THM]) THEN
+        ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[] THEN
+        DISCH_THEN(X_CHOOSE_THEN `l:real` STRIP_ASSUME_TAC) THEN
+        DISCH_THEN(MP_TAC o SPEC `lift l`) THEN
+        REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+        X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+        FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+        REWRITE_TAC[DIST_REAL; GSYM drop; DROP_SUB; LIFT_DROP];
+        ALL_TAC] THEN
+      DISCH_TAC THEN REWRITE_TAC[NOT_FORALL_THM; EVENTUALLY_SEQUENTIALLY] THEN
+      REWRITE_TAC[NOT_EXISTS_THM; NOT_FORALL_THM; REAL_NOT_LE] THEN
+      DISCH_TAC THEN
+      EXISTS_TAC `0` THEN  X_GEN_TAC `i:num` THEN DISCH_TAC THEN
+      MATCH_MP_TAC(ISPEC `sequentially` LIM_UNIQUE) THEN
+      EXISTS_TAC `(\n. (g:num->num->real^N->real^1) i n x)` THEN
+      ASM_SIMP_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+      MATCH_MP_TAC LIM_EVENTUALLY THEN
+      EXPAND_TAC "g" THEN REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `&i + &1`) 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
+      REWRITE_TAC[GSYM DROP_EQ; DROP_VEC; LIFT_DROP] THEN
+      REWRITE_TAC[REAL_ARITH `min a b = b <=> b <= a`] THEN
+      SIMP_TAC[REAL_LE_RDIV_EQ; REAL_ARITH `&0 < &i + &1`; REAL_MUL_LID] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+       `a < abs N ==> &0 <= N /\ N <= n ==> a <= n`)) THEN
+      ASM_SIMP_TAC[];
+      UNDISCH_TAC `~((x:real^N) IN Z)` THEN EXPAND_TAC "Z" THEN
+      REWRITE_TAC[IN_ELIM_THM] THEN ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `l:real^1` THEN
+      DISCH_THEN(MP_TAC o MATCH_MP CONVERGENT_IMP_BOUNDED) THEN
+      REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE; IN_UNIV] THEN
+      DISCH_THEN(X_CHOOSE_THEN `C:real` STRIP_ASSUME_TAC) THEN
+      REWRITE_TAC[LIM_SEQUENTIALLY; DIST_0] THEN
+      X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+      MP_TAC(ISPEC `e / C:real` REAL_ARCH_INV) THEN
+      ASM_SIMP_TAC[REAL_LT_DIV] THEN MATCH_MP_TAC MONO_EXISTS THEN
+      X_GEN_TAC `N:num` THEN ASM_SIMP_TAC[REAL_LT_RDIV_EQ] THEN STRIP_TAC THEN
+      X_GEN_TAC `i:num` THEN DISCH_TAC THEN
+      MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `inv(&N) * C` THEN
+      ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `C / (&i + &1)` THEN
+      CONJ_TAC THENL
+       [ALL_TAC;
+        REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] real_div] THEN
+        ASM_SIMP_TAC[REAL_LE_RMUL_EQ] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+        ASM_REWRITE_TAC[REAL_OF_NUM_LT; REAL_OF_NUM_LE; REAL_OF_NUM_ADD] THEN
+        ASM_ARITH_TAC] THEN
+      MATCH_MP_TAC(ISPEC `sequentially` LIM_NORM_UBOUND) THEN
+      EXISTS_TAC `\n. (g:num->num->real^N->real^1) i n x` THEN
+      ASM_SIMP_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+      MATCH_MP_TAC ALWAYS_EVENTUALLY THEN X_GEN_TAC `n:num` THEN
+      EXPAND_TAC "g" THEN REWRITE_TAC[NORM_REAL; GSYM drop; LIFT_DROP] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `&0 <= x /\ x <= a ==> abs(min x (&1)) <= a`) THEN
+      ASM_SIMP_TAC[REAL_LE_DIV; REAL_LE_ADD; REAL_POS] THEN
+      ASM_SIMP_TAC[REAL_LE_DIV2_EQ; REAL_ARITH `&0 < &i + &1`] THEN
+      MATCH_MP_TAC(REAL_ARITH `abs x <= a ==> x <= a`) THEN
+      ASM_REWRITE_TAC[GSYM NORM_LIFT; LIFT_DROP]];
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    MATCH_MP_TAC(MESON[LIM_UNIQUE; TRIVIAL_LIMIT_SEQUENTIALLY]
+     `(f --> vec 0) sequentially /\ (i = vec 0 ==> p)
+      ==> (f --> i) sequentially ==> p`) THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC LIM_NULL_COMPARISON THEN
+      EXISTS_TAC `\i. B / (&i + &1)` THEN
+      ASM_SIMP_TAC[ALWAYS_EVENTUALLY] THEN
+      REWRITE_TAC[real_div; LIFT_CMUL] THEN
+      SUBST1_TAC(VECTOR_ARITH `vec 0:real^1 = B % vec 0`) THEN
+      MATCH_MP_TAC LIM_CMUL THEN
+      REWRITE_TAC[LIM_SEQUENTIALLY; DIST_0] 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
+      X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+      REWRITE_TAC[NORM_LIFT; GSYM drop; LIFT_DROP; REAL_ABS_INV] THEN
+      MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `inv(&N)` THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+      REWRITE_TAC[REAL_ARITH `abs(&n + &1) = &n + &1`] THEN
+      REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+      ASM_ARITH_TAC;
+      ASM_SIMP_TAC[INTEGRAL_EQ_HAS_INTEGRAL] THEN
+      W(MP_TAC o PART_MATCH (lhs o rand) HAS_INTEGRAL_NEGLIGIBLE_EQ o
+        lhand o snd) THEN
+      ANTS_TAC THENL
+       [REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+        REWRITE_TAC[IMP_IMP; DIMINDEX_1; FORALL_1; GSYM drop] THEN
+        REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+        REWRITE_TAC[DROP_VEC; REAL_POS];
+        DISCH_THEN SUBST1_TAC THEN
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] NEGLIGIBLE_SUBSET) THEN
+        SIMP_TAC[SUBSET; IN_ELIM_THM; VEC_EQ; ARITH_EQ] THEN
+        EXPAND_TAC "Z" THEN SIMP_TAC[IN_ELIM_THM]]]]);;
+
+let BEPPO_LEVI_DECREASING = prove
+ (`!f:num->real^N->real^1 s.
+        (!k. (f k) integrable_on s) /\
+        (!k x. x IN s ==> drop(f (SUC k) x) <= drop(f k x)) /\
+        bounded {integral s (f k) | k IN (:num)}
+        ==> ?g k. negligible k /\
+                  !x. x IN (s DIFF k) ==> ((\k. f k x) --> g x) sequentially`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n x. --((f:num->real^N->real^1) n x)`; `s:real^N->bool`]
+        BEPPO_LEVI_INCREASING) THEN
+  ASM_SIMP_TAC[INTEGRABLE_NEG; DROP_NEG; ETA_AX; REAL_LE_NEG2] THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[bounded] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [bounded]) THEN
+    REWRITE_TAC[FORALL_IN_GSPEC] THEN
+    ASM_SIMP_TAC[INTEGRAL_NEG; ETA_AX; NORM_NEG];
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `k:real^N->bool` THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^1` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\x. --((g:real^N->real^1) x)` THEN
+    ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+    GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV o ABS_CONV)
+      [GSYM VECTOR_NEG_NEG] THEN
+    ASM_SIMP_TAC[LIM_NEG_EQ]]);;
+
+let BEPPO_LEVI_MONOTONE_CONVERGENCE_INCREASING = prove
+ (`!f:num->real^N->real^1 s.
+        (!k. (f k) integrable_on s) /\
+        (!k x. x IN s ==> drop(f k x) <= drop(f (SUC k) x)) /\
+        bounded {integral s (f k) | k IN (:num)}
+        ==> ?g k. negligible k /\
+                  (!x. x IN (s DIFF k)
+                       ==> ((\k. f k x) --> g x) sequentially) /\
+                  g integrable_on s /\
+                  ((\k. integral s (f k)) --> integral s g) sequentially`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP BEPPO_LEVI_INCREASING) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^1` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^N->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `(g:real^N->real^1) integrable_on (s DIFF k) /\
+    ((\i. integral (s DIFF k) (f i)) --> integral (s DIFF k) g) sequentially`
+  MP_TAC THENL
+   [MATCH_MP_TAC MONOTONE_CONVERGENCE_INCREASING THEN
+    ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o check (is_conj o concl));
+    ALL_TAC] THEN
+  (SUBGOAL_THEN
+    `!f:real^N->real^1. integral (s DIFF k) f = integral s f /\
+                        (f integrable_on (s DIFF k) <=> f integrable_on s)`
+    (fun th -> SIMP_TAC[th; IN_DIFF]) THEN
+   GEN_TAC THEN CONJ_TAC THEN TRY EQ_TAC THEN
+   (MATCH_MP_TAC INTEGRABLE_SPIKE_SET ORELSE
+    MATCH_MP_TAC INTEGRAL_SPIKE_SET) THEN
+   FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        NEGLIGIBLE_SUBSET)) THEN
+     SET_TAC[]));;
+
+let BEPPO_LEVI_MONOTONE_CONVERGENCE_DECREASING = prove
+ (`!f:num->real^N->real^1 s.
+        (!k. (f k) integrable_on s) /\
+        (!k x. x IN s ==> drop(f (SUC k) x) <= drop(f k x)) /\
+        bounded {integral s (f k) | k IN (:num)}
+        ==> ?g k. negligible k /\
+                  (!x. x IN (s DIFF k)
+                       ==> ((\k. f k x) --> g x) sequentially) /\
+                  g integrable_on s /\
+                  ((\k. integral s (f k)) --> integral s g) sequentially`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP BEPPO_LEVI_DECREASING) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^1` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^N->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `(g:real^N->real^1) integrable_on (s DIFF k) /\
+    ((\i. integral (s DIFF k) (f i)) --> integral (s DIFF k) g) sequentially`
+  MP_TAC THENL
+   [MATCH_MP_TAC MONOTONE_CONVERGENCE_DECREASING THEN
+    ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o check (is_conj o concl));
+    ALL_TAC] THEN
+  (SUBGOAL_THEN
+    `!f:real^N->real^1. integral (s DIFF k) f = integral s f /\
+                        (f integrable_on (s DIFF k) <=> f integrable_on s)`
+    (fun th -> SIMP_TAC[th; IN_DIFF]) THEN
+   GEN_TAC THEN CONJ_TAC THEN TRY EQ_TAC THEN
+   (MATCH_MP_TAC INTEGRABLE_SPIKE_SET ORELSE
+    MATCH_MP_TAC INTEGRAL_SPIKE_SET) THEN
+   FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        NEGLIGIBLE_SUBSET)) THEN
+     SET_TAC[]));;
+
+(* ------------------------------------------------------------------------- *)
+(* Fundamental theorem of calculus, starting with strong forms.              *)
+(* ------------------------------------------------------------------------- *)
+
+let FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG = prove
+ (`!f:real^1->real^N f' s a b.
+        COUNTABLE s /\
+        drop a <= drop b /\ f continuous_on interval[a,b] /\
+        (!x. x IN interval[a,b] DIFF s
+             ==> (f has_vector_derivative f'(x)) (at x within interval[a,b]))
+        ==> (f' has_integral (f(b) - f(a))) (interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPIKE THEN
+  EXISTS_TAC `(\x. if x IN s then vec 0 else f' x):real^1->real^N` THEN
+  EXISTS_TAC `s:real^1->bool` THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_COUNTABLE; IN_DIFF] THEN
+  SUBGOAL_THEN
+   `?f t. s = IMAGE (f:num->real^1) t /\
+          (!m n. m IN t /\ n IN t /\ f m = f n ==> m = n)`
+  MP_TAC THENL
+   [ASM_CASES_TAC `FINITE(s:real^1->bool)` THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [FINITE_INDEX_NUMSEG]) THEN
+      ASM_MESON_TAC[];
+      MP_TAC(ISPEC `s:real^1->bool` COUNTABLE_AS_INJECTIVE_IMAGE) THEN
+      ASM_REWRITE_TAC[INFINITE] THEN MESON_TAC[IN_UNIV]];
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM; INJECTIVE_ON_LEFT_INVERSE] THEN
+    MAP_EVERY X_GEN_TAC [`r:num->real^1`; `t:num->bool`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC MP_TAC) THEN
+    DISCH_THEN(X_CHOOSE_TAC `n:real^1->num`)] THEN
+  REWRITE_TAC[HAS_INTEGRAL_FACTOR_CONTENT] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `!x. ?d. &0 < d /\
+            (x IN interval[a,b]
+             ==> (x IN IMAGE (r:num->real^1) t
+                  ==> !y. norm(y - x) < d /\ y IN interval[a,b]
+                          ==> norm(f y - f x)
+                              <= e / &2 pow (4 + n x) * norm(b - a)) /\
+                 (~(x IN IMAGE r t)
+                  ==> !y. norm(y - x) < d /\ y IN interval[a,b]
+                          ==> norm(f y - f x - drop(y - x) % f' x:real^N)
+                                <= e / &2 * norm(y - x)))`
+  MP_TAC THENL
+   [X_GEN_TAC `x:real^1` THEN
+    ASM_CASES_TAC `(x:real^1) IN interval[a,b]` THENL
+     [ALL_TAC; EXISTS_TAC `&1` THEN ASM_REWRITE_TAC[REAL_LT_01]] THEN
+    ASM_CASES_TAC `x IN IMAGE (r:num->real^1) t` THEN ASM_REWRITE_TAC[] THENL
+     [FIRST_ASSUM(MP_TAC o MATCH_MP (REAL_ARITH
+       `a <= b ==> a = b \/ a < b`)) THEN
+      REWRITE_TAC[DROP_EQ] THEN STRIP_TAC THENL
+       [EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN
+        UNDISCH_TAC `(x:real^1) IN interval[a,b]` THEN
+        ASM_SIMP_TAC[INTERVAL_SING; IN_SING; VECTOR_SUB_REFL; NORM_0] THEN
+        REAL_ARITH_TAC;
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [continuous_on]) THEN
+        DISCH_THEN(MP_TAC o SPEC `x:real^1`) THEN ASM_REWRITE_TAC[dist] THEN
+        DISCH_THEN(MP_TAC o SPEC
+         `e / &2 pow (4 + n(x:real^1)) * norm(b - a:real^1)`) THEN
+        ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_MUL; NORM_POS_LT; VECTOR_SUB_EQ;
+                     REAL_LT_POW2; GSYM DROP_EQ; REAL_LT_IMP_NE] THEN
+        MESON_TAC[REAL_LT_IMP_LE]];
+      FIRST_X_ASSUM(MP_TAC o SPEC `x:real^1`) THEN
+      ASM_REWRITE_TAC[IN_DIFF; has_vector_derivative;
+                      HAS_DERIVATIVE_WITHIN_ALT] THEN
+      DISCH_THEN(MP_TAC o SPEC `e / &2` o CONJUNCT2) THEN
+      ASM_REWRITE_TAC[REAL_HALF] THEN MESON_TAC[]];
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM; FORALL_AND_THM; IMP_IMP;
+                TAUT `p ==> q /\ r <=> (p ==> q) /\ (p ==> r)`] THEN
+    X_GEN_TAC `d:real^1->real` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "E") (LABEL_TAC "U"))] THEN
+  EXISTS_TAC `\x. ball(x:real^1,d(x))` THEN
+  ASM_SIMP_TAC[GAUGE_BALL_DEPENDENT] THEN
+  X_GEN_TAC `p:(real^1#(real^1->bool))->bool` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^1->real^N`; `p:(real^1#(real^1->bool))->bool`;
+                 `a:real^1`; `b:real^1`]
+                ADDITIVE_TAGGED_DIVISION_1) THEN
+  ASM_SIMP_TAC[CONTENT_1] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  ASM_SIMP_TAC[GSYM VSUM_SUB; LAMBDA_PAIR_THM] THEN
+  SUBGOAL_THEN
+   `p:(real^1#(real^1->bool))->bool =
+    {(x,k) | (x,k) IN p /\ x IN IMAGE r (t:num->bool)} UNION
+    {(x,k) | (x,k) IN p /\ ~(x IN IMAGE r (t:num->bool))}`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; FORALL_PAIR_THM; IN_ELIM_PAIR_THM; IN_UNION] THEN
+    MESON_TAC[];
+    ALL_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) VSUM_UNION o rand o lhand o snd) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[SET_RULE `DISJOINT s t <=> !x. x IN s ==> ~(x IN t)`] THEN
+    SIMP_TAC[FORALL_IN_GSPEC; IN_ELIM_PAIR_THM] THEN CONJ_TAC THEN
+    MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC `p:(real^1#(real^1->bool))->bool` THEN
+    ASM_SIMP_TAC[SUBSET; FORALL_IN_GSPEC; IN_ELIM_PAIR_THM];
+    DISCH_THEN SUBST1_TAC] THEN
+  SUBGOAL_THEN
+   `(!P. FINITE {(x:real^1,k:real^1->bool) | (x,k) IN p /\ P x k}) /\
+    (!P x. FINITE {(x:real^1,k:real^1->bool) |k| (x,k) IN p /\ P x k})`
+  STRIP_ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC `p:real^1#(real^1->bool)->bool` THEN
+    ASM_SIMP_TAC[SUBSET; FORALL_IN_GSPEC];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `norm(x:real^N) <= e / &2 * a /\ norm(y) <= e / &2 * a
+    ==> norm(x + y) <= e * a`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+     `norm(vsum {(x,k) | (x,k) IN p /\ x IN IMAGE (r:num->real^1) t /\
+                         ~(content k = &0)}
+                (\(x,k). --(f(interval_upperbound k) -
+                            (f:real^1->real^N)(interval_lowerbound k))))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_EQ_IMP_LE THEN AP_TERM_TAC THEN
+      MATCH_MP_TAC VSUM_EQ_SUPERSET THEN
+      ASM_REWRITE_TAC[FORALL_IN_GSPEC; IMP_CONJ] THEN
+      CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+      SIMP_TAC[VECTOR_ARITH `a % vec 0 - x:real^N = --x`] THEN
+      REWRITE_TAC[IN_ELIM_PAIR_THM] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^1`; `k:real^1->bool`] THEN DISCH_TAC THEN
+      SUBGOAL_THEN `?u v:real^1. k = interval[u,v] /\ x IN interval[u,v]`
+      STRIP_ASSUME_TAC THENL
+       [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[CONTENT_EQ_0_1] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+      DISCH_THEN(MP_TAC o MATCH_MP REAL_LE_TRANS) THEN
+      SIMP_TAC[INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1;
+               INTERVAL_EQ_EMPTY; REAL_NOT_LE; REAL_NOT_LT] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC(VECTOR_ARITH
+       `x:real^N = y ==> --(x - y) = vec 0`) THEN
+      AP_TERM_TAC THEN ASM_REWRITE_TAC[GSYM DROP_EQ; GSYM REAL_LE_ANTISYM];
+      ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+     `sum {(x,k:real^1->bool) | (x,k) IN p /\ x IN IMAGE (r:num->real^1) t /\
+                                ~(content k = &0)}
+          ((\(x,k). e / &2 pow (3 + n x) * norm (b - a:real^1)))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC VSUM_NORM_LE THEN
+      ASM_REWRITE_TAC[FORALL_IN_GSPEC; IMP_CONJ] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^1`; `k:real^1->bool`] THEN DISCH_TAC THEN
+      SUBGOAL_THEN `?u v:real^1. k = interval[u,v] /\ x IN interval[u,v]`
+      MP_TAC THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+      DISCH_THEN(REPEAT_TCL CHOOSE_THEN
+        (CONJUNCTS_THEN2 SUBST_ALL_TAC MP_TAC)) THEN
+      SIMP_TAC[CONTENT_EQ_0_1; REAL_NOT_LE; REAL_LT_IMP_LE; IN_INTERVAL_1;
+               INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1] THEN
+      REPEAT STRIP_TAC THEN
+      REMOVE_THEN "E" (MP_TAC o SPEC `x:real^1`) THEN ANTS_TAC THENL
+       [ASM_MESON_TAC[TAGGED_DIVISION_OF; SUBSET]; ALL_TAC] THEN
+      DISCH_THEN(fun th ->
+        MP_TAC(ISPEC `u:real^1` th) THEN MP_TAC(ISPEC `v:real^1` th)) THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+      DISCH_THEN(MP_TAC o SPECL [`x:real^1`; `interval[u:real^1,v]`]) THEN
+      ASM_REWRITE_TAC[SUBSET; IN_BALL] THEN
+      DISCH_THEN(fun th ->
+        MP_TAC(ISPEC `u:real^1` th) THEN MP_TAC(ISPEC `v:real^1` th)) THEN
+      ASM_REWRITE_TAC[dist; ENDS_IN_INTERVAL; INTERVAL_NE_EMPTY_1] THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE; NORM_SUB] THEN DISCH_TAC THEN DISCH_TAC THEN
+      SUBGOAL_THEN `interval[u:real^1,v] SUBSET interval[a,b]` ASSUME_TAC THENL
+       [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+      REPEAT(ANTS_TAC THENL
+       [ASM_MESON_TAC[ENDS_IN_INTERVAL; SUBSET; INTERVAL_NE_EMPTY_1;
+                      REAL_LT_IMP_LE];
+        ONCE_REWRITE_TAC[TAUT `p ==> q ==> r <=> q ==> p ==> r`]]) THEN
+      REWRITE_TAC[REAL_POW_ADD; real_div; REAL_INV_MUL] THEN NORM_ARITH_TAC;
+      ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`FST:real^1#(real^1->bool)->real^1`;
+      `\(x:real^1,k:real^1->bool). e / &2 pow (3 + n x) * norm (b - a:real^1)`;
+      `{(x,k:real^1->bool) | (x,k) IN p /\ x IN IMAGE (r:num->real^1) t /\
+                                ~(content k = &0)}`;
+      `IMAGE (r:num->real^1) t`
+     ] SUM_GROUP) THEN
+    ANTS_TAC THENL
+     [ASM_REWRITE_TAC[] THEN
+      SIMP_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC];
+      DISCH_THEN(SUBST1_TAC o SYM)] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+     `sum (IMAGE (r:num->real^1) t)
+          (\x. sum {(x,k:real^1->bool) |k|
+                    (x,k) IN p /\ ~(content k = &0)}
+                   (\yk. e / &2 pow (3 + n x) * norm(b - a:real^1)))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_EQ_IMP_LE THEN MATCH_MP_TAC SUM_EQ THEN
+      X_GEN_TAC `x:real^1` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+      MATCH_MP_TAC SUM_EQ_SUPERSET THEN
+      ASM_REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IMP_CONJ] THEN
+      REWRITE_TAC[IN_ELIM_THM; PAIR_EQ] THEN ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[SUM_CONST] THEN
+    REWRITE_TAC[SUM_RMUL; NORM_1; DROP_SUB; REAL_MUL_ASSOC] THEN
+    ASM_REWRITE_TAC[real_abs; REAL_SUB_LE] THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+    ASM_REWRITE_TAC[REAL_SUB_LE; REAL_POW_ADD; real_div; REAL_INV_MUL] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH
+     `p * e * inv(&2 pow 3) * n = e / &8 * (p * n)`] THEN
+    ASM_SIMP_TAC[REAL_LE_LMUL_EQ; SUM_LMUL; REAL_ARITH
+     `e / &8 * x <= e * inv(&2) <=> e * x <= e * &4`] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+     `sum (IMAGE (r:num->real^1) t INTER
+           IMAGE (FST:real^1#(real^1->bool)->real^1) p)
+          (\x. &(CARD {(x,k:real^1->bool) | k |
+                      (x,k) IN p /\ ~(content k = &0)}) *
+               inv(&2 pow n x))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_EQ_IMP_LE THEN MATCH_MP_TAC SUM_SUPERSET THEN
+      REWRITE_TAC[INTER_SUBSET; IMP_CONJ; FORALL_IN_IMAGE] THEN
+      SIMP_TAC[IN_INTER; FUN_IN_IMAGE] THEN
+      REWRITE_TAC[IN_IMAGE; EXISTS_PAIR_THM] THEN
+      REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_ENTIRE] THEN
+      DISJ1_TAC THEN AP_TERM_TAC THEN
+      MATCH_MP_TAC(MESON[CARD_CLAUSES] `s = {} ==> CARD s = 0`) THEN
+      ASM SET_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+     `sum (IMAGE (r:num->real^1) t INTER
+           IMAGE (FST:real^1#(real^1->bool)->real^1) p)
+          (\x. &2 / &2 pow (n x))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC SUM_LE THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; FINITE_INTER] THEN
+      GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[real_div] THEN
+      MATCH_MP_TAC REAL_LE_RMUL THEN
+      SIMP_TAC[REAL_LE_INV_EQ; REAL_POW_LE; REAL_POS; REAL_OF_NUM_LE] THEN
+      GEN_REWRITE_TAC RAND_CONV [ARITH_RULE `2 = 2 EXP 1`] THEN
+      GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM DIMINDEX_1] THEN
+      MATCH_MP_TAC TAGGED_PARTIAL_DIVISION_COMMON_TAGS THEN
+      ASM_MESON_TAC[tagged_division_of];
+      ALL_TAC] THEN
+    REWRITE_TAC[real_div; SUM_LMUL; REAL_ARITH `&2 * x <= &4 <=> x <= &2`;
+                REAL_INV_POW] THEN
+    SUBGOAL_THEN
+     `(\x:real^1. inv (&2) pow n x) = (\n. inv(&2) pow n) o n`
+    SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+    W(MP_TAC o PART_MATCH (rand o rand) SUM_IMAGE o lhand o snd) THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; DISCH_THEN(SUBST1_TAC o SYM)] THEN
+    SUBGOAL_THEN
+     `?m. IMAGE (n:real^1->num)
+                (IMAGE (r:num->real^1) t INTER
+                IMAGE (FST:real^1#(real^1->bool)->real^1) p) SUBSET 0..m`
+    STRIP_ASSUME_TAC THENL
+     [REWRITE_TAC[SUBSET; IN_NUMSEG; LE_0] THEN
+      MATCH_MP_TAC UPPER_BOUND_FINITE_SET THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; FINITE_INTER];
+      ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum(0..m) (\n. inv(&2) pow n)` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC SUM_SUBSET THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; FINITE_INTER; FINITE_NUMSEG] THEN
+      SIMP_TAC[REAL_LE_INV_EQ; REAL_POW_LE; REAL_POS] THEN ASM SET_TAC[];
+      REWRITE_TAC[SUM_GP; LT; SUB_0] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      REWRITE_TAC[REAL_ARITH `(&1 - x) / (&1 / &2) <= &2 <=> &0 <= x`] THEN
+      MATCH_MP_TAC REAL_POW_LE THEN CONV_TAC REAL_RAT_REDUCE_CONV];
+    MP_TAC(ISPECL [`\x:real^1. x`; `p:(real^1#(real^1->bool))->bool`;
+                   `a:real^1`; `b:real^1`]
+                  ADDITIVE_TAGGED_DIVISION_1) THEN
+    ASM_SIMP_TAC[] THEN DISCH_THEN(MP_TAC o AP_TERM `drop`) THEN
+    ASM_SIMP_TAC[DROP_VSUM; DROP_SUB] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[GSYM SUM_LMUL] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC
+     `sum {(x:real^1,k:real^1->bool) |
+           (x,k) IN p /\ ~(x IN IMAGE r (t:num->bool))}
+          (\x. e / &2 * (drop o
+            (\(x,k). interval_upperbound k - interval_lowerbound k)) x)` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC VSUM_NORM_LE THEN ASM_REWRITE_TAC[FORALL_IN_GSPEC] THEN
+      SIMP_TAC[o_DEF] THEN
+      REWRITE_TAC[NORM_ARITH `norm(a - (b - c):real^N) = norm(b - c - a)`] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^1`; `k:real^1->bool`] THEN STRIP_TAC THEN
+      SUBGOAL_THEN `?u v:real^1. k = interval[u,v] /\ x IN interval[u,v]`
+      MP_TAC THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+      DISCH_THEN(REPEAT_TCL CHOOSE_THEN
+       (CONJUNCTS_THEN2 SUBST_ALL_TAC MP_TAC)) THEN
+      REWRITE_TAC[IN_INTERVAL_1] THEN DISCH_THEN(fun th ->
+        ASSUME_TAC th THEN MP_TAC(MATCH_MP REAL_LE_TRANS th)) THEN
+      SIMP_TAC[CONTENT_1; INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1] THEN
+      DISCH_TAC THEN REMOVE_THEN "U" (MP_TAC o SPEC `x:real^1`) THEN
+      ASM_REWRITE_TAC[] THEN
+      SUBGOAL_THEN `interval[u:real^1,v] SUBSET interval[a,b]` ASSUME_TAC THENL
+       [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+      ANTS_TAC THENL [ASM_MESON_TAC[SUBSET; IN_INTERVAL_1]; ALL_TAC] THEN
+      DISCH_THEN(fun th ->
+        MP_TAC(ISPEC `u:real^1` th) THEN MP_TAC(ISPEC `v:real^1` th)) THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+      DISCH_THEN(MP_TAC o SPECL [`x:real^1`; `interval[u:real^1,v]`]) THEN
+      ASM_REWRITE_TAC[SUBSET; IN_BALL] THEN
+      DISCH_THEN(fun th ->
+        MP_TAC(ISPEC `u:real^1` th) THEN MP_TAC(ISPEC `v:real^1` th)) THEN
+      ASM_REWRITE_TAC[dist; ENDS_IN_INTERVAL; INTERVAL_NE_EMPTY_1] THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE; NORM_SUB] THEN DISCH_TAC THEN DISCH_TAC THEN
+      REPEAT(ANTS_TAC THENL
+       [ASM_MESON_TAC[ENDS_IN_INTERVAL; SUBSET; INTERVAL_NE_EMPTY_1;
+                      REAL_LT_IMP_LE];
+        ONCE_REWRITE_TAC[TAUT `p ==> q ==> r <=> q ==> p ==> r`]]) THEN
+      REWRITE_TAC[NORM_1; DROP_SUB] THEN
+      ASM_SIMP_TAC[REAL_ARITH `a <= b ==> abs(a - b) = b - a`;
+                   REAL_ARITH `b <= a ==> abs(a - b) = a - b`] THEN
+      REWRITE_TAC[REAL_SUB_LDISTRIB] THEN MATCH_MP_TAC(NORM_ARITH
+       `x - y:real^N = z ==> norm(x) <= c - b
+                   ==> norm(y) <= b - a ==> norm(z) <= c - a`) THEN
+      VECTOR_ARITH_TAC;
+      MATCH_MP_TAC SUM_SUBSET_SIMPLE THEN ASM_REWRITE_TAC[] THEN
+      CONJ_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[FORALL_PAIR_THM]] THEN
+      REWRITE_TAC[IN_DIFF; IN_ELIM_PAIR_THM] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^1`; `k:real^1->bool`] THEN STRIP_TAC THEN
+      SUBGOAL_THEN `?u v:real^1. k = interval[u,v] /\ x IN interval[u,v]`
+      MP_TAC THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+      DISCH_THEN(REPEAT_TCL CHOOSE_THEN
+       (CONJUNCTS_THEN2 SUBST_ALL_TAC MP_TAC)) THEN
+      REWRITE_TAC[IN_INTERVAL_1; o_THM] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP REAL_LE_TRANS) THEN
+      SIMP_TAC[INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_MUL THEN
+      ASM_REWRITE_TAC[DROP_SUB] THEN ASM_REAL_ARITH_TAC]]);;
+
+let FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG = prove
+ (`!f:real^1->real^N f' s a b.
+        COUNTABLE s /\
+        drop a <= drop b /\ f continuous_on interval[a,b] /\
+        (!x. x IN interval(a,b) DIFF s
+             ==> (f has_vector_derivative f'(x)) (at x))
+        ==> (f' has_integral (f(b) - f(a))) (interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG THEN
+  EXISTS_TAC `(a:real^1) INSERT (b:real^1) INSERT s` THEN
+  ASM_REWRITE_TAC[COUNTABLE_INSERT; IN_INTERVAL_1; IN_DIFF] THEN
+  REWRITE_TAC[DE_MORGAN_THM; IN_INSERT] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_AT_WITHIN THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[IN_INTERVAL_1; IN_DIFF; IN_INSERT] THEN
+  ASM_REWRITE_TAC[REAL_LT_LE; DROP_EQ]);;
+
+let FUNDAMENTAL_THEOREM_OF_CALCULUS = prove
+ (`!f:real^1->real^N f' a b.
+        drop a <= drop b /\
+        (!x. x IN interval[a,b]
+             ==> (f has_vector_derivative f'(x)) (at x within interval[a,b]))
+        ==> (f' has_integral (f(b) - f(a))) (interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG THEN
+  EXISTS_TAC `{}:real^1->bool` THEN
+  ASM_REWRITE_TAC[COUNTABLE_EMPTY; DIFF_EMPTY] THEN
+  MATCH_MP_TAC DIFFERENTIABLE_IMP_CONTINUOUS_ON THEN
+  REWRITE_TAC[differentiable_on] THEN
+  ASM_MESON_TAC[has_vector_derivative; differentiable]);;
+
+let FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR = prove
+ (`!f:real^1->real^N f' a b.
+        drop a <= drop b /\ f continuous_on interval[a,b] /\
+        (!x. x IN interval(a,b)
+             ==> (f has_vector_derivative f'(x)) (at x))
+        ==> (f' has_integral (f(b) - f(a))) (interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG THEN
+  EXISTS_TAC `{}:real^1->bool` THEN
+  ASM_REWRITE_TAC[COUNTABLE_EMPTY; DIFF_EMPTY]);;
+
+let ANTIDERIVATIVE_INTEGRAL_CONTINUOUS = prove
+ (`!f:real^1->real^N a b.
+     (f continuous_on interval[a,b])
+     ==> ?g. !u v. u IN interval[a,b] /\ v IN interval[a,b] /\ drop u <= drop v
+                   ==> (f has_integral (g(v) - g(u))) (interval[u,v])`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ANTIDERIVATIVE_CONTINUOUS) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^1->real^N` THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC FUNDAMENTAL_THEOREM_OF_CALCULUS THEN
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:real^1` THEN
+  STRIP_TAC THEN MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_WITHIN_SUBSET THEN
+  EXISTS_TAC `interval[a:real^1,b]` THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC; ALL_TAC] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[SUBSET_INTERVAL_1; IN_INTERVAL_1] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* This doesn't directly involve integration, but that gives an easy proof.  *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_INTERVAL = prove
+ (`!f:real^1->real^N a b k y.
+        COUNTABLE k /\ f continuous_on interval[a,b] /\ f a = y /\
+        (!x. x IN (interval[a,b] DIFF k)
+             ==> (f has_derivative (\h. vec 0)) (at x within interval[a,b]))
+        ==> !x. x IN interval[a,b] ==> f x = y`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+  MATCH_MP_TAC(ISPEC `(\x. vec 0):real^1->real^N` HAS_INTEGRAL_UNIQUE) THEN
+  EXISTS_TAC `interval[a:real^1,x]` THEN
+  REWRITE_TAC[HAS_INTEGRAL_0] THEN FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+  MATCH_MP_TAC FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG THEN
+  EXISTS_TAC `k:real^1->bool` THEN ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1])) THEN
+    REAL_ARITH_TAC;
+    MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+    EXISTS_TAC `interval[a:real^1,b]` THEN
+    ASM_REWRITE_TAC[SUBSET_INTERVAL_1] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1])) THEN
+    REAL_ARITH_TAC;
+    X_GEN_TAC `y:real^1` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `y:real^1`) THEN ANTS_TAC THENL
+     [REPEAT(POP_ASSUM MP_TAC) THEN
+      SIMP_TAC[IN_DIFF; IN_INTERVAL_1] THEN REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      HAS_DERIVATIVE_WITHIN_SUBSET)) THEN
+    DISCH_THEN(MP_TAC o SPEC `interval(a:real^1,b)`) THEN
+    REWRITE_TAC[INTERVAL_OPEN_SUBSET_CLOSED] THEN
+    REWRITE_TAC[has_vector_derivative; VECTOR_MUL_RZERO] THEN
+    MATCH_MP_TAC EQ_IMP THEN MATCH_MP_TAC HAS_DERIVATIVE_WITHIN_OPEN THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN
+    SIMP_TAC[OPEN_INTERVAL; IN_INTERVAL_1; IN_DIFF] THEN REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Generalize a bit to any convex set.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_CONVEX = prove
+ (`!f:real^M->real^N s k c y.
+      convex s /\ COUNTABLE k /\ f continuous_on s /\ c IN s /\ f c = y /\
+      (!x. x IN (s DIFF k) ==> (f has_derivative (\h. vec 0)) (at x within s))
+      ==> !x. x IN s ==> f x = y`,
+  GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `z:real^N`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+  X_GEN_TAC `y:real^M` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `x:real^M = y` THEN ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPECL [`(f:real^M->real^N) o (\t. (&1 - drop t) % x + drop t % y)`;
+                 `vec 0:real^1`; `vec 1:real^1`;
+                 `{t | ((&1 - drop t) % (x:real^M) + drop t % y) IN k}`;
+                 `(f:real^M->real^N) x`]
+                HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_INTERVAL) THEN
+  REWRITE_TAC[o_THM] THEN ANTS_TAC THENL
+   [ALL_TAC;
+    DISCH_THEN(MP_TAC o SPEC `vec 1:real^1`) THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN AP_TERM_TAC THEN VECTOR_ARITH_TAC] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC COUNTABLE_IMAGE_INJ THEN ASM_REWRITE_TAC[] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ; REAL_SUB_0; DROP_EQ;
+    VECTOR_ARITH `(&1 - t) % x + t % y = (&1 - u) % x + u % y <=>
+                  (t - u) % (x - y) = vec 0`];
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN CONJ_TAC THEN
+      MATCH_MP_TAC CONTINUOUS_ON_VMUL THEN
+      REWRITE_TAC[o_DEF; LIFT_DROP; CONTINUOUS_ON_ID; LIFT_SUB] THEN
+      SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1; GSYM FORALL_DROP] THEN
+      REWRITE_TAC[DROP_VEC] THEN ASM_MESON_TAC[CONVEX_ALT]];
+    AP_TERM_TAC THEN REWRITE_TAC[DROP_VEC] THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `(\h. vec 0) = ((\h. vec 0):real^M->real^N) o
+                               (\t. drop t % (y - x))`
+  SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+  MATCH_MP_TAC DIFF_CHAIN_WITHIN THEN CONJ_TAC THENL
+   [REWRITE_TAC[VECTOR_ARITH `t % (y - x) = ((&0 - t) % x) + t % y`] THEN
+    MATCH_MP_TAC HAS_DERIVATIVE_ADD THEN
+    REWRITE_TAC[GSYM DROP_NEG; GSYM DROP_VEC; GSYM DROP_SUB] THEN
+    SIMP_TAC[HAS_DERIVATIVE_VMUL_DROP; HAS_DERIVATIVE_ID] THEN
+    REWRITE_TAC[DROP_SUB; VECTOR_SUB_RDISTRIB] THEN
+    MATCH_MP_TAC HAS_DERIVATIVE_SUB THEN
+    REWRITE_TAC[VECTOR_MUL_LZERO; DROP_VEC; HAS_DERIVATIVE_CONST] THEN
+    SIMP_TAC[HAS_DERIVATIVE_VMUL_DROP; HAS_DERIVATIVE_ID];
+    ALL_TAC] THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_WITHIN_SUBSET THEN
+  EXISTS_TAC `s:real^M->bool` THEN REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[IN_INTERVAL_1; GSYM FORALL_DROP; DROP_VEC] THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[CONVEX_ALT]] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_DIFF]) THEN
+  SIMP_TAC[IN_ELIM_THM; IN_DIFF] THEN REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[IN_INTERVAL_1; GSYM FORALL_DROP; DROP_VEC] THEN
+  ASM_MESON_TAC[CONVEX_ALT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Also to any open connected set with finite set of exceptions. Could       *)
+(* generalize to locally convex set with limpt-free set of exceptions.       *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_CONNECTED = prove
+ (`!f:real^M->real^N s k c y.
+      connected s /\ open s /\ COUNTABLE k /\ f continuous_on s /\
+      c IN s /\ f c = y /\
+      (!x. x IN (s DIFF k) ==> (f has_derivative (\h. vec 0)) (at x within s))
+      ==> !x. x IN s ==> f x = y`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONNECTED_CLOPEN]) THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `{x | x IN s /\ (f:real^M->real^N) x IN {y}}`) THEN
+  ANTS_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN CONJ_TAC THEN
+  ASM_SIMP_TAC[CONTINUOUS_CLOSED_IN_PREIMAGE; CLOSED_SING] THEN
+  MATCH_MP_TAC OPEN_OPEN_IN_TRANS THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL [ALL_TAC; SET_TAC[]] THEN
+  UNDISCH_TAC `open(s:real^M->bool)` THEN REWRITE_TAC[OPEN_CONTAINS_BALL] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `u:real^M` THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_SING] 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 STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+  MATCH_MP_TAC HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_CONVEX THEN
+  MAP_EVERY EXISTS_TAC [`k:real^M->bool`; `u:real^M`] THEN
+  ASM_REWRITE_TAC[CONVEX_BALL; IN_DIFF; CENTRE_IN_BALL] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[SUBSET; CONTINUOUS_ON_SUBSET]; ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_WITHIN_SUBSET THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[SUBSET] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[IN_DIFF]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Equiintegrability. The definition here only really makes sense for an     *)
+(* elementary set. We just use compact intervals in applications below.      *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("equiintegrable_on",(12,"right"));;
+
+let equiintegrable_on = new_definition
+  `fs equiintegrable_on i <=>
+        (!f:real^M->real^N. f IN fs ==> f integrable_on i) /\
+        (!e. &0 < e
+             ==> ?d. gauge d /\
+                    !f p. f IN fs /\ p tagged_division_of i /\ d fine p
+                        ==> norm(vsum p (\(x,k). content(k) % f(x)) -
+                                 integral i f) < e)`;;
+
+let EQUIINTEGRABLE_ON_SING = prove
+ (`!f:real^M->real^N a b.
+        {f} equiintegrable_on interval[a,b] <=>
+        f integrable_on interval[a,b]`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[equiintegrable_on] THEN
+  REWRITE_TAC[IN_SING; FORALL_UNWIND_THM2] THEN
+  ASM_CASES_TAC `(f:real^M->real^N) integrable_on interval[a,b]` THEN
+  ASM_REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_UNWIND_THM2] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP INTEGRABLE_INTEGRAL) THEN
+  REWRITE_TAC[has_integral; IMP_IMP]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic combining theorems for the interval of integration.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let EQUIINTEGRABLE_ON_NULL = prove
+ (`!fs:(real^M->real^N)->bool a b.
+     content(interval[a,b]) = &0 ==> fs equiintegrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[equiintegrable_on] THEN
+  ASM_SIMP_TAC[INTEGRABLE_ON_NULL] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  EXISTS_TAC `\x:real^M. ball(x,&1)` THEN REWRITE_TAC[GAUGE_TRIVIAL] THEN
+  FIRST_ASSUM(fun th -> SIMP_TAC[MATCH_MP (REWRITE_RULE[IMP_CONJ]
+                                           VSUM_CONTENT_NULL) th]) THEN
+  ASM_SIMP_TAC[INTEGRAL_NULL; VECTOR_SUB_REFL; NORM_0]);;
+
+let EQUIINTEGRABLE_ON_SPLIT = prove
+ (`!fs:(real^M->real^N)->bool k a b c.
+      fs equiintegrable_on (interval[a,b] INTER {x | x$k <= c}) /\
+      fs equiintegrable_on (interval[a,b] INTER {x | x$k >= c}) /\
+      1 <= k /\ k <= dimindex(:M)
+      ==> fs equiintegrable_on (interval[a,b])`,
+  let lemma1 = prove
+   (`(!x k. (x,k) IN {x,f k | P x k} ==> Q x k) <=>
+     (!x k. P x k ==> Q x (f k))`,
+    REWRITE_TAC[IN_ELIM_THM; PAIR_EQ] THEN
+    SET_TAC[]) in
+  let lemma2 = prove
+   (`!f:B->B s:(A#B)->bool.
+      FINITE s ==> FINITE {x,f k | (x,k) IN s /\ P x k}`,
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC `IMAGE (\(x:A,k:B). x,(f k:B)) s` THEN
+    ASM_SIMP_TAC[FINITE_IMAGE] THEN
+    REWRITE_TAC[SUBSET; FORALL_PAIR_THM; lemma1; IN_IMAGE] THEN
+    REWRITE_TAC[EXISTS_PAIR_THM; PAIR_EQ] THEN MESON_TAC[]) in
+  let lemma3 = prove
+   (`!f:real^M->real^N g:(real^M->bool)->(real^M->bool) p.
+     FINITE p
+     ==> vsum {x,g k |x,k| (x,k) IN p /\ ~(g k = {})}
+              (\(x,k). content k % f x) =
+         vsum (IMAGE (\(x,k). x,g k) p) (\(x,k). content k % f x)`,
+    REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_SUPERSET THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; lemma2] THEN
+    REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[FORALL_PAIR_THM; SUBSET; IN_IMAGE; EXISTS_PAIR_THM] THEN
+    REWRITE_TAC[IN_ELIM_THM; PAIR_EQ; VECTOR_MUL_EQ_0] THEN
+    MESON_TAC[CONTENT_EMPTY]) in
+  let lemma4 = prove
+   (`(\(x,l). content (g l) % f x) =
+     (\(x,l). content l % f x) o (\(x,l). x,g l)`,
+    REWRITE_TAC[FUN_EQ_THM; o_THM; FORALL_PAIR_THM]) in
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `1 <= k /\ k <= dimindex(:M)` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[equiintegrable_on] THEN
+  MATCH_MP_TAC(TAUT
+   `(a /\ b ==> c) /\ (a /\ b /\ c ==> a' /\ b' ==> c')
+    ==> (a /\ a') /\ (b /\ b') ==> c /\ c'`) THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[integrable_on] THEN ASM MESON_TAC[HAS_INTEGRAL_SPLIT];
+    STRIP_TAC] THEN
+  SUBGOAL_THEN
+   `!f:real^M->real^N.
+        f IN fs
+        ==> integral (interval[a,b]) f =
+                integral (interval [a,b] INTER {x | x$k <= c}) f +
+                integral (interval [a,b] INTER {x | x$k >= c}) f`
+   (fun th -> SIMP_TAC[th])
+  THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+    MATCH_MP_TAC HAS_INTEGRAL_SPLIT THEN
+    MAP_EVERY EXISTS_TAC [`k:num`; `c:real`] THEN
+    ASM_SIMP_TAC[GSYM HAS_INTEGRAL_INTEGRAL];
+    ALL_TAC] THEN
+  DISCH_TAC THEN X_GEN_TAC `e:real` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(CONJUNCTS_THEN2 (MP_TAC o SPEC `e / &2`) STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d2:real^M->real^M->bool`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "I2"))) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real^M->real^M->bool`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "I1"))) THEN
+  EXISTS_TAC `\x. if x$k = c then (d1(x:real^M) INTER d2(x)):real^M->bool
+                  else ball(x,abs(x$k - c)) INTER d1(x) INTER d2(x)` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[gauge] THEN GEN_TAC THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[gauge]) THEN COND_CASES_TAC THEN
+    ASM_SIMP_TAC[OPEN_INTER; IN_INTER; OPEN_BALL; IN_BALL] THEN
+    ASM_REWRITE_TAC[DIST_REFL; GSYM REAL_ABS_NZ; REAL_SUB_0];
+    ALL_TAC] THEN
+  X_GEN_TAC `f:real^M->real^N` THEN
+  X_GEN_TAC `p:(real^M#(real^M->bool))->bool` THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+    `(!x:real^M kk. (x,kk) IN p /\ ~(kk INTER {x:real^M | x$k <= c} = {})
+                    ==> x$k <= c) /\
+     (!x:real^M kk. (x,kk) IN p /\ ~(kk INTER {x:real^M | x$k >= c} = {})
+                    ==> x$k >= c)`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:real^M` THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `kk:real^M->bool` THEN
+    DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_LE_REFL; real_ge] THEN DISCH_THEN
+     (MP_TAC o MATCH_MP (SET_RULE `k SUBSET (a INTER b) ==> k SUBSET a`)) THEN
+    REWRITE_TAC[SUBSET; IN_BALL; dist] THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^M` MP_TAC) THEN
+    REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `u:real^M`) THEN ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[REAL_NOT_LE; REAL_NOT_LT] THEN STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `abs((x - u:real^M)$k)` THEN
+    ASM_SIMP_TAC[COMPONENT_LE_NORM] THEN
+    ASM_SIMP_TAC[VECTOR_SUB_COMPONENT] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REMOVE_THEN "I2" (MP_TAC o SPEC
+   `{(x:real^M,kk INTER {x:real^M | x$k >= c}) |x,kk|
+     (x,kk) IN p /\ ~(kk INTER {x:real^M | x$k >= c} = {})}` o
+   SPEC `f:real^M->real^N`) THEN
+  REMOVE_THEN "I1" (MP_TAC o SPEC
+   `{(x:real^M,kk INTER {x:real^M | x$k <= c}) |x,kk|
+     (x,kk) IN p /\ ~(kk INTER {x:real^M | x$k <= c} = {})}` o
+   SPEC `f:real^M->real^N`) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(TAUT
+   `(a /\ b) /\ (a' /\ b' ==> c) ==> (a ==> a') ==> (b ==> b') ==> c`) THEN
+  CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+    REWRITE_TAC[TAGGED_DIVISION_OF] THEN
+    REPEAT(MATCH_MP_TAC(TAUT
+     `(a ==> (a' /\ a'')) /\ (b ==> (b' /\ d) /\ (b'' /\ e))
+      ==> a /\ b ==> ((a' /\ b') /\ d) /\ ((a'' /\ b'') /\ e)`) THEN
+      CONJ_TAC) THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[lemma1] THEN REWRITE_TAC[IMP_IMP] THENL
+     [SIMP_TAC[lemma2];
+      REWRITE_TAC[AND_FORALL_THM] THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:real^M` THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `kk:real^M->bool` THEN
+      DISCH_THEN(fun th -> CONJ_TAC THEN STRIP_TAC THEN MP_TAC th) THEN
+      (ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+        [SIMP_TAC[IN_INTER; IN_ELIM_THM] THEN ASM_MESON_TAC[]; ALL_TAC]) THEN
+      (MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL [SET_TAC[]; ALL_TAC]) THEN
+      ASM_MESON_TAC[INTERVAL_SPLIT];
+      DISCH_THEN(fun th -> CONJ_TAC THEN MP_TAC th) THEN
+      (REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+       DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_SIMP_TAC[] THEN
+       REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+       DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_SIMP_TAC[] THEN
+       ANTS_TAC THENL [ASM_MESON_TAC[PAIR_EQ]; ALL_TAC] THEN
+       MATCH_MP_TAC(SET_RULE
+        `s SUBSET s' /\ t SUBSET t'
+         ==> s' INTER t' = {} ==> s INTER t = {}`) THEN
+       CONJ_TAC THEN MATCH_MP_TAC SUBSET_INTERIOR THEN SET_TAC[]);
+      ALL_TAC] THEN
+    MATCH_MP_TAC(TAUT `(a ==> b /\ c) /\ d /\ e
+                       ==> (a ==> (b /\ d) /\ (c /\ e))`) THEN
+    CONJ_TAC THENL
+     [DISCH_THEN(fun th -> CONJ_TAC THEN MP_TAC th) THEN
+      DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[INTER_UNIONS] THEN
+      ONCE_REWRITE_TAC[EXTENSION] THEN REWRITE_TAC[IN_UNIONS] THEN
+      X_GEN_TAC `x:real^M` THEN AP_TERM_TAC THEN
+      GEN_REWRITE_TAC I [FUN_EQ_THM] THEN X_GEN_TAC `kk:real^M->bool` THEN
+      REWRITE_TAC[IN_ELIM_THM; PAIR_EQ] THEN MESON_TAC[NOT_IN_EMPTY];
+      ALL_TAC] THEN
+    CONJ_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+    REWRITE_TAC[fine; lemma1] THEN
+    REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+    DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+    ASM_SIMP_TAC[] THEN SET_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+   `x < e / &2 /\ y < e / &2 ==> x + y < e`)) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP NORM_TRIANGLE_LT) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `(a - i) + (b - j) = c - (i + j) <=> a + b = c:real^N`] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+ MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC
+   `vsum p (\(x,l). content (l INTER {x:real^M | x$k <= c}) %
+                     (f:real^M->real^N) x) +
+    vsum p (\(x,l). content (l INTER {x:real^M | x$k >= c}) %
+                     (f:real^M->real^N) x)` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[GSYM VSUM_ADD] THEN MATCH_MP_TAC VSUM_EQ THEN
+    REWRITE_TAC[FORALL_PAIR_THM; GSYM VECTOR_ADD_RDISTRIB] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `l:real^M->bool`] THEN
+    DISCH_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+    DISCH_THEN(MP_TAC o SPECL [`x:real^M`; `l:real^M->bool`] o
+               el 1 o CONJUNCTS) THEN
+    ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[GSYM CONTENT_SPLIT]] THEN
+  ASM_SIMP_TAC[lemma3] THEN BINOP_TAC THEN
+  (GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [lemma4] THEN
+   MATCH_MP_TAC VSUM_IMAGE_NONZERO THEN ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+   REWRITE_TAC[PAIR_EQ] THEN
+   ASM_MESON_TAC[TAGGED_DIVISION_SPLIT_LEFT_INJ; VECTOR_MUL_LZERO;
+                 TAGGED_DIVISION_SPLIT_RIGHT_INJ]));;
+
+let EQUIINTEGRABLE_DIVISION = prove
+ (`!fs:(real^M->real^N)->bool d a b.
+        d division_of interval[a,b]
+        ==> (fs equiintegrable_on interval[a,b] <=>
+             !i. i IN d ==> fs equiintegrable_on i)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC OPERATIVE_DIVISION_AND THEN
+  ASM_REWRITE_TAC[operative; NEUTRAL_AND] THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN DISCH_TAC THEN
+    ASM_SIMP_TAC[equiintegrable_on; INTEGRABLE_ON_NULL] THEN
+    GEN_TAC THEN DISCH_TAC THEN EXISTS_TAC `\x:real^M. ball(x,&1)` THEN
+    ASM_SIMP_TAC[GAUGE_TRIVIAL; INTEGRAL_NULL; VECTOR_SUB_RZERO] THEN
+    REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (NORM_ARITH
+     `&0 < e ==> x = vec 0 ==> norm x < e`)) THEN
+    MATCH_MP_TAC VSUM_EQ_0 THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISJ1_TAC THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[TAGGED_DIVISION_OF]) THEN
+    ASM_MESON_TAC[CONTENT_EQ_0_INTERIOR; SUBSET_INTERIOR;
+                  SET_RULE `s = {} <=> s SUBSET {}`];
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`; `c:real`; `k:num`] THEN
+  STRIP_TAC THEN EQ_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[EQUIINTEGRABLE_ON_SPLIT]] THEN
+  ASM_SIMP_TAC[INTEGRABLE_SPLIT; equiintegrable_on] THEN
+  STRIP_TAC THEN CONJ_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 `d:real^M->real^M->bool` THEN
+   ASM_CASES_TAC `gauge(d:real^M->real^M->bool)` THEN ASM_REWRITE_TAC[] THEN
+   MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `f:real^M->real^N` THEN
+   ASM_CASES_TAC `(f:real^M->real^N) IN fs` THEN ASM_REWRITE_TAC[] THEN
+   DISCH_TAC THEN
+   MP_TAC(ISPECL [`f:real^M->real^N`; `a:real^M`; `b:real^M`;
+                  `d:real^M->real^M->bool`; `e / &2`]
+         HENSTOCK_LEMMA_PART1) THEN ASM_SIMP_TAC[REAL_HALF] THEN
+   MATCH_MP_TAC MONO_FORALL THEN
+   X_GEN_TAC `p:real^M#(real^M->bool)->bool` THEN
+   DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ANTS_TAC THENL
+    [ASM_REWRITE_TAC[] THEN MATCH_MP_TAC TAGGED_PARTIAL_DIVISION_OF_SUBSET THEN
+     RULE_ASSUM_TAC(REWRITE_RULE[tagged_division_of]) THEN
+     ASM_MESON_TAC[INTER_SUBSET];
+     ALL_TAC] THEN
+   MATCH_MP_TAC(NORM_ARITH
+    `&0 < e /\ x:real^N = y ==> norm(x) <= e / &2 ==> norm(y) < e`) THEN
+   ASM_REWRITE_TAC[] THEN ASM_SIMP_TAC[INTERVAL_SPLIT] THEN
+   W(MP_TAC o PART_MATCH (lhand o rand)
+     INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN o rand o rand o snd) THEN
+   ASM_SIMP_TAC[GSYM INTERVAL_SPLIT; INTEGRABLE_SPLIT] THEN
+   DISCH_THEN SUBST1_TAC THEN
+   FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+   ASM_SIMP_TAC[GSYM VSUM_SUB] THEN MATCH_MP_TAC VSUM_EQ THEN
+   REWRITE_TAC[FORALL_PAIR_THM]));;
+
+(* ------------------------------------------------------------------------- *)
+(* Main limit theorem for an equiintegrable sequence.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let EQUIINTEGRABLE_LIMIT = prove
+ (`!f g:real^M->real^N a b.
+        {f n | n IN (:num)} equiintegrable_on interval[a,b] /\
+        (!x. x IN interval[a,b] ==> ((\n. f n x) --> g x) sequentially)
+        ==> g integrable_on interval[a,b] /\
+            ((\n. integral(interval[a,b]) (f n)) --> integral(interval[a,b]) g)
+            sequentially`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  ASM_CASES_TAC `content(interval[a:real^M,b]) = &0` THEN
+  ASM_SIMP_TAC[INTEGRABLE_ON_NULL; INTEGRAL_NULL; LIM_CONST] THEN
+  SUBGOAL_THEN `cauchy (\n. integral(interval[a,b]) (f n :real^M->real^N))`
+  MP_TAC THENL
+   [REWRITE_TAC[cauchy] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [equiintegrable_on]) THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC; IN_UNIV] THEN
+    DISCH_TAC THEN REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] 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 `d:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP FINE_DIVISION_EXISTS) THEN
+    DISCH_THEN(MP_TAC o SPECL [`a:real^M`; `b:real^M`]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `p:(real^M#(real^M->bool))->bool`
+        STRIP_ASSUME_TAC) THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN `n:num` o SPECL
+     [`n:num`; `p:(real^M#(real^M->bool))->bool`]) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_TAC THEN SUBGOAL_THEN
+     `cauchy (\n. vsum p (\(x,k:real^M->bool).
+               content k % (f:num->real^M->real^N) n x))`
+    MP_TAC THENL
+     [MATCH_MP_TAC CONVERGENT_IMP_CAUCHY THEN
+      EXISTS_TAC `vsum p (\(x,k:real^M->bool).
+          content k % (g:real^M->real^N) x)` THEN
+      MATCH_MP_TAC
+       (REWRITE_RULE[LAMBDA_PAIR_THM]
+        (REWRITE_RULE[FORALL_PAIR_THM]
+         (ISPEC `\(x:real^M,k:real^M->bool) (n:num).
+                  content k % (f n x:real^N)` LIM_VSUM))) THEN
+      ASM_REWRITE_TAC[] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+      MATCH_MP_TAC LIM_CMUL THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+      ASM_SIMP_TAC[SUBSET] THEN ASM_MESON_TAC[];
+      REWRITE_TAC[cauchy] THEN DISCH_THEN(MP_TAC o SPEC `e / &3`) THEN
+      ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+      REWRITE_TAC[IMP_IMP; RIGHT_IMP_FORALL_THM; GE] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `m:num` THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `n:num` THEN
+      ASM_CASES_TAC `N:num <= m /\ N <= n` THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(NORM_ARITH
+       `norm(sm - gm:real^N) < e / &3 /\ norm(sn - gn) < e / &3
+        ==> dist(sm,sn) < e / &3 ==> dist(gm,gn) < e`) THEN
+      ASM_REWRITE_TAC[]];
+    REWRITE_TAC[GSYM CONVERGENT_EQ_CAUCHY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `l:real^N`) THEN
+    SUBGOAL_THEN `((g:real^M->real^N) has_integral l) (interval[a,b])`
+     (fun th -> ASM_MESON_TAC[th; integrable_on; INTEGRAL_UNIQUE]) THEN
+    REWRITE_TAC[has_integral] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [equiintegrable_on]) THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC; IN_UNIV] THEN
+    DISCH_TAC THEN REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real^M->real^M->bool` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `p:(real^M#(real^M->bool))->bool` THEN STRIP_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(ISPEC `sequentially` LIM_NORM_UBOUND) THEN
+    EXISTS_TAC `\n:num. vsum p (\(x,k:real^M->bool). content k % f n x) -
+                       integral (interval [a,b]) (f n :real^M->real^N)` THEN
+    ASM_SIMP_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[EVENTUALLY_TRUE] THEN
+    MATCH_MP_TAC LIM_SUB THEN ASM_REWRITE_TAC[] THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+    MATCH_MP_TAC
+     (REWRITE_RULE[LAMBDA_PAIR_THM]
+      (REWRITE_RULE[FORALL_PAIR_THM]
+       (ISPEC `\(x:real^M,k:real^M->bool) (n:num).
+                content k % (f n x:real^N)` LIM_VSUM))) THEN
+    ASM_REWRITE_TAC[] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+    MATCH_MP_TAC LIM_CMUL THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+    ASM_SIMP_TAC[SUBSET] THEN ASM_MESON_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Combining theorems for the set of equiintegrable functions.               *)
+(* ------------------------------------------------------------------------- *)
+
+let EQUIINTEGRABLE_SUBSET = prove
+ (`!fs gs s.
+   fs equiintegrable_on s /\ gs SUBSET fs ==> gs equiintegrable_on s`,
+  REWRITE_TAC[equiintegrable_on; SUBSET] THEN MESON_TAC[]);;
+
+let EQUIINTEGRABLE_UNION = prove
+ (`!fs:(real^M->real^N)->bool gs s.
+        fs equiintegrable_on s /\ gs equiintegrable_on s
+        ==> (fs UNION gs) equiintegrable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[equiintegrable_on; IN_UNION] THEN
+  REWRITE_TAC[TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `e:real`)) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d2:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\x. (d1:real^M->real^M->bool) x INTER d2 x` THEN
+  ASM_SIMP_TAC[GAUGE_INTER; FINE_INTER] THEN
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[]);;
+
+let EQUIINTEGRABLE_EQ = prove
+ (`!fs gs:(real^M->real^N)->bool s.
+        fs equiintegrable_on s /\
+        (!g. g IN gs ==> ?f. f IN fs /\ (!x. x IN s ==> f x = g x))
+        ==> gs equiintegrable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[equiintegrable_on] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC (LABEL_TAC "*")) THEN
+  CONJ_TAC THENL
+   [X_GEN_TAC `g:real^M->real^N` THEN DISCH_TAC THEN
+    REMOVE_THEN "*" (MP_TAC o SPEC `g:real^M->real^N`) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `f:real^M->real^N` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `f:real^M->real^N`) THEN
+    ASM_MESON_TAC[INTEGRABLE_SPIKE; IN_DIFF; NEGLIGIBLE_EMPTY];
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real^M->real^M->bool` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MAP_EVERY X_GEN_TAC
+     [`g:real^M->real^N`;`p:(real^M#(real^M->bool))->bool`] THEN
+    STRIP_TAC THEN REMOVE_THEN "*" (MP_TAC o SPEC `g:real^M->real^N`) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `f:real^M->real^N` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`f:real^M->real^N`;`p:(real^M#(real^M->bool))->bool`]) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(MESON[]
+     `x:real^N = y /\ a = b ==> norm(x - a) < e ==> norm(y - b) < e`) THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC VSUM_EQ THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[TAGGED_DIVISION_OF; SUBSET]) THEN
+      ASM_MESON_TAC[];
+      ASM_MESON_TAC[INTEGRAL_EQ]]]);;
+
+let EQUIINTEGRABLE_CMUL = prove
+ (`!fs:(real^M->real^N)->bool s k.
+        fs equiintegrable_on s
+        ==> {(\x. c % f x) | abs(c) <= k /\ f IN fs} equiintegrable_on s`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[equiintegrable_on; INTEGRABLE_CMUL; FORALL_IN_GSPEC] THEN
+  STRIP_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC] THEN
+  ASM_SIMP_TAC[RIGHT_IMP_FORALL_THM; INTEGRAL_CMUL; IMP_IMP] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e / (abs(k) + &1)`) THEN
+  ASM_SIMP_TAC[REAL_LT_RDIV_EQ; REAL_MUL_LZERO;
+               REAL_ARITH `&0 < abs(k) + &1`] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real^M->real^M->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`c:real`; `f:real^M->real^N`;
+                       `p:(real^M#(real^M->bool))->bool`] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o
+   SPECL [`f:real^M->real^N`; `p:(real^M#(real^M->bool))->bool`]) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_LET_TRANS) THEN
+  MATCH_MP_TAC(REAL_ARITH `&0 <= y /\ x <= c * y ==> x <= y * (c + &1)`) THEN
+  REWRITE_TAC[NORM_POS_LE] THEN MATCH_MP_TAC(REAL_ARITH
+   `!c. x = c * y /\ c *  y <= k * y ==> x <= k * y`) THEN
+  EXISTS_TAC `abs c:real` THEN CONJ_TAC THENL
+   [REWRITE_TAC[GSYM NORM_MUL; GSYM VSUM_LMUL; VECTOR_SUB_LDISTRIB] THEN
+    REWRITE_TAC[LAMBDA_PAIR_THM; VECTOR_MUL_ASSOC; REAL_MUL_SYM];
+    MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let EQUIINTEGRABLE_ADD = prove
+ (`!fs:(real^M->real^N)->bool gs s.
+        fs equiintegrable_on s /\ gs equiintegrable_on s
+        ==> {(\x. f x + g x) | f IN fs /\ g IN gs} equiintegrable_on s`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[equiintegrable_on; INTEGRABLE_ADD; FORALL_IN_GSPEC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "f"))
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "g"))) THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC] THEN
+  ASM_SIMP_TAC[RIGHT_IMP_FORALL_THM; INTEGRAL_ADD; IMP_IMP] THEN
+  REMOVE_THEN "g" (MP_TAC o SPEC `e / &2`) THEN
+  REMOVE_THEN "f" (MP_TAC o SPEC `e / &2`) THEN
+  ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real^M->real^M->bool`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "f"))) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d2:real^M->real^M->bool`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "g"))) THEN
+  EXISTS_TAC `\x. (d1:real^M->real^M->bool) x INTER d2 x` THEN
+  ASM_SIMP_TAC[GAUGE_INTER; FINE_INTER] THEN
+  MAP_EVERY X_GEN_TAC [`f:real^M->real^N`; `g:real^M->real^N`;
+                       `p:(real^M#(real^M->bool))->bool`] THEN STRIP_TAC THEN
+  REMOVE_THEN "g" (MP_TAC o SPECL
+   [`g:real^M->real^N`; `p:(real^M#(real^M->bool))->bool`]) THEN
+  REMOVE_THEN "f" (MP_TAC o SPECL
+   [`f:real^M->real^N`; `p:(real^M#(real^M->bool))->bool`]) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(NORM_ARITH
+   `s + s' = t
+    ==> norm(s - i) < e / &2 ==> norm(s' - i') < e / &2
+        ==> norm(t - (i + i')) < e`) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  ASM_SIMP_TAC[GSYM VSUM_ADD] THEN
+  REWRITE_TAC[LAMBDA_PAIR_THM; VECTOR_ADD_LDISTRIB]);;
+
+let EQUIINTEGRABLE_NEG = prove
+ (`!fs:(real^M->real^N)->bool s.
+        fs equiintegrable_on s
+        ==> {(\x. --(f x)) | f IN fs} equiintegrable_on s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `&1` o MATCH_MP EQUIINTEGRABLE_CMUL) THEN
+  MATCH_MP_TAC (REWRITE_RULE[IMP_CONJ_ALT] EQUIINTEGRABLE_SUBSET) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  X_GEN_TAC `f:real^M->real^N` THEN DISCH_TAC THEN EXISTS_TAC `-- &1` THEN
+  EXISTS_TAC `f:real^M->real^N` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LNEG; VECTOR_MUL_LID] THEN REAL_ARITH_TAC);;
+
+let EQUIINTEGRABLE_SUB = prove
+ (`!fs:(real^M->real^N)->bool gs s.
+        fs equiintegrable_on s /\ gs equiintegrable_on s
+        ==> {(\x. f x - g x) | f IN fs /\ g IN gs} equiintegrable_on s`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2
+   MP_TAC (MP_TAC o MATCH_MP EQUIINTEGRABLE_NEG)) THEN
+  REWRITE_TAC[GSYM IMP_CONJ_ALT] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP EQUIINTEGRABLE_ADD) THEN
+  MATCH_MP_TAC (REWRITE_RULE[IMP_CONJ_ALT] EQUIINTEGRABLE_SUBSET) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  MAP_EVERY X_GEN_TAC [`f:real^M->real^N`; `g:real^M->real^N`] THEN
+  STRIP_TAC THEN EXISTS_TAC `f:real^M->real^N` THEN
+  EXISTS_TAC `\x. --((g:real^M->real^N) x)` THEN
+  ASM_REWRITE_TAC[VECTOR_SUB] THEN EXISTS_TAC `g:real^M->real^N` THEN
+  ASM_REWRITE_TAC[]);;
+
+let EQUIINTEGRABLE_SUM = prove
+ (`!fs:(real^M->real^N)->bool a b.
+        fs equiintegrable_on interval[a,b]
+        ==> {(\x. vsum t (\i. c i % f i x)) |
+               FINITE t /\
+               (!i:A. i IN t ==> &0 <= c i /\ (f i) IN fs) /\
+               sum t c = &1}
+            equiintegrable_on interval[a,b]`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[equiintegrable_on] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC; RIGHT_IMP_FORALL_THM] THEN
+  STRIP_TAC THEN
+  ASM (CONV_TAC o GEN_SIMPLIFY_CONV TOP_DEPTH_SQCONV (basic_ss []) 5)
+   [INTEGRABLE_CMUL; INTEGRABLE_VSUM; ETA_AX; INTEGRAL_VSUM] 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 `d:real^M->real^M->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN MAP_EVERY X_GEN_TAC
+   [`t:A->bool`; `c:A->real`; `f:A->real^M->real^N`;
+    `p:(real^M#(real^M->bool))->bool`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!i:A. i IN t
+          ==> integral (interval[a,b]) (\x:real^M. c i % f i x:real^N) =
+              vsum p (\(x:real^M,k).
+                       integral (k:real^M->bool) (\x:real^M. c i % f i x))`
+   (fun th -> SIMP_TAC[th])
+  THENL
+   [REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN THEN
+    ASM_SIMP_TAC[INTEGRABLE_CMUL; ETA_AX];
+    ALL_TAC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  SUBGOAL_THEN
+   `vsum p (\(x,k:real^M->bool). content k % vsum t (\i. c i % f i x)) =
+    vsum t (\i. c i %
+                vsum p (\(x,k). content k % (f:A->real^M->real^N) i x))`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[GSYM VSUM_LMUL] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) VSUM_SWAP o
+      rand o snd) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
+    MATCH_MP_TAC VSUM_EQ THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC; REAL_MUL_SYM];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `sum t (\i:A. c i * e / &2)` THEN CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[SUM_RMUL; ETA_AX; REAL_MUL_LID] THEN ASM_REAL_ARITH_TAC] THEN
+  ASM_SIMP_TAC[GSYM VSUM_SUB] THEN MATCH_MP_TAC VSUM_NORM_LE THEN
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `i:A` THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[GSYM VSUM_LMUL; GSYM VSUM_SUB] THEN
+  REWRITE_TAC[LAMBDA_PAIR_THM] THEN FIRST_X_ASSUM(MP_TAC o SPECL
+   [`(f:A->real^M->real^N) i`; `p:(real^M#(real^M->bool))->bool`]) THEN
+  ASM_SIMP_TAC[] THEN DISCH_THEN(MP_TAC o MATCH_MP REAL_LT_IMP_LE) THEN
+  DISCH_THEN(MP_TAC o SPEC `abs((c:A->real) i)` o
+    MATCH_MP(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_LMUL)) THEN
+  ASM_REWRITE_TAC[REAL_ABS_POS; GSYM NORM_MUL] THEN
+  ASM_SIMP_TAC[GSYM VSUM_LMUL; VECTOR_SUB_LDISTRIB; real_abs] THEN
+  REWRITE_TAC[LAMBDA_PAIR_THM] THEN
+  MATCH_MP_TAC(REAL_ARITH `x = y ==> x <= a ==> y <= a`) THEN
+  AP_TERM_TAC THEN
+  SUBGOAL_THEN
+   `integral (interval[a,b]) ((f:A->real^M->real^N) i) =
+    vsum p (\(x:real^M,k). integral (k:real^M->bool) (f i))`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN THEN ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM VSUM_LMUL; GSYM VSUM_SUB] THEN
+  MATCH_MP_TAC VSUM_EQ THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+  AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC INTEGRAL_CMUL THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[TAGGED_DIVISION_OF]) THEN
+  ASM_MESON_TAC[INTEGRABLE_SUBINTERVAL]);;
+
+let EQUIINTEGRABLE_UNIFORM_LIMIT = prove
+ (`!fs:(real^M->real^N)->bool a b.
+        fs equiintegrable_on interval[a,b]
+        ==> {g | !e. &0 < e
+                     ==> ?f. f IN fs /\
+                             !x. x IN interval[a,b] ==> norm(g x - f x) < e}
+            equiintegrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [equiintegrable_on]) THEN
+  REWRITE_TAC[equiintegrable_on; IN_ELIM_THM] THEN REPEAT GEN_TAC THEN
+  STRIP_TAC THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[INTEGRABLE_UNIFORM_LIMIT; REAL_LT_IMP_LE]; ALL_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 `d:real^M->real^M->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN MAP_EVERY X_GEN_TAC
+   [`g:real^M->real^N`;`p:(real^M#(real^M->bool))->bool`] THEN
+  STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  SUBGOAL_THEN `(g:real^M->real^N) integrable_on interval[a,b]`
+  ASSUME_TAC THENL
+   [ASM_MESON_TAC[INTEGRABLE_UNIFORM_LIMIT; REAL_LT_IMP_LE]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN `n:num` o SPEC `inv(&n + &1)`) THEN
+  REWRITE_TAC[REAL_LT_INV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+  REWRITE_TAC[SKOLEM_THM; FORALL_AND_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `f:num->real^M->real^N` THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x. x IN interval[a,b]
+        ==> ((\n. f n x) --> (g:real^M->real^N) x) sequentially`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    REWRITE_TAC[LIM_SEQUENTIALLY] THEN X_GEN_TAC `k:real` THEN DISCH_TAC THEN
+    MP_TAC(SPEC `k:real` REAL_ARCH_INV) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+    STRIP_TAC THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+    REWRITE_TAC[NORM_ARITH `dist(a:real^N,b) = norm(b - a)`] THEN
+    MATCH_MP_TAC REAL_LT_TRANS THEN EXISTS_TAC `inv(&n + &1)` THEN
+    ASM_SIMP_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
+    REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+    ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`f:num->real^M->real^N`; `g:real^M->real^N`;
+                 `a:real^M`; `b:real^M`] EQUIINTEGRABLE_LIMIT) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN MATCH_MP_TAC EQUIINTEGRABLE_SUBSET THEN
+    EXISTS_TAC `fs:(real^M->real^N)->bool` THEN ASM SET_TAC[];
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "*"))] THEN
+  SUBGOAL_THEN
+   `((\n. vsum p (\(x,k:real^M->bool).
+                    content k % (f:num->real^M->real^N) n x)) -->
+     vsum p (\(x,k). content k % g x)) sequentially`
+   (LABEL_TAC "+")
+  THENL
+   [MATCH_MP_TAC
+       (REWRITE_RULE[LAMBDA_PAIR_THM]
+        (REWRITE_RULE[FORALL_PAIR_THM]
+         (ISPEC `\(x:real^M,k:real^M->bool) (n:num).
+                  content k % (f n x:real^N)` LIM_VSUM))) THEN
+    ASM_REWRITE_TAC[] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+    MATCH_MP_TAC LIM_CMUL THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+    ASM_SIMP_TAC[SUBSET] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  REMOVE_THEN "*" (MP_TAC o REWRITE_RULE[LIM_SEQUENTIALLY]) THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &4`) THEN
+  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; REWRITE_TAC[dist]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N1:num` (LABEL_TAC "*")) THEN
+  REMOVE_THEN "+" (MP_TAC o REWRITE_RULE[LIM_SEQUENTIALLY]) THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &4`) THEN
+  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; REWRITE_TAC[dist]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N2:num` (LABEL_TAC "+")) THEN
+  SUBGOAL_THEN `?n:num. N1 <= n /\ N2 <= n` STRIP_ASSUME_TAC THENL
+   [EXISTS_TAC `N1 + N2:num` THEN ARITH_TAC; ALL_TAC] THEN
+  REMOVE_THEN "*" (MP_TAC o SPEC `n:num`) THEN
+  REMOVE_THEN "+" (MP_TAC o SPEC `n:num`) THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+   [`(f:num->real^M->real^N) n`;`p:(real^M#(real^M->bool))->bool`]) THEN
+  ASM_REWRITE_TAC[] THEN NORM_ARITH_TAC);;
+
+let EQUIINTEGRABLE_REFLECT = prove
+ (`!fs:(real^M->real^N)->bool a b.
+        fs equiintegrable_on interval[a,b]
+        ==> {(\x. f(--x)) | f IN fs} equiintegrable_on interval[--b,--a]`,
+  let lemma = prove
+   (`(!x k. (x,k) IN IMAGE (\(x,k). f x k,g x k) s ==> Q x k) <=>
+     (!x k. (x,k) IN s ==> Q (f x k) (g x k))`,
+    REWRITE_TAC[IN_IMAGE; PAIR_EQ; EXISTS_PAIR_THM] THEN SET_TAC[]) in
+  REPEAT GEN_TAC THEN REWRITE_TAC[equiintegrable_on] THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ; FORALL_IN_GSPEC] THEN
+  DISCH_TAC THEN DISCH_TAC THEN
+  ASM_REWRITE_TAC[INTEGRABLE_REFLECT; INTEGRAL_REFLECT] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(K ALL_TAC o check (is_forall o concl)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\x. IMAGE (--) ((d:real^M->real^M->bool) (--x))` THEN
+  CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [gauge]) THEN
+    SIMP_TAC[gauge; OPEN_NEGATIONS] THEN DISCH_TAC THEN
+    GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_NEG_NEG] THEN
+    MATCH_MP_TAC FUN_IN_IMAGE THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  X_GEN_TAC `f:real^M->real^N` THEN DISCH_TAC THEN
+  X_GEN_TAC `p:real^M#(real^M->bool)->bool` THEN REPEAT DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `f:real^M->real^N`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `IMAGE (\(x,k). (--x:real^M,IMAGE (--) (k:real^M->bool))) p`) THEN
+  ANTS_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+    REWRITE_TAC[TAGGED_DIVISION_OF] THEN
+    STRIP_TAC THEN ASM_SIMP_TAC[FINITE_IMAGE] THEN
+    REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ; lemma] THEN
+    REPEAT CONJ_TAC THENL
+     [MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+      ASM_SIMP_TAC[FUN_IN_IMAGE] THEN CONJ_TAC THENL
+       [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+        ONCE_REWRITE_TAC[GSYM IN_INTERVAL_REFLECT] THEN
+        ASM_SIMP_TAC[VECTOR_NEG_NEG; GSYM SUBSET] THEN ASM_MESON_TAC[];
+        REWRITE_TAC[EXTENSION; IN_IMAGE] THEN
+        REWRITE_TAC[VECTOR_ARITH `x:real^N = --y <=> --x = y`] THEN
+        ONCE_REWRITE_TAC[GSYM IN_INTERVAL_REFLECT] THEN
+        REWRITE_TAC[UNWIND_THM1] THEN
+        SUBGOAL_THEN `?u v:real^M. k = interval[u,v]`
+         (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+        THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+        ASM_MESON_TAC[VECTOR_NEG_NEG]];
+      MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+      MAP_EVERY X_GEN_TAC [`y:real^M`; `l:real^M->bool`] THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL
+       [`x:real^M`; `k:real^M->bool`;
+        `y:real^M`; `l:real^M->bool`]) THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_IMP THEN
+      CONJ_TAC THENL [MESON_TAC[PAIR_EQ]; ALL_TAC] THEN
+      REWRITE_TAC[INTERIOR_NEGATIONS] THEN
+      MATCH_MP_TAC(SET_RULE
+       `(!x. f(f x) = x)
+        ==> s INTER t = {} ==> IMAGE f s INTER IMAGE f t = {}`) THEN
+      REWRITE_TAC[VECTOR_NEG_NEG];
+      GEN_REWRITE_TAC I [EXTENSION] THEN
+      ONCE_REWRITE_TAC[GSYM IN_INTERVAL_REFLECT] THEN
+      FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN X_GEN_TAC `y:real^M` THEN
+      REWRITE_TAC[IN_UNIONS; IN_ELIM_THM] THEN
+      MATCH_MP_TAC(MESON[]
+       `!f. (!x. f(f x) = x) /\ (!x. P x <=> Q(f x))
+            ==> ((?x. P x) <=> (?x. Q x))`) THEN
+      EXISTS_TAC `IMAGE ((--):real^M->real^M)` THEN CONJ_TAC THENL
+       [REWRITE_TAC[GSYM IMAGE_o; o_DEF; VECTOR_NEG_NEG; IMAGE_ID];
+        ALL_TAC] THEN
+      X_GEN_TAC `t:real^M->bool` THEN BINOP_TAC THENL
+       [REWRITE_TAC[IN_IMAGE; EXISTS_PAIR_THM; PAIR_EQ] THEN
+        SUBGOAL_THEN `!k:real^M->bool. IMAGE (--) (IMAGE (--) k) = k`
+        MP_TAC THENL
+         [REWRITE_TAC[GSYM IMAGE_o; o_DEF; VECTOR_NEG_NEG; IMAGE_ID];
+          MESON_TAC[]];
+        MATCH_MP_TAC(SET_RULE
+         `(!x. f(f x) = x) ==> (y IN s <=> f y IN IMAGE f s)`) THEN
+        REWRITE_TAC[VECTOR_NEG_NEG]]];
+    ANTS_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+      REWRITE_TAC[fine; lemma] THEN
+      REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+      MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+      MATCH_MP_TAC(SET_RULE
+       `(!x. f(f x) = x) ==> k SUBSET IMAGE f s ==> IMAGE f k SUBSET s`) THEN
+      REWRITE_TAC[VECTOR_NEG_NEG];
+      ALL_TAC] THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `x:real^N = y ==> norm(x - i) < e ==> norm(y - i) < e`) THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) VSUM_IMAGE o lhs o snd) THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [MATCH_MP_TAC(MESON[]
+       `(!x. f(f x) = x)
+        ==> !x y. x IN p /\ y IN p /\ f x = f y ==> x = y`) THEN
+      REWRITE_TAC[FORALL_PAIR_THM; GSYM IMAGE_o; o_DEF; VECTOR_NEG_NEG;
+                  IMAGE_ID];
+      DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC VSUM_EQ THEN
+      REWRITE_TAC[FORALL_PAIR_THM; o_THM] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+      SUBGOAL_THEN `?u v:real^M. k = interval[u,v]`
+       (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+      THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+      AP_THM_TAC THEN AP_TERM_TAC THEN
+      SUBGOAL_THEN `(--):real^M->real^M = (\x. --(&1) % x + vec 0)` SUBST1_TAC
+      THENL [REWRITE_TAC[FUN_EQ_THM] THEN VECTOR_ARITH_TAC; ALL_TAC] THEN
+      REWRITE_TAC[CONTENT_IMAGE_AFFINITY_INTERVAL; REAL_ABS_NEG] THEN
+      REWRITE_TAC[REAL_POW_ONE; REAL_MUL_LID; REAL_ABS_NUM]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some technical lemmas about minimizing a "flat" part of a sum over a      *)
+(* division, followed by subinterval resictions for equiintegrable family.   *)
+(* ------------------------------------------------------------------------- *)
+
+let SUM_CONTENT_AREA_OVER_THIN_DIVISION = prove
+ (`!d a b:real^M s i c.
+        d division_of s /\ s SUBSET interval[a,b] /\
+        1 <= i /\ i <= dimindex(:M) /\ a$i <= c /\ c <= b$i /\
+        (!k. k IN d ==> ~(k INTER {x | x$i = c} = {}))
+        ==> (b$i - a$i) *
+            sum d (\k. content k /
+                       (interval_upperbound k$i - interval_lowerbound k$i))
+            <= &2 * content(interval[a,b])`,
+  let lemma0 = prove
+   (`!k:real^M->bool i.
+          1 <= i /\ i <= dimindex(:M)
+          ==> content k / (interval_upperbound k$i - interval_lowerbound k$i) =
+              if content k = &0 then &0
+              else product ((1..dimindex(:M)) DELETE i)
+                           (\j. interval_upperbound k$j -
+                                interval_lowerbound k$j)`,
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[real_div; REAL_MUL_LZERO] THEN
+    REWRITE_TAC[content] THEN
+    COND_CASES_TAC THENL [ASM_MESON_TAC[CONTENT_EMPTY]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `1..dimindex(:M) = i INSERT ((1..dimindex(:M)) DELETE i)`
+    MP_TAC THENL
+     [REWRITE_TAC[SET_RULE `s = x INSERT (s DELETE x) <=> x IN s`] THEN
+      ASM_REWRITE_TAC[IN_NUMSEG];
+      DISCH_THEN(fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+       [th])] THEN
+    ASM_SIMP_TAC[PRODUCT_CLAUSES; IN_NUMSEG; FINITE_DELETE; FINITE_NUMSEG;
+                 IN_DELETE] THEN
+    MATCH_MP_TAC(REAL_FIELD `~(y = &0) ==> (y * x) * inv y = x`) THEN
+    DISCH_TAC THEN
+    UNDISCH_TAC `~(content(k:real^M->bool) = &0)` THEN
+    ASM_REWRITE_TAC[content; PRODUCT_EQ_0_NUMSEG] THEN ASM_MESON_TAC[])
+  and lemma1 = prove
+   (`!d a b:real^M s i.
+          d division_of s /\ s SUBSET interval[a,b] /\
+          1 <= i /\ i <= dimindex(:M) /\
+          ((!k. k IN d
+                ==> ~(content k = &0) /\ ~(k INTER {x | x$i = a$i} = {})) \/
+           (!k. k IN d
+                ==> ~(content k = &0) /\ ~(k INTER {x | x$i = b$i} = {})))
+          ==> (b$i - a$i) *
+              sum d (\k. content k /
+                         (interval_upperbound k$i - interval_lowerbound k$i))
+              <= content(interval[a,b])`,
+    REPEAT GEN_TAC THEN DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+    ABBREV_TAC
+     `extend =
+      \k:real^M->bool. interval
+           [(lambda j. if j = i then (a:real^M)$i
+                       else interval_lowerbound k$j):real^M,
+            (lambda j. if j = i then (b:real^M)$i
+                       else interval_upperbound k$j)]` THEN
+    SUBGOAL_THEN `!k. k IN d ==> k SUBSET interval[a:real^M,b]`
+    ASSUME_TAC THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[division_of]) THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `!k:real^M->bool. k IN d ==> ~(k = {})` ASSUME_TAC THENL
+     [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `(!k. k IN d ==> ~((extend:(real^M->bool)->(real^M->bool)) k = {})) /\
+      (!k. k IN d ==> extend k SUBSET interval[a,b])`
+    STRIP_ASSUME_TAC THENL
+     [FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+      CONJ_TAC THEN MAP_EVERY X_GEN_TAC [`u:real^M`; `v:real^M`] THEN
+      (DISCH_TAC THEN EXPAND_TAC "extend" THEN
+       SUBGOAL_THEN `interval[u:real^M,v] SUBSET interval[a,b]` MP_TAC THENL
+        [ASM_SIMP_TAC[]; ALL_TAC] THEN
+       SUBGOAL_THEN `~(interval[u:real^M,v] = {})` MP_TAC THENL
+        [ASM_SIMP_TAC[]; ALL_TAC] THEN
+       SIMP_TAC[SUBSET_INTERVAL; INTERVAL_NE_EMPTY; LAMBDA_BETA;
+                INTERVAL_LOWERBOUND; INTERVAL_UPPERBOUND] THEN
+       MESON_TAC[REAL_LE_TRANS; REAL_LE_REFL]);
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!k1 k2. k1 IN d /\ k2 IN d /\ ~(k1 = k2)
+              ==> interior((extend:(real^M->bool)->(real^M->bool)) k1) INTER
+                  interior(extend k2) = {}`
+    ASSUME_TAC THENL
+     [REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+      FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+      MAP_EVERY X_GEN_TAC [`u:real^M`; `v:real^M`] THEN DISCH_TAC THEN
+      MAP_EVERY X_GEN_TAC [`w:real^M`; `z:real^M`] THEN DISCH_TAC THEN
+      DISCH_TAC THEN
+      FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+      DISCH_THEN(MP_TAC o el 2 o CONJUNCTS) THEN DISCH_THEN(MP_TAC o SPECL
+       [`interval[u:real^M,v]`; `interval[w:real^M,z]`]) THEN
+      ASM_REWRITE_TAC[INTERIOR_CLOSED_INTERVAL] THEN
+      ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+      EXPAND_TAC "extend" THEN
+      SIMP_TAC[INTERIOR_CLOSED_INTERVAL; IN_INTERVAL; LAMBDA_BETA] THEN
+      SUBGOAL_THEN `~(interval[u:real^M,v] = {}) /\
+                    ~(interval[w:real^M,z] = {})`
+      MP_TAC THENL [ASM_SIMP_TAC[]; ALL_TAC] THEN
+      SIMP_TAC[SUBSET_INTERVAL; INTERVAL_NE_EMPTY; LAMBDA_BETA;
+               INTERVAL_LOWERBOUND; INTERVAL_UPPERBOUND] THEN
+      STRIP_TAC THEN DISCH_THEN(X_CHOOSE_THEN `x:real^M` MP_TAC) THEN
+      MP_TAC(MESON[]
+       `(!P. (!j:num. P j) <=> P i /\ (!j. ~(j = i) ==> P j))`) THEN
+      DISCH_THEN(fun th -> GEN_REWRITE_TAC
+       (LAND_CONV o ONCE_DEPTH_CONV) [th]) THEN
+      ASM_SIMP_TAC[IMP_IMP] THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(DISJ_CASES_THEN
+       (fun th -> MP_TAC(SPEC `interval[u:real^M,v]` th) THEN
+                  MP_TAC(SPEC `interval[w:real^M,z]` th))) THEN
+      ASM_REWRITE_TAC[CONTENT_EQ_0_INTERIOR; INTERIOR_CLOSED_INTERVAL] THEN
+      REWRITE_TAC[IMP_CONJ; GSYM MEMBER_NOT_EMPTY; IN_INTER; IN_ELIM_THM] THEN
+      REWRITE_TAC[IN_INTERVAL; LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `q:real^M` THEN STRIP_TAC THEN
+      X_GEN_TAC `r:real^M` THEN STRIP_TAC THEN
+      X_GEN_TAC `s:real^M` THEN STRIP_TAC THEN
+      X_GEN_TAC `t:real^M` THEN STRIP_TAC THENL
+       [EXISTS_TAC `(lambda j. if j = i then min ((q:real^M)$i) ((s:real^M)$i)
+                               else (x:real^M)$j):real^M`;
+        EXISTS_TAC `(lambda j. if j = i then max ((q:real^M)$i) ((s:real^M)$i)
+                               else (x:real^M)$j):real^M`] THEN
+      (SIMP_TAC[AND_FORALL_THM; LAMBDA_BETA] THEN X_GEN_TAC `j:num` THEN
+       ASM_CASES_TAC `j:num = i` THEN ASM_SIMP_TAC[] THEN
+       UNDISCH_THEN `j:num = i` SUBST_ALL_TAC THEN
+       SUBGOAL_THEN `interval[u:real^M,v] SUBSET interval[a,b] /\
+                     interval[w:real^M,z] SUBSET interval[a,b]`
+       MP_TAC THENL [ASM_SIMP_TAC[]; ALL_TAC] THEN
+       SUBGOAL_THEN `~(interval[u:real^M,v] = {}) /\
+                     ~(interval[w:real^M,z] = {})`
+       MP_TAC THENL [ASM_SIMP_TAC[]; ALL_TAC] THEN
+       SIMP_TAC[INTERVAL_NE_EMPTY; SUBSET_INTERVAL] THEN
+       REPEAT STRIP_TAC THEN
+       REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `i:num`)) THEN ASM_REWRITE_TAC[] THEN
+       ASM_REAL_ARITH_TAC);
+      ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+     `sum (IMAGE (extend:(real^M->bool)->(real^M->bool)) d) content` THEN
+    CONJ_TAC THENL
+     [W(MP_TAC o PART_MATCH (lhs o rand) SUM_IMAGE_NONZERO o rand o snd) THEN
+      ANTS_TAC THENL
+       [ASM_REWRITE_TAC[] THEN
+        MAP_EVERY X_GEN_TAC [`k1:real^M->bool`; `k2:real^M->bool`] THEN
+        STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+         [`k1:real^M->bool`; `k2:real^M->bool`]) THEN
+        ASM_REWRITE_TAC[INTER_IDEMPOT] THEN
+        EXPAND_TAC "extend" THEN REWRITE_TAC[CONTENT_EQ_0_INTERIOR];
+        DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[GSYM SUM_LMUL] THEN
+        MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[] THEN
+        FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+        MAP_EVERY X_GEN_TAC [`u:real^M`; `v:real^M`] THEN DISCH_TAC THEN
+        ASM_CASES_TAC `content(interval[u:real^M,v]) = &0` THENL
+         [ASM_REWRITE_TAC[real_div; REAL_MUL_LZERO; REAL_MUL_RZERO; o_THM] THEN
+          EXPAND_TAC "extend" THEN REWRITE_TAC[CONTENT_POS_LE];
+          ALL_TAC] THEN
+        FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM CONTENT_LT_NZ]) THEN
+        DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+        REWRITE_TAC[CONTENT_POS_LT_EQ] THEN STRIP_TAC THEN
+        ASM_SIMP_TAC[INTERVAL_LOWERBOUND; INTERVAL_UPPERBOUND;
+                     REAL_LT_IMP_LE; real_div; REAL_MUL_ASSOC] THEN
+        ASM_SIMP_TAC[GSYM real_div; REAL_LE_LDIV_EQ; REAL_SUB_LT] THEN
+        SUBGOAL_THEN
+         `~((extend:(real^M->bool)->(real^M->bool)) (interval[u,v]) = {})`
+        MP_TAC THENL [ASM_SIMP_TAC[]; ALL_TAC] THEN
+        EXPAND_TAC "extend" THEN ASM_SIMP_TAC[content; o_THM] THEN
+        ASM_SIMP_TAC[INTERVAL_NE_EMPTY; INTERVAL_LOWERBOUND;
+                     INTERVAL_UPPERBOUND; REAL_LT_IMP_LE] THEN
+        DISCH_THEN(K ALL_TAC) THEN
+        SUBGOAL_THEN
+         `1..dimindex(:M) = i INSERT ((1..dimindex(:M)) DELETE i)`
+        SUBST1_TAC THENL
+         [MATCH_MP_TAC(SET_RULE `x IN s ==> s = x INSERT (s DELETE x)`) THEN
+          ASM_REWRITE_TAC[IN_NUMSEG];
+          ALL_TAC] THEN
+        SIMP_TAC[PRODUCT_CLAUSES; FINITE_NUMSEG; FINITE_DELETE] THEN
+        ASM_SIMP_TAC[IN_DELETE; IN_NUMSEG; LAMBDA_BETA] THEN
+        MATCH_MP_TAC REAL_EQ_IMP_LE THEN MATCH_MP_TAC(REAL_RING
+          `x:real = y ==> ab * uv * x = (ab * y) * uv`) THEN
+        MATCH_MP_TAC PRODUCT_EQ THEN
+        SIMP_TAC[IN_DELETE; IN_NUMSEG; LAMBDA_BETA]];
+      MATCH_MP_TAC SUBADDITIVE_CONTENT_DIVISION THEN EXISTS_TAC
+       `UNIONS (IMAGE (extend:(real^M->bool)->(real^M->bool)) d)` THEN
+      ASM_SIMP_TAC[UNIONS_SUBSET; division_of; FINITE_IMAGE] THEN
+      REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+      FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+      REPEAT CONJ_TAC THEN MAP_EVERY X_GEN_TAC [`u:real^M`; `v:real^M`] THEN
+      DISCH_TAC THENL
+       [CONJ_TAC THENL [ASM SET_TAC[]; ASM_SIMP_TAC[]] THEN
+        EXPAND_TAC "extend" THEN REWRITE_TAC[] THEN MESON_TAC[];
+        ASM_MESON_TAC[];
+        ASM_SIMP_TAC[]]]) in
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `content(interval[a:real^M,b]) = &0` THENL
+   [MATCH_MP_TAC(REAL_ARITH `x = &0 /\ &0 <= y ==> x <= &2 * y`) THEN
+    REWRITE_TAC[CONTENT_POS_LE; REAL_ENTIRE] THEN DISJ2_TAC THEN
+    MATCH_MP_TAC SUM_EQ_0 THEN X_GEN_TAC `k:real^M->bool` THEN
+    DISCH_TAC THEN REWRITE_TAC[real_div; REAL_ENTIRE] THEN DISJ1_TAC THEN
+    MATCH_MP_TAC CONTENT_0_SUBSET THEN
+    MAP_EVERY EXISTS_TAC [`a:real^M`; `b:real^M`] THEN
+    ASM_MESON_TAC[division_of; SUBSET_TRANS];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM CONTENT_LT_NZ]) THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  REWRITE_TAC[CONTENT_POS_LT_EQ] THEN STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  MP_TAC(ISPECL
+   [`{k | k IN {l INTER {x | x$i <= c} | l |
+                l IN d /\ ~(l INTER {x:real^M | x$i <= c} = {})} /\
+          ~(content k = &0)}`;
+    `a:real^M`;
+    `(lambda j. if j = i then c else (b:real^M)$j):real^M`;
+    `UNIONS {k | k IN {l INTER {x | x$i <= c} | l |
+                       l IN d /\ ~(l INTER {x:real^M | x$i <= c} = {})} /\
+                 ~(content k = &0)}`;
+    `i:num`] lemma1) THEN
+  MP_TAC(ISPECL
+   [`{k | k IN {l INTER {x | x$i >= c} | l |
+                l IN d /\ ~(l INTER {x:real^M | x$i >= c} = {})} /\
+          ~(content k = &0)}`;
+    `(lambda j. if j = i then c else (a:real^M)$j):real^M`;
+    `b:real^M`;
+    `UNIONS {k | k IN {l INTER {x | x$i >= c} | l |
+                       l IN d /\ ~(l INTER {x:real^M | x$i >= c} = {})} /\
+                 ~(content k = &0)}`;
+    `i:num`] lemma1) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(TAUT
+   `(p1 /\ p2) /\ (q1 /\ q2 ==> r) ==> (p2 ==> q2) ==> (p1 ==> q1) ==> r`) THEN
+  CONJ_TAC THENL
+   [CONJ_TAC THEN
+    (REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[division_of] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC FINITE_RESTRICT THEN
+        ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+        MATCH_MP_TAC FINITE_IMAGE THEN MATCH_MP_TAC FINITE_RESTRICT THEN
+        ASM_REWRITE_TAC[];
+        ALL_TAC] THEN
+      REWRITE_TAC[FORALL_IN_GSPEC; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+      CONJ_TAC THENL
+       [FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+        MAP_EVERY X_GEN_TAC [`u:real^M`; `v:real^M`] THEN
+        REPEAT DISCH_TAC THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+         [REWRITE_TAC[IN_ELIM_THM; SUBSET; IN_UNIONS] THEN ASM_MESON_TAC[];
+          ASM_SIMP_TAC[INTERVAL_SPLIT] THEN MESON_TAC[]];
+        X_GEN_TAC `k:real^M->bool` THEN REPEAT DISCH_TAC THEN
+        X_GEN_TAC `l:real^M->bool` THEN REPEAT DISCH_TAC THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+        DISCH_THEN(MP_TAC o SPECL [`k:real^M->bool`; `l:real^M->bool`] o
+          el 2 o CONJUNCTS) THEN
+        ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+        MATCH_MP_TAC(SET_RULE
+         `s SUBSET s' /\ t SUBSET t'
+          ==> s' INTER t' = {} ==> s INTER t = {}`) THEN
+        CONJ_TAC THEN MATCH_MP_TAC SUBSET_INTERIOR THEN SET_TAC[]];
+      REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC; IMP_CONJ] THEN
+      X_GEN_TAC `k:real^M->bool` THEN REPEAT DISCH_TAC THEN
+      SUBGOAL_THEN `k SUBSET interval[a:real^M,b]` MP_TAC THENL
+       [ASM_MESON_TAC[division_of; SUBSET_TRANS]; ALL_TAC] THEN
+      MATCH_MP_TAC(SET_RULE
+       `i INTER h SUBSET j ==> k SUBSET i ==> k INTER h SUBSET j`) THEN
+      ASM_SIMP_TAC[INTERVAL_SPLIT; SUBSET_INTERVAL; LAMBDA_BETA] THEN
+      MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN MATCH_MP_TAC MONO_IMP THEN
+      REAL_ARITH_TAC;
+      ALL_TAC])
+    THENL [DISJ2_TAC; DISJ1_TAC] THEN
+    REWRITE_TAC[FORALL_IN_GSPEC; IMP_CONJ] THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; real_ge] THEN ASM SET_TAC[REAL_LE_REFL];
+    ASM_SIMP_TAC[LAMBDA_BETA]] THEN
+  SUBGOAL_THEN
+   `sum {k | k IN
+             { l INTER {x | x$i <= c} | l |
+               l IN d /\ ~(l INTER {x:real^M | x$i <= c} = {})} /\
+             ~(content k = &0)}
+        (\k. content k /
+             (interval_upperbound k$i - interval_lowerbound k$i)) =
+    sum d ((\k. content k /
+             (interval_upperbound k$i - interval_lowerbound k$i)) o
+           (\k. k INTER {x | x$i <= c})) /\
+    sum {k | k IN
+             { l INTER {x | x$i >= c} | l |
+               l IN d /\ ~(l INTER {x:real^M | x$i >= c} = {})} /\
+             ~(content k = &0)}
+        (\k. content k /
+             (interval_upperbound k$i - interval_lowerbound k$i)) =
+    sum d ((\k. content k /
+             (interval_upperbound k$i - interval_lowerbound k$i)) o
+           (\k. k INTER {x | x$i >= c}))`
+  (CONJUNCTS_THEN SUBST1_TAC) THENL
+   [CONJ_TAC THEN
+    (W(MP_TAC o PART_MATCH (rand o rand) SUM_IMAGE_NONZERO o rand o snd) THEN
+     ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+      [MAP_EVERY X_GEN_TAC [`k:real^M->bool`; `l:real^M->bool`] THEN
+       STRIP_TAC THEN
+       REWRITE_TAC[real_div; REAL_ENTIRE] THEN DISJ1_TAC THEN
+       (MATCH_MP_TAC DIVISION_SPLIT_LEFT_INJ ORELSE
+        MATCH_MP_TAC DIVISION_SPLIT_RIGHT_INJ) THEN ASM_MESON_TAC[];
+       DISCH_THEN(SUBST1_TAC o SYM) THEN CONV_TAC SYM_CONV THEN
+       MATCH_MP_TAC SUM_SUPERSET THEN CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+       GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE
+        `x IN IMAGE f d /\
+         ~(x IN {x | x IN {f y |y| y IN d /\ ~(f y = a)} /\ ~P x})
+         ==> (!y. f y = a ==> P(f y)) ==> P x`)) THEN
+       SIMP_TAC[CONTENT_EMPTY; real_div; REAL_MUL_LZERO]]);
+     ALL_TAC] THEN
+  MAP_EVERY (fun (t,tac) ->
+    ASM_CASES_TAC t THENL
+     [FIRST_X_ASSUM SUBST_ALL_TAC THEN DISCH_THEN(MP_TAC o tac) THEN
+      MATCH_MP_TAC(REAL_ARITH `x = y /\ a <= b ==> x <= a ==> y <= b`) THEN
+      CONJ_TAC THENL
+       [AP_TERM_TAC THEN MATCH_MP_TAC SUM_EQ THEN
+        X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN
+        PURE_REWRITE_TAC[o_THM] THEN AP_TERM_TAC THEN
+        REWRITE_TAC[real_ge; SET_RULE
+         `k INTER {x | P x} = k <=> (!x. x IN k ==> P x)`] THEN
+        X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+        SUBGOAL_THEN `x IN interval[a:real^M,b]` MP_TAC THENL
+         [ASM_MESON_TAC[SUBSET; division_of]; ALL_TAC] THEN
+        ASM_SIMP_TAC[IN_INTERVAL];
+        MATCH_MP_TAC(REAL_ARITH `&0 <= y /\ x <= y ==> x <= &2 * y`) THEN
+        REWRITE_TAC[CONTENT_POS_LE] THEN MATCH_MP_TAC CONTENT_SUBSET THEN
+        SIMP_TAC[SUBSET_INTERVAL; LAMBDA_BETA] THEN
+        MESON_TAC[REAL_LE_REFL]];
+      ALL_TAC])
+    [`c = (a:real^M)$i`,CONJUNCT2; `c = (b:real^M)$i`,CONJUNCT1] THEN
+  SUBGOAL_THEN `(a:real^M)$i < c /\ c < (b:real^M)$i` STRIP_ASSUME_TAC THENL
+   [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; REAL_SUB_LT] THEN
+  REWRITE_TAC[REAL_ARITH `(x * &2) / y = &2 * x / y`] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `s <= s1 + s2 /\ c1 = c /\ c2 = c
+    ==> s1 <= c1 /\ s2 <= c2 ==> s <= &2 * c`) THEN
+  CONJ_TAC THENL
+   [ASM_SIMP_TAC[GSYM SUM_ADD] THEN MATCH_MP_TAC SUM_LE THEN
+    ASM_SIMP_TAC[lemma0] THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+    MAP_EVERY X_GEN_TAC [`u:real^M`; `v:real^M`] THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `~(interval[u:real^M,v] = {}) /\ interval[u,v] SUBSET interval[a,b]`
+    MP_TAC THENL [ASM_MESON_TAC[division_of; SUBSET_TRANS]; ALL_TAC] THEN
+    SIMP_TAC[INTERVAL_NE_EMPTY; SUBSET_INTERVAL; IMP_CONJ] THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[o_THM] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `&0 <= x /\ c1 + c2 = c /\
+      (~(c1 = &0) ==> x1 = x) /\ (~(c2 = &0) ==> x2 = x)
+      ==> (if c = &0 then &0 else x) <=
+          (if c1 = &0 then &0 else x1) +
+          (if c2 = &0 then &0 else x2)`) THEN
+    ASM_SIMP_TAC[GSYM CONTENT_SPLIT] THEN
+    ASM_SIMP_TAC[INTERVAL_SPLIT; CONTENT_POS_LE] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC PRODUCT_POS_LE THEN
+      ASM_SIMP_TAC[FINITE_DELETE; FINITE_NUMSEG; IN_DELETE; IN_NUMSEG;
+                   INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND; REAL_SUB_LE];
+      REWRITE_TAC[CONTENT_EQ_0; REAL_NOT_LE; MESON[]
+       `~(?i. P i /\ Q i /\ R i) <=> (!i. P i /\ Q i ==> ~R i)`] THEN
+      SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND; REAL_LT_IMP_LE] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC PRODUCT_EQ THEN
+      ASM_SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND; IN_DELETE;
+                   IN_NUMSEG; LAMBDA_BETA]];
+    SUBGOAL_THEN
+     `~(interval[a,b] = {}) /\
+      ~(interval[a:real^M,(lambda j. if j = i then c else b$j)] = {}) /\
+      ~(interval[(lambda j. if j = i then c else a$j):real^M,b] = {})`
+    MP_TAC THENL
+     [SIMP_TAC[INTERVAL_NE_EMPTY; LAMBDA_BETA] THEN
+      ASM_MESON_TAC[REAL_LT_IMP_LE; REAL_LE_REFL];
+      ALL_TAC] THEN
+    SIMP_TAC[content] THEN
+    SIMP_TAC[INTERVAL_NE_EMPTY; INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND] THEN
+    STRIP_TAC THEN
+    SUBGOAL_THEN
+     `1..dimindex(:M) = i INSERT ((1..dimindex(:M)) DELETE i)`
+    SUBST1_TAC THENL
+     [MATCH_MP_TAC(SET_RULE `x IN s ==> s = x INSERT (s DELETE x)`) THEN
+      ASM_REWRITE_TAC[IN_NUMSEG];
+      ALL_TAC] THEN
+    SIMP_TAC[PRODUCT_CLAUSES; FINITE_NUMSEG; FINITE_DELETE] THEN
+    ASM_SIMP_TAC[IN_DELETE; IN_NUMSEG; LAMBDA_BETA] THEN
+    CONJ_TAC THEN MATCH_MP_TAC(REAL_FIELD
+     `y < x /\ z < w /\ a = b
+      ==> ((x - y) * a) / (x - y) = ((w - z) * b) / (w - z)`) THEN
+    ASM_SIMP_TAC[] THEN MATCH_MP_TAC PRODUCT_EQ THEN
+    SIMP_TAC[IN_DELETE; IN_NUMSEG; LAMBDA_BETA]]);;
+
+let BOUNDED_EQUIINTEGRAL_OVER_THIN_TAGGED_PARTIAL_DIVISION = prove
+ (`!fs f:real^M->real^N a b e.
+    fs equiintegrable_on interval[a,b] /\ f IN fs /\
+    (!h x. h IN fs /\ x IN interval[a,b] ==> norm(h x) <= norm(f x)) /\
+    &0 < e
+    ==> ?d. gauge d /\
+            !c i p h. c IN interval[a,b] /\ 1 <= i /\ i <= dimindex(:M) /\
+                      p tagged_partial_division_of interval[a,b] /\
+                      d fine p /\
+                      h IN fs /\
+                      (!x k. (x,k) IN p ==> ~(k INTER {x | x$i = c$i} = {}))
+                      ==> sum p(\(x,k). norm(integral k h)) < e`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `content(interval[a:real^M,b]) = &0` THENL
+   [EXISTS_TAC `\x:real^M. ball(x,&1)` THEN REWRITE_TAC[GAUGE_TRIVIAL] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `&0 < e ==> x = &0 ==> x < e`)) THEN
+    MATCH_MP_TAC SUM_EQ_0 THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+    GEN_TAC THEN X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `?u v:real^M. k = interval[u,v] /\ interval[u,v] SUBSET interval[a,b]`
+    STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[tagged_partial_division_of]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[NORM_EQ_0] THEN MATCH_MP_TAC INTEGRAL_NULL THEN
+    ASM_MESON_TAC[CONTENT_0_SUBSET];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM CONTENT_LT_NZ]) THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  REWRITE_TAC[CONTENT_POS_LT_EQ] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?d. gauge d /\
+        !p h. p tagged_partial_division_of interval [a,b] /\
+              d fine p /\ (h:real^M->real^N) IN fs
+              ==> sum p (\(x,k). norm(content k % h x - integral k h)) <
+                  e / &2`
+   (X_CHOOSE_THEN `g0:real^M->real^M->bool` STRIP_ASSUME_TAC)
+  THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [equiintegrable_on]) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC
+      `e / &5 / (&(dimindex(:N)) + &1)`)) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < &5 /\ &0 < &n + &1`] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^M->real^M->bool` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN MAP_EVERY X_GEN_TAC
+     [`p:(real^M#(real^M->bool))->bool`; `h:real^M->real^N`] THEN
+    STRIP_TAC THEN
+    MP_TAC(ISPECL [`h:real^M->real^N`; `a:real^M`; `b:real^M`;
+           `g:real^M->real^M->bool`; `e / &5 / (&(dimindex(:N)) + &1)`]
+        HENSTOCK_LEMMA_PART2) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < &5 /\ &0 < &n + &1`] THEN
+    DISCH_THEN(MP_TAC o SPEC `p:(real^M#(real^M->bool))->bool`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(REAL_ARITH
+     `a < b ==> x <= a ==> x < b`) THEN
+    REWRITE_TAC[REAL_ARITH `&2 * d * e / &5 / (d + &1) =
+                            (e * &2 / &5 * d) / (d + &1)`] THEN
+    SIMP_TAC[REAL_LT_LDIV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `&0 < e /\ &0 < e * d ==> e * &2 / &5 * d < e / &2 * (d + &1)`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LT_MUL THEN
+    ASM_SIMP_TAC[REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1];
+    ALL_TAC] THEN
+  ABBREV_TAC
+   `g:real^M->real^M->bool =
+       \x. g0(x) INTER
+           ball(x,(e / &8 / (norm(f x:real^N) + &1)) *
+                  inf(IMAGE (\m. b$m - a$m) (1..dimindex(:M))) /
+                  content(interval[a:real^M,b]))` THEN
+  SUBGOAL_THEN `gauge(g:real^M->real^M->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "g" THEN MATCH_MP_TAC GAUGE_INTER THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[gauge; OPEN_BALL; CENTRE_IN_BALL] THEN
+    X_GEN_TAC `x:real^M` THEN MATCH_MP_TAC REAL_LT_MUL THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; NORM_ARITH
+     `&0 < &8 /\ &0 < norm(x:real^N) + &1`] THEN
+    MATCH_MP_TAC REAL_LT_DIV THEN ASM_REWRITE_TAC[] THEN
+    W(MP_TAC o PART_MATCH (lhand o rand) REAL_LT_INF_FINITE o snd) THEN
+    ANTS_TAC THENL
+     [ASM_SIMP_TAC[FINITE_IMAGE; FINITE_NUMSEG; FINITE_RESTRICT] THEN
+      SIMP_TAC[IMAGE_EQ_EMPTY; NUMSEG_EMPTY;
+               GSYM NOT_LE; DIMINDEX_GE_1] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [CART_EQ]) THEN
+      REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY; IN_NUMSEG] THEN
+      MESON_TAC[];
+      DISCH_THEN SUBST1_TAC THEN
+      REWRITE_TAC[FORALL_IN_IMAGE] THEN
+      ASM_SIMP_TAC[REAL_SUB_LT; IN_NUMSEG; GSYM REAL_ABS_NZ; REAL_SUB_0;
+                   IN_ELIM_THM]];
+    ALL_TAC] THEN
+  EXISTS_TAC `g:real^M->real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC
+   [`c:real^M`; `i:num`; `p:(real^M#(real^M->bool))->bool`;
+    `h:real^M->real^N`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN
+   `interval[c:real^M,b] SUBSET interval[a,b]`
+  ASSUME_TAC THENL
+   [UNDISCH_TAC `c IN interval[a:real^M,b]` THEN
+    SIMP_TAC[IN_INTERVAL; SUBSET_INTERVAL; REAL_LE_REFL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `FINITE(p:(real^M#(real^M->bool))->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[tagged_partial_division_of]; ALL_TAC] THEN
+  MP_TAC(ASSUME `(g:real^M->real^M->bool) fine p`) THEN
+  EXPAND_TAC "g" THEN REWRITE_TAC[FINE_INTER] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "F")) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `p:(real^M#(real^M->bool))->bool`) THEN
+  DISCH_THEN(MP_TAC o SPEC `h:real^M->real^N`) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[TAGGED_PARTIAL_DIVISION_OF_SUBSET]; ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `x - y <= e / &2 ==> y < e / &2 ==> x < e`) THEN
+  ASM_SIMP_TAC[GSYM SUM_SUB] THEN
+  ONCE_REWRITE_TAC[LAMBDA_PAIR_THM] THEN REWRITE_TAC[] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC
+   `sum p (\(x:real^M,k:real^M->bool). norm(content k % h x:real^N))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+    REWRITE_TAC[NORM_ARITH `norm y - norm(x - y:real^N) <= norm x`];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC
+   `sum p (\(x:real^M,k).
+                   e / &4 * (b$i - a$i) / content(interval[a:real^M,b]) *
+                   content(k:real^M->bool) /
+                   (interval_upperbound k$i - interval_lowerbound k$i))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+    ASM_CASES_TAC `content(k:real^M->bool) = &0` THENL
+     [ASM_REWRITE_TAC[real_div; REAL_MUL_LZERO; VECTOR_MUL_LZERO; NORM_0;
+                      REAL_MUL_RZERO; REAL_LE_REFL];
+      ALL_TAC] THEN
+    REWRITE_TAC[REAL_ARITH `a * b * content k / d = content k * (a * b) / d`;
+                NORM_MUL] THEN
+    SUBGOAL_THEN `&0 < content(k:real^M->bool)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[CONTENT_LT_NZ; tagged_partial_division_of]; ALL_TAC] THEN
+    ASM_SIMP_TAC[real_abs; REAL_LT_IMP_LE; REAL_LE_LMUL_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH `x + &1 <= y ==> x <= y`) THEN
+    SUBGOAL_THEN `?u v. k = interval[u:real^M,v]` MP_TAC THENL
+     [ASM_MESON_TAC[tagged_partial_division_of]; ALL_TAC] THEN
+    DISCH_THEN(REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC) THEN
+    MP_TAC(ISPECL [`u:real^M`; `v:real^M`] CONTENT_POS_LT_EQ) THEN
+    ASM_SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND; REAL_LT_IMP_LE] THEN
+    DISCH_TAC THEN
+    W(MP_TAC o PART_MATCH (lhand o rand) REAL_LE_RDIV_EQ o snd) THEN
+    ASM_SIMP_TAC[REAL_SUB_LT] THEN DISCH_THEN SUBST1_TAC THEN
+    GEN_REWRITE_TAC LAND_CONV [REAL_MUL_SYM] THEN
+    SIMP_TAC[GSYM REAL_LE_RDIV_EQ; NORM_ARITH `&0 < norm(x:real^N) + &1`] THEN
+    REMOVE_THEN "F" MP_TAC THEN REWRITE_TAC[fine] THEN
+    DISCH_THEN(MP_TAC o SPECL [`x:real^M`; `interval[u:real^M,v]`]) THEN
+    ASM_REWRITE_TAC[SUBSET] THEN
+    DISCH_THEN(fun th -> MP_TAC(SPEC `v:real^M` th) THEN
+                         MP_TAC(SPEC `u:real^M` th)) THEN
+    ASM_SIMP_TAC[INTERVAL_NE_EMPTY; REAL_LT_IMP_LE; ENDS_IN_INTERVAL] THEN
+    REWRITE_TAC[IN_BALL; IMP_IMP] THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `abs(vi - ui) <= norm(v - u:real^N) /\ &2 * a <= b
+      ==> dist(x,u) < a /\ dist(x,v) < a ==> vi - ui <= b`) THEN
+    ASM_SIMP_TAC[GSYM VECTOR_SUB_COMPONENT; COMPONENT_LE_NORM] THEN
+    REWRITE_TAC[REAL_ARITH `&2 * e / &8 / x * y = e / &4 * y / x`] THEN
+    REWRITE_TAC[real_div; GSYM REAL_MUL_ASSOC] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `a * inv b * inv c:real = (a / c) / b`] THEN
+    ASM_SIMP_TAC[REAL_LE_DIV2_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH `abs x <= e ==> x <= e`) THEN
+    REWRITE_TAC[real_div; REAL_ABS_MUL] THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+    REWRITE_TAC[REAL_ABS_POS] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ x <= y ==> abs x <= y`) THEN
+      SIMP_TAC[REAL_INF_LE_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY; FINITE_NUMSEG;
+               NUMSEG_EMPTY; NOT_LT; DIMINDEX_GE_1; REAL_LE_INF_FINITE] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; EXISTS_IN_IMAGE; IN_NUMSEG] THEN
+      ASM_SIMP_TAC[VECTOR_SUB_COMPONENT; REAL_LE_REFL; REAL_SUB_LE;
+                   REAL_LT_IMP_LE] THEN
+      ASM_MESON_TAC[REAL_LE_REFL];
+      REWRITE_TAC[REAL_ABS_INV] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+      CONJ_TAC THENL [NORM_ARITH_TAC; ALL_TAC] THEN
+      MATCH_MP_TAC(REAL_ARITH `x <= y ==> x + &1 <= abs(y + &1)`) THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_MESON_TAC[tagged_partial_division_of; SUBSET]];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP TAGGED_PARTIAL_DIVISION_OF_UNION_SELF) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    SUM_OVER_TAGGED_DIVISION_LEMMA)) THEN
+  DISCH_THEN(fun th ->
+    W(MP_TAC o PART_MATCH (lhs o rand) th o lhand o snd)) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [SIMP_TAC[real_div; REAL_MUL_LZERO; REAL_MUL_RZERO];
+    DISCH_THEN SUBST1_TAC] THEN
+  REWRITE_TAC[SUM_LMUL; REAL_ARITH
+   `e / &4 * ba / c * s <= e / &2 <=> e * (ba * s) / c <= e * &2`] THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL_EQ] THEN ASM_SIMP_TAC[REAL_LE_LDIV_EQ] THEN
+  MATCH_MP_TAC SUM_CONTENT_AREA_OVER_THIN_DIVISION THEN
+  EXISTS_TAC `UNIONS(IMAGE SND (p:(real^M#(real^M->bool))->bool))` THEN
+  EXISTS_TAC `(c:real^M)$i` THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL]) THEN ASM_SIMP_TAC[] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC DIVISION_OF_TAGGED_DIVISION THEN
+    ASM_MESON_TAC[TAGGED_PARTIAL_DIVISION_OF_UNION_SELF];
+    REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_IMAGE; FORALL_PAIR_THM] THEN
+    ASM_MESON_TAC[tagged_partial_division_of];
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM]]);;
+
+let EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LE = prove
+ (`!fs f:real^M->real^N a b.
+        fs equiintegrable_on interval[a,b] /\ f IN fs /\
+        (!h x. h IN fs /\ x IN interval[a,b] ==> norm(h x) <= norm(f x))
+        ==> { (\x. if x$i <= c then h x else vec 0) |
+              i IN 1..dimindex(:M) /\ c IN (:real) /\ h IN fs }
+            equiintegrable_on interval[a,b]`,
+  let lemma = prove
+   (`(!x k. (x,k) IN IMAGE (\(x,k). f x k,g x k) s ==> Q x k) <=>
+     (!x k. (x,k) IN s ==> Q (f x k) (g x k))`,
+    REWRITE_TAC[IN_IMAGE; PAIR_EQ; EXISTS_PAIR_THM] THEN SET_TAC[]) in
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `content(interval[a:real^M,b]) = &0` THEN
+  ASM_SIMP_TAC[EQUIINTEGRABLE_ON_NULL] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM CONTENT_LT_NZ]) THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  REWRITE_TAC[CONTENT_POS_LT_EQ] THEN STRIP_TAC THEN
+  REWRITE_TAC[equiintegrable_on] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[IN_UNIV; IMP_IMP; GSYM CONJ_ASSOC; RIGHT_IMP_FORALL_THM;
+              IN_NUMSEG] THEN
+  FIRST_ASSUM(ASSUME_TAC o CONJUNCT1 o REWRITE_RULE[equiintegrable_on]) THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REPEAT GEN_TAC THEN
+    ONCE_REWRITE_TAC[SET_RULE `x$i <= c <=> x IN {x:real^N | x$i <= c}`] THEN
+    REWRITE_TAC[INTEGRABLE_RESTRICT_INTER] THEN
+    ONCE_REWRITE_TAC[INTER_COMM] THEN SIMP_TAC[INTERVAL_SPLIT] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+    EXISTS_TAC `interval[a:real^M,b]` THEN ASM_SIMP_TAC[] THEN
+    SIMP_TAC[SUBSET_INTERVAL; LAMBDA_BETA; REAL_LE_REFL] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+    REAL_ARITH_TAC;
+    DISCH_TAC] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`fs:(real^M->real^N)->bool`; `f:real^M->real^N`;
+                 `a:real^M`; `b:real^M`; `e / &12`]
+        BOUNDED_EQUIINTEGRAL_OVER_THIN_TAGGED_PARTIAL_DIVISION) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < &12`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g0:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `?d. gauge d /\
+        !p h. p tagged_partial_division_of interval [a,b] /\
+              d fine p /\ (h:real^M->real^N) IN fs
+              ==> sum p (\(x,k). norm(content k % h x - integral k h)) <
+                  e / &3`
+   (X_CHOOSE_THEN `g1:real^M->real^M->bool` STRIP_ASSUME_TAC)
+  THENL
+   [FIRST_ASSUM(MP_TAC o CONJUNCT2 o REWRITE_RULE[equiintegrable_on]) THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &7 / (&(dimindex(:N)) + &1)`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < &7 /\ &0 < &n + &1`] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `d:real^M->real^M->bool` THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN
+    MAP_EVERY X_GEN_TAC
+     [`p:(real^M#(real^M->bool))->bool`; `h:real^M->real^N`] THEN
+    STRIP_TAC THEN
+    MP_TAC(ISPECL [`h:real^M->real^N`; `a:real^M`; `b:real^M`;
+           `d:real^M->real^M->bool`; `e / &7 / (&(dimindex(:N)) + &1)`]
+        HENSTOCK_LEMMA_PART2) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < &7 /\ &0 < &n + &1`] THEN
+    DISCH_THEN(MP_TAC o SPEC `p:(real^M#(real^M->bool))->bool`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(REAL_ARITH
+     `a < b ==> x <= a ==> x < b`) THEN
+    REWRITE_TAC[REAL_ARITH `&2 * d * e / &7 / (d + &1) =
+                            (e * &2 / &7 * d) / (d + &1)`] THEN
+    SIMP_TAC[REAL_LT_LDIV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `&0 < e /\ &0 < e * d ==> e * &2 / &7 * d < e / &3 * (d + &1)`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LT_MUL THEN
+    ASM_SIMP_TAC[REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1];
+    ALL_TAC] THEN
+  EXISTS_TAC `\x. (g0:real^M->real^M->bool) x INTER g1 x` THEN
+  ASM_SIMP_TAC[GAUGE_INTER; FINE_INTER] THEN
+  X_GEN_TAC `i:num` THEN
+  ASM_CASES_TAC `1 <= i` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `i <= dimindex(:M)` THEN ASM_REWRITE_TAC[] THEN
+  MP_TAC(MESON[]
+   `!P. ((!c. (a:real^M)$i <= c /\ c <= (b:real^M)$i ==> P c) ==> (!c. P c)) /\
+        (!c. (a:real^M)$i <= c /\ c <= (b:real^M)$i ==> P c)
+        ==> !c. P c`) THEN
+  DISCH_THEN MATCH_MP_TAC THEN CONJ_TAC THENL
+   [DISCH_THEN(LABEL_TAC "*") THEN
+    X_GEN_TAC `c:real` THEN
+    ASM_CASES_TAC `(a:real^M)$i <= c /\ c <= (b:real^M)$i` THENL
+     [REMOVE_THEN "*" MATCH_MP_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
+    REMOVE_THEN "*" (MP_TAC o SPEC `(b:real^M)$i`) THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LE_REFL] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `h:real^M->real^N` THEN
+    MATCH_MP_TAC MONO_FORALL THEN
+    X_GEN_TAC `p:real^M#(real^M->bool)->bool` THEN
+    DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [DE_MORGAN_THM]) THEN
+    REWRITE_TAC[REAL_NOT_LE] THEN STRIP_TAC THENL
+     [DISCH_TAC THEN MATCH_MP_TAC(NORM_ARITH
+       `x:real^N = vec 0 /\ y = vec 0 /\ &0 < e ==> norm(x - y) < e`) THEN
+      ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC VSUM_EQ_0 THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+        MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+        COND_CASES_TAC THEN ASM_REWRITE_TAC[VECTOR_MUL_RZERO] THEN
+        SUBGOAL_THEN `(x:real^M) IN interval[a,b]` MP_TAC THENL
+         [ASM_MESON_TAC[TAGGED_DIVISION_OF; SUBSET]; ALL_TAC] THEN
+        REWRITE_TAC[IN_INTERVAL] THEN
+        DISCH_THEN(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+        ASM_REAL_ARITH_TAC;
+        MATCH_MP_TAC EQ_TRANS THEN
+        EXISTS_TAC `integral(interval[a,b]) ((\x. vec 0):real^M->real^N)` THEN
+        CONJ_TAC THENL [ALL_TAC; REWRITE_TAC[INTEGRAL_0]] THEN
+        MATCH_MP_TAC INTEGRAL_EQ THEN REWRITE_TAC[] THEN GEN_TAC THEN
+        COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_INTERVAL] THEN
+        DISCH_THEN(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+        ASM_REAL_ARITH_TAC];
+      MATCH_MP_TAC(NORM_ARITH
+       `x:real^N = y /\ w = z ==> norm(x - w) < e ==> norm(y - z) < e`) THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC VSUM_EQ THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+        MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+        SUBGOAL_THEN `(x:real^M) IN interval[a,b]` MP_TAC THENL
+         [ASM_MESON_TAC[TAGGED_DIVISION_OF; SUBSET]; ALL_TAC] THEN
+        REWRITE_TAC[IN_INTERVAL] THEN
+        DISCH_THEN(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+        STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+        COND_CASES_TAC THEN ASM_REWRITE_TAC[VECTOR_MUL_RZERO] THEN
+        ASM_REAL_ARITH_TAC;
+        MATCH_MP_TAC INTEGRAL_EQ THEN REWRITE_TAC[] THEN GEN_TAC THEN
+        COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_INTERVAL] THEN
+        DISCH_THEN(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+        ASM_REAL_ARITH_TAC]];
+    ALL_TAC] THEN
+  X_GEN_TAC `c:real` THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`h:real^M->real^N`;
+                  `p:(real^M#(real^M->bool))->bool`] THEN STRIP_TAC THEN
+  ABBREV_TAC
+   `q:(real^M#(real^M->bool))->bool =
+        {(x,k) | (x,k) IN p /\ ~(k INTER {x | x$i <= c} = {})}` THEN
+  MP_TAC(ISPECL
+   [`\x. if x$i <= c then (h:real^M->real^N) x else vec 0`;
+    `a:real^M`; `b:real^M`; `p:(real^M#(real^M->bool))->bool`]
+        INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN) THEN
+  ASM_SIMP_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
+  SUBGOAL_THEN `FINITE(p:(real^M#(real^M->bool))->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+  SUBGOAL_THEN `q SUBSET (p:(real^M#(real^M->bool))->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "q" THEN SIMP_TAC[SUBSET; FORALL_PAIR_THM; IN_ELIM_PAIR_THM];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `FINITE(q:(real^M#(real^M->bool))->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM VSUM_SUB] THEN ONCE_REWRITE_TAC[LAMBDA_PAIR_THM] THEN
+  REWRITE_TAC[] THEN
+  SUBGOAL_THEN `q tagged_partial_division_of interval[a:real^M,b] /\
+                g0 fine q /\ g1 fine q`
+  STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[TAGGED_PARTIAL_DIVISION_SUBSET; tagged_division_of;
+                  FINE_SUBSET];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(MESON[] `!q. vsum p s = vsum q s /\ norm(vsum q s) < e
+                            ==> norm(vsum p s:real^N) < e`) THEN
+  EXISTS_TAC `q:(real^M#(real^M->bool))->bool` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC VSUM_SUPERSET THEN ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+    EXPAND_TAC "q" THEN REWRITE_TAC[IN_ELIM_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `(x:real^M) IN k` ASSUME_TAC THENL
+     [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+    DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+    REWRITE_TAC[EXTENSION] THEN DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN
+    REWRITE_TAC[IN_INTER; NOT_IN_EMPTY] THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_RZERO] THEN
+    REWRITE_TAC[VECTOR_NEG_EQ_0; VECTOR_SUB_LZERO] THEN
+    MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `integral k ((\x. vec 0):real^M->real^N)` THEN
+    CONJ_TAC THENL [ALL_TAC; REWRITE_TAC[INTEGRAL_0]] THEN
+    MATCH_MP_TAC INTEGRAL_EQ THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `norm(vsum q (\(x,k). content k % h x - integral k (h:real^M->real^N)))
+        < e / &3`
+  MP_TAC THENL
+   [MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `sum q
+      (\(x,k). norm(content k % h x - integral k (h:real^M->real^N)))` THEN
+    ASM_SIMP_TAC[] THEN MATCH_MP_TAC VSUM_NORM_LE THEN
+    ASM_REWRITE_TAC[FORALL_PAIR_THM; REAL_LE_REFL];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `norm(x - y:real^N) <= &2 * e / &3
+    ==> norm(x) < e / &3 ==> norm(y) < e`) THEN
+  ASM_SIMP_TAC[GSYM VSUM_SUB] THEN ONCE_REWRITE_TAC[LAMBDA_PAIR_THM] THEN
+  REWRITE_TAC[] THEN
+  ABBREV_TAC
+   `r:(real^M#(real^M->bool))->bool =
+        {(x,k) | (x,k) IN q /\ ~(k SUBSET {x | x$i <= c})}` THEN
+  SUBGOAL_THEN `r SUBSET (q:(real^M#(real^M->bool))->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "r" THEN SIMP_TAC[SUBSET; FORALL_PAIR_THM; IN_ELIM_PAIR_THM];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `FINITE(r:(real^M#(real^M->bool))->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+  SUBGOAL_THEN `r tagged_partial_division_of interval[a:real^M,b] /\
+                g0 fine r /\ g1 fine r`
+  STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[TAGGED_PARTIAL_DIVISION_SUBSET; FINE_SUBSET];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(MESON[] `!r. vsum q s = vsum r s /\ norm(vsum r s) <= e
+                            ==> norm(vsum q s:real^N) <= e`) THEN
+  EXISTS_TAC `r:(real^M#(real^M->bool))->bool` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC VSUM_SUPERSET THEN ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+    EXPAND_TAC "r" THEN REWRITE_TAC[IN_ELIM_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `(x:real^M) IN k` ASSUME_TAC THENL
+     [ASM_MESON_TAC[tagged_partial_division_of]; ALL_TAC] THEN
+    DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+    REWRITE_TAC[SUBSET] THEN DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[VECTOR_ARITH `c - i - (c - j):real^N = j - i`] THEN
+    REWRITE_TAC[VECTOR_SUB_EQ] THEN MATCH_MP_TAC INTEGRAL_EQ THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) VSUM_NORM o lhand o snd) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+  ONCE_REWRITE_TAC[LAMBDA_PAIR_THM] THEN REWRITE_TAC[] THEN
+  MAP_EVERY ABBREV_TAC
+   [`s:(real^M#(real^M->bool))->bool =
+        {(x,k) | (x,k) IN r /\ x IN {x | x$i <= c}}`;
+    `t:(real^M#(real^M->bool))->bool =
+        {(x,k) | (x,k) IN r /\ ~(x IN {x | x$i <= c})}`] THEN
+  SUBGOAL_THEN
+   `(s:(real^M#(real^M->bool))->bool) SUBSET r /\
+    (t:(real^M#(real^M->bool))->bool) SUBSET r`
+  STRIP_ASSUME_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["s"; "t"] THEN
+    SIMP_TAC[SUBSET; FORALL_PAIR_THM; IN_ELIM_PAIR_THM];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `FINITE(s:(real^M#(real^M->bool))->bool) /\
+    FINITE(t:(real^M#(real^M->bool))->bool)`
+  STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+  SUBGOAL_THEN `DISJOINT (s:(real^M#(real^M->bool))->bool) t` ASSUME_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["s"; "t"] THEN
+    REWRITE_TAC[EXTENSION; DISJOINT; IN_INTER; FORALL_PAIR_THM;
+                IN_ELIM_PAIR_THM] THEN SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `r:(real^M#(real^M->bool))->bool = s UNION t` SUBST1_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["s"; "t"] THEN
+    REWRITE_TAC[EXTENSION; IN_UNION; FORALL_PAIR_THM; IN_ELIM_PAIR_THM] THEN
+    SET_TAC[];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[SUM_UNION] THEN MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+   `sum s (\(x:real^M,k). norm
+          (integral k (h:real^M->real^N) -
+           integral k (\x. if x$i <= c then h x else vec 0))) +
+    sum t (\(x:real^M,k). norm
+          ((content k % (h:real^M->real^N) x - integral k h) +
+           integral k (\x. if x$i <= c then h x else vec 0)))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_EQ_IMP_LE THEN BINOP_TAC THEN
+    MATCH_MP_TAC SUM_EQ THEN REWRITE_TAC[FORALL_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN
+    MAP_EVERY EXPAND_TAC ["s"; "t"] THEN
+    REWRITE_TAC[IN_ELIM_PAIR_THM] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
+     [MATCH_MP_TAC(NORM_ARITH `a:real^N = --b ==> norm a = norm b`) THEN
+      VECTOR_ARITH_TAC;
+      AP_TERM_TAC THEN VECTOR_ARITH_TAC];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `s tagged_partial_division_of interval[a:real^M,b] /\
+                t tagged_partial_division_of interval[a:real^M,b] /\
+                g0 fine s /\ g1 fine s /\ g0 fine t /\ g1 fine t`
+  STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[TAGGED_PARTIAL_DIVISION_SUBSET; FINE_SUBSET];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+   `(sum s (\(x:real^M,k). norm(integral k (h:real^M->real^N))) +
+     sum (IMAGE (\(x,k). (x,k INTER {x | x$i <= c})) s)
+         (\(x:real^M,k). norm(integral k (h:real^M->real^N)))) +
+    (sum t (\(x:real^M,k). norm(content k % h x - integral k h)) +
+     sum t (\(x:real^M,k). norm(integral k (h:real^M->real^N))) +
+     sum (IMAGE (\(x,k). (x,k INTER {x | x$i >= c})) t)
+         (\(x:real^M,k). norm(integral k (h:real^M->real^N))))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_LE_ADD2 THEN CONJ_TAC THENL
+     [W(MP_TAC o PART_MATCH (lhand o rand) SUM_IMAGE_NONZERO o
+        rand o rand o snd) THEN
+      ANTS_TAC THENL
+       [ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+        MAP_EVERY X_GEN_TAC
+         [`x:real^M`; `k:real^M->bool`; `y:real^M`; `l:real^M->bool`] THEN
+        ASM_CASES_TAC `x:real^M = y` THEN ASM_REWRITE_TAC[PAIR_EQ] THEN
+        REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+         [`s:real^M#(real^M->bool)->bool`;
+          `UNIONS(IMAGE SND (s:real^M#(real^M->bool)->bool))`;
+          `x:real^M`; `k:real^M->bool`;
+          `y:real^M`; `l:real^M->bool`; `i:num`; `c:real`]
+         TAGGED_DIVISION_SPLIT_LEFT_INJ) THEN
+        ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+         [ASM_MESON_TAC[TAGGED_PARTIAL_DIVISION_OF_UNION_SELF]; ALL_TAC] THEN
+        REWRITE_TAC[NORM_EQ_0] THEN
+        SUBGOAL_THEN `?u v:real^M. l = interval[u,v]`
+         (REPEAT_TCL CHOOSE_THEN SUBST1_TAC)
+        THENL [ASM_MESON_TAC[tagged_partial_division_of]; ALL_TAC] THEN
+        ASM_SIMP_TAC[INTERVAL_SPLIT; INTEGRAL_NULL];
+        DISCH_THEN SUBST1_TAC THEN
+        ASM_SIMP_TAC[GSYM SUM_ADD] THEN MATCH_MP_TAC SUM_LE THEN
+        ASM_REWRITE_TAC[o_THM; FORALL_PAIR_THM] THEN
+        ONCE_REWRITE_TAC[SET_RULE
+         `x$i <= c <=> x IN {x:real^M | x$i <= c}`] THEN
+        REWRITE_TAC[INTEGRAL_RESTRICT_INTER] THEN
+        REWRITE_TAC[IN_ELIM_THM; INTER_COMM] THEN
+        REWRITE_TAC[NORM_ARITH `norm(a - b:real^N) <= norm a + norm b`]];
+      W(MP_TAC o PART_MATCH (lhand o rand) SUM_IMAGE_NONZERO o
+        rand o rand o rand o snd) THEN
+      ANTS_TAC THENL
+       [ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+        MAP_EVERY X_GEN_TAC
+         [`x:real^M`; `k:real^M->bool`; `y:real^M`; `l:real^M->bool`] THEN
+        ASM_CASES_TAC `x:real^M = y` THEN ASM_REWRITE_TAC[PAIR_EQ] THEN
+        REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+         [`t:real^M#(real^M->bool)->bool`;
+          `UNIONS(IMAGE SND (t:real^M#(real^M->bool)->bool))`;
+          `x:real^M`; `k:real^M->bool`;
+          `y:real^M`; `l:real^M->bool`; `i:num`; `c:real`]
+         TAGGED_DIVISION_SPLIT_RIGHT_INJ) THEN
+        ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+         [ASM_MESON_TAC[TAGGED_PARTIAL_DIVISION_OF_UNION_SELF]; ALL_TAC] THEN
+        REWRITE_TAC[NORM_EQ_0] THEN
+        SUBGOAL_THEN `?u v:real^M. l = interval[u,v]`
+         (REPEAT_TCL CHOOSE_THEN SUBST1_TAC)
+        THENL [ASM_MESON_TAC[tagged_partial_division_of]; ALL_TAC] THEN
+        ASM_SIMP_TAC[INTERVAL_SPLIT; INTEGRAL_NULL];
+        DISCH_THEN SUBST1_TAC THEN
+        ASM_SIMP_TAC[GSYM SUM_ADD] THEN MATCH_MP_TAC SUM_LE THEN
+        ASM_REWRITE_TAC[o_THM; FORALL_PAIR_THM] THEN
+        MAP_EVERY X_GEN_TAC [`x:real^M`; `k:real^M->bool`] THEN DISCH_TAC THEN
+        MATCH_MP_TAC(NORM_ARITH
+         `i = i1 + i2
+          ==> norm(c + i1:real^N) <= norm(c) + norm(i) + norm(i2)`) THEN
+        ONCE_REWRITE_TAC[SET_RULE
+         `x$i <= c <=> x IN {x:real^M | x$i <= c}`] THEN
+        REWRITE_TAC[INTEGRAL_RESTRICT_INTER] THEN
+        ONCE_REWRITE_TAC[SET_RULE `{x | P x} INTER s = s INTER {x | P x}`] THEN
+        SUBGOAL_THEN `?u v:real^M. k = interval[u,v]`
+         (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+        THENL [ASM_MESON_TAC[tagged_partial_division_of]; ALL_TAC] THEN
+        ASM_SIMP_TAC[INTERVAL_SPLIT] THEN MATCH_MP_TAC INTEGRAL_SPLIT THEN
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+        EXISTS_TAC `interval[a:real^M,b]` THEN
+        ASM_SIMP_TAC[] THEN ASM_MESON_TAC[tagged_partial_division_of]]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x:real^M k. (x,k) IN r ==> ~(k INTER {x:real^M | x$i = c} = {})`
+  ASSUME_TAC THENL
+   [REPEAT GEN_TAC THEN MAP_EVERY EXPAND_TAC ["r"; "q"] THEN
+    REWRITE_TAC[IN_ELIM_PAIR_THM] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC; SUBSET; EXTENSION; NOT_FORALL_THM] THEN
+    REWRITE_TAC[IN_ELIM_THM; NOT_IN_EMPTY; IN_INTER; NOT_IMP] THEN
+    DISCH_TAC THEN MATCH_MP_TAC CONNECTED_IVT_COMPONENT THEN
+    REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[REAL_LE_TOTAL]] THEN
+    SUBGOAL_THEN `?u v:real^M. k = interval[u,v]`
+     (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+    THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+    MATCH_MP_TAC CONVEX_CONNECTED THEN REWRITE_TAC[CONVEX_INTERVAL];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `x <= e / &6 /\ y <= e / &2 ==> x + y <= &2 * e / &3`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC(REAL_ARITH
+     `x < e / &12 /\ y < e / &12 ==> x + y <= e / &6`) THEN
+    CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    EXISTS_TAC `(lambda j. if j = i then c else (a:real^M)$j):real^M` THEN
+    EXISTS_TAC `i:num` THEN ASM_SIMP_TAC[LAMBDA_BETA; IN_INTERVAL] THENL
+     [CONJ_TAC THENL
+       [X_GEN_TAC `j:num` THEN COND_CASES_TAC THEN
+        ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LE_REFL];
+        EXPAND_TAC "s" THEN REWRITE_TAC[IN_ELIM_PAIR_THM] THEN
+        ASM_MESON_TAC[]];
+      REPEAT CONJ_TAC THENL
+       [X_GEN_TAC `j:num` THEN COND_CASES_TAC THEN
+        ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LE_REFL];
+        UNDISCH_TAC `s tagged_partial_division_of interval[a:real^M,b]`;
+        UNDISCH_TAC `(g0:real^M->real^M->bool) fine s` THEN
+        REWRITE_TAC[fine; FORALL_IN_IMAGE; lemma] THEN SET_TAC[];
+        REWRITE_TAC[lemma] THEN
+        REPEAT GEN_TAC THEN EXPAND_TAC "s" THEN REWRITE_TAC[IN_ELIM_THM] THEN
+        DISCH_TAC THEN MATCH_MP_TAC(SET_RULE
+        `~(k INTER t = {}) /\ t SUBSET s ==> ~((k INTER s) INTER t = {})`) THEN
+        SIMP_TAC[SUBSET; IN_ELIM_THM; REAL_LE_REFL] THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[]]];
+    MATCH_MP_TAC(REAL_ARITH
+     `x < e / &3 /\ y < e / &12 /\ z < e / &12 ==> x + y + z <= e / &2`) THEN
+    REPEAT CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+    EXISTS_TAC `(lambda j. if j = i then c else (a:real^M)$j):real^M` THEN
+    EXISTS_TAC `i:num` THEN ASM_SIMP_TAC[LAMBDA_BETA; IN_INTERVAL] THENL
+     [CONJ_TAC THENL
+       [X_GEN_TAC `j:num` THEN COND_CASES_TAC THEN
+        ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LE_REFL];
+        EXPAND_TAC "t" THEN REWRITE_TAC[IN_ELIM_PAIR_THM] THEN
+        ASM_MESON_TAC[]];
+      REPEAT CONJ_TAC THENL
+       [X_GEN_TAC `j:num` THEN COND_CASES_TAC THEN
+        ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LE_REFL];
+        UNDISCH_TAC `t tagged_partial_division_of interval[a:real^M,b]`;
+        UNDISCH_TAC `(g0:real^M->real^M->bool) fine t` THEN
+        REWRITE_TAC[fine; FORALL_IN_IMAGE; lemma] THEN SET_TAC[];
+        REWRITE_TAC[lemma] THEN
+        REPEAT GEN_TAC THEN EXPAND_TAC "t" THEN REWRITE_TAC[IN_ELIM_THM] THEN
+        DISCH_TAC THEN MATCH_MP_TAC(SET_RULE
+        `~(k INTER t = {}) /\ t SUBSET s ==> ~((k INTER s) INTER t = {})`) THEN
+        SIMP_TAC[SUBSET; IN_ELIM_THM; REAL_LE_REFL; real_ge] THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[]]]] THEN
+  REWRITE_TAC[tagged_partial_division_of] THEN
+  (MATCH_MP_TAC MONO_AND THEN SIMP_TAC[FINITE_IMAGE] THEN
+   MATCH_MP_TAC MONO_AND THEN
+   REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ; FORALL_IN_GSPEC] THEN
+   REWRITE_TAC[lemma] THEN CONJ_TAC THEN
+   MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:real^M` THEN
+   MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `k:real^M->bool` THEN
+   DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THENL
+    [MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+      [SIMP_TAC[real_ge; IN_INTER; IN_ELIM_THM] THEN ASM SET_TAC[REAL_LE_TOTAL];
+       MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+        [SET_TAC[];
+         STRIP_TAC THEN ASM_SIMP_TAC[INTERVAL_SPLIT] THEN MESON_TAC[]]];
+     REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+     MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+     MATCH_MP_TAC MONO_IMP THEN SIMP_TAC[PAIR_EQ; CONTRAPOS_THM] THEN
+     MATCH_MP_TAC(SET_RULE
+      `s SUBSET s' /\ t SUBSET t'
+       ==> s' INTER t' = {} ==> s INTER t = {}`) THEN CONJ_TAC THEN
+     MATCH_MP_TAC SUBSET_INTERIOR THEN REWRITE_TAC[INTER_SUBSET]]));;
+
+let EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GE = prove
+ (`!fs f:real^M->real^N a b.
+        fs equiintegrable_on interval[a,b] /\ f IN fs /\
+        (!h x. h IN fs /\ x IN interval[a,b] ==> norm(h x) <= norm(f x))
+        ==> { (\x. if x$i >= c then h x else vec 0) |
+              i IN 1..dimindex(:M) /\ c IN (:real) /\ h IN fs }
+            equiintegrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`{\x. (f:real^M->real^N) (--x) | f IN fs}`;
+    `\x. (f:real^M->real^N)(--x)`;
+    `--b:real^M`; `--a:real^M`]
+        EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LE) THEN
+  ASM_SIMP_TAC[EQUIINTEGRABLE_REFLECT] THEN ANTS_TAC THENL
+   [ASM_SIMP_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC] THEN
+    ONCE_REWRITE_TAC[GSYM IN_INTERVAL_REFLECT] THEN
+    ASM_SIMP_TAC[VECTOR_NEG_NEG] THEN
+    REWRITE_TAC[SIMPLE_IMAGE; IN_IMAGE] THEN
+    EXISTS_TAC `f:real^M->real^N` THEN ASM_REWRITE_TAC[];
+    DISCH_THEN(MP_TAC o MATCH_MP EQUIINTEGRABLE_REFLECT) THEN
+    REWRITE_TAC[VECTOR_NEG_NEG] THEN MATCH_MP_TAC
+     (REWRITE_RULE[IMP_CONJ_ALT] EQUIINTEGRABLE_SUBSET) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+    MAP_EVERY X_GEN_TAC [`i:num`; `c:real`; `h:real^M->real^N`] THEN
+    STRIP_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN EXISTS_TAC
+     `(\x. if (--x)$i >= c then (h:real^M->real^N)(--x) else vec 0)` THEN
+    REWRITE_TAC[VECTOR_NEG_NEG] THEN MAP_EVERY EXISTS_TAC
+     [`i:num`; `--c:real`; `\x. (h:real^M->real^N)(--x)`] THEN
+    ASM_REWRITE_TAC[IN_UNIV; VECTOR_NEG_COMPONENT] THEN
+    REWRITE_TAC[REAL_ARITH `--x >= c <=> x <= --c`] THEN
+    EXISTS_TAC `h:real^M->real^N` THEN ASM_REWRITE_TAC[]]);;
+
+let EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LT = prove
+ (`!fs f:real^M->real^N a b.
+        fs equiintegrable_on interval[a,b] /\ f IN fs /\
+        (!h x. h IN fs /\ x IN interval[a,b] ==> norm(h x) <= norm(f x))
+        ==> { (\x. if x$i < c then h x else vec 0) |
+              i IN 1..dimindex(:M) /\ c IN (:real) /\ h IN fs }
+            equiintegrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`fs:(real^M->real^N)->bool`; `f:real^M->real^N`;
+                 `a:real^M`; `b:real^M`]
+    EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GE) THEN
+  ASM_REWRITE_TAC[] THEN UNDISCH_TAC
+   `(fs:(real^M->real^N)->bool) equiintegrable_on interval[a,b]` THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP EQUIINTEGRABLE_SUB) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] EQUIINTEGRABLE_SUBSET) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+  MAP_EVERY X_GEN_TAC [`i:num`; `c:real`; `h:real^M->real^N`] THEN
+  STRIP_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  EXISTS_TAC `h:real^M->real^N` THEN
+  EXISTS_TAC `\x. if x$i >= c then (h:real^M->real^N) x else vec 0` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MAP_EVERY EXISTS_TAC [`i:num`; `c:real`; `h:real^M->real^N`] THEN
+    ASM_REWRITE_TAC[];
+    REWRITE_TAC[FUN_EQ_THM; real_ge; GSYM REAL_NOT_LT] THEN
+    GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+    VECTOR_ARITH_TAC]);;
+
+let EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GT = prove
+ (`!fs f:real^M->real^N a b.
+        fs equiintegrable_on interval[a,b] /\ f IN fs /\
+        (!h x. h IN fs /\ x IN interval[a,b] ==> norm(h x) <= norm(f x))
+        ==> { (\x. if x$i > c then h x else vec 0) |
+              i IN 1..dimindex(:M) /\ c IN (:real) /\ h IN fs }
+            equiintegrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`fs:(real^M->real^N)->bool`; `f:real^M->real^N`;
+                 `a:real^M`; `b:real^M`]
+    EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LE) THEN
+  ASM_REWRITE_TAC[] THEN UNDISCH_TAC
+   `(fs:(real^M->real^N)->bool) equiintegrable_on interval[a,b]` THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP EQUIINTEGRABLE_SUB) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] EQUIINTEGRABLE_SUBSET) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+  MAP_EVERY X_GEN_TAC [`i:num`; `c:real`; `h:real^M->real^N`] THEN
+  STRIP_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  EXISTS_TAC `h:real^M->real^N` THEN
+  EXISTS_TAC `\x. if x$i <= c then (h:real^M->real^N) x else vec 0` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MAP_EVERY EXISTS_TAC [`i:num`; `c:real`; `h:real^M->real^N`] THEN
+    ASM_REWRITE_TAC[];
+    REWRITE_TAC[FUN_EQ_THM; real_gt; GSYM REAL_NOT_LE] THEN
+    GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+    VECTOR_ARITH_TAC]);;
+
+let EQUIINTEGRABLE_OPEN_INTERVAL_RESTRICTIONS = prove
+ (`!f:real^M->real^N a b.
+        f integrable_on interval[a,b]
+        ==> { (\x. if x IN interval(c,d) then f x else vec 0) |
+              c IN (:real^M) /\ d IN (:real^M) }
+            equiintegrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!n. n <= dimindex(:M)
+        ==> f INSERT
+            { (\x. if !i. 1 <= i /\ i <= n ==> c$i < x$i /\ x$i < d$i
+                   then (f:real^M->real^N) x else vec 0) |
+              c IN (:real^M) /\ d IN (:real^M) }
+            equiintegrable_on interval[a,b]`
+  MP_TAC THENL
+   [MATCH_MP_TAC num_INDUCTION THEN
+    REWRITE_TAC[ARITH_RULE `~(1 <= i /\ i <= 0)`] THEN
+    ASM_REWRITE_TAC[ETA_AX; EQUIINTEGRABLE_ON_SING; SET_RULE
+     `f INSERT {f |c,d| c IN UNIV /\ d IN UNIV} = {f}`] THEN
+    X_GEN_TAC `n:num` THEN ASM_CASES_TAC `SUC n <= dimindex(:M)` THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o SPEC `f:real^M->real^N` o
+        MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LT)) THEN
+    REWRITE_TAC[IN_INSERT] THEN ANTS_TAC THENL
+     [REWRITE_TAC[TAUT
+       `a \/ b ==> c ==> d <=> (a ==> c ==> d) /\ (b ==> c ==> d)`] THEN
+      SIMP_TAC[REAL_LE_REFL; RIGHT_FORALL_IMP_THM] THEN
+      REWRITE_TAC[FORALL_IN_GSPEC] THEN
+      REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+      ASM_SIMP_TAC[NORM_0; REAL_LE_REFL; NORM_POS_LE];
+      ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM EQUIINTEGRABLE_ON_SING]) THEN
+    REWRITE_TAC[IMP_IMP] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP EQUIINTEGRABLE_UNION) THEN
+    DISCH_THEN(MP_TAC o SPEC `f:real^M->real^N` o
+        MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GT)) THEN
+    ASM_REWRITE_TAC[IN_UNION; IN_SING] THEN ANTS_TAC THENL
+     [REWRITE_TAC[TAUT
+       `a \/ b ==> c ==> d <=> (a ==> c ==> d) /\ (b ==> c ==> d)`] THEN
+      SIMP_TAC[REAL_LE_REFL; RIGHT_FORALL_IMP_THM] THEN
+      REWRITE_TAC[FORALL_IN_GSPEC; LEFT_OR_DISTRIB] THEN
+      REWRITE_TAC[TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN
+      SIMP_TAC[REAL_LE_REFL; RIGHT_FORALL_IMP_THM]  THEN
+      REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC;
+                  FORALL_AND_THM] THEN
+      SIMP_TAC[IN_UNIV] THEN
+      REPEAT STRIP_TAC THEN
+      REPEAT(COND_CASES_TAC THEN
+             ASM_SIMP_TAC[NORM_0; REAL_LE_REFL; NORM_POS_LE]);
+      ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM EQUIINTEGRABLE_ON_SING]) THEN
+    REWRITE_TAC[IMP_IMP] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP EQUIINTEGRABLE_UNION) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] EQUIINTEGRABLE_SUBSET) THEN
+    MATCH_MP_TAC(SET_RULE
+      `s SUBSET t ==> (x INSERT s) SUBSET ({x} UNION t)`) THEN
+    REWRITE_TAC[SUBSET; real_gt; FORALL_IN_GSPEC; IN_UNIV] THEN
+    MAP_EVERY X_GEN_TAC [`c:real^M`; `d:real^M`] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN EXISTS_TAC `SUC n` THEN
+    ASM_REWRITE_TAC[IN_NUMSEG; ARITH_RULE `1 <= SUC n`] THEN
+    EXISTS_TAC `(c:real^M)$(SUC n)` THEN
+    MATCH_MP_TAC(MESON[]
+     `(?i c k. P i c k /\ Q (g i c k))
+      ==> ?h. (h = f \/ ?i c k. P i c k /\ h = g i c k) /\ Q h`) THEN
+    EXISTS_TAC `SUC n` THEN
+    ASM_REWRITE_TAC[IN_NUMSEG; ARITH_RULE `1 <= SUC n`] THEN
+    EXISTS_TAC `(d:real^M)$(SUC n)` THEN
+    EXISTS_TAC
+     `\x. if !i. 1 <= i /\ i <= n ==> (c:real^M)$i < x$i /\ x$i < (d:real^M)$i
+          then (f:real^M->real^N) x else vec 0` THEN
+    REWRITE_TAC[] THEN CONJ_TAC THENL
+     [DISJ2_TAC THEN
+      MAP_EVERY EXISTS_TAC [`c:real^M`; `d:real^M`] THEN REWRITE_TAC[];
+      REWRITE_TAC[FUN_EQ_THM; LE] THEN
+      ASM_MESON_TAC[ARITH_RULE `1 <= SUC n`]];
+    DISCH_THEN(MP_TAC o SPEC `dimindex(:M)`) THEN
+    REWRITE_TAC[IN_INTERVAL; LE_REFL] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] EQUIINTEGRABLE_SUBSET) THEN
+    SET_TAC[]]);;
+
+let EQUIINTEGRABLE_CLOSED_INTERVAL_RESTRICTIONS = prove
+ (`!f:real^M->real^N a b.
+        f integrable_on interval[a,b]
+        ==> { (\x. if x IN interval[c,d] then f x else vec 0) |
+              c IN (:real^M) /\ d IN (:real^M) }
+            equiintegrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!n. n <= dimindex(:M)
+        ==> f INSERT
+            { (\x. if !i. 1 <= i /\ i <= n ==> c$i <= x$i /\ x$i <= d$i
+                   then (f:real^M->real^N) x else vec 0) |
+              c IN (:real^M) /\ d IN (:real^M) }
+            equiintegrable_on interval[a,b]`
+  MP_TAC THENL
+   [MATCH_MP_TAC num_INDUCTION THEN
+    REWRITE_TAC[ARITH_RULE `~(1 <= i /\ i <= 0)`] THEN
+    ASM_REWRITE_TAC[ETA_AX; EQUIINTEGRABLE_ON_SING; SET_RULE
+     `f INSERT {f |c,d| c IN UNIV /\ d IN UNIV} = {f}`] THEN
+    X_GEN_TAC `n:num` THEN ASM_CASES_TAC `SUC n <= dimindex(:M)` THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o SPEC `f:real^M->real^N` o
+        MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LE)) THEN
+    REWRITE_TAC[IN_INSERT] THEN ANTS_TAC THENL
+     [REWRITE_TAC[TAUT
+       `a \/ b ==> c ==> d <=> (a ==> c ==> d) /\ (b ==> c ==> d)`] THEN
+      SIMP_TAC[REAL_LE_REFL; RIGHT_FORALL_IMP_THM] THEN
+      REWRITE_TAC[FORALL_IN_GSPEC] THEN
+      REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+      ASM_SIMP_TAC[NORM_0; REAL_LE_REFL; NORM_POS_LE];
+      ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM EQUIINTEGRABLE_ON_SING]) THEN
+    REWRITE_TAC[IMP_IMP] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP EQUIINTEGRABLE_UNION) THEN
+    DISCH_THEN(MP_TAC o SPEC `f:real^M->real^N` o
+        MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GE)) THEN
+    ASM_REWRITE_TAC[IN_UNION; IN_SING] THEN ANTS_TAC THENL
+     [REWRITE_TAC[TAUT
+       `a \/ b ==> c ==> d <=> (a ==> c ==> d) /\ (b ==> c ==> d)`] THEN
+      SIMP_TAC[REAL_LE_REFL; RIGHT_FORALL_IMP_THM] THEN
+      REWRITE_TAC[FORALL_IN_GSPEC; LEFT_OR_DISTRIB] THEN
+      REWRITE_TAC[TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN
+      SIMP_TAC[REAL_LE_REFL; RIGHT_FORALL_IMP_THM]  THEN
+      REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC;
+                  FORALL_AND_THM] THEN
+      SIMP_TAC[IN_UNIV] THEN
+      REPEAT STRIP_TAC THEN
+      REPEAT(COND_CASES_TAC THEN
+             ASM_SIMP_TAC[NORM_0; REAL_LE_REFL; NORM_POS_LE]);
+      ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM EQUIINTEGRABLE_ON_SING]) THEN
+    REWRITE_TAC[IMP_IMP] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP EQUIINTEGRABLE_UNION) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] EQUIINTEGRABLE_SUBSET) THEN
+    MATCH_MP_TAC(SET_RULE
+      `s SUBSET t ==> (x INSERT s) SUBSET ({x} UNION t)`) THEN
+    REWRITE_TAC[SUBSET; real_ge; FORALL_IN_GSPEC; IN_UNIV] THEN
+    MAP_EVERY X_GEN_TAC [`c:real^M`; `d:real^M`] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN EXISTS_TAC `SUC n` THEN
+    ASM_REWRITE_TAC[IN_NUMSEG; ARITH_RULE `1 <= SUC n`] THEN
+    EXISTS_TAC `(c:real^M)$(SUC n)` THEN
+    MATCH_MP_TAC(MESON[]
+     `(?i c k. P i c k /\ Q (g i c k))
+      ==> ?h. (h = f \/ ?i c k. P i c k /\ h = g i c k) /\ Q h`) THEN
+    EXISTS_TAC `SUC n` THEN
+    ASM_REWRITE_TAC[IN_NUMSEG; ARITH_RULE `1 <= SUC n`] THEN
+    EXISTS_TAC `(d:real^M)$(SUC n)` THEN
+    EXISTS_TAC
+     `\x. if !i. 1 <= i /\ i <= n ==> (c:real^M)$i <= x$i /\ x$i <= (d:real^M)$i
+          then (f:real^M->real^N) x else vec 0` THEN
+    REWRITE_TAC[] THEN CONJ_TAC THENL
+     [DISJ2_TAC THEN
+      MAP_EVERY EXISTS_TAC [`c:real^M`; `d:real^M`] THEN REWRITE_TAC[];
+      REWRITE_TAC[FUN_EQ_THM; LE] THEN
+      ASM_MESON_TAC[ARITH_RULE `1 <= SUC n`]];
+    DISCH_THEN(MP_TAC o SPEC `dimindex(:M)`) THEN
+    REWRITE_TAC[IN_INTERVAL; LE_REFL] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] EQUIINTEGRABLE_SUBSET) THEN
+    SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Continuity of the indefinite integral.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let INDEFINITE_INTEGRAL_CONTINUOUS = prove
+ (`!f:real^M->real^N a b c d e.
+        f integrable_on interval[a,b] /\
+        c IN interval[a,b] /\ d IN interval[a,b] /\ &0 < e
+        ==> ?k. &0 < k /\
+                !c' d'. c' IN interval[a,b] /\
+                        d' IN interval[a,b] /\
+                        norm(c' - c) <= k /\ norm(d' - d) <= k
+                        ==> norm(integral(interval[c',d']) f -
+                                 integral(interval[c,d]) f) < e`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[MESON[] `(?k. P k /\ Q k) <=> ~(!k. P k ==> ~Q k)`] THEN
+  DISCH_THEN(MP_TAC o GEN `n:num` o SPEC `inv(&n + &1)`) THEN
+  PURE_REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN
+  REWRITE_TAC[REAL_LT_INV_EQ; REAL_ARITH `&0 < &n + &1`; SKOLEM_THM] THEN
+  REWRITE_TAC[NOT_EXISTS_THM; REAL_NOT_LT; GSYM CONJ_ASSOC] THEN
+  MAP_EVERY X_GEN_TAC [`u:num->real^M`; `v:num->real^M`] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC THEN
+  ABBREV_TAC
+   `k:real^M->bool =
+    UNIONS (IMAGE (\i. {x | x$i = (c:real^M)$i} UNION {x | x$i = (d:real^M)$i})
+                  (1..dimindex(:M)))` THEN
+  SUBGOAL_THEN `negligible(k:real^M->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "k" THEN MATCH_MP_TAC NEGLIGIBLE_UNIONS THEN
+    SIMP_TAC[FINITE_IMAGE; FINITE_NUMSEG; FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `i:num` THEN REWRITE_TAC[IN_NUMSEG] THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[NEGLIGIBLE_UNION; NEGLIGIBLE_STANDARD_HYPERPLANE];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`\n:num x. if x IN interval[u n,v n] then
+                 if x IN k then vec 0 else (f:real^M->real^N) x
+               else vec 0`;
+    `\x. if x IN interval[c,d] then
+            if x IN k then vec 0 else (f:real^M->real^N) x
+         else vec 0`;
+    `a:real^M`; `b:real^M`] EQUIINTEGRABLE_LIMIT) THEN
+  REWRITE_TAC[NOT_IMP] THEN REPEAT CONJ_TAC THENL
+   [SUBGOAL_THEN
+     `(\x. if x IN k then vec 0 else (f:real^M->real^N) x)
+      integrable_on interval[a,b]`
+    MP_TAC THENL
+     [UNDISCH_TAC `(f:real^M->real^N) integrable_on interval[a,b]` THEN
+      MATCH_MP_TAC INTEGRABLE_SPIKE THEN EXISTS_TAC `k:real^M->bool` THEN
+      ASM_REWRITE_TAC[] THEN SET_TAC[];
+      ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP
+      EQUIINTEGRABLE_CLOSED_INTERVAL_RESTRICTIONS) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] EQUIINTEGRABLE_SUBSET) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_UNIV] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    X_GEN_TAC `n:num` THEN MAP_EVERY EXISTS_TAC
+     [`(u:num->real^M) n`; `(v:num->real^M) n`] THEN
+    REWRITE_TAC[];
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `(x:real^M) IN k` THEN
+    ASM_REWRITE_TAC[COND_ID; LIM_CONST] THEN MATCH_MP_TAC LIM_EVENTUALLY THEN
+    REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+    MP_TAC(SPEC `inf (IMAGE (\i. min (abs((x:real^M)$i - (c:real^M)$i))
+                                     (abs((x:real^M)$i - (d:real^M)$i)))
+                            (1..dimindex(:M)))` REAL_ARCH_INV) THEN
+    SIMP_TAC[REAL_LT_INF_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY;
+             FINITE_NUMSEG; NUMSEG_EMPTY; NOT_LT; DIMINDEX_GE_1] THEN
+    ASM_SIMP_TAC[FORALL_IN_IMAGE; REAL_LT_MIN; IN_NUMSEG] THEN
+    UNDISCH_TAC `~((x:real^M) IN k)` THEN EXPAND_TAC "k" THEN
+    REWRITE_TAC[UNIONS_IMAGE; IN_ELIM_THM; NOT_EXISTS_THM] THEN
+    REWRITE_TAC[IN_NUMSEG; SET_RULE
+     `~(p /\ x IN (s UNION t)) <=> p ==> ~(x IN s) /\ ~(x IN t)`] THEN
+    REWRITE_TAC[IN_ELIM_THM; REAL_ARITH `&0 < abs(x - y) <=> ~(x = y)`] THEN
+    DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN STRIP_TAC THEN
+    X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `x IN interval[(u:num->real^M) n,v n] <=> x IN interval[c,d]`
+     (fun th -> REWRITE_TAC[th]) THEN
+    REWRITE_TAC[IN_INTERVAL] THEN AP_TERM_TAC THEN
+    GEN_REWRITE_TAC I [FUN_EQ_THM] THEN X_GEN_TAC `i:num` THEN
+    ASM_CASES_TAC `1 <= i /\ i <= dimindex(:M)` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `!N n. abs(u - c) <= n /\ abs(v - d) <= n /\
+            N < abs(x - c) /\ N < abs(x - d) /\ n <= N
+      ==> (u <= x /\ x <= v <=> c <= x /\ x <= d)`) THEN
+    MAP_EVERY EXISTS_TAC [`inv(&N)`; `inv(&n + &1)`] THEN
+    ASM_SIMP_TAC[] THEN REPEAT (CONJ_TAC THENL
+     [ASM_MESON_TAC[REAL_LE_TRANS; COMPONENT_LE_NORM; VECTOR_SUB_COMPONENT];
+      ALL_TAC]) THEN
+    MATCH_MP_TAC REAL_LE_INV2 THEN
+    REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+    ASM_ARITH_TAC;
+    DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+    REWRITE_TAC[INTEGRAL_RESTRICT_INTER] THEN
+    SUBGOAL_THEN
+     `interval[c:real^M,d] INTER interval[a,b] = interval[c,d] /\
+      !n:num. interval[u n,v n] INTER interval[a,b] = interval[u n,v n]`
+     (fun th -> SIMP_TAC[th])
+    THENL
+     [REWRITE_TAC[SET_RULE `s INTER t = s <=> s SUBSET t`] THEN
+      REWRITE_TAC[SUBSET_INTERVAL] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL]) THEN ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+    DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `N:num` (MP_TAC o SPEC `N:num`)) THEN
+    REWRITE_TAC[LE_REFL; REAL_NOT_LT] THEN
+    FIRST_ASSUM(fun th -> MP_TAC(SPEC `N:num` th) THEN MATCH_MP_TAC
+    (NORM_ARITH `x = a /\ y = b ==> e <= norm(x - y) ==> e <= dist(a,b)`)) THEN
+    CONJ_TAC THEN MATCH_MP_TAC INTEGRAL_SPIKE THEN
+    EXISTS_TAC `k:real^M->bool` THEN ASM_SIMP_TAC[IN_DIFF]]);;
+
+let INDEFINITE_INTEGRAL_CONTINUOUS_RIGHT = prove
+ (`!f:real^M->real^N a b.
+        f integrable_on interval[a,b]
+         ==> (\x. integral (interval[a,x]) f) continuous_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN REWRITE_TAC[continuous_within] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `a:real^M`; `b:real^M`;
+                 `a:real^M`; `x:real^M`; `e:real`]
+        INDEFINITE_INTEGRAL_CONTINUOUS) THEN
+  ASM_REWRITE_TAC[ENDS_IN_INTERVAL] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[dist]] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[ENDS_IN_INTERVAL; VECTOR_SUB_REFL; NORM_0; REAL_LT_IMP_LE] THEN
+  ASM SET_TAC[]);;
+
+let INDEFINITE_INTEGRAL_CONTINUOUS_LEFT = prove
+ (`!f:real^M->real^N a b.
+        f integrable_on interval[a,b]
+        ==> (\x. integral(interval[x,b]) f) continuous_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN REWRITE_TAC[continuous_within] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `a:real^M`; `b:real^M`;
+                 `x:real^M`; `b:real^M`; `e:real`]
+        INDEFINITE_INTEGRAL_CONTINUOUS) THEN
+  ASM_REWRITE_TAC[ENDS_IN_INTERVAL] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[dist]] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[ENDS_IN_INTERVAL; VECTOR_SUB_REFL; NORM_0; REAL_LT_IMP_LE] THEN
+  ASM SET_TAC[]);;
+
+let INDEFINITE_INTEGRAL_UNIFORMLY_CONTINUOUS = prove
+ (`!f:real^M->real^N a b.
+        f integrable_on interval[a,b]
+        ==> (\y. integral (interval[fstcart y,sndcart y]) f)
+            uniformly_continuous_on interval[pastecart a a,pastecart b b]`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC COMPACT_UNIFORMLY_CONTINUOUS THEN
+  REWRITE_TAC[COMPACT_INTERVAL; continuous_on] THEN
+  REWRITE_TAC[FORALL_PASTECART; GSYM PCROSS_INTERVAL; PCROSS] THEN
+  REWRITE_TAC[IN_ELIM_PASTECART_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  MAP_EVERY X_GEN_TAC [`c:real^M`; `d:real^M`] THEN STRIP_TAC THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN MP_TAC(ISPECL
+   [`f:real^M->real^N`; `a:real^M`; `b:real^M`; `c:real^M`; `d:real^M`;
+    `e:real`] INDEFINITE_INTEGRAL_CONTINUOUS) THEN
+  ASM_REWRITE_TAC[dist] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `k:real` THEN STRIP_TAC THEN ASM_REWRITE_TAC[PASTECART_SUB] THEN
+  ASM_MESON_TAC[NORM_LE_PASTECART; REAL_LT_IMP_LE; REAL_LE_TRANS]);;
+
+let INDEFINITE_INTEGRAL_UNIFORMLY_CONTINUOUS_EXPLICIT = prove
+ (`!f:real^M->real^N a b e.
+        f integrable_on interval[a,b] /\ &0 < e
+        ==> ?k. &0 < k /\
+                !c d c' d'. c IN interval[a,b] /\ d IN interval[a,b] /\
+                            c' IN interval[a,b] /\ d' IN interval[a,b] /\
+                            norm (c' - c) <= k /\ norm (d' - d) <= k
+                            ==> norm(integral(interval[c',d']) f -
+                                     integral(interval[c,d]) f) < e`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`f:real^M->real^N`; `a:real^M`; `b:real^M`]
+    INDEFINITE_INTEGRAL_UNIFORMLY_CONTINUOUS) THEN
+  ASM_REWRITE_TAC[uniformly_continuous_on] THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `k / &3` THEN CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`c:real^M`; `c':real^M`; `d:real^M`; `d':real^M`] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+   [`pastecart (c:real^M) (c':real^M)`;
+    `pastecart (d:real^M) (d':real^M)`]) THEN
+  REWRITE_TAC[GSYM PCROSS_INTERVAL; PCROSS] THEN
+  REWRITE_TAC[IN_ELIM_PASTECART_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  ASM_REWRITE_TAC[dist; PASTECART_SUB] THEN DISCH_THEN MATCH_MP_TAC THEN
+  ASM_MESON_TAC[NORM_PASTECART_LE; REAL_LET_TRANS;
+    REAL_ARITH `&0 < k /\ x <= k / &3 /\ y <= k / &3 ==> x + y < k`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Second mean value theorem and corollaries.                                *)
+(* ------------------------------------------------------------------------- *)
+
+let SECOND_MEAN_VALUE_THEOREM_FULL = prove
+ (`!f:real^1->real^1 g a b.
+        ~(interval[a,b] = {}) /\
+        f integrable_on interval [a,b] /\
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> g x <= g y)
+        ==> ?c. c IN interval [a,b] /\
+                ((\x. g x % f x) has_integral
+                 (g(a) % integral (interval[a,c]) f +
+                  g(b) % integral (interval[c,b]) f)) (interval[a,b])`,
+  let lemma1 = prove
+   (`!f:real->real s.
+      (!x. x IN s ==> &0 <= f x /\ f x <= &1)
+      ==> (!n x. x IN s /\ ~(n = 0)
+                 ==> abs(f x -
+                         sum(1..n) (\k. if &k / &n <= f(x)
+                                        then inv(&n) else &0)) < inv(&n))`,
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `?m. floor(&n * (f:real->real) x) = &m` CHOOSE_TAC THENL
+     [MATCH_MP_TAC FLOOR_POS THEN ASM_SIMP_TAC[REAL_LE_MUL; REAL_POS];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `!k. &k / &n <= (f:real->real) x <=> k <= m` ASSUME_TAC THENL
+     [REWRITE_TAC[GSYM REAL_OF_NUM_LE] THEN
+      FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; LE_1] THEN
+      SIMP_TAC[REAL_LE_FLOOR; INTEGER_CLOSED; REAL_MUL_SYM];
+      ALL_TAC] THEN
+    ASM_REWRITE_TAC[GSYM SUM_RESTRICT_SET] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `n + 1`) THEN
+    REWRITE_TAC[GSYM REAL_OF_NUM_ADD; real_div; REAL_ADD_RDISTRIB] THEN
+    ASM_SIMP_TAC[REAL_MUL_RINV; REAL_MUL_LID; REAL_OF_NUM_EQ] THEN
+    ASM_SIMP_TAC[REAL_ARITH `y <= &1 /\ &0 < i ==> ~(&1 + i <= y)`;
+                 REAL_LT_INV_EQ; REAL_OF_NUM_LT; LE_1; NOT_LE] THEN
+    SIMP_TAC[IN_NUMSEG; ARITH_RULE
+     `m < n + 1 ==> ((1 <= k /\ k <= n) /\ k <= m <=> 1 <= k /\ k <= m)`] THEN
+    DISCH_TAC THEN REWRITE_TAC[GSYM numseg; SUM_CONST_NUMSEG; ADD_SUB] THEN
+    MATCH_MP_TAC REAL_LT_LCANCEL_IMP THEN EXISTS_TAC `abs(&n)` THEN
+    REWRITE_TAC[GSYM REAL_ABS_MUL] THEN
+    ASM_SIMP_TAC[REAL_ABS_NUM; REAL_MUL_RINV; REAL_OF_NUM_EQ] THEN
+    ASM_SIMP_TAC[REAL_OF_NUM_LT; LE_1; REAL_SUB_LDISTRIB; GSYM real_div] THEN
+    ASM_SIMP_TAC[REAL_DIV_LMUL; REAL_OF_NUM_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH `f <= x /\ x < f + &1 ==> abs(x - f) < &1`) THEN
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN REWRITE_TAC[FLOOR]) in
+  let lemma2 = prove
+   (`!f:real^1->real^N g a b.
+          f integrable_on interval[a,b] /\
+          (!x y. drop x <= drop y ==> g(x) <= g(y))
+          ==> {(\x. if c <= g(x) then f x else vec 0) | c IN (:real)}
+              equiintegrable_on interval[a,b]`,
+    REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM EQUIINTEGRABLE_ON_SING]) THEN
+    DISCH_THEN(fun th ->
+     MP_TAC(SPEC `f:real^1->real^N` (MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GE) th)) THEN
+     MP_TAC(SPEC `f:real^1->real^N` (MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GT) th)) THEN
+      MP_TAC th) THEN
+    SIMP_TAC[IN_SING; REAL_LE_REFL] THEN
+    SUBGOAL_THEN `{(\x. vec 0):real^1->real^N} equiintegrable_on interval[a,b]`
+    MP_TAC THENL
+     [REWRITE_TAC[EQUIINTEGRABLE_ON_SING; INTEGRABLE_CONST]; ALL_TAC] THEN
+    REPEAT(ONCE_REWRITE_TAC[IMP_IMP] THEN
+           DISCH_THEN(MP_TAC o MATCH_MP EQUIINTEGRABLE_UNION)) THEN
+    REWRITE_TAC[NUMSEG_SING; DIMINDEX_1; IN_SING] THEN
+    REWRITE_TAC[SET_RULE `{m i c h | i = 1 /\ c IN (:real) /\ h = f} =
+                          {m 1 c f | c IN (:real)}`] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] EQUIINTEGRABLE_SUBSET) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_UNIV] THEN
+    X_GEN_TAC `y:real` THEN
+    ASM_CASES_TAC `!x. y <= (g:real^1->real) x` THENL
+     [ASM_REWRITE_TAC[ETA_AX; IN_UNION; IN_SING]; ALL_TAC] THEN
+    ASM_CASES_TAC `!x. ~(y <= (g:real^1->real) x)` THENL
+     [ASM_REWRITE_TAC[ETA_AX; IN_UNION; IN_SING]; ALL_TAC] THEN
+    MP_TAC(ISPEC `IMAGE drop {x | y <= (g:real^1->real) x}` INF) THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; IN_ELIM_THM; IMAGE_EQ_EMPTY] THEN
+    ANTS_TAC THENL
+     [ASM_REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY] THEN
+      ASM_MESON_TAC[REAL_LE_TRANS; REAL_LE_TOTAL];
+      STRIP_TAC THEN REWRITE_TAC[real_gt; real_ge]] THEN
+    REWRITE_TAC[IN_UNION; GSYM DISJ_ASSOC] THEN
+    ASM_CASES_TAC `y <= g(lift(inf(IMAGE drop {x | y <= g x})))` THENL
+     [REPEAT DISJ2_TAC; REPLICATE_TAC 2 DISJ2_TAC THEN DISJ1_TAC] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    EXISTS_TAC `inf(IMAGE drop {x | y <= g x})` THEN
+    REWRITE_TAC[FUN_EQ_THM] THEN
+    MATCH_MP_TAC(MESON[]
+     `(!x. P x <=> Q x)
+      ==> !x. (if P x then f x else b) = (if Q x then f x else b)`) THEN
+    X_GEN_TAC `x:real^1` THEN REWRITE_TAC[GSYM REAL_NOT_LE; GSYM drop] THEN
+    ASM_MESON_TAC[REAL_LE_TOTAL; REAL_LT_ANTISYM; REAL_LE_TRANS; LIFT_DROP]) in
+  let lemma3 = prove
+   (`!f:real^1->real^N g a b.
+          f integrable_on interval[a,b] /\
+          (!x y. drop x <= drop y ==> g(x) <= g(y))
+          ==> {(\x. vsum (1..n)
+                     (\k. if &k / &n <= g x then inv(&n) % f(x) else vec 0)) |
+               ~(n = 0)}
+              equiintegrable_on interval[a,b]`,
+    REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o
+     MATCH_MP lemma2) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP
+     (INST_TYPE [`:num`,`:A`] EQUIINTEGRABLE_SUM)) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] EQUIINTEGRABLE_SUBSET) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_UNIV] THEN X_GEN_TAC `n:num` THEN
+    DISCH_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    MAP_EVERY EXISTS_TAC [`1..n`; `\k:num. inv(&n)`;
+     `\k x. if &k / &n <= g x then (f:real^1->real^N) x else vec 0`] THEN
+    ASM_SIMP_TAC[SUM_CONST_NUMSEG; ADD_SUB; REAL_MUL_RINV; REAL_OF_NUM_EQ] THEN
+    REWRITE_TAC[FINITE_NUMSEG; COND_RAND; COND_RATOR; VECTOR_MUL_RZERO] THEN
+    X_GEN_TAC `k:num` THEN
+    REWRITE_TAC[IN_NUMSEG; REAL_LE_INV_EQ; REAL_POS] THEN STRIP_TAC THEN
+    EXISTS_TAC `&k / &n` THEN REWRITE_TAC[]) in
+  let lemma4 = prove
+   (`!f:real^1->real^1 g a b.
+          ~(interval[a,b] = {}) /\
+          f integrable_on interval[a,b] /\
+          (!x y. drop x <= drop y ==> g(x) <= g(y)) /\
+          (!x. x IN interval[a,b] ==> &0 <= g x /\ g x <= &1)
+          ==> (\x. g(x) % f(x)) integrable_on interval[a,b] /\
+              ?c. c IN interval[a,b] /\
+                  integral (interval[a,b]) (\x. g(x) % f(x)) =
+                  integral (interval[c,b]) f`,
+    REPEAT GEN_TAC THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `?m M. IMAGE (\x. integral (interval[x,b]) (f:real^1->real^1))
+                  (interval[a,b]) = interval[m,M]`
+    STRIP_ASSUME_TAC THENL
+     [REWRITE_TAC[GSYM CONNECTED_COMPACT_INTERVAL_1] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE;
+        MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE] THEN
+      ASM_SIMP_TAC[INDEFINITE_INTEGRAL_CONTINUOUS_LEFT; CONVEX_CONNECTED;
+                   CONVEX_INTERVAL; COMPACT_INTERVAL];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL[`f:real^1->real^1`; `g:real^1->real`; `a:real^1`; `b:real^1`]
+          lemma3) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `!n. ?c. c IN interval[a,b] /\
+              integral (interval[c,b]) (f:real^1->real^1) =
+              integral (interval[a,b])
+                (\x. vsum (1..n)
+                    (\k. if &k / &n <= g x then inv(&n) % f x else vec 0))`
+    MP_TAC THENL
+     [X_GEN_TAC `n:num` THEN ASM_CASES_TAC `n = 0` THENL
+       [ASM_REWRITE_TAC[VSUM_CLAUSES_NUMSEG; ARITH_EQ; INTEGRAL_0] THEN
+        EXISTS_TAC `b:real^1` THEN ASM_REWRITE_TAC[ENDS_IN_INTERVAL] THEN
+        SIMP_TAC[INTEGRAL_NULL; CONTENT_EQ_0_1; REAL_LE_REFL];
+        ALL_TAC] THEN
+      MP_TAC(ISPECL [`f:real^1->real^1`; `g:real^1->real`;
+                     `a:real^1`; `b:real^1`] lemma2) THEN
+      ASM_REWRITE_TAC[equiintegrable_on; FORALL_IN_GSPEC; IN_UNIV] THEN
+      DISCH_THEN(ASSUME_TAC o CONJUNCT1) THEN
+      REWRITE_TAC[MESON[VECTOR_MUL_RZERO]
+       `(if p then a % x else vec 0:real^1) =
+        a % (if p then x else vec 0)`] THEN
+      ASM_SIMP_TAC[VSUM_LMUL; INTEGRAL_CMUL; INTEGRABLE_VSUM; ETA_AX;
+                   FINITE_NUMSEG; INTEGRAL_VSUM] THEN
+      SUBGOAL_THEN
+       `!y:real. ?d:real^1.
+          d IN interval[a,b] /\
+          integral (interval[a,b]) (\x. if y <= g x then f x else vec 0) =
+          integral (interval[d,b]) (f:real^1->real^1)`
+      MP_TAC THENL
+       [X_GEN_TAC `y:real` THEN
+        SUBGOAL_THEN
+         `{x | y <= g x} = {} \/
+          {x | y <= g x} = (:real^1) \/
+          (?a. {x | y <= g x} = {x | a <= drop x}) \/
+          (?a. {x | y <= g x} = {x | a < drop x})`
+        MP_TAC THENL
+         [MATCH_MP_TAC(TAUT `(~a /\ ~b ==> c \/ d) ==> a \/ b \/ c \/ d`) THEN
+          DISCH_TAC THEN
+          MP_TAC(ISPEC `IMAGE drop {x | y <= (g:real^1->real) x}` INF) THEN
+          ASM_REWRITE_TAC[FORALL_IN_IMAGE; IN_ELIM_THM; IMAGE_EQ_EMPTY] THEN
+          ANTS_TAC THENL
+           [FIRST_ASSUM(MP_TAC o CONJUNCT2) THEN
+            REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_UNIV] THEN
+            ASM_MESON_TAC[REAL_LE_TRANS; REAL_LE_TOTAL];
+            STRIP_TAC] THEN
+          ASM_CASES_TAC `y <= g(lift(inf(IMAGE drop {x | y <= g x})))` THENL
+           [DISJ1_TAC; DISJ2_TAC] THEN
+          REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+          EXISTS_TAC `inf(IMAGE drop {x | y <= g x})` THEN
+          REWRITE_TAC[FUN_EQ_THM] THEN
+          X_GEN_TAC `x:real^1` THEN
+          REWRITE_TAC[GSYM REAL_NOT_LE; GSYM drop] THEN
+          ASM_MESON_TAC[REAL_LE_TOTAL; REAL_LT_ANTISYM;
+                        REAL_LE_TRANS; LIFT_DROP];
+          REWRITE_TAC[EXTENSION; IN_UNIV; NOT_IN_EMPTY; IN_ELIM_THM] THEN
+          DISCH_THEN(DISJ_CASES_THEN2 ASSUME_TAC MP_TAC) THENL
+           [EXISTS_TAC `b:real^1` THEN ASM_REWRITE_TAC[] THEN
+            SIMP_TAC[INTEGRAL_NULL; CONTENT_EQ_0_1; REAL_LE_REFL] THEN
+            ASM_REWRITE_TAC[ENDS_IN_INTERVAL; INTEGRAL_0];
+            ALL_TAC] THEN
+          DISCH_THEN(DISJ_CASES_THEN2 ASSUME_TAC MP_TAC) THENL
+           [EXISTS_TAC `a:real^1` THEN
+            ASM_REWRITE_TAC[ETA_AX; ENDS_IN_INTERVAL];
+            ALL_TAC] THEN
+          GEN_REWRITE_TAC LAND_CONV [OR_EXISTS_THM] THEN
+          REWRITE_TAC[EXISTS_DROP] THEN
+          DISCH_THEN(X_CHOOSE_THEN `d:real^1` ASSUME_TAC) THEN
+          ASM_CASES_TAC `drop d < drop a` THENL
+           [EXISTS_TAC `a:real^1` THEN
+            ASM_REWRITE_TAC[ETA_AX; ENDS_IN_INTERVAL] THEN
+            MATCH_MP_TAC INTEGRAL_EQ THEN
+            REWRITE_TAC[IN_DIFF; IN_INTERVAL_1; NOT_IN_EMPTY] THEN
+            GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+            UNDISCH_TAC `~(y <= (g:real^1->real) x)` THEN
+            FIRST_X_ASSUM DISJ_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+            ASM_REAL_ARITH_TAC;
+            ALL_TAC] THEN
+          ASM_CASES_TAC `drop b < drop d` THENL
+           [EXISTS_TAC `b:real^1` THEN
+            SIMP_TAC[INTEGRAL_NULL; CONTENT_EQ_0_1; REAL_LE_REFL] THEN
+            ASM_REWRITE_TAC[ENDS_IN_INTERVAL; INTEGRAL_0] THEN
+            MATCH_MP_TAC INTEGRAL_EQ_0 THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+            REPEAT STRIP_TAC THEN
+            COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+            UNDISCH_TAC `y <= (g:real^1->real) x` THEN
+            FIRST_X_ASSUM DISJ_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+            ASM_REAL_ARITH_TAC;
+            ALL_TAC] THEN
+          EXISTS_TAC `d:real^1` THEN
+          ASM_REWRITE_TAC[IN_INTERVAL_1; GSYM REAL_NOT_LT] THEN
+          ONCE_REWRITE_TAC[SET_RULE
+            `~((g:real^1->real) x < y) <=> x IN {x | ~(g x < y)}`] THEN
+          REWRITE_TAC[INTEGRAL_RESTRICT_INTER] THEN
+          MATCH_MP_TAC INTEGRAL_SPIKE_SET THEN
+          MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC `{d:real^1}` THEN
+          REWRITE_TAC[NEGLIGIBLE_SING; REAL_NOT_LT; SUBSET] THEN GEN_TAC THEN
+          REWRITE_TAC[SUBSET; IN_UNION; IN_INTER; IN_DIFF; IN_INTERVAL_1;
+                      IN_ELIM_THM; IN_SING; GSYM DROP_EQ] THEN
+          FIRST_X_ASSUM DISJ_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+          ASM_REAL_ARITH_TAC];
+        DISCH_THEN(MP_TAC o GEN `k:num` o SPEC `&k / &n`) THEN
+        REWRITE_TAC[SKOLEM_THM; FORALL_AND_THM; LEFT_IMP_EXISTS_THM] THEN
+        X_GEN_TAC `d:num->real^1` THEN STRIP_TAC THEN
+        FIRST_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+         `IMAGE f s = t ==> !y. y IN t ==> ?x. x IN s /\ f x = y`)) THEN
+        REWRITE_TAC[GSYM VSUM_LMUL] THEN DISCH_THEN MATCH_MP_TAC THEN
+        MATCH_MP_TAC(REWRITE_RULE[CONVEX_INDEXED]
+         (CONJUNCT1(SPEC_ALL CONVEX_INTERVAL))) THEN
+        REWRITE_TAC[SUM_CONST_NUMSEG; ADD_SUB; REAL_LE_INV_EQ; REAL_POS] THEN
+        ASM_SIMP_TAC[REAL_MUL_RINV; REAL_OF_NUM_EQ] THEN ASM SET_TAC[]];
+      REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM; FORALL_AND_THM] THEN
+      X_GEN_TAC `c:num->real^1` THEN DISCH_THEN(STRIP_ASSUME_TAC o GSYM)] THEN
+    SUBGOAL_THEN `compact(interval[a:real^1,b])` MP_TAC THENL
+     [REWRITE_TAC[COMPACT_INTERVAL]; REWRITE_TAC[compact]] THEN
+    DISCH_THEN(MP_TAC o SPEC `c:num->real^1`) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN MAP_EVERY X_GEN_TAC
+     [`d:real^1`; `s:num->num`] THEN STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`\n:num x. vsum (1..(s n))
+                      (\k. if &k / &(s n) <= g x
+                           then inv(&(s n)) % (f:real^1->real^1) x
+                           else vec 0)`;
+      `\x. g x % (f:real^1->real^1) x`; `a:real^1`; `b:real^1`]
+     EQUIINTEGRABLE_LIMIT) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [CONJ_TAC THENL
+       [MATCH_MP_TAC EQUIINTEGRABLE_SUBSET THEN
+        EXISTS_TAC
+         `{\x. vsum(1..0) (\k. if &k / &0 <= g x
+                               then inv(&0) % (f:real^1->real^1) x else vec 0)}
+          UNION
+          {\x. vsum (1..n)
+                    (\k. if &k / &n <= g x then inv (&n) % f x else vec 0)
+           | ~(n = 0)}` THEN
+        CONJ_TAC THENL
+         [MATCH_MP_TAC EQUIINTEGRABLE_UNION THEN ASM_REWRITE_TAC[] THEN
+          REWRITE_TAC[EQUIINTEGRABLE_ON_SING; VSUM_CLAUSES_NUMSEG;
+                      ARITH_EQ] THEN
+          REWRITE_TAC[INTEGRABLE_0];
+          REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_UNIV; IN_UNION] THEN
+          REWRITE_TAC[IN_ELIM_THM; IN_SING] THEN
+          X_GEN_TAC `n:num` THEN ASM_CASES_TAC `(s:num->num) n = 0` THEN
+          ASM_REWRITE_TAC[] THEN DISJ2_TAC THEN
+          EXISTS_TAC `(s:num->num) n` THEN ASM_REWRITE_TAC[]];
+        X_GEN_TAC `x:real^1` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+        ONCE_REWRITE_TAC[MESON[VECTOR_MUL_LZERO]
+         `(if p then a % x else vec 0) = (if p then a else &0) % x`] THEN
+        REWRITE_TAC[VSUM_RMUL] THEN MATCH_MP_TAC LIM_VMUL THEN
+        REWRITE_TAC[LIM_SEQUENTIALLY; o_DEF; DIST_LIFT] THEN
+        X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+        MP_TAC(ISPEC `e:real` REAL_ARCH_INV) THEN
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+        X_GEN_TAC `N:num` THEN STRIP_TAC THEN X_GEN_TAC `n:num` THEN
+        DISCH_TAC THEN
+        ONCE_REWRITE_TAC[REAL_ABS_SUB] THEN
+        MATCH_MP_TAC REAL_LT_TRANS THEN EXISTS_TAC `inv(&n)` THEN
+        CONJ_TAC THENL
+         [MP_TAC(ISPECL
+           [`(g:real^1->real) o lift`; `IMAGE drop (interval[a,b])`]
+            lemma1) THEN
+          ASM_REWRITE_TAC[FORALL_IN_IMAGE; o_DEF; LIFT_DROP; IMP_CONJ;
+                          RIGHT_FORALL_IMP_THM] THEN
+          REWRITE_TAC[IMP_IMP] THEN DISCH_TAC THEN
+          MATCH_MP_TAC REAL_LTE_TRANS THEN
+          EXISTS_TAC `inv(&((s:num->num) n))` THEN CONJ_TAC THENL
+           [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[];
+            MATCH_MP_TAC REAL_LE_INV2 THEN
+            REWRITE_TAC[REAL_OF_NUM_LE; REAL_OF_NUM_LT]] THEN
+          FIRST_ASSUM(MP_TAC o SPEC `n:num` o MATCH_MP MONOTONE_BIGGER) THEN
+          ASM_ARITH_TAC;
+          MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `inv(&N)` THEN
+          ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+          REWRITE_TAC[REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN ASM_ARITH_TAC]];
+      STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      EXISTS_TAC `d:real^1` THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(ISPEC `sequentially` LIM_UNIQUE) THEN
+      EXISTS_TAC `\n. integral (interval [c((s:num->num) n),b])
+                               (f:real^1->real^1)` THEN
+      ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+      MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `b:real^1`]
+          INDEFINITE_INTEGRAL_CONTINUOUS_LEFT) THEN
+      ASM_REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+      DISCH_THEN(MP_TAC o SPEC `d:real^1`) THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[CONTINUOUS_WITHIN_SEQUENTIALLY] THEN
+      DISCH_THEN(MP_TAC o SPEC `(c:num->real^1) o (s:num->num)`) THEN
+      ASM_REWRITE_TAC[] THEN ASM_REWRITE_TAC[o_DEF]]) in
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  SUBGOAL_THEN `(g:real^1->real) a <= g b` MP_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[ENDS_IN_INTERVAL] THEN
+    ASM_MESON_TAC[INTERVAL_EQ_EMPTY_1; REAL_LET_TOTAL];
+    ALL_TAC] THEN
+  REWRITE_TAC[REAL_LE_LT] THEN STRIP_TAC THENL
+   [ALL_TAC;
+    SUBGOAL_THEN
+     `!x. x IN interval[a,b] ==> g(x) % (f:real^1->real^1)(x) = g(a) % f x`
+    ASSUME_TAC THENL
+     [X_GEN_TAC `x:real^1` THEN
+      REWRITE_TAC[IN_INTERVAL_1] THEN STRIP_TAC THEN
+      AP_THM_TAC THEN AP_TERM_TAC THEN
+      RULE_ASSUM_TAC(REWRITE_RULE
+       [IN_INTERVAL_1; INTERVAL_EQ_EMPTY_1; REAL_NOT_LT]) THEN
+      ASM_MESON_TAC[REAL_LE_ANTISYM; REAL_LE_TRANS; REAL_LE_TOTAL];
+      ALL_TAC] THEN
+    EXISTS_TAC `a:real^1` THEN ASM_REWRITE_TAC[ENDS_IN_INTERVAL] THEN
+    MATCH_MP_TAC HAS_INTEGRAL_EQ THEN
+    EXISTS_TAC `\x. g(a:real^1) % (f:real^1->real^1) x` THEN
+    ASM_SIMP_TAC[INTEGRAL_NULL; CONTENT_EQ_0_1; REAL_LE_REFL] THEN
+    ASM_SIMP_TAC[INTEGRAL_CMUL; VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+    MATCH_MP_TAC HAS_INTEGRAL_CMUL THEN
+    ASM_REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL]] THEN
+  MP_TAC(ISPECL
+   [`f:real^1->real^1`;
+    `\x. if drop x < drop a then &0
+         else if drop b < drop x then &1
+         else (g(x) - g(a)) / (g(b) - g(a))`;
+    `a:real^1`; `b:real^1`]
+   lemma4) THEN ASM_REWRITE_TAC[] THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THEN
+    REPEAT GEN_TAC THEN
+    REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_POS; REAL_LE_REFL]) THEN
+    TRY ASM_REAL_ARITH_TAC THEN
+    ASM_SIMP_TAC[IN_INTERVAL_1; REAL_LE_DIV2_EQ; REAL_SUB_LT] THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; REAL_SUB_LT] THEN
+    ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID; REAL_SUB_LE;
+                    REAL_ARITH `x - a <= y - a <=> x <= y`] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[IN_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^1` THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> b ==> a /\ c ==> d`] THEN
+  DISCH_TAC THEN ASM_REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRABLE_INTEGRAL] THEN
+  DISCH_THEN(MP_TAC o SPEC `(g:real^1->real) b - g a` o
+        MATCH_MP HAS_INTEGRAL_CMUL) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP INTEGRABLE_INTEGRAL) THEN
+  DISCH_THEN(MP_TAC o SPEC `(g:real^1->real)(a)` o
+      MATCH_MP HAS_INTEGRAL_CMUL) THEN REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_ADD) THEN
+  MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `b:real^1`; `c:real^1`]
+        INTEGRAL_COMBINE) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[IN_INTERVAL_1]; ALL_TAC] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `ga % (i1 + i2) + (gb - ga) % i2:real^N = ga % i1 + gb % i2`] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HAS_INTEGRAL_EQ) THEN
+  X_GEN_TAC `x:real^1` THEN REWRITE_TAC[IN_INTERVAL_1] THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[GSYM REAL_NOT_LE; VECTOR_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_DIV_LMUL; REAL_LT_IMP_NZ; REAL_SUB_LT] THEN
+  VECTOR_ARITH_TAC);;
+
+let SECOND_MEAN_VALUE_THEOREM = prove
+ (`!f:real^1->real^1 g a b.
+        ~(interval[a,b] = {}) /\
+        f integrable_on interval [a,b] /\
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> g x <= g y)
+        ==> ?c. c IN interval [a,b] /\
+                integral (interval[a,b]) (\x. g x % f x) =
+                 g(a) % integral (interval[a,c]) f +
+                 g(b) % integral (interval[c,b]) f`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SECOND_MEAN_VALUE_THEOREM_FULL) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^1` THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP INTEGRAL_UNIQUE) THEN REWRITE_TAC[]);;
+
+let SECOND_MEAN_VALUE_THEOREM_GEN_FULL = prove
+ (`!f:real^1->real^1 g a b u v.
+        ~(interval[a,b] = {}) /\ f integrable_on interval [a,b] /\
+        (!x. x IN interval(a,b) ==> u <= g x /\ g x <= v) /\
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> g x <= g y)
+        ==> ?c. c IN interval [a,b] /\
+                ((\x. g x % f x) has_integral
+                 (u % integral (interval[a,c]) f +
+                  v % integral (interval[c,b]) f)) (interval[a,b])`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `b:real^1 = a` THENL
+   [EXISTS_TAC `a:real^1` THEN ASM_REWRITE_TAC[INTERVAL_SING; IN_SING] THEN
+    ASM_SIMP_TAC[GSYM INTERVAL_SING; INTEGRAL_NULL; CONTENT_EQ_0_1;
+      VECTOR_ADD_LID; REAL_LE_REFL; VECTOR_MUL_RZERO; HAS_INTEGRAL_NULL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `drop a < drop b` ASSUME_TAC THENL
+   [ASM_MESON_TAC[INTERVAL_EQ_EMPTY_1; REAL_NOT_LE; DROP_EQ; REAL_LT_LE];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `u <= v` ASSUME_TAC THENL
+   [ASM_MESON_TAC[INTERVAL_EQ_EMPTY_1; MEMBER_NOT_EMPTY; REAL_NOT_LT;
+                  REAL_LE_TRANS];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`f:real^1->real^1`;
+    `\x:real^1. if x = a then u else if x = b then v else g x:real`;
+    `a:real^1`; `b:real^1`] SECOND_MEAN_VALUE_THEOREM_FULL) THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_LID] THEN ANTS_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN
+    ASM_CASES_TAC `x:real^1 = a` THEN ASM_REWRITE_TAC[] THENL
+     [ASM_MESON_TAC[REAL_LE_REFL; INTERVAL_CASES_1]; ALL_TAC] THEN
+    ASM_CASES_TAC `y:real^1 = b` THEN ASM_REWRITE_TAC[] THENL
+     [ASM_MESON_TAC[REAL_LE_REFL; INTERVAL_CASES_1]; ALL_TAC] THEN
+    REPEAT(COND_CASES_TAC THEN ASM_SIMP_TAC[]) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM DROP_EQ]) THEN
+    REWRITE_TAC[IN_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^1` THEN
+    MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN MATCH_MP_TAC
+     (REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+        HAS_INTEGRAL_SPIKE) THEN
+    EXISTS_TAC `{a:real^1,b}` THEN
+    SIMP_TAC[NEGLIGIBLE_EMPTY; NEGLIGIBLE_INSERT; IN_DIFF; IN_INSERT;
+             NOT_IN_EMPTY; DE_MORGAN_THM]]);;
+
+let SECOND_MEAN_VALUE_THEOREM_GEN = prove
+ (`!f:real^1->real^1 g a b u v.
+        ~(interval[a,b] = {}) /\ f integrable_on interval [a,b] /\
+        (!x. x IN interval(a,b) ==> u <= g x /\ g x <= v) /\
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> g x <= g y)
+        ==> ?c. c IN interval [a,b] /\
+                integral (interval[a,b]) (\x. g x % f x) =
+                u % integral (interval[a,c]) f +
+                v % integral (interval[c,b]) f`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SECOND_MEAN_VALUE_THEOREM_GEN_FULL) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^1` THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP INTEGRAL_UNIQUE) THEN REWRITE_TAC[]);;
+
+let SECOND_MEAN_VALUE_THEOREM_BONNET_FULL = prove
+ (`!f:real^1->real^1 g a b.
+        ~(interval[a,b] = {}) /\ f integrable_on interval [a,b] /\
+        (!x. x IN interval[a,b] ==> &0 <= g x) /\
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> g x <= g y)
+        ==> ?c. c IN interval [a,b] /\
+                ((\x. g x % f x) has_integral
+                 (g(b) % integral (interval[c,b]) f)) (interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`f:real^1->real^1`; `g:real^1->real`; `a:real^1`; `b:real^1`;
+    `&0`; `(g:real^1->real) b`] SECOND_MEAN_VALUE_THEOREM_GEN_FULL) THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_LID] THEN
+  DISCH_THEN MATCH_MP_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[IN_INTERVAL_1] THEN ASM_REAL_ARITH_TAC);;
+
+let SECOND_MEAN_VALUE_THEOREM_BONNET = prove
+ (`!f:real^1->real^1 g a b.
+        ~(interval[a,b] = {}) /\ f integrable_on interval[a,b] /\
+        (!x. x IN interval[a,b] ==> &0 <= g x) /\
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> g x <= g y)
+        ==> ?c. c IN interval [a,b] /\
+                integral (interval[a,b]) (\x. g x % f x) =
+                g(b) % integral (interval[c,b]) f`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SECOND_MEAN_VALUE_THEOREM_BONNET_FULL) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^1` THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP INTEGRAL_UNIQUE) THEN REWRITE_TAC[]);;
+
+let INTEGRABLE_INCREASING_PRODUCT = prove
+ (`!f:real^1->real^N g a b.
+        f integrable_on interval[a,b] /\
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> g(x) <= g(y))
+        ==> (\x. g(x) % f(x)) integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `interval[a:real^1,b] = {}` THEN
+  ASM_REWRITE_TAC[INTEGRABLE_ON_EMPTY] THEN
+  ONCE_REWRITE_TAC[INTEGRABLE_COMPONENTWISE] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\x. lift((f:real^1->real^N) x$i)`;
+                 `g:real^1->real`; `a:real^1`; `b:real^1`]
+    SECOND_MEAN_VALUE_THEOREM_FULL) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [RULE_ASSUM_TAC(ONCE_REWRITE_RULE[INTEGRABLE_COMPONENTWISE]) THEN
+    ASM_SIMP_TAC[];
+    REWRITE_TAC[VECTOR_MUL_COMPONENT; LIFT_CMUL; integrable_on] THEN
+    MESON_TAC[]]);;
+
+let INTEGRABLE_INCREASING_PRODUCT_UNIV = prove
+ (`!f:real^1->real^N g B.
+        f integrable_on (:real^1) /\
+        (!x y. drop x <= drop y ==> g x <= g y) /\
+        (!x. abs(g x) <= B)
+         ==> (\x. g x % f x) integrable_on (:real^1)`,
+  let lemma = prove
+   (`!f:real^1->real^1 g B.
+          f integrable_on (:real^1) /\
+          (!x y. drop x <= drop y ==> g x <= g y) /\
+          (!x. abs(g x) <= B)
+           ==> (\x. g x % f x) integrable_on (:real^1)`,
+    REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[INTEGRABLE_ALT_SUBSET] THEN
+    REWRITE_TAC[IN_UNIV; ETA_AX] THEN STRIP_TAC THEN
+    MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+     [REPEAT GEN_TAC THEN MATCH_MP_TAC INTEGRABLE_INCREASING_PRODUCT THEN
+      ASM_SIMP_TAC[];
+      DISCH_TAC] THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `e / (&8 * abs B + &8)`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < &8 * abs B + &8`] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `C:real` THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `~(ball(vec 0:real^1,C) = {})` ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[BALL_EQ_EMPTY; REAL_NOT_LE]; ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^1`; `b:real^1`; `c:real^1`; `d:real^1`] THEN
+    STRIP_TAC THEN SUBGOAL_THEN
+     `~(interval[a:real^1,b] = {}) /\ ~(interval[c:real^1,d] = {})`
+    MP_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    REWRITE_TAC[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT] THEN STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET_INTERVAL_1]) THEN
+    ASM_REWRITE_TAC[GSYM REAL_NOT_LE] THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`\x. g x % (f:real^1->real^1) x`;
+                   `c:real^1`; `b:real^1`; `a:real^1`] INTEGRAL_COMBINE) THEN
+    MP_TAC(ISPECL [`\x. g x % (f:real^1->real^1) x`;
+                   `c:real^1`; `d:real^1`; `b:real^1`] INTEGRAL_COMBINE) THEN
+    ASM_REWRITE_TAC[] THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; DISCH_THEN(SUBST1_TAC o SYM)] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[REAL_NOT_LE; NORM_ARITH
+     `norm(ab - ((ca + ab) + bd):real^1) = norm(ca + bd)`] THEN
+    MP_TAC(ISPECL[`f:real^1->real^1`; `g:real^1->real`; `c:real^1`; `a:real^1`]
+          SECOND_MEAN_VALUE_THEOREM) THEN
+    ASM_SIMP_TAC[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT] THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^1` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL[`f:real^1->real^1`; `g:real^1->real`; `b:real^1`; `d:real^1`]
+          SECOND_MEAN_VALUE_THEOREM) THEN
+    ASM_SIMP_TAC[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT] THEN
+    DISCH_THEN(X_CHOOSE_THEN `v:real^1` STRIP_ASSUME_TAC) THEN
+    ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN
+     `!x y. drop y <= drop a
+            ==> norm(integral (interval[x,y]) (f:real^1->real^1))
+                < e / (&4 * abs B + &4)`
+     (LABEL_TAC "L")
+    THENL
+     [REPEAT STRIP_TAC THEN
+      ASM_CASES_TAC `drop x <= drop y` THENL
+       [FIRST_X_ASSUM(fun th ->
+         MP_TAC(SPECL[`a:real^1`; `b:real^1`; `y:real^1`; `b:real^1`] th) THEN
+         MP_TAC(SPECL[`a:real^1`; `b:real^1`; `x:real^1`; `b:real^1`] th)) THEN
+        ASM_REWRITE_TAC[SUBSET_INTERVAL_1; REAL_LE_REFL] THEN
+        ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+        MP_TAC(ISPECL [`f:real^1->real^1`; `x:real^1`; `b:real^1`; `y:real^1`]
+          INTEGRAL_COMBINE) THEN
+        ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+         [ASM_ARITH_TAC; DISCH_THEN(SUBST1_TAC o SYM)] THEN
+        MATCH_MP_TAC(NORM_ARITH
+         `&2 * d = e
+          ==> norm(ab - (xy + yb)) < d
+              ==> norm(ab - yb) < d
+                  ==> norm(xy:real^1) < e`) THEN
+        CONV_TAC REAL_FIELD;
+        SUBGOAL_THEN `interval[x:real^1,y] = {}` SUBST1_TAC THENL
+         [REWRITE_TAC[INTERVAL_EQ_EMPTY_1] THEN ASM_REAL_ARITH_TAC;
+          REWRITE_TAC[INTEGRAL_EMPTY; NORM_0] THEN
+          MATCH_MP_TAC REAL_LT_DIV THEN ASM_REAL_ARITH_TAC]];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!x y. drop b <= drop x
+            ==> norm(integral (interval[x,y]) (f:real^1->real^1))
+                < e / (&4 * abs B + &4)`
+     (LABEL_TAC "R")
+    THENL
+     [REPEAT STRIP_TAC THEN
+      ASM_CASES_TAC `drop x <= drop y` THENL
+       [FIRST_X_ASSUM(fun th ->
+         MP_TAC(SPECL[`a:real^1`; `b:real^1`; `a:real^1`; `x:real^1`] th) THEN
+         MP_TAC(SPECL[`a:real^1`; `b:real^1`; `a:real^1`; `y:real^1`] th)) THEN
+        ASM_REWRITE_TAC[SUBSET_INTERVAL_1; REAL_LE_REFL] THEN
+        ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+        MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `y:real^1`; `x:real^1`]
+          INTEGRAL_COMBINE) THEN
+        ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+         [ASM_ARITH_TAC; DISCH_THEN(SUBST1_TAC o SYM)] THEN
+        MATCH_MP_TAC(NORM_ARITH
+         `&2 * d = e
+          ==> norm(ab - (ax + xy)) < d
+              ==> norm(ab - ax) < d
+                  ==> norm(xy:real^1) < e`) THEN
+        CONV_TAC REAL_FIELD;
+        SUBGOAL_THEN `interval[x:real^1,y] = {}` SUBST1_TAC THENL
+         [REWRITE_TAC[INTERVAL_EQ_EMPTY_1] THEN ASM_REAL_ARITH_TAC;
+          REWRITE_TAC[INTEGRAL_EMPTY; NORM_0] THEN
+          MATCH_MP_TAC REAL_LT_DIV THEN ASM_REAL_ARITH_TAC]];
+      ALL_TAC] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `&4 * B * e / (&4 * abs B + &4)` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC(NORM_ARITH
+       `(norm a <= e /\ norm b <= e) /\ (norm c <= e /\ norm d <= e)
+        ==> norm((a + b) + (c + d):real^1) <= &4 * e`) THEN
+      REWRITE_TAC[NORM_MUL] THEN CONJ_TAC THENL
+       [CONJ_TAC THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+        ASM_REWRITE_TAC[NORM_POS_LE; REAL_ABS_POS] THEN
+        MATCH_MP_TAC REAL_LT_IMP_LE THEN
+        REMOVE_THEN "L" MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC;
+        CONJ_TAC THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+        ASM_REWRITE_TAC[NORM_POS_LE; REAL_ABS_POS] THEN
+        MATCH_MP_TAC REAL_LT_IMP_LE THEN
+        REMOVE_THEN "R" MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC];
+      REWRITE_TAC[REAL_ARITH
+       `&4 * B * e / y < e <=> e * (&4 * B) / y < e * &1`] THEN
+      ASM_SIMP_TAC[REAL_LT_LMUL_EQ; REAL_LT_LDIV_EQ;
+                   REAL_ARITH `&0 < &4 * abs B + &4`] THEN
+      REAL_ARITH_TAC]) in
+  GEN_TAC THEN ONCE_REWRITE_TAC[INTEGRABLE_COMPONENTWISE] THEN
+  REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[VECTOR_MUL_COMPONENT; LIFT_CMUL] THEN
+  MATCH_MP_TAC lemma THEN EXISTS_TAC `B:real` THEN ASM_SIMP_TAC[]);;
+
+let INTEGRABLE_INCREASING = prove
+ (`!f:real^1->real^N a b.
+        (!x y i. x IN interval[a,b] /\ y IN interval[a,b] /\
+                 drop x <= drop y /\ 1 <= i /\ i <= dimindex(:N)
+                 ==> f(x)$i <= f(y)$i)
+        ==> f integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[INTEGRABLE_COMPONENTWISE] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM REAL_MUL_RID] THEN
+  REWRITE_TAC[LIFT_CMUL; LIFT_NUM] THEN
+  MATCH_MP_TAC INTEGRABLE_INCREASING_PRODUCT THEN
+  ASM_SIMP_TAC[INTEGRABLE_CONST]);;
+
+let INTEGRABLE_INCREASING_1 = prove
+ (`!f:real^1->real^1 a b.
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f x) <= drop(f y))
+        ==> f integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_INCREASING THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[IMP_IMP; FORALL_1; DIMINDEX_1; GSYM drop]);;
+
+let INTEGRABLE_DECREASING_PRODUCT = prove
+ (`!f:real^1->real^N g a b.
+        f integrable_on interval[a,b] /\
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> g(y) <= g(x))
+        ==> (\x. g(x) % f(x)) integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `x % y:real^N = --(--x % y)`] THEN
+  MATCH_MP_TAC INTEGRABLE_NEG THEN
+  MATCH_MP_TAC INTEGRABLE_INCREASING_PRODUCT THEN
+  ASM_REWRITE_TAC[REAL_LE_NEG2]);;
+
+let INTEGRABLE_DECREASING_PRODUCT_UNIV = prove
+ (`!f:real^1->real^N g B.
+        f integrable_on (:real^1) /\
+        (!x y. drop x <= drop y ==> g y <= g x) /\
+        (!x. abs(g x) <= B)
+         ==> (\x. g x % f x) integrable_on (:real^1)`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `x % y:real^N = --(--x % y)`] THEN
+  MATCH_MP_TAC INTEGRABLE_NEG THEN
+  MATCH_MP_TAC INTEGRABLE_INCREASING_PRODUCT_UNIV THEN
+  EXISTS_TAC `B:real` THEN ASM_REWRITE_TAC[REAL_LE_NEG2; REAL_ABS_NEG]);;
+
+let INTEGRABLE_DECREASING = prove
+ (`!f:real^1->real^N a b.
+        (!x y i. x IN interval[a,b] /\ y IN interval[a,b] /\
+                 drop x <= drop y /\ 1 <= i /\ i <= dimindex(:N)
+                 ==> f(y)$i <= f(x)$i)
+        ==> f integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [GSYM VECTOR_NEG_NEG] THEN
+  MATCH_MP_TAC INTEGRABLE_NEG THEN MATCH_MP_TAC INTEGRABLE_INCREASING THEN
+  ASM_SIMP_TAC[VECTOR_NEG_COMPONENT; REAL_LE_NEG2]);;
+
+let INTEGRABLE_DECREASING_1 = prove
+ (`!f:real^1->real^1 a b.
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f y) <= drop(f x))
+        ==> f integrable_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_DECREASING THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[IMP_IMP; FORALL_1; DIMINDEX_1; GSYM drop]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Bounded variation and variation function, for real^1->real^N functions.   *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("has_bounded_variation_on",(12,"right"));;
+
+let has_bounded_variation_on = new_definition
+ `(f:real^1->real^N) has_bounded_variation_on s <=>
+        (\k. f(interval_upperbound k) - f(interval_lowerbound k))
+        has_bounded_setvariation_on s`;;
+
+let vector_variation = new_definition
+ `vector_variation s (f:real^1->real^N) =
+  set_variation s (\k. f(interval_upperbound k) - f(interval_lowerbound k))`;;
+
+let HAS_BOUNDED_VARIATION_ON_EQ = prove
+ (`!f g:real^1->real^N s.
+        (!x. x IN s ==> f x = g x) /\ f has_bounded_variation_on s
+        ==> g has_bounded_variation_on s`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[has_bounded_variation_on] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HAS_BOUNDED_SETVARIATION_ON_EQ) THEN
+  SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND;
+           GSYM INTERVAL_NE_EMPTY] THEN
+  ASM_MESON_TAC[ENDS_IN_INTERVAL; SUBSET]);;
+
+let VECTOR_VARIATION_EQ = prove
+ (`!f g:real^1->real^N s.
+        (!x. x IN s ==> f x = g x)
+        ==> vector_variation s f = vector_variation s g`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[vector_variation] THEN
+  MATCH_MP_TAC SET_VARIATION_EQ THEN
+  SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND;
+           GSYM INTERVAL_NE_EMPTY] THEN
+  ASM_MESON_TAC[ENDS_IN_INTERVAL; SUBSET]);;
+
+let HAS_BOUNDED_VARIATION_ON_COMPONENTWISE = prove
+ (`!f:real^1->real^N s.
+        f has_bounded_variation_on s <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> (\x. lift(f x$i)) has_bounded_variation_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_variation_on] THEN
+  GEN_REWRITE_TAC LAND_CONV [HAS_BOUNDED_SETVARIATION_ON_COMPONENTWISE] THEN
+  REWRITE_TAC[VECTOR_SUB_COMPONENT; LIFT_SUB]);;
+
+let VARIATION_EQUAL_LEMMA = prove
+ (`!ms ms'.
+        (!s. ms'(ms s) = s /\ ms(ms' s) = s) /\
+        (!d t. d division_of t
+               ==> (IMAGE (IMAGE ms) d) division_of IMAGE ms t /\
+                   (IMAGE (IMAGE ms') d) division_of IMAGE ms' t) /\
+        (!a b. ~(interval[a,b] = {})
+               ==> IMAGE ms' (interval [a,b]) = interval[ms' a,ms' b] \/
+                   IMAGE ms' (interval [a,b]) = interval[ms' b,ms' a])
+   ==> (!f:real^1->real^N s.
+            (\x. f(ms' x)) has_bounded_variation_on (IMAGE ms s) <=>
+            f has_bounded_variation_on s) /\
+       (!f:real^1->real^N s.
+            vector_variation (IMAGE ms s) (\x. f(ms' x)) =
+            vector_variation s f)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  REWRITE_TAC[has_bounded_variation_on; vector_variation] THEN
+  GEN_REWRITE_TAC I [AND_FORALL_THM] THEN X_GEN_TAC `f:real^1->real^N` THEN
+  MP_TAC(ISPECL
+   [`\f k. (f:(real^1->bool)->real^N) (IMAGE (ms':real^1->real^1) k)`;
+    `IMAGE (ms:real^1->real^1)`;
+    `IMAGE (ms':real^1->real^1)`]
+  SETVARIATION_EQUAL_LEMMA) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID; IMAGE_SUBSET] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^1`; `b:real^1`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`a:real^1`; `b:real^1`]) THEN
+    ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[IMAGE_EQ_EMPTY];
+    ALL_TAC] THEN
+  REWRITE_TAC[] THEN GEN_REWRITE_TAC LAND_CONV [AND_FORALL_THM] THEN
+  DISCH_THEN(fun th ->
+    MP_TAC(SPEC `\k. (f:real^1->real^N) (interval_upperbound k) -
+                     f (interval_lowerbound k)` th)) THEN
+  REWRITE_TAC[] THEN DISCH_THEN(fun th -> ONCE_REWRITE_TAC[GSYM th]) THEN
+  GEN_REWRITE_TAC I [AND_FORALL_THM] THEN X_GEN_TAC `s:real^1->bool` THEN
+  REWRITE_TAC[has_bounded_setvariation_on; set_variation] THEN
+  CONJ_TAC THENL
+   [REPLICATE_TAC 3 (AP_TERM_TAC THEN ABS_TAC) THEN
+    REWRITE_TAC[TAUT `((p ==> q) <=> (p ==> r)) <=> p ==> (q <=> r)`] THEN
+    STRIP_TAC THEN AP_THM_TAC THEN AP_TERM_TAC;
+    AP_TERM_TAC THEN
+    MATCH_MP_TAC(SET_RULE
+     `(!x. P x ==> f x = g x) ==> {f x | P x} = {g x | P x}`) THEN
+    GEN_TAC THEN STRIP_TAC] THEN
+  MATCH_MP_TAC SUM_EQ THEN FIRST_ASSUM(fun th ->
+   GEN_REWRITE_TAC I [MATCH_MP FORALL_IN_DIVISION_NONEMPTY th]) THEN
+  MAP_EVERY X_GEN_TAC [`a:real^1`; `b:real^1`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`a:real^1`; `b:real^1`]) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(DISJ_CASES_THEN MP_TAC) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE
+   `IMAGE f s = s' ==> ~(s = {}) ==> IMAGE f s = s' /\ ~(s' = {})`)) THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY_1]) THEN
+  ASM_SIMP_TAC[INTERVAL_UPPERBOUND_1; INTERVAL_LOWERBOUND_1] THEN
+  NORM_ARITH_TAC);;
+
+let HAS_BOUNDED_VARIATION_ON_SUBSET = prove
+ (`!f:real^1->real^N s t.
+        f has_bounded_variation_on s /\ t SUBSET s
+        ==> f has_bounded_variation_on t`,
+  REWRITE_TAC[HAS_BOUNDED_SETVARIATION_ON_SUBSET; has_bounded_variation_on]);;
+
+let HAS_BOUNDED_VARIATION_ON_CONST = prove
+ (`!s c:real^N. (\x. c) has_bounded_variation_on s`,
+  REWRITE_TAC[has_bounded_variation_on; VECTOR_SUB_REFL;
+              HAS_BOUNDED_SETVARIATION_ON_0]);;
+
+let VECTOR_VARIATION_CONST = prove
+ (`!s c:real^N. vector_variation s (\x. c) = &0`,
+  REWRITE_TAC[vector_variation; VECTOR_SUB_REFL; SET_VARIATION_0]);;
+
+let HAS_BOUNDED_VARIATION_ON_CMUL = prove
+ (`!f:real^1->real^N c s.
+        f has_bounded_variation_on s
+        ==> (\x. c % f x) has_bounded_variation_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_variation_on] THEN
+  REWRITE_TAC[GSYM VECTOR_SUB_LDISTRIB; HAS_BOUNDED_SETVARIATION_ON_CMUL]);;
+
+let HAS_BOUNDED_VARIATION_ON_NEG = prove
+ (`!f:real^1->real^N s.
+        f has_bounded_variation_on s
+        ==> (\x. --f x) has_bounded_variation_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_variation_on] THEN
+  REWRITE_TAC[VECTOR_ARITH `--a - --b:real^N = --(a - b)`;
+              HAS_BOUNDED_SETVARIATION_ON_NEG]);;
+
+let HAS_BOUNDED_VARIATION_ON_ADD = prove
+ (`!f g:real^1->real^N s.
+        f has_bounded_variation_on s /\ g has_bounded_variation_on s
+        ==> (\x. f x + g x) has_bounded_variation_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_variation_on] THEN
+  REWRITE_TAC[VECTOR_ARITH `(f + g) - (f' + g'):real^N = (f - f') + (g - g')`;
+              HAS_BOUNDED_SETVARIATION_ON_ADD]);;
+
+let HAS_BOUNDED_VARIATION_ON_SUB = prove
+ (`!f g:real^1->real^N s.
+        f has_bounded_variation_on s /\ g has_bounded_variation_on s
+        ==> (\x. f x - g x) has_bounded_variation_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_variation_on] THEN
+  REWRITE_TAC[VECTOR_ARITH `(f - g) - (f' - g'):real^N = (f - f') - (g - g')`;
+              HAS_BOUNDED_SETVARIATION_ON_SUB]);;
+
+let HAS_BOUNDED_VARIATION_ON_COMPOSE_LINEAR = prove
+ (`!f:real^1->real^M g:real^M->real^N s.
+        f has_bounded_variation_on s /\ linear g
+        ==> (g o f) has_bounded_variation_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_variation_on] THEN
+  SIMP_TAC[o_THM; GSYM LINEAR_SUB] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_BOUNDED_SETVARIATION_ON_COMPOSE_LINEAR) THEN
+  REWRITE_TAC[o_DEF]);;
+
+let HAS_BOUNDED_VARIATION_ON_NULL = prove
+ (`!f:real^1->real^N s.
+        content s = &0 /\ bounded s ==> f has_bounded_variation_on s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[has_bounded_variation_on] THEN
+  MATCH_MP_TAC HAS_BOUNDED_SETVARIATION_ON_NULL THEN
+  ASM_SIMP_TAC[INTERVAL_BOUNDS_NULL_1; VECTOR_SUB_REFL]);;
+
+let HAS_BOUNDED_VARIATION_ON_EMPTY = prove
+ (`!f:real^1->real^N. f has_bounded_variation_on {}`,
+  MESON_TAC[CONTENT_EMPTY; BOUNDED_EMPTY; HAS_BOUNDED_VARIATION_ON_NULL]);;
+
+let VECTOR_VARIATION_ON_NULL = prove
+ (`!f s. content s = &0 /\ bounded s ==> vector_variation s f = &0`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[vector_variation] THEN
+  MATCH_MP_TAC SET_VARIATION_ON_NULL THEN ASM_REWRITE_TAC[] THEN
+  SIMP_TAC[INTERVAL_BOUNDS_NULL_1; VECTOR_SUB_REFL]);;
+
+let HAS_BOUNDED_VARIATION_ON_NORM = prove
+ (`!f:real^1->real^N s.
+        f has_bounded_variation_on s
+        ==> (\x. lift(norm(f x))) has_bounded_variation_on s`,
+  REWRITE_TAC[has_bounded_variation_on; has_bounded_setvariation_on] THEN
+  REPEAT GEN_TAC THEN MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_LE_TRANS) THEN
+  MATCH_MP_TAC SUM_LE THEN
+  REWRITE_TAC[NORM_REAL; GSYM drop; LIFT_DROP; DROP_SUB] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[DIVISION_OF_FINITE]; NORM_ARITH_TAC]);;
+
+let HAS_BOUNDED_VARIATION_ON_MAX = prove
+ (`!f g s. f has_bounded_variation_on s /\ g has_bounded_variation_on s
+           ==> (\x. lift(max (drop(f x)) (drop(g x))))
+               has_bounded_variation_on s`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[REAL_ARITH `max a b = inv(&2) * (a + b + abs(a - b))`] THEN
+  REWRITE_TAC[LIFT_CMUL; LIFT_ADD; LIFT_DROP; GSYM DROP_SUB] THEN
+  REWRITE_TAC[drop; GSYM NORM_REAL] THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_CMUL THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_ADD THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_ADD THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_NORM THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_SUB THEN ASM_REWRITE_TAC[]);;
+
+let HAS_BOUNDED_VARIATION_ON_MIN = prove
+ (`!f g s. f has_bounded_variation_on s /\ g has_bounded_variation_on s
+           ==> (\x. lift(min (drop(f x)) (drop(g x))))
+               has_bounded_variation_on s`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[REAL_ARITH `min a b = inv(&2) * ((a + b) - abs(a - b))`] THEN
+  REWRITE_TAC[LIFT_CMUL; LIFT_ADD; LIFT_DROP; LIFT_SUB; GSYM DROP_SUB] THEN
+  REWRITE_TAC[drop; GSYM NORM_REAL] THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_CMUL THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_SUB THEN
+  ASM_SIMP_TAC[HAS_BOUNDED_VARIATION_ON_ADD] THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_NORM THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_SUB THEN ASM_REWRITE_TAC[]);;
+
+let HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_SUBINTERVALS = prove
+ (`!f:real^1->real^N s.
+        f has_bounded_variation_on s
+        ==> bounded { f(d) - f(c) | interval[c,d] SUBSET s /\
+                                    ~(interval[c,d] = {})}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_variation_on] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP
+   HAS_BOUNDED_SETVARIATION_ON_IMP_BOUNDED_ON_SUBINTERVALS) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] BOUNDED_SUBSET) THEN
+  GEN_REWRITE_TAC I [SUBSET] THEN REWRITE_TAC[FORALL_IN_GSPEC] THEN
+  MAP_EVERY X_GEN_TAC [`d:real^1`; `c:real^1`] THEN
+  REWRITE_TAC[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT] THEN STRIP_TAC THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  MAP_EVERY EXISTS_TAC [`c:real^1`; `d:real^1`] THEN
+  ASM_SIMP_TAC[INTERVAL_UPPERBOUND_1; INTERVAL_LOWERBOUND_1]);;
+
+let HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_INTERVAL = prove
+ (`!f:real^1->real^N a b.
+        f has_bounded_variation_on interval[a,b]
+        ==> bounded(IMAGE f (interval[a,b]))`,
+  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP
+   HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_SUBINTERVALS) THEN
+  REWRITE_TAC[BOUNDED_POS_LT; FORALL_IN_GSPEC; FORALL_IN_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `B + norm((f:real^1->real^N) a)` THEN
+  ASM_SIMP_TAC[NORM_ARITH `&0 < B ==> &0 < B + norm(x:real^N)`] THEN
+  X_GEN_TAC `x:real^1` THEN REWRITE_TAC[IN_INTERVAL_1] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^1`; `a:real^1`]) THEN
+  REWRITE_TAC[SUBSET_INTERVAL_1; INTERVAL_EQ_EMPTY_1] THEN ANTS_TAC THENL
+   [ASM_REAL_ARITH_TAC; NORM_ARITH_TAC]);;
+
+let HAS_BOUNDED_VARIATION_ON_MUL = prove
+ (`!f g:real^1->real^N a b.
+        f has_bounded_variation_on interval[a,b] /\
+        g has_bounded_variation_on interval[a,b]
+        ==> (\x. drop(f x) % g x) has_bounded_variation_on interval[a,b]`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+    `bounded(IMAGE (f:real^1->real^1) (interval[a,b])) /\
+     bounded(IMAGE (g:real^1->real^N) (interval[a,b]))`
+  MP_TAC THENL
+   [ASM_SIMP_TAC[HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_INTERVAL];
+    REWRITE_TAC[BOUNDED_POS_LT; FORALL_IN_IMAGE]] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `B1:real` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `B2:real` STRIP_ASSUME_TAC)) THEN
+  FIRST_X_ASSUM(CONJUNCTS_THEN MP_TAC) THEN
+  REWRITE_TAC[HAS_BOUNDED_SETVARIATION_ON_INTERVAL;
+              has_bounded_variation_on] THEN
+  DISCH_THEN(X_CHOOSE_THEN `C2:real` (LABEL_TAC "G")) THEN
+  DISCH_THEN(X_CHOOSE_THEN `C1:real` (LABEL_TAC "F")) THEN
+  EXISTS_TAC `B1 * C2 + B2 * C1:real` THEN
+  X_GEN_TAC `d:(real^1->bool)->bool` THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+   `B1 * sum d (\k. norm((g:real^1->real^N)(interval_upperbound k) -
+                         g(interval_lowerbound k))) +
+    B2 * sum d (\k. norm((f:real^1->real^1)(interval_upperbound k) -
+                         f(interval_lowerbound k)))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC; MATCH_MP_TAC REAL_LE_ADD2 THEN ASM_SIMP_TAC[REAL_LE_LMUL_EQ]] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  ASM_SIMP_TAC[GSYM SUM_LMUL; GSYM SUM_ADD] THEN
+  MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+  MAP_EVERY X_GEN_TAC [`u:real^1`; `v:real^1`] THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH
+   `f' % g' - f % g:real^N = f' % (g' - g) + (f' - f) % g`] THEN
+  MATCH_MP_TAC(NORM_ARITH
+    `norm x <= a /\ norm y <= b ==> norm(x + y) <= a + b`) THEN
+  REWRITE_TAC[NORM_MUL; NORM_REAL] THEN
+  REWRITE_TAC[drop; GSYM NORM_REAL; GSYM VECTOR_SUB_COMPONENT] THEN
+  SUBGOAL_THEN `~(interval[u:real^1,v] = {})` MP_TAC THENL
+   [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+  REWRITE_TAC[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT] THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1] THEN
+  SUBGOAL_THEN `interval[u:real^1,v] SUBSET interval[a,b]` MP_TAC THENL
+   [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[SUBSET_INTERVAL_1; GSYM REAL_NOT_LE] THEN
+  STRIP_TAC THEN
+  GEN_REWRITE_TAC (RAND_CONV o LAND_CONV) [REAL_MUL_SYM] THEN
+  CONJ_TAC THEN MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+  MATCH_MP_TAC REAL_LT_IMP_LE THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[IN_INTERVAL_1] THEN ASM_REAL_ARITH_TAC);;
+
+let VECTOR_VARIATION_POS_LE = prove
+ (`!f:real^1->real^N s.
+        f has_bounded_variation_on s ==> &0 <= vector_variation s f`,
+  REWRITE_TAC[has_bounded_variation_on; vector_variation] THEN
+  REWRITE_TAC[SET_VARIATION_POS_LE]);;
+
+let VECTOR_VARIATION_GE_NORM_FUNCTION = prove
+ (`!f:real^1->real^N s a b.
+        f has_bounded_variation_on s /\ segment[a,b] SUBSET s
+        ==> norm(f b - f a) <= vector_variation s f`,
+  REWRITE_TAC[FORALL_LIFT] THEN GEN_TAC THEN GEN_TAC THEN
+  MATCH_MP_TAC REAL_WLOG_LE THEN CONJ_TAC THENL
+   [MESON_TAC[SEGMENT_SYM; NORM_SUB]; ALL_TAC] THEN
+  REWRITE_TAC[FORALL_DROP; LIFT_DROP; has_bounded_variation_on] THEN
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+  [`\k. (f:real^1->real^N)(interval_upperbound k) - f(interval_lowerbound k)`;
+   `s:real^1->bool`; `a:real^1`; `b:real^1`] SET_VARIATION_GE_FUNCTION) THEN
+  ASM_REWRITE_TAC[vector_variation; INTERVAL_NE_EMPTY_1] THEN
+  ASM_SIMP_TAC[INTERVAL_UPPERBOUND_1; INTERVAL_LOWERBOUND_1] THEN
+  ASM_MESON_TAC[SEGMENT_1]);;
+
+let VECTOR_VARIATION_GE_DROP_FUNCTION = prove
+ (`!f s a b.
+        f has_bounded_variation_on s /\ segment[a,b] SUBSET s
+        ==> drop(f b) - drop(f a) <= vector_variation s f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `norm((f:real^1->real^1) b - f a)` THEN
+  ASM_SIMP_TAC[VECTOR_VARIATION_GE_NORM_FUNCTION] THEN
+  REWRITE_TAC[NORM_REAL; DROP_SUB; GSYM drop] THEN REAL_ARITH_TAC);;
+
+let VECTOR_VARIATION_CONST_EQ = prove
+ (`!f:real^1->real^N s.
+        is_interval s /\ f has_bounded_variation_on s
+        ==> (vector_variation s f = &0 <=> ?c. !x. x IN s ==> f x = c)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [DISCH_TAC THEN REWRITE_TAC[MESON[]
+     `(?c. !x. P x ==> f x = c) <=> !a b. P a /\ P b ==> f a = f b`] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^1`; `b:real^1`] THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`f:real^1->real^N`; `s:real^1->bool`;
+        `a:real^1`; `b:real^1`] VECTOR_VARIATION_GE_NORM_FUNCTION) THEN
+    ANTS_TAC THENL
+     [ASM_MESON_TAC[IS_INTERVAL_CONVEX_1; CONVEX_CONTAINS_SEGMENT];
+      ASM_REWRITE_TAC[] THEN CONV_TAC NORM_ARITH];
+    DISCH_THEN(X_CHOOSE_TAC `c:real^N`) THEN
+    MP_TAC(ISPECL [`f:real^1->real^N`; `(\x. c):real^1->real^N`;
+                   `s:real^1->bool`] VECTOR_VARIATION_EQ) THEN
+    ASM_SIMP_TAC[VECTOR_VARIATION_CONST]]);;
+
+let VECTOR_VARIATION_MONOTONE = prove
+ (`!f s t. f has_bounded_variation_on s /\ t SUBSET s
+           ==> vector_variation t f <= vector_variation s f`,
+  REWRITE_TAC[has_bounded_variation_on; vector_variation] THEN
+  REWRITE_TAC[SET_VARIATION_MONOTONE]);;
+
+let VECTOR_VARIATION_NEG = prove
+ (`!f:real^1->real^N s.
+        vector_variation s (\x. --(f x)) = vector_variation s f`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[vector_variation; set_variation] THEN
+  REWRITE_TAC[NORM_ARITH `norm(--x - --y:real^N) = norm(x - y)`]);;
+
+let VECTOR_VARIATION_TRIANGLE = prove
+ (`!f g:real^1->real^N s.
+        f has_bounded_variation_on s /\ g has_bounded_variation_on s
+        ==> vector_variation s (\x. f x + g x)
+              <= vector_variation s f + vector_variation s g`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[has_bounded_variation_on; vector_variation] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SET_VARIATION_TRIANGLE) THEN
+  REWRITE_TAC[VECTOR_ARITH `(a + b) - (c + d):real^N = (a - c) + (b - d)`]);;
+
+let OPERATIVE_FUNCTION_ENDPOINT_DIFF = prove
+ (`!f:real^1->real^N.
+    operative (+) (\k. f (interval_upperbound k) - f (interval_lowerbound k))`,
+  GEN_TAC THEN
+  SIMP_TAC[operative; INTERVAL_BOUNDS_NULL_1; VECTOR_SUB_REFL] THEN
+  REWRITE_TAC[NEUTRAL_VECTOR_ADD; DIMINDEX_1; FORALL_1; GSYM drop] THEN
+  REWRITE_TAC[FORALL_DROP] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^1`; `b:real^1`; `c:real^1`] THEN
+  ASM_CASES_TAC `interval[a:real^1,b] = {}` THENL
+   [ASM_REWRITE_TAC[INTER_EMPTY; INTERVAL_BOUNDS_EMPTY_1] THEN
+    VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_CASES_TAC `interval[a,b] INTER {x | drop x <= drop c} = {}` THENL
+   [ASM_REWRITE_TAC[INTERVAL_BOUNDS_EMPTY_1; VECTOR_SUB_REFL] THEN
+    SUBGOAL_THEN `interval[a,b] INTER {x | drop x >= drop c} = interval[a,b]`
+     (fun th -> REWRITE_TAC[th; VECTOR_ADD_LID]) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `i INTER s = {} ==> s UNION t = UNIV ==> i INTER t = i`)) THEN
+    REWRITE_TAC[EXTENSION; IN_UNIV; IN_UNION; IN_ELIM_THM] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_CASES_TAC `interval[a,b] INTER {x | drop x >= drop c} = {}` THENL
+   [ASM_REWRITE_TAC[INTERVAL_BOUNDS_EMPTY_1; VECTOR_SUB_REFL] THEN
+    SUBGOAL_THEN `interval[a,b] INTER {x | drop x <= drop c} = interval[a,b]`
+     (fun th -> REWRITE_TAC[th; VECTOR_ADD_RID]) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `i INTER s = {} ==> s UNION t = UNIV ==> i INTER t = i`)) THEN
+    REWRITE_TAC[EXTENSION; IN_UNIV; IN_UNION; IN_ELIM_THM] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+  SIMP_TAC[INTERVAL_SPLIT; drop; DIMINDEX_1; LE_REFL] THEN
+  REWRITE_TAC[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT] THEN
+  SIMP_TAC[INTERVAL_UPPERBOUND_1; INTERVAL_LOWERBOUND_1] THEN
+  SIMP_TAC[drop; LAMBDA_BETA; DIMINDEX_1; LE_REFL] THEN STRIP_TAC THEN
+  MATCH_MP_TAC(VECTOR_ARITH
+   `fx:real^N = fy ==> fb - fa = fx - fa + fb - fy`) THEN
+  AP_TERM_TAC THEN REWRITE_TAC[GSYM DROP_EQ; drop] THEN
+  SIMP_TAC[LAMBDA_BETA; DIMINDEX_1; LE_REFL] THEN ASM_REAL_ARITH_TAC);;
+
+let OPERATIVE_REAL_FUNCTION_ENDPOINT_DIFF = prove
+ (`!f:real^1->real.
+    operative (+) (\k. f (interval_upperbound k) - f (interval_lowerbound k))`,
+  GEN_TAC THEN
+  MP_TAC(ISPEC `lift o (f:real^1->real)` OPERATIVE_FUNCTION_ENDPOINT_DIFF) THEN
+  REWRITE_TAC[operative; NEUTRAL_REAL_ADD; NEUTRAL_VECTOR_ADD] THEN
+  REWRITE_TAC[o_THM; GSYM LIFT_SUB; GSYM LIFT_ADD; GSYM LIFT_NUM] THEN
+  REWRITE_TAC[LIFT_EQ]);;
+
+let OPERATIVE_LIFTED_VECTOR_VARIATION = prove
+ (`!f:real^1->real^N.
+        operative (lifted(+))
+                  (\i. if f has_bounded_variation_on i
+                       then SOME(vector_variation i f) else NONE)`,
+  GEN_TAC THEN REWRITE_TAC[has_bounded_variation_on; vector_variation] THEN
+  MATCH_MP_TAC OPERATIVE_LIFTED_SETVARIATION THEN
+  REWRITE_TAC[OPERATIVE_FUNCTION_ENDPOINT_DIFF]);;
+
+let HAS_BOUNDED_VARIATION_ON_DIVISION = prove
+ (`!f:real^1->real^N a b d.
+        d division_of interval[a,b]
+        ==> ((!k. k IN d ==> f has_bounded_variation_on k) <=>
+             f has_bounded_variation_on interval[a,b])`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[has_bounded_variation_on] THEN
+  MATCH_MP_TAC HAS_BOUNDED_SETVARIATION_ON_DIVISION THEN
+  ASM_REWRITE_TAC[OPERATIVE_FUNCTION_ENDPOINT_DIFF]);;
+
+let VECTOR_VARIATION_ON_DIVISION = prove
+ (`!f:real^1->real^N a b d.
+        d division_of interval[a,b] /\
+        f has_bounded_variation_on interval[a,b]
+        ==> sum d (\k. vector_variation k f) =
+            vector_variation (interval[a,b]) f`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[vector_variation] THEN
+  MATCH_MP_TAC SET_VARIATION_ON_DIVISION THEN
+  ASM_REWRITE_TAC[OPERATIVE_FUNCTION_ENDPOINT_DIFF; GSYM
+                  has_bounded_variation_on]);;
+
+let HAS_BOUNDED_VARIATION_ON_COMBINE = prove
+ (`!f:real^1->real^N a b c.
+        drop a <= drop c /\ drop c <= drop b
+        ==> (f has_bounded_variation_on interval[a,b] <=>
+             f has_bounded_variation_on interval[a,c] /\
+             f has_bounded_variation_on interval[c,b])`,
+  REPEAT STRIP_TAC THEN MP_TAC
+   (ISPEC `f:real^1->real^N` OPERATIVE_LIFTED_VECTOR_VARIATION) THEN
+  REWRITE_TAC[operative; FORALL_1; FORALL_DROP; DIMINDEX_1] THEN
+  DISCH_THEN(MP_TAC o SPECL [`a:real^1`; `b:real^1`; `c:real^1`] o
+   CONJUNCT2) THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `interval[a,b] INTER {x:real^1 | x$1 <= drop c} = interval[a,c] /\
+    interval[a,b] INTER {x:real^1 | x$1 >= drop c} = interval[c,b]`
+   (fun th -> REWRITE_TAC[th])
+  THENL
+   [SIMP_TAC[EXTENSION; IN_INTER; GSYM drop; IN_INTERVAL_1; IN_ELIM_THM] THEN
+    ASM_REAL_ARITH_TAC;
+    REPEAT(COND_CASES_TAC THEN
+           ASM_REWRITE_TAC[distinctness "option"; lifted])]);;
+
+let VECTOR_VARIATION_COMBINE = prove
+ (`!f:real^1->real^N a b c.
+        drop a <= drop c /\
+        drop c <= drop b /\
+        f has_bounded_variation_on interval[a,b]
+        ==> vector_variation (interval[a,c]) f +
+            vector_variation (interval[c,b]) f =
+            vector_variation (interval[a,b]) f`,
+  REPEAT STRIP_TAC THEN MP_TAC
+   (ISPEC `f:real^1->real^N` OPERATIVE_LIFTED_VECTOR_VARIATION) THEN
+  REWRITE_TAC[operative; FORALL_1; FORALL_DROP; DIMINDEX_1] THEN
+  DISCH_THEN(MP_TAC o SPECL [`a:real^1`; `b:real^1`; `c:real^1`] o
+   CONJUNCT2) THEN ASM_REWRITE_TAC[] THEN REPEAT(COND_CASES_TAC THENL
+    [ALL_TAC;
+     ASM_MESON_TAC[HAS_BOUNDED_VARIATION_ON_SUBSET; INTER_SUBSET]]) THEN
+  REWRITE_TAC[lifted; injectivity "option"] THEN DISCH_THEN SUBST1_TAC THEN
+  SIMP_TAC[INTERVAL_SPLIT; DIMINDEX_1; LE_REFL] THEN
+  BINOP_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  SIMP_TAC[EXTENSION; IN_INTERVAL_1; drop; LAMBDA_BETA;
+           DIMINDEX_1; LE_REFL] THEN
+  REWRITE_TAC[GSYM drop] THEN ASM_REAL_ARITH_TAC);;
+
+let VECTOR_VARIATION_MINUS_FUNCTION_MONOTONE = prove
+ (`!f a b c d.
+        f has_bounded_variation_on interval[a,b] /\
+        interval[c,d] SUBSET interval[a,b] /\ ~(interval[c,d] = {})
+        ==> vector_variation (interval[c,d]) f - drop(f d - f c) <=
+            vector_variation (interval[a,b]) f - drop(f b - f a)`,
+  REWRITE_TAC[SUBSET_INTERVAL_1; INTERVAL_EQ_EMPTY_1; REAL_NOT_LT] THEN
+  REPEAT STRIP_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `drop(f c) - drop(f a) <= vector_variation(interval[a,c]) f /\
+    drop(f b) - drop(f d) <= vector_variation(interval[d,b]) f`
+  MP_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC VECTOR_VARIATION_GE_DROP_FUNCTION THEN
+    ASM_REWRITE_TAC[SEGMENT_1; SUBSET_INTERVAL_1; INTERVAL_EQ_EMPTY_1] THEN
+    (CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC]) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      HAS_BOUNDED_VARIATION_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[DROP_SUB] THEN
+  MP_TAC(ISPEC `f:real^1->real^1` VECTOR_VARIATION_COMBINE) THEN
+  DISCH_THEN(fun th ->
+    MP_TAC(SPECL [`a:real^1`; `b:real^1`; `d:real^1`] th) THEN
+    MP_TAC(SPECL [`a:real^1`; `d:real^1`; `c:real^1`] th)) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+     HAS_BOUNDED_VARIATION_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+    ASM_REAL_ARITH_TAC]);;
+
+let INCREASING_BOUNDED_VARIATION = prove
+ (`!f a b.
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f x) <= drop(f y))
+        ==> f has_bounded_variation_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `interval[a:real^1,b] = {}` THEN
+  ASM_REWRITE_TAC[HAS_BOUNDED_VARIATION_ON_EMPTY] THEN
+  REWRITE_TAC[has_bounded_variation_on;
+              HAS_BOUNDED_SETVARIATION_ON_INTERVAL] THEN
+  EXISTS_TAC `drop(f b) - drop(f(a:real^1))` THEN
+  MP_TAC(MATCH_MP (REWRITE_RULE
+   [TAUT `a /\ b /\ c ==> d <=> b ==> a /\ c ==> d`]
+   OPERATIVE_DIVISION) (SPEC `drop o (f:real^1->real^1)`
+      OPERATIVE_REAL_FUNCTION_ENDPOINT_DIFF)) THEN
+  MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  DISCH_THEN(MP_TAC o SPECL [`a:real^1`; `b:real^1`]) THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[GSYM sum; MONOIDAL_REAL_ADD] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT]) THEN
+  ASM_SIMP_TAC[o_THM; INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN MATCH_MP_TAC REAL_EQ_IMP_LE THEN
+  MATCH_MP_TAC SUM_EQ THEN REWRITE_TAC[NORM_REAL; GSYM drop] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+  MAP_EVERY X_GEN_TAC [`u:real^1`; `v:real^1`] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `~(interval[u:real^1,v] = {})` ASSUME_TAC THENL
+   [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+   RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT]) THEN
+  ASM_SIMP_TAC[DROP_SUB; INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1] THEN
+  MATCH_MP_TAC(REAL_ARITH `x <= y ==> abs(y - x) = y - x`) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+  SUBGOAL_THEN `interval[u:real^1,v] SUBSET interval[a,b]` MP_TAC THENL
+   [ASM_MESON_TAC[division_of]; REWRITE_TAC[SUBSET_INTERVAL_1]] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let DECREASING_BOUNDED_VARIATION = prove
+ (`!f a b.
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f y) <= drop(f x))
+         ==> f has_bounded_variation_on interval[a,b]`,
+  REPEAT GEN_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV o BINDER_CONV o RAND_CONV)
+   [GSYM REAL_LE_NEG2] THEN
+  REWRITE_TAC[GSYM DROP_NEG] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP INCREASING_BOUNDED_VARIATION) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_BOUNDED_VARIATION_ON_NEG) THEN
+  REWRITE_TAC[VECTOR_NEG_NEG; ETA_AX]);;
+
+let INCREASING_VECTOR_VARIATION = prove
+ (`!f a b.
+        ~(interval[a,b] = {}) /\
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f x) <= drop(f y))
+        ==> vector_variation (interval[a,b]) f = drop(f b) - drop(f a)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[vector_variation] THEN
+  REWRITE_TAC[SET_VARIATION_ON_INTERVAL] THEN
+  SUBGOAL_THEN
+   `{sum d (\k. norm (f (interval_upperbound k) - f (interval_lowerbound k))) |
+     d division_of interval[a:real^1,b]} =
+    {drop (f b) - drop(f a)}`
+   (fun th -> SIMP_TAC[SUP_INSERT_FINITE; FINITE_EMPTY; th]) THEN
+  MATCH_MP_TAC(SET_RULE
+   `(?x. P x) /\ (!x. P x ==> f x = a) ==> {f x | P x} = {a}`) THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[DIVISION_OF_SELF]; ALL_TAC] THEN
+  MP_TAC(MATCH_MP (REWRITE_RULE
+   [TAUT `a /\ b /\ c ==> d <=> b ==> a /\ c ==> d`]
+   OPERATIVE_DIVISION) (SPEC `drop o (f:real^1->real^1)`
+      OPERATIVE_REAL_FUNCTION_ENDPOINT_DIFF)) THEN
+   MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  DISCH_THEN(MP_TAC o SPECL [`a:real^1`; `b:real^1`]) THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[GSYM sum; MONOIDAL_REAL_ADD] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT]) THEN
+  ASM_SIMP_TAC[o_THM; INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC SUM_EQ THEN REWRITE_TAC[NORM_REAL; GSYM drop] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP FORALL_IN_DIVISION th]) THEN
+  MAP_EVERY X_GEN_TAC [`u:real^1`; `v:real^1`] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `~(interval[u:real^1,v] = {})` ASSUME_TAC THENL
+   [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+   RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT]) THEN
+  ASM_SIMP_TAC[DROP_SUB; INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1] THEN
+  MATCH_MP_TAC(REAL_ARITH `x <= y ==> abs(y - x) = y - x`) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+  SUBGOAL_THEN `interval[u:real^1,v] SUBSET interval[a,b]` MP_TAC THENL
+   [ASM_MESON_TAC[division_of]; REWRITE_TAC[SUBSET_INTERVAL_1]] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let DECREASING_VECTOR_VARIATION = prove
+ (`!f a b.
+        ~(interval[a,b] = {}) /\
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f y) <= drop(f x))
+        ==> vector_variation (interval[a,b]) f = drop(f a) - drop(f b)`,
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC
+   (LAND_CONV o RAND_CONV o BINDER_CONV o BINDER_CONV o RAND_CONV)
+   [GSYM REAL_LE_NEG2] THEN
+  REWRITE_TAC[GSYM DROP_NEG] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP INCREASING_VECTOR_VARIATION) THEN
+  SIMP_TAC[VECTOR_VARIATION_NEG; DROP_NEG] THEN
+  DISCH_TAC THEN REAL_ARITH_TAC);;
+
+let HAS_BOUNDED_VARIATION_TRANSLATION2_EQ,VECTOR_VARIATION_TRANSLATION2 =
+ (CONJ_PAIR o prove)
+ (`(!a f:real^1->real^N s.
+        (\x. f(a + x)) has_bounded_variation_on (IMAGE (\x. --a + x) s) <=>
+        f has_bounded_variation_on s) /\
+   (!a f:real^1->real^N s.
+        vector_variation (IMAGE (\x. --a + x) s) (\x. f(a + x)) =
+        vector_variation s f)`,
+  GEN_REWRITE_TAC I [AND_FORALL_THM] THEN X_GEN_TAC `a:real^1` THEN
+  MATCH_MP_TAC VARIATION_EQUAL_LEMMA THEN
+  REWRITE_TAC[] THEN CONJ_TAC THENL [VECTOR_ARITH_TAC; ALL_TAC] THEN
+  SIMP_TAC[DIVISION_OF_TRANSLATION; GSYM INTERVAL_TRANSLATION]);;
+
+let HAS_BOUNDED_VARIATION_AFFINITY2_EQ,VECTOR_VARIATION_AFFINITY2 =
+ (CONJ_PAIR o prove)
+ (`(!m c f:real^1->real^N s.
+        (\x. f (m % x + c)) has_bounded_variation_on
+        IMAGE (\x. inv m % x + --(inv m % c)) s <=>
+        m = &0 \/ f has_bounded_variation_on s) /\
+   (!m c f:real^1->real^N s.
+        vector_variation (IMAGE (\x. inv m % x + --(inv m % c)) s)
+                         (\x. f (m % x + c)) =
+        if m = &0 then &0 else vector_variation s f)`,
+  GEN_REWRITE_TAC I [AND_FORALL_THM] THEN X_GEN_TAC `m:real` THEN
+  GEN_REWRITE_TAC I [AND_FORALL_THM] THEN X_GEN_TAC `c:real^1` THEN
+  ASM_CASES_TAC `m = &0` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; HAS_BOUNDED_VARIATION_ON_CONST] THEN
+    REWRITE_TAC[VECTOR_VARIATION_CONST];
+    MATCH_MP_TAC VARIATION_EQUAL_LEMMA THEN
+    ASM_SIMP_TAC[REWRITE_RULE[FUN_EQ_THM; o_DEF] AFFINITY_INVERSES; I_THM] THEN
+    ASM_SIMP_TAC[IMAGE_AFFINITY_INTERVAL] THEN
+    ASM_REWRITE_TAC[DIVISION_OF_AFFINITY; REAL_INV_EQ_0] THEN
+    MESON_TAC[]]);;
+
+let HAS_BOUNDED_VARIATION_AFFINITY_EQ,VECTOR_VARIATION_AFFINITY =
+ (CONJ_PAIR o prove)
+ (`(!m c f:real^1->real^N s.
+        (\x. f(m % x + c)) has_bounded_variation_on s <=>
+        m = &0 \/ f has_bounded_variation_on (IMAGE (\x. m % x + c) s)) /\
+   (!m c f:real^1->real^N s.
+        vector_variation s (\x. f(m % x + c)) =
+        if m = &0 then &0 else vector_variation (IMAGE (\x. m % x + c) s) f)`,
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `m = &0` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LZERO; HAS_BOUNDED_VARIATION_ON_CONST;
+                  VECTOR_VARIATION_CONST] THEN
+  CONJ_TAC THENL
+   [MP_TAC(ISPECL[`m:real`; `c:real^1`; `f:real^1->real^N`;
+                  `IMAGE (\x:real^1. m % x + c) s`]
+          HAS_BOUNDED_VARIATION_AFFINITY2_EQ);
+    MP_TAC(ISPECL[`m:real`; `c:real^1`; `f:real^1->real^N`;
+                  `IMAGE (\x:real^1. m % x + c) s`]
+          VECTOR_VARIATION_AFFINITY2)] THEN
+  ASM_SIMP_TAC[AFFINITY_INVERSES; GSYM IMAGE_o; IMAGE_I]);;
+
+let HAS_BOUNDED_VARIATION_TRANSLATION_EQ,VECTOR_VARIATION_TRANSLATION =
+ (CONJ_PAIR o prove)
+ (`(!a f:real^1->real^N s.
+        (\x. f(a + x)) has_bounded_variation_on s <=>
+        f has_bounded_variation_on (IMAGE (\x. a + x) s)) /\
+   (!a f:real^1->real^N s.
+        vector_variation s (\x. f(a + x)) =
+        vector_variation (IMAGE (\x. a + x) s) f)`,
+  REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL[`a:real^1`; `f:real^1->real^N`; `IMAGE (\x:real^1. a + x) s`]
+          HAS_BOUNDED_VARIATION_TRANSLATION2_EQ);
+    MP_TAC(ISPECL[`a:real^1`; `f:real^1->real^N`; `IMAGE (\x:real^1. a + x) s`]
+          VECTOR_VARIATION_TRANSLATION2)] THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF] THEN
+  REWRITE_TAC[IMAGE_ID; VECTOR_ARITH `--a + a + x:real^N = x`;
+              VECTOR_ARITH `a + --a + x:real^N = x`]);;
+
+let HAS_BOUNDED_VARIATION_TRANSLATION_EQ_INTERVAL,
+    VECTOR_VARIATION_TRANSLATION_INTERVAL =
+ (CONJ_PAIR o prove)
+ (`(!a f:real^1->real^N u v.
+        (\x. f(a + x)) has_bounded_variation_on interval[u,v] <=>
+        f has_bounded_variation_on interval[a+u,a+v]) /\
+   (!a f:real^1->real^N u v.
+        vector_variation (interval[u,v]) (\x. f(a + x)) =
+        vector_variation (interval[a+u,a+v]) f)`,
+  REWRITE_TAC[INTERVAL_TRANSLATION; HAS_BOUNDED_VARIATION_TRANSLATION_EQ;
+              VECTOR_VARIATION_TRANSLATION]);;
+
+let HAS_BOUNDED_VARIATION_TRANSLATION = prove
+ (`!f:real^1->real^N s a.
+        f has_bounded_variation_on s
+        ==> (\x. f(a + x)) has_bounded_variation_on (IMAGE (\x. --a + x) s)`,
+  REWRITE_TAC[HAS_BOUNDED_VARIATION_TRANSLATION2_EQ]);;
+
+let HAS_BOUNDED_VARIATION_REFLECT2_EQ,VECTOR_VARIATION_REFLECT2 =
+ (CONJ_PAIR o prove)
+ (`(!f:real^1->real^N s.
+        (\x. f(--x)) has_bounded_variation_on (IMAGE (--) s) <=>
+        f has_bounded_variation_on s) /\
+   (!f:real^1->real^N s.
+        vector_variation (IMAGE (--) s) (\x. f(--x)) =
+        vector_variation s f)`,
+  MATCH_MP_TAC VARIATION_EQUAL_LEMMA THEN
+  REWRITE_TAC[] THEN CONJ_TAC THENL [VECTOR_ARITH_TAC; ALL_TAC] THEN
+  SIMP_TAC[DIVISION_OF_REFLECT; REFLECT_INTERVAL]);;
+
+let HAS_BOUNDED_VARIATION_REFLECT_EQ,VECTOR_VARIATION_REFLECT =
+ (CONJ_PAIR o prove)
+ (`(!f:real^1->real^N s.
+        (\x. f(--x)) has_bounded_variation_on s <=>
+        f has_bounded_variation_on (IMAGE (--) s)) /\
+   (!f:real^1->real^N s.
+        vector_variation s (\x. f(--x)) =
+        vector_variation (IMAGE (--) s) f)`,
+  REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL[`f:real^1->real^N`; `IMAGE (--) (s:real^1->bool)`]
+          HAS_BOUNDED_VARIATION_REFLECT2_EQ);
+    MP_TAC(ISPECL[`f:real^1->real^N`; `IMAGE (--) (s:real^1->bool)`]
+          VECTOR_VARIATION_REFLECT2)] THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF] THEN
+  REWRITE_TAC[IMAGE_ID; VECTOR_NEG_NEG]);;
+
+let HAS_BOUNDED_VARIATION_REFLECT_EQ_INTERVAL,
+    VECTOR_VARIATION_REFLECT_INTERVAL =
+ (CONJ_PAIR o prove)
+ (`(!f:real^1->real^N u v.
+        (\x. f(--x)) has_bounded_variation_on interval[u,v] <=>
+        f has_bounded_variation_on interval[--v,--u]) /\
+   (!f:real^1->real^N u v.
+        vector_variation (interval[u,v]) (\x. f(--x)) =
+        vector_variation (interval[--v,--u]) f)`,
+  REWRITE_TAC[GSYM REFLECT_INTERVAL; HAS_BOUNDED_VARIATION_REFLECT_EQ;
+              VECTOR_VARIATION_REFLECT]);;
+
+let HAS_BOUNDED_VARIATION_DARBOUX = prove
+ (`!f a b.
+     f has_bounded_variation_on interval[a,b] <=>
+     ?g h. (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+                  ==> drop(g x) <= drop(g y)) /\
+           (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+                  ==> drop(h x) <= drop(h y)) /\
+           (!x. f x = g x - h x)`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN STRIP_TAC THENL
+   [MAP_EVERY EXISTS_TAC
+     [`\x:real^1. lift(vector_variation (interval[a,x]) (f:real^1->real^1))`;
+      `\x:real^1. lift(vector_variation (interval[a,x]) f) - f x`] THEN
+    REWRITE_TAC[VECTOR_ARITH `a - (a - x):real^1 = x`] THEN
+    REWRITE_TAC[LIFT_DROP; DROP_SUB] THEN REPEAT STRIP_TAC THENL
+     [MATCH_MP_TAC VECTOR_VARIATION_MONOTONE;
+      MATCH_MP_TAC(REAL_ARITH
+       `!x. a - (b - x) <= c - (d - x) ==> a - b <= c - d`) THEN
+      EXISTS_TAC `drop(f(a:real^1))` THEN
+      REWRITE_TAC[GSYM DROP_SUB] THEN
+      MATCH_MP_TAC VECTOR_VARIATION_MINUS_FUNCTION_MONOTONE] THEN
+    (CONJ_TAC THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+         HAS_BOUNDED_VARIATION_ON_SUBSET));
+        ALL_TAC] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+      REWRITE_TAC[SUBSET_INTERVAL_1; INTERVAL_EQ_EMPTY_1] THEN
+      ASM_REAL_ARITH_TAC);
+    GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_SUB THEN
+    CONJ_TAC THEN MATCH_MP_TAC INCREASING_BOUNDED_VARIATION THEN
+    ASM_REWRITE_TAC[]]);;
+
+let HAS_BOUNDED_VARIATION_DARBOUX_STRICT = prove
+ (`!f a b.
+     f has_bounded_variation_on interval[a,b] <=>
+     ?g h. (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x < drop y
+                  ==> drop(g x) < drop(g y)) /\
+           (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x < drop y
+                  ==> drop(h x) < drop(h y)) /\
+           (!x. f x = g x - h x)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_BOUNDED_VARIATION_DARBOUX] THEN
+  EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`g:real^1->real^1`; `h:real^1->real^1`] THEN
+  STRIP_TAC THENL
+   [MAP_EVERY EXISTS_TAC [`\x:real^1. g x + x`; `\x:real^1. h x + x`] THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH `(a + x) - (b + x):real^1 = a - b`] THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[DROP_ADD] THEN
+    MATCH_MP_TAC REAL_LET_ADD2 THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[REAL_LT_IMP_LE];
+    MAP_EVERY EXISTS_TAC [`g:real^1->real^1`; `h:real^1->real^1`] THEN
+    ASM_REWRITE_TAC[REAL_LE_LT; DROP_EQ] THEN ASM_MESON_TAC[]]);;
+
+let HAS_BOUNDED_VARIATION_COMPOSE_INCREASING = prove
+ (`!f g:real^1->real^N a b.
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f x) <= drop(f y)) /\
+        g has_bounded_variation_on interval[f a,f b]
+        ==> (g o f) has_bounded_variation_on interval[a,b]`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ONCE_REWRITE_TAC[HAS_BOUNDED_VARIATION_ON_COMPONENTWISE] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[HAS_BOUNDED_VARIATION_DARBOUX; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`h:real^1->real^1`; `k:real^1->real^1`] THEN
+  STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`(h:real^1->real^1) o (f:real^1->real^1)`;
+                        `(k:real^1->real^1) o (f:real^1->real^1)`] THEN
+  ASM_REWRITE_TAC[o_THM] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REPEAT STRIP_TAC THEN TRY(FIRST_X_ASSUM MATCH_MP_TAC) THEN
+  ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[IN_INTERVAL_1] THEN CONJ_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[IN_INTERVAL_1] THEN ASM_REAL_ARITH_TAC);;
+
+let HAS_BOUNDED_VARIATION_ON_REFLECT = prove
+ (`!f:real^1->real^N s.
+        f has_bounded_variation_on IMAGE (--) s
+        ==> (\x. f(--x)) has_bounded_variation_on s`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[has_bounded_variation_on] THEN
+  REWRITE_TAC[has_bounded_setvariation_on] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `B:real` THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`d:(real^1->bool)->bool`; `t:real^1->bool`] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+   [`IMAGE (IMAGE (--)) (d:(real^1->bool)->bool)`;
+    `IMAGE (--) (t:real^1->bool)`]) THEN
+  ASM_SIMP_TAC[DIVISION_OF_REFLECT] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[GSYM SUBSET] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) SUM_IMAGE o lhand o lhand o snd) THEN
+  ANTS_TAC THENL
+   [MESON_TAC[VECTOR_ARITH `--x:real^N = --y <=> x = y`; INJECTIVE_IMAGE];
+    DISCH_THEN SUBST1_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `x = y ==> x <= d ==> y <= d`) THEN
+    MATCH_MP_TAC SUM_EQ THEN FIRST_ASSUM(fun th ->
+      GEN_REWRITE_TAC I [MATCH_MP FORALL_IN_DIVISION th]) THEN
+    MAP_EVERY X_GEN_TAC [`u:real^1`; `v:real^1`] THEN DISCH_TAC THEN
+    SUBGOAL_THEN `drop u <= drop v` ASSUME_TAC THENL
+     [ASM_MESON_TAC[INTERVAL_NE_EMPTY_1; division_of]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[o_THM; REFLECT_INTERVAL] THEN
+    ASM_SIMP_TAC[INTERVAL_UPPERBOUND_1; INTERVAL_LOWERBOUND_1;
+                 DROP_NEG; REAL_LE_NEG2] THEN
+    NORM_ARITH_TAC]);;
+
+let HAS_BOUNDED_VARIATION_ON_REFLECT_INTERVAL = prove
+ (`!f:real^1->real^N a b.
+        f has_bounded_variation_on interval[--b,--a]
+        ==> (\x. f(--x)) has_bounded_variation_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_REFLECT THEN
+  ASM_REWRITE_TAC[REFLECT_INTERVAL]);;
+
+let VECTOR_VARIATION_REFLECT = prove
+ (`!f:real^1->real^N s.
+        vector_variation s (\x. f(--x)) =
+        vector_variation (IMAGE (--) s) f`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[vector_variation; set_variation] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+  X_GEN_TAC `y:real` THEN EQ_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:(real^1->bool)->bool`
+   (CONJUNCTS_THEN2 MP_TAC SUBST1_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^1->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `IMAGE (IMAGE (--)) (d:(real^1->bool)->bool)` THEN
+  (CONJ_TAC THENL
+    [EXISTS_TAC `IMAGE (--) (t:real^1->bool)` THEN
+     ASM_SIMP_TAC[DIVISION_OF_REFLECT] THEN
+     ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+     RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; IN_IMAGE]) THEN
+     ASM_MESON_TAC[VECTOR_NEG_NEG; IN_IMAGE];
+     ALL_TAC]) THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) SUM_IMAGE o rand o snd) THEN
+  (ANTS_TAC THENL
+   [MESON_TAC[VECTOR_ARITH `--x:real^N = --y <=> x = y`; INJECTIVE_IMAGE];
+    DISCH_THEN SUBST1_TAC]) THEN
+  MATCH_MP_TAC SUM_EQ THEN FIRST_ASSUM(fun th ->
+    GEN_REWRITE_TAC I [MATCH_MP FORALL_IN_DIVISION th]) THEN
+  MAP_EVERY X_GEN_TAC [`u:real^1`; `v:real^1`] THEN DISCH_TAC THEN
+  (SUBGOAL_THEN `drop u <= drop v` ASSUME_TAC THENL
+   [ASM_MESON_TAC[INTERVAL_NE_EMPTY_1; division_of]; ALL_TAC]) THEN
+  ASM_REWRITE_TAC[o_THM; REFLECT_INTERVAL] THEN
+  ASM_SIMP_TAC[INTERVAL_UPPERBOUND_1; INTERVAL_LOWERBOUND_1;
+               DROP_NEG; REAL_LE_NEG2; VECTOR_NEG_NEG] THEN
+  NORM_ARITH_TAC);;
+
+let VECTOR_VARIATION_REFLECT_INTERVAL = prove
+ (`!f:real^1->real^N a b.
+        vector_variation (interval[a,b]) (\x. f(--x)) =
+        vector_variation (interval[--b,--a]) f`,
+  REWRITE_TAC[VECTOR_VARIATION_REFLECT; REFLECT_INTERVAL]);;
+
+let HAS_BOUNDED_VARIATION_COMPOSE_DECREASING = prove
+ (`!f g:real^1->real^N a b.
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f y) <= drop(f x)) /\
+        g has_bounded_variation_on interval[f b,f a]
+        ==> (g o f) has_bounded_variation_on interval[a,b]`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[VECTOR_NEG_NEG]
+    (ISPECL [`f:real^1->real^N`; `--b:real^1`; `--a:real^1`]
+        HAS_BOUNDED_VARIATION_ON_REFLECT_INTERVAL))) THEN
+  POP_ASSUM MP_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV o BINDER_CONV o RAND_CONV)
+   [GSYM REAL_LE_NEG2] THEN
+  REWRITE_TAC[GSYM DROP_NEG; IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_BOUNDED_VARIATION_COMPOSE_INCREASING) THEN
+  REWRITE_TAC[o_DEF; VECTOR_NEG_NEG]);;
+
+let HAS_BOUNDED_VARIATION_ON_ID = prove
+ (`!a b. (\x. x) has_bounded_variation_on interval[a,b]`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC INCREASING_BOUNDED_VARIATION THEN
+  SIMP_TAC[]);;
+
+let HAS_BOUNDED_VARIATION_ON_LINEAR_IMAGE = prove
+ (`!f:real^1->real^1 g:real^1->real^N a b.
+        linear f /\ g has_bounded_variation_on IMAGE f (interval[a,b])
+        ==> (g o f) has_bounded_variation_on interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LINEAR_1]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `c:real` SUBST_ALL_TAC) THEN
+  REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC (REAL_ARITH
+   `c = &0 \/ &0 <= c /\ &0 < c \/ ~(&0 <= c) /\ &0 < --c`)
+  THENL
+   [ASM_REWRITE_TAC[o_DEF; VECTOR_MUL_LZERO; HAS_BOUNDED_VARIATION_ON_CONST];
+    MATCH_MP_TAC HAS_BOUNDED_VARIATION_COMPOSE_INCREASING THEN
+    REWRITE_TAC[DROP_CMUL];
+    MATCH_MP_TAC HAS_BOUNDED_VARIATION_COMPOSE_DECREASING THEN
+    REWRITE_TAC[DROP_CMUL] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `c * y <= c * x <=> --c * x <= --c * y`]] THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL; REAL_LT_IMP_LE] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP(MESON[]
+   `g has_bounded_variation_on s
+    ==> s = t ==> g has_bounded_variation_on t`)) THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `c % x:real^N = c % x + vec 0`] THEN
+  ASM_REWRITE_TAC[IMAGE_AFFINITY_INTERVAL] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[VECTOR_ADD_RID] THEN
+  CONV_TAC SYM_CONV THEN REWRITE_TAC[INTERVAL_EQ_EMPTY_1; DROP_CMUL] THENL
+   [ALL_TAC;
+   ONCE_REWRITE_TAC[REAL_ARITH `c * y < c * x <=> --c * x < --c * y`]] THEN
+  MATCH_MP_TAC REAL_LT_LMUL THEN
+  ASM_REWRITE_TAC[GSYM INTERVAL_EQ_EMPTY_1]);;
+
+let INCREASING_LEFT_LIMIT_1 = prove
+ (`!f a b c.
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f x) <= drop(f y)) /\
+        c IN interval[a,b]
+       ==> ?l. (f --> l) (at c within interval[a,c])`,
+  REPEAT STRIP_TAC THEN EXISTS_TAC
+   `lift(sup {drop(f x) | x IN interval[a,b] /\ drop x < drop c})` THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN REWRITE_TAC[LIM_WITHIN] THEN
+  REWRITE_TAC[DIST_REAL; GSYM drop] THEN
+  ASM_CASES_TAC `{x | x IN interval[a,b] /\ drop x < drop c} = {}` THENL
+   [GEN_TAC THEN DISCH_TAC THEN EXISTS_TAC `&1` THEN
+    REWRITE_TAC[REAL_LT_01] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+    MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN MATCH_MP_TAC(TAUT
+     `(a ==> ~b) ==> a ==> b ==> c`) THEN
+    REWRITE_TAC[NOT_IN_EMPTY; IN_ELIM_THM; IN_INTERVAL_1] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPEC `{drop(f x) | x IN interval[a,b] /\ drop x < drop c}` SUP) THEN
+  ASM_REWRITE_TAC[FORALL_IN_GSPEC] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN ASM_SIMP_TAC[IMAGE_EQ_EMPTY];
+      EXISTS_TAC `drop(f(b:real^1))` THEN REPEAT STRIP_TAC THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC];
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN REWRITE_TAC[IMAGE_ID] THEN
+    ABBREV_TAC `s = sup (IMAGE (\x. drop(f x))
+                        {x | x IN interval[a,b] /\ drop x < drop c})` THEN
+    REWRITE_TAC[LIFT_DROP] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `s - e:real`)) THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < e ==> ~(s <= s - e)`; NOT_FORALL_THM] THEN
+    REWRITE_TAC[NOT_IMP; REAL_NOT_LE; IN_INTERVAL_1] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real^1` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `drop c - drop d` THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+    CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    X_GEN_TAC `x:real^1` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`d:real^1`; `x:real^1`]) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^1`) THEN ASM_REAL_ARITH_TAC]);;
+
+let DECREASING_LEFT_LIMIT_1 = prove
+ (`!f a b c.
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f y) <= drop(f x)) /\
+        c IN interval[a,b]
+        ==> ?l. (f --> l) (at c within interval[a,c])`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`\x. --((f:real^1->real^1) x)`; `a:real^1`; `b:real^1`; `c:real^1`]
+        INCREASING_LEFT_LIMIT_1) THEN
+  ASM_REWRITE_TAC[REAL_LE_NEG2; DROP_NEG] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [GSYM LIM_NEG_EQ] THEN
+  REWRITE_TAC[VECTOR_NEG_NEG; ETA_AX] THEN MESON_TAC[]);;
+
+let INCREASING_RIGHT_LIMIT_1 = prove
+ (`!f a b c.
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f x) <= drop(f y)) /\
+        c IN interval[a,b]
+       ==> ?l. (f --> l) (at c within interval[c,b])`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\x. (f:real^1->real^1) (--x)`;
+                 `--b:real^1`; `--a:real^1`; `--c:real^1`]
+        DECREASING_LEFT_LIMIT_1) THEN
+  ASM_REWRITE_TAC[IN_INTERVAL_REFLECT] THEN
+  ONCE_REWRITE_TAC[MESON[VECTOR_NEG_NEG]
+   `(!x:real^1 y:real^1. P x y) <=> (!x y. P (--x) (--y))`] THEN
+  REWRITE_TAC[DROP_NEG; IN_INTERVAL_REFLECT; VECTOR_NEG_NEG] THEN
+  ASM_SIMP_TAC[REAL_LE_NEG2] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `l:real^1` THEN REWRITE_TAC[LIM_WITHIN] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+   [MESON[VECTOR_NEG_NEG] `(!x:real^1. P x) <=> (!x. P (--x))`] THEN
+  REWRITE_TAC[IN_INTERVAL_REFLECT; VECTOR_NEG_NEG;
+              NORM_ARITH `dist(--x:real^1,--y) = dist(x,y)`]);;
+
+let DECREASING_RIGHT_LIMIT_1 = prove
+ (`!f a b c.
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f y) <= drop(f x)) /\
+        c IN interval[a,b]
+       ==> ?l. (f --> l) (at c within interval[c,b])`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`\x. --((f:real^1->real^1) x)`; `a:real^1`; `b:real^1`; `c:real^1`]
+        INCREASING_RIGHT_LIMIT_1) THEN
+  ASM_REWRITE_TAC[REAL_LE_NEG2; DROP_NEG] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [GSYM LIM_NEG_EQ] THEN
+  REWRITE_TAC[VECTOR_NEG_NEG; ETA_AX] THEN MESON_TAC[]);;
+
+let HAS_BOUNDED_VECTOR_VARIATION_LEFT_LIMIT = prove
+ (`!f:real^1->real^N a b c.
+        f has_bounded_variation_on interval[a,b] /\ c IN interval[a,b]
+        ==> ?l. (f --> l) (at c within interval[a,c])`,
+  ONCE_REWRITE_TAC[LIM_COMPONENTWISE_LIFT;
+                   HAS_BOUNDED_VARIATION_ON_COMPONENTWISE] THEN
+  REWRITE_TAC[GSYM LAMBDA_SKOLEM] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+  SPEC_TAC(`\x. lift((f:real^1->real^N)x$i)`,`f:real^1->real^1`) THEN
+  UNDISCH_TAC `(c:real^1) IN interval[a,b]` THEN POP_ASSUM_LIST(K ALL_TAC) THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM EXISTS_LIFT] THEN
+  FIRST_X_ASSUM
+   (MP_TAC o GEN_REWRITE_RULE I [HAS_BOUNDED_VARIATION_DARBOUX]) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; CONJ_ASSOC] THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC] THEN DISCH_THEN(CONJUNCTS_THEN
+   (MP_TAC o SPEC `c:real^1` o MATCH_MP
+     (ONCE_REWRITE_RULE[IMP_CONJ] INCREASING_LEFT_LIMIT_1))) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `l2:real^1` THEN DISCH_TAC THEN
+  X_GEN_TAC `l1:real^1` THEN DISCH_TAC THEN
+  EXISTS_TAC `l1 - l2:real^1` THEN
+  GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+  ASM_SIMP_TAC[LIM_SUB]);;
+
+let HAS_BOUNDED_VECTOR_VARIATION_RIGHT_LIMIT = prove
+ (`!f:real^1->real^N a b c.
+        f has_bounded_variation_on interval[a,b] /\ c IN interval[a,b]
+        ==> ?l. (f --> l) (at c within interval[c,b])`,
+  ONCE_REWRITE_TAC[LIM_COMPONENTWISE_LIFT;
+                   HAS_BOUNDED_VARIATION_ON_COMPONENTWISE] THEN
+  REWRITE_TAC[GSYM LAMBDA_SKOLEM] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+  SPEC_TAC(`\x. lift((f:real^1->real^N)x$i)`,`f:real^1->real^1`) THEN
+  UNDISCH_TAC `(c:real^1) IN interval[a,b]` THEN POP_ASSUM_LIST(K ALL_TAC) THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM EXISTS_LIFT] THEN
+  FIRST_X_ASSUM
+   (MP_TAC o GEN_REWRITE_RULE I [HAS_BOUNDED_VARIATION_DARBOUX]) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; CONJ_ASSOC] THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC] THEN DISCH_THEN(CONJUNCTS_THEN
+   (MP_TAC o SPEC `c:real^1` o MATCH_MP
+     (ONCE_REWRITE_RULE[IMP_CONJ] INCREASING_RIGHT_LIMIT_1))) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `l2:real^1` THEN DISCH_TAC THEN
+  X_GEN_TAC `l1:real^1` THEN DISCH_TAC THEN
+  EXISTS_TAC `l1 - l2:real^1` THEN
+  GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+  ASM_SIMP_TAC[LIM_SUB]);;
+
+let VECTOR_VARIATION_CONTINUOUS_LEFT = prove
+ (`!f:real^1->real^1 a b c.
+        f has_bounded_variation_on interval[a,b] /\ c IN interval[a,b]
+        ==> ((\x. lift(vector_variation(interval[a,x]) f))
+             continuous (at c within interval[a,c]) <=>
+            f continuous (at c within interval[a,c]))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[continuous_within] THEN
+    REWRITE_TAC[DIST_LIFT; IN_ELIM_THM; DIST_REAL; GSYM drop] 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
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:real^1` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^1`) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_LET_TRANS) THEN
+    REWRITE_TAC[GSYM DROP_SUB] THEN
+    MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `c:real^1`; `x:real^1`]
+        VECTOR_VARIATION_COMBINE) THEN
+    ANTS_TAC THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+      REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+         HAS_BOUNDED_VARIATION_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[REAL_ARITH `abs(a - (a + b)) = abs b`] THEN
+    REWRITE_TAC[drop; GSYM NORM_REAL] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= a ==> x <= abs a`) THEN
+    ONCE_REWRITE_TAC[NORM_SUB] THEN
+    MATCH_MP_TAC VECTOR_VARIATION_GE_NORM_FUNCTION THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        HAS_BOUNDED_VARIATION_ON_SUBSET));
+      REWRITE_TAC[SEGMENT_1] THEN COND_CASES_TAC] THEN
+    REWRITE_TAC[SUBSET_INTERVAL_1] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_TAC THEN ASM_CASES_TAC `c limit_point_of interval[a:real^1,c]` THENL
+   [ALL_TAC;
+    ASM_REWRITE_TAC[CONTINUOUS_WITHIN; LIM; TRIVIAL_LIMIT_WITHIN]] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HAS_BOUNDED_VARIATION_DARBOUX]) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`g:real^1->real^1`; `h:real^1->real^1`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`h:real^1->real^1`; `a:real^1`; `b:real^1`; `c:real^1`]
+   INCREASING_LEFT_LIMIT_1) THEN
+  MP_TAC(ISPECL [`g:real^1->real^1`; `a:real^1`; `b:real^1`; `c:real^1`]
+   INCREASING_LEFT_LIMIT_1) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `gc:real^1` THEN DISCH_TAC THEN
+  X_GEN_TAC `hc:real^1` THEN DISCH_TAC THEN
+  ABBREV_TAC `k = gc - (g:real^1->real^1) c` THEN
+  SUBGOAL_THEN `hc - (h:real^1->real^1) c = k` ASSUME_TAC THENL
+   [EXPAND_TAC "k" THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+     `hc' - hc:real^1 = gc' - gc <=> gc' - hc' = gc - hc`] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONTINUOUS_WITHIN]) THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+      LIM_UNIQUE) THEN
+    ASM_REWRITE_TAC[TRIVIAL_LIMIT_WITHIN] THEN
+    GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+    ASM_SIMP_TAC[LIM_SUB];
+    ALL_TAC] THEN
+  MAP_EVERY ABBREV_TAC
+   [`g':real^1->real^1 = \x. if drop c <= drop x then g(x) + k else g(x)`;
+    `h':real^1->real^1 = \x. if drop c <= drop x then h(x) + k else h(x)`] THEN
+  SUBGOAL_THEN
+   `(!x y. x IN interval[a,c] /\ y IN interval[a,c] /\ drop x <= drop y
+           ==> drop(g' x) <= drop(g' y)) /\
+    (!x y. x IN interval[a,c] /\ y IN interval[a,c] /\ drop x <= drop y
+           ==> drop(h' x) <= drop(h' y))`
+  STRIP_ASSUME_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["g'"; "h'"] THEN REWRITE_TAC[] THEN CONJ_TAC THEN
+    MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN
+    REWRITE_TAC[IN_INTERVAL_1] THEN STRIP_TAC THEN
+    (ASM_CASES_TAC `drop c <= drop x` THENL
+      [SUBGOAL_THEN `drop c <= drop y` ASSUME_TAC THENL
+        [ASM_REAL_ARITH_TAC; ASM_REWRITE_TAC[]] THEN
+       REWRITE_TAC[DROP_ADD; REAL_LE_RADD] THEN
+       FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+       RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+       ALL_TAC] THEN
+     ASM_REWRITE_TAC[] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+      [ALL_TAC;
+       FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+       RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC] THEN
+     SUBGOAL_THEN `y:real^1 = c` SUBST_ALL_TAC THENL
+      [REWRITE_TAC[GSYM DROP_EQ] THEN ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+     FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[]
+      `gc - g c = k
+       ==> b <= drop(g c + (gc - g c)) ==> b <= drop(g c + k)`)) THEN
+     REWRITE_TAC[VECTOR_ARITH `a + b - a:real^1 = b`] THEN
+     MATCH_MP_TAC(ISPEC `at c within interval[a:real^1,c]`
+        LIM_DROP_LBOUND))
+    THENL [EXISTS_TAC `g:real^1->real^1`; EXISTS_TAC `h:real^1->real^1`] THEN
+    ASM_REWRITE_TAC[TRIVIAL_LIMIT_WITHIN; EVENTUALLY_WITHIN] THEN
+    EXISTS_TAC `drop c - drop x` THEN
+    (CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+    REWRITE_TAC[DIST_REAL; GSYM drop; IN_INTERVAL_1] THEN
+    REWRITE_TAC[IN_INTERVAL_1] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(g':real^1->real^1) continuous (at c within interval[a,c]) /\
+    (h':real^1->real^1) continuous (at c within interval[a,c])`
+  MP_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["g'"; "h'"] THEN
+    REWRITE_TAC[CONTINUOUS_WITHIN; REAL_LE_REFL] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[VECTOR_ARITH
+     `g - g':real^1 = k <=> g' + k = g`]) THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ_ALT] LIM_TRANSFORM)) THEN
+    MAP_EVERY EXPAND_TAC ["g'"; "h'"] THEN
+    REWRITE_TAC[LIM_WITHIN; DIST_REAL; GSYM drop; IN_INTERVAL_1] THEN
+    SIMP_TAC[REAL_ARITH `x <= c /\ &0 < abs(x - c) ==> ~(c <= x)`] THEN
+    REWRITE_TAC[VECTOR_SUB_REFL; DROP_VEC; REAL_SUB_REFL; REAL_ABS_NUM] THEN
+    MESON_TAC[REAL_LT_01];
+    ALL_TAC] THEN
+  REWRITE_TAC[continuous_within] THEN
+  REWRITE_TAC[DIST_LIFT; IN_ELIM_THM; DIST_REAL; GSYM drop] THEN
+  DISCH_THEN(fun th ->
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    CONJUNCTS_THEN (MP_TAC o SPEC `e / &2`) th) THEN
+  ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d2:real` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `min d1 d2:real` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+  X_GEN_TAC `d:real^1` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `c:real^1`; `d:real^1`]
+        VECTOR_VARIATION_COMBINE) THEN
+  ANTS_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+    REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       HAS_BOUNDED_VARIATION_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+    DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  REWRITE_TAC[REAL_ARITH `abs(a - (a + b)) = abs b`] THEN
+  MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ x < a ==> abs x < a`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC VECTOR_VARIATION_POS_LE THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       HAS_BOUNDED_VARIATION_ON_SUBSET)) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+    REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `f:real^1->real^1 = \x. g' x - h' x` SUBST1_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["g'"; "h'"] THEN REWRITE_TAC[FUN_EQ_THM] THEN
+    GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`g':real^1->real^1`; `\x. --((h':real^1->real^1) x)`;
+    `interval[d:real^1,c]`] VECTOR_VARIATION_TRIANGLE) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL [ALL_TAC; MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_NEG] THEN
+    MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_SUBSET THEN
+    EXISTS_TAC `interval[a:real^1,c]` THEN
+    ASM_SIMP_TAC[INCREASING_BOUNDED_VARIATION; SUBSET_INTERVAL_1] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN  ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[VECTOR_SUB] THEN MATCH_MP_TAC(REAL_ARITH
+   `y < a / &2 /\ z < a / &2 ==> x <= y + z ==> x < a`) THEN
+  REWRITE_TAC[VECTOR_VARIATION_NEG] THEN CONJ_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand)
+    INCREASING_VECTOR_VARIATION o lhand o snd) THEN
+  (ANTS_TAC THENL
+    [RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+     ASM_REWRITE_TAC[INTERVAL_EQ_EMPTY_1; IN_INTERVAL_1; REAL_NOT_LT] THEN
+     REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC;
+     DISCH_THEN SUBST1_TAC]) THEN
+  MATCH_MP_TAC(REAL_ARITH `abs(x - y) < e ==> y - x < e`) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]);;
+
+let VECTOR_VARIATION_CONTINUOUS_RIGHT = prove
+ (`!f:real^1->real^1 a b c.
+        f has_bounded_variation_on interval[a,b] /\ c IN interval[a,b]
+        ==> ((\x. lift(vector_variation(interval[a,x]) f))
+             continuous (at c within interval[c,b]) <=>
+            f continuous (at c within interval[c,b]))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[continuous_within] THEN
+    REWRITE_TAC[DIST_LIFT; IN_ELIM_THM; DIST_REAL; GSYM drop] 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
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:real^1` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^1`) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_LET_TRANS) THEN
+    REWRITE_TAC[GSYM DROP_SUB] THEN
+    MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `x:real^1`; `c:real^1`]
+        VECTOR_VARIATION_COMBINE) THEN
+    ANTS_TAC THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+      REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+         HAS_BOUNDED_VARIATION_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[REAL_ARITH `abs((a + b) - a) = abs b`] THEN
+    REWRITE_TAC[drop; GSYM NORM_REAL] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= a ==> x <= abs a`) THEN
+    MATCH_MP_TAC VECTOR_VARIATION_GE_NORM_FUNCTION THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        HAS_BOUNDED_VARIATION_ON_SUBSET));
+      REWRITE_TAC[SEGMENT_1] THEN COND_CASES_TAC] THEN
+    REWRITE_TAC[SUBSET_INTERVAL_1] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_TAC THEN ASM_CASES_TAC `c limit_point_of interval[c:real^1,b]` THENL
+   [ALL_TAC;
+    ASM_REWRITE_TAC[CONTINUOUS_WITHIN; LIM; TRIVIAL_LIMIT_WITHIN]] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HAS_BOUNDED_VARIATION_DARBOUX]) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`g:real^1->real^1`; `h:real^1->real^1`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`h:real^1->real^1`; `a:real^1`; `b:real^1`; `c:real^1`]
+   INCREASING_RIGHT_LIMIT_1) THEN
+  MP_TAC(ISPECL [`g:real^1->real^1`; `a:real^1`; `b:real^1`; `c:real^1`]
+   INCREASING_RIGHT_LIMIT_1) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `gc:real^1` THEN DISCH_TAC THEN
+  X_GEN_TAC `hc:real^1` THEN DISCH_TAC THEN
+  ABBREV_TAC `k = gc - (g:real^1->real^1) c` THEN
+  SUBGOAL_THEN `hc - (h:real^1->real^1) c = k` ASSUME_TAC THENL
+   [EXPAND_TAC "k" THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+     `hc' - hc:real^1 = gc' - gc <=> gc' - hc' = gc - hc`] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONTINUOUS_WITHIN]) THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+      LIM_UNIQUE) THEN
+    ASM_REWRITE_TAC[TRIVIAL_LIMIT_WITHIN] THEN
+    GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+    ASM_SIMP_TAC[LIM_SUB];
+    ALL_TAC] THEN
+  MAP_EVERY ABBREV_TAC
+   [`g':real^1->real^1 = \x. if drop x <= drop c then g(x) + k else g(x)`;
+    `h':real^1->real^1 = \x. if drop x <= drop c then h(x) + k else h(x)`] THEN
+  SUBGOAL_THEN
+   `(!x y. x IN interval[c,b] /\ y IN interval[c,b] /\ drop x <= drop y
+           ==> drop(g' x) <= drop(g' y)) /\
+    (!x y. x IN interval[c,b] /\ y IN interval[c,b] /\ drop x <= drop y
+           ==> drop(h' x) <= drop(h' y))`
+  STRIP_ASSUME_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["g'"; "h'"] THEN REWRITE_TAC[] THEN CONJ_TAC THEN
+    MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN
+    REWRITE_TAC[IN_INTERVAL_1] THEN STRIP_TAC THEN
+    (ASM_CASES_TAC `drop y <= drop c` THENL
+      [SUBGOAL_THEN `drop x <= drop c` ASSUME_TAC THENL
+        [ASM_REAL_ARITH_TAC; ASM_REWRITE_TAC[]] THEN
+       REWRITE_TAC[DROP_ADD; REAL_LE_RADD] THEN
+       FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+       RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+       ALL_TAC] THEN
+     ASM_REWRITE_TAC[] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+      [ALL_TAC;
+       FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+       RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC] THEN
+     SUBGOAL_THEN `x:real^1 = c` SUBST_ALL_TAC THENL
+      [REWRITE_TAC[GSYM DROP_EQ] THEN ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+     FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[]
+      `gc - g c = k
+       ==> drop(g c + (gc - g c)) <= b ==> drop(g c + k) <= b`)) THEN
+     REWRITE_TAC[VECTOR_ARITH `a + b - a:real^1 = b`] THEN
+     MATCH_MP_TAC(ISPEC `at c within interval[c:real^1,b]`
+        LIM_DROP_UBOUND))
+    THENL [EXISTS_TAC `g:real^1->real^1`; EXISTS_TAC `h:real^1->real^1`] THEN
+    ASM_REWRITE_TAC[TRIVIAL_LIMIT_WITHIN; EVENTUALLY_WITHIN] THEN
+    EXISTS_TAC `drop y - drop c` THEN
+    (CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+    REWRITE_TAC[DIST_REAL; GSYM drop; IN_INTERVAL_1] THEN
+    REWRITE_TAC[IN_INTERVAL_1] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(g':real^1->real^1) continuous (at c within interval[c,b]) /\
+    (h':real^1->real^1) continuous (at c within interval[c,b])`
+  MP_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["g'"; "h'"] THEN
+    REWRITE_TAC[CONTINUOUS_WITHIN; REAL_LE_REFL] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[VECTOR_ARITH
+     `g - g':real^1 = k <=> g' + k = g`]) THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ_ALT] LIM_TRANSFORM)) THEN
+    MAP_EVERY EXPAND_TAC ["g'"; "h'"] THEN
+    REWRITE_TAC[LIM_WITHIN; DIST_REAL; GSYM drop; IN_INTERVAL_1] THEN
+    SIMP_TAC[REAL_ARITH `c <= x /\ &0 < abs(x - c) ==> ~(x <= c)`] THEN
+    REWRITE_TAC[VECTOR_SUB_REFL; DROP_VEC; REAL_SUB_REFL; REAL_ABS_NUM] THEN
+    MESON_TAC[REAL_LT_01];
+    ALL_TAC] THEN
+  REWRITE_TAC[continuous_within] THEN
+  REWRITE_TAC[DIST_LIFT; IN_ELIM_THM; DIST_REAL; GSYM drop] THEN
+  DISCH_THEN(fun th ->
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    CONJUNCTS_THEN (MP_TAC o SPEC `e / &2`) th) THEN
+  ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d2:real` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `min d1 d2:real` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+  X_GEN_TAC `d:real^1` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `d:real^1`; `c:real^1`]
+        VECTOR_VARIATION_COMBINE) THEN
+  ANTS_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+    REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       HAS_BOUNDED_VARIATION_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+    DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  REWRITE_TAC[REAL_ARITH `(a + b) - a:real = b`] THEN
+  MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ x < a ==> abs x < a`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC VECTOR_VARIATION_POS_LE THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       HAS_BOUNDED_VARIATION_ON_SUBSET)) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+    REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `f:real^1->real^1 = \x. g' x - h' x` SUBST1_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["g'"; "h'"] THEN REWRITE_TAC[FUN_EQ_THM] THEN
+    GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`g':real^1->real^1`; `\x. --((h':real^1->real^1) x)`;
+    `interval[c:real^1,d]`] VECTOR_VARIATION_TRIANGLE) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL [ALL_TAC; MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_NEG] THEN
+    MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_SUBSET THEN
+    EXISTS_TAC `interval[c:real^1,b]` THEN
+    ASM_SIMP_TAC[INCREASING_BOUNDED_VARIATION; SUBSET_INTERVAL_1] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN  ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[VECTOR_SUB] THEN MATCH_MP_TAC(REAL_ARITH
+   `y < a / &2 /\ z < a / &2 ==> x <= y + z ==> x < a`) THEN
+  REWRITE_TAC[VECTOR_VARIATION_NEG] THEN CONJ_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand)
+    INCREASING_VECTOR_VARIATION o lhand o snd) THEN
+  (ANTS_TAC THENL
+    [RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+     ASM_REWRITE_TAC[INTERVAL_EQ_EMPTY_1; IN_INTERVAL_1; REAL_NOT_LT] THEN
+     REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC;
+     DISCH_THEN SUBST1_TAC]) THEN
+  MATCH_MP_TAC(REAL_ARITH `abs x < e ==> x < e`) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]);;
+
+let VECTOR_VARIATION_CONTINUOUS = prove
+ (`!f:real^1->real^1 a b c.
+        f has_bounded_variation_on interval[a,b] /\ c IN interval[a,b]
+        ==> ((\x. lift(vector_variation(interval[a,x]) f))
+             continuous (at c within interval[a,b]) <=>
+            f continuous (at c within interval[a,b]))`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!f:real^1->real^1.
+        f continuous (at c within interval[a,b]) <=>
+        f continuous (at c within interval[a,c]) /\
+        f continuous (at c within interval[c,b])`
+   (fun th -> REWRITE_TAC[th] THEN
+              ASM_MESON_TAC[VECTOR_VARIATION_CONTINUOUS_LEFT;
+                            VECTOR_VARIATION_CONTINUOUS_RIGHT]) THEN
+  GEN_TAC THEN REWRITE_TAC[CONTINUOUS_WITHIN] THEN EQ_TAC THENL
+   [DISCH_THEN(ASSUME_TAC o GEN_ALL o
+     MATCH_MP (REWRITE_RULE[IMP_CONJ] LIM_WITHIN_SUBSET)) THEN
+    CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC;
+    DISCH_THEN(MP_TAC o MATCH_MP LIM_UNION) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] LIM_WITHIN_SUBSET)] THEN
+  REWRITE_TAC[SUBSET; IN_UNION; IN_INTERVAL_1] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC);;
+
+let HAS_BOUNDED_VARIATION_DARBOUX_STRONG = prove
+ (`!f a b.
+     f has_bounded_variation_on interval[a,b]
+     ==> ?g h. (!x. f x = g x - h x) /\
+               (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\
+                      drop x <= drop y
+                      ==> drop(g x) <= drop(g y)) /\
+               (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\
+                      drop x <= drop y
+                      ==> drop(h x) <= drop(h y)) /\
+               (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\
+                      drop x < drop y
+                      ==> drop(g x) < drop(g y)) /\
+               (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\
+                      drop x < drop y
+                      ==> drop(h x) < drop(h y)) /\
+               (!x. x IN interval[a,b] /\
+                    f continuous (at x within interval[a,x])
+                    ==> g continuous (at x within interval[a,x]) /\
+                        h continuous (at x within interval[a,x])) /\
+               (!x. x IN interval[a,b] /\
+                    f continuous (at x within interval[x,b])
+                    ==> g continuous (at x within interval[x,b]) /\
+                        h continuous (at x within interval[x,b])) /\
+               (!x. x IN interval[a,b] /\
+                    f continuous (at x within interval[a,b])
+                    ==> g continuous (at x within interval[a,b]) /\
+                        h continuous (at x within interval[a,b]))`,
+  REPEAT STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC
+   [`\x:real^1. x + lift(vector_variation (interval[a,x]) (f:real^1->real^1))`;
+    `\x:real^1. x + lift(vector_variation (interval[a,x]) f) - f x`] THEN
+  REWRITE_TAC[VECTOR_ARITH `(x + l) - (x + l - f):real^1 = f`] THEN
+  REWRITE_TAC[LIFT_DROP; DROP_SUB; DROP_ADD] THEN REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC REAL_LE_ADD2 THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC VECTOR_VARIATION_MONOTONE;
+    MATCH_MP_TAC REAL_LE_ADD2 THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `!x. a - (b - x) <= c - (d - x) ==> a - b <= c - d`) THEN
+    EXISTS_TAC `drop(f(a:real^1))` THEN
+    REWRITE_TAC[GSYM DROP_SUB] THEN
+    MATCH_MP_TAC VECTOR_VARIATION_MINUS_FUNCTION_MONOTONE;
+    MATCH_MP_TAC REAL_LTE_ADD2 THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC VECTOR_VARIATION_MONOTONE;
+    MATCH_MP_TAC REAL_LTE_ADD2 THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `!x. a - (b - x) <= c - (d - x) ==> a - b <= c - d`) THEN
+    EXISTS_TAC `drop(f(a:real^1))` THEN
+    REWRITE_TAC[GSYM DROP_SUB] THEN
+    MATCH_MP_TAC VECTOR_VARIATION_MINUS_FUNCTION_MONOTONE;
+    MATCH_MP_TAC CONTINUOUS_ADD THEN
+    REWRITE_TAC[CONTINUOUS_WITHIN_ID] THEN
+    MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `b:real^1`; `x:real^1`]
+        VECTOR_VARIATION_CONTINUOUS_LEFT) THEN
+    ASM_REWRITE_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ADD THEN
+    REWRITE_TAC[CONTINUOUS_WITHIN_ID] THEN
+    MATCH_MP_TAC CONTINUOUS_SUB THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `b:real^1`; `x:real^1`]
+        VECTOR_VARIATION_CONTINUOUS_LEFT) THEN
+    ASM_REWRITE_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ADD THEN
+    REWRITE_TAC[CONTINUOUS_WITHIN_ID] THEN
+    MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `b:real^1`; `x:real^1`]
+        VECTOR_VARIATION_CONTINUOUS_RIGHT) THEN
+    ASM_REWRITE_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ADD THEN
+    REWRITE_TAC[CONTINUOUS_WITHIN_ID] THEN
+    MATCH_MP_TAC CONTINUOUS_SUB THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `b:real^1`; `x:real^1`]
+        VECTOR_VARIATION_CONTINUOUS_RIGHT) THEN
+    ASM_REWRITE_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ADD THEN
+    REWRITE_TAC[CONTINUOUS_WITHIN_ID] THEN
+    MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `b:real^1`; `x:real^1`]
+        VECTOR_VARIATION_CONTINUOUS) THEN
+    ASM_REWRITE_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ADD THEN
+    REWRITE_TAC[CONTINUOUS_WITHIN_ID] THEN
+    MATCH_MP_TAC CONTINUOUS_SUB THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `b:real^1`; `x:real^1`]
+        VECTOR_VARIATION_CONTINUOUS) THEN
+    ASM_REWRITE_TAC[]] THEN
+  (CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       HAS_BOUNDED_VARIATION_ON_SUBSET));
+      ALL_TAC] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+    REWRITE_TAC[SUBSET_INTERVAL_1; INTERVAL_EQ_EMPTY_1] THEN
+    ASM_REAL_ARITH_TAC));;
+
+let HAS_BOUNDED_VARIATION_COUNTABLE_DISCONTINUITIES = prove
+ (`!f:real^1->real^1 a b.
+        f has_bounded_variation_on interval[a,b]
+        ==> COUNTABLE {x | x IN interval[a,b] /\ ~(f continuous at x)}`,
+  SUBGOAL_THEN
+   `!f a b.
+        (!x y. x IN interval[a,b] /\ y IN interval[a,b] /\ drop x <= drop y
+               ==> drop(f x) <= drop(f y))
+        ==> COUNTABLE {x | x IN interval[a,b] /\ ~(f continuous at x)}`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o
+     GEN_REWRITE_RULE I [HAS_BOUNDED_VARIATION_DARBOUX]) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`g:real^1->real^1`; `h:real^1->real^1`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(fun th ->
+      MP_TAC(ISPECL [`g:real^1->real^1`; `a:real^1`; `b:real^1`] th) THEN
+      MP_TAC(ISPECL [`h:real^1->real^1`; `a:real^1`; `b:real^1`] th)) THEN
+    ASM_REWRITE_TAC[IMP_IMP; GSYM COUNTABLE_UNION] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] COUNTABLE_SUBSET) THEN
+    REWRITE_TAC[SUBSET; IN_UNION; IN_ELIM_THM] THEN GEN_TAC THEN
+    MATCH_MP_TAC(TAUT
+     `(p /\ q ==> r) ==> a /\ ~r ==> a /\ ~p \/ a /\ ~q`) THEN
+    GEN_REWRITE_TAC (RAND_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+    ASM_SIMP_TAC[CONTINUOUS_SUB]] THEN
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `interval[a:real^1,b] = {}` THEN
+  ASM_REWRITE_TAC[NOT_IN_EMPTY; EMPTY_GSPEC; COUNTABLE_EMPTY] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_EQ_EMPTY_1; REAL_NOT_LT]) THEN
+  ASM_SIMP_TAC[CLOSED_OPEN_INTERVAL_1] THEN
+  MATCH_MP_TAC COUNTABLE_SUBSET THEN EXISTS_TAC
+   `a INSERT b INSERT
+    {x | x IN interval(a,b) /\ ~((f:real^1->real^1) continuous at x)}` THEN
+  CONJ_TAC THENL [REWRITE_TAC[COUNTABLE_INSERT]; SET_TAC[]] THEN
+  SUBGOAL_THEN
+   `(!c:real^1. c IN interval(a,b) ==> c limit_point_of interval[a,c]) /\
+    (!c:real^1. c IN interval(a,b) ==> c limit_point_of interval[c,b])`
+  STRIP_ASSUME_TAC THENL
+   [SIMP_TAC[IN_INTERVAL_1; REAL_LE_REFL; LIMPT_OF_CONVEX;
+             CONVEX_INTERVAL; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[GSYM INTERVAL_SING; GSYM SUBSET_ANTISYM_EQ] THEN
+    REWRITE_TAC[SUBSET_INTERVAL_1] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `b:real^1`]
+        INCREASING_LEFT_LIMIT_1) THEN
+  ASM_REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `l:real^1->real^1` (LABEL_TAC "l")) THEN
+  MP_TAC(ISPECL [`f:real^1->real^1`; `a:real^1`; `b:real^1`]
+        INCREASING_RIGHT_LIMIT_1) THEN
+  ASM_REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real^1->real^1` (LABEL_TAC "r")) THEN
+  SUBGOAL_THEN
+   `!c. c IN interval(a:real^1,b)
+        ==> drop(l c) <= drop(f c) /\ drop(f c) <= drop(r c)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THENL
+     [MATCH_MP_TAC(ISPEC `at c within interval[a:real^1,c]`
+        LIM_DROP_UBOUND);
+      MATCH_MP_TAC(ISPEC `at c within interval[c:real^1,b]`
+        LIM_DROP_LBOUND)] THEN
+    EXISTS_TAC `f:real^1->real^1` THEN
+    ASM_SIMP_TAC[REWRITE_RULE[SUBSET] INTERVAL_OPEN_SUBSET_CLOSED;
+                 TRIVIAL_LIMIT_WITHIN; EVENTUALLY_WITHIN] THEN
+    EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01; IN_INTERVAL_1] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[IN_INTERVAL_1] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(!c x. c IN interval(a:real^1,b) /\ x IN interval[a,b] /\ drop x < drop c
+           ==> drop(f x) <= drop(l c)) /\
+    (!c x. c IN interval(a:real^1,b) /\ x IN interval[a,b] /\ drop c < drop x
+           ==> drop(r c) <= drop(f x))`
+  STRIP_ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THENL
+     [MATCH_MP_TAC(ISPEC `at c within interval[a:real^1,c]`
+        LIM_DROP_LBOUND);
+      MATCH_MP_TAC(ISPEC `at c within interval[c:real^1,b]`
+        LIM_DROP_UBOUND)] THEN
+    EXISTS_TAC `f:real^1->real^1` THEN
+    ASM_SIMP_TAC[REWRITE_RULE[SUBSET] INTERVAL_OPEN_SUBSET_CLOSED;
+                 TRIVIAL_LIMIT_WITHIN; EVENTUALLY_WITHIN]
+    THENL
+     [EXISTS_TAC `drop c - drop x`; EXISTS_TAC `drop x - drop c`] THEN
+    ASM_REWRITE_TAC[REAL_SUB_LT] THEN
+    X_GEN_TAC `y:real^1` THEN
+    REWRITE_TAC[IN_INTERVAL_1; IN_ELIM_THM; DIST_REAL; GSYM drop] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[COUNTABLE; ge_c] THEN
+  TRANS_TAC CARD_LE_TRANS `rational` THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM ge_c] THEN
+  REWRITE_TAC[COUNTABLE_RATIONAL; GSYM COUNTABLE; le_c] THEN
+  SUBGOAL_THEN
+   `!c. c IN interval(a,b) /\ ~((f:real^1->real^1) continuous at c)
+          ==> drop(l(c:real^1)) < drop(r c)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_LT_LE] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[REAL_LE_TRANS]; ALL_TAC] THEN
+    REWRITE_TAC[DROP_EQ] THEN DISCH_TAC THEN
+    SUBGOAL_THEN `l c = (f:real^1->real^1) c /\ r c = f c` ASSUME_TAC THENL
+     [ASM_MESON_TAC[REAL_LE_ANTISYM; DROP_EQ]; ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [CONTINUOUS_AT]) THEN
+    REWRITE_TAC[] THEN
+    SUBGOAL_THEN
+     `((f:real^1->real^1) --> f c) (at c within interval(a,b))`
+    MP_TAC THENL
+     [ALL_TAC; ASM_SIMP_TAC[OPEN_INTERVAL; LIM_WITHIN_OPEN]] THEN
+    MATCH_MP_TAC LIM_WITHIN_SUBSET THEN
+    EXISTS_TAC `interval[a:real^1,c] UNION interval[c,b]` THEN
+    REWRITE_TAC[LIM_WITHIN_UNION] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[REWRITE_RULE[SUBSET] INTERVAL_OPEN_SUBSET_CLOSED];
+      REWRITE_TAC[SUBSET; IN_UNION; IN_INTERVAL_1] THEN REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!c. c IN interval(a,b) /\ ~((f:real^1->real^1) continuous at c)
+        ==> ?q. rational q /\ drop(l c) < q /\ q < drop(r c)`
+  MP_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `drop(l(c:real^1)) < drop(r c)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[]; ALL_TAC] THEN
+    MP_TAC(ISPECL [`(drop(l(c:real^1)) + drop(r c)) / &2`;
+                   `(drop(r c) - drop(l(c:real^1))) / &2`]
+      RATIONAL_APPROXIMATION) THEN
+    ASM_REWRITE_TAC[REAL_HALF; REAL_SUB_LT] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; IN_ELIM_THM; IN_INTERVAL_1] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `q:real^1->real` THEN
+  SIMP_TAC[IN] THEN DISCH_THEN(LABEL_TAC "*") THEN
+  MATCH_MP_TAC(MESON[REAL_LE_TOTAL]
+   `(!x y. P x y ==> P y x) /\ (!x y. drop x <= drop y ==> P x y)
+    ==> !x y. P x y`) THEN
+  CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN
+  REWRITE_TAC[REAL_LE_LT; DROP_EQ] THEN
+  ASM_CASES_TAC `x:real^1 = y` THEN ASM_REWRITE_TAC[] THEN
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `q(x:real^1) < q(y)` MP_TAC THENL
+   [ALL_TAC; ASM_REWRITE_TAC[REAL_LT_REFL]] THEN
+  MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `drop(r(x:real^1))` THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `drop(l(y:real^1))` THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `drop(f(inv(&2) % (x + y):real^1))` THEN
+  CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_CMUL; DROP_ADD] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let HAS_BOUNDED_VARIATION_ABSOLUTELY_INTEGRABLE_DERIVATIVE = prove
+ (`!f:real^1->real^N s a b.
+        COUNTABLE s /\ f continuous_on interval[a,b] /\
+        (!x. x IN interval[a,b] DIFF s ==> f differentiable at x)
+        ==> (f has_bounded_variation_on interval[a,b] <=>
+             (\x. vector_derivative f (at x))
+             absolutely_integrable_on interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION_EQ] THEN
+  REWRITE_TAC[has_bounded_variation_on] THEN
+  MATCH_MP_TAC(TAUT `q /\ (p <=> r) ==> (p <=> q /\ r)`) THEN CONJ_TAC THENL
+   [ASM_CASES_TAC `interval[a:real^1,b] = {}` THEN
+    ASM_REWRITE_TAC[INTEGRABLE_ON_EMPTY] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY_1]) THEN
+    MP_TAC(ISPECL [`f:real^1->real^N`;
+                   `\x. vector_derivative (f:real^1->real^N) (at x)`;
+                   `s:real^1->bool`; `a:real^1`; `b:real^1`]
+      FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG) THEN
+    ASM_MESON_TAC[VECTOR_DERIVATIVE_WORKS; integrable_on;
+                  HAS_VECTOR_DERIVATIVE_AT_WITHIN];
+    MATCH_MP_TAC(MESON[HAS_BOUNDED_SETVARIATION_ON_EQ]
+     `(!a b. ~(interval[a,b] = {}) /\ interval[a,b] SUBSET s
+               ==> f(interval[a,b]) = g(interval[a,b]))
+      ==> (f has_bounded_setvariation_on s <=>
+           g has_bounded_setvariation_on s)`) THEN
+    SIMP_TAC[INTERVAL_UPPERBOUND; INTERVAL_LOWERBOUND;
+             GSYM INTERVAL_NE_EMPTY] THEN
+    MAP_EVERY X_GEN_TAC [`u:real^1`; `v:real^1`] THEN
+    REWRITE_TAC[INTERVAL_NE_EMPTY_1] THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`f:real^1->real^N`;
+                   `\x. vector_derivative (f:real^1->real^N) (at x)`;
+                   `s:real^1->bool`; `u:real^1`; `v:real^1`]
+      FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG) THEN
+    ASM_REWRITE_TAC[GSYM VECTOR_DERIVATIVE_WORKS] THEN
+    ANTS_TAC THENL [ALL_TAC; MESON_TAC[INTEGRAL_UNIQUE]] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; IN_DIFF; SUBSET];
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_VECTOR_DERIVATIVE_AT_WITHIN THEN
+      ASM_SIMP_TAC[GSYM VECTOR_DERIVATIVE_WORKS] THEN ASM SET_TAC[]]]);;
+
+let HAS_BOUNDED_VARIATION_INTEGRABLE_NORM_DERIVATIVE = prove
+ (`!f:real^1->real^N s a b.
+        COUNTABLE s /\ f continuous_on interval[a,b] /\
+        (!x. x IN interval[a,b] DIFF s ==> f differentiable at x)
+        ==> (f has_bounded_variation_on interval[a,b] <=>
+             (\x. lift(norm(vector_derivative f (at x))))
+             integrable_on interval[a,b])`,
+  REPEAT GEN_TAC THEN DISCH_THEN(fun th ->
+    STRIP_ASSUME_TAC th THEN
+    REWRITE_TAC[MATCH_MP HAS_BOUNDED_VARIATION_ABSOLUTELY_INTEGRABLE_DERIVATIVE
+                th]) THEN
+  REWRITE_TAC[absolutely_integrable_on] THEN
+  MATCH_MP_TAC(TAUT `p ==> (p /\ q <=> q)`) THEN
+  ASM_CASES_TAC `interval[a:real^1,b] = {}` THEN
+  ASM_REWRITE_TAC[INTEGRABLE_ON_EMPTY] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY_1]) THEN
+  MP_TAC(ISPECL [`f:real^1->real^N`;
+                 `\x. vector_derivative (f:real^1->real^N) (at x)`;
+                 `s:real^1->bool`; `a:real^1`; `b:real^1`]
+    FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG) THEN
+  ASM_MESON_TAC[VECTOR_DERIVATIVE_WORKS; integrable_on;
+                HAS_VECTOR_DERIVATIVE_AT_WITHIN]);;
+
+let VECTOR_VARIATION_INTEGRAL_NORM_DERIVATIVE = prove
+ (`!f:real^1->real^N s a b.
+        COUNTABLE s /\ f continuous_on interval[a,b] /\
+        (!x. x IN interval[a,b] DIFF s ==> f differentiable at x) /\
+        f has_bounded_variation_on interval[a,b]
+        ==> vector_variation (interval[a,b]) f =
+                drop(integral (interval[a,b])
+                        (\x. lift(norm(vector_derivative f (at x)))))`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`f:real^1->real^N`; `s:real^1->bool`; `a:real^1`; `b:real^1`]
+   HAS_BOUNDED_VARIATION_ABSOLUTELY_INTEGRABLE_DERIVATIVE) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ABSOLUTELY_INTEGRABLE_SET_VARIATION) THEN
+  REWRITE_TAC[vector_variation] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC SET_VARIATION_EQ THEN
+  MAP_EVERY X_GEN_TAC [`u:real^1`; `v:real^1`] THEN
+  SIMP_TAC[INTERVAL_NE_EMPTY_1; INTERVAL_LOWERBOUND_1;
+           INTERVAL_UPPERBOUND_1] THEN
+  STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG THEN
+  EXISTS_TAC `s:real^1->bool` THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ALL_TAC] THEN
+  ASM_MESON_TAC[VECTOR_DERIVATIVE_WORKS; HAS_VECTOR_DERIVATIVE_AT_WITHIN;
+                IN_DIFF; SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Baby Fubini theorems for continuous functions. Will be generalized.       *)
+(* ------------------------------------------------------------------------- *)
+
+let INTEGRAL_PASTECART_CONTINUOUS = prove
+ (`!f:real^(M,N)finite_sum->real^P a b c d.
+        f continuous_on interval[pastecart a c,pastecart b d]
+        ==> integral (interval[pastecart a c,pastecart b d]) f =
+            integral (interval[a,b])
+                     (\x. integral (interval[c,d])
+                                   (\y. f(pastecart x y)))`,
+  let lemma1 = prove
+   (`!(f:real^(M,N)finite_sum->real^P) a b c d x.
+          f continuous_on interval [pastecart a c,pastecart b d] /\
+          x IN interval[a,b]
+          ==> (\y. (f:real^(M,N)finite_sum->real^P) (pastecart x y))
+              integrable_on interval[c,d]`,
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_CONTINUOUS THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_CONST;
+             CONTINUOUS_ON_ID] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      CONTINUOUS_ON_SUBSET)) THEN
+    ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; GSYM PCROSS_INTERVAL; PCROSS;
+                 IN_ELIM_PASTECART_THM]) in
+  let lemma2 = prove
+   (`!(f:real^(M,N)finite_sum->real^P) a b c d.
+      f continuous_on interval [pastecart a c,pastecart b d]
+      ==> (\x. integral (interval [c,d]) (\y. f (pastecart x y))) integrable_on
+          interval [a,b]`,
+    REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] lemma1)) THEN
+    MATCH_MP_TAC INTEGRABLE_CONTINUOUS THEN REWRITE_TAC[continuous_on] THEN
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    ASM_SIMP_TAC[dist; GSYM INTEGRAL_SUB] THEN
+    ASM_CASES_TAC `content(interval[c:real^N,d]) = &0` THENL
+     [ASM_SIMP_TAC[INTEGRAL_NULL; NORM_0] THEN MESON_TAC[REAL_LT_01];
+      ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          COMPACT_UNIFORMLY_CONTINUOUS)) THEN
+    REWRITE_TAC[COMPACT_INTERVAL; uniformly_continuous_on] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM CONTENT_LT_NZ]) THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2 / content(interval[c:real^N,d])`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_HALF; FORALL_PASTECART] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+    REWRITE_TAC[GSYM PCROSS_INTERVAL; PCROSS; dist;
+                IN_ELIM_PASTECART_THM] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `x':real^M` THEN DISCH_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
+    ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN
+     `e / &2 = e / &2 / content(interval[c:real^N,d]) * content(interval[c,d])`
+    SUBST1_TAC THENL
+     [UNDISCH_TAC `&0 < content(interval[c:real^N,d])` THEN
+      CONV_TAC REAL_FIELD;
+      MATCH_MP_TAC HAS_INTEGRAL_BOUND THEN
+      EXISTS_TAC `\y. (f:real^(M,N)finite_sum->real^P) (pastecart x' y) -
+                      (f:real^(M,N)finite_sum->real^P) (pastecart x y)` THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_HALF; REAL_LT_DIV;
+                   GSYM HAS_INTEGRAL_INTEGRAL; INTEGRABLE_SUB; lemma1] THEN
+      REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC REAL_LT_IMP_LE THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_SIMP_TAC[NORM_PASTECART; PASTECART_SUB; VECTOR_SUB_REFL; NORM_0] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      ASM_SIMP_TAC[REAL_ADD_RID; POW_2_SQRT; NORM_POS_LE]]) in
+  let lemma3 = prove
+   (`!f:real^(M,N)finite_sum->real^P e s.
+      &0 < e /\ f continuous_on s
+      ==> operative(/\)
+           (\k. !a b c d.
+                interval[pastecart a c,pastecart b d] SUBSET k /\
+                interval[pastecart a c,pastecart b d] SUBSET s
+                ==> norm(integral (interval[pastecart a c,pastecart b d]) f -
+                         integral (interval[a,b])
+                           (\x. integral (interval[c,d])
+                                    (\y. f(pastecart x y))))
+                    <= e * content(interval[pastecart a c,pastecart b d]))`,
+    REPEAT STRIP_TAC THEN REWRITE_TAC[operative; NEUTRAL_AND] THEN
+    CONJ_TAC THEN MAP_EVERY X_GEN_TAC
+     [`A:real^(M,N)finite_sum`;`B:real^(M,N)finite_sum`] THENL
+     [DISCH_TAC THEN
+      MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`; `c:real^N`; `d:real^N`] THEN
+      DISCH_TAC THEN
+      SUBGOAL_THEN
+       `content(interval[pastecart (a:real^M) (c:real^N),pastecart b d]) = &0`
+       (fun th -> ASSUME_TAC th THEN MP_TAC th)
+      THENL [ASM_MESON_TAC[CONTENT_0_SUBSET]; ALL_TAC] THEN
+      REWRITE_TAC[CONTENT_PASTECART; REAL_ENTIRE] THEN STRIP_TAC THEN
+      ASM_SIMP_TAC[INTEGRAL_NULL; REAL_MUL_LZERO; REAL_MUL_RZERO;
+                   VECTOR_SUB_REFL; NORM_0; REAL_LE_REFL; INTEGRAL_0];
+      MAP_EVERY X_GEN_TAC [`l:real`; `k:num`] THEN STRIP_TAC THEN EQ_TAC THENL
+       [REWRITE_TAC[AND_FORALL_THM] THEN
+        REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+        MATCH_MP_TAC(TAUT
+         `(P1 ==> P) /\ (P2 ==> P)
+          ==> (P ==> Q) ==> (P1 ==> Q) /\ (P2 ==> Q)`) THEN
+        SET_TAC[];
+        DISCH_TAC]] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`; `c:real^N`; `d:real^N`] THEN
+    STRIP_TAC THEN RULE_ASSUM_TAC(REWRITE_RULE[DIMINDEX_FINITE_SUM]) THEN
+    ASM_CASES_TAC `k <= dimindex(:M)` THENL
+     [FIRST_X_ASSUM(CONJUNCTS_THEN2
+       (MP_TAC o SPECL
+         [`a:real^M`;
+          `(lambda i. if i = k then min (b$k) l else (b:real^M)$i):real^M`;
+          `c:real^N`; `d:real^N`])
+       (MP_TAC o SPECL
+         [`(lambda i. if i = k then max (a$k) l else (a:real^M)$i):real^M`;
+          `b:real^M`; `c:real^N`; `d:real^N`])) THEN
+      ASM_SIMP_TAC[GSYM INTERVAL_SPLIT; GSYM PCROSS_INTERVAL; PCROSS] THEN
+      SUBGOAL_THEN
+       `!P Q. { pastecart (x:real^M) (y:real^N) |
+                x IN interval[a,b] INTER {x | P (x$k)} /\ Q y} =
+              {pastecart x y | x IN interval[a,b] /\ Q y} INTER {x | P (x$k)}`
+       (fun th -> REWRITE_TAC[th])
+      THENL
+       [REWRITE_TAC[EXTENSION; FORALL_PASTECART; IN_ELIM_PASTECART_THM;
+                    IN_INTER] THEN
+        ASM_SIMP_TAC[pastecart; IN_ELIM_THM; LAMBDA_BETA; DIMINDEX_FINITE_SUM;
+                     ARITH_RULE `i:num <= m ==> i <= m + n`] THEN
+        MESON_TAC[];
+        ALL_TAC] THEN
+      REWRITE_TAC[REWRITE_RULE[PCROSS] PCROSS_INTERVAL] THEN
+      ASM_SIMP_TAC[SET_RULE `s SUBSET t ==> s INTER u SUBSET t INTER u`] THEN
+      ASM_SIMP_TAC[SET_RULE `s SUBSET t ==> s INTER u SUBSET t`] THEN
+      MATCH_MP_TAC(NORM_ARITH
+       `y = y1 + y2 /\ x = x1 + x2 /\ e = e1 + e2
+        ==> norm(y2 - x2:real^N) <= e2 ==> norm(y1 - x1) <= e1
+            ==> norm(y - x) <= e`) THEN
+      REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC(SIMP_RULE[GSYM INTERVAL_SPLIT] INTEGRAL_SPLIT) THEN
+        ASM_SIMP_TAC[DIMINDEX_FINITE_SUM;
+                     ARITH_RULE `i:num <= m ==> i <= m + n`] THEN
+        ASM_MESON_TAC[INTEGRABLE_CONTINUOUS; CONTINUOUS_ON_SUBSET];
+        MATCH_MP_TAC(SIMP_RULE[GSYM INTERVAL_SPLIT] INTEGRAL_SPLIT) THEN
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC lemma2 THEN
+        ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+        REWRITE_TAC[GSYM REAL_ADD_LDISTRIB] THEN AP_TERM_TAC THEN
+        MATCH_MP_TAC CONTENT_SPLIT THEN
+        ASM_REWRITE_TAC[DIMINDEX_FINITE_SUM]];
+      FIRST_X_ASSUM(CONJUNCTS_THEN2
+       (MP_TAC o SPECL
+         [`a:real^M`; `b:real^M`; `c:real^N`;
+          `(lambda i. if i = k - dimindex(:M)
+                      then min (d$(k - dimindex(:M))) l
+                      else (d:real^N)$i):real^N`])
+       (MP_TAC o SPECL
+         [`a:real^M`; `b:real^M`;
+          `(lambda i. if i = k - dimindex(:M)
+                      then max (c$(k - dimindex(:M))) l
+                      else (c:real^N)$i):real^N`;
+          `d:real^N`])) THEN
+      ASM_SIMP_TAC[GSYM INTERVAL_SPLIT; GSYM PCROSS_INTERVAL; PCROSS;
+                ARITH_RULE `~(i <= m) ==> 1 <= i - m`;
+                ARITH_RULE `~(i <= m) /\ i:num <= m + n ==> i - m <= n`] THEN
+      SUBGOAL_THEN
+       `!P Q. { pastecart (x:real^M) (y:real^N) |
+              P x /\ y IN interval[c,d] INTER {y | Q (y$(k - dimindex(:M)))}} =
+              {pastecart x y | P x /\ y IN interval[c,d]} INTER
+              {x | Q (x$k)}`
+       (fun th -> REWRITE_TAC[th])
+      THENL
+       [REWRITE_TAC[EXTENSION; FORALL_PASTECART; IN_ELIM_PASTECART_THM;
+                    IN_INTER] THEN
+        ASM_SIMP_TAC[pastecart; IN_ELIM_THM; LAMBDA_BETA;
+                     DIMINDEX_FINITE_SUM] THEN
+        MESON_TAC[];
+        ALL_TAC] THEN
+      REWRITE_TAC[REWRITE_RULE[PCROSS] PCROSS_INTERVAL] THEN
+      ASM_SIMP_TAC[SET_RULE `s SUBSET t ==> s INTER u SUBSET t INTER u`] THEN
+      ASM_SIMP_TAC[SET_RULE `s SUBSET t ==> s INTER u SUBSET t`] THEN
+      MATCH_MP_TAC(NORM_ARITH
+       `y = y1 + y2 /\ x = x1 + x2 /\ e = e1 + e2
+        ==> norm(y2 - x2:real^N) <= e2 ==> norm(y1 - x1) <= e1
+            ==> norm(y - x) <= e`) THEN
+      REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC(SIMP_RULE[GSYM INTERVAL_SPLIT] INTEGRAL_SPLIT) THEN
+        ASM_SIMP_TAC[DIMINDEX_FINITE_SUM;
+                     ARITH_RULE `i:num <= m ==> i <= m + n`] THEN
+        ASM_MESON_TAC[INTEGRABLE_CONTINUOUS; CONTINUOUS_ON_SUBSET];
+        W(MP_TAC o PART_MATCH (rand o rand) INTEGRAL_ADD o rand o snd) THEN
+        REWRITE_TAC[] THEN ANTS_TAC THENL
+         [ASM_SIMP_TAC[INTERVAL_SPLIT; DIMINDEX_FINITE_SUM;
+                 ARITH_RULE `~(i <= m) ==> 1 <= i - m`;
+                 ARITH_RULE `~(i <= m) /\ i:num <= m + n ==> i - m <= n`] THEN
+          CONJ_TAC THEN MATCH_MP_TAC lemma2 THEN
+          MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+          EXISTS_TAC `s:real^(M,N)finite_sum->bool` THEN
+          ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MATCH_MP_TAC o
+             MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] SUBSET_TRANS)) THEN
+          REWRITE_TAC[SUBSET_INTERVAL] THEN DISCH_THEN(K ALL_TAC) THEN
+          ASM_SIMP_TAC[pastecart; LAMBDA_BETA; DIMINDEX_FINITE_SUM;
+                  ARITH_RULE `~(i <= m) ==> 1 <= i - m`;
+                  ARITH_RULE `~(i <= m) /\ i:num <= m + n ==> i - m <= n`] THEN
+          REPEAT STRIP_TAC THEN
+          REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_LE_REFL]) THEN
+          REAL_ARITH_TAC;
+          DISCH_THEN(SUBST1_TAC o SYM) THEN MATCH_MP_TAC INTEGRAL_EQ THEN
+          X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+          MATCH_MP_TAC(SIMP_RULE[GSYM INTERVAL_SPLIT] INTEGRAL_SPLIT) THEN
+          CONJ_TAC THENL [ALL_TAC; ASM_ARITH_TAC] THEN
+          MATCH_MP_TAC lemma1 THEN ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]];
+        REWRITE_TAC[GSYM REAL_ADD_LDISTRIB] THEN AP_TERM_TAC THEN
+        MATCH_MP_TAC CONTENT_SPLIT THEN
+        ASM_REWRITE_TAC[DIMINDEX_FINITE_SUM]]]) in
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC
+   `content(interval[pastecart(a:real^M) (c:real^N),pastecart b d]) = &0` THEN
+  ASM_SIMP_TAC[INTEGRAL_NULL] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[CONTENT_PASTECART]) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[REAL_ENTIRE; DE_MORGAN_THM]) THENL
+   [FIRST_X_ASSUM DISJ_CASES_TAC THEN
+    ASM_SIMP_TAC[INTEGRAL_NULL; INTEGRAL_0];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `&0 < content(interval[pastecart(a:real^M) (c:real^N),pastecart b d])`
+  ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[CONTENT_LT_NZ; CONTENT_PASTECART; REAL_ENTIRE];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+  ONCE_REWRITE_TAC[GSYM NORM_EQ_0] THEN
+  MATCH_MP_TAC(MESON[REAL_ARITH
+   `~(x = &0) ==> &0 < abs x / &2 /\ ~(abs x <= abs x / &2)`]
+   `(!e. &0 < e ==> abs x <= e) ==> x = &0`) THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN REWRITE_TAC[REAL_ABS_NORM] THEN
+  MP_TAC(ISPECL
+   [`f:real^(M,N)finite_sum->real^P`;
+    `e / content(interval[pastecart(a:real^M) (c:real^N),pastecart b d])`;
+    `interval[pastecart(a:real^M) (c:real^N),pastecart b d]`]
+   lemma3) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV] THEN DISCH_THEN(MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] OPERATIVE_DIVISION_AND)) THEN
+  REWRITE_TAC[] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    COMPACT_UNIFORMLY_CONTINUOUS)) THEN
+  REWRITE_TAC[COMPACT_INTERVAL; uniformly_continuous_on] THEN
+  DISCH_THEN(MP_TAC o SPEC
+    `e / &2 /
+     content(interval[pastecart(a:real^M) (c:real^N),pastecart b d])`) THEN
+  ASM_SIMP_TAC[dist; REAL_HALF; REAL_LT_DIV] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `?p. p tagged_division_of
+        interval[pastecart(a:real^M) (c:real^N),pastecart b d] /\
+        (\x. ball(x,k)) fine p`
+  STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[FINE_DIVISION_EXISTS; GAUGE_BALL]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC
+  `IMAGE SND (p:real^(M,N)finite_sum#(real^(M,N)finite_sum->bool)->bool)`) THEN
+  DISCH_THEN(MP_TAC o SPECL
+   [`pastecart(a:real^M) (c:real^N)`; `pastecart(b:real^M) (d:real^N)`]) THEN
+  ASM_SIMP_TAC[DIVISION_OF_TAGGED_DIVISION] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM] THEN
+  MATCH_MP_TAC(TAUT `(b ==> c) /\ a ==> (a <=> b) ==> c`) THEN CONJ_TAC THENL
+   [DISCH_THEN(MP_TAC o SPECL
+     [`a:real^M`; `b:real^M`; `c:real^N`; `d:real^N`]) THEN
+    ASM_SIMP_TAC[REAL_DIV_RMUL; REAL_LT_IMP_NZ; SUBSET_REFL];
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC
+   [`t:real^(M,N)finite_sum`; `l:real^(M,N)finite_sum->bool`] THEN
+  DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [TAGGED_DIVISION_OF]) THEN
+  DISCH_THEN(MP_TAC o SPECL
+    [`t:real^(M,N)finite_sum`; `l:real^(M,N)finite_sum->bool`] o
+     el 1 o CONJUNCTS) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^M`; `v:real^M`; `w:real^N`; `z:real^N`] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
+  REWRITE_TAC[SUBSET; IN_BALL; dist] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL
+   [`u:real^M`; `v:real^M`; `w:real^N`; `z:real^N`;
+    `(f:real^(M,N)finite_sum->real^P) t`]
+   INTEGRAL_PASTECART_CONST) THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `norm(x - x') <= e / &2 /\ norm(y - y') <= e / &2
+    ==> x':real^P = y' ==> norm(x - y) <= e`) THEN
+  REWRITE_TAC[REAL_ARITH `(e / c * d) / &2 = e / &2 / c * d`] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC HAS_INTEGRAL_BOUND THEN
+    EXISTS_TAC `\y. (f:real^(M,N)finite_sum->real^P) y - f t` THEN
+    ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; REAL_LT_IMP_LE] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HAS_INTEGRAL_SUB THEN
+      REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL; INTEGRABLE_CONST] THEN
+      ASM_MESON_TAC[INTEGRABLE_CONTINUOUS; INTEGRABLE_ON_SUBINTERVAL];
+      X_GEN_TAC `y:real^(M,N)finite_sum` THEN DISCH_TAC THEN
+      MATCH_MP_TAC REAL_LT_IMP_LE THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      MATCH_MP_TAC(TAUT `(a /\ b) /\ (a /\ b ==> c) ==> a /\ b /\ c`) THEN
+      CONJ_TAC THENL [ASM SET_TAC[]; ASM_MESON_TAC[NORM_SUB; SUBSET]]];
+    GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [CONTENT_PASTECART] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `a * b * c:real = (a * c) * b`] THEN
+    MATCH_MP_TAC HAS_INTEGRAL_BOUND THEN EXISTS_TAC
+     `\x. integral (interval [w,z]) (\y. f (pastecart x y)) -
+           integral (interval [w,z])
+                    (\y. (f:real^(M,N)finite_sum->real^P) t)` THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_LE_MUL THEN REWRITE_TAC[CONTENT_POS_LE] THEN
+      ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; REAL_LT_IMP_LE];
+      MATCH_MP_TAC HAS_INTEGRAL_SUB THEN
+      REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL; INTEGRABLE_CONST] THEN
+      MATCH_MP_TAC lemma2 THEN ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+      X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+      MATCH_MP_TAC HAS_INTEGRAL_BOUND THEN EXISTS_TAC
+       `\y. (f:real^(M,N)finite_sum->real^P) (pastecart x y) - f t` THEN
+      ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; REAL_LT_IMP_LE] THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC HAS_INTEGRAL_SUB THEN
+        REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL; INTEGRABLE_CONST] THEN
+        MATCH_MP_TAC lemma1 THEN ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET];
+        X_GEN_TAC `s:real^N` THEN DISCH_TAC THEN
+        MATCH_MP_TAC REAL_LT_IMP_LE THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+        REPEAT CONJ_TAC THENL
+         [ASM SET_TAC[];
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+           `s SUBSET t ==> x IN s ==> x IN t`)) THEN
+          ASM_REWRITE_TAC[GSYM PCROSS_INTERVAL; PCROSS;
+                          IN_ELIM_PASTECART_THM];
+          RULE_ASSUM_TAC(REWRITE_RULE[IMP_IMP; RIGHT_IMP_FORALL_THM]) THEN
+          ONCE_REWRITE_TAC[NORM_SUB] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+          EXISTS_TAC `l:real^(M,N)finite_sum->bool` THEN
+          ASM_REWRITE_TAC[] THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+           `s SUBSET t ==> x IN s ==> x IN t`)) THEN
+          ASM_REWRITE_TAC[GSYM PCROSS_INTERVAL; PCROSS;
+                          IN_ELIM_PASTECART_THM]]]]]);;
+
+let INTEGRAL_SWAP_CONTINUOUS = prove
+ (`!f:real^M->real^N->real^P a b c d.
+        (\z. f (fstcart z) (sndcart z))
+        continuous_on interval[pastecart a c,pastecart b d]
+        ==> integral (interval[a,b]) (\x. integral (interval[c,d]) (f x)) =
+            integral (interval[c,d])
+                     (\y. integral (interval[a,b]) (\x. f x y))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\z. (f:real^M->real^N->real^P) (fstcart z) (sndcart z)`;
+   `a:real^M`; `b:real^M`; `c:real^N`; `d:real^N`]
+   INTEGRAL_PASTECART_CONTINUOUS) THEN
+  ASM_REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; ETA_AX] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  MP_TAC(ISPECL [`\z. (f:real^M->real^N->real^P) (sndcart z) (fstcart z)`;
+   `c:real^N`; `d:real^N`; `a:real^M`; `b:real^M`]
+   INTEGRAL_PASTECART_CONTINUOUS) THEN
+  ASM_REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN ANTS_TAC THENL
+   [SUBGOAL_THEN
+     `(\z. (f:real^M->real^N->real^P) (sndcart z) (fstcart z)) =
+      (\z. (f:real^M->real^N->real^P) (fstcart z) (sndcart z)) o
+      (\z. pastecart (sndcart z) (fstcart z))`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[o_DEF; FSTCART_PASTECART; SNDCART_PASTECART];
+      ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_PASTECART; LINEAR_CONTINUOUS_ON;
+             LINEAR_FSTCART; LINEAR_SNDCART] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      CONTINUOUS_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; PCROSS; GSYM PCROSS_INTERVAL] THEN
+    REWRITE_TAC[FORALL_IN_GSPEC; IN_ELIM_PASTECART_THM] THEN
+    SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART];
+    DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  MP_TAC(ISPECL
+   [`\z. (f:real^M->real^N->real^P) (fstcart z) (sndcart z)`;
+    `\z:real^(N,M)finite_sum. pastecart (sndcart z) (fstcart z)`;
+    `\z:real^(M,N)finite_sum. pastecart (sndcart z) (fstcart z)`;
+    `&1`;
+    `integral (interval[pastecart a c,pastecart b d])
+              (\z. (f:real^M->real^N->real^P) (fstcart z) (sndcart z))`;
+    `pastecart (a:real^M) (c:real^N)`;
+    `pastecart (b:real^M) (d:real^N)`]
+  HAS_INTEGRAL_TWIDDLE) THEN
+  REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; REAL_INV_1; REAL_LT_01;
+              PASTECART_FST_SND; VECTOR_MUL_LID; REAL_MUL_LID] THEN
+  ASM_SIMP_TAC[GSYM HAS_INTEGRAL_INTEGRAL; INTEGRABLE_CONTINUOUS] THEN
+  REWRITE_TAC[GSYM SIMPLE_IMAGE; FORALL_PASTECART; EXISTS_PASTECART;
+              FSTCART_PASTECART; SNDCART_PASTECART; PCROSS;
+              GSYM PCROSS_INTERVAL; IN_ELIM_PASTECART_THM] THEN
+  REWRITE_TAC[REWRITE_RULE[PCROSS] PCROSS_INTERVAL] THEN
+  CONV_TAC(ONCE_DEPTH_CONV
+   (fun t -> if fst(dest_const(fst(strip_comb
+                (snd(dest_exists(snd(dest_exists t))))))) = "SETSPEC"
+             then REWR_CONV SWAP_EXISTS_THM t else NO_CONV t)) THEN
+  ONCE_REWRITE_TAC[SET_RULE
+   `{pastecart (y:real^M) (x:real^N) | p x /\ q y} =
+    {pastecart x y | q x /\ p y}`] THEN
+  REWRITE_TAC[REWRITE_RULE[PCROSS] PCROSS_INTERVAL] THEN
+  DISCH_THEN MATCH_MP_TAC  THEN
+  SIMP_TAC[CONTINUOUS_PASTECART; LINEAR_CONTINUOUS_AT;
+             LINEAR_FSTCART; LINEAR_SNDCART] THEN
+  REWRITE_TAC[CONTENT_PASTECART] THEN
+  REWRITE_TAC[REAL_MUL_SYM] THEN MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Rectifiable paths and path length defined using variation.                *)
+(* ------------------------------------------------------------------------- *)
+
+let rectifiable_path = new_definition
+ `rectifiable_path (g:real^1->real^N) <=>
+    path g /\ g has_bounded_variation_on interval[vec 0,vec 1]`;;
+
+let path_length = new_definition
+ `path_length (g:real^1->real^N) =
+  vector_variation (interval[vec 0,vec 1]) g`;;
+
+let BOUNDED_RECTIFIABLE_PATH_IMAGE = prove
+ (`!g:real^1->real^N. rectifiable_path g ==> bounded(path_image g)`,
+  SIMP_TAC[rectifiable_path; BOUNDED_PATH_IMAGE]);;
+
+let RECTIFIABLE_PATH_IMP_PATH = prove
+ (`!g:real^1->real^N. rectifiable_path g ==> path g`,
+  SIMP_TAC[rectifiable_path]);;
+
+let RECTIFIABLE_PATH_LINEPATH = prove
+ (`!a b:real^N. rectifiable_path(linepath(a,b))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[rectifiable_path; PATH_LINEPATH] THEN
+  REWRITE_TAC[linepath] THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_ADD THEN
+  REWRITE_TAC[GSYM DROP_VEC; GSYM DROP_SUB] THEN
+  CONJ_TAC THEN MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_MUL THEN
+  REWRITE_TAC[HAS_BOUNDED_VARIATION_ON_CONST] THEN
+  REWRITE_TAC[HAS_BOUNDED_VARIATION_ON_ID] THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_SUB THEN
+  REWRITE_TAC[HAS_BOUNDED_VARIATION_ON_CONST] THEN
+  REWRITE_TAC[HAS_BOUNDED_VARIATION_ON_ID]);;
+
+let RECTIFIABLE_PATH_REVERSEPATH = prove
+ (`!g:real^1->real^N. rectifiable_path(reversepath g) <=> rectifiable_path g`,
+  SUBGOAL_THEN
+   `!g:real^1->real^N. rectifiable_path g ==> rectifiable_path(reversepath g)`
+   (fun th -> MESON_TAC[th; REVERSEPATH_REVERSEPATH]) THEN
+  GEN_TAC THEN REWRITE_TAC[rectifiable_path] THEN
+  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[PATH_REVERSEPATH] THEN
+  REWRITE_TAC[reversepath] THEN DISCH_TAC THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_COMPOSE_DECREASING THEN
+  ASM_REWRITE_TAC[DROP_SUB; VECTOR_SUB_RZERO; VECTOR_SUB_REFL] THEN
+  REAL_ARITH_TAC);;
+
+let PATH_LENGTH_REVERSEPATH = prove
+ (`!g:real^1->real^N. path_length(reversepath g) = path_length g`,
+  GEN_TAC THEN REWRITE_TAC[path_length; reversepath] THEN
+  REWRITE_TAC[VECTOR_SUB; VECTOR_VARIATION_REFLECT] THEN
+  REWRITE_TAC[VECTOR_VARIATION_TRANSLATION] THEN
+  REWRITE_TAC[REFLECT_INTERVAL; GSYM INTERVAL_TRANSLATION] THEN
+  REWRITE_TAC[GSYM VECTOR_SUB; VECTOR_SUB_REFL; VECTOR_SUB_RZERO]);;
+
+let RECTIFIABLE_PATH_SUBPATH = prove
+ (`!u v g:real^1->real^N.
+        rectifiable_path g /\
+        u IN interval[vec 0,vec 1] /\
+        v IN interval[vec 0,vec 1]
+        ==> rectifiable_path(subpath u v g)`,
+  REPEAT GEN_TAC THEN SIMP_TAC[PATH_SUBPATH; rectifiable_path] THEN
+  STRIP_TAC THEN REWRITE_TAC[subpath] THEN
+  ONCE_REWRITE_TAC[VECTOR_ADD_SYM] THEN
+  REWRITE_TAC[HAS_BOUNDED_VARIATION_AFFINITY_EQ; IMAGE_AFFINITY_INTERVAL] THEN
+  REWRITE_TAC[UNIT_INTERVAL_NONEMPTY; DROP_SUB; REAL_SUB_LE; REAL_SUB_0] THEN
+  DISJ2_TAC THEN COND_CASES_TAC THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        HAS_BOUNDED_VARIATION_ON_SUBSET)) THEN
+  REWRITE_TAC[SUBSET_INTERVAL_1] THEN
+  REWRITE_TAC[DROP_ADD; DROP_CMUL; DROP_VEC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+  ASM_REAL_ARITH_TAC);;
+
+let RECTIFIABLE_PATH_JOIN = prove
+ (`!g1 g2:real^1->real^N.
+        pathfinish g1 = pathstart g2
+        ==> (rectifiable_path(g1 ++ g2) <=>
+             rectifiable_path g1 /\ rectifiable_path g2)`,
+  REPEAT GEN_TAC THEN SIMP_TAC[rectifiable_path; PATH_JOIN] THEN
+  REWRITE_TAC[pathfinish; pathstart] THEN DISCH_TAC THEN
+  ASM_CASES_TAC `path(g1:real^1->real^N)` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `path(g2:real^1->real^N)` THEN ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPECL [`g1 ++ g2:real^1->real^N`; `vec 0:real^1`; `vec 1:real^1`;
+                 `lift(&1 / &2)`]
+        HAS_BOUNDED_VARIATION_ON_COMBINE) THEN
+  REWRITE_TAC[DROP_VEC; LIFT_DROP] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[joinpaths] THEN BINOP_TAC THEN
+  MATCH_MP_TAC EQ_TRANS THENL
+   [EXISTS_TAC
+     `(\x. (g1:real^1->real^N)(&2 % x)) has_bounded_variation_on
+      interval [vec 0,lift(&1 / &2)]` THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH `&2 % x:real^N = &2 % x + vec 0`];
+    EXISTS_TAC
+     `(\x. (g2:real^1->real^N)(&2 % x - vec 1)) has_bounded_variation_on
+      interval [lift (&1 / &2),vec 1]` THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH `&2 % x - v:real^N = &2 % x + --v`]] THEN
+  (CONJ_TAC THENL
+    [ALL_TAC;
+     REWRITE_TAC[HAS_BOUNDED_VARIATION_AFFINITY_EQ] THEN
+     REWRITE_TAC[IMAGE_AFFINITY_INTERVAL; INTERVAL_EQ_EMPTY_1] THEN
+     REWRITE_TAC[DROP_VEC; LIFT_DROP] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+     AP_TERM_TAC THEN AP_TERM_TAC THEN
+     REWRITE_TAC[CONS_11; PAIR_EQ; GSYM DROP_EQ] THEN
+     REWRITE_TAC[DROP_ADD; DROP_CMUL; LIFT_DROP; DROP_VEC; DROP_NEG] THEN
+     REAL_ARITH_TAC]) THEN
+  MATCH_MP_TAC(MESON[HAS_BOUNDED_VARIATION_ON_EQ]
+   `(!x. x IN s ==> f x = g x)
+    ==> (f has_bounded_variation_on s <=>
+         g has_bounded_variation_on s)`) THEN
+  SIMP_TAC[IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN X_GEN_TAC `x:real^1` THEN
+  COND_CASES_TAC THEN REWRITE_TAC[] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `&2 % x + --vec 1:real^1 = vec 0 /\ &2 % x = vec 1`
+    (fun th -> ASM_REWRITE_TAC[th]) THEN
+  REWRITE_TAC[VECTOR_SUB_EQ; GSYM VECTOR_SUB] THEN
+  REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; DROP_VEC] THEN ASM_REAL_ARITH_TAC);;
+
+let RECTIFIABLE_PATH_JOIN_IMP = prove
+ (`!g1 g2:real^1->real^N.
+        rectifiable_path g1 /\ rectifiable_path g2 /\
+        pathfinish g1 = pathstart g2
+        ==> rectifiable_path(g1 ++ g2)`,
+  SIMP_TAC[RECTIFIABLE_PATH_JOIN]);;
+
+let RECTIFIABLE_PATH_JOIN_EQ = prove
+ (`!g1 g2:real^1->real^N.
+        rectifiable_path g1 /\ rectifiable_path g2
+        ==> (rectifiable_path (g1 ++ g2) <=> pathfinish g1 = pathstart g2)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  ASM_SIMP_TAC[RECTIFIABLE_PATH_JOIN_IMP] THEN
+  DISCH_TAC THEN MATCH_MP_TAC PATH_JOIN_PATH_ENDS THEN
+  ASM_SIMP_TAC[RECTIFIABLE_PATH_IMP_PATH]);;
+
+let PATH_LENGTH_JOIN = prove
+ (`!g1 g2:real^1->real^N.
+        rectifiable_path g1 /\ rectifiable_path g2 /\
+        pathfinish g1 = pathstart g2
+        ==> path_length(g1 ++ g2) = path_length g1 + path_length g2`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[path_length] THEN
+  MP_TAC(ISPECL [`g1 ++ g2:real^1->real^N`; `vec 0:real^1`; `vec 1:real^1`;
+                 `lift(&1 / &2)`]
+        VECTOR_VARIATION_COMBINE) THEN
+  REWRITE_TAC[DROP_VEC; LIFT_DROP] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[rectifiable_path; RECTIFIABLE_PATH_JOIN_IMP];
+    DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `vector_variation (interval [vec 0,lift (&1 / &2)])
+                     (\x. (g1:real^1->real^N)(&2 % x)) +
+    vector_variation (interval [lift (&1 / &2),vec 1])
+                     (\x.  (g2:real^1->real^N)(&2 % x - vec 1))` THEN
+  CONJ_TAC THENL
+   [BINOP_TAC THEN MATCH_MP_TAC VECTOR_VARIATION_EQ THEN
+    SIMP_TAC[IN_INTERVAL_1; LIFT_DROP; DROP_VEC; joinpaths] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[pathfinish; pathstart]) THEN
+    X_GEN_TAC `x:real^1` THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+    COND_CASES_TAC THEN REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `&2 % x - vec 1:real^1 = vec 0 /\ &2 % x = vec 1`
+     (fun th -> ASM_REWRITE_TAC[th]) THEN
+    REWRITE_TAC[VECTOR_SUB_EQ] THEN
+    REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; DROP_VEC] THEN ASM_REAL_ARITH_TAC;
+    ONCE_REWRITE_TAC[VECTOR_ARITH `&2 % x:real^N = &2 % x + vec 0`] THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+     `(&2 % x + vec 0) - v:real^N = &2 % x + --v`] THEN
+    REWRITE_TAC[VECTOR_VARIATION_AFFINITY; IMAGE_AFFINITY_INTERVAL] THEN
+    REWRITE_TAC[INTERVAL_EQ_EMPTY_1; LIFT_DROP; DROP_VEC] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN BINOP_TAC THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    REWRITE_TAC[CONS_11; PAIR_EQ; GSYM DROP_EQ] THEN
+    REWRITE_TAC[DROP_ADD; DROP_CMUL; LIFT_DROP; DROP_VEC; DROP_NEG] THEN
+    REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Useful equivalent formulations where the path is differentiable.          *)
+(* ------------------------------------------------------------------------- *)
+
+let RECTIFIABLE_PATH_DIFFERENTIABLE = prove
+ (`!g:real^1->real^N s.
+        COUNTABLE s /\ path g /\
+        (!t. t IN interval[vec 0,vec 1] DIFF s ==> g differentiable at t)
+        ==> (rectifiable_path g <=>
+                (\t. vector_derivative g (at t))
+                absolutely_integrable_on interval[vec 0,vec 1])`,
+  SIMP_TAC[rectifiable_path] THEN REWRITE_TAC[path] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC
+    HAS_BOUNDED_VARIATION_ABSOLUTELY_INTEGRABLE_DERIVATIVE THEN
+  EXISTS_TAC `s:real^1->bool` THEN ASM_REWRITE_TAC[]);;
+
+let PATH_LENGTH_DIFFERENTIABLE = prove
+ (`!g:real^1->real^N s.
+        COUNTABLE s /\ rectifiable_path g /\
+        (!t. t IN interval[vec 0,vec 1] DIFF s ==> g differentiable at t)
+        ==> path_length g =
+                drop(integral (interval[vec 0,vec 1])
+                              (\t. lift(norm(vector_derivative g (at t)))))`,
+  REWRITE_TAC[rectifiable_path; path_length; path] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC VECTOR_VARIATION_INTEGRAL_NORM_DERIVATIVE THEN
+  EXISTS_TAC `s:real^1->bool` THEN ASM_REWRITE_TAC[]);;
diff --git a/Multivariate/make_complex.ml b/Multivariate/make_complex.ml
new file mode 100644 (file)
index 0000000..4d90065
--- /dev/null
@@ -0,0 +1,48 @@
+(* ========================================================================= *)
+(* Theory of multivariate calculus in Euclidean space.                       *)
+(* ========================================================================= *)
+
+loadt "Library/card.ml";;               (* For countable set theorems.      *)
+loadt "Library/permutations.ml";;       (* For determinants                 *)
+loadt "Library/products.ml";;           (* For determinants and integrals   *)
+loadt "Library/floor.ml";;              (* Useful here and there            *)
+loadt "Multivariate/misc.ml";;          (* Background stuff                 *)
+loadt "Library/binomial.ml";;           (* For Leibniz deriv formula etc.   *)
+loadt "Library/iter.ml";;               (* n-fold iteration of function     *)
+
+(* ------------------------------------------------------------------------- *)
+(* The main core theory.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+loadt "Multivariate/vectors.ml";;       (* Basic vectors, linear algebra    *)
+loadt "Multivariate/determinants.ml";;  (* Determinant and trace            *)
+loadt "Multivariate/topology.ml";;      (* Basic topological notions        *)
+loadt "Multivariate/convex.ml";;        (* Convex sets and functions        *)
+loadt "Multivariate/paths.ml";;         (* Paths, simple connectedness etc. *)
+loadt "Multivariate/polytope.ml";;      (* Faces, polytopes, polyhedra etc. *)
+loadt "Multivariate/dimension.ml";;     (* Dimensional theorems             *)
+loadt "Multivariate/derivatives.ml";;   (* Derivatives                      *)
+
+(* ------------------------------------------------------------------------- *)
+(* Work in progress.                                                         *)
+(* ------------------------------------------------------------------------- *)
+
+loadt "Multivariate/clifford.ml";;      (* Geometric (Clifford) algebra     *)
+loadt "Multivariate/integration.ml";;   (* Integration                      *)
+loadt "Multivariate/measure.ml";;       (* Lebesgue measure                 *)
+
+(* ------------------------------------------------------------------------- *)
+(* Complex numbers (as R^2) and complex analysis.                            *)
+(* ------------------------------------------------------------------------- *)
+
+loadt "Multivariate/complexes.ml";;       (* Complex numbers                *)
+loadt "Multivariate/canal.ml";;           (* Complex analysis               *)
+loadt "Multivariate/transcendentals.ml";; (* Real & complex transcendentals *)
+loadt "Multivariate/realanalysis.ml";;    (* Some analytical stuff on R     *)
+loadt "Multivariate/cauchy.ml";;          (* Complex line integrals         *)
+
+(* ------------------------------------------------------------------------- *)
+(* Updated database, for convenience where dynamic updating doesn't work.    *)
+(* ------------------------------------------------------------------------- *)
+
+loadt "Multivariate/complex_database.ml";;
diff --git a/Multivariate/measure.ml b/Multivariate/measure.ml
new file mode 100644 (file)
index 0000000..d2a685b
--- /dev/null
@@ -0,0 +1,9716 @@
+(* ========================================================================= *)
+(* Lebsegue measure, measurable functions (defined via the gauge integral).  *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(* ========================================================================= *)
+
+needs "Library/card.ml";;
+needs "Library/permutations.ml";;
+needs "Multivariate/integration.ml";;
+needs "Multivariate/determinants.ml";;
+prioritize_real();;
+
+(* ------------------------------------------------------------------------- *)
+(* Lebesgue measure in the case where the measure is finite. This is our     *)
+(* default notion of "measurable", but we also define "lebesgue_measurable"  *)
+(* further down. Note that in neither case do we assume the set is bounded.  *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("has_measure",(12,"right"));;
+
+let has_measure = new_definition
+ `s has_measure m <=> ((\x. vec 1) has_integral (lift m)) s`;;
+
+let measurable = new_definition
+ `measurable s <=> ?m. s has_measure m`;;
+
+let measure = new_definition
+ `measure s = @m. s has_measure m`;;
+
+let HAS_MEASURE_MEASURE = prove
+ (`!s. measurable s <=> s has_measure (measure s)`,
+  REWRITE_TAC[measure; measurable] THEN MESON_TAC[]);;
+
+let HAS_MEASURE_UNIQUE = prove
+ (`!s m1 m2. s has_measure m1 /\ s has_measure m2 ==> m1 = m2`,
+  REWRITE_TAC[has_measure; GSYM LIFT_EQ] THEN MESON_TAC[HAS_INTEGRAL_UNIQUE]);;
+
+let MEASURE_UNIQUE = prove
+ (`!s m. s has_measure m ==> measure s = m`,
+  MESON_TAC[HAS_MEASURE_UNIQUE; HAS_MEASURE_MEASURE; measurable]);;
+
+let HAS_MEASURE_MEASURABLE_MEASURE = prove
+ (`!s m. s has_measure m <=> measurable s /\ measure s = m`,
+  REWRITE_TAC[HAS_MEASURE_MEASURE] THEN MESON_TAC[MEASURE_UNIQUE]);;
+
+let HAS_MEASURE_IMP_MEASURABLE = prove
+ (`!s m. s has_measure m ==> measurable s`,
+  REWRITE_TAC[measurable] THEN MESON_TAC[]);;
+
+let HAS_MEASURE = prove
+ (`!s m. s has_measure m <=>
+              ((\x. if x IN s then vec 1 else vec 0) has_integral (lift m))
+              (:real^N)`,
+  SIMP_TAC[HAS_INTEGRAL_RESTRICT_UNIV; has_measure]);;
+
+let MEASURABLE = prove
+ (`!s. measurable s <=> (\x. vec 1:real^1) integrable_on s`,
+  REWRITE_TAC[measurable; integrable_on;
+              has_measure; EXISTS_DROP; LIFT_DROP]);;
+
+let MEASURABLE_INTEGRABLE = prove
+ (`measurable s <=>
+     (\x. if x IN s then vec 1 else vec 0:real^1) integrable_on UNIV`,
+  REWRITE_TAC[measurable; integrable_on;
+              HAS_MEASURE; EXISTS_DROP; LIFT_DROP]);;
+
+let MEASURE_INTEGRAL = prove
+ (`!s. measurable s ==> measure s = drop (integral s (\x. vec 1))`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  REWRITE_TAC[GSYM LIFT_EQ; LIFT_DROP] THEN
+  MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  ASM_REWRITE_TAC[GSYM has_measure; GSYM HAS_MEASURE_MEASURE]);;
+
+let MEASURE_INTEGRAL_UNIV = prove
+ (`!s. measurable s
+       ==> measure s =
+           drop(integral UNIV (\x. if x IN s then vec 1 else vec 0))`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  REWRITE_TAC[GSYM LIFT_EQ; LIFT_DROP] THEN
+  MATCH_MP_TAC INTEGRAL_UNIQUE THEN
+  ASM_REWRITE_TAC[GSYM HAS_MEASURE; GSYM HAS_MEASURE_MEASURE]);;
+
+let INTEGRAL_MEASURE = prove
+ (`!s. measurable s ==> integral s (\x. vec 1) = lift(measure s)`,
+  SIMP_TAC[GSYM DROP_EQ; LIFT_DROP; MEASURE_INTEGRAL]);;
+
+let INTEGRAL_MEASURE_UNIV = prove
+ (`!s. measurable s
+       ==> integral UNIV (\x. if x IN s then vec 1 else vec 0) =
+           lift(measure s)`,
+  SIMP_TAC[GSYM DROP_EQ; LIFT_DROP; MEASURE_INTEGRAL_UNIV]);;
+
+let HAS_MEASURE_INTERVAL = prove
+ (`(!a b:real^N. interval[a,b] has_measure content(interval[a,b])) /\
+   (!a b:real^N. interval(a,b) has_measure content(interval[a,b]))`,
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REWRITE_TAC[has_measure] THEN
+    ONCE_REWRITE_TAC[LIFT_EQ_CMUL] THEN REWRITE_TAC[HAS_INTEGRAL_CONST];
+    ALL_TAC] THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN SIMP_TAC[HAS_MEASURE] THEN
+  MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+                           HAS_INTEGRAL_SPIKE) THEN
+  EXISTS_TAC `interval[a:real^N,b] DIFF interval(a,b)` THEN
+  REWRITE_TAC[NEGLIGIBLE_FRONTIER_INTERVAL] THEN
+  MP_TAC(ISPECL [`a:real^N`; `b:real^N`] INTERVAL_OPEN_SUBSET_CLOSED) THEN
+  SET_TAC[]);;
+
+let MEASURABLE_INTERVAL = prove
+ (`(!a b:real^N. measurable (interval[a,b])) /\
+   (!a b:real^N. measurable (interval(a,b)))`,
+  REWRITE_TAC[measurable] THEN MESON_TAC[HAS_MEASURE_INTERVAL]);;
+
+let MEASURE_INTERVAL = prove
+ (`(!a b:real^N. measure(interval[a,b]) = content(interval[a,b])) /\
+   (!a b:real^N. measure(interval(a,b)) = content(interval[a,b]))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_UNIQUE THEN
+  REWRITE_TAC[HAS_MEASURE_INTERVAL]);;
+
+let MEASURE_INTERVAL_1 = prove
+ (`(!a b:real^1. measure(interval[a,b]) =
+                    if drop a <= drop b then drop b - drop a else &0) /\
+   (!a b:real^1. measure(interval(a,b)) =
+                    if drop a <= drop b then drop b - drop a else &0)`,
+  REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+  REWRITE_TAC[DIMINDEX_1; FORALL_1; PRODUCT_1; drop]);;
+
+let MEASURE_INTERVAL_1_ALT = prove
+ (`(!a b:real^1. measure(interval[a,b]) =
+                    if drop a < drop b then drop b - drop a else &0) /\
+   (!a b:real^1. measure(interval(a,b)) =
+                    if drop a < drop b then drop b - drop a else &0)`,
+  REWRITE_TAC[MEASURE_INTERVAL_1] THEN REAL_ARITH_TAC);;
+
+let MEASURE_INTERVAL_2 = prove
+ (`(!a b:real^2. measure(interval[a,b]) =
+                 if a$1 <= b$1 /\ a$2 <= b$2
+                 then (b$1 - a$1) * (b$2 - a$2)
+                 else &0) /\
+   (!a b:real^2. measure(interval(a,b)) =
+                 if a$1 <= b$1 /\ a$2 <= b$2
+                 then (b$1 - a$1) * (b$2 - a$2)
+                 else &0)`,
+  REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+  REWRITE_TAC[DIMINDEX_2; FORALL_2; PRODUCT_2]);;
+
+let MEASURE_INTERVAL_2_ALT = prove
+ (`(!a b:real^2. measure(interval[a,b]) =
+                 if a$1 < b$1 /\ a$2 < b$2
+                 then (b$1 - a$1) * (b$2 - a$2)
+                 else &0) /\
+   (!a b:real^2. measure(interval(a,b)) =
+                 if a$1 < b$1 /\ a$2 < b$2
+                 then (b$1 - a$1) * (b$2 - a$2)
+                 else &0)`,
+  REWRITE_TAC[MEASURE_INTERVAL_2] THEN REPEAT GEN_TAC THEN
+  MAP_EVERY ASM_CASES_TAC
+   [`(a:real^2)$1 = (b:real^2)$1`; `(a:real^2)$2 = (b:real^2)$2`] THEN
+  ASM_REWRITE_TAC[REAL_LT_REFL; REAL_MUL_LZERO; REAL_MUL_RZERO;
+                  REAL_SUB_REFL; REAL_LE_REFL; REAL_ABS_NUM; COND_ID] THEN
+  ASM_REWRITE_TAC[REAL_LT_LE]);;
+
+let MEASURE_INTERVAL_3 = prove
+ (`(!a b:real^3. measure(interval[a,b]) =
+                 if a$1 <= b$1 /\ a$2 <= b$2 /\ a$3 <= b$3
+                 then (b$1 - a$1) * (b$2 - a$2) * (b$3 - a$3)
+                 else &0) /\
+   (!a b:real^3. measure(interval(a,b)) =
+                 if a$1 <= b$1 /\ a$2 <= b$2 /\ a$3 <= b$3
+                 then (b$1 - a$1) * (b$2 - a$2) * (b$3 - a$3)
+                 else &0)`,
+  REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+  REWRITE_TAC[DIMINDEX_3; FORALL_3; PRODUCT_3]);;
+
+let MEASURE_INTERVAL_3_ALT = prove
+ (`(!a b:real^3. measure(interval[a,b]) =
+                 if a$1 < b$1 /\ a$2 < b$2 /\ a$3 < b$3
+                 then (b$1 - a$1) * (b$2 - a$2) * (b$3 - a$3)
+                 else &0) /\
+   (!a b:real^3. measure(interval(a,b)) =
+                 if a$1 < b$1 /\ a$2 < b$2 /\ a$3 < b$3
+                 then (b$1 - a$1) * (b$2 - a$2) * (b$3 - a$3)
+                 else &0)`,
+  REWRITE_TAC[MEASURE_INTERVAL_3] THEN REPEAT GEN_TAC THEN
+  MAP_EVERY ASM_CASES_TAC
+   [`(a:real^3)$1 = (b:real^3)$1`;
+    `(a:real^3)$2 = (b:real^3)$2`;
+    `(a:real^3)$3 = (b:real^3)$3`] THEN
+  ASM_REWRITE_TAC[REAL_LT_REFL; REAL_MUL_LZERO; REAL_MUL_RZERO;
+                  REAL_SUB_REFL; REAL_LE_REFL; REAL_ABS_NUM; COND_ID] THEN
+  ASM_REWRITE_TAC[REAL_LT_LE]);;
+
+let MEASURE_INTERVAL_4 = prove
+ (`(!a b:real^4. measure(interval[a,b]) =
+                 if a$1 <= b$1 /\ a$2 <= b$2 /\ a$3 <= b$3 /\ a$4 <= b$4
+                 then (b$1 - a$1) * (b$2 - a$2) * (b$3 - a$3) * (b$4 - a$4)
+                 else &0) /\
+   (!a b:real^4. measure(interval(a,b)) =
+                 if a$1 <= b$1 /\ a$2 <= b$2 /\ a$3 <= b$3 /\ a$4 <= b$4
+                 then (b$1 - a$1) * (b$2 - a$2) * (b$3 - a$3) * (b$4 - a$4)
+                 else &0)`,
+  REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+  REWRITE_TAC[DIMINDEX_4; FORALL_4; PRODUCT_4]);;
+
+let MEASURE_INTERVAL_4_ALT = prove
+ (`(!a b:real^4. measure(interval[a,b]) =
+                 if a$1 < b$1 /\ a$2 < b$2 /\ a$3 < b$3 /\ a$4 < b$4
+                 then (b$1 - a$1) * (b$2 - a$2) * (b$3 - a$3) * (b$4 - a$4)
+                 else &0) /\
+   (!a b:real^4. measure(interval(a,b)) =
+                 if a$1 < b$1 /\ a$2 < b$2 /\ a$3 < b$3 /\ a$4 < b$4
+                 then (b$1 - a$1) * (b$2 - a$2) * (b$3 - a$3) * (b$4 - a$4)
+                 else &0)`,
+  REWRITE_TAC[MEASURE_INTERVAL_4] THEN REPEAT GEN_TAC THEN
+  MAP_EVERY ASM_CASES_TAC
+   [`(a:real^4)$1 = (b:real^4)$1`;
+    `(a:real^4)$2 = (b:real^4)$2`;
+    `(a:real^4)$3 = (b:real^4)$3`;
+    `(a:real^4)$4 = (b:real^4)$4`] THEN
+  ASM_REWRITE_TAC[REAL_LT_REFL; REAL_MUL_LZERO; REAL_MUL_RZERO;
+                  REAL_SUB_REFL; REAL_LE_REFL; REAL_ABS_NUM; COND_ID] THEN
+  ASM_REWRITE_TAC[REAL_LT_LE]);;
+
+let MEASURABLE_INTER = prove
+ (`!s t:real^N->bool. measurable s /\ measurable t ==> measurable (s INTER t)`,
+  REWRITE_TAC[MEASURABLE_INTEGRABLE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+  SUBGOAL_THEN
+   `(\x. if x IN s INTER t then vec 1 else vec 0):real^N->real^1 =
+    (\x. lambda i. min (((if x IN s then vec 1 else vec 0):real^1)$i)
+                       (((if x IN t then vec 1 else vec 0):real^1)$i))`
+  SUBST1_TAC THENL
+   [SIMP_TAC[FUN_EQ_THM; CART_EQ; LAMBDA_BETA] THEN
+    X_GEN_TAC `x:real^N` THEN REPEAT STRIP_TAC THEN
+    MAP_EVERY ASM_CASES_TAC [`(x:real^N) IN s`; `(x:real^N) IN t`] THEN
+    ASM_SIMP_TAC[IN_INTER; VEC_COMPONENT] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_MIN THEN
+  CONJ_TAC THEN MATCH_MP_TAC NONNEGATIVE_ABSOLUTELY_INTEGRABLE THEN
+  ASM_SIMP_TAC[] THEN REPEAT STRIP_TAC THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[VEC_COMPONENT; REAL_POS]);;
+
+let MEASURABLE_UNION = prove
+ (`!s t:real^N->bool. measurable s /\ measurable t ==> measurable (s UNION t)`,
+  REWRITE_TAC[MEASURABLE_INTEGRABLE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+  SUBGOAL_THEN
+   `(\x. if x IN s UNION t then vec 1 else vec 0):real^N->real^1 =
+    (\x. lambda i. max (((if x IN s then vec 1 else vec 0):real^1)$i)
+                       (((if x IN t then vec 1 else vec 0):real^1)$i))`
+  SUBST1_TAC THENL
+   [SIMP_TAC[FUN_EQ_THM; CART_EQ; LAMBDA_BETA] THEN
+    X_GEN_TAC `x:real^N` THEN REPEAT STRIP_TAC THEN
+    MAP_EVERY ASM_CASES_TAC [`(x:real^N) IN s`; `(x:real^N) IN t`] THEN
+    ASM_SIMP_TAC[IN_UNION; VEC_COMPONENT] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_MAX THEN
+  CONJ_TAC THEN MATCH_MP_TAC NONNEGATIVE_ABSOLUTELY_INTEGRABLE THEN
+  ASM_SIMP_TAC[] THEN REPEAT STRIP_TAC THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[VEC_COMPONENT; REAL_POS]);;
+
+let HAS_MEASURE_DISJOINT_UNION = prove
+ (`!s1 s2 m1 m2. s1 has_measure m1 /\ s2 has_measure m2 /\ DISJOINT s1 s2
+                 ==> (s1 UNION s2) has_measure (m1 + m2)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_MEASURE; CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_ADD) THEN
+  REWRITE_TAC[LIFT_ADD] THEN MATCH_MP_TAC EQ_IMP THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN
+  REPEAT(COND_CASES_TAC THEN REWRITE_TAC[VECTOR_ADD_LID; VECTOR_ADD_RID]) THEN
+  ASM SET_TAC[]);;
+
+let MEASURE_DISJOINT_UNION = prove
+ (`!s t. measurable s /\ measurable t /\ DISJOINT s t
+         ==> measure(s UNION t) = measure s + measure t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_MEASURE_DISJOINT_UNION; GSYM HAS_MEASURE_MEASURE]);;
+
+let MEASURE_DISJOINT_UNION_EQ = prove
+ (`!s t u.
+        measurable s /\ measurable t /\ s UNION t = u /\ DISJOINT s t
+        ==> measure s + measure t = measure u`,
+  MESON_TAC[MEASURE_DISJOINT_UNION]);;
+
+let HAS_MEASURE_POS_LE = prove
+ (`!m s:real^N->bool. s has_measure m ==> &0 <= m`,
+  REWRITE_TAC[HAS_MEASURE] THEN REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM(CONJUNCT2 LIFT_DROP)] THEN
+  REWRITE_TAC[drop] THEN MATCH_MP_TAC(ISPEC
+   `(\x. if x IN s then vec 1 else vec 0):real^N->real^1`
+   HAS_INTEGRAL_COMPONENT_POS) THEN
+  EXISTS_TAC `(:real^N)` THEN ASM_REWRITE_TAC[DIMINDEX_1; ARITH; IN_UNIV] THEN
+  GEN_TAC THEN COND_CASES_TAC THEN
+  REWRITE_TAC[GSYM drop; DROP_VEC; REAL_POS]);;
+
+let MEASURE_POS_LE = prove
+ (`!s. measurable s ==> &0 <= measure s`,
+  REWRITE_TAC[HAS_MEASURE_MEASURE; HAS_MEASURE_POS_LE]);;
+
+let HAS_MEASURE_SUBSET = prove
+ (`!s1 s2:real^N->bool m1 m2.
+        s1 has_measure m1 /\ s2 has_measure m2 /\ s1 SUBSET s2
+        ==> m1 <= m2`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_measure] THEN STRIP_TAC THEN
+  GEN_REWRITE_TAC BINOP_CONV [GSYM(CONJUNCT2 LIFT_DROP)] THEN
+  MATCH_MP_TAC(ISPEC `(\x. vec 1):real^N->real^1`
+    HAS_INTEGRAL_SUBSET_DROP_LE) THEN
+  MAP_EVERY EXISTS_TAC [`s1:real^N->bool`; `s2:real^N->bool`] THEN
+  ASM_REWRITE_TAC[DROP_VEC; REAL_POS]);;
+
+let MEASURE_SUBSET = prove
+ (`!s t. measurable s /\ measurable t /\ s SUBSET t
+         ==> measure s <= measure t`,
+  REWRITE_TAC[HAS_MEASURE_MEASURE] THEN MESON_TAC[HAS_MEASURE_SUBSET]);;
+
+let HAS_MEASURE_0 = prove
+ (`!s:real^N->bool. s has_measure &0 <=> negligible s`,
+  GEN_TAC THEN EQ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[NEGLIGIBLE; has_measure] THEN
+    DISCH_THEN(MP_TAC o SPEC `(:real^N)`) THEN
+    ONCE_REWRITE_TAC[GSYM HAS_INTEGRAL_RESTRICT_UNIV] THEN
+    REWRITE_TAC[IN_UNIV; indicator; LIFT_NUM]] THEN
+  REWRITE_TAC[negligible] THEN REWRITE_TAC[has_measure] THEN
+  ONCE_REWRITE_TAC[GSYM HAS_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[LIFT_NUM] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [HAS_INTEGRAL_ALT]) THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  REWRITE_TAC[integrable_on; IN_UNIV] THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV)
+   [GSYM HAS_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[indicator] THEN DISCH_THEN(X_CHOOSE_TAC `y:real^1`) THEN
+  SUBGOAL_THEN `y:real^1 = vec 0` (fun th -> ASM_MESON_TAC[th]) THEN
+  REWRITE_TAC[GSYM DROP_EQ; GSYM REAL_LE_ANTISYM] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC(ISPEC
+     `(\x. if x IN interval [a,b]
+           then if x IN s then vec 1 else vec 0 else vec 0):real^N->real^1`
+     HAS_INTEGRAL_DROP_LE) THEN
+    EXISTS_TAC `(\x. if x IN s then vec 1 else vec 0):real^N->real^1`;
+    REWRITE_TAC[DROP_VEC] THEN MATCH_MP_TAC(ISPEC
+     `(\x. if x IN interval [a,b]
+           then if x IN s then vec 1 else vec 0 else vec 0):real^N->real^1`
+     HAS_INTEGRAL_DROP_POS)] THEN
+  EXISTS_TAC `(:real^N)` THEN ASM_REWRITE_TAC[] THEN
+  REPEAT STRIP_TAC THEN REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+  REWRITE_TAC[DROP_VEC; REAL_POS; REAL_LE_REFL]);;
+
+let MEASURE_EQ_0 = prove
+ (`!s. negligible s ==> measure s = &0`,
+  MESON_TAC[MEASURE_UNIQUE; HAS_MEASURE_0]);;
+
+let NEGLIGIBLE_IMP_MEASURABLE = prove
+ (`!s:real^N->bool. negligible s ==> measurable s`,
+  MESON_TAC[HAS_MEASURE_0; measurable]);;
+
+let HAS_MEASURE_EMPTY = prove
+ (`{} has_measure &0`,
+  REWRITE_TAC[HAS_MEASURE_0; NEGLIGIBLE_EMPTY]);;
+
+let MEASURE_EMPTY = prove
+ (`measure {} = &0`,
+  SIMP_TAC[MEASURE_EQ_0; NEGLIGIBLE_EMPTY]);;
+
+let MEASURABLE_EMPTY = prove
+ (`measurable {}`,
+  REWRITE_TAC[measurable] THEN MESON_TAC[HAS_MEASURE_EMPTY]);;
+
+let MEASURABLE_MEASURE_EQ_0 = prove
+ (`!s. measurable s ==> (measure s = &0 <=> negligible s)`,
+  REWRITE_TAC[HAS_MEASURE_MEASURE; GSYM HAS_MEASURE_0] THEN
+  MESON_TAC[MEASURE_UNIQUE]);;
+
+let NEGLIGIBLE_EQ_MEASURE_0 = prove
+ (`!s:real^N->bool.
+        negligible s <=> measurable s /\ measure s = &0`,
+  MESON_TAC[NEGLIGIBLE_IMP_MEASURABLE; MEASURABLE_MEASURE_EQ_0]);;
+
+let MEASURABLE_MEASURE_POS_LT = prove
+ (`!s. measurable s ==> (&0 < measure s <=> ~negligible s)`,
+  SIMP_TAC[REAL_LT_LE; MEASURE_POS_LE; GSYM MEASURABLE_MEASURE_EQ_0] THEN
+  REWRITE_TAC[EQ_SYM_EQ]);;
+
+let NEGLIGIBLE_INTERVAL = prove
+ (`(!a b. negligible(interval[a,b]) <=> interval(a,b) = {}) /\
+   (!a b. negligible(interval(a,b)) <=> interval(a,b) = {})`,
+  REWRITE_TAC[GSYM HAS_MEASURE_0] THEN
+  MESON_TAC[HAS_MEASURE_INTERVAL; CONTENT_EQ_0_INTERIOR;
+            INTERIOR_CLOSED_INTERVAL; HAS_MEASURE_UNIQUE]);;
+
+let MEASURABLE_UNIONS = prove
+ (`!f:(real^N->bool)->bool.
+        FINITE f /\ (!s. s IN f ==> measurable s)
+        ==> measurable (UNIONS f)`,
+  REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[UNIONS_0; UNIONS_INSERT; MEASURABLE_EMPTY] THEN
+  REWRITE_TAC[IN_INSERT] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC MEASURABLE_UNION THEN ASM_SIMP_TAC[]);;
+
+let HAS_MEASURE_DIFF_SUBSET = prove
+ (`!s1 s2 m1 m2. s1 has_measure m1 /\ s2 has_measure m2 /\ s2 SUBSET s1
+                 ==> (s1 DIFF s2) has_measure (m1 - m2)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_MEASURE; CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_SUB) THEN
+  REWRITE_TAC[LIFT_SUB] THEN MATCH_MP_TAC EQ_IMP THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN
+  REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+  REWRITE_TAC[VECTOR_SUB_REFL; VECTOR_SUB_RZERO] THEN
+  ASM SET_TAC[]);;
+
+let MEASURABLE_DIFF = prove
+ (`!s t:real^N->bool. measurable s /\ measurable t ==> measurable (s DIFF t)`,
+  SUBGOAL_THEN
+   `!s t:real^N->bool. measurable s /\ measurable t /\ t SUBSET s
+         ==> measurable (s DIFF t)`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[measurable] THEN MESON_TAC[HAS_MEASURE_DIFF_SUBSET];
+    ONCE_REWRITE_TAC[SET_RULE `s DIFF t = s DIFF (s INTER t)`] THEN
+    REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[MEASURABLE_INTER] THEN
+    SET_TAC[]]);;
+
+let MEASURE_DIFF_SUBSET = prove
+ (`!s t. measurable s /\ measurable t /\ t SUBSET s
+         ==> measure(s DIFF t) = measure s - measure t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_MEASURE_DIFF_SUBSET; GSYM HAS_MEASURE_MEASURE]);;
+
+let HAS_MEASURE_UNION_NEGLIGIBLE = prove
+ (`!s t:real^N->bool m.
+        s has_measure m /\ negligible t ==> (s UNION t) has_measure m`,
+  REWRITE_TAC[HAS_MEASURE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPIKE THEN
+  MAP_EVERY EXISTS_TAC
+   [`(\x. if x IN s then vec 1 else vec 0):real^N->real^1`;
+    `t:real^N->bool`] THEN
+  ASM_SIMP_TAC[IN_DIFF; IN_UNIV; IN_UNION]);;
+
+let HAS_MEASURE_DIFF_NEGLIGIBLE = prove
+ (`!s t:real^N->bool m.
+        s has_measure m /\ negligible t ==> (s DIFF t) has_measure m`,
+  REWRITE_TAC[HAS_MEASURE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_INTEGRAL_SPIKE THEN
+  MAP_EVERY EXISTS_TAC
+   [`(\x. if x IN s then vec 1 else vec 0):real^N->real^1`;
+    `t:real^N->bool`] THEN
+  ASM_SIMP_TAC[IN_DIFF; IN_UNIV; IN_UNION]);;
+
+let HAS_MEASURE_UNION_NEGLIGIBLE_EQ = prove
+ (`!s t:real^N->bool m.
+     negligible t ==> ((s UNION t) has_measure m <=> s has_measure m)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[HAS_MEASURE_UNION_NEGLIGIBLE] THEN
+  SUBST1_TAC(SET_RULE `s:real^N->bool = (s UNION t) DIFF (t DIFF s)`) THEN
+  MATCH_MP_TAC HAS_MEASURE_DIFF_NEGLIGIBLE THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC NEGLIGIBLE_DIFF THEN ASM_REWRITE_TAC[]);;
+
+let HAS_MEASURE_DIFF_NEGLIGIBLE_EQ = prove
+ (`!s t:real^N->bool m.
+     negligible t ==> ((s DIFF t) has_measure m <=> s has_measure m)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[HAS_MEASURE_DIFF_NEGLIGIBLE] THEN
+  SUBST1_TAC(SET_RULE `s:real^N->bool = (s DIFF t) UNION (t INTER s)`) THEN
+  MATCH_MP_TAC HAS_MEASURE_UNION_NEGLIGIBLE THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_INTER]);;
+
+let HAS_MEASURE_ALMOST = prove
+ (`!s s' t m. s has_measure m /\ negligible t /\ s UNION t = s' UNION t
+              ==> s' has_measure m`,
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP (SET_RULE
+   `s UNION t = s' UNION t ==> s' = (s UNION t) DIFF (t DIFF s')`)) THEN
+  ASM_SIMP_TAC[HAS_MEASURE_DIFF_NEGLIGIBLE; HAS_MEASURE_UNION_NEGLIGIBLE;
+               NEGLIGIBLE_DIFF]);;
+
+let HAS_MEASURE_ALMOST_EQ = prove
+ (`!s s' t. negligible t /\ s UNION t = s' UNION t
+            ==> (s has_measure m <=> s' has_measure m)`,
+  MESON_TAC[HAS_MEASURE_ALMOST]);;
+
+let MEASURABLE_ALMOST = prove
+ (`!s s' t. measurable s /\ negligible t /\ s UNION t = s' UNION t
+            ==> measurable s'`,
+  REWRITE_TAC[measurable] THEN MESON_TAC[HAS_MEASURE_ALMOST]);;
+
+let HAS_MEASURE_NEGLIGIBLE_UNION = prove
+ (`!s1 s2:real^N->bool m1 m2.
+        s1 has_measure m1 /\ s2 has_measure m2 /\ negligible(s1 INTER s2)
+        ==> (s1 UNION s2) has_measure (m1 + m2)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_MEASURE_ALMOST THEN
+  MAP_EVERY EXISTS_TAC
+   [`(s1 DIFF (s1 INTER s2)) UNION (s2 DIFF (s1 INTER s2)):real^N->bool`;
+    `s1 INTER s2:real^N->bool`] THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ALL_TAC; SET_TAC[]] THEN
+  MATCH_MP_TAC HAS_MEASURE_DISJOINT_UNION THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC HAS_MEASURE_ALMOST THEN EXISTS_TAC `s1:real^N->bool`;
+    MATCH_MP_TAC HAS_MEASURE_ALMOST THEN EXISTS_TAC `s2:real^N->bool`;
+    SET_TAC[]] THEN
+  EXISTS_TAC `s1 INTER s2:real^N->bool` THEN
+  ASM_REWRITE_TAC[] THEN SET_TAC[]);;
+
+let MEASURE_NEGLIGIBLE_UNION = prove
+ (`!s t. measurable s /\ measurable t /\ negligible(s INTER t)
+         ==> measure(s UNION t) = measure s + measure t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_MEASURE_NEGLIGIBLE_UNION; GSYM HAS_MEASURE_MEASURE]);;
+
+let MEASURE_NEGLIGIBLE_UNION_EQ = prove
+ (`!s t u.
+        measurable s /\ measurable t /\ s UNION t = u /\ negligible(s INTER t)
+        ==> measure s + measure t = measure u`,
+  MESON_TAC[MEASURE_NEGLIGIBLE_UNION]);;
+
+let HAS_MEASURE_NEGLIGIBLE_SYMDIFF = prove
+ (`!s t:real^N->bool m.
+        s has_measure m /\
+        negligible((s DIFF t) UNION (t DIFF s))
+        ==> t has_measure m`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_MEASURE_ALMOST THEN
+  MAP_EVERY EXISTS_TAC
+   [`s:real^N->bool`; `(s DIFF t) UNION (t DIFF s):real^N->bool`] THEN
+  ASM_REWRITE_TAC[] THEN SET_TAC[]);;
+
+let MEASURABLE_NEGLIGIBLE_SYMDIFF = prove
+ (`!s t:real^N->bool.
+        measurable s /\ negligible((s DIFF t) UNION (t DIFF s))
+        ==> measurable t`,
+  REWRITE_TAC[measurable] THEN
+  MESON_TAC[HAS_MEASURE_NEGLIGIBLE_SYMDIFF]);;
+
+let MEASURABLE_NEGLIGIBLE_SYMDIFF_EQ = prove
+ (`!s t:real^N->bool.
+        negligible(s DIFF t UNION t DIFF s)
+        ==> (measurable s <=> measurable t)`,
+  MESON_TAC[MEASURABLE_NEGLIGIBLE_SYMDIFF; UNION_COMM]);;
+
+let MEASURE_NEGLIGIBLE_SYMDIFF = prove
+ (`!s t:real^N->bool.
+        negligible(s DIFF t UNION t DIFF s) ==> measure s = measure t`,
+  REPEAT STRIP_TAC THEN MAP_EVERY ASM_CASES_TAC
+   [`measurable(s:real^N->bool)`; `measurable(t:real^N->bool)`]
+  THENL
+   [ASM_MESON_TAC[HAS_MEASURE_NEGLIGIBLE_SYMDIFF; MEASURE_UNIQUE;
+                  HAS_MEASURE_MEASURE];
+    ASM_MESON_TAC[MEASURABLE_NEGLIGIBLE_SYMDIFF_EQ];
+    ASM_MESON_TAC[MEASURABLE_NEGLIGIBLE_SYMDIFF_EQ];
+    REWRITE_TAC[measure] THEN AP_TERM_TAC THEN ABS_TAC THEN
+    ASM_MESON_TAC[measurable]]);;
+
+let NEGLIGIBLE_SYMDIFF_EQ = prove
+ (`!s t:real^N->bool.
+        negligible (s DIFF t UNION t DIFF s)
+        ==> (negligible s <=> negligible t)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[IMP_IMP; GSYM NEGLIGIBLE_UNION_EQ] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] NEGLIGIBLE_SUBSET) THEN
+  SET_TAC[]);;
+
+let NEGLIGIBLE_DELETE = prove
+ (`!a:real^N. negligible(s DELETE a) <=> negligible s`,
+  GEN_TAC THEN MATCH_MP_TAC NEGLIGIBLE_SYMDIFF_EQ THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `{a:real^N}` THEN REWRITE_TAC[NEGLIGIBLE_SING] THEN SET_TAC[]);;
+
+let HAS_MEASURE_NEGLIGIBLE_UNIONS = prove
+ (`!m f:(real^N->bool)->bool.
+        FINITE f /\
+        (!s. s IN f ==> s has_measure (m s)) /\
+        (!s t. s IN f /\ t IN f /\ ~(s = t) ==> negligible(s INTER t))
+        ==> (UNIONS f) has_measure (sum f m)`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[SUM_CLAUSES; UNIONS_0; UNIONS_INSERT; HAS_MEASURE_EMPTY] THEN
+  REWRITE_TAC[IN_INSERT] THEN
+  MAP_EVERY X_GEN_TAC [`s:real^N->bool`; `f:(real^N->bool)->bool`] THEN
+  STRIP_TAC THEN STRIP_TAC THEN MATCH_MP_TAC HAS_MEASURE_NEGLIGIBLE_UNION THEN
+  REPEAT(CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC]) THEN
+  REWRITE_TAC[INTER_UNIONS] THEN MATCH_MP_TAC NEGLIGIBLE_UNIONS THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[]);;
+
+let MEASURE_NEGLIGIBLE_UNIONS = prove
+ (`!m f:(real^N->bool)->bool.
+        FINITE f /\
+        (!s. s IN f ==> s has_measure (m s)) /\
+        (!s t. s IN f /\ t IN f /\ ~(s = t) ==> negligible(s INTER t))
+        ==> measure(UNIONS f) = sum f m`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_MEASURE_NEGLIGIBLE_UNIONS]);;
+
+let HAS_MEASURE_DISJOINT_UNIONS = prove
+ (`!m f:(real^N->bool)->bool.
+        FINITE f /\
+        (!s. s IN f ==> s has_measure (m s)) /\
+        (!s t. s IN f /\ t IN f /\ ~(s = t) ==> DISJOINT s t)
+        ==> (UNIONS f) has_measure (sum f m)`,
+  REWRITE_TAC[DISJOINT] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_MEASURE_NEGLIGIBLE_UNIONS THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_EMPTY]);;
+
+let MEASURE_DISJOINT_UNIONS = prove
+ (`!m f:(real^N->bool)->bool.
+        FINITE f /\
+        (!s. s IN f ==> s has_measure (m s)) /\
+        (!s t. s IN f /\ t IN f /\ ~(s = t) ==> DISJOINT s t)
+        ==> measure(UNIONS f) = sum f m`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_MEASURE_DISJOINT_UNIONS]);;
+
+let HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE = prove
+ (`!f:A->real^N->bool s.
+        FINITE s /\
+        (!x. x IN s ==> measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> negligible((f x) INTER (f y)))
+        ==> (UNIONS (IMAGE f s)) has_measure (sum s (\x. measure(f x)))`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `sum s (\x. measure(f x)) = sum (IMAGE (f:A->real^N->bool) s) measure`
+  SUBST1_TAC THENL
+   [CONV_TAC SYM_CONV THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+    MATCH_MP_TAC SUM_IMAGE_NONZERO THEN ASM_REWRITE_TAC[] THEN
+    MAP_EVERY X_GEN_TAC [`x:A`; `y:A`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:A`; `y:A`]) THEN
+    ASM_SIMP_TAC[INTER_ACI; MEASURABLE_MEASURE_EQ_0];
+    MATCH_MP_TAC HAS_MEASURE_NEGLIGIBLE_UNIONS THEN
+    ASM_SIMP_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ; FORALL_IN_IMAGE] THEN
+    ASM_MESON_TAC[FINITE_IMAGE; HAS_MEASURE_MEASURE]]);;
+
+let MEASURE_NEGLIGIBLE_UNIONS_IMAGE = prove
+ (`!f:A->real^N->bool s.
+        FINITE s /\
+        (!x. x IN s ==> measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> negligible((f x) INTER (f y)))
+        ==> measure(UNIONS (IMAGE f s)) = sum s (\x. measure(f x))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE]);;
+
+let HAS_MEASURE_DISJOINT_UNIONS_IMAGE = prove
+ (`!f:A->real^N->bool s.
+        FINITE s /\
+        (!x. x IN s ==> measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> DISJOINT (f x) (f y))
+        ==> (UNIONS (IMAGE f s)) has_measure (sum s (\x. measure(f x)))`,
+  REWRITE_TAC[DISJOINT] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_EMPTY]);;
+
+let MEASURE_DISJOINT_UNIONS_IMAGE = prove
+ (`!f:A->real^N->bool s.
+        FINITE s /\
+        (!x. x IN s ==> measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> DISJOINT (f x) (f y))
+        ==> measure(UNIONS (IMAGE f s)) = sum s (\x. measure(f x))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_MEASURE_DISJOINT_UNIONS_IMAGE]);;
+
+let HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG = prove
+ (`!f:A->real^N->bool s.
+        FINITE {x | x IN s /\ ~(f x = {})} /\
+        (!x. x IN s ==> measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> negligible((f x) INTER (f y)))
+        ==> (UNIONS (IMAGE f s)) has_measure (sum s (\x. measure(f x)))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:A->real^N->bool`;
+                 `{x | x IN s /\ ~((f:A->real^N->bool) x = {})}`]
+        HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE) THEN
+  ASM_SIMP_TAC[IN_ELIM_THM; FINITE_RESTRICT] THEN
+  MATCH_MP_TAC EQ_IMP THEN BINOP_TAC THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_UNIONS; IN_IMAGE; IN_ELIM_THM] THEN
+    MESON_TAC[NOT_IN_EMPTY];
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_SUPERSET THEN
+    SIMP_TAC[SUBSET; IN_ELIM_THM; TAUT `a /\ ~(a /\ b) <=> a /\ ~b`] THEN
+    REWRITE_TAC[MEASURE_EMPTY]]);;
+
+let MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG = prove
+ (`!f:A->real^N->bool s.
+        FINITE {x | x IN s /\ ~(f x = {})} /\
+        (!x. x IN s ==> measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> negligible((f x) INTER (f y)))
+        ==> measure(UNIONS (IMAGE f s)) = sum s (\x. measure(f x))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG]);;
+
+let HAS_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG = prove
+ (`!f:A->real^N->bool s.
+        FINITE {x | x IN s /\ ~(f x = {})} /\
+        (!x. x IN s ==> measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> DISJOINT (f x) (f y))
+        ==> (UNIONS (IMAGE f s)) has_measure (sum s (\x. measure(f x)))`,
+  REWRITE_TAC[DISJOINT] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_EMPTY]);;
+
+let MEASURE_DISJOINT_UNIONS_IMAGE_STRONG = prove
+ (`!f:A->real^N->bool s.
+        FINITE {x | x IN s /\ ~(f x = {})} /\
+        (!x. x IN s ==> measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> DISJOINT (f x) (f y))
+        ==> measure(UNIONS (IMAGE f s)) = sum s (\x. measure(f x))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG]);;
+
+let MEASURE_UNION = prove
+ (`!s t:real^N->bool.
+        measurable s /\ measurable t
+        ==> measure(s UNION t) = measure(s) + measure(t) - measure(s INTER t)`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[SET_RULE
+   `s UNION t = (s INTER t) UNION (s DIFF t) UNION (t DIFF s)`] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a + b - c:real = c + (a - c) + (b - c)`] THEN
+  MP_TAC(ISPECL [`s DIFF t:real^N->bool`; `t DIFF s:real^N->bool`]
+        MEASURE_DISJOINT_UNION) THEN
+  ASM_SIMP_TAC[MEASURABLE_DIFF] THEN
+  ANTS_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`s INTER t:real^N->bool`;
+                 `(s DIFF t) UNION (t DIFF s):real^N->bool`]
+                MEASURE_DISJOINT_UNION) THEN
+  ASM_SIMP_TAC[MEASURABLE_DIFF; MEASURABLE_UNION; MEASURABLE_INTER] THEN
+  ANTS_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+  REPEAT(DISCH_THEN SUBST1_TAC) THEN AP_TERM_TAC THEN BINOP_TAC THEN
+  REWRITE_TAC[REAL_EQ_SUB_LADD] THEN MATCH_MP_TAC EQ_TRANS THENL
+   [EXISTS_TAC `measure((s DIFF t) UNION (s INTER t):real^N->bool)`;
+    EXISTS_TAC `measure((t DIFF s) UNION (s INTER t):real^N->bool)`] THEN
+  (CONJ_TAC THENL
+    [CONV_TAC SYM_CONV THEN MATCH_MP_TAC MEASURE_DISJOINT_UNION THEN
+     ASM_SIMP_TAC[MEASURABLE_DIFF; MEASURABLE_INTER];
+     AP_TERM_TAC] THEN
+   SET_TAC[]));;
+
+let MEASURE_UNION_LE = prove
+ (`!s t:real^N->bool.
+        measurable s /\ measurable t
+        ==> measure(s UNION t) <= measure s + measure t`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[MEASURE_UNION] THEN
+  REWRITE_TAC[REAL_ARITH `a + b - c <= a + b <=> &0 <= c`] THEN
+  MATCH_MP_TAC MEASURE_POS_LE THEN ASM_SIMP_TAC[MEASURABLE_INTER]);;
+
+let MEASURE_UNIONS_LE = prove
+ (`!f:(real^N->bool)->bool.
+        FINITE f /\ (!s. s IN f ==> measurable s)
+        ==> measure(UNIONS f) <= sum f (\s. measure s)`,
+  REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[UNIONS_0; UNIONS_INSERT; SUM_CLAUSES] THEN
+  REWRITE_TAC[MEASURE_EMPTY; REAL_LE_REFL] THEN
+  MAP_EVERY X_GEN_TAC [`s:real^N->bool`; `f:(real^N->bool)->bool`] THEN
+  REWRITE_TAC[IN_INSERT] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `measure(s:real^N->bool) + measure(UNIONS f:real^N->bool)` THEN
+  ASM_SIMP_TAC[MEASURE_UNION_LE; MEASURABLE_UNIONS] THEN
+  REWRITE_TAC[REAL_LE_LADD] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[]);;
+
+let MEASURABLE_INSERT = prove
+ (`!x s:real^N->bool. measurable(x INSERT s) <=> measurable s`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC MEASURABLE_NEGLIGIBLE_SYMDIFF_EQ THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC `{x:real^N}` THEN
+  REWRITE_TAC[NEGLIGIBLE_SING] THEN SET_TAC[]);;
+
+let MEASURE_INSERT = prove
+ (`!x s:real^N->bool. measure(x INSERT s) = measure s`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC MEASURE_NEGLIGIBLE_SYMDIFF THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC `{x:real^N}` THEN
+  REWRITE_TAC[NEGLIGIBLE_SING] THEN SET_TAC[]);;
+
+let MEASURE_UNIONS_LE_IMAGE = prove
+ (`!f:A->bool s:A->(real^N->bool).
+        FINITE f /\ (!a. a IN f ==> measurable(s a))
+        ==> measure(UNIONS (IMAGE s f)) <= sum f (\a. measure(s a))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum (IMAGE s (f:A->bool)) (\k:real^N->bool. measure k)` THEN
+  ASM_SIMP_TAC[MEASURE_UNIONS_LE; FORALL_IN_IMAGE; FINITE_IMAGE] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM o_DEF] THEN
+  REWRITE_TAC[ETA_AX] THEN MATCH_MP_TAC SUM_IMAGE_LE THEN
+  ASM_SIMP_TAC[MEASURE_POS_LE]);;
+
+let MEASURABLE_INNER_OUTER = prove
+ (`!s:real^N->bool.
+        measurable s <=>
+                !e. &0 < e
+                    ==> ?t u. t SUBSET s /\ s SUBSET u /\
+                              measurable t /\ measurable u /\
+                              abs(measure t - measure u) < e`,
+  GEN_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+   [GEN_TAC THEN DISCH_TAC THEN REPEAT(EXISTS_TAC `s:real^N->bool`) THEN
+    ASM_REWRITE_TAC[SUBSET_REFL; REAL_SUB_REFL; REAL_ABS_NUM];
+    ALL_TAC] THEN
+  REWRITE_TAC[MEASURABLE_INTEGRABLE] THEN MATCH_MP_TAC INTEGRABLE_STRADDLE THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`t:real^N->bool`; `u:real^N->bool`] THEN STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC
+   [`(\x. if x IN t then vec 1 else vec 0):real^N->real^1`;
+    `(\x. if x IN u then vec 1 else vec 0):real^N->real^1`;
+    `lift(measure(t:real^N->bool))`;
+    `lift(measure(u:real^N->bool))`] THEN
+  ASM_REWRITE_TAC[GSYM HAS_MEASURE; GSYM HAS_MEASURE_MEASURE] THEN
+  ASM_REWRITE_TAC[GSYM LIFT_SUB; NORM_LIFT] THEN REPEAT STRIP_TAC THEN
+  REPEAT(COND_CASES_TAC THEN
+         ASM_REWRITE_TAC[DROP_VEC; REAL_POS; REAL_LE_REFL]) THEN
+  ASM SET_TAC[]);;
+
+let HAS_MEASURE_INNER_OUTER = prove
+ (`!s:real^N->bool m.
+        s has_measure m <=>
+                (!e. &0 < e ==> ?t. t SUBSET s /\ measurable t /\
+                                    m - e < measure t) /\
+                (!e. &0 < e ==> ?u. s SUBSET u /\ measurable u /\
+                                    measure u < m + e)`,
+  REPEAT GEN_TAC THEN
+  GEN_REWRITE_TAC LAND_CONV [HAS_MEASURE_MEASURABLE_MEASURE] THEN EQ_TAC THENL
+   [REPEAT STRIP_TAC THEN EXISTS_TAC `s:real^N->bool` THEN
+    ASM_REWRITE_TAC[SUBSET_REFL] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "t") (LABEL_TAC "u")) THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [GEN_REWRITE_TAC I [MEASURABLE_INNER_OUTER] THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    REMOVE_THEN "u" (MP_TAC o SPEC `e / &2`) THEN
+    REMOVE_THEN "t" (MP_TAC o SPEC `e / &2`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+    REWRITE_TAC[IMP_IMP; LEFT_AND_EXISTS_THM] THEN
+    REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(REAL_ARITH
+     `&0 < e /\ t <= u /\ m - e / &2 < t /\ u < m + e / &2
+                          ==> abs(t - u) < e`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    DISCH_TAC THEN MATCH_MP_TAC(REAL_ARITH
+     `~(&0 < x - y) /\ ~(&0 < y - x) ==> x = y`) THEN
+    CONJ_TAC THEN DISCH_TAC THENL
+     [REMOVE_THEN "u" (MP_TAC o SPEC `measure(s:real^N->bool) - m`) THEN
+      ASM_REWRITE_TAC[REAL_SUB_ADD2; GSYM REAL_NOT_LE];
+      REMOVE_THEN "t" (MP_TAC o SPEC `m - measure(s:real^N->bool)`) THEN
+      ASM_REWRITE_TAC[REAL_SUB_SUB2; GSYM REAL_NOT_LE]] THEN
+    ASM_MESON_TAC[MEASURE_SUBSET]]);;
+
+let HAS_MEASURE_INNER_OUTER_LE = prove
+ (`!s:real^N->bool m.
+        s has_measure m <=>
+                (!e. &0 < e ==> ?t. t SUBSET s /\ measurable t /\
+                                    m - e <= measure t) /\
+                (!e. &0 < e ==> ?u. s SUBSET u /\ measurable u /\
+                                    measure u <= m + e)`,
+  REWRITE_TAC[HAS_MEASURE_INNER_OUTER] THEN
+  MESON_TAC[REAL_ARITH `&0 < e /\ m - e / &2 <= t ==> m - e < t`;
+            REAL_ARITH `&0 < e /\ u <= m + e / &2 ==> u < m + e`;
+            REAL_ARITH `&0 < e <=> &0 < e / &2`; REAL_LT_IMP_LE]);;
+
+let NEGLIGIBLE_OUTER = prove
+ (`!s:real^N->bool.
+      negligible s <=>
+      !e. &0 < e ==> ?t. s SUBSET t /\ measurable t /\ measure t < e`,
+  GEN_TAC THEN REWRITE_TAC[GSYM HAS_MEASURE_0; HAS_MEASURE_INNER_OUTER] THEN
+  REWRITE_TAC[REAL_ADD_LID] THEN MATCH_MP_TAC(TAUT `a ==> (a /\ b <=> b)`) THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN EXISTS_TAC `{}:real^N->bool` THEN
+  REWRITE_TAC[EMPTY_SUBSET; MEASURABLE_EMPTY; MEASURE_EMPTY] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let NEGLIGIBLE_OUTER_LE = prove
+ (`!s:real^N->bool.
+      negligible s <=>
+      !e. &0 < e ==> ?t. s SUBSET t /\ measurable t /\ measure t <= e`,
+  REWRITE_TAC[NEGLIGIBLE_OUTER] THEN
+  MESON_TAC[REAL_LT_IMP_LE; REAL_ARITH
+    `&0 < e ==> &0 < e / &2 /\ (x <= e / &2 ==> x < e)`]);;
+
+let HAS_MEASURE_LIMIT = prove
+ (`!s. s has_measure m <=>
+        !e. &0 < e
+            ==> ?B. &0 < B /\
+                    !a b. ball(vec 0,B) SUBSET interval[a,b]
+                          ==> ?z. (s INTER interval[a,b]) has_measure z /\
+                                  abs(z - m) < e`,
+  GEN_TAC THEN REWRITE_TAC[HAS_MEASURE] THEN
+  GEN_REWRITE_TAC LAND_CONV [HAS_INTEGRAL] THEN
+  REWRITE_TAC[IN_UNIV] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+    [GSYM HAS_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[MESON[IN_INTER]
+        `(if x IN k INTER s then a else b) =
+         (if x IN s then if x IN k then a else b else b)`] THEN
+  REWRITE_TAC[EXISTS_LIFT; GSYM LIFT_SUB; NORM_LIFT]);;
+
+let MEASURE_LIMIT = prove
+ (`!s:real^N->bool e.
+        measurable s /\ &0 < e
+        ==> ?B. &0 < B /\
+                !a b. ball(vec 0,B) SUBSET interval[a,b]
+                      ==> abs(measure(s INTER interval[a,b]) -
+                              measure s) < e`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HAS_MEASURE_MEASURE]) THEN
+  GEN_REWRITE_TAC LAND_CONV [HAS_MEASURE_LIMIT] THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[MEASURE_UNIQUE]);;
+
+let INTEGRABLE_ON_CONST = prove
+ (`!c:real^N. (\x:real^M. c) integrable_on s <=> c = vec 0 \/ measurable s`,
+  GEN_TAC THEN ASM_CASES_TAC `c:real^N = vec 0` THEN
+  ASM_REWRITE_TAC[INTEGRABLE_0; MEASURABLE] THEN EQ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [CART_EQ]) THEN
+    REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; VEC_COMPONENT] THEN
+    DISCH_THEN(X_CHOOSE_THEN `k:num` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(MP_TAC o
+      ISPEC `(\y. lambda i. y$k / (c:real^N)$k):real^N->real^1` o
+      MATCH_MP(REWRITE_RULE[IMP_CONJ] INTEGRABLE_LINEAR)) THEN
+    ASM_SIMP_TAC[vec; o_DEF; REAL_DIV_REFL] THEN DISCH_THEN MATCH_MP_TAC THEN
+    SIMP_TAC[linear; CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+             LAMBDA_BETA] THEN REAL_ARITH_TAC;
+    DISCH_THEN(MP_TAC o
+      ISPEC `(\y. lambda i. (c:real^N)$i * y$i):real^1->real^N` o
+      MATCH_MP(REWRITE_RULE[IMP_CONJ] INTEGRABLE_LINEAR)) THEN
+    ANTS_TAC THENL
+     [SIMP_TAC[linear; CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+               LAMBDA_BETA] THEN REAL_ARITH_TAC;
+      MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+      SIMP_TAC[FUN_EQ_THM; CART_EQ; o_THM; LAMBDA_BETA; VEC_COMPONENT] THEN
+      REWRITE_TAC[REAL_MUL_RID]]]);;
+
+let ABSOLUTELY_INTEGRABLE_ON_CONST = prove
+ (`!c. (\x. c) absolutely_integrable_on s <=> c = vec 0 \/ measurable s`,
+  REWRITE_TAC[absolutely_integrable_on; INTEGRABLE_ON_CONST] THEN
+  REWRITE_TAC[GSYM DROP_EQ; LIFT_DROP; DROP_VEC; NORM_EQ_0]);;
+
+let OPEN_NOT_NEGLIGIBLE = prove
+ (`!s:real^N->bool. open s /\ ~(s = {}) ==> ~(negligible s)`,
+  GEN_TAC THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; RIGHT_AND_EXISTS_THM] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `a:real^N` THEN
+  STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `a:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN DISCH_TAC THEN
+  SUBGOAL_THEN `negligible(interval[a - e / (&(dimindex(:N))) % vec 1:real^N,
+                                    a + e / (&(dimindex(:N))) % vec 1])`
+  MP_TAC THENL
+   [MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+    EXISTS_TAC `cball(a:real^N,e)` THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[NEGLIGIBLE_SUBSET]; ALL_TAC] THEN
+    REWRITE_TAC[SUBSET; IN_INTERVAL; IN_CBALL; VECTOR_ADD_COMPONENT;
+      VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID;
+      REAL_ARITH `a - e <= x /\ x <= a + e <=> abs(x - a) <= e`; dist] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_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_BOUND_GEN THEN
+    REWRITE_TAC[FINITE_NUMSEG; CARD_NUMSEG_1; NUMSEG_EMPTY; NOT_LT] THEN
+    REWRITE_TAC[IN_NUMSEG; VECTOR_SUB_COMPONENT; DIMINDEX_GE_1] THEN
+    ASM_MESON_TAC[REAL_ABS_SUB];
+    REWRITE_TAC[NEGLIGIBLE_INTERVAL; INTERVAL_NE_EMPTY] THEN
+    REWRITE_TAC[VECTOR_ADD_COMPONENT; REAL_MUL_RID;
+      VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT; VEC_COMPONENT] THEN
+    REPEAT STRIP_TAC THEN
+    REWRITE_TAC[REAL_ARITH `a - e < a + e <=> &0 < e`] THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1]]);;
+
+let NOT_NEGLIGIBLE_UNIV = prove
+ (`~negligible(:real^N)`,
+  SIMP_TAC[OPEN_NOT_NEGLIGIBLE; OPEN_UNIV; UNIV_NOT_EMPTY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Properties of measure under simple affine transformations.                *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_MEASURE_AFFINITY = prove
+ (`!s m c y. s has_measure y
+             ==> (IMAGE (\x:real^N. m % x + c) s)
+                 has_measure abs(m) pow (dimindex(:N)) * y`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `m = &0` THENL
+   [ASM_REWRITE_TAC[REAL_ABS_NUM; VECTOR_ADD_LID; VECTOR_MUL_LZERO] THEN
+    ONCE_REWRITE_TAC[MATCH_MP (ARITH_RULE `~(x = 0) ==> x = SUC(x - 1)`)
+     (SPEC_ALL DIMINDEX_NONZERO)] THEN DISCH_TAC THEN
+    REWRITE_TAC[real_pow; REAL_MUL_LZERO; HAS_MEASURE_0] THEN
+    MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC `{c:real^N}` THEN
+    SIMP_TAC[NEGLIGIBLE_FINITE; FINITE_RULES] THEN SET_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[HAS_MEASURE] THEN
+  ONCE_REWRITE_TAC[HAS_INTEGRAL] THEN REWRITE_TAC[IN_UNIV] THEN
+  DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e:real / abs(m) pow dimindex(:N)`) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_POW_LT; GSYM REAL_ABS_NZ; REAL_POW_LT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `abs(m) * B + norm(c:real^N)` THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 < B /\ &0 <= x ==> &0 < B + x`;
+               NORM_POS_LE; REAL_LT_MUL; GSYM REAL_ABS_NZ; REAL_POW_LT] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN DISCH_TAC THEN
+  REWRITE_TAC[IN_IMAGE] THEN
+  ASM_SIMP_TAC[VECTOR_EQ_AFFINITY; UNWIND_THM1] THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+    [`if &0 <= m then inv m % u + --(inv m % c):real^N
+                 else inv m % v + --(inv m % c)`;
+     `if &0 <= m then inv m % v + --(inv m % c):real^N
+                 else inv m % u + --(inv m % c)`]) THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b ==> c) ==> (a ==> b) ==> c`) THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET] THEN X_GEN_TAC `x:real^N` THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    DISCH_THEN(MP_TAC o SPEC `m % x + c:real^N`) THEN
+    MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[IN_BALL; IN_INTERVAL] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[NORM_ARITH `dist(vec 0,x) = norm(x:real^N)`] THEN
+      DISCH_TAC THEN MATCH_MP_TAC(NORM_ARITH
+       `norm(x:real^N) < a ==> norm(x + y) < a + norm(y)`) THEN
+      ASM_SIMP_TAC[NORM_MUL; REAL_LT_LMUL; GSYM REAL_ABS_NZ];
+      ALL_TAC] THEN
+    SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; VECTOR_NEG_COMPONENT;
+             COND_COMPONENT] THEN
+    MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN MATCH_MP_TAC MONO_IMP THEN
+    REWRITE_TAC[REAL_ARITH `m * u + --(m * c):real = (u - c) * m`] THEN
+    SUBST1_TAC(REAL_ARITH
+      `inv(m) = if &0 <= inv(m) then abs(inv m) else --(abs(inv m))`) THEN
+    SIMP_TAC[REAL_LE_INV_EQ] THEN
+    REWRITE_TAC[REAL_ARITH `(x - y:real) * --z = (y - x) * z`] THEN
+    REWRITE_TAC[REAL_ABS_INV; GSYM real_div] THEN COND_CASES_TAC THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; GSYM REAL_ABS_NZ] THEN
+    ASM_REWRITE_TAC[real_abs] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[SUBSET] THEN DISCH_THEN(MP_TAC o SPEC `vec 0:real^N`) THEN
+  ASM_REWRITE_TAC[CENTRE_IN_BALL] THEN DISCH_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real^1`
+   (fun th -> EXISTS_TAC `(abs m pow dimindex (:N)) % z:real^1` THEN
+              MP_TAC th)) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP(REAL_FIELD `~(x = &0) ==> ~(inv x = &0)`)) THEN
+  REWRITE_TAC[TAUT `a ==> b ==> c <=> b /\ a ==> c`] THEN
+  DISCH_THEN(MP_TAC o SPEC `--(inv m % c):real^N` o
+    MATCH_MP HAS_INTEGRAL_AFFINITY) THEN
+  ASM_REWRITE_TAC[IMAGE_AFFINITY_INTERVAL; REAL_INV_INV] THEN
+  SIMP_TAC[COND_ID] THEN COND_CASES_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC;
+               VECTOR_MUL_LNEG; VECTOR_MUL_RNEG] THEN
+  ASM_SIMP_TAC[REAL_MUL_RINV; VECTOR_MUL_LID; VECTOR_NEG_NEG] THEN
+  REWRITE_TAC[VECTOR_ARITH `(u + --c) + c:real^N = u`] THEN
+  REWRITE_TAC[REAL_ABS_INV; REAL_INV_INV; GSYM REAL_POW_INV] THEN
+  DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN
+  REWRITE_TAC[LIFT_CMUL; GSYM VECTOR_SUB_LDISTRIB] THEN
+  REWRITE_TAC[NORM_MUL; REAL_ABS_POW; REAL_ABS_ABS] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_POW_LT; GSYM REAL_ABS_NZ]);;
+
+let STRETCH_GALOIS = prove
+ (`!x:real^N y:real^N m.
+        (!k. 1 <= k /\ k <= dimindex(:N) ==>  ~(m k = &0))
+        ==> ((y = (lambda k. m k * x$k)) <=> (lambda k. inv(m k) * y$k) = x)`,
+  REPEAT GEN_TAC THEN SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!x. p x ==> (q x <=> r x))
+    ==> (!x. p x) ==> ((!x. q x) <=> (!x. r x))`) THEN
+  GEN_TAC THEN ASM_CASES_TAC `1 <= k /\ k <= dimindex(:N)` THEN
+  ASM_REWRITE_TAC[] THEN CONV_TAC REAL_FIELD);;
+
+let HAS_MEASURE_STRETCH = prove
+ (`!s m y. s has_measure y
+           ==> (IMAGE (\x:real^N. lambda k. m k * x$k) s :real^N->bool)
+               has_measure abs(product (1..dimindex(:N)) m) * y`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC
+   `!k. 1 <= k /\ k <= dimindex(:N) ==> ~(m k = &0)`
+  THENL
+   [ALL_TAC;
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM]) THEN
+    REWRITE_TAC[NOT_IMP; GSYM CONJ_ASSOC; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+    SUBGOAL_THEN `product(1..dimindex (:N)) m = &0` SUBST1_TAC THENL
+     [ASM_MESON_TAC[PRODUCT_EQ_0_NUMSEG]; ALL_TAC] THEN
+    REWRITE_TAC[REAL_ABS_NUM; REAL_MUL_LZERO; HAS_MEASURE_0] THEN
+    MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+    EXISTS_TAC `{x:real^N | x$k = &0}` THEN
+    ASM_SIMP_TAC[NEGLIGIBLE_STANDARD_HYPERPLANE; SUBSET; FORALL_IN_IMAGE] THEN
+    ASM_SIMP_TAC[IN_ELIM_THM; LAMBDA_BETA; REAL_MUL_LZERO]] THEN
+  UNDISCH_TAC `(s:real^N->bool) has_measure y` THEN
+  REWRITE_TAC[HAS_MEASURE] THEN
+  ONCE_REWRITE_TAC[HAS_INTEGRAL] THEN REWRITE_TAC[IN_UNIV] THEN
+  DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `&0 < abs(product(1..dimindex(:N)) m)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[REAL_ABS_NZ; REAL_LT_DIV; PRODUCT_EQ_0_NUMSEG];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e:real / abs(product(1..dimindex(:N)) m)`) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `sup(IMAGE (\k. abs(m k) * B) (1..dimindex(:N)))` THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[REAL_LT_SUP_FINITE; FINITE_IMAGE; NUMSEG_EMPTY; FINITE_NUMSEG;
+                 IN_NUMSEG; GSYM NOT_LE; DIMINDEX_GE_1; IMAGE_EQ_EMPTY;
+                 EXISTS_IN_IMAGE] THEN
+    ASM_MESON_TAC[IN_NUMSEG; DIMINDEX_GE_1; LE_REFL; REAL_LT_MUL; REAL_ABS_NZ];
+    DISCH_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[IN_IMAGE; STRETCH_GALOIS; UNWIND_THM1] THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+    [`(lambda k. min (inv(m k) * (u:real^N)$k)
+                     (inv(m k) * (v:real^N)$k)):real^N`;
+     `(lambda k. max (inv(m k) * (u:real^N)$k)
+                 (inv(m k) * (v:real^N)$k)):real^N`]) THEN
+  MATCH_MP_TAC(TAUT `a /\ (b ==> a ==> c) ==> (a ==> b) ==> c`) THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `z:real^1` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    SUBGOAL_THEN `!k. 1 <= k /\ k <= dimindex (:N) ==> ~(inv(m k) = &0)`
+    MP_TAC THENL [ASM_SIMP_TAC[REAL_INV_EQ_0]; ALL_TAC] THEN
+    ONCE_REWRITE_TAC[GSYM IMP_CONJ_ALT] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_STRETCH)] THEN
+  (MP_TAC(ISPECL [`u:real^N`; `v:real^N`; `\i:num. inv(m i:real)`]
+    IMAGE_STRETCH_INTERVAL) THEN
+   SUBGOAL_THEN `~(interval[u:real^N,v] = {})` ASSUME_TAC THENL
+    [FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+      `s SUBSET t ==> ~(s = {}) ==> ~(t = {})`)) THEN
+     ASM_REWRITE_TAC[BALL_EQ_EMPTY; GSYM REAL_NOT_LT];
+     ALL_TAC] THEN
+   ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o SYM))
+  THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `b SUBSET s ==> b' SUBSET IMAGE f b ==> b' SUBSET IMAGE f s`)) THEN
+    REWRITE_TAC[IN_BALL; SUBSET; NORM_ARITH `dist(vec 0:real^N,x) = norm x`;
+                IN_IMAGE] THEN
+    ASM_SIMP_TAC[STRETCH_GALOIS; REAL_INV_EQ_0; UNWIND_THM1; REAL_INV_INV] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC
+     `norm(sup(IMAGE(\k. abs(m k)) (1..dimindex(:N))) % x:real^N)` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC NORM_LE_COMPONENTWISE THEN
+      SIMP_TAC[LAMBDA_BETA; VECTOR_MUL_COMPONENT; REAL_ABS_MUL] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+      REWRITE_TAC[REAL_ABS_POS] THEN
+      MATCH_MP_TAC(REAL_ARITH `x <= y ==> x <= abs y`) THEN
+      ASM_SIMP_TAC[REAL_LE_SUP_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY;
+                  NUMSEG_EMPTY; FINITE_NUMSEG; GSYM NOT_LE; DIMINDEX_GE_1] THEN
+      REWRITE_TAC[EXISTS_IN_IMAGE; IN_NUMSEG] THEN ASM_MESON_TAC[REAL_LE_REFL];
+      ALL_TAC] THEN
+    REWRITE_TAC[NORM_MUL] THEN MATCH_MP_TAC REAL_LTE_TRANS THEN
+    EXISTS_TAC `abs(sup(IMAGE(\k. abs(m k)) (1..dimindex(:N)))) * B` THEN
+    SUBGOAL_THEN `&0 < sup(IMAGE(\k. abs(m k)) (1..dimindex(:N)))`
+    ASSUME_TAC THENL
+     [ASM_SIMP_TAC[REAL_LT_SUP_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY;
+                  NUMSEG_EMPTY; FINITE_NUMSEG; GSYM NOT_LE; DIMINDEX_GE_1] THEN
+      REWRITE_TAC[EXISTS_IN_IMAGE; GSYM REAL_ABS_NZ; IN_NUMSEG] THEN
+      ASM_MESON_TAC[DIMINDEX_GE_1; LE_REFL];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[REAL_LT_LMUL_EQ; REAL_ARITH `&0 < x ==> &0 < abs x`] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sup(IMAGE(\k. abs(m k)) (1..dimindex(:N))) * B` THEN
+    ASM_SIMP_TAC[REAL_LE_RMUL_EQ; REAL_ARITH `&0 < x ==> abs x <= x`] THEN
+    ASM_SIMP_TAC[REAL_LE_SUP_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY;
+                  NUMSEG_EMPTY; FINITE_NUMSEG; GSYM NOT_LE; DIMINDEX_GE_1] THEN
+    ASM_SIMP_TAC[EXISTS_IN_IMAGE; REAL_LE_RMUL_EQ] THEN
+    ASM_SIMP_TAC[REAL_SUP_LE_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY;
+                 NUMSEG_EMPTY; FINITE_NUMSEG; GSYM NOT_LE; DIMINDEX_GE_1] THEN
+    MP_TAC(ISPEC `IMAGE (\k. abs (m k)) (1..dimindex(:N))` SUP_FINITE) THEN
+    REWRITE_TAC[FORALL_IN_IMAGE] THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; FINITE_NUMSEG; IMAGE_EQ_EMPTY; NUMSEG_EMPTY;
+                 GSYM NOT_LE; DIMINDEX_GE_1] THEN
+    REWRITE_TAC[IN_IMAGE] THEN MESON_TAC[];
+
+    MATCH_MP_TAC(MESON[]
+     `s = t /\ P z ==> (f has_integral z) s ==> Q
+                       ==> ?w. (f has_integral w) t /\ P w`) THEN
+    SIMP_TAC[GSYM PRODUCT_INV; FINITE_NUMSEG; GSYM REAL_ABS_INV] THEN
+    REWRITE_TAC[REAL_INV_INV] THEN CONJ_TAC THENL
+     [REWRITE_TAC[GSYM IMAGE_o] THEN MATCH_MP_TAC(SET_RULE
+       `(!x. f x = x) ==> IMAGE f s = s`) THEN
+      SIMP_TAC[o_THM; LAMBDA_BETA; CART_EQ] THEN
+      ASM_SIMP_TAC[REAL_MUL_ASSOC; REAL_MUL_RINV; REAL_MUL_LID];
+      REWRITE_TAC[ABS_DROP; DROP_SUB; LIFT_DROP; DROP_CMUL] THEN
+      REWRITE_TAC[GSYM REAL_SUB_LDISTRIB; ETA_AX] THEN
+      REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_ABS] THEN
+      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+      ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ] THEN
+      ASM_MESON_TAC[ABS_DROP; DROP_SUB; LIFT_DROP]]]);;
+
+let HAS_MEASURE_TRANSLATION = prove
+ (`!s m a. s has_measure m ==> (IMAGE (\x:real^N. a + x) s) has_measure m`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `&1`; `a:real^N`; `m:real`]
+                HAS_MEASURE_AFFINITY) THEN
+  REWRITE_TAC[VECTOR_MUL_LID; REAL_ABS_NUM; REAL_POW_ONE; REAL_MUL_LID] THEN
+  REWRITE_TAC[VECTOR_ADD_SYM]);;
+
+let NEGLIGIBLE_TRANSLATION = prove
+ (`!s a. negligible s ==> negligible (IMAGE (\x:real^N. a + x) s)`,
+  SIMP_TAC[GSYM HAS_MEASURE_0; HAS_MEASURE_TRANSLATION]);;
+
+let HAS_MEASURE_TRANSLATION_EQ = prove
+ (`!a s m. (IMAGE (\x:real^N. a + x) s) has_measure m <=> s has_measure m`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[HAS_MEASURE_TRANSLATION] THEN
+  DISCH_THEN(MP_TAC o SPEC `--a:real^N` o
+    MATCH_MP HAS_MEASURE_TRANSLATION) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; VECTOR_ARITH `--a + a + b:real^N = b`] THEN
+  SET_TAC[]);;
+
+add_translation_invariants [HAS_MEASURE_TRANSLATION_EQ];;
+
+let MEASURE_TRANSLATION = prove
+ (`!a s. measure(IMAGE (\x:real^N. a + x) s) = measure s`,
+  REWRITE_TAC[measure; HAS_MEASURE_TRANSLATION_EQ]);;
+
+add_translation_invariants [MEASURE_TRANSLATION];;
+
+let NEGLIGIBLE_TRANSLATION_REV = prove
+ (`!s a. negligible (IMAGE (\x:real^N. a + x) s) ==> negligible s`,
+  SIMP_TAC[GSYM HAS_MEASURE_0; HAS_MEASURE_TRANSLATION_EQ]);;
+
+let NEGLIGIBLE_TRANSLATION_EQ = prove
+ (`!a s. negligible (IMAGE (\x:real^N. a + x) s) <=> negligible s`,
+  SIMP_TAC[GSYM HAS_MEASURE_0; HAS_MEASURE_TRANSLATION_EQ]);;
+
+add_translation_invariants [NEGLIGIBLE_TRANSLATION_EQ];;
+
+let MEASURABLE_TRANSLATION_EQ = prove
+ (`!a:real^N s. measurable (IMAGE (\x. a + x) s) <=> measurable s`,
+  REWRITE_TAC[measurable; HAS_MEASURE_TRANSLATION_EQ]);;
+
+add_translation_invariants [MEASURABLE_TRANSLATION_EQ];;
+
+let MEASURABLE_TRANSLATION = prove
+ (`!s a:real^N. measurable s ==> measurable (IMAGE (\x. a + x) s)`,
+  REWRITE_TAC[MEASURABLE_TRANSLATION_EQ]);;
+
+let HAS_MEASURE_SCALING = prove
+ (`!s m c. s has_measure m
+           ==> (IMAGE (\x:real^N. c % x) s) has_measure
+               (abs(c) pow dimindex(:N)) * m`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `c:real`; `vec 0:real^N`; `m:real`]
+                HAS_MEASURE_AFFINITY) THEN
+  REWRITE_TAC[VECTOR_ADD_RID]);;
+
+let HAS_MEASURE_SCALING_EQ = prove
+ (`!s m c. ~(c = &0)
+           ==> (IMAGE (\x:real^N. c % x) s
+                  has_measure (abs(c) pow dimindex(:N)) * m <=>
+                s has_measure m)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REWRITE_TAC[HAS_MEASURE_SCALING] THEN
+  DISCH_THEN(MP_TAC o SPEC `inv(c):real` o MATCH_MP HAS_MEASURE_SCALING) THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; GSYM REAL_ABS_MUL] THEN
+  REWRITE_TAC[GSYM REAL_POW_MUL; VECTOR_MUL_ASSOC; REAL_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[GSYM REAL_ABS_MUL; REAL_MUL_LINV] THEN
+  REWRITE_TAC[REAL_POW_ONE; REAL_ABS_NUM; REAL_MUL_LID; VECTOR_MUL_LID] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN SET_TAC[]);;
+
+let MEASURABLE_SCALING = prove
+ (`!s c. measurable s ==> measurable (IMAGE (\x:real^N. c % x) s)`,
+  REWRITE_TAC[measurable] THEN MESON_TAC[HAS_MEASURE_SCALING]);;
+
+let MEASURABLE_SCALING_EQ = prove
+ (`!s c. ~(c = &0)
+         ==> (measurable (IMAGE (\x:real^N. c % x) s) <=> measurable s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REWRITE_TAC[MEASURABLE_SCALING] THEN
+  DISCH_THEN(MP_TAC o SPEC `inv c:real` o MATCH_MP MEASURABLE_SCALING) THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; GSYM REAL_ABS_MUL] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; VECTOR_MUL_LID] THEN
+  SET_TAC[]);;
+
+let MEASURE_SCALING = prove
+ (`!s. measurable s
+       ==> measure(IMAGE (\x:real^N. c % x) s) =
+              (abs(c) pow dimindex(:N)) * measure s`,
+  REWRITE_TAC[HAS_MEASURE_MEASURE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC MEASURE_UNIQUE THEN ASM_SIMP_TAC[HAS_MEASURE_SCALING]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Measurability of countable unions and intersections of various kinds.     *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_MEASURE_NESTED_UNIONS = prove
+ (`!s:num->real^N->bool B.
+        (!n. measurable(s n)) /\
+        (!n. measure(s n) <= B) /\
+        (!n. s(n) SUBSET s(SUC n))
+        ==> measurable(UNIONS { s(n) | n IN (:num) }) /\
+            ((\n. lift(measure(s n)))
+                  --> lift(measure(UNIONS { s(n) | n IN (:num) })))
+            sequentially`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[TAUT `a ==> b /\ c <=> (a ==> b /\ (b ==> c))`] THEN
+  SIMP_TAC[MEASURE_INTEGRAL_UNIV; LIFT_DROP] THEN
+  REWRITE_TAC[MEASURABLE_INTEGRABLE] THEN
+  STRIP_TAC THEN MATCH_MP_TAC(TAUT `b /\ c ==> b /\ (b ==> c)`) THEN
+  MATCH_MP_TAC MONOTONE_CONVERGENCE_INCREASING THEN
+  ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [REPEAT GEN_TAC THEN REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+    REWRITE_TAC[DROP_VEC; REAL_POS; REAL_LE_REFL] THEN ASM SET_TAC[];
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN COND_CASES_TAC THENL
+     [MATCH_MP_TAC LIM_EVENTUALLY THEN
+      REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_UNIONS]) THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN REWRITE_TAC[EXISTS_IN_IMAGE] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN STRIP_TAC THEN
+      REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+      FIRST_ASSUM(MP_TAC o PART_MATCH (rand o rand)
+                  TRANSITIVE_STEPWISE_LE_EQ o concl) THEN
+      ASM_REWRITE_TAC[SUBSET_TRANS; SUBSET_REFL] THEN ASM SET_TAC[];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [IN_UNIONS]) THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN REWRITE_TAC[EXISTS_IN_IMAGE] THEN
+      SIMP_TAC[NOT_EXISTS_THM; IN_UNIV; LIM_CONST]];
+     RULE_ASSUM_TAC(REWRITE_RULE[GSYM MEASURABLE_INTEGRABLE]) THEN
+     ASM_SIMP_TAC[INTEGRAL_MEASURE_UNIV] THEN
+     REWRITE_TAC[bounded; SIMPLE_IMAGE; FORALL_IN_IMAGE] THEN
+     EXISTS_TAC `B:real` THEN REWRITE_TAC[IN_UNIV; NORM_LIFT] THEN
+     REWRITE_TAC[real_abs] THEN ASM_MESON_TAC[MEASURE_POS_LE]]);;
+
+let MEASURABLE_NESTED_UNIONS = prove
+ (`!s:num->real^N->bool B.
+        (!n. measurable(s n)) /\
+        (!n. measure(s n) <= B) /\
+        (!n. s(n) SUBSET s(SUC n))
+        ==> measurable(UNIONS { s(n) | n IN (:num) })`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_MEASURE_NESTED_UNIONS) THEN
+  SIMP_TAC[]);;
+
+let HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS = prove
+ (`!s:num->real^N->bool B.
+        (!n. measurable(s n)) /\
+        (!m n. ~(m = n) ==> negligible(s m INTER s n)) /\
+        (!n. sum (0..n) (\k. measure(s k)) <= B)
+        ==> measurable(UNIONS { s(n) | n IN (:num) }) /\
+            ((\n. lift(measure(s n))) sums
+             lift(measure(UNIONS { s(n) | n IN (:num) }))) (from 0)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n. UNIONS (IMAGE s (0..n)):real^N->bool`; `B:real`]
+               HAS_MEASURE_NESTED_UNIONS) THEN
+  REWRITE_TAC[sums; FROM_0; INTER_UNIV] THEN
+  SUBGOAL_THEN
+   `!n. (UNIONS (IMAGE s (0..n)):real^N->bool) has_measure
+        (sum(0..n) (\k. measure(s k)))`
+  MP_TAC THENL
+   [GEN_TAC THEN MATCH_MP_TAC HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE THEN
+    ASM_SIMP_TAC[FINITE_NUMSEG];
+    ALL_TAC] THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN
+    ASSUME_TAC(GEN `n:num` (MATCH_MP MEASURE_UNIQUE (SPEC `n:num` th)))) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [ASM_MESON_TAC[measurable]; ALL_TAC] THEN
+    GEN_TAC THEN MATCH_MP_TAC SUBSET_UNIONS THEN
+    MATCH_MP_TAC IMAGE_SUBSET THEN
+    REWRITE_TAC[SUBSET; IN_NUMSEG] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  SIMP_TAC[LIFT_SUM; FINITE_NUMSEG; o_DEF] THEN
+  SUBGOAL_THEN
+   `UNIONS {UNIONS (IMAGE s (0..n)) | n IN (:num)}:real^N->bool =
+    UNIONS (IMAGE s (:num))`
+   (fun th -> REWRITE_TAC[th] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+              REWRITE_TAC[]) THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN X_GEN_TAC `x:real^N` THEN
+  REWRITE_TAC[IN_UNIONS] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE; EXISTS_IN_UNIONS; IN_UNIV] THEN
+  REWRITE_TAC[IN_UNIONS; EXISTS_IN_IMAGE] THEN
+  REWRITE_TAC[IN_NUMSEG; LE_0] THEN MESON_TAC[LE_REFL]);;
+
+let NEGLIGIBLE_COUNTABLE_UNIONS_GEN = prove
+ (`!f. COUNTABLE f /\ (!s:real^N->bool. s IN f ==> negligible s)
+       ==> negligible(UNIONS f)`,
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THEN
+  ASM_REWRITE_TAC[UNIONS_0; NEGLIGIBLE_EMPTY] THEN
+  MP_TAC(ISPEC `f:(real^N->bool)->bool` COUNTABLE_AS_IMAGE) THEN
+  ASM_SIMP_TAC[LEFT_IMP_EXISTS_THM; FORALL_IN_IMAGE; IN_UNIV] THEN
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM SIMPLE_IMAGE] THEN
+  MATCH_MP_TAC NEGLIGIBLE_COUNTABLE_UNIONS THEN ASM_REWRITE_TAC[]);;
+
+let HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS_BOUNDED = prove
+ (`!s:num->real^N->bool.
+        (!n. measurable(s n)) /\
+        (!m n. ~(m = n) ==> negligible(s m INTER s n)) /\
+        bounded(UNIONS { s(n) | n IN (:num) })
+        ==> measurable(UNIONS { s(n) | n IN (:num) }) /\
+            ((\n. lift(measure(s n))) sums
+             lift(measure(UNIONS { s(n) | n IN (:num) }))) (from 0)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+  MATCH_MP_TAC HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS THEN
+  EXISTS_TAC `measure(interval[a:real^N,b])` THEN
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `n:num` THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `measure(UNIONS (IMAGE (s:num->real^N->bool) (0..n)))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_EQ_IMP_LE THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC MEASURE_NEGLIGIBLE_UNIONS_IMAGE THEN
+    ASM_SIMP_TAC[FINITE_NUMSEG];
+    MATCH_MP_TAC MEASURE_SUBSET THEN REWRITE_TAC[MEASURABLE_INTERVAL] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC MEASURABLE_UNIONS THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; FINITE_NUMSEG; FORALL_IN_IMAGE];
+      ASM SET_TAC[]]]);;
+
+let MEASURABLE_COUNTABLE_UNIONS_BOUNDED = prove
+ (`!s:num->real^N->bool.
+        (!n. measurable(s n)) /\
+        bounded(UNIONS { s(n) | n IN (:num) })
+        ==> measurable(UNIONS { s(n) | n IN (:num) })`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `UNIONS { s(n):real^N->bool | n IN (:num) } =
+    UNIONS { UNIONS {s(m) | m IN 0..n} | n IN (:num)}`
+  SUBST1_TAC THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN REWRITE_TAC[IN_UNIONS; IN_ELIM_THM] THEN
+    REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC; UNWIND_THM2; IN_UNIONS; IN_ELIM_THM] THEN
+    REWRITE_TAC[IN_NUMSEG; IN_UNIV; LE_0] THEN MESON_TAC[LE_REFL];
+    MATCH_MP_TAC MEASURABLE_NESTED_UNIONS THEN
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+    EXISTS_TAC `measure(interval[a:real^N,b])` THEN
+    MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+     [GEN_TAC THEN MATCH_MP_TAC MEASURABLE_UNIONS THEN
+      ASM_SIMP_TAC[FORALL_IN_GSPEC] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      SIMP_TAC[FINITE_IMAGE; FINITE_NUMSEG];
+      DISCH_TAC] THEN
+    CONJ_TAC THENL
+     [GEN_TAC THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+      ASM_REWRITE_TAC[MEASURABLE_INTERVAL] THEN ASM SET_TAC[];
+      GEN_TAC THEN REWRITE_TAC[NUMSEG_CLAUSES; LE_0] THEN SET_TAC[]]]);;
+
+let MEASURE_COUNTABLE_UNIONS_LE_STRONG = prove
+ (`!d:num->(real^N->bool) B.
+        (!n. measurable(d n)) /\
+        (!n. measure(UNIONS {d k | k <= n}) <= B)
+        ==> measurable(UNIONS {d n | n IN (:num)}) /\
+            measure(UNIONS {d n | n IN (:num)}) <= B`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n. UNIONS {(d:num->(real^N->bool)) k | k IN (0..n)}`;
+                 `B:real`]
+         HAS_MEASURE_NESTED_UNIONS) THEN REWRITE_TAC[] THEN
+  SUBGOAL_THEN `UNIONS {UNIONS {d k | k IN (0..n)} | n IN (:num)} =
+                UNIONS {d n:real^N->bool | n IN (:num)}`
+  SUBST1_TAC THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_UNIONS; EXISTS_IN_GSPEC; IN_UNIV; IN_NUMSEG; LE_0] THEN
+    MESON_TAC[LE_REFL];
+    ALL_TAC] THEN
+  ANTS_TAC THENL
+   [REPEAT CONJ_TAC THENL
+     [GEN_TAC THEN MATCH_MP_TAC MEASURABLE_UNIONS THEN
+      SIMP_TAC[SIMPLE_IMAGE; FINITE_IMAGE; FINITE_NUMSEG] THEN
+      ASM_REWRITE_TAC[FORALL_IN_IMAGE];
+      ASM_REWRITE_TAC[IN_NUMSEG; LE_0];
+      GEN_TAC THEN REWRITE_TAC[SIMPLE_IMAGE] THEN
+      MATCH_MP_TAC SUBSET_UNIONS THEN MATCH_MP_TAC IMAGE_SUBSET THEN
+      REWRITE_TAC[SUBSET_NUMSEG] THEN ARITH_TAC];
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM(CONJUNCT2 LIFT_DROP)] THEN
+    MATCH_MP_TAC(ISPEC `sequentially` LIM_DROP_UBOUND) THEN
+    EXISTS_TAC `\n. lift(measure(UNIONS {d k | k IN 0..n} :real^N->bool))` THEN
+    ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; EVENTUALLY_SEQUENTIALLY] THEN
+    EXISTS_TAC `0` THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+    ASM_REWRITE_TAC[LIFT_DROP; IN_NUMSEG; LE_0]]);;
+
+let MEASURE_COUNTABLE_UNIONS_LE = prove
+ (`!d:num->(real^N->bool) B.
+        (!n. measurable(d n)) /\
+        (!n. sum(0..n) (\k. measure(d k)) <= B)
+        ==> measurable(UNIONS {d n | n IN (:num)}) /\
+            measure(UNIONS {d n | n IN (:num)}) <= B`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC MEASURE_COUNTABLE_UNIONS_LE_STRONG THEN
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `n:num` THEN
+  MP_TAC(ISPECL [`0..n`;`d:num->real^N->bool`] MEASURE_UNIONS_LE_IMAGE) THEN
+  ASM_REWRITE_TAC[FINITE_NUMSEG] THEN
+  REPEAT(FIRST_X_ASSUM (MP_TAC o SPEC `n:num`)) THEN
+  REWRITE_TAC[GSYM SIMPLE_IMAGE; numseg; LE_0; IN_ELIM_THM] THEN
+  MESON_TAC[REAL_LE_TRANS]);;
+
+let MEASURABLE_COUNTABLE_UNIONS_STRONG = prove
+ (`!s:num->real^N->bool B.
+        (!n. measurable(s n)) /\
+        (!n. measure(UNIONS {s k | k <= n}) <= B)
+        ==> measurable(UNIONS { s(n) | n IN (:num) })`,
+  MESON_TAC[MEASURE_COUNTABLE_UNIONS_LE_STRONG; REAL_LE_REFL]);;
+
+let MEASURABLE_COUNTABLE_UNIONS = prove
+ (`!s:num->real^N->bool B.
+        (!n. measurable(s n)) /\
+        (!n. sum (0..n) (\k. measure(s k)) <= B)
+        ==> measurable(UNIONS { s(n) | n IN (:num) })`,
+  MESON_TAC[MEASURE_COUNTABLE_UNIONS_LE; REAL_LE_REFL]);;
+
+let MEASURE_COUNTABLE_UNIONS_LE_STRONG_GEN = prove
+ (`!D B. COUNTABLE D /\
+         (!d:real^N->bool. d IN D ==> measurable d) /\
+         (!D'. D' SUBSET D /\ FINITE D' ==> measure(UNIONS D') <= B)
+         ==> measurable(UNIONS D) /\ measure(UNIONS D) <= B`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `D:(real^N->bool)->bool = {}` THENL
+   [ASM_SIMP_TAC[UNIONS_0; MEASURABLE_EMPTY; SUBSET_EMPTY] THEN
+    MESON_TAC[FINITE_EMPTY];
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    MP_TAC(ISPEC `D:(real^N->bool)->bool` COUNTABLE_AS_IMAGE) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:num->real^N->bool` SUBST1_TAC) THEN
+    REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; FORALL_SUBSET_IMAGE] THEN
+    REWRITE_TAC[IN_UNIV; SUBSET_UNIV] THEN REPEAT DISCH_TAC THEN
+    ONCE_REWRITE_TAC[GSYM SIMPLE_IMAGE] THEN
+    MATCH_MP_TAC MEASURE_COUNTABLE_UNIONS_LE_STRONG THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `n:num` THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `{k:num | k <= n}`) THEN
+    SIMP_TAC[FINITE_NUMSEG_LE; FINITE_IMAGE] THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN
+    REPLICATE_TAC 3 AP_TERM_TAC THEN SET_TAC[]]);;
+
+let MEASURE_COUNTABLE_UNIONS_LE_GEN = prove
+ (`!D B. COUNTABLE D /\
+         (!d:real^N->bool. d IN D ==> measurable d) /\
+         (!D'. D' SUBSET D /\ FINITE D' ==> sum D' (\d. measure d) <= B)
+         ==> measurable(UNIONS D) /\ measure(UNIONS D) <= B`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC MEASURE_COUNTABLE_UNIONS_LE_STRONG_GEN THEN
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `D':(real^N->bool)->bool` THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `D':(real^N->bool)->bool`) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_LE_TRANS) THEN
+  MATCH_MP_TAC MEASURE_UNIONS_LE THEN ASM SET_TAC[]);;
+
+let MEASURABLE_COUNTABLE_INTERS = prove
+ (`!s:num->real^N->bool.
+        (!n. measurable(s n))
+        ==> measurable(INTERS { s(n) | n IN (:num) })`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `INTERS { s(n):real^N->bool | n IN (:num) } =
+                s 0 DIFF (UNIONS {s 0 DIFF s n | n IN (:num)})`
+  SUBST1_TAC THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_INTERS; IN_DIFF; IN_UNIONS] THEN
+    REWRITE_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE; EXISTS_IN_IMAGE] THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MEASURABLE_DIFF THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MEASURABLE_COUNTABLE_UNIONS_STRONG THEN
+  EXISTS_TAC `measure(s 0:real^N->bool)` THEN
+  ASM_SIMP_TAC[MEASURABLE_DIFF; LE_0] THEN
+  GEN_TAC THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[SUBSET; FORALL_IN_UNIONS; IN_ELIM_THM; IN_DIFF] THEN
+    MESON_TAC[IN_DIFF]] THEN
+  ONCE_REWRITE_TAC[GSYM IN_NUMSEG_0] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; FINITE_IMAGE; FINITE_NUMSEG;
+               MEASURABLE_DIFF; MEASURABLE_UNIONS]);;
+
+let MEASURABLE_COUNTABLE_INTERS_GEN = prove
+ (`!D. COUNTABLE D /\ ~(D = {}) /\
+       (!d:real^N->bool. d IN D ==> measurable d)
+       ==> measurable(INTERS D)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `D:(real^N->bool)->bool` COUNTABLE_AS_IMAGE) THEN
+  ASM_SIMP_TAC[LEFT_IMP_EXISTS_THM; FORALL_IN_IMAGE; IN_UNIV] THEN
+  GEN_TAC THEN DISCH_THEN SUBST_ALL_TAC THEN
+  ONCE_REWRITE_TAC[GSYM SIMPLE_IMAGE] THEN
+  MATCH_MP_TAC MEASURABLE_COUNTABLE_INTERS THEN ASM SET_TAC[]);;
+
+let MEASURE_COUNTABLE_UNIONS_APPROACHABLE = prove
+ (`!D B e.
+        COUNTABLE D /\
+        (!d. d IN D ==> measurable d) /\
+        (!D'. D' SUBSET D /\ FINITE D' ==> measure(UNIONS D') <= B) /\
+        &0 < e
+        ==> ?D'. D' SUBSET D /\ FINITE D' /\
+                 measure(UNIONS D) - e < measure(UNIONS D':real^N->bool)`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `D:(real^N->bool)->bool = {}` THENL
+   [DISCH_TAC THEN EXISTS_TAC `{}:(real^N->bool)->bool` THEN
+    ASM_REWRITE_TAC[EMPTY_SUBSET; FINITE_EMPTY; UNIONS_0; MEASURE_EMPTY] THEN
+    ASM_REAL_ARITH_TAC;
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    MP_TAC(ISPEC `D:(real^N->bool)->bool` COUNTABLE_AS_IMAGE) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:num->real^N->bool` SUBST1_TAC) THEN
+    REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; EXISTS_SUBSET_IMAGE;
+                FORALL_SUBSET_IMAGE] THEN
+    REWRITE_TAC[IN_UNIV; SUBSET_UNIV] THEN REPEAT DISCH_TAC THEN
+    MP_TAC(ISPECL
+     [`\n. UNIONS(IMAGE (d:num->real^N->bool) {k | k <= n})`;
+                   `B:real`] HAS_MEASURE_NESTED_UNIONS) THEN
+    REWRITE_TAC[] THEN ANTS_TAC THENL
+     [ASM_SIMP_TAC[MEASURABLE_UNIONS; FORALL_IN_IMAGE; FINITE_IMAGE;
+                   FINITE_NUMSEG_LE; IN_ELIM_THM] THEN
+      GEN_TAC THEN MATCH_MP_TAC SUBSET_UNIONS THEN
+      MATCH_MP_TAC IMAGE_SUBSET THEN
+      REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `UNIONS {UNIONS (IMAGE d {k | k <= n}) | n IN (:num)}:real^N->bool =
+      UNIONS (IMAGE d (:num))`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[UNIONS_IMAGE] THEN REWRITE_TAC[UNIONS_GSPEC] THEN
+      REWRITE_TAC[IN_UNIV; IN_ELIM_THM; EXTENSION] THEN
+      MESON_TAC[LE_REFL];
+      ALL_TAC] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    REWRITE_TAC[LIM_SEQUENTIALLY; DIST_REAL; GSYM drop; LIFT_DROP] THEN
+    DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:num` (MP_TAC o SPEC `n:num`)) THEN
+    REWRITE_TAC[LE_REFL] THEN DISCH_TAC THEN
+    EXISTS_TAC `{k:num | k <= n}` THEN
+    SIMP_TAC[FINITE_IMAGE; FINITE_NUMSEG_LE] THEN
+    ASM_SIMP_TAC[REAL_ARITH `abs(x - u) < e /\ &0 < e ==> u - e < x`]]);;
+
+let HAS_MEASURE_NESTED_INTERS = prove
+ (`!s:num->real^N->bool.
+        (!n. measurable(s n)) /\
+        (!n. s(SUC n) SUBSET s(n))
+        ==> measurable(INTERS {s n | n IN (:num)}) /\
+            ((\n. lift(measure (s n))) -->
+                  lift(measure (INTERS {s n | n IN (:num)}))) sequentially`,
+  GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`\n. (s:num->real^N->bool) 0 DIFF s n`; `measure(s 0:real^N->bool)`]
+        HAS_MEASURE_NESTED_UNIONS) THEN
+  ASM_SIMP_TAC[MEASURABLE_DIFF] THEN ANTS_TAC THENL
+   [CONJ_TAC THEN X_GEN_TAC `n:num` THENL
+     [MATCH_MP_TAC MEASURE_SUBSET THEN
+      ASM_SIMP_TAC[MEASURABLE_DIFF; SUBSET_DIFF] THEN SET_TAC[];
+      REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `n:num`)) THEN SET_TAC[]];
+    SUBGOAL_THEN
+     `UNIONS {s 0 DIFF s n | n IN (:num)} =
+      s 0 DIFF INTERS {s n :real^N->bool | n IN (:num)}`
+     (fun th -> REWRITE_TAC[th])
+    THENL [REWRITE_TAC[DIFF_INTERS] THEN SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+     [DISCH_TAC THEN
+      SUBGOAL_THEN
+       `measurable(s 0 DIFF (s 0 DIFF INTERS {s n | n IN (:num)})
+                   :real^N->bool)`
+      MP_TAC THENL [ASM_SIMP_TAC[MEASURABLE_DIFF]; ALL_TAC] THEN
+      MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN MATCH_MP_TAC(SET_RULE
+       `t SUBSET s ==> s DIFF (s DIFF t) = t`) THEN
+      REWRITE_TAC[SUBSET; INTERS_GSPEC; IN_ELIM_THM] THEN SET_TAC[];
+
+      MP_TAC(ISPECL [`sequentially`; `lift(measure(s 0:real^N->bool))`]
+        LIM_CONST) THEN REWRITE_TAC[IMP_IMP] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP LIM_SUB) THEN
+      REWRITE_TAC[GSYM LIFT_SUB] THEN MATCH_MP_TAC EQ_IMP THEN
+      AP_THM_TAC THEN BINOP_TAC THEN REWRITE_TAC[LIFT_EQ; FUN_EQ_THM] THEN
+      REPEAT GEN_TAC THEN
+      REWRITE_TAC[REAL_ARITH `s - m:real = n <=> m = s - n`] THEN
+      MATCH_MP_TAC MEASURE_DIFF_SUBSET THEN
+      ASM_SIMP_TAC[MEASURABLE_COUNTABLE_INTERS] THENL
+       [ALL_TAC; SET_TAC[]] THEN
+      MP_TAC(ISPEC `\m n:num. (s n :real^N->bool) SUBSET (s m)`
+          TRANSITIVE_STEPWISE_LE) THEN
+      ASM_REWRITE_TAC[] THEN
+      ANTS_TAC THENL [SET_TAC[]; MESON_TAC[LE_0]]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Measurability of compact and bounded open sets.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_COMPACT = prove
+ (`!s:real^N->bool. compact s ==> measurable s`,
+  let lemma = prove
+   (`!f s:real^N->bool.
+          (!n. FINITE(f n)) /\
+          (!n. s SUBSET UNIONS(f n)) /\
+          (!x. ~(x IN s) ==> ?n. ~(x IN UNIONS(f n))) /\
+          (!n a. a IN f(SUC n) ==> ?b. b IN f(n) /\ a SUBSET b) /\
+          (!n a. a IN f(n) ==> measurable a)
+          ==> measurable s`,
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `!n. UNIONS(f(SUC n):(real^N->bool)->bool) SUBSET UNIONS(f n)`
+    ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN `s = INTERS { UNIONS(f n) | n IN (:num) }:real^N->bool`
+    SUBST1_TAC THENL
+     [ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THEN
+      REWRITE_TAC[SUBSET; IN_INTERS; FORALL_IN_IMAGE; IN_UNIV] THEN
+      REWRITE_TAC[IN_IMAGE] THEN ASM SET_TAC[];
+      MATCH_MP_TAC MEASURABLE_COUNTABLE_INTERS THEN
+      ASM_REWRITE_TAC[] THEN GEN_TAC THEN
+      MATCH_MP_TAC MEASURABLE_UNIONS THEN
+      ASM_MESON_TAC[]]) in
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC lemma THEN
+  EXISTS_TAC
+   `\n. { k | ?u:real^N. (!i. 1 <= i /\ i <= dimindex(:N)
+                              ==> integer(u$i)) /\
+                  k = { x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
+                                       ==> u$i / &2 pow n <= x$i /\
+                                           x$i < (u$i + &1) / &2 pow n } /\
+                  ~(s INTER k = {})}` THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN REPEAT CONJ_TAC THENL
+   [X_GEN_TAC `n:num` THEN
+    SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LT_RDIV_EQ; REAL_LT_POW2] THEN
+    SUBGOAL_THEN
+     `?N. !x:real^N i. x IN s /\ 1 <= i /\ i <= dimindex(:N)
+                       ==> abs(x$i * &2 pow n) < &N`
+    STRIP_ASSUME_TAC THENL
+     [FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_IMP_BOUNDED) THEN
+      REWRITE_TAC[BOUNDED_POS; LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `B:real` THEN STRIP_TAC THEN
+      MP_TAC(SPEC `B * &2 pow n` (MATCH_MP REAL_ARCH REAL_LT_01)) THEN
+      MATCH_MP_TAC MONO_EXISTS THEN REWRITE_TAC[REAL_MUL_RID] THEN
+      X_GEN_TAC `N:num` THEN
+      REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_POW; REAL_ABS_NUM] THEN
+      SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_LT_POW2] THEN
+      ASM_MESON_TAC[COMPONENT_LE_NORM; REAL_LE_TRANS; REAL_LET_TRANS];
+      ALL_TAC] THEN
+    MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC
+     `IMAGE (\u. {x | !i. 1 <= i /\ i <= dimindex(:N)
+                          ==> (u:real^N)$i <= (x:real^N)$i * &2 pow n /\
+                              x$i * &2 pow n < u$i + &1})
+            {u | !i. 1 <= i /\ i <= dimindex(:N) ==> integer (u$i) /\
+                                                     abs(u$i) <= &N}` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC FINITE_IMAGE THEN MATCH_MP_TAC FINITE_CART THEN
+      REWRITE_TAC[GSYM REAL_BOUNDS_LE; FINITE_INTSEG];
+      REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_IMAGE] THEN
+      X_GEN_TAC `l:real^N->bool` THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real^N` THEN
+      STRIP_TAC THEN FIRST_X_ASSUM SUBST_ALL_TAC THEN ASM_SIMP_TAC[] THEN
+      X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+      MATCH_MP_TAC REAL_LE_REVERSE_INTEGERS THEN
+      ASM_SIMP_TAC[INTEGER_CLOSED] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `x:real^N` MP_TAC) THEN
+      REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `k:num`)) THEN
+      ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `k:num`]) THEN
+      ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC];
+    X_GEN_TAC `n:num` THEN REWRITE_TAC[SUBSET; IN_UNIONS; IN_ELIM_THM] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    EXISTS_TAC `(lambda i. floor(&2 pow n * (x:real^N)$i)):real^N` THEN
+    ONCE_REWRITE_TAC[TAUT `(a /\ b /\ c) /\ d <=> b /\ a /\ c /\ d`] THEN
+    REWRITE_TAC[UNWIND_THM2] THEN SIMP_TAC[LAMBDA_BETA; FLOOR] THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+    REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN EXISTS_TAC `x:real^N` THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM] THEN
+    SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LT_RDIV_EQ; REAL_LT_POW2] THEN
+    REWRITE_TAC[REAL_MUL_SYM; FLOOR];
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_IMP_CLOSED) THEN
+    REWRITE_TAC[closed; open_def] THEN
+    DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+    ASM_REWRITE_TAC[IN_DIFF; IN_UNIV] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    MP_TAC(SPECL [`inv(&2)`; `e / &(dimindex(:N))`] REAL_ARCH_POW_INV) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_RDIV_EQ; REAL_OF_NUM_LT;
+                 DIMINDEX_GE_1; ARITH_RULE `0 < x <=> 1 <= x`] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+    REWRITE_TAC[IN_UNIONS; IN_ELIM_THM] THEN
+    REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    ONCE_REWRITE_TAC[TAUT `(a /\ b /\ c) /\ d <=> b /\ a /\ c /\ d`] THEN
+    REWRITE_TAC[UNWIND_THM2] THEN REWRITE_TAC[NOT_EXISTS_THM] THEN
+    X_GEN_TAC `u:real^N` THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC o CONJUNCT2) THEN
+    DISCH_THEN(X_CHOOSE_THEN `y:real^N`
+     (CONJUNCTS_THEN2 MP_TAC ASSUME_TAC)) THEN
+    REWRITE_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `d < e ==> x <= d ==> x < e`)) THEN
+    REWRITE_TAC[dist] THEN
+    W(MP_TAC o PART_MATCH lhand NORM_LE_L1 o lhand o snd) THEN
+    MATCH_MP_TAC(REAL_ARITH `a <= b ==> x <= a ==> x <= b`) THEN
+    GEN_REWRITE_TAC (funpow 3 RAND_CONV) [GSYM CARD_NUMSEG_1] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN MATCH_MP_TAC SUM_BOUND THEN
+    SIMP_TAC[FINITE_NUMSEG; IN_NUMSEG; VECTOR_SUB_COMPONENT] THEN
+    X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `k:num`)) THEN
+    ASM_REWRITE_TAC[real_div; REAL_ADD_RDISTRIB] THEN
+    REWRITE_TAC[REAL_MUL_LID; GSYM REAL_POW_INV] THEN REAL_ARITH_TAC;
+    MAP_EVERY X_GEN_TAC [`n:num`; `a:real^N->bool`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^N`
+     (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (ASSUME_TAC o SYM) ASSUME_TAC) THEN
+    REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    ONCE_REWRITE_TAC[TAUT `(a /\ b /\ c) /\ d <=> b /\ a /\ c /\ d`] THEN
+    REWRITE_TAC[UNWIND_THM2] THEN
+    EXISTS_TAC `(lambda i. floor((u:real^N)$i / &2)):real^N` THEN
+    ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; LAMBDA_BETA; FLOOR] THEN
+    MATCH_MP_TAC(SET_RULE `~(s INTER a = {}) /\ a SUBSET b
+                           ==> ~(s INTER b = {}) /\ a SUBSET b`) THEN
+    ASM_REWRITE_TAC[] THEN EXPAND_TAC "a" THEN REWRITE_TAC[SUBSET] THEN
+    X_GEN_TAC `x:real^N` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `k:num` THEN
+    DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[real_pow; real_div; REAL_INV_MUL; REAL_MUL_ASSOC] THEN
+    REWRITE_TAC[GSYM real_div] THEN
+    SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LT_RDIV_EQ; REAL_LT_POW2] THEN
+    MP_TAC(SPEC `(u:real^N)$k / &2` FLOOR) THEN
+    REWRITE_TAC[REAL_ARITH `u / &2 < floor(u / &2) + &1 <=>
+                            u < &2 * floor(u / &2) + &2`] THEN
+    ASM_SIMP_TAC[REAL_LT_INTEGERS; INTEGER_CLOSED; FLOOR_FRAC] THEN
+    REAL_ARITH_TAC;
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`n:num`; `a:real^N->bool`; `u:real^N`] THEN
+    DISCH_THEN(SUBST1_TAC o CONJUNCT1 o CONJUNCT2) THEN
+    ONCE_REWRITE_TAC[MEASURABLE_INNER_OUTER] THEN
+    GEN_TAC THEN DISCH_TAC THEN
+    EXISTS_TAC `interval(inv(&2 pow n) % u:real^N,
+                         inv(&2 pow n) % (u + vec 1))` THEN
+    EXISTS_TAC `interval[inv(&2 pow n) % u:real^N,
+                         inv(&2 pow n) % (u + vec 1)]` THEN
+    REWRITE_TAC[MEASURABLE_INTERVAL; MEASURE_INTERVAL] THEN
+    ASM_REWRITE_TAC[REAL_SUB_REFL; REAL_ABS_0] THEN
+    REWRITE_TAC[SUBSET; IN_INTERVAL; IN_ELIM_THM] THEN
+    CONJ_TAC THEN X_GEN_TAC `y:real^N` THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `k:num` THEN
+    DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+    ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; VECTOR_ADD_COMPONENT;
+                 VEC_COMPONENT] THEN
+    REAL_ARITH_TAC]);;
+
+let MEASURABLE_OPEN = prove
+ (`!s:real^N->bool. bounded s /\ open s ==> measurable s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP (SET_RULE
+   `s SUBSET t ==> s = t DIFF (t DIFF s)`)) THEN
+  MATCH_MP_TAC MEASURABLE_DIFF THEN
+  REWRITE_TAC[MEASURABLE_INTERVAL] THEN
+  MATCH_MP_TAC MEASURABLE_COMPACT THEN
+  SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; BOUNDED_DIFF; BOUNDED_INTERVAL] THEN
+  MATCH_MP_TAC CLOSED_DIFF THEN ASM_REWRITE_TAC[CLOSED_INTERVAL]);;
+
+let MEASURE_OPEN_POS_LT = prove
+ (`!s. open s /\ bounded s /\ ~(s = {}) ==> &0 < measure s`,
+  MESON_TAC[OPEN_NOT_NEGLIGIBLE; MEASURABLE_MEASURE_POS_LT; MEASURABLE_OPEN]);;
+
+let MEASURABLE_CLOSURE = prove
+ (`!s. bounded s ==> measurable(closure s)`,
+  SIMP_TAC[MEASURABLE_COMPACT; COMPACT_EQ_BOUNDED_CLOSED; CLOSED_CLOSURE;
+           BOUNDED_CLOSURE]);;
+
+let MEASURABLE_INTERIOR = prove
+ (`!s. bounded s ==> measurable(interior s)`,
+  SIMP_TAC[MEASURABLE_OPEN; OPEN_INTERIOR; BOUNDED_INTERIOR]);;
+
+let MEASURABLE_FRONTIER = prove
+ (`!s:real^N->bool. bounded s ==> measurable(frontier s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[frontier] THEN
+  MATCH_MP_TAC MEASURABLE_DIFF THEN
+  ASM_SIMP_TAC[MEASURABLE_CLOSURE; MEASURABLE_INTERIOR] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `s:real^N->bool` THEN
+  REWRITE_TAC[INTERIOR_SUBSET; CLOSURE_SUBSET]);;
+
+let MEASURE_FRONTIER = prove
+ (`!s:real^N->bool.
+        bounded s
+        ==> measure(frontier s) = measure(closure s) - measure(interior s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[frontier] THEN
+  MATCH_MP_TAC MEASURE_DIFF_SUBSET THEN
+  ASM_SIMP_TAC[MEASURABLE_CLOSURE; MEASURABLE_INTERIOR] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `s:real^N->bool` THEN
+  REWRITE_TAC[INTERIOR_SUBSET; CLOSURE_SUBSET]);;
+
+let MEASURE_CLOSURE = prove
+ (`!s:real^N->bool.
+        bounded s /\ negligible(frontier s)
+        ==> measure(closure s) = measure s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_NEGLIGIBLE_SYMDIFF THEN
+  ASM_SIMP_TAC[MEASURABLE_CLOSURE] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    NEGLIGIBLE_SUBSET)) THEN
+  MP_TAC(ISPEC `s:real^N->bool` INTERIOR_SUBSET) THEN
+  MP_TAC(ISPEC `s:real^N->bool` CLOSURE_SUBSET) THEN
+  REWRITE_TAC[frontier] THEN SET_TAC[]);;
+
+let MEASURE_INTERIOR = prove
+ (`!s:real^N->bool.
+        bounded s /\ negligible(frontier s)
+        ==> measure(interior s) = measure s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_NEGLIGIBLE_SYMDIFF THEN
+  ASM_SIMP_TAC[MEASURABLE_INTERIOR] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    NEGLIGIBLE_SUBSET)) THEN
+  MP_TAC(ISPEC `s:real^N->bool` INTERIOR_SUBSET) THEN
+  MP_TAC(ISPEC `s:real^N->bool` CLOSURE_SUBSET) THEN
+  REWRITE_TAC[frontier] THEN SET_TAC[]);;
+
+let MEASURABLE_JORDAN = prove
+ (`!s:real^N->bool. bounded s /\ negligible(frontier s) ==> measurable s`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[MEASURABLE_INNER_OUTER] THEN
+  GEN_TAC THEN DISCH_TAC THEN
+  EXISTS_TAC `interior(s):real^N->bool` THEN
+  EXISTS_TAC `closure(s):real^N->bool` THEN
+  ASM_SIMP_TAC[MEASURABLE_INTERIOR; MEASURABLE_CLOSURE] THEN
+  REWRITE_TAC[INTERIOR_SUBSET; CLOSURE_SUBSET] THEN
+  ONCE_REWRITE_TAC[REAL_ABS_SUB] THEN
+  ASM_SIMP_TAC[GSYM MEASURE_FRONTIER; REAL_ABS_NUM; MEASURE_EQ_0]);;
+
+let HAS_MEASURE_ELEMENTARY = prove
+ (`!d s. d division_of s ==> s has_measure (sum d content)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[has_measure] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP DIVISION_OF_FINITE) THEN
+  ASM_SIMP_TAC[LIFT_SUM] THEN
+  MATCH_MP_TAC HAS_INTEGRAL_COMBINE_DIVISION THEN
+  ASM_REWRITE_TAC[o_THM] THEN REWRITE_TAC[GSYM has_measure] THEN
+  ASM_MESON_TAC[HAS_MEASURE_INTERVAL; division_of]);;
+
+let MEASURABLE_ELEMENTARY = prove
+ (`!d s. d division_of s ==> measurable s`,
+  REWRITE_TAC[measurable] THEN MESON_TAC[HAS_MEASURE_ELEMENTARY]);;
+
+let MEASURE_ELEMENTARY = prove
+ (`!d s. d division_of s ==> measure s = sum d content`,
+  MESON_TAC[HAS_MEASURE_ELEMENTARY; MEASURE_UNIQUE]);;
+
+let MEASURABLE_INTER_INTERVAL = prove
+ (`!s a b:real^N. measurable s ==> measurable (s INTER interval[a,b])`,
+  SIMP_TAC[MEASURABLE_INTER; MEASURABLE_INTERVAL]);;
+
+let MEASURABLE_INSIDE = prove
+ (`!s:real^N->bool. compact s ==> measurable(inside s)`,
+  SIMP_TAC[MEASURABLE_OPEN; BOUNDED_INSIDE; COMPACT_IMP_CLOSED;
+           OPEN_INSIDE; COMPACT_IMP_BOUNDED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A nice lemma for negligibility proofs.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let STARLIKE_NEGLIGIBLE_BOUNDED_MEASURABLE = prove
+ (`!s. measurable s /\ bounded s /\
+       (!c x:real^N. &0 <= c /\ x IN s /\ (c % x) IN s ==> c = &1)
+       ==> negligible s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `~(&0 < measure(s:real^N->bool))`
+   (fun th -> ASM_MESON_TAC[th; MEASURABLE_MEASURE_POS_LT]) THEN
+  DISCH_TAC THEN
+  MP_TAC(SPEC `(vec 0:real^N) INSERT s`
+      BOUNDED_SUBSET_CLOSED_INTERVAL_SYMMETRIC) THEN
+  ASM_SIMP_TAC[BOUNDED_INSERT; COMPACT_IMP_BOUNDED; NOT_EXISTS_THM] THEN
+  X_GEN_TAC `a:real^N` THEN REWRITE_TAC[INSERT_SUBSET] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?N. EVEN N /\ &0 < &N /\
+        measure(interval[--a:real^N,a])
+         < (&N * measure(s:real^N->bool)) / &4 pow dimindex (:N)`
+  STRIP_ASSUME_TAC THENL
+   [FIRST_ASSUM(MP_TAC o SPEC
+     `measure(interval[--a:real^N,a]) * &4 pow (dimindex(:N))` o
+     MATCH_MP REAL_ARCH) THEN
+    SIMP_TAC[REAL_LT_RDIV_EQ; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+    SIMP_TAC[GSYM REAL_LT_LDIV_EQ; ASSUME `&0 < measure(s:real^N->bool)`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `N:num` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `2 * (N DIV 2 + 1)` THEN REWRITE_TAC[EVEN_MULT; ARITH] THEN
+    CONJ_TAC THENL [ARITH_TAC; ALL_TAC] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `x < a ==> a <= b ==> x < b`)) THEN
+    REWRITE_TAC[REAL_OF_NUM_LE] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`UNIONS (IMAGE (\m. IMAGE (\x:real^N. (&m / &N) % x) s)
+                                (1..N))`;
+                  `interval[--a:real^N,a]`] MEASURE_SUBSET) THEN
+  MP_TAC(ISPECL [`measure:(real^N->bool)->real`;
+                 `IMAGE (\m. IMAGE (\x:real^N. (&m / &N) % x) s) (1..N)`]
+                HAS_MEASURE_DISJOINT_UNIONS) THEN
+  SIMP_TAC[FINITE_IMAGE; FINITE_NUMSEG; IMP_CONJ] THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN ANTS_TAC THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM HAS_MEASURE_MEASURE] THEN
+    MATCH_MP_TAC MEASURABLE_SCALING THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP] THEN
+  ONCE_REWRITE_TAC[TAUT `(a /\ b) /\ ~c ==> d <=> a /\ b /\ ~d ==> c`] THEN
+  SUBGOAL_THEN
+   `!m n. m IN 1..N /\ n IN 1..N /\
+          ~(DISJOINT (IMAGE (\x:real^N. &m / &N % x) s)
+                     (IMAGE (\x. &n / &N % x) s))
+          ==> m = n`
+  ASSUME_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    REWRITE_TAC[DISJOINT; GSYM MEMBER_NOT_EMPTY] THEN
+    REWRITE_TAC[EXISTS_IN_IMAGE; IN_INTER] THEN
+    DISCH_THEN(X_CHOOSE_THEN `x:real^N`
+     (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    REWRITE_TAC[IN_IMAGE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `y:real^N`
+     (CONJUNCTS_THEN2 MP_TAC ASSUME_TAC)) THEN
+    DISCH_THEN(MP_TAC o AP_TERM `(%) (&N / &m) :real^N->real^N`) THEN
+    SUBGOAL_THEN `~(&N = &0) /\ ~(&m = &0)` STRIP_ASSUME_TAC THENL
+     [REWRITE_TAC[REAL_OF_NUM_EQ] THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_NUMSEG])) THEN
+      ARITH_TAC;
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(ASSUME_TAC o GEN_REWRITE_RULE (BINDER_CONV o BINDER_CONV)
+     [GSYM CONTRAPOS_THM]) THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_FIELD
+     `~(x = &0) /\ ~(y = &0) ==> x / y * y / x = &1`] THEN
+    ASM_SIMP_TAC[REAL_FIELD
+     `~(x = &0) /\ ~(y = &0) ==> x / y * z / x = z / y`] THEN
+    REWRITE_TAC[VECTOR_MUL_LID] THEN DISCH_THEN SUBST_ALL_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`&n / &m`; `y:real^N`]) THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; REAL_POS; REAL_FIELD
+     `~(y = &0) ==> (x / y = &1 <=> x = y)`] THEN
+    REWRITE_TAC[REAL_OF_NUM_EQ; EQ_SYM_EQ];
+    ALL_TAC] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[]; DISCH_TAC] THEN
+  REWRITE_TAC[NOT_IMP] THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[measurable] THEN ASM_MESON_TAC[];
+    REWRITE_TAC[MEASURABLE_INTERVAL];
+    REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `n:num` THEN DISCH_TAC THEN X_GEN_TAC `x:real^N` THEN
+    DISCH_TAC THEN
+    MP_TAC(ISPECL [`--a:real^N`; `a:real^N`] CONVEX_INTERVAL) THEN
+    DISCH_THEN(MP_TAC o REWRITE_RULE[CONVEX_ALT] o CONJUNCT1) THEN
+    DISCH_THEN(MP_TAC o SPECL [`vec 0:real^N`; `x:real^N`; `&n / &N`]) THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+    DISCH_THEN MATCH_MP_TAC THEN SIMP_TAC[REAL_LE_DIV; REAL_POS] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_NUMSEG]) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (ARITH_RULE
+     `1 <= n /\ n <= N ==> 0 < N /\ n <= N`)) THEN
+    SIMP_TAC[GSYM REAL_OF_NUM_LE; GSYM REAL_OF_NUM_LT; REAL_LE_LDIV_EQ] THEN
+    SIMP_TAC[REAL_MUL_LID];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP MEASURE_UNIQUE) THEN
+  ASM_SIMP_TAC[MEASURE_SCALING; REAL_NOT_LE] THEN
+  FIRST_X_ASSUM(K ALL_TAC o SPEC `&0`) THEN
+  MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC
+   `sum (1..N) (measure o (\m. IMAGE (\x:real^N. &m / &N % x) s))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC REAL_EQ_IMP_LE THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC SUM_IMAGE THEN REWRITE_TAC[] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[SET_RULE `DISJOINT s s <=> s = {}`; IMAGE_EQ_EMPTY] THEN
+    DISCH_THEN SUBST_ALL_TAC THEN
+    ASM_MESON_TAC[REAL_LT_REFL; MEASURE_EMPTY]] THEN
+  FIRST_X_ASSUM(K ALL_TAC o SPEC `0`) THEN
+  ASM_SIMP_TAC[o_DEF; MEASURE_SCALING; SUM_RMUL] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+   `x < a ==> a <= b ==> x < b`)) THEN
+  ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `(a * b) * c:real = (a * c) * b`] THEN
+  ASM_SIMP_TAC[REAL_LE_RMUL_EQ] THEN REWRITE_TAC[GSYM SUM_RMUL] THEN
+  REWRITE_TAC[GSYM REAL_POW_MUL] THEN
+  REWRITE_TAC[REAL_ABS_DIV; REAL_ABS_NUM] THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `M:num` SUBST_ALL_TAC o
+        GEN_REWRITE_RULE I [EVEN_EXISTS]) THEN
+  REWRITE_TAC[GSYM REAL_OF_NUM_MUL] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM REAL_OF_NUM_MUL]) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[REAL_ARITH `&0 < &2 * x <=> &0 < x`]) THEN
+  ASM_SIMP_TAC[REAL_FIELD `&0 < y ==> x / (&2 * y) * &4 = x * &2 / y`] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum(M..(2*M)) (\i. (&i * &2 / &M) pow dimindex (:N))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC SUM_SUBSET_SIMPLE THEN
+    SIMP_TAC[REAL_POW_LE; REAL_LE_MUL; REAL_LE_DIV; REAL_POS] THEN
+    REWRITE_TAC[IN_NUMSEG; FINITE_NUMSEG; SUBSET] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REAL_OF_NUM_LT]) THEN
+    ARITH_TAC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum(M..(2*M)) (\i. &2)` THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUM_CONST_NUMSEG] THEN
+    REWRITE_TAC[ARITH_RULE `(2 * M + 1) - M = M + 1`] THEN
+    REWRITE_TAC[GSYM REAL_OF_NUM_ADD] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC SUM_LE THEN REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+  X_GEN_TAC `n:num` THEN STRIP_TAC THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `&2 pow (dimindex(:N))` THEN
+  CONJ_TAC THENL
+   [GEN_REWRITE_TAC LAND_CONV [GSYM REAL_POW_1] THEN
+    MATCH_MP_TAC REAL_POW_MONO THEN REWRITE_TAC[DIMINDEX_GE_1] THEN
+    ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_POW_LE2 THEN
+  REWRITE_TAC[REAL_POS; ARITH; real_div; REAL_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[GSYM real_div; REAL_LE_RDIV_EQ] THEN
+  REWRITE_TAC[REAL_OF_NUM_MUL; REAL_OF_NUM_LE] THEN
+  UNDISCH_TAC `M:num <= n` THEN ARITH_TAC);;
+
+let STARLIKE_NEGLIGIBLE_LEMMA = prove
+ (`!s. compact s /\
+       (!c x:real^N. &0 <= c /\ x IN s /\ (c % x) IN s ==> c = &1)
+       ==> negligible s`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC STARLIKE_NEGLIGIBLE_BOUNDED_MEASURABLE THEN
+  ASM_MESON_TAC[MEASURABLE_COMPACT; COMPACT_IMP_BOUNDED]);;
+
+let STARLIKE_NEGLIGIBLE = prove
+ (`!s a. closed s /\
+         (!c x:real^N. &0 <= c /\ (a + x) IN s /\ (a + c % x) IN s ==> c = &1)
+         ==> negligible s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC NEGLIGIBLE_TRANSLATION_REV THEN
+  EXISTS_TAC `--a:real^N` THEN ONCE_REWRITE_TAC[NEGLIGIBLE_ON_INTERVALS] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN
+  MATCH_MP_TAC STARLIKE_NEGLIGIBLE_LEMMA THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CLOSED_INTER_COMPACT THEN REWRITE_TAC[COMPACT_INTERVAL] THEN
+    ASM_SIMP_TAC[CLOSED_TRANSLATION];
+    REWRITE_TAC[IN_IMAGE; IN_INTER] THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH `x:real^N = --a + y <=> y = a + x`] THEN
+    REWRITE_TAC[UNWIND_THM2] THEN ASM MESON_TAC[]]);;
+
+let STARLIKE_NEGLIGIBLE_STRONG = prove
+ (`!s a. closed s /\
+         (!c x:real^N. &0 <= c /\ c < &1 /\ (a + x) IN s
+                       ==> ~((a + c % x) IN s))
+         ==> negligible s`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC STARLIKE_NEGLIGIBLE THEN
+  EXISTS_TAC `a:real^N` THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`c:real`; `x:real^N`] THEN STRIP_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH `~(x < y) /\ ~(y < x) ==> x = y`) THEN
+  STRIP_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`inv c:real`; `c % x:real^N`]) THEN
+  ASM_REWRITE_TAC[REAL_LE_INV_EQ; VECTOR_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_MUL_LINV; REAL_ARITH `&1 < c ==> ~(c = &0)`] THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LID] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM REAL_INV_1] THEN
+  MATCH_MP_TAC REAL_LT_INV2 THEN ASM_REWRITE_TAC[REAL_LT_01]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In particular.                                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_HYPERPLANE = prove
+ (`!a b. ~(a = vec 0 /\ b = &0) ==> negligible {x:real^N | a dot x = b}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THEN
+  ASM_SIMP_TAC[DOT_LZERO; SET_RULE `{x | F} = {}`; NEGLIGIBLE_EMPTY] THEN
+  MATCH_MP_TAC STARLIKE_NEGLIGIBLE THEN
+  SUBGOAL_THEN `?x:real^N. ~(a dot x = b)` MP_TAC THENL
+   [MATCH_MP_TAC(MESON[] `!a:real^N. P a \/ P(--a) ==> ?x. P x`) THEN
+    EXISTS_TAC `a:real^N` THEN REWRITE_TAC[DOT_RNEG] THEN
+    MATCH_MP_TAC(REAL_ARITH `~(a = &0) ==> ~(a = b) \/ ~(--a = b)`) THEN
+    ASM_REWRITE_TAC[DOT_EQ_0];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^N` THEN DISCH_TAC THEN
+  REWRITE_TAC[CLOSED_HYPERPLANE; IN_ELIM_THM; DOT_RADD; DOT_RMUL] THEN
+  MAP_EVERY X_GEN_TAC [`t:real`; `y:real^N`] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+   `&0 <= t /\ ac + ay = b /\ ac + t * ay = b
+    ==> ((ay = &0 ==> ac = b) /\ (t - &1) * ay = &0)`)) THEN
+  ASM_SIMP_TAC[REAL_ENTIRE; REAL_SUB_0] THEN CONV_TAC TAUT);;
+
+let NEGLIGIBLE_LOWDIM = prove
+ (`!s:real^N->bool. dim(s) < dimindex(:N) ==> negligible 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 NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `span(s):real^N->bool` THEN REWRITE_TAC[SPAN_INC] THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `{x:real^N | a dot x = &0}` THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_HYPERPLANE]);;
+
+let NEGLIGIBLE_AFFINE_HULL = prove
+ (`!s:real^N->bool.
+        FINITE s /\ CARD(s) <= dimindex(:N) ==> negligible(affine hull s)`,
+  REWRITE_TAC[IMP_CONJ] THEN  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[AFFINE_HULL_EMPTY; NEGLIGIBLE_EMPTY] THEN
+  SUBGOAL_THEN
+   `!x s:real^N->bool n.
+        ~(x IN s) /\ (x INSERT s) HAS_SIZE n /\ n <= dimindex(:N)
+        ==> negligible(affine hull(x INSERT s))`
+   (fun th -> MESON_TAC[th; HAS_SIZE; FINITE_INSERT]) THEN
+  X_GEN_TAC `orig:real^N` THEN GEOM_ORIGIN_TAC `orig:real^N` THEN
+  SIMP_TAC[AFFINE_HULL_EQ_SPAN; IN_INSERT; SPAN_INSERT_0; HULL_INC] THEN
+  REWRITE_TAC[HAS_SIZE; FINITE_INSERT; IMP_CONJ] THEN
+  SIMP_TAC[CARD_CLAUSES] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC NEGLIGIBLE_LOWDIM THEN
+  MATCH_MP_TAC LET_TRANS THEN EXISTS_TAC `CARD(s:real^N->bool)` THEN
+  ASM_SIMP_TAC[DIM_LE_CARD; DIM_SPAN] THEN ASM_ARITH_TAC);;
+
+let NEGLIGIBLE_AFFINE_HULL_1 = prove
+ (`!a:real^1. negligible (affine hull {a})`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC NEGLIGIBLE_AFFINE_HULL THEN
+  SIMP_TAC[FINITE_INSERT; CARD_CLAUSES; FINITE_EMPTY; DIMINDEX_1] THEN
+  ARITH_TAC);;
+
+let NEGLIGIBLE_AFFINE_HULL_2 = prove
+ (`!a b:real^2. negligible (affine hull {a,b})`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC NEGLIGIBLE_AFFINE_HULL THEN
+  SIMP_TAC[FINITE_INSERT; CARD_CLAUSES; FINITE_EMPTY; DIMINDEX_2] THEN
+  ARITH_TAC);;
+
+let NEGLIGIBLE_AFFINE_HULL_3 = prove
+ (`!a b c:real^3. negligible (affine hull {a,b,c})`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC NEGLIGIBLE_AFFINE_HULL THEN
+  SIMP_TAC[FINITE_INSERT; CARD_CLAUSES; FINITE_EMPTY; DIMINDEX_3] THEN
+  ARITH_TAC);;
+
+let NEGLIGIBLE_CONVEX_HULL = prove
+ (`!s:real^N->bool.
+        FINITE s /\ CARD(s) <= dimindex(:N) ==> negligible(convex hull s)`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP NEGLIGIBLE_AFFINE_HULL) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] NEGLIGIBLE_SUBSET) THEN
+  REWRITE_TAC[CONVEX_HULL_SUBSET_AFFINE_HULL]);;
+
+let NEGLIGIBLE_CONVEX_HULL_1 = prove
+ (`!a:real^1. negligible (convex hull {a})`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC NEGLIGIBLE_CONVEX_HULL THEN
+  SIMP_TAC[FINITE_INSERT; CARD_CLAUSES; FINITE_EMPTY; DIMINDEX_1] THEN
+  ARITH_TAC);;
+
+let NEGLIGIBLE_CONVEX_HULL_2 = prove
+ (`!a b:real^2. negligible (convex hull {a,b})`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC NEGLIGIBLE_CONVEX_HULL THEN
+  SIMP_TAC[FINITE_INSERT; CARD_CLAUSES; FINITE_EMPTY; DIMINDEX_2] THEN
+  ARITH_TAC);;
+
+let NEGLIGIBLE_CONVEX_HULL_3 = prove
+ (`!a b c:real^3. negligible (convex hull {a,b,c})`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC NEGLIGIBLE_CONVEX_HULL THEN
+  SIMP_TAC[FINITE_INSERT; CARD_CLAUSES; FINITE_EMPTY; DIMINDEX_3] THEN
+  ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Measurability of bounded convex sets.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_CONVEX_FRONTIER = prove
+ (`!s:real^N->bool. convex s ==> negligible(frontier s)`,
+  SUBGOAL_THEN
+   `!s:real^N->bool. convex s /\ (vec 0) IN s ==> negligible(frontier s)`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    X_GEN_TAC `s:real^N->bool` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `s:real^N->bool = {}` THEN
+    ASM_REWRITE_TAC[FRONTIER_EMPTY; NEGLIGIBLE_EMPTY] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE (\x:real^N. --a + x) s`) THEN
+    ASM_SIMP_TAC[CONVEX_TRANSLATION; IN_IMAGE] THEN
+    ASM_REWRITE_TAC[UNWIND_THM2;
+                    VECTOR_ARITH `vec 0:real^N = --a + x <=> x = a`] THEN
+    REWRITE_TAC[FRONTIER_TRANSLATION; NEGLIGIBLE_TRANSLATION_EQ]] THEN
+  REPEAT STRIP_TAC THEN MP_TAC(ISPEC `s:real^N->bool` DIM_SUBSET_UNIV) THEN
+  REWRITE_TAC[ARITH_RULE `d:num <= e <=> d < e \/ d = e`] THEN STRIP_TAC THENL
+   [MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+    EXISTS_TAC `closure s:real^N->bool` THEN
+    REWRITE_TAC[frontier; SUBSET_DIFF] THEN
+    MATCH_MP_TAC NEGLIGIBLE_LOWDIM THEN ASM_REWRITE_TAC[DIM_CLOSURE];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `?a:real^N. a IN interior s` CHOOSE_TAC THENL
+   [X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC
+     (ISPEC `s:real^N->bool` BASIS_EXISTS) THEN
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    MP_TAC(ISPEC `b:real^N->bool` INTERIOR_SIMPLEX_NONEMPTY) THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN REWRITE_TAC[GSYM SUBSET] THEN
+    MATCH_MP_TAC SUBSET_INTERIOR THEN MATCH_MP_TAC HULL_MINIMAL THEN
+    ASM_REWRITE_TAC[INSERT_SUBSET];
+    ALL_TAC] THEN
+  MATCH_MP_TAC STARLIKE_NEGLIGIBLE_STRONG THEN
+  EXISTS_TAC `a:real^N` THEN REWRITE_TAC[FRONTIER_CLOSED] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  REWRITE_TAC[frontier; IN_DIFF; DE_MORGAN_THM] THEN DISJ2_TAC THEN
+  SIMP_TAC[VECTOR_ARITH
+   `a + c % x:real^N = (a + x) - (&1 - c) % ((a + x) - a)`] THEN
+  MATCH_MP_TAC IN_INTERIOR_CLOSURE_CONVEX_SHRINK THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[frontier; IN_DIFF]) THEN
+  ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC);;
+
+let MEASURABLE_CONVEX = prove
+ (`!s:real^N->bool. convex s /\ bounded s ==> measurable s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_JORDAN THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_CONVEX_FRONTIER]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Various special cases.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_SPHERE = prove
+ (`!a:real^N r. negligible (sphere(a,e))`,
+  REWRITE_TAC[GSYM FRONTIER_CBALL] THEN
+  SIMP_TAC[NEGLIGIBLE_CONVEX_FRONTIER; CONVEX_CBALL]);;
+
+let MEASURABLE_BALL = prove
+ (`!a r. measurable(ball(a,r))`,
+  SIMP_TAC[MEASURABLE_OPEN; BOUNDED_BALL; OPEN_BALL]);;
+
+let MEASURABLE_CBALL = prove
+ (`!a r. measurable(cball(a,r))`,
+  SIMP_TAC[MEASURABLE_COMPACT; COMPACT_CBALL]);;
+
+let MEASURE_BALL_POS = prove
+ (`!x:real^N e. &0 < e ==> &0 < measure(ball(x,e))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_OPEN_POS_LT THEN
+  REWRITE_TAC[OPEN_BALL; BOUNDED_BALL; BALL_EQ_EMPTY] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let MEASURE_CBALL_POS = prove
+ (`!x:real^N e. &0 < e ==> &0 < measure(cball(x,e))`,
+  MESON_TAC[MEASURE_SUBSET; REAL_LTE_TRANS; MEASURABLE_BALL; MEASURABLE_CBALL;
+            BALL_SUBSET_CBALL; MEASURE_BALL_POS]);;
+
+let HAS_INTEGRAL_OPEN_INTERVAL = prove
+ (`!f a b y. (f has_integral y) (interval(a,b)) <=>
+             (f has_integral y) (interval[a,b])`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM INTERIOR_CLOSED_INTERVAL] THEN
+  MATCH_MP_TAC HAS_INTEGRAL_INTERIOR THEN
+  MATCH_MP_TAC NEGLIGIBLE_CONVEX_FRONTIER THEN
+  REWRITE_TAC[CONVEX_INTERVAL]);;
+
+let INTEGRABLE_ON_OPEN_INTERVAL = prove
+ (`!f a b. f integrable_on interval(a,b) <=>
+           f integrable_on interval[a,b]`,
+  REWRITE_TAC[integrable_on; HAS_INTEGRAL_OPEN_INTERVAL]);;
+
+let INTEGRAL_OPEN_INTERVAL = prove
+ (`!f a b. integral(interval(a,b)) f = integral(interval[a,b]) f`,
+  REWRITE_TAC[integral; HAS_INTEGRAL_OPEN_INTERVAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Crude upper bounds for measure of balls.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURE_CBALL_BOUND = prove
+ (`!x:real^N d.
+        &0 <= d ==> measure(cball(x,d)) <= (&2 * d) pow (dimindex(:N))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `measure(interval[x - d % vec 1:real^N,x + d % vec 1])` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC MEASURE_SUBSET THEN
+    REWRITE_TAC[MEASURABLE_CBALL; MEASURABLE_INTERVAL] THEN
+    REWRITE_TAC[SUBSET; IN_CBALL; IN_INTERVAL] THEN
+    REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_SUB_COMPONENT; dist] THEN
+    REWRITE_TAC[VECTOR_MUL_COMPONENT; VEC_COMPONENT] THEN
+    X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`x - y:real^N`; `i:num`] COMPONENT_LE_NORM) THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_COMPONENT] THEN ASM_REAL_ARITH_TAC;
+    SIMP_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+    COND_CASES_TAC THEN
+    ASM_SIMP_TAC[REAL_POW_LE; REAL_LE_MUL; REAL_POS] THEN
+    REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_SUB_COMPONENT] THEN
+    REWRITE_TAC[REAL_ARITH `(x + a) - (x - a):real = &2 * a`] THEN
+    REWRITE_TAC[PRODUCT_CONST_NUMSEG; VECTOR_MUL_COMPONENT; VEC_COMPONENT] THEN
+    REWRITE_TAC[REAL_MUL_RID; ADD_SUB; REAL_LE_REFL]]);;
+
+let MEASURE_BALL_BOUND = prove
+ (`!x:real^N d.
+        &0 <= d ==> measure(ball(x,d)) <= (&2 * d) pow (dimindex(:N))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `measure(cball(x:real^N,d))` THEN
+  ASM_SIMP_TAC[MEASURE_CBALL_BOUND] THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+  REWRITE_TAC[BALL_SUBSET_CBALL; MEASURABLE_BALL; MEASURABLE_CBALL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Negligibility of image under non-injective linear map.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_LINEAR_SINGULAR_IMAGE = prove
+ (`!f:real^N->real^N s.
+        linear f /\ ~(!x y. f(x) = f(y) ==> x = y)
+        ==> negligible(IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LINEAR_SINGULAR_IMAGE_HYPERPLANE) THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `{x:real^N | a dot x = &0}` THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_HYPERPLANE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some technical lemmas used in the approximation results that follow.      *)
+(* Proof of the covering lemma is an obvious multidimensional generalization *)
+(* of Lemma 3, p65 of Swartz's "Introduction to Gauge Integrals".            *)
+(* ------------------------------------------------------------------------- *)
+
+let COVERING_LEMMA = prove
+ (`!a b:real^N s g.
+        s SUBSET interval[a,b] /\ ~(interval(a,b) = {}) /\ gauge g
+        ==> ?d. COUNTABLE d /\
+                (!k. k IN d ==> k SUBSET interval[a,b] /\ ~(interior k = {}) /\
+                                (?c d. k = interval[c,d])) /\
+                (!k1 k2. k1 IN d /\ k2 IN d /\ ~(k1 = k2)
+                         ==> interior k1 INTER interior k2 = {}) /\
+                (!k. k IN d ==> ?x. x IN (s INTER k) /\ k SUBSET g(x)) /\
+                (!u v. interval[u,v] IN d
+                       ==> ?n. !i. 1 <= i /\ i <= dimindex(:N)
+                                   ==> v$i - u$i = (b$i - a$i) / &2 pow n) /\
+                s SUBSET UNIONS d`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?d. COUNTABLE d /\
+        (!k. k IN d ==> k SUBSET interval[a,b] /\ ~(interior k = {}) /\
+                        (?c d:real^N. k = interval[c,d])) /\
+        (!k1 k2. k1 IN d /\ k2 IN d
+                 ==> k1 SUBSET k2 \/ k2 SUBSET k1 \/
+                     interior k1 INTER interior k2 = {}) /\
+        (!x. x IN s ==> ?k. k IN d /\ x IN k /\ k SUBSET g(x)) /\
+        (!u v. interval[u,v] IN d
+                       ==> ?n. !i. 1 <= i /\ i <= dimindex(:N)
+                                   ==> v$i - u$i = (b$i - a$i) / &2 pow n) /\
+        (!k. k IN d ==> FINITE {l | l IN d /\ k SUBSET l})`
+  ASSUME_TAC THENL
+   [EXISTS_TAC
+     `IMAGE (\(n,v).
+             interval[(lambda i. a$i + &(v$i) / &2 pow n *
+                                       ((b:real^N)$i - (a:real^N)$i)):real^N,
+                      (lambda i. a$i + (&(v$i) + &1) / &2 pow n * (b$i - a$i))])
+            {n,v | n IN (:num) /\
+                   v IN {v:num^N | !i. 1 <= i /\ i <= dimindex(:N)
+                                       ==> v$i < 2 EXP n}}` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC COUNTABLE_IMAGE THEN
+      MATCH_MP_TAC COUNTABLE_PRODUCT_DEPENDENT THEN
+      REWRITE_TAC[NUM_COUNTABLE; IN_UNIV] THEN
+      GEN_TAC THEN MATCH_MP_TAC FINITE_IMP_COUNTABLE THEN
+      MATCH_MP_TAC FINITE_CART THEN REWRITE_TAC[FINITE_NUMSEG_LT];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM] THEN
+      MAP_EVERY X_GEN_TAC [`n:num`; `v:num^N`] THEN
+      REWRITE_TAC[IN_ELIM_PAIR_THM] THEN
+      REWRITE_TAC[IN_ELIM_THM; IN_UNIV] THEN DISCH_TAC THEN
+      REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+      REWRITE_TAC[INTERIOR_CLOSED_INTERVAL] THEN
+      SIMP_TAC[INTERVAL_NE_EMPTY; SUBSET_INTERVAL; LAMBDA_BETA] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+      ASM_SIMP_TAC[REAL_LE_LADD; REAL_LE_RMUL_EQ; REAL_SUB_LT; REAL_LE_MUL_EQ;
+                   REAL_LT_LADD; REAL_LT_RMUL_EQ; REAL_LE_ADDR; REAL_ARITH
+                     `a + x * (b - a) <= b <=> &0 <= (&1 - x) * (b - a)`] THEN
+      SIMP_TAC[REAL_LE_DIV2_EQ; REAL_LT_DIV2_EQ; REAL_LT_POW2] THEN
+      REWRITE_TAC[REAL_ARITH `x <= x + &1 /\ x < x + &1`] THEN
+      REWRITE_TAC[REAL_SUB_LE] THEN
+      SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; REAL_LT_POW2] THEN
+      REWRITE_TAC[REAL_MUL_LZERO; REAL_POS; REAL_MUL_LID] THEN
+      SIMP_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_POW; REAL_OF_NUM_LE] THEN
+      ASM_SIMP_TAC[ARITH_RULE `x + 1 <= y <=> x < y`; REAL_LT_IMP_LE];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [ONCE_REWRITE_TAC[IMP_CONJ] THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM; RIGHT_FORALL_IMP_THM] THEN
+      REWRITE_TAC[IN_ELIM_PAIR_THM; IN_UNIV] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+      REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
+      GEN_REWRITE_TAC BINDER_CONV [SWAP_FORALL_THM] THEN
+      MATCH_MP_TAC WLOG_LE THEN CONJ_TAC THENL
+       [REPEAT GEN_TAC THEN
+        GEN_REWRITE_TAC RAND_CONV [SWAP_FORALL_THM] THEN
+        REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN SET_TAC[];
+        ALL_TAC] THEN
+      MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN DISCH_TAC THEN
+      MAP_EVERY X_GEN_TAC [`v:num^N`; `w:num^N`] THEN REPEAT DISCH_TAC THEN
+      REWRITE_TAC[INTERIOR_CLOSED_INTERVAL; SUBSET_INTERVAL] THEN
+      SIMP_TAC[DISJOINT_INTERVAL; LAMBDA_BETA] THEN
+      MATCH_MP_TAC(TAUT `p \/ q \/ r ==> (a ==> p) \/ (b ==> q) \/ r`) THEN
+      ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> ~(a /\ b ==> ~c)`] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+      ASM_SIMP_TAC[REAL_LE_LADD; REAL_LE_RMUL_EQ; REAL_SUB_LT; LAMBDA_BETA] THEN
+      REWRITE_TAC[NOT_IMP; REAL_LE_LADD] THEN
+      ASM_SIMP_TAC[REAL_LE_DIV2_EQ; REAL_LT_POW2] THEN
+      REWRITE_TAC[REAL_ARITH `~(x + &1 <= x)`] THEN DISJ2_TAC THEN
+      MATCH_MP_TAC(MESON[]
+       `(!i. ~P i ==> Q i) ==> (!i. Q i) \/ (?i. P i)`) THEN
+      X_GEN_TAC `i:num` THEN
+      DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+      ASM_REWRITE_TAC[DE_MORGAN_THM; REAL_NOT_LE] THEN
+      UNDISCH_TAC `m:num <= n` THEN REWRITE_TAC[LE_EXISTS] THEN
+      DISCH_THEN(X_CHOOSE_THEN `p:num` SUBST1_TAC) THEN
+      ONCE_REWRITE_TAC[ADD_SYM] THEN
+      REWRITE_TAC[REAL_POW_ADD; real_div; REAL_INV_MUL] THEN
+      REWRITE_TAC[REAL_MUL_ASSOC] THEN REWRITE_TAC[GSYM real_div] THEN
+      ASM_SIMP_TAC[REAL_LE_DIV2_EQ; REAL_LT_POW2; REAL_LT_DIV2_EQ] THEN
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; REAL_LT_POW2;
+                   REAL_LT_LDIV_EQ; REAL_LT_RDIV_EQ] THEN
+      SIMP_TAC[REAL_LT_INTEGERS; INTEGER_CLOSED] THEN REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+      SUBGOAL_THEN
+        `?e. &0 < e /\ !y. (!i. 1 <= i /\ i <= dimindex(:N)
+                                ==> abs((x:real^N)$i - (y:real^N)$i) <= e)
+                           ==> y IN g(x)`
+      STRIP_ASSUME_TAC THENL
+       [FIRST_ASSUM(MP_TAC o SPEC `x:real^N` o GEN_REWRITE_RULE I [gauge]) THEN
+        STRIP_TAC THEN
+        FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+        DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+        DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+        EXISTS_TAC `e / &2 / &(dimindex(:N))` THEN
+        ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1;
+                     ARITH] THEN
+        X_GEN_TAC `y:real^N` THEN STRIP_TAC THEN
+        MATCH_MP_TAC(SET_RULE `!s. s SUBSET t /\ x IN s ==> x IN t`) THEN
+        EXISTS_TAC `ball(x:real^N,e)` THEN ASM_REWRITE_TAC[IN_BALL] THEN
+        MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
+        ASM_REWRITE_TAC[dist] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+        EXISTS_TAC `sum(1..dimindex(:N)) (\i. abs((x - y:real^N)$i))` THEN
+        REWRITE_TAC[NORM_LE_L1] THEN MATCH_MP_TAC SUM_BOUND_GEN THEN
+        ASM_SIMP_TAC[IN_NUMSEG; FINITE_NUMSEG; NUMSEG_EMPTY; NOT_LT;
+                     DIMINDEX_GE_1; VECTOR_SUB_COMPONENT; CARD_NUMSEG_1];
+        ALL_TAC] THEN
+      REWRITE_TAC[EXISTS_IN_IMAGE; EXISTS_PAIR_THM; IN_ELIM_PAIR_THM] THEN
+      MP_TAC(SPECL [`&1 / &2`; `e / norm(b - a:real^N)`]
+        REAL_ARCH_POW_INV) THEN
+      SUBGOAL_THEN `&0 < norm(b - a:real^N)` ASSUME_TAC THENL
+       [ASM_MESON_TAC[VECTOR_SUB_EQ; NORM_POS_LT; INTERVAL_SING]; ALL_TAC] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_SIMP_TAC[REAL_LT_DIV] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `n:num` THEN
+      REWRITE_TAC[real_div; REAL_MUL_LID; REAL_POW_INV] THEN DISCH_TAC THEN
+      SIMP_TAC[IN_ELIM_THM; IN_INTERVAL; SUBSET; LAMBDA_BETA] THEN
+      MATCH_MP_TAC(MESON[]
+       `(!x. Q x ==> R x) /\ (?x. P x /\ Q x) ==> ?x. P x /\ Q x /\ R x`) THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
+        MAP_EVERY X_GEN_TAC [`w:num^N`; `y:real^N`] THEN
+        REWRITE_TAC[IMP_IMP; AND_FORALL_THM] THEN
+        DISCH_THEN(fun th -> FIRST_X_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+        MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+        DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+        ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+         `(a + n <= x /\ x <= a + m) /\
+          (a + n <= y /\ y <= a + m) ==> abs(x - y) <= m - n`)) THEN
+        MATCH_MP_TAC(REAL_ARITH
+         `y * z <= e
+          ==> a <= ((x + &1) * y) * z - ((x * y) * z) ==> a <= e`) THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+        ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; REAL_SUB_LT] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+        (REAL_ARITH `n < e * x ==> &0 <= e * (inv y - x) ==> n <= e / y`)) THEN
+        MATCH_MP_TAC REAL_LE_MUL THEN ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+        REWRITE_TAC[REAL_SUB_LE] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+        ASM_SIMP_TAC[REAL_SUB_LT] THEN
+        MP_TAC(SPECL [`b - a:real^N`; `i:num`] COMPONENT_LE_NORM) THEN
+        ASM_SIMP_TAC[VECTOR_SUB_COMPONENT] THEN REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[IN_UNIV; AND_FORALL_THM] THEN
+      REWRITE_TAC[TAUT `(a ==> c) /\ (a ==> b) <=> a ==> b /\ c`] THEN
+      REWRITE_TAC[GSYM LAMBDA_SKOLEM] THEN X_GEN_TAC `i:num` THEN
+      STRIP_TAC THEN
+      SUBGOAL_THEN `(x:real^N) IN interval[a,b]` MP_TAC THENL
+       [ASM SET_TAC[]; ALL_TAC] THEN REWRITE_TAC[IN_INTERVAL] THEN
+      DISCH_THEN(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN STRIP_TAC THEN
+      DISJ_CASES_TAC(MATCH_MP (REAL_ARITH `x <= y ==> x = y \/ x < y`)
+       (ASSUME `(x:real^N)$i <= (b:real^N)$i`))
+      THENL
+       [EXISTS_TAC `2 EXP n - 1` THEN
+        SIMP_TAC[GSYM REAL_OF_NUM_SUB; GSYM REAL_OF_NUM_LT;
+                 EXP_LT_0; LE_1; ARITH] THEN
+        ASM_REWRITE_TAC[REAL_SUB_ADD; REAL_ARITH `a - &1 < a`] THEN
+        MATCH_MP_TAC(REAL_ARITH
+         `&1 * (b - a) = x /\ y <= x ==> a + y <= b /\ b <= a + x`) THEN
+        ASM_SIMP_TAC[REAL_EQ_MUL_RCANCEL; REAL_LT_IMP_NZ; REAL_LE_RMUL_EQ;
+                     REAL_SUB_LT; REAL_LT_INV_EQ; REAL_LT_POW2] THEN
+        SIMP_TAC[GSYM REAL_OF_NUM_POW; REAL_MUL_RINV; REAL_POW_EQ_0;
+                 REAL_OF_NUM_EQ; ARITH_EQ] THEN REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      MP_TAC(SPEC `&2 pow n * ((x:real^N)$i - (a:real^N)$i) /
+                              ((b:real^N)$i - (a:real^N)$i)` FLOOR_POS) THEN
+      ANTS_TAC THENL
+       [ASM_MESON_TAC[REAL_LE_MUL; REAL_LE_MUL; REAL_POW_LE; REAL_POS;
+                      REAL_SUB_LE; REAL_LT_IMP_LE; REAL_LE_DIV];
+        ALL_TAC] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `m:num` THEN
+      REWRITE_TAC[GSYM REAL_OF_NUM_LT; GSYM REAL_OF_NUM_POW] THEN
+      DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+      REWRITE_TAC[REAL_ARITH `a + b * c <= x /\ x <= a + b' * c <=>
+                              b * c <= x - a /\ x - a <= b' * c`] THEN
+      ASM_SIMP_TAC[GSYM REAL_LE_LDIV_EQ; GSYM REAL_LE_RDIV_EQ;
+                   REAL_SUB_LT; GSYM real_div] THEN
+      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+      SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; REAL_LT_POW2] THEN
+      SIMP_TAC[FLOOR; REAL_LT_IMP_LE] THEN MATCH_MP_TAC REAL_LET_TRANS THEN
+      EXISTS_TAC `((x:real^N)$i - (a:real^N)$i) /
+                  ((b:real^N)$i - (a:real^N)$i) *
+                  &2 pow n` THEN
+      REWRITE_TAC[FLOOR] THEN GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
+      ASM_SIMP_TAC[REAL_LT_RMUL_EQ; REAL_LT_POW2] THEN
+      ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_MUL_LID; REAL_SUB_LT] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [REPEAT GEN_TAC THEN REWRITE_TAC[IN_IMAGE; EXISTS_PAIR_THM] THEN
+      REWRITE_TAC[EQ_INTERVAL; IN_ELIM_PAIR_THM] THEN
+      REWRITE_TAC[INTERVAL_EQ_EMPTY; IN_UNIV; IN_ELIM_THM] THEN
+      SIMP_TAC[TAUT `a /\ b /\ c <=> ~(a /\ b ==> ~c)`; LAMBDA_BETA] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+      ASM_SIMP_TAC[REAL_LT_LADD; REAL_LT_RMUL_EQ; REAL_SUB_LT;
+                   REAL_LT_DIV2_EQ; REAL_LT_POW2;
+                   REAL_ARITH `~(v + &1 < v)`] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `n:num` THEN
+      STRIP_TAC THEN ASM_SIMP_TAC[LAMBDA_BETA] THEN REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM; IN_ELIM_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`n:num`; `v:num^N`] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_UNIV] THEN DISCH_TAC THEN
+    MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC
+     `IMAGE (\(n,v).
+            interval[(lambda i. a$i + &(v$i) / &2 pow n *
+                                      ((b:real^N)$i - (a:real^N)$i)):real^N,
+                     (lambda i. a$i + (&(v$i) + &1) / &2 pow n * (b$i - a$i))])
+            {m,v | m IN 0..n /\
+                   v IN {v:num^N | !i. 1 <= i /\ i <= dimindex(:N)
+                                       ==> v$i < 2 EXP m}}` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC FINITE_IMAGE THEN
+      MATCH_MP_TAC FINITE_PRODUCT_DEPENDENT THEN
+      REWRITE_TAC[FINITE_NUMSEG] THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC FINITE_CART THEN REWRITE_TAC[FINITE_NUMSEG_LT];
+      ALL_TAC] THEN
+    GEN_REWRITE_TAC I [SUBSET] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM; IN_ELIM_PAIR_THM] THEN
+    MAP_EVERY X_GEN_TAC [`m:num`; `w:num^N`] THEN DISCH_TAC THEN
+    DISCH_TAC THEN SIMP_TAC[IN_IMAGE; EXISTS_PAIR_THM; IN_ELIM_PAIR_THM] THEN
+    MAP_EVERY EXISTS_TAC [`m:num`; `w:num^N`] THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[IN_NUMSEG; GSYM NOT_LT; LT] THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET_INTERVAL]) THEN
+    SIMP_TAC[NOT_IMP; LAMBDA_BETA] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+    ASM_SIMP_TAC[REAL_LE_LADD; REAL_LE_RMUL_EQ; REAL_SUB_LT] THEN
+    ASM_SIMP_TAC[REAL_LE_DIV2_EQ; REAL_LT_POW2] THEN
+    REWRITE_TAC[REAL_ARITH `x <= x + &1`] THEN
+    DISCH_THEN(MP_TAC o SPEC `1`) THEN
+    REWRITE_TAC[LE_REFL; DIMINDEX_GE_1] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+     `w / m <= v / n /\ (v + &1) / n <= (w + &1) / m
+      ==> inv n <= inv m`)) THEN
+    REWRITE_TAC[REAL_NOT_LE] THEN MATCH_MP_TAC REAL_LT_INV2 THEN
+    ASM_REWRITE_TAC[REAL_LT_POW2] THEN MATCH_MP_TAC REAL_POW_MONO_LT THEN
+    ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?d. COUNTABLE d /\
+        (!k. k IN d ==> k SUBSET interval[a,b] /\ ~(interior k = {}) /\
+                        (?c d:real^N. k = interval[c,d])) /\
+        (!k1 k2. k1 IN d /\ k2 IN d
+                 ==> k1 SUBSET k2 \/ k2 SUBSET k1 \/
+                     interior k1 INTER interior k2 = {}) /\
+        (!k. k IN d ==> (?x. x IN s INTER k /\ k SUBSET g x)) /\
+        (!u v. interval[u,v] IN d
+                       ==> ?n. !i. 1 <= i /\ i <= dimindex(:N)
+                                   ==> v$i - u$i = (b$i - a$i) / &2 pow n) /\
+        (!k. k IN d ==> FINITE {l | l IN d /\ k SUBSET l}) /\
+        s SUBSET UNIONS d`
+  MP_TAC THENL
+   [FIRST_X_ASSUM(X_CHOOSE_THEN `d:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC
+     `{k:real^N->bool | k IN d /\ ?x. x IN (s INTER k) /\ k SUBSET g x}` THEN
+    ASM_SIMP_TAC[IN_ELIM_THM] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC COUNTABLE_SUBSET THEN
+      EXISTS_TAC `d:(real^N->bool)->bool` THEN
+      ASM_REWRITE_TAC[] THEN SET_TAC[];
+      X_GEN_TAC `k:real^N->bool` THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC FINITE_SUBSET THEN
+      EXISTS_TAC `{l:real^N->bool | l IN d /\ k SUBSET l}` THEN
+      ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+      ASM SET_TAC[]];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC
+   `{k:real^N->bool | k IN d /\ !k'. k' IN d /\ ~(k = k')
+                                     ==> ~(k SUBSET k')}` THEN
+  ASM_SIMP_TAC[IN_ELIM_THM] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC COUNTABLE_SUBSET THEN EXISTS_TAC `d:(real^N->bool)->bool` THEN
+    ASM_REWRITE_TAC[] THEN SET_TAC[];
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] SUBSET_TRANS)) THEN
+  GEN_REWRITE_TAC I [SUBSET] THEN REWRITE_TAC[FORALL_IN_UNIONS] THEN
+  MAP_EVERY X_GEN_TAC [`k:real^N->bool`; `x:real^N`] THEN DISCH_TAC THEN
+  REWRITE_TAC[IN_UNIONS; IN_ELIM_THM] THEN
+  MP_TAC(ISPEC `\k l:real^N->bool. k IN d /\ l IN d /\ l SUBSET k /\ ~(k = l)`
+     WF_FINITE) THEN
+  REWRITE_TAC[WF] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN X_GEN_TAC `l:real^N->bool` THEN
+    ASM_CASES_TAC `(l:real^N->bool) IN d` THEN
+    ASM_REWRITE_TAC[EMPTY_GSPEC; FINITE_RULES] THEN
+    MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC `{m:real^N->bool | m IN d /\ l SUBSET m}` THEN
+    ASM_SIMP_TAC[] THEN SET_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `\l:real^N->bool. l IN d /\ x IN l`) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN ASM SET_TAC[]);;
+
+let COUNTABLE_ELEMENTARY_DIVISION = prove
+ (`!d. COUNTABLE d /\ (!k. k IN d ==> ?a b:real^N. k = interval[a,b])
+       ==> ?d'. COUNTABLE d' /\
+                (!k. k IN d' ==> ~(k = {}) /\ ?a b. k = interval[a,b]) /\
+                (!k l. k IN d' /\ l IN d' /\ ~(k = l)
+                       ==> interior k INTER interior l = {}) /\
+                UNIONS d' = UNIONS d`,
+  let lemma = prove
+   (`!s. UNIONS(s DELETE {}) = UNIONS s`,
+    REWRITE_TAC[EXTENSION; IN_UNIONS; IN_DELETE] THEN
+    MESON_TAC[NOT_IN_EMPTY]) in
+  REWRITE_TAC[IMP_CONJ; FORALL_COUNTABLE_AS_IMAGE] THEN
+  REWRITE_TAC[UNIONS_0; EMPTY_UNIONS] THEN CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN EXISTS_TAC `{}:(real^N->bool)->bool` THEN
+    REWRITE_TAC[NOT_IN_EMPTY; COUNTABLE_EMPTY];
+    ALL_TAC] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; IN_UNIV; SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`d:num->real^N->bool`; `a:num->real^N`; `b:num->real^N`] THEN
+  DISCH_TAC THEN
+  (CHOOSE_THEN MP_TAC o prove_recursive_functions_exist num_RECURSION)
+   `x 0 = ({}:(real^N->bool)->bool) /\
+    (!n. x(SUC n) = @q. (x n) SUBSET q /\
+                        q division_of (d n) UNION UNIONS(x n))` THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!n:num. (x n) division_of UNIONS {d k:real^N->bool | k < n}`
+  ASSUME_TAC THENL
+   [INDUCT_TAC THEN
+    ASM_REWRITE_TAC[LT; SET_RULE `UNIONS {f x |x| F} = {}`;
+                    DIVISION_OF_TRIVIAL] THEN
+    FIRST_ASSUM(MP_TAC o SPECL [`(a:num->real^N) n`; `(b:num->real^N) n`] o
+      MATCH_MP ELEMENTARY_UNION_INTERVAL_STRONG o
+      MATCH_MP DIVISION_OF_UNION_SELF) THEN
+    DISCH_THEN(ASSUME_TAC o SELECT_RULE) THEN
+    REWRITE_TAC[SET_RULE `{f x | x = a \/ q x} = f a INSERT {f x | q x}`] THEN
+    REWRITE_TAC[UNIONS_INSERT] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of]) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o SYM o last o CONJUNCTS) THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!m n. m <= n ==> (x:num->(real^N->bool)->bool) m SUBSET x n`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN
+    REPEAT(CONJ_TAC THENL [SET_TAC[]; ALL_TAC]) THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `n:num` THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`(a:num->real^N) n`; `(b:num->real^N) n`] o
+      MATCH_MP ELEMENTARY_UNION_INTERVAL_STRONG o
+      MATCH_MP DIVISION_OF_UNION_SELF o SPEC `n:num`) THEN
+    DISCH_THEN(ASSUME_TAC o SELECT_RULE) THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  EXISTS_TAC `UNIONS(IMAGE x (:num)) DELETE ({}:real^N->bool)` THEN
+  REWRITE_TAC[COUNTABLE_DELETE; IMP_CONJ; RIGHT_FORALL_IMP_THM;
+              FORALL_IN_UNIONS; FORALL_IN_IMAGE; IN_DELETE; IN_UNIV] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC COUNTABLE_UNIONS THEN
+    SIMP_TAC[COUNTABLE_IMAGE; NUM_COUNTABLE; FORALL_IN_IMAGE; IN_UNIV] THEN
+    GEN_TAC THEN MATCH_MP_TAC FINITE_IMP_COUNTABLE THEN
+    ASM_MESON_TAC[DIVISION_OF_FINITE];
+    MAP_EVERY X_GEN_TAC [`n:num`; `k:real^N->bool`] THEN
+    ASM_MESON_TAC[division_of];
+    REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP] THEN
+    GEN_REWRITE_TAC BINDER_CONV [SWAP_FORALL_THM] THEN
+    MATCH_MP_TAC WLOG_LE THEN
+    CONJ_TAC THENL [MESON_TAC[INTER_COMM]; ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`k:real^N->bool`; `l:real^N->bool`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL [`m:num`; `n:num`]) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of] o
+      SPEC `n:num`) THEN ASM SET_TAC[];
+    REWRITE_TAC[lemma] THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE; IN_UNIV;
+                FORALL_IN_UNIONS; SUBSET; IN_UNIONS; EXISTS_IN_IMAGE]
+    THENL
+     [X_GEN_TAC `k:real^N->bool` THEN DISCH_THEN(X_CHOOSE_TAC `n:num`) THEN
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of] o
+         SPEC `n:num`) THEN
+      DISCH_THEN(MP_TAC o last o CONJUNCTS) THEN ASM SET_TAC[];
+      MAP_EVERY X_GEN_TAC [`n:num`; `y:real^N`] THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [division_of] o
+         SPEC `SUC n`) THEN
+      DISCH_THEN(MP_TAC o last o CONJUNCTS) THEN
+      REWRITE_TAC[EXTENSION; IN_UNIONS; EXISTS_IN_GSPEC] THEN
+      DISCH_THEN(MP_TAC o SPEC `y:real^N`) THEN
+      ASM_MESON_TAC[ARITH_RULE `n < SUC n`]]]);;
+
+let EXPAND_CLOSED_OPEN_INTERVAL = prove
+ (`!a b:real^N e.
+        &0 < e
+        ==> ?c d. interval[a,b] SUBSET interval(c,d) /\
+                  measure(interval(c,d)) <= measure(interval[a,b]) + e`,
+  let lemma = prove
+   (`!f n. (\x. lift(product(1..n) (\i. f i + drop x))) continuous at (vec 0)`,
+    GEN_TAC THEN INDUCT_TAC THEN
+    REWRITE_TAC[PRODUCT_CLAUSES_NUMSEG; ARITH_EQ; CONTINUOUS_CONST] THEN
+    REWRITE_TAC[ARITH_RULE `1 <= SUC n`] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[LIFT_CMUL] THEN
+    MATCH_MP_TAC CONTINUOUS_MUL THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[o_DEF; LIFT_ADD; LIFT_DROP] THEN
+    SIMP_TAC[CONTINUOUS_ADD; CONTINUOUS_AT_ID; CONTINUOUS_CONST]) in
+  REPEAT GEN_TAC THEN ABBREV_TAC `m:real^N = midpoint(a,b)` THEN
+  POP_ASSUM MP_TAC THEN GEOM_ORIGIN_TAC `m:real^N` THEN
+  REWRITE_TAC[midpoint; VECTOR_ARITH
+   `inv(&2) % (a + b):real^N = vec 0 <=> a = --b`] THEN
+  REPEAT GEN_TAC THEN DISCH_THEN SUBST1_TAC THEN
+  DISCH_TAC THEN ASM_CASES_TAC `interval[--b:real^N,b] = {}` THENL
+   [MAP_EVERY EXISTS_TAC [`--b:real^N`; `b:real^N`] THEN
+    REWRITE_TAC[MEASURE_INTERVAL] THEN
+    ASM_REWRITE_TAC[CONTENT_EMPTY; EMPTY_SUBSET] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INTERVAL_NE_EMPTY]) THEN
+  REWRITE_TAC[VECTOR_NEG_COMPONENT; REAL_ARITH `--x <= x <=> &0 <= x`] THEN
+  DISCH_TAC THEN
+  MP_TAC(ISPECL [`\i. &2 * (b:real^N)$i`; `dimindex(:N)`] lemma) THEN
+  REWRITE_TAC[continuous_at; DIST_LIFT; FORALL_LIFT; DIST_0; DROP_VEC] THEN
+  REWRITE_TAC[NORM_LIFT; LIFT_DROP; REAL_ADD_RID] THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN
+  MAP_EVERY EXISTS_TAC
+   [`--(b + k / &4 % vec 1:real^N)`; `b + k / &4 % vec 1:real^N`] THEN
+  REWRITE_TAC[MEASURE_INTERVAL; SUBSET_INTERVAL;
+              CONTENT_CLOSED_INTERVAL_CASES] THEN
+  REWRITE_TAC[VECTOR_NEG_COMPONENT; VECTOR_ADD_COMPONENT;
+              VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+  ASM_SIMP_TAC[REAL_ARITH `--x <= x <=> &0 <= x`; REAL_LT_ADDR;
+               REAL_ARITH `&0 < k / &4 <=> &0 < k`;
+               REAL_ARITH `&0 <= b /\ &0 < k ==> --(b + k) < b`;
+               REAL_ARITH `&0 <= b /\ &0 < k ==> --(b + k) < --b`;
+               REAL_ARITH `&0 <= b /\ &0 < k ==> &0 <= b + k`] THEN
+  REWRITE_TAC[REAL_ARITH `b - --b = &2 * b`; REAL_ADD_LDISTRIB] THEN
+  MATCH_MP_TAC(REAL_ARITH `abs(a - b) < e ==> a <= b + e`) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Outer and inner approximation of measurable set by well-behaved sets.     *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_OUTER_INTERVALS_BOUNDED = prove
+ (`!s a b:real^N e.
+        measurable s /\ s SUBSET interval[a,b] /\ &0 < e
+        ==> ?d. COUNTABLE d /\
+                (!k. k IN d ==> k SUBSET interval[a,b] /\ ~(k = {}) /\
+                                (?c d. k = interval[c,d])) /\
+                (!k1 k2. k1 IN d /\ k2 IN d /\ ~(k1 = k2)
+                         ==> interior k1 INTER interior k2 = {}) /\
+                (!u v. interval[u,v] IN d
+                       ==> ?n. !i. 1 <= i /\ i <= dimindex(:N)
+                                   ==> v$i - u$i = (b$i - a$i) / &2 pow n) /\
+                (!k. k IN d /\ ~(interval(a,b) = {}) ==> ~(interior k = {})) /\
+                s SUBSET UNIONS d /\
+                measurable (UNIONS d) /\
+                measure (UNIONS d) <= measure s + e`,
+  let lemma = prove
+   (`(!x y. (x,y) IN IMAGE (\z. f z,g z) s ==> P x y) <=>
+     (!z. z IN s ==> P (f z) (g z))`,
+  REWRITE_TAC[IN_IMAGE; PAIR_EQ] THEN MESON_TAC[]) in
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `interval[a:real^N,b] = {}` THENL
+   [ASM_REWRITE_TAC[SUBSET_EMPTY] THEN STRIP_TAC THEN
+    EXISTS_TAC `{}:(real^N->bool)->bool` THEN
+    ASM_REWRITE_TAC[NOT_IN_EMPTY; UNIONS_0; MEASURE_EMPTY; REAL_ADD_LID;
+                    SUBSET_REFL; COUNTABLE_EMPTY; MEASURABLE_EMPTY] THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE];
+    ALL_TAC] THEN
+  STRIP_TAC THEN ASM_CASES_TAC `interval(a:real^N,b) = {}` THEN
+  ASM_REWRITE_TAC[] THENL
+   [EXISTS_TAC `{interval[a:real^N,b]}` THEN
+    REWRITE_TAC[UNIONS_1; COUNTABLE_SING] THEN
+    ASM_REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_INSERT;
+                    NOT_IN_EMPTY; SUBSET_REFL; MEASURABLE_INTERVAL] THEN
+    CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN CONJ_TAC THENL
+     [ASM_REWRITE_TAC[IN_SING; EQ_INTERVAL] THEN
+      REPEAT STRIP_TAC THEN EXISTS_TAC `0` THEN
+      ASM_REWRITE_TAC[real_pow; REAL_DIV_1];
+      SUBGOAL_THEN
+       `measure(interval[a:real^N,b]) = &0 /\ measure(s:real^N->bool) = &0`
+       (fun th -> ASM_SIMP_TAC[th; REAL_LT_IMP_LE; REAL_ADD_LID]) THEN
+      SUBGOAL_THEN
+        `interval[a:real^N,b] has_measure &0 /\
+         (s:real^N->bool) has_measure &0`
+        (fun th -> MESON_TAC[th; MEASURE_UNIQUE]) THEN
+      REWRITE_TAC[HAS_MEASURE_0] THEN
+      MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+       [ASM_REWRITE_TAC[NEGLIGIBLE_INTERVAL];
+        ASM_MESON_TAC[NEGLIGIBLE_SUBSET]]];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [measurable]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `m:real`) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP MEASURE_UNIQUE) THEN
+  SUBGOAL_THEN
+   `((\x:real^N. if x IN s then vec 1 else vec 0) has_integral (lift m))
+    (interval[a,b])`
+  ASSUME_TAC THENL
+   [ONCE_REWRITE_TAC[GSYM HAS_INTEGRAL_RESTRICT_UNIV] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HAS_MEASURE]) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HAS_INTEGRAL_EQ) THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP HAS_INTEGRAL_INTEGRABLE) THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [has_integral]) THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPECL [`a:real^N`; `b:real^N`; `s:real^N->bool`;
+                `g:real^N->real^N->bool`] COVERING_LEMMA) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `d:(real^N->bool)->bool` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[INTERIOR_EMPTY]; ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`(\x. if x IN s then vec 1 else vec 0):real^N->real^1`;
+                 `a:real^N`; `b:real^N`; `g:real^N->real^N->bool`;
+                 `e:real`]
+                HENSTOCK_LEMMA_PART1) THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP INTEGRAL_UNIQUE) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(LABEL_TAC "*") THEN
+  SUBGOAL_THEN
+   `!k l:real^N->bool. k IN d /\ l IN d /\ ~(k = l)
+                       ==> negligible(k INTER l)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`k:real^N->bool`; `l:real^N->bool`]) THEN
+    ASM_SIMP_TAC[] THEN
+    SUBGOAL_THEN
+     `?x y:real^N u v:real^N. k = interval[x,y] /\ l = interval[u,v]`
+    MP_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+    DISCH_THEN(REPEAT_TCL CHOOSE_THEN (CONJUNCTS_THEN SUBST_ALL_TAC)) THEN
+    REWRITE_TAC[INTERIOR_CLOSED_INTERVAL] THEN DISCH_TAC THEN
+    MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+    EXISTS_TAC `(interval[x:real^N,y] DIFF interval(x,y)) UNION
+                (interval[u:real^N,v] DIFF interval(u,v)) UNION
+                (interval (x,y) INTER interval (u,v))` THEN
+    CONJ_TAC THENL [ALL_TAC; SET_TAC[]] THEN
+    ASM_REWRITE_TAC[UNION_EMPTY] THEN
+    SIMP_TAC[NEGLIGIBLE_UNION; NEGLIGIBLE_FRONTIER_INTERVAL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!D. FINITE D /\ D SUBSET d
+         ==> measurable(UNIONS D :real^N->bool) /\ measure(UNIONS D) <= m + e`
+  ASSUME_TAC THENL
+   [GEN_TAC THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `?t:(real^N->bool)->real^N. !k. k IN D ==> t(k) IN (s INTER k) /\
+                                                k SUBSET (g(t k))`
+    (CHOOSE_THEN (LABEL_TAC "+")) THENL
+     [REWRITE_TAC[GSYM SKOLEM_THM] THEN ASM SET_TAC[]; ALL_TAC] THEN
+    REMOVE_THEN "*" (MP_TAC o SPEC
+     `IMAGE (\k. (t:(real^N->bool)->real^N) k,k) D`) THEN
+    ASM_SIMP_TAC[VSUM_IMAGE; PAIR_EQ] THEN REWRITE_TAC[o_DEF] THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[tagged_partial_division_of; fine] THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE] THEN
+      REWRITE_TAC[lemma; RIGHT_FORALL_IMP_THM; IMP_CONJ; PAIR_EQ] THEN
+      ASM_SIMP_TAC[] THEN
+      CONJ_TAC THENL [ASM SET_TAC[]; ASM_MESON_TAC[SUBSET]];
+      ALL_TAC] THEN
+    USE_THEN "+" (MP_TAC o REWRITE_RULE[IN_INTER]) THEN
+    SIMP_TAC[] THEN DISCH_THEN(K ALL_TAC) THEN
+    ASM_SIMP_TAC[VSUM_SUB] THEN
+    SUBGOAL_THEN `D division_of (UNIONS D:real^N->bool)` ASSUME_TAC THENL
+     [REWRITE_TAC[division_of] THEN ASM SET_TAC[]; ALL_TAC] THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP MEASURABLE_ELEMENTARY) THEN
+    SUBGOAL_THEN `vsum D (\k:real^N->bool. content k % vec 1) =
+                  lift(measure(UNIONS D))`
+    SUBST1_TAC THENL
+     [ONCE_REWRITE_TAC[GSYM DROP_EQ] THEN
+      ASM_SIMP_TAC[LIFT_DROP; DROP_VSUM; o_DEF; DROP_CMUL; DROP_VEC] THEN
+      SIMP_TAC[REAL_MUL_RID; ETA_AX] THEN ASM_MESON_TAC[MEASURE_ELEMENTARY];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `vsum D (\k. integral k (\x:real^N. if x IN s then vec 1 else vec 0)) =
+      lift(sum D (\k. measure(k INTER s)))`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[LIFT_SUM; o_DEF] THEN MATCH_MP_TAC VSUM_EQ THEN
+      X_GEN_TAC `k:real^N->bool` THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+      SUBGOAL_THEN `measurable(k:real^N->bool)` ASSUME_TAC THENL
+       [ASM_MESON_TAC[SUBSET; MEASURABLE_INTERVAL]; ALL_TAC] THEN
+      ASM_SIMP_TAC[GSYM INTEGRAL_MEASURE_UNIV; MEASURABLE_INTER] THEN
+      REWRITE_TAC[MESON[IN_INTER]
+        `(if x IN k INTER s then a else b) =
+         (if x IN k then if x IN s then a else b else b)`] THEN
+      REWRITE_TAC[INTEGRAL_RESTRICT_UNIV];
+      ALL_TAC] THEN
+    ASM_REWRITE_TAC[GSYM LIFT_SUB; NORM_LIFT] THEN
+    MATCH_MP_TAC(REAL_ARITH `y <= m ==> abs(x - y) <= e ==> x <= m + e`) THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `measure(UNIONS D INTER s:real^N->bool)` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      EXPAND_TAC "m" THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+      ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ALL_TAC; SET_TAC[]] THEN
+      MATCH_MP_TAC MEASURABLE_INTER THEN ASM_REWRITE_TAC[]] THEN
+    REWRITE_TAC[INTER_UNIONS] THEN MATCH_MP_TAC REAL_EQ_IMP_LE THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG THEN
+    ASM_SIMP_TAC[FINITE_RESTRICT] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[SUBSET; MEASURABLE_INTERVAL; MEASURABLE_INTER];
+      ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`k:real^N->bool`; `l:real^N->bool`] THEN
+    STRIP_TAC THEN MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+    EXISTS_TAC `k INTER l:real^N->bool` THEN ASM_SIMP_TAC[] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `FINITE(d:(real^N->bool)->bool)` THENL
+   [ASM_MESON_TAC[SUBSET_REFL]; ALL_TAC] THEN
+  MP_TAC(ISPEC `d:(real^N->bool)->bool` COUNTABLE_AS_INJECTIVE_IMAGE) THEN
+  ASM_REWRITE_TAC[INFINITE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:num->real^N->bool`
+   (CONJUNCTS_THEN2 SUBST_ALL_TAC ASSUME_TAC)) THEN
+  MP_TAC(ISPECL [`s:num->real^N->bool`; `m + e:real`]
+    HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS) THEN
+  MATCH_MP_TAC(TAUT `a /\ (a /\ b ==> c) ==> (a ==> b) ==> c`) THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IMP_CONJ; RIGHT_FORALL_IMP_THM;
+                              FORALL_IN_IMAGE; IN_UNIV]) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IMP_IMP; RIGHT_IMP_FORALL_THM]) THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[MEASURABLE_INTERVAL; MEASURABLE_INTER];
+    ASM_MESON_TAC[];
+    X_GEN_TAC `n:num` THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE (s:num->real^N->bool) (0..n)`) THEN
+    SIMP_TAC[FINITE_IMAGE; FINITE_NUMSEG; IMAGE_SUBSET; SUBSET_UNIV] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    MATCH_MP_TAC(REAL_ARITH `x = y ==> x <= e ==> y <= e`) THEN
+    MATCH_MP_TAC MEASURE_NEGLIGIBLE_UNIONS_IMAGE THEN
+    ASM_MESON_TAC[FINITE_NUMSEG; MEASURABLE_INTERVAL];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM(CONJUNCT2 LIFT_DROP)] THEN
+  REWRITE_TAC[drop] THEN
+  MATCH_MP_TAC(ISPEC `sequentially` LIM_COMPONENT_UBOUND) THEN
+  EXISTS_TAC
+   `\n. vsum(from 0 INTER (0..n)) (\n. lift(measure(s n:real^N->bool)))` THEN
+  ASM_REWRITE_TAC[GSYM sums; TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+  REWRITE_TAC[DIMINDEX_1; ARITH; EVENTUALLY_SEQUENTIALLY] THEN
+  SIMP_TAC[VSUM_COMPONENT; ARITH; DIMINDEX_1] THEN
+  ASM_REWRITE_TAC[GSYM drop; LIFT_DROP; FROM_INTER_NUMSEG]);;
+
+let MEASURABLE_OUTER_CLOSED_INTERVALS = prove
+ (`!s:real^N->bool e.
+        measurable s /\ &0 < e
+        ==> ?d. COUNTABLE d /\
+                (!k. k IN d ==> ~(k = {}) /\ (?a b. k = interval[a,b])) /\
+                (!k l. k IN d /\ l IN d /\ ~(k = l)
+                       ==> interior k INTER interior l = {}) /\
+                s SUBSET UNIONS d /\
+                measurable (UNIONS d) /\
+                measure (UNIONS d) <= measure s + e`,
+  let lemma = prove
+   (`UNIONS (UNIONS {d n | n IN (:num)}) =
+     UNIONS {UNIONS(d n) | n IN (:num)}`,
+    REWRITE_TAC[SIMPLE_IMAGE; UNIONS_IMAGE] THEN
+    GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_UNIONS; IN_ELIM_THM; IN_UNIV] THEN MESON_TAC[]) in
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?d. COUNTABLE d /\
+        (!k. k IN d ==> ?a b:real^N. k = interval[a,b]) /\
+        s SUBSET UNIONS d /\
+        measurable (UNIONS d) /\
+        measure (UNIONS d) <= measure s + e`
+  MP_TAC THENL
+   [ALL_TAC;
+    DISCH_THEN(X_CHOOSE_THEN `d1:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPEC `d1:(real^N->bool)->bool` COUNTABLE_ELEMENTARY_DIVISION) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `d:(real^N->bool)->bool` THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+    ASM_REWRITE_TAC[]] THEN
+  MP_TAC(ISPECL
+   [`\n. s INTER (ball(vec 0:real^N,&n + &1) DIFF ball(vec 0,&n))`;
+    `measure(s:real^N->bool)`] HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS) THEN
+  ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_DIFF; MEASURABLE_BALL] THEN
+  SUBGOAL_THEN
+   `!m n. ~(m = n)
+          ==> (s INTER (ball(vec 0,&m + &1) DIFF ball(vec 0,&m))) INTER
+              (s INTER (ball(vec 0,&n + &1) DIFF ball(vec 0,&n))) =
+              ({}:real^N->bool)`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC WLOG_LT THEN REWRITE_TAC[] THEN
+    CONJ_TAC THENL [MESON_TAC[INTER_COMM]; ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC(SET_RULE
+     `m1 SUBSET n
+      ==> (s INTER (m1 DIFF m)) INTER (s INTER (n1 DIFF n)) = {}`) THEN
+    MATCH_MP_TAC SUBSET_BALL THEN
+    REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE] THEN ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[NEGLIGIBLE_EMPTY] THEN X_GEN_TAC `n:num` THEN
+    W(MP_TAC o PART_MATCH (rand o rand)
+      MEASURE_DISJOINT_UNIONS_IMAGE o lhand o snd) THEN
+    ASM_SIMP_TAC[FINITE_NUMSEG; DISJOINT] THEN
+    ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_DIFF; MEASURABLE_BALL] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+    SIMP_TAC[SUBSET; FORALL_IN_UNIONS; IMP_CONJ; FORALL_IN_IMAGE;
+             RIGHT_FORALL_IMP_THM; IN_INTER] THEN
+    ASM_SIMP_TAC[MEASURABLE_UNIONS; FINITE_NUMSEG; FORALL_IN_IMAGE;
+            FINITE_IMAGE; MEASURABLE_INTER; MEASURABLE_DIFF; MEASURABLE_BALL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `UNIONS {s INTER (ball(vec 0,&n + &1) DIFF ball(vec 0,&n)) | n IN (:num)} =
+    (s:real^N->bool)`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_UNIONS; EXISTS_IN_GSPEC; IN_UNIV; IN_INTER] THEN
+    X_GEN_TAC `x:real^N` THEN
+    ASM_CASES_TAC `(x:real^N) IN s` THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `?n. (x:real^N) IN ball(vec 0,&n)` MP_TAC THENL
+     [REWRITE_TAC[IN_BALL_0; REAL_ARCH_LT];
+      GEN_REWRITE_TAC LAND_CONV [num_WOP] THEN
+      DISCH_THEN(X_CHOOSE_THEN `n:num` MP_TAC) THEN ASM_CASES_TAC `n = 0` THENL
+       [ASM_REWRITE_TAC[IN_BALL_0; GSYM REAL_NOT_LE; NORM_POS_LE];
+        STRIP_TAC THEN EXISTS_TAC `n - 1` THEN REWRITE_TAC[IN_DIFF] THEN
+        ASM_SIMP_TAC[REAL_OF_NUM_ADD; SUB_ADD; LE_1] THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC]];
+    ASM_REWRITE_TAC[] THEN DISCH_TAC] THEN
+  MP_TAC(MATCH_MP MONO_FORALL (GEN `n:num`
+   (ISPECL
+     [`s INTER (ball(vec 0:real^N,&n + &1) DIFF ball(vec 0,&n))`;
+      `--(vec(n + 1)):real^N`; `vec(n + 1):real^N`;
+      `e / &2 / &2 pow n`]
+        MEASURABLE_OUTER_INTERVALS_BOUNDED))) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[REAL_LT_DIV; REAL_HALF; REAL_LT_POW2] THEN
+    ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_DIFF; MEASURABLE_BALL] THEN
+    REWRITE_TAC[SUBSET; IN_INTER; IN_INTERVAL; IN_BALL_0; IN_DIFF; REAL_NOT_LT;
+      REAL_OF_NUM_ADD; VECTOR_NEG_COMPONENT; VEC_COMPONENT; REAL_BOUNDS_LE] THEN
+    MESON_TAC[COMPONENT_LE_NORM; REAL_LET_TRANS; REAL_LT_IMP_LE];
+    REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM; FORALL_AND_THM]] THEN
+  X_GEN_TAC `d:num->(real^N->bool)->bool` THEN STRIP_TAC THEN
+  EXISTS_TAC `UNIONS {d n | n IN (:num)} :(real^N->bool)->bool` THEN
+  REWRITE_TAC[lemma] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC COUNTABLE_UNIONS THEN
+    ASM_REWRITE_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE] THEN
+    SIMP_TAC[COUNTABLE_IMAGE; NUM_COUNTABLE];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[FORALL_IN_UNIONS; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    ASM_SIMP_TAC[FORALL_IN_GSPEC; IN_UNIV] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [GSYM th]) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_UNIONS; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    ASM_SIMP_TAC[FORALL_IN_GSPEC; IN_UNIV; IN_UNIONS] THEN
+    REWRITE_TAC[EXISTS_IN_GSPEC] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MEASURE_COUNTABLE_UNIONS_LE THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `n:num` THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+   `sum(0..n) (\k. measure(s INTER (ball(vec 0:real^N,&k + &1) DIFF
+                                  ball(vec 0,&k))) + e / &2 / &2 pow k)` THEN
+  ASM_SIMP_TAC[SUM_LE_NUMSEG] THEN REWRITE_TAC[SUM_ADD_NUMSEG] THEN
+  MATCH_MP_TAC REAL_LE_ADD2 THEN CONJ_TAC THENL
+   [W(MP_TAC o PART_MATCH (rand o rand) MEASURE_DISJOINT_UNIONS_IMAGE o
+      lhand o snd) THEN
+    ASM_SIMP_TAC[DISJOINT; FINITE_NUMSEG; MEASURABLE_DIFF; MEASURABLE_INTER;
+                 MEASURABLE_BALL] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+    ASM_SIMP_TAC[MEASURABLE_UNIONS; FORALL_IN_IMAGE; FINITE_NUMSEG;
+      FINITE_IMAGE; MEASURABLE_DIFF; MEASURABLE_INTER; MEASURABLE_BALL] THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [GSYM th]) THEN
+    MATCH_MP_TAC SUBSET_UNIONS THEN REWRITE_TAC[SIMPLE_IMAGE] THEN
+    MATCH_MP_TAC IMAGE_SUBSET THEN REWRITE_TAC[SUBSET_UNIV];
+    REWRITE_TAC[real_div; SUM_LMUL; REAL_INV_POW; SUM_GP; LT] THEN
+    REWRITE_TAC[GSYM real_div] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[REAL_ARITH `e / &2 * (&1 - x) / (&1 / &2) <= e <=>
+                            &0 <= e * x`] THEN
+    MATCH_MP_TAC REAL_LE_MUL THEN ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+    MATCH_MP_TAC REAL_POW_LE THEN CONV_TAC REAL_RAT_REDUCE_CONV]);;
+
+let MEASURABLE_OUTER_OPEN_INTERVALS = prove
+ (`!s:real^N->bool e.
+        measurable s /\ &0 < e
+        ==> ?d. COUNTABLE d /\
+                (!k. k IN d ==> ~(k = {}) /\ (?a b. k = interval(a,b))) /\
+                s SUBSET UNIONS d /\
+                measurable (UNIONS d) /\
+                measure (UNIONS d) <= measure s + e`,
+  let lemma = prove
+   (`!s. UNIONS(s DELETE {}) = UNIONS s`,
+    REWRITE_TAC[EXTENSION; IN_UNIONS; IN_DELETE] THEN
+    MESON_TAC[NOT_IN_EMPTY]) in
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `e / &2`]
+    MEASURABLE_OUTER_CLOSED_INTERVALS) THEN
+  ASM_REWRITE_TAC[REAL_HALF; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `dset:(real^N->bool)->bool` THEN
+  ASM_CASES_TAC `dset:(real^N->bool)->bool = {}` THENL
+   [ASM_REWRITE_TAC[UNIONS_0; SUBSET_EMPTY] THEN STRIP_TAC THEN
+    EXISTS_TAC `{}:(real^N->bool)->bool` THEN
+    ASM_REWRITE_TAC[UNIONS_0; NOT_IN_EMPTY; MEASURE_EMPTY; SUBSET_REFL] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  SUBGOAL_THEN
+   `?f. dset = IMAGE (f:num->(real^N->bool)) (:num) DELETE {} /\
+        (!m n. f m = f n ==> m = n \/ f n = {})`
+  MP_TAC THENL
+   [ASM_CASES_TAC `FINITE(dset:(real^N->bool)->bool)` THENL
+     [FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [FINITE_HAS_SIZE]) THEN
+      DISCH_THEN(MP_TAC o MATCH_MP HAS_SIZE_INDEX) THEN
+      ABBREV_TAC `m = CARD(dset:(real^N->bool)->bool)` THEN
+      DISCH_THEN(X_CHOOSE_THEN `f:num->real^N->bool` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `\i. if i < m then (f:num->real^N->bool) i else {}` THEN
+      REWRITE_TAC[] THEN CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+      GEN_REWRITE_TAC I [EXTENSION] THEN
+      REWRITE_TAC[IN_DELETE; IN_IMAGE; IN_UNIV] THEN ASM_MESON_TAC[];
+      MP_TAC(ISPEC `dset:(real^N->bool)->bool`
+        COUNTABLE_AS_INJECTIVE_IMAGE) THEN
+      ASM_REWRITE_TAC[INFINITE] THEN MATCH_MP_TAC MONO_EXISTS THEN
+      GEN_TAC THEN STRIP_TAC THEN CONJ_TAC THENL
+       [ALL_TAC; ASM_MESON_TAC[]] THEN
+      ASM_REWRITE_TAC[SET_RULE `s = s DELETE a <=> ~(a IN s)`] THEN
+      ASM_MESON_TAC[]];
+    ALL_TAC] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `d:num->real^N->bool` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC MP_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o check (is_forall o concl)) THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; IN_UNIV; FORALL_AND_THM; SKOLEM_THM;
+              IMP_CONJ; RIGHT_FORALL_IMP_THM; IN_DELETE; lemma] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (MESON[]
+   `(!x. ~(P x) ==> ~(P x) /\ Q x) ==> (!x. P x ==> Q x) ==> !x. Q x`)) THEN
+  ANTS_TAC THENL [MESON_TAC[EMPTY_AS_INTERVAL]; ALL_TAC] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:num->real^N`; `b:num->real^N`] THEN
+  DISCH_TAC THEN DISCH_TAC THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; GSYM CONJ_ASSOC] THEN
+  GEN_REWRITE_TAC I [IMP_CONJ] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP(MESON[]
+   `(!x y. ~(P x) /\ ~(P y) /\ ~(f x = f y) ==> Q x y)
+    ==> (!x y. P x ==> Q x y) /\ (!x y. P y ==> Q x y)
+        ==> (!x y. ~(f x = f y) ==> Q x y)`)) THEN
+  SIMP_TAC[INTERIOR_EMPTY; INTER_EMPTY] THEN
+  ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?d. COUNTABLE d /\
+        (!k. k IN d ==> ?a b:real^N. k = interval(a,b)) /\
+        s SUBSET UNIONS d /\
+        measurable (UNIONS d) /\
+        measure (UNIONS d) <= measure s + e`
+  MP_TAC THENL
+   [ALL_TAC;
+    DISCH_THEN(X_CHOOSE_TAC `d:(real^N->bool)->bool`) THEN
+    EXISTS_TAC `d DELETE ({}:real^N->bool)` THEN
+    ASM_SIMP_TAC[lemma; COUNTABLE_DELETE; IN_DELETE]] THEN
+  MP_TAC(GEN `n:num` (ISPECL [`(a:num->real^N) n`; `(b:num->real^N) n`;
+    `e / &2 pow (n + 2)`] EXPAND_CLOSED_OPEN_INTERVAL)) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_POW2; SKOLEM_THM] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; FORALL_AND_THM] THEN
+  MAP_EVERY X_GEN_TAC [`A:num->real^N`; `B:num->real^N`] THEN STRIP_TAC THEN
+  EXISTS_TAC `IMAGE (\n. interval(A n:real^N,B n)) (:num)` THEN
+  SIMP_TAC[COUNTABLE_IMAGE; NUM_COUNTABLE; FORALL_IN_IMAGE; IN_UNIV] THEN
+  CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  CONJ_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ] SUBSET_TRANS)) THEN
+    ASM_REWRITE_TAC[SUBSET; FORALL_IN_UNIONS] THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE; IN_UNIV] THEN
+    MAP_EVERY X_GEN_TAC [`n:num`; `x:real^N`] THEN
+    ASM_REWRITE_TAC[IN_UNIONS; EXISTS_IN_IMAGE; IN_UNIV] THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[GSYM SIMPLE_IMAGE] THEN
+  MATCH_MP_TAC MEASURE_COUNTABLE_UNIONS_LE THEN
+  REWRITE_TAC[MEASURABLE_INTERVAL] THEN X_GEN_TAC `n:num` THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+   `sum(0..n) (\i. measure(interval[a i:real^N,b i]) + e / &2 pow (i + 2))` THEN
+  ASM_SIMP_TAC[SUM_LE_NUMSEG] THEN REWRITE_TAC[SUM_ADD_NUMSEG] THEN
+  REWRITE_TAC[real_div; REAL_INV_MUL; SUM_LMUL; REAL_POW_ADD; SUM_RMUL] THEN
+  REWRITE_TAC[REAL_INV_POW; SUM_GP; LT] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `s <= m + e / &2 /\ &0 <= e * x
+    ==> s + e * (&1 - x) / (&1 / &2) * &1 / &4 <= m + e`) THEN
+  ASM_SIMP_TAC[REAL_LE_MUL; REAL_POW_LE; REAL_LT_IMP_LE;
+               REAL_LE_DIV; REAL_POS] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS)) THEN
+  W(MP_TAC o PART_MATCH (rhs o rand) MEASURE_NEGLIGIBLE_UNIONS_IMAGE o
+        lhand o snd) THEN
+  REWRITE_TAC[FINITE_NUMSEG; MEASURABLE_INTERVAL] THEN ANTS_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`i:num`; `j:num`] THEN STRIP_TAC THEN
+    ASM_CASES_TAC `interval[(a:num->real^N) i,b i] = interval[a j,b j]` THENL
+     [UNDISCH_TAC
+       `!m n. (d:num->real^N->bool) m = d n ==> m = n \/ d n = {}` THEN
+      DISCH_THEN(MP_TAC o SPECL [`i:num`; `j:num`]) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[INTER_EMPTY; NEGLIGIBLE_EMPTY];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE
+       (BINDER_CONV o BINDER_CONV o RAND_CONV o LAND_CONV)
+       [GSYM INTERIOR_INTER]) THEN
+      DISCH_THEN(MP_TAC o SPECL [`i:num`; `j:num`]) THEN
+      ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[GSYM HAS_MEASURE_0; HAS_MEASURE_MEASURABLE_MEASURE] THEN
+      SIMP_TAC[MEASURABLE_INTER; MEASURABLE_INTERVAL] THEN
+      MATCH_MP_TAC(MESON[MEASURE_EMPTY]
+       `measure(interior s) = measure s
+        ==> interior s = {} ==> measure s = &0`) THEN
+      MATCH_MP_TAC MEASURE_INTERIOR THEN
+      SIMP_TAC[BOUNDED_INTER; BOUNDED_INTERVAL; NEGLIGIBLE_CONVEX_FRONTIER;
+               CONVEX_INTER; CONVEX_INTERVAL]];
+    DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  MATCH_MP_TAC MEASURE_SUBSET THEN CONJ_TAC THENL
+   [MATCH_MP_TAC MEASURABLE_UNIONS THEN
+    SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE; MEASURABLE_INTERVAL;
+             FINITE_NUMSEG];
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC SUBSET_UNIONS THEN
+    ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    ASM_REWRITE_TAC[IN_IMAGE; IN_UNIV] THEN MESON_TAC[]]);;
+
+let MEASURABLE_OUTER_OPEN = prove
+ (`!s:real^N->bool e.
+        measurable s /\ &0 < e
+        ==> ?t. open t /\ s SUBSET t /\
+                measurable t /\ measure t < measure s + e`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `e / &2`]
+    MEASURABLE_OUTER_OPEN_INTERVALS) THEN
+  ASM_REWRITE_TAC[REAL_HALF; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `d:(real^N->bool)->bool` THEN STRIP_TAC THEN
+  EXISTS_TAC `UNIONS d :real^N->bool` THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 < e /\ m <= s + e / &2 ==> m < s + e`] THEN
+  MATCH_MP_TAC OPEN_UNIONS THEN ASM_MESON_TAC[OPEN_INTERVAL]);;
+
+let MEASURABLE_INNER_COMPACT = prove
+ (`!s:real^N->bool e.
+        measurable s /\ &0 < e
+        ==> ?t. compact t /\ t SUBSET s /\
+                measurable t /\ measure s < measure t + e`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HAS_MEASURE_MEASURE]) THEN
+  GEN_REWRITE_TAC LAND_CONV [HAS_MEASURE_LIMIT] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &4`) THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 < e ==> &0 < e / &4`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  MP_TAC(ISPEC `ball(vec 0:real^N,B)` BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+  REWRITE_TAC[BOUNDED_BALL; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+  DISCH_THEN(MP_TAC o SPECL [`a:real^N`; `b:real^N`]) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `z:real` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL  [`interval[a:real^N,b] DIFF s`; `e/ &4`]
+        MEASURABLE_OUTER_OPEN) THEN
+  ASM_SIMP_TAC[MEASURABLE_DIFF; MEASURABLE_INTERVAL;
+               REAL_ARITH `&0 < e ==> &0 < e / &4`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `interval[a:real^N,b] DIFF t` THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN
+    ASM_SIMP_TAC[CLOSED_DIFF; CLOSED_INTERVAL; BOUNDED_DIFF; BOUNDED_INTERVAL];
+    ASM SET_TAC[];
+    ASM_SIMP_TAC[MEASURABLE_DIFF; MEASURABLE_INTERVAL];
+    MATCH_MP_TAC(REAL_ARITH
+        `&0 < e /\
+         measure(s) < measure(interval[a,b] INTER s) + e / &4 /\
+         measure(t) < measure(interval[a,b] DIFF s) + e / &4 /\
+         measure(interval[a,b] INTER s) +
+         measure(interval[a,b] DIFF s) = measure(interval[a,b]) /\
+         measure(interval[a,b] INTER t) +
+         measure(interval[a,b] DIFF t) = measure(interval[a,b]) /\
+         measure(interval[a,b] INTER t) <= measure t
+         ==> measure s < measure(interval[a,b] DIFF t) + e`) THEN
+    ASM_SIMP_TAC[MEASURE_SUBSET; INTER_SUBSET; MEASURABLE_INTER;
+                 MEASURABLE_INTERVAL] THEN
+    CONJ_TAC THENL
+     [FIRST_ASSUM(SUBST_ALL_TAC o SYM o MATCH_MP MEASURE_UNIQUE) THEN
+      ONCE_REWRITE_TAC[INTER_COMM] THEN ASM_REAL_ARITH_TAC;
+      CONJ_TAC THEN MATCH_MP_TAC MEASURE_DISJOINT_UNION_EQ THEN
+      ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_DIFF; MEASURABLE_INTERVAL] THEN
+      SET_TAC[]]]);;
+
+let OPEN_MEASURABLE_INNER_DIVISION = prove
+ (`!s:real^N->bool e.
+        open s /\ measurable s /\ &0 < e
+        ==> ?D. D division_of UNIONS D /\
+                UNIONS D SUBSET s /\
+                measure s < measure(UNIONS D) + e`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `e / &2`] MEASURE_LIMIT) THEN
+  ASM_REWRITE_TAC[REAL_HALF; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `B:real` THEN STRIP_TAC THEN
+  MP_TAC(ISPEC `ball(vec 0:real^N,B)` BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+  ASM_REWRITE_TAC[BOUNDED_BALL; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`a:real^N`; `b:real^N`]) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  MP_TAC(ISPEC `s INTER interval(a - vec 1:real^N,b + vec 1)`
+        OPEN_COUNTABLE_UNION_CLOSED_INTERVALS) THEN
+  ASM_SIMP_TAC[OPEN_INTER; OPEN_INTERVAL; SUBSET_INTER] THEN
+  DISCH_THEN(X_CHOOSE_THEN `D:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`D:(real^N->bool)->bool`; `measure(s:real^N->bool)`;
+                 `e / &2`] MEASURE_COUNTABLE_UNIONS_APPROACHABLE) THEN
+  ASM_REWRITE_TAC[REAL_HALF] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [ASM_MESON_TAC[MEASURABLE_INTERVAL]; ALL_TAC] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `measure(UNIONS D :real^N->bool)` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC MEASURE_SUBSET THEN REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC MEASURABLE_UNIONS THEN
+        ASM_MESON_TAC[SUBSET; MEASURABLE_INTERVAL];
+        ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_INTERVAL];
+        ASM_SIMP_TAC[SUBSET_UNIONS]];
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+      ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_INTERVAL; INTER_SUBSET]];
+    DISCH_THEN(X_CHOOSE_THEN `d:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPEC `d:(real^N->bool)->bool` ELEMENTARY_UNIONS_INTERVALS) THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[MEASURABLE_INTERVAL; SUBSET]; ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `p:(real^N->bool)->bool` THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN `UNIONS p :real^N->bool = UNIONS d` SUBST1_TAC THENL
+     [ASM_MESON_TAC[division_of]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `UNIONS D :real^N->bool` THEN
+      ASM_SIMP_TAC[SUBSET_UNIONS; INTER_SUBSET];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+       `ms' - e / &2 < mud ==> ms < ms' + e / &2 ==> ms < mud + e`)) THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+       `abs(sc - s) < e / &2
+        ==> sc <= so /\ sc <= s ==> s < so + e / &2`)) THEN
+      CONJ_TAC THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+      ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_INTERVAL; INTER_SUBSET] THEN
+      MATCH_MP_TAC(SET_RULE `t SUBSET u ==> s INTER t SUBSET s INTER u`) THEN
+      REWRITE_TAC[SUBSET_INTERVAL; VECTOR_SUB_COMPONENT; VEC_COMPONENT;
+                  VECTOR_ADD_COMPONENT] THEN
+      MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+      MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN REAL_ARITH_TAC]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence for linear transformation, suffices to check compact intervals.     *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_LINEAR_IMAGE_INTERVAL = prove
+ (`!f a b. linear f ==> measurable(IMAGE f (interval[a,b]))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_CONVEX THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONVEX_LINEAR_IMAGE THEN
+    ASM_MESON_TAC[CONVEX_INTERVAL];
+    MATCH_MP_TAC BOUNDED_LINEAR_IMAGE THEN
+    ASM_MESON_TAC[BOUNDED_INTERVAL]]);;
+
+let HAS_MEASURE_LINEAR_SUFFICIENT = prove
+ (`!f:real^N->real^N m.
+        linear f /\
+        (!a b. IMAGE f (interval[a,b]) has_measure
+               (m * measure(interval[a,b])))
+        ==> !s. measurable s ==> (IMAGE f s) has_measure (m * measure s)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  DISJ_CASES_TAC(REAL_ARITH `m < &0 \/ &0 <= m`) THENL
+   [FIRST_X_ASSUM(MP_TAC o SPECL [`vec 0:real^N`; `vec 1:real^N`]) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HAS_MEASURE_POS_LE) THEN
+    MATCH_MP_TAC(TAUT `~a ==> a ==> b`) THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < --m * x ==> ~(&0 <= m * x)`) THEN
+    MATCH_MP_TAC REAL_LT_MUL THEN ASM_REWRITE_TAC[REAL_NEG_GT0] THEN
+    REWRITE_TAC[MEASURE_INTERVAL] THEN MATCH_MP_TAC CONTENT_POS_LT THEN
+    SIMP_TAC[VEC_COMPONENT; REAL_LT_01];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `!x y. (f:real^N->real^N) x = f y ==> x = y` THENL
+   [ALL_TAC;
+    SUBGOAL_THEN `!s. negligible(IMAGE (f:real^N->real^N) s)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[NEGLIGIBLE_LINEAR_SINGULAR_IMAGE]; ALL_TAC] THEN
+    SUBGOAL_THEN `m * measure(interval[vec 0:real^N,vec 1]) = &0` MP_TAC THENL
+     [MATCH_MP_TAC(ISPEC `IMAGE (f:real^N->real^N) (interval[vec 0,vec 1])`
+        HAS_MEASURE_UNIQUE) THEN
+      ASM_REWRITE_TAC[HAS_MEASURE_0];
+      REWRITE_TAC[REAL_ENTIRE; MEASURE_INTERVAL] THEN
+      MATCH_MP_TAC(TAUT `~b /\ (a ==> c) ==> a \/ b ==> c`) THEN CONJ_TAC THENL
+       [SIMP_TAC[CONTENT_EQ_0_INTERIOR; INTERIOR_CLOSED_INTERVAL;
+                 INTERVAL_NE_EMPTY; VEC_COMPONENT; REAL_LT_01];
+        ASM_SIMP_TAC[REAL_MUL_LZERO; HAS_MEASURE_0]]]] THEN
+  MP_TAC(ISPEC `f:real^N->real^N` LINEAR_INJECTIVE_ISOMORPHISM) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^N->real^N` STRIP_ASSUME_TAC) THEN
+  UNDISCH_THEN `!x y. (f:real^N->real^N) x = f y ==> x = y` (K ALL_TAC) THEN
+  SUBGOAL_THEN
+   `!s. bounded s /\ measurable s
+        ==> (IMAGE (f:real^N->real^N) s) has_measure (m * measure s)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `!d. COUNTABLE d /\
+          (!k. k IN d ==> k SUBSET interval[a,b] /\ ~(k = {}) /\
+                          (?c d. k = interval[c,d])) /\
+          (!k1 k2. k1 IN d /\ k2 IN d /\ ~(k1 = k2)
+                   ==> interior k1 INTER interior k2 = {})
+          ==> IMAGE (f:real^N->real^N) (UNIONS d) has_measure
+                    (m * measure(UNIONS d))`
+    ASSUME_TAC THENL
+     [REWRITE_TAC[IMAGE_UNIONS] THEN REPEAT STRIP_TAC THEN
+      SUBGOAL_THEN
+       `!g:real^N->real^N.
+          linear g
+          ==> !k l. k IN d /\ l IN d /\ ~(k = l)
+                    ==> negligible((IMAGE g k) INTER (IMAGE g l))`
+      MP_TAC THENL
+       [REPEAT STRIP_TAC THEN
+        ASM_CASES_TAC `!x y. (g:real^N->real^N) x = g y ==> x = y` THENL
+         [ALL_TAC;
+          ASM_MESON_TAC[NEGLIGIBLE_LINEAR_SINGULAR_IMAGE;
+                        NEGLIGIBLE_INTER]] THEN
+        MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+        EXISTS_TAC `frontier(IMAGE (g:real^N->real^N) k INTER IMAGE g l) UNION
+                    interior(IMAGE g k INTER IMAGE g l)` THEN
+        CONJ_TAC THENL
+         [ALL_TAC;
+          REWRITE_TAC[frontier] THEN MATCH_MP_TAC(SET_RULE
+           `s SUBSET t ==> s SUBSET (t DIFF u) UNION u`) THEN
+          REWRITE_TAC[CLOSURE_SUBSET]] THEN
+        MATCH_MP_TAC NEGLIGIBLE_UNION THEN CONJ_TAC THENL
+         [MATCH_MP_TAC NEGLIGIBLE_CONVEX_FRONTIER THEN
+          MATCH_MP_TAC CONVEX_INTER THEN CONJ_TAC THEN
+          MATCH_MP_TAC CONVEX_LINEAR_IMAGE THEN ASM_MESON_TAC[CONVEX_INTERVAL];
+          ALL_TAC] THEN
+        REWRITE_TAC[INTERIOR_INTER] THEN MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+        EXISTS_TAC `IMAGE (g:real^N->real^N) (interior k) INTER
+                    IMAGE g (interior l)` THEN
+        CONJ_TAC THENL
+         [MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+          EXISTS_TAC
+           `IMAGE (g:real^N->real^N) (interior k INTER interior l)` THEN
+          CONJ_TAC THENL
+           [ASM_SIMP_TAC[IMAGE_CLAUSES; NEGLIGIBLE_EMPTY]; ASM SET_TAC[]];
+          MATCH_MP_TAC(SET_RULE
+           `s SUBSET u /\ t SUBSET v ==> (s INTER t) SUBSET (u INTER v)`) THEN
+          CONJ_TAC THEN MATCH_MP_TAC INTERIOR_IMAGE_SUBSET THEN
+          ASM_MESON_TAC[LINEAR_CONTINUOUS_AT]];
+        ALL_TAC] THEN
+      DISCH_THEN(fun th -> MP_TAC(SPEC `f:real^N->real^N` th) THEN
+          MP_TAC(SPEC `\x:real^N. x` th)) THEN
+      ASM_REWRITE_TAC[LINEAR_ID; SET_RULE `IMAGE (\x. x) s = s`] THEN
+      REPEAT STRIP_TAC THEN ASM_CASES_TAC `FINITE(d:(real^N->bool)->bool)` THENL
+       [MP_TAC(ISPECL [`IMAGE (f:real^N->real^N)`; `d:(real^N->bool)->bool`]
+                  HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE) THEN
+        ANTS_TAC THENL [ASM_MESON_TAC[measurable]; ALL_TAC] THEN
+        MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+        MATCH_MP_TAC EQ_TRANS THEN
+        EXISTS_TAC `sum d (\k:real^N->bool. m * measure k)` THEN CONJ_TAC THENL
+         [MATCH_MP_TAC SUM_EQ THEN ASM_MESON_TAC[MEASURE_UNIQUE]; ALL_TAC] THEN
+        REWRITE_TAC[SUM_LMUL] THEN AP_TERM_TAC THEN
+        CONV_TAC SYM_CONV THEN MATCH_MP_TAC MEASURE_NEGLIGIBLE_UNIONS THEN
+        ASM_REWRITE_TAC[GSYM HAS_MEASURE_MEASURE] THEN
+        ASM_MESON_TAC[MEASURABLE_INTERVAL];
+        ALL_TAC] THEN
+      MP_TAC(ISPEC `d:(real^N->bool)->bool` COUNTABLE_AS_INJECTIVE_IMAGE) THEN
+      ASM_REWRITE_TAC[INFINITE] THEN
+      DISCH_THEN(X_CHOOSE_THEN `s:num->real^N->bool`
+       (CONJUNCTS_THEN2 SUBST_ALL_TAC ASSUME_TAC)) THEN
+      MP_TAC(ISPEC `s:num->real^N->bool`
+        HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS_BOUNDED) THEN
+      MP_TAC(ISPEC `\n:num. IMAGE (f:real^N->real^N) (s n)`
+        HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS_BOUNDED) THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IMP_CONJ; RIGHT_FORALL_IMP_THM;
+                                  FORALL_IN_IMAGE; IN_UNIV]) THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IMP_IMP; RIGHT_IMP_FORALL_THM]) THEN
+      ASM_SIMP_TAC[] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN ANTS_TAC THENL
+       [REPEAT CONJ_TAC THENL
+         [ASM_MESON_TAC[MEASURABLE_LINEAR_IMAGE_INTERVAL];
+          ASM_MESON_TAC[];
+          ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+          REWRITE_TAC[GSYM IMAGE_UNIONS; IMAGE_o] THEN
+          MATCH_MP_TAC BOUNDED_LINEAR_IMAGE THEN ASM_REWRITE_TAC[] THEN
+          MATCH_MP_TAC BOUNDED_SUBSET THEN REWRITE_TAC[UNIONS_SUBSET] THEN
+          EXISTS_TAC `interval[a:real^N,b]` THEN
+          REWRITE_TAC[BOUNDED_INTERVAL] THEN ASM SET_TAC[]];
+        ALL_TAC] THEN
+      STRIP_TAC THEN ANTS_TAC THENL
+       [REPEAT CONJ_TAC THENL
+         [ASM_MESON_TAC[MEASURABLE_INTERVAL];
+          ASM_MESON_TAC[];
+          MATCH_MP_TAC BOUNDED_SUBSET THEN REWRITE_TAC[UNIONS_SUBSET] THEN
+          EXISTS_TAC `interval[a:real^N,b]` THEN
+          REWRITE_TAC[BOUNDED_INTERVAL] THEN ASM SET_TAC[]];
+        ALL_TAC] THEN
+      STRIP_TAC THEN REWRITE_TAC[GSYM IMAGE_o; o_DEF] THEN
+      SUBGOAL_THEN `m * measure (UNIONS (IMAGE s (:num)):real^N->bool) =
+             measure(UNIONS (IMAGE (\x. IMAGE f (s x)) (:num)):real^N->bool)`
+       (fun th -> ASM_REWRITE_TAC[GSYM HAS_MEASURE_MEASURE; th]) THEN
+      ONCE_REWRITE_TAC[GSYM LIFT_EQ] THEN
+      MATCH_MP_TAC SERIES_UNIQUE THEN
+      EXISTS_TAC `\n:num. lift(measure(IMAGE (f:real^N->real^N) (s n)))` THEN
+      EXISTS_TAC `from 0` THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC SUMS_EQ THEN
+      EXISTS_TAC `\n:num. m % lift(measure(s n:real^N->bool))` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[GSYM LIFT_CMUL; LIFT_EQ] THEN
+        ASM_MESON_TAC[MEASURE_UNIQUE];
+        REWRITE_TAC[LIFT_CMUL] THEN MATCH_MP_TAC SERIES_CMUL THEN
+        ASM_REWRITE_TAC[]];
+      ALL_TAC] THEN
+    REWRITE_TAC[HAS_MEASURE_INNER_OUTER_LE] THEN CONJ_TAC THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THENL
+     [MP_TAC(ISPECL [`interval[a,b] DIFF s:real^N->bool`; `a:real^N`;
+       `b:real^N`; `e / (&1 + abs m)`] MEASURABLE_OUTER_INTERVALS_BOUNDED) THEN
+      ANTS_TAC THENL
+       [ASM_SIMP_TAC[MEASURABLE_DIFF; MEASURABLE_INTERVAL] THEN
+        ASM_SIMP_TAC[REAL_ARITH `&0 < &1 + abs x`; REAL_LT_DIV] THEN SET_TAC[];
+        ALL_TAC] THEN
+      DISCH_THEN(X_CHOOSE_THEN `d:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `IMAGE f (interval[a,b]) DIFF
+                  IMAGE (f:real^N->real^N) (UNIONS d)` THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `d:(real^N->bool)->bool`) THEN
+      ASM_SIMP_TAC[IMAGE_SUBSET] THEN DISCH_TAC THEN
+      CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[MEASURABLE_DIFF; measurable]; ALL_TAC] THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `measure(IMAGE f (interval[a,b])) -
+                  measure(IMAGE (f:real^N->real^N) (UNIONS d))` THEN
+      CONJ_TAC THENL
+       [ALL_TAC;
+        MATCH_MP_TAC REAL_EQ_IMP_LE THEN CONV_TAC SYM_CONV THEN
+        MATCH_MP_TAC MEASURE_DIFF_SUBSET THEN
+        REPEAT(CONJ_TAC THENL [ASM_MESON_TAC[measurable]; ALL_TAC]) THEN
+        MATCH_MP_TAC IMAGE_SUBSET THEN ASM_SIMP_TAC[UNIONS_SUBSET]] THEN
+      UNDISCH_TAC `!a b. IMAGE (f:real^N->real^N) (interval [a,b])
+                         has_measure m * measure (interval [a,b])` THEN
+      DISCH_THEN(ASSUME_TAC o SPECL [`a:real^N`; `b:real^N`]) THEN
+      REPEAT(FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP MEASURE_UNIQUE)) THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `m * measure(s:real^N->bool) - m * e / (&1 + abs m)` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[REAL_ARITH `a - x <= a - y <=> y <= x`] THEN
+        REWRITE_TAC[real_div; REAL_MUL_ASSOC] THEN
+        REWRITE_TAC[GSYM real_div] THEN
+        ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_ARITH `&0 < &1 + abs x`] THEN
+        GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
+        ASM_SIMP_TAC[REAL_LE_RMUL_EQ] THEN REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[GSYM REAL_SUB_LDISTRIB] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
+      ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+        `d <= a + e ==> a = i - s ==> s - e <= i - d`)) THEN
+      MATCH_MP_TAC MEASURE_DIFF_SUBSET THEN
+      ASM_REWRITE_TAC[MEASURABLE_INTERVAL];
+      MP_TAC(ISPECL [`s:real^N->bool`; `a:real^N`; `b:real^N`;
+                `e / (&1 + abs m)`] MEASURABLE_OUTER_INTERVALS_BOUNDED) THEN
+      ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < &1 + abs x`] THEN
+      DISCH_THEN(X_CHOOSE_THEN `d:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `IMAGE (f:real^N->real^N) (UNIONS d)` THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `d:(real^N->bool)->bool`) THEN
+      ASM_SIMP_TAC[IMAGE_SUBSET] THEN
+      SIMP_TAC[HAS_MEASURE_MEASURABLE_MEASURE] THEN STRIP_TAC THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `m * measure(s:real^N->bool) + m * e / (&1 + abs m)` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[GSYM REAL_ADD_LDISTRIB] THEN ASM_SIMP_TAC[REAL_LE_LMUL];
+        REWRITE_TAC[REAL_LE_LADD] THEN
+        REWRITE_TAC[real_div; REAL_MUL_ASSOC] THEN
+        REWRITE_TAC[GSYM real_div] THEN
+        ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_ARITH `&0 < &1 + abs x`] THEN
+        GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
+        ASM_SIMP_TAC[REAL_LE_RMUL_EQ] THEN REAL_ARITH_TAC]];
+      ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[HAS_MEASURE_LIMIT] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HAS_MEASURE_MEASURE]) THEN
+  GEN_REWRITE_TAC LAND_CONV [HAS_MEASURE_LIMIT] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / (&1 + abs m)`) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_ARITH `&0 < &1 + abs x`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "*"))) THEN
+  MP_TAC(ISPEC `ball(vec 0:real^N,B)` BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+  REWRITE_TAC[BOUNDED_BALL; LEFT_IMP_EXISTS_THM] THEN
+  REMOVE_THEN "*" MP_TAC THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `c:real^N` THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `d:real^N` THEN
+  DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`interval[c:real^N,d]`; `vec 0:real^N`]
+    BOUNDED_SUBSET_BALL) THEN
+  REWRITE_TAC[BOUNDED_INTERVAL] THEN
+  DISCH_THEN(X_CHOOSE_THEN `D:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPEC `f:real^N->real^N` LINEAR_BOUNDED_POS) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `C:real` STRIP_ASSUME_TAC) THEN
+
+  EXISTS_TAC `D * C:real` THEN ASM_SIMP_TAC[REAL_LT_MUL] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC
+   `s INTER (IMAGE (h:real^N->real^N) (interval[a,b]))`) THEN
+  SUBGOAL_THEN
+   `IMAGE (f:real^N->real^N) (s INTER IMAGE h (interval [a,b])) =
+    (IMAGE f s) INTER interval[a,b]`
+  SUBST1_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN ANTS_TAC THENL
+   [ASM_SIMP_TAC[BOUNDED_INTER; BOUNDED_LINEAR_IMAGE; BOUNDED_INTERVAL] THEN
+    ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_LINEAR_IMAGE_INTERVAL];
+    ALL_TAC] THEN
+  DISCH_TAC THEN EXISTS_TAC
+   `m * measure(s INTER (IMAGE (h:real^N->real^N) (interval[a,b])))` THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `m * e / (&1 + abs m)` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[real_div; REAL_MUL_ASSOC] THEN REWRITE_TAC[GSYM real_div] THEN
+    ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_ARITH `&0 < &1 + abs x`] THEN
+    GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[REAL_LT_RMUL_EQ] THEN REAL_ARITH_TAC] THEN
+  REWRITE_TAC[GSYM REAL_SUB_LDISTRIB; REAL_ABS_MUL] THEN
+  GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [real_abs] THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_LMUL THEN ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+   `abs(z - m) < e ==> z <= w /\ w <= m ==> abs(w - m) <= e`)) THEN
+  SUBST1_TAC(SYM(MATCH_MP MEASURE_UNIQUE
+   (ASSUME `s INTER interval [c:real^N,d] has_measure z`))) THEN
+  CONJ_TAC THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+  ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_LINEAR_IMAGE_INTERVAL;
+               MEASURABLE_INTERVAL; INTER_SUBSET] THEN
+  MATCH_MP_TAC(SET_RULE
+   `!v. t SUBSET v /\ v SUBSET u ==> s INTER t SUBSET s INTER u`) THEN
+  EXISTS_TAC `ball(vec 0:real^N,D)` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(SET_RULE
+   `!f. (!x. h(f x) = x) /\ IMAGE f s SUBSET t ==> s SUBSET IMAGE h t`) THEN
+  EXISTS_TAC `f:real^N->real^N` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `ball(vec 0:real^N,D * C)` THEN
+  ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_BALL_0] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `C * norm(x:real^N)` THEN
+  ASM_REWRITE_TAC[] THEN GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[REAL_LT_LMUL_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some inductions by expressing mapping in terms of elementary matrices.    *)
+(* ------------------------------------------------------------------------- *)
+
+let INDUCT_MATRIX_ROW_OPERATIONS = prove
+ (`!P:real^N^N->bool.
+        (!A i. 1 <= i /\ i <= dimindex(:N) /\ row i A = vec 0 ==> P A) /\
+        (!A. (!i j. 1 <= i /\ i <= dimindex(:N) /\
+                    1 <= j /\ j <= dimindex(:N) /\ ~(i = j)
+                    ==> A$i$j = &0) ==> P A) /\
+        (!A m n. P A /\ 1 <= m /\ m <= dimindex(:N) /\
+                 1 <= n /\ n <= dimindex(:N) /\ ~(m = n)
+                 ==> P(lambda i j. A$i$(swap(m,n) j))) /\
+        (!A m n c. P A /\ 1 <= m /\ m <= dimindex(:N) /\
+                   1 <= n /\ n <= dimindex(:N) /\ ~(m = n)
+                   ==> P(lambda i. if i = m then row m A + c % row n A
+                                   else row i A))
+        ==> !A. P A`,
+  GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "zero_row") MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "diagonal") MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "swap_cols") (LABEL_TAC "row_op")) THEN
+  SUBGOAL_THEN
+   `!k A:real^N^N.
+        (!i j. 1 <= i /\ i <= dimindex(:N) /\
+               k <= j /\ j <= dimindex(:N) /\ ~(i = j)
+               ==> A$i$j = &0)
+        ==> P A`
+   (fun th -> GEN_TAC THEN MATCH_MP_TAC th THEN
+              EXISTS_TAC `dimindex(:N) + 1` THEN ARITH_TAC) THEN
+  MATCH_MP_TAC num_INDUCTION THEN CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN USE_THEN "diagonal" MATCH_MP_TAC THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[LE_0];
+    ALL_TAC] THEN
+  X_GEN_TAC `k:num` THEN DISCH_THEN(LABEL_TAC "ind_hyp") THEN
+  DISJ_CASES_THEN2 SUBST1_TAC ASSUME_TAC (ARITH_RULE `k = 0 \/ 1 <= k`) THEN
+  ASM_REWRITE_TAC[ARITH] THEN
+  ASM_CASES_TAC `k <= dimindex(:N)` THENL
+   [ALL_TAC;
+    REPEAT STRIP_TAC THEN REMOVE_THEN "ind_hyp" MATCH_MP_TAC THEN
+    ASM_ARITH_TAC] THEN
+  SUBGOAL_THEN
+   `!A:real^N^N.
+        ~(A$k$k = &0) /\
+        (!i j. 1 <= i /\ i <= dimindex (:N) /\
+               SUC k <= j /\ j <= dimindex (:N) /\ ~(i = j)
+               ==> A$i$j = &0)
+        ==> P A`
+  (LABEL_TAC "nonzero_hyp") THENL
+   [ALL_TAC;
+    X_GEN_TAC `A:real^N^N` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `row k (A:real^N^N) = vec 0` THENL
+     [REMOVE_THEN "zero_row" MATCH_MP_TAC THEN ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [CART_EQ]) THEN
+    SIMP_TAC[VEC_COMPONENT; row; LAMBDA_BETA] THEN
+    REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `l:num` THEN STRIP_TAC THEN
+    ASM_CASES_TAC `l:num = k` THENL
+     [REMOVE_THEN "nonzero_hyp" MATCH_MP_TAC THEN ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    REMOVE_THEN "swap_cols" (MP_TAC o SPECL
+     [`(lambda i j. (A:real^N^N)$i$swap(k,l) j):real^N^N`;
+      `k:num`; `l:num`]) THEN
+    ASM_SIMP_TAC[LAMBDA_BETA] THEN ANTS_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+      SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN
+      REPEAT STRIP_TAC THEN REWRITE_TAC[swap] THEN
+      REPEAT(COND_CASES_TAC THEN ASM_SIMP_TAC[LAMBDA_BETA])] THEN
+    REMOVE_THEN "nonzero_hyp" MATCH_MP_TAC THEN
+    ONCE_REWRITE_TAC[ARITH_RULE `SUC k <= i <=> 1 <= i /\ SUC k <= i`] THEN
+    ASM_SIMP_TAC[LAMBDA_BETA] THEN
+    ASM_REWRITE_TAC[swap] THEN MAP_EVERY X_GEN_TAC [`i:num`; `j:num`] THEN
+    STRIP_TAC THEN SUBGOAL_THEN `l:num <= k` ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPECL [`k:num`; `l:num`]) THEN
+      ASM_REWRITE_TAC[] THEN ARITH_TAC;
+      ALL_TAC] THEN
+    REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_ARITH_TAC] THEN
+   SUBGOAL_THEN
+   `!l A:real^N^N.
+        ~(A$k$k = &0) /\
+        (!i j. 1 <= i /\ i <= dimindex (:N) /\
+               SUC k <= j /\ j <= dimindex (:N) /\ ~(i = j)
+               ==> A$i$j = &0) /\
+        (!i. l <= i /\ i <= dimindex(:N) /\ ~(i = k) ==> A$i$k = &0)
+        ==> P A`
+   MP_TAC THENL
+    [ALL_TAC;
+     DISCH_THEN(MP_TAC o SPEC `dimindex(:N) + 1`) THEN
+     REWRITE_TAC[CONJ_ASSOC; ARITH_RULE `~(n + 1 <= i /\ i <= n)`]] THEN
+   MATCH_MP_TAC num_INDUCTION THEN CONJ_TAC THENL
+    [GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+     DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "main") (LABEL_TAC "aux")) THEN
+     USE_THEN "ind_hyp" MATCH_MP_TAC THEN
+     MAP_EVERY X_GEN_TAC [`i:num`; `j:num`] THEN STRIP_TAC THEN
+     ASM_CASES_TAC `j:num = k` THENL
+      [ASM_REWRITE_TAC[] THEN USE_THEN "aux" MATCH_MP_TAC THEN ASM_ARITH_TAC;
+       REMOVE_THEN "main" MATCH_MP_TAC THEN ASM_ARITH_TAC];
+    ALL_TAC] THEN
+  X_GEN_TAC `l:num` THEN DISCH_THEN(LABEL_TAC "inner_hyp") THEN
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "main") (LABEL_TAC "aux")) THEN
+  ASM_CASES_TAC `l:num = k` THENL
+   [REMOVE_THEN "inner_hyp" MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+    REPEAT STRIP_TAC THEN REMOVE_THEN "aux" MATCH_MP_TAC THEN ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  DISJ_CASES_TAC(ARITH_RULE `l = 0 \/ 1 <= l`) THENL
+   [REMOVE_THEN "ind_hyp" MATCH_MP_TAC THEN
+    MAP_EVERY X_GEN_TAC [`i:num`; `j:num`] THEN STRIP_TAC THEN
+    ASM_CASES_TAC `j:num = k` THENL
+     [ASM_REWRITE_TAC[] THEN REMOVE_THEN "aux" MATCH_MP_TAC THEN ASM_ARITH_TAC;
+      REMOVE_THEN "main" MATCH_MP_TAC THEN ASM_ARITH_TAC];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `l <= dimindex(:N)` THENL
+   [ALL_TAC;
+    REMOVE_THEN "inner_hyp" MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_ARITH_TAC] THEN
+  REMOVE_THEN "inner_hyp" (MP_TAC o SPECL
+   [`(lambda i. if i = l then row l (A:real^N^N) + --(A$l$k/A$k$k) % row k A
+                else row i A):real^N^N`]) THEN
+  ANTS_TAC THENL
+   [SUBGOAL_THEN `!i. l <= i ==> 1 <= i` ASSUME_TAC THENL
+     [ASM_ARITH_TAC; ALL_TAC] THEN
+    ONCE_REWRITE_TAC[ARITH_RULE `SUC k <= j <=> 1 <= j /\ SUC k <= j`] THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; row; COND_COMPONENT;
+                 VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+    ASM_SIMP_TAC[REAL_FIELD `~(y = &0) ==> x + --(x / y) * y = &0`] THEN
+    REWRITE_TAC[AND_FORALL_THM] THEN X_GEN_TAC `i:num` THEN
+    ASM_CASES_TAC `i:num = l` THEN ASM_REWRITE_TAC[] THENL
+     [REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC(REAL_RING `x = &0 /\ y = &0 ==> x + z * y = &0`) THEN
+      CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC;
+      REPEAT STRIP_TAC THEN REMOVE_THEN "aux" MATCH_MP_TAC THEN ASM_ARITH_TAC];
+    ALL_TAC] THEN
+  DISCH_TAC THEN REMOVE_THEN "row_op" (MP_TAC o SPECL
+   [`(lambda i. if i = l then row l A + --(A$l$k / A$k$k) % row k A
+                else row i (A:real^N^N)):real^N^N`;
+    `l:num`; `k:num`; `(A:real^N^N)$l$k / A$k$k`]) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT;
+               VECTOR_MUL_COMPONENT; row; COND_COMPONENT] THEN
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  REAL_ARITH_TAC);;
+
+let INDUCT_MATRIX_ELEMENTARY = prove
+ (`!P:real^N^N->bool.
+        (!A B. P A /\ P B ==> P(A ** B)) /\
+        (!A i. 1 <= i /\ i <= dimindex(:N) /\ row i A = vec 0 ==> P A) /\
+        (!A. (!i j. 1 <= i /\ i <= dimindex(:N) /\
+                    1 <= j /\ j <= dimindex(:N) /\ ~(i = j)
+                    ==> A$i$j = &0) ==> P A) /\
+        (!m n. 1 <= m /\ m <= dimindex(:N) /\
+               1 <= n /\ n <= dimindex(:N) /\ ~(m = n)
+               ==> P(lambda i j. (mat 1:real^N^N)$i$(swap(m,n) j))) /\
+        (!m n c. 1 <= m /\ m <= dimindex(:N) /\
+                 1 <= n /\ n <= dimindex(:N) /\ ~(m = n)
+                 ==> P(lambda i j. if i = m /\ j = n then c
+                                   else if i = j then &1 else &0))
+        ==> !A. P A`,
+  GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(fun th ->
+    MATCH_MP_TAC INDUCT_MATRIX_ROW_OPERATIONS THEN MP_TAC th) THEN
+  REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THEN REWRITE_TAC[] THEN
+  DISCH_THEN(fun th -> X_GEN_TAC `A:real^N^N` THEN MP_TAC th) THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+  UNDISCH_TAC `(P:real^N^N->bool) A` THENL
+   [REWRITE_TAC[GSYM IMP_CONJ]; REWRITE_TAC[GSYM IMP_CONJ_ALT]] THEN
+  DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN MATCH_MP_TAC EQ_IMP THEN
+  AP_TERM_TAC THEN REWRITE_TAC[CART_EQ] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA; matrix_mul; row] THENL
+   [ASM_SIMP_TAC[mat; IN_DIMINDEX_SWAP; LAMBDA_BETA] THEN
+    ONCE_REWRITE_TAC[COND_RAND] THEN
+    SIMP_TAC[SUM_DELTA; REAL_MUL_RZERO; REAL_MUL_RID] THEN
+    COND_CASES_TAC THEN REWRITE_TAC[] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[swap; IN_NUMSEG]) THEN ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_CASES_TAC `i:num = m` THEN ASM_REWRITE_TAC[] THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+    REWRITE_TAC[REAL_MUL_LZERO] THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
+    ASM_SIMP_TAC[SUM_DELTA; LAMBDA_BETA; IN_NUMSEG; REAL_MUL_LID]] THEN
+  ASM_SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; LAMBDA_BETA] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC
+    `sum {m,n} (\k. (if k = n then c else if m = k then &1 else &0) *
+                    (A:real^N^N)$k$j)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_SUPERSET THEN
+    ASM_SIMP_TAC[SUBSET; IN_INSERT; NOT_IN_EMPTY; DE_MORGAN_THM;
+                 IN_NUMSEG; REAL_MUL_LZERO] THEN
+    ASM_ARITH_TAC;
+    ASM_SIMP_TAC[SUM_CLAUSES; FINITE_RULES; IN_INSERT; NOT_IN_EMPTY] THEN
+    REAL_ARITH_TAC]);;
+
+let INDUCT_MATRIX_ELEMENTARY_ALT = prove
+ (`!P:real^N^N->bool.
+        (!A B. P A /\ P B ==> P(A ** B)) /\
+        (!A i. 1 <= i /\ i <= dimindex(:N) /\ row i A = vec 0 ==> P A) /\
+        (!A. (!i j. 1 <= i /\ i <= dimindex(:N) /\
+                    1 <= j /\ j <= dimindex(:N) /\ ~(i = j)
+                    ==> A$i$j = &0) ==> P A) /\
+        (!m n. 1 <= m /\ m <= dimindex(:N) /\
+               1 <= n /\ n <= dimindex(:N) /\ ~(m = n)
+               ==> P(lambda i j. (mat 1:real^N^N)$i$(swap(m,n) j))) /\
+        (!m n. 1 <= m /\ m <= dimindex(:N) /\
+               1 <= n /\ n <= dimindex(:N) /\ ~(m = n)
+               ==> P(lambda i j. if i = m /\ j = n \/ i = j then &1 else &0))
+        ==> !A. P A`,
+  GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC INDUCT_MATRIX_ELEMENTARY THEN
+  ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `c = &0` THENL
+   [FIRST_X_ASSUM(fun th -> MATCH_MP_TAC th THEN
+        MAP_EVERY X_GEN_TAC [`i:num`; `j:num`]) THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; COND_ID];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(lambda i j. if i = m /\ j = n then c else if i = j then &1 else &0) =
+  ((lambda i j. if i = j then if j = n then inv c else &1 else &0):real^N^N) **
+    ((lambda i j. if i = m /\ j = n \/ i = j then &1 else &0):real^N^N) **
+    ((lambda i j. if i = j then if j = n then c else &1 else &0):real^N^N)`
+  SUBST1_TAC THENL
+   [ALL_TAC;
+    REPEAT(MATCH_MP_TAC(ASSUME `!A B:real^N^N. P A /\ P B ==> P(A ** B)`) THEN
+           CONJ_TAC) THEN
+    ASM_SIMP_TAC[] THEN FIRST_X_ASSUM(fun th -> MATCH_MP_TAC th THEN
+        MAP_EVERY X_GEN_TAC [`i:num`; `j:num`]) THEN
+    ASM_SIMP_TAC[LAMBDA_BETA]] THEN
+  SIMP_TAC[CART_EQ; matrix_mul; LAMBDA_BETA] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[SUM_DELTA; IN_NUMSEG; REAL_ARITH
+       `(if p then &1 else &0) * (if q then c else &0) =
+        if q then if p then c else &0 else &0`] THEN
+  REWRITE_TAC[REAL_ARITH
+   `(if p then x else &0) * y = (if p then x * y else &0)`] THEN
+  GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
+  ASM_SIMP_TAC[SUM_DELTA; IN_NUMSEG] THEN
+  ASM_CASES_TAC `i:num = m` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `j:num = n` THEN ASM_REWRITE_TAC[REAL_MUL_LID; EQ_SYM_EQ] THEN
+  ASM_CASES_TAC `i:num = n` THEN
+  ASM_SIMP_TAC[REAL_MUL_LINV; REAL_MUL_LID; REAL_MUL_RZERO]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The same thing in mapping form (might have been easier all along).        *)
+(* ------------------------------------------------------------------------- *)
+
+let INDUCT_LINEAR_ELEMENTARY = prove
+ (`!P. (!f g. linear f /\ linear g /\ P f /\ P g ==> P(f o g)) /\
+       (!f i. linear f /\ 1 <= i /\ i <= dimindex(:N) /\ (!x. (f x)$i = &0)
+              ==> P f) /\
+       (!c. P(\x. lambda i. c i * x$i)) /\
+       (!m n. 1 <= m /\ m <= dimindex(:N) /\
+              1 <= n /\ n <= dimindex(:N) /\ ~(m = n)
+              ==> P(\x. lambda i. x$swap(m,n) i)) /\
+       (!m n. 1 <= m /\ m <= dimindex(:N) /\
+              1 <= n /\ n <= dimindex(:N) /\ ~(m = n)
+              ==> P(\x. lambda i. if i = m then x$m + x$n else x$i))
+       ==> !f:real^N->real^N. linear f ==> P f`,
+  GEN_TAC THEN
+  MP_TAC(ISPEC `\A:real^N^N. P(\x:real^N. A ** x):bool`
+    INDUCT_MATRIX_ELEMENTARY_ALT) THEN
+  REWRITE_TAC[] THEN MATCH_MP_TAC MONO_IMP THEN CONJ_TAC THENL
+   [ALL_TAC;
+    DISCH_TAC THEN X_GEN_TAC `f:real^N->real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `matrix(f:real^N->real^N)`) THEN
+    ASM_SIMP_TAC[MATRIX_WORKS] THEN REWRITE_TAC[ETA_AX]] THEN
+  MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+   [DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`A:real^N^N`; `B:real^N^N`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+     [`\x:real^N. (A:real^N^N) ** x`; `\x:real^N. (B:real^N^N) ** x`]) THEN
+    ASM_REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR; o_DEF] THEN
+    REWRITE_TAC[MATRIX_VECTOR_MUL_ASSOC];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+   [DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`A:real^N^N`; `m:num`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+     [`\x:real^N. (A:real^N^N) ** x`; `m:num`]) THEN
+    ASM_REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    UNDISCH_TAC `row m (A:real^N^N) = vec 0` THEN
+    ASM_SIMP_TAC[CART_EQ; row; LAMBDA_BETA; VEC_COMPONENT; matrix_vector_mul;
+                 REAL_MUL_LZERO; SUM_0];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+   [DISCH_TAC THEN X_GEN_TAC `A:real^N^N` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `\i. (A:real^N^N)$i$i`) THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+    ASM_SIMP_TAC[CART_EQ; matrix_vector_mul; FUN_EQ_THM; LAMBDA_BETA] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `i:num`] THEN STRIP_TAC THEN
+    MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+     `sum(1..dimindex(:N)) (\j. if j = i then (A:real^N^N)$i$j * (x:real^N)$j
+                                else &0)` THEN
+    CONJ_TAC THENL [ASM_SIMP_TAC[SUM_DELTA; IN_NUMSEG]; ALL_TAC] THEN
+    MATCH_MP_TAC SUM_EQ_NUMSEG THEN X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[] THEN COND_CASES_TAC THEN ASM_SIMP_TAC[REAL_MUL_LZERO];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_AND THEN CONJ_TAC THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `m:num` THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `n:num` THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  ASM_SIMP_TAC[CART_EQ; matrix_vector_mul; FUN_EQ_THM; LAMBDA_BETA;
+               mat; IN_DIMINDEX_SWAP]
+  THENL
+   [ONCE_REWRITE_TAC[SWAP_GALOIS] THEN ONCE_REWRITE_TAC[COND_RAND] THEN
+    ONCE_REWRITE_TAC[COND_RATOR] THEN
+    SIMP_TAC[SUM_DELTA; REAL_MUL_LID; REAL_MUL_LZERO; IN_NUMSEG] THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[swap] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC;
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `i:num`] THEN STRIP_TAC THEN
+    ASM_CASES_TAC `i:num = m` THEN ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+    GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
+    ASM_SIMP_TAC[SUM_DELTA; REAL_MUL_LZERO; REAL_MUL_LID; IN_NUMSEG] THEN
+    MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+     `sum {m,n} (\j. if n = j \/ j = m then (x:real^N)$j else &0)` THEN
+    CONJ_TAC THENL
+     [SIMP_TAC[SUM_CLAUSES; FINITE_RULES; IN_INSERT; NOT_IN_EMPTY] THEN
+      ASM_REWRITE_TAC[REAL_ADD_RID];
+      CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_SUPERSET THEN
+      ASM_SIMP_TAC[SUBSET; IN_INSERT; NOT_IN_EMPTY; DE_MORGAN_THM;
+                   IN_NUMSEG; REAL_MUL_LZERO] THEN
+      ASM_ARITH_TAC]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence the effect of an arbitrary linear map on a measurable set.          *)
+(* ------------------------------------------------------------------------- *)
+
+let LAMBDA_SWAP_GALOIS = prove
+ (`!x:real^N y:real^N.
+        1 <= m /\ m <= dimindex(:N) /\ 1 <= n /\ n <= dimindex(:N)
+        ==> (x = (lambda i. y$swap(m,n) i) <=>
+             (lambda i. x$swap(m,n) i) = y)`,
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; IN_DIMINDEX_SWAP] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN EQ_TAC THEN
+  DISCH_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `swap(m,n) (i:num)`) THEN
+  ASM_SIMP_TAC[IN_DIMINDEX_SWAP] THEN
+  ASM_MESON_TAC[REWRITE_RULE[FUN_EQ_THM; o_THM; I_THM] SWAP_IDEMPOTENT]);;
+
+let LAMBDA_ADD_GALOIS = prove
+ (`!x:real^N y:real^N.
+        1 <= m /\ m <= dimindex(:N) /\ 1 <= n /\ n <= dimindex(:N) /\
+        ~(m = n)
+        ==> (x = (lambda i. if i = m then y$m + y$n else y$i) <=>
+             (lambda i. if i = m then x$m - x$n else x$i) = y)`,
+  SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN EQ_TAC THEN
+  DISCH_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `n:num`) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
+  ASM_REWRITE_TAC[] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  REAL_ARITH_TAC);;
+
+let HAS_MEASURE_SHEAR_INTERVAL = prove
+ (`!a b:real^N m n.
+        1 <= m /\ m <= dimindex(:N) /\
+        1 <= n /\ n <= dimindex(:N) /\
+        ~(m = n) /\ ~(interval[a,b] = {}) /\
+        &0 <= a$n
+        ==> (IMAGE (\x. (lambda i. if i = m then x$m + x$n else x$i))
+                   (interval[a,b]):real^N->bool)
+            has_measure measure (interval [a,b])`,
+  let lemma = prove
+   (`!s t u v:real^N->bool.
+          measurable s /\ measurable t /\ measurable u /\
+          negligible(s INTER t) /\ negligible(s INTER u) /\
+          negligible(t INTER u) /\
+          s UNION t UNION u = v
+          ==> v has_measure (measure s) + (measure t) + (measure u)`,
+    REPEAT STRIP_TAC THEN
+    ASM_SIMP_TAC[HAS_MEASURE_MEASURABLE_MEASURE; MEASURABLE_UNION] THEN
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    ASM_SIMP_TAC[MEASURE_UNION; MEASURABLE_UNION] THEN
+    ASM_SIMP_TAC[MEASURE_EQ_0; UNION_OVER_INTER; MEASURE_UNION;
+                 MEASURABLE_UNION; NEGLIGIBLE_INTER; MEASURABLE_INTER] THEN
+    REAL_ARITH_TAC)
+  and lemma' = prove
+   (`!s t u a:real^N.
+          measurable s /\ measurable t /\
+          s UNION (IMAGE (\x. a + x) t) = u /\
+          negligible(s INTER (IMAGE (\x. a + x) t))
+          ==> measure s + measure t = measure u`,
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+    ASM_SIMP_TAC[MEASURE_NEGLIGIBLE_UNION; MEASURABLE_TRANSLATION_EQ;
+                 MEASURE_TRANSLATION]) in
+  REWRITE_TAC[INTERVAL_NE_EMPTY] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `linear((\x. lambda i. if i = m then x$m + x$n else x$i):real^N->real^N)`
+  ASSUME_TAC THENL
+   [ASM_SIMP_TAC[linear; LAMBDA_BETA; VECTOR_ADD_COMPONENT;
+                 VECTOR_MUL_COMPONENT; CART_EQ] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`IMAGE (\x. lambda i. if i = m then x$m + x$n else x$i)
+            (interval[a:real^N,b]):real^N->bool`;
+    `interval[a,(lambda i. if i = m then (b:real^N)$m + b$n else b$i)] INTER
+       {x:real^N | (basis m - basis n) dot x <= a$m}`;
+    `interval[a,(lambda i. if i = m then b$m + b$n else b$i)] INTER
+       {x:real^N | (basis m - basis n) dot x >= (b:real^N)$m}`;
+    `interval[a:real^N,
+              (lambda i. if i = m then (b:real^N)$m + b$n else b$i)]`]
+     lemma) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[CONVEX_LINEAR_IMAGE; CONVEX_INTERVAL;
+                 CONVEX_HALFSPACE_LE; CONVEX_HALFSPACE_GE;
+                 CONVEX_INTER; MEASURABLE_CONVEX; BOUNDED_INTER;
+                 BOUNDED_LINEAR_IMAGE; BOUNDED_INTERVAL] THEN
+    REWRITE_TAC[INTER] THEN
+    REWRITE_TAC[EXTENSION; IN_UNION; IN_INTER; IN_IMAGE] THEN
+    ASM_SIMP_TAC[LAMBDA_ADD_GALOIS; UNWIND_THM1] THEN
+    ASM_SIMP_TAC[IN_INTERVAL; IN_ELIM_THM; LAMBDA_BETA;
+                 DOT_BASIS; DOT_LSUB] THEN
+    ONCE_REWRITE_TAC[MESON[]
+       `(!i:num. P i) <=> P m /\ (!i. ~(i = m) ==> P i)`] THEN
+    ASM_SIMP_TAC[] THEN
+    REWRITE_TAC[TAUT `(p /\ x) /\ (q /\ x) /\ r <=> x /\ p /\ q /\ r`;
+                TAUT `(p /\ x) /\ q /\ (r /\ x) <=> x /\ p /\ q /\ r`;
+                TAUT `((p /\ x) /\ q) /\ (r /\ x) /\ s <=>
+                            x /\ p /\ q /\ r /\ s`;
+            TAUT `(a /\ x \/ (b /\ x) /\ c \/ (d /\ x) /\ e <=> f /\ x) <=>
+                  x ==> (a \/ b /\ c \/ d /\ e <=> f)`] THEN
+    ONCE_REWRITE_TAC[SET_RULE
+     `{x | P x /\ Q x} = {x | P x} INTER {x | Q x}`] THEN
+    REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+     [ALL_TAC;
+      GEN_TAC THEN DISCH_THEN(MP_TAC o SPEC `n:num`) THEN
+      ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC] THEN REPEAT CONJ_TAC THEN
+    MATCH_MP_TAC NEGLIGIBLE_INTER THEN DISJ2_TAC THEN
+    MATCH_MP_TAC NEGLIGIBLE_SUBSET THENL
+     [EXISTS_TAC `{x:real^N | (basis m - basis n) dot x = (a:real^N)$m}`;
+      EXISTS_TAC `{x:real^N | (basis m - basis n) dot x = (b:real^N)$m}`;
+      EXISTS_TAC `{x:real^N | (basis m - basis n) dot x = (b:real^N)$m}`]
+    THEN (CONJ_TAC THENL
+      [MATCH_MP_TAC NEGLIGIBLE_HYPERPLANE THEN
+       REWRITE_TAC[VECTOR_SUB_EQ] THEN
+       ASM_MESON_TAC[BASIS_INJ];
+       ASM_SIMP_TAC[DOT_LSUB; DOT_BASIS; SUBSET; IN_ELIM_THM;
+                    NOT_IN_EMPTY] THEN
+       FIRST_X_ASSUM(MP_TAC o SPEC `m:num`) THEN ASM_REWRITE_TAC[] THEN
+       ASM_REAL_ARITH_TAC]);
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[HAS_MEASURE_MEASURABLE_MEASURE;
+               MEASURABLE_LINEAR_IMAGE_INTERVAL;
+               MEASURABLE_INTERVAL] THEN
+  MP_TAC(ISPECL
+   [`interval[a,(lambda i. if i = m then (b:real^N)$m + b$n else b$i)] INTER
+       {x:real^N | (basis m - basis n) dot x <= a$m}`;
+    `interval[a,(lambda i. if i = m then b$m + b$n else b$i)] INTER
+       {x:real^N | (basis m - basis n) dot x >= (b:real^N)$m}`;
+    `interval[a:real^N,
+              (lambda i. if i = m then (a:real^N)$m + b$n
+                         else (b:real^N)$i)]`;
+    `(lambda i. if i = m then (a:real^N)$m - (b:real^N)$m
+                else &0):real^N`]
+     lemma') THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[CONVEX_LINEAR_IMAGE; CONVEX_INTERVAL;
+                 CONVEX_HALFSPACE_LE; CONVEX_HALFSPACE_GE;
+                 CONVEX_INTER; MEASURABLE_CONVEX; BOUNDED_INTER;
+                 BOUNDED_LINEAR_IMAGE; BOUNDED_INTERVAL] THEN
+    REWRITE_TAC[INTER] THEN
+    REWRITE_TAC[EXTENSION; IN_UNION; IN_INTER; IN_IMAGE] THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH `x:real^N = (lambda i. p i) + y <=>
+                                   x - (lambda i. p i) = y`] THEN
+    ASM_SIMP_TAC[IN_INTERVAL; IN_ELIM_THM; LAMBDA_BETA;
+                 DOT_BASIS; DOT_LSUB; UNWIND_THM1;
+                 VECTOR_SUB_COMPONENT] THEN
+    ONCE_REWRITE_TAC[MESON[]
+       `(!i:num. P i) <=> P m /\ (!i. ~(i = m) ==> P i)`] THEN
+    ASM_SIMP_TAC[REAL_SUB_RZERO] THEN CONJ_TAC THENL
+     [X_GEN_TAC `x:real^N` THEN
+      FIRST_ASSUM(MP_TAC o SPEC `n:num`) THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `m:num`) THEN
+      ASM_REWRITE_TAC[] THEN
+      ASM_CASES_TAC
+       `!i. ~(i = m)
+            ==> 1 <= i /\ i <= dimindex (:N)
+                ==> (a:real^N)$i <= (x:real^N)$i /\
+                    x$i <= (b:real^N)$i` THEN
+      ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `n:num`) THEN
+      ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+      ONCE_REWRITE_TAC[TAUT `((a /\ b) /\ c) /\ (d /\ e) /\ f <=>
+                             (b /\ e) /\ a /\ c /\ d /\ f`] THEN
+      ONCE_REWRITE_TAC[SET_RULE
+       `{x | P x /\ Q x} = {x | P x} INTER {x | Q x}`] THEN
+      MATCH_MP_TAC NEGLIGIBLE_INTER THEN DISJ2_TAC THEN
+      MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+      EXISTS_TAC `{x:real^N | (basis m - basis n) dot x = (a:real^N)$m}`
+      THEN CONJ_TAC THENL
+       [MATCH_MP_TAC NEGLIGIBLE_HYPERPLANE THEN
+        REWRITE_TAC[VECTOR_SUB_EQ] THEN
+        ASM_MESON_TAC[BASIS_INJ];
+        ASM_SIMP_TAC[DOT_LSUB; DOT_BASIS; SUBSET; IN_ELIM_THM;
+                     NOT_IN_EMPTY] THEN
+        FIRST_ASSUM(MP_TAC o SPEC `n:num`) THEN
+        FIRST_X_ASSUM(MP_TAC o SPEC `m:num`) THEN
+        ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC]];
+    ALL_TAC] THEN
+  DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC(REAL_ARITH
+   `a:real = b + c ==> a = x + b ==> x = c`) THEN
+  ASM_SIMP_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES;
+               LAMBDA_BETA] THEN
+  REPEAT(COND_CASES_TAC THENL
+   [ALL_TAC;
+    FIRST_X_ASSUM(MP_TAC o check (is_neg o concl)) THEN
+    MATCH_MP_TAC(TAUT `p ==> ~p ==> q`) THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    COND_CASES_TAC THEN ASM_SIMP_TAC[] THEN
+    FIRST_ASSUM(MP_TAC o SPEC `n:num`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `m:num`) THEN
+    ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC]) THEN
+  SUBGOAL_THEN `1..dimindex(:N) = m INSERT ((1..dimindex(:N)) DELETE m)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_INSERT; IN_DELETE; IN_NUMSEG] THEN
+    ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  SIMP_TAC[PRODUCT_CLAUSES; FINITE_DELETE; FINITE_NUMSEG] THEN
+  ASM_SIMP_TAC[IN_DELETE] THEN
+  MATCH_MP_TAC(REAL_RING
+   `s1:real = s3 /\ s2 = s3
+    ==> ((bm + bn) - am) * s1 =
+        ((am + bn) - am) * s2 + (bm - am) * s3`) THEN
+  CONJ_TAC THEN MATCH_MP_TAC PRODUCT_EQ THEN
+  SIMP_TAC[IN_DELETE] THEN REAL_ARITH_TAC);;
+
+let HAS_MEASURE_LINEAR_IMAGE = prove
+ (`!f:real^N->real^N s.
+        linear f /\ measurable s
+        ==> (IMAGE f s) has_measure (abs(det(matrix f)) * measure s)`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC INDUCT_LINEAR_ELEMENTARY THEN REPEAT CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`f:real^N->real^N`; `g:real^N->real^N`] THEN
+    REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(fun th -> REPEAT STRIP_TAC THEN MP_TAC th) THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (MP_TAC o SPEC `IMAGE (g:real^N->real^N) s`)
+     (MP_TAC o SPEC `s:real^N->bool`)) THEN
+    ASM_REWRITE_TAC[] THEN
+    GEN_REWRITE_TAC LAND_CONV [HAS_MEASURE_MEASURABLE_MEASURE] THEN
+    STRIP_TAC THEN ASM_SIMP_TAC[MATRIX_COMPOSE; DET_MUL; REAL_ABS_MUL] THEN
+    REWRITE_TAC[IMAGE_o; GSYM REAL_MUL_ASSOC];
+
+    MAP_EVERY X_GEN_TAC [`f:real^N->real^N`; `m:num`] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `~(!x y. (f:real^N->real^N) x = f y ==> x = y)`
+    ASSUME_TAC THENL
+     [ASM_SIMP_TAC[LINEAR_SINGULAR_INTO_HYPERPLANE] THEN
+      EXISTS_TAC `basis m:real^N` THEN
+      ASM_SIMP_TAC[BASIS_NONZERO; DOT_BASIS];
+      ALL_TAC] THEN
+    MP_TAC(ISPEC `matrix f:real^N^N` INVERTIBLE_DET_NZ) THEN
+    ASM_SIMP_TAC[INVERTIBLE_LEFT_INVERSE; MATRIX_LEFT_INVERTIBLE_INJECTIVE;
+                 MATRIX_WORKS; REAL_ABS_NUM; REAL_MUL_LZERO] THEN
+    DISCH_THEN(K ALL_TAC) THEN REWRITE_TAC[HAS_MEASURE_0] THEN
+    ASM_SIMP_TAC[NEGLIGIBLE_LINEAR_SINGULAR_IMAGE];
+
+    MAP_EVERY X_GEN_TAC [`c:num->real`; `s:real^N->bool`] THEN
+    DISCH_TAC THEN
+    FIRST_ASSUM(ASSUME_TAC o REWRITE_RULE[HAS_MEASURE_MEASURE]) THEN
+    FIRST_ASSUM(MP_TAC o SPEC `c:num->real` o
+     MATCH_MP HAS_MEASURE_STRETCH) THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    SIMP_TAC[matrix; LAMBDA_BETA] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) DET_DIAGONAL o rand o snd) THEN
+    SIMP_TAC[LAMBDA_BETA; BASIS_COMPONENT; REAL_MUL_RZERO] THEN
+    DISCH_THEN(K ALL_TAC) THEN MATCH_MP_TAC PRODUCT_EQ_NUMSEG THEN
+    REWRITE_TAC[REAL_MUL_RID];
+
+    MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN STRIP_TAC THEN
+    MATCH_MP_TAC HAS_MEASURE_LINEAR_SUFFICIENT THEN
+    ASM_SIMP_TAC[linear; LAMBDA_BETA; IN_DIMINDEX_SWAP; VECTOR_ADD_COMPONENT;
+                 VECTOR_MUL_COMPONENT; CART_EQ] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+    SUBGOAL_THEN `matrix (\x:real^N. lambda i. x$swap (m,n) i):real^N^N =
+                  transp(lambda i j. (mat 1:real^N^N)$i$swap (m,n) j)`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[MATRIX_EQ; LAMBDA_BETA; IN_DIMINDEX_SWAP;
+                    matrix_vector_mul; CART_EQ; matrix; mat; basis;
+                    COND_COMPONENT; transp] THEN
+      REWRITE_TAC[EQ_SYM_EQ];
+      ALL_TAC] THEN
+    REWRITE_TAC[DET_TRANSP] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) DET_PERMUTE_COLUMNS o
+        rand o lhand o rand o snd) THEN
+    ASM_SIMP_TAC[PERMUTES_SWAP; IN_NUMSEG; ETA_AX] THEN
+    DISCH_THEN(K ALL_TAC) THEN
+    REWRITE_TAC[DET_I; REAL_ABS_SIGN; REAL_MUL_RID; REAL_MUL_LID] THEN
+    ASM_CASES_TAC `interval[a:real^N,b] = {}` THENL
+     [ASM_SIMP_TAC[IMAGE_CLAUSES; HAS_MEASURE_EMPTY; MEASURE_EMPTY];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `~(IMAGE (\x:real^N. lambda i. x$swap (m,n) i)
+              (interval[a,b]):real^N->bool = {})`
+    MP_TAC THENL [ASM_REWRITE_TAC[IMAGE_EQ_EMPTY]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `IMAGE (\x:real^N. lambda i. x$swap (m,n) i)
+              (interval[a,b]):real^N->bool =
+      interval[(lambda i. a$swap (m,n) i),
+               (lambda i. b$swap (m,n) i)]`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[EXTENSION; IN_INTERVAL; IN_IMAGE] THEN
+      ASM_SIMP_TAC[LAMBDA_SWAP_GALOIS; UNWIND_THM1] THEN
+      SIMP_TAC[LAMBDA_BETA] THEN GEN_TAC THEN EQ_TAC THEN
+      DISCH_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `swap(m,n) (i:num)`) THEN
+      ASM_SIMP_TAC[IN_DIMINDEX_SWAP] THEN
+      ASM_MESON_TAC[REWRITE_RULE[FUN_EQ_THM; o_THM; I_THM] SWAP_IDEMPOTENT];
+      ALL_TAC] THEN
+    REWRITE_TAC[HAS_MEASURE_MEASURABLE_MEASURE; MEASURABLE_INTERVAL] THEN
+    REWRITE_TAC[MEASURE_INTERVAL] THEN
+    ASM_SIMP_TAC[CONTENT_CLOSED_INTERVAL; GSYM INTERVAL_NE_EMPTY] THEN
+    DISCH_THEN(K ALL_TAC) THEN SIMP_TAC[LAMBDA_BETA] THEN
+    ASM_SIMP_TAC[GSYM VECTOR_SUB_COMPONENT; IN_DIMINDEX_SWAP] THEN
+    MP_TAC(ISPECL [`\i. (b - a:real^N)$i`; `swap(m:num,n)`; `1..dimindex(:N)`]
+                (GSYM PRODUCT_PERMUTE)) THEN
+    REWRITE_TAC[o_DEF] THEN DISCH_THEN MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[PERMUTES_SWAP; IN_NUMSEG];
+
+    MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN STRIP_TAC THEN
+    MATCH_MP_TAC HAS_MEASURE_LINEAR_SUFFICIENT THEN
+    MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+     [ASM_SIMP_TAC[linear; LAMBDA_BETA; VECTOR_ADD_COMPONENT;
+                   VECTOR_MUL_COMPONENT; CART_EQ] THEN REAL_ARITH_TAC;
+      DISCH_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+    SUBGOAL_THEN
+      `det(matrix(\x. lambda i. if i = m then (x:real^N)$m + x$n
+                                else x$i):real^N^N) = &1`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[matrix; basis; COND_COMPONENT; LAMBDA_BETA] THEN
+      FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (ARITH_RULE
+       `~(m:num = n) ==> m < n \/ n < m`))
+      THENL
+       [W(MP_TAC o PART_MATCH (lhs o rand) DET_UPPERTRIANGULAR o lhs o snd);
+        W(MP_TAC o PART_MATCH (lhs o rand) DET_LOWERTRIANGULAR o lhs o snd)]
+      THEN ASM_SIMP_TAC[LAMBDA_BETA; BASIS_COMPONENT; COND_COMPONENT;
+                        matrix; REAL_ADD_RID; COND_ID;
+                        PRODUCT_CONST_NUMSEG; REAL_POW_ONE] THEN
+      DISCH_THEN MATCH_MP_TAC THEN
+      REPEAT GEN_TAC THEN REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+      ASM_ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[REAL_ABS_NUM; REAL_MUL_LID] THEN
+    ASM_CASES_TAC `interval[a:real^N,b] = {}` THENL
+     [ASM_SIMP_TAC[IMAGE_CLAUSES; HAS_MEASURE_EMPTY; MEASURE_EMPTY];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `IMAGE (\x. lambda i. if i = m then x$m + x$n else x$i) (interval [a,b]) =
+      IMAGE (\x:real^N. (lambda i. if i = m \/ i = n then a$n else &0) +
+                        x)
+            (IMAGE (\x:real^N. lambda i. if i = m then x$m + x$n else x$i)
+                   (IMAGE (\x. (lambda i. if i = n then --(a$n) else &0) + x)
+                          (interval[a,b])))`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[GSYM IMAGE_o] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+      ASM_SIMP_TAC[FUN_EQ_THM; o_THM; VECTOR_ADD_COMPONENT; LAMBDA_BETA;
+                   CART_EQ] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^N`; `i:num`] THEN
+      STRIP_TAC THEN ASM_CASES_TAC `i:num = m` THEN ASM_REWRITE_TAC[] THEN
+      ASM_CASES_TAC `i:num = n` THEN ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC HAS_MEASURE_TRANSLATION THEN
+    SUBGOAL_THEN
+     `measure(interval[a,b]) =
+      measure(IMAGE (\x:real^N. (lambda i. if i = n then --(a$n) else &0) + x)
+                    (interval[a,b]):real^N->bool)`
+    SUBST1_TAC THENL [REWRITE_TAC[MEASURE_TRANSLATION]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `~(IMAGE (\x:real^N. (lambda i. if i = n then --(a$n) else &0) + x)
+                    (interval[a,b]):real^N->bool = {})`
+    MP_TAC THENL [ASM_SIMP_TAC[IMAGE_EQ_EMPTY]; ALL_TAC] THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH `c + x:real^N = &1 % x + c`] THEN
+    ASM_REWRITE_TAC[IMAGE_AFFINITY_INTERVAL; REAL_POS] THEN
+    DISCH_TAC THEN MATCH_MP_TAC HAS_MEASURE_SHEAR_INTERVAL THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+    REAL_ARITH_TAC]);;
+
+let MEASURABLE_LINEAR_IMAGE = prove
+ (`!f:real^N->real^N s.
+        linear f /\ measurable s ==> measurable(IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_MEASURE_LINEAR_IMAGE) THEN
+  SIMP_TAC[HAS_MEASURE_MEASURABLE_MEASURE]);;
+
+let MEASURE_LINEAR_IMAGE = prove
+ (`!f:real^N->real^N s.
+        linear f /\ measurable s
+        ==> measure(IMAGE f s) = abs(det(matrix f)) * measure s`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_MEASURE_LINEAR_IMAGE) THEN
+  SIMP_TAC[HAS_MEASURE_MEASURABLE_MEASURE]);;
+
+let HAS_MEASURE_LINEAR_IMAGE_ALT = prove
+ (`!f:real^N->real^N s m.
+        linear f /\ s has_measure m
+        ==> (IMAGE f s) has_measure (abs(det(matrix f)) * m)`,
+  MESON_TAC[MEASURE_UNIQUE; measurable; HAS_MEASURE_LINEAR_IMAGE]);;
+
+let HAS_MEASURE_LINEAR_IMAGE_SAME = prove
+ (`!f s. linear f /\ measurable s /\ abs(det(matrix f)) = &1
+         ==> (IMAGE f s) has_measure (measure s)`,
+  MESON_TAC[HAS_MEASURE_LINEAR_IMAGE; REAL_MUL_LID]);;
+
+let MEASURE_LINEAR_IMAGE_SAME = prove
+ (`!f:real^N->real^N s.
+        linear f /\ measurable s /\ abs(det(matrix f)) = &1
+        ==> measure(IMAGE f s) = measure s`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_MEASURE_LINEAR_IMAGE_SAME) THEN
+  SIMP_TAC[HAS_MEASURE_MEASURABLE_MEASURE]);;
+
+let MEASURABLE_LINEAR_IMAGE_EQ = prove
+ (`!f:real^N->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (measurable (IMAGE f s) <=> measurable s)`,
+  MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE MEASURABLE_LINEAR_IMAGE));;
+
+add_linear_invariants [MEASURABLE_LINEAR_IMAGE_EQ];;
+
+let NEGLIGIBLE_LINEAR_IMAGE = prove
+ (`!f:real^N->real^N s. linear f /\ negligible s ==> negligible(IMAGE f s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM HAS_MEASURE_0] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HAS_MEASURE_LINEAR_IMAGE_ALT) THEN
+  REWRITE_TAC[REAL_MUL_RZERO]);;
+
+let NEGLIGIBLE_LINEAR_IMAGE_EQ = prove
+ (`!f:real^N->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (negligible (IMAGE f s) <=> negligible s)`,
+  MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE NEGLIGIBLE_LINEAR_IMAGE));;
+
+add_linear_invariants [NEGLIGIBLE_LINEAR_IMAGE_EQ];;
+
+let HAS_MEASURE_ORTHOGONAL_IMAGE = prove
+ (`!f:real^N->real^N s m.
+        orthogonal_transformation f /\ s has_measure m
+        ==> (IMAGE f s) has_measure m`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ORTHOGONAL_TRANSFORMATION_LINEAR) THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_MEASURE_LINEAR_IMAGE_ALT) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC(REAL_RING `x = &1 ==> x * m = m`) THEN
+  REWRITE_TAC[REAL_ARITH `abs x = &1 <=> x = &1 \/ x = -- &1`] THEN
+  MATCH_MP_TAC DET_ORTHOGONAL_MATRIX THEN
+  ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_MATRIX]);;
+
+let HAS_MEASURE_ORTHOGONAL_IMAGE_EQ = prove
+ (`!f:real^N->real^N s m.
+        orthogonal_transformation f
+        ==> ((IMAGE f s) has_measure m <=> s has_measure m)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  ASM_SIMP_TAC[HAS_MEASURE_ORTHOGONAL_IMAGE] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ORTHOGONAL_TRANSFORMATION_INVERSE_o) THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^N` MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+   REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_MEASURE_ORTHOGONAL_IMAGE) THEN
+  ASM_SIMP_TAC[GSYM IMAGE_o; IMAGE_I]);;
+
+add_linear_invariants
+ [REWRITE_RULE[ORTHOGONAL_TRANSFORMATION] HAS_MEASURE_ORTHOGONAL_IMAGE_EQ];;
+
+let MEASURE_ORTHOGONAL_IMAGE_EQ = prove
+ (`!f:real^N->real^N s.
+        orthogonal_transformation f
+        ==> measure(IMAGE f s) = measure s`,
+  SIMP_TAC[measure; HAS_MEASURE_ORTHOGONAL_IMAGE_EQ]);;
+
+add_linear_invariants
+ [REWRITE_RULE[ORTHOGONAL_TRANSFORMATION] MEASURE_ORTHOGONAL_IMAGE_EQ];;
+
+(* ------------------------------------------------------------------------- *)
+(* Measure of a standard simplex.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let CONGRUENT_IMAGE_STD_SIMPLEX = prove
+ (`!p. p permutes 1..dimindex(:N)
+       ==> {x:real^N | &0 <= x$(p 1) /\ x$(p(dimindex(:N))) <= &1 /\
+                       (!i. 1 <= i /\ i < dimindex(:N)
+                            ==> x$(p i) <= x$(p(i + 1)))} =
+           IMAGE (\x:real^N. lambda i. sum(1..inverse p(i)) (\j. x$j))
+                 {x | (!i. 1 <= i /\ i <= dimindex (:N) ==> &0 <= x$i) /\
+                      sum (1..dimindex (:N)) (\i. x$i) <= &1}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN X_GEN_TAC `x:real^N` THEN
+    ASM_SIMP_TAC[IN_ELIM_THM; LAMBDA_BETA; LAMBDA_BETA_PERM; LE_REFL;
+                 ARITH_RULE `i < n ==> i <= n /\ i + 1 <= n`;
+                 ARITH_RULE `1 <= n + 1`; DIMINDEX_GE_1] THEN
+    STRIP_TAC THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP PERMUTES_INVERSES th]) THEN
+    ASM_SIMP_TAC[SUM_SING_NUMSEG; DIMINDEX_GE_1; LE_REFL] THEN
+    REWRITE_TAC[GSYM ADD1; SUM_CLAUSES_NUMSEG; ARITH_RULE `1 <= SUC n`] THEN
+    ASM_SIMP_TAC[REAL_LE_ADDR] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC] THEN
+  REWRITE_TAC[SUBSET; IN_IMAGE; IN_ELIM_THM] THEN X_GEN_TAC `x:real^N` THEN
+  STRIP_TAC THEN
+  EXISTS_TAC `(lambda i. if i = 1 then x$(p 1)
+                         else (x:real^N)$p(i) - x$p(i - 1)):real^N` THEN
+  ASM_SIMP_TAC[IN_ELIM_THM; LAMBDA_BETA; LAMBDA_BETA_PERM; LE_REFL;
+               ARITH_RULE `i < n ==> i <= n /\ i + 1 <= n`;
+               ARITH_RULE `1 <= n + 1`; DIMINDEX_GE_1; CART_EQ] THEN
+  REPEAT CONJ_TAC THENL
+   [X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    SUBGOAL_THEN `1 <= inverse (p:num->num) i /\
+                  !x. x <= inverse p i ==> x <= dimindex(:N)`
+    ASSUME_TAC THENL
+     [ASM_MESON_TAC[PERMUTES_INVERSE; IN_NUMSEG; LE_TRANS; PERMUTES_IN_IMAGE];
+      ASM_SIMP_TAC[LAMBDA_BETA] THEN ASM_SIMP_TAC[SUM_CLAUSES_LEFT; ARITH]] THEN
+    SIMP_TAC[ARITH_RULE `2 <= n ==> ~(n = 1)`] THEN
+    GEN_REWRITE_TAC (RAND_CONV o RAND_CONV o BINDER_CONV)
+                [GSYM REAL_MUL_LID] THEN
+    ONCE_REWRITE_TAC[SUM_PARTIAL_PRE] THEN
+    REWRITE_TAC[REAL_SUB_REFL; REAL_MUL_RZERO; SUM_0; COND_ID] THEN
+    REWRITE_TAC[REAL_MUL_LID; ARITH; REAL_SUB_RZERO] THEN
+    FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (ARITH_RULE
+     `1 <= p ==> p = 1 \/ 2 <= p`) o CONJUNCT1) THEN
+    ASM_SIMP_TAC[ARITH] THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP PERMUTES_INVERSES th]) THEN
+    REWRITE_TAC[REAL_ADD_RID] THEN TRY REAL_ARITH_TAC THEN
+    ASM_MESON_TAC[PERMUTES_INVERSE_EQ; PERMUTES_INVERSE];
+
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[REAL_SUB_LE] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `i - 1`) THEN
+    ASM_SIMP_TAC[SUB_ADD] THEN DISCH_THEN MATCH_MP_TAC THEN ASM_ARITH_TAC;
+
+    SIMP_TAC[SUM_CLAUSES_LEFT; DIMINDEX_GE_1; ARITH;
+             ARITH_RULE `2 <= n ==> ~(n = 1)`] THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o RAND_CONV o BINDER_CONV)
+                [GSYM REAL_MUL_LID] THEN
+    ONCE_REWRITE_TAC[SUM_PARTIAL_PRE] THEN
+    REWRITE_TAC[REAL_SUB_REFL; REAL_MUL_RZERO; SUM_0; COND_ID] THEN
+    REWRITE_TAC[REAL_MUL_LID; ARITH; REAL_SUB_RZERO] THEN
+    COND_CASES_TAC THEN ASM_SIMP_TAC[REAL_ADD_RID] THEN
+    ASM_REWRITE_TAC[REAL_ARITH `x + y - x:real = y`] THEN
+    ASM_MESON_TAC[DIMINDEX_GE_1;
+                  ARITH_RULE `1 <= n /\ ~(2 <= n) ==> n = 1`]]);;
+
+let HAS_MEASURE_IMAGE_STD_SIMPLEX = prove
+ (`!p. p permutes 1..dimindex(:N)
+       ==> {x:real^N | &0 <= x$(p 1) /\ x$(p(dimindex(:N))) <= &1 /\
+                       (!i. 1 <= i /\ i < dimindex(:N)
+                            ==> x$(p i) <= x$(p(i + 1)))}
+           has_measure
+           (measure (convex hull
+             (vec 0 INSERT {basis i:real^N | 1 <= i /\ i <= dimindex(:N)})))`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[CONGRUENT_IMAGE_STD_SIMPLEX] THEN
+  ASM_SIMP_TAC[GSYM STD_SIMPLEX] THEN
+  MATCH_MP_TAC HAS_MEASURE_LINEAR_IMAGE_SAME THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[linear; CART_EQ] THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+                 GSYM SUM_ADD_NUMSEG; GSYM SUM_LMUL] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ_NUMSEG THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[];
+    MATCH_MP_TAC MEASURABLE_CONVEX THEN REWRITE_TAC[CONVEX_CONVEX_HULL] THEN
+    MATCH_MP_TAC BOUNDED_CONVEX_HULL THEN REWRITE_TAC[BOUNDED_INSERT] THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    MATCH_MP_TAC FINITE_IMP_BOUNDED THEN MATCH_MP_TAC FINITE_IMAGE THEN
+    REWRITE_TAC[GSYM numseg; FINITE_NUMSEG];
+    MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+     `abs(det
+       ((lambda i. ((lambda i j. if j <= i then &1 else &0):real^N^N)
+                   $inverse p i)
+        :real^N^N))` THEN
+    CONJ_TAC THENL
+     [AP_TERM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[CART_EQ] THEN
+      ASM_SIMP_TAC[matrix; LAMBDA_BETA; BASIS_COMPONENT; COND_COMPONENT;
+                   LAMBDA_BETA_PERM; PERMUTES_INVERSE] THEN
+      X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+      X_GEN_TAC `j:num` THEN STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+      EXISTS_TAC `sum (1..inverse (p:num->num) i)
+                      (\k. if k = j then &1 else &0)` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC SUM_EQ THEN
+        ASM_SIMP_TAC[IN_NUMSEG; PERMUTES_IN_IMAGE; basis] THEN
+        REPEAT STRIP_TAC THEN MATCH_MP_TAC LAMBDA_BETA THEN
+        ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG; LE_TRANS;
+                      PERMUTES_INVERSE];
+        ASM_SIMP_TAC[SUM_DELTA; IN_NUMSEG]];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[PERMUTES_INVERSE; DET_PERMUTE_ROWS; ETA_AX] THEN
+    REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_SIGN; REAL_MUL_LID] THEN
+    MATCH_MP_TAC(REAL_ARITH `x = &1 ==> abs x = &1`) THEN
+    ASM_SIMP_TAC[DET_LOWERTRIANGULAR; GSYM NOT_LT; LAMBDA_BETA] THEN
+    REWRITE_TAC[LT_REFL; PRODUCT_CONST_NUMSEG; REAL_POW_ONE]]);;
+
+let HAS_MEASURE_STD_SIMPLEX = prove
+ (`(convex hull (vec 0:real^N INSERT {basis i | 1 <= i /\ i <= dimindex(:N)}))
+   has_measure inv(&(FACT(dimindex(:N))))`,
+  let lemma = prove
+   (`!f:num->real. (!i. 1 <= i /\ i < n ==> f i <= f(i + 1)) <=>
+                   (!i j. 1 <= i /\ i <= j /\ j <= n ==> f i <= f j)`,
+    GEN_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+     [GEN_TAC THEN INDUCT_TAC THEN
+      SIMP_TAC[LE; REAL_LE_REFL] THEN
+      STRIP_TAC THEN ASM_SIMP_TAC[REAL_LE_REFL] THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `(f:num->real) j` THEN
+      ASM_SIMP_TAC[ARITH_RULE `SUC x <= y ==> x <= y`] THEN
+      REWRITE_TAC[ADD1] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC;
+      REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC]) in
+  MP_TAC(ISPECL
+   [`\p. {x:real^N | &0 <= x$(p 1) /\ x$(p(dimindex(:N))) <= &1 /\
+                     (!i. 1 <= i /\ i < dimindex(:N)
+                          ==> x$(p i) <= x$(p(i + 1)))}`;
+    `{p | p permutes 1..dimindex(:N)}`]
+    HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE) THEN
+  ASM_SIMP_TAC[REWRITE_RULE[HAS_MEASURE_MEASURABLE_MEASURE]
+                            HAS_MEASURE_IMAGE_STD_SIMPLEX; IN_ELIM_THM] THEN
+  ASM_SIMP_TAC[SUM_CONST; FINITE_PERMUTATIONS; FINITE_NUMSEG;
+               CARD_PERMUTATIONS; CARD_NUMSEG_1] THEN
+  ANTS_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`p:num->num`; `q:num->num`] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `?i. i IN 1..dimindex(:N) /\ ~(p i:num = q i)` MP_TAC THENL
+     [ASM_MESON_TAC[permutes; FUN_EQ_THM]; ALL_TAC] THEN
+    GEN_REWRITE_TAC LAND_CONV [num_WOP] THEN
+    REWRITE_TAC[TAUT `a ==> ~(b /\ ~c) <=> a /\ b ==> c`] THEN
+    REWRITE_TAC[IN_NUMSEG] THEN
+    DISCH_THEN(X_CHOOSE_THEN `k:num` STRIP_ASSUME_TAC) THEN
+    MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+    EXISTS_TAC `{x:real^N | (basis(p(k:num)) - basis(q k)) dot x = &0}` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC NEGLIGIBLE_HYPERPLANE THEN REWRITE_TAC[VECTOR_SUB_EQ] THEN
+      MATCH_MP_TAC BASIS_NE THEN ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG];
+      ALL_TAC] THEN
+    REWRITE_TAC[SUBSET; IN_INTER; IN_ELIM_THM; DOT_LSUB; VECTOR_SUB_EQ] THEN
+    ASM_SIMP_TAC[DOT_BASIS; GSYM IN_NUMSEG; PERMUTES_IN_IMAGE] THEN
+    SUBGOAL_THEN `?l. (q:num->num) l = p(k:num)` STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[permutes]; ALL_TAC] THEN
+    SUBGOAL_THEN `1 <= l /\ l <= dimindex(:N)` STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG]; ALL_TAC] THEN
+    SUBGOAL_THEN `k:num < l` ASSUME_TAC THENL
+     [REWRITE_TAC[GSYM NOT_LE] THEN REWRITE_TAC[LE_LT] THEN
+      ASM_MESON_TAC[PERMUTES_INJECTIVE; IN_NUMSEG];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `?m. (p:num->num) m = q(k:num)` STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[permutes]; ALL_TAC] THEN
+    SUBGOAL_THEN `1 <= m /\ m <= dimindex(:N)` STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG]; ALL_TAC] THEN
+    SUBGOAL_THEN `k:num < m` ASSUME_TAC THENL
+     [REWRITE_TAC[GSYM NOT_LE] THEN REWRITE_TAC[LE_LT] THEN
+      ASM_MESON_TAC[PERMUTES_INJECTIVE; IN_NUMSEG];
+      ALL_TAC] THEN
+    X_GEN_TAC `x:real^N` THEN REWRITE_TAC[lemma] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`k:num`; `l:num`]) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`k:num`; `m:num`]) THEN
+    ASM_SIMP_TAC[LT_IMP_LE; IMP_IMP; REAL_LE_ANTISYM; REAL_SUB_0] THEN
+    MATCH_MP_TAC EQ_IMP THEN BINOP_TAC THEN
+    ASM_MESON_TAC[PERMUTES_IN_IMAGE; IN_NUMSEG; DOT_BASIS];
+    ALL_TAC] THEN
+  REWRITE_TAC[HAS_MEASURE_MEASURABLE_MEASURE] THEN
+  DISCH_THEN(ASSUME_TAC o CONJUNCT2) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC MEASURABLE_CONVEX THEN REWRITE_TAC[CONVEX_CONVEX_HULL] THEN
+    MATCH_MP_TAC BOUNDED_CONVEX_HULL THEN REWRITE_TAC[BOUNDED_INSERT] THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    MATCH_MP_TAC FINITE_IMP_BOUNDED THEN MATCH_MP_TAC FINITE_IMAGE THEN
+    REWRITE_TAC[GSYM numseg; FINITE_NUMSEG];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_FIELD `~(y = &0) ==> (x = inv y <=> y * x = &1)`;
+               REAL_OF_NUM_EQ; FACT_NZ] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `measure(interval[vec 0:real^N,vec 1])` THEN CONJ_TAC THENL
+   [AP_TERM_TAC; REWRITE_TAC[MEASURE_INTERVAL; CONTENT_UNIT]] THEN
+  REWRITE_TAC[lemma] THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_UNIONS; FORALL_IN_IMAGE; IMP_CONJ;
+                RIGHT_FORALL_IMP_THM; IN_ELIM_THM] THEN
+    SIMP_TAC[IMP_IMP; IN_INTERVAL; LAMBDA_BETA; VEC_COMPONENT] THEN
+    X_GEN_TAC `p:num->num` THEN STRIP_TAC THEN X_GEN_TAC `x:real^N` THEN
+    STRIP_TAC THEN X_GEN_TAC `i:num` THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THENL
+     [EXISTS_TAC `(x:real^N)$(p 1)`;
+      EXISTS_TAC `(x:real^N)$(p(dimindex(:N)))`] THEN
+    ASM_REWRITE_TAC[] THEN
+    FIRST_ASSUM(MP_TAC o SPEC `i:num` o MATCH_MP PERMUTES_SURJECTIVE) THEN
+    ASM_MESON_TAC[LE_REFL; PERMUTES_IN_IMAGE; IN_NUMSEG];
+    ALL_TAC] THEN
+  REWRITE_TAC[SET_RULE `s SUBSET UNIONS(IMAGE f t) <=>
+                        !x. x IN s ==> ?y. y IN t /\ x IN f y`] THEN
+  X_GEN_TAC `x:real^N` THEN REWRITE_TAC[IN_INTERVAL; IN_ELIM_THM] THEN
+  SIMP_TAC[VEC_COMPONENT] THEN DISCH_TAC THEN
+  MP_TAC(ISPEC `\i j. ~((x:real^N)$j <= x$i)` TOPOLOGICAL_SORT) THEN
+  REWRITE_TAC[REAL_NOT_LE; REAL_NOT_LT] THEN
+  ANTS_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPECL [`dimindex(:N)`; `1..dimindex(:N)`]) THEN
+  REWRITE_TAC[HAS_SIZE_NUMSEG_1; EXTENSION; IN_IMAGE; IN_NUMSEG] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:num->num` (CONJUNCTS_THEN2
+   (ASSUME_TAC o GSYM) ASSUME_TAC)) THEN
+  EXISTS_TAC `\i. if i IN 1..dimindex(:N) then f(i) else i` THEN
+  REWRITE_TAC[] THEN ONCE_REWRITE_TAC[ARITH_RULE
+    `1 <= i /\ i <= j /\ j <= n <=>
+     1 <= i /\ 1 <= j /\ i <= n /\ j <= n /\ i <= j`] THEN
+  ASM_SIMP_TAC[IN_NUMSEG; LE_REFL; DIMINDEX_GE_1] THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_MESON_TAC[LE_REFL; DIMINDEX_GE_1; LE_LT; REAL_LE_LT]] THEN
+  SIMP_TAC[PERMUTES_FINITE_SURJECTIVE; FINITE_NUMSEG] THEN
+  SIMP_TAC[IN_NUMSEG] THEN ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence the measure of a general simplex.                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_MEASURE_SIMPLEX_0 = prove
+ (`!l:(real^N)list.
+        LENGTH l = dimindex(:N)
+        ==> (convex hull (vec 0 INSERT set_of_list l)) has_measure
+            abs(det(vector l)) / &(FACT(dimindex(:N)))`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `vec 0 INSERT (set_of_list l) =
+        IMAGE (\x:real^N. transp(vector l:real^N^N) ** x)
+              (vec 0 INSERT {basis i:real^N | 1 <= i /\ i <= dimindex(:N)})`
+  SUBST1_TAC THENL
+   [ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    REWRITE_TAC[IMAGE_CLAUSES; GSYM IMAGE_o; o_DEF] THEN
+    REWRITE_TAC[MATRIX_VECTOR_MUL_RZERO] THEN AP_TERM_TAC THEN
+    SIMP_TAC[matrix_vector_mul; vector; transp; LAMBDA_BETA; basis] THEN
+    ONCE_REWRITE_TAC[COND_RAND] THEN
+    SIMP_TAC[REAL_MUL_RZERO; SUM_DELTA] THEN
+    REWRITE_TAC[EXTENSION; IN_IMAGE; IN_ELIM_THM; IN_NUMSEG] THEN
+    ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> ~(b /\ c ==> ~a)`] THEN
+    X_GEN_TAC `y:real^N` THEN SIMP_TAC[LAMBDA_BETA; REAL_MUL_RID] THEN
+    SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN
+    REWRITE_TAC[NOT_IMP; REAL_MUL_RID; GSYM CART_EQ] THEN
+    ASM_REWRITE_TAC[IN_SET_OF_LIST; MEM_EXISTS_EL] THEN
+    EQ_TAC THEN DISCH_THEN(X_CHOOSE_THEN `i:num` STRIP_ASSUME_TAC) THENL
+     [EXISTS_TAC `SUC i`; EXISTS_TAC `i - 1`] THEN
+    ASM_REWRITE_TAC[SUC_SUB1] THEN ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[CONVEX_HULL_LINEAR_IMAGE; MATRIX_VECTOR_MUL_LINEAR] THEN
+  SUBGOAL_THEN
+   `det(vector l:real^N^N) = det(matrix(\x:real^N. transp(vector l) ** x))`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[MATRIX_OF_MATRIX_VECTOR_MUL; DET_TRANSP]; ALL_TAC] THEN
+  REWRITE_TAC[real_div] THEN
+  ASM_SIMP_TAC[GSYM(REWRITE_RULE[HAS_MEASURE_MEASURABLE_MEASURE]
+                 HAS_MEASURE_STD_SIMPLEX)] THEN
+  MATCH_MP_TAC HAS_MEASURE_LINEAR_IMAGE THEN
+  REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR] THEN
+  MATCH_MP_TAC MEASURABLE_CONVEX THEN REWRITE_TAC[CONVEX_CONVEX_HULL] THEN
+  MATCH_MP_TAC BOUNDED_CONVEX_HULL THEN REWRITE_TAC[BOUNDED_INSERT] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+  MATCH_MP_TAC FINITE_IMP_BOUNDED THEN MATCH_MP_TAC FINITE_IMAGE THEN
+  REWRITE_TAC[GSYM numseg; FINITE_NUMSEG]);;
+
+let HAS_MEASURE_SIMPLEX = prove
+ (`!a l:(real^N)list.
+        LENGTH l = dimindex(:N)
+        ==> (convex hull (set_of_list(CONS a l))) has_measure
+            abs(det(vector(MAP (\x. x - a) l))) / &(FACT(dimindex(:N)))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `MAP (\x:real^N. x - a) l` HAS_MEASURE_SIMPLEX_0) THEN
+  ASM_REWRITE_TAC[LENGTH_MAP; set_of_list] THEN
+  DISCH_THEN(MP_TAC o SPEC `a:real^N` o MATCH_MP HAS_MEASURE_TRANSLATION) THEN
+  REWRITE_TAC[GSYM CONVEX_HULL_TRANSLATION] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[IMAGE_CLAUSES; VECTOR_ADD_RID; SET_OF_LIST_MAP] THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; VECTOR_ARITH `a + x - a:real^N = x`;
+              SET_RULE `IMAGE (\x. x) s = s`]);;
+
+let MEASURABLE_CONVEX_HULL = prove
+ (`!s. bounded s ==> measurable(convex hull s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_CONVEX THEN
+  ASM_SIMP_TAC[CONVEX_CONVEX_HULL; BOUNDED_CONVEX_HULL]);;
+
+let MEASURABLE_SIMPLEX = prove
+ (`!l. measurable(convex hull (set_of_list l))`,
+  GEN_TAC THEN MATCH_MP_TAC MEASURABLE_CONVEX_HULL THEN
+  MATCH_MP_TAC FINITE_IMP_BOUNDED THEN REWRITE_TAC[FINITE_SET_OF_LIST]);;
+
+let MEASURE_SIMPLEX = prove
+ (`!a l:(real^N)list.
+        LENGTH l = dimindex(:N)
+        ==> measure(convex hull (set_of_list(CONS a l))) =
+            abs(det(vector(MAP (\x. x - a) l))) / &(FACT(dimindex(:N)))`,
+  MESON_TAC[HAS_MEASURE_SIMPLEX; HAS_MEASURE_MEASURABLE_MEASURE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Area of a triangle.                                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_MEASURE_TRIANGLE = prove
+ (`!a b c:real^2.
+        convex hull {a,b,c} has_measure
+        abs((b$1 - a$1) * (c$2 - a$2) - (b$2 - a$2) * (c$1 - a$1)) / &2`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`a:real^2`; `[b;c]:(real^2)list`] HAS_MEASURE_SIMPLEX) THEN
+  REWRITE_TAC[LENGTH; DIMINDEX_2; ARITH; set_of_list; MAP] THEN
+  CONV_TAC NUM_REDUCE_CONV THEN SIMP_TAC[DET_2; VECTOR_2] THEN
+  SIMP_TAC[VECTOR_SUB_COMPONENT; DIMINDEX_2; ARITH]);;
+
+let MEASURABLE_TRIANGLE = prove
+ (`!a b c:real^N. measurable(convex hull {a,b,c})`,
+  REPEAT GEN_TAC THEN
+  MATCH_MP_TAC MEASURABLE_CONVEX THEN REWRITE_TAC[CONVEX_CONVEX_HULL] THEN
+  MATCH_MP_TAC BOUNDED_CONVEX_HULL THEN MATCH_MP_TAC FINITE_IMP_BOUNDED THEN
+  REWRITE_TAC[FINITE_INSERT; FINITE_RULES]);;
+
+let MEASURE_TRIANGLE = prove
+ (`!a b c:real^2.
+        measure(convex hull {a,b,c}) =
+        abs((b$1 - a$1) * (c$2 - a$2) - (b$2 - a$2) * (c$1 - a$1)) / &2`,
+  REWRITE_TAC[REWRITE_RULE[HAS_MEASURE_MEASURABLE_MEASURE]
+               HAS_MEASURE_TRIANGLE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Volume of a tetrahedron.                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_MEASURE_TETRAHEDRON = prove
+ (`!a b c d:real^3.
+        convex hull {a,b,c,d} has_measure
+        abs((b$1 - a$1) * (c$2 - a$2) * (d$3 - a$3) +
+            (b$2 - a$2) * (c$3 - a$3) * (d$1 - a$1) +
+            (b$3 - a$3) * (c$1 - a$1) * (d$2 - a$2) -
+            (b$1 - a$1) * (c$3 - a$3) * (d$2 - a$2) -
+            (b$2 - a$2) * (c$1 - a$1) * (d$3 - a$3) -
+            (b$3 - a$3) * (c$2 - a$2) * (d$1 - a$1)) /
+           &6`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`a:real^3`; `[b;c;d]:(real^3)list`] HAS_MEASURE_SIMPLEX) THEN
+  REWRITE_TAC[LENGTH; DIMINDEX_3; ARITH; set_of_list; MAP] THEN
+  CONV_TAC NUM_REDUCE_CONV THEN SIMP_TAC[DET_3; VECTOR_3] THEN
+  SIMP_TAC[VECTOR_SUB_COMPONENT; DIMINDEX_3; ARITH]);;
+
+let MEASURABLE_TETRAHEDRON = prove
+ (`!a b c d:real^N. measurable(convex hull {a,b,c,d})`,
+  REPEAT GEN_TAC THEN
+  MATCH_MP_TAC MEASURABLE_CONVEX THEN REWRITE_TAC[CONVEX_CONVEX_HULL] THEN
+  MATCH_MP_TAC BOUNDED_CONVEX_HULL THEN MATCH_MP_TAC FINITE_IMP_BOUNDED THEN
+  REWRITE_TAC[FINITE_INSERT; FINITE_RULES]);;
+
+let MEASURE_TETRAHEDRON = prove
+ (`!a b c d:real^3.
+        measure(convex hull {a,b,c,d}) =
+        abs((b$1 - a$1) * (c$2 - a$2) * (d$3 - a$3) +
+            (b$2 - a$2) * (c$3 - a$3) * (d$1 - a$1) +
+            (b$3 - a$3) * (c$1 - a$1) * (d$2 - a$2) -
+            (b$1 - a$1) * (c$3 - a$3) * (d$2 - a$2) -
+            (b$2 - a$2) * (c$1 - a$1) * (d$3 - a$3) -
+            (b$3 - a$3) * (c$2 - a$2) * (d$1 - a$1)) / &6`,
+  REWRITE_TAC[REWRITE_RULE[HAS_MEASURE_MEASURABLE_MEASURE]
+               HAS_MEASURE_TETRAHEDRON]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Steinhaus's theorem. (Stromberg's proof as given on Wikipedia.)           *)
+(* ------------------------------------------------------------------------- *)
+
+let STEINHAUS = prove
+ (`!s:real^N->bool.
+        measurable s /\ &0 < measure s
+        ==> ?d. &0 < d /\ ball(vec 0,d) SUBSET {x - y | x IN s /\ y IN s}`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `measure(s:real^N->bool) / &3`]
+    MEASURABLE_INNER_COMPACT) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `measure(s:real^N->bool) / &3`]
+    MEASURABLE_OUTER_OPEN) THEN
+  ASM_REWRITE_TAC[REAL_ARITH `&0 < x / &3 <=> &0 < x`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`k:real^N->bool`; `(:real^N) DIFF u`]
+    SEPARATE_COMPACT_CLOSED) THEN
+  ASM_REWRITE_TAC[GSYM OPEN_CLOSED] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[SUBSET; IN_BALL_0; IN_ELIM_THM] THEN
+  X_GEN_TAC `v:real^N` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `~((IMAGE (\x:real^N. v + x) k) INTER k = {})` MP_TAC THENL
+   [DISCH_TAC THEN
+    MP_TAC(ISPECL [`IMAGE (\x:real^N. v + x) k`; `k:real^N->bool`]
+        MEASURE_UNION) THEN
+    ASM_REWRITE_TAC[MEASURABLE_TRANSLATION_EQ; MEASURE_EMPTY] THEN
+    REWRITE_TAC[MEASURE_TRANSLATION; REAL_SUB_RZERO] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `!s:real^N->bool u:real^N->bool.
+        measure u < measure s + measure s / &3 /\
+        measure s < measure k + measure s / &3 /\
+        measure x <= measure u
+        ==> ~(measure x = measure k + measure k)`) THEN
+    MAP_EVERY EXISTS_TAC [`s:real^N->bool`; `u:real^N->bool`] THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+    ASM_SIMP_TAC[MEASURABLE_TRANSLATION_EQ; MEASURABLE_UNION] THEN
+    ASM_REWRITE_TAC[UNION_SUBSET] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `v + x:real^N`]) THEN
+    ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; NORM_ARITH
+     `d <= dist(x:real^N,v + x) <=> ~(norm v < d)`];
+    REWRITE_TAC[EXTENSION; IN_INTER; NOT_IN_EMPTY; IN_IMAGE] THEN
+    REWRITE_TAC[VECTOR_ARITH `v:real^N = x - y <=> x = v + y`] THEN
+    ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A measurable set with cardinality less than c is negligible.              *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_NONNEGLIGIBLE_IMP_LARGE = prove
+ (`!s:real^N->bool. measurable s /\ &0 < measure s ==> s =_c (:real)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `FINITE(s:real^N->bool)` THENL
+   [ASM_MESON_TAC[NEGLIGIBLE_FINITE; MEASURABLE_MEASURE_POS_LT];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP STEINHAUS) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[GSYM CARD_LE_ANTISYM] THEN CONJ_TAC THENL
+   [TRANS_TAC CARD_LE_TRANS `(:real^N)` THEN
+    REWRITE_TAC[CARD_LE_UNIV] THEN MATCH_MP_TAC CARD_EQ_IMP_LE THEN
+    REWRITE_TAC[CARD_EQ_EUCLIDEAN];
+    ALL_TAC] THEN
+  TRANS_TAC CARD_LE_TRANS `(:real^N)` THEN CONJ_TAC THENL
+   [MESON_TAC[CARD_EQ_EUCLIDEAN; CARD_EQ_SYM; CARD_EQ_IMP_LE]; ALL_TAC] THEN
+  TRANS_TAC CARD_LE_TRANS `interval(vec 0:real^N,vec 1)` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CARD_EQ_IMP_LE THEN ONCE_REWRITE_TAC[CARD_EQ_SYM] THEN
+    MATCH_MP_TAC HOMEOMORPHIC_IMP_CARD_EQ THEN
+    MATCH_MP_TAC HOMEOMORPHIC_OPEN_INTERVAL_UNIV THEN
+    REWRITE_TAC[UNIT_INTERVAL_NONEMPTY];
+    ALL_TAC] THEN
+  TRANS_TAC CARD_LE_TRANS `interval[vec 0:real^N,vec 1]` THEN
+  SIMP_TAC[INTERVAL_OPEN_SUBSET_CLOSED; CARD_LE_SUBSET] THEN
+  TRANS_TAC CARD_LE_TRANS `cball(vec 0:real^N,d / &2)` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CARD_EQ_IMP_LE THEN
+    MATCH_MP_TAC HOMEOMORPHIC_IMP_CARD_EQ THEN
+    MATCH_MP_TAC HOMEOMORPHIC_CONVEX_COMPACT THEN
+    REWRITE_TAC[CONVEX_INTERVAL; COMPACT_INTERVAL; INTERIOR_CLOSED_INTERVAL;
+                CONVEX_CBALL; COMPACT_CBALL; UNIT_INTERVAL_NONEMPTY;
+                INTERIOR_CBALL; BALL_EQ_EMPTY] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  TRANS_TAC CARD_LE_TRANS `ball(vec 0:real^N,d)` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CARD_LE_SUBSET THEN
+    REWRITE_TAC[SUBSET; IN_BALL; IN_CBALL] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  TRANS_TAC CARD_LE_TRANS `IMAGE (\(x:real^N,y). x - y) (s *_c s)` THEN
+  CONJ_TAC THENL
+   [ASM_SIMP_TAC[mul_c; CARD_LE_SUBSET; SET_RULE
+     `IMAGE f {g x y | P x /\ Q y} = {f(g x y) | P x /\ Q y}`];
+    ALL_TAC] THEN
+  TRANS_TAC CARD_LE_TRANS `((s:real^N->bool) *_c s)` THEN
+  REWRITE_TAC[CARD_LE_IMAGE] THEN
+  MATCH_MP_TAC CARD_EQ_IMP_LE THEN MATCH_MP_TAC CARD_SQUARE_INFINITE THEN
+  ASM_REWRITE_TAC[INFINITE]);;
+
+let MEASURABLE_SMALL_IMP_NEGLIGIBLE = prove
+ (`!s:real^N->bool. measurable s /\ s <_c (:real) ==> negligible s`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[TAUT `a /\ b ==> c <=> a ==> ~c ==> ~b`] THEN
+  SIMP_TAC[GSYM MEASURABLE_MEASURE_POS_LT] THEN REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_NONNEGLIGIBLE_IMP_LARGE) THEN
+  REWRITE_TAC[lt_c] THEN MESON_TAC[CARD_EQ_IMP_LE; CARD_EQ_SYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Austin's Lemma.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let AUSTIN_LEMMA = prove
+ (`!D. FINITE D /\
+       (!d. d IN D
+            ==> ?k a b. d = interval[a:real^N,b] /\
+                        (!i. 1 <= i /\ i <= dimindex(:N) ==> b$i - a$i = k))
+       ==> ?D'. D' SUBSET D /\ pairwise DISJOINT D' /\
+                measure(UNIONS D') >=
+                measure(UNIONS D) / &3 pow (dimindex(:N))`,
+  GEN_TAC THEN WF_INDUCT_TAC `CARD(D:(real^N->bool)->bool)` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "*")) THEN
+  ASM_CASES_TAC `D:(real^N->bool)->bool = {}` THENL
+   [ASM_REWRITE_TAC[SUBSET_EMPTY; UNWIND_THM2; PAIRWISE_EMPTY] THEN
+    REWRITE_TAC[UNIONS_0; real_ge; MEASURE_EMPTY; NOT_IN_EMPTY] THEN
+    REWRITE_TAC[REAL_ARITH `&0 / x = &0`; REAL_LE_REFL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?d:real^N->bool. d IN D /\ !d'. d' IN D ==> measure d' <= measure d`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPEC `IMAGE measure (D:(real^N->bool)->bool)` SUP_FINITE) THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; IMAGE_EQ_EMPTY; FORALL_IN_IMAGE] THEN SET_TAC[];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC
+    `{c:real^N->bool | c IN (D DELETE d) /\ c INTER d = {}}`) THEN
+  ANTS_TAC THENL [MATCH_MP_TAC CARD_PSUBSET THEN ASM SET_TAC[]; ALL_TAC] THEN
+  ASM_SIMP_TAC[FINITE_DELETE; FINITE_RESTRICT; IN_ELIM_THM; real_ge] THEN
+  ANTS_TAC THENL [ASM_SIMP_TAC[IN_DELETE]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `D':(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(d:real^N->bool) INSERT D'` THEN REPEAT CONJ_TAC THENL
+   [ASM SET_TAC[];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [pairwise]) THEN
+    REWRITE_TAC[pairwise; IN_INSERT] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?a3 b3:real^N.
+        measure(interval[a3,b3]) = &3 pow dimindex(:N) * measure d /\
+        !c. c IN D /\ ~(c INTER d = {}) ==> c SUBSET interval[a3,b3]`
+  STRIP_ASSUME_TAC THENL
+   [USE_THEN "*" (MP_TAC o SPEC `d:real^N->bool`) THEN
+    ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`k:real`; `a:real^N`; `b:real^N`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC ASSUME_TAC) THEN
+    EXISTS_TAC `inv(&2) % (a + b) - &3 / &2 % (b - a):real^N` THEN
+    EXISTS_TAC `inv(&2) % (a + b) + &3 / &2 % (b - a):real^N` THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+      REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_SUB_COMPONENT;
+                  VECTOR_MUL_COMPONENT] THEN
+      REWRITE_TAC[REAL_ARITH `(x + &3 / &2 * a) - (x - &3 / &2 * a) = &3 * a`;
+                  REAL_ARITH `x - a <= x + a <=> &0 <= a`] THEN
+      ASM_SIMP_TAC[] THEN ONCE_REWRITE_TAC[GSYM REAL_SUB_LE] THEN
+      ASM_SIMP_TAC[REAL_ARITH `&0 <= &3 / &2 * x - &0 <=> &0 <= x`] THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_MUL_RZERO] THEN
+      SIMP_TAC[PRODUCT_CONST; FINITE_NUMSEG; CARD_NUMSEG_1; REAL_POW_MUL];
+      X_GEN_TAC `c:real^N->bool` THEN STRIP_TAC THEN
+      REMOVE_THEN "*" (MP_TAC o SPEC `c:real^N->bool`) THEN
+      ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+      MAP_EVERY X_GEN_TAC [`k':real`; `a':real^N`; `b':real^N`] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC ASSUME_TAC) THEN
+      FIRST_X_ASSUM(MP_TAC o
+        GEN_REWRITE_RULE RAND_CONV [DISJOINT_INTERVAL]) THEN
+      REWRITE_TAC[NOT_EXISTS_THM; SUBSET_INTERVAL] THEN
+      REWRITE_TAC[IMP_IMP; AND_FORALL_THM] THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+      ASM_CASES_TAC `1 <= i` THEN ASM_REWRITE_TAC[] THEN
+      ASM_CASES_TAC `i <= dimindex(:N)` THEN ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `interval[a':real^N,b']`) THEN
+      ASM_REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+      REWRITE_TAC[DE_MORGAN_THM; REAL_NOT_LT] THEN
+      REWRITE_TAC[REAL_ARITH `a$k <= b$k <=> &0 <= b$k - a$k`] THEN
+      ASM_SIMP_TAC[IN_NUMSEG] THEN
+      ASM_CASES_TAC `&0 <= k` THEN ASM_REWRITE_TAC[] THEN
+      ASM_CASES_TAC `&0 <= k'` THEN ASM_REWRITE_TAC[] THEN
+      REPEAT(FIRST_X_ASSUM(fun th ->
+        SIMP_TAC[th] THEN MP_TAC(ISPEC `i:num` th))) THEN
+      ASM_SIMP_TAC[PRODUCT_CONST; CARD_NUMSEG_1; FINITE_NUMSEG] THEN
+      DISCH_TAC THEN DISCH_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP
+       (REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> c ==> a /\ b ==> d`]
+        REAL_POW_LE2_REV)) THEN
+      ASM_SIMP_TAC[DIMINDEX_GE_1; LE_1] THEN
+      REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_SUB_COMPONENT;
+                  VECTOR_MUL_COMPONENT] THEN
+      ASM_REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  REWRITE_TAC[UNIONS_INSERT] THEN
+  SUBGOAL_THEN `!d:real^N->bool. d IN D ==> measurable d` ASSUME_TAC THENL
+   [ASM_MESON_TAC[MEASURABLE_INTERVAL]; ALL_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) MEASURE_DISJOINT_UNION o
+    rand o snd) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC MEASURABLE_UNIONS THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+      FINITE_SUBSET)) THEN
+    ASM_SIMP_TAC[FINITE_RESTRICT; FINITE_DELETE];
+    DISCH_THEN SUBST1_TAC] THEN
+  ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `measure(interval[a3:real^N,b3]) +
+              measure(UNIONS D DIFF interval[a3,b3])` THEN
+  CONJ_TAC THENL
+   [W(MP_TAC o PART_MATCH (rand o rand) MEASURE_DISJOINT_UNION o
+      rand o snd) THEN
+    ANTS_TAC THENL
+     [ASM_SIMP_TAC[MEASURABLE_UNIONS; MEASURABLE_DIFF;
+                   MEASURABLE_INTERVAL] THEN SET_TAC[];
+      DISCH_THEN(SUBST1_TAC o SYM) THEN
+      MATCH_MP_TAC MEASURE_SUBSET THEN REPEAT CONJ_TAC THENL
+       [ASM_SIMP_TAC[MEASURABLE_UNIONS];
+        ASM_MESON_TAC[MEASURABLE_UNIONS; MEASURABLE_DIFF;
+                     MEASURABLE_INTERVAL; MEASURABLE_UNION];
+        SET_TAC[]]];
+    ASM_REWRITE_TAC[REAL_ARITH `a * x + y <= (x + z) * a <=> y <= z * a`] THEN
+    ASM_SIMP_TAC[GSYM REAL_LE_LDIV_EQ; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `y <= a ==> x <= y ==> x <= a`)) THEN
+    SIMP_TAC[REAL_LE_DIV2_EQ; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+    MATCH_MP_TAC MEASURE_SUBSET THEN
+    ASM_SIMP_TAC[MEASURABLE_DIFF; MEASURABLE_UNIONS; MEASURABLE_INTERVAL;
+                 IN_ELIM_THM; IN_DELETE; FINITE_DELETE; FINITE_RESTRICT] THEN
+    ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some differentiability-like properties of the indefinite integral.        *)
+(* The first two proofs are minor variants of each other, but it was more    *)
+(* work to derive one from the other.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let INTEGRABLE_CCONTINUOUS_EXPLICIT = prove
+ (`!f:real^M->real^N.
+    (!a b. f integrable_on interval[a,b])
+    ==> ?k. negligible k /\
+         !x e. ~(x IN k) /\ &0 < e
+               ==> ?d. &0 < d /\
+                       !h. &0 < h /\ h < d
+                           ==> norm(inv(content(interval[x,x + h % vec 1])) %
+                                    integral (interval[x,x + h % vec 1]) f -
+                                    f(x)) < e`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[IN_UNIV] THEN
+  MAP_EVERY ABBREV_TAC
+   [`box = \h x. interval[x:real^M,x + h % vec 1]`;
+    `box2 = \h x. interval[x:real^M - h % vec 1,x + h % vec 1]`;
+    `i = \h:real x:real^M. inv(content(box h x)) %
+                      integral (box h x) (f:real^M->real^N)`] THEN
+  SUBGOAL_THEN
+   `?k. negligible k /\
+        !x e. ~(x IN k) /\ &0 < e
+              ==> ?d. &0 < d /\
+                      !h. &0 < h /\ h < d
+                          ==> norm(i h x - (f:real^M->real^N) x) < e`
+  MP_TAC THENL
+   [ALL_TAC; MAP_EVERY EXPAND_TAC ["i"; "box"] THEN REWRITE_TAC[]] THEN
+  EXISTS_TAC
+   `{x | ~(!e. &0 < e
+              ==> ?d. &0 < d /\
+                      !h. &0 < h /\ h < d
+                          ==> norm(i h x - (f:real^M->real^N) x) < e)}` THEN
+  SIMP_TAC[IN_ELIM_THM] THEN
+  REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; NOT_EXISTS_THM] THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC
+   `UNIONS {{x | !d. &0 < d
+                     ==> ?h. &0 < h /\ h < d /\
+                             inv(&k + &1) <= dist(i h x,(f:real^M->real^N) x)}
+            |  k IN (:num)}` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[SUBSET; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`y:real^M`; `e:real`] THEN STRIP_TAC THEN
+    REWRITE_TAC[SIMPLE_IMAGE; UNIONS_IMAGE] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_UNIV] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REAL_ARCH_INV]) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:num` THEN DISCH_TAC THEN
+    X_GEN_TAC `d:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `d:real`) THEN
+    ASM_REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; REAL_NOT_LT] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `h:real` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+    ASM_REWRITE_TAC[dist] THEN
+    MATCH_MP_TAC (REWRITE_RULE[IMP_CONJ] REAL_LE_TRANS) THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `inv(&k)` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+    MATCH_MP_TAC REAL_LE_INV2 THEN
+    ASM_REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+    ASM_ARITH_TAC] THEN
+  MATCH_MP_TAC NEGLIGIBLE_COUNTABLE_UNIONS THEN
+  X_GEN_TAC `jj:num` THEN
+  SUBGOAL_THEN `&0 < inv(&jj + &1)` MP_TAC THENL
+   [REWRITE_TAC[REAL_LT_INV_EQ] THEN REAL_ARITH_TAC;
+    SPEC_TAC(`inv(&jj + &1)`,`mu:real`) THEN GEN_TAC THEN DISCH_TAC] THEN
+  ONCE_REWRITE_TAC[NEGLIGIBLE_ON_INTERVALS] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN
+  ASM_CASES_TAC `negligible(interval[a:real^M,b])` THENL
+   [ASM_MESON_TAC[NEGLIGIBLE_SUBSET; INTER_SUBSET]; ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[NEGLIGIBLE_INTERVAL]) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+  REWRITE_TAC[NEGLIGIBLE_OUTER_LE] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `a - vec 1:real^M`; `b + vec 1:real^M`]
+    HENSTOCK_LEMMA) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[INTEGRABLE_ON_SUBINTERVAL; SUBSET_UNIV]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `(e * mu) / &2 / &6 pow (dimindex(:M))`) THEN
+  ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; REAL_LT_MUL;
+               REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[SET_RULE `{x | P x} INTER s = {x | x IN s /\ P x}`] THEN
+  ABBREV_TAC
+    `E = {x | x IN interval[a,b] /\
+              !d. &0 < d
+                   ==> ?h. &0 < h /\ h < d /\
+                           mu <= dist(i h x,(f:real^M->real^N) x)}` THEN
+  SUBGOAL_THEN
+   `!x. x IN E
+        ==> ?h. &0 < h /\
+                (box h x:real^M->bool) SUBSET (g x) /\
+                (box h x:real^M->bool) SUBSET interval[a - vec 1,b + vec 1] /\
+                mu <= dist(i h x,(f:real^M->real^N) x)`
+  MP_TAC THENL
+   [X_GEN_TAC `x:real^M` THEN EXPAND_TAC "E" THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [gauge]) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC o SPEC `x:real^M`) THEN
+    REWRITE_TAC[OPEN_CONTAINS_BALL] THEN
+    DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
+     (MP_TAC o SPEC `min (&1) (d / &(dimindex(:M)))`)) THEN
+    REWRITE_TAC[REAL_LT_MIN; REAL_LT_01; GSYM CONJ_ASSOC] THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; DIMINDEX_GE_1; LE_1; REAL_OF_NUM_LT] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `h:real` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `ball(x:real^M,d)` THEN ASM_REWRITE_TAC[] THEN
+      EXPAND_TAC "box" THEN
+      REWRITE_TAC[SUBSET; IN_INTERVAL; IN_BALL] THEN
+      X_GEN_TAC `y:real^M` THEN
+      REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                  VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+      DISCH_TAC THEN MATCH_MP_TAC REAL_LET_TRANS THEN
+      EXISTS_TAC `sum(1..dimindex(:M)) (\i. abs((x - y:real^M)$i))` THEN
+      REWRITE_TAC[NORM_LE_L1] THEN MATCH_MP_TAC SUM_BOUND_LT_GEN THEN
+      REWRITE_TAC[FINITE_NUMSEG; NUMSEG_EMPTY; IN_NUMSEG] THEN
+      SIMP_TAC[NOT_LT; DIMINDEX_GE_1; CARD_NUMSEG_1; VECTOR_SUB_COMPONENT] THEN
+      X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `i:num`)) THEN
+      ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+      UNDISCH_TAC `(x:real^M) IN interval[a,b]` THEN
+      EXPAND_TAC "box" THEN REWRITE_TAC[SUBSET; IN_INTERVAL] THEN
+      DISCH_THEN(fun th -> X_GEN_TAC `y:real^M` THEN MP_TAC th) THEN
+      REWRITE_TAC[IMP_IMP; AND_FORALL_THM] THEN MATCH_MP_TAC MONO_FORALL THEN
+      X_GEN_TAC `i:num` THEN
+      DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+      ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                  VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+      ASM_REAL_ARITH_TAC];
+    ALL_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 `uv:real^M->real` THEN
+  REWRITE_TAC[TAUT `(a ==> b /\ c) <=> (a ==> b) /\ (a ==> c)`] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`a:real^M`; `b:real^M`; `E:real^M->bool`;
+                 `\x:real^M. if x IN E then ball(x,uv x) else g(x)`]
+   COVERING_LEMMA) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[INTERVAL_NE_EMPTY] THEN CONJ_TAC THENL
+     [EXPAND_TAC "E" THEN SET_TAC[]; ALL_TAC] THEN
+    REWRITE_TAC[gauge] THEN GEN_TAC THEN
+    COND_CASES_TAC THEN ASM_SIMP_TAC[OPEN_BALL; CENTRE_IN_BALL] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[gauge]) THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_TAC `D:(real^M->bool)->bool`) THEN
+  EXISTS_TAC `UNIONS D:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `measurable(UNIONS D:real^M->bool) /\
+    measure(UNIONS D) <= measure(interval[a:real^M,b])`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC MEASURE_COUNTABLE_UNIONS_LE_STRONG_GEN THEN
+    ASM_REWRITE_TAC[] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[SUBSET; MEASURABLE_INTERVAL]; ALL_TAC] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+    REWRITE_TAC[MEASURABLE_INTERVAL] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC MEASURABLE_UNIONS THEN
+    ASM_MESON_TAC[SUBSET; MEASURABLE_INTERVAL];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `?d. d SUBSET D /\ FINITE d /\
+        measure(UNIONS D:real^M->bool) <= &2 * measure(UNIONS d)`
+  STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `measure(UNIONS D:real^M->bool) = &0` THENL
+     [EXISTS_TAC `{}:(real^M->bool)->bool` THEN
+      ASM_REWRITE_TAC[FINITE_EMPTY; EMPTY_SUBSET; MEASURE_EMPTY; UNIONS_0] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV;
+      MP_TAC(ISPECL [`D:(real^M->bool)->bool`; `measure(interval[a:real^M,b])`;
+                     `measure(UNIONS D:real^M->bool) / &2`]
+                MEASURE_COUNTABLE_UNIONS_APPROACHABLE) THEN
+      ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+       [ASM_SIMP_TAC[MEASURABLE_MEASURE_POS_LT; REAL_HALF] THEN
+        ASM_SIMP_TAC[GSYM MEASURABLE_MEASURE_EQ_0] THEN
+        CONJ_TAC THENL [ASM_MESON_TAC[MEASURABLE_INTERVAL]; ALL_TAC] THEN
+        REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+        REPEAT(CONJ_TAC THENL
+          [ASM_MESON_TAC[SUBSET; MEASURABLE_INTERVAL; MEASURABLE_UNIONS];
+           ALL_TAC]) THEN
+        ASM SET_TAC[];
+        MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN REAL_ARITH_TAC]];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o el 3 o CONJUNCTS) THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b <=> ~(a ==> ~b)`] THEN
+  SIMP_TAC[IN_INTER] THEN REWRITE_TAC[NOT_IMP; GSYM CONJ_ASSOC] THEN
+  DISCH_THEN(X_CHOOSE_TAC `tag:(real^M->bool)->real^M`) THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+   `D <= &2 * d ==> d <= e / &2 ==> D <= e`)) THEN
+  MP_TAC(ISPEC
+   `IMAGE (\k:real^M->bool. (box2:real->real^M->real^M->bool)
+                            (uv(tag k):real) ((tag k:real^M))) d`
+   AUSTIN_LEMMA) THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE] THEN ANTS_TAC THENL
+   [X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN EXPAND_TAC "box2" THEN
+    EXISTS_TAC `&2 * uv((tag:(real^M->bool)->real^M) k):real` THEN
+    EXISTS_TAC `(tag:(real^M->bool)->real^M) k - uv(tag k) % vec 1:real^M` THEN
+    EXISTS_TAC `(tag:(real^M->bool)->real^M) k + uv(tag k) % vec 1:real^M` THEN
+    REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[EXISTS_SUBSET_IMAGE; real_ge] THEN
+  SIMP_TAC[REAL_LE_LDIV_EQ; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:(real^M->bool)->bool` MP_TAC) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `d <= d' /\ p <= e ==> d' <= p ==> d <= e`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC MEASURE_SUBSET THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC MEASURABLE_UNIONS THEN
+      ASM_MESON_TAC[SUBSET; MEASURABLE_INTERVAL];
+      MATCH_MP_TAC MEASURABLE_UNIONS THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE] THEN
+      EXPAND_TAC "box2" THEN REWRITE_TAC[MEASURABLE_INTERVAL];
+      REWRITE_TAC[SUBSET; IN_UNIONS; EXISTS_IN_IMAGE] THEN
+      X_GEN_TAC `z:real^M` THEN MATCH_MP_TAC MONO_EXISTS THEN
+      X_GEN_TAC `k:real^M->bool` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      UNDISCH_TAC `(z:real^M) IN k` THEN SPEC_TAC(`z:real^M`,`z:real^M`) THEN
+      REWRITE_TAC[GSYM SUBSET] THEN MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `ball(tag k:real^M,uv(tag(k:real^M->bool)))` THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+      EXPAND_TAC "box2" THEN REWRITE_TAC[SUBSET; IN_BALL; IN_INTERVAL] THEN
+      X_GEN_TAC `z:real^M` THEN REWRITE_TAC[dist] THEN DISCH_TAC THEN
+      REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                  VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+
+      SIMP_TAC[REAL_ARITH `x - h <= y /\ y <= x + h <=> abs(x - y) <= h`] THEN
+      REWRITE_TAC[GSYM VECTOR_SUB_COMPONENT] THEN
+      ASM_MESON_TAC[COMPONENT_LE_NORM; REAL_LT_IMP_LE; REAL_LE_TRANS]];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `measure(UNIONS (IMAGE (\k:real^M->bool.
+                            (box:real->real^M->real^M->bool)
+                            (uv(tag k):real) ((tag k:real^M))) p)) *
+              &6 pow dimindex (:M)` THEN
+  CONJ_TAC THENL
+   [SUBGOAL_THEN
+     `!box. IMAGE (\k:real^M->bool. (box:real->real^M->real^M->bool)
+                                    (uv(tag k):real) ((tag k:real^M))) p =
+             IMAGE (\t. box (uv t) t) (IMAGE tag p)`
+     (fun th -> REWRITE_TAC[th])
+    THENL [REWRITE_TAC[GSYM IMAGE_o; o_DEF]; ALL_TAC] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) MEASURE_NEGLIGIBLE_UNIONS_IMAGE o
+        lhand o rand o snd) THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) MEASURE_NEGLIGIBLE_UNIONS_IMAGE o
+        lhand o lhand o rand o snd) THEN
+    MATCH_MP_TAC(TAUT
+     `fp /\ (mb /\ mb') /\ (db /\ db') /\ (m1 /\ m2 ==> p)
+      ==> (fp /\ mb /\ db ==> m1) ==> (fp /\ mb' /\ db' ==> m2) ==> p`) THEN
+    SUBGOAL_THEN `FINITE(p:(real^M->bool)->bool)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[FINITE_SUBSET]; ASM_SIMP_TAC[FINITE_IMAGE]] THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [MAP_EVERY EXPAND_TAC ["box"; "box2"] THEN
+      REWRITE_TAC[MEASURABLE_INTERVAL];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+      REWRITE_TAC[IMP_IMP; RIGHT_IMP_FORALL_THM; AND_FORALL_THM] THEN
+      MAP_EVERY X_GEN_TAC [`k1:real^M->bool`; `k2:real^M->bool`] THEN
+      MATCH_MP_TAC(TAUT
+        `(q ==> r) /\ (p ==> q) ==> (p ==> q) /\ (p ==> r)`) THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] NEGLIGIBLE_SUBSET) THEN
+        MATCH_MP_TAC(SET_RULE
+        `s SUBSET s' /\ t SUBSET t' ==> (s INTER t) SUBSET (s' INTER t')`) THEN
+        CONJ_TAC THEN MAP_EVERY EXPAND_TAC ["box"; "box2"] THEN
+        REWRITE_TAC[SUBSET_INTERVAL] THEN
+        REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                   VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+        MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+        DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+        ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      STRIP_TAC THEN
+      MATCH_MP_TAC(MESON[NEGLIGIBLE_EMPTY] `s = {} ==> negligible s`) THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [pairwise]) THEN
+      REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+      DISCH_THEN(MP_TAC o SPEC `k1:real^M->bool`) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(MP_TAC o SPEC `k2:real^M->bool`) THEN
+      ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+       [EXPAND_TAC "box2" THEN REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+        REWRITE_TAC[SUBSET_INTERVAL] THEN
+        REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                   VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+        REWRITE_TAC[REAL_ARITH `x - e <= x + e <=> &0 <= e`] THEN
+        SUBGOAL_THEN `&0 <= uv((tag:(real^M->bool)->real^M) k1) /\
+                      &0 <= uv((tag:(real^M->bool)->real^M) k2)`
+        STRIP_ASSUME_TAC THENL
+         [ASM_MESON_TAC[SUBSET; REAL_LT_IMP_LE]; ASM_REWRITE_TAC[]] THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [CART_EQ]) THEN
+        MATCH_MP_TAC MONO_NOT THEN REWRITE_TAC[AND_FORALL_THM] THEN
+        MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+        DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+        ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+        SET_TAC[]];
+      ALL_TAC] THEN
+    DISCH_THEN(CONJUNCTS_THEN SUBST1_TAC) THEN
+    REWRITE_TAC[GSYM SUM_RMUL] THEN
+    MATCH_MP_TAC REAL_EQ_IMP_LE THEN MATCH_MP_TAC SUM_EQ THEN
+    X_GEN_TAC `t:real^M` THEN DISCH_THEN(K ALL_TAC) THEN
+    SUBST1_TAC(REAL_ARITH `&6 = &2 * &3`) THEN
+    REWRITE_TAC[REAL_POW_MUL; REAL_MUL_ASSOC] THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN
+    MAP_EVERY EXPAND_TAC ["box"; "box2"] THEN
+    REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+    REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                   VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+    REWRITE_TAC[REAL_ARITH `a <= a + x <=> &0 <= x`;
+                REAL_ARITH `a - x <= a + x <=> &0 <= x`] THEN
+    COND_CASES_TAC THEN REWRITE_TAC[REAL_MUL_LZERO] THEN
+    REWRITE_TAC[REAL_ARITH `(t + h) - (t - h):real = &2 * h`;
+                REAL_ARITH `(t + h) - t:real = h`] THEN
+    REWRITE_TAC[PRODUCT_MUL_NUMSEG; PRODUCT_CONST_NUMSEG] THEN
+    REWRITE_TAC[ADD_SUB; REAL_MUL_AC];
+    ALL_TAC] THEN
+  SIMP_TAC[GSYM REAL_LE_RDIV_EQ; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+  SUBGOAL_THEN `FINITE(p:(real^M->bool)->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_LCANCEL_IMP THEN
+  EXISTS_TAC `mu:real` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC
+   `IMAGE (\k. (tag:(real^M->bool)->real^M) k,
+                (box(uv(tag k):real) (tag k):real^M->bool)) p`) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[tagged_partial_division_of; fine] THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[IN_IMAGE; PAIR_EQ] THEN
+    REWRITE_TAC[MESON[]
+     `(!x j. (?k. (x = tag k /\ j = g k) /\ k IN d) ==> P x j) <=>
+      (!k. k IN d ==> P (tag k) (g k))`] THEN
+    ASM_SIMP_TAC[FINITE_IMAGE] THEN REPEAT CONJ_TAC THENL
+     [X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN REPEAT CONJ_TAC THENL
+       [EXPAND_TAC "box" THEN REWRITE_TAC[IN_INTERVAL] THEN
+        REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                   VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+        GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC(REAL_ARITH
+         `&0 < u ==> x <= x /\ x <= x + u`) THEN ASM_MESON_TAC[SUBSET];
+        ASM_MESON_TAC[SUBSET];
+        EXPAND_TAC "box" THEN MESON_TAC[]];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [pairwise]) THEN
+      REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `k1:real^M->bool` THEN
+      ASM_CASES_TAC `(k1:real^M->bool) IN p` THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `k2:real^M->bool` THEN
+      ASM_CASES_TAC `(k2:real^M->bool) IN p` THEN ASM_REWRITE_TAC[] THEN
+      ASM_CASES_TAC `(tag:(real^M->bool)->real^M) k1 = tag k2` THEN
+      ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+       [EXPAND_TAC "box2" THEN REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+        REWRITE_TAC[SUBSET_INTERVAL] THEN
+        REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                   VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+        REWRITE_TAC[REAL_ARITH `x - e <= x + e <=> &0 <= e`] THEN
+        SUBGOAL_THEN `&0 <= uv((tag:(real^M->bool)->real^M) k1) /\
+                      &0 <= uv((tag:(real^M->bool)->real^M) k2)`
+        STRIP_ASSUME_TAC THENL
+         [ASM_MESON_TAC[SUBSET; REAL_LT_IMP_LE]; ASM_REWRITE_TAC[]] THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [CART_EQ]) THEN
+        MATCH_MP_TAC MONO_NOT THEN REWRITE_TAC[AND_FORALL_THM] THEN
+        MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+        DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+        ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+        MATCH_MP_TAC(SET_RULE
+         `i1 SUBSET s1 /\ i2 SUBSET s2
+          ==> DISJOINT s1 s2 ==> i1 INTER i2 = {}`) THEN
+        CONJ_TAC THEN MATCH_MP_TAC(MESON[INTERIOR_SUBSET; SUBSET_TRANS]
+         `s SUBSET t ==> interior s SUBSET t`) THEN
+        MAP_EVERY EXPAND_TAC ["box"; "box2"] THEN
+        REWRITE_TAC[SUBSET_INTERVAL] THEN
+        REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                   VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+        MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+        DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+        ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC];
+      ASM_MESON_TAC[SUBSET]];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH `e = e' /\ y <= x ==> x < e ==> y <= e'`) THEN
+  CONJ_TAC THENL [REWRITE_TAC[real_div; REAL_MUL_AC]; ALL_TAC] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) MEASURE_UNIONS_LE o lhand o snd) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE] THEN
+    EXPAND_TAC "box" THEN REWRITE_TAC[MEASURABLE_INTERVAL];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH `a' <= e ==> a <= a' ==> a <= e`) THEN
+  ASM_SIMP_TAC[REAL_LE_RDIV_EQ; GSYM SUM_RMUL] THEN
+  MATCH_MP_TAC SUM_LE_INCLUDED THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; RIGHT_EXISTS_AND_THM; FINITE_IMAGE] THEN
+  REWRITE_TAC[NORM_POS_LE; EXISTS_IN_IMAGE] THEN
+  EXISTS_TAC `SND:real^M#(real^M->bool)->real^M->bool` THEN
+  X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN
+  EXISTS_TAC `k:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `&0 < uv(tag(k:real^M->bool):real^M):real` ASSUME_TAC
+  THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `&0 < measure(box(uv(tag(k:real^M->bool):real^M):real) (tag k):real^M->bool)`
+  MP_TAC THENL
+   [EXPAND_TAC "box" THEN
+    REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+    REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                   VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < x ==> a <= a + x`] THEN
+    MATCH_MP_TAC PRODUCT_POS_LT_NUMSEG THEN
+    REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN SIMP_TAC[GSYM REAL_LE_RDIV_EQ] THEN
+  DISCH_THEN(fun th ->
+   GEN_REWRITE_TAC (funpow 2 RAND_CONV)
+    [MATCH_MP(REAL_ARITH `&0 < x ==> x = abs x`) th] THEN
+   ASSUME_TAC th) THEN
+  REWRITE_TAC[real_div; GSYM REAL_ABS_INV] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM NORM_MUL] THEN
+  SUBGOAL_THEN
+   `mu <= dist(i (uv(tag(k:real^M->bool):real^M):real) (tag k):real^N,
+               f(tag k))`
+  MP_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH `x = y ==> m <= x ==> m <= y`) THEN
+  ONCE_REWRITE_TAC[DIST_SYM] THEN EXPAND_TAC "i" THEN
+  REWRITE_TAC[dist; VECTOR_SUB_LDISTRIB] THEN
+  UNDISCH_TAC
+    `&0 < measure(box(uv(tag(k:real^M->bool):real^M):real)
+                (tag k):real^M->bool)` THEN
+  EXPAND_TAC "box" THEN REWRITE_TAC[MEASURE_INTERVAL] THEN
+  SIMP_TAC[VECTOR_MUL_ASSOC; REAL_LT_IMP_NZ; REAL_MUL_LINV] THEN
+  REWRITE_TAC[VECTOR_MUL_LID]);;
+
+let INTEGRABLE_CCONTINUOUS_EXPLICIT_SYMMETRIC = prove
+ (`!f:real^M->real^N.
+    (!a b. f integrable_on interval[a,b])
+    ==> ?k. negligible k /\
+         !x e. ~(x IN k) /\ &0 < e
+               ==> ?d. &0 < d /\
+                       !h. &0 < h /\ h < d
+                ==> norm(inv(content(interval[x - h % vec 1,x + h % vec 1])) %
+                    integral (interval[x - h % vec 1,x + h % vec 1]) f -
+                    f(x)) < e`,
+  REPEAT STRIP_TAC THEN
+  MAP_EVERY ABBREV_TAC
+   [`box = \h x. interval[x - h % vec 1:real^M,x + h % vec 1]`;
+    `i = \h:real x:real^M. inv(content(box h x)) %
+                      integral (box h x) (f:real^M->real^N)`] THEN
+  SUBGOAL_THEN
+   `?k. negligible k /\
+        !x e. ~(x IN k) /\ &0 < e
+              ==> ?d. &0 < d /\
+                      !h. &0 < h /\ h < d
+                          ==> norm(i h x - (f:real^M->real^N) x) < e`
+  MP_TAC THENL
+   [ALL_TAC; MAP_EVERY EXPAND_TAC ["i"; "box"] THEN REWRITE_TAC[]] THEN
+  EXISTS_TAC
+   `{x | ~(!e. &0 < e
+              ==> ?d. &0 < d /\
+                      !h. &0 < h /\ h < d
+                          ==> norm(i h x - (f:real^M->real^N) x) < e)}` THEN
+  SIMP_TAC[IN_ELIM_THM] THEN
+  REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; NOT_EXISTS_THM] THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC
+   `UNIONS {{x | !d. &0 < d
+                     ==> ?h. &0 < h /\ h < d /\
+                             inv(&k + &1) <= dist(i h x,(f:real^M->real^N) x)}
+            |  k IN (:num)}` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[SUBSET; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`y:real^M`; `e:real`] THEN STRIP_TAC THEN
+    REWRITE_TAC[SIMPLE_IMAGE; UNIONS_IMAGE] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_UNIV] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REAL_ARCH_INV]) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:num` THEN DISCH_TAC THEN
+    X_GEN_TAC `d:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `d:real`) THEN
+    ASM_REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; REAL_NOT_LT] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `h:real` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+    ASM_REWRITE_TAC[dist] THEN
+    MATCH_MP_TAC (REWRITE_RULE[IMP_CONJ] REAL_LE_TRANS) THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `inv(&k)` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+    MATCH_MP_TAC REAL_LE_INV2 THEN
+    ASM_REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+    ASM_ARITH_TAC] THEN
+  MATCH_MP_TAC NEGLIGIBLE_COUNTABLE_UNIONS THEN
+  X_GEN_TAC `jj:num` THEN
+  SUBGOAL_THEN `&0 < inv(&jj + &1)` MP_TAC THENL
+   [REWRITE_TAC[REAL_LT_INV_EQ] THEN REAL_ARITH_TAC;
+    SPEC_TAC(`inv(&jj + &1)`,`mu:real`) THEN GEN_TAC THEN DISCH_TAC] THEN
+  ONCE_REWRITE_TAC[NEGLIGIBLE_ON_INTERVALS] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN
+  ASM_CASES_TAC `negligible(interval[a:real^M,b])` THENL
+   [ASM_MESON_TAC[NEGLIGIBLE_SUBSET; INTER_SUBSET]; ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[NEGLIGIBLE_INTERVAL]) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+  REWRITE_TAC[NEGLIGIBLE_OUTER_LE] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `a - vec 1:real^M`; `b + vec 1:real^M`]
+    HENSTOCK_LEMMA) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[INTEGRABLE_ON_SUBINTERVAL; SUBSET_UNIV]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `(e * mu) / &2 / &3 pow (dimindex(:M))`) THEN
+  ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; REAL_LT_MUL;
+               REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^M->bool` STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[SET_RULE `{x | P x} INTER s = {x | x IN s /\ P x}`] THEN
+  ABBREV_TAC
+    `E = {x | x IN interval[a,b] /\
+              !d. &0 < d
+                   ==> ?h. &0 < h /\ h < d /\
+                           mu <= dist(i h x,(f:real^M->real^N) x)}` THEN
+  SUBGOAL_THEN
+   `!x. x IN E
+        ==> ?h. &0 < h /\
+                (box h x:real^M->bool) SUBSET (g x) /\
+                (box h x:real^M->bool) SUBSET interval[a - vec 1,b + vec 1] /\
+                mu <= dist(i h x,(f:real^M->real^N) x)`
+  MP_TAC THENL
+   [X_GEN_TAC `x:real^M` THEN EXPAND_TAC "E" THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [gauge]) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC o SPEC `x:real^M`) THEN
+    REWRITE_TAC[OPEN_CONTAINS_BALL] THEN
+    DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
+     (MP_TAC o SPEC `min (&1) (d / &(dimindex(:M)))`)) THEN
+    REWRITE_TAC[REAL_LT_MIN; REAL_LT_01; GSYM CONJ_ASSOC] THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; DIMINDEX_GE_1; LE_1; REAL_OF_NUM_LT] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `h:real` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `ball(x:real^M,d)` THEN ASM_REWRITE_TAC[] THEN
+      EXPAND_TAC "box" THEN
+      REWRITE_TAC[SUBSET; IN_INTERVAL; IN_BALL] THEN
+      X_GEN_TAC `y:real^M` THEN
+      REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                  VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+      SIMP_TAC[REAL_ARITH `x - h <= y /\ y <= x + h <=> abs(x - y) <= h`] THEN
+      DISCH_TAC THEN MATCH_MP_TAC REAL_LET_TRANS THEN
+      EXISTS_TAC `sum(1..dimindex(:M)) (\i. abs((x - y:real^M)$i))` THEN
+      REWRITE_TAC[NORM_LE_L1] THEN MATCH_MP_TAC SUM_BOUND_LT_GEN THEN
+      REWRITE_TAC[FINITE_NUMSEG; NUMSEG_EMPTY; IN_NUMSEG] THEN
+      SIMP_TAC[NOT_LT; DIMINDEX_GE_1; CARD_NUMSEG_1; VECTOR_SUB_COMPONENT] THEN
+      ASM_MESON_TAC[REAL_LET_TRANS];
+      UNDISCH_TAC `(x:real^M) IN interval[a,b]` THEN
+      EXPAND_TAC "box" THEN REWRITE_TAC[SUBSET; IN_INTERVAL] THEN
+      DISCH_THEN(fun th -> X_GEN_TAC `y:real^M` THEN MP_TAC th) THEN
+      REWRITE_TAC[IMP_IMP; AND_FORALL_THM] THEN MATCH_MP_TAC MONO_FORALL THEN
+      X_GEN_TAC `i:num` THEN
+      DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+      ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                  VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+      ASM_REAL_ARITH_TAC];
+    ALL_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 `uv:real^M->real` THEN
+  REWRITE_TAC[TAUT `(a ==> b /\ c) <=> (a ==> b) /\ (a ==> c)`] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`a:real^M`; `b:real^M`; `E:real^M->bool`;
+                 `\x:real^M. if x IN E then ball(x,uv x) else g(x)`]
+   COVERING_LEMMA) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[INTERVAL_NE_EMPTY] THEN CONJ_TAC THENL
+     [EXPAND_TAC "E" THEN SET_TAC[]; ALL_TAC] THEN
+    REWRITE_TAC[gauge] THEN GEN_TAC THEN
+    COND_CASES_TAC THEN ASM_SIMP_TAC[OPEN_BALL; CENTRE_IN_BALL] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[gauge]) THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_TAC `D:(real^M->bool)->bool`) THEN
+  EXISTS_TAC `UNIONS D:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `measurable(UNIONS D:real^M->bool) /\
+    measure(UNIONS D) <= measure(interval[a:real^M,b])`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC MEASURE_COUNTABLE_UNIONS_LE_STRONG_GEN THEN
+    ASM_REWRITE_TAC[] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[SUBSET; MEASURABLE_INTERVAL]; ALL_TAC] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+    REWRITE_TAC[MEASURABLE_INTERVAL] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC MEASURABLE_UNIONS THEN
+    ASM_MESON_TAC[SUBSET; MEASURABLE_INTERVAL];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `?d. d SUBSET D /\ FINITE d /\
+        measure(UNIONS D:real^M->bool) <= &2 * measure(UNIONS d)`
+  STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `measure(UNIONS D:real^M->bool) = &0` THENL
+     [EXISTS_TAC `{}:(real^M->bool)->bool` THEN
+      ASM_REWRITE_TAC[FINITE_EMPTY; EMPTY_SUBSET; MEASURE_EMPTY; UNIONS_0] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV;
+      MP_TAC(ISPECL [`D:(real^M->bool)->bool`; `measure(interval[a:real^M,b])`;
+                     `measure(UNIONS D:real^M->bool) / &2`]
+                MEASURE_COUNTABLE_UNIONS_APPROACHABLE) THEN
+      ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+       [ASM_SIMP_TAC[MEASURABLE_MEASURE_POS_LT; REAL_HALF] THEN
+        ASM_SIMP_TAC[GSYM MEASURABLE_MEASURE_EQ_0] THEN
+        CONJ_TAC THENL [ASM_MESON_TAC[MEASURABLE_INTERVAL]; ALL_TAC] THEN
+        REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+        REPEAT(CONJ_TAC THENL
+          [ASM_MESON_TAC[SUBSET; MEASURABLE_INTERVAL; MEASURABLE_UNIONS];
+           ALL_TAC]) THEN
+        ASM SET_TAC[];
+        MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN REAL_ARITH_TAC]];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o el 3 o CONJUNCTS) THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b <=> ~(a ==> ~b)`] THEN
+  SIMP_TAC[IN_INTER] THEN REWRITE_TAC[NOT_IMP; GSYM CONJ_ASSOC] THEN
+  DISCH_THEN(X_CHOOSE_TAC `tag:(real^M->bool)->real^M`) THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+   `D <= &2 * d ==> d <= e / &2 ==> D <= e`)) THEN
+  MP_TAC(ISPEC
+   `IMAGE (\k:real^M->bool. (box:real->real^M->real^M->bool)
+                            (uv(tag k):real) ((tag k:real^M))) d`
+   AUSTIN_LEMMA) THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE] THEN ANTS_TAC THENL
+   [X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN EXPAND_TAC "box" THEN
+    EXISTS_TAC `&2 * uv((tag:(real^M->bool)->real^M) k):real` THEN
+    EXISTS_TAC `(tag:(real^M->bool)->real^M) k - uv(tag k) % vec 1:real^M` THEN
+    EXISTS_TAC `(tag:(real^M->bool)->real^M) k + uv(tag k) % vec 1:real^M` THEN
+    REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[EXISTS_SUBSET_IMAGE; real_ge] THEN
+  SIMP_TAC[REAL_LE_LDIV_EQ; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:(real^M->bool)->bool` MP_TAC) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `d <= d' /\ p <= e ==> d' <= p ==> d <= e`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC MEASURE_SUBSET THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC MEASURABLE_UNIONS THEN
+      ASM_MESON_TAC[SUBSET; MEASURABLE_INTERVAL];
+      MATCH_MP_TAC MEASURABLE_UNIONS THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE] THEN
+      EXPAND_TAC "box" THEN REWRITE_TAC[MEASURABLE_INTERVAL];
+      REWRITE_TAC[SUBSET; IN_UNIONS; EXISTS_IN_IMAGE] THEN
+      X_GEN_TAC `z:real^M` THEN MATCH_MP_TAC MONO_EXISTS THEN
+      X_GEN_TAC `k:real^M->bool` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      UNDISCH_TAC `(z:real^M) IN k` THEN SPEC_TAC(`z:real^M`,`z:real^M`) THEN
+      REWRITE_TAC[GSYM SUBSET] THEN MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `ball(tag k:real^M,uv(tag(k:real^M->bool)))` THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+      EXPAND_TAC "box" THEN REWRITE_TAC[SUBSET; IN_BALL; IN_INTERVAL] THEN
+      X_GEN_TAC `z:real^M` THEN REWRITE_TAC[dist] THEN DISCH_TAC THEN
+      REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                  VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+      SIMP_TAC[REAL_ARITH `x - h <= y /\ y <= x + h <=> abs(x - y) <= h`] THEN
+      REWRITE_TAC[GSYM VECTOR_SUB_COMPONENT] THEN
+      ASM_MESON_TAC[COMPONENT_LE_NORM; REAL_LT_IMP_LE; REAL_LE_TRANS]];
+    ALL_TAC] THEN
+  SIMP_TAC[GSYM REAL_LE_RDIV_EQ; REAL_POW_LT; REAL_OF_NUM_LT; ARITH] THEN
+  SUBGOAL_THEN `FINITE(p:(real^M->bool)->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_LCANCEL_IMP THEN
+  EXISTS_TAC `mu:real` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC
+   `IMAGE (\k. (tag:(real^M->bool)->real^M) k,
+                (box(uv(tag k):real) (tag k):real^M->bool)) p`) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[tagged_partial_division_of; fine] THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[IN_IMAGE; PAIR_EQ] THEN
+    REWRITE_TAC[MESON[]
+     `(!x j. (?k. (x = tag k /\ j = g k) /\ k IN d) ==> P x j) <=>
+      (!k. k IN d ==> P (tag k) (g k))`] THEN
+    ASM_SIMP_TAC[FINITE_IMAGE] THEN REPEAT CONJ_TAC THENL
+     [X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN REPEAT CONJ_TAC THENL
+       [EXPAND_TAC "box" THEN REWRITE_TAC[IN_INTERVAL] THEN
+        REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                   VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+        GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC(REAL_ARITH
+         `&0 < u ==> x - u <= x /\ x <= x + u`) THEN ASM_MESON_TAC[SUBSET];
+        ASM_MESON_TAC[SUBSET];
+        EXPAND_TAC "box" THEN MESON_TAC[]];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [pairwise]) THEN
+      REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `k1:real^M->bool` THEN
+      ASM_CASES_TAC `(k1:real^M->bool) IN p` THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `k2:real^M->bool` THEN
+      ASM_CASES_TAC `(k2:real^M->bool) IN p` THEN ASM_REWRITE_TAC[] THEN
+      ASM_CASES_TAC `(tag:(real^M->bool)->real^M) k1 = tag k2` THEN
+      ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+       [EXPAND_TAC "box" THEN REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+        REWRITE_TAC[SUBSET_INTERVAL] THEN
+        REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                   VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+        REWRITE_TAC[REAL_ARITH `x - e <= x + e <=> &0 <= e`] THEN
+        SUBGOAL_THEN `&0 <= uv((tag:(real^M->bool)->real^M) k1) /\
+                      &0 <= uv((tag:(real^M->bool)->real^M) k2)`
+        STRIP_ASSUME_TAC THENL
+         [ASM_MESON_TAC[SUBSET; REAL_LT_IMP_LE]; ASM_REWRITE_TAC[]] THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [CART_EQ]) THEN
+        MATCH_MP_TAC MONO_NOT THEN REWRITE_TAC[AND_FORALL_THM] THEN
+        MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+        DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+        ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+        MATCH_MP_TAC(SET_RULE
+         `i1 SUBSET s1 /\ i2 SUBSET s2
+          ==> DISJOINT s1 s2 ==> i1 INTER i2 = {}`) THEN
+        REWRITE_TAC[INTERIOR_SUBSET]];
+      ASM_MESON_TAC[SUBSET]];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH `e = e' /\ y <= x ==> x < e ==> y <= e'`) THEN
+  CONJ_TAC THENL [REWRITE_TAC[real_div; REAL_MUL_AC]; ALL_TAC] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) MEASURE_UNIONS_LE o lhand o snd) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE] THEN
+    EXPAND_TAC "box" THEN REWRITE_TAC[MEASURABLE_INTERVAL];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH `a' <= e ==> a <= a' ==> a <= e`) THEN
+  ASM_SIMP_TAC[REAL_LE_RDIV_EQ; GSYM SUM_RMUL] THEN
+  MATCH_MP_TAC SUM_LE_INCLUDED THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; RIGHT_EXISTS_AND_THM; FINITE_IMAGE] THEN
+  REWRITE_TAC[NORM_POS_LE; EXISTS_IN_IMAGE] THEN
+  EXISTS_TAC `SND:real^M#(real^M->bool)->real^M->bool` THEN
+  X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN
+  EXISTS_TAC `k:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `&0 < uv(tag(k:real^M->bool):real^M):real` ASSUME_TAC
+  THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `&0 < measure(box(uv(tag(k:real^M->bool):real^M):real) (tag
+k):real^M->bool)`
+  MP_TAC THENL
+   [EXPAND_TAC "box" THEN
+    REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+    REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                   VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < x ==> a - x <= a + x`] THEN
+    MATCH_MP_TAC PRODUCT_POS_LT_NUMSEG THEN
+    REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN SIMP_TAC[GSYM REAL_LE_RDIV_EQ] THEN
+  DISCH_THEN(fun th ->
+   GEN_REWRITE_TAC (funpow 2 RAND_CONV)
+    [MATCH_MP(REAL_ARITH `&0 < x ==> x = abs x`) th] THEN
+   ASSUME_TAC th) THEN
+  REWRITE_TAC[real_div; GSYM REAL_ABS_INV] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM NORM_MUL] THEN
+  SUBGOAL_THEN
+   `mu <= dist(i (uv(tag(k:real^M->bool):real^M):real) (tag k):real^N,
+               f(tag k))`
+  MP_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH `x = y ==> m <= x ==> m <= y`) THEN
+  ONCE_REWRITE_TAC[DIST_SYM] THEN EXPAND_TAC "i" THEN
+  REWRITE_TAC[dist; VECTOR_SUB_LDISTRIB] THEN
+  UNDISCH_TAC
+    `&0 < measure(box(uv(tag(k:real^M->bool):real^M):real)
+                (tag k):real^M->bool)` THEN
+  EXPAND_TAC "box" THEN REWRITE_TAC[MEASURE_INTERVAL] THEN
+  SIMP_TAC[VECTOR_MUL_ASSOC; REAL_LT_IMP_NZ; REAL_MUL_LINV] THEN
+  REWRITE_TAC[VECTOR_MUL_LID]);;
+
+let HAS_VECTOR_DERIVATIVE_INDEFINITE_INTEGRAL = prove
+ (`!f:real^1->real^N a b.
+        f integrable_on interval[a,b]
+        ==> ?k. negligible k /\
+                !x. x IN interval[a,b] DIFF k
+                    ==> ((\x. integral(interval[a,x]) f) has_vector_derivative
+                         f(x)) (at x within interval[a,b])`,
+  SUBGOAL_THEN
+   `!f:real^1->real^N a b.
+        f integrable_on interval[a,b]
+        ==> ?k. negligible k /\
+                !x e. x IN interval[a,b] DIFF k /\ & 0 < e
+                      ==> ?d. &0 < d /\
+                              !x'. x' IN interval[a,b] /\
+                                   drop x < drop x' /\ drop x' < drop x + d
+                                   ==> norm(integral(interval[x,x']) f -
+                                            drop(x' - x) % f x) /
+                                       norm(x' - x) < e`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN MP_TAC(ISPEC
+     `(\x. if x IN interval[a,b] then f x else vec 0):real^1->real^N`
+     INTEGRABLE_CCONTINUOUS_EXPLICIT) THEN
+    REWRITE_TAC[] THEN ANTS_TAC THENL
+     [REPEAT GEN_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+      EXISTS_TAC `(:real^1)` THEN
+      ASM_REWRITE_TAC[INTEGRABLE_RESTRICT_UNIV; SUBSET_UNIV];
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^1->bool` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^1`; `e:real`] THEN
+    REWRITE_TAC[IN_DIFF] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^1`; `e:real`]) THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `y:real^1` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `drop y - drop x`) THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    SUBGOAL_THEN `x + (drop y - drop x) % vec 1 = y` SUBST1_TAC THENL
+     [REWRITE_TAC[GSYM DROP_EQ; DROP_ADD; DROP_CMUL; DROP_VEC] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[CONTENT_1; REAL_LT_IMP_LE] THEN
+    MATCH_MP_TAC(REAL_ARITH `x = y ==> x < e ==> y < e`) THEN
+    ASM_SIMP_TAC[REAL_EQ_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ;
+                 GSYM DROP_EQ; REAL_LT_IMP_NE] THEN
+    SUBGOAL_THEN `norm(y - x) = abs(drop y - drop x)` SUBST1_TAC THENL
+     [REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB]; ALL_TAC] THEN
+    REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] (GSYM NORM_MUL)] THEN
+    REWRITE_TAC[VECTOR_SUB_LDISTRIB; VECTOR_MUL_ASSOC] THEN
+    ASM_SIMP_TAC[REAL_FIELD `x < y ==> (y - x) * inv(y - x) = &1`] THEN
+    AP_TERM_TAC THEN REWRITE_TAC[DROP_SUB; VECTOR_MUL_LID] THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN MATCH_MP_TAC INTEGRAL_EQ THEN
+    X_GEN_TAC `z:real^1` THEN REWRITE_TAC[DIFF_EMPTY] THEN DISCH_TAC THEN
+    COND_CASES_TAC THEN REWRITE_TAC[] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(fun th ->
+    MP_TAC(ISPECL [`f:real^1->real^N`; `a:real^1`; `b:real^1`] th) THEN
+    MP_TAC(ISPECL [`\x. (f:real^1->real^N) (--x)`; `--b:real^1`;
+                   `--a:real^1`] th)) THEN
+  ASM_REWRITE_TAC[INTEGRABLE_REFLECT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k2:real^1->bool`
+    (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "2"))) THEN
+  DISCH_THEN(X_CHOOSE_THEN `k1:real^1->bool`
+    (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "1"))) THEN
+  EXISTS_TAC `k1 UNION IMAGE (--) k2:real^1->bool` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC NEGLIGIBLE_UNION THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC NEGLIGIBLE_LINEAR_IMAGE THEN ASM_REWRITE_TAC[linear] THEN
+    VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  X_GEN_TAC `x:real^1` THEN REWRITE_TAC[IN_DIFF; IN_UNION; DE_MORGAN_THM] THEN
+  REWRITE_TAC[IN_IMAGE; VECTOR_ARITH `x:real^1 = --x' <=> --x = x'`] THEN
+  REWRITE_TAC[UNWIND_THM1] THEN STRIP_TAC THEN
+  REWRITE_TAC[has_vector_derivative; HAS_DERIVATIVE_WITHIN] THEN CONJ_TAC THENL
+   [REWRITE_TAC[linear; DROP_ADD; DROP_CMUL] THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  REMOVE_THEN "2" (MP_TAC o SPECL [`--x:real^1`; `e:real`]) THEN
+  REMOVE_THEN "1" (MP_TAC o SPECL [`x:real^1`; `e:real`]) THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_INTERVAL_REFLECT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "1"))) THEN
+  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 `y:real^1` THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+  REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN STRIP_TAC THEN
+  SUBGOAL_THEN `drop x < drop y \/ drop y < drop x` DISJ_CASES_TAC THENL
+   [ASM_REAL_ARITH_TAC;
+    REMOVE_THEN "1" (MP_TAC o SPEC `y:real^1`) THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB] THEN
+    MATCH_MP_TAC(REAL_ARITH `x = y ==> x < e ==> y < e`) THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN
+    MATCH_MP_TAC(VECTOR_ARITH `c + a:real^N = b ==> a = b - c`) THEN
+    MATCH_MP_TAC INTEGRAL_COMBINE THEN
+    REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+    MATCH_MP_TAC INTEGRABLE_SUBINTERVAL THEN
+    MAP_EVERY EXISTS_TAC [`a:real^1`; `b:real^1`] THEN
+    ASM_REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+    REMOVE_THEN "2" (MP_TAC o SPEC `--y:real^1`) THEN
+    ANTS_TAC THENL [SIMP_TAC[DROP_NEG] THEN ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    SUBGOAL_THEN `norm(--y - --x) = abs(drop y - drop x)` SUBST1_TAC THENL
+     [REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB; DROP_NEG] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC(REAL_ARITH `x = y ==> x < e ==> y < e`) THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[INTEGRAL_REFLECT] THEN
+    REWRITE_TAC[VECTOR_NEG_NEG; DROP_SUB; DROP_NEG] THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+      `x - (--a - --b) % y:real^N = --(--x - (a - b) % y)`] THEN
+    REWRITE_TAC[NORM_NEG] THEN AP_TERM_TAC THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN
+    MATCH_MP_TAC(VECTOR_ARITH `b + a = c ==> --a:real^N = b - c`) THEN
+    MATCH_MP_TAC INTEGRAL_COMBINE THEN
+    REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+    MATCH_MP_TAC INTEGRABLE_SUBINTERVAL THEN
+    MAP_EVERY EXISTS_TAC [`a:real^1`; `b:real^1`] THEN
+    ASM_REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC]);;
+
+let ABSOLUTELY_INTEGRABLE_LEBESGUE_POINTS = prove
+ (`!f:real^M->real^N.
+    (!a b. f absolutely_integrable_on interval[a,b])
+    ==> ?k. negligible k /\
+            !x e. ~(x IN k) /\ &0 < e
+                  ==> ?d. &0 < d /\
+                          !h. &0 < h /\ h < d
+                             ==> norm(inv(content(interval[x - h % vec 1,
+                                                           x + h % vec 1])) %
+                                      integral (interval[x - h % vec 1,
+                                                         x + h % vec 1])
+                                               (\t. lift(norm(f t - f x))))
+                                 < e`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(GEN `r:real^N` (ISPEC `\t. lift(norm((f:real^M->real^N) t - r))`
+        INTEGRABLE_CCONTINUOUS_EXPLICIT_SYMMETRIC)) THEN
+  REWRITE_TAC[] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MONO_FORALL) THEN ANTS_TAC THENL
+   [REPEAT GEN_TAC THEN MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+    MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_NORM THEN
+    MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_SUB THEN
+    ASM_REWRITE_TAC[ABSOLUTELY_INTEGRABLE_CONST];
+    ALL_TAC] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM; FORALL_AND_THM] THEN
+  X_GEN_TAC `k:real^N->real^M->bool` THEN STRIP_TAC THEN
+  EXISTS_TAC
+   `UNIONS (IMAGE (k:real^N->real^M->bool)
+           {x | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i)})` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC NEGLIGIBLE_COUNTABLE_UNIONS_GEN THEN
+    ASM_SIMP_TAC[COUNTABLE_IMAGE; COUNTABLE_RATIONAL_COORDINATES] THEN
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE];
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `e:real`] THEN
+  REWRITE_TAC[UNIONS_IMAGE; IN_ELIM_THM; NOT_EXISTS_THM] THEN
+  REWRITE_TAC[TAUT `~(p /\ q) <=> p ==> ~q`] THEN STRIP_TAC THEN
+  MP_TAC(SET_RULE `(f:real^M->real^N) x IN (:real^N)`) THEN
+  REWRITE_TAC[GSYM CLOSURE_RATIONAL_COORDINATES] THEN
+  REWRITE_TAC[CLOSURE_APPROACHABLE; IN_ELIM_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &3`) THEN
+  ASM_REWRITE_TAC[REAL_ARITH `&0 < e / &3 <=> &0 < e`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real^N` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`r:real^N`; `x:real^M`; `e / &3`]) THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 < e / &3 <=> &0 < e`] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `h:real` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `h:real`) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `norm(y1:real^N) < e / &3 /\ norm(i1 - i2) <= e / &3
+    ==> norm(i1 - y1) < e / &3 ==> norm(i2) < e`) THEN
+  REWRITE_TAC[NORM_LIFT; REAL_ABS_NORM] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[dist; DIST_SYM]; ALL_TAC] THEN
+  REWRITE_TAC[GSYM VECTOR_SUB_LDISTRIB; NORM_MUL] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC
+   `abs(inv(content(interval[x - h % vec 1,x + h % vec 1]))) *
+    drop(integral (interval[x - h % vec 1,x + h % vec 1])
+                  (\x:real^M. lift(e / &3)))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[REAL_ABS_POS] THEN
+    W(MP_TAC o PART_MATCH (rand o rand) INTEGRAL_SUB o rand o lhand o snd) THEN
+    ANTS_TAC THENL
+     [CONJ_TAC THEN MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+      MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_NORM THEN
+      MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_SUB THEN
+      ASM_REWRITE_TAC[ABSOLUTELY_INTEGRABLE_CONST];
+      DISCH_THEN(SUBST1_TAC o SYM) THEN
+      MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+      REWRITE_TAC[INTEGRABLE_CONST] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+        MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_SUB THEN CONJ_TAC THEN
+        MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_NORM THEN
+        MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_SUB THEN
+        ASM_REWRITE_TAC[ABSOLUTELY_INTEGRABLE_CONST];
+        X_GEN_TAC `y:real^M` THEN STRIP_TAC THEN
+        REWRITE_TAC[NORM_LIFT; REAL_ABS_NORM; LIFT_DROP; GSYM LIFT_SUB] THEN
+        ASM_MESON_TAC[NORM_ARITH
+         `dist(r,x) < e / &3
+          ==> abs(norm(y - r:real^N) - norm(y - x)) <= e / &3`]]];
+    ASM_CASES_TAC
+     `content(interval[x - h % vec 1:real^M,x + h % vec 1]) = &0`
+    THENL
+     [ASM_REWRITE_TAC[REAL_INV_0; REAL_ABS_NUM; REAL_MUL_LZERO] THEN
+      ASM_REAL_ARITH_TAC;
+      REWRITE_TAC[REAL_ABS_INV] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+      ASM_SIMP_TAC[GSYM real_div; REAL_LE_LDIV_EQ;
+                   GSYM REAL_ABS_NZ] THEN
+      REWRITE_TAC[INTEGRAL_CONST; DROP_CMUL; LIFT_DROP] THEN
+      SIMP_TAC[real_abs; CONTENT_POS_LE; REAL_MUL_SYM; REAL_LE_REFL]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Measurability of a function on a set (not necessarily itself measurable). *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("measurable_on",(12,"right"));;
+
+let measurable_on = new_definition
+ `(f:real^M->real^N) measurable_on s <=>
+        ?k g. negligible k /\
+              (!n. (g n) continuous_on (:real^M)) /\
+              (!x. ~(x IN k)
+                   ==> ((\n. g n x) --> if x IN s then f(x) else vec 0)
+                       sequentially)`;;
+
+let MEASURABLE_ON_UNIV = prove
+ (`(\x.  if x IN s then f(x) else vec 0) measurable_on (:real^M) <=>
+   f measurable_on s`,
+  REWRITE_TAC[measurable_on; IN_UNIV; ETA_AX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Lebesgue measurability (like "measurable" but allowing infinite measure)  *)
+(* ------------------------------------------------------------------------- *)
+
+let lebesgue_measurable = new_definition
+ `lebesgue_measurable s <=> (indicator s) measurable_on (:real^N)`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Relation between measurability and integrability.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE = prove
+ (`!f:real^M->real^N g s.
+        f measurable_on s /\
+        g integrable_on s /\
+        (!x. x IN s ==> norm(f x) <= drop(g x))
+        ==> f integrable_on s`,
+  let lemma = prove
+   (`!f:real^M->real^N g a b.
+          f measurable_on (:real^M) /\
+          g integrable_on interval[a,b] /\
+          (!x. x IN interval[a,b] ==> norm(f x) <= drop(g x))
+          ==> f integrable_on interval[a,b]`,
+    REPEAT GEN_TAC THEN REWRITE_TAC[measurable_on; IN_UNIV] THEN
+    REWRITE_TAC[LEFT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`k:real^M->bool`; `h:num->real^M->real^N`] THEN
+    STRIP_TAC THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_IMP] INTEGRABLE_SPIKE_SET) THEN
+    EXISTS_TAC `interval[a:real^M,b] DIFF k` THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       NEGLIGIBLE_SUBSET)) THEN SET_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC DOMINATED_CONVERGENCE_INTEGRABLE THEN
+    MAP_EVERY EXISTS_TAC
+     [`h:num->real^M->real^N`; `g:real^M->real^1`] THEN
+    ASM_SIMP_TAC[IN_DIFF] THEN REWRITE_TAC[LEFT_AND_FORALL_THM] THEN
+    X_GEN_TAC `n:num` THEN
+    UNDISCH_TAC `(g:real^M->real^1) integrable_on interval [a,b]` THEN
+    SUBGOAL_THEN
+     `(h:num->real^M->real^N) n absolutely_integrable_on interval[a,b]`
+    MP_TAC THENL
+     [MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_CONTINUOUS THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNIV];
+      REWRITE_TAC[IMP_IMP; absolutely_integrable_on; GSYM CONJ_ASSOC] THEN
+      REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THEN
+      MATCH_MP_TAC INTEGRABLE_SPIKE_SET THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       NEGLIGIBLE_SUBSET)) THEN SET_TAC[]]) in
+  ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC INTEGRABLE_ON_ALL_INTERVALS_INTEGRABLE_BOUND THEN
+  EXISTS_TAC `g:real^M->real^1` THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN
+  MATCH_MP_TAC lemma THEN
+  EXISTS_TAC `(\x. if x IN s then g x else vec 0):real^M->real^1` THEN
+  RULE_ASSUM_TAC(ONCE_REWRITE_RULE[INTEGRABLE_ALT]) THEN
+  ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[NORM_0; DROP_VEC; REAL_POS]);;
+
+let MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_ABSOLUTELY_INTEGRABLE = prove
+ (`!f:real^M->real^N g s.
+        f measurable_on s /\
+        g integrable_on s /\
+        (!x. x IN s ==> norm(f x) <= drop(g x))
+        ==> f absolutely_integrable_on s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `g:real^M->real^1`]
+    ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_BOUND) THEN
+  DISCH_THEN MATCH_MP_TAC THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[NORM_REAL; GSYM drop] THEN
+    ASM_MESON_TAC[REAL_ABS_LE; REAL_LE_TRANS];
+    ASM_MESON_TAC[MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE];
+    MATCH_MP_TAC NONNEGATIVE_ABSOLUTELY_INTEGRABLE THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    ASM_REWRITE_TAC[IMP_IMP; DIMINDEX_1; FORALL_1; GSYM drop] THEN
+    ASM_MESON_TAC[NORM_ARITH `norm(x) <= a ==> &0 <= a`]]);;
+
+let INTEGRAL_DROP_LE_MEASURABLE = prove
+ (`!f g s:real^N->bool.
+        f measurable_on s /\
+        g integrable_on s /\
+        (!x. x IN s ==> &0 <= drop(f x) /\ drop(f x) <= drop(g x))
+        ==> drop(integral s f) <= drop(integral s g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_DROP_LE THEN ASM_SIMP_TAC[] THEN
+  MATCH_MP_TAC MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE THEN
+  EXISTS_TAC `g:real^N->real^1` THEN
+  ASM_SIMP_TAC[NORM_REAL; GSYM drop; real_abs]);;
+
+let INTEGRABLE_SUBINTERVALS_IMP_MEASURABLE = prove
+ (`!f:real^M->real^N.
+        (!a b. f integrable_on interval[a,b]) ==> f measurable_on (:real^M)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[measurable_on; IN_UNIV] THEN
+  MAP_EVERY ABBREV_TAC
+   [`box = \h x. interval[x:real^M,x + h % vec 1]`;
+    `i = \h:real x:real^M. inv(content(box h x)) %
+                      integral (box h x) (f:real^M->real^N)`] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  EXISTS_TAC `(\n x. i (inv(&n + &1)) x):num->real^M->real^N` THEN
+  REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> b /\ a /\ c`] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN CONJ_TAC THENL
+   [REWRITE_TAC[continuous_on; IN_UNIV] THEN
+    MAP_EVERY X_GEN_TAC [`n:num`; `x:real^M`; `e:real`] THEN
+    DISCH_TAC THEN EXPAND_TAC "i" THEN EXPAND_TAC "box" THEN
+    MP_TAC(ISPECL
+     [`f:real^M->real^N`;
+      `x - &2 % vec 1:real^M`;
+      `x + &2 % vec 1:real^M`;
+      `x:real^M`;
+      `x + inv(&n + &1) % vec 1:real^M`;
+      `e * (&1 / (&n + &1)) pow dimindex(:M)`]
+     INDEFINITE_INTEGRAL_CONTINUOUS) THEN
+    ANTS_TAC THENL
+     [ASM_REWRITE_TAC[IN_INTERVAL; VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT;
+        REAL_MUL_RID; VECTOR_MUL_COMPONENT; VEC_COMPONENT] THEN
+      REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+       [SUBGOAL_THEN `&0 <= inv(&n + &1) /\ inv(&n + &1) <= &1` MP_TAC THENL
+         [ALL_TAC; REAL_ARITH_TAC] THEN
+        ASM_REWRITE_TAC[REAL_LE_INV_EQ; REAL_ARITH `&0 <= &n + &1`] THEN
+        MATCH_MP_TAC REAL_INV_LE_1 THEN REAL_ARITH_TAC;
+        MATCH_MP_TAC REAL_LT_MUL THEN ASM_REWRITE_TAC[] THEN
+        MATCH_MP_TAC REAL_POW_LT THEN MATCH_MP_TAC REAL_LT_DIV THEN
+        REAL_ARITH_TAC];
+      DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `min k (&1)` THEN
+      ASM_REWRITE_TAC[REAL_LT_MIN; REAL_LT_01] THEN
+      ASM_REWRITE_TAC[dist] THEN X_GEN_TAC `y:real^M` THEN DISCH_TAC THEN
+      REWRITE_TAC[CONTENT_CLOSED_INTERVAL_CASES] THEN
+      REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                  VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+      REWRITE_TAC[REAL_ARITH `a <= a + x <=> &0 <= x`] THEN
+      REWRITE_TAC[REAL_LE_INV_EQ; REAL_ARITH `&0 <= &n + &1`] THEN
+      REWRITE_TAC[REAL_ARITH `(x + inv y) - x = &1 / y`] THEN
+      REWRITE_TAC[PRODUCT_CONST_NUMSEG; ADD_SUB] THEN
+      REWRITE_TAC[GSYM VECTOR_SUB_LDISTRIB; NORM_MUL] THEN
+      REWRITE_TAC[REAL_ABS_INV; REAL_ABS_POW; REAL_ABS_DIV] THEN
+      REWRITE_TAC[REAL_ABS_NUM; REAL_ARITH `abs(&n + &1) = &n + &1`] THEN
+      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM real_div] THEN
+      ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_LT_DIV; REAL_POW_LT;
+                   REAL_ARITH `&0 < &1 /\ &0 < &n + &1`] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      REWRITE_TAC[VECTOR_ARITH `(y + i) - (x + i):real^N = y - x`;
+                  VECTOR_ARITH `(y - i) - (x - i):real^N = y - x`] THEN
+      ASM_SIMP_TAC[IN_INTERVAL; REAL_LT_IMP_LE] THEN
+      REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; dist;
+                  VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+      REWRITE_TAC[AND_FORALL_THM] THEN X_GEN_TAC `i:num` THEN
+      ASM_CASES_TAC `1 <= i /\ i <= dimindex(:M)` THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `&0 <= i /\ i <= &1 /\ abs(x - y) <= &1
+        ==> (x - &2 <= y /\ y <= x + &2) /\
+            (x - &2 <= y + i /\ y + i <= x + &2)`) THEN
+      ASM_SIMP_TAC[REAL_LE_INV_EQ; REAL_INV_LE_1;
+                   REAL_ARITH `&0 <= &n + &1 /\ &1 <= &n + &1`] THEN
+      REWRITE_TAC[GSYM VECTOR_SUB_COMPONENT] THEN
+      ASM_MESON_TAC[COMPONENT_LE_NORM; REAL_LT_IMP_LE; NORM_SUB;
+                    REAL_LE_TRANS]];
+    FIRST_ASSUM(MP_TAC o MATCH_MP INTEGRABLE_CCONTINUOUS_EXPLICIT) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^M->bool` THEN
+    ASM_CASES_TAC `negligible(k:real^M->bool)` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:real^M` THEN
+    DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+    REWRITE_TAC[LIM_SEQUENTIALLY] 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[LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+    MP_TAC(SPEC `d:real` REAL_ARCH_INV) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+    STRIP_TAC THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+    MAP_EVERY EXPAND_TAC ["i"; "box"] THEN REWRITE_TAC[dist] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[REAL_LT_INV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `inv(&N)` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+    REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+    ASM_ARITH_TAC]);;
+
+let INTEGRABLE_IMP_MEASURABLE = prove
+ (`!f:real^M->real^N s.
+        f integrable_on s ==> f measurable_on s`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[GSYM INTEGRABLE_RESTRICT_UNIV; GSYM MEASURABLE_ON_UNIV] THEN
+  SPEC_TAC(`\x. if x IN s then (f:real^M->real^N) x else vec 0`,
+           `f:real^M->real^N`) THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC INTEGRABLE_SUBINTERVALS_IMP_MEASURABLE THEN
+  REPEAT GEN_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+  EXISTS_TAC `(:real^M)` THEN ASM_REWRITE_TAC[SUBSET_UNIV]);;
+
+let ABSOLUTELY_INTEGRABLE_MEASURABLE = prove
+ (`!f:real^M->real^N s.
+        f absolutely_integrable_on s <=>
+        f measurable_on s /\ (\x. lift(norm(f x))) integrable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[absolutely_integrable_on] THEN
+  MATCH_MP_TAC(TAUT `(a ==> b) /\ (b /\ c ==> a) ==> (a /\ c <=> b /\ c)`) THEN
+  REWRITE_TAC[INTEGRABLE_IMP_MEASURABLE] THEN STRIP_TAC THEN
+  MATCH_MP_TAC MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE THEN
+  EXISTS_TAC `\x. lift(norm((f:real^M->real^N) x))` THEN
+  ASM_REWRITE_TAC[LIFT_DROP; REAL_LE_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Composing continuous and measurable functions; a few variants.            *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_ON_COMPOSE_CONTINUOUS = prove
+ (`!f:real^M->real^N g:real^N->real^P.
+        f measurable_on (:real^M) /\ g continuous_on (:real^N)
+        ==> (g o f) measurable_on (:real^M)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[measurable_on; IN_UNIV] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^M->bool` THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:num->real^M->real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\n x. (g:real^N->real^P) ((h:num->real^M->real^N) n x)` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    ASM_REWRITE_TAC[ETA_AX] THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNIV];
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+     [CONTINUOUS_ON_SEQUENTIALLY]) THEN
+    ASM_SIMP_TAC[o_DEF; IN_UNIV]]);;
+
+let MEASURABLE_ON_COMPOSE_CONTINUOUS_0 = prove
+ (`!f:real^M->real^N g:real^N->real^P s.
+        f measurable_on s /\ g continuous_on (:real^N) /\ g(vec 0) = vec 0
+        ==> (g o f) measurable_on s`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> c ==> a /\ b ==> d`] THEN
+  DISCH_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_COMPOSE_CONTINUOUS) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; o_DEF] THEN ASM_MESON_TAC[]);;
+
+let MEASURABLE_ON_COMPOSE_CONTINUOUS_OPEN_INTERVAL = prove
+ (`!f:real^M->real^N g:real^N->real^P a b.
+        f measurable_on (:real^M) /\
+        (!x. f(x) IN interval(a,b)) /\
+        g continuous_on interval(a,b)
+        ==> (g o f) measurable_on (:real^M)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[measurable_on; IN_UNIV] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^M->bool` THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:num->real^M->real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC
+   `(\n x. (g:real^N->real^P)
+           (lambda i. max ((a:real^N)$i + (b$i - a$i) / (&n + &2))
+                          (min ((h n x:real^N)$i)
+                               ((b:real^N)$i - (b$i - a$i) / (&n + &2)))))
+    :num->real^M->real^P` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [X_GEN_TAC `n:num` THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+     [MP_TAC(ISPECL
+       [`(:real^M)`;
+        `(lambda i. (b:real^N)$i - (b$i - (a:real^N)$i) / (&n + &2)):real^N`]
+         CONTINUOUS_ON_CONST) THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `n:num`) THEN
+      REWRITE_TAC[IMP_IMP] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP CONTINUOUS_ON_MIN) THEN
+      MP_TAC(ISPECL
+       [`(:real^M)`;
+        `(lambda i. (a:real^N)$i + ((b:real^N)$i - a$i) / (&n + &2)):real^N`]
+         CONTINUOUS_ON_CONST) THEN
+      REWRITE_TAC[IMP_IMP] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP CONTINUOUS_ON_MAX) THEN
+      MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+      SIMP_TAC[FUN_EQ_THM; CART_EQ; LAMBDA_BETA];
+      MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+      EXISTS_TAC `interval(a:real^N,b)` THEN
+      ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_UNIV] THEN
+      X_GEN_TAC `x:real^M` THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M` o CONJUNCT1) THEN
+      SIMP_TAC[IN_INTERVAL; LAMBDA_BETA] THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+      MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN DISCH_TAC THEN
+      SUBGOAL_THEN
+        `&0 < ((b:real^N)$i - (a:real^N)$i) / (&n + &2) /\
+         ((b:real^N)$i - (a:real^N)$i) / (&n + &2) <= (b$i - a$i) / &2` MP_TAC
+      THENL [ALL_TAC; REAL_ARITH_TAC] THEN
+      ASM_SIMP_TAC[REAL_LT_RDIV_EQ; REAL_LT_LDIV_EQ;
+                   REAL_ARITH `&0 < &n + &2`] THEN
+      CONJ_TAC THENL [ASM_REAL_ARITH_TAC; REWRITE_TAC[real_div]] THEN
+      MATCH_MP_TAC REAL_LE_LMUL THEN CONJ_TAC THENL
+       [ASM_REAL_ARITH_TAC;
+        MATCH_MP_TAC REAL_LE_INV2 THEN REAL_ARITH_TAC]];
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    REWRITE_TAC[o_DEF] THEN MATCH_MP_TAC LIM_CONTINUOUS_FUNCTION THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; OPEN_INTERVAL];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `((\n. (lambda i. ((a:real^N)$i + ((b:real^N)$i - a$i) / (&n + &2))))
+       --> a) sequentially /\
+      ((\n. (lambda i. ((b:real^N)$i - ((b:real^N)$i - a$i) / (&n + &2))))
+       --> b) sequentially`
+    MP_TAC THENL
+     [ONCE_REWRITE_TAC[LIM_COMPONENTWISE_LIFT] THEN
+      SIMP_TAC[LAMBDA_BETA] THEN
+      CONJ_TAC THEN X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+      REWRITE_TAC[real_sub] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_ADD_RID] THEN
+      REWRITE_TAC[LIFT_ADD] THEN MATCH_MP_TAC LIM_ADD THEN
+      REWRITE_TAC[LIM_CONST; LIFT_NEG; real_div; LIFT_CMUL] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_NEG_0] THEN
+      TRY(MATCH_MP_TAC LIM_NEG) THEN REWRITE_TAC[VECTOR_NEG_0] THEN
+      SUBST1_TAC(VECTOR_ARITH
+       `vec 0:real^1 = ((b:real^N)$j + --((a:real^N)$j)) % vec 0`) THEN
+      MATCH_MP_TAC LIM_CMUL THEN
+      REWRITE_TAC[LIM_SEQUENTIALLY; DIST_0; NORM_LIFT] 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
+      X_GEN_TAC `m:num` THEN DISCH_TAC THEN REWRITE_TAC[REAL_ABS_INV] 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_ADD; REAL_OF_NUM_LT; LE_1;
+                   REAL_OF_NUM_LE; REAL_ABS_NUM] THEN
+      ASM_ARITH_TAC;
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN
+    ASM_REWRITE_TAC[TAUT `a ==> b /\ c ==> d <=> a /\ c ==> b ==> d`] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP LIM_MIN) THEN
+    REWRITE_TAC[GSYM IMP_CONJ_ALT] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP LIM_MAX) THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN BINOP_TAC THEN
+    SIMP_TAC[CART_EQ; LAMBDA_BETA; FUN_EQ_THM] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL]) THEN
+    ASM_MESON_TAC[REAL_ARITH `a < x /\ x < b ==> max a (min x b) = x`]]);;
+
+let MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET = prove
+ (`!f:real^M->real^N g:real^N->real^P s.
+        closed s /\
+        f measurable_on (:real^M) /\
+        (!x. f(x) IN s) /\
+        g continuous_on s
+        ==> (g o f) measurable_on (:real^M)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`g:real^N->real^P`; `(:real^N)`; `s:real^N->bool`]
+    TIETZE_UNBOUNDED) THEN
+  ASM_REWRITE_TAC[SUBTOPOLOGY_UNIV; GSYM CLOSED_IN] THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `h:real^N->real^P` THEN
+  DISCH_TAC THEN SUBGOAL_THEN
+   `(g:real^N->real^P) o (f:real^M->real^N) = h o f` SUBST1_TAC
+  THENL [ASM_SIMP_TAC[FUN_EQ_THM; o_THM]; ALL_TAC] THEN
+  MATCH_MP_TAC MEASURABLE_ON_COMPOSE_CONTINUOUS THEN ASM_REWRITE_TAC[]);;
+
+let MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET_0 = prove
+ (`!f:real^M->real^N g:real^N->real^P s t.
+        closed s /\
+        f measurable_on t /\
+        (!x. f(x) IN s) /\
+        g continuous_on s /\
+        vec 0 IN s /\ g(vec 0) = vec 0
+        ==> (g o f) measurable_on t`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+  MP_TAC(ISPECL [`(\x. if x IN t then f x else vec 0):real^M->real^N`;
+                 `g:real^N->real^P`; `s:real^N->bool`]
+        MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[MEASURABLE_ON_UNIV] THEN ASM_MESON_TAC[];
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    REWRITE_TAC[FUN_EQ_THM; o_THM] THEN ASM_MESON_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic closure properties of measurable functions.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_IMP_MEASURABLE_ON = prove
+ (`!f:real^M->real^N. f continuous_on (:real^M) ==> f measurable_on (:real^M)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[measurable_on; IN_UNIV] THEN
+  EXISTS_TAC `{}:real^M->bool` THEN REWRITE_TAC[NEGLIGIBLE_EMPTY] THEN
+  EXISTS_TAC `\n:num. (f:real^M->real^N)` THEN
+  ASM_REWRITE_TAC[LIM_CONST]);;
+
+let MEASURABLE_ON_CONST = prove
+ (`!k:real^N. (\x. k) measurable_on (:real^M)`,
+  SIMP_TAC[CONTINUOUS_IMP_MEASURABLE_ON; CONTINUOUS_ON_CONST]);;
+
+let MEASURABLE_ON_0 = prove
+ (`!s. (\x. vec 0) measurable_on s`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+  REWRITE_TAC[MEASURABLE_ON_CONST; COND_ID]);;
+
+let MEASURABLE_ON_CMUL = prove
+ (`!c f:real^M->real^N s.
+        f measurable_on s ==> (\x. c % f x) measurable_on s`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC MEASURABLE_ON_COMPOSE_CONTINUOUS_0 THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_RZERO] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN
+  SIMP_TAC[CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID]);;
+
+let MEASURABLE_ON_NEG = prove
+ (`!f:real^M->real^N s.
+     f measurable_on s ==> (\x. --(f x)) measurable_on s`,
+  REWRITE_TAC[VECTOR_ARITH `--x:real^N = --(&1) % x`;
+              MEASURABLE_ON_CMUL]);;
+
+let MEASURABLE_ON_NEG_EQ = prove
+ (`!f:real^M->real^N s. (\x. --(f x)) measurable_on s <=> f measurable_on s`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_NEG) THEN
+  REWRITE_TAC[VECTOR_NEG_NEG; ETA_AX]);;
+
+let MEASURABLE_ON_NORM = prove
+ (`!f:real^M->real^N s.
+        f measurable_on s ==> (\x. lift(norm(f x))) measurable_on s`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o ISPEC `\x:real^N. lift(norm x)` o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] MEASURABLE_ON_COMPOSE_CONTINUOUS_0)) THEN
+  REWRITE_TAC[o_DEF; NORM_0; LIFT_NUM] THEN DISCH_THEN MATCH_MP_TAC THEN
+  REWRITE_TAC[continuous_on; IN_UNIV; DIST_LIFT] THEN
+  GEN_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  EXISTS_TAC `e:real` THEN ASM_REWRITE_TAC[] THEN NORM_ARITH_TAC);;
+
+let MEASURABLE_ON_PASTECART = prove
+ (`!f:real^M->real^N g:real^M->real^P s.
+        f measurable_on s /\ g measurable_on s
+        ==> (\x. pastecart (f x) (g x)) measurable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[measurable_on] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `k1:real^M->bool` MP_TAC)
+   (X_CHOOSE_THEN `k2:real^M->bool` MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `g2:num->real^M->real^P` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `g1:num->real^M->real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `k1 UNION k2:real^M->bool` THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_UNION] THEN
+  EXISTS_TAC `(\n x. pastecart (g1 n x) (g2 n x))
+              :num->real^M->real^(N,P)finite_sum` THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_PASTECART; ETA_AX; IN_UNION; DE_MORGAN_THM] THEN
+  X_GEN_TAC `x:real^M` THEN STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`)) THEN
+  ASM_CASES_TAC `(x:real^M) IN s` THEN
+  REWRITE_TAC[GSYM PASTECART_VEC] THEN ASM_SIMP_TAC[LIM_PASTECART]);;
+
+let MEASURABLE_ON_COMBINE = prove
+ (`!h:real^N->real^P->real^Q f:real^M->real^N g:real^M->real^P s.
+        f measurable_on s /\ g measurable_on s /\
+        (\x. h (fstcart x) (sndcart x)) continuous_on UNIV /\
+        h (vec 0) (vec 0) = vec 0
+        ==> (\x. h (f x) (g x)) measurable_on s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `(\x:real^M. (h:real^N->real^P->real^Q) (f x) (g x)) =
+    (\x. h (fstcart x) (sndcart x)) o (\x. pastecart (f x) (g x))`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[FUN_EQ_THM; FSTCART_PASTECART; SNDCART_PASTECART; o_THM];
+    MATCH_MP_TAC MEASURABLE_ON_COMPOSE_CONTINUOUS_0 THEN
+    ASM_SIMP_TAC[MEASURABLE_ON_PASTECART; FSTCART_VEC; SNDCART_VEC]]);;
+
+let MEASURABLE_ON_ADD = prove
+ (`!f:real^M->real^N g:real^M->real^N s.
+        f measurable_on s /\ g measurable_on s
+        ==> (\x. f x + g x) measurable_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_ON_COMBINE THEN
+  ASM_REWRITE_TAC[VECTOR_ADD_LID] THEN MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
+  CONJ_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN
+  REWRITE_TAC[LINEAR_FSTCART; LINEAR_SNDCART]);;
+
+let MEASURABLE_ON_SUB = prove
+ (`!f:real^M->real^N g:real^M->real^N s.
+        f measurable_on s /\ g measurable_on s
+        ==> (\x. f x - g x) measurable_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_ON_COMBINE THEN
+  ASM_REWRITE_TAC[VECTOR_SUB_RZERO] THEN MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+  CONJ_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN
+  REWRITE_TAC[LINEAR_FSTCART; LINEAR_SNDCART]);;
+
+let MEASURABLE_ON_MAX = prove
+ (`!f:real^M->real^N g:real^M->real^N s.
+      f measurable_on s /\ g measurable_on s
+      ==> (\x. (lambda i. max ((f x)$i) ((g x)$i)):real^N)
+          measurable_on s`,
+  let lemma = REWRITE_RULE[]
+   (ISPEC `(\x y. lambda i. max (x$i) (y$i)):real^N->real^N->real^N`
+          MEASURABLE_ON_COMBINE) in
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC lemma THEN ASM_REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[CONTINUOUS_ON_COMPONENTWISE_LIFT] THEN
+  REWRITE_TAC[REAL_ARITH `max x x = x`; LAMBDA_ETA] THEN
+  SIMP_TAC[continuous_on; LAMBDA_BETA; IN_UNIV; DIST_LIFT] THEN
+  GEN_TAC THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`x:real^(N,N)finite_sum`; `e:real`] THEN
+  DISCH_TAC THEN EXISTS_TAC `e:real` THEN ASM_REWRITE_TAC[dist] THEN
+  X_GEN_TAC `y:real^(N,N)finite_sum` THEN DISCH_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `abs(x - y) < e /\ abs(x' - y') < e
+    ==> abs(max x x' - max y y') < e`) THEN
+  REWRITE_TAC[GSYM VECTOR_SUB_COMPONENT] THEN CONJ_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `norm(x) < e /\ abs(x$i) <= norm x ==> abs(x$i) < e`) THEN
+  ASM_SIMP_TAC[COMPONENT_LE_NORM; GSYM FSTCART_SUB; GSYM SNDCART_SUB] THEN
+  ASM_MESON_TAC[REAL_LET_TRANS; NORM_FSTCART; NORM_SNDCART]);;
+
+let MEASURABLE_ON_MIN = prove
+ (`!f:real^M->real^N g:real^M->real^N s.
+      f measurable_on s /\ g measurable_on s
+      ==> (\x. (lambda i. min ((f x)$i) ((g x)$i)):real^N)
+          measurable_on s`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_NEG)) THEN
+  REWRITE_TAC[GSYM IMP_CONJ_ALT] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_MAX) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_NEG) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN
+  SIMP_TAC[CART_EQ; VECTOR_NEG_COMPONENT; LAMBDA_BETA] THEN REAL_ARITH_TAC);;
+
+let MEASURABLE_ON_DROP_MUL = prove
+ (`!f g:real^M->real^N s.
+      f measurable_on s /\ g measurable_on s
+      ==> (\x. drop(f x) % g x) measurable_on s`,
+  let lemma = REWRITE_RULE[]
+   (ISPEC `\x y. drop x % y :real^N` MEASURABLE_ON_COMBINE) in
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC lemma THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_RZERO] THEN MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+  REWRITE_TAC[o_DEF; ETA_AX; LIFT_DROP] THEN
+  CONJ_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN
+  REWRITE_TAC[LINEAR_FSTCART; LINEAR_SNDCART]);;
+
+let MEASURABLE_ON_LIFT_MUL = prove
+ (`!f g s. (\x. lift(f x)) measurable_on s /\
+           (\x. lift(g x)) measurable_on s
+           ==> (\x. lift(f x * g x)) measurable_on s`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_DROP_MUL) THEN
+  REWRITE_TAC[LIFT_CMUL; LIFT_DROP]);;
+
+let MEASURABLE_ON_VSUM = prove
+ (`!f:A->real^M->real^N t.
+        FINITE t /\ (!i. i IN t ==> (f i) measurable_on s)
+        ==> (\x. vsum t (\i. f i x)) measurable_on s`,
+  GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; MEASURABLE_ON_0; MEASURABLE_ON_ADD; IN_INSERT;
+           ETA_AX]);;
+
+let MEASURABLE_ON_COMPONENTWISE = prove
+ (`!f:real^M->real^N.
+        f measurable_on (:real^M) <=>
+        (!i. 1 <= i /\ i <= dimindex(:N)
+             ==> (\x. lift(f x$i)) measurable_on (:real^M))`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o
+     ISPEC `\x:real^N. lift(x$i)` o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ] MEASURABLE_ON_COMPOSE_CONTINUOUS)) THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT; o_DEF];
+    ALL_TAC] THEN
+  REWRITE_TAC[measurable_on; IN_UNIV] THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`k:num->real^M->bool`; `g:num->num->real^M->real^1`] THEN
+  DISCH_TAC THEN
+  EXISTS_TAC `UNIONS(IMAGE k (1..dimindex(:N))):real^M->bool` THEN
+  EXISTS_TAC `(\n x. lambda i. drop(g i n x)):num->real^M->real^N` THEN
+  REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC NEGLIGIBLE_UNIONS THEN
+    ASM_SIMP_TAC[FINITE_NUMSEG; IN_NUMSEG; FORALL_IN_IMAGE; FINITE_IMAGE];
+    GEN_TAC THEN ONCE_REWRITE_TAC[CONTINUOUS_ON_COMPONENTWISE_LIFT] THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; LIFT_DROP; ETA_AX];
+    X_GEN_TAC `x:real^M` THEN REWRITE_TAC[IN_UNIONS; EXISTS_IN_IMAGE] THEN
+    REWRITE_TAC[NOT_EXISTS_THM; TAUT `~(a /\ b) <=> a ==> ~b`] THEN
+    REWRITE_TAC[IN_NUMSEG] THEN STRIP_TAC THEN
+    ONCE_REWRITE_TAC[LIM_COMPONENTWISE_LIFT] THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; LIFT_DROP; ETA_AX]]);;
+
+let MEASURABLE_ON_SPIKE = prove
+ (`!f:real^M->real^N g s t.
+        negligible s /\ (!x. x IN t DIFF s ==> g x = f x)
+        ==> f measurable_on t ==> g measurable_on t`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[IN_DIFF] THEN STRIP_TAC THEN
+  REWRITE_TAC[measurable_on] THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real^M->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `s UNION k:real^M->bool` THEN
+  ASM_SIMP_TAC[DE_MORGAN_THM; IN_UNION; NEGLIGIBLE_UNION]);;
+
+let MEASURABLE_ON_SPIKE_SET = prove
+ (`!f:real^M->real^N s t.
+        negligible (s DIFF t UNION t DIFF s)
+        ==> f measurable_on s
+            ==> f measurable_on t`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[measurable_on] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `g:num->real^M->real^N` THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real^M->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `k UNION (s DIFF t UNION t DIFF s):real^M->bool` THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_UNION; IN_UNION; DE_MORGAN_THM] THEN
+  X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN
+  MAP_EVERY ASM_CASES_TAC [`(x:real^M) IN s`; `(x:real^M) IN t`] THEN
+  ASM_REWRITE_TAC[] THEN ASM SET_TAC[]);;
+
+let MEASURABLE_ON_RESTRICT = prove
+ (`!f:real^M->real^N s.
+        f measurable_on (:real^M) /\ lebesgue_measurable s
+        ==> (\x. if x IN s then f(x) else vec 0) measurable_on (:real^M)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[lebesgue_measurable; indicator] THEN
+  ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_DROP_MUL) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[DROP_VEC] THEN VECTOR_ARITH_TAC);;
+
+let MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET = prove
+ (`!f s t. s SUBSET t /\ f measurable_on t /\
+           lebesgue_measurable s
+           ==> f measurable_on s`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+  REWRITE_TAC[IN_UNIV] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_RESTRICT) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN ASM SET_TAC[]);;
+
+let MEASURABLE_ON_LIMIT = prove
+ (`!f:num->real^M->real^N g s k.
+        (!n. (f n) measurable_on s) /\
+        negligible k /\
+        (!x. x IN s DIFF k ==> ((\n. f n x) --> g x) sequentially)
+        ==> g measurable_on s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`vec 0:real^N`; `vec 1:real^N`]
+    HOMEOMORPHIC_OPEN_INTERVAL_UNIV) THEN
+  REWRITE_TAC[INTERVAL_NE_EMPTY; VEC_COMPONENT; REAL_LT_01] THEN
+  REWRITE_TAC[homeomorphic; homeomorphism; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`h':real^N->real^N`; `h:real^N->real^N`] THEN
+  REWRITE_TAC[IN_UNIV] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `((h':real^N->real^N) o (h:real^N->real^N) o
+     (\x. if x IN s then g x else vec 0)) measurable_on (:real^M)`
+  MP_TAC THENL
+   [ALL_TAC; ASM_REWRITE_TAC[o_DEF; MEASURABLE_ON_UNIV]] THEN
+  SUBGOAL_THEN `!y:real^N. norm(h y:real^N) <= &(dimindex(:N))`
+  ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `IMAGE h UNIV = s ==> (!z. z IN s ==> P z) ==> !y. P(h y)`)) THEN
+    X_GEN_TAC `y:real^N` THEN REWRITE_TAC[IN_INTERVAL] THEN
+    REWRITE_TAC[VEC_COMPONENT] THEN DISCH_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum(1..dimindex(:N)) (\i. abs((y:real^N)$i))` THEN
+    REWRITE_TAC[NORM_LE_L1] THEN
+    GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM CARD_NUMSEG_1] THEN
+    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
+    MATCH_MP_TAC SUM_BOUND THEN REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < x /\ x < &1 ==> abs(x) <= &1`];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MEASURABLE_ON_COMPOSE_CONTINUOUS_OPEN_INTERVAL THEN
+  MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `vec 1:real^N`] THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC INTEGRABLE_SUBINTERVALS_IMP_MEASURABLE THEN
+    MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_IMP] INTEGRABLE_SPIKE_SET) THEN
+    EXISTS_TAC `interval[a:real^M,b] DIFF k` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC `k:real^M->bool` THEN
+      ASM_REWRITE_TAC[] THEN SET_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC DOMINATED_CONVERGENCE_INTEGRABLE THEN
+    MAP_EVERY EXISTS_TAC
+     [`(\n x. h(if x IN s then f n x else vec 0:real^N)):num->real^M->real^N`;
+      `(\x. vec(dimindex(:N))):real^M->real^1`] THEN
+    REWRITE_TAC[o_DEF; INTEGRABLE_CONST] THEN REPEAT CONJ_TAC THENL
+     [X_GEN_TAC `n:num` THEN MATCH_MP_TAC
+        MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_ABSOLUTELY_INTEGRABLE THEN
+      EXISTS_TAC `(\x. vec(dimindex(:N))):real^M->real^1` THEN
+      ASM_REWRITE_TAC[ETA_AX; INTEGRABLE_CONST] THEN
+      ASM_SIMP_TAC[DROP_VEC] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC(REWRITE_RULE[IMP_IMP] MEASURABLE_ON_SPIKE_SET) THEN
+        EXISTS_TAC `interval[a:real^M,b:real^M]` THEN CONJ_TAC THENL
+         [MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC `k:real^M->bool` THEN
+          ASM_REWRITE_TAC[] THEN SET_TAC[];
+          ALL_TAC] THEN
+        ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+        MATCH_MP_TAC(REWRITE_RULE[indicator; lebesgue_measurable]
+              MEASURABLE_ON_RESTRICT) THEN
+        REWRITE_TAC[MEASURABLE_ON_UNIV] THEN CONJ_TAC THENL
+         [MP_TAC(ISPECL
+           [`(\x. if x IN s then f (n:num) x else vec 0):real^M->real^N`;
+            `h:real^N->real^N`] MEASURABLE_ON_COMPOSE_CONTINUOUS) THEN
+          ASM_REWRITE_TAC[o_DEF] THEN DISCH_THEN MATCH_MP_TAC THEN
+          ASM_REWRITE_TAC[MEASURABLE_ON_UNIV; ETA_AX];
+          MATCH_MP_TAC INTEGRABLE_IMP_MEASURABLE THEN
+          REWRITE_TAC[INTEGRABLE_CONST]];
+        MATCH_MP_TAC(REWRITE_RULE[IMP_IMP] INTEGRABLE_SPIKE_SET) THEN
+        EXISTS_TAC `interval[a:real^M,b:real^M]` THEN
+        REWRITE_TAC[INTEGRABLE_CONST] THEN MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+        EXISTS_TAC `k:real^M->bool` THEN ASM_REWRITE_TAC[] THEN SET_TAC[]];
+      MATCH_MP_TAC(REWRITE_RULE[IMP_IMP] INTEGRABLE_SPIKE_SET) THEN
+      EXISTS_TAC `interval[a:real^M,b:real^M]` THEN
+      REWRITE_TAC[INTEGRABLE_CONST] THEN MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+      EXISTS_TAC `k:real^M->bool` THEN ASM_REWRITE_TAC[] THEN SET_TAC[];
+      ASM_SIMP_TAC[DROP_VEC];
+      X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+      ASM_CASES_TAC `(x:real^M) IN s` THEN ASM_REWRITE_TAC[LIM_CONST] THEN
+      MATCH_MP_TAC LIM_CONTINUOUS_FUNCTION THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; OPEN_UNIV; IN_UNIV];
+        FIRST_X_ASSUM MATCH_MP_TAC THEN ASM SET_TAC[]]];
+    REWRITE_TAC[o_THM] THEN ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Natural closure properties of measurable functions; the intersection      *)
+(* one is actually quite tedious since we end up reinventing cube roots      *)
+(* before they actually get introduced in transcendentals.ml                 *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_ON_EMPTY = prove
+ (`!f:real^M->real^N. f measurable_on {}`,
+  ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+  REWRITE_TAC[NOT_IN_EMPTY; MEASURABLE_ON_CONST]);;
+
+let MEASURABLE_ON_INTER = prove
+ (`!f:real^M->real^N s t.
+        f measurable_on s /\ f measurable_on t
+        ==> f measurable_on (s INTER t)`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+  ONCE_REWRITE_TAC[MEASURABLE_ON_COMPONENTWISE] THEN
+  REWRITE_TAC[AND_FORALL_THM] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q ==> r <=> p /\ p ==> q ==> r`] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_LIFT_MUL) THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_LIFT_MUL) THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+  REWRITE_TAC[VEC_COMPONENT; REAL_ARITH
+   `(if p then x else &0) * (if q then y else &0) =
+    if p /\ q then x * y else &0`] THEN
+  SUBGOAL_THEN `!s. (\x. lift (drop x pow 3)) continuous_on s` ASSUME_TAC THENL
+   [GEN_TAC THEN REWRITE_TAC[REAL_ARITH `(x:real) pow 3 = x * x * x`] THEN
+    REWRITE_TAC[LIFT_CMUL] THEN
+    REPEAT(MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+           ASM_REWRITE_TAC[o_DEF; LIFT_DROP; CONTINUOUS_ON_ID]);
+    ALL_TAC] THEN
+  SUBGOAL_THEN `?r. !x. lift(drop(r x) pow 3) = x` STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM SKOLEM_THM; FORALL_LIFT; GSYM EXISTS_DROP; LIFT_EQ] THEN
+    X_GEN_TAC `x:real` THEN  MP_TAC(ISPECL
+     [`\x. lift (drop x pow 3)`; `lift(--(abs x + &1))`;
+      `lift(abs x + &1)`;`x:real`; `1`] IVT_INCREASING_COMPONENT_1) THEN
+    REWRITE_TAC[GSYM drop; LIFT_DROP; EXISTS_DROP] THEN
+    ANTS_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+    REWRITE_TAC[DIMINDEX_1; LE_REFL] THEN
+    CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `(:real^1)`) THEN
+      ASM_SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; OPEN_UNIV; IN_UNIV];
+      REWRITE_TAC[REAL_BOUNDS_LE; REAL_POW_NEG; ARITH] THEN
+      MATCH_MP_TAC(REAL_ARITH
+      `&0 <= x /\ &0 <= x pow 2 /\ &0 <= x pow 3 ==> x <= (x + &1) pow 3`) THEN
+      SIMP_TAC[REAL_POW_LE; REAL_ABS_POS]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!x.  r(lift(x pow 3)) = lift x` STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM DROP_EQ; LIFT_DROP] THEN GEN_TAC THEN
+    MATCH_MP_TAC REAL_POW_EQ_ODD THEN EXISTS_TAC `3` THEN
+    ASM_REWRITE_TAC[ARITH; GSYM LIFT_EQ; LIFT_DROP];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(r:real^1->real^1) continuous_on (:real^1)` ASSUME_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_INVERSE_OPEN_MAP THEN
+    MAP_EVERY EXISTS_TAC [`\x. lift(drop x pow 3)`; `(:real^1)`] THEN
+    ASM_REWRITE_TAC[LIFT_DROP] THEN
+    MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(fun th -> REPEAT STRIP_TAC THEN SUBST1_TAC(SYM th)) THEN
+    MATCH_MP_TAC INJECTIVE_INTO_1D_IMP_OPEN_MAP THEN
+    ASM_REWRITE_TAC[PATH_CONNECTED_UNIV; LIFT_EQ] THEN
+    SIMP_TAC[REAL_POW_EQ_ODD_EQ; ARITH; DROP_EQ];
+    ONCE_REWRITE_TAC[REAL_ARITH `&0 = &0 pow 3`] THEN
+    REWRITE_TAC[REAL_ARITH `(x * x) * x:real = x pow 3`; IN_INTER] THEN
+    REWRITE_TAC[MESON[] `(if p then x pow 3 else y pow 3) =
+                         (if p then x else y:real) pow 3`] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    DISCH_THEN(MP_TAC o ISPEC `r:real^1->real^1` o
+      MATCH_MP (REWRITE_RULE[IMP_CONJ] MEASURABLE_ON_COMPOSE_CONTINUOUS)) THEN
+    ASM_REWRITE_TAC[o_DEF]]);;
+
+let MEASURABLE_ON_DIFF = prove
+ (`!f:real^M->real^N s t.
+    f measurable_on s /\ f measurable_on t ==> f measurable_on (s DIFF t)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP MEASURABLE_ON_INTER) THEN
+  FIRST_ASSUM(MP_TAC o CONJUNCT1) THEN REWRITE_TAC[IMP_IMP] THEN
+  ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_SUB) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; IN_DIFF; IN_INTER] THEN
+  X_GEN_TAC `x:real^M` THEN
+  MAP_EVERY ASM_CASES_TAC [`(x:real^M) IN s`; `(x:real^M) IN t`] THEN
+  ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC);;
+
+let MEASURABLE_ON_UNION = prove
+ (`!f:real^M->real^N s t.
+    f measurable_on s /\ f measurable_on t ==> f measurable_on (s UNION t)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP MEASURABLE_ON_INTER) THEN
+  POP_ASSUM MP_TAC THEN ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_ADD) THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_SUB) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; IN_UNION; IN_INTER] THEN
+  X_GEN_TAC `x:real^M` THEN
+  MAP_EVERY ASM_CASES_TAC [`(x:real^M) IN s`; `(x:real^M) IN t`] THEN
+  ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC);;
+
+let MEASURABLE_ON_UNIONS = prove
+ (`!f:real^M->real^N k.
+        FINITE k /\ (!s. s IN k ==> f measurable_on s)
+        ==> f measurable_on (UNIONS k)`,
+  GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[UNIONS_0; MEASURABLE_ON_EMPTY; UNIONS_INSERT] THEN
+  SIMP_TAC[FORALL_IN_INSERT; MEASURABLE_ON_UNION]);;
+
+let MEASURABLE_ON_COUNTABLE_UNIONS = prove
+ (`!f:real^M->real^N k.
+        COUNTABLE k /\ (!s. s IN k ==> f measurable_on s)
+        ==> f measurable_on (UNIONS k)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `k:(real^M->bool)->bool = {}` THEN
+  ASM_REWRITE_TAC[UNIONS_0; MEASURABLE_ON_EMPTY] THEN
+  MP_TAC(ISPEC `k:(real^M->bool)->bool` COUNTABLE_AS_IMAGE) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `d:num->real^M->bool` THEN DISCH_THEN SUBST_ALL_TAC THEN
+  ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+  MATCH_MP_TAC MEASURABLE_ON_LIMIT THEN
+  EXISTS_TAC `(\n x. if x IN UNIONS (IMAGE d (0..n)) then f x else vec 0):
+              num->real^M->real^N` THEN
+  EXISTS_TAC `{}:real^M->bool` THEN
+  ASM_REWRITE_TAC[NEGLIGIBLE_EMPTY; MEASURABLE_ON_UNIV] THEN CONJ_TAC THENL
+   [X_GEN_TAC `n:num` THEN MATCH_MP_TAC MEASURABLE_ON_UNIONS THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [FORALL_IN_IMAGE]) THEN
+    SIMP_TAC[FORALL_IN_IMAGE; IN_UNIV; FINITE_IMAGE; FINITE_NUMSEG];
+    X_GEN_TAC `x:real^M` THEN DISCH_THEN(K ALL_TAC) THEN
+    ASM_CASES_TAC `(x:real^M) IN UNIONS (IMAGE d (:num))` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC LIM_EVENTUALLY THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_UNIONS]) THEN
+      REWRITE_TAC[EXISTS_IN_IMAGE; IN_UNIV; EVENTUALLY_SEQUENTIALLY] 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
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [IN_UNIONS]) THEN
+      ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN
+      REWRITE_TAC[EXISTS_IN_IMAGE; IN_NUMSEG; LE_0] THEN ASM_MESON_TAC[];
+      MATCH_MP_TAC ALWAYS_EVENTUALLY THEN ASM SET_TAC[]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Negligibility of a Lipschitz image of a negligible set.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_LOCALLY_LIPSCHITZ_IMAGE = prove
+ (`!f:real^M->real^N s.
+        dimindex(:M) <= dimindex(:N) /\ negligible s /\
+        (!x. x IN s
+             ==> ?t b. open t /\ x IN t /\
+                       !y. y IN s INTER t
+                           ==> norm(f y - f x) <= b * norm(y - x))
+        ==> negligible(IMAGE f s)`,
+  let lemma = prove
+   (`!f:real^M->real^N s B.
+        dimindex(:M) <= dimindex(:N) /\ bounded s /\ negligible s /\ &0 < B /\
+        (!x. x IN s
+             ==> ?t. open t /\ x IN t /\
+                     !y. y IN s INTER t
+                         ==> norm(f y - f x) <= B * norm(y - x))
+        ==> negligible(IMAGE f s)`,
+    REPEAT STRIP_TAC THEN REWRITE_TAC[NEGLIGIBLE_OUTER] THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`s:real^M->bool`;
+                   `e / &2 / (&2 * B * &(dimindex(:M))) pow (dimindex(:N))`]
+      MEASURABLE_OUTER_OPEN) THEN
+    ANTS_TAC THENL
+     [ASM_SIMP_TAC[NEGLIGIBLE_IMP_MEASURABLE] THEN
+      MATCH_MP_TAC REAL_LT_DIV THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+      MATCH_MP_TAC REAL_POW_LT THEN
+      REPEAT(MATCH_MP_TAC REAL_LT_MUL THEN CONJ_TAC) THEN
+      ASM_SIMP_TAC[DIMINDEX_GE_1; REAL_OF_NUM_LT; ARITH; LE_1];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[NEGLIGIBLE_IMP_MEASURABLE; REAL_HALF; MEASURE_EQ_0] THEN
+    REWRITE_TAC[REAL_ADD_LID] THEN
+    DISCH_THEN(X_CHOOSE_THEN `t:real^M->bool` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `!x. ?r. &0 < r /\ r <= &1 / &2 /\
+              (x IN s
+               ==> !y. norm(y - x:real^M) < r
+                       ==> y IN t /\
+                           (y IN s
+                            ==> norm(f y - f x:real^N) <= B * norm(y - x)))`
+    MP_TAC THENL
+     [X_GEN_TAC `x:real^M` THEN ASM_CASES_TAC `(x:real^M) IN s` THEN
+      ASM_REWRITE_TAC[] THENL
+       [ALL_TAC; EXISTS_TAC `&1 / &4` THEN REAL_ARITH_TAC] THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN
+      ASM_REWRITE_TAC[IN_INTER] THEN
+      DISCH_THEN(X_CHOOSE_THEN `u:real^M->bool` STRIP_ASSUME_TAC) THEN
+      MP_TAC(ISPEC `t INTER u :real^M->bool` open_def) THEN
+      ASM_SIMP_TAC[OPEN_INTER; OPEN_BALL] THEN
+      DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[IN_INTER; dist]] THEN
+      DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `min (&1 / &2) r` THEN
+      ASM_REWRITE_TAC[REAL_MIN_LE; REAL_LT_MIN] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_MESON_TAC[];
+      FIRST_X_ASSUM(K ALL_TAC o check (is_forall o concl)) THEN
+      REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM; FORALL_AND_THM] THEN
+      REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP] THEN
+      X_GEN_TAC `r:real^M->real` THEN STRIP_TAC] THEN
+    SUBGOAL_THEN
+     `?c. s SUBSET interval[--(vec c):real^M,vec c] /\
+          ~(interval(--(vec c):real^M,vec c) = {})`
+    STRIP_ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [bounded]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `c:real` STRIP_ASSUME_TAC) THEN
+      MP_TAC(SPEC `abs c + &1` REAL_ARCH_SIMPLE) THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `n:num` THEN
+      DISCH_TAC THEN REWRITE_TAC[SUBSET; INTERVAL_NE_EMPTY] THEN
+      REWRITE_TAC[IN_INTERVAL; VEC_COMPONENT; VECTOR_NEG_COMPONENT] THEN
+      CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+      X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN X_GEN_TAC `i:num` THEN
+      STRIP_TAC THEN REWRITE_TAC[REAL_BOUNDS_LE] THEN W(MP_TAC o
+        PART_MATCH (lhand o rand) COMPONENT_LE_NORM o lhand o snd) THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`)) THEN
+      ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`--(vec c):real^M`; `(vec c):real^M`; `s:real^M->bool`;
+                   `\x:real^M. ball(x,r x)`] COVERING_LEMMA) THEN
+    ASM_REWRITE_TAC[gauge; OPEN_BALL; CENTRE_IN_BALL] THEN
+
+    REWRITE_TAC[VEC_COMPONENT; VECTOR_NEG_COMPONENT] THEN
+    DISCH_THEN(X_CHOOSE_THEN `D:(real^M->bool)->bool` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `!k. k IN D
+          ==> ?u v z. k = interval[u,v] /\ ~(interval(u,v) = {}) /\
+                      z IN s /\ z IN interval[u,v] /\
+                      interval[u:real^M,v] SUBSET ball(z,r z)`
+    MP_TAC THENL
+     [X_GEN_TAC `d:real^M->bool` THEN DISCH_TAC THEN
+      SUBGOAL_THEN `?u v:real^M. d = interval[u,v]` MP_TAC THENL
+       [ASM_MESON_TAC[]; ALL_TAC] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real^M` THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `v:real^M` THEN
+      DISCH_THEN SUBST_ALL_TAC THEN
+      ASM_MESON_TAC[SUBSET; INTERIOR_CLOSED_INTERVAL; IN_INTER];
+      ALL_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 MAP_EVERY X_GEN_TAC
+     [`u:(real^M->bool)->real^M`; `v:(real^M->bool)->real^M`;
+      `z:(real^M->bool)->real^M`] THEN
+    DISCH_THEN(LABEL_TAC "*") THEN EXISTS_TAC
+     `UNIONS(IMAGE (\d:real^M->bool.
+         interval[(f:real^M->real^N)(z d) -
+      (B * &(dimindex(:M)) *
+      ((v(d):real^M)$1 - (u(d):real^M)$1)) % vec 1:real^N,
+                  f(z d) +
+                  (B * &(dimindex(:M)) * (v(d)$1 - u(d)$1)) % vec 1]) D)` THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+      X_GEN_TAC `y:real^M` THEN DISCH_TAC THEN
+      SUBGOAL_THEN `(y:real^M) IN UNIONS D` MP_TAC THENL
+       [ASM_MESON_TAC[SUBSET]; REWRITE_TAC[UNIONS_IMAGE]] THEN
+      REWRITE_TAC[IN_UNIONS; IN_ELIM_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+      X_GEN_TAC `d:real^M->bool` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      SUBGOAL_THEN `(y:real^M) IN ball(z(d:real^M->bool),r(z d))` MP_TAC THENL
+       [ASM_MESON_TAC[SUBSET]; REWRITE_TAC[IN_BALL; dist]] THEN
+      ONCE_REWRITE_TAC[NORM_SUB] THEN DISCH_TAC THEN
+      SUBGOAL_THEN
+       `y IN t /\
+        norm((f:real^M->real^N) y - f(z d)) <= B * norm(y - z(d:real^M->bool))`
+      STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+      REWRITE_TAC[IN_INTERVAL] THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+      REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_SUB_COMPONENT] THEN
+      REWRITE_TAC[REAL_ARITH
+       `z - b <= y /\ y <= z + b <=> abs(y - z) <= b`] THEN
+      REWRITE_TAC[GSYM VECTOR_SUB_COMPONENT] THEN W(MP_TAC o
+        PART_MATCH (lhand o rand) COMPONENT_LE_NORM o lhand o snd) THEN
+      ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+      REWRITE_TAC[VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          REAL_LE_TRANS)) THEN
+      ASM_SIMP_TAC[REAL_LE_LMUL_EQ] 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
+      GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o RAND_CONV)
+       [GSYM CARD_NUMSEG_1] THEN
+      SIMP_TAC[GSYM SUM_CONST; FINITE_NUMSEG] THEN
+      MATCH_MP_TAC SUM_LE_NUMSEG THEN X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `((v:(real^M->bool)->real^M) d - u d)$j` THEN
+      REWRITE_TAC[VECTOR_SUB_COMPONENT] THEN CONJ_TAC THENL
+       [SUBGOAL_THEN `y IN interval[(u:(real^M->bool)->real^M) d,v d] /\
+                      (z d) IN interval[u d,v d]`
+        MP_TAC THENL [ASM_MESON_TAC[]; REWRITE_TAC[IN_INTERVAL]] THEN
+        DISCH_THEN(CONJUNCTS_THEN (MP_TAC o SPEC `j:num`)) THEN
+        ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+        MATCH_MP_TAC REAL_EQ_IMP_LE THEN FIRST_X_ASSUM(MP_TAC o SPECL
+         [`(u:(real^M->bool)->real^M) d`; `(v:(real^M->bool)->real^M) d`]) THEN
+        ASM_MESON_TAC[DIMINDEX_GE_1; LE_REFL]];
+      ALL_TAC] THEN
+    MATCH_MP_TAC(MESON[]
+     `(x <= e / &2 ==> x < e) /\ P /\ x <= e / &2 ==> P /\ x < e`) THEN
+    CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    MATCH_MP_TAC MEASURE_COUNTABLE_UNIONS_LE_GEN THEN
+    ASM_SIMP_TAC[COUNTABLE_IMAGE; FORALL_IN_IMAGE; MEASURABLE_INTERVAL] THEN
+    ONCE_REWRITE_TAC[CONJ_SYM] THEN
+    REWRITE_TAC[FORALL_FINITE_SUBSET_IMAGE] THEN
+    X_GEN_TAC `D':(real^M->bool)->bool` THEN STRIP_TAC THEN
+    W(MP_TAC o PART_MATCH (lhand o rand) SUM_IMAGE_LE o lhand o snd) THEN
+    ASM_SIMP_TAC[MEASURE_POS_LE; MEASURABLE_INTERVAL] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+    REWRITE_TAC[o_DEF] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `(&2 * B * &(dimindex(:M))) pow (dimindex(:N)) *
+                sum D' (\d:real^M->bool. measure d)` THEN
+    SUBGOAL_THEN `FINITE(D':(real^M->bool)->bool)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[GSYM SUM_LMUL] THEN MATCH_MP_TAC SUM_LE THEN
+      ASM_REWRITE_TAC[MEASURE_INTERVAL] THEN X_GEN_TAC `d:real^M->bool` THEN
+      DISCH_TAC THEN REWRITE_TAC[CONTENT_CLOSED_INTERVAL_CASES] THEN
+      REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_SUB_COMPONENT; REAL_ARITH
+       `(a - x <= a + x <=> &0 <= x) /\ (a + x) - (a - x) = &2 * x`] THEN
+      REWRITE_TAC[VECTOR_MUL_COMPONENT; VEC_COMPONENT; REAL_MUL_RID] THEN
+      ASM_SIMP_TAC[REAL_LE_MUL_EQ; REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1] THEN
+      SUBGOAL_THEN `d = interval[u d:real^M,v d]`
+       (fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [th])
+      THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+      REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+      SUBGOAL_THEN
+       `!i. 1 <= i /\ i <= dimindex(:M)
+            ==> ((u:(real^M->bool)->real^M) d)$i <= (v d:real^M)$i`
+      MP_TAC THENL
+       [ASM_MESON_TAC[SUBSET; INTERVAL_NE_EMPTY; REAL_LT_IMP_LE]; ALL_TAC] THEN
+      SIMP_TAC[REAL_SUB_LE; DIMINDEX_GE_1; LE_REFL] THEN DISCH_TAC THEN
+      REWRITE_TAC[PRODUCT_CONST_NUMSEG; REAL_POW_MUL] THEN
+      ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_POW_LT; REAL_OF_NUM_LT; ARITH;
+                   GSYM REAL_MUL_ASSOC; ADD_SUB; DIMINDEX_GE_1; LE_1] THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `((v d:real^M)$1 - ((u:(real^M->bool)->real^M) d)$1)
+                  pow (dimindex(:M))` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC REAL_POW_MONO_INV THEN
+        ASM_SIMP_TAC[REAL_SUB_LE; DIMINDEX_GE_1; LE_REFL] THEN
+        REWRITE_TAC[GSYM VECTOR_SUB_COMPONENT] THEN
+        MATCH_MP_TAC(REAL_ARITH `abs x <= a ==> x <= a`) THEN W(MP_TAC o
+          PART_MATCH (lhand o rand) COMPONENT_LE_NORM o lhand o snd) THEN
+        REWRITE_TAC[DIMINDEX_GE_1; LE_REFL] THEN
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+        MATCH_MP_TAC(NORM_ARITH
+         `!z r. norm(z - u) < r /\ norm(z - v) < r /\ r <= &1 / &2
+                ==> norm(v - u:real^M) <= &1`) THEN
+        MAP_EVERY EXISTS_TAC
+         [`(z:(real^M->bool)->real^M) d`;
+          `r((z:(real^M->bool)->real^M) d):real`] THEN
+        ASM_REWRITE_TAC[GSYM dist; GSYM IN_BALL] THEN
+        SUBGOAL_THEN
+         `(u:(real^M->bool)->real^M) d IN interval[u d,v d] /\
+          (v:(real^M->bool)->real^M) d IN interval[u d,v d]`
+        MP_TAC THENL [ALL_TAC; ASM_MESON_TAC[SUBSET]] THEN
+        ASM_REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_NE_EMPTY];
+        GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM CARD_NUMSEG_1] THEN
+        SIMP_TAC[GSYM PRODUCT_CONST; FINITE_NUMSEG] THEN
+        MATCH_MP_TAC REAL_EQ_IMP_LE THEN MATCH_MP_TAC PRODUCT_EQ_NUMSEG THEN
+        FIRST_X_ASSUM(MP_TAC o SPECL
+         [`(u:(real^M->bool)->real^M) d`; `(v:(real^M->bool)->real^M) d`]) THEN
+        ASM_MESON_TAC[DIMINDEX_GE_1; LE_REFL; SUBSET]];
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `(&2 * B * &(dimindex(:M))) pow dimindex(:N) *
+                  measure(t:real^M->bool)` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC REAL_LE_LMUL THEN
+        CONJ_TAC THENL [MATCH_MP_TAC REAL_LT_IMP_LE; ALL_TAC];
+        MATCH_MP_TAC REAL_LT_IMP_LE THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+        W(MP_TAC o PART_MATCH (rand o rand) REAL_LT_RDIV_EQ o snd)] THEN
+      ASM_SIMP_TAC[REAL_POW_LT; REAL_LT_MUL; LE_1; DIMINDEX_GE_1;
+                   REAL_ARITH `&0 < &2 * B <=> &0 < B`; REAL_OF_NUM_LT] THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `measure(UNIONS D':real^M->bool)` THEN CONJ_TAC THENL
+       [MP_TAC(ISPECL [`D':(real^M->bool)->bool`; `UNIONS D':real^M->bool`]
+          MEASURE_ELEMENTARY) THEN
+        ANTS_TAC THENL
+         [ASM_REWRITE_TAC[division_of] THEN
+          CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[SUBSET]] THEN
+          GEN_TAC THEN DISCH_TAC THEN CONJ_TAC THENL
+           [ASM SET_TAC[]; ASM_MESON_TAC[SUBSET; INTERIOR_EMPTY]];
+          DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC REAL_EQ_IMP_LE THEN
+          MATCH_MP_TAC SUM_EQ THEN ASM_MESON_TAC[MEASURE_INTERVAL; SUBSET]];
+        MATCH_MP_TAC MEASURE_SUBSET THEN CONJ_TAC THENL
+         [MATCH_MP_TAC MEASURABLE_UNIONS THEN
+          ASM_MESON_TAC[MEASURABLE_INTERVAL; SUBSET];
+          ASM_REWRITE_TAC[] THEN MATCH_MP_TAC SUBSET_TRANS THEN
+          EXISTS_TAC `UNIONS D:real^M->bool` THEN
+          ASM_SIMP_TAC[SUBSET_UNIONS] THEN
+          REWRITE_TAC[SUBSET; FORALL_IN_UNIONS] THEN
+          X_GEN_TAC `d:real^M->bool` THEN
+          REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ] THEN
+          DISCH_TAC THEN REWRITE_TAC[GSYM SUBSET] THEN
+          SUBGOAL_THEN `d SUBSET ball(z d:real^M,r(z d))` MP_TAC THENL
+           [ASM_MESON_TAC[];
+            REWRITE_TAC[SUBSET; IN_BALL; dist] THEN
+            ASM_MESON_TAC[NORM_SUB]]]]]) in
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `s = UNIONS
+    {{x | x IN s /\ norm(x:real^M) <= &n /\
+          ?t. open t /\ x IN t /\
+              !y. y IN s INTER t
+                  ==> norm(f y - f x:real^N) <= (&n + &1) * norm(y - x)} |
+     n IN (:num)}`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; UNIONS_GSPEC; IN_ELIM_THM; IN_UNIV] THEN
+    X_GEN_TAC `x:real^M` THEN
+    ASM_CASES_TAC `(x:real^M) IN s` THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `t:real^M->bool` THEN
+    DISCH_THEN(X_CHOOSE_THEN `b:real` STRIP_ASSUME_TAC) THEN
+    MP_TAC(SPEC `max (norm(x:real^M)) b` REAL_ARCH_SIMPLE) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN REWRITE_TAC[REAL_MAX_LE] THEN
+    X_GEN_TAC `n:num` THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `b * norm(y - x:real^M)` THEN ASM_SIMP_TAC[] THEN
+    MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+    ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[IMAGE_UNIONS] THEN
+    MATCH_MP_TAC NEGLIGIBLE_COUNTABLE_UNIONS_GEN THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+    ASM_SIMP_TAC[GSYM IMAGE_o; COUNTABLE_IMAGE; NUM_COUNTABLE] THEN
+    X_GEN_TAC `n:num` THEN REWRITE_TAC[IN_UNIV] THEN
+    MATCH_MP_TAC lemma THEN EXISTS_TAC `&n + &1` THEN ASM_REWRITE_TAC[] THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC BOUNDED_SUBSET THEN
+      EXISTS_TAC `cball(vec 0:real^M,&n)` THEN
+      SIMP_TAC[BOUNDED_CBALL; SUBSET; IN_CBALL_0; IN_ELIM_THM];
+      MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC `s:real^M->bool` THEN
+      ASM_REWRITE_TAC[] THEN SET_TAC[];
+      REAL_ARITH_TAC;
+      REWRITE_TAC[IN_ELIM_THM; IN_INTER] THEN MESON_TAC[]]]);;
+
+let NEGLIGIBLE_LIPSCHITZ_IMAGE_UNIV = prove
+ (`!f:real^N->real^N s B.
+        negligible s /\ (!x y. norm(f x - f y) <= B * norm(x - y))
+        ==> negligible(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC NEGLIGIBLE_LOCALLY_LIPSCHITZ_IMAGE THEN
+  ASM_REWRITE_TAC[LE_REFL] THEN X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+  MAP_EVERY EXISTS_TAC [`interval(a - vec 1:real^N,a + vec 1)`; `B:real`] THEN
+  ASM_REWRITE_TAC[OPEN_INTERVAL; IN_INTERVAL] THEN
+  REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT; VEC_COMPONENT] THEN
+  REAL_ARITH_TAC);;
+
+let NEGLIGIBLE_DIFFERENTIABLE_IMAGE_NEGLIGIBLE = prove
+ (`!f:real^M->real^N s.
+        dimindex(:M) <= dimindex(:N) /\ negligible s /\ f differentiable_on s
+        ==> negligible(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC NEGLIGIBLE_LOCALLY_LIPSCHITZ_IMAGE THEN
+  ASM_REWRITE_TAC[IN_INTER] THEN
+  X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [differentiable_on]) THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN
+  ASM_REWRITE_TAC[differentiable; HAS_DERIVATIVE_WITHIN_ALT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f':real^M->real^N` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `&1`) THEN
+  REWRITE_TAC[REAL_LT_01; REAL_MUL_RID] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP LINEAR_BOUNDED_POS) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `ball(x:real^M,d)` THEN EXISTS_TAC `B + &1` THEN
+  ASM_REWRITE_TAC[OPEN_BALL; CENTRE_IN_BALL] THEN
+  REWRITE_TAC[IN_BALL; dist; REAL_ADD_RDISTRIB] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `!d. norm(y - x - d:real^N) <= z /\ norm(d) <= b
+        ==> norm(y - x) <= b + z`) THEN
+  EXISTS_TAC `(f':real^M->real^N)(y - x)` THEN
+  ASM_MESON_TAC[NORM_SUB]);;
+
+let NEGLIGIBLE_DIFFERENTIABLE_IMAGE_LOWDIM = prove
+ (`!f:real^M->real^N s.
+        dimindex(:M) < dimindex(:N) /\ f differentiable_on s
+        ==> negligible(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP
+   (ARITH_RULE `m < n ==> !x:num. x <= m ==> x <= n`)) THEN
+  SUBGOAL_THEN
+   `(f:real^M->real^N) =
+    (f o ((\x. lambda i. x$i):real^N->real^M)) o
+    ((\x. lambda i. if i <= dimindex(:M) then x$i else &0):real^M->real^N)`
+  SUBST1_TAC THENL
+   [SIMP_TAC[FUN_EQ_THM; o_THM] THEN GEN_TAC THEN AP_TERM_TAC THEN
+    ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA];
+    ONCE_REWRITE_TAC[IMAGE_o] THEN
+    MATCH_MP_TAC NEGLIGIBLE_DIFFERENTIABLE_IMAGE_NEGLIGIBLE THEN
+    REWRITE_TAC[LE_REFL] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+      EXISTS_TAC `{y:real^N | y$(dimindex(:N)) = &0}` THEN
+      SIMP_TAC[NEGLIGIBLE_STANDARD_HYPERPLANE; LE_REFL; DIMINDEX_GE_1] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+      SIMP_TAC[LAMBDA_BETA; LE_REFL; DIMINDEX_GE_1] THEN
+      ASM_REWRITE_TAC[GSYM NOT_LT];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [differentiable_on]) THEN
+      REWRITE_TAC[differentiable_on; FORALL_IN_IMAGE] THEN STRIP_TAC THEN
+      X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+      MATCH_MP_TAC DIFFERENTIABLE_CHAIN_WITHIN THEN CONJ_TAC THENL
+       [MATCH_MP_TAC DIFFERENTIABLE_LINEAR THEN
+        SIMP_TAC[linear; LAMBDA_BETA; CART_EQ;
+                 VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT];
+        FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+        MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN BINOP_TAC THENL
+         [AP_TERM_TAC;
+          MATCH_MP_TAC(SET_RULE
+           `(!x. f(g x) = x) ==> s = IMAGE f (IMAGE g s)`)] THEN
+        ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA]]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Simplest case of Sard's theorem (we don't need continuity of derivative). *)
+(* ------------------------------------------------------------------------- *)
+
+let BABY_SARD = prove
+ (`!f:real^M->real^N f' s.
+        dimindex(:M) <= dimindex(:N) /\
+        (!x. x IN s
+             ==> (f has_derivative f' x) (at x within s) /\
+                 rank(matrix(f' x)) < dimindex(:N))
+        ==> negligible(IMAGE f s)`,
+  let lemma = prove
+   (`!p w e m.
+      dim p < dimindex(:N) /\ &0 <= m /\ &0 <= e
+      ==> ?s. measurable s /\
+              {z:real^N | norm(z - w) <= m /\
+                          ?t. t IN p /\ norm(z - w - t) <= e}
+              SUBSET s /\
+              measure s <= (&2 * e) * (&2 * m) pow (dimindex(:N) - 1)`,
+    REPEAT GEN_TAC THEN GEN_GEOM_ORIGIN_TAC `w:real^N` ["t"; "p"] THEN
+    REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP LOWDIM_SUBSET_HYPERPLANE) THEN
+    REWRITE_TAC[VECTOR_SUB_RZERO; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `a:real^N` THEN GEOM_BASIS_MULTIPLE_TAC 1 `a:real^N` THEN
+    X_GEN_TAC `a:real` THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN
+    ASM_CASES_TAC `a = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+    REPEAT STRIP_TAC THEN
+    EXISTS_TAC
+     `interval[--(lambda i. if i = 1 then e else m):real^N,
+               (lambda i. if i = 1 then e else m)]` THEN
+    REWRITE_TAC[MEASURABLE_INTERVAL] THEN CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_INTERVAL] THEN
+      SIMP_TAC[VECTOR_NEG_COMPONENT; LAMBDA_BETA] THEN
+      X_GEN_TAC `x:real^N` THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
+      REWRITE_TAC[REAL_BOUNDS_LE] THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+      COND_CASES_TAC THENL
+       [ALL_TAC; ASM_MESON_TAC[COMPONENT_LE_NORM; REAL_LE_TRANS]] THEN
+      FIRST_X_ASSUM(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC) THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+      DISCH_THEN(MP_TAC o SPEC `y:real^N`) THEN
+      ASM_SIMP_TAC[SPAN_SUPERSET; IN_ELIM_THM; DOT_BASIS; DOT_LMUL;
+                   DIMINDEX_GE_1; LE_REFL; REAL_ENTIRE; REAL_LT_IMP_NZ] THEN
+      MP_TAC(ISPECL [`x - y:real^N`; `1`] COMPONENT_LE_NORM) THEN
+      REWRITE_TAC[VECTOR_SUB_COMPONENT; ARITH; DIMINDEX_GE_1] THEN
+      ASM_REAL_ARITH_TAC;
+      REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+      SIMP_TAC[VECTOR_NEG_COMPONENT; LAMBDA_BETA] THEN
+      COND_CASES_TAC THEN ASM_SIMP_TAC[REAL_LE_MUL; REAL_POW_LE; REAL_POS] THEN
+      REWRITE_TAC[REAL_ARITH `x - --x = &2 * x`] THEN
+      SIMP_TAC[PRODUCT_CLAUSES_LEFT; DIMINDEX_GE_1] THEN
+      MATCH_MP_TAC REAL_LE_LMUL THEN ASM_SIMP_TAC[REAL_LE_MUL; REAL_POS] THEN
+      SIMP_TAC[ARITH; ARITH_RULE `2 <= n ==> ~(n = 1)`] THEN
+      SIMP_TAC[PRODUCT_CONST_NUMSEG; DIMINDEX_GE_1; REAL_LE_REFL; ARITH_RULE
+       `1 <= n ==> (n + 1) - 2 = n - 1`]]) in
+  let semma = prove
+   (`!f:real^M->real^N f' s B.
+          dimindex(:M) <= dimindex(:N) /\ &0 < B /\ bounded s /\
+          (!x. x IN s ==> (f has_derivative f' x) (at x within s) /\
+                         rank(matrix(f' x)) < dimindex(:N) /\ onorm(f' x) <= B)
+          ==> negligible(IMAGE f s)`,
+    REWRITE_TAC[TAUT `p ==> q /\ r <=> (p ==> q) /\ (p ==> r)`] THEN
+    REWRITE_TAC[FORALL_AND_THM] THEN REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `!x. x IN s ==> linear((f':real^M->real^M->real^N) x)`
+    ASSUME_TAC THENL [ASM_MESON_TAC[has_derivative]; ALL_TAC] THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[NEGLIGIBLE_OUTER_LE] THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `?c. s SUBSET interval(--(vec c):real^M,vec c) /\
+            ~(interval(--(vec c):real^M,vec c) = {})`
+    STRIP_ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [bounded]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `c:real` STRIP_ASSUME_TAC) THEN
+      MP_TAC(SPEC `abs c + &1` REAL_ARCH_SIMPLE) THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `n:num` THEN
+      DISCH_TAC THEN REWRITE_TAC[SUBSET; INTERVAL_NE_EMPTY] THEN
+      REWRITE_TAC[IN_INTERVAL; VEC_COMPONENT; VECTOR_NEG_COMPONENT] THEN
+      CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+      X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN X_GEN_TAC `i:num` THEN
+      STRIP_TAC THEN REWRITE_TAC[REAL_BOUNDS_LT] THEN W(MP_TAC o
+        PART_MATCH (lhand o rand) COMPONENT_LE_NORM o lhand o snd) THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`)) THEN
+      ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INTERVAL_NE_EMPTY]) THEN
+    DISCH_THEN(MP_TAC o SPEC `1`) THEN
+    REWRITE_TAC[VEC_COMPONENT; DIMINDEX_GE_1;
+                LE_REFL; VECTOR_NEG_COMPONENT] THEN
+    REWRITE_TAC[REAL_ARITH `--x < x <=> &0 < &2 * x`; REAL_OF_NUM_MUL] THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN
+     `?d. &0 < d /\ d <= B /\
+          (d * &2) * (&4 * B) pow (dimindex(:N) - 1) <=
+          e / &(2 * c) pow dimindex(:M) / &(dimindex(:M)) pow dimindex(:M)`
+    STRIP_ASSUME_TAC THENL
+     [EXISTS_TAC
+       `min B (e / &(2 * c) pow dimindex(:M) /
+               &(dimindex(:M)) pow dimindex(:M) /
+               (&4 * B) pow (dimindex(:N) - 1) / &2)` THEN
+      ASM_REWRITE_TAC[REAL_LT_MIN; REAL_ARITH `min x y <= x`] THEN
+      CONJ_TAC THENL
+       [REPEAT(MATCH_MP_TAC REAL_LT_DIV THEN CONJ_TAC) THEN
+        ASM_SIMP_TAC[REAL_POW_LT; REAL_OF_NUM_LT; DIMINDEX_GE_1; LE_1;
+                     REAL_ARITH `&0 < &4 * B <=> &0 < B`; ARITH];
+        ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; REAL_POW_LT;
+                     REAL_ARITH `&0 < &4 * B <=> &0 < B`; ARITH] THEN
+        REAL_ARITH_TAC];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!x. ?r. &0 < r /\ r <= &1 / &2 /\
+              (x IN s
+               ==> !y. y IN s /\ norm(y - x) < r
+                       ==> norm((f:real^M->real^N) y - f x - f' x (y - x)) <=
+                           d * norm(y - x))`
+    MP_TAC THENL
+     [X_GEN_TAC `x:real^M` THEN ASM_CASES_TAC `(x:real^M) IN s` THEN
+      ASM_REWRITE_TAC[] THENL
+       [ALL_TAC; EXISTS_TAC `&1 / &4` THEN REAL_ARITH_TAC] THEN
+      UNDISCH_THEN
+       `!x. x IN s ==> ((f:real^M->real^N) has_derivative f' x) (at x within s)`
+       (MP_TAC o REWRITE_RULE[HAS_DERIVATIVE_WITHIN_ALT]) THEN
+      ASM_SIMP_TAC[RIGHT_IMP_FORALL_THM] THEN
+      DISCH_THEN(MP_TAC o SPECL [`x:real^M`; `d:real`]) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `min r (&1 / &2)` THEN
+      ASM_REWRITE_TAC[REAL_LT_MIN; REAL_MIN_LE; REAL_LE_REFL] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_MESON_TAC[];
+      REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM; FORALL_AND_THM] THEN
+      X_GEN_TAC `r:real^M->real` THEN REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
+      REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+      REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+      DISCH_THEN(LABEL_TAC "*")] THEN
+    MP_TAC(ISPECL [`--(vec c):real^M`; `(vec c):real^M`; `s:real^M->bool`;
+                   `\x:real^M. ball(x,r x)`] COVERING_LEMMA) THEN
+    ASM_REWRITE_TAC[gauge; OPEN_BALL; CENTRE_IN_BALL] THEN ANTS_TAC THENL
+     [ASM_MESON_TAC[SUBSET_TRANS; INTERVAL_OPEN_SUBSET_CLOSED]; ALL_TAC] THEN
+    REWRITE_TAC[VEC_COMPONENT; VECTOR_NEG_COMPONENT] THEN
+    DISCH_THEN(X_CHOOSE_THEN `D:(real^M->bool)->bool` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `!k:real^M->bool.
+          k IN D
+          ==> ?t. measurable(t) /\
+                  IMAGE (f:real^M->real^N) (k INTER s) SUBSET t /\
+                  measure t <= e / &(2 * c) pow (dimindex(:M)) * measure(k)`
+    MP_TAC THENL
+     [X_GEN_TAC `k:real^M->bool` THEN DISCH_TAC THEN
+      SUBGOAL_THEN `?u v:real^M. k = interval[u,v]`
+       (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+      THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+      SUBGOAL_THEN `?x:real^M. x IN (s INTER interval[u,v]) /\
+                               interval[u,v] SUBSET ball(x,r x)`
+      MP_TAC THENL [ASM_MESON_TAC[]; REWRITE_TAC[IN_INTER]] THEN
+      DISCH_THEN(X_CHOOSE_THEN `x:real^M` STRIP_ASSUME_TAC) THEN
+      MP_TAC(ISPECL [`IMAGE ((f':real^M->real^M->real^N) x) (:real^M)`;
+               `(f:real^M->real^N) x`;
+                 `d * norm(v - u:real^M)`;
+                 `(&2 * B) * norm(v - u:real^M)`]
+          lemma) THEN
+      ANTS_TAC THENL
+       [ASM_SIMP_TAC[REAL_LE_MUL; REAL_POS; NORM_POS_LE; REAL_LT_IMP_LE] THEN
+        MP_TAC(ISPEC `matrix ((f':real^M->real^M->real^N) x)`
+          RANK_DIM_IM) THEN
+        ASM_SIMP_TAC[MATRIX_WORKS] THEN REWRITE_TAC[ETA_AX] THEN
+        ASM_MESON_TAC[];
+        ALL_TAC] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real^N->bool` THEN
+      REPEAT(MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[]) THEN CONJ_TAC THENL
+       [MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] SUBSET_TRANS) THEN
+        REWRITE_TAC[FORALL_IN_IMAGE; SUBSET; IN_ELIM_THM] THEN
+        X_GEN_TAC `y:real^M` THEN
+        REWRITE_TAC[IN_INTER; EXISTS_IN_IMAGE; IN_UNIV] THEN
+        STRIP_TAC THEN REMOVE_THEN "*"
+         (MP_TAC o SPECL [`x:real^M`; `y:real^M`]) THEN
+        ANTS_TAC THENL
+         [ASM_MESON_TAC[IN_BALL; SUBSET; NORM_SUB; dist]; ALL_TAC] THEN
+        DISCH_THEN(fun th -> CONJ_TAC THEN MP_TAC th) THENL
+         [REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN MATCH_MP_TAC(NORM_ARITH
+           `norm(z) <= B /\ d <= B
+            ==> norm(y - x - z:real^N) <= d
+                ==> norm(y - x) <= &2 * B`) THEN
+          CONJ_TAC THENL
+           [MP_TAC(ISPEC `(f':real^M->real^M->real^N) x` ONORM) THEN
+            ASM_SIMP_TAC[] THEN
+            DISCH_THEN(MP_TAC o SPEC `y - x:real^M` o CONJUNCT1) THEN
+            MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+            MATCH_MP_TAC REAL_LE_MUL2 THEN
+            ASM_SIMP_TAC[ONORM_POS_LE; NORM_POS_LE];
+            MATCH_MP_TAC REAL_LE_MUL2 THEN
+            ASM_SIMP_TAC[REAL_LT_IMP_LE; NORM_POS_LE]];
+          DISCH_THEN(fun th -> EXISTS_TAC `y - x:real^M` THEN MP_TAC th) THEN
+          MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+          ASM_SIMP_TAC[REAL_LE_LMUL_EQ]] THEN
+        MATCH_MP_TAC NORM_LE_COMPONENTWISE THEN
+        REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL])) THEN
+        REWRITE_TAC[IMP_IMP; AND_FORALL_THM] THEN
+        MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+        DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+        ASM_REWRITE_TAC[VECTOR_SUB_COMPONENT] THEN REAL_ARITH_TAC;
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+        REWRITE_TAC[REAL_ARITH `&2 * (&2 * B) * n = (&4 * B) * n`] THEN
+        GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [REAL_POW_MUL] THEN
+        SIMP_TAC[REAL_ARITH `(&2 * d * n) * a * b = d * &2 * a * (n * b)`] THEN
+        REWRITE_TAC[GSYM(CONJUNCT2 real_pow)] THEN
+        SIMP_TAC[DIMINDEX_GE_1; ARITH_RULE `1 <= n ==> SUC(n - 1) = n`] THEN
+        MATCH_MP_TAC REAL_LE_TRANS THEN
+        EXISTS_TAC `e / &(2 * c) pow (dimindex(:M)) /
+                    (&(dimindex(:M)) pow dimindex(:M)) *
+                    norm(v - u:real^M) pow dimindex(:N)` THEN
+        CONJ_TAC THENL
+         [REWRITE_TAC[REAL_MUL_ASSOC] THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+          ASM_SIMP_TAC[NORM_POS_LE; REAL_POW_LE];
+          ALL_TAC] THEN
+        GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [real_div] THEN
+        REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
+        ASM_SIMP_TAC[REAL_LE_DIV; REAL_POW_LE; REAL_LT_IMP_LE] THEN
+        REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] (GSYM real_div)] THEN
+        SIMP_TAC[REAL_LE_LDIV_EQ; REAL_POW_LT; REAL_OF_NUM_LT;
+                 LE_1; DIMINDEX_GE_1] THEN
+        MATCH_MP_TAC REAL_LE_TRANS THEN
+        EXISTS_TAC `norm(v - u:real^M) pow dimindex(:M)` THEN CONJ_TAC THENL
+         [MATCH_MP_TAC REAL_POW_MONO_INV THEN ASM_REWRITE_TAC[NORM_POS_LE] THEN
+          SUBGOAL_THEN `u IN ball(x:real^M,r x) /\ v IN ball(x,r x)` MP_TAC
+          THENL
+           [ASM_MESON_TAC[SUBSET; ENDS_IN_INTERVAL; INTERIOR_EMPTY];
+            REWRITE_TAC[IN_BALL] THEN
+            SUBGOAL_THEN `(r:real^M->real) x <= &1 / &2` MP_TAC THENL
+              [ASM_REWRITE_TAC[]; CONV_TAC NORM_ARITH]];
+          REMOVE_THEN "*" (K ALL_TAC) THEN
+          FIRST_X_ASSUM(MP_TAC o SPECL [`u:real^M`; `v:real^M`]) THEN
+          ASM_REWRITE_TAC[REAL_ARITH `x - --x = &2 * x`] THEN
+          REWRITE_TAC[LEFT_IMP_EXISTS_THM; REAL_OF_NUM_MUL] THEN
+          X_GEN_TAC `p:num` THEN DISCH_TAC THEN
+          MATCH_MP_TAC REAL_LE_TRANS THEN
+          EXISTS_TAC `(sum(1..dimindex(:M)) (\i. abs((v - u:real^M)$i)))
+                      pow (dimindex(:M))` THEN
+          CONJ_TAC THENL
+           [MATCH_MP_TAC REAL_POW_LE2 THEN SIMP_TAC[NORM_POS_LE; NORM_LE_L1];
+            REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+            GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV)
+             [GSYM REAL_SUB_LE] THEN
+            ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LT_DIV; REAL_LT_POW2] THEN
+            ASM_SIMP_TAC[SUM_CONST_NUMSEG; PRODUCT_CONST_NUMSEG;
+                         VECTOR_SUB_COMPONENT; ADD_SUB] THEN
+            REWRITE_TAC[REAL_POW_MUL; REAL_MUL_SYM] THEN
+            MATCH_MP_TAC REAL_EQ_IMP_LE THEN BINOP_TAC THEN REWRITE_TAC[] THEN
+            AP_THM_TAC THEN AP_TERM_TAC THEN SIMP_TAC[REAL_ABS_REFL] THEN
+            ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LT_DIV; REAL_LT_POW2]]]];
+      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 `g:(real^M->bool)->(real^N->bool)` THEN DISCH_TAC THEN
+      EXISTS_TAC `UNIONS (IMAGE (g:(real^M->bool)->(real^N->bool)) D)` THEN
+      CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      MATCH_MP_TAC MEASURE_COUNTABLE_UNIONS_LE_STRONG_GEN THEN
+      ASM_SIMP_TAC[COUNTABLE_IMAGE; FORALL_IN_IMAGE] THEN
+      ONCE_REWRITE_TAC[CONJ_SYM] THEN
+      REWRITE_TAC[FORALL_FINITE_SUBSET_IMAGE] THEN
+      X_GEN_TAC `D':(real^M->bool)->bool` THEN STRIP_TAC THEN
+      W(MP_TAC o PART_MATCH (lhand o rand) MEASURE_UNIONS_LE_IMAGE o
+        lhand o snd) THEN
+      ANTS_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC
+       `sum D' (\k:real^M->bool.
+                  e / &(2 * c) pow (dimindex(:M)) * measure k)` THEN CONJ_TAC
+      THENL [MATCH_MP_TAC SUM_LE THEN ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+      REWRITE_TAC[SUM_LMUL] THEN
+      REWRITE_TAC[REAL_ARITH `e / b * x:real = (e * x) / b`] THEN
+      ASM_SIMP_TAC[REAL_POW_LT; REAL_LE_LDIV_EQ; REAL_LE_LMUL_EQ] THEN
+      MP_TAC(ISPECL [`D':(real^M->bool)->bool`; `UNIONS D':real^M->bool`]
+              MEASURE_ELEMENTARY) THEN
+      ANTS_TAC THENL
+       [ASM_REWRITE_TAC[division_of] THEN
+        CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[SUBSET]] THEN
+        GEN_TAC THEN DISCH_TAC THEN CONJ_TAC THENL
+         [ASM SET_TAC[]; ASM_MESON_TAC[SUBSET; INTERIOR_EMPTY]];
+        ALL_TAC] THEN
+      MATCH_MP_TAC(REAL_ARITH `y = z /\ x <= e ==> x = y ==> z <= e`) THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC SUM_EQ THEN ASM_MESON_TAC[MEASURE_INTERVAL; SUBSET];
+        ALL_TAC] THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `measure(interval[--(vec c):real^M,vec c])` THEN CONJ_TAC THENL
+       [MATCH_MP_TAC MEASURE_SUBSET THEN REWRITE_TAC[MEASURABLE_INTERVAL] THEN
+        CONJ_TAC THENL [MATCH_MP_TAC MEASURABLE_UNIONS; ASM SET_TAC[]] THEN
+        ASM_MESON_TAC[SUBSET; MEASURABLE_INTERVAL];
+        SIMP_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+        REWRITE_TAC[VEC_COMPONENT; VECTOR_NEG_COMPONENT; REAL_ARITH
+         `x - --x = &2 * x /\ (--x <= x <=> &0 <= &2 * x)`] THEN
+        ASM_SIMP_TAC[REAL_OF_NUM_MUL; REAL_LT_IMP_LE] THEN
+        REWRITE_TAC[PRODUCT_CONST_NUMSEG; ADD_SUB; REAL_LE_REFL]]]) in
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `s = UNIONS
+    {{x | x IN s /\ norm(x:real^M) <= &n /\
+          onorm((f':real^M->real^M->real^N) x) <= &n} |
+     n IN (:num)}`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; UNIONS_GSPEC; IN_ELIM_THM; IN_UNIV] THEN
+    X_GEN_TAC `x:real^M` THEN
+    ASM_CASES_TAC `(x:real^M) IN s` THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[GSYM REAL_MAX_LE; REAL_ARCH_SIMPLE];
+    REWRITE_TAC[IMAGE_UNIONS] THEN
+    MATCH_MP_TAC NEGLIGIBLE_COUNTABLE_UNIONS_GEN THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+    ASM_SIMP_TAC[GSYM IMAGE_o; COUNTABLE_IMAGE; NUM_COUNTABLE] THEN
+    X_GEN_TAC `n:num` THEN REWRITE_TAC[IN_UNIV] THEN
+    MATCH_MP_TAC semma THEN
+    MAP_EVERY EXISTS_TAC [`f':real^M->real^M->real^N`; `&n + &1:real`] THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC BOUNDED_SUBSET THEN
+      EXISTS_TAC `cball(vec 0:real^M,&n)` THEN
+      SIMP_TAC[BOUNDED_CBALL; SUBSET; IN_CBALL_0; IN_ELIM_THM];
+      X_GEN_TAC `x:real^M` THEN REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN
+      ASM_SIMP_TAC[REAL_ARITH `x <= n ==> x <= n + &1`] THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+      REPEAT STRIP_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       HAS_DERIVATIVE_WITHIN_SUBSET)) THEN SET_TAC[]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Also negligibility of BV low-dimensional image.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_IMAGE_BOUNDED_VARIATION_INTERVAL = prove
+ (`!f:real^1->real^N a b.
+        2 <= dimindex(:N) /\ f has_bounded_variation_on interval[a,b]
+        ==> negligible(IMAGE f (interval[a,b]))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        HAS_BOUNDED_VECTOR_VARIATION_RIGHT_LIMIT)) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        HAS_BOUNDED_VECTOR_VARIATION_LEFT_LIMIT)) THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `l:real^1->real^N` THEN DISCH_TAC THEN
+  X_GEN_TAC `r:real^1->real^N` THEN DISCH_TAC THEN
+  REWRITE_TAC[NEGLIGIBLE_OUTER_LE] THEN X_GEN_TAC `ee:real` THEN DISCH_TAC THEN
+  ABBREV_TAC
+   `e = min (&1) (ee /
+     (&2 pow (dimindex(:N)) *
+      vector_variation (interval[a,b]) (f:real^1->real^N) + &1))` THEN
+  SUBGOAL_THEN `&0 < e` ASSUME_TAC THENL
+   [EXPAND_TAC "e" THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < x ==> &0 < min (&1) x`) THEN
+    MATCH_MP_TAC REAL_LT_DIV THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= x ==> &0 < x + &1`) THEN
+    MATCH_MP_TAC REAL_LE_MUL THEN ASM_SIMP_TAC[VECTOR_VARIATION_POS_LE] THEN
+    MATCH_MP_TAC REAL_POW_LE THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!c. ?d. &0 < d /\
+            (c IN interval[a,b]
+             ==> (!x. x IN interval[a,c] /\ ~(x = c) /\ dist(x,c) < d
+                      ==> dist((f:real^1->real^N) x,l c) < e) /\
+                 (!x. x IN interval[c,b] /\ ~(x = c) /\ dist(x,c) < d
+                      ==> dist(f x,r c) < e))`
+  MP_TAC THENL
+   [X_GEN_TAC `c:real^1` THEN ASM_CASES_TAC `(c:real^1) IN interval[a,b]` THENL
+     [ALL_TAC; EXISTS_TAC `&1` THEN ASM_REWRITE_TAC[REAL_LT_01]] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `c:real^1`)) THEN
+    ASM_REWRITE_TAC[LIM_WITHIN; IMP_IMP; AND_FORALL_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[GSYM DIST_NZ] THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC)
+     (X_CHOOSE_THEN `d2:real` STRIP_ASSUME_TAC)) THEN
+    EXISTS_TAC `min d1 d2:real` THEN ASM_SIMP_TAC[REAL_LT_MIN];
+    REWRITE_TAC[SKOLEM_THM; FORALL_AND_THM; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `d:real^1->real` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "*"))] THEN
+  MP_TAC(ISPECL [`\x:real^1. ball(x,d x)`; `a:real^1`; `b:real^1`]
+    FINE_DIVISION_EXISTS) THEN
+  ASM_REWRITE_TAC[fine; gauge; OPEN_BALL; CENTRE_IN_BALL] THEN
+  DISCH_THEN(X_CHOOSE_THEN
+   `p:(real^1#(real^1->bool))->bool` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP TAGGED_DIVISION_OF_FINITE) THEN
+  EXISTS_TAC
+   `UNIONS(IMAGE (\(c,k).
+       (f c) INSERT
+       (cball((l:real^1->real^N) c,
+              min e (vector_variation (interval[interval_lowerbound k,c])
+                                      (f:real^1->real^N))) UNION
+        cball((r:real^1->real^N) c,
+              min e (vector_variation (interval[c,interval_upperbound k])
+                                      (f:real^1->real^N))))) p)` THEN
+  REPEAT CONJ_TAC THENL
+   [FIRST_ASSUM(SUBST1_TAC o MATCH_MP TAGGED_DIVISION_UNION_IMAGE_SND) THEN
+    REWRITE_TAC[IMAGE_UNIONS; GSYM IMAGE_o] THEN
+    MATCH_MP_TAC UNIONS_MONO_IMAGE THEN
+    REWRITE_TAC[FORALL_PAIR_THM; o_THM] THEN
+    MAP_EVERY X_GEN_TAC [`c:real^1`; `k:real^1->bool`] THEN DISCH_TAC THEN
+    SUBGOAL_THEN `?u v:real^1. k = interval[u,v]`
+     (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+    THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+    SUBGOAL_THEN `drop u <= drop v` ASSUME_TAC THENL
+     [ASM_MESON_TAC[TAGGED_DIVISION_OF; INTERVAL_NE_EMPTY_1; NOT_IN_EMPTY];
+      ASM_SIMP_TAC[INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1]] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `x:real^1` THEN REWRITE_TAC[IN_INTERVAL_1] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`c:real^1`; `interval[u:real^1,v]`]) THEN
+    ASM_REWRITE_TAC[SUBSET; IN_INTERVAL_1; IN_CBALL] THEN DISCH_TAC THEN
+    REWRITE_TAC[IN_INSERT; IN_UNION] THEN ASM_CASES_TAC `x:real^1 = c` THEN
+    ASM_REWRITE_TAC[] THEN DISJ2_TAC THEN
+    SIMP_TAC[IN_CBALL; REAL_LE_MIN] THEN ASM_CASES_TAC `drop x <= drop c` THENL
+     [DISJ1_TAC THEN CONJ_TAC THENL
+       [ONCE_REWRITE_TAC[DIST_SYM] THEN MATCH_MP_TAC REAL_LT_IMP_LE THEN
+        REMOVE_THEN "*" (MP_TAC o SPEC `c:real^1`) THEN ANTS_TAC THENL
+         [ASM_MESON_TAC[TAGGED_DIVISION_OF; SUBSET]; ALL_TAC] THEN
+        DISCH_THEN(MATCH_MP_TAC o CONJUNCT1) THEN ASM_REWRITE_TAC[] THEN
+        ASM_SIMP_TAC[GSYM(ONCE_REWRITE_RULE[DIST_SYM] IN_BALL)] THEN
+        ASM_MESON_TAC[IN_INTERVAL_1; SUBSET; TAGGED_DIVISION_OF];
+        ALL_TAC] THEN
+      SUBGOAL_THEN `drop a <= drop u /\ drop x < drop c /\
+                    drop c <= drop v /\ drop v <= drop b`
+      STRIP_ASSUME_TAC THENL
+       [ASM_REWRITE_TAC[REAL_LT_LE; DROP_EQ] THEN
+        ASM_MESON_TAC[IN_INTERVAL_1; SUBSET; TAGGED_DIVISION_OF;
+                      REAL_LE_TOTAL];
+        ALL_TAC] THEN
+      REWRITE_TAC[ONCE_REWRITE_RULE[NORM_SUB] dist] THEN
+      MATCH_MP_TAC
+       (REWRITE_RULE[LIFT_DROP; FORALL_LIFT]
+          (ISPEC `at c within interval [u:real^1,c]` LIM_DROP_UBOUND)) THEN
+      EXISTS_TAC `\y:real^1. lift(norm(f x - f y:real^N))` THEN
+      REWRITE_TAC[TRIVIAL_LIMIT_WITHIN; LIFT_DROP] THEN REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC LIM_NORM THEN MATCH_MP_TAC LIM_SUB THEN
+        ASM_SIMP_TAC[IN_INTERVAL_1; LIM_CONST] THEN
+        MATCH_MP_TAC LIM_WITHIN_SUBSET THEN
+        EXISTS_TAC `interval[a:real^1,c]` THEN CONJ_TAC THENL
+         [FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+          ASM_REAL_ARITH_TAC;
+          REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC];
+        W(MP_TAC o PART_MATCH (lhs o rand) LIMPT_OF_CONVEX o snd) THEN
+        ANTS_TAC THENL
+         [SIMP_TAC[CONVEX_INTERVAL; ENDS_IN_INTERVAL;
+                   INTERVAL_NE_EMPTY_1] THEN
+          ASM_REAL_ARITH_TAC;
+          DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC(SET_RULE
+           `(?y. ~(y = x) /\ y IN s) ==> ~(s = {x})`) THEN
+          EXISTS_TAC `u:real^1` THEN
+          REWRITE_TAC[IN_INTERVAL_1; GSYM DROP_EQ] THEN ASM_REAL_ARITH_TAC];
+        REWRITE_TAC[EVENTUALLY_WITHIN] THEN EXISTS_TAC `&1` THEN
+        REWRITE_TAC[REAL_LT_01] THEN X_GEN_TAC `y:real^1` THEN
+        REWRITE_TAC[IN_INTERVAL_1] THEN STRIP_TAC THEN
+        MATCH_MP_TAC VECTOR_VARIATION_GE_NORM_FUNCTION THEN CONJ_TAC THENL
+         [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            HAS_BOUNDED_VARIATION_ON_SUBSET)) THEN
+          REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+          MATCH_MP_TAC(CONJUNCT1(SPEC_ALL
+           (REWRITE_RULE[CONVEX_CONTAINS_SEGMENT] CONVEX_INTERVAL))) THEN
+          REWRITE_TAC[IN_INTERVAL_1] THEN ASM_REAL_ARITH_TAC]];
+      DISJ2_TAC THEN CONJ_TAC THENL
+       [ONCE_REWRITE_TAC[DIST_SYM] THEN MATCH_MP_TAC REAL_LT_IMP_LE THEN
+        REMOVE_THEN "*" (MP_TAC o SPEC `c:real^1`) THEN ANTS_TAC THENL
+         [ASM_MESON_TAC[TAGGED_DIVISION_OF; SUBSET]; ALL_TAC] THEN
+        DISCH_THEN(MATCH_MP_TAC o CONJUNCT2) THEN ASM_REWRITE_TAC[] THEN
+        ASM_SIMP_TAC[GSYM(ONCE_REWRITE_RULE[DIST_SYM] IN_BALL)] THEN
+        ASM_MESON_TAC[IN_INTERVAL_1; SUBSET; TAGGED_DIVISION_OF;
+                      REAL_LE_TOTAL];
+        ALL_TAC] THEN
+      SUBGOAL_THEN `drop a <= drop c /\ drop c < drop x /\
+                    drop x <= drop v /\ drop v <= drop b`
+      STRIP_ASSUME_TAC THENL
+       [ASM_REWRITE_TAC[GSYM REAL_NOT_LE] THEN
+        ASM_MESON_TAC[IN_INTERVAL_1; SUBSET; TAGGED_DIVISION_OF;
+                      REAL_LE_TOTAL];
+        ALL_TAC] THEN
+      REWRITE_TAC[ONCE_REWRITE_RULE[NORM_SUB] dist] THEN
+      MATCH_MP_TAC
+       (REWRITE_RULE[LIFT_DROP; FORALL_LIFT]
+          (ISPEC `at c within interval [c:real^1,v]` LIM_DROP_UBOUND)) THEN
+      EXISTS_TAC `\y:real^1. lift(norm(f x - f y:real^N))` THEN
+      REWRITE_TAC[TRIVIAL_LIMIT_WITHIN; LIFT_DROP] THEN REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC LIM_NORM THEN MATCH_MP_TAC LIM_SUB THEN
+        ASM_SIMP_TAC[IN_INTERVAL_1; LIM_CONST] THEN
+        MATCH_MP_TAC LIM_WITHIN_SUBSET THEN
+        EXISTS_TAC `interval[c:real^1,b]` THEN CONJ_TAC THENL
+         [FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+          ASM_REAL_ARITH_TAC;
+          REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC];
+        W(MP_TAC o PART_MATCH (lhs o rand) LIMPT_OF_CONVEX o snd) THEN
+        ANTS_TAC THENL
+         [SIMP_TAC[CONVEX_INTERVAL; ENDS_IN_INTERVAL;
+                   INTERVAL_NE_EMPTY_1] THEN
+          ASM_REAL_ARITH_TAC;
+          DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC(SET_RULE
+           `(?y. ~(y = x) /\ y IN s) ==> ~(s = {x})`) THEN
+          EXISTS_TAC `v:real^1` THEN
+          REWRITE_TAC[IN_INTERVAL_1; GSYM DROP_EQ] THEN ASM_REAL_ARITH_TAC];
+        REWRITE_TAC[EVENTUALLY_WITHIN] THEN EXISTS_TAC `&1` THEN
+        REWRITE_TAC[REAL_LT_01] THEN X_GEN_TAC `y:real^1` THEN
+        REWRITE_TAC[IN_INTERVAL_1] THEN STRIP_TAC THEN
+        MATCH_MP_TAC VECTOR_VARIATION_GE_NORM_FUNCTION THEN CONJ_TAC THENL
+         [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            HAS_BOUNDED_VARIATION_ON_SUBSET)) THEN
+          REWRITE_TAC[SUBSET_INTERVAL_1] THEN ASM_REAL_ARITH_TAC;
+          MATCH_MP_TAC(CONJUNCT1(SPEC_ALL
+           (REWRITE_RULE[CONVEX_CONTAINS_SEGMENT] CONVEX_INTERVAL))) THEN
+          REWRITE_TAC[IN_INTERVAL_1] THEN ASM_REAL_ARITH_TAC]]];
+    MATCH_MP_TAC MEASURABLE_UNIONS THEN ASM_SIMP_TAC[FINITE_IMAGE] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM] THEN
+    SIMP_TAC[MEASURABLE_CBALL; MEASURABLE_UNION; MEASURABLE_INSERT];
+    W(MP_TAC o PART_MATCH (lhand o rand) MEASURE_UNIONS_LE_IMAGE o
+      lhand o snd) THEN
+    ANTS_TAC THENL
+     [ASM_REWRITE_TAC[FORALL_IN_IMAGE; FORALL_PAIR_THM] THEN
+      SIMP_TAC[MEASURABLE_CBALL; MEASURABLE_UNION; MEASURABLE_INSERT];
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS)] THEN
+    ONCE_REWRITE_TAC[LAMBDA_PAIR_THM] THEN REWRITE_TAC[MEASURE_INSERT] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC
+     `&2 pow (dimindex(:N)) *
+      e * sum p (\(x:real^1,k). vector_variation k (f:real^1->real^N))` THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[GSYM SUM_LMUL] THEN MATCH_MP_TAC SUM_LE THEN
+      ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+      MAP_EVERY X_GEN_TAC [`c:real^1`; `k:real^1->bool`] THEN DISCH_TAC THEN
+      SUBGOAL_THEN `?u v:real^1. k = interval[u,v]`
+       (REPEAT_TCL CHOOSE_THEN SUBST_ALL_TAC)
+      THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+      SUBGOAL_THEN `drop u <= drop v` ASSUME_TAC THENL
+       [ASM_MESON_TAC[TAGGED_DIVISION_OF; INTERVAL_NE_EMPTY_1; NOT_IN_EMPTY];
+        ASM_SIMP_TAC[INTERVAL_LOWERBOUND_1; INTERVAL_UPPERBOUND_1]] THEN
+      SUBGOAL_THEN
+       `(f:real^1->real^N) has_bounded_variation_on interval[u,c] /\
+        (f:real^1->real^N) has_bounded_variation_on interval[c,v]`
+      STRIP_ASSUME_TAC THENL
+       [CONJ_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+         (REWRITE_RULE[IMP_CONJ] HAS_BOUNDED_VARIATION_ON_SUBSET)) THEN
+        MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `interval[u:real^1,v]` THEN
+        (CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[TAGGED_DIVISION_OF]]) THEN
+        REWRITE_TAC[SUBSET_INTERVAL_1; REAL_LE_REFL] THEN
+        REWRITE_TAC[GSYM IN_INTERVAL_1] THEN ASM_MESON_TAC[TAGGED_DIVISION_OF];
+        ALL_TAC] THEN
+      SUBGOAL_THEN
+       `vector_variation (interval [u,v]) (f:real^1->real^N) =
+        vector_variation (interval [u,c]) f +
+        vector_variation (interval [c,v]) f`
+      SUBST1_TAC THENL
+       [CONV_TAC SYM_CONV THEN MATCH_MP_TAC VECTOR_VARIATION_COMBINE THEN
+        ASM_REWRITE_TAC[CONJ_ASSOC; GSYM IN_INTERVAL_1] THEN
+        CONJ_TAC THENL [ASM_MESON_TAC[TAGGED_DIVISION_OF]; ALL_TAC] THEN
+        ASM_MESON_TAC[TAGGED_DIVISION_OF; HAS_BOUNDED_VARIATION_ON_SUBSET];
+        ALL_TAC] THEN
+      W(MP_TAC o PART_MATCH (lhand o rand) MEASURE_UNION_LE o lhand o snd) THEN
+      REWRITE_TAC[MEASURABLE_CBALL; REAL_ADD_LDISTRIB] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+      MATCH_MP_TAC REAL_LE_ADD2 THEN CONJ_TAC THEN
+      W(MP_TAC o PART_MATCH (lhand o rand)
+        MEASURE_CBALL_BOUND o lhand o snd) THEN
+      ASM_SIMP_TAC[REAL_LE_MIN; REAL_LT_IMP_LE; VECTOR_VARIATION_POS_LE] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+      REWRITE_TAC[REAL_POW_MUL] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
+      SIMP_TAC[REAL_POW_LE; REAL_POS] THEN
+      (SUBGOAL_THEN `dimindex(:N) = (dimindex(:N) - 1) + 1` SUBST1_TAC THENL
+       [ASM_ARITH_TAC; REWRITE_TAC[REAL_POW_ADD; REAL_POW_1]]) THEN
+      MATCH_MP_TAC REAL_LE_MUL2 THEN
+      ASM_SIMP_TAC[REAL_LE_MIN; REAL_LT_IMP_LE; VECTOR_VARIATION_POS_LE;
+                   REAL_POW_LE; REAL_ARITH `min e v <= v`] THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `(e:real) pow (dimindex(:N) - 1)` THEN
+      (CONJ_TAC THENL
+       [MATCH_MP_TAC REAL_POW_LE2 THEN
+        ASM_SIMP_TAC[REAL_LE_MIN; REAL_LT_IMP_LE; VECTOR_VARIATION_POS_LE] THEN
+        REAL_ARITH_TAC;
+        GEN_REWRITE_TAC RAND_CONV [GSYM REAL_POW_1] THEN
+        MATCH_MP_TAC REAL_POW_MONO_INV THEN
+        ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN EXPAND_TAC "e" THEN CONJ_TAC THENL
+         [ASM_REAL_ARITH_TAC; ASM_ARITH_TAC]]);
+      MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+       `&2 pow dimindex (:N) *
+        (ee / (&2 pow (dimindex(:N)) *
+            vector_variation (interval[a,b]) (f:real^1->real^N) + &1)) *
+        sum p (\(x:real^1,k). vector_variation k f)` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC REAL_LE_LMUL THEN SIMP_TAC[REAL_POS; REAL_POW_LE] THEN
+        MATCH_MP_TAC REAL_LE_RMUL THEN CONJ_TAC THENL
+         [EXPAND_TAC "e" THEN REAL_ARITH_TAC; ALL_TAC] THEN
+        MATCH_MP_TAC SUM_POS_LE THEN ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN
+        ASM_MESON_TAC[HAS_BOUNDED_VARIATION_ON_SUBSET; TAGGED_DIVISION_OF;
+                      VECTOR_VARIATION_POS_LE];
+        ALL_TAC] THEN
+      REWRITE_TAC[REAL_ARITH `a * b / c * d:real = (b * a * d) / c`] THEN
+      W(MP_TAC o PART_MATCH (lhand o rand) REAL_LE_LDIV_EQ o snd) THEN
+      ASM_SIMP_TAC[REAL_LE_MUL; REAL_POS; REAL_POW_LE; VECTOR_VARIATION_POS_LE;
+                   REAL_ARITH `&0 <= x ==> &0 < x + &1`] THEN
+      DISCH_THEN SUBST1_TAC THEN
+      ASM_SIMP_TAC[REAL_LE_LMUL_EQ; GSYM REAL_MUL_ASSOC] THEN
+      MATCH_MP_TAC(REAL_ARITH `x <= y ==> x <= y + &1`) THEN
+      MATCH_MP_TAC REAL_LE_LMUL THEN SIMP_TAC[REAL_POW_LE; REAL_POS] THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          SUM_OVER_TAGGED_DIVISION_LEMMA)) THEN DISCH_THEN(fun th ->
+      W(MP_TAC o PART_MATCH (lhs o rand) th o lhand o snd)) THEN
+      SIMP_TAC[VECTOR_VARIATION_ON_NULL; BOUNDED_INTERVAL] THEN
+      DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[ETA_AX] THEN
+      MATCH_MP_TAC REAL_EQ_IMP_LE THEN
+      MATCH_MP_TAC VECTOR_VARIATION_ON_DIVISION THEN
+      ASM_SIMP_TAC[DIVISION_OF_TAGGED_DIVISION]]]);;
+
+let NEGLIGIBLE_RECTIFIABLE_PATH_IMAGE = prove
+ (`!g:real^1->real^N.
+        2 <= dimindex(:N) /\ rectifiable_path g ==> negligible(path_image g)`,
+  REWRITE_TAC[rectifiable_path; path_image] THEN
+  SIMP_TAC[NEGLIGIBLE_IMAGE_BOUNDED_VARIATION_INTERVAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Properties of Lebesgue measurable sets.                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_IMP_LEBESGUE_MEASURABLE = prove
+ (`!s:real^N->bool. measurable s ==> lebesgue_measurable s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[lebesgue_measurable] THEN
+  MATCH_MP_TAC INTEGRABLE_IMP_MEASURABLE THEN
+  ASM_REWRITE_TAC[indicator; GSYM MEASURABLE_INTEGRABLE]);;
+
+let NEGLIGIBLE_IMP_LEBESGUE_MEASURABLE = prove
+ (`!s:real^N->bool. negligible s ==> lebesgue_measurable s`,
+  SIMP_TAC[NEGLIGIBLE_IMP_MEASURABLE; MEASURABLE_IMP_LEBESGUE_MEASURABLE]);;
+
+let LEBESGUE_MEASURABLE_EMPTY = prove
+ (`lebesgue_measurable {}`,
+  SIMP_TAC[MEASURABLE_IMP_LEBESGUE_MEASURABLE; MEASURABLE_EMPTY]);;
+
+let LEBESGUE_MEASURABLE_UNIV = prove
+ (`lebesgue_measurable (:real^N)`,
+  REWRITE_TAC[lebesgue_measurable; indicator; IN_UNIV; MEASURABLE_ON_CONST]);;
+
+let LEBESGUE_MEASURABLE_COMPACT = prove
+ (`!s:real^N->bool. compact s ==> lebesgue_measurable s`,
+  SIMP_TAC[MEASURABLE_IMP_LEBESGUE_MEASURABLE; MEASURABLE_COMPACT]);;
+
+let LEBESGUE_MEASURABLE_INTERVAL = prove
+ (`(!a b:real^N. lebesgue_measurable(interval[a,b])) /\
+   (!a b:real^N. lebesgue_measurable(interval(a,b)))`,
+  SIMP_TAC[MEASURABLE_IMP_LEBESGUE_MEASURABLE; MEASURABLE_INTERVAL]);;
+
+let LEBESGUE_MEASURABLE_INTER = prove
+ (`!s t:real^N->bool.
+        lebesgue_measurable s /\ lebesgue_measurable t
+        ==> lebesgue_measurable(s INTER t)`,
+  REWRITE_TAC[indicator; lebesgue_measurable; MEASURABLE_ON_UNIV] THEN
+  REWRITE_TAC[MEASURABLE_ON_INTER]);;
+
+let LEBESGUE_MEASURABLE_UNION = prove
+ (`!s t:real^N->bool.
+        lebesgue_measurable s /\ lebesgue_measurable t
+        ==> lebesgue_measurable(s UNION t)`,
+  REWRITE_TAC[indicator; lebesgue_measurable; MEASURABLE_ON_UNIV] THEN
+  REWRITE_TAC[MEASURABLE_ON_UNION]);;
+
+let LEBESGUE_MEASURABLE_DIFF = prove
+ (`!s t:real^N->bool.
+        lebesgue_measurable s /\ lebesgue_measurable t
+        ==> lebesgue_measurable(s DIFF t)`,
+  REWRITE_TAC[indicator; lebesgue_measurable; MEASURABLE_ON_UNIV] THEN
+  REWRITE_TAC[MEASURABLE_ON_DIFF]);;
+
+let LEBESGUE_MEASURABLE_COMPL = prove
+ (`!s. lebesgue_measurable((:real^N) DIFF s) <=> lebesgue_measurable s`,
+  MESON_TAC[LEBESGUE_MEASURABLE_DIFF; LEBESGUE_MEASURABLE_UNIV;
+            SET_RULE `UNIV DIFF (UNIV DIFF s) = s`]);;
+
+let LEBESGUE_MEASURABLE_ON_SUBINTERVALS = prove
+ (`!s. lebesgue_measurable s <=>
+       !a b:real^N. lebesgue_measurable(s INTER interval[a,b])`,
+  GEN_TAC THEN EQ_TAC THEN
+  SIMP_TAC[LEBESGUE_MEASURABLE_INTERVAL; LEBESGUE_MEASURABLE_INTER] THEN
+  REWRITE_TAC[lebesgue_measurable] THEN DISCH_TAC THEN
+  MATCH_MP_TAC INTEGRABLE_SUBINTERVALS_IMP_MEASURABLE THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  MATCH_MP_TAC MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE THEN
+  EXISTS_TAC `(\x. vec 1):real^N->real^1` THEN
+  REWRITE_TAC[INTEGRABLE_CONST] THEN CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`a:real^N`; `b:real^N`]) THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    REWRITE_TAC[FUN_EQ_THM; indicator; IN_INTER] THEN MESON_TAC[];
+    REPEAT STRIP_TAC THEN REWRITE_TAC[indicator] THEN
+    COND_CASES_TAC THEN REWRITE_TAC[DROP_VEC; NORM_REAL; GSYM drop] THEN
+    REAL_ARITH_TAC]);;
+
+let LEBESGUE_MEASURABLE_CLOSED = prove
+ (`!s:real^N->bool. closed s ==> lebesgue_measurable s`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[LEBESGUE_MEASURABLE_ON_SUBINTERVALS] THEN
+  ASM_SIMP_TAC[CLOSED_INTER_COMPACT; LEBESGUE_MEASURABLE_COMPACT;
+               COMPACT_INTERVAL]);;
+
+let LEBESGUE_MEASURABLE_OPEN = prove
+ (`!s:real^N->bool. open s ==> lebesgue_measurable s`,
+  REWRITE_TAC[OPEN_CLOSED] THEN REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM LEBESGUE_MEASURABLE_COMPL] THEN
+  ASM_SIMP_TAC[LEBESGUE_MEASURABLE_CLOSED]);;
+
+let LEBESGUE_MEASURABLE_UNIONS = prove
+ (`!f. FINITE f /\ (!s. s IN f ==> lebesgue_measurable s)
+       ==> lebesgue_measurable (UNIONS f)`,
+  REWRITE_TAC[indicator; lebesgue_measurable; MEASURABLE_ON_UNIV] THEN
+  REWRITE_TAC[MEASURABLE_ON_UNIONS]);;
+
+let LEBESGUE_MEASURABLE_COUNTABLE_UNIONS = prove
+ (`!f:(real^N->bool)->bool.
+        COUNTABLE f /\ (!s. s IN f ==> lebesgue_measurable s)
+        ==> lebesgue_measurable (UNIONS f)`,
+  REWRITE_TAC[indicator; lebesgue_measurable; MEASURABLE_ON_UNIV] THEN
+  REWRITE_TAC[MEASURABLE_ON_COUNTABLE_UNIONS]);;
+
+let LEBESGUE_MEASURABLE_COUNTABLE_UNIONS_EXPLICIT = prove
+ (`!s:num->real^N->bool.
+        (!n. lebesgue_measurable(s n))
+        ==> lebesgue_measurable(UNIONS {s n | n IN (:num)})`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC LEBESGUE_MEASURABLE_COUNTABLE_UNIONS THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+  ASM_SIMP_TAC[COUNTABLE_IMAGE; FORALL_IN_IMAGE; IN_UNIV; NUM_COUNTABLE]);;
+
+let LEBESGUE_MEASURABLE_COUNTABLE_INTERS = prove
+ (`!f:(real^N->bool)->bool.
+        COUNTABLE f /\ (!s. s IN f ==> lebesgue_measurable s)
+        ==> lebesgue_measurable (INTERS f)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[INTERS_UNIONS; LEBESGUE_MEASURABLE_COMPL] THEN
+  MATCH_MP_TAC LEBESGUE_MEASURABLE_COUNTABLE_UNIONS THEN
+  ASM_SIMP_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE; COUNTABLE_IMAGE;
+               LEBESGUE_MEASURABLE_COMPL]);;
+
+let LEBESGUE_MEASURABLE_COUNTABLE_INTERS_EXPLICIT = prove
+ (`!s:num->real^N->bool.
+        (!n. lebesgue_measurable(s n))
+        ==> lebesgue_measurable(INTERS {s n | n IN (:num)})`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC LEBESGUE_MEASURABLE_COUNTABLE_INTERS THEN
+  ASM_SIMP_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE; COUNTABLE_IMAGE;
+               NUM_COUNTABLE]);;
+
+let LEBESGUE_MEASURABLE_INTERS = prove
+ (`!f:(real^N->bool)->bool.
+        FINITE f /\ (!s. s IN f ==> lebesgue_measurable s)
+        ==> lebesgue_measurable (INTERS f)`,
+  SIMP_TAC[LEBESGUE_MEASURABLE_COUNTABLE_INTERS; FINITE_IMP_COUNTABLE]);;
+
+let LEBESGUE_MEASURABLE_IFF_MEASURABLE = prove
+ (`!s:real^N->bool. bounded s ==> (lebesgue_measurable s <=> measurable s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  SIMP_TAC[MEASURABLE_IMP_LEBESGUE_MEASURABLE] THEN
+  REWRITE_TAC[lebesgue_measurable; indicator; MEASURABLE_INTEGRABLE] THEN
+  SUBGOAL_THEN `?a b:real^N. s = s INTER interval[a,b]`
+   (REPEAT_TCL CHOOSE_THEN SUBST1_TAC)
+  THENL [REWRITE_TAC[SET_RULE `s = s INTER t <=> s SUBSET t`] THEN
+         ASM_MESON_TAC[BOUNDED_SUBSET_CLOSED_INTERVAL]; ALL_TAC] THEN
+  REWRITE_TAC[IN_INTER; MESON[]
+   `(if P x /\ Q x then a else b) =
+    (if Q x then if P x then a else b else b)`] THEN
+  REWRITE_TAC[MEASURABLE_ON_UNIV; INTEGRABLE_RESTRICT_UNIV] THEN
+  STRIP_TAC THEN MATCH_MP_TAC
+    MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE THEN
+  EXISTS_TAC `(\x. vec 1):real^N->real^1` THEN
+  ASM_REWRITE_TAC[INTEGRABLE_CONST; NORM_REAL; DROP_VEC; GSYM drop] THEN
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN SIMP_TAC[DROP_VEC] THEN
+  REAL_ARITH_TAC);;
+
+let MEASURABLE_ON_MEASURABLE_SUBSET = prove
+ (`!f s t. s SUBSET t /\ f measurable_on t /\ measurable s
+           ==> f measurable_on s`,
+  MESON_TAC[MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET;
+            MEASURABLE_IMP_LEBESGUE_MEASURABLE]);;
+
+let MEASURABLE_ON_CASES = prove
+ (`!P f g:real^M->real^N s.
+        lebesgue_measurable {x | P x} /\
+        f measurable_on s /\ g measurable_on s
+        ==> (\x. if P x then f x else g x) measurable_on s`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x. (if x IN s then if P x then (f:real^M->real^N) x else g x else vec 0) =
+        (if x IN {x | P x} then if x IN s then f x else vec 0 else vec 0) +
+        (if x IN (:real^M) DIFF {x | P x}
+         then if x IN s then g x else vec 0 else vec 0)`
+   (fun th -> REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN REWRITE_TAC[IN_UNIV; IN_ELIM_THM; IN_DIFF] THEN
+    MESON_TAC[VECTOR_ADD_LID; VECTOR_ADD_RID];
+    MATCH_MP_TAC MEASURABLE_ON_ADD THEN
+    CONJ_TAC THEN MATCH_MP_TAC MEASURABLE_ON_RESTRICT THEN
+    ASM_REWRITE_TAC[LEBESGUE_MEASURABLE_COMPL]]);;
+
+let LEBESGUE_MEASURABLE_JORDAN = prove
+ (`!s:real^N->bool. negligible(frontier s) ==> lebesgue_measurable s`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[LEBESGUE_MEASURABLE_ON_SUBINTERVALS] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  MATCH_MP_TAC MEASURABLE_IMP_LEBESGUE_MEASURABLE THEN
+  MATCH_MP_TAC MEASURABLE_JORDAN THEN
+  SIMP_TAC[BOUNDED_INTER; BOUNDED_INTERVAL] THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `frontier s UNION frontier(interval[a:real^N,b])` THEN
+  ASM_REWRITE_TAC[FRONTIER_INTER_SUBSET; NEGLIGIBLE_UNION_EQ] THEN
+  SIMP_TAC[NEGLIGIBLE_CONVEX_FRONTIER; CONVEX_INTERVAL]);;
+
+let LEBESGUE_MEASURABLE_CONVEX = prove
+ (`!s:real^N->bool. convex s ==> lebesgue_measurable s`,
+  SIMP_TAC[LEBESGUE_MEASURABLE_JORDAN; NEGLIGIBLE_CONVEX_FRONTIER]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Invariance theorems for Lebesgue measurability.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_ON_TRANSLATION = prove
+ (`!f:real^M->real^N s a.
+          f measurable_on (IMAGE (\x. a + x) s)
+          ==> (\x. f(a + x)) measurable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[measurable_on; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`k:real^M->bool`; `g:num->real^M->real^N`] THEN
+  STRIP_TAC THEN EXISTS_TAC `IMAGE (\x:real^M. --a + x) k` THEN
+  EXISTS_TAC `\n. (g:num->real^M->real^N) n o (\x. a + x)` THEN
+  ASM_REWRITE_TAC[NEGLIGIBLE_TRANSLATION_EQ] THEN CONJ_TAC THENL
+   [GEN_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNIV];
+    X_GEN_TAC `x:real^M` THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `a + x:real^M`) THEN
+    REWRITE_TAC[o_DEF; IN_IMAGE] THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH `x:real^N = --a + y <=> a + x = y`] THEN
+    REWRITE_TAC[UNWIND_THM1; VECTOR_ARITH `a + x:real^N = a + y <=> x = y`]]);;
+
+let MEASURABLE_ON_TRANSLATION_EQ = prove
+ (`!f:real^M->real^N s a.
+        (\x. f(a + x)) measurable_on s <=>
+        f measurable_on (IMAGE (\x. a + x) s)`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[MEASURABLE_ON_TRANSLATION] THEN
+  MP_TAC(ISPECL [`\x. (f:real^M->real^N) (a + x)`;
+                 `IMAGE (\x:real^M. a + x) s`; `--a:real^M`]
+    MEASURABLE_ON_TRANSLATION) THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; ETA_AX; IMAGE_ID; VECTOR_ARITH
+   `--a + a + x:real^N = x /\ a + --a + x = x`]);;
+
+let MEASURABLE_ON_LINEAR_IMAGE_EQ = prove
+ (`!f:real^N->real^N h:real^N->real^P s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> ((h o f) measurable_on s <=> h measurable_on (IMAGE f s))`,
+  let lemma = prove
+   (`!f:real^N->real^P g:real^N->real^N h s.
+        linear g /\ linear h /\ (!x. h(g x) = x) /\ (!x. g(h x) = x)
+        ==> (f o g) measurable_on s ==> f measurable_on (IMAGE g s)`,
+    REPEAT GEN_TAC THEN REWRITE_TAC[measurable_on] THEN
+    STRIP_TAC THEN DISCH_THEN(X_CHOOSE_THEN `k:real^N->bool`
+     (X_CHOOSE_THEN `G:num->real^N->real^P` STRIP_ASSUME_TAC)) THEN
+    EXISTS_TAC `IMAGE (g:real^N->real^N) k` THEN
+    EXISTS_TAC `\n x. (G:num->real^N->real^P) n ((h:real^N->real^N) x)` THEN
+    ASM_SIMP_TAC[NEGLIGIBLE_LINEAR_IMAGE] THEN CONJ_TAC THENL
+     [GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      ASM_MESON_TAC[LINEAR_CONTINUOUS_ON; CONTINUOUS_ON_SUBSET; SUBSET_UNIV];
+      X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `(h:real^N->real^N) y`) THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+      ASM_REWRITE_TAC[o_THM] THEN
+      AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN ASM SET_TAC[]]) in
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP LINEAR_INJECTIVE_IMP_SURJECTIVE) THEN
+  POP_ASSUM MP_TAC THEN REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  DISCH_TAC THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `g:real^N->real^N` STRIP_ASSUME_TAC o
+        MATCH_MP LINEAR_BIJECTIVE_LEFT_RIGHT_INVERSE) THEN
+  EQ_TAC THENL [ASM_MESON_TAC[lemma]; DISCH_TAC] THEN
+  MP_TAC(ISPECL [`(h:real^N->real^P) o (f:real^N->real^N)`;
+                 `g:real^N->real^N`; `f:real^N->real^N`;
+                 `IMAGE (f:real^N->real^N) s`] lemma) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID; ETA_AX]);;
+
+let LEBESGUE_MEASURABLE_TRANSLATION = prove
+ (`!a:real^N s.
+     lebesgue_measurable (IMAGE (\x. a + x) s) <=>
+     lebesgue_measurable s`,
+  ONCE_REWRITE_TAC[LEBESGUE_MEASURABLE_ON_SUBINTERVALS] THEN
+  SIMP_TAC[LEBESGUE_MEASURABLE_IFF_MEASURABLE;
+           BOUNDED_INTER; BOUNDED_INTERVAL] THEN
+  GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [LEBESGUE_MEASURABLE_TRANSLATION];;
+
+let LEBESGUE_MEASURABLE_LINEAR_IMAGE_EQ = prove
+ (`!f:real^N->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+         ==> (lebesgue_measurable (IMAGE f s) <=>
+              lebesgue_measurable s)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP LINEAR_INJECTIVE_IMP_SURJECTIVE) THEN
+  POP_ASSUM MP_TAC THEN REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  DISCH_TAC THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `g:real^N->real^N` STRIP_ASSUME_TAC o
+        MATCH_MP LINEAR_BIJECTIVE_LEFT_RIGHT_INVERSE) THEN
+  REWRITE_TAC[lebesgue_measurable] THEN MP_TAC(ISPECL
+   [`g:real^N->real^N`; `indicator(s:real^N->bool)`; `(:real^N)`]
+   MEASURABLE_ON_LINEAR_IMAGE_EQ) THEN
+  ASM_REWRITE_TAC[indicator; o_DEF] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[]; MATCH_MP_TAC EQ_IMP] THEN
+  BINOP_TAC THENL
+   [AP_THM_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
+    AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN ASM SET_TAC[];
+    AP_TERM_TAC THEN ASM SET_TAC[]]);;
+
+add_linear_invariants [LEBESGUE_MEASURABLE_LINEAR_IMAGE_EQ];;
+
+(* ------------------------------------------------------------------------- *)
+(* Various common equivalent forms of function measurability.                *)
+(* ------------------------------------------------------------------------- *)
+
+let (MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT,
+     MEASURABLE_ON_SIMPLE_FUNCTION_LIMIT) = (CONJ_PAIR o prove)
+ (`(!f:real^M->real^N.
+        f measurable_on (:real^M) <=>
+        !a k. 1 <= k /\ k <= dimindex(:N)
+              ==> lebesgue_measurable {x | f(x)$k < a}) /\
+   (!f:real^M->real^N.
+        f measurable_on (:real^M) <=>
+        ?g. (!n. (g n) measurable_on (:real^M)) /\
+            (!n. FINITE(IMAGE (g n) (:real^M))) /\
+            (!x. ((\n. g n x) --> f x) sequentially))`,
+  let lemma0 = prove
+   (`!f:real^M->real^1 n m.
+          integer m /\
+          m / &2 pow n <= drop(f x) /\
+          drop(f x) < (m + &1) / &2 pow n /\
+          abs(m) <= &2 pow (2 * n)
+          ==> vsum {k | integer k /\ abs(k) <= &2 pow (2 * n)}
+                   (\k. k / &2 pow n %
+                        indicator {y:real^M | k / &2 pow n <= drop(f y) /\
+                                              drop(f y) < (k + &1) / &2 pow n}
+                                  x) =
+              lift(m / &2 pow n)`,
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC
+     `vsum {m} (\k. k / &2 pow n %
+                    indicator {y:real^M | k / &2 pow n <= drop(f y) /\
+                                          drop(f y) < (k + &1) / &2 pow n}
+                              x)` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC VSUM_SUPERSET THEN
+      ASM_REWRITE_TAC[SING_SUBSET; IN_ELIM_THM; IN_SING] THEN
+      X_GEN_TAC `k:real` THEN STRIP_TAC THEN
+      REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISJ2_TAC THEN
+      ASM_REWRITE_TAC[indicator; IN_ELIM_THM] THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(TAUT `F ==> p`) THEN
+      UNDISCH_TAC `~(k:real = m)` THEN ASM_SIMP_TAC[REAL_EQ_INTEGERS] THEN
+      POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+      SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LT_RDIV_EQ; REAL_LT_POW2] THEN
+      REAL_ARITH_TAC;
+      ASM_REWRITE_TAC[VSUM_SING; indicator; IN_ELIM_THM; LIFT_EQ_CMUL]]) in
+  let lemma1 = prove
+   (`!f:real^M->real^1.
+          (!a b. lebesgue_measurable {x | a <= drop(f x) /\ drop(f x) < b})
+          ==> ?g. (!n. (g n) measurable_on (:real^M)) /\
+                  (!n. FINITE(IMAGE (g n) (:real^M))) /\
+                  (!x. ((\n. g n x) --> f x) sequentially)`,
+    REPEAT STRIP_TAC THEN
+    EXISTS_TAC
+     `\n x. vsum {k | integer k /\ abs(k) <= &2 pow (2 * n)}
+                 (\k. k / &2 pow n %
+                      indicator {y:real^M | k / &2 pow n <= drop(f y) /\
+                                            drop(f y) < (k + &1) / &2 pow n}
+                                x)` THEN
+    REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [X_GEN_TAC `n:num` THEN MATCH_MP_TAC MEASURABLE_ON_VSUM THEN
+      REWRITE_TAC[REAL_ABS_BOUNDS; FINITE_INTSEG; IN_ELIM_THM] THEN
+      GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_ON_CMUL THEN
+      ASM_REWRITE_TAC[GSYM lebesgue_measurable; ETA_AX];
+      X_GEN_TAC `n:num` THEN
+      MATCH_MP_TAC FINITE_SUBSET THEN
+      EXISTS_TAC `IMAGE (\k. lift(k / &2 pow n))
+                        {k | integer k /\ abs(k) <= &2 pow (2 * n)}` THEN
+      CONJ_TAC THENL
+       [SIMP_TAC[REAL_ABS_BOUNDS; FINITE_INTSEG; FINITE_IMAGE];
+        ALL_TAC] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_UNIV] THEN
+      X_GEN_TAC `x:real^M` THEN REWRITE_TAC[IN_IMAGE] THEN
+      ASM_CASES_TAC
+       `?k. integer k /\ abs k <= &2 pow (2 * n) /\
+            k / &2 pow n <= drop(f(x:real^M)) /\
+            drop(f x) < (k + &1) / &2 pow n`
+      THENL
+       [FIRST_X_ASSUM(fun th -> MP_TAC th THEN MATCH_MP_TAC MONO_EXISTS) THEN
+        X_GEN_TAC `m:real` THEN STRIP_TAC THEN ASM_REWRITE_TAC[IN_ELIM_THM] THEN
+        MATCH_MP_TAC lemma0 THEN ASM_REWRITE_TAC[];
+        EXISTS_TAC `&0` THEN
+        ASM_REWRITE_TAC[IN_ELIM_THM; INTEGER_CLOSED; REAL_ABS_NUM] THEN
+        SIMP_TAC[REAL_POW_LE; REAL_POS; real_div; REAL_MUL_LZERO] THEN
+        REWRITE_TAC[LIFT_NUM; GSYM real_div] THEN
+        MATCH_MP_TAC VSUM_EQ_0 THEN
+        X_GEN_TAC `k:real` THEN REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN
+        REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISJ2_TAC THEN
+        REWRITE_TAC[indicator; IN_ELIM_THM] THEN ASM_MESON_TAC[]];
+      X_GEN_TAC `x:real^M` THEN REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+      MP_TAC(ISPECL [`&2`; `abs(drop((f:real^M->real^1) x))`]
+          REAL_ARCH_POW) THEN
+      ANTS_TAC THENL [REAL_ARITH_TAC; DISCH_THEN(X_CHOOSE_TAC `N1:num`)] THEN
+      X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+      MP_TAC(ISPECL [`inv(&2)`; `e:real`] REAL_ARCH_POW_INV) THEN
+      REWRITE_TAC[REAL_POW_INV] THEN
+      ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+      DISCH_THEN(X_CHOOSE_THEN `N2:num` MP_TAC) THEN
+      SUBST1_TAC(REAL_ARITH `inv(&2 pow N2) = &1 / &2 pow N2`) THEN
+      SIMP_TAC[REAL_LT_LDIV_EQ; REAL_LT_POW2] THEN DISCH_TAC THEN
+      EXISTS_TAC `MAX N1 N2` THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+      ABBREV_TAC `m = floor(&2 pow n * drop(f(x:real^M)))` THEN
+      SUBGOAL_THEN `dist(lift(m / &2 pow n),(f:real^M->real^1) x) < e`
+      MP_TAC THENL
+       [REWRITE_TAC[DIST_REAL; GSYM drop; LIFT_DROP] THEN
+        MATCH_MP_TAC REAL_LT_LCANCEL_IMP THEN EXISTS_TAC `abs(&2 pow n)` THEN
+        REWRITE_TAC[GSYM REAL_ABS_MUL; REAL_SUB_LDISTRIB] THEN
+        SIMP_TAC[REAL_DIV_LMUL; REAL_POW_EQ_0; GSYM REAL_ABS_NZ;
+                 REAL_OF_NUM_EQ; ARITH] THEN
+        MATCH_MP_TAC(REAL_ARITH
+         `x <= y /\ y < x + &1 /\ &1 <= z ==> abs(x - y) < z`) THEN
+        EXPAND_TAC "m" THEN REWRITE_TAC[FLOOR] THEN
+        ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+        EXISTS_TAC `e * &2 pow N2` THEN
+        ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_ABS_POW; REAL_ABS_NUM] THEN
+        MATCH_MP_TAC REAL_LE_LMUL THEN ASM_SIMP_TAC[REAL_LT_IMP_LE];
+        MATCH_MP_TAC(NORM_ARITH
+         `x:real^1 = y ==> dist(y,z) < e ==> dist(x,z) < e`) THEN
+        MATCH_MP_TAC lemma0 THEN
+        SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LT_RDIV_EQ; REAL_LT_POW2] THEN
+        ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+        EXPAND_TAC "m" THEN REWRITE_TAC[FLOOR] THEN
+        SIMP_TAC[REAL_ABS_BOUNDS; REAL_LE_FLOOR; REAL_FLOOR_LE;
+                 INTEGER_CLOSED] THEN
+        MATCH_MP_TAC(REAL_ARITH `abs(x) <= e ==> --e <= x /\ x - &1 < e`) THEN
+        REWRITE_TAC[MULT_2; REAL_POW_ADD; REAL_ABS_MUL; REAL_ABS_POW;
+                    REAL_ABS_NUM] THEN
+        MATCH_MP_TAC REAL_LE_LMUL THEN SIMP_TAC[REAL_POW_LE; REAL_POS] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+         `x < e ==> e <= d ==> x <= d`))] THEN
+      MATCH_MP_TAC REAL_POW_MONO THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      ASM_ARITH_TAC]) in
+  MATCH_MP_TAC(MESON[]
+   `(!f. P f ==> Q f) /\ (!f. Q f ==> R f) /\ (!f. R f ==> P f)
+    ==> (!f. P f <=> Q f) /\ (!f. P f <=> R f)`) THEN
+  REPEAT CONJ_TAC THENL
+   [X_GEN_TAC `g:real^M->real^N` THEN DISCH_TAC THEN
+    ABBREV_TAC `f:real^M->real^N = \x. --(g x)` THEN
+    SUBGOAL_THEN `(f:real^M->real^N) measurable_on (:real^M)` ASSUME_TAC THENL
+     [EXPAND_TAC "f" THEN MATCH_MP_TAC MEASURABLE_ON_NEG THEN ASM_SIMP_TAC[];
+      ALL_TAC] THEN
+    ONCE_REWRITE_TAC[GSYM REAL_LT_NEG2] THEN X_GEN_TAC `a:real` THEN
+    SPEC_TAC(`--a:real`,`a:real`) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [FUN_EQ_THM]) THEN
+    SIMP_TAC[GSYM VECTOR_NEG_COMPONENT] THEN DISCH_THEN(K ALL_TAC) THEN
+    REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `k:num` o
+      GEN_REWRITE_RULE I [MEASURABLE_ON_COMPONENTWISE]) THEN
+    ASM_REWRITE_TAC[] THEN  REPEAT STRIP_TAC THEN
+    MP_TAC(GEN `d:real` (ISPECL
+     [`\x. lift ((f:real^M->real^N) x$k)`;
+       `(\x. lift a + (lambda i. d)):real^M->real^1`;
+      `(:real^M)`] MEASURABLE_ON_MIN)) THEN
+    ASM_REWRITE_TAC[MEASURABLE_ON_CONST] THEN
+    DISCH_THEN(fun th ->
+      MP_TAC(GEN `n:num` (ISPEC `&n + &1` (MATCH_MP MEASURABLE_ON_CMUL
+        (MATCH_MP MEASURABLE_ON_SUB
+       (CONJ (SPEC `inv(&n + &1)` th) (SPEC `&0` th))))))) THEN
+    REWRITE_TAC[lebesgue_measurable; indicator] THEN
+    DISCH_THEN(MATCH_MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+          MEASURABLE_ON_LIMIT)) THEN
+    EXISTS_TAC `{}:real^M->bool` THEN
+    REWRITE_TAC[NEGLIGIBLE_EMPTY; IN_DIFF; IN_UNIV; NOT_IN_EMPTY] THEN
+    X_GEN_TAC `x:real^M` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    SIMP_TAC[LIM_SEQUENTIALLY; DIST_REAL; VECTOR_MUL_COMPONENT;
+             VECTOR_ADD_COMPONENT; VECTOR_SUB_COMPONENT;
+             LAMBDA_BETA; DIMINDEX_1; ARITH] THEN
+    REWRITE_TAC[GSYM drop; LIFT_DROP; REAL_ADD_RID] THEN
+    SIMP_TAC[REAL_LT_INV_EQ; REAL_ARITH `&0 < &n + &1`; REAL_ARITH
+     `&0 < d ==> (min x (a + d) - min x a =
+                  if x <= a then &0 else if x <= a + d then x - a else d)`] THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `a < (f:real^M->real^N) x $k` THEN ASM_REWRITE_TAC[] THEN
+    ASM_REWRITE_TAC[REAL_ARITH `(x:real^N)$k <= a <=> ~(a < x$k)`] THEN
+    ASM_REWRITE_TAC[REAL_MUL_RZERO; DROP_VEC; REAL_SUB_REFL; REAL_ABS_NUM] THEN
+    MP_TAC(SPEC `((f:real^M->real^N) x)$k - a` REAL_ARCH_INV) THEN
+    ASM_REWRITE_TAC[REAL_SUB_LT] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `N:num` THEN STRIP_TAC THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `a + inv(&n + &1) < ((f:real^M->real^N) x)$k` ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+       `N < f - a ==> n <= N ==> a + n < f`)) THEN
+      MATCH_MP_TAC REAL_LE_INV2 THEN
+      REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+      ASM_ARITH_TAC;
+      ASM_SIMP_TAC[REAL_MUL_RINV; REAL_ARITH `~(&n + &1 = &0)`] THEN
+      ASM_REAL_ARITH_TAC];
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+     `!k. 1 <= k /\ k <= dimindex(:N)
+          ==> ?g. (!n. (g n) measurable_on (:real^M)) /\
+                  (!n. FINITE(IMAGE (g n) (:real^M))) /\
+                  (!x. ((\n. g n x) --> lift((f x:real^N)$k)) sequentially)`
+    MP_TAC THENL
+     [REPEAT STRIP_TAC THEN MATCH_MP_TAC lemma1 THEN
+      ASM_SIMP_TAC[LIFT_DROP] THEN
+      MAP_EVERY X_GEN_TAC [`a:real`; `b:real`] THEN
+      REWRITE_TAC[SET_RULE `{x | P x /\ Q x} = {x | Q x} DIFF {x | ~P x}`] THEN
+      MATCH_MP_TAC LEBESGUE_MEASURABLE_DIFF THEN
+      ASM_SIMP_TAC[REAL_NOT_LE];
+      GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [RIGHT_IMP_EXISTS_THM]] THEN
+    REWRITE_TAC[SKOLEM_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:num->num->real^M->real^1` MP_TAC) THEN
+    REWRITE_TAC[TAUT `a ==> b /\ c <=> (a ==> b) /\ (a ==> c)`] THEN
+    REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC THEN
+    EXISTS_TAC
+      `\n x. (lambda k. drop((g:num->num->real^M->real^1) k n x)):real^N` THEN
+    REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [X_GEN_TAC `n:num` THEN ONCE_REWRITE_TAC[MEASURABLE_ON_COMPONENTWISE] THEN
+      X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+      ASM_SIMP_TAC[LAMBDA_BETA; LIFT_DROP; ETA_AX];
+      X_GEN_TAC `n:num` THEN MATCH_MP_TAC FINITE_SUBSET THEN
+      EXISTS_TAC `{x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
+                        ==> lift(x$i) IN IMAGE (g i (n:num)) (:real^M)}` THEN
+      ASM_SIMP_TAC[GSYM IN_IMAGE_LIFT_DROP; SET_RULE `{x | x IN s} = s`;
+                   FINITE_IMAGE; FINITE_CART] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM; IN_UNIV] THEN
+      SIMP_TAC[IN_IMAGE; IN_UNIV; LAMBDA_BETA; DROP_EQ] THEN MESON_TAC[];
+      X_GEN_TAC `x:real^M` THEN ONCE_REWRITE_TAC[LIM_COMPONENTWISE_LIFT] THEN
+      X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+      ASM_SIMP_TAC[LAMBDA_BETA; LIFT_DROP; ETA_AX]];
+    X_GEN_TAC `f:real^M->real^N` THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:num->real^M->real^N` STRIP_ASSUME_TAC) THEN
+    MATCH_MP_TAC MEASURABLE_ON_LIMIT THEN
+    MAP_EVERY EXISTS_TAC [`g:num->real^M->real^N`; `{}:real^M->bool`] THEN
+    ASM_REWRITE_TAC[NEGLIGIBLE_EMPTY]]);;
+
+let MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE = prove
+ (`!f:real^M->real^N.
+        f measurable_on (:real^M) <=>
+        !a k. 1 <= k /\ k <= dimindex(:N)
+              ==> lebesgue_measurable {x | f(x)$k >= a}`,
+  GEN_TAC THEN REWRITE_TAC[REAL_ARITH `x >= a <=> ~(x < a)`] THEN
+  REWRITE_TAC[SET_RULE `{x | ~P x} = UNIV DIFF {x | P x}`] THEN
+  REWRITE_TAC[LEBESGUE_MEASURABLE_COMPL] THEN
+  REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT]);;
+
+let MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT = prove
+ (`!f:real^M->real^N.
+        f measurable_on (:real^M) <=>
+        !a k. 1 <= k /\ k <= dimindex(:N)
+              ==> lebesgue_measurable {x | f(x)$k > a}`,
+  GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM MEASURABLE_ON_NEG_EQ] THEN
+  REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT] THEN
+  GEN_REWRITE_TAC LAND_CONV
+   [MESON[REAL_NEG_NEG] `(!x. P x) <=> (!x:real. P(--x))`] THEN
+  REWRITE_TAC[real_gt; VECTOR_NEG_COMPONENT; REAL_LT_NEG2]);;
+
+let MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE = prove
+ (`!f:real^M->real^N.
+        f measurable_on (:real^M) <=>
+        !a k. 1 <= k /\ k <= dimindex(:N)
+              ==> lebesgue_measurable {x | f(x)$k <= a}`,
+  GEN_TAC THEN REWRITE_TAC[REAL_ARITH `x <= a <=> ~(x > a)`] THEN
+  REWRITE_TAC[SET_RULE `{x | ~P x} = UNIV DIFF {x | P x}`] THEN
+  REWRITE_TAC[LEBESGUE_MEASURABLE_COMPL] THEN
+  REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT]);;
+
+let (MEASURABLE_ON_PREIMAGE_OPEN_INTERVAL,
+    MEASURABLE_ON_PREIMAGE_OPEN) = (CONJ_PAIR o prove)
+ (`(!f:real^M->real^N.
+        f measurable_on (:real^M) <=>
+        !a b. lebesgue_measurable {x | f(x) IN interval(a,b)}) /\
+   (!f:real^M->real^N.
+        f measurable_on (:real^M) <=>
+        !t. open t ==> lebesgue_measurable {x | f(x) IN t})`,
+  let ulemma = prove
+   (`{x | f x IN UNIONS D} = UNIONS {{x | f(x) IN s} | s IN D}`,
+    REWRITE_TAC[UNIONS_GSPEC] THEN SET_TAC[]) in
+  MATCH_MP_TAC(MESON[]
+   `(!f. P f ==> Q f) /\ (!f. Q f ==> R f) /\ (!f. R f ==> P f)
+    ==> (!f. P f <=> Q f) /\ (!f. P f <=> R f)`) THEN
+  REPEAT CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN SUBGOAL_THEN
+    `{x | (f:real^M->real^N) x IN interval(a,b)} =
+        INTERS {{x | a$k < f(x)$k} | k IN 1..dimindex(:N)} INTER
+        INTERS {{x | (--b)$k < --(f(x))$k} | k IN 1..dimindex(:N)}`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[IN_INTERVAL; GSYM IN_NUMSEG] THEN
+      REWRITE_TAC[VECTOR_NEG_COMPONENT; REAL_LT_NEG2] THEN
+      REWRITE_TAC[INTERS_GSPEC] THEN SET_TAC[];
+      MATCH_MP_TAC LEBESGUE_MEASURABLE_INTER THEN
+      CONJ_TAC THEN MATCH_MP_TAC LEBESGUE_MEASURABLE_INTERS THEN
+      SIMP_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE; FINITE_IMAGE; FINITE_NUMSEG] THEN
+      REWRITE_TAC[IN_NUMSEG] THEN REPEAT STRIP_TAC THENL
+       [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+         [MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT]);
+        FIRST_X_ASSUM(MP_TAC o MATCH_MP MEASURABLE_ON_NEG) THEN
+        REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT]] THEN
+      ASM_SIMP_TAC[real_gt]];
+    REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_COUNTABLE_UNION_OPEN_INTERVALS) THEN
+    DISCH_THEN(X_CHOOSE_THEN `D:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN ONCE_REWRITE_TAC[ulemma] THEN
+    MATCH_MP_TAC LEBESGUE_MEASURABLE_COUNTABLE_UNIONS THEN
+    ASM_SIMP_TAC[SIMPLE_IMAGE; COUNTABLE_IMAGE; FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `i:real^N->bool` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `i:real^N->bool`) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    ASM_SIMP_TAC[LEFT_IMP_EXISTS_THM];
+    REPEAT STRIP_TAC THEN
+    REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT] THEN
+    REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[SET_RULE
+      `{x:real^M | (f x)$k < a} = {x | f x IN {y:real^N | y$k < a}}`] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[OPEN_HALFSPACE_COMPONENT_LT]]);;
+
+let MEASURABLE_ON_PREIMAGE_CLOSED = prove
+ (`!f:real^M->real^N.
+        f measurable_on (:real^M) <=>
+        !t. closed t ==> lebesgue_measurable {x | f(x) IN t}`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM LEBESGUE_MEASURABLE_COMPL; closed] THEN
+  REWRITE_TAC[SET_RULE
+   `UNIV DIFF {x | f x IN t} = {x | f x IN (UNIV DIFF t)}`] THEN
+  REWRITE_TAC[MESON[SET_RULE `UNIV DIFF (UNIV DIFF s) = s`]
+   `(!s. P(UNIV DIFF s)) <=> (!s. P s)`] THEN
+  REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN]);;
+
+let MEASURABLE_ON_PREIMAGE_CLOSED_INTERVAL = prove
+ (`!f:real^M->real^N.
+         f measurable_on (:real^M) <=>
+         !a b. lebesgue_measurable {x | f(x) IN interval[a,b]}`,
+  let ulemma = prove
+   (`{x | f x IN UNIONS D} = UNIONS {{x | f(x) IN s} | s IN D}`,
+    REWRITE_TAC[UNIONS_GSPEC] THEN SET_TAC[]) in
+  GEN_TAC THEN EQ_TAC THENL
+   [SIMP_TAC[MEASURABLE_ON_PREIMAGE_CLOSED; CLOSED_INTERVAL]; DISCH_TAC] THEN
+  REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_COUNTABLE_UNION_CLOSED_INTERVALS) THEN
+  DISCH_THEN(X_CHOOSE_THEN `D:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN ONCE_REWRITE_TAC[ulemma] THEN
+  MATCH_MP_TAC LEBESGUE_MEASURABLE_COUNTABLE_UNIONS THEN
+  ASM_SIMP_TAC[SIMPLE_IMAGE; COUNTABLE_IMAGE; FORALL_IN_IMAGE] THEN
+  X_GEN_TAC `i:real^N->bool` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `i:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_SIMP_TAC[LEFT_IMP_EXISTS_THM]);;
+
+let LEBESGUE_MEASURABLE_PREIMAGE_OPEN = prove
+ (`!f:real^M->real^N t.
+        f measurable_on (:real^M) /\ open t
+        ==> lebesgue_measurable {x | f(x) IN t}`,
+  SIMP_TAC[MEASURABLE_ON_PREIMAGE_OPEN]);;
+
+let LEBESGUE_MEASURABLE_PREIMAGE_CLOSED = prove
+ (`!f:real^M->real^N t.
+        f measurable_on (:real^M) /\ closed t
+        ==> lebesgue_measurable {x | f(x) IN t}`,
+  SIMP_TAC[MEASURABLE_ON_PREIMAGE_CLOSED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More connections with measure where Lebesgue measurability is useful.     *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_LEGESGUE_MEASURABLE_SUBSET = prove
+ (`!s t:real^N->bool.
+        lebesgue_measurable s /\ measurable t /\ s SUBSET t
+        ==> measurable s`,
+  REWRITE_TAC[lebesgue_measurable; MEASURABLE_INTEGRABLE] THEN
+  REWRITE_TAC[indicator] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE THEN
+  EXISTS_TAC `(\x. if x IN t then vec 1 else vec 0):real^N->real^1` THEN
+  ASM_REWRITE_TAC[IN_UNIV] THEN GEN_TAC THEN
+  REPEAT(COND_CASES_TAC THEN
+         ASM_REWRITE_TAC[DROP_VEC; NORM_REAL; GSYM drop]) THEN
+  REWRITE_TAC[REAL_ABS_NUM; REAL_LE_REFL; REAL_POS] THEN ASM SET_TAC[]);;
+
+let MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE = prove
+ (`!s t:real^N->bool.
+        lebesgue_measurable s /\ measurable t ==> measurable(s INTER t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_LEGESGUE_MEASURABLE_SUBSET THEN
+  EXISTS_TAC `t:real^N->bool` THEN
+  ASM_SIMP_TAC[LEBESGUE_MEASURABLE_INTER; MEASURABLE_IMP_LEBESGUE_MEASURABLE;
+               INTER_SUBSET]);;
+
+let MEASURABLE_MEASURABLE_INTER_LEGESGUE_MEASURABLE = prove
+ (`!s t:real^N->bool.
+        measurable s /\ lebesgue_measurable t ==> measurable(s INTER t)`,
+  MESON_TAC[INTER_COMM; MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE]);;
+
+let MEASURABLE_INTER_HALFSPACE_LE = prove
+ (`!s a i. measurable s ==> measurable(s INTER {x:real^N | x$i <= a})`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:N) /\ !z:real^N. z$i = z$k`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MEASURABLE_MEASURABLE_INTER_LEGESGUE_MEASURABLE THEN
+  ASM_SIMP_TAC[CLOSED_HALFSPACE_COMPONENT_LE; LEBESGUE_MEASURABLE_CLOSED]);;
+
+let MEASURABLE_INTER_HALFSPACE_GE = prove
+ (`!s a i. measurable s ==> measurable(s INTER {x:real^N | x$i >= a})`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:N) /\ !z:real^N. z$i = z$k`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MEASURABLE_MEASURABLE_INTER_LEGESGUE_MEASURABLE THEN
+  ASM_SIMP_TAC[CLOSED_HALFSPACE_COMPONENT_GE; LEBESGUE_MEASURABLE_CLOSED]);;
+
+let MEASURABLE_MEASURABLE_DIFF_LEGESGUE_MEASURABLE = prove
+ (`!s t. measurable s /\ lebesgue_measurable t ==> measurable(s DIFF t)`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[SET_RULE `s DIFF t = s INTER (UNIV DIFF t)`] THEN
+  ASM_SIMP_TAC[MEASURABLE_MEASURABLE_INTER_LEGESGUE_MEASURABLE;
+                LEBESGUE_MEASURABLE_COMPL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Localized variants of function measurability equivalents.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let [MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED;
+     MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED_INTERVAL;
+     MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN;
+     MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE;
+     MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT;
+     MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE;
+     MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT;
+     MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_INTERVAL] =
+  (CONJUNCTS o prove)
+ (`(!f:real^M->real^N s.
+      lebesgue_measurable s
+      ==> (f measurable_on s <=>
+           !t. closed t ==> lebesgue_measurable {x | x IN s /\ f x IN t})) /\
+   (!f:real^M->real^N s.
+      lebesgue_measurable s
+      ==> (f measurable_on s <=>
+           !a b. lebesgue_measurable {x | x IN s /\ f x IN interval[a,b]})) /\
+   (!f:real^M->real^N s.
+      lebesgue_measurable s
+      ==> (f measurable_on s <=>
+           !t. open t ==> lebesgue_measurable {x | x IN s /\ f x IN t})) /\
+   (!f:real^M->real^N s.
+      lebesgue_measurable s
+      ==> (f measurable_on s <=>
+           !a k. 1 <= k /\ k <= dimindex(:N)
+                 ==> lebesgue_measurable {x | x IN s /\ (f x)$k >= a})) /\
+   (!f:real^M->real^N s.
+      lebesgue_measurable s
+      ==> (f measurable_on s <=>
+           !a k. 1 <= k /\ k <= dimindex(:N)
+                 ==> lebesgue_measurable {x | x IN s /\ (f x)$k > a})) /\
+   (!f:real^M->real^N s.
+      lebesgue_measurable s
+      ==> (f measurable_on s <=>
+           !a k. 1 <= k /\ k <= dimindex(:N)
+                 ==> lebesgue_measurable {x | x IN s /\ (f x)$k <= a})) /\
+   (!f:real^M->real^N s.
+      lebesgue_measurable s
+      ==> (f measurable_on s <=>
+           !a k. 1 <= k /\ k <= dimindex(:N)
+                 ==> lebesgue_measurable {x | x IN s /\ (f x)$k < a})) /\
+   (!f:real^M->real^N s.
+      lebesgue_measurable s
+      ==> (f measurable_on s <=>
+           !a b. lebesgue_measurable {x | x IN s /\ f x IN interval(a,b)}))`,
+  let lemma = prove
+   (`!f s P. {x | P(if x IN s then f x else vec 0)} =
+             if P(vec 0) then s INTER {x | P(f x)} UNION ((:real^M) DIFF s)
+             else {x | x IN s /\ P(f x)}`,
+    REPEAT GEN_TAC THEN
+    COND_CASES_TAC THEN REPEAT(POP_ASSUM MP_TAC) THEN SET_TAC[]) in
+  ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN  REPEAT STRIP_TAC THENL
+   [REWRITE_TAC[MEASURABLE_ON_PREIMAGE_CLOSED];
+    REWRITE_TAC[MEASURABLE_ON_PREIMAGE_CLOSED_INTERVAL];
+    REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN];
+    REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE];
+    REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT];
+    REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE];
+    REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT];
+    REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN_INTERVAL]] THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `s:real^M->bool`] lemma) THEN
+  DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN
+  REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+  TRY(MATCH_MP_TAC(TAUT `(q <=> q') ==> (p ==> q <=> p ==> q')`)) THEN
+  COND_CASES_TAC THEN REWRITE_TAC[] THEN
+  REWRITE_TAC[SET_RULE `{x | x IN s /\ P x} = s INTER {x | P x}`] THEN
+  EQ_TAC THEN
+  ASM_SIMP_TAC[LEBESGUE_MEASURABLE_UNION; LEBESGUE_MEASURABLE_COMPL] THEN
+  UNDISCH_TAC `lebesgue_measurable(s:real^M->bool)` THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LEBESGUE_MEASURABLE_INTER) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN SET_TAC[]);;
+
+let LEBESGUE_MEASURABLE_LEBESGUE_MEASURABLE_PREIMAGE_OPEN = prove
+ (`!f:real^M->real^N s t.
+        f measurable_on s /\ lebesgue_measurable s /\ open t
+        ==> lebesgue_measurable {x | x IN s /\ f(x) IN t}`,
+  MESON_TAC[MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN]);;
+
+let LEBESGUE_MEASURABLE_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED = prove
+ (`!f:real^M->real^N s t.
+        f measurable_on s /\ lebesgue_measurable s /\ closed t
+        ==> lebesgue_measurable {x | x IN s /\ f(x) IN t}`,
+  MESON_TAC[MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED]);;
+
+let MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_EQ = prove
+ (`!f:real^M->real^N s.
+        f measurable_on s /\ lebesgue_measurable s <=>
+        !t. open t ==> lebesgue_measurable {x | x IN s /\ f(x) IN t}`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  SIMP_TAC[LEBESGUE_MEASURABLE_LEBESGUE_MEASURABLE_PREIMAGE_OPEN] THEN
+  DISCH_THEN(fun th -> MP_TAC th THEN MP_TAC(SPEC `(:real^N)` th)) THEN
+  REWRITE_TAC[OPEN_UNIV; SET_RULE `{x | x IN s /\ f x IN UNIV} = s`] THEN
+  SIMP_TAC[MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN]);;
+
+let MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED_EQ = prove
+ (`!f:real^M->real^N s.
+        f measurable_on s /\ lebesgue_measurable s <=>
+        !t. closed t ==> lebesgue_measurable {x | x IN s /\ f(x) IN t}`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  SIMP_TAC[LEBESGUE_MEASURABLE_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED] THEN
+  DISCH_THEN(fun th -> MP_TAC th THEN MP_TAC(SPEC `(:real^N)` th)) THEN
+  REWRITE_TAC[CLOSED_UNIV; SET_RULE `{x | x IN s /\ f x IN UNIV} = s`] THEN
+  SIMP_TAC[MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED]);;
+
+let [MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED;
+     MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED_INTERVAL;
+     MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN;
+     MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE;
+     MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT;
+     MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE;
+     MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT;
+     MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_INTERVAL] =
+  (CONJUNCTS o prove)
+ (`(!f:real^M->real^N s.
+      measurable s
+      ==> (f measurable_on s <=>
+           !t. closed t ==> measurable {x | x IN s /\ f x IN t})) /\
+   (!f:real^M->real^N s.
+      measurable s
+      ==> (f measurable_on s <=>
+           !a b. measurable {x | x IN s /\ f x IN interval[a,b]})) /\
+   (!f:real^M->real^N s.
+      measurable s
+      ==> (f measurable_on s <=>
+           !t. open t ==> measurable {x | x IN s /\ f x IN t})) /\
+   (!f:real^M->real^N s.
+      measurable s
+      ==> (f measurable_on s <=>
+           !a k. 1 <= k /\ k <= dimindex(:N)
+                 ==> measurable {x | x IN s /\ (f x)$k >= a})) /\
+   (!f:real^M->real^N s.
+      measurable s
+      ==> (f measurable_on s <=>
+           !a k. 1 <= k /\ k <= dimindex(:N)
+                 ==> measurable {x | x IN s /\ (f x)$k > a})) /\
+   (!f:real^M->real^N s.
+      measurable s
+      ==> (f measurable_on s <=>
+           !a k. 1 <= k /\ k <= dimindex(:N)
+                 ==> measurable {x | x IN s /\ (f x)$k <= a})) /\
+   (!f:real^M->real^N s.
+      measurable s
+      ==> (f measurable_on s <=>
+           !a k. 1 <= k /\ k <= dimindex(:N)
+                 ==> measurable {x | x IN s /\ (f x)$k < a})) /\
+   (!f:real^M->real^N s.
+      measurable s
+      ==> (f measurable_on s <=>
+           !a b. measurable {x | x IN s /\ f x IN interval(a,b)}))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP MEASURABLE_IMP_LEBESGUE_MEASURABLE) THENL
+   [ASM_SIMP_TAC[MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED];
+    ASM_SIMP_TAC[MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED_INTERVAL];
+    ASM_SIMP_TAC[MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN];
+    ASM_SIMP_TAC
+     [MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE];
+    ASM_SIMP_TAC
+     [MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT];
+    ASM_SIMP_TAC
+     [MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE];
+    ASM_SIMP_TAC
+     [MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT];
+    ASM_SIMP_TAC
+     [MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_INTERVAL]] THEN
+  EQ_TAC THEN SIMP_TAC[MEASURABLE_IMP_LEBESGUE_MEASURABLE] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_LEGESGUE_MEASURABLE_SUBSET THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_SIMP_TAC[] THEN SET_TAC[]);;
+
+let MEASURABLE_MEASURABLE_PREIMAGE_OPEN = prove
+ (`!f:real^M->real^N s t.
+        f measurable_on s /\ measurable s /\ open t
+        ==> measurable {x | x IN s /\ f(x) IN t}`,
+  MESON_TAC[MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN]);;
+
+let MEASURABLE_MEASURABLE_PREIMAGE_CLOSED = prove
+ (`!f:real^M->real^N s t.
+        f measurable_on s /\ measurable s /\ closed t
+        ==> measurable {x | x IN s /\ f(x) IN t}`,
+  MESON_TAC[MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED]);;
+
+let MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_EQ = prove
+ (`!f:real^M->real^N s.
+        f measurable_on s /\ measurable s <=>
+        !t. open t ==> measurable {x | x IN s /\ f(x) IN t}`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  SIMP_TAC[MEASURABLE_MEASURABLE_PREIMAGE_OPEN] THEN
+  DISCH_THEN(fun th -> MP_TAC th THEN MP_TAC(SPEC `(:real^N)` th)) THEN
+  REWRITE_TAC[OPEN_UNIV; SET_RULE `{x | x IN s /\ f x IN UNIV} = s`] THEN
+  SIMP_TAC[MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN]);;
+
+let MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED_EQ = prove
+ (`!f:real^M->real^N s.
+        f measurable_on s /\ measurable s <=>
+        !t. closed t ==> measurable {x | x IN s /\ f(x) IN t}`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  SIMP_TAC[MEASURABLE_MEASURABLE_PREIMAGE_CLOSED] THEN
+  DISCH_THEN(fun th -> MP_TAC th THEN MP_TAC(SPEC `(:real^N)` th)) THEN
+  REWRITE_TAC[CLOSED_UNIV; SET_RULE `{x | x IN s /\ f x IN UNIV} = s`] THEN
+  SIMP_TAC[MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Regularity properties and Steinhaus, this time for Lebesgue measure.      *)
+(* ------------------------------------------------------------------------- *)
+
+let LEBESGUE_MEASURABLE_OUTER_OPEN = prove
+ (`!s:real^N->bool e.
+        lebesgue_measurable s /\ &0 < e
+        ==> ?t. open t /\
+                s SUBSET t /\
+                measurable(t DIFF s) /\
+                measure(t DIFF s) < e`,
+  REPEAT STRIP_TAC THEN MP_TAC(GEN `n:num`
+   (ISPECL [`s INTER ball(vec 0:real^N,&2 pow n)`;
+            `e / &4 / &2 pow n`]
+        MEASURABLE_OUTER_OPEN)) THEN
+  ASM_SIMP_TAC[MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE; REAL_LT_DIV;
+               MEASURABLE_BALL; REAL_LT_INV_EQ; REAL_LT_POW2;
+               REAL_ARITH `&0 < e / &4 <=> &0 < e`] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM; FORALL_AND_THM] THEN
+  X_GEN_TAC `t:num->real^N->bool` THEN STRIP_TAC THEN
+  EXISTS_TAC `UNIONS(IMAGE t (:num)):real^N->bool` THEN
+  ASM_SIMP_TAC[OPEN_UNIONS; FORALL_IN_IMAGE] THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; UNIONS_IMAGE; IN_ELIM_THM; IN_UNIV] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MP_TAC(ISPEC `norm(x:real^N)` REAL_ARCH_POW2) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `n:num` THEN
+    DISCH_TAC THEN RULE_ASSUM_TAC(REWRITE_RULE[SUBSET]) THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[IN_BALL_0; IN_INTER];
+    REWRITE_TAC[UNIONS_DIFF; SET_RULE
+     `{f x | x IN IMAGE g s} = {f(g(x)) | x IN s}`] THEN
+    MATCH_MP_TAC(MESON[REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`]
+        `&0 < e /\ P /\ x <= e / &2 ==> P /\ x < e`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MEASURE_COUNTABLE_UNIONS_LE THEN
+    ASM_SIMP_TAC[MEASURABLE_MEASURABLE_DIFF_LEGESGUE_MEASURABLE] THEN
+    X_GEN_TAC `n:num` THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum(0..n) (\i. e / &4 / &2 pow i)` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC SUM_LE_NUMSEG THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `measure(t i DIFF (s INTER ball(vec 0:real^N,&2 pow i)))` THEN
+      REWRITE_TAC[] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC MEASURE_SUBSET THEN
+        ASM_SIMP_TAC[MEASURABLE_MEASURABLE_DIFF_LEGESGUE_MEASURABLE;
+          MEASURABLE_INTER; MEASURABLE_BALL; LEBESGUE_MEASURABLE_INTER;
+          MEASURABLE_IMP_LEBESGUE_MEASURABLE] THEN
+        SET_TAC[];
+        ASM_SIMP_TAC[MEASURE_DIFF_SUBSET; MEASURABLE_DIFF; MEASURABLE_BALL;
+                     MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE] THEN
+        ASM_SIMP_TAC[REAL_ARITH `t < s + e ==> t - s <= e`]];
+      REWRITE_TAC[real_div; SUM_LMUL; REAL_INV_POW; SUM_GP] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[CONJUNCT1 LT] THEN
+      ASM_SIMP_TAC[GSYM REAL_MUL_ASSOC; REAL_LE_LMUL_EQ] THEN
+      REWRITE_TAC[REAL_ARITH
+        `&1 / &4 * (&1 - x) * &2 <= &1 / &2 <=> &0 <= x`] THEN
+      MATCH_MP_TAC REAL_POW_LE THEN CONV_TAC REAL_RAT_REDUCE_CONV]]);;
+
+let LEBESGUE_MEASURABLE_INNER_CLOSED = prove
+ (`!s:real^N->bool e.
+        lebesgue_measurable s /\ &0 < e
+        ==> ?t. closed t /\
+                t SUBSET s /\
+                measurable(s DIFF t) /\
+                measure(s DIFF t) < e`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM LEBESGUE_MEASURABLE_COMPL] THEN
+  DISCH_THEN(X_CHOOSE_TAC `t:real^N->bool` o MATCH_MP
+    LEBESGUE_MEASURABLE_OUTER_OPEN) THEN
+  EXISTS_TAC `(:real^N) DIFF t` THEN POP_ASSUM MP_TAC THEN
+  REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THEN
+  REWRITE_TAC[GSYM OPEN_CLOSED] THENL
+   [SET_TAC[];
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC;
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC] THEN
+  SET_TAC[]);;
+
+let STEINHAUS_LEBESGUE = prove
+ (`!s:real^N->bool.
+        lebesgue_measurable s /\ ~negligible s
+        ==> ?d. &0 < d /\ ball(vec 0,d) SUBSET {x - y | x IN s /\ y IN s}`,
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ONCE_REWRITE_TAC[NEGLIGIBLE_ON_INTERVALS] THEN
+  REWRITE_TAC[NOT_FORALL_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  MP_TAC(ISPEC `s INTER interval[a:real^N,b]` STEINHAUS) THEN
+  ASM_SIMP_TAC[GSYM MEASURABLE_MEASURE_POS_LT; MEASURABLE_INTERVAL;
+               MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE] THEN
+  SET_TAC[]);;
+
+let LEBESGUE_MEASURABLE_REGULAR_OUTER = prove
+ (`!s:real^N->bool.
+        lebesgue_measurable s
+        ==> ?k c. negligible k /\ (!n. open(c n)) /\
+                  s = INTERS {c n | n IN (:num)} DIFF k`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    LEBESGUE_MEASURABLE_OUTER_OPEN)) THEN
+  DISCH_THEN(MP_TAC o GEN `n:num` o SPEC `inv(&2 pow n)`) THEN
+  REWRITE_TAC[REAL_LT_POW2; SKOLEM_THM; REAL_LT_INV_EQ] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; FORALL_AND_THM] THEN
+  X_GEN_TAC `c:num->real^N->bool` THEN STRIP_TAC THEN
+  EXISTS_TAC `INTERS {c n | n IN (:num)} DIFF s:real^N->bool` THEN
+  EXISTS_TAC `c:num->real^N->bool` THEN
+  ASM_REWRITE_TAC[SET_RULE `s = t DIFF (t DIFF s) <=> s SUBSET t`] THEN
+  ASM_REWRITE_TAC[SUBSET_INTERS; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[NEGLIGIBLE_OUTER_LE] THEN 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; REWRITE_TAC[REAL_POW_INV]] THEN
+  DISCH_THEN(X_CHOOSE_TAC `n:num`) THEN
+  EXISTS_TAC `(c:num->real^N->bool) n DIFF s` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [SET_TAC[]; ASM_MESON_TAC[REAL_LT_IMP_LE; REAL_LE_TRANS]]);;
+
+let LEBESGUE_MEASURABLE_REGULAR_INNER = prove
+ (`!s:real^N->bool.
+        lebesgue_measurable s
+        ==> ?k c. negligible k /\ (!n. compact(c n)) /\
+                  s = UNIONS {c n | n IN (:num)} UNION k`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    LEBESGUE_MEASURABLE_INNER_CLOSED)) THEN
+  DISCH_THEN(MP_TAC o GEN `n:num` o SPEC `inv(&2 pow n)`) THEN
+  REWRITE_TAC[REAL_LT_POW2; SKOLEM_THM; REAL_LT_INV_EQ] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; FORALL_AND_THM] THEN
+  X_GEN_TAC `c:num->real^N->bool` THEN STRIP_TAC THEN
+  EXISTS_TAC `s DIFF UNIONS {c n | n IN (:num)}:real^N->bool` THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN CONJ_TAC THENL
+   [REWRITE_TAC[NEGLIGIBLE_OUTER_LE] THEN 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; REWRITE_TAC[REAL_POW_INV]] THEN
+    DISCH_THEN(X_CHOOSE_TAC `n:num`) THEN
+    EXISTS_TAC `s DIFF (c:num->real^N->bool) n` THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [SET_TAC[]; ASM_MESON_TAC[REAL_LT_IMP_LE; REAL_LE_TRANS]];
+    SUBGOAL_THEN
+     `?d. (!n. compact(d n:real^N->bool)) /\
+          UNIONS {d n | n IN (:num)} = UNIONS {c n | n IN (:num)}`
+    MP_TAC THENL
+     [MP_TAC(GEN `n:num` (ISPEC
+       `(c:num->real^N->bool) n` CLOSED_UNION_COMPACT_SUBSETS)) THEN
+      ASM_REWRITE_TAC[SKOLEM_THM; FORALL_AND_THM] THEN DISCH_THEN
+       (X_CHOOSE_THEN `d:num->num->real^N->bool` STRIP_ASSUME_TAC) THEN
+      SUBGOAL_THEN
+       `COUNTABLE {d n m:real^N->bool | n IN (:num) /\ m IN (:num)}`
+      MP_TAC THENL
+       [MATCH_MP_TAC COUNTABLE_PRODUCT_DEPENDENT THEN
+        REWRITE_TAC[NUM_COUNTABLE];
+        DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          COUNTABLE_AS_IMAGE)) THEN
+        ANTS_TAC THENL [SET_TAC[]; MATCH_MP_TAC MONO_EXISTS] THEN
+        ASM SET_TAC[]];
+      MATCH_MP_TAC MONO_EXISTS THEN
+      REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      ASM_REWRITE_TAC[SET_RULE `s = t UNION (s DIFF t) <=> t SUBSET s`] THEN
+      ASM_REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Existence of nonmeasurable subsets of any set of positive measure.        *)
+(* ------------------------------------------------------------------------- *)
+
+let NEGLIGIBLE_IFF_LEBESGUE_MEASURABLE_SUBSETS = prove
+ (`!s:real^N->bool. negligible s <=> !t. t SUBSET s ==> lebesgue_measurable t`,
+  let lemma = prove
+   (`!s:real^N->bool.
+      lebesgue_measurable s /\
+      (!x y q. x IN s /\ y IN s /\ rational q /\ y = q % basis 1 + x ==> y = x)
+      ==> negligible s`,
+    SIMP_TAC[VECTOR_ARITH `q + x:real^N = x <=> q = vec 0`; VECTOR_MUL_EQ_0;
+             BASIS_NONZERO; DIMINDEX_GE_1; ARITH] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN
+    DISCH_TAC THEN MP_TAC(ISPEC `s:real^N->bool` STEINHAUS_LEBESGUE) THEN
+    ASM_REWRITE_TAC[NOT_EXISTS_THM] THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+    FIRST_ASSUM(X_CHOOSE_TAC `q:real` o MATCH_MP RATIONAL_BETWEEN) THEN
+    FIRST_X_ASSUM
+     (MP_TAC o SPEC `q % basis 1:real^N` o GEN_REWRITE_RULE I [SUBSET]) THEN
+    SIMP_TAC[IN_BALL_0; NORM_MUL; NORM_BASIS; DIMINDEX_GE_1;
+             ARITH; NOT_IMP] THEN
+    CONJ_TAC THENL [ASM_REAL_ARITH_TAC; REWRITE_TAC[IN_ELIM_THM]] THEN
+    ASM_REWRITE_TAC[REAL_MUL_RID; IN_ELIM_THM; NOT_EXISTS_THM;
+                    VECTOR_ARITH `q:real^N = x - y <=> x = q + y`] THEN
+    ASM_CASES_TAC `q = &0` THENL [ASM_REAL_ARITH_TAC; ASM_MESON_TAC[]]) in
+  GEN_TAC THEN EQ_TAC THENL
+   [MESON_TAC[NEGLIGIBLE_SUBSET; NEGLIGIBLE_IMP_LEBESGUE_MEASURABLE];
+    DISCH_TAC] THEN
+  ABBREV_TAC
+   `(canonize:real^N->real^N) =
+    \x. @y. y IN s /\ ?q. rational q /\ q % basis 1 + y = x` THEN
+  SUBGOAL_THEN
+   `!x:real^N. x IN s
+               ==> canonize x IN s /\
+                   ?q. rational q /\ q % basis 1 + canonize x = x`
+  ASSUME_TAC THENL
+   [GEN_TAC THEN DISCH_TAC THEN EXPAND_TAC "canonize" THEN
+    CONV_TAC SELECT_CONV THEN EXISTS_TAC `x:real^N` THEN
+    ASM_REWRITE_TAC[] THEN EXISTS_TAC `&0` THEN
+    REWRITE_TAC[RATIONAL_CLOSED] THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  ABBREV_TAC `v = IMAGE (canonize:real^N->real^N) s` THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC
+   `UNIONS (IMAGE (\q. IMAGE (\x:real^N. q % basis 1 + x) v) rational)` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[UNIONS_IMAGE; SUBSET; IN_ELIM_THM] THEN ASM SET_TAC[]] THEN
+  MATCH_MP_TAC NEGLIGIBLE_COUNTABLE_UNIONS_GEN THEN
+  SIMP_TAC[COUNTABLE_RATIONAL; COUNTABLE_IMAGE; FORALL_IN_IMAGE] THEN
+  ASM_REWRITE_TAC[NEGLIGIBLE_TRANSLATION_EQ] THEN GEN_TAC THEN
+  DISCH_THEN(K ALL_TAC) THEN MATCH_MP_TAC lemma THEN
+  CONJ_TAC THENL [FIRST_ASSUM MATCH_MP_TAC THEN ASM SET_TAC[]; ALL_TAC] THEN
+  EXPAND_TAC "v" THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ; FORALL_IN_IMAGE] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+  X_GEN_TAC `q:real` THEN REPEAT DISCH_TAC THEN
+  EXPAND_TAC "canonize" THEN AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN
+  X_GEN_TAC `z:real^N` THEN AP_TERM_TAC THEN FIRST_X_ASSUM(fun th ->
+    MP_TAC(SPEC `y:real^N` th) THEN MP_TAC(SPEC `x:real^N` th)) THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH `q % b + x:real^N = y <=> x = y - q % b`] THEN
+  STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH `x - q % b:real^N = y - r % b - s % b <=>
+                   y + (q - r - s) % b = x /\ x + (r + s - q) % b = y`] THEN
+  STRIP_TAC THEN EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC
+   (BINDER_CONV o RAND_CONV o RAND_CONV o LAND_CONV) [SYM th]) THEN
+  SIMP_TAC[VECTOR_MUL_EQ_0; BASIS_NONZERO; DIMINDEX_GE_1; ARITH; VECTOR_ARITH
+   `y - q % b:real^N = (y + r % b) - s % b <=> (q + r - s) % b = vec 0`] THEN
+  ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  REWRITE_TAC[REAL_ARITH `a + b - c = &0 <=> c = a + b`; UNWIND_THM2] THEN
+  ASM_SIMP_TAC[RATIONAL_CLOSED]);;
+
+let NEGLIGIBLE_IFF_MEASURABLE_SUBSETS = prove
+ (`!s:real^N->bool. negligible s <=> !t. t SUBSET s ==> measurable t`,
+  MESON_TAC[NEGLIGIBLE_SUBSET; NEGLIGIBLE_IMP_MEASURABLE;
+            MEASURABLE_IMP_LEBESGUE_MEASURABLE;
+            NEGLIGIBLE_IFF_LEBESGUE_MEASURABLE_SUBSETS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Preserving Lebesgue measurability vs. preserving negligibility.           *)
+(* ------------------------------------------------------------------------- *)
+
+let PRESERVES_LEBESGUE_MEASURABLE_IMP_PRESERVES_NEGLIGIBLE = prove
+ (`!f s:real^N->bool.
+        (!t. negligible t /\ t SUBSET s ==> lebesgue_measurable(IMAGE f t))
+        ==> (!t. negligible t /\ t SUBSET s ==> negligible(IMAGE f t))`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[NEGLIGIBLE_IFF_LEBESGUE_MEASURABLE_SUBSETS] THEN
+  REWRITE_TAC[FORALL_SUBSET_IMAGE] THEN
+  ASM_MESON_TAC[NEGLIGIBLE_SUBSET; SUBSET_TRANS]);;
+
+let LEBESGUE_MEASURABLE_CONTINUOUS_IMAGE = prove
+ (`!f:real^M->real^N s.
+        f continuous_on s /\
+        (!t. negligible t /\ t SUBSET s ==> negligible(IMAGE f t))
+        ==> !t. lebesgue_measurable t /\ t SUBSET s
+                ==> lebesgue_measurable(IMAGE f t)`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(STRIP_ASSUME_TAC o
+    MATCH_MP LEBESGUE_MEASURABLE_REGULAR_INNER) THEN
+  ASM_REWRITE_TAC[IMAGE_UNION; IMAGE_UNIONS] THEN
+  MATCH_MP_TAC LEBESGUE_MEASURABLE_UNION THEN
+  SUBGOAL_THEN `(k:real^M->bool) SUBSET s` ASSUME_TAC THENL
+   [ASM SET_TAC[]; ASM_SIMP_TAC[NEGLIGIBLE_IMP_LEBESGUE_MEASURABLE]] THEN
+  MATCH_MP_TAC LEBESGUE_MEASURABLE_COUNTABLE_UNIONS THEN
+  REWRITE_TAC[SIMPLE_IMAGE; GSYM IMAGE_o; FORALL_IN_IMAGE] THEN
+  SIMP_TAC[IN_UNIV; COUNTABLE_IMAGE; NUM_COUNTABLE] THEN
+  GEN_TAC THEN MATCH_MP_TAC LEBESGUE_MEASURABLE_COMPACT THEN
+  MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    CONTINUOUS_ON_SUBSET)) THEN ASM SET_TAC[]);;
+
+let LEBESGUE_MEASURABLE_DIFFERENTIABLE_IMAGE = prove
+ (`!f:real^M->real^N s.
+        dimindex(:M) <= dimindex(:N) /\
+        f differentiable_on s /\ lebesgue_measurable s
+        ==> lebesgue_measurable(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC
+   (REWRITE_RULE[IMP_IMP; RIGHT_IMP_FORALL_THM]
+        LEBESGUE_MEASURABLE_CONTINUOUS_IMAGE) THEN
+  EXISTS_TAC `s:real^M->bool` THEN
+  ASM_SIMP_TAC[SUBSET_REFL; DIFFERENTIABLE_IMP_CONTINUOUS_ON] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC NEGLIGIBLE_DIFFERENTIABLE_IMAGE_NEGLIGIBLE THEN
+  ASM_MESON_TAC[DIFFERENTIABLE_ON_SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Measurability of continuous functions.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_IMP_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET = prove
+ (`!f:real^M->real^N s.
+        f continuous_on s /\ lebesgue_measurable s
+        ==> f measurable_on s`,
+  let lemma = prove
+   (`!s. lebesgue_measurable s
+         ==> ?u:num->real^M->bool.
+                (!n. closed(u n)) /\ (!n. u n SUBSET s) /\
+                (!n. measurable(s DIFF u n) /\
+                     measure(s DIFF u n) < inv(&n + &1)) /\
+                (!n. u(n) SUBSET u(SUC n))`,
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+     `!n t. closed t /\ t SUBSET s
+            ==> ?u:real^M->bool.
+                      closed u /\ t SUBSET u /\ u SUBSET s /\
+                      measurable(s DIFF u) /\ measure(s DIFF u) < inv(&n + &1)`
+    MP_TAC THENL
+     [REPEAT STRIP_TAC THEN
+      MP_TAC(ISPECL [`s DIFF t:real^M->bool`; `inv(&n + &1)`]
+        LEBESGUE_MEASURABLE_INNER_CLOSED) THEN
+      ASM_SIMP_TAC[LEBESGUE_MEASURABLE_DIFF; LEBESGUE_MEASURABLE_CLOSED] THEN
+      REWRITE_TAC[REAL_LT_INV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+      DISCH_THEN(X_CHOOSE_THEN `u:real^M->bool` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `t UNION u:real^M->bool` THEN ASM_SIMP_TAC[CLOSED_UNION] THEN
+      CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+      CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[SET_RULE `s DIFF (t UNION u) = s DIFF t DIFF u`];
+      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 `v:num->(real^M->bool)->(real^M->bool)` THEN DISCH_TAC THEN
+      MP_TAC(prove_recursive_functions_exist num_RECURSION
+          `(u:num->real^M->bool) 0 = v 0 {} /\
+           (!n. u(SUC n) = v (SUC n) (u n))`) THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:num->real^M->bool` THEN
+      STRIP_TAC THEN
+      SUBGOAL_THEN
+       `!n. closed(u n) /\ (u:num->real^M->bool) n SUBSET s`
+      ASSUME_TAC THENL
+       [INDUCT_TAC THEN
+        ASM_SIMP_TAC[CLOSED_EMPTY; EMPTY_SUBSET];
+        ASM_SIMP_TAC[]] THEN
+      INDUCT_TAC THEN ONCE_ASM_REWRITE_TAC[] THEN
+      ASM_SIMP_TAC[CLOSED_EMPTY; EMPTY_SUBSET]]) in
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `u:num->real^M->bool` STRIP_ASSUME_TAC o
+    MATCH_MP lemma) THEN
+  SUBGOAL_THEN `lebesgue_measurable((:real^M) DIFF s)` MP_TAC THENL
+   [ASM_REWRITE_TAC[LEBESGUE_MEASURABLE_COMPL]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:num->real^M->bool` STRIP_ASSUME_TAC o
+    MATCH_MP lemma) THEN
+  REWRITE_TAC[measurable_on] THEN
+  EXISTS_TAC `(:real^M) DIFF
+           (UNIONS {u n | n IN (:num)} UNION UNIONS {v n | n IN (:num)})` THEN
+  SUBGOAL_THEN
+   `!n. ?g. g continuous_on (:real^M) /\
+            (!x. x IN u(n) UNION v(n:num)
+                 ==> g x = if x IN s then (f:real^M->real^N)(x) else vec 0)`
+  MP_TAC THENL
+   [X_GEN_TAC `n:num` THEN MATCH_MP_TAC TIETZE_UNBOUNDED THEN
+    ASM_SIMP_TAC[SUBTOPOLOGY_UNIV; GSYM CLOSED_IN; CLOSED_UNION] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CASES THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_CONST] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ASM SET_TAC[]];
+    REWRITE_TAC[SKOLEM_THM] THEN MATCH_MP_TAC MONO_EXISTS] THEN
+  X_GEN_TAC `g:num->real^M->real^N` THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+    EXISTS_TAC `(s DIFF UNIONS {u n | n IN (:num)}) UNION
+                ((:real^M) DIFF s DIFF UNIONS {v n | n IN (:num)})` THEN
+    CONJ_TAC THENL [ALL_TAC; SET_TAC[]] THEN
+    MATCH_MP_TAC NEGLIGIBLE_UNION THEN CONJ_TAC THEN
+    REWRITE_TAC[NEGLIGIBLE_OUTER] THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    MP_TAC(ISPEC `e:real` REAL_ARCH_INV) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:num` STRIP_ASSUME_TAC) THENL
+     [EXISTS_TAC `s DIFF u(n:num):real^M->bool`;
+      EXISTS_TAC `(:real^M) DIFF s DIFF v(n:num):real^M->bool`] THEN
+    (CONJ_TAC THENL [SET_TAC[]; ASM_REWRITE_TAC[]] THEN
+     MATCH_MP_TAC REAL_LT_TRANS THEN
+     EXISTS_TAC `inv(&n + &1)` THEN ASM_REWRITE_TAC[] THEN
+     MATCH_MP_TAC REAL_LT_TRANS THEN
+     EXISTS_TAC `inv(&n)` THEN ASM_REWRITE_TAC[] THEN
+     MATCH_MP_TAC REAL_LT_INV2 THEN ASM_REWRITE_TAC[REAL_OF_NUM_LT] THEN
+     CONJ_TAC THENL [ASM_ARITH_TAC; REAL_ARITH_TAC]);
+    X_GEN_TAC `x:real^M` THEN REWRITE_TAC[SET_RULE
+     `~(x IN (UNIV DIFF (s UNION t))) <=> x IN s \/ x IN t`] THEN
+    REWRITE_TAC[UNIONS_GSPEC; IN_ELIM_THM; IN_UNIV] THEN
+    REWRITE_TAC[OR_EXISTS_THM] THEN
+    DISCH_THEN(X_CHOOSE_TAC `n:num`) THEN
+    MATCH_MP_TAC LIM_EVENTUALLY THEN
+    REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+    EXISTS_TAC `n:num` THEN X_GEN_TAC `m:num` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_UNION] THEN
+    SUBGOAL_THEN
+     `!i j. i <= j ==> (u:num->real^M->bool)(i) SUBSET u(j) /\
+                       (v:num->real^M->bool)(i) SUBSET v(j)`
+     (fun th -> ASM_MESON_TAC[SUBSET; th]) THEN
+    MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN
+   ASM_REWRITE_TAC[] THEN SET_TAC[]]);;
+
+let CONTINUOUS_IMP_MEASURABLE_ON_CLOSED_SUBSET = prove
+ (`!f:real^M->real^N s.
+        f continuous_on s /\ closed s ==> f measurable_on s`,
+  SIMP_TAC[CONTINUOUS_IMP_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET;
+           LEBESGUE_MEASURABLE_CLOSED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Measurability of a.e. derivatives.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_ON_VECTOR_DERIVATIVE = prove
+ (`!f:real^1->real^N f' s k.
+        negligible k /\ negligible(frontier s) /\
+        (!x. x IN (s DIFF k) ==> (f has_vector_derivative f'(x)) (at x))
+        ==> f' measurable_on s`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+  ABBREV_TAC `g:real^1->real^N = \x. if x IN s then f(x) else vec 0` THEN
+  SUBGOAL_THEN `(g:real^1->real^N) measurable_on (:real^1)` ASSUME_TAC THENL
+   [EXPAND_TAC "g" THEN REWRITE_TAC[MEASURABLE_ON_UNIV] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_IMP] MEASURABLE_ON_SPIKE_SET) THEN
+    EXISTS_TAC `s DIFF k:real^1->bool` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+      EXISTS_TAC `k:real^1->bool` THEN ASM_REWRITE_TAC[] THEN SET_TAC[];
+      MATCH_MP_TAC CONTINUOUS_IMP_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC DIFFERENTIABLE_IMP_CONTINUOUS_ON THEN
+        MATCH_MP_TAC DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON THEN
+        ASM_MESON_TAC[differentiable; has_vector_derivative];
+        MATCH_MP_TAC LEBESGUE_MEASURABLE_DIFF THEN
+        ASM_SIMP_TAC[NEGLIGIBLE_IMP_LEBESGUE_MEASURABLE] THEN
+        ASM_SIMP_TAC[LEBESGUE_MEASURABLE_JORDAN]]];
+     ALL_TAC] THEN
+  MATCH_MP_TAC MEASURABLE_ON_LIMIT THEN
+  EXISTS_TAC `\n x. (&n + &1) % (g(x + lift(inv(&n + &1))) - g(x):real^N)` THEN
+  EXISTS_TAC `k UNION frontier s:real^1->bool` THEN
+  ASM_REWRITE_TAC[NEGLIGIBLE_UNION_EQ] THEN CONJ_TAC THENL
+   [X_GEN_TAC `n:num` THEN MATCH_MP_TAC MEASURABLE_ON_CMUL THEN
+    MATCH_MP_TAC MEASURABLE_ON_SUB THEN ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[VECTOR_ADD_SYM] THEN
+    REWRITE_TAC[MEASURABLE_ON_TRANSLATION_EQ] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[]
+     `g measurable_on s ==> t = s ==> g measurable_on t`)) THEN
+    MATCH_MP_TAC(SET_RULE
+     `!g. (!x. f(g x) = x /\ g(f x) = x) ==> IMAGE f UNIV = UNIV`) THEN
+    EXISTS_TAC `\x. --(lift(inv(&n + &1))) + x` THEN VECTOR_ARITH_TAC;
+
+    X_GEN_TAC `x:real^1` THEN
+    REWRITE_TAC[IN_UNIV; IN_DIFF; IN_UNION; DE_MORGAN_THM; frontier;
+                CLOSURE_INTERIOR] THEN
+    STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERIOR]) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM; SUBSET; IN_BALL; IN_DIFF; IN_UNIV] THEN
+    X_GEN_TAC `d:real` THEN ASM_SIMP_TAC[DIST_REFL] THEN STRIP_TAC THEN
+    MATCH_MP_TAC LIM_TRANSFORM_EVENTUALLY THENL
+     [EXISTS_TAC `(\n. vec 0):num->real^N`;
+      EXISTS_TAC `(\n. (&n + &1) % (f(x + lift (inv (&n + &1))) - f x))
+                  :num->real^N`] THEN
+    (CONJ_TAC THENL
+      [REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+       MP_TAC(SPEC `d:real` REAL_ARCH_INV) THEN
+       ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+       X_GEN_TAC `N:num` THEN STRIP_TAC THEN X_GEN_TAC `n:num` THEN
+       DISCH_TAC THEN
+       SUBGOAL_THEN `dist(x,x + lift(inv(&n + &1))) < d` ASSUME_TAC THENL
+        [REWRITE_TAC[NORM_ARITH `dist(a:real^N,a + x) = norm x`] THEN
+         REWRITE_TAC[NORM_LIFT; REAL_ABS_INV] THEN
+         REWRITE_TAC[REAL_ARITH `abs(&n + &1) = &n + &1`] THEN
+         MATCH_MP_TAC REAL_LT_TRANS THEN EXISTS_TAC `inv(&N)` THEN
+         ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LT_INV2 THEN
+         ASM_REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LT] THEN ASM_ARITH_TAC;
+         EXPAND_TAC "g" THEN REWRITE_TAC[] THEN ASM_SIMP_TAC[DIST_REFL] THEN
+         VECTOR_ARITH_TAC];
+       ALL_TAC]) THEN
+     REWRITE_TAC[LIM_CONST] THEN
+     UNDISCH_THEN
+      `!x. x IN s DIFF k
+           ==> ((f:real^1->real^N) has_vector_derivative f' x) (at x)`
+      (MP_TAC o SPEC `x:real^1`) THEN
+     ASM_SIMP_TAC[IN_DIFF; DIST_REFL; has_vector_derivative] THEN
+     REWRITE_TAC[has_derivative; NETLIMIT_AT] THEN
+     DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+     REWRITE_TAC[LIM_AT; LIM_SEQUENTIALLY] 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_TAC `k:real`) THEN
+     MP_TAC(SPEC `k:real` REAL_ARCH_INV) THEN
+     ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+     X_GEN_TAC `N:num` THEN STRIP_TAC THEN X_GEN_TAC `n:num` THEN
+     DISCH_TAC THEN
+     FIRST_X_ASSUM(MP_TAC o SPEC `x +  lift(inv(&n + &1))` o CONJUNCT2) THEN
+     REWRITE_TAC[NORM_ARITH `dist(x + a:real^N,x) = norm a`] THEN
+     REWRITE_TAC[NORM_LIFT; REAL_ABS_INV; REAL_ARITH `abs(&n + &1) = &n + &1`;
+              VECTOR_ARITH `(x + e) - x:real^N = e`; LIFT_DROP] THEN
+     ANTS_TAC THENL
+      [REWRITE_TAC[REAL_LT_INV_EQ] THEN
+       CONJ_TAC THENL [REAL_ARITH_TAC; MATCH_MP_TAC REAL_LT_TRANS] THEN
+       EXISTS_TAC `inv(&N)` THEN
+       ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LT_INV2 THEN
+       ASM_REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LT] THEN ASM_ARITH_TAC;
+       MATCH_MP_TAC(NORM_ARITH
+        `x - y:real^N = z ==> dist(z,vec 0) < e ==> dist(x,y) < e`) THEN
+       REWRITE_TAC[REAL_INV_INV; VECTOR_SUB_LDISTRIB; VECTOR_ADD_LDISTRIB] THEN
+       SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; VECTOR_MUL_LID;
+                REAL_ARITH `~(&n + &1 = &0)`] THEN
+       VECTOR_ARITH_TAC]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Approximation of L_1 functions by bounded continuous ones.                *)
+(* Note that 100/fourier.ml has some generalizations to L_p spaces.          *)
+(* ------------------------------------------------------------------------- *)
+
+let ABSOLUTELY_INTEGRABLE_APPROXIMATE_CONTINUOUS = prove
+ (`!f:real^M->real^N s e.
+        measurable s /\ f absolutely_integrable_on s /\ &0 < e
+        ==> ?g. g absolutely_integrable_on s /\
+                g continuous_on (:real^M) /\
+                bounded (IMAGE g (:real^M)) /\
+                norm(integral s (\x. lift(norm(f x - g x)))) < e`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+    `?h. h absolutely_integrable_on s /\
+         bounded (IMAGE h (:real^M)) /\
+         norm(integral s (\x. lift(norm(f x - h x:real^N)))) < e / &2`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPECL
+     [`\n x. lift(norm
+       (f x - (lambda i. max (--(&n)) (min (&n) ((f:real^M->real^N)(x)$i)))))`;
+      `(\x. vec 0):real^M->real^1`;
+      `\x. lift(norm((f:real^M->real^N)(x)))`;
+      `s:real^M->bool`]
+          DOMINATED_CONVERGENCE) THEN
+    ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN
+     `!n. ((\x. lambda i. max (--(&n)) (min (&n) ((f x:real^N)$i)))
+          :real^M->real^N) absolutely_integrable_on s`
+    ASSUME_TAC THENL
+     [GEN_TAC THEN
+      FIRST_ASSUM(MP_TAC o SPEC `(\x. lambda i. &n):real^M->real^N` o
+        MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] ABSOLUTELY_INTEGRABLE_MIN)) THEN
+      ASM_REWRITE_TAC[ABSOLUTELY_INTEGRABLE_ON_CONST] THEN
+      DISCH_THEN(MP_TAC o SPEC `(\x. lambda i. --(&n)):real^M->real^N` o
+        MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] ABSOLUTELY_INTEGRABLE_MAX)) THEN
+      ASM_REWRITE_TAC[ABSOLUTELY_INTEGRABLE_ON_CONST] THEN
+      MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
+      SIMP_TAC[CART_EQ; LAMBDA_BETA];
+      ALL_TAC] THEN
+    ANTS_TAC THENL
+     [REPEAT CONJ_TAC THENL
+       [X_GEN_TAC `n:num` THEN
+        MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+        MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_NORM THEN
+        ASM_SIMP_TAC[ABSOLUTELY_INTEGRABLE_SUB];
+        ASM_SIMP_TAC[ABSOLUTELY_INTEGRABLE_NORM;
+                     ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE];
+        MAP_EVERY X_GEN_TAC [`n:num`; `x:real^M`] THEN DISCH_TAC THEN
+        REWRITE_TAC[LIFT_DROP; NORM_LIFT; REAL_ABS_NORM] THEN
+        MATCH_MP_TAC NORM_LE_COMPONENTWISE THEN
+        SIMP_TAC[LAMBDA_BETA; VECTOR_SUB_COMPONENT] THEN REAL_ARITH_TAC;
+        X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+        REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+        X_GEN_TAC `d:real` THEN DISCH_TAC THEN
+        MP_TAC(SPEC `norm((f:real^M->real^N) x)` REAL_ARCH_SIMPLE) 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
+        REWRITE_TAC[DIST_0; NORM_LIFT; REAL_ABS_NORM; GSYM LIFT_SUB] THEN
+        MATCH_MP_TAC(NORM_ARITH
+         `&0 < d /\ x = y ==> norm(x:real^N - y) < d`) THEN
+        ASM_SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN REPEAT STRIP_TAC THEN
+        MATCH_MP_TAC(REAL_ARITH
+          `abs(x) <= n ==> x = max (--n) (min n x)`) THEN
+        ASM_MESON_TAC[COMPONENT_LE_NORM; REAL_LE_TRANS; REAL_OF_NUM_LE]];
+      DISCH_THEN(MP_TAC o CONJUNCT2) 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_THEN `n:num` (MP_TAC o SPEC `n:num`)) THEN
+      REWRITE_TAC[INTEGRAL_0; DIST_0; LE_REFL] THEN DISCH_TAC THEN
+      EXISTS_TAC `(\x. lambda i. max (--(&n)) (min (&n)
+                             ((f:real^M->real^N)(x)$i))):real^M->real^N` THEN
+      ASM_REWRITE_TAC[] THEN
+      ONCE_REWRITE_TAC[BOUNDED_COMPONENTWISE] THEN
+      REWRITE_TAC[bounded; FORALL_IN_IMAGE] THEN
+      X_GEN_TAC `i:num` THEN STRIP_TAC THEN EXISTS_TAC `&n` THEN
+      X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+      ASM_SIMP_TAC[NORM_LIFT; LAMBDA_BETA] THEN REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [BOUNDED_POS]) THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; IN_UNIV] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `?k g. negligible k /\
+          (!n. g n continuous_on (:real^M)) /\
+          (!n x. norm(g n x:real^N) <= norm(B % vec 1:real^N)) /\
+          (!x. x IN (s DIFF k)  ==> ((\n. g n x) --> h x) sequentially)`
+  STRIP_ASSUME_TAC THENL
+   [SUBGOAL_THEN `(h:real^M->real^N) measurable_on s` MP_TAC THENL
+     [ASM_MESON_TAC[ABSOLUTELY_INTEGRABLE_MEASURABLE]; ALL_TAC] THEN
+    REWRITE_TAC[measurable_on] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `k:real^M->bool` THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:num->real^M->real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(\n x. lambda i. max (--B) (min B (((g n x):real^N)$i))):
+                num->real^M->real^N` THEN
+    ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [X_GEN_TAC `n:num` THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `n:num`) THEN
+      MP_TAC(ISPECL [`(:real^M)`; `(lambda i. B):real^N`]
+                CONTINUOUS_ON_CONST) THEN
+      REWRITE_TAC[IMP_IMP] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP CONTINUOUS_ON_MIN) THEN
+      MP_TAC(ISPECL [`(:real^M)`; `(lambda i. --B):real^N`]
+                CONTINUOUS_ON_CONST) THEN
+      REWRITE_TAC[IMP_IMP] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP CONTINUOUS_ON_MAX) THEN
+      MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+      SIMP_TAC[FUN_EQ_THM; CART_EQ; LAMBDA_BETA];
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC NORM_LE_COMPONENTWISE THEN
+      SIMP_TAC[LAMBDA_BETA; VEC_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+      REAL_ARITH_TAC;
+      X_GEN_TAC `x:real^M` THEN REWRITE_TAC[IN_DIFF] THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `ee:real` THEN
+      MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `n:num` THEN
+      MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+      MATCH_MP_TAC(NORM_ARITH
+       `norm(c - a:real^N) <= norm(b - a)
+        ==> dist(b,a) < ee ==> dist(c,a) < ee`) THEN
+      MATCH_MP_TAC NORM_LE_COMPONENTWISE THEN
+      SIMP_TAC[LAMBDA_BETA; VECTOR_SUB_COMPONENT] THEN
+      X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP NORM_BOUND_COMPONENT_LE) THEN
+      DISCH_THEN(MP_TAC o SPEC `k:num`) THEN ASM_REWRITE_TAC[] THEN
+      REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n. (g:num->real^M->real^N) n absolutely_integrable_on s`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `n:num` THEN MATCH_MP_TAC
+      MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_ABSOLUTELY_INTEGRABLE THEN
+    EXISTS_TAC `(\x. lift(norm(B % vec 1:real^N))):real^M->real^1` THEN
+    ASM_REWRITE_TAC[LIFT_DROP; INTEGRABLE_ON_CONST] THEN
+    ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+    MATCH_MP_TAC(REWRITE_RULE[lebesgue_measurable; indicator]
+        MEASURABLE_ON_RESTRICT) THEN
+    ASM_SIMP_TAC[CONTINUOUS_IMP_MEASURABLE_ON; ETA_AX] THEN
+    MATCH_MP_TAC INTEGRABLE_IMP_MEASURABLE THEN
+    ASM_REWRITE_TAC[GSYM MEASURABLE_INTEGRABLE];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`\n x. lift(norm((g:num->real^M->real^N) n x - h x))`;
+    `(\x. vec 0):real^M->real^1`;
+    `(\x. lift(B + norm(B % vec 1:real^N))):real^M->real^1`;
+    `s DIFF k:real^M->bool`] DOMINATED_CONVERGENCE) THEN
+  ASM_SIMP_TAC[INTEGRAL_0; INTEGRABLE_ON_CONST; MEASURABLE_DIFF;
+               NEGLIGIBLE_IMP_MEASURABLE] THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[NORM_LIFT; REAL_ABS_NORM] THEN REPEAT CONJ_TAC THENL
+     [GEN_TAC THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_IMP] INTEGRABLE_SPIKE_SET) THEN
+      EXISTS_TAC `s:real^M->bool` THEN
+      ASM_SIMP_TAC[ABSOLUTELY_INTEGRABLE_NORM;
+                   ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE;
+                   ABSOLUTELY_INTEGRABLE_SUB; ETA_AX] THEN
+      MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC `k:real^M->bool` THEN
+      ASM_REWRITE_TAC[] THEN SET_TAC[];
+      REPEAT STRIP_TAC THEN REWRITE_TAC[LIFT_DROP] THEN
+      MATCH_MP_TAC(NORM_ARITH
+       `norm(g:real^N) <= b /\ norm(h) <= a ==> norm(g - h) <= a + b`) THEN
+      ASM_REWRITE_TAC[];
+      ASM_REWRITE_TAC[GSYM LIM_NULL_NORM; GSYM LIM_NULL]];
+    REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:num` (MP_TAC o SPEC `n:num`)) THEN
+    REWRITE_TAC[LE_REFL; DIST_0] THEN DISCH_TAC THEN
+    EXISTS_TAC `(g:num->real^M->real^N) n` THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[bounded; FORALL_IN_IMAGE; IN_UNIV] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `norm(integral s (\x. lift(norm(f x - h x)))) +
+     norm(integral s (\x. lift(norm((g:num->real^M->real^N) n x - h x))))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC(NORM_ARITH
+       `norm(x:real^N) <= norm(y + z:real^N)
+        ==> norm(x) <= norm(y) + norm(z)`) THEN
+      W(MP_TAC o PART_MATCH (lhs o rand) (GSYM INTEGRAL_ADD) o
+         rand o rand o snd) THEN
+      ASM_SIMP_TAC[ABSOLUTELY_INTEGRABLE_NORM;
+               ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE;
+               ABSOLUTELY_INTEGRABLE_SUB; ETA_AX] THEN
+      DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC(MESON[]
+       `norm x = drop x /\ norm(a:real^N) <= drop x ==> norm a <= norm x`) THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC NORM_1_POS THEN MATCH_MP_TAC INTEGRAL_DROP_POS THEN
+        SIMP_TAC[DROP_ADD; LIFT_DROP; NORM_POS_LE; REAL_LE_ADD] THEN
+        MATCH_MP_TAC INTEGRABLE_ADD THEN CONJ_TAC;
+        MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+        REWRITE_TAC[DROP_ADD; LIFT_DROP; NORM_LIFT; REAL_ABS_NORM] THEN
+        REWRITE_TAC[NORM_ARITH
+         `norm(f - g:real^N) <= norm(f - h) + norm(g - h)`] THEN
+        CONJ_TAC THENL
+         [ALL_TAC; MATCH_MP_TAC INTEGRABLE_ADD THEN CONJ_TAC]] THEN
+      MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+      ASM_SIMP_TAC[ABSOLUTELY_INTEGRABLE_NORM;
+                   ABSOLUTELY_INTEGRABLE_SUB; ETA_AX];
+      MATCH_MP_TAC(REAL_ARITH `a < e / &2 /\ b < e / &2 ==> a + b < e`) THEN
+      ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+       `x < e ==> x = y ==> y < e`)) THEN AP_TERM_TAC THEN
+      MATCH_MP_TAC INTEGRAL_SPIKE_SET THEN
+      MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN EXISTS_TAC `k:real^M->bool` THEN
+      ASM_REWRITE_TAC[] THEN SET_TAC[]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Luzin's theorem (Talvila and Loeb's proof from Marius Junge's notes).     *)
+(* ------------------------------------------------------------------------- *)
+
+let LUZIN = prove
+ (`!f:real^M->real^N s e.
+        measurable s /\ f measurable_on s /\ &0 < e
+        ==> ?k. compact k /\ k SUBSET s /\
+                measure(s DIFF k) < e /\ f continuous_on k`,
+  REPEAT STRIP_TAC THEN
+  X_CHOOSE_THEN `v:num->real^N->bool` STRIP_ASSUME_TAC
+    UNIV_SECOND_COUNTABLE_SEQUENCE THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `s:real^M->bool`]
+        MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN) THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `s:real^M->bool`]
+        MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED) THEN
+  ASM_REWRITE_TAC[] THEN REPEAT DISCH_TAC THEN
+  SUBGOAL_THEN
+   `!n. ?k k'.
+        compact k /\ k SUBSET {x | x IN s /\ (f:real^M->real^N) x IN v n} /\
+        compact k' /\ k' SUBSET {x | x IN s /\ f x IN ((:real^N) DIFF v n)} /\
+        measure(s DIFF (k UNION k')) < e / &4 / &2 pow n`
+  MP_TAC THENL
+   [GEN_TAC THEN
+    MP_TAC(ISPECL [`{x:real^M | x IN s /\ f(x) IN (v:num->real^N->bool) n}`;
+                   `e / &4 / &2 / &2 pow n`] MEASURABLE_INNER_COMPACT) THEN
+    ASM_SIMP_TAC[REAL_OF_NUM_LT; ARITH; REAL_LT_DIV; REAL_LT_POW2] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^M->bool` THEN
+    STRIP_TAC THEN
+    MP_TAC(ISPECL [`{x:real^M | x IN s /\ f(x) IN (:real^N) DIFF v(n:num)}`;
+                   `e / &4 / &2 / &2 pow n`] MEASURABLE_INNER_COMPACT) THEN
+    ASM_SIMP_TAC[GSYM OPEN_CLOSED; REAL_LT_DIV; REAL_POW_LT; REAL_OF_NUM_LT;
+                 ARITH] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k':real^M->bool` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC
+     `measure(({x | x IN s /\ (f:real^M->real^N) x IN v n} DIFF k) UNION
+              ({x | x IN s /\ f x IN ((:real^N) DIFF v(n:num))} DIFF k'))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC MEASURE_SUBSET THEN
+      ASM_SIMP_TAC[MEASURABLE_DIFF; MEASURABLE_UNION; MEASURABLE_COMPACT;
+                   GSYM OPEN_CLOSED] THEN SET_TAC[];
+      ASM_SIMP_TAC[MEASURE_UNION; MEASURABLE_DIFF; MEASURABLE_COMPACT;
+                   GSYM OPEN_CLOSED; MEASURE_DIFF_SUBSET] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `s < k + e / &4 / &2 / d /\ s' < k' + e / &4 / &2 / d /\ m = &0
+        ==> (s - k) + (s' - k') - m < e / &4 / d`) THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(MESON[MEASURE_EMPTY]
+       `s = {} ==> measure s = &0`) THEN SET_TAC[]];
+    REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM; IN_DIFF; IN_UNIV] THEN
+    MAP_EVERY X_GEN_TAC [`k:num->real^M->bool`; `k':num->real^M->bool`] THEN
+    REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC] THEN
+  EXISTS_TAC `INTERS {k n UNION k' n | n IN (:num)} :real^M->bool` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC COMPACT_INTERS THEN
+    ASM_SIMP_TAC[FORALL_IN_GSPEC; COMPACT_UNION] THEN SET_TAC[];
+    REWRITE_TAC[INTERS_GSPEC] THEN ASM SET_TAC[];
+    REWRITE_TAC[DIFF_INTERS; SET_RULE
+     `{f y | y IN {g x | x IN s}} = {f(g x) | x IN s}`] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC
+     (MESON[] `measurable s /\ measure s <= b ==> measure s <= b`) THEN
+    MATCH_MP_TAC MEASURE_COUNTABLE_UNIONS_LE THEN
+    ASM_SIMP_TAC[MEASURABLE_DIFF; MEASURABLE_UNION; MEASURABLE_COMPACT] THEN
+    X_GEN_TAC `n:num` THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum(0..n) (\i. e / &4 / &2 pow i)` THEN CONJ_TAC THENL
+     [ASM_SIMP_TAC[SUM_LE_NUMSEG; REAL_LT_IMP_LE]; ALL_TAC] THEN
+    ASM_SIMP_TAC[real_div; SUM_LMUL; REAL_LE_LMUL_EQ; REAL_ARITH
+     `(e * inv(&4)) * s <= e * inv(&2) <=> e * s <= e * &2`] THEN
+    REWRITE_TAC[REAL_INV_POW; SUM_GP; LT] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[REAL_ARITH
+     `(&1 - s) / (&1 / &2) <= &2 <=> &0 <= s`] THEN
+    MATCH_MP_TAC REAL_POW_LE THEN CONV_TAC REAL_RAT_REDUCE_CONV;
+
+    REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+    REWRITE_TAC[INTERS_GSPEC; IN_ELIM_THM; IN_UNIV] THEN
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    REWRITE_TAC[CONTINUOUS_WITHIN_OPEN; IN_ELIM_THM] THEN
+    X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `?n:num. (f:real^M->real^N)(x) IN v(n) /\ v(n) SUBSET t`
+    STRIP_ASSUME_TAC THENL
+     [UNDISCH_THEN
+       `!s. open s ==> (?k. s:real^N->bool = UNIONS {v(n:num) | n IN k})`
+       (MP_TAC o SPEC `t:real^N->bool`) THEN
+      ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; UNIONS_GSPEC] THEN ASM SET_TAC[];
+      EXISTS_TAC `(:real^M) DIFF k'(n:num)` THEN
+      ASM_SIMP_TAC[GSYM closed; COMPACT_IMP_CLOSED] THEN ASM SET_TAC[]]]);;
+
+let LUZIN_EQ,LUZIN_EQ_ALT = (CONJ_PAIR o prove)
+ (`(!f:real^M->real^N s.
+        measurable s
+        ==> (f measurable_on s <=>
+             !e. &0 < e
+                 ==> ?k. compact k /\ k SUBSET s /\
+                         measure(s DIFF k) < e /\ f continuous_on k)) /\
+   (!f:real^M->real^N s.
+        measurable s
+        ==> (f measurable_on s <=>
+             !e. &0 < e
+                 ==> ?k g. compact k /\ k SUBSET s /\
+                           measure(s DIFF k) < e /\
+                           g continuous_on (:real^M) /\
+                           (!x. x IN k ==> g x = f x)))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `measurable(s:real^M->bool)` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(TAUT
+   `(p ==> q) /\ (q ==> r) /\ (r ==> p) ==> (p <=> q) /\ (p <=> r)`) THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[LUZIN];
+    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 `k:real^M->bool` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC TIETZE_UNBOUNDED THEN
+    ASM_SIMP_TAC[COMPACT_IMP_CLOSED; SUBTOPOLOGY_UNIV; GSYM CLOSED_IN];
+    DISCH_THEN(MP_TAC o GEN `n:num` o SPEC `inv(&2 pow n)`) THEN
+    REWRITE_TAC[REAL_LT_INV_EQ; REAL_LT_POW2] THEN
+    REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM; FORALL_AND_THM] THEN
+    MAP_EVERY X_GEN_TAC [`k:num->real^M->bool`; `g:num->real^M->real^N`] THEN
+    STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_ON_LIMIT THEN MAP_EVERY EXISTS_TAC
+     [`g:num->real^M->real^N`;
+      `s DIFF UNIONS {INTERS {k m | n <= m} | n IN (:num)}:real^M->bool`] THEN
+    REPEAT CONJ_TAC THENL
+     [X_GEN_TAC `n:num` THEN
+      MATCH_MP_TAC CONTINUOUS_IMP_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET THEN
+      ASM_MESON_TAC[MEASURABLE_IMP_LEBESGUE_MEASURABLE; CONTINUOUS_ON_SUBSET;
+                    SUBSET_UNIV];
+      SIMP_TAC[DIFF_UNIONS_NONEMPTY; SET_RULE `~({f x | x IN UNIV} = {})`] THEN
+      REWRITE_TAC[NEGLIGIBLE_OUTER] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+      MP_TAC(SPECL [`inv(&2)`; `e / &4`] REAL_ARCH_POW_INV) THEN
+      ANTS_TAC THENL [ASM_REAL_ARITH_TAC; REWRITE_TAC[REAL_POW_INV]] THEN
+      DISCH_THEN(X_CHOOSE_THEN `n:num` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `s DIFF INTERS {k m | n:num <= m}:real^M->bool` THEN
+      REPEAT CONJ_TAC THENL
+       [REWRITE_TAC[INTERS_GSPEC; FORALL_IN_GSPEC] THEN ASM SET_TAC[];
+        MATCH_MP_TAC MEASURABLE_DIFF THEN ASM_REWRITE_TAC[] THEN
+        MATCH_MP_TAC MEASURABLE_COUNTABLE_INTERS_GEN THEN
+        ASM_SIMP_TAC[FORALL_IN_GSPEC; MEASURABLE_COMPACT] THEN
+        CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[LE_REFL]] THEN
+        ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+        MATCH_MP_TAC COUNTABLE_IMAGE THEN
+        MESON_TAC[NUM_COUNTABLE; COUNTABLE_SUBSET; SUBSET_UNIV];
+        REWRITE_TAC[DIFF_INTERS] THEN
+        MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC
+         (MESON[] `measurable s /\ measure s <= b ==> measure s <= b`) THEN
+        MATCH_MP_TAC MEASURE_COUNTABLE_UNIONS_LE_GEN THEN
+        ASM_SIMP_TAC[FORALL_IN_GSPEC; MEASURABLE_COMPACT; MEASURABLE_DIFF] THEN
+        CONJ_TAC THENL
+         [ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+          MATCH_MP_TAC COUNTABLE_IMAGE THEN
+          REWRITE_TAC[SET_RULE `{x | x IN s} = s`] THEN
+          ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+          MATCH_MP_TAC COUNTABLE_IMAGE THEN
+          MESON_TAC[NUM_COUNTABLE; COUNTABLE_SUBSET; SUBSET_UNIV];
+          REWRITE_TAC[SIMPLE_IMAGE] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+          REWRITE_TAC[FORALL_FINITE_SUBSET_IMAGE] THEN
+          ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+          REWRITE_TAC[FORALL_FINITE_SUBSET_IMAGE] THEN
+          X_GEN_TAC `ns:num->bool` THEN REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+          STRIP_TAC THEN REWRITE_TAC[GSYM IMAGE_o] THEN
+          W(MP_TAC o PART_MATCH (lhand o rand) SUM_IMAGE_LE o lhand o snd) THEN
+          ASM_SIMP_TAC[o_DEF; MEASURE_POS_LE; MEASURABLE_DIFF;
+                       MEASURABLE_COMPACT] THEN
+          MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+          FIRST_ASSUM(MP_TAC o SPEC `\x:num. x` o
+            MATCH_MP UPPER_BOUND_FINITE_SET) THEN
+          REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `m:num` THEN
+          STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+          EXISTS_TAC `sum (n..m) (\i. measure(s DIFF k i:real^M->bool))` THEN
+          CONJ_TAC THENL
+           [MATCH_MP_TAC SUM_SUBSET_SIMPLE THEN
+            ASM_SIMP_TAC[MEASURE_POS_LE; MEASURABLE_DIFF; MEASURABLE_COMPACT;
+                         FINITE_NUMSEG; SUBSET; IN_NUMSEG];
+            ALL_TAC] THEN
+          MATCH_MP_TAC REAL_LE_TRANS THEN
+          EXISTS_TAC `sum (n..m) (\i. inv(&2 pow i))` THEN
+          ASM_SIMP_TAC[SUM_LE_NUMSEG; REAL_LT_IMP_LE] THEN
+          REWRITE_TAC[REAL_INV_POW; SUM_GP; LT] THEN
+          COND_CASES_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+          CONV_TAC REAL_RAT_REDUCE_CONV THEN MATCH_MP_TAC(REAL_ARITH
+           `a <= e / &4 /\ &0 <= b
+            ==> (a - b) / (&1 / &2) <= e / &2`) THEN
+          REWRITE_TAC[real_div; REAL_MUL_LID; REAL_POW_INV] THEN
+          ASM_SIMP_TAC[GSYM real_div; REAL_LT_IMP_LE; REAL_LE_INV_EQ;
+                       REAL_LT_POW2]]];
+      REWRITE_TAC[SET_RULE `s DIFF (s DIFF t) = s INTER t`] THEN
+      X_GEN_TAC `x:real^M` THEN REWRITE_TAC[UNIONS_GSPEC; IN_INTER] THEN
+      REWRITE_TAC[IN_UNIV; IN_ELIM_THM; INTERS_GSPEC] THEN
+      STRIP_TAC THEN MATCH_MP_TAC LIM_EVENTUALLY THEN
+      REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN ASM_MESON_TAC[]]]);;
diff --git a/Multivariate/misc.ml b/Multivariate/misc.ml
new file mode 100644 (file)
index 0000000..b6bc121
--- /dev/null
@@ -0,0 +1,526 @@
+(* ========================================================================= *)
+(* Various convenient background stuff.                                      *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(* ========================================================================= *)
+
+prioritize_real();;
+
+(* ------------------------------------------------------------------------- *)
+(* A couple of extra tactics used in some proofs below.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let ASSERT_TAC tm =
+  SUBGOAL_THEN tm STRIP_ASSUME_TAC;;
+
+let EQ_TRANS_TAC tm =
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC tm THEN CONJ_TAC;;
+
+(* ------------------------------------------------------------------------- *)
+(* Miscellaneous lemmas.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let EXISTS_DIFF = prove
+ (`(?s:A->bool. P(UNIV DIFF s)) <=> (?s. P s)`,
+  MESON_TAC[prove(`UNIV DIFF (UNIV DIFF s) = s`,SET_TAC[])]);;
+
+let GE_REFL = prove
+ (`!n:num. n >= n`,
+  REWRITE_TAC[GE; LE_REFL]);;
+
+let FORALL_SUC = prove
+ (`(!n. ~(n = 0) ==> P n) <=> (!n. P(SUC n))`,
+  MESON_TAC[num_CASES; NOT_SUC]);;
+
+let SEQ_MONO_LEMMA = prove
+ (`!d e. (!n. n >= m ==> d(n) < e(n)) /\ (!n. n >= m ==> e(n) <= e(m))
+         ==> !n:num. n >= m ==> d(n) < e(m)`,
+  MESON_TAC[GE; REAL_LTE_TRANS]);;
+
+let REAL_HALF = prove
+ (`(!e. &0 < e / &2 <=> &0 < e) /\
+   (!e. e / &2 + e / &2 = e) /\
+   (!e. &2 * (e / &2) = e)`,
+  REAL_ARITH_TAC);;
+
+let UPPER_BOUND_FINITE_SET = prove
+ (`!f:(A->num) s. FINITE(s) ==> ?a. !x. x IN s ==> f(x) <= a`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+  MESON_TAC[LE_CASES; LE_REFL; LE_TRANS]);;
+
+let UPPER_BOUND_FINITE_SET_REAL = prove
+ (`!f:(A->real) s. FINITE(s) ==> ?a. !x. x IN s ==> f(x) <= a`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+  MESON_TAC[REAL_LE_TOTAL; REAL_LE_REFL; REAL_LE_TRANS]);;
+
+let LOWER_BOUND_FINITE_SET = prove
+ (`!f:(A->num) s. FINITE(s) ==> ?a. !x. x IN s ==> a <= f(x)`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+  MESON_TAC[LE_CASES; LE_REFL; LE_TRANS]);;
+
+let LOWER_BOUND_FINITE_SET_REAL = prove
+ (`!f:(A->real) s. FINITE(s) ==> ?a. !x. x IN s ==> a <= f(x)`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+  MESON_TAC[REAL_LE_TOTAL; REAL_LE_REFL; REAL_LE_TRANS]);;
+
+let REAL_CONVEX_BOUND2_LT = prove
+ (`!x y a u v. x < a /\ y < b /\ &0 <= u /\ &0 <= v /\ u + v = &1
+               ==> u * x + v * y < u * a + v * b`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `u = &0` THENL
+   [ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_ADD_LID] THEN REPEAT STRIP_TAC;
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LTE_ADD2 THEN
+    ASM_SIMP_TAC[REAL_LE_LMUL; REAL_LT_IMP_LE]] THEN
+  MATCH_MP_TAC REAL_LT_LMUL THEN ASM_REAL_ARITH_TAC);;
+
+let REAL_CONVEX_BOUND_LT = prove
+ (`!x y a u v. x < a /\ y < a /\ &0 <= u /\ &0 <= v /\ (u + v = &1)
+               ==> u * x + v * y < a`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LTE_TRANS THEN
+  EXISTS_TAC `u * a + v * a:real` THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[REAL_CONVEX_BOUND2_LT];
+    MATCH_MP_TAC REAL_EQ_IMP_LE THEN
+    UNDISCH_TAC `u + v = &1` THEN CONV_TAC REAL_RING]);;
+
+let REAL_CONVEX_BOUND_LE = prove
+ (`!x y a u v. x <= a /\ y <= a /\ &0 <= u /\ &0 <= v /\ (u + v = &1)
+               ==> u * x + v * y <= a`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `(u + v) * a` THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_REWRITE_TAC[REAL_LE_REFL; REAL_MUL_LID]] THEN
+  ASM_SIMP_TAC[REAL_ADD_RDISTRIB; REAL_LE_ADD2; REAL_LE_LMUL]);;
+
+let INFINITE_ENUMERATE = prove
+ (`!s:num->bool.
+       INFINITE s
+       ==> ?r:num->num. (!m n. m < n ==> r(m) < r(n)) /\ (!n. r n IN s)`,
+  GEN_TAC THEN REWRITE_TAC[INFINITE; num_FINITE; NOT_EXISTS_THM] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; NOT_LE; SKOLEM_THM] THEN
+  DISCH_THEN(X_CHOOSE_TAC `next:num->num`) THEN
+  (MP_TAC o prove_recursive_functions_exist num_RECURSION)
+   `(f(0) = next 0) /\ (!n. f(SUC n) = next(f n))` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN STRIP_TAC THEN CONJ_TAC THENL
+   [GEN_TAC; ALL_TAC] THEN
+  INDUCT_TAC THEN ASM_REWRITE_TAC[LT] THEN ASM_MESON_TAC[LT_TRANS]);;
+
+let APPROACHABLE_LT_LE = prove
+ (`!P f. (?d. &0 < d /\ !x. f(x) < d ==> P x) =
+         (?d. &0 < d /\ !x. f(x) <= d ==> P x)`,
+  let lemma = prove
+   (`&0 < d ==> x <= d / &2 ==> x < d`,
+    SIMP_TAC[REAL_LE_RDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN REAL_ARITH_TAC) in
+  MESON_TAC[REAL_LT_IMP_LE; lemma; REAL_HALF]);;
+
+let REAL_LE_BETWEEN = prove
+ (`!a b. a <= b <=> ?x. a <= x /\ x <= b`,
+  MESON_TAC[REAL_LE_TRANS; REAL_LE_REFL]);;
+
+let REAL_LT_BETWEEN = prove
+ (`!a b. a < b <=> ?x. a < x /\ x < b`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL [ALL_TAC; MESON_TAC[REAL_LT_TRANS]] THEN
+  DISCH_TAC THEN EXISTS_TAC `(a + b) / &2` THEN
+  SIMP_TAC[REAL_LT_RDIV_EQ; REAL_LT_LDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN
+  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC);;
+
+let TRIANGLE_LEMMA = prove
+ (`!x y z. &0 <= x /\ &0 <= y /\ &0 <= z /\ x pow 2 <= y pow 2 + z pow 2
+           ==> x <= y + z`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  REWRITE_TAC[REAL_NOT_LE] THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `(y + z) pow 2` THEN
+  ASM_SIMP_TAC[REAL_POW_LT2; REAL_LE_ADD; ARITH_EQ] THEN
+  ASM_SIMP_TAC[REAL_LE_MUL; REAL_POW_2; REAL_ARITH
+   `x * x + y * y <= (x + y) * (x + y) <=> &0 <= x * y`]);;
+
+let LAMBDA_SKOLEM = prove
+ (`(!i. 1 <= i /\ i <= dimindex(:N) ==> ?x. P i x) =
+   (?x:A^N. !i. 1 <= i /\ i <= dimindex(:N) ==> P i (x$i))`,
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_TAC `x:num->A`) THEN
+    EXISTS_TAC `(lambda i. x i):A^N` THEN ASM_SIMP_TAC[LAMBDA_BETA];
+    DISCH_THEN(X_CHOOSE_TAC `x:A^N`) THEN
+    EXISTS_TAC `\i. (x:A^N)$i` THEN ASM_REWRITE_TAC[]]);;
+
+let LAMBDA_PAIR = prove
+ (`(\(x,y). P x y) = (\p. P (FST p) (SND p))`,
+  REWRITE_TAC[FUN_EQ_THM; FORALL_PAIR_THM] THEN
+  CONV_TAC(ONCE_DEPTH_CONV GEN_BETA_CONV) THEN REWRITE_TAC[]);;
+
+let EPSILON_DELTA_MINIMAL = prove
+ (`!P:real->A->bool Q.
+        FINITE {x | Q x} /\
+        (!d e x. Q x /\ &0 < e /\ e < d ==> P d x ==> P e x) /\
+        (!x. Q x ==> ?d. &0 < d /\ P d x)
+        ==> ?d. &0 < d /\ !x. Q x ==> P d x`,
+  REWRITE_TAC[IMP_IMP] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `{x:A | Q x} = {}` THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+    REWRITE_TAC[NOT_IN_EMPTY; IN_ELIM_THM] THEN
+    DISCH_TAC THEN EXISTS_TAC `&1` THEN ASM_REWRITE_TAC[REAL_LT_01];
+    FIRST_X_ASSUM(MP_TAC o
+     GEN_REWRITE_RULE BINDER_CONV [RIGHT_IMP_EXISTS_THM]) THEN
+    REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `d:A->real` THEN DISCH_TAC THEN
+    EXISTS_TAC `inf(IMAGE d {x:A | Q x})` THEN
+    ASM_SIMP_TAC[REAL_LT_INF_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+    ASM_SIMP_TAC[FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    X_GEN_TAC `a:A` THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `&0 < inf(IMAGE d {x:A | Q x}) /\ inf(IMAGE d {x | Q x}) <= d a`
+    MP_TAC THENL
+     [ASM_SIMP_TAC[REAL_LT_INF_FINITE; REAL_INF_LE_FINITE;
+                   FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+      REWRITE_TAC[EXISTS_IN_IMAGE; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+      ASM_MESON_TAC[REAL_LE_REFL];
+      REWRITE_TAC[REAL_LE_LT] THEN STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      EXISTS_TAC `(d:A->real) a` THEN ASM_SIMP_TAC[]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A generic notion of "hull" (convex, affine, conic hull and closure).      *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("hull",(21,"left"));;
+
+let hull = new_definition
+  `P hull s = INTERS {t | P t /\ s SUBSET t}`;;
+
+let HULL_P = prove
+ (`!P s. P s ==> (P hull s = s)`,
+  REWRITE_TAC[hull; EXTENSION; IN_INTERS; IN_ELIM_THM] THEN
+  MESON_TAC[SUBSET]);;
+
+let P_HULL = prove
+ (`!P s. (!f. (!s. s IN f ==> P s) ==> P(INTERS f)) ==> P(P hull s)`,
+  REWRITE_TAC[hull] THEN SIMP_TAC[IN_ELIM_THM]);;
+
+let HULL_EQ = prove
+ (`!P s. (!f. (!s. s IN f ==> P s) ==> P(INTERS f))
+         ==> ((P hull s = s) <=> P s)`,
+  MESON_TAC[P_HULL; HULL_P]);;
+
+let HULL_HULL = prove
+ (`!P s. P hull (P hull s) = P hull s`,
+  REWRITE_TAC[hull; EXTENSION; IN_INTERS; IN_ELIM_THM; SUBSET] THEN
+  MESON_TAC[]);;
+
+let HULL_SUBSET = prove
+ (`!P s. s SUBSET (P hull s)`,
+  REWRITE_TAC[hull; SUBSET; IN_INTERS; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let HULL_MONO = prove
+ (`!P s t. s SUBSET t ==> (P hull s) SUBSET (P hull t)`,
+   REWRITE_TAC[hull; SUBSET; IN_INTERS; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let HULL_ANTIMONO = prove
+ (`!P Q s. P SUBSET Q ==> (Q hull s) SUBSET (P hull s)`,
+  REWRITE_TAC[SUBSET; hull; IN_INTERS; IN_ELIM_THM] THEN MESON_TAC[IN]);;
+
+let HULL_MINIMAL = prove
+ (`!P s t. s SUBSET t /\ P t ==> (P hull s) SUBSET t`,
+  REWRITE_TAC[hull; SUBSET; IN_INTERS; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let SUBSET_HULL = prove
+ (`!P s t. P t ==> ((P hull s) SUBSET t <=> s SUBSET t)`,
+  REWRITE_TAC[hull; SUBSET; IN_INTERS; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let HULL_UNIQUE = prove
+ (`!P s t. s SUBSET t /\ P t /\ (!t'. s SUBSET t' /\ P t' ==> t SUBSET t')
+           ==> (P hull s = t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[hull; SUBSET; IN_INTERS; IN_ELIM_THM] THEN
+  ASM_MESON_TAC[SUBSET_HULL; SUBSET]);;
+
+let HULL_UNION_SUBSET = prove
+ (`!P s t. (P hull s) UNION (P hull t) SUBSET (P hull (s UNION t))`,
+  SIMP_TAC[UNION_SUBSET; HULL_MONO; SUBSET_UNION]);;
+
+let HULL_UNION = prove
+ (`!P s t. P hull (s UNION t) = P hull (P hull s UNION P hull t)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[hull] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; UNION_SUBSET] THEN
+  MESON_TAC[SUBSET_HULL]);;
+
+let HULL_UNION_LEFT = prove
+ (`!P s t:A->bool.
+        P hull (s UNION t) = P hull (P hull s UNION t)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[hull] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; UNION_SUBSET] THEN
+  MESON_TAC[SUBSET_HULL]);;
+
+let HULL_UNION_RIGHT = prove
+ (`!P s t:A->bool.
+        P hull (s UNION t) = P hull (s UNION P hull t)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[hull] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; UNION_SUBSET] THEN
+  MESON_TAC[SUBSET_HULL]);;
+
+let HULL_REDUNDANT_EQ = prove
+ (`!P a s. a IN (P hull s) <=> (P hull (a INSERT s) = P hull s)`,
+  REWRITE_TAC[hull] THEN SET_TAC[]);;
+
+let HULL_REDUNDANT = prove
+ (`!P a s. a IN (P hull s) ==> (P hull (a INSERT s) = P hull s)`,
+  REWRITE_TAC[HULL_REDUNDANT_EQ]);;
+
+let HULL_INDUCT = prove
+ (`!P p s. (!x:A. x IN s ==> p x) /\ P {x | p x}
+           ==> !x. x IN P hull s ==> p x`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`P:(A->bool)->bool`; `s:A->bool`; `{x:A | p x}`]
+                HULL_MINIMAL) THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM]);;
+
+let HULL_INC = prove
+ (`!P s x. x IN s ==> x IN P hull s`,
+  MESON_TAC[REWRITE_RULE[SUBSET] HULL_SUBSET]);;
+
+let HULL_IMAGE_SUBSET = prove
+ (`!P f s. P(P hull s) /\ (!s. P s ==> P(IMAGE f s))
+           ==> P hull (IMAGE f s) SUBSET (IMAGE f (P hull s))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HULL_MINIMAL THEN
+  ASM_SIMP_TAC[IMAGE_SUBSET; HULL_SUBSET]);;
+
+let HULL_IMAGE_GALOIS = prove
+ (`!P f g s. (!s. P(P hull s)) /\
+             (!s. P s ==> P(IMAGE f s)) /\ (!s. P s ==> P(IMAGE g s)) /\
+             (!s t. s SUBSET IMAGE g t <=> IMAGE f s SUBSET t)
+             ==> P hull (IMAGE f s) = IMAGE f (P hull s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  ASM_SIMP_TAC[HULL_IMAGE_SUBSET] THEN
+  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC I [GSYM th]) THEN
+  MATCH_MP_TAC HULL_MINIMAL THEN
+  ASM_SIMP_TAC[HULL_SUBSET]);;
+
+let HULL_IMAGE = prove
+ (`!P f s. (!s. P(P hull s)) /\ (!s. P(IMAGE f s) <=> P s) /\
+           (!x y:A. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+           ==> P hull (IMAGE f s) = IMAGE f (P hull s)`,
+  REPEAT GEN_TAC THEN
+  REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[BIJECTIVE_LEFT_RIGHT_INVERSE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:A->A` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC HULL_IMAGE_GALOIS THEN EXISTS_TAC `g:A->A` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  X_GEN_TAC `s:A->bool` THEN
+  FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [GSYM th]) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[]);;
+
+let IS_HULL = prove
+ (`!P s. (!f. (!s. s IN f ==> P s) ==> P(INTERS f))
+         ==> (P s <=> ?t. s = P hull t)`,
+  MESON_TAC[HULL_P; P_HULL]);;
+
+let HULLS_EQ = prove
+ (`!P s t.
+        (!f. (!s. s IN f ==> P s) ==> P (INTERS f)) /\
+        s SUBSET P hull t /\ t SUBSET P hull s
+        ==> P hull s = P hull t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  CONJ_TAC THEN MATCH_MP_TAC HULL_MINIMAL THEN
+  ASM_SIMP_TAC[P_HULL]);;
+
+let HULL_P_AND_Q = prove
+ (`!P Q. (!f. (!s. s IN f ==> P s) ==> P(INTERS f)) /\
+         (!f. (!s. s IN f ==> Q s) ==> Q(INTERS f)) /\
+         (!s. Q s ==> Q(P hull s))
+         ==> (\x. P x /\ Q x) hull s = P hull (Q hull s)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HULL_UNIQUE THEN ASM_SIMP_TAC[HULL_INC; SUBSET_HULL] THEN
+  ASM_MESON_TAC[P_HULL; HULL_SUBSET; SUBSET_TRANS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More variants of the Archimedian property and useful consequences.        *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_ARCH_INV = prove
+ (`!e. &0 < e <=> ?n. ~(n = 0) /\ &0 < inv(&n) /\ inv(&n) < e`,
+  GEN_TAC THEN EQ_TAC THENL [ALL_TAC; MESON_TAC[REAL_LT_TRANS]] THEN
+  DISCH_TAC THEN MP_TAC(SPEC `inv(e)` REAL_ARCH_LT) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN
+  ASM_MESON_TAC[REAL_LT_INV2; REAL_INV_INV; REAL_LT_INV_EQ; REAL_LT_TRANS;
+                REAL_LT_ANTISYM]);;
+
+let REAL_POW_LBOUND = prove
+ (`!x n. &0 <= x ==> &1 + &n * x <= (&1 + x) pow n`,
+  GEN_TAC THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN DISCH_TAC THEN
+  INDUCT_TAC THEN
+  REWRITE_TAC[real_pow; REAL_MUL_LZERO; REAL_ADD_RID; REAL_LE_REFL] THEN
+  REWRITE_TAC[GSYM REAL_OF_NUM_SUC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `(&1 + x) * (&1 + &n * x)` THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL; REAL_ARITH `&0 <= x ==> &0 <= &1 + x`] THEN
+  ASM_SIMP_TAC[REAL_LE_MUL; REAL_POS; REAL_ARITH
+   `&1 + (n + &1) * x <= (&1 + x) * (&1 + n * x) <=> &0 <= n * x * x`]);;
+
+let REAL_ARCH_POW = prove
+ (`!x y. &1 < x ==> ?n. y < x pow n`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPEC `x - &1` REAL_ARCH) THEN ASM_REWRITE_TAC[REAL_SUB_LT] THEN
+  DISCH_THEN(MP_TAC o SPEC `y:real`) THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `n:num` THEN DISCH_TAC THEN MATCH_MP_TAC REAL_LTE_TRANS THEN
+  EXISTS_TAC `&1 + &n * (x - &1)` THEN
+  ASM_SIMP_TAC[REAL_ARITH `x < y ==> x < &1 + y`] THEN
+  ASM_MESON_TAC[REAL_POW_LBOUND; REAL_SUB_ADD2; REAL_ARITH
+    `&1 < x ==> &0 <= x - &1`]);;
+
+let REAL_ARCH_POW2 = prove
+ (`!x. ?n. x < &2 pow n`,
+  SIMP_TAC[REAL_ARCH_POW; REAL_OF_NUM_LT; ARITH]);;
+
+let REAL_ARCH_POW_INV = prove
+ (`!x y. &0 < y /\ x < &1 ==> ?n. x pow n < y`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `&0 < x` THENL
+   [ALL_TAC; ASM_MESON_TAC[REAL_POW_1; REAL_LET_TRANS; REAL_NOT_LT]] THEN
+  SUBGOAL_THEN `inv(&1) < inv(x)` MP_TAC THENL
+   [ASM_SIMP_TAC[REAL_LT_INV2]; REWRITE_TAC[REAL_INV_1]] THEN
+  DISCH_THEN(MP_TAC o SPEC `inv(y)` o MATCH_MP REAL_ARCH_POW) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN DISCH_TAC THEN
+  GEN_REWRITE_TAC BINOP_CONV [GSYM REAL_INV_INV] THEN
+  ASM_SIMP_TAC[GSYM REAL_POW_INV; REAL_LT_INV; REAL_LT_INV2]);;
+
+let FORALL_POS_MONO = prove
+ (`!P. (!d e. d < e /\ P d ==> P e) /\ (!n. ~(n = 0) ==> P(inv(&n)))
+       ==> !e. &0 < e ==> P e`,
+  MESON_TAC[REAL_ARCH_INV; REAL_LT_TRANS]);;
+
+let FORALL_POS_MONO_1 = prove
+ (`!P. (!d e. d < e /\ P d ==> P e) /\ (!n. P(inv(&n + &1)))
+       ==> !e. &0 < e ==> P e`,
+  REWRITE_TAC[REAL_OF_NUM_SUC; GSYM FORALL_SUC; FORALL_POS_MONO]);;
+
+let REAL_ARCH_RDIV_EQ_0 = prove
+ (`!x c. &0 <= x /\ &0 <= c /\ (!m. 0 < m ==> &m * x <= c) ==> x = &0`,
+  SIMP_TAC [GSYM REAL_LE_ANTISYM; GSYM REAL_NOT_LT] THEN REPEAT STRIP_TAC THEN
+  POP_ASSUM (STRIP_ASSUME_TAC o SPEC `c:real` o MATCH_MP REAL_ARCH) THEN
+  ASM_CASES_TAC `n=0` THENL
+   [POP_ASSUM SUBST_ALL_TAC THEN
+    RULE_ASSUM_TAC (REWRITE_RULE [REAL_MUL_LZERO]) THEN
+    ASM_MESON_TAC [REAL_LET_ANTISYM];
+    ASM_MESON_TAC [REAL_LET_ANTISYM; REAL_MUL_SYM; LT_NZ]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relate max and min to sup and inf.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_MAX_SUP = prove
+ (`!x y. max x y = sup {x,y}`,
+  SIMP_TAC[GSYM REAL_LE_ANTISYM; REAL_SUP_LE_FINITE; REAL_LE_SUP_FINITE;
+           FINITE_RULES; NOT_INSERT_EMPTY; REAL_MAX_LE; REAL_LE_MAX] THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN MESON_TAC[REAL_LE_TOTAL]);;
+
+let REAL_MIN_INF = prove
+ (`!x y. min x y = inf {x,y}`,
+  SIMP_TAC[GSYM REAL_LE_ANTISYM; REAL_INF_LE_FINITE; REAL_LE_INF_FINITE;
+           FINITE_RULES; NOT_INSERT_EMPTY; REAL_MIN_LE; REAL_LE_MIN] THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN MESON_TAC[REAL_LE_TOTAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Define square root here to decouple it from the existing analysis theory. *)
+(* ------------------------------------------------------------------------- *)
+
+let sqrt = new_definition
+  `sqrt(x) = @y. &0 <= y /\ (y pow 2 = x)`;;
+
+let SQRT_UNIQUE = prove
+ (`!x y. &0 <= y /\ (y pow 2 = x) ==> (sqrt(x) = y)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[sqrt] THEN MATCH_MP_TAC SELECT_UNIQUE THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN REWRITE_TAC[REAL_POW_2] THEN
+  REWRITE_TAC[REAL_ARITH `(x * x = y * y) <=> ((x + y) * (x - y) = &0)`] THEN
+  REWRITE_TAC[REAL_ENTIRE] THEN POP_ASSUM MP_TAC THEN REAL_ARITH_TAC);;
+
+let POW_2_SQRT = prove
+ (`!x. &0 <= x ==> (sqrt(x pow 2) = x)`,
+  MESON_TAC[SQRT_UNIQUE]);;
+
+let SQRT_0 = prove
+ (`sqrt(&0) = &0`,
+  MESON_TAC[SQRT_UNIQUE; REAL_POW_2; REAL_MUL_LZERO; REAL_POS]);;
+
+let SQRT_1 = prove
+ (`sqrt(&1) = &1`,
+   MESON_TAC[SQRT_UNIQUE; REAL_POW_2; REAL_MUL_LID; REAL_POS]);;
+
+let POW_2_SQRT_ABS = prove
+ (`!x. sqrt(x pow 2) = abs(x)`,
+  GEN_TAC THEN MATCH_MP_TAC SQRT_UNIQUE THEN
+  REWRITE_TAC[REAL_ABS_POS; REAL_POW_2; GSYM REAL_ABS_MUL] THEN
+  REWRITE_TAC[real_abs; REAL_LE_SQUARE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Geometric progression.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let SUM_GP_BASIC = prove
+ (`!x n. (&1 - x) * sum(0..n) (\i. x pow i) = &1 - x pow (SUC n)`,
+  GEN_TAC THEN INDUCT_TAC THEN REWRITE_TAC[SUM_CLAUSES_NUMSEG] THEN
+  REWRITE_TAC[real_pow; REAL_MUL_RID; LE_0] THEN
+  ASM_REWRITE_TAC[REAL_ADD_LDISTRIB; real_pow] THEN REAL_ARITH_TAC);;
+
+let SUM_GP_MULTIPLIED = prove
+ (`!x m n. m <= n
+           ==> ((&1 - x) * sum(m..n) (\i. x pow i) = x pow m - x pow (SUC n))`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC
+   [SUM_OFFSET_0; REAL_POW_ADD; REAL_MUL_ASSOC; SUM_GP_BASIC; SUM_RMUL] THEN
+  REWRITE_TAC[REAL_SUB_RDISTRIB; GSYM REAL_POW_ADD; REAL_MUL_LID] THEN
+  ASM_SIMP_TAC[ARITH_RULE `m <= n ==> (SUC(n - m) + m = SUC n)`]);;
+
+let SUM_GP = prove
+ (`!x m n.
+        sum(m..n) (\i. x pow i) =
+                if n < m then &0
+                else if x = &1 then &((n + 1) - m)
+                else (x pow m - x pow (SUC n)) / (&1 - x)`,
+  REPEAT GEN_TAC THEN
+  DISJ_CASES_TAC(ARITH_RULE `n < m \/ ~(n < m) /\ m <= n:num`) THEN
+  ASM_SIMP_TAC[SUM_TRIV_NUMSEG] THEN COND_CASES_TAC THENL
+   [ASM_REWRITE_TAC[REAL_POW_ONE; SUM_CONST_NUMSEG; REAL_MUL_RID]; ALL_TAC] THEN
+  MATCH_MP_TAC REAL_EQ_LCANCEL_IMP THEN EXISTS_TAC `&1 - x` THEN
+  ASM_SIMP_TAC[REAL_DIV_LMUL; REAL_SUB_0; SUM_GP_MULTIPLIED]);;
+
+let SUM_GP_OFFSET = prove
+ (`!x m n. sum(m..m+n) (\i. x pow i) =
+                if x = &1 then &n + &1
+                else x pow m * (&1 - x pow (SUC n)) / (&1 - x)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[SUM_GP; ARITH_RULE `~(m + n < m:num)`] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [REWRITE_TAC[REAL_OF_NUM_ADD] THEN AP_TERM_TAC THEN ARITH_TAC;
+    REWRITE_TAC[real_div; real_pow; REAL_POW_ADD] THEN REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Segment of natural numbers starting at a specific number.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let from = new_definition                                                      
+  `from n = {m:num | n <= m}`;;                                                
+                                                                               
+let FROM_0 = prove                                               
+ (`from 0 = (:num)`,                                                           
+  REWRITE_TAC[from; LE_0] THEN SET_TAC[]);;                                 
+                                                               
+let FROM_INTER_NUMSEG_GEN = prove                              
+ (`!k m n. (from k) INTER (m..n) = (if m < k then k..n else m..n)`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THEN POP_ASSUM MP_TAC THEN         
+  REWRITE_TAC[from; IN_ELIM_THM; IN_INTER; IN_NUMSEG; EXTENSION] THEN   
+  ARITH_TAC);;                                           
+                                                                               
+let FROM_INTER_NUMSEG = prove                                                  
+ (`!k n. (from k) INTER (0..n) = k..n`,                                        
+  REWRITE_TAC[from; IN_ELIM_THM; IN_INTER; IN_NUMSEG; EXTENSION] THEN      
+  ARITH_TAC);;                           
+                                                              
+let IN_FROM = prove                                                    
+ (`!m n. m IN from n <=> n <= m`,                                     
+  REWRITE_TAC[from; IN_ELIM_THM]);;                                         
+
+let INFINITE_FROM = prove                                                      
+ (`!n. INFINITE(from n)`,                                                      
+  GEN_TAC THEN                                                                 
+  SUBGOAL_THEN `from n = (:num) DIFF {i | i < n}`                              
+   (fun th -> SIMP_TAC[th; INFINITE_DIFF_FINITE; FINITE_NUMSEG_LT;
+   num_INFINITE]) THEN                                               
+  REWRITE_TAC[EXTENSION; from; IN_DIFF; IN_UNIV; IN_ELIM_THM] THEN ARITH_TAC);;
diff --git a/Multivariate/multivariate_database.ml b/Multivariate/multivariate_database.ml
new file mode 100644 (file)
index 0000000..5b85747
--- /dev/null
@@ -0,0 +1,8226 @@
+needs "help.ml";;
+
+theorems :=
+[
+"ABSOLUTELY_INTEGRABLE_0",ABSOLUTELY_INTEGRABLE_0;
+"ABSOLUTELY_INTEGRABLE_ABS",ABSOLUTELY_INTEGRABLE_ABS;
+"ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_BOUND",ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_BOUND;
+"ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_LBOUND",ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_LBOUND;
+"ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_UBOUND",ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_UBOUND;
+"ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_DROP_LBOUND",ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_DROP_LBOUND;
+"ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_DROP_UBOUND",ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_DROP_UBOUND;
+"ABSOLUTELY_INTEGRABLE_ABS_1",ABSOLUTELY_INTEGRABLE_ABS_1;
+"ABSOLUTELY_INTEGRABLE_ABS_EQ",ABSOLUTELY_INTEGRABLE_ABS_EQ;
+"ABSOLUTELY_INTEGRABLE_ADD",ABSOLUTELY_INTEGRABLE_ADD;
+"ABSOLUTELY_INTEGRABLE_APPROXIMATE_CONTINUOUS",ABSOLUTELY_INTEGRABLE_APPROXIMATE_CONTINUOUS;
+"ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION",ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION;
+"ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION_EQ",ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION_EQ;
+"ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION_UNIV_EQ",ABSOLUTELY_INTEGRABLE_BOUNDED_SETVARIATION_UNIV_EQ;
+"ABSOLUTELY_INTEGRABLE_CMUL",ABSOLUTELY_INTEGRABLE_CMUL;
+"ABSOLUTELY_INTEGRABLE_COMPONENTWISE",ABSOLUTELY_INTEGRABLE_COMPONENTWISE;
+"ABSOLUTELY_INTEGRABLE_CONST",ABSOLUTELY_INTEGRABLE_CONST;
+"ABSOLUTELY_INTEGRABLE_CONTINUOUS",ABSOLUTELY_INTEGRABLE_CONTINUOUS;
+"ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE",ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE;
+"ABSOLUTELY_INTEGRABLE_INF_1",ABSOLUTELY_INTEGRABLE_INF_1;
+"ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND",ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND;
+"ABSOLUTELY_INTEGRABLE_LE",ABSOLUTELY_INTEGRABLE_LE;
+"ABSOLUTELY_INTEGRABLE_LEBESGUE_POINTS",ABSOLUTELY_INTEGRABLE_LEBESGUE_POINTS;
+"ABSOLUTELY_INTEGRABLE_LINEAR",ABSOLUTELY_INTEGRABLE_LINEAR;
+"ABSOLUTELY_INTEGRABLE_MAX",ABSOLUTELY_INTEGRABLE_MAX;
+"ABSOLUTELY_INTEGRABLE_MAX_1",ABSOLUTELY_INTEGRABLE_MAX_1;
+"ABSOLUTELY_INTEGRABLE_MEASURABLE",ABSOLUTELY_INTEGRABLE_MEASURABLE;
+"ABSOLUTELY_INTEGRABLE_MIN",ABSOLUTELY_INTEGRABLE_MIN;
+"ABSOLUTELY_INTEGRABLE_MIN_1",ABSOLUTELY_INTEGRABLE_MIN_1;
+"ABSOLUTELY_INTEGRABLE_NEG",ABSOLUTELY_INTEGRABLE_NEG;
+"ABSOLUTELY_INTEGRABLE_NORM",ABSOLUTELY_INTEGRABLE_NORM;
+"ABSOLUTELY_INTEGRABLE_ON_CONST",ABSOLUTELY_INTEGRABLE_ON_CONST;
+"ABSOLUTELY_INTEGRABLE_ON_SUBINTERVAL",ABSOLUTELY_INTEGRABLE_ON_SUBINTERVAL;
+"ABSOLUTELY_INTEGRABLE_RESTRICT_UNIV",ABSOLUTELY_INTEGRABLE_RESTRICT_UNIV;
+"ABSOLUTELY_INTEGRABLE_SET_VARIATION",ABSOLUTELY_INTEGRABLE_SET_VARIATION;
+"ABSOLUTELY_INTEGRABLE_SUB",ABSOLUTELY_INTEGRABLE_SUB;
+"ABSOLUTELY_INTEGRABLE_SUP_1",ABSOLUTELY_INTEGRABLE_SUP_1;
+"ABSOLUTELY_INTEGRABLE_VSUM",ABSOLUTELY_INTEGRABLE_VSUM;
+"ABSOLUTE_RETRACTION_CONVEX_CLOSED",ABSOLUTE_RETRACTION_CONVEX_CLOSED;
+"ABSOLUTE_RETRACTION_CONVEX_CLOSED_RELATIVE",ABSOLUTE_RETRACTION_CONVEX_CLOSED_RELATIVE;
+"ABSOLUTE_RETRACT_CONTRACTIBLE_ANR",ABSOLUTE_RETRACT_CONTRACTIBLE_ANR;
+"ABSOLUTE_RETRACT_CONVEX_CLOSED",ABSOLUTE_RETRACT_CONVEX_CLOSED;
+"ABSOLUTE_RETRACT_HOMEOMORPHIC_CONVEX_COMPACT",ABSOLUTE_RETRACT_HOMEOMORPHIC_CONVEX_COMPACT;
+"ABSOLUTE_RETRACT_IMP_AR",ABSOLUTE_RETRACT_IMP_AR;
+"ABSOLUTE_RETRACT_IMP_AR_GEN",ABSOLUTE_RETRACT_IMP_AR_GEN;
+"ABSOLUTE_RETRACT_PATH_IMAGE_ARC",ABSOLUTE_RETRACT_PATH_IMAGE_ARC;
+"ABSORPTION",ABSORPTION;
+"ABS_DROP",ABS_DROP;
+"ABS_SIMP",ABS_SIMP;
+"ADD",ADD;
+"ADD1",ADD1;
+"ADDITIVE_CONTENT_DIVISION",ADDITIVE_CONTENT_DIVISION;
+"ADDITIVE_CONTENT_TAGGED_DIVISION",ADDITIVE_CONTENT_TAGGED_DIVISION;
+"ADDITIVE_TAGGED_DIVISION_1",ADDITIVE_TAGGED_DIVISION_1;
+"ADD_0",ADD_0;
+"ADD_AC",ADD_AC;
+"ADD_ASSOC",ADD_ASSOC;
+"ADD_CLAUSES",ADD_CLAUSES;
+"ADD_EQ_0",ADD_EQ_0;
+"ADD_SUB",ADD_SUB;
+"ADD_SUB2",ADD_SUB2;
+"ADD_SUBR",ADD_SUBR;
+"ADD_SUBR2",ADD_SUBR2;
+"ADD_SUC",ADD_SUC;
+"ADD_SYM",ADD_SYM;
+"ADJOINT_ADJOINT",ADJOINT_ADJOINT;
+"ADJOINT_CLAUSES",ADJOINT_CLAUSES;
+"ADJOINT_COMPOSE",ADJOINT_COMPOSE;
+"ADJOINT_INJECTIVE",ADJOINT_INJECTIVE;
+"ADJOINT_INJECTIVE_INJECTIVE",ADJOINT_INJECTIVE_INJECTIVE;
+"ADJOINT_INJECTIVE_INJECTIVE_0",ADJOINT_INJECTIVE_INJECTIVE_0;
+"ADJOINT_LINEAR",ADJOINT_LINEAR;
+"ADJOINT_MATRIX",ADJOINT_MATRIX;
+"ADJOINT_SURJECTIVE",ADJOINT_SURJECTIVE;
+"ADJOINT_UNIQUE",ADJOINT_UNIQUE;
+"ADJOINT_WORKS",ADJOINT_WORKS;
+"ADMISSIBLE_BASE",ADMISSIBLE_BASE;
+"ADMISSIBLE_COMB",ADMISSIBLE_COMB;
+"ADMISSIBLE_COND",ADMISSIBLE_COND;
+"ADMISSIBLE_CONST",ADMISSIBLE_CONST;
+"ADMISSIBLE_GUARDED_PATTERN",ADMISSIBLE_GUARDED_PATTERN;
+"ADMISSIBLE_IMP_SUPERADMISSIBLE",ADMISSIBLE_IMP_SUPERADMISSIBLE;
+"ADMISSIBLE_LAMBDA",ADMISSIBLE_LAMBDA;
+"ADMISSIBLE_MAP",ADMISSIBLE_MAP;
+"ADMISSIBLE_MATCH",ADMISSIBLE_MATCH;
+"ADMISSIBLE_MATCH_SEQPATTERN",ADMISSIBLE_MATCH_SEQPATTERN;
+"ADMISSIBLE_NEST",ADMISSIBLE_NEST;
+"ADMISSIBLE_NSUM",ADMISSIBLE_NSUM;
+"ADMISSIBLE_RAND",ADMISSIBLE_RAND;
+"ADMISSIBLE_SEQPATTERN",ADMISSIBLE_SEQPATTERN;
+"ADMISSIBLE_SUM",ADMISSIBLE_SUM;
+"ADMISSIBLE_UNGUARDED_PATTERN",ADMISSIBLE_UNGUARDED_PATTERN;
+"AFFINE",AFFINE;
+"AFFINE_AFFINE_HULL",AFFINE_AFFINE_HULL;
+"AFFINE_AFFINITY",AFFINE_AFFINITY;
+"AFFINE_ALT",AFFINE_ALT;
+"AFFINE_BASIS_EXISTS",AFFINE_BASIS_EXISTS;
+"AFFINE_BOUNDED_EQ_LOWDIM",AFFINE_BOUNDED_EQ_LOWDIM;
+"AFFINE_BOUNDED_EQ_TRIVIAL",AFFINE_BOUNDED_EQ_TRIVIAL;
+"AFFINE_DEPENDENT_BIGGERSET",AFFINE_DEPENDENT_BIGGERSET;
+"AFFINE_DEPENDENT_BIGGERSET_GENERAL",AFFINE_DEPENDENT_BIGGERSET_GENERAL;
+"AFFINE_DEPENDENT_CHOOSE",AFFINE_DEPENDENT_CHOOSE;
+"AFFINE_DEPENDENT_EXPLICIT",AFFINE_DEPENDENT_EXPLICIT;
+"AFFINE_DEPENDENT_EXPLICIT_FINITE",AFFINE_DEPENDENT_EXPLICIT_FINITE;
+"AFFINE_DEPENDENT_IMP_COLLINEAR_3",AFFINE_DEPENDENT_IMP_COLLINEAR_3;
+"AFFINE_DEPENDENT_IMP_DEPENDENT",AFFINE_DEPENDENT_IMP_DEPENDENT;
+"AFFINE_DEPENDENT_LINEAR_IMAGE",AFFINE_DEPENDENT_LINEAR_IMAGE;
+"AFFINE_DEPENDENT_LINEAR_IMAGE_EQ",AFFINE_DEPENDENT_LINEAR_IMAGE_EQ;
+"AFFINE_DEPENDENT_MONO",AFFINE_DEPENDENT_MONO;
+"AFFINE_DEPENDENT_TRANSLATION",AFFINE_DEPENDENT_TRANSLATION;
+"AFFINE_DEPENDENT_TRANSLATION_EQ",AFFINE_DEPENDENT_TRANSLATION_EQ;
+"AFFINE_DIFFERENCES",AFFINE_DIFFERENCES;
+"AFFINE_DIFFS_SUBSPACE",AFFINE_DIFFS_SUBSPACE;
+"AFFINE_EMPTY",AFFINE_EMPTY;
+"AFFINE_EQ_SUBSPACE",AFFINE_EQ_SUBSPACE;
+"AFFINE_EXPLICIT",AFFINE_EXPLICIT;
+"AFFINE_HULLS_EQ",AFFINE_HULLS_EQ;
+"AFFINE_HULL_2",AFFINE_HULL_2;
+"AFFINE_HULL_2_ALT",AFFINE_HULL_2_ALT;
+"AFFINE_HULL_3",AFFINE_HULL_3;
+"AFFINE_HULL_3_IMP_COLLINEAR",AFFINE_HULL_3_IMP_COLLINEAR;
+"AFFINE_HULL_AFFINE_INTER_NONEMPTY_INTERIOR",AFFINE_HULL_AFFINE_INTER_NONEMPTY_INTERIOR;
+"AFFINE_HULL_AFFINE_INTER_OPEN",AFFINE_HULL_AFFINE_INTER_OPEN;
+"AFFINE_HULL_AFFINE_INTER_OPEN_IN",AFFINE_HULL_AFFINE_INTER_OPEN_IN;
+"AFFINE_HULL_CLOSURE",AFFINE_HULL_CLOSURE;
+"AFFINE_HULL_CONVEX_HULL",AFFINE_HULL_CONVEX_HULL;
+"AFFINE_HULL_CONVEX_INTER_NONEMPTY_INTERIOR",AFFINE_HULL_CONVEX_INTER_NONEMPTY_INTERIOR;
+"AFFINE_HULL_CONVEX_INTER_OPEN",AFFINE_HULL_CONVEX_INTER_OPEN;
+"AFFINE_HULL_CONVEX_INTER_OPEN_IN",AFFINE_HULL_CONVEX_INTER_OPEN_IN;
+"AFFINE_HULL_EMPTY",AFFINE_HULL_EMPTY;
+"AFFINE_HULL_EQ",AFFINE_HULL_EQ;
+"AFFINE_HULL_EQ_EMPTY",AFFINE_HULL_EQ_EMPTY;
+"AFFINE_HULL_EQ_SING",AFFINE_HULL_EQ_SING;
+"AFFINE_HULL_EQ_SPAN",AFFINE_HULL_EQ_SPAN;
+"AFFINE_HULL_EQ_SPAN_EQ",AFFINE_HULL_EQ_SPAN_EQ;
+"AFFINE_HULL_EXPLICIT",AFFINE_HULL_EXPLICIT;
+"AFFINE_HULL_EXPLICIT_ALT",AFFINE_HULL_EXPLICIT_ALT;
+"AFFINE_HULL_EXPLICIT_UNIQUE",AFFINE_HULL_EXPLICIT_UNIQUE;
+"AFFINE_HULL_FACE_OF_DISJOINT_RELATIVE_INTERIOR",AFFINE_HULL_FACE_OF_DISJOINT_RELATIVE_INTERIOR;
+"AFFINE_HULL_FINITE",AFFINE_HULL_FINITE;
+"AFFINE_HULL_FINITE_INTERSECTION_HYPERPLANES",AFFINE_HULL_FINITE_INTERSECTION_HYPERPLANES;
+"AFFINE_HULL_FINITE_STEP",AFFINE_HULL_FINITE_STEP;
+"AFFINE_HULL_FINITE_STEP_GEN",AFFINE_HULL_FINITE_STEP_GEN;
+"AFFINE_HULL_HALFSPACE_GE",AFFINE_HULL_HALFSPACE_GE;
+"AFFINE_HULL_HALFSPACE_GT",AFFINE_HULL_HALFSPACE_GT;
+"AFFINE_HULL_HALFSPACE_LE",AFFINE_HULL_HALFSPACE_LE;
+"AFFINE_HULL_HALFSPACE_LT",AFFINE_HULL_HALFSPACE_LT;
+"AFFINE_HULL_INDEXED",AFFINE_HULL_INDEXED;
+"AFFINE_HULL_INSERT_SPAN",AFFINE_HULL_INSERT_SPAN;
+"AFFINE_HULL_INSERT_SUBSET_SPAN",AFFINE_HULL_INSERT_SUBSET_SPAN;
+"AFFINE_HULL_INTER",AFFINE_HULL_INTER;
+"AFFINE_HULL_INTERS",AFFINE_HULL_INTERS;
+"AFFINE_HULL_LINEAR_IMAGE",AFFINE_HULL_LINEAR_IMAGE;
+"AFFINE_HULL_NONEMPTY_INTERIOR",AFFINE_HULL_NONEMPTY_INTERIOR;
+"AFFINE_HULL_OPEN",AFFINE_HULL_OPEN;
+"AFFINE_HULL_OPEN_IN",AFFINE_HULL_OPEN_IN;
+"AFFINE_HULL_PCROSS",AFFINE_HULL_PCROSS;
+"AFFINE_HULL_RELATIVE_INTERIOR",AFFINE_HULL_RELATIVE_INTERIOR;
+"AFFINE_HULL_SEGMENT",AFFINE_HULL_SEGMENT;
+"AFFINE_HULL_SING",AFFINE_HULL_SING;
+"AFFINE_HULL_SPAN",AFFINE_HULL_SPAN;
+"AFFINE_HULL_SUBSET_SPAN",AFFINE_HULL_SUBSET_SPAN;
+"AFFINE_HULL_TRANSLATION",AFFINE_HULL_TRANSLATION;
+"AFFINE_HULL_UNIV",AFFINE_HULL_UNIV;
+"AFFINE_HYPERPLANE",AFFINE_HYPERPLANE;
+"AFFINE_HYPERPLANE_SUMS_EQ_UNIV",AFFINE_HYPERPLANE_SUMS_EQ_UNIV;
+"AFFINE_IMP_CONVEX",AFFINE_IMP_CONVEX;
+"AFFINE_IMP_POLYHEDRON",AFFINE_IMP_POLYHEDRON;
+"AFFINE_IMP_SUBSPACE",AFFINE_IMP_SUBSPACE;
+"AFFINE_INDEPENDENT_1",AFFINE_INDEPENDENT_1;
+"AFFINE_INDEPENDENT_2",AFFINE_INDEPENDENT_2;
+"AFFINE_INDEPENDENT_CARD_DIM_DIFFS",AFFINE_INDEPENDENT_CARD_DIM_DIFFS;
+"AFFINE_INDEPENDENT_CARD_LE",AFFINE_INDEPENDENT_CARD_LE;
+"AFFINE_INDEPENDENT_CONVEX_AFFINE_HULL",AFFINE_INDEPENDENT_CONVEX_AFFINE_HULL;
+"AFFINE_INDEPENDENT_DELETE",AFFINE_INDEPENDENT_DELETE;
+"AFFINE_INDEPENDENT_EMPTY",AFFINE_INDEPENDENT_EMPTY;
+"AFFINE_INDEPENDENT_IFF_CARD",AFFINE_INDEPENDENT_IFF_CARD;
+"AFFINE_INDEPENDENT_IMP_FINITE",AFFINE_INDEPENDENT_IMP_FINITE;
+"AFFINE_INDEPENDENT_INSERT",AFFINE_INDEPENDENT_INSERT;
+"AFFINE_INDEPENDENT_SPAN_EQ",AFFINE_INDEPENDENT_SPAN_EQ;
+"AFFINE_INDEPENDENT_SPAN_GT",AFFINE_INDEPENDENT_SPAN_GT;
+"AFFINE_INDEPENDENT_STDBASIS",AFFINE_INDEPENDENT_STDBASIS;
+"AFFINE_INDEPENDENT_SUBSET",AFFINE_INDEPENDENT_SUBSET;
+"AFFINE_INDEXED",AFFINE_INDEXED;
+"AFFINE_INTER",AFFINE_INTER;
+"AFFINE_INTERS",AFFINE_INTERS;
+"AFFINE_LINEAR_IMAGE",AFFINE_LINEAR_IMAGE;
+"AFFINE_LINEAR_IMAGE_EQ",AFFINE_LINEAR_IMAGE_EQ;
+"AFFINE_NEGATIONS",AFFINE_NEGATIONS;
+"AFFINE_PARALLEL_SLICE",AFFINE_PARALLEL_SLICE;
+"AFFINE_PCROSS",AFFINE_PCROSS;
+"AFFINE_PCROSS_EQ",AFFINE_PCROSS_EQ;
+"AFFINE_SCALING",AFFINE_SCALING;
+"AFFINE_SCALING_EQ",AFFINE_SCALING_EQ;
+"AFFINE_SING",AFFINE_SING;
+"AFFINE_SPAN",AFFINE_SPAN;
+"AFFINE_STANDARD_HYPERPLANE",AFFINE_STANDARD_HYPERPLANE;
+"AFFINE_SUMS",AFFINE_SUMS;
+"AFFINE_TRANSLATION",AFFINE_TRANSLATION;
+"AFFINE_TRANSLATION_EQ",AFFINE_TRANSLATION_EQ;
+"AFFINE_TRANSLATION_SUBSPACE",AFFINE_TRANSLATION_SUBSPACE;
+"AFFINE_TRANSLATION_SUBSPACE_EXPLICIT",AFFINE_TRANSLATION_SUBSPACE_EXPLICIT;
+"AFFINE_TRANSLATION_UNIQUE_SUBSPACE",AFFINE_TRANSLATION_UNIQUE_SUBSPACE;
+"AFFINE_UNIV",AFFINE_UNIV;
+"AFFINE_VSUM",AFFINE_VSUM;
+"AFFINITY_INVERSES",AFFINITY_INVERSES;
+"AFF_DIM",AFF_DIM;
+"AFF_DIM_2",AFF_DIM_2;
+"AFF_DIM_AFFINE_HULL",AFF_DIM_AFFINE_HULL;
+"AFF_DIM_AFFINE_INDEPENDENT",AFF_DIM_AFFINE_INDEPENDENT;
+"AFF_DIM_AFFINE_INTER_HYPERPLANE",AFF_DIM_AFFINE_INTER_HYPERPLANE;
+"AFF_DIM_BALL",AFF_DIM_BALL;
+"AFF_DIM_CBALL",AFF_DIM_CBALL;
+"AFF_DIM_CLOSURE",AFF_DIM_CLOSURE;
+"AFF_DIM_CONVEX_HULL",AFF_DIM_CONVEX_HULL;
+"AFF_DIM_CONVEX_INTER_NONEMPTY_INTERIOR",AFF_DIM_CONVEX_INTER_NONEMPTY_INTERIOR;
+"AFF_DIM_CONVEX_INTER_OPEN",AFF_DIM_CONVEX_INTER_OPEN;
+"AFF_DIM_DIM_0",AFF_DIM_DIM_0;
+"AFF_DIM_DIM_AFFINE_DIFFS",AFF_DIM_DIM_AFFINE_DIFFS;
+"AFF_DIM_DIM_SUBSPACE",AFF_DIM_DIM_SUBSPACE;
+"AFF_DIM_EMPTY",AFF_DIM_EMPTY;
+"AFF_DIM_EQ_0",AFF_DIM_EQ_0;
+"AFF_DIM_EQ_AFFINE_HULL",AFF_DIM_EQ_AFFINE_HULL;
+"AFF_DIM_EQ_FULL",AFF_DIM_EQ_FULL;
+"AFF_DIM_EQ_HYPERPLANE",AFF_DIM_EQ_HYPERPLANE;
+"AFF_DIM_EQ_MINUS1",AFF_DIM_EQ_MINUS1;
+"AFF_DIM_GE",AFF_DIM_GE;
+"AFF_DIM_HALFSPACE_GE",AFF_DIM_HALFSPACE_GE;
+"AFF_DIM_HALFSPACE_GT",AFF_DIM_HALFSPACE_GT;
+"AFF_DIM_HALFSPACE_LE",AFF_DIM_HALFSPACE_LE;
+"AFF_DIM_HALFSPACE_LT",AFF_DIM_HALFSPACE_LT;
+"AFF_DIM_HYPERPLANE",AFF_DIM_HYPERPLANE;
+"AFF_DIM_INJECTIVE_LINEAR_IMAGE",AFF_DIM_INJECTIVE_LINEAR_IMAGE;
+"AFF_DIM_INSERT",AFF_DIM_INSERT;
+"AFF_DIM_INTERVAL",AFF_DIM_INTERVAL;
+"AFF_DIM_LE_CARD",AFF_DIM_LE_CARD;
+"AFF_DIM_LE_DIM",AFF_DIM_LE_DIM;
+"AFF_DIM_LE_UNIV",AFF_DIM_LE_UNIV;
+"AFF_DIM_LINEAR_IMAGE_LE",AFF_DIM_LINEAR_IMAGE_LE;
+"AFF_DIM_LT_FULL",AFF_DIM_LT_FULL;
+"AFF_DIM_NONEMPTY_INTERIOR",AFF_DIM_NONEMPTY_INTERIOR;
+"AFF_DIM_NONEMPTY_INTERIOR_EQ",AFF_DIM_NONEMPTY_INTERIOR_EQ;
+"AFF_DIM_OPEN",AFF_DIM_OPEN;
+"AFF_DIM_OPEN_IN",AFF_DIM_OPEN_IN;
+"AFF_DIM_POS_LE",AFF_DIM_POS_LE;
+"AFF_DIM_PSUBSET",AFF_DIM_PSUBSET;
+"AFF_DIM_SIMPLEX",AFF_DIM_SIMPLEX;
+"AFF_DIM_SING",AFF_DIM_SING;
+"AFF_DIM_SUBSET",AFF_DIM_SUBSET;
+"AFF_DIM_SUMS_INTER",AFF_DIM_SUMS_INTER;
+"AFF_DIM_TRANSLATION_EQ",AFF_DIM_TRANSLATION_EQ;
+"AFF_DIM_UNIQUE",AFF_DIM_UNIQUE;
+"AFF_DIM_UNIV",AFF_DIM_UNIV;
+"AFF_LOWDIM_SUBSET_HYPERPLANE",AFF_LOWDIM_SUBSET_HYPERPLANE;
+"ALL",ALL;
+"ALL2",ALL2;
+"ALL2_ALL",ALL2_ALL;
+"ALL2_AND_RIGHT",ALL2_AND_RIGHT;
+"ALL2_DEF",ALL2_DEF;
+"ALL2_MAP",ALL2_MAP;
+"ALL2_MAP2",ALL2_MAP2;
+"ALL_APPEND",ALL_APPEND;
+"ALL_EL",ALL_EL;
+"ALL_FILTER",ALL_FILTER;
+"ALL_IMP",ALL_IMP;
+"ALL_MAP",ALL_MAP;
+"ALL_MEM",ALL_MEM;
+"ALL_MP",ALL_MP;
+"ALL_T",ALL_T;
+"ALWAYS_EVENTUALLY",ALWAYS_EVENTUALLY;
+"AND_ALL",AND_ALL;
+"AND_ALL2",AND_ALL2;
+"AND_CLAUSES",AND_CLAUSES;
+"AND_DEF",AND_DEF;
+"AND_FORALL_THM",AND_FORALL_THM;
+"ANR_RELATIVE_FRONTIER_CONVEX",ANR_RELATIVE_FRONTIER_CONVEX;
+"ANTIDERIVATIVE_CONTINUOUS",ANTIDERIVATIVE_CONTINUOUS;
+"ANTIDERIVATIVE_INTEGRAL_CONTINUOUS",ANTIDERIVATIVE_INTEGRAL_CONTINUOUS;
+"ANY_CLOSEST_POINT_AFFINE_ORTHOGONAL",ANY_CLOSEST_POINT_AFFINE_ORTHOGONAL;
+"ANY_CLOSEST_POINT_DOT",ANY_CLOSEST_POINT_DOT;
+"ANY_CLOSEST_POINT_UNIQUE",ANY_CLOSEST_POINT_UNIQUE;
+"APPEND",APPEND;
+"APPEND_ASSOC",APPEND_ASSOC;
+"APPEND_BUTLAST_LAST",APPEND_BUTLAST_LAST;
+"APPEND_EQ_NIL",APPEND_EQ_NIL;
+"APPEND_NIL",APPEND_NIL;
+"APPEND_SING",APPEND_SING;
+"APPROACHABLE_LT_LE",APPROACHABLE_LT_LE;
+"APPROXIMABLE_ON_DIVISION",APPROXIMABLE_ON_DIVISION;
+"ARC_ASSOC",ARC_ASSOC;
+"ARC_CONNECTED_TRANS",ARC_CONNECTED_TRANS;
+"ARC_DISTINCT_ENDS",ARC_DISTINCT_ENDS;
+"ARC_IMP_PATH",ARC_IMP_PATH;
+"ARC_IMP_SIMPLE_PATH",ARC_IMP_SIMPLE_PATH;
+"ARC_JOIN",ARC_JOIN;
+"ARC_JOIN_EQ",ARC_JOIN_EQ;
+"ARC_JOIN_EQ_ALT",ARC_JOIN_EQ_ALT;
+"ARC_LINEAR_IMAGE_EQ",ARC_LINEAR_IMAGE_EQ;
+"ARC_LINEPATH",ARC_LINEPATH;
+"ARC_LINEPATH_EQ",ARC_LINEPATH_EQ;
+"ARC_REVERSEPATH",ARC_REVERSEPATH;
+"ARC_SIMPLE_PATH",ARC_SIMPLE_PATH;
+"ARC_SIMPLE_PATH_SUBPATH",ARC_SIMPLE_PATH_SUBPATH;
+"ARC_SIMPLE_PATH_SUBPATH_INTERIOR",ARC_SIMPLE_PATH_SUBPATH_INTERIOR;
+"ARC_SUBPATH_ARC",ARC_SUBPATH_ARC;
+"ARC_SUBPATH_EQ",ARC_SUBPATH_EQ;
+"ARC_TRANSLATION_EQ",ARC_TRANSLATION_EQ;
+"ARITH",ARITH;
+"ARITH_ADD",ARITH_ADD;
+"ARITH_EQ",ARITH_EQ;
+"ARITH_EVEN",ARITH_EVEN;
+"ARITH_EXP",ARITH_EXP;
+"ARITH_GE",ARITH_GE;
+"ARITH_GT",ARITH_GT;
+"ARITH_LE",ARITH_LE;
+"ARITH_LT",ARITH_LT;
+"ARITH_MULT",ARITH_MULT;
+"ARITH_ODD",ARITH_ODD;
+"ARITH_PRE",ARITH_PRE;
+"ARITH_SUB",ARITH_SUB;
+"ARITH_SUC",ARITH_SUC;
+"ARITH_ZERO",ARITH_ZERO;
+"ARZELA_ASCOLI",ARZELA_ASCOLI;
+"ASSOC",ASSOC;
+"AT",AT;
+"AT_INFINITY",AT_INFINITY;
+"AUSTIN_LEMMA",AUSTIN_LEMMA;
+"BABY_SARD",BABY_SARD;
+"BALL_1",BALL_1;
+"BALL_EMPTY",BALL_EMPTY;
+"BALL_EQ_EMPTY",BALL_EQ_EMPTY;
+"BALL_INTERVAL",BALL_INTERVAL;
+"BALL_INTERVAL_0",BALL_INTERVAL_0;
+"BALL_LINEAR_IMAGE",BALL_LINEAR_IMAGE;
+"BALL_MAX_UNION",BALL_MAX_UNION;
+"BALL_MIN_INTER",BALL_MIN_INTER;
+"BALL_SCALING",BALL_SCALING;
+"BALL_SUBSET_CBALL",BALL_SUBSET_CBALL;
+"BALL_SUBSET_OPEN_MAP_IMAGE",BALL_SUBSET_OPEN_MAP_IMAGE;
+"BALL_TRANSLATION",BALL_TRANSLATION;
+"BALL_TRIVIAL",BALL_TRIVIAL;
+"BALL_UNION_SPHERE",BALL_UNION_SPHERE;
+"BANACH_FIX",BANACH_FIX;
+"BASIS_CARD_EQ_DIM",BASIS_CARD_EQ_DIM;
+"BASIS_COMPONENT",BASIS_COMPONENT;
+"BASIS_COORDINATES_CONTINUOUS",BASIS_COORDINATES_CONTINUOUS;
+"BASIS_COORDINATES_LIPSCHITZ",BASIS_COORDINATES_LIPSCHITZ;
+"BASIS_EQ_0",BASIS_EQ_0;
+"BASIS_EXISTS",BASIS_EXISTS;
+"BASIS_EXISTS_FINITE",BASIS_EXISTS_FINITE;
+"BASIS_EXPANSION",BASIS_EXPANSION;
+"BASIS_EXPANSION_UNIQUE",BASIS_EXPANSION_UNIQUE;
+"BASIS_HAS_SIZE_DIM",BASIS_HAS_SIZE_DIM;
+"BASIS_HAS_SIZE_UNIV",BASIS_HAS_SIZE_UNIV;
+"BASIS_INJ",BASIS_INJ;
+"BASIS_INJ_EQ",BASIS_INJ_EQ;
+"BASIS_NE",BASIS_NE;
+"BASIS_NONZERO",BASIS_NONZERO;
+"BASIS_ORTHOGONAL",BASIS_ORTHOGONAL;
+"BASIS_SUBSPACE_EXISTS",BASIS_SUBSPACE_EXISTS;
+"BEPPO_LEVI_DECREASING",BEPPO_LEVI_DECREASING;
+"BEPPO_LEVI_INCREASING",BEPPO_LEVI_INCREASING;
+"BEPPO_LEVI_MONOTONE_CONVERGENCE_DECREASING",BEPPO_LEVI_MONOTONE_CONVERGENCE_DECREASING;
+"BEPPO_LEVI_MONOTONE_CONVERGENCE_INCREASING",BEPPO_LEVI_MONOTONE_CONVERGENCE_INCREASING;
+"BESSEL_INEQUALITY",BESSEL_INEQUALITY;
+"BETA_THM",BETA_THM;
+"BETWEEN_ANTISYM",BETWEEN_ANTISYM;
+"BETWEEN_COLLINEAR_DIST_EQ",BETWEEN_COLLINEAR_DIST_EQ;
+"BETWEEN_DIST_LE",BETWEEN_DIST_LE;
+"BETWEEN_DIST_LT",BETWEEN_DIST_LT;
+"BETWEEN_DOT",BETWEEN_DOT;
+"BETWEEN_EXISTS_EXTENSION",BETWEEN_EXISTS_EXTENSION;
+"BETWEEN_IMP_COLLINEAR",BETWEEN_IMP_COLLINEAR;
+"BETWEEN_IN_CONVEX_HULL",BETWEEN_IN_CONVEX_HULL;
+"BETWEEN_IN_SEGMENT",BETWEEN_IN_SEGMENT;
+"BETWEEN_LINEAR_IMAGE_EQ",BETWEEN_LINEAR_IMAGE_EQ;
+"BETWEEN_MIDPOINT",BETWEEN_MIDPOINT;
+"BETWEEN_NORM",BETWEEN_NORM;
+"BETWEEN_NORM_LE",BETWEEN_NORM_LE;
+"BETWEEN_NORM_LT",BETWEEN_NORM_LT;
+"BETWEEN_REFL",BETWEEN_REFL;
+"BETWEEN_REFL_EQ",BETWEEN_REFL_EQ;
+"BETWEEN_SYM",BETWEEN_SYM;
+"BETWEEN_TRANS",BETWEEN_TRANS;
+"BETWEEN_TRANSLATION",BETWEEN_TRANSLATION;
+"BETWEEN_TRANS_2",BETWEEN_TRANS_2;
+"BIJ",BIJ;
+"BIJECTIONS_CARD_EQ",BIJECTIONS_CARD_EQ;
+"BIJECTIONS_HAS_SIZE",BIJECTIONS_HAS_SIZE;
+"BIJECTIONS_HAS_SIZE_EQ",BIJECTIONS_HAS_SIZE_EQ;
+"BIJECTIVE_INJECTIVE_SURJECTIVE",BIJECTIVE_INJECTIVE_SURJECTIVE;
+"BIJECTIVE_INVERSES",BIJECTIVE_INVERSES;
+"BIJECTIVE_LEFT_RIGHT_INVERSE",BIJECTIVE_LEFT_RIGHT_INVERSE;
+"BIJECTIVE_ON_LEFT_RIGHT_INVERSE",BIJECTIVE_ON_LEFT_RIGHT_INVERSE;
+"BILINEAR_BOUNDED",BILINEAR_BOUNDED;
+"BILINEAR_BOUNDED_POS",BILINEAR_BOUNDED_POS;
+"BILINEAR_CONTINUOUS_COMPOSE",BILINEAR_CONTINUOUS_COMPOSE;
+"BILINEAR_CONTINUOUS_ON_COMPOSE",BILINEAR_CONTINUOUS_ON_COMPOSE;
+"BILINEAR_DIFFERENTIABLE_AT_COMPOSE",BILINEAR_DIFFERENTIABLE_AT_COMPOSE;
+"BILINEAR_DIFFERENTIABLE_ON_COMPOSE",BILINEAR_DIFFERENTIABLE_ON_COMPOSE;
+"BILINEAR_DIFFERENTIABLE_WITHIN_COMPOSE",BILINEAR_DIFFERENTIABLE_WITHIN_COMPOSE;
+"BILINEAR_DOT",BILINEAR_DOT;
+"BILINEAR_DROP_MUL",BILINEAR_DROP_MUL;
+"BILINEAR_EQ",BILINEAR_EQ;
+"BILINEAR_EQ_MBASIS",BILINEAR_EQ_MBASIS;
+"BILINEAR_EQ_STDBASIS",BILINEAR_EQ_STDBASIS;
+"BILINEAR_GEOM",BILINEAR_GEOM;
+"BILINEAR_INNER",BILINEAR_INNER;
+"BILINEAR_LADD",BILINEAR_LADD;
+"BILINEAR_LMUL",BILINEAR_LMUL;
+"BILINEAR_LNEG",BILINEAR_LNEG;
+"BILINEAR_LSUB",BILINEAR_LSUB;
+"BILINEAR_LZERO",BILINEAR_LZERO;
+"BILINEAR_OUTER",BILINEAR_OUTER;
+"BILINEAR_PRODUCT",BILINEAR_PRODUCT;
+"BILINEAR_RADD",BILINEAR_RADD;
+"BILINEAR_RMUL",BILINEAR_RMUL;
+"BILINEAR_RNEG",BILINEAR_RNEG;
+"BILINEAR_RSUB",BILINEAR_RSUB;
+"BILINEAR_RZERO",BILINEAR_RZERO;
+"BILINEAR_UNIFORMLY_CONTINUOUS_ON_COMPOSE",BILINEAR_UNIFORMLY_CONTINUOUS_ON_COMPOSE;
+"BILINEAR_VSUM",BILINEAR_VSUM;
+"BILINEAR_VSUM_PARTIAL_PRE",BILINEAR_VSUM_PARTIAL_PRE;
+"BILINEAR_VSUM_PARTIAL_SUC",BILINEAR_VSUM_PARTIAL_SUC;
+"BINARYSUM_BITSET",BINARYSUM_BITSET;
+"BINARYSUM_BOUND",BINARYSUM_BOUND;
+"BINARYSUM_BOUND_EQ",BINARYSUM_BOUND_EQ;
+"BINARYSUM_BOUND_LEMMA",BINARYSUM_BOUND_LEMMA;
+"BINARYSUM_DIV",BINARYSUM_DIV;
+"BINARYSUM_DIV_DIVISIBLE",BINARYSUM_DIV_DIVISIBLE;
+"BINARY_INDUCT",BINARY_INDUCT;
+"BIT0",BIT0;
+"BIT0_DEF",BIT0_DEF;
+"BIT0_THM",BIT0_THM;
+"BIT1",BIT1;
+"BIT1_DEF",BIT1_DEF;
+"BIT1_THM",BIT1_THM;
+"BITSET_0",BITSET_0;
+"BITSET_BINARYSUM",BITSET_BINARYSUM;
+"BITSET_BOUND",BITSET_BOUND;
+"BITSET_BOUND_EQ",BITSET_BOUND_EQ;
+"BITSET_BOUND_LEMMA",BITSET_BOUND_LEMMA;
+"BITSET_BOUND_WEAK",BITSET_BOUND_WEAK;
+"BITSET_EQ",BITSET_EQ;
+"BITSET_EQ_EMPTY",BITSET_EQ_EMPTY;
+"BITSET_STEP",BITSET_STEP;
+"BOLZANO_WEIERSTRASS",BOLZANO_WEIERSTRASS;
+"BOLZANO_WEIERSTRASS_CONTRAPOS",BOLZANO_WEIERSTRASS_CONTRAPOS;
+"BOLZANO_WEIERSTRASS_IMP_BOUNDED",BOLZANO_WEIERSTRASS_IMP_BOUNDED;
+"BOLZANO_WEIERSTRASS_IMP_CLOSED",BOLZANO_WEIERSTRASS_IMP_CLOSED;
+"BOOL_CASES_AX",BOOL_CASES_AX;
+"BORSUK_HOMOTOPY_EXTENSION",BORSUK_HOMOTOPY_EXTENSION;
+"BOTTOM",BOTTOM;
+"BOUNDED_ARC_IMAGE",BOUNDED_ARC_IMAGE;
+"BOUNDED_BALL",BOUNDED_BALL;
+"BOUNDED_CBALL",BOUNDED_CBALL;
+"BOUNDED_CLOSED_CHAIN",BOUNDED_CLOSED_CHAIN;
+"BOUNDED_CLOSED_IMP_COMPACT",BOUNDED_CLOSED_IMP_COMPACT;
+"BOUNDED_CLOSED_INTERVAL",BOUNDED_CLOSED_INTERVAL;
+"BOUNDED_CLOSED_NEST",BOUNDED_CLOSED_NEST;
+"BOUNDED_CLOSURE",BOUNDED_CLOSURE;
+"BOUNDED_CLOSURE_EQ",BOUNDED_CLOSURE_EQ;
+"BOUNDED_COMPONENTWISE",BOUNDED_COMPONENTWISE;
+"BOUNDED_CONVEX_HULL",BOUNDED_CONVEX_HULL;
+"BOUNDED_CONVEX_HULL_EQ",BOUNDED_CONVEX_HULL_EQ;
+"BOUNDED_DECREASING_CONVERGENT",BOUNDED_DECREASING_CONVERGENT;
+"BOUNDED_DIFF",BOUNDED_DIFF;
+"BOUNDED_DIFFS",BOUNDED_DIFFS;
+"BOUNDED_EMPTY",BOUNDED_EMPTY;
+"BOUNDED_EQUIINTEGRAL_OVER_THIN_TAGGED_PARTIAL_DIVISION",BOUNDED_EQUIINTEGRAL_OVER_THIN_TAGGED_PARTIAL_DIVISION;
+"BOUNDED_FINITE",BOUNDED_FINITE;
+"BOUNDED_FRONTIER",BOUNDED_FRONTIER;
+"BOUNDED_FUNCTIONS_BIJECTIONS_1",BOUNDED_FUNCTIONS_BIJECTIONS_1;
+"BOUNDED_FUNCTIONS_BIJECTIONS_2",BOUNDED_FUNCTIONS_BIJECTIONS_2;
+"BOUNDED_HALFSPACE_GE",BOUNDED_HALFSPACE_GE;
+"BOUNDED_HALFSPACE_GT",BOUNDED_HALFSPACE_GT;
+"BOUNDED_HALFSPACE_LE",BOUNDED_HALFSPACE_LE;
+"BOUNDED_HALFSPACE_LT",BOUNDED_HALFSPACE_LT;
+"BOUNDED_HAS_INF",BOUNDED_HAS_INF;
+"BOUNDED_HAS_SUP",BOUNDED_HAS_SUP;
+"BOUNDED_HYPERPLANE_EQ_TRIVIAL",BOUNDED_HYPERPLANE_EQ_TRIVIAL;
+"BOUNDED_INCREASING_CONVERGENT",BOUNDED_INCREASING_CONVERGENT;
+"BOUNDED_INSERT",BOUNDED_INSERT;
+"BOUNDED_INSIDE",BOUNDED_INSIDE;
+"BOUNDED_INTER",BOUNDED_INTER;
+"BOUNDED_INTERIOR",BOUNDED_INTERIOR;
+"BOUNDED_INTERS",BOUNDED_INTERS;
+"BOUNDED_INTERVAL",BOUNDED_INTERVAL;
+"BOUNDED_LIFT",BOUNDED_LIFT;
+"BOUNDED_LINEAR_IMAGE",BOUNDED_LINEAR_IMAGE;
+"BOUNDED_LINEAR_IMAGE_EQ",BOUNDED_LINEAR_IMAGE_EQ;
+"BOUNDED_NEGATIONS",BOUNDED_NEGATIONS;
+"BOUNDED_PARTIAL_SUMS",BOUNDED_PARTIAL_SUMS;
+"BOUNDED_PATH_IMAGE",BOUNDED_PATH_IMAGE;
+"BOUNDED_PCROSS",BOUNDED_PCROSS;
+"BOUNDED_PCROSS_EQ",BOUNDED_PCROSS_EQ;
+"BOUNDED_POS",BOUNDED_POS;
+"BOUNDED_POS_LT",BOUNDED_POS_LT;
+"BOUNDED_RECTIFIABLE_PATH_IMAGE",BOUNDED_RECTIFIABLE_PATH_IMAGE;
+"BOUNDED_RELATIVE_FRONTIER",BOUNDED_RELATIVE_FRONTIER;
+"BOUNDED_SCALING",BOUNDED_SCALING;
+"BOUNDED_SEGMENT",BOUNDED_SEGMENT;
+"BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE",BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE;
+"BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE_INTERVAL",BOUNDED_SETVARIATION_ABSOLUTELY_INTEGRABLE_INTERVAL;
+"BOUNDED_SIMPLE_PATH_IMAGE",BOUNDED_SIMPLE_PATH_IMAGE;
+"BOUNDED_SING",BOUNDED_SING;
+"BOUNDED_SPHERE",BOUNDED_SPHERE;
+"BOUNDED_SUBSET",BOUNDED_SUBSET;
+"BOUNDED_SUBSET_BALL",BOUNDED_SUBSET_BALL;
+"BOUNDED_SUBSET_CBALL",BOUNDED_SUBSET_CBALL;
+"BOUNDED_SUBSET_CLOSED_INTERVAL",BOUNDED_SUBSET_CLOSED_INTERVAL;
+"BOUNDED_SUBSET_CLOSED_INTERVAL_SYMMETRIC",BOUNDED_SUBSET_CLOSED_INTERVAL_SYMMETRIC;
+"BOUNDED_SUBSET_OPEN_INTERVAL",BOUNDED_SUBSET_OPEN_INTERVAL;
+"BOUNDED_SUBSET_OPEN_INTERVAL_SYMMETRIC",BOUNDED_SUBSET_OPEN_INTERVAL_SYMMETRIC;
+"BOUNDED_SUMS",BOUNDED_SUMS;
+"BOUNDED_SUMS_IMAGE",BOUNDED_SUMS_IMAGE;
+"BOUNDED_SUMS_IMAGES",BOUNDED_SUMS_IMAGES;
+"BOUNDED_TRANSLATION",BOUNDED_TRANSLATION;
+"BOUNDED_TRANSLATION_EQ",BOUNDED_TRANSLATION_EQ;
+"BOUNDED_UNIFORMLY_CONTINUOUS_IMAGE",BOUNDED_UNIFORMLY_CONTINUOUS_IMAGE;
+"BOUNDED_UNION",BOUNDED_UNION;
+"BOUNDED_UNIONS",BOUNDED_UNIONS;
+"BOUNDED_UNIQUE_OUTSIDE",BOUNDED_UNIQUE_OUTSIDE;
+"BOUNDS_DIVIDED",BOUNDS_DIVIDED;
+"BOUNDS_IGNORE",BOUNDS_IGNORE;
+"BOUNDS_LINEAR",BOUNDS_LINEAR;
+"BOUNDS_LINEAR_0",BOUNDS_LINEAR_0;
+"BOUNDS_NOTZERO",BOUNDS_NOTZERO;
+"BROUWER",BROUWER;
+"BROUWER_BALL",BROUWER_BALL;
+"BROUWER_COMPACTNESS_LEMMA",BROUWER_COMPACTNESS_LEMMA;
+"BROUWER_CONTRACTIBLE_ANR",BROUWER_CONTRACTIBLE_ANR;
+"BROUWER_CUBE",BROUWER_CUBE;
+"BROUWER_INESSENTIAL_ANR",BROUWER_INESSENTIAL_ANR;
+"BROUWER_REDUCTION_THEOREM",BROUWER_REDUCTION_THEOREM;
+"BROUWER_REDUCTION_THEOREM_GEN",BROUWER_REDUCTION_THEOREM_GEN;
+"BROUWER_SURJECTIVE",BROUWER_SURJECTIVE;
+"BROUWER_SURJECTIVE_CBALL",BROUWER_SURJECTIVE_CBALL;
+"BROUWER_WEAK",BROUWER_WEAK;
+"BUTLAST",BUTLAST;
+"CANTOR_THM",CANTOR_THM;
+"CANTOR_THM_UNIV",CANTOR_THM_UNIV;
+"CARATHEODORY",CARATHEODORY;
+"CARATHEODORY_AFF_DIM",CARATHEODORY_AFF_DIM;
+"CARD",CARD;
+"CARD_ADD2_ABSORB_LE",CARD_ADD2_ABSORB_LE;
+"CARD_ADD2_ABSORB_LT",CARD_ADD2_ABSORB_LT;
+"CARD_ADD_ABSORB",CARD_ADD_ABSORB;
+"CARD_ADD_ABSORB_LE",CARD_ADD_ABSORB_LE;
+"CARD_ADD_ASSOC",CARD_ADD_ASSOC;
+"CARD_ADD_C",CARD_ADD_C;
+"CARD_ADD_CONG",CARD_ADD_CONG;
+"CARD_ADD_FINITE",CARD_ADD_FINITE;
+"CARD_ADD_FINITE_EQ",CARD_ADD_FINITE_EQ;
+"CARD_ADD_LE_MUL_INFINITE",CARD_ADD_LE_MUL_INFINITE;
+"CARD_ADD_SYM",CARD_ADD_SYM;
+"CARD_ADD_SYMDIFF_INTER",CARD_ADD_SYMDIFF_INTER;
+"CARD_BOOL",CARD_BOOL;
+"CARD_CART_UNIV",CARD_CART_UNIV;
+"CARD_CLAUSES",CARD_CLAUSES;
+"CARD_COUNTABLE_CONG",CARD_COUNTABLE_CONG;
+"CARD_CROSS",CARD_CROSS;
+"CARD_DELETE",CARD_DELETE;
+"CARD_DIFF",CARD_DIFF;
+"CARD_DIFF_INTER",CARD_DIFF_INTER;
+"CARD_DISJOINT_UNION",CARD_DISJOINT_UNION;
+"CARD_EQ_0",CARD_EQ_0;
+"CARD_EQ_ARC_IMAGE",CARD_EQ_ARC_IMAGE;
+"CARD_EQ_BALL",CARD_EQ_BALL;
+"CARD_EQ_BIJECTION",CARD_EQ_BIJECTION;
+"CARD_EQ_BIJECTIONS",CARD_EQ_BIJECTIONS;
+"CARD_EQ_CARD",CARD_EQ_CARD;
+"CARD_EQ_CARD_IMP",CARD_EQ_CARD_IMP;
+"CARD_EQ_CART",CARD_EQ_CART;
+"CARD_EQ_CBALL",CARD_EQ_CBALL;
+"CARD_EQ_CLOSED",CARD_EQ_CLOSED;
+"CARD_EQ_CLOSED_SETS",CARD_EQ_CLOSED_SETS;
+"CARD_EQ_COMPACT_SETS",CARD_EQ_COMPACT_SETS;
+"CARD_EQ_CONDENSATION_POINTS",CARD_EQ_CONDENSATION_POINTS;
+"CARD_EQ_CONDENSATION_POINTS_IN_SET",CARD_EQ_CONDENSATION_POINTS_IN_SET;
+"CARD_EQ_CONG",CARD_EQ_CONG;
+"CARD_EQ_CONNECTED",CARD_EQ_CONNECTED;
+"CARD_EQ_CONVEX",CARD_EQ_CONVEX;
+"CARD_EQ_COUNTABLE",CARD_EQ_COUNTABLE;
+"CARD_EQ_COUNTABLE_SUBSETS_REAL",CARD_EQ_COUNTABLE_SUBSETS_REAL;
+"CARD_EQ_COVERING_MAP_FIBRES",CARD_EQ_COVERING_MAP_FIBRES;
+"CARD_EQ_DIM",CARD_EQ_DIM;
+"CARD_EQ_EMPTY",CARD_EQ_EMPTY;
+"CARD_EQ_EUCLIDEAN",CARD_EQ_EUCLIDEAN;
+"CARD_EQ_FINITE",CARD_EQ_FINITE;
+"CARD_EQ_FINITE_SUBSETS",CARD_EQ_FINITE_SUBSETS;
+"CARD_EQ_IMAGE",CARD_EQ_IMAGE;
+"CARD_EQ_IMP_LE",CARD_EQ_IMP_LE;
+"CARD_EQ_INTEGER",CARD_EQ_INTEGER;
+"CARD_EQ_INTERVAL",CARD_EQ_INTERVAL;
+"CARD_EQ_LIST",CARD_EQ_LIST;
+"CARD_EQ_LIST_GEN",CARD_EQ_LIST_GEN;
+"CARD_EQ_NONEMPTY_INTERIOR",CARD_EQ_NONEMPTY_INTERIOR;
+"CARD_EQ_NSUM",CARD_EQ_NSUM;
+"CARD_EQ_OPEN",CARD_EQ_OPEN;
+"CARD_EQ_OPEN_IN",CARD_EQ_OPEN_IN;
+"CARD_EQ_OPEN_IN_AFFINE",CARD_EQ_OPEN_IN_AFFINE;
+"CARD_EQ_OPEN_SETS",CARD_EQ_OPEN_SETS;
+"CARD_EQ_PATH_CONNECTED",CARD_EQ_PATH_CONNECTED;
+"CARD_EQ_PCROSS",CARD_EQ_PCROSS;
+"CARD_EQ_RATIONAL",CARD_EQ_RATIONAL;
+"CARD_EQ_REAL",CARD_EQ_REAL;
+"CARD_EQ_REAL_IMP_UNCOUNTABLE",CARD_EQ_REAL_IMP_UNCOUNTABLE;
+"CARD_EQ_REAL_SEQUENCES",CARD_EQ_REAL_SEQUENCES;
+"CARD_EQ_REFL",CARD_EQ_REFL;
+"CARD_EQ_SEGMENT",CARD_EQ_SEGMENT;
+"CARD_EQ_SIMPLE_PATH_IMAGE",CARD_EQ_SIMPLE_PATH_IMAGE;
+"CARD_EQ_SPHERE",CARD_EQ_SPHERE;
+"CARD_EQ_SUM",CARD_EQ_SUM;
+"CARD_EQ_SYM",CARD_EQ_SYM;
+"CARD_EQ_TRANS",CARD_EQ_TRANS;
+"CARD_FACES_OF_SIMPLEX",CARD_FACES_OF_SIMPLEX;
+"CARD_FINITE_CONG",CARD_FINITE_CONG;
+"CARD_FINITE_IMAGE",CARD_FINITE_IMAGE;
+"CARD_FUNSPACE",CARD_FUNSPACE;
+"CARD_FUNSPACE_CONG",CARD_FUNSPACE_CONG;
+"CARD_FUNSPACE_CURRY",CARD_FUNSPACE_CURRY;
+"CARD_FUNSPACE_LE",CARD_FUNSPACE_LE;
+"CARD_FUNSPACE_UNIV",CARD_FUNSPACE_UNIV;
+"CARD_GE_DIM_INDEPENDENT",CARD_GE_DIM_INDEPENDENT;
+"CARD_HAS_SIZE_CONG",CARD_HAS_SIZE_CONG;
+"CARD_IMAGE_EQ_INJ",CARD_IMAGE_EQ_INJ;
+"CARD_IMAGE_INJ",CARD_IMAGE_INJ;
+"CARD_IMAGE_INJ_EQ",CARD_IMAGE_INJ_EQ;
+"CARD_IMAGE_LE",CARD_IMAGE_LE;
+"CARD_INFINITE_CONG",CARD_INFINITE_CONG;
+"CARD_INTSEG_INT",CARD_INTSEG_INT;
+"CARD_LDISTRIB",CARD_LDISTRIB;
+"CARD_LET_TOTAL",CARD_LET_TOTAL;
+"CARD_LET_TRANS",CARD_LET_TRANS;
+"CARD_LE_ADD",CARD_LE_ADD;
+"CARD_LE_ADDL",CARD_LE_ADDL;
+"CARD_LE_ADDR",CARD_LE_ADDR;
+"CARD_LE_ANTISYM",CARD_LE_ANTISYM;
+"CARD_LE_CARD",CARD_LE_CARD;
+"CARD_LE_CARD_IMP",CARD_LE_CARD_IMP;
+"CARD_LE_CONG",CARD_LE_CONG;
+"CARD_LE_COUNTABLE",CARD_LE_COUNTABLE;
+"CARD_LE_COUNTABLE_SUBSETS",CARD_LE_COUNTABLE_SUBSETS;
+"CARD_LE_DIM_SPANNING",CARD_LE_DIM_SPANNING;
+"CARD_LE_EMPTY",CARD_LE_EMPTY;
+"CARD_LE_EQ_SUBSET",CARD_LE_EQ_SUBSET;
+"CARD_LE_FINITE",CARD_LE_FINITE;
+"CARD_LE_FINITE_SUBSETS",CARD_LE_FINITE_SUBSETS;
+"CARD_LE_IMAGE",CARD_LE_IMAGE;
+"CARD_LE_IMAGE_GEN",CARD_LE_IMAGE_GEN;
+"CARD_LE_INFINITE",CARD_LE_INFINITE;
+"CARD_LE_INJ",CARD_LE_INJ;
+"CARD_LE_LIST",CARD_LE_LIST;
+"CARD_LE_LT",CARD_LE_LT;
+"CARD_LE_MUL",CARD_LE_MUL;
+"CARD_LE_POWERSET",CARD_LE_POWERSET;
+"CARD_LE_REFL",CARD_LE_REFL;
+"CARD_LE_RELATIONAL",CARD_LE_RELATIONAL;
+"CARD_LE_SQUARE",CARD_LE_SQUARE;
+"CARD_LE_SUBPOWERSET",CARD_LE_SUBPOWERSET;
+"CARD_LE_SUBSET",CARD_LE_SUBSET;
+"CARD_LE_TOTAL",CARD_LE_TOTAL;
+"CARD_LE_TRANS",CARD_LE_TRANS;
+"CARD_LE_UNIV",CARD_LE_UNIV;
+"CARD_LTE_TOTAL",CARD_LTE_TOTAL;
+"CARD_LTE_TRANS",CARD_LTE_TRANS;
+"CARD_LT_ADD",CARD_LT_ADD;
+"CARD_LT_CARD",CARD_LT_CARD;
+"CARD_LT_CONG",CARD_LT_CONG;
+"CARD_LT_FINITE_INFINITE",CARD_LT_FINITE_INFINITE;
+"CARD_LT_IMP_DISCONNECTED",CARD_LT_IMP_DISCONNECTED;
+"CARD_LT_IMP_LE",CARD_LT_IMP_LE;
+"CARD_LT_LE",CARD_LT_LE;
+"CARD_LT_REFL",CARD_LT_REFL;
+"CARD_LT_TOTAL",CARD_LT_TOTAL;
+"CARD_LT_TRANS",CARD_LT_TRANS;
+"CARD_MUL2_ABSORB_LE",CARD_MUL2_ABSORB_LE;
+"CARD_MUL_ABSORB",CARD_MUL_ABSORB;
+"CARD_MUL_ABSORB_LE",CARD_MUL_ABSORB_LE;
+"CARD_MUL_ASSOC",CARD_MUL_ASSOC;
+"CARD_MUL_CONG",CARD_MUL_CONG;
+"CARD_MUL_FINITE",CARD_MUL_FINITE;
+"CARD_MUL_LT_INFINITE",CARD_MUL_LT_INFINITE;
+"CARD_MUL_LT_LEMMA",CARD_MUL_LT_LEMMA;
+"CARD_MUL_SYM",CARD_MUL_SYM;
+"CARD_NOT_LE",CARD_NOT_LE;
+"CARD_NOT_LT",CARD_NOT_LT;
+"CARD_NUMSEG",CARD_NUMSEG;
+"CARD_NUMSEG_1",CARD_NUMSEG_1;
+"CARD_NUMSEG_LE",CARD_NUMSEG_LE;
+"CARD_NUMSEG_LEMMA",CARD_NUMSEG_LEMMA;
+"CARD_NUMSEG_LT",CARD_NUMSEG_LT;
+"CARD_PERMUTATIONS",CARD_PERMUTATIONS;
+"CARD_POWERSET",CARD_POWERSET;
+"CARD_PRODUCT",CARD_PRODUCT;
+"CARD_PSUBSET",CARD_PSUBSET;
+"CARD_RDISTRIB",CARD_RDISTRIB;
+"CARD_SET_OF_LIST_LE",CARD_SET_OF_LIST_LE;
+"CARD_SING",CARD_SING;
+"CARD_SQUARE_INFINITE",CARD_SQUARE_INFINITE;
+"CARD_SQUARE_NUM",CARD_SQUARE_NUM;
+"CARD_STDBASIS",CARD_STDBASIS;
+"CARD_SUBSET",CARD_SUBSET;
+"CARD_SUBSET_EQ",CARD_SUBSET_EQ;
+"CARD_SUBSET_IMAGE",CARD_SUBSET_IMAGE;
+"CARD_SUBSET_LE",CARD_SUBSET_LE;
+"CARD_UNION",CARD_UNION;
+"CARD_UNIONS",CARD_UNIONS;
+"CARD_UNIONS_LE",CARD_UNIONS_LE;
+"CARD_UNION_EQ",CARD_UNION_EQ;
+"CARD_UNION_GEN",CARD_UNION_GEN;
+"CARD_UNION_LE",CARD_UNION_LE;
+"CARD_UNION_LEMMA",CARD_UNION_LEMMA;
+"CARD_UNION_OVERLAP",CARD_UNION_OVERLAP;
+"CARD_UNION_OVERLAP_EQ",CARD_UNION_OVERLAP_EQ;
+"CART_EQ",CART_EQ;
+"CART_EQ_FULL",CART_EQ_FULL;
+"CASEWISE",CASEWISE;
+"CASEWISE_CASES",CASEWISE_CASES;
+"CASEWISE_DEF",CASEWISE_DEF;
+"CASEWISE_WORKS",CASEWISE_WORKS;
+"CAUCHY",CAUCHY;
+"CAUCHY_CONTINUOUS_EXTENDS_TO_CLOSURE",CAUCHY_CONTINUOUS_EXTENDS_TO_CLOSURE;
+"CAUCHY_CONTINUOUS_IMP_CONTINUOUS",CAUCHY_CONTINUOUS_IMP_CONTINUOUS;
+"CAUCHY_CONTINUOUS_UNIQUENESS_LEMMA",CAUCHY_CONTINUOUS_UNIQUENESS_LEMMA;
+"CAUCHY_IMP_BOUNDED",CAUCHY_IMP_BOUNDED;
+"CAUCHY_ISOMETRIC",CAUCHY_ISOMETRIC;
+"CBALL_DIFF_BALL",CBALL_DIFF_BALL;
+"CBALL_DIFF_SPHERE",CBALL_DIFF_SPHERE;
+"CBALL_EMPTY",CBALL_EMPTY;
+"CBALL_EQ_EMPTY",CBALL_EQ_EMPTY;
+"CBALL_EQ_SING",CBALL_EQ_SING;
+"CBALL_INTERVAL",CBALL_INTERVAL;
+"CBALL_INTERVAL_0",CBALL_INTERVAL_0;
+"CBALL_LINEAR_IMAGE",CBALL_LINEAR_IMAGE;
+"CBALL_SCALING",CBALL_SCALING;
+"CBALL_SING",CBALL_SING;
+"CBALL_TRANSLATION",CBALL_TRANSLATION;
+"CBALL_TRIVIAL",CBALL_TRIVIAL;
+"CELL_COMPLEX_SUBDIVISION_EXISTS",CELL_COMPLEX_SUBDIVISION_EXISTS;
+"CENTRE_IN_BALL",CENTRE_IN_BALL;
+"CENTRE_IN_CBALL",CENTRE_IN_CBALL;
+"CHAIN_SUBSET",CHAIN_SUBSET;
+"CHARACTERISTIC_POLYNOMIAL",CHARACTERISTIC_POLYNOMIAL;
+"CHOICE",CHOICE;
+"CHOICE_DEF",CHOICE_DEF;
+"CHOOSE_AFFINE_SUBSET",CHOOSE_AFFINE_SUBSET;
+"CHOOSE_POLYTOPE",CHOOSE_POLYTOPE;
+"CHOOSE_SIMPLEX",CHOOSE_SIMPLEX;
+"CHOOSE_SUBSET",CHOOSE_SUBSET;
+"CHOOSE_SUBSET_BETWEEN",CHOOSE_SUBSET_BETWEEN;
+"CHOOSE_SUBSET_STRONG",CHOOSE_SUBSET_STRONG;
+"CHOOSE_SUBSPACE_OF_SUBSPACE",CHOOSE_SUBSPACE_OF_SUBSPACE;
+"CLOPEN",CLOPEN;
+"CLOSED_AFFINE",CLOSED_AFFINE;
+"CLOSED_AFFINE_HULL",CLOSED_AFFINE_HULL;
+"CLOSED_APPROACHABLE",CLOSED_APPROACHABLE;
+"CLOSED_ARC_IMAGE",CLOSED_ARC_IMAGE;
+"CLOSED_AS_FRONTIER",CLOSED_AS_FRONTIER;
+"CLOSED_AS_FRONTIER_OF_SUBSET",CLOSED_AS_FRONTIER_OF_SUBSET;
+"CLOSED_BOUNDEDPREIM_CONTINUOUS_IMAGE",CLOSED_BOUNDEDPREIM_CONTINUOUS_IMAGE;
+"CLOSED_CBALL",CLOSED_CBALL;
+"CLOSED_CLOSED_IN_TRANS",CLOSED_CLOSED_IN_TRANS;
+"CLOSED_CLOSURE",CLOSED_CLOSURE;
+"CLOSED_COMPACT_DIFFERENCES",CLOSED_COMPACT_DIFFERENCES;
+"CLOSED_COMPACT_PROJECTION",CLOSED_COMPACT_PROJECTION;
+"CLOSED_COMPACT_SUMS",CLOSED_COMPACT_SUMS;
+"CLOSED_COMPONENTS",CLOSED_COMPONENTS;
+"CLOSED_CONDENSATION_POINTS",CLOSED_CONDENSATION_POINTS;
+"CLOSED_CONNECTED_COMPONENT",CLOSED_CONNECTED_COMPONENT;
+"CLOSED_CONTAINS_SEQUENTIAL_LIMIT",CLOSED_CONTAINS_SEQUENTIAL_LIMIT;
+"CLOSED_CONVEX_CONE_HULL",CLOSED_CONVEX_CONE_HULL;
+"CLOSED_DIFF",CLOSED_DIFF;
+"CLOSED_DIFF_OPEN_INTERVAL_1",CLOSED_DIFF_OPEN_INTERVAL_1;
+"CLOSED_EMPTY",CLOSED_EMPTY;
+"CLOSED_FIP",CLOSED_FIP;
+"CLOSED_FORALL",CLOSED_FORALL;
+"CLOSED_FORALL_IN",CLOSED_FORALL_IN;
+"CLOSED_HALFSPACE_COMPONENT_GE",CLOSED_HALFSPACE_COMPONENT_GE;
+"CLOSED_HALFSPACE_COMPONENT_LE",CLOSED_HALFSPACE_COMPONENT_LE;
+"CLOSED_HALFSPACE_GE",CLOSED_HALFSPACE_GE;
+"CLOSED_HALFSPACE_LE",CLOSED_HALFSPACE_LE;
+"CLOSED_HYPERPLANE",CLOSED_HYPERPLANE;
+"CLOSED_IMP_LOCALLY_COMPACT",CLOSED_IMP_LOCALLY_COMPACT;
+"CLOSED_IN",CLOSED_IN;
+"CLOSED_INJECTIVE_IMAGE_SUBSET_SUBSPACE",CLOSED_INJECTIVE_IMAGE_SUBSET_SUBSPACE;
+"CLOSED_INJECTIVE_IMAGE_SUBSPACE",CLOSED_INJECTIVE_IMAGE_SUBSPACE;
+"CLOSED_INJECTIVE_LINEAR_IMAGE",CLOSED_INJECTIVE_LINEAR_IMAGE;
+"CLOSED_INJECTIVE_LINEAR_IMAGE_EQ",CLOSED_INJECTIVE_LINEAR_IMAGE_EQ;
+"CLOSED_INSERT",CLOSED_INSERT;
+"CLOSED_INTER",CLOSED_INTER;
+"CLOSED_INTERS",CLOSED_INTERS;
+"CLOSED_INTERS_COMPACT",CLOSED_INTERS_COMPACT;
+"CLOSED_INTERVAL",CLOSED_INTERVAL;
+"CLOSED_INTERVAL_AS_CONVEX_HULL",CLOSED_INTERVAL_AS_CONVEX_HULL;
+"CLOSED_INTERVAL_EQ",CLOSED_INTERVAL_EQ;
+"CLOSED_INTERVAL_IMAGE_UNIT_INTERVAL",CLOSED_INTERVAL_IMAGE_UNIT_INTERVAL;
+"CLOSED_INTERVAL_LEFT",CLOSED_INTERVAL_LEFT;
+"CLOSED_INTERVAL_RIGHT",CLOSED_INTERVAL_RIGHT;
+"CLOSED_INTER_COMPACT",CLOSED_INTER_COMPACT;
+"CLOSED_IN_CLOSED",CLOSED_IN_CLOSED;
+"CLOSED_IN_CLOSED_EQ",CLOSED_IN_CLOSED_EQ;
+"CLOSED_IN_CLOSED_INTER",CLOSED_IN_CLOSED_INTER;
+"CLOSED_IN_CLOSED_TRANS",CLOSED_IN_CLOSED_TRANS;
+"CLOSED_IN_COMPACT",CLOSED_IN_COMPACT;
+"CLOSED_IN_COMPACT_PROJECTION",CLOSED_IN_COMPACT_PROJECTION;
+"CLOSED_IN_CONNECTED_COMPONENT",CLOSED_IN_CONNECTED_COMPONENT;
+"CLOSED_IN_DIFF",CLOSED_IN_DIFF;
+"CLOSED_IN_EMPTY",CLOSED_IN_EMPTY;
+"CLOSED_IN_IMP_SUBSET",CLOSED_IN_IMP_SUBSET;
+"CLOSED_IN_INJECTIVE_LINEAR_IMAGE",CLOSED_IN_INJECTIVE_LINEAR_IMAGE;
+"CLOSED_IN_INTER",CLOSED_IN_INTER;
+"CLOSED_IN_INTERS",CLOSED_IN_INTERS;
+"CLOSED_IN_INTER_CLOSED",CLOSED_IN_INTER_CLOSED;
+"CLOSED_IN_LIMPT",CLOSED_IN_LIMPT;
+"CLOSED_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED",CLOSED_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED;
+"CLOSED_IN_REFL",CLOSED_IN_REFL;
+"CLOSED_IN_RETRACT",CLOSED_IN_RETRACT;
+"CLOSED_IN_SING",CLOSED_IN_SING;
+"CLOSED_IN_SUBSET",CLOSED_IN_SUBSET;
+"CLOSED_IN_SUBSET_TRANS",CLOSED_IN_SUBSET_TRANS;
+"CLOSED_IN_SUBTOPOLOGY",CLOSED_IN_SUBTOPOLOGY;
+"CLOSED_IN_SUBTOPOLOGY_EMPTY",CLOSED_IN_SUBTOPOLOGY_EMPTY;
+"CLOSED_IN_SUBTOPOLOGY_REFL",CLOSED_IN_SUBTOPOLOGY_REFL;
+"CLOSED_IN_SUBTOPOLOGY_UNION",CLOSED_IN_SUBTOPOLOGY_UNION;
+"CLOSED_IN_TOPSPACE",CLOSED_IN_TOPSPACE;
+"CLOSED_IN_TRANS",CLOSED_IN_TRANS;
+"CLOSED_IN_TRANSLATION_EQ",CLOSED_IN_TRANSLATION_EQ;
+"CLOSED_IN_UNION",CLOSED_IN_UNION;
+"CLOSED_IN_UNIONS",CLOSED_IN_UNIONS;
+"CLOSED_IN_UNION_COMPLEMENT_COMPONENT",CLOSED_IN_UNION_COMPLEMENT_COMPONENT;
+"CLOSED_LIFT",CLOSED_LIFT;
+"CLOSED_LIMPT",CLOSED_LIMPT;
+"CLOSED_LIMPTS",CLOSED_LIMPTS;
+"CLOSED_MAP_FROM_COMPOSITION_INJECTIVE",CLOSED_MAP_FROM_COMPOSITION_INJECTIVE;
+"CLOSED_MAP_FROM_COMPOSITION_SURJECTIVE",CLOSED_MAP_FROM_COMPOSITION_SURJECTIVE;
+"CLOSED_MAP_IMP_OPEN_MAP",CLOSED_MAP_IMP_OPEN_MAP;
+"CLOSED_MAP_IMP_QUOTIENT_MAP",CLOSED_MAP_IMP_QUOTIENT_MAP;
+"CLOSED_NEGATIONS",CLOSED_NEGATIONS;
+"CLOSED_OPEN_INTERVAL_1",CLOSED_OPEN_INTERVAL_1;
+"CLOSED_PATH_IMAGE",CLOSED_PATH_IMAGE;
+"CLOSED_PCROSS",CLOSED_PCROSS;
+"CLOSED_PCROSS_EQ",CLOSED_PCROSS_EQ;
+"CLOSED_POSITIVE_ORTHANT",CLOSED_POSITIVE_ORTHANT;
+"CLOSED_RELATIVE_BOUNDARY",CLOSED_RELATIVE_BOUNDARY;
+"CLOSED_RELATIVE_FRONTIER",CLOSED_RELATIVE_FRONTIER;
+"CLOSED_SCALING",CLOSED_SCALING;
+"CLOSED_SEGMENT",CLOSED_SEGMENT;
+"CLOSED_SEGMENT_LINEAR_IMAGE",CLOSED_SEGMENT_LINEAR_IMAGE;
+"CLOSED_SEQUENTIAL_LIMITS",CLOSED_SEQUENTIAL_LIMITS;
+"CLOSED_SHIFTPATH",CLOSED_SHIFTPATH;
+"CLOSED_SIMPLE_PATH_IMAGE",CLOSED_SIMPLE_PATH_IMAGE;
+"CLOSED_SING",CLOSED_SING;
+"CLOSED_SPAN",CLOSED_SPAN;
+"CLOSED_SPHERE",CLOSED_SPHERE;
+"CLOSED_STANDARD_HYPERPLANE",CLOSED_STANDARD_HYPERPLANE;
+"CLOSED_SUBSET",CLOSED_SUBSET;
+"CLOSED_SUBSET_EQ",CLOSED_SUBSET_EQ;
+"CLOSED_SUBSPACE",CLOSED_SUBSPACE;
+"CLOSED_SUBSTANDARD",CLOSED_SUBSTANDARD;
+"CLOSED_TRANSLATION",CLOSED_TRANSLATION;
+"CLOSED_TRANSLATION_EQ",CLOSED_TRANSLATION_EQ;
+"CLOSED_UNION",CLOSED_UNION;
+"CLOSED_UNIONS",CLOSED_UNIONS;
+"CLOSED_UNION_COMPACT_SUBSETS",CLOSED_UNION_COMPACT_SUBSETS;
+"CLOSED_UNION_COMPLEMENT_COMPONENT",CLOSED_UNION_COMPLEMENT_COMPONENT;
+"CLOSED_UNIV",CLOSED_UNIV;
+"CLOSER_POINTS_LEMMA",CLOSER_POINTS_LEMMA;
+"CLOSER_POINT_LEMMA",CLOSER_POINT_LEMMA;
+"CLOSEST_POINT_AFFINE_ORTHOGONAL",CLOSEST_POINT_AFFINE_ORTHOGONAL;
+"CLOSEST_POINT_AFFINE_ORTHOGONAL_EQ",CLOSEST_POINT_AFFINE_ORTHOGONAL_EQ;
+"CLOSEST_POINT_DOT",CLOSEST_POINT_DOT;
+"CLOSEST_POINT_EXISTS",CLOSEST_POINT_EXISTS;
+"CLOSEST_POINT_IN_FRONTIER",CLOSEST_POINT_IN_FRONTIER;
+"CLOSEST_POINT_IN_INTERIOR",CLOSEST_POINT_IN_INTERIOR;
+"CLOSEST_POINT_IN_RELATIVE_FRONTIER",CLOSEST_POINT_IN_RELATIVE_FRONTIER;
+"CLOSEST_POINT_IN_RELATIVE_INTERIOR",CLOSEST_POINT_IN_RELATIVE_INTERIOR;
+"CLOSEST_POINT_IN_SET",CLOSEST_POINT_IN_SET;
+"CLOSEST_POINT_LE",CLOSEST_POINT_LE;
+"CLOSEST_POINT_LIPSCHITZ",CLOSEST_POINT_LIPSCHITZ;
+"CLOSEST_POINT_LT",CLOSEST_POINT_LT;
+"CLOSEST_POINT_REFL",CLOSEST_POINT_REFL;
+"CLOSEST_POINT_SELF",CLOSEST_POINT_SELF;
+"CLOSEST_POINT_UNIQUE",CLOSEST_POINT_UNIQUE;
+"CLOSURE_APPROACHABLE",CLOSURE_APPROACHABLE;
+"CLOSURE_BALL",CLOSURE_BALL;
+"CLOSURE_BOUNDED_LINEAR_IMAGE",CLOSURE_BOUNDED_LINEAR_IMAGE;
+"CLOSURE_CLOSED",CLOSURE_CLOSED;
+"CLOSURE_CLOSURE",CLOSURE_CLOSURE;
+"CLOSURE_COCOUNTABLE_COORDINATES",CLOSURE_COCOUNTABLE_COORDINATES;
+"CLOSURE_COMPLEMENT",CLOSURE_COMPLEMENT;
+"CLOSURE_CONVEX_HULL",CLOSURE_CONVEX_HULL;
+"CLOSURE_CONVEX_INTER_AFFINE",CLOSURE_CONVEX_INTER_AFFINE;
+"CLOSURE_CONVEX_INTER_SUPERSET",CLOSURE_CONVEX_INTER_SUPERSET;
+"CLOSURE_COSMALL_COORDINATES",CLOSURE_COSMALL_COORDINATES;
+"CLOSURE_DYADIC_RATIONALS",CLOSURE_DYADIC_RATIONALS;
+"CLOSURE_DYADIC_RATIONALS_IN_CONVEX_SET",CLOSURE_DYADIC_RATIONALS_IN_CONVEX_SET;
+"CLOSURE_DYADIC_RATIONALS_IN_OPEN_SET",CLOSURE_DYADIC_RATIONALS_IN_OPEN_SET;
+"CLOSURE_EMPTY",CLOSURE_EMPTY;
+"CLOSURE_EQ",CLOSURE_EQ;
+"CLOSURE_EQ_EMPTY",CLOSURE_EQ_EMPTY;
+"CLOSURE_HALFSPACE_COMPONENT_GT",CLOSURE_HALFSPACE_COMPONENT_GT;
+"CLOSURE_HALFSPACE_COMPONENT_LT",CLOSURE_HALFSPACE_COMPONENT_LT;
+"CLOSURE_HALFSPACE_GT",CLOSURE_HALFSPACE_GT;
+"CLOSURE_HALFSPACE_LT",CLOSURE_HALFSPACE_LT;
+"CLOSURE_HULL",CLOSURE_HULL;
+"CLOSURE_IMAGE_CLOSURE",CLOSURE_IMAGE_CLOSURE;
+"CLOSURE_INJECTIVE_LINEAR_IMAGE",CLOSURE_INJECTIVE_LINEAR_IMAGE;
+"CLOSURE_INSIDE_SUBSET",CLOSURE_INSIDE_SUBSET;
+"CLOSURE_INTERIOR",CLOSURE_INTERIOR;
+"CLOSURE_INTERIOR_IDEMP",CLOSURE_INTERIOR_IDEMP;
+"CLOSURE_INTERS_CONVEX",CLOSURE_INTERS_CONVEX;
+"CLOSURE_INTERS_CONVEX_OPEN",CLOSURE_INTERS_CONVEX_OPEN;
+"CLOSURE_INTERS_SUBSET",CLOSURE_INTERS_SUBSET;
+"CLOSURE_INTERVAL",CLOSURE_INTERVAL;
+"CLOSURE_INTER_CONVEX",CLOSURE_INTER_CONVEX;
+"CLOSURE_INTER_CONVEX_OPEN",CLOSURE_INTER_CONVEX_OPEN;
+"CLOSURE_INTER_SUBSET",CLOSURE_INTER_SUBSET;
+"CLOSURE_IRRATIONAL_COORDINATES",CLOSURE_IRRATIONAL_COORDINATES;
+"CLOSURE_LINEAR_IMAGE_SUBSET",CLOSURE_LINEAR_IMAGE_SUBSET;
+"CLOSURE_MINIMAL",CLOSURE_MINIMAL;
+"CLOSURE_MINIMAL_EQ",CLOSURE_MINIMAL_EQ;
+"CLOSURE_NEGATIONS",CLOSURE_NEGATIONS;
+"CLOSURE_OPEN_INTERVAL",CLOSURE_OPEN_INTERVAL;
+"CLOSURE_OPEN_INTER_SUPERSET",CLOSURE_OPEN_INTER_SUPERSET;
+"CLOSURE_OUTSIDE_SUBSET",CLOSURE_OUTSIDE_SUBSET;
+"CLOSURE_PCROSS",CLOSURE_PCROSS;
+"CLOSURE_RATIONALS_IN_CONVEX_SET",CLOSURE_RATIONALS_IN_CONVEX_SET;
+"CLOSURE_RATIONALS_IN_OPEN_SET",CLOSURE_RATIONALS_IN_OPEN_SET;
+"CLOSURE_RATIONAL_COORDINATES",CLOSURE_RATIONAL_COORDINATES;
+"CLOSURE_SEGMENT",CLOSURE_SEGMENT;
+"CLOSURE_SEQUENTIAL",CLOSURE_SEQUENTIAL;
+"CLOSURE_SING",CLOSURE_SING;
+"CLOSURE_SUBSET",CLOSURE_SUBSET;
+"CLOSURE_SUBSET_AFFINE_HULL",CLOSURE_SUBSET_AFFINE_HULL;
+"CLOSURE_SUBSET_EQ",CLOSURE_SUBSET_EQ;
+"CLOSURE_SURJECTIVE_LINEAR_IMAGE",CLOSURE_SURJECTIVE_LINEAR_IMAGE;
+"CLOSURE_TRANSLATION",CLOSURE_TRANSLATION;
+"CLOSURE_UNION",CLOSURE_UNION;
+"CLOSURE_UNIONS",CLOSURE_UNIONS;
+"CLOSURE_UNION_FRONTIER",CLOSURE_UNION_FRONTIER;
+"CLOSURE_UNIQUE",CLOSURE_UNIQUE;
+"CLOSURE_UNIV",CLOSURE_UNIV;
+"COBOUNDED_HAS_BOUNDED_COMPONENT",COBOUNDED_HAS_BOUNDED_COMPONENT;
+"COBOUNDED_IMP_UNBOUNDED",COBOUNDED_IMP_UNBOUNDED;
+"COBOUNDED_INTER_UNBOUNDED",COBOUNDED_INTER_UNBOUNDED;
+"COBOUNDED_OUTSIDE",COBOUNDED_OUTSIDE;
+"COBOUNDED_UNBOUNDED_COMPONENT",COBOUNDED_UNBOUNDED_COMPONENT;
+"COBOUNDED_UNBOUNDED_COMPONENTS",COBOUNDED_UNBOUNDED_COMPONENTS;
+"COBOUNDED_UNIQUE_UNBOUNDED_COMPONENT",COBOUNDED_UNIQUE_UNBOUNDED_COMPONENT;
+"COBOUNDED_UNIQUE_UNBOUNDED_COMPONENTS",COBOUNDED_UNIQUE_UNBOUNDED_COMPONENTS;
+"COCOUNTABLE_APPROXIMATION",COCOUNTABLE_APPROXIMATION;
+"CODESET_SETCODE_BIJECTIONS",CODESET_SETCODE_BIJECTIONS;
+"COFACTOR_0",COFACTOR_0;
+"COFACTOR_CMUL",COFACTOR_CMUL;
+"COFACTOR_COFACTOR",COFACTOR_COFACTOR;
+"COFACTOR_COLUMN",COFACTOR_COLUMN;
+"COFACTOR_I",COFACTOR_I;
+"COFACTOR_MATRIX_INV",COFACTOR_MATRIX_INV;
+"COFACTOR_MATRIX_MUL",COFACTOR_MATRIX_MUL;
+"COFACTOR_ROW",COFACTOR_ROW;
+"COFACTOR_TRANSP",COFACTOR_TRANSP;
+"COHOMOTOPICALLY_TRIVIAL_RETRACTION_GEN",COHOMOTOPICALLY_TRIVIAL_RETRACTION_GEN;
+"COHOMOTOPICALLY_TRIVIAL_RETRACTION_NULL_GEN",COHOMOTOPICALLY_TRIVIAL_RETRACTION_NULL_GEN;
+"COLLINEAR_1",COLLINEAR_1;
+"COLLINEAR_2",COLLINEAR_2;
+"COLLINEAR_3",COLLINEAR_3;
+"COLLINEAR_3_2D",COLLINEAR_3_2D;
+"COLLINEAR_3_AFFINE_HULL",COLLINEAR_3_AFFINE_HULL;
+"COLLINEAR_3_DOT_MULTIPLES",COLLINEAR_3_DOT_MULTIPLES;
+"COLLINEAR_3_EQ_AFFINE_DEPENDENT",COLLINEAR_3_EQ_AFFINE_DEPENDENT;
+"COLLINEAR_3_EXPAND",COLLINEAR_3_EXPAND;
+"COLLINEAR_3_IN_AFFINE_HULL",COLLINEAR_3_IN_AFFINE_HULL;
+"COLLINEAR_3_TRANS",COLLINEAR_3_TRANS;
+"COLLINEAR_4_3",COLLINEAR_4_3;
+"COLLINEAR_AFFINE_HULL",COLLINEAR_AFFINE_HULL;
+"COLLINEAR_AFFINE_HULL_COLLINEAR",COLLINEAR_AFFINE_HULL_COLLINEAR;
+"COLLINEAR_AFF_DIM",COLLINEAR_AFF_DIM;
+"COLLINEAR_BETWEEN_CASES",COLLINEAR_BETWEEN_CASES;
+"COLLINEAR_CONVEX_HULL_COLLINEAR",COLLINEAR_CONVEX_HULL_COLLINEAR;
+"COLLINEAR_DIST_BETWEEN",COLLINEAR_DIST_BETWEEN;
+"COLLINEAR_DIST_IN_CLOSED_SEGMENT",COLLINEAR_DIST_IN_CLOSED_SEGMENT;
+"COLLINEAR_DIST_IN_OPEN_SEGMENT",COLLINEAR_DIST_IN_OPEN_SEGMENT;
+"COLLINEAR_EMPTY",COLLINEAR_EMPTY;
+"COLLINEAR_EXTREME_POINTS",COLLINEAR_EXTREME_POINTS;
+"COLLINEAR_IMP_COPLANAR",COLLINEAR_IMP_COPLANAR;
+"COLLINEAR_LEMMA",COLLINEAR_LEMMA;
+"COLLINEAR_LEMMA_ALT",COLLINEAR_LEMMA_ALT;
+"COLLINEAR_LINEAR_IMAGE",COLLINEAR_LINEAR_IMAGE;
+"COLLINEAR_LINEAR_IMAGE_EQ",COLLINEAR_LINEAR_IMAGE_EQ;
+"COLLINEAR_MIDPOINT",COLLINEAR_MIDPOINT;
+"COLLINEAR_SEGMENT",COLLINEAR_SEGMENT;
+"COLLINEAR_SING",COLLINEAR_SING;
+"COLLINEAR_SMALL",COLLINEAR_SMALL;
+"COLLINEAR_SUBSET",COLLINEAR_SUBSET;
+"COLLINEAR_TRANSLATION",COLLINEAR_TRANSLATION;
+"COLLINEAR_TRANSLATION_EQ",COLLINEAR_TRANSLATION_EQ;
+"COLLINEAR_TRIPLES",COLLINEAR_TRIPLES;
+"COLUMNS_IMAGE_BASIS",COLUMNS_IMAGE_BASIS;
+"COLUMNS_TRANSP",COLUMNS_TRANSP;
+"COLUMN_TRANSP",COLUMN_TRANSP;
+"COMMA_DEF",COMMA_DEF;
+"COMPACT_AFFINITY",COMPACT_AFFINITY;
+"COMPACT_ARC_IMAGE",COMPACT_ARC_IMAGE;
+"COMPACT_ATTAINS_INF",COMPACT_ATTAINS_INF;
+"COMPACT_ATTAINS_SUP",COMPACT_ATTAINS_SUP;
+"COMPACT_CBALL",COMPACT_CBALL;
+"COMPACT_CHAIN",COMPACT_CHAIN;
+"COMPACT_CLOSED_DIFFERENCES",COMPACT_CLOSED_DIFFERENCES;
+"COMPACT_CLOSED_SUMS",COMPACT_CLOSED_SUMS;
+"COMPACT_CLOSURE",COMPACT_CLOSURE;
+"COMPACT_CONTINUOUS_IMAGE",COMPACT_CONTINUOUS_IMAGE;
+"COMPACT_CONTINUOUS_IMAGE_EQ",COMPACT_CONTINUOUS_IMAGE_EQ;
+"COMPACT_CONVEX_COLLINEAR_SEGMENT",COMPACT_CONVEX_COLLINEAR_SEGMENT;
+"COMPACT_CONVEX_COMBINATIONS",COMPACT_CONVEX_COMBINATIONS;
+"COMPACT_CONVEX_HULL",COMPACT_CONVEX_HULL;
+"COMPACT_DIFF",COMPACT_DIFF;
+"COMPACT_DIFFERENCES",COMPACT_DIFFERENCES;
+"COMPACT_EMPTY",COMPACT_EMPTY;
+"COMPACT_EQ_BOLZANO_WEIERSTRASS",COMPACT_EQ_BOLZANO_WEIERSTRASS;
+"COMPACT_EQ_BOUNDED_CLOSED",COMPACT_EQ_BOUNDED_CLOSED;
+"COMPACT_EQ_HEINE_BOREL",COMPACT_EQ_HEINE_BOREL;
+"COMPACT_EQ_HEINE_BOREL_SUBTOPOLOGY",COMPACT_EQ_HEINE_BOREL_SUBTOPOLOGY;
+"COMPACT_FIP",COMPACT_FIP;
+"COMPACT_FRONTIER",COMPACT_FRONTIER;
+"COMPACT_FRONTIER_BOUNDED",COMPACT_FRONTIER_BOUNDED;
+"COMPACT_FRONTIER_LINE_LEMMA",COMPACT_FRONTIER_LINE_LEMMA;
+"COMPACT_IMP_BOUNDED",COMPACT_IMP_BOUNDED;
+"COMPACT_IMP_CLOSED",COMPACT_IMP_CLOSED;
+"COMPACT_IMP_COMPLETE",COMPACT_IMP_COMPLETE;
+"COMPACT_IMP_FIP",COMPACT_IMP_FIP;
+"COMPACT_IMP_HEINE_BOREL",COMPACT_IMP_HEINE_BOREL;
+"COMPACT_IMP_TOTALLY_BOUNDED",COMPACT_IMP_TOTALLY_BOUNDED;
+"COMPACT_INSERT",COMPACT_INSERT;
+"COMPACT_INTER",COMPACT_INTER;
+"COMPACT_INTERS",COMPACT_INTERS;
+"COMPACT_INTERVAL",COMPACT_INTERVAL;
+"COMPACT_INTERVAL_EQ",COMPACT_INTERVAL_EQ;
+"COMPACT_INTER_CLOSED",COMPACT_INTER_CLOSED;
+"COMPACT_LEMMA",COMPACT_LEMMA;
+"COMPACT_LINEAR_IMAGE",COMPACT_LINEAR_IMAGE;
+"COMPACT_LINEAR_IMAGE_EQ",COMPACT_LINEAR_IMAGE_EQ;
+"COMPACT_NEGATIONS",COMPACT_NEGATIONS;
+"COMPACT_NEST",COMPACT_NEST;
+"COMPACT_OPEN",COMPACT_OPEN;
+"COMPACT_PATH_IMAGE",COMPACT_PATH_IMAGE;
+"COMPACT_PCROSS",COMPACT_PCROSS;
+"COMPACT_PCROSS_EQ",COMPACT_PCROSS_EQ;
+"COMPACT_REAL_LEMMA",COMPACT_REAL_LEMMA;
+"COMPACT_RELATIVE_BOUNDARY",COMPACT_RELATIVE_BOUNDARY;
+"COMPACT_RELATIVE_FRONTIER",COMPACT_RELATIVE_FRONTIER;
+"COMPACT_RELATIVE_FRONTIER_BOUNDED",COMPACT_RELATIVE_FRONTIER_BOUNDED;
+"COMPACT_SCALING",COMPACT_SCALING;
+"COMPACT_SEGMENT",COMPACT_SEGMENT;
+"COMPACT_SEQUENCE_WITH_LIMIT",COMPACT_SEQUENCE_WITH_LIMIT;
+"COMPACT_SIMPLEX",COMPACT_SIMPLEX;
+"COMPACT_SIMPLE_PATH_IMAGE",COMPACT_SIMPLE_PATH_IMAGE;
+"COMPACT_SING",COMPACT_SING;
+"COMPACT_SPHERE",COMPACT_SPHERE;
+"COMPACT_SUBSET_FRONTIER_RETRACTION",COMPACT_SUBSET_FRONTIER_RETRACTION;
+"COMPACT_SUMS",COMPACT_SUMS;
+"COMPACT_SUP_MAXDISTANCE",COMPACT_SUP_MAXDISTANCE;
+"COMPACT_TRANSLATION",COMPACT_TRANSLATION;
+"COMPACT_TRANSLATION_EQ",COMPACT_TRANSLATION_EQ;
+"COMPACT_UNIFORMLY_CONTINUOUS",COMPACT_UNIFORMLY_CONTINUOUS;
+"COMPACT_UNIFORMLY_EQUICONTINUOUS",COMPACT_UNIFORMLY_EQUICONTINUOUS;
+"COMPACT_UNION",COMPACT_UNION;
+"COMPACT_UNIONS",COMPACT_UNIONS;
+"COMPLETE_EQ_CLOSED",COMPLETE_EQ_CLOSED;
+"COMPLETE_FACE_TOP",COMPLETE_FACE_TOP;
+"COMPLETE_INJECTIVE_LINEAR_IMAGE",COMPLETE_INJECTIVE_LINEAR_IMAGE;
+"COMPLETE_INJECTIVE_LINEAR_IMAGE_EQ",COMPLETE_INJECTIVE_LINEAR_IMAGE_EQ;
+"COMPLETE_ISOMETRIC_IMAGE",COMPLETE_ISOMETRIC_IMAGE;
+"COMPLETE_SUBSPACE",COMPLETE_SUBSPACE;
+"COMPLETE_TRANSLATION_EQ",COMPLETE_TRANSLATION_EQ;
+"COMPLETE_UNIV",COMPLETE_UNIV;
+"COMPONENT",COMPONENT;
+"COMPONENTS_EQ",COMPONENTS_EQ;
+"COMPONENTS_EQ_EMPTY",COMPONENTS_EQ_EMPTY;
+"COMPONENTS_EQ_SING",COMPONENTS_EQ_SING;
+"COMPONENTS_EQ_SING_EXISTS",COMPONENTS_EQ_SING_EXISTS;
+"COMPONENTS_LINEAR_IMAGE",COMPONENTS_LINEAR_IMAGE;
+"COMPONENTS_MAXIMAL",COMPONENTS_MAXIMAL;
+"COMPONENTS_NONOVERLAP",COMPONENTS_NONOVERLAP;
+"COMPONENTS_OPEN_UNIQUE",COMPONENTS_OPEN_UNIQUE;
+"COMPONENTS_TRANSLATION",COMPONENTS_TRANSLATION;
+"COMPONENTS_UNIQUE",COMPONENTS_UNIQUE;
+"COMPONENTS_UNIQUE_EQ",COMPONENTS_UNIQUE_EQ;
+"COMPONENT_COMPLEMENT_CONNECTED",COMPONENT_COMPLEMENT_CONNECTED;
+"COMPONENT_LE_INFNORM",COMPONENT_LE_INFNORM;
+"COMPONENT_LE_NORM",COMPONENT_LE_NORM;
+"CONDENSATION_POINTS_EQ_EMPTY",CONDENSATION_POINTS_EQ_EMPTY;
+"CONDENSATION_POINT_IMP_LIMPT",CONDENSATION_POINT_IMP_LIMPT;
+"CONDENSATION_POINT_INFINITE_BALL",CONDENSATION_POINT_INFINITE_BALL;
+"CONDENSATION_POINT_INFINITE_CBALL",CONDENSATION_POINT_INFINITE_CBALL;
+"COND_ABS",COND_ABS;
+"COND_CLAUSES",COND_CLAUSES;
+"COND_COMPONENT",COND_COMPONENT;
+"COND_DEF",COND_DEF;
+"COND_ELIM_THM",COND_ELIM_THM;
+"COND_EXPAND",COND_EXPAND;
+"COND_ID",COND_ID;
+"COND_RAND",COND_RAND;
+"COND_RATOR",COND_RATOR;
+"CONGRUENT_IMAGE_STD_SIMPLEX",CONGRUENT_IMAGE_STD_SIMPLEX;
+"CONIC_CONIC_HULL",CONIC_CONIC_HULL;
+"CONIC_CONTAINS_0",CONIC_CONTAINS_0;
+"CONIC_CONVEX_CONE_HULL",CONIC_CONVEX_CONE_HULL;
+"CONIC_EMPTY",CONIC_EMPTY;
+"CONIC_HALFSPACE_GE",CONIC_HALFSPACE_GE;
+"CONIC_HALFSPACE_LE",CONIC_HALFSPACE_LE;
+"CONIC_HULL_EMPTY",CONIC_HULL_EMPTY;
+"CONIC_HULL_EQ",CONIC_HULL_EQ;
+"CONIC_HULL_EQ_EMPTY",CONIC_HULL_EQ_EMPTY;
+"CONIC_HULL_EXPLICIT",CONIC_HULL_EXPLICIT;
+"CONIC_HULL_LINEAR_IMAGE",CONIC_HULL_LINEAR_IMAGE;
+"CONIC_HULL_SUBSET_CONVEX_CONE_HULL",CONIC_HULL_SUBSET_CONVEX_CONE_HULL;
+"CONIC_INTERS",CONIC_INTERS;
+"CONIC_LINEAR_IMAGE",CONIC_LINEAR_IMAGE;
+"CONIC_LINEAR_IMAGE_EQ",CONIC_LINEAR_IMAGE_EQ;
+"CONIC_NEGATIONS",CONIC_NEGATIONS;
+"CONIC_PCROSS",CONIC_PCROSS;
+"CONIC_PCROSS_EQ",CONIC_PCROSS_EQ;
+"CONIC_POSITIVE_ORTHANT",CONIC_POSITIVE_ORTHANT;
+"CONIC_SPAN",CONIC_SPAN;
+"CONIC_SUMS",CONIC_SUMS;
+"CONIC_UNIV",CONIC_UNIV;
+"CONJ_ACI",CONJ_ACI;
+"CONJ_ASSOC",CONJ_ASSOC;
+"CONJ_SYM",CONJ_SYM;
+"CONNECTED_ANNULUS",CONNECTED_ANNULUS;
+"CONNECTED_ARC_COMPLEMENT",CONNECTED_ARC_COMPLEMENT;
+"CONNECTED_ARC_IMAGE",CONNECTED_ARC_IMAGE;
+"CONNECTED_BALL",CONNECTED_BALL;
+"CONNECTED_CARD_EQ_IFF_NONTRIVIAL",CONNECTED_CARD_EQ_IFF_NONTRIVIAL;
+"CONNECTED_CBALL",CONNECTED_CBALL;
+"CONNECTED_CHAIN",CONNECTED_CHAIN;
+"CONNECTED_CHAIN_GEN",CONNECTED_CHAIN_GEN;
+"CONNECTED_CLOPEN",CONNECTED_CLOPEN;
+"CONNECTED_CLOSED",CONNECTED_CLOSED;
+"CONNECTED_CLOSED_IN",CONNECTED_CLOSED_IN;
+"CONNECTED_CLOSED_IN_EQ",CONNECTED_CLOSED_IN_EQ;
+"CONNECTED_CLOSED_SET",CONNECTED_CLOSED_SET;
+"CONNECTED_CLOSURE",CONNECTED_CLOSURE;
+"CONNECTED_COMPACT_INTERVAL_1",CONNECTED_COMPACT_INTERVAL_1;
+"CONNECTED_COMPLEMENT_ABSOLUTE_RETRACT",CONNECTED_COMPLEMENT_ABSOLUTE_RETRACT;
+"CONNECTED_COMPLEMENT_BOUNDED_CONVEX",CONNECTED_COMPLEMENT_BOUNDED_CONVEX;
+"CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT",CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT;
+"CONNECTED_COMPONENT_1",CONNECTED_COMPONENT_1;
+"CONNECTED_COMPONENT_1_GEN",CONNECTED_COMPONENT_1_GEN;
+"CONNECTED_COMPONENT_DISJOINT",CONNECTED_COMPONENT_DISJOINT;
+"CONNECTED_COMPONENT_EMPTY",CONNECTED_COMPONENT_EMPTY;
+"CONNECTED_COMPONENT_EQ",CONNECTED_COMPONENT_EQ;
+"CONNECTED_COMPONENT_EQUIVALENCE_RELATION",CONNECTED_COMPONENT_EQUIVALENCE_RELATION;
+"CONNECTED_COMPONENT_EQ_EMPTY",CONNECTED_COMPONENT_EQ_EMPTY;
+"CONNECTED_COMPONENT_EQ_EQ",CONNECTED_COMPONENT_EQ_EQ;
+"CONNECTED_COMPONENT_EQ_SELF",CONNECTED_COMPONENT_EQ_SELF;
+"CONNECTED_COMPONENT_EQ_UNIV",CONNECTED_COMPONENT_EQ_UNIV;
+"CONNECTED_COMPONENT_IDEMP",CONNECTED_COMPONENT_IDEMP;
+"CONNECTED_COMPONENT_IN",CONNECTED_COMPONENT_IN;
+"CONNECTED_COMPONENT_LINEAR_IMAGE",CONNECTED_COMPONENT_LINEAR_IMAGE;
+"CONNECTED_COMPONENT_MAXIMAL",CONNECTED_COMPONENT_MAXIMAL;
+"CONNECTED_COMPONENT_MONO",CONNECTED_COMPONENT_MONO;
+"CONNECTED_COMPONENT_NONOVERLAP",CONNECTED_COMPONENT_NONOVERLAP;
+"CONNECTED_COMPONENT_OF_SUBSET",CONNECTED_COMPONENT_OF_SUBSET;
+"CONNECTED_COMPONENT_OVERLAP",CONNECTED_COMPONENT_OVERLAP;
+"CONNECTED_COMPONENT_REFL",CONNECTED_COMPONENT_REFL;
+"CONNECTED_COMPONENT_REFL_EQ",CONNECTED_COMPONENT_REFL_EQ;
+"CONNECTED_COMPONENT_SET",CONNECTED_COMPONENT_SET;
+"CONNECTED_COMPONENT_SUBSET",CONNECTED_COMPONENT_SUBSET;
+"CONNECTED_COMPONENT_SYM",CONNECTED_COMPONENT_SYM;
+"CONNECTED_COMPONENT_SYM_EQ",CONNECTED_COMPONENT_SYM_EQ;
+"CONNECTED_COMPONENT_TRANS",CONNECTED_COMPONENT_TRANS;
+"CONNECTED_COMPONENT_TRANSLATION",CONNECTED_COMPONENT_TRANSLATION;
+"CONNECTED_COMPONENT_UNIONS",CONNECTED_COMPONENT_UNIONS;
+"CONNECTED_COMPONENT_UNIQUE",CONNECTED_COMPONENT_UNIQUE;
+"CONNECTED_COMPONENT_UNIV",CONNECTED_COMPONENT_UNIV;
+"CONNECTED_CONNECTED_COMPONENT",CONNECTED_CONNECTED_COMPONENT;
+"CONNECTED_CONNECTED_COMPONENT_SET",CONNECTED_CONNECTED_COMPONENT_SET;
+"CONNECTED_CONTINUOUS_IMAGE",CONNECTED_CONTINUOUS_IMAGE;
+"CONNECTED_CONVEX_1",CONNECTED_CONVEX_1;
+"CONNECTED_CONVEX_1_GEN",CONNECTED_CONVEX_1_GEN;
+"CONNECTED_DIFF_BALL",CONNECTED_DIFF_BALL;
+"CONNECTED_DIFF_OPEN_FROM_CLOSED",CONNECTED_DIFF_OPEN_FROM_CLOSED;
+"CONNECTED_DISJOINT_UNIONS_OPEN_UNIQUE",CONNECTED_DISJOINT_UNIONS_OPEN_UNIQUE;
+"CONNECTED_EMPTY",CONNECTED_EMPTY;
+"CONNECTED_EQUIVALENCE_RELATION",CONNECTED_EQUIVALENCE_RELATION;
+"CONNECTED_EQUIVALENCE_RELATION_GEN",CONNECTED_EQUIVALENCE_RELATION_GEN;
+"CONNECTED_EQ_CONNECTED_COMPONENTS_EQ",CONNECTED_EQ_CONNECTED_COMPONENTS_EQ;
+"CONNECTED_EQ_CONNECTED_COMPONENT_EQ",CONNECTED_EQ_CONNECTED_COMPONENT_EQ;
+"CONNECTED_FINITE_IFF_COUNTABLE",CONNECTED_FINITE_IFF_COUNTABLE;
+"CONNECTED_FINITE_IFF_SING",CONNECTED_FINITE_IFF_SING;
+"CONNECTED_IFF_CONNECTED_COMPONENT",CONNECTED_IFF_CONNECTED_COMPONENT;
+"CONNECTED_IMP_PERFECT",CONNECTED_IMP_PERFECT;
+"CONNECTED_IMP_PERFECT_AFF_DIM",CONNECTED_IMP_PERFECT_AFF_DIM;
+"CONNECTED_INDUCTION",CONNECTED_INDUCTION;
+"CONNECTED_INDUCTION_SIMPLE",CONNECTED_INDUCTION_SIMPLE;
+"CONNECTED_INFINITE_IFF_CARD_EQ",CONNECTED_INFINITE_IFF_CARD_EQ;
+"CONNECTED_INTERMEDIATE_CLOSURE",CONNECTED_INTERMEDIATE_CLOSURE;
+"CONNECTED_INTERVAL",CONNECTED_INTERVAL;
+"CONNECTED_INTER_FRONTIER",CONNECTED_INTER_FRONTIER;
+"CONNECTED_INTER_RELATIVE_FRONTIER",CONNECTED_INTER_RELATIVE_FRONTIER;
+"CONNECTED_IVT_COMPONENT",CONNECTED_IVT_COMPONENT;
+"CONNECTED_IVT_HYPERPLANE",CONNECTED_IVT_HYPERPLANE;
+"CONNECTED_LINEAR_IMAGE",CONNECTED_LINEAR_IMAGE;
+"CONNECTED_LINEAR_IMAGE_EQ",CONNECTED_LINEAR_IMAGE_EQ;
+"CONNECTED_NEGATIONS",CONNECTED_NEGATIONS;
+"CONNECTED_NEST",CONNECTED_NEST;
+"CONNECTED_NEST_GEN",CONNECTED_NEST_GEN;
+"CONNECTED_OPEN_ARC_CONNECTED",CONNECTED_OPEN_ARC_CONNECTED;
+"CONNECTED_OPEN_DELETE",CONNECTED_OPEN_DELETE;
+"CONNECTED_OPEN_DIFF_CARD_LT",CONNECTED_OPEN_DIFF_CARD_LT;
+"CONNECTED_OPEN_DIFF_CBALL",CONNECTED_OPEN_DIFF_CBALL;
+"CONNECTED_OPEN_DIFF_COUNTABLE",CONNECTED_OPEN_DIFF_COUNTABLE;
+"CONNECTED_OPEN_IN",CONNECTED_OPEN_IN;
+"CONNECTED_OPEN_IN_DIFF_CARD_LT",CONNECTED_OPEN_IN_DIFF_CARD_LT;
+"CONNECTED_OPEN_IN_EQ",CONNECTED_OPEN_IN_EQ;
+"CONNECTED_OPEN_PATH_CONNECTED",CONNECTED_OPEN_PATH_CONNECTED;
+"CONNECTED_OPEN_SET",CONNECTED_OPEN_SET;
+"CONNECTED_OUTSIDE",CONNECTED_OUTSIDE;
+"CONNECTED_PATH_IMAGE",CONNECTED_PATH_IMAGE;
+"CONNECTED_PCROSS",CONNECTED_PCROSS;
+"CONNECTED_PCROSS_EQ",CONNECTED_PCROSS_EQ;
+"CONNECTED_PUNCTURED_BALL",CONNECTED_PUNCTURED_BALL;
+"CONNECTED_PUNCTURED_UNIVERSE",CONNECTED_PUNCTURED_UNIVERSE;
+"CONNECTED_REAL_LEMMA",CONNECTED_REAL_LEMMA;
+"CONNECTED_SCALING",CONNECTED_SCALING;
+"CONNECTED_SEGMENT",CONNECTED_SEGMENT;
+"CONNECTED_SEMIOPEN_SEGMENT",CONNECTED_SEMIOPEN_SEGMENT;
+"CONNECTED_SIMPLE_PATH_ENDLESS",CONNECTED_SIMPLE_PATH_ENDLESS;
+"CONNECTED_SIMPLE_PATH_IMAGE",CONNECTED_SIMPLE_PATH_IMAGE;
+"CONNECTED_SING",CONNECTED_SING;
+"CONNECTED_SPHERE",CONNECTED_SPHERE;
+"CONNECTED_SPHERE_EQ",CONNECTED_SPHERE_EQ;
+"CONNECTED_SUMS",CONNECTED_SUMS;
+"CONNECTED_TRANSLATION",CONNECTED_TRANSLATION;
+"CONNECTED_TRANSLATION_EQ",CONNECTED_TRANSLATION_EQ;
+"CONNECTED_UNION",CONNECTED_UNION;
+"CONNECTED_UNIONS",CONNECTED_UNIONS;
+"CONNECTED_UNION_CLOPEN_IN_COMPLEMENT",CONNECTED_UNION_CLOPEN_IN_COMPLEMENT;
+"CONNECTED_UNION_STRONG",CONNECTED_UNION_STRONG;
+"CONNECTED_UNIV",CONNECTED_UNIV;
+"CONNECTED_WITH_INSIDE",CONNECTED_WITH_INSIDE;
+"CONNECTED_WITH_OUTSIDE",CONNECTED_WITH_OUTSIDE;
+"CONSTR",CONSTR;
+"CONSTR_BOT",CONSTR_BOT;
+"CONSTR_IND",CONSTR_IND;
+"CONSTR_INJ",CONSTR_INJ;
+"CONSTR_REC",CONSTR_REC;
+"CONS_11",CONS_11;
+"CONS_HD_TL",CONS_HD_TL;
+"CONTENT_0_SUBSET",CONTENT_0_SUBSET;
+"CONTENT_0_SUBSET_GEN",CONTENT_0_SUBSET_GEN;
+"CONTENT_1",CONTENT_1;
+"CONTENT_CLOSED_INTERVAL",CONTENT_CLOSED_INTERVAL;
+"CONTENT_CLOSED_INTERVAL_CASES",CONTENT_CLOSED_INTERVAL_CASES;
+"CONTENT_DOUBLESPLIT",CONTENT_DOUBLESPLIT;
+"CONTENT_EMPTY",CONTENT_EMPTY;
+"CONTENT_EQ_0",CONTENT_EQ_0;
+"CONTENT_EQ_0_1",CONTENT_EQ_0_1;
+"CONTENT_EQ_0_GEN",CONTENT_EQ_0_GEN;
+"CONTENT_EQ_0_INTERIOR",CONTENT_EQ_0_INTERIOR;
+"CONTENT_IMAGE_AFFINITY_INTERVAL",CONTENT_IMAGE_AFFINITY_INTERVAL;
+"CONTENT_IMAGE_STRETCH_INTERVAL",CONTENT_IMAGE_STRETCH_INTERVAL;
+"CONTENT_LT_NZ",CONTENT_LT_NZ;
+"CONTENT_PASTECART",CONTENT_PASTECART;
+"CONTENT_POS_LE",CONTENT_POS_LE;
+"CONTENT_POS_LT",CONTENT_POS_LT;
+"CONTENT_POS_LT_1",CONTENT_POS_LT_1;
+"CONTENT_POS_LT_EQ",CONTENT_POS_LT_EQ;
+"CONTENT_SPLIT",CONTENT_SPLIT;
+"CONTENT_SUBSET",CONTENT_SUBSET;
+"CONTENT_UNIT",CONTENT_UNIT;
+"CONTENT_UNIT_1",CONTENT_UNIT_1;
+"CONTINUOUS_ABS",CONTINUOUS_ABS;
+"CONTINUOUS_ADD",CONTINUOUS_ADD;
+"CONTINUOUS_AGREE_ON_CLOSURE",CONTINUOUS_AGREE_ON_CLOSURE;
+"CONTINUOUS_AT",CONTINUOUS_AT;
+"CONTINUOUS_ATTAINS_INF",CONTINUOUS_ATTAINS_INF;
+"CONTINUOUS_ATTAINS_SUP",CONTINUOUS_ATTAINS_SUP;
+"CONTINUOUS_AT_AVOID",CONTINUOUS_AT_AVOID;
+"CONTINUOUS_AT_BALL",CONTINUOUS_AT_BALL;
+"CONTINUOUS_AT_CLOSEST_POINT",CONTINUOUS_AT_CLOSEST_POINT;
+"CONTINUOUS_AT_COMPOSE",CONTINUOUS_AT_COMPOSE;
+"CONTINUOUS_AT_COMPOSE_EQ",CONTINUOUS_AT_COMPOSE_EQ;
+"CONTINUOUS_AT_DIST_CLOSEST_POINT",CONTINUOUS_AT_DIST_CLOSEST_POINT;
+"CONTINUOUS_AT_ID",CONTINUOUS_AT_ID;
+"CONTINUOUS_AT_IMP_CONTINUOUS_ON",CONTINUOUS_AT_IMP_CONTINUOUS_ON;
+"CONTINUOUS_AT_INV",CONTINUOUS_AT_INV;
+"CONTINUOUS_AT_LIFT_COMPONENT",CONTINUOUS_AT_LIFT_COMPONENT;
+"CONTINUOUS_AT_LIFT_DIST",CONTINUOUS_AT_LIFT_DIST;
+"CONTINUOUS_AT_LIFT_DOT",CONTINUOUS_AT_LIFT_DOT;
+"CONTINUOUS_AT_LIFT_INFNORM",CONTINUOUS_AT_LIFT_INFNORM;
+"CONTINUOUS_AT_LIFT_NORM",CONTINUOUS_AT_LIFT_NORM;
+"CONTINUOUS_AT_LIFT_RANGE",CONTINUOUS_AT_LIFT_RANGE;
+"CONTINUOUS_AT_LIFT_SETDIST",CONTINUOUS_AT_LIFT_SETDIST;
+"CONTINUOUS_AT_LINEAR_IMAGE",CONTINUOUS_AT_LINEAR_IMAGE;
+"CONTINUOUS_AT_OPEN",CONTINUOUS_AT_OPEN;
+"CONTINUOUS_AT_SEQUENTIALLY",CONTINUOUS_AT_SEQUENTIALLY;
+"CONTINUOUS_AT_SQRT",CONTINUOUS_AT_SQRT;
+"CONTINUOUS_AT_SQRT_COMPOSE",CONTINUOUS_AT_SQRT_COMPOSE;
+"CONTINUOUS_AT_TRANSLATION",CONTINUOUS_AT_TRANSLATION;
+"CONTINUOUS_AT_WITHIN",CONTINUOUS_AT_WITHIN;
+"CONTINUOUS_AT_WITHIN_INV",CONTINUOUS_AT_WITHIN_INV;
+"CONTINUOUS_CARD_LT_RANGE_CONSTANT",CONTINUOUS_CARD_LT_RANGE_CONSTANT;
+"CONTINUOUS_CARD_LT_RANGE_CONSTANT_EQ",CONTINUOUS_CARD_LT_RANGE_CONSTANT_EQ;
+"CONTINUOUS_CLOSED_IMP_CAUCHY_CONTINUOUS",CONTINUOUS_CLOSED_IMP_CAUCHY_CONTINUOUS;
+"CONTINUOUS_CLOSED_IN_PREIMAGE",CONTINUOUS_CLOSED_IN_PREIMAGE;
+"CONTINUOUS_CLOSED_IN_PREIMAGE_CONSTANT",CONTINUOUS_CLOSED_IN_PREIMAGE_CONSTANT;
+"CONTINUOUS_CLOSED_IN_PREIMAGE_EQ",CONTINUOUS_CLOSED_IN_PREIMAGE_EQ;
+"CONTINUOUS_CLOSED_IN_PREIMAGE_GEN",CONTINUOUS_CLOSED_IN_PREIMAGE_GEN;
+"CONTINUOUS_CLOSED_PREIMAGE",CONTINUOUS_CLOSED_PREIMAGE;
+"CONTINUOUS_CLOSED_PREIMAGE_CONSTANT",CONTINUOUS_CLOSED_PREIMAGE_CONSTANT;
+"CONTINUOUS_CLOSED_PREIMAGE_UNIV",CONTINUOUS_CLOSED_PREIMAGE_UNIV;
+"CONTINUOUS_CMUL",CONTINUOUS_CMUL;
+"CONTINUOUS_COMPONENTWISE_LIFT",CONTINUOUS_COMPONENTWISE_LIFT;
+"CONTINUOUS_CONST",CONTINUOUS_CONST;
+"CONTINUOUS_CONSTANT_ON_CLOSURE",CONTINUOUS_CONSTANT_ON_CLOSURE;
+"CONTINUOUS_COUNTABLE_RANGE_CONSTANT",CONTINUOUS_COUNTABLE_RANGE_CONSTANT;
+"CONTINUOUS_COUNTABLE_RANGE_CONSTANT_EQ",CONTINUOUS_COUNTABLE_RANGE_CONSTANT_EQ;
+"CONTINUOUS_DISCONNECTED_RANGE_CONSTANT",CONTINUOUS_DISCONNECTED_RANGE_CONSTANT;
+"CONTINUOUS_DISCONNECTED_RANGE_CONSTANT_EQ",CONTINUOUS_DISCONNECTED_RANGE_CONSTANT_EQ;
+"CONTINUOUS_DISCRETE_RANGE_CONSTANT",CONTINUOUS_DISCRETE_RANGE_CONSTANT;
+"CONTINUOUS_DISCRETE_RANGE_CONSTANT_EQ",CONTINUOUS_DISCRETE_RANGE_CONSTANT_EQ;
+"CONTINUOUS_FINITE_RANGE_CONSTANT",CONTINUOUS_FINITE_RANGE_CONSTANT;
+"CONTINUOUS_FINITE_RANGE_CONSTANT_EQ",CONTINUOUS_FINITE_RANGE_CONSTANT_EQ;
+"CONTINUOUS_GE_ON_CLOSURE",CONTINUOUS_GE_ON_CLOSURE;
+"CONTINUOUS_IMP_CLOSED_MAP",CONTINUOUS_IMP_CLOSED_MAP;
+"CONTINUOUS_IMP_MEASURABLE_ON",CONTINUOUS_IMP_MEASURABLE_ON;
+"CONTINUOUS_IMP_MEASURABLE_ON_CLOSED_SUBSET",CONTINUOUS_IMP_MEASURABLE_ON_CLOSED_SUBSET;
+"CONTINUOUS_IMP_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET",CONTINUOUS_IMP_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET;
+"CONTINUOUS_INJECTIVE_IFF_MONOTONIC",CONTINUOUS_INJECTIVE_IFF_MONOTONIC;
+"CONTINUOUS_INJECTIVE_IMAGE_OPEN_SEGMENT_1",CONTINUOUS_INJECTIVE_IMAGE_OPEN_SEGMENT_1;
+"CONTINUOUS_INJECTIVE_IMAGE_SEGMENT_1",CONTINUOUS_INJECTIVE_IMAGE_SEGMENT_1;
+"CONTINUOUS_INTERVAL_BIJ",CONTINUOUS_INTERVAL_BIJ;
+"CONTINUOUS_INV",CONTINUOUS_INV;
+"CONTINUOUS_IVT_LOCAL_EXTREMUM",CONTINUOUS_IVT_LOCAL_EXTREMUM;
+"CONTINUOUS_LEFT_INVERSE_IMP_QUOTIENT_MAP",CONTINUOUS_LEFT_INVERSE_IMP_QUOTIENT_MAP;
+"CONTINUOUS_LEVELSET_OPEN",CONTINUOUS_LEVELSET_OPEN;
+"CONTINUOUS_LEVELSET_OPEN_IN",CONTINUOUS_LEVELSET_OPEN_IN;
+"CONTINUOUS_LEVELSET_OPEN_IN_CASES",CONTINUOUS_LEVELSET_OPEN_IN_CASES;
+"CONTINUOUS_LE_ON_CLOSURE",CONTINUOUS_LE_ON_CLOSURE;
+"CONTINUOUS_LIFT_COMPONENT_COMPOSE",CONTINUOUS_LIFT_COMPONENT_COMPOSE;
+"CONTINUOUS_LIFT_DET",CONTINUOUS_LIFT_DET;
+"CONTINUOUS_LIFT_DOT2",CONTINUOUS_LIFT_DOT2;
+"CONTINUOUS_LIFT_NORM_COMPOSE",CONTINUOUS_LIFT_NORM_COMPOSE;
+"CONTINUOUS_LIFT_POW",CONTINUOUS_LIFT_POW;
+"CONTINUOUS_LIFT_PRODUCT",CONTINUOUS_LIFT_PRODUCT;
+"CONTINUOUS_LINEPATH_AT",CONTINUOUS_LINEPATH_AT;
+"CONTINUOUS_MAX",CONTINUOUS_MAX;
+"CONTINUOUS_MIDPOINT_CONVEX",CONTINUOUS_MIDPOINT_CONVEX;
+"CONTINUOUS_MIN",CONTINUOUS_MIN;
+"CONTINUOUS_MUL",CONTINUOUS_MUL;
+"CONTINUOUS_NEG",CONTINUOUS_NEG;
+"CONTINUOUS_ON",CONTINUOUS_ON;
+"CONTINUOUS_ON_ABS",CONTINUOUS_ON_ABS;
+"CONTINUOUS_ON_ADD",CONTINUOUS_ON_ADD;
+"CONTINUOUS_ON_AVOID",CONTINUOUS_ON_AVOID;
+"CONTINUOUS_ON_CASES",CONTINUOUS_ON_CASES;
+"CONTINUOUS_ON_CASES_1",CONTINUOUS_ON_CASES_1;
+"CONTINUOUS_ON_CASES_LE",CONTINUOUS_ON_CASES_LE;
+"CONTINUOUS_ON_CASES_LOCAL",CONTINUOUS_ON_CASES_LOCAL;
+"CONTINUOUS_ON_CASES_LOCAL_OPEN",CONTINUOUS_ON_CASES_LOCAL_OPEN;
+"CONTINUOUS_ON_CASES_OPEN",CONTINUOUS_ON_CASES_OPEN;
+"CONTINUOUS_ON_CLOSED",CONTINUOUS_ON_CLOSED;
+"CONTINUOUS_ON_CLOSED_GEN",CONTINUOUS_ON_CLOSED_GEN;
+"CONTINUOUS_ON_CLOSEST_POINT",CONTINUOUS_ON_CLOSEST_POINT;
+"CONTINUOUS_ON_CLOSURE",CONTINUOUS_ON_CLOSURE;
+"CONTINUOUS_ON_CLOSURE_COMPONENT_GE",CONTINUOUS_ON_CLOSURE_COMPONENT_GE;
+"CONTINUOUS_ON_CLOSURE_COMPONENT_LE",CONTINUOUS_ON_CLOSURE_COMPONENT_LE;
+"CONTINUOUS_ON_CLOSURE_NORM_LE",CONTINUOUS_ON_CLOSURE_NORM_LE;
+"CONTINUOUS_ON_CLOSURE_SEQUENTIALLY",CONTINUOUS_ON_CLOSURE_SEQUENTIALLY;
+"CONTINUOUS_ON_CMUL",CONTINUOUS_ON_CMUL;
+"CONTINUOUS_ON_COMPACT_SURFACE_PROJECTION",CONTINUOUS_ON_COMPACT_SURFACE_PROJECTION;
+"CONTINUOUS_ON_COMPONENTS",CONTINUOUS_ON_COMPONENTS;
+"CONTINUOUS_ON_COMPONENTS_CLOSED",CONTINUOUS_ON_COMPONENTS_CLOSED;
+"CONTINUOUS_ON_COMPONENTS_CLOSED_GEN",CONTINUOUS_ON_COMPONENTS_CLOSED_GEN;
+"CONTINUOUS_ON_COMPONENTS_EQ",CONTINUOUS_ON_COMPONENTS_EQ;
+"CONTINUOUS_ON_COMPONENTS_GEN",CONTINUOUS_ON_COMPONENTS_GEN;
+"CONTINUOUS_ON_COMPONENTWISE_LIFT",CONTINUOUS_ON_COMPONENTWISE_LIFT;
+"CONTINUOUS_ON_COMPOSE",CONTINUOUS_ON_COMPOSE;
+"CONTINUOUS_ON_CONST",CONTINUOUS_ON_CONST;
+"CONTINUOUS_ON_DIST_CLOSEST_POINT",CONTINUOUS_ON_DIST_CLOSEST_POINT;
+"CONTINUOUS_ON_EMPTY",CONTINUOUS_ON_EMPTY;
+"CONTINUOUS_ON_EQ",CONTINUOUS_ON_EQ;
+"CONTINUOUS_ON_EQ_CONTINUOUS_AT",CONTINUOUS_ON_EQ_CONTINUOUS_AT;
+"CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN",CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+"CONTINUOUS_ON_FINITE",CONTINUOUS_ON_FINITE;
+"CONTINUOUS_ON_ID",CONTINUOUS_ON_ID;
+"CONTINUOUS_ON_IMP_CLOSED_IN",CONTINUOUS_ON_IMP_CLOSED_IN;
+"CONTINUOUS_ON_IMP_OPEN_IN",CONTINUOUS_ON_IMP_OPEN_IN;
+"CONTINUOUS_ON_INTERIOR",CONTINUOUS_ON_INTERIOR;
+"CONTINUOUS_ON_INTERVAL_BIJ",CONTINUOUS_ON_INTERVAL_BIJ;
+"CONTINUOUS_ON_INV",CONTINUOUS_ON_INV;
+"CONTINUOUS_ON_INVERSE",CONTINUOUS_ON_INVERSE;
+"CONTINUOUS_ON_INVERSE_CLOSED_MAP",CONTINUOUS_ON_INVERSE_CLOSED_MAP;
+"CONTINUOUS_ON_INVERSE_OPEN_MAP",CONTINUOUS_ON_INVERSE_OPEN_MAP;
+"CONTINUOUS_ON_LIFT_COMPONENT",CONTINUOUS_ON_LIFT_COMPONENT;
+"CONTINUOUS_ON_LIFT_COMPONENT_COMPOSE",CONTINUOUS_ON_LIFT_COMPONENT_COMPOSE;
+"CONTINUOUS_ON_LIFT_DET",CONTINUOUS_ON_LIFT_DET;
+"CONTINUOUS_ON_LIFT_DIST",CONTINUOUS_ON_LIFT_DIST;
+"CONTINUOUS_ON_LIFT_DOT",CONTINUOUS_ON_LIFT_DOT;
+"CONTINUOUS_ON_LIFT_DOT2",CONTINUOUS_ON_LIFT_DOT2;
+"CONTINUOUS_ON_LIFT_NORM",CONTINUOUS_ON_LIFT_NORM;
+"CONTINUOUS_ON_LIFT_NORM_COMPOSE",CONTINUOUS_ON_LIFT_NORM_COMPOSE;
+"CONTINUOUS_ON_LIFT_POW",CONTINUOUS_ON_LIFT_POW;
+"CONTINUOUS_ON_LIFT_PRODUCT",CONTINUOUS_ON_LIFT_PRODUCT;
+"CONTINUOUS_ON_LIFT_RANGE",CONTINUOUS_ON_LIFT_RANGE;
+"CONTINUOUS_ON_LIFT_SETDIST",CONTINUOUS_ON_LIFT_SETDIST;
+"CONTINUOUS_ON_LIFT_SQRT",CONTINUOUS_ON_LIFT_SQRT;
+"CONTINUOUS_ON_LIFT_SQRT_COMPOSE",CONTINUOUS_ON_LIFT_SQRT_COMPOSE;
+"CONTINUOUS_ON_LINEPATH",CONTINUOUS_ON_LINEPATH;
+"CONTINUOUS_ON_MAX",CONTINUOUS_ON_MAX;
+"CONTINUOUS_ON_MIN",CONTINUOUS_ON_MIN;
+"CONTINUOUS_ON_MUL",CONTINUOUS_ON_MUL;
+"CONTINUOUS_ON_NEG",CONTINUOUS_ON_NEG;
+"CONTINUOUS_ON_NO_LIMPT",CONTINUOUS_ON_NO_LIMPT;
+"CONTINUOUS_ON_OPEN",CONTINUOUS_ON_OPEN;
+"CONTINUOUS_ON_OPEN_AVOID",CONTINUOUS_ON_OPEN_AVOID;
+"CONTINUOUS_ON_OPEN_GEN",CONTINUOUS_ON_OPEN_GEN;
+"CONTINUOUS_ON_PASTECART",CONTINUOUS_ON_PASTECART;
+"CONTINUOUS_ON_SEQUENTIALLY",CONTINUOUS_ON_SEQUENTIALLY;
+"CONTINUOUS_ON_SING",CONTINUOUS_ON_SING;
+"CONTINUOUS_ON_SUB",CONTINUOUS_ON_SUB;
+"CONTINUOUS_ON_SUBSET",CONTINUOUS_ON_SUBSET;
+"CONTINUOUS_ON_UNION",CONTINUOUS_ON_UNION;
+"CONTINUOUS_ON_UNION_LOCAL",CONTINUOUS_ON_UNION_LOCAL;
+"CONTINUOUS_ON_UNION_LOCAL_OPEN",CONTINUOUS_ON_UNION_LOCAL_OPEN;
+"CONTINUOUS_ON_UNION_OPEN",CONTINUOUS_ON_UNION_OPEN;
+"CONTINUOUS_ON_VMUL",CONTINUOUS_ON_VMUL;
+"CONTINUOUS_ON_VSUM",CONTINUOUS_ON_VSUM;
+"CONTINUOUS_OPEN_IN_PREIMAGE",CONTINUOUS_OPEN_IN_PREIMAGE;
+"CONTINUOUS_OPEN_IN_PREIMAGE_EQ",CONTINUOUS_OPEN_IN_PREIMAGE_EQ;
+"CONTINUOUS_OPEN_IN_PREIMAGE_GEN",CONTINUOUS_OPEN_IN_PREIMAGE_GEN;
+"CONTINUOUS_OPEN_PREIMAGE",CONTINUOUS_OPEN_PREIMAGE;
+"CONTINUOUS_OPEN_PREIMAGE_UNIV",CONTINUOUS_OPEN_PREIMAGE_UNIV;
+"CONTINUOUS_PASTECART",CONTINUOUS_PASTECART;
+"CONTINUOUS_RIGHT_INVERSE_IMP_QUOTIENT_MAP",CONTINUOUS_RIGHT_INVERSE_IMP_QUOTIENT_MAP;
+"CONTINUOUS_SUB",CONTINUOUS_SUB;
+"CONTINUOUS_TRANSFORM_AT",CONTINUOUS_TRANSFORM_AT;
+"CONTINUOUS_TRANSFORM_WITHIN",CONTINUOUS_TRANSFORM_WITHIN;
+"CONTINUOUS_TRIVIAL_LIMIT",CONTINUOUS_TRIVIAL_LIMIT;
+"CONTINUOUS_UNIFORM_LIMIT",CONTINUOUS_UNIFORM_LIMIT;
+"CONTINUOUS_VMUL",CONTINUOUS_VMUL;
+"CONTINUOUS_VSUM",CONTINUOUS_VSUM;
+"CONTINUOUS_WITHIN",CONTINUOUS_WITHIN;
+"CONTINUOUS_WITHIN_AVOID",CONTINUOUS_WITHIN_AVOID;
+"CONTINUOUS_WITHIN_BALL",CONTINUOUS_WITHIN_BALL;
+"CONTINUOUS_WITHIN_CLOSED_NONTRIVIAL",CONTINUOUS_WITHIN_CLOSED_NONTRIVIAL;
+"CONTINUOUS_WITHIN_COMPOSE",CONTINUOUS_WITHIN_COMPOSE;
+"CONTINUOUS_WITHIN_ID",CONTINUOUS_WITHIN_ID;
+"CONTINUOUS_WITHIN_LIFT_SQRT",CONTINUOUS_WITHIN_LIFT_SQRT;
+"CONTINUOUS_WITHIN_OPEN",CONTINUOUS_WITHIN_OPEN;
+"CONTINUOUS_WITHIN_SEQUENTIALLY",CONTINUOUS_WITHIN_SEQUENTIALLY;
+"CONTINUOUS_WITHIN_SQRT_COMPOSE",CONTINUOUS_WITHIN_SQRT_COMPOSE;
+"CONTINUOUS_WITHIN_SUBSET",CONTINUOUS_WITHIN_SUBSET;
+"CONTRACTIBLE_CONVEX_TWEAK_BOUNDARY_POINTS",CONTRACTIBLE_CONVEX_TWEAK_BOUNDARY_POINTS;
+"CONTRACTIBLE_EMPTY",CONTRACTIBLE_EMPTY;
+"CONTRACTIBLE_IMP_CONNECTED",CONTRACTIBLE_IMP_CONNECTED;
+"CONTRACTIBLE_IMP_PATH_CONNECTED",CONTRACTIBLE_IMP_PATH_CONNECTED;
+"CONTRACTIBLE_IMP_SIMPLY_CONNECTED",CONTRACTIBLE_IMP_SIMPLY_CONNECTED;
+"CONTRACTIBLE_INJECTIVE_LINEAR_IMAGE",CONTRACTIBLE_INJECTIVE_LINEAR_IMAGE;
+"CONTRACTIBLE_PCROSS",CONTRACTIBLE_PCROSS;
+"CONTRACTIBLE_PCROSS_EQ",CONTRACTIBLE_PCROSS_EQ;
+"CONTRACTIBLE_PUNCTURED_SPHERE",CONTRACTIBLE_PUNCTURED_SPHERE;
+"CONTRACTIBLE_SING",CONTRACTIBLE_SING;
+"CONTRACTIBLE_SPHERE",CONTRACTIBLE_SPHERE;
+"CONTRACTIBLE_TRANSLATION",CONTRACTIBLE_TRANSLATION;
+"CONTRACTIBLE_UNIV",CONTRACTIBLE_UNIV;
+"CONTRACTION_IMP_CONTINUOUS_ON",CONTRACTION_IMP_CONTINUOUS_ON;
+"CONTRAPOS_THM",CONTRAPOS_THM;
+"CONVERGENT_BOUNDED_INCREASING",CONVERGENT_BOUNDED_INCREASING;
+"CONVERGENT_BOUNDED_MONOTONE",CONVERGENT_BOUNDED_MONOTONE;
+"CONVERGENT_EQ_CAUCHY",CONVERGENT_EQ_CAUCHY;
+"CONVERGENT_IMP_BOUNDED",CONVERGENT_IMP_BOUNDED;
+"CONVERGENT_IMP_CAUCHY",CONVERGENT_IMP_CAUCHY;
+"CONVEX",CONVEX;
+"CONVEX_ADD",CONVEX_ADD;
+"CONVEX_AFFINITY",CONVEX_AFFINITY;
+"CONVEX_ALT",CONVEX_ALT;
+"CONVEX_AND_AFFINE_INTER_OPEN",CONVEX_AND_AFFINE_INTER_OPEN;
+"CONVEX_BALL",CONVEX_BALL;
+"CONVEX_BOUNDS_LEMMA",CONVEX_BOUNDS_LEMMA;
+"CONVEX_CBALL",CONVEX_CBALL;
+"CONVEX_CLOSED_CONTAINS_SAME_RAY",CONVEX_CLOSED_CONTAINS_SAME_RAY;
+"CONVEX_CLOSURE",CONVEX_CLOSURE;
+"CONVEX_CLOSURE_INTERIOR",CONVEX_CLOSURE_INTERIOR;
+"CONVEX_CLOSURE_RELATIVE_INTERIOR",CONVEX_CLOSURE_RELATIVE_INTERIOR;
+"CONVEX_CMUL",CONVEX_CMUL;
+"CONVEX_CONE",CONVEX_CONE;
+"CONVEX_CONE_CONTAINS_0",CONVEX_CONE_CONTAINS_0;
+"CONVEX_CONE_CONVEX_CONE_HULL",CONVEX_CONE_CONVEX_CONE_HULL;
+"CONVEX_CONE_HALFSPACE_GE",CONVEX_CONE_HALFSPACE_GE;
+"CONVEX_CONE_HALFSPACE_LE",CONVEX_CONE_HALFSPACE_LE;
+"CONVEX_CONE_HULL_ADD",CONVEX_CONE_HULL_ADD;
+"CONVEX_CONE_HULL_CONTAINS_0",CONVEX_CONE_HULL_CONTAINS_0;
+"CONVEX_CONE_HULL_CONVEX_HULL",CONVEX_CONE_HULL_CONVEX_HULL;
+"CONVEX_CONE_HULL_CONVEX_HULL_NONEMPTY",CONVEX_CONE_HULL_CONVEX_HULL_NONEMPTY;
+"CONVEX_CONE_HULL_EMPTY",CONVEX_CONE_HULL_EMPTY;
+"CONVEX_CONE_HULL_LINEAR_IMAGE",CONVEX_CONE_HULL_LINEAR_IMAGE;
+"CONVEX_CONE_HULL_MUL",CONVEX_CONE_HULL_MUL;
+"CONVEX_CONE_HULL_NONEMPTY",CONVEX_CONE_HULL_NONEMPTY;
+"CONVEX_CONE_HULL_SEPARATE",CONVEX_CONE_HULL_SEPARATE;
+"CONVEX_CONE_HULL_SEPARATE_NONEMPTY",CONVEX_CONE_HULL_SEPARATE_NONEMPTY;
+"CONVEX_CONE_HULL_UNION",CONVEX_CONE_HULL_UNION;
+"CONVEX_CONE_INTERS",CONVEX_CONE_INTERS;
+"CONVEX_CONE_LINEAR_IMAGE",CONVEX_CONE_LINEAR_IMAGE;
+"CONVEX_CONE_LINEAR_IMAGE_EQ",CONVEX_CONE_LINEAR_IMAGE_EQ;
+"CONVEX_CONE_NEGATIONS",CONVEX_CONE_NEGATIONS;
+"CONVEX_CONE_PCROSS",CONVEX_CONE_PCROSS;
+"CONVEX_CONE_PCROSS_EQ",CONVEX_CONE_PCROSS_EQ;
+"CONVEX_CONE_SING",CONVEX_CONE_SING;
+"CONVEX_CONE_SPAN",CONVEX_CONE_SPAN;
+"CONVEX_CONE_SUMS",CONVEX_CONE_SUMS;
+"CONVEX_CONIC_HULL",CONVEX_CONIC_HULL;
+"CONVEX_CONNECTED",CONVEX_CONNECTED;
+"CONVEX_CONNECTED_1",CONVEX_CONNECTED_1;
+"CONVEX_CONNECTED_1_GEN",CONVEX_CONNECTED_1_GEN;
+"CONVEX_CONTAINS_SEGMENT",CONVEX_CONTAINS_SEGMENT;
+"CONVEX_CONTAINS_SEGMENT_EQ",CONVEX_CONTAINS_SEGMENT_EQ;
+"CONVEX_CONTAINS_SEGMENT_IMP",CONVEX_CONTAINS_SEGMENT_IMP;
+"CONVEX_CONVEX_CONE_HULL",CONVEX_CONVEX_CONE_HULL;
+"CONVEX_CONVEX_HULL",CONVEX_CONVEX_HULL;
+"CONVEX_DIFFERENCES",CONVEX_DIFFERENCES;
+"CONVEX_DISTANCE",CONVEX_DISTANCE;
+"CONVEX_EMPTY",CONVEX_EMPTY;
+"CONVEX_EPIGRAPH",CONVEX_EPIGRAPH;
+"CONVEX_EPIGRAPH_CONVEX",CONVEX_EPIGRAPH_CONVEX;
+"CONVEX_EXPLICIT",CONVEX_EXPLICIT;
+"CONVEX_FINITE",CONVEX_FINITE;
+"CONVEX_HALFSPACE_COMPONENT_GE",CONVEX_HALFSPACE_COMPONENT_GE;
+"CONVEX_HALFSPACE_COMPONENT_GT",CONVEX_HALFSPACE_COMPONENT_GT;
+"CONVEX_HALFSPACE_COMPONENT_LE",CONVEX_HALFSPACE_COMPONENT_LE;
+"CONVEX_HALFSPACE_COMPONENT_LT",CONVEX_HALFSPACE_COMPONENT_LT;
+"CONVEX_HALFSPACE_GE",CONVEX_HALFSPACE_GE;
+"CONVEX_HALFSPACE_GT",CONVEX_HALFSPACE_GT;
+"CONVEX_HALFSPACE_INTERSECTION",CONVEX_HALFSPACE_INTERSECTION;
+"CONVEX_HALFSPACE_LE",CONVEX_HALFSPACE_LE;
+"CONVEX_HALFSPACE_LT",CONVEX_HALFSPACE_LT;
+"CONVEX_HULLS_EQ",CONVEX_HULLS_EQ;
+"CONVEX_HULL_2",CONVEX_HULL_2;
+"CONVEX_HULL_2_ALT",CONVEX_HULL_2_ALT;
+"CONVEX_HULL_3",CONVEX_HULL_3;
+"CONVEX_HULL_3_ALT",CONVEX_HULL_3_ALT;
+"CONVEX_HULL_AFFINITY",CONVEX_HULL_AFFINITY;
+"CONVEX_HULL_CARATHEODORY",CONVEX_HULL_CARATHEODORY;
+"CONVEX_HULL_CARATHEODORY_AFF_DIM",CONVEX_HULL_CARATHEODORY_AFF_DIM;
+"CONVEX_HULL_EMPTY",CONVEX_HULL_EMPTY;
+"CONVEX_HULL_EQ",CONVEX_HULL_EQ;
+"CONVEX_HULL_EQ_EMPTY",CONVEX_HULL_EQ_EMPTY;
+"CONVEX_HULL_EQ_SING",CONVEX_HULL_EQ_SING;
+"CONVEX_HULL_EXCHANGE_INTER",CONVEX_HULL_EXCHANGE_INTER;
+"CONVEX_HULL_EXCHANGE_UNION",CONVEX_HULL_EXCHANGE_UNION;
+"CONVEX_HULL_EXPLICIT",CONVEX_HULL_EXPLICIT;
+"CONVEX_HULL_FINITE",CONVEX_HULL_FINITE;
+"CONVEX_HULL_FINITE_STEP",CONVEX_HULL_FINITE_STEP;
+"CONVEX_HULL_INDEXED",CONVEX_HULL_INDEXED;
+"CONVEX_HULL_INSERT",CONVEX_HULL_INSERT;
+"CONVEX_HULL_INSERT_ALT",CONVEX_HULL_INSERT_ALT;
+"CONVEX_HULL_INTER",CONVEX_HULL_INTER;
+"CONVEX_HULL_INTERS",CONVEX_HULL_INTERS;
+"CONVEX_HULL_LINEAR_IMAGE",CONVEX_HULL_LINEAR_IMAGE;
+"CONVEX_HULL_PCROSS",CONVEX_HULL_PCROSS;
+"CONVEX_HULL_SCALING",CONVEX_HULL_SCALING;
+"CONVEX_HULL_SING",CONVEX_HULL_SING;
+"CONVEX_HULL_SUBSET_AFFINE_HULL",CONVEX_HULL_SUBSET_AFFINE_HULL;
+"CONVEX_HULL_SUBSET_CONVEX_CONE_HULL",CONVEX_HULL_SUBSET_CONVEX_CONE_HULL;
+"CONVEX_HULL_SUBSET_SPAN",CONVEX_HULL_SUBSET_SPAN;
+"CONVEX_HULL_SUMS",CONVEX_HULL_SUMS;
+"CONVEX_HULL_TRANSLATION",CONVEX_HULL_TRANSLATION;
+"CONVEX_HULL_UNION_EXPLICIT",CONVEX_HULL_UNION_EXPLICIT;
+"CONVEX_HULL_UNION_NONEMPTY_EXPLICIT",CONVEX_HULL_UNION_NONEMPTY_EXPLICIT;
+"CONVEX_HULL_UNION_UNIONS",CONVEX_HULL_UNION_UNIONS;
+"CONVEX_HULL_UNIV",CONVEX_HULL_UNIV;
+"CONVEX_HYPERPLANE",CONVEX_HYPERPLANE;
+"CONVEX_IMP_CONTRACTIBLE",CONVEX_IMP_CONTRACTIBLE;
+"CONVEX_IMP_LOCALLY_CONNECTED",CONVEX_IMP_LOCALLY_CONNECTED;
+"CONVEX_IMP_LOCALLY_PATH_CONNECTED",CONVEX_IMP_LOCALLY_PATH_CONNECTED;
+"CONVEX_IMP_PATH_CONNECTED",CONVEX_IMP_PATH_CONNECTED;
+"CONVEX_IMP_SIMPLY_CONNECTED",CONVEX_IMP_SIMPLY_CONNECTED;
+"CONVEX_IMP_STARLIKE",CONVEX_IMP_STARLIKE;
+"CONVEX_INDEXED",CONVEX_INDEXED;
+"CONVEX_INTER",CONVEX_INTER;
+"CONVEX_INTERIOR",CONVEX_INTERIOR;
+"CONVEX_INTERIOR_CLOSURE",CONVEX_INTERIOR_CLOSURE;
+"CONVEX_INTERS",CONVEX_INTERS;
+"CONVEX_INTERVAL",CONVEX_INTERVAL;
+"CONVEX_LINEAR_IMAGE",CONVEX_LINEAR_IMAGE;
+"CONVEX_LINEAR_IMAGE_EQ",CONVEX_LINEAR_IMAGE_EQ;
+"CONVEX_LINEAR_PREIMAGE",CONVEX_LINEAR_PREIMAGE;
+"CONVEX_LOCAL_GLOBAL_MINIMUM",CONVEX_LOCAL_GLOBAL_MINIMUM;
+"CONVEX_LOWER",CONVEX_LOWER;
+"CONVEX_LOWER_SEGMENT",CONVEX_LOWER_SEGMENT;
+"CONVEX_MAX",CONVEX_MAX;
+"CONVEX_NEGATIONS",CONVEX_NEGATIONS;
+"CONVEX_NORM",CONVEX_NORM;
+"CONVEX_ON_BOUNDED_CONTINUOUS",CONVEX_ON_BOUNDED_CONTINUOUS;
+"CONVEX_ON_COMPOSE_LINEAR",CONVEX_ON_COMPOSE_LINEAR;
+"CONVEX_ON_CONTINUOUS",CONVEX_ON_CONTINUOUS;
+"CONVEX_ON_CONVEX_HULL_BOUND",CONVEX_ON_CONVEX_HULL_BOUND;
+"CONVEX_ON_DERIVATIVES",CONVEX_ON_DERIVATIVES;
+"CONVEX_ON_DERIVATIVES_IMP",CONVEX_ON_DERIVATIVES_IMP;
+"CONVEX_ON_DERIVATIVE_SECANT",CONVEX_ON_DERIVATIVE_SECANT;
+"CONVEX_ON_DERIVATIVE_SECANT_IMP",CONVEX_ON_DERIVATIVE_SECANT_IMP;
+"CONVEX_ON_EPIGRAPH_SLICE_LE",CONVEX_ON_EPIGRAPH_SLICE_LE;
+"CONVEX_ON_EPIGRAPH_SLICE_LT",CONVEX_ON_EPIGRAPH_SLICE_LT;
+"CONVEX_ON_JENSEN",CONVEX_ON_JENSEN;
+"CONVEX_ON_LEFT_SECANT",CONVEX_ON_LEFT_SECANT;
+"CONVEX_ON_LEFT_SECANT_MUL",CONVEX_ON_LEFT_SECANT_MUL;
+"CONVEX_ON_RIGHT_SECANT",CONVEX_ON_RIGHT_SECANT;
+"CONVEX_ON_RIGHT_SECANT_MUL",CONVEX_ON_RIGHT_SECANT_MUL;
+"CONVEX_ON_SECANT_DERIVATIVE",CONVEX_ON_SECANT_DERIVATIVE;
+"CONVEX_ON_SECANT_DERIVATIVE_IMP",CONVEX_ON_SECANT_DERIVATIVE_IMP;
+"CONVEX_ON_SUBSET",CONVEX_ON_SUBSET;
+"CONVEX_ON_TRANSLATION",CONVEX_ON_TRANSLATION;
+"CONVEX_PCROSS",CONVEX_PCROSS;
+"CONVEX_PCROSS_EQ",CONVEX_PCROSS_EQ;
+"CONVEX_POSITIVE_ORTHANT",CONVEX_POSITIVE_ORTHANT;
+"CONVEX_RELATIVE_INTERIOR",CONVEX_RELATIVE_INTERIOR;
+"CONVEX_RELATIVE_INTERIOR_CLOSURE",CONVEX_RELATIVE_INTERIOR_CLOSURE;
+"CONVEX_SAME_RELATIVE_INTERIOR_CLOSURE",CONVEX_SAME_RELATIVE_INTERIOR_CLOSURE;
+"CONVEX_SAME_RELATIVE_INTERIOR_CLOSURE_STRADDLE",CONVEX_SAME_RELATIVE_INTERIOR_CLOSURE_STRADDLE;
+"CONVEX_SCALING",CONVEX_SCALING;
+"CONVEX_SCALING_EQ",CONVEX_SCALING_EQ;
+"CONVEX_SEGMENT",CONVEX_SEGMENT;
+"CONVEX_SEMIOPEN_SEGMENT",CONVEX_SEMIOPEN_SEGMENT;
+"CONVEX_SIMPLEX",CONVEX_SIMPLEX;
+"CONVEX_SING",CONVEX_SING;
+"CONVEX_SPAN",CONVEX_SPAN;
+"CONVEX_STANDARD_HYPERPLANE",CONVEX_STANDARD_HYPERPLANE;
+"CONVEX_SUMS",CONVEX_SUMS;
+"CONVEX_TRANSLATION",CONVEX_TRANSLATION;
+"CONVEX_TRANSLATION_EQ",CONVEX_TRANSLATION_EQ;
+"CONVEX_UNIV",CONVEX_UNIV;
+"CONVEX_VSUM",CONVEX_VSUM;
+"CONVEX_VSUM_STRONG",CONVEX_VSUM_STRONG;
+"COPLANAR_2",COPLANAR_2;
+"COPLANAR_3",COPLANAR_3;
+"COPLANAR_AFFINE_HULL_COPLANAR",COPLANAR_AFFINE_HULL_COPLANAR;
+"COPLANAR_EMPTY",COPLANAR_EMPTY;
+"COPLANAR_LINEAR_IMAGE",COPLANAR_LINEAR_IMAGE;
+"COPLANAR_LINEAR_IMAGE_EQ",COPLANAR_LINEAR_IMAGE_EQ;
+"COPLANAR_SING",COPLANAR_SING;
+"COPLANAR_SMALL",COPLANAR_SMALL;
+"COPLANAR_SUBSET",COPLANAR_SUBSET;
+"COPLANAR_TRANSLATION",COPLANAR_TRANSLATION;
+"COPLANAR_TRANSLATION_EQ",COPLANAR_TRANSLATION_EQ;
+"COSMALL_APPROXIMATION",COSMALL_APPROXIMATION;
+"COUNTABLE",COUNTABLE;
+"COUNTABLE_ALT",COUNTABLE_ALT;
+"COUNTABLE_AS_IMAGE",COUNTABLE_AS_IMAGE;
+"COUNTABLE_AS_IMAGE_SUBSET",COUNTABLE_AS_IMAGE_SUBSET;
+"COUNTABLE_AS_IMAGE_SUBSET_EQ",COUNTABLE_AS_IMAGE_SUBSET_EQ;
+"COUNTABLE_AS_INJECTIVE_IMAGE",COUNTABLE_AS_INJECTIVE_IMAGE;
+"COUNTABLE_CARD_MUL",COUNTABLE_CARD_MUL;
+"COUNTABLE_CARD_MUL_EQ",COUNTABLE_CARD_MUL_EQ;
+"COUNTABLE_CART",COUNTABLE_CART;
+"COUNTABLE_CASES",COUNTABLE_CASES;
+"COUNTABLE_COMPONENTS",COUNTABLE_COMPONENTS;
+"COUNTABLE_CROSS",COUNTABLE_CROSS;
+"COUNTABLE_DELETE",COUNTABLE_DELETE;
+"COUNTABLE_DIFF_FINITE",COUNTABLE_DIFF_FINITE;
+"COUNTABLE_DISJOINT_OPEN_SUBSETS",COUNTABLE_DISJOINT_OPEN_SUBSETS;
+"COUNTABLE_ELEMENTARY_DIVISION",COUNTABLE_ELEMENTARY_DIVISION;
+"COUNTABLE_EMPTY",COUNTABLE_EMPTY;
+"COUNTABLE_EMPTY_INTERIOR",COUNTABLE_EMPTY_INTERIOR;
+"COUNTABLE_FINITE_SUBSETS",COUNTABLE_FINITE_SUBSETS;
+"COUNTABLE_IMAGE",COUNTABLE_IMAGE;
+"COUNTABLE_IMAGE_INJ",COUNTABLE_IMAGE_INJ;
+"COUNTABLE_IMAGE_INJ_EQ",COUNTABLE_IMAGE_INJ_EQ;
+"COUNTABLE_IMAGE_INJ_GENERAL",COUNTABLE_IMAGE_INJ_GENERAL;
+"COUNTABLE_IMP_CARD_LT_REAL",COUNTABLE_IMP_CARD_LT_REAL;
+"COUNTABLE_IMP_DISCONNECTED",COUNTABLE_IMP_DISCONNECTED;
+"COUNTABLE_INSERT",COUNTABLE_INSERT;
+"COUNTABLE_INTEGER",COUNTABLE_INTEGER;
+"COUNTABLE_INTEGER_COORDINATES",COUNTABLE_INTEGER_COORDINATES;
+"COUNTABLE_INTER",COUNTABLE_INTER;
+"COUNTABLE_LIST",COUNTABLE_LIST;
+"COUNTABLE_LIST_GEN",COUNTABLE_LIST_GEN;
+"COUNTABLE_NON_CONDENSATION_POINTS",COUNTABLE_NON_CONDENSATION_POINTS;
+"COUNTABLE_OPEN_INTERVAL",COUNTABLE_OPEN_INTERVAL;
+"COUNTABLE_PCROSS",COUNTABLE_PCROSS;
+"COUNTABLE_PCROSS_EQ",COUNTABLE_PCROSS_EQ;
+"COUNTABLE_PRODUCT_DEPENDENT",COUNTABLE_PRODUCT_DEPENDENT;
+"COUNTABLE_RATIONAL",COUNTABLE_RATIONAL;
+"COUNTABLE_RATIONAL_COORDINATES",COUNTABLE_RATIONAL_COORDINATES;
+"COUNTABLE_RESTRICT",COUNTABLE_RESTRICT;
+"COUNTABLE_SING",COUNTABLE_SING;
+"COUNTABLE_SUBSET",COUNTABLE_SUBSET;
+"COUNTABLE_SUBSET_IMAGE",COUNTABLE_SUBSET_IMAGE;
+"COUNTABLE_UNION",COUNTABLE_UNION;
+"COUNTABLE_UNIONS",COUNTABLE_UNIONS;
+"COUNTABLE_UNION_IMP",COUNTABLE_UNION_IMP;
+"COVERING_LEMMA",COVERING_LEMMA;
+"COVERING_SPACE_CLOSED_MAP",COVERING_SPACE_CLOSED_MAP;
+"COVERING_SPACE_COMPACT",COVERING_SPACE_COMPACT;
+"COVERING_SPACE_COUNTABLE_SHEETS",COVERING_SPACE_COUNTABLE_SHEETS;
+"COVERING_SPACE_FIBRE_NO_LIMPT",COVERING_SPACE_FIBRE_NO_LIMPT;
+"COVERING_SPACE_FINITE_EQ_COMPACT_FIBRE",COVERING_SPACE_FINITE_EQ_COMPACT_FIBRE;
+"COVERING_SPACE_FINITE_SHEETS",COVERING_SPACE_FINITE_SHEETS;
+"COVERING_SPACE_FINITE_SHEETS_EQ_CLOSED_MAP",COVERING_SPACE_FINITE_SHEETS_EQ_CLOSED_MAP;
+"COVERING_SPACE_FINITE_SHEETS_EQ_CLOSED_MAP_STRONG",COVERING_SPACE_FINITE_SHEETS_EQ_CLOSED_MAP_STRONG;
+"COVERING_SPACE_FINITE_SHEETS_EQ_PROPER_MAP",COVERING_SPACE_FINITE_SHEETS_EQ_PROPER_MAP;
+"COVERING_SPACE_HOMEOMORPHISM",COVERING_SPACE_HOMEOMORPHISM;
+"COVERING_SPACE_IMP_CONTINUOUS",COVERING_SPACE_IMP_CONTINUOUS;
+"COVERING_SPACE_IMP_SURJECTIVE",COVERING_SPACE_IMP_SURJECTIVE;
+"COVERING_SPACE_INESSENTIAL_LOOP_LIFT_IS_LOOP",COVERING_SPACE_INESSENTIAL_LOOP_LIFT_IS_LOOP;
+"COVERING_SPACE_INJECTIVE",COVERING_SPACE_INJECTIVE;
+"COVERING_SPACE_LIFT",COVERING_SPACE_LIFT;
+"COVERING_SPACE_LIFT_GENERAL",COVERING_SPACE_LIFT_GENERAL;
+"COVERING_SPACE_LIFT_HOMOTOPIC_FUNCTION",COVERING_SPACE_LIFT_HOMOTOPIC_FUNCTION;
+"COVERING_SPACE_LIFT_HOMOTOPIC_PATH",COVERING_SPACE_LIFT_HOMOTOPIC_PATH;
+"COVERING_SPACE_LIFT_HOMOTOPIC_PATHS",COVERING_SPACE_LIFT_HOMOTOPIC_PATHS;
+"COVERING_SPACE_LIFT_HOMOTOPY",COVERING_SPACE_LIFT_HOMOTOPY;
+"COVERING_SPACE_LIFT_HOMOTOPY_ALT",COVERING_SPACE_LIFT_HOMOTOPY_ALT;
+"COVERING_SPACE_LIFT_INESSENTIAL_FUNCTION",COVERING_SPACE_LIFT_INESSENTIAL_FUNCTION;
+"COVERING_SPACE_LIFT_PATH",COVERING_SPACE_LIFT_PATH;
+"COVERING_SPACE_LIFT_PATH_STRONG",COVERING_SPACE_LIFT_PATH_STRONG;
+"COVERING_SPACE_LIFT_STRONG",COVERING_SPACE_LIFT_STRONG;
+"COVERING_SPACE_LIFT_STRONGER",COVERING_SPACE_LIFT_STRONGER;
+"COVERING_SPACE_LIFT_UNIQUE",COVERING_SPACE_LIFT_UNIQUE;
+"COVERING_SPACE_LIFT_UNIQUE_GEN",COVERING_SPACE_LIFT_UNIQUE_GEN;
+"COVERING_SPACE_LIFT_UNIQUE_IDENTITY",COVERING_SPACE_LIFT_UNIQUE_IDENTITY;
+"COVERING_SPACE_LOCALLY",COVERING_SPACE_LOCALLY;
+"COVERING_SPACE_LOCALLY_CONNECTED",COVERING_SPACE_LOCALLY_CONNECTED;
+"COVERING_SPACE_LOCALLY_PATH_CONNECTED",COVERING_SPACE_LOCALLY_PATH_CONNECTED;
+"COVERING_SPACE_LOCAL_HOMEOMORPHISM",COVERING_SPACE_LOCAL_HOMEOMORPHISM;
+"COVERING_SPACE_LOCAL_HOMEOMORPHISM_ALT",COVERING_SPACE_LOCAL_HOMEOMORPHISM_ALT;
+"COVERING_SPACE_MONODROMY",COVERING_SPACE_MONODROMY;
+"COVERING_SPACE_OPEN_MAP",COVERING_SPACE_OPEN_MAP;
+"COVERING_SPACE_QUOTIENT_MAP",COVERING_SPACE_QUOTIENT_MAP;
+"COVERING_SPACE_SIMPLY_CONNECTED_LOOP_LIFT_IS_LOOP",COVERING_SPACE_SIMPLY_CONNECTED_LOOP_LIFT_IS_LOOP;
+"CRAMER",CRAMER;
+"CRAMER_LEMMA",CRAMER_LEMMA;
+"CRAMER_LEMMA_TRANSP",CRAMER_LEMMA_TRANSP;
+"CRAMER_MATRIX_LEFT",CRAMER_MATRIX_LEFT;
+"CRAMER_MATRIX_LEFT_INVERSE",CRAMER_MATRIX_LEFT_INVERSE;
+"CRAMER_MATRIX_RIGHT",CRAMER_MATRIX_RIGHT;
+"CRAMER_MATRIX_RIGHT_INVERSE",CRAMER_MATRIX_RIGHT_INVERSE;
+"CROSS",CROSS;
+"CROSS_EQ_EMPTY",CROSS_EQ_EMPTY;
+"CURRY_DEF",CURRY_DEF;
+"DECIMAL",DECIMAL;
+"DECOMPOSITION",DECOMPOSITION;
+"DECREASING_BOUNDED_VARIATION",DECREASING_BOUNDED_VARIATION;
+"DECREASING_CLOSED_NEST",DECREASING_CLOSED_NEST;
+"DECREASING_CLOSED_NEST_SING",DECREASING_CLOSED_NEST_SING;
+"DECREASING_LEFT_LIMIT_1",DECREASING_LEFT_LIMIT_1;
+"DECREASING_RIGHT_LIMIT_1",DECREASING_RIGHT_LIMIT_1;
+"DECREASING_VECTOR_VARIATION",DECREASING_VECTOR_VARIATION;
+"DELETE",DELETE;
+"DELETE_COMM",DELETE_COMM;
+"DELETE_DELETE",DELETE_DELETE;
+"DELETE_INSERT",DELETE_INSERT;
+"DELETE_INTER",DELETE_INTER;
+"DELETE_NON_ELEMENT",DELETE_NON_ELEMENT;
+"DELETE_SUBSET",DELETE_SUBSET;
+"DENSE_ACCESSIBLE_FRONTIER_POINTS",DENSE_ACCESSIBLE_FRONTIER_POINTS;
+"DENSE_ACCESSIBLE_FRONTIER_POINTS_CONNECTED",DENSE_ACCESSIBLE_FRONTIER_POINTS_CONNECTED;
+"DENSE_ACCESSIBLE_FRONTIER_POINT_PAIRS",DENSE_ACCESSIBLE_FRONTIER_POINT_PAIRS;
+"DEPENDENT_2",DEPENDENT_2;
+"DEPENDENT_3",DEPENDENT_3;
+"DEPENDENT_AFFINE_DEPENDENT_CASES",DEPENDENT_AFFINE_DEPENDENT_CASES;
+"DEPENDENT_BIGGERSET",DEPENDENT_BIGGERSET;
+"DEPENDENT_BIGGERSET_GENERAL",DEPENDENT_BIGGERSET_GENERAL;
+"DEPENDENT_EXPLICIT",DEPENDENT_EXPLICIT;
+"DEPENDENT_FINITE",DEPENDENT_FINITE;
+"DEPENDENT_IMP_AFFINE_DEPENDENT",DEPENDENT_IMP_AFFINE_DEPENDENT;
+"DEPENDENT_LINEAR_IMAGE",DEPENDENT_LINEAR_IMAGE;
+"DEPENDENT_LINEAR_IMAGE_EQ",DEPENDENT_LINEAR_IMAGE_EQ;
+"DEPENDENT_MONO",DEPENDENT_MONO;
+"DEPENDENT_SING",DEPENDENT_SING;
+"DEST_MK_MULTIVECTOR",DEST_MK_MULTIVECTOR;
+"DEST_REC_INJ",DEST_REC_INJ;
+"DET_0",DET_0;
+"DET_1",DET_1;
+"DET_2",DET_2;
+"DET_3",DET_3;
+"DET_4",DET_4;
+"DET_CMUL",DET_CMUL;
+"DET_COFACTOR",DET_COFACTOR;
+"DET_COFACTOR_EXPANSION",DET_COFACTOR_EXPANSION;
+"DET_DEPENDENT_COLUMNS",DET_DEPENDENT_COLUMNS;
+"DET_DEPENDENT_ROWS",DET_DEPENDENT_ROWS;
+"DET_DIAGONAL",DET_DIAGONAL;
+"DET_EQ_0",DET_EQ_0;
+"DET_EQ_0_RANK",DET_EQ_0_RANK;
+"DET_I",DET_I;
+"DET_IDENTICAL_COLUMNS",DET_IDENTICAL_COLUMNS;
+"DET_IDENTICAL_ROWS",DET_IDENTICAL_ROWS;
+"DET_LINEAR_ROWS_VSUM",DET_LINEAR_ROWS_VSUM;
+"DET_LINEAR_ROWS_VSUM_LEMMA",DET_LINEAR_ROWS_VSUM_LEMMA;
+"DET_LINEAR_ROW_VSUM",DET_LINEAR_ROW_VSUM;
+"DET_LOWERTRIANGULAR",DET_LOWERTRIANGULAR;
+"DET_MATRIX_EQ_0",DET_MATRIX_EQ_0;
+"DET_MATRIX_EQ_0_LEFT",DET_MATRIX_EQ_0_LEFT;
+"DET_MATRIX_EQ_0_RIGHT",DET_MATRIX_EQ_0_RIGHT;
+"DET_MATRIX_REFLECT_ALONG",DET_MATRIX_REFLECT_ALONG;
+"DET_MUL",DET_MUL;
+"DET_NEG",DET_NEG;
+"DET_ORTHOGONAL_MATRIX",DET_ORTHOGONAL_MATRIX;
+"DET_PERMUTE_COLUMNS",DET_PERMUTE_COLUMNS;
+"DET_PERMUTE_ROWS",DET_PERMUTE_ROWS;
+"DET_ROWS_MUL",DET_ROWS_MUL;
+"DET_ROW_ADD",DET_ROW_ADD;
+"DET_ROW_MUL",DET_ROW_MUL;
+"DET_ROW_OPERATION",DET_ROW_OPERATION;
+"DET_ROW_SPAN",DET_ROW_SPAN;
+"DET_TRANSP",DET_TRANSP;
+"DET_UPPERTRIANGULAR",DET_UPPERTRIANGULAR;
+"DET_ZERO_COLUMN",DET_ZERO_COLUMN;
+"DET_ZERO_ROW",DET_ZERO_ROW;
+"DE_MORGAN_THM",DE_MORGAN_THM;
+"DIAMETER_ATTAINED_FRONTIER",DIAMETER_ATTAINED_FRONTIER;
+"DIAMETER_ATTAINED_RELATIVE_FRONTIER",DIAMETER_ATTAINED_RELATIVE_FRONTIER;
+"DIAMETER_BALL",DIAMETER_BALL;
+"DIAMETER_BOUNDED",DIAMETER_BOUNDED;
+"DIAMETER_BOUNDED_BOUND",DIAMETER_BOUNDED_BOUND;
+"DIAMETER_BOUNDED_BOUND_LT",DIAMETER_BOUNDED_BOUND_LT;
+"DIAMETER_CBALL",DIAMETER_CBALL;
+"DIAMETER_CLOSURE",DIAMETER_CLOSURE;
+"DIAMETER_COMPACT_ATTAINED",DIAMETER_COMPACT_ATTAINED;
+"DIAMETER_CONVEX_HULL",DIAMETER_CONVEX_HULL;
+"DIAMETER_EMPTY",DIAMETER_EMPTY;
+"DIAMETER_EQ_0",DIAMETER_EQ_0;
+"DIAMETER_FRONTIER",DIAMETER_FRONTIER;
+"DIAMETER_INTERVAL",DIAMETER_INTERVAL;
+"DIAMETER_LE",DIAMETER_LE;
+"DIAMETER_LINEAR_IMAGE",DIAMETER_LINEAR_IMAGE;
+"DIAMETER_POS_LE",DIAMETER_POS_LE;
+"DIAMETER_RELATIVE_FRONTIER",DIAMETER_RELATIVE_FRONTIER;
+"DIAMETER_SIMPLEX",DIAMETER_SIMPLEX;
+"DIAMETER_SING",DIAMETER_SING;
+"DIAMETER_SPHERE",DIAMETER_SPHERE;
+"DIAMETER_SUBSET",DIAMETER_SUBSET;
+"DIAMETER_SUBSET_CBALL",DIAMETER_SUBSET_CBALL;
+"DIAMETER_SUBSET_CBALL_NONEMPTY",DIAMETER_SUBSET_CBALL_NONEMPTY;
+"DIAMETER_TRANSLATION",DIAMETER_TRANSLATION;
+"DIFF",DIFF;
+"DIFFERENTIABLE_ADD",DIFFERENTIABLE_ADD;
+"DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON",DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON;
+"DIFFERENTIABLE_AT_LIFT_DOT2",DIFFERENTIABLE_AT_LIFT_DOT2;
+"DIFFERENTIABLE_AT_WITHIN",DIFFERENTIABLE_AT_WITHIN;
+"DIFFERENTIABLE_BOUND",DIFFERENTIABLE_BOUND;
+"DIFFERENTIABLE_CHAIN_AT",DIFFERENTIABLE_CHAIN_AT;
+"DIFFERENTIABLE_CHAIN_WITHIN",DIFFERENTIABLE_CHAIN_WITHIN;
+"DIFFERENTIABLE_CMUL",DIFFERENTIABLE_CMUL;
+"DIFFERENTIABLE_COMPONENTWISE_AT",DIFFERENTIABLE_COMPONENTWISE_AT;
+"DIFFERENTIABLE_COMPONENTWISE_WITHIN",DIFFERENTIABLE_COMPONENTWISE_WITHIN;
+"DIFFERENTIABLE_CONST",DIFFERENTIABLE_CONST;
+"DIFFERENTIABLE_ID",DIFFERENTIABLE_ID;
+"DIFFERENTIABLE_IMP_CONTINUOUS_AT",DIFFERENTIABLE_IMP_CONTINUOUS_AT;
+"DIFFERENTIABLE_IMP_CONTINUOUS_ON",DIFFERENTIABLE_IMP_CONTINUOUS_ON;
+"DIFFERENTIABLE_IMP_CONTINUOUS_WITHIN",DIFFERENTIABLE_IMP_CONTINUOUS_WITHIN;
+"DIFFERENTIABLE_LIFT_COMPONENT",DIFFERENTIABLE_LIFT_COMPONENT;
+"DIFFERENTIABLE_LINEAR",DIFFERENTIABLE_LINEAR;
+"DIFFERENTIABLE_MUL_AT",DIFFERENTIABLE_MUL_AT;
+"DIFFERENTIABLE_MUL_WITHIN",DIFFERENTIABLE_MUL_WITHIN;
+"DIFFERENTIABLE_NEG",DIFFERENTIABLE_NEG;
+"DIFFERENTIABLE_ON_ADD",DIFFERENTIABLE_ON_ADD;
+"DIFFERENTIABLE_ON_COMPOSE",DIFFERENTIABLE_ON_COMPOSE;
+"DIFFERENTIABLE_ON_CONST",DIFFERENTIABLE_ON_CONST;
+"DIFFERENTIABLE_ON_EMPTY",DIFFERENTIABLE_ON_EMPTY;
+"DIFFERENTIABLE_ON_EQ_DIFFERENTIABLE_AT",DIFFERENTIABLE_ON_EQ_DIFFERENTIABLE_AT;
+"DIFFERENTIABLE_ON_ID",DIFFERENTIABLE_ON_ID;
+"DIFFERENTIABLE_ON_LIFT_DOT2",DIFFERENTIABLE_ON_LIFT_DOT2;
+"DIFFERENTIABLE_ON_LINEAR",DIFFERENTIABLE_ON_LINEAR;
+"DIFFERENTIABLE_ON_MUL",DIFFERENTIABLE_ON_MUL;
+"DIFFERENTIABLE_ON_NEG",DIFFERENTIABLE_ON_NEG;
+"DIFFERENTIABLE_ON_SQNORM",DIFFERENTIABLE_ON_SQNORM;
+"DIFFERENTIABLE_ON_SUB",DIFFERENTIABLE_ON_SUB;
+"DIFFERENTIABLE_ON_SUBSET",DIFFERENTIABLE_ON_SUBSET;
+"DIFFERENTIABLE_SQNORM_AT",DIFFERENTIABLE_SQNORM_AT;
+"DIFFERENTIABLE_SUB",DIFFERENTIABLE_SUB;
+"DIFFERENTIABLE_TRANSFORM_AT",DIFFERENTIABLE_TRANSFORM_AT;
+"DIFFERENTIABLE_TRANSFORM_WITHIN",DIFFERENTIABLE_TRANSFORM_WITHIN;
+"DIFFERENTIABLE_VSUM",DIFFERENTIABLE_VSUM;
+"DIFFERENTIABLE_VSUM_NUMSEG",DIFFERENTIABLE_VSUM_NUMSEG;
+"DIFFERENTIABLE_WITHIN_LIFT_DOT2",DIFFERENTIABLE_WITHIN_LIFT_DOT2;
+"DIFFERENTIABLE_WITHIN_OPEN",DIFFERENTIABLE_WITHIN_OPEN;
+"DIFFERENTIABLE_WITHIN_SUBSET",DIFFERENTIABLE_WITHIN_SUBSET;
+"DIFFERENTIAL_COMPONENT_NEG_AT_MAXIMUM",DIFFERENTIAL_COMPONENT_NEG_AT_MAXIMUM;
+"DIFFERENTIAL_COMPONENT_POS_AT_MINIMUM",DIFFERENTIAL_COMPONENT_POS_AT_MINIMUM;
+"DIFFERENTIAL_COMPONENT_ZERO_AT_MAXMIN",DIFFERENTIAL_COMPONENT_ZERO_AT_MAXMIN;
+"DIFFERENTIAL_ZERO_MAXMIN",DIFFERENTIAL_ZERO_MAXMIN;
+"DIFFERENTIAL_ZERO_MAXMIN_COMPONENT",DIFFERENTIAL_ZERO_MAXMIN_COMPONENT;
+"DIFFERENT_NORM_3_COLLINEAR_POINTS",DIFFERENT_NORM_3_COLLINEAR_POINTS;
+"DIFFS_AFFINE_HULL_SPAN",DIFFS_AFFINE_HULL_SPAN;
+"DIFF_CHAIN_AT",DIFF_CHAIN_AT;
+"DIFF_CHAIN_WITHIN",DIFF_CHAIN_WITHIN;
+"DIFF_DIFF",DIFF_DIFF;
+"DIFF_EMPTY",DIFF_EMPTY;
+"DIFF_EQ_EMPTY",DIFF_EQ_EMPTY;
+"DIFF_INSERT",DIFF_INSERT;
+"DIFF_INTERS",DIFF_INTERS;
+"DIFF_UNIONS",DIFF_UNIONS;
+"DIFF_UNIONS_NONEMPTY",DIFF_UNIONS_NONEMPTY;
+"DIFF_UNIV",DIFF_UNIV;
+"DIMINDEX_1",DIMINDEX_1;
+"DIMINDEX_2",DIMINDEX_2;
+"DIMINDEX_3",DIMINDEX_3;
+"DIMINDEX_4",DIMINDEX_4;
+"DIMINDEX_FINITE_IMAGE",DIMINDEX_FINITE_IMAGE;
+"DIMINDEX_FINITE_SUM",DIMINDEX_FINITE_SUM;
+"DIMINDEX_GE_1",DIMINDEX_GE_1;
+"DIMINDEX_HAS_SIZE_FINITE_SUM",DIMINDEX_HAS_SIZE_FINITE_SUM;
+"DIMINDEX_MULTIVECTOR",DIMINDEX_MULTIVECTOR;
+"DIMINDEX_NONZERO",DIMINDEX_NONZERO;
+"DIMINDEX_UNIQUE",DIMINDEX_UNIQUE;
+"DIMINDEX_UNIV",DIMINDEX_UNIV;
+"DIM_CLOSURE",DIM_CLOSURE;
+"DIM_EMPTY",DIM_EMPTY;
+"DIM_EQ_0",DIM_EQ_0;
+"DIM_EQ_CARD",DIM_EQ_CARD;
+"DIM_EQ_FULL",DIM_EQ_FULL;
+"DIM_EQ_HYPERPLANE",DIM_EQ_HYPERPLANE;
+"DIM_EQ_SPAN",DIM_EQ_SPAN;
+"DIM_HYPERPLANE",DIM_HYPERPLANE;
+"DIM_IMAGE_KERNEL",DIM_IMAGE_KERNEL;
+"DIM_IMAGE_KERNEL_GEN",DIM_IMAGE_KERNEL_GEN;
+"DIM_INJECTIVE_LINEAR_IMAGE",DIM_INJECTIVE_LINEAR_IMAGE;
+"DIM_INSERT",DIM_INSERT;
+"DIM_INSERT_0",DIM_INSERT_0;
+"DIM_KERNEL_COMPOSE",DIM_KERNEL_COMPOSE;
+"DIM_LE_CARD",DIM_LE_CARD;
+"DIM_LINEAR_IMAGE_LE",DIM_LINEAR_IMAGE_LE;
+"DIM_OPEN",DIM_OPEN;
+"DIM_OPEN_IN",DIM_OPEN_IN;
+"DIM_ORTHOGONAL_SUM",DIM_ORTHOGONAL_SUM;
+"DIM_PCROSS",DIM_PCROSS;
+"DIM_PCROSS_STRONG",DIM_PCROSS_STRONG;
+"DIM_PSUBSET",DIM_PSUBSET;
+"DIM_ROWS_LE_DIM_COLUMNS",DIM_ROWS_LE_DIM_COLUMNS;
+"DIM_SING",DIM_SING;
+"DIM_SPAN",DIM_SPAN;
+"DIM_SPECIAL_HYPERPLANE",DIM_SPECIAL_HYPERPLANE;
+"DIM_SPECIAL_SUBSPACE",DIM_SPECIAL_SUBSPACE;
+"DIM_SUBSET",DIM_SUBSET;
+"DIM_SUBSET_UNIV",DIM_SUBSET_UNIV;
+"DIM_SUBSPACE_ORTHOGONAL_TO_VECTORS",DIM_SUBSPACE_ORTHOGONAL_TO_VECTORS;
+"DIM_SUBSTANDARD",DIM_SUBSTANDARD;
+"DIM_SUMS_INTER",DIM_SUMS_INTER;
+"DIM_UNIQUE",DIM_UNIQUE;
+"DIM_UNIV",DIM_UNIV;
+"DINI",DINI;
+"DISCRETE_BOUNDED_IMP_FINITE",DISCRETE_BOUNDED_IMP_FINITE;
+"DISCRETE_IMP_CLOSED",DISCRETE_IMP_CLOSED;
+"DISCRETE_IMP_COUNTABLE",DISCRETE_IMP_COUNTABLE;
+"DISJOINT",DISJOINT;
+"DISJOINT_AFFINE_HULL",DISJOINT_AFFINE_HULL;
+"DISJOINT_DELETE_SYM",DISJOINT_DELETE_SYM;
+"DISJOINT_EMPTY",DISJOINT_EMPTY;
+"DISJOINT_EMPTY_REFL",DISJOINT_EMPTY_REFL;
+"DISJOINT_INSERT",DISJOINT_INSERT;
+"DISJOINT_INTERVAL",DISJOINT_INTERVAL;
+"DISJOINT_INTERVAL_1",DISJOINT_INTERVAL_1;
+"DISJOINT_NUMSEG",DISJOINT_NUMSEG;
+"DISJOINT_SYM",DISJOINT_SYM;
+"DISJOINT_UNION",DISJOINT_UNION;
+"DISJ_ACI",DISJ_ACI;
+"DISJ_ASSOC",DISJ_ASSOC;
+"DISJ_SYM",DISJ_SYM;
+"DISTANCE_ATTAINS_INF",DISTANCE_ATTAINS_INF;
+"DISTANCE_ATTAINS_SUP",DISTANCE_ATTAINS_SUP;
+"DIST_0",DIST_0;
+"DIST_ADD2",DIST_ADD2;
+"DIST_ADD2_REV",DIST_ADD2_REV;
+"DIST_ADDBOUND",DIST_ADDBOUND;
+"DIST_CLOSEST_POINT_LIPSCHITZ",DIST_CLOSEST_POINT_LIPSCHITZ;
+"DIST_ELIM_THM",DIST_ELIM_THM;
+"DIST_EQ",DIST_EQ;
+"DIST_EQ_0",DIST_EQ_0;
+"DIST_FSTCART",DIST_FSTCART;
+"DIST_INCREASES_ONLINE",DIST_INCREASES_ONLINE;
+"DIST_IN_CLOSED_SEGMENT",DIST_IN_CLOSED_SEGMENT;
+"DIST_IN_OPEN_SEGMENT",DIST_IN_OPEN_SEGMENT;
+"DIST_LADD",DIST_LADD;
+"DIST_LADD_0",DIST_LADD_0;
+"DIST_LE_0",DIST_LE_0;
+"DIST_LE_CASES",DIST_LE_CASES;
+"DIST_LIFT",DIST_LIFT;
+"DIST_LMUL",DIST_LMUL;
+"DIST_LZERO",DIST_LZERO;
+"DIST_MIDPOINT",DIST_MIDPOINT;
+"DIST_MUL",DIST_MUL;
+"DIST_NZ",DIST_NZ;
+"DIST_PASTECART_CANCEL",DIST_PASTECART_CANCEL;
+"DIST_POS_LE",DIST_POS_LE;
+"DIST_POS_LT",DIST_POS_LT;
+"DIST_RADD",DIST_RADD;
+"DIST_RADD_0",DIST_RADD_0;
+"DIST_REAL",DIST_REAL;
+"DIST_REFL",DIST_REFL;
+"DIST_RMUL",DIST_RMUL;
+"DIST_RZERO",DIST_RZERO;
+"DIST_SNDCART",DIST_SNDCART;
+"DIST_SYM",DIST_SYM;
+"DIST_TRIANGLE",DIST_TRIANGLE;
+"DIST_TRIANGLES_LE",DIST_TRIANGLES_LE;
+"DIST_TRIANGLE_ADD",DIST_TRIANGLE_ADD;
+"DIST_TRIANGLE_ADD_HALF",DIST_TRIANGLE_ADD_HALF;
+"DIST_TRIANGLE_ALT",DIST_TRIANGLE_ALT;
+"DIST_TRIANGLE_EQ",DIST_TRIANGLE_EQ;
+"DIST_TRIANGLE_HALF_L",DIST_TRIANGLE_HALF_L;
+"DIST_TRIANGLE_HALF_R",DIST_TRIANGLE_HALF_R;
+"DIST_TRIANGLE_LE",DIST_TRIANGLE_LE;
+"DIST_TRIANGLE_LT",DIST_TRIANGLE_LT;
+"DIVISION",DIVISION;
+"DIVISION_0",DIVISION_0;
+"DIVISION_COMMON_POINT_BOUND",DIVISION_COMMON_POINT_BOUND;
+"DIVISION_CONTAINS",DIVISION_CONTAINS;
+"DIVISION_DISJOINT_UNION",DIVISION_DISJOINT_UNION;
+"DIVISION_DOUBLESPLIT",DIVISION_DOUBLESPLIT;
+"DIVISION_INTER",DIVISION_INTER;
+"DIVISION_INTER_1",DIVISION_INTER_1;
+"DIVISION_OF",DIVISION_OF;
+"DIVISION_OF_AFFINITY",DIVISION_OF_AFFINITY;
+"DIVISION_OF_CLOSED",DIVISION_OF_CLOSED;
+"DIVISION_OF_CONTENT_0",DIVISION_OF_CONTENT_0;
+"DIVISION_OF_FINITE",DIVISION_OF_FINITE;
+"DIVISION_OF_NONTRIVIAL",DIVISION_OF_NONTRIVIAL;
+"DIVISION_OF_REFLECT",DIVISION_OF_REFLECT;
+"DIVISION_OF_SELF",DIVISION_OF_SELF;
+"DIVISION_OF_SING",DIVISION_OF_SING;
+"DIVISION_OF_SUBSET",DIVISION_OF_SUBSET;
+"DIVISION_OF_TAGGED_DIVISION",DIVISION_OF_TAGGED_DIVISION;
+"DIVISION_OF_TRANSLATION",DIVISION_OF_TRANSLATION;
+"DIVISION_OF_TRIVIAL",DIVISION_OF_TRIVIAL;
+"DIVISION_OF_UNIONS",DIVISION_OF_UNIONS;
+"DIVISION_OF_UNION_SELF",DIVISION_OF_UNION_SELF;
+"DIVISION_POINTS_FINITE",DIVISION_POINTS_FINITE;
+"DIVISION_POINTS_PSUBSET",DIVISION_POINTS_PSUBSET;
+"DIVISION_POINTS_SUBSET",DIVISION_POINTS_SUBSET;
+"DIVISION_SIMP",DIVISION_SIMP;
+"DIVISION_SPLIT",DIVISION_SPLIT;
+"DIVISION_SPLIT_LEFT_INJ",DIVISION_SPLIT_LEFT_INJ;
+"DIVISION_SPLIT_RIGHT_INJ",DIVISION_SPLIT_RIGHT_INJ;
+"DIVISION_UNION_INTERVALS_EXISTS",DIVISION_UNION_INTERVALS_EXISTS;
+"DIVMOD_ELIM_THM",DIVMOD_ELIM_THM;
+"DIVMOD_ELIM_THM'",DIVMOD_ELIM_THM';
+"DIVMOD_EXIST",DIVMOD_EXIST;
+"DIVMOD_EXIST_0",DIVMOD_EXIST_0;
+"DIVMOD_UNIQ",DIVMOD_UNIQ;
+"DIVMOD_UNIQ_LEMMA",DIVMOD_UNIQ_LEMMA;
+"DIV_0",DIV_0;
+"DIV_1",DIV_1;
+"DIV_ADD_MOD",DIV_ADD_MOD;
+"DIV_DIV",DIV_DIV;
+"DIV_EQ_0",DIV_EQ_0;
+"DIV_EQ_EXCLUSION",DIV_EQ_EXCLUSION;
+"DIV_LE",DIV_LE;
+"DIV_LE_EXCLUSION",DIV_LE_EXCLUSION;
+"DIV_LT",DIV_LT;
+"DIV_MOD",DIV_MOD;
+"DIV_MONO",DIV_MONO;
+"DIV_MONO2",DIV_MONO2;
+"DIV_MONO_LT",DIV_MONO_LT;
+"DIV_MULT",DIV_MULT;
+"DIV_MULT2",DIV_MULT2;
+"DIV_MULT_ADD",DIV_MULT_ADD;
+"DIV_MUL_LE",DIV_MUL_LE;
+"DIV_REFL",DIV_REFL;
+"DIV_UNIQ",DIV_UNIQ;
+"DOMINATED_CONVERGENCE",DOMINATED_CONVERGENCE;
+"DOMINATED_CONVERGENCE_ABSOLUTELY_INTEGRABLE",DOMINATED_CONVERGENCE_ABSOLUTELY_INTEGRABLE;
+"DOMINATED_CONVERGENCE_INTEGRABLE",DOMINATED_CONVERGENCE_INTEGRABLE;
+"DOT_1",DOT_1;
+"DOT_2",DOT_2;
+"DOT_3",DOT_3;
+"DOT_4",DOT_4;
+"DOT_BASIS",DOT_BASIS;
+"DOT_BASIS_BASIS",DOT_BASIS_BASIS;
+"DOT_BASIS_BASIS_UNEQUAL",DOT_BASIS_BASIS_UNEQUAL;
+"DOT_CAUCHY_SCHWARZ_EQUAL",DOT_CAUCHY_SCHWARZ_EQUAL;
+"DOT_EQ_0",DOT_EQ_0;
+"DOT_LADD",DOT_LADD;
+"DOT_LMUL",DOT_LMUL;
+"DOT_LMUL_MATRIX",DOT_LMUL_MATRIX;
+"DOT_LNEG",DOT_LNEG;
+"DOT_LSUB",DOT_LSUB;
+"DOT_LSUM",DOT_LSUM;
+"DOT_LZERO",DOT_LZERO;
+"DOT_MATRIX_PRODUCT",DOT_MATRIX_PRODUCT;
+"DOT_MATRIX_VECTOR_MUL",DOT_MATRIX_VECTOR_MUL;
+"DOT_NORM",DOT_NORM;
+"DOT_NORM_NEG",DOT_NORM_NEG;
+"DOT_NORM_SUB",DOT_NORM_SUB;
+"DOT_PASTECART",DOT_PASTECART;
+"DOT_POS_LE",DOT_POS_LE;
+"DOT_POS_LT",DOT_POS_LT;
+"DOT_RADD",DOT_RADD;
+"DOT_RMUL",DOT_RMUL;
+"DOT_RNEG",DOT_RNEG;
+"DOT_ROWVECTOR_COLUMNVECTOR",DOT_ROWVECTOR_COLUMNVECTOR;
+"DOT_RSUB",DOT_RSUB;
+"DOT_RSUM",DOT_RSUM;
+"DOT_RZERO",DOT_RZERO;
+"DOT_SQUARE_NORM",DOT_SQUARE_NORM;
+"DOT_SYM",DOT_SYM;
+"DROP_ADD",DROP_ADD;
+"DROP_CMUL",DROP_CMUL;
+"DROP_DIFFERENTIAL_NEG_AT_MAXIMUM",DROP_DIFFERENTIAL_NEG_AT_MAXIMUM;
+"DROP_DIFFERENTIAL_POS_AT_MINIMUM",DROP_DIFFERENTIAL_POS_AT_MINIMUM;
+"DROP_EQ",DROP_EQ;
+"DROP_EQ_0",DROP_EQ_0;
+"DROP_INDICATOR",DROP_INDICATOR;
+"DROP_INDICATOR_ABS_LE_1",DROP_INDICATOR_ABS_LE_1;
+"DROP_INDICATOR_LE_1",DROP_INDICATOR_LE_1;
+"DROP_INDICATOR_POS_LE",DROP_INDICATOR_POS_LE;
+"DROP_IN_IMAGE_DROP",DROP_IN_IMAGE_DROP;
+"DROP_LAMBDA",DROP_LAMBDA;
+"DROP_NEG",DROP_NEG;
+"DROP_SUB",DROP_SUB;
+"DROP_VEC",DROP_VEC;
+"DROP_VSUM",DROP_VSUM;
+"DROP_WLOG_LE",DROP_WLOG_LE;
+"DSUM_BOUND",DSUM_BOUND;
+"EDELSTEIN_FIX",EDELSTEIN_FIX;
+"EDGE_OF_IMP_SUBSET",EDGE_OF_IMP_SUBSET;
+"EDGE_OF_LINEAR_IMAGE",EDGE_OF_LINEAR_IMAGE;
+"EDGE_OF_TRANSLATION_EQ",EDGE_OF_TRANSLATION_EQ;
+"EL",EL;
+"ELEMENTARY_BOUNDED",ELEMENTARY_BOUNDED;
+"ELEMENTARY_COMPACT",ELEMENTARY_COMPACT;
+"ELEMENTARY_EMPTY",ELEMENTARY_EMPTY;
+"ELEMENTARY_INTER",ELEMENTARY_INTER;
+"ELEMENTARY_INTERS",ELEMENTARY_INTERS;
+"ELEMENTARY_INTERVAL",ELEMENTARY_INTERVAL;
+"ELEMENTARY_SUBSET_INTERVAL",ELEMENTARY_SUBSET_INTERVAL;
+"ELEMENTARY_UNION",ELEMENTARY_UNION;
+"ELEMENTARY_UNIONS_INTERVALS",ELEMENTARY_UNIONS_INTERVALS;
+"ELEMENTARY_UNION_INTERVAL",ELEMENTARY_UNION_INTERVAL;
+"ELEMENTARY_UNION_INTERVAL_STRONG",ELEMENTARY_UNION_INTERVAL_STRONG;
+"EL_APPEND",EL_APPEND;
+"EL_CONS",EL_CONS;
+"EL_MAP",EL_MAP;
+"EL_TL",EL_TL;
+"EMPTY",EMPTY;
+"EMPTY_AS_INTERVAL",EMPTY_AS_INTERVAL;
+"EMPTY_DELETE",EMPTY_DELETE;
+"EMPTY_DIFF",EMPTY_DIFF;
+"EMPTY_DIVISION_OF",EMPTY_DIVISION_OF;
+"EMPTY_EXPOSED_FACE_OF",EMPTY_EXPOSED_FACE_OF;
+"EMPTY_FACE_OF",EMPTY_FACE_OF;
+"EMPTY_GSPEC",EMPTY_GSPEC;
+"EMPTY_INTERIOR_AFFINE_HULL",EMPTY_INTERIOR_AFFINE_HULL;
+"EMPTY_INTERIOR_CONVEX_HULL",EMPTY_INTERIOR_CONVEX_HULL;
+"EMPTY_INTERIOR_FINITE",EMPTY_INTERIOR_FINITE;
+"EMPTY_INTERIOR_LOWDIM",EMPTY_INTERIOR_LOWDIM;
+"EMPTY_INTERIOR_SUBSET_HYPERPLANE",EMPTY_INTERIOR_SUBSET_HYPERPLANE;
+"EMPTY_NOT_UNIV",EMPTY_NOT_UNIV;
+"EMPTY_SUBSET",EMPTY_SUBSET;
+"EMPTY_UNION",EMPTY_UNION;
+"EMPTY_UNIONS",EMPTY_UNIONS;
+"ENDPOINTS_SHIFTPATH",ENDPOINTS_SHIFTPATH;
+"ENDS_IN_INTERVAL",ENDS_IN_INTERVAL;
+"ENDS_IN_SEGMENT",ENDS_IN_SEGMENT;
+"ENDS_IN_UNIT_INTERVAL",ENDS_IN_UNIT_INTERVAL;
+"ENDS_NOT_IN_SEGMENT",ENDS_NOT_IN_SEGMENT;
+"EPSILON_DELTA_MINIMAL",EPSILON_DELTA_MINIMAL;
+"EQUIINTEGRABLE_ADD",EQUIINTEGRABLE_ADD;
+"EQUIINTEGRABLE_CLOSED_INTERVAL_RESTRICTIONS",EQUIINTEGRABLE_CLOSED_INTERVAL_RESTRICTIONS;
+"EQUIINTEGRABLE_CMUL",EQUIINTEGRABLE_CMUL;
+"EQUIINTEGRABLE_DIVISION",EQUIINTEGRABLE_DIVISION;
+"EQUIINTEGRABLE_EQ",EQUIINTEGRABLE_EQ;
+"EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GE",EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GE;
+"EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GT",EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_GT;
+"EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LE",EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LE;
+"EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LT",EQUIINTEGRABLE_HALFSPACE_RESTRICTIONS_LT;
+"EQUIINTEGRABLE_LIMIT",EQUIINTEGRABLE_LIMIT;
+"EQUIINTEGRABLE_NEG",EQUIINTEGRABLE_NEG;
+"EQUIINTEGRABLE_ON_NULL",EQUIINTEGRABLE_ON_NULL;
+"EQUIINTEGRABLE_ON_SING",EQUIINTEGRABLE_ON_SING;
+"EQUIINTEGRABLE_ON_SPLIT",EQUIINTEGRABLE_ON_SPLIT;
+"EQUIINTEGRABLE_OPEN_INTERVAL_RESTRICTIONS",EQUIINTEGRABLE_OPEN_INTERVAL_RESTRICTIONS;
+"EQUIINTEGRABLE_REFLECT",EQUIINTEGRABLE_REFLECT;
+"EQUIINTEGRABLE_SUB",EQUIINTEGRABLE_SUB;
+"EQUIINTEGRABLE_SUBSET",EQUIINTEGRABLE_SUBSET;
+"EQUIINTEGRABLE_SUM",EQUIINTEGRABLE_SUM;
+"EQUIINTEGRABLE_UNIFORM_LIMIT",EQUIINTEGRABLE_UNIFORM_LIMIT;
+"EQUIINTEGRABLE_UNION",EQUIINTEGRABLE_UNION;
+"EQ_ADD_LCANCEL",EQ_ADD_LCANCEL;
+"EQ_ADD_LCANCEL_0",EQ_ADD_LCANCEL_0;
+"EQ_ADD_RCANCEL",EQ_ADD_RCANCEL;
+"EQ_ADD_RCANCEL_0",EQ_ADD_RCANCEL_0;
+"EQ_BALLS",EQ_BALLS;
+"EQ_C",EQ_C;
+"EQ_CLAUSES",EQ_CLAUSES;
+"EQ_C_BIJECTIONS",EQ_C_BIJECTIONS;
+"EQ_EXP",EQ_EXP;
+"EQ_EXT",EQ_EXT;
+"EQ_IMP",EQ_IMP;
+"EQ_IMP_LE",EQ_IMP_LE;
+"EQ_INTERVAL",EQ_INTERVAL;
+"EQ_INTERVAL_1",EQ_INTERVAL_1;
+"EQ_MULT_LCANCEL",EQ_MULT_LCANCEL;
+"EQ_MULT_RCANCEL",EQ_MULT_RCANCEL;
+"EQ_REFL",EQ_REFL;
+"EQ_SPAN_INSERT_EQ",EQ_SPAN_INSERT_EQ;
+"EQ_SYM",EQ_SYM;
+"EQ_SYM_EQ",EQ_SYM_EQ;
+"EQ_TRANS",EQ_TRANS;
+"EQ_UNIV",EQ_UNIV;
+"ETA_AX",ETA_AX;
+"EUCLIDEAN_SPACE_INFINITE",EUCLIDEAN_SPACE_INFINITE;
+"EULER_ROTATION_THEOREM",EULER_ROTATION_THEOREM;
+"EULER_ROTOINVERSION_THEOREM",EULER_ROTOINVERSION_THEOREM;
+"EVEN",EVEN;
+"EVENPERM_COMPOSE",EVENPERM_COMPOSE;
+"EVENPERM_I",EVENPERM_I;
+"EVENPERM_INVERSE",EVENPERM_INVERSE;
+"EVENPERM_SWAP",EVENPERM_SWAP;
+"EVENPERM_UNIQUE",EVENPERM_UNIQUE;
+"EVENTUALLY_AND",EVENTUALLY_AND;
+"EVENTUALLY_AT",EVENTUALLY_AT;
+"EVENTUALLY_AT_INFINITY",EVENTUALLY_AT_INFINITY;
+"EVENTUALLY_FALSE",EVENTUALLY_FALSE;
+"EVENTUALLY_FORALL",EVENTUALLY_FORALL;
+"EVENTUALLY_HAPPENS",EVENTUALLY_HAPPENS;
+"EVENTUALLY_MONO",EVENTUALLY_MONO;
+"EVENTUALLY_MP",EVENTUALLY_MP;
+"EVENTUALLY_SEQUENTIALLY",EVENTUALLY_SEQUENTIALLY;
+"EVENTUALLY_TRUE",EVENTUALLY_TRUE;
+"EVENTUALLY_WITHIN",EVENTUALLY_WITHIN;
+"EVENTUALLY_WITHIN_INTERIOR",EVENTUALLY_WITHIN_INTERIOR;
+"EVENTUALLY_WITHIN_LE",EVENTUALLY_WITHIN_LE;
+"EVEN_ADD",EVEN_ADD;
+"EVEN_AND_ODD",EVEN_AND_ODD;
+"EVEN_DOUBLE",EVEN_DOUBLE;
+"EVEN_EXISTS",EVEN_EXISTS;
+"EVEN_EXISTS_LEMMA",EVEN_EXISTS_LEMMA;
+"EVEN_EXP",EVEN_EXP;
+"EVEN_MOD",EVEN_MOD;
+"EVEN_MULT",EVEN_MULT;
+"EVEN_NSUM",EVEN_NSUM;
+"EVEN_ODD_DECOMPOSITION",EVEN_ODD_DECOMPOSITION;
+"EVEN_OR_ODD",EVEN_OR_ODD;
+"EVEN_SUB",EVEN_SUB;
+"EX",EX;
+"EXCHANGE_LEMMA",EXCHANGE_LEMMA;
+"EXCLUDED_MIDDLE",EXCLUDED_MIDDLE;
+"EXISTS_ARC_PSUBSET_SIMPLE_PATH",EXISTS_ARC_PSUBSET_SIMPLE_PATH;
+"EXISTS_BOOL_THM",EXISTS_BOOL_THM;
+"EXISTS_COUNTABLE_SUBSET_IMAGE",EXISTS_COUNTABLE_SUBSET_IMAGE;
+"EXISTS_CURRY",EXISTS_CURRY;
+"EXISTS_DEF",EXISTS_DEF;
+"EXISTS_DIFF",EXISTS_DIFF;
+"EXISTS_DOUBLE_ARC",EXISTS_DOUBLE_ARC;
+"EXISTS_DROP",EXISTS_DROP;
+"EXISTS_DROP_FUN",EXISTS_DROP_FUN;
+"EXISTS_DROP_IMAGE",EXISTS_DROP_IMAGE;
+"EXISTS_EX",EXISTS_EX;
+"EXISTS_FINITE_SUBSET_IMAGE",EXISTS_FINITE_SUBSET_IMAGE;
+"EXISTS_IN_CLAUSES",EXISTS_IN_CLAUSES;
+"EXISTS_IN_GSPEC",EXISTS_IN_GSPEC;
+"EXISTS_IN_IMAGE",EXISTS_IN_IMAGE;
+"EXISTS_IN_INSERT",EXISTS_IN_INSERT;
+"EXISTS_IN_PCROSS",EXISTS_IN_PCROSS;
+"EXISTS_IN_UNIONS",EXISTS_IN_UNIONS;
+"EXISTS_LIFT",EXISTS_LIFT;
+"EXISTS_LIFT_FUN",EXISTS_LIFT_FUN;
+"EXISTS_LIFT_IMAGE",EXISTS_LIFT_IMAGE;
+"EXISTS_NOT_THM",EXISTS_NOT_THM;
+"EXISTS_ONE_REP",EXISTS_ONE_REP;
+"EXISTS_OPTION",EXISTS_OPTION;
+"EXISTS_OR_THM",EXISTS_OR_THM;
+"EXISTS_PAIRED_THM",EXISTS_PAIRED_THM;
+"EXISTS_PAIR_THM",EXISTS_PAIR_THM;
+"EXISTS_PASTECART",EXISTS_PASTECART;
+"EXISTS_PATH_SUBPATH_TO_FRONTIER",EXISTS_PATH_SUBPATH_TO_FRONTIER;
+"EXISTS_PATH_SUBPATH_TO_FRONTIER_CLOSED",EXISTS_PATH_SUBPATH_TO_FRONTIER_CLOSED;
+"EXISTS_REFL",EXISTS_REFL;
+"EXISTS_SIMP",EXISTS_SIMP;
+"EXISTS_SUBARC_OF_ARC_NOENDS",EXISTS_SUBARC_OF_ARC_NOENDS;
+"EXISTS_SUBPATH_OF_ARC_NOENDS",EXISTS_SUBPATH_OF_ARC_NOENDS;
+"EXISTS_SUBPATH_OF_PATH",EXISTS_SUBPATH_OF_PATH;
+"EXISTS_SUBSET_IMAGE",EXISTS_SUBSET_IMAGE;
+"EXISTS_SUBSET_UNION",EXISTS_SUBSET_UNION;
+"EXISTS_SUM_THM",EXISTS_SUM_THM;
+"EXISTS_SWAP",EXISTS_SWAP;
+"EXISTS_THM",EXISTS_THM;
+"EXISTS_TRIPLED_THM",EXISTS_TRIPLED_THM;
+"EXISTS_UNCURRY",EXISTS_UNCURRY;
+"EXISTS_UNIQUE",EXISTS_UNIQUE;
+"EXISTS_UNIQUE_ALT",EXISTS_UNIQUE_ALT;
+"EXISTS_UNIQUE_DEF",EXISTS_UNIQUE_DEF;
+"EXISTS_UNIQUE_REFL",EXISTS_UNIQUE_REFL;
+"EXISTS_UNIQUE_THM",EXISTS_UNIQUE_THM;
+"EXISTS_VECTOR_1",EXISTS_VECTOR_1;
+"EXISTS_VECTOR_2",EXISTS_VECTOR_2;
+"EXISTS_VECTOR_3",EXISTS_VECTOR_3;
+"EXISTS_VECTOR_4",EXISTS_VECTOR_4;
+"EXP",EXP;
+"EXPAND_CLOSED_OPEN_INTERVAL",EXPAND_CLOSED_OPEN_INTERVAL;
+"EXPLICIT_SUBSET_INTERIOR_CONVEX_HULL",EXPLICIT_SUBSET_INTERIOR_CONVEX_HULL;
+"EXPLICIT_SUBSET_INTERIOR_CONVEX_HULL_MINIMAL",EXPLICIT_SUBSET_INTERIOR_CONVEX_HULL_MINIMAL;
+"EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL",EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL;
+"EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL_MINIMAL",EXPLICIT_SUBSET_RELATIVE_INTERIOR_CONVEX_HULL_MINIMAL;
+"EXPOSED_FACE_OF",EXPOSED_FACE_OF;
+"EXPOSED_FACE_OF_INTER",EXPOSED_FACE_OF_INTER;
+"EXPOSED_FACE_OF_INTERS",EXPOSED_FACE_OF_INTERS;
+"EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE",EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE;
+"EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE",EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE;
+"EXPOSED_FACE_OF_LINEAR_IMAGE",EXPOSED_FACE_OF_LINEAR_IMAGE;
+"EXPOSED_FACE_OF_PARALLEL",EXPOSED_FACE_OF_PARALLEL;
+"EXPOSED_FACE_OF_POLYHEDRON",EXPOSED_FACE_OF_POLYHEDRON;
+"EXPOSED_FACE_OF_REFL",EXPOSED_FACE_OF_REFL;
+"EXPOSED_FACE_OF_REFL_EQ",EXPOSED_FACE_OF_REFL_EQ;
+"EXPOSED_FACE_OF_SUMS",EXPOSED_FACE_OF_SUMS;
+"EXPOSED_FACE_OF_TRANSLATION_EQ",EXPOSED_FACE_OF_TRANSLATION_EQ;
+"EXPOSED_POINT_OF_FURTHEST_POINT",EXPOSED_POINT_OF_FURTHEST_POINT;
+"EXPOSED_POINT_OF_INTER_SUPPORTING_HYPERPLANE_GE",EXPOSED_POINT_OF_INTER_SUPPORTING_HYPERPLANE_GE;
+"EXPOSED_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE",EXPOSED_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE;
+"EXP_1",EXP_1;
+"EXP_2",EXP_2;
+"EXP_ADD",EXP_ADD;
+"EXP_EQ_0",EXP_EQ_0;
+"EXP_EQ_1",EXP_EQ_1;
+"EXP_LT_0",EXP_LT_0;
+"EXP_MONO_EQ",EXP_MONO_EQ;
+"EXP_MONO_LE",EXP_MONO_LE;
+"EXP_MONO_LE_IMP",EXP_MONO_LE_IMP;
+"EXP_MONO_LT",EXP_MONO_LT;
+"EXP_MONO_LT_IMP",EXP_MONO_LT_IMP;
+"EXP_MULT",EXP_MULT;
+"EXP_ONE",EXP_ONE;
+"EXP_ZERO",EXP_ZERO;
+"EXTEND_FL",EXTEND_FL;
+"EXTEND_INSEG",EXTEND_INSEG;
+"EXTEND_LINSEG",EXTEND_LINSEG;
+"EXTEND_TO_AFFINE_BASIS",EXTEND_TO_AFFINE_BASIS;
+"EXTENSION",EXTENSION;
+"EXTREME_POINTS_OF_CONVEX_HULL",EXTREME_POINTS_OF_CONVEX_HULL;
+"EXTREME_POINTS_OF_CONVEX_HULL_EQ",EXTREME_POINTS_OF_CONVEX_HULL_EQ;
+"EXTREME_POINTS_OF_LINEAR_IMAGE",EXTREME_POINTS_OF_LINEAR_IMAGE;
+"EXTREME_POINTS_OF_TRANSLATION",EXTREME_POINTS_OF_TRANSLATION;
+"EXTREME_POINT_EXISTS_CONVEX",EXTREME_POINT_EXISTS_CONVEX;
+"EXTREME_POINT_NOT_IN_INTERIOR",EXTREME_POINT_NOT_IN_INTERIOR;
+"EXTREME_POINT_NOT_IN_RELATIVE_INTERIOR",EXTREME_POINT_NOT_IN_RELATIVE_INTERIOR;
+"EXTREME_POINT_OF_CONIC",EXTREME_POINT_OF_CONIC;
+"EXTREME_POINT_OF_CONVEX_HULL",EXTREME_POINT_OF_CONVEX_HULL;
+"EXTREME_POINT_OF_CONVEX_HULL_2",EXTREME_POINT_OF_CONVEX_HULL_2;
+"EXTREME_POINT_OF_CONVEX_HULL_AFFINE_INDEPENDENT",EXTREME_POINT_OF_CONVEX_HULL_AFFINE_INDEPENDENT;
+"EXTREME_POINT_OF_CONVEX_HULL_CONVEX_INDEPENDENT",EXTREME_POINT_OF_CONVEX_HULL_CONVEX_INDEPENDENT;
+"EXTREME_POINT_OF_CONVEX_HULL_EQ",EXTREME_POINT_OF_CONVEX_HULL_EQ;
+"EXTREME_POINT_OF_CONVEX_HULL_INSERT",EXTREME_POINT_OF_CONVEX_HULL_INSERT;
+"EXTREME_POINT_OF_CONVEX_HULL_INSERT_EQ",EXTREME_POINT_OF_CONVEX_HULL_INSERT_EQ;
+"EXTREME_POINT_OF_EMPTY",EXTREME_POINT_OF_EMPTY;
+"EXTREME_POINT_OF_FACE",EXTREME_POINT_OF_FACE;
+"EXTREME_POINT_OF_INTER",EXTREME_POINT_OF_INTER;
+"EXTREME_POINT_OF_INTER_SUPPORTING_HYPERPLANE_GE",EXTREME_POINT_OF_INTER_SUPPORTING_HYPERPLANE_GE;
+"EXTREME_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE",EXTREME_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE;
+"EXTREME_POINT_OF_LINEAR_IMAGE",EXTREME_POINT_OF_LINEAR_IMAGE;
+"EXTREME_POINT_OF_MIDPOINT",EXTREME_POINT_OF_MIDPOINT;
+"EXTREME_POINT_OF_SEGMENT",EXTREME_POINT_OF_SEGMENT;
+"EXTREME_POINT_OF_SING",EXTREME_POINT_OF_SING;
+"EXTREME_POINT_OF_STILLCONVEX",EXTREME_POINT_OF_STILLCONVEX;
+"EXTREME_POINT_OF_TRANSLATION_EQ",EXTREME_POINT_OF_TRANSLATION_EQ;
+"EX_IMP",EX_IMP;
+"EX_MAP",EX_MAP;
+"EX_MEM",EX_MEM;
+"FACES_OF_LINEAR_IMAGE",FACES_OF_LINEAR_IMAGE;
+"FACES_OF_SIMPLEX",FACES_OF_SIMPLEX;
+"FACES_OF_TRANSLATION",FACES_OF_TRANSLATION;
+"FACETS_OF_POLYHEDRON_EXPLICIT_DISTINCT",FACETS_OF_POLYHEDRON_EXPLICIT_DISTINCT;
+"FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT",FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT;
+"FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT_ALT",FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT_ALT;
+"FACET_OF_EMPTY",FACET_OF_EMPTY;
+"FACET_OF_HALFSPACE_GE",FACET_OF_HALFSPACE_GE;
+"FACET_OF_HALFSPACE_LE",FACET_OF_HALFSPACE_LE;
+"FACET_OF_IMP_FACE_OF",FACET_OF_IMP_FACE_OF;
+"FACET_OF_IMP_PROPER",FACET_OF_IMP_PROPER;
+"FACET_OF_IMP_SUBSET",FACET_OF_IMP_SUBSET;
+"FACET_OF_LINEAR_IMAGE",FACET_OF_LINEAR_IMAGE;
+"FACET_OF_POLYHEDRON",FACET_OF_POLYHEDRON;
+"FACET_OF_POLYHEDRON_EXPLICIT",FACET_OF_POLYHEDRON_EXPLICIT;
+"FACET_OF_REFL",FACET_OF_REFL;
+"FACET_OF_TRANSLATION_EQ",FACET_OF_TRANSLATION_EQ;
+"FACE_OF_AFFINE_EQ",FACE_OF_AFFINE_EQ;
+"FACE_OF_AFFINE_TRIVIAL",FACE_OF_AFFINE_TRIVIAL;
+"FACE_OF_AFF_DIM_LT",FACE_OF_AFF_DIM_LT;
+"FACE_OF_CONIC",FACE_OF_CONIC;
+"FACE_OF_CONVEX_HULLS",FACE_OF_CONVEX_HULLS;
+"FACE_OF_CONVEX_HULL_AFFINE_INDEPENDENT",FACE_OF_CONVEX_HULL_AFFINE_INDEPENDENT;
+"FACE_OF_CONVEX_HULL_INSERT",FACE_OF_CONVEX_HULL_INSERT;
+"FACE_OF_CONVEX_HULL_INSERT_EQ",FACE_OF_CONVEX_HULL_INSERT_EQ;
+"FACE_OF_CONVEX_HULL_SUBSET",FACE_OF_CONVEX_HULL_SUBSET;
+"FACE_OF_DISJOINT_INTERIOR",FACE_OF_DISJOINT_INTERIOR;
+"FACE_OF_DISJOINT_RELATIVE_INTERIOR",FACE_OF_DISJOINT_RELATIVE_INTERIOR;
+"FACE_OF_EMPTY",FACE_OF_EMPTY;
+"FACE_OF_EQ",FACE_OF_EQ;
+"FACE_OF_FACE",FACE_OF_FACE;
+"FACE_OF_HALFSPACE_GE",FACE_OF_HALFSPACE_GE;
+"FACE_OF_HALFSPACE_LE",FACE_OF_HALFSPACE_LE;
+"FACE_OF_IMP_CLOSED",FACE_OF_IMP_CLOSED;
+"FACE_OF_IMP_COMPACT",FACE_OF_IMP_COMPACT;
+"FACE_OF_IMP_CONVEX",FACE_OF_IMP_CONVEX;
+"FACE_OF_IMP_SUBSET",FACE_OF_IMP_SUBSET;
+"FACE_OF_INTER",FACE_OF_INTER;
+"FACE_OF_INTERS",FACE_OF_INTERS;
+"FACE_OF_INTER_INTER",FACE_OF_INTER_INTER;
+"FACE_OF_INTER_SUBFACE",FACE_OF_INTER_SUBFACE;
+"FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE",FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE;
+"FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE_STRONG",FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE_STRONG;
+"FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE",FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE;
+"FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE_STRONG",FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE_STRONG;
+"FACE_OF_LINEAR_IMAGE",FACE_OF_LINEAR_IMAGE;
+"FACE_OF_PCROSS",FACE_OF_PCROSS;
+"FACE_OF_PCROSS_DECOMP",FACE_OF_PCROSS_DECOMP;
+"FACE_OF_PCROSS_EQ",FACE_OF_PCROSS_EQ;
+"FACE_OF_POLYHEDRON",FACE_OF_POLYHEDRON;
+"FACE_OF_POLYHEDRON_EXPLICIT",FACE_OF_POLYHEDRON_EXPLICIT;
+"FACE_OF_POLYHEDRON_POLYHEDRON",FACE_OF_POLYHEDRON_POLYHEDRON;
+"FACE_OF_POLYHEDRON_SUBSET_EXPLICIT",FACE_OF_POLYHEDRON_SUBSET_EXPLICIT;
+"FACE_OF_POLYHEDRON_SUBSET_FACET",FACE_OF_POLYHEDRON_SUBSET_FACET;
+"FACE_OF_POLYTOPE_POLYTOPE",FACE_OF_POLYTOPE_POLYTOPE;
+"FACE_OF_REFL",FACE_OF_REFL;
+"FACE_OF_REFL_EQ",FACE_OF_REFL_EQ;
+"FACE_OF_SIMPLEX_SUBSET",FACE_OF_SIMPLEX_SUBSET;
+"FACE_OF_SING",FACE_OF_SING;
+"FACE_OF_SLICE",FACE_OF_SLICE;
+"FACE_OF_STILLCONVEX",FACE_OF_STILLCONVEX;
+"FACE_OF_SUBSET",FACE_OF_SUBSET;
+"FACE_OF_SUBSET_RELATIVE_BOUNDARY",FACE_OF_SUBSET_RELATIVE_BOUNDARY;
+"FACE_OF_SUBSET_RELATIVE_FRONTIER",FACE_OF_SUBSET_RELATIVE_FRONTIER;
+"FACE_OF_TRANS",FACE_OF_TRANS;
+"FACE_OF_TRANSLATION_EQ",FACE_OF_TRANSLATION_EQ;
+"FACT",FACT;
+"FACT_LE",FACT_LE;
+"FACT_LT",FACT_LT;
+"FACT_MONO",FACT_MONO;
+"FACT_NZ",FACT_NZ;
+"FARKAS_LEMMA",FARKAS_LEMMA;
+"FARKAS_LEMMA_ALT",FARKAS_LEMMA_ALT;
+"FASHODA",FASHODA;
+"FASHODA_INTERLACE",FASHODA_INTERLACE;
+"FASHODA_UNIT",FASHODA_UNIT;
+"FASHODA_UNIT_PATH",FASHODA_UNIT_PATH;
+"FCONS",FCONS;
+"FCONS_UNDO",FCONS_UNDO;
+"FILTER",FILTER;
+"FILTER_APPEND",FILTER_APPEND;
+"FILTER_MAP",FILTER_MAP;
+"FINE_DIVISION_EXISTS",FINE_DIVISION_EXISTS;
+"FINE_INTER",FINE_INTER;
+"FINE_INTERS",FINE_INTERS;
+"FINE_SUBSET",FINE_SUBSET;
+"FINE_UNION",FINE_UNION;
+"FINE_UNIONS",FINE_UNIONS;
+"FINITELY_GENERATED_CONIC_POLYHEDRON",FINITELY_GENERATED_CONIC_POLYHEDRON;
+"FINITE_BALL",FINITE_BALL;
+"FINITE_BITSET",FINITE_BITSET;
+"FINITE_BOOL",FINITE_BOOL;
+"FINITE_BOUNDED_FUNCTIONS",FINITE_BOUNDED_FUNCTIONS;
+"FINITE_CARD_LT",FINITE_CARD_LT;
+"FINITE_CART",FINITE_CART;
+"FINITE_CART_SUBSET_LEMMA",FINITE_CART_SUBSET_LEMMA;
+"FINITE_CART_UNIV",FINITE_CART_UNIV;
+"FINITE_CASES",FINITE_CASES;
+"FINITE_CBALL",FINITE_CBALL;
+"FINITE_COLUMNS",FINITE_COLUMNS;
+"FINITE_COMPONENTS",FINITE_COMPONENTS;
+"FINITE_CROSS",FINITE_CROSS;
+"FINITE_DELETE",FINITE_DELETE;
+"FINITE_DELETE_IMP",FINITE_DELETE_IMP;
+"FINITE_DIFF",FINITE_DIFF;
+"FINITE_EMPTY",FINITE_EMPTY;
+"FINITE_EMPTY_INTERIOR",FINITE_EMPTY_INTERIOR;
+"FINITE_FACES_OF_SIMPLEX",FINITE_FACES_OF_SIMPLEX;
+"FINITE_FINITE_IMAGE",FINITE_FINITE_IMAGE;
+"FINITE_FINITE_PREIMAGE",FINITE_FINITE_PREIMAGE;
+"FINITE_FINITE_PREIMAGE_GENERAL",FINITE_FINITE_PREIMAGE_GENERAL;
+"FINITE_FINITE_UNIONS",FINITE_FINITE_UNIONS;
+"FINITE_FUNSPACE",FINITE_FUNSPACE;
+"FINITE_FUNSPACE_UNIV",FINITE_FUNSPACE_UNIV;
+"FINITE_HAS_SIZE",FINITE_HAS_SIZE;
+"FINITE_IMAGE",FINITE_IMAGE;
+"FINITE_IMAGE_EXPAND",FINITE_IMAGE_EXPAND;
+"FINITE_IMAGE_IMAGE",FINITE_IMAGE_IMAGE;
+"FINITE_IMAGE_INJ",FINITE_IMAGE_INJ;
+"FINITE_IMAGE_INJ_EQ",FINITE_IMAGE_INJ_EQ;
+"FINITE_IMAGE_INJ_GENERAL",FINITE_IMAGE_INJ_GENERAL;
+"FINITE_IMP_BOUNDED",FINITE_IMP_BOUNDED;
+"FINITE_IMP_BOUNDED_CONVEX_HULL",FINITE_IMP_BOUNDED_CONVEX_HULL;
+"FINITE_IMP_CLOSED",FINITE_IMP_CLOSED;
+"FINITE_IMP_CLOSED_IN",FINITE_IMP_CLOSED_IN;
+"FINITE_IMP_COMPACT",FINITE_IMP_COMPACT;
+"FINITE_IMP_COMPACT_CONVEX_HULL",FINITE_IMP_COMPACT_CONVEX_HULL;
+"FINITE_IMP_COUNTABLE",FINITE_IMP_COUNTABLE;
+"FINITE_IMP_NOT_OPEN",FINITE_IMP_NOT_OPEN;
+"FINITE_INDEX_INJ",FINITE_INDEX_INJ;
+"FINITE_INDEX_INRANGE",FINITE_INDEX_INRANGE;
+"FINITE_INDEX_INRANGE_2",FINITE_INDEX_INRANGE_2;
+"FINITE_INDEX_NUMBERS",FINITE_INDEX_NUMBERS;
+"FINITE_INDEX_NUMSEG",FINITE_INDEX_NUMSEG;
+"FINITE_INDEX_NUMSEG_SPECIAL",FINITE_INDEX_NUMSEG_SPECIAL;
+"FINITE_INDEX_WORKS",FINITE_INDEX_WORKS;
+"FINITE_INDUCT",FINITE_INDUCT;
+"FINITE_INDUCT_DELETE",FINITE_INDUCT_DELETE;
+"FINITE_INDUCT_STRONG",FINITE_INDUCT_STRONG;
+"FINITE_INSERT",FINITE_INSERT;
+"FINITE_INTER",FINITE_INTER;
+"FINITE_INTERVAL_1",FINITE_INTERVAL_1;
+"FINITE_INTER_COLLINEAR_OPEN_SEGMENTS",FINITE_INTER_COLLINEAR_OPEN_SEGMENTS;
+"FINITE_INTER_NUMSEG",FINITE_INTER_NUMSEG;
+"FINITE_INTSEG",FINITE_INTSEG;
+"FINITE_MULTIVECTOR",FINITE_MULTIVECTOR;
+"FINITE_NUMSEG",FINITE_NUMSEG;
+"FINITE_NUMSEG_LE",FINITE_NUMSEG_LE;
+"FINITE_NUMSEG_LT",FINITE_NUMSEG_LT;
+"FINITE_PCROSS",FINITE_PCROSS;
+"FINITE_PCROSS_EQ",FINITE_PCROSS_EQ;
+"FINITE_PERMUTATIONS",FINITE_PERMUTATIONS;
+"FINITE_POLYHEDRON_EXPOSED_FACES",FINITE_POLYHEDRON_EXPOSED_FACES;
+"FINITE_POLYHEDRON_EXTREME_POINTS",FINITE_POLYHEDRON_EXTREME_POINTS;
+"FINITE_POLYHEDRON_FACES",FINITE_POLYHEDRON_FACES;
+"FINITE_POLYHEDRON_FACETS",FINITE_POLYHEDRON_FACETS;
+"FINITE_POLYTOPE_FACES",FINITE_POLYTOPE_FACES;
+"FINITE_POLYTOPE_FACETS",FINITE_POLYTOPE_FACETS;
+"FINITE_POWERSET",FINITE_POWERSET;
+"FINITE_PRODUCT",FINITE_PRODUCT;
+"FINITE_PRODUCT_DEPENDENT",FINITE_PRODUCT_DEPENDENT;
+"FINITE_REAL_INTERVAL",FINITE_REAL_INTERVAL;
+"FINITE_RECURSION",FINITE_RECURSION;
+"FINITE_RECURSION_DELETE",FINITE_RECURSION_DELETE;
+"FINITE_RESTRICT",FINITE_RESTRICT;
+"FINITE_ROWS",FINITE_ROWS;
+"FINITE_RULES",FINITE_RULES;
+"FINITE_SEGMENT",FINITE_SEGMENT;
+"FINITE_SET_AVOID",FINITE_SET_AVOID;
+"FINITE_SET_OF_LIST",FINITE_SET_OF_LIST;
+"FINITE_SIMPLICES",FINITE_SIMPLICES;
+"FINITE_SING",FINITE_SING;
+"FINITE_SPHERE",FINITE_SPHERE;
+"FINITE_SPHERE_1",FINITE_SPHERE_1;
+"FINITE_STDBASIS",FINITE_STDBASIS;
+"FINITE_SUBSET",FINITE_SUBSET;
+"FINITE_SUBSET_IMAGE",FINITE_SUBSET_IMAGE;
+"FINITE_SUBSET_IMAGE_IMP",FINITE_SUBSET_IMAGE_IMP;
+"FINITE_SUM_IMAGE",FINITE_SUM_IMAGE;
+"FINITE_SUPPORT",FINITE_SUPPORT;
+"FINITE_SUPPORT_DELTA",FINITE_SUPPORT_DELTA;
+"FINITE_TRANSITIVITY_CHAIN",FINITE_TRANSITIVITY_CHAIN;
+"FINITE_UNION",FINITE_UNION;
+"FINITE_UNIONS",FINITE_UNIONS;
+"FINITE_UNION_IMP",FINITE_UNION_IMP;
+"FINREC",FINREC;
+"FINREC_1_LEMMA",FINREC_1_LEMMA;
+"FINREC_EXISTS_LEMMA",FINREC_EXISTS_LEMMA;
+"FINREC_FUN",FINREC_FUN;
+"FINREC_FUN_LEMMA",FINREC_FUN_LEMMA;
+"FINREC_SUC_LEMMA",FINREC_SUC_LEMMA;
+"FINREC_UNIQUE_LEMMA",FINREC_UNIQUE_LEMMA;
+"FIXED_POINT_INESSENTIAL_SPHERE_MAP",FIXED_POINT_INESSENTIAL_SPHERE_MAP;
+"FIXING_SWAPSEQ_DECREASE",FIXING_SWAPSEQ_DECREASE;
+"FLATTEN_LEMMA",FLATTEN_LEMMA;
+"FLOOR",FLOOR;
+"FLOOR_DIV_DIV",FLOOR_DIV_DIV;
+"FLOOR_DOUBLE",FLOOR_DOUBLE;
+"FLOOR_EQ_0",FLOOR_EQ_0;
+"FLOOR_FRAC",FLOOR_FRAC;
+"FLOOR_MONO",FLOOR_MONO;
+"FLOOR_NUM",FLOOR_NUM;
+"FLOOR_POS",FLOOR_POS;
+"FLOOR_POS_LE",FLOOR_POS_LE;
+"FLOOR_UNIQUE",FLOOR_UNIQUE;
+"FL_RESTRICT",FL_RESTRICT;
+"FL_RESTRICTED_SUBSET",FL_RESTRICTED_SUBSET;
+"FL_SUC",FL_SUC;
+"FNIL",FNIL;
+"FORALL_1",FORALL_1;
+"FORALL_2",FORALL_2;
+"FORALL_3",FORALL_3;
+"FORALL_4",FORALL_4;
+"FORALL_ALL",FORALL_ALL;
+"FORALL_AND_THM",FORALL_AND_THM;
+"FORALL_BOOL_THM",FORALL_BOOL_THM;
+"FORALL_COUNTABLE_AS_IMAGE",FORALL_COUNTABLE_AS_IMAGE;
+"FORALL_COUNTABLE_SUBSET_IMAGE",FORALL_COUNTABLE_SUBSET_IMAGE;
+"FORALL_CURRY",FORALL_CURRY;
+"FORALL_DEF",FORALL_DEF;
+"FORALL_DIMINDEX_1",FORALL_DIMINDEX_1;
+"FORALL_DOT_EQ_0",FORALL_DOT_EQ_0;
+"FORALL_DROP",FORALL_DROP;
+"FORALL_DROP_FUN",FORALL_DROP_FUN;
+"FORALL_DROP_IMAGE",FORALL_DROP_IMAGE;
+"FORALL_EVENTUALLY",FORALL_EVENTUALLY;
+"FORALL_FINITE_INDEX",FORALL_FINITE_INDEX;
+"FORALL_FINITE_SUBSET_IMAGE",FORALL_FINITE_SUBSET_IMAGE;
+"FORALL_INTEGER",FORALL_INTEGER;
+"FORALL_IN_CLAUSES",FORALL_IN_CLAUSES;
+"FORALL_IN_CLOSURE",FORALL_IN_CLOSURE;
+"FORALL_IN_DIVISION",FORALL_IN_DIVISION;
+"FORALL_IN_DIVISION_NONEMPTY",FORALL_IN_DIVISION_NONEMPTY;
+"FORALL_IN_GSPEC",FORALL_IN_GSPEC;
+"FORALL_IN_IMAGE",FORALL_IN_IMAGE;
+"FORALL_IN_INSERT",FORALL_IN_INSERT;
+"FORALL_IN_PCROSS",FORALL_IN_PCROSS;
+"FORALL_IN_UNIONS",FORALL_IN_UNIONS;
+"FORALL_LIFT",FORALL_LIFT;
+"FORALL_LIFT_FUN",FORALL_LIFT_FUN;
+"FORALL_LIFT_IMAGE",FORALL_LIFT_IMAGE;
+"FORALL_MULTIVECTOR",FORALL_MULTIVECTOR;
+"FORALL_NOT_THM",FORALL_NOT_THM;
+"FORALL_OF_DROP",FORALL_OF_DROP;
+"FORALL_OF_PASTECART",FORALL_OF_PASTECART;
+"FORALL_OPTION",FORALL_OPTION;
+"FORALL_PAIRED_THM",FORALL_PAIRED_THM;
+"FORALL_PAIR_THM",FORALL_PAIR_THM;
+"FORALL_PASTECART",FORALL_PASTECART;
+"FORALL_POS_MONO",FORALL_POS_MONO;
+"FORALL_POS_MONO_1",FORALL_POS_MONO_1;
+"FORALL_REAL_ONE",FORALL_REAL_ONE;
+"FORALL_SETCODE",FORALL_SETCODE;
+"FORALL_SIMP",FORALL_SIMP;
+"FORALL_SUBSET_IMAGE",FORALL_SUBSET_IMAGE;
+"FORALL_SUBSET_UNION",FORALL_SUBSET_UNION;
+"FORALL_SUC",FORALL_SUC;
+"FORALL_SUM_THM",FORALL_SUM_THM;
+"FORALL_TRIPLED_THM",FORALL_TRIPLED_THM;
+"FORALL_UNCURRY",FORALL_UNCURRY;
+"FORALL_UNWIND_THM1",FORALL_UNWIND_THM1;
+"FORALL_UNWIND_THM2",FORALL_UNWIND_THM2;
+"FORALL_VECTOR_1",FORALL_VECTOR_1;
+"FORALL_VECTOR_2",FORALL_VECTOR_2;
+"FORALL_VECTOR_3",FORALL_VECTOR_3;
+"FORALL_VECTOR_4",FORALL_VECTOR_4;
+"FRAC_FLOOR",FRAC_FLOOR;
+"FRAC_NUM",FRAC_NUM;
+"FRAC_UNIQUE",FRAC_UNIQUE;
+"FRECHET_DERIVATIVE_AT",FRECHET_DERIVATIVE_AT;
+"FRECHET_DERIVATIVE_CONST_AT",FRECHET_DERIVATIVE_CONST_AT;
+"FRECHET_DERIVATIVE_UNIQUE_AT",FRECHET_DERIVATIVE_UNIQUE_AT;
+"FRECHET_DERIVATIVE_UNIQUE_WITHIN",FRECHET_DERIVATIVE_UNIQUE_WITHIN;
+"FRECHET_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL",FRECHET_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL;
+"FRECHET_DERIVATIVE_UNIQUE_WITHIN_OPEN_INTERVAL",FRECHET_DERIVATIVE_UNIQUE_WITHIN_OPEN_INTERVAL;
+"FRECHET_DERIVATIVE_WITHIN_CLOSED_INTERVAL",FRECHET_DERIVATIVE_WITHIN_CLOSED_INTERVAL;
+"FRECHET_DERIVATIVE_WORKS",FRECHET_DERIVATIVE_WORKS;
+"FROM_0",FROM_0;
+"FROM_INTER_NUMSEG",FROM_INTER_NUMSEG;
+"FROM_INTER_NUMSEG_GEN",FROM_INTER_NUMSEG_GEN;
+"FRONTIER_BALL",FRONTIER_BALL;
+"FRONTIER_BIJECTIVE_LINEAR_IMAGE",FRONTIER_BIJECTIVE_LINEAR_IMAGE;
+"FRONTIER_CBALL",FRONTIER_CBALL;
+"FRONTIER_CLOSED",FRONTIER_CLOSED;
+"FRONTIER_CLOSED_INTERVAL",FRONTIER_CLOSED_INTERVAL;
+"FRONTIER_CLOSURES",FRONTIER_CLOSURES;
+"FRONTIER_CLOSURE_CONVEX",FRONTIER_CLOSURE_CONVEX;
+"FRONTIER_COMPLEMENT",FRONTIER_COMPLEMENT;
+"FRONTIER_CONVEX_HULL_CASES",FRONTIER_CONVEX_HULL_CASES;
+"FRONTIER_CONVEX_HULL_EXPLICIT",FRONTIER_CONVEX_HULL_EXPLICIT;
+"FRONTIER_DISJOINT_EQ",FRONTIER_DISJOINT_EQ;
+"FRONTIER_EMPTY",FRONTIER_EMPTY;
+"FRONTIER_EQ_EMPTY",FRONTIER_EQ_EMPTY;
+"FRONTIER_FRONTIER_FRONTIER",FRONTIER_FRONTIER_FRONTIER;
+"FRONTIER_FRONTIER_SUBSET",FRONTIER_FRONTIER_SUBSET;
+"FRONTIER_HALFSPACE_GE",FRONTIER_HALFSPACE_GE;
+"FRONTIER_HALFSPACE_GT",FRONTIER_HALFSPACE_GT;
+"FRONTIER_HALFSPACE_LE",FRONTIER_HALFSPACE_LE;
+"FRONTIER_HALFSPACE_LT",FRONTIER_HALFSPACE_LT;
+"FRONTIER_INJECTIVE_LINEAR_IMAGE",FRONTIER_INJECTIVE_LINEAR_IMAGE;
+"FRONTIER_INSIDE_SUBSET",FRONTIER_INSIDE_SUBSET;
+"FRONTIER_INTERIORS",FRONTIER_INTERIORS;
+"FRONTIER_INTER_SUBSET",FRONTIER_INTER_SUBSET;
+"FRONTIER_MINIMAL_SEPARATING_CLOSED",FRONTIER_MINIMAL_SEPARATING_CLOSED;
+"FRONTIER_NOT_EMPTY",FRONTIER_NOT_EMPTY;
+"FRONTIER_OF_COMPONENTS_CLOSED_COMPLEMENT",FRONTIER_OF_COMPONENTS_CLOSED_COMPLEMENT;
+"FRONTIER_OF_COMPONENTS_SUBSET",FRONTIER_OF_COMPONENTS_SUBSET;
+"FRONTIER_OF_CONNECTED_COMPONENT_SUBSET",FRONTIER_OF_CONNECTED_COMPONENT_SUBSET;
+"FRONTIER_OF_CONVEX_HULL",FRONTIER_OF_CONVEX_HULL;
+"FRONTIER_OF_TRIANGLE",FRONTIER_OF_TRIANGLE;
+"FRONTIER_OPEN_INTERVAL",FRONTIER_OPEN_INTERVAL;
+"FRONTIER_OUTSIDE_SUBSET",FRONTIER_OUTSIDE_SUBSET;
+"FRONTIER_RETRACT_OF_PUNCTURED_UNIVERSE",FRONTIER_RETRACT_OF_PUNCTURED_UNIVERSE;
+"FRONTIER_SING",FRONTIER_SING;
+"FRONTIER_STRADDLE",FRONTIER_STRADDLE;
+"FRONTIER_SUBSET_CLOSED",FRONTIER_SUBSET_CLOSED;
+"FRONTIER_SUBSET_COMPACT",FRONTIER_SUBSET_COMPACT;
+"FRONTIER_SUBSET_EQ",FRONTIER_SUBSET_EQ;
+"FRONTIER_SUBSET_RETRACTION",FRONTIER_SUBSET_RETRACTION;
+"FRONTIER_SURJECTIVE_LINEAR_IMAGE",FRONTIER_SURJECTIVE_LINEAR_IMAGE;
+"FRONTIER_TRANSLATION",FRONTIER_TRANSLATION;
+"FRONTIER_UNION",FRONTIER_UNION;
+"FRONTIER_UNIONS_SUBSET_CLOSURE",FRONTIER_UNIONS_SUBSET_CLOSURE;
+"FRONTIER_UNION_SUBSET",FRONTIER_UNION_SUBSET;
+"FRONTIER_UNIV",FRONTIER_UNIV;
+"FST",FST;
+"FSTCART_ADD",FSTCART_ADD;
+"FSTCART_CMUL",FSTCART_CMUL;
+"FSTCART_NEG",FSTCART_NEG;
+"FSTCART_PASTECART",FSTCART_PASTECART;
+"FSTCART_SUB",FSTCART_SUB;
+"FSTCART_VEC",FSTCART_VEC;
+"FSTCART_VSUM",FSTCART_VSUM;
+"FST_DEF",FST_DEF;
+"FULL_RANK_INJECTIVE",FULL_RANK_INJECTIVE;
+"FULL_RANK_SURJECTIVE",FULL_RANK_SURJECTIVE;
+"FUNCTION_CONVERGENT_SUBSEQUENCE",FUNCTION_CONVERGENT_SUBSEQUENCE;
+"FUNCTION_FACTORS_LEFT",FUNCTION_FACTORS_LEFT;
+"FUNCTION_FACTORS_LEFT_GEN",FUNCTION_FACTORS_LEFT_GEN;
+"FUNCTION_FACTORS_RIGHT",FUNCTION_FACTORS_RIGHT;
+"FUNCTION_FACTORS_RIGHT_GEN",FUNCTION_FACTORS_RIGHT_GEN;
+"FUNDAMENTAL_THEOREM_OF_CALCULUS",FUNDAMENTAL_THEOREM_OF_CALCULUS;
+"FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR",FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR;
+"FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG",FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG;
+"FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG",FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG;
+"FUN_EQ_THM",FUN_EQ_THM;
+"FUN_IN_IMAGE",FUN_IN_IMAGE;
+"F_DEF",F_DEF;
+"GABS_DEF",GABS_DEF;
+"GAUGE_BALL",GAUGE_BALL;
+"GAUGE_BALL_DEPENDENT",GAUGE_BALL_DEPENDENT;
+"GAUGE_EXISTENCE_LEMMA",GAUGE_EXISTENCE_LEMMA;
+"GAUGE_INTER",GAUGE_INTER;
+"GAUGE_INTERS",GAUGE_INTERS;
+"GAUGE_MODIFY",GAUGE_MODIFY;
+"GAUGE_TRIVIAL",GAUGE_TRIVIAL;
+"GE",GE;
+"GENERAL_CONNECTED_OPEN",GENERAL_CONNECTED_OPEN;
+"GEOM_ASSOC",GEOM_ASSOC;
+"GEOM_LADD",GEOM_LADD;
+"GEOM_LMUL",GEOM_LMUL;
+"GEOM_LNEG",GEOM_LNEG;
+"GEOM_LZERO",GEOM_LZERO;
+"GEOM_MBASIS",GEOM_MBASIS;
+"GEOM_MBASIS_SING",GEOM_MBASIS_SING;
+"GEOM_RADD",GEOM_RADD;
+"GEOM_RMUL",GEOM_RMUL;
+"GEOM_RNEG",GEOM_RNEG;
+"GEOM_RZERO",GEOM_RZERO;
+"GEQ_DEF",GEQ_DEF;
+"GE_C",GE_C;
+"GE_REFL",GE_REFL;
+"GRADE_ADD",GRADE_ADD;
+"GRADE_CMUL",GRADE_CMUL;
+"GRAM_SCHMIDT_STEP",GRAM_SCHMIDT_STEP;
+"GRASSMANN_PLUCKER_2",GRASSMANN_PLUCKER_2;
+"GRASSMANN_PLUCKER_3",GRASSMANN_PLUCKER_3;
+"GRASSMANN_PLUCKER_4",GRASSMANN_PLUCKER_4;
+"GSPEC",GSPEC;
+"GT",GT;
+"HALFSPACE_EQ_EMPTY_GE",HALFSPACE_EQ_EMPTY_GE;
+"HALFSPACE_EQ_EMPTY_GT",HALFSPACE_EQ_EMPTY_GT;
+"HALFSPACE_EQ_EMPTY_LE",HALFSPACE_EQ_EMPTY_LE;
+"HALFSPACE_EQ_EMPTY_LT",HALFSPACE_EQ_EMPTY_LT;
+"HAS_ANTIDERIVATIVE_LIMIT",HAS_ANTIDERIVATIVE_LIMIT;
+"HAS_ANTIDERIVATIVE_SEQUENCE",HAS_ANTIDERIVATIVE_SEQUENCE;
+"HAS_BOUNDED_SETVARIATION_ON",HAS_BOUNDED_SETVARIATION_ON;
+"HAS_BOUNDED_SETVARIATION_ON_0",HAS_BOUNDED_SETVARIATION_ON_0;
+"HAS_BOUNDED_SETVARIATION_ON_ADD",HAS_BOUNDED_SETVARIATION_ON_ADD;
+"HAS_BOUNDED_SETVARIATION_ON_CMUL",HAS_BOUNDED_SETVARIATION_ON_CMUL;
+"HAS_BOUNDED_SETVARIATION_ON_COMPONENTWISE",HAS_BOUNDED_SETVARIATION_ON_COMPONENTWISE;
+"HAS_BOUNDED_SETVARIATION_ON_COMPOSE_LINEAR",HAS_BOUNDED_SETVARIATION_ON_COMPOSE_LINEAR;
+"HAS_BOUNDED_SETVARIATION_ON_DIVISION",HAS_BOUNDED_SETVARIATION_ON_DIVISION;
+"HAS_BOUNDED_SETVARIATION_ON_ELEMENTARY",HAS_BOUNDED_SETVARIATION_ON_ELEMENTARY;
+"HAS_BOUNDED_SETVARIATION_ON_EQ",HAS_BOUNDED_SETVARIATION_ON_EQ;
+"HAS_BOUNDED_SETVARIATION_ON_IMP_BOUNDED_ON_SUBINTERVALS",HAS_BOUNDED_SETVARIATION_ON_IMP_BOUNDED_ON_SUBINTERVALS;
+"HAS_BOUNDED_SETVARIATION_ON_INTERVAL",HAS_BOUNDED_SETVARIATION_ON_INTERVAL;
+"HAS_BOUNDED_SETVARIATION_ON_NEG",HAS_BOUNDED_SETVARIATION_ON_NEG;
+"HAS_BOUNDED_SETVARIATION_ON_NORM",HAS_BOUNDED_SETVARIATION_ON_NORM;
+"HAS_BOUNDED_SETVARIATION_ON_NULL",HAS_BOUNDED_SETVARIATION_ON_NULL;
+"HAS_BOUNDED_SETVARIATION_ON_SUB",HAS_BOUNDED_SETVARIATION_ON_SUB;
+"HAS_BOUNDED_SETVARIATION_ON_SUBSET",HAS_BOUNDED_SETVARIATION_ON_SUBSET;
+"HAS_BOUNDED_SETVARIATION_ON_UNIV",HAS_BOUNDED_SETVARIATION_ON_UNIV;
+"HAS_BOUNDED_SETVARIATION_REFLECT2_EQ",HAS_BOUNDED_SETVARIATION_REFLECT2_EQ;
+"HAS_BOUNDED_SETVARIATION_TRANSLATION",HAS_BOUNDED_SETVARIATION_TRANSLATION;
+"HAS_BOUNDED_SETVARIATION_TRANSLATION2_EQ",HAS_BOUNDED_SETVARIATION_TRANSLATION2_EQ;
+"HAS_BOUNDED_SETVARIATION_WORKS",HAS_BOUNDED_SETVARIATION_WORKS;
+"HAS_BOUNDED_SETVARIATION_WORKS_ON_ELEMENTARY",HAS_BOUNDED_SETVARIATION_WORKS_ON_ELEMENTARY;
+"HAS_BOUNDED_SETVARIATION_WORKS_ON_INTERVAL",HAS_BOUNDED_SETVARIATION_WORKS_ON_INTERVAL;
+"HAS_BOUNDED_VARIATION_ABSOLUTELY_INTEGRABLE_DERIVATIVE",HAS_BOUNDED_VARIATION_ABSOLUTELY_INTEGRABLE_DERIVATIVE;
+"HAS_BOUNDED_VARIATION_AFFINITY2_EQ",HAS_BOUNDED_VARIATION_AFFINITY2_EQ;
+"HAS_BOUNDED_VARIATION_AFFINITY_EQ",HAS_BOUNDED_VARIATION_AFFINITY_EQ;
+"HAS_BOUNDED_VARIATION_COMPOSE_DECREASING",HAS_BOUNDED_VARIATION_COMPOSE_DECREASING;
+"HAS_BOUNDED_VARIATION_COMPOSE_INCREASING",HAS_BOUNDED_VARIATION_COMPOSE_INCREASING;
+"HAS_BOUNDED_VARIATION_COUNTABLE_DISCONTINUITIES",HAS_BOUNDED_VARIATION_COUNTABLE_DISCONTINUITIES;
+"HAS_BOUNDED_VARIATION_DARBOUX",HAS_BOUNDED_VARIATION_DARBOUX;
+"HAS_BOUNDED_VARIATION_DARBOUX_STRICT",HAS_BOUNDED_VARIATION_DARBOUX_STRICT;
+"HAS_BOUNDED_VARIATION_DARBOUX_STRONG",HAS_BOUNDED_VARIATION_DARBOUX_STRONG;
+"HAS_BOUNDED_VARIATION_INTEGRABLE_NORM_DERIVATIVE",HAS_BOUNDED_VARIATION_INTEGRABLE_NORM_DERIVATIVE;
+"HAS_BOUNDED_VARIATION_ON_ADD",HAS_BOUNDED_VARIATION_ON_ADD;
+"HAS_BOUNDED_VARIATION_ON_CMUL",HAS_BOUNDED_VARIATION_ON_CMUL;
+"HAS_BOUNDED_VARIATION_ON_COMBINE",HAS_BOUNDED_VARIATION_ON_COMBINE;
+"HAS_BOUNDED_VARIATION_ON_COMPONENTWISE",HAS_BOUNDED_VARIATION_ON_COMPONENTWISE;
+"HAS_BOUNDED_VARIATION_ON_COMPOSE_LINEAR",HAS_BOUNDED_VARIATION_ON_COMPOSE_LINEAR;
+"HAS_BOUNDED_VARIATION_ON_CONST",HAS_BOUNDED_VARIATION_ON_CONST;
+"HAS_BOUNDED_VARIATION_ON_DIVISION",HAS_BOUNDED_VARIATION_ON_DIVISION;
+"HAS_BOUNDED_VARIATION_ON_EMPTY",HAS_BOUNDED_VARIATION_ON_EMPTY;
+"HAS_BOUNDED_VARIATION_ON_EQ",HAS_BOUNDED_VARIATION_ON_EQ;
+"HAS_BOUNDED_VARIATION_ON_ID",HAS_BOUNDED_VARIATION_ON_ID;
+"HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_INTERVAL",HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_INTERVAL;
+"HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_SUBINTERVALS",HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_SUBINTERVALS;
+"HAS_BOUNDED_VARIATION_ON_LINEAR_IMAGE",HAS_BOUNDED_VARIATION_ON_LINEAR_IMAGE;
+"HAS_BOUNDED_VARIATION_ON_MAX",HAS_BOUNDED_VARIATION_ON_MAX;
+"HAS_BOUNDED_VARIATION_ON_MIN",HAS_BOUNDED_VARIATION_ON_MIN;
+"HAS_BOUNDED_VARIATION_ON_MUL",HAS_BOUNDED_VARIATION_ON_MUL;
+"HAS_BOUNDED_VARIATION_ON_NEG",HAS_BOUNDED_VARIATION_ON_NEG;
+"HAS_BOUNDED_VARIATION_ON_NORM",HAS_BOUNDED_VARIATION_ON_NORM;
+"HAS_BOUNDED_VARIATION_ON_NULL",HAS_BOUNDED_VARIATION_ON_NULL;
+"HAS_BOUNDED_VARIATION_ON_REFLECT",HAS_BOUNDED_VARIATION_ON_REFLECT;
+"HAS_BOUNDED_VARIATION_ON_REFLECT_INTERVAL",HAS_BOUNDED_VARIATION_ON_REFLECT_INTERVAL;
+"HAS_BOUNDED_VARIATION_ON_SUB",HAS_BOUNDED_VARIATION_ON_SUB;
+"HAS_BOUNDED_VARIATION_ON_SUBSET",HAS_BOUNDED_VARIATION_ON_SUBSET;
+"HAS_BOUNDED_VARIATION_REFLECT2_EQ",HAS_BOUNDED_VARIATION_REFLECT2_EQ;
+"HAS_BOUNDED_VARIATION_REFLECT_EQ",HAS_BOUNDED_VARIATION_REFLECT_EQ;
+"HAS_BOUNDED_VARIATION_REFLECT_EQ_INTERVAL",HAS_BOUNDED_VARIATION_REFLECT_EQ_INTERVAL;
+"HAS_BOUNDED_VARIATION_TRANSLATION",HAS_BOUNDED_VARIATION_TRANSLATION;
+"HAS_BOUNDED_VARIATION_TRANSLATION2_EQ",HAS_BOUNDED_VARIATION_TRANSLATION2_EQ;
+"HAS_BOUNDED_VARIATION_TRANSLATION_EQ",HAS_BOUNDED_VARIATION_TRANSLATION_EQ;
+"HAS_BOUNDED_VARIATION_TRANSLATION_EQ_INTERVAL",HAS_BOUNDED_VARIATION_TRANSLATION_EQ_INTERVAL;
+"HAS_BOUNDED_VECTOR_VARIATION_LEFT_LIMIT",HAS_BOUNDED_VECTOR_VARIATION_LEFT_LIMIT;
+"HAS_BOUNDED_VECTOR_VARIATION_RIGHT_LIMIT",HAS_BOUNDED_VECTOR_VARIATION_RIGHT_LIMIT;
+"HAS_DERIVATIVE_ADD",HAS_DERIVATIVE_ADD;
+"HAS_DERIVATIVE_AT",HAS_DERIVATIVE_AT;
+"HAS_DERIVATIVE_AT_ALT",HAS_DERIVATIVE_AT_ALT;
+"HAS_DERIVATIVE_AT_WITHIN",HAS_DERIVATIVE_AT_WITHIN;
+"HAS_DERIVATIVE_BILINEAR_AT",HAS_DERIVATIVE_BILINEAR_AT;
+"HAS_DERIVATIVE_BILINEAR_WITHIN",HAS_DERIVATIVE_BILINEAR_WITHIN;
+"HAS_DERIVATIVE_CMUL",HAS_DERIVATIVE_CMUL;
+"HAS_DERIVATIVE_CMUL_EQ",HAS_DERIVATIVE_CMUL_EQ;
+"HAS_DERIVATIVE_COMPONENTWISE_AT",HAS_DERIVATIVE_COMPONENTWISE_AT;
+"HAS_DERIVATIVE_COMPONENTWISE_WITHIN",HAS_DERIVATIVE_COMPONENTWISE_WITHIN;
+"HAS_DERIVATIVE_CONST",HAS_DERIVATIVE_CONST;
+"HAS_DERIVATIVE_ID",HAS_DERIVATIVE_ID;
+"HAS_DERIVATIVE_IMP_DIFFERENTIABLE",HAS_DERIVATIVE_IMP_DIFFERENTIABLE;
+"HAS_DERIVATIVE_INVERSE",HAS_DERIVATIVE_INVERSE;
+"HAS_DERIVATIVE_INVERSE_BASIC",HAS_DERIVATIVE_INVERSE_BASIC;
+"HAS_DERIVATIVE_INVERSE_BASIC_X",HAS_DERIVATIVE_INVERSE_BASIC_X;
+"HAS_DERIVATIVE_INVERSE_DIEUDONNE",HAS_DERIVATIVE_INVERSE_DIEUDONNE;
+"HAS_DERIVATIVE_INVERSE_ON",HAS_DERIVATIVE_INVERSE_ON;
+"HAS_DERIVATIVE_INVERSE_STRONG",HAS_DERIVATIVE_INVERSE_STRONG;
+"HAS_DERIVATIVE_INVERSE_STRONG_X",HAS_DERIVATIVE_INVERSE_STRONG_X;
+"HAS_DERIVATIVE_LIFT_COMPONENT",HAS_DERIVATIVE_LIFT_COMPONENT;
+"HAS_DERIVATIVE_LIFT_DOT",HAS_DERIVATIVE_LIFT_DOT;
+"HAS_DERIVATIVE_LINEAR",HAS_DERIVATIVE_LINEAR;
+"HAS_DERIVATIVE_LOCALLY_INJECTIVE",HAS_DERIVATIVE_LOCALLY_INJECTIVE;
+"HAS_DERIVATIVE_MUL_AT",HAS_DERIVATIVE_MUL_AT;
+"HAS_DERIVATIVE_MUL_WITHIN",HAS_DERIVATIVE_MUL_WITHIN;
+"HAS_DERIVATIVE_NEG",HAS_DERIVATIVE_NEG;
+"HAS_DERIVATIVE_NEG_EQ",HAS_DERIVATIVE_NEG_EQ;
+"HAS_DERIVATIVE_SEQUENCE",HAS_DERIVATIVE_SEQUENCE;
+"HAS_DERIVATIVE_SEQUENCE_LIPSCHITZ",HAS_DERIVATIVE_SEQUENCE_LIPSCHITZ;
+"HAS_DERIVATIVE_SERIES",HAS_DERIVATIVE_SERIES;
+"HAS_DERIVATIVE_SQNORM_AT",HAS_DERIVATIVE_SQNORM_AT;
+"HAS_DERIVATIVE_SUB",HAS_DERIVATIVE_SUB;
+"HAS_DERIVATIVE_TRANSFORM_AT",HAS_DERIVATIVE_TRANSFORM_AT;
+"HAS_DERIVATIVE_TRANSFORM_WITHIN",HAS_DERIVATIVE_TRANSFORM_WITHIN;
+"HAS_DERIVATIVE_TRANSFORM_WITHIN_OPEN",HAS_DERIVATIVE_TRANSFORM_WITHIN_OPEN;
+"HAS_DERIVATIVE_VMUL_COMPONENT",HAS_DERIVATIVE_VMUL_COMPONENT;
+"HAS_DERIVATIVE_VMUL_DROP",HAS_DERIVATIVE_VMUL_DROP;
+"HAS_DERIVATIVE_VSUM",HAS_DERIVATIVE_VSUM;
+"HAS_DERIVATIVE_VSUM_NUMSEG",HAS_DERIVATIVE_VSUM_NUMSEG;
+"HAS_DERIVATIVE_WITHIN",HAS_DERIVATIVE_WITHIN;
+"HAS_DERIVATIVE_WITHIN_ALT",HAS_DERIVATIVE_WITHIN_ALT;
+"HAS_DERIVATIVE_WITHIN_OPEN",HAS_DERIVATIVE_WITHIN_OPEN;
+"HAS_DERIVATIVE_WITHIN_SUBSET",HAS_DERIVATIVE_WITHIN_SUBSET;
+"HAS_DERIVATIVE_ZERO_CONNECTED_CONSTANT",HAS_DERIVATIVE_ZERO_CONNECTED_CONSTANT;
+"HAS_DERIVATIVE_ZERO_CONNECTED_UNIQUE",HAS_DERIVATIVE_ZERO_CONNECTED_UNIQUE;
+"HAS_DERIVATIVE_ZERO_CONSTANT",HAS_DERIVATIVE_ZERO_CONSTANT;
+"HAS_DERIVATIVE_ZERO_UNIQUE",HAS_DERIVATIVE_ZERO_UNIQUE;
+"HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_CONNECTED",HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_CONNECTED;
+"HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_CONVEX",HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_CONVEX;
+"HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_INTERVAL",HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_INTERVAL;
+"HAS_FRECHET_DERIVATIVE_UNIQUE_AT",HAS_FRECHET_DERIVATIVE_UNIQUE_AT;
+"HAS_INTEGRAL",HAS_INTEGRAL;
+"HAS_INTEGRAL_0",HAS_INTEGRAL_0;
+"HAS_INTEGRAL_0_EQ",HAS_INTEGRAL_0_EQ;
+"HAS_INTEGRAL_ADD",HAS_INTEGRAL_ADD;
+"HAS_INTEGRAL_AFFINITY",HAS_INTEGRAL_AFFINITY;
+"HAS_INTEGRAL_ALT",HAS_INTEGRAL_ALT;
+"HAS_INTEGRAL_BOUND",HAS_INTEGRAL_BOUND;
+"HAS_INTEGRAL_CLOSURE",HAS_INTEGRAL_CLOSURE;
+"HAS_INTEGRAL_CMUL",HAS_INTEGRAL_CMUL;
+"HAS_INTEGRAL_COMBINE",HAS_INTEGRAL_COMBINE;
+"HAS_INTEGRAL_COMBINE_DIVISION",HAS_INTEGRAL_COMBINE_DIVISION;
+"HAS_INTEGRAL_COMBINE_DIVISION_TOPDOWN",HAS_INTEGRAL_COMBINE_DIVISION_TOPDOWN;
+"HAS_INTEGRAL_COMBINE_TAGGED_DIVISION",HAS_INTEGRAL_COMBINE_TAGGED_DIVISION;
+"HAS_INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN",HAS_INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN;
+"HAS_INTEGRAL_COMPONENTWISE",HAS_INTEGRAL_COMPONENTWISE;
+"HAS_INTEGRAL_COMPONENT_LBOUND",HAS_INTEGRAL_COMPONENT_LBOUND;
+"HAS_INTEGRAL_COMPONENT_LE",HAS_INTEGRAL_COMPONENT_LE;
+"HAS_INTEGRAL_COMPONENT_NEG",HAS_INTEGRAL_COMPONENT_NEG;
+"HAS_INTEGRAL_COMPONENT_POS",HAS_INTEGRAL_COMPONENT_POS;
+"HAS_INTEGRAL_COMPONENT_UBOUND",HAS_INTEGRAL_COMPONENT_UBOUND;
+"HAS_INTEGRAL_CONST",HAS_INTEGRAL_CONST;
+"HAS_INTEGRAL_DIFF",HAS_INTEGRAL_DIFF;
+"HAS_INTEGRAL_DROP_LE",HAS_INTEGRAL_DROP_LE;
+"HAS_INTEGRAL_DROP_NEG",HAS_INTEGRAL_DROP_NEG;
+"HAS_INTEGRAL_DROP_POS",HAS_INTEGRAL_DROP_POS;
+"HAS_INTEGRAL_EMPTY",HAS_INTEGRAL_EMPTY;
+"HAS_INTEGRAL_EMPTY_EQ",HAS_INTEGRAL_EMPTY_EQ;
+"HAS_INTEGRAL_EQ",HAS_INTEGRAL_EQ;
+"HAS_INTEGRAL_EQ_EQ",HAS_INTEGRAL_EQ_EQ;
+"HAS_INTEGRAL_FACTOR_CONTENT",HAS_INTEGRAL_FACTOR_CONTENT;
+"HAS_INTEGRAL_INTEGRABLE",HAS_INTEGRAL_INTEGRABLE;
+"HAS_INTEGRAL_INTEGRABLE_INTEGRAL",HAS_INTEGRAL_INTEGRABLE_INTEGRAL;
+"HAS_INTEGRAL_INTEGRAL",HAS_INTEGRAL_INTEGRAL;
+"HAS_INTEGRAL_INTERIOR",HAS_INTEGRAL_INTERIOR;
+"HAS_INTEGRAL_IS_0",HAS_INTEGRAL_IS_0;
+"HAS_INTEGRAL_LINEAR",HAS_INTEGRAL_LINEAR;
+"HAS_INTEGRAL_NEG",HAS_INTEGRAL_NEG;
+"HAS_INTEGRAL_NEGLIGIBLE",HAS_INTEGRAL_NEGLIGIBLE;
+"HAS_INTEGRAL_NEGLIGIBLE_EQ",HAS_INTEGRAL_NEGLIGIBLE_EQ;
+"HAS_INTEGRAL_NORM_BOUND_INTEGRAL_COMPONENT",HAS_INTEGRAL_NORM_BOUND_INTEGRAL_COMPONENT;
+"HAS_INTEGRAL_NULL",HAS_INTEGRAL_NULL;
+"HAS_INTEGRAL_NULL_EQ",HAS_INTEGRAL_NULL_EQ;
+"HAS_INTEGRAL_ON_SUPERSET",HAS_INTEGRAL_ON_SUPERSET;
+"HAS_INTEGRAL_OPEN_INTERVAL",HAS_INTEGRAL_OPEN_INTERVAL;
+"HAS_INTEGRAL_REFL",HAS_INTEGRAL_REFL;
+"HAS_INTEGRAL_REFLECT",HAS_INTEGRAL_REFLECT;
+"HAS_INTEGRAL_REFLECT_LEMMA",HAS_INTEGRAL_REFLECT_LEMMA;
+"HAS_INTEGRAL_RESTRICT",HAS_INTEGRAL_RESTRICT;
+"HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVAL",HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVAL;
+"HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVALS_EQ",HAS_INTEGRAL_RESTRICT_CLOSED_SUBINTERVALS_EQ;
+"HAS_INTEGRAL_RESTRICT_INTER",HAS_INTEGRAL_RESTRICT_INTER;
+"HAS_INTEGRAL_RESTRICT_OPEN_SUBINTERVAL",HAS_INTEGRAL_RESTRICT_OPEN_SUBINTERVAL;
+"HAS_INTEGRAL_RESTRICT_UNIV",HAS_INTEGRAL_RESTRICT_UNIV;
+"HAS_INTEGRAL_SEPARATE_SIDES",HAS_INTEGRAL_SEPARATE_SIDES;
+"HAS_INTEGRAL_SPIKE",HAS_INTEGRAL_SPIKE;
+"HAS_INTEGRAL_SPIKE_EQ",HAS_INTEGRAL_SPIKE_EQ;
+"HAS_INTEGRAL_SPIKE_FINITE",HAS_INTEGRAL_SPIKE_FINITE;
+"HAS_INTEGRAL_SPIKE_FINITE_EQ",HAS_INTEGRAL_SPIKE_FINITE_EQ;
+"HAS_INTEGRAL_SPIKE_INTERIOR",HAS_INTEGRAL_SPIKE_INTERIOR;
+"HAS_INTEGRAL_SPIKE_INTERIOR_EQ",HAS_INTEGRAL_SPIKE_INTERIOR_EQ;
+"HAS_INTEGRAL_SPIKE_SET",HAS_INTEGRAL_SPIKE_SET;
+"HAS_INTEGRAL_SPIKE_SET_EQ",HAS_INTEGRAL_SPIKE_SET_EQ;
+"HAS_INTEGRAL_SPLIT",HAS_INTEGRAL_SPLIT;
+"HAS_INTEGRAL_STRADDLE_NULL",HAS_INTEGRAL_STRADDLE_NULL;
+"HAS_INTEGRAL_STRETCH",HAS_INTEGRAL_STRETCH;
+"HAS_INTEGRAL_SUB",HAS_INTEGRAL_SUB;
+"HAS_INTEGRAL_SUBSET_COMPONENT_LE",HAS_INTEGRAL_SUBSET_COMPONENT_LE;
+"HAS_INTEGRAL_SUBSET_DROP_LE",HAS_INTEGRAL_SUBSET_DROP_LE;
+"HAS_INTEGRAL_TWIDDLE",HAS_INTEGRAL_TWIDDLE;
+"HAS_INTEGRAL_UNION",HAS_INTEGRAL_UNION;
+"HAS_INTEGRAL_UNIONS",HAS_INTEGRAL_UNIONS;
+"HAS_INTEGRAL_UNIQUE",HAS_INTEGRAL_UNIQUE;
+"HAS_INTEGRAL_VSUM",HAS_INTEGRAL_VSUM;
+"HAS_MEASURE",HAS_MEASURE;
+"HAS_MEASURE_0",HAS_MEASURE_0;
+"HAS_MEASURE_AFFINITY",HAS_MEASURE_AFFINITY;
+"HAS_MEASURE_ALMOST",HAS_MEASURE_ALMOST;
+"HAS_MEASURE_ALMOST_EQ",HAS_MEASURE_ALMOST_EQ;
+"HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS",HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS;
+"HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS_BOUNDED",HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS_BOUNDED;
+"HAS_MEASURE_DIFF_NEGLIGIBLE",HAS_MEASURE_DIFF_NEGLIGIBLE;
+"HAS_MEASURE_DIFF_NEGLIGIBLE_EQ",HAS_MEASURE_DIFF_NEGLIGIBLE_EQ;
+"HAS_MEASURE_DIFF_SUBSET",HAS_MEASURE_DIFF_SUBSET;
+"HAS_MEASURE_DISJOINT_UNION",HAS_MEASURE_DISJOINT_UNION;
+"HAS_MEASURE_DISJOINT_UNIONS",HAS_MEASURE_DISJOINT_UNIONS;
+"HAS_MEASURE_DISJOINT_UNIONS_IMAGE",HAS_MEASURE_DISJOINT_UNIONS_IMAGE;
+"HAS_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG",HAS_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG;
+"HAS_MEASURE_ELEMENTARY",HAS_MEASURE_ELEMENTARY;
+"HAS_MEASURE_EMPTY",HAS_MEASURE_EMPTY;
+"HAS_MEASURE_IMAGE_STD_SIMPLEX",HAS_MEASURE_IMAGE_STD_SIMPLEX;
+"HAS_MEASURE_IMP_MEASURABLE",HAS_MEASURE_IMP_MEASURABLE;
+"HAS_MEASURE_INNER_OUTER",HAS_MEASURE_INNER_OUTER;
+"HAS_MEASURE_INNER_OUTER_LE",HAS_MEASURE_INNER_OUTER_LE;
+"HAS_MEASURE_INTERVAL",HAS_MEASURE_INTERVAL;
+"HAS_MEASURE_LIMIT",HAS_MEASURE_LIMIT;
+"HAS_MEASURE_LINEAR_IMAGE",HAS_MEASURE_LINEAR_IMAGE;
+"HAS_MEASURE_LINEAR_IMAGE_ALT",HAS_MEASURE_LINEAR_IMAGE_ALT;
+"HAS_MEASURE_LINEAR_IMAGE_SAME",HAS_MEASURE_LINEAR_IMAGE_SAME;
+"HAS_MEASURE_LINEAR_SUFFICIENT",HAS_MEASURE_LINEAR_SUFFICIENT;
+"HAS_MEASURE_MEASURABLE_MEASURE",HAS_MEASURE_MEASURABLE_MEASURE;
+"HAS_MEASURE_MEASURE",HAS_MEASURE_MEASURE;
+"HAS_MEASURE_NEGLIGIBLE_SYMDIFF",HAS_MEASURE_NEGLIGIBLE_SYMDIFF;
+"HAS_MEASURE_NEGLIGIBLE_UNION",HAS_MEASURE_NEGLIGIBLE_UNION;
+"HAS_MEASURE_NEGLIGIBLE_UNIONS",HAS_MEASURE_NEGLIGIBLE_UNIONS;
+"HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE",HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE;
+"HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG",HAS_MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG;
+"HAS_MEASURE_NESTED_INTERS",HAS_MEASURE_NESTED_INTERS;
+"HAS_MEASURE_NESTED_UNIONS",HAS_MEASURE_NESTED_UNIONS;
+"HAS_MEASURE_ORTHOGONAL_IMAGE",HAS_MEASURE_ORTHOGONAL_IMAGE;
+"HAS_MEASURE_ORTHOGONAL_IMAGE_EQ",HAS_MEASURE_ORTHOGONAL_IMAGE_EQ;
+"HAS_MEASURE_POS_LE",HAS_MEASURE_POS_LE;
+"HAS_MEASURE_SCALING",HAS_MEASURE_SCALING;
+"HAS_MEASURE_SCALING_EQ",HAS_MEASURE_SCALING_EQ;
+"HAS_MEASURE_SHEAR_INTERVAL",HAS_MEASURE_SHEAR_INTERVAL;
+"HAS_MEASURE_SIMPLEX",HAS_MEASURE_SIMPLEX;
+"HAS_MEASURE_SIMPLEX_0",HAS_MEASURE_SIMPLEX_0;
+"HAS_MEASURE_STD_SIMPLEX",HAS_MEASURE_STD_SIMPLEX;
+"HAS_MEASURE_STRETCH",HAS_MEASURE_STRETCH;
+"HAS_MEASURE_SUBSET",HAS_MEASURE_SUBSET;
+"HAS_MEASURE_TETRAHEDRON",HAS_MEASURE_TETRAHEDRON;
+"HAS_MEASURE_TRANSLATION",HAS_MEASURE_TRANSLATION;
+"HAS_MEASURE_TRANSLATION_EQ",HAS_MEASURE_TRANSLATION_EQ;
+"HAS_MEASURE_TRIANGLE",HAS_MEASURE_TRIANGLE;
+"HAS_MEASURE_UNION_NEGLIGIBLE",HAS_MEASURE_UNION_NEGLIGIBLE;
+"HAS_MEASURE_UNION_NEGLIGIBLE_EQ",HAS_MEASURE_UNION_NEGLIGIBLE_EQ;
+"HAS_MEASURE_UNIQUE",HAS_MEASURE_UNIQUE;
+"HAS_SIZE",HAS_SIZE;
+"HAS_SIZE_0",HAS_SIZE_0;
+"HAS_SIZE_1",HAS_SIZE_1;
+"HAS_SIZE_1_EXISTS",HAS_SIZE_1_EXISTS;
+"HAS_SIZE_2",HAS_SIZE_2;
+"HAS_SIZE_2_EXISTS",HAS_SIZE_2_EXISTS;
+"HAS_SIZE_3",HAS_SIZE_3;
+"HAS_SIZE_4",HAS_SIZE_4;
+"HAS_SIZE_BOOL",HAS_SIZE_BOOL;
+"HAS_SIZE_CARD",HAS_SIZE_CARD;
+"HAS_SIZE_CART_UNIV",HAS_SIZE_CART_UNIV;
+"HAS_SIZE_CLAUSES",HAS_SIZE_CLAUSES;
+"HAS_SIZE_CROSS",HAS_SIZE_CROSS;
+"HAS_SIZE_DIFF",HAS_SIZE_DIFF;
+"HAS_SIZE_FACES_OF_SIMPLEX",HAS_SIZE_FACES_OF_SIMPLEX;
+"HAS_SIZE_FINITE_IMAGE",HAS_SIZE_FINITE_IMAGE;
+"HAS_SIZE_FUNSPACE",HAS_SIZE_FUNSPACE;
+"HAS_SIZE_FUNSPACE_UNIV",HAS_SIZE_FUNSPACE_UNIV;
+"HAS_SIZE_IMAGE_INJ",HAS_SIZE_IMAGE_INJ;
+"HAS_SIZE_IMAGE_INJ_EQ",HAS_SIZE_IMAGE_INJ_EQ;
+"HAS_SIZE_INDEX",HAS_SIZE_INDEX;
+"HAS_SIZE_INTSEG_INT",HAS_SIZE_INTSEG_INT;
+"HAS_SIZE_INTSEG_NUM",HAS_SIZE_INTSEG_NUM;
+"HAS_SIZE_MULTIVECTOR",HAS_SIZE_MULTIVECTOR;
+"HAS_SIZE_NUMSEG",HAS_SIZE_NUMSEG;
+"HAS_SIZE_NUMSEG_1",HAS_SIZE_NUMSEG_1;
+"HAS_SIZE_NUMSEG_LE",HAS_SIZE_NUMSEG_LE;
+"HAS_SIZE_NUMSEG_LT",HAS_SIZE_NUMSEG_LT;
+"HAS_SIZE_PCROSS",HAS_SIZE_PCROSS;
+"HAS_SIZE_PERMUTATIONS",HAS_SIZE_PERMUTATIONS;
+"HAS_SIZE_POWERSET",HAS_SIZE_POWERSET;
+"HAS_SIZE_PRODUCT",HAS_SIZE_PRODUCT;
+"HAS_SIZE_PRODUCT_DEPENDENT",HAS_SIZE_PRODUCT_DEPENDENT;
+"HAS_SIZE_SET_OF_LIST",HAS_SIZE_SET_OF_LIST;
+"HAS_SIZE_STDBASIS",HAS_SIZE_STDBASIS;
+"HAS_SIZE_SUC",HAS_SIZE_SUC;
+"HAS_SIZE_UNION",HAS_SIZE_UNION;
+"HAS_SIZE_UNIONS",HAS_SIZE_UNIONS;
+"HAS_VECTOR_DERIVATIVE_ADD",HAS_VECTOR_DERIVATIVE_ADD;
+"HAS_VECTOR_DERIVATIVE_AT_WITHIN",HAS_VECTOR_DERIVATIVE_AT_WITHIN;
+"HAS_VECTOR_DERIVATIVE_BILINEAR_AT",HAS_VECTOR_DERIVATIVE_BILINEAR_AT;
+"HAS_VECTOR_DERIVATIVE_BILINEAR_WITHIN",HAS_VECTOR_DERIVATIVE_BILINEAR_WITHIN;
+"HAS_VECTOR_DERIVATIVE_CMUL",HAS_VECTOR_DERIVATIVE_CMUL;
+"HAS_VECTOR_DERIVATIVE_CMUL_EQ",HAS_VECTOR_DERIVATIVE_CMUL_EQ;
+"HAS_VECTOR_DERIVATIVE_CONST",HAS_VECTOR_DERIVATIVE_CONST;
+"HAS_VECTOR_DERIVATIVE_ID",HAS_VECTOR_DERIVATIVE_ID;
+"HAS_VECTOR_DERIVATIVE_INDEFINITE_INTEGRAL",HAS_VECTOR_DERIVATIVE_INDEFINITE_INTEGRAL;
+"HAS_VECTOR_DERIVATIVE_NEG",HAS_VECTOR_DERIVATIVE_NEG;
+"HAS_VECTOR_DERIVATIVE_NEG_EQ",HAS_VECTOR_DERIVATIVE_NEG_EQ;
+"HAS_VECTOR_DERIVATIVE_SUB",HAS_VECTOR_DERIVATIVE_SUB;
+"HAS_VECTOR_DERIVATIVE_TRANSFORM_AT",HAS_VECTOR_DERIVATIVE_TRANSFORM_AT;
+"HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN",HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN;
+"HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN_OPEN",HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN_OPEN;
+"HAS_VECTOR_DERIVATIVE_UNIQUE_AT",HAS_VECTOR_DERIVATIVE_UNIQUE_AT;
+"HAS_VECTOR_DERIVATIVE_WITHIN_SUBSET",HAS_VECTOR_DERIVATIVE_WITHIN_SUBSET;
+"HD",HD;
+"HD_APPEND",HD_APPEND;
+"HEINE_BOREL_IMP_BOLZANO_WEIERSTRASS",HEINE_BOREL_IMP_BOLZANO_WEIERSTRASS;
+"HEINE_BOREL_LEMMA",HEINE_BOREL_LEMMA;
+"HELLY",HELLY;
+"HELLY_ALT",HELLY_ALT;
+"HELLY_CLOSED",HELLY_CLOSED;
+"HELLY_CLOSED_ALT",HELLY_CLOSED_ALT;
+"HELLY_COMPACT",HELLY_COMPACT;
+"HELLY_COMPACT_ALT",HELLY_COMPACT_ALT;
+"HELLY_INDUCT",HELLY_INDUCT;
+"HENSTOCK_LEMMA",HENSTOCK_LEMMA;
+"HENSTOCK_LEMMA_PART1",HENSTOCK_LEMMA_PART1;
+"HENSTOCK_LEMMA_PART2",HENSTOCK_LEMMA_PART2;
+"HOMEOMORPHIC_AFFINE_SETS",HOMEOMORPHIC_AFFINE_SETS;
+"HOMEOMORPHIC_AFFINITY",HOMEOMORPHIC_AFFINITY;
+"HOMEOMORPHIC_ANRNESS",HOMEOMORPHIC_ANRNESS;
+"HOMEOMORPHIC_ARC_IMAGES",HOMEOMORPHIC_ARC_IMAGES;
+"HOMEOMORPHIC_ARC_IMAGE_INTERVAL",HOMEOMORPHIC_ARC_IMAGE_INTERVAL;
+"HOMEOMORPHIC_ARC_IMAGE_SEGMENT",HOMEOMORPHIC_ARC_IMAGE_SEGMENT;
+"HOMEOMORPHIC_BALLS",HOMEOMORPHIC_BALLS;
+"HOMEOMORPHIC_BALL_UNIV",HOMEOMORPHIC_BALL_UNIV;
+"HOMEOMORPHIC_CBALLS",HOMEOMORPHIC_CBALLS;
+"HOMEOMORPHIC_CLOSED_INTERVALS",HOMEOMORPHIC_CLOSED_INTERVALS;
+"HOMEOMORPHIC_COMPACT",HOMEOMORPHIC_COMPACT;
+"HOMEOMORPHIC_COMPACTNESS",HOMEOMORPHIC_COMPACTNESS;
+"HOMEOMORPHIC_COMPACT_ARNESS",HOMEOMORPHIC_COMPACT_ARNESS;
+"HOMEOMORPHIC_CONNECTEDNESS",HOMEOMORPHIC_CONNECTEDNESS;
+"HOMEOMORPHIC_CONTRACTIBLE",HOMEOMORPHIC_CONTRACTIBLE;
+"HOMEOMORPHIC_CONTRACTIBLE_EQ",HOMEOMORPHIC_CONTRACTIBLE_EQ;
+"HOMEOMORPHIC_CONVEX_COMPACT",HOMEOMORPHIC_CONVEX_COMPACT;
+"HOMEOMORPHIC_CONVEX_COMPACT_CBALL",HOMEOMORPHIC_CONVEX_COMPACT_CBALL;
+"HOMEOMORPHIC_CONVEX_COMPACT_SETS",HOMEOMORPHIC_CONVEX_COMPACT_SETS;
+"HOMEOMORPHIC_EMPTY",HOMEOMORPHIC_EMPTY;
+"HOMEOMORPHIC_FINITE",HOMEOMORPHIC_FINITE;
+"HOMEOMORPHIC_FINITE_STRONG",HOMEOMORPHIC_FINITE_STRONG;
+"HOMEOMORPHIC_FIXPOINT_PROPERTY",HOMEOMORPHIC_FIXPOINT_PROPERTY;
+"HOMEOMORPHIC_HYPERPLANES",HOMEOMORPHIC_HYPERPLANES;
+"HOMEOMORPHIC_HYPERPLANE_STANDARD_HYPERPLANE",HOMEOMORPHIC_HYPERPLANE_STANDARD_HYPERPLANE;
+"HOMEOMORPHIC_HYPERPLANE_UNIV",HOMEOMORPHIC_HYPERPLANE_UNIV;
+"HOMEOMORPHIC_IMP_CARD_EQ",HOMEOMORPHIC_IMP_CARD_EQ;
+"HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT",HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT;
+"HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_LEFT_EQ",HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_LEFT_EQ;
+"HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ",HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ;
+"HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_SELF",HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_SELF;
+"HOMEOMORPHIC_LOCALLY",HOMEOMORPHIC_LOCALLY;
+"HOMEOMORPHIC_LOCAL_COMPACTNESS",HOMEOMORPHIC_LOCAL_COMPACTNESS;
+"HOMEOMORPHIC_LOCAL_CONNECTEDNESS",HOMEOMORPHIC_LOCAL_CONNECTEDNESS;
+"HOMEOMORPHIC_LOCAL_PATH_CONNECTEDNESS",HOMEOMORPHIC_LOCAL_PATH_CONNECTEDNESS;
+"HOMEOMORPHIC_MINIMAL",HOMEOMORPHIC_MINIMAL;
+"HOMEOMORPHIC_MONOTONE_IMAGE_INTERVAL",HOMEOMORPHIC_MONOTONE_IMAGE_INTERVAL;
+"HOMEOMORPHIC_ONE_POINT_COMPACTIFICATIONS",HOMEOMORPHIC_ONE_POINT_COMPACTIFICATIONS;
+"HOMEOMORPHIC_OPEN_INTERVALS",HOMEOMORPHIC_OPEN_INTERVALS;
+"HOMEOMORPHIC_OPEN_INTERVALS_1",HOMEOMORPHIC_OPEN_INTERVALS_1;
+"HOMEOMORPHIC_OPEN_INTERVAL_UNIV",HOMEOMORPHIC_OPEN_INTERVAL_UNIV;
+"HOMEOMORPHIC_OPEN_INTERVAL_UNIV_1",HOMEOMORPHIC_OPEN_INTERVAL_UNIV_1;
+"HOMEOMORPHIC_PATH_CONNECTEDNESS",HOMEOMORPHIC_PATH_CONNECTEDNESS;
+"HOMEOMORPHIC_PCROSS",HOMEOMORPHIC_PCROSS;
+"HOMEOMORPHIC_PCROSS_ASSOC",HOMEOMORPHIC_PCROSS_ASSOC;
+"HOMEOMORPHIC_PCROSS_SING",HOMEOMORPHIC_PCROSS_SING;
+"HOMEOMORPHIC_PCROSS_SYM",HOMEOMORPHIC_PCROSS_SYM;
+"HOMEOMORPHIC_PUNCTURED_AFFINE_SPHERE_AFFINE",HOMEOMORPHIC_PUNCTURED_AFFINE_SPHERE_AFFINE;
+"HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE",HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE;
+"HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE_GEN",HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE_GEN;
+"HOMEOMORPHIC_PUNCTURED_SPHERE_HYPERPLANE",HOMEOMORPHIC_PUNCTURED_SPHERE_HYPERPLANE;
+"HOMEOMORPHIC_PUNCTURED_SPHERE_UNIV",HOMEOMORPHIC_PUNCTURED_SPHERE_UNIV;
+"HOMEOMORPHIC_REFL",HOMEOMORPHIC_REFL;
+"HOMEOMORPHIC_RELATIVE_FRONTIERS_CONVEX_BOUNDED_SETS",HOMEOMORPHIC_RELATIVE_FRONTIERS_CONVEX_BOUNDED_SETS;
+"HOMEOMORPHIC_SCALING",HOMEOMORPHIC_SCALING;
+"HOMEOMORPHIC_SCALING_LEFT",HOMEOMORPHIC_SCALING_LEFT;
+"HOMEOMORPHIC_SCALING_RIGHT",HOMEOMORPHIC_SCALING_RIGHT;
+"HOMEOMORPHIC_SIMPLY_CONNECTED",HOMEOMORPHIC_SIMPLY_CONNECTED;
+"HOMEOMORPHIC_SIMPLY_CONNECTED_EQ",HOMEOMORPHIC_SIMPLY_CONNECTED_EQ;
+"HOMEOMORPHIC_SING",HOMEOMORPHIC_SING;
+"HOMEOMORPHIC_SPHERES",HOMEOMORPHIC_SPHERES;
+"HOMEOMORPHIC_STANDARD_HYPERPLANE_HYPERPLANE",HOMEOMORPHIC_STANDARD_HYPERPLANE_HYPERPLANE;
+"HOMEOMORPHIC_SUBSPACES",HOMEOMORPHIC_SUBSPACES;
+"HOMEOMORPHIC_SYM",HOMEOMORPHIC_SYM;
+"HOMEOMORPHIC_TRANS",HOMEOMORPHIC_TRANS;
+"HOMEOMORPHIC_TRANSLATION",HOMEOMORPHIC_TRANSLATION;
+"HOMEOMORPHIC_TRANSLATION_LEFT_EQ",HOMEOMORPHIC_TRANSLATION_LEFT_EQ;
+"HOMEOMORPHIC_TRANSLATION_RIGHT_EQ",HOMEOMORPHIC_TRANSLATION_RIGHT_EQ;
+"HOMEOMORPHIC_TRANSLATION_SELF",HOMEOMORPHIC_TRANSLATION_SELF;
+"HOMEOMORPHISM",HOMEOMORPHISM;
+"HOMEOMORPHISM_ARC",HOMEOMORPHISM_ARC;
+"HOMEOMORPHISM_COMPACT",HOMEOMORPHISM_COMPACT;
+"HOMEOMORPHISM_COMPOSE",HOMEOMORPHISM_COMPOSE;
+"HOMEOMORPHISM_FROM_COMPOSITION_INJECTIVE",HOMEOMORPHISM_FROM_COMPOSITION_INJECTIVE;
+"HOMEOMORPHISM_FROM_COMPOSITION_SURJECTIVE",HOMEOMORPHISM_FROM_COMPOSITION_SURJECTIVE;
+"HOMEOMORPHISM_GROUPING_POINTS_EXISTS",HOMEOMORPHISM_GROUPING_POINTS_EXISTS;
+"HOMEOMORPHISM_GROUPING_POINTS_EXISTS_GEN",HOMEOMORPHISM_GROUPING_POINTS_EXISTS_GEN;
+"HOMEOMORPHISM_I",HOMEOMORPHISM_I;
+"HOMEOMORPHISM_ID",HOMEOMORPHISM_ID;
+"HOMEOMORPHISM_IMP_CLOSED_MAP",HOMEOMORPHISM_IMP_CLOSED_MAP;
+"HOMEOMORPHISM_IMP_COVERING_SPACE",HOMEOMORPHISM_IMP_COVERING_SPACE;
+"HOMEOMORPHISM_IMP_OPEN_MAP",HOMEOMORPHISM_IMP_OPEN_MAP;
+"HOMEOMORPHISM_IMP_QUOTIENT_MAP",HOMEOMORPHISM_IMP_QUOTIENT_MAP;
+"HOMEOMORPHISM_INJECTIVE_CLOSED_MAP",HOMEOMORPHISM_INJECTIVE_CLOSED_MAP;
+"HOMEOMORPHISM_INJECTIVE_CLOSED_MAP_EQ",HOMEOMORPHISM_INJECTIVE_CLOSED_MAP_EQ;
+"HOMEOMORPHISM_INJECTIVE_OPEN_MAP",HOMEOMORPHISM_INJECTIVE_OPEN_MAP;
+"HOMEOMORPHISM_INJECTIVE_OPEN_MAP_EQ",HOMEOMORPHISM_INJECTIVE_OPEN_MAP_EQ;
+"HOMEOMORPHISM_LOCALLY",HOMEOMORPHISM_LOCALLY;
+"HOMEOMORPHISM_MOVING_POINTS_EXISTS",HOMEOMORPHISM_MOVING_POINTS_EXISTS;
+"HOMEOMORPHISM_MOVING_POINTS_EXISTS_GEN",HOMEOMORPHISM_MOVING_POINTS_EXISTS_GEN;
+"HOMEOMORPHISM_MOVING_POINT_EXISTS",HOMEOMORPHISM_MOVING_POINT_EXISTS;
+"HOMEOMORPHISM_OF_SUBSETS",HOMEOMORPHISM_OF_SUBSETS;
+"HOMEOMORPHISM_SYM",HOMEOMORPHISM_SYM;
+"HOMOGENEOUS_LINEAR_EQUATIONS_DET",HOMOGENEOUS_LINEAR_EQUATIONS_DET;
+"HOMOTOPICALLY_TRIVIAL_RETRACTION_GEN",HOMOTOPICALLY_TRIVIAL_RETRACTION_GEN;
+"HOMOTOPICALLY_TRIVIAL_RETRACTION_NULL_GEN",HOMOTOPICALLY_TRIVIAL_RETRACTION_NULL_GEN;
+"HOMOTOPIC_COMPOSE_CONTINUOUS_LEFT",HOMOTOPIC_COMPOSE_CONTINUOUS_LEFT;
+"HOMOTOPIC_COMPOSE_CONTINUOUS_RIGHT",HOMOTOPIC_COMPOSE_CONTINUOUS_RIGHT;
+"HOMOTOPIC_CONSTANT_MAPS",HOMOTOPIC_CONSTANT_MAPS;
+"HOMOTOPIC_FROM_CONTRACTIBLE",HOMOTOPIC_FROM_CONTRACTIBLE;
+"HOMOTOPIC_INTO_CONTRACTIBLE",HOMOTOPIC_INTO_CONTRACTIBLE;
+"HOMOTOPIC_JOIN_LEMMA",HOMOTOPIC_JOIN_LEMMA;
+"HOMOTOPIC_JOIN_SUBPATHS",HOMOTOPIC_JOIN_SUBPATHS;
+"HOMOTOPIC_LOOPS",HOMOTOPIC_LOOPS;
+"HOMOTOPIC_LOOPS_ADD_SYM",HOMOTOPIC_LOOPS_ADD_SYM;
+"HOMOTOPIC_LOOPS_CONJUGATE",HOMOTOPIC_LOOPS_CONJUGATE;
+"HOMOTOPIC_LOOPS_CONTINUOUS_IMAGE",HOMOTOPIC_LOOPS_CONTINUOUS_IMAGE;
+"HOMOTOPIC_LOOPS_EQ",HOMOTOPIC_LOOPS_EQ;
+"HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_PATHS_NULL",HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_PATHS_NULL;
+"HOMOTOPIC_LOOPS_IMP_LOOP",HOMOTOPIC_LOOPS_IMP_LOOP;
+"HOMOTOPIC_LOOPS_IMP_PATH",HOMOTOPIC_LOOPS_IMP_PATH;
+"HOMOTOPIC_LOOPS_IMP_PATH_COMPONENT_VALUE",HOMOTOPIC_LOOPS_IMP_PATH_COMPONENT_VALUE;
+"HOMOTOPIC_LOOPS_IMP_SUBSET",HOMOTOPIC_LOOPS_IMP_SUBSET;
+"HOMOTOPIC_LOOPS_LINEAR",HOMOTOPIC_LOOPS_LINEAR;
+"HOMOTOPIC_LOOPS_NEARBY_EXPLICIT",HOMOTOPIC_LOOPS_NEARBY_EXPLICIT;
+"HOMOTOPIC_LOOPS_REFL",HOMOTOPIC_LOOPS_REFL;
+"HOMOTOPIC_LOOPS_SHIFTPATH",HOMOTOPIC_LOOPS_SHIFTPATH;
+"HOMOTOPIC_LOOPS_SHIFTPATH_SELF",HOMOTOPIC_LOOPS_SHIFTPATH_SELF;
+"HOMOTOPIC_LOOPS_SUBSET",HOMOTOPIC_LOOPS_SUBSET;
+"HOMOTOPIC_LOOPS_SYM",HOMOTOPIC_LOOPS_SYM;
+"HOMOTOPIC_LOOPS_TRANS",HOMOTOPIC_LOOPS_TRANS;
+"HOMOTOPIC_NEARBY_LOOPS",HOMOTOPIC_NEARBY_LOOPS;
+"HOMOTOPIC_NEARBY_PATHS",HOMOTOPIC_NEARBY_PATHS;
+"HOMOTOPIC_NON_ANTIPODAL_SPHEREMAPS",HOMOTOPIC_NON_ANTIPODAL_SPHEREMAPS;
+"HOMOTOPIC_NON_MIDPOINT_SPHEREMAPS",HOMOTOPIC_NON_MIDPOINT_SPHEREMAPS;
+"HOMOTOPIC_PATHS",HOMOTOPIC_PATHS;
+"HOMOTOPIC_PATHS_ASSOC",HOMOTOPIC_PATHS_ASSOC;
+"HOMOTOPIC_PATHS_CONTINUOUS_IMAGE",HOMOTOPIC_PATHS_CONTINUOUS_IMAGE;
+"HOMOTOPIC_PATHS_EQ",HOMOTOPIC_PATHS_EQ;
+"HOMOTOPIC_PATHS_IMP_HOMOTOPIC_LOOPS",HOMOTOPIC_PATHS_IMP_HOMOTOPIC_LOOPS;
+"HOMOTOPIC_PATHS_IMP_PATH",HOMOTOPIC_PATHS_IMP_PATH;
+"HOMOTOPIC_PATHS_IMP_PATHFINISH",HOMOTOPIC_PATHS_IMP_PATHFINISH;
+"HOMOTOPIC_PATHS_IMP_PATHSTART",HOMOTOPIC_PATHS_IMP_PATHSTART;
+"HOMOTOPIC_PATHS_IMP_SUBSET",HOMOTOPIC_PATHS_IMP_SUBSET;
+"HOMOTOPIC_PATHS_JOIN",HOMOTOPIC_PATHS_JOIN;
+"HOMOTOPIC_PATHS_LID",HOMOTOPIC_PATHS_LID;
+"HOMOTOPIC_PATHS_LINEAR",HOMOTOPIC_PATHS_LINEAR;
+"HOMOTOPIC_PATHS_LINV",HOMOTOPIC_PATHS_LINV;
+"HOMOTOPIC_PATHS_LOOP_PARTS",HOMOTOPIC_PATHS_LOOP_PARTS;
+"HOMOTOPIC_PATHS_NEARBY_EXPLICIT",HOMOTOPIC_PATHS_NEARBY_EXPLICIT;
+"HOMOTOPIC_PATHS_REFL",HOMOTOPIC_PATHS_REFL;
+"HOMOTOPIC_PATHS_REPARAMETRIZE",HOMOTOPIC_PATHS_REPARAMETRIZE;
+"HOMOTOPIC_PATHS_REVERSEPATH",HOMOTOPIC_PATHS_REVERSEPATH;
+"HOMOTOPIC_PATHS_RID",HOMOTOPIC_PATHS_RID;
+"HOMOTOPIC_PATHS_RINV",HOMOTOPIC_PATHS_RINV;
+"HOMOTOPIC_PATHS_SUBSET",HOMOTOPIC_PATHS_SUBSET;
+"HOMOTOPIC_PATHS_SYM",HOMOTOPIC_PATHS_SYM;
+"HOMOTOPIC_PATHS_TRANS",HOMOTOPIC_PATHS_TRANS;
+"HOMOTOPIC_POINTS_EQ_PATH_COMPONENT",HOMOTOPIC_POINTS_EQ_PATH_COMPONENT;
+"HOMOTOPIC_THROUGH_CONTRACTIBLE",HOMOTOPIC_THROUGH_CONTRACTIBLE;
+"HOMOTOPIC_TRIVIALITY",HOMOTOPIC_TRIVIALITY;
+"HOMOTOPIC_WITH",HOMOTOPIC_WITH;
+"HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT",HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT;
+"HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT",HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT;
+"HOMOTOPIC_WITH_EQ",HOMOTOPIC_WITH_EQ;
+"HOMOTOPIC_WITH_EQUAL",HOMOTOPIC_WITH_EQUAL;
+"HOMOTOPIC_WITH_IMP_CONTINUOUS",HOMOTOPIC_WITH_IMP_CONTINUOUS;
+"HOMOTOPIC_WITH_IMP_PROPERTY",HOMOTOPIC_WITH_IMP_PROPERTY;
+"HOMOTOPIC_WITH_IMP_SUBSET",HOMOTOPIC_WITH_IMP_SUBSET;
+"HOMOTOPIC_WITH_LINEAR",HOMOTOPIC_WITH_LINEAR;
+"HOMOTOPIC_WITH_MONO",HOMOTOPIC_WITH_MONO;
+"HOMOTOPIC_WITH_PCROSS",HOMOTOPIC_WITH_PCROSS;
+"HOMOTOPIC_WITH_REFL",HOMOTOPIC_WITH_REFL;
+"HOMOTOPIC_WITH_SUBSET_LEFT",HOMOTOPIC_WITH_SUBSET_LEFT;
+"HOMOTOPIC_WITH_SUBSET_RIGHT",HOMOTOPIC_WITH_SUBSET_RIGHT;
+"HOMOTOPIC_WITH_SYM",HOMOTOPIC_WITH_SYM;
+"HOMOTOPIC_WITH_TRANS",HOMOTOPIC_WITH_TRANS;
+"HOMOTOPY_EQUIVALENT",HOMOTOPY_EQUIVALENT;
+"HOMOTOPY_EQUIVALENT_COHOMOTOPIC_TRIVIALITY",HOMOTOPY_EQUIVALENT_COHOMOTOPIC_TRIVIALITY;
+"HOMOTOPY_EQUIVALENT_COHOMOTOPIC_TRIVIALITY_NULL",HOMOTOPY_EQUIVALENT_COHOMOTOPIC_TRIVIALITY_NULL;
+"HOMOTOPY_EQUIVALENT_CONNECTEDNESS",HOMOTOPY_EQUIVALENT_CONNECTEDNESS;
+"HOMOTOPY_EQUIVALENT_CONTRACTIBILITY",HOMOTOPY_EQUIVALENT_CONTRACTIBILITY;
+"HOMOTOPY_EQUIVALENT_CONTRACTIBLE_SETS",HOMOTOPY_EQUIVALENT_CONTRACTIBLE_SETS;
+"HOMOTOPY_EQUIVALENT_EMPTY",HOMOTOPY_EQUIVALENT_EMPTY;
+"HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY",HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY;
+"HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY_NULL",HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY_NULL;
+"HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_LEFT_EQ",HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_LEFT_EQ;
+"HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ",HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ;
+"HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_SELF",HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_SELF;
+"HOMOTOPY_EQUIVALENT_PATH_CONNECTEDNESS",HOMOTOPY_EQUIVALENT_PATH_CONNECTEDNESS;
+"HOMOTOPY_EQUIVALENT_REFL",HOMOTOPY_EQUIVALENT_REFL;
+"HOMOTOPY_EQUIVALENT_SING",HOMOTOPY_EQUIVALENT_SING;
+"HOMOTOPY_EQUIVALENT_SYM",HOMOTOPY_EQUIVALENT_SYM;
+"HOMOTOPY_EQUIVALENT_TRANS",HOMOTOPY_EQUIVALENT_TRANS;
+"HOMOTOPY_EQUIVALENT_TRANSLATION_LEFT_EQ",HOMOTOPY_EQUIVALENT_TRANSLATION_LEFT_EQ;
+"HOMOTOPY_EQUIVALENT_TRANSLATION_RIGHT_EQ",HOMOTOPY_EQUIVALENT_TRANSLATION_RIGHT_EQ;
+"HOMOTOPY_EQUIVALENT_TRANSLATION_SELF",HOMOTOPY_EQUIVALENT_TRANSLATION_SELF;
+"HOMOTOPY_INVARIANT_CONNECTEDNESS",HOMOTOPY_INVARIANT_CONNECTEDNESS;
+"HOMOTOPY_INVARIANT_PATH_CONNECTEDNESS",HOMOTOPY_INVARIANT_PATH_CONNECTEDNESS;
+"HP",HP;
+"HREAL_ADD_AC",HREAL_ADD_AC;
+"HREAL_ADD_ASSOC",HREAL_ADD_ASSOC;
+"HREAL_ADD_LCANCEL",HREAL_ADD_LCANCEL;
+"HREAL_ADD_LDISTRIB",HREAL_ADD_LDISTRIB;
+"HREAL_ADD_LID",HREAL_ADD_LID;
+"HREAL_ADD_RDISTRIB",HREAL_ADD_RDISTRIB;
+"HREAL_ADD_RID",HREAL_ADD_RID;
+"HREAL_ADD_SYM",HREAL_ADD_SYM;
+"HREAL_ARCH",HREAL_ARCH;
+"HREAL_COMPLETE",HREAL_COMPLETE;
+"HREAL_EQ_ADD_LCANCEL",HREAL_EQ_ADD_LCANCEL;
+"HREAL_EQ_ADD_RCANCEL",HREAL_EQ_ADD_RCANCEL;
+"HREAL_INV_0",HREAL_INV_0;
+"HREAL_LE_ADD",HREAL_LE_ADD;
+"HREAL_LE_ADD2",HREAL_LE_ADD2;
+"HREAL_LE_ADD_LCANCEL",HREAL_LE_ADD_LCANCEL;
+"HREAL_LE_ADD_RCANCEL",HREAL_LE_ADD_RCANCEL;
+"HREAL_LE_ANTISYM",HREAL_LE_ANTISYM;
+"HREAL_LE_EXISTS",HREAL_LE_EXISTS;
+"HREAL_LE_EXISTS_DEF",HREAL_LE_EXISTS_DEF;
+"HREAL_LE_MUL_RCANCEL_IMP",HREAL_LE_MUL_RCANCEL_IMP;
+"HREAL_LE_REFL",HREAL_LE_REFL;
+"HREAL_LE_TOTAL",HREAL_LE_TOTAL;
+"HREAL_LE_TRANS",HREAL_LE_TRANS;
+"HREAL_MUL_ASSOC",HREAL_MUL_ASSOC;
+"HREAL_MUL_LID",HREAL_MUL_LID;
+"HREAL_MUL_LINV",HREAL_MUL_LINV;
+"HREAL_MUL_LZERO",HREAL_MUL_LZERO;
+"HREAL_MUL_RZERO",HREAL_MUL_RZERO;
+"HREAL_MUL_SYM",HREAL_MUL_SYM;
+"HREAL_OF_NUM_ADD",HREAL_OF_NUM_ADD;
+"HREAL_OF_NUM_EQ",HREAL_OF_NUM_EQ;
+"HREAL_OF_NUM_LE",HREAL_OF_NUM_LE;
+"HREAL_OF_NUM_MUL",HREAL_OF_NUM_MUL;
+"HULLS_EQ",HULLS_EQ;
+"HULL_ANTIMONO",HULL_ANTIMONO;
+"HULL_EQ",HULL_EQ;
+"HULL_HULL",HULL_HULL;
+"HULL_IMAGE",HULL_IMAGE;
+"HULL_IMAGE_GALOIS",HULL_IMAGE_GALOIS;
+"HULL_IMAGE_SUBSET",HULL_IMAGE_SUBSET;
+"HULL_INC",HULL_INC;
+"HULL_INDUCT",HULL_INDUCT;
+"HULL_MINIMAL",HULL_MINIMAL;
+"HULL_MONO",HULL_MONO;
+"HULL_P",HULL_P;
+"HULL_P_AND_Q",HULL_P_AND_Q;
+"HULL_REDUNDANT",HULL_REDUNDANT;
+"HULL_REDUNDANT_EQ",HULL_REDUNDANT_EQ;
+"HULL_SUBSET",HULL_SUBSET;
+"HULL_UNION",HULL_UNION;
+"HULL_UNION_LEFT",HULL_UNION_LEFT;
+"HULL_UNION_RIGHT",HULL_UNION_RIGHT;
+"HULL_UNION_SUBSET",HULL_UNION_SUBSET;
+"HULL_UNIQUE",HULL_UNIQUE;
+"HYPERPLANE_EQ_EMPTY",HYPERPLANE_EQ_EMPTY;
+"HYPERPLANE_EQ_UNIV",HYPERPLANE_EQ_UNIV;
+"HYPERPLANE_FACET_OF_HALFSPACE_GE",HYPERPLANE_FACET_OF_HALFSPACE_GE;
+"HYPERPLANE_FACET_OF_HALFSPACE_LE",HYPERPLANE_FACET_OF_HALFSPACE_LE;
+"HYPERPLANE_FACE_OF_HALFSPACE_GE",HYPERPLANE_FACE_OF_HALFSPACE_GE;
+"HYPERPLANE_FACE_OF_HALFSPACE_LE",HYPERPLANE_FACE_OF_HALFSPACE_LE;
+"IDEMPOTENT_IMP_RETRACTION",IDEMPOTENT_IMP_RETRACTION;
+"IMAGE",IMAGE;
+"IMAGE_AFFINITY_INTERVAL",IMAGE_AFFINITY_INTERVAL;
+"IMAGE_CLAUSES",IMAGE_CLAUSES;
+"IMAGE_CLOSURE_SUBSET",IMAGE_CLOSURE_SUBSET;
+"IMAGE_COMPOSE_PERMUTATIONS_L",IMAGE_COMPOSE_PERMUTATIONS_L;
+"IMAGE_COMPOSE_PERMUTATIONS_R",IMAGE_COMPOSE_PERMUTATIONS_R;
+"IMAGE_CONST",IMAGE_CONST;
+"IMAGE_DELETE_INJ",IMAGE_DELETE_INJ;
+"IMAGE_DIFF_INJ",IMAGE_DIFF_INJ;
+"IMAGE_DROP_UNIV",IMAGE_DROP_UNIV;
+"IMAGE_EQ_EMPTY",IMAGE_EQ_EMPTY;
+"IMAGE_FSTCART_PCROSS",IMAGE_FSTCART_PCROSS;
+"IMAGE_I",IMAGE_I;
+"IMAGE_ID",IMAGE_ID;
+"IMAGE_IMP_INJECTIVE",IMAGE_IMP_INJECTIVE;
+"IMAGE_IMP_INJECTIVE_GEN",IMAGE_IMP_INJECTIVE_GEN;
+"IMAGE_INJECTIVE_IMAGE_OF_SUBSET",IMAGE_INJECTIVE_IMAGE_OF_SUBSET;
+"IMAGE_INTER_INJ",IMAGE_INTER_INJ;
+"IMAGE_INVERSE_PERMUTATIONS",IMAGE_INVERSE_PERMUTATIONS;
+"IMAGE_LEMMA_0",IMAGE_LEMMA_0;
+"IMAGE_LEMMA_1",IMAGE_LEMMA_1;
+"IMAGE_LEMMA_2",IMAGE_LEMMA_2;
+"IMAGE_LIFT_DROP",IMAGE_LIFT_DROP;
+"IMAGE_LIFT_UNIV",IMAGE_LIFT_UNIV;
+"IMAGE_SNDCART_PCROSS",IMAGE_SNDCART_PCROSS;
+"IMAGE_STRETCH_INTERVAL",IMAGE_STRETCH_INTERVAL;
+"IMAGE_SUBSET",IMAGE_SUBSET;
+"IMAGE_UNION",IMAGE_UNION;
+"IMAGE_UNIONS",IMAGE_UNIONS;
+"IMAGE_o",IMAGE_o;
+"IMP_CLAUSES",IMP_CLAUSES;
+"IMP_CONJ",IMP_CONJ;
+"IMP_CONJ_ALT",IMP_CONJ_ALT;
+"IMP_DEF",IMP_DEF;
+"IMP_IMP",IMP_IMP;
+"IN",IN;
+"INCREASING_BOUNDED_VARIATION",INCREASING_BOUNDED_VARIATION;
+"INCREASING_LEFT_LIMIT_1",INCREASING_LEFT_LIMIT_1;
+"INCREASING_RIGHT_LIMIT_1",INCREASING_RIGHT_LIMIT_1;
+"INCREASING_VECTOR_VARIATION",INCREASING_VECTOR_VARIATION;
+"INDEFINITE_INTEGRAL_CONTINUOUS",INDEFINITE_INTEGRAL_CONTINUOUS;
+"INDEFINITE_INTEGRAL_CONTINUOUS_LEFT",INDEFINITE_INTEGRAL_CONTINUOUS_LEFT;
+"INDEFINITE_INTEGRAL_CONTINUOUS_RIGHT",INDEFINITE_INTEGRAL_CONTINUOUS_RIGHT;
+"INDEFINITE_INTEGRAL_UNIFORMLY_CONTINUOUS",INDEFINITE_INTEGRAL_UNIFORMLY_CONTINUOUS;
+"INDEFINITE_INTEGRAL_UNIFORMLY_CONTINUOUS_EXPLICIT",INDEFINITE_INTEGRAL_UNIFORMLY_CONTINUOUS_EXPLICIT;
+"INDEPENDENT_2",INDEPENDENT_2;
+"INDEPENDENT_3",INDEPENDENT_3;
+"INDEPENDENT_BOUND",INDEPENDENT_BOUND;
+"INDEPENDENT_BOUND_GENERAL",INDEPENDENT_BOUND_GENERAL;
+"INDEPENDENT_CARD_LE_DIM",INDEPENDENT_CARD_LE_DIM;
+"INDEPENDENT_EMPTY",INDEPENDENT_EMPTY;
+"INDEPENDENT_EXPLICIT",INDEPENDENT_EXPLICIT;
+"INDEPENDENT_IMP_AFFINE_DEPENDENT_0",INDEPENDENT_IMP_AFFINE_DEPENDENT_0;
+"INDEPENDENT_IMP_FINITE",INDEPENDENT_IMP_FINITE;
+"INDEPENDENT_INJECTIVE_IMAGE",INDEPENDENT_INJECTIVE_IMAGE;
+"INDEPENDENT_INJECTIVE_IMAGE_GEN",INDEPENDENT_INJECTIVE_IMAGE_GEN;
+"INDEPENDENT_INSERT",INDEPENDENT_INSERT;
+"INDEPENDENT_LINEAR_IMAGE_EQ",INDEPENDENT_LINEAR_IMAGE_EQ;
+"INDEPENDENT_MONO",INDEPENDENT_MONO;
+"INDEPENDENT_NONZERO",INDEPENDENT_NONZERO;
+"INDEPENDENT_SING",INDEPENDENT_SING;
+"INDEPENDENT_SPAN_BOUND",INDEPENDENT_SPAN_BOUND;
+"INDEPENDENT_STDBASIS",INDEPENDENT_STDBASIS;
+"INDUCT_LINEAR_ELEMENTARY",INDUCT_LINEAR_ELEMENTARY;
+"INDUCT_MATRIX_ELEMENTARY",INDUCT_MATRIX_ELEMENTARY;
+"INDUCT_MATRIX_ELEMENTARY_ALT",INDUCT_MATRIX_ELEMENTARY_ALT;
+"INDUCT_MATRIX_ROW_OPERATIONS",INDUCT_MATRIX_ROW_OPERATIONS;
+"IND_SUC_0",IND_SUC_0;
+"IND_SUC_0_EXISTS",IND_SUC_0_EXISTS;
+"IND_SUC_INJ",IND_SUC_INJ;
+"IND_SUC_SPEC",IND_SUC_SPEC;
+"INF",INF;
+"INFINITE",INFINITE;
+"INFINITE_ARC_IMAGE",INFINITE_ARC_IMAGE;
+"INFINITE_CARD_LE",INFINITE_CARD_LE;
+"INFINITE_DIFF_FINITE",INFINITE_DIFF_FINITE;
+"INFINITE_ENUMERATE",INFINITE_ENUMERATE;
+"INFINITE_FROM",INFINITE_FROM;
+"INFINITE_IMAGE_INJ",INFINITE_IMAGE_INJ;
+"INFINITE_INTEGER",INFINITE_INTEGER;
+"INFINITE_NONEMPTY",INFINITE_NONEMPTY;
+"INFINITE_OPEN_IN",INFINITE_OPEN_IN;
+"INFINITE_RATIONAL",INFINITE_RATIONAL;
+"INFINITE_SIMPLE_PATH_IMAGE",INFINITE_SIMPLE_PATH_IMAGE;
+"INFINITE_SUPERSET",INFINITE_SUPERSET;
+"INFINITY_AX",INFINITY_AX;
+"INFNORM_0",INFNORM_0;
+"INFNORM_2",INFNORM_2;
+"INFNORM_EQ_0",INFNORM_EQ_0;
+"INFNORM_EQ_1_2",INFNORM_EQ_1_2;
+"INFNORM_EQ_1_IMP",INFNORM_EQ_1_IMP;
+"INFNORM_LE_NORM",INFNORM_LE_NORM;
+"INFNORM_MUL",INFNORM_MUL;
+"INFNORM_MUL_LEMMA",INFNORM_MUL_LEMMA;
+"INFNORM_NEG",INFNORM_NEG;
+"INFNORM_POS_LE",INFNORM_POS_LE;
+"INFNORM_POS_LT",INFNORM_POS_LT;
+"INFNORM_SET_IMAGE",INFNORM_SET_IMAGE;
+"INFNORM_SET_LEMMA",INFNORM_SET_LEMMA;
+"INFNORM_SUB",INFNORM_SUB;
+"INFNORM_TRIANGLE",INFNORM_TRIANGLE;
+"INFSUM_0",INFSUM_0;
+"INFSUM_ADD",INFSUM_ADD;
+"INFSUM_CMUL",INFSUM_CMUL;
+"INFSUM_EQ",INFSUM_EQ;
+"INFSUM_LINEAR",INFSUM_LINEAR;
+"INFSUM_NEG",INFSUM_NEG;
+"INFSUM_RESTRICT",INFSUM_RESTRICT;
+"INFSUM_SUB",INFSUM_SUB;
+"INFSUM_UNIQUE",INFSUM_UNIQUE;
+"INF_EQ",INF_EQ;
+"INF_FINITE",INF_FINITE;
+"INF_FINITE_LEMMA",INF_FINITE_LEMMA;
+"INF_INSERT",INF_INSERT;
+"INF_INSERT_FINITE",INF_INSERT_FINITE;
+"INF_SING",INF_SING;
+"INF_UNIQUE_FINITE",INF_UNIQUE_FINITE;
+"INJ",INJ;
+"INJA",INJA;
+"INJA_INJ",INJA_INJ;
+"INJECTIVE_ALT",INJECTIVE_ALT;
+"INJECTIVE_IMAGE",INJECTIVE_IMAGE;
+"INJECTIVE_IMP_ISOMETRIC",INJECTIVE_IMP_ISOMETRIC;
+"INJECTIVE_INTO_1D_EQ_HOMEOMORPHISM",INJECTIVE_INTO_1D_EQ_HOMEOMORPHISM;
+"INJECTIVE_INTO_1D_IMP_OPEN_MAP",INJECTIVE_INTO_1D_IMP_OPEN_MAP;
+"INJECTIVE_INVERSE",INJECTIVE_INVERSE;
+"INJECTIVE_INVERSE_o",INJECTIVE_INVERSE_o;
+"INJECTIVE_LEFT_INVERSE",INJECTIVE_LEFT_INVERSE;
+"INJECTIVE_LEFT_INVERSE_NONEMPTY",INJECTIVE_LEFT_INVERSE_NONEMPTY;
+"INJECTIVE_MAP",INJECTIVE_MAP;
+"INJECTIVE_MAP_OPEN_IFF_CLOSED",INJECTIVE_MAP_OPEN_IFF_CLOSED;
+"INJECTIVE_ON_ALT",INJECTIVE_ON_ALT;
+"INJECTIVE_ON_IMAGE",INJECTIVE_ON_IMAGE;
+"INJECTIVE_ON_LEFT_INVERSE",INJECTIVE_ON_LEFT_INVERSE;
+"INJECTIVE_SCALING",INJECTIVE_SCALING;
+"INJF",INJF;
+"INJF_INJ",INJF_INJ;
+"INJN",INJN;
+"INJN_INJ",INJN_INJ;
+"INJP",INJP;
+"INJP_INJ",INJP_INJ;
+"INJ_INVERSE2",INJ_INVERSE2;
+"INNER_LADD",INNER_LADD;
+"INNER_LMUL",INNER_LMUL;
+"INNER_LNEG",INNER_LNEG;
+"INNER_LZERO",INNER_LZERO;
+"INNER_RADD",INNER_RADD;
+"INNER_RMUL",INNER_RMUL;
+"INNER_RNEG",INNER_RNEG;
+"INNER_RZERO",INNER_RZERO;
+"INSEG_LINSEG",INSEG_LINSEG;
+"INSEG_PROPER_SUBSET",INSEG_PROPER_SUBSET;
+"INSEG_PROPER_SUBSET_FL",INSEG_PROPER_SUBSET_FL;
+"INSEG_SUBSET",INSEG_SUBSET;
+"INSEG_SUBSET_FL",INSEG_SUBSET_FL;
+"INSEG_WOSET",INSEG_WOSET;
+"INSERT",INSERT;
+"INSERT_AC",INSERT_AC;
+"INSERT_COMM",INSERT_COMM;
+"INSERT_DEF",INSERT_DEF;
+"INSERT_DELETE",INSERT_DELETE;
+"INSERT_DIFF",INSERT_DIFF;
+"INSERT_INSERT",INSERT_INSERT;
+"INSERT_INTER",INSERT_INTER;
+"INSERT_SUBSET",INSERT_SUBSET;
+"INSERT_UNION",INSERT_UNION;
+"INSERT_UNION_EQ",INSERT_UNION_EQ;
+"INSERT_UNIV",INSERT_UNIV;
+"INSIDE_ARC_EMPTY",INSIDE_ARC_EMPTY;
+"INSIDE_BOUNDED_COMPLEMENT_CONNECTED_EMPTY",INSIDE_BOUNDED_COMPLEMENT_CONNECTED_EMPTY;
+"INSIDE_COMPLEMENT_UNBOUNDED_CONNECTED_EMPTY",INSIDE_COMPLEMENT_UNBOUNDED_CONNECTED_EMPTY;
+"INSIDE_CONNECTED_COMPONENT_LE",INSIDE_CONNECTED_COMPONENT_LE;
+"INSIDE_CONNECTED_COMPONENT_LT",INSIDE_CONNECTED_COMPONENT_LT;
+"INSIDE_CONVEX",INSIDE_CONVEX;
+"INSIDE_EMPTY",INSIDE_EMPTY;
+"INSIDE_EQ_OUTSIDE",INSIDE_EQ_OUTSIDE;
+"INSIDE_FRONTIER_EQ_INTERIOR",INSIDE_FRONTIER_EQ_INTERIOR;
+"INSIDE_INSIDE",INSIDE_INSIDE;
+"INSIDE_INSIDE_COMPACT_CONNECTED",INSIDE_INSIDE_COMPACT_CONNECTED;
+"INSIDE_INSIDE_EQ_EMPTY",INSIDE_INSIDE_EQ_EMPTY;
+"INSIDE_INSIDE_SUBSET",INSIDE_INSIDE_SUBSET;
+"INSIDE_INTER_OUTSIDE",INSIDE_INTER_OUTSIDE;
+"INSIDE_IN_COMPONENTS",INSIDE_IN_COMPONENTS;
+"INSIDE_LINEAR_IMAGE",INSIDE_LINEAR_IMAGE;
+"INSIDE_MONO",INSIDE_MONO;
+"INSIDE_NO_OVERLAP",INSIDE_NO_OVERLAP;
+"INSIDE_OF_TRIANGLE",INSIDE_OF_TRIANGLE;
+"INSIDE_OUTSIDE",INSIDE_OUTSIDE;
+"INSIDE_OUTSIDE_INTERSECT_CONNECTED",INSIDE_OUTSIDE_INTERSECT_CONNECTED;
+"INSIDE_OUTSIDE_UNIQUE",INSIDE_OUTSIDE_UNIQUE;
+"INSIDE_SAME_COMPONENT",INSIDE_SAME_COMPONENT;
+"INSIDE_SIMPLE_CURVE_IMP_CLOSED",INSIDE_SIMPLE_CURVE_IMP_CLOSED;
+"INSIDE_SUBSET",INSIDE_SUBSET;
+"INSIDE_TRANSLATION",INSIDE_TRANSLATION;
+"INSIDE_UNION_OUTSIDE",INSIDE_UNION_OUTSIDE;
+"INSIDE_UNIQUE",INSIDE_UNIQUE;
+"INTEGER_ABS",INTEGER_ABS;
+"INTEGER_ABS_MUL_EQ_1",INTEGER_ABS_MUL_EQ_1;
+"INTEGER_ADD",INTEGER_ADD;
+"INTEGER_ADD_EQ",INTEGER_ADD_EQ;
+"INTEGER_CASES",INTEGER_CASES;
+"INTEGER_CLOSED",INTEGER_CLOSED;
+"INTEGER_DET",INTEGER_DET;
+"INTEGER_EXISTS_BETWEEN",INTEGER_EXISTS_BETWEEN;
+"INTEGER_EXISTS_BETWEEN_ABS",INTEGER_EXISTS_BETWEEN_ABS;
+"INTEGER_EXISTS_BETWEEN_ABS_LT",INTEGER_EXISTS_BETWEEN_ABS_LT;
+"INTEGER_EXISTS_BETWEEN_ALT",INTEGER_EXISTS_BETWEEN_ALT;
+"INTEGER_EXISTS_BETWEEN_LT",INTEGER_EXISTS_BETWEEN_LT;
+"INTEGER_MUL",INTEGER_MUL;
+"INTEGER_NEG",INTEGER_NEG;
+"INTEGER_POS",INTEGER_POS;
+"INTEGER_POW",INTEGER_POW;
+"INTEGER_PRODUCT",INTEGER_PRODUCT;
+"INTEGER_ROUND",INTEGER_ROUND;
+"INTEGER_SIGN",INTEGER_SIGN;
+"INTEGER_SUB",INTEGER_SUB;
+"INTEGER_SUB_EQ",INTEGER_SUB_EQ;
+"INTEGER_SUM",INTEGER_SUM;
+"INTEGRABLE_0",INTEGRABLE_0;
+"INTEGRABLE_ADD",INTEGRABLE_ADD;
+"INTEGRABLE_AFFINITY",INTEGRABLE_AFFINITY;
+"INTEGRABLE_ALT",INTEGRABLE_ALT;
+"INTEGRABLE_ALT_SUBSET",INTEGRABLE_ALT_SUBSET;
+"INTEGRABLE_CAUCHY",INTEGRABLE_CAUCHY;
+"INTEGRABLE_CCONTINUOUS_EXPLICIT",INTEGRABLE_CCONTINUOUS_EXPLICIT;
+"INTEGRABLE_CCONTINUOUS_EXPLICIT_SYMMETRIC",INTEGRABLE_CCONTINUOUS_EXPLICIT_SYMMETRIC;
+"INTEGRABLE_CMUL",INTEGRABLE_CMUL;
+"INTEGRABLE_COMBINE",INTEGRABLE_COMBINE;
+"INTEGRABLE_COMBINE_DIVISION",INTEGRABLE_COMBINE_DIVISION;
+"INTEGRABLE_COMPONENTWISE",INTEGRABLE_COMPONENTWISE;
+"INTEGRABLE_CONST",INTEGRABLE_CONST;
+"INTEGRABLE_CONTINUOUS",INTEGRABLE_CONTINUOUS;
+"INTEGRABLE_DECREASING",INTEGRABLE_DECREASING;
+"INTEGRABLE_DECREASING_1",INTEGRABLE_DECREASING_1;
+"INTEGRABLE_DECREASING_PRODUCT",INTEGRABLE_DECREASING_PRODUCT;
+"INTEGRABLE_DECREASING_PRODUCT_UNIV",INTEGRABLE_DECREASING_PRODUCT_UNIV;
+"INTEGRABLE_EQ",INTEGRABLE_EQ;
+"INTEGRABLE_IMP_MEASURABLE",INTEGRABLE_IMP_MEASURABLE;
+"INTEGRABLE_INCREASING",INTEGRABLE_INCREASING;
+"INTEGRABLE_INCREASING_1",INTEGRABLE_INCREASING_1;
+"INTEGRABLE_INCREASING_PRODUCT",INTEGRABLE_INCREASING_PRODUCT;
+"INTEGRABLE_INCREASING_PRODUCT_UNIV",INTEGRABLE_INCREASING_PRODUCT_UNIV;
+"INTEGRABLE_INTEGRAL",INTEGRABLE_INTEGRAL;
+"INTEGRABLE_LINEAR",INTEGRABLE_LINEAR;
+"INTEGRABLE_MIN_CONST_1",INTEGRABLE_MIN_CONST_1;
+"INTEGRABLE_NEG",INTEGRABLE_NEG;
+"INTEGRABLE_ON_ALL_INTERVALS_INTEGRABLE_BOUND",INTEGRABLE_ON_ALL_INTERVALS_INTEGRABLE_BOUND;
+"INTEGRABLE_ON_CONST",INTEGRABLE_ON_CONST;
+"INTEGRABLE_ON_EMPTY",INTEGRABLE_ON_EMPTY;
+"INTEGRABLE_ON_LITTLE_SUBINTERVALS",INTEGRABLE_ON_LITTLE_SUBINTERVALS;
+"INTEGRABLE_ON_NULL",INTEGRABLE_ON_NULL;
+"INTEGRABLE_ON_OPEN_INTERVAL",INTEGRABLE_ON_OPEN_INTERVAL;
+"INTEGRABLE_ON_REFL",INTEGRABLE_ON_REFL;
+"INTEGRABLE_ON_SUBDIVISION",INTEGRABLE_ON_SUBDIVISION;
+"INTEGRABLE_ON_SUBINTERVAL",INTEGRABLE_ON_SUBINTERVAL;
+"INTEGRABLE_ON_SUPERSET",INTEGRABLE_ON_SUPERSET;
+"INTEGRABLE_REFLECT",INTEGRABLE_REFLECT;
+"INTEGRABLE_RESTRICT",INTEGRABLE_RESTRICT;
+"INTEGRABLE_RESTRICT_INTER",INTEGRABLE_RESTRICT_INTER;
+"INTEGRABLE_RESTRICT_UNIV",INTEGRABLE_RESTRICT_UNIV;
+"INTEGRABLE_SPIKE",INTEGRABLE_SPIKE;
+"INTEGRABLE_SPIKE_FINITE",INTEGRABLE_SPIKE_FINITE;
+"INTEGRABLE_SPIKE_INTERIOR",INTEGRABLE_SPIKE_INTERIOR;
+"INTEGRABLE_SPIKE_SET",INTEGRABLE_SPIKE_SET;
+"INTEGRABLE_SPIKE_SET_EQ",INTEGRABLE_SPIKE_SET_EQ;
+"INTEGRABLE_SPLIT",INTEGRABLE_SPLIT;
+"INTEGRABLE_STRADDLE",INTEGRABLE_STRADDLE;
+"INTEGRABLE_STRADDLE_INTERVAL",INTEGRABLE_STRADDLE_INTERVAL;
+"INTEGRABLE_STRETCH",INTEGRABLE_STRETCH;
+"INTEGRABLE_SUB",INTEGRABLE_SUB;
+"INTEGRABLE_SUBINTERVAL",INTEGRABLE_SUBINTERVAL;
+"INTEGRABLE_SUBINTERVALS_IMP_MEASURABLE",INTEGRABLE_SUBINTERVALS_IMP_MEASURABLE;
+"INTEGRABLE_UNIFORM_LIMIT",INTEGRABLE_UNIFORM_LIMIT;
+"INTEGRABLE_VSUM",INTEGRABLE_VSUM;
+"INTEGRAL_0",INTEGRAL_0;
+"INTEGRAL_ADD",INTEGRAL_ADD;
+"INTEGRAL_CMUL",INTEGRAL_CMUL;
+"INTEGRAL_COMBINE",INTEGRAL_COMBINE;
+"INTEGRAL_COMBINE_DIVISION_BOTTOMUP",INTEGRAL_COMBINE_DIVISION_BOTTOMUP;
+"INTEGRAL_COMBINE_DIVISION_TOPDOWN",INTEGRAL_COMBINE_DIVISION_TOPDOWN;
+"INTEGRAL_COMBINE_TAGGED_DIVISION_BOTTOMUP",INTEGRAL_COMBINE_TAGGED_DIVISION_BOTTOMUP;
+"INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN",INTEGRAL_COMBINE_TAGGED_DIVISION_TOPDOWN;
+"INTEGRAL_COMPONENT",INTEGRAL_COMPONENT;
+"INTEGRAL_COMPONENT_LBOUND",INTEGRAL_COMPONENT_LBOUND;
+"INTEGRAL_COMPONENT_LE",INTEGRAL_COMPONENT_LE;
+"INTEGRAL_COMPONENT_POS",INTEGRAL_COMPONENT_POS;
+"INTEGRAL_COMPONENT_UBOUND",INTEGRAL_COMPONENT_UBOUND;
+"INTEGRAL_CONST",INTEGRAL_CONST;
+"INTEGRAL_DIFF",INTEGRAL_DIFF;
+"INTEGRAL_DROP_LE",INTEGRAL_DROP_LE;
+"INTEGRAL_DROP_LE_MEASURABLE",INTEGRAL_DROP_LE_MEASURABLE;
+"INTEGRAL_DROP_POS",INTEGRAL_DROP_POS;
+"INTEGRAL_EMPTY",INTEGRAL_EMPTY;
+"INTEGRAL_EQ",INTEGRAL_EQ;
+"INTEGRAL_EQ_0",INTEGRAL_EQ_0;
+"INTEGRAL_EQ_HAS_INTEGRAL",INTEGRAL_EQ_HAS_INTEGRAL;
+"INTEGRAL_HAS_VECTOR_DERIVATIVE",INTEGRAL_HAS_VECTOR_DERIVATIVE;
+"INTEGRAL_INTERVALS_DIFF_INCLUSION_EXCLUSION",INTEGRAL_INTERVALS_DIFF_INCLUSION_EXCLUSION;
+"INTEGRAL_INTERVALS_INCLUSION_EXCLUSION",INTEGRAL_INTERVALS_INCLUSION_EXCLUSION;
+"INTEGRAL_INTERVALS_INCLUSION_EXCLUSION_LEFT",INTEGRAL_INTERVALS_INCLUSION_EXCLUSION_LEFT;
+"INTEGRAL_INTERVALS_INCLUSION_EXCLUSION_RIGHT",INTEGRAL_INTERVALS_INCLUSION_EXCLUSION_RIGHT;
+"INTEGRAL_LINEAR",INTEGRAL_LINEAR;
+"INTEGRAL_MEASURE",INTEGRAL_MEASURE;
+"INTEGRAL_MEASURE_UNIV",INTEGRAL_MEASURE_UNIV;
+"INTEGRAL_NEG",INTEGRAL_NEG;
+"INTEGRAL_NORM_BOUND_INTEGRAL",INTEGRAL_NORM_BOUND_INTEGRAL;
+"INTEGRAL_NORM_BOUND_INTEGRAL_COMPONENT",INTEGRAL_NORM_BOUND_INTEGRAL_COMPONENT;
+"INTEGRAL_NULL",INTEGRAL_NULL;
+"INTEGRAL_OPEN_INTERVAL",INTEGRAL_OPEN_INTERVAL;
+"INTEGRAL_PASTECART_CONST",INTEGRAL_PASTECART_CONST;
+"INTEGRAL_PASTECART_CONTINUOUS",INTEGRAL_PASTECART_CONTINUOUS;
+"INTEGRAL_REFL",INTEGRAL_REFL;
+"INTEGRAL_REFLECT",INTEGRAL_REFLECT;
+"INTEGRAL_RESTRICT",INTEGRAL_RESTRICT;
+"INTEGRAL_RESTRICT_INTER",INTEGRAL_RESTRICT_INTER;
+"INTEGRAL_RESTRICT_UNIV",INTEGRAL_RESTRICT_UNIV;
+"INTEGRAL_SPIKE",INTEGRAL_SPIKE;
+"INTEGRAL_SPIKE_SET",INTEGRAL_SPIKE_SET;
+"INTEGRAL_SPLIT",INTEGRAL_SPLIT;
+"INTEGRAL_SPLIT_SIGNED",INTEGRAL_SPLIT_SIGNED;
+"INTEGRAL_SUB",INTEGRAL_SUB;
+"INTEGRAL_SUBSET_COMPONENT_LE",INTEGRAL_SUBSET_COMPONENT_LE;
+"INTEGRAL_SUBSET_DROP_LE",INTEGRAL_SUBSET_DROP_LE;
+"INTEGRAL_SWAP_CONTINUOUS",INTEGRAL_SWAP_CONTINUOUS;
+"INTEGRAL_UNION",INTEGRAL_UNION;
+"INTEGRAL_UNIQUE",INTEGRAL_UNIQUE;
+"INTEGRAL_VSUM",INTEGRAL_VSUM;
+"INTER",INTER;
+"INTERIOR_BIJECTIVE_LINEAR_IMAGE",INTERIOR_BIJECTIVE_LINEAR_IMAGE;
+"INTERIOR_CBALL",INTERIOR_CBALL;
+"INTERIOR_CLOSED_EQ_EMPTY_AS_FRONTIER",INTERIOR_CLOSED_EQ_EMPTY_AS_FRONTIER;
+"INTERIOR_CLOSED_INTERVAL",INTERIOR_CLOSED_INTERVAL;
+"INTERIOR_CLOSED_UNION_EMPTY_INTERIOR",INTERIOR_CLOSED_UNION_EMPTY_INTERIOR;
+"INTERIOR_CLOSURE",INTERIOR_CLOSURE;
+"INTERIOR_CLOSURE_IDEMP",INTERIOR_CLOSURE_IDEMP;
+"INTERIOR_COMPLEMENT",INTERIOR_COMPLEMENT;
+"INTERIOR_CONVEX_HULL_3",INTERIOR_CONVEX_HULL_3;
+"INTERIOR_CONVEX_HULL_3_MINIMAL",INTERIOR_CONVEX_HULL_3_MINIMAL;
+"INTERIOR_CONVEX_HULL_EQ_EMPTY",INTERIOR_CONVEX_HULL_EQ_EMPTY;
+"INTERIOR_CONVEX_HULL_EXPLICIT",INTERIOR_CONVEX_HULL_EXPLICIT;
+"INTERIOR_CONVEX_HULL_EXPLICIT_MINIMAL",INTERIOR_CONVEX_HULL_EXPLICIT_MINIMAL;
+"INTERIOR_DIFF",INTERIOR_DIFF;
+"INTERIOR_EMPTY",INTERIOR_EMPTY;
+"INTERIOR_EQ",INTERIOR_EQ;
+"INTERIOR_EQ_EMPTY",INTERIOR_EQ_EMPTY;
+"INTERIOR_EQ_EMPTY_ALT",INTERIOR_EQ_EMPTY_ALT;
+"INTERIOR_FINITE_INTERS",INTERIOR_FINITE_INTERS;
+"INTERIOR_FRONTIER",INTERIOR_FRONTIER;
+"INTERIOR_FRONTIER_EMPTY",INTERIOR_FRONTIER_EMPTY;
+"INTERIOR_HALFSPACE_COMPONENT_GE",INTERIOR_HALFSPACE_COMPONENT_GE;
+"INTERIOR_HALFSPACE_COMPONENT_LE",INTERIOR_HALFSPACE_COMPONENT_LE;
+"INTERIOR_HALFSPACE_GE",INTERIOR_HALFSPACE_GE;
+"INTERIOR_HALFSPACE_LE",INTERIOR_HALFSPACE_LE;
+"INTERIOR_HYPERPLANE",INTERIOR_HYPERPLANE;
+"INTERIOR_IMAGE_SUBSET",INTERIOR_IMAGE_SUBSET;
+"INTERIOR_INJECTIVE_LINEAR_IMAGE",INTERIOR_INJECTIVE_LINEAR_IMAGE;
+"INTERIOR_INSIDE_FRONTIER",INTERIOR_INSIDE_FRONTIER;
+"INTERIOR_INTER",INTERIOR_INTER;
+"INTERIOR_INTERIOR",INTERIOR_INTERIOR;
+"INTERIOR_INTERS_SUBSET",INTERIOR_INTERS_SUBSET;
+"INTERIOR_INTERVAL",INTERIOR_INTERVAL;
+"INTERIOR_LIMIT_POINT",INTERIOR_LIMIT_POINT;
+"INTERIOR_MAXIMAL",INTERIOR_MAXIMAL;
+"INTERIOR_MAXIMAL_EQ",INTERIOR_MAXIMAL_EQ;
+"INTERIOR_NEGATIONS",INTERIOR_NEGATIONS;
+"INTERIOR_OF_TRIANGLE",INTERIOR_OF_TRIANGLE;
+"INTERIOR_OPEN",INTERIOR_OPEN;
+"INTERIOR_PCROSS",INTERIOR_PCROSS;
+"INTERIOR_SEGMENT",INTERIOR_SEGMENT;
+"INTERIOR_SIMPLEX_NONEMPTY",INTERIOR_SIMPLEX_NONEMPTY;
+"INTERIOR_SING",INTERIOR_SING;
+"INTERIOR_STANDARD_HYPERPLANE",INTERIOR_STANDARD_HYPERPLANE;
+"INTERIOR_STD_SIMPLEX",INTERIOR_STD_SIMPLEX;
+"INTERIOR_SUBSET",INTERIOR_SUBSET;
+"INTERIOR_SUBSET_RELATIVE_INTERIOR",INTERIOR_SUBSET_RELATIVE_INTERIOR;
+"INTERIOR_SUBSET_UNION_INTERVALS",INTERIOR_SUBSET_UNION_INTERVALS;
+"INTERIOR_SURJECTIVE_LINEAR_IMAGE",INTERIOR_SURJECTIVE_LINEAR_IMAGE;
+"INTERIOR_TRANSLATION",INTERIOR_TRANSLATION;
+"INTERIOR_UNIONS_OPEN_SUBSETS",INTERIOR_UNIONS_OPEN_SUBSETS;
+"INTERIOR_UNION_EQ_EMPTY",INTERIOR_UNION_EQ_EMPTY;
+"INTERIOR_UNIQUE",INTERIOR_UNIQUE;
+"INTERIOR_UNIV",INTERIOR_UNIV;
+"INTERS",INTERS;
+"INTERS_0",INTERS_0;
+"INTERS_1",INTERS_1;
+"INTERS_2",INTERS_2;
+"INTERS_FACES_FINITE_ALTBOUND",INTERS_FACES_FINITE_ALTBOUND;
+"INTERS_FACES_FINITE_BOUND",INTERS_FACES_FINITE_BOUND;
+"INTERS_GSPEC",INTERS_GSPEC;
+"INTERS_IMAGE",INTERS_IMAGE;
+"INTERS_INSERT",INTERS_INSERT;
+"INTERS_OVER_UNIONS",INTERS_OVER_UNIONS;
+"INTERS_UNION",INTERS_UNION;
+"INTERS_UNIONS",INTERS_UNIONS;
+"INTERVAL_BIJ_AFFINE",INTERVAL_BIJ_AFFINE;
+"INTERVAL_BIJ_BIJ",INTERVAL_BIJ_BIJ;
+"INTERVAL_BISECTION",INTERVAL_BISECTION;
+"INTERVAL_BISECTION_STEP",INTERVAL_BISECTION_STEP;
+"INTERVAL_BOUNDS_EMPTY_1",INTERVAL_BOUNDS_EMPTY_1;
+"INTERVAL_BOUNDS_NULL_1",INTERVAL_BOUNDS_NULL_1;
+"INTERVAL_CASES_1",INTERVAL_CASES_1;
+"INTERVAL_CONTAINS_COMPACT_NEIGHBOURHOOD",INTERVAL_CONTAINS_COMPACT_NEIGHBOURHOOD;
+"INTERVAL_DOUBLESPLIT",INTERVAL_DOUBLESPLIT;
+"INTERVAL_EQ_EMPTY",INTERVAL_EQ_EMPTY;
+"INTERVAL_EQ_EMPTY_1",INTERVAL_EQ_EMPTY_1;
+"INTERVAL_IMAGE_AFFINITY_INTERVAL",INTERVAL_IMAGE_AFFINITY_INTERVAL;
+"INTERVAL_IMAGE_STRETCH_INTERVAL",INTERVAL_IMAGE_STRETCH_INTERVAL;
+"INTERVAL_LOWERBOUND",INTERVAL_LOWERBOUND;
+"INTERVAL_LOWERBOUND_1",INTERVAL_LOWERBOUND_1;
+"INTERVAL_NE_EMPTY",INTERVAL_NE_EMPTY;
+"INTERVAL_NE_EMPTY_1",INTERVAL_NE_EMPTY_1;
+"INTERVAL_OPEN_SUBSET_CLOSED",INTERVAL_OPEN_SUBSET_CLOSED;
+"INTERVAL_SING",INTERVAL_SING;
+"INTERVAL_SPLIT",INTERVAL_SPLIT;
+"INTERVAL_SUBDIVISION",INTERVAL_SUBDIVISION;
+"INTERVAL_SUBSET_IS_INTERVAL",INTERVAL_SUBSET_IS_INTERVAL;
+"INTERVAL_TRANSLATION",INTERVAL_TRANSLATION;
+"INTERVAL_UPPERBOUND",INTERVAL_UPPERBOUND;
+"INTERVAL_UPPERBOUND_1",INTERVAL_UPPERBOUND_1;
+"INTER_ACI",INTER_ACI;
+"INTER_ASSOC",INTER_ASSOC;
+"INTER_COMM",INTER_COMM;
+"INTER_EMPTY",INTER_EMPTY;
+"INTER_IDEMPOT",INTER_IDEMPOT;
+"INTER_INTERIOR_UNIONS_INTERVALS",INTER_INTERIOR_UNIONS_INTERVALS;
+"INTER_INTERVAL",INTER_INTERVAL;
+"INTER_INTERVAL_1",INTER_INTERVAL_1;
+"INTER_INTERVAL_MIXED_EQ_EMPTY",INTER_INTERVAL_MIXED_EQ_EMPTY;
+"INTER_OVER_UNION",INTER_OVER_UNION;
+"INTER_SEGMENT",INTER_SEGMENT;
+"INTER_SUBSET",INTER_SUBSET;
+"INTER_UNIONS",INTER_UNIONS;
+"INTER_UNIV",INTER_UNIV;
+"INT_ABS",INT_ABS;
+"INT_ABS_0",INT_ABS_0;
+"INT_ABS_1",INT_ABS_1;
+"INT_ABS_ABS",INT_ABS_ABS;
+"INT_ABS_BETWEEN",INT_ABS_BETWEEN;
+"INT_ABS_BETWEEN1",INT_ABS_BETWEEN1;
+"INT_ABS_BETWEEN2",INT_ABS_BETWEEN2;
+"INT_ABS_BOUND",INT_ABS_BOUND;
+"INT_ABS_CASES",INT_ABS_CASES;
+"INT_ABS_CIRCLE",INT_ABS_CIRCLE;
+"INT_ABS_LE",INT_ABS_LE;
+"INT_ABS_MUL",INT_ABS_MUL;
+"INT_ABS_MUL_1",INT_ABS_MUL_1;
+"INT_ABS_NEG",INT_ABS_NEG;
+"INT_ABS_NUM",INT_ABS_NUM;
+"INT_ABS_NZ",INT_ABS_NZ;
+"INT_ABS_POS",INT_ABS_POS;
+"INT_ABS_POW",INT_ABS_POW;
+"INT_ABS_REFL",INT_ABS_REFL;
+"INT_ABS_SGN",INT_ABS_SGN;
+"INT_ABS_SIGN",INT_ABS_SIGN;
+"INT_ABS_SIGN2",INT_ABS_SIGN2;
+"INT_ABS_STILLNZ",INT_ABS_STILLNZ;
+"INT_ABS_SUB",INT_ABS_SUB;
+"INT_ABS_SUB_ABS",INT_ABS_SUB_ABS;
+"INT_ABS_TRIANGLE",INT_ABS_TRIANGLE;
+"INT_ABS_ZERO",INT_ABS_ZERO;
+"INT_ADD2_SUB2",INT_ADD2_SUB2;
+"INT_ADD_AC",INT_ADD_AC;
+"INT_ADD_ASSOC",INT_ADD_ASSOC;
+"INT_ADD_LDISTRIB",INT_ADD_LDISTRIB;
+"INT_ADD_LID",INT_ADD_LID;
+"INT_ADD_LINV",INT_ADD_LINV;
+"INT_ADD_RDISTRIB",INT_ADD_RDISTRIB;
+"INT_ADD_RID",INT_ADD_RID;
+"INT_ADD_RINV",INT_ADD_RINV;
+"INT_ADD_SUB",INT_ADD_SUB;
+"INT_ADD_SUB2",INT_ADD_SUB2;
+"INT_ADD_SYM",INT_ADD_SYM;
+"INT_ARCH",INT_ARCH;
+"INT_BOUNDS_LE",INT_BOUNDS_LE;
+"INT_BOUNDS_LT",INT_BOUNDS_LT;
+"INT_DIFFSQ",INT_DIFFSQ;
+"INT_DIVISION",INT_DIVISION;
+"INT_DIVISION_0",INT_DIVISION_0;
+"INT_DIVMOD_EXIST_0",INT_DIVMOD_EXIST_0;
+"INT_DIVMOD_UNIQ",INT_DIVMOD_UNIQ;
+"INT_ENTIRE",INT_ENTIRE;
+"INT_EQ_ADD_LCANCEL",INT_EQ_ADD_LCANCEL;
+"INT_EQ_ADD_LCANCEL_0",INT_EQ_ADD_LCANCEL_0;
+"INT_EQ_ADD_RCANCEL",INT_EQ_ADD_RCANCEL;
+"INT_EQ_ADD_RCANCEL_0",INT_EQ_ADD_RCANCEL_0;
+"INT_EQ_IMP_LE",INT_EQ_IMP_LE;
+"INT_EQ_MUL_LCANCEL",INT_EQ_MUL_LCANCEL;
+"INT_EQ_MUL_RCANCEL",INT_EQ_MUL_RCANCEL;
+"INT_EQ_NEG2",INT_EQ_NEG2;
+"INT_EQ_SQUARE_ABS",INT_EQ_SQUARE_ABS;
+"INT_EQ_SUB_LADD",INT_EQ_SUB_LADD;
+"INT_EQ_SUB_RADD",INT_EQ_SUB_RADD;
+"INT_EXISTS_ABS",INT_EXISTS_ABS;
+"INT_EXISTS_POS",INT_EXISTS_POS;
+"INT_FORALL_ABS",INT_FORALL_ABS;
+"INT_FORALL_POS",INT_FORALL_POS;
+"INT_GCD_EXISTS",INT_GCD_EXISTS;
+"INT_GCD_EXISTS_POS",INT_GCD_EXISTS_POS;
+"INT_GE",INT_GE;
+"INT_GT",INT_GT;
+"INT_GT_DISCRETE",INT_GT_DISCRETE;
+"INT_IMAGE",INT_IMAGE;
+"INT_LET_ADD",INT_LET_ADD;
+"INT_LET_ADD2",INT_LET_ADD2;
+"INT_LET_ANTISYM",INT_LET_ANTISYM;
+"INT_LET_TOTAL",INT_LET_TOTAL;
+"INT_LET_TRANS",INT_LET_TRANS;
+"INT_LE_01",INT_LE_01;
+"INT_LE_ADD",INT_LE_ADD;
+"INT_LE_ADD2",INT_LE_ADD2;
+"INT_LE_ADDL",INT_LE_ADDL;
+"INT_LE_ADDR",INT_LE_ADDR;
+"INT_LE_ANTISYM",INT_LE_ANTISYM;
+"INT_LE_DOUBLE",INT_LE_DOUBLE;
+"INT_LE_LADD",INT_LE_LADD;
+"INT_LE_LADD_IMP",INT_LE_LADD_IMP;
+"INT_LE_LMUL",INT_LE_LMUL;
+"INT_LE_LNEG",INT_LE_LNEG;
+"INT_LE_LT",INT_LE_LT;
+"INT_LE_MAX",INT_LE_MAX;
+"INT_LE_MIN",INT_LE_MIN;
+"INT_LE_MUL",INT_LE_MUL;
+"INT_LE_MUL_EQ",INT_LE_MUL_EQ;
+"INT_LE_NEG",INT_LE_NEG;
+"INT_LE_NEG2",INT_LE_NEG2;
+"INT_LE_NEGL",INT_LE_NEGL;
+"INT_LE_NEGR",INT_LE_NEGR;
+"INT_LE_NEGTOTAL",INT_LE_NEGTOTAL;
+"INT_LE_POW2",INT_LE_POW2;
+"INT_LE_RADD",INT_LE_RADD;
+"INT_LE_REFL",INT_LE_REFL;
+"INT_LE_RMUL",INT_LE_RMUL;
+"INT_LE_RNEG",INT_LE_RNEG;
+"INT_LE_SQUARE",INT_LE_SQUARE;
+"INT_LE_SQUARE_ABS",INT_LE_SQUARE_ABS;
+"INT_LE_SUB_LADD",INT_LE_SUB_LADD;
+"INT_LE_SUB_RADD",INT_LE_SUB_RADD;
+"INT_LE_TOTAL",INT_LE_TOTAL;
+"INT_LE_TRANS",INT_LE_TRANS;
+"INT_LNEG_UNIQ",INT_LNEG_UNIQ;
+"INT_LT",INT_LT;
+"INT_LTE_ADD",INT_LTE_ADD;
+"INT_LTE_ADD2",INT_LTE_ADD2;
+"INT_LTE_ANTISYM",INT_LTE_ANTISYM;
+"INT_LTE_TOTAL",INT_LTE_TOTAL;
+"INT_LTE_TRANS",INT_LTE_TRANS;
+"INT_LT_01",INT_LT_01;
+"INT_LT_ADD",INT_LT_ADD;
+"INT_LT_ADD1",INT_LT_ADD1;
+"INT_LT_ADD2",INT_LT_ADD2;
+"INT_LT_ADDL",INT_LT_ADDL;
+"INT_LT_ADDNEG",INT_LT_ADDNEG;
+"INT_LT_ADDNEG2",INT_LT_ADDNEG2;
+"INT_LT_ADDR",INT_LT_ADDR;
+"INT_LT_ADD_SUB",INT_LT_ADD_SUB;
+"INT_LT_ANTISYM",INT_LT_ANTISYM;
+"INT_LT_DISCRETE",INT_LT_DISCRETE;
+"INT_LT_GT",INT_LT_GT;
+"INT_LT_IMP_LE",INT_LT_IMP_LE;
+"INT_LT_IMP_NE",INT_LT_IMP_NE;
+"INT_LT_LADD",INT_LT_LADD;
+"INT_LT_LE",INT_LT_LE;
+"INT_LT_LMUL_EQ",INT_LT_LMUL_EQ;
+"INT_LT_MAX",INT_LT_MAX;
+"INT_LT_MIN",INT_LT_MIN;
+"INT_LT_MUL",INT_LT_MUL;
+"INT_LT_MUL_EQ",INT_LT_MUL_EQ;
+"INT_LT_NEG",INT_LT_NEG;
+"INT_LT_NEG2",INT_LT_NEG2;
+"INT_LT_NEGTOTAL",INT_LT_NEGTOTAL;
+"INT_LT_POW2",INT_LT_POW2;
+"INT_LT_RADD",INT_LT_RADD;
+"INT_LT_REFL",INT_LT_REFL;
+"INT_LT_RMUL_EQ",INT_LT_RMUL_EQ;
+"INT_LT_SQUARE_ABS",INT_LT_SQUARE_ABS;
+"INT_LT_SUB_LADD",INT_LT_SUB_LADD;
+"INT_LT_SUB_RADD",INT_LT_SUB_RADD;
+"INT_LT_TOTAL",INT_LT_TOTAL;
+"INT_LT_TRANS",INT_LT_TRANS;
+"INT_MAX",INT_MAX;
+"INT_MAX_ACI",INT_MAX_ACI;
+"INT_MAX_ASSOC",INT_MAX_ASSOC;
+"INT_MAX_LE",INT_MAX_LE;
+"INT_MAX_LT",INT_MAX_LT;
+"INT_MAX_MAX",INT_MAX_MAX;
+"INT_MAX_MIN",INT_MAX_MIN;
+"INT_MAX_SYM",INT_MAX_SYM;
+"INT_MIN",INT_MIN;
+"INT_MIN_ACI",INT_MIN_ACI;
+"INT_MIN_ASSOC",INT_MIN_ASSOC;
+"INT_MIN_LE",INT_MIN_LE;
+"INT_MIN_LT",INT_MIN_LT;
+"INT_MIN_MAX",INT_MIN_MAX;
+"INT_MIN_MIN",INT_MIN_MIN;
+"INT_MIN_SYM",INT_MIN_SYM;
+"INT_MUL_AC",INT_MUL_AC;
+"INT_MUL_ASSOC",INT_MUL_ASSOC;
+"INT_MUL_LID",INT_MUL_LID;
+"INT_MUL_LNEG",INT_MUL_LNEG;
+"INT_MUL_LZERO",INT_MUL_LZERO;
+"INT_MUL_POS_LE",INT_MUL_POS_LE;
+"INT_MUL_POS_LT",INT_MUL_POS_LT;
+"INT_MUL_RID",INT_MUL_RID;
+"INT_MUL_RNEG",INT_MUL_RNEG;
+"INT_MUL_RZERO",INT_MUL_RZERO;
+"INT_MUL_SYM",INT_MUL_SYM;
+"INT_NEGNEG",INT_NEGNEG;
+"INT_NEG_0",INT_NEG_0;
+"INT_NEG_ADD",INT_NEG_ADD;
+"INT_NEG_EQ",INT_NEG_EQ;
+"INT_NEG_EQ_0",INT_NEG_EQ_0;
+"INT_NEG_GE0",INT_NEG_GE0;
+"INT_NEG_GT0",INT_NEG_GT0;
+"INT_NEG_LE0",INT_NEG_LE0;
+"INT_NEG_LMUL",INT_NEG_LMUL;
+"INT_NEG_LT0",INT_NEG_LT0;
+"INT_NEG_MINUS1",INT_NEG_MINUS1;
+"INT_NEG_MUL2",INT_NEG_MUL2;
+"INT_NEG_NEG",INT_NEG_NEG;
+"INT_NEG_RMUL",INT_NEG_RMUL;
+"INT_NEG_SUB",INT_NEG_SUB;
+"INT_NOT_EQ",INT_NOT_EQ;
+"INT_NOT_LE",INT_NOT_LE;
+"INT_NOT_LT",INT_NOT_LT;
+"INT_OF_NUM_ADD",INT_OF_NUM_ADD;
+"INT_OF_NUM_EQ",INT_OF_NUM_EQ;
+"INT_OF_NUM_EXISTS",INT_OF_NUM_EXISTS;
+"INT_OF_NUM_GE",INT_OF_NUM_GE;
+"INT_OF_NUM_GT",INT_OF_NUM_GT;
+"INT_OF_NUM_LE",INT_OF_NUM_LE;
+"INT_OF_NUM_LT",INT_OF_NUM_LT;
+"INT_OF_NUM_MAX",INT_OF_NUM_MAX;
+"INT_OF_NUM_MIN",INT_OF_NUM_MIN;
+"INT_OF_NUM_MUL",INT_OF_NUM_MUL;
+"INT_OF_NUM_OF_INT",INT_OF_NUM_OF_INT;
+"INT_OF_NUM_POW",INT_OF_NUM_POW;
+"INT_OF_NUM_SUB",INT_OF_NUM_SUB;
+"INT_OF_NUM_SUC",INT_OF_NUM_SUC;
+"INT_OF_REAL_OF_INT",INT_OF_REAL_OF_INT;
+"INT_POS",INT_POS;
+"INT_POS_NZ",INT_POS_NZ;
+"INT_POW",INT_POW;
+"INT_POW2_ABS",INT_POW2_ABS;
+"INT_POW_1",INT_POW_1;
+"INT_POW_1_LE",INT_POW_1_LE;
+"INT_POW_1_LT",INT_POW_1_LT;
+"INT_POW_2",INT_POW_2;
+"INT_POW_ADD",INT_POW_ADD;
+"INT_POW_EQ",INT_POW_EQ;
+"INT_POW_EQ_0",INT_POW_EQ_0;
+"INT_POW_EQ_ABS",INT_POW_EQ_ABS;
+"INT_POW_LE",INT_POW_LE;
+"INT_POW_LE2",INT_POW_LE2;
+"INT_POW_LE2_ODD",INT_POW_LE2_ODD;
+"INT_POW_LE2_REV",INT_POW_LE2_REV;
+"INT_POW_LE_1",INT_POW_LE_1;
+"INT_POW_LT",INT_POW_LT;
+"INT_POW_LT2",INT_POW_LT2;
+"INT_POW_LT2_REV",INT_POW_LT2_REV;
+"INT_POW_LT_1",INT_POW_LT_1;
+"INT_POW_MONO",INT_POW_MONO;
+"INT_POW_MONO_LT",INT_POW_MONO_LT;
+"INT_POW_MUL",INT_POW_MUL;
+"INT_POW_NEG",INT_POW_NEG;
+"INT_POW_NZ",INT_POW_NZ;
+"INT_POW_ONE",INT_POW_ONE;
+"INT_POW_POW",INT_POW_POW;
+"INT_POW_ZERO",INT_POW_ZERO;
+"INT_RNEG_UNIQ",INT_RNEG_UNIQ;
+"INT_SGN",INT_SGN;
+"INT_SGN_0",INT_SGN_0;
+"INT_SGN_ABS",INT_SGN_ABS;
+"INT_SGN_CASES",INT_SGN_CASES;
+"INT_SGN_EQ",INT_SGN_EQ;
+"INT_SGN_INEQS",INT_SGN_INEQS;
+"INT_SGN_MUL",INT_SGN_MUL;
+"INT_SGN_NEG",INT_SGN_NEG;
+"INT_SOS_EQ_0",INT_SOS_EQ_0;
+"INT_SUB",INT_SUB;
+"INT_SUB_0",INT_SUB_0;
+"INT_SUB_ABS",INT_SUB_ABS;
+"INT_SUB_ADD",INT_SUB_ADD;
+"INT_SUB_ADD2",INT_SUB_ADD2;
+"INT_SUB_LDISTRIB",INT_SUB_LDISTRIB;
+"INT_SUB_LE",INT_SUB_LE;
+"INT_SUB_LNEG",INT_SUB_LNEG;
+"INT_SUB_LT",INT_SUB_LT;
+"INT_SUB_LZERO",INT_SUB_LZERO;
+"INT_SUB_NEG2",INT_SUB_NEG2;
+"INT_SUB_RDISTRIB",INT_SUB_RDISTRIB;
+"INT_SUB_REFL",INT_SUB_REFL;
+"INT_SUB_RNEG",INT_SUB_RNEG;
+"INT_SUB_RZERO",INT_SUB_RZERO;
+"INT_SUB_SUB",INT_SUB_SUB;
+"INT_SUB_SUB2",INT_SUB_SUB2;
+"INT_SUB_TRIANGLE",INT_SUB_TRIANGLE;
+"INT_WOP",INT_WOP;
+"INVERSE_I",INVERSE_I;
+"INVERSE_SWAP",INVERSE_SWAP;
+"INVERSE_UNIQUE_o",INVERSE_UNIQUE_o;
+"INVERTIBLE_COFACTOR",INVERTIBLE_COFACTOR;
+"INVERTIBLE_DET_NZ",INVERTIBLE_DET_NZ;
+"INVERTIBLE_FIXPOINT_PROPERTY",INVERTIBLE_FIXPOINT_PROPERTY;
+"INVERTIBLE_IMP_SQUARE_MATRIX",INVERTIBLE_IMP_SQUARE_MATRIX;
+"INVERTIBLE_LEFT_INVERSE",INVERTIBLE_LEFT_INVERSE;
+"INVERTIBLE_MATRIX_MUL",INVERTIBLE_MATRIX_MUL;
+"INVERTIBLE_NEG",INVERTIBLE_NEG;
+"INVERTIBLE_RIGHT_INVERSE",INVERTIBLE_RIGHT_INVERSE;
+"INVERTIBLE_TRANSP",INVERTIBLE_TRANSP;
+"IN_AFFINE_ADD_MUL",IN_AFFINE_ADD_MUL;
+"IN_AFFINE_ADD_MUL_DIFF",IN_AFFINE_ADD_MUL_DIFF;
+"IN_AFFINE_HULL_LINEAR_IMAGE",IN_AFFINE_HULL_LINEAR_IMAGE;
+"IN_AFFINE_MUL_DIFF_ADD",IN_AFFINE_MUL_DIFF_ADD;
+"IN_AFFINE_SUB_MUL_DIFF",IN_AFFINE_SUB_MUL_DIFF;
+"IN_BALL",IN_BALL;
+"IN_BALL_0",IN_BALL_0;
+"IN_CARD_ADD",IN_CARD_ADD;
+"IN_CARD_MUL",IN_CARD_MUL;
+"IN_CBALL",IN_CBALL;
+"IN_CBALL_0",IN_CBALL_0;
+"IN_CLOSURE_CONNECTED_COMPONENT",IN_CLOSURE_CONNECTED_COMPONENT;
+"IN_CLOSURE_DELETE",IN_CLOSURE_DELETE;
+"IN_COMPONENTS",IN_COMPONENTS;
+"IN_COMPONENTS_CONNECTED",IN_COMPONENTS_CONNECTED;
+"IN_COMPONENTS_MAXIMAL",IN_COMPONENTS_MAXIMAL;
+"IN_COMPONENTS_NONEMPTY",IN_COMPONENTS_NONEMPTY;
+"IN_COMPONENTS_SELF",IN_COMPONENTS_SELF;
+"IN_COMPONENTS_SUBSET",IN_COMPONENTS_SUBSET;
+"IN_CONVEX_HULL_EXCHANGE",IN_CONVEX_HULL_EXCHANGE;
+"IN_CONVEX_HULL_EXCHANGE_UNIQUE",IN_CONVEX_HULL_EXCHANGE_UNIQUE;
+"IN_CONVEX_HULL_LINEAR_IMAGE",IN_CONVEX_HULL_LINEAR_IMAGE;
+"IN_CONVEX_SET",IN_CONVEX_SET;
+"IN_CROSS",IN_CROSS;
+"IN_DELETE",IN_DELETE;
+"IN_DELETE_EQ",IN_DELETE_EQ;
+"IN_DIFF",IN_DIFF;
+"IN_DIMINDEX_SWAP",IN_DIMINDEX_SWAP;
+"IN_DIRECTION",IN_DIRECTION;
+"IN_DISJOINT",IN_DISJOINT;
+"IN_ELIM_PAIR_THM",IN_ELIM_PAIR_THM;
+"IN_ELIM_PASTECART_THM",IN_ELIM_PASTECART_THM;
+"IN_ELIM_THM",IN_ELIM_THM;
+"IN_EPIGRAPH",IN_EPIGRAPH;
+"IN_FROM",IN_FROM;
+"IN_FRONTIER_CONVEX_HULL",IN_FRONTIER_CONVEX_HULL;
+"IN_IMAGE",IN_IMAGE;
+"IN_IMAGE_LIFT_DROP",IN_IMAGE_LIFT_DROP;
+"IN_INSERT",IN_INSERT;
+"IN_INTER",IN_INTER;
+"IN_INTERIOR",IN_INTERIOR;
+"IN_INTERIOR_CBALL",IN_INTERIOR_CBALL;
+"IN_INTERIOR_CLOSURE_CONVEX_SEGMENT",IN_INTERIOR_CLOSURE_CONVEX_SEGMENT;
+"IN_INTERIOR_CLOSURE_CONVEX_SHRINK",IN_INTERIOR_CLOSURE_CONVEX_SHRINK;
+"IN_INTERIOR_CONVEX_SHRINK",IN_INTERIOR_CONVEX_SHRINK;
+"IN_INTERIOR_LINEAR_IMAGE",IN_INTERIOR_LINEAR_IMAGE;
+"IN_INTERS",IN_INTERS;
+"IN_INTERVAL",IN_INTERVAL;
+"IN_INTERVAL_1",IN_INTERVAL_1;
+"IN_INTERVAL_INTERVAL_BIJ",IN_INTERVAL_INTERVAL_BIJ;
+"IN_INTERVAL_REFLECT",IN_INTERVAL_REFLECT;
+"IN_NUMSEG",IN_NUMSEG;
+"IN_NUMSEG_0",IN_NUMSEG_0;
+"IN_OPEN_SEGMENT",IN_OPEN_SEGMENT;
+"IN_OPEN_SEGMENT_ALT",IN_OPEN_SEGMENT_ALT;
+"IN_RELATIVE_INTERIOR",IN_RELATIVE_INTERIOR;
+"IN_RELATIVE_INTERIOR_CBALL",IN_RELATIVE_INTERIOR_CBALL;
+"IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SEGMENT",IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SEGMENT;
+"IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SHRINK",IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SHRINK;
+"IN_RELATIVE_INTERIOR_CONVEX_SHRINK",IN_RELATIVE_INTERIOR_CONVEX_SHRINK;
+"IN_REST",IN_REST;
+"IN_SEGMENT",IN_SEGMENT;
+"IN_SEGMENT_COMPONENT",IN_SEGMENT_COMPONENT;
+"IN_SET_OF_LIST",IN_SET_OF_LIST;
+"IN_SING",IN_SING;
+"IN_SPAN_DELETE",IN_SPAN_DELETE;
+"IN_SPAN_IMAGE_BASIS",IN_SPAN_IMAGE_BASIS;
+"IN_SPAN_INSERT",IN_SPAN_INSERT;
+"IN_SPHERE",IN_SPHERE;
+"IN_SPHERE_0",IN_SPHERE_0;
+"IN_SUPPORT",IN_SUPPORT;
+"IN_UNION",IN_UNION;
+"IN_UNIONS",IN_UNIONS;
+"IN_UNIV",IN_UNIV;
+"IRRATIONAL_APPROXIMATION",IRRATIONAL_APPROXIMATION;
+"ISO",ISO;
+"ISOMETRIES_SUBSPACES",ISOMETRIES_SUBSPACES;
+"ISOMETRY_IMP_AFFINITY",ISOMETRY_IMP_AFFINITY;
+"ISOMETRY_LINEAR",ISOMETRY_LINEAR;
+"ISOMETRY_ON_IMP_CONTINUOUS_ON",ISOMETRY_ON_IMP_CONTINUOUS_ON;
+"ISOMETRY_SPHERE_EXTEND",ISOMETRY_SPHERE_EXTEND;
+"ISOMETRY_SUBSET_SUBSPACE",ISOMETRY_SUBSET_SUBSPACE;
+"ISOMETRY_SUBSPACES",ISOMETRY_SUBSPACES;
+"ISOMETRY_UNIV_SUBSPACE",ISOMETRY_UNIV_SUBSPACE;
+"ISOMETRY_UNIV_SUPERSET_SUBSPACE",ISOMETRY_UNIV_SUPERSET_SUBSPACE;
+"ISOMETRY_UNIV_UNIV",ISOMETRY_UNIV_UNIV;
+"ISOMORPHISMS_UNIV_UNIV",ISOMORPHISMS_UNIV_UNIV;
+"ISOMORPHISM_EXPAND",ISOMORPHISM_EXPAND;
+"ISO_FUN",ISO_FUN;
+"ISO_REFL",ISO_REFL;
+"ISO_USAGE",ISO_USAGE;
+"ISTOPLOGY_SUBTOPOLOGY",ISTOPLOGY_SUBTOPOLOGY;
+"ISTOPOLOGY_OPEN_IN",ISTOPOLOGY_OPEN_IN;
+"IS_AFFINE_HULL",IS_AFFINE_HULL;
+"IS_CONVEX_HULL",IS_CONVEX_HULL;
+"IS_HULL",IS_HULL;
+"IS_INTERVAL_1",IS_INTERVAL_1;
+"IS_INTERVAL_1_CASES",IS_INTERVAL_1_CASES;
+"IS_INTERVAL_COMPACT",IS_INTERVAL_COMPACT;
+"IS_INTERVAL_CONNECTED",IS_INTERVAL_CONNECTED;
+"IS_INTERVAL_CONNECTED_1",IS_INTERVAL_CONNECTED_1;
+"IS_INTERVAL_CONTRACTIBLE_1",IS_INTERVAL_CONTRACTIBLE_1;
+"IS_INTERVAL_CONVEX",IS_INTERVAL_CONVEX;
+"IS_INTERVAL_CONVEX_1",IS_INTERVAL_CONVEX_1;
+"IS_INTERVAL_EMPTY",IS_INTERVAL_EMPTY;
+"IS_INTERVAL_IMP_LOCALLY_COMPACT",IS_INTERVAL_IMP_LOCALLY_COMPACT;
+"IS_INTERVAL_INTER",IS_INTERVAL_INTER;
+"IS_INTERVAL_INTERVAL",IS_INTERVAL_INTERVAL;
+"IS_INTERVAL_PATH_CONNECTED",IS_INTERVAL_PATH_CONNECTED;
+"IS_INTERVAL_PATH_CONNECTED_1",IS_INTERVAL_PATH_CONNECTED_1;
+"IS_INTERVAL_PCROSS",IS_INTERVAL_PCROSS;
+"IS_INTERVAL_PCROSS_EQ",IS_INTERVAL_PCROSS_EQ;
+"IS_INTERVAL_POINTWISE",IS_INTERVAL_POINTWISE;
+"IS_INTERVAL_SCALING",IS_INTERVAL_SCALING;
+"IS_INTERVAL_SCALING_EQ",IS_INTERVAL_SCALING_EQ;
+"IS_INTERVAL_SIMPLY_CONNECTED_1",IS_INTERVAL_SIMPLY_CONNECTED_1;
+"IS_INTERVAL_SING",IS_INTERVAL_SING;
+"IS_INTERVAL_SUMS",IS_INTERVAL_SUMS;
+"IS_INTERVAL_TRANSLATION",IS_INTERVAL_TRANSLATION;
+"IS_INTERVAL_TRANSLATION_EQ",IS_INTERVAL_TRANSLATION_EQ;
+"IS_INTERVAL_UNIV",IS_INTERVAL_UNIV;
+"ITERATE_AND",ITERATE_AND;
+"ITERATE_BIJECTION",ITERATE_BIJECTION;
+"ITERATE_CASES",ITERATE_CASES;
+"ITERATE_CLAUSES",ITERATE_CLAUSES;
+"ITERATE_CLAUSES_GEN",ITERATE_CLAUSES_GEN;
+"ITERATE_CLAUSES_NUMSEG",ITERATE_CLAUSES_NUMSEG;
+"ITERATE_CLOSED",ITERATE_CLOSED;
+"ITERATE_DELETE",ITERATE_DELETE;
+"ITERATE_DELTA",ITERATE_DELTA;
+"ITERATE_DIFF",ITERATE_DIFF;
+"ITERATE_DIFF_GEN",ITERATE_DIFF_GEN;
+"ITERATE_EQ",ITERATE_EQ;
+"ITERATE_EQ_GENERAL",ITERATE_EQ_GENERAL;
+"ITERATE_EQ_GENERAL_INVERSES",ITERATE_EQ_GENERAL_INVERSES;
+"ITERATE_EQ_NEUTRAL",ITERATE_EQ_NEUTRAL;
+"ITERATE_EXPAND_CASES",ITERATE_EXPAND_CASES;
+"ITERATE_IMAGE",ITERATE_IMAGE;
+"ITERATE_IMAGE_NONZERO",ITERATE_IMAGE_NONZERO;
+"ITERATE_INCL_EXCL",ITERATE_INCL_EXCL;
+"ITERATE_INJECTION",ITERATE_INJECTION;
+"ITERATE_ITERATE_PRODUCT",ITERATE_ITERATE_PRODUCT;
+"ITERATE_NONZERO_IMAGE_LEMMA",ITERATE_NONZERO_IMAGE_LEMMA;
+"ITERATE_OP",ITERATE_OP;
+"ITERATE_OP_GEN",ITERATE_OP_GEN;
+"ITERATE_PAIR",ITERATE_PAIR;
+"ITERATE_PERMUTE",ITERATE_PERMUTE;
+"ITERATE_RELATED",ITERATE_RELATED;
+"ITERATE_SING",ITERATE_SING;
+"ITERATE_SOME",ITERATE_SOME;
+"ITERATE_SUPERSET",ITERATE_SUPERSET;
+"ITERATE_SUPPORT",ITERATE_SUPPORT;
+"ITERATE_UNION",ITERATE_UNION;
+"ITERATE_UNION_GEN",ITERATE_UNION_GEN;
+"ITERATE_UNION_NONZERO",ITERATE_UNION_NONZERO;
+"ITLIST",ITLIST;
+"ITLIST2",ITLIST2;
+"ITLIST2_DEF",ITLIST2_DEF;
+"ITLIST_APPEND",ITLIST_APPEND;
+"ITLIST_EXTRA",ITLIST_EXTRA;
+"ITSET",ITSET;
+"ITSET_EQ",ITSET_EQ;
+"IVT_DECREASING_COMPONENT_1",IVT_DECREASING_COMPONENT_1;
+"IVT_DECREASING_COMPONENT_ON_1",IVT_DECREASING_COMPONENT_ON_1;
+"IVT_INCREASING_COMPONENT_1",IVT_INCREASING_COMPONENT_1;
+"IVT_INCREASING_COMPONENT_ON_1",IVT_INCREASING_COMPONENT_ON_1;
+"I_DEF",I_DEF;
+"I_O_ID",I_O_ID;
+"I_THM",I_THM;
+"JACOBIAN_WORKS",JACOBIAN_WORKS;
+"JOINABLE_COMPONENTS_EQ",JOINABLE_COMPONENTS_EQ;
+"JOINABLE_CONNECTED_COMPONENT_EQ",JOINABLE_CONNECTED_COMPONENT_EQ;
+"JOINPATHS",JOINPATHS;
+"JOINPATHS_LINEAR_IMAGE",JOINPATHS_LINEAR_IMAGE;
+"JOINPATHS_TRANSLATION",JOINPATHS_TRANSLATION;
+"JOIN_PATHS_EQ",JOIN_PATHS_EQ;
+"JOIN_SUBPATHS_MIDDLE",JOIN_SUBPATHS_MIDDLE;
+"JORDAN_CURVE_THEOREM",JORDAN_CURVE_THEOREM;
+"JORDAN_DISCONNECTED",JORDAN_DISCONNECTED;
+"JORDAN_INSIDE_OUTSIDE",JORDAN_INSIDE_OUTSIDE;
+"JUNG",JUNG;
+"KIRCHBERGER",KIRCHBERGER;
+"KL",KL;
+"KLE_ADJACENT",KLE_ADJACENT;
+"KLE_ANTISYM",KLE_ANTISYM;
+"KLE_BETWEEN_L",KLE_BETWEEN_L;
+"KLE_BETWEEN_R",KLE_BETWEEN_R;
+"KLE_IMP_POINTWISE",KLE_IMP_POINTWISE;
+"KLE_MAXIMAL",KLE_MAXIMAL;
+"KLE_MINIMAL",KLE_MINIMAL;
+"KLE_RANGE_COMBINE",KLE_RANGE_COMBINE;
+"KLE_RANGE_COMBINE_L",KLE_RANGE_COMBINE_L;
+"KLE_RANGE_COMBINE_R",KLE_RANGE_COMBINE_R;
+"KLE_RANGE_INDUCT",KLE_RANGE_INDUCT;
+"KLE_REFL",KLE_REFL;
+"KLE_STRICT",KLE_STRICT;
+"KLE_STRICT_SET",KLE_STRICT_SET;
+"KLE_SUC",KLE_SUC;
+"KLE_TRANS",KLE_TRANS;
+"KLE_TRANS_1",KLE_TRANS_1;
+"KLE_TRANS_2",KLE_TRANS_2;
+"KL_POSET_LEMMA",KL_POSET_LEMMA;
+"KREIN_MILMAN",KREIN_MILMAN;
+"KREIN_MILMAN_FRONTIER",KREIN_MILMAN_FRONTIER;
+"KREIN_MILMAN_MINKOWSKI",KREIN_MILMAN_MINKOWSKI;
+"KREIN_MILMAN_POLYTOPE",KREIN_MILMAN_POLYTOPE;
+"KREIN_MILMAN_RELATIVE_FRONTIER",KREIN_MILMAN_RELATIVE_FRONTIER;
+"KSIMPLEX_0",KSIMPLEX_0;
+"KSIMPLEX_EXTREMA",KSIMPLEX_EXTREMA;
+"KSIMPLEX_EXTREMA_STRONG",KSIMPLEX_EXTREMA_STRONG;
+"KSIMPLEX_FIX_PLANE",KSIMPLEX_FIX_PLANE;
+"KSIMPLEX_FIX_PLANE_0",KSIMPLEX_FIX_PLANE_0;
+"KSIMPLEX_FIX_PLANE_P",KSIMPLEX_FIX_PLANE_P;
+"KSIMPLEX_PREDECESSOR",KSIMPLEX_PREDECESSOR;
+"KSIMPLEX_REPLACE_0",KSIMPLEX_REPLACE_0;
+"KSIMPLEX_REPLACE_1",KSIMPLEX_REPLACE_1;
+"KSIMPLEX_REPLACE_2",KSIMPLEX_REPLACE_2;
+"KSIMPLEX_SUCCESSOR",KSIMPLEX_SUCCESSOR;
+"KUHN_COMBINATORIAL",KUHN_COMBINATORIAL;
+"KUHN_COMPLETE_LEMMA",KUHN_COMPLETE_LEMMA;
+"KUHN_COUNTING_LEMMA",KUHN_COUNTING_LEMMA;
+"KUHN_INDUCTION",KUHN_INDUCTION;
+"KUHN_LABELLING_LEMMA",KUHN_LABELLING_LEMMA;
+"KUHN_LEMMA",KUHN_LEMMA;
+"KUHN_SIMPLEX_LEMMA",KUHN_SIMPLEX_LEMMA;
+"L1_LE_NORM",L1_LE_NORM;
+"LAMBDA_ADD_GALOIS",LAMBDA_ADD_GALOIS;
+"LAMBDA_BETA",LAMBDA_BETA;
+"LAMBDA_BETA_PERM",LAMBDA_BETA_PERM;
+"LAMBDA_ETA",LAMBDA_ETA;
+"LAMBDA_PAIR",LAMBDA_PAIR;
+"LAMBDA_PAIR_THM",LAMBDA_PAIR_THM;
+"LAMBDA_SKOLEM",LAMBDA_SKOLEM;
+"LAMBDA_SWAP_GALOIS",LAMBDA_SWAP_GALOIS;
+"LAMBDA_UNIQUE",LAMBDA_UNIQUE;
+"LAST",LAST;
+"LAST_APPEND",LAST_APPEND;
+"LAST_CLAUSES",LAST_CLAUSES;
+"LAST_EL",LAST_EL;
+"LE",LE;
+"LEBESGUE_COVERING_LEMMA",LEBESGUE_COVERING_LEMMA;
+"LEBESGUE_MEASURABLE_CLOSED",LEBESGUE_MEASURABLE_CLOSED;
+"LEBESGUE_MEASURABLE_COMPACT",LEBESGUE_MEASURABLE_COMPACT;
+"LEBESGUE_MEASURABLE_COMPL",LEBESGUE_MEASURABLE_COMPL;
+"LEBESGUE_MEASURABLE_CONTINUOUS_IMAGE",LEBESGUE_MEASURABLE_CONTINUOUS_IMAGE;
+"LEBESGUE_MEASURABLE_CONVEX",LEBESGUE_MEASURABLE_CONVEX;
+"LEBESGUE_MEASURABLE_COUNTABLE_INTERS",LEBESGUE_MEASURABLE_COUNTABLE_INTERS;
+"LEBESGUE_MEASURABLE_COUNTABLE_INTERS_EXPLICIT",LEBESGUE_MEASURABLE_COUNTABLE_INTERS_EXPLICIT;
+"LEBESGUE_MEASURABLE_COUNTABLE_UNIONS",LEBESGUE_MEASURABLE_COUNTABLE_UNIONS;
+"LEBESGUE_MEASURABLE_COUNTABLE_UNIONS_EXPLICIT",LEBESGUE_MEASURABLE_COUNTABLE_UNIONS_EXPLICIT;
+"LEBESGUE_MEASURABLE_DIFF",LEBESGUE_MEASURABLE_DIFF;
+"LEBESGUE_MEASURABLE_DIFFERENTIABLE_IMAGE",LEBESGUE_MEASURABLE_DIFFERENTIABLE_IMAGE;
+"LEBESGUE_MEASURABLE_EMPTY",LEBESGUE_MEASURABLE_EMPTY;
+"LEBESGUE_MEASURABLE_IFF_MEASURABLE",LEBESGUE_MEASURABLE_IFF_MEASURABLE;
+"LEBESGUE_MEASURABLE_INNER_CLOSED",LEBESGUE_MEASURABLE_INNER_CLOSED;
+"LEBESGUE_MEASURABLE_INTER",LEBESGUE_MEASURABLE_INTER;
+"LEBESGUE_MEASURABLE_INTERS",LEBESGUE_MEASURABLE_INTERS;
+"LEBESGUE_MEASURABLE_INTERVAL",LEBESGUE_MEASURABLE_INTERVAL;
+"LEBESGUE_MEASURABLE_JORDAN",LEBESGUE_MEASURABLE_JORDAN;
+"LEBESGUE_MEASURABLE_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED",LEBESGUE_MEASURABLE_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED;
+"LEBESGUE_MEASURABLE_LEBESGUE_MEASURABLE_PREIMAGE_OPEN",LEBESGUE_MEASURABLE_LEBESGUE_MEASURABLE_PREIMAGE_OPEN;
+"LEBESGUE_MEASURABLE_LINEAR_IMAGE_EQ",LEBESGUE_MEASURABLE_LINEAR_IMAGE_EQ;
+"LEBESGUE_MEASURABLE_ON_SUBINTERVALS",LEBESGUE_MEASURABLE_ON_SUBINTERVALS;
+"LEBESGUE_MEASURABLE_OPEN",LEBESGUE_MEASURABLE_OPEN;
+"LEBESGUE_MEASURABLE_OUTER_OPEN",LEBESGUE_MEASURABLE_OUTER_OPEN;
+"LEBESGUE_MEASURABLE_PREIMAGE_CLOSED",LEBESGUE_MEASURABLE_PREIMAGE_CLOSED;
+"LEBESGUE_MEASURABLE_PREIMAGE_OPEN",LEBESGUE_MEASURABLE_PREIMAGE_OPEN;
+"LEBESGUE_MEASURABLE_REGULAR_INNER",LEBESGUE_MEASURABLE_REGULAR_INNER;
+"LEBESGUE_MEASURABLE_REGULAR_OUTER",LEBESGUE_MEASURABLE_REGULAR_OUTER;
+"LEBESGUE_MEASURABLE_TRANSLATION",LEBESGUE_MEASURABLE_TRANSLATION;
+"LEBESGUE_MEASURABLE_UNION",LEBESGUE_MEASURABLE_UNION;
+"LEBESGUE_MEASURABLE_UNIONS",LEBESGUE_MEASURABLE_UNIONS;
+"LEBESGUE_MEASURABLE_UNIV",LEBESGUE_MEASURABLE_UNIV;
+"LEFT_ADD_DISTRIB",LEFT_ADD_DISTRIB;
+"LEFT_AND_EXISTS_THM",LEFT_AND_EXISTS_THM;
+"LEFT_AND_FORALL_THM",LEFT_AND_FORALL_THM;
+"LEFT_EXISTS_AND_THM",LEFT_EXISTS_AND_THM;
+"LEFT_EXISTS_IMP_THM",LEFT_EXISTS_IMP_THM;
+"LEFT_FORALL_IMP_THM",LEFT_FORALL_IMP_THM;
+"LEFT_FORALL_OR_THM",LEFT_FORALL_OR_THM;
+"LEFT_IMP_EXISTS_THM",LEFT_IMP_EXISTS_THM;
+"LEFT_IMP_FORALL_THM",LEFT_IMP_FORALL_THM;
+"LEFT_INVERSE_LINEAR",LEFT_INVERSE_LINEAR;
+"LEFT_INVERTIBLE_TRANSP",LEFT_INVERTIBLE_TRANSP;
+"LEFT_OR_DISTRIB",LEFT_OR_DISTRIB;
+"LEFT_OR_EXISTS_THM",LEFT_OR_EXISTS_THM;
+"LEFT_OR_FORALL_THM",LEFT_OR_FORALL_THM;
+"LEFT_RIGHT_INVERSE_EQ",LEFT_RIGHT_INVERSE_EQ;
+"LEFT_RIGHT_INVERSE_LINEAR",LEFT_RIGHT_INVERSE_LINEAR;
+"LEFT_SUB_DISTRIB",LEFT_SUB_DISTRIB;
+"LEMMA",LEMMA;
+"LENGTH",LENGTH;
+"LENGTH_APPEND",LENGTH_APPEND;
+"LENGTH_EQ_CONS",LENGTH_EQ_CONS;
+"LENGTH_EQ_NIL",LENGTH_EQ_NIL;
+"LENGTH_LIST_OF_SET",LENGTH_LIST_OF_SET;
+"LENGTH_MAP",LENGTH_MAP;
+"LENGTH_MAP2",LENGTH_MAP2;
+"LENGTH_REPLICATE",LENGTH_REPLICATE;
+"LENGTH_TL",LENGTH_TL;
+"LET_ADD2",LET_ADD2;
+"LET_ANTISYM",LET_ANTISYM;
+"LET_CASES",LET_CASES;
+"LET_DEF",LET_DEF;
+"LET_END_DEF",LET_END_DEF;
+"LET_TRANS",LET_TRANS;
+"LE_0",LE_0;
+"LE_1",LE_1;
+"LE_ADD",LE_ADD;
+"LE_ADD2",LE_ADD2;
+"LE_ADDR",LE_ADDR;
+"LE_ADD_LCANCEL",LE_ADD_LCANCEL;
+"LE_ADD_RCANCEL",LE_ADD_RCANCEL;
+"LE_ANTISYM",LE_ANTISYM;
+"LE_C",LE_C;
+"LE_CASES",LE_CASES;
+"LE_EXISTS",LE_EXISTS;
+"LE_EXP",LE_EXP;
+"LE_LDIV",LE_LDIV;
+"LE_LDIV_EQ",LE_LDIV_EQ;
+"LE_LT",LE_LT;
+"LE_MULT2",LE_MULT2;
+"LE_MULT_LCANCEL",LE_MULT_LCANCEL;
+"LE_MULT_RCANCEL",LE_MULT_RCANCEL;
+"LE_RDIV_EQ",LE_RDIV_EQ;
+"LE_REFL",LE_REFL;
+"LE_SQUARE_REFL",LE_SQUARE_REFL;
+"LE_SUC",LE_SUC;
+"LE_SUC_LT",LE_SUC_LT;
+"LE_TRANS",LE_TRANS;
+"LIFT_ADD",LIFT_ADD;
+"LIFT_CMUL",LIFT_CMUL;
+"LIFT_COMPONENT",LIFT_COMPONENT;
+"LIFT_DROP",LIFT_DROP;
+"LIFT_EQ",LIFT_EQ;
+"LIFT_EQ_CMUL",LIFT_EQ_CMUL;
+"LIFT_INTEGRAL_COMPONENT",LIFT_INTEGRAL_COMPONENT;
+"LIFT_IN_IMAGE_LIFT",LIFT_IN_IMAGE_LIFT;
+"LIFT_NEG",LIFT_NEG;
+"LIFT_NUM",LIFT_NUM;
+"LIFT_SUB",LIFT_SUB;
+"LIFT_SUM",LIFT_SUM;
+"LIM",LIM;
+"LIMIT_POINT_FINITE",LIMIT_POINT_FINITE;
+"LIMIT_POINT_OF_SPHERE",LIMIT_POINT_OF_SPHERE;
+"LIMIT_POINT_UNION",LIMIT_POINT_UNION;
+"LIMPT_APPROACHABLE",LIMPT_APPROACHABLE;
+"LIMPT_APPROACHABLE_LE",LIMPT_APPROACHABLE_LE;
+"LIMPT_APPROACHABLE_LIFT",LIMPT_APPROACHABLE_LIFT;
+"LIMPT_BALL",LIMPT_BALL;
+"LIMPT_EMPTY",LIMPT_EMPTY;
+"LIMPT_INFINITE_BALL",LIMPT_INFINITE_BALL;
+"LIMPT_INFINITE_CBALL",LIMPT_INFINITE_CBALL;
+"LIMPT_INFINITE_OPEN",LIMPT_INFINITE_OPEN;
+"LIMPT_INJECTIVE_LINEAR_IMAGE_EQ",LIMPT_INJECTIVE_LINEAR_IMAGE_EQ;
+"LIMPT_INSERT",LIMPT_INSERT;
+"LIMPT_OF_CLOSURE",LIMPT_OF_CLOSURE;
+"LIMPT_OF_CONDENSATION_POINTS",LIMPT_OF_CONDENSATION_POINTS;
+"LIMPT_OF_CONVEX",LIMPT_OF_CONVEX;
+"LIMPT_OF_LIMPTS",LIMPT_OF_LIMPTS;
+"LIMPT_OF_OPEN",LIMPT_OF_OPEN;
+"LIMPT_OF_OPEN_IN",LIMPT_OF_OPEN_IN;
+"LIMPT_OF_SEQUENCE_SUBSEQUENCE",LIMPT_OF_SEQUENCE_SUBSEQUENCE;
+"LIMPT_OF_UNIV",LIMPT_OF_UNIV;
+"LIMPT_PCROSS",LIMPT_PCROSS;
+"LIMPT_SEQUENTIAL",LIMPT_SEQUENTIAL;
+"LIMPT_SEQUENTIAL_INJ",LIMPT_SEQUENTIAL_INJ;
+"LIMPT_SING",LIMPT_SING;
+"LIMPT_SUBSET",LIMPT_SUBSET;
+"LIMPT_TRANSLATION_EQ",LIMPT_TRANSLATION_EQ;
+"LIMPT_UNIV",LIMPT_UNIV;
+"LIM_ABS",LIM_ABS;
+"LIM_ADD",LIM_ADD;
+"LIM_AT",LIM_AT;
+"LIM_AT_ID",LIM_AT_ID;
+"LIM_AT_INFINITY",LIM_AT_INFINITY;
+"LIM_AT_WITHIN",LIM_AT_WITHIN;
+"LIM_AT_ZERO",LIM_AT_ZERO;
+"LIM_BILINEAR",LIM_BILINEAR;
+"LIM_CASES_COFINITE_SEQUENTIALLY",LIM_CASES_COFINITE_SEQUENTIALLY;
+"LIM_CASES_FINITE_SEQUENTIALLY",LIM_CASES_FINITE_SEQUENTIALLY;
+"LIM_CASES_SEQUENTIALLY",LIM_CASES_SEQUENTIALLY;
+"LIM_CMUL",LIM_CMUL;
+"LIM_CMUL_EQ",LIM_CMUL_EQ;
+"LIM_COMPONENT",LIM_COMPONENT;
+"LIM_COMPONENTWISE_LIFT",LIM_COMPONENTWISE_LIFT;
+"LIM_COMPONENT_EQ",LIM_COMPONENT_EQ;
+"LIM_COMPONENT_LBOUND",LIM_COMPONENT_LBOUND;
+"LIM_COMPONENT_LE",LIM_COMPONENT_LE;
+"LIM_COMPONENT_UBOUND",LIM_COMPONENT_UBOUND;
+"LIM_COMPOSE_AT",LIM_COMPOSE_AT;
+"LIM_COMPOSE_WITHIN",LIM_COMPOSE_WITHIN;
+"LIM_CONG_AT",LIM_CONG_AT;
+"LIM_CONG_WITHIN",LIM_CONG_WITHIN;
+"LIM_CONST",LIM_CONST;
+"LIM_CONST_EQ",LIM_CONST_EQ;
+"LIM_CONTINUOUS_FUNCTION",LIM_CONTINUOUS_FUNCTION;
+"LIM_DROP_LBOUND",LIM_DROP_LBOUND;
+"LIM_DROP_LE",LIM_DROP_LE;
+"LIM_DROP_UBOUND",LIM_DROP_UBOUND;
+"LIM_EVENTUALLY",LIM_EVENTUALLY;
+"LIM_INV",LIM_INV;
+"LIM_IN_CLOSED_SET",LIM_IN_CLOSED_SET;
+"LIM_LIFT_DOT",LIM_LIFT_DOT;
+"LIM_LINEAR",LIM_LINEAR;
+"LIM_MAX",LIM_MAX;
+"LIM_MIN",LIM_MIN;
+"LIM_MUL",LIM_MUL;
+"LIM_MUL_NORM_WITHIN",LIM_MUL_NORM_WITHIN;
+"LIM_NEG",LIM_NEG;
+"LIM_NEG_EQ",LIM_NEG_EQ;
+"LIM_NORM",LIM_NORM;
+"LIM_NORM_LBOUND",LIM_NORM_LBOUND;
+"LIM_NORM_UBOUND",LIM_NORM_UBOUND;
+"LIM_NULL",LIM_NULL;
+"LIM_NULL_CMUL_BOUNDED",LIM_NULL_CMUL_BOUNDED;
+"LIM_NULL_CMUL_EQ",LIM_NULL_CMUL_EQ;
+"LIM_NULL_COMPARISON",LIM_NULL_COMPARISON;
+"LIM_NULL_NORM",LIM_NULL_NORM;
+"LIM_NULL_VMUL_BOUNDED",LIM_NULL_VMUL_BOUNDED;
+"LIM_PASTECART",LIM_PASTECART;
+"LIM_PASTECART_EQ",LIM_PASTECART_EQ;
+"LIM_SEQUENTIALLY",LIM_SEQUENTIALLY;
+"LIM_SUB",LIM_SUB;
+"LIM_SUBSEQUENCE",LIM_SUBSEQUENCE;
+"LIM_TRANSFORM",LIM_TRANSFORM;
+"LIM_TRANSFORM_AT",LIM_TRANSFORM_AT;
+"LIM_TRANSFORM_AWAY_AT",LIM_TRANSFORM_AWAY_AT;
+"LIM_TRANSFORM_AWAY_WITHIN",LIM_TRANSFORM_AWAY_WITHIN;
+"LIM_TRANSFORM_BOUND",LIM_TRANSFORM_BOUND;
+"LIM_TRANSFORM_EQ",LIM_TRANSFORM_EQ;
+"LIM_TRANSFORM_EVENTUALLY",LIM_TRANSFORM_EVENTUALLY;
+"LIM_TRANSFORM_WITHIN",LIM_TRANSFORM_WITHIN;
+"LIM_TRANSFORM_WITHIN_OPEN",LIM_TRANSFORM_WITHIN_OPEN;
+"LIM_TRANSFORM_WITHIN_SET",LIM_TRANSFORM_WITHIN_SET;
+"LIM_UNION",LIM_UNION;
+"LIM_UNION_UNIV",LIM_UNION_UNIV;
+"LIM_UNIQUE",LIM_UNIQUE;
+"LIM_VMUL",LIM_VMUL;
+"LIM_VSUM",LIM_VSUM;
+"LIM_WITHIN",LIM_WITHIN;
+"LIM_WITHIN_CLOSED_TRIVIAL",LIM_WITHIN_CLOSED_TRIVIAL;
+"LIM_WITHIN_EMPTY",LIM_WITHIN_EMPTY;
+"LIM_WITHIN_ID",LIM_WITHIN_ID;
+"LIM_WITHIN_INTERIOR",LIM_WITHIN_INTERIOR;
+"LIM_WITHIN_LE",LIM_WITHIN_LE;
+"LIM_WITHIN_OPEN",LIM_WITHIN_OPEN;
+"LIM_WITHIN_SUBSET",LIM_WITHIN_SUBSET;
+"LIM_WITHIN_UNION",LIM_WITHIN_UNION;
+"LINDELOF",LINDELOF;
+"LINDELOF_OPEN_IN",LINDELOF_OPEN_IN;
+"LINEAR_0",LINEAR_0;
+"LINEAR_1",LINEAR_1;
+"LINEAR_ADD",LINEAR_ADD;
+"LINEAR_BIJECTIVE_DIMINDEX_EQ",LINEAR_BIJECTIVE_DIMINDEX_EQ;
+"LINEAR_BIJECTIVE_LEFT_RIGHT_INVERSE",LINEAR_BIJECTIVE_LEFT_RIGHT_INVERSE;
+"LINEAR_BOUNDED",LINEAR_BOUNDED;
+"LINEAR_BOUNDED_POS",LINEAR_BOUNDED_POS;
+"LINEAR_CMUL",LINEAR_CMUL;
+"LINEAR_COMPONENTWISE",LINEAR_COMPONENTWISE;
+"LINEAR_COMPONENTWISE_EXPANSION",LINEAR_COMPONENTWISE_EXPANSION;
+"LINEAR_COMPOSE",LINEAR_COMPOSE;
+"LINEAR_COMPOSE_ADD",LINEAR_COMPOSE_ADD;
+"LINEAR_COMPOSE_CMUL",LINEAR_COMPOSE_CMUL;
+"LINEAR_COMPOSE_NEG",LINEAR_COMPOSE_NEG;
+"LINEAR_COMPOSE_SUB",LINEAR_COMPOSE_SUB;
+"LINEAR_COMPOSE_VSUM",LINEAR_COMPOSE_VSUM;
+"LINEAR_CONTINUOUS_AT",LINEAR_CONTINUOUS_AT;
+"LINEAR_CONTINUOUS_COMPOSE",LINEAR_CONTINUOUS_COMPOSE;
+"LINEAR_CONTINUOUS_ON",LINEAR_CONTINUOUS_ON;
+"LINEAR_CONTINUOUS_ON_COMPOSE",LINEAR_CONTINUOUS_ON_COMPOSE;
+"LINEAR_CONTINUOUS_WITHIN",LINEAR_CONTINUOUS_WITHIN;
+"LINEAR_EQ",LINEAR_EQ;
+"LINEAR_EQ_0",LINEAR_EQ_0;
+"LINEAR_EQ_0_SPAN",LINEAR_EQ_0_SPAN;
+"LINEAR_EQ_MATRIX",LINEAR_EQ_MATRIX;
+"LINEAR_EQ_MBASIS",LINEAR_EQ_MBASIS;
+"LINEAR_EQ_STDBASIS",LINEAR_EQ_STDBASIS;
+"LINEAR_FRECHET_DERIVATIVE",LINEAR_FRECHET_DERIVATIVE;
+"LINEAR_FROM_REALS",LINEAR_FROM_REALS;
+"LINEAR_FSTCART",LINEAR_FSTCART;
+"LINEAR_I",LINEAR_I;
+"LINEAR_ID",LINEAR_ID;
+"LINEAR_IMAGE_SUBSET_INTERIOR",LINEAR_IMAGE_SUBSET_INTERIOR;
+"LINEAR_INDEPENDENT_EXTEND",LINEAR_INDEPENDENT_EXTEND;
+"LINEAR_INDEPENDENT_EXTEND_LEMMA",LINEAR_INDEPENDENT_EXTEND_LEMMA;
+"LINEAR_INDEP_IMAGE_LEMMA",LINEAR_INDEP_IMAGE_LEMMA;
+"LINEAR_INJECTIVE_0",LINEAR_INJECTIVE_0;
+"LINEAR_INJECTIVE_0_SUBSPACE",LINEAR_INJECTIVE_0_SUBSPACE;
+"LINEAR_INJECTIVE_BOUNDED_BELOW_POS",LINEAR_INJECTIVE_BOUNDED_BELOW_POS;
+"LINEAR_INJECTIVE_DIMINDEX_LE",LINEAR_INJECTIVE_DIMINDEX_LE;
+"LINEAR_INJECTIVE_IMP_SURJECTIVE",LINEAR_INJECTIVE_IMP_SURJECTIVE;
+"LINEAR_INJECTIVE_ISOMORPHISM",LINEAR_INJECTIVE_ISOMORPHISM;
+"LINEAR_INJECTIVE_LEFT_INVERSE",LINEAR_INJECTIVE_LEFT_INVERSE;
+"LINEAR_INTERIOR_IMAGE_SUBSET",LINEAR_INTERIOR_IMAGE_SUBSET;
+"LINEAR_INVERSE_LEFT",LINEAR_INVERSE_LEFT;
+"LINEAR_INVERTIBLE_BOUNDED_BELOW",LINEAR_INVERTIBLE_BOUNDED_BELOW;
+"LINEAR_INVERTIBLE_BOUNDED_BELOW_POS",LINEAR_INVERTIBLE_BOUNDED_BELOW_POS;
+"LINEAR_LIFT_COMPONENT",LINEAR_LIFT_COMPONENT;
+"LINEAR_LIFT_DOT",LINEAR_LIFT_DOT;
+"LINEAR_LIM_0",LINEAR_LIM_0;
+"LINEAR_MATRIX_EXISTS",LINEAR_MATRIX_EXISTS;
+"LINEAR_NEG",LINEAR_NEG;
+"LINEAR_NEGATION",LINEAR_NEGATION;
+"LINEAR_OPEN_MAPPING",LINEAR_OPEN_MAPPING;
+"LINEAR_PASTECART",LINEAR_PASTECART;
+"LINEAR_PROPERTY",LINEAR_PROPERTY;
+"LINEAR_REFLECT_ALONG",LINEAR_REFLECT_ALONG;
+"LINEAR_SCALING",LINEAR_SCALING;
+"LINEAR_SINGULAR_IMAGE_HYPERPLANE",LINEAR_SINGULAR_IMAGE_HYPERPLANE;
+"LINEAR_SINGULAR_INTO_HYPERPLANE",LINEAR_SINGULAR_INTO_HYPERPLANE;
+"LINEAR_SNDCART",LINEAR_SNDCART;
+"LINEAR_SUB",LINEAR_SUB;
+"LINEAR_SUBSPACE_GRAPH",LINEAR_SUBSPACE_GRAPH;
+"LINEAR_SURJECTIVE_DIMINDEX_LE",LINEAR_SURJECTIVE_DIMINDEX_LE;
+"LINEAR_SURJECTIVE_IFF_INJECTIVE",LINEAR_SURJECTIVE_IFF_INJECTIVE;
+"LINEAR_SURJECTIVE_IMP_INJECTIVE",LINEAR_SURJECTIVE_IMP_INJECTIVE;
+"LINEAR_SURJECTIVE_ISOMORPHISM",LINEAR_SURJECTIVE_ISOMORPHISM;
+"LINEAR_SURJECTIVE_RIGHT_INVERSE",LINEAR_SURJECTIVE_RIGHT_INVERSE;
+"LINEAR_TO_REALS",LINEAR_TO_REALS;
+"LINEAR_UNIFORMLY_CONTINUOUS_ON",LINEAR_UNIFORMLY_CONTINUOUS_ON;
+"LINEAR_VMUL_COMPONENT",LINEAR_VMUL_COMPONENT;
+"LINEAR_VMUL_DROP",LINEAR_VMUL_DROP;
+"LINEAR_VSUM",LINEAR_VSUM;
+"LINEAR_VSUM_MUL",LINEAR_VSUM_MUL;
+"LINEAR_ZERO",LINEAR_ZERO;
+"LINEPATH_LINEAR_IMAGE",LINEPATH_LINEAR_IMAGE;
+"LINEPATH_REFL",LINEPATH_REFL;
+"LINEPATH_TRANSLATION",LINEPATH_TRANSLATION;
+"LINSEG_FL",LINSEG_FL;
+"LINSEG_INSEG",LINSEG_INSEG;
+"LINSEG_WOSET",LINSEG_WOSET;
+"LIST_OF_SET_PROPERTIES",LIST_OF_SET_PROPERTIES;
+"LOCALLY_CLOSED",LOCALLY_CLOSED;
+"LOCALLY_COMPACT",LOCALLY_COMPACT;
+"LOCALLY_COMPACT_CLOSED_IN",LOCALLY_COMPACT_CLOSED_IN;
+"LOCALLY_COMPACT_CLOSED_IN_OPEN",LOCALLY_COMPACT_CLOSED_IN_OPEN;
+"LOCALLY_COMPACT_HOMEOMORPHIC_CLOSED",LOCALLY_COMPACT_HOMEOMORPHIC_CLOSED;
+"LOCALLY_COMPACT_HOMEOMORPHISM_PROJECTION_CLOSED",LOCALLY_COMPACT_HOMEOMORPHISM_PROJECTION_CLOSED;
+"LOCALLY_COMPACT_INTER",LOCALLY_COMPACT_INTER;
+"LOCALLY_COMPACT_LINEAR_IMAGE_EQ",LOCALLY_COMPACT_LINEAR_IMAGE_EQ;
+"LOCALLY_COMPACT_OPEN_IN",LOCALLY_COMPACT_OPEN_IN;
+"LOCALLY_COMPACT_OPEN_INTER_CLOSURE",LOCALLY_COMPACT_OPEN_INTER_CLOSURE;
+"LOCALLY_COMPACT_TRANSLATION_EQ",LOCALLY_COMPACT_TRANSLATION_EQ;
+"LOCALLY_COMPACT_UNIV",LOCALLY_COMPACT_UNIV;
+"LOCALLY_CONNECTED",LOCALLY_CONNECTED;
+"LOCALLY_CONNECTED_COMPONENTS",LOCALLY_CONNECTED_COMPONENTS;
+"LOCALLY_CONNECTED_CONNECTED_COMPONENT",LOCALLY_CONNECTED_CONNECTED_COMPONENT;
+"LOCALLY_CONNECTED_CONTINUOUS_IMAGE_COMPACT",LOCALLY_CONNECTED_CONTINUOUS_IMAGE_COMPACT;
+"LOCALLY_CONNECTED_IM_KLEINEN",LOCALLY_CONNECTED_IM_KLEINEN;
+"LOCALLY_CONNECTED_LEFT_INVERTIBLE_IMAGE",LOCALLY_CONNECTED_LEFT_INVERTIBLE_IMAGE;
+"LOCALLY_CONNECTED_LINEAR_IMAGE_EQ",LOCALLY_CONNECTED_LINEAR_IMAGE_EQ;
+"LOCALLY_CONNECTED_OPEN_COMPONENT",LOCALLY_CONNECTED_OPEN_COMPONENT;
+"LOCALLY_CONNECTED_OPEN_CONNECTED_COMPONENT",LOCALLY_CONNECTED_OPEN_CONNECTED_COMPONENT;
+"LOCALLY_CONNECTED_PATH_IMAGE",LOCALLY_CONNECTED_PATH_IMAGE;
+"LOCALLY_CONNECTED_PCROSS",LOCALLY_CONNECTED_PCROSS;
+"LOCALLY_CONNECTED_PCROSS_EQ",LOCALLY_CONNECTED_PCROSS_EQ;
+"LOCALLY_CONNECTED_QUOTIENT_IMAGE",LOCALLY_CONNECTED_QUOTIENT_IMAGE;
+"LOCALLY_CONNECTED_RIGHT_INVERTIBLE_IMAGE",LOCALLY_CONNECTED_RIGHT_INVERTIBLE_IMAGE;
+"LOCALLY_CONNECTED_SPHERE",LOCALLY_CONNECTED_SPHERE;
+"LOCALLY_CONNECTED_SPHERE_GEN",LOCALLY_CONNECTED_SPHERE_GEN;
+"LOCALLY_CONNECTED_TRANSLATION_EQ",LOCALLY_CONNECTED_TRANSLATION_EQ;
+"LOCALLY_CONNECTED_UNIV",LOCALLY_CONNECTED_UNIV;
+"LOCALLY_DIFF_CLOSED",LOCALLY_DIFF_CLOSED;
+"LOCALLY_EMPTY",LOCALLY_EMPTY;
+"LOCALLY_INJECTIVE_LINEAR_IMAGE",LOCALLY_INJECTIVE_LINEAR_IMAGE;
+"LOCALLY_INTER",LOCALLY_INTER;
+"LOCALLY_MONO",LOCALLY_MONO;
+"LOCALLY_OPEN_MAP_IMAGE",LOCALLY_OPEN_MAP_IMAGE;
+"LOCALLY_OPEN_SUBSET",LOCALLY_OPEN_SUBSET;
+"LOCALLY_PATH_CONNECTED",LOCALLY_PATH_CONNECTED;
+"LOCALLY_PATH_CONNECTED_COMPONENTS",LOCALLY_PATH_CONNECTED_COMPONENTS;
+"LOCALLY_PATH_CONNECTED_CONNECTED_COMPONENT",LOCALLY_PATH_CONNECTED_CONNECTED_COMPONENT;
+"LOCALLY_PATH_CONNECTED_CONTINUOUS_IMAGE_COMPACT",LOCALLY_PATH_CONNECTED_CONTINUOUS_IMAGE_COMPACT;
+"LOCALLY_PATH_CONNECTED_IMP_LOCALLY_CONNECTED",LOCALLY_PATH_CONNECTED_IMP_LOCALLY_CONNECTED;
+"LOCALLY_PATH_CONNECTED_IM_KLEINEN",LOCALLY_PATH_CONNECTED_IM_KLEINEN;
+"LOCALLY_PATH_CONNECTED_LEFT_INVERTIBLE_IMAGE",LOCALLY_PATH_CONNECTED_LEFT_INVERTIBLE_IMAGE;
+"LOCALLY_PATH_CONNECTED_LINEAR_IMAGE_EQ",LOCALLY_PATH_CONNECTED_LINEAR_IMAGE_EQ;
+"LOCALLY_PATH_CONNECTED_OPEN_PATH_COMPONENT",LOCALLY_PATH_CONNECTED_OPEN_PATH_COMPONENT;
+"LOCALLY_PATH_CONNECTED_PATH_COMPONENT",LOCALLY_PATH_CONNECTED_PATH_COMPONENT;
+"LOCALLY_PATH_CONNECTED_PATH_IMAGE",LOCALLY_PATH_CONNECTED_PATH_IMAGE;
+"LOCALLY_PATH_CONNECTED_PCROSS",LOCALLY_PATH_CONNECTED_PCROSS;
+"LOCALLY_PATH_CONNECTED_PCROSS_EQ",LOCALLY_PATH_CONNECTED_PCROSS_EQ;
+"LOCALLY_PATH_CONNECTED_QUOTIENT_IMAGE",LOCALLY_PATH_CONNECTED_QUOTIENT_IMAGE;
+"LOCALLY_PATH_CONNECTED_RIGHT_INVERTIBLE_IMAGE",LOCALLY_PATH_CONNECTED_RIGHT_INVERTIBLE_IMAGE;
+"LOCALLY_PATH_CONNECTED_SPHERE",LOCALLY_PATH_CONNECTED_SPHERE;
+"LOCALLY_PATH_CONNECTED_SPHERE_GEN",LOCALLY_PATH_CONNECTED_SPHERE_GEN;
+"LOCALLY_PATH_CONNECTED_TRANSLATION_EQ",LOCALLY_PATH_CONNECTED_TRANSLATION_EQ;
+"LOCALLY_PATH_CONNECTED_UNIV",LOCALLY_PATH_CONNECTED_UNIV;
+"LOCALLY_PCROSS",LOCALLY_PCROSS;
+"LOCALLY_SING",LOCALLY_SING;
+"LOCALLY_TRANSLATION",LOCALLY_TRANSLATION;
+"LOWDIM_EQ_HYPERPLANE",LOWDIM_EQ_HYPERPLANE;
+"LOWDIM_EXPAND_BASIS",LOWDIM_EXPAND_BASIS;
+"LOWDIM_EXPAND_DIMENSION",LOWDIM_EXPAND_DIMENSION;
+"LOWDIM_SUBSET_HYPERPLANE",LOWDIM_SUBSET_HYPERPLANE;
+"LOWER_BOUND_FINITE_SET",LOWER_BOUND_FINITE_SET;
+"LOWER_BOUND_FINITE_SET_REAL",LOWER_BOUND_FINITE_SET_REAL;
+"LT",LT;
+"LTE_ADD2",LTE_ADD2;
+"LTE_ANTISYM",LTE_ANTISYM;
+"LTE_CASES",LTE_CASES;
+"LTE_TRANS",LTE_TRANS;
+"LT_0",LT_0;
+"LT_ADD",LT_ADD;
+"LT_ADD2",LT_ADD2;
+"LT_ADDR",LT_ADDR;
+"LT_ADD_LCANCEL",LT_ADD_LCANCEL;
+"LT_ADD_RCANCEL",LT_ADD_RCANCEL;
+"LT_ANTISYM",LT_ANTISYM;
+"LT_CASES",LT_CASES;
+"LT_EXISTS",LT_EXISTS;
+"LT_EXP",LT_EXP;
+"LT_IMP_LE",LT_IMP_LE;
+"LT_LE",LT_LE;
+"LT_LMULT",LT_LMULT;
+"LT_MULT",LT_MULT;
+"LT_MULT2",LT_MULT2;
+"LT_MULT_LCANCEL",LT_MULT_LCANCEL;
+"LT_MULT_RCANCEL",LT_MULT_RCANCEL;
+"LT_NZ",LT_NZ;
+"LT_POW2_REFL",LT_POW2_REFL;
+"LT_REFL",LT_REFL;
+"LT_SUC",LT_SUC;
+"LT_SUC_LE",LT_SUC_LE;
+"LT_TRANS",LT_TRANS;
+"LUZIN",LUZIN;
+"LUZIN_EQ",LUZIN_EQ;
+"LUZIN_EQ_ALT",LUZIN_EQ_ALT;
+"MAP",MAP;
+"MAP2",MAP2;
+"MAP2_DEF",MAP2_DEF;
+"MAP_APPEND",MAP_APPEND;
+"MAP_EQ",MAP_EQ;
+"MAP_EQ_ALL2",MAP_EQ_ALL2;
+"MAP_EQ_DEGEN",MAP_EQ_DEGEN;
+"MAP_EQ_NIL",MAP_EQ_NIL;
+"MAP_FST_ZIP",MAP_FST_ZIP;
+"MAP_I",MAP_I;
+"MAP_ID",MAP_ID;
+"MAP_REVERSE",MAP_REVERSE;
+"MAP_SND_ZIP",MAP_SND_ZIP;
+"MAP_o",MAP_o;
+"MATCH_SEQPATTERN",MATCH_SEQPATTERN;
+"MATRIX_ADD_AC",MATRIX_ADD_AC;
+"MATRIX_ADD_ASSOC",MATRIX_ADD_ASSOC;
+"MATRIX_ADD_COMPONENT",MATRIX_ADD_COMPONENT;
+"MATRIX_ADD_LDISTRIB",MATRIX_ADD_LDISTRIB;
+"MATRIX_ADD_LID",MATRIX_ADD_LID;
+"MATRIX_ADD_LNEG",MATRIX_ADD_LNEG;
+"MATRIX_ADD_RDISTRIB",MATRIX_ADD_RDISTRIB;
+"MATRIX_ADD_RID",MATRIX_ADD_RID;
+"MATRIX_ADD_RNEG",MATRIX_ADD_RNEG;
+"MATRIX_ADD_SYM",MATRIX_ADD_SYM;
+"MATRIX_ADJOINT",MATRIX_ADJOINT;
+"MATRIX_CMUL_ADD_LDISTRIB",MATRIX_CMUL_ADD_LDISTRIB;
+"MATRIX_CMUL_ADD_RDISTRIB",MATRIX_CMUL_ADD_RDISTRIB;
+"MATRIX_CMUL_ASSOC",MATRIX_CMUL_ASSOC;
+"MATRIX_CMUL_COMPONENT",MATRIX_CMUL_COMPONENT;
+"MATRIX_CMUL_LID",MATRIX_CMUL_LID;
+"MATRIX_CMUL_LZERO",MATRIX_CMUL_LZERO;
+"MATRIX_CMUL_RZERO",MATRIX_CMUL_RZERO;
+"MATRIX_CMUL_SUB_LDISTRIB",MATRIX_CMUL_SUB_LDISTRIB;
+"MATRIX_CMUL_SUB_RDISTRIB",MATRIX_CMUL_SUB_RDISTRIB;
+"MATRIX_COMPOSE",MATRIX_COMPOSE;
+"MATRIX_EQ",MATRIX_EQ;
+"MATRIX_EQUAL_COLUMNS",MATRIX_EQUAL_COLUMNS;
+"MATRIX_EQUAL_ROWS",MATRIX_EQUAL_ROWS;
+"MATRIX_FULL_LINEAR_EQUATIONS",MATRIX_FULL_LINEAR_EQUATIONS;
+"MATRIX_I",MATRIX_I;
+"MATRIX_ID",MATRIX_ID;
+"MATRIX_INV",MATRIX_INV;
+"MATRIX_INVERTIBLE",MATRIX_INVERTIBLE;
+"MATRIX_INV_COFACTOR",MATRIX_INV_COFACTOR;
+"MATRIX_INV_I",MATRIX_INV_I;
+"MATRIX_INV_MUL",MATRIX_INV_MUL;
+"MATRIX_INV_UNIQUE",MATRIX_INV_UNIQUE;
+"MATRIX_INV_UNIQUE_LEFT",MATRIX_INV_UNIQUE_LEFT;
+"MATRIX_INV_UNIQUE_RIGHT",MATRIX_INV_UNIQUE_RIGHT;
+"MATRIX_LEFT_INVERSE_COFACTOR",MATRIX_LEFT_INVERSE_COFACTOR;
+"MATRIX_LEFT_INVERTIBLE",MATRIX_LEFT_INVERTIBLE;
+"MATRIX_LEFT_INVERTIBLE_INDEPENDENT_COLUMNS",MATRIX_LEFT_INVERTIBLE_INDEPENDENT_COLUMNS;
+"MATRIX_LEFT_INVERTIBLE_INJECTIVE",MATRIX_LEFT_INVERTIBLE_INJECTIVE;
+"MATRIX_LEFT_INVERTIBLE_KER",MATRIX_LEFT_INVERTIBLE_KER;
+"MATRIX_LEFT_INVERTIBLE_SPAN_ROWS",MATRIX_LEFT_INVERTIBLE_SPAN_ROWS;
+"MATRIX_LEFT_RIGHT_INVERSE",MATRIX_LEFT_RIGHT_INVERSE;
+"MATRIX_MUL_ASSOC",MATRIX_MUL_ASSOC;
+"MATRIX_MUL_COMPONENT",MATRIX_MUL_COMPONENT;
+"MATRIX_MUL_DOT",MATRIX_MUL_DOT;
+"MATRIX_MUL_LEFT_COFACTOR",MATRIX_MUL_LEFT_COFACTOR;
+"MATRIX_MUL_LID",MATRIX_MUL_LID;
+"MATRIX_MUL_LINV",MATRIX_MUL_LINV;
+"MATRIX_MUL_LMUL",MATRIX_MUL_LMUL;
+"MATRIX_MUL_LNEG",MATRIX_MUL_LNEG;
+"MATRIX_MUL_LTRANSP_DOT_COLUMN",MATRIX_MUL_LTRANSP_DOT_COLUMN;
+"MATRIX_MUL_LZERO",MATRIX_MUL_LZERO;
+"MATRIX_MUL_RID",MATRIX_MUL_RID;
+"MATRIX_MUL_RIGHT_COFACTOR",MATRIX_MUL_RIGHT_COFACTOR;
+"MATRIX_MUL_RINV",MATRIX_MUL_RINV;
+"MATRIX_MUL_RMUL",MATRIX_MUL_RMUL;
+"MATRIX_MUL_RNEG",MATRIX_MUL_RNEG;
+"MATRIX_MUL_RTRANSP_DOT_ROW",MATRIX_MUL_RTRANSP_DOT_ROW;
+"MATRIX_MUL_RZERO",MATRIX_MUL_RZERO;
+"MATRIX_MUL_VSUM",MATRIX_MUL_VSUM;
+"MATRIX_MUL_VSUM_ALT",MATRIX_MUL_VSUM_ALT;
+"MATRIX_NEG_0",MATRIX_NEG_0;
+"MATRIX_NEG_ADD",MATRIX_NEG_ADD;
+"MATRIX_NEG_COMPONENT",MATRIX_NEG_COMPONENT;
+"MATRIX_NEG_EQ_0",MATRIX_NEG_EQ_0;
+"MATRIX_NEG_MINUS1",MATRIX_NEG_MINUS1;
+"MATRIX_NEG_NEG",MATRIX_NEG_NEG;
+"MATRIX_NEG_SUB",MATRIX_NEG_SUB;
+"MATRIX_NONFULL_LINEAR_EQUATIONS",MATRIX_NONFULL_LINEAR_EQUATIONS;
+"MATRIX_NONFULL_LINEAR_EQUATIONS_EQ",MATRIX_NONFULL_LINEAR_EQUATIONS_EQ;
+"MATRIX_OF_MATRIX_VECTOR_MUL",MATRIX_OF_MATRIX_VECTOR_MUL;
+"MATRIX_REFLECT_ALONG_BASIS",MATRIX_REFLECT_ALONG_BASIS;
+"MATRIX_RIGHT_INVERSE_COFACTOR",MATRIX_RIGHT_INVERSE_COFACTOR;
+"MATRIX_RIGHT_INVERTIBLE",MATRIX_RIGHT_INVERTIBLE;
+"MATRIX_RIGHT_INVERTIBLE_INDEPENDENT_ROWS",MATRIX_RIGHT_INVERTIBLE_INDEPENDENT_ROWS;
+"MATRIX_RIGHT_INVERTIBLE_SPAN_COLUMNS",MATRIX_RIGHT_INVERTIBLE_SPAN_COLUMNS;
+"MATRIX_RIGHT_INVERTIBLE_SURJECTIVE",MATRIX_RIGHT_INVERTIBLE_SURJECTIVE;
+"MATRIX_SELF_ADJOINT",MATRIX_SELF_ADJOINT;
+"MATRIX_SUB",MATRIX_SUB;
+"MATRIX_SUB_COMPONENT",MATRIX_SUB_COMPONENT;
+"MATRIX_SUB_LDISTRIB",MATRIX_SUB_LDISTRIB;
+"MATRIX_SUB_LZERO",MATRIX_SUB_LZERO;
+"MATRIX_SUB_RDISTRIB",MATRIX_SUB_RDISTRIB;
+"MATRIX_SUB_REFL",MATRIX_SUB_REFL;
+"MATRIX_SUB_RZERO",MATRIX_SUB_RZERO;
+"MATRIX_TRANSP_MUL",MATRIX_TRANSP_MUL;
+"MATRIX_TRIVIAL_LINEAR_EQUATIONS",MATRIX_TRIVIAL_LINEAR_EQUATIONS;
+"MATRIX_VECTOR_COLUMN",MATRIX_VECTOR_COLUMN;
+"MATRIX_VECTOR_MUL",MATRIX_VECTOR_MUL;
+"MATRIX_VECTOR_MUL_ADD_LDISTRIB",MATRIX_VECTOR_MUL_ADD_LDISTRIB;
+"MATRIX_VECTOR_MUL_ADD_RDISTRIB",MATRIX_VECTOR_MUL_ADD_RDISTRIB;
+"MATRIX_VECTOR_MUL_ASSOC",MATRIX_VECTOR_MUL_ASSOC;
+"MATRIX_VECTOR_MUL_BASIS",MATRIX_VECTOR_MUL_BASIS;
+"MATRIX_VECTOR_MUL_COMPONENT",MATRIX_VECTOR_MUL_COMPONENT;
+"MATRIX_VECTOR_MUL_INJECTIVE_ON_ROWSPACE",MATRIX_VECTOR_MUL_INJECTIVE_ON_ROWSPACE;
+"MATRIX_VECTOR_MUL_IN_COLUMNSPACE",MATRIX_VECTOR_MUL_IN_COLUMNSPACE;
+"MATRIX_VECTOR_MUL_LID",MATRIX_VECTOR_MUL_LID;
+"MATRIX_VECTOR_MUL_LINEAR",MATRIX_VECTOR_MUL_LINEAR;
+"MATRIX_VECTOR_MUL_LZERO",MATRIX_VECTOR_MUL_LZERO;
+"MATRIX_VECTOR_MUL_RMUL",MATRIX_VECTOR_MUL_RMUL;
+"MATRIX_VECTOR_MUL_RZERO",MATRIX_VECTOR_MUL_RZERO;
+"MATRIX_VECTOR_MUL_SUB_LDISTRIB",MATRIX_VECTOR_MUL_SUB_LDISTRIB;
+"MATRIX_VECTOR_MUL_SUB_RDISTRIB",MATRIX_VECTOR_MUL_SUB_RDISTRIB;
+"MATRIX_VECTOR_MUL_TRANSP",MATRIX_VECTOR_MUL_TRANSP;
+"MATRIX_WLOG_INVERTIBLE",MATRIX_WLOG_INVERTIBLE;
+"MATRIX_WORKS",MATRIX_WORKS;
+"MAT_0_COMPONENT",MAT_0_COMPONENT;
+"MAT_COMPONENT",MAT_COMPONENT;
+"MAX",MAX;
+"MAXIMAL_AFFINE_INDEPENDENT_SUBSET",MAXIMAL_AFFINE_INDEPENDENT_SUBSET;
+"MAXIMAL_AFFINE_INDEPENDENT_SUBSET_AFFINE",MAXIMAL_AFFINE_INDEPENDENT_SUBSET_AFFINE;
+"MAXIMAL_INDEPENDENT_SUBSET",MAXIMAL_INDEPENDENT_SUBSET;
+"MAXIMAL_INDEPENDENT_SUBSET_EXTEND",MAXIMAL_INDEPENDENT_SUBSET_EXTEND;
+"MBASIS_COMPONENT",MBASIS_COMPONENT;
+"MBASIS_EQ_0",MBASIS_EQ_0;
+"MBASIS_EXPANSION",MBASIS_EXPANSION;
+"MBASIS_EXTENSION",MBASIS_EXTENSION;
+"MBASIS_NONZERO",MBASIS_NONZERO;
+"MBASIS_SPLIT",MBASIS_SPLIT;
+"MEASURABLE",MEASURABLE;
+"MEASURABLE_ALMOST",MEASURABLE_ALMOST;
+"MEASURABLE_BALL",MEASURABLE_BALL;
+"MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_ABSOLUTELY_INTEGRABLE",MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_ABSOLUTELY_INTEGRABLE;
+"MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE",MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE;
+"MEASURABLE_CBALL",MEASURABLE_CBALL;
+"MEASURABLE_CLOSURE",MEASURABLE_CLOSURE;
+"MEASURABLE_COMPACT",MEASURABLE_COMPACT;
+"MEASURABLE_CONVEX",MEASURABLE_CONVEX;
+"MEASURABLE_CONVEX_HULL",MEASURABLE_CONVEX_HULL;
+"MEASURABLE_COUNTABLE_INTERS",MEASURABLE_COUNTABLE_INTERS;
+"MEASURABLE_COUNTABLE_INTERS_GEN",MEASURABLE_COUNTABLE_INTERS_GEN;
+"MEASURABLE_COUNTABLE_UNIONS",MEASURABLE_COUNTABLE_UNIONS;
+"MEASURABLE_COUNTABLE_UNIONS_BOUNDED",MEASURABLE_COUNTABLE_UNIONS_BOUNDED;
+"MEASURABLE_COUNTABLE_UNIONS_STRONG",MEASURABLE_COUNTABLE_UNIONS_STRONG;
+"MEASURABLE_DIFF",MEASURABLE_DIFF;
+"MEASURABLE_ELEMENTARY",MEASURABLE_ELEMENTARY;
+"MEASURABLE_EMPTY",MEASURABLE_EMPTY;
+"MEASURABLE_FRONTIER",MEASURABLE_FRONTIER;
+"MEASURABLE_IMP_LEBESGUE_MEASURABLE",MEASURABLE_IMP_LEBESGUE_MEASURABLE;
+"MEASURABLE_INNER_COMPACT",MEASURABLE_INNER_COMPACT;
+"MEASURABLE_INNER_OUTER",MEASURABLE_INNER_OUTER;
+"MEASURABLE_INSERT",MEASURABLE_INSERT;
+"MEASURABLE_INSIDE",MEASURABLE_INSIDE;
+"MEASURABLE_INTEGRABLE",MEASURABLE_INTEGRABLE;
+"MEASURABLE_INTER",MEASURABLE_INTER;
+"MEASURABLE_INTERIOR",MEASURABLE_INTERIOR;
+"MEASURABLE_INTERVAL",MEASURABLE_INTERVAL;
+"MEASURABLE_INTER_HALFSPACE_GE",MEASURABLE_INTER_HALFSPACE_GE;
+"MEASURABLE_INTER_HALFSPACE_LE",MEASURABLE_INTER_HALFSPACE_LE;
+"MEASURABLE_INTER_INTERVAL",MEASURABLE_INTER_INTERVAL;
+"MEASURABLE_JORDAN",MEASURABLE_JORDAN;
+"MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE",MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE;
+"MEASURABLE_LEGESGUE_MEASURABLE_SUBSET",MEASURABLE_LEGESGUE_MEASURABLE_SUBSET;
+"MEASURABLE_LINEAR_IMAGE",MEASURABLE_LINEAR_IMAGE;
+"MEASURABLE_LINEAR_IMAGE_EQ",MEASURABLE_LINEAR_IMAGE_EQ;
+"MEASURABLE_LINEAR_IMAGE_INTERVAL",MEASURABLE_LINEAR_IMAGE_INTERVAL;
+"MEASURABLE_MEASURABLE_DIFF_LEGESGUE_MEASURABLE",MEASURABLE_MEASURABLE_DIFF_LEGESGUE_MEASURABLE;
+"MEASURABLE_MEASURABLE_INTER_LEGESGUE_MEASURABLE",MEASURABLE_MEASURABLE_INTER_LEGESGUE_MEASURABLE;
+"MEASURABLE_MEASURABLE_PREIMAGE_CLOSED",MEASURABLE_MEASURABLE_PREIMAGE_CLOSED;
+"MEASURABLE_MEASURABLE_PREIMAGE_OPEN",MEASURABLE_MEASURABLE_PREIMAGE_OPEN;
+"MEASURABLE_MEASURE_EQ_0",MEASURABLE_MEASURE_EQ_0;
+"MEASURABLE_MEASURE_POS_LT",MEASURABLE_MEASURE_POS_LT;
+"MEASURABLE_NEGLIGIBLE_SYMDIFF",MEASURABLE_NEGLIGIBLE_SYMDIFF;
+"MEASURABLE_NEGLIGIBLE_SYMDIFF_EQ",MEASURABLE_NEGLIGIBLE_SYMDIFF_EQ;
+"MEASURABLE_NESTED_UNIONS",MEASURABLE_NESTED_UNIONS;
+"MEASURABLE_NONNEGLIGIBLE_IMP_LARGE",MEASURABLE_NONNEGLIGIBLE_IMP_LARGE;
+"MEASURABLE_ON_0",MEASURABLE_ON_0;
+"MEASURABLE_ON_ADD",MEASURABLE_ON_ADD;
+"MEASURABLE_ON_CASES",MEASURABLE_ON_CASES;
+"MEASURABLE_ON_CMUL",MEASURABLE_ON_CMUL;
+"MEASURABLE_ON_COMBINE",MEASURABLE_ON_COMBINE;
+"MEASURABLE_ON_COMPONENTWISE",MEASURABLE_ON_COMPONENTWISE;
+"MEASURABLE_ON_COMPOSE_CONTINUOUS",MEASURABLE_ON_COMPOSE_CONTINUOUS;
+"MEASURABLE_ON_COMPOSE_CONTINUOUS_0",MEASURABLE_ON_COMPOSE_CONTINUOUS_0;
+"MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET",MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET;
+"MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET_0",MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET_0;
+"MEASURABLE_ON_COMPOSE_CONTINUOUS_OPEN_INTERVAL",MEASURABLE_ON_COMPOSE_CONTINUOUS_OPEN_INTERVAL;
+"MEASURABLE_ON_CONST",MEASURABLE_ON_CONST;
+"MEASURABLE_ON_COUNTABLE_UNIONS",MEASURABLE_ON_COUNTABLE_UNIONS;
+"MEASURABLE_ON_DIFF",MEASURABLE_ON_DIFF;
+"MEASURABLE_ON_DROP_MUL",MEASURABLE_ON_DROP_MUL;
+"MEASURABLE_ON_EMPTY",MEASURABLE_ON_EMPTY;
+"MEASURABLE_ON_INTER",MEASURABLE_ON_INTER;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED_EQ",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED_EQ;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED_INTERVAL",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED_INTERVAL;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_EQ",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_EQ;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_INTERVAL",MEASURABLE_ON_LEBESGUE_MEASURABLE_PREIMAGE_OPEN_INTERVAL;
+"MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET",MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET;
+"MEASURABLE_ON_LIFT_MUL",MEASURABLE_ON_LIFT_MUL;
+"MEASURABLE_ON_LIMIT",MEASURABLE_ON_LIMIT;
+"MEASURABLE_ON_LINEAR_IMAGE_EQ",MEASURABLE_ON_LINEAR_IMAGE_EQ;
+"MEASURABLE_ON_MAX",MEASURABLE_ON_MAX;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED",MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED_EQ",MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED_EQ;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED_INTERVAL",MEASURABLE_ON_MEASURABLE_PREIMAGE_CLOSED_INTERVAL;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_EQ",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_EQ;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT;
+"MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_INTERVAL",MEASURABLE_ON_MEASURABLE_PREIMAGE_OPEN_INTERVAL;
+"MEASURABLE_ON_MEASURABLE_SUBSET",MEASURABLE_ON_MEASURABLE_SUBSET;
+"MEASURABLE_ON_MIN",MEASURABLE_ON_MIN;
+"MEASURABLE_ON_NEG",MEASURABLE_ON_NEG;
+"MEASURABLE_ON_NEG_EQ",MEASURABLE_ON_NEG_EQ;
+"MEASURABLE_ON_NORM",MEASURABLE_ON_NORM;
+"MEASURABLE_ON_PASTECART",MEASURABLE_ON_PASTECART;
+"MEASURABLE_ON_PREIMAGE_CLOSED",MEASURABLE_ON_PREIMAGE_CLOSED;
+"MEASURABLE_ON_PREIMAGE_CLOSED_INTERVAL",MEASURABLE_ON_PREIMAGE_CLOSED_INTERVAL;
+"MEASURABLE_ON_PREIMAGE_OPEN",MEASURABLE_ON_PREIMAGE_OPEN;
+"MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE",MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE;
+"MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT",MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT;
+"MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE",MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE;
+"MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT",MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT;
+"MEASURABLE_ON_PREIMAGE_OPEN_INTERVAL",MEASURABLE_ON_PREIMAGE_OPEN_INTERVAL;
+"MEASURABLE_ON_RESTRICT",MEASURABLE_ON_RESTRICT;
+"MEASURABLE_ON_SIMPLE_FUNCTION_LIMIT",MEASURABLE_ON_SIMPLE_FUNCTION_LIMIT;
+"MEASURABLE_ON_SPIKE",MEASURABLE_ON_SPIKE;
+"MEASURABLE_ON_SPIKE_SET",MEASURABLE_ON_SPIKE_SET;
+"MEASURABLE_ON_SUB",MEASURABLE_ON_SUB;
+"MEASURABLE_ON_TRANSLATION",MEASURABLE_ON_TRANSLATION;
+"MEASURABLE_ON_TRANSLATION_EQ",MEASURABLE_ON_TRANSLATION_EQ;
+"MEASURABLE_ON_UNION",MEASURABLE_ON_UNION;
+"MEASURABLE_ON_UNIONS",MEASURABLE_ON_UNIONS;
+"MEASURABLE_ON_UNIV",MEASURABLE_ON_UNIV;
+"MEASURABLE_ON_VECTOR_DERIVATIVE",MEASURABLE_ON_VECTOR_DERIVATIVE;
+"MEASURABLE_ON_VSUM",MEASURABLE_ON_VSUM;
+"MEASURABLE_OPEN",MEASURABLE_OPEN;
+"MEASURABLE_OUTER_CLOSED_INTERVALS",MEASURABLE_OUTER_CLOSED_INTERVALS;
+"MEASURABLE_OUTER_INTERVALS_BOUNDED",MEASURABLE_OUTER_INTERVALS_BOUNDED;
+"MEASURABLE_OUTER_OPEN",MEASURABLE_OUTER_OPEN;
+"MEASURABLE_OUTER_OPEN_INTERVALS",MEASURABLE_OUTER_OPEN_INTERVALS;
+"MEASURABLE_SCALING",MEASURABLE_SCALING;
+"MEASURABLE_SCALING_EQ",MEASURABLE_SCALING_EQ;
+"MEASURABLE_SIMPLEX",MEASURABLE_SIMPLEX;
+"MEASURABLE_SMALL_IMP_NEGLIGIBLE",MEASURABLE_SMALL_IMP_NEGLIGIBLE;
+"MEASURABLE_TETRAHEDRON",MEASURABLE_TETRAHEDRON;
+"MEASURABLE_TRANSLATION",MEASURABLE_TRANSLATION;
+"MEASURABLE_TRANSLATION_EQ",MEASURABLE_TRANSLATION_EQ;
+"MEASURABLE_TRIANGLE",MEASURABLE_TRIANGLE;
+"MEASURABLE_UNION",MEASURABLE_UNION;
+"MEASURABLE_UNIONS",MEASURABLE_UNIONS;
+"MEASURE",MEASURE;
+"MEASURE_BALL_BOUND",MEASURE_BALL_BOUND;
+"MEASURE_BALL_POS",MEASURE_BALL_POS;
+"MEASURE_CBALL_BOUND",MEASURE_CBALL_BOUND;
+"MEASURE_CBALL_POS",MEASURE_CBALL_POS;
+"MEASURE_CLOSURE",MEASURE_CLOSURE;
+"MEASURE_COUNTABLE_UNIONS_APPROACHABLE",MEASURE_COUNTABLE_UNIONS_APPROACHABLE;
+"MEASURE_COUNTABLE_UNIONS_LE",MEASURE_COUNTABLE_UNIONS_LE;
+"MEASURE_COUNTABLE_UNIONS_LE_GEN",MEASURE_COUNTABLE_UNIONS_LE_GEN;
+"MEASURE_COUNTABLE_UNIONS_LE_STRONG",MEASURE_COUNTABLE_UNIONS_LE_STRONG;
+"MEASURE_COUNTABLE_UNIONS_LE_STRONG_GEN",MEASURE_COUNTABLE_UNIONS_LE_STRONG_GEN;
+"MEASURE_DIFF_SUBSET",MEASURE_DIFF_SUBSET;
+"MEASURE_DISJOINT_UNION",MEASURE_DISJOINT_UNION;
+"MEASURE_DISJOINT_UNIONS",MEASURE_DISJOINT_UNIONS;
+"MEASURE_DISJOINT_UNIONS_IMAGE",MEASURE_DISJOINT_UNIONS_IMAGE;
+"MEASURE_DISJOINT_UNIONS_IMAGE_STRONG",MEASURE_DISJOINT_UNIONS_IMAGE_STRONG;
+"MEASURE_DISJOINT_UNION_EQ",MEASURE_DISJOINT_UNION_EQ;
+"MEASURE_ELEMENTARY",MEASURE_ELEMENTARY;
+"MEASURE_EMPTY",MEASURE_EMPTY;
+"MEASURE_EQ_0",MEASURE_EQ_0;
+"MEASURE_FRONTIER",MEASURE_FRONTIER;
+"MEASURE_INSERT",MEASURE_INSERT;
+"MEASURE_INTEGRAL",MEASURE_INTEGRAL;
+"MEASURE_INTEGRAL_UNIV",MEASURE_INTEGRAL_UNIV;
+"MEASURE_INTERIOR",MEASURE_INTERIOR;
+"MEASURE_INTERVAL",MEASURE_INTERVAL;
+"MEASURE_INTERVAL_1",MEASURE_INTERVAL_1;
+"MEASURE_INTERVAL_1_ALT",MEASURE_INTERVAL_1_ALT;
+"MEASURE_INTERVAL_2",MEASURE_INTERVAL_2;
+"MEASURE_INTERVAL_2_ALT",MEASURE_INTERVAL_2_ALT;
+"MEASURE_INTERVAL_3",MEASURE_INTERVAL_3;
+"MEASURE_INTERVAL_3_ALT",MEASURE_INTERVAL_3_ALT;
+"MEASURE_INTERVAL_4",MEASURE_INTERVAL_4;
+"MEASURE_INTERVAL_4_ALT",MEASURE_INTERVAL_4_ALT;
+"MEASURE_LE",MEASURE_LE;
+"MEASURE_LIMIT",MEASURE_LIMIT;
+"MEASURE_LINEAR_IMAGE",MEASURE_LINEAR_IMAGE;
+"MEASURE_LINEAR_IMAGE_SAME",MEASURE_LINEAR_IMAGE_SAME;
+"MEASURE_NEGLIGIBLE_SYMDIFF",MEASURE_NEGLIGIBLE_SYMDIFF;
+"MEASURE_NEGLIGIBLE_UNION",MEASURE_NEGLIGIBLE_UNION;
+"MEASURE_NEGLIGIBLE_UNIONS",MEASURE_NEGLIGIBLE_UNIONS;
+"MEASURE_NEGLIGIBLE_UNIONS_IMAGE",MEASURE_NEGLIGIBLE_UNIONS_IMAGE;
+"MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG",MEASURE_NEGLIGIBLE_UNIONS_IMAGE_STRONG;
+"MEASURE_NEGLIGIBLE_UNION_EQ",MEASURE_NEGLIGIBLE_UNION_EQ;
+"MEASURE_OPEN_POS_LT",MEASURE_OPEN_POS_LT;
+"MEASURE_ORTHOGONAL_IMAGE_EQ",MEASURE_ORTHOGONAL_IMAGE_EQ;
+"MEASURE_POS_LE",MEASURE_POS_LE;
+"MEASURE_SCALING",MEASURE_SCALING;
+"MEASURE_SIMPLEX",MEASURE_SIMPLEX;
+"MEASURE_SUBSET",MEASURE_SUBSET;
+"MEASURE_TETRAHEDRON",MEASURE_TETRAHEDRON;
+"MEASURE_TRANSLATION",MEASURE_TRANSLATION;
+"MEASURE_TRIANGLE",MEASURE_TRIANGLE;
+"MEASURE_UNION",MEASURE_UNION;
+"MEASURE_UNIONS_LE",MEASURE_UNIONS_LE;
+"MEASURE_UNIONS_LE_IMAGE",MEASURE_UNIONS_LE_IMAGE;
+"MEASURE_UNION_LE",MEASURE_UNION_LE;
+"MEASURE_UNIQUE",MEASURE_UNIQUE;
+"MEM",MEM;
+"MEMBER_NOT_EMPTY",MEMBER_NOT_EMPTY;
+"MEM_APPEND",MEM_APPEND;
+"MEM_APPEND_DECOMPOSE",MEM_APPEND_DECOMPOSE;
+"MEM_APPEND_DECOMPOSE_LEFT",MEM_APPEND_DECOMPOSE_LEFT;
+"MEM_ASSOC",MEM_ASSOC;
+"MEM_EL",MEM_EL;
+"MEM_EXISTS_EL",MEM_EXISTS_EL;
+"MEM_FILTER",MEM_FILTER;
+"MEM_LINEAR_IMAGE",MEM_LINEAR_IMAGE;
+"MEM_LIST_OF_SET",MEM_LIST_OF_SET;
+"MEM_MAP",MEM_MAP;
+"MEM_TRANSLATION",MEM_TRANSLATION;
+"MIDPOINT_BETWEEN",MIDPOINT_BETWEEN;
+"MIDPOINT_COLLINEAR",MIDPOINT_COLLINEAR;
+"MIDPOINT_CONVEX_DYADIC_RATIONALS",MIDPOINT_CONVEX_DYADIC_RATIONALS;
+"MIDPOINT_EQ_ENDPOINT",MIDPOINT_EQ_ENDPOINT;
+"MIDPOINT_IN_SEGMENT",MIDPOINT_IN_SEGMENT;
+"MIDPOINT_LINEAR_IMAGE",MIDPOINT_LINEAR_IMAGE;
+"MIDPOINT_REFL",MIDPOINT_REFL;
+"MIDPOINT_SYM",MIDPOINT_SYM;
+"MIN",MIN;
+"MINIMAL",MINIMAL;
+"MINIMAL_IN_INSERT",MINIMAL_IN_INSERT;
+"MK_REC_INJ",MK_REC_INJ;
+"MOD_0",MOD_0;
+"MOD_1",MOD_1;
+"MOD_ADD_MOD",MOD_ADD_MOD;
+"MOD_EQ",MOD_EQ;
+"MOD_EQ_0",MOD_EQ_0;
+"MOD_EXISTS",MOD_EXISTS;
+"MOD_EXP_MOD",MOD_EXP_MOD;
+"MOD_LE",MOD_LE;
+"MOD_LT",MOD_LT;
+"MOD_MOD",MOD_MOD;
+"MOD_MOD_EXP_MIN",MOD_MOD_EXP_MIN;
+"MOD_MOD_REFL",MOD_MOD_REFL;
+"MOD_MULT",MOD_MULT;
+"MOD_MULT2",MOD_MULT2;
+"MOD_MULT_ADD",MOD_MULT_ADD;
+"MOD_MULT_LMOD",MOD_MULT_LMOD;
+"MOD_MULT_MOD2",MOD_MULT_MOD2;
+"MOD_MULT_RMOD",MOD_MULT_RMOD;
+"MOD_NSUM_MOD",MOD_NSUM_MOD;
+"MOD_NSUM_MOD_NUMSEG",MOD_NSUM_MOD_NUMSEG;
+"MOD_UNIQ",MOD_UNIQ;
+"MONOIDAL_AC",MONOIDAL_AC;
+"MONOIDAL_ADD",MONOIDAL_ADD;
+"MONOIDAL_AND",MONOIDAL_AND;
+"MONOIDAL_LIFTED",MONOIDAL_LIFTED;
+"MONOIDAL_MUL",MONOIDAL_MUL;
+"MONOIDAL_REAL_ADD",MONOIDAL_REAL_ADD;
+"MONOIDAL_REAL_MUL",MONOIDAL_REAL_MUL;
+"MONOIDAL_VECTOR_ADD",MONOIDAL_VECTOR_ADD;
+"MONOTONE_BIGGER",MONOTONE_BIGGER;
+"MONOTONE_CONVERGENCE_DECREASING",MONOTONE_CONVERGENCE_DECREASING;
+"MONOTONE_CONVERGENCE_INCREASING",MONOTONE_CONVERGENCE_INCREASING;
+"MONOTONE_CONVERGENCE_INTERVAL",MONOTONE_CONVERGENCE_INTERVAL;
+"MONOTONE_SUBSEQUENCE",MONOTONE_SUBSEQUENCE;
+"MONO_ALL",MONO_ALL;
+"MONO_ALL2",MONO_ALL2;
+"MONO_AND",MONO_AND;
+"MONO_COND",MONO_COND;
+"MONO_EXISTS",MONO_EXISTS;
+"MONO_FORALL",MONO_FORALL;
+"MONO_IMP",MONO_IMP;
+"MONO_NOT",MONO_NOT;
+"MONO_OR",MONO_OR;
+"MULT",MULT;
+"MULTIVECTOR_ADD_COMPONENT",MULTIVECTOR_ADD_COMPONENT;
+"MULTIVECTOR_BETA",MULTIVECTOR_BETA;
+"MULTIVECTOR_EQ",MULTIVECTOR_EQ;
+"MULTIVECTOR_ETA",MULTIVECTOR_ETA;
+"MULTIVECTOR_GRADE",MULTIVECTOR_GRADE;
+"MULTIVECTOR_IMAGE",MULTIVECTOR_IMAGE;
+"MULTIVECTOR_MUL_COMPONENT",MULTIVECTOR_MUL_COMPONENT;
+"MULTIVECTOR_UNIQUE",MULTIVECTOR_UNIQUE;
+"MULTIVECTOR_VEC_COMPONENT",MULTIVECTOR_VEC_COMPONENT;
+"MULTIVECTOR_VSUM",MULTIVECTOR_VSUM;
+"MULTIVECTOR_VSUM_COMPONENT",MULTIVECTOR_VSUM_COMPONENT;
+"MULT_0",MULT_0;
+"MULT_2",MULT_2;
+"MULT_AC",MULT_AC;
+"MULT_ASSOC",MULT_ASSOC;
+"MULT_CLAUSES",MULT_CLAUSES;
+"MULT_DIV_LE",MULT_DIV_LE;
+"MULT_EQ_0",MULT_EQ_0;
+"MULT_EQ_1",MULT_EQ_1;
+"MULT_EXP",MULT_EXP;
+"MULT_SUC",MULT_SUC;
+"MULT_SYM",MULT_SYM;
+"MUL_C_UNIV",MUL_C_UNIV;
+"MVT",MVT;
+"MVT_GENERAL",MVT_GENERAL;
+"MVT_SIMPLE",MVT_SIMPLE;
+"MVT_VERY_SIMPLE",MVT_VERY_SIMPLE;
+"NADD_ADD",NADD_ADD;
+"NADD_ADDITIVE",NADD_ADDITIVE;
+"NADD_ADD_ASSOC",NADD_ADD_ASSOC;
+"NADD_ADD_LCANCEL",NADD_ADD_LCANCEL;
+"NADD_ADD_LID",NADD_ADD_LID;
+"NADD_ADD_SYM",NADD_ADD_SYM;
+"NADD_ADD_WELLDEF",NADD_ADD_WELLDEF;
+"NADD_ALTMUL",NADD_ALTMUL;
+"NADD_ARCH",NADD_ARCH;
+"NADD_ARCH_LEMMA",NADD_ARCH_LEMMA;
+"NADD_ARCH_MULT",NADD_ARCH_MULT;
+"NADD_ARCH_ZERO",NADD_ARCH_ZERO;
+"NADD_BOUND",NADD_BOUND;
+"NADD_CAUCHY",NADD_CAUCHY;
+"NADD_COMPLETE",NADD_COMPLETE;
+"NADD_DIST",NADD_DIST;
+"NADD_DIST_LEMMA",NADD_DIST_LEMMA;
+"NADD_EQ_IMP_LE",NADD_EQ_IMP_LE;
+"NADD_EQ_REFL",NADD_EQ_REFL;
+"NADD_EQ_SYM",NADD_EQ_SYM;
+"NADD_EQ_TRANS",NADD_EQ_TRANS;
+"NADD_INV",NADD_INV;
+"NADD_INV_0",NADD_INV_0;
+"NADD_INV_WELLDEF",NADD_INV_WELLDEF;
+"NADD_LBOUND",NADD_LBOUND;
+"NADD_LDISTRIB",NADD_LDISTRIB;
+"NADD_LE_0",NADD_LE_0;
+"NADD_LE_ADD",NADD_LE_ADD;
+"NADD_LE_ANTISYM",NADD_LE_ANTISYM;
+"NADD_LE_EXISTS",NADD_LE_EXISTS;
+"NADD_LE_LADD",NADD_LE_LADD;
+"NADD_LE_LMUL",NADD_LE_LMUL;
+"NADD_LE_RADD",NADD_LE_RADD;
+"NADD_LE_REFL",NADD_LE_REFL;
+"NADD_LE_RMUL",NADD_LE_RMUL;
+"NADD_LE_TOTAL",NADD_LE_TOTAL;
+"NADD_LE_TOTAL_LEMMA",NADD_LE_TOTAL_LEMMA;
+"NADD_LE_TRANS",NADD_LE_TRANS;
+"NADD_LE_WELLDEF",NADD_LE_WELLDEF;
+"NADD_LE_WELLDEF_LEMMA",NADD_LE_WELLDEF_LEMMA;
+"NADD_MUL",NADD_MUL;
+"NADD_MULTIPLICATIVE",NADD_MULTIPLICATIVE;
+"NADD_MUL_ASSOC",NADD_MUL_ASSOC;
+"NADD_MUL_LID",NADD_MUL_LID;
+"NADD_MUL_LINV",NADD_MUL_LINV;
+"NADD_MUL_LINV_LEMMA0",NADD_MUL_LINV_LEMMA0;
+"NADD_MUL_LINV_LEMMA1",NADD_MUL_LINV_LEMMA1;
+"NADD_MUL_LINV_LEMMA2",NADD_MUL_LINV_LEMMA2;
+"NADD_MUL_LINV_LEMMA3",NADD_MUL_LINV_LEMMA3;
+"NADD_MUL_LINV_LEMMA4",NADD_MUL_LINV_LEMMA4;
+"NADD_MUL_LINV_LEMMA5",NADD_MUL_LINV_LEMMA5;
+"NADD_MUL_LINV_LEMMA6",NADD_MUL_LINV_LEMMA6;
+"NADD_MUL_LINV_LEMMA7",NADD_MUL_LINV_LEMMA7;
+"NADD_MUL_LINV_LEMMA7a",NADD_MUL_LINV_LEMMA7a;
+"NADD_MUL_LINV_LEMMA8",NADD_MUL_LINV_LEMMA8;
+"NADD_MUL_SYM",NADD_MUL_SYM;
+"NADD_MUL_WELLDEF",NADD_MUL_WELLDEF;
+"NADD_MUL_WELLDEF_LEMMA",NADD_MUL_WELLDEF_LEMMA;
+"NADD_NONZERO",NADD_NONZERO;
+"NADD_OF_NUM",NADD_OF_NUM;
+"NADD_OF_NUM_ADD",NADD_OF_NUM_ADD;
+"NADD_OF_NUM_EQ",NADD_OF_NUM_EQ;
+"NADD_OF_NUM_LE",NADD_OF_NUM_LE;
+"NADD_OF_NUM_MUL",NADD_OF_NUM_MUL;
+"NADD_OF_NUM_WELLDEF",NADD_OF_NUM_WELLDEF;
+"NADD_RDISTRIB",NADD_RDISTRIB;
+"NADD_SUC",NADD_SUC;
+"NADD_UBOUND",NADD_UBOUND;
+"NEARBY_INVERTIBLE_MATRIX",NEARBY_INVERTIBLE_MATRIX;
+"NEGATIONS_BALL",NEGATIONS_BALL;
+"NEGATIONS_CBALL",NEGATIONS_CBALL;
+"NEGATIONS_SPHERE",NEGATIONS_SPHERE;
+"NEGLIGIBLE",NEGLIGIBLE;
+"NEGLIGIBLE_AFFINE_HULL",NEGLIGIBLE_AFFINE_HULL;
+"NEGLIGIBLE_AFFINE_HULL_1",NEGLIGIBLE_AFFINE_HULL_1;
+"NEGLIGIBLE_AFFINE_HULL_2",NEGLIGIBLE_AFFINE_HULL_2;
+"NEGLIGIBLE_AFFINE_HULL_3",NEGLIGIBLE_AFFINE_HULL_3;
+"NEGLIGIBLE_CONVEX_FRONTIER",NEGLIGIBLE_CONVEX_FRONTIER;
+"NEGLIGIBLE_CONVEX_HULL",NEGLIGIBLE_CONVEX_HULL;
+"NEGLIGIBLE_CONVEX_HULL_1",NEGLIGIBLE_CONVEX_HULL_1;
+"NEGLIGIBLE_CONVEX_HULL_2",NEGLIGIBLE_CONVEX_HULL_2;
+"NEGLIGIBLE_CONVEX_HULL_3",NEGLIGIBLE_CONVEX_HULL_3;
+"NEGLIGIBLE_COUNTABLE",NEGLIGIBLE_COUNTABLE;
+"NEGLIGIBLE_COUNTABLE_UNIONS",NEGLIGIBLE_COUNTABLE_UNIONS;
+"NEGLIGIBLE_COUNTABLE_UNIONS_GEN",NEGLIGIBLE_COUNTABLE_UNIONS_GEN;
+"NEGLIGIBLE_DELETE",NEGLIGIBLE_DELETE;
+"NEGLIGIBLE_DIFF",NEGLIGIBLE_DIFF;
+"NEGLIGIBLE_DIFFERENTIABLE_IMAGE_LOWDIM",NEGLIGIBLE_DIFFERENTIABLE_IMAGE_LOWDIM;
+"NEGLIGIBLE_DIFFERENTIABLE_IMAGE_NEGLIGIBLE",NEGLIGIBLE_DIFFERENTIABLE_IMAGE_NEGLIGIBLE;
+"NEGLIGIBLE_EMPTY",NEGLIGIBLE_EMPTY;
+"NEGLIGIBLE_EQ_MEASURE_0",NEGLIGIBLE_EQ_MEASURE_0;
+"NEGLIGIBLE_FINITE",NEGLIGIBLE_FINITE;
+"NEGLIGIBLE_FRONTIER_INTERVAL",NEGLIGIBLE_FRONTIER_INTERVAL;
+"NEGLIGIBLE_HYPERPLANE",NEGLIGIBLE_HYPERPLANE;
+"NEGLIGIBLE_IFF_LEBESGUE_MEASURABLE_SUBSETS",NEGLIGIBLE_IFF_LEBESGUE_MEASURABLE_SUBSETS;
+"NEGLIGIBLE_IFF_MEASURABLE_SUBSETS",NEGLIGIBLE_IFF_MEASURABLE_SUBSETS;
+"NEGLIGIBLE_IMAGE_BOUNDED_VARIATION_INTERVAL",NEGLIGIBLE_IMAGE_BOUNDED_VARIATION_INTERVAL;
+"NEGLIGIBLE_IMP_LEBESGUE_MEASURABLE",NEGLIGIBLE_IMP_LEBESGUE_MEASURABLE;
+"NEGLIGIBLE_IMP_MEASURABLE",NEGLIGIBLE_IMP_MEASURABLE;
+"NEGLIGIBLE_INSERT",NEGLIGIBLE_INSERT;
+"NEGLIGIBLE_INTER",NEGLIGIBLE_INTER;
+"NEGLIGIBLE_INTERVAL",NEGLIGIBLE_INTERVAL;
+"NEGLIGIBLE_LINEAR_IMAGE",NEGLIGIBLE_LINEAR_IMAGE;
+"NEGLIGIBLE_LINEAR_IMAGE_EQ",NEGLIGIBLE_LINEAR_IMAGE_EQ;
+"NEGLIGIBLE_LINEAR_SINGULAR_IMAGE",NEGLIGIBLE_LINEAR_SINGULAR_IMAGE;
+"NEGLIGIBLE_LIPSCHITZ_IMAGE_UNIV",NEGLIGIBLE_LIPSCHITZ_IMAGE_UNIV;
+"NEGLIGIBLE_LOCALLY_LIPSCHITZ_IMAGE",NEGLIGIBLE_LOCALLY_LIPSCHITZ_IMAGE;
+"NEGLIGIBLE_LOWDIM",NEGLIGIBLE_LOWDIM;
+"NEGLIGIBLE_ON_INTERVALS",NEGLIGIBLE_ON_INTERVALS;
+"NEGLIGIBLE_ON_UNIV",NEGLIGIBLE_ON_UNIV;
+"NEGLIGIBLE_OUTER",NEGLIGIBLE_OUTER;
+"NEGLIGIBLE_OUTER_LE",NEGLIGIBLE_OUTER_LE;
+"NEGLIGIBLE_RECTIFIABLE_PATH_IMAGE",NEGLIGIBLE_RECTIFIABLE_PATH_IMAGE;
+"NEGLIGIBLE_SING",NEGLIGIBLE_SING;
+"NEGLIGIBLE_SPHERE",NEGLIGIBLE_SPHERE;
+"NEGLIGIBLE_STANDARD_HYPERPLANE",NEGLIGIBLE_STANDARD_HYPERPLANE;
+"NEGLIGIBLE_SUBSET",NEGLIGIBLE_SUBSET;
+"NEGLIGIBLE_SYMDIFF_EQ",NEGLIGIBLE_SYMDIFF_EQ;
+"NEGLIGIBLE_TRANSLATION",NEGLIGIBLE_TRANSLATION;
+"NEGLIGIBLE_TRANSLATION_EQ",NEGLIGIBLE_TRANSLATION_EQ;
+"NEGLIGIBLE_TRANSLATION_REV",NEGLIGIBLE_TRANSLATION_REV;
+"NEGLIGIBLE_UNION",NEGLIGIBLE_UNION;
+"NEGLIGIBLE_UNIONS",NEGLIGIBLE_UNIONS;
+"NEGLIGIBLE_UNION_EQ",NEGLIGIBLE_UNION_EQ;
+"NEIGHBOURHOOD_EXTENSION_INTO_ANR",NEIGHBOURHOOD_EXTENSION_INTO_ANR;
+"NEIGHBOURHOOD_EXTENSION_INTO_ANR_LOCAL",NEIGHBOURHOOD_EXTENSION_INTO_ANR_LOCAL;
+"NEIGHBOURHOOD_RETRACT_IMP_ANR",NEIGHBOURHOOD_RETRACT_IMP_ANR;
+"NEIGHBOURHOOD_RETRACT_IMP_ANR_UNIV",NEIGHBOURHOOD_RETRACT_IMP_ANR_UNIV;
+"NET",NET;
+"NETLIMIT_AT",NETLIMIT_AT;
+"NETLIMIT_WITHIN",NETLIMIT_WITHIN;
+"NETLIMIT_WITHIN_INTERIOR",NETLIMIT_WITHIN_INTERIOR;
+"NET_DILEMMA",NET_DILEMMA;
+"NEUTRAL_ADD",NEUTRAL_ADD;
+"NEUTRAL_AND",NEUTRAL_AND;
+"NEUTRAL_LIFTED",NEUTRAL_LIFTED;
+"NEUTRAL_MUL",NEUTRAL_MUL;
+"NEUTRAL_OUTER",NEUTRAL_OUTER;
+"NEUTRAL_REAL_ADD",NEUTRAL_REAL_ADD;
+"NEUTRAL_REAL_MUL",NEUTRAL_REAL_MUL;
+"NEUTRAL_VECTOR_ADD",NEUTRAL_VECTOR_ADD;
+"NONEMPTY_SIMPLE_PATH_ENDLESS",NONEMPTY_SIMPLE_PATH_ENDLESS;
+"NONNEGATIVE_ABSOLUTELY_INTEGRABLE",NONNEGATIVE_ABSOLUTELY_INTEGRABLE;
+"NONTRIVIAL_LIMIT_WITHIN",NONTRIVIAL_LIMIT_WITHIN;
+"NORM_0",NORM_0;
+"NORM_1",NORM_1;
+"NORM_1_POS",NORM_1_POS;
+"NORM_ADD_PYTHAGOREAN",NORM_ADD_PYTHAGOREAN;
+"NORM_BASIS",NORM_BASIS;
+"NORM_BASIS_1",NORM_BASIS_1;
+"NORM_BOUND_COMPONENT_LE",NORM_BOUND_COMPONENT_LE;
+"NORM_BOUND_COMPONENT_LT",NORM_BOUND_COMPONENT_LT;
+"NORM_BOUND_GENERALIZE",NORM_BOUND_GENERALIZE;
+"NORM_CAUCHY_SCHWARZ",NORM_CAUCHY_SCHWARZ;
+"NORM_CAUCHY_SCHWARZ_ABS",NORM_CAUCHY_SCHWARZ_ABS;
+"NORM_CAUCHY_SCHWARZ_ABS_EQ",NORM_CAUCHY_SCHWARZ_ABS_EQ;
+"NORM_CAUCHY_SCHWARZ_DIV",NORM_CAUCHY_SCHWARZ_DIV;
+"NORM_CAUCHY_SCHWARZ_EQ",NORM_CAUCHY_SCHWARZ_EQ;
+"NORM_CAUCHY_SCHWARZ_EQUAL",NORM_CAUCHY_SCHWARZ_EQUAL;
+"NORM_CROSS_MULTIPLY",NORM_CROSS_MULTIPLY;
+"NORM_EQ",NORM_EQ;
+"NORM_EQ_0",NORM_EQ_0;
+"NORM_EQ_0_DOT",NORM_EQ_0_DOT;
+"NORM_EQ_0_IMP",NORM_EQ_0_IMP;
+"NORM_EQ_1",NORM_EQ_1;
+"NORM_EQ_SQUARE",NORM_EQ_SQUARE;
+"NORM_FSTCART",NORM_FSTCART;
+"NORM_GE_SQUARE",NORM_GE_SQUARE;
+"NORM_GT_SQUARE",NORM_GT_SQUARE;
+"NORM_INCREASES_ONLINE",NORM_INCREASES_ONLINE;
+"NORM_LE",NORM_LE;
+"NORM_LE_0",NORM_LE_0;
+"NORM_LE_COMPONENTWISE",NORM_LE_COMPONENTWISE;
+"NORM_LE_INFNORM",NORM_LE_INFNORM;
+"NORM_LE_L1",NORM_LE_L1;
+"NORM_LE_PASTECART",NORM_LE_PASTECART;
+"NORM_LE_SQUARE",NORM_LE_SQUARE;
+"NORM_LIFT",NORM_LIFT;
+"NORM_LT",NORM_LT;
+"NORM_LT_SQUARE",NORM_LT_SQUARE;
+"NORM_LT_SQUARE_ALT",NORM_LT_SQUARE_ALT;
+"NORM_MUL",NORM_MUL;
+"NORM_NEG",NORM_NEG;
+"NORM_PASTECART",NORM_PASTECART;
+"NORM_PASTECART_0",NORM_PASTECART_0;
+"NORM_PASTECART_LE",NORM_PASTECART_LE;
+"NORM_POS_LE",NORM_POS_LE;
+"NORM_POS_LT",NORM_POS_LT;
+"NORM_POW_2",NORM_POW_2;
+"NORM_REAL",NORM_REAL;
+"NORM_SEGMENT_LOWERBOUND",NORM_SEGMENT_LOWERBOUND;
+"NORM_SEGMENT_ORTHOGONAL_LOWERBOUND",NORM_SEGMENT_ORTHOGONAL_LOWERBOUND;
+"NORM_SNDCART",NORM_SNDCART;
+"NORM_SUB",NORM_SUB;
+"NORM_TRIANGLE",NORM_TRIANGLE;
+"NORM_TRIANGLE_EQ",NORM_TRIANGLE_EQ;
+"NORM_TRIANGLE_LE",NORM_TRIANGLE_LE;
+"NORM_TRIANGLE_LT",NORM_TRIANGLE_LT;
+"NORM_TRIANGLE_SUB",NORM_TRIANGLE_SUB;
+"NORM_VSUM_PYTHAGOREAN",NORM_VSUM_PYTHAGOREAN;
+"NORM_VSUM_TRIVIAL_LEMMA",NORM_VSUM_TRIVIAL_LEMMA;
+"NOT_ABSOLUTE_RETRACT_COBOUNDED",NOT_ABSOLUTE_RETRACT_COBOUNDED;
+"NOT_ALL",NOT_ALL;
+"NOT_BOUNDED_UNIV",NOT_BOUNDED_UNIV;
+"NOT_CLAUSES",NOT_CLAUSES;
+"NOT_CLAUSES_WEAK",NOT_CLAUSES_WEAK;
+"NOT_CONS_NIL",NOT_CONS_NIL;
+"NOT_DEF",NOT_DEF;
+"NOT_EMPTY_INSERT",NOT_EMPTY_INSERT;
+"NOT_EQUAL_SETS",NOT_EQUAL_SETS;
+"NOT_EVEN",NOT_EVEN;
+"NOT_EVENTUALLY",NOT_EVENTUALLY;
+"NOT_EX",NOT_EX;
+"NOT_EXISTS_THM",NOT_EXISTS_THM;
+"NOT_FORALL_THM",NOT_FORALL_THM;
+"NOT_IMP",NOT_IMP;
+"NOT_INSERT_EMPTY",NOT_INSERT_EMPTY;
+"NOT_INTERVAL_UNIV",NOT_INTERVAL_UNIV;
+"NOT_IN_EMPTY",NOT_IN_EMPTY;
+"NOT_IN_INTERIOR_CONVEX_HULL",NOT_IN_INTERIOR_CONVEX_HULL;
+"NOT_IN_PATH_IMAGE_JOIN",NOT_IN_PATH_IMAGE_JOIN;
+"NOT_LE",NOT_LE;
+"NOT_LT",NOT_LT;
+"NOT_NEGLIGIBLE_UNIV",NOT_NEGLIGIBLE_UNIV;
+"NOT_ODD",NOT_ODD;
+"NOT_ON_PATH_BALL",NOT_ON_PATH_BALL;
+"NOT_ON_PATH_CBALL",NOT_ON_PATH_CBALL;
+"NOT_OUTSIDE_CONNECTED_COMPONENT_LE",NOT_OUTSIDE_CONNECTED_COMPONENT_LE;
+"NOT_OUTSIDE_CONNECTED_COMPONENT_LT",NOT_OUTSIDE_CONNECTED_COMPONENT_LT;
+"NOT_PSUBSET_EMPTY",NOT_PSUBSET_EMPTY;
+"NOT_SUC",NOT_SUC;
+"NOT_UNIV_PSUBSET",NOT_UNIV_PSUBSET;
+"NOWHERE_DENSE",NOWHERE_DENSE;
+"NOWHERE_DENSE_UNION",NOWHERE_DENSE_UNION;
+"NO_LIMIT_POINT_IMP_CLOSED",NO_LIMIT_POINT_IMP_CLOSED;
+"NO_RETRACTION_CBALL",NO_RETRACTION_CBALL;
+"NO_RETRACTION_FRONTIER_BOUNDED",NO_RETRACTION_FRONTIER_BOUNDED;
+"NSUM_0",NSUM_0;
+"NSUM_ADD",NSUM_ADD;
+"NSUM_ADD_GEN",NSUM_ADD_GEN;
+"NSUM_ADD_NUMSEG",NSUM_ADD_NUMSEG;
+"NSUM_ADD_SPLIT",NSUM_ADD_SPLIT;
+"NSUM_BIJECTION",NSUM_BIJECTION;
+"NSUM_BOUND",NSUM_BOUND;
+"NSUM_BOUND_GEN",NSUM_BOUND_GEN;
+"NSUM_BOUND_LT",NSUM_BOUND_LT;
+"NSUM_BOUND_LT_ALL",NSUM_BOUND_LT_ALL;
+"NSUM_BOUND_LT_GEN",NSUM_BOUND_LT_GEN;
+"NSUM_CASES",NSUM_CASES;
+"NSUM_CLAUSES",NSUM_CLAUSES;
+"NSUM_CLAUSES_LEFT",NSUM_CLAUSES_LEFT;
+"NSUM_CLAUSES_NUMSEG",NSUM_CLAUSES_NUMSEG;
+"NSUM_CLAUSES_RIGHT",NSUM_CLAUSES_RIGHT;
+"NSUM_CLOSED",NSUM_CLOSED;
+"NSUM_CONST",NSUM_CONST;
+"NSUM_CONST_NUMSEG",NSUM_CONST_NUMSEG;
+"NSUM_DELETE",NSUM_DELETE;
+"NSUM_DELTA",NSUM_DELTA;
+"NSUM_DIFF",NSUM_DIFF;
+"NSUM_EQ",NSUM_EQ;
+"NSUM_EQ_0",NSUM_EQ_0;
+"NSUM_EQ_0_IFF",NSUM_EQ_0_IFF;
+"NSUM_EQ_0_IFF_NUMSEG",NSUM_EQ_0_IFF_NUMSEG;
+"NSUM_EQ_0_NUMSEG",NSUM_EQ_0_NUMSEG;
+"NSUM_EQ_GENERAL",NSUM_EQ_GENERAL;
+"NSUM_EQ_GENERAL_INVERSES",NSUM_EQ_GENERAL_INVERSES;
+"NSUM_EQ_NUMSEG",NSUM_EQ_NUMSEG;
+"NSUM_EQ_SUPERSET",NSUM_EQ_SUPERSET;
+"NSUM_GROUP",NSUM_GROUP;
+"NSUM_IMAGE",NSUM_IMAGE;
+"NSUM_IMAGE_GEN",NSUM_IMAGE_GEN;
+"NSUM_IMAGE_NONZERO",NSUM_IMAGE_NONZERO;
+"NSUM_INCL_EXCL",NSUM_INCL_EXCL;
+"NSUM_INJECTION",NSUM_INJECTION;
+"NSUM_LE",NSUM_LE;
+"NSUM_LE_NUMSEG",NSUM_LE_NUMSEG;
+"NSUM_LMUL",NSUM_LMUL;
+"NSUM_LT",NSUM_LT;
+"NSUM_LT_ALL",NSUM_LT_ALL;
+"NSUM_MULTICOUNT",NSUM_MULTICOUNT;
+"NSUM_MULTICOUNT_GEN",NSUM_MULTICOUNT_GEN;
+"NSUM_NSUM_PRODUCT",NSUM_NSUM_PRODUCT;
+"NSUM_NSUM_RESTRICT",NSUM_NSUM_RESTRICT;
+"NSUM_OFFSET",NSUM_OFFSET;
+"NSUM_OFFSET_0",NSUM_OFFSET_0;
+"NSUM_PAIR",NSUM_PAIR;
+"NSUM_PERMUTE",NSUM_PERMUTE;
+"NSUM_PERMUTE_NUMSEG",NSUM_PERMUTE_NUMSEG;
+"NSUM_POS_BOUND",NSUM_POS_BOUND;
+"NSUM_POS_LT",NSUM_POS_LT;
+"NSUM_RESTRICT",NSUM_RESTRICT;
+"NSUM_RESTRICT_SET",NSUM_RESTRICT_SET;
+"NSUM_RMUL",NSUM_RMUL;
+"NSUM_SING",NSUM_SING;
+"NSUM_SING_NUMSEG",NSUM_SING_NUMSEG;
+"NSUM_SUBSET",NSUM_SUBSET;
+"NSUM_SUBSET_SIMPLE",NSUM_SUBSET_SIMPLE;
+"NSUM_SUPERSET",NSUM_SUPERSET;
+"NSUM_SUPPORT",NSUM_SUPPORT;
+"NSUM_SWAP",NSUM_SWAP;
+"NSUM_SWAP_NUMSEG",NSUM_SWAP_NUMSEG;
+"NSUM_TRIV_NUMSEG",NSUM_TRIV_NUMSEG;
+"NSUM_UNION",NSUM_UNION;
+"NSUM_UNIONS_NONZERO",NSUM_UNIONS_NONZERO;
+"NSUM_UNION_EQ",NSUM_UNION_EQ;
+"NSUM_UNION_LZERO",NSUM_UNION_LZERO;
+"NSUM_UNION_NONZERO",NSUM_UNION_NONZERO;
+"NSUM_UNION_RZERO",NSUM_UNION_RZERO;
+"NULL",NULL;
+"NULLHOMOTOPIC_FROM_CONTRACTIBLE",NULLHOMOTOPIC_FROM_CONTRACTIBLE;
+"NULLHOMOTOPIC_FROM_SPHERE_EXTENSION",NULLHOMOTOPIC_FROM_SPHERE_EXTENSION;
+"NULLHOMOTOPIC_INTO_ANR_EXTENSION",NULLHOMOTOPIC_INTO_ANR_EXTENSION;
+"NULLHOMOTOPIC_INTO_CONTRACTIBLE",NULLHOMOTOPIC_INTO_CONTRACTIBLE;
+"NULLHOMOTOPIC_INTO_RELATIVE_FRONTIER_EXTENSION",NULLHOMOTOPIC_INTO_RELATIVE_FRONTIER_EXTENSION;
+"NULLHOMOTOPIC_INTO_SPHERE_EXTENSION",NULLHOMOTOPIC_INTO_SPHERE_EXTENSION;
+"NULLHOMOTOPIC_THROUGH_CONTRACTIBLE",NULLHOMOTOPIC_THROUGH_CONTRACTIBLE;
+"NULLSPACE_INTER_ROWSPACE",NULLSPACE_INTER_ROWSPACE;
+"NUMERAL",NUMERAL;
+"NUMPAIR",NUMPAIR;
+"NUMPAIR_DEST",NUMPAIR_DEST;
+"NUMPAIR_INJ",NUMPAIR_INJ;
+"NUMPAIR_INJ_LEMMA",NUMPAIR_INJ_LEMMA;
+"NUMSEG_ADD_SPLIT",NUMSEG_ADD_SPLIT;
+"NUMSEG_CLAUSES",NUMSEG_CLAUSES;
+"NUMSEG_COMBINE_L",NUMSEG_COMBINE_L;
+"NUMSEG_COMBINE_R",NUMSEG_COMBINE_R;
+"NUMSEG_DIMINDEX_NONEMPTY",NUMSEG_DIMINDEX_NONEMPTY;
+"NUMSEG_EMPTY",NUMSEG_EMPTY;
+"NUMSEG_LE",NUMSEG_LE;
+"NUMSEG_LREC",NUMSEG_LREC;
+"NUMSEG_LT",NUMSEG_LT;
+"NUMSEG_OFFSET_IMAGE",NUMSEG_OFFSET_IMAGE;
+"NUMSEG_REC",NUMSEG_REC;
+"NUMSEG_RREC",NUMSEG_RREC;
+"NUMSEG_SING",NUMSEG_SING;
+"NUMSUM",NUMSUM;
+"NUMSUM_DEST",NUMSUM_DEST;
+"NUMSUM_INJ",NUMSUM_INJ;
+"NUM_COUNTABLE",NUM_COUNTABLE;
+"NUM_GCD",NUM_GCD;
+"NUM_OF_INT",NUM_OF_INT;
+"NUM_OF_INT_OF_NUM",NUM_OF_INT_OF_NUM;
+"NUM_REP_CASES",NUM_REP_CASES;
+"NUM_REP_INDUCT",NUM_REP_INDUCT;
+"NUM_REP_RULES",NUM_REP_RULES;
+"ODD",ODD;
+"ODD_ADD",ODD_ADD;
+"ODD_DOUBLE",ODD_DOUBLE;
+"ODD_EXISTS",ODD_EXISTS;
+"ODD_EXP",ODD_EXP;
+"ODD_MOD",ODD_MOD;
+"ODD_MULT",ODD_MULT;
+"ODD_SUB",ODD_SUB;
+"OEP",OEP;
+"OLDNET",OLDNET;
+"ONE",ONE;
+"ONE_ONE",ONE_ONE;
+"ONORM",ONORM;
+"ONORM_COMPOSE",ONORM_COMPOSE;
+"ONORM_CONST",ONORM_CONST;
+"ONORM_EQ_0",ONORM_EQ_0;
+"ONORM_I",ONORM_I;
+"ONORM_ID",ONORM_ID;
+"ONORM_NEG",ONORM_NEG;
+"ONORM_NEG_LEMMA",ONORM_NEG_LEMMA;
+"ONORM_POS_LE",ONORM_POS_LE;
+"ONORM_POS_LT",ONORM_POS_LT;
+"ONORM_TRIANGLE",ONORM_TRIANGLE;
+"ONORM_TRIANGLE_LE",ONORM_TRIANGLE_LE;
+"ONORM_TRIANGLE_LT",ONORM_TRIANGLE_LT;
+"ONTO",ONTO;
+"OPEN_AFFINITY",OPEN_AFFINITY;
+"OPEN_BALL",OPEN_BALL;
+"OPEN_BIJECTIVE_LINEAR_IMAGE_EQ",OPEN_BIJECTIVE_LINEAR_IMAGE_EQ;
+"OPEN_CLOSED",OPEN_CLOSED;
+"OPEN_CLOSED_INTERVAL_1",OPEN_CLOSED_INTERVAL_1;
+"OPEN_CLOSED_INTERVAL_CONVEX",OPEN_CLOSED_INTERVAL_CONVEX;
+"OPEN_COMPONENTS",OPEN_COMPONENTS;
+"OPEN_CONNECTED_COMPONENT",OPEN_CONNECTED_COMPONENT;
+"OPEN_CONTAINS_BALL",OPEN_CONTAINS_BALL;
+"OPEN_CONTAINS_BALL_EQ",OPEN_CONTAINS_BALL_EQ;
+"OPEN_CONTAINS_CBALL",OPEN_CONTAINS_CBALL;
+"OPEN_CONTAINS_CBALL_EQ",OPEN_CONTAINS_CBALL_EQ;
+"OPEN_CONTAINS_INTERVAL",OPEN_CONTAINS_INTERVAL;
+"OPEN_CONTAINS_OPEN_INTERVAL",OPEN_CONTAINS_OPEN_INTERVAL;
+"OPEN_CONVEX_HULL",OPEN_CONVEX_HULL;
+"OPEN_COUNTABLE_UNION_CLOSED_INTERVALS",OPEN_COUNTABLE_UNION_CLOSED_INTERVALS;
+"OPEN_COUNTABLE_UNION_OPEN_INTERVALS",OPEN_COUNTABLE_UNION_OPEN_INTERVALS;
+"OPEN_DELETE",OPEN_DELETE;
+"OPEN_DIFF",OPEN_DIFF;
+"OPEN_EMPTY",OPEN_EMPTY;
+"OPEN_EXISTS",OPEN_EXISTS;
+"OPEN_EXISTS_IN",OPEN_EXISTS_IN;
+"OPEN_GENERAL_COMPONENT",OPEN_GENERAL_COMPONENT;
+"OPEN_HALFSPACE_COMPONENT_GT",OPEN_HALFSPACE_COMPONENT_GT;
+"OPEN_HALFSPACE_COMPONENT_LT",OPEN_HALFSPACE_COMPONENT_LT;
+"OPEN_HALFSPACE_GT",OPEN_HALFSPACE_GT;
+"OPEN_HALFSPACE_LT",OPEN_HALFSPACE_LT;
+"OPEN_IMP_INFINITE",OPEN_IMP_INFINITE;
+"OPEN_IMP_LOCALLY_COMPACT",OPEN_IMP_LOCALLY_COMPACT;
+"OPEN_IMP_LOCALLY_CONNECTED",OPEN_IMP_LOCALLY_CONNECTED;
+"OPEN_IMP_LOCALLY_PATH_CONNECTED",OPEN_IMP_LOCALLY_PATH_CONNECTED;
+"OPEN_IN",OPEN_IN;
+"OPEN_INSIDE",OPEN_INSIDE;
+"OPEN_INTER",OPEN_INTER;
+"OPEN_INTERIOR",OPEN_INTERIOR;
+"OPEN_INTERS",OPEN_INTERS;
+"OPEN_INTERVAL",OPEN_INTERVAL;
+"OPEN_INTERVAL_EQ",OPEN_INTERVAL_EQ;
+"OPEN_INTERVAL_LEMMA",OPEN_INTERVAL_LEMMA;
+"OPEN_INTERVAL_MIDPOINT",OPEN_INTERVAL_MIDPOINT;
+"OPEN_INTER_CLOSURE_EQ_EMPTY",OPEN_INTER_CLOSURE_EQ_EMPTY;
+"OPEN_INTER_CLOSURE_SUBSET",OPEN_INTER_CLOSURE_SUBSET;
+"OPEN_IN_CLAUSES",OPEN_IN_CLAUSES;
+"OPEN_IN_CLOSED_IN",OPEN_IN_CLOSED_IN;
+"OPEN_IN_CLOSED_IN_EQ",OPEN_IN_CLOSED_IN_EQ;
+"OPEN_IN_COMPONENTS_LOCALLY_CONNECTED",OPEN_IN_COMPONENTS_LOCALLY_CONNECTED;
+"OPEN_IN_CONNECTED_COMPONENT",OPEN_IN_CONNECTED_COMPONENT;
+"OPEN_IN_CONNECTED_COMPONENTS",OPEN_IN_CONNECTED_COMPONENTS;
+"OPEN_IN_CONNECTED_COMPONENT_LOCALLY_CONNECTED",OPEN_IN_CONNECTED_COMPONENT_LOCALLY_CONNECTED;
+"OPEN_IN_CONTAINS_BALL",OPEN_IN_CONTAINS_BALL;
+"OPEN_IN_CONTAINS_CBALL",OPEN_IN_CONTAINS_CBALL;
+"OPEN_IN_DELETE",OPEN_IN_DELETE;
+"OPEN_IN_DIFF",OPEN_IN_DIFF;
+"OPEN_IN_EMPTY",OPEN_IN_EMPTY;
+"OPEN_IN_IMP_SUBSET",OPEN_IN_IMP_SUBSET;
+"OPEN_IN_INJECTIVE_LINEAR_IMAGE",OPEN_IN_INJECTIVE_LINEAR_IMAGE;
+"OPEN_IN_INTER",OPEN_IN_INTER;
+"OPEN_IN_INTERS",OPEN_IN_INTERS;
+"OPEN_IN_INTER_OPEN",OPEN_IN_INTER_OPEN;
+"OPEN_IN_OPEN",OPEN_IN_OPEN;
+"OPEN_IN_OPEN_EQ",OPEN_IN_OPEN_EQ;
+"OPEN_IN_OPEN_INTER",OPEN_IN_OPEN_INTER;
+"OPEN_IN_OPEN_TRANS",OPEN_IN_OPEN_TRANS;
+"OPEN_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED",OPEN_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED;
+"OPEN_IN_PCROSS",OPEN_IN_PCROSS;
+"OPEN_IN_PCROSS_EQ",OPEN_IN_PCROSS_EQ;
+"OPEN_IN_REFL",OPEN_IN_REFL;
+"OPEN_IN_RELATIVE_INTERIOR",OPEN_IN_RELATIVE_INTERIOR;
+"OPEN_IN_SING",OPEN_IN_SING;
+"OPEN_IN_SUBOPEN",OPEN_IN_SUBOPEN;
+"OPEN_IN_SUBSET",OPEN_IN_SUBSET;
+"OPEN_IN_SUBSET_RELATIVE_INTERIOR",OPEN_IN_SUBSET_RELATIVE_INTERIOR;
+"OPEN_IN_SUBSET_TRANS",OPEN_IN_SUBSET_TRANS;
+"OPEN_IN_SUBTOPOLOGY",OPEN_IN_SUBTOPOLOGY;
+"OPEN_IN_SUBTOPOLOGY_EMPTY",OPEN_IN_SUBTOPOLOGY_EMPTY;
+"OPEN_IN_SUBTOPOLOGY_INTER_SUBSET",OPEN_IN_SUBTOPOLOGY_INTER_SUBSET;
+"OPEN_IN_SUBTOPOLOGY_REFL",OPEN_IN_SUBTOPOLOGY_REFL;
+"OPEN_IN_SUBTOPOLOGY_UNION",OPEN_IN_SUBTOPOLOGY_UNION;
+"OPEN_IN_TOPSPACE",OPEN_IN_TOPSPACE;
+"OPEN_IN_TRANS",OPEN_IN_TRANS;
+"OPEN_IN_TRANSLATION_EQ",OPEN_IN_TRANSLATION_EQ;
+"OPEN_IN_UNION",OPEN_IN_UNION;
+"OPEN_IN_UNIONS",OPEN_IN_UNIONS;
+"OPEN_LIFT",OPEN_LIFT;
+"OPEN_MAP_FROM_COMPOSITION_INJECTIVE",OPEN_MAP_FROM_COMPOSITION_INJECTIVE;
+"OPEN_MAP_FROM_COMPOSITION_SURJECTIVE",OPEN_MAP_FROM_COMPOSITION_SURJECTIVE;
+"OPEN_MAP_IMP_CLOSED_MAP",OPEN_MAP_IMP_CLOSED_MAP;
+"OPEN_MAP_IMP_QUOTIENT_MAP",OPEN_MAP_IMP_QUOTIENT_MAP;
+"OPEN_MEASURABLE_INNER_DIVISION",OPEN_MEASURABLE_INNER_DIVISION;
+"OPEN_NEGATIONS",OPEN_NEGATIONS;
+"OPEN_NON_GENERAL_COMPONENT",OPEN_NON_GENERAL_COMPONENT;
+"OPEN_NON_PATH_COMPONENT",OPEN_NON_PATH_COMPONENT;
+"OPEN_NOT_NEGLIGIBLE",OPEN_NOT_NEGLIGIBLE;
+"OPEN_OPEN_IN_TRANS",OPEN_OPEN_IN_TRANS;
+"OPEN_OPEN_LEFT_PROJECTION",OPEN_OPEN_LEFT_PROJECTION;
+"OPEN_OPEN_RIGHT_PROJECTION",OPEN_OPEN_RIGHT_PROJECTION;
+"OPEN_OUTSIDE",OPEN_OUTSIDE;
+"OPEN_PATH_COMPONENT",OPEN_PATH_COMPONENT;
+"OPEN_PATH_CONNECTED_COMPONENT",OPEN_PATH_CONNECTED_COMPONENT;
+"OPEN_PCROSS",OPEN_PCROSS;
+"OPEN_PCROSS_EQ",OPEN_PCROSS_EQ;
+"OPEN_POSITIVE_MULTIPLES",OPEN_POSITIVE_MULTIPLES;
+"OPEN_SCALING",OPEN_SCALING;
+"OPEN_SEGMENT_1",OPEN_SEGMENT_1;
+"OPEN_SEGMENT_ALT",OPEN_SEGMENT_ALT;
+"OPEN_SEGMENT_LINEAR_IMAGE",OPEN_SEGMENT_LINEAR_IMAGE;
+"OPEN_SET_COCOUNTABLE_COORDINATES",OPEN_SET_COCOUNTABLE_COORDINATES;
+"OPEN_SET_COSMALL_COORDINATES",OPEN_SET_COSMALL_COORDINATES;
+"OPEN_SET_IRRATIONAL_COORDINATES",OPEN_SET_IRRATIONAL_COORDINATES;
+"OPEN_SET_RATIONAL_COORDINATES",OPEN_SET_RATIONAL_COORDINATES;
+"OPEN_SUBOPEN",OPEN_SUBOPEN;
+"OPEN_SUBSET",OPEN_SUBSET;
+"OPEN_SUBSET_INTERIOR",OPEN_SUBSET_INTERIOR;
+"OPEN_SUMS",OPEN_SUMS;
+"OPEN_SURJECTIVE_LINEAR_IMAGE",OPEN_SURJECTIVE_LINEAR_IMAGE;
+"OPEN_TRANSLATION",OPEN_TRANSLATION;
+"OPEN_TRANSLATION_EQ",OPEN_TRANSLATION_EQ;
+"OPEN_UNION",OPEN_UNION;
+"OPEN_UNIONS",OPEN_UNIONS;
+"OPEN_UNION_COMPACT_SUBSETS",OPEN_UNION_COMPACT_SUBSETS;
+"OPEN_UNIV",OPEN_UNIV;
+"OPERATIVE_1_LE",OPERATIVE_1_LE;
+"OPERATIVE_1_LT",OPERATIVE_1_LT;
+"OPERATIVE_APPROXIMABLE",OPERATIVE_APPROXIMABLE;
+"OPERATIVE_CONTENT",OPERATIVE_CONTENT;
+"OPERATIVE_DIVISION",OPERATIVE_DIVISION;
+"OPERATIVE_DIVISION_AND",OPERATIVE_DIVISION_AND;
+"OPERATIVE_EMPTY",OPERATIVE_EMPTY;
+"OPERATIVE_FUNCTION_ENDPOINT_DIFF",OPERATIVE_FUNCTION_ENDPOINT_DIFF;
+"OPERATIVE_INTEGRABLE",OPERATIVE_INTEGRABLE;
+"OPERATIVE_INTEGRAL",OPERATIVE_INTEGRAL;
+"OPERATIVE_LIFTED_SETVARIATION",OPERATIVE_LIFTED_SETVARIATION;
+"OPERATIVE_LIFTED_VECTOR_VARIATION",OPERATIVE_LIFTED_VECTOR_VARIATION;
+"OPERATIVE_REAL_FUNCTION_ENDPOINT_DIFF",OPERATIVE_REAL_FUNCTION_ENDPOINT_DIFF;
+"OPERATIVE_TAGGED_DIVISION",OPERATIVE_TAGGED_DIVISION;
+"OPERATIVE_TRIVIAL",OPERATIVE_TRIVIAL;
+"ORDINAL_CHAINED",ORDINAL_CHAINED;
+"ORDINAL_CHAINED_LEMMA",ORDINAL_CHAINED_LEMMA;
+"ORDINAL_SUC",ORDINAL_SUC;
+"ORDINAL_UNION",ORDINAL_UNION;
+"ORDINAL_UNION_LEMMA",ORDINAL_UNION_LEMMA;
+"ORDINAL_UP",ORDINAL_UP;
+"ORTHGOONAL_TRANSFORMATION_REFLECT_ALONG",ORTHGOONAL_TRANSFORMATION_REFLECT_ALONG;
+"ORTHOGONAL_0",ORTHOGONAL_0;
+"ORTHOGONAL_ANY_CLOSEST_POINT",ORTHOGONAL_ANY_CLOSEST_POINT;
+"ORTHOGONAL_BASIS",ORTHOGONAL_BASIS;
+"ORTHOGONAL_BASIS_BASIS",ORTHOGONAL_BASIS_BASIS;
+"ORTHOGONAL_BASIS_EXISTS",ORTHOGONAL_BASIS_EXISTS;
+"ORTHOGONAL_BASIS_SUBSPACE",ORTHOGONAL_BASIS_SUBSPACE;
+"ORTHOGONAL_CLAUSES",ORTHOGONAL_CLAUSES;
+"ORTHOGONAL_EXTENSION",ORTHOGONAL_EXTENSION;
+"ORTHOGONAL_EXTENSION_STRONG",ORTHOGONAL_EXTENSION_STRONG;
+"ORTHOGONAL_LINEAR_IMAGE_EQ",ORTHOGONAL_LINEAR_IMAGE_EQ;
+"ORTHOGONAL_LNEG",ORTHOGONAL_LNEG;
+"ORTHOGONAL_LVSUM",ORTHOGONAL_LVSUM;
+"ORTHOGONAL_MATRIX",ORTHOGONAL_MATRIX;
+"ORTHOGONAL_MATRIX_2",ORTHOGONAL_MATRIX_2;
+"ORTHOGONAL_MATRIX_2_ALT",ORTHOGONAL_MATRIX_2_ALT;
+"ORTHOGONAL_MATRIX_ALT",ORTHOGONAL_MATRIX_ALT;
+"ORTHOGONAL_MATRIX_EXISTS_BASIS",ORTHOGONAL_MATRIX_EXISTS_BASIS;
+"ORTHOGONAL_MATRIX_ID",ORTHOGONAL_MATRIX_ID;
+"ORTHOGONAL_MATRIX_INV",ORTHOGONAL_MATRIX_INV;
+"ORTHOGONAL_MATRIX_MATRIX",ORTHOGONAL_MATRIX_MATRIX;
+"ORTHOGONAL_MATRIX_MUL",ORTHOGONAL_MATRIX_MUL;
+"ORTHOGONAL_MATRIX_ORTHOGONAL_EIGENVECTORS",ORTHOGONAL_MATRIX_ORTHOGONAL_EIGENVECTORS;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS",ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_INDEXED",ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_INDEXED;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_PAIRWISE",ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_PAIRWISE;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_SPAN",ORTHOGONAL_MATRIX_ORTHONORMAL_COLUMNS_SPAN;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS",ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_INDEXED",ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_INDEXED;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_PAIRWISE",ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_PAIRWISE;
+"ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_SPAN",ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_SPAN;
+"ORTHOGONAL_MATRIX_TRANSFORMATION",ORTHOGONAL_MATRIX_TRANSFORMATION;
+"ORTHOGONAL_MATRIX_TRANSP",ORTHOGONAL_MATRIX_TRANSP;
+"ORTHOGONAL_MUL",ORTHOGONAL_MUL;
+"ORTHOGONAL_NULLSPACE_ROWSPACE",ORTHOGONAL_NULLSPACE_ROWSPACE;
+"ORTHOGONAL_REFL",ORTHOGONAL_REFL;
+"ORTHOGONAL_RNEG",ORTHOGONAL_RNEG;
+"ORTHOGONAL_ROTATION_OR_ROTOINVERSION",ORTHOGONAL_ROTATION_OR_ROTOINVERSION;
+"ORTHOGONAL_RVSUM",ORTHOGONAL_RVSUM;
+"ORTHOGONAL_SPANNINGSET_SUBSPACE",ORTHOGONAL_SPANNINGSET_SUBSPACE;
+"ORTHOGONAL_SUBSPACE_DECOMP",ORTHOGONAL_SUBSPACE_DECOMP;
+"ORTHOGONAL_SUBSPACE_DECOMP_EXISTS",ORTHOGONAL_SUBSPACE_DECOMP_EXISTS;
+"ORTHOGONAL_SUBSPACE_DECOMP_UNIQUE",ORTHOGONAL_SUBSPACE_DECOMP_UNIQUE;
+"ORTHOGONAL_SYM",ORTHOGONAL_SYM;
+"ORTHOGONAL_TO_ORTHOGONAL_2D",ORTHOGONAL_TO_ORTHOGONAL_2D;
+"ORTHOGONAL_TO_SPAN",ORTHOGONAL_TO_SPAN;
+"ORTHOGONAL_TO_SPANS_EQ",ORTHOGONAL_TO_SPANS_EQ;
+"ORTHOGONAL_TO_SPAN_EQ",ORTHOGONAL_TO_SPAN_EQ;
+"ORTHOGONAL_TO_SUBSPACE_EXISTS",ORTHOGONAL_TO_SUBSPACE_EXISTS;
+"ORTHOGONAL_TO_SUBSPACE_EXISTS_GEN",ORTHOGONAL_TO_SUBSPACE_EXISTS_GEN;
+"ORTHOGONAL_TO_VECTOR_EXISTS",ORTHOGONAL_TO_VECTOR_EXISTS;
+"ORTHOGONAL_TRANSFORMATION",ORTHOGONAL_TRANSFORMATION;
+"ORTHOGONAL_TRANSFORMATION_BETWEEN_ORTHOGONAL_SETS",ORTHOGONAL_TRANSFORMATION_BETWEEN_ORTHOGONAL_SETS;
+"ORTHOGONAL_TRANSFORMATION_COMPOSE",ORTHOGONAL_TRANSFORMATION_COMPOSE;
+"ORTHOGONAL_TRANSFORMATION_EXISTS",ORTHOGONAL_TRANSFORMATION_EXISTS;
+"ORTHOGONAL_TRANSFORMATION_EXISTS_1",ORTHOGONAL_TRANSFORMATION_EXISTS_1;
+"ORTHOGONAL_TRANSFORMATION_GENERATED_BY_REFLECTIONS",ORTHOGONAL_TRANSFORMATION_GENERATED_BY_REFLECTIONS;
+"ORTHOGONAL_TRANSFORMATION_I",ORTHOGONAL_TRANSFORMATION_I;
+"ORTHOGONAL_TRANSFORMATION_ID",ORTHOGONAL_TRANSFORMATION_ID;
+"ORTHOGONAL_TRANSFORMATION_INJECTIVE",ORTHOGONAL_TRANSFORMATION_INJECTIVE;
+"ORTHOGONAL_TRANSFORMATION_INTO_SUBSPACE",ORTHOGONAL_TRANSFORMATION_INTO_SUBSPACE;
+"ORTHOGONAL_TRANSFORMATION_INVERSE",ORTHOGONAL_TRANSFORMATION_INVERSE;
+"ORTHOGONAL_TRANSFORMATION_INVERSE_o",ORTHOGONAL_TRANSFORMATION_INVERSE_o;
+"ORTHOGONAL_TRANSFORMATION_ISOMETRY",ORTHOGONAL_TRANSFORMATION_ISOMETRY;
+"ORTHOGONAL_TRANSFORMATION_LINEAR",ORTHOGONAL_TRANSFORMATION_LINEAR;
+"ORTHOGONAL_TRANSFORMATION_LOWDIM_HORIZONTAL",ORTHOGONAL_TRANSFORMATION_LOWDIM_HORIZONTAL;
+"ORTHOGONAL_TRANSFORMATION_MATRIX",ORTHOGONAL_TRANSFORMATION_MATRIX;
+"ORTHOGONAL_TRANSFORMATION_ONTO_SUBSPACE",ORTHOGONAL_TRANSFORMATION_ONTO_SUBSPACE;
+"ORTHOGONAL_TRANSFORMATION_ORTHOGONAL_EIGENVECTORS",ORTHOGONAL_TRANSFORMATION_ORTHOGONAL_EIGENVECTORS;
+"ORTHOGONAL_TRANSFORMATION_SURJECTIVE",ORTHOGONAL_TRANSFORMATION_SURJECTIVE;
+"ORTHONORMAL_BASIS_EXPAND",ORTHONORMAL_BASIS_EXPAND;
+"ORTHONORMAL_BASIS_SUBSPACE",ORTHONORMAL_BASIS_SUBSPACE;
+"ORTHONORMAL_EXTENSION",ORTHONORMAL_EXTENSION;
+"OR_CLAUSES",OR_CLAUSES;
+"OR_DEF",OR_DEF;
+"OR_EXISTS_THM",OR_EXISTS_THM;
+"OUTER",OUTER;
+"OUTERMORPHISM_MBASIS",OUTERMORPHISM_MBASIS;
+"OUTERMORPHISM_MBASIS_EMPTY",OUTERMORPHISM_MBASIS_EMPTY;
+"OUTER_ACI",OUTER_ACI;
+"OUTER_ASSOC",OUTER_ASSOC;
+"OUTER_LADD",OUTER_LADD;
+"OUTER_LMUL",OUTER_LMUL;
+"OUTER_LNEG",OUTER_LNEG;
+"OUTER_LZERO",OUTER_LZERO;
+"OUTER_MBASIS",OUTER_MBASIS;
+"OUTER_MBASIS_LSCALAR",OUTER_MBASIS_LSCALAR;
+"OUTER_MBASIS_REFL",OUTER_MBASIS_REFL;
+"OUTER_MBASIS_RSCALAR",OUTER_MBASIS_RSCALAR;
+"OUTER_MBASIS_SING",OUTER_MBASIS_SING;
+"OUTER_MBASIS_SKEWSYM",OUTER_MBASIS_SKEWSYM;
+"OUTER_RADD",OUTER_RADD;
+"OUTER_RMUL",OUTER_RMUL;
+"OUTER_RNEG",OUTER_RNEG;
+"OUTER_RZERO",OUTER_RZERO;
+"OUTL",OUTL;
+"OUTR",OUTR;
+"OUTSIDE",OUTSIDE;
+"OUTSIDE_BOUNDED_NONEMPTY",OUTSIDE_BOUNDED_NONEMPTY;
+"OUTSIDE_COMPACT_IN_OPEN",OUTSIDE_COMPACT_IN_OPEN;
+"OUTSIDE_CONNECTED_COMPONENT_LE",OUTSIDE_CONNECTED_COMPONENT_LE;
+"OUTSIDE_CONNECTED_COMPONENT_LT",OUTSIDE_CONNECTED_COMPONENT_LT;
+"OUTSIDE_CONVEX",OUTSIDE_CONVEX;
+"OUTSIDE_EMPTY",OUTSIDE_EMPTY;
+"OUTSIDE_FRONTIER_EQ_COMPLEMENT_CLOSURE",OUTSIDE_FRONTIER_EQ_COMPLEMENT_CLOSURE;
+"OUTSIDE_FRONTIER_MISSES_CLOSURE",OUTSIDE_FRONTIER_MISSES_CLOSURE;
+"OUTSIDE_INSIDE",OUTSIDE_INSIDE;
+"OUTSIDE_IN_COMPONENTS",OUTSIDE_IN_COMPONENTS;
+"OUTSIDE_LINEAR_IMAGE",OUTSIDE_LINEAR_IMAGE;
+"OUTSIDE_MONO",OUTSIDE_MONO;
+"OUTSIDE_NO_OVERLAP",OUTSIDE_NO_OVERLAP;
+"OUTSIDE_SAME_COMPONENT",OUTSIDE_SAME_COMPONENT;
+"OUTSIDE_SUBSET_CONVEX",OUTSIDE_SUBSET_CONVEX;
+"OUTSIDE_TRANSLATION",OUTSIDE_TRANSLATION;
+"OUTSIDE_UNION_OUTSIDE_UNION",OUTSIDE_UNION_OUTSIDE_UNION;
+"PAIR",PAIR;
+"PAIRED_ETA_THM",PAIRED_ETA_THM;
+"PAIRED_EXT",PAIRED_EXT;
+"PAIRWISE",PAIRWISE;
+"PAIRWISE_DISJOINT_COMPONENTS",PAIRWISE_DISJOINT_COMPONENTS;
+"PAIRWISE_EMPTY",PAIRWISE_EMPTY;
+"PAIRWISE_IMAGE",PAIRWISE_IMAGE;
+"PAIRWISE_INSERT",PAIRWISE_INSERT;
+"PAIRWISE_MONO",PAIRWISE_MONO;
+"PAIRWISE_ORTHOGONAL_IMP_FINITE",PAIRWISE_ORTHOGONAL_IMP_FINITE;
+"PAIRWISE_ORTHOGONAL_INDEPENDENT",PAIRWISE_ORTHOGONAL_INDEPENDENT;
+"PAIRWISE_SING",PAIRWISE_SING;
+"PAIR_EQ",PAIR_EQ;
+"PAIR_EXISTS_THM",PAIR_EXISTS_THM;
+"PAIR_SURJECTIVE",PAIR_SURJECTIVE;
+"PARTIAL_DIVISION_EXTEND",PARTIAL_DIVISION_EXTEND;
+"PARTIAL_DIVISION_EXTEND_1",PARTIAL_DIVISION_EXTEND_1;
+"PARTIAL_DIVISION_EXTEND_INTERVAL",PARTIAL_DIVISION_EXTEND_INTERVAL;
+"PARTIAL_DIVISION_OF_TAGGED_DIVISION",PARTIAL_DIVISION_OF_TAGGED_DIVISION;
+"PARTIAL_SUMS_COMPONENT_LE_INFSUM",PARTIAL_SUMS_COMPONENT_LE_INFSUM;
+"PARTIAL_SUMS_DROP_LE_INFSUM",PARTIAL_SUMS_DROP_LE_INFSUM;
+"PASSOC_DEF",PASSOC_DEF;
+"PASTECART_ADD",PASTECART_ADD;
+"PASTECART_AS_ORTHOGONAL_SUM",PASTECART_AS_ORTHOGONAL_SUM;
+"PASTECART_CMUL",PASTECART_CMUL;
+"PASTECART_EQ",PASTECART_EQ;
+"PASTECART_EQ_VEC",PASTECART_EQ_VEC;
+"PASTECART_FST_SND",PASTECART_FST_SND;
+"PASTECART_INJ",PASTECART_INJ;
+"PASTECART_IN_INTERIOR_SUBTOPOLOGY",PASTECART_IN_INTERIOR_SUBTOPOLOGY;
+"PASTECART_IN_PCROSS",PASTECART_IN_PCROSS;
+"PASTECART_NEG",PASTECART_NEG;
+"PASTECART_SUB",PASTECART_SUB;
+"PASTECART_VEC",PASTECART_VEC;
+"PASTECART_VSUM",PASTECART_VSUM;
+"PASTING_LEMMA",PASTING_LEMMA;
+"PASTING_LEMMA_CLOSED",PASTING_LEMMA_CLOSED;
+"PASTING_LEMMA_EXISTS",PASTING_LEMMA_EXISTS;
+"PASTING_LEMMA_EXISTS_CLOSED",PASTING_LEMMA_EXISTS_CLOSED;
+"PATHFINISH_COMPOSE",PATHFINISH_COMPOSE;
+"PATHFINISH_IN_PATH_IMAGE",PATHFINISH_IN_PATH_IMAGE;
+"PATHFINISH_JOIN",PATHFINISH_JOIN;
+"PATHFINISH_LINEAR_IMAGE",PATHFINISH_LINEAR_IMAGE;
+"PATHFINISH_LINEPATH",PATHFINISH_LINEPATH;
+"PATHFINISH_REVERSEPATH",PATHFINISH_REVERSEPATH;
+"PATHFINISH_SHIFTPATH",PATHFINISH_SHIFTPATH;
+"PATHFINISH_SUBPATH",PATHFINISH_SUBPATH;
+"PATHFINISH_TRANSLATION",PATHFINISH_TRANSLATION;
+"PATHSTART_COMPOSE",PATHSTART_COMPOSE;
+"PATHSTART_IN_PATH_IMAGE",PATHSTART_IN_PATH_IMAGE;
+"PATHSTART_JOIN",PATHSTART_JOIN;
+"PATHSTART_LINEAR_IMAGE_EQ",PATHSTART_LINEAR_IMAGE_EQ;
+"PATHSTART_LINEPATH",PATHSTART_LINEPATH;
+"PATHSTART_REVERSEPATH",PATHSTART_REVERSEPATH;
+"PATHSTART_SHIFTPATH",PATHSTART_SHIFTPATH;
+"PATHSTART_SUBPATH",PATHSTART_SUBPATH;
+"PATHSTART_TRANSLATION",PATHSTART_TRANSLATION;
+"PATH_ASSOC",PATH_ASSOC;
+"PATH_COMPONENT",PATH_COMPONENT;
+"PATH_COMPONENT_DISJOINT",PATH_COMPONENT_DISJOINT;
+"PATH_COMPONENT_EMPTY",PATH_COMPONENT_EMPTY;
+"PATH_COMPONENT_EQ",PATH_COMPONENT_EQ;
+"PATH_COMPONENT_EQ_CONNECTED_COMPONENT",PATH_COMPONENT_EQ_CONNECTED_COMPONENT;
+"PATH_COMPONENT_EQ_EMPTY",PATH_COMPONENT_EQ_EMPTY;
+"PATH_COMPONENT_EQ_EQ",PATH_COMPONENT_EQ_EQ;
+"PATH_COMPONENT_IMP_HOMOTOPIC_POINTS",PATH_COMPONENT_IMP_HOMOTOPIC_POINTS;
+"PATH_COMPONENT_IN",PATH_COMPONENT_IN;
+"PATH_COMPONENT_LINEAR_IMAGE",PATH_COMPONENT_LINEAR_IMAGE;
+"PATH_COMPONENT_MAXIMAL",PATH_COMPONENT_MAXIMAL;
+"PATH_COMPONENT_MONO",PATH_COMPONENT_MONO;
+"PATH_COMPONENT_OF_SUBSET",PATH_COMPONENT_OF_SUBSET;
+"PATH_COMPONENT_PATH_COMPONENT",PATH_COMPONENT_PATH_COMPONENT;
+"PATH_COMPONENT_PATH_IMAGE_PATHSTART",PATH_COMPONENT_PATH_IMAGE_PATHSTART;
+"PATH_COMPONENT_REFL",PATH_COMPONENT_REFL;
+"PATH_COMPONENT_REFL_EQ",PATH_COMPONENT_REFL_EQ;
+"PATH_COMPONENT_SET",PATH_COMPONENT_SET;
+"PATH_COMPONENT_SUBSET",PATH_COMPONENT_SUBSET;
+"PATH_COMPONENT_SUBSET_CONNECTED_COMPONENT",PATH_COMPONENT_SUBSET_CONNECTED_COMPONENT;
+"PATH_COMPONENT_SYM",PATH_COMPONENT_SYM;
+"PATH_COMPONENT_SYM_EQ",PATH_COMPONENT_SYM_EQ;
+"PATH_COMPONENT_TRANS",PATH_COMPONENT_TRANS;
+"PATH_COMPONENT_TRANSLATION",PATH_COMPONENT_TRANSLATION;
+"PATH_COMPONENT_UNIV",PATH_COMPONENT_UNIV;
+"PATH_COMPOSE_JOIN",PATH_COMPOSE_JOIN;
+"PATH_COMPOSE_REVERSEPATH",PATH_COMPOSE_REVERSEPATH;
+"PATH_CONNECTED_ANNULUS",PATH_CONNECTED_ANNULUS;
+"PATH_CONNECTED_ARCWISE",PATH_CONNECTED_ARCWISE;
+"PATH_CONNECTED_ARC_COMPLEMENT",PATH_CONNECTED_ARC_COMPLEMENT;
+"PATH_CONNECTED_COMPLEMENT_ABSOLUTE_RETRACT",PATH_CONNECTED_COMPLEMENT_ABSOLUTE_RETRACT;
+"PATH_CONNECTED_COMPLEMENT_BOUNDED_CONVEX",PATH_CONNECTED_COMPLEMENT_BOUNDED_CONVEX;
+"PATH_CONNECTED_COMPLEMENT_CARD_LT",PATH_CONNECTED_COMPLEMENT_CARD_LT;
+"PATH_CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT",PATH_CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT;
+"PATH_CONNECTED_COMPONENT_SET",PATH_CONNECTED_COMPONENT_SET;
+"PATH_CONNECTED_CONTINUOUS_IMAGE",PATH_CONNECTED_CONTINUOUS_IMAGE;
+"PATH_CONNECTED_CONVEX_DIFF_CARD_LT",PATH_CONNECTED_CONVEX_DIFF_CARD_LT;
+"PATH_CONNECTED_DIFF_BALL",PATH_CONNECTED_DIFF_BALL;
+"PATH_CONNECTED_EMPTY",PATH_CONNECTED_EMPTY;
+"PATH_CONNECTED_EQ_CONNECTED",PATH_CONNECTED_EQ_CONNECTED;
+"PATH_CONNECTED_EQ_CONNECTED_LPC",PATH_CONNECTED_EQ_CONNECTED_LPC;
+"PATH_CONNECTED_EQ_HOMOTOPIC_POINTS",PATH_CONNECTED_EQ_HOMOTOPIC_POINTS;
+"PATH_CONNECTED_IFF_PATH_COMPONENT",PATH_CONNECTED_IFF_PATH_COMPONENT;
+"PATH_CONNECTED_IMP_CONNECTED",PATH_CONNECTED_IMP_CONNECTED;
+"PATH_CONNECTED_INTERVAL",PATH_CONNECTED_INTERVAL;
+"PATH_CONNECTED_LINEAR_IMAGE",PATH_CONNECTED_LINEAR_IMAGE;
+"PATH_CONNECTED_LINEAR_IMAGE_EQ",PATH_CONNECTED_LINEAR_IMAGE_EQ;
+"PATH_CONNECTED_LINEPATH",PATH_CONNECTED_LINEPATH;
+"PATH_CONNECTED_NEGATIONS",PATH_CONNECTED_NEGATIONS;
+"PATH_CONNECTED_OPEN_DELETE",PATH_CONNECTED_OPEN_DELETE;
+"PATH_CONNECTED_OPEN_DIFF_CARD_LT",PATH_CONNECTED_OPEN_DIFF_CARD_LT;
+"PATH_CONNECTED_OPEN_DIFF_COUNTABLE",PATH_CONNECTED_OPEN_DIFF_COUNTABLE;
+"PATH_CONNECTED_OPEN_IN_DIFF_CARD_LT",PATH_CONNECTED_OPEN_IN_DIFF_CARD_LT;
+"PATH_CONNECTED_PATH_COMPONENT",PATH_CONNECTED_PATH_COMPONENT;
+"PATH_CONNECTED_PATH_IMAGE",PATH_CONNECTED_PATH_IMAGE;
+"PATH_CONNECTED_PCROSS",PATH_CONNECTED_PCROSS;
+"PATH_CONNECTED_PCROSS_EQ",PATH_CONNECTED_PCROSS_EQ;
+"PATH_CONNECTED_PUNCTURED_BALL",PATH_CONNECTED_PUNCTURED_BALL;
+"PATH_CONNECTED_PUNCTURED_UNIVERSE",PATH_CONNECTED_PUNCTURED_UNIVERSE;
+"PATH_CONNECTED_SCALING",PATH_CONNECTED_SCALING;
+"PATH_CONNECTED_SEGMENT",PATH_CONNECTED_SEGMENT;
+"PATH_CONNECTED_SEMIOPEN_SEGMENT",PATH_CONNECTED_SEMIOPEN_SEGMENT;
+"PATH_CONNECTED_SING",PATH_CONNECTED_SING;
+"PATH_CONNECTED_SPHERE",PATH_CONNECTED_SPHERE;
+"PATH_CONNECTED_SPHERE_EQ",PATH_CONNECTED_SPHERE_EQ;
+"PATH_CONNECTED_SUMS",PATH_CONNECTED_SUMS;
+"PATH_CONNECTED_TRANSLATION",PATH_CONNECTED_TRANSLATION;
+"PATH_CONNECTED_TRANSLATION_EQ",PATH_CONNECTED_TRANSLATION_EQ;
+"PATH_CONNECTED_UNION",PATH_CONNECTED_UNION;
+"PATH_CONNECTED_UNIV",PATH_CONNECTED_UNIV;
+"PATH_CONTAINS_ARC",PATH_CONTAINS_ARC;
+"PATH_CONTINUOUS_IMAGE",PATH_CONTINUOUS_IMAGE;
+"PATH_EQ",PATH_EQ;
+"PATH_IMAGE_COMPOSE",PATH_IMAGE_COMPOSE;
+"PATH_IMAGE_JOIN",PATH_IMAGE_JOIN;
+"PATH_IMAGE_JOIN_SUBSET",PATH_IMAGE_JOIN_SUBSET;
+"PATH_IMAGE_LINEAR_IMAGE",PATH_IMAGE_LINEAR_IMAGE;
+"PATH_IMAGE_LINEPATH",PATH_IMAGE_LINEPATH;
+"PATH_IMAGE_NONEMPTY",PATH_IMAGE_NONEMPTY;
+"PATH_IMAGE_REVERSEPATH",PATH_IMAGE_REVERSEPATH;
+"PATH_IMAGE_SHIFTPATH",PATH_IMAGE_SHIFTPATH;
+"PATH_IMAGE_SUBPATH",PATH_IMAGE_SUBPATH;
+"PATH_IMAGE_SUBPATH_GEN",PATH_IMAGE_SUBPATH_GEN;
+"PATH_IMAGE_SUBPATH_SUBSET",PATH_IMAGE_SUBPATH_SUBSET;
+"PATH_IMAGE_SYM",PATH_IMAGE_SYM;
+"PATH_IMAGE_TRANSLATION",PATH_IMAGE_TRANSLATION;
+"PATH_JOIN",PATH_JOIN;
+"PATH_JOIN_EQ",PATH_JOIN_EQ;
+"PATH_JOIN_IMP",PATH_JOIN_IMP;
+"PATH_JOIN_PATH_ENDS",PATH_JOIN_PATH_ENDS;
+"PATH_LENGTH_DIFFERENTIABLE",PATH_LENGTH_DIFFERENTIABLE;
+"PATH_LENGTH_JOIN",PATH_LENGTH_JOIN;
+"PATH_LENGTH_REVERSEPATH",PATH_LENGTH_REVERSEPATH;
+"PATH_LINEAR_IMAGE_EQ",PATH_LINEAR_IMAGE_EQ;
+"PATH_LINEPATH",PATH_LINEPATH;
+"PATH_REVERSEPATH",PATH_REVERSEPATH;
+"PATH_SHIFTPATH",PATH_SHIFTPATH;
+"PATH_SUBPATH",PATH_SUBPATH;
+"PATH_SYM",PATH_SYM;
+"PATH_TRANSLATION_EQ",PATH_TRANSLATION_EQ;
+"PCROSS",PCROSS;
+"PCROSS_AS_ORTHOGONAL_SUM",PCROSS_AS_ORTHOGONAL_SUM;
+"PCROSS_EMPTY",PCROSS_EMPTY;
+"PCROSS_EQ",PCROSS_EQ;
+"PCROSS_EQ_EMPTY",PCROSS_EQ_EMPTY;
+"PCROSS_INTER",PCROSS_INTER;
+"PCROSS_INTERVAL",PCROSS_INTERVAL;
+"PCROSS_MONO",PCROSS_MONO;
+"PCROSS_UNION",PCROSS_UNION;
+"PCROSS_UNIONS",PCROSS_UNIONS;
+"PCROSS_UNIONS_UNIONS",PCROSS_UNIONS_UNIONS;
+"PERMUTATION",PERMUTATION;
+"PERMUTATION_BIJECTIVE",PERMUTATION_BIJECTIVE;
+"PERMUTATION_COMPOSE",PERMUTATION_COMPOSE;
+"PERMUTATION_COMPOSE_EQ",PERMUTATION_COMPOSE_EQ;
+"PERMUTATION_COMPOSE_SWAP",PERMUTATION_COMPOSE_SWAP;
+"PERMUTATION_FINITE_SUPPORT",PERMUTATION_FINITE_SUPPORT;
+"PERMUTATION_I",PERMUTATION_I;
+"PERMUTATION_INVERSE",PERMUTATION_INVERSE;
+"PERMUTATION_INVERSE_COMPOSE",PERMUTATION_INVERSE_COMPOSE;
+"PERMUTATION_INVERSE_WORKS",PERMUTATION_INVERSE_WORKS;
+"PERMUTATION_LEMMA",PERMUTATION_LEMMA;
+"PERMUTATION_PERMUTES",PERMUTATION_PERMUTES;
+"PERMUTATION_SWAP",PERMUTATION_SWAP;
+"PERMUTES_COMPOSE",PERMUTES_COMPOSE;
+"PERMUTES_EMPTY",PERMUTES_EMPTY;
+"PERMUTES_FINITE_INJECTIVE",PERMUTES_FINITE_INJECTIVE;
+"PERMUTES_FINITE_SURJECTIVE",PERMUTES_FINITE_SURJECTIVE;
+"PERMUTES_I",PERMUTES_I;
+"PERMUTES_IMAGE",PERMUTES_IMAGE;
+"PERMUTES_INDUCT",PERMUTES_INDUCT;
+"PERMUTES_INJECTIVE",PERMUTES_INJECTIVE;
+"PERMUTES_INSERT",PERMUTES_INSERT;
+"PERMUTES_INSERT_LEMMA",PERMUTES_INSERT_LEMMA;
+"PERMUTES_INVERSE",PERMUTES_INVERSE;
+"PERMUTES_INVERSES",PERMUTES_INVERSES;
+"PERMUTES_INVERSES_o",PERMUTES_INVERSES_o;
+"PERMUTES_INVERSE_EQ",PERMUTES_INVERSE_EQ;
+"PERMUTES_INVERSE_INVERSE",PERMUTES_INVERSE_INVERSE;
+"PERMUTES_IN_IMAGE",PERMUTES_IN_IMAGE;
+"PERMUTES_IN_NUMSEG",PERMUTES_IN_NUMSEG;
+"PERMUTES_NUMSET_GE",PERMUTES_NUMSET_GE;
+"PERMUTES_NUMSET_LE",PERMUTES_NUMSET_LE;
+"PERMUTES_SING",PERMUTES_SING;
+"PERMUTES_SUBSET",PERMUTES_SUBSET;
+"PERMUTES_SUPERSET",PERMUTES_SUPERSET;
+"PERMUTES_SURJECTIVE",PERMUTES_SURJECTIVE;
+"PERMUTES_SWAP",PERMUTES_SWAP;
+"PERMUTES_UNIV",PERMUTES_UNIV;
+"POINTWISE_ANTISYM",POINTWISE_ANTISYM;
+"POINTWISE_MAXIMAL",POINTWISE_MAXIMAL;
+"POINTWISE_MINIMAL",POINTWISE_MINIMAL;
+"POLYHEDRON_AFFINE_HULL",POLYHEDRON_AFFINE_HULL;
+"POLYHEDRON_AS_CONE_PLUS_CONV",POLYHEDRON_AS_CONE_PLUS_CONV;
+"POLYHEDRON_CONVEX_CONE_HULL",POLYHEDRON_CONVEX_CONE_HULL;
+"POLYHEDRON_CONVEX_HULL",POLYHEDRON_CONVEX_HULL;
+"POLYHEDRON_EMPTY",POLYHEDRON_EMPTY;
+"POLYHEDRON_EQ_FINITE_EXPOSED_FACES",POLYHEDRON_EQ_FINITE_EXPOSED_FACES;
+"POLYHEDRON_EQ_FINITE_FACES",POLYHEDRON_EQ_FINITE_FACES;
+"POLYHEDRON_HALFSPACE_GE",POLYHEDRON_HALFSPACE_GE;
+"POLYHEDRON_HALFSPACE_LE",POLYHEDRON_HALFSPACE_LE;
+"POLYHEDRON_HYPERPLANE",POLYHEDRON_HYPERPLANE;
+"POLYHEDRON_IMP_CLOSED",POLYHEDRON_IMP_CLOSED;
+"POLYHEDRON_IMP_CONVEX",POLYHEDRON_IMP_CONVEX;
+"POLYHEDRON_INTER",POLYHEDRON_INTER;
+"POLYHEDRON_INTERS",POLYHEDRON_INTERS;
+"POLYHEDRON_INTERVAL",POLYHEDRON_INTERVAL;
+"POLYHEDRON_INTER_AFFINE",POLYHEDRON_INTER_AFFINE;
+"POLYHEDRON_INTER_AFFINE_MINIMAL",POLYHEDRON_INTER_AFFINE_MINIMAL;
+"POLYHEDRON_INTER_AFFINE_PARALLEL",POLYHEDRON_INTER_AFFINE_PARALLEL;
+"POLYHEDRON_INTER_AFFINE_PARALLEL_MINIMAL",POLYHEDRON_INTER_AFFINE_PARALLEL_MINIMAL;
+"POLYHEDRON_INTER_POLYTOPE",POLYHEDRON_INTER_POLYTOPE;
+"POLYHEDRON_LINEAR_IMAGE",POLYHEDRON_LINEAR_IMAGE;
+"POLYHEDRON_LINEAR_IMAGE_EQ",POLYHEDRON_LINEAR_IMAGE_EQ;
+"POLYHEDRON_NEGATIONS",POLYHEDRON_NEGATIONS;
+"POLYHEDRON_POLYTOPE_SUMS",POLYHEDRON_POLYTOPE_SUMS;
+"POLYHEDRON_POSITIVE_ORTHANT",POLYHEDRON_POSITIVE_ORTHANT;
+"POLYHEDRON_RIDGE_TWO_FACETS",POLYHEDRON_RIDGE_TWO_FACETS;
+"POLYHEDRON_SUMS",POLYHEDRON_SUMS;
+"POLYHEDRON_TRANSLATION_EQ",POLYHEDRON_TRANSLATION_EQ;
+"POLYHEDRON_UNIV",POLYHEDRON_UNIV;
+"POLYTOPE_CONVEX_HULL",POLYTOPE_CONVEX_HULL;
+"POLYTOPE_EMPTY",POLYTOPE_EMPTY;
+"POLYTOPE_EQ_BOUNDED_POLYHEDRON",POLYTOPE_EQ_BOUNDED_POLYHEDRON;
+"POLYTOPE_FACET_EXISTS",POLYTOPE_FACET_EXISTS;
+"POLYTOPE_FACET_LOWER_BOUND",POLYTOPE_FACET_LOWER_BOUND;
+"POLYTOPE_IMP_BOUNDED",POLYTOPE_IMP_BOUNDED;
+"POLYTOPE_IMP_CLOSED",POLYTOPE_IMP_CLOSED;
+"POLYTOPE_IMP_COMPACT",POLYTOPE_IMP_COMPACT;
+"POLYTOPE_IMP_CONVEX",POLYTOPE_IMP_CONVEX;
+"POLYTOPE_IMP_POLYHEDRON",POLYTOPE_IMP_POLYHEDRON;
+"POLYTOPE_INTER",POLYTOPE_INTER;
+"POLYTOPE_INTERVAL",POLYTOPE_INTERVAL;
+"POLYTOPE_INTER_POLYHEDRON",POLYTOPE_INTER_POLYHEDRON;
+"POLYTOPE_LINEAR_IMAGE",POLYTOPE_LINEAR_IMAGE;
+"POLYTOPE_LINEAR_IMAGE_EQ",POLYTOPE_LINEAR_IMAGE_EQ;
+"POLYTOPE_NEGATIONS",POLYTOPE_NEGATIONS;
+"POLYTOPE_PCROSS",POLYTOPE_PCROSS;
+"POLYTOPE_PCROSS_EQ",POLYTOPE_PCROSS_EQ;
+"POLYTOPE_SCALING",POLYTOPE_SCALING;
+"POLYTOPE_SCALING_EQ",POLYTOPE_SCALING_EQ;
+"POLYTOPE_SING",POLYTOPE_SING;
+"POLYTOPE_SUMS",POLYTOPE_SUMS;
+"POLYTOPE_TRANSLATION_EQ",POLYTOPE_TRANSLATION_EQ;
+"POLYTOPE_UNION_CONVEX_HULL_FACETS",POLYTOPE_UNION_CONVEX_HULL_FACETS;
+"POLYTOPE_VERTEX_LOWER_BOUND",POLYTOPE_VERTEX_LOWER_BOUND;
+"POSET_ANTISYM",POSET_ANTISYM;
+"POSET_FLEQ",POSET_FLEQ;
+"POSET_REFL",POSET_REFL;
+"POSET_RESTRICTED_SUBSET",POSET_RESTRICTED_SUBSET;
+"POSET_TRANS",POSET_TRANS;
+"POWERSET_CLAUSES",POWERSET_CLAUSES;
+"POW_2_SQRT",POW_2_SQRT;
+"POW_2_SQRT_ABS",POW_2_SQRT_ABS;
+"PRE",PRE;
+"PRESERVES_LEBESGUE_MEASURABLE_IMP_PRESERVES_NEGLIGIBLE",PRESERVES_LEBESGUE_MEASURABLE_IMP_PRESERVES_NEGLIGIBLE;
+"PRESERVES_NORM_INJECTIVE",PRESERVES_NORM_INJECTIVE;
+"PRESERVES_NORM_PRESERVES_DOT",PRESERVES_NORM_PRESERVES_DOT;
+"PRE_ELIM_THM",PRE_ELIM_THM;
+"PRE_ELIM_THM'",PRE_ELIM_THM';
+"PRODUCT_1",PRODUCT_1;
+"PRODUCT_2",PRODUCT_2;
+"PRODUCT_3",PRODUCT_3;
+"PRODUCT_4",PRODUCT_4;
+"PRODUCT_ABS",PRODUCT_ABS;
+"PRODUCT_ADD_SPLIT",PRODUCT_ADD_SPLIT;
+"PRODUCT_ASSOCIATIVE",PRODUCT_ASSOCIATIVE;
+"PRODUCT_CLAUSES",PRODUCT_CLAUSES;
+"PRODUCT_CLAUSES_LEFT",PRODUCT_CLAUSES_LEFT;
+"PRODUCT_CLAUSES_NUMSEG",PRODUCT_CLAUSES_NUMSEG;
+"PRODUCT_CLAUSES_RIGHT",PRODUCT_CLAUSES_RIGHT;
+"PRODUCT_CLOSED",PRODUCT_CLOSED;
+"PRODUCT_CONST",PRODUCT_CONST;
+"PRODUCT_CONST_NUMSEG",PRODUCT_CONST_NUMSEG;
+"PRODUCT_CONST_NUMSEG_1",PRODUCT_CONST_NUMSEG_1;
+"PRODUCT_DIV",PRODUCT_DIV;
+"PRODUCT_DIV_NUMSEG",PRODUCT_DIV_NUMSEG;
+"PRODUCT_EQ",PRODUCT_EQ;
+"PRODUCT_EQ_0",PRODUCT_EQ_0;
+"PRODUCT_EQ_0_NUMSEG",PRODUCT_EQ_0_NUMSEG;
+"PRODUCT_EQ_1",PRODUCT_EQ_1;
+"PRODUCT_EQ_1_NUMSEG",PRODUCT_EQ_1_NUMSEG;
+"PRODUCT_EQ_NUMSEG",PRODUCT_EQ_NUMSEG;
+"PRODUCT_IMAGE",PRODUCT_IMAGE;
+"PRODUCT_INV",PRODUCT_INV;
+"PRODUCT_LADD",PRODUCT_LADD;
+"PRODUCT_LE",PRODUCT_LE;
+"PRODUCT_LE_1",PRODUCT_LE_1;
+"PRODUCT_LE_NUMSEG",PRODUCT_LE_NUMSEG;
+"PRODUCT_LMUL",PRODUCT_LMUL;
+"PRODUCT_LNEG",PRODUCT_LNEG;
+"PRODUCT_LZERO",PRODUCT_LZERO;
+"PRODUCT_MBASIS",PRODUCT_MBASIS;
+"PRODUCT_MBASIS_SING",PRODUCT_MBASIS_SING;
+"PRODUCT_MUL",PRODUCT_MUL;
+"PRODUCT_MUL_NUMSEG",PRODUCT_MUL_NUMSEG;
+"PRODUCT_NEG",PRODUCT_NEG;
+"PRODUCT_NEG_NUMSEG",PRODUCT_NEG_NUMSEG;
+"PRODUCT_NEG_NUMSEG_1",PRODUCT_NEG_NUMSEG_1;
+"PRODUCT_OFFSET",PRODUCT_OFFSET;
+"PRODUCT_ONE",PRODUCT_ONE;
+"PRODUCT_PERMUTE",PRODUCT_PERMUTE;
+"PRODUCT_PERMUTE_NUMSEG",PRODUCT_PERMUTE_NUMSEG;
+"PRODUCT_POS_LE",PRODUCT_POS_LE;
+"PRODUCT_POS_LE_NUMSEG",PRODUCT_POS_LE_NUMSEG;
+"PRODUCT_POS_LT",PRODUCT_POS_LT;
+"PRODUCT_POS_LT_NUMSEG",PRODUCT_POS_LT_NUMSEG;
+"PRODUCT_RADD",PRODUCT_RADD;
+"PRODUCT_RMUL",PRODUCT_RMUL;
+"PRODUCT_RNEG",PRODUCT_RNEG;
+"PRODUCT_RZERO",PRODUCT_RZERO;
+"PRODUCT_SING",PRODUCT_SING;
+"PRODUCT_SING_NUMSEG",PRODUCT_SING_NUMSEG;
+"PRODUCT_UNION",PRODUCT_UNION;
+"PROPERTY_EMPTY_INTERVAL",PROPERTY_EMPTY_INTERVAL;
+"PROPER_MAP",PROPER_MAP;
+"PROPER_MAP_FROM_COMPACT",PROPER_MAP_FROM_COMPACT;
+"PSUBSET",PSUBSET;
+"PSUBSET_ALT",PSUBSET_ALT;
+"PSUBSET_INSERT_SUBSET",PSUBSET_INSERT_SUBSET;
+"PSUBSET_IRREFL",PSUBSET_IRREFL;
+"PSUBSET_MEMBER",PSUBSET_MEMBER;
+"PSUBSET_SUBSET_TRANS",PSUBSET_SUBSET_TRANS;
+"PSUBSET_TRANS",PSUBSET_TRANS;
+"PSUBSET_UNIV",PSUBSET_UNIV;
+"P_HULL",P_HULL;
+"Product_DEF",Product_DEF;
+"QUANTIFY_SURJECTION_HIGHER_THM",QUANTIFY_SURJECTION_HIGHER_THM;
+"QUANTIFY_SURJECTION_THM",QUANTIFY_SURJECTION_THM;
+"QUOTIENT_MAP_OPEN_CLOSED",QUOTIENT_MAP_OPEN_CLOSED;
+"RADON",RADON;
+"RADON_EX_LEMMA",RADON_EX_LEMMA;
+"RADON_PARTITION",RADON_PARTITION;
+"RADON_S_LEMMA",RADON_S_LEMMA;
+"RADON_V_LEMMA",RADON_V_LEMMA;
+"RANK_0",RANK_0;
+"RANK_BOUND",RANK_BOUND;
+"RANK_DIM_IM",RANK_DIM_IM;
+"RANK_EQ_0",RANK_EQ_0;
+"RANK_GRAM",RANK_GRAM;
+"RANK_I",RANK_I;
+"RANK_MUL_LE_LEFT",RANK_MUL_LE_LEFT;
+"RANK_MUL_LE_RIGHT",RANK_MUL_LE_RIGHT;
+"RANK_NULLSPACE",RANK_NULLSPACE;
+"RANK_ROW",RANK_ROW;
+"RANK_SYLVESTER",RANK_SYLVESTER;
+"RANK_TRANSP",RANK_TRANSP;
+"RANK_TRIANGLE",RANK_TRIANGLE;
+"RATIONAL_ABS",RATIONAL_ABS;
+"RATIONAL_ADD",RATIONAL_ADD;
+"RATIONAL_ALT",RATIONAL_ALT;
+"RATIONAL_APPROXIMATION",RATIONAL_APPROXIMATION;
+"RATIONAL_APPROXIMATION_STRADDLE",RATIONAL_APPROXIMATION_STRADDLE;
+"RATIONAL_BETWEEN",RATIONAL_BETWEEN;
+"RATIONAL_CLOSED",RATIONAL_CLOSED;
+"RATIONAL_DIV",RATIONAL_DIV;
+"RATIONAL_INTEGER",RATIONAL_INTEGER;
+"RATIONAL_INV",RATIONAL_INV;
+"RATIONAL_INV_EQ",RATIONAL_INV_EQ;
+"RATIONAL_MUL",RATIONAL_MUL;
+"RATIONAL_NEG",RATIONAL_NEG;
+"RATIONAL_NEG_EQ",RATIONAL_NEG_EQ;
+"RATIONAL_NUM",RATIONAL_NUM;
+"RATIONAL_POW",RATIONAL_POW;
+"RATIONAL_SUB",RATIONAL_SUB;
+"RAT_LEMMA1",RAT_LEMMA1;
+"RAT_LEMMA2",RAT_LEMMA2;
+"RAT_LEMMA3",RAT_LEMMA3;
+"RAT_LEMMA4",RAT_LEMMA4;
+"RAT_LEMMA5",RAT_LEMMA5;
+"RAY_TO_FRONTIER",RAY_TO_FRONTIER;
+"RAY_TO_RELATIVE_FRONTIER",RAY_TO_RELATIVE_FRONTIER;
+"REAL_ABS_0",REAL_ABS_0;
+"REAL_ABS_1",REAL_ABS_1;
+"REAL_ABS_ABS",REAL_ABS_ABS;
+"REAL_ABS_BETWEEN",REAL_ABS_BETWEEN;
+"REAL_ABS_BETWEEN1",REAL_ABS_BETWEEN1;
+"REAL_ABS_BETWEEN2",REAL_ABS_BETWEEN2;
+"REAL_ABS_BOUND",REAL_ABS_BOUND;
+"REAL_ABS_BOUNDS",REAL_ABS_BOUNDS;
+"REAL_ABS_CASES",REAL_ABS_CASES;
+"REAL_ABS_CIRCLE",REAL_ABS_CIRCLE;
+"REAL_ABS_DIV",REAL_ABS_DIV;
+"REAL_ABS_INFNORM",REAL_ABS_INFNORM;
+"REAL_ABS_INF_LE",REAL_ABS_INF_LE;
+"REAL_ABS_INTEGER_LEMMA",REAL_ABS_INTEGER_LEMMA;
+"REAL_ABS_INV",REAL_ABS_INV;
+"REAL_ABS_LE",REAL_ABS_LE;
+"REAL_ABS_MUL",REAL_ABS_MUL;
+"REAL_ABS_NEG",REAL_ABS_NEG;
+"REAL_ABS_NORM",REAL_ABS_NORM;
+"REAL_ABS_NUM",REAL_ABS_NUM;
+"REAL_ABS_NZ",REAL_ABS_NZ;
+"REAL_ABS_POS",REAL_ABS_POS;
+"REAL_ABS_POW",REAL_ABS_POW;
+"REAL_ABS_REFL",REAL_ABS_REFL;
+"REAL_ABS_SGN",REAL_ABS_SGN;
+"REAL_ABS_SIGN",REAL_ABS_SIGN;
+"REAL_ABS_SIGN2",REAL_ABS_SIGN2;
+"REAL_ABS_STILLNZ",REAL_ABS_STILLNZ;
+"REAL_ABS_SUB",REAL_ABS_SUB;
+"REAL_ABS_SUB_ABS",REAL_ABS_SUB_ABS;
+"REAL_ABS_SUB_INFNORM",REAL_ABS_SUB_INFNORM;
+"REAL_ABS_SUB_NORM",REAL_ABS_SUB_NORM;
+"REAL_ABS_SUP_LE",REAL_ABS_SUP_LE;
+"REAL_ABS_TRIANGLE",REAL_ABS_TRIANGLE;
+"REAL_ABS_TRIANGLE_LE",REAL_ABS_TRIANGLE_LE;
+"REAL_ABS_TRIANGLE_LT",REAL_ABS_TRIANGLE_LT;
+"REAL_ABS_ZERO",REAL_ABS_ZERO;
+"REAL_ADD2_SUB2",REAL_ADD2_SUB2;
+"REAL_ADD_AC",REAL_ADD_AC;
+"REAL_ADD_ASSOC",REAL_ADD_ASSOC;
+"REAL_ADD_LDISTRIB",REAL_ADD_LDISTRIB;
+"REAL_ADD_LID",REAL_ADD_LID;
+"REAL_ADD_LINV",REAL_ADD_LINV;
+"REAL_ADD_RDISTRIB",REAL_ADD_RDISTRIB;
+"REAL_ADD_RID",REAL_ADD_RID;
+"REAL_ADD_RINV",REAL_ADD_RINV;
+"REAL_ADD_SUB",REAL_ADD_SUB;
+"REAL_ADD_SUB2",REAL_ADD_SUB2;
+"REAL_ADD_SYM",REAL_ADD_SYM;
+"REAL_AFFINITY_EQ",REAL_AFFINITY_EQ;
+"REAL_AFFINITY_LE",REAL_AFFINITY_LE;
+"REAL_AFFINITY_LT",REAL_AFFINITY_LT;
+"REAL_ARCH",REAL_ARCH;
+"REAL_ARCH_INV",REAL_ARCH_INV;
+"REAL_ARCH_LT",REAL_ARCH_LT;
+"REAL_ARCH_POW",REAL_ARCH_POW;
+"REAL_ARCH_POW2",REAL_ARCH_POW2;
+"REAL_ARCH_POW_INV",REAL_ARCH_POW_INV;
+"REAL_ARCH_RDIV_EQ_0",REAL_ARCH_RDIV_EQ_0;
+"REAL_ARCH_SIMPLE",REAL_ARCH_SIMPLE;
+"REAL_BOUNDS_LE",REAL_BOUNDS_LE;
+"REAL_BOUNDS_LT",REAL_BOUNDS_LT;
+"REAL_CARD_INTSEG_INT",REAL_CARD_INTSEG_INT;
+"REAL_COMPLETE",REAL_COMPLETE;
+"REAL_COMPLETE_SOMEPOS",REAL_COMPLETE_SOMEPOS;
+"REAL_CONVEX_BOUND2_LT",REAL_CONVEX_BOUND2_LT;
+"REAL_CONVEX_BOUND_LE",REAL_CONVEX_BOUND_LE;
+"REAL_CONVEX_BOUND_LT",REAL_CONVEX_BOUND_LT;
+"REAL_DIFFSQ",REAL_DIFFSQ;
+"REAL_DIV_1",REAL_DIV_1;
+"REAL_DIV_EQ_0",REAL_DIV_EQ_0;
+"REAL_DIV_LMUL",REAL_DIV_LMUL;
+"REAL_DIV_POW2",REAL_DIV_POW2;
+"REAL_DIV_POW2_ALT",REAL_DIV_POW2_ALT;
+"REAL_DIV_REFL",REAL_DIV_REFL;
+"REAL_DIV_RMUL",REAL_DIV_RMUL;
+"REAL_DIV_SQRT",REAL_DIV_SQRT;
+"REAL_DOWN",REAL_DOWN;
+"REAL_DOWN2",REAL_DOWN2;
+"REAL_ENTIRE",REAL_ENTIRE;
+"REAL_EQ_ADD_LCANCEL",REAL_EQ_ADD_LCANCEL;
+"REAL_EQ_ADD_LCANCEL_0",REAL_EQ_ADD_LCANCEL_0;
+"REAL_EQ_ADD_RCANCEL",REAL_EQ_ADD_RCANCEL;
+"REAL_EQ_ADD_RCANCEL_0",REAL_EQ_ADD_RCANCEL_0;
+"REAL_EQ_AFFINITY",REAL_EQ_AFFINITY;
+"REAL_EQ_IMP_LE",REAL_EQ_IMP_LE;
+"REAL_EQ_INTEGERS",REAL_EQ_INTEGERS;
+"REAL_EQ_INTEGERS_IMP",REAL_EQ_INTEGERS_IMP;
+"REAL_EQ_INV2",REAL_EQ_INV2;
+"REAL_EQ_LCANCEL_IMP",REAL_EQ_LCANCEL_IMP;
+"REAL_EQ_LDIV_EQ",REAL_EQ_LDIV_EQ;
+"REAL_EQ_MUL_LCANCEL",REAL_EQ_MUL_LCANCEL;
+"REAL_EQ_MUL_RCANCEL",REAL_EQ_MUL_RCANCEL;
+"REAL_EQ_NEG2",REAL_EQ_NEG2;
+"REAL_EQ_RCANCEL_IMP",REAL_EQ_RCANCEL_IMP;
+"REAL_EQ_RDIV_EQ",REAL_EQ_RDIV_EQ;
+"REAL_EQ_SQUARE_ABS",REAL_EQ_SQUARE_ABS;
+"REAL_EQ_SUB_LADD",REAL_EQ_SUB_LADD;
+"REAL_EQ_SUB_RADD",REAL_EQ_SUB_RADD;
+"REAL_FLOOR_ADD",REAL_FLOOR_ADD;
+"REAL_FLOOR_EQ",REAL_FLOOR_EQ;
+"REAL_FLOOR_LE",REAL_FLOOR_LE;
+"REAL_FLOOR_LT",REAL_FLOOR_LT;
+"REAL_FLOOR_REFL",REAL_FLOOR_REFL;
+"REAL_FRAC_ADD",REAL_FRAC_ADD;
+"REAL_FRAC_EQ",REAL_FRAC_EQ;
+"REAL_FRAC_EQ_0",REAL_FRAC_EQ_0;
+"REAL_FRAC_POS_LT",REAL_FRAC_POS_LT;
+"REAL_FRAC_ZERO",REAL_FRAC_ZERO;
+"REAL_HALF",REAL_HALF;
+"REAL_HREAL_LEMMA1",REAL_HREAL_LEMMA1;
+"REAL_HREAL_LEMMA2",REAL_HREAL_LEMMA2;
+"REAL_INF_ASCLOSE",REAL_INF_ASCLOSE;
+"REAL_INF_BOUNDS",REAL_INF_BOUNDS;
+"REAL_INF_LE_FINITE",REAL_INF_LE_FINITE;
+"REAL_INF_LT_FINITE",REAL_INF_LT_FINITE;
+"REAL_INF_UNIQUE",REAL_INF_UNIQUE;
+"REAL_INV_0",REAL_INV_0;
+"REAL_INV_1",REAL_INV_1;
+"REAL_INV_1_LE",REAL_INV_1_LE;
+"REAL_INV_1_LT",REAL_INV_1_LT;
+"REAL_INV_DIV",REAL_INV_DIV;
+"REAL_INV_EQ_0",REAL_INV_EQ_0;
+"REAL_INV_EQ_1",REAL_INV_EQ_1;
+"REAL_INV_INV",REAL_INV_INV;
+"REAL_INV_LE_1",REAL_INV_LE_1;
+"REAL_INV_LT_1",REAL_INV_LT_1;
+"REAL_INV_MUL",REAL_INV_MUL;
+"REAL_INV_NEG",REAL_INV_NEG;
+"REAL_INV_POW",REAL_INV_POW;
+"REAL_LET_ADD",REAL_LET_ADD;
+"REAL_LET_ADD2",REAL_LET_ADD2;
+"REAL_LET_ANTISYM",REAL_LET_ANTISYM;
+"REAL_LET_TOTAL",REAL_LET_TOTAL;
+"REAL_LET_TRANS",REAL_LET_TRANS;
+"REAL_LE_01",REAL_LE_01;
+"REAL_LE_ADD",REAL_LE_ADD;
+"REAL_LE_ADD2",REAL_LE_ADD2;
+"REAL_LE_ADDL",REAL_LE_ADDL;
+"REAL_LE_ADDR",REAL_LE_ADDR;
+"REAL_LE_AFFINITY",REAL_LE_AFFINITY;
+"REAL_LE_ANTISYM",REAL_LE_ANTISYM;
+"REAL_LE_BETWEEN",REAL_LE_BETWEEN;
+"REAL_LE_CASES_INTEGERS",REAL_LE_CASES_INTEGERS;
+"REAL_LE_DIV",REAL_LE_DIV;
+"REAL_LE_DIV2_EQ",REAL_LE_DIV2_EQ;
+"REAL_LE_DOUBLE",REAL_LE_DOUBLE;
+"REAL_LE_FLOOR",REAL_LE_FLOOR;
+"REAL_LE_INF",REAL_LE_INF;
+"REAL_LE_INF_FINITE",REAL_LE_INF_FINITE;
+"REAL_LE_INF_SUBSET",REAL_LE_INF_SUBSET;
+"REAL_LE_INTEGERS",REAL_LE_INTEGERS;
+"REAL_LE_INV",REAL_LE_INV;
+"REAL_LE_INV2",REAL_LE_INV2;
+"REAL_LE_INV_EQ",REAL_LE_INV_EQ;
+"REAL_LE_LADD",REAL_LE_LADD;
+"REAL_LE_LADD_IMP",REAL_LE_LADD_IMP;
+"REAL_LE_LCANCEL_IMP",REAL_LE_LCANCEL_IMP;
+"REAL_LE_LDIV_EQ",REAL_LE_LDIV_EQ;
+"REAL_LE_LINV",REAL_LE_LINV;
+"REAL_LE_LMUL",REAL_LE_LMUL;
+"REAL_LE_LMUL_EQ",REAL_LE_LMUL_EQ;
+"REAL_LE_LNEG",REAL_LE_LNEG;
+"REAL_LE_LSQRT",REAL_LE_LSQRT;
+"REAL_LE_LT",REAL_LE_LT;
+"REAL_LE_MAX",REAL_LE_MAX;
+"REAL_LE_MIN",REAL_LE_MIN;
+"REAL_LE_MUL",REAL_LE_MUL;
+"REAL_LE_MUL2",REAL_LE_MUL2;
+"REAL_LE_MUL_EQ",REAL_LE_MUL_EQ;
+"REAL_LE_NEG",REAL_LE_NEG;
+"REAL_LE_NEG2",REAL_LE_NEG2;
+"REAL_LE_NEGL",REAL_LE_NEGL;
+"REAL_LE_NEGR",REAL_LE_NEGR;
+"REAL_LE_NEGTOTAL",REAL_LE_NEGTOTAL;
+"REAL_LE_POW2",REAL_LE_POW2;
+"REAL_LE_POW_2",REAL_LE_POW_2;
+"REAL_LE_RADD",REAL_LE_RADD;
+"REAL_LE_RCANCEL_IMP",REAL_LE_RCANCEL_IMP;
+"REAL_LE_RDIV_EQ",REAL_LE_RDIV_EQ;
+"REAL_LE_REFL",REAL_LE_REFL;
+"REAL_LE_REVERSE_INTEGERS",REAL_LE_REVERSE_INTEGERS;
+"REAL_LE_RINV",REAL_LE_RINV;
+"REAL_LE_RMUL",REAL_LE_RMUL;
+"REAL_LE_RMUL_EQ",REAL_LE_RMUL_EQ;
+"REAL_LE_RNEG",REAL_LE_RNEG;
+"REAL_LE_RSQRT",REAL_LE_RSQRT;
+"REAL_LE_SETDIST",REAL_LE_SETDIST;
+"REAL_LE_SETDIST_EQ",REAL_LE_SETDIST_EQ;
+"REAL_LE_SQUARE",REAL_LE_SQUARE;
+"REAL_LE_SQUARE_ABS",REAL_LE_SQUARE_ABS;
+"REAL_LE_SUB_LADD",REAL_LE_SUB_LADD;
+"REAL_LE_SUB_RADD",REAL_LE_SUB_RADD;
+"REAL_LE_SUP_FINITE",REAL_LE_SUP_FINITE;
+"REAL_LE_TOTAL",REAL_LE_TOTAL;
+"REAL_LE_TRANS",REAL_LE_TRANS;
+"REAL_LNEG_UNIQ",REAL_LNEG_UNIQ;
+"REAL_LSQRT_LE",REAL_LSQRT_LE;
+"REAL_LTE_ADD",REAL_LTE_ADD;
+"REAL_LTE_ADD2",REAL_LTE_ADD2;
+"REAL_LTE_ANTISYM",REAL_LTE_ANTISYM;
+"REAL_LTE_TOTAL",REAL_LTE_TOTAL;
+"REAL_LTE_TRANS",REAL_LTE_TRANS;
+"REAL_LT_01",REAL_LT_01;
+"REAL_LT_ADD",REAL_LT_ADD;
+"REAL_LT_ADD1",REAL_LT_ADD1;
+"REAL_LT_ADD2",REAL_LT_ADD2;
+"REAL_LT_ADDL",REAL_LT_ADDL;
+"REAL_LT_ADDNEG",REAL_LT_ADDNEG;
+"REAL_LT_ADDNEG2",REAL_LT_ADDNEG2;
+"REAL_LT_ADDR",REAL_LT_ADDR;
+"REAL_LT_ADD_SUB",REAL_LT_ADD_SUB;
+"REAL_LT_AFFINITY",REAL_LT_AFFINITY;
+"REAL_LT_ANTISYM",REAL_LT_ANTISYM;
+"REAL_LT_BETWEEN",REAL_LT_BETWEEN;
+"REAL_LT_DIV",REAL_LT_DIV;
+"REAL_LT_DIV2_EQ",REAL_LT_DIV2_EQ;
+"REAL_LT_GT",REAL_LT_GT;
+"REAL_LT_IMP_LE",REAL_LT_IMP_LE;
+"REAL_LT_IMP_NE",REAL_LT_IMP_NE;
+"REAL_LT_IMP_NZ",REAL_LT_IMP_NZ;
+"REAL_LT_INF_FINITE",REAL_LT_INF_FINITE;
+"REAL_LT_INTEGERS",REAL_LT_INTEGERS;
+"REAL_LT_INV",REAL_LT_INV;
+"REAL_LT_INV2",REAL_LT_INV2;
+"REAL_LT_INV_EQ",REAL_LT_INV_EQ;
+"REAL_LT_LADD",REAL_LT_LADD;
+"REAL_LT_LADD_IMP",REAL_LT_LADD_IMP;
+"REAL_LT_LCANCEL_IMP",REAL_LT_LCANCEL_IMP;
+"REAL_LT_LDIV_EQ",REAL_LT_LDIV_EQ;
+"REAL_LT_LE",REAL_LT_LE;
+"REAL_LT_LINV",REAL_LT_LINV;
+"REAL_LT_LMUL",REAL_LT_LMUL;
+"REAL_LT_LMUL_EQ",REAL_LT_LMUL_EQ;
+"REAL_LT_LNEG",REAL_LT_LNEG;
+"REAL_LT_LSQRT",REAL_LT_LSQRT;
+"REAL_LT_MAX",REAL_LT_MAX;
+"REAL_LT_MIN",REAL_LT_MIN;
+"REAL_LT_MUL",REAL_LT_MUL;
+"REAL_LT_MUL2",REAL_LT_MUL2;
+"REAL_LT_MUL_EQ",REAL_LT_MUL_EQ;
+"REAL_LT_NEG",REAL_LT_NEG;
+"REAL_LT_NEG2",REAL_LT_NEG2;
+"REAL_LT_NEGTOTAL",REAL_LT_NEGTOTAL;
+"REAL_LT_POW2",REAL_LT_POW2;
+"REAL_LT_RADD",REAL_LT_RADD;
+"REAL_LT_RCANCEL_IMP",REAL_LT_RCANCEL_IMP;
+"REAL_LT_RDIV_EQ",REAL_LT_RDIV_EQ;
+"REAL_LT_REFL",REAL_LT_REFL;
+"REAL_LT_RINV",REAL_LT_RINV;
+"REAL_LT_RMUL",REAL_LT_RMUL;
+"REAL_LT_RMUL_EQ",REAL_LT_RMUL_EQ;
+"REAL_LT_RNEG",REAL_LT_RNEG;
+"REAL_LT_RSQRT",REAL_LT_RSQRT;
+"REAL_LT_SQUARE",REAL_LT_SQUARE;
+"REAL_LT_SQUARE_ABS",REAL_LT_SQUARE_ABS;
+"REAL_LT_SUB_LADD",REAL_LT_SUB_LADD;
+"REAL_LT_SUB_RADD",REAL_LT_SUB_RADD;
+"REAL_LT_SUP_FINITE",REAL_LT_SUP_FINITE;
+"REAL_LT_TOTAL",REAL_LT_TOTAL;
+"REAL_LT_TRANS",REAL_LT_TRANS;
+"REAL_MAX_ACI",REAL_MAX_ACI;
+"REAL_MAX_ASSOC",REAL_MAX_ASSOC;
+"REAL_MAX_LE",REAL_MAX_LE;
+"REAL_MAX_LT",REAL_MAX_LT;
+"REAL_MAX_MAX",REAL_MAX_MAX;
+"REAL_MAX_MIN",REAL_MAX_MIN;
+"REAL_MAX_SUP",REAL_MAX_SUP;
+"REAL_MAX_SYM",REAL_MAX_SYM;
+"REAL_MIN_ACI",REAL_MIN_ACI;
+"REAL_MIN_ASSOC",REAL_MIN_ASSOC;
+"REAL_MIN_INF",REAL_MIN_INF;
+"REAL_MIN_LE",REAL_MIN_LE;
+"REAL_MIN_LT",REAL_MIN_LT;
+"REAL_MIN_MAX",REAL_MIN_MAX;
+"REAL_MIN_MIN",REAL_MIN_MIN;
+"REAL_MIN_SYM",REAL_MIN_SYM;
+"REAL_MUL_2",REAL_MUL_2;
+"REAL_MUL_AC",REAL_MUL_AC;
+"REAL_MUL_ASSOC",REAL_MUL_ASSOC;
+"REAL_MUL_LID",REAL_MUL_LID;
+"REAL_MUL_LINV",REAL_MUL_LINV;
+"REAL_MUL_LINV_UNIQ",REAL_MUL_LINV_UNIQ;
+"REAL_MUL_LNEG",REAL_MUL_LNEG;
+"REAL_MUL_LZERO",REAL_MUL_LZERO;
+"REAL_MUL_POS_LE",REAL_MUL_POS_LE;
+"REAL_MUL_POS_LT",REAL_MUL_POS_LT;
+"REAL_MUL_RID",REAL_MUL_RID;
+"REAL_MUL_RINV",REAL_MUL_RINV;
+"REAL_MUL_RINV_UNIQ",REAL_MUL_RINV_UNIQ;
+"REAL_MUL_RNEG",REAL_MUL_RNEG;
+"REAL_MUL_RZERO",REAL_MUL_RZERO;
+"REAL_MUL_SUM",REAL_MUL_SUM;
+"REAL_MUL_SUM_NUMSEG",REAL_MUL_SUM_NUMSEG;
+"REAL_MUL_SYM",REAL_MUL_SYM;
+"REAL_NEGNEG",REAL_NEGNEG;
+"REAL_NEG_0",REAL_NEG_0;
+"REAL_NEG_ADD",REAL_NEG_ADD;
+"REAL_NEG_EQ",REAL_NEG_EQ;
+"REAL_NEG_EQ_0",REAL_NEG_EQ_0;
+"REAL_NEG_GE0",REAL_NEG_GE0;
+"REAL_NEG_GT0",REAL_NEG_GT0;
+"REAL_NEG_LE0",REAL_NEG_LE0;
+"REAL_NEG_LMUL",REAL_NEG_LMUL;
+"REAL_NEG_LT0",REAL_NEG_LT0;
+"REAL_NEG_MINUS1",REAL_NEG_MINUS1;
+"REAL_NEG_MUL2",REAL_NEG_MUL2;
+"REAL_NEG_NEG",REAL_NEG_NEG;
+"REAL_NEG_RMUL",REAL_NEG_RMUL;
+"REAL_NEG_SUB",REAL_NEG_SUB;
+"REAL_NOT_EQ",REAL_NOT_EQ;
+"REAL_NOT_LE",REAL_NOT_LE;
+"REAL_NOT_LT",REAL_NOT_LT;
+"REAL_OF_INT_OF_REAL",REAL_OF_INT_OF_REAL;
+"REAL_OF_NUM_ADD",REAL_OF_NUM_ADD;
+"REAL_OF_NUM_EQ",REAL_OF_NUM_EQ;
+"REAL_OF_NUM_GE",REAL_OF_NUM_GE;
+"REAL_OF_NUM_GT",REAL_OF_NUM_GT;
+"REAL_OF_NUM_LE",REAL_OF_NUM_LE;
+"REAL_OF_NUM_LT",REAL_OF_NUM_LT;
+"REAL_OF_NUM_MAX",REAL_OF_NUM_MAX;
+"REAL_OF_NUM_MIN",REAL_OF_NUM_MIN;
+"REAL_OF_NUM_MUL",REAL_OF_NUM_MUL;
+"REAL_OF_NUM_POW",REAL_OF_NUM_POW;
+"REAL_OF_NUM_SUB",REAL_OF_NUM_SUB;
+"REAL_OF_NUM_SUC",REAL_OF_NUM_SUC;
+"REAL_OF_NUM_SUM",REAL_OF_NUM_SUM;
+"REAL_OF_NUM_SUM_NUMSEG",REAL_OF_NUM_SUM_NUMSEG;
+"REAL_POLYFUN_EQ_0",REAL_POLYFUN_EQ_0;
+"REAL_POLYFUN_EQ_CONST",REAL_POLYFUN_EQ_CONST;
+"REAL_POLYFUN_FINITE_ROOTS",REAL_POLYFUN_FINITE_ROOTS;
+"REAL_POLYFUN_ROOTBOUND",REAL_POLYFUN_ROOTBOUND;
+"REAL_POLY_CLAUSES",REAL_POLY_CLAUSES;
+"REAL_POLY_NEG_CLAUSES",REAL_POLY_NEG_CLAUSES;
+"REAL_POS",REAL_POS;
+"REAL_POS_NZ",REAL_POS_NZ;
+"REAL_POW2_ABS",REAL_POW2_ABS;
+"REAL_POW_1",REAL_POW_1;
+"REAL_POW_1_LE",REAL_POW_1_LE;
+"REAL_POW_1_LT",REAL_POW_1_LT;
+"REAL_POW_2",REAL_POW_2;
+"REAL_POW_ADD",REAL_POW_ADD;
+"REAL_POW_DIV",REAL_POW_DIV;
+"REAL_POW_EQ",REAL_POW_EQ;
+"REAL_POW_EQ_0",REAL_POW_EQ_0;
+"REAL_POW_EQ_1",REAL_POW_EQ_1;
+"REAL_POW_EQ_1_IMP",REAL_POW_EQ_1_IMP;
+"REAL_POW_EQ_ABS",REAL_POW_EQ_ABS;
+"REAL_POW_EQ_EQ",REAL_POW_EQ_EQ;
+"REAL_POW_EQ_ODD",REAL_POW_EQ_ODD;
+"REAL_POW_EQ_ODD_EQ",REAL_POW_EQ_ODD_EQ;
+"REAL_POW_INV",REAL_POW_INV;
+"REAL_POW_LBOUND",REAL_POW_LBOUND;
+"REAL_POW_LE",REAL_POW_LE;
+"REAL_POW_LE2",REAL_POW_LE2;
+"REAL_POW_LE2_ODD",REAL_POW_LE2_ODD;
+"REAL_POW_LE2_ODD_EQ",REAL_POW_LE2_ODD_EQ;
+"REAL_POW_LE2_REV",REAL_POW_LE2_REV;
+"REAL_POW_LE_1",REAL_POW_LE_1;
+"REAL_POW_LT",REAL_POW_LT;
+"REAL_POW_LT2",REAL_POW_LT2;
+"REAL_POW_LT2_ODD",REAL_POW_LT2_ODD;
+"REAL_POW_LT2_ODD_EQ",REAL_POW_LT2_ODD_EQ;
+"REAL_POW_LT2_REV",REAL_POW_LT2_REV;
+"REAL_POW_LT_1",REAL_POW_LT_1;
+"REAL_POW_MONO",REAL_POW_MONO;
+"REAL_POW_MONO_INV",REAL_POW_MONO_INV;
+"REAL_POW_MONO_LT",REAL_POW_MONO_LT;
+"REAL_POW_MUL",REAL_POW_MUL;
+"REAL_POW_NEG",REAL_POW_NEG;
+"REAL_POW_NZ",REAL_POW_NZ;
+"REAL_POW_ONE",REAL_POW_ONE;
+"REAL_POW_POW",REAL_POW_POW;
+"REAL_POW_SUB",REAL_POW_SUB;
+"REAL_POW_ZERO",REAL_POW_ZERO;
+"REAL_RNEG_UNIQ",REAL_RNEG_UNIQ;
+"REAL_RSQRT_LE",REAL_RSQRT_LE;
+"REAL_SGN",REAL_SGN;
+"REAL_SGN_0",REAL_SGN_0;
+"REAL_SGN_ABS",REAL_SGN_ABS;
+"REAL_SGN_CASES",REAL_SGN_CASES;
+"REAL_SGN_DIV",REAL_SGN_DIV;
+"REAL_SGN_EQ",REAL_SGN_EQ;
+"REAL_SGN_INEQS",REAL_SGN_INEQS;
+"REAL_SGN_INV",REAL_SGN_INV;
+"REAL_SGN_MUL",REAL_SGN_MUL;
+"REAL_SGN_NEG",REAL_SGN_NEG;
+"REAL_SOS_EQ_0",REAL_SOS_EQ_0;
+"REAL_SUB_0",REAL_SUB_0;
+"REAL_SUB_ABS",REAL_SUB_ABS;
+"REAL_SUB_ADD",REAL_SUB_ADD;
+"REAL_SUB_ADD2",REAL_SUB_ADD2;
+"REAL_SUB_INV",REAL_SUB_INV;
+"REAL_SUB_LDISTRIB",REAL_SUB_LDISTRIB;
+"REAL_SUB_LE",REAL_SUB_LE;
+"REAL_SUB_LNEG",REAL_SUB_LNEG;
+"REAL_SUB_LT",REAL_SUB_LT;
+"REAL_SUB_LZERO",REAL_SUB_LZERO;
+"REAL_SUB_NEG2",REAL_SUB_NEG2;
+"REAL_SUB_POLYFUN",REAL_SUB_POLYFUN;
+"REAL_SUB_POLYFUN_ALT",REAL_SUB_POLYFUN_ALT;
+"REAL_SUB_POW",REAL_SUB_POW;
+"REAL_SUB_POW_L1",REAL_SUB_POW_L1;
+"REAL_SUB_POW_R1",REAL_SUB_POW_R1;
+"REAL_SUB_RDISTRIB",REAL_SUB_RDISTRIB;
+"REAL_SUB_REFL",REAL_SUB_REFL;
+"REAL_SUB_RNEG",REAL_SUB_RNEG;
+"REAL_SUB_RZERO",REAL_SUB_RZERO;
+"REAL_SUB_SUB",REAL_SUB_SUB;
+"REAL_SUB_SUB2",REAL_SUB_SUB2;
+"REAL_SUB_TRIANGLE",REAL_SUB_TRIANGLE;
+"REAL_SUP_ASCLOSE",REAL_SUP_ASCLOSE;
+"REAL_SUP_BOUNDS",REAL_SUP_BOUNDS;
+"REAL_SUP_EQ_INF",REAL_SUP_EQ_INF;
+"REAL_SUP_LE",REAL_SUP_LE;
+"REAL_SUP_LE_FINITE",REAL_SUP_LE_FINITE;
+"REAL_SUP_LE_SUBSET",REAL_SUP_LE_SUBSET;
+"REAL_SUP_LT_FINITE",REAL_SUP_LT_FINITE;
+"REAL_SUP_UNIQUE",REAL_SUP_UNIQUE;
+"REAL_TRUNCATE",REAL_TRUNCATE;
+"REAL_TRUNCATE_POS",REAL_TRUNCATE_POS;
+"REAL_WLOG_LE",REAL_WLOG_LE;
+"REAL_WLOG_LT",REAL_WLOG_LT;
+"RECTIFIABLE_PATH_DIFFERENTIABLE",RECTIFIABLE_PATH_DIFFERENTIABLE;
+"RECTIFIABLE_PATH_IMP_PATH",RECTIFIABLE_PATH_IMP_PATH;
+"RECTIFIABLE_PATH_JOIN",RECTIFIABLE_PATH_JOIN;
+"RECTIFIABLE_PATH_JOIN_EQ",RECTIFIABLE_PATH_JOIN_EQ;
+"RECTIFIABLE_PATH_JOIN_IMP",RECTIFIABLE_PATH_JOIN_IMP;
+"RECTIFIABLE_PATH_LINEPATH",RECTIFIABLE_PATH_LINEPATH;
+"RECTIFIABLE_PATH_REVERSEPATH",RECTIFIABLE_PATH_REVERSEPATH;
+"RECTIFIABLE_PATH_SUBPATH",RECTIFIABLE_PATH_SUBPATH;
+"RECURSION_CASEWISE",RECURSION_CASEWISE;
+"RECURSION_CASEWISE_PAIRWISE",RECURSION_CASEWISE_PAIRWISE;
+"RECURSION_SUPERADMISSIBLE",RECURSION_SUPERADMISSIBLE;
+"REDUCED_LABELLING",REDUCED_LABELLING;
+"REDUCED_LABELLING_0",REDUCED_LABELLING_0;
+"REDUCED_LABELLING_1",REDUCED_LABELLING_1;
+"REDUCED_LABELLING_SUC",REDUCED_LABELLING_SUC;
+"REDUCED_LABELLING_UNIQUE",REDUCED_LABELLING_UNIQUE;
+"REDUCE_LABELLING_0",REDUCE_LABELLING_0;
+"REFLECT_ALONG_0",REFLECT_ALONG_0;
+"REFLECT_ALONG_1D",REFLECT_ALONG_1D;
+"REFLECT_ALONG_ADD",REFLECT_ALONG_ADD;
+"REFLECT_ALONG_BASIS",REFLECT_ALONG_BASIS;
+"REFLECT_ALONG_EQ_0",REFLECT_ALONG_EQ_0;
+"REFLECT_ALONG_EQ_SELF",REFLECT_ALONG_EQ_SELF;
+"REFLECT_ALONG_INVOLUTION",REFLECT_ALONG_INVOLUTION;
+"REFLECT_ALONG_LINEAR_IMAGE",REFLECT_ALONG_LINEAR_IMAGE;
+"REFLECT_ALONG_MUL",REFLECT_ALONG_MUL;
+"REFLECT_ALONG_REFL",REFLECT_ALONG_REFL;
+"REFLECT_ALONG_SCALE",REFLECT_ALONG_SCALE;
+"REFLECT_ALONG_ZERO",REFLECT_ALONG_ZERO;
+"REFLECT_INTERVAL",REFLECT_INTERVAL;
+"REFL_CLAUSE",REFL_CLAUSE;
+"RELATIVE_BOUNDARY_OF_CONVEX_HULL",RELATIVE_BOUNDARY_OF_CONVEX_HULL;
+"RELATIVE_BOUNDARY_OF_POLYHEDRON",RELATIVE_BOUNDARY_OF_POLYHEDRON;
+"RELATIVE_BOUNDARY_OF_TRIANGLE",RELATIVE_BOUNDARY_OF_TRIANGLE;
+"RELATIVE_BOUNDARY_RETRACT_OF_PUNCTURED_AFFINE_HULL",RELATIVE_BOUNDARY_RETRACT_OF_PUNCTURED_AFFINE_HULL;
+"RELATIVE_FRONTIER_BALL",RELATIVE_FRONTIER_BALL;
+"RELATIVE_FRONTIER_CBALL",RELATIVE_FRONTIER_CBALL;
+"RELATIVE_FRONTIER_CLOSURE",RELATIVE_FRONTIER_CLOSURE;
+"RELATIVE_FRONTIER_CONVEX_HULL_CASES",RELATIVE_FRONTIER_CONVEX_HULL_CASES;
+"RELATIVE_FRONTIER_CONVEX_HULL_EXPLICIT",RELATIVE_FRONTIER_CONVEX_HULL_EXPLICIT;
+"RELATIVE_FRONTIER_CONVEX_INTER_AFFINE",RELATIVE_FRONTIER_CONVEX_INTER_AFFINE;
+"RELATIVE_FRONTIER_EMPTY",RELATIVE_FRONTIER_EMPTY;
+"RELATIVE_FRONTIER_EQ_EMPTY",RELATIVE_FRONTIER_EQ_EMPTY;
+"RELATIVE_FRONTIER_FRONTIER",RELATIVE_FRONTIER_FRONTIER;
+"RELATIVE_FRONTIER_INJECTIVE_LINEAR_IMAGE",RELATIVE_FRONTIER_INJECTIVE_LINEAR_IMAGE;
+"RELATIVE_FRONTIER_NONEMPTY_INTERIOR",RELATIVE_FRONTIER_NONEMPTY_INTERIOR;
+"RELATIVE_FRONTIER_NOT_SING",RELATIVE_FRONTIER_NOT_SING;
+"RELATIVE_FRONTIER_OF_CONVEX_HULL",RELATIVE_FRONTIER_OF_CONVEX_HULL;
+"RELATIVE_FRONTIER_OF_POLYHEDRON",RELATIVE_FRONTIER_OF_POLYHEDRON;
+"RELATIVE_FRONTIER_OF_POLYHEDRON_ALT",RELATIVE_FRONTIER_OF_POLYHEDRON_ALT;
+"RELATIVE_FRONTIER_OF_TRIANGLE",RELATIVE_FRONTIER_OF_TRIANGLE;
+"RELATIVE_FRONTIER_RETRACT_OF_PUNCTURED_AFFINE_HULL",RELATIVE_FRONTIER_RETRACT_OF_PUNCTURED_AFFINE_HULL;
+"RELATIVE_FRONTIER_SING",RELATIVE_FRONTIER_SING;
+"RELATIVE_FRONTIER_TRANSLATION",RELATIVE_FRONTIER_TRANSLATION;
+"RELATIVE_INTERIOR",RELATIVE_INTERIOR;
+"RELATIVE_INTERIOR_AFFINE",RELATIVE_INTERIOR_AFFINE;
+"RELATIVE_INTERIOR_CONVEX_CONTAINS_SAME_RAY",RELATIVE_INTERIOR_CONVEX_CONTAINS_SAME_RAY;
+"RELATIVE_INTERIOR_CONVEX_HULL_EXPLICIT",RELATIVE_INTERIOR_CONVEX_HULL_EXPLICIT;
+"RELATIVE_INTERIOR_CONVEX_INTER_AFFINE",RELATIVE_INTERIOR_CONVEX_INTER_AFFINE;
+"RELATIVE_INTERIOR_CONVEX_PROLONG",RELATIVE_INTERIOR_CONVEX_PROLONG;
+"RELATIVE_INTERIOR_EMPTY",RELATIVE_INTERIOR_EMPTY;
+"RELATIVE_INTERIOR_EQ",RELATIVE_INTERIOR_EQ;
+"RELATIVE_INTERIOR_EQ_CLOSURE",RELATIVE_INTERIOR_EQ_CLOSURE;
+"RELATIVE_INTERIOR_EQ_EMPTY",RELATIVE_INTERIOR_EQ_EMPTY;
+"RELATIVE_INTERIOR_INJECTIVE_LINEAR_IMAGE",RELATIVE_INTERIOR_INJECTIVE_LINEAR_IMAGE;
+"RELATIVE_INTERIOR_INTERIOR",RELATIVE_INTERIOR_INTERIOR;
+"RELATIVE_INTERIOR_LINEAR_IMAGE_CONVEX",RELATIVE_INTERIOR_LINEAR_IMAGE_CONVEX;
+"RELATIVE_INTERIOR_MAXIMAL",RELATIVE_INTERIOR_MAXIMAL;
+"RELATIVE_INTERIOR_NONEMPTY_INTERIOR",RELATIVE_INTERIOR_NONEMPTY_INTERIOR;
+"RELATIVE_INTERIOR_OF_POLYHEDRON",RELATIVE_INTERIOR_OF_POLYHEDRON;
+"RELATIVE_INTERIOR_OPEN",RELATIVE_INTERIOR_OPEN;
+"RELATIVE_INTERIOR_OPEN_IN",RELATIVE_INTERIOR_OPEN_IN;
+"RELATIVE_INTERIOR_PCROSS",RELATIVE_INTERIOR_PCROSS;
+"RELATIVE_INTERIOR_POLYHEDRON_EXPLICIT",RELATIVE_INTERIOR_POLYHEDRON_EXPLICIT;
+"RELATIVE_INTERIOR_PROLONG",RELATIVE_INTERIOR_PROLONG;
+"RELATIVE_INTERIOR_SEGMENT",RELATIVE_INTERIOR_SEGMENT;
+"RELATIVE_INTERIOR_SING",RELATIVE_INTERIOR_SING;
+"RELATIVE_INTERIOR_SUBSET",RELATIVE_INTERIOR_SUBSET;
+"RELATIVE_INTERIOR_TRANSLATION",RELATIVE_INTERIOR_TRANSLATION;
+"RELATIVE_INTERIOR_UNBOUNDED_CONVEX_CONTAINS_RAY",RELATIVE_INTERIOR_UNBOUNDED_CONVEX_CONTAINS_RAY;
+"RELATIVE_INTERIOR_UNBOUNDED_CONVEX_CONTAINS_RAYS",RELATIVE_INTERIOR_UNBOUNDED_CONVEX_CONTAINS_RAYS;
+"RELATIVE_INTERIOR_UNIQUE",RELATIVE_INTERIOR_UNIQUE;
+"RELATIVE_INTERIOR_UNIV",RELATIVE_INTERIOR_UNIV;
+"REPLICATE",REPLICATE;
+"REP_ABS_PAIR",REP_ABS_PAIR;
+"REST",REST;
+"RETRACTION",RETRACTION;
+"RETRACTION_ARC",RETRACTION_ARC;
+"RETRACTION_IDEMPOTENT",RETRACTION_IDEMPOTENT;
+"RETRACTION_IMP_QUOTIENT_MAP",RETRACTION_IMP_QUOTIENT_MAP;
+"RETRACTION_REFL",RETRACTION_REFL;
+"RETRACTION_SUBSET",RETRACTION_SUBSET;
+"RETRACTION_o",RETRACTION_o;
+"RETRACT_FIXPOINT_PROPERTY",RETRACT_FIXPOINT_PROPERTY;
+"RETRACT_OF_CLOSED",RETRACT_OF_CLOSED;
+"RETRACT_OF_COHOMOTOPICALLY_TRIVIAL",RETRACT_OF_COHOMOTOPICALLY_TRIVIAL;
+"RETRACT_OF_COHOMOTOPICALLY_TRIVIAL_NULL",RETRACT_OF_COHOMOTOPICALLY_TRIVIAL_NULL;
+"RETRACT_OF_COMPACT",RETRACT_OF_COMPACT;
+"RETRACT_OF_CONNECTED",RETRACT_OF_CONNECTED;
+"RETRACT_OF_CONTRACTIBLE",RETRACT_OF_CONTRACTIBLE;
+"RETRACT_OF_EMPTY",RETRACT_OF_EMPTY;
+"RETRACT_OF_HOMOTOPICALLY_TRIVIAL",RETRACT_OF_HOMOTOPICALLY_TRIVIAL;
+"RETRACT_OF_HOMOTOPICALLY_TRIVIAL_NULL",RETRACT_OF_HOMOTOPICALLY_TRIVIAL_NULL;
+"RETRACT_OF_IMP_EXTENSIBLE",RETRACT_OF_IMP_EXTENSIBLE;
+"RETRACT_OF_IMP_SUBSET",RETRACT_OF_IMP_SUBSET;
+"RETRACT_OF_INJECTIVE_LINEAR_IMAGE",RETRACT_OF_INJECTIVE_LINEAR_IMAGE;
+"RETRACT_OF_LINEAR_IMAGE_EQ",RETRACT_OF_LINEAR_IMAGE_EQ;
+"RETRACT_OF_LOCALLY_COMPACT",RETRACT_OF_LOCALLY_COMPACT;
+"RETRACT_OF_LOCALLY_CONNECTED",RETRACT_OF_LOCALLY_CONNECTED;
+"RETRACT_OF_LOCALLY_PATH_CONNECTED",RETRACT_OF_LOCALLY_PATH_CONNECTED;
+"RETRACT_OF_PATH_CONNECTED",RETRACT_OF_PATH_CONNECTED;
+"RETRACT_OF_PCROSS",RETRACT_OF_PCROSS;
+"RETRACT_OF_REFL",RETRACT_OF_REFL;
+"RETRACT_OF_SIMPLY_CONNECTED",RETRACT_OF_SIMPLY_CONNECTED;
+"RETRACT_OF_SING",RETRACT_OF_SING;
+"RETRACT_OF_SUBSET",RETRACT_OF_SUBSET;
+"RETRACT_OF_TRANS",RETRACT_OF_TRANS;
+"RETRACT_OF_TRANSLATION",RETRACT_OF_TRANSLATION;
+"RETRACT_OF_TRANSLATION_EQ",RETRACT_OF_TRANSLATION_EQ;
+"REVERSE",REVERSE;
+"REVERSEPATH_JOINPATHS",REVERSEPATH_JOINPATHS;
+"REVERSEPATH_LINEAR_IMAGE",REVERSEPATH_LINEAR_IMAGE;
+"REVERSEPATH_LINEPATH",REVERSEPATH_LINEPATH;
+"REVERSEPATH_REVERSEPATH",REVERSEPATH_REVERSEPATH;
+"REVERSEPATH_SUBPATH",REVERSEPATH_SUBPATH;
+"REVERSEPATH_TRANSLATION",REVERSEPATH_TRANSLATION;
+"REVERSE_APPEND",REVERSE_APPEND;
+"REVERSE_REVERSE",REVERSE_REVERSE;
+"RIGHT_ADD_DISTRIB",RIGHT_ADD_DISTRIB;
+"RIGHT_AND_EXISTS_THM",RIGHT_AND_EXISTS_THM;
+"RIGHT_AND_FORALL_THM",RIGHT_AND_FORALL_THM;
+"RIGHT_EXISTS_AND_THM",RIGHT_EXISTS_AND_THM;
+"RIGHT_EXISTS_IMP_THM",RIGHT_EXISTS_IMP_THM;
+"RIGHT_FORALL_IMP_THM",RIGHT_FORALL_IMP_THM;
+"RIGHT_FORALL_OR_THM",RIGHT_FORALL_OR_THM;
+"RIGHT_IMP_EXISTS_THM",RIGHT_IMP_EXISTS_THM;
+"RIGHT_IMP_FORALL_THM",RIGHT_IMP_FORALL_THM;
+"RIGHT_INVERSE_LINEAR",RIGHT_INVERSE_LINEAR;
+"RIGHT_INVERTIBLE_TRANSP",RIGHT_INVERTIBLE_TRANSP;
+"RIGHT_OR_DISTRIB",RIGHT_OR_DISTRIB;
+"RIGHT_OR_EXISTS_THM",RIGHT_OR_EXISTS_THM;
+"RIGHT_OR_FORALL_THM",RIGHT_OR_FORALL_THM;
+"RIGHT_SUB_DISTRIB",RIGHT_SUB_DISTRIB;
+"RIGID_TRANSFORMATION_BETWEEN_2",RIGID_TRANSFORMATION_BETWEEN_2;
+"RIGID_TRANSFORMATION_BETWEEN_3",RIGID_TRANSFORMATION_BETWEEN_3;
+"RIGID_TRANSFORMATION_BETWEEN_CONGRUENT_SETS",RIGID_TRANSFORMATION_BETWEEN_CONGRUENT_SETS;
+"RIGID_TRANSFORMATION_BETWEEN_CONGRUENT_SETS_STRONG",RIGID_TRANSFORMATION_BETWEEN_CONGRUENT_SETS_STRONG;
+"ROLLE",ROLLE;
+"ROTATION_EXISTS",ROTATION_EXISTS;
+"ROTATION_EXISTS_1",ROTATION_EXISTS_1;
+"ROTATION_LOWDIM_HORIZONTAL",ROTATION_LOWDIM_HORIZONTAL;
+"ROTATION_MATRIX_2",ROTATION_MATRIX_2;
+"ROTATION_MATRIX_EXISTS_BASIS",ROTATION_MATRIX_EXISTS_BASIS;
+"ROTATION_RIGHTWARD_LINE",ROTATION_RIGHTWARD_LINE;
+"ROTHE",ROTHE;
+"ROTOINVERSION_MATRIX_REFLECT_ALONG",ROTOINVERSION_MATRIX_REFLECT_ALONG;
+"ROWS_TRANSP",ROWS_TRANSP;
+"ROW_TRANSP",ROW_TRANSP;
+"RSUM_BOUND",RSUM_BOUND;
+"RSUM_COMPONENT_LE",RSUM_COMPONENT_LE;
+"RSUM_DIFF_BOUND",RSUM_DIFF_BOUND;
+"SAME_DISTANCES_TO_AFFINE_HULL",SAME_DISTANCES_TO_AFFINE_HULL;
+"SCALING_LINEAR",SCALING_LINEAR;
+"SCHAUDER",SCHAUDER;
+"SCHAUDER_PROJECTION",SCHAUDER_PROJECTION;
+"SCHAUDER_UNIV",SCHAUDER_UNIV;
+"SECOND_MEAN_VALUE_THEOREM",SECOND_MEAN_VALUE_THEOREM;
+"SECOND_MEAN_VALUE_THEOREM_BONNET",SECOND_MEAN_VALUE_THEOREM_BONNET;
+"SECOND_MEAN_VALUE_THEOREM_BONNET_FULL",SECOND_MEAN_VALUE_THEOREM_BONNET_FULL;
+"SECOND_MEAN_VALUE_THEOREM_FULL",SECOND_MEAN_VALUE_THEOREM_FULL;
+"SECOND_MEAN_VALUE_THEOREM_GEN",SECOND_MEAN_VALUE_THEOREM_GEN;
+"SECOND_MEAN_VALUE_THEOREM_GEN_FULL",SECOND_MEAN_VALUE_THEOREM_GEN_FULL;
+"SEGMENT_1",SEGMENT_1;
+"SEGMENT_AS_BALL",SEGMENT_AS_BALL;
+"SEGMENT_BOUND",SEGMENT_BOUND;
+"SEGMENT_CLOSED_OPEN",SEGMENT_CLOSED_OPEN;
+"SEGMENT_CONVEX_HULL",SEGMENT_CONVEX_HULL;
+"SEGMENT_EDGE_OF",SEGMENT_EDGE_OF;
+"SEGMENT_EQ",SEGMENT_EQ;
+"SEGMENT_EQ_EMPTY",SEGMENT_EQ_EMPTY;
+"SEGMENT_EQ_SING",SEGMENT_EQ_SING;
+"SEGMENT_FACE_OF",SEGMENT_FACE_OF;
+"SEGMENT_FURTHEST_LE",SEGMENT_FURTHEST_LE;
+"SEGMENT_HORIZONTAL",SEGMENT_HORIZONTAL;
+"SEGMENT_IMAGE_INTERVAL",SEGMENT_IMAGE_INTERVAL;
+"SEGMENT_OPEN_SUBSET_CLOSED",SEGMENT_OPEN_SUBSET_CLOSED;
+"SEGMENT_REFL",SEGMENT_REFL;
+"SEGMENT_SCALAR_MULTIPLE",SEGMENT_SCALAR_MULTIPLE;
+"SEGMENT_SYM",SEGMENT_SYM;
+"SEGMENT_TO_CLOSEST_POINT",SEGMENT_TO_CLOSEST_POINT;
+"SEGMENT_TO_POINT_EXISTS",SEGMENT_TO_POINT_EXISTS;
+"SEGMENT_TRANSLATION",SEGMENT_TRANSLATION;
+"SEGMENT_VERTICAL",SEGMENT_VERTICAL;
+"SELECT_AX",SELECT_AX;
+"SELECT_REFL",SELECT_REFL;
+"SELECT_UNIQUE",SELECT_UNIQUE;
+"SELF_ADJOINT_COMPOSE",SELF_ADJOINT_COMPOSE;
+"SELF_ADJOINT_HAS_EIGENVECTOR",SELF_ADJOINT_HAS_EIGENVECTOR;
+"SELF_ADJOINT_HAS_EIGENVECTOR_BASIS",SELF_ADJOINT_HAS_EIGENVECTOR_BASIS;
+"SELF_ADJOINT_HAS_EIGENVECTOR_BASIS_OF_SUBSPACE",SELF_ADJOINT_HAS_EIGENVECTOR_BASIS_OF_SUBSPACE;
+"SELF_ADJOINT_HAS_EIGENVECTOR_IN_SUBSPACE",SELF_ADJOINT_HAS_EIGENVECTOR_IN_SUBSPACE;
+"SELF_ADJOINT_ORTHOGONAL_EIGENVECTORS",SELF_ADJOINT_ORTHOGONAL_EIGENVECTORS;
+"SEPARABLE",SEPARABLE;
+"SEPARATE_CLOSED_COMPACT",SEPARATE_CLOSED_COMPACT;
+"SEPARATE_CLOSED_CONES",SEPARATE_CLOSED_CONES;
+"SEPARATE_COMPACT_CLOSED",SEPARATE_COMPACT_CLOSED;
+"SEPARATE_POINT_CLOSED",SEPARATE_POINT_CLOSED;
+"SEPARATING_HYPERPLANE_CLOSED_0",SEPARATING_HYPERPLANE_CLOSED_0;
+"SEPARATING_HYPERPLANE_CLOSED_0_INSET",SEPARATING_HYPERPLANE_CLOSED_0_INSET;
+"SEPARATING_HYPERPLANE_CLOSED_COMPACT",SEPARATING_HYPERPLANE_CLOSED_COMPACT;
+"SEPARATING_HYPERPLANE_CLOSED_POINT",SEPARATING_HYPERPLANE_CLOSED_POINT;
+"SEPARATING_HYPERPLANE_CLOSED_POINT_INSET",SEPARATING_HYPERPLANE_CLOSED_POINT_INSET;
+"SEPARATING_HYPERPLANE_COMPACT_CLOSED",SEPARATING_HYPERPLANE_COMPACT_CLOSED;
+"SEPARATING_HYPERPLANE_COMPACT_CLOSED_NONZERO",SEPARATING_HYPERPLANE_COMPACT_CLOSED_NONZERO;
+"SEPARATING_HYPERPLANE_COMPACT_COMPACT",SEPARATING_HYPERPLANE_COMPACT_COMPACT;
+"SEPARATING_HYPERPLANE_POLYHEDRA",SEPARATING_HYPERPLANE_POLYHEDRA;
+"SEPARATING_HYPERPLANE_RELATIVE_INTERIORS",SEPARATING_HYPERPLANE_RELATIVE_INTERIORS;
+"SEPARATING_HYPERPLANE_SETS",SEPARATING_HYPERPLANE_SETS;
+"SEPARATING_HYPERPLANE_SET_0",SEPARATING_HYPERPLANE_SET_0;
+"SEPARATING_HYPERPLANE_SET_0_INSPAN",SEPARATING_HYPERPLANE_SET_0_INSPAN;
+"SEPARATING_HYPERPLANE_SET_POINT_INAFF",SEPARATING_HYPERPLANE_SET_POINT_INAFF;
+"SEPARATION_CLOSURES",SEPARATION_CLOSURES;
+"SEPARATION_HAUSDORFF",SEPARATION_HAUSDORFF;
+"SEPARATION_NORMAL",SEPARATION_NORMAL;
+"SEPARATION_NORMAL_COMPACT",SEPARATION_NORMAL_COMPACT;
+"SEPARATION_T0",SEPARATION_T0;
+"SEPARATION_T1",SEPARATION_T1;
+"SEPARATION_T2",SEPARATION_T2;
+"SEQITERATE_CLAUSES",SEQITERATE_CLAUSES;
+"SEQITERATE_ITERATE",SEQITERATE_ITERATE;
+"SEQUENCE_CAUCHY_WLOG",SEQUENCE_CAUCHY_WLOG;
+"SEQUENCE_INFINITE_LEMMA",SEQUENCE_INFINITE_LEMMA;
+"SEQUENCE_UNIQUE_LIMPT",SEQUENCE_UNIQUE_LIMPT;
+"SEQUENTIALLY",SEQUENTIALLY;
+"SEQ_HARMONIC",SEQ_HARMONIC;
+"SEQ_MONO_LEMMA",SEQ_MONO_LEMMA;
+"SEQ_OFFSET",SEQ_OFFSET;
+"SEQ_OFFSET_NEG",SEQ_OFFSET_NEG;
+"SEQ_OFFSET_REV",SEQ_OFFSET_REV;
+"SERIES_0",SERIES_0;
+"SERIES_ADD",SERIES_ADD;
+"SERIES_CAUCHY",SERIES_CAUCHY;
+"SERIES_CAUCHY_UNIFORM",SERIES_CAUCHY_UNIFORM;
+"SERIES_CMUL",SERIES_CMUL;
+"SERIES_COMPARISON",SERIES_COMPARISON;
+"SERIES_COMPARISON_UNIFORM",SERIES_COMPARISON_UNIFORM;
+"SERIES_COMPONENT",SERIES_COMPONENT;
+"SERIES_DIFFS",SERIES_DIFFS;
+"SERIES_DIRICHLET",SERIES_DIRICHLET;
+"SERIES_DIRICHLET_BILINEAR",SERIES_DIRICHLET_BILINEAR;
+"SERIES_FINITE",SERIES_FINITE;
+"SERIES_FINITE_SUPPORT",SERIES_FINITE_SUPPORT;
+"SERIES_FROM",SERIES_FROM;
+"SERIES_GOESTOZERO",SERIES_GOESTOZERO;
+"SERIES_INJECTIVE_IMAGE",SERIES_INJECTIVE_IMAGE;
+"SERIES_INJECTIVE_IMAGE_STRONG",SERIES_INJECTIVE_IMAGE_STRONG;
+"SERIES_LIFT_ABSCONV_IMP_CONV",SERIES_LIFT_ABSCONV_IMP_CONV;
+"SERIES_LINEAR",SERIES_LINEAR;
+"SERIES_NEG",SERIES_NEG;
+"SERIES_RATIO",SERIES_RATIO;
+"SERIES_REARRANGE",SERIES_REARRANGE;
+"SERIES_REARRANGE_EQ",SERIES_REARRANGE_EQ;
+"SERIES_RESTRICT",SERIES_RESTRICT;
+"SERIES_SUB",SERIES_SUB;
+"SERIES_SUBSET",SERIES_SUBSET;
+"SERIES_TRIVIAL",SERIES_TRIVIAL;
+"SERIES_UNIQUE",SERIES_UNIQUE;
+"SERIES_VSUM",SERIES_VSUM;
+"SETCODE_BOUNDS",SETCODE_BOUNDS;
+"SETDIST_CLOSED_COMPACT",SETDIST_CLOSED_COMPACT;
+"SETDIST_CLOSEST_POINT",SETDIST_CLOSEST_POINT;
+"SETDIST_CLOSURE",SETDIST_CLOSURE;
+"SETDIST_COMPACT_CLOSED",SETDIST_COMPACT_CLOSED;
+"SETDIST_DIFFERENCES",SETDIST_DIFFERENCES;
+"SETDIST_EMPTY",SETDIST_EMPTY;
+"SETDIST_EQ_0_BOUNDED",SETDIST_EQ_0_BOUNDED;
+"SETDIST_EQ_0_CLOSED_COMPACT",SETDIST_EQ_0_CLOSED_COMPACT;
+"SETDIST_EQ_0_COMPACT_CLOSED",SETDIST_EQ_0_COMPACT_CLOSED;
+"SETDIST_EQ_0_SING",SETDIST_EQ_0_SING;
+"SETDIST_LE_DIST",SETDIST_LE_DIST;
+"SETDIST_LINEAR_IMAGE",SETDIST_LINEAR_IMAGE;
+"SETDIST_LIPSCHITZ",SETDIST_LIPSCHITZ;
+"SETDIST_POS_LE",SETDIST_POS_LE;
+"SETDIST_REFL",SETDIST_REFL;
+"SETDIST_SINGS",SETDIST_SINGS;
+"SETDIST_SUBSET_LEFT",SETDIST_SUBSET_LEFT;
+"SETDIST_SUBSET_RIGHT",SETDIST_SUBSET_RIGHT;
+"SETDIST_SYM",SETDIST_SYM;
+"SETDIST_TRANSLATION",SETDIST_TRANSLATION;
+"SETDIST_TRIANGLE",SETDIST_TRIANGLE;
+"SETDIST_UNIQUE",SETDIST_UNIQUE;
+"SETSPEC",SETSPEC;
+"SETVARIATION_EQUAL_LEMMA",SETVARIATION_EQUAL_LEMMA;
+"SET_CASES",SET_CASES;
+"SET_OF_LIST_APPEND",SET_OF_LIST_APPEND;
+"SET_OF_LIST_EQ_EMPTY",SET_OF_LIST_EQ_EMPTY;
+"SET_OF_LIST_MAP",SET_OF_LIST_MAP;
+"SET_OF_LIST_OF_SET",SET_OF_LIST_OF_SET;
+"SET_PAIR_THM",SET_PAIR_THM;
+"SET_PROVE_CASES",SET_PROVE_CASES;
+"SET_RECURSION_LEMMA",SET_RECURSION_LEMMA;
+"SET_VARIATION",SET_VARIATION;
+"SET_VARIATION_0",SET_VARIATION_0;
+"SET_VARIATION_ELEMENTARY_LEMMA",SET_VARIATION_ELEMENTARY_LEMMA;
+"SET_VARIATION_EQ",SET_VARIATION_EQ;
+"SET_VARIATION_GE_FUNCTION",SET_VARIATION_GE_FUNCTION;
+"SET_VARIATION_LBOUND",SET_VARIATION_LBOUND;
+"SET_VARIATION_LBOUND_ON_INTERVAL",SET_VARIATION_LBOUND_ON_INTERVAL;
+"SET_VARIATION_MONOTONE",SET_VARIATION_MONOTONE;
+"SET_VARIATION_ON_DIVISION",SET_VARIATION_ON_DIVISION;
+"SET_VARIATION_ON_ELEMENTARY",SET_VARIATION_ON_ELEMENTARY;
+"SET_VARIATION_ON_INTERVAL",SET_VARIATION_ON_INTERVAL;
+"SET_VARIATION_ON_NULL",SET_VARIATION_ON_NULL;
+"SET_VARIATION_POS_LE",SET_VARIATION_POS_LE;
+"SET_VARIATION_REFLECT2",SET_VARIATION_REFLECT2;
+"SET_VARIATION_TRANSLATION2",SET_VARIATION_TRANSLATION2;
+"SET_VARIATION_TRIANGLE",SET_VARIATION_TRIANGLE;
+"SET_VARIATION_UBOUND",SET_VARIATION_UBOUND;
+"SET_VARIATION_UBOUND_ON_INTERVAL",SET_VARIATION_UBOUND_ON_INTERVAL;
+"SET_VARIATION_WORKS_ON_INTERVAL",SET_VARIATION_WORKS_ON_INTERVAL;
+"SHIFTPATH_LINEAR_IMAGE",SHIFTPATH_LINEAR_IMAGE;
+"SHIFTPATH_SHIFTPATH",SHIFTPATH_SHIFTPATH;
+"SHIFTPATH_TRANSLATION",SHIFTPATH_TRANSLATION;
+"SHIFTPATH_TRIVIAL",SHIFTPATH_TRIVIAL;
+"SIGMA_COMPACT",SIGMA_COMPACT;
+"SIGN_COMPOSE",SIGN_COMPOSE;
+"SIGN_I",SIGN_I;
+"SIGN_IDEMPOTENT",SIGN_IDEMPOTENT;
+"SIGN_INVERSE",SIGN_INVERSE;
+"SIGN_NZ",SIGN_NZ;
+"SIGN_SWAP",SIGN_SWAP;
+"SIMPLEX",SIMPLEX;
+"SIMPLEX_DIM_GE",SIMPLEX_DIM_GE;
+"SIMPLEX_EMPTY",SIMPLEX_EMPTY;
+"SIMPLEX_EXPLICIT",SIMPLEX_EXPLICIT;
+"SIMPLEX_EXTREMAL_LE",SIMPLEX_EXTREMAL_LE;
+"SIMPLEX_EXTREMAL_LE_EXISTS",SIMPLEX_EXTREMAL_LE_EXISTS;
+"SIMPLEX_EXTREME_POINTS",SIMPLEX_EXTREME_POINTS;
+"SIMPLEX_FACE_OF_SIMPLEX",SIMPLEX_FACE_OF_SIMPLEX;
+"SIMPLEX_FURTHEST_LE",SIMPLEX_FURTHEST_LE;
+"SIMPLEX_FURTHEST_LE_EXISTS",SIMPLEX_FURTHEST_LE_EXISTS;
+"SIMPLEX_FURTHEST_LT",SIMPLEX_FURTHEST_LT;
+"SIMPLEX_IMP_POLYTOPE",SIMPLEX_IMP_POLYTOPE;
+"SIMPLEX_MINUS_1",SIMPLEX_MINUS_1;
+"SIMPLEX_TOP_FACE",SIMPLEX_TOP_FACE;
+"SIMPLE_IMAGE",SIMPLE_IMAGE;
+"SIMPLE_IMAGE_GEN",SIMPLE_IMAGE_GEN;
+"SIMPLE_PATH_ASSOC",SIMPLE_PATH_ASSOC;
+"SIMPLE_PATH_CASES",SIMPLE_PATH_CASES;
+"SIMPLE_PATH_ENDLESS",SIMPLE_PATH_ENDLESS;
+"SIMPLE_PATH_EQ_ARC",SIMPLE_PATH_EQ_ARC;
+"SIMPLE_PATH_IMP_ARC",SIMPLE_PATH_IMP_ARC;
+"SIMPLE_PATH_IMP_PATH",SIMPLE_PATH_IMP_PATH;
+"SIMPLE_PATH_JOIN_IMP",SIMPLE_PATH_JOIN_IMP;
+"SIMPLE_PATH_JOIN_LOOP",SIMPLE_PATH_JOIN_LOOP;
+"SIMPLE_PATH_JOIN_LOOP_EQ",SIMPLE_PATH_JOIN_LOOP_EQ;
+"SIMPLE_PATH_LINEAR_IMAGE_EQ",SIMPLE_PATH_LINEAR_IMAGE_EQ;
+"SIMPLE_PATH_LINEPATH",SIMPLE_PATH_LINEPATH;
+"SIMPLE_PATH_LINEPATH_EQ",SIMPLE_PATH_LINEPATH_EQ;
+"SIMPLE_PATH_REVERSEPATH",SIMPLE_PATH_REVERSEPATH;
+"SIMPLE_PATH_SHIFTPATH",SIMPLE_PATH_SHIFTPATH;
+"SIMPLE_PATH_SUBPATH",SIMPLE_PATH_SUBPATH;
+"SIMPLE_PATH_SUBPATH_EQ",SIMPLE_PATH_SUBPATH_EQ;
+"SIMPLE_PATH_SYM",SIMPLE_PATH_SYM;
+"SIMPLE_PATH_TRANSLATION_EQ",SIMPLE_PATH_TRANSLATION_EQ;
+"SIMPLICIAL_COMPLEX_IMP_TRIANGULATION",SIMPLICIAL_COMPLEX_IMP_TRIANGULATION;
+"SIMPLY_CONNECTED_EMPTY",SIMPLY_CONNECTED_EMPTY;
+"SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ALL",SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ALL;
+"SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY",SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY;
+"SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_SOME",SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_SOME;
+"SIMPLY_CONNECTED_EQ_CONTRACTIBLE_PATH",SIMPLY_CONNECTED_EQ_CONTRACTIBLE_PATH;
+"SIMPLY_CONNECTED_EQ_HOMOTOPIC_PATHS",SIMPLY_CONNECTED_EQ_HOMOTOPIC_PATHS;
+"SIMPLY_CONNECTED_IMP_CONNECTED",SIMPLY_CONNECTED_IMP_CONNECTED;
+"SIMPLY_CONNECTED_IMP_PATH_CONNECTED",SIMPLY_CONNECTED_IMP_PATH_CONNECTED;
+"SIMPLY_CONNECTED_INJECTIVE_LINEAR_IMAGE",SIMPLY_CONNECTED_INJECTIVE_LINEAR_IMAGE;
+"SIMPLY_CONNECTED_PCROSS",SIMPLY_CONNECTED_PCROSS;
+"SIMPLY_CONNECTED_PCROSS_EQ",SIMPLY_CONNECTED_PCROSS_EQ;
+"SIMPLY_CONNECTED_RETRACTION_GEN",SIMPLY_CONNECTED_RETRACTION_GEN;
+"SIMPLY_CONNECTED_SPHERE",SIMPLY_CONNECTED_SPHERE;
+"SIMPLY_CONNECTED_TRANSLATION",SIMPLY_CONNECTED_TRANSLATION;
+"SIMPLY_CONNECTED_UNION",SIMPLY_CONNECTED_UNION;
+"SING",SING;
+"SING_GSPEC",SING_GSPEC;
+"SING_SUBSET",SING_SUBSET;
+"SKOLEM_THM",SKOLEM_THM;
+"SND",SND;
+"SNDCART_ADD",SNDCART_ADD;
+"SNDCART_CMUL",SNDCART_CMUL;
+"SNDCART_NEG",SNDCART_NEG;
+"SNDCART_PASTECART",SNDCART_PASTECART;
+"SNDCART_SUB",SNDCART_SUB;
+"SNDCART_VEC",SNDCART_VEC;
+"SNDCART_VSUM",SNDCART_VSUM;
+"SND_DEF",SND_DEF;
+"SPANNING_SUBSET_INDEPENDENT",SPANNING_SUBSET_INDEPENDENT;
+"SPANNING_SURJECTIVE_IMAGE",SPANNING_SURJECTIVE_IMAGE;
+"SPANS_IMAGE",SPANS_IMAGE;
+"SPAN_0",SPAN_0;
+"SPAN_2",SPAN_2;
+"SPAN_3",SPAN_3;
+"SPAN_ADD",SPAN_ADD;
+"SPAN_ADD_EQ",SPAN_ADD_EQ;
+"SPAN_BREAKDOWN",SPAN_BREAKDOWN;
+"SPAN_BREAKDOWN_EQ",SPAN_BREAKDOWN_EQ;
+"SPAN_CARD_GE_DIM",SPAN_CARD_GE_DIM;
+"SPAN_CLAUSES",SPAN_CLAUSES;
+"SPAN_CONVEX_CONE_ALLSIGNS",SPAN_CONVEX_CONE_ALLSIGNS;
+"SPAN_DELETE_0",SPAN_DELETE_0;
+"SPAN_EMPTY",SPAN_EMPTY;
+"SPAN_EQ",SPAN_EQ;
+"SPAN_EQ_DIM",SPAN_EQ_DIM;
+"SPAN_EQ_INSERT",SPAN_EQ_INSERT;
+"SPAN_EQ_SELF",SPAN_EQ_SELF;
+"SPAN_EXPLICIT",SPAN_EXPLICIT;
+"SPAN_FINITE",SPAN_FINITE;
+"SPAN_IMAGE_SCALE",SPAN_IMAGE_SCALE;
+"SPAN_INC",SPAN_INC;
+"SPAN_INDUCT",SPAN_INDUCT;
+"SPAN_INDUCT_ALT",SPAN_INDUCT_ALT;
+"SPAN_INSERT_0",SPAN_INSERT_0;
+"SPAN_LINEAR_IMAGE",SPAN_LINEAR_IMAGE;
+"SPAN_MBASIS",SPAN_MBASIS;
+"SPAN_MONO",SPAN_MONO;
+"SPAN_MUL",SPAN_MUL;
+"SPAN_MUL_EQ",SPAN_MUL_EQ;
+"SPAN_NEG",SPAN_NEG;
+"SPAN_NEG_EQ",SPAN_NEG_EQ;
+"SPAN_NOT_UNIV_ORTHOGONAL",SPAN_NOT_UNIV_ORTHOGONAL;
+"SPAN_NOT_UNIV_SUBSET_HYPERPLANE",SPAN_NOT_UNIV_SUBSET_HYPERPLANE;
+"SPAN_OF_SUBSPACE",SPAN_OF_SUBSPACE;
+"SPAN_OPEN",SPAN_OPEN;
+"SPAN_PCROSS",SPAN_PCROSS;
+"SPAN_PCROSS_SUBSET",SPAN_PCROSS_SUBSET;
+"SPAN_SING",SPAN_SING;
+"SPAN_SPAN",SPAN_SPAN;
+"SPAN_STDBASIS",SPAN_STDBASIS;
+"SPAN_SUB",SPAN_SUB;
+"SPAN_SUBSET_SUBSPACE",SPAN_SUBSET_SUBSPACE;
+"SPAN_SUBSPACE",SPAN_SUBSPACE;
+"SPAN_SUMS",SPAN_SUMS;
+"SPAN_SUPERSET",SPAN_SUPERSET;
+"SPAN_TRANS",SPAN_TRANS;
+"SPAN_UNION",SPAN_UNION;
+"SPAN_UNION_SUBSET",SPAN_UNION_SUBSET;
+"SPAN_UNIV",SPAN_UNIV;
+"SPAN_VSUM",SPAN_VSUM;
+"SPECIAL_HYPERPLANE_SPAN",SPECIAL_HYPERPLANE_SPAN;
+"SPHERE_1",SPHERE_1;
+"SPHERE_EMPTY",SPHERE_EMPTY;
+"SPHERE_EQ_EMPTY",SPHERE_EQ_EMPTY;
+"SPHERE_EQ_SING",SPHERE_EQ_SING;
+"SPHERE_LINEAR_IMAGE",SPHERE_LINEAR_IMAGE;
+"SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE",SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE;
+"SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE_GEN",SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE_GEN;
+"SPHERE_SING",SPHERE_SING;
+"SPHERE_SUBSET_CBALL",SPHERE_SUBSET_CBALL;
+"SPHERE_TRANSLATION",SPHERE_TRANSLATION;
+"SPHERE_UNION_BALL",SPHERE_UNION_BALL;
+"SPLIT_INSIDE_SIMPLE_CLOSED_CURVE",SPLIT_INSIDE_SIMPLE_CLOSED_CURVE;
+"SQNORM_PASTECART",SQNORM_PASTECART;
+"SQRT_0",SQRT_0;
+"SQRT_1",SQRT_1;
+"SQRT_DIV",SQRT_DIV;
+"SQRT_EQ_0",SQRT_EQ_0;
+"SQRT_EVEN_POW2",SQRT_EVEN_POW2;
+"SQRT_INJ",SQRT_INJ;
+"SQRT_INV",SQRT_INV;
+"SQRT_LT_0",SQRT_LT_0;
+"SQRT_MONO_LE",SQRT_MONO_LE;
+"SQRT_MONO_LE_EQ",SQRT_MONO_LE_EQ;
+"SQRT_MONO_LT",SQRT_MONO_LT;
+"SQRT_MONO_LT_EQ",SQRT_MONO_LT_EQ;
+"SQRT_MUL",SQRT_MUL;
+"SQRT_POS_LE",SQRT_POS_LE;
+"SQRT_POS_LT",SQRT_POS_LT;
+"SQRT_POW2",SQRT_POW2;
+"SQRT_POW_2",SQRT_POW_2;
+"SQRT_UNIQUE",SQRT_UNIQUE;
+"SQRT_WORKS",SQRT_WORKS;
+"SQUARE_BOUND_LEMMA",SQUARE_BOUND_LEMMA;
+"SQUARE_CONTINUOUS",SQUARE_CONTINUOUS;
+"STARLIKE_CLOSURE",STARLIKE_CLOSURE;
+"STARLIKE_COMPACT_PROJECTIVE",STARLIKE_COMPACT_PROJECTIVE;
+"STARLIKE_CONVEX_TWEAK_BOUNDARY_POINTS",STARLIKE_CONVEX_TWEAK_BOUNDARY_POINTS;
+"STARLIKE_IMP_CONNECTED",STARLIKE_IMP_CONNECTED;
+"STARLIKE_IMP_CONTRACTIBLE",STARLIKE_IMP_CONTRACTIBLE;
+"STARLIKE_IMP_CONTRACTIBLE_GEN",STARLIKE_IMP_CONTRACTIBLE_GEN;
+"STARLIKE_IMP_PATH_CONNECTED",STARLIKE_IMP_PATH_CONNECTED;
+"STARLIKE_IMP_SIMPLY_CONNECTED",STARLIKE_IMP_SIMPLY_CONNECTED;
+"STARLIKE_LINEAR_IMAGE",STARLIKE_LINEAR_IMAGE;
+"STARLIKE_LINEAR_IMAGE_EQ",STARLIKE_LINEAR_IMAGE_EQ;
+"STARLIKE_NEGLIGIBLE",STARLIKE_NEGLIGIBLE;
+"STARLIKE_NEGLIGIBLE_BOUNDED_MEASURABLE",STARLIKE_NEGLIGIBLE_BOUNDED_MEASURABLE;
+"STARLIKE_NEGLIGIBLE_LEMMA",STARLIKE_NEGLIGIBLE_LEMMA;
+"STARLIKE_NEGLIGIBLE_STRONG",STARLIKE_NEGLIGIBLE_STRONG;
+"STARLIKE_PCROSS",STARLIKE_PCROSS;
+"STARLIKE_PCROSS_EQ",STARLIKE_PCROSS_EQ;
+"STARLIKE_TRANSLATION_EQ",STARLIKE_TRANSLATION_EQ;
+"STARLIKE_UNIV",STARLIKE_UNIV;
+"STD_SIMPLEX",STD_SIMPLEX;
+"STEINHAUS",STEINHAUS;
+"STEINHAUS_LEBESGUE",STEINHAUS_LEBESGUE;
+"STRETCH_GALOIS",STRETCH_GALOIS;
+"SUB",SUB;
+"SUBADDITIVE_CONTENT_DIVISION",SUBADDITIVE_CONTENT_DIVISION;
+"SUBPATH_LINEAR_IMAGE",SUBPATH_LINEAR_IMAGE;
+"SUBPATH_REFL",SUBPATH_REFL;
+"SUBPATH_REVERSEPATH",SUBPATH_REVERSEPATH;
+"SUBPATH_SCALING_LEMMA",SUBPATH_SCALING_LEMMA;
+"SUBPATH_TO_FRONTIER",SUBPATH_TO_FRONTIER;
+"SUBPATH_TO_FRONTIER_EXPLICIT",SUBPATH_TO_FRONTIER_EXPLICIT;
+"SUBPATH_TO_FRONTIER_STRONG",SUBPATH_TO_FRONTIER_STRONG;
+"SUBPATH_TRANSLATION",SUBPATH_TRANSLATION;
+"SUBPATH_TRIVIAL",SUBPATH_TRIVIAL;
+"SUBSEQUENCE_DIAGONALIZATION_LEMMA",SUBSEQUENCE_DIAGONALIZATION_LEMMA;
+"SUBSET",SUBSET;
+"SUBSET_ANTISYM",SUBSET_ANTISYM;
+"SUBSET_ANTISYM_EQ",SUBSET_ANTISYM_EQ;
+"SUBSET_BALL",SUBSET_BALL;
+"SUBSET_BALLS",SUBSET_BALLS;
+"SUBSET_CARD_EQ",SUBSET_CARD_EQ;
+"SUBSET_CBALL",SUBSET_CBALL;
+"SUBSET_CLOSURE",SUBSET_CLOSURE;
+"SUBSET_CONTINUOUS_IMAGE_SEGMENT_1",SUBSET_CONTINUOUS_IMAGE_SEGMENT_1;
+"SUBSET_DELETE",SUBSET_DELETE;
+"SUBSET_DIFF",SUBSET_DIFF;
+"SUBSET_DROP_IMAGE",SUBSET_DROP_IMAGE;
+"SUBSET_EMPTY",SUBSET_EMPTY;
+"SUBSET_FACE_OF_SIMPLEX",SUBSET_FACE_OF_SIMPLEX;
+"SUBSET_HULL",SUBSET_HULL;
+"SUBSET_HYPERPLANES",SUBSET_HYPERPLANES;
+"SUBSET_IMAGE",SUBSET_IMAGE;
+"SUBSET_INSERT",SUBSET_INSERT;
+"SUBSET_INSERT_DELETE",SUBSET_INSERT_DELETE;
+"SUBSET_INTER",SUBSET_INTER;
+"SUBSET_INTERIOR",SUBSET_INTERIOR;
+"SUBSET_INTERS",SUBSET_INTERS;
+"SUBSET_INTERVAL",SUBSET_INTERVAL;
+"SUBSET_INTERVAL_1",SUBSET_INTERVAL_1;
+"SUBSET_INTERVAL_IMP",SUBSET_INTERVAL_IMP;
+"SUBSET_INTER_ABSORPTION",SUBSET_INTER_ABSORPTION;
+"SUBSET_LE_DIM",SUBSET_LE_DIM;
+"SUBSET_LIFT_IMAGE",SUBSET_LIFT_IMAGE;
+"SUBSET_NUMSEG",SUBSET_NUMSEG;
+"SUBSET_OF_FACE_OF",SUBSET_OF_FACE_OF;
+"SUBSET_PATH_IMAGE_JOIN",SUBSET_PATH_IMAGE_JOIN;
+"SUBSET_PCROSS",SUBSET_PCROSS;
+"SUBSET_PRED",SUBSET_PRED;
+"SUBSET_PSUBSET_TRANS",SUBSET_PSUBSET_TRANS;
+"SUBSET_REFL",SUBSET_REFL;
+"SUBSET_RELATIVE_INTERIOR",SUBSET_RELATIVE_INTERIOR;
+"SUBSET_RESTRICT",SUBSET_RESTRICT;
+"SUBSET_SECOND_COUNTABLE",SUBSET_SECOND_COUNTABLE;
+"SUBSET_SEGMENT",SUBSET_SEGMENT;
+"SUBSET_SEGMENT_OPEN_CLOSED",SUBSET_SEGMENT_OPEN_CLOSED;
+"SUBSET_TRANS",SUBSET_TRANS;
+"SUBSET_UNION",SUBSET_UNION;
+"SUBSET_UNIONS",SUBSET_UNIONS;
+"SUBSET_UNION_ABSORPTION",SUBSET_UNION_ABSORPTION;
+"SUBSET_UNIV",SUBSET_UNIV;
+"SUBSPACE_0",SUBSPACE_0;
+"SUBSPACE_ADD",SUBSPACE_ADD;
+"SUBSPACE_BOUNDED_EQ_TRIVIAL",SUBSPACE_BOUNDED_EQ_TRIVIAL;
+"SUBSPACE_CONVEX_CONE_SYMMETRIC",SUBSPACE_CONVEX_CONE_SYMMETRIC;
+"SUBSPACE_HYPERPLANE",SUBSPACE_HYPERPLANE;
+"SUBSPACE_IMP_AFFINE",SUBSPACE_IMP_AFFINE;
+"SUBSPACE_IMP_CONIC",SUBSPACE_IMP_CONIC;
+"SUBSPACE_IMP_CONVEX",SUBSPACE_IMP_CONVEX;
+"SUBSPACE_IMP_CONVEX_CONE",SUBSPACE_IMP_CONVEX_CONE;
+"SUBSPACE_IMP_NONEMPTY",SUBSPACE_IMP_NONEMPTY;
+"SUBSPACE_INTER",SUBSPACE_INTER;
+"SUBSPACE_INTERS",SUBSPACE_INTERS;
+"SUBSPACE_ISOMORPHISM",SUBSPACE_ISOMORPHISM;
+"SUBSPACE_KERNEL",SUBSPACE_KERNEL;
+"SUBSPACE_LINEAR_FIXED_POINTS",SUBSPACE_LINEAR_FIXED_POINTS;
+"SUBSPACE_LINEAR_IMAGE",SUBSPACE_LINEAR_IMAGE;
+"SUBSPACE_LINEAR_IMAGE_EQ",SUBSPACE_LINEAR_IMAGE_EQ;
+"SUBSPACE_LINEAR_PREIMAGE",SUBSPACE_LINEAR_PREIMAGE;
+"SUBSPACE_MUL",SUBSPACE_MUL;
+"SUBSPACE_NEG",SUBSPACE_NEG;
+"SUBSPACE_ORTHOGONAL_TO_VECTOR",SUBSPACE_ORTHOGONAL_TO_VECTOR;
+"SUBSPACE_ORTHOGONAL_TO_VECTORS",SUBSPACE_ORTHOGONAL_TO_VECTORS;
+"SUBSPACE_PCROSS",SUBSPACE_PCROSS;
+"SUBSPACE_PCROSS_EQ",SUBSPACE_PCROSS_EQ;
+"SUBSPACE_SPAN",SUBSPACE_SPAN;
+"SUBSPACE_SPECIAL_HYPERPLANE",SUBSPACE_SPECIAL_HYPERPLANE;
+"SUBSPACE_SUB",SUBSPACE_SUB;
+"SUBSPACE_SUBSTANDARD",SUBSPACE_SUBSTANDARD;
+"SUBSPACE_SUMS",SUBSPACE_SUMS;
+"SUBSPACE_TRANSLATION_SELF",SUBSPACE_TRANSLATION_SELF;
+"SUBSPACE_TRANSLATION_SELF_EQ",SUBSPACE_TRANSLATION_SELF_EQ;
+"SUBSPACE_TRIVIAL",SUBSPACE_TRIVIAL;
+"SUBSPACE_UNION_CHAIN",SUBSPACE_UNION_CHAIN;
+"SUBSPACE_UNIV",SUBSPACE_UNIV;
+"SUBSPACE_VSUM",SUBSPACE_VSUM;
+"SUBTOPOLOGY_SUPERSET",SUBTOPOLOGY_SUPERSET;
+"SUBTOPOLOGY_TOPSPACE",SUBTOPOLOGY_TOPSPACE;
+"SUBTOPOLOGY_UNIV",SUBTOPOLOGY_UNIV;
+"SUB_0",SUB_0;
+"SUB_ADD",SUB_ADD;
+"SUB_ADD_LCANCEL",SUB_ADD_LCANCEL;
+"SUB_ADD_RCANCEL",SUB_ADD_RCANCEL;
+"SUB_ELIM_THM",SUB_ELIM_THM;
+"SUB_ELIM_THM'",SUB_ELIM_THM';
+"SUB_EQ_0",SUB_EQ_0;
+"SUB_PRESUC",SUB_PRESUC;
+"SUB_REFL",SUB_REFL;
+"SUB_SUC",SUB_SUC;
+"SUC_DEF",SUC_DEF;
+"SUC_INJ",SUC_INJ;
+"SUC_SUB1",SUC_SUB1;
+"SUMMABLE_0",SUMMABLE_0;
+"SUMMABLE_ADD",SUMMABLE_ADD;
+"SUMMABLE_BILINEAR_PARTIAL_PRE",SUMMABLE_BILINEAR_PARTIAL_PRE;
+"SUMMABLE_CAUCHY",SUMMABLE_CAUCHY;
+"SUMMABLE_CMUL",SUMMABLE_CMUL;
+"SUMMABLE_COMPARISON",SUMMABLE_COMPARISON;
+"SUMMABLE_COMPONENT",SUMMABLE_COMPONENT;
+"SUMMABLE_EQ",SUMMABLE_EQ;
+"SUMMABLE_EQ_COFINITE",SUMMABLE_EQ_COFINITE;
+"SUMMABLE_EQ_EVENTUALLY",SUMMABLE_EQ_EVENTUALLY;
+"SUMMABLE_FROM_ELSEWHERE",SUMMABLE_FROM_ELSEWHERE;
+"SUMMABLE_IFF",SUMMABLE_IFF;
+"SUMMABLE_IFF_COFINITE",SUMMABLE_IFF_COFINITE;
+"SUMMABLE_IFF_EVENTUALLY",SUMMABLE_IFF_EVENTUALLY;
+"SUMMABLE_IMP_BOUNDED",SUMMABLE_IMP_BOUNDED;
+"SUMMABLE_IMP_SUMS_BOUNDED",SUMMABLE_IMP_SUMS_BOUNDED;
+"SUMMABLE_IMP_TOZERO",SUMMABLE_IMP_TOZERO;
+"SUMMABLE_LINEAR",SUMMABLE_LINEAR;
+"SUMMABLE_NEG",SUMMABLE_NEG;
+"SUMMABLE_REARRANGE",SUMMABLE_REARRANGE;
+"SUMMABLE_REINDEX",SUMMABLE_REINDEX;
+"SUMMABLE_RESTRICT",SUMMABLE_RESTRICT;
+"SUMMABLE_SUB",SUMMABLE_SUB;
+"SUMMABLE_SUBSET",SUMMABLE_SUBSET;
+"SUMMABLE_SUBSET_ABSCONV",SUMMABLE_SUBSET_ABSCONV;
+"SUMMABLE_TRIVIAL",SUMMABLE_TRIVIAL;
+"SUMS_0",SUMS_0;
+"SUMS_EQ",SUMS_EQ;
+"SUMS_FINITE_DIFF",SUMS_FINITE_DIFF;
+"SUMS_FINITE_UNION",SUMS_FINITE_UNION;
+"SUMS_IFF",SUMS_IFF;
+"SUMS_INFSUM",SUMS_INFSUM;
+"SUMS_INTERVALS",SUMS_INTERVALS;
+"SUMS_LIM",SUMS_LIM;
+"SUMS_OFFSET",SUMS_OFFSET;
+"SUMS_OFFSET_REV",SUMS_OFFSET_REV;
+"SUMS_REINDEX",SUMS_REINDEX;
+"SUMS_SUMMABLE",SUMS_SUMMABLE;
+"SUM_0",SUM_0;
+"SUM_1",SUM_1;
+"SUM_2",SUM_2;
+"SUM_3",SUM_3;
+"SUM_4",SUM_4;
+"SUM_ABS",SUM_ABS;
+"SUM_ABS_BOUND",SUM_ABS_BOUND;
+"SUM_ABS_LE",SUM_ABS_LE;
+"SUM_ABS_NUMSEG",SUM_ABS_NUMSEG;
+"SUM_ADD",SUM_ADD;
+"SUM_ADD_GEN",SUM_ADD_GEN;
+"SUM_ADD_NUMSEG",SUM_ADD_NUMSEG;
+"SUM_ADD_SPLIT",SUM_ADD_SPLIT;
+"SUM_BIJECTION",SUM_BIJECTION;
+"SUM_BOUND",SUM_BOUND;
+"SUM_BOUND_GEN",SUM_BOUND_GEN;
+"SUM_BOUND_LT",SUM_BOUND_LT;
+"SUM_BOUND_LT_ALL",SUM_BOUND_LT_ALL;
+"SUM_BOUND_LT_GEN",SUM_BOUND_LT_GEN;
+"SUM_CASES",SUM_CASES;
+"SUM_CASES_1",SUM_CASES_1;
+"SUM_CLAUSES",SUM_CLAUSES;
+"SUM_CLAUSES_LEFT",SUM_CLAUSES_LEFT;
+"SUM_CLAUSES_NUMSEG",SUM_CLAUSES_NUMSEG;
+"SUM_CLAUSES_RIGHT",SUM_CLAUSES_RIGHT;
+"SUM_CLOSED",SUM_CLOSED;
+"SUM_COMBINE_L",SUM_COMBINE_L;
+"SUM_COMBINE_R",SUM_COMBINE_R;
+"SUM_CONST",SUM_CONST;
+"SUM_CONST_NUMSEG",SUM_CONST_NUMSEG;
+"SUM_CONTENT_AREA_OVER_THIN_DIVISION",SUM_CONTENT_AREA_OVER_THIN_DIVISION;
+"SUM_DELETE",SUM_DELETE;
+"SUM_DELETE_CASES",SUM_DELETE_CASES;
+"SUM_DELTA",SUM_DELTA;
+"SUM_DIFF",SUM_DIFF;
+"SUM_DIFFS",SUM_DIFFS;
+"SUM_DIFFS_ALT",SUM_DIFFS_ALT;
+"SUM_EQ",SUM_EQ;
+"SUM_EQ_0",SUM_EQ_0;
+"SUM_EQ_0_NUMSEG",SUM_EQ_0_NUMSEG;
+"SUM_EQ_GENERAL",SUM_EQ_GENERAL;
+"SUM_EQ_GENERAL_INVERSES",SUM_EQ_GENERAL_INVERSES;
+"SUM_EQ_NUMSEG",SUM_EQ_NUMSEG;
+"SUM_EQ_SUPERSET",SUM_EQ_SUPERSET;
+"SUM_GP",SUM_GP;
+"SUM_GP_BASIC",SUM_GP_BASIC;
+"SUM_GP_MULTIPLIED",SUM_GP_MULTIPLIED;
+"SUM_GP_OFFSET",SUM_GP_OFFSET;
+"SUM_GROUP",SUM_GROUP;
+"SUM_IMAGE",SUM_IMAGE;
+"SUM_IMAGE_GEN",SUM_IMAGE_GEN;
+"SUM_IMAGE_LE",SUM_IMAGE_LE;
+"SUM_IMAGE_NONZERO",SUM_IMAGE_NONZERO;
+"SUM_INCL_EXCL",SUM_INCL_EXCL;
+"SUM_INJECTION",SUM_INJECTION;
+"SUM_LE",SUM_LE;
+"SUM_LE_INCLUDED",SUM_LE_INCLUDED;
+"SUM_LE_NUMSEG",SUM_LE_NUMSEG;
+"SUM_LMUL",SUM_LMUL;
+"SUM_LT",SUM_LT;
+"SUM_LT_ALL",SUM_LT_ALL;
+"SUM_MULTICOUNT",SUM_MULTICOUNT;
+"SUM_MULTICOUNT_GEN",SUM_MULTICOUNT_GEN;
+"SUM_NEG",SUM_NEG;
+"SUM_OFFSET",SUM_OFFSET;
+"SUM_OFFSET_0",SUM_OFFSET_0;
+"SUM_OVER_PERMUTATIONS_INSERT",SUM_OVER_PERMUTATIONS_INSERT;
+"SUM_OVER_PERMUTATIONS_NUMSEG",SUM_OVER_PERMUTATIONS_NUMSEG;
+"SUM_OVER_TAGGED_DIVISION_LEMMA",SUM_OVER_TAGGED_DIVISION_LEMMA;
+"SUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA",SUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA;
+"SUM_PAIR",SUM_PAIR;
+"SUM_PARTIAL_PRE",SUM_PARTIAL_PRE;
+"SUM_PARTIAL_SUC",SUM_PARTIAL_SUC;
+"SUM_PERMUTATIONS_COMPOSE_L",SUM_PERMUTATIONS_COMPOSE_L;
+"SUM_PERMUTATIONS_COMPOSE_R",SUM_PERMUTATIONS_COMPOSE_R;
+"SUM_PERMUTATIONS_INVERSE",SUM_PERMUTATIONS_INVERSE;
+"SUM_PERMUTE",SUM_PERMUTE;
+"SUM_PERMUTE_NUMSEG",SUM_PERMUTE_NUMSEG;
+"SUM_POS_BOUND",SUM_POS_BOUND;
+"SUM_POS_EQ_0",SUM_POS_EQ_0;
+"SUM_POS_EQ_0_NUMSEG",SUM_POS_EQ_0_NUMSEG;
+"SUM_POS_LE",SUM_POS_LE;
+"SUM_POS_LE_NUMSEG",SUM_POS_LE_NUMSEG;
+"SUM_POS_LT",SUM_POS_LT;
+"SUM_RESTRICT",SUM_RESTRICT;
+"SUM_RESTRICT_SET",SUM_RESTRICT_SET;
+"SUM_RMUL",SUM_RMUL;
+"SUM_SING",SUM_SING;
+"SUM_SING_NUMSEG",SUM_SING_NUMSEG;
+"SUM_SUB",SUM_SUB;
+"SUM_SUBSET",SUM_SUBSET;
+"SUM_SUBSET_SIMPLE",SUM_SUBSET_SIMPLE;
+"SUM_SUB_NUMSEG",SUM_SUB_NUMSEG;
+"SUM_SUM_PRODUCT",SUM_SUM_PRODUCT;
+"SUM_SUM_RESTRICT",SUM_SUM_RESTRICT;
+"SUM_SUPERSET",SUM_SUPERSET;
+"SUM_SUPPORT",SUM_SUPPORT;
+"SUM_SWAP",SUM_SWAP;
+"SUM_SWAP_NUMSEG",SUM_SWAP_NUMSEG;
+"SUM_TRIV_NUMSEG",SUM_TRIV_NUMSEG;
+"SUM_UNION",SUM_UNION;
+"SUM_UNIONS_NONZERO",SUM_UNIONS_NONZERO;
+"SUM_UNION_EQ",SUM_UNION_EQ;
+"SUM_UNION_LZERO",SUM_UNION_LZERO;
+"SUM_UNION_NONZERO",SUM_UNION_NONZERO;
+"SUM_UNION_RZERO",SUM_UNION_RZERO;
+"SUM_VSUM",SUM_VSUM;
+"SUM_ZERO_EXISTS",SUM_ZERO_EXISTS;
+"SUP",SUP;
+"SUPERADMISSIBLE_COND",SUPERADMISSIBLE_COND;
+"SUPERADMISSIBLE_CONST",SUPERADMISSIBLE_CONST;
+"SUPERADMISSIBLE_MATCH_GUARDED_PATTERN",SUPERADMISSIBLE_MATCH_GUARDED_PATTERN;
+"SUPERADMISSIBLE_MATCH_SEQPATTERN",SUPERADMISSIBLE_MATCH_SEQPATTERN;
+"SUPERADMISSIBLE_MATCH_UNGUARDED_PATTERN",SUPERADMISSIBLE_MATCH_UNGUARDED_PATTERN;
+"SUPERADMISSIBLE_T",SUPERADMISSIBLE_T;
+"SUPERADMISSIBLE_TAIL",SUPERADMISSIBLE_TAIL;
+"SUPPORTING_HYPERPLANE_CLOSED_POINT",SUPPORTING_HYPERPLANE_CLOSED_POINT;
+"SUPPORTING_HYPERPLANE_COMPACT_POINT_INF",SUPPORTING_HYPERPLANE_COMPACT_POINT_INF;
+"SUPPORTING_HYPERPLANE_COMPACT_POINT_SUP",SUPPORTING_HYPERPLANE_COMPACT_POINT_SUP;
+"SUPPORTING_HYPERPLANE_RELATIVE_BOUNDARY",SUPPORTING_HYPERPLANE_RELATIVE_BOUNDARY;
+"SUPPORTING_HYPERPLANE_RELATIVE_FRONTIER",SUPPORTING_HYPERPLANE_RELATIVE_FRONTIER;
+"SUPPORT_CLAUSES",SUPPORT_CLAUSES;
+"SUPPORT_DELTA",SUPPORT_DELTA;
+"SUPPORT_EMPTY",SUPPORT_EMPTY;
+"SUPPORT_SUBSET",SUPPORT_SUBSET;
+"SUPPORT_SUPPORT",SUPPORT_SUPPORT;
+"SUP_EQ",SUP_EQ;
+"SUP_FINITE",SUP_FINITE;
+"SUP_FINITE_LEMMA",SUP_FINITE_LEMMA;
+"SUP_INSERT",SUP_INSERT;
+"SUP_INSERT_FINITE",SUP_INSERT_FINITE;
+"SUP_SING",SUP_SING;
+"SUP_UNIQUE_FINITE",SUP_UNIQUE_FINITE;
+"SURA_BURA_CLOSED",SURA_BURA_CLOSED;
+"SURA_BURA_COMPACT",SURA_BURA_COMPACT;
+"SURJ",SURJ;
+"SURJECTIVE_EXISTS_THM",SURJECTIVE_EXISTS_THM;
+"SURJECTIVE_FORALL_THM",SURJECTIVE_FORALL_THM;
+"SURJECTIVE_IFF_INJECTIVE",SURJECTIVE_IFF_INJECTIVE;
+"SURJECTIVE_IFF_INJECTIVE_GEN",SURJECTIVE_IFF_INJECTIVE_GEN;
+"SURJECTIVE_IMAGE",SURJECTIVE_IMAGE;
+"SURJECTIVE_IMAGE_EQ",SURJECTIVE_IMAGE_EQ;
+"SURJECTIVE_IMAGE_THM",SURJECTIVE_IMAGE_THM;
+"SURJECTIVE_INVERSE",SURJECTIVE_INVERSE;
+"SURJECTIVE_INVERSE_o",SURJECTIVE_INVERSE_o;
+"SURJECTIVE_MAP",SURJECTIVE_MAP;
+"SURJECTIVE_ON_IMAGE",SURJECTIVE_ON_IMAGE;
+"SURJECTIVE_ON_RIGHT_INVERSE",SURJECTIVE_ON_RIGHT_INVERSE;
+"SURJECTIVE_RIGHT_INVERSE",SURJECTIVE_RIGHT_INVERSE;
+"SURJECTIVE_SCALING",SURJECTIVE_SCALING;
+"SUSSMANN_OPEN_MAPPING",SUSSMANN_OPEN_MAPPING;
+"SWAPSEQ_COMPOSE",SWAPSEQ_COMPOSE;
+"SWAPSEQ_ENDSWAP",SWAPSEQ_ENDSWAP;
+"SWAPSEQ_EVEN_EVEN",SWAPSEQ_EVEN_EVEN;
+"SWAPSEQ_I",SWAPSEQ_I;
+"SWAPSEQ_IDENTITY_EVEN",SWAPSEQ_IDENTITY_EVEN;
+"SWAPSEQ_INVERSE",SWAPSEQ_INVERSE;
+"SWAPSEQ_INVERSE_EXISTS",SWAPSEQ_INVERSE_EXISTS;
+"SWAPSEQ_SWAP",SWAPSEQ_SWAP;
+"SWAP_COMMON",SWAP_COMMON;
+"SWAP_COMMON'",SWAP_COMMON';
+"SWAP_EXISTS_THM",SWAP_EXISTS_THM;
+"SWAP_FORALL_THM",SWAP_FORALL_THM;
+"SWAP_GALOIS",SWAP_GALOIS;
+"SWAP_GENERAL",SWAP_GENERAL;
+"SWAP_IDEMPOTENT",SWAP_IDEMPOTENT;
+"SWAP_INDEPENDENT",SWAP_INDEPENDENT;
+"SWAP_REFL",SWAP_REFL;
+"SWAP_SYM",SWAP_SYM;
+"SYLVESTER_DETERMINANT_IDENTITY",SYLVESTER_DETERMINANT_IDENTITY;
+"SYMDIFF_PARITY_LEMMA",SYMDIFF_PARITY_LEMMA;
+"SYMMETRIC_CLOSURE",SYMMETRIC_CLOSURE;
+"SYMMETRIC_INTERIOR",SYMMETRIC_INTERIOR;
+"SYMMETRIC_LINEAR_IMAGE",SYMMETRIC_LINEAR_IMAGE;
+"SYMMETRIC_MATRIX",SYMMETRIC_MATRIX;
+"SYMMETRIC_MATRIX_DIAGONALIZABLE_EXPLICIT",SYMMETRIC_MATRIX_DIAGONALIZABLE_EXPLICIT;
+"SYMMETRIC_MATRIX_EQ_DIAGONALIZABLE",SYMMETRIC_MATRIX_EQ_DIAGONALIZABLE;
+"SYMMETRIC_MATRIX_IMP_DIAGONALIZABLE",SYMMETRIC_MATRIX_IMP_DIAGONALIZABLE;
+"SYMMETRIC_MATRIX_MUL",SYMMETRIC_MATRIX_MUL;
+"SYMMETRIC_MATRIX_ORTHOGONAL_EIGENVECTORS",SYMMETRIC_MATRIX_ORTHOGONAL_EIGENVECTORS;
+"SYMMETRIX_MATRIX_CONJUGATE",SYMMETRIX_MATRIX_CONJUGATE;
+"SYMMETRY_LEMMA",SYMMETRY_LEMMA;
+"TAGGED_DIVISION_FINER",TAGGED_DIVISION_FINER;
+"TAGGED_DIVISION_OF",TAGGED_DIVISION_OF;
+"TAGGED_DIVISION_OF_ALT",TAGGED_DIVISION_OF_ALT;
+"TAGGED_DIVISION_OF_ANOTHER",TAGGED_DIVISION_OF_ANOTHER;
+"TAGGED_DIVISION_OF_EMPTY",TAGGED_DIVISION_OF_EMPTY;
+"TAGGED_DIVISION_OF_FINITE",TAGGED_DIVISION_OF_FINITE;
+"TAGGED_DIVISION_OF_NONTRIVIAL",TAGGED_DIVISION_OF_NONTRIVIAL;
+"TAGGED_DIVISION_OF_SELF",TAGGED_DIVISION_OF_SELF;
+"TAGGED_DIVISION_OF_TRIVIAL",TAGGED_DIVISION_OF_TRIVIAL;
+"TAGGED_DIVISION_OF_UNION_SELF",TAGGED_DIVISION_OF_UNION_SELF;
+"TAGGED_DIVISION_SPLIT_LEFT_INJ",TAGGED_DIVISION_SPLIT_LEFT_INJ;
+"TAGGED_DIVISION_SPLIT_RIGHT_INJ",TAGGED_DIVISION_SPLIT_RIGHT_INJ;
+"TAGGED_DIVISION_UNION",TAGGED_DIVISION_UNION;
+"TAGGED_DIVISION_UNIONS",TAGGED_DIVISION_UNIONS;
+"TAGGED_DIVISION_UNIONS_EXISTS",TAGGED_DIVISION_UNIONS_EXISTS;
+"TAGGED_DIVISION_UNION_IMAGE_SND",TAGGED_DIVISION_UNION_IMAGE_SND;
+"TAGGED_DIVISION_UNION_INTERVAL",TAGGED_DIVISION_UNION_INTERVAL;
+"TAGGED_PARTIAL_DIVISION_COMMON_POINT_BOUND",TAGGED_PARTIAL_DIVISION_COMMON_POINT_BOUND;
+"TAGGED_PARTIAL_DIVISION_COMMON_TAGS",TAGGED_PARTIAL_DIVISION_COMMON_TAGS;
+"TAGGED_PARTIAL_DIVISION_OF_SUBSET",TAGGED_PARTIAL_DIVISION_OF_SUBSET;
+"TAGGED_PARTIAL_DIVISION_OF_TRIVIAL",TAGGED_PARTIAL_DIVISION_OF_TRIVIAL;
+"TAGGED_PARTIAL_DIVISION_OF_UNION_SELF",TAGGED_PARTIAL_DIVISION_OF_UNION_SELF;
+"TAGGED_PARTIAL_DIVISION_SUBSET",TAGGED_PARTIAL_DIVISION_SUBSET;
+"TAG_IN_INTERVAL",TAG_IN_INTERVAL;
+"TARSKI_SET",TARSKI_SET;
+"TENDSTO_LIM",TENDSTO_LIM;
+"TIETZE",TIETZE;
+"TIETZE_CLOSED_INTERVAL",TIETZE_CLOSED_INTERVAL;
+"TIETZE_CLOSED_INTERVAL_1",TIETZE_CLOSED_INTERVAL_1;
+"TIETZE_OPEN_INTERVAL",TIETZE_OPEN_INTERVAL;
+"TIETZE_OPEN_INTERVAL_1",TIETZE_OPEN_INTERVAL_1;
+"TIETZE_STEP",TIETZE_STEP;
+"TIETZE_UNBOUNDED",TIETZE_UNBOUNDED;
+"TIETZE_UNBOUNDED_1",TIETZE_UNBOUNDED_1;
+"TL",TL;
+"TOPOLOGICAL_SORT",TOPOLOGICAL_SORT;
+"TOPOLOGY_EQ",TOPOLOGY_EQ;
+"TOPSPACE_EUCLIDEAN",TOPSPACE_EUCLIDEAN;
+"TOPSPACE_EUCLIDEAN_SUBTOPOLOGY",TOPSPACE_EUCLIDEAN_SUBTOPOLOGY;
+"TOPSPACE_SUBTOPOLOGY",TOPSPACE_SUBTOPOLOGY;
+"TRACE_0",TRACE_0;
+"TRACE_ADD",TRACE_ADD;
+"TRACE_CONJUGATE",TRACE_CONJUGATE;
+"TRACE_I",TRACE_I;
+"TRACE_MUL_SYM",TRACE_MUL_SYM;
+"TRACE_SUB",TRACE_SUB;
+"TRACE_TRANSP",TRACE_TRANSP;
+"TRANSITIVE_STEPWISE_LE",TRANSITIVE_STEPWISE_LE;
+"TRANSITIVE_STEPWISE_LE_EQ",TRANSITIVE_STEPWISE_LE_EQ;
+"TRANSITIVE_STEPWISE_LT",TRANSITIVE_STEPWISE_LT;
+"TRANSITIVE_STEPWISE_LT_EQ",TRANSITIVE_STEPWISE_LT_EQ;
+"TRANSLATION_DIFF",TRANSLATION_DIFF;
+"TRANSLATION_EQ_IMP",TRANSLATION_EQ_IMP;
+"TRANSLATION_GALOIS",TRANSLATION_GALOIS;
+"TRANSLATION_UNIV",TRANSLATION_UNIV;
+"TRANSP_COLUMNVECTOR",TRANSP_COLUMNVECTOR;
+"TRANSP_COMPONENT",TRANSP_COMPONENT;
+"TRANSP_DIAGONAL_MATRIX",TRANSP_DIAGONAL_MATRIX;
+"TRANSP_EQ",TRANSP_EQ;
+"TRANSP_MAT",TRANSP_MAT;
+"TRANSP_MATRIX_ADD",TRANSP_MATRIX_ADD;
+"TRANSP_MATRIX_CMUL",TRANSP_MATRIX_CMUL;
+"TRANSP_MATRIX_NEG",TRANSP_MATRIX_NEG;
+"TRANSP_MATRIX_SUB",TRANSP_MATRIX_SUB;
+"TRANSP_ROWVECTOR",TRANSP_ROWVECTOR;
+"TRANSP_TRANSP",TRANSP_TRANSP;
+"TREAL_ADD_ASSOC",TREAL_ADD_ASSOC;
+"TREAL_ADD_LDISTRIB",TREAL_ADD_LDISTRIB;
+"TREAL_ADD_LID",TREAL_ADD_LID;
+"TREAL_ADD_LINV",TREAL_ADD_LINV;
+"TREAL_ADD_SYM",TREAL_ADD_SYM;
+"TREAL_ADD_SYM_EQ",TREAL_ADD_SYM_EQ;
+"TREAL_ADD_WELLDEF",TREAL_ADD_WELLDEF;
+"TREAL_ADD_WELLDEFR",TREAL_ADD_WELLDEFR;
+"TREAL_EQ_AP",TREAL_EQ_AP;
+"TREAL_EQ_IMP_LE",TREAL_EQ_IMP_LE;
+"TREAL_EQ_REFL",TREAL_EQ_REFL;
+"TREAL_EQ_SYM",TREAL_EQ_SYM;
+"TREAL_EQ_TRANS",TREAL_EQ_TRANS;
+"TREAL_INV_0",TREAL_INV_0;
+"TREAL_INV_WELLDEF",TREAL_INV_WELLDEF;
+"TREAL_LE_ANTISYM",TREAL_LE_ANTISYM;
+"TREAL_LE_LADD_IMP",TREAL_LE_LADD_IMP;
+"TREAL_LE_MUL",TREAL_LE_MUL;
+"TREAL_LE_REFL",TREAL_LE_REFL;
+"TREAL_LE_TOTAL",TREAL_LE_TOTAL;
+"TREAL_LE_TRANS",TREAL_LE_TRANS;
+"TREAL_LE_WELLDEF",TREAL_LE_WELLDEF;
+"TREAL_MUL_ASSOC",TREAL_MUL_ASSOC;
+"TREAL_MUL_LID",TREAL_MUL_LID;
+"TREAL_MUL_LINV",TREAL_MUL_LINV;
+"TREAL_MUL_SYM",TREAL_MUL_SYM;
+"TREAL_MUL_SYM_EQ",TREAL_MUL_SYM_EQ;
+"TREAL_MUL_WELLDEF",TREAL_MUL_WELLDEF;
+"TREAL_MUL_WELLDEFR",TREAL_MUL_WELLDEFR;
+"TREAL_NEG_WELLDEF",TREAL_NEG_WELLDEF;
+"TREAL_OF_NUM_ADD",TREAL_OF_NUM_ADD;
+"TREAL_OF_NUM_EQ",TREAL_OF_NUM_EQ;
+"TREAL_OF_NUM_LE",TREAL_OF_NUM_LE;
+"TREAL_OF_NUM_MUL",TREAL_OF_NUM_MUL;
+"TREAL_OF_NUM_WELLDEF",TREAL_OF_NUM_WELLDEF;
+"TRIANGLE_LEMMA",TRIANGLE_LEMMA;
+"TRIANGULATION_INTER_SIMPLEX",TRIANGULATION_INTER_SIMPLEX;
+"TRIANGULATION_SIMPLICIAL_COMPLEX",TRIANGULATION_SIMPLICIAL_COMPLEX;
+"TRIANGULATION_UNION",TRIANGULATION_UNION;
+"TRIVIAL_LIMIT_AT",TRIVIAL_LIMIT_AT;
+"TRIVIAL_LIMIT_AT_INFINITY",TRIVIAL_LIMIT_AT_INFINITY;
+"TRIVIAL_LIMIT_SEQUENTIALLY",TRIVIAL_LIMIT_SEQUENTIALLY;
+"TRIVIAL_LIMIT_WITHIN",TRIVIAL_LIMIT_WITHIN;
+"TRIVIAL_LIMIT_WITHIN_CONVEX",TRIVIAL_LIMIT_WITHIN_CONVEX;
+"TRIV_AND_EXISTS_THM",TRIV_AND_EXISTS_THM;
+"TRIV_EXISTS_AND_THM",TRIV_EXISTS_AND_THM;
+"TRIV_EXISTS_IMP_THM",TRIV_EXISTS_IMP_THM;
+"TRIV_FORALL_IMP_THM",TRIV_FORALL_IMP_THM;
+"TRIV_FORALL_OR_THM",TRIV_FORALL_OR_THM;
+"TRIV_OR_FORALL_THM",TRIV_OR_FORALL_THM;
+"TRUTH",TRUTH;
+"TUBE_LEMMA",TUBE_LEMMA;
+"TWO",TWO;
+"T_DEF",T_DEF;
+"UNBOUNDED_COMPONENTS_COMPLEMENT_ABSOLUTE_RETRACT",UNBOUNDED_COMPONENTS_COMPLEMENT_ABSOLUTE_RETRACT;
+"UNBOUNDED_CONVEX_CLOSED_CONTAINS_RAY",UNBOUNDED_CONVEX_CLOSED_CONTAINS_RAY;
+"UNBOUNDED_CONVEX_CLOSED_CONTAINS_RAYS",UNBOUNDED_CONVEX_CLOSED_CONTAINS_RAYS;
+"UNBOUNDED_HALFSPACE_COMPONENT_GE",UNBOUNDED_HALFSPACE_COMPONENT_GE;
+"UNBOUNDED_HALFSPACE_COMPONENT_GT",UNBOUNDED_HALFSPACE_COMPONENT_GT;
+"UNBOUNDED_HALFSPACE_COMPONENT_LE",UNBOUNDED_HALFSPACE_COMPONENT_LE;
+"UNBOUNDED_HALFSPACE_COMPONENT_LT",UNBOUNDED_HALFSPACE_COMPONENT_LT;
+"UNBOUNDED_INTER_COBOUNDED",UNBOUNDED_INTER_COBOUNDED;
+"UNBOUNDED_OUTSIDE",UNBOUNDED_OUTSIDE;
+"UNCOUNTABLE_CONNECTED",UNCOUNTABLE_CONNECTED;
+"UNCOUNTABLE_CONTAINS_LIMIT_POINT",UNCOUNTABLE_CONTAINS_LIMIT_POINT;
+"UNCOUNTABLE_CONVEX",UNCOUNTABLE_CONVEX;
+"UNCOUNTABLE_EUCLIDEAN",UNCOUNTABLE_EUCLIDEAN;
+"UNCOUNTABLE_HAS_CONDENSATION_POINT",UNCOUNTABLE_HAS_CONDENSATION_POINT;
+"UNCOUNTABLE_INTERVAL",UNCOUNTABLE_INTERVAL;
+"UNCOUNTABLE_NONEMPTY_INTERIOR",UNCOUNTABLE_NONEMPTY_INTERIOR;
+"UNCOUNTABLE_OPEN",UNCOUNTABLE_OPEN;
+"UNCOUNTABLE_PATH_CONNECTED",UNCOUNTABLE_PATH_CONNECTED;
+"UNCOUNTABLE_REAL",UNCOUNTABLE_REAL;
+"UNCOUNTABLE_SEGMENT",UNCOUNTABLE_SEGMENT;
+"UNCURRY_DEF",UNCURRY_DEF;
+"UNIFORMLY_CAUCHY_IMP_UNIFORMLY_CONVERGENT",UNIFORMLY_CAUCHY_IMP_UNIFORMLY_CONVERGENT;
+"UNIFORMLY_CONTINUOUS_EXTENDS_TO_CLOSURE",UNIFORMLY_CONTINUOUS_EXTENDS_TO_CLOSURE;
+"UNIFORMLY_CONTINUOUS_IMP_CAUCHY_CONTINUOUS",UNIFORMLY_CONTINUOUS_IMP_CAUCHY_CONTINUOUS;
+"UNIFORMLY_CONTINUOUS_IMP_CONTINUOUS",UNIFORMLY_CONTINUOUS_IMP_CONTINUOUS;
+"UNIFORMLY_CONTINUOUS_ON_ADD",UNIFORMLY_CONTINUOUS_ON_ADD;
+"UNIFORMLY_CONTINUOUS_ON_CLOSURE",UNIFORMLY_CONTINUOUS_ON_CLOSURE;
+"UNIFORMLY_CONTINUOUS_ON_CMUL",UNIFORMLY_CONTINUOUS_ON_CMUL;
+"UNIFORMLY_CONTINUOUS_ON_COMPOSE",UNIFORMLY_CONTINUOUS_ON_COMPOSE;
+"UNIFORMLY_CONTINUOUS_ON_CONST",UNIFORMLY_CONTINUOUS_ON_CONST;
+"UNIFORMLY_CONTINUOUS_ON_DIST_CLOSEST_POINT",UNIFORMLY_CONTINUOUS_ON_DIST_CLOSEST_POINT;
+"UNIFORMLY_CONTINUOUS_ON_EQ",UNIFORMLY_CONTINUOUS_ON_EQ;
+"UNIFORMLY_CONTINUOUS_ON_ID",UNIFORMLY_CONTINUOUS_ON_ID;
+"UNIFORMLY_CONTINUOUS_ON_LIFT_SETDIST",UNIFORMLY_CONTINUOUS_ON_LIFT_SETDIST;
+"UNIFORMLY_CONTINUOUS_ON_MUL",UNIFORMLY_CONTINUOUS_ON_MUL;
+"UNIFORMLY_CONTINUOUS_ON_NEG",UNIFORMLY_CONTINUOUS_ON_NEG;
+"UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY",UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY;
+"UNIFORMLY_CONTINUOUS_ON_SUB",UNIFORMLY_CONTINUOUS_ON_SUB;
+"UNIFORMLY_CONTINUOUS_ON_SUBSET",UNIFORMLY_CONTINUOUS_ON_SUBSET;
+"UNIFORMLY_CONTINUOUS_ON_VMUL",UNIFORMLY_CONTINUOUS_ON_VMUL;
+"UNIFORMLY_CONTINUOUS_ON_VSUM",UNIFORMLY_CONTINUOUS_ON_VSUM;
+"UNIFORMLY_CONVERGENT_EQ_CAUCHY",UNIFORMLY_CONVERGENT_EQ_CAUCHY;
+"UNIFORM_LIM_ADD",UNIFORM_LIM_ADD;
+"UNIFORM_LIM_BILINEAR",UNIFORM_LIM_BILINEAR;
+"UNIFORM_LIM_SUB",UNIFORM_LIM_SUB;
+"UNION",UNION;
+"UNIONS",UNIONS;
+"UNIONS_0",UNIONS_0;
+"UNIONS_1",UNIONS_1;
+"UNIONS_2",UNIONS_2;
+"UNIONS_COMPONENTS",UNIONS_COMPONENTS;
+"UNIONS_CONNECTED_COMPONENT",UNIONS_CONNECTED_COMPONENT;
+"UNIONS_DIFF",UNIONS_DIFF;
+"UNIONS_GSPEC",UNIONS_GSPEC;
+"UNIONS_IMAGE",UNIONS_IMAGE;
+"UNIONS_INSERT",UNIONS_INSERT;
+"UNIONS_INTERS",UNIONS_INTERS;
+"UNIONS_MAXIMAL_SETS",UNIONS_MAXIMAL_SETS;
+"UNIONS_MONO",UNIONS_MONO;
+"UNIONS_MONO_IMAGE",UNIONS_MONO_IMAGE;
+"UNIONS_PATH_COMPONENT",UNIONS_PATH_COMPONENT;
+"UNIONS_PRED",UNIONS_PRED;
+"UNIONS_SUBSET",UNIONS_SUBSET;
+"UNIONS_UNION",UNIONS_UNION;
+"UNION_ACI",UNION_ACI;
+"UNION_ASSOC",UNION_ASSOC;
+"UNION_COMM",UNION_COMM;
+"UNION_EMPTY",UNION_EMPTY;
+"UNION_FL",UNION_FL;
+"UNION_IDEMPOT",UNION_IDEMPOT;
+"UNION_INSEG",UNION_INSEG;
+"UNION_INTERIOR_SUBSET",UNION_INTERIOR_SUBSET;
+"UNION_LE_ADD_C",UNION_LE_ADD_C;
+"UNION_OVER_INTER",UNION_OVER_INTER;
+"UNION_SEGMENT",UNION_SEGMENT;
+"UNION_SUBSET",UNION_SUBSET;
+"UNION_UNIV",UNION_UNIV;
+"UNION_WITH_INSIDE",UNION_WITH_INSIDE;
+"UNION_WITH_OUTSIDE",UNION_WITH_OUTSIDE;
+"UNIQUE_SKOLEM_ALT",UNIQUE_SKOLEM_ALT;
+"UNIQUE_SKOLEM_THM",UNIQUE_SKOLEM_THM;
+"UNIT_INTERVAL_CONVEX_HULL",UNIT_INTERVAL_CONVEX_HULL;
+"UNIT_INTERVAL_NONEMPTY",UNIT_INTERVAL_NONEMPTY;
+"UNIV",UNIV;
+"UNIV_GSPEC",UNIV_GSPEC;
+"UNIV_NOT_EMPTY",UNIV_NOT_EMPTY;
+"UNIV_PCROSS_UNIV",UNIV_PCROSS_UNIV;
+"UNIV_SECOND_COUNTABLE",UNIV_SECOND_COUNTABLE;
+"UNIV_SECOND_COUNTABLE_SEQUENCE",UNIV_SECOND_COUNTABLE_SEQUENCE;
+"UNIV_SUBSET",UNIV_SUBSET;
+"UNWIND_THM1",UNWIND_THM1;
+"UNWIND_THM2",UNWIND_THM2;
+"UPPER_BOUND_FINITE_SET",UPPER_BOUND_FINITE_SET;
+"UPPER_BOUND_FINITE_SET_REAL",UPPER_BOUND_FINITE_SET_REAL;
+"URYSOHN",URYSOHN;
+"URYSOHN_LOCAL",URYSOHN_LOCAL;
+"URYSOHN_LOCAL_STRONG",URYSOHN_LOCAL_STRONG;
+"URYSOHN_STRONG",URYSOHN_STRONG;
+"VARIATION_EQUAL_LEMMA",VARIATION_EQUAL_LEMMA;
+"VECTOR_1",VECTOR_1;
+"VECTOR_2",VECTOR_2;
+"VECTOR_3",VECTOR_3;
+"VECTOR_4",VECTOR_4;
+"VECTOR_ADD_AC",VECTOR_ADD_AC;
+"VECTOR_ADD_ASSOC",VECTOR_ADD_ASSOC;
+"VECTOR_ADD_COMPONENT",VECTOR_ADD_COMPONENT;
+"VECTOR_ADD_LDISTRIB",VECTOR_ADD_LDISTRIB;
+"VECTOR_ADD_LID",VECTOR_ADD_LID;
+"VECTOR_ADD_LINV",VECTOR_ADD_LINV;
+"VECTOR_ADD_RDISTRIB",VECTOR_ADD_RDISTRIB;
+"VECTOR_ADD_RID",VECTOR_ADD_RID;
+"VECTOR_ADD_RINV",VECTOR_ADD_RINV;
+"VECTOR_ADD_SUB",VECTOR_ADD_SUB;
+"VECTOR_ADD_SYM",VECTOR_ADD_SYM;
+"VECTOR_AFFINITY_EQ",VECTOR_AFFINITY_EQ;
+"VECTOR_CHOOSE_DIST",VECTOR_CHOOSE_DIST;
+"VECTOR_CHOOSE_SIZE",VECTOR_CHOOSE_SIZE;
+"VECTOR_COMPONENTWISE",VECTOR_COMPONENTWISE;
+"VECTOR_DERIVATIVE_AT",VECTOR_DERIVATIVE_AT;
+"VECTOR_DERIVATIVE_CONST_AT",VECTOR_DERIVATIVE_CONST_AT;
+"VECTOR_DERIVATIVE_UNIQUE_AT",VECTOR_DERIVATIVE_UNIQUE_AT;
+"VECTOR_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL",VECTOR_DERIVATIVE_UNIQUE_WITHIN_CLOSED_INTERVAL;
+"VECTOR_DERIVATIVE_WITHIN_CLOSED_INTERVAL",VECTOR_DERIVATIVE_WITHIN_CLOSED_INTERVAL;
+"VECTOR_DERIVATIVE_WORKS",VECTOR_DERIVATIVE_WORKS;
+"VECTOR_DIFF_CHAIN_AT",VECTOR_DIFF_CHAIN_AT;
+"VECTOR_DIFF_CHAIN_WITHIN",VECTOR_DIFF_CHAIN_WITHIN;
+"VECTOR_EQ",VECTOR_EQ;
+"VECTOR_EQ_ADDR",VECTOR_EQ_ADDR;
+"VECTOR_EQ_AFFINITY",VECTOR_EQ_AFFINITY;
+"VECTOR_EQ_DOT_SPAN",VECTOR_EQ_DOT_SPAN;
+"VECTOR_EQ_LDOT",VECTOR_EQ_LDOT;
+"VECTOR_EQ_NEG2",VECTOR_EQ_NEG2;
+"VECTOR_EQ_RDOT",VECTOR_EQ_RDOT;
+"VECTOR_EXPAND_1",VECTOR_EXPAND_1;
+"VECTOR_EXPAND_2",VECTOR_EXPAND_2;
+"VECTOR_EXPAND_3",VECTOR_EXPAND_3;
+"VECTOR_EXPAND_4",VECTOR_EXPAND_4;
+"VECTOR_IN_ORTHOGONAL_BASIS",VECTOR_IN_ORTHOGONAL_BASIS;
+"VECTOR_IN_ORTHOGONAL_SPANNINGSET",VECTOR_IN_ORTHOGONAL_SPANNINGSET;
+"VECTOR_IN_ORTHONORMAL_BASIS",VECTOR_IN_ORTHONORMAL_BASIS;
+"VECTOR_MATRIX_MUL_TRANSP",VECTOR_MATRIX_MUL_TRANSP;
+"VECTOR_MUL_ASSOC",VECTOR_MUL_ASSOC;
+"VECTOR_MUL_COMPONENT",VECTOR_MUL_COMPONENT;
+"VECTOR_MUL_EQ_0",VECTOR_MUL_EQ_0;
+"VECTOR_MUL_LCANCEL",VECTOR_MUL_LCANCEL;
+"VECTOR_MUL_LCANCEL_IMP",VECTOR_MUL_LCANCEL_IMP;
+"VECTOR_MUL_LID",VECTOR_MUL_LID;
+"VECTOR_MUL_LNEG",VECTOR_MUL_LNEG;
+"VECTOR_MUL_LZERO",VECTOR_MUL_LZERO;
+"VECTOR_MUL_RCANCEL",VECTOR_MUL_RCANCEL;
+"VECTOR_MUL_RCANCEL_IMP",VECTOR_MUL_RCANCEL_IMP;
+"VECTOR_MUL_RNEG",VECTOR_MUL_RNEG;
+"VECTOR_MUL_RZERO",VECTOR_MUL_RZERO;
+"VECTOR_NEG_0",VECTOR_NEG_0;
+"VECTOR_NEG_COMPONENT",VECTOR_NEG_COMPONENT;
+"VECTOR_NEG_EQ_0",VECTOR_NEG_EQ_0;
+"VECTOR_NEG_MINUS1",VECTOR_NEG_MINUS1;
+"VECTOR_NEG_NEG",VECTOR_NEG_NEG;
+"VECTOR_NEG_SUB",VECTOR_NEG_SUB;
+"VECTOR_ONE",VECTOR_ONE;
+"VECTOR_SUB",VECTOR_SUB;
+"VECTOR_SUB_ADD",VECTOR_SUB_ADD;
+"VECTOR_SUB_ADD2",VECTOR_SUB_ADD2;
+"VECTOR_SUB_COMPONENT",VECTOR_SUB_COMPONENT;
+"VECTOR_SUB_EQ",VECTOR_SUB_EQ;
+"VECTOR_SUB_LDISTRIB",VECTOR_SUB_LDISTRIB;
+"VECTOR_SUB_LZERO",VECTOR_SUB_LZERO;
+"VECTOR_SUB_PROJECT_ORTHOGONAL",VECTOR_SUB_PROJECT_ORTHOGONAL;
+"VECTOR_SUB_RADD",VECTOR_SUB_RADD;
+"VECTOR_SUB_RDISTRIB",VECTOR_SUB_RDISTRIB;
+"VECTOR_SUB_REFL",VECTOR_SUB_REFL;
+"VECTOR_SUB_RZERO",VECTOR_SUB_RZERO;
+"VECTOR_VARIATION_AFFINITY",VECTOR_VARIATION_AFFINITY;
+"VECTOR_VARIATION_AFFINITY2",VECTOR_VARIATION_AFFINITY2;
+"VECTOR_VARIATION_COMBINE",VECTOR_VARIATION_COMBINE;
+"VECTOR_VARIATION_CONST",VECTOR_VARIATION_CONST;
+"VECTOR_VARIATION_CONST_EQ",VECTOR_VARIATION_CONST_EQ;
+"VECTOR_VARIATION_CONTINUOUS",VECTOR_VARIATION_CONTINUOUS;
+"VECTOR_VARIATION_CONTINUOUS_LEFT",VECTOR_VARIATION_CONTINUOUS_LEFT;
+"VECTOR_VARIATION_CONTINUOUS_RIGHT",VECTOR_VARIATION_CONTINUOUS_RIGHT;
+"VECTOR_VARIATION_EQ",VECTOR_VARIATION_EQ;
+"VECTOR_VARIATION_GE_DROP_FUNCTION",VECTOR_VARIATION_GE_DROP_FUNCTION;
+"VECTOR_VARIATION_GE_NORM_FUNCTION",VECTOR_VARIATION_GE_NORM_FUNCTION;
+"VECTOR_VARIATION_INTEGRAL_NORM_DERIVATIVE",VECTOR_VARIATION_INTEGRAL_NORM_DERIVATIVE;
+"VECTOR_VARIATION_MINUS_FUNCTION_MONOTONE",VECTOR_VARIATION_MINUS_FUNCTION_MONOTONE;
+"VECTOR_VARIATION_MONOTONE",VECTOR_VARIATION_MONOTONE;
+"VECTOR_VARIATION_NEG",VECTOR_VARIATION_NEG;
+"VECTOR_VARIATION_ON_DIVISION",VECTOR_VARIATION_ON_DIVISION;
+"VECTOR_VARIATION_ON_NULL",VECTOR_VARIATION_ON_NULL;
+"VECTOR_VARIATION_POS_LE",VECTOR_VARIATION_POS_LE;
+"VECTOR_VARIATION_REFLECT",VECTOR_VARIATION_REFLECT;
+"VECTOR_VARIATION_REFLECT2",VECTOR_VARIATION_REFLECT2;
+"VECTOR_VARIATION_REFLECT_INTERVAL",VECTOR_VARIATION_REFLECT_INTERVAL;
+"VECTOR_VARIATION_TRANSLATION",VECTOR_VARIATION_TRANSLATION;
+"VECTOR_VARIATION_TRANSLATION2",VECTOR_VARIATION_TRANSLATION2;
+"VECTOR_VARIATION_TRANSLATION_INTERVAL",VECTOR_VARIATION_TRANSLATION_INTERVAL;
+"VECTOR_VARIATION_TRIANGLE",VECTOR_VARIATION_TRIANGLE;
+"VEC_COMPONENT",VEC_COMPONENT;
+"VEC_EQ",VEC_EQ;
+"VSUM",VSUM;
+"VSUM_0",VSUM_0;
+"VSUM_1",VSUM_1;
+"VSUM_2",VSUM_2;
+"VSUM_3",VSUM_3;
+"VSUM_4",VSUM_4;
+"VSUM_ADD",VSUM_ADD;
+"VSUM_ADD_GEN",VSUM_ADD_GEN;
+"VSUM_ADD_NUMSEG",VSUM_ADD_NUMSEG;
+"VSUM_ADD_SPLIT",VSUM_ADD_SPLIT;
+"VSUM_BIJECTION",VSUM_BIJECTION;
+"VSUM_CASES",VSUM_CASES;
+"VSUM_CASES_1",VSUM_CASES_1;
+"VSUM_CLAUSES",VSUM_CLAUSES;
+"VSUM_CLAUSES_LEFT",VSUM_CLAUSES_LEFT;
+"VSUM_CLAUSES_NUMSEG",VSUM_CLAUSES_NUMSEG;
+"VSUM_CLAUSES_RIGHT",VSUM_CLAUSES_RIGHT;
+"VSUM_CMUL_NUMSEG",VSUM_CMUL_NUMSEG;
+"VSUM_COMBINE_L",VSUM_COMBINE_L;
+"VSUM_COMBINE_R",VSUM_COMBINE_R;
+"VSUM_COMPONENT",VSUM_COMPONENT;
+"VSUM_CONST",VSUM_CONST;
+"VSUM_CONST_NUMSEG",VSUM_CONST_NUMSEG;
+"VSUM_CONTENT_NULL",VSUM_CONTENT_NULL;
+"VSUM_DELETE",VSUM_DELETE;
+"VSUM_DELETE_CASES",VSUM_DELETE_CASES;
+"VSUM_DELTA",VSUM_DELTA;
+"VSUM_DIFF",VSUM_DIFF;
+"VSUM_DIFFS",VSUM_DIFFS;
+"VSUM_DIFFS_ALT",VSUM_DIFFS_ALT;
+"VSUM_DIFF_LEMMA",VSUM_DIFF_LEMMA;
+"VSUM_EQ",VSUM_EQ;
+"VSUM_EQ_0",VSUM_EQ_0;
+"VSUM_EQ_GENERAL",VSUM_EQ_GENERAL;
+"VSUM_EQ_GENERAL_INVERSES",VSUM_EQ_GENERAL_INVERSES;
+"VSUM_EQ_NUMSEG",VSUM_EQ_NUMSEG;
+"VSUM_EQ_SUPERSET",VSUM_EQ_SUPERSET;
+"VSUM_GROUP",VSUM_GROUP;
+"VSUM_IMAGE",VSUM_IMAGE;
+"VSUM_IMAGE_GEN",VSUM_IMAGE_GEN;
+"VSUM_IMAGE_NONZERO",VSUM_IMAGE_NONZERO;
+"VSUM_INCL_EXCL",VSUM_INCL_EXCL;
+"VSUM_INJECTION",VSUM_INJECTION;
+"VSUM_LMUL",VSUM_LMUL;
+"VSUM_NEG",VSUM_NEG;
+"VSUM_NONZERO_IMAGE_LEMMA",VSUM_NONZERO_IMAGE_LEMMA;
+"VSUM_NORM",VSUM_NORM;
+"VSUM_NORM_ALLSUBSETS_BOUND",VSUM_NORM_ALLSUBSETS_BOUND;
+"VSUM_NORM_BOUND",VSUM_NORM_BOUND;
+"VSUM_NORM_LE",VSUM_NORM_LE;
+"VSUM_NORM_TRIANGLE",VSUM_NORM_TRIANGLE;
+"VSUM_OFFSET",VSUM_OFFSET;
+"VSUM_OFFSET_0",VSUM_OFFSET_0;
+"VSUM_OVER_TAGGED_DIVISION_LEMMA",VSUM_OVER_TAGGED_DIVISION_LEMMA;
+"VSUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA",VSUM_OVER_TAGGED_PARTIAL_DIVISION_LEMMA;
+"VSUM_PAIR",VSUM_PAIR;
+"VSUM_PAIR_0",VSUM_PAIR_0;
+"VSUM_PARTIAL_PRE",VSUM_PARTIAL_PRE;
+"VSUM_PARTIAL_SUC",VSUM_PARTIAL_SUC;
+"VSUM_REAL",VSUM_REAL;
+"VSUM_RESTRICT",VSUM_RESTRICT;
+"VSUM_RESTRICT_SET",VSUM_RESTRICT_SET;
+"VSUM_RMUL",VSUM_RMUL;
+"VSUM_SING",VSUM_SING;
+"VSUM_SING_NUMSEG",VSUM_SING_NUMSEG;
+"VSUM_SUB",VSUM_SUB;
+"VSUM_SUB_NUMSEG",VSUM_SUB_NUMSEG;
+"VSUM_SUC",VSUM_SUC;
+"VSUM_SUPERSET",VSUM_SUPERSET;
+"VSUM_SWAP",VSUM_SWAP;
+"VSUM_SWAP_NUMSEG",VSUM_SWAP_NUMSEG;
+"VSUM_TRIV_NUMSEG",VSUM_TRIV_NUMSEG;
+"VSUM_UNION",VSUM_UNION;
+"VSUM_UNIONS_NONZERO",VSUM_UNIONS_NONZERO;
+"VSUM_UNION_LZERO",VSUM_UNION_LZERO;
+"VSUM_UNION_NONZERO",VSUM_UNION_NONZERO;
+"VSUM_UNION_RZERO",VSUM_UNION_RZERO;
+"VSUM_VMUL",VSUM_VMUL;
+"VSUM_VSUM_PRODUCT",VSUM_VSUM_PRODUCT;
+"WF",WF;
+"WF_DCHAIN",WF_DCHAIN;
+"WF_EQ",WF_EQ;
+"WF_EREC",WF_EREC;
+"WF_FALSE",WF_FALSE;
+"WF_FINITE",WF_FINITE;
+"WF_IND",WF_IND;
+"WF_INT_MEASURE",WF_INT_MEASURE;
+"WF_INT_MEASURE_2",WF_INT_MEASURE_2;
+"WF_LEX",WF_LEX;
+"WF_LEX_DEPENDENT",WF_LEX_DEPENDENT;
+"WF_MEASURE",WF_MEASURE;
+"WF_MEASURE_GEN",WF_MEASURE_GEN;
+"WF_POINTWISE",WF_POINTWISE;
+"WF_REC",WF_REC;
+"WF_REC_CASES",WF_REC_CASES;
+"WF_REC_CASES'",WF_REC_CASES';
+"WF_REC_INVARIANT",WF_REC_INVARIANT;
+"WF_REC_TAIL",WF_REC_TAIL;
+"WF_REC_TAIL_GENERAL",WF_REC_TAIL_GENERAL;
+"WF_REC_TAIL_GENERAL'",WF_REC_TAIL_GENERAL';
+"WF_REC_WF",WF_REC_WF;
+"WF_REC_num",WF_REC_num;
+"WF_REFL",WF_REFL;
+"WF_SUBSET",WF_SUBSET;
+"WF_UREC",WF_UREC;
+"WF_UREC_WF",WF_UREC_WF;
+"WF_num",WF_num;
+"WITHIN",WITHIN;
+"WITHIN_UNIV",WITHIN_UNIV;
+"WITHIN_WITHIN",WITHIN_WITHIN;
+"WLOG_LE",WLOG_LE;
+"WLOG_LINEAR_INJECTIVE_IMAGE",WLOG_LINEAR_INJECTIVE_IMAGE;
+"WLOG_LINEAR_INJECTIVE_IMAGE_2",WLOG_LINEAR_INJECTIVE_IMAGE_2;
+"WLOG_LINEAR_INJECTIVE_IMAGE_2_ALT",WLOG_LINEAR_INJECTIVE_IMAGE_2_ALT;
+"WLOG_LINEAR_INJECTIVE_IMAGE_ALT",WLOG_LINEAR_INJECTIVE_IMAGE_ALT;
+"WLOG_LT",WLOG_LT;
+"WO",WO;
+"WOSET",WOSET;
+"WOSET_ANTISYM",WOSET_ANTISYM;
+"WOSET_FLEQ",WOSET_FLEQ;
+"WOSET_POSET",WOSET_POSET;
+"WOSET_REFL",WOSET_REFL;
+"WOSET_TOTAL",WOSET_TOTAL;
+"WOSET_TOTAL_LE",WOSET_TOTAL_LE;
+"WOSET_TOTAL_LT",WOSET_TOTAL_LT;
+"WOSET_TRANS",WOSET_TRANS;
+"WOSET_TRANS_LE",WOSET_TRANS_LE;
+"WOSET_TRANS_LESS",WOSET_TRANS_LESS;
+"WOSET_WELL",WOSET_WELL;
+"WOSET_WELL_CONTRAPOS",WOSET_WELL_CONTRAPOS;
+"ZBOT",ZBOT;
+"ZCONSTR",ZCONSTR;
+"ZCONSTR_ZBOT",ZCONSTR_ZBOT;
+"ZERO_DEF",ZERO_DEF;
+"ZIP",ZIP;
+"ZIP_DEF",ZIP_DEF;
+"ZL",ZL;
+"ZL_SUBSETS",ZL_SUBSETS;
+"ZL_SUBSETS_UNIONS",ZL_SUBSETS_UNIONS;
+"ZL_SUBSETS_UNIONS_NONEMPTY",ZL_SUBSETS_UNIONS_NONEMPTY;
+"ZRECSPACE_CASES",ZRECSPACE_CASES;
+"ZRECSPACE_INDUCT",ZRECSPACE_INDUCT;
+"ZRECSPACE_RULES",ZRECSPACE_RULES;
+"_FALSITY_",_FALSITY_;
+"_FUNCTION",_FUNCTION;
+"_GUARDED_PATTERN",_GUARDED_PATTERN;
+"_MATCH",_MATCH;
+"_SEQPATTERN",_SEQPATTERN;
+"_UNGUARDED_PATTERN",_UNGUARDED_PATTERN;
+"absolutely_integrable_on",absolutely_integrable_on;
+"add_c",add_c;
+"adjoint",adjoint;
+"admissible",admissible;
+"aff_dim",aff_dim;
+"affine",affine;
+"affine_dependent",affine_dependent;
+"arc",arc;
+"at",at;
+"at_infinity",at_infinity;
+"ball",ball;
+"basis",basis;
+"between",between;
+"bilinear",bilinear;
+"binarysum",binarysum;
+"bitset",bitset;
+"bool_INDUCT",bool_INDUCT;
+"bool_RECURSION",bool_RECURSION;
+"bounded",bounded;
+"cart_tybij",cart_tybij;
+"cauchy",cauchy;
+"cball",cball;
+"chain",chain;
+"char_INDUCT",char_INDUCT;
+"char_RECURSION",char_RECURSION;
+"closed",closed;
+"closed_in",closed_in;
+"closed_interval",closed_interval;
+"closed_segment",closed_segment;
+"closest_point",closest_point;
+"closure",closure;
+"codeset",codeset;
+"cofactor",cofactor;
+"collinear",collinear;
+"column",column;
+"columns",columns;
+"columnvector",columnvector;
+"compact",compact;
+"complete",complete;
+"components",components;
+"condensation_point_of",condensation_point_of;
+"cong",cong;
+"conic",conic;
+"connected",connected;
+"connected_component",connected_component;
+"content",content;
+"continuous",continuous;
+"continuous_at",continuous_at;
+"continuous_on",continuous_on;
+"continuous_within",continuous_within;
+"contractible",contractible;
+"convex",convex;
+"convex_cone",convex_cone;
+"convex_on",convex_on;
+"coplanar",coplanar;
+"covering_space",covering_space;
+"dependent",dependent;
+"dest_int_rep",dest_int_rep;
+"det",det;
+"diagonal_matrix",diagonal_matrix;
+"diameter",diameter;
+"differentiable",differentiable;
+"differentiable_on",differentiable_on;
+"dim",dim;
+"dimindex",dimindex;
+"dist",dist;
+"division_of",division_of;
+"division_points",division_points;
+"dot",dot;
+"drop",drop;
+"edge_of",edge_of;
+"epigraph",epigraph;
+"eq_c",eq_c;
+"equiintegrable_on",equiintegrable_on;
+"euclidean",euclidean;
+"evenperm",evenperm;
+"eventually",eventually;
+"exposed_face_of",exposed_face_of;
+"extreme_point_of",extreme_point_of;
+"face_of",face_of;
+"facet_of",facet_of;
+"fine",fine;
+"finite_image_tybij",finite_image_tybij;
+"finite_index",finite_index;
+"finite_sum_tybij",finite_sum_tybij;
+"fl",fl;
+"frechet_derivative",frechet_derivative;
+"from",from;
+"frontier",frontier;
+"fstcart",fstcart;
+"gauge",gauge;
+"ge_c",ge_c;
+"geom_mul",geom_mul;
+"grade",grade;
+"gt_c",gt_c;
+"has_bounded_setvariation_on",has_bounded_setvariation_on;
+"has_bounded_variation_on",has_bounded_variation_on;
+"has_derivative",has_derivative;
+"has_derivative_at",has_derivative_at;
+"has_derivative_within",has_derivative_within;
+"has_integral",has_integral;
+"has_integral_alt",has_integral_alt;
+"has_integral_compact_interval",has_integral_compact_interval;
+"has_integral_def",has_integral_def;
+"has_measure",has_measure;
+"has_vector_derivative",has_vector_derivative;
+"homeomorphic",homeomorphic;
+"homeomorphism",homeomorphism;
+"homotopic_loops",homotopic_loops;
+"homotopic_paths",homotopic_paths;
+"homotopic_with",homotopic_with;
+"homotopy_equivalent",homotopy_equivalent;
+"hreal_add",hreal_add;
+"hreal_add_th",hreal_add_th;
+"hreal_inv",hreal_inv;
+"hreal_inv_th",hreal_inv_th;
+"hreal_le",hreal_le;
+"hreal_le_th",hreal_le_th;
+"hreal_mul",hreal_mul;
+"hreal_mul_th",hreal_mul_th;
+"hreal_of_num",hreal_of_num;
+"hreal_of_num_th",hreal_of_num_th;
+"hull",hull;
+"in_direction",in_direction;
+"independent",independent;
+"indicator",indicator;
+"inf",inf;
+"infnorm",infnorm;
+"infsum",infsum;
+"inner",inner;
+"inseg",inseg;
+"inside",inside;
+"int_abs",int_abs;
+"int_abs_th",int_abs_th;
+"int_abstr",int_abstr;
+"int_add",int_add;
+"int_add_th",int_add_th;
+"int_congruent",int_congruent;
+"int_coprime",int_coprime;
+"int_divides",int_divides;
+"int_eq",int_eq;
+"int_gcd",int_gcd;
+"int_ge",int_ge;
+"int_gt",int_gt;
+"int_le",int_le;
+"int_lt",int_lt;
+"int_max",int_max;
+"int_max_th",int_max_th;
+"int_min",int_min;
+"int_min_th",int_min_th;
+"int_mod",int_mod;
+"int_mul",int_mul;
+"int_mul_th",int_mul_th;
+"int_neg",int_neg;
+"int_neg_th",int_neg_th;
+"int_of_num",int_of_num;
+"int_of_num_th",int_of_num_th;
+"int_pow",int_pow;
+"int_pow_th",int_pow_th;
+"int_rep",int_rep;
+"int_sgn",int_sgn;
+"int_sgn_th",int_sgn_th;
+"int_sub",int_sub;
+"int_sub_th",int_sub_th;
+"int_tybij",int_tybij;
+"integer",integer;
+"integrable_on",integrable_on;
+"integral",integral;
+"interior",interior;
+"interval",interval;
+"interval_bij",interval_bij;
+"interval_lowerbound",interval_lowerbound;
+"interval_upperbound",interval_upperbound;
+"inverse",inverse;
+"invertible",invertible;
+"is_int",is_int;
+"is_interval",is_interval;
+"is_nadd",is_nadd;
+"is_nadd_0",is_nadd_0;
+"istopology",istopology;
+"iterate",iterate;
+"jacobian",jacobian;
+"joinpaths",joinpaths;
+"kle",kle;
+"ksimplex",ksimplex;
+"lambda",lambda;
+"lambdas",lambdas;
+"le_c",le_c;
+"lebesgue_measurable",lebesgue_measurable;
+"lemma",lemma;
+"less",less;
+"lift",lift;
+"lifted",lifted;
+"lim",lim;
+"limit_point_of",limit_point_of;
+"linear",linear;
+"linepath",linepath;
+"linseg",linseg;
+"list_CASES",list_CASES;
+"list_INDUCT",list_INDUCT;
+"list_RECURSION",list_RECURSION;
+"list_of_set",list_of_set;
+"locally",locally;
+"lt_c",lt_c;
+"mat",mat;
+"matrix",matrix;
+"matrix_add",matrix_add;
+"matrix_cmul",matrix_cmul;
+"matrix_inv",matrix_inv;
+"matrix_mul",matrix_mul;
+"matrix_neg",matrix_neg;
+"matrix_sub",matrix_sub;
+"matrix_vector_mul",matrix_vector_mul;
+"mbasis",mbasis;
+"measurable",measurable;
+"measurable_on",measurable_on;
+"measure",measure;
+"midpoint",midpoint;
+"minimal",minimal;
+"mk_pair_def",mk_pair_def;
+"monoidal",monoidal;
+"mul_c",mul_c;
+"multivec",multivec;
+"multivector",multivector;
+"multivector_tybij",multivector_tybij;
+"multivector_tybij_th",multivector_tybij_th;
+"nadd_abs",nadd_abs;
+"nadd_add",nadd_add;
+"nadd_eq",nadd_eq;
+"nadd_inv",nadd_inv;
+"nadd_le",nadd_le;
+"nadd_mul",nadd_mul;
+"nadd_of_num",nadd_of_num;
+"nadd_rep",nadd_rep;
+"nadd_rinv",nadd_rinv;
+"negligible",negligible;
+"net_tybij",net_tybij;
+"netlimit",netlimit;
+"neutral",neutral;
+"nsum",nsum;
+"num_Axiom",num_Axiom;
+"num_CASES",num_CASES;
+"num_FINITE",num_FINITE;
+"num_FINITE_AVOID",num_FINITE_AVOID;
+"num_INDUCTION",num_INDUCTION;
+"num_INFINITE",num_INFINITE;
+"num_MAX",num_MAX;
+"num_RECURSION",num_RECURSION;
+"num_RECURSION_STD",num_RECURSION_STD;
+"num_WF",num_WF;
+"num_WOP",num_WOP;
+"num_congruent",num_congruent;
+"num_coprime",num_coprime;
+"num_divides",num_divides;
+"num_gcd",num_gcd;
+"num_mod",num_mod;
+"num_of_int",num_of_int;
+"numseg",numseg;
+"o_ASSOC",o_ASSOC;
+"o_DEF",o_DEF;
+"o_THM",o_THM;
+"one",one;
+"one_Axiom",one_Axiom;
+"one_DEF",one_DEF;
+"one_INDUCT",one_INDUCT;
+"one_RECURSION",one_RECURSION;
+"one_axiom",one_axiom;
+"one_tydef",one_tydef;
+"onorm",onorm;
+"open_def",open_def;
+"open_in",open_in;
+"open_interval",open_interval;
+"open_segment",open_segment;
+"operative",operative;
+"option_INDUCT",option_INDUCT;
+"option_RECURSION",option_RECURSION;
+"ordinal",ordinal;
+"orthogonal",orthogonal;
+"orthogonal_matrix",orthogonal_matrix;
+"orthogonal_transformation",orthogonal_transformation;
+"outer",outer;
+"outermorphism",outermorphism;
+"outside",outside;
+"pair_INDUCT",pair_INDUCT;
+"pair_RECURSION",pair_RECURSION;
+"pairwise",pairwise;
+"pastecart",pastecart;
+"path",path;
+"path_component",path_component;
+"path_connected",path_connected;
+"path_image",path_image;
+"path_length",path_length;
+"pathfinish",pathfinish;
+"pathstart",pathstart;
+"permutation",permutation;
+"permutes",permutes;
+"polyhedron",polyhedron;
+"polytope",polytope;
+"poset",poset;
+"prod_tybij",prod_tybij;
+"product",product;
+"rank",rank;
+"rational",rational;
+"real_INFINITE",real_INFINITE;
+"real_abs",real_abs;
+"real_add",real_add;
+"real_add_th",real_add_th;
+"real_div",real_div;
+"real_ge",real_ge;
+"real_gt",real_gt;
+"real_inv",real_inv;
+"real_inv_th",real_inv_th;
+"real_le",real_le;
+"real_le_th",real_le_th;
+"real_lt",real_lt;
+"real_max",real_max;
+"real_min",real_min;
+"real_mod",real_mod;
+"real_mul",real_mul;
+"real_mul_th",real_mul_th;
+"real_neg",real_neg;
+"real_neg_th",real_neg_th;
+"real_of_num",real_of_num;
+"real_of_num_th",real_of_num_th;
+"real_pow",real_pow;
+"real_sgn",real_sgn;
+"real_sub",real_sub;
+"rectifiable_path",rectifiable_path;
+"reduced",reduced;
+"reflect_along",reflect_along;
+"relative_frontier",relative_frontier;
+"relative_interior",relative_interior;
+"retract_of",retract_of;
+"retraction",retraction;
+"reversepath",reversepath;
+"reversion",reversion;
+"rotation_matrix",rotation_matrix;
+"rotoinversion_matrix",rotoinversion_matrix;
+"row",row;
+"rows",rows;
+"rowvector",rowvector;
+"segment",segment;
+"seqiterate",seqiterate;
+"seqiterate_EXISTS",seqiterate_EXISTS;
+"sequentially",sequentially;
+"set_of_list",set_of_list;
+"set_variation",set_variation;
+"setcode",setcode;
+"setdist",setdist;
+"shiftpath",shiftpath;
+"sign",sign;
+"simple_path",simple_path;
+"simplex",simplex;
+"simplicial_complex",simplicial_complex;
+"simply_connected",simply_connected;
+"sindex",sindex;
+"sndcart",sndcart;
+"span",span;
+"sphere",sphere;
+"sqrt",sqrt;
+"starlike",starlike;
+"string_INFINITE",string_INFINITE;
+"subpath",subpath;
+"subspace",subspace;
+"subtopology",subtopology;
+"sum",sum;
+"sum_CASES",sum_CASES;
+"sum_DISTINCT",sum_DISTINCT;
+"sum_INDUCT",sum_INDUCT;
+"sum_INJECTIVE",sum_INJECTIVE;
+"sum_RECURSION",sum_RECURSION;
+"summable",summable;
+"sums",sums;
+"sup",sup;
+"superadmissible",superadmissible;
+"support",support;
+"swap",swap;
+"swapseq_CASES",swapseq_CASES;
+"swapseq_INDUCT",swapseq_INDUCT;
+"swapseq_RULES",swapseq_RULES;
+"tagged_division_of",tagged_division_of;
+"tagged_partial_division_of",tagged_partial_division_of;
+"tailadmissible",tailadmissible;
+"tendsto",tendsto;
+"topology_tybij",topology_tybij;
+"topology_tybij_th",topology_tybij_th;
+"topspace",topspace;
+"toset",toset;
+"trace",trace;
+"transp",transp;
+"treal_add",treal_add;
+"treal_eq",treal_eq;
+"treal_inv",treal_inv;
+"treal_le",treal_le;
+"treal_mul",treal_mul;
+"treal_neg",treal_neg;
+"treal_of_num",treal_of_num;
+"triangulation",triangulation;
+"trivial_limit",trivial_limit;
+"uniformly_continuous_on",uniformly_continuous_on;
+"vec",vec;
+"vector",vector;
+"vector_add",vector_add;
+"vector_derivative",vector_derivative;
+"vector_matrix_mul",vector_matrix_mul;
+"vector_mul",vector_mul;
+"vector_neg",vector_neg;
+"vector_norm",vector_norm;
+"vector_sub",vector_sub;
+"vector_variation",vector_variation;
+"vsum",vsum;
+"within",within;
+"woset",woset
+];;
diff --git a/Multivariate/paths.ml b/Multivariate/paths.ml
new file mode 100644 (file)
index 0000000..53728d8
--- /dev/null
@@ -0,0 +1,15949 @@
+(* ========================================================================= *)
+(* Paths, connectedness, homotopy, simple connectedness & contractibility.   *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(*              (c) Copyright, Valentina Bruno 2010                          *)
+(* ========================================================================= *)
+
+needs "Multivariate/convex.ml";;
+
+(* ------------------------------------------------------------------------- *)
+(* Paths and arcs.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let path = new_definition
+ `!g:real^1->real^N. path g <=> g continuous_on interval[vec 0,vec 1]`;;
+
+let pathstart = new_definition
+ `pathstart (g:real^1->real^N) = g(vec 0)`;;
+
+let pathfinish = new_definition
+ `pathfinish (g:real^1->real^N) = g(vec 1)`;;
+
+let path_image = new_definition
+ `path_image (g:real^1->real^N) = IMAGE g (interval[vec 0,vec 1])`;;
+
+let reversepath = new_definition
+ `reversepath (g:real^1->real^N) = \x. g(vec 1 - x)`;;
+
+let joinpaths = new_definition
+ `(g1 ++ g2) = \x. if drop x <= &1 / &2 then g1(&2 % x)
+                   else g2(&2 % x - vec 1)`;;
+
+let simple_path = new_definition
+ `simple_path (g:real^1->real^N) <=>
+        path g /\
+        !x y. x IN interval[vec 0,vec 1] /\
+              y IN interval[vec 0,vec 1] /\
+              g x = g y
+              ==> x = y \/ x = vec 0 /\ y = vec 1 \/ x = vec 1 /\ y = vec 0`;;
+
+let arc = new_definition
+ `arc (g:real^1->real^N) <=>
+        path g /\
+        !x y. x IN interval [vec 0,vec 1] /\
+              y IN interval [vec 0,vec 1] /\
+              g x = g y
+              ==> x = y`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Invariance theorems.                                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_EQ = prove
+ (`!p q. (!t. t IN interval[vec 0,vec 1] ==> p t = q t) /\ path p
+         ==> path q`,
+  REWRITE_TAC[path; CONTINUOUS_ON_EQ]);;
+
+let PATH_CONTINUOUS_IMAGE = prove
+ (`!f:real^M->real^N g.
+     path g /\ f continuous_on path_image g ==> path(f o g)`,
+  REWRITE_TAC[path; path_image; CONTINUOUS_ON_COMPOSE]);;
+
+let PATH_TRANSLATION_EQ = prove
+ (`!a g:real^1->real^N. path((\x. a + x) o g) <=> path g`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[path] THEN EQ_TAC THEN DISCH_TAC THENL
+   [SUBGOAL_THEN `(g:real^1->real^N) = (\x. --a + x) o (\x. a + x) o g`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[FUN_EQ_THM; o_THM] THEN VECTOR_ARITH_TAC; ALL_TAC];
+    ALL_TAC] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST]);;
+
+add_translation_invariants [PATH_TRANSLATION_EQ];;
+
+let PATH_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N g.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (path(f o g) <=> path g)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `h:real^N->real^M` STRIP_ASSUME_TAC o
+        MATCH_MP LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+  REWRITE_TAC[path] THEN EQ_TAC THEN DISCH_TAC THENL
+   [SUBGOAL_THEN `g:real^1->real^M = h o (f:real^M->real^N) o g`
+    SUBST1_TAC THENL [ASM_REWRITE_TAC[o_ASSOC; I_O_ID]; ALL_TAC];
+    ALL_TAC] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON]);;
+
+add_linear_invariants [PATH_LINEAR_IMAGE_EQ];;
+
+let PATHSTART_TRANSLATION = prove
+ (`!a g. pathstart((\x. a + x) o g) = a + pathstart g`,
+  REWRITE_TAC[pathstart; o_THM]);;
+
+add_translation_invariants [PATHSTART_TRANSLATION];;
+
+let PATHSTART_LINEAR_IMAGE_EQ = prove
+ (`!f g. linear f ==> pathstart(f o g) = f(pathstart g)`,
+  REWRITE_TAC[pathstart; o_THM]);;
+
+add_linear_invariants [PATHSTART_LINEAR_IMAGE_EQ];;
+
+let PATHFINISH_TRANSLATION = prove
+ (`!a g. pathfinish((\x. a + x) o g) = a + pathfinish g`,
+  REWRITE_TAC[pathfinish; o_THM]);;
+
+add_translation_invariants [PATHFINISH_TRANSLATION];;
+
+let PATHFINISH_LINEAR_IMAGE = prove
+ (`!f g. linear f ==> pathfinish(f o g) = f(pathfinish g)`,
+  REWRITE_TAC[pathfinish; o_THM]);;
+
+add_linear_invariants [PATHFINISH_LINEAR_IMAGE];;
+
+let PATH_IMAGE_TRANSLATION = prove
+ (`!a g. path_image((\x. a + x) o g) = IMAGE (\x. a + x) (path_image g)`,
+  REWRITE_TAC[path_image; IMAGE_o]);;
+
+add_translation_invariants [PATH_IMAGE_TRANSLATION];;
+
+let PATH_IMAGE_LINEAR_IMAGE = prove
+ (`!f g. linear f ==> path_image(f o g) = IMAGE f (path_image g)`,
+  REWRITE_TAC[path_image; IMAGE_o]);;
+
+add_linear_invariants [PATH_IMAGE_LINEAR_IMAGE];;
+
+let REVERSEPATH_TRANSLATION = prove
+ (`!a g. reversepath((\x. a + x) o g) = (\x. a + x) o reversepath g`,
+  REWRITE_TAC[FUN_EQ_THM; reversepath; o_THM]);;
+
+add_translation_invariants [REVERSEPATH_TRANSLATION];;
+
+let REVERSEPATH_LINEAR_IMAGE = prove
+ (`!f g. linear f ==> reversepath(f o g) = f o reversepath g`,
+  REWRITE_TAC[FUN_EQ_THM; reversepath; o_THM]);;
+
+add_linear_invariants [REVERSEPATH_LINEAR_IMAGE];;
+
+let JOINPATHS_TRANSLATION = prove
+ (`!a:real^N g1 g2. ((\x. a + x) o g1) ++ ((\x. a + x) o g2) =
+                    (\x. a + x) o (g1 ++ g2)`,
+  REWRITE_TAC[joinpaths; FUN_EQ_THM] THEN REPEAT GEN_TAC THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[o_THM]);;
+
+add_translation_invariants [JOINPATHS_TRANSLATION];;
+
+let JOINPATHS_LINEAR_IMAGE = prove
+ (`!f g1 g2. linear f ==> (f o g1) ++ (f o g2) = f o (g1 ++ g2)`,
+  REWRITE_TAC[joinpaths; FUN_EQ_THM] THEN REPEAT STRIP_TAC THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[o_THM]);;
+
+add_linear_invariants [JOINPATHS_LINEAR_IMAGE];;
+
+let SIMPLE_PATH_TRANSLATION_EQ = prove
+ (`!a g:real^1->real^N. simple_path((\x. a + x) o g) <=> simple_path g`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[simple_path; PATH_TRANSLATION_EQ] THEN
+  REWRITE_TAC[o_THM; VECTOR_ARITH `a + x:real^N = a + y <=> x = y`]);;
+
+add_translation_invariants [SIMPLE_PATH_TRANSLATION_EQ];;
+
+let SIMPLE_PATH_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N g.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (simple_path(f o g) <=> simple_path g)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[simple_path; PATH_TRANSLATION_EQ] THEN
+  BINOP_TAC THENL [ASM_MESON_TAC[PATH_LINEAR_IMAGE_EQ]; ALL_TAC] THEN
+  REWRITE_TAC[o_THM] THEN ASM_MESON_TAC[]);;
+
+add_linear_invariants [SIMPLE_PATH_LINEAR_IMAGE_EQ];;
+
+let ARC_TRANSLATION_EQ = prove
+ (`!a g:real^1->real^N. arc((\x. a + x) o g) <=> arc g`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[arc; PATH_TRANSLATION_EQ] THEN
+  REWRITE_TAC[o_THM; VECTOR_ARITH `a + x:real^N = a + y <=> x = y`]);;
+
+add_translation_invariants [ARC_TRANSLATION_EQ];;
+
+let ARC_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N g.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (arc(f o g) <=> arc g)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[arc; PATH_TRANSLATION_EQ] THEN
+  BINOP_TAC THENL [ASM_MESON_TAC[PATH_LINEAR_IMAGE_EQ]; ALL_TAC] THEN
+  REWRITE_TAC[o_THM] THEN ASM_MESON_TAC[]);;
+
+add_linear_invariants [ARC_LINEAR_IMAGE_EQ];;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic lemmas about paths.                                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let ARC_IMP_SIMPLE_PATH = prove
+ (`!g. arc g ==> simple_path g`,
+  REWRITE_TAC[arc; simple_path] THEN MESON_TAC[]);;
+
+let ARC_IMP_PATH = prove
+ (`!g. arc g ==> path g`,
+  REWRITE_TAC[arc] THEN MESON_TAC[]);;
+
+let SIMPLE_PATH_IMP_PATH = prove
+ (`!g. simple_path g ==> path g`,
+  REWRITE_TAC[simple_path] THEN MESON_TAC[]);;
+
+let SIMPLE_PATH_CASES = prove
+ (`!g:real^1->real^N. simple_path g ==> arc g \/ pathfinish g = pathstart g`,
+  REWRITE_TAC[simple_path; arc; pathfinish; pathstart] THEN
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `(g:real^1->real^N) (vec 0) = g(vec 1)` THEN
+  ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^1`; `v:real^1`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`u:real^1`; `v:real^1`]) THEN
+  ASM_MESON_TAC[]);;
+
+let SIMPLE_PATH_IMP_ARC = prove
+ (`!g:real^1->real^N.
+        simple_path g /\ ~(pathfinish g = pathstart g) ==> arc g`,
+  MESON_TAC[SIMPLE_PATH_CASES]);;
+
+let ARC_DISTINCT_ENDS = prove
+ (`!g:real^1->real^N. arc g ==> ~(pathfinish g = pathstart g)`,
+  GEN_TAC THEN REWRITE_TAC[arc; pathfinish; pathstart] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> a /\ b /\ ~d ==> ~c`] THEN
+  DISCH_THEN(MATCH_MP_TAC o CONJUNCT2) THEN
+  REWRITE_TAC[GSYM DROP_EQ; IN_INTERVAL_1; DROP_VEC] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let ARC_SIMPLE_PATH = prove
+ (`!g:real^1->real^N.
+        arc g <=> simple_path g /\ ~(pathfinish g = pathstart g)`,
+  MESON_TAC[SIMPLE_PATH_CASES; ARC_IMP_SIMPLE_PATH; ARC_DISTINCT_ENDS]);;
+
+let SIMPLE_PATH_EQ_ARC = prove
+ (`!g. ~(pathstart g = pathfinish g) ==> (simple_path g <=> arc g)`,
+  SIMP_TAC[ARC_SIMPLE_PATH]);;
+
+let PATH_IMAGE_NONEMPTY = prove
+ (`!g. ~(path_image g = {})`,
+  REWRITE_TAC[path_image; IMAGE_EQ_EMPTY; INTERVAL_EQ_EMPTY] THEN
+  SIMP_TAC[DIMINDEX_1; CONJ_ASSOC; LE_ANTISYM; UNWIND_THM1; VEC_COMPONENT;
+           ARITH; REAL_OF_NUM_LT]);;
+
+let PATHSTART_IN_PATH_IMAGE = prove
+ (`!g. (pathstart g) IN path_image g`,
+  GEN_TAC THEN REWRITE_TAC[pathstart; path_image] THEN
+  MATCH_MP_TAC FUN_IN_IMAGE THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS]);;
+
+let PATHFINISH_IN_PATH_IMAGE = prove
+ (`!g. (pathfinish g) IN path_image g`,
+  GEN_TAC THEN REWRITE_TAC[pathfinish; path_image] THEN
+  MATCH_MP_TAC FUN_IN_IMAGE THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN REAL_ARITH_TAC);;
+
+let CONNECTED_PATH_IMAGE = prove
+ (`!g. path g ==> connected(path_image g)`,
+  REWRITE_TAC[path; path_image] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN
+  ASM_SIMP_TAC[CONVEX_CONNECTED; CONVEX_INTERVAL]);;
+
+let COMPACT_PATH_IMAGE = prove
+ (`!g. path g ==> compact(path_image g)`,
+  REWRITE_TAC[path; path_image] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+  ASM_REWRITE_TAC[COMPACT_INTERVAL]);;
+
+let BOUNDED_PATH_IMAGE = prove
+ (`!g. path g ==> bounded(path_image g)`,
+  MESON_TAC[COMPACT_PATH_IMAGE; COMPACT_IMP_BOUNDED]);;
+
+let CLOSED_PATH_IMAGE = prove
+ (`!g. path g ==> closed(path_image g)`,
+  MESON_TAC[COMPACT_PATH_IMAGE; COMPACT_IMP_CLOSED]);;
+
+let CONNECTED_SIMPLE_PATH_IMAGE = prove
+ (`!g. simple_path g ==> connected(path_image g)`,
+  MESON_TAC[CONNECTED_PATH_IMAGE; SIMPLE_PATH_IMP_PATH]);;
+
+let COMPACT_SIMPLE_PATH_IMAGE = prove
+ (`!g. simple_path g ==> compact(path_image g)`,
+  MESON_TAC[COMPACT_PATH_IMAGE; SIMPLE_PATH_IMP_PATH]);;
+
+let BOUNDED_SIMPLE_PATH_IMAGE = prove
+ (`!g. simple_path g ==> bounded(path_image g)`,
+  MESON_TAC[BOUNDED_PATH_IMAGE; SIMPLE_PATH_IMP_PATH]);;
+
+let CLOSED_SIMPLE_PATH_IMAGE = prove
+ (`!g. simple_path g ==> closed(path_image g)`,
+  MESON_TAC[CLOSED_PATH_IMAGE; SIMPLE_PATH_IMP_PATH]);;
+
+let CONNECTED_ARC_IMAGE = prove
+ (`!g. arc g ==> connected(path_image g)`,
+  MESON_TAC[CONNECTED_PATH_IMAGE; ARC_IMP_PATH]);;
+
+let COMPACT_ARC_IMAGE = prove
+ (`!g. arc g ==> compact(path_image g)`,
+  MESON_TAC[COMPACT_PATH_IMAGE; ARC_IMP_PATH]);;
+
+let BOUNDED_ARC_IMAGE = prove
+ (`!g. arc g ==> bounded(path_image g)`,
+  MESON_TAC[BOUNDED_PATH_IMAGE; ARC_IMP_PATH]);;
+
+let CLOSED_ARC_IMAGE = prove
+ (`!g. arc g ==> closed(path_image g)`,
+  MESON_TAC[CLOSED_PATH_IMAGE; ARC_IMP_PATH]);;
+
+let PATHSTART_COMPOSE = prove
+ (`!f p. pathstart(f o p) = f(pathstart p)`,
+  REWRITE_TAC[pathstart; o_THM]);;
+
+let PATHFINISH_COMPOSE = prove
+ (`!f p. pathfinish(f o p) = f(pathfinish p)`,
+  REWRITE_TAC[pathfinish; o_THM]);;
+
+let PATH_IMAGE_COMPOSE = prove
+ (`!f p. path_image (f o p) = IMAGE f (path_image p)`,
+  REWRITE_TAC[path_image; IMAGE_o]);;
+
+let PATH_COMPOSE_JOIN = prove
+ (`!f p q. f o (p ++ q) = (f o p) ++ (f o q)`,
+  REWRITE_TAC[joinpaths; o_DEF; FUN_EQ_THM] THEN MESON_TAC[]);;
+
+let PATH_COMPOSE_REVERSEPATH = prove
+ (`!f p. f o reversepath p = reversepath(f o p)`,
+  REWRITE_TAC[reversepath; o_DEF; FUN_EQ_THM] THEN MESON_TAC[]);;
+
+let JOIN_PATHS_EQ = prove
+ (`!p q:real^1->real^N.
+   (!t. t IN interval[vec 0,vec 1] ==> p t = p' t) /\
+   (!t. t IN interval[vec 0,vec 1] ==> q t = q' t)
+   ==> !t. t IN interval[vec 0,vec 1] ==> (p ++ q) t = (p' ++ q') t`,
+  REWRITE_TAC[joinpaths; IN_INTERVAL_1; DROP_VEC] THEN REPEAT STRIP_TAC THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_CMUL; DROP_SUB; DROP_VEC] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let CARD_EQ_SIMPLE_PATH_IMAGE = prove
+ (`!g. simple_path g ==> path_image g =_c (:real)`,
+  SIMP_TAC[CONNECTED_CARD_EQ_IFF_NONTRIVIAL; CONNECTED_SIMPLE_PATH_IMAGE] THEN
+  GEN_TAC THEN REWRITE_TAC[simple_path; path_image] THEN MATCH_MP_TAC(SET_RULE
+   `(?u v. u IN s /\ v IN s /\ ~(u = a) /\ ~(v = a) /\ ~(u = v))
+    ==> P /\ (!x y. x IN s /\ y IN s /\ f x = f y
+                    ==> x = y \/ x = a /\ y = b \/ x = b /\ y = a)
+        ==> ~(?c. IMAGE f s SUBSET {c})`) THEN
+  MAP_EVERY EXISTS_TAC [`lift(&1 / &3)`; `lift(&1 / &2)`] THEN
+  REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP; GSYM LIFT_NUM; LIFT_EQ] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let INFINITE_SIMPLE_PATH_IMAGE = prove
+ (`!g. simple_path g ==> INFINITE(path_image g)`,
+  MESON_TAC[CARD_EQ_SIMPLE_PATH_IMAGE; INFINITE; FINITE_IMP_COUNTABLE;
+            UNCOUNTABLE_REAL; CARD_COUNTABLE_CONG]);;
+
+let CARD_EQ_ARC_IMAGE = prove
+ (`!g. arc g ==> path_image g =_c (:real)`,
+  MESON_TAC[ARC_IMP_SIMPLE_PATH; CARD_EQ_SIMPLE_PATH_IMAGE]);;
+
+let INFINITE_ARC_IMAGE = prove
+ (`!g. arc g ==> INFINITE(path_image g)`,
+  MESON_TAC[ARC_IMP_SIMPLE_PATH; INFINITE_SIMPLE_PATH_IMAGE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Simple paths with the endpoints removed.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let SIMPLE_PATH_ENDLESS = prove
+ (`!c:real^1->real^N.
+        simple_path c
+        ==> path_image c DIFF {pathstart c,pathfinish c} =
+            IMAGE c (interval(vec 0,vec 1))`,
+  REWRITE_TAC[simple_path; path_image; pathstart; pathfinish] THEN
+  REWRITE_TAC[OPEN_CLOSED_INTERVAL_1; path] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(SET_RULE
+   `(!x y. x IN s /\ y IN s /\ c x = c y
+           ==> x = y \/ x = a /\ y = b \/ x = b /\ y = a) /\
+    a IN s /\ b IN s
+    ==>  IMAGE c s DIFF {c a,c b} = IMAGE c (s DIFF {a,b})`) THEN
+  ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL]);;
+
+let CONNECTED_SIMPLE_PATH_ENDLESS = prove
+ (`!c:real^1->real^N.
+        simple_path c
+        ==> connected(path_image c DIFF {pathstart c,pathfinish c})`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[SIMPLE_PATH_ENDLESS] THEN
+  MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN
+  SIMP_TAC[CONVEX_INTERVAL; CONVEX_CONNECTED] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+  EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[simple_path; path]) THEN
+  ASM_REWRITE_TAC[INTERVAL_OPEN_SUBSET_CLOSED]);;
+
+let NONEMPTY_SIMPLE_PATH_ENDLESS = prove
+ (`!c:real^1->real^N.
+      simple_path c ==> ~(path_image c DIFF {pathstart c,pathfinish c} = {})`,
+  SIMP_TAC[SIMPLE_PATH_ENDLESS; IMAGE_EQ_EMPTY; INTERVAL_EQ_EMPTY_1] THEN
+  REWRITE_TAC[DROP_VEC] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* The operations on paths.                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let JOINPATHS = prove
+ (`!g1 g2. pathfinish g1 = pathstart g2
+           ==> g1 ++ g2 = \x. if drop x < &1 / &2 then g1(&2 % x)
+                              else g2 (&2 % x - vec 1)`,
+  REWRITE_TAC[pathstart; pathfinish] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[joinpaths; FUN_EQ_THM] THEN
+  X_GEN_TAC `x:real^1` THEN ASM_CASES_TAC `drop x = &1 / &2` THENL
+   [FIRST_X_ASSUM(MP_TAC o AP_TERM `lift`) THEN
+    REWRITE_TAC[LIFT_DROP] THEN DISCH_THEN SUBST1_TAC THEN
+    REWRITE_TAC[LIFT_DROP; REAL_LE_REFL; GSYM LIFT_CMUL; REAL_LT_REFL] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ASM_REWRITE_TAC[LIFT_NUM; VECTOR_SUB_REFL];
+    REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN ASM_REAL_ARITH_TAC]);;
+
+let REVERSEPATH_REVERSEPATH = prove
+ (`!g:real^1->real^N. reversepath(reversepath g) = g`,
+  REWRITE_TAC[reversepath; ETA_AX;
+              VECTOR_ARITH `vec 1 - (vec 1 - x):real^1 = x`]);;
+
+let PATHSTART_REVERSEPATH = prove
+ (`pathstart(reversepath g) = pathfinish g`,
+  REWRITE_TAC[pathstart; reversepath; pathfinish; VECTOR_SUB_RZERO]);;
+
+let PATHFINISH_REVERSEPATH = prove
+ (`pathfinish(reversepath g) = pathstart g`,
+  REWRITE_TAC[pathstart; reversepath; pathfinish; VECTOR_SUB_REFL]);;
+
+let PATHSTART_JOIN = prove
+ (`!g1 g2. pathstart(g1 ++ g2) = pathstart g1`,
+  REWRITE_TAC[joinpaths; pathstart; pathstart; DROP_VEC; VECTOR_MUL_RZERO] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let PATHFINISH_JOIN = prove
+ (`!g1 g2. pathfinish(g1 ++ g2) = pathfinish g2`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[joinpaths; pathfinish; DROP_VEC] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN AP_TERM_TAC THEN VECTOR_ARITH_TAC);;
+
+let PATH_IMAGE_REVERSEPATH = prove
+ (`!g:real^1->real^N. path_image(reversepath g) = path_image g`,
+  SUBGOAL_THEN `!g:real^1->real^N.
+      path_image(reversepath g) SUBSET path_image g`
+   (fun th -> MESON_TAC[th; REVERSEPATH_REVERSEPATH; SUBSET_ANTISYM]) THEN
+  REWRITE_TAC[SUBSET; path_image; FORALL_IN_IMAGE] THEN
+  MAP_EVERY X_GEN_TAC [`g:real^1->real^N`; `x:real^1`] THEN
+  DISCH_TAC THEN REWRITE_TAC[reversepath; IN_IMAGE] THEN
+  EXISTS_TAC `vec 1 - x:real^1` THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_SUB; DROP_VEC] THEN REAL_ARITH_TAC);;
+
+let PATH_REVERSEPATH = prove
+ (`!g:real^1->real^N. path(reversepath g) <=> path g`,
+  SUBGOAL_THEN `!g:real^1->real^N. path g ==> path(reversepath g)`
+   (fun th -> MESON_TAC[th; REVERSEPATH_REVERSEPATH]) THEN
+  GEN_TAC THEN REWRITE_TAC[path; reversepath] THEN STRIP_TAC THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+  EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+  ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1] THEN
+  REWRITE_TAC[DROP_VEC; DROP_SUB] THEN REAL_ARITH_TAC);;
+
+let PATH_JOIN = prove
+ (`!g1 g2:real^1->real^N.
+        pathfinish g1 = pathstart g2
+        ==> (path(g1 ++ g2) <=> path g1 /\ path g2)`,
+  REWRITE_TAC[path; pathfinish; pathstart] THEN
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [STRIP_TAC THEN CONJ_TAC THENL
+     [SUBGOAL_THEN
+       `(g1:real^1->real^N) = (\x. g1 (&2 % x)) o (\x. &1 / &2 % x)`
+      SUBST1_TAC THENL
+       [REWRITE_TAC[FUN_EQ_THM; o_THM] THEN GEN_TAC THEN AP_TERM_TAC THEN
+        VECTOR_ARITH_TAC;
+        ALL_TAC] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_EQ THEN
+      EXISTS_TAC `(g1 ++ g2):real^1->real^N` THEN CONJ_TAC THENL
+       [REWRITE_TAC[FORALL_IN_IMAGE; joinpaths; IN_INTERVAL_1; DROP_CMUL] THEN
+        SIMP_TAC[DROP_VEC; REAL_ARITH `&1 / &2 * x <= &1 / &2 <=> x <= &1`];
+        ALL_TAC] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+      EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1; DROP_CMUL] THEN
+      REWRITE_TAC[DROP_VEC] THEN REAL_ARITH_TAC;
+      SUBGOAL_THEN
+       `(g2:real^1->real^N) =
+        (\x. g2 (&2 % x - vec 1)) o (\x. &1 / &2 % (x + vec 1))`
+      SUBST1_TAC THENL
+       [REWRITE_TAC[FUN_EQ_THM; o_THM] THEN GEN_TAC THEN AP_TERM_TAC THEN
+        VECTOR_ARITH_TAC;
+        ALL_TAC] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST;
+               CONTINUOUS_ON_ADD] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_EQ THEN
+      EXISTS_TAC `(g1 ++ g2):real^1->real^N` THEN CONJ_TAC THENL
+       [REWRITE_TAC[FORALL_IN_IMAGE; joinpaths; IN_INTERVAL_1; DROP_CMUL] THEN
+        REWRITE_TAC[DROP_VEC; DROP_ADD; REAL_ARITH
+         `&1 / &2 * (x + &1) <= &1 / &2 <=> x <= &0`] THEN
+        SIMP_TAC[REAL_ARITH `&0 <= x ==> (x <= &0 <=> x = &0)`; LIFT_NUM;
+          VECTOR_MUL_ASSOC; GSYM LIFT_EQ; LIFT_DROP; GSYM LIFT_CMUL] THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV THEN
+        ASM_REWRITE_TAC[VECTOR_ADD_LID; VECTOR_MUL_LID] THEN
+        REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+        REWRITE_TAC[VECTOR_ARITH `(x + vec 1) - vec 1 = x`];
+        ALL_TAC] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+      EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1; DROP_CMUL] THEN
+      REWRITE_TAC[DROP_VEC; DROP_ADD] THEN REAL_ARITH_TAC];
+    STRIP_TAC THEN
+    SUBGOAL_THEN `interval[vec 0,vec 1] =
+                  interval[vec 0,lift(&1 / &2)] UNION
+                  interval[lift(&1 / &2),vec 1]`
+    SUBST1_TAC THENL
+     [SIMP_TAC[EXTENSION; IN_UNION; IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_UNION THEN REWRITE_TAC[CLOSED_INTERVAL] THEN
+    CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_EQ THENL
+     [EXISTS_TAC `\x. (g1:real^1->real^N) (&2 % x)`;
+      EXISTS_TAC `\x. (g2:real^1->real^N) (&2 % x - vec 1)`] THEN
+    REWRITE_TAC[joinpaths] THEN SIMP_TAC[IN_INTERVAL_1; LIFT_DROP] THENL
+     [GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID] THEN
+      ONCE_REWRITE_TAC[VECTOR_ARITH `&2 % (x:real^1) = &2 % x + vec 0`] THEN
+      REWRITE_TAC[IMAGE_AFFINITY_INTERVAL] THEN
+      REWRITE_TAC[REAL_POS; INTERVAL_EQ_EMPTY_1; LIFT_DROP; DROP_VEC] THEN
+      REWRITE_TAC[GSYM LIFT_CMUL; VECTOR_ADD_RID; VECTOR_MUL_RZERO] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[LIFT_NUM];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [SIMP_TAC[REAL_ARITH `&1 / &2 <= x ==> (x <= &1 / &2 <=> x = &1 / &2)`;
+               GSYM LIFT_EQ; LIFT_DROP; GSYM LIFT_CMUL] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+      ASM_REWRITE_TAC[LIFT_NUM] THEN
+      REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[GSYM LIFT_CMUL] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      REWRITE_TAC[LIFT_NUM; VECTOR_SUB_REFL];
+      ALL_TAC] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_CMUL; CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST;
+             CONTINUOUS_ON_ID] THEN
+    ONCE_REWRITE_TAC[VECTOR_ARITH `&2 % x - vec 1 = &2 % x + --vec 1`] THEN
+    REWRITE_TAC[IMAGE_AFFINITY_INTERVAL] THEN
+    REWRITE_TAC[REAL_POS; INTERVAL_EQ_EMPTY_1; LIFT_DROP; DROP_VEC] THEN
+    REWRITE_TAC[GSYM LIFT_CMUL; VECTOR_ADD_RID; VECTOR_MUL_RZERO] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[LIFT_NUM] THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH `&2 % x + --x = x /\ x + --x = vec 0`]]);;
+
+let PATH_JOIN_IMP = prove
+ (`!g1 g2:real^1->real^N.
+        path g1 /\ path g2 /\ pathfinish g1 = pathstart g2
+        ==> path(g1 ++ g2)`,
+  MESON_TAC[PATH_JOIN]);;
+
+let PATH_IMAGE_JOIN_SUBSET = prove
+ (`!g1 g2:real^1->real^N.
+        path_image(g1 ++ g2) SUBSET (path_image g1 UNION path_image g2)`,
+  REWRITE_TAC[path_image; FORALL_IN_IMAGE; SUBSET] THEN
+  GEN_TAC THEN GEN_TAC THEN X_GEN_TAC `x:real^1` THEN
+  REWRITE_TAC[IN_INTERVAL_1; IN_UNION; IN_IMAGE; DROP_VEC; joinpaths] THEN
+  STRIP_TAC THEN ASM_CASES_TAC `drop x <= &1 / &2` THEN ASM_REWRITE_TAC[] THENL
+   [DISJ1_TAC THEN EXISTS_TAC `&2 % x:real^1` THEN REWRITE_TAC[DROP_CMUL];
+    DISJ2_TAC THEN EXISTS_TAC `&2 % x - vec 1:real^1` THEN
+    REWRITE_TAC[DROP_CMUL; DROP_SUB; DROP_VEC]] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let SUBSET_PATH_IMAGE_JOIN = prove
+ (`!g1 g2:real^1->real^N s.
+        path_image g1 SUBSET s /\ path_image g2 SUBSET s
+        ==> path_image(g1 ++ g2) SUBSET s`,
+  MP_TAC PATH_IMAGE_JOIN_SUBSET THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  SET_TAC[]);;
+
+let PATH_IMAGE_JOIN = prove
+ (`!g1 g2. pathfinish g1 = pathstart g2
+           ==> path_image(g1 ++ g2) = path_image g1 UNION path_image g2`,
+  REWRITE_TAC[pathfinish; pathstart] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[PATH_IMAGE_JOIN_SUBSET] THEN
+  REWRITE_TAC[path_image; SUBSET; FORALL_AND_THM; IN_UNION; TAUT
+                `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; joinpaths] THEN
+  REWRITE_TAC[IN_INTERVAL_1; IN_IMAGE; DROP_VEC] THEN
+  CONJ_TAC THEN X_GEN_TAC `x:real^1` THEN REPEAT STRIP_TAC THENL
+   [EXISTS_TAC `(&1 / &2) % x:real^1` THEN
+    ASM_REWRITE_TAC[DROP_CMUL; REAL_ARITH
+     `&1 / &2 * x <= &1 / &2 <=> x <= &1`] THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_LID];
+    EXISTS_TAC `(&1 / &2) % (x + vec 1):real^1` THEN
+    ASM_REWRITE_TAC[DROP_CMUL; DROP_ADD; DROP_VEC] THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[VECTOR_MUL_LID; VECTOR_ARITH `(x + vec 1) - vec 1 = x`] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 <= x ==> (&1 / &2 * (x + &1) <= &1 / &2 <=>
+                                          x = &0)`] THEN
+    REWRITE_TAC[GSYM LIFT_EQ; LIFT_DROP; LIFT_NUM] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[VECTOR_ADD_LID; DROP_VEC]] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let NOT_IN_PATH_IMAGE_JOIN = prove
+ (`!g1 g2 x. ~(x IN path_image g1) /\ ~(x IN path_image g2)
+             ==> ~(x IN path_image(g1 ++ g2))`,
+  MESON_TAC[PATH_IMAGE_JOIN_SUBSET; SUBSET; IN_UNION]);;
+
+let ARC_REVERSEPATH = prove
+ (`!g. arc g ==> arc(reversepath g)`,
+  GEN_TAC THEN SIMP_TAC[arc; PATH_REVERSEPATH] THEN
+  REWRITE_TAC[arc; reversepath] THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`vec 1 - x:real^1`; `vec 1 - y:real^1`]) THEN
+  ASM_REWRITE_TAC[] THEN REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[IN_INTERVAL_1; GSYM DROP_EQ; DROP_SUB; DROP_VEC] THEN
+  REAL_ARITH_TAC);;
+
+let SIMPLE_PATH_REVERSEPATH = prove
+ (`!g. simple_path g ==> simple_path (reversepath g)`,
+  GEN_TAC THEN SIMP_TAC[simple_path; PATH_REVERSEPATH] THEN
+  REWRITE_TAC[simple_path; reversepath] THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`vec 1 - x:real^1`; `vec 1 - y:real^1`]) THEN
+  ASM_REWRITE_TAC[] THEN REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[IN_INTERVAL_1; GSYM DROP_EQ; DROP_SUB; DROP_VEC] THEN
+  REAL_ARITH_TAC);;
+
+let SIMPLE_PATH_JOIN_LOOP = prove
+ (`!g1 g2:real^1->real^N.
+        arc g1 /\ arc g2 /\
+        pathfinish g1 = pathstart g2 /\
+        pathfinish g2 = pathstart g1 /\
+        (path_image g1 INTER path_image g2) SUBSET
+            {pathstart g1,pathstart g2}
+        ==> simple_path(g1 ++ g2)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[arc; simple_path] THEN
+  MATCH_MP_TAC(TAUT
+   `(a /\ b /\ c /\ d ==> f) /\
+    (a' /\ b' /\ c /\ d /\ e ==> g)
+    ==> (a /\ a') /\ (b /\ b') /\ c /\ d /\ e ==> f /\ g`) THEN
+  CONJ_TAC THENL [MESON_TAC[PATH_JOIN]; ALL_TAC] THEN
+  REWRITE_TAC[arc; simple_path; SUBSET; IN_INTER; pathstart;
+    pathfinish; IN_INTERVAL_1; DROP_VEC; IN_INSERT; NOT_IN_EMPTY] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "G1") MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "G2") MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "G0")) THEN
+  MATCH_MP_TAC DROP_WLOG_LE THEN CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[joinpaths] THEN
+  MAP_EVERY ASM_CASES_TAC [`drop x <= &1 / &2`; `drop y <= &1 / &2`] THEN
+  ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THENL
+   [REMOVE_THEN "G1" (MP_TAC o SPECL [`&2 % x:real^1`; `&2 % y:real^1`]) THEN
+    ASM_REWRITE_TAC[DROP_CMUL; DROP_VEC; DROP_SUB] THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    DISCH_THEN(fun th -> DISJ1_TAC THEN MP_TAC th) THEN VECTOR_ARITH_TAC;
+    ALL_TAC;
+    ASM_REAL_ARITH_TAC;
+    REMOVE_THEN "G2" (MP_TAC o SPECL
+     [`&2 % x:real^1 - vec 1`; `&2 % y:real^1 - vec 1`]) THEN
+    ASM_REWRITE_TAC[DROP_CMUL; DROP_VEC; DROP_SUB] THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    DISCH_THEN(fun th -> DISJ1_TAC THEN MP_TAC th) THEN VECTOR_ARITH_TAC] THEN
+  REMOVE_THEN "G0" (MP_TAC o SPEC `(g1:real^1->real^N) (&2 % x)`) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [REWRITE_TAC[path_image; IN_IMAGE] THEN EXISTS_TAC `&2 % x:real^1` THEN
+      REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_CMUL] THEN
+      ASM_REAL_ARITH_TAC;
+      ASM_REWRITE_TAC[path_image; IN_IMAGE] THEN
+      EXISTS_TAC `&2 % y:real^1 - vec 1` THEN
+      REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_CMUL; DROP_SUB] THEN
+      ASM_REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  STRIP_TAC THENL
+   [DISJ2_TAC THEN DISJ1_TAC;
+    DISJ1_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `&1 / &2 % vec 1:real^1`] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [SUBGOAL_THEN `&2 % x:real^1 = vec 0` MP_TAC THENL
+     [ALL_TAC; VECTOR_ARITH_TAC] THEN
+    REMOVE_THEN "G1" MATCH_MP_TAC;
+    DISCH_THEN SUBST_ALL_TAC THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[VECTOR_MUL_RZERO]) THEN
+    UNDISCH_TAC `T` THEN REWRITE_TAC[] THEN
+    SUBGOAL_THEN `&2 % y:real^1 - vec 1 = vec 1` MP_TAC THENL
+     [ALL_TAC; VECTOR_ARITH_TAC] THEN
+    REMOVE_THEN "G2" MATCH_MP_TAC;
+    SUBGOAL_THEN `&2 % x:real^1 = vec 1` MP_TAC THENL
+     [ALL_TAC; VECTOR_ARITH_TAC] THEN
+    REMOVE_THEN "G1" MATCH_MP_TAC;
+    DISCH_THEN SUBST_ALL_TAC THEN
+    SUBGOAL_THEN `&2 % y:real^1 - vec 1 = vec 0` MP_TAC THENL
+     [ALL_TAC; VECTOR_ARITH_TAC] THEN
+    REMOVE_THEN "G2" MATCH_MP_TAC] THEN
+  (REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+    [ALL_TAC; ASM_MESON_TAC[]] THEN
+   ASM_REWRITE_TAC[DROP_CMUL; DROP_SUB; DROP_VEC] THEN
+   ASM_REAL_ARITH_TAC));;
+
+let ARC_JOIN = prove
+ (`!g1 g2:real^1->real^N.
+        arc g1 /\ arc g2 /\
+        pathfinish g1 = pathstart g2 /\
+        (path_image g1 INTER path_image g2) SUBSET {pathstart g2}
+        ==> arc(g1 ++ g2)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[arc; simple_path] THEN
+  MATCH_MP_TAC(TAUT
+   `(a /\ b /\ c /\ d ==> f) /\
+    (a' /\ b' /\ c /\ d ==> g)
+    ==> (a /\ a') /\ (b /\ b') /\ c /\ d ==> f /\ g`) THEN
+  CONJ_TAC THENL [MESON_TAC[PATH_JOIN]; ALL_TAC] THEN
+  REWRITE_TAC[arc; simple_path; SUBSET; IN_INTER; pathstart;
+    pathfinish; IN_INTERVAL_1; DROP_VEC; IN_INSERT; NOT_IN_EMPTY] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "G1") MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "G2") MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "G0")) THEN
+  MATCH_MP_TAC DROP_WLOG_LE THEN CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[joinpaths] THEN
+  MAP_EVERY ASM_CASES_TAC [`drop x <= &1 / &2`; `drop y <= &1 / &2`] THEN
+  ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THENL
+   [REMOVE_THEN "G1" (MP_TAC o SPECL [`&2 % x:real^1`; `&2 % y:real^1`]) THEN
+    ASM_REWRITE_TAC[DROP_CMUL; DROP_VEC; DROP_SUB] THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    VECTOR_ARITH_TAC;
+    ALL_TAC;
+    ASM_REAL_ARITH_TAC;
+    REMOVE_THEN "G2" (MP_TAC o SPECL
+     [`&2 % x:real^1 - vec 1`; `&2 % y:real^1 - vec 1`]) THEN
+    ASM_REWRITE_TAC[DROP_CMUL; DROP_VEC; DROP_SUB] THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    VECTOR_ARITH_TAC] THEN
+  REMOVE_THEN "G0" (MP_TAC o SPEC `(g1:real^1->real^N) (&2 % x)`) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [REWRITE_TAC[path_image; IN_IMAGE] THEN EXISTS_TAC `&2 % x:real^1` THEN
+      REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_CMUL] THEN
+      ASM_REAL_ARITH_TAC;
+      ASM_REWRITE_TAC[path_image; IN_IMAGE] THEN
+      EXISTS_TAC `&2 % y:real^1 - vec 1` THEN
+      REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_CMUL; DROP_SUB] THEN
+      ASM_REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `x:real^1 = &1 / &2 % vec 1` SUBST_ALL_TAC THENL
+   [SUBGOAL_THEN `&2 % x:real^1 = vec 1` MP_TAC THENL
+     [ALL_TAC; VECTOR_ARITH_TAC] THEN
+    REMOVE_THEN "G1" MATCH_MP_TAC;
+    SUBGOAL_THEN `&2 % y:real^1 - vec 1 = vec 0` MP_TAC THENL
+     [ALL_TAC; VECTOR_ARITH_TAC] THEN
+    REMOVE_THEN "G2" MATCH_MP_TAC] THEN
+  (REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+    [ALL_TAC; ASM_MESON_TAC[]] THEN
+   ASM_REWRITE_TAC[DROP_CMUL; DROP_SUB; DROP_VEC] THEN
+   ASM_REAL_ARITH_TAC));;
+
+let REVERSEPATH_JOINPATHS = prove
+ (`!g1 g2. pathfinish g1 = pathstart g2
+           ==> reversepath(g1 ++ g2) = reversepath g2 ++ reversepath g1`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[reversepath; joinpaths; pathfinish; pathstart; FUN_EQ_THM] THEN
+  DISCH_TAC THEN X_GEN_TAC `t:real^1` THEN
+  REWRITE_TAC[DROP_VEC; DROP_SUB; REAL_ARITH
+   `&1 - x <= &1 / &2 <=> &1 / &2 <= x`] THEN
+  ASM_CASES_TAC `t = lift(&1 / &2)` THENL
+   [ASM_REWRITE_TAC[LIFT_DROP; REAL_LE_REFL; GSYM LIFT_NUM; GSYM LIFT_SUB;
+                    GSYM LIFT_CMUL] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[LIFT_NUM];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [GSYM DROP_EQ]) THEN
+    REWRITE_TAC[LIFT_DROP] THEN DISCH_TAC THEN
+    ASM_SIMP_TAC[REAL_ARITH
+     `~(x = &1 / &2) ==> (&1 / &2 <= x <=> ~(x <= &1 / &2))`] THEN
+    ASM_CASES_TAC `drop t <= &1 / &2` THEN ASM_REWRITE_TAC[] THEN
+    AP_TERM_TAC THEN REWRITE_TAC[VECTOR_SUB_LDISTRIB] THEN VECTOR_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some reversed and "if and only if" versions of joining theorems.          *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_JOIN_PATH_ENDS = prove
+ (`!g1 g2:real^1->real^N.
+        path g2 /\ path(g1 ++ g2) ==> pathfinish g1 = pathstart g2`,
+  REPEAT GEN_TAC THEN DISJ_CASES_TAC(NORM_ARITH
+   `pathfinish g1:real^N = pathstart g2 \/
+    &0 < dist(pathfinish g1,pathstart g2)`) THEN
+  ASM_REWRITE_TAC[path; continuous_on; joinpaths] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+  REWRITE_TAC[pathstart; pathfinish] THEN
+  ABBREV_TAC `e = dist((g1:real^1->real^N)(vec 1),g2(vec 0:real^1))` THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (MP_TAC o SPEC `vec 0:real^1`) (MP_TAC o SPEC `lift(&1 / &2)`)) THEN
+  REWRITE_TAC[ENDS_IN_UNIT_INTERVAL; LIFT_DROP; REAL_LE_REFL] THEN
+  REWRITE_TAC[GSYM LIFT_CMUL; IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[LIFT_NUM] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "1"))) THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d2:real`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "2"))) THEN
+  REMOVE_THEN "2" (MP_TAC o SPEC `lift(min (&1 / &2) (min d1 d2) / &2)`) THEN
+  REWRITE_TAC[LIFT_DROP; DIST_LIFT; DIST_0; NORM_REAL; GSYM drop] THEN
+  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  REMOVE_THEN "1" (MP_TAC o SPEC
+   `lift(&1 / &2 + min (&1 / &2) (min d1 d2) / &4)`) THEN
+  REWRITE_TAC[LIFT_DROP; DIST_LIFT] THEN
+  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  COND_CASES_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[GSYM LIFT_CMUL; LIFT_ADD; REAL_ADD_LDISTRIB] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[LIFT_NUM] THEN
+  REWRITE_TAC[VECTOR_ADD_SUB; REAL_ARITH `&2 * x / &4 = x / &2`] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC);;
+
+let PATH_JOIN_EQ = prove
+ (`!g1 g2:real^1->real^N.
+        path g1 /\ path g2
+        ==> (path(g1 ++ g2) <=> pathfinish g1 = pathstart g2)`,
+  MESON_TAC[PATH_JOIN_PATH_ENDS; PATH_JOIN_IMP]);;
+
+let SIMPLE_PATH_JOIN_IMP = prove
+ (`!g1 g2:real^1->real^N.
+        simple_path(g1 ++ g2) /\ pathfinish g1 = pathstart g2
+        ==> arc g1 /\ arc g2 /\
+            path_image g1 INTER path_image g2 SUBSET
+            {pathstart g1, pathstart g2}`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `path(g1:real^1->real^N) /\ path(g2:real^1->real^N)` THENL
+   [ALL_TAC; ASM_MESON_TAC[PATH_JOIN; SIMPLE_PATH_IMP_PATH]] THEN
+  REWRITE_TAC[simple_path; pathstart; pathfinish; arc] THEN
+  STRIP_TAC THEN REPEAT CONJ_TAC THEN ASM_REWRITE_TAC[] THENL
+   [MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`&1 / &2 % x:real^1`; `&1 / &2 % y:real^1`]) THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; joinpaths; DROP_CMUL] THEN
+    REPEAT(COND_CASES_TAC THEN TRY ASM_REAL_ARITH_TAC) THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ASM_REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; VECTOR_MUL_LID; DROP_VEC] THEN
+    ASM_REAL_ARITH_TAC;
+    MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`&1 / &2 % (x + vec 1):real^1`; `&1 / &2 % (y + vec 1):real^1`]) THEN
+    ASM_SIMP_TAC[JOINPATHS; pathstart; pathfinish] THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_ADD; DROP_CMUL] THEN
+    REPEAT(COND_CASES_TAC THEN TRY ASM_REAL_ARITH_TAC) THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_LID; VECTOR_ARITH `(a + b) - b:real^N = a`] THEN
+    ASM_REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; VECTOR_MUL_LID; DROP_VEC;
+                    DROP_ADD] THEN
+    ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[SET_RULE
+     `s INTER t SUBSET u <=> !x. x IN s ==> x IN t ==> x IN u`] THEN
+    REWRITE_TAC[path_image; FORALL_IN_IMAGE] THEN X_GEN_TAC `x:real^1` THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN STRIP_TAC THEN
+    REWRITE_TAC[IN_IMAGE; LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `y:real^1` THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN STRIP_TAC THEN
+    SUBST1_TAC(SYM(ASSUME
+     `(g1:real^1->real^N)(vec 1) = g2(vec 0:real^1)`)) THEN
+    MATCH_MP_TAC(SET_RULE `x = a \/ x = b ==> f x IN {f a,f b}`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`&1 / &2 % x:real^1`; `&1 / &2 % (y + vec 1):real^1`]) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_CMUL; DROP_ADD] THEN
+      REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+      GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [joinpaths] THEN
+      ASM_SIMP_TAC[JOINPATHS; pathstart; pathfinish] THEN
+      REWRITE_TAC[DROP_ADD; DROP_CMUL; DROP_VEC] THEN
+      REPEAT(COND_CASES_TAC THEN TRY ASM_REAL_ARITH_TAC) THEN
+      REWRITE_TAC[VECTOR_ARITH `&2 % &1 / &2 % x:real^N = x`] THEN
+      ASM_REWRITE_TAC[VECTOR_ARITH `(a + b) - b:real^N = a`];
+      REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; DROP_ADD; DROP_VEC] THEN
+      ASM_REAL_ARITH_TAC]]);;
+
+let SIMPLE_PATH_JOIN_LOOP_EQ = prove
+ (`!g1 g2:real^1->real^N.
+        pathfinish g2 = pathstart g1 /\
+        pathfinish g1 = pathstart g2
+        ==> (simple_path(g1 ++ g2) <=>
+             arc g1 /\ arc g2 /\
+             path_image g1 INTER path_image g2 SUBSET
+             {pathstart g1, pathstart g2})`,
+  MESON_TAC[SIMPLE_PATH_JOIN_IMP; SIMPLE_PATH_JOIN_LOOP]);;
+
+let ARC_JOIN_EQ = prove
+ (`!g1 g2:real^1->real^N.
+        pathfinish g1 = pathstart g2
+        ==> (arc(g1 ++ g2) <=>
+             arc g1 /\ arc g2 /\
+             path_image g1 INTER path_image g2 SUBSET {pathstart g2})`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN ASM_SIMP_TAC[ARC_JOIN] THEN
+  GEN_REWRITE_TAC LAND_CONV [ARC_SIMPLE_PATH] THEN
+  REWRITE_TAC[PATHFINISH_JOIN; PATHSTART_JOIN] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`g1:real^1->real^N`; `g2:real^1->real^N`]
+        SIMPLE_PATH_JOIN_IMP) THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `~((pathstart g1:real^N) IN path_image g2)`
+   (fun th -> MP_TAC th THEN ASM SET_TAC[]) THEN
+  REWRITE_TAC[path_image; IN_IMAGE; IN_INTERVAL_1; DROP_VEC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^1` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [simple_path]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`vec 0:real^1`; `lift(&1 / &2) + inv(&2) % u`] o
+    CONJUNCT2) THEN
+  REWRITE_TAC[GSYM DROP_EQ; IN_INTERVAL_1; DROP_ADD; DROP_VEC;
+              DROP_CMUL; LIFT_DROP; joinpaths] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LT_IMP_NZ;
+               REAL_ARITH `&0 <= x ==> &0 < &1 / &2 + &1 / &2 * x`] THEN
+  REWRITE_TAC[REAL_ARITH `&1 / &2 + &1 / &2 * u = &1 <=> u = &1`] THEN
+  ASM_SIMP_TAC[REAL_ARITH
+   `&0 <= u ==> (&1 / &2 + &1 / &2 * u <= &1 / &2 <=> u = &0)`] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_RZERO] THEN
+  ASM_SIMP_TAC[REAL_ARITH `u <= &1 ==> &1 / &2 + &1 / &2 * u <= &1`] THEN
+  REWRITE_TAC[GSYM LIFT_EQ; LIFT_NUM; LIFT_DROP] THEN COND_CASES_TAC THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_RID; GSYM LIFT_CMUL] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[LIFT_NUM] THEN
+    ASM_REWRITE_TAC[VEC_EQ] THEN ARITH_TAC;
+    REWRITE_TAC[VECTOR_ADD_LDISTRIB; GSYM LIFT_CMUL] THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[LIFT_NUM; VECTOR_MUL_LID; VECTOR_ADD_SUB] THEN
+    ASM_MESON_TAC[]]);;
+
+let ARC_JOIN_EQ_ALT = prove
+ (`!g1 g2:real^1->real^N.
+        pathfinish g1 = pathstart g2
+        ==> (arc(g1 ++ g2) <=>
+             arc g1 /\ arc g2 /\
+             path_image g1 INTER path_image g2 = {pathstart g2})`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[ARC_JOIN_EQ] THEN
+  MP_TAC(ISPEC `g1:real^1->real^N` PATHFINISH_IN_PATH_IMAGE) THEN
+  MP_TAC(ISPEC `g2:real^1->real^N` PATHSTART_IN_PATH_IMAGE) THEN
+  ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Reassociating a joined path doesn't matter for various properties.        *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_ASSOC = prove
+ (`!p q r:real^1->real^N.
+        pathfinish p = pathstart q /\ pathfinish q = pathstart r
+        ==> (path(p ++ (q ++ r)) <=> path((p ++ q) ++ r))`,
+  SIMP_TAC[PATH_JOIN; PATHSTART_JOIN; PATHFINISH_JOIN] THEN CONV_TAC TAUT);;
+
+let SIMPLE_PATH_ASSOC = prove
+ (`!p q r:real^1->real^N.
+        pathfinish p = pathstart q /\ pathfinish q = pathstart r
+        ==> (simple_path(p ++ (q ++ r)) <=> simple_path((p ++ q) ++ r))`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `pathstart(p:real^1->real^N) = pathfinish r` THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[SIMPLE_PATH_EQ_ARC; PATHSTART_JOIN; PATHFINISH_JOIN]] THEN
+  ASM_SIMP_TAC[SIMPLE_PATH_JOIN_LOOP_EQ; PATHSTART_JOIN; PATHFINISH_JOIN;
+               ARC_JOIN_EQ; PATH_IMAGE_JOIN] THEN
+  MAP_EVERY ASM_CASES_TAC
+   [`arc(p:real^1->real^N)`; `arc(q:real^1->real^N)`;
+    `arc(r:real^1->real^N)`] THEN
+  ASM_REWRITE_TAC[UNION_OVER_INTER; UNION_SUBSET;
+                  ONCE_REWRITE_RULE[INTER_COMM] UNION_OVER_INTER] THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o MATCH_MP ARC_DISTINCT_ENDS)) THEN
+  MAP_EVERY (fun t -> MP_TAC(ISPEC t PATHSTART_IN_PATH_IMAGE) THEN
+                      MP_TAC(ISPEC t PATHFINISH_IN_PATH_IMAGE))
+   [`p:real^1->real^N`; `q:real^1->real^N`; `r:real^1->real^N`] THEN
+  ASM SET_TAC[]);;
+
+let ARC_ASSOC = prove
+ (`!p q r:real^1->real^N.
+        pathfinish p = pathstart q /\ pathfinish q = pathstart r
+        ==> (arc(p ++ (q ++ r)) <=> arc((p ++ q) ++ r))`,
+  SIMP_TAC[ARC_SIMPLE_PATH; SIMPLE_PATH_ASSOC] THEN
+  SIMP_TAC[PATHSTART_JOIN; PATHFINISH_JOIN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In the case of a loop, neither does symmetry.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_SYM = prove
+ (`!p q. pathfinish p = pathstart q /\ pathfinish q = pathstart p
+         ==> (path(p ++ q) <=> path(q ++ p))`,
+  SIMP_TAC[PATH_JOIN; CONJ_ACI]);;
+
+let SIMPLE_PATH_SYM = prove
+ (`!p q. pathfinish p = pathstart q /\ pathfinish q = pathstart p
+         ==> (simple_path(p ++ q) <=> simple_path(q ++ p))`,
+  SIMP_TAC[SIMPLE_PATH_JOIN_LOOP_EQ; INTER_ACI; CONJ_ACI; INSERT_AC]);;
+
+let PATH_IMAGE_SYM = prove
+ (`!p q. pathfinish p = pathstart q /\ pathfinish q = pathstart p
+         ==> path_image(p ++ q) = path_image(q ++ p)`,
+  SIMP_TAC[PATH_IMAGE_JOIN; UNION_ACI]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Reparametrizing a closed curve to start at some chosen point.             *)
+(* ------------------------------------------------------------------------- *)
+
+let shiftpath = new_definition
+  `shiftpath a (f:real^1->real^N) =
+        \x. if drop(a + x) <= &1 then f(a + x)
+            else f(a + x - vec 1)`;;
+
+let SHIFTPATH_TRANSLATION = prove
+ (`!a t g. shiftpath t ((\x. a + x) o g) = (\x. a + x) o shiftpath t g`,
+  REWRITE_TAC[FUN_EQ_THM; shiftpath; o_THM] THEN MESON_TAC[]);;
+
+add_translation_invariants [SHIFTPATH_TRANSLATION];;
+
+let SHIFTPATH_LINEAR_IMAGE = prove
+ (`!f t g. linear f ==> shiftpath t (f o g) = f o shiftpath t g`,
+  REWRITE_TAC[FUN_EQ_THM; shiftpath; o_THM] THEN MESON_TAC[]);;
+
+add_linear_invariants [SHIFTPATH_LINEAR_IMAGE];;
+
+let PATHSTART_SHIFTPATH = prove
+ (`!a g. drop a <= &1 ==> pathstart(shiftpath a g) = g(a)`,
+  SIMP_TAC[pathstart; shiftpath; VECTOR_ADD_RID]);;
+
+let PATHFINISH_SHIFTPATH = prove
+ (`!a g. &0 <= drop a /\ pathfinish g = pathstart g
+         ==> pathfinish(shiftpath a g) = g(a)`,
+  SIMP_TAC[pathfinish; shiftpath; pathstart; DROP_ADD; DROP_VEC] THEN
+  REWRITE_TAC[VECTOR_ARITH `a + vec 1 - vec 1 = a`] THEN
+  ASM_SIMP_TAC[REAL_ARITH `&0 <= x ==> (x + &1 <= &1 <=> x = &0)`] THEN
+  SIMP_TAC[DROP_EQ_0; VECTOR_ADD_LID] THEN MESON_TAC[]);;
+
+let ENDPOINTS_SHIFTPATH = prove
+ (`!a g. pathfinish g = pathstart g /\ a IN interval[vec 0,vec 1]
+         ==> pathfinish(shiftpath a g) = g a /\
+             pathstart(shiftpath a g) = g a`,
+  SIMP_TAC[IN_INTERVAL_1; DROP_VEC;
+           PATHSTART_SHIFTPATH; PATHFINISH_SHIFTPATH]);;
+
+let CLOSED_SHIFTPATH = prove
+ (`!a g. pathfinish g = pathstart g /\ a IN interval[vec 0,vec 1]
+         ==> pathfinish(shiftpath a g) = pathstart(shiftpath a g)`,
+  SIMP_TAC[IN_INTERVAL_1; PATHSTART_SHIFTPATH; PATHFINISH_SHIFTPATH;
+           DROP_VEC]);;
+
+let PATH_SHIFTPATH = prove
+ (`!g a. path g /\ pathfinish g:real^N = pathstart g /\
+         a IN interval[vec 0,vec 1]
+         ==> path(shiftpath a g)`,
+  REWRITE_TAC[shiftpath; path] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `interval[vec 0,vec 1] = interval[vec 0,vec 1 - a:real^1] UNION
+                            interval[vec 1 - a,vec 1]`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_UNION; IN_INTERVAL_1] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+    REWRITE_TAC[DROP_SUB; DROP_VEC] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_UNION THEN REWRITE_TAC[CLOSED_INTERVAL] THEN
+  CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_EQ THENL
+   [EXISTS_TAC `(\x. g(a + x)):real^1->real^N` THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_ADD; DROP_VEC; DROP_SUB] THEN
+    SIMP_TAC[REAL_ARITH `a + x <= &1 <=> x <= &1 - a`];
+    EXISTS_TAC `(\x. g(a + x - vec 1)):real^1->real^N` THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_ADD; DROP_VEC; DROP_SUB] THEN
+    SIMP_TAC[REAL_ARITH `&1 - a <= x ==> (a + x <= &1 <=> a + x = &1)`] THEN
+    ONCE_REWRITE_TAC[COND_RAND] THEN
+    REWRITE_TAC[VECTOR_ARITH `a + x - vec 1 = (a + x) - vec 1`] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+    ASM_SIMP_TAC[GSYM LIFT_EQ; LIFT_ADD; LIFT_NUM; LIFT_DROP] THEN
+    REWRITE_TAC[VECTOR_SUB_REFL; COND_ID]] THEN
+  MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_COMPOSE) THEN
+  SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID;
+           CONTINUOUS_ON_SUB] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+  EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+  ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_SUB; DROP_VEC; DROP_ADD] THEN
+  REAL_ARITH_TAC);;
+
+let SHIFTPATH_SHIFTPATH = prove
+ (`!g a x. a IN interval[vec 0,vec 1] /\ pathfinish g = pathstart g /\
+           x IN interval[vec 0,vec 1]
+           ==> shiftpath (vec 1 - a) (shiftpath a g) x = g x`,
+  REWRITE_TAC[shiftpath; pathfinish; pathstart] THEN
+  REWRITE_TAC[DROP_ADD; DROP_SUB; DROP_VEC] THEN
+  REPEAT STRIP_TAC THEN REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1])) THEN
+  REWRITE_TAC[DROP_VEC] THEN REPEAT STRIP_TAC THENL
+   [ALL_TAC;
+    AP_TERM_TAC THEN VECTOR_ARITH_TAC;
+    AP_TERM_TAC THEN VECTOR_ARITH_TAC;
+    ASM_REAL_ARITH_TAC] THEN
+  SUBGOAL_THEN `x:real^1 = vec 0` SUBST1_TAC THENL
+   [REWRITE_TAC[GSYM DROP_EQ; DROP_VEC] THEN
+    ASM_REAL_ARITH_TAC;
+    ASM_REWRITE_TAC[VECTOR_ARITH `a + vec 1 - a + vec 0:real^1 = vec 1`]]);;
+
+let PATH_IMAGE_SHIFTPATH = prove
+ (`!a g:real^1->real^N.
+        a IN interval[vec 0,vec 1] /\ pathfinish g = pathstart g
+        ==> path_image(shiftpath a g) = path_image g`,
+  REWRITE_TAC[IN_INTERVAL_1; pathfinish; pathstart] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THEN
+  REWRITE_TAC[path_image; shiftpath; FORALL_IN_IMAGE; SUBSET] THEN
+  REWRITE_TAC[IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+  REPEAT COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_IMAGE] THENL
+   [EXISTS_TAC `a + x:real^1`;
+    EXISTS_TAC `a + x - vec 1:real^1`;
+    ALL_TAC] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_SUB; DROP_ADD] THEN
+  TRY REAL_ARITH_TAC THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `drop a <= drop x` THENL
+   [EXISTS_TAC `x - a:real^1` THEN
+    REWRITE_TAC[VECTOR_ARITH `a + x - a:real^1 = x`; DROP_SUB] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_REAL_ARITH_TAC;
+    EXISTS_TAC `vec 1 + x - a:real^1` THEN
+    REWRITE_TAC[VECTOR_ARITH `a + (v + x - a) - v:real^1 = x`] THEN
+    REWRITE_TAC[DROP_ADD; DROP_SUB; DROP_VEC] THEN
+    ASM_CASES_TAC `x:real^1 = vec 0` THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH `a + v + x - a:real^1 = v + x`] THEN
+    ASM_REWRITE_TAC[VECTOR_ADD_RID; DROP_VEC; COND_ID] THEN
+    ASM_REWRITE_TAC[REAL_ARITH `a + &1 + x - a <= &1 <=> x <= &0`] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN REWRITE_TAC[GSYM DROP_EQ; DROP_VEC] THEN
+    TRY(COND_CASES_TAC THEN POP_ASSUM MP_TAC) THEN REWRITE_TAC[] THEN
+    REAL_ARITH_TAC]);;
+
+let SIMPLE_PATH_SHIFTPATH = prove
+ (`!g a. simple_path g /\ pathfinish g = pathstart g /\
+         a IN interval[vec 0,vec 1]
+         ==> simple_path(shiftpath a g)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[simple_path] THEN
+  MATCH_MP_TAC(TAUT
+   `(a /\ c /\ d ==> e) /\ (b /\ c /\ d ==> f)
+    ==>  (a /\ b) /\ c /\ d ==> e /\ f`) THEN
+  CONJ_TAC THENL [MESON_TAC[PATH_SHIFTPATH]; ALL_TAC] THEN
+  REWRITE_TAC[simple_path; shiftpath; IN_INTERVAL_1; DROP_VEC;
+              DROP_ADD; DROP_SUB] THEN
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> c ==> a /\ b ==> d`] THEN
+  STRIP_TAC THEN REPEAT GEN_TAC THEN
+  REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+  DISCH_THEN(fun th -> FIRST_X_ASSUM(MP_TAC o C MATCH_MP th)) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[DROP_ADD; DROP_SUB; DROP_VEC; GSYM DROP_EQ] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Choosing a sub-path of an existing path.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let subpath = new_definition
+ `subpath u v g = \x. g(u + drop(v - u) % x)`;;
+
+let SUBPATH_SCALING_LEMMA = prove
+ (`!u v.
+    IMAGE (\x. u + drop(v - u) % x) (interval[vec 0,vec 1]) = segment[u,v]`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[VECTOR_ADD_SYM] THEN
+  REWRITE_TAC[IMAGE_AFFINITY_INTERVAL; SEGMENT_1] THEN
+  REWRITE_TAC[DROP_SUB; REAL_SUB_LE; INTERVAL_EQ_EMPTY_1; DROP_VEC] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[] THEN AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  BINOP_TAC THEN REWRITE_TAC[GSYM LIFT_EQ_CMUL; VECTOR_MUL_RZERO] THEN
+  REWRITE_TAC[LIFT_DROP; LIFT_SUB] THEN VECTOR_ARITH_TAC);;
+
+let PATH_IMAGE_SUBPATH_GEN = prove
+ (`!u v g:real^1->real^N. path_image(subpath u v g) = IMAGE g (segment[u,v])`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[path_image; subpath] THEN
+  ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+  REWRITE_TAC[IMAGE_o; SUBPATH_SCALING_LEMMA]);;
+
+let PATH_IMAGE_SUBPATH = prove
+ (`!u v g:real^1->real^N.
+        drop u <= drop v
+        ==> path_image(subpath u v g) = IMAGE g (interval[u,v])`,
+  SIMP_TAC[PATH_IMAGE_SUBPATH_GEN; SEGMENT_1]);;
+
+let PATH_SUBPATH = prove
+ (`!u v g:real^1->real^N.
+        path g /\ u IN interval[vec 0,vec 1] /\ v IN interval[vec 0,vec 1]
+        ==> path(subpath u v g)`,
+  REWRITE_TAC[path; subpath] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_COMPOSE) THEN
+  SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID;
+           CONTINUOUS_ON_CONST] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    CONTINUOUS_ON_SUBSET)) THEN
+  REWRITE_TAC[SUBPATH_SCALING_LEMMA; SEGMENT_1] THEN
+  COND_CASES_TAC THEN REWRITE_TAC[SUBSET_INTERVAL_1] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN
+  REAL_ARITH_TAC);;
+
+let PATHSTART_SUBPATH = prove
+ (`!u v g:real^1->real^N. pathstart(subpath u v g) = g(u)`,
+  REWRITE_TAC[pathstart; subpath; VECTOR_MUL_RZERO; VECTOR_ADD_RID]);;
+
+let PATHFINISH_SUBPATH = prove
+ (`!u v g:real^1->real^N. pathfinish(subpath u v g) = g(v)`,
+  REWRITE_TAC[pathfinish; subpath; GSYM LIFT_EQ_CMUL] THEN
+  REWRITE_TAC[LIFT_DROP; VECTOR_ARITH `u + v - u:real^N = v`]);;
+
+let SUBPATH_TRIVIAL = prove
+ (`!g. subpath (vec 0) (vec 1) g = g`,
+  REWRITE_TAC[subpath; VECTOR_SUB_RZERO; DROP_VEC; VECTOR_MUL_LID;
+              VECTOR_ADD_LID; ETA_AX]);;
+
+let SUBPATH_REVERSEPATH = prove
+ (`!g. subpath (vec 1) (vec 0) g = reversepath g`,
+  REWRITE_TAC[subpath; reversepath; VECTOR_SUB_LZERO; DROP_NEG; DROP_VEC] THEN
+  REWRITE_TAC[VECTOR_ARITH `a + -- &1 % b:real^N = a - b`]);;
+
+let REVERSEPATH_SUBPATH = prove
+ (`!g u v. reversepath(subpath u v g) = subpath v u g`,
+  REWRITE_TAC[reversepath; subpath; FUN_EQ_THM] THEN REPEAT GEN_TAC THEN
+  AP_TERM_TAC THEN REWRITE_TAC[DROP_SUB; VECTOR_SUB_LDISTRIB] THEN
+  REWRITE_TAC[GSYM LIFT_EQ_CMUL; LIFT_SUB; LIFT_DROP] THEN
+  VECTOR_ARITH_TAC);;
+
+let SUBPATH_TRANSLATION = prove
+ (`!a g u v. subpath u v ((\x. a + x) o g) = (\x. a + x) o subpath u v g`,
+  REWRITE_TAC[FUN_EQ_THM; subpath; o_THM]);;
+
+add_translation_invariants [SUBPATH_TRANSLATION];;
+
+let SUBPATH_LINEAR_IMAGE = prove
+ (`!f g u v. linear f ==> subpath u v (f o g) = f o subpath u v g`,
+  REWRITE_TAC[FUN_EQ_THM; subpath; o_THM]);;
+
+add_linear_invariants [SUBPATH_LINEAR_IMAGE];;
+
+let SIMPLE_PATH_SUBPATH_EQ = prove
+ (`!g u v. simple_path(subpath u v g) <=>
+           path(subpath u v g) /\ ~(u = v) /\
+           (!x y. x IN segment[u,v] /\ y IN segment[u,v] /\ g x = g y
+                  ==> x = y \/ x = u /\ y = v \/ x = v /\ y = u)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[simple_path; subpath] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[GSYM SUBPATH_SCALING_LEMMA] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[VECTOR_ARITH `u + a % x = u <=> a % x = vec 0`;
+              VECTOR_ARITH `a + x:real^N = a + y <=> x = y`] THEN
+  REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_MUL_LCANCEL] THEN
+  REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; DROP_ADD; DROP_SUB;
+              REAL_RING `u + (v - u) * y = v <=> v = u \/ y = &1`] THEN
+  REWRITE_TAC[REAL_SUB_0; DROP_EQ; GSYM DROP_VEC] THEN
+  ASM_CASES_TAC `v:real^1 = u` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[REAL_SUB_REFL; DROP_VEC; VECTOR_MUL_LZERO] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
+  DISCH_THEN(MP_TAC o SPECL [`lift(&1 / &2)`; `lift(&3 / &4)`]) THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; GSYM DROP_EQ; LIFT_DROP] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let ARC_SUBPATH_EQ = prove
+ (`!g u v. arc(subpath u v g) <=>
+           path(subpath u v g) /\ ~(u = v) /\
+           (!x y. x IN segment[u,v] /\ y IN segment[u,v] /\ g x = g y
+                  ==> x = y)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[arc; subpath] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[GSYM SUBPATH_SCALING_LEMMA] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[VECTOR_ARITH `u + a % x = u + a % y <=> a % (x - y) = vec 0`;
+              VECTOR_MUL_EQ_0; DROP_EQ_0; VECTOR_SUB_EQ] THEN
+  ASM_CASES_TAC `v:real^1 = u` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[VECTOR_SUB_REFL; DROP_VEC; VECTOR_MUL_LZERO] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
+  DISCH_THEN(MP_TAC o SPECL [`lift(&1 / &2)`; `lift(&3 / &4)`]) THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; GSYM DROP_EQ; LIFT_DROP] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let SIMPLE_PATH_SUBPATH = prove
+ (`!g u v. simple_path g /\
+           u IN interval[vec 0,vec 1] /\ v IN interval[vec 0,vec 1] /\
+           ~(u = v)
+           ==> simple_path(subpath u v g)`,
+  SIMP_TAC[SIMPLE_PATH_SUBPATH_EQ; PATH_SUBPATH; SIMPLE_PATH_IMP_PATH] THEN
+  REWRITE_TAC[simple_path] THEN GEN_TAC THEN
+  REWRITE_TAC[FORALL_LIFT] THEN MATCH_MP_TAC REAL_WLOG_LT THEN
+  REWRITE_TAC[FORALL_DROP; LIFT_DROP] THEN
+  CONJ_TAC THENL [MESON_TAC[SEGMENT_SYM]; ALL_TAC] THEN
+  SIMP_TAC[SEGMENT_1; REAL_LT_IMP_LE] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^1`; `v:real^1`] THEN DISCH_TAC THEN
+  STRIP_TAC THEN MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^1`; `y:real^1`]) THEN
+  SUBGOAL_THEN
+   `!x:real^1. x IN interval[u,v] ==> x IN interval[vec 0,vec 1]`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM SUBSET; SUBSET_INTERVAL_1] THEN
+    ASM_MESON_TAC[IN_INTERVAL_1; DROP_VEC; REAL_LE_TRANS];
+    ASM_SIMP_TAC[]] THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1])) THEN
+  REWRITE_TAC[DROP_VEC; GSYM DROP_EQ] THEN ASM_REAL_ARITH_TAC);;
+
+let ARC_SIMPLE_PATH_SUBPATH = prove
+ (`!g u v. simple_path g /\
+           u IN interval[vec 0,vec 1] /\ v IN interval[vec 0,vec 1] /\
+           ~(g u = g v)
+           ==> arc(subpath u v g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SIMPLE_PATH_IMP_ARC THEN
+  ASM_REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+  ASM_MESON_TAC[SIMPLE_PATH_SUBPATH]);;
+
+let ARC_SUBPATH_ARC = prove
+ (`!u v g. arc g /\
+           u IN interval [vec 0,vec 1] /\ v IN interval [vec 0,vec 1] /\
+           ~(u = v)
+           ==> arc(subpath u v g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ARC_SIMPLE_PATH_SUBPATH THEN
+  ASM_MESON_TAC[ARC_IMP_SIMPLE_PATH; arc]);;
+
+let ARC_SIMPLE_PATH_SUBPATH_INTERIOR = prove
+ (`!g u v. simple_path g /\
+           u IN interval[vec 0,vec 1] /\ v IN interval[vec 0,vec 1] /\
+           ~(u = v) /\ abs(drop u - drop v) < &1
+           ==> arc(subpath u v g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ARC_SIMPLE_PATH_SUBPATH THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [simple_path]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`u:real^1`; `v:real^1`] o CONJUNCT2) THEN
+  ASM_REWRITE_TAC[] THEN POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[DROP_VEC] THEN REAL_ARITH_TAC);;
+
+let PATH_IMAGE_SUBPATH_SUBSET = prove
+ (`!u v g:real^1->real^N.
+        path g /\ u IN interval[vec 0,vec 1] /\ v IN interval[vec 0,vec 1]
+        ==> path_image(subpath u v g) SUBSET path_image g`,
+  SIMP_TAC[PATH_IMAGE_SUBPATH_GEN] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[path_image] THEN MATCH_MP_TAC IMAGE_SUBSET THEN
+  SIMP_TAC[SEGMENT_CONVEX_HULL; SUBSET_HULL; CONVEX_INTERVAL] THEN
+  ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET]);;
+
+let JOIN_SUBPATHS_MIDDLE = prove
+ (`!p:real^1->real^N.
+   subpath (vec 0) (lift(&1 / &2)) p ++ subpath (lift(&1 / &2)) (vec 1) p = p`,
+  REWRITE_TAC[FUN_EQ_THM] THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[joinpaths; subpath] THEN COND_CASES_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[GSYM DROP_EQ; DROP_ADD; DROP_SUB; DROP_CMUL; LIFT_DROP;
+              DROP_VEC] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some additional lemmas about choosing sub-paths.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let EXISTS_SUBPATH_OF_PATH = prove
+ (`!g a b:real^N.
+        path g /\ a IN path_image g /\ b IN path_image g
+        ==> ?h. path h /\ pathstart h = a /\ pathfinish h = b /\
+                path_image h SUBSET path_image g`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; path_image; FORALL_IN_IMAGE] THEN
+  GEN_TAC THEN DISCH_TAC THEN
+  X_GEN_TAC `u:real^1` THEN DISCH_TAC THEN
+  X_GEN_TAC `v:real^1` THEN DISCH_TAC THEN
+  EXISTS_TAC `subpath u v (g:real^1->real^N)` THEN
+  ASM_REWRITE_TAC[GSYM path_image; PATH_IMAGE_SUBPATH_GEN] THEN
+  ASM_SIMP_TAC[PATH_SUBPATH; PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+  REWRITE_TAC[path_image] THEN MATCH_MP_TAC IMAGE_SUBSET THEN
+  SIMP_TAC[SEGMENT_CONVEX_HULL; SUBSET_HULL; CONVEX_INTERVAL] THEN
+  ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET]);;
+
+let EXISTS_SUBPATH_OF_ARC_NOENDS = prove
+ (`!g a b:real^N.
+        arc g /\ a IN path_image g /\ b IN path_image g /\
+        {a,b} INTER {pathstart g,pathfinish g} = {}
+        ==> ?h. path h /\ pathstart h = a /\ pathfinish h = b /\
+                path_image h SUBSET
+                (path_image g) DIFF {pathstart g,pathfinish g}`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; path_image; FORALL_IN_IMAGE] THEN
+  GEN_TAC THEN DISCH_TAC THEN
+  X_GEN_TAC `u:real^1` THEN DISCH_TAC THEN
+  X_GEN_TAC `v:real^1` THEN DISCH_TAC THEN DISCH_TAC THEN
+  EXISTS_TAC `subpath u v (g:real^1->real^N)` THEN
+  ASM_SIMP_TAC[PATH_SUBPATH; PATHSTART_SUBPATH; PATHFINISH_SUBPATH;
+               ARC_IMP_PATH; GSYM path_image; PATH_IMAGE_SUBPATH_GEN] THEN
+  REWRITE_TAC[path_image; pathstart; pathfinish] THEN
+  REWRITE_TAC[SET_RULE
+   `s SUBSET t DIFF {a,b} <=> s SUBSET t /\ ~(a IN s) /\ ~(b IN s)`] THEN
+  REWRITE_TAC[IN_IMAGE] THEN
+  SUBGOAL_THEN `~(vec 0 IN segment[u:real^1,v]) /\ ~(vec 1 IN segment[u,v])`
+  STRIP_ASSUME_TAC THENL
+   [REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1])) THEN
+    REWRITE_TAC[SEGMENT_1] THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN
+    SIMP_TAC[REAL_ARITH `a <= b ==> (b <= a <=> a = b)`] THEN
+    REWRITE_TAC[GSYM DROP_VEC; DROP_EQ] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[arc; pathstart; pathfinish]) THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `segment[u:real^1,v] SUBSET interval[vec 0,vec 1]` MP_TAC THENL
+   [SIMP_TAC[SEGMENT_CONVEX_HULL; SUBSET_HULL; CONVEX_INTERVAL] THEN
+    ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET];
+    ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[arc; pathstart; pathfinish]) THEN
+  SUBGOAL_THEN `(vec 0:real^1) IN interval[vec 0,vec 1] /\
+                (vec 1:real^1) IN interval[vec 0,vec 1]`
+  MP_TAC THENL
+   [REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL];
+    ASM SET_TAC[]]);;
+
+let EXISTS_SUBARC_OF_ARC_NOENDS = prove
+ (`!g a b:real^N.
+        arc g /\ a IN path_image g /\ b IN path_image g /\ ~(a = b) /\
+        {a,b} INTER {pathstart g,pathfinish g} = {}
+        ==> ?h. arc h /\ pathstart h = a /\ pathfinish h = b /\
+                path_image h SUBSET
+                (path_image g) DIFF {pathstart g,pathfinish g}`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; path_image; FORALL_IN_IMAGE] THEN
+  GEN_TAC THEN DISCH_TAC THEN
+  X_GEN_TAC `u:real^1` THEN DISCH_TAC THEN
+  X_GEN_TAC `v:real^1` THEN REPEAT DISCH_TAC THEN
+  EXISTS_TAC `subpath u v (g:real^1->real^N)` THEN
+  ASM_SIMP_TAC[PATH_SUBPATH; PATHSTART_SUBPATH; PATHFINISH_SUBPATH;
+               ARC_IMP_PATH; GSYM path_image; PATH_IMAGE_SUBPATH_GEN] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC ARC_SIMPLE_PATH_SUBPATH THEN
+    ASM_SIMP_TAC[ARC_IMP_SIMPLE_PATH];
+    ALL_TAC] THEN
+  REWRITE_TAC[path_image; pathstart; pathfinish] THEN
+  REWRITE_TAC[SET_RULE
+   `s SUBSET t DIFF {a,b} <=> s SUBSET t /\ ~(a IN s) /\ ~(b IN s)`] THEN
+  REWRITE_TAC[IN_IMAGE] THEN
+  SUBGOAL_THEN `~(vec 0 IN segment[u:real^1,v]) /\ ~(vec 1 IN segment[u,v])`
+  STRIP_ASSUME_TAC THENL
+   [REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1])) THEN
+    REWRITE_TAC[SEGMENT_1] THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN
+    SIMP_TAC[REAL_ARITH `a <= b ==> (b <= a <=> a = b)`] THEN
+    REWRITE_TAC[GSYM DROP_VEC; DROP_EQ] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[arc; pathstart; pathfinish]) THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `segment[u:real^1,v] SUBSET interval[vec 0,vec 1]` MP_TAC THENL
+   [SIMP_TAC[SEGMENT_CONVEX_HULL; SUBSET_HULL; CONVEX_INTERVAL] THEN
+    ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET];
+    ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[arc; pathstart; pathfinish]) THEN
+  SUBGOAL_THEN `(vec 0:real^1) IN interval[vec 0,vec 1] /\
+                (vec 1:real^1) IN interval[vec 0,vec 1]`
+  MP_TAC THENL
+   [REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL];
+    ASM SET_TAC[]]);;
+
+let EXISTS_ARC_PSUBSET_SIMPLE_PATH = prove
+ (`!g:real^1->real^N.
+        simple_path g /\ closed s /\ s PSUBSET path_image g
+        ==> ?h. arc h /\
+                s SUBSET path_image h /\
+                path_image h SUBSET path_image g`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP SIMPLE_PATH_CASES) THENL
+   [EXISTS_TAC `g:real^1->real^N` THEN ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [PSUBSET_ALT]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [path_image] THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^1` STRIP_ASSUME_TAC) THEN
+  ABBREV_TAC `(h:real^1->real^N) = shiftpath u g` THEN
+  SUBGOAL_THEN
+   `simple_path(h:real^1->real^N) /\
+    pathstart h = (g:real^1->real^N) u /\
+    pathfinish h = (g:real^1->real^N) u /\
+    path_image h = path_image g`
+  MP_TAC THENL
+   [EXPAND_TAC "h" THEN
+    ASM_MESON_TAC[SIMPLE_PATH_SHIFTPATH; PATH_IMAGE_SHIFTPATH;
+                  PATHSTART_SHIFTPATH; PATHFINISH_SHIFTPATH;
+                  IN_INTERVAL_1; DROP_VEC];
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+    UNDISCH_THEN `pathstart(h:real^1->real^N) = (g:real^1->real^N) u`
+        (SUBST_ALL_TAC o SYM)] THEN
+  SUBGOAL_THEN
+   `open_in (subtopology euclidean (interval[vec 0,vec 1]))
+            {x:real^1 | x IN interval[vec 0,vec 1] /\
+                        (h x) IN ((:real^N) DIFF s)}`
+  MP_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE THEN
+    ASM_SIMP_TAC[GSYM path; GSYM closed; SIMPLE_PATH_IMP_PATH];
+    REWRITE_TAC[open_in] THEN DISCH_THEN(MP_TAC o CONJUNCT2)] THEN
+  REWRITE_TAC[IN_DIFF; IN_UNIV; IN_ELIM_THM] THEN
+  DISCH_THEN(fun th ->
+    MP_TAC(SPEC `vec 0:real^1` th) THEN MP_TAC(SPEC `vec 1:real^1` th)) THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL] THEN
+  REWRITE_TAC[DIST_REAL; VEC_COMPONENT; REAL_SUB_RZERO] THEN
+  SIMP_TAC[GSYM drop] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[pathfinish]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d2:real` STRIP_ASSUME_TAC) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[pathstart]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC
+   `subpath (lift(min d1 (&1 / &4))) (lift(&1 - min d2 (&1 / &4)))
+            (h:real^1->real^N)` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC ARC_SIMPLE_PATH_SUBPATH_INTERIOR THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP; LIFT_EQ] THEN
+    ASM_REAL_ARITH_TAC;
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `s SUBSET t ==> t INTER s SUBSET u ==> s SUBSET u`)) THEN
+    REWRITE_TAC[SUBSET; IN_INTER; IMP_CONJ] THEN
+    SIMP_TAC[PATH_IMAGE_SUBPATH; LIFT_DROP;
+             REAL_ARITH `min d1 (&1 / &4) <= &1 - min d2 (&1 / &4)`] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; path_image; IN_INTERVAL_1; DROP_VEC] THEN
+    X_GEN_TAC `x:real^1` THEN REPEAT STRIP_TAC THEN
+    REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `x:real^1` THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `x:real^1`)) THEN
+    ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+    MATCH_MP_TAC PATH_IMAGE_SUBPATH_SUBSET THEN
+    ASM_SIMP_TAC[SIMPLE_PATH_IMP_PATH; IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let EXISTS_DOUBLE_ARC = prove
+ (`!g:real^1->real^N a b.
+        simple_path g /\ pathfinish g = pathstart g /\
+        a IN path_image g /\ b IN path_image g /\ ~(a = b)
+        ==> ?u d. arc u /\ arc d /\
+                  pathstart u = a /\ pathfinish u = b /\
+                  pathstart d = b /\ pathfinish d = a /\
+                  (path_image u) INTER (path_image d) = {a,b} /\
+                  (path_image u) UNION (path_image d) = path_image g`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; path_image] THEN
+  ONCE_REWRITE_TAC[FORALL_IN_IMAGE] THEN GEN_TAC THEN REPEAT DISCH_TAC THEN
+  X_GEN_TAC `u:real^1` THEN DISCH_TAC THEN REWRITE_TAC[GSYM path_image] THEN
+  X_GEN_TAC `b:real^N` THEN DISCH_TAC THEN DISCH_TAC THEN
+  ABBREV_TAC `h = shiftpath u (g:real^1->real^N)` THEN
+  SUBGOAL_THEN
+   `simple_path(h:real^1->real^N) /\
+    pathstart h = g u /\
+    pathfinish h = g u /\
+    path_image h = path_image g`
+  STRIP_ASSUME_TAC THENL
+   [EXPAND_TAC "h" THEN
+    ASM_SIMP_TAC[SIMPLE_PATH_SHIFTPATH; PATH_IMAGE_SHIFTPATH] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+    EXPAND_TAC "h" THEN
+    ASM_SIMP_TAC[PATHSTART_SHIFTPATH; PATHFINISH_SHIFTPATH];
+    UNDISCH_THEN `path_image h :real^N->bool = path_image g`
+     (SUBST_ALL_TAC o SYM)] THEN
+  UNDISCH_TAC `(b:real^N) IN path_image h` THEN
+  REWRITE_TAC[IN_IMAGE; path_image; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `v:real^1` THEN STRIP_TAC THEN REWRITE_TAC[GSYM path_image] THEN
+  MAP_EVERY EXISTS_TAC
+   [`subpath (vec 0) v (h:real^1->real^N)`;
+    `subpath v (vec 1) (h:real^1->real^N)`] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+  ASM_REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+  UNDISCH_THEN `b = (h:real^1->real^N) v` SUBST_ALL_TAC THEN
+  STRIP_ASSUME_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]
+   (ASSUME `(v:real^1) IN interval[vec 0,vec 1]`)) THEN
+  ASM_SIMP_TAC[ARC_SIMPLE_PATH_SUBPATH; IN_INTERVAL_1; DROP_VEC;
+               REAL_LE_REFL; REAL_POS; PATH_IMAGE_SUBPATH] THEN
+  REWRITE_TAC[GSYM IMAGE_UNION; path_image] THEN
+  UNDISCH_THEN `(h:real^1->real^N)(vec 0) = (g:real^1->real^N) u`
+   (SUBST_ALL_TAC o SYM) THEN
+  SUBGOAL_THEN
+   `interval[vec 0,v] UNION interval[v,vec 1] = interval[vec 0:real^1,vec 1]`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[IMAGE_SUBSET] THEN
+    MATCH_MP_TAC(SET_RULE
+     `(!x y. x IN (s UNION t) /\ y IN (s UNION t) /\ f x = f y
+             ==> x = y \/ x = vec 0 /\ y = vec 1 \/ x = vec 1 /\ y = vec 0) /\
+      (f(vec 0) = f(vec 1)) /\ (vec 0) IN s /\ (vec 1) IN t /\
+      s INTER t = {c}
+      ==> IMAGE f s INTER IMAGE f t = {f (vec 0), f c}`) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[simple_path]) THEN ASM_REWRITE_TAC[]] THEN
+  REWRITE_TAC[EXTENSION; IN_INSERT; NOT_IN_EMPTY; IN_INTER; IN_UNION] THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1])) THEN
+  REWRITE_TAC[IN_INTERVAL_1; GSYM DROP_EQ; DROP_VEC] THEN ASM_REAL_ARITH_TAC);;
+
+let SUBPATH_TO_FRONTIER_EXPLICIT = prove
+ (`!g:real^1->real^N s.
+        path g /\ pathstart g IN s /\ ~(pathfinish g IN s)
+        ==> ?u. u IN interval[vec 0,vec 1] /\
+                (!x. &0 <= drop x /\ drop x < drop u ==> g x IN interior s) /\
+                ~(g u IN interior s) /\
+                (u = vec 0 \/ g u IN closure s)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `{u | lift u IN interval[vec 0,vec 1] /\
+                     g(lift u) IN closure((:real^N) DIFF s)}`
+         COMPACT_ATTAINS_INF) THEN
+  SIMP_TAC[LIFT_DROP; SET_RULE
+   `(!x. lift(drop x) = x) ==> IMAGE lift {x | P(lift x)} = {x | P x}`] THEN
+  ANTS_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[path; pathstart; pathfinish; SUBSET;
+                                path_image; FORALL_IN_IMAGE]) THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC BOUNDED_SUBSET THEN
+        EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+        REWRITE_TAC[BOUNDED_INTERVAL] THEN SET_TAC[];
+        MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE THEN
+        ASM_REWRITE_TAC[CLOSED_CLOSURE; CLOSED_INTERVAL]];
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+      EXISTS_TAC `&1` THEN REWRITE_TAC[LIFT_NUM] THEN
+      REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL] THEN
+      MATCH_MP_TAC(REWRITE_RULE[SUBSET] CLOSURE_SUBSET) THEN
+      ASM_REWRITE_TAC[IN_DIFF; IN_UNIV]];
+    ALL_TAC] THEN
+  REWRITE_TAC[EXISTS_DROP; FORALL_DROP; IN_ELIM_THM; LIFT_DROP] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real^1` THEN
+  REWRITE_TAC[CLOSURE_COMPLEMENT; IN_DIFF; IN_UNIV] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[subpath; VECTOR_SUB_RZERO; VECTOR_ADD_LID] THEN
+  ASM_REWRITE_TAC[GSYM LIFT_EQ_CMUL; LIFT_DROP] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; GSYM DROP_EQ] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE BINDER_CONV
+     [TAUT `a /\ ~b ==> c <=> a /\ ~c ==> b`]) THEN
+    ASM_REAL_ARITH_TAC;
+    FIRST_X_ASSUM(K ALL_TAC o SPEC `x:real^1`) THEN DISCH_TAC] THEN
+  ASM_CASES_TAC `drop u = &0` THEN
+  ASM_REWRITE_TAC[frontier; IN_DIFF; CLOSURE_APPROACHABLE] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[path; pathstart; pathfinish]) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [continuous_on]) THEN
+  DISCH_THEN(MP_TAC o SPEC `u:real^1`) THEN
+  ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(MP_TAC o SPEC `lift(max (&0) (drop u - d / &2))`) THEN
+  REWRITE_TAC[LIFT_DROP; DIST_REAL; GSYM drop] THEN
+  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN MATCH_MP_TAC
+   (MESON[] `P a ==> dist(a,y) < e ==> ?x. P x /\ dist(x,y) < e`) THEN
+  MATCH_MP_TAC(REWRITE_RULE[SUBSET] INTERIOR_SUBSET) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[LIFT_DROP] THEN ASM_ARITH_TAC);;
+
+let SUBPATH_TO_FRONTIER_STRONG = prove
+ (`!g:real^1->real^N s.
+        path g /\ pathstart g IN s /\ ~(pathfinish g IN s)
+        ==> ?u. u IN interval[vec 0,vec 1] /\
+                 ~(pathfinish(subpath (vec 0) u g) IN interior s) /\
+                (u = vec 0 \/
+                 (!x. x IN interval[vec 0,vec 1] /\ ~(x = vec 1)
+                      ==> (subpath (vec 0) u g x) IN interior s) /\
+                 pathfinish(subpath (vec 0) u g) IN closure s)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP SUBPATH_TO_FRONTIER_EXPLICIT) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real^1` THEN
+  REWRITE_TAC[subpath; pathfinish; VECTOR_SUB_RZERO; VECTOR_ADD_LID] THEN
+  ASM_CASES_TAC `u:real^1 = vec 0` THEN ASM_REWRITE_TAC[] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[DROP_VEC; VECTOR_MUL_LZERO] THEN
+  ASM_REWRITE_TAC[GSYM LIFT_EQ_CMUL; LIFT_DROP] THEN
+  X_GEN_TAC `x:real^1` THEN
+  REWRITE_TAC[IN_INTERVAL_1; GSYM DROP_EQ; DROP_VEC] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+  ASM_SIMP_TAC[DROP_CMUL; REAL_LE_MUL] THEN
+  REWRITE_TAC[REAL_ARITH `u * x < u <=> &0 < u * (&1 - x)`] THEN
+  MATCH_MP_TAC REAL_LT_MUL THEN REWRITE_TAC[REAL_SUB_LT] THEN
+  ASM_REWRITE_TAC[REAL_LT_LE] THEN
+  ASM_REWRITE_TAC[GSYM LIFT_EQ; LIFT_DROP; LIFT_NUM]);;
+
+let SUBPATH_TO_FRONTIER = prove
+ (`!g:real^1->real^N s.
+        path g /\ pathstart g IN s /\ ~(pathfinish g IN s)
+        ==> ?u. u IN interval[vec 0,vec 1] /\
+                pathfinish(subpath (vec 0) u g) IN frontier s /\
+                (path_image(subpath (vec 0) u g) DELETE
+                 pathfinish(subpath (vec 0) u g))
+                SUBSET interior s`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[frontier; IN_DIFF] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP SUBPATH_TO_FRONTIER_STRONG) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real^1` THEN
+  ASM_CASES_TAC `u:real^1 = vec 0` THEN ASM_REWRITE_TAC[] THENL
+   [REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[pathstart]) THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[REWRITE_RULE[SUBSET] CLOSURE_SUBSET] THEN
+    REWRITE_TAC[subpath; path_image; VECTOR_SUB_REFL; DROP_VEC;
+                VECTOR_MUL_LZERO; VECTOR_ADD_LID] THEN
+    SET_TAC[];
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[SUBSET; path_image; FORALL_IN_IMAGE; IN_DELETE; IMP_CONJ] THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; pathfinish] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN ASM_MESON_TAC[]]);;
+
+let EXISTS_PATH_SUBPATH_TO_FRONTIER = prove
+ (`!g:real^1->real^N s.
+        path g /\ pathstart g IN s /\ ~(pathfinish g IN s)
+        ==> ?h. path h /\ pathstart h = pathstart g /\
+                (path_image h) SUBSET (path_image g) /\
+                (path_image h DELETE (pathfinish h)) SUBSET interior s /\
+                pathfinish h IN frontier s`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP SUBPATH_TO_FRONTIER) THEN
+  EXISTS_TAC `subpath (vec 0) u (g:real^1->real^N)` THEN
+  ASM_SIMP_TAC[PATH_SUBPATH; IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL;
+               PATHSTART_SUBPATH; PATH_IMAGE_SUBPATH_SUBSET] THEN
+  REWRITE_TAC[pathstart]);;
+
+let EXISTS_PATH_SUBPATH_TO_FRONTIER_CLOSED = prove
+ (`!g:real^1->real^N s.
+        closed s /\ path g /\ pathstart g IN s /\ ~(pathfinish g IN s)
+        ==> ?h. path h /\ pathstart h = pathstart g /\
+                (path_image h) SUBSET (path_image g) INTER s /\
+                pathfinish h IN frontier s`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP EXISTS_PATH_SUBPATH_TO_FRONTIER) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN
+  REWRITE_TAC[SUBSET_INTER] THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC
+   `(pathfinish h:real^N) INSERT (path_image h DELETE pathfinish h)` THEN
+  CONJ_TAC THENL [SET_TAC[]; REWRITE_TAC[INSERT_SUBSET]] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[frontier; CLOSURE_EQ; IN_DIFF];
+    ASM_MESON_TAC[SUBSET_TRANS; INTERIOR_SUBSET]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Special case of straight-line paths.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let linepath = new_definition
+ `linepath(a,b) = \x. (&1 - drop x) % a + drop x % b`;;
+
+let LINEPATH_TRANSLATION = prove
+ (`!a b c. linepath(a + b,a + c) = (\x. a + x) o linepath(b,c)`,
+  REWRITE_TAC[linepath; o_THM; FUN_EQ_THM] THEN VECTOR_ARITH_TAC);;
+
+add_translation_invariants [LINEPATH_TRANSLATION];;
+
+let LINEPATH_LINEAR_IMAGE = prove
+ (`!f. linear f ==> !b c. linepath(f b,f c) = f o linepath(b,c)`,
+  REWRITE_TAC[linepath; o_THM; FUN_EQ_THM] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP LINEAR_ADD) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP LINEAR_CMUL) THEN
+  ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC);;
+
+add_linear_invariants [LINEPATH_LINEAR_IMAGE];;
+
+let PATHSTART_LINEPATH = prove
+ (`!a b. pathstart(linepath(a,b)) = a`,
+  REWRITE_TAC[linepath; pathstart; DROP_VEC] THEN VECTOR_ARITH_TAC);;
+
+let PATHFINISH_LINEPATH = prove
+ (`!a b. pathfinish(linepath(a,b)) = b`,
+  REWRITE_TAC[linepath; pathfinish; DROP_VEC] THEN VECTOR_ARITH_TAC);;
+
+let CONTINUOUS_LINEPATH_AT = prove
+ (`!a b x. linepath(a,b) continuous (at x)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[linepath] THEN
+  REWRITE_TAC[VECTOR_ARITH `(&1 - u) % x + y = x + u % --x + y`] THEN
+  MATCH_MP_TAC CONTINUOUS_ADD THEN REWRITE_TAC[CONTINUOUS_CONST] THEN
+  MATCH_MP_TAC CONTINUOUS_ADD THEN CONJ_TAC THEN
+  MATCH_MP_TAC CONTINUOUS_VMUL THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP; CONTINUOUS_AT_ID]);;
+
+let CONTINUOUS_ON_LINEPATH = prove
+ (`!a b s. linepath(a,b) continuous_on s`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON; CONTINUOUS_LINEPATH_AT]);;
+
+let PATH_LINEPATH = prove
+ (`!a b. path(linepath(a,b))`,
+  REWRITE_TAC[path; CONTINUOUS_ON_LINEPATH]);;
+
+let PATH_IMAGE_LINEPATH = prove
+ (`!a b. path_image(linepath (a,b)) = segment[a,b]`,
+  REWRITE_TAC[segment; path_image; linepath] THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_ELIM_THM; IN_INTERVAL] THEN
+  SIMP_TAC[DIMINDEX_1; FORALL_1; VEC_COMPONENT; ARITH] THEN
+  REWRITE_TAC[EXISTS_LIFT; GSYM drop; LIFT_DROP] THEN MESON_TAC[]);;
+
+let REVERSEPATH_LINEPATH = prove
+ (`!a b. reversepath(linepath(a,b)) = linepath(b,a)`,
+  REWRITE_TAC[reversepath; linepath; DROP_SUB; DROP_VEC; FUN_EQ_THM] THEN
+  VECTOR_ARITH_TAC);;
+
+let ARC_LINEPATH = prove
+ (`!a b. ~(a = b) ==> arc(linepath(a,b))`,
+  REWRITE_TAC[arc; PATH_LINEPATH] THEN REWRITE_TAC[linepath] THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `(&1 - x) % a + x % b:real^N = (&1 - y) % a + y % b <=>
+    (x - y) % (a - b) = vec 0`] THEN
+  SIMP_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ; DROP_EQ; REAL_SUB_0]);;
+
+let SIMPLE_PATH_LINEPATH = prove
+ (`!a b. ~(a = b) ==> simple_path(linepath(a,b))`,
+  MESON_TAC[ARC_IMP_SIMPLE_PATH; ARC_LINEPATH]);;
+
+let SIMPLE_PATH_LINEPATH_EQ = prove
+ (`!a b:real^N. simple_path(linepath(a,b)) <=> ~(a = b)`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[SIMPLE_PATH_LINEPATH] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[simple_path] THEN
+  DISCH_THEN SUBST1_TAC THEN DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+  REWRITE_TAC[linepath; GSYM VECTOR_ADD_RDISTRIB] THEN
+  DISCH_THEN(MP_TAC o SPECL [`lift(&0)`; `lift(&1 / &2)`]) THEN
+  REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP; GSYM DROP_EQ; DROP_VEC] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let ARC_LINEPATH_EQ = prove
+ (`!a b. arc(linepath(a,b)) <=> ~(a = b)`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[ARC_LINEPATH] THEN
+  MESON_TAC[SIMPLE_PATH_LINEPATH_EQ; ARC_IMP_SIMPLE_PATH]);;
+
+let LINEPATH_REFL = prove
+ (`!a. linepath(a,a) = \x. a`,
+  REWRITE_TAC[linepath; VECTOR_ARITH `(&1 - u) % x + u % x:real^N = x`]);;
+
+let SHIFTPATH_TRIVIAL = prove
+ (`!t a. shiftpath t (linepath(a,a)) = linepath(a,a)`,
+  REWRITE_TAC[shiftpath; LINEPATH_REFL; COND_ID]);;
+
+let SUBPATH_REFL = prove
+ (`!g a. subpath a a g = linepath(g a,g a)`,
+  REWRITE_TAC[subpath; linepath; VECTOR_SUB_REFL; DROP_VEC; VECTOR_MUL_LZERO;
+              FUN_EQ_THM; VECTOR_ADD_RID] THEN
+  VECTOR_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Bounding a point away from a path.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let NOT_ON_PATH_BALL = prove
+ (`!g z:real^N.
+        path g /\ ~(z IN path_image g)
+        ==> ?e. &0 < e /\ ball(z,e) INTER (path_image g) = {}`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`path_image g:real^N->bool`; `z:real^N`]
+     DISTANCE_ATTAINS_INF) THEN
+  REWRITE_TAC[PATH_IMAGE_NONEMPTY] THEN
+  ASM_SIMP_TAC[COMPACT_PATH_IMAGE; COMPACT_IMP_CLOSED] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `dist(z:real^N,a)` THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[DIST_POS_LT]; ALL_TAC] THEN
+  REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_BALL; IN_INTER] THEN
+  ASM_MESON_TAC[REAL_NOT_LE]);;
+
+let NOT_ON_PATH_CBALL = prove
+ (`!g z:real^N.
+        path g /\ ~(z IN path_image g)
+        ==> ?e. &0 < e /\ cball(z,e) INTER (path_image g) = {}`,
+  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP NOT_ON_PATH_BALL) THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `e / &2` THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+   `s INTER u = {} ==> t SUBSET s ==> t INTER u = {}`)) THEN
+  REWRITE_TAC[SUBSET; IN_BALL; IN_CBALL] THEN
+  UNDISCH_TAC `&0 < e` THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homeomorphisms of arc images.                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMEOMORPHISM_ARC = prove
+ (`!g:real^1->real^N.
+     arc g ==> ?h. homeomorphism (interval[vec 0,vec 1],path_image g) (g,h)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMEOMORPHISM_COMPACT THEN
+  ASM_REWRITE_TAC[path_image; COMPACT_INTERVAL; GSYM path; GSYM arc]);;
+
+let HOMEOMORPHIC_ARC_IMAGE_INTERVAL = prove
+ (`!g:real^1->real^N a b:real^1.
+      arc g /\ drop a < drop b ==> (path_image g) homeomorphic interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  TRANS_TAC HOMEOMORPHIC_TRANS `interval[vec 0:real^1,vec 1]` THEN
+  CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN REWRITE_TAC[homeomorphic] THEN
+    EXISTS_TAC `g:real^1->real^N` THEN ASM_SIMP_TAC[HOMEOMORPHISM_ARC];
+    MATCH_MP_TAC HOMEOMORPHIC_CLOSED_INTERVALS THEN
+    ASM_REWRITE_TAC[INTERVAL_NE_EMPTY_1; DROP_VEC; REAL_LT_01]]);;
+
+let HOMEOMORPHIC_ARC_IMAGES = prove
+ (`!g:real^1->real^M h:real^1->real^N.
+        arc g /\ arc h ==> (path_image g) homeomorphic (path_image h)`,
+  REPEAT STRIP_TAC THEN
+  TRANS_TAC HOMEOMORPHIC_TRANS `interval[vec 0:real^1,vec 1]` THEN
+  CONJ_TAC THENL [ALL_TAC; ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM]] THEN
+  MATCH_MP_TAC HOMEOMORPHIC_ARC_IMAGE_INTERVAL THEN
+  ASM_REWRITE_TAC[DROP_VEC; REAL_LT_01]);;
+
+let HOMEOMORPHIC_ARC_IMAGE_SEGMENT = prove
+ (`!g:real^1->real^N a b:real^M.
+        arc g /\ ~(a = b) ==> (path_image g) homeomorphic segment[a,b]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM PATH_IMAGE_LINEPATH] THEN
+  MATCH_MP_TAC HOMEOMORPHIC_ARC_IMAGES THEN
+  ASM_REWRITE_TAC[ARC_LINEPATH_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Path component, considered as a "joinability" relation (from Tom Hales).  *)
+(* ------------------------------------------------------------------------- *)
+
+let path_component = new_definition
+ `path_component s x y <=>
+        ?g. path g /\ path_image g SUBSET s /\
+            pathstart g = x /\ pathfinish g = y`;;
+
+let PATH_COMPONENT_IN = prove
+ (`!s x y. path_component s x y ==> x IN s /\ y IN s`,
+  REWRITE_TAC[path_component; path_image; pathstart; pathfinish] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(SUBST1_TAC o SYM)) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_LE_REFL; REAL_POS]);;
+
+let PATH_COMPONENT_REFL = prove
+ (`!s x:real^N. x IN s ==> path_component s x x`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[path_component] THEN
+  EXISTS_TAC `(\u. x):real^1->real^N` THEN
+  REWRITE_TAC[pathstart; pathfinish; path_image; path;
+              CONTINUOUS_ON_CONST; IMAGE; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN ASM_MESON_TAC[]);;
+
+let PATH_COMPONENT_REFL_EQ = prove
+ (`!s x:real^N. path_component s x x <=> x IN s`,
+  MESON_TAC[PATH_COMPONENT_IN; PATH_COMPONENT_REFL]);;
+
+let PATH_COMPONENT_SYM = prove
+ (`!s x y:real^N. path_component s x y ==> path_component s y x`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[path_component] THEN
+  MESON_TAC[PATH_REVERSEPATH; PATH_IMAGE_REVERSEPATH;
+            PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH]);;
+
+let PATH_COMPONENT_SYM_EQ = prove
+ (`!s x y. path_component s x y <=> path_component s y x`,
+  MESON_TAC[PATH_COMPONENT_SYM]);;
+
+let PATH_COMPONENT_TRANS = prove
+ (`!s x y:real^N.
+    path_component s x y /\ path_component s y z ==> path_component s x z`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[path_component] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_TAC `g1:real^1->real^N`) (X_CHOOSE_TAC `g2:real^1->real^N`)) THEN
+  EXISTS_TAC `g1 ++ g2 :real^1->real^N` THEN
+  ASM_SIMP_TAC[PATH_JOIN; PATH_IMAGE_JOIN; UNION_SUBSET;
+               PATHSTART_JOIN; PATHFINISH_JOIN]);;
+
+let PATH_COMPONENT_OF_SUBSET = prove
+ (`!s t x. s SUBSET t /\ path_component s x y ==> path_component t x y`,
+  REWRITE_TAC[path_component] THEN SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Can also consider it as a set, as the name suggests.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_COMPONENT_SET = prove
+ (`!s x. path_component s x =
+            { y | ?g. path g /\ path_image g SUBSET s /\
+                      pathstart g = x /\ pathfinish g = y }`,
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN REWRITE_TAC[IN; path_component]);;
+
+let PATH_COMPONENT_SUBSET = prove
+ (`!s x. (path_component s x) SUBSET s`,
+  REWRITE_TAC[SUBSET; IN] THEN MESON_TAC[PATH_COMPONENT_IN; IN]);;
+
+let PATH_COMPONENT_EQ_EMPTY = prove
+ (`!s x. path_component s x = {} <=> ~(x IN s)`,
+  REWRITE_TAC[EXTENSION; NOT_IN_EMPTY] THEN
+  MESON_TAC[IN; PATH_COMPONENT_REFL; PATH_COMPONENT_IN]);;
+
+let PATH_COMPONENT_EMPTY = prove
+ (`!x. path_component {} x = {}`,
+  REWRITE_TAC[PATH_COMPONENT_EQ_EMPTY; NOT_IN_EMPTY]);;
+
+let UNIONS_PATH_COMPONENT = prove
+ (`!s:real^N->bool. UNIONS {path_component s x |x| x IN s} = s`,
+  GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC; PATH_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[PATH_COMPONENT_REFL_EQ]);;
+
+let PATH_COMPONENT_TRANSLATION = prove
+ (`!a s x. path_component (IMAGE (\x. a + x) s) (a + x) =
+                IMAGE (\x. a + x) (path_component s x)`,
+  REWRITE_TAC[PATH_COMPONENT_SET] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [PATH_COMPONENT_TRANSLATION];;
+
+let PATH_COMPONENT_LINEAR_IMAGE = prove
+ (`!f s x. linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+           ==> path_component (IMAGE f s) (f x) =
+               IMAGE f (path_component s x)`,
+  REWRITE_TAC[PATH_COMPONENT_SET] THEN
+  GEOM_TRANSFORM_TAC[]);;
+
+add_linear_invariants [PATH_COMPONENT_LINEAR_IMAGE];;
+
+(* ------------------------------------------------------------------------- *)
+(* Path connectedness of a space.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let path_connected = new_definition
+ `path_connected s <=>
+        !x y. x IN s /\ y IN s
+              ==> ?g. path g /\ (path_image g) SUBSET s /\
+                      pathstart g = x /\ pathfinish g = y`;;
+
+let PATH_CONNECTED_IFF_PATH_COMPONENT = prove
+ (`!s. path_connected s <=> !x y. x IN s /\ y IN s ==> path_component s x y`,
+  REWRITE_TAC[path_connected; path_component]);;
+
+let PATH_CONNECTED_COMPONENT_SET = prove
+ (`!s. path_connected s <=> !x. x IN s ==> path_component s x = s`,
+  REWRITE_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT; GSYM SUBSET_ANTISYM_EQ] THEN
+  REWRITE_TAC[PATH_COMPONENT_SUBSET] THEN SET_TAC[]);;
+
+let PATH_COMPONENT_MONO = prove
+ (`!s t x. s SUBSET t ==> (path_component s x) SUBSET (path_component t x)`,
+  REWRITE_TAC[PATH_COMPONENT_SET] THEN SET_TAC[]);;
+
+let PATH_COMPONENT_MAXIMAL = prove
+ (`!s t x. x IN t /\ path_connected t /\ t SUBSET s
+           ==> t SUBSET (path_component s x)`,
+  REWRITE_TAC[path_connected; PATH_COMPONENT_SET; SUBSET; IN_ELIM_THM] THEN
+  MESON_TAC[]);;
+
+let PATH_COMPONENT_EQ = prove
+ (`!s x y. y IN path_component s x
+           ==> path_component s y = path_component s x`,
+  REWRITE_TAC[EXTENSION; IN] THEN
+  MESON_TAC[PATH_COMPONENT_SYM; PATH_COMPONENT_TRANS]);;
+
+let PATH_COMPONENT_PATH_IMAGE_PATHSTART = prove
+ (`!p x:real^N.
+        path p /\ x IN path_image p
+        ==> path_component (path_image p) (pathstart p) x`,
+  REWRITE_TAC[path_image; IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `x:real^1 = vec 0` THENL
+   [ASM_REWRITE_TAC[pathstart] THEN MATCH_MP_TAC PATH_COMPONENT_REFL THEN
+    MATCH_MP_TAC FUN_IN_IMAGE THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+    REWRITE_TAC[DROP_VEC; REAL_POS];
+    ALL_TAC] THEN
+  REWRITE_TAC[path_component] THEN
+  EXISTS_TAC `\y. (p:real^1->real^N)(drop x % y)` THEN
+  ASM_REWRITE_TAC[path; path_image; pathstart; pathfinish] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_COMPOSE) THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [path]) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] CONTINUOUS_ON_SUBSET);
+    ONCE_REWRITE_TAC[GSYM o_DEF] THEN REWRITE_TAC[IMAGE_o] THEN
+    MATCH_MP_TAC IMAGE_SUBSET;
+    AP_TERM_TAC THEN REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; DROP_VEC] THEN
+    REWRITE_TAC[REAL_MUL_RID]] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+  SIMP_TAC[IN_INTERVAL_1; DROP_CMUL; DROP_VEC; REAL_LE_MUL] THEN
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
+  MATCH_MP_TAC REAL_LE_MUL2 THEN ASM_REWRITE_TAC[]);;
+
+let PATH_CONNECTED_PATH_IMAGE = prove
+ (`!p:real^1->real^N. path p ==> path_connected(path_image p)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+  MATCH_MP_TAC PATH_COMPONENT_TRANS THEN
+  EXISTS_TAC `pathstart p :real^N` THEN
+  ASM_MESON_TAC[PATH_COMPONENT_PATH_IMAGE_PATHSTART; PATH_COMPONENT_SYM]);;
+
+let PATH_CONNECTED_PATH_COMPONENT = prove
+ (`!s x:real^N. path_connected(path_component s x)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[path_connected; IN] THEN
+  MAP_EVERY X_GEN_TAC [`y:real^N`; `z:real^N`] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `path_component s y (z:real^N)` MP_TAC THENL
+   [ASM_MESON_TAC[PATH_COMPONENT_SYM; PATH_COMPONENT_TRANS]; ALL_TAC] THEN
+  REWRITE_TAC[path_component] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `p:real^1->real^N` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[SUBSET] THEN
+  X_GEN_TAC `w:real^N` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `path_component s (x:real^N) = path_component s y`
+  SUBST1_TAC THENL [ASM_MESON_TAC[PATH_COMPONENT_EQ; IN]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`p:real^1->real^N`; `w:real^N`]
+     PATH_COMPONENT_PATH_IMAGE_PATHSTART) THEN
+  ASM_REWRITE_TAC[] THEN REWRITE_TAC[IN] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP PATH_COMPONENT_MONO) THEN
+  REWRITE_TAC[SUBSET; IN] THEN MESON_TAC[]);;
+
+let PATH_COMPONENT = prove
+ (`!s x y:real^N.
+        path_component s x y <=>
+        ?t. path_connected t /\ t SUBSET s /\ x IN t /\ y IN t`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN STRIP_TAC THENL
+   [EXISTS_TAC `path_component s (x:real^N)` THEN
+    REWRITE_TAC[PATH_CONNECTED_PATH_COMPONENT; PATH_COMPONENT_SUBSET] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP PATH_COMPONENT_IN) THEN
+    ASM_SIMP_TAC[IN; PATH_COMPONENT_REFL_EQ];
+    REWRITE_TAC[path_component] THEN ASM_MESON_TAC[path_connected; SUBSET]]);;
+
+let PATH_COMPONENT_PATH_COMPONENT = prove
+ (`!s x:real^N.
+        path_component (path_component s x) x = path_component s x`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `(x:real^N) IN s` THENL
+   [MATCH_MP_TAC SUBSET_ANTISYM THEN
+    SIMP_TAC[PATH_COMPONENT_MONO; PATH_COMPONENT_SUBSET] THEN
+    MATCH_MP_TAC PATH_COMPONENT_MAXIMAL THEN
+    REWRITE_TAC[SUBSET_REFL; PATH_CONNECTED_PATH_COMPONENT] THEN
+    ASM_REWRITE_TAC[IN; PATH_COMPONENT_REFL_EQ];
+    MATCH_MP_TAC(SET_RULE `s = {} /\ t = {} ==> s = t`) THEN
+    ASM_REWRITE_TAC[PATH_COMPONENT_EQ_EMPTY] THEN
+    ASM_MESON_TAC[SUBSET; PATH_COMPONENT_SUBSET]]);;
+
+let PATH_CONNECTED_LINEPATH = prove
+ (`!s a b:real^N. segment[a,b] SUBSET s ==> path_component s a b`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[path_component] THEN
+  EXISTS_TAC `linepath(a:real^N,b)` THEN
+  ASM_REWRITE_TAC[PATHSTART_LINEPATH; PATHFINISH_LINEPATH; PATH_LINEPATH] THEN
+  ASM_REWRITE_TAC[PATH_IMAGE_LINEPATH]);;
+
+let PATH_COMPONENT_DISJOINT = prove
+ (`!s a b. DISJOINT (path_component s a) (path_component s b) <=>
+             ~(a IN path_component s b)`,
+  REWRITE_TAC[DISJOINT; EXTENSION; IN_INTER; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[IN] THEN MESON_TAC[PATH_COMPONENT_SYM; PATH_COMPONENT_TRANS]);;
+
+let PATH_COMPONENT_EQ_EQ = prove
+ (`!s x y:real^N.
+        path_component s x = path_component s y <=>
+        ~(x IN s) /\ ~(y IN s) \/
+        x IN s /\ y IN s /\ path_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[PATH_COMPONENT_TRANS; PATH_COMPONENT_REFL;
+                    PATH_COMPONENT_SYM];
+      ASM_MESON_TAC[PATH_COMPONENT_EQ_EMPTY]];
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM PATH_COMPONENT_EQ_EMPTY]) THEN
+    ASM_REWRITE_TAC[PATH_COMPONENT_EQ_EMPTY] THEN
+    ONCE_REWRITE_TAC[PATH_COMPONENT_SYM_EQ] THEN
+    ASM_REWRITE_TAC[EMPTY] THEN ASM_MESON_TAC[PATH_COMPONENT_EQ_EMPTY]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* General "locally connected implies connected" type results.               *)
+(* ------------------------------------------------------------------------- *)
+
+let OPEN_GENERAL_COMPONENT = prove
+ (`!c. (!s x y. c s x y ==> x IN s /\ y IN s) /\
+       (!s x y. c s x y ==> c s y x) /\
+       (!s x y z. c s x y /\ c s y z ==> c s x z) /\
+       (!s t x y. s SUBSET t /\ c s x y ==> c t x y) /\
+       (!s x y e. y IN ball(x,e) /\ ball(x,e) SUBSET s
+                  ==> c (ball(x,e)) x y)
+       ==> !s x:real^N. open s ==> open(c s x)`,
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "IN") MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "SYM") MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "TRANS") MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "SUBSET") (LABEL_TAC "BALL")) THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_CONTAINS_BALL; SUBSET; IN_BALL] THEN
+  DISCH_TAC THEN X_GEN_TAC `y:real^N` THEN
+  REWRITE_TAC[SUBSET; IN] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `(x:real^N) IN s /\ y IN s` STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o C MATCH_MP (ASSUME `(y:real^N) IN s`)) 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
+  REMOVE_THEN "TRANS" MATCH_MP_TAC THEN EXISTS_TAC `y:real^N` THEN
+  ASM_REWRITE_TAC[] THEN REMOVE_THEN "SUBSET" MATCH_MP_TAC THEN
+  EXISTS_TAC `ball(y:real^N,e)` THEN ASM_REWRITE_TAC[SUBSET; IN_BALL] THEN
+  REMOVE_THEN "BALL" MATCH_MP_TAC THEN
+  REWRITE_TAC[SUBSET; IN_BALL] THEN ASM_MESON_TAC[]);;
+
+let OPEN_NON_GENERAL_COMPONENT = prove
+ (`!c. (!s x y. c s x y ==> x IN s /\ y IN s) /\
+       (!s x y. c s x y ==> c s y x) /\
+       (!s x y z. c s x y /\ c s y z ==> c s x z) /\
+       (!s t x y. s SUBSET t /\ c s x y ==> c t x y) /\
+       (!s x y e. y IN ball(x,e) /\ ball(x,e) SUBSET s
+                  ==> c (ball(x,e)) x y)
+       ==> !s x:real^N. open s ==> open(s DIFF c s x)`,
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "IN") MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "SYM") MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "TRANS") MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "SUBSET") (LABEL_TAC "BALL")) THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_CONTAINS_BALL; SUBSET; IN_BALL] THEN
+  DISCH_TAC THEN X_GEN_TAC `y:real^N` THEN REWRITE_TAC[IN_DIFF] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (ASSUME_TAC o REWRITE_RULE[IN])) THEN
+  FIRST_X_ASSUM(MP_TAC o C MATCH_MP (ASSUME `(y:real^N) IN s`)) 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 ASM_SIMP_TAC[] THEN
+  REWRITE_TAC[IN] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o check (is_neg o concl)) THEN REWRITE_TAC[] THEN
+  REMOVE_THEN "TRANS" MATCH_MP_TAC THEN EXISTS_TAC `z:real^N` THEN
+  ASM_REWRITE_TAC[] THEN REMOVE_THEN "SUBSET" MATCH_MP_TAC THEN
+  EXISTS_TAC `ball(y:real^N,e)` THEN ASM_REWRITE_TAC[SUBSET; IN_BALL] THEN
+  REMOVE_THEN "SYM" MATCH_MP_TAC THEN
+  REMOVE_THEN "BALL" MATCH_MP_TAC THEN
+  REWRITE_TAC[SUBSET; IN_BALL] THEN ASM_MESON_TAC[]);;
+
+let GENERAL_CONNECTED_OPEN = prove
+ (`!c. (!s x y. c s x y ==> x IN s /\ y IN s) /\
+       (!s x y. c s x y ==> c s y x) /\
+       (!s x y z. c s x y /\ c s y z ==> c s x z) /\
+       (!s t x y. s SUBSET t /\ c s x y ==> c t x y) /\
+       (!s x y e. y IN ball(x,e) /\ ball(x,e) SUBSET s
+                  ==> c (ball(x,e)) x y)
+       ==> !s x y:real^N. open s /\ connected s /\ x IN s /\ y IN s
+                          ==> c s x y`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [connected]) THEN
+  REWRITE_TAC[IN] THEN REWRITE_TAC[NOT_EXISTS_THM; LEFT_IMP_FORALL_THM] THEN
+  MAP_EVERY EXISTS_TAC
+   [`c (s:real^N->bool) (x:real^N):real^N->bool`;
+    `s DIFF (c (s:real^N->bool) (x:real^N))`] THEN
+  MATCH_MP_TAC(TAUT `a /\ b /\ c /\ d /\ e /\ (f ==> g)
+                     ==> ~(a /\ b /\ c /\ d /\ e /\ ~f) ==> g`) THEN
+  REPEAT CONJ_TAC THENL
+   [MP_TAC(SPEC `c:(real^N->bool)->real^N->real^N->bool`
+        OPEN_GENERAL_COMPONENT) THEN ASM_MESON_TAC[];
+    MP_TAC(SPEC `c:(real^N->bool)->real^N->real^N->bool`
+        OPEN_NON_GENERAL_COMPONENT) THEN ASM_MESON_TAC[];
+    SET_TAC[];
+    SET_TAC[];
+    ALL_TAC;
+    ASM SET_TAC[]] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `x:real^N` THEN
+  ASM_REWRITE_TAC[IN_INTER] THEN REWRITE_TAC[IN] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o
+    SPECL [`ball(x:real^N,e)`; `s:real^N->bool`]) THEN
+  ASM_MESON_TAC[CENTRE_IN_BALL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some useful lemmas about path-connectedness.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let CONVEX_IMP_PATH_CONNECTED = prove
+ (`!s:real^N->bool. convex s ==> path_connected s`,
+  REWRITE_TAC[CONVEX_ALT; path_connected] THEN REPEAT GEN_TAC THEN
+  DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
+  STRIP_TAC THEN EXISTS_TAC `\u. (&1 - drop u) % x + drop u % y:real^N` THEN
+  ASM_SIMP_TAC[pathstart; pathfinish; DROP_VEC; path; path_image;
+               SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1; GSYM FORALL_DROP] THEN
+  CONJ_TAC THENL [ALL_TAC; CONJ_TAC THEN VECTOR_ARITH_TAC] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_ADD THEN CONJ_TAC THEN
+  MATCH_MP_TAC CONTINUOUS_ON_VMUL THEN
+  REWRITE_TAC[o_DEF; LIFT_SUB; LIFT_DROP; LIFT_NUM] THEN
+  SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID]);;
+
+let PATH_CONNECTED_UNIV = prove
+ (`path_connected(:real^N)`,
+  SIMP_TAC[CONVEX_IMP_PATH_CONNECTED; CONVEX_UNIV]);;
+
+let IS_INTERVAL_PATH_CONNECTED = prove
+ (`!s. is_interval s ==> path_connected s`,
+  SIMP_TAC[CONVEX_IMP_PATH_CONNECTED; IS_INTERVAL_CONVEX]);;
+
+let PATH_CONNECTED_INTERVAL = prove
+ (`(!a b:real^N. path_connected(interval[a,b])) /\
+   (!a b:real^N. path_connected(interval(a,b)))`,
+  SIMP_TAC[IS_INTERVAL_PATH_CONNECTED; IS_INTERVAL_INTERVAL]);;
+
+let PATH_COMPONENT_UNIV = prove
+ (`!x. path_component(:real^N) x = (:real^N)`,
+  MESON_TAC[PATH_CONNECTED_COMPONENT_SET; PATH_CONNECTED_UNIV; IN_UNIV]);;
+
+let PATH_CONNECTED_IMP_CONNECTED = prove
+ (`!s:real^N->bool. path_connected s ==> connected s`,
+  GEN_TAC THEN
+  REWRITE_TAC[path_connected; CONNECTED_IFF_CONNECTED_COMPONENT] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:real^N` THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `y:real^N` THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^N` STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[connected_component] THEN
+  EXISTS_TAC `path_image(g:real^1->real^N)` THEN
+  ASM_MESON_TAC[CONNECTED_PATH_IMAGE; PATHSTART_IN_PATH_IMAGE;
+                PATHFINISH_IN_PATH_IMAGE]);;
+
+let OPEN_PATH_COMPONENT = prove
+ (`!s x:real^N. open s ==> open(path_component s x)`,
+  MATCH_MP_TAC OPEN_GENERAL_COMPONENT THEN
+  REWRITE_TAC[PATH_COMPONENT_IN; PATH_COMPONENT_SYM; PATH_COMPONENT_TRANS;
+              PATH_COMPONENT_OF_SUBSET] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[PATH_CONNECTED_IFF_PATH_COMPONENT]
+   (MATCH_MP CONVEX_IMP_PATH_CONNECTED (SPEC_ALL CONVEX_BALL))) THEN
+  ASM_MESON_TAC[CENTRE_IN_BALL; BALL_EQ_EMPTY; REAL_NOT_LE; NOT_IN_EMPTY]);;
+
+let OPEN_NON_PATH_COMPONENT = prove
+ (`!s x:real^N. open s ==> open(s DIFF path_component s x)`,
+  MATCH_MP_TAC OPEN_NON_GENERAL_COMPONENT THEN
+  REWRITE_TAC[PATH_COMPONENT_IN; PATH_COMPONENT_SYM; PATH_COMPONENT_TRANS;
+              PATH_COMPONENT_OF_SUBSET] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[PATH_CONNECTED_IFF_PATH_COMPONENT]
+   (MATCH_MP CONVEX_IMP_PATH_CONNECTED (SPEC_ALL CONVEX_BALL))) THEN
+  ASM_MESON_TAC[CENTRE_IN_BALL; BALL_EQ_EMPTY; REAL_NOT_LE; NOT_IN_EMPTY]);;
+
+let PATH_CONNECTED_CONTINUOUS_IMAGE = prove
+ (`!f:real^M->real^N s.
+        f continuous_on s /\ path_connected s ==> path_connected (IMAGE f s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[path_connected] THEN STRIP_TAC THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+  X_GEN_TAC `y:real^M` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^M`; `y:real^M`]) THEN
+  ASM_REWRITE_TAC[path; path_image; pathstart; pathfinish] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^M` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(f:real^M->real^N) o (g:real^1->real^M)` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+    ASM_REWRITE_TAC[o_DEF] THEN ASM SET_TAC[]]);;
+
+let HOMEOMORPHIC_PATH_CONNECTEDNESS = prove
+ (`!s t. s homeomorphic t ==> (path_connected s <=> path_connected t)`,
+  REWRITE_TAC[homeomorphic; homeomorphism] THEN
+  MESON_TAC[PATH_CONNECTED_CONTINUOUS_IMAGE]);;
+
+let PATH_CONNECTED_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+     path_connected s /\ linear f ==> path_connected(IMAGE f s)`,
+  SIMP_TAC[LINEAR_CONTINUOUS_ON; PATH_CONNECTED_CONTINUOUS_IMAGE]);;
+
+let PATH_CONNECTED_LINEAR_IMAGE_EQ = prove
+ (`!f s. linear f /\ (!x y. f x = f y ==> x = y)
+         ==> (path_connected (IMAGE f s) <=> path_connected s)`,
+  MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE PATH_CONNECTED_LINEAR_IMAGE));;
+
+add_linear_invariants [PATH_CONNECTED_LINEAR_IMAGE_EQ];;
+
+let PATH_CONNECTED_EMPTY = prove
+ (`path_connected {}`,
+  REWRITE_TAC[path_connected; NOT_IN_EMPTY]);;
+
+let PATH_CONNECTED_SING = prove
+ (`!a:real^N. path_connected {a}`,
+  GEN_TAC THEN REWRITE_TAC[path_connected; IN_SING] THEN
+  REPEAT STRIP_TAC THEN EXISTS_TAC `linepath(a:real^N,a)` THEN
+  ASM_REWRITE_TAC[PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+  REWRITE_TAC[SEGMENT_REFL; PATH_IMAGE_LINEPATH; SUBSET_REFL]);;
+
+let PATH_CONNECTED_UNION = prove
+ (`!s t. path_connected s /\ path_connected t /\ ~(s INTER t = {})
+         ==> path_connected (s UNION t)`,
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; PATH_CONNECTED_IFF_PATH_COMPONENT] THEN
+  REWRITE_TAC[IN_INTER; IN_UNION] THEN
+  MESON_TAC[PATH_COMPONENT_OF_SUBSET; SUBSET_UNION; PATH_COMPONENT_TRANS]);;
+
+let PATH_CONNECTED_TRANSLATION = prove
+ (`!a s. path_connected s ==> path_connected (IMAGE (\x:real^N. a + x) s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_CONNECTED_CONTINUOUS_IMAGE THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST]);;
+
+let PATH_CONNECTED_TRANSLATION_EQ = prove
+ (`!a s. path_connected (IMAGE (\x:real^N. a + x) s) <=> path_connected s`,
+  REWRITE_TAC[path_connected] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [PATH_CONNECTED_TRANSLATION_EQ];;
+
+let PATH_CONNECTED_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        path_connected s /\ path_connected t
+        ==> path_connected (s PCROSS t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[PCROSS; path_connected] 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] THEN
+  X_GEN_TAC `h:real^1->real^N` THEN STRIP_TAC THEN
+  X_GEN_TAC `g:real^1->real^M` THEN STRIP_TAC THEN
+  EXISTS_TAC `(\t. pastecart (x1:real^M) ((h:real^1->real^N) t)) ++
+              (\t. pastecart ((g:real^1->real^M) t) (y2:real^N))` THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish; path]) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[path_image; FORALL_IN_IMAGE; SUBSET]) THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC PATH_JOIN_IMP THEN REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[path] THEN MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+      ASM_REWRITE_TAC[CONTINUOUS_ON_CONST];
+      REWRITE_TAC[path] THEN MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+      ASM_REWRITE_TAC[CONTINUOUS_ON_CONST];
+      ASM_REWRITE_TAC[pathstart; pathfinish]];
+    MATCH_MP_TAC SUBSET_PATH_IMAGE_JOIN THEN
+    ASM_SIMP_TAC[path_image; FORALL_IN_IMAGE; SUBSET; IN_ELIM_PASTECART_THM];
+    REWRITE_TAC[PATHSTART_JOIN] THEN ASM_REWRITE_TAC[pathstart];
+    REWRITE_TAC[PATHFINISH_JOIN] THEN ASM_REWRITE_TAC[pathfinish]]);;
+
+let PATH_CONNECTED_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        path_connected(s PCROSS t) <=>
+        s = {} \/ t = {} \/ path_connected s /\ path_connected t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; PATH_CONNECTED_EMPTY] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; PATH_CONNECTED_EMPTY] THEN
+  EQ_TAC THEN REWRITE_TAC[PATH_CONNECTED_PCROSS] THEN REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL [`fstcart:real^(M,N)finite_sum->real^M`;
+                    `(s:real^M->bool) PCROSS (t:real^N->bool)`]
+       PATH_CONNECTED_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_FSTCART];
+    MP_TAC(ISPECL [`sndcart:real^(M,N)finite_sum->real^N`;
+                   `(s:real^M->bool) PCROSS (t:real^N->bool)`]
+       PATH_CONNECTED_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_SNDCART]] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; EXISTS_PASTECART; PASTECART_IN_PCROSS;
+              FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  ASM SET_TAC[]);;
+
+let PATH_CONNECTED_SCALING = prove
+ (`!s:real^N->bool c.
+        path_connected s ==> path_connected (IMAGE (\x. c % x) s)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC PATH_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 PATH_CONNECTED_NEGATIONS = prove
+ (`!s:real^N->bool.
+        path_connected s ==> path_connected (IMAGE (--) s)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC PATH_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 PATH_CONNECTED_SUMS = prove
+ (`!s t:real^N->bool.
+        path_connected s /\ path_connected t
+        ==> path_connected {x + y | x IN s /\ y IN t}`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP PATH_CONNECTED_PCROSS) THEN
+  DISCH_THEN(MP_TAC o ISPEC
+   `\z. (fstcart z + sndcart z:real^N)` o
+    MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+      PATH_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 IS_INTERVAL_PATH_CONNECTED_1 = prove
+ (`!s:real^1->bool. is_interval s <=> path_connected s`,
+  MESON_TAC[CONVEX_IMP_PATH_CONNECTED; PATH_CONNECTED_IMP_CONNECTED;
+            IS_INTERVAL_CONNECTED_1; IS_INTERVAL_CONVEX_1]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More stuff about segments.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let SEGMENT_OPEN_SUBSET_CLOSED = prove
+ (`!a b. segment(a,b) SUBSET segment[a,b]`,
+  REWRITE_TAC[CONJUNCT2(SPEC_ALL segment)] THEN SET_TAC[]);;
+
+let CLOSED_SEGMENT = prove
+ (`!a b. closed(segment[a,b])`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+  MATCH_MP_TAC COMPACT_IMP_CLOSED THEN MATCH_MP_TAC COMPACT_CONVEX_HULL THEN
+  MATCH_MP_TAC FINITE_IMP_COMPACT THEN SIMP_TAC[FINITE_RULES]);;
+
+let SEGMENT_IMAGE_INTERVAL = prove
+ (`(!a b. segment[a,b] =
+          IMAGE (\u. (&1 - drop u) % a + drop u % b)
+                (interval[vec 0,vec 1])) /\
+   (!a b. ~(a = b)
+          ==> segment(a,b) =
+                IMAGE (\u. (&1 - drop u) % a + drop u % b)
+                (interval(vec 0,vec 1)))`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_INTERVAL_1; IN_SEGMENT] THEN
+  ASM_REWRITE_TAC[GSYM EXISTS_DROP; DROP_VEC] THEN MESON_TAC[]);;
+
+let CLOSURE_SEGMENT = prove
+ (`(!a b:real^N. closure(segment[a,b]) = segment[a,b]) /\
+   (!a b:real^N. closure(segment(a,b)) = if a = b then {} else segment[a,b])`,
+  REWRITE_TAC[CLOSURE_EQ; CLOSED_SEGMENT] THEN
+  REPEAT GEN_TAC THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[SEGMENT_REFL; CLOSURE_EMPTY] THEN
+  ASM_SIMP_TAC[SEGMENT_IMAGE_INTERVAL] THEN
+  ASM_SIMP_TAC[CONV_RULE(RAND_CONV SYM_CONV) (SPEC_ALL CLOSURE_OPEN_INTERVAL);
+               INTERVAL_EQ_EMPTY_1; DROP_VEC; REAL_ARITH `~(&1 <= &0)`] THEN
+  SUBGOAL_THEN
+   `(\u. (&1 - drop u) % a + drop u % (b:real^N)) =
+    (\x. a + x) o (\u. drop u % (b - a))`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[FUN_EQ_THM; o_THM] THEN VECTOR_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[IMAGE_o; CLOSURE_TRANSLATION] THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC CLOSURE_INJECTIVE_LINEAR_IMAGE THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_RCANCEL; VECTOR_SUB_EQ; DROP_EQ] THEN
+  REWRITE_TAC[linear; DROP_ADD; DROP_CMUL] THEN VECTOR_ARITH_TAC);;
+
+let AFFINE_HULL_SEGMENT = prove
+ (`(!a b:real^N. affine hull (segment [a,b]) = affine hull {a,b}) /\
+   (!a b:real^N. affine hull (segment(a,b)) =
+                 if a = b then {} else affine hull {a,b})`,
+  REWRITE_TAC[SEGMENT_CONVEX_HULL; AFFINE_HULL_CONVEX_HULL] THEN
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM AFFINE_HULL_CLOSURE] THEN
+  REWRITE_TAC[CLOSURE_SEGMENT] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[AFFINE_HULL_EMPTY] THEN
+  REWRITE_TAC[SEGMENT_CONVEX_HULL; AFFINE_HULL_CONVEX_HULL]);;
+
+let SEGMENT_AS_BALL = prove
+ (`(!a b. segment[a:real^N,b] =
+         affine hull {a,b} INTER cball(inv(&2) % (a + b),norm(b - a) / &2)) /\
+   (!a b. segment(a:real^N,b) =
+         affine hull {a,b} INTER ball(inv(&2) % (a + b),norm(b - a) / &2))`,
+  REPEAT STRIP_TAC THEN
+  (ASM_CASES_TAC `b:real^N = a` THEN
+   ASM_REWRITE_TAC[SEGMENT_REFL; VECTOR_SUB_REFL; NORM_0] THEN
+   CONV_TAC REAL_RAT_REDUCE_CONV THEN
+   REWRITE_TAC[BALL_TRIVIAL; CBALL_TRIVIAL] THENL
+    [REWRITE_TAC[INTER_EMPTY; INSERT_AC] THEN
+     REWRITE_TAC[VECTOR_ARITH `&1 / &2 % (a + a) = a`] THEN
+     REWRITE_TAC[SET_RULE `a = b INTER a <=> a SUBSET b`; HULL_SUBSET];
+     ASM_REWRITE_TAC[EXTENSION; IN_SEGMENT; IN_INTER; AFFINE_HULL_2] THEN
+     X_GEN_TAC `y:real^N` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+     ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+     REWRITE_TAC[REAL_ARITH `u + v:real = &1 <=> u = &1 - v`] THEN
+     REWRITE_TAC[UNWIND_THM2] THEN REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN
+     AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+     X_GEN_TAC `u:real` THEN REWRITE_TAC[] THEN
+     ASM_CASES_TAC `y:real^N = (&1 - u) % a + u % b` THEN
+     ASM_REWRITE_TAC[] THEN REWRITE_TAC[IN_BALL; IN_CBALL; dist; VECTOR_ARITH
+      `&1 / &2 % (a + b) - ((&1 - u) % a + u % b):real^N =
+       (&1 / &2 - u) % (b - a)`] THEN
+    ASM_SIMP_TAC[NORM_MUL; REAL_LT_MUL_EQ; REAL_LE_MUL_EQ; NORM_POS_LT;
+     VECTOR_SUB_EQ; REAL_ARITH `a * n < n / &2 <=> &0 < n * (inv(&2) - a)`;
+              REAL_ARITH `a * n <= n / &2 <=> &0 <= n * (inv(&2) - a)`] THEN
+    REAL_ARITH_TAC]));;
+
+let CONVEX_SEGMENT = prove
+ (`(!a b. convex(segment[a,b])) /\ (!a b. convex(segment(a,b)))`,
+  REWRITE_TAC[SEGMENT_AS_BALL] THEN
+  SIMP_TAC[CONVEX_INTER; CONVEX_BALL; CONVEX_CBALL;
+           AFFINE_IMP_CONVEX; AFFINE_AFFINE_HULL]);;
+
+let RELATIVE_INTERIOR_SEGMENT = prove
+ (`(!a b:real^N.
+      relative_interior(segment[a,b]) = if a = b then {a} else segment(a,b)) /\
+   (!a b:real^N. relative_interior(segment(a,b)) = segment(a,b))`,
+  MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = b` THEN
+    ASM_REWRITE_TAC[SEGMENT_REFL; RELATIVE_INTERIOR_EMPTY] THEN
+    REWRITE_TAC[RELATIVE_INTERIOR_EQ; OPEN_IN_OPEN] THEN
+    ASM_REWRITE_TAC[AFFINE_HULL_SEGMENT] THEN
+    EXISTS_TAC `ball(inv(&2) % (a + b):real^N,norm(b - a) / &2)` THEN
+    REWRITE_TAC[OPEN_BALL; SEGMENT_AS_BALL];
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[SEGMENT_REFL; RELATIVE_INTERIOR_SING] THEN
+    MP_TAC(ISPECL [`a:real^N`; `b:real^N`] (CONJUNCT2 CLOSURE_SEGMENT)) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [GSYM th]) THEN
+    MATCH_MP_TAC CONVEX_RELATIVE_INTERIOR_CLOSURE THEN
+    REWRITE_TAC[CONVEX_SEGMENT]]);;
+
+let PATH_CONNECTED_SEGMENT = prove
+ (`(!a b. path_connected(segment[a,b])) /\
+   (!a b. path_connected(segment(a,b)))`,
+  SIMP_TAC[CONVEX_IMP_PATH_CONNECTED; CONVEX_SEGMENT]);;
+
+let CONNECTED_SEGMENT = prove
+ (`(!a b. connected(segment[a,b])) /\ (!a b. connected(segment(a,b)))`,
+  SIMP_TAC[CONVEX_CONNECTED; CONVEX_SEGMENT]);;
+
+let CONVEX_SEMIOPEN_SEGMENT = prove
+ (`(!a b:real^N. convex(segment[a,b] DELETE a)) /\
+   (!a b:real^N. convex(segment[a,b] DELETE b))`,
+  MATCH_MP_TAC(TAUT `(a ==> b) /\ a ==> a /\ b`) THEN
+  CONJ_TAC THENL [MESON_TAC[SEGMENT_SYM]; ALL_TAC] THEN
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `b:real^N = a` THEN
+  ASM_SIMP_TAC[SEGMENT_REFL; SET_RULE `{a} DELETE a = {}`; CONVEX_EMPTY] THEN
+  REWRITE_TAC[CONVEX_ALT; IN_DELETE] THEN
+  SIMP_TAC[REWRITE_RULE[CONVEX_ALT] CONVEX_SEGMENT] THEN
+  REWRITE_TAC[IN_SEGMENT] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC;
+                  GSYM VECTOR_ADD_ASSOC] THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH
+   `x % a + y % b + z % a + w % b:real^N = a <=>
+    (&1 - x - z) % a = (w + y) % b`] THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LCANCEL; REAL_ARITH
+   `&1 - (&1 - u) * (&1 - v) - u * (&1 - w) =
+    u * w + (&1 - u) * v`] THEN
+  ASM_SIMP_TAC[REAL_LE_MUL; REAL_SUB_LE; REAL_ARITH
+   `&0 <= x /\ &0 <= y ==> (x + y = &0 <=> x = &0 /\ y = &0)`] THEN
+  REWRITE_TAC[REAL_ENTIRE; REAL_ARITH `&1 - x = &0 <=> x = &1`] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+   `(u = &0 \/ w = &0) /\ (u = &1 \/ v = &0)
+    ==> u = &0 /\ v = &0 \/ u = &1 /\ w = &0 \/ v = &0 /\ w = &0`)) THEN
+  DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN (CONJUNCTS_THEN SUBST_ALL_TAC)) THEN
+  ASM_MESON_TAC[VECTOR_ARITH `(&1 - &0) % a + &0 % b:real^N = a`]);;
+
+let PATH_CONNECTED_SEMIOPEN_SEGMENT = prove
+ (`(!a b:real^N. path_connected(segment[a,b] DELETE a)) /\
+   (!a b:real^N. path_connected(segment[a,b] DELETE b))`,
+  SIMP_TAC[CONVEX_IMP_PATH_CONNECTED; CONVEX_SEMIOPEN_SEGMENT]);;
+
+let CONNECTED_SEMIOPEN_SEGMENT = prove
+ (`(!a b:real^N. connected(segment[a,b] DELETE a)) /\
+   (!a b:real^N. connected(segment[a,b] DELETE b))`,
+  SIMP_TAC[CONVEX_CONNECTED; CONVEX_SEMIOPEN_SEGMENT]);;
+
+let SEGMENT_EQ_EMPTY = prove
+ (`(!a b:real^N. ~(segment[a,b] = {})) /\
+   (!a b:real^N. segment(a,b) = {} <=> a = b)`,
+  REWRITE_TAC[SEGMENT_CONVEX_HULL; CONVEX_HULL_EQ_EMPTY; NOT_INSERT_EMPTY] THEN
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = b` THEN
+  ASM_REWRITE_TAC[SEGMENT_REFL] THEN
+  ASM_MESON_TAC[NOT_IN_EMPTY; MIDPOINT_IN_SEGMENT]);;
+
+let FINITE_SEGMENT = prove
+ (`(!a b:real^N. FINITE(segment[a,b]) <=> a = b) /\
+   (!a b:real^N. FINITE(segment(a,b)) <=> a = b)`,
+  REWRITE_TAC[open_segment; SET_RULE `s DIFF {a,b} = s DELETE a DELETE b`] THEN
+  REWRITE_TAC[FINITE_DELETE] THEN REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `a:real^N = b` THEN
+  ASM_REWRITE_TAC[SEGMENT_REFL; FINITE_SING] THEN
+  REWRITE_TAC[SEGMENT_IMAGE_INTERVAL] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) FINITE_IMAGE_INJ_EQ o rand o snd) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[VECTOR_ARITH
+     `(&1 - u) % a + u % b:real^N = (&1 - v) % a + v % b <=>
+      (u - v) % (b - a) = vec 0`] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ; REAL_SUB_0; DROP_EQ];
+    DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[FINITE_INTERVAL_1] THEN
+    REWRITE_TAC[DROP_VEC] THEN REAL_ARITH_TAC]);;
+
+let SEGMENT_EQ_SING = prove
+ (`(!a b c:real^N. segment[a,b] = {c} <=> a = c /\ b = c) /\
+   (!a b c:real^N. ~(segment(a,b) = {c}))`,
+  REWRITE_TAC[SEGMENT_CONVEX_HULL; CONVEX_HULL_EQ_SING] THEN
+  CONJ_TAC THENL [SET_TAC[]; REPEAT GEN_TAC] THEN
+  ASM_CASES_TAC `a:real^N = b` THEN
+  ASM_REWRITE_TAC[SEGMENT_REFL; NOT_INSERT_EMPTY] THEN
+  DISCH_TAC THEN
+  MP_TAC(ISPECL [`a:real^N`; `b:real^N`] (CONJUNCT2 FINITE_SEGMENT)) THEN
+  ASM_REWRITE_TAC[FINITE_SING]);;
+
+let SUBSET_SEGMENT_OPEN_CLOSED = prove
+ (`!a b c d:real^N.
+        segment(a,b) SUBSET segment(c,d) <=>
+        a = b \/ segment[a,b] SUBSET segment[c,d]`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [ASM_CASES_TAC `a:real^N = b` THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP SUBSET_CLOSURE) THEN
+    ASM_REWRITE_TAC[CLOSURE_SEGMENT] THEN
+    COND_CASES_TAC THEN REWRITE_TAC[SUBSET_EMPTY; SEGMENT_EQ_EMPTY];
+    ALL_TAC] THEN
+  DISCH_THEN(DISJ_CASES_THEN2 SUBST1_TAC MP_TAC) THEN
+  REWRITE_TAC[SEGMENT_REFL; EMPTY_SUBSET] THEN
+  ABBREV_TAC `m:real^N = d - c` THEN POP_ASSUM MP_TAC THEN
+  GEOM_NORMALIZE_TAC `m:real^N` THEN
+  SIMP_TAC[VECTOR_SUB_EQ; SEGMENT_REFL; SEGMENT_EQ_SING; SEGMENT_EQ_EMPTY;
+           SET_RULE `s SUBSET {a} <=> s = {a} \/ s = {}`; SUBSET_REFL] THEN
+  X_GEN_TAC `m:real^N` THEN DISCH_TAC THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(SUBST_ALL_TAC o SYM) THEN POP_ASSUM MP_TAC THEN
+  GEOM_ORIGIN_TAC `c:real^N` THEN GEOM_BASIS_MULTIPLE_TAC 1 `d:real^N` THEN
+  X_GEN_TAC `d:real` THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
+  SIMP_TAC[VECTOR_SUB_RZERO; NORM_MUL; NORM_BASIS; DIMINDEX_GE_1; LE_REFL] THEN
+  ASM_REWRITE_TAC[real_abs; REAL_MUL_RID] THEN DISCH_THEN SUBST_ALL_TAC THEN
+  POP_ASSUM(K ALL_TAC) THEN DISCH_TAC THEN
+  SUBGOAL_THEN `collinear{vec 0:real^N,&1 % basis 1,x} /\
+                collinear{vec 0:real^N,&1 % basis 1,y}`
+  MP_TAC THENL
+   [ONCE_REWRITE_TAC[SET_RULE `{a,b,c} = {a,c,b}`] THEN
+    CONJ_TAC THEN MATCH_MP_TAC BETWEEN_IMP_COLLINEAR THEN
+    REWRITE_TAC[BETWEEN_IN_SEGMENT] THEN
+    ASM_MESON_TAC[SUBSET; ENDS_IN_SEGMENT];
+    ALL_TAC] THEN
+  SIMP_TAC[COLLINEAR_LEMMA_ALT; BASIS_NONZERO; DIMINDEX_GE_1; LE_REFL;
+           VECTOR_ARITH `&1 % x:real^N = vec 0 <=> x = vec 0`] THEN
+  REWRITE_TAC[IMP_CONJ; VECTOR_MUL_ASSOC; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `a:real` THEN REWRITE_TAC[REAL_MUL_RID] THEN
+  DISCH_THEN SUBST_ALL_TAC THEN X_GEN_TAC `b:real` THEN
+  DISCH_THEN SUBST_ALL_TAC THEN POP_ASSUM MP_TAC THEN
+  SUBST1_TAC(VECTOR_ARITH `vec 0:real^N = &0 % basis 1`) THEN
+  ASM_SIMP_TAC[SEGMENT_SCALAR_MULTIPLE; VECTOR_MUL_RCANCEL; BASIS_NONZERO;
+               DIMINDEX_GE_1; LE_REFL; SET_RULE
+                `(!x y. x % v = y % v <=> x = y)
+                 ==> ({x % v | P x} SUBSET {x % v | Q x} <=>
+                      {x | P x} SUBSET {x | Q x})`] THEN
+  REWRITE_TAC[REAL_ARITH `a <= x /\ x <= b \/ b <= x /\ x <= a <=>
+                          min a b <= x /\ x <= max a b`;
+              REAL_ARITH `a < x /\ x < b \/ b < x /\ x < a <=>
+                          min a b < x /\ x < max a b`] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN DISCH_TAC THEN
+  X_GEN_TAC `x:real` THEN
+  FIRST_X_ASSUM(fun th -> MAP_EVERY (MP_TAC o C SPEC th)
+        [`min (a:real) b`; `max (a:real) b`]) THEN
+  REAL_ARITH_TAC);;
+
+let SUBSET_SEGMENT = prove
+ (`(!a b c d:real^N.
+        segment[a,b] SUBSET segment[c,d] <=>
+        a IN segment[c,d] /\ b IN segment[c,d]) /\
+   (!a b c d:real^N.
+        segment[a,b] SUBSET segment(c,d) <=>
+        a IN segment(c,d) /\ b IN segment(c,d)) /\
+   (!a b c d:real^N.
+        segment(a,b) SUBSET segment[c,d] <=>
+        a = b \/ a IN segment[c,d] /\ b IN segment[c,d]) /\
+   (!a b c d:real^N.
+        segment(a,b) SUBSET segment(c,d) <=>
+        a = b \/ a IN segment[c,d] /\ b IN segment[c,d])`,
+  MATCH_MP_TAC(TAUT `(a /\ b) /\ (a /\ b ==> c) ==> a /\ b /\ c`) THEN
+  CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [SEGMENT_CONVEX_HULL] THEN
+    SIMP_TAC[SUBSET_HULL; CONVEX_SEGMENT] THEN SET_TAC[];
+    STRIP_TAC THEN ASM_REWRITE_TAC[SUBSET_SEGMENT_OPEN_CLOSED] THEN
+    REPEAT GEN_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `closure(segment(a:real^N,b)) SUBSET segment[c,d]` THEN
+    CONJ_TAC THENL [SIMP_TAC[CLOSURE_MINIMAL_EQ; CLOSED_SEGMENT]; ALL_TAC] THEN
+    REWRITE_TAC[CLOSURE_SEGMENT] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[EMPTY_SUBSET]]);;
+
+let INTERIOR_SEGMENT = prove
+ (`(!a b:real^N. interior(segment[a,b]) =
+                 if 2 <= dimindex(:N) then {} else segment(a,b)) /\
+   (!a b:real^N. interior(segment(a,b)) =
+                 if 2 <= dimindex(:N) then {} else segment(a,b))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `2 <= dimindex(:N)` THEN ASM_REWRITE_TAC[] THENL
+   [MATCH_MP_TAC(SET_RULE `t SUBSET s /\ s = {} ==> s = {} /\ t = {}`) THEN
+    SIMP_TAC[SEGMENT_OPEN_SUBSET_CLOSED; SUBSET_INTERIOR] THEN
+    REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+    MATCH_MP_TAC EMPTY_INTERIOR_CONVEX_HULL THEN
+    REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY] THEN FIRST_ASSUM
+     (MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] LE_TRANS)) THEN
+    SIMP_TAC[CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN ARITH_TAC;
+    ASM_CASES_TAC `a:real^N = b` THEN
+    ASM_SIMP_TAC[SEGMENT_REFL; INTERIOR_EMPTY; EMPTY_INTERIOR_FINITE;
+                 FINITE_SING] THEN
+    SUBGOAL_THEN
+     `affine hull (segment[a,b]) = (:real^N) /\
+      affine hull (segment(a,b)) = (:real^N)`
+     (fun th -> ASM_SIMP_TAC[th; GSYM RELATIVE_INTERIOR_INTERIOR;
+                             RELATIVE_INTERIOR_SEGMENT]) THEN
+    ASM_REWRITE_TAC[AFFINE_HULL_SEGMENT] THEN
+    MATCH_MP_TAC AFFINE_INDEPENDENT_SPAN_GT THEN
+    REWRITE_TAC[AFFINE_INDEPENDENT_2] THEN
+    ASM_SIMP_TAC[CARD_CLAUSES; FINITE_RULES; IN_INSERT; NOT_IN_EMPTY] THEN
+    ASM_ARITH_TAC]);;
+
+let SEGMENT_EQ = prove
+ (`(!a b c d:real^N.
+        segment[a,b] = segment[c,d] <=> {a,b} = {c,d}) /\
+   (!a b c d:real^N.
+        ~(segment[a,b] = segment(c,d))) /\
+   (!a b c d:real^N.
+        ~(segment(a,b) = segment[c,d])) /\
+   (!a b c d:real^N.
+        segment(a,b) = segment(c,d) <=> a = b /\ c = d \/ {a,b} = {c,d})`,
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REPEAT GEN_TAC THEN EQ_TAC THENL
+     [DISCH_THEN(fun th -> MP_TAC th THEN
+       MP_TAC(AP_TERM `\s:real^N->bool. s DIFF relative_interior s` th)) THEN
+      REWRITE_TAC[RELATIVE_INTERIOR_SEGMENT] THEN
+      REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[SEGMENT_REFL]) THEN
+      SIMP_TAC[ENDS_IN_SEGMENT; open_segment; SET_RULE
+        `a IN s /\ b IN s ==> s DIFF (s DIFF {a,b}) = {a,b}`] THEN
+      ASM SET_TAC[SEGMENT_EQ_SING];
+      SIMP_TAC[SEGMENT_CONVEX_HULL]];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o AP_TERM `closed:(real^N->bool)->bool`) THEN
+    REWRITE_TAC[CLOSED_SEGMENT] THEN
+    REWRITE_TAC[GSYM CLOSURE_EQ; CLOSURE_SEGMENT] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+     [ASM SET_TAC[SEGMENT_EQ_EMPTY];
+      REWRITE_TAC[open_segment; ENDS_IN_SEGMENT; SET_RULE
+       `s = s DIFF {a,b} <=> ~(a IN s) /\ ~(b IN s)`]];
+    DISCH_TAC THEN CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+      REPEAT GEN_TAC THEN ASM_CASES_TAC `c:real^N = d` THEN
+    ASM_REWRITE_TAC[SEGMENT_EQ_EMPTY; SEGMENT_REFL] THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    CONV_TAC(BINOP_CONV SYM_CONV)THEN
+    ASM_CASES_TAC `a:real^N = b` THEN
+    ASM_REWRITE_TAC[SEGMENT_EQ_EMPTY; SEGMENT_REFL] THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ; SUBSET_SEGMENT_OPEN_CLOSED] THEN
+    ASM_REWRITE_TAC[SUBSET_ANTISYM_EQ]]);;
+
+let COMPACT_SEGMENT = prove
+ (`!a b. compact(segment[a,b])`,
+  SIMP_TAC[SEGMENT_CONVEX_HULL; COMPACT_CONVEX_HULL; FINITE_IMP_COMPACT;
+           FINITE_INSERT; FINITE_EMPTY]);;
+
+let BOUNDED_SEGMENT = prove
+ (`(!a b:real^N. bounded(segment[a,b])) /\
+   (!a b:real^N. bounded(segment(a,b)))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN
+  MATCH_MP_TAC(MESON[BOUNDED_SUBSET]
+   `bounded s /\ t SUBSET s ==> bounded s /\ bounded t`) THEN
+  REWRITE_TAC[SEGMENT_OPEN_SUBSET_CLOSED] THEN
+  MESON_TAC[COMPACT_IMP_BOUNDED; COMPACT_SEGMENT]);;
+
+let COLLINEAR_SEGMENT = prove
+ (`(!a b:real^N. collinear(segment[a,b])) /\
+   (!a b:real^N. collinear(segment(a,b)))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN
+  MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+   [REWRITE_TAC[COLLINEAR_AFFINE_HULL] THEN
+    MAP_EVERY EXISTS_TAC [`a:real^N`; `b:real^N`] THEN
+    REWRITE_TAC[SEGMENT_CONVEX_HULL; CONVEX_HULL_SUBSET_AFFINE_HULL];
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] COLLINEAR_SUBSET) THEN
+    REWRITE_TAC[SEGMENT_OPEN_SUBSET_CLOSED]]);;
+
+let UNION_SEGMENT = prove
+ (`!a b c:real^N.
+        b IN segment[a,c]
+        ==> segment[a,b] UNION segment[b,c] = segment[a,c]`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `c:real^N = a` THENL
+   [ASM_SIMP_TAC[SEGMENT_REFL; IN_SING; UNION_IDEMPOT];
+    ONCE_REWRITE_TAC[UNION_COMM] THEN REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+    DISCH_THEN(SUBST1_TAC o MATCH_MP CONVEX_HULL_EXCHANGE_UNION) THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+    REWRITE_TAC[IMAGE_CLAUSES; UNIONS_2] THEN
+    BINOP_TAC THEN AP_TERM_TAC THEN ASM SET_TAC[]]);;
+
+let INTER_SEGMENT = prove
+ (`!a b c:real^N.
+        b IN segment[a,c] \/ ~collinear{a,b,c}
+        ==> segment[a,b] INTER segment[b,c] = {b}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `c:real^N = a` THENL
+   [ASM_SIMP_TAC[SEGMENT_REFL; IN_SING; INTER_IDEMPOT; INSERT_AC; COLLINEAR_2];
+    ALL_TAC] THEN
+  DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL
+   [REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`{a:real^N,c}`; `b:real^N`; `{a:real^N}`; `{c:real^N}`]
+        CONVEX_HULL_EXCHANGE_INTER) THEN
+    ASM_REWRITE_TAC[AFFINE_INDEPENDENT_2] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[INSERT_AC]] THEN
+    DISCH_THEN SUBST1_TAC THEN
+    ASM_SIMP_TAC[SET_RULE `~(a = c) ==> {a} INTER {c} = {}`] THEN
+    REWRITE_TAC[CONVEX_HULL_SING];
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE
+     `~(s INTER t = {b})
+      ==> b IN s /\ b IN t
+          ==> ?a. ~(a = b) /\ a IN s /\ b IN s /\ a IN t /\ b IN t`)) THEN
+    ANTS_TAC THENL [REWRITE_TAC[ENDS_IN_SEGMENT]; ALL_TAC] THEN
+    REWRITE_TAC[GSYM BETWEEN_IN_SEGMENT; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `d:real^N` THEN STRIP_TAC THEN
+    REPEAT(FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP BETWEEN_IMP_COLLINEAR)) THEN
+    MATCH_MP_TAC COLLINEAR_3_TRANS THEN EXISTS_TAC `d:real^N` THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN SIMP_TAC[INSERT_AC]]);;
+
+let SUBSET_CONTINUOUS_IMAGE_SEGMENT_1 = prove
+ (`!f:real^N->real^1 a b.
+        f continuous_on segment[a,b]
+        ==> segment[f a,f b] SUBSET IMAGE f (segment[a,b])`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONNECTED_CONTINUOUS_IMAGE)) THEN
+  REWRITE_TAC[CONNECTED_SEGMENT] THEN
+  REWRITE_TAC[GSYM IS_INTERVAL_CONNECTED_1; IS_INTERVAL_CONVEX_1] THEN
+  REWRITE_TAC[CONVEX_CONTAINS_SEGMENT] THEN
+  MESON_TAC[IN_IMAGE; ENDS_IN_SEGMENT]);;
+
+let CONTINUOUS_INJECTIVE_IMAGE_SEGMENT_1 = prove
+ (`!f:real^N->real^1 a b.
+        f continuous_on segment[a,b] /\
+        (!x y. x IN segment[a,b] /\ y IN segment[a,b] /\ f x = f y ==> x = y)
+        ==> IMAGE f (segment[a,b]) = segment[f a,f b]`,
+  let lemma = prove
+   (`!a b c:real^1.
+      ~(a = b) /\ ~(a IN segment(c,b)) /\ ~(b IN segment(a,c))
+      ==> c IN segment[a,b]`,
+    REWRITE_TAC[FORALL_LIFT; SEGMENT_1; LIFT_DROP] THEN
+    REPEAT GEN_TAC THEN REWRITE_TAC[SEGMENT_1; LIFT_EQ] THEN
+    REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP]) THEN
+    ASM_REAL_ARITH_TAC) in
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[INJECTIVE_ON_LEFT_INVERSE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `g:real^1->real^N` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`f:real^N->real^1`; `g:real^1->real^N`;
+                 `segment[a:real^N,b]`]
+        CONTINUOUS_ON_INVERSE) THEN
+  ASM_REWRITE_TAC[COMPACT_SEGMENT] THEN DISCH_TAC THEN
+  REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+  MATCH_MP_TAC(TAUT `q /\ (q ==> p) ==> p /\ q`) THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[SUBSET_CONTINUOUS_IMAGE_SEGMENT_1]; DISCH_TAC] THEN
+  ASM_CASES_TAC `a:real^N = b` THEN
+  ASM_REWRITE_TAC[SEGMENT_REFL] THENL [SET_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN X_GEN_TAC `c:real^N` THEN
+  DISCH_TAC THEN MATCH_MP_TAC lemma THEN
+  MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[ENDS_IN_SEGMENT]; DISCH_TAC] THEN
+  ONCE_REWRITE_TAC[segment] THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_INSERT; NOT_IN_EMPTY] THEN
+  REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL [`f:real^N->real^1`; `c:real^N`; `b:real^N`]
+        SUBSET_CONTINUOUS_IMAGE_SEGMENT_1) THEN
+    SUBGOAL_THEN `segment[c:real^N,b] SUBSET segment[a,b]` ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[SUBSET_SEGMENT; ENDS_IN_SEGMENT]; ALL_TAC] THEN
+    REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; REWRITE_TAC[SUBSET]] THEN
+    DISCH_THEN(MP_TAC o SPEC `(f:real^N->real^1) a`) THEN
+    ASM_REWRITE_TAC[IN_IMAGE; NOT_EXISTS_THM] THEN
+    X_GEN_TAC `d:real^N` THEN ASM_CASES_TAC `d:real^N = a` THENL
+     [ASM_MESON_TAC[BETWEEN_ANTISYM; BETWEEN_IN_SEGMENT];
+      ASM_MESON_TAC[ENDS_IN_SEGMENT; SUBSET]];
+    MP_TAC(ISPECL [`f:real^N->real^1`; `a:real^N`; `c:real^N`]
+        SUBSET_CONTINUOUS_IMAGE_SEGMENT_1) THEN
+    SUBGOAL_THEN `segment[a:real^N,c] SUBSET segment[a,b]` ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[SUBSET_SEGMENT; ENDS_IN_SEGMENT]; ALL_TAC] THEN
+    REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; REWRITE_TAC[SUBSET]] THEN
+    DISCH_THEN(MP_TAC o SPEC `(f:real^N->real^1) b`) THEN
+    ASM_REWRITE_TAC[IN_IMAGE; NOT_EXISTS_THM] THEN
+    X_GEN_TAC `d:real^N` THEN ASM_CASES_TAC `d:real^N = b` THENL
+     [ASM_MESON_TAC[BETWEEN_ANTISYM; BETWEEN_IN_SEGMENT; BETWEEN_SYM];
+      ASM_MESON_TAC[ENDS_IN_SEGMENT; SUBSET]]]);;
+
+let CONTINUOUS_INJECTIVE_IMAGE_OPEN_SEGMENT_1 = prove
+ (`!f:real^N->real^1 a b.
+        f continuous_on segment[a,b] /\
+        (!x y. x IN segment[a,b] /\ y IN segment[a,b] /\ f x = f y ==> x = y)
+        ==> IMAGE f (segment(a,b)) = segment(f a,f b)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[segment] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP CONTINUOUS_INJECTIVE_IMAGE_SEGMENT_1) THEN
+  MP_TAC(ISPECL [`a:real^N`; `b:real^N`] ENDS_IN_SEGMENT) THEN
+  MP_TAC(ISPECL [`(f:real^N->real^1) a`; `(f:real^1->real^1) b`]
+    ENDS_IN_SEGMENT) THEN
+  ASM SET_TAC[]);;
+
+let CONTINUOUS_IVT_LOCAL_EXTREMUM = prove
+ (`!f:real^N->real^1 a b.
+        f continuous_on segment[a,b] /\ ~(a = b) /\ f(a) = f(b)
+         ==> ?z. z IN segment(a,b) /\
+                 ((!w. w IN segment[a,b] ==> drop(f w) <= drop(f z)) \/
+                  (!w. w IN segment[a,b] ==> drop(f z) <= drop(f w)))`,
+  REPEAT STRIP_TAC THEN
+  MAP_EVERY (MP_TAC o ISPECL
+            [`drop o (f:real^N->real^1)`; `segment[a:real^N,b]`])
+            [CONTINUOUS_ATTAINS_SUP; CONTINUOUS_ATTAINS_INF] THEN
+  ASM_REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX] THEN
+  REWRITE_TAC[COMPACT_SEGMENT; SEGMENT_EQ_EMPTY] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real^N` STRIP_ASSUME_TAC) THEN
+  ASM_CASES_TAC `(d:real^N) IN segment(a,b)` THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `c:real^N` STRIP_ASSUME_TAC) THEN
+  ASM_CASES_TAC `(c:real^N) IN segment(a,b)` THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  EXISTS_TAC `midpoint(a:real^N,b)` THEN
+  MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+   [ASM_REWRITE_TAC[MIDPOINT_IN_SEGMENT]; DISCH_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [CONJUNCT2 segment]) THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o
+    GEN_REWRITE_RULE (RAND_CONV o RAND_CONV) [segment])) THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_INSERT; NOT_IN_EMPTY] THEN
+  REPEAT(DISCH_THEN(DISJ_CASES_THEN SUBST_ALL_TAC)) THEN
+  FIRST_X_ASSUM SUBST_ALL_TAC THEN ASM_MESON_TAC[REAL_LE_ANTISYM; DROP_EQ]);;
+
+let FRONTIER_UNIONS_SUBSET_CLOSURE = prove
+ (`!f:(real^N->bool)->bool.
+        frontier(UNIONS f) SUBSET closure(UNIONS {frontier t | t IN f})`,
+  GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [frontier] THEN
+  REWRITE_TAC[SUBSET; IN_DIFF; CLOSURE_APPROACHABLE] THEN
+  X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN
+  ASM_REWRITE_TAC[EXISTS_IN_UNIONS; EXISTS_IN_GSPEC; RIGHT_EXISTS_AND_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real^N->bool` THEN
+  ASM_CASES_TAC `(t:real^N->bool) IN f` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `(x:real^N) IN t` THENL
+   [DISCH_THEN(K ALL_TAC) THEN EXISTS_TAC `x:real^N` THEN
+    ASM_REWRITE_TAC[frontier; DIST_REFL; IN_DIFF] THEN
+    ASM_SIMP_TAC[REWRITE_RULE[SUBSET] CLOSURE_SUBSET] THEN
+    FIRST_X_ASSUM(MP_TAC o check (is_neg o concl)) THEN
+    SPEC_TAC(`x:real^N`,`z:real^N`) THEN
+    REWRITE_TAC[CONTRAPOS_THM; GSYM SUBSET] THEN
+    MATCH_MP_TAC SUBSET_INTERIOR THEN ASM SET_TAC[];
+    DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`segment[x:real^N,y]`; `t:real^N->bool`]
+        CONNECTED_INTER_FRONTIER) THEN
+    SIMP_TAC[CONNECTED_SEGMENT; GSYM MEMBER_NOT_EMPTY; IN_INTER; IN_DIFF] THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[ENDS_IN_SEGMENT]; ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `z:real^N` THEN
+    ASM_MESON_TAC[DIST_IN_CLOSED_SEGMENT; DIST_SYM; REAL_LET_TRANS]]);;
+
+let CLOSURE_CONVEX_INTER_AFFINE = prove
+ (`!s t:real^N->bool.
+      convex s /\ affine t /\ ~(relative_interior s INTER t = {})
+      ==> closure(s INTER t) = closure(s) INTER t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[SUBSET_INTER] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC SUBSET_CLOSURE THEN SET_TAC[];
+    TRANS_TAC SUBSET_TRANS `closure t:real^N->bool` THEN
+    SIMP_TAC[SUBSET_CLOSURE; INTER_SUBSET] THEN
+    ASM_SIMP_TAC[CLOSURE_CLOSED; CLOSED_AFFINE; SUBSET_REFL];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `a:real^N` MP_TAC o
+        GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[IN_INTER] THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_SIMP_TAC[AFFINE_EQ_SUBSPACE] THEN STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP(REWRITE_RULE[SUBSET]
+    RELATIVE_INTERIOR_SUBSET)) THEN
+  REWRITE_TAC[SUBSET; IN_INTER] THEN X_GEN_TAC `x:real^N` THEN
+  STRIP_TAC THEN ASM_CASES_TAC `x:real^N = vec 0` THENL
+   [MATCH_MP_TAC(REWRITE_RULE[SUBSET] CLOSURE_SUBSET) THEN
+    ASM_REWRITE_TAC[IN_INTER];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `x IN closure(segment(vec 0:real^N,x))` MP_TAC THENL
+   [ASM_REWRITE_TAC[CLOSURE_SEGMENT; ENDS_IN_SEGMENT]; ALL_TAC] THEN
+  MATCH_MP_TAC(SET_RULE `s SUBSET t ==> x IN s ==> x IN t`) THEN
+  MATCH_MP_TAC SUBSET_CLOSURE THEN REWRITE_TAC[SUBSET_INTER] THEN
+  CONJ_TAC THENL
+   [TRANS_TAC SUBSET_TRANS `relative_interior s:real^N->bool` THEN
+    REWRITE_TAC[RELATIVE_INTERIOR_SUBSET] THEN
+    MATCH_MP_TAC IN_RELATIVE_INTERIOR_CLOSURE_CONVEX_SEGMENT THEN
+    ASM_REWRITE_TAC[];
+    ASM_SIMP_TAC[SUBSET; IN_SEGMENT; VECTOR_MUL_RZERO; VECTOR_ADD_LID;
+                 SUBSPACE_MUL; LEFT_IMP_EXISTS_THM]]);;
+
+let RELATIVE_FRONTIER_CONVEX_INTER_AFFINE = prove
+ (`!s t:real^N->bool.
+        convex s /\ affine t /\ ~(interior s INTER t = {})
+        ==> relative_frontier(s INTER t) = frontier s INTER t`,
+  SIMP_TAC[relative_frontier; RELATIVE_INTERIOR_CONVEX_INTER_AFFINE;
+           frontier] THEN
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `~(relative_interior s INTER t:real^N->bool = {})`
+  ASSUME_TAC THENL
+   [MP_TAC(ISPEC `s:real^N->bool` INTERIOR_SUBSET_RELATIVE_INTERIOR) THEN
+    ASM SET_TAC[];
+    ASM_SIMP_TAC[CLOSURE_CONVEX_INTER_AFFINE] THEN SET_TAC[]]);;
+
+let CONNECTED_COMPONENT_1_GEN = prove
+ (`!s a b:real^N.
+        dimindex(:N) = 1
+        ==> (connected_component s a b <=> segment[a,b] SUBSET s)`,
+  SIMP_TAC[connected_component; GSYM CONNECTED_CONVEX_1_GEN] THEN
+ MESON_TAC[CONVEX_CONTAINS_SEGMENT; SUBSET; CONVEX_SEGMENT;
+            ENDS_IN_SEGMENT]);;
+
+let CONNECTED_COMPONENT_1 = prove
+ (`!s a b:real^1. connected_component s a b <=> segment[a,b] SUBSET s`,
+  SIMP_TAC[CONNECTED_COMPONENT_1_GEN; DIMINDEX_1]);;
+
+(* ------------------------------------------------------------------------- *)
+(* An injective function into R is a homeomorphism and so an open map.       *)
+(* ------------------------------------------------------------------------- *)
+
+let INJECTIVE_INTO_1D_EQ_HOMEOMORPHISM = prove
+ (`!f:real^N->real^1 s.
+        f continuous_on s /\ path_connected s
+        ==>  ((!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) <=>
+              ?g. homeomorphism (s,IMAGE f s) (f,g))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[INJECTIVE_ON_LEFT_INVERSE];
+    REWRITE_TAC[homeomorphism] THEN MESON_TAC[]] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^1->real^N` THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[homeomorphism; FORALL_IN_IMAGE] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `is_interval (IMAGE (f:real^N->real^1) s)` ASSUME_TAC THENL
+   [REWRITE_TAC[IS_INTERVAL_PATH_CONNECTED_1] THEN
+    ASM_MESON_TAC[PATH_CONNECTED_CONTINUOUS_IMAGE];
+    ALL_TAC] THEN
+  REWRITE_TAC[continuous_on; IMP_CONJ; FORALL_IN_IMAGE] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  ABBREV_TAC `y = (f:real^N->real^1) x` THEN
+  ABBREV_TAC `t = IMAGE (f:real^N->real^1) s` THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `?a b d. a IN s /\ b IN s /\ &0 < d /\
+            ball(y,d) INTER t SUBSET segment[(f:real^N->real^1) a,f b]`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPECL [`t:real^1->bool`; `y:real^1`]
+        INTERVAL_CONTAINS_COMPACT_NEIGHBOURHOOD) THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    ASM_SIMP_TAC[INTERVAL_SUBSET_IS_INTERVAL] THEN
+    REWRITE_TAC[SET_RULE
+     `P /\ y IN s /\ (s = {} \/ a IN t /\ b IN t) /\ R <=>
+      a IN t /\ b IN t /\ P /\ y IN s /\ R`] THEN
+    REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+    EXPAND_TAC "t" THEN REWRITE_TAC[EXISTS_IN_IMAGE] THEN
+    REWRITE_TAC[SEGMENT_1; IN_INTERVAL_1] THEN
+    MESON_TAC[REAL_LE_TRANS];
+   FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [path_connected]) THEN
+   DISCH_THEN(MP_TAC o SPECL [`a:real^N`; `b:real^N`]) THEN
+   ASM_REWRITE_TAC[] THEN
+   DISCH_THEN(X_CHOOSE_THEN `p:real^1->real^N` STRIP_ASSUME_TAC) THEN
+   SUBGOAL_THEN
+    `(g:real^1->real^N) continuous_on segment[(f:real^N->real^1) a,f b]`
+   MP_TAC THENL
+    [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+     EXISTS_TAC `IMAGE (f:real^N->real^1) (path_image p)` THEN CONJ_TAC THENL
+      [MATCH_MP_TAC CONTINUOUS_ON_INVERSE THEN
+       ASM_SIMP_TAC[COMPACT_PATH_IMAGE] THEN CONJ_TAC THENL
+        [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ASM SET_TAC[]];
+       SUBGOAL_THEN `convex(IMAGE (f:real^N->real^1) (path_image p))`
+       MP_TAC THENL
+        [REWRITE_TAC[GSYM IS_INTERVAL_CONVEX_1; IS_INTERVAL_CONNECTED_1] THEN
+         MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN
+         ASM_SIMP_TAC[CONNECTED_PATH_IMAGE] THEN
+         ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+         REWRITE_TAC[CONVEX_CONTAINS_SEGMENT] THEN DISCH_THEN MATCH_MP_TAC THEN
+         CONJ_TAC THEN MATCH_MP_TAC FUN_IN_IMAGE THEN
+         ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; PATHFINISH_IN_PATH_IMAGE]]];
+     REWRITE_TAC[continuous_on] THEN
+     DISCH_THEN(MP_TAC o SPEC `y:real^1`) THEN ANTS_TAC THENL
+      [FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+       ASM_REWRITE_TAC[IN_INTER; CENTRE_IN_BALL] THEN ASM SET_TAC[];
+       ALL_TAC] THEN
+     DISCH_THEN(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` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+     X_GEN_TAC `x':real^N` THEN REPEAT STRIP_TAC THEN
+     FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+     FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+     ASM_REWRITE_TAC[IN_INTER; IN_BALL] THEN
+     ONCE_REWRITE_TAC[DIST_SYM] THEN ASM SET_TAC[]]]);;
+
+let INJECTIVE_INTO_1D_IMP_OPEN_MAP = prove
+ (`!f:real^N->real^1 s t.
+        f continuous_on s /\ path_connected s /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+        open_in (subtopology euclidean s) t
+        ==> open_in (subtopology euclidean (IMAGE f s)) (IMAGE f t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMEOMORPHISM_IMP_OPEN_MAP THEN
+  ASM_MESON_TAC[INJECTIVE_INTO_1D_EQ_HOMEOMORPHISM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Injective function on an interval is strictly increasing or decreasing.   *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_INJECTIVE_IFF_MONOTONIC = prove
+ (`!f:real^1->real^1 s.
+        f continuous_on s /\ is_interval s
+        ==> ((!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) <=>
+             (!x y. x IN s /\ y IN s /\ drop x < drop y
+                    ==> drop(f x) < drop(f y)) \/
+             (!x y. x IN s /\ y IN s /\ drop x < drop y
+                    ==> drop(f y) < drop(f x)))`,
+  let lemma = prove
+   (`!s f:real^1->real^1.
+        f continuous_on s /\ is_interval s /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> !u v w. u IN s /\ v IN s /\ w IN s /\
+                    drop u < drop v /\ drop v < drop w /\
+                    drop(f u) <= drop(f v) /\ drop(f w) <= drop(f v) ==> F`,
+    REWRITE_TAC[IS_INTERVAL_CONVEX_1; CONVEX_CONTAINS_SEGMENT] THEN
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`f:real^1->real^1`; `u:real^1`; `w:real^1`]
+        CONTINUOUS_INJECTIVE_IMAGE_SEGMENT_1) THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET]; ALL_TAC] THEN
+    REWRITE_TAC[EXTENSION] THEN
+    DISCH_THEN(MP_TAC o SPEC `(f:real^1->real^1) v`) THEN
+    MATCH_MP_TAC(TAUT `p /\ ~q ==> (p <=> q) ==> F`) THEN CONJ_TAC THENL
+     [MATCH_MP_TAC FUN_IN_IMAGE THEN ASM_REWRITE_TAC[SEGMENT_1] THEN
+      COND_CASES_TAC THENL
+       [ASM_SIMP_TAC[IN_INTERVAL_1; REAL_LT_IMP_LE]; ASM_REAL_ARITH_TAC];
+      REWRITE_TAC[SEGMENT_1] THEN COND_CASES_TAC THEN
+      ASM_REWRITE_TAC[IN_INTERVAL_1] THEN DISCH_TAC THENL
+       [SUBGOAL_THEN `drop(f(w:real^1)) = drop(f v)` ASSUME_TAC THENL
+         [ASM_REAL_ARITH_TAC; ASM_MESON_TAC[DROP_EQ; REAL_LT_REFL]];
+        SUBGOAL_THEN `drop(f(u:real^1)) = drop(f v)` ASSUME_TAC THENL
+         [ASM_REAL_ARITH_TAC; ASM_MESON_TAC[DROP_EQ; REAL_LT_REFL]]]])
+  and tac s1 s2 =
+   let [l1;l2] = map (map (fun x -> mk_var(x,`:real^1`)) o explode) [s1;s2] in
+   REPEAT(FIRST_X_ASSUM(fun th ->
+     MP_TAC(ISPECL l1 th) THEN MP_TAC(ISPECL l2 th))) THEN
+   ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC in
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[GSYM DROP_EQ] THEN
+    MESON_TAC[REAL_LT_TOTAL; REAL_LT_REFL]] THEN
+  DISCH_TAC THEN MATCH_MP_TAC(MESON[]
+   `(!a b c d. ~(~P a b /\ ~Q c d)) ==> (!x y. P x y) \/ (!x y. Q x y)`) THEN
+  MAP_EVERY X_GEN_TAC [`a:real^1`; `b:real^1`; `c:real^1`; `d:real^1`] THEN
+  REWRITE_TAC[NOT_IMP; REAL_NOT_LT] THEN STRIP_TAC THEN
+  REPEAT
+   (FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REAL_LE_LT]) THEN
+    REWRITE_TAC[DROP_EQ] THEN STRIP_TAC THENL
+     [ALL_TAC; ASM_MESON_TAC[REAL_LT_REFL]]) THEN
+  MP_TAC(ISPEC `s:real^1->bool` lemma) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(fun th ->
+   MP_TAC(SPEC `(--) o (f:real^1->real^1)` th) THEN
+   MP_TAC(SPEC `f:real^1->real^1` th)) THEN
+  ASM_REWRITE_TAC[o_THM; VECTOR_ARITH `--x:real^N = --y <=> x = y`] THEN
+  DISCH_TAC THEN REWRITE_TAC[NOT_IMP; DROP_NEG; REAL_LE_NEG2] THEN
+  CONJ_TAC THENL
+   [ASM_MESON_TAC[CONTINUOUS_ON_COMPOSE;LINEAR_CONTINUOUS_ON; LINEAR_NEGATION];
+    DISCH_TAC] THEN
+  ASM_CASES_TAC `drop d <= drop a` THENL [tac "cab" "cdb"; ALL_TAC] THEN
+  ASM_CASES_TAC `drop b <= drop c` THENL [tac "abd" "acd"; ALL_TAC] THEN
+  ASM_CASES_TAC `c:real^1 = a /\ d:real^1 = b` THENL
+   [ASM_MESON_TAC[REAL_LT_ANTISYM]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[]
+   `~(c = a /\ d = b)
+    ==> (c = a ==> d = b) /\ (d = b ==> c = a) /\
+        (~(c = a) /\ ~(d = b) ==> F) ==> F`)) THEN
+  REPEAT CONJ_TAC THENL
+   [DISCH_THEN SUBST_ALL_TAC THEN SIMP_TAC[GSYM DROP_EQ] THEN tac "adb" "abd";
+    DISCH_THEN SUBST_ALL_TAC THEN SIMP_TAC[GSYM DROP_EQ] THEN tac "acb" "cab";
+    REWRITE_TAC[GSYM DROP_EQ] THEN STRIP_TAC] THEN
+  ASM_CASES_TAC `drop a <= drop c` THENL [tac "acb" "acd"; tac "cab" "cad"]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some uncountability results for relevant sets.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let CARD_EQ_SEGMENT = prove
+ (`(!a b:real^N. ~(a = b) ==> segment[a,b] =_c (:real)) /\
+   (!a b:real^N. ~(a = b) ==> segment(a,b) =_c (:real))`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[SEGMENT_IMAGE_INTERVAL] THENL
+   [TRANS_TAC CARD_EQ_TRANS `interval[vec 0:real^1,vec 1]`;
+    TRANS_TAC CARD_EQ_TRANS `interval(vec 0:real^1,vec 1)`] THEN
+  SIMP_TAC[CARD_EQ_INTERVAL; UNIT_INTERVAL_NONEMPTY] THEN
+  MATCH_MP_TAC CARD_EQ_IMAGE THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ; VECTOR_ARITH
+   `(&1 - x) % a + x % b:real^N = (&1 - y) % a + y % b <=>
+    (x - y) % (a - b) = vec 0`] THEN
+  SIMP_TAC[REAL_SUB_0; DROP_EQ]);;
+
+let UNCOUNTABLE_SEGMENT = prove
+ (`(!a b:real^N. ~(a = b) ==> ~COUNTABLE(segment[a,b])) /\
+   (!a b:real^N. ~(a = b) ==> ~COUNTABLE(segment(a,b)))`,
+  SIMP_TAC[CARD_EQ_REAL_IMP_UNCOUNTABLE; CARD_EQ_SEGMENT]);;
+
+let CARD_EQ_PATH_CONNECTED = prove
+ (`!s a b:real^N.
+        path_connected s /\ a IN s /\ b IN s /\ ~(a = b) ==> s =_c (:real)`,
+  MESON_TAC[CARD_EQ_CONNECTED; PATH_CONNECTED_IMP_CONNECTED]);;
+
+let UNCOUNTABLE_PATH_CONNECTED = prove
+ (`!s a b:real^N.
+        path_connected s /\ a IN s /\ b IN s /\ ~(a = b) ==> ~COUNTABLE s`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC CARD_EQ_REAL_IMP_UNCOUNTABLE THEN
+  MATCH_MP_TAC CARD_EQ_PATH_CONNECTED THEN
+  ASM_MESON_TAC[]);;
+
+let CARD_EQ_CONVEX = prove
+ (`!s a b:real^N.
+        convex s /\ a IN s /\ b IN s /\ ~(a = b) ==> s =_c (:real)`,
+  MESON_TAC[CARD_EQ_PATH_CONNECTED; CONVEX_IMP_PATH_CONNECTED]);;
+
+let UNCOUNTABLE_CONVEX = prove
+ (`!s a b:real^N.
+        convex s /\ a IN s /\ b IN s /\ ~(a = b) ==> ~COUNTABLE s`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC CARD_EQ_REAL_IMP_UNCOUNTABLE THEN
+  MATCH_MP_TAC CARD_EQ_CONVEX THEN
+  ASM_MESON_TAC[]);;
+
+let CARD_EQ_NONEMPTY_INTERIOR = prove
+ (`!s:real^N->bool. ~(interior s = {}) ==> s =_c (:real)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM CARD_LE_ANTISYM] THEN CONJ_TAC THENL
+   [TRANS_TAC CARD_LE_TRANS `(:real^N)` THEN
+    SIMP_TAC[CARD_LE_UNIV; CARD_EQ_IMP_LE; CARD_EQ_EUCLIDEAN];
+    TRANS_TAC CARD_LE_TRANS `interior(s:real^N->bool)` THEN
+    SIMP_TAC[CARD_LE_SUBSET; INTERIOR_SUBSET] THEN
+    MATCH_MP_TAC(ONCE_REWRITE_RULE[CARD_EQ_SYM] CARD_EQ_IMP_LE) THEN
+    MATCH_MP_TAC CARD_EQ_OPEN THEN ASM_REWRITE_TAC[OPEN_INTERIOR]]);;
+
+let UNCOUNTABLE_NONEMPTY_INTERIOR = prove
+ (`!s:real^N->bool. ~(interior s = {}) ==> ~(COUNTABLE s)`,
+  SIMP_TAC[CARD_EQ_NONEMPTY_INTERIOR; CARD_EQ_REAL_IMP_UNCOUNTABLE]);;
+
+let COUNTABLE_EMPTY_INTERIOR = prove
+ (`!s:real^N->bool. COUNTABLE s ==> interior s = {}`,
+  MESON_TAC[UNCOUNTABLE_NONEMPTY_INTERIOR]);;
+
+let FINITE_EMPTY_INTERIOR = prove
+ (`!s:real^N->bool. FINITE s ==> interior s = {}`,
+  SIMP_TAC[COUNTABLE_EMPTY_INTERIOR; FINITE_IMP_COUNTABLE]);;
+
+let [CONNECTED_FINITE_IFF_SING;
+     CONNECTED_FINITE_IFF_COUNTABLE;
+     CONNECTED_INFINITE_IFF_CARD_EQ] = (CONJUNCTS o prove)
+ (`(!s:real^N->bool. connected s ==> (FINITE s <=> s = {} \/ ?a. s = {a})) /\
+   (!s:real^N->bool. connected s ==> (FINITE s <=> COUNTABLE s)) /\
+   (!s:real^N->bool. connected s ==> (INFINITE s <=> s =_c (:real)))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN GEN_TAC THEN
+  ASM_CASES_TAC `connected(s:real^N->bool)` THEN
+  ASM_REWRITE_TAC[INFINITE] THEN MATCH_MP_TAC(TAUT
+   `(f ==> c) /\ (r ==> ~c) /\ (s ==> f) /\ (~s ==> r)
+    ==> (f <=> s) /\ (f <=> c) /\ (~f <=> r)`) THEN
+  REWRITE_TAC[FINITE_IMP_COUNTABLE] THEN
+  REPEAT CONJ_TAC THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[CARD_EQ_REAL_IMP_UNCOUNTABLE; FINITE_INSERT; FINITE_EMPTY] THEN
+  MATCH_MP_TAC CARD_EQ_CONNECTED THEN ASM SET_TAC[]);;
+
+let CLOSED_AS_FRONTIER_OF_SUBSET = prove
+ (`!s:real^N->bool. closed s <=> ?t. t SUBSET s /\ s = frontier t`,
+  GEN_TAC THEN EQ_TAC THENL [ALL_TAC; MESON_TAC[FRONTIER_CLOSED]] THEN
+  DISCH_TAC THEN MP_TAC(ISPEC `s:real^N->bool` SEPARABLE) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real^N->bool` THEN
+  SIMP_TAC[frontier] THEN STRIP_TAC THEN MATCH_MP_TAC(SET_RULE
+   `s SUBSET c /\ c SUBSET s /\ i = {} ==> s = c DIFF i`) THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[SUBSET_CLOSURE; CLOSURE_CLOSED];
+    ASM_MESON_TAC[UNCOUNTABLE_NONEMPTY_INTERIOR]]);;
+
+let CLOSED_AS_FRONTIER = prove
+ (`!s:real^N->bool. closed s <=> ?t. s = frontier t`,
+  GEN_TAC THEN EQ_TAC THENL
+   [MESON_TAC[CLOSED_AS_FRONTIER_OF_SUBSET]; MESON_TAC[FRONTIER_CLOSED]]);;
+
+let CARD_EQ_CLOSED = prove
+ (`!s:real^N->bool. closed s ==> s <=_c (:num) \/ s =_c (:real)`,
+  let slemma = prove
+   (`!s:real^N->bool.
+          ~COUNTABLE s
+          ==> ?x y. ~(x = y) /\ x IN s /\ y IN s /\
+                    x condensation_point_of s /\
+                    y condensation_point_of s`,
+    REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP CARD_EQ_CONDENSATION_POINTS_IN_SET) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP CARD_INFINITE_CONG) THEN
+    REWRITE_TAC[INFINITE] THEN
+    MATCH_MP_TAC(TAUT `q /\ (p ==> s) ==> (p <=> q) ==> s`) THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[FINITE_IMP_COUNTABLE]; ALL_TAC] THEN
+    DISCH_TAC THEN
+    MP_TAC(ISPECL [`2`; `{x:real^N | x IN s /\ x condensation_point_of s}`]
+          CHOOSE_SUBSET_STRONG) THEN
+    ASM_REWRITE_TAC[HAS_SIZE_CONV `s HAS_SIZE 2`; RIGHT_AND_EXISTS_THM] THEN
+    DISCH_THEN(CHOOSE_THEN MP_TAC) THEN REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    STRIP_TAC THEN FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[FORALL_IN_INSERT; NOT_IN_EMPTY]) THEN
+    ASM_REWRITE_TAC[]) in
+  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[GSYM COUNTABLE_ALT] THEN
+  ASM_CASES_TAC `COUNTABLE(s:real^N->bool)` THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `!n t:real^N->bool.
+        closed t /\ ~COUNTABLE t
+        ==> ?l r. (compact l /\ ~COUNTABLE l) /\ (compact r /\ ~COUNTABLE r) /\
+                  l INTER r = {} /\ l SUBSET t /\ r SUBSET t /\
+                  diameter l <= inv(&2 pow n) /\
+                  diameter r <= inv(&2 pow n)`
+  MP_TAC THENL
+   [REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
+     (MP_TAC o MATCH_MP slemma)) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC
+     [`t INTER cball(a:real^N,min (inv(&2 pow (SUC n))) (dist(a,b) / &3))`;
+     `t INTER cball(b:real^N,min (inv(&2 pow (SUC n))) (dist(a,b) / &3))`] THEN
+    ASM_SIMP_TAC[CLOSED_INTER_COMPACT; COMPACT_CBALL] THEN
+    REPEAT CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I
+       [CONDENSATION_POINT_INFINITE_CBALL]) THEN
+      REWRITE_TAC[REAL_LT_MIN; REAL_LT_INV_EQ; REAL_LT_POW2] THEN
+      UNDISCH_TAC `~(a:real^N = b)` THEN CONV_TAC NORM_ARITH;
+      FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I
+       [CONDENSATION_POINT_INFINITE_CBALL]) THEN
+      REWRITE_TAC[REAL_LT_MIN; REAL_LT_INV_EQ; REAL_LT_POW2] THEN
+      UNDISCH_TAC `~(a:real^N = b)` THEN CONV_TAC NORM_ARITH;
+      MATCH_MP_TAC(SET_RULE
+       `(!x. ~(x IN t /\ x IN u)) ==> (s INTER t) INTER (s INTER u) = {}`) THEN
+      REWRITE_TAC[IN_CBALL; REAL_LE_MIN] THEN
+      UNDISCH_TAC `~(a:real^N = b)` THEN CONV_TAC NORM_ARITH;
+      SET_TAC[];
+      SET_TAC[];
+      MATCH_MP_TAC DIAMETER_LE THEN
+      SIMP_TAC[REAL_LE_INV_EQ; REAL_LT_IMP_LE; REAL_LT_POW2] THEN
+      REWRITE_TAC[IN_INTER; IN_CBALL; REAL_LE_MIN; real_pow; REAL_INV_MUL] THEN
+      CONV_TAC NORM_ARITH;
+      MATCH_MP_TAC DIAMETER_LE THEN
+      SIMP_TAC[REAL_LE_INV_EQ; REAL_LT_IMP_LE; REAL_LT_POW2] THEN
+      REWRITE_TAC[IN_INTER; IN_CBALL; REAL_LE_MIN; real_pow; REAL_INV_MUL] THEN
+      CONV_TAC NORM_ARITH];
+    REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC
+     [`l:num->(real^N->bool)->(real^N->bool)`;
+      `r:num->(real^N->bool)->(real^N->bool)`] THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN
+     `!b. ?x:num->real^N->bool.
+          (x 0 = s) /\ (!n. x(SUC n) = if b(n) then r n (x n) else l n (x n))`
+    MP_TAC THENL
+     [GEN_TAC THEN
+      W(ACCEPT_TAC o prove_recursive_functions_exist num_RECURSION o
+        snd o dest_exists o snd);
+      REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM; FORALL_AND_THM]] THEN
+    X_GEN_TAC `x:(num->bool)->num->real^N->bool` THEN STRIP_TAC THEN
+    REWRITE_TAC[GSYM CARD_LE_ANTISYM] THEN CONJ_TAC THENL
+     [TRANS_TAC CARD_LE_TRANS `(:real^N)` THEN
+      SIMP_TAC[CARD_LE_UNIV; CARD_EQ_EUCLIDEAN; CARD_EQ_IMP_LE];
+      TRANS_TAC CARD_LE_TRANS `(:num->bool)` THEN
+      SIMP_TAC[CARD_EQ_REAL; CARD_EQ_IMP_LE]] THEN
+    REWRITE_TAC[le_c; IN_UNIV] THEN
+    SUBGOAL_THEN
+     `!b n. closed((x:(num->bool)->num->real^N->bool) b n) /\
+            ~COUNTABLE(x b n)`
+    MP_TAC THENL
+     [GEN_TAC THEN INDUCT_TAC THEN ASM_SIMP_TAC[] THEN
+      COND_CASES_TAC THEN ASM_SIMP_TAC[COMPACT_IMP_CLOSED];
+      REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC] THEN
+    MP_TAC(GEN `b:num->bool` (ISPEC `(x:(num->bool)->num->real^N->bool) b`
+          DECREASING_CLOSED_NEST_SING)) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP MONO_FORALL) THEN ANTS_TAC THENL
+     [ASM_SIMP_TAC[FORALL_AND_THM] THEN REPEAT CONJ_TAC THENL
+       [ASM_MESON_TAC[COUNTABLE_EMPTY];
+        GEN_TAC THEN MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN
+        REWRITE_TAC[SUBSET_REFL] THEN ASM SET_TAC[];
+        MAP_EVERY X_GEN_TAC [`b:num->bool`; `e:real`] THEN DISCH_TAC THEN
+        MP_TAC(ISPECL [`inv(&2)`; `e:real`] REAL_ARCH_POW_INV) THEN
+        ASM_REWRITE_TAC[REAL_POW_INV] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+        DISCH_THEN(X_CHOOSE_TAC `m:num`) THEN
+        EXISTS_TAC `SUC m` THEN ASM_SIMP_TAC[] THEN
+        REPEAT GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+        DISCH_THEN(MP_TAC o MATCH_MP
+         (REWRITE_RULE[TAUT `p /\ q /\ r ==> s <=> q /\ r ==> p ==> s`]
+          DIAMETER_BOUNDED_BOUND)) THEN
+        ASM_SIMP_TAC[COMPACT_IMP_BOUNDED] THEN
+        UNDISCH_TAC `inv(&2 pow m) < e` THEN MATCH_MP_TAC(NORM_ARITH
+         `d <= i ==> i < e ==> norm(x - y) <= d ==> dist(x:real^N,y) < e`) THEN
+        ASM_SIMP_TAC[]];
+      ALL_TAC] THEN
+    REWRITE_TAC[SKOLEM_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `f:(num->bool)->real^N` THEN STRIP_TAC THEN CONJ_TAC THENL
+     [X_GEN_TAC `b:num->bool` THEN
+      REWRITE_TAC[SET_RULE `x IN s <=> {x} SUBSET s`] THEN
+      FIRST_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [GSYM th]) THEN
+      REWRITE_TAC[SUBSET; INTERS_GSPEC; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+      ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+      SIMP_TAC[FORALL_UNWIND_THM2] THEN GEN_TAC THEN ASM SET_TAC[];
+      MAP_EVERY X_GEN_TAC [`b:num->bool`; `c:num->bool`] THEN
+      ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+      GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [FUN_EQ_THM] THEN
+      REWRITE_TAC[NOT_FORALL_THM] THEN ONCE_REWRITE_TAC[num_WOP] THEN
+      SIMP_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `k:num` STRIP_ASSUME_TAC) THEN
+      MATCH_MP_TAC(SET_RULE
+       `!f g. INTERS f = {a} /\ INTERS g = {b} /\
+              (?s t. s IN f /\ t IN g /\ s INTER t = {})
+              ==> ~(a = b)`) THEN
+      EXISTS_TAC `{t | ?n. t = (x:(num->bool)->num->real^N->bool) b n}` THEN
+      EXISTS_TAC `{t | ?n. t = (x:(num->bool)->num->real^N->bool) c n}` THEN
+      ASM_REWRITE_TAC[IN_ELIM_THM] THEN
+      EXISTS_TAC `(x:(num->bool)->num->real^N->bool) b (SUC k)` THEN
+      EXISTS_TAC `(x:(num->bool)->num->real^N->bool) c (SUC k)` THEN
+      REPEAT(CONJ_TAC THENL [MESON_TAC[]; ALL_TAC]) THEN ASM_SIMP_TAC[] THEN
+      SUBGOAL_THEN
+       `!i. i <= k ==> (x:(num->bool)->num->real^N->bool) b i = x c i`
+      MP_TAC THENL
+       [INDUCT_TAC THEN ASM_SIMP_TAC[LE_SUC_LT; LT_IMP_LE];
+        DISCH_THEN(MP_TAC o SPEC `k:num`)] THEN
+      REWRITE_TAC[LE_REFL] THEN DISCH_THEN SUBST1_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+       [TAUT `~(p <=> q) <=> (q <=> ~p)`]) THEN
+      REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+      ASM_MESON_TAC[INTER_COMM]]]);;
+
+let CONDENSATION_POINTS_EQ_EMPTY,CARD_EQ_CONDENSATION_POINTS =
+ (CONJ_PAIR o prove)
+ (`(!s:real^N->bool.
+        {x | x condensation_point_of s} = {} <=> COUNTABLE s) /\
+   (!s:real^N->bool.
+        {x | x condensation_point_of s} =_c (:real) <=> ~(COUNTABLE s))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN GEN_TAC THEN MATCH_MP_TAC(TAUT
+   `(r ==> p) /\ (~r ==> q) /\ (p ==> ~q)
+    ==> (p <=> r) /\ (q <=> ~r)`) THEN
+  REPEAT CONJ_TAC THENL
+   [DISCH_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY] THEN
+    REWRITE_TAC[condensation_point_of] THEN
+    ASM_MESON_TAC[COUNTABLE_SUBSET; INTER_SUBSET; IN_UNIV; OPEN_UNIV];
+    DISCH_TAC THEN MATCH_MP_TAC(REWRITE_RULE
+     [TAUT `p ==> q \/ r <=> p /\ ~q ==> r`] CARD_EQ_CLOSED) THEN
+    REWRITE_TAC[CLOSED_CONDENSATION_POINTS; GSYM COUNTABLE_ALT] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP CARD_EQ_CONDENSATION_POINTS_IN_SET) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP CARD_COUNTABLE_CONG) THEN
+    ASM_REWRITE_TAC[CONTRAPOS_THM] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] COUNTABLE_SUBSET) THEN SET_TAC[];
+    DISCH_THEN SUBST1_TAC THEN
+    DISCH_THEN(MP_TAC o MATCH_MP CARD_FINITE_CONG) THEN
+    REWRITE_TAC[FINITE_EMPTY; GSYM INFINITE; real_INFINITE]]);;
+
+let UNCOUNTABLE_HAS_CONDENSATION_POINT = prove
+ (`!s:real^N->bool. ~COUNTABLE s ==> ?x. x condensation_point_of s`,
+  REWRITE_TAC[GSYM CONDENSATION_POINTS_EQ_EMPTY] THEN SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Density of sets with small complement, including irrationals.             *)
+(* ------------------------------------------------------------------------- *)
+
+let COSMALL_APPROXIMATION = prove
+ (`!s. ((:real) DIFF s) <_c (:real)
+       ==> !x e. &0 < e ==> ?y. y IN s /\ abs(y - x) < e`,
+  let lemma = prove
+   (`!s. ((:real^1) DIFF s) <_c (:real)
+         ==> !x e. &0 < e ==> ?y. y IN s /\ norm(y - x) < e`,
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC(SET_RULE
+      `~({x | P x} SUBSET UNIV DIFF s) ==> ?x. x IN s /\ P x`) THEN
+    MP_TAC(ISPEC `ball(x:real^1,e)` CARD_EQ_OPEN) THEN
+    ASM_REWRITE_TAC[OPEN_BALL; BALL_EQ_EMPTY; REAL_NOT_LE] THEN DISCH_TAC THEN
+    DISCH_THEN(MP_TAC o MATCH_MP CARD_LE_SUBSET) THEN
+    REWRITE_TAC[CARD_NOT_LE] THEN
+    REWRITE_TAC[GSYM(ONCE_REWRITE_RULE[DIST_SYM] dist); GSYM ball] THEN
+    TRANS_TAC CARD_LTE_TRANS `(:real)` THEN
+    ASM_SIMP_TAC[ONCE_REWRITE_RULE[CARD_EQ_SYM] CARD_EQ_IMP_LE]) in
+  REWRITE_TAC[FORALL_DROP_IMAGE; FORALL_DROP; EXISTS_DROP] THEN
+  REWRITE_TAC[GSYM IMAGE_DROP_UNIV; GSYM DROP_SUB; GSYM ABS_DROP] THEN
+  REWRITE_TAC[DROP_IN_IMAGE_DROP] THEN REWRITE_TAC[GSYM FORALL_DROP] THEN
+  SIMP_TAC[GSYM IMAGE_DIFF_INJ; DROP_EQ] THEN GEN_TAC THEN
+  DISCH_TAC THEN MATCH_MP_TAC lemma THEN POP_ASSUM MP_TAC THEN
+  MATCH_MP_TAC EQ_IMP THEN MATCH_MP_TAC CARD_LT_CONG THEN
+  REWRITE_TAC[IMAGE_DROP_UNIV; CARD_EQ_REFL] THEN
+  MATCH_MP_TAC CARD_EQ_IMAGE THEN SIMP_TAC[DROP_EQ]);;
+
+let COCOUNTABLE_APPROXIMATION = prove
+ (`!s. COUNTABLE((:real) DIFF s)
+       ==> !x e. &0 < e ==> ?y. y IN s /\ abs(y - x) < e`,
+  GEN_TAC THEN REWRITE_TAC[COUNTABLE; ge_c] THEN DISCH_TAC THEN
+  MATCH_MP_TAC COSMALL_APPROXIMATION THEN
+  TRANS_TAC CARD_LET_TRANS `(:num)` THEN ASM_REWRITE_TAC[] THEN
+  TRANS_TAC CARD_LTE_TRANS `(:num->bool)` THEN SIMP_TAC[CANTOR_THM_UNIV] THEN
+  MATCH_MP_TAC CARD_EQ_IMP_LE THEN ONCE_REWRITE_TAC[CARD_EQ_SYM] THEN
+  REWRITE_TAC[CARD_EQ_REAL]);;
+
+let IRRATIONAL_APPROXIMATION = prove
+ (`!x e. &0 < e ==> ?y. ~(rational y) /\ abs(y - x) < e`,
+  REWRITE_TAC[SET_RULE `~rational y <=> y IN UNIV DIFF rational`] THEN
+  MATCH_MP_TAC COCOUNTABLE_APPROXIMATION THEN
+  REWRITE_TAC[SET_RULE `UNIV DIFF (UNIV DIFF s) = s`; COUNTABLE_RATIONAL]);;
+
+let OPEN_SET_COSMALL_COORDINATES = prove
+ (`!P. (!i. 1 <= i /\ i <= dimindex(:N)
+            ==> (:real) DIFF {x | P i x} <_c (:real))
+       ==> !s:real^N->bool.
+              open s /\ ~(s = {})
+              ==> ?x. x IN s /\ !i. 1 <= i /\ i <= dimindex(:N) ==> P i (x$i)`,
+  REPEAT STRIP_TAC 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
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `a:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `!i. 1 <= i /\ i <= dimindex(:N)
+        ==> ?y:real. P i y /\ abs(y - (a:real^N)$i) < d / &(dimindex(:N))`
+  MP_TAC THENL
+   [X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP COSMALL_APPROXIMATION) THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN DISCH_THEN MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1];
+    REWRITE_TAC[LAMBDA_SKOLEM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    REPEAT STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    REWRITE_TAC[IN_CBALL; dist] 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_BOUND_GEN THEN REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+    REWRITE_TAC[VECTOR_SUB_COMPONENT; NUMSEG_EMPTY; NOT_LT; DIMINDEX_GE_1] THEN
+    ONCE_REWRITE_TAC[REAL_ABS_SUB] THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; CARD_NUMSEG_1]]);;
+
+let OPEN_SET_COCOUNTABLE_COORDINATES = prove
+ (`!P. (!i. 1 <= i /\ i <= dimindex(:N)
+            ==> COUNTABLE((:real) DIFF {x | P i x}))
+       ==> !s:real^N->bool.
+              open s /\ ~(s = {})
+              ==> ?x. x IN s /\ !i. 1 <= i /\ i <= dimindex(:N) ==> P i (x$i)`,
+  GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC OPEN_SET_COSMALL_COORDINATES THEN
+  REPEAT STRIP_TAC THEN
+  TRANS_TAC CARD_LET_TRANS `(:num)` THEN ASM_SIMP_TAC[GSYM COUNTABLE_ALT] THEN
+  TRANS_TAC CARD_LTE_TRANS `(:num->bool)` THEN SIMP_TAC[CANTOR_THM_UNIV] THEN
+  MATCH_MP_TAC CARD_EQ_IMP_LE THEN ONCE_REWRITE_TAC[CARD_EQ_SYM] THEN
+  REWRITE_TAC[CARD_EQ_REAL]);;
+
+let OPEN_SET_IRRATIONAL_COORDINATES = prove
+ (`!s:real^N->bool.
+        open s /\ ~(s = {})
+        ==> ?x. x IN s /\ !i. 1 <= i /\ i <= dimindex(:N) ==> ~rational(x$i)`,
+  MATCH_MP_TAC OPEN_SET_COCOUNTABLE_COORDINATES THEN
+  REWRITE_TAC[SET_RULE `UNIV DIFF {x | ~P x} = P`; COUNTABLE_RATIONAL]);;
+
+let CLOSURE_COSMALL_COORDINATES = prove
+ (`!P. (!i. 1 <= i /\ i <= dimindex(:N)
+            ==> (:real) DIFF {x | P i x} <_c (:real))
+       ==> closure {x | !i. 1 <= i /\ i <= dimindex (:N) ==> P i (x$i)} =
+           (:real^N)`,
+  GEN_TAC THEN DISCH_TAC THEN
+  REWRITE_TAC[CLOSURE_APPROACHABLE; IN_UNIV; EXTENSION; IN_ELIM_THM] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `e:real`] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP OPEN_SET_COSMALL_COORDINATES) THEN
+  DISCH_THEN(MP_TAC o SPEC `ball(x:real^N,e)`) THEN
+  ASM_REWRITE_TAC[OPEN_BALL; BALL_EQ_EMPTY; REAL_NOT_LE; IN_BALL] THEN
+  MESON_TAC[DIST_SYM]);;
+
+let CLOSURE_COCOUNTABLE_COORDINATES = prove
+ (`!P. (!i. 1 <= i /\ i <= dimindex(:N)
+            ==> COUNTABLE((:real) DIFF {x | P i x}))
+       ==> closure {x | !i. 1 <= i /\ i <= dimindex (:N) ==> P i (x$i)} =
+           (:real^N)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSURE_COSMALL_COORDINATES THEN
+  REPEAT STRIP_TAC THEN
+  TRANS_TAC CARD_LET_TRANS `(:num)` THEN ASM_SIMP_TAC[GSYM COUNTABLE_ALT] THEN
+  TRANS_TAC CARD_LTE_TRANS `(:num->bool)` THEN SIMP_TAC[CANTOR_THM_UNIV] THEN
+  MATCH_MP_TAC CARD_EQ_IMP_LE THEN ONCE_REWRITE_TAC[CARD_EQ_SYM] THEN
+  REWRITE_TAC[CARD_EQ_REAL]);;
+
+let CLOSURE_IRRATIONAL_COORDINATES = prove
+ (`closure {x | !i. 1 <= i /\ i <= dimindex (:N) ==> ~rational(x$i)} =
+   (:real^N)`,
+  MATCH_MP_TAC CLOSURE_COCOUNTABLE_COORDINATES THEN
+  REWRITE_TAC[SET_RULE `UNIV DIFF {x | ~P x} = P`; COUNTABLE_RATIONAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Every path between distinct points contains an arc, and hence             *)
+(* that path connection is equivalent to arcwise connection, for distinct    *)
+(* points. The proof is based on Whyburn's "Topological Analysis".           *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMEOMORPHIC_MONOTONE_IMAGE_INTERVAL = prove
+ (`!f:real^1->real^N.
+       f continuous_on interval[vec 0,vec 1] /\
+       (!y. connected {x | x IN interval[vec 0,vec 1] /\ f x = y}) /\
+       ~(f(vec 1) = f(vec 0))
+       ==> (IMAGE f (interval[vec 0,vec 1])) homeomorphic
+           (interval[vec 0:real^1,vec 1])`,
+  let closure_dyadic_rationals_in_convex_set_pos_1 = prove
+   (`!s. convex s /\ ~(interior s = {}) /\ (!x. x IN s ==> &0 <= drop x)
+         ==> closure(s INTER { lift(&m / &2 pow n) |
+                               m IN (:num) /\ n IN (:num)}) =
+             closure s`,
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPEC `s:real^1->bool` CLOSURE_DYADIC_RATIONALS_IN_CONVEX_SET) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN AP_TERM_TAC THEN
+    MATCH_MP_TAC(SET_RULE
+     `(!x. x IN t ==> x IN u) /\ (!x. x IN u ==> x IN s ==> x IN t)
+      ==> s INTER t = s INTER u`) THEN
+    REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV; DIMINDEX_1; FORALL_1] THEN
+    REWRITE_TAC[IN_ELIM_THM; EXISTS_LIFT; GSYM drop; LIFT_DROP] THEN
+    REWRITE_TAC[REAL_ARITH `x / y:real = inv y * x`; LIFT_CMUL] THEN
+    CONJ_TAC THENL [MESON_TAC[INTEGER_CLOSED]; ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`n:num`; `x:real^1`] THEN REPEAT DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `inv(&2 pow n) % x:real^1`) THEN
+    ASM_SIMP_TAC[DROP_CMUL; REAL_LE_MUL_EQ; REAL_LT_POW2; REAL_LT_INV_EQ] THEN
+    ASM_MESON_TAC[INTEGER_POS; LIFT_DROP]) in
+  let function_on_dyadic_rationals = prove
+   (`!f:num->num->A.
+          (!m n. f (2 * m) (n + 1) = f m n)
+          ==> ?g. !m n. g(&m / &2 pow n) = f m n`,
+    REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[EQ_SYM_EQ] THEN MP_TAC(ISPECL
+     [`\(m,n). (f:num->num->A) m n`; `\(m,n). &m / &2 pow n`]
+     FUNCTION_FACTORS_LEFT) THEN
+    REWRITE_TAC[FORALL_PAIR_THM; FUN_EQ_THM; o_THM] THEN
+    DISCH_THEN (SUBST1_TAC o SYM) THEN
+    ONCE_REWRITE_TAC[MESON[]
+      `(!a b c d. P a b c d) <=> (!b d a c. P a b c d)`] THEN
+    MATCH_MP_TAC WLOG_LE THEN REPEAT CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+    SIMP_TAC[REAL_FIELD `~(y = &0) /\ ~(y' = &0)
+                         ==> (x / y = x' / y' <=> y' / y * x = x')`;
+       REAL_POW_EQ_0; REAL_OF_NUM_EQ; REAL_DIV_POW2; ARITH_EQ] THEN
+    SIMP_TAC[LE_EXISTS; LEFT_IMP_EXISTS_THM] THEN
+    SIMP_TAC[ADD_SUB2; REAL_OF_NUM_MUL; REAL_OF_NUM_EQ; REAL_OF_NUM_POW] THEN
+    REWRITE_TAC[MESON[]
+     `(!n n' d. n' = f d n ==> !m m'. g d m = m' ==> P m m' n d) <=>
+      (!d m n. P m (g d m) n d)`] THEN
+    INDUCT_TAC THEN SIMP_TAC[EXP; MULT_CLAUSES; ADD_CLAUSES] THEN
+    REWRITE_TAC[GSYM MULT_ASSOC; ADD1] THEN ASM_MESON_TAC[]) in
+  let recursion_on_dyadic_rationals = prove
+   (`!b:num->A l r.
+          ?f. (!m. f(&m) = b m) /\
+              (!m n. f(&(4 * m + 1) / &2 pow (n + 1)) =
+                     l(f(&(2 * m + 1) / &2 pow n))) /\
+              (!m n. f(&(4 * m + 3) / &2 pow (n + 1)) =
+                     r(f(&(2 * m + 1) / &2 pow n)))`,
+    REPEAT GEN_TAC THEN
+    SUBGOAL_THEN
+     `?f:num->num->A.
+          (!m n. f (2 * m) (n + 1) = f m n) /\
+          (!m. f m 0 = b m) /\
+          (!m n. f (4 * m + 1) (n + 1) = l(f (2 * m + 1) n)) /\
+          (!m n. f (4 * m + 3) (n + 1) = r(f (2 * m + 1) n))`
+    MP_TAC THENL
+     [MP_TAC(prove_recursive_functions_exist num_RECURSION
+       `(!m. f m 0 = (b:num->A) m) /\
+        (!m n. f m (SUC n) =
+                  if EVEN m then f (m DIV 2) n
+                  else if EVEN(m DIV 2)
+                       then l(f ((m + 1) DIV 2) n)
+                       else r(f (m DIV 2) n))`) THEN
+      MATCH_MP_TAC MONO_EXISTS THEN
+      X_GEN_TAC `f:num->num->A` THEN STRIP_TAC THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[ADD1]) THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[EVEN_MULT; ARITH_EVEN; ARITH_RULE `(2 * m) DIV 2 = m`] THEN
+      REWRITE_TAC[ARITH_RULE `(4 * m + 1) DIV 2 = 2 * m`;
+                  ARITH_RULE `(4 * m + 3) DIV 2 = 2 * m + 1`;
+                  ARITH_RULE `((4 * m + 1) + 1) DIV 2 = 2 * m + 1`;
+                  ARITH_RULE `((4 * m + 3) + 1) DIV 2 = 2 * m + 2`] THEN
+      REWRITE_TAC[EVEN_ADD; EVEN_MULT; EVEN; ARITH_EVEN; SND];
+      DISCH_THEN(X_CHOOSE_THEN `f:num->num->A`
+       (CONJUNCTS_THEN2 MP_TAC ASSUME_TAC)) THEN
+      DISCH_THEN(MP_TAC o MATCH_MP function_on_dyadic_rationals) THEN
+      MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+      DISCH_THEN(fun th -> RULE_ASSUM_TAC(REWRITE_RULE[GSYM th])) THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[REAL_ARITH `x / &2 pow 0 = x`]) THEN
+      ASM_REWRITE_TAC[]]) in
+  let recursion_on_dyadic_rationals_1 = prove
+   (`!b:A l r.
+          ?f. (!m. f(&m / &2) = b) /\
+              (!m n. 0 < n ==> f(&(4 * m + 1) / &2 pow (n + 1)) =
+                               l(f(&(2 * m + 1) / &2 pow n))) /\
+              (!m n. 0 < n ==> f(&(4 * m + 3) / &2 pow (n + 1)) =
+                               r(f(&(2 * m + 1) / &2 pow n)))`,
+    REPEAT GEN_TAC THEN
+    MP_TAC(ISPECL [`(\n. b):num->A`; `l:A->A`; `r:A->A`]
+          recursion_on_dyadic_rationals) THEN
+    REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `f:real->A` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\x. (f:real->A)(&2 * x)` THEN
+    ASM_REWRITE_TAC[REAL_ARITH `&2 * x / &2 = x`] THEN
+    CONJ_TAC THEN GEN_TAC THEN INDUCT_TAC THEN REWRITE_TAC[LT_REFL] THEN
+    ASM_SIMP_TAC[ADD_CLAUSES; real_pow; REAL_POW_EQ_0; REAL_OF_NUM_EQ;
+      ARITH_EQ; REAL_FIELD `~(y = &0) ==> &2 * x / (&2 * y) = x / y`]) in
+  let exists_function_unpair = prove
+   (`(?f:A->B#C. P f) <=> (?f1 f2. P(\x. (f1 x,f2 x)))`,
+    EQ_TAC THENL [ALL_TAC; MESON_TAC[]] THEN STRIP_TAC THEN
+    EXISTS_TAC `\x. FST((f:A->B#C) x)` THEN
+    EXISTS_TAC `\x. SND((f:A->B#C) x)` THEN
+    ASM_REWRITE_TAC[PAIR; ETA_AX]) in
+  let dyadics_in_open_unit_interval = prove
+   (`interval(vec 0,vec 1) INTER
+      {lift(&m / &2 pow n) | m IN (:num) /\ n IN (:num)} =
+      {lift(&m / &2 pow n) | 0 < m /\ m < 2 EXP n}`,
+    MATCH_MP_TAC(SET_RULE
+     `(!m n. (f m n) IN s <=> P m n)
+      ==> s INTER {f m n | m IN UNIV /\ n IN UNIV} =
+          {f m n | P m n}`) THEN
+    REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+    SIMP_TAC[REAL_LT_RDIV_EQ; REAL_LT_LDIV_EQ; REAL_LT_POW2] THEN
+    SIMP_TAC[REAL_MUL_LZERO; REAL_MUL_LID; REAL_OF_NUM_POW; REAL_OF_NUM_LT]) in
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!a b m. m IN interval[a,b] /\ interval[a,b] SUBSET interval[vec 0,vec 1]
+            ==> ?c d. drop a <= drop c /\ drop c <= drop m /\
+                      drop m <= drop d /\ drop d <= drop b /\
+                      (!x. x IN interval[c,d] ==> f x = f m) /\
+                      (!x. x IN interval[a,c] DELETE c ==> ~(f x = f m)) /\
+                      (!x. x IN interval[d,b] DELETE d ==> ~(f x = f m)) /\
+                      (!x y. x IN interval[a,c] DELETE c /\
+                             y IN interval[d,b] DELETE d
+                             ==> ~((f:real^1->real^N) x = f y))`
+  MP_TAC THENL
+   [REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; SUBSET_INTERVAL_1] THEN
+    REPEAT STRIP_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?c d. {x | x IN interval[a,b] /\ (f:real^1->real^N) x = f m} =
+            interval[c,d]`
+    MP_TAC THENL
+     [SUBGOAL_THEN
+       `{x | x IN interval[a,b] /\ (f:real^1->real^N) x = f m} =
+        interval[a,b] INTER
+        {x | x IN interval[vec 0,vec 1] /\ (f:real^1->real^N) x = f m}`
+      SUBST1_TAC THENL
+       [REWRITE_TAC[EXTENSION; IN_INTER; IN_INTERVAL_1; IN_ELIM_THM;
+                    DROP_VEC] THEN
+        GEN_TAC THEN EQ_TAC THEN SIMP_TAC[] THEN ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      SUBGOAL_THEN
+       `?c d. {x | x IN interval[vec 0,vec 1] /\ (f:real^1->real^N) x = f m} =
+              interval[c,d]`
+      MP_TAC THENL
+       [ASM_REWRITE_TAC[GSYM CONNECTED_COMPACT_INTERVAL_1] THEN
+        ONCE_REWRITE_TAC[SET_RULE
+         `{x | x IN s /\ P x} = s INTER {x | x IN s /\ P x}`] THEN
+        MATCH_MP_TAC COMPACT_INTER_CLOSED THEN
+        REWRITE_TAC[COMPACT_INTERVAL] THEN
+        MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE_CONSTANT THEN
+        ASM_REWRITE_TAC[CLOSED_INTERVAL];
+        STRIP_TAC THEN ASM_REWRITE_TAC[INTER_INTERVAL_1] THEN MESON_TAC[]];
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^1` THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real^1` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `m IN interval[c:real^1,d]` MP_TAC THENL
+     [FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [GSYM th]) THEN
+      REWRITE_TAC[IN_ELIM_THM; IN_INTERVAL_1; DROP_VEC] THEN
+                  ASM_REAL_ARITH_TAC;
+      REWRITE_TAC[IN_INTERVAL_1; IN_DELETE] THEN STRIP_TAC] THEN
+    SUBGOAL_THEN `{c:real^1,d} SUBSET interval[c,d]` MP_TAC THENL
+     [ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; IN_INTERVAL_1] THEN
+      ASM_REAL_ARITH_TAC;
+      FIRST_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV)
+       [GSYM th]) THEN
+      REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; IN_ELIM_THM; IN_INTERVAL_1] THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[]] THEN
+    CONJ_TAC THENL
+     [GEN_TAC THEN REWRITE_TAC[GSYM IN_INTERVAL_1] THEN
+      FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC  (LAND_CONV o RAND_CONV)
+       [GSYM th]) THEN SIMP_TAC[IN_ELIM_THM];
+      ALL_TAC] THEN
+    GEN_REWRITE_TAC I [CONJ_ASSOC] THEN CONJ_TAC THENL
+     [CONJ_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+      `{x | x IN s /\ f x = a} = t
+       ==> (!x. P x ==> x IN s) /\ (!x. P x /\ Q x ==> ~(x IN t))
+           ==> !x. P x /\ Q x ==> ~(f x = a)`)) THEN
+      REWRITE_TAC[IN_INTERVAL_1; GSYM DROP_EQ] THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN
+    REWRITE_TAC[GSYM DROP_EQ] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `{x:real^1,y} INTER interval[c,d] = {}` MP_TAC THENL
+     [REWRITE_TAC[SET_RULE `{a,b} INTER s = {} <=> ~(a IN s) /\ ~(b IN s)`;
+                  IN_INTERVAL_1] THEN
+      ASM_REAL_ARITH_TAC;
+      FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC
+       (LAND_CONV o LAND_CONV o RAND_CONV) [GSYM th])] THEN
+    REWRITE_TAC[SET_RULE `{a,b} INTER s = {} <=> ~(a IN s) /\ ~(b IN s)`] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_INTERVAL_1] THEN
+    ASM_CASES_TAC `(f:real^1->real^N) x = f m` THENL
+     [ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    ASM_CASES_TAC `(f:real^1->real^N) y = f m` THENL
+     [ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM IS_INTERVAL_CONNECTED_1] o
+                  SPEC `(f:real^1->real^N) y`) THEN
+    ASM_REWRITE_TAC[IS_INTERVAL_1] THEN DISCH_THEN(MP_TAC o SPECL
+     [`x:real^1`; `y:real^1`; `m:real^1`]) THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM; IN_INTERVAL_1; DROP_VEC] THEN
+    ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC
+     [`leftcut:real^1->real^1->real^1->real^1`;
+      `rightcut:real^1->real^1->real^1->real^1`] THEN
+    STRIP_TAC] THEN
+  FIRST_ASSUM(MP_TAC o SPECL
+   [`vec 0:real^1`; `vec 1:real^1`; `vec 0:real^1`]) THEN
+  REWRITE_TAC[SUBSET_REFL; ENDS_IN_UNIT_INTERVAL] THEN ABBREV_TAC
+   `u = (rightcut:real^1->real^1->real^1->real^1) (vec 0) (vec 1) (vec 0)` THEN
+  REWRITE_TAC[CONJ_ASSOC; REAL_LE_ANTISYM; DROP_EQ] THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC] THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[INTERVAL_SING; SET_RULE `~(x IN ({a} DELETE a))`] THEN
+  STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPECL
+   [`u:real^1`; `vec 1:real^1`; `vec 1:real^1`]) THEN
+  REWRITE_TAC[ENDS_IN_INTERVAL; SUBSET_INTERVAL_1; INTERVAL_NE_EMPTY_1] THEN
+  ASM_REWRITE_TAC[REAL_LE_REFL] THEN ABBREV_TAC
+   `v = (leftcut:real^1->real^1->real^1->real^1) u (vec 1) (vec 1)` THEN
+  ONCE_REWRITE_TAC[TAUT
+    `a /\ b /\ c /\ d /\ e <=> (c /\ d) /\ a /\ b /\ e`] THEN
+  REWRITE_TAC[REAL_LE_ANTISYM; DROP_EQ] THEN
+  ONCE_REWRITE_TAC[IMP_CONJ] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[INTERVAL_SING; SET_RULE `~(x IN ({a} DELETE a))`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x. x IN interval[vec 0,v] DELETE v
+        ==> ~((f:real^1->real^N) x = f(vec 1))`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `t:real^1` THEN
+    REWRITE_TAC[IN_DELETE; IN_INTERVAL_1; GSYM DROP_EQ] THEN STRIP_TAC THEN
+    ASM_CASES_TAC `drop t < drop u` THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[]
+       `~(f1 = f0) ==> ft = f0 ==> ~(ft = f1)`));
+      ALL_TAC] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; IN_DELETE; GSYM DROP_EQ] THEN
+    ASM_REAL_ARITH_TAC;
+    UNDISCH_THEN
+      `!x. x IN interval[u,v] DELETE v ==> ~((f:real^1->real^N) x = f (vec 1))`
+      (K ALL_TAC)] THEN
+  MP_TAC(ISPECL
+   [`(u:real^1,v:real^1)`;
+    `\(a,b). (a:real^1,leftcut a b (midpoint(a,b)):real^1)`;
+    `\(a,b). (rightcut a b (midpoint(a,b)):real^1,b:real^1)`]
+        recursion_on_dyadic_rationals_1) THEN
+  REWRITE_TAC[exists_function_unpair; PAIR_EQ] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real->real^1`; `b:real->real^1`] THEN
+  ABBREV_TAC `(c:real->real^1) x = midpoint(a x,b x)` THEN
+  REWRITE_TAC[TAUT `a ==> b /\ c <=> (a ==> b) /\ (a ==> c)`] THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!m n. drop u <= drop(a(&m / &2 pow n)) /\
+          drop(a(&m / &2 pow n)) <= drop(b(&m / &2 pow n)) /\
+          drop(b(&m / &2 pow n)) <= drop v`
+  MP_TAC THENL
+   [GEN_REWRITE_TAC I [SWAP_FORALL_THM] THEN MATCH_MP_TAC num_INDUCTION THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[REAL_ARITH `x / &2 pow 0 = (&2 * x) / &2`] THEN
+      ASM_REWRITE_TAC[REAL_OF_NUM_MUL; REAL_LE_REFL];
+      X_GEN_TAC `n:num` THEN DISCH_THEN(LABEL_TAC "*")] THEN
+    X_GEN_TAC `p:num` THEN DISJ_CASES_TAC(SPEC `p:num` EVEN_OR_ODD) THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EVEN_EXISTS]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `m:num` SUBST1_TAC) THEN
+      REWRITE_TAC[GSYM REAL_OF_NUM_MUL; real_pow] THEN
+      ASM_SIMP_TAC[REAL_LT_POW2; REAL_FIELD
+       `&0 < y ==> (&2 * x) / (&2 * y) = x / y`];
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ODD_EXISTS]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `m:num` SUBST1_TAC) THEN
+    DISJ_CASES_TAC(ARITH_RULE `n = 0 \/ 0 < n`) THENL
+     [ASM_REWRITE_TAC[real_pow; REAL_MUL_RID; REAL_LE_REFL];
+      REWRITE_TAC[ADD1]] THEN
+    DISJ_CASES_TAC(SPEC `m:num` EVEN_OR_ODD) THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EVEN_EXISTS]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `r:num` SUBST_ALL_TAC) THEN
+      ASM_SIMP_TAC[ARITH_RULE `2 * 2 * r = 4 * r`];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ODD_EXISTS]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `r:num` SUBST_ALL_TAC) THEN
+      ASM_SIMP_TAC[ARITH_RULE `2 * SUC(2 * r) + 1 = 4 * r + 3`]] THEN
+    (FIRST_X_ASSUM(MP_TAC o SPECL
+      [`a(&(2 * r + 1) / &2 pow n):real^1`;
+       `b(&(2 * r + 1) / &2 pow n):real^1`;
+       `c(&(2 * r + 1) / &2 pow n):real^1`]) THEN
+     ANTS_TAC THENL
+      [FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o LAND_CONV)
+        [GSYM th]) THEN
+       REWRITE_TAC[midpoint; IN_INTERVAL_1; SUBSET_INTERVAL_1] THEN
+       REWRITE_TAC[DROP_CMUL; DROP_ADD] THEN
+       UNDISCH_TAC `drop(vec 0) <= drop u` THEN
+       UNDISCH_TAC `drop v <= drop (vec 1)`;
+       ALL_TAC] THEN
+     REMOVE_THEN "*" (MP_TAC o SPEC `2 * r + 1`) THEN REAL_ARITH_TAC);
+    REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC] THEN
+  SUBGOAL_THEN `!m n. drop(vec 0) <= drop(a(&m / &2 pow n))` ASSUME_TAC THENL
+   [ASM_MESON_TAC[REAL_LE_TRANS]; ALL_TAC] THEN
+  SUBGOAL_THEN `!m n. drop(b(&m / &2 pow n)) <= drop(vec 1)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[REAL_LE_TRANS]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!m n. drop(a(&m / &2 pow n)) <= drop(c(&m / &2 pow n)) /\
+          drop(c(&m / &2 pow n)) <= drop(b(&m / &2 pow n))`
+  MP_TAC THENL
+   [UNDISCH_THEN `!x:real. midpoint(a x:real^1,b x) = c x`
+      (fun th -> REWRITE_TAC[GSYM th]) THEN
+    REWRITE_TAC[midpoint; IN_INTERVAL_1; SUBSET_INTERVAL_1] THEN
+    ASM_REWRITE_TAC[DROP_CMUL; DROP_ADD; REAL_ARITH
+     `a <= inv(&2) * (a + b) /\ inv(&2) * (a + b) <= b <=> a <= b`];
+    REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC] THEN
+  SUBGOAL_THEN
+   `!i m n j. ODD j /\
+              abs(&i / &2 pow m - &j / &2 pow n) < inv(&2 pow n)
+              ==> drop(a(&j / &2 pow n)) <= drop(c(&i / &2 pow m)) /\
+                  drop(c(&i / &2 pow m)) <= drop(b(&j / &2 pow n))`
+  ASSUME_TAC THENL
+   [REPLICATE_TAC 3 GEN_TAC THEN WF_INDUCT_TAC `m - n:num` THEN
+    DISJ_CASES_TAC(ARITH_RULE `m <= n \/ n:num < m`) THENL
+     [GEN_TAC THEN STRIP_TAC THEN
+      MP_TAC(SPEC `abs(&2 pow n) * abs(&i / &2 pow m - &j / &2 pow n)`
+                REAL_ABS_INTEGER_LEMMA) THEN
+      MATCH_MP_TAC(TAUT
+       `i /\ ~b /\ (n ==> p) ==> (i /\ ~n ==> b) ==> p`) THEN
+      REPEAT CONJ_TAC THENL
+       [REWRITE_TAC[GSYM REAL_ABS_MUL; INTEGER_ABS] THEN
+        REWRITE_TAC[REAL_ARITH
+         `n * (x / m - y / n):real = x * (n / m) - y * (n / n)`] THEN
+        ASM_SIMP_TAC[GSYM REAL_POW_SUB; LE_REFL; REAL_OF_NUM_EQ; ARITH_EQ] THEN
+        MESON_TAC[INTEGER_CLOSED];
+        SIMP_TAC[REAL_ABS_MUL; REAL_ABS_ABS; REAL_ABS_POW; REAL_ABS_NUM] THEN
+        REWRITE_TAC[REAL_ARITH `~(&1 <= x * y) <=> y * x < &1`] THEN
+        SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_LT_POW2] THEN
+        ASM_REWRITE_TAC[REAL_ARITH `&1 / x = inv x`];
+        ASM_SIMP_TAC[REAL_ABS_POW; REAL_ABS_NUM; REAL_ENTIRE; REAL_LT_IMP_NZ;
+          REAL_LT_POW2; REAL_ARITH `abs(x - y) = &0 <=> x = y`]];
+      ALL_TAC] THEN
+    X_GEN_TAC `k:num` THEN REWRITE_TAC[IMP_CONJ; ODD_EXISTS] THEN
+    DISCH_THEN(X_CHOOSE_THEN `j:num` SUBST1_TAC) THEN
+    DISJ_CASES_TAC(ARITH_RULE `n = 0 \/ 0 < n`) THENL
+     [ASM_REWRITE_TAC[REAL_ARITH `x / &2 pow 0 = (&2 * x) / &2`] THEN
+      ASM_REWRITE_TAC[REAL_OF_NUM_MUL] THEN ASM_MESON_TAC[REAL_LE_TRANS];
+      ALL_TAC] THEN
+    UNDISCH_THEN `n:num < m`
+      (fun th -> let th' = MATCH_MP
+                   (ARITH_RULE `n < m ==> m - SUC n < m - n`) th in
+                 FIRST_X_ASSUM(MP_TAC o C MATCH_MP th')) THEN
+    REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC (REAL_ARITH
+     `&i / &2 pow m = &(2 * j + 1) / &2 pow n \/
+      &i / &2 pow m < &(2 * j + 1) / &2 pow n \/
+      &(2 * j + 1) / &2 pow n < &i / &2 pow m`)
+    THENL
+     [ASM_REWRITE_TAC[ADD1];
+      DISCH_THEN(MP_TAC o SPEC `4 * j + 1`) THEN
+      REWRITE_TAC[ODD_ADD; ODD_MULT; ARITH] THEN ASM_SIMP_TAC[ADD1] THEN
+      MATCH_MP_TAC MONO_IMP THEN CONJ_TAC THENL
+       [MATCH_MP_TAC(REAL_ARITH
+         `x < i /\ &2 * n1 = n /\ j + n1 = i
+          ==> abs(x - i) < n ==> abs(x - j) < n1`) THEN
+        ASM_REWRITE_TAC[REAL_ARITH `a / b + inv b = (a + &1) / b`] THEN
+        REWRITE_TAC[real_div; REAL_POW_ADD; REAL_INV_MUL] THEN
+        REWRITE_TAC[GSYM REAL_OF_NUM_ADD; GSYM REAL_OF_NUM_MUL] THEN
+        REAL_ARITH_TAC;
+        MATCH_MP_TAC(REAL_ARITH
+         `b' <= b ==> a <= c /\ c <= b' ==> a <= c /\ c <= b`) THEN
+        FIRST_X_ASSUM(MP_TAC o SPECL
+         [`a(&(2 * j + 1) / &2 pow n):real^1`;
+          `b(&(2 * j + 1) / &2 pow n):real^1`;
+          `c(&(2 * j + 1) / &2 pow n):real^1`]) THEN
+        ANTS_TAC THENL [ALL_TAC; REAL_ARITH_TAC] THEN
+        FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o LAND_CONV)
+          [GSYM th]) THEN
+        REWRITE_TAC[midpoint; IN_INTERVAL_1; SUBSET_INTERVAL_1] THEN
+        REWRITE_TAC[DROP_CMUL; DROP_ADD] THEN
+        ASM_REWRITE_TAC[DROP_CMUL; DROP_ADD; REAL_ARITH
+         `a <= inv(&2) * (a + b) /\ inv(&2) * (a + b) <= b <=> a <= b`]];
+      DISCH_THEN(MP_TAC o SPEC `4 * j + 3`) THEN
+      REWRITE_TAC[ODD_ADD; ODD_MULT; ARITH] THEN ASM_SIMP_TAC[ADD1] THEN
+      MATCH_MP_TAC MONO_IMP THEN CONJ_TAC THENL
+       [MATCH_MP_TAC(REAL_ARITH
+         `i < x /\ &2 * n1 = n /\ j - n1 = i
+          ==> abs(x - i) < n ==> abs(x - j) < n1`) THEN
+        ASM_REWRITE_TAC[REAL_ARITH `a / b - inv b = (a - &1) / b`] THEN
+        REWRITE_TAC[real_div; REAL_POW_ADD; REAL_INV_MUL] THEN
+        REWRITE_TAC[GSYM REAL_OF_NUM_ADD; GSYM REAL_OF_NUM_MUL] THEN
+        REAL_ARITH_TAC;
+        MATCH_MP_TAC(REAL_ARITH
+         `a <= a' ==> a' <= c /\ c <= b ==> a <= c /\ c <= b`) THEN
+        FIRST_X_ASSUM(MP_TAC o SPECL
+         [`a(&(2 * j + 1) / &2 pow n):real^1`;
+          `b(&(2 * j + 1) / &2 pow n):real^1`;
+          `c(&(2 * j + 1) / &2 pow n):real^1`]) THEN
+        ANTS_TAC THENL [ALL_TAC; REAL_ARITH_TAC] THEN
+        FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o LAND_CONV)
+          [GSYM th]) THEN
+        REWRITE_TAC[midpoint; IN_INTERVAL_1; SUBSET_INTERVAL_1] THEN
+        REWRITE_TAC[DROP_CMUL; DROP_ADD] THEN
+        ASM_REWRITE_TAC[DROP_CMUL; DROP_ADD; REAL_ARITH
+         `a <= inv(&2) * (a + b) /\ inv(&2) * (a + b) <= b <=> a <= b`]]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!m n. ODD m ==> abs(drop(a(&m / &2 pow n)) - drop(b(&m / &2 pow n)))
+                    <= &2 / &2 pow n`
+  ASSUME_TAC THENL
+   [ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN INDUCT_TAC THENL
+     [ASM_REWRITE_TAC[REAL_ARITH `x / &2 pow 0 = (&2 * x) / &2`] THEN
+      ASM_REWRITE_TAC[REAL_OF_NUM_MUL] THEN CONV_TAC NUM_REDUCE_CONV THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[DROP_VEC]) THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    X_GEN_TAC `m:num` THEN REWRITE_TAC[ODD_EXISTS] THEN
+    DISCH_THEN(X_CHOOSE_THEN `k:num` SUBST1_TAC) THEN
+    DISJ_CASES_TAC(ARITH_RULE `n = 0 \/ 0 < n`) THENL
+     [ASM_REWRITE_TAC[ARITH; REAL_POW_1] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[DROP_VEC]) THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    DISJ_CASES_TAC(SPEC `k:num` EVEN_OR_ODD) THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EVEN_EXISTS]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `j:num` SUBST1_TAC) THEN
+      REWRITE_TAC[ARITH_RULE `SUC(2 * 2 * j) = 4 * j + 1`] THEN
+      ASM_SIMP_TAC[ADD1] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `drop c = (drop a + drop b) / &2 /\
+        abs(drop a - drop b) <= &2 * k /\
+        drop a <= drop(leftcut a b c) /\
+        drop(leftcut a b c) <= drop c
+        ==> abs(drop a - drop(leftcut a b c)) <= k`);
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ODD_EXISTS]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `j:num` SUBST1_TAC) THEN
+      REWRITE_TAC[ARITH_RULE `SUC(2 * SUC(2 * j)) = 4 * j + 3`] THEN
+      ASM_SIMP_TAC[ADD1] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `drop c = (drop a + drop b) / &2 /\
+        abs(drop a - drop b) <= &2 * k /\
+        drop c <= drop(rightcut a b c) /\
+        drop(rightcut a b c) <= drop b
+        ==> abs(drop(rightcut a b c) - drop b) <= k`)] THEN
+    (CONJ_TAC THENL
+      [UNDISCH_THEN `!x:real. midpoint(a x:real^1,b x) = c x`
+        (fun th -> REWRITE_TAC[GSYM th]) THEN
+       REWRITE_TAC[midpoint; DROP_CMUL; DROP_ADD] THEN REAL_ARITH_TAC;
+       ALL_TAC] THEN
+     CONJ_TAC THENL
+      [REWRITE_TAC[real_div; REAL_POW_ADD; REAL_INV_MUL] THEN
+       REWRITE_TAC[REAL_ARITH `&2 * x * inv y * inv(&2 pow 1) = x / y`] THEN
+       ASM_SIMP_TAC[GSYM real_div; ODD_ADD; ODD_MULT; ARITH];
+       ALL_TAC] THEN
+     FIRST_X_ASSUM(MP_TAC o SPECL
+      [`a(&(2 * j + 1) / &2 pow n):real^1`;
+       `b(&(2 * j + 1) / &2 pow n):real^1`;
+       `c(&(2 * j + 1) / &2 pow n):real^1`]) THEN
+     ANTS_TAC THENL [ALL_TAC; REAL_ARITH_TAC] THEN
+     FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o LAND_CONV)
+       [GSYM th]) THEN
+     REWRITE_TAC[midpoint; IN_INTERVAL_1; SUBSET_INTERVAL_1] THEN
+     REWRITE_TAC[DROP_CMUL; DROP_ADD] THEN
+     ASM_REWRITE_TAC[DROP_CMUL; DROP_ADD; REAL_ARITH
+      `a <= inv(&2) * (a + b) /\ inv(&2) * (a + b) <= b <=> a <= b`]);
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n j. 0 < 2 * j /\ 2 * j < 2 EXP n
+          ==> (f:real^1->real^N)(b(&(2 * j - 1) / &2 pow n)) =
+              f(a(&(2 * j + 1) / &2 pow n))`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC num_INDUCTION THEN CONJ_TAC THENL
+     [REWRITE_TAC[ARITH_RULE `0 < 2 * j <=> 0 < j`;
+                  ARITH_RULE `2 * j < 2 <=> j < 1`] THEN
+      ARITH_TAC;
+      ALL_TAC] THEN
+    X_GEN_TAC `n:num` THEN DISCH_THEN(LABEL_TAC "+") THEN
+    DISJ_CASES_TAC(ARITH_RULE `n = 0 \/ 0 < n`) THENL
+     [ASM_REWRITE_TAC[] THEN CONV_TAC NUM_REDUCE_CONV THEN
+      REWRITE_TAC[ARITH_RULE `0 < 2 * j <=> 0 < j`;
+                   ARITH_RULE `2 * j < 2  <=> j < 1`] THEN
+      ARITH_TAC;
+      ALL_TAC] THEN
+    X_GEN_TAC `k:num` THEN DISJ_CASES_TAC(SPEC `k:num` EVEN_OR_ODD) THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EVEN_EXISTS]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `j:num` SUBST1_TAC) THEN
+      REWRITE_TAC[EXP; ARITH_RULE `0 < 2 * j <=> 0 < j`; LT_MULT_LCANCEL] THEN
+      CONV_TAC NUM_REDUCE_CONV THEN
+      ASM_SIMP_TAC[ARITH_RULE `0 < j ==> 2 * 2 * j - 1 = 4 * (j - 1) + 3`;
+        ADD1; ARITH_RULE `2 * 2 * j + 1 = 4 * j + 1`] THEN
+      SIMP_TAC[ARITH_RULE `0 < j ==> 2 * (j - 1) + 1 = 2 * j - 1`] THEN
+      STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC;
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ODD_EXISTS]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `j:num` SUBST1_TAC) THEN
+      STRIP_TAC THEN
+      ASM_SIMP_TAC[ADD1; ARITH_RULE `2 * SUC(2 * j) - 1 = 4 * j + 1`;
+                   ARITH_RULE `2 * SUC(2 * j) + 1 = 4 * j + 3`] THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL
+       [`a(&(2 * j + 1) / &2 pow n):real^1`;
+        `b(&(2 * j + 1) / &2 pow n):real^1`;
+        `c(&(2 * j + 1) / &2 pow n):real^1`]) THEN
+      ANTS_TAC THENL
+       [FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o LAND_CONV)
+         [GSYM th]) THEN
+        REWRITE_TAC[midpoint; IN_INTERVAL_1; SUBSET_INTERVAL_1] THEN
+        REWRITE_TAC[DROP_CMUL; DROP_ADD] THEN
+        ASM_REWRITE_TAC[DROP_CMUL; DROP_ADD; REAL_ARITH
+         `a <= inv(&2) * (a + b) /\ inv(&2) * (a + b) <= b <=> a <= b`];
+        REPLICATE_TAC 4 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+        DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+        MATCH_MP_TAC(MESON[]
+         `a IN s /\ b IN s ==> (!x. x IN s ==> f x = c) ==> f a = f b`) THEN
+        REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_NE_EMPTY_1] THEN
+        ASM_MESON_TAC[REAL_LE_TRANS]]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n j. 0 < j /\ j < 2 EXP n
+          ==> (f:real^1->real^N)(b(&(2 * j - 1) / &2 pow (n + 1))) =
+              f(c(&j / &2 pow n)) /\
+              f(a(&(2 * j + 1) / &2 pow (n + 1))) = f(c(&j / &2 pow n))`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC num_INDUCTION THEN
+    REWRITE_TAC[ARITH_RULE `~(0 < j /\ j < 2 EXP 0)`] THEN
+    X_GEN_TAC `n:num` THEN DISCH_THEN(LABEL_TAC "*") THEN
+    X_GEN_TAC `j:num` THEN
+    DISJ_CASES_TAC(SPEC `j:num` EVEN_OR_ODD) THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EVEN_EXISTS]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `k:num` SUBST1_TAC) THEN
+      REWRITE_TAC[ADD_CLAUSES; EXP; ARITH_RULE `0 < 2 * k <=> 0 < k`;
+                  ARITH_RULE `2 * x < 2 * y <=> x < y`] THEN STRIP_TAC THEN
+      REMOVE_THEN "*" (MP_TAC o SPEC `k:num`) THEN
+      ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(MESON[]
+       `c' = c /\ a' = a /\ b' = b
+        ==> b = c /\ a = c ==> b' = c' /\ a' = c'`) THEN
+      REPEAT CONJ_TAC THEN AP_TERM_TAC THENL
+       [AP_TERM_TAC THEN
+        REWRITE_TAC[real_pow; real_div; REAL_INV_MUL;
+                    GSYM REAL_OF_NUM_MUL] THEN
+        REAL_ARITH_TAC;
+        REWRITE_TAC[ADD1; ARITH_RULE `2 * 2 * n = 4 * n`] THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN ARITH_TAC;
+        SUBGOAL_THEN `k = PRE k + 1` SUBST1_TAC THENL
+         [ASM_ARITH_TAC; ALL_TAC] THEN
+        REWRITE_TAC[ARITH_RULE `2 * (k + 1) - 1 = 2 * k + 1`;
+                    ARITH_RULE `2 * 2 * (k + 1) - 1 = 4 * k + 3`] THEN
+        REWRITE_TAC[ADD1] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ARITH_TAC];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ODD_EXISTS]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `k:num` SUBST1_TAC) THEN
+      REWRITE_TAC[EXP; ARITH_RULE `SUC(2 * k) < 2 * n <=> k < n`] THEN
+      STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+       [`a(&(2 * k + 1) / &2 pow (SUC n)):real^1`;
+        `b(&(2 * k + 1) / &2 pow (SUC n)):real^1`;
+        `c(&(2 * k + 1) / &2 pow (SUC n)):real^1`]) THEN
+      ANTS_TAC THENL
+       [ASM_REWRITE_TAC[midpoint; IN_INTERVAL_1; SUBSET_INTERVAL_1];
+        REPLICATE_TAC 4 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+        DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC)] THEN
+      REWRITE_TAC[ARITH_RULE `SUC(2 * k) = 2 * k + 1`] THEN
+      DISCH_THEN(fun th -> CONJ_TAC THEN MATCH_MP_TAC th) THEN
+      ASM_SIMP_TAC[ARITH_RULE `2 * (2 * k + 1) - 1 = 4 * k + 1`; ADD1;
+                   ARITH_RULE `2 * (2 * k + 1) + 1 = 4 * k + 3`;
+                   ARITH_RULE `0 < n + 1`] THEN
+      ASM_REWRITE_TAC[IN_INTERVAL_1; GSYM ADD1] THEN
+      ASM_SIMP_TAC[ARITH_RULE `SUC(2 * k) = 2 * k + 1`] THEN
+      ASM_REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+  MATCH_MP_TAC HOMEOMORPHIC_COMPACT THEN
+  REWRITE_TAC[COMPACT_INTERVAL] THEN
+  MP_TAC(ISPECL [`\x. (f:real^1->real^N)(c(drop x))`;
+                 `interval(vec 0,vec 1) INTER
+                  {lift(&m / &2 pow n) | m IN (:num) /\ n IN (:num)}`]
+        UNIFORMLY_CONTINUOUS_EXTENDS_TO_CLOSURE) THEN
+  SIMP_TAC[closure_dyadic_rationals_in_convex_set_pos_1;
+           CONVEX_INTERVAL; INTERIOR_OPEN; OPEN_INTERVAL;
+           UNIT_INTERVAL_NONEMPTY; IN_INTERVAL_1; REAL_LT_IMP_LE; DROP_VEC;
+           CLOSURE_OPEN_INTERVAL] THEN
+  REWRITE_TAC[dyadics_in_open_unit_interval] THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[uniformly_continuous_on; FORALL_IN_GSPEC] THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN SUBGOAL_THEN
+     `(f:real^1->real^N) uniformly_continuous_on interval[vec 0,vec 1]`
+    MP_TAC THENL
+     [ASM_SIMP_TAC[COMPACT_UNIFORMLY_CONTINUOUS; COMPACT_INTERVAL];
+      REWRITE_TAC[uniformly_continuous_on]] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    MP_TAC(SPECL [`inv(&2)`; `min (d:real) (&1 / &4)`] REAL_ARCH_POW_INV) THEN
+    ASM_REWRITE_TAC[REAL_HALF; REAL_POW_INV; REAL_LT_MIN] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:num` MP_TAC) THEN
+    ASM_CASES_TAC `n = 0` THEN ASM_REWRITE_TAC[] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN STRIP_TAC THEN
+    EXISTS_TAC `inv(&2 pow n)` THEN
+    REWRITE_TAC[REAL_LT_POW2; REAL_LT_INV_EQ] THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[FORALL_IN_GSPEC] THEN
+    SUBGOAL_THEN
+     `!i j m. 0 < i /\ i < 2 EXP m /\ 0 < j /\ j < 2 EXP n /\
+              abs(&i / &2 pow m - &j / &2 pow n) < inv(&2 pow n)
+              ==> norm((f:real^1->real^N)(c(&i / &2 pow m)) -
+                       f(c(&j / &2 pow n))) < e / &2`
+    ASSUME_TAC THENL
+     [REPEAT GEN_TAC THEN
+      REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+      DISCH_THEN(DISJ_CASES_THEN MP_TAC o MATCH_MP (REAL_ARITH
+       `abs(x - a) < e
+        ==> x = a \/
+            abs(x - (a - e / &2)) < e / &2 \/
+            abs(x - (a + e / &2)) < e / &2`))
+      THENL
+       [DISCH_THEN SUBST1_TAC THEN
+        ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0; REAL_HALF];
+        ALL_TAC] THEN
+      SUBGOAL_THEN
+       `&j / &2 pow n = &(2 * j) / &2 pow (n + 1)`
+       (fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [th])
+      THENL
+       [REWRITE_TAC[REAL_POW_ADD; real_div; REAL_INV_MUL;
+                    GSYM REAL_OF_NUM_MUL] THEN
+        REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[real_div; GSYM REAL_INV_MUL] THEN
+      REWRITE_TAC[GSYM real_div;
+           GSYM(ONCE_REWRITE_RULE[REAL_MUL_SYM] (CONJUNCT2 real_pow))] THEN
+      REWRITE_TAC[ADD1; REAL_ARITH `x / n + inv n = (x + &1) / n`;
+                  REAL_ARITH `x / n - inv n = (x - &1) / n`] THEN
+      ASM_SIMP_TAC[REAL_OF_NUM_SUB; ARITH_RULE `0 < j ==> 1 <= 2 * j`] THEN
+      REWRITE_TAC[REAL_OF_NUM_ADD] THEN STRIP_TAC THENL
+       [SUBGOAL_THEN `(f:real^1->real^N)(c(&j / &2 pow n)) =
+                      f(b (&(2 * j - 1) / &2 pow (n + 1)))`
+        SUBST1_TAC THENL [ASM_SIMP_TAC[]; ALL_TAC];
+        SUBGOAL_THEN `(f:real^1->real^N)(c(&j / &2 pow n)) =
+                      f(a (&(2 * j + 1) / &2 pow (n + 1)))`
+        SUBST1_TAC THENL [ASM_SIMP_TAC[]; ALL_TAC]] THEN
+      REWRITE_TAC[GSYM dist] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      REWRITE_TAC[IN_INTERVAL_1] THEN
+      REPEAT(CONJ_TAC THENL [ASM_MESON_TAC[REAL_LE_TRANS]; ALL_TAC]) THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL [`i:num`; `m:num`; `n + 1`]) THENL
+       [DISCH_THEN(MP_TAC o SPEC `2 * j - 1`) THEN REWRITE_TAC[ODD_SUB];
+        DISCH_THEN(MP_TAC o SPEC `2 * j + 1`) THEN REWRITE_TAC[ODD_ADD]] THEN
+      ASM_REWRITE_TAC[ODD_MULT; ARITH; ARITH_RULE `1 < 2 * j <=> 0 < j`] THEN
+      REWRITE_TAC[DIST_REAL; GSYM drop] THENL
+       [MATCH_MP_TAC(NORM_ARITH
+         `!t. abs(a - b) <= t /\ t < d
+              ==> a <= c /\ c <= b ==> abs(c - b) < d`);
+        MATCH_MP_TAC(NORM_ARITH
+         `!t. abs(a - b) <= t /\ t < d
+              ==> a <= c /\ c <= b ==> abs(c - a) < d`)] THEN
+      EXISTS_TAC `&2 / &2 pow (n + 1)` THEN
+      (CONJ_TAC THENL
+        [FIRST_X_ASSUM MATCH_MP_TAC THEN
+         REWRITE_TAC[ODD_SUB; ODD_ADD; ODD_MULT; ARITH_ODD] THEN
+         ASM_REWRITE_TAC[ARITH_RULE `1 < 2 * j <=> 0 < j`];
+         REWRITE_TAC[REAL_POW_ADD; real_div; REAL_INV_MUL] THEN
+         ASM_REAL_ARITH_TAC]);
+      ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`i:num`; `m:num`] THEN STRIP_TAC THEN
+    MAP_EVERY X_GEN_TAC [`k:num`; `p:num`] THEN STRIP_TAC THEN
+    REWRITE_TAC[DIST_LIFT; LIFT_DROP] THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `?j. 0 < j /\ j < 2 EXP n /\
+          abs(&i / &2 pow m - &j / &2 pow n) < inv(&2 pow n) /\
+          abs(&k / &2 pow p - &j / &2 pow n) < inv(&2 pow n)`
+    STRIP_ASSUME_TAC THENL
+     [MP_TAC(SPEC `max (&2 pow n * &i / &2 pow m)
+                       (&2 pow n * &k / &2 pow p)`
+        FLOOR_POS) THEN
+      SIMP_TAC[REAL_LE_MUL; REAL_LE_MAX; REAL_LE_DIV;
+               REAL_POS; REAL_POW_LE] THEN
+      DISCH_THEN(X_CHOOSE_TAC `j:num`) THEN
+      MP_TAC(SPEC `max (&2 pow n * &i / &2 pow m)
+                       (&2 pow n * &k / &2 pow p)` FLOOR) THEN
+      ASM_REWRITE_TAC[REAL_LE_MAX; REAL_MAX_LT] THEN
+      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+      SIMP_TAC[GSYM REAL_LE_LDIV_EQ; GSYM REAL_LT_RDIV_EQ; REAL_LT_POW2] THEN
+      REWRITE_TAC[REAL_ARITH `(j + &1) / n = j / n + inv n`] THEN
+      ASM_CASES_TAC `j = 0` THENL
+       [ASM_REWRITE_TAC[REAL_ARITH `&0 / x = &0`; REAL_ADD_LID] THEN
+        DISCH_TAC THEN EXISTS_TAC `1` THEN CONV_TAC NUM_REDUCE_CONV THEN
+        REWRITE_TAC[ARITH_RULE `1 < n <=> 2 EXP 1 <= n`] THEN
+        ASM_SIMP_TAC[LE_EXP; LE_1] THEN CONV_TAC NUM_REDUCE_CONV THEN
+        MATCH_MP_TAC(REAL_ARITH
+         `&0 < x /\ x < inv n /\ &0 < y /\ y < inv n
+          ==> abs(x - &1 / n) < inv n /\ abs(y - &1 / n) < inv n`) THEN
+        ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; REAL_LT_POW2];
+        DISCH_TAC THEN EXISTS_TAC `j:num` THEN ASM_SIMP_TAC[LE_1] THEN
+        REWRITE_TAC[GSYM REAL_OF_NUM_LT; GSYM REAL_OF_NUM_POW] THEN
+        CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+        FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [GSYM th]) THEN
+        SIMP_TAC[GSYM REAL_NOT_LE; REAL_LE_FLOOR; INTEGER_CLOSED] THEN
+        REWRITE_TAC[REAL_NOT_LE; REAL_MAX_LT] THEN
+        REWRITE_TAC[REAL_ARITH `n * x < n <=> n * x < n * &1`] THEN
+        SIMP_TAC[REAL_LT_LMUL_EQ; REAL_LT_POW2; REAL_LT_LDIV_EQ] THEN
+        ASM_REWRITE_TAC[REAL_MUL_LID; REAL_OF_NUM_POW; REAL_OF_NUM_LT]];
+      MATCH_MP_TAC(NORM_ARITH
+       `!u. dist(w:real^N,u) < e / &2 /\ dist(z,u) < e / &2
+            ==> dist(w,z) < e`) THEN
+      EXISTS_TAC `(f:real^1->real^N)(c(&j / &2 pow n))` THEN
+      REWRITE_TAC[dist] THEN CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REWRITE_TAC[]];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `h:real^1->real^N` THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; LIFT_DROP] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o CONJUNCT1)) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP UNIFORMLY_CONTINUOUS_IMP_CONTINUOUS) THEN
+  ONCE_REWRITE_TAC[MESON[] `h x = f(c(drop x)) <=> f(c(drop x)) = h x`] THEN
+  REWRITE_TAC[IN_INTER; IMP_CONJ_ALT; FORALL_IN_GSPEC] THEN
+  ASM_REWRITE_TAC[IN_UNIV; LIFT_DROP; IMP_IMP; GSYM CONJ_ASSOC] THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+  SIMP_TAC[REAL_LT_RDIV_EQ; REAL_LT_LDIV_EQ; REAL_LT_POW2] THEN
+  REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID] THEN
+  REWRITE_TAC[REAL_OF_NUM_POW; REAL_OF_NUM_LT] THEN
+  REWRITE_TAC[GSYM REAL_OF_NUM_POW] THEN DISCH_TAC THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+     [MP_TAC(ISPEC `interval(vec 0:real^1,vec 1)`
+        closure_dyadic_rationals_in_convex_set_pos_1) THEN
+      SIMP_TAC[CONVEX_INTERVAL; IN_INTERVAL_1; REAL_LT_IMP_LE; DROP_VEC;
+        INTERIOR_OPEN; OPEN_INTERVAL; INTERVAL_NE_EMPTY_1; REAL_LT_01;
+        CLOSURE_OPEN_INTERVAL] THEN
+      DISCH_THEN(fun th ->
+        GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM th]) THEN
+      MATCH_MP_TAC IMAGE_CLOSURE_SUBSET THEN REPEAT CONJ_TAC THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        MATCH_MP_TAC CLOSURE_MINIMAL THEN REWRITE_TAC[CLOSED_INTERVAL] THEN
+        MATCH_MP_TAC(SET_RULE `s SUBSET u ==> s INTER t SUBSET u`) THEN
+        REWRITE_TAC[INTERVAL_OPEN_SUBSET_CLOSED];
+        MATCH_MP_TAC COMPACT_IMP_CLOSED THEN
+        MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+        ASM_REWRITE_TAC[COMPACT_INTERVAL];
+        SIMP_TAC[dyadics_in_open_unit_interval; SUBSET; FORALL_IN_IMAGE] THEN
+        ASM_SIMP_TAC[FORALL_IN_GSPEC] THEN
+        MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN STRIP_TAC THEN
+        MATCH_MP_TAC FUN_IN_IMAGE THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+        ASM_MESON_TAC[REAL_LE_TRANS]];
+      MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `closure(IMAGE (h:real^1->real^N)
+                                 (interval (vec 0,vec 1) INTER
+        {lift (&m / &2 pow n) | m IN (:num) /\ n IN (:num)}))` THEN
+      CONJ_TAC THENL
+       [ALL_TAC;
+        MATCH_MP_TAC CLOSURE_MINIMAL THEN
+        ASM_SIMP_TAC[COMPACT_IMP_CLOSED; COMPACT_INTERVAL;
+                     COMPACT_CONTINUOUS_IMAGE] THEN
+        MATCH_MP_TAC IMAGE_SUBSET THEN
+        MATCH_MP_TAC(SET_RULE `s SUBSET u ==> s INTER t SUBSET u`) THEN
+        REWRITE_TAC[INTERVAL_OPEN_SUBSET_CLOSED]] THEN
+      REWRITE_TAC[SUBSET; CLOSURE_APPROACHABLE; FORALL_IN_IMAGE] THEN
+      REWRITE_TAC[dyadics_in_open_unit_interval;
+                  EXISTS_IN_IMAGE; EXISTS_IN_GSPEC] THEN
+      X_GEN_TAC `x:real^1` THEN DISCH_TAC THEN
+      X_GEN_TAC `e:real` THEN DISCH_TAC THEN UNDISCH_TAC
+       `(f:real^1->real^N) continuous_on interval [vec 0,vec 1]` THEN
+      DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        COMPACT_UNIFORMLY_CONTINUOUS)) THEN
+      REWRITE_TAC[COMPACT_INTERVAL; uniformly_continuous_on] THEN
+      DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+      SUBGOAL_THEN
+       `!n. ~(n = 0)
+            ==> ?m y. ODD m /\ 0 < m /\ m < 2 EXP n /\
+                      y IN interval[a(&m / &2 pow n),b(&m / &2 pow n)] /\
+                     (f:real^1->real^N) y = f x`
+      MP_TAC THENL
+       [ALL_TAC;
+        MP_TAC(SPECL [`inv(&2)`; `min (d / &2) (&1 / &4)`]
+         REAL_ARCH_POW_INV) THEN
+        ASM_REWRITE_TAC[REAL_HALF; REAL_POW_INV; REAL_LT_MIN] THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV THEN
+        DISCH_THEN(X_CHOOSE_THEN `n:num` MP_TAC) THEN
+        ASM_CASES_TAC `n = 0` THEN ASM_REWRITE_TAC[] THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV THEN STRIP_TAC THEN
+        DISCH_THEN(MP_TAC o SPEC `n:num`) THEN ASM_REWRITE_TAC[] THEN
+        MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `m:num` THEN
+        DISCH_THEN(X_CHOOSE_THEN `y:real^1` MP_TAC) THEN
+        REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+        DISCH_THEN(SUBST1_TAC o SYM) THEN EXISTS_TAC `n:num` THEN
+        ASM_SIMP_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+        REWRITE_TAC[DIST_REAL; GSYM drop; IN_INTERVAL_1] THEN
+        REPEAT(CONJ_TAC THENL [ASM_MESON_TAC[REAL_LE_TRANS]; ALL_TAC]) THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+         `a <= y /\ y <= b
+          ==> a <= c /\ c <= b /\ abs(a - b) < d
+              ==> abs(c - y) < d`)) THEN
+        REPEAT(CONJ_TAC THENL [ASM_MESON_TAC[REAL_LE_TRANS]; ALL_TAC]) THEN
+        MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `&2 / &2 pow n` THEN
+        ASM_SIMP_TAC[] THEN ASM_REAL_ARITH_TAC] THEN
+      MATCH_MP_TAC num_INDUCTION THEN REWRITE_TAC[NOT_SUC] THEN
+      X_GEN_TAC `n:num` THEN ASM_CASES_TAC `n = 0` THEN ASM_REWRITE_TAC[] THENL
+       [EXISTS_TAC `1` THEN CONV_TAC NUM_REDUCE_CONV THEN
+        ASM_REWRITE_TAC[REAL_POW_1] THEN
+        SUBGOAL_THEN
+         `x IN interval[vec 0:real^1,u] \/
+          x IN interval[u,v] \/
+          x IN interval[v,vec 1]`
+        STRIP_ASSUME_TAC THENL
+         [REWRITE_TAC[IN_INTERVAL_1] THEN
+          RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+          ASM_REAL_ARITH_TAC;
+          EXISTS_TAC `u:real^1` THEN
+          ASM_MESON_TAC[ENDS_IN_INTERVAL; INTERVAL_NE_EMPTY_1];
+          EXISTS_TAC `x:real^1` THEN ASM_MESON_TAC[];
+          EXISTS_TAC `v:real^1` THEN
+          ASM_MESON_TAC[ENDS_IN_INTERVAL; INTERVAL_NE_EMPTY_1]];
+        DISCH_THEN(X_CHOOSE_THEN `m:num`
+         (X_CHOOSE_THEN `y:real^1` MP_TAC)) THEN
+        REPLICATE_TAC 3 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+        DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (SUBST1_TAC o SYM)) THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ODD_EXISTS]) THEN
+        DISCH_THEN(X_CHOOSE_THEN `j:num` SUBST_ALL_TAC) THEN
+        REWRITE_TAC[ADD1] THEN DISCH_TAC THEN
+        SUBGOAL_THEN
+        `y IN interval[a(&(2 * j + 1) / &2 pow n):real^1,
+                       b(&(4 * j + 1) / &2 pow (n + 1))] \/
+         y IN interval[b(&(4 * j + 1) / &2 pow (n + 1)),
+                       a(&(4 * j + 3) / &2 pow (n + 1))] \/
+         y IN interval[a(&(4 * j + 3) / &2 pow (n + 1)),
+                       b(&(2 * j + 1) / &2 pow n)]`
+        STRIP_ASSUME_TAC THENL
+         [REWRITE_TAC[IN_INTERVAL_1] THEN
+          RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+          ASM_REAL_ARITH_TAC;
+          EXISTS_TAC `4 * j + 1` THEN
+          EXISTS_TAC `y:real^1` THEN
+          REWRITE_TAC[ODD_ADD; ODD_MULT; ARITH; EXP_ADD] THEN
+          REPEAT(CONJ_TAC THENL [ASM_ARITH_TAC; ALL_TAC]) THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[]
+           `y IN interval[a,b]
+            ==> a = a' /\ b = b' ==> y IN interval[a',b']`)) THEN
+          ASM_MESON_TAC[LE_1];
+          EXISTS_TAC `4 * j + 1` THEN
+          EXISTS_TAC `b(&(4 * j + 1) / &2 pow (n + 1)):real^1` THEN
+          REWRITE_TAC[ODD_ADD; ODD_MULT; ARITH; EXP_ADD] THEN
+          REPEAT(CONJ_TAC THENL [ASM_ARITH_TAC; ALL_TAC]) THEN
+          REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_NE_EMPTY_1] THEN
+          CONJ_TAC THENL [ASM_MESON_TAC[REAL_LE_TRANS]; ALL_TAC] THEN
+          FIRST_X_ASSUM(MP_TAC o SPECL
+           [`a(&(2 * j + 1) / &2 pow n):real^1`;
+            `b(&(2 * j + 1) / &2 pow n):real^1`;
+            `c(&(2 * j + 1) / &2 pow n):real^1`]) THEN
+          ANTS_TAC THENL
+           [ASM_REWRITE_TAC[midpoint; IN_INTERVAL_1; SUBSET_INTERVAL_1];
+            REPLICATE_TAC 4
+             (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+            DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC)] THEN
+          MATCH_MP_TAC(MESON[]
+           `a IN s /\ b IN s ==> (!x. x IN s ==> f x = k) ==> f a = f b`) THEN
+          SUBGOAL_THEN
+           `leftcut (a (&(2 * j + 1) / &2 pow n))
+                    (b (&(2 * j + 1) / &2 pow n))
+                    (c (&(2 * j + 1) / &2 pow n):real^1):real^1 =
+            b(&(4 * j + 1) / &2 pow (n + 1)) /\
+            rightcut (a (&(2 * j + 1) / &2 pow n))
+                     (b (&(2 * j + 1) / &2 pow n))
+                     (c (&(2 * j + 1) / &2 pow n)):real^1 =
+            a(&(4 * j + 3) / &2 pow (n + 1))`
+          (CONJUNCTS_THEN SUBST_ALL_TAC) THENL
+            [ASM_MESON_TAC[LE_1]; ALL_TAC] THEN
+          REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_NE_EMPTY_1] THEN
+          CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[]
+           `y IN interval[a,b]
+            ==> a = a' /\ b = b' ==> y IN interval[a',b']`)) THEN
+          ASM_MESON_TAC[LE_1];
+          EXISTS_TAC `4 * j + 3` THEN
+          EXISTS_TAC `y:real^1` THEN
+          REWRITE_TAC[ODD_ADD; ODD_MULT; ARITH; EXP_ADD] THEN
+          REPEAT(CONJ_TAC THENL [ASM_ARITH_TAC; ALL_TAC]) THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[]
+           `y IN interval[a,b]
+            ==> a = a' /\ b = b' ==> y IN interval[a',b']`)) THEN
+          ASM_MESON_TAC[LE_1]]]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n m. drop(a(&m / &2 pow n)) < drop(b(&m / &2 pow n)) /\
+          (!x. drop(a(&m / &2 pow n)) < drop x /\
+               drop x <= drop(b(&m / &2 pow n))
+               ==> ~(f x = f(a(&m / &2 pow n)))) /\
+          (!x. drop(a(&m / &2 pow n)) <= drop x /\
+               drop x < drop(b(&m / &2 pow n))
+               ==> ~(f x :real^N = f(b(&m / &2 pow n))))`
+  ASSUME_TAC THENL
+   [SUBGOAL_THEN `drop u < drop v` ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[REAL_LT_LE; DROP_EQ] THEN DISCH_THEN SUBST_ALL_TAC THEN
+      RULE_ASSUM_TAC(REWRITE_RULE
+       [IN_DELETE; IN_INTERVAL_1; GSYM DROP_EQ; DROP_VEC]) THEN
+      ASM_MESON_TAC[DROP_EQ];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `(!x. drop u < drop x /\ drop x <= drop v
+          ==> ~((f:real^1->real^N) x = f u)) /\
+      (!x. drop u <= drop x /\ drop x < drop v
+           ==> ~(f x = f v))`
+    STRIP_ASSUME_TAC THENL
+     [SUBGOAL_THEN
+       `(f:real^1->real^N) u = f(vec 0) /\
+        (f:real^1->real^N) v = f(vec 1)`
+       (CONJUNCTS_THEN SUBST1_TAC)
+      THENL
+       [CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+        ASM_REWRITE_TAC[IN_INTERVAL_1; REAL_LE_REFL];
+        ALL_TAC] THEN
+      CONJ_TAC THEN GEN_TAC THEN STRIP_TAC THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REWRITE_TAC[IN_DELETE; IN_INTERVAL_1; GSYM DROP_EQ] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC num_INDUCTION THEN
+    ASM_REWRITE_TAC[REAL_ARITH `&m / &2 pow 0 = (&2 * &m) / &2`] THEN
+    ASM_REWRITE_TAC[REAL_OF_NUM_MUL] THEN
+    X_GEN_TAC `n:num` THEN DISCH_THEN(LABEL_TAC "*") THEN
+    DISJ_CASES_TAC(ARITH_RULE `n = 0 \/ 0 < n`) THEN
+    ASM_REWRITE_TAC[ARITH; REAL_POW_1] THEN
+    X_GEN_TAC `j:num` THEN
+    DISJ_CASES_TAC(ISPEC `j:num` EVEN_OR_ODD) THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EVEN_EXISTS]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `k:num` SUBST1_TAC) THEN
+      SIMP_TAC[GSYM REAL_OF_NUM_MUL; real_div; REAL_INV_MUL; real_pow] THEN
+      ASM_REWRITE_TAC[REAL_ARITH `(&2 * p) * inv(&2) * inv q = p / q`];
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ODD_EXISTS]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `k:num` SUBST1_TAC) THEN
+    DISJ_CASES_TAC(ISPEC `k:num` EVEN_OR_ODD) THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EVEN_EXISTS]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `m:num` SUBST1_TAC) THEN
+      ASM_SIMP_TAC[ARITH_RULE `2 * 2 * m = 4 * m`; ADD1] THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL
+       [`a(&(2 * m + 1) / &2 pow n):real^1`;
+        `b(&(2 * m + 1) / &2 pow n):real^1`;
+        `c(&(2 * m + 1) / &2 pow n):real^1`]) THEN
+      ANTS_TAC THENL
+       [REWRITE_TAC[IN_INTERVAL_1; SUBSET_INTERVAL_1] THEN
+        ASM_MESON_TAC[REAL_LE_TRANS];
+        REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+        DISCH_THEN(K ALL_TAC)] THEN
+      SUBGOAL_THEN
+       `(f:real^1->real^N)
+        (leftcut (a (&(2 * m + 1) / &2 pow n):real^1)
+                 (b (&(2 * m + 1) / &2 pow n):real^1)
+                 (c (&(2 * m + 1) / &2 pow n):real^1)) =
+        (f:real^1->real^N) (c(&(2 * m + 1) / &2 pow n))`
+      ASSUME_TAC THENL
+       [FIRST_X_ASSUM MATCH_MP_TAC THEN
+        ASM_REWRITE_TAC[IN_INTERVAL_1; REAL_LE_REFL] THEN ASM_REAL_ARITH_TAC;
+        ASM_REWRITE_TAC[]] THEN
+      GEN_REWRITE_TAC LAND_CONV [REAL_LT_LE] THEN ASM_REWRITE_TAC[DROP_EQ] THEN
+      REPEAT CONJ_TAC THENL
+       [DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+        UNDISCH_THEN
+         `(f:real^1->real^N) (a (&(2 * m + 1) / &2 pow n)) =
+          f(c (&(2 * m + 1) / &2 pow n))` (MP_TAC o SYM) THEN
+        REWRITE_TAC[] THEN
+        FIRST_ASSUM(MATCH_MP_TAC o CONJUNCT1 o CONJUNCT2 o SPEC_ALL) THEN
+        REWRITE_TAC[GSYM(ASSUME `!x. midpoint ((a:real->real^1) x,b x) = c x`);
+                    midpoint; DROP_CMUL; DROP_ADD] THEN
+        ASM_REWRITE_TAC[REAL_ARITH
+         `a < inv(&2) * (a + b) /\ inv(&2) * (a + b) <= b <=> a < b`];
+        GEN_TAC THEN STRIP_TAC THEN
+        FIRST_ASSUM(MATCH_MP_TAC o CONJUNCT1 o CONJUNCT2 o SPEC_ALL) THEN
+        ASM_MESON_TAC[REAL_LE_TRANS];
+        GEN_TAC THEN STRIP_TAC THEN FIRST_X_ASSUM
+         (fun th -> MATCH_MP_TAC th THEN
+                    REWRITE_TAC[IN_INTERVAL_1; IN_DELETE; GSYM DROP_EQ] THEN
+             GEN_REWRITE_TAC I [REAL_ARITH
+              `(a <= x /\ x <= b) /\ ~(x = b) <=> a <= x /\ x < b`]) THEN
+        ASM_REWRITE_TAC[]];
+       FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ODD_EXISTS]) THEN
+       DISCH_THEN(X_CHOOSE_THEN `m:num` SUBST1_TAC) THEN
+       ASM_SIMP_TAC[ARITH_RULE `2 * (2 * m + 1) + 1  = 4 * m + 3`; ADD1] THEN
+       FIRST_X_ASSUM(MP_TAC o SPECL
+        [`a(&(2 * m + 1) / &2 pow n):real^1`;
+         `b(&(2 * m + 1) / &2 pow n):real^1`;
+         `c(&(2 * m + 1) / &2 pow n):real^1`]) THEN
+      ANTS_TAC THENL
+       [REWRITE_TAC[IN_INTERVAL_1; SUBSET_INTERVAL_1] THEN
+        ASM_MESON_TAC[REAL_LE_TRANS];
+        REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+        DISCH_THEN(K ALL_TAC)] THEN
+      SUBGOAL_THEN
+       `(f:real^1->real^N)
+        (rightcut (a (&(2 * m + 1) / &2 pow n):real^1)
+                  (b (&(2 * m + 1) / &2 pow n):real^1)
+                  (c (&(2 * m + 1) / &2 pow n):real^1)) =
+        (f:real^1->real^N) (c(&(2 * m + 1) / &2 pow n))`
+      ASSUME_TAC THENL
+       [FIRST_X_ASSUM MATCH_MP_TAC THEN
+        ASM_REWRITE_TAC[IN_INTERVAL_1; REAL_LE_REFL] THEN ASM_REAL_ARITH_TAC;
+        ASM_REWRITE_TAC[]] THEN
+      GEN_REWRITE_TAC LAND_CONV [REAL_LT_LE] THEN ASM_REWRITE_TAC[DROP_EQ] THEN
+      REPEAT CONJ_TAC THENL
+       [DISCH_THEN SUBST_ALL_TAC THEN
+        UNDISCH_THEN
+         `(f:real^1->real^N) (b (&(2 * m + 1) / &2 pow n)) =
+          f(c (&(2 * m + 1) / &2 pow n))` (MP_TAC o SYM) THEN
+        REWRITE_TAC[] THEN
+        FIRST_ASSUM(MATCH_MP_TAC o CONJUNCT2 o CONJUNCT2 o SPEC_ALL) THEN
+        REWRITE_TAC[GSYM(ASSUME `!x. midpoint ((a:real->real^1) x,b x) = c x`);
+                    midpoint; DROP_CMUL; DROP_ADD] THEN
+        ASM_REWRITE_TAC[REAL_ARITH
+         `a <= inv(&2) * (a + b) /\ inv(&2) * (a + b) < b <=> a < b`];
+        GEN_TAC THEN STRIP_TAC THEN FIRST_X_ASSUM
+         (fun th -> MATCH_MP_TAC th THEN
+                    REWRITE_TAC[IN_INTERVAL_1; IN_DELETE; GSYM DROP_EQ] THEN
+             GEN_REWRITE_TAC I [REAL_ARITH
+              `(a <= x /\ x <= b) /\ ~(x = a) <=> a < x /\ x <= b`]) THEN
+        ASM_REWRITE_TAC[];
+        GEN_TAC THEN STRIP_TAC THEN
+        FIRST_ASSUM(MATCH_MP_TAC o CONJUNCT2 o CONJUNCT2 o SPEC_ALL) THEN
+        ASM_MESON_TAC[REAL_LE_TRANS]]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!m i n j. 0 < i /\ i < 2 EXP m /\ 0 < j /\ j < 2 EXP n /\
+              &i / &2 pow m < &j / &2 pow n
+              ==> drop(c(&i / &2 pow m)) <= drop(c(&j / &2 pow n))`
+  ASSUME_TAC THENL
+   [SUBGOAL_THEN
+     `!N m p i k.
+         0 < i /\ i < 2 EXP m /\ 0 < k /\ k < 2 EXP p /\
+         &i / &2 pow m < &k / &2 pow p /\ m + p = N
+         ==> ?j n. ODD(j) /\ ~(n = 0) /\
+                   &i / &2 pow m <= &j / &2 pow n /\
+                   &j / &2 pow n <= &k / &2 pow p /\
+                   abs(&i / &2 pow m - &j / &2 pow n) < inv(&2 pow n) /\
+                   abs(&k / &2 pow p - &j / &2 pow n) < inv(&2 pow n)`
+    MP_TAC THENL
+     [MATCH_MP_TAC num_WF THEN X_GEN_TAC `N:num` THEN
+      DISCH_THEN(LABEL_TAC "I") THEN
+      MAP_EVERY X_GEN_TAC [`m:num`; `p:num`; `i:num`; `k:num`] THEN
+      STRIP_TAC THEN
+      SUBGOAL_THEN
+       `&i / &2 pow m <= &1 / &2 pow 1 /\
+        &1 / &2 pow 1 <= &k / &2 pow p \/
+        &k / &2 pow p < &1 / &2 \/
+        &1 / &2 < &i / &2 pow m`
+       (REPEAT_TCL DISJ_CASES_THEN STRIP_ASSUME_TAC)
+      THENL
+       [ASM_REAL_ARITH_TAC;
+        MAP_EVERY EXISTS_TAC [`1`; `1`] THEN ASM_REWRITE_TAC[ARITH] THEN
+        MATCH_MP_TAC(REAL_ARITH
+         `&0 < i /\ i <= &1 / &2 pow 1 /\ &1 / &2 pow 1 <= k /\ k < &1
+          ==> abs(i -  &1 / &2 pow 1) < inv(&2 pow 1) /\
+              abs(k -  &1 / &2 pow 1) < inv(&2 pow 1)`) THEN
+        ASM_SIMP_TAC[REAL_LT_RDIV_EQ; REAL_LT_LDIV_EQ; REAL_LT_POW2] THEN
+        REWRITE_TAC[MULT_CLAUSES; REAL_OF_NUM_POW; REAL_OF_NUM_MUL] THEN
+        ASM_REWRITE_TAC[REAL_OF_NUM_LT];
+        REMOVE_THEN "I" MP_TAC THEN
+        POP_ASSUM_LIST(MP_TAC o end_itlist CONJ o rev) THEN
+        SPEC_TAC(`m:num`,`m:num`) THEN INDUCT_TAC THEN
+        REWRITE_TAC[ARITH_RULE `i < 2 EXP 0 <=> ~(0 < i)`] THEN
+        REWRITE_TAC[TAUT `p /\ ~p /\ q <=> F`] THEN POP_ASSUM(K ALL_TAC) THEN
+        SPEC_TAC(`p:num`,`p:num`) THEN INDUCT_TAC THEN
+        REWRITE_TAC[ARITH_RULE `i < 2 EXP 0 <=> ~(0 < i)`] THEN
+        REWRITE_TAC[TAUT `p /\ ~p /\ q <=> F`] THEN POP_ASSUM(K ALL_TAC) THEN
+        STRIP_TAC THEN DISCH_THEN(MP_TAC o SPEC `m + p:num`) THEN
+        ANTS_TAC THENL [EXPAND_TAC "N" THEN ARITH_TAC; ALL_TAC] THEN
+        DISCH_THEN(MP_TAC o SPECL [`m:num`; `p:num`; `i:num`; `k:num`]) THEN
+        ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+         [MAP_EVERY UNDISCH_TAC
+           [`&k / &2 pow SUC p < &1 / &2`;
+            `&i / &2 pow SUC m < &k / &2 pow SUC p`] THEN
+          REWRITE_TAC[real_div; real_pow; REAL_INV_MUL;
+                      REAL_ARITH `x * inv(&2) * y = (x * y) * inv(&2)`] THEN
+          SIMP_TAC[GSYM real_div; REAL_LT_DIV2_EQ; REAL_OF_NUM_LT; ARITH] THEN
+          REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+           `x < y /\ y < &1 ==> x < &1 /\ y < &1`)) THEN
+          SIMP_TAC[REAL_LT_LDIV_EQ; REAL_LT_POW2; REAL_MUL_LID] THEN
+          REWRITE_TAC[REAL_OF_NUM_POW; REAL_OF_NUM_LT];
+          MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `j:num` THEN
+          DISCH_THEN(X_CHOOSE_THEN `n:num` STRIP_ASSUME_TAC) THEN
+          EXISTS_TAC `SUC n` THEN ASM_REWRITE_TAC[NOT_SUC] THEN
+          REWRITE_TAC[real_div; real_pow; REAL_INV_MUL;
+                      REAL_ARITH `inv(&2) * y = y * inv(&2)`] THEN
+          REWRITE_TAC[GSYM REAL_SUB_RDISTRIB; REAL_MUL_ASSOC;
+                      REAL_ABS_MUL; REAL_ABS_INV; REAL_ABS_NUM] THEN
+          REWRITE_TAC[GSYM real_div; REAL_ABS_NUM] THEN
+          ASM_SIMP_TAC[REAL_LT_DIV2_EQ; REAL_LE_DIV2_EQ;
+                       REAL_OF_NUM_LT; ARITH]];
+        REMOVE_THEN "I" MP_TAC THEN
+        POP_ASSUM_LIST(MP_TAC o end_itlist CONJ o rev) THEN
+        SPEC_TAC(`m:num`,`m:num`) THEN INDUCT_TAC THEN
+        REWRITE_TAC[ARITH_RULE `i < 2 EXP 0 <=> ~(0 < i)`] THEN
+        REWRITE_TAC[TAUT `p /\ ~p /\ q <=> F`] THEN POP_ASSUM(K ALL_TAC) THEN
+        SPEC_TAC(`p:num`,`p:num`) THEN INDUCT_TAC THEN
+        REWRITE_TAC[ARITH_RULE `i < 2 EXP 0 <=> ~(0 < i)`] THEN
+        REWRITE_TAC[TAUT `p /\ ~p /\ q <=> F`] THEN POP_ASSUM(K ALL_TAC) THEN
+        STRIP_TAC THEN DISCH_THEN(MP_TAC o SPEC `m + p:num`) THEN
+        ANTS_TAC THENL [EXPAND_TAC "N" THEN ARITH_TAC; ALL_TAC] THEN
+        DISCH_THEN(MP_TAC o SPECL
+         [`m:num`; `p:num`; `i - 2 EXP m`; `k - 2 EXP p`]) THEN
+        ASM_REWRITE_TAC[] THEN
+        MAP_EVERY UNDISCH_TAC
+         [`&1 / &2 < &i / &2 pow SUC m`;
+          `&i / &2 pow SUC m < &k / &2 pow SUC p`] THEN
+        REWRITE_TAC[real_div; real_pow; REAL_INV_MUL;
+                    REAL_ARITH `x * inv(&2) * y = (x * y) * inv(&2)`] THEN
+        SIMP_TAC[GSYM real_div; REAL_LT_DIV2_EQ; REAL_OF_NUM_LT; ARITH] THEN
+        GEN_REWRITE_TAC I [IMP_IMP] THEN DISCH_THEN(fun th ->
+          STRIP_ASSUME_TAC th THEN MP_TAC(MATCH_MP
+           (REAL_ARITH `i < k /\ &1 < i ==> &1 < i /\ &1 < k`) th)) THEN
+        SIMP_TAC[REAL_LT_RDIV_EQ; REAL_LT_POW2; REAL_MUL_LID] THEN
+        GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [REAL_OF_NUM_POW] THEN
+        SIMP_TAC[REAL_OF_NUM_LT; GSYM REAL_OF_NUM_SUB; LT_IMP_LE] THEN
+        STRIP_TAC THEN REWRITE_TAC[GSYM REAL_OF_NUM_POW] THEN ANTS_TAC THENL
+         [ASM_SIMP_TAC[ARITH_RULE `a < b ==> 0 < b - a`] THEN
+          ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_LT_POW2] THEN
+          REWRITE_TAC[real_div; REAL_SUB_RDISTRIB] THEN
+          ASM_SIMP_TAC[REAL_MUL_RINV; REAL_LT_IMP_NZ; REAL_LT_POW2] THEN
+          ASM_REWRITE_TAC[REAL_ARITH `u * inv v - &1 < w * inv z - &1 <=>
+                                      u / v < w / z`] THEN
+          CONJ_TAC THEN MATCH_MP_TAC(ARITH_RULE
+           `i < 2 * m ==> i - m < m`) THEN
+          ASM_REWRITE_TAC[GSYM(CONJUNCT2 EXP)];
+          REWRITE_TAC[real_div; REAL_SUB_RDISTRIB] THEN
+          ASM_SIMP_TAC[REAL_MUL_RINV; REAL_LT_IMP_NZ; REAL_LT_POW2] THEN
+          REWRITE_TAC[GSYM real_div] THEN
+          DISCH_THEN(X_CHOOSE_THEN `j:num` (X_CHOOSE_THEN `n:num`
+           STRIP_ASSUME_TAC)) THEN
+          EXISTS_TAC `2 EXP n + j` THEN EXISTS_TAC `SUC n` THEN
+          ASM_REWRITE_TAC[NOT_SUC; ODD_ADD; ODD_EXP; ARITH] THEN
+          REWRITE_TAC[GSYM REAL_OF_NUM_ADD; GSYM REAL_OF_NUM_POW] THEN
+          REWRITE_TAC[real_div; real_pow; REAL_INV_MUL;
+                      REAL_ARITH `inv(&2) * y = y * inv(&2)`] THEN
+          REWRITE_TAC[GSYM REAL_SUB_RDISTRIB; REAL_MUL_ASSOC;
+                      REAL_ABS_MUL; REAL_ABS_INV; REAL_ABS_NUM] THEN
+          REWRITE_TAC[GSYM real_div; REAL_ABS_NUM] THEN
+          ASM_SIMP_TAC[REAL_LT_DIV2_EQ; REAL_LE_DIV2_EQ;
+                       REAL_OF_NUM_LT; ARITH] THEN
+          REWRITE_TAC[real_div; REAL_ADD_RDISTRIB] THEN
+          ASM_SIMP_TAC[REAL_MUL_RINV; REAL_LT_IMP_NZ; REAL_LT_POW2] THEN
+          REWRITE_TAC[GSYM real_div] THEN ASM_REAL_ARITH_TAC]];
+      DISCH_THEN(fun th ->
+       MAP_EVERY X_GEN_TAC [`m:num`; `i:num`; `p:num`; `k:num`] THEN
+       STRIP_TAC THEN MP_TAC(ISPECL
+        [`m + p:num`; `m:num`; `p:num`; `i:num`; `k:num`] th)) THEN
+      ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+      MAP_EVERY X_GEN_TAC [`j:num`; `n:num`] THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [ODD_EXISTS]) THEN
+      REWRITE_TAC[ADD1; LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `q:num` THEN DISCH_THEN SUBST_ALL_TAC THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `drop(c(&(2 * q + 1) / &2 pow n))` THEN CONJ_TAC THENL
+       [ASM_CASES_TAC `&i / &2 pow m = &(2 * q + 1) / &2 pow n` THEN
+        ASM_REWRITE_TAC[REAL_LE_REFL] THEN
+        SUBGOAL_THEN
+         `drop(a(&(4 * q + 1) / &2 pow (n + 1))) <= drop(c(&i / &2 pow m)) /\
+          drop(c(&i / &2 pow m)) <= drop(b(&(4 * q + 1) / &2 pow (n + 1)))`
+        MP_TAC THENL
+         [FIRST_X_ASSUM MATCH_MP_TAC THEN
+          REWRITE_TAC[ODD_ADD; ODD_MULT; ARITH] THEN
+          SIMP_TAC[real_div; REAL_POW_ADD; REAL_INV_MUL; REAL_MUL_ASSOC] THEN
+          REWRITE_TAC[GSYM real_div; REAL_POW_1] THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+           `abs(i - q) < n
+            ==> i <= q /\ ~(i = q) /\ q = q' + n / &2
+                ==> abs(i - q') < n / &2`)) THEN
+          ASM_REWRITE_TAC[] THEN
+          REWRITE_TAC[GSYM REAL_OF_NUM_ADD; GSYM REAL_OF_NUM_MUL] THEN
+          REAL_ARITH_TAC;
+          ASM_SIMP_TAC[LE_1] THEN MATCH_MP_TAC(REAL_ARITH
+           `l <= d ==> u <= v /\ c <= l ==> c <= d`) THEN
+          FIRST_X_ASSUM(MP_TAC o SPECL
+           [`a(&(2 * q + 1) / &2 pow n):real^1`;
+            `b(&(2 * q + 1) / &2 pow n):real^1`;
+            `c(&(2 * q + 1) / &2 pow n):real^1`]) THEN
+          ANTS_TAC THENL
+           [REWRITE_TAC[IN_INTERVAL_1; SUBSET_INTERVAL_1] THEN
+            ASM_MESON_TAC[REAL_LE_TRANS];
+            DISCH_THEN(fun th -> REWRITE_TAC[th])]];
+        ASM_CASES_TAC `&k / &2 pow p = &(2 * q + 1) / &2 pow n` THEN
+        ASM_REWRITE_TAC[REAL_LE_REFL] THEN
+        SUBGOAL_THEN
+         `drop(a(&(4 * q + 3) / &2 pow (n + 1))) <= drop(c(&k / &2 pow p)) /\
+          drop(c(&k / &2 pow p)) <= drop(b(&(4 * q + 3) / &2 pow (n + 1)))`
+        MP_TAC THENL
+         [FIRST_X_ASSUM MATCH_MP_TAC THEN
+          REWRITE_TAC[ODD_ADD; ODD_MULT; ARITH] THEN
+          SIMP_TAC[real_div; REAL_POW_ADD; REAL_INV_MUL; REAL_MUL_ASSOC] THEN
+          REWRITE_TAC[GSYM real_div; REAL_POW_1] THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+           `abs(i - q) < n
+            ==> q <= i /\ ~(i = q) /\ q' = q +  n / &2
+                ==> abs(i - q') < n / &2`)) THEN
+          ASM_REWRITE_TAC[] THEN
+          REWRITE_TAC[GSYM REAL_OF_NUM_ADD; GSYM REAL_OF_NUM_MUL] THEN
+          REAL_ARITH_TAC;
+          ASM_SIMP_TAC[LE_1] THEN MATCH_MP_TAC(REAL_ARITH
+           `d <= l ==> l <= c /\ u <= v ==> d <= c`) THEN
+          FIRST_X_ASSUM(MP_TAC o SPECL
+           [`a(&(2 * q + 1) / &2 pow n):real^1`;
+            `b(&(2 * q + 1) / &2 pow n):real^1`;
+            `c(&(2 * q + 1) / &2 pow n):real^1`]) THEN
+          ANTS_TAC THENL
+           [REWRITE_TAC[IN_INTERVAL_1; SUBSET_INTERVAL_1] THEN
+            ASM_MESON_TAC[REAL_LE_TRANS];
+            DISCH_THEN(fun th -> REWRITE_TAC[th])]]]];
+    ALL_TAC] THEN
+  REWRITE_TAC[FORALL_LIFT] THEN MATCH_MP_TAC REAL_WLOG_LT THEN
+  REWRITE_TAC[] THEN CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[FORALL_DROP; LIFT_DROP; IN_INTERVAL_1; DROP_VEC] THEN
+  MAP_EVERY X_GEN_TAC [`x1:real^1`; `x2:real^1`] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?m n. 0 < m /\ m < 2 EXP n /\
+          drop x1 < &m / &2 pow n /\ &m / &2 pow n < drop x2 /\
+          ~(h(x1):real^N = h(lift(&m / &2 pow n)))`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPEC `interval(vec 0:real^1,vec 1)`
+        closure_dyadic_rationals_in_convex_set_pos_1) THEN
+    SIMP_TAC[CONVEX_INTERVAL; IN_INTERVAL_1; REAL_LT_IMP_LE; DROP_VEC;
+            INTERIOR_OPEN; OPEN_INTERVAL; INTERVAL_NE_EMPTY_1; REAL_LT_01;
+            CLOSURE_OPEN_INTERVAL] THEN
+    REWRITE_TAC[EXTENSION] THEN
+    DISCH_THEN(MP_TAC o SPEC `inv(&2) % (x1 + x2):real^1`) THEN
+    REWRITE_TAC[dyadics_in_open_unit_interval; IN_INTERVAL_1; DROP_VEC] THEN
+    REWRITE_TAC[DROP_CMUL; DROP_ADD] THEN
+    MATCH_MP_TAC(TAUT `p /\ (q ==> r) ==> (q <=> p) ==> r`) THEN
+    CONJ_TAC THENL [ASM_REAL_ARITH_TAC; REWRITE_TAC[CLOSURE_APPROACHABLE]] THEN
+    DISCH_THEN(MP_TAC o SPEC `(drop x2 - drop x1) / &64`) THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; REWRITE_TAC[EXISTS_IN_GSPEC]] THEN
+    REWRITE_TAC[DIST_REAL; GSYM drop; LIFT_DROP; DROP_CMUL; DROP_ADD] THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN
+     `?m n. (0 < m /\ m < 2 EXP n) /\
+            abs(&m / &2 pow n - inv (&2) * (drop x1 + drop x2)) <
+            (drop x2 - drop x1) / &64 /\
+            inv(&2 pow n) < (drop x2 - drop x1) / &128`
+    STRIP_ASSUME_TAC THENL
+     [MP_TAC(ISPECL [`inv(&2)`; `min (&1 / &4) ((drop x2 - drop x1) / &128)`]
+      REAL_ARCH_POW_INV) THEN ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+      DISCH_THEN(X_CHOOSE_THEN `N:num` MP_TAC) THEN
+      ASM_CASES_TAC `N = 0` THENL
+       [ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC; ALL_TAC] THEN
+      REWRITE_TAC[REAL_INV_POW; REAL_LT_MIN; EXISTS_IN_GSPEC] THEN
+      STRIP_TAC THEN
+      FIRST_X_ASSUM(X_CHOOSE_THEN `m:num` (X_CHOOSE_THEN `n:num`
+        STRIP_ASSUME_TAC)) THEN
+      EXISTS_TAC `2 EXP N * m` THEN EXISTS_TAC `N + n:num` THEN
+      ASM_SIMP_TAC[EXP_ADD; LT_MULT; EXP_LT_0; LT_MULT_LCANCEL; LE_1;
+                   ARITH_EQ] THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[REAL_POW_ADD; real_div; REAL_INV_MUL] THEN
+        REWRITE_TAC[GSYM REAL_OF_NUM_MUL; GSYM REAL_OF_NUM_POW; REAL_ARITH
+         `(N * n) * inv N * inv m:real = (N / N) * (n / m)`] THEN
+        ASM_SIMP_TAC[REAL_DIV_REFL; REAL_POW_EQ_0; REAL_OF_NUM_EQ; ARITH_EQ;
+                     REAL_MUL_LID; GSYM real_div];
+        MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `inv(&2) pow N` THEN
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_POW_MONO_INV THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[LE_ADD]];
+      REWRITE_TAC[CONJ_ASSOC] THEN MATCH_MP_TAC(MESON[]
+       `!m n m' n'. (P m n /\ P m' n') /\
+                    (P m n /\ P m' n' ==> ~(g m n = g m' n'))
+        ==> (?m n. P m n /\ ~(a = g m n))`) THEN
+      MAP_EVERY EXISTS_TAC
+       [`2 * m + 1`; `n + 1`; `4 * m + 3`; `n + 2`] THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[EXP_ADD] THEN CONV_TAC NUM_REDUCE_CONV THEN CONJ_TAC THEN
+        (REWRITE_TAC[GSYM CONJ_ASSOC] THEN
+         REPLICATE_TAC 2 (CONJ_TAC THENL [ASM_ARITH_TAC; ALL_TAC])) THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+         `abs(x - inv(&2) * (x1 + x2)) < (x2 - x1) / &64
+          ==> abs(x - y) < (x2 - x1) / &4
+              ==> x1 < y /\ y < x2`)) THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+         `n < x / &128 ==> &0 < x /\ y < &4 * n ==> y < x / &4`)) THEN
+        ASM_REWRITE_TAC[REAL_SUB_LT] THEN
+        REWRITE_TAC[GSYM REAL_OF_NUM_ADD; GSYM REAL_OF_NUM_MUL] THEN
+        MATCH_MP_TAC(REAL_ARITH
+         `a / y = x /\ abs(b / y) < z
+          ==> abs(x - (a + b) / y) < z`) THEN
+        ONCE_REWRITE_TAC[ADD_SYM] THEN REWRITE_TAC[REAL_POW_ADD] THEN
+        SIMP_TAC[REAL_ABS_DIV; REAL_ABS_NUM; REAL_ABS_MUL; REAL_ABS_POW] THEN
+        REWRITE_TAC[real_div; REAL_INV_MUL; REAL_MUL_ASSOC] THEN
+        SIMP_TAC[REAL_LT_RMUL_EQ; REAL_EQ_MUL_RCANCEL; REAL_LT_INV_EQ;
+           REAL_LT_POW2; REAL_INV_EQ_0; REAL_POW_EQ_0; ARITH_EQ;
+           REAL_OF_NUM_EQ] THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV THEN REAL_ARITH_TAC;
+        ASM_SIMP_TAC[] THEN DISCH_THEN(K ALL_TAC) THEN
+        FIRST_X_ASSUM(MP_TAC o CONJUNCT1 o SPECL [`n + 2`; `4 * m + 3`]) THEN
+        UNDISCH_THEN `!x. midpoint ((a:real->real^1) x,b x) = c x`
+         (fun th -> REWRITE_TAC[GSYM th] THEN
+              ASM_SIMP_TAC[ARITH_RULE `n + 2 = (n + 1) + 1 /\ 0 < n + 1`] THEN
+              REWRITE_TAC[th] THEN ASSUME_TAC th) THEN
+        DISCH_TAC THEN
+        CONV_TAC(RAND_CONV SYM_CONV) THEN
+        FIRST_X_ASSUM(MP_TAC o SPECL
+         [`a(&(2 * m + 1) / &2 pow (n + 1)):real^1`;
+          `b(&(2 * m + 1) / &2 pow (n + 1)):real^1`;
+          `c(&(2 * m + 1) / &2 pow (n + 1)):real^1`]) THEN
+        ANTS_TAC THENL
+         [REWRITE_TAC[IN_INTERVAL_1; SUBSET_INTERVAL_1] THEN
+          ASM_MESON_TAC[REAL_LE_TRANS];
+          REPLICATE_TAC 6 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+          DISCH_THEN(MATCH_MP_TAC o CONJUNCT1)] THEN
+        REWRITE_TAC[IN_INTERVAL_1; IN_DELETE; GSYM DROP_EQ] THEN
+        REWRITE_TAC[REAL_ARITH
+         `(a <= b /\ b <= c) /\ ~(b = a) <=> a < b /\ b <= c`] THEN
+        REWRITE_TAC[midpoint; DROP_CMUL; DROP_ADD] THEN
+        ASM_REWRITE_TAC[REAL_ARITH
+           `a < inv(&2) * (a + b) /\ inv(&2) * (a + b) <= b <=> a < b`] THEN
+        ASM_REWRITE_TAC[REAL_LT_LE]]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `IMAGE h (interval[vec 0,lift(&m / &2 pow n)]) SUBSET
+    IMAGE (f:real^1->real^N) (interval[vec 0,c(&m / &2 pow n)]) /\
+    IMAGE h (interval[lift(&m / &2 pow n),vec 1]) SUBSET
+    IMAGE (f:real^1->real^N) (interval[c(&m / &2 pow n),vec 1])`
+  MP_TAC THENL
+   [MP_TAC(ISPEC `interval(lift(&m / &2 pow n),vec 1)`
+      closure_dyadic_rationals_in_convex_set_pos_1) THEN
+    MP_TAC(ISPEC `interval(vec 0,lift(&m / &2 pow n))`
+      closure_dyadic_rationals_in_convex_set_pos_1) THEN
+    SUBGOAL_THEN `&0 < &m / &2 pow n /\ &m / &2 pow n < &1`
+    STRIP_ASSUME_TAC THENL
+     [ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_POW2; REAL_OF_NUM_LT; REAL_LT_LDIV_EQ;
+        REAL_OF_NUM_MUL; REAL_OF_NUM_LT; REAL_OF_NUM_POW; MULT_CLAUSES];
+      ALL_TAC] THEN
+    MATCH_MP_TAC(TAUT
+     `(p1 /\ p2) /\ (q1 ==> r1) /\ (q2 ==> r2)
+      ==> (p1 ==> q1) ==> (p2 ==> q2) ==> r1 /\ r2`) THEN
+    ASM_SIMP_TAC[CONVEX_INTERVAL; IN_INTERVAL_1; REAL_LT_IMP_LE; DROP_VEC;
+     INTERIOR_OPEN; OPEN_INTERVAL; INTERVAL_NE_EMPTY_1; REAL_LT_01;
+     CLOSURE_OPEN_INTERVAL; LIFT_DROP] THEN
+    CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    CONJ_TAC THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+    (MATCH_MP_TAC IMAGE_CLOSURE_SUBSET THEN REPEAT CONJ_TAC THENL
+      [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+         CONTINUOUS_ON_SUBSET)) THEN
+       MATCH_MP_TAC CLOSURE_MINIMAL THEN REWRITE_TAC[CLOSED_INTERVAL] THEN
+       MATCH_MP_TAC(SET_RULE `s SUBSET u ==> s INTER t SUBSET u`) THEN
+       ASM_SIMP_TAC[SUBSET_INTERVAL_1; LIFT_DROP; REAL_LT_IMP_LE; DROP_VEC;
+                    REAL_LE_REFL];
+       MATCH_MP_TAC COMPACT_IMP_CLOSED THEN
+       MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+       ASM_REWRITE_TAC[COMPACT_INTERVAL] THEN
+       FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+         CONTINUOUS_ON_SUBSET)) THEN
+       REWRITE_TAC[SUBSET_INTERVAL_1; REAL_LE_REFL] THEN
+       ASM_MESON_TAC[REAL_LE_TRANS];
+       REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+       MATCH_MP_TAC(SET_RULE
+        `i SUBSET interval(vec 0,vec 1) /\
+         (!x. x IN interval(vec 0,vec 1) INTER l ==> x IN i ==> P x)
+         ==> !x. x IN i INTER l ==> P x`) THEN
+       ASM_SIMP_TAC[SUBSET_INTERVAL_1; LIFT_DROP; DROP_VEC;
+                    REAL_LT_IMP_LE; REAL_LE_REFL] THEN
+       REWRITE_TAC[dyadics_in_open_unit_interval; FORALL_IN_GSPEC] THEN
+       MAP_EVERY X_GEN_TAC [`k:num`; `p:num`] THEN STRIP_TAC THEN
+       REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+       STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+       MATCH_MP_TAC FUN_IN_IMAGE THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+       ASM_SIMP_TAC[] THEN ASM_MESON_TAC[REAL_LE_TRANS]]);
+    DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE
+     `IMAGE h s SUBSET t /\ IMAGE h s' SUBSET t'
+      ==> !x y. x IN s /\ y IN s' ==> h(x) IN t /\ h(y) IN t'`)) THEN
+    DISCH_THEN(MP_TAC o SPECL [`x1:real^1`; `x2:real^1`]) THEN
+    ASM_SIMP_TAC[IN_INTERVAL_1; LIFT_DROP; DROP_VEC; REAL_LT_IMP_LE] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE
+     `a IN IMAGE f s /\ a IN IMAGE f t
+      ==> ?x y. x IN s /\ y IN t /\ f x = a /\ f y = a`)) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`t1:real^1`; `t2:real^1`] THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(h:real^1->real^N) x2` o
+     GEN_REWRITE_RULE BINDER_CONV [GSYM IS_INTERVAL_CONNECTED_1]) THEN
+    REWRITE_TAC[IS_INTERVAL_1; IN_ELIM_THM] THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`t1:real^1`; `t2:real^1`; `c(&m / &2 pow n):real^1`]) THEN
+    UNDISCH_TAC `~(h x1:real^N = h(lift (&m / &2 pow n)))` THEN
+    ASM_SIMP_TAC[] THEN MATCH_MP_TAC(TAUT `q ==> p ==> ~q ==> r`) THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN
+    ASM_MESON_TAC[REAL_LE_TRANS]]);;
+
+let PATH_CONTAINS_ARC = prove
+ (`!p:real^1->real^N a b.
+        path p /\ pathstart p = a /\ pathfinish p = b /\ ~(a = b)
+        ==> ?q. arc q /\ path_image q SUBSET path_image p /\
+                pathstart q = a /\ pathfinish q = b`,
+  REWRITE_TAC[pathstart; pathfinish; path] THEN
+  MAP_EVERY X_GEN_TAC [`f:real^1->real^N`; `a:real^N`; `b:real^N`] THEN
+  STRIP_TAC THEN MP_TAC(ISPECL
+   [`\s. s SUBSET interval[vec 0,vec 1] /\
+         vec 0 IN s /\ vec 1 IN s /\
+         (!x y. x IN s /\ y IN s /\ segment(x,y) INTER s = {}
+                ==> (f:real^1->real^N)(x) = f(y))`;
+    `interval[vec 0:real^1,vec 1]`]
+  BROUWER_REDUCTION_THEOREM_GEN) THEN
+  ASM_REWRITE_TAC[GSYM path_image; CLOSED_INTERVAL; SUBSET_REFL] THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [ALL_TAC;
+      REWRITE_TAC[ENDS_IN_UNIT_INTERVAL] THEN
+      REPEAT GEN_TAC THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+       `s INTER i = {} ==> s SUBSET i ==> s = {}`)) THEN
+      REWRITE_TAC[SEGMENT_EQ_EMPTY] THEN
+      ANTS_TAC THENL [ONCE_REWRITE_TAC[segment]; MESON_TAC[]] THEN
+      MATCH_MP_TAC(SET_RULE `s SUBSET t ==> s DIFF i SUBSET t`) THEN
+      ASM_MESON_TAC[CONVEX_CONTAINS_SEGMENT; CONVEX_INTERVAL]] THEN
+    X_GEN_TAC `s:num->real^1->bool` THEN
+    REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC THEN CONJ_TAC THENL
+     [REWRITE_TAC[INTERS_GSPEC; SUBSET; IN_ELIM_THM; IN_UNIV] THEN
+      ASM SET_TAC[];
+      ALL_TAC] THEN
+    REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+    REWRITE_TAC[FORALL_LIFT] THEN MATCH_MP_TAC REAL_WLOG_LT THEN
+    REWRITE_TAC[] THEN CONJ_TAC THENL
+     [REWRITE_TAC[SEGMENT_SYM] THEN MESON_TAC[];
+      REWRITE_TAC[FORALL_DROP; LIFT_DROP]] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN
+    REWRITE_TAC[INTERS_GSPEC; IN_UNIV; IN_ELIM_THM] THEN
+    SIMP_TAC[SEGMENT_1; REAL_LT_IMP_LE] THEN DISCH_TAC THEN STRIP_TAC THEN
+    MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        COMPACT_UNIFORMLY_CONTINUOUS)) THEN
+    REWRITE_TAC[COMPACT_INTERVAL; uniformly_continuous_on] THEN
+    DISCH_THEN(MP_TAC o SPEC `norm((f:real^1->real^N) x - f y) / &2`) THEN
+    ASM_REWRITE_TAC[REAL_HALF; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `?u v. u IN interval[vec 0,vec 1] /\ v IN interval[vec 0,vec 1] /\
+            norm(u - x) < e /\ norm(v - y) < e /\ (f:real^1->real^N) u = f v`
+    STRIP_ASSUME_TAC THENL
+     [ALL_TAC;
+      FIRST_X_ASSUM(fun th ->
+        MP_TAC(ISPECL [`x:real^1`; `u:real^1`] th) THEN
+        MP_TAC(ISPECL [`y:real^1`; `v:real^1`] th)) THEN
+      ASM_REWRITE_TAC[dist] THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      MATCH_MP_TAC(TAUT `q /\ (p ==> ~r) ==> p ==> ~(q ==> r)`) THEN
+      CONJ_TAC THENL [ASM SET_TAC[]; CONV_TAC NORM_ARITH]] THEN
+    SUBGOAL_THEN
+     `?w z. w IN interval(x,y) /\ z IN interval(x,y) /\ drop w < drop z /\
+            norm(w - x) < e /\ norm(z - y) < e`
+    STRIP_ASSUME_TAC THENL
+     [EXISTS_TAC `x + lift(min e (drop y - drop x) / &3)` THEN
+      EXISTS_TAC `y - lift(min e (drop y - drop x) / &3)` THEN
+      REWRITE_TAC[IN_INTERVAL_1; DROP_ADD; DROP_SUB; LIFT_DROP;
+                  NORM_REAL; GSYM drop] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`interval[w:real^1,z]`;
+                   `{s n :real^1->bool | n IN (:num)}`] COMPACT_IMP_FIP) THEN
+    ASM_REWRITE_TAC[COMPACT_INTERVAL; FORALL_IN_GSPEC] THEN
+    MATCH_MP_TAC(TAUT `q /\ (~p ==> r) ==> (p ==> ~q) ==> r`) THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[INTERS_GSPEC; IN_UNIV] THEN FIRST_X_ASSUM(MATCH_MP_TAC o
+       MATCH_MP (SET_RULE
+        `s INTER u = {} ==> t SUBSET s ==> t INTER u = {}`)) THEN
+      REWRITE_TAC[SUBSET_INTERVAL_1] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[MESON[] `~(!x. P x /\ Q x ==> R x) <=>
+                         (?x. P x /\ Q x /\ ~R x)`] THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+    REWRITE_TAC[EXISTS_FINITE_SUBSET_IMAGE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `k:num->bool` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `\n:num. n` o MATCH_MP
+      UPPER_BOUND_FINITE_SET) THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `interval[w,z] INTER (s:num->real^1->bool) n = {}`
+    ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `a INTER t = {} ==> s SUBSET t ==> a INTER s = {}`)) THEN
+      REWRITE_TAC[SUBSET; INTERS_IMAGE; IN_ELIM_THM] THEN
+      REWRITE_TAC[SET_RULE
+       `(!x. x IN s n ==> !i. i IN k ==> x IN s i) <=>
+        (!i. i IN k ==> s n SUBSET s i)`] THEN
+      SUBGOAL_THEN
+       `!i n. i <= n ==> (s:num->real^1->bool) n SUBSET s i`
+       (fun th -> ASM_MESON_TAC[th]) THEN
+      MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN ASM_REWRITE_TAC[] THEN
+      SET_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?u. u IN (s:num->real^1->bool) n /\ u IN interval[x,w] /\
+          (interval[u,w] DELETE u) INTER (s n) = {}`
+    MP_TAC THENL
+     [ASM_CASES_TAC `w IN (s:num->real^1->bool) n` THENL
+       [EXISTS_TAC `w:real^1` THEN ASM_REWRITE_TAC[ENDS_IN_INTERVAL] THEN
+        REWRITE_TAC[INTERVAL_SING; SET_RULE `{a} DELETE a = {}`] THEN
+        REWRITE_TAC[INTER_EMPTY; INTERVAL_NE_EMPTY_1] THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      MP_TAC(ISPECL [`(s:num->real^1->bool) n INTER interval[x,w]`;
+                   `w:real^1`] SEGMENT_TO_POINT_EXISTS) THEN
+      ASM_SIMP_TAC[CLOSED_INTER; CLOSED_INTERVAL] THEN ANTS_TAC THENL
+       [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `x:real^1` THEN
+        ASM_REWRITE_TAC[IN_INTER; IN_INTERVAL_1] THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+        MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real^1` THEN
+        REWRITE_TAC[IN_INTER] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+        FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+         `s INTER t INTER u = {} ==> s SUBSET u ==> s INTER t = {}`)) THEN
+        REWRITE_TAC[SEGMENT_1] THEN COND_CASES_TAC THENL
+         [RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+          ASM_MESON_TAC[DROP_EQ; REAL_LE_ANTISYM];
+          ANTS_TAC THENL
+           [REWRITE_TAC[SUBSET_INTERVAL_1] THEN
+            RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+            ASM_REAL_ARITH_TAC;
+            REWRITE_TAC[OPEN_CLOSED_INTERVAL_1] THEN ASM SET_TAC[]]]];
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real^1` THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `?v. v IN (s:num->real^1->bool) n /\ v IN interval[z,y] /\
+          (interval[z,v] DELETE v) INTER (s n) = {}`
+    MP_TAC THENL
+     [ASM_CASES_TAC `z IN (s:num->real^1->bool) n` THENL
+       [EXISTS_TAC `z:real^1` THEN ASM_REWRITE_TAC[ENDS_IN_INTERVAL] THEN
+        REWRITE_TAC[INTERVAL_SING; SET_RULE `{a} DELETE a = {}`] THEN
+        REWRITE_TAC[INTER_EMPTY; INTERVAL_NE_EMPTY_1] THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      MP_TAC(ISPECL [`(s:num->real^1->bool) n INTER interval[z,y]`;
+                   `z:real^1`] SEGMENT_TO_POINT_EXISTS) THEN
+      ASM_SIMP_TAC[CLOSED_INTER; CLOSED_INTERVAL] THEN ANTS_TAC THENL
+       [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `y:real^1` THEN
+        ASM_REWRITE_TAC[IN_INTER; IN_INTERVAL_1] THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+        MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `v:real^1` THEN
+        REWRITE_TAC[IN_INTER] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+        FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+         `s INTER t INTER u = {} ==> s SUBSET u ==> s INTER t = {}`)) THEN
+        REWRITE_TAC[SEGMENT_1] THEN COND_CASES_TAC THENL
+         [ANTS_TAC THENL
+           [REWRITE_TAC[SUBSET_INTERVAL_1] THEN
+            RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+            ASM_REAL_ARITH_TAC;
+            REWRITE_TAC[OPEN_CLOSED_INTERVAL_1] THEN ASM SET_TAC[]];
+          RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+          ASM_MESON_TAC[DROP_EQ; REAL_LE_ANTISYM]]];
+      ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `v:real^1` THEN STRIP_TAC THEN
+    REPEAT CONJ_TAC THENL
+     [ASM SET_TAC[];
+      ASM SET_TAC[];
+      RULE_ASSUM_TAC(REWRITE_RULE[NORM_REAL; GSYM drop; DROP_SUB]) THEN
+      REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+      RULE_ASSUM_TAC(REWRITE_RULE[NORM_REAL; GSYM drop; DROP_SUB]) THEN
+      REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC;
+      FIRST_X_ASSUM MATCH_MP_TAC THEN EXISTS_TAC `n:num` THEN
+      ASM_REWRITE_TAC[SEGMENT_1] THEN COND_CASES_TAC THENL
+       [MAP_EVERY UNDISCH_TAC
+         [`interval[w,z] INTER (s:num->real^1->bool) n = {}`;
+          `interval[u,w] DELETE u INTER (s:num->real^1->bool) n = {}`;
+          `interval[z,v] DELETE v INTER (s:num->real^1->bool) n = {}`] THEN
+        REWRITE_TAC[IMP_IMP; SET_RULE
+          `s1 INTER t = {} /\ s2 INTER t = {} <=>
+           (s1 UNION s2) INTER t = {}`] THEN
+        MATCH_MP_TAC(SET_RULE
+         `t SUBSET s ==> s INTER u = {} ==> t INTER u = {}`) THEN
+        REWRITE_TAC[SUBSET; IN_UNION; IN_DELETE;
+                    GSYM DROP_EQ; IN_INTERVAL_1] THEN
+        ASM_REAL_ARITH_TAC;
+        RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN ASM_REAL_ARITH_TAC]];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^1->bool` STRIP_ASSUME_TAC) THEN
+  ASM_CASES_TAC `t:real^1->bool = {}` THENL
+   [ASM_MESON_TAC[IN_IMAGE; NOT_IN_EMPTY]; ALL_TAC] THEN
+  ABBREV_TAC
+   `h = \x. (f:real^1->real^N)(@y. y IN t /\ segment(x,y) INTER t = {})` THEN
+  SUBGOAL_THEN
+   `!x y. y IN t /\ segment(x,y) INTER t = {} ==> h(x) = (f:real^1->real^N)(y)`
+  ASSUME_TAC THENL
+   [SUBGOAL_THEN
+     `!x y z. y IN t /\ segment(x,y) INTER t = {} /\
+              z IN t /\ segment(x,z) INTER t = {}
+              ==> (f:real^1->real^N)(y) = f(z)`
+    ASSUME_TAC THENL
+     [REPEAT GEN_TAC THEN ASM_CASES_TAC `(x:real^1) IN t` THENL
+       [ASM_MESON_TAC[]; UNDISCH_TAC `~((x:real^1) IN t)`] THEN
+      ONCE_REWRITE_TAC[TAUT `p ==> a /\ b /\ c /\ d ==> q <=>
+                             (a /\ c) ==> p /\ b /\ d ==> q`] THEN
+      STRIP_TAC THEN
+      REWRITE_TAC[SET_RULE `~(x IN t) /\ s INTER t = {} /\ s' INTER t = {} <=>
+                            (x INSERT (s UNION s')) INTER t = {}`] THEN
+      DISCH_THEN(fun th -> FIRST_X_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(SET_RULE
+       `s SUBSET s' ==> s' INTER t = {} ==> s INTER t = {}`) THEN
+      REWRITE_TAC[SEGMENT_1; SUBSET; IN_UNION; IN_INSERT; IN_INTERVAL_1] THEN
+      GEN_TAC THEN REWRITE_TAC[GSYM DROP_EQ] THEN
+      REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_INTERVAL_1]) THEN
+      ASM_REAL_ARITH_TAC;
+      REPEAT STRIP_TAC THEN EXPAND_TAC "h" THEN ASM_MESON_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!x. x IN t ==> h(x) = (f:real^1->real^N)(x)` ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[SEGMENT_REFL; INTER_EMPTY];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!x:real^1. ?y. y IN t /\ segment(x,y) INTER t = {}`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `x:real^1` THEN
+    EXISTS_TAC `closest_point t (x:real^1)` THEN
+    ASM_SIMP_TAC[SEGMENT_TO_CLOSEST_POINT; CLOSEST_POINT_EXISTS];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x y. segment(x,y) INTER t = {} ==> (h:real^1->real^N) x = h y`
+  ASSUME_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`x:real^1`; `x':real^1`] THEN
+    ASM_CASES_TAC `(x:real^1) IN t` THENL
+     [ASM_MESON_TAC[SEGMENT_SYM]; ALL_TAC] THEN
+    ASM_CASES_TAC `(x':real^1) IN t` THENL
+     [ASM_MESON_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?y y'. y IN t /\ segment(x,y) INTER t = {} /\ h x = f y /\
+             y' IN t /\ segment(x',y') INTER t = {} /\
+             (h:real^1->real^N) x' = f y'`
+    STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[] THEN MAP_EVERY UNDISCH_TAC
+     [`~((x:real^1) IN t)`; `~((x':real^1) IN t)`;
+      `segment(x:real^1,y) INTER t = {}`;
+      `segment(x':real^1,y') INTER t = {}`;
+      `segment(x:real^1,x') INTER t = {}`] THEN
+    MATCH_MP_TAC(SET_RULE
+     `s SUBSET (x1 INSERT x2 INSERT (s0 UNION s1 UNION s2))
+      ==> s0 INTER t = {} ==> s1 INTER t = {} ==> s2 INTER t = {}
+          ==> ~(x1 IN t) ==> ~(x2 IN t) ==> s INTER t = {}`) THEN
+    REWRITE_TAC[SEGMENT_1; SUBSET; IN_UNION; IN_INSERT; IN_INTERVAL_1] THEN
+      GEN_TAC THEN REWRITE_TAC[GSYM DROP_EQ] THEN
+    REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_INTERVAL_1]) THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPEC `h:real^1->real^N` HOMEOMORPHIC_MONOTONE_IMAGE_INTERVAL) THEN
+  ANTS_TAC THENL
+   [REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[continuous_on] THEN X_GEN_TAC `u:real^1` THEN DISCH_TAC THEN
+      X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [continuous_on]) THEN
+      DISCH_THEN(MP_TAC o SPEC `u:real^1`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+      ASM_REWRITE_TAC[] THEN X_GEN_TAC `v:real^1` THEN STRIP_TAC THEN
+      ASM_CASES_TAC `segment(u:real^1,v) INTER t = {}` THENL
+       [ASM_MESON_TAC[DIST_REFL]; ALL_TAC] THEN
+      SUBGOAL_THEN
+       `(?w:real^1. w IN t /\ w IN segment[u,v] /\ segment(u,w) INTER t = {}) /\
+        (?z:real^1. z IN t /\ z IN segment[u,v] /\ segment(v,z) INTER t = {})`
+      STRIP_ASSUME_TAC THENL
+       [CONJ_TAC THENL
+         [MP_TAC(ISPECL [`segment[u:real^1,v] INTER t`; `u:real^1`]
+            SEGMENT_TO_POINT_EXISTS);
+          MP_TAC(ISPECL [`segment[u:real^1,v] INTER t`; `v:real^1`]
+          SEGMENT_TO_POINT_EXISTS)] THEN
+       (ASM_SIMP_TAC[CLOSED_INTER; CLOSED_SEGMENT] THEN ANTS_TAC THENL
+         [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+            `~(segment(u,v) INTER t = {})
+             ==> segment(u,v) SUBSET segment[u,v]
+                 ==> ~(segment[u,v] INTER t = {})`)) THEN
+          REWRITE_TAC[SEGMENT_OPEN_SUBSET_CLOSED];
+          ALL_TAC] THEN
+        MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `w:real^1` THEN
+        SIMP_TAC[IN_INTER] THEN
+        MATCH_MP_TAC(SET_RULE
+         `(w IN uv ==> uw SUBSET uv)
+          ==> (w IN uv /\ w IN t) /\ (uw INTER uv INTER t = {})
+          ==> uw INTER t = {}`) THEN
+        DISCH_TAC THEN REWRITE_TAC[open_segment] THEN
+        MATCH_MP_TAC(SET_RULE `s SUBSET t ==> s DIFF u SUBSET t`) THEN
+        REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+        REWRITE_TAC[GSYM SEGMENT_CONVEX_HULL; CONVEX_SEGMENT] THEN
+        ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; ENDS_IN_SEGMENT]);
+        SUBGOAL_THEN `(h:real^1->real^N) u = (f:real^1->real^N) w /\
+                      (h:real^1->real^N) v = (f:real^1->real^N) z`
+          (fun th -> REWRITE_TAC[th]) THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+        MATCH_MP_TAC(NORM_ARITH
+         `!u. dist(w:real^N,u) < e / &2 /\ dist(z,u) < e / &2
+              ==> dist(w,z) < e`) THEN
+        EXISTS_TAC `(f:real^1->real^N) u` THEN CONJ_TAC THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN
+        (CONJ_TAC THENL
+          [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+            `x IN s ==> s SUBSET t ==> x IN t`)) THEN
+           REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+           ASM_REWRITE_TAC[CONVEX_INTERVAL; INSERT_SUBSET; EMPTY_SUBSET];
+           ASM_MESON_TAC[DIST_IN_CLOSED_SEGMENT; REAL_LET_TRANS; DIST_SYM]])];
+      X_GEN_TAC `z:real^N` THEN
+      REWRITE_TAC[CONNECTED_IFF_CONNECTED_COMPONENT] THEN
+      MAP_EVERY X_GEN_TAC [`u:real^1`; `v:real^1`] THEN
+      REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN
+      REWRITE_TAC[connected_component] THEN
+      EXISTS_TAC `segment[u:real^1,v]` THEN
+      REWRITE_TAC[CONNECTED_SEGMENT; ENDS_IN_SEGMENT] THEN
+      ASM_CASES_TAC `segment(u:real^1,v) INTER t = {}` THENL
+       [REWRITE_TAC[SET_RULE `s SUBSET {x | x IN t /\ P x} <=>
+                              s SUBSET t /\ !x. x IN s ==> P x`] THEN
+        CONJ_TAC THENL
+         [ASM_MESON_TAC[CONVEX_CONTAINS_SEGMENT; CONVEX_INTERVAL];
+          X_GEN_TAC `x:real^1` THEN DISCH_TAC THEN
+          SUBGOAL_THEN `segment(u:real^1,x) INTER t = {}`
+            (fun th -> ASM_MESON_TAC[th]) THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+           `uv INTER t = {} ==> ux SUBSET uv ==> ux INTER t = {}`)) THEN
+          UNDISCH_TAC `(x:real^1) IN segment[u,v]` THEN
+          REWRITE_TAC[SEGMENT_1] THEN
+          REPEAT(COND_CASES_TAC THEN
+                 ASM_REWRITE_TAC[IN_INTERVAL_1; SUBSET_INTERVAL_1]) THEN
+          ASM_REAL_ARITH_TAC];
+        ALL_TAC] THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `t DIFF segment(u:real^1,v)`) THEN
+      ASM_REWRITE_TAC[SET_RULE `t DIFF s PSUBSET t <=> ~(s INTER t = {})`] THEN
+      MATCH_MP_TAC(TAUT `p ==> ~p ==> q`) THEN
+      REPEAT CONJ_TAC THENL
+       [ASM SET_TAC[];
+        MATCH_MP_TAC CLOSED_DIFF THEN ASM_REWRITE_TAC[OPEN_SEGMENT_1];
+        ASM SET_TAC[];
+        ASM_REWRITE_TAC[IN_DIFF] THEN MAP_EVERY UNDISCH_TAC
+         [`(u:real^1) IN interval[vec 0,vec 1]`;
+          `(v:real^1) IN interval[vec 0,vec 1]`] THEN
+        REWRITE_TAC[SEGMENT_1] THEN
+        REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_INTERVAL_1]) THEN
+        ASM_REAL_ARITH_TAC;
+        ASM_REWRITE_TAC[IN_DIFF] THEN MAP_EVERY UNDISCH_TAC
+         [`(u:real^1) IN interval[vec 0,vec 1]`;
+          `(v:real^1) IN interval[vec 0,vec 1]`] THEN
+        REWRITE_TAC[SEGMENT_1] THEN
+        REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_INTERVAL_1]) THEN
+        ASM_REAL_ARITH_TAC;
+        MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN
+        REWRITE_TAC[IN_DIFF] THEN STRIP_TAC THEN
+        ASM_CASES_TAC `segment(x:real^1,y) INTER segment(u,v) = {}` THENL
+         [ASM SET_TAC[]; ALL_TAC] THEN
+        SUBGOAL_THEN
+         `(segment(x:real^1,u) SUBSET segment(x,y) DIFF segment(u,v) /\
+           segment(y:real^1,v) SUBSET segment(x,y) DIFF segment(u,v)) \/
+          (segment(y:real^1,u) SUBSET segment(x,y) DIFF segment(u,v) /\
+           segment(x:real^1,v) SUBSET segment(x,y) DIFF segment(u,v))`
+        MP_TAC THENL
+         [MAP_EVERY UNDISCH_TAC
+           [`~(x IN segment(u:real^1,v))`; `~(y IN segment(u:real^1,v))`;
+            `~(segment(x:real^1,y) INTER segment (u,v) = {})`] THEN
+          POP_ASSUM_LIST(K ALL_TAC) THEN
+          MAP_EVERY (fun t -> SPEC_TAC(t,t))
+           [`v:real^1`; `u:real^1`; `y:real^1`; `x:real^1`] THEN
+          REWRITE_TAC[FORALL_LIFT] THEN
+          MATCH_MP_TAC REAL_WLOG_LE THEN CONJ_TAC THENL
+           [REWRITE_TAC[SEGMENT_SYM] THEN MESON_TAC[]; ALL_TAC] THEN
+          REWRITE_TAC[FORALL_DROP; LIFT_DROP] THEN
+          MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN DISCH_TAC THEN
+          REWRITE_TAC[FORALL_LIFT] THEN
+          MATCH_MP_TAC REAL_WLOG_LE THEN CONJ_TAC THENL
+           [REWRITE_TAC[SEGMENT_SYM] THEN MESON_TAC[]; ALL_TAC] THEN
+          REWRITE_TAC[FORALL_DROP; LIFT_DROP] THEN
+          MAP_EVERY X_GEN_TAC [`u:real^1`; `v:real^1`] THEN DISCH_TAC THEN
+          ASM_REWRITE_TAC[SEGMENT_1] THEN
+          REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+          REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+          REWRITE_TAC[IN_INTERVAL_1; SUBSET; IN_DIFF; AND_FORALL_THM] THEN
+          ASM_REAL_ARITH_TAC;
+          DISCH_THEN(DISJ_CASES_THEN(CONJUNCTS_THEN
+           (let sl = SET_RULE
+             `i SUBSET xy DIFF uv
+              ==> xy INTER (t DIFF uv) = {} ==> i INTER t = {}` in
+            fun th -> FIRST_ASSUM(MP_TAC o MATCH_MP (MATCH_MP sl th))))) THEN
+          ASM_MESON_TAC[]]];
+      ASM_MESON_TAC[]];
+    DISCH_TAC] THEN
+  SUBGOAL_THEN
+   `?q:real^1->real^N.
+        arc q /\ path_image q SUBSET path_image f /\
+        a IN path_image q /\ b IN path_image q`
+  STRIP_ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homeomorphic]) THEN
+    REWRITE_TAC[homeomorphism] THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `q:real^1->real^N` THEN
+    REWRITE_TAC[arc; path; path_image] THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
+     [ASM MESON_TAC[];
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; path_image] THEN ASM SET_TAC[];
+      REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `vec 0:real^1` THEN
+      REWRITE_TAC[ENDS_IN_UNIT_INTERVAL] THEN ASM_MESON_TAC[];
+      REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `vec 1:real^1` THEN
+      REWRITE_TAC[ENDS_IN_UNIT_INTERVAL] THEN ASM_MESON_TAC[]];
+    SUBGOAL_THEN
+     `?u v. u IN interval[vec 0,vec 1] /\ a = (q:real^1->real^N) u /\
+            v IN interval[vec 0,vec 1] /\ b = (q:real^1->real^N) v`
+    STRIP_ASSUME_TAC THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[path_image]) THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    EXISTS_TAC `subpath u v (q:real^1->real^N)` THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC ARC_SIMPLE_PATH_SUBPATH THEN
+      ASM_MESON_TAC[ARC_IMP_SIMPLE_PATH];
+      ASM_MESON_TAC[SUBSET_TRANS; PATH_IMAGE_SUBPATH_SUBSET; ARC_IMP_PATH];
+      ASM_MESON_TAC[pathstart; PATHSTART_SUBPATH];
+      ASM_MESON_TAC[pathfinish; PATHFINISH_SUBPATH]]]);;
+
+let PATH_CONNECTED_ARCWISE = prove
+ (`!s:real^N->bool.
+        path_connected s <=>
+        !x y. x IN s /\ y IN s /\ ~(x = y)
+              ==> ?g. arc g /\
+                      path_image g SUBSET s /\
+                      pathstart g = x /\
+                      pathfinish g = y`,
+  GEN_TAC THEN REWRITE_TAC[path_connected] THEN EQ_TAC THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `y:real^N`]) THEN
+  ASM_REWRITE_TAC[] THENL
+   [DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^N` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`g:real^1->real^N`; `x:real^N`; `y:real^N`]
+        PATH_CONTAINS_ARC) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    ASM_MESON_TAC[SUBSET_TRANS];
+    ASM_CASES_TAC `y:real^N = x` THEN ASM_REWRITE_TAC[] THENL
+     [EXISTS_TAC `linepath(y:real^N,y)` THEN
+      ASM_REWRITE_TAC[PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+                      PATH_IMAGE_LINEPATH; SEGMENT_REFL; SING_SUBSET];
+      MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[ARC_IMP_PATH]]]);;
+
+let ARC_CONNECTED_TRANS = prove
+ (`!g h:real^1->real^N.
+        arc g /\ arc h /\
+        pathfinish g = pathstart h /\ ~(pathstart g = pathfinish h)
+        ==> ?i. arc i /\
+                path_image i SUBSET (path_image g UNION path_image h) /\
+                pathstart i = pathstart g /\
+                pathfinish i = pathfinish h`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`g ++ h:real^1->real^N`; `pathstart(g):real^N`;
+                 `pathfinish(h):real^N`] PATH_CONTAINS_ARC) THEN
+  ASM_SIMP_TAC[PATHSTART_JOIN; PATHFINISH_JOIN; PATH_JOIN_EQ; ARC_IMP_PATH;
+               PATH_IMAGE_JOIN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Local versions of topological properties in general.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let locally = new_definition
+ `locally P (s:real^N->bool) <=>
+        !w x. open_in (subtopology euclidean s) w /\ x IN w
+              ==> ?u v. open_in (subtopology euclidean s) u /\ P v /\
+                        x IN u /\ u SUBSET v /\ v SUBSET w`;;
+
+let LOCALLY_MONO = prove
+ (`!P Q s. (!t. P t ==> Q t) /\ locally P s ==> locally Q s`,
+  REWRITE_TAC[locally] THEN MESON_TAC[]);;
+
+let LOCALLY_OPEN_SUBSET = prove
+ (`!P s t:real^N->bool.
+        locally P s /\ open_in (subtopology euclidean s) t
+        ==> locally P t`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[locally] THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`w:real^N->bool`; `x:real^N`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`w:real^N->bool`; `x:real^N`]) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[OPEN_IN_TRANS]; ALL_TAC] THEN
+  REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC OPEN_IN_SUBSET_TRANS THEN
+  EXISTS_TAC `s:real^N->bool` THEN ASM_MESON_TAC[open_in; SUBSET]);;
+
+let LOCALLY_DIFF_CLOSED = prove
+ (`!P s t:real^N->bool.
+        locally P s /\ closed_in (subtopology euclidean s) t
+        ==> locally P (s DIFF t)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC LOCALLY_OPEN_SUBSET THEN
+  EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC OPEN_IN_DIFF THEN
+  ASM_REWRITE_TAC[OPEN_IN_SUBTOPOLOGY_REFL; SUBSET_UNIV; TOPSPACE_EUCLIDEAN]);;
+
+let LOCALLY_EMPTY = prove
+ (`!P. locally P {}`,
+  REWRITE_TAC[locally] THEN MESON_TAC[open_in; SUBSET; NOT_IN_EMPTY]);;
+
+let LOCALLY_SING = prove
+ (`!P a. locally P {a} <=> P {a}`,
+  REWRITE_TAC[locally; open_in] THEN
+  REWRITE_TAC[SET_RULE
+   `(w SUBSET {a} /\ P) /\ x IN w <=> w = {a} /\ x = a /\ P`] THEN
+  SIMP_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_UNWIND_THM2; IN_SING] THEN
+  REWRITE_TAC[SET_RULE
+   `(u SUBSET {a} /\ P) /\ Q /\ a IN u /\ u SUBSET v /\ v SUBSET {a} <=>
+    u = {a} /\ v = {a} /\ P /\ Q`] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM2; IN_SING] THEN
+  REWRITE_TAC[FORALL_UNWIND_THM2; MESON[REAL_LT_01] `?x. &0 < x`]);;
+
+let LOCALLY_INTER = prove
+ (`!P:(real^N->bool)->bool.
+        (!s t. P s /\ P t ==> P(s INTER t))
+        ==> !s t. locally P s /\ locally P t ==> locally P (s INTER t)`,
+  GEN_TAC THEN DISCH_TAC THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[locally; OPEN_IN_OPEN] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM; GSYM CONJ_ASSOC; MESON[]
+   `(!w x. (?t. P t /\ w = f t) /\ Q w x ==> R w x) <=>
+    (!t x. P t /\ Q (f t) x ==> R (f t) x)`] THEN
+  ONCE_REWRITE_TAC[MESON[]
+   `(?a b c. P a b c /\ Q a b c /\ R a b c) <=>
+    (?b c a. Q a b c /\ P a b c /\ R a b c)`] THEN
+  REWRITE_TAC[AND_FORALL_THM; UNWIND_THM2; IN_INTER] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `w:real^N->bool` THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:real^N` THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `u1:real^N->bool` (X_CHOOSE_THEN `v1:real^N->bool`
+        STRIP_ASSUME_TAC))
+   (X_CHOOSE_THEN `u2:real^N->bool` (X_CHOOSE_THEN `v2:real^N->bool`
+        STRIP_ASSUME_TAC))) THEN
+  EXISTS_TAC `u1 INTER u2:real^N->bool` THEN
+  EXISTS_TAC `v1 INTER v2:real^N->bool` THEN
+  ASM_SIMP_TAC[OPEN_INTER] THEN ASM SET_TAC[]);;
+
+let HOMEOMORPHISM_LOCALLY = prove
+ (`!P Q f:real^N->real^M g.
+        (!s t. homeomorphism (s,t) (f,g) ==> (P s <=> Q t))
+        ==> (!s t. homeomorphism (s,t) (f,g)
+                   ==> (locally P s <=> locally Q t))`,
+
+  let lemma = prove
+   (`!P Q f g.
+        (!s t. P s /\ homeomorphism (s,t) (f,g) ==> Q t)
+        ==> (!s:real^N->bool t:real^M->bool.
+                locally P s /\ homeomorphism (s,t) (f,g) ==> locally Q t)`,
+    REPEAT GEN_TAC THEN DISCH_TAC THEN REPEAT GEN_TAC THEN
+    REWRITE_TAC[locally] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [homeomorphism]) THEN
+    MAP_EVERY X_GEN_TAC [`w:real^M->bool`; `y:real^M`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`IMAGE (g:real^M->real^N) w`; `(g:real^M->real^N) y`]) THEN
+    ANTS_TAC THENL
+     [CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+      SUBGOAL_THEN `IMAGE (g:real^M->real^N) w =
+                     {x | x IN s /\ f(x) IN w}`
+      SUBST1_TAC THENL
+       [RULE_ASSUM_TAC(REWRITE_RULE[open_in]) THEN ASM SET_TAC[];
+        MATCH_MP_TAC CONTINUOUS_ON_IMP_OPEN_IN THEN ASM_REWRITE_TAC[]];
+      REWRITE_TAC[LEFT_IMP_EXISTS_THM]] THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `v:real^N->bool`] THEN
+    STRIP_TAC THEN MAP_EVERY EXISTS_TAC
+     [`IMAGE (f:real^N->real^M) u`; `IMAGE (f:real^N->real^M) v`] THEN
+    CONJ_TAC THENL
+     [SUBGOAL_THEN `IMAGE (f:real^N->real^M) u =
+                     {x | x IN t /\ g(x) IN u}`
+      SUBST1_TAC THENL
+       [RULE_ASSUM_TAC(REWRITE_RULE[open_in]) THEN ASM SET_TAC[];
+        MATCH_MP_TAC CONTINUOUS_ON_IMP_OPEN_IN THEN ASM_REWRITE_TAC[]];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [FIRST_X_ASSUM MATCH_MP_TAC THEN EXISTS_TAC `v:real^N->bool` THEN
+      ASM_REWRITE_TAC[homeomorphism] THEN
+      REWRITE_TAC[homeomorphism] THEN REPEAT CONJ_TAC THEN
+      TRY(FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)));
+      ALL_TAC] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[open_in]) THEN ASM SET_TAC[]) in
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM;
+        TAUT `p ==> q /\ r ==> s <=> p /\ r ==> q ==> s`] lemma) THEN
+  ASM_MESON_TAC[HOMEOMORPHISM_SYM]);;
+
+let HOMEOMORPHIC_LOCALLY = prove
+ (`!P Q. (!s:real^N->bool t:real^M->bool. s homeomorphic t ==> (P s <=> Q t))
+         ==> (!s t. s homeomorphic t ==> (locally P s <=> locally Q t))`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  REWRITE_TAC[homeomorphic; LEFT_IMP_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[MESON[]
+   `(!a b c d. P a b c d) <=> (!c d a b. P a b c d)`] THEN
+  GEN_TAC THEN GEN_TAC THEN MATCH_MP_TAC HOMEOMORPHISM_LOCALLY THEN
+  ASM_MESON_TAC[homeomorphic]);;
+
+let LOCALLY_TRANSLATION = prove
+ (`!P:(real^N->bool)->bool.
+        (!a s. P (IMAGE (\x. a + x) s) <=> P s)
+        ==> (!a s. locally P (IMAGE (\x. a + x) s) <=> locally P s)`,
+  GEN_TAC THEN MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  MP_TAC(ISPECL
+   [`P:(real^N->bool)->bool`; `P:(real^N->bool)->bool`;
+    `\x:real^N. a + x`; `\x:real^N. --a + x`]
+     HOMEOMORPHISM_LOCALLY) THEN
+  REWRITE_TAC[homeomorphism] THEN
+  SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+  REWRITE_TAC[FORALL_UNWIND_THM1; IMP_CONJ; GSYM IMAGE_o; o_DEF; IMAGE_ID;
+              VECTOR_ARITH `--a + a + x:real^N = x /\ a + --a + x = x`] THEN
+  MESON_TAC[]);;
+
+let LOCALLY_INJECTIVE_LINEAR_IMAGE = prove
+ (`!P:(real^N->bool)->bool Q:(real^M->bool)->bool.
+        (!f s. linear f /\ (!x y. f x = f y ==> x = y)
+               ==> (P (IMAGE f s) <=> Q s))
+        ==>  (!f s. linear f /\ (!x y. f x = f y ==> x = y)
+                    ==> (locally P (IMAGE f s) <=> locally Q s))`,
+  GEN_TAC THEN GEN_TAC THEN MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  ASM_CASES_TAC `linear(f:real^M->real^N) /\ (!x y. f x = f y ==> x = y)` THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+  REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^M` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`Q:(real^M->bool)->bool`; `P:(real^N->bool)->bool`;
+    `f:real^M->real^N`; `g:real^N->real^M`]
+     HOMEOMORPHISM_LOCALLY) THEN
+  ASM_SIMP_TAC[homeomorphism; LINEAR_CONTINUOUS_ON] THEN
+  ASM_REWRITE_TAC[FORALL_UNWIND_THM1; IMP_CONJ; FORALL_IN_IMAGE] THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID] THEN MESON_TAC[]);;
+
+let LOCALLY_OPEN_MAP_IMAGE = prove
+ (`!P Q 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 s /\ P t ==> Q(IMAGE f t)) /\
+        locally P s
+        ==> locally Q (IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[locally] THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`w:real^N->bool`; `y:real^N`] THEN
+  STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [open_in]) THEN
+  FIRST_ASSUM(MP_TAC o  SPEC `w:real^N->bool` o
+    GEN_REWRITE_RULE I [CONTINUOUS_ON_OPEN]) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `?x. x IN s /\ (f:real^M->real^N) x = y` STRIP_ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+   [`{x | x IN s /\ (f:real^M->real^N) x IN w}`; `x:real^M`]) THEN
+  ASM_REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^M->bool`; `v:real^M->bool`] THEN
+  STRIP_TAC THEN MAP_EVERY EXISTS_TAC
+   [`IMAGE (f:real^M->real^N) u`; `IMAGE (f:real^M->real^N) v`] THEN
+  ASM_SIMP_TAC[] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Important special cases of local connectedness & path connectedness.      *)
+(* ------------------------------------------------------------------------- *)
+
+let LOCALLY_CONNECTED,LOCALLY_CONNECTED_OPEN_CONNECTED_COMPONENT =
+ (CONJ_PAIR o prove)
+ (`(!s:real^N->bool.
+        locally connected s <=>
+        !v x. open_in (subtopology euclidean s) v /\ x IN v
+              ==> ?u. open_in (subtopology euclidean s) u /\
+                      connected u /\
+                      x IN u /\ u SUBSET v) /\
+   (!s:real^N->bool.
+        locally connected s <=>
+        !t x. open_in (subtopology euclidean s) t /\ x IN t
+              ==> open_in (subtopology euclidean s)
+                          (connected_component t x))`,
+  REWRITE_TAC[AND_FORALL_THM; locally] THEN X_GEN_TAC `s:real^N->bool` THEN
+  MATCH_MP_TAC(TAUT
+   `(q ==> p) /\ (p ==> r) /\ (r ==> q) ==> (p <=> q) /\ (p <=> r)`) THEN
+  REPEAT CONJ_TAC THENL
+   [MESON_TAC[SUBSET_REFL];
+    DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `y:real^N`] THEN STRIP_TAC THEN
+    ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP CONNECTED_COMPONENT_EQ) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`u:real^N->bool`; `x:real^N`]) THEN ANTS_TAC
+    THENL [ASM_MESON_TAC[CONNECTED_COMPONENT_SUBSET; SUBSET]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `v:real^N->bool` (X_CHOOSE_THEN `a:real^N->bool`
+          STRIP_ASSUME_TAC)) THEN
+    EXISTS_TAC `v:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `a:real^N->bool` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `x:real^N`] THEN STRIP_TAC THEN
+    EXISTS_TAC `connected_component u (x:real^N)` THEN
+    REWRITE_TAC[CONNECTED_COMPONENT_SUBSET; CONNECTED_CONNECTED_COMPONENT] THEN
+    ASM_SIMP_TAC[IN; CONNECTED_COMPONENT_REFL]]);;
+
+let LOCALLY_PATH_CONNECTED,LOCALLY_PATH_CONNECTED_OPEN_PATH_COMPONENT =
+ (CONJ_PAIR o prove)
+ (`(!s:real^N->bool.
+        locally path_connected s <=>
+        !v x. open_in (subtopology euclidean s) v /\ x IN v
+              ==> ?u. open_in (subtopology euclidean s) u /\
+                      path_connected u /\
+                      x IN u /\ u SUBSET v) /\
+   (!s:real^N->bool.
+        locally path_connected s <=>
+        !t x. open_in (subtopology euclidean s) t /\ x IN t
+              ==> open_in (subtopology euclidean s)
+                          (path_component t x))`,
+  REWRITE_TAC[AND_FORALL_THM; locally] THEN X_GEN_TAC `s:real^N->bool` THEN
+  MATCH_MP_TAC(TAUT
+   `(q ==> p) /\ (p ==> r) /\ (r ==> q) ==> (p <=> q) /\ (p <=> r)`) THEN
+  REPEAT CONJ_TAC THENL
+   [MESON_TAC[SUBSET_REFL];
+    DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `y:real^N`] THEN STRIP_TAC THEN
+    ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP PATH_COMPONENT_EQ) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`u:real^N->bool`; `x:real^N`]) THEN ANTS_TAC
+    THENL [ASM_MESON_TAC[PATH_COMPONENT_SUBSET; SUBSET]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `v:real^N->bool` (X_CHOOSE_THEN `a:real^N->bool`
+          STRIP_ASSUME_TAC)) THEN
+    EXISTS_TAC `v:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `a:real^N->bool` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC PATH_COMPONENT_MAXIMAL THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `x:real^N`] THEN STRIP_TAC THEN
+    EXISTS_TAC `path_component u (x:real^N)` THEN
+    REWRITE_TAC[PATH_COMPONENT_SUBSET; PATH_CONNECTED_PATH_COMPONENT] THEN
+    ASM_SIMP_TAC[IN; PATH_COMPONENT_REFL]]);;
+
+let LOCALLY_CONNECTED_OPEN_COMPONENT = prove
+ (`!s:real^N->bool.
+        locally connected s <=>
+        !t c. open_in (subtopology euclidean s) t /\ c IN components t
+              ==> open_in (subtopology euclidean s) c`,
+  REWRITE_TAC[LOCALLY_CONNECTED_OPEN_CONNECTED_COMPONENT] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; components; FORALL_IN_GSPEC]);;
+
+let LOCALLY_CONNECTED_IM_KLEINEN = prove
+ (`!s:real^N->bool.
+      locally connected s <=>
+      !v x. open_in (subtopology euclidean s) v /\ x IN v
+            ==> ?u. open_in (subtopology euclidean s) u /\
+                    x IN u /\ u SUBSET v /\
+                    !y. y IN u
+                        ==> ?c. connected c /\ c SUBSET v /\ x IN c /\ y IN c`,
+  GEN_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[LOCALLY_CONNECTED] THEN MESON_TAC[SUBSET_REFL]; DISCH_TAC] THEN
+  REWRITE_TAC[LOCALLY_CONNECTED_OPEN_COMPONENT] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `c:real^N->bool`] THEN STRIP_TAC THEN
+  ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`u:real^N->bool`; `x:real^N`]) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[IN_COMPONENTS_SUBSET; SUBSET]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `v:real^N->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] 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[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real^N->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `(k:real^N->bool) SUBSET c` MP_TAC THENL
+   [ALL_TAC; ASM SET_TAC[]] THEN
+  MATCH_MP_TAC COMPONENTS_MAXIMAL THEN
+  EXISTS_TAC `u:real^N->bool` THEN ASM SET_TAC[]);;
+
+let LOCALLY_PATH_CONNECTED_IM_KLEINEN = prove
+ (`!s:real^N->bool.
+      locally path_connected s <=>
+      !v x. open_in (subtopology euclidean s) v /\ x IN v
+            ==> ?u. open_in (subtopology euclidean s) u /\
+                    x IN u /\ u SUBSET v /\
+                    !y. y IN u
+                        ==> ?p. path p /\ path_image p SUBSET v /\
+                                pathstart p = x /\ pathfinish p = y`,
+  GEN_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[LOCALLY_PATH_CONNECTED] THEN
+    REWRITE_TAC[path_connected] THEN
+    REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+    MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    REWRITE_TAC[LOCALLY_PATH_CONNECTED_OPEN_PATH_COMPONENT] THEN DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `z:real^N`] THEN STRIP_TAC THEN
+    ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`u:real^N->bool`; `x:real^N`]) THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[PATH_COMPONENT_SUBSET; SUBSET]; ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `v:real^N->bool` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] 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[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `p:real^1->real^N` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `(path_image p) SUBSET path_component u (z:real^N)` MP_TAC
+    THENL [ALL_TAC; ASM_MESON_TAC[PATHFINISH_IN_PATH_IMAGE; SUBSET]] THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP PATH_COMPONENT_EQ) THEN
+    MATCH_MP_TAC PATH_COMPONENT_MAXIMAL THEN
+    ASM_SIMP_TAC[PATH_CONNECTED_PATH_IMAGE] THEN
+    ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE]]);;
+
+let LOCALLY_PATH_CONNECTED_IMP_LOCALLY_CONNECTED = prove
+ (`!s:real^N->bool. locally path_connected s ==> locally connected s`,
+  MESON_TAC[LOCALLY_MONO; PATH_CONNECTED_IMP_CONNECTED]);;
+
+let LOCALLY_CONNECTED_COMPONENTS = prove
+ (`!s c:real^N->bool.
+        locally connected s /\ c IN components s ==> locally connected c`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] LOCALLY_OPEN_SUBSET)) THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o
+   GEN_REWRITE_RULE I [LOCALLY_CONNECTED_OPEN_COMPONENT]) THEN
+  EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[OPEN_IN_REFL]);;
+
+let LOCALLY_CONNECTED_CONNECTED_COMPONENT = prove
+ (`!s x:real^N.
+        locally connected s
+        ==> locally connected (connected_component s x)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `connected_component s (x:real^N) = {}` THEN
+  ASM_REWRITE_TAC[LOCALLY_EMPTY] THEN
+  MATCH_MP_TAC LOCALLY_CONNECTED_COMPONENTS THEN
+  EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[IN_COMPONENTS] THEN
+  ASM_MESON_TAC[CONNECTED_COMPONENT_EQ_EMPTY]);;
+
+let LOCALLY_PATH_CONNECTED_COMPONENTS = prove
+ (`!s c:real^N->bool.
+        locally path_connected s /\ c IN components s
+        ==> locally path_connected c`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] LOCALLY_OPEN_SUBSET)) THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o
+   GEN_REWRITE_RULE I [LOCALLY_CONNECTED_OPEN_COMPONENT] o
+   MATCH_MP LOCALLY_PATH_CONNECTED_IMP_LOCALLY_CONNECTED) THEN
+  EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[OPEN_IN_REFL]);;
+
+let LOCALLY_PATH_CONNECTED_CONNECTED_COMPONENT = prove
+ (`!s x:real^N.
+        locally path_connected s
+        ==> locally path_connected (connected_component s x)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `connected_component s (x:real^N) = {}` THEN
+  ASM_REWRITE_TAC[LOCALLY_EMPTY] THEN
+  MATCH_MP_TAC LOCALLY_PATH_CONNECTED_COMPONENTS THEN
+  EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[IN_COMPONENTS] THEN
+  ASM_MESON_TAC[CONNECTED_COMPONENT_EQ_EMPTY]);;
+
+let OPEN_IMP_LOCALLY_PATH_CONNECTED = prove
+ (`!s:real^N->bool. open s ==> locally path_connected s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC LOCALLY_MONO THEN
+  EXISTS_TAC `convex:(real^N->bool)->bool` THEN
+  REWRITE_TAC[CONVEX_IMP_PATH_CONNECTED] THEN
+  ASM_SIMP_TAC[locally; OPEN_IN_OPEN_EQ] THEN
+  ASM_MESON_TAC[OPEN_CONTAINS_BALL; CENTRE_IN_BALL; OPEN_BALL; CONVEX_BALL;
+                SUBSET]);;
+
+let OPEN_IMP_LOCALLY_CONNECTED = prove
+ (`!s:real^N->bool. open s ==> locally connected s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC LOCALLY_MONO THEN
+  EXISTS_TAC `path_connected:(real^N->bool)->bool` THEN
+  ASM_SIMP_TAC[OPEN_IMP_LOCALLY_PATH_CONNECTED;
+               PATH_CONNECTED_IMP_CONNECTED]);;
+
+let LOCALLY_PATH_CONNECTED_UNIV = prove
+ (`locally path_connected (:real^N)`,
+  SIMP_TAC[OPEN_IMP_LOCALLY_PATH_CONNECTED; OPEN_UNIV]);;
+
+let LOCALLY_CONNECTED_UNIV = prove
+ (`locally connected (:real^N)`,
+  SIMP_TAC[OPEN_IMP_LOCALLY_CONNECTED; OPEN_UNIV]);;
+
+let OPEN_IN_CONNECTED_COMPONENT_LOCALLY_CONNECTED = prove
+ (`!s x:real^N.
+        locally connected s
+        ==> open_in (subtopology euclidean s) (connected_component s x)`,
+  REWRITE_TAC[LOCALLY_CONNECTED_OPEN_CONNECTED_COMPONENT] THEN
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `(x:real^N) IN s` THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[OPEN_IN_SUBTOPOLOGY_REFL; SUBSET_UNIV; TOPSPACE_EUCLIDEAN];
+    ASM_MESON_TAC[OPEN_IN_EMPTY; CONNECTED_COMPONENT_EQ_EMPTY]]);;
+
+let OPEN_IN_COMPONENTS_LOCALLY_CONNECTED = prove
+ (`!s c:real^N->bool.
+        locally connected s /\ c IN components s
+        ==> open_in (subtopology euclidean s) c`,
+  MESON_TAC[LOCALLY_CONNECTED_OPEN_COMPONENT; OPEN_IN_REFL]);;
+
+let OPEN_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED = prove
+ (`!s x:real^N.
+        locally path_connected s
+        ==> open_in (subtopology euclidean s) (path_component s x)`,
+  REWRITE_TAC[LOCALLY_PATH_CONNECTED_OPEN_PATH_COMPONENT] THEN
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `(x:real^N) IN s` THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[OPEN_IN_SUBTOPOLOGY_REFL; SUBSET_UNIV; TOPSPACE_EUCLIDEAN];
+    ASM_MESON_TAC[OPEN_IN_EMPTY; PATH_COMPONENT_EQ_EMPTY]]);;
+
+let CLOSED_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED = prove
+ (`!s x:real^N.
+        locally path_connected s
+        ==> closed_in (subtopology euclidean s) (path_component s x)`,
+  REWRITE_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY;
+              PATH_COMPONENT_SUBSET] THEN
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `s DIFF path_component s (x:real^N) =
+    UNIONS({path_component s y | y | y IN s} DELETE (path_component s x))`
+  SUBST1_TAC THENL
+   [GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM UNIONS_PATH_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[PATH_COMPONENT_DISJOINT; PATH_COMPONENT_EQ_EQ] THEN
+    MESON_TAC[IN; SUBSET; PATH_COMPONENT_SUBSET];
+    MATCH_MP_TAC OPEN_IN_UNIONS THEN
+    REWRITE_TAC[IMP_CONJ; FORALL_IN_GSPEC; IN_DELETE] THEN
+    ASM_SIMP_TAC[OPEN_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED]]);;
+
+let CONVEX_IMP_LOCALLY_PATH_CONNECTED = prove
+ (`!s:real^N->bool. convex s ==> locally path_connected s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[LOCALLY_PATH_CONNECTED] THEN
+  MAP_EVERY X_GEN_TAC [`v:real^N->bool`; `x:real^N`] THEN 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 SUBST_ALL_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_INTER]) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `s INTER ball(x:real^N,e)` THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[OPEN_IN_OPEN] THEN MESON_TAC[OPEN_BALL];
+    MATCH_MP_TAC CONVEX_IMP_PATH_CONNECTED THEN
+    ASM_SIMP_TAC[CONVEX_INTER; CONVEX_BALL];
+    ASM_REWRITE_TAC[IN_INTER; CENTRE_IN_BALL];
+    ASM SET_TAC[]]);;
+
+let OPEN_IN_CONNECTED_COMPONENTS = prove
+ (`!s c:real^N->bool.
+        FINITE(components s) /\ c IN components s
+        ==> open_in (subtopology euclidean s) c`,
+  REWRITE_TAC[components; IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC] THEN
+  SIMP_TAC[OPEN_IN_CONNECTED_COMPONENT]);;
+
+let FINITE_COMPONENTS = prove
+ (`!s:real^N->bool. compact s /\ locally connected s ==> FINITE(components s)`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM
+   (MP_TAC o GEN_REWRITE_RULE I [COMPACT_EQ_HEINE_BOREL_SUBTOPOLOGY]) THEN
+  DISCH_THEN(MP_TAC o SPEC `components(s:real^N->bool)`) THEN
+  REWRITE_TAC[GSYM UNIONS_COMPONENTS; SUBSET_REFL] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[OPEN_IN_COMPONENTS_LOCALLY_CONNECTED]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `components(s:real^N->bool) = f`
+   (fun th -> ASM_REWRITE_TAC[th]) THEN
+  ASM_CASES_TAC `?c:real^N->bool. c IN components s /\ ~(c IN f)` THENL
+   [FIRST_X_ASSUM(CHOOSE_THEN STRIP_ASSUME_TAC); ASM SET_TAC[]] THEN
+  SUBGOAL_THEN
+   `~(c:real^N->bool = {}) /\ c SUBSET UNIONS f /\ DISJOINT c (UNIONS f)`
+  MP_TAC THENL [ALL_TAC; SET_TAC[]] THEN REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[IN_COMPONENTS_NONEMPTY];
+    ASM_MESON_TAC[IN_COMPONENTS_SUBSET; SUBSET_TRANS];
+    REWRITE_TAC[DISJOINT; INTER_UNIONS; EMPTY_UNIONS; FORALL_IN_GSPEC] THEN
+    REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM DISJOINT] THEN
+    MATCH_MP_TAC(REWRITE_RULE[pairwise] PAIRWISE_DISJOINT_COMPONENTS) THEN
+    ASM_MESON_TAC[SUBSET]]);;
+
+let CONVEX_IMP_LOCALLY_CONNECTED = prove
+ (`!s:real^N->bool. convex s ==> locally connected s`,
+  MESON_TAC[CONVEX_IMP_LOCALLY_PATH_CONNECTED;
+            LOCALLY_PATH_CONNECTED_IMP_LOCALLY_CONNECTED]);;
+
+let HOMEOMORPHIC_LOCAL_CONNECTEDNESS = prove
+ (`!s t. s homeomorphic t ==> (locally connected s <=> locally connected t)`,
+  MATCH_MP_TAC HOMEOMORPHIC_LOCALLY THEN
+  REWRITE_TAC[HOMEOMORPHIC_CONNECTEDNESS]);;
+
+let HOMEOMORPHIC_LOCAL_PATH_CONNECTEDNESS = prove
+ (`!s t. s homeomorphic t
+         ==> (locally path_connected s <=> locally path_connected t)`,
+  MATCH_MP_TAC HOMEOMORPHIC_LOCALLY THEN
+  REWRITE_TAC[HOMEOMORPHIC_PATH_CONNECTEDNESS]);;
+
+let LOCALLY_PATH_CONNECTED_TRANSLATION_EQ = prove
+ (`!a:real^N s. locally path_connected (IMAGE (\x. a + x) s) <=>
+                locally path_connected s`,
+  MATCH_MP_TAC LOCALLY_TRANSLATION THEN
+  REWRITE_TAC[PATH_CONNECTED_TRANSLATION_EQ]);;
+
+add_translation_invariants [LOCALLY_PATH_CONNECTED_TRANSLATION_EQ];;
+
+let LOCALLY_CONNECTED_TRANSLATION_EQ = prove
+ (`!a:real^N s. locally connected (IMAGE (\x. a + x) s) <=>
+                locally connected s`,
+  MATCH_MP_TAC LOCALLY_TRANSLATION THEN
+  REWRITE_TAC[CONNECTED_TRANSLATION_EQ]);;
+
+add_translation_invariants [LOCALLY_CONNECTED_TRANSLATION_EQ];;
+
+let LOCALLY_PATH_CONNECTED_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (locally path_connected (IMAGE f s) <=> locally path_connected s)`,
+  MATCH_MP_TAC LOCALLY_INJECTIVE_LINEAR_IMAGE THEN
+  REWRITE_TAC[PATH_CONNECTED_LINEAR_IMAGE_EQ]);;
+
+add_linear_invariants [LOCALLY_PATH_CONNECTED_LINEAR_IMAGE_EQ];;
+
+let LOCALLY_CONNECTED_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (locally connected (IMAGE f s) <=> locally connected s)`,
+  MATCH_MP_TAC LOCALLY_INJECTIVE_LINEAR_IMAGE THEN
+  REWRITE_TAC[CONNECTED_LINEAR_IMAGE_EQ]);;
+
+add_linear_invariants [LOCALLY_CONNECTED_LINEAR_IMAGE_EQ];;
+
+let LOCALLY_CONNECTED_QUOTIENT_IMAGE = prove
+ (`!f:real^M->real^N s.
+      (!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)) /\
+      locally connected s
+      ==> locally connected (IMAGE f s)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[LOCALLY_CONNECTED_OPEN_COMPONENT] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `c:real^N->bool`] THEN
+  STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP IN_COMPONENTS_SUBSET) THEN
+  FIRST_ASSUM(ASSUME_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [open_in]) THEN
+  FIRST_ASSUM(MP_TAC o SPEC `c:real^N->bool`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN X_GEN_TAC `x:real^M` THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN EXISTS_TAC
+   `connected_component {w | w IN s /\ (f:real^M->real^N)(w) IN u} x` THEN
+  REPEAT CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o SPEC `u:real^N->bool`) THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ASM_REWRITE_TAC[]] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+     [LOCALLY_CONNECTED_OPEN_COMPONENT]) THEN
+    REWRITE_TAC[IMP_CONJ_ALT] THEN DISCH_THEN MATCH_MP_TAC THEN
+    REWRITE_TAC[IN_COMPONENTS; IN_ELIM_THM] THEN ASM SET_TAC[];
+    ALL_TAC;
+    ASSUME_TAC(ISPECL [`{w | w IN s /\ (f:real^M->real^N) w IN u}`; `x:real^M`]
+        CONNECTED_COMPONENT_SUBSET) THEN
+    SUBGOAL_THEN
+     `IMAGE (f:real^M->real^N) (connected_component {w | w IN s /\ f w IN u} x)
+      SUBSET c`
+    MP_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC COMPONENTS_MAXIMAL THEN EXISTS_TAC `u:real^N->bool` THEN
+    ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN
+      REWRITE_TAC[CONNECTED_CONNECTED_COMPONENT] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:real^M->bool` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[CONTINUOUS_ON_OPEN] THEN ASM_MESON_TAC[open_in];
+        ASM SET_TAC[]];
+      ASM SET_TAC[];
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+      EXISTS_TAC `(f:real^M->real^N) x` THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC FUN_IN_IMAGE]] THEN
+  GEN_REWRITE_TAC I [IN] THEN REWRITE_TAC[CONNECTED_COMPONENT_REFL_EQ] THEN
+  ASM SET_TAC[]);;
+
+let LOCALLY_PATH_CONNECTED_QUOTIENT_IMAGE = prove
+ (`!f:real^M->real^N s.
+      (!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)) /\
+      locally path_connected s
+      ==> locally path_connected (IMAGE f s)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[LOCALLY_PATH_CONNECTED_OPEN_PATH_COMPONENT] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `y:real^N`] THEN
+  STRIP_TAC THEN
+  ASSUME_TAC(ISPECL [`u:real^N->bool`; `y:real^N`] PATH_COMPONENT_SUBSET) THEN
+  FIRST_ASSUM(ASSUME_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [open_in]) THEN
+  FIRST_ASSUM(MP_TAC o SPEC `path_component u (y:real^N)`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN X_GEN_TAC `x:real^M` THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN EXISTS_TAC
+   `path_component {w | w IN s /\ (f:real^M->real^N)(w) IN u} x` THEN
+  REPEAT CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o SPEC `u:real^N->bool`) THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ASM_REWRITE_TAC[]] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+     [LOCALLY_PATH_CONNECTED_OPEN_PATH_COMPONENT]) THEN
+    REWRITE_TAC[IMP_CONJ_ALT] THEN DISCH_THEN MATCH_MP_TAC THEN ASM SET_TAC[];
+    ALL_TAC;
+    ASSUME_TAC(ISPECL [`{w | w IN s /\ (f:real^M->real^N) w IN u}`; `x:real^M`]
+        PATH_COMPONENT_SUBSET) THEN
+    SUBGOAL_THEN
+     `IMAGE (f:real^M->real^N) (path_component {w | w IN s /\ f w IN u} x)
+      SUBSET path_component u y`
+    MP_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP PATH_COMPONENT_EQ) THEN
+    MATCH_MP_TAC PATH_COMPONENT_MAXIMAL THEN
+    ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC FUN_IN_IMAGE;
+      MATCH_MP_TAC PATH_CONNECTED_CONTINUOUS_IMAGE THEN
+      REWRITE_TAC[PATH_CONNECTED_PATH_COMPONENT] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:real^M->bool` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[CONTINUOUS_ON_OPEN] THEN ASM_MESON_TAC[open_in];
+        ASM SET_TAC[]];
+      ASM SET_TAC[]]] THEN
+  GEN_REWRITE_TAC I [IN] THEN REWRITE_TAC[PATH_COMPONENT_REFL_EQ] THEN
+  ASM SET_TAC[]);;
+
+let LOCALLY_CONNECTED_CONTINUOUS_IMAGE_COMPACT = prove
+ (`!f:real^M->real^N s.
+        locally connected s /\ compact s /\ f continuous_on s
+        ==> locally connected (IMAGE f s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC LOCALLY_CONNECTED_QUOTIENT_IMAGE THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CLOSED_MAP_IMP_QUOTIENT_MAP THEN
+  ASM_SIMP_TAC[CLOSED_IN_CLOSED_EQ; COMPACT_IMP_CLOSED;
+               COMPACT_CONTINUOUS_IMAGE; IMAGE_SUBSET] THEN
+  ASM_MESON_TAC[COMPACT_IMP_CLOSED; COMPACT_CONTINUOUS_IMAGE;
+    CONTINUOUS_ON_SUBSET; BOUNDED_SUBSET; COMPACT_EQ_BOUNDED_CLOSED]);;
+
+let LOCALLY_PATH_CONNECTED_CONTINUOUS_IMAGE_COMPACT = prove
+ (`!f:real^M->real^N s.
+        locally path_connected s /\ compact s /\ f continuous_on s
+        ==> locally path_connected (IMAGE f s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC LOCALLY_PATH_CONNECTED_QUOTIENT_IMAGE THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CLOSED_MAP_IMP_QUOTIENT_MAP THEN
+  ASM_SIMP_TAC[CLOSED_IN_CLOSED_EQ; COMPACT_IMP_CLOSED;
+               COMPACT_CONTINUOUS_IMAGE; IMAGE_SUBSET] THEN
+  ASM_MESON_TAC[COMPACT_IMP_CLOSED; COMPACT_CONTINUOUS_IMAGE;
+    CONTINUOUS_ON_SUBSET; BOUNDED_SUBSET; COMPACT_EQ_BOUNDED_CLOSED]);;
+
+let LOCALLY_PATH_CONNECTED_PATH_IMAGE = prove
+ (`!p:real^1->real^N. path p ==> locally path_connected (path_image p)`,
+  REWRITE_TAC[path; path_image] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC LOCALLY_PATH_CONNECTED_CONTINUOUS_IMAGE_COMPACT THEN
+  ASM_SIMP_TAC[COMPACT_INTERVAL; CONVEX_INTERVAL;
+               CONVEX_IMP_LOCALLY_PATH_CONNECTED]);;
+
+let LOCALLY_CONNECTED_PATH_IMAGE = prove
+ (`!p:real^1->real^N. path p ==> locally connected (path_image p)`,
+  SIMP_TAC[LOCALLY_PATH_CONNECTED_PATH_IMAGE;
+           LOCALLY_PATH_CONNECTED_IMP_LOCALLY_CONNECTED]);;
+
+let LOCALLY_CONNECTED_LEFT_INVERTIBLE_IMAGE = 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) /\
+        locally connected s
+        ==> locally connected (IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LOCALLY_CONNECTED_QUOTIENT_IMAGE) THEN
+  MATCH_MP_TAC CONTINUOUS_LEFT_INVERSE_IMP_QUOTIENT_MAP THEN ASM_MESON_TAC[]);;
+
+let LOCALLY_CONNECTED_RIGHT_INVERTIBLE_IMAGE = prove
+ (`!f:real^M->real^N g s.
+        f continuous_on s /\ g continuous_on (IMAGE f s) /\
+        IMAGE g (IMAGE f s) SUBSET s /\ (!x. x IN IMAGE f s ==> f(g x) = x) /\
+        locally connected s
+        ==> locally connected (IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LOCALLY_CONNECTED_QUOTIENT_IMAGE) THEN
+  MATCH_MP_TAC CONTINUOUS_RIGHT_INVERSE_IMP_QUOTIENT_MAP THEN
+  EXISTS_TAC `g:real^N->real^M` THEN ASM SET_TAC[]);;
+
+let LOCALLY_PATH_CONNECTED_LEFT_INVERTIBLE_IMAGE = 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) /\
+        locally path_connected s
+        ==> locally path_connected (IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ]
+    LOCALLY_PATH_CONNECTED_QUOTIENT_IMAGE) THEN
+  MATCH_MP_TAC CONTINUOUS_LEFT_INVERSE_IMP_QUOTIENT_MAP THEN ASM_MESON_TAC[]);;
+
+let LOCALLY_PATH_CONNECTED_RIGHT_INVERTIBLE_IMAGE = prove
+ (`!f:real^M->real^N g s.
+        f continuous_on s /\ g continuous_on (IMAGE f s) /\
+        IMAGE g (IMAGE f s) SUBSET s /\ (!x. x IN IMAGE f s ==> f(g x) = x) /\
+        locally path_connected s
+        ==> locally path_connected (IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ]
+    LOCALLY_PATH_CONNECTED_QUOTIENT_IMAGE) THEN
+  MATCH_MP_TAC CONTINUOUS_RIGHT_INVERSE_IMP_QUOTIENT_MAP THEN
+  EXISTS_TAC `g:real^N->real^M` THEN ASM SET_TAC[]);;
+
+let LOCALLY_PCROSS = prove
+ (`!P Q R.
+        (!s:real^M->bool t:real^N->bool. P s /\ Q t ==> R(s PCROSS t))
+        ==> (!s t. locally P s /\ locally Q t ==> locally R (s PCROSS t))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[locally; FORALL_PASTECART] THEN
+  MAP_EVERY X_GEN_TAC
+   [`w:real^(M,N)finite_sum->bool`; `x:real^M`; `y:real^N`] THEN
+  DISCH_THEN(fun th -> STRIP_ASSUME_TAC th THEN
+   MP_TAC(MATCH_MP PASTECART_IN_INTERIOR_SUBTOPOLOGY
+        (ONCE_REWRITE_RULE[CONJ_SYM] th))) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^M->bool`; `v:real^N->bool`] THEN
+  STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`u:real^M->bool`; `x:real^M`] o
+    GEN_REWRITE_RULE I [locally]) THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`v:real^N->bool`; `y:real^N`] o
+    GEN_REWRITE_RULE I [locally]) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`v':real^N->bool`; `v'':real^N->bool`] THEN
+  STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`u':real^M->bool`; `u'':real^M->bool`] THEN
+  STRIP_TAC THEN
+  EXISTS_TAC `(u':real^M->bool) PCROSS (v':real^N->bool)` THEN
+  EXISTS_TAC `(u'':real^M->bool) PCROSS (v'':real^N->bool)` THEN
+  ASM_SIMP_TAC[PASTECART_IN_PCROSS; PCROSS_MONO; OPEN_IN_PCROSS] THEN
+  ASM_MESON_TAC[PCROSS_MONO; SUBSET_TRANS]);;
+
+let LOCALLY_CONNECTED_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        locally connected s /\ locally connected t
+        ==> locally connected (s PCROSS t)`,
+  MATCH_MP_TAC LOCALLY_PCROSS THEN REWRITE_TAC[CONNECTED_PCROSS]);;
+
+let LOCALLY_PATH_CONNECTED_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        locally path_connected s /\ locally path_connected t
+        ==> locally path_connected (s PCROSS t)`,
+  MATCH_MP_TAC LOCALLY_PCROSS THEN REWRITE_TAC[PATH_CONNECTED_PCROSS]);;
+
+let LOCALLY_CONNECTED_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        locally connected (s PCROSS t) <=>
+        s = {} \/ t = {} \/ locally connected s /\ locally connected t`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; LOCALLY_EMPTY] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; LOCALLY_EMPTY] THEN
+  EQ_TAC THEN REWRITE_TAC[LOCALLY_CONNECTED_PCROSS] THEN
+  GEN_REWRITE_TAC LAND_CONV [LOCALLY_CONNECTED] THEN DISCH_TAC THEN
+  REWRITE_TAC[LOCALLY_CONNECTED_IM_KLEINEN] THEN CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`u:real^M->bool`; `x:real^M`] THEN STRIP_TAC THEN
+    UNDISCH_TAC `~(t:real^N->bool = {})` THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `y:real^N`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`(u:real^M->bool) PCROSS (t:real^N->bool)`;
+      `pastecart (x:real^M) (y:real^N)`]);
+    MAP_EVERY X_GEN_TAC [`v:real^N->bool`; `y:real^N`] THEN STRIP_TAC THEN
+    UNDISCH_TAC `~(s:real^M->bool = {})` THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `x:real^M`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`(s:real^M->bool) PCROSS (v:real^N->bool)`;
+      `pastecart (x:real^M) (y:real^N)`])] THEN
+  ASM_SIMP_TAC[OPEN_IN_PCROSS_EQ; PASTECART_IN_PCROSS; SUBSET_UNIV;
+    OPEN_IN_SUBTOPOLOGY_REFL; TOPSPACE_EUCLIDEAN; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `w:real^(M,N)finite_sum->bool` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`s:real^M->bool`; `t:real^N->bool`; `w:real^(M,N)finite_sum->bool`;
+    `x:real^M`; `y:real^N`] PASTECART_IN_INTERIOR_SUBTOPOLOGY) THEN
+  ASM_REWRITE_TAC[] THENL
+   [MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u':real^M->bool` THEN
+    DISCH_THEN(X_CHOOSE_THEN `v:real^N->bool` STRIP_ASSUME_TAC) THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ALL_TAC;
+      X_GEN_TAC `z:real^M` THEN DISCH_TAC THEN
+      EXISTS_TAC `IMAGE fstcart (w:real^(M,N)finite_sum->bool)` THEN
+      ASM_SIMP_TAC[CONNECTED_LINEAR_IMAGE; LINEAR_FSTCART] THEN
+      REWRITE_TAC[SUBSET; IN_IMAGE; EXISTS_PASTECART; FSTCART_PASTECART]];
+    DISCH_THEN(X_CHOOSE_THEN `u:real^M->bool` MP_TAC) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `v':real^N->bool` THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ALL_TAC;
+      X_GEN_TAC `z:real^N` THEN DISCH_TAC THEN
+      EXISTS_TAC `IMAGE sndcart (w:real^(M,N)finite_sum->bool)` THEN
+      ASM_SIMP_TAC[CONNECTED_LINEAR_IMAGE; LINEAR_SNDCART] THEN
+      REWRITE_TAC[SUBSET; IN_IMAGE; EXISTS_PASTECART; SNDCART_PASTECART]]] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE
+   [SUBSET; FORALL_IN_PCROSS; PASTECART_IN_PCROSS; FORALL_PASTECART]) THEN
+  ASM SET_TAC[]);;
+
+let LOCALLY_PATH_CONNECTED_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        locally path_connected (s PCROSS t) <=>
+        s = {} \/ t = {} \/
+        locally path_connected s /\ locally path_connected t`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; LOCALLY_EMPTY] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; LOCALLY_EMPTY] THEN
+  EQ_TAC THEN REWRITE_TAC[LOCALLY_PATH_CONNECTED_PCROSS] THEN
+  GEN_REWRITE_TAC LAND_CONV [LOCALLY_PATH_CONNECTED] THEN DISCH_TAC THEN
+  REWRITE_TAC[LOCALLY_PATH_CONNECTED_IM_KLEINEN] THEN CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`u:real^M->bool`; `x:real^M`] THEN STRIP_TAC THEN
+    UNDISCH_TAC `~(t:real^N->bool = {})` THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `y:real^N`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`(u:real^M->bool) PCROSS (t:real^N->bool)`;
+      `pastecart (x:real^M) (y:real^N)`]);
+    MAP_EVERY X_GEN_TAC [`v:real^N->bool`; `y:real^N`] THEN STRIP_TAC THEN
+    UNDISCH_TAC `~(s:real^M->bool = {})` THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `x:real^M`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`(s:real^M->bool) PCROSS (v:real^N->bool)`;
+      `pastecart (x:real^M) (y:real^N)`])] THEN
+  ASM_SIMP_TAC[OPEN_IN_PCROSS_EQ; PASTECART_IN_PCROSS; SUBSET_UNIV;
+    OPEN_IN_SUBTOPOLOGY_REFL; TOPSPACE_EUCLIDEAN; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `w:real^(M,N)finite_sum->bool` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`s:real^M->bool`; `t:real^N->bool`; `w:real^(M,N)finite_sum->bool`;
+    `x:real^M`; `y:real^N`] PASTECART_IN_INTERIOR_SUBTOPOLOGY) THEN
+  ASM_REWRITE_TAC[] THENL
+   [MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u':real^M->bool` THEN
+    DISCH_THEN(X_CHOOSE_THEN `v:real^N->bool` STRIP_ASSUME_TAC) THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ALL_TAC;
+      X_GEN_TAC `z:real^M` THEN DISCH_TAC THEN
+      MP_TAC(ISPECL [`fstcart:real^(M,N)finite_sum->real^M`;
+                     `w:real^(M,N)finite_sum->bool`]
+        PATH_CONNECTED_LINEAR_IMAGE) THEN ASM_REWRITE_TAC[LINEAR_FSTCART] THEN
+      REWRITE_TAC[path_connected] THEN
+      DISCH_THEN(MP_TAC o SPECL [`x:real^M`; `z:real^M`]) THEN ANTS_TAC THENL
+       [REWRITE_TAC[IN_IMAGE; EXISTS_PASTECART; FSTCART_PASTECART];
+        MATCH_MP_TAC MONO_EXISTS THEN
+        REWRITE_TAC[SUBSET; IN_IMAGE; EXISTS_PASTECART; FSTCART_PASTECART] THEN
+        REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[]]];
+    DISCH_THEN(X_CHOOSE_THEN `u:real^M->bool` MP_TAC) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `v':real^N->bool` THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ALL_TAC;
+      X_GEN_TAC `z:real^N` THEN DISCH_TAC THEN
+      MP_TAC(ISPECL [`sndcart:real^(M,N)finite_sum->real^N`;
+                     `w:real^(M,N)finite_sum->bool`]
+        PATH_CONNECTED_LINEAR_IMAGE) THEN ASM_REWRITE_TAC[LINEAR_SNDCART] THEN
+      REWRITE_TAC[path_connected] THEN
+      DISCH_THEN(MP_TAC o SPECL [`y:real^N`; `z:real^N`]) THEN ANTS_TAC THENL
+       [REWRITE_TAC[IN_IMAGE; EXISTS_PASTECART; SNDCART_PASTECART];
+        MATCH_MP_TAC MONO_EXISTS THEN
+        REWRITE_TAC[SUBSET; IN_IMAGE; EXISTS_PASTECART; SNDCART_PASTECART] THEN
+        REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[]]]] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE
+   [SUBSET; FORALL_IN_PCROSS; PASTECART_IN_PCROSS; FORALL_PASTECART]) THEN
+  ASM SET_TAC[]);;
+
+let CARD_EQ_OPEN_IN = prove
+ (`!u s:real^N->bool.
+      locally connected u /\
+      open_in (subtopology euclidean u) s /\
+      (?x. x IN s /\ x limit_point_of u)
+      ==> s =_c (:real)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM CARD_LE_ANTISYM] THEN CONJ_TAC THENL
+   [TRANS_TAC CARD_LE_TRANS `(:real^N)` THEN
+    SIMP_TAC[CARD_EQ_IMP_LE; CARD_EQ_EUCLIDEAN] THEN
+    MATCH_MP_TAC CARD_LE_SUBSET THEN REWRITE_TAC[SUBSET_UNIV];
+    ALL_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
+  UNDISCH_TAC `(x:real^N) IN s` THEN ASM_REWRITE_TAC[IN_INTER] THEN
+  STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LOCALLY_CONNECTED]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`u INTER t:real^N->bool`; `x:real^N`]) THEN
+  ASM_SIMP_TAC[OPEN_IN_OPEN_INTER; IN_INTER] THEN
+  REWRITE_TAC[OPEN_IN_OPEN; GSYM CONJ_ASSOC; LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> q /\ p /\ r`] THEN
+  REWRITE_TAC[UNWIND_THM2; IN_INTER] THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:real^N->bool` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [limit_point_of]) THEN
+  DISCH_THEN(MP_TAC o SPEC `t INTER v:real^N->bool`) THEN
+  ASM_SIMP_TAC[IN_INTER; OPEN_INTER] THEN
+  DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC) THEN
+  TRANS_TAC CARD_LE_TRANS `u INTER v:real^N->bool` THEN
+  ASM_SIMP_TAC[CARD_LE_SUBSET] THEN MATCH_MP_TAC CARD_EQ_IMP_LE THEN
+  ONCE_REWRITE_TAC[CARD_EQ_SYM] THEN MATCH_MP_TAC CARD_EQ_CONNECTED THEN
+  ASM SET_TAC[]);;
+
+let CARD_EQ_OPEN_IN_AFFINE = prove
+ (`!u s:real^N->bool.
+        affine u /\ ~(aff_dim u = &0) /\
+        open_in (subtopology euclidean u) s /\ ~(s = {})
+        ==> s =_c (:real)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CARD_EQ_OPEN_IN THEN
+  EXISTS_TAC `u:real^N->bool` THEN
+  ASM_SIMP_TAC[CONVEX_IMP_LOCALLY_CONNECTED; AFFINE_IMP_CONVEX] 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
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONNECTED_IMP_PERFECT_AFF_DIM THEN
+  ASM_SIMP_TAC[AFFINE_IMP_CONVEX; CONVEX_CONNECTED] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic properties of local compactness.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let LOCALLY_COMPACT = prove
+ (`!s:real^N->bool.
+        locally compact s <=>
+        !x. x IN s ==> ?u v. x IN u /\ u SUBSET v /\ v SUBSET s /\
+                             open_in (subtopology euclidean s) u /\
+                             compact v`,
+  GEN_TAC THEN REWRITE_TAC[locally] THEN EQ_TAC THEN DISCH_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN FIRST_X_ASSUM
+     (MP_TAC o SPECL [`s INTER ball(x:real^N,&1)`; `x:real^N`]) THEN
+    ASM_SIMP_TAC[OPEN_IN_OPEN_INTER; OPEN_BALL] THEN
+    ASM_REWRITE_TAC[IN_INTER; CENTRE_IN_BALL; REAL_LT_01] THEN
+    MESON_TAC[SUBSET_INTER];
+    MAP_EVERY X_GEN_TAC [`w:real^N->bool`; `x:real^N`] THEN
+    REWRITE_TAC[IMP_CONJ] THEN GEN_REWRITE_TAC LAND_CONV [OPEN_IN_OPEN] THEN
+    DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+    ASM_REWRITE_TAC[IN_INTER] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `v:real^N->bool`] THEN
+    STRIP_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` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(s INTER ball(x:real^N,e)) INTER u` THEN
+    EXISTS_TAC `cball(x:real^N,e) INTER v` THEN
+    ASM_SIMP_TAC[OPEN_IN_INTER; OPEN_IN_OPEN_INTER; OPEN_BALL; CENTRE_IN_BALL;
+                 COMPACT_INTER; COMPACT_CBALL; IN_INTER] THEN
+    MP_TAC(ISPECL [`x:real^N`; `e:real`] BALL_SUBSET_CBALL) THEN
+    ASM SET_TAC[]]);;
+
+let OPEN_IMP_LOCALLY_COMPACT = prove
+ (`!s:real^N->bool. open s ==> locally compact s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[LOCALLY_COMPACT] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN FIRST_ASSUM
+   (MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+  ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  MAP_EVERY EXISTS_TAC [`ball(x:real^N,e)`; `cball(x:real^N,e)`] THEN
+  ASM_REWRITE_TAC[BALL_SUBSET_CBALL; CENTRE_IN_BALL; COMPACT_CBALL] THEN
+  MATCH_MP_TAC OPEN_OPEN_IN_TRANS THEN ASM_REWRITE_TAC[OPEN_BALL] THEN
+  ASM_MESON_TAC[BALL_SUBSET_CBALL; SUBSET_TRANS]);;
+
+let CLOSED_IMP_LOCALLY_COMPACT = prove
+ (`!s:real^N->bool. closed s ==> locally compact s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[LOCALLY_COMPACT] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN MAP_EVERY EXISTS_TAC
+   [`s INTER ball(x:real^N,&1)`; `s INTER cball(x:real^N,&1)`] THEN
+  ASM_REWRITE_TAC[IN_INTER; CENTRE_IN_BALL; INTER_SUBSET; REAL_LT_01] THEN
+  ASM_SIMP_TAC[OPEN_IN_OPEN_INTER; OPEN_BALL] THEN
+  ASM_SIMP_TAC[CLOSED_INTER_COMPACT; COMPACT_CBALL] THEN
+  MP_TAC(ISPECL [`x:real^N`; `&1`] BALL_SUBSET_CBALL) THEN ASM SET_TAC[]);;
+
+let IS_INTERVAL_IMP_LOCALLY_COMPACT = prove
+ (`!s:real^N->bool. is_interval s ==> locally compact s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[LOCALLY_COMPACT] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `x:real^N`]
+   INTERVAL_CONTAINS_COMPACT_NEIGHBOURHOOD) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`; `d:real`] THEN STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC
+   [`s INTER ball(x:real^N,d)`; `interval[a:real^N,b]`] THEN
+  ASM_SIMP_TAC[COMPACT_INTERVAL; OPEN_IN_OPEN_INTER; OPEN_BALL] THEN
+  ASM_REWRITE_TAC[CENTRE_IN_BALL; IN_INTER] THEN ASM SET_TAC[]);;
+
+let LOCALLY_COMPACT_UNIV = prove
+ (`locally compact (:real^N)`,
+  SIMP_TAC[OPEN_IMP_LOCALLY_COMPACT; OPEN_UNIV]);;
+
+let LOCALLY_COMPACT_INTER = prove
+ (`!s t:real^N->bool.
+        locally compact s /\ locally compact t
+        ==> locally compact (s INTER t)`,
+  MATCH_MP_TAC LOCALLY_INTER THEN REWRITE_TAC[COMPACT_INTER]);;
+
+let LOCALLY_COMPACT_OPEN_IN = prove
+ (`!s t:real^N->bool.
+        open_in (subtopology euclidean s) t /\ locally compact s
+        ==> locally compact t`,
+  REWRITE_TAC[OPEN_IN_OPEN] THEN REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[LOCALLY_COMPACT_INTER; OPEN_IMP_LOCALLY_COMPACT]);;
+
+let LOCALLY_COMPACT_CLOSED_IN = prove
+ (`!s t:real^N->bool.
+        closed_in (subtopology euclidean s) t /\ locally compact s
+        ==> locally compact t`,
+  REWRITE_TAC[CLOSED_IN_CLOSED] THEN REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[LOCALLY_COMPACT_INTER; CLOSED_IMP_LOCALLY_COMPACT]);;
+
+let SIGMA_COMPACT = prove
+ (`!s:real^N->bool.
+        locally compact s
+        ==> ?f. COUNTABLE f /\ (!t. t IN f ==> compact t) /\ UNIONS f = s`,
+  GEN_TAC THEN REWRITE_TAC[LOCALLY_COMPACT] THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N->real^N->bool`; `c:real^N->real^N->bool`] THEN
+  DISCH_TAC THEN
+  MP_TAC(ISPECL [`IMAGE (u:real^N->real^N->bool) s`; `s:real^N->bool`]
+   LINDELOF_OPEN_IN) THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE] THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> q /\ p /\ r`] THEN
+  REWRITE_TAC[EXISTS_COUNTABLE_SUBSET_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `IMAGE (c:real^N->real^N->bool) t` THEN
+  REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ; FORALL_IN_IMAGE; FORALL_IN_UNIONS] THEN
+  ASM_SIMP_TAC[COUNTABLE_IMAGE] THEN ASM SET_TAC[]);;
+
+let HOMEOMORPHIC_LOCAL_COMPACTNESS = prove
+ (`!s t:real^N->bool.
+        s homeomorphic t ==> (locally compact s <=> locally compact t)`,
+  MATCH_MP_TAC HOMEOMORPHIC_LOCALLY THEN
+  REWRITE_TAC[HOMEOMORPHIC_COMPACTNESS]);;
+
+let LOCALLY_COMPACT_TRANSLATION_EQ = prove
+ (`!a:real^N s. locally compact (IMAGE (\x. a + x) s) <=>
+                locally compact s`,
+  MATCH_MP_TAC LOCALLY_TRANSLATION THEN
+  REWRITE_TAC[COMPACT_TRANSLATION_EQ]);;
+
+add_translation_invariants [LOCALLY_COMPACT_TRANSLATION_EQ];;
+
+let LOCALLY_COMPACT_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (locally compact (IMAGE f s) <=> locally compact s)`,
+  MATCH_MP_TAC LOCALLY_INJECTIVE_LINEAR_IMAGE THEN
+  REWRITE_TAC[COMPACT_LINEAR_IMAGE_EQ]);;
+
+add_linear_invariants [LOCALLY_COMPACT_LINEAR_IMAGE_EQ];;
+
+let LOCALLY_CLOSED = prove
+ (`!s:real^N->bool. locally closed s <=> locally compact s`,
+  GEN_TAC THEN EQ_TAC THENL
+   [ALL_TAC; MESON_TAC[LOCALLY_MONO; COMPACT_IMP_CLOSED]] THEN
+  REWRITE_TAC[locally] THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`w:real^N->bool`; `x:real^N`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`w:real^N->bool`; `x:real^N`]) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `v:real^N->bool`] THEN
+  STRIP_TAC THEN
+  EXISTS_TAC `u INTER ball(x:real^N,&1)` THEN
+  EXISTS_TAC `v INTER cball(x:real^N,&1)` THEN
+  ASM_SIMP_TAC[OPEN_IN_INTER_OPEN; OPEN_BALL] THEN
+  ASM_SIMP_TAC[CLOSED_INTER_COMPACT; COMPACT_CBALL] THEN
+  ASM_REWRITE_TAC[IN_INTER; CENTRE_IN_BALL; REAL_LT_01] THEN
+  MP_TAC(ISPEC `x:real^N` BALL_SUBSET_CBALL) THEN ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Locally compact sets are closed in an open set and are homeomorphic       *)
+(* to an absolutely closed set if we have one more dimension to play with.   *)
+(* ------------------------------------------------------------------------- *)
+
+let LOCALLY_COMPACT_OPEN_INTER_CLOSURE = prove
+ (`!s:real^N->bool. locally compact s ==> ?t. open t /\ s = t INTER closure s`,
+  GEN_TAC THEN SIMP_TAC[LOCALLY_COMPACT; OPEN_IN_OPEN; CLOSED_IN_CLOSED] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM; RIGHT_AND_EXISTS_THM] THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC; TAUT `p /\ x = y /\ q <=> x = y /\ p /\ q`] THEN
+  ONCE_REWRITE_TAC[MESON[] `(?a b c. P a b c) <=> (?c b a. P a b c)`] THEN
+  REWRITE_TAC[UNWIND_THM2] THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N->real^N->bool`; `v:real^N->real^N->bool`] THEN
+  DISCH_TAC THEN EXISTS_TAC `UNIONS (IMAGE (u:real^N->real^N->bool) s)` THEN
+  ASM_SIMP_TAC[CLOSED_CLOSURE; OPEN_UNIONS; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[INTER_UNIONS] THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `UNIONS {v INTER s | v | v IN IMAGE (u:real^N->real^N->bool) s}` THEN
+  CONJ_TAC THENL
+   [SIMP_TAC[UNIONS_GSPEC; EXISTS_IN_IMAGE] THEN ASM SET_TAC[]; ALL_TAC] THEN
+  AP_TERM_TAC THEN MATCH_MP_TAC(SET_RULE
+   `(!x. x IN s ==> f(g x) = f'(g x))
+    ==> {f x | x IN IMAGE g s} = {f' x | x IN IMAGE g s}`) THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN CONJ_TAC THENL
+   [MP_TAC(ISPEC `s:real^N->bool` CLOSURE_SUBSET) THEN ASM SET_TAC[];
+  REWRITE_TAC[SUBSET_INTER; INTER_SUBSET] THEN MATCH_MP_TAC  SUBSET_TRANS THEN
+  EXISTS_TAC `closure((u:real^N->real^N->bool) x INTER s)` THEN
+  ASM_SIMP_TAC[OPEN_INTER_CLOSURE_SUBSET] THEN MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `(v:real^N->real^N->bool) x` THEN
+  ASM_SIMP_TAC[] THEN MATCH_MP_TAC CLOSURE_MINIMAL THEN
+  ASM_SIMP_TAC[COMPACT_IMP_CLOSED] THEN ASM SET_TAC[]]);;
+
+let LOCALLY_COMPACT_CLOSED_IN_OPEN = prove
+ (`!s:real^N->bool.
+    locally compact s ==> ?t. open t /\ closed_in (subtopology euclidean t) s`,
+  GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LOCALLY_COMPACT_OPEN_INTER_CLOSURE) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real^N->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM SUBST1_TAC THEN
+  SIMP_TAC[CLOSED_IN_CLOSED_INTER; CLOSED_CLOSURE]);;
+
+let LOCALLY_COMPACT_HOMEOMORPHISM_PROJECTION_CLOSED = prove
+ (`!s:real^M->bool.
+        locally compact s
+        ==> ?t:real^(M,N)finite_sum->bool f.
+                closed t /\ homeomorphism (s,t) (f,fstcart)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `closed(s:real^M->bool)` THENL
+   [EXISTS_TAC `(s:real^M->bool) PCROSS {vec 0:real^N}` THEN
+    EXISTS_TAC `\x. (pastecart x (vec 0):real^(M,N)finite_sum)` THEN
+    ASM_SIMP_TAC[CLOSED_PCROSS; CLOSED_SING; HOMEOMORPHISM] THEN
+    SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID;
+      LINEAR_FSTCART; LINEAR_CONTINUOUS_ON; SUBSET; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[FORALL_IN_PCROSS; PASTECART_IN_PCROSS; IN_SING] THEN
+    SIMP_TAC[FSTCART_PASTECART];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP LOCALLY_COMPACT_OPEN_INTER_CLOSURE) THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^M->bool` (STRIP_ASSUME_TAC o GSYM)) THEN
+  DISJ_CASES_TAC(SET_RULE `t = (:real^M) \/ ~((:real^M) DIFF t = {})`) THENL
+   [ASM_MESON_TAC[CLOSURE_EQ; INTER_UNIV]; ALL_TAC] THEN
+  ABBREV_TAC
+   `f:real^M->real^(M,N)finite_sum =
+      \x. pastecart x (inv(setdist({x},(:real^M) DIFF t)) % vec 1)` THEN
+  SUBGOAL_THEN
+   `homeomorphism (t,IMAGE (f:real^M->real^(M,N)finite_sum) t) (f,fstcart)`
+  ASSUME_TAC THENL
+   [SIMP_TAC[HOMEOMORPHISM; SUBSET_REFL; LINEAR_CONTINUOUS_ON;
+             LINEAR_FSTCART; FORALL_IN_IMAGE] THEN
+    MATCH_MP_TAC(TAUT `(r ==> q /\ s) /\ r /\ p ==> p /\ q /\ r /\ s`) THEN
+    CONJ_TAC THENL [SET_TAC[]; EXPAND_TAC "f"] THEN
+    SIMP_TAC[FSTCART_PASTECART] THEN MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+    REWRITE_TAC[CONTINUOUS_ON_ID] THEN MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+    REWRITE_TAC[o_DEF; CONTINUOUS_ON_CONST] THEN
+    MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
+    REWRITE_TAC[SETDIST_EQ_0_SING; CONTINUOUS_ON_LIFT_SETDIST] THEN
+    ASM_SIMP_TAC[CLOSURE_COMPLEMENT; IN_DIFF; IN_UNIV; INTERIOR_OPEN];
+    ALL_TAC] THEN
+  EXISTS_TAC `IMAGE (f:real^M->real^(M,N)finite_sum) s` THEN
+  EXISTS_TAC `f:real^M->real^(M,N)finite_sum` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CLOSED_IN_CLOSED_TRANS THEN
+    EXISTS_TAC `IMAGE (f:real^M->real^(M,N)finite_sum) t` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HOMEOMORPHISM_IMP_CLOSED_MAP THEN MAP_EVERY EXISTS_TAC
+       [`fstcart:real^(M,N)finite_sum->real^M`; `t:real^M->bool`] THEN
+      ASM_REWRITE_TAC[] THEN EXPAND_TAC "s" THEN
+      SIMP_TAC[CLOSED_IN_CLOSED_INTER; CLOSED_CLOSURE];
+      SUBGOAL_THEN
+       `IMAGE (f:real^M->real^(M,N)finite_sum) t =
+        {z | (setdist({fstcart z},(:real^M) DIFF t) % sndcart z) IN {vec 1}}`
+      SUBST1_TAC THENL
+       [EXPAND_TAC "f" THEN
+        REWRITE_TAC[EXTENSION; FORALL_PASTECART; IN_ELIM_THM; PASTECART_INJ;
+                    FSTCART_PASTECART; SNDCART_PASTECART; IN_IMAGE; IN_INTER;
+                    GSYM CONJ_ASSOC; UNWIND_THM1; IN_SING] THEN
+        REWRITE_TAC[CART_EQ; VECTOR_MUL_COMPONENT; VEC_COMPONENT] THEN
+        MAP_EVERY X_GEN_TAC [`x:real^M`; `y:real^N`] THEN
+        MP_TAC(ISPECL [`(:real^M) DIFF t`; `x:real^M`]
+          (CONJUNCT1 SETDIST_EQ_0_SING)) THEN
+        ASM_SIMP_TAC[CLOSURE_COMPLEMENT; IN_DIFF; IN_UNIV; INTERIOR_OPEN] THEN
+        ASM_CASES_TAC `(x:real^M) IN t` THEN ASM_SIMP_TAC[REAL_FIELD
+         `~(x = &0) ==> (y = inv x * &1 <=> x * y = &1)`] THEN
+        DISCH_TAC THEN DISCH_THEN(MP_TAC o SPEC `1`) THEN
+        REWRITE_TAC[LE_REFL; DIMINDEX_GE_1] THEN REAL_ARITH_TAC;
+        MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE_UNIV THEN
+        REWRITE_TAC[CLOSED_SING] THEN X_GEN_TAC `z:real^(M,N)finite_sum` THEN
+        MATCH_MP_TAC CONTINUOUS_MUL THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_AT; LINEAR_SNDCART; o_DEF] THEN
+        SUBGOAL_THEN
+         `(\z:real^(M,N)finite_sum.
+             lift(setdist({fstcart z},(:real^M) DIFF t))) =
+          (\x. lift (setdist ({x},(:real^M) DIFF t))) o fstcart`
+        SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+        MATCH_MP_TAC CONTINUOUS_AT_COMPOSE THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_AT; LINEAR_FSTCART] THEN
+        REWRITE_TAC[CONTINUOUS_AT_LIFT_SETDIST]]];
+    MATCH_MP_TAC HOMEOMORPHISM_OF_SUBSETS THEN MAP_EVERY EXISTS_TAC
+     [`t:real^M->bool`; `IMAGE (f:real^M->real^(M,N)finite_sum) t`] THEN
+    ASM SET_TAC[]]);;
+
+let LOCALLY_COMPACT_HOMEOMORPHIC_CLOSED = prove
+ (`!s:real^M->bool.
+        locally compact s /\ dimindex(:M) < dimindex(:N)
+        ==> ?t:real^N->bool. closed t /\ s homeomorphic t`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+   `?t:real^(M,1)finite_sum->bool h.
+            closed t /\ homeomorphism (s,t) (h,fstcart)`
+  STRIP_ASSUME_TAC THENL
+   [ASM_SIMP_TAC[LOCALLY_COMPACT_HOMEOMORPHISM_PROJECTION_CLOSED];
+    ALL_TAC] THEN
+  ABBREV_TAC
+   `f:real^(M,1)finite_sum->real^N =
+        \x. lambda i. if i <= dimindex(:M) then x$i
+                      else x$(dimindex(:M)+1)` THEN
+  ABBREV_TAC
+   `g:real^N->real^(M,1)finite_sum = (\x. lambda i. x$i)` THEN
+  EXISTS_TAC `IMAGE (f:real^(M,1)finite_sum->real^N) t` THEN
+  SUBGOAL_THEN `linear(f:real^(M,1)finite_sum->real^N)` ASSUME_TAC THENL
+   [EXPAND_TAC "f" THEN REWRITE_TAC[linear; CART_EQ] THEN
+    SIMP_TAC[LAMBDA_BETA; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+    MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `linear(g:real^N->real^(M,1)finite_sum)` ASSUME_TAC THENL
+   [EXPAND_TAC "g" THEN REWRITE_TAC[linear; CART_EQ] THEN
+    SIMP_TAC[LAMBDA_BETA; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+    MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x. (g:real^N->real^(M,1)finite_sum)((f:real^(M,1)finite_sum->real^N) x) =
+        x`
+  ASSUME_TAC THENL
+   [MAP_EVERY EXPAND_TAC ["f"; "g"] THEN FIRST_ASSUM(MP_TAC o MATCH_MP
+     (ARITH_RULE `m < n ==> !i. i <= m + 1 ==> i <= n`)) THEN
+    SIMP_TAC[CART_EQ; LAMBDA_BETA; DIMINDEX_FINITE_SUM; DIMINDEX_1] THEN
+    REWRITE_TAC[ARITH_RULE `i <= n + 1 <=> i <= n \/ i = n + 1`] THEN
+    MESON_TAC[];
+    ALL_TAC] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[CLOSED_INJECTIVE_LINEAR_IMAGE]; ALL_TAC] THEN
+  TRANS_TAC HOMEOMORPHIC_TRANS `t:real^(M,1)finite_sum->bool` THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[homeomorphic]; ALL_TAC] THEN
+  REWRITE_TAC[homeomorphic; HOMEOMORPHISM] THEN MAP_EVERY EXISTS_TAC
+   [`f:real^(M,1)finite_sum->real^N`; `g:real^N->real^(M,1)finite_sum`] THEN
+  ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON] THEN ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relations between components and path components.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let OPEN_CONNECTED_COMPONENT = prove
+ (`!s x:real^N. open s ==> open(connected_component s x)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_CONTAINS_BALL] THEN
+  DISCH_TAC THEN 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_MESON_TAC[SUBSET; CONNECTED_COMPONENT_SUBSET]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `connected_component s (x:real^N) = connected_component s y`
+  SUBST1_TAC THENL
+   [ASM_MESON_TAC[CONNECTED_COMPONENT_EQ];
+    MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+    ASM_REWRITE_TAC[CENTRE_IN_BALL; CONNECTED_BALL]]);;
+
+let IN_CLOSURE_CONNECTED_COMPONENT = prove
+ (`!x y:real^N.
+        x IN s /\ open s
+        ==> (x IN closure(connected_component s y) <=>
+             x IN connected_component s y)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  REWRITE_TAC[REWRITE_RULE[SUBSET] CLOSURE_SUBSET] THEN
+  DISCH_TAC THEN SUBGOAL_THEN
+   `~((connected_component s (x:real^N)) INTER
+      closure(connected_component s y) = {})`
+  MP_TAC THENL
+   [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `x:real^N` THEN
+    ASM_REWRITE_TAC[IN_INTER] THEN
+    ASM_REWRITE_TAC[IN; CONNECTED_COMPONENT_REFL_EQ];
+    ASM_SIMP_TAC[OPEN_INTER_CLOSURE_EQ_EMPTY; OPEN_CONNECTED_COMPONENT] THEN
+    REWRITE_TAC[CONNECTED_COMPONENT_OVERLAP] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    ASM_REWRITE_TAC[IN; CONNECTED_COMPONENT_REFL_EQ]]);;
+
+let PATH_COMPONENT_SUBSET_CONNECTED_COMPONENT = prove
+ (`!s x:real^N. (path_component s x) SUBSET (connected_component s x)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `(x:real^N) IN s` THENL
+   [MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+    ASM_REWRITE_TAC[PATH_COMPONENT_SUBSET; IN; PATH_COMPONENT_REFL_EQ] THEN
+    SIMP_TAC[PATH_CONNECTED_IMP_CONNECTED; PATH_CONNECTED_PATH_COMPONENT];
+    ASM_MESON_TAC[PATH_COMPONENT_EQ_EMPTY; SUBSET_REFL;
+                  CONNECTED_COMPONENT_EQ_EMPTY]]);;
+
+let PATH_COMPONENT_EQ_CONNECTED_COMPONENT = prove
+ (`!s x:real^N.
+        locally path_connected s
+        ==> (path_component s x = connected_component s x)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `(x:real^N) IN s` THENL
+   [ALL_TAC;
+    ASM_MESON_TAC[PATH_COMPONENT_EQ_EMPTY; CONNECTED_COMPONENT_EQ_EMPTY]] THEN
+  MP_TAC(ISPECL[`s:real^N->bool`; `x:real^N`]
+    CONNECTED_CONNECTED_COMPONENT) THEN REWRITE_TAC[CONNECTED_CLOPEN] THEN
+  REWRITE_TAC[TAUT `p ==> q \/ r <=> p /\ ~q ==> r`] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[PATH_COMPONENT_EQ_EMPTY] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC OPEN_IN_SUBSET_TRANS;
+    MATCH_MP_TAC CLOSED_IN_SUBSET_TRANS] THEN
+  EXISTS_TAC `s:real^N->bool` THEN
+  ASM_SIMP_TAC[OPEN_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED;
+               CLOSED_IN_PATH_COMPONENT_LOCALLY_PATH_CONNECTED;
+               PATH_COMPONENT_SUBSET_CONNECTED_COMPONENT;
+               CONNECTED_COMPONENT_SUBSET]);;
+
+let LOCALLY_PATH_CONNECTED_PATH_COMPONENT = prove
+ (`!s x:real^N.
+        locally path_connected s
+        ==> locally path_connected (path_component s x)`,
+  MESON_TAC[LOCALLY_PATH_CONNECTED_CONNECTED_COMPONENT;
+            PATH_COMPONENT_EQ_CONNECTED_COMPONENT]);;
+
+let OPEN_PATH_CONNECTED_COMPONENT = prove
+ (`!s x:real^N. open s ==> path_component s x = connected_component s x`,
+  SIMP_TAC[PATH_COMPONENT_EQ_CONNECTED_COMPONENT;
+  OPEN_IMP_LOCALLY_PATH_CONNECTED]);;
+
+let PATH_CONNECTED_EQ_CONNECTED_LPC = prove
+ (`!s. locally path_connected s ==> (path_connected s <=> connected s)`,
+  REWRITE_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT;
+              CONNECTED_IFF_CONNECTED_COMPONENT] THEN
+  SIMP_TAC[PATH_COMPONENT_EQ_CONNECTED_COMPONENT]);;
+
+let PATH_CONNECTED_EQ_CONNECTED = prove
+ (`!s. open s ==> (path_connected s <=> connected s)`,
+  SIMP_TAC[PATH_CONNECTED_EQ_CONNECTED_LPC; OPEN_IMP_LOCALLY_PATH_CONNECTED]);;
+
+let CONNECTED_OPEN_PATH_CONNECTED = prove
+ (`!s:real^N->bool. open s /\ connected s ==> path_connected s`,
+  SIMP_TAC[PATH_CONNECTED_EQ_CONNECTED]);;
+
+let CONNECTED_OPEN_ARC_CONNECTED = prove
+ (`!s:real^N->bool.
+      open s /\ connected s
+      ==> !x y. x IN s /\ y IN s
+                ==> x = y \/
+                    ?g. arc g /\
+                        path_image g SUBSET s /\
+                        pathstart g = x /\
+                        pathfinish g = y`,
+  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP CONNECTED_OPEN_PATH_CONNECTED) THEN
+  REWRITE_TAC[PATH_CONNECTED_ARCWISE] THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN MESON_TAC[]);;
+
+let OPEN_COMPONENTS = prove
+ (`!u:real^N->bool s. open u /\ s IN components u ==> open s`,
+  REPEAT STRIP_TAC THEN STRIP_ASSUME_TAC (MESON[IN_COMPONENTS;
+  ASSUME `s:real^N->bool IN components u`] `?x. s:real^N->bool =
+  connected_component u x`) THEN ASM_SIMP_TAC [OPEN_CONNECTED_COMPONENT]);;
+
+let COMPONENTS_OPEN_UNIQUE = prove
+ (`!f:(real^N->bool)->bool s.
+        (!c. c IN f ==> open c /\ connected c /\ ~(c = {})) /\
+        pairwise DISJOINT f /\ UNIONS f = s
+        ==> components s = f`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC CONNECTED_DISJOINT_UNIONS_OPEN_UNIQUE THEN
+  ASM_REWRITE_TAC[GSYM UNIONS_COMPONENTS; PAIRWISE_DISJOINT_COMPONENTS] THEN
+  ASM_MESON_TAC[OPEN_COMPONENTS; IN_COMPONENTS_NONEMPTY;
+                IN_COMPONENTS_CONNECTED; OPEN_UNIONS]);;
+
+let CONTINUOUS_ON_COMPONENTS = prove
+ (`!f:real^M->real^N s.
+        open s /\ (!c. c IN components s ==> f continuous_on c)
+        ==> f continuous_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_COMPONENTS_GEN THEN
+  ASM_SIMP_TAC[] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC OPEN_SUBSET THEN
+  ASM_MESON_TAC[OPEN_COMPONENTS; IN_COMPONENTS_SUBSET]);;
+
+let CONTINUOUS_ON_COMPONENTS_EQ = prove
+ (`!f s. open s
+         ==> (f continuous_on s <=>
+              !c. c IN components s ==> f continuous_on c)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [MESON_TAC[CONTINUOUS_ON_SUBSET; IN_COMPONENTS_SUBSET];
+    ASM_MESON_TAC[CONTINUOUS_ON_COMPONENTS]]);;
+
+let CLOSED_IN_UNION_COMPLEMENT_COMPONENT = prove
+ (`!u s c:real^N->bool.
+        locally connected u /\
+        closed_in (subtopology euclidean u) s /\
+        c IN components(u DIFF s)
+        ==> closed_in (subtopology euclidean u) (s UNION c)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `s UNION c:real^N->bool = u DIFF (UNIONS(components(u DIFF s) DELETE c))`
+  SUBST1_TAC THENL
+   [MP_TAC(ISPEC `(u:real^N->bool) DIFF s` UNIONS_COMPONENTS) THEN
+    ONCE_REWRITE_TAC [EXTENSION] THEN
+    REWRITE_TAC[IN_UNION; IN_UNIV; IN_UNIONS; IN_DELETE; IN_DIFF] THEN
+    MP_TAC(ISPEC `(u:real^N->bool) DIFF s` PAIRWISE_DISJOINT_COMPONENTS) THEN
+    REWRITE_TAC[pairwise; SET_RULE
+     `DISJOINT s t <=> !x. ~(x IN s /\ x IN t)`] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP IN_COMPONENTS_SUBSET) THEN
+    REWRITE_TAC[SUBSET] THEN ASM_MESON_TAC[];
+    REWRITE_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY; SUBSET_DIFF] THEN
+    MATCH_MP_TAC OPEN_IN_DIFF THEN REWRITE_TAC[OPEN_IN_REFL] THEN
+    MATCH_MP_TAC CLOSED_IN_DIFF THEN REWRITE_TAC[CLOSED_IN_REFL] THEN
+    MATCH_MP_TAC OPEN_IN_UNIONS THEN REWRITE_TAC[IN_DELETE] THEN
+    X_GEN_TAC `d:real^N->bool` THEN STRIP_TAC THEN
+    MATCH_MP_TAC OPEN_IN_TRANS THEN
+    EXISTS_TAC `u DIFF s:real^N->bool` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC OPEN_IN_COMPONENTS_LOCALLY_CONNECTED THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC LOCALLY_OPEN_SUBSET THEN
+      EXISTS_TAC `u:real^N->bool` THEN ASM_REWRITE_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC OPEN_IN_DIFF THEN ASM_SIMP_TAC[OPEN_IN_REFL]]);;
+
+let CLOSED_UNION_COMPLEMENT_COMPONENT = prove
+ (`!s c. closed s /\ c IN components((:real^N) DIFF s) ==> closed(s UNION c)`,
+  ONCE_REWRITE_TAC[CLOSED_IN] THEN ONCE_REWRITE_TAC[GSYM SUBTOPOLOGY_UNIV] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC CLOSED_IN_UNION_COMPLEMENT_COMPONENT THEN
+  ASM_REWRITE_TAC[LOCALLY_CONNECTED_UNIV]);;
+
+let COUNTABLE_COMPONENTS = prove
+ (`!s:real^N->bool. open s ==> COUNTABLE(components s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC COUNTABLE_DISJOINT_OPEN_SUBSETS THEN
+  REWRITE_TAC[PAIRWISE_DISJOINT_COMPONENTS] THEN
+  ASM_MESON_TAC[OPEN_COMPONENTS]);;
+
+let FRONTIER_MINIMAL_SEPARATING_CLOSED = prove
+ (`!s c. closed s /\ ~connected((:real^N) DIFF s) /\
+         (!t. closed t /\ t PSUBSET s ==> connected((:real^N) DIFF t)) /\
+         c IN components ((:real^N) DIFF s)
+         ==> frontier c = s`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o
+    GEN_REWRITE_RULE RAND_CONV [CONNECTED_EQ_CONNECTED_COMPONENTS_EQ]) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (MESON[]
+   `~(!x x'. x IN s /\ x' IN s ==> x = x')
+    ==> !x. x IN s ==> ?y. y IN s /\ ~(y = x)`)) THEN
+  DISCH_THEN(MP_TAC o SPEC `c:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real^N->bool` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `frontier c:real^N->bool`) THEN
+  REWRITE_TAC[SET_RULE `s PSUBSET t <=> s SUBSET t /\ ~(t SUBSET s)`;
+              GSYM SUBSET_ANTISYM_EQ] THEN
+  ASM_SIMP_TAC[FRONTIER_OF_COMPONENTS_CLOSED_COMPLEMENT; FRONTIER_CLOSED] THEN
+  MATCH_MP_TAC(TAUT `~r ==> (~p ==> r) ==> p`) THEN
+  REWRITE_TAC[connected] THEN
+  MAP_EVERY EXISTS_TAC [`c:real^N->bool`; `(:real^N) DIFF closure c`] THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[OPEN_COMPONENTS; closed];
+    REWRITE_TAC[GSYM closed; CLOSED_CLOSURE];
+    MP_TAC(ISPEC `c:real^N->bool` INTERIOR_SUBSET) THEN
+    REWRITE_TAC[frontier] THEN SET_TAC[];
+    MATCH_MP_TAC(SET_RULE
+     `c SUBSET c' ==> c INTER (UNIV DIFF c') INTER s = {}`) THEN
+    REWRITE_TAC[GSYM INTERIOR_COMPLEMENT; CLOSURE_SUBSET];
+    REWRITE_TAC[frontier] THEN MATCH_MP_TAC(SET_RULE
+     `ci = c /\ ~(c = {})
+      ==> ~(c INTER (UNIV DIFF (cc DIFF ci)) = {})`) THEN
+    ASM_MESON_TAC[IN_COMPONENTS_NONEMPTY; INTERIOR_OPEN; closed;
+                  OPEN_COMPONENTS];
+    REWRITE_TAC[frontier] THEN MATCH_MP_TAC(SET_RULE
+     `~(UNIV DIFF c = {})
+      ==> ~((UNIV DIFF c) INTER (UNIV DIFF (c DIFF i)) = {})`) THEN
+    REWRITE_TAC[GSYM INTERIOR_COMPLEMENT] THEN
+    MATCH_MP_TAC(SET_RULE `!t. t SUBSET s /\ ~(t = {}) ==> ~(s = {})`) THEN
+    EXISTS_TAC `d:real^N->bool` THEN CONJ_TAC THENL
+     [ALL_TAC; ASM_MESON_TAC[IN_COMPONENTS_NONEMPTY]] THEN
+    MATCH_MP_TAC INTERIOR_MAXIMAL THEN
+    REWRITE_TAC[SET_RULE `s SUBSET UNIV DIFF t <=> s INTER t = {}`] THEN
+    ASM_MESON_TAC[COMPONENTS_NONOVERLAP; OPEN_COMPONENTS; GSYM closed]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Lower bound on norms within segment between vectors.                      *)
+(* Could have used these for connectedness results below, in fact.           *)
+(* ------------------------------------------------------------------------- *)
+
+let NORM_SEGMENT_LOWERBOUND = prove
+ (`!a b x:real^N r d.
+        &0 < r /\
+        norm(a) = r /\ norm(b) = r /\ x IN segment[a,b] /\
+        a dot b = d * r pow 2
+        ==> sqrt((&1 - abs d) / &2) * r <= norm(x)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM real_ge] THEN
+  REWRITE_TAC[NORM_GE_SQUARE] THEN DISJ2_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_SEGMENT]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[real_ge; DOT_LMUL; DOT_RMUL; REAL_MUL_RZERO; VECTOR_ARITH
+   `(a + b) dot (a + b) = a dot a + b dot b + &2 * a dot b`] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `(&1 - u) * (&1 - u) * r pow 2 + u * u * r pow 2 -
+              &2 * (&1 - u) * u * abs d * r pow 2` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[REAL_POW_MUL; REAL_MUL_ASSOC] THEN
+    REWRITE_TAC[GSYM REAL_ADD_RDISTRIB; GSYM REAL_SUB_RDISTRIB] THEN
+    MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[REAL_POW_2; REAL_LE_SQUARE] THEN
+    REWRITE_TAC[GSYM REAL_POW_2; REAL_ARITH
+     `(&1 - u) pow 2 + u pow 2 - ((&2 * (&1 - u)) * u) * d =
+      (&1 + d) * (&1 - &2 * u + &2 * u pow 2) - d`] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `(&1 + abs d) * &1 / &2 - abs d` THEN CONJ_TAC THENL
+     [REWRITE_TAC[REAL_ARITH `(&1 + d) * &1 / &2 - d = (&1 - d) / &2`] THEN
+      MATCH_MP_TAC REAL_EQ_IMP_LE THEN MATCH_MP_TAC SQRT_POW_2 THEN
+      MP_TAC(ISPECL [`a:real^N`; `b:real^N`] NORM_CAUCHY_SCHWARZ_ABS) THEN
+      ASM_REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_POW; REAL_POW2_ABS] THEN
+      ASM_REWRITE_TAC[REAL_ARITH `r * r = &1 * r pow 2`] THEN
+      ASM_SIMP_TAC[REAL_LE_RMUL_EQ; REAL_POW_LT] THEN REAL_ARITH_TAC;
+      MATCH_MP_TAC(REAL_ARITH `x <= y ==> x - a <= y - a`) THEN
+      MATCH_MP_TAC REAL_LE_LMUL THEN CONJ_TAC THENL
+       [REAL_ARITH_TAC;
+        MATCH_MP_TAC(REAL_ARITH
+         `&0 <= (u - &1 / &2) * (u - &1 / &2)
+          ==> &1 / &2 <= &1 - &2 * u + &2 * u pow 2`) THEN
+        REWRITE_TAC[REAL_LE_SQUARE]]];
+    ASM_REWRITE_TAC[GSYM NORM_POW_2; REAL_LE_LADD; real_sub] THEN
+    MATCH_MP_TAC(REAL_ARITH `abs(a) <= --x ==> x <= a`) THEN
+    ASM_REWRITE_TAC[REAL_ABS_MUL; REAL_MUL_LNEG; REAL_NEG_NEG] THEN
+    REWRITE_TAC[REAL_ABS_POW; REAL_POW2_ABS; REAL_ABS_NUM] THEN
+    REWRITE_TAC[REAL_MUL_ASSOC] THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+    REWRITE_TAC[REAL_POW_2; REAL_LE_SQUARE] THEN
+    ASM_REWRITE_TAC[real_abs; GSYM real_sub; REAL_SUB_LE; REAL_POS] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN CONJ_TAC THEN
+    REPEAT(MATCH_MP_TAC REAL_LE_MUL THEN
+          CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+    ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Special case of orthogonality (could replace 2 by sqrt(2)).               *)
+(* ------------------------------------------------------------------------- *)
+
+let NORM_SEGMENT_ORTHOGONAL_LOWERBOUND = prove
+ (`!a b:real^N x r.
+        r <= norm(a) /\ r <= norm(b) /\ orthogonal a b /\ x IN segment[a,b]
+        ==> r / &2 <= norm(x)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM real_ge] THEN
+  REWRITE_TAC[NORM_GE_SQUARE] THEN REWRITE_TAC[real_ge] THEN
+  ASM_CASES_TAC `r <= &0` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[orthogonal] THEN STRIP_TAC THEN DISJ2_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_SEGMENT]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[DOT_LMUL; DOT_RMUL; REAL_MUL_RZERO; VECTOR_ARITH
+   `(a + b) dot (a + b) = a dot a + b dot b + &2 * a dot b`] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `(&1 - u) * (&1 - u) * r pow 2 + u * u * r pow 2` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[REAL_ARITH `(r / &2) pow 2 = &1 / &4 * r pow 2`] THEN
+    REWRITE_TAC[GSYM REAL_ADD_RDISTRIB; REAL_MUL_ASSOC] THEN
+    MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[REAL_POW_2; REAL_LE_SQUARE] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `&0 <= (u - &1 / &2) * (u - &1 / &2)
+      ==> &1 / &4 <= (&1 - u) * (&1 - u) + u * u`) THEN
+    REWRITE_TAC[REAL_LE_SQUARE];
+    REWRITE_TAC[REAL_ADD_RID] THEN MATCH_MP_TAC REAL_LE_ADD2 THEN
+    CONJ_TAC THEN
+    REPEAT(MATCH_MP_TAC REAL_LE_LMUL THEN
+        CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+    ASM_REWRITE_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Accessibility of frontier points.                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let DENSE_ACCESSIBLE_FRONTIER_POINTS = prove
+ (`!s:real^N->bool v.
+        open s /\ open_in (subtopology euclidean (frontier s)) v /\ ~(v = {})
+        ==> ?g. arc g /\
+                IMAGE g (interval [vec 0,vec 1] DELETE vec 1) SUBSET s /\
+                pathstart g IN s /\ pathfinish g IN v`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `z:real^N`) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_IN_CONTAINS_BALL]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `z:real^N`)) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `r:real` THEN STRIP_TAC THEN
+  SUBGOAL_THEN `(z:real^N) IN frontier s` MP_TAC THENL
+   [ASM SET_TAC[];
+    DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+    REWRITE_TAC[frontier] THEN ASM_SIMP_TAC[IN_DIFF; INTERIOR_OPEN]] THEN
+  REWRITE_TAC[closure; IN_UNION; TAUT `(p \/ q) /\ ~p <=> ~p /\ q`] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIMPT_INFINITE_BALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `r:real`) THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `s INTER ball(z:real^N,r) = {}` THENL
+   [ASM_MESON_TAC[INFINITE; FINITE_EMPTY]; DISCH_THEN(K ALL_TAC)] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  REWRITE_TAC[IN_INTER] THEN
+  DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `~((y:real^N) IN frontier s)` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[IN_DIFF; INTERIOR_OPEN; frontier]; ALL_TAC] THEN
+  SUBGOAL_THEN `path_connected(ball(z:real^N,r))` MP_TAC THENL
+   [ASM_SIMP_TAC[CONVEX_BALL; CONVEX_IMP_PATH_CONNECTED]; ALL_TAC] THEN
+  REWRITE_TAC[PATH_CONNECTED_ARCWISE] THEN
+  DISCH_THEN(MP_TAC o SPECL [`y:real^N`; `z:real^N`]) THEN
+  ASM_REWRITE_TAC[CENTRE_IN_BALL] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^N` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPEC
+    `IMAGE drop {t | t IN interval[vec 0,vec 1] /\
+                     (g:real^1->real^N) t IN frontier s}`
+   COMPACT_ATTAINS_INF) THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE; IMAGE_EQ_EMPTY; FORALL_IN_IMAGE; IMP_CONJ] THEN
+  REWRITE_TAC[IMP_IMP; FORALL_IN_GSPEC; EXISTS_IN_GSPEC; GSYM IMAGE_o] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP; IMAGE_ID] THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC BOUNDED_SUBSET THEN
+        EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+        REWRITE_TAC[BOUNDED_INTERVAL; SUBSET_RESTRICT];
+        MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE THEN
+        REWRITE_TAC[FRONTIER_CLOSED; CLOSED_INTERVAL; GSYM path] THEN
+        ASM_MESON_TAC[arc]];
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `vec 1:real^1` THEN
+      ASM_REWRITE_TAC[IN_ELIM_THM; ENDS_IN_UNIT_INTERVAL] THEN
+      ASM_MESON_TAC[pathfinish; SUBSET]];
+    DISCH_THEN(X_CHOOSE_THEN `t:real^1` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `subpath (vec 0) t (g:real^1->real^N)` THEN
+    ASM_REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+    MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+     [MATCH_MP_TAC ARC_SUBPATH_ARC THEN
+      ASM_REWRITE_TAC[ENDS_IN_UNIT_INTERVAL] THEN
+      ASM_MESON_TAC[pathstart];
+      REWRITE_TAC[arc] THEN STRIP_TAC] THEN
+    GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o LAND_CONV) [GSYM pathstart] THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ALL_TAC; RULE_ASSUM_TAC(SIMP_RULE[path_image]) THEN ASM SET_TAC[]] THEN
+    MATCH_MP_TAC(SET_RULE
+     `a IN s /\ IMAGE f s DELETE (f a) SUBSET t /\
+      (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+      ==> IMAGE f (s DELETE a) SUBSET t`) THEN
+    ASM_REWRITE_TAC[ENDS_IN_UNIT_INTERVAL; GSYM path_image] THEN
+    W(MP_TAC o PART_MATCH (lhand o rand) PATH_IMAGE_SUBPATH o lhand o lhand o
+      snd) THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[IN_INTERVAL_1]; DISCH_THEN SUBST1_TAC] THEN
+    REWRITE_TAC[REWRITE_RULE[pathfinish] PATHFINISH_SUBPATH] THEN
+    MATCH_MP_TAC(SET_RULE
+     `IMAGE f (s DELETE a) DIFF t = {}
+      ==> IMAGE f s DELETE f a SUBSET t`) THEN
+    MATCH_MP_TAC(REWRITE_RULE[TAUT
+     `p /\ q /\ ~r ==> ~s <=> p /\ q /\ s ==> r`]
+     CONNECTED_INTER_FRONTIER) THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN CONJ_TAC THENL
+       [FIRST_X_ASSUM(MP_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [arc]) THEN
+        REWRITE_TAC[path] THEN MATCH_MP_TAC
+         (REWRITE_RULE[IMP_CONJ_ALT] CONTINUOUS_ON_SUBSET) THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+        REWRITE_TAC[SUBSET; IN_DELETE; GSYM DROP_EQ; IN_INTERVAL_1] THEN
+        REAL_ARITH_TAC;
+        MATCH_MP_TAC CONNECTED_INTERMEDIATE_CLOSURE THEN
+        EXISTS_TAC `interval(vec 0:real^1,t)` THEN
+        REWRITE_TAC[CONNECTED_INTERVAL; CLOSURE_INTERVAL] THEN
+        REWRITE_TAC[INTERVAL_EQ_EMPTY_1] THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+        COND_CASES_TAC THEN
+        ASM_REWRITE_TAC[SUBSET; IN_DELETE; GSYM DROP_EQ; IN_INTERVAL_1] THEN
+        REWRITE_TAC[NOT_IN_EMPTY] THEN ASM_REAL_ARITH_TAC];
+      REWRITE_TAC[SET_RULE
+        `~(IMAGE f s INTER t = {}) <=> ?x. x IN s /\ f x IN t`] THEN
+      EXISTS_TAC `vec 0:real^1` THEN
+      REWRITE_TAC[IN_INTERVAL_1; IN_DELETE; REAL_LE_REFL] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+      ASM SET_TAC[pathstart];
+      REWRITE_TAC[SET_RULE
+       `IMAGE g i INTER s = {} <=> !x. x IN i ==> ~(g x IN s)`] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_DELETE; IN_UNIV; IN_DIFF] THEN
+      X_GEN_TAC `z:real^1` THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+      REWRITE_TAC[GSYM DROP_EQ; IN_INTERVAL_1] THEN DISCH_TAC THEN
+      DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+      ASM_REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[IN_INTERVAL_1] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+      ASM_REAL_ARITH_TAC]]);;
+
+let DENSE_ACCESSIBLE_FRONTIER_POINTS_CONNECTED = prove
+ (`!s:real^N->bool v x.
+        open s /\ connected s /\ x IN s /\
+        open_in (subtopology euclidean (frontier s)) v /\ ~(v = {})
+        ==> ?g. arc g /\
+                IMAGE g (interval [vec 0,vec 1] DELETE vec 1) SUBSET s /\
+                pathstart g = x /\ pathfinish g IN v`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `v:real^N->bool`]
+        DENSE_ACCESSIBLE_FRONTIER_POINTS) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `path_connected(s:real^N->bool)` MP_TAC THENL
+   [ASM_MESON_TAC[CONNECTED_OPEN_PATH_CONNECTED]; ALL_TAC] THEN
+  REWRITE_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT] THEN
+  DISCH_THEN(MP_TAC o SPECL [`x:real^N`; `pathstart g:real^N`]) THEN
+  ASM_REWRITE_TAC[path_component; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `f:real^1->real^N` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`f ++ g:real^1->real^N`; `x:real^N`; `pathfinish g:real^N`]
+        PATH_CONTAINS_ARC) THEN
+  ASM_SIMP_TAC[PATH_JOIN_EQ; ARC_IMP_PATH; PATH_IMAGE_JOIN;
+               PATHSTART_JOIN; PATHFINISH_JOIN] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN
+  GEN_REWRITE_TAC LAND_CONV [SUBSET] THEN
+  ASM_SIMP_TAC[frontier; INTERIOR_OPEN; IN_DIFF] THEN
+  DISCH_TAC THEN ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `h:real^1->real^N` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(SET_RULE
+   `a IN s /\ IMAGE f s DELETE (f a) SUBSET t /\
+    (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+    ==> IMAGE f (s DELETE a) SUBSET t`) THEN
+  REWRITE_TAC[ENDS_IN_UNIT_INTERVAL] THEN
+  CONJ_TAC THENL [REWRITE_TAC[GSYM path_image]; ASM_MESON_TAC[arc]] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+   `h SUBSET f UNION g
+    ==> f SUBSET s /\ g DELETE a SUBSET s ==> h DELETE a SUBSET s`)) THEN
+  ASM_REWRITE_TAC[] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[path_image; pathstart; pathfinish]) THEN
+  REWRITE_TAC[path_image] THEN ASM SET_TAC[]);;
+
+let DENSE_ACCESSIBLE_FRONTIER_POINT_PAIRS = prove
+ (`!s u v:real^N->bool.
+         open s /\ connected s /\
+         open_in (subtopology euclidean (frontier s)) u /\
+         open_in (subtopology euclidean (frontier s)) v /\
+         ~(u = {}) /\ ~(v = {}) /\ ~(u = v)
+         ==> ?g. arc g /\
+                 pathstart g IN u /\ pathfinish g IN v /\
+                 IMAGE g (interval(vec 0,vec 1)) SUBSET s`,
+  GEN_TAC THEN REWRITE_TAC[CONJ_ASSOC] THEN
+  ONCE_REWRITE_TAC[IMP_CONJ_ALT] THEN
+  GEN_REWRITE_TAC (funpow 2 BINDER_CONV o LAND_CONV o RAND_CONV)
+    [GSYM SUBSET_ANTISYM_EQ] THEN
+  REWRITE_TAC[DE_MORGAN_THM; GSYM CONJ_ASSOC] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!u v. R u v ==> R v u) /\ (!u v. P u v ==> R u v)
+    ==> !u v. P u v \/ P v u ==> R u v`) THEN
+  CONJ_TAC THENL
+   [REPEAT GEN_TAC THEN DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `g:real^1->real^N` THEN
+    STRIP_TAC THEN EXISTS_TAC `reversepath g:real^1->real^N` THEN
+    ASM_SIMP_TAC[ARC_REVERSEPATH; PATHSTART_REVERSEPATH;
+                 PATHFINISH_REVERSEPATH] THEN
+    REWRITE_TAC[reversepath] THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+    REWRITE_TAC[IMAGE_o] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (SET_RULE `IMAGE f i SUBSET t
+                ==> IMAGE r i SUBSET i ==> IMAGE f (IMAGE r i) SUBSET t`)) THEN
+    SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1; DROP_SUB; DROP_VEC] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REPEAT GEN_TAC THEN DISCH_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[FRONTIER_EMPTY; OPEN_IN_SUBTOPOLOGY_EMPTY] THENL
+   [CONV_TAC TAUT; STRIP_TAC THEN UNDISCH_TAC `~(s:real^N->bool = {})`] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL
+   [`s:real^N->bool`; `v:real^N->bool`; `x:real^N`]
+   DENSE_ACCESSIBLE_FRONTIER_POINTS_CONNECTED) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `g:real^1->real^N` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`s:real^N->bool`; `(u DELETE pathfinish g):real^N->bool`; `x:real^N`]
+   DENSE_ACCESSIBLE_FRONTIER_POINTS_CONNECTED) THEN
+  ASM_SIMP_TAC[OPEN_IN_DELETE; IN_DELETE; LEFT_IMP_EXISTS_THM] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[LEFT_IMP_EXISTS_THM]] THEN
+  X_GEN_TAC `h:real^1->real^N` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`(reversepath h ++ g):real^1->real^N`;
+                 `pathfinish h:real^N`; `pathfinish g:real^N`]
+        PATH_CONTAINS_ARC) THEN
+  ASM_SIMP_TAC[PATH_JOIN; PATHSTART_JOIN; PATHFINISH_JOIN;
+               PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+               PATH_REVERSEPATH; ARC_IMP_PATH; PATH_IMAGE_JOIN;
+               PATH_IMAGE_REVERSEPATH] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `q:real^1->real^N` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[OPEN_CLOSED_INTERVAL_1] THEN
+  MATCH_MP_TAC(SET_RULE
+   `(!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+    t SUBSET s /\ IMAGE f s SUBSET u UNION IMAGE f t
+    ==> IMAGE f (s DIFF t) SUBSET u`) THEN
+  REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; ENDS_IN_UNIT_INTERVAL] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[arc]; REWRITE_TAC[GSYM path_image]] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        SUBSET_TRANS)) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish; path_image]) THEN
+  REWRITE_TAC[path_image] THEN ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some simple positive connection theorems.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_CONNECTED_CONVEX_DIFF_CARD_LT = prove
+ (`!u s:real^N->bool.
+    convex u /\ ~(collinear u) /\ s <_c (:real) ==> path_connected(u DIFF s)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[path_connected; IN_DIFF; IN_UNIV] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN STRIP_TAC THEN
+  ASM_CASES_TAC `a:real^N = b` THENL
+   [EXISTS_TAC `linepath(a:real^N,b)` THEN
+    REWRITE_TAC[PATHSTART_LINEPATH; PATHFINISH_LINEPATH; PATH_LINEPATH] THEN
+    ASM_REWRITE_TAC[PATH_IMAGE_LINEPATH; SEGMENT_REFL] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ABBREV_TAC `m:real^N = midpoint(a,b)` THEN
+  SUBGOAL_THEN `~(m:real^N = a) /\ ~(m = b)` STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[MIDPOINT_EQ_ENDPOINT]; ALL_TAC] THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ o rev) THEN
+  GEOM_ORIGIN_TAC `m:real^N` THEN REPEAT GEN_TAC THEN
+  GEOM_NORMALIZE_TAC `b:real^N` THEN REWRITE_TAC[] THEN GEN_TAC THEN
+  GEOM_BASIS_MULTIPLE_TAC 1 `b:real^N` THEN X_GEN_TAC `bbb:real` THEN
+  DISCH_TAC THEN SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_GE_1; LE_REFL] THEN
+  ASM_REWRITE_TAC[real_abs; REAL_MUL_RID] THEN
+  DISCH_THEN SUBST1_TAC THEN POP_ASSUM(K ALL_TAC) THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[midpoint; VECTOR_MUL_LID] THEN
+  REWRITE_TAC[VECTOR_ARITH `inv(&2) % (a + b):real^N = vec 0 <=> a = --b`] THEN
+  ASM_CASES_TAC `a:real^N = --(basis 1)` THEN ASM_REWRITE_TAC[] THEN
+  POP_ASSUM(K ALL_TAC) THEN
+  REPLICATE_TAC 7 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(K ALL_TAC) THEN
+  SUBGOAL_THEN `segment[--basis 1:real^N,basis 1] SUBSET u` ASSUME_TAC THENL
+   [REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(vec 0:real^N) IN u` ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    REWRITE_TAC[IN_SEGMENT] THEN EXISTS_TAC `&1 / &2` THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `?c:real^N k. 1 <= k /\ ~(k = 1) /\ k <= dimindex(:N) /\
+                             c IN u /\ ~(c$k = &0)`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM NOT_FORALL_THM; TAUT
+     `a /\ ~b /\ c /\ d /\ ~e <=> ~(d ==> a /\ c ==> ~b ==> e)`] THEN
+    DISCH_TAC THEN UNDISCH_TAC `~collinear(u:real^N->bool)` THEN
+    REWRITE_TAC[COLLINEAR_AFFINE_HULL] THEN
+    MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `basis 1:real^N`] THEN
+    SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC; IN_INSERT; SPAN_INSERT_0] THEN
+    REWRITE_TAC[SPAN_SING; SUBSET; IN_ELIM_THM; IN_UNIV] THEN
+    X_GEN_TAC `c:real^N` THEN DISCH_TAC THEN EXISTS_TAC `(c:real^N)$1` THEN
+    SIMP_TAC[CART_EQ; VECTOR_MUL_COMPONENT; BASIS_COMPONENT] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[REAL_MUL_RID; REAL_MUL_RZERO] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~(c:real^N = vec 0)` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[CART_EQ; VEC_COMPONENT] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `segment[vec 0:real^N,c] SUBSET u` ASSUME_TAC THENL
+   [REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?z:real^N. z IN segment[vec 0,c] /\
+               (segment[--basis 1,z] UNION segment[z,basis 1]) INTER s = {}`
+  STRIP_ASSUME_TAC THENL
+   [ALL_TAC;
+    EXISTS_TAC `linepath(--basis 1:real^N,z) ++ linepath(z,basis 1)` THEN
+    ASM_SIMP_TAC[PATH_JOIN; PATHSTART_JOIN; PATHFINISH_JOIN; PATH_LINEPATH;
+                 PATHSTART_LINEPATH; PATHFINISH_LINEPATH; PATH_IMAGE_JOIN] THEN
+    REWRITE_TAC[PATH_IMAGE_LINEPATH] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `(t UNION v) INTER s = {}
+      ==> t SUBSET u /\ v SUBSET u
+          ==> (t UNION v) SUBSET u DIFF s`)) THEN
+    REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+    CONJ_TAC THEN MATCH_MP_TAC HULL_MINIMAL THEN ASM SET_TAC[]] THEN
+  MATCH_MP_TAC(SET_RULE
+   `~(s SUBSET {z | z IN s /\ ~P z}) ==> ?z. z IN s /\ P z`) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CARD_LE_SUBSET) THEN
+  REWRITE_TAC[CARD_NOT_LE; SET_RULE
+   `~((b UNION c) INTER s = {}) <=>
+    ~(b INTER s = {}) \/ ~(c INTER s = {})`] THEN
+  REWRITE_TAC[SET_RULE
+   `{x | P x /\ (Q x \/ R x)} = {x | P x /\ Q x} UNION {x | P x /\ R x}`] THEN
+  W(MP_TAC o PART_MATCH lhand UNION_LE_ADD_C o lhand o snd) THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] CARD_LET_TRANS) THEN
+  TRANS_TAC CARD_LTE_TRANS `(:real)` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CARD_ADD2_ABSORB_LT THEN REWRITE_TAC[real_INFINITE];
+    MATCH_MP_TAC CARD_EQ_IMP_LE THEN ONCE_REWRITE_TAC[CARD_EQ_SYM] THEN
+    ASM_SIMP_TAC[CARD_EQ_SEGMENT]] THEN
+  REWRITE_TAC[MESON[SEGMENT_SYM] `segment[--a:real^N,b] = segment[b,--a]`] THEN
+  SUBGOAL_THEN
+   `!b:real^N.
+       b IN u /\ ~(b IN s) /\ ~(b = vec 0) /\ b$k = &0
+       ==> {z | z IN segment[vec 0,c] /\ ~(segment[z,b] INTER s = {})} <_c
+           (:real)`
+   (fun th -> CONJ_TAC THEN MATCH_MP_TAC th THEN
+              REWRITE_TAC[VECTOR_NEG_EQ_0; VECTOR_NEG_COMPONENT] THEN
+              ASM_SIMP_TAC[BASIS_NONZERO; DIMINDEX_GE_1; LE_REFL;
+                           BASIS_COMPONENT] THEN
+              REWRITE_TAC[REAL_NEG_0]) THEN
+  REPEAT STRIP_TAC THEN TRANS_TAC CARD_LET_TRANS `s:real^N->bool` THEN
+  ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER; RIGHT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> r /\ p /\ q`] THEN
+  MATCH_MP_TAC CARD_LE_RELATIONAL THEN
+  MAP_EVERY X_GEN_TAC [`w:real^N`; `x1:real^N`; `x2:real^N`] THEN
+  REWRITE_TAC[SEGMENT_SYM] THEN STRIP_TAC THEN
+  ASM_CASES_TAC `x2:real^N = x1` THEN ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPECL
+   [`x1:real^N`; `b:real^N`; `x2:real^N`] INTER_SEGMENT) THEN
+  REWRITE_TAC[NOT_IMP; SEGMENT_SYM] THEN
+  CONJ_TAC THENL [DISJ2_TAC; REWRITE_TAC[SEGMENT_SYM] THEN ASM SET_TAC[]] THEN
+  ONCE_REWRITE_TAC[SET_RULE `{x1,b,x2} = {x1,x2,b}`] THEN
+  ASM_SIMP_TAC[COLLINEAR_3_AFFINE_HULL] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `(b:real^N) IN affine hull {vec 0,c}` MP_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `b IN s ==> s SUBSET t ==> b IN t`)) THEN
+    MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[AFFINE_AFFINE_HULL] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `segment[c:real^N,vec 0]` THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ONCE_REWRITE_TAC[SEGMENT_SYM]] THEN
+    REWRITE_TAC[SEGMENT_CONVEX_HULL; CONVEX_HULL_SUBSET_AFFINE_HULL];
+    REWRITE_TAC[AFFINE_HULL_2_ALT; IN_ELIM_THM; IN_UNIV] THEN
+    REWRITE_TAC[VECTOR_ADD_LID; VECTOR_SUB_RZERO; NOT_EXISTS_THM] THEN
+    X_GEN_TAC `r:real` THEN
+    ASM_CASES_TAC `r = &0` THEN ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+    CONV_TAC(RAND_CONV SYM_CONV) THEN
+    DISCH_THEN(MP_TAC o AP_TERM `\x:real^N. x$k`) THEN
+    ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; REAL_ENTIRE]]);;
+
+let PATH_CONNECTED_COMPLEMENT_CARD_LT = prove
+ (`!s. 2 <= dimindex(:N) /\ s <_c (:real)
+       ==> path_connected((:real^N) DIFF s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_CONNECTED_CONVEX_DIFF_CARD_LT THEN
+  ASM_REWRITE_TAC[CONVEX_UNIV; COLLINEAR_AFF_DIM; AFF_DIM_UNIV] THEN
+  REWRITE_TAC[INT_OF_NUM_LE] THEN ASM_ARITH_TAC);;
+
+let PATH_CONNECTED_OPEN_IN_DIFF_CARD_LT = prove
+ (`!s t:real^N->bool.
+        connected s /\ open_in (subtopology euclidean (affine hull s)) s /\
+        ~collinear s /\ t <_c (:real)
+        ==> path_connected(s DIFF t)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT; IN_DIFF] THEN
+  REWRITE_TAC[TAUT `(p /\ q) /\ (r /\ s) <=> p /\ r /\ q /\ s`] THEN
+  MATCH_MP_TAC CONNECTED_EQUIVALENCE_RELATION_GEN THEN
+  ASM_REWRITE_TAC[IN_DIFF] THEN
+  REWRITE_TAC[PATH_COMPONENT_SYM; PATH_COMPONENT_TRANS] THEN CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `x:real^N`] THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+      `open_in (subtopology euclidean (affine hull s)) (u:real^N->bool)`
+    MP_TAC THENL [ASM_MESON_TAC[OPEN_IN_TRANS]; ALL_TAC] THEN
+    REWRITE_TAC[OPEN_IN_CONTAINS_BALL] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `x:real^N`)) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+    MATCH_MP_TAC(SET_RULE `~(s SUBSET t) ==> ?x. x IN s /\ ~(x IN t)`) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP CARD_LE_SUBSET) THEN
+    REWRITE_TAC[CARD_NOT_LE] THEN TRANS_TAC CARD_LTE_TRANS `(:real)` THEN
+    ASM_REWRITE_TAC[] THEN
+    TRANS_TAC CARD_LE_TRANS `ball(x:real^N,r) INTER affine hull s` THEN
+    ASM_SIMP_TAC[CARD_LE_SUBSET] THEN MATCH_MP_TAC CARD_EQ_IMP_LE THEN
+    ONCE_REWRITE_TAC[CARD_EQ_SYM] THEN MATCH_MP_TAC CARD_EQ_CONVEX THEN
+    EXISTS_TAC `x:real^N` THEN
+    ASM_SIMP_TAC[CONVEX_INTER; AFFINE_IMP_CONVEX; CONVEX_BALL;
+                 AFFINE_AFFINE_HULL; IN_INTER; CENTRE_IN_BALL; HULL_INC] THEN
+    SUBGOAL_THEN `~(s SUBSET {x:real^N})` MP_TAC THENL
+     [ASM_MESON_TAC[COLLINEAR_SUBSET; COLLINEAR_SING]; ALL_TAC] THEN
+    REWRITE_TAC[SUBSET; IN_SING; NOT_FORALL_THM; NOT_IMP] THEN
+    DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `x + r / &2 / norm(y - x) % (y - x):real^N` THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET]) THEN
+    ASM_SIMP_TAC[HULL_INC; IN_AFFINE_ADD_MUL_DIFF; AFFINE_AFFINE_HULL] THEN
+    REWRITE_TAC[IN_BALL; VECTOR_ARITH `x:real^N = x + y <=> y = vec 0`] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_DIV_EQ_0; NORM_EQ_0; VECTOR_SUB_EQ;
+            REAL_LT_IMP_NZ; NORM_ARITH `dist(x:real^N,x + y) = norm y`] THEN
+    REWRITE_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NUM; REAL_ABS_NORM] THEN
+    ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+    ASM_REAL_ARITH_TAC;
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_IN_CONTAINS_BALL]) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `x:real^N`)) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `ball(x:real^N,r) INTER affine hull s` THEN
+    ASM_SIMP_TAC[IN_INTER; HULL_INC; CENTRE_IN_BALL] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC OPEN_IN_SUBSET_TRANS THEN
+      EXISTS_TAC `affine hull s:real^N->bool` THEN
+      ASM_SIMP_TAC[ONCE_REWRITE_RULE[INTER_COMM]OPEN_IN_OPEN_INTER; OPEN_BALL];
+      MAP_EVERY X_GEN_TAC [`y:real^N`; `z:real^N`] THEN STRIP_TAC THEN
+      MP_TAC(ISPECL [`ball(x:real^N,r) INTER affine hull s`; `t:real^N->bool`]
+        PATH_CONNECTED_CONVEX_DIFF_CARD_LT) THEN
+      ASM_SIMP_TAC[CONVEX_INTER; AFFINE_IMP_CONVEX; CONVEX_BALL;
+                   AFFINE_AFFINE_HULL] THEN
+      ANTS_TAC THENL
+       [REWRITE_TAC[COLLINEAR_AFF_DIM] THEN ONCE_REWRITE_TAC[INTER_COMM] THEN
+        W(MP_TAC o PART_MATCH (lhs o rand) AFF_DIM_CONVEX_INTER_OPEN o
+          lhand o rand o snd) THEN
+        SIMP_TAC[AFFINE_IMP_CONVEX; AFFINE_AFFINE_HULL; OPEN_BALL] THEN
+        ANTS_TAC THENL [ASM SET_TAC[CENTRE_IN_BALL]; ALL_TAC] THEN
+        DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[AFF_DIM_AFFINE_HULL] THEN
+        ASM_REWRITE_TAC[GSYM COLLINEAR_AFF_DIM];
+        REWRITE_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT] THEN
+        DISCH_THEN(MP_TAC o SPECL [`y:real^N`; `z:real^N`]) THEN
+        ASM_REWRITE_TAC[IN_INTER; IN_DIFF] THEN
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] PATH_COMPONENT_OF_SUBSET) THEN
+        ASM SET_TAC[]]]]);;
+
+let CONNECTED_OPEN_IN_DIFF_CARD_LT = prove
+ (`!s t:real^N->bool.
+        connected s /\ open_in (subtopology euclidean (affine hull s)) s /\
+        ~collinear s /\ t <_c (:real)
+        ==> connected(s DIFF t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_CONNECTED_IMP_CONNECTED THEN
+  MATCH_MP_TAC PATH_CONNECTED_OPEN_IN_DIFF_CARD_LT THEN
+  ASM_REWRITE_TAC[]);;
+
+let PATH_CONNECTED_OPEN_DIFF_CARD_LT = prove
+ (`!s t:real^N->bool.
+        2 <= dimindex(:N) /\ open s /\ connected s /\ t <_c (:real)
+        ==> path_connected(s DIFF t)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[EMPTY_DIFF; PATH_CONNECTED_EMPTY] THEN
+  MATCH_MP_TAC PATH_CONNECTED_OPEN_IN_DIFF_CARD_LT THEN
+  ASM_REWRITE_TAC[COLLINEAR_AFF_DIM] THEN
+  ASM_SIMP_TAC[AFFINE_HULL_OPEN; AFF_DIM_OPEN] THEN
+  ASM_REWRITE_TAC[INT_OF_NUM_LE; SUBTOPOLOGY_UNIV; GSYM OPEN_IN] THEN
+  ASM_ARITH_TAC);;
+
+let CONNECTED_OPEN_DIFF_CARD_LT = prove
+ (`!s t:real^N->bool.
+        2 <= dimindex(:N) /\ open s /\ connected s /\ t <_c (:real)
+        ==> connected(s DIFF t)`,
+  SIMP_TAC[PATH_CONNECTED_OPEN_DIFF_CARD_LT; PATH_CONNECTED_IMP_CONNECTED]);;
+
+let PATH_CONNECTED_OPEN_DIFF_COUNTABLE = prove
+ (`!s t:real^N->bool.
+        2 <= dimindex(:N) /\ open s /\ connected s /\ COUNTABLE t
+        ==> path_connected(s DIFF t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_CONNECTED_OPEN_DIFF_CARD_LT THEN
+  ASM_REWRITE_TAC[GSYM CARD_NOT_LE] THEN
+  ASM_MESON_TAC[UNCOUNTABLE_REAL; CARD_LE_COUNTABLE]);;
+
+let CONNECTED_OPEN_DIFF_COUNTABLE = prove
+ (`!s t:real^N->bool.
+        2 <= dimindex(:N) /\ open s /\ connected s /\ COUNTABLE t
+        ==> connected(s DIFF t)`,
+  SIMP_TAC[PATH_CONNECTED_OPEN_DIFF_COUNTABLE; PATH_CONNECTED_IMP_CONNECTED]);;
+
+let PATH_CONNECTED_OPEN_DELETE = prove
+ (`!s a:real^N. 2 <= dimindex(:N) /\ open s /\ connected s
+                ==> path_connected(s DELETE a)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[SET_RULE `s DELETE a = s DIFF {a}`] THEN
+  MATCH_MP_TAC PATH_CONNECTED_OPEN_DIFF_COUNTABLE THEN
+  ASM_REWRITE_TAC[COUNTABLE_SING]);;
+
+let CONNECTED_OPEN_DELETE = prove
+ (`!s a:real^N. 2 <= dimindex(:N) /\ open s /\ connected s
+                ==> connected(s DELETE a)`,
+  SIMP_TAC[PATH_CONNECTED_OPEN_DELETE; PATH_CONNECTED_IMP_CONNECTED]);;
+
+let PATH_CONNECTED_PUNCTURED_UNIVERSE = prove
+ (`!a. 2 <= dimindex(:N) ==> path_connected((:real^N) DIFF {a})`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_CONNECTED_OPEN_DIFF_COUNTABLE THEN
+  ASM_REWRITE_TAC[OPEN_UNIV; CONNECTED_UNIV; COUNTABLE_SING]);;
+
+let CONNECTED_PUNCTURED_UNIVERSE = prove
+ (`!a. 2 <= dimindex(:N) ==> connected((:real^N) DIFF {a})`,
+  SIMP_TAC[PATH_CONNECTED_PUNCTURED_UNIVERSE; PATH_CONNECTED_IMP_CONNECTED]);;
+
+let PATH_CONNECTED_PUNCTURED_BALL = prove
+ (`!a:real^N r. 2 <= dimindex(:N) ==> path_connected(ball(a,r) DELETE a)`,
+  SIMP_TAC[PATH_CONNECTED_OPEN_DELETE; OPEN_BALL; CONNECTED_BALL]);;
+
+let CONNECTED_PUNCTURED_BALL = prove
+ (`!a:real^N r. 2 <= dimindex(:N) ==> connected(ball(a,r) DELETE a)`,
+  SIMP_TAC[CONNECTED_OPEN_DELETE; OPEN_BALL; CONNECTED_BALL]);;
+
+let PATH_CONNECTED_SPHERE = prove
+ (`!a:real^N r. 2 <= dimindex(:N) ==> path_connected(sphere(a,r))`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[sphere; dist] THEN ONCE_REWRITE_TAC[NORM_SUB] THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN GEN_TAC THEN
+  REWRITE_TAC[VECTOR_SUB_RZERO] THEN DISCH_TAC THEN
+  REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
+   (REAL_ARITH `r < &0 \/ r = &0 \/ &0 < r`)
+  THENL
+   [ASM_SIMP_TAC[NORM_ARITH `r < &0 ==> ~(norm(x:real^N) = r)`] THEN
+    REWRITE_TAC[EMPTY_GSPEC; PATH_CONNECTED_EMPTY];
+    ASM_REWRITE_TAC[NORM_EQ_0; SING_GSPEC; PATH_CONNECTED_SING];
+    SUBGOAL_THEN
+     `{x:real^N | norm x = r} =
+      IMAGE (\x. r / norm x % x) ((:real^N) DIFF {vec 0})`
+    SUBST1_TAC THENL
+     [MATCH_MP_TAC SUBSET_ANTISYM THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+      REWRITE_TAC[IN_IMAGE; IN_ELIM_THM; IN_DIFF; IN_SING; IN_UNIV] THEN
+      ASM_SIMP_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM; REAL_DIV_RMUL;
+                   NORM_EQ_0; REAL_ARITH `&0 < r ==> abs r = r`] THEN
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN EXISTS_TAC `x:real^N` THEN
+      ASM_SIMP_TAC[REAL_DIV_REFL; REAL_LT_IMP_NZ; VECTOR_MUL_LID] THEN
+      ASM_MESON_TAC[NORM_0; REAL_LT_IMP_NZ];
+      MATCH_MP_TAC PATH_CONNECTED_CONTINUOUS_IMAGE THEN
+      ASM_SIMP_TAC[PATH_CONNECTED_PUNCTURED_UNIVERSE] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_MUL THEN REWRITE_TAC[CONTINUOUS_ON_ID] THEN
+    REWRITE_TAC[o_DEF; CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+    X_GEN_TAC `x:real^N` THEN REWRITE_TAC[IN_DIFF; IN_UNIV; IN_SING] THEN
+    DISCH_TAC THEN REWRITE_TAC[real_div; LIFT_CMUL] THEN
+    MATCH_MP_TAC CONTINUOUS_CMUL THEN
+    MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_AT_WITHIN_INV) THEN
+    ASM_REWRITE_TAC[NORM_EQ_0] THEN MATCH_MP_TAC CONTINUOUS_AT_WITHIN THEN
+    REWRITE_TAC[REWRITE_RULE[o_DEF] CONTINUOUS_AT_LIFT_NORM]]]);;
+
+let CONNECTED_SPHERE = prove
+ (`!a:real^N r. 2 <= dimindex(:N) ==> connected(sphere(a,r))`,
+  SIMP_TAC[PATH_CONNECTED_SPHERE; PATH_CONNECTED_IMP_CONNECTED]);;
+
+let CONNECTED_SPHERE_EQ = prove
+ (`!a:real^N r. connected(sphere(a,r)) <=> 2 <= dimindex(:N) \/ r <= &0`,
+  let lemma = prove
+   (`!a:real^1 r. &0 < r
+         ==> ?x y. ~(x = y) /\ dist(a,x) = r /\ dist(a,y) = r`,
+    MP_TAC SPHERE_1 THEN REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+    COND_CASES_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    REWRITE_TAC[EXTENSION; IN_SPHERE; IN_INSERT; NOT_IN_EMPTY] THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(MESON[]
+    `~(a = b) ==> ?x y. ~(x = y) /\ (x = a \/ x = b) /\ (y = a \/ y = b)`) THEN
+    REWRITE_TAC[VECTOR_ARITH `a - r:real^1 = a + r <=> r = vec 0`] THEN
+    REWRITE_TAC[GSYM DROP_EQ; DROP_VEC; LIFT_DROP] THEN ASM_REAL_ARITH_TAC) in
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `r < &0` THEN
+  ASM_SIMP_TAC[SPHERE_EMPTY; CONNECTED_EMPTY; REAL_LT_IMP_LE] THEN
+  ASM_CASES_TAC `r = &0` THEN
+  ASM_SIMP_TAC[SPHERE_SING; REAL_LE_REFL; CONNECTED_SING] THEN
+  SUBGOAL_THEN `&0 < r` ASSUME_TAC THENL
+   [ASM_REAL_ARITH_TAC; ASM_REWRITE_TAC[GSYM REAL_NOT_LT]] THEN
+  EQ_TAC THEN SIMP_TAC[CONNECTED_SPHERE] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CONNECTED_FINITE_IFF_SING) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  SIMP_TAC[DIMINDEX_GE_1; ARITH_RULE `1 <= n ==> (2 <= n <=> ~(n = 1))`] THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM DIMINDEX_1] THEN
+  DISCH_TAC THEN FIRST_ASSUM (fun th ->
+    REWRITE_TAC[GEOM_EQUAL_DIMENSION_RULE th FINITE_SPHERE_1]) THEN
+  REWRITE_TAC[SET_RULE
+   `~(s = {} \/ ?a. s = {a}) <=> ?x y. ~(x = y) /\ x IN s /\ y IN s`] THEN
+  REWRITE_TAC[IN_SPHERE] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o C GEOM_EQUAL_DIMENSION_RULE lemma) THEN
+  ASM_REWRITE_TAC[]);;
+
+let PATH_CONNECTED_SPHERE_EQ = prove
+ (`!a:real^N r. path_connected(sphere(a,r)) <=> 2 <= dimindex(:N) \/ r <= &0`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[GSYM CONNECTED_SPHERE_EQ; PATH_CONNECTED_IMP_CONNECTED];
+    STRIP_TAC THEN ASM_SIMP_TAC[PATH_CONNECTED_SPHERE]] THEN
+  ASM_CASES_TAC `r < &0` THEN
+  ASM_SIMP_TAC[SPHERE_EMPTY; PATH_CONNECTED_EMPTY] THEN
+  ASM_CASES_TAC `r = &0` THEN
+  ASM_SIMP_TAC[SPHERE_SING; PATH_CONNECTED_SING] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let FINITE_SPHERE = prove
+ (`!a:real^N r. FINITE(sphere(a,r)) <=> r <= &0 \/ dimindex(:N) = 1`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `dimindex(:N) = 1` THEN
+  ASM_REWRITE_TAC[] THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[GSYM DIMINDEX_1]) THEN
+    FIRST_ASSUM(MATCH_ACCEPT_TAC o C PROVE_HYP
+      (GEOM_EQUAL_DIMENSION_RULE(ASSUME `dimindex(:N) = dimindex(:1)`)
+      FINITE_SPHERE_1));
+    ASM_SIMP_TAC[CONNECTED_SPHERE; ARITH_RULE `2 <= n <=> 1 <= n /\ ~(n = 1)`;
+                 DIMINDEX_GE_1; CONNECTED_FINITE_IFF_SING] THEN
+    REWRITE_TAC[SET_RULE `(s = {} \/ ?a. s = {a}) <=>
+                          (!a b. a IN s /\ b IN s ==> a = b)`] THEN
+    SIMP_TAC[IN_SPHERE] THEN EQ_TAC THENL [ALL_TAC; CONV_TAC NORM_ARITH] THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[REAL_NOT_LE] THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`a:real^N`; `r:real`] VECTOR_CHOOSE_DIST) THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    DISCH_THEN(MP_TAC o SPECL [`x:real^N`; `a - (x - a):real^N`]) THEN
+    FIRST_X_ASSUM(K ALL_TAC o check (is_neg o concl)) THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC NORM_ARITH]);;
+
+let LIMIT_POINT_OF_SPHERE = prove
+ (`!a r x:real^N. x limit_point_of sphere(a,r) <=>
+                  &0 < r /\ 2 <= dimindex(:N) /\ x IN sphere(a,r)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `FINITE(sphere(a:real^N,r))` THENL
+   [ASM_SIMP_TAC[LIMIT_POINT_FINITE]; ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o REWRITE_RULE[FINITE_SPHERE]) THEN
+  REWRITE_TAC[DE_MORGAN_THM] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[REAL_NOT_LE; ARITH; REAL_NOT_LT] THEN
+  ASM_SIMP_TAC[GSYM REAL_NOT_LE; DIMINDEX_GE_1;
+               ARITH_RULE `1 <= n ==> (2 <= n <=> ~(n = 1))`] THEN
+  EQ_TAC THEN REWRITE_TAC[REWRITE_RULE[CLOSED_LIMPT] CLOSED_SPHERE] THEN
+  DISCH_TAC THEN MATCH_MP_TAC CONNECTED_IMP_PERFECT THEN
+  ASM_SIMP_TAC[CONNECTED_SPHERE_EQ; DIMINDEX_GE_1;
+               ARITH_RULE `1 <= n ==> (2 <= n <=> ~(n = 1))`] THEN
+  ASM_MESON_TAC[FINITE_SING]);;
+
+let CARD_EQ_SPHERE = prove
+ (`!a:real^N r. 2 <= dimindex(:N) /\ &0 < r ==> sphere(a,r) =_c (:real)`,
+  SIMP_TAC[CONNECTED_CARD_EQ_IFF_NONTRIVIAL; CONNECTED_SPHERE] THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP(REWRITE_RULE[IMP_CONJ_ALT] FINITE_SUBSET)) THEN
+  ASM_REWRITE_TAC[FINITE_SING; FINITE_SPHERE; REAL_NOT_LE; DE_MORGAN_THM] THEN
+  ASM_ARITH_TAC);;
+
+let PATH_CONNECTED_ANNULUS = prove
+ (`(!a:real^N r1 r2.
+        2 <= dimindex(:N)
+        ==> path_connected {x | r1 < norm(x - a) /\ norm(x - a) < r2}) /\
+   (!a:real^N r1 r2.
+        2 <= dimindex(:N)
+        ==> path_connected {x | r1 < norm(x - a) /\ norm(x - a) <= r2}) /\
+   (!a:real^N r1 r2.
+        2 <= dimindex(:N)
+        ==> path_connected {x | r1 <= norm(x - a) /\ norm(x - a) < r2}) /\
+   (!a:real^N r1 r2.
+        2 <= dimindex(:N)
+        ==> path_connected {x | r1 <= norm(x - a) /\ norm(x - a) < r2})`,
+  let lemma = prove
+   (`!a:real^N P.
+      2 <= dimindex(:N) /\ path_connected {lift r | &0 <= r /\ P r}
+      ==> path_connected {x | P(norm(x - a))}`,
+    REPEAT GEN_TAC THEN GEOM_ORIGIN_TAC `a:real^N` THEN
+    REWRITE_TAC[VECTOR_SUB_RZERO] THEN REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+     `{x:real^N | P(norm(x))} =
+      IMAGE (\z. drop(fstcart z) % sndcart z)
+            {pastecart x y | x IN {lift x | &0 <= x /\ P x} /\
+                             y IN {y | norm y = &1}}`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[EXTENSION; IN_IMAGE] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+      REWRITE_TAC[EXISTS_IN_GSPEC; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+      X_GEN_TAC `z:real^N` THEN REWRITE_TAC[EXISTS_LIFT; LIFT_DROP] THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+      REWRITE_TAC[LIFT_IN_IMAGE_LIFT; IMAGE_ID] THEN
+      REWRITE_TAC[IN_ELIM_THM] THEN
+      EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[NORM_MUL; REAL_MUL_RID] THEN
+      ASM_REWRITE_TAC[real_abs] THEN ASM_CASES_TAC `z:real^N = vec 0` THENL
+       [MAP_EVERY EXISTS_TAC [`&0`; `basis 1:real^N`] THEN
+        ASM_SIMP_TAC[NORM_BASIS; DIMINDEX_GE_1; LE_REFL; VECTOR_MUL_LZERO] THEN
+        ASM_MESON_TAC[NORM_0; REAL_ABS_NUM; REAL_LE_REFL];
+        MAP_EVERY EXISTS_TAC [`norm(z:real^N)`; `inv(norm z) % z:real^N`] THEN
+        ASM_SIMP_TAC[REAL_ABS_NORM; NORM_MUL; VECTOR_MUL_ASSOC; VECTOR_MUL_LID;
+          NORM_POS_LE; REAL_ABS_INV; REAL_MUL_RINV; REAL_MUL_LINV; NORM_EQ_0]];
+      MATCH_MP_TAC PATH_CONNECTED_CONTINUOUS_IMAGE THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+        REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX] THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART];
+        REWRITE_TAC[GSYM PCROSS] THEN
+        MATCH_MP_TAC PATH_CONNECTED_PCROSS THEN ASM_REWRITE_TAC[] THEN
+        ONCE_REWRITE_TAC[NORM_ARITH `norm y = norm(y - vec 0:real^N)`] THEN
+        ONCE_REWRITE_TAC[NORM_SUB] THEN
+        REWRITE_TAC[REWRITE_RULE[dist] (GSYM sphere)] THEN
+        ASM_SIMP_TAC[PATH_CONNECTED_SPHERE]]]) in
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `a:real^N` lemma) THEN
+  DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC CONVEX_IMP_PATH_CONNECTED THEN
+  MATCH_MP_TAC IS_INTERVAL_CONVEX THEN
+  REWRITE_TAC[is_interval] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+  REWRITE_TAC[IN_IMAGE_LIFT_DROP; FORALL_1; DIMINDEX_1] THEN
+  REWRITE_TAC[IN_ELIM_THM; GSYM drop] THEN REAL_ARITH_TAC);;
+
+let CONNECTED_ANNULUS = prove
+ (`(!a:real^N r1 r2.
+        2 <= dimindex(:N)
+        ==> connected {x | r1 < norm(x - a) /\ norm(x - a) < r2}) /\
+   (!a:real^N r1 r2.
+        2 <= dimindex(:N)
+        ==> connected {x | r1 < norm(x - a) /\ norm(x - a) <= r2}) /\
+   (!a:real^N r1 r2.
+        2 <= dimindex(:N)
+        ==> connected {x | r1 <= norm(x - a) /\ norm(x - a) < r2}) /\
+   (!a:real^N r1 r2.
+        2 <= dimindex(:N)
+        ==> connected {x | r1 <= norm(x - a) /\ norm(x - a) < r2})`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC PATH_CONNECTED_IMP_CONNECTED THEN
+  ASM_SIMP_TAC[PATH_CONNECTED_ANNULUS]);;
+
+let PATH_CONNECTED_COMPLEMENT_BOUNDED_CONVEX = prove
+ (`!s. 2 <= dimindex(:N) /\ bounded s /\ convex s
+       ==> path_connected((:real^N) DIFF s)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[DIFF_EMPTY; CONVEX_IMP_PATH_CONNECTED; CONVEX_UNIV] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+  REWRITE_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
+  REWRITE_TAC[IN_DIFF; IN_UNIV] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `~(x:real^N = a) /\ ~(y = a)` STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `bounded((x:real^N) INSERT y INSERT s)` MP_TAC THENL
+   [ASM_REWRITE_TAC[BOUNDED_INSERT]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `a:real^N` o MATCH_MP BOUNDED_SUBSET_BALL) THEN
+  REWRITE_TAC[INSERT_SUBSET] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC PATH_COMPONENT_TRANS THEN
+  ABBREV_TAC `C = (B / norm(x - a:real^N))` THEN
+  EXISTS_TAC `a + C % (x - a):real^N` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC PATH_CONNECTED_LINEPATH THEN
+    REWRITE_TAC[SUBSET; segment; FORALL_IN_GSPEC; IN_DIFF; IN_UNIV] THEN
+    REWRITE_TAC[VECTOR_ARITH
+     `(&1 - u) % x + u % (a + B % (x - a)):real^N =
+      a + (&1 + (B - &1) * u) % (x - a)`] THEN
+    X_GEN_TAC `u:real` THEN STRIP_TAC THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONVEX_ALT]) THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`a:real^N`; `a + (&1 + (C - &1) * u) % (x - a):real^N`;
+      `&1 / (&1 + (C - &1) * u)`]) THEN
+    SUBGOAL_THEN `&1 <= &1 + (C - &1) * u` ASSUME_TAC THENL
+     [REWRITE_TAC[REAL_LE_ADDR] THEN MATCH_MP_TAC REAL_LE_MUL THEN
+      ASM_REWRITE_TAC[REAL_SUB_LE] THEN
+      EXPAND_TAC "C" THEN
+      ASM_SIMP_TAC[REAL_LE_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_BALL; dist]) THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE; NORM_ARITH `&1 * norm(x - a) = norm(a - x)`];
+      FIRST_ASSUM(ASSUME_TAC o MATCH_MP
+       (REAL_ARITH `&1 <= a ==> &0 < a`))] THEN
+    ASM_REWRITE_TAC[NOT_IMP] THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; REAL_POS; REAL_LT_IMP_LE; REAL_LE_LDIV_EQ;
+                 REAL_MUL_LID] THEN
+    ASM_SIMP_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC; REAL_DIV_RMUL;
+                 REAL_LT_IMP_NZ] THEN
+    UNDISCH_TAC `~((x:real^N) IN s)` THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC PATH_COMPONENT_SYM THEN
+  MATCH_MP_TAC PATH_COMPONENT_TRANS THEN
+  ABBREV_TAC `D = (B / norm(y - a:real^N))` THEN
+  EXISTS_TAC `a + D % (y - a):real^N` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC PATH_CONNECTED_LINEPATH THEN
+    REWRITE_TAC[SUBSET; segment; FORALL_IN_GSPEC; IN_DIFF; IN_UNIV] THEN
+    REWRITE_TAC[VECTOR_ARITH
+     `(&1 - u) % y + u % (a + B % (y - a)):real^N =
+      a + (&1 + (B - &1) * u) % (y - a)`] THEN
+    X_GEN_TAC `u:real` THEN STRIP_TAC THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONVEX_ALT]) THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`a:real^N`; `a + (&1 + (D - &1) * u) % (y - a):real^N`;
+      `&1 / (&1 + (D - &1) * u)`]) THEN
+    SUBGOAL_THEN `&1 <= &1 + (D - &1) * u` ASSUME_TAC THENL
+     [REWRITE_TAC[REAL_LE_ADDR] THEN MATCH_MP_TAC REAL_LE_MUL THEN
+      ASM_REWRITE_TAC[REAL_SUB_LE] THEN
+      EXPAND_TAC "D" THEN
+      ASM_SIMP_TAC[REAL_LE_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_BALL; dist]) THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE; NORM_ARITH `&1 * norm(y - a) = norm(a - y)`];
+      FIRST_ASSUM(ASSUME_TAC o MATCH_MP
+       (REAL_ARITH `&1 <= a ==> &0 < a`))] THEN
+    ASM_REWRITE_TAC[NOT_IMP] THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; REAL_POS; REAL_LT_IMP_LE; REAL_LE_LDIV_EQ;
+                 REAL_MUL_LID] THEN
+    ASM_SIMP_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC; REAL_DIV_RMUL;
+                 REAL_LT_IMP_NZ] THEN
+    UNDISCH_TAC `~((y:real^N) IN s)` THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC PATH_COMPONENT_OF_SUBSET THEN
+  EXISTS_TAC `{x:real^N | norm(x - a) = B}` THEN CONJ_TAC THENL
+   [UNDISCH_TAC `s SUBSET ball(a:real^N,B)` THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_DIFF; IN_UNIV; IN_BALL; dist] THEN
+    MESON_TAC[NORM_SUB; REAL_LT_REFL];
+    MP_TAC(ISPECL [`a:real^N`; `B:real`] PATH_CONNECTED_SPHERE) THEN
+    REWRITE_TAC[REWRITE_RULE[ONCE_REWRITE_RULE[DIST_SYM] dist] sphere] THEN
+    ASM_REWRITE_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    REWRITE_TAC[IN_ELIM_THM; VECTOR_ADD_SUB; NORM_MUL] THEN
+    MAP_EVERY EXPAND_TAC ["C"; "D"] THEN
+    REWRITE_TAC[REAL_ABS_DIV; REAL_ABS_NORM] THEN
+    ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let CONNECTED_COMPLEMENT_BOUNDED_CONVEX = prove
+ (`!s. 2 <= dimindex(:N) /\ bounded s /\ convex s
+       ==> connected((:real^N) DIFF s)`,
+  SIMP_TAC[PATH_CONNECTED_IMP_CONNECTED;
+           PATH_CONNECTED_COMPLEMENT_BOUNDED_CONVEX]);;
+
+let CONNECTED_DIFF_BALL = prove
+ (`!s a:real^N r.
+        2 <= dimindex(:N) /\ connected s /\ cball(a,r) SUBSET s
+        ==> connected(s DIFF ball(a,r))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CONNECTED_DIFF_OPEN_FROM_CLOSED THEN
+  EXISTS_TAC `cball(a:real^N,r)` THEN
+  ASM_REWRITE_TAC[OPEN_BALL; CLOSED_CBALL; BALL_SUBSET_CBALL] THEN
+  REWRITE_TAC[CBALL_DIFF_BALL] THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] dist] THEN
+  ASM_SIMP_TAC[CONNECTED_SPHERE]);;
+
+let PATH_CONNECTED_DIFF_BALL = prove
+ (`!s a:real^N r.
+        2 <= dimindex(:N) /\ path_connected s /\ cball(a,r) SUBSET s
+        ==> path_connected(s DIFF ball(a,r))`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `ball(a:real^N,r) = {}` THEN
+  ASM_SIMP_TAC[DIFF_EMPTY] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[BALL_EQ_EMPTY; REAL_NOT_LE]) THEN
+  REWRITE_TAC[path_connected] THEN
+  FIRST_ASSUM(MP_TAC o SPEC `a:real^N` o GEN_REWRITE_RULE I [SUBSET]) THEN
+  ASM_SIMP_TAC[CENTRE_IN_CBALL; REAL_LT_IMP_LE] THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
+  REWRITE_TAC[IN_DIFF] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [path_connected]) THEN
+  DISCH_THEN(fun th ->
+   MP_TAC(SPECL [`x:real^N`; `a:real^N`] th) THEN
+   MP_TAC(SPECL [`y:real^N`; `a:real^N`] th)) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g2:real^1->real^N` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `g1:real^1->real^N` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`g2:real^1->real^N`; `(:real^N) DIFF ball(a,r)`]
+        EXISTS_PATH_SUBPATH_TO_FRONTIER) THEN
+  MP_TAC(ISPECL [`g1:real^1->real^N`; `(:real^N) DIFF ball(a,r)`]
+        EXISTS_PATH_SUBPATH_TO_FRONTIER) THEN
+  ASM_SIMP_TAC[CENTRE_IN_BALL; IN_DIFF; IN_UNIV; LEFT_IMP_EXISTS_THM] THEN
+  ASM_SIMP_TAC[FRONTIER_COMPLEMENT; INTERIOR_COMPLEMENT; CLOSURE_BALL] THEN
+  ASM_SIMP_TAC[FRONTIER_BALL; IN_SPHERE] THEN
+  X_GEN_TAC `h1:real^1->real^N` THEN STRIP_TAC THEN
+  X_GEN_TAC `h2:real^1->real^N` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`a:real^N`; `r:real`] PATH_CONNECTED_SPHERE) THEN
+  ASM_REWRITE_TAC[path_connected] THEN
+  DISCH_THEN(MP_TAC o SPECL
+   [`pathfinish h1:real^N`; `pathfinish h2:real^N`]) THEN
+  ASM_SIMP_TAC[IN_SPHERE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^1->real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `h1 ++ h ++ reversepath h2:real^1->real^N` THEN
+  ASM_SIMP_TAC[PATHSTART_JOIN; PATHFINISH_JOIN; PATHSTART_REVERSEPATH;
+               PATHFINISH_REVERSEPATH; PATH_JOIN; PATH_REVERSEPATH;
+               PATH_IMAGE_JOIN; PATH_IMAGE_REVERSEPATH] THEN
+  REWRITE_TAC[UNION_SUBSET] THEN REPEAT CONJ_TAC THENL
+   [ALL_TAC;
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          SUBSET_TRANS)) THEN
+    UNDISCH_TAC `cball(a:real^N,r) SUBSET s` THEN
+    SIMP_TAC[SUBSET; IN_CBALL; IN_SPHERE; IN_BALL; IN_DIFF] THEN
+    MESON_TAC[REAL_LE_REFL; REAL_LT_REFL];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(SET_RULE
+   `s SUBSET t /\ s INTER u = {} ==> s SUBSET t DIFF u`) THEN
+  (CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+   `s DELETE a SUBSET (UNIV DIFF t) ==> ~(a IN u) /\ u SUBSET t
+      ==> s INTER u = {}`)) THEN
+  ASM_REWRITE_TAC[BALL_SUBSET_CBALL; IN_BALL; REAL_LT_REFL]);;
+
+let CONNECTED_OPEN_DIFF_CBALL = prove
+ (`!s a:real^N r.
+        2 <= dimindex (:N) /\ open s /\ connected s /\ cball(a,r) SUBSET s
+        ==> connected(s DIFF cball(a,r))`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `cball(a:real^N,r) = {}` THEN ASM_REWRITE_TAC[DIFF_EMPTY] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[CBALL_EQ_EMPTY; REAL_NOT_LT]) THEN
+  SUBGOAL_THEN `?r'. r < r' /\ cball(a:real^N,r') SUBSET s`
+  STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `s = (:real^N)` THENL
+     [EXISTS_TAC `r + &1` THEN ASM_SIMP_TAC[SUBSET_UNIV] THEN REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`cball(a:real^N,r)`; `(:real^N) DIFF s`]
+      SETDIST_POS_LE) THEN
+    REWRITE_TAC[REAL_ARITH `&0 <= x <=> &0 < x \/ x = &0`] THEN
+    ASM_SIMP_TAC[SETDIST_EQ_0_COMPACT_CLOSED; GSYM OPEN_CLOSED;
+                 COMPACT_CBALL; CBALL_EQ_EMPTY] THEN
+    ASM_REWRITE_TAC[SET_RULE `UNIV DIFF s = {} <=> s = UNIV`] THEN
+    ASM_SIMP_TAC[SET_RULE `b INTER (UNIV DIFF s) = {} <=> b SUBSET s`;
+                 REAL_ARITH `&0 <= r ==> ~(r < &0)`] THEN
+    STRIP_TAC THEN
+    EXISTS_TAC `r + setdist(cball(a,r),(:real^N) DIFF s) / &2` THEN
+    ASM_REWRITE_TAC[REAL_LT_ADDR; REAL_HALF; SUBSET; IN_CBALL] THEN
+    X_GEN_TAC `x:real^N` THEN ASM_CASES_TAC `x:real^N = a` THENL
+     [ASM_MESON_TAC[SUBSET; DIST_REFL; IN_CBALL]; ALL_TAC] THEN
+    ASM_CASES_TAC `(x:real^N) IN s` THEN ASM_REWRITE_TAC[REAL_NOT_LE] THEN
+    MP_TAC(ISPECL [`cball(a:real^N,r)`; `(:real^N) DIFF s`;
+                   `a + r / dist(a,x) % (x - a):real^N`; `x:real^N`]
+      SETDIST_LE_DIST) THEN
+    ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; IN_CBALL] THEN
+    REWRITE_TAC[NORM_ARITH `dist(a:real^N,a + x) = norm x`] THEN
+    ASM_SIMP_TAC[NORM_MUL; REAL_ABS_DIV; ONCE_REWRITE_RULE[DIST_SYM] dist;
+                 REAL_ABS_NORM; REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+    ASM_REWRITE_TAC[REAL_ARITH `abs r <= r <=> &0 <= r`] THEN
+    REWRITE_TAC[NORM_MUL; VECTOR_ARITH
+     `x - (a + d % (x - a)):real^N = (&1 - d) % (x - a)`] THEN
+    ONCE_REWRITE_TAC[GSYM REAL_ABS_NORM] THEN
+    REWRITE_TAC[GSYM REAL_ABS_MUL] THEN
+    REWRITE_TAC[REAL_ABS_NORM; REAL_SUB_RDISTRIB] THEN
+    ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N` o REWRITE_RULE[SUBSET]) THEN
+    ASM_REWRITE_TAC[IN_CBALL; ONCE_REWRITE_RULE[DIST_SYM] dist] THEN
+    REAL_ARITH_TAC;
+    SUBGOAL_THEN `s DIFF cball(a:real^N,r) =
+                  s DIFF ball(a,r') UNION
+                  {x | r < norm(x - a) /\ norm(x - a) <= r'}`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] (GSYM dist)] THEN
+      REWRITE_TAC[GSYM REAL_NOT_LE; GSYM IN_CBALL] THEN MATCH_MP_TAC(SET_RULE
+       `b' SUBSET c' /\ c' SUBSET s /\ c SUBSET b'
+        ==> s DIFF c = (s DIFF b') UNION {x | ~(x IN c) /\ x IN c'}`) THEN
+      ASM_REWRITE_TAC[BALL_SUBSET_CBALL] THEN
+      REWRITE_TAC[SUBSET; IN_BALL; IN_CBALL] THEN ASM_REAL_ARITH_TAC;
+      MATCH_MP_TAC CONNECTED_UNION THEN
+      ASM_SIMP_TAC[CONNECTED_ANNULUS; PATH_CONNECTED_DIFF_BALL;
+        PATH_CONNECTED_IMP_CONNECTED; CONNECTED_OPEN_PATH_CONNECTED] THEN
+      REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] (GSYM dist)] THEN
+      REWRITE_TAC[GSYM REAL_NOT_LE; GSYM IN_CBALL] THEN MATCH_MP_TAC(SET_RULE
+       `c' SUBSET s /\ (?x. x IN c' /\ ~(x IN b') /\ ~(x IN c))
+        ==> ~((s DIFF b') INTER {x | ~(x IN c) /\ x IN c'} = {})`) THEN
+      ASM_REWRITE_TAC[] THEN EXISTS_TAC `a + r' % basis 1:real^N` THEN
+      REWRITE_TAC[IN_BALL; IN_CBALL] THEN
+      REWRITE_TAC[NORM_ARITH `dist(a:real^N,a + x) = norm x`] THEN
+      SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_GE_1; LE_REFL] THEN
+      ASM_REAL_ARITH_TAC]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Existence of unbounded components.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let COBOUNDED_UNBOUNDED_COMPONENT = prove
+ (`!s. bounded((:real^N) DIFF s)
+       ==> ?x. x IN s /\ ~bounded(connected_component s x)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `vec 0:real^N` o MATCH_MP BOUNDED_SUBSET_BALL) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `B % basis 1:real^N` THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o SPEC `B % basis 1:real^N` o
+     GEN_REWRITE_RULE I [SUBSET]) THEN
+    REWRITE_TAC[IN_UNIV; IN_DIFF; IN_BALL_0] THEN
+    SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_GE_1; LE_REFL] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < B ==> ~(abs B * &1 < B)`];
+    MP_TAC(ISPECL [`basis 1:real^N`; `B:real`] BOUNDED_HALFSPACE_GE) THEN
+    SIMP_TAC[BASIS_NONZERO; DIMINDEX_GE_1; LE_REFL; CONTRAPOS_THM] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] BOUNDED_SUBSET) THEN
+    MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+    SIMP_TAC[CONVEX_HALFSPACE_GE; CONVEX_CONNECTED] THEN
+    ASM_SIMP_TAC[IN_ELIM_THM; DOT_RMUL; DOT_BASIS_BASIS; DIMINDEX_GE_1;
+                 LE_REFL; real_ge; REAL_MUL_RID; REAL_LE_REFL] THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+    `UNIV DIFF s SUBSET b ==> (!x. x IN h ==> ~(x IN b)) ==> h SUBSET s`)) THEN
+    SIMP_TAC[IN_ELIM_THM; DOT_BASIS; IN_BALL_0; DIMINDEX_GE_1; LE_REFL] THEN
+    GEN_TAC THEN REWRITE_TAC[REAL_NOT_LT] THEN
+    MATCH_MP_TAC(REAL_ARITH `abs x <= n ==> b <= x ==> b <= n`) THEN
+    SIMP_TAC[COMPONENT_LE_NORM; DIMINDEX_GE_1; LE_REFL]]);;
+
+let COBOUNDED_UNIQUE_UNBOUNDED_COMPONENT = prove
+ (`!s x y:real^N.
+        2 <= dimindex(:N) /\ bounded((:real^N) DIFF s) /\
+        ~bounded(connected_component s x) /\
+        ~bounded(connected_component s y)
+        ==> connected_component s x = connected_component s y`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `vec 0:real^N` o MATCH_MP BOUNDED_SUBSET_BALL) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPEC `ball(vec 0:real^N,B)` CONNECTED_COMPLEMENT_BOUNDED_CONVEX) THEN
+  ASM_REWRITE_TAC[BOUNDED_BALL; CONVEX_BALL] THEN DISCH_TAC THEN
+  MAP_EVERY
+   (MP_TAC o SPEC `B:real` o REWRITE_RULE[bounded; NOT_EXISTS_THM] o ASSUME)
+   [`~bounded(connected_component s (y:real^N))`;
+    `~bounded(connected_component s (x:real^N))`] THEN
+  REWRITE_TAC[NOT_FORALL_THM; IN; NOT_IMP] THEN
+  DISCH_THEN(X_CHOOSE_THEN `x':real^N` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `y':real^N` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC CONNECTED_COMPONENT_EQ THEN REWRITE_TAC[IN] THEN
+  SUBGOAL_THEN `connected_component s (x':real^N) (y':real^N)` ASSUME_TAC THENL
+   [REWRITE_TAC[connected_component] THEN
+    EXISTS_TAC `(:real^N) DIFF ball (vec 0,B)` THEN ASM_REWRITE_TAC[] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[IN_DIFF; IN_UNIV]] THEN
+    REWRITE_TAC[IN_BALL_0] THEN ASM_MESON_TAC[REAL_LT_IMP_LE];
+    ASM_MESON_TAC[CONNECTED_COMPONENT_SYM; CONNECTED_COMPONENT_TRANS]]);;
+
+let COBOUNDED_UNBOUNDED_COMPONENTS = prove
+ (`!s. bounded ((:real^N) DIFF s) ==> ?c. c IN components s /\ ~bounded c`,
+  REWRITE_TAC[components; EXISTS_IN_GSPEC; COBOUNDED_UNBOUNDED_COMPONENT]);;
+
+let COBOUNDED_UNIQUE_UNBOUNDED_COMPONENTS = prove
+ (`!s c c'.
+        2 <= dimindex(:N) /\
+        bounded ((:real^N) DIFF s) /\
+        c IN components s /\ ~bounded c /\
+        c' IN components s /\ ~bounded c'
+        ==> c' = c`,
+  REWRITE_TAC[components; IN_ELIM_THM] THEN
+  MESON_TAC[COBOUNDED_UNIQUE_UNBOUNDED_COMPONENT]);;
+
+let COBOUNDED_HAS_BOUNDED_COMPONENT = prove
+ (`!s. 2 <= dimindex(:N) /\ bounded((:real^N) DIFF s) /\ ~connected s
+       ==> ?c. c IN components s /\ bounded c`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?c c':real^N->bool. c IN components s /\ c' IN components s /\ ~(c = c')`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `~(s = {}) /\ ~(?a. s = {a}) ==> ?x y. x IN s /\ y IN s /\ ~(x = y)`) THEN
+    ASM_REWRITE_TAC[COMPONENTS_EQ_SING_EXISTS; COMPONENTS_EQ_EMPTY] THEN
+    ASM_MESON_TAC[DIFF_EMPTY; NOT_BOUNDED_UNIV];
+    ASM_MESON_TAC[COBOUNDED_UNIQUE_UNBOUNDED_COMPONENTS]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Self-homeomorphisms shuffling points about in various ways.               *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMEOMORPHISM_MOVING_POINT_EXISTS = prove
+ (`!s t a b:real^N.
+        open_in (subtopology euclidean (affine hull s)) s /\
+        s SUBSET t /\ t SUBSET affine hull s /\
+        connected s /\ a IN s /\ b IN s
+        ==> ?f g. homeomorphism (t,t) (f,g) /\ f a = b /\
+                  {x | ~(f x = x /\ g x = x)} SUBSET s /\
+                  bounded {x | ~(f x = x /\ g x = x)}`,
+  let lemma1 = prove
+   (`!a t r u:real^N.
+          affine t /\ a IN t /\ u IN ball(a,r) INTER t
+          ==> ?f g. homeomorphism (cball(a,r) INTER t,cball(a,r) INTER t)
+                                  (f,g) /\
+                    f(a) = u /\ (!x. x IN sphere(a,r) ==> f(x) = x)`,
+    REPEAT STRIP_TAC THEN
+    DISJ_CASES_TAC(REAL_ARITH `r <= &0 \/ &0 < r`) THENL
+     [ASM_MESON_TAC[BALL_EMPTY; INTER_EMPTY; NOT_IN_EMPTY]; ALL_TAC] THEN
+    EXISTS_TAC `\x:real^N. (&1 - norm(x - a) / r) % (u - a) + x` THEN
+    REWRITE_TAC[LEFT_EXISTS_AND_THM] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HOMEOMORPHISM_COMPACT THEN
+      ASM_SIMP_TAC[COMPACT_INTER_CLOSED; COMPACT_CBALL; CLOSED_AFFINE];
+      ASM_SIMP_TAC[IN_SPHERE; ONCE_REWRITE_RULE[NORM_SUB] dist;
+                   REAL_DIV_REFL; REAL_LT_IMP_NZ; IN_INTER] THEN
+      REWRITE_TAC[real_div; VECTOR_SUB_REFL; NORM_0; REAL_MUL_LZERO] THEN
+      REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN REWRITE_TAC[CONTINUOUS_ON_ID] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_MUL THEN REWRITE_TAC[o_DEF; LIFT_SUB] THEN
+      SIMP_TAC[CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST; CONTINUOUS_ON_SUB] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_SUB THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+      REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] real_div; LIFT_CMUL] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_CMUL THEN
+      MATCH_MP_TAC CONTINUOUS_ON_LIFT_NORM_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST; CONTINUOUS_ON_SUB];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC(SET_RULE
+       `(!x. x IN s ==> f x IN s) /\ (!y. y IN s ==> ?x. x IN s /\ f x = y)
+        ==> IMAGE f s = s`) THEN REWRITE_TAC[] THEN
+      ONCE_REWRITE_TAC[VECTOR_ARITH
+       `(&1 - n) % (u - a) + x:real^N = a + (&1 - n) % (u - a) + (x - a)`];
+      ALL_TAC] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN GEOM_ORIGIN_TAC `a:real^N` THEN
+    REWRITE_TAC[IN_BALL_0; VECTOR_SUB_RZERO; IN_CBALL_0; IN_INTER] THEN
+    REWRITE_TAC[VECTOR_ADD_LID; VECTOR_ADD_RID;
+                VECTOR_ARITH `a + x:real^N = a + y <=> x = y`;
+                VECTOR_ARITH `(&1 - n) % u + a + x = (&1 - m) % u + a + y <=>
+                              (n - m) % u:real^N = x - y`] THEN
+    REWRITE_TAC[REAL_ARITH `x / r - y / r:real = (x - y) / r`] THENL
+     [ALL_TAC;
+      REPEAT GEN_TAC THEN REPEAT DISCH_TAC THEN REPEAT GEN_TAC THEN
+      ASM_CASES_TAC `x:real^N = y` THEN ASM_REWRITE_TAC[] THEN
+      ASM_CASES_TAC `norm(x:real^N) = norm(y:real^N)` THEN
+      ASM_REWRITE_TAC[real_div; REAL_SUB_REFL; REAL_MUL_LZERO; VECTOR_MUL_LZERO;
+                      VECTOR_ARITH `vec 0:real^N = x - y <=> x = y`] THEN
+      STRIP_TAC THEN FIRST_ASSUM(MP_TAC o AP_TERM `norm:real^N->real`) THEN
+      ASM_SIMP_TAC[NORM_MUL; REAL_ABS_MUL; REAL_ABS_INV] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP (NORM_ARITH
+       `r = norm(x - y:real^N) ==> r < abs(norm x - norm y) * &1 ==> F`)) THEN
+      REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN MATCH_MP_TAC REAL_LT_LMUL THEN
+      CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ONCE_REWRITE_TAC[REAL_MUL_SYM]] THEN
+      ASM_SIMP_TAC[GSYM real_div; REAL_LT_LDIV_EQ;
+                   REAL_ARITH `&0 < r ==> &0 < abs r`] THEN
+      ASM_REAL_ARITH_TAC] THEN
+    REPEAT GEN_TAC THEN
+    ASM_CASES_TAC `subspace(t:real^N->bool)` THENL
+     [ALL_TAC; ASM_MESON_TAC[AFFINE_IMP_SUBSPACE]] THEN
+    ASM_SIMP_TAC[SUBSPACE_ADD; SUBSPACE_MUL] THEN
+    REPEAT STRIP_TAC THENL
+     [MATCH_MP_TAC(NORM_ARITH
+       `norm(x) + norm(y) <= &1 * r ==> norm(x + y:real^N) <= r`) THEN
+      ASM_SIMP_TAC[NORM_MUL; GSYM REAL_LE_LDIV_EQ; REAL_ARITH
+       `(a * u + x) / r:real = a * u / r + x / r`] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `x <= &1 /\ a <= abs(&1 - x) * &1 ==> a + x <= &1`) THEN
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ] THEN
+      CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+      MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[REAL_ABS_POS] THEN
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_MUL_LID; REAL_LT_IMP_LE];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`\a. lift((&1 - drop a) * r - norm(y - drop a % u:real^N))`;
+      `vec 0:real^1`; `vec 1:real^1`; `&0`; `1`]
+          IVT_DECREASING_COMPONENT_1) THEN
+    REWRITE_TAC[DIMINDEX_1; GSYM drop; LIFT_DROP; DROP_VEC] THEN
+    REWRITE_TAC[REAL_POS; LE_REFL; REAL_SUB_REFL; VECTOR_MUL_LZERO] THEN
+    REWRITE_TAC[REAL_SUB_RZERO; VECTOR_SUB_RZERO; REAL_MUL_LID] THEN
+    REWRITE_TAC[NORM_ARITH `&0 * r - norm(x:real^N) <= &0`] THEN
+    ASM_REWRITE_TAC[REAL_SUB_LE; GSYM EXISTS_DROP; IN_INTERVAL_1] THEN
+    ANTS_TAC THENL
+     [REPEAT STRIP_TAC THEN
+      REWRITE_TAC[REAL_ARITH `(&1 - x) * r - b:real = r - r * x - b`] THEN
+      REWRITE_TAC[LIFT_SUB; LIFT_CMUL; LIFT_DROP] THEN
+      REPEAT(MATCH_MP_TAC CONTINUOUS_SUB THEN CONJ_TAC THEN
+             REWRITE_TAC[CONTINUOUS_CONST]) THEN
+      SIMP_TAC[CONTINUOUS_CMUL; CONTINUOUS_AT_ID] THEN
+      MATCH_MP_TAC CONTINUOUS_LIFT_NORM_COMPOSE THEN
+      MATCH_MP_TAC CONTINUOUS_SUB THEN REWRITE_TAC[CONTINUOUS_CONST] THEN
+      MATCH_MP_TAC CONTINUOUS_MUL THEN
+      REWRITE_TAC[o_DEF; LIFT_DROP; CONTINUOUS_AT_ID; CONTINUOUS_CONST];
+
+      ASM_SIMP_TAC[DROP_VEC; REAL_FIELD
+       `&0 < r ==> ((&1 - x) * r - n = &0 <=> &1 - n / r = x)`] THEN
+      DISCH_THEN(X_CHOOSE_THEN `a:real` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `y - a % u:real^N` THEN ASM_REWRITE_TAC[] THEN
+      CONJ_TAC THENL [ALL_TAC; VECTOR_ARITH_TAC] THEN
+      ASM_SIMP_TAC[SUBSPACE_SUB; SUBSPACE_MUL] THEN
+      GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
+      ASM_SIMP_TAC[GSYM REAL_LE_LDIV_EQ] THEN ASM_REAL_ARITH_TAC]) in
+  let lemma2 = prove
+   (`!a t u v:real^N r.
+          affine t /\ a IN t /\
+          u IN ball(a,r) INTER t /\ v IN ball(a,r) INTER t
+          ==> ?f g. homeomorphism (cball(a,r) INTER t,cball(a,r) INTER t)
+                                  (f,g) /\ f(u) = v /\
+                    !x. x IN sphere(a,r) /\ x IN t ==> f(x) = x`,
+    REPEAT GEN_TAC THEN
+    DISJ_CASES_TAC(REAL_ARITH `r <= &0 \/ &0 < r`) THENL
+     [ASM_MESON_TAC[BALL_EMPTY; INTER_EMPTY; NOT_IN_EMPTY];
+      REPLICATE_TAC 2 (DISCH_THEN (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+      DISCH_TAC] THEN
+    MP_TAC(ISPECL [`a:real^N`; `t:real^N->bool`; `r:real`] lemma1) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(fun th ->
+        FIRST_ASSUM(CONJUNCTS_THEN(MP_TAC o MATCH_MP th))) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`f1:real^N->real^N`; `g1:real^N->real^N`] THEN
+    STRIP_TAC THEN
+    MAP_EVERY X_GEN_TAC [`f2:real^N->real^N`; `g2:real^N->real^N`] THEN
+    STRIP_TAC THEN
+    EXISTS_TAC `(f1:real^N->real^N) o (g2:real^N->real^N)` THEN
+    EXISTS_TAC `(f2:real^N->real^N) o (g1:real^N->real^N)` THEN
+    REWRITE_TAC[o_THM; SUBSET; IN_ELIM_THM] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HOMEOMORPHISM_COMPOSE THEN ASM_MESON_TAC[HOMEOMORPHISM_SYM];
+      RULE_ASSUM_TAC(REWRITE_RULE[homeomorphism; IN_INTER]) THEN CONJ_TAC THENL
+       [MP_TAC(ISPECL [`a:real^N`; `r:real`] CENTRE_IN_CBALL) THEN
+        ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN ASM SET_TAC[];
+        MP_TAC(ISPECL [`a:real^N`; `r:real`] SPHERE_SUBSET_CBALL) THEN
+        ASM SET_TAC[]]]) in
+  let lemma3 = prove
+   (`!a t u v:real^N r s.
+        affine t /\ a IN t /\ ball(a,r) INTER t SUBSET s /\ s SUBSET t /\
+        u IN ball(a,r) INTER t /\ v IN ball(a,r) INTER t
+        ==> ?f g. homeomorphism (s,s) (f,g) /\ f(u) = v /\
+                  {x | ~(f x = x /\ g x = x)} SUBSET ball(a,r) INTER t`,
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`a:real^N`; `t:real^N->bool`; `u:real^N`; `v:real^N`;
+                   `r:real`] lemma2) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`f:real^N->real^N`; `g:real^N->real^N`] THEN
+    STRIP_TAC THEN
+    EXISTS_TAC `\x:real^N. if x IN ball(a,r) INTER t then f x else x` THEN
+    EXISTS_TAC `\x:real^N. if x IN ball(a,r) INTER t then g x else x` THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ALL_TAC; SET_TAC[]] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HOMEOMORPHISM]) THEN
+    REWRITE_TAC[HOMEOMORPHISM; SUBSET; FORALL_IN_IMAGE] THEN
+    STRIP_TAC THEN
+    SUBGOAL_THEN `(!x:real^N. x IN ball(a,r) INTER t ==> f x IN ball(a,r)) /\
+                  (!x:real^N. x IN ball(a,r) INTER t ==> g x IN ball(a,r))`
+    STRIP_ASSUME_TAC THENL
+     [REWRITE_TAC[GSYM CBALL_DIFF_SPHERE] THEN ASM SET_TAC[]; ALL_TAC] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET]) THEN
+    REWRITE_TAC[IN_INTER] THEN REPEAT CONJ_TAC THEN
+    TRY(X_GEN_TAC `x:real^N` THEN
+        ASM_CASES_TAC `x IN ball(a:real^N,r)` THEN ASM_SIMP_TAC[] THEN
+        MP_TAC(ISPECL [`a:real^N`; `r:real`] BALL_SUBSET_CBALL) THEN
+        REPEAT(COND_CASES_TAC THEN ASM_SIMP_TAC[]) THEN
+        ASM SET_TAC[]) THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+    EXISTS_TAC `(cball(a,r) INTER t) UNION
+                ((t:real^N->bool) DIFF ball(a,r))` THEN
+    (CONJ_TAC THENL
+      [ALL_TAC;
+       MP_TAC(ISPECL [`a:real^N`; `r:real`] BALL_SUBSET_CBALL) THEN
+       ASM SET_TAC[]]) THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CASES THEN
+    ASM_SIMP_TAC[CLOSED_CBALL; CLOSED_DIFF; OPEN_BALL; CONTINUOUS_ON_ID;
+             GSYM IN_DIFF; CBALL_DIFF_BALL; CLOSED_AFFINE; CLOSED_INTER] THEN
+    MP_TAC(ISPECL [`a:real^N`; `r:real`] SPHERE_SUBSET_CBALL) THEN
+    MP_TAC(ISPECL [`a:real^N`; `r:real`] CBALL_DIFF_BALL) THEN
+    ASM SET_TAC[]) in
+  REWRITE_TAC[TAUT `p /\ q /\ r /\ s /\ t ==> u <=>
+                    p /\ q /\ r /\ s ==> t ==> u`] THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN
+  ONCE_REWRITE_TAC[TAUT `p ==> q <=> p ==> p /\ q`] THEN
+  MATCH_MP_TAC CONNECTED_EQUIVALENCE_RELATION THEN ASM_REWRITE_TAC[] THEN
+  REPEAT CONJ_TAC THEN X_GEN_TAC `a:real^N` THENL
+   [X_GEN_TAC `b:real^N` THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    ASM_REWRITE_TAC[] THEN
+    GEN_REWRITE_TAC LAND_CONV [SWAP_EXISTS_THM] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^N->real^N` THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^N` THEN
+    REWRITE_TAC[HOMEOMORPHISM] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[TAUT `~(p /\ q) <=> ~(q /\ p)`] THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    MAP_EVERY X_GEN_TAC [`b:real^N`; `c:real^N`] THEN
+    MAP_EVERY (fun t -> ASM_CASES_TAC t THEN ASM_REWRITE_TAC[])
+     [`(a:real^N) IN s`; `(b:real^N) IN s`; `(c:real^N) IN s`] THEN
+    ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`f1:real^N->real^N`; `g1:real^N->real^N`] THEN
+    STRIP_TAC THEN
+    MAP_EVERY X_GEN_TAC [`f2:real^N->real^N`; `g2:real^N->real^N`] THEN
+    STRIP_TAC THEN
+    EXISTS_TAC `(f2:real^N->real^N) o (f1:real^N->real^N)` THEN
+    EXISTS_TAC `(g1:real^N->real^N) o (g2:real^N->real^N)` THEN
+    ASM_REWRITE_TAC[o_THM] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[HOMEOMORPHISM_COMPOSE]; ALL_TAC] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC BOUNDED_SUBSET THEN
+    EXISTS_TAC `{x | ~(f1 x = x /\ g1 x = x)} UNION
+                {x:real^N | ~(f2 x = x /\ g2 x = x)}` THEN
+    ASM_REWRITE_TAC[BOUNDED_UNION] THEN ASM SET_TAC[];
+    DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_IN_CONTAINS_BALL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `a:real^N` o CONJUNCT2) THEN ASM_SIMP_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `s INTER ball(a:real^N,r)` THEN
+    ASM_SIMP_TAC[IN_INTER; CENTRE_IN_BALL; OPEN_IN_OPEN_INTER; OPEN_BALL] THEN
+    X_GEN_TAC `b:real^N` THEN STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`a:real^N`; `affine hull s:real^N->bool`;
+      `a:real^N`; `b:real^N`; `r:real`; `t:real^N->bool`]
+        lemma3) THEN
+    ASM_SIMP_TAC[CENTRE_IN_BALL; AFFINE_AFFINE_HULL; HULL_INC; IN_INTER] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    ASM_MESON_TAC[BOUNDED_SUBSET; BOUNDED_BALL; INTER_SUBSET; SUBSET_TRANS]]);;
+
+let HOMEOMORPHISM_MOVING_POINTS_EXISTS_GEN = prove
+ (`!s t x (y:A->real^N) k.
+        &2 <= aff_dim s /\ open_in (subtopology euclidean (affine hull s)) s /\
+        s SUBSET t /\ t SUBSET affine hull s /\ connected s /\
+        FINITE k /\ (!i. i IN k ==> x i IN s /\ y i IN s) /\
+        pairwise (\i j. ~(x i = x j) /\ ~(y i = y j)) k
+        ==> ?f g. homeomorphism (t,t) (f,g) /\
+                  (!i. i IN k ==> f(x i) = y i) /\
+                  {x | ~(f x = x /\ g x = x)} SUBSET s /\
+                  bounded {x | ~(f x = x /\ g x = x)}`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `FINITE(k:A->bool)` THEN ASM_REWRITE_TAC[] THEN
+  SPEC_TAC(`s:real^N->bool`,`s:real^N->bool`) THEN POP_ASSUM MP_TAC THEN
+  SPEC_TAC(`k:A->bool`,`k:A->bool`) THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  CONJ_TAC THENL
+   [GEN_TAC THEN STRIP_TAC THEN REPEAT(EXISTS_TAC `I:real^N->real^N`) THEN
+    REWRITE_TAC[HOMEOMORPHISM_I; NOT_IN_EMPTY; I_THM; EMPTY_GSPEC] THEN
+    REWRITE_TAC[EMPTY_SUBSET; BOUNDED_EMPTY];
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`i:A`; `k:A->bool`] THEN STRIP_TAC THEN
+  X_GEN_TAC `s:real^N->bool` THEN
+  REWRITE_TAC[PAIRWISE_INSERT; FORALL_IN_INSERT] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `s:real^N->bool`) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`f:real^N->real^N`; `g:real^N->real^N`] THEN
+  STRIP_TAC THEN MP_TAC(ISPECL
+   [`s DIFF IMAGE (y:A->real^N) k`; `t:real^N->bool`;
+    `(f:real^N->real^N) ((x:A->real^N) i)`; `(y:A->real^N) i`]
+   HOMEOMORPHISM_MOVING_POINT_EXISTS) THEN
+  SUBGOAL_THEN
+   `affine hull (s DIFF (IMAGE (y:A->real^N) k)) = affine hull s`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC AFFINE_HULL_OPEN_IN THEN CONJ_TAC THENL
+     [TRANS_TAC OPEN_IN_TRANS `s:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC OPEN_IN_DIFF THEN REWRITE_TAC[OPEN_IN_REFL] THEN
+      MATCH_MP_TAC FINITE_IMP_CLOSED_IN THEN
+      ASM_SIMP_TAC[FINITE_IMAGE] THEN ASM SET_TAC[];
+
+      REWRITE_TAC[SET_RULE `s DIFF t = {} <=> s SUBSET t`] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+        FINITE_SUBSET)) THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; CONNECTED_FINITE_IFF_SING] THEN
+      UNDISCH_TAC `&2 <= aff_dim(s:real^N->bool)` THEN
+      ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+      REWRITE_TAC[] THEN STRIP_TAC THEN
+      ASM_REWRITE_TAC[AFF_DIM_EMPTY; AFF_DIM_SING] THEN
+      CONV_TAC INT_REDUCE_CONV];
+    ASM_REWRITE_TAC[]] THEN
+  ANTS_TAC THENL
+   [REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC OPEN_IN_DIFF THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC FINITE_IMP_CLOSED_IN THEN ASM_SIMP_TAC[FINITE_IMAGE] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC HULL_INC THEN ASM SET_TAC[];
+      ASM SET_TAC[];
+      MATCH_MP_TAC CONNECTED_OPEN_IN_DIFF_CARD_LT THEN
+      ASM_REWRITE_TAC[COLLINEAR_AFF_DIM;
+                      INT_ARITH `~(s:int <= &1) <=> &2 <= s`] THEN
+      MATCH_MP_TAC CARD_LT_FINITE_INFINITE THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; real_INFINITE];
+      ALL_TAC; ALL_TAC] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[homeomorphism]) THEN REWRITE_TAC[IN_DIFF] THEN
+    (CONJ_TAC THENL [ASM SET_TAC[]; ASM_REWRITE_TAC[IN_DIFF]]) THEN
+    SIMP_TAC[SET_RULE `~(y IN IMAGE f s) <=> !x. x IN s ==> ~(f x = y)`] THEN
+    ASM SET_TAC[];
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`h:real^N->real^N`; `k:real^N->real^N`] THEN
+    STRIP_TAC THEN MAP_EVERY EXISTS_TAC
+     [`(h:real^N->real^N) o (f:real^N->real^N)`;
+      `(g:real^N->real^N) o (k:real^N->real^N)`] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[HOMEOMORPHISM_COMPOSE]; ALL_TAC] THEN
+    ASM_SIMP_TAC[o_THM] THEN
+    REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+    MATCH_MP_TAC BOUNDED_SUBSET THEN
+    EXISTS_TAC `{x | ~(f x = x /\ g x = x)} UNION
+                {x:real^N | ~(h x = x /\ k x = x)}` THEN
+    ASM_REWRITE_TAC[BOUNDED_UNION] THEN ASM SET_TAC[]]);;
+
+let HOMEOMORPHISM_MOVING_POINTS_EXISTS = prove
+ (`!s t x (y:A->real^N) k.
+        2 <= dimindex(:N) /\ open s /\ connected s /\ s SUBSET t /\
+        FINITE k /\ (!i. i IN k ==> x i IN s /\ y i IN s) /\
+        pairwise (\i j. ~(x i = x j) /\ ~(y i = y j)) k
+        ==> ?f g. homeomorphism (t,t) (f,g) /\
+                  (!i. i IN k ==> f(x i) = y i) /\
+                  {x | ~(f x = x /\ g x = x)} SUBSET s /\
+                  bounded {x | ~(f x = x /\ g x = x)}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [STRIP_TAC THEN REPEAT(EXISTS_TAC `I:real^N->real^N`) THEN
+    REWRITE_TAC[HOMEOMORPHISM_I; NOT_IN_EMPTY; I_THM; EMPTY_GSPEC] THEN
+    REWRITE_TAC[EMPTY_SUBSET; BOUNDED_EMPTY] THEN ASM SET_TAC[];
+    STRIP_TAC] THEN
+  MATCH_MP_TAC HOMEOMORPHISM_MOVING_POINTS_EXISTS_GEN THEN
+  ASM_REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+  SUBGOAL_THEN `affine hull s = (:real^N)` SUBST1_TAC THENL
+   [MATCH_MP_TAC AFFINE_HULL_OPEN THEN ASM SET_TAC[];
+    ASM_REWRITE_TAC[SUBTOPOLOGY_UNIV; GSYM OPEN_IN; AFF_DIM_UNIV] THEN
+    ASM_REWRITE_TAC[INT_OF_NUM_LE; SUBSET_UNIV]]);;
+
+let HOMEOMORPHISM_GROUPING_POINTS_EXISTS = prove
+ (`!u s t k:real^N->bool.
+        open u /\ open s /\ connected s /\ ~(u = {}) /\
+        FINITE k /\ k SUBSET s /\ u SUBSET s /\ s SUBSET t
+        ==> ?f g. homeomorphism (t,t) (f,g) /\
+                  {x | ~(f x = x /\ g x = x)} SUBSET s /\
+                  bounded {x | ~(f x = x /\ g x = x)} /\
+                  !x. x IN k ==> (f x) IN u`,
+  let lemma1 = prove
+   (`!a b:real^1 c d:real^1.
+          drop a < drop b /\ drop c < drop d
+          ==> ?f g. homeomorphism (interval[a,b],interval[c,d]) (f,g) /\
+                    f(a) = c /\ f(b) = d`,
+    REPEAT STRIP_TAC THEN EXISTS_TAC
+     `\x. c + (drop x - drop a) / (drop b - drop a) % (d - c:real^1)` THEN
+    ASM_SIMP_TAC[REAL_DIV_REFL; REAL_SUB_LT; REAL_LT_IMP_NZ;
+                 REAL_ARITH `(a - a) / x = &0`; LEFT_EXISTS_AND_THM] THEN
+    CONJ_TAC THENL [ALL_TAC; VECTOR_ARITH_TAC] THEN
+    MATCH_MP_TAC HOMEOMORPHISM_COMPACT THEN
+    REWRITE_TAC[COMPACT_INTERVAL] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_VMUL THEN
+      REWRITE_TAC[LIFT_CMUL; real_div; o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_VMUL THEN
+      REWRITE_TAC[o_DEF; LIFT_SUB; LIFT_DROP] THEN
+      SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID];
+      REWRITE_TAC[EXTENSION; IN_INTERVAL_1; IN_IMAGE] THEN
+      ASM_SIMP_TAC[GSYM DROP_EQ; DROP_ADD; DROP_CMUL; DROP_SUB; REAL_FIELD
+       `a < b /\ c < d
+        ==> (x = c + (y - a) / (b - a) * (d - c) <=>
+             a + (x - c) / (d - c) * (b - a) = y)`] THEN
+      REWRITE_TAC[GSYM EXISTS_DROP; UNWIND_THM1] THEN
+      REWRITE_TAC[REAL_ARITH
+       `c <= c + x /\ c + x <= d <=> &0 <= x /\ x <= &1 * (d - c)`] THEN
+      ASM_SIMP_TAC[REAL_LE_MUL_EQ; REAL_LE_RMUL_EQ; REAL_SUB_LT] THEN
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; REAL_SUB_LT] THEN
+      REAL_ARITH_TAC;
+      ASM_SIMP_TAC[VECTOR_ARITH `a + x:real^N = a + y <=> x = y`;
+                  REAL_FIELD `a < b ==> (x / (b - a) = y / (b - a) <=> x = y)`;
+                  REAL_ARITH `x - a:real = y - a <=> x = y`;
+                  VECTOR_MUL_RCANCEL; DROP_EQ; VECTOR_SUB_EQ] THEN
+      ASM_MESON_TAC[REAL_LT_REFL]]) in
+  let lemma2 = prove
+   (`!a b c:real^1 u v w:real^1 f1 g1 f2 g2.
+          homeomorphism (interval[a,b],interval[u,v]) (f1,g1) /\
+          homeomorphism (interval[b,c],interval[v,w]) (f2,g2)
+          ==> b IN interval[a,c] /\ v IN interval[u,w] /\
+              f1 a = u /\ f1 b = v /\ f2 b = v /\ f2 c = w
+              ==> ?f g. homeomorphism(interval[a,c],interval[u,w]) (f,g) /\
+                        f a = u /\ f c = w /\
+                        (!x. x IN interval[a,b] ==> f x = f1 x) /\
+                        (!x. x IN interval[b,c] ==> f x = f2 x)`,
+    REWRITE_TAC[IN_INTERVAL_1] THEN REPEAT STRIP_TAC THEN REPEAT(FIRST_X_ASSUM
+     (STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [homeomorphism])) THEN
+    EXISTS_TAC `\x. if drop x <= drop b then (f1:real^1->real^1) x
+                    else f2 x` THEN
+    ASM_REWRITE_TAC[LEFT_EXISTS_AND_THM; REAL_LE_REFL] THEN
+    ASM_SIMP_TAC[DROP_EQ; REAL_ARITH `b <= c ==> (c <= b <=> c = b)`] THEN
+    CONJ_TAC THENL [REWRITE_TAC[GSYM CONJ_ASSOC]; ASM_MESON_TAC[]] THEN
+    MATCH_MP_TAC HOMEOMORPHISM_COMPACT THEN
+    REWRITE_TAC[COMPACT_INTERVAL] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_CASES_LE THEN
+      ASM_SIMP_TAC[o_DEF; LIFT_DROP; CONTINUOUS_ON_ID; DROP_EQ] THEN
+      CONJ_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+      SIMP_TAC[SUBSET; FORALL_DROP; IN_ELIM_THM; IN_INTERVAL_1];
+      SUBGOAL_THEN
+       `interval[a:real^1,c] = interval[a,b] UNION interval[b,c] /\
+        interval[u:real^1,w] = interval[u,v] UNION interval[v,w]`
+      (CONJUNCTS_THEN SUBST1_TAC) THENL
+       [REWRITE_TAC[EXTENSION; IN_UNION; IN_INTERVAL_1] THEN
+        ASM_REAL_ARITH_TAC;
+        REWRITE_TAC[IMAGE_UNION] THEN BINOP_TAC THEN FIRST_X_ASSUM(fun th ->
+          GEN_REWRITE_TAC RAND_CONV [SYM th]) THEN
+        MATCH_MP_TAC(SET_RULE
+         `(!x. x IN s ==> f x = g x) ==> IMAGE f s = IMAGE g s`) THEN
+        SIMP_TAC[IN_INTERVAL_1; REAL_ARITH
+           `b <= c ==> (c <= b <=> c = b)`] THEN
+        ASM_MESON_TAC[DROP_EQ]];
+      REWRITE_TAC[FORALL_LIFT] THEN MATCH_MP_TAC REAL_WLOG_LT THEN
+      REWRITE_TAC[] THEN CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+      REWRITE_TAC[FORALL_DROP; LIFT_DROP; IN_INTERVAL_1] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN DISCH_TAC THEN
+      ASM_CASES_TAC `drop y <= drop b` THEN ASM_REWRITE_TAC[] THENL
+       [COND_CASES_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; REAL_NOT_LE]) THEN
+        ASM_MESON_TAC[];
+        ALL_TAC] THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; REAL_NOT_LE]) THENL
+       [ALL_TAC; ASM_MESON_TAC[REAL_LT_IMP_LE]] THEN
+      STRIP_TAC THEN
+      SUBGOAL_THEN `(f1:real^1->real^1) x IN interval[u,v] INTER interval[v,w]`
+      MP_TAC THENL
+       [REWRITE_TAC[IN_INTER] THEN CONJ_TAC THENL
+         [ALL_TAC; ASM_REWRITE_TAC[]] THEN
+        FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [SYM th]) THEN
+        MATCH_MP_TAC FUN_IN_IMAGE THEN ASM_REWRITE_TAC[IN_INTERVAL_1] THEN
+        ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[IN_INTER; IN_INTERVAL_1] THEN DISCH_THEN(MP_TAC o MATCH_MP
+       (REAL_ARITH `(a <= x /\ x <= b) /\ (b <= x /\ x <= c) ==> x = b`)) THEN
+      REWRITE_TAC[DROP_EQ] THEN DISCH_TAC THEN
+      SUBGOAL_THEN
+       `(f1:real^1->real^1) x = f1 b /\ (f2:real^1->real^1) y = f2 b`
+      MP_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+      MATCH_MP_TAC(MESON[]
+       `!g1:real^1->real^1 g2:real^1->real^1.
+          g1(f1 x) = x /\ g1(f1 b) = b /\ g2(f2 y) = y /\ g2(f2 b) = b
+          ==> f1 x = f1 b /\ f2 y = f2 b ==> x = y`) THEN
+      MAP_EVERY EXISTS_TAC [`g1:real^1->real^1`; `g2:real^1->real^1`] THEN
+      REPEAT CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REAL_ARITH_TAC]) in
+  let lemma3 = prove
+   (`!a b c d u v:real^1.
+          interval[c,d] SUBSET interval(a,b) /\
+          interval[u,v] SUBSET interval(a,b) /\
+          ~(interval(c,d) = {}) /\ ~(interval(u,v) = {})
+          ==> ?f g. homeomorphism (interval[a,b],interval[a,b]) (f,g) /\
+                    f a = a /\ f b = b /\
+                    !x. x IN interval[c,d] ==> f(x) IN interval[u,v]`,
+    REPEAT GEN_TAC THEN
+    REWRITE_TAC[SUBSET_INTERVAL_1; INTERVAL_NE_EMPTY_1] THEN
+    ASM_CASES_TAC `drop u < drop v` THEN
+    ASM_SIMP_TAC[REAL_ARITH `u < v ==> ~(v < u)`] THEN
+    ASM_CASES_TAC `interval[c:real^1,d] = {}` THENL
+     [DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+      REPEAT(EXISTS_TAC `I:real^1->real^1`) THEN
+      REWRITE_TAC[HOMEOMORPHISM_I; NOT_IN_EMPTY; I_THM];
+      RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY_1]) THEN
+      ASM_SIMP_TAC[REAL_ARITH `c <= d ==> ~(d < c)`] THEN STRIP_TAC] THEN
+    MP_TAC(ISPECL [`d:real^1`; `b:real^1`; `v:real^1`; `b:real^1`] lemma1) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`f3:real^1->real^1`; `g3:real^1->real^1`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`c:real^1`; `d:real^1`; `u:real^1`; `v:real^1`] lemma1) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`f2:real^1->real^1`; `g2:real^1->real^1`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`a:real^1`; `c:real^1`; `a:real^1`; `u:real^1`] lemma1) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`f1:real^1->real^1`; `g1:real^1->real^1`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+    GEN_REWRITE_TAC I [IMP_IMP] THEN DISCH_THEN(fun th ->
+      ASSUME_TAC(CONJUNCT2 th) THEN MP_TAC(MATCH_MP lemma2 th)) THEN
+    ASM_SIMP_TAC[IN_INTERVAL_1; REAL_LT_IMP_LE; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`f4:real^1->real^1`; `g4:real^1->real^1`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+    GEN_REWRITE_TAC I [IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP lemma2) THEN
+    ASM_SIMP_TAC[IN_INTERVAL_1; REAL_LT_IMP_LE; LEFT_IMP_EXISTS_THM] THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN SIMP_TAC[] THEN
+    DISCH_THEN(STRIP_ASSUME_TAC o CONJUNCT2) THEN
+    X_GEN_TAC `x:real^1` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [HOMEOMORPHISM]) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1]) THEN
+    SUBGOAL_THEN `drop a <= drop x` ASSUME_TAC THENL
+     [ASM_REAL_ARITH_TAC; ASM_SIMP_TAC[]]) in
+  let lemma4 = prove
+   (`!s k u t:real^1->bool.
+          open u /\ open s /\ connected s /\ ~(u = {}) /\
+          FINITE k /\ k SUBSET s /\ u SUBSET s /\ s SUBSET t
+          ==> ?f g. homeomorphism (t,t) (f,g) /\
+                    (!x. x IN k ==> f(x) IN u) /\
+                    {x | ~(f x = x /\ g x = x)} SUBSET s /\
+                    bounded {x | ~(f x = x /\ g x = x)}`,
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+     `?c d:real^1. ~(interval(c,d) = {}) /\ interval[c,d] SUBSET u`
+    STRIP_ASSUME_TAC THENL
+     [UNDISCH_TAC `open(u:real^1->bool)` THEN
+      REWRITE_TAC[OPEN_CONTAINS_INTERVAL] THEN
+      FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+      DISCH_THEN(X_CHOOSE_TAC `y:real^1`) THEN
+      DISCH_THEN(MP_TAC o SPEC `y:real^1`) THEN
+      ASM_REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN MESON_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?a b:real^1. ~(interval(a,b) = {}) /\
+                   k SUBSET interval[a,b] /\
+                   interval[a,b] SUBSET s`
+    STRIP_ASSUME_TAC THENL
+     [ASM_CASES_TAC `k:real^1->bool = {}` THENL
+       [ASM_MESON_TAC[SUBSET_TRANS; EMPTY_SUBSET]; ALL_TAC] THEN
+      MP_TAC(SPEC `IMAGE drop k` COMPACT_ATTAINS_SUP) THEN
+      MP_TAC(SPEC `IMAGE drop k` COMPACT_ATTAINS_INF) THEN
+      ASM_SIMP_TAC[GSYM IMAGE_o; o_DEF; LIFT_DROP; IMAGE_EQ_EMPTY;
+        IMAGE_ID; FINITE_IMP_COMPACT; EXISTS_IN_IMAGE; FORALL_IN_IMAGE] THEN
+      DISCH_THEN(X_CHOOSE_THEN `a:real^1` STRIP_ASSUME_TAC) THEN
+      DISCH_THEN(X_CHOOSE_THEN `b:real^1` STRIP_ASSUME_TAC) THEN
+      UNDISCH_TAC `open(s:real^1->bool)` THEN
+      REWRITE_TAC[OPEN_CONTAINS_INTERVAL] THEN
+      DISCH_THEN(MP_TAC o SPEC `b:real^1`) THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[LEFT_IMP_EXISTS_THM]] THEN
+      MAP_EVERY X_GEN_TAC [`u:real^1`; `v:real^1`] THEN
+      REWRITE_TAC[SUBSET; IN_INTERVAL_1] THEN STRIP_TAC THEN
+      MAP_EVERY EXISTS_TAC [`a:real^1`; `v:real^1`] THEN
+      REWRITE_TAC[INTERVAL_NE_EMPTY_1] THEN FIRST_X_ASSUM(MP_TAC o
+        GEN_REWRITE_RULE I [GSYM IS_INTERVAL_CONNECTED_1]) THEN
+      REWRITE_TAC[IS_INTERVAL_1] THEN
+      ASM_MESON_TAC[GSYM MEMBER_NOT_EMPTY; REAL_LET_TRANS; REAL_LE_TRANS;
+                    REAL_LT_IMP_LE; SUBSET; REAL_LE_TOTAL];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?w z:real^1. interval[w,z] SUBSET s /\
+                   interval[a,b] UNION interval[c,d] SUBSET interval(w,z)`
+    STRIP_ASSUME_TAC THENL
+     [SUBGOAL_THEN
+        `?w z:real^1. interval[w,z] SUBSET s /\
+                      interval[a,b] UNION interval[c,d] SUBSET interval[w,z]`
+      STRIP_ASSUME_TAC THENL
+       [EXISTS_TAC `lift(min (drop a) (drop c))` THEN
+        EXISTS_TAC `lift(max (drop b) (drop d))` THEN
+        REWRITE_TAC[UNION_SUBSET; SUBSET_INTERVAL_1; LIFT_DROP] THEN
+        CONJ_TAC THENL
+         [FIRST_X_ASSUM(MP_TAC o
+           GEN_REWRITE_RULE I [GSYM IS_INTERVAL_CONNECTED_1]) THEN
+          REWRITE_TAC[IS_INTERVAL_1; SUBSET; IN_INTERVAL_1; LIFT_DROP] THEN
+          REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+          EXISTS_TAC `lift(min (drop a) (drop c))` THEN
+          EXISTS_TAC `lift(max (drop b) (drop d))` THEN
+          ASM_REWRITE_TAC[LIFT_DROP] THEN
+          REWRITE_TAC[real_min; real_max] THEN CONJ_TAC THEN
+          COND_CASES_TAC THEN ASM_REWRITE_TAC[LIFT_DROP] THEN
+          ASM_MESON_TAC[ENDS_IN_INTERVAL; SUBSET; INTERVAL_EQ_EMPTY_1;
+                        REAL_LT_IMP_LE];
+          ASM_REAL_ARITH_TAC];
+        UNDISCH_TAC `open(s:real^1->bool)` THEN
+        REWRITE_TAC[OPEN_CONTAINS_INTERVAL] THEN DISCH_THEN(fun th ->
+          MP_TAC(SPEC `z:real^1` th) THEN MP_TAC(SPEC `w:real^1` th)) THEN
+        SUBGOAL_THEN `(w:real^1) IN interval[w,z] /\ z IN interval[w,z]`
+        STRIP_ASSUME_TAC THENL
+         [REWRITE_TAC[ENDS_IN_INTERVAL] THEN MP_TAC
+           (ISPECL [`a:real^1`; `b:real^1`] INTERVAL_OPEN_SUBSET_CLOSED) THEN
+          ASM SET_TAC[];
+          REWRITE_TAC[UNION_SUBSET]] THEN
+        ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[LEFT_IMP_EXISTS_THM]] THEN
+        MAP_EVERY X_GEN_TAC [`w0:real^1`; `w1:real^1`] THEN
+        REWRITE_TAC[IN_INTERVAL_1; SUBSET] THEN STRIP_TAC THEN
+        ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[LEFT_IMP_EXISTS_THM]] THEN
+        MAP_EVERY X_GEN_TAC [`z0:real^1`; `z1:real^1`] THEN
+        STRIP_TAC THEN MAP_EVERY EXISTS_TAC [`w0:real^1`; `z1:real^1`] THEN
+        RULE_ASSUM_TAC
+         (REWRITE_RULE[ENDS_IN_UNIT_INTERVAL; INTERVAL_NE_EMPTY_1;
+                       UNION_SUBSET; SUBSET_INTERVAL_1]) THEN
+        CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; IN_INTERVAL_1]) THEN
+        X_GEN_TAC `x:real^1` THEN
+        REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `x:real^1`)) THEN
+        ASM_CASES_TAC `(x:real^1) IN s` THEN ASM_REWRITE_TAC[] THEN
+        ASM_REAL_ARITH_TAC];
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [UNION_SUBSET]) THEN
+    MP_TAC(ISPECL
+     [`w:real^1`; `z:real^1`; `a:real^1`; `b:real^1`; `c:real^1`; `d:real^1`]
+     lemma3) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`f:real^1->real^1`; `g:real^1->real^1`] THEN
+    REWRITE_TAC[homeomorphism] THEN STRIP_TAC THEN
+    EXISTS_TAC `\x:real^1. if x IN interval[w,z] then f x else x` THEN
+    EXISTS_TAC `\x:real^1. if x IN interval[w,z] then g x else x` THEN
+    ASSUME_TAC(ISPECL [`w:real^1`; `z:real^1`]INTERVAL_OPEN_SUBSET_CLOSED) THEN
+    REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [ASM SET_TAC[];
+      ASM SET_TAC[];
+      ALL_TAC;
+      ASM SET_TAC[];
+      ASM SET_TAC[];
+      ALL_TAC;
+      ASM SET_TAC[];
+      ASM SET_TAC[];
+      MATCH_MP_TAC BOUNDED_SUBSET THEN EXISTS_TAC `interval[w:real^1,z]` THEN
+      REWRITE_TAC[BOUNDED_INTERVAL] THEN ASM SET_TAC[]] THEN
+    (SUBGOAL_THEN
+      `t = interval[w:real^1,z] UNION (t DIFF interval(w,z))`
+      (fun th -> SUBST1_TAC th THEN
+                 MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN
+                 ASSUME_TAC(SYM th))
+     THENL [ASM SET_TAC[]; ASM_REWRITE_TAC[]] THEN
+     ASM_REWRITE_TAC[CONTINUOUS_ON_ID] THEN REPEAT CONJ_TAC THENL
+      [MATCH_MP_TAC CLOSED_SUBSET THEN REWRITE_TAC[CLOSED_INTERVAL] THEN
+       ASM SET_TAC[];
+       MATCH_MP_TAC CLOSED_IN_DIFF THEN REWRITE_TAC[CLOSED_IN_REFL] THEN
+       MATCH_MP_TAC OPEN_SUBSET THEN REWRITE_TAC[OPEN_INTERVAL] THEN
+       ASM SET_TAC[];
+       REWRITE_TAC[CLOSED_DIFF_OPEN_INTERVAL_1; SET_RULE
+        `p /\ ~p \/ x IN t DIFF s /\ x IN u <=> x IN t /\ x IN u DIFF s`] THEN
+       MAP_EVERY (MP_TAC o ISPECL [`w:real^1`; `z:real^1`])
+                 (CONJUNCTS ENDS_IN_INTERVAL) THEN
+       ASM SET_TAC[]])) in
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `2 <= dimindex(:N)` THENL
+   [MP_TAC(ISPECL
+     [`CARD(k:real^N->bool)`; `u:real^N->bool`] CHOOSE_SUBSET_STRONG) THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[FINITE_IMP_NOT_OPEN]; ALL_TAC] THEN
+    REWRITE_TAC[HAS_SIZE; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `p:real^N->bool` THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`k:real^N->bool`; `p:real^N->bool`] CARD_EQ_BIJECTION) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `y:real^N->real^N` THEN STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`s:real^N->bool`; `t:real^N->bool`; `\x:real^N. x`;
+      `y:real^N->real^N`; `k:real^N->bool`]
+     HOMEOMORPHISM_MOVING_POINTS_EXISTS) THEN
+    ASM_REWRITE_TAC[pairwise] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_REWRITE_TAC[] THEN
+    ASM SET_TAC[];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_LE]) THEN
+    SIMP_TAC[DIMINDEX_GE_1; ARITH_RULE `1 <= n ==> (n < 2 <=> n = 1)`] THEN
+    REWRITE_TAC[GSYM DIMINDEX_1] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP ISOMORPHISMS_UNIV_UNIV) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`h:real^N->real^1`; `j:real^1->real^N`] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPECL
+     [`IMAGE (h:real^N->real^1) s`;
+      `IMAGE (h:real^N->real^1) k`;
+      `IMAGE (h:real^N->real^1) u`;
+      `IMAGE (h:real^N->real^1) t`]
+        lemma4) THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; IMAGE_SUBSET; IMAGE_EQ_EMPTY;
+                 CONNECTED_CONTINUOUS_IMAGE; LINEAR_CONTINUOUS_ON] THEN
+    ANTS_TAC THENL
+     [ASM_MESON_TAC[OPEN_BIJECTIVE_LINEAR_IMAGE_EQ];
+      REWRITE_TAC[LEFT_IMP_EXISTS_THM; homeomorphism]] THEN
+    MAP_EVERY X_GEN_TAC [`f:real^1->real^1`; `g:real^1->real^1`] THEN
+    STRIP_TAC THEN MAP_EVERY EXISTS_TAC
+     [`(j:real^1->real^N) o (f:real^1->real^1) o (h:real^N->real^1)`;
+      `(j:real^1->real^N) o (g:real^1->real^1) o (h:real^N->real^1)`] THEN
+    ASM_REWRITE_TAC[o_THM; IMAGE_o] THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_COMPOSE; LINEAR_CONTINUOUS_ON] THEN
+    ASM_REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `{x | ~(j ((f:real^1->real^1) (h x)) = x /\ j (g (h x)) = x)} =
+      IMAGE (j:real^1->real^N) {x | ~(f x = x /\ g x = x)}`
+    SUBST1_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    ASM_SIMP_TAC[BOUNDED_LINEAR_IMAGE]]);;
+
+let HOMEOMORPHISM_GROUPING_POINTS_EXISTS_GEN = prove
+ (`!u s t k:real^N->bool.
+        open_in (subtopology euclidean (affine hull s)) s /\
+        s SUBSET t /\ t SUBSET affine hull s /\ connected s /\
+        FINITE k /\ k SUBSET s /\
+        open_in (subtopology euclidean s) u /\ ~(u = {})
+        ==> ?f g. homeomorphism (t,t) (f,g) /\
+                  (!x. x IN k ==> f(x) IN u) /\
+                  {x | ~(f x = x /\ g x = x)} SUBSET s /\
+                  bounded {x | ~(f x = x /\ g x = x)}`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `&2 <= aff_dim(s:real^N->bool)` THENL
+   [MP_TAC(ISPECL
+     [`CARD(k:real^N->bool)`; `u:real^N->bool`] CHOOSE_SUBSET_STRONG) THEN
+    ANTS_TAC THENL
+     [MATCH_MP_TAC(TAUT `~p ==> p ==> q`) THEN REWRITE_TAC[GSYM INFINITE] THEN
+      MATCH_MP_TAC INFINITE_OPEN_IN THEN
+      EXISTS_TAC `affine hull s:real^N->bool` THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[OPEN_IN_TRANS]; ALL_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 `y:real^N` THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC CONNECTED_IMP_PERFECT_AFF_DIM THEN
+      ASM_SIMP_TAC[CONVEX_CONNECTED; AFFINE_AFFINE_HULL; AFFINE_IMP_CONVEX;
+                   AFF_DIM_AFFINE_HULL] THEN
+      CONJ_TAC THENL [ASM_INT_ARITH_TAC; ALL_TAC] THEN
+      ASM_MESON_TAC[OPEN_IN_IMP_SUBSET; SUBSET];
+      REWRITE_TAC[HAS_SIZE; LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `p:real^N->bool` THEN STRIP_TAC THEN MP_TAC
+       (ISPECL [`k:real^N->bool`; `p:real^N->bool`] CARD_EQ_BIJECTION) THEN
+      ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `y:real^N->real^N` THEN STRIP_TAC THEN
+      MP_TAC(ISPECL
+       [`s:real^N->bool`; `t:real^N->bool`; `\x:real^N. x`;
+        `y:real^N->real^N`; `k:real^N->bool`]
+       HOMEOMORPHISM_MOVING_POINTS_EXISTS_GEN) THEN
+      ASM_REWRITE_TAC[pairwise] THEN
+      REPEAT(FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET)) THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_REWRITE_TAC[] THEN
+      ASM SET_TAC[]];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INT_NOT_LE])] THEN
+  SIMP_TAC[AFF_DIM_GE; INT_ARITH
+   `--(&1):int <= x ==> (x < &2 <=> x = --(&1) \/ x = &0 \/ x = &1)`] THEN
+  REWRITE_TAC[AFF_DIM_EQ_MINUS1; AFF_DIM_EQ_0] THEN
+  SUBGOAL_THEN
+   `(u:real^N->bool) SUBSET s /\ s SUBSET affine hull s`
+  STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[open_in]; ALL_TAC] THEN
+  DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  STRIP_TAC THENL
+   [REPEAT(EXISTS_TAC `I:real^N->real^N`) THEN
+    REWRITE_TAC[HOMEOMORPHISM_I; I_THM; EMPTY_GSPEC; BOUNDED_EMPTY] THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`affine hull s:real^N->bool`; `(:real^1)`]
+   HOMEOMORPHIC_AFFINE_SETS) THEN
+  ASM_REWRITE_TAC[AFF_DIM_UNIV; AFFINE_AFFINE_HULL; AFFINE_UNIV] THEN
+  ASM_REWRITE_TAC[DIMINDEX_1; AFF_DIM_AFFINE_HULL] THEN
+  REWRITE_TAC[homeomorphic; homeomorphism; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`h:real^N->real^1`; `j:real^1->real^N`] THEN
+  STRIP_TAC THEN MP_TAC(ISPECL
+   [`IMAGE (h:real^N->real^1) u`; `IMAGE (h:real^N->real^1) s`;
+    `IMAGE (h:real^N->real^1) t`; `IMAGE (h:real^N->real^1) k`]
+    HOMEOMORPHISM_GROUPING_POINTS_EXISTS) THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; IMAGE_SUBSET; IMAGE_EQ_EMPTY] THEN
+  ANTS_TAC THENL
+   [MP_TAC(ISPECL
+     [`h:real^N->real^1`; `j:real^1->real^N`;
+      `affine hull s:real^N->bool`; `(:real^1)`]
+     HOMEOMORPHISM_IMP_OPEN_MAP) THEN
+    ASM_SIMP_TAC[homeomorphism; SUBTOPOLOGY_UNIV; GSYM OPEN_IN] THEN
+    REPEAT STRIP_TAC THENL [ASM_MESON_TAC[OPEN_IN_TRANS]; ALL_TAC] THEN
+    MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM; homeomorphism]] THEN
+  MAP_EVERY X_GEN_TAC [`f:real^1->real^1`; `g:real^1->real^1`] THEN
+  STRIP_TAC THEN MAP_EVERY EXISTS_TAC
+   [`\x. if x IN affine hull s
+         then ((j:real^1->real^N) o (f:real^1->real^1) o (h:real^N->real^1)) x
+         else x`;
+    `\x. if x IN affine hull s
+         then ((j:real^1->real^N) o (g:real^1->real^1) o (h:real^N->real^1)) x
+         else x`] THEN
+  ASM_SIMP_TAC[o_THM; IMAGE_o] THEN REPEAT CONJ_TAC THENL
+   [ASM SET_TAC[];
+    ASM_SIMP_TAC[SET_RULE
+     `t SUBSET s ==> IMAGE (\x. if x IN s then f x else x) t = IMAGE f t`] THEN
+    REPLICATE_TAC 3 (ONCE_REWRITE_TAC[GSYM o_DEF]) THEN
+    ASM_REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ON_EQ THEN EXISTS_TAC
+     `(j:real^1->real^N) o (f:real^1->real^1) o (h:real^N->real^1)` THEN
+    REWRITE_TAC[o_THM] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+    ASM SET_TAC[];
+    ASM SET_TAC[];
+    ASM_SIMP_TAC[SET_RULE
+     `t SUBSET s ==> IMAGE (\x. if x IN s then f x else x) t = IMAGE f t`] THEN
+    REPLICATE_TAC 3 (ONCE_REWRITE_TAC[GSYM o_DEF]) THEN
+    ASM_REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ON_EQ THEN EXISTS_TAC
+     `(j:real^1->real^N) o (g:real^1->real^1) o (h:real^N->real^1)` THEN
+    REWRITE_TAC[o_THM] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+    ASM SET_TAC[];
+    ASM SET_TAC[];
+    ALL_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[MESON[] `(if P then f x else x) = x <=> ~P \/ f x = x`] THEN
+  REWRITE_TAC[DE_MORGAN_THM; GSYM LEFT_OR_DISTRIB] THEN
+  (SUBGOAL_THEN
+   `{x | x IN affine hull s /\ (~(j (f (h x)) = x) \/ ~(j (g (h x)) = x))} =
+    IMAGE (j:real^1->real^N) {x | ~(f x = x /\ g x = x)}`
+   SUBST1_TAC THENL [ASM SET_TAC[]; ALL_TAC])
+  THENL
+   [TRANS_TAC SUBSET_TRANS
+     `IMAGE (j:real^1->real^N) (IMAGE (h:real^N->real^1) s)` THEN
+    ASM SET_TAC[];
+    MATCH_MP_TAC(MESON[CLOSURE_SUBSET; BOUNDED_SUBSET; IMAGE_SUBSET]
+     `bounded (IMAGE f (closure s)) ==> bounded (IMAGE f s)`) THEN
+    MATCH_MP_TAC COMPACT_IMP_BOUNDED THEN
+    MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+    ASM_REWRITE_TAC[COMPACT_CLOSURE] THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNIV]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The "inside" and "outside" of a set, i.e. the points respectively in a    *)
+(* bounded or unbounded connected component of the set's complement.         *)
+(* ------------------------------------------------------------------------- *)
+
+let inside = new_definition
+ `inside s = {x | ~(x IN s) /\
+                  bounded(connected_component ((:real^N) DIFF s) x)}`;;
+
+let outside = new_definition
+ `outside s = {x | ~(x IN s) /\
+                   ~bounded(connected_component ((:real^N) DIFF s) x)}`;;
+
+let INSIDE_TRANSLATION = prove
+ (`!a s. inside(IMAGE (\x. a + x) s) = IMAGE (\x. a + x) (inside s)`,
+  REWRITE_TAC[inside] THEN GEOM_TRANSLATE_TAC[]);;
+
+let OUTSIDE_TRANSLATION = prove
+ (`!a s. outside(IMAGE (\x. a + x) s) = IMAGE (\x. a + x) (outside s)`,
+  REWRITE_TAC[outside] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [INSIDE_TRANSLATION; OUTSIDE_TRANSLATION];;
+
+let INSIDE_LINEAR_IMAGE = prove
+ (`!f s. linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+         ==> inside(IMAGE f s) = IMAGE f (inside s)`,
+  REWRITE_TAC[inside] THEN GEOM_TRANSFORM_TAC[]);;
+
+let OUTSIDE_LINEAR_IMAGE = prove
+ (`!f s. linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+         ==> outside(IMAGE f s) = IMAGE f (outside s)`,
+  REWRITE_TAC[outside] THEN GEOM_TRANSFORM_TAC[]);;
+
+add_linear_invariants [INSIDE_LINEAR_IMAGE; OUTSIDE_LINEAR_IMAGE];;
+
+let OUTSIDE = prove
+ (`!s. outside s = {x | ~bounded(connected_component((:real^N) DIFF s) x)}`,
+  GEN_TAC THEN REWRITE_TAC[outside; EXTENSION; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN ASM_CASES_TAC `(x:real^N) IN s` THEN
+  ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[BOUNDED_EMPTY; CONNECTED_COMPONENT_EQ_EMPTY; IN_DIFF]);;
+
+let INSIDE_NO_OVERLAP = prove
+ (`!s. inside s INTER s = {}`,
+  REWRITE_TAC[inside] THEN SET_TAC[]);;
+
+let OUTSIDE_NO_OVERLAP = prove
+ (`!s. outside s INTER s = {}`,
+  REWRITE_TAC[outside] THEN SET_TAC[]);;
+
+let INSIDE_INTER_OUTSIDE = prove
+ (`!s. inside s INTER outside s = {}`,
+  REWRITE_TAC[inside; outside] THEN SET_TAC[]);;
+
+let INSIDE_UNION_OUTSIDE = prove
+ (`!s. inside s UNION outside s = (:real^N) DIFF s`,
+  REWRITE_TAC[inside; outside] THEN SET_TAC[]);;
+
+let INSIDE_EQ_OUTSIDE = prove
+ (`!s. inside s = outside s <=> s = (:real^N)`,
+  REWRITE_TAC[inside; outside] THEN SET_TAC[]);;
+
+let INSIDE_OUTSIDE = prove
+ (`!s. inside s = (:real^N) DIFF (s UNION outside s)`,
+  GEN_TAC THEN MAP_EVERY (MP_TAC o ISPEC `s:real^N->bool`)
+   [INSIDE_INTER_OUTSIDE; INSIDE_UNION_OUTSIDE] THEN
+  SET_TAC[]);;
+
+let OUTSIDE_INSIDE = prove
+ (`!s. outside s = (:real^N) DIFF (s UNION inside s)`,
+  GEN_TAC THEN MAP_EVERY (MP_TAC o ISPEC `s:real^N->bool`)
+   [INSIDE_INTER_OUTSIDE; INSIDE_UNION_OUTSIDE] THEN
+  SET_TAC[]);;
+
+let UNION_WITH_INSIDE = prove
+ (`!s. s UNION inside s = (:real^N) DIFF outside s`,
+  REWRITE_TAC[OUTSIDE_INSIDE] THEN SET_TAC[]);;
+
+let UNION_WITH_OUTSIDE = prove
+ (`!s. s UNION outside s = (:real^N) DIFF inside s`,
+  REWRITE_TAC[INSIDE_OUTSIDE] THEN SET_TAC[]);;
+
+let OUTSIDE_MONO = prove
+ (`!s t. s SUBSET t ==> outside t SUBSET outside s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[OUTSIDE; SUBSET; IN_ELIM_THM] THEN
+  DISCH_TAC THEN GEN_TAC THEN REWRITE_TAC[CONTRAPOS_THM] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] BOUNDED_SUBSET) THEN
+  MATCH_MP_TAC CONNECTED_COMPONENT_MONO THEN ASM SET_TAC[]);;
+
+let INSIDE_MONO = prove
+ (`!s t. s SUBSET t ==> inside s DIFF t SUBSET inside t`,
+  REPEAT STRIP_TAC THEN SIMP_TAC[SUBSET; IN_DIFF; inside; IN_ELIM_THM] THEN
+  GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)
+    ASSUME_TAC) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] BOUNDED_SUBSET) THEN
+  MATCH_MP_TAC CONNECTED_COMPONENT_MONO THEN ASM SET_TAC[]);;
+
+let COBOUNDED_OUTSIDE = prove
+ (`!s:real^N->bool. bounded s ==> bounded((:real^N) DIFF outside s)`,
+  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[outside] THEN
+  REWRITE_TAC[SET_RULE `UNIV DIFF {x | ~(x IN s) /\ ~P x} =
+                        s UNION {x | P x}`] THEN
+  ASM_REWRITE_TAC[BOUNDED_UNION] THEN
+  FIRST_ASSUM(MP_TAC o SPEC `vec 0:real^N` o MATCH_MP BOUNDED_SUBSET_BALL) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC BOUNDED_SUBSET THEN EXISTS_TAC `ball(vec 0:real^N,B)` THEN
+  REWRITE_TAC[BOUNDED_BALL; SUBSET; IN_ELIM_THM; IN_BALL_0] THEN
+  X_GEN_TAC `x:real^N` THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  REWRITE_TAC[REAL_NOT_LT] THEN
+  ASM_CASES_TAC `x:real^N = vec 0` THENL
+   [ASM_REWRITE_TAC[NORM_0] THEN ASM_REAL_ARITH_TAC; DISCH_TAC] THEN
+  REWRITE_TAC[BOUNDED_POS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `C:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(B + C) / norm(x) % x:real^N`) THEN
+  REWRITE_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM] THEN
+  ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0; NOT_IMP] THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+  REWRITE_TAC[IN] THEN REWRITE_TAC[connected_component] THEN
+  EXISTS_TAC `segment[x:real^N,(B + C) / norm(x) % x]` THEN
+  REWRITE_TAC[ENDS_IN_SEGMENT; CONNECTED_SEGMENT] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `(:real^N) DIFF ball(vec 0,B)` THEN
+  ASM_REWRITE_TAC[SET_RULE
+   `UNIV DIFF s SUBSET UNIV DIFF t <=> t SUBSET s`] THEN
+  REWRITE_TAC[SUBSET; IN_DIFF; IN_UNIV; IN_BALL_0] THEN
+  REWRITE_TAC[segment; FORALL_IN_GSPEC] THEN X_GEN_TAC `u:real` THEN
+  STRIP_TAC THEN REWRITE_TAC[REAL_NOT_LT] THEN
+  REWRITE_TAC[GSYM VECTOR_ADD_RDISTRIB; NORM_MUL; VECTOR_MUL_ASSOC] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM REAL_ABS_NORM] THEN
+  REWRITE_TAC[GSYM REAL_ABS_MUL] THEN MATCH_MP_TAC(REAL_ARITH
+   `&0 < B /\ B <= x ==> B <= abs x`) THEN
+  ASM_SIMP_TAC[REAL_ADD_RDISTRIB; REAL_DIV_RMUL; NORM_EQ_0; GSYM
+               REAL_MUL_ASSOC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `(&1 - u) * B + u * (B + C)` THEN
+  ASM_SIMP_TAC[REAL_LE_RADD; REAL_LE_LMUL; REAL_SUB_LE] THEN
+  SIMP_TAC[REAL_ARITH `B <= (&1 - u) * B + u * (B + C) <=> &0 <= u * C`] THEN
+  MATCH_MP_TAC REAL_LE_MUL THEN ASM_REAL_ARITH_TAC);;
+
+let UNBOUNDED_OUTSIDE = prove
+ (`!s:real^N->bool. bounded s ==> ~bounded(outside s)`,
+  MESON_TAC[COBOUNDED_IMP_UNBOUNDED; COBOUNDED_OUTSIDE]);;
+
+let BOUNDED_INSIDE = prove
+ (`!s:real^N->bool. bounded s ==> bounded(inside s)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC BOUNDED_SUBSET THEN
+  EXISTS_TAC `(:real^N) DIFF outside s` THEN
+  ASM_SIMP_TAC[COBOUNDED_OUTSIDE] THEN
+  MP_TAC(ISPEC `s:real^N->bool` INSIDE_INTER_OUTSIDE) THEN SET_TAC[]);;
+
+let CONNECTED_OUTSIDE = prove
+ (`!s:real^N->bool. 2 <= dimindex(:N) /\ bounded s ==> connected(outside s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CONNECTED_IFF_CONNECTED_COMPONENT] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
+  REWRITE_TAC[outside; IN_ELIM_THM] THEN STRIP_TAC THEN
+  MATCH_MP_TAC CONNECTED_COMPONENT_OF_SUBSET THEN
+  EXISTS_TAC `connected_component ((:real^N) DIFF s) x` THEN
+  REWRITE_TAC[SUBSET; IN_UNIV; IN_DIFF; IN_ELIM_THM] THEN CONJ_TAC THENL
+   [X_GEN_TAC `z:real^N` THEN STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[SUBSET]
+      CONNECTED_COMPONENT_SUBSET)) THEN
+    REWRITE_TAC[IN_DIFF] THEN ASM_MESON_TAC[CONNECTED_COMPONENT_EQ];
+    REWRITE_TAC[CONNECTED_COMPONENT_IDEMP] THEN
+    SUBGOAL_THEN `connected_component ((:real^N) DIFF s) x =
+                  connected_component ((:real^N) DIFF s) y`
+    SUBST1_TAC THENL
+     [MATCH_MP_TAC COBOUNDED_UNIQUE_UNBOUNDED_COMPONENT THEN
+      ASM_REWRITE_TAC[SET_RULE `UNIV DIFF (UNIV DIFF s) = s`];
+      ASM_REWRITE_TAC[CONNECTED_COMPONENT_REFL_EQ; IN_DIFF; IN_UNIV]]]);;
+
+let OUTSIDE_CONNECTED_COMPONENT_LT = prove
+ (`!s. outside s =
+            {x | !B. ?y. B < norm(y) /\
+                         connected_component((:real^N) DIFF s) x y}`,
+  REWRITE_TAC[OUTSIDE; bounded; EXTENSION; IN_ELIM_THM] THEN
+  REWRITE_TAC[IN] THEN ASM_MESON_TAC[REAL_NOT_LE]);;
+
+let OUTSIDE_CONNECTED_COMPONENT_LE = prove
+ (`!s. outside s =
+            {x | !B. ?y. B <= norm(y) /\
+                         connected_component((:real^N) DIFF s) x y}`,
+  GEN_TAC THEN REWRITE_TAC[OUTSIDE_CONNECTED_COMPONENT_LT] THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN X_GEN_TAC `x:real^N` THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  MESON_TAC[REAL_LT_IMP_LE; REAL_ARITH `B + &1 <= x ==> B < x`]);;
+
+let NOT_OUTSIDE_CONNECTED_COMPONENT_LT = prove
+ (`!s. 2 <= dimindex(:N) /\ bounded s
+       ==> (:real^N) DIFF (outside s) =
+           {x | !B. ?y. B < norm(y) /\
+                        ~(connected_component((:real^N) DIFF s) x y)}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[OUTSIDE] THEN
+  REWRITE_TAC[EXTENSION; IN_DIFF; IN_UNIV; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN REWRITE_TAC[bounded] THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_TAC `C:real`) THEN X_GEN_TAC `B:real` THEN
+    EXISTS_TAC `(abs B + abs C + &1) % basis 1:real^N` THEN
+    RULE_ASSUM_TAC(ONCE_REWRITE_RULE[GSYM CONTRAPOS_THM]) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN]) THEN
+    CONJ_TAC THENL [ALL_TAC; FIRST_X_ASSUM MATCH_MP_TAC] THEN
+    SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_GE_1; LE_REFL] THEN
+    REAL_ARITH_TAC;
+    DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [BOUNDED_POS]) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `B:real` THEN STRIP_TAC THEN
+    X_GEN_TAC `y:real^N` THEN REWRITE_TAC[IN] THEN DISCH_TAC THEN
+    ONCE_REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `B:real`) THEN DISCH_THEN
+     (X_CHOOSE_THEN `z:real^N` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    REWRITE_TAC[] THEN MATCH_MP_TAC CONNECTED_COMPONENT_TRANS THEN
+    EXISTS_TAC `y:real^N` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC CONNECTED_COMPONENT_OF_SUBSET THEN
+    EXISTS_TAC `(:real^N) DIFF cball(vec 0,B)` THEN
+    ASM_REWRITE_TAC[SUBSET; IN_DIFF; IN_CBALL_0; IN_UNIV; CONTRAPOS_THM] THEN
+    REWRITE_TAC[connected_component] THEN
+    EXISTS_TAC `(:real^N) DIFF cball(vec 0,B)` THEN
+    ASM_SIMP_TAC[SUBSET_REFL; IN_DIFF; IN_UNIV; IN_CBALL_0; REAL_NOT_LE] THEN
+    MATCH_MP_TAC CONNECTED_COMPLEMENT_BOUNDED_CONVEX THEN
+    ASM_SIMP_TAC[BOUNDED_CBALL; CONVEX_CBALL]]);;
+
+let NOT_OUTSIDE_CONNECTED_COMPONENT_LE = prove
+ (`!s. 2 <= dimindex(:N) /\ bounded s
+       ==> (:real^N) DIFF (outside s) =
+           {x | !B. ?y. B <= norm(y) /\
+                        ~(connected_component((:real^N) DIFF s) x y)}`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[NOT_OUTSIDE_CONNECTED_COMPONENT_LT] THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN X_GEN_TAC `x:real^N` THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  MESON_TAC[REAL_LT_IMP_LE; REAL_ARITH `B + &1 <= x ==> B < x`]);;
+
+let INSIDE_CONNECTED_COMPONENT_LT = prove
+ (`!s. 2 <= dimindex(:N) /\ bounded s
+       ==> inside s =
+            {x:real^N | ~(x IN s) /\
+                        !B. ?y. B < norm(y) /\
+                                ~(connected_component((:real^N) DIFF s) x y)}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[INSIDE_OUTSIDE] THEN
+  REWRITE_TAC[SET_RULE `UNIV DIFF (s UNION t) = (UNIV DIFF t) DIFF s`] THEN
+  ASM_SIMP_TAC[NOT_OUTSIDE_CONNECTED_COMPONENT_LT] THEN SET_TAC[]);;
+
+let INSIDE_CONNECTED_COMPONENT_LE = prove
+ (`!s. 2 <= dimindex(:N) /\ bounded s
+       ==> inside s =
+            {x:real^N | ~(x IN s) /\
+                        !B. ?y. B <= norm(y) /\
+                                ~(connected_component((:real^N) DIFF s) x y)}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[INSIDE_OUTSIDE] THEN
+  REWRITE_TAC[SET_RULE `UNIV DIFF (s UNION t) = (UNIV DIFF t) DIFF s`] THEN
+  ASM_SIMP_TAC[NOT_OUTSIDE_CONNECTED_COMPONENT_LE] THEN SET_TAC[]);;
+
+let OUTSIDE_UNION_OUTSIDE_UNION = prove
+ (`!c c1 c2:real^N->bool.
+        c INTER outside(c1 UNION c2) = {}
+        ==> outside(c1 UNION c2) SUBSET outside(c1 UNION c)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[SUBSET] THEN
+  X_GEN_TAC `x:real^N` THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  REWRITE_TAC[OUTSIDE_CONNECTED_COMPONENT_LT; IN_ELIM_THM] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `B:real` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `y:real^N` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_REWRITE_TAC[connected_component] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real^N->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `t SUBSET outside(c1 UNION c2:real^N->bool)`
+  MP_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `connected_component((:real^N) DIFF (c1 UNION c2)) x` THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[CONNECTED_COMPONENT_MAXIMAL]; ALL_TAC] THEN
+  UNDISCH_TAC `(x:real^N) IN outside(c1 UNION c2)` THEN
+  REWRITE_TAC[OUTSIDE; IN_ELIM_THM; SUBSET] THEN
+  MESON_TAC[CONNECTED_COMPONENT_EQ]);;
+
+let INSIDE_SUBSET = prove
+ (`!s t u. connected u /\ ~bounded u /\ t UNION u = (:real^N) DIFF s
+           ==> inside s SUBSET t`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[SUBSET; inside; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
+  MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+  UNDISCH_TAC `~bounded(u:real^N->bool)` THEN REWRITE_TAC[] THEN
+  MATCH_MP_TAC BOUNDED_SUBSET THEN
+  EXISTS_TAC `connected_component((:real^N) DIFF s) x` THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+  ASM_REWRITE_TAC[] THEN ASM SET_TAC[]);;
+
+let INSIDE_UNIQUE = prove
+ (`!s t u. connected t /\ bounded t /\
+           connected u /\ ~(bounded u) /\
+           ~connected((:real^N) DIFF s) /\
+           t UNION u = (:real^N) DIFF s
+           ==> inside s = t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[INSIDE_SUBSET]; ALL_TAC] THEN
+  REWRITE_TAC[SUBSET; inside; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC BOUNDED_SUBSET THEN EXISTS_TAC `t:real^N->bool` THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(SET_RULE
+   `!s u. c INTER s = {} /\ c INTER u = {} /\ t UNION u = UNIV DIFF s
+          ==> c SUBSET t`) THEN
+  MAP_EVERY EXISTS_TAC [`s:real^N->bool`; `u:real^N->bool`] THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [REWRITE_TAC[SET_RULE `c INTER s = {} <=> c SUBSET (UNIV DIFF s)`] THEN
+    REWRITE_TAC[CONNECTED_COMPONENT_SUBSET];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(SET_RULE `(!x. x IN s /\ x IN t ==> F) ==> s INTER t = {}`) THEN
+  X_GEN_TAC `y:real^N` THEN
+  GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [IN] THEN STRIP_TAC THEN
+  UNDISCH_TAC `~connected((:real^N) DIFF s)` THEN
+  REWRITE_TAC[CONNECTED_IFF_CONNECTED_COMPONENT] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN
+  SUBGOAL_THEN
+   `(!w. w IN t ==> connected_component ((:real^N) DIFF s) x w) /\
+    (!w. w IN u ==> connected_component ((:real^N) DIFF s) y w)`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN GEN_TAC THEN DISCH_TAC THEN
+    REWRITE_TAC[connected_component] THENL
+     [EXISTS_TAC `t:real^N->bool`; EXISTS_TAC `u:real^N->bool`] THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    FIRST_ASSUM(SUBST1_TAC o SYM) THEN REWRITE_TAC[IN_UNION] THEN
+    ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[CONNECTED_COMPONENT_TRANS; CONNECTED_COMPONENT_SYM]]);;
+
+let INSIDE_OUTSIDE_UNIQUE = prove
+ (`!s t u. connected t /\ bounded t /\
+           connected u /\ ~(bounded u) /\
+           ~connected((:real^N) DIFF s) /\
+           t UNION u = (:real^N) DIFF s
+           ==> inside s = t /\ outside s = u`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN REWRITE_TAC[OUTSIDE_INSIDE] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[INSIDE_UNIQUE];
+    MP_TAC(ISPEC `(:real^N) DIFF s` INSIDE_NO_OVERLAP) THEN
+    SUBGOAL_THEN `t INTER u:real^N->bool = {}` MP_TAC THENL
+     [ALL_TAC; ASM SET_TAC[]] THEN
+    UNDISCH_TAC `~connected ((:real^N) DIFF s)` THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN DISCH_TAC THEN
+    REWRITE_TAC[] THEN MATCH_MP_TAC CONNECTED_UNION THEN
+    ASM_REWRITE_TAC[]]);;
+
+let INTERIOR_INSIDE_FRONTIER = prove
+ (`!s:real^N->bool. bounded s ==> interior s SUBSET inside(frontier s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[inside; SUBSET; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [ASM_REWRITE_TAC[frontier; IN_DIFF]; DISCH_TAC] THEN
+  MATCH_MP_TAC BOUNDED_SUBSET THEN EXISTS_TAC `s:real^N->bool` THEN
+  ASM_REWRITE_TAC[SUBSET] THEN X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+  MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+  SUBGOAL_THEN `~(connected_component((:real^N) DIFF frontier s) x INTER
+                  frontier s = {})`
+  MP_TAC THENL
+   [MATCH_MP_TAC CONNECTED_INTER_FRONTIER THEN
+    REWRITE_TAC[CONNECTED_CONNECTED_COMPONENT; GSYM MEMBER_NOT_EMPTY] THEN
+    CONJ_TAC THENL [REWRITE_TAC[IN_INTER]; ASM SET_TAC[]] THEN
+    EXISTS_TAC `x:real^N` THEN CONJ_TAC THENL
+     [REWRITE_TAC[IN; CONNECTED_COMPONENT_REFL_EQ] THEN
+      GEN_REWRITE_TAC I [GSYM IN] THEN ASM SET_TAC[];
+      ASM_MESON_TAC[INTERIOR_SUBSET; SUBSET]];
+    REWRITE_TAC[SET_RULE `s INTER t = {} <=> s SUBSET (UNIV DIFF t)`] THEN
+    REWRITE_TAC[CONNECTED_COMPONENT_SUBSET]]);;
+
+let INSIDE_EMPTY = prove
+ (`inside {} = {}`,
+  REWRITE_TAC[inside; NOT_IN_EMPTY; DIFF_EMPTY; CONNECTED_COMPONENT_UNIV] THEN
+  REWRITE_TAC[NOT_BOUNDED_UNIV; EMPTY_GSPEC]);;
+
+let OUTSIDE_EMPTY = prove
+ (`outside {} = (:real^N)`,
+  REWRITE_TAC[OUTSIDE_INSIDE; INSIDE_EMPTY] THEN SET_TAC[]);;
+
+let INSIDE_SAME_COMPONENT = prove
+ (`!s x y. connected_component((:real^N) DIFF s) x y /\ x IN inside s
+           ==> y IN inside s`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (ASSUME_TAC o GEN_REWRITE_RULE I [GSYM IN])
+        MP_TAC) THEN
+  REWRITE_TAC[inside; IN_ELIM_THM] THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP CONNECTED_COMPONENT_EQ) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN]) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP CONNECTED_COMPONENT_IN) THEN
+  SIMP_TAC[IN_DIFF]);;
+
+let OUTSIDE_SAME_COMPONENT = prove
+ (`!s x y. connected_component((:real^N) DIFF s) x y /\ x IN outside s
+           ==> y IN outside s`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (ASSUME_TAC o GEN_REWRITE_RULE I [GSYM IN])
+        MP_TAC) THEN
+  REWRITE_TAC[outside; IN_ELIM_THM] THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP CONNECTED_COMPONENT_EQ) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN]) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP CONNECTED_COMPONENT_IN) THEN
+  SIMP_TAC[IN_DIFF]);;
+
+let OUTSIDE_CONVEX = prove
+ (`!s. convex s ==> outside s = (:real^N) DIFF s`,
+  REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ;
+              REWRITE_RULE[SET_RULE `t INTER s = {} <=> t SUBSET UNIV DIFF s`]
+                          OUTSIDE_NO_OVERLAP] THEN
+  REWRITE_TAC[SUBSET; IN_UNIV; IN_DIFF] THEN
+  MATCH_MP_TAC SET_PROVE_CASES THEN REWRITE_TAC[OUTSIDE_EMPTY; IN_UNIV] THEN
+  X_GEN_TAC `a:real^N` THEN GEOM_ORIGIN_TAC `a:real^N` THEN
+  X_GEN_TAC `t:real^N->bool` THEN DISCH_THEN(K ALL_TAC) THEN
+  MP_TAC(SET_RULE `(vec 0:real^N) IN (vec 0 INSERT t)`) THEN
+  SPEC_TAC(`(vec 0:real^N) INSERT t`,`s:real^N->bool`) THEN
+  GEN_TAC THEN DISCH_TAC THEN DISCH_TAC THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  ASM_REWRITE_TAC[outside; IN_ELIM_THM] THEN
+  SUBGOAL_THEN `~(x:real^N = vec 0)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[BOUNDED_POS; NOT_EXISTS_THM] THEN X_GEN_TAC `B:real` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(MP_TAC o SPEC `(max (&2) ((B + &1) / norm(x))) % x:real^N`) THEN
+  REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THENL
+   [REWRITE_TAC[IN] THEN REWRITE_TAC[connected_component] THEN
+    EXISTS_TAC `segment[x:real^N,(max (&2) ((B + &1) / norm(x))) % x]` THEN
+    REWRITE_TAC[ENDS_IN_SEGMENT; CONNECTED_SEGMENT] THEN
+    REWRITE_TAC[segment; SUBSET; FORALL_IN_GSPEC] THEN X_GEN_TAC `u:real` THEN
+    ASM_CASES_TAC `u = &0` THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_MUL_LID; REAL_SUB_RZERO;
+                    VECTOR_ADD_RID; IN_DIFF; IN_UNIV] THEN
+    DISCH_TAC THEN
+    REWRITE_TAC[VECTOR_ARITH `a % x + b % c % x:real^N = (a + b * c) % x`] THEN
+    ABBREV_TAC `c = &1 - u + u * max (&2) ((B + &1) / norm(x:real^N))` THEN
+    DISCH_TAC THEN SUBGOAL_THEN `&1 < c` ASSUME_TAC THENL
+     [EXPAND_TAC "c" THEN
+      REWRITE_TAC[REAL_ARITH `&1 < &1 - u + u * x <=> &0 < u * (x - &1)`] THEN
+      MATCH_MP_TAC REAL_LT_MUL THEN ASM_REAL_ARITH_TAC;
+      UNDISCH_TAC `~((x:real^N) IN s)` THEN REWRITE_TAC[] THEN
+      SUBGOAL_THEN `x:real^N = (&1 - inv c) % vec 0 + inv c % c % x`
+      SUBST1_TAC THENL
+       [REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID; VECTOR_MUL_ASSOC] THEN
+        ASM_SIMP_TAC[REAL_MUL_LINV; REAL_ARITH `&1 < x ==> ~(x = &0)`] THEN
+        REWRITE_TAC[VECTOR_MUL_LID];
+        MATCH_MP_TAC IN_CONVEX_SET THEN
+        ASM_SIMP_TAC[REAL_LE_INV_EQ; REAL_INV_LE_1; REAL_LT_IMP_LE] THEN
+        ASM_REAL_ARITH_TAC]];
+    ASM_SIMP_TAC[NORM_MUL; REAL_NOT_LE; GSYM REAL_LT_LDIV_EQ; NORM_POS_LT] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < b /\ b < c ==> b < abs(max (&2) c)`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; REAL_LT_DIV2_EQ] THEN
+    REAL_ARITH_TAC]);;
+
+let INSIDE_CONVEX = prove
+ (`!s. convex s ==> inside s = {}`,
+  SIMP_TAC[INSIDE_OUTSIDE; OUTSIDE_CONVEX] THEN SET_TAC[]);;
+
+let OUTSIDE_SUBSET_CONVEX = prove
+ (`!s t. convex t /\ s SUBSET t ==> (:real^N) DIFF t SUBSET outside s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `outside(t:real^N->bool)` THEN
+  ASM_SIMP_TAC[OUTSIDE_MONO] THEN
+  ASM_SIMP_TAC[OUTSIDE_CONVEX; SUBSET_REFL]);;
+
+let OUTSIDE_FRONTIER_MISSES_CLOSURE = prove
+ (`!s. bounded s ==> outside(frontier s) SUBSET (:real^N) DIFF closure s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[OUTSIDE_INSIDE] THEN
+  SIMP_TAC[SET_RULE `(UNIV DIFF s) SUBSET (UNIV DIFF t) <=> t SUBSET s`] THEN
+  REWRITE_TAC[frontier] THEN
+  MATCH_MP_TAC(SET_RULE
+   `i SUBSET ins ==> c SUBSET (c DIFF i) UNION ins`) THEN
+  ASM_SIMP_TAC[GSYM frontier; INTERIOR_INSIDE_FRONTIER]);;
+
+let OUTSIDE_FRONTIER_EQ_COMPLEMENT_CLOSURE = prove
+ (`!s. bounded s /\ convex s
+       ==> outside(frontier s) = (:real^N) DIFF closure s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  ASM_SIMP_TAC[OUTSIDE_FRONTIER_MISSES_CLOSURE] THEN
+  MATCH_MP_TAC OUTSIDE_SUBSET_CONVEX THEN
+  ASM_SIMP_TAC[CONVEX_CLOSURE; frontier] THEN SET_TAC[]);;
+
+let INSIDE_FRONTIER_EQ_INTERIOR = prove
+ (`!s:real^N->bool.
+        bounded s /\ convex s ==> inside(frontier s) = interior s`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[INSIDE_OUTSIDE; OUTSIDE_FRONTIER_EQ_COMPLEMENT_CLOSURE] THEN
+  REWRITE_TAC[frontier] THEN
+  MAP_EVERY (MP_TAC o ISPEC `s:real^N->bool`)
+   [CLOSURE_SUBSET; INTERIOR_SUBSET] THEN
+  ASM SET_TAC[]);;
+
+let OPEN_INSIDE = prove
+ (`!s:real^N->bool. closed s ==> open(inside s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[OPEN_CONTAINS_BALL] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `open(connected_component ((:real^N) DIFF s) x)` MP_TAC THENL
+   [MATCH_MP_TAC OPEN_CONNECTED_COMPONENT THEN ASM_REWRITE_TAC[GSYM closed];
+    REWRITE_TAC[open_def] THEN DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[IN; CONNECTED_COMPONENT_REFL_EQ] THEN
+      GEN_REWRITE_TAC I [GSYM IN] THEN
+      ASM_REWRITE_TAC[IN_DIFF; IN_UNIV] THEN
+      MP_TAC(ISPEC `s:real^N->bool` INSIDE_NO_OVERLAP) THEN
+      ASM SET_TAC[];
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[SUBSET; IN_BALL] THEN
+      X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+      MATCH_MP_TAC INSIDE_SAME_COMPONENT THEN
+      EXISTS_TAC `x:real^N` THEN ASM_REWRITE_TAC[] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN]) THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[DIST_SYM]]]);;
+
+let OPEN_OUTSIDE = prove
+ (`!s:real^N->bool. closed s ==> open(outside s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[OPEN_CONTAINS_BALL] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `open(connected_component ((:real^N) DIFF s) x)` MP_TAC THENL
+   [MATCH_MP_TAC OPEN_CONNECTED_COMPONENT THEN ASM_REWRITE_TAC[GSYM closed];
+    REWRITE_TAC[open_def] THEN DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[IN; CONNECTED_COMPONENT_REFL_EQ] THEN
+      GEN_REWRITE_TAC I [GSYM IN] THEN
+      ASM_REWRITE_TAC[IN_DIFF; IN_UNIV] THEN
+      MP_TAC(ISPEC `s:real^N->bool` OUTSIDE_NO_OVERLAP) THEN
+      ASM SET_TAC[];
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[SUBSET; IN_BALL] THEN
+      X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+      MATCH_MP_TAC OUTSIDE_SAME_COMPONENT THEN
+      EXISTS_TAC `x:real^N` THEN ASM_REWRITE_TAC[] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN]) THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[DIST_SYM]]]);;
+
+let CLOSURE_INSIDE_SUBSET = prove
+ (`!s:real^N->bool. closed s ==> closure(inside s) SUBSET s UNION inside s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSURE_MINIMAL THEN
+  ASM_SIMP_TAC[closed; GSYM OUTSIDE_INSIDE; OPEN_OUTSIDE] THEN SET_TAC[]);;
+
+let FRONTIER_INSIDE_SUBSET = prove
+ (`!s:real^N->bool. closed s ==> frontier(inside s) SUBSET s`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[frontier; OPEN_INSIDE; INTERIOR_OPEN] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP CLOSURE_INSIDE_SUBSET) THEN SET_TAC[]);;
+
+let CLOSURE_OUTSIDE_SUBSET = prove
+ (`!s:real^N->bool. closed s ==> closure(outside s) SUBSET s UNION outside s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSURE_MINIMAL THEN
+  ASM_SIMP_TAC[closed; GSYM INSIDE_OUTSIDE; OPEN_INSIDE] THEN SET_TAC[]);;
+
+let FRONTIER_OUTSIDE_SUBSET = prove
+ (`!s:real^N->bool. closed s ==> frontier(outside s) SUBSET s`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[frontier; OPEN_OUTSIDE; INTERIOR_OPEN] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP CLOSURE_OUTSIDE_SUBSET) THEN SET_TAC[]);;
+
+let INSIDE_COMPLEMENT_UNBOUNDED_CONNECTED_EMPTY = prove
+ (`!s. connected((:real^N) DIFF s) /\ ~bounded((:real^N) DIFF s)
+       ==> inside s = {}`,
+  REWRITE_TAC[inside; CONNECTED_CONNECTED_COMPONENT_SET] THEN
+  REWRITE_TAC[SET_RULE `s = {} <=> !x. x IN s ==> F`] THEN
+  SIMP_TAC[IN_ELIM_THM; IN_DIFF; IN_UNIV; TAUT `~(a /\ b) <=> a ==> ~b`]);;
+
+let INSIDE_BOUNDED_COMPLEMENT_CONNECTED_EMPTY = prove
+ (`!s. connected((:real^N) DIFF s) /\ bounded s
+       ==> inside s = {}`,
+  MESON_TAC[INSIDE_COMPLEMENT_UNBOUNDED_CONNECTED_EMPTY;
+            COBOUNDED_IMP_UNBOUNDED]);;
+
+let INSIDE_INSIDE = prove
+ (`!s t:real^N->bool.
+        s SUBSET inside t ==> inside s DIFF t SUBSET inside t`,
+  REPEAT STRIP_TAC THEN SIMP_TAC[SUBSET; inside; IN_DIFF; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
+  ASM_CASES_TAC `s INTER connected_component ((:real^N) DIFF t) x = {}` THENL
+   [MATCH_MP_TAC BOUNDED_SUBSET THEN
+    EXISTS_TAC `connected_component ((:real^N) DIFF s) x` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+    REWRITE_TAC[CONNECTED_CONNECTED_COMPONENT; IN] THEN
+    REWRITE_TAC[CONNECTED_COMPONENT_REFL_EQ] THEN ASM SET_TAC[];
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+     `~(s INTER t = {}) ==> ?x. x IN s /\ x IN t`)) THEN
+    DISCH_THEN(X_CHOOSE_THEN `y:real^N`
+     (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(SUBST_ALL_TAC o SYM o MATCH_MP CONNECTED_COMPONENT_EQ) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    DISCH_THEN(MP_TAC o SPEC `y:real^N`) THEN
+    ASM_SIMP_TAC[inside; IN_ELIM_THM]]);;
+
+let INSIDE_INSIDE_SUBSET = prove
+ (`!s:real^N->bool. inside(inside s) SUBSET s`,
+  GEN_TAC THEN MP_TAC
+   (ISPECL [`inside s:real^N->bool`; `s:real^N->bool`] INSIDE_INSIDE) THEN
+  REWRITE_TAC[SUBSET_REFL] THEN
+  MP_TAC(ISPEC `inside s:real^N->bool` INSIDE_NO_OVERLAP) THEN SET_TAC[]);;
+
+let INSIDE_OUTSIDE_INTERSECT_CONNECTED = prove
+ (`!s t:real^N->bool.
+        connected t /\ ~(inside s INTER t = {}) /\ ~(outside s INTER t = {})
+        ==> ~(s INTER t = {})`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+  REWRITE_TAC[inside; outside; IN_ELIM_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `x:real^N` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC)) THEN
+  SUBGOAL_THEN
+   `connected_component ((:real^N) DIFF s) y =
+    connected_component ((:real^N) DIFF s) x`
+   (fun th -> ASM_MESON_TAC[th]) THEN
+  ASM_REWRITE_TAC[CONNECTED_COMPONENT_EQ_EQ; IN_DIFF; IN_UNIV] THEN
+  REWRITE_TAC[connected_component] THEN
+  EXISTS_TAC `t:real^N->bool` THEN ASM SET_TAC[]);;
+
+let OUTSIDE_BOUNDED_NONEMPTY = prove
+ (`!s:real^N->bool. bounded s ==> ~(outside s = {})`,
+  GEN_TAC THEN
+  DISCH_THEN(MP_TAC o SPEC `vec 0:real^N` o MATCH_MP BOUNDED_SUBSET_BALL) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ_ALT] OUTSIDE_SUBSET_CONVEX)) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  SIMP_TAC[CONVEX_BALL; SUBSET_EMPTY] THEN
+  REWRITE_TAC[SET_RULE `s DIFF t = {} <=> s SUBSET t`] THEN
+  MESON_TAC[BOUNDED_BALL; BOUNDED_SUBSET; NOT_BOUNDED_UNIV]);;
+
+let OUTSIDE_COMPACT_IN_OPEN = prove
+ (`!s t:real^N->bool.
+        compact s /\ open t /\ s SUBSET t /\ ~(t = {})
+        ==> ~(outside s INTER t = {})`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP OUTSIDE_BOUNDED_NONEMPTY o
+        MATCH_MP COMPACT_IMP_BOUNDED) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; LEFT_IMP_EXISTS_THM; IN_INTER] THEN
+  X_GEN_TAC `b:real^N` THEN DISCH_TAC THEN
+  X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `(a:real^N) IN t` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`linepath(a:real^N,b)`; `(:real^N) DIFF t`]
+        EXISTS_PATH_SUBPATH_TO_FRONTIER) THEN
+  REWRITE_TAC[PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `g:real^1->real^N` THEN REWRITE_TAC[FRONTIER_COMPLEMENT] THEN
+  REWRITE_TAC[PATH_IMAGE_LINEPATH; INTERIOR_DIFF; INTERIOR_UNIV] THEN
+  ABBREV_TAC `c:real^N = pathfinish g` THEN STRIP_TAC THEN
+  SUBGOAL_THEN `frontier t SUBSET (:real^N) DIFF s` MP_TAC THENL
+   [ONCE_REWRITE_TAC[GSYM FRONTIER_COMPLEMENT] THEN
+    REWRITE_TAC[frontier] THEN
+    ASM_SIMP_TAC[CLOSURE_CLOSED; GSYM OPEN_CLOSED] THEN ASM SET_TAC[];
+    REWRITE_TAC[SUBSET; IN_DIFF; IN_UNIV]] THEN
+  DISCH_THEN(MP_TAC o SPEC `c:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_TAC THEN MP_TAC(ISPEC `(:real^N) DIFF s` OPEN_CONTAINS_CBALL) THEN
+  ASM_SIMP_TAC[GSYM closed; COMPACT_IMP_CLOSED; IN_DIFF; IN_UNIV] THEN
+  DISCH_THEN(MP_TAC o SPEC `c:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`c:real^N`; `t:real^N->bool`]
+        CLOSURE_APPROACHABLE) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[frontier; IN_DIFF]) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real^N` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC OUTSIDE_SAME_COMPONENT THEN
+  EXISTS_TAC `a:real^N` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[connected_component] THEN
+  EXISTS_TAC `path_image(g) UNION segment[c:real^N,d]` THEN
+  REWRITE_TAC[IN_UNION; ENDS_IN_SEGMENT] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONNECTED_UNION THEN
+    ASM_SIMP_TAC[CONNECTED_SEGMENT; GSYM MEMBER_NOT_EMPTY;
+                 CONNECTED_PATH_IMAGE] THEN
+    EXISTS_TAC `c:real^N` THEN REWRITE_TAC[ENDS_IN_SEGMENT; IN_INTER] THEN
+    ASM_MESON_TAC[PATHFINISH_IN_PATH_IMAGE; SUBSET];
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE]] THEN
+    REWRITE_TAC[UNION_SUBSET] THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `~(c IN s)
+        ==> (t DELETE c) SUBSET (UNIV DIFF s)
+            ==> t SUBSET (UNIV DIFF s)`)) THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        SUBSET_TRANS)) THEN
+      SIMP_TAC[SET_RULE `UNIV DIFF s SUBSET UNIV DIFF t <=> t SUBSET s`] THEN
+      ASM_MESON_TAC[SUBSET_TRANS; CLOSURE_SUBSET];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+        SUBSET_TRANS)) THEN
+     REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+      ASM_SIMP_TAC[CONVEX_CBALL; INSERT_SUBSET; REAL_LT_IMP_LE;
+                   EMPTY_SUBSET; CENTRE_IN_CBALL] THEN
+      REWRITE_TAC[IN_CBALL] THEN
+      ASM_MESON_TAC[DIST_SYM; REAL_LT_IMP_LE]]]);;
+
+let INSIDE_INSIDE_COMPACT_CONNECTED = prove
+ (`!s t:real^N->bool.
+        closed s /\ compact t /\ s SUBSET inside t /\ connected t
+        ==> inside s SUBSET inside t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `inside t:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[INSIDE_EMPTY; SUBSET_EMPTY; EMPTY_SUBSET] THEN
+  SUBGOAL_THEN `1 <= dimindex(:N)` MP_TAC THENL
+   [REWRITE_TAC[DIMINDEX_GE_1];
+    REWRITE_TAC[ARITH_RULE `1 <= n <=> n = 1 \/ 2 <= n`]] THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[GSYM CONNECTED_CONVEX_1_GEN] THENL
+   [ASM_MESON_TAC[INSIDE_CONVEX]; ALL_TAC] THEN
+  STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP INSIDE_INSIDE) THEN
+  MATCH_MP_TAC(SET_RULE
+   `s INTER t = {} ==> s DIFF t SUBSET u ==> s SUBSET u`) THEN
+  SUBGOAL_THEN `compact(s:real^N->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[COMPACT_EQ_BOUNDED_CLOSED; BOUNDED_SUBSET; BOUNDED_INSIDE];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `t:real^N->bool`]
+        INSIDE_OUTSIDE_INTERSECT_CONNECTED) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(TAUT
+   `r /\ q ==> (~p /\ q ==> ~r) ==> p`) THEN
+  CONJ_TAC THENL
+   [MP_TAC(ISPEC `t:real^N->bool` INSIDE_NO_OVERLAP) THEN ASM SET_TAC[];
+    ONCE_REWRITE_TAC[INTER_COMM]] THEN
+  MATCH_MP_TAC INSIDE_OUTSIDE_INTERSECT_CONNECTED THEN
+  ASM_SIMP_TAC[CONNECTED_OUTSIDE; COMPACT_IMP_BOUNDED] THEN CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[INTER_COMM] THEN MATCH_MP_TAC OUTSIDE_COMPACT_IN_OPEN THEN
+    ASM_SIMP_TAC[OPEN_INSIDE; COMPACT_IMP_CLOSED];
+    MP_TAC(ISPECL [`s UNION t:real^N->bool`; `vec 0:real^N`]
+        BOUNDED_SUBSET_BALL) THEN
+    ASM_SIMP_TAC[BOUNDED_UNION; COMPACT_IMP_BOUNDED] THEN
+    DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+    MATCH_MP_TAC(SET_RULE
+     `!u. ~(u = UNIV) /\ UNIV DIFF u SUBSET s /\ UNIV DIFF u SUBSET t
+          ==> ~(s INTER t = {})`) THEN
+    EXISTS_TAC `ball(vec 0:real^N,r)` THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[NOT_BOUNDED_UNIV; BOUNDED_BALL]; ALL_TAC] THEN
+    CONJ_TAC THEN MATCH_MP_TAC OUTSIDE_SUBSET_CONVEX THEN
+    REWRITE_TAC[CONVEX_BALL] THEN ASM SET_TAC[]]);;
+
+let CONNECTED_WITH_INSIDE = prove
+ (`!s:real^N->bool. closed s /\ connected s ==> connected(s UNION inside s)`,
+  GEN_TAC THEN ASM_CASES_TAC `s UNION inside s = (:real^N)` THEN
+  ASM_REWRITE_TAC[CONNECTED_UNIV] THEN
+  REWRITE_TAC[CONNECTED_IFF_CONNECTED_COMPONENT] THEN
+  REWRITE_TAC[CONNECTED_COMPONENT_SET; IN_ELIM_THM] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x. x IN (s UNION inside s)
+        ==> ?y:real^N t. y IN s /\ connected t /\ x IN t /\ y IN t /\
+                         t SUBSET (s UNION inside s)`
+  MP_TAC THENL
+   [X_GEN_TAC `a:real^N` THEN REWRITE_TAC[IN_UNION] THEN STRIP_TAC THENL
+     [MAP_EVERY EXISTS_TAC [`a:real^N`; `{a:real^N}`] THEN
+      ASM_REWRITE_TAC[IN_SING; CONNECTED_SING] THEN ASM SET_TAC[];
+      FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+       `~(s UNION t = UNIV) ==> ?b. ~(b IN s) /\ ~(b IN t)`)) THEN
+      DISCH_THEN(X_CHOOSE_THEN `b:real^N` STRIP_ASSUME_TAC) THEN
+      MP_TAC(ISPECL [`linepath(a:real^N,b)`; `inside s:real^N->bool`]
+        EXISTS_PATH_SUBPATH_TO_FRONTIER) THEN
+      ASM_SIMP_TAC[PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+                   IN_UNION; OPEN_INSIDE; INTERIOR_OPEN] THEN
+      DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^N` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `pathfinish g :real^N` THEN
+      EXISTS_TAC `path_image g :real^N->bool` THEN
+      ASM_SIMP_TAC[PATHFINISH_IN_PATH_IMAGE; CONNECTED_PATH_IMAGE] THEN
+      MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN
+      REPEAT STRIP_TAC THENL
+       [ASM_MESON_TAC[FRONTIER_INSIDE_SUBSET; SUBSET];
+        ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE];
+        ASM SET_TAC[]]];
+    DISCH_THEN(fun th ->
+      MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+      MP_TAC(SPEC `y:real^N` th) THEN MP_TAC(SPEC `x:real^N` th)) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `t:real^N->bool`] THEN STRIP_TAC THEN
+    MAP_EVERY X_GEN_TAC [`b:real^N`; `u:real^N->bool`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`a:real^N`; `b:real^N`]) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `v:real^N->bool` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `t UNION v UNION u:real^N->bool` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    REPEAT(MATCH_MP_TAC CONNECTED_UNION THEN
+           ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC) THEN
+    ASM SET_TAC[]]);;
+
+let CONNECTED_WITH_OUTSIDE = prove
+ (`!s:real^N->bool. closed s /\ connected s ==> connected(s UNION outside s)`,
+  GEN_TAC THEN ASM_CASES_TAC `s UNION outside s = (:real^N)` THEN
+  ASM_REWRITE_TAC[CONNECTED_UNIV] THEN
+  REWRITE_TAC[CONNECTED_IFF_CONNECTED_COMPONENT] THEN
+  REWRITE_TAC[CONNECTED_COMPONENT_SET; IN_ELIM_THM] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x. x IN (s UNION outside s)
+        ==> ?y:real^N t. y IN s /\ connected t /\ x IN t /\ y IN t /\
+                         t SUBSET (s UNION outside s)`
+  MP_TAC THENL
+   [X_GEN_TAC `a:real^N` THEN REWRITE_TAC[IN_UNION] THEN STRIP_TAC THENL
+     [MAP_EVERY EXISTS_TAC [`a:real^N`; `{a:real^N}`] THEN
+      ASM_REWRITE_TAC[IN_SING; CONNECTED_SING] THEN ASM SET_TAC[];
+      FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+       `~(s UNION t = UNIV) ==> ?b. ~(b IN s) /\ ~(b IN t)`)) THEN
+      DISCH_THEN(X_CHOOSE_THEN `b:real^N` STRIP_ASSUME_TAC) THEN
+      MP_TAC(ISPECL [`linepath(a:real^N,b)`; `outside s:real^N->bool`]
+        EXISTS_PATH_SUBPATH_TO_FRONTIER) THEN
+      ASM_SIMP_TAC[PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+                   IN_UNION; OPEN_OUTSIDE; INTERIOR_OPEN] THEN
+      DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^N` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `pathfinish g :real^N` THEN
+      EXISTS_TAC `path_image g :real^N->bool` THEN
+      ASM_SIMP_TAC[PATHFINISH_IN_PATH_IMAGE; CONNECTED_PATH_IMAGE] THEN
+      MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN
+      REPEAT STRIP_TAC THENL
+       [ASM_MESON_TAC[FRONTIER_OUTSIDE_SUBSET; SUBSET];
+        ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE];
+        ASM SET_TAC[]]];
+    DISCH_THEN(fun th ->
+      MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+      MP_TAC(SPEC `y:real^N` th) THEN MP_TAC(SPEC `x:real^N` th)) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `t:real^N->bool`] THEN STRIP_TAC THEN
+    MAP_EVERY X_GEN_TAC [`b:real^N`; `u:real^N->bool`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`a:real^N`; `b:real^N`]) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `v:real^N->bool` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `t UNION v UNION u:real^N->bool` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    REPEAT(MATCH_MP_TAC CONNECTED_UNION THEN
+           ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC) THEN
+    ASM SET_TAC[]]);;
+
+let INSIDE_INSIDE_EQ_EMPTY = prove
+ (`!s:real^N->bool.
+        closed s /\ connected s ==> inside(inside s) = {}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[EXTENSION; NOT_IN_EMPTY] THEN
+  X_GEN_TAC `x:real^N` THEN ONCE_REWRITE_TAC[inside] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  ONCE_REWRITE_TAC[INSIDE_OUTSIDE] THEN
+  REWRITE_TAC[SET_RULE `UNIV DIFF (UNIV DIFF s) = s`] THEN
+  REWRITE_TAC[IN_DIFF; IN_UNIV] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_SIMP_TAC[CONNECTED_COMPONENT_EQ_SELF; CONNECTED_WITH_OUTSIDE] THEN
+  REWRITE_TAC[BOUNDED_UNION] THEN MESON_TAC[UNBOUNDED_OUTSIDE]);;
+
+let INSIDE_IN_COMPONENTS = prove
+ (`!s. (inside s) IN components((:real^N) DIFF s) <=>
+       connected(inside s) /\ ~(inside s = {})`,
+  X_GEN_TAC `s:real^N->bool` THEN REWRITE_TAC[IN_COMPONENTS_MAXIMAL] THEN
+  ASM_CASES_TAC `inside s:real^N->bool = {}` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `connected(inside s:real^N->bool)` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[SET_RULE `s SUBSET UNIV DIFF t <=> s INTER t = {}`] THEN
+  REWRITE_TAC[INSIDE_NO_OVERLAP] THEN
+  X_GEN_TAC `d:real^N->bool` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+  REWRITE_TAC[SUBSET] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  MATCH_MP_TAC INSIDE_SAME_COMPONENT THEN
+  UNDISCH_TAC `~(inside s:real^N->bool = {})` THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+  ASM_REWRITE_TAC[connected_component] THEN
+  EXISTS_TAC `d:real^N->bool` THEN ASM SET_TAC[]);;
+
+let OUTSIDE_IN_COMPONENTS = prove
+ (`!s. (outside s) IN components((:real^N) DIFF s) <=>
+       connected(outside s) /\ ~(outside s = {})`,
+  X_GEN_TAC `s:real^N->bool` THEN REWRITE_TAC[IN_COMPONENTS_MAXIMAL] THEN
+  ASM_CASES_TAC `outside s:real^N->bool = {}` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `connected(outside s:real^N->bool)` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[SET_RULE `s SUBSET UNIV DIFF t <=> s INTER t = {}`] THEN
+  REWRITE_TAC[OUTSIDE_NO_OVERLAP] THEN
+  X_GEN_TAC `d:real^N->bool` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+  REWRITE_TAC[SUBSET] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  MATCH_MP_TAC OUTSIDE_SAME_COMPONENT THEN
+  UNDISCH_TAC `~(outside s:real^N->bool = {})` THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+  ASM_REWRITE_TAC[connected_component] THEN
+  EXISTS_TAC `d:real^N->bool` THEN ASM SET_TAC[]);;
+
+let BOUNDED_UNIQUE_OUTSIDE = prove
+ (`!c s. 2 <= dimindex(:N) /\ bounded s
+         ==> (c IN components ((:real^N) DIFF s) /\ ~bounded c <=>
+              c = outside s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN STRIP_TAC THENL
+   [MATCH_MP_TAC COBOUNDED_UNIQUE_UNBOUNDED_COMPONENTS THEN
+    EXISTS_TAC `(:real^N) DIFF s` THEN
+    ASM_REWRITE_TAC[SET_RULE `UNIV DIFF (UNIV DIFF s) = s`] THEN
+    ASM_REWRITE_TAC[OUTSIDE_IN_COMPONENTS];
+    ASM_REWRITE_TAC[OUTSIDE_IN_COMPONENTS]] THEN
+  ASM_SIMP_TAC[UNBOUNDED_OUTSIDE; OUTSIDE_BOUNDED_NONEMPTY;
+               CONNECTED_OUTSIDE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homotopy of maps p,q : X->Y with property P of all intermediate maps.     *)
+(* We often just want to require that it fixes some subset, but to take in   *)
+(* the case of loop homotopy it's convenient to have a general property P.   *)
+(* ------------------------------------------------------------------------- *)
+
+let homotopic_with = new_definition
+ `homotopic_with P (X,Y) p q <=>
+   ?h:real^(1,M)finite_sum->real^N.
+     h continuous_on (interval[vec 0,vec 1] PCROSS X) /\
+     IMAGE h (interval[vec 0,vec 1] PCROSS X) SUBSET Y /\
+     (!x. h(pastecart (vec 0) x) = p x) /\
+     (!x. h(pastecart (vec 1) x) = q x) /\
+     (!t. t IN interval[vec 0,vec 1] ==> P(\x. h(pastecart t x)))`;;
+
+(* ------------------------------------------------------------------------- *)
+(* We often want to just localize the ending function equality or whatever.  *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPIC_WITH = prove
+ (`(!h k. (!x. x IN X ==> h x = k x) ==> (P h <=> P k))
+   ==> (homotopic_with P (X,Y) p q <=>
+        ?h:real^(1,M)finite_sum->real^N.
+          h continuous_on (interval[vec 0,vec 1] PCROSS X) /\
+          IMAGE h (interval[vec 0,vec 1] PCROSS X) SUBSET Y /\
+          (!x. x IN X ==> h(pastecart (vec 0) x) = p x) /\
+          (!x. x IN X ==> h(pastecart (vec 1) x) = q x) /\
+          (!t. t IN interval[vec 0,vec 1] ==> P(\x. h(pastecart t x))))`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[homotopic_with; PCROSS] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[];
+    REWRITE_TAC[homotopic_with; PCROSS] THEN
+     DISCH_THEN(X_CHOOSE_THEN `h:real^(1,M)finite_sum->real^N`
+      (fun th -> EXISTS_TAC
+        `\y. if sndcart(y) IN X then (h:real^(1,M)finite_sum->real^N) y
+             else if fstcart(y) = vec 0 then p(sndcart y)
+             else q(sndcart y)` THEN
+      MP_TAC th)) THEN
+     REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; VEC_EQ; ARITH_EQ] THEN
+     REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THENL
+      [MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_EQ) THEN
+       SIMP_TAC[FORALL_IN_GSPEC; SNDCART_PASTECART];
+       SIMP_TAC[FORALL_IN_IMAGE; FORALL_IN_GSPEC; SUBSET] THEN
+       SIMP_TAC[FORALL_IN_GSPEC; SNDCART_PASTECART];
+       ASM_MESON_TAC[];
+       ASM_MESON_TAC[];
+       MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `t:real^1` THEN
+       MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+       MATCH_MP_TAC EQ_IMP THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+       SIMP_TAC[]]]);;
+
+let HOMOTOPIC_WITH_EQ = prove
+ (`!P X Y f g f' g':real^M->real^N.
+        homotopic_with P (X,Y) f g /\
+        (!x. x IN X ==> f' x = f x /\ g' x = g x) /\
+        (!h k. (!x. x IN X ==> h x = k x) ==> (P h <=> P k))
+        ==>  homotopic_with P (X,Y) f' g'`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[homotopic_with] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^(1,M)finite_sum->real^N`
+   (fun th -> EXISTS_TAC
+     `\y. if sndcart(y) IN X then (h:real^(1,M)finite_sum->real^N) y
+          else if fstcart(y) = vec 0 then f'(sndcart y)
+          else g'(sndcart y)` THEN
+   MP_TAC th)) THEN
+  REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; VEC_EQ; ARITH_EQ] THEN
+  REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THENL
+   [MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_EQ) THEN
+    SIMP_TAC[FORALL_IN_PCROSS; SNDCART_PASTECART];
+    SIMP_TAC[FORALL_IN_IMAGE; FORALL_IN_PCROSS; SUBSET] THEN
+    SIMP_TAC[FORALL_IN_PCROSS; SNDCART_PASTECART];
+    ASM_MESON_TAC[];
+    ASM_MESON_TAC[];
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `t:real^1` THEN
+    MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC EQ_IMP THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    SIMP_TAC[]]);;
+
+let HOMOTOPIC_WITH_EQUAL = prove
+ (`!P f:real^M->real^N g s t.
+        P f /\ P g /\
+        f continuous_on s /\ IMAGE f s SUBSET t /\
+        (!x. x IN s ==> g x = f x)
+        ==> homotopic_with P (s,t) f g`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[homotopic_with] THEN
+  EXISTS_TAC `\z:real^(1,M)finite_sum.
+    if fstcart z = vec 1 then g(sndcart z):real^N else f(sndcart z)` THEN
+  REWRITE_TAC[VEC_EQ; ARITH_EQ; SNDCART_PASTECART; FSTCART_PASTECART] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_EQ THEN
+    EXISTS_TAC `\z:real^(1,M)finite_sum. (f:real^M->real^N)(sndcart z)` THEN
+    ASM_SIMP_TAC[FORALL_IN_PCROSS; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    REWRITE_TAC[COND_ID] THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART; IMAGE_SNDCART_PCROSS] THEN
+    ASM_REWRITE_TAC[UNIT_INTERVAL_NONEMPTY];
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+    REWRITE_TAC[ FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    CONJ_TAC THEN X_GEN_TAC `t:real^1` THEN REPEAT STRIP_TAC THEN
+    ASM_CASES_TAC `t:real^1 = vec 1` THEN ASM_REWRITE_TAC[ETA_AX] THEN
+    ASM SET_TAC[]]);;
+
+let HOMOTOPIC_CONSTANT_MAPS = prove
+ (`!s:real^M->bool t:real^N->bool a b.
+        homotopic_with (\x. T) (s,t) (\x. a) (\x. b) <=>
+        s = {} \/ path_component t a b`,
+  REPEAT GEN_TAC THEN SIMP_TAC[HOMOTOPIC_WITH; path_component] THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[NOT_IN_EMPTY; PCROSS_EMPTY; IMAGE_CLAUSES] THEN
+  REWRITE_TAC[EMPTY_SUBSET; CONTINUOUS_ON_EMPTY] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[PATH_IMAGE_NONEMPTY; SUBSET_EMPTY; PCROSS_EQ_EMPTY;
+                  IMAGE_EQ_EMPTY; UNIT_INTERVAL_NONEMPTY] THEN
+  EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `h:real^(1,M)finite_sum->real^N`
+        STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `?c:real^M. c IN s` STRIP_ASSUME_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    EXISTS_TAC `(h:real^(1,M)finite_sum->real^N) o (\t. pastecart t c)` THEN
+    ASM_SIMP_TAC[pathstart; pathfinish; o_THM; PATH_IMAGE_COMPOSE] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[path] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_ID;
+               CONTINUOUS_ON_CONST] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET));
+      REWRITE_TAC[path_image]] THEN
+    ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    ASM_SIMP_TAC[FORALL_IN_IMAGE; FORALL_IN_PCROSS];
+    REWRITE_TAC[path; pathstart; path_image; pathfinish] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC
+     `(g:real^1->real^N) o (fstcart:real^(1,M)finite_sum->real^1)` THEN
+    ASM_SIMP_TAC[FSTCART_PASTECART; o_THM; IMAGE_o; IMAGE_FSTCART_PCROSS] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    ASM_SIMP_TAC[LINEAR_FSTCART; LINEAR_CONTINUOUS_ON;
+                 IMAGE_FSTCART_PCROSS]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Trivial properties.                                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPIC_WITH_IMP_PROPERTY = prove
+ (`!P X Y (f:real^M->real^N) g. homotopic_with P (X,Y) f g ==> P f /\ P g`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_with] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^(1,M)finite_sum->real^N` MP_TAC) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN DISCH_THEN
+   (fun th -> MP_TAC(SPEC `vec 0:real^1` th) THEN
+              MP_TAC(SPEC `vec 1:real^1` th)) THEN
+  ASM_SIMP_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL; ETA_AX]);;
+
+let HOMOTOPIC_WITH_IMP_CONTINUOUS = prove
+ (`!P X Y (f:real^M->real^N) g.
+      homotopic_with P (X,Y) f g ==> f continuous_on X /\ g continuous_on X`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_with] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^(1,M)finite_sum->real^N` MP_TAC) THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN
+   `((h:real^(1,M)finite_sum->real^N) o (\x. pastecart (vec 0) x))
+    continuous_on X /\
+    ((h:real^(1,M)finite_sum->real^N) o (\x. pastecart (vec 1) x))
+    continuous_on X`
+  MP_TAC THENL [ALL_TAC; ASM_REWRITE_TAC[o_DEF; ETA_AX]] THEN
+  CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS] THEN
+  ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  SIMP_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM1; IN_INTERVAL_1] THEN
+  REWRITE_TAC[DROP_VEC; REAL_POS; REAL_LE_REFL]);;
+
+let HOMOTOPIC_WITH_IMP_SUBSET = prove
+ (`!P X Y (f:real^M->real^N) g.
+      homotopic_with P (X,Y) f g ==> IMAGE f X SUBSET Y /\ IMAGE g X SUBSET Y`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_with] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^(1,M)finite_sum->real^N` MP_TAC) THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; FORALL_IN_PCROSS; SUBSET] THEN DISCH_THEN
+   (fun th -> MP_TAC(SPEC `vec 0:real^1` th) THEN
+              MP_TAC(SPEC `vec 1:real^1` th)) THEN
+  ASM_SIMP_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL]);;
+
+let HOMOTOPIC_WITH_MONO = prove
+ (`!P Q X Y f g:real^M->real^N.
+        homotopic_with P (X,Y) f g /\
+        (!h. h continuous_on X /\ IMAGE h X SUBSET Y /\ P h ==> Q h)
+        ==> homotopic_with Q (X,Y) f g`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[homotopic_with; PCROSS] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[] THEN CONJ_TAC THENL
+   [GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_ID;
+             CONTINUOUS_ON_CONST] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    ASM SET_TAC[];
+    ASM SET_TAC[]]);;
+
+let HOMOTOPIC_WITH_SUBSET_LEFT = prove
+ (`!P X Y Z f g.
+        homotopic_with P (X,Y) f g /\ Z SUBSET X
+        ==> homotopic_with P (Z,Y) f g`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[homotopic_with; PCROSS] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+  STRIP_TAC 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
+    ASM SET_TAC[];
+    ASM SET_TAC[]]);;
+
+let HOMOTOPIC_WITH_SUBSET_RIGHT = prove
+ (`!P X Y Z (f:real^M->real^N) g h.
+        homotopic_with P (X,Y) f g /\ Y SUBSET Z
+        ==> homotopic_with P (X,Z) f g`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[homotopic_with] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN
+  ASM_MESON_TAC[SUBSET_TRANS]);;
+
+let HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT = prove
+ (`!p f:real^N->real^P g h:real^M->real^N W X Y.
+        homotopic_with (\f. p(f o h)) (X,Y) f g /\
+        h continuous_on W /\ IMAGE h W SUBSET X
+        ==> homotopic_with p (W,Y) (f o h) (g o h)`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[homotopic_with; o_DEF; PCROSS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real^(1,N)finite_sum->real^P`
+    STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\y:real^(1,M)finite_sum.
+                (k:real^(1,N)finite_sum->real^P)
+                (pastecart (fstcart y) (h(sndcart y)))` THEN
+  ASM_REWRITE_TAC[o_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  CONJ_TAC THENL
+   [GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+      SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART];
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE [IMP_CONJ]
+      CONTINUOUS_ON_SUBSET));
+    ALL_TAC] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+  SIMP_TAC[IN_ELIM_PASTECART_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  ASM SET_TAC[]);;
+
+let HOMOTOPIC_COMPOSE_CONTINUOUS_RIGHT = prove
+ (`!f:real^N->real^P g h:real^M->real^N W X Y.
+        homotopic_with (\f. T) (X,Y) f g /\
+        h continuous_on W /\ IMAGE h W SUBSET X
+        ==> homotopic_with (\f. T) (W,Y) (f o h) (g o h)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+  EXISTS_TAC `X:real^N->bool` THEN ASM_REWRITE_TAC[]);;
+
+let HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT = prove
+ (`!p f:real^M->real^N g h:real^N->real^P X Y Z.
+        homotopic_with (\f. p(h o f)) (X,Y) f g /\
+        h continuous_on Y /\ IMAGE h Y SUBSET Z
+        ==> homotopic_with p (X,Z) (h o f) (h o g)`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[homotopic_with; o_DEF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real^(1,M)finite_sum->real^N`
+    STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(h:real^N->real^P) o (k:real^(1,M)finite_sum->real^N)` THEN
+  ASM_REWRITE_TAC[o_THM] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE [IMP_CONJ]
+      CONTINUOUS_ON_SUBSET));
+    ALL_TAC] THEN
+  REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[]);;
+
+let HOMOTOPIC_COMPOSE_CONTINUOUS_LEFT = prove
+ (`!f:real^M->real^N g h:real^N->real^P X Y Z.
+        homotopic_with (\f. T) (X,Y) f g /\
+        h continuous_on Y /\ IMAGE h Y SUBSET Z
+        ==> homotopic_with (\f. T) (X,Z) (h o f) (h o g)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+  EXISTS_TAC `Y:real^N->bool` THEN ASM_REWRITE_TAC[]);;
+
+let HOMOTOPIC_WITH_PCROSS = prove
+ (`!f:real^M->real^N f':real^P->real^Q g g' p p' q s s' t t'.
+     homotopic_with p (s,t) f g /\
+     homotopic_with p' (s',t') f' g' /\
+     (!f g. p f /\ p' g ==> q(\x. pastecart (f(fstcart x)) (g(sndcart x))))
+     ==> homotopic_with q (s PCROSS s',t PCROSS t')
+          (\z. pastecart (f(fstcart z)) (f'(sndcart z)))
+          (\z. pastecart (g(fstcart z)) (g'(sndcart z)))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_with] THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `k:real^(1,M)finite_sum->real^N` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `k':real^(1,P)finite_sum->real^Q` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC
+   `\z:real^(1,(M,P)finite_sum)finite_sum.
+        pastecart (k(pastecart (fstcart z) (fstcart(sndcart z))):real^N)
+                  (k'(pastecart (fstcart z) (sndcart(sndcart z))):real^Q)` THEN
+  ASM_REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS]) THEN
+  ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS;
+               FSTCART_PASTECART; SNDCART_PASTECART; PASTECART_IN_PCROSS;
+               IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN CONJ_TAC THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  (CONJ_TAC THENL
+    [MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+     SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART] THEN
+     GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+     MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+     SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART];
+     FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      CONTINUOUS_ON_SUBSET)) THEN
+     REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS;
+                 IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+     ASM_SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART;
+                  PASTECART_IN_PCROSS]]));;
+
+(* ------------------------------------------------------------------------- *)
+(* Homotopy with P is an equivalence relation (on continuous functions       *)
+(* mapping X into Y that satisfy P, though this only affects reflexivity).   *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPIC_WITH_REFL = prove
+ (`!P X Y (f:real^M->real^N).
+      homotopic_with P (X,Y) f f <=>
+      f continuous_on X /\ IMAGE f X SUBSET Y /\ P f`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [MESON_TAC[HOMOTOPIC_WITH_IMP_PROPERTY; HOMOTOPIC_WITH_IMP_CONTINUOUS;
+              HOMOTOPIC_WITH_IMP_SUBSET];
+    STRIP_TAC THEN REWRITE_TAC[homotopic_with; PCROSS]] THEN
+  EXISTS_TAC `\y:real^(1,M)finite_sum. (f:real^M->real^N) (sndcart y)` THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; FORALL_IN_IMAGE]) THEN
+  ASM_SIMP_TAC[SNDCART_PASTECART; ETA_AX; SUBSET; FORALL_IN_IMAGE;
+               FORALL_IN_GSPEC] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+  ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC; SNDCART_PASTECART]);;
+
+let HOMOTOPIC_WITH_SYM = prove
+ (`!P X Y (f:real^M->real^N) g.
+      homotopic_with P (X,Y) f g <=> homotopic_with P (X,Y) g f`,
+  REPLICATE_TAC 3 GEN_TAC THEN MATCH_MP_TAC(MESON[]
+   `(!x y. P x y ==> P y x) ==> (!x y. P x y <=> P y x)`) THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_with; PCROSS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^(1,M)finite_sum->real^N`
+    STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\y:real^(1,M)finite_sum.
+        (h:real^(1,M)finite_sum->real^N)
+        (pastecart (vec 1 - fstcart y) (sndcart y))` THEN
+  REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  ASM_REWRITE_TAC[VECTOR_SUB_REFL; VECTOR_SUB_RZERO] THEN REPEAT CONJ_TAC THENL
+   [GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST;
+             LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET));
+    GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM o_DEF] THEN
+    REWRITE_TAC[IMAGE_o] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `IMAGE h s SUBSET t ==> IMAGE g s SUBSET s
+      ==> IMAGE h (IMAGE g s) SUBSET t`)) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC];
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC] THEN
+  SIMP_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; IN_ELIM_THM] THEN
+  ONCE_REWRITE_TAC[CONJ_SYM] THEN REWRITE_TAC[PASTECART_EQ] THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  SIMP_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM1; IN_INTERVAL_1] THEN
+  REWRITE_TAC[DROP_VEC; REAL_POS; REAL_LE_REFL; DROP_SUB] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let HOMOTOPIC_WITH_TRANS = prove
+ (`!P X Y (f:real^M->real^N) g h.
+      homotopic_with P (X,Y) f g /\ homotopic_with P (X,Y) g h
+      ==> homotopic_with P (X,Y) f h`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_with; PCROSS] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `k1:real^(1,M)finite_sum->real^N` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `k2:real^(1,M)finite_sum->real^N` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `\y:real^(1,M)finite_sum.
+        if drop(fstcart y) <= &1 / &2
+        then (k1:real^(1,M)finite_sum->real^N)
+             (pastecart (&2 % fstcart y) (sndcart y))
+        else (k2:real^(1,M)finite_sum->real^N)
+             (pastecart (&2 % fstcart y - vec 1) (sndcart y))` THEN
+  REWRITE_TAC[FSTCART_PASTECART; DROP_VEC] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[VECTOR_MUL_RZERO] THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH `&2 % x - x:real^N = x`; SNDCART_PASTECART] THEN
+  REPEAT CONJ_TAC THENL
+   [SUBGOAL_THEN
+     `interval[vec 0:real^1,vec 1] =
+      interval[vec 0,lift(&1 / &2)] UNION interval[lift(&1 / &2),vec 1]`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[EXTENSION; IN_UNION; IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[SET_RULE `{f x y | x IN s UNION t /\ y IN u} =
+                          {f x y | x IN s /\ y IN u} UNION
+                          {f x y | x IN t /\ y IN u}`] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN
+    ONCE_REWRITE_TAC[TAUT
+     `a /\ b /\ c /\ d /\ e <=> (a /\ b) /\ (c /\ d) /\ e`] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[CLOSED_IN_CLOSED] THEN CONJ_TAC THENL
+       [EXISTS_TAC `{ pastecart (t:real^1) (x:real^M) |
+                      t IN interval[vec 0,lift(&1 / &2)] /\ x IN UNIV }`;
+        EXISTS_TAC `{ pastecart (t:real^1) (x:real^M) |
+                      t IN interval[lift(&1 / &2),vec 1] /\ x IN UNIV}`] THEN
+      SIMP_TAC[REWRITE_RULE[PCROSS] CLOSED_PCROSS;
+               CLOSED_INTERVAL; CLOSED_UNIV] THEN
+      MATCH_MP_TAC SUBSET_ANTISYM THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_INTER; TAUT
+       `(x IN (s UNION t) /\ x IN u ==> x IN v) <=>
+        (x IN u ==> x IN (s UNION t) ==> x IN v)`] THEN
+      REWRITE_TAC[PASTECART_EQ; IN_ELIM_THM; IN_UNION] THEN
+      REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; IN_UNIV] THEN
+      MESON_TAC[];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [CONJ_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      (CONV_TAC o GEN_SIMPLIFY_CONV TOP_DEPTH_SQCONV (basic_ss []) 5)
+       [CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_CMUL; CONTINUOUS_ON_SUB;
+        CONTINUOUS_ON_CONST; LINEAR_CONTINUOUS_ON; LINEAR_FSTCART;
+        LINEAR_SNDCART] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+      REWRITE_TAC[IN_ELIM_THM; PASTECART_EQ; FSTCART_PASTECART;
+                  SNDCART_PASTECART] THEN
+      REWRITE_TAC[MESON[] `(?t x. P t x /\ a = t /\ b = x) <=> P a b`] THEN
+      SIMP_TAC[IN_INTERVAL_1; DROP_SUB; DROP_VEC; DROP_CMUL; LIFT_DROP] THEN
+      REAL_ARITH_TAC;
+      REWRITE_TAC[TAUT `p \/ q ==> r <=> (p ==> r) /\ (q ==> r)`] THEN
+      REWRITE_TAC[FORALL_AND_THM; IMP_CONJ; FORALL_IN_GSPEC] THEN
+      REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; IN_INTERVAL_1] THEN
+      SIMP_TAC[LIFT_DROP; DROP_VEC; REAL_ARITH
+       `&1 / &2 <= t ==> (t <= &1 / &2 <=> t = &1 / &2)`] THEN
+      SIMP_TAC[GSYM LIFT_EQ; LIFT_DROP; GSYM LIFT_CMUL; GSYM LIFT_NUM] THEN
+      REWRITE_TAC[GSYM LIFT_SUB] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      ASM_REWRITE_TAC[LIFT_NUM]];
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `IMAGE k s SUBSET t ==> x IN s ==> k x IN t`)) THEN
+    ASM_REWRITE_TAC[IN_ELIM_PASTECART_THM; IN_INTERVAL_1; DROP_VEC;
+                    DROP_CMUL; DROP_SUB] THEN
+    ASM_REAL_ARITH_TAC;
+    X_GEN_TAC `t:real^1` THEN REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN
+    STRIP_TAC THEN ASM_CASES_TAC `drop t <= &1 / &2` THEN ASM_SIMP_TAC[] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_CMUL; DROP_SUB] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Two characterizations of homotopic triviality, one of which               *)
+(* implicitly incorporates path-connectedness.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPIC_TRIVIALITY = prove
+ (`!s:real^M->bool t:real^N->bool.
+        (!f g. f continuous_on s /\ IMAGE f s SUBSET t /\
+               g continuous_on s /\ IMAGE g s SUBSET t
+               ==> homotopic_with (\x. T) (s,t) f g) <=>
+        (s = {} \/ path_connected t) /\
+        (!f. f continuous_on s /\ IMAGE f s SUBSET t
+             ==> ?c. homotopic_with (\x. T) (s,t) f (\x. c))`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^M->bool = {}` THENL
+   [ASM_SIMP_TAC[CONTINUOUS_ON_EMPTY; HOMOTOPIC_WITH; NOT_IN_EMPTY;
+                 PCROSS_EMPTY; IMAGE_CLAUSES; EMPTY_SUBSET];
+    ASM_CASES_TAC `t:real^N->bool = {}` THEN
+    ASM_REWRITE_TAC[SUBSET_EMPTY; IMAGE_EQ_EMPTY; PATH_CONNECTED_EMPTY]] THEN
+  EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [REWRITE_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT] THEN
+    REPEAT STRIP_TAC THEN
+    W(MP_TAC o PART_MATCH (rand o rand) HOMOTOPIC_CONSTANT_MAPS o snd) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; CONTINUOUS_ON_CONST] THEN
+    ASM SET_TAC[];
+    SUBGOAL_THEN `?c:real^N. c IN t` MP_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; CONTINUOUS_ON_CONST];
+    FIRST_X_ASSUM(fun th ->
+      MP_TAC(ISPEC `g:real^M->real^N` th) THEN
+      MP_TAC(ISPEC `f:real^M->real^N` th)) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `c:real^N` THEN DISCH_TAC THEN
+    X_GEN_TAC `d:real^N` THEN DISCH_TAC THEN
+    TRANS_TAC HOMOTOPIC_WITH_TRANS `(\x. c):real^M->real^N` THEN
+    ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN
+    TRANS_TAC HOMOTOPIC_WITH_TRANS `(\x. d):real^M->real^N` THEN
+    ASM_REWRITE_TAC[HOMOTOPIC_CONSTANT_MAPS] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o
+      REWRITE_RULE[PATH_CONNECTED_IFF_PATH_COMPONENT]) THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET)) THEN
+    ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homotopy of paths, maintaining the same endpoints.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let homotopic_paths = new_definition
+ `homotopic_paths s p q =
+     homotopic_with
+       (\r. pathstart r = pathstart p /\ pathfinish r = pathfinish p)
+       (interval[vec 0:real^1,vec 1],s)
+       p q`;;
+
+let HOMOTOPIC_PATHS = prove
+ (`!s p q:real^1->real^N.
+      homotopic_paths s p q <=>
+      ?h. h continuous_on
+          interval[vec 0,vec 1] PCROSS interval[vec 0,vec 1] /\
+          IMAGE h (interval[vec 0,vec 1] PCROSS interval[vec 0,vec 1])
+          SUBSET s /\
+          (!x. x IN interval[vec 0,vec 1] ==> h(pastecart (vec 0) x) = p x) /\
+          (!x. x IN interval[vec 0,vec 1] ==> h(pastecart (vec 1) x) = q x) /\
+          (!t. t IN interval[vec 0:real^1,vec 1]
+               ==> pathstart(h o pastecart t) = pathstart p /\
+                   pathfinish(h o pastecart t) = pathfinish p)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[homotopic_paths] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) HOMOTOPIC_WITH o lhand o snd) THEN
+  ANTS_TAC THENL
+   [SIMP_TAC[pathstart; pathfinish; ENDS_IN_UNIT_INTERVAL];
+    DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[o_DEF]]);;
+
+let HOMOTOPIC_PATHS_IMP_PATHSTART = prove
+ (`!s p q. homotopic_paths s p q ==> pathstart p = pathstart q`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_paths] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_PROPERTY) THEN
+  SIMP_TAC[]);;
+
+let HOMOTOPIC_PATHS_IMP_PATHFINISH = prove
+ (`!s p q. homotopic_paths s p q ==> pathfinish p = pathfinish q`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_paths] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_PROPERTY) THEN
+  SIMP_TAC[]);;
+
+let HOMOTOPIC_PATHS_IMP_PATH = prove
+ (`!s p q. homotopic_paths s p q ==> path p /\ path q`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_paths] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_CONTINUOUS) THEN
+  SIMP_TAC[path]);;
+
+let HOMOTOPIC_PATHS_IMP_SUBSET = prove
+ (`!s p q.
+     homotopic_paths s p q ==> path_image p SUBSET s /\ path_image q SUBSET s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_paths] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET) THEN
+  SIMP_TAC[path_image]);;
+
+let HOMOTOPIC_PATHS_REFL = prove
+ (`!s p. homotopic_paths s p p <=>
+           path p /\ path_image p SUBSET s`,
+  REWRITE_TAC[homotopic_paths; HOMOTOPIC_WITH_REFL; path; path_image]);;
+
+let HOMOTOPIC_PATHS_SYM = prove
+ (`!s p q. homotopic_paths s p q <=> homotopic_paths s q p`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHSTART) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHFINISH) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopic_paths]) THEN
+  ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN ASM_SIMP_TAC[homotopic_paths]);;
+
+let HOMOTOPIC_PATHS_TRANS = prove
+ (`!s p q r.
+        homotopic_paths s p q /\ homotopic_paths s q r
+        ==> homotopic_paths s p r`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(CONJUNCTS_THEN
+   (fun th -> ASSUME_TAC(MATCH_MP HOMOTOPIC_PATHS_IMP_PATHSTART th) THEN
+              ASSUME_TAC(MATCH_MP HOMOTOPIC_PATHS_IMP_PATHFINISH th))) THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE BINOP_CONV [homotopic_paths]) THEN
+  ASM_REWRITE_TAC[HOMOTOPIC_WITH_TRANS; homotopic_paths]);;
+
+let HOMOTOPIC_PATHS_EQ = prove
+ (`!p:real^1->real^N q s.
+        path p /\ path_image p SUBSET s /\
+        (!t. t IN interval[vec 0,vec 1] ==> p(t) = q(t))
+        ==> homotopic_paths s p q`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[homotopic_paths] THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_EQ THEN
+  REPEAT(EXISTS_TAC `p:real^1->real^N`) THEN
+  ASM_SIMP_TAC[HOMOTOPIC_WITH_REFL] THEN
+  ASM_REWRITE_TAC[GSYM path; GSYM path_image] THEN
+  REWRITE_TAC[pathstart; pathfinish] THEN
+  MESON_TAC[ENDS_IN_UNIT_INTERVAL]);;
+
+let HOMOTOPIC_PATHS_REPARAMETRIZE = prove
+ (`!p:real^1->real^N q f:real^1->real^1.
+        path p /\ path_image p SUBSET s /\
+        (?f. f continuous_on interval[vec 0,vec 1] /\
+             IMAGE f (interval[vec 0,vec 1]) SUBSET interval[vec 0,vec 1] /\
+             f(vec 0) = vec 0 /\ f(vec 1) = vec 1 /\
+             !t. t IN interval[vec 0,vec 1] ==> q(t) = p(f t))
+        ==> homotopic_paths s p q`,
+  REWRITE_TAC[path; path_image] THEN REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+  EXISTS_TAC `(p:real^1->real^N) o (f:real^1->real^1)` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HOMOTOPIC_PATHS_EQ THEN
+    ASM_SIMP_TAC[o_THM; pathstart; pathfinish; o_THM;
+                 IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL] THEN
+    REWRITE_TAC[path; path_image] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_EQ THEN
+      EXISTS_TAC `(p:real^1->real^N) o (f:real^1->real^1)` THEN
+      ASM_SIMP_TAC[o_THM] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+      ASM SET_TAC[]];
+    REWRITE_TAC[homotopic_paths; homotopic_with; PCROSS] THEN
+    EXISTS_TAC `(p:real^1->real^N) o
+                (\y. (&1 - drop(fstcart y)) % f(sndcart y) +
+                     drop(fstcart y) % sndcart y)` THEN
+    ASM_REWRITE_TAC[o_THM; FSTCART_PASTECART; SNDCART_PASTECART; DROP_VEC;
+                    pathstart; pathfinish] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_MUL_RZERO; VECTOR_ADD_LID;
+                VECTOR_MUL_LID; VECTOR_ADD_RID] THEN
+    REWRITE_TAC[VECTOR_ARITH `(&1 - u) % x + u % x:real^N = x`] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN CONJ_TAC THEN
+        MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+        REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX; LIFT_SUB] THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; CONTINUOUS_ON_CONST; LINEAR_FSTCART;
+                 LINEAR_SNDCART; CONTINUOUS_ON_SUB] THEN
+        MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_COMPOSE) THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        SIMP_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC; SNDCART_PASTECART];
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET))];
+      ONCE_REWRITE_TAC[IMAGE_o] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `IMAGE p i SUBSET s
+        ==> IMAGE f x SUBSET i
+            ==> IMAGE p (IMAGE f x) SUBSET s`))] THEN
+    SIMP_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC; SNDCART_PASTECART;
+             FSTCART_PASTECART] THEN
+    REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC(REWRITE_RULE[CONVEX_ALT] (CONJUNCT1(SPEC_ALL
+      CONVEX_INTERVAL))) THEN
+    ASM_MESON_TAC[IN_INTERVAL_1; DROP_VEC; SUBSET; IN_IMAGE]]);;
+
+let HOMOTOPIC_PATHS_SUBSET = prove
+ (`!s p q.
+        homotopic_paths s p q /\ s SUBSET t
+        ==> homotopic_paths t p q`,
+  REWRITE_TAC[homotopic_paths; HOMOTOPIC_WITH_SUBSET_RIGHT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A slightly ad-hoc but useful lemma in constructing homotopies.            *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPIC_JOIN_LEMMA = prove
+ (`!p q:real^1->real^1->real^N.
+  (\y. p (fstcart y) (sndcart y)) continuous_on
+  (interval[vec 0,vec 1] PCROSS interval[vec 0,vec 1]) /\
+  (\y. q (fstcart y) (sndcart y)) continuous_on
+  (interval[vec 0,vec 1] PCROSS interval[vec 0,vec 1]) /\
+  (!t. t IN interval[vec 0,vec 1] ==> pathfinish(p t) = pathstart(q t))
+  ==> (\y. (p(fstcart y) ++ q(fstcart y)) (sndcart y)) continuous_on
+      (interval[vec 0,vec 1] PCROSS interval[vec 0,vec 1])`,
+  REWRITE_TAC[joinpaths; PCROSS] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC CONTINUOUS_ON_CASES_LE THEN REPEAT CONJ_TAC THENL
+   [SUBGOAL_THEN
+    `(\y. p (fstcart y) (&2 % sndcart y)):real^(1,1)finite_sum->real^N =
+     (\y. p (fstcart y) (sndcart y)) o
+     (\y. pastecart (fstcart y) (&2 % sndcart y))`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[o_DEF; FSTCART_PASTECART; SNDCART_PASTECART]; ALL_TAC];
+    SUBGOAL_THEN
+    `(\y. q (fstcart y) (&2 % sndcart y - vec 1)):real^(1,1)finite_sum->real^N =
+     (\y. q (fstcart y) (sndcart y)) o
+     (\y. pastecart (fstcart y) (&2 % sndcart y - vec 1))`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[o_DEF; FSTCART_PASTECART; SNDCART_PASTECART]; ALL_TAC];
+    SIMP_TAC[o_DEF; LIFT_DROP; LINEAR_CONTINUOUS_ON; LINEAR_SNDCART; ETA_AX];
+    SIMP_TAC[IMP_CONJ; FORALL_IN_GSPEC; FSTCART_PASTECART; SNDCART_PASTECART;
+             GSYM LIFT_EQ; LIFT_DROP; GSYM LIFT_CMUL] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+    ASM_SIMP_TAC[LIFT_NUM; VECTOR_SUB_REFL]] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  (CONJ_TAC THENL [MATCH_MP_TAC CONTINUOUS_ON_PASTECART; ALL_TAC]) THEN
+  SIMP_TAC[CONTINUOUS_ON_CMUL; LINEAR_CONTINUOUS_ON; CONTINUOUS_ON_SUB;
+           CONTINUOUS_ON_CONST; LINEAR_FSTCART; LINEAR_SNDCART] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    CONTINUOUS_ON_SUBSET)) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC; IMP_CONJ] THEN
+  SIMP_TAC[IN_ELIM_PASTECART_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_CMUL; DROP_SUB; DROP_VEC] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Congruence properties of homotopy w.r.t. path-combining operations.       *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPIC_PATHS_REVERSEPATH = prove
+ (`!s p q:real^1->real^N.
+     homotopic_paths s (reversepath p) (reversepath q) <=>
+     homotopic_paths s p q`,
+  GEN_TAC THEN MATCH_MP_TAC(MESON[]
+   `(!p. f(f p) = p) /\
+    (!a b. homotopic_paths s a b ==> homotopic_paths s (f a) (f b))
+    ==> !a b. homotopic_paths s (f a) (f b) <=>
+              homotopic_paths s a b`) THEN
+  REWRITE_TAC[REVERSEPATH_REVERSEPATH] THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[homotopic_paths; homotopic_with; PCROSS; o_DEF] THEN DISCH_THEN
+   (X_CHOOSE_THEN `h:real^(1,1)finite_sum->real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\y:real^(1,1)finite_sum.
+                 (h:real^(1,1)finite_sum->real^N)
+                 (pastecart(fstcart y) (vec 1 - sndcart y))` THEN
+  ASM_REWRITE_TAC[o_DEF; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+  ASM_SIMP_TAC[reversepath; pathstart; pathfinish; VECTOR_SUB_REFL;
+               VECTOR_SUB_RZERO] THEN
+  CONJ_TAC THENL
+   [GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+      SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART;
+               CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+      SIMP_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC;
+        IN_ELIM_PASTECART_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+      REWRITE_TAC[IN_INTERVAL_1; DROP_SUB; DROP_VEC] THEN REAL_ARITH_TAC];
+     GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM o_DEF] THEN
+     REWRITE_TAC[IMAGE_o] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `IMAGE h s SUBSET t ==> IMAGE g s SUBSET s
+      ==> IMAGE h (IMAGE g s) SUBSET t`)) THEN
+     SIMP_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC;
+        IN_ELIM_PASTECART_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+     REWRITE_TAC[IN_INTERVAL_1; DROP_SUB; DROP_VEC] THEN REAL_ARITH_TAC]);;
+
+let HOMOTOPIC_PATHS_JOIN = prove
+ (`!s p q p' q':real^1->real^N.
+     homotopic_paths s p p' /\ homotopic_paths s q q' /\
+     pathfinish p = pathstart q
+     ==> homotopic_paths s (p ++ q) (p' ++ q')`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[homotopic_paths; homotopic_with; PCROSS] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `k1:real^(1,1)finite_sum->real^N` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `k2:real^(1,1)finite_sum->real^N` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `(\y. ((k1 o pastecart (fstcart y)) ++
+                    (k2 o pastecart (fstcart y))) (sndcart y))
+              :real^(1,1)finite_sum->real^N` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC(REWRITE_RULE[PCROSS] HOMOTOPIC_JOIN_LEMMA) THEN
+    ASM_REWRITE_TAC[o_DEF; PASTECART_FST_SND; ETA_AX] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+    ASM_REWRITE_TAC[pathstart; pathfinish] THEN ASM_MESON_TAC[];
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[ETA_AX; GSYM path_image; SET_RULE
+      `(!x. x IN i ==> f x IN s) <=> IMAGE f i SUBSET s`] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_PATH_IMAGE_JOIN THEN
+    REWRITE_TAC[path_image; SUBSET; FORALL_IN_IMAGE; o_DEF] THEN ASM SET_TAC[];
+    ALL_TAC; ALL_TAC; ALL_TAC] THEN
+  REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  ASM_REWRITE_TAC[joinpaths; o_DEF] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+  REWRITE_TAC[pathstart; pathfinish; DROP_VEC] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  ASM_SIMP_TAC[VECTOR_ARITH `&2 % x - x:real^N = x`; VECTOR_MUL_RZERO]);;
+
+let HOMOTOPIC_PATHS_CONTINUOUS_IMAGE = prove
+ (`!f:real^1->real^M g h:real^M->real^N s t.
+        homotopic_paths s f g /\
+        h continuous_on s /\ IMAGE h s SUBSET t
+        ==> homotopic_paths t (h o f) (h o g)`,
+  REWRITE_TAC[homotopic_paths] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        HOMOTOPIC_WITH_MONO)) THEN
+  SIMP_TAC[pathstart; pathfinish; o_THM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Group properties for homotopy of paths (so taking equivalence classes     *)
+(* under homotopy would give the fundamental group).                         *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPIC_PATHS_RID = prove
+ (`!s p. path p /\ path_image p SUBSET s
+         ==> homotopic_paths s (p ++ linepath(pathfinish p,pathfinish p)) p`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_REPARAMETRIZE THEN
+  ASM_REWRITE_TAC[joinpaths] THEN
+  EXISTS_TAC `\t. if drop t <= &1 / &2 then &2 % t else vec 1` THEN
+  ASM_REWRITE_TAC[DROP_VEC] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; linepath; pathfinish;
+              VECTOR_ARITH `(&1 - t) % x + t % x:real^N = x`] THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+  CONJ_TAC THENL
+   [SUBGOAL_THEN
+     `interval[vec 0:real^1,vec 1] =
+      interval[vec 0,lift(&1 / &2)] UNION interval[lift(&1 / &2),vec 1]`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[EXTENSION; IN_UNION; IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+      REAL_ARITH_TAC;
+      MATCH_MP_TAC CONTINUOUS_ON_CASES THEN
+      SIMP_TAC[CLOSED_INTERVAL; CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID;
+               CONTINUOUS_ON_CONST; IN_INTERVAL_1; DROP_VEC; LIFT_DROP;
+               GSYM DROP_EQ; DROP_CMUL] THEN
+      REAL_ARITH_TAC];
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1; DROP_VEC] THEN
+    GEN_TAC THEN COND_CASES_TAC THEN REWRITE_TAC[DROP_CMUL; DROP_VEC] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let HOMOTOPIC_PATHS_LID = prove
+ (`!s p:real^1->real^N.
+        path p /\ path_image p SUBSET s
+        ==> homotopic_paths s (linepath(pathstart p,pathstart p) ++ p) p`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM HOMOTOPIC_PATHS_REVERSEPATH] THEN
+  REWRITE_TAC[o_DEF; PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH] THEN
+  SIMP_TAC[REVERSEPATH_JOINPATHS; REVERSEPATH_LINEPATH;
+           PATHFINISH_LINEPATH] THEN
+  ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `reversepath p :real^1->real^N`]
+    HOMOTOPIC_PATHS_RID) THEN
+  ASM_SIMP_TAC[PATH_REVERSEPATH; PATH_IMAGE_REVERSEPATH;
+               PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH]);;
+
+let HOMOTOPIC_PATHS_ASSOC = prove
+ (`!s p q r:real^1->real^N.
+        path p /\ path_image p SUBSET s /\
+        path q /\ path_image q SUBSET s /\
+        path r /\ path_image r SUBSET s /\
+        pathfinish p = pathstart q /\ pathfinish q = pathstart r
+        ==> homotopic_paths s (p ++ (q ++ r)) ((p ++ q) ++ r)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_REPARAMETRIZE THEN
+  ASM_SIMP_TAC[PATH_JOIN; PATH_IMAGE_JOIN; UNION_SUBSET;
+               PATHSTART_JOIN; PATHFINISH_JOIN] THEN
+  REWRITE_TAC[joinpaths] THEN
+  EXISTS_TAC `\t. if drop t <= &1 / &2 then inv(&2) % t
+                  else if drop t <= &3 / &4 then t - lift(&1 / &4)
+                  else &2 % t - vec 1` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_CASES_1 THEN
+    SIMP_TAC[CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID; LIFT_DROP] THEN
+    REWRITE_TAC[GSYM LIFT_SUB; GSYM LIFT_CMUL] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CASES_1 THEN
+    SIMP_TAC[CONTINUOUS_ON_CMUL; CONTINUOUS_ON_SUB; CONTINUOUS_ON_ID;
+             CONTINUOUS_ON_CONST] THEN
+    REWRITE_TAC[GSYM LIFT_SUB; GSYM LIFT_CMUL; GSYM LIFT_NUM] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV;
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1; DROP_VEC] THEN
+    REPEAT STRIP_TAC THEN
+    REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+    REWRITE_TAC[DROP_CMUL; DROP_VEC; LIFT_DROP; DROP_SUB] THEN
+    ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[DROP_VEC] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[VECTOR_MUL_RZERO];
+    REWRITE_TAC[DROP_VEC] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    VECTOR_ARITH_TAC;
+    X_GEN_TAC `t:real^1` THEN REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN
+    STRIP_TAC THEN
+    ASM_CASES_TAC `drop t <= &1 / &2` THEN ASM_REWRITE_TAC[DROP_CMUL] THEN
+    ASM_REWRITE_TAC[REAL_ARITH `inv(&2) * t <= &1 / &2 <=> t <= &1`] THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC; REAL_MUL_ASSOC] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[REAL_MUL_LID] THEN
+    ASM_CASES_TAC `drop t <= &3 / &4` THEN
+    ASM_REWRITE_TAC[DROP_SUB; DROP_VEC; DROP_CMUL; LIFT_DROP;
+                    REAL_ARITH `&2 * (t - &1 / &4) <= &1 / &2 <=> t <= &1 / &2`;
+                    REAL_ARITH `&2 * t - &1 <= &1 / &2 <=> t <= &3 / &4`;
+                    REAL_ARITH `t - &1 / &4 <= &1 / &2 <=> t <= &3 / &4`] THEN
+    REWRITE_TAC[VECTOR_SUB_LDISTRIB; VECTOR_MUL_ASSOC; GSYM LIFT_CMUL] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[LIFT_NUM] THEN
+    REWRITE_TAC[VECTOR_ARITH `a - b - b:real^N = a - &2 % b`]]);;
+
+let HOMOTOPIC_PATHS_RINV = prove
+ (`!s p:real^1->real^N.
+        path p /\ path_image p SUBSET s
+        ==> homotopic_paths s
+              (p ++ reversepath p) (linepath(pathstart p,pathstart p))`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+  REWRITE_TAC[homotopic_paths; homotopic_with; PCROSS] THEN
+  EXISTS_TAC `(\y. (subpath (vec 0) (fstcart y) p ++
+                    reversepath(subpath (vec 0) (fstcart y) p)) (sndcart y))
+              : real^(1,1)finite_sum->real^N` THEN
+  REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; SUBPATH_TRIVIAL] THEN
+  REWRITE_TAC[ETA_AX; PATHSTART_JOIN; PATHFINISH_JOIN] THEN
+  REWRITE_TAC[REVERSEPATH_SUBPATH; PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[joinpaths] THEN MATCH_MP_TAC CONTINUOUS_ON_CASES_LE THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[path; path_image]) THEN REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[subpath; VECTOR_ADD_LID; VECTOR_SUB_RZERO] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+        REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX] THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART;
+                 CONTINUOUS_ON_CMUL];
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        REWRITE_TAC[FORALL_IN_IMAGE; SUBSET; FORALL_IN_GSPEC; IMP_CONJ] THEN
+        REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+        REWRITE_TAC[IN_INTERVAL_1; DROP_CMUL; DROP_VEC] THEN
+        REPEAT STRIP_TAC THEN ASM_SIMP_TAC[REAL_LE_MUL; REAL_POS] THEN
+        MATCH_MP_TAC REAL_LE_TRANS THEN
+        EXISTS_TAC `drop x * &2 * &1 / &2` THEN CONJ_TAC THEN
+        REPEAT(MATCH_MP_TAC REAL_LE_LMUL THEN CONJ_TAC) THEN
+        ASM_REAL_ARITH_TAC];
+      REWRITE_TAC[subpath; VECTOR_ADD_LID; VECTOR_SUB_RZERO] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+        REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX] THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART;
+                 CONTINUOUS_ON_CMUL; CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST];
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        REWRITE_TAC[FORALL_IN_IMAGE; SUBSET; FORALL_IN_GSPEC; IMP_CONJ] THEN
+        REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+        REWRITE_TAC[IN_INTERVAL_1; DROP_SUB; DROP_CMUL; DROP_VEC; DROP_ADD;
+         REAL_ARITH `t + (&0 - t) * (&2 * x - &1) =
+                     t * &2 * (&1 - x)`] THEN
+        REPEAT STRIP_TAC THEN
+        ASM_SIMP_TAC[REAL_LE_MUL; REAL_POS; REAL_SUB_LE] THEN
+        MATCH_MP_TAC REAL_LE_TRANS THEN
+        EXISTS_TAC `drop x * &2 * &1 / &2` THEN CONJ_TAC THEN
+        REPEAT(MATCH_MP_TAC REAL_LE_LMUL THEN CONJ_TAC) THEN
+        ASM_REAL_ARITH_TAC];
+      SIMP_TAC[o_DEF; LIFT_DROP; ETA_AX; LINEAR_CONTINUOUS_ON; LINEAR_SNDCART];
+      REWRITE_TAC[GSYM LIFT_EQ; LIFT_DROP] THEN
+      REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[subpath] THEN AP_TERM_TAC THEN
+      REWRITE_TAC[GSYM DROP_EQ; DROP_SUB; DROP_VEC; DROP_ADD; DROP_CMUL;
+                  LIFT_DROP] THEN
+      REAL_ARITH_TAC];
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ] THEN
+    X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; ETA_AX;
+      SET_RULE `(!x. x IN s ==> f x IN t) <=> IMAGE f s SUBSET t`] THEN
+    REWRITE_TAC[GSYM path_image] THEN MATCH_MP_TAC SUBSET_PATH_IMAGE_JOIN THEN
+    REWRITE_TAC[PATH_IMAGE_SUBPATH_GEN] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE LAND_CONV [path_image]) THEN
+    MATCH_MP_TAC(SET_RULE
+      `t SUBSET s /\ u SUBSET s
+       ==> IMAGE p s SUBSET v
+           ==> IMAGE p t SUBSET v /\ IMAGE p u SUBSET v`) THEN
+    REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN CONJ_TAC THEN
+    MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_INTERVAL] THEN
+    ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET] THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; REAL_POS; REAL_LE_REFL];
+    REWRITE_TAC[subpath; linepath; pathstart; joinpaths] THEN
+    REWRITE_TAC[VECTOR_SUB_REFL; DROP_VEC; VECTOR_MUL_LZERO] THEN
+    REWRITE_TAC[VECTOR_ADD_RID; COND_ID] THEN VECTOR_ARITH_TAC;
+    REWRITE_TAC[pathstart; PATHFINISH_LINEPATH; PATHSTART_LINEPATH]]);;
+
+let HOMOTOPIC_PATHS_LINV = prove
+ (`!s p:real^1->real^N.
+        path p /\ path_image p SUBSET s
+        ==> homotopic_paths s
+              (reversepath p ++ p) (linepath(pathfinish p,pathfinish p))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `reversepath p:real^1->real^N`]
+        HOMOTOPIC_PATHS_RINV) THEN
+  ASM_SIMP_TAC[PATH_REVERSEPATH; PATH_IMAGE_REVERSEPATH] THEN
+  REWRITE_TAC[PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+              REVERSEPATH_REVERSEPATH]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homotopy of loops without requiring preservation of endpoints.            *)
+(* ------------------------------------------------------------------------- *)
+
+let homotopic_loops = new_definition
+ `homotopic_loops s p q =
+     homotopic_with
+       (\r. pathfinish r = pathstart r)
+       (interval[vec 0:real^1,vec 1],s)
+       p q`;;
+
+let HOMOTOPIC_LOOPS = prove
+ (`!s p q:real^1->real^N.
+      homotopic_loops s p q <=>
+      ?h. h continuous_on
+          interval[vec 0,vec 1] PCROSS interval[vec 0,vec 1] /\
+          IMAGE h (interval[vec 0,vec 1] PCROSS interval[vec 0,vec 1])
+          SUBSET s /\
+          (!x. x IN interval[vec 0,vec 1] ==> h(pastecart (vec 0) x) = p x) /\
+          (!x. x IN interval[vec 0,vec 1] ==> h(pastecart (vec 1) x) = q x) /\
+          (!t. t IN interval[vec 0:real^1,vec 1]
+               ==> pathfinish(h o pastecart t) = pathstart(h o pastecart t))`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[homotopic_loops] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) HOMOTOPIC_WITH o lhand o snd) THEN
+  ANTS_TAC THENL
+   [SIMP_TAC[pathstart; pathfinish; ENDS_IN_UNIT_INTERVAL];
+    DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[o_DEF]]);;
+
+let HOMOTOPIC_LOOPS_IMP_LOOP = prove
+ (`!s p q. homotopic_loops s p q
+           ==> pathfinish p = pathstart p /\
+               pathfinish q = pathstart q`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_loops] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_PROPERTY) THEN
+  SIMP_TAC[]);;
+
+let HOMOTOPIC_LOOPS_IMP_PATH = prove
+ (`!s p q. homotopic_loops s p q ==> path p /\ path q`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_loops] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_CONTINUOUS) THEN
+  SIMP_TAC[path]);;
+
+let HOMOTOPIC_LOOPS_IMP_SUBSET = prove
+ (`!s p q.
+     homotopic_loops s p q ==> path_image p SUBSET s /\ path_image q SUBSET s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_loops] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET) THEN
+  SIMP_TAC[path_image]);;
+
+let HOMOTOPIC_LOOPS_REFL = prove
+ (`!s p. homotopic_loops s p p <=>
+           path p /\ path_image p SUBSET s /\ pathfinish p = pathstart p`,
+  REWRITE_TAC[homotopic_loops; HOMOTOPIC_WITH_REFL; path; path_image]);;
+
+let HOMOTOPIC_LOOPS_SYM = prove
+ (`!s p q. homotopic_loops s p q <=> homotopic_loops s q p`,
+  REWRITE_TAC[homotopic_loops; HOMOTOPIC_WITH_SYM]);;
+
+let HOMOTOPIC_LOOPS_TRANS = prove
+ (`!s p q r.
+        homotopic_loops s p q /\ homotopic_loops s q r
+        ==> homotopic_loops s p r`,
+  REWRITE_TAC[homotopic_loops; HOMOTOPIC_WITH_TRANS]);;
+
+let HOMOTOPIC_LOOPS_SUBSET = prove
+ (`!s p q.
+        homotopic_loops s p q /\ s SUBSET t
+        ==> homotopic_loops t p q`,
+  REWRITE_TAC[homotopic_loops; HOMOTOPIC_WITH_SUBSET_RIGHT]);;
+
+let HOMOTOPIC_LOOPS_EQ = prove
+ (`!p:real^1->real^N q s.
+        path p /\ path_image p SUBSET s /\ pathfinish p = pathstart p /\
+        (!t. t IN interval[vec 0,vec 1] ==> p(t) = q(t))
+        ==> homotopic_loops s p q`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[homotopic_loops] THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_EQ THEN
+  REPEAT(EXISTS_TAC `p:real^1->real^N`) THEN
+  ASM_SIMP_TAC[HOMOTOPIC_WITH_REFL] THEN
+  ASM_REWRITE_TAC[GSYM path; GSYM path_image] THEN
+  REWRITE_TAC[pathstart; pathfinish] THEN
+  MESON_TAC[ENDS_IN_UNIT_INTERVAL]);;
+
+let HOMOTOPIC_LOOPS_CONTINUOUS_IMAGE = prove
+ (`!f:real^1->real^M g h:real^M->real^N s t.
+        homotopic_loops s f g /\
+        h continuous_on s /\ IMAGE h s SUBSET t
+        ==> homotopic_loops t (h o f) (h o g)`,
+  REWRITE_TAC[homotopic_loops] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        HOMOTOPIC_WITH_MONO)) THEN
+  SIMP_TAC[pathstart; pathfinish; o_THM]);;
+
+let HOMOTOPIC_LOOPS_SHIFTPATH_SELF = prove
+ (`!p:real^1->real^N t s.
+        path p /\ path_image p SUBSET s /\ pathfinish p = pathstart p /\
+        t IN interval[vec 0,vec 1]
+        ==> homotopic_loops s p (shiftpath t p)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[HOMOTOPIC_LOOPS] THEN EXISTS_TAC
+   `\z. shiftpath (drop t % fstcart z) (p:real^1->real^N) (sndcart z)` THEN
+  REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; o_DEF] THEN
+  REWRITE_TAC[GSYM LIFT_EQ_CMUL; VECTOR_MUL_RZERO; ETA_AX] THEN
+  REPEAT CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    MATCH_MP_TAC(SET_RULE
+     `IMAGE p t SUBSET u /\
+      (!x. x IN s ==> IMAGE(shiftpath (f x) p) t = IMAGE p t)
+      ==> (!x y. x IN s /\ y IN t ==> shiftpath (f x) p y  IN u)`) THEN
+    ASM_REWRITE_TAC[GSYM path_image] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC PATH_IMAGE_SHIFTPATH THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_CMUL; DROP_VEC] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+    ASM_SIMP_TAC[REAL_LE_MUL] THEN
+    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN ASM_SIMP_TAC[];
+    SIMP_TAC[shiftpath; VECTOR_ADD_LID; IN_INTERVAL_1; DROP_VEC];
+    REWRITE_TAC[LIFT_DROP];
+    X_GEN_TAC `x:real^1` THEN STRIP_TAC THEN MATCH_MP_TAC CLOSED_SHIFTPATH THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_CMUL; DROP_VEC] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+    ASM_SIMP_TAC[REAL_LE_MUL] THEN
+    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN ASM_SIMP_TAC[]] THEN
+  REWRITE_TAC[shiftpath; DROP_ADD; DROP_CMUL] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_CASES_LE THEN REPEAT CONJ_TAC THENL
+   [GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_MUL; o_DEF; LIFT_DROP;
+             LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART;
+             CONTINUOUS_ON_CONST] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[path]) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_PASTECART] THEN
+    REWRITE_TAC[IN_ELIM_THM; PASTECART_IN_PCROSS] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+    ASM_SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART; IN_INTERVAL_1;
+                 DROP_ADD; DROP_CMUL; DROP_VEC; REAL_LE_ADD; REAL_LE_MUL];
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_MUL; o_DEF; LIFT_DROP;
+             LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART;
+             CONTINUOUS_ON_CONST; CONTINUOUS_ON_SUB] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[path]) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_PASTECART] THEN
+    REWRITE_TAC[IN_ELIM_THM; PASTECART_IN_PCROSS] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+    ASM_SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART; IN_INTERVAL_1; DROP_SUB;
+                 DROP_ADD; DROP_CMUL; DROP_VEC; REAL_LE_ADD; REAL_LE_MUL] THEN
+    SIMP_TAC[REAL_ARITH `&0 <= x + y - &1 <=> &1 <= x + y`] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC(REAL_ARITH
+     `t * x <= &1 * &1 /\ y <= &1 ==> t * x + y - &1 <= &1`) THEN
+    ASM_SIMP_TAC[REAL_LE_MUL2; REAL_POS];
+    REWRITE_TAC[o_DEF; LIFT_ADD; LIFT_CMUL; LIFT_DROP] THEN
+    SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_CMUL; LINEAR_CONTINUOUS_ON;
+             LINEAR_FSTCART; LINEAR_SNDCART];
+    SIMP_TAC[GSYM LIFT_EQ; LIFT_ADD; LIFT_CMUL; LIFT_DROP; LIFT_NUM;
+             VECTOR_ARITH `a + b - c:real^1 = (a + b) - c`] THEN
+    ASM_MESON_TAC[VECTOR_SUB_REFL; pathstart; pathfinish]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relations between the two variants of homotopy.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPIC_PATHS_IMP_HOMOTOPIC_LOOPS = prove
+ (`!s p q. homotopic_paths s p q /\
+           pathfinish p = pathstart p /\
+           pathfinish q = pathstart p
+           ==> homotopic_loops s p q`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[homotopic_paths; homotopic_loops] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_MONO) THEN
+  ASM_SIMP_TAC[]);;
+
+let HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_PATHS_NULL = prove
+ (`!s p a:real^N.
+        homotopic_loops s p (linepath(a,a))
+        ==> homotopic_paths s p (linepath(pathstart p,pathstart p))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o CONJUNCT1 o MATCH_MP HOMOTOPIC_LOOPS_IMP_LOOP) THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP HOMOTOPIC_LOOPS_IMP_PATH) THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP HOMOTOPIC_LOOPS_IMP_SUBSET) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopic_loops]) THEN
+  REWRITE_TAC[homotopic_with; PCROSS; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `h:real^(1,1)finite_sum->real^N` THEN STRIP_TAC THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN EXISTS_TAC
+   `(p:real^1->real^N) ++ linepath(pathfinish p,pathfinish p)` THEN
+  CONJ_TAC THENL
+   [ASM_MESON_TAC[HOMOTOPIC_PATHS_RID; HOMOTOPIC_PATHS_SYM]; ALL_TAC] THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN EXISTS_TAC
+   `linepath(pathstart p,pathstart p) ++ (p:real^1->real^N) ++
+    linepath(pathfinish p,pathfinish p)` THEN
+  CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+    MP_TAC(ISPECL [`s:real^N->bool`;
+       `(p:real^1->real^N) ++ linepath(pathfinish p,pathfinish p)`]
+     HOMOTOPIC_PATHS_LID) THEN
+    REWRITE_TAC[PATHSTART_JOIN] THEN DISCH_THEN MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[PATH_JOIN; PATH_LINEPATH; PATHSTART_LINEPATH] THEN
+    MATCH_MP_TAC SUBSET_PATH_IMAGE_JOIN THEN
+    ASM_REWRITE_TAC[PATH_IMAGE_LINEPATH; SEGMENT_REFL] THEN
+    REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET] THEN
+    ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; SUBSET];
+    ALL_TAC] THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN EXISTS_TAC
+   `((\u. (h:real^(1,1)finite_sum->real^N) (pastecart u (vec 0))) ++
+     linepath(a,a) ++
+     reversepath(\u. h (pastecart u (vec 0))))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC(MESON[HOMOTOPIC_PATHS_LID; HOMOTOPIC_PATHS_JOIN;
+                       HOMOTOPIC_PATHS_TRANS; HOMOTOPIC_PATHS_SYM;
+                       HOMOTOPIC_PATHS_RINV]
+       `(path p /\ path(reversepath p)) /\
+        (path_image p SUBSET s /\ path_image(reversepath p) SUBSET s) /\
+        (pathfinish p = pathstart(linepath(b,b) ++ reversepath p) /\
+         pathstart(reversepath p) = b) /\
+        pathstart p = a
+        ==> homotopic_paths s (p ++ linepath(b,b) ++ reversepath p)
+                              (linepath(a,a))`) THEN
+    REWRITE_TAC[PATHSTART_REVERSEPATH; PATHSTART_JOIN; PATH_REVERSEPATH;
+                PATH_IMAGE_REVERSEPATH; PATHSTART_LINEPATH] THEN
+    ASM_REWRITE_TAC[path; path_image; pathstart; pathfinish;
+                    LINEPATH_REFL] THEN
+    CONJ_TAC THENL
+     [GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_ID;
+               CONTINUOUS_ON_CONST] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+      SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_PASTECART_THM;
+               ENDS_IN_UNIT_INTERVAL];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+          SUBSET_TRANS)) THEN
+      GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM o_DEF] THEN
+      REWRITE_TAC[IMAGE_o] THEN MATCH_MP_TAC IMAGE_SUBSET THEN
+      SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_PASTECART_THM;
+               ENDS_IN_UNIT_INTERVAL]]] THEN
+  REWRITE_TAC[homotopic_paths; homotopic_with; PCROSS] THEN
+  EXISTS_TAC
+   `\y:real^(1,1)finite_sum.
+        (subpath (vec 0) (fstcart y) (\u. h(pastecart u (vec 0))) ++
+         (\u. (h:real^(1,1)finite_sum->real^N) (pastecart (fstcart y) u)) ++
+         subpath (fstcart y) (vec 0) (\u. h(pastecart u (vec 0))))
+        (sndcart y)` THEN
+  ASM_REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; SUBPATH_TRIVIAL;
+                  SUBPATH_REFL; SUBPATH_REVERSEPATH; ETA_AX;
+                  PATHSTART_JOIN; PATHFINISH_JOIN;
+                  PATHSTART_SUBPATH; PATHFINISH_SUBPATH;
+                  PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+  ONCE_REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+   [ALL_TAC; REWRITE_TAC[pathstart]] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC(REWRITE_RULE[PCROSS] HOMOTOPIC_JOIN_LEMMA) THEN
+    REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC(REWRITE_RULE[PCROSS] HOMOTOPIC_JOIN_LEMMA) THEN
+      ASM_REWRITE_TAC[PASTECART_FST_SND; ETA_AX] THEN CONJ_TAC THENL
+       [ALL_TAC;
+        RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+        REWRITE_TAC[PATHSTART_SUBPATH] THEN
+        ASM_SIMP_TAC[pathstart; pathfinish]];
+      RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+      REWRITE_TAC[PATHFINISH_SUBPATH; PATHSTART_JOIN] THEN
+      ASM_SIMP_TAC[pathstart]] THEN
+    REWRITE_TAC[subpath] THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    REWRITE_TAC[VECTOR_SUB_RZERO; VECTOR_SUB_LZERO; VECTOR_ADD_LID] THEN
+    (CONV_TAC o GEN_SIMPLIFY_CONV TOP_DEPTH_SQCONV (basic_ss []) 5)
+       [CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_ADD; CONTINUOUS_ON_MUL;
+        LIFT_DROP; CONTINUOUS_ON_NEG; DROP_NEG; CONTINUOUS_ON_CONST;
+        CONTINUOUS_ON_ID; LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART;
+        LIFT_NEG; o_DEF; ETA_AX] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       CONTINUOUS_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[IN_ELIM_PASTECART_THM] THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; IN_INTERVAL_1] THEN
+    REWRITE_TAC[DROP_ADD; DROP_NEG; DROP_VEC; DROP_CMUL; REAL_POS] THEN
+    SIMP_TAC[REAL_LE_MUL; REAL_SUB_LE; REAL_ARITH
+     `t + --t * x = t * (&1 - x)`] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `t * x <= t * &1 /\ &1 * t <= &1 * &1 ==> t * x <= &1`) THEN
+    CONJ_TAC THEN MATCH_MP_TAC REAL_LE_LMUL THEN ASM_REAL_ARITH_TAC;
+
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC; IMP_CONJ;
+      RIGHT_FORALL_IMP_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    X_GEN_TAC `t:real^1` THEN STRIP_TAC THEN
+    REWRITE_TAC[SET_RULE
+     `(!x. x IN s ==> f x IN t) <=> IMAGE f s SUBSET t`] THEN
+    REWRITE_TAC[GSYM path_image; ETA_AX] THEN
+    REPEAT(MATCH_MP_TAC SUBSET_PATH_IMAGE_JOIN THEN CONJ_TAC) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+      SUBSET_TRANS)) THEN
+    REWRITE_TAC[path_image; subpath] THEN
+    GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM o_DEF] THEN
+    REWRITE_TAC[IMAGE_o] THEN MATCH_MP_TAC IMAGE_SUBSET THEN
+    ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_PASTECART_THM] THEN
+    SIMP_TAC[IN_INTERVAL_1; DROP_SUB; DROP_VEC; DROP_CMUL; DROP_ADD] THEN
+    REWRITE_TAC[REAL_ADD_LID; REAL_SUB_RZERO; REAL_POS] THEN
+    REWRITE_TAC[REAL_ARITH `t + (&0 - t) * x = t * (&1 - x)`] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; REAL_SUB_LE] THEN
+    REPEAT STRIP_TAC THEN
+    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN ASM_REAL_ARITH_TAC]);;
+
+let HOMOTOPIC_LOOPS_CONJUGATE = prove
+ (`!p q s:real^N->bool.
+        path p /\ path_image p SUBSET s /\
+        path q /\ path_image q SUBSET s /\
+        pathfinish p = pathstart q /\ pathfinish q = pathstart q
+        ==> homotopic_loops s (p ++ q ++ reversepath p) q`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMOTOPIC_LOOPS_TRANS THEN EXISTS_TAC
+   `linepath(pathstart q,pathstart q) ++ (q:real^1->real^N) ++
+    linepath(pathstart q,pathstart q)` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC HOMOTOPIC_PATHS_IMP_HOMOTOPIC_LOOPS THEN
+    MP_TAC(ISPECL [`s:real^N->bool`;
+       `(q:real^1->real^N) ++ linepath(pathfinish q,pathfinish q)`]
+     HOMOTOPIC_PATHS_LID) THEN
+    ASM_SIMP_TAC[PATHSTART_JOIN; PATHFINISH_JOIN; UNION_SUBSET; SING_SUBSET;
+                 PATHSTART_LINEPATH; PATHFINISH_LINEPATH; PATH_IMAGE_LINEPATH;
+                 PATH_JOIN; PATH_IMAGE_JOIN; PATH_LINEPATH; SEGMENT_REFL] THEN
+    ANTS_TAC THENL
+     [ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; SUBSET]; ALL_TAC] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_PATHS_TRANS) THEN
+    ASM_MESON_TAC[HOMOTOPIC_PATHS_RID]] THEN
+  REWRITE_TAC[homotopic_loops; homotopic_with; PCROSS] THEN
+  EXISTS_TAC
+   `(\y. (subpath (fstcart y) (vec 1) p ++ q ++ subpath (vec 1) (fstcart y) p)
+         (sndcart y)):real^(1,1)finite_sum->real^N` THEN
+  ASM_REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; SUBPATH_TRIVIAL;
+                  SUBPATH_REFL; SUBPATH_REVERSEPATH; ETA_AX;
+                 PATHSTART_JOIN; PATHFINISH_JOIN;
+                  PATHSTART_SUBPATH; PATHFINISH_SUBPATH;
+                  PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+  ASM_REWRITE_TAC[pathstart; pathfinish] THEN CONJ_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[path; path_image]) THEN
+    MATCH_MP_TAC(REWRITE_RULE[PCROSS] HOMOTOPIC_JOIN_LEMMA) THEN
+    REPEAT CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC(REWRITE_RULE[PCROSS] HOMOTOPIC_JOIN_LEMMA) THEN
+      REPEAT CONJ_TAC THENL
+       [GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+        SIMP_TAC[SNDCART_PASTECART];
+        ALL_TAC;
+        REWRITE_TAC[PATHSTART_SUBPATH] THEN ASM_REWRITE_TAC[pathfinish]];
+      REWRITE_TAC[PATHSTART_JOIN; PATHFINISH_SUBPATH] THEN
+      ASM_REWRITE_TAC[pathstart]] THEN
+    REWRITE_TAC[subpath] THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    (CONJ_TAC THENL
+      [REWRITE_TAC[DROP_SUB] THEN MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
+       SIMP_TAC[LINEAR_CONTINUOUS_ON; CONTINUOUS_ON_CONST; LINEAR_FSTCART] THEN
+       MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+       SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+       REWRITE_TAC[o_DEF; LIFT_SUB; LIFT_DROP] THEN
+       SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; LINEAR_CONTINUOUS_ON;
+                LINEAR_FSTCART];
+       FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+       REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+       REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; IN_INTERVAL_1] THEN
+       REWRITE_TAC[DROP_ADD; DROP_SUB; DROP_VEC; DROP_CMUL]])
+    THENL
+     [REPEAT STRIP_TAC THENL
+       [MATCH_MP_TAC REAL_LE_ADD THEN CONJ_TAC THEN
+        TRY(MATCH_MP_TAC REAL_LE_MUL) THEN ASM_REAL_ARITH_TAC;
+        REWRITE_TAC[REAL_ARITH `t + (&1 - t) * x <= &1 <=>
+                                (&1 - t) * x <= (&1 - t) * &1`] THEN
+        MATCH_MP_TAC REAL_LE_LMUL THEN ASM_REAL_ARITH_TAC];
+      REPEAT STRIP_TAC THENL
+       [MATCH_MP_TAC(REAL_ARITH
+         `x * (&1 - t) <= x * &1 /\ x <= &1
+          ==> &0 <= &1 + (t - &1) * x`) THEN
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
+        ASM_REAL_ARITH_TAC;
+        REWRITE_TAC[REAL_ARITH
+         `a + (t - &1) * x <= a <=> &0 <= (&1 - t) * x`] THEN
+        MATCH_MP_TAC REAL_LE_MUL THEN ASM_REAL_ARITH_TAC]];
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[ETA_AX; GSYM path_image; SET_RULE
+      `(!x. x IN i ==> f x IN s) <=> IMAGE f i SUBSET s`] THEN
+    REPEAT STRIP_TAC THEN
+    REPEAT(MATCH_MP_TAC SUBSET_PATH_IMAGE_JOIN THEN CONJ_TAC) THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `path_image p:real^N->bool` THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC PATH_IMAGE_SUBPATH_SUBSET THEN
+    ASM_REWRITE_TAC[ENDS_IN_UNIT_INTERVAL]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relating homotopy of trivial loops to path-connectedness.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_COMPONENT_IMP_HOMOTOPIC_POINTS = prove
+ (`!s a b:real^N.
+        path_component s a b
+        ==> homotopic_loops s (linepath(a,a)) (linepath(b,b))`,
+  REWRITE_TAC[path_component; homotopic_loops; homotopic_with; PCROSS] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[pathstart; pathfinish; path_image; path] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\y:real^(1,1)finite_sum. (g(fstcart y):real^N)` THEN
+  ASM_SIMP_TAC[FSTCART_PASTECART; linepath] THEN
+  REWRITE_TAC[VECTOR_ARITH `(&1 - x) % a + x % a:real^N = a`] THEN
+  MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_COMPOSE) THEN
+  SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+  SIMP_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC; FSTCART_PASTECART]);;
+
+let HOMOTOPIC_LOOPS_IMP_PATH_COMPONENT_VALUE = prove
+ (`!s p q:real^1->real^N t.
+        homotopic_loops s p q /\ t IN interval[vec 0,vec 1]
+        ==> path_component s (p t) (q t)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[path_component; homotopic_loops; homotopic_with; PCROSS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^(1,1)finite_sum->real^N` MP_TAC) THEN
+  STRIP_TAC THEN
+  EXISTS_TAC `\u. (h:real^(1,1)finite_sum->real^N) (pastecart u t)` THEN
+  ASM_REWRITE_TAC[pathstart; pathfinish] THEN CONJ_TAC THENL
+   [REWRITE_TAC[path] THEN
+    MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_COMPOSE) THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+      REWRITE_TAC[CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+      ASM SET_TAC[]];
+    REWRITE_TAC[path_image] THEN ASM SET_TAC[]]);;
+
+let HOMOTOPIC_POINTS_EQ_PATH_COMPONENT = prove
+ (`!s a b:real^N.
+        homotopic_loops s (linepath(a,a)) (linepath(b,b)) <=>
+        path_component s a b`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  REWRITE_TAC[PATH_COMPONENT_IMP_HOMOTOPIC_POINTS] THEN
+  DISCH_THEN(MP_TAC o SPEC `vec 0:real^1` o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+    HOMOTOPIC_LOOPS_IMP_PATH_COMPONENT_VALUE)) THEN
+  REWRITE_TAC[linepath; IN_INTERVAL_1; DROP_VEC; REAL_POS] THEN
+  REWRITE_TAC[VECTOR_ARITH `(&1 - &0) % a + &0 % b:real^N = a`]);;
+
+let PATH_CONNECTED_EQ_HOMOTOPIC_POINTS = prove
+ (`!s:real^N->bool.
+        path_connected s <=>
+        !a b. a IN s /\ b IN s
+              ==> homotopic_loops s (linepath(a,a)) (linepath(b,b))`,
+  GEN_TAC THEN REWRITE_TAC[HOMOTOPIC_POINTS_EQ_PATH_COMPONENT] THEN
+  REWRITE_TAC[path_connected; path_component]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homotopy of "nearby" function, paths and loops.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPIC_WITH_LINEAR = prove
+ (`!f g:real^M->real^N s t.
+        f continuous_on s /\ g continuous_on s /\
+        (!x. x IN s ==> segment[f x,g x] SUBSET t)
+        ==> homotopic_with (\z. T) (s,t) f g`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[homotopic_with] THEN
+  EXISTS_TAC
+    `\y. ((&1 - drop(fstcart y)) % (f:real^M->real^N)(sndcart y) +
+         drop(fstcart y) % g(sndcart y):real^N)` THEN
+  REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; DROP_VEC] THEN
+  ASM_REWRITE_TAC[REAL_SUB_REFL; REAL_SUB_RZERO] THEN
+  REWRITE_TAC[VECTOR_ARITH `(&1 - t) % a + t % a:real^N = a`] THEN
+  REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_MUL_LID] THEN
+  REWRITE_TAC[VECTOR_ADD_LID; VECTOR_ADD_RID] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN CONJ_TAC THEN
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+    REWRITE_TAC[o_DEF; LIFT_DROP; LIFT_SUB] THEN
+    SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; LINEAR_CONTINUOUS_ON;
+             LINEAR_FSTCART; ETA_AX] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    SIMP_TAC[SNDCART_PASTECART; FORALL_IN_PCROSS];
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+    MAP_EVERY X_GEN_TAC [`t:real^1`; `u:real^M`] THEN STRIP_TAC THEN
+    SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; RIGHT_IMP_FORALL_THM; IMP_IMP]) THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN EXISTS_TAC `u:real^M` THEN
+    ASM_REWRITE_TAC[IN_SEGMENT] THEN EXISTS_TAC `drop t` THEN
+    ASM_MESON_TAC[IN_INTERVAL_1; DROP_VEC]]);;
+
+let HOMOTOPIC_PATHS_LINEAR,HOMOTOPIC_LOOPS_LINEAR = (CONJ_PAIR o prove)
+ (`(!g s:real^N->bool h.
+        path g /\ path h /\
+        pathstart h = pathstart g /\ pathfinish h = pathfinish g /\
+        (!t x. t IN interval[vec 0,vec 1] ==> segment[g t,h t] SUBSET s)
+        ==> homotopic_paths s g h) /\
+   (!g s:real^N->bool h.
+        path g /\ path h /\
+        pathfinish g = pathstart g /\ pathfinish h = pathstart h /\
+        (!t x. t IN interval[vec 0,vec 1] ==> segment[g t,h t] SUBSET s)
+        ==> homotopic_loops s g h)`,
+  CONJ_TAC THEN
+ (REWRITE_TAC[pathstart; pathfinish] THEN
+  REWRITE_TAC[SUBSET; RIGHT_IMP_FORALL_THM; IMP_IMP] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[homotopic_paths; homotopic_loops; homotopic_with; PCROSS] THEN
+  EXISTS_TAC
+   `\y:real^(1,1)finite_sum.
+      ((&1 - drop(fstcart y)) % g(sndcart y) +
+       drop(fstcart y) % h(sndcart y):real^N)` THEN
+  REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; DROP_VEC] THEN
+  ASM_REWRITE_TAC[pathstart; pathfinish; REAL_SUB_REFL; REAL_SUB_RZERO] THEN
+  REWRITE_TAC[VECTOR_ARITH `(&1 - t) % a + t % a:real^N = a`] THEN
+  REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_MUL_LID] THEN
+  REWRITE_TAC[VECTOR_ADD_LID; VECTOR_ADD_RID] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN CONJ_TAC THEN
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+    REWRITE_TAC[o_DEF; LIFT_DROP; LIFT_SUB] THEN
+    SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; LINEAR_CONTINUOUS_ON;
+             LINEAR_FSTCART; ETA_AX] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[path]) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    SIMP_TAC[SNDCART_PASTECART];
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    MAP_EVERY X_GEN_TAC [`t:real^1`; `u:real^1`] THEN STRIP_TAC THEN
+    SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN EXISTS_TAC `u:real^1` THEN
+    ASM_REWRITE_TAC[IN_SEGMENT] THEN EXISTS_TAC `drop t` THEN
+    ASM_MESON_TAC[IN_INTERVAL_1; DROP_VEC]]));;
+
+let HOMOTOPIC_PATHS_NEARBY_EXPLICIT,
+    HOMOTOPIC_LOOPS_NEARBY_EXPLICIT = (CONJ_PAIR o prove)
+ (`(!g s:real^N->bool h.
+        path g /\ path h /\
+        pathstart h = pathstart g /\ pathfinish h = pathfinish g /\
+        (!t x. t IN interval[vec 0,vec 1] /\ ~(x IN s)
+               ==> norm(h t - g t) < norm(g t - x))
+        ==> homotopic_paths s g h) /\
+   (!g s:real^N->bool h.
+        path g /\ path h /\
+        pathfinish g = pathstart g /\ pathfinish h = pathstart h /\
+        (!t x. t IN interval[vec 0,vec 1] /\ ~(x IN s)
+               ==> norm(h t - g t) < norm(g t - x))
+        ==> homotopic_loops s g h)`,
+  ONCE_REWRITE_TAC[TAUT `p /\ ~q ==> r <=> p /\ ~r ==> q`] THEN
+  REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC HOMOTOPIC_PATHS_LINEAR;
+    MATCH_MP_TAC HOMOTOPIC_LOOPS_LINEAR] THEN
+  ASM_REWRITE_TAC[] THEN REWRITE_TAC[SUBSET; segment; FORALL_IN_GSPEC] THEN
+  X_GEN_TAC `t:real^1` THEN STRIP_TAC THEN
+  X_GEN_TAC `u:real` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN EXISTS_TAC `t:real^1` THEN
+  ASM_REWRITE_TAC[REAL_NOT_LT] THEN
+  MP_TAC(ISPECL [`(g:real^1->real^N) t`; `(h:real^1->real^N) t`]
+      DIST_IN_CLOSED_SEGMENT) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+  REWRITE_TAC[segment; FORALL_IN_GSPEC;
+              ONCE_REWRITE_RULE[DIST_SYM] dist] THEN
+  ASM_MESON_TAC[]);;
+
+let HOMOTOPIC_NEARBY_PATHS,HOMOTOPIC_NEARBY_LOOPS = (CONJ_PAIR o prove)
+ (`(!g s:real^N->bool.
+        path g /\ open s /\ path_image g SUBSET s
+        ==> ?e. &0 < e /\
+                !h. path h /\
+                    pathstart h = pathstart g /\
+                    pathfinish h = pathfinish g /\
+                    (!t. t IN interval[vec 0,vec 1] ==> norm(h t - g t) < e)
+                    ==> homotopic_paths s g h) /\
+   (!g s:real^N->bool.
+        path g /\ pathfinish g = pathstart g /\ open s /\ path_image g SUBSET s
+        ==> ?e. &0 < e /\
+                !h. path h /\
+                    pathfinish h = pathstart h /\
+                    (!t. t IN interval[vec 0,vec 1] ==> norm(h t - g t) < e)
+                    ==> homotopic_loops s g h)`,
+  CONJ_TAC THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`path_image g:real^N->bool`; `(:real^N) DIFF s`]
+        SEPARATE_COMPACT_CLOSED) THEN
+  ASM_SIMP_TAC[COMPACT_PATH_IMAGE; GSYM OPEN_CLOSED] THEN
+  (ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[IN_DIFF; IN_UNIV; dist]]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN
+  REWRITE_TAC[REAL_NOT_LE] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `h:real^1->real^N` THEN STRIP_TAC THENL
+   [MATCH_MP_TAC HOMOTOPIC_PATHS_NEARBY_EXPLICIT;
+    MATCH_MP_TAC HOMOTOPIC_LOOPS_NEARBY_EXPLICIT] THEN
+  ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`t:real^1`; `x:real^N`] THEN STRIP_TAC THEN
+  MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `e:real` THEN
+  ASM_SIMP_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[path_image] THEN ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homotopy of non-antipodal sphere maps.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPIC_NON_MIDPOINT_SPHEREMAPS = prove
+ (`!f g:real^M->real^N s a r.
+        f continuous_on s /\ IMAGE f s SUBSET sphere(a,r) /\
+        g continuous_on s /\ IMAGE g s SUBSET sphere(a,r) /\
+        (!x. x IN s ==> ~(midpoint(f x,g x) = a))
+    ==> homotopic_with (\x. T) (s,sphere(a,r)) f g`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `r <= &0` THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMOTOPIC_WITH_EQ THEN
+    REPEAT(EXISTS_TAC `g:real^M->real^N`) THEN
+    ASM_REWRITE_TAC[HOMOTOPIC_WITH_REFL] THEN
+    SUBGOAL_THEN `?c:real^N. sphere(a,r) SUBSET {c}` MP_TAC THENL
+     [ALL_TAC; ASM SET_TAC[]] THEN
+    ASM_CASES_TAC `r = &0` THEN
+    ASM_SIMP_TAC[SPHERE_SING; SPHERE_EMPTY; REAL_LT_LE] THEN
+    MESON_TAC[SUBSET_REFL; EMPTY_SUBSET];
+    RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LE]) THEN STRIP_TAC] THEN
+  SUBGOAL_THEN
+   `homotopic_with (\z. T) (s:real^M->bool,(:real^N) DELETE a) f g`
+  MP_TAC THENL
+   [MATCH_MP_TAC HOMOTOPIC_WITH_LINEAR THEN
+    ASM_REWRITE_TAC[SET_RULE `s SUBSET UNIV DELETE a <=> ~(a IN s)`] THEN
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET])) THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; IN_SPHERE; IMP_IMP] THEN
+    REWRITE_TAC[AND_FORALL_THM] THEN DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN
+    FIRST_X_ASSUM(MP_TAC o GSYM o SPEC `x:real^M`) THEN
+    ASM_REWRITE_TAC[GSYM BETWEEN_IN_SEGMENT; MIDPOINT_BETWEEN] THEN
+    MESON_TAC[DIST_SYM];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o
+    ISPECL [`\y:real^N. a + r / norm(y - a) % (y - a)`;
+            `sphere(a:real^N,r)`] o
+    MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+    HOMOTOPIC_COMPOSE_CONTINUOUS_LEFT)) THEN
+  REWRITE_TAC[o_DEF] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+      SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+      REWRITE_TAC[real_div; o_DEF; LIFT_CMUL] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_CMUL THEN
+      MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
+      SIMP_TAC[IN_DELETE; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_LIFT_NORM_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID];
+      SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_UNIV; IN_DELETE; IN_SPHERE] THEN
+      REWRITE_TAC[NORM_ARITH `dist(a:real^N,a + b) = norm b`] THEN
+      SIMP_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM] THEN
+      ASM_SIMP_TAC[real_abs; REAL_LE_RMUL; REAL_DIV_RMUL;
+                   NORM_EQ_0; VECTOR_SUB_EQ; REAL_LT_IMP_LE]];
+      MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_EQ) THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; FORALL_IN_IMAGE; IN_SPHERE]) THEN
+      ASM_SIMP_TAC[NORM_ARITH `norm(a - b:real^N) = dist(b,a)`] THEN
+      ASM_SIMP_TAC[REAL_DIV_REFL; REAL_LT_IMP_NZ] THEN REPEAT STRIP_TAC THEN
+      VECTOR_ARITH_TAC]);;
+
+let HOMOTOPIC_NON_ANTIPODAL_SPHEREMAPS = prove
+ (`!f g:real^M->real^N s r.
+        f continuous_on s /\ IMAGE f s SUBSET sphere(vec 0,r) /\
+        g continuous_on s /\ IMAGE g s SUBSET sphere(vec 0,r) /\
+        (!x. x IN s ==> ~(f x = --g x))
+    ==> homotopic_with (\x. T) (s,sphere(vec 0,r)) f g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMOTOPIC_NON_MIDPOINT_SPHEREMAPS THEN
+  ASM_REWRITE_TAC[midpoint; VECTOR_ARITH
+   `inv(&2) % (a + b):real^N = vec 0 <=> a = --b`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Retracts, in a general sense, preserve (co)homotopic triviality.          *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPICALLY_TRIVIAL_RETRACTION_GEN = prove
+ (`!P Q s:real^M->bool t:real^N->bool u:real^P->bool h k.
+        (h continuous_on s /\ IMAGE h s = t /\
+         k continuous_on t /\ IMAGE k t SUBSET s /\
+         (!y. y IN t ==> h(k y) = y) /\
+         (!f. f continuous_on u /\ IMAGE f u SUBSET t /\ Q f ==> P(k o f)) /\
+         (!f. f continuous_on u /\ IMAGE f u SUBSET s /\ P f ==> Q(h o f)) /\
+         (!h k. (!x. x IN u ==> h x = k x) ==> (Q h <=> Q k))) /\
+        (!f g. f continuous_on u /\ IMAGE f u SUBSET s /\ P f /\
+               g continuous_on u /\ IMAGE g u SUBSET s /\ P g
+               ==> homotopic_with P (u,s)  f g)
+        ==> (!f g. f continuous_on u /\ IMAGE f u SUBSET t /\ Q f /\
+                   g continuous_on u /\ IMAGE g u SUBSET t /\ Q g
+                   ==> homotopic_with Q (u,t) f g)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`p:real^P->real^N`; `q:real^P->real^N`] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+   [`(k:real^N->real^M) o (p:real^P->real^N)`;
+    `(k:real^N->real^M) o (q:real^P->real^N)`]) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[IMAGE_o] THEN REPEAT CONJ_TAC THEN
+    TRY(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE) THEN ASM_REWRITE_TAC[] THEN
+    TRY(FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET))) THEN
+    ASM SET_TAC[];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_EQ THEN MAP_EVERY EXISTS_TAC
+   [`(h:real^M->real^N) o (k:real^N->real^M) o (p:real^P->real^N)`;
+    `(h:real^M->real^N) o (k:real^N->real^M) o (q:real^P->real^N)`] THEN
+  ASM_REWRITE_TAC[o_THM] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[SUBSET_REFL] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        HOMOTOPIC_WITH_MONO)) THEN
+  ASM_SIMP_TAC[]);;
+
+let HOMOTOPICALLY_TRIVIAL_RETRACTION_NULL_GEN = prove
+ (`!P Q s:real^M->bool t:real^N->bool u:real^P->bool h k.
+        (h continuous_on s /\ IMAGE h s = t /\
+         k continuous_on t /\ IMAGE k t SUBSET s /\
+         (!y. y IN t ==> h(k y) = y) /\
+         (!f. f continuous_on u /\ IMAGE f u SUBSET t /\ Q f ==> P(k o f)) /\
+         (!f. f continuous_on u /\ IMAGE f u SUBSET s /\ P f ==> Q(h o f)) /\
+         (!h k. (!x. x IN u ==> h x = k x) ==> (Q h <=> Q k))) /\
+        (!f. f continuous_on u /\ IMAGE f u SUBSET s /\ P f
+             ==> ?c. homotopic_with P (u,s) f (\x. c))
+        ==> (!f. f continuous_on u /\ IMAGE f u SUBSET t /\ Q f
+                 ==> ?c. homotopic_with Q (u,t) f (\x. c))`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN X_GEN_TAC `p:real^P->real^N` THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC
+    `(k:real^N->real^M) o (p:real^P->real^N)`) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[IMAGE_o] THEN CONJ_TAC THEN
+    TRY(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE) THEN ASM_REWRITE_TAC[] THEN
+    TRY(FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET))) THEN
+    ASM SET_TAC[];
+    DISCH_THEN(X_CHOOSE_TAC `c:real^M`)] THEN
+  EXISTS_TAC `(h:real^M->real^N) c` THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_EQ THEN MAP_EVERY EXISTS_TAC
+   [`(h:real^M->real^N) o (k:real^N->real^M) o (p:real^P->real^N)`;
+    `(h:real^M->real^N) o ((\x. c):real^P->real^M)`] THEN
+  ASM_REWRITE_TAC[o_THM] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[SUBSET_REFL] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        HOMOTOPIC_WITH_MONO)) THEN
+  ASM_SIMP_TAC[]);;
+
+let COHOMOTOPICALLY_TRIVIAL_RETRACTION_GEN = prove
+ (`!P Q s:real^M->bool t:real^N->bool u:real^P->bool h k.
+        (h continuous_on s /\ IMAGE h s = t /\
+         k continuous_on t /\ IMAGE k t SUBSET s /\
+         (!y. y IN t ==> h(k y) = y) /\
+         (!f. f continuous_on t /\ IMAGE f t SUBSET u /\ Q f ==> P(f o h)) /\
+         (!f. f continuous_on s /\ IMAGE f s SUBSET u /\ P f ==> Q(f o k)) /\
+         (!h k. (!x. x IN t ==> h x = k x) ==> (Q h <=> Q k))) /\
+        (!f g. f continuous_on s /\ IMAGE f s SUBSET u /\ P f /\
+               g continuous_on s /\ IMAGE g s SUBSET u /\ P g
+               ==> homotopic_with P (s,u) f g)
+        ==> (!f g. f continuous_on t /\ IMAGE f t SUBSET u /\ Q f /\
+                   g continuous_on t /\ IMAGE g t SUBSET u /\ Q g
+                   ==> homotopic_with Q (t,u) f g)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`p:real^N->real^P`; `q:real^N->real^P`] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+   [`(p:real^N->real^P) o (h:real^M->real^N)`;
+    `(q:real^N->real^P) o (h:real^M->real^N)`]) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[IMAGE_o] THEN REPEAT CONJ_TAC THEN
+    TRY(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE) THEN ASM_REWRITE_TAC[] THEN
+    TRY(FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET))) THEN
+    ASM SET_TAC[];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_EQ THEN MAP_EVERY EXISTS_TAC
+   [`((p:real^N->real^P) o (h:real^M->real^N)) o (k:real^N->real^M)`;
+    `((q:real^N->real^P) o (h:real^M->real^N)) o (k:real^N->real^M)`] THEN
+  ASM_REWRITE_TAC[o_THM] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[SUBSET_REFL] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        HOMOTOPIC_WITH_MONO)) THEN
+  ASM_SIMP_TAC[]);;
+
+let COHOMOTOPICALLY_TRIVIAL_RETRACTION_NULL_GEN = prove
+ (`!P Q s:real^M->bool t:real^N->bool u:real^P->bool h k.
+        (h continuous_on s /\ IMAGE h s = t /\
+         k continuous_on t /\ IMAGE k t SUBSET s /\
+         (!y. y IN t ==> h(k y) = y) /\
+         (!f. f continuous_on t /\ IMAGE f t SUBSET u /\ Q f ==> P(f o h)) /\
+         (!f. f continuous_on s /\ IMAGE f s SUBSET u /\ P f ==> Q(f o k)) /\
+         (!h k. (!x. x IN t ==> h x = k x) ==> (Q h <=> Q k))) /\
+        (!f. f continuous_on s /\ IMAGE f s SUBSET u /\ P f
+             ==> ?c. homotopic_with P (s,u) f (\x. c))
+        ==> (!f. f continuous_on t /\ IMAGE f t SUBSET u /\ Q f
+                 ==> ?c. homotopic_with Q (t,u) f (\x. c))`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN X_GEN_TAC `p:real^N->real^P` THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC
+    `(p:real^N->real^P) o (h:real^M->real^N)`) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[IMAGE_o] THEN
+    TRY(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE) THEN ASM_REWRITE_TAC[] THEN
+    TRY(FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET))) THEN
+    ASM SET_TAC[];
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^P` THEN DISCH_TAC] THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_EQ THEN MAP_EVERY EXISTS_TAC
+   [`((p:real^N->real^P) o (h:real^M->real^N)) o (k:real^N->real^M)`;
+    `((\x. c):real^M->real^P) o (k:real^N->real^M)`] THEN
+  ASM_REWRITE_TAC[o_THM] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[SUBSET_REFL] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        HOMOTOPIC_WITH_MONO)) THEN
+  ASM_SIMP_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Another useful lemma.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPIC_JOIN_SUBPATHS = prove
+ (`!g:real^1->real^N s.
+       path g /\ path_image g SUBSET s /\
+       u IN interval[vec 0,vec 1] /\
+       v IN interval[vec 0,vec 1] /\
+       w IN interval[vec 0,vec 1]
+       ==> homotopic_paths s (subpath u v g ++ subpath v w g) (subpath u w g)`,
+  let lemma1 = prove
+   (`!g:real^1->real^N s.
+         drop u <= drop v /\ drop v <= drop w
+         ==> path g /\ path_image g SUBSET s /\
+             u IN interval[vec 0,vec 1] /\
+             v IN interval[vec 0,vec 1] /\
+             w IN interval[vec 0,vec 1] /\
+             drop u <= drop v /\ drop v <= drop w
+             ==> homotopic_paths s
+                 (subpath u v g ++ subpath v w g) (subpath u w g)`,
+    REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_SUBSET THEN
+    EXISTS_TAC `path_image g:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+    ASM_CASES_TAC `w:real^1 = u` THENL
+     [MP_TAC(ISPECL
+      [`path_image g:real^N->bool`;
+       `subpath u v (g:real^1->real^N)`] HOMOTOPIC_PATHS_RINV) THEN
+      ASM_REWRITE_TAC[REVERSEPATH_SUBPATH; SUBPATH_REFL] THEN
+      REWRITE_TAC[LINEPATH_REFL; PATHSTART_SUBPATH] THEN
+      ASM_SIMP_TAC[PATH_SUBPATH; PATH_IMAGE_SUBPATH_SUBSET];
+      ALL_TAC] THEN
+    ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_REPARAMETRIZE THEN
+    ASM_SIMP_TAC[PATH_SUBPATH; PATH_IMAGE_SUBPATH_SUBSET] THEN
+    EXISTS_TAC
+    `\t. if drop t <= &1 / &2
+         then inv(drop(w - u)) % (&2 * drop(v - u)) % t
+         else inv(drop(w - u)) %
+              ((v - u) + drop(w - v) % (&2 % t - vec 1))` THEN
+    REWRITE_TAC[DROP_VEC] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[VECTOR_MUL_RZERO] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_CASES_1 THEN
+      REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; LIFT_DROP; GSYM LIFT_NUM;
+                  DROP_ADD; DROP_SUB] THEN
+      (CONV_TAC o GEN_SIMPLIFY_CONV TOP_DEPTH_SQCONV (basic_ss []) 5)
+        [CONTINUOUS_ON_MUL; o_DEF; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID;
+         CONTINUOUS_ON_SUB; CONTINUOUS_ON_ADD] THEN
+      REPEAT STRIP_TAC THEN REAL_ARITH_TAC;
+      SUBGOAL_THEN `drop u < drop w` ASSUME_TAC THENL
+       [ASM_SIMP_TAC[REAL_LT_LE; DROP_EQ] THEN ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+      X_GEN_TAC `t:real^1` THEN STRIP_TAC THEN COND_CASES_TAC THEN
+      REWRITE_TAC[IN_INTERVAL_1; DROP_CMUL; DROP_VEC; DROP_ADD; DROP_SUB] THEN
+      ONCE_REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] (GSYM real_div)] THEN
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; REAL_SUB_LT] THEN
+      REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+      (CONJ_TAC THENL
+        [REPEAT(MATCH_MP_TAC REAL_LE_ADD THEN CONJ_TAC) THEN
+         REPEAT(MATCH_MP_TAC REAL_LE_MUL THEN CONJ_TAC) THEN
+         ASM_REAL_ARITH_TAC;
+         ALL_TAC]) THEN
+      REWRITE_TAC[REAL_ARITH `v - u + x * t <= w - u <=> x * t <= w - v`;
+                  REAL_ARITH `(&2 * x) * t = x * &2 * t`] THEN
+      MATCH_MP_TAC(REAL_ARITH `a * t <= a * &1 /\ a <= b ==> a * t <= b`) THEN
+      (CONJ_TAC THENL [MATCH_MP_TAC REAL_LE_LMUL; ALL_TAC]) THEN
+      ASM_REAL_ARITH_TAC;
+      REWRITE_TAC[GSYM DROP_EQ; DROP_VEC; DROP_ADD; DROP_CMUL; DROP_SUB] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      REWRITE_TAC[REAL_ARITH `(v - u) + (w - v) * &1 = w - u`] THEN
+      ASM_SIMP_TAC[REAL_SUB_0; DROP_EQ; REAL_MUL_LINV];
+      X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+      REWRITE_TAC[subpath; joinpaths] THEN COND_CASES_TAC THEN
+      ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_ASSOC] THEN
+      ASM_SIMP_TAC[REAL_MUL_RINV; DROP_EQ_0; VECTOR_SUB_EQ] THEN
+      AP_TERM_TAC THEN
+      REWRITE_TAC[GSYM DROP_EQ; DROP_VEC; DROP_ADD; DROP_CMUL; DROP_SUB] THEN
+      REAL_ARITH_TAC]) in
+  let lemma2 = prove
+   (`path g /\ path_image g SUBSET s /\
+     u IN interval[vec 0,vec 1] /\
+     v IN interval[vec 0,vec 1] /\
+     w IN interval[vec 0,vec 1] /\
+     homotopic_paths s (subpath u v g ++ subpath v w g) (subpath u w g)
+     ==> homotopic_paths s (subpath w v g ++ subpath v u g) (subpath w u g)`,
+    REPEAT STRIP_TAC THEN
+    ONCE_REWRITE_TAC[GSYM HOMOTOPIC_PATHS_REVERSEPATH] THEN
+    SIMP_TAC[REVERSEPATH_JOINPATHS; PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+    ASM_REWRITE_TAC[REVERSEPATH_SUBPATH]) in
+  let lemma3 = prove
+   (`path (g:real^1->real^N) /\ path_image g SUBSET s /\
+     u IN interval[vec 0,vec 1] /\
+     v IN interval[vec 0,vec 1] /\
+     w IN interval[vec 0,vec 1] /\
+     homotopic_paths s (subpath u v g ++ subpath v w g) (subpath u w g)
+     ==> homotopic_paths s (subpath v w g ++ subpath w u g) (subpath v u g)`,
+    let tac =
+      ASM_MESON_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH; PATH_SUBPATH;
+                 HOMOTOPIC_PATHS_REFL; PATH_IMAGE_SUBPATH_SUBSET; SUBSET_TRANS;
+                 PATHSTART_JOIN; PATHFINISH_JOIN] in
+    REPEAT STRIP_TAC THEN
+    ONCE_REWRITE_TAC[GSYM HOMOTOPIC_PATHS_REVERSEPATH] THEN
+    SIMP_TAC[REVERSEPATH_JOINPATHS; PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+    ASM_REWRITE_TAC[REVERSEPATH_SUBPATH] THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+    EXISTS_TAC
+     `(subpath u v g ++ subpath v w g) ++ subpath w v g:real^1->real^N` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC HOMOTOPIC_PATHS_JOIN THEN
+      ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+      ASM_REWRITE_TAC[HOMOTOPIC_PATHS_REFL] THEN tac;
+      ALL_TAC] THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+    EXISTS_TAC
+     `subpath u v g ++ (subpath v w g ++ subpath w v g):real^1->real^N` THEN
+    CONJ_TAC THENL
+     [ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+      MATCH_MP_TAC HOMOTOPIC_PATHS_ASSOC THEN tac;
+      ALL_TAC] THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+    EXISTS_TAC
+     `(subpath u v g :real^1->real^N) ++
+      linepath(pathfinish(subpath u v g),pathfinish(subpath u v g))` THEN
+    CONJ_TAC THENL [ALL_TAC; MATCH_MP_TAC HOMOTOPIC_PATHS_RID THEN tac] THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_JOIN THEN
+    REPEAT CONJ_TAC THENL [tac; ALL_TAC; tac] THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+    EXISTS_TAC
+     `linepath(pathstart(subpath v w g):real^N,pathstart(subpath v w g))` THEN
+    CONJ_TAC THENL
+     [GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM REVERSEPATH_SUBPATH] THEN
+      MATCH_MP_TAC HOMOTOPIC_PATHS_RINV THEN tac;
+      ALL_TAC] THEN
+    REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH; HOMOTOPIC_PATHS_REFL;
+                PATH_LINEPATH; PATH_IMAGE_LINEPATH; SEGMENT_REFL;
+                INSERT_SUBSET; EMPTY_SUBSET] THEN
+    ASM_MESON_TAC[path_image; IN_IMAGE; SUBSET]) in
+  REPEAT STRIP_TAC THEN
+  REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
+     (REAL_ARITH `(drop u <= drop v /\ drop v <= drop w \/
+                   drop w <= drop v /\ drop v <= drop u) \/
+                  (drop u <= drop w /\ drop w <= drop v \/
+                   drop v <= drop w /\ drop w <= drop u) \/
+                  (drop v <= drop u /\ drop u <= drop w \/
+                   drop w <= drop u /\ drop u <= drop v)`) THEN
+  FIRST_ASSUM(MP_TAC o SPECL [`g:real^1->real^N`; `s:real^N->bool`] o
+    MATCH_MP lemma1) THEN
+  ASM_MESON_TAC[lemma2; lemma3]);;
+
+let HOMOTOPIC_LOOPS_SHIFTPATH = prove
+ (`!s:real^N->bool p q u.
+        homotopic_loops s p q /\ u IN interval[vec 0,vec 1]
+        ==> homotopic_loops s (shiftpath u p) (shiftpath u q)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_loops; homotopic_with; PCROSS] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN DISCH_THEN(
+   (X_CHOOSE_THEN `h:real^(1,1)finite_sum->real^N` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC
+   `\z. shiftpath u (\t. (h:real^(1,1)finite_sum->real^N)
+                         (pastecart (fstcart z) t)) (sndcart z)` THEN
+  ASM_REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; ETA_AX] THEN
+  ASM_SIMP_TAC[CLOSED_SHIFTPATH] THEN CONJ_TAC THENL
+   [REWRITE_TAC[shiftpath; DROP_ADD; REAL_ARITH
+     `u + z <= &1 <=> z <= &1 - u`] THEN
+    SUBGOAL_THEN
+     `{ pastecart (t:real^1) (x:real^1) |
+        t IN interval[vec 0,vec 1] /\ x IN interval[vec 0,vec 1]} =
+      { pastecart (t:real^1) (x:real^1) |
+        t IN interval[vec 0,vec 1] /\ x IN interval[vec 0,vec 1 - u]} UNION
+      { pastecart (t:real^1) (x:real^1) |
+        t IN interval[vec 0,vec 1] /\ x IN interval[vec 1 - u,vec 1]}`
+    SUBST1_TAC THENL
+     [MATCH_MP_TAC(SET_RULE `s UNION s' = u
+        ==> {f t x | t IN i /\ x IN u} =
+            {f t x | t IN i /\ x IN s} UNION
+            {f t x | t IN i /\ x IN s'}`) THEN
+      UNDISCH_TAC `(u:real^1) IN interval[vec 0,vec 1]` THEN
+      REWRITE_TAC[EXTENSION; IN_INTERVAL_1; IN_UNION; DROP_SUB; DROP_VEC] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CASES THEN
+    SIMP_TAC[REWRITE_RULE[PCROSS] CLOSED_PCROSS; CLOSED_INTERVAL] THEN
+    REWRITE_TAC[FORALL_AND_THM; FORALL_IN_GSPEC; TAUT
+     `p /\ q \/ r /\ s ==> t <=> (p ==> q ==> t) /\ (r ==> s ==> t)`] THEN
+    SIMP_TAC[SNDCART_PASTECART; IN_INTERVAL_1; DROP_SUB; DROP_VEC] THEN
+    SIMP_TAC[REAL_ARITH `&1 - u <= x ==> (x <= &1 - u <=> x = &1 - u)`] THEN
+    SIMP_TAC[GSYM LIFT_EQ; LIFT_SUB; LIFT_DROP; LIFT_NUM] THEN
+    REWRITE_TAC[FSTCART_PASTECART; VECTOR_ARITH `u + v - u:real^N = v`;
+                VECTOR_ARITH `u + v - u - v:real^N = vec 0`] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[pathstart; pathfinish]) THEN
+    ASM_SIMP_TAC[GSYM IN_INTERVAL_1; GSYM DROP_VEC] THEN CONJ_TAC THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST;
+             LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART;
+             VECTOR_ARITH `u + z - v:real^N = (u - v) + z`] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      CONTINUOUS_ON_SUBSET)) THEN
+    UNDISCH_TAC `(u:real^1) IN interval[vec 0,vec 1]` THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; IN_INTERVAL_1;
+                IN_ELIM_PASTECART_THM; DROP_ADD; DROP_SUB; DROP_VEC] THEN
+    REAL_ARITH_TAC;
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; SET_RULE
+     `(!t x. t IN i /\ x IN i ==> f t x IN s) <=>
+      (!t. t IN i ==> IMAGE (f t) i SUBSET s)`] THEN
+    X_GEN_TAC `t:real^1` THEN STRIP_TAC THEN REWRITE_TAC[GSYM path_image] THEN
+    ASM_SIMP_TAC[PATH_IMAGE_SHIFTPATH; ETA_AX] THEN
+    REWRITE_TAC[path_image] THEN ASM SET_TAC[]]);;
+
+let HOMOTOPIC_PATHS_LOOP_PARTS = prove
+ (`!s p q a:real^N.
+        homotopic_loops s (p ++ reversepath q) (linepath(a,a)) /\ path q
+        ==> homotopic_paths s p q`,
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o
+    MATCH_MP HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_PATHS_NULL) THEN
+  REWRITE_TAC[PATHSTART_JOIN] THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o CONJUNCT1 o MATCH_MP HOMOTOPIC_PATHS_IMP_PATH) THEN
+  ASM_CASES_TAC `pathfinish p:real^N = pathstart(reversepath q)` THENL
+   [ASM_SIMP_TAC[PATH_JOIN; PATH_REVERSEPATH] THEN STRIP_TAC;
+    ASM_MESON_TAC[PATH_JOIN_PATH_ENDS; PATH_REVERSEPATH]] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[PATHSTART_REVERSEPATH]) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_SUBSET) THEN
+  ASM_SIMP_TAC[PATH_IMAGE_JOIN; PATHSTART_JOIN; PATHFINISH_JOIN;
+    PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH; UNION_SUBSET; SING_SUBSET;
+    PATH_IMAGE_REVERSEPATH; PATH_IMAGE_LINEPATH; SEGMENT_REFL] THEN
+  STRIP_TAC THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+  EXISTS_TAC `p ++ (linepath(pathfinish p:real^N,pathfinish p))` THEN
+  CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_RID THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+  EXISTS_TAC `p ++ (reversepath q ++ q):real^1->real^N` THEN CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_JOIN THEN
+    ASM_SIMP_TAC[HOMOTOPIC_PATHS_LINV; PATHSTART_JOIN; PATHSTART_REVERSEPATH;
+                 HOMOTOPIC_PATHS_REFL];
+    ALL_TAC] THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+  EXISTS_TAC `(p ++ reversepath q) ++ q:real^1->real^N` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HOMOTOPIC_PATHS_ASSOC THEN
+    ASM_REWRITE_TAC[PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+                    PATH_IMAGE_REVERSEPATH; PATH_REVERSEPATH];
+    ALL_TAC] THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+  EXISTS_TAC `linepath(pathstart p:real^N,pathstart p) ++ q` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC HOMOTOPIC_PATHS_JOIN THEN
+    ASM_REWRITE_TAC[HOMOTOPIC_PATHS_REFL] THEN
+    REWRITE_TAC[PATHFINISH_JOIN; PATHFINISH_REVERSEPATH];
+    FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHFINISH) THEN
+    REWRITE_TAC[PATHFINISH_JOIN; PATHFINISH_LINEPATH;
+                PATHFINISH_REVERSEPATH] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_LID THEN ASM_REWRITE_TAC[]]);;
+
+let HOMOTOPIC_LOOPS_ADD_SYM = prove
+ (`!p q:real^1->real^N.
+        path p /\ path_image p SUBSET s /\ pathfinish p = pathstart p /\
+        path q /\ path_image q SUBSET s /\ pathfinish q = pathstart q /\
+        pathstart q = pathstart p
+        ==> homotopic_loops s (p ++ q) (q ++ p)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HOMOTOPIC_LOOPS_TRANS THEN
+  SUBGOAL_THEN `lift(&1 / &2) IN interval[vec 0,vec 1]` ASSUME_TAC THENL
+   [REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  EXISTS_TAC `shiftpath (lift(&1 / &2)) (p ++ q:real^1->real^N)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC HOMOTOPIC_LOOPS_SHIFTPATH_SELF;
+    MATCH_MP_TAC HOMOTOPIC_LOOPS_EQ] THEN
+  ASM_SIMP_TAC[PATH_JOIN; PATH_IMAGE_JOIN; PATHSTART_JOIN; PATHFINISH_JOIN;
+               UNION_SUBSET; IN_INTERVAL_1; DROP_VEC; LIFT_DROP;
+               PATH_SHIFTPATH; PATH_IMAGE_SHIFTPATH; CLOSED_SHIFTPATH] THEN
+  SIMP_TAC[shiftpath; joinpaths; LIFT_DROP; DROP_ADD; DROP_SUB; DROP_VEC;
+           REAL_ARITH `&0 <= t ==> (a + t <= a <=> t = &0)`;
+           REAL_ARITH `t <= &1 ==> &1 / &2 + t - &1 <= &1 / &2`;
+           REAL_ARITH `&1 / &2 + t <= &1 <=> t <= &1 / &2`] THEN
+  X_GEN_TAC `t:real^1` THEN STRIP_TAC THEN
+  ASM_CASES_TAC `drop t <= &1 / &2` THEN ASM_REWRITE_TAC[] THENL
+   [REWRITE_TAC[GSYM LIFT_EQ; LIFT_NUM; LIFT_DROP] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[VECTOR_ADD_RID] THENL
+     [REWRITE_TAC[GSYM LIFT_CMUL; VECTOR_MUL_RZERO] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      ASM_MESON_TAC[LIFT_NUM; pathstart; pathfinish];
+      ALL_TAC];
+    ALL_TAC] THEN
+  AP_TERM_TAC THEN
+  REWRITE_TAC[GSYM DROP_EQ; DROP_SUB; DROP_ADD; DROP_VEC; DROP_CMUL;
+              LIFT_DROP] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Simply connected sets defined as "all loops are homotopic (as loops)".    *)
+(* ------------------------------------------------------------------------- *)
+
+let simply_connected = new_definition
+ `simply_connected(s:real^N->bool) <=>
+        !p q. path p /\ pathfinish p = pathstart p /\ path_image p SUBSET s /\
+              path q /\ pathfinish q = pathstart q /\ path_image q SUBSET s
+              ==> homotopic_loops s p q`;;
+
+let SIMPLY_CONNECTED_EMPTY = prove
+ (`simply_connected {}`,
+  REWRITE_TAC[simply_connected; SUBSET_EMPTY] THEN
+  MESON_TAC[PATH_IMAGE_NONEMPTY]);;
+
+let SIMPLY_CONNECTED_IMP_PATH_CONNECTED = prove
+ (`!s:real^N->bool. simply_connected s ==> path_connected s`,
+  REWRITE_TAC[simply_connected; PATH_CONNECTED_EQ_HOMOTOPIC_POINTS] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH;
+                  PATH_IMAGE_LINEPATH; SEGMENT_REFL] THEN
+  ASM SET_TAC[]);;
+
+let SIMPLY_CONNECTED_IMP_CONNECTED = prove
+ (`!s:real^N->bool. simply_connected s ==> connected s`,
+  SIMP_TAC[SIMPLY_CONNECTED_IMP_PATH_CONNECTED;
+           PATH_CONNECTED_IMP_CONNECTED]);;
+
+let SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY = prove
+ (`!s:real^N->bool.
+        simply_connected s <=>
+        !p a. path p /\ path_image p SUBSET s /\
+              pathfinish p = pathstart p /\ a IN s
+              ==> homotopic_loops s p (linepath(a,a))`,
+  GEN_TAC THEN REWRITE_TAC[simply_connected] THEN EQ_TAC THEN DISCH_TAC THENL
+   [REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+    ASM_REWRITE_TAC[PATH_IMAGE_LINEPATH; SEGMENT_REFL; SING_SUBSET];
+    MAP_EVERY X_GEN_TAC [`p:real^1->real^N`; `q:real^1->real^N`] THEN
+    STRIP_TAC THEN MATCH_MP_TAC HOMOTOPIC_LOOPS_TRANS THEN
+    EXISTS_TAC `linepath(pathstart p:real^N,pathstart p)` THEN
+    CONJ_TAC THENL [ALL_TAC; ONCE_REWRITE_TAC[HOMOTOPIC_LOOPS_SYM]] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; SUBSET]]);;
+
+let SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_SOME = prove
+ (`!s:real^N->bool.
+        simply_connected s <=>
+        path_connected s /\
+        !p. path p /\ path_image p SUBSET s /\ pathfinish p = pathstart p
+            ==> ?a. a IN s /\ homotopic_loops s p (linepath(a,a))`,
+  GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[SIMPLY_CONNECTED_IMP_PATH_CONNECTED] THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+     [SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY]) THEN
+    MESON_TAC[SUBSET; PATHSTART_IN_PATH_IMAGE];
+    REWRITE_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY] THEN
+    MAP_EVERY X_GEN_TAC [`p:real^1->real^N`; `a:real^N`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `p:real^1->real^N`) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `b:real^N` THEN
+    STRIP_TAC THEN MATCH_MP_TAC HOMOTOPIC_LOOPS_TRANS THEN
+    EXISTS_TAC `linepath(b:real^N,b)` THEN
+    ASM_REWRITE_TAC[HOMOTOPIC_POINTS_EQ_PATH_COMPONENT] THEN
+    ASM_MESON_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT]]);;
+
+let SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ALL = prove
+ (`!s:real^N->bool.
+        simply_connected s <=>
+        s = {} \/
+        ?a. a IN s /\
+            !p. path p /\ path_image p SUBSET s /\ pathfinish p = pathstart p
+                ==> homotopic_loops s p (linepath(a,a))`,
+  GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[SIMPLY_CONNECTED_EMPTY] THEN
+  REWRITE_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_SOME] THEN
+  EQ_TAC THENL
+   [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 STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `p:real^1->real^N` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `p:real^1->real^N`) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `b:real^N` THEN
+    STRIP_TAC THEN MATCH_MP_TAC HOMOTOPIC_LOOPS_TRANS THEN
+    EXISTS_TAC `linepath(b:real^N,b)` THEN
+    ASM_REWRITE_TAC[HOMOTOPIC_POINTS_EQ_PATH_COMPONENT] THEN
+    ASM_MESON_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT];
+    DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+    REWRITE_TAC[PATH_CONNECTED_EQ_HOMOTOPIC_POINTS] THEN
+    MAP_EVERY X_GEN_TAC [`b:real^N`; `c:real^N`] THEN STRIP_TAC THEN
+    MATCH_MP_TAC HOMOTOPIC_LOOPS_TRANS THEN
+    EXISTS_TAC `linepath(a:real^N,a)` THEN
+    GEN_REWRITE_TAC RAND_CONV [HOMOTOPIC_LOOPS_SYM] THEN
+    CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[PATH_LINEPATH; PATH_IMAGE_LINEPATH; SEGMENT_REFL;
+                PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+    ASM SET_TAC[]]);;
+
+let SIMPLY_CONNECTED_EQ_CONTRACTIBLE_PATH = prove
+ (`!s:real^N->bool.
+        simply_connected s <=>
+        path_connected s /\
+        !p. path p /\ path_image p SUBSET s /\ pathfinish p = pathstart p
+            ==> homotopic_paths s p (linepath(pathstart p,pathstart p))`,
+  GEN_TAC THEN EQ_TAC THEN STRIP_TAC THENL
+   [ASM_SIMP_TAC[SIMPLY_CONNECTED_IMP_PATH_CONNECTED] THEN
+    REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_PATHS_NULL THEN
+    EXISTS_TAC `pathstart p :real^N` THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o
+      REWRITE_RULE[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY]) THEN
+    ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; SUBSET];
+    REWRITE_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY] THEN
+    MAP_EVERY X_GEN_TAC [`p:real^1->real^N`; `a:real^N`] THEN
+    STRIP_TAC THEN MATCH_MP_TAC HOMOTOPIC_LOOPS_TRANS THEN
+    EXISTS_TAC `linepath(pathstart p:real^N,pathfinish p)` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC HOMOTOPIC_PATHS_IMP_HOMOTOPIC_LOOPS THEN
+      ASM_SIMP_TAC[PATHFINISH_LINEPATH];
+      ASM_REWRITE_TAC[HOMOTOPIC_POINTS_EQ_PATH_COMPONENT] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[PATH_CONNECTED_IFF_PATH_COMPONENT]) THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; SUBSET]]]);;
+
+let SIMPLY_CONNECTED_EQ_HOMOTOPIC_PATHS = prove
+ (`!s:real^N->bool.
+        simply_connected s <=>
+        path_connected s /\
+        !p q. path p /\ path_image p SUBSET s /\
+              path q /\ path_image q SUBSET s /\
+              pathstart q = pathstart p /\ pathfinish q = pathfinish p
+              ==> homotopic_paths s p q`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_PATH] THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `p:real^1->real^N` THENL
+   [X_GEN_TAC `q:real^1->real^N` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `p ++ reversepath q :real^1->real^N`) THEN
+    ASM_SIMP_TAC[PATH_JOIN; PATHSTART_REVERSEPATH; PATH_REVERSEPATH;
+                 PATHSTART_JOIN; PATHFINISH_JOIN; PATHFINISH_REVERSEPATH;
+                 PATH_IMAGE_JOIN; UNION_SUBSET; PATH_IMAGE_REVERSEPATH] THEN
+    DISCH_TAC THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+    EXISTS_TAC `p ++ linepath(pathfinish p,pathfinish p):real^1->real^N` THEN
+    GEN_REWRITE_TAC LAND_CONV [HOMOTOPIC_PATHS_SYM] THEN
+    ASM_SIMP_TAC[HOMOTOPIC_PATHS_RID] THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+    EXISTS_TAC `p ++ (reversepath q ++ q):real^1->real^N` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC HOMOTOPIC_PATHS_JOIN THEN
+      ASM_REWRITE_TAC[HOMOTOPIC_PATHS_REFL; PATHSTART_LINEPATH] THEN
+      ASM_MESON_TAC[HOMOTOPIC_PATHS_LINV; HOMOTOPIC_PATHS_SYM];
+      ALL_TAC] THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+    EXISTS_TAC `(p ++ reversepath q) ++ q:real^1->real^N` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC HOMOTOPIC_PATHS_ASSOC THEN
+      ASM_SIMP_TAC[PATH_REVERSEPATH; PATH_IMAGE_REVERSEPATH] THEN
+      ASM_REWRITE_TAC[PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH];
+      ALL_TAC] THEN
+    MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+    EXISTS_TAC `linepath(pathstart q,pathstart q) ++ q:real^1->real^N` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC HOMOTOPIC_PATHS_JOIN THEN
+      ASM_SIMP_TAC[HOMOTOPIC_PATHS_RINV; HOMOTOPIC_PATHS_REFL] THEN
+      ASM_REWRITE_TAC[PATHFINISH_JOIN; PATHFINISH_REVERSEPATH];
+      ASM_MESON_TAC[HOMOTOPIC_PATHS_LID]];
+    STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[PATHSTART_LINEPATH; PATHFINISH_LINEPATH; PATH_LINEPATH] THEN
+    REWRITE_TAC[PATH_IMAGE_LINEPATH; SEGMENT_REFL; SING_SUBSET] THEN
+    ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; SUBSET]]);;
+
+let SIMPLY_CONNECTED_RETRACTION_GEN = prove
+ (`!s:real^M->bool t:real^N->bool h k.
+        h continuous_on s /\ IMAGE h s = t /\
+        k continuous_on t /\ IMAGE k t SUBSET s /\
+        (!y. y IN t ==> h(k y) = y) /\
+        simply_connected s
+        ==> simply_connected t`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[simply_connected; path; path_image; homotopic_loops] THEN
+  ONCE_REWRITE_TAC[TAUT
+   `a /\ b /\ c /\ a' /\ b' /\ c' <=> a /\ c /\ b /\ a' /\ c' /\ b'`] THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ]
+    HOMOTOPICALLY_TRIVIAL_RETRACTION_GEN) THEN
+  MAP_EVERY EXISTS_TAC [`h:real^M->real^N`; `k:real^N->real^M`] THEN
+  ASM_SIMP_TAC[PATHSTART_COMPOSE; PATHFINISH_COMPOSE] THEN
+  REWRITE_TAC[pathfinish; pathstart] THEN MESON_TAC[ENDS_IN_UNIT_INTERVAL]);;
+
+let HOMEOMORPHIC_SIMPLY_CONNECTED = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homeomorphic t /\ simply_connected s
+        ==> simply_connected t`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ]
+   (REWRITE_RULE[CONJ_ASSOC] SIMPLY_CONNECTED_RETRACTION_GEN)) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homeomorphic]) THEN
+  REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+  SIMP_TAC[homeomorphism; SUBSET_REFL]);;
+
+let HOMEOMORPHIC_SIMPLY_CONNECTED_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homeomorphic t
+        ==> (simply_connected s <=> simply_connected t)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HOMEOMORPHIC_SIMPLY_CONNECTED) THEN
+  ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+  ASM_REWRITE_TAC[]);;
+
+let SIMPLY_CONNECTED_TRANSLATION = prove
+ (`!a:real^N s. simply_connected (IMAGE (\x. a + x) s) <=> simply_connected s`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC HOMEOMORPHIC_SIMPLY_CONNECTED_EQ THEN
+  ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+  REWRITE_TAC[HOMEOMORPHIC_TRANSLATION]);;
+
+add_translation_invariants [SIMPLY_CONNECTED_TRANSLATION];;
+
+let SIMPLY_CONNECTED_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (simply_connected (IMAGE f s) <=> simply_connected s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMEOMORPHIC_SIMPLY_CONNECTED_EQ THEN
+  ASM_MESON_TAC[HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_LEFT_EQ;
+                HOMEOMORPHIC_REFL]);;
+
+add_linear_invariants [SIMPLY_CONNECTED_INJECTIVE_LINEAR_IMAGE];;
+
+let SIMPLY_CONNECTED_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        simply_connected s /\ simply_connected t
+        ==> simply_connected(s PCROSS t)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY] THEN
+  REWRITE_TAC[path; path_image; pathstart; pathfinish; FORALL_PASTECART] THEN
+  DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC
+   [`p:real^1->real^(M,N)finite_sum`; `a:real^M`; `b:real^N`] THEN
+  REWRITE_TAC[PASTECART_IN_PCROSS; FORALL_IN_IMAGE; SUBSET] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(CONJUNCTS_THEN2
+   (MP_TAC o SPECL [`fstcart o (p:real^1->real^(M,N)finite_sum)`; `a:real^M`])
+   (MP_TAC o SPECL [`sndcart o (p:real^1->real^(M,N)finite_sum)`;
+                    `b:real^N`])) THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_COMPOSE; LINEAR_FSTCART; LINEAR_SNDCART;
+               LINEAR_CONTINUOUS_ON; homotopic_loops; homotopic_with;
+               pathfinish; pathstart; IMAGE_o; o_THM] THEN
+  ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE] THEN ANTS_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[PCROSS; IN_ELIM_THM]) THEN
+    ASM_MESON_TAC[SNDCART_PASTECART];
+    DISCH_THEN(X_CHOOSE_THEN
+      `k:real^(1,1)finite_sum->real^N` STRIP_ASSUME_TAC)] THEN
+  ANTS_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[PCROSS; IN_ELIM_THM]) THEN
+    ASM_MESON_TAC[FSTCART_PASTECART];
+    DISCH_THEN(X_CHOOSE_THEN
+      `h:real^(1,1)finite_sum->real^M` STRIP_ASSUME_TAC)] THEN
+  EXISTS_TAC
+   `(\z. pastecart (h z) (k z))
+    :real^(1,1)finite_sum->real^(M,N)finite_sum` THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_PASTECART; ETA_AX] THEN
+  REWRITE_TAC[LINEPATH_REFL; PASTECART_FST_SND] THEN
+  ASM_SIMP_TAC[PASTECART_IN_PCROSS]);;
+
+let SIMPLY_CONNECTED_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        simply_connected(s PCROSS t) <=>
+        s = {} \/ t = {} \/ simply_connected s /\ simply_connected t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; SIMPLY_CONNECTED_EMPTY] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; SIMPLY_CONNECTED_EMPTY] THEN
+  EQ_TAC THEN REWRITE_TAC[SIMPLY_CONNECTED_PCROSS] THEN REPEAT STRIP_TAC THENL
+   [REWRITE_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY] THEN
+    MAP_EVERY X_GEN_TAC [`p:real^1->real^M`; `a:real^M`] THEN
+    REWRITE_TAC[path; path_image; pathstart; pathfinish; SUBSET;
+                FORALL_IN_IMAGE] THEN
+    STRIP_TAC THEN UNDISCH_TAC `~(t:real^N->bool = {})` THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_THEN `b:real^N` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+     [SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY]) THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`(\t. pastecart (p t) (b)):real^1->real^(M,N)finite_sum`;
+      `pastecart (a:real^M) (b:real^N)`]) THEN
+    ASM_REWRITE_TAC[PASTECART_IN_PCROSS] THEN
+    ASM_SIMP_TAC[path; path_image; pathstart; pathfinish; SUBSET;
+                 FORALL_IN_IMAGE; PASTECART_IN_PCROSS; PASTECART_INJ;
+                 CONTINUOUS_ON_PASTECART; ETA_AX; CONTINUOUS_ON_CONST] THEN
+    STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`(\t. pastecart (p t) b):real^1->real^(M,N)finite_sum`;
+      `linepath (pastecart (a:real^M) (b:real^N),pastecart a b)`;
+      `fstcart:real^(M,N)finite_sum->real^M`;
+      `(s:real^M->bool) PCROSS (t:real^N->bool)`; `s:real^M->bool`]
+        HOMOTOPIC_LOOPS_CONTINUOUS_IMAGE) THEN
+    ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART] THEN
+    SIMP_TAC[o_DEF; LINEPATH_REFL; FSTCART_PASTECART; ETA_AX;
+             SUBSET; FORALL_IN_PCROSS; FORALL_IN_IMAGE];
+    REWRITE_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY] THEN
+    MAP_EVERY X_GEN_TAC [`p:real^1->real^N`; `b:real^N`] THEN
+    REWRITE_TAC[path; path_image; pathstart; pathfinish; SUBSET;
+                FORALL_IN_IMAGE] THEN
+    STRIP_TAC THEN UNDISCH_TAC `~(s:real^M->bool = {})` THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_THEN `a:real^M` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+     [SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ANY]) THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`(\t. pastecart a (p t)):real^1->real^(M,N)finite_sum`;
+      `pastecart (a:real^M) (b:real^N)`]) THEN
+    ASM_REWRITE_TAC[PASTECART_IN_PCROSS] THEN
+    ASM_SIMP_TAC[path; path_image; pathstart; pathfinish; SUBSET;
+                 FORALL_IN_IMAGE; PASTECART_IN_PCROSS; PASTECART_INJ;
+                 CONTINUOUS_ON_PASTECART; ETA_AX; CONTINUOUS_ON_CONST] THEN
+    STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`(\t. pastecart a (p t)):real^1->real^(M,N)finite_sum`;
+      `linepath (pastecart (a:real^M) (b:real^N),pastecart a b)`;
+      `sndcart:real^(M,N)finite_sum->real^N`;
+      `(s:real^M->bool) PCROSS (t:real^N->bool)`; `t:real^N->bool`]
+        HOMOTOPIC_LOOPS_CONTINUOUS_IMAGE) THEN
+    ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+    SIMP_TAC[o_DEF; LINEPATH_REFL; SNDCART_PASTECART; ETA_AX;
+             SUBSET; FORALL_IN_PCROSS; FORALL_IN_IMAGE]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A mapping out of a sphere is nullhomotopic iff it extends to the ball.    *)
+(* This even works out in the degenerate cases when the radius is <= 0, and  *)
+(* we also don't need to explicitly assume continuity since it's already     *)
+(* implicit in both sides of the equivalence.                                *)
+(* ------------------------------------------------------------------------- *)
+
+let NULLHOMOTOPIC_FROM_SPHERE_EXTENSION = prove
+ (`!f:real^M->real^N s a r.
+        (?c. homotopic_with (\x. T) (sphere(a,r),s) f (\x. c)) <=>
+        (?g. g continuous_on cball(a,r) /\ IMAGE g (cball(a,r)) SUBSET s /\
+             !x. x IN sphere(a,r) ==> g x = f x)`,
+  let lemma = prove
+   (`!f:real^M->real^N g a r.
+        (!e. &0 < e
+             ==> ?d. &0 < d /\
+                     !x. ~(x = a) /\ norm(x - a) < d ==> norm(g x - f a) < e) /\
+        g continuous_on (cball(a,r) DELETE a) /\
+        (!x. x IN cball(a,r) /\ ~(x = a) ==> f x = g x)
+        ==> f continuous_on cball(a,r)`,
+    REPEAT STRIP_TAC THEN REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+    X_GEN_TAC `x:real^M` THEN REWRITE_TAC[IN_CBALL; dist] THEN STRIP_TAC THEN
+    ASM_CASES_TAC `x:real^M = a` THENL
+     [ASM_REWRITE_TAC[continuous_within; IN_CBALL; dist] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_CBALL; dist]) THEN
+      X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+      GEN_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+      X_GEN_TAC `y:real^M` THEN ASM_CASES_TAC `y:real^M = a` THEN
+      ASM_MESON_TAC[VECTOR_SUB_REFL; NORM_0];
+      MATCH_MP_TAC CONTINUOUS_TRANSFORM_WITHIN THEN
+      EXISTS_TAC `g:real^M->real^N` THEN EXISTS_TAC `norm(x - a:real^M)` THEN
+      ASM_SIMP_TAC[NORM_POS_LT; VECTOR_SUB_EQ; IN_CBALL; dist] THEN
+      CONJ_TAC THENL
+       [RULE_ASSUM_TAC(REWRITE_RULE[IN_CBALL; dist]);
+        UNDISCH_TAC
+         `(g:real^M->real^N) continuous_on (cball(a,r) DELETE a)` THEN
+        REWRITE_TAC[continuous_on; continuous_within] THEN
+        DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN
+        ASM_REWRITE_TAC[IN_DELETE; IN_CBALL; dist] 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 `d:real` STRIP_ASSUME_TAC) THEN
+        EXISTS_TAC `min d (norm(x - a:real^M))` THEN
+        ASM_REWRITE_TAC[REAL_LT_MIN; NORM_POS_LT; VECTOR_SUB_EQ]] THEN
+       ASM_MESON_TAC[NORM_SUB; NORM_ARITH
+        `norm(y - x:real^N) < norm(x - a) ==> ~(y = a)`]]) in
+  REWRITE_TAC[sphere; ONCE_REWRITE_RULE[DIST_SYM] dist] THEN
+  REPEAT GEN_TAC THEN REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
+   (REAL_ARITH `r < &0 \/ r = &0 \/ &0 < r`)
+  THENL
+   [ASM_SIMP_TAC[NORM_ARITH `r < &0 ==> ~(norm x = r)`] THEN
+    FIRST_ASSUM(ASSUME_TAC o GEN_REWRITE_RULE I [GSYM CBALL_EQ_EMPTY]) THEN
+    ASM_SIMP_TAC[HOMOTOPIC_WITH; IMAGE_CLAUSES; EMPTY_GSPEC; NOT_IN_EMPTY;
+       PCROSS; SET_RULE `{f t x |x,t| F} = {}`; EMPTY_SUBSET] THEN
+    REWRITE_TAC[CONTINUOUS_ON_EMPTY];
+    ASM_SIMP_TAC[NORM_EQ_0; VECTOR_SUB_EQ; CBALL_SING] THEN
+    SIMP_TAC[HOMOTOPIC_WITH; PCROSS; FORALL_IN_GSPEC; FORALL_UNWIND_THM2] THEN
+    ASM_CASES_TAC `(f:real^M->real^N) a IN s` THENL
+     [MATCH_MP_TAC(TAUT `p /\ q ==> (p <=> q)`) THEN CONJ_TAC THENL
+       [EXISTS_TAC `(f:real^M->real^N) a` THEN
+        EXISTS_TAC `\y:real^(1,M)finite_sum. (f:real^M->real^N) a` THEN
+        ASM_REWRITE_TAC[CONTINUOUS_ON_CONST; SUBSET; FORALL_IN_IMAGE];
+        EXISTS_TAC `f:real^M->real^N` THEN REWRITE_TAC[CONTINUOUS_ON_SING] THEN
+        ASM SET_TAC[]];
+      MATCH_MP_TAC(TAUT `~q /\ ~p ==> (p <=> q)`) THEN CONJ_TAC THENL
+       [ASM SET_TAC[]; STRIP_TAC] THEN
+      UNDISCH_TAC `~((f:real^M->real^N) a IN s)` THEN REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `IMAGE h t SUBSET s ==> (?y. y IN t /\ z = h y) ==> z IN s`)) THEN
+      REWRITE_TAC[EXISTS_IN_GSPEC] THEN
+      EXISTS_TAC `vec 0:real^1` THEN ASM_SIMP_TAC[ENDS_IN_UNIT_INTERVAL] THEN
+      ASM_REWRITE_TAC[EXISTS_IN_GSPEC; UNWIND_THM2]];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(TAUT
+   `!p. (q ==> p) /\ (r ==> p) /\ (p ==> (q <=> r)) ==> (q <=> r)`) THEN
+  EXISTS_TAC
+   `(f:real^M->real^N) continuous_on {x | norm(x - a) = r} /\
+    IMAGE f {x | norm(x - a) = r} SUBSET s` THEN
+  REPEAT CONJ_TAC THENL
+   [STRIP_TAC THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET) THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_CONTINUOUS) THEN
+    ASM_REWRITE_TAC[];
+    DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^N` STRIP_ASSUME_TAC) THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_EQ THEN EXISTS_TAC `g:real^M->real^N` THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+      EXISTS_TAC `cball(a:real^M,r)`;
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+        `IMAGE g t SUBSET s
+         ==> u SUBSET t /\ (!x. x IN u ==> f x = g x)
+             ==> IMAGE f u SUBSET s`)) THEN
+      ASM_SIMP_TAC[]] THEN
+    ASM_SIMP_TAC[SUBSET; IN_CBALL; dist; IN_ELIM_THM] THEN
+    MESON_TAC[REAL_LE_REFL; NORM_SUB];
+    STRIP_TAC] THEN
+  ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN EQ_TAC THENL
+   [REWRITE_TAC[homotopic_with; PCROSS; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`c:real^N`; `h:real^(1,M)finite_sum->real^N`] THEN
+    STRIP_TAC THEN
+    EXISTS_TAC `\x. (h:real^(1,M)finite_sum->real^N)
+                    (pastecart (lift(inv(r) * norm(x - a)))
+                               (a + (if x = a then r % basis 1
+                                     else r / norm(x - a) % (x - a))))` THEN
+    ASM_SIMP_TAC[IN_ELIM_THM; REAL_MUL_LINV; REAL_DIV_REFL; REAL_LT_IMP_NZ;
+                 LIFT_NUM; VECTOR_ARITH `a + &1 % (x - a):real^N = x`] THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC lemma THEN
+      EXISTS_TAC `\x. (h:real^(1,M)finite_sum->real^N)
+                    (pastecart (lift(inv(r) * norm(x - a)))
+                               (a + r / norm(x - a) % (x - a)))` THEN
+      SIMP_TAC[] THEN CONJ_TAC THENL
+       [X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+        ASM_REWRITE_TAC[VECTOR_SUB_REFL; NORM_0; REAL_MUL_RZERO; LIFT_NUM] THEN
+        FIRST_X_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          COMPACT_UNIFORMLY_CONTINUOUS)) THEN
+        SIMP_TAC[REWRITE_RULE[PCROSS] COMPACT_PCROSS;
+            REWRITE_RULE[REWRITE_RULE[ONCE_REWRITE_RULE[DIST_SYM] dist] sphere]
+                 COMPACT_SPHERE; COMPACT_INTERVAL] THEN
+        REWRITE_TAC[uniformly_continuous_on] THEN
+        DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+        REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC] THEN
+        DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+        EXISTS_TAC `min r (d * r):real` THEN
+        ASM_SIMP_TAC[REAL_LT_MUL; REAL_LT_MIN] THEN
+        X_GEN_TAC `x:real^M` THEN REPEAT STRIP_TAC THEN
+        FIRST_X_ASSUM(MP_TAC o SPEC `vec 0:real^1`) THEN
+        REWRITE_TAC[ENDS_IN_UNIT_INTERVAL; RIGHT_IMP_FORALL_THM] THEN
+        ASM_REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+        DISCH_THEN(MP_TAC o MATCH_MP (MESON[]
+         `(!x t y. P x t y) ==> (!t x. P x t x)`)) THEN
+        REWRITE_TAC[dist] THEN DISCH_THEN MATCH_MP_TAC THEN
+        REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+        REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] (GSYM real_div)] THEN
+        ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ] THEN
+        ASM_SIMP_TAC[REAL_MUL_LID; REAL_MUL_LZERO; NORM_POS_LE] THEN
+        ASM_SIMP_TAC[REAL_LT_IMP_LE; CONJ_ASSOC] THEN
+        REWRITE_TAC[VECTOR_ADD_SUB; NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM] THEN
+        ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+        ASM_SIMP_TAC[REAL_ARITH `&0 < r ==> abs r = r`] THEN
+        REWRITE_TAC[PASTECART_SUB; VECTOR_SUB_REFL; NORM_PASTECART] THEN
+        REWRITE_TAC[NORM_0; VECTOR_SUB_RZERO] THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[REAL_ADD_RID] THEN
+        REWRITE_TAC[POW_2_SQRT_ABS; REAL_ABS_NORM; NORM_LIFT] THEN
+        ASM_SIMP_TAC[REAL_ABS_DIV; REAL_LT_LDIV_EQ; REAL_ABS_NORM;
+                     REAL_ARITH `&0 < r ==> abs r = r`];
+        GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+         [MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+          SIMP_TAC[CONTINUOUS_ON_CMUL; LIFT_CMUL; CONTINUOUS_ON_SUB;
+                   CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST;
+                   CONTINUOUS_ON_LIFT_NORM_COMPOSE] THEN
+          MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
+          REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+          MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+          SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST;
+                   o_DEF; real_div; LIFT_CMUL] THEN
+          MATCH_MP_TAC CONTINUOUS_ON_CMUL THEN
+          REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+          GEN_TAC THEN REWRITE_TAC[IN_DELETE] THEN DISCH_TAC THEN
+          MATCH_MP_TAC CONTINUOUS_AT_WITHIN THEN
+          MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_INV) THEN
+          ASM_SIMP_TAC[NETLIMIT_AT; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+          MATCH_MP_TAC CONTINUOUS_LIFT_NORM_COMPOSE THEN
+          SIMP_TAC[CONTINUOUS_SUB; CONTINUOUS_AT_ID; CONTINUOUS_CONST];
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN
+          REWRITE_TAC[FORALL_IN_IMAGE; FORALL_IN_GSPEC; SUBSET] THEN
+          REWRITE_TAC[IN_ELIM_PASTECART_THM; IN_DELETE; IN_ELIM_THM] THEN
+          SIMP_TAC[IN_CBALL; NORM_ARITH `dist(a:real^M,a + x) = norm x`] THEN
+          REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] dist] THEN
+          REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+          REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] (GSYM real_div)] THEN
+          ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ] THEN
+          ASM_SIMP_TAC[REAL_MUL_LID; REAL_MUL_LZERO; NORM_POS_LE] THEN
+          SIMP_TAC[VECTOR_ADD_SUB; NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM;
+                   REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+          ASM_REAL_ARITH_TAC]];
+      GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM o_DEF] THEN
+      REWRITE_TAC[IMAGE_o] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `IMAGE g s SUBSET u ==> t SUBSET s ==> IMAGE g t SUBSET u`)) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+      REWRITE_TAC[IN_ELIM_PASTECART_THM; IN_CBALL; IN_ELIM_THM] THEN
+      X_GEN_TAC `x:real^M` THEN
+      REWRITE_TAC[ONCE_REWRITE_RULE[DIST_SYM] dist] THEN REPEAT STRIP_TAC THENL
+       [REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+        REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] (GSYM real_div)] THEN
+        ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ] THEN
+        ASM_REWRITE_TAC[REAL_MUL_LID; REAL_MUL_LZERO; NORM_POS_LE];
+        REWRITE_TAC[VECTOR_ADD_SUB] THEN COND_CASES_TAC THEN
+        ASM_SIMP_TAC[NORM_MUL; NORM_BASIS; DIMINDEX_GE_1; LE_REFL;
+                     REAL_ABS_DIV; REAL_ABS_NORM;
+                     REAL_MUL_RID; REAL_ARITH `&0 < r ==> abs r = r`] THEN
+        ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ]];
+      GEN_TAC THEN COND_CASES_TAC THEN
+      ASM_SIMP_TAC[VECTOR_SUB_REFL; NORM_0; REAL_LT_IMP_NZ] THEN
+      REWRITE_TAC[VECTOR_ARITH `a + &1 % (x - a):real^N = x`]];
+    DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(g:real^M->real^N) a` THEN
+    ASM_SIMP_TAC[HOMOTOPIC_WITH; PCROSS] THEN
+    EXISTS_TAC `\y:real^(1,M)finite_sum.
+                   (g:real^M->real^N)
+                   (a + drop(fstcart y) % (sndcart y - a))` THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; DROP_VEC] THEN
+    REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_RID; VECTOR_MUL_LID] THEN
+    ASM_SIMP_TAC[VECTOR_SUB_ADD2] THEN CONJ_TAC THENL
+     [GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN SIMP_TAC[CONTINUOUS_ON_CONST] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+        SIMP_TAC[o_DEF; LIFT_DROP; CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST;
+                 LINEAR_CONTINUOUS_ON; LINEAR_SNDCART; LINEAR_FSTCART; ETA_AX];
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET))];
+      GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM o_DEF] THEN
+      REWRITE_TAC[IMAGE_o] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `IMAGE g s SUBSET u ==> t SUBSET s ==> IMAGE g t SUBSET u`))] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; IN_ELIM_THM] THEN
+    REWRITE_TAC[IN_CBALL; NORM_ARITH `dist(a:real^M,a + x) = norm x`] THEN
+    ASM_SIMP_TAC[NORM_MUL; IN_INTERVAL_1; DROP_VEC; REAL_LE_RMUL_EQ;
+                 REAL_ARITH `x * r <= r <=> x * r <= &1 * r`] THEN
+    REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homotopy equivalence.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("homotopy_equivalent",(12,"right"));;
+
+let homotopy_equivalent = new_definition
+ `(s:real^M->bool) homotopy_equivalent (t:real^N->bool) <=>
+        ?f g. f continuous_on s /\ IMAGE f s SUBSET t /\
+              g continuous_on t /\ IMAGE g t SUBSET s /\
+              homotopic_with (\x. T) (s,s) (g o f) I /\
+              homotopic_with (\x. T) (t,t) (f o g) I`;;
+
+let HOMOTOPY_EQUIVALENT = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homotopy_equivalent t <=>
+        ?f g h. f continuous_on s /\ IMAGE f s SUBSET t /\
+                g continuous_on t /\ IMAGE g t SUBSET s /\
+                h continuous_on t /\ IMAGE h t SUBSET s /\
+                homotopic_with (\x. T) (s,s) (g o f) I /\
+                homotopic_with (\x. T) (t,t) (f o h) I`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopy_equivalent] THEN
+  MATCH_MP_TAC(MESON[] `(!x. P x <=> Q x) ==> ((?x. P x) <=> (?x. Q x))`) THEN
+  X_GEN_TAC `f:real^M->real^N` THEN
+  EQ_TAC THENL [MESON_TAC[]; STRIP_TAC] THEN
+  EXISTS_TAC `(g:real^N->real^M) o f o (h:real^N->real^M)` THEN
+  ASM_REWRITE_TAC[IMAGE_o] THEN REPEAT CONJ_TAC THENL
+   [REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC) THEN
+    REWRITE_TAC[IMAGE_o] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_SUBSET)) THEN ASM SET_TAC[];
+    ASM SET_TAC[];
+    TRANS_TAC HOMOTOPIC_WITH_TRANS
+      `((g:real^N->real^M) o I) o (f:real^M->real^N)` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_REWRITE_TAC[I_O_ID]] THEN
+    MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+    EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+    EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[];
+    TRANS_TAC HOMOTOPIC_WITH_TRANS
+      `(f:real^M->real^N) o I o (h:real^N->real^M)` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_REWRITE_TAC[I_O_ID]] THEN
+    MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+    EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[o_ASSOC] THEN
+    MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+    EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[]]);;
+
+let HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homeomorphic t ==> s homotopy_equivalent t`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[homeomorphic; homotopy_equivalent; homeomorphism] THEN
+  REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[SUBSET_REFL] THEN
+  CONJ_TAC THEN MATCH_MP_TAC HOMOTOPIC_WITH_EQUAL THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_COMPOSE; IMAGE_o; o_THM; I_THM; SUBSET_REFL]);;
+
+let HOMOTOPY_EQUIVALENT_REFL = prove
+ (`!s:real^N->bool. s homotopy_equivalent s`,
+  SIMP_TAC[HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT; HOMEOMORPHIC_REFL]);;
+
+let HOMOTOPY_EQUIVALENT_SYM = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homotopy_equivalent t <=> t homotopy_equivalent s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopy_equivalent] THEN
+  GEN_REWRITE_TAC RAND_CONV [SWAP_EXISTS_THM] THEN
+  REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN CONV_TAC TAUT);;
+
+let HOMOTOPY_EQUIVALENT_TRANS = prove
+ (`!s:real^M->bool t:real^N->bool u:real^P->bool.
+        s homotopy_equivalent t /\ t homotopy_equivalent u
+        ==> s homotopy_equivalent u`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[homotopy_equivalent; LEFT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+  SIMP_TAC[RIGHT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`f1:real^M->real^N`; `g1:real^N->real^M`;
+    `f2:real^N->real^P`; `g2:real^P->real^N`] THEN
+  STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC
+   [`(f2:real^N->real^P) o (f1:real^M->real^N)`;
+    `(g1:real^N->real^M) o (g2:real^P->real^N)`] THEN
+  REWRITE_TAC[IMAGE_o] THEN
+  REPLICATE_TAC 2
+   (CONJ_TAC THENL
+    [ASM_MESON_TAC[CONTINUOUS_ON_COMPOSE; CONTINUOUS_ON_SUBSET];ALL_TAC] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+  CONJ_TAC THEN MATCH_MP_TAC HOMOTOPIC_WITH_TRANS THENL
+   [EXISTS_TAC `(g1:real^N->real^M) o I o (f1:real^M->real^N)`;
+    EXISTS_TAC `(f2:real^N->real^P) o I o (g2:real^P->real^N)`] THEN
+  (CONJ_TAC THENL [ALL_TAC; ASM_REWRITE_TAC[I_O_ID]]) THEN
+  REWRITE_TAC[GSYM o_ASSOC] THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+  EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[o_ASSOC] THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+  EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[]);;
+
+let HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_SELF = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (IMAGE f s) homotopy_equivalent s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT THEN
+  MATCH_MP_TAC HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_SELF THEN
+  ASM_REWRITE_TAC[]);;
+
+let HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_LEFT_EQ = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> ((IMAGE f s) homotopy_equivalent t <=> s homotopy_equivalent t)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(ASSUME_TAC o SPEC `s:real^M->bool` o
+    MATCH_MP HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_SELF) THEN
+  EQ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HOMOTOPY_EQUIVALENT_SYM]);
+    POP_ASSUM MP_TAC] THEN
+  REWRITE_TAC[IMP_IMP; HOMOTOPY_EQUIVALENT_TRANS]);;
+
+let HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (s homotopy_equivalent (IMAGE f t) <=> s homotopy_equivalent t)`,
+  ONCE_REWRITE_TAC[HOMOTOPY_EQUIVALENT_SYM] THEN
+  REWRITE_TAC[HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_LEFT_EQ]);;
+
+add_linear_invariants
+  [HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_LEFT_EQ;
+   HOMOTOPY_EQUIVALENT_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ];;
+
+let HOMOTOPY_EQUIVALENT_TRANSLATION_SELF = prove
+ (`!a:real^N s. (IMAGE (\x. a + x) s) homotopy_equivalent s`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT THEN
+  REWRITE_TAC[HOMEOMORPHIC_TRANSLATION_SELF]);;
+
+let HOMOTOPY_EQUIVALENT_TRANSLATION_LEFT_EQ = prove
+ (`!a:real^N s t.
+      (IMAGE (\x. a + x) s) homotopy_equivalent t <=> s homotopy_equivalent t`,
+  MESON_TAC[HOMOTOPY_EQUIVALENT_TRANSLATION_SELF;
+            HOMOTOPY_EQUIVALENT_SYM; HOMOTOPY_EQUIVALENT_TRANS]);;
+
+let HOMOTOPY_EQUIVALENT_TRANSLATION_RIGHT_EQ = prove
+ (`!a:real^N s t.
+      s homotopy_equivalent (IMAGE (\x. a + x) t) <=> s homotopy_equivalent t`,
+  ONCE_REWRITE_TAC[HOMOTOPY_EQUIVALENT_SYM] THEN
+  REWRITE_TAC[HOMOTOPY_EQUIVALENT_TRANSLATION_LEFT_EQ]);;
+
+add_translation_invariants
+  [HOMOTOPY_EQUIVALENT_TRANSLATION_LEFT_EQ;
+   HOMOTOPY_EQUIVALENT_TRANSLATION_RIGHT_EQ];;
+
+let HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY = prove
+  (`!s:real^M->bool t:real^N->bool u:real^P->bool.
+        s homotopy_equivalent t
+        ==> ((!f g. f continuous_on u /\ IMAGE f u SUBSET s /\
+                    g continuous_on u /\ IMAGE g u SUBSET s
+                    ==> homotopic_with (\x. T) (u,s) f g) <=>
+             (!f g. f continuous_on u /\ IMAGE f u SUBSET t /\
+                    g continuous_on u /\ IMAGE g u SUBSET t
+                    ==> homotopic_with (\x. T) (u,t) f g))`,
+  let lemma = prove
+   (`!s:real^M->bool t:real^N->bool u:real^P->bool.
+          s homotopy_equivalent t /\
+          (!f g. f continuous_on u /\ IMAGE f u SUBSET s /\
+                 g continuous_on u /\ IMAGE g u SUBSET s
+                 ==> homotopic_with (\x. T) (u,s) f g)
+          ==> (!f g. f continuous_on u /\ IMAGE f u SUBSET t /\
+                     g continuous_on u /\ IMAGE g u SUBSET t
+                     ==> homotopic_with (\x. T) (u,t) f g)`,
+    REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopy_equivalent]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `h:real^M->real^N`
+     (X_CHOOSE_THEN `k:real^N->real^M` STRIP_ASSUME_TAC)) THEN
+    SUBGOAL_THEN
+     `homotopic_with (\x. T) (u,t)
+          ((h:real^M->real^N) o (k:real^N->real^M) o (f:real^P->real^N))
+          (h o k o g)`
+    MP_TAC THENL
+     [MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+      EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IMAGE_o] THEN
+      REPEAT CONJ_TAC THEN TRY(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE) THEN
+      ASM_REWRITE_TAC[] THEN
+      TRY(FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET))) THEN
+      ASM SET_TAC[];
+      MATCH_MP_TAC(MESON[HOMOTOPIC_WITH_TRANS; HOMOTOPIC_WITH_SYM]
+       `homotopic_with P (u,t) f f' /\ homotopic_with P (u,t) g g'
+        ==> homotopic_with P (u,t) f g ==> homotopic_with P (u,t) f' g'`) THEN
+      CONJ_TAC THEN
+      GEN_REWRITE_TAC RAND_CONV [GSYM(CONJUNCT1(SPEC_ALL I_O_ID))] THEN
+      REWRITE_TAC[o_ASSOC] THEN
+      MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+      EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[]]) in
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ] lemma) THEN
+  ASM_MESON_TAC[HOMOTOPY_EQUIVALENT_SYM]);;
+
+let HOMOTOPY_EQUIVALENT_COHOMOTOPIC_TRIVIALITY = prove
+ (`!s:real^M->bool t:real^N->bool u:real^P->bool.
+        s homotopy_equivalent t
+        ==> ((!f g. f continuous_on s /\ IMAGE f s SUBSET u /\
+                    g continuous_on s /\ IMAGE g s SUBSET u
+                    ==> homotopic_with (\x. T) (s,u) f g) <=>
+             (!f g. f continuous_on t /\ IMAGE f t SUBSET u /\
+                    g continuous_on t /\ IMAGE g t SUBSET u
+                    ==> homotopic_with (\x. T) (t,u) f g))`,
+  let lemma = prove
+   (`!s:real^M->bool t:real^N->bool u:real^P->bool.
+          s homotopy_equivalent t /\
+          (!f g. f continuous_on s /\ IMAGE f s SUBSET u /\
+                 g continuous_on s /\ IMAGE g s SUBSET u
+                 ==> homotopic_with (\x. T) (s,u) f g)
+           ==> (!f g. f continuous_on t /\ IMAGE f t SUBSET u /\
+                      g continuous_on t /\ IMAGE g t SUBSET u
+                      ==> homotopic_with (\x. T) (t,u) f g)`,
+    REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopy_equivalent]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `h:real^M->real^N`
+     (X_CHOOSE_THEN `k:real^N->real^M` STRIP_ASSUME_TAC)) THEN
+    SUBGOAL_THEN
+     `homotopic_with (\x. T) (t,u)
+          (((f:real^N->real^P) o h) o (k:real^N->real^M)) ((g o h) o k)`
+    MP_TAC THENL
+     [MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+      EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IMAGE_o] THEN
+      REPEAT CONJ_TAC THEN TRY(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE) THEN
+      ASM_REWRITE_TAC[] THEN
+      TRY(FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET))) THEN
+      ASM SET_TAC[];
+      MATCH_MP_TAC(MESON[HOMOTOPIC_WITH_TRANS; HOMOTOPIC_WITH_SYM]
+       `homotopic_with P (u,t) f f' /\ homotopic_with P (u,t) g g'
+        ==> homotopic_with P (u,t) f g ==> homotopic_with P (u,t) f' g'`) THEN
+      CONJ_TAC THEN
+      GEN_REWRITE_TAC RAND_CONV [GSYM(CONJUNCT2(SPEC_ALL I_O_ID))] THEN
+      REWRITE_TAC[GSYM o_ASSOC] THEN
+      MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+      EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[]]) in
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ] lemma) THEN
+  ASM_MESON_TAC[HOMOTOPY_EQUIVALENT_SYM]);;
+
+let HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY_NULL = prove
+  (`!s:real^M->bool t:real^N->bool u:real^P->bool.
+        s homotopy_equivalent t
+        ==> ((!f. f continuous_on u /\ IMAGE f u SUBSET s
+                  ==> ?c. homotopic_with (\x. T) (u,s) f (\x. c)) <=>
+             (!f. f continuous_on u /\ IMAGE f u SUBSET t
+                  ==> ?c. homotopic_with (\x. T) (u,t) f (\x. c)))`,
+  let lemma = prove
+   (`!s:real^M->bool t:real^N->bool u:real^P->bool.
+          s homotopy_equivalent t /\
+          (!f. f continuous_on u /\ IMAGE f u SUBSET s
+               ==> ?c. homotopic_with (\x. T) (u,s) f (\x. c))
+          ==> (!f. f continuous_on u /\ IMAGE f u SUBSET t
+                   ==> ?c. homotopic_with (\x. T) (u,t) f (\x. c))`,
+    REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopy_equivalent]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `h:real^M->real^N`
+     (X_CHOOSE_THEN `k:real^N->real^M` STRIP_ASSUME_TAC)) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(k:real^N->real^M) o (f:real^P->real^N)`) THEN
+    REWRITE_TAC[IMAGE_o] THEN ANTS_TAC THENL
+     [CONJ_TAC THENL [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE; ASM SET_TAC[]] THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+      DISCH_THEN(X_CHOOSE_TAC `c:real^M`) THEN
+      EXISTS_TAC `(h:real^M->real^N) c`] THEN
+    SUBGOAL_THEN
+     `homotopic_with (\x. T) (u,t)
+          ((h:real^M->real^N) o (k:real^N->real^M) o (f:real^P->real^N))
+          (h o (\x. c))`
+    MP_TAC THENL
+     [MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+      EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[];
+      GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [o_DEF] THEN
+      REWRITE_TAC[] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HOMOTOPIC_WITH_TRANS) THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM(CONJUNCT1(SPEC_ALL I_O_ID))] THEN
+      REWRITE_TAC[o_ASSOC] THEN ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN
+      MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+      EXISTS_TAC `t:real^N->bool` THEN
+      ASM_REWRITE_TAC[]]) in
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ] lemma) THEN
+  ASM_MESON_TAC[HOMOTOPY_EQUIVALENT_SYM]);;
+
+let HOMOTOPY_EQUIVALENT_COHOMOTOPIC_TRIVIALITY_NULL = prove
+ (`!s:real^M->bool t:real^N->bool u:real^P->bool.
+        s homotopy_equivalent t
+        ==> ((!f. f continuous_on s /\ IMAGE f s SUBSET u
+                  ==> ?c. homotopic_with (\x. T) (s,u) f (\x. c)) <=>
+             (!f. f continuous_on t /\ IMAGE f t SUBSET u
+                  ==> ?c. homotopic_with (\x. T) (t,u) f (\x. c)))`,
+  let lemma = prove
+   (`!s:real^M->bool t:real^N->bool u:real^P->bool.
+          s homotopy_equivalent t /\
+          (!f. f continuous_on s /\ IMAGE f s SUBSET u
+               ==> ?c. homotopic_with (\x. T) (s,u) f (\x. c))
+          ==> (!f. f continuous_on t /\ IMAGE f t SUBSET u
+                   ==> ?c. homotopic_with (\x. T) (t,u) f (\x. c))`,
+    REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopy_equivalent]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `h:real^M->real^N`
+     (X_CHOOSE_THEN `k:real^N->real^M` STRIP_ASSUME_TAC)) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(f:real^N->real^P) o (h:real^M->real^N)`) THEN
+    REWRITE_TAC[IMAGE_o] THEN ANTS_TAC THENL
+     [CONJ_TAC THENL [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE; ASM SET_TAC[]] THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^P` THEN DISCH_TAC] THEN
+    SUBGOAL_THEN
+     `homotopic_with (\x. T) (t,u)
+          (((f:real^N->real^P) o h) o (k:real^N->real^M)) ((\x. c) o k)`
+    MP_TAC THENL
+     [MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+      EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[];
+      GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [o_DEF] THEN
+      REWRITE_TAC[] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HOMOTOPIC_WITH_TRANS) THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM(CONJUNCT2(SPEC_ALL I_O_ID))] THEN
+      REWRITE_TAC[GSYM o_ASSOC] THEN ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN
+      MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+      EXISTS_TAC `t:real^N->bool` THEN
+      ASM_REWRITE_TAC[]]) in
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ] lemma) THEN
+  ASM_MESON_TAC[HOMOTOPY_EQUIVALENT_SYM]);;
+
+let HOMOTOPY_INVARIANT_CONNECTEDNESS = 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 /\
+        homotopic_with (\x. T) (t,t) (f o g) I /\
+        connected s
+        ==> connected t`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopic_with]) THEN
+  REWRITE_TAC[o_THM; I_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^(1,N)finite_sum->real^N`
+        STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+  `t = IMAGE (h:real^(1,N)finite_sum->real^N) (interval[vec 0,vec 1] PCROSS t)`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC SUBSET_ANTISYM THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[SUBSET; IN_IMAGE] THEN X_GEN_TAC `x:real^N` THEN
+    DISCH_TAC THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+    REWRITE_TAC[EXISTS_IN_PCROSS] THEN
+    ASM_MESON_TAC[ENDS_IN_UNIT_INTERVAL];
+    ALL_TAC] THEN
+  REWRITE_TAC[CONNECTED_IFF_CONNECTED_COMPONENT; IMP_CONJ] THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+  MAP_EVERY X_GEN_TAC [`t1:real^1`; `x1:real^N`] THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`t2:real^1`; `x2:real^N`] THEN STRIP_TAC THEN
+  MATCH_MP_TAC(MESON[CONNECTED_COMPONENT_TRANS; CONNECTED_COMPONENT_SYM]
+    `!a b. (connected_component t a a' /\ connected_component t b b') /\
+           connected_component t a b
+           ==> connected_component t a' b'`) THEN
+  MAP_EVERY EXISTS_TAC
+   [`(h:real^(1,N)finite_sum->real^N) (pastecart (vec 0) x1)`;
+    `(h:real^(1,N)finite_sum->real^N) (pastecart (vec 0) x2)`] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[connected_component] THEN CONJ_TAC THENL
+     [EXISTS_TAC
+       `IMAGE ((h:real^(1,N)finite_sum->real^N) o (\s. pastecart s x1))
+              (interval[vec 0,vec 1])`;
+      EXISTS_TAC
+       `IMAGE ((h:real^(1,N)finite_sum->real^N) o (\s. pastecart s x2))
+              (interval[vec 0,vec 1])`] THEN
+    (CONJ_TAC THENL
+     [MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN
+      REWRITE_TAC[CONNECTED_INTERVAL] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_ID;
+               CONTINUOUS_ON_CONST] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+      ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS];
+      REWRITE_TAC[IMAGE_o] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC IMAGE_SUBSET THEN
+        ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS];
+        CONJ_TAC THEN MATCH_MP_TAC FUN_IN_IMAGE] THEN
+      REWRITE_TAC[IN_IMAGE] THEN ASM_MESON_TAC[ENDS_IN_UNIT_INTERVAL]]);
+    ASM_REWRITE_TAC[connected_component] THEN
+    EXISTS_TAC `IMAGE (f:real^M->real^N) s` THEN
+    ASM_SIMP_TAC[CONNECTED_CONTINUOUS_IMAGE] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_IMAGE] THEN
+    REWRITE_TAC[EXISTS_PASTECART; PASTECART_IN_PCROSS] THEN
+    X_GEN_TAC `y:real^M` THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`vec 1:real^1`; `(f:real^M->real^N) y`] THEN
+    ASM_REWRITE_TAC[ENDS_IN_UNIT_INTERVAL] THEN ASM SET_TAC[]]);;
+
+let HOMOTOPY_INVARIANT_PATH_CONNECTEDNESS = 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 /\
+        homotopic_with (\x. T) (t,t) (f o g) I /\
+        path_connected s
+        ==> path_connected t`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopic_with]) THEN
+  REWRITE_TAC[o_THM; I_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^(1,N)finite_sum->real^N`
+        STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+  `t = IMAGE (h:real^(1,N)finite_sum->real^N) (interval[vec 0,vec 1] PCROSS t)`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC SUBSET_ANTISYM THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[SUBSET; IN_IMAGE] THEN X_GEN_TAC `x:real^N` THEN
+    DISCH_TAC THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+    REWRITE_TAC[EXISTS_IN_PCROSS] THEN
+    ASM_MESON_TAC[ENDS_IN_UNIT_INTERVAL];
+    ALL_TAC] THEN
+  REWRITE_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT; IMP_CONJ] THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+  MAP_EVERY X_GEN_TAC [`t1:real^1`; `x1:real^N`] THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`t2:real^1`; `x2:real^N`] THEN STRIP_TAC THEN
+  MATCH_MP_TAC(MESON[PATH_COMPONENT_TRANS; PATH_COMPONENT_SYM]
+    `!a b. (path_component t a a' /\ path_component t b b') /\
+           path_component t a b
+           ==> path_component t a' b'`) THEN
+  MAP_EVERY EXISTS_TAC
+   [`(h:real^(1,N)finite_sum->real^N) (pastecart (vec 0) x1)`;
+    `(h:real^(1,N)finite_sum->real^N) (pastecart (vec 0) x2)`] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[PATH_COMPONENT] THEN CONJ_TAC THENL
+     [EXISTS_TAC
+       `IMAGE ((h:real^(1,N)finite_sum->real^N) o (\s. pastecart s x1))
+              (interval[vec 0,vec 1])`;
+      EXISTS_TAC
+       `IMAGE ((h:real^(1,N)finite_sum->real^N) o (\s. pastecart s x2))
+              (interval[vec 0,vec 1])`] THEN
+    (CONJ_TAC THENL
+     [MATCH_MP_TAC PATH_CONNECTED_CONTINUOUS_IMAGE THEN
+      REWRITE_TAC[PATH_CONNECTED_INTERVAL] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_ID;
+               CONTINUOUS_ON_CONST] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+      ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS];
+      REWRITE_TAC[IMAGE_o] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC IMAGE_SUBSET THEN
+        ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS];
+        CONJ_TAC THEN MATCH_MP_TAC FUN_IN_IMAGE] THEN
+      REWRITE_TAC[IN_IMAGE] THEN ASM_MESON_TAC[ENDS_IN_UNIT_INTERVAL]]);
+    ASM_REWRITE_TAC[PATH_COMPONENT] THEN
+    EXISTS_TAC `IMAGE (f:real^M->real^N) s` THEN
+    ASM_SIMP_TAC[PATH_CONNECTED_CONTINUOUS_IMAGE] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_IMAGE] THEN
+    REWRITE_TAC[EXISTS_PASTECART; PASTECART_IN_PCROSS] THEN
+    X_GEN_TAC `y:real^M` THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`vec 1:real^1`; `(f:real^M->real^N) y`] THEN
+    ASM_REWRITE_TAC[ENDS_IN_UNIT_INTERVAL] THEN ASM SET_TAC[]]);;
+
+let HOMOTOPY_EQUIVALENT_CONNECTEDNESS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homotopy_equivalent t ==> (connected s <=> connected t)`,
+  REWRITE_TAC[homotopy_equivalent] THEN REPEAT STRIP_TAC THEN
+  EQ_TAC THEN MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ]
+   (REWRITE_RULE[CONJ_ASSOC] HOMOTOPY_INVARIANT_CONNECTEDNESS)) THEN
+  ASM_MESON_TAC[]);;
+
+let HOMOTOPY_EQUIVALENT_PATH_CONNECTEDNESS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homotopy_equivalent t ==> (path_connected s <=> path_connected t)`,
+  REWRITE_TAC[homotopy_equivalent] THEN REPEAT STRIP_TAC THEN
+  EQ_TAC THEN MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ]
+   (REWRITE_RULE[CONJ_ASSOC] HOMOTOPY_INVARIANT_PATH_CONNECTEDNESS)) THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Contractible sets.                                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let contractible = new_definition
+ `contractible s <=> ?a. homotopic_with (\x. T) (s,s) (\x. x) (\x. a)`;;
+
+let CONTRACTIBLE_IMP_SIMPLY_CONNECTED = prove
+ (`!s:real^N->bool. contractible s ==> simply_connected s`,
+  GEN_TAC THEN REWRITE_TAC[contractible] THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[SIMPLY_CONNECTED_EMPTY] THEN
+  ASM_REWRITE_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_ALL] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+  DISCH_TAC THEN REWRITE_TAC[homotopic_loops; PCROSS] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET) THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; DISCH_TAC] THEN
+  X_GEN_TAC `p:real^1->real^N` THEN
+  REWRITE_TAC[path; path_image; pathfinish; pathstart] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopic_with]) THEN
+  REWRITE_TAC[homotopic_with; SUBSET; FORALL_IN_IMAGE; PCROSS] THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^(1,N)finite_sum->real^N`
+    STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(h o (\y. pastecart (fstcart y) (p(sndcart y):real^N)))
+              :real^(1,1)finite_sum->real^N` THEN
+  ASM_SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART; linepath; o_THM] THEN
+  CONJ_TAC THENL [ALL_TAC; CONV_TAC VECTOR_ARITH] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE [IMP_CONJ]
+     CONTINUOUS_ON_SUBSET)) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+  ASM_SIMP_TAC[IN_ELIM_PASTECART_THM; FSTCART_PASTECART; SNDCART_PASTECART]);;
+
+let CONTRACTIBLE_IMP_CONNECTED = prove
+ (`!s:real^N->bool. contractible s ==> connected s`,
+  SIMP_TAC[CONTRACTIBLE_IMP_SIMPLY_CONNECTED;
+           SIMPLY_CONNECTED_IMP_CONNECTED]);;
+
+let CONTRACTIBLE_IMP_PATH_CONNECTED = prove
+ (`!s:real^N->bool. contractible s ==> path_connected s`,
+  SIMP_TAC[CONTRACTIBLE_IMP_SIMPLY_CONNECTED;
+           SIMPLY_CONNECTED_IMP_PATH_CONNECTED]);;
+
+let NULLHOMOTOPIC_THROUGH_CONTRACTIBLE = 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 /\
+        contractible t
+        ==> ?c. homotopic_with (\h. T) (s,u) (g o f) (\x. c)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [contractible]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N` MP_TAC) THEN
+  DISCH_THEN(MP_TAC o ISPECL [`g:real^N->real^P`; `u:real^P->bool`] o MATCH_MP
+   (ONCE_REWRITE_RULE[IMP_CONJ] HOMOTOPIC_COMPOSE_CONTINUOUS_LEFT)) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(MP_TAC o ISPECL [`f:real^M->real^N`; `s:real^M->bool`] o MATCH_MP
+   (ONCE_REWRITE_RULE[IMP_CONJ] HOMOTOPIC_COMPOSE_CONTINUOUS_RIGHT)) THEN
+  ASM_REWRITE_TAC[o_DEF] THEN DISCH_TAC THEN
+  EXISTS_TAC `(g:real^N->real^P) b` THEN ASM_REWRITE_TAC[]);;
+
+let NULLHOMOTOPIC_INTO_CONTRACTIBLE = prove
+ (`!f:real^M->real^N s t.
+        f continuous_on s /\ IMAGE f s SUBSET t /\ contractible t
+        ==> ?c. homotopic_with (\h. T) (s,t) f (\x. c)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(f:real^M->real^N) = (\x. x) o f` SUBST1_TAC THENL
+   [REWRITE_TAC[o_THM; FUN_EQ_THM];
+    MATCH_MP_TAC NULLHOMOTOPIC_THROUGH_CONTRACTIBLE THEN
+    EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[CONTINUOUS_ON_ID] THEN
+    SET_TAC[]]);;
+
+let NULLHOMOTOPIC_FROM_CONTRACTIBLE = prove
+ (`!f:real^M->real^N s t.
+        f continuous_on s /\ IMAGE f s SUBSET t /\ contractible s
+        ==> ?c. homotopic_with (\h. T) (s,t) f (\x. c)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(f:real^M->real^N) = f o (\x. x)` SUBST1_TAC THENL
+   [REWRITE_TAC[o_THM; FUN_EQ_THM];
+    MATCH_MP_TAC NULLHOMOTOPIC_THROUGH_CONTRACTIBLE THEN
+    EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[CONTINUOUS_ON_ID] THEN
+    SET_TAC[]]);;
+
+let HOMOTOPIC_THROUGH_CONTRACTIBLE = prove
+ (`!f1:real^M->real^N g1:real^N->real^P f2 g2 s t u.
+        f1 continuous_on s /\ IMAGE f1 s SUBSET t /\
+        g1 continuous_on t /\ IMAGE g1 t SUBSET u /\
+        f2 continuous_on s /\ IMAGE f2 s SUBSET t /\
+        g2 continuous_on t /\ IMAGE g2 t SUBSET u /\
+        contractible t /\ path_connected u
+        ==> homotopic_with (\h. T) (s,u) (g1 o f1) (g2 o f2)`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`f1:real^M->real^N`; `g1:real^N->real^P`; `s:real^M->bool`;
+    `t:real^N->bool`; `u:real^P->bool`]
+    NULLHOMOTOPIC_THROUGH_CONTRACTIBLE) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `c1:real^P` THEN
+  DISCH_THEN(fun th -> ASSUME_TAC(MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET th) THEN
+                       MP_TAC th) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_TRANS) THEN
+  ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN MP_TAC(ISPECL
+   [`f2:real^M->real^N`; `g2:real^N->real^P`; `s:real^M->bool`;
+    `t:real^N->bool`; `u:real^P->bool`]
+   NULLHOMOTOPIC_THROUGH_CONTRACTIBLE) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `c2:real^P` THEN
+  DISCH_THEN(fun th -> ASSUME_TAC(MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET th) THEN
+                       MP_TAC th) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_TRANS) THEN
+  REWRITE_TAC[HOMOTOPIC_CONSTANT_MAPS] THEN FIRST_X_ASSUM
+   (MP_TAC o GEN_REWRITE_RULE I [PATH_CONNECTED_IFF_PATH_COMPONENT]) THEN
+  ASM SET_TAC[]);;
+
+let HOMOTOPIC_INTO_CONTRACTIBLE = prove
+ (`!f:real^M->real^N g s t.
+        f continuous_on s /\ IMAGE f s SUBSET t /\
+        g continuous_on s /\ IMAGE g s SUBSET t /\
+        contractible t
+        ==> homotopic_with (\h. T) (s,t) f g`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+   `(f:real^M->real^N) = (\x. x) o f /\ (g:real^M->real^N) = (\x. x) o g`
+   (CONJUNCTS_THEN SUBST1_TAC)
+  THENL [REWRITE_TAC[o_THM; FUN_EQ_THM]; ALL_TAC] THEN
+  MATCH_MP_TAC HOMOTOPIC_THROUGH_CONTRACTIBLE THEN
+  EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[CONTINUOUS_ON_ID] THEN
+  ASM_SIMP_TAC[IMAGE_ID; SUBSET_REFL; CONTRACTIBLE_IMP_PATH_CONNECTED]);;
+
+let HOMOTOPIC_FROM_CONTRACTIBLE = prove
+ (`!f:real^M->real^N g s t.
+        f continuous_on s /\ IMAGE f s SUBSET t /\
+        g continuous_on s /\ IMAGE g s SUBSET t /\
+        contractible s /\ path_connected t
+        ==> homotopic_with (\h. T) (s,t) f g`,
+  REPEAT STRIP_TAC THEN
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+   `(f:real^M->real^N) = f o (\x. x) /\ (g:real^M->real^N) = g o (\x. x)`
+   (CONJUNCTS_THEN SUBST1_TAC)
+  THENL [REWRITE_TAC[o_THM; FUN_EQ_THM]; ALL_TAC] THEN
+  MATCH_MP_TAC HOMOTOPIC_THROUGH_CONTRACTIBLE THEN
+  EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[CONTINUOUS_ON_ID] THEN
+  ASM_REWRITE_TAC[IMAGE_ID; SUBSET_REFL]);;
+
+let HOMOTOPY_EQUIVALENT_CONTRACTIBLE_SETS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        contractible s /\ contractible t /\ (s = {} <=> t = {})
+        ==> s homotopy_equivalent t`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT; HOMEOMORPHIC_EMPTY] THEN
+  FIRST_X_ASSUM(X_CHOOSE_TAC `b:real^N` o
+    GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  STRIP_TAC THEN REWRITE_TAC[homotopy_equivalent] THEN
+  FIRST_X_ASSUM(X_CHOOSE_TAC `a:real^M` o
+    GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  EXISTS_TAC `(\x. b):real^M->real^N` THEN
+  EXISTS_TAC `(\y. a):real^N->real^M` THEN
+  REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+  REPLICATE_TAC 2 (CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+  CONJ_TAC THEN MATCH_MP_TAC HOMOTOPIC_INTO_CONTRACTIBLE THEN
+  ASM_REWRITE_TAC[o_DEF; IMAGE_ID; I_DEF; SUBSET_REFL; CONTINUOUS_ON_ID;
+                  CONTINUOUS_ON_CONST] THEN
+  ASM SET_TAC[]);;
+
+let STARLIKE_IMP_CONTRACTIBLE_GEN = prove
+ (`!P s.
+        (!a t. a IN s /\ &0 <= t /\ t <= &1 ==> P(\x. (&1 - t) % x + t % a)) /\
+        starlike s
+        ==> ?a:real^N. homotopic_with P (s,s) (\x. x) (\x. a)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[starlike] THEN ONCE_REWRITE_TAC[SEGMENT_SYM] THEN
+  REWRITE_TAC[segment; SUBSET; FORALL_IN_GSPEC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN STRIP_TAC THEN
+  REWRITE_TAC[homotopic_with; PCROSS] THEN
+  EXISTS_TAC `\y:real^(1,N)finite_sum.
+             (&1 - drop(fstcart y)) % sndcart y +
+             drop(fstcart y) % a` THEN
+  ASM_SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART; DROP_VEC; IN_INTERVAL_1;
+    SUBSET; FORALL_IN_IMAGE; REAL_SUB_RZERO; REAL_SUB_REFL; FORALL_IN_GSPEC;
+    VECTOR_MUL_LZERO; VECTOR_MUL_LID; VECTOR_ADD_LID; VECTOR_ADD_RID] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_ADD THEN CONJ_TAC THEN
+  MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+  SIMP_TAC[o_DEF; LIFT_DROP; ETA_AX; LIFT_SUB; CONTINUOUS_ON_SUB;
+           CONTINUOUS_ON_CONST; LINEAR_CONTINUOUS_ON; ETA_AX;
+           LINEAR_FSTCART; LINEAR_SNDCART]);;
+
+let STARLIKE_IMP_CONTRACTIBLE = prove
+ (`!s:real^N->bool. starlike s ==> contractible s`,
+  SIMP_TAC[contractible; STARLIKE_IMP_CONTRACTIBLE_GEN]);;
+
+let CONTRACTIBLE_UNIV = prove
+ (`contractible(:real^N)`,
+  SIMP_TAC[STARLIKE_IMP_CONTRACTIBLE; STARLIKE_UNIV]);;
+
+let STARLIKE_IMP_SIMPLY_CONNECTED = prove
+ (`!s:real^N->bool. starlike s ==> simply_connected s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTRACTIBLE_IMP_SIMPLY_CONNECTED THEN
+  MATCH_MP_TAC STARLIKE_IMP_CONTRACTIBLE THEN ASM_REWRITE_TAC[]);;
+
+let CONVEX_IMP_SIMPLY_CONNECTED = prove
+ (`!s:real^N->bool. convex s ==> simply_connected s`,
+  MESON_TAC[CONVEX_IMP_STARLIKE; STARLIKE_IMP_SIMPLY_CONNECTED;
+            SIMPLY_CONNECTED_EMPTY]);;
+
+let STARLIKE_IMP_PATH_CONNECTED = prove
+ (`!s:real^N->bool. starlike s ==> path_connected s`,
+  MESON_TAC[STARLIKE_IMP_SIMPLY_CONNECTED;
+            SIMPLY_CONNECTED_IMP_PATH_CONNECTED]);;
+
+let STARLIKE_IMP_CONNECTED = prove
+ (`!s:real^N->bool. starlike s ==> connected s`,
+  MESON_TAC[STARLIKE_IMP_PATH_CONNECTED; PATH_CONNECTED_IMP_CONNECTED]);;
+
+let IS_INTERVAL_SIMPLY_CONNECTED_1 = prove
+ (`!s:real^1->bool. is_interval s <=> simply_connected s`,
+  MESON_TAC[SIMPLY_CONNECTED_IMP_PATH_CONNECTED; IS_INTERVAL_PATH_CONNECTED_1;
+            CONVEX_IMP_SIMPLY_CONNECTED; IS_INTERVAL_CONVEX_1]);;
+
+let CONTRACTIBLE_EMPTY = prove
+ (`contractible {}`,
+  SIMP_TAC[contractible; HOMOTOPIC_WITH; PCROSS_EMPTY; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[CONTINUOUS_ON_EMPTY] THEN SET_TAC[]);;
+
+let CONTRACTIBLE_CONVEX_TWEAK_BOUNDARY_POINTS = prove
+ (`!s t:real^N->bool.
+        convex s /\ relative_interior s SUBSET t /\ t SUBSET closure s
+        ==> contractible t`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[SUBSET_EMPTY; CLOSURE_EMPTY; CONTRACTIBLE_EMPTY] THEN
+  STRIP_TAC THEN MATCH_MP_TAC STARLIKE_IMP_CONTRACTIBLE THEN
+  MATCH_MP_TAC STARLIKE_CONVEX_TWEAK_BOUNDARY_POINTS THEN ASM_MESON_TAC[]);;
+
+let CONVEX_IMP_CONTRACTIBLE = prove
+ (`!s:real^N->bool. convex s ==> contractible s`,
+  MESON_TAC[CONVEX_IMP_STARLIKE; CONTRACTIBLE_EMPTY;
+            STARLIKE_IMP_CONTRACTIBLE]);;
+
+let CONTRACTIBLE_SING = prove
+ (`!a:real^N. contractible {a}`,
+  SIMP_TAC[CONVEX_IMP_CONTRACTIBLE; CONVEX_SING]);;
+
+let IS_INTERVAL_CONTRACTIBLE_1 = prove
+ (`!s:real^1->bool. is_interval s <=> contractible s`,
+  MESON_TAC[CONTRACTIBLE_IMP_PATH_CONNECTED; IS_INTERVAL_PATH_CONNECTED_1;
+            CONVEX_IMP_CONTRACTIBLE; IS_INTERVAL_CONVEX_1]);;
+
+let CONTRACTIBLE_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        contractible s /\ contractible t ==> contractible(s PCROSS t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[contractible; homotopic_with] THEN
+  REWRITE_TAC[IMP_CONJ; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `h:real^(1,M)finite_sum->real^M`] THEN
+  REPEAT DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`b:real^N`; `k:real^(1,N)finite_sum->real^N`] THEN
+  REPEAT DISCH_TAC THEN
+  EXISTS_TAC `pastecart (a:real^M) (b:real^N)` THEN
+  EXISTS_TAC `\z. pastecart
+                   ((h:real^(1,M)finite_sum->real^M)
+                    (pastecart (fstcart z) (fstcart(sndcart z))))
+                   ((k:real^(1,N)finite_sum->real^N)
+                    (pastecart (fstcart z) (sndcart(sndcart z))))` THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; FORALL_PASTECART; PASTECART_IN_PCROSS;
+               FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN CONJ_TAC THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  SIMP_TAC[CONTINUOUS_ON_PASTECART; LINEAR_CONTINUOUS_ON;
+           LINEAR_FSTCART; LINEAR_SNDCART; CONTINUOUS_ON_ID;
+           GSYM o_DEF; CONTINUOUS_ON_COMPOSE] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_PASTECART] THEN
+  SIMP_TAC[PASTECART_IN_PCROSS; FSTCART_PASTECART; SNDCART_PASTECART]);;
+
+let CONTRACTIBLE_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        contractible(s PCROSS t) <=>
+        s = {} \/ t = {} \/ contractible s /\ contractible t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; CONTRACTIBLE_EMPTY] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; CONTRACTIBLE_EMPTY] THEN
+  EQ_TAC THEN REWRITE_TAC[CONTRACTIBLE_PCROSS] THEN
+  REWRITE_TAC[contractible; homotopic_with; LEFT_IMP_EXISTS_THM] THEN
+  SIMP_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_PASTECART; PASTECART_IN_PCROSS] THEN
+  MAP_EVERY X_GEN_TAC
+   [`a:real^M`; `b:real^N`;
+    `h:real^(1,(M,N)finite_sum)finite_sum->real^(M,N)finite_sum`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `(a:real^M) IN s /\ (b:real^N) IN t` STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM PASTECART_IN_PCROSS] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM MEMBER_NOT_EMPTY]) THEN
+    ASM_MESON_TAC[ENDS_IN_UNIT_INTERVAL];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [EXISTS_TAC `a:real^M` THEN
+    EXISTS_TAC
+     `fstcart o
+      (h:real^(1,(M,N)finite_sum)finite_sum->real^(M,N)finite_sum) o
+      (\z. pastecart (fstcart z) (pastecart (sndcart z) b))`;
+    EXISTS_TAC `b:real^N` THEN
+    EXISTS_TAC
+     `sndcart o
+      (h:real^(1,(M,N)finite_sum)finite_sum->real^(M,N)finite_sum) o
+      (\z. pastecart (fstcart z) (pastecart a (sndcart z)))`] THEN
+  ASM_REWRITE_TAC[o_THM; FSTCART_PASTECART; SNDCART_PASTECART;
+                  SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS; o_THM] THEN
+  (CONJ_TAC THENL
+    [ALL_TAC;  ASM_MESON_TAC[PASTECART_FST_SND; PASTECART_IN_PCROSS]]) THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_CONST;
+           LINEAR_CONTINUOUS_ON; LINEAR_FSTCART; LINEAR_SNDCART] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+  ASM_SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART; PASTECART_IN_PCROSS]);;
+
+let HOMOTOPY_EQUIVALENT_EMPTY = prove
+ (`(!s. (s:real^M->bool) homotopy_equivalent ({}:real^N->bool) <=> s = {}) /\
+   (!t. ({}:real^M->bool) homotopy_equivalent (t:real^N->bool) <=> t = {})`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  SIMP_TAC[HOMOTOPY_EQUIVALENT_CONTRACTIBLE_SETS; CONTRACTIBLE_EMPTY] THEN
+  REWRITE_TAC[homotopy_equivalent] THEN SET_TAC[]);;
+
+let HOMOTOPY_EQUIVALENT_CONTRACTIBILITY = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homotopy_equivalent t ==> (contractible s <=> contractible t)`,
+  let lemma = prove
+   (`!s:real^M->bool t:real^N->bool.
+          s homotopy_equivalent t /\ contractible s ==> contractible t`,
+    REPEAT GEN_TAC THEN SIMP_TAC[homotopy_equivalent; contractible; I_DEF] THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `f:real^M->real^N` (X_CHOOSE_THEN `g:real^N->real^M`
+          STRIP_ASSUME_TAC))
+     (X_CHOOSE_TAC `a:real^M`)) THEN
+    MP_TAC(ISPECL [`f:real^M->real^N`; `s:real^M->bool`; `t:real^N->bool`]
+          NULLHOMOTOPIC_FROM_CONTRACTIBLE) THEN
+    ASM_REWRITE_TAC[contractible; I_DEF] THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:real^N` THEN
+    ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN DISCH_TAC THEN
+    MATCH_MP_TAC HOMOTOPIC_WITH_TRANS THEN
+    EXISTS_TAC `(f:real^M->real^N) o (g:real^N->real^M)` THEN
+    ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `(\x. (b:real^N)) = (\x. b) o (g:real^N->real^M)`
+    SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+    MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+    EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[]) in
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] lemma) THEN
+  ASM_MESON_TAC[HOMOTOPY_EQUIVALENT_SYM]);;
+
+let HOMOTOPY_EQUIVALENT_SING = prove
+ (`!s:real^M->bool a:real^N.
+        s homotopy_equivalent {a} <=> ~(s = {}) /\ contractible s`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[HOMOTOPY_EQUIVALENT_EMPTY; NOT_INSERT_EMPTY] THEN
+  EQ_TAC THENL
+   [DISCH_THEN(MP_TAC o MATCH_MP HOMOTOPY_EQUIVALENT_CONTRACTIBILITY) THEN
+    REWRITE_TAC[CONTRACTIBLE_SING];
+    DISCH_TAC THEN MATCH_MP_TAC HOMOTOPY_EQUIVALENT_CONTRACTIBLE_SETS THEN
+    ASM_REWRITE_TAC[CONTRACTIBLE_SING; NOT_INSERT_EMPTY]]);;
+
+let HOMEOMORPHIC_CONTRACTIBLE_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homeomorphic t ==> (contractible s <=> contractible t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMOTOPY_EQUIVALENT_CONTRACTIBILITY THEN
+  ASM_SIMP_TAC[HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT]);;
+
+let HOMEOMORPHIC_CONTRACTIBLE = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homeomorphic t /\ contractible s ==> contractible t`,
+  MESON_TAC[HOMEOMORPHIC_CONTRACTIBLE_EQ]);;
+
+let CONTRACTIBLE_TRANSLATION = prove
+ (`!a:real^N s. contractible (IMAGE (\x. a + x) s) <=> contractible s`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC HOMEOMORPHIC_CONTRACTIBLE_EQ THEN
+  ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+  REWRITE_TAC[HOMEOMORPHIC_TRANSLATION]);;
+
+add_translation_invariants [CONTRACTIBLE_TRANSLATION];;
+
+let CONTRACTIBLE_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (contractible (IMAGE f s) <=> contractible s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMEOMORPHIC_CONTRACTIBLE_EQ THEN
+  ASM_MESON_TAC[HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_LEFT_EQ;
+                HOMEOMORPHIC_REFL]);;
+
+add_linear_invariants [CONTRACTIBLE_INJECTIVE_LINEAR_IMAGE];;
+
+(* ------------------------------------------------------------------------- *)
+(* Homeomorphisms between punctured spheres and affine sets.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMEOMORPHIC_PUNCTURED_AFFINE_SPHERE_AFFINE = prove
+ (`!a r b t:real^N->bool p:real^M->bool.
+        &0 < r /\ b IN sphere(a,r) /\ affine t /\ a IN t /\ b IN t /\
+        affine p /\ aff_dim t = aff_dim p + &1
+        ==> ((sphere(a:real^N,r) INTER t) DELETE b) homeomorphic p`,
+  GEOM_ORIGIN_TAC `a:real^N` THEN REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET] THEN
+  REWRITE_TAC[sphere; DIST_0; IN_ELIM_THM] THEN
+  SIMP_TAC[CONJ_ASSOC; NORM_ARITH
+   `&0 < r /\ norm(b:real^N) = r <=> norm(b) = r /\ ~(b = vec 0)`] THEN
+  GEOM_NORMALIZE_TAC `b:real^N` THEN REWRITE_TAC[] THEN
+  GEOM_BASIS_MULTIPLE_TAC 1 `b:real^N` THEN
+  SIMP_TAC[NORM_MUL; real_abs; NORM_BASIS; LE_REFL; DIMINDEX_GE_1] THEN
+  X_GEN_TAC `b:real` THEN REWRITE_TAC[REAL_MUL_RID; VECTOR_MUL_EQ_0] THEN
+  DISCH_THEN(K ALL_TAC) THEN DISCH_THEN SUBST1_TAC THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[VECTOR_MUL_LID] THEN
+  ASM_CASES_TAC `r = &1` THEN ASM_REWRITE_TAC[] THEN POP_ASSUM(K ALL_TAC) THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  SIMP_TAC[BASIS_NONZERO; DIMINDEX_GE_1; LE_REFL] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `subspace(t:real^N->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[AFFINE_EQ_SUBSPACE]; ALL_TAC] THEN
+  TRANS_TAC HOMEOMORPHIC_TRANS `{x:real^N | x$1 = &0} INTER t` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC HOMEOMORPHIC_AFFINE_SETS THEN
+    ASM_SIMP_TAC[AFFINE_INTER; AFFINE_STANDARD_HYPERPLANE] THEN
+    ONCE_REWRITE_TAC[INTER_COMM] THEN
+    MP_TAC(ISPECL [`basis 1:real^N`; `&0`; `t:real^N->bool`]
+        AFF_DIM_AFFINE_INTER_HYPERPLANE) THEN
+    ASM_SIMP_TAC[DOT_BASIS; DIMINDEX_GE_1; LE_REFL] THEN
+    DISCH_THEN SUBST1_TAC THEN
+    SUBGOAL_THEN `~(t INTER {x:real^N | x$1 = &0} = {})` ASSUME_TAC THENL
+     [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER; IN_ELIM_THM] THEN
+      EXISTS_TAC `vec 0:real^N` THEN ASM_REWRITE_TAC[VEC_COMPONENT];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `~(t SUBSET {v:real^N | v$1 = &0})` ASSUME_TAC THENL
+     [REWRITE_TAC[SUBSET] THEN DISCH_THEN(MP_TAC o SPEC `basis 1:real^N`) THEN
+      ASM_SIMP_TAC[IN_ELIM_THM; BASIS_COMPONENT; DIMINDEX_GE_1; LE_REFL] THEN
+      REAL_ARITH_TAC;
+      ASM_REWRITE_TAC[] THEN INT_ARITH_TAC]] THEN
+  SUBGOAL_THEN
+   `({x:real^N | norm x = &1} INTER t) DELETE (basis 1) =
+    {x | norm x = &1 /\ ~(x$1 = &1)} INTER t`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `s DELETE a = s' ==> (s INTER t) DELETE a = s' INTER t`) THEN
+    MATCH_MP_TAC(SET_RULE
+     `Q a /\ (!x. P x /\ Q x ==> x = a)
+      ==> {x | P x} DELETE a = {x | P x /\ ~Q x}`) THEN
+    SIMP_TAC[BASIS_COMPONENT; CART_EQ; DIMINDEX_GE_1; LE_REFL] THEN
+    REWRITE_TAC[NORM_EQ_SQUARE; REAL_POS; REAL_POW_ONE] THEN
+    X_GEN_TAC `x:real^N` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    ASM_SIMP_TAC[dot; SUM_CLAUSES_LEFT; DIMINDEX_GE_1] THEN
+    REWRITE_TAC[REAL_ARITH `&1 * &1 + s = &1 <=> s = &0`] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+      SUM_POS_EQ_0_NUMSEG)) THEN
+    REWRITE_TAC[REAL_LE_SQUARE; REAL_ENTIRE] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[homeomorphic; HOMEOMORPHISM] THEN MAP_EVERY ABBREV_TAC
+   [`f = \x:real^N. &2 % basis 1 + &2 / (&1 - x$1) % (x - basis 1)`;
+    `g = \y:real^N.
+           basis 1 + &4 / (norm y pow 2 + &4) % (y - &2 % basis 1)`] THEN
+  MAP_EVERY EXISTS_TAC [`f:real^N->real^N`; `g:real^N->real^N`] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC(MESON[CONTINUOUS_ON_SUBSET; INTER_SUBSET]
+     `f continuous_on s ==> f continuous_on (s INTER t)`) THEN
+    EXPAND_TAC "f" THEN MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+    SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+    REWRITE_TAC[o_DEF; real_div; LIFT_CMUL] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CMUL THEN
+    MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
+    SIMP_TAC[REAL_SUB_0; IN_ELIM_THM] THEN
+    REWRITE_TAC[LIFT_SUB] THEN MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_LIFT_COMPONENT THEN
+    REWRITE_TAC[LE_REFL; DIMINDEX_GE_1];
+    MATCH_MP_TAC(SET_RULE
+     `IMAGE f s SUBSET s' /\ IMAGE f t SUBSET t
+      ==> IMAGE f (s INTER t) SUBSET (s' INTER t)`) THEN
+    EXPAND_TAC "f" THEN REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    ASM_SIMP_TAC[SUBSPACE_ADD; SUBSPACE_MUL; SUBSPACE_SUB] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_DELETE] THEN
+    SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; BASIS_COMPONENT;
+             LE_REFL; DIMINDEX_GE_1; VECTOR_SUB_COMPONENT] THEN
+    CONV_TAC REAL_FIELD;
+    MATCH_MP_TAC(MESON[CONTINUOUS_ON_SUBSET; INTER_SUBSET]
+     `f continuous_on s ==> f continuous_on (s INTER t)`) THEN
+    EXPAND_TAC "g" THEN MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+    SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+    REWRITE_TAC[o_DEF; real_div; LIFT_CMUL] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CMUL THEN
+    MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
+    SIMP_TAC[LIFT_ADD; REAL_POW_LE; NORM_POS_LE; REAL_ARITH
+     `&0 <= x ==> ~(x + &4 = &0)`] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
+    REWRITE_TAC[REAL_POW_2; LIFT_CMUL; CONTINUOUS_ON_CONST] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+    REWRITE_TAC[CONTINUOUS_ON_LIFT_NORM; GSYM o_DEF];
+    MATCH_MP_TAC(SET_RULE
+     `IMAGE f s SUBSET s' /\ IMAGE f t SUBSET t
+      ==> IMAGE f (s INTER t) SUBSET (s' INTER t)`) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+    REWRITE_TAC[NORM_EQ_SQUARE; REAL_POS] THEN EXPAND_TAC "g" THEN
+    CONJ_TAC THENL
+     [ALL_TAC; ASM_MESON_TAC[SUBSPACE_ADD; SUBSPACE_MUL; SUBSPACE_SUB]] THEN
+    X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+    REWRITE_TAC[VECTOR_ARITH
+     `b + a % (y - &2 % b):real^N = (&1 - &2 * a) % b + a % y`] THEN
+    REWRITE_TAC[NORM_POW_2; VECTOR_ARITH
+     `(a + b:real^N) dot (a + b) = (a dot a + b dot b) + &2 * a dot b`] THEN
+    ASM_SIMP_TAC[DOT_LMUL; DOT_RMUL; DOT_BASIS; BASIS_COMPONENT; LE_REFL;
+                VECTOR_ADD_COMPONENT; DIMINDEX_GE_1; VECTOR_MUL_COMPONENT] THEN
+    REWRITE_TAC[REAL_MUL_RZERO; REAL_MUL_RID; GSYM REAL_POW_2] THEN
+    SUBGOAL_THEN `~((y:real^N) dot y + &4 = &0)` MP_TAC THENL
+     [MESON_TAC[DOT_POS_LE; REAL_ARITH `&0 <= x ==> ~(x + &4 = &0)`];
+      CONV_TAC REAL_FIELD];
+    SUBGOAL_THEN
+     `!x. norm x = &1 /\ ~(x$1 = &1)
+          ==> norm((f:real^N->real^N) x) pow 2 = &4 * (&1 + x$1) / (&1 - x$1)`
+    ASSUME_TAC THENL
+     [REPEAT STRIP_TAC THEN EXPAND_TAC "f" THEN
+      REWRITE_TAC[VECTOR_ARITH
+       `a % b + m % (x - b):real^N = (a - m) % b + m % x`] THEN
+      REWRITE_TAC[NORM_POW_2; VECTOR_ARITH
+       `(a + b:real^N) dot (a + b) = (a dot a + b dot b) + &2 * a dot b`] THEN
+      SIMP_TAC[DOT_LMUL; DOT_RMUL; DOT_BASIS; BASIS_COMPONENT;
+               DIMINDEX_GE_1; LE_REFL; VECTOR_MUL_COMPONENT] THEN
+      ASM_REWRITE_TAC[GSYM NORM_POW_2; GSYM REAL_POW_2; REAL_MUL_RID;
+                      REAL_POW_ONE] THEN
+      UNDISCH_TAC `~((x:real^N)$1 = &1)` THEN CONV_TAC REAL_FIELD;
+      ALL_TAC] THEN
+    EXPAND_TAC "g" THEN REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN
+    ASM_SIMP_TAC[] THEN X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[REAL_FIELD
+     `~(x = &1)
+      ==> &4 * (&1 + x) / (&1 - x) + &4 = &8 / (&1 - x)`] THEN
+    REWRITE_TAC[real_div; REAL_INV_MUL; REAL_INV_INV] THEN
+    REWRITE_TAC[REAL_ARITH `&4 * inv(&8) * x = x / &2`] THEN
+    EXPAND_TAC "f" THEN
+    REWRITE_TAC[VECTOR_ARITH `(a + x) - a:real^N = x`] THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC; VECTOR_ARITH
+     `b + a % (x - b):real^N = x <=> (&1 - a) % (x - b) = vec 0`] THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0] THEN DISJ1_TAC THEN
+    UNDISCH_TAC `~((x:real^N)$1 = &1)` THEN CONV_TAC REAL_FIELD;
+    X_GEN_TAC `y:real^N` THEN REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN `~((y:real^N) dot y + &4 = &0)` ASSUME_TAC THENL
+     [MESON_TAC[DOT_POS_LE; REAL_ARITH `&0 <= x ==> ~(x + &4 = &0)`];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `((g:real^N->real^N) y)$1 =
+                  (y dot y - &4) / (y dot y + &4)` ASSUME_TAC THENL
+     [EXPAND_TAC "g" THEN REWRITE_TAC[VECTOR_ADD_COMPONENT] THEN
+      REWRITE_TAC[VECTOR_MUL_COMPONENT; VECTOR_SUB_COMPONENT] THEN
+      ASM_SIMP_TAC[BASIS_COMPONENT; LE_REFL; NORM_POW_2; DIMINDEX_GE_1] THEN
+      UNDISCH_TAC `~((y:real^N) dot y + &4 = &0)` THEN
+      CONV_TAC REAL_FIELD;
+      ALL_TAC] THEN
+    EXPAND_TAC "f" THEN REWRITE_TAC[] THEN ASM_REWRITE_TAC[] THEN
+    EXPAND_TAC "g" THEN SIMP_TAC[VECTOR_ARITH `(a + x) - a:real^N = x`] THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC; VECTOR_ARITH
+     `b + a % (x - b):real^N = x <=> (&1 - a) % (x - b) = vec 0`] THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0; NORM_POW_2] THEN DISJ1_TAC THEN
+    UNDISCH_TAC `~((y:real^N) dot y + &4 = &0)` THEN CONV_TAC REAL_FIELD]);;
+
+let HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE_GEN = prove
+ (`!s:real^N->bool t:real^M->bool a.
+        convex s /\ bounded s /\ a IN relative_frontier s /\
+        affine t /\ aff_dim s = aff_dim t + &1
+        ==> (relative_frontier s DELETE a) homeomorphic t`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[AFF_DIM_EMPTY; AFF_DIM_GE; INT_ARITH
+   `--(&1):int <= s ==> ~(--(&1) = s + &1)`] THEN
+  MP_TAC(ISPECL [`(:real^N)`; `aff_dim(s:real^N->bool)`]
+    CHOOSE_AFFINE_SUBSET) THEN REWRITE_TAC[SUBSET_UNIV] THEN
+  REWRITE_TAC[AFF_DIM_GE; AFF_DIM_LE_UNIV; AFF_DIM_UNIV; AFFINE_UNIV] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `~(t:real^N->bool = {})` MP_TAC THENL
+   [ASM_MESON_TAC[AFF_DIM_EQ_MINUS1]; ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM MEMBER_NOT_EMPTY] THEN
+  DISCH_THEN(X_CHOOSE_TAC `z:real^N`) THEN STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`s:real^N->bool`; `ball(z:real^N,&1) INTER t`]
+        HOMEOMORPHIC_RELATIVE_FRONTIERS_CONVEX_BOUNDED_SETS) THEN
+  MP_TAC(ISPECL [`t:real^N->bool`; `ball(z:real^N,&1)`]
+        (ONCE_REWRITE_RULE[INTER_COMM] AFF_DIM_CONVEX_INTER_OPEN)) THEN
+  MP_TAC(ISPECL [`ball(z:real^N,&1)`; `t:real^N->bool`]
+        RELATIVE_FRONTIER_CONVEX_INTER_AFFINE) THEN
+  ASM_SIMP_TAC[CONVEX_INTER; BOUNDED_INTER; BOUNDED_BALL; CONVEX_BALL;
+               AFFINE_IMP_CONVEX; INTERIOR_OPEN; OPEN_BALL;
+               FRONTIER_BALL; REAL_LT_01] THEN
+  SUBGOAL_THEN `~(ball(z:real^N,&1) INTER t = {})` ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+    EXISTS_TAC `z:real^N` THEN ASM_REWRITE_TAC[CENTRE_IN_BALL; REAL_LT_01];
+    ASM_REWRITE_TAC[] THEN REPEAT(DISCH_THEN SUBST1_TAC) THEN SIMP_TAC[]] THEN
+  REWRITE_TAC[homeomorphic; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`h:real^N->real^N`; `k:real^N->real^N`] THEN
+  STRIP_TAC THEN REWRITE_TAC[GSYM homeomorphic] THEN
+  TRANS_TAC HOMEOMORPHIC_TRANS
+    `(sphere(z,&1) INTER t) DELETE (h:real^N->real^N) a` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[homeomorphic] THEN
+    MAP_EVERY EXISTS_TAC [`h:real^N->real^N`; `k:real^N->real^N`] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HOMEOMORPHISM]) THEN
+    REWRITE_TAC[HOMEOMORPHISM] THEN STRIP_TAC THEN REPEAT CONJ_TAC THENL
+     [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; DELETE_SUBSET];
+      ASM SET_TAC[];
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; DELETE_SUBSET];
+      ASM SET_TAC[];
+      ASM SET_TAC[];
+      ASM SET_TAC[]];
+    MATCH_MP_TAC HOMEOMORPHIC_PUNCTURED_AFFINE_SPHERE_AFFINE THEN
+    ASM_REWRITE_TAC[REAL_LT_01; GSYM IN_INTER] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HOMEOMORPHISM]) THEN
+    ASM SET_TAC[]]);;
+
+let HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE = prove
+ (`!a r b:real^N t:real^M->bool.
+    &0 < r /\ b IN sphere(a,r) /\ affine t /\ aff_dim(t) + &1 = &(dimindex(:N))
+    ==> (sphere(a:real^N,r) DELETE b) homeomorphic t`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`cball(a:real^N,r)`; `t:real^M->bool`; `b:real^N`]
+        HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE_GEN) THEN
+  ASM_SIMP_TAC[RELATIVE_FRONTIER_CBALL; REAL_LT_IMP_NZ; AFF_DIM_CBALL;
+               CONVEX_CBALL; BOUNDED_CBALL]);;
+
+let HOMEOMORPHIC_PUNCTURED_SPHERE_HYPERPLANE = prove
+ (`!a r b c d.
+        &0 < r /\ b IN sphere(a,r) /\ ~(c = vec 0)
+        ==> (sphere(a:real^N,r) DELETE b) homeomorphic
+             {x:real^N | c dot x = d}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE THEN
+  ASM_SIMP_TAC[AFFINE_HYPERPLANE; AFF_DIM_HYPERPLANE] THEN INT_ARITH_TAC);;
+
+let HOMEOMORPHIC_PUNCTURED_SPHERE_UNIV = prove
+ (`!a r b.
+        &0 < r /\ b IN sphere(a,r) /\ dimindex(:N) = dimindex(:M) + 1
+        ==> (sphere(a:real^N,r) DELETE b) homeomorphic (:real^M)`,
+  REPEAT STRIP_TAC THEN
+  TRANS_TAC HOMEOMORPHIC_TRANS `{x:real^N | basis 1 dot x = &0}` THEN
+  ASM_SIMP_TAC[HOMEOMORPHIC_HYPERPLANE_UNIV; BASIS_NONZERO; LE_REFL;
+               DIMINDEX_GE_1; HOMEOMORPHIC_PUNCTURED_SPHERE_HYPERPLANE]);;
+
+let CONTRACTIBLE_PUNCTURED_SPHERE = prove
+ (`!a r b:real^N.
+        &0 < r /\ b IN sphere(a,r) ==> contractible(sphere(a,r) DELETE b)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `contractible {x:real^N | basis 1 dot x = &0}` MP_TAC THENL
+   [SIMP_TAC[CONVEX_IMP_CONTRACTIBLE; CONVEX_HYPERPLANE];
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HOMEOMORPHIC_CONTRACTIBLE) THEN
+    ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+    MATCH_MP_TAC HOMEOMORPHIC_PUNCTURED_SPHERE_HYPERPLANE THEN
+    ASM_SIMP_TAC[BASIS_NONZERO; LE_REFL; DIMINDEX_GE_1]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Simple connectedness of a union. This is essentially a stripped-down      *)
+(* version of the Seifert - Van Kampen theorem.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let SIMPLY_CONNECTED_UNION = prove
+ (`!s t:real^N->bool.
+    open_in (subtopology euclidean (s UNION t)) s /\
+    open_in (subtopology euclidean (s UNION t)) t /\
+    simply_connected s /\ simply_connected t /\
+    path_connected (s INTER t) /\ ~(s INTER t = {})
+    ==> simply_connected (s UNION t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_IN_OPEN] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_THEN `u:real^N->bool`
+   (STRIP_ASSUME_TAC o GSYM)) MP_TAC) THEN
+   DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_THEN `v:real^N->bool`
+   (STRIP_ASSUME_TAC o GSYM)) MP_TAC) THEN
+  SIMP_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_PATH; PATH_CONNECTED_UNION] THEN
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(pathstart p:real^N) IN s UNION t` MP_TAC THENL
+   [ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; SUBSET]; REWRITE_TAC[IN_UNION]] THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ o rev) THEN
+  ONCE_REWRITE_TAC[TAUT `p ==> q ==> r <=> q ==> p ==> r`] THEN
+  MAP_EVERY (fun s -> let x = mk_var(s,`:real^N->bool`) in SPEC_TAC(x,x))
+   ["v"; "u"; "t"; "s"] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!s t u v. x IN s ==> P x s t u v) /\
+    (!x s t u v. P x s t u v ==> P x t s v u)
+    ==> (!s t u v. x IN s \/ x IN t ==>  P x s t u v)`) THEN
+  CONJ_TAC THENL
+   [REPEAT STRIP_TAC;
+    REPEAT GEN_TAC THEN REWRITE_TAC[UNION_COMM; INTER_COMM] THEN
+    MATCH_MP_TAC MONO_IMP THEN SIMP_TAC[]] THEN
+  SUBGOAL_THEN
+   `?e. &0 < e /\
+        !x y. x IN interval[vec 0,vec 1] /\ y IN interval[vec 0,vec 1] /\
+              norm(x - y) < e
+              ==> path_image(subpath x y p) SUBSET (s:real^N->bool) \/
+                  path_image(subpath x y p) SUBSET t`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPEC `path_image(p:real^1->real^N)` HEINE_BOREL_LEMMA) THEN
+    ASM_SIMP_TAC[COMPACT_PATH_IMAGE] THEN
+    DISCH_THEN(MP_TAC o SPEC `{u:real^N->bool,v}`) THEN
+    SIMP_TAC[UNIONS_2; EXISTS_IN_INSERT; FORALL_IN_INSERT; NOT_IN_EMPTY] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`p:real^1->real^N`; `interval[vec 0:real^1,vec 1]`]
+        COMPACT_UNIFORMLY_CONTINUOUS) THEN
+    ASM_REWRITE_TAC[GSYM path; COMPACT_INTERVAL; uniformly_continuous_on] THEN
+    DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[dist] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^1`; `y:real^1`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(p:real^1->real^N) x`) THEN
+    ANTS_TAC THENL [REWRITE_TAC[path_image] THEN ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC(SET_RULE
+     `!p'. p SUBSET b /\
+           (s UNION t) INTER u = s /\ (s UNION t) INTER v = t /\
+           p SUBSET p' /\ p' SUBSET s UNION t
+           ==>  (b SUBSET u \/ b SUBSET v) ==> p SUBSET s \/ p SUBSET t`) THEN
+    EXISTS_TAC `path_image(p:real^1->real^N)` THEN
+    ASM_SIMP_TAC[PATH_IMAGE_SUBPATH_SUBSET] THEN
+    REWRITE_TAC[PATH_IMAGE_SUBPATH_GEN; SUBSET; FORALL_IN_IMAGE] THEN
+    SUBGOAL_THEN `segment[x,y] SUBSET ball(x:real^1,d)` MP_TAC THENL
+     [REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+      ASM_REWRITE_TAC[INSERT_SUBSET; CENTRE_IN_BALL] THEN
+      ASM_REWRITE_TAC[IN_BALL; EMPTY_SUBSET; CONVEX_BALL; dist];
+      REWRITE_TAC[IN_BALL; dist; SUBSET] THEN STRIP_TAC THEN
+      X_GEN_TAC `z:real^1` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [SEGMENT_1]) THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1])) THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN
+      ASM_REAL_ARITH_TAC];
+    MP_TAC(SPEC `e:real` REAL_ARCH_INV) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `N:num` THEN STRIP_TAC] THEN
+  SUBGOAL_THEN
+   `!n. n <= N /\ p(lift(&n / &N)) IN s
+        ==> ?q. path(q:real^1->real^N) /\ path_image q SUBSET s /\
+                homotopic_paths (s UNION t)
+                                (subpath (vec 0) (lift(&n / &N)) p) q`
+  MP_TAC THENL
+   [ALL_TAC;
+    DISCH_THEN(MP_TAC o SPEC `N:num`) THEN
+    ASM_SIMP_TAC[REAL_DIV_REFL; REAL_OF_NUM_EQ; LE_REFL; LIFT_NUM] THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[pathfinish]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `q:real^1->real^N` MP_TAC) THEN
+    REWRITE_TAC[SUBPATH_TRIVIAL] THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_PATHS_TRANS) THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHSTART) THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHFINISH) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC HOMOTOPIC_PATHS_SUBSET THEN
+    EXISTS_TAC `s:real^N->bool` THEN
+    ASM_MESON_TAC[SUBSET_UNION]] THEN
+  SUBGOAL_THEN
+   `!n. n < N
+        ==> path_image(subpath (lift(&n / &N)) (lift(&(SUC n) / &N)) p)
+              SUBSET (s:real^N->bool) \/
+            path_image(subpath (lift(&n / &N)) (lift(&(SUC n) / &N)) p)
+              SUBSET t`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP; GSYM LIFT_SUB; DROP_VEC;
+                NORM_REAL; GSYM drop;
+                REAL_ARITH `abs(a / c - b / c) = abs((b - a) / c)`] THEN
+    ASM_SIMP_TAC[GSYM REAL_OF_NUM_SUC; REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ;
+                 REAL_OF_NUM_LT; LE_1; REAL_ARITH `(x + &1) - x = &1`] THEN
+    ASM_REWRITE_TAC[real_div; REAL_MUL_LID; REAL_MUL_LZERO; REAL_ABS_INV;
+      REAL_ABS_NUM; REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+    ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC num_WF THEN X_GEN_TAC `n:num` THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN STRIP_TAC THEN
+  ASM_CASES_TAC `n = 0` THENL
+   [ASM_REWRITE_TAC[REAL_ARITH `&0 / x = &0`; LIFT_NUM] THEN
+    EXISTS_TAC `linepath((p:real^1->real^N)(vec 0),p(vec 0))` THEN
+    REWRITE_TAC[SUBPATH_REFL; HOMOTOPIC_PATHS_REFL] THEN
+    REWRITE_TAC[PATH_LINEPATH; PATH_IMAGE_LINEPATH; SEGMENT_REFL] THEN
+    UNDISCH_TAC `(pathstart p:real^N) IN s` THEN REWRITE_TAC[pathstart] THEN
+    SET_TAC[];
+    ALL_TAC] THEN
+  MP_TAC(ISPEC `\m. m < n /\ (p(lift(&m / &N)):real^N) IN s` num_MAX) THEN
+  REWRITE_TAC[] THEN
+  MATCH_MP_TAC(TAUT `p /\ (q ==> r) ==> (p <=> q) ==> r`) THEN
+  CONJ_TAC THENL
+   [CONJ_TAC THENL [EXISTS_TAC `0`; MESON_TAC[LT_IMP_LE]] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 / x = &0`; LIFT_NUM; LE_1] THEN
+    ASM_MESON_TAC[pathstart];
+    DISCH_THEN(X_CHOOSE_THEN `m:num` STRIP_ASSUME_TAC)] THEN
+  SUBGOAL_THEN
+   `?q. path q /\
+        path_image(q:real^1->real^N) SUBSET s /\
+        homotopic_paths (s UNION t) (subpath (vec 0) (lift (&m / &N)) p) q`
+  STRIP_ASSUME_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!i. m < i /\ i <= n
+        ==> path_image(subpath (lift(&m / &N)) (lift(&i / &N)) p) SUBSET s \/
+            path_image(subpath (lift(&m / &N)) (lift(&i / &N)) p) SUBSET
+                 (t:real^N->bool)`
+  MP_TAC THENL
+   [MATCH_MP_TAC num_INDUCTION THEN REWRITE_TAC[CONJUNCT1 LT] THEN
+    X_GEN_TAC `i:num` THEN DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+    ASM_CASES_TAC `i:num = m` THENL
+     [DISCH_THEN(K ALL_TAC) THEN ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC;
+      ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC]] THEN
+    SUBGOAL_THEN
+     `p(lift(&i / &N)) IN t /\ ~((p(lift(&i / &N)):real^N) IN s)`
+    STRIP_ASSUME_TAC THENL
+     [MATCH_MP_TAC(SET_RULE
+       `x IN s UNION t /\ ~(x IN s) ==> x IN t /\ ~(x IN s)`) THEN
+      CONJ_TAC THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `s SUBSET t ==> x IN s ==> x IN t`)) THEN
+        REWRITE_TAC[path_image] THEN MATCH_MP_TAC FUN_IN_IMAGE THEN
+        REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+        ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT;
+                     LE_1; REAL_MUL_LZERO; REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+        ASM_ARITH_TAC;
+        SUBGOAL_THEN `i < n /\ ~(i:num <= m)` MP_TAC THENL
+         [ASM_ARITH_TAC; ASM_MESON_TAC[]]];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `path_image(subpath (lift(&i / &N)) (lift (&(SUC i) / &N)) p) SUBSET s \/
+      path_image(subpath (lift(&i / &N)) (lift (&(SUC i) / &N)) p) SUBSET
+        (t:real^N->bool)`
+    MP_TAC THENL [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC; ALL_TAC] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `~(x IN s)
+      ==> (x IN p /\ x IN q) /\ (q UNION p = r)
+          ==> p SUBSET s \/ p SUBSET t
+              ==> q SUBSET s \/ q SUBSET t
+                  ==> r SUBSET s \/ r SUBSET t`)) THEN
+    SIMP_TAC[PATH_IMAGE_SUBPATH_GEN; FUN_IN_IMAGE; ENDS_IN_SEGMENT] THEN
+    REWRITE_TAC[GSYM IMAGE_UNION] THEN AP_TERM_TAC THEN
+    MATCH_MP_TAC UNION_SEGMENT THEN
+    ASM_SIMP_TAC[SEGMENT_1; LIFT_DROP; REAL_LE_DIV2_EQ; REAL_OF_NUM_LT;
+                 LE_1; REAL_OF_NUM_LE; LT_IMP_LE; IN_INTERVAL_1] THEN
+    ASM_ARITH_TAC;
+    DISCH_THEN(MP_TAC o SPEC `n:num`) THEN ASM_REWRITE_TAC[LE_REFL]] THEN
+  STRIP_TAC THENL
+   [EXISTS_TAC `(q:real^1->real^N) ++
+                subpath (lift(&m / &N)) (lift (&n / &N)) p` THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC PATH_JOIN_IMP THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHFINISH) THEN
+      ASM_SIMP_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+      DISCH_TAC THEN MATCH_MP_TAC PATH_SUBPATH THEN
+      ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+      ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT;
+                   LE_1; REAL_MUL_LZERO; REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+      ASM_ARITH_TAC;
+      MATCH_MP_TAC SUBSET_PATH_IMAGE_JOIN THEN ASM_REWRITE_TAC[];
+      MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+      EXISTS_TAC `subpath (vec 0) (lift(&m / &N)) (p:real^1->real^N) ++
+                  subpath (lift(&m / &N)) (lift(&n / &N)) p` THEN
+      CONJ_TAC THENL
+       [ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+        MATCH_MP_TAC HOMOTOPIC_JOIN_SUBPATHS THEN
+        ASM_REWRITE_TAC[ENDS_IN_UNIT_INTERVAL];
+        MATCH_MP_TAC HOMOTOPIC_PATHS_JOIN THEN
+        ASM_REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+        MATCH_MP_TAC HOMOTOPIC_PATHS_SUBSET THEN
+        EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[SUBSET_UNION] THEN
+        ASM_REWRITE_TAC[HOMOTOPIC_PATHS_REFL] THEN
+        MATCH_MP_TAC PATH_SUBPATH] THEN
+      ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+      ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT;
+                   LE_1; REAL_MUL_LZERO; REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+      ASM_ARITH_TAC];
+    SUBGOAL_THEN
+     `(p(lift(&m / &N)):real^N) IN t /\ (p(lift(&n / &N)):real^N) IN t`
+    STRIP_ASSUME_TAC THENL
+     [ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; PATHFINISH_IN_PATH_IMAGE;
+                    PATHSTART_SUBPATH; PATHFINISH_SUBPATH; SUBSET];
+      ALL_TAC] THEN
+    UNDISCH_TAC `path_connected(s INTER t:real^N->bool)` THEN
+    REWRITE_TAC[path_connected] THEN DISCH_THEN(MP_TAC o SPECL
+     [`p(lift(&m / &N)):real^N`; `p(lift(&n / &N)):real^N`]) THEN
+    ASM_REWRITE_TAC[IN_INTER; SUBSET_INTER] THEN
+    DISCH_THEN(X_CHOOSE_THEN `r:real^1->real^N` STRIP_ASSUME_TAC) THEN
+    UNDISCH_THEN
+     `!p. path p /\ path_image p SUBSET t /\ pathfinish p:real^N = pathstart p
+          ==> homotopic_paths t p (linepath (pathstart p,pathstart p))`
+     (MP_TAC o SPEC `subpath (lift(&m / &N)) (lift(&n / &N)) p ++
+                     reversepath(r:real^1->real^N)`) THEN
+    ASM_REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH;
+                PATHSTART_JOIN; PATHFINISH_JOIN; PATHFINISH_REVERSEPATH] THEN
+    ANTS_TAC THENL
+     [ASM_SIMP_TAC[SUBSET_PATH_IMAGE_JOIN; PATH_IMAGE_REVERSEPATH] THEN
+      MATCH_MP_TAC PATH_JOIN_IMP THEN
+      ASM_SIMP_TAC[PATH_REVERSEPATH; PATHFINISH_SUBPATH;
+                   PATHSTART_REVERSEPATH] THEN
+      MATCH_MP_TAC PATH_SUBPATH THEN
+      ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+      ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT;
+                   LE_1; REAL_MUL_LZERO; REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+      ASM_ARITH_TAC;
+      ALL_TAC] THEN
+     DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        HOMOTOPIC_PATHS_IMP_HOMOTOPIC_LOOPS)) THEN
+     ASM_REWRITE_TAC[PATHFINISH_LINEPATH; PATHSTART_SUBPATH;
+       PATHSTART_JOIN; PATHFINISH_JOIN; PATHFINISH_REVERSEPATH] THEN
+     DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        HOMOTOPIC_PATHS_LOOP_PARTS)) THEN
+     FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHSTART) THEN
+     FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHFINISH) THEN
+     REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+     REPLICATE_TAC 2 (DISCH_THEN(ASSUME_TAC o SYM)) THEN
+     ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+     EXISTS_TAC `(q:real^1->real^N) ++ r` THEN
+     ASM_SIMP_TAC[PATH_JOIN; PATH_IMAGE_JOIN; UNION_SUBSET] THEN
+     MATCH_MP_TAC HOMOTOPIC_PATHS_TRANS THEN
+     EXISTS_TAC `subpath (vec 0) (lift(&m / &N)) (p:real^1->real^N) ++
+                 subpath (lift(&m / &N)) (lift(&n / &N)) p` THEN
+     CONJ_TAC THENL
+      [ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN
+       MATCH_MP_TAC HOMOTOPIC_JOIN_SUBPATHS THEN
+       ASM_REWRITE_TAC[ENDS_IN_UNIT_INTERVAL] THEN
+       ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+       ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT;
+                    LE_1; REAL_MUL_LZERO; REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+       ASM_ARITH_TAC;
+       MATCH_MP_TAC HOMOTOPIC_PATHS_JOIN THEN
+       ASM_REWRITE_TAC[PATHSTART_SUBPATH; PATHFINISH_SUBPATH] THEN
+       MATCH_MP_TAC HOMOTOPIC_PATHS_SUBSET THEN
+       EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[SUBSET_UNION]]]);;
+
+let SIMPLY_CONNECTED_SPHERE = prove
+ (`!a:real^N r. 3 <= dimindex(:N) ==> simply_connected(sphere(a,r))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[sphere] THEN GEOM_ORIGIN_TAC `a:real^N` THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[DIST_0] THEN
+  ASM_CASES_TAC `r < &0` THENL
+   [ASM_SIMP_TAC[NORM_ARITH `r < &0 ==> ~(norm(x:real^N) = r)`] THEN
+    REWRITE_TAC[EMPTY_GSPEC; SIMPLY_CONNECTED_EMPTY];
+    RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LT])] THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `b:real^N` (SUBST1_TAC o SYM) o
+        MATCH_MP VECTOR_CHOOSE_SIZE) THEN
+  UNDISCH_THEN `&0 <= r` (K ALL_TAC) THEN POP_ASSUM MP_TAC THEN
+  GEOM_NORMALIZE_TAC `b:real^N` THEN REWRITE_TAC[] THEN
+  REWRITE_TAC[NORM_EQ_0; SING_GSPEC; NORM_0] THEN
+  SIMP_TAC[CONVEX_SING; CONVEX_IMP_SIMPLY_CONNECTED] THEN
+  X_GEN_TAC `bbb:real^N` THEN DISCH_THEN(K ALL_TAC) THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `{x:real^N | norm x = &1} =
+    {x | norm x = &1} DELETE (basis 1) UNION
+    {x | norm x = &1} DELETE (--(basis 1))`
+   (fun th -> SUBST1_TAC th THEN ASSUME_TAC(SYM th))
+  THENL
+   [MATCH_MP_TAC(SET_RULE
+     `~(x = y) ==> s = s DELETE x UNION s DELETE y`) THEN
+    REWRITE_TAC[VECTOR_ARITH `x:real^N = --x <=> x = vec 0`] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ; BASIS_NONZERO;
+                 DIMINDEX_GE_1; LE_REFL];
+    ALL_TAC] THEN
+  MATCH_MP_TAC SIMPLY_CONNECTED_UNION THEN
+  ASM_SIMP_TAC[TAUT `p /\ q /\ r /\ s /\ t <=> (p /\ q) /\ (r /\ s) /\ t`] THEN
+  CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[SET_RULE `s DELETE x = s INTER (UNIV DELETE x)`] THEN
+    CONJ_TAC THEN MATCH_MP_TAC OPEN_IN_INTER_OPEN THEN
+    SIMP_TAC[OPEN_DELETE; OPEN_UNIV; OPEN_IN_SUBTOPOLOGY_REFL] THEN
+    REWRITE_TAC[SUBSET_UNIV; TOPSPACE_EUCLIDEAN];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC CONTRACTIBLE_IMP_SIMPLY_CONNECTED THEN
+    ONCE_REWRITE_TAC[NORM_ARITH `norm(x:real^N) = dist(vec 0,x)`] THEN
+    REWRITE_TAC[GSYM sphere] THEN
+    MATCH_MP_TAC CONTRACTIBLE_PUNCTURED_SPHERE THEN
+    SIMP_TAC[IN_SPHERE; DIST_0; NORM_BASIS; DIMINDEX_GE_1;
+             LE_REFL; REAL_LT_01; NORM_NEG];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER; IN_DELETE] THEN
+    EXISTS_TAC `basis 2:real^N` THEN
+    ASM_SIMP_TAC[IN_ELIM_THM; NORM_MUL; NORM_BASIS; ARITH;
+                 ARITH_RULE `3 <= n ==> 2 <= n`] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < r ==> abs r * &1 = r`] THEN
+    CONJ_TAC THEN DISCH_THEN(MP_TAC o AP_TERM `\x:real^N. x$1`) THEN
+    ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; VECTOR_NEG_COMPONENT; BASIS_COMPONENT;
+                 ARITH; DIMINDEX_GE_1] THEN
+    ASM_REAL_ARITH_TAC] THEN
+  SUBGOAL_THEN
+   `({x:real^N | norm x = &1} DELETE basis 1) INTER
+    ({x | norm x = &1} DELETE --basis 1) =
+    ({x:real^N | norm x = &1} DELETE basis 1) INTER {x | &0 <= x$1} UNION
+    ({x:real^N | norm x = &1} DELETE --basis 1) INTER {x | x$1 <= &0}`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `t UNION u = UNIV /\ ~(b IN u) /\ ~(c IN t)
+      ==> (s DELETE b) INTER (s DELETE c) =
+          (s DELETE b) INTER t UNION (s DELETE c) INTER u`) THEN
+    SIMP_TAC[IN_ELIM_THM; EXTENSION; IN_UNION; IN_UNIV; BASIS_COMPONENT;
+             DIMINDEX_GE_1; LE_REFL; VECTOR_NEG_COMPONENT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC PATH_CONNECTED_UNION THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `basis 2:real^N` THEN
+    ASM_SIMP_TAC[IN_INTER; IN_DELETE; IN_ELIM_THM; NORM_BASIS; BASIS_NE; ARITH;
+      BASIS_COMPONENT; ARITH_RULE `3 <= n ==> 1 <= n /\ 2 <= n`] THEN
+    REWRITE_TAC[REAL_LE_REFL] THEN
+    DISCH_THEN(MP_TAC o AP_TERM `\x:real^N. x$1`) THEN
+    ASM_SIMP_TAC[VECTOR_NEG_COMPONENT; BASIS_COMPONENT;
+                 ARITH; ARITH_RULE `3 <= n ==> 1 <= n /\ 2 <= n`] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV] THEN
+  SUBGOAL_THEN
+   `path_connected((cball(vec 0,&1) INTER {x:real^N | x$1 = &0}) DELETE
+                   (vec 0))`
+  MP_TAC THENL
+   [REWRITE_TAC[SET_RULE `s DELETE a = s DIFF {a}`] THEN
+    MATCH_MP_TAC PATH_CONNECTED_CONVEX_DIFF_CARD_LT THEN
+    SIMP_TAC[CARD_LT_FINITE_INFINITE; FINITE_SING; real_INFINITE] THEN
+    SIMP_TAC[CONVEX_INTER; CONVEX_CBALL; CONVEX_STANDARD_HYPERPLANE] THEN
+    DISCH_THEN(MP_TAC o
+      SPEC `{vec 0:real^N,basis 2,basis 3}` o
+      MATCH_MP (REWRITE_RULE [IMP_CONJ] COLLINEAR_SUBSET)) THEN
+    REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; IN_INTER; IN_CBALL_0;
+                IN_ELIM_THM; NORM_0; VEC_COMPONENT; REAL_POS] THEN
+    ASM_SIMP_TAC[NORM_BASIS; BASIS_COMPONENT; ARITH; REAL_LE_REFL;
+                 ARITH_RULE `3 <= n ==> 1 <= n /\ 2 <= n`;
+                 COLLINEAR_3_AFFINE_HULL; BASIS_NONZERO] THEN
+    REWRITE_TAC[AFFINE_HULL_2_ALT; VECTOR_ADD_LID; VECTOR_SUB_RZERO] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_UNIV] THEN DISCH_THEN(CHOOSE_THEN MP_TAC) THEN
+    DISCH_THEN(MP_TAC o AP_TERM `\x:real^N. x$3`) THEN
+    ASM_SIMP_TAC[BASIS_COMPONENT; VECTOR_MUL_COMPONENT;
+                 ARITH; ARITH_RULE `3 <= n ==> 1 <= n /\ 2 <= n`] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC(MESON[PATH_CONNECTED_CONTINUOUS_IMAGE]
+   `(?f g. f continuous_on s /\ g continuous_on s /\
+           IMAGE f s = t /\ IMAGE g s = u)
+    ==> path_connected s ==> path_connected t /\ path_connected u`) THEN
+  EXISTS_TAC `\x:real^N. x + sqrt(&1 - norm(x) pow 2) % basis 1` THEN
+  EXISTS_TAC `\x:real^N. x - sqrt(&1 - norm(x) pow 2) % basis 1` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN REWRITE_TAC[CONTINUOUS_ON_ID] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+    REWRITE_TAC[o_DEF] THEN MATCH_MP_TAC(REWRITE_RULE[o_DEF]
+      CONTINUOUS_ON_LIFT_SQRT_COMPOSE) THEN
+    SIMP_TAC[IN_INTER; IN_DELETE; IN_CBALL_0; REAL_SUB_LE;
+             REAL_POW_1_LE; NORM_POS_LE; LIFT_SUB] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+    REWRITE_TAC[REAL_POW_2; LIFT_CMUL] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+    REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX] THEN
+    REWRITE_TAC[REWRITE_RULE[o_DEF] CONTINUOUS_ON_LIFT_NORM];
+    MATCH_MP_TAC CONTINUOUS_ON_SUB THEN REWRITE_TAC[CONTINUOUS_ON_ID] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+    REWRITE_TAC[o_DEF] THEN MATCH_MP_TAC(REWRITE_RULE[o_DEF]
+      CONTINUOUS_ON_LIFT_SQRT_COMPOSE) THEN
+    SIMP_TAC[IN_INTER; IN_DELETE; IN_CBALL_0; REAL_SUB_LE;
+             REAL_POW_1_LE; NORM_POS_LE; LIFT_SUB] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+    REWRITE_TAC[REAL_POW_2; LIFT_CMUL] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+    REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX] THEN
+    REWRITE_TAC[REWRITE_RULE[o_DEF] CONTINUOUS_ON_LIFT_NORM];
+    REWRITE_TAC[EXTENSION; IN_IMAGE; IN_INTER; IN_DELETE; IN_CBALL_0;
+                IN_ELIM_THM] THEN
+    X_GEN_TAC `y:real^N` THEN EQ_TAC THENL
+     [DISCH_THEN(X_CHOOSE_THEN `x:real^N` STRIP_ASSUME_TAC) THEN
+      ASM_REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+      SIMP_TAC[BASIS_COMPONENT; DIMINDEX_GE_1; LE_REFL] THEN
+      REWRITE_TAC[NORM_EQ_SQUARE; REAL_ADD_LID; REAL_MUL_RID; REAL_POS] THEN
+      REWRITE_TAC[VECTOR_ARITH
+       `(x + y:real^N) dot (x + y) = (x dot x + y dot y) + &2 * x dot y`] THEN
+      ASM_SIMP_TAC[DOT_BASIS; DIMINDEX_GE_1; LE_REFL; DOT_RMUL;
+                   VECTOR_MUL_COMPONENT; BASIS_COMPONENT] THEN
+      REWRITE_TAC[REAL_MUL_RZERO; REAL_MUL_RID; REAL_ADD_RID] THEN
+      REWRITE_TAC[GSYM REAL_POW_2] THEN
+      ASM_SIMP_TAC[SQRT_POW_2; SQRT_POS_LE; REAL_SUB_LE; REAL_POW_1_LE;
+                   NORM_POS_LE] THEN
+      CONJ_TAC THENL [REWRITE_TAC[NORM_POW_2] THEN REAL_ARITH_TAC; ALL_TAC] THEN
+      DISCH_THEN(MP_TAC o AP_TERM `\x:real^N. x$1`) THEN
+      ASM_SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+                   BASIS_COMPONENT; DIMINDEX_GE_1; LE_REFL] THEN
+      REWRITE_TAC[REAL_ADD_LID; REAL_MUL_RID] THEN
+      DISCH_THEN(MP_TAC o AP_TERM `\x:real. x pow 2`) THEN
+      ASM_SIMP_TAC[SQRT_POW_2; SQRT_POS_LE; REAL_SUB_LE; REAL_POW_1_LE;
+                   NORM_POS_LE] THEN
+      REWRITE_TAC[REAL_RING `&1 - x pow 2 = &1 pow 2 <=> x = &0`] THEN
+      ASM_REWRITE_TAC[NORM_EQ_0];
+      STRIP_TAC THEN EXISTS_TAC `y - y$1 % basis 1:real^N` THEN
+      REPEAT CONJ_TAC THENL
+       [REWRITE_TAC[VECTOR_MUL_EQ_0; REAL_SUB_0; VECTOR_ARITH
+         `y:real^N = y - r % b + s % b <=> (s - r) % b = vec 0`] THEN
+        DISJ1_TAC THEN MATCH_MP_TAC SQRT_UNIQUE THEN
+        ASM_REWRITE_TAC[NORM_POW_2; VECTOR_ARITH
+        `(x - y:real^N) dot (x - y) = (x dot x + y dot y) - &2 * x dot y`] THEN
+        SIMP_TAC[DOT_RMUL] THEN
+        SIMP_TAC[DOT_LMUL; DOT_BASIS; DIMINDEX_GE_1; LE_REFL;
+                 BASIS_COMPONENT] THEN
+        ASM_REWRITE_TAC[GSYM NORM_POW_2] THEN REAL_ARITH_TAC;
+        FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+        MATCH_MP_TAC NORM_LE_COMPONENTWISE THEN
+        SIMP_TAC[VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT;
+                 BASIS_COMPONENT; DIMINDEX_GE_1; LE_REFL] THEN
+        REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+        REAL_ARITH_TAC;
+        SIMP_TAC[VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT;
+                 BASIS_COMPONENT; DIMINDEX_GE_1; LE_REFL] THEN
+        REAL_ARITH_TAC;
+        REWRITE_TAC[VECTOR_SUB_EQ] THEN DISCH_THEN SUBST_ALL_TAC THEN
+        MAP_EVERY UNDISCH_TAC
+         [`~((y:real^N)$1 % basis 1:real^N = basis 1)`;
+          `norm((y:real^N)$1 % basis 1:real^N) = &1`;
+          `&0 <= ((y:real^N)$1 % basis 1:real^N)$1`] THEN
+        SIMP_TAC[NORM_MUL; VECTOR_MUL_COMPONENT; BASIS_COMPONENT; NORM_BASIS;
+          DIMINDEX_GE_1; LE_REFL; REAL_MUL_RID; real_abs; VECTOR_MUL_LID]]];
+    REWRITE_TAC[EXTENSION; IN_IMAGE; IN_INTER; IN_DELETE; IN_CBALL_0;
+                IN_ELIM_THM] THEN
+    X_GEN_TAC `y:real^N` THEN EQ_TAC THENL
+     [DISCH_THEN(X_CHOOSE_THEN `x:real^N` STRIP_ASSUME_TAC) THEN
+      ASM_REWRITE_TAC[VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+      SIMP_TAC[BASIS_COMPONENT; DIMINDEX_GE_1; LE_REFL] THEN
+      REWRITE_TAC[NORM_EQ_SQUARE; REAL_ADD_LID; REAL_MUL_RID; REAL_POS] THEN
+      REWRITE_TAC[VECTOR_ARITH
+       `(x - y:real^N) dot (x - y) = (x dot x + y dot y) - &2 * x dot y`] THEN
+      ASM_SIMP_TAC[DOT_BASIS; DIMINDEX_GE_1; LE_REFL; DOT_RMUL;
+                   VECTOR_MUL_COMPONENT; BASIS_COMPONENT] THEN
+      REWRITE_TAC[REAL_MUL_RZERO; REAL_MUL_RID; REAL_SUB_RZERO] THEN
+      REWRITE_TAC[GSYM REAL_POW_2] THEN
+      REWRITE_TAC[REAL_ARITH `&0 - x <= &0 <=> &0 <= x`] THEN
+      ASM_SIMP_TAC[SQRT_POW_2; SQRT_POS_LE; REAL_SUB_LE; REAL_POW_1_LE;
+                   NORM_POS_LE] THEN
+      CONJ_TAC THENL [REWRITE_TAC[NORM_POW_2] THEN REAL_ARITH_TAC; ALL_TAC] THEN
+      DISCH_THEN(MP_TAC o AP_TERM `\x:real^N. x$1`) THEN
+      ASM_SIMP_TAC[VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT;
+        VECTOR_NEG_COMPONENT; BASIS_COMPONENT; DIMINDEX_GE_1; LE_REFL] THEN
+      REWRITE_TAC[REAL_ARITH `&0 - x * &1 = -- &1 <=> x = &1`] THEN
+      DISCH_THEN(MP_TAC o AP_TERM `\x:real. x pow 2`) THEN
+      ASM_SIMP_TAC[SQRT_POW_2; SQRT_POS_LE; REAL_SUB_LE; REAL_POW_1_LE;
+                   NORM_POS_LE] THEN
+      REWRITE_TAC[REAL_RING `&1 - x pow 2 = &1 pow 2 <=> x = &0`] THEN
+      ASM_REWRITE_TAC[NORM_EQ_0];
+      STRIP_TAC THEN EXISTS_TAC `y - y$1 % basis 1:real^N` THEN
+      REPEAT CONJ_TAC THENL
+       [REWRITE_TAC[VECTOR_MUL_EQ_0; REAL_SUB_0; VECTOR_ARITH
+         `y:real^N = y - r % b - s % b <=> (s + r) % b = vec 0`] THEN
+        DISJ1_TAC THEN REWRITE_TAC[REAL_ARITH `x + y = &0 <=> x = --y`] THEN
+        MATCH_MP_TAC SQRT_UNIQUE THEN
+        ASM_REWRITE_TAC[REAL_NEG_GE0; NORM_POW_2; VECTOR_ARITH
+        `(x - y:real^N) dot (x - y) = (x dot x + y dot y) - &2 * x dot y`] THEN
+        SIMP_TAC[DOT_RMUL] THEN
+        SIMP_TAC[DOT_LMUL; DOT_BASIS; DIMINDEX_GE_1; LE_REFL;
+                 BASIS_COMPONENT] THEN
+        ASM_REWRITE_TAC[GSYM NORM_POW_2] THEN REAL_ARITH_TAC;
+        FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+        MATCH_MP_TAC NORM_LE_COMPONENTWISE THEN
+        SIMP_TAC[VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT;
+                 BASIS_COMPONENT; DIMINDEX_GE_1; LE_REFL] THEN
+        REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+        REAL_ARITH_TAC;
+        SIMP_TAC[VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT;
+                 BASIS_COMPONENT; DIMINDEX_GE_1; LE_REFL] THEN
+        REAL_ARITH_TAC;
+        REWRITE_TAC[VECTOR_SUB_EQ] THEN DISCH_THEN SUBST_ALL_TAC THEN
+        MAP_EVERY UNDISCH_TAC
+         [`~((y:real^N)$1 % basis 1:real^N = --basis 1)`;
+          `norm((y:real^N)$1 % basis 1:real^N) = &1`;
+          `((y:real^N)$1 % basis 1:real^N)$1 <= &0`] THEN
+        SIMP_TAC[NORM_MUL; VECTOR_MUL_COMPONENT; BASIS_COMPONENT; NORM_BASIS;
+          DIMINDEX_GE_1; LE_REFL; REAL_MUL_RID; VECTOR_MUL_LID;
+          REAL_ARITH `y <= &0 ==> abs y = --y`;
+          REAL_ARITH `--x = &1 <=> x = -- &1`] THEN
+        REPEAT DISCH_TAC THEN VECTOR_ARITH_TAC]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Covering spaces and lifting results for them.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let covering_space = new_definition
+ `covering_space(c,(p:real^M->real^N)) s <=>
+        p continuous_on c /\ IMAGE p c = s /\
+        !x. x IN s
+            ==> ?t. x IN t /\ open_in (subtopology euclidean s) t /\
+                    ?v. UNIONS v = {x | x IN c /\ p(x) IN t} /\
+                        (!u. u IN v ==> open_in (subtopology euclidean c) u) /\
+                        pairwise DISJOINT v /\
+                        (!u. u IN v ==> ?q. homeomorphism (u,t) (p,q))`;;
+
+let COVERING_SPACE_IMP_CONTINUOUS = prove
+ (`!p:real^M->real^N c s. covering_space (c,p) s ==> p continuous_on c`,
+  SIMP_TAC[covering_space]);;
+
+let COVERING_SPACE_IMP_SURJECTIVE = prove
+ (`!p:real^M->real^N c s. covering_space (c,p) s ==> IMAGE p c = s`,
+  SIMP_TAC[covering_space]);;
+
+let HOMEOMORPHISM_IMP_COVERING_SPACE = prove
+ (`!f:real^M->real^N g s t.
+        homeomorphism (s,t) (f,g) ==> covering_space (s,f) t`,
+  REWRITE_TAC[homeomorphism] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[covering_space] THEN X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+  EXISTS_TAC `t:real^N->bool` THEN
+  ASM_SIMP_TAC[OPEN_IN_SUBTOPOLOGY_REFL; TOPSPACE_EUCLIDEAN; SUBSET_UNIV] THEN
+  EXISTS_TAC `{s:real^M->bool}` THEN
+  REWRITE_TAC[FORALL_IN_INSERT; NOT_IN_EMPTY; UNIONS_1; PAIRWISE_SING] THEN
+  ASM_SIMP_TAC[OPEN_IN_SUBTOPOLOGY_REFL; TOPSPACE_EUCLIDEAN; SUBSET_UNIV] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; EXISTS_TAC `g:real^N->real^M`] THEN
+  ASM_REWRITE_TAC[homeomorphism]);;
+
+let COVERING_SPACE_LOCAL_HOMEOMORPHISM = prove
+ (`!p:real^M->real^N c s.
+        covering_space (c,p) s
+        ==> !x. x IN c
+                ==> ?t u. x IN t /\ open_in (subtopology euclidean c) t /\
+                          p(x) IN u /\ open_in (subtopology euclidean s) u /\
+                          ?q. homeomorphism (t,u) (p,q)`,
+  REWRITE_TAC[covering_space] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(p:real^M->real^N) x`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` MP_TAC) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:(real^M->bool)->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `(x:real^M) IN UNIONS v` MP_TAC THENL
+   [ASM SET_TAC[]; REWRITE_TAC[IN_UNIONS]] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real^M->bool` THEN
+  STRIP_TAC THEN EXISTS_TAC `t:real^N->bool` THEN ASM_SIMP_TAC[]);;
+
+let COVERING_SPACE_LOCAL_HOMEOMORPHISM_ALT = prove
+ (`!p:real^M->real^N c s.
+        covering_space (c,p) s
+        ==> !y. y IN s
+                ==> ?x t u. p(x) = y /\
+                            x IN t /\ open_in (subtopology euclidean c) t /\
+                            y IN u /\ open_in (subtopology euclidean s) u /\
+                            ?q. homeomorphism (t,u) (p,q)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?x. x IN c /\ (p:real^M->real^N) x = y` MP_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+    ASM SET_TAC[];
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x:real^M` THEN STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o SPEC `x:real^M` o MATCH_MP
+     COVERING_SPACE_LOCAL_HOMEOMORPHISM) THEN
+    ASM_MESON_TAC[]]);;
+
+let COVERING_SPACE_OPEN_MAP = prove
+ (`!p:real^M->real^N c s t.
+        covering_space (c,p) s /\
+        open_in (subtopology euclidean c) t
+        ==> open_in (subtopology euclidean s) (IMAGE p t)`,
+  REWRITE_TAC[covering_space] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [open_in]) THEN
+  ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN 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[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` MP_TAC) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `vs:(real^M->bool)->bool`
+   (STRIP_ASSUME_TAC o GSYM)) THEN
+  SUBGOAL_THEN
+   `?x. x IN {x | x IN c /\ (p:real^M->real^N) x IN u} /\ x IN t /\ p x = y`
+  MP_TAC THENL [ASM SET_TAC[]; ASM_REWRITE_TAC[]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `x:real^M` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_UNIONS]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:real^M->bool` STRIP_ASSUME_TAC) THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `v:real^M->bool`)) THEN
+  ASM_REWRITE_TAC[homeomorphism] THEN REPEAT DISCH_TAC THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `q:real^N->real^M` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `IMAGE (p:real^M->real^N) (t INTER v)` THEN CONJ_TAC THENL
+   [ALL_TAC; ASM SET_TAC[]] THEN
+  SUBGOAL_THEN
+   `IMAGE (p:real^M->real^N) (t INTER v) =
+    {z | z IN u /\ q z IN (t INTER v)}`
+  SUBST1_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC OPEN_IN_TRANS THEN EXISTS_TAC `u:real^N->bool` THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [CONTINUOUS_ON_OPEN]) THEN
+  ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[INTER_COMM] THEN
+  MATCH_MP_TAC OPEN_IN_SUBTOPOLOGY_INTER_SUBSET THEN
+  EXISTS_TAC `c:real^M->bool` THEN
+  CONJ_TAC THENL [MATCH_MP_TAC OPEN_IN_INTER; ASM_MESON_TAC[open_in]] THEN
+  ASM_REWRITE_TAC[OPEN_IN_SUBTOPOLOGY_REFL; TOPSPACE_EUCLIDEAN; SUBSET_UNIV]);;
+
+let COVERING_SPACE_QUOTIENT_MAP = prove
+ (`!p:real^M->real^N c s.
+    covering_space (c,p) s
+    ==> !u. u SUBSET s
+            ==> (open_in (subtopology euclidean c) {x | x IN c /\ p x IN u} <=>
+                 open_in (subtopology euclidean s) u)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+  MATCH_MP_TAC OPEN_MAP_IMP_QUOTIENT_MAP THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[COVERING_SPACE_IMP_CONTINUOUS]; ALL_TAC] THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+  ASM_MESON_TAC[COVERING_SPACE_OPEN_MAP]);;
+
+let COVERING_SPACE_LOCALLY = prove
+ (`!P Q p:real^M->real^N c s.
+        covering_space (c,p) s /\ (!t. t SUBSET c /\ P t ==> Q(IMAGE p t)) /\
+        locally P c
+        ==> locally Q s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+  MATCH_MP_TAC LOCALLY_OPEN_MAP_IMAGE THEN
+  EXISTS_TAC `P:(real^M->bool)->bool` THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[COVERING_SPACE_IMP_CONTINUOUS]; ALL_TAC] THEN
+  ASM_SIMP_TAC[] THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+  ASM_MESON_TAC[COVERING_SPACE_OPEN_MAP]);;
+
+let COVERING_SPACE_LOCALLY_CONNECTED = prove
+ (`!p:real^M->real^N c s.
+        covering_space (c,p) s /\ locally connected c ==> locally connected s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC COVERING_SPACE_LOCALLY THEN
+  MAP_EVERY EXISTS_TAC
+   [`connected:(real^M->bool)->bool`;
+    `p:real^M->real^N`; `c:real^M->bool`] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN
+  ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[COVERING_SPACE_IMP_CONTINUOUS; CONTINUOUS_ON_SUBSET]);;
+
+let COVERING_SPACE_LOCALLY_PATH_CONNECTED = prove
+ (`!p:real^M->real^N c s.
+        covering_space (c,p) s /\ locally path_connected c
+        ==> locally path_connected s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC COVERING_SPACE_LOCALLY THEN
+  MAP_EVERY EXISTS_TAC
+   [`path_connected:(real^M->bool)->bool`;
+    `p:real^M->real^N`; `c:real^M->bool`] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC PATH_CONNECTED_CONTINUOUS_IMAGE THEN
+  ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[COVERING_SPACE_IMP_CONTINUOUS; CONTINUOUS_ON_SUBSET]);;
+
+let COVERING_SPACE_LIFT_UNIQUE_GEN = prove
+ (`!p:real^M->real^N f:real^P->real^N g1 g2 c s t u a x.
+        covering_space (c,p) s /\
+        f continuous_on t /\ IMAGE f t SUBSET s /\
+        g1 continuous_on t /\ IMAGE g1 t SUBSET c /\
+        (!x. x IN t ==> f(x) = p(g1 x)) /\
+        g2 continuous_on t /\ IMAGE g2 t SUBSET c /\
+        (!x. x IN t ==> f(x) = p(g2 x)) /\
+        u IN components t /\ a IN u /\ g1(a) = g2(a) /\ x IN u
+        ==> g1(x) = g2(x)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+  UNDISCH_TAC `(x:real^P) IN u` THEN SPEC_TAC(`x:real^P`,`x:real^P`) THEN
+  MATCH_MP_TAC(SET_RULE
+   `(?a. a IN u /\ g a = z) /\
+    ({x | x IN u /\ g x = z} = {} \/ {x | x IN u /\ g x = z} = u)
+    ==> !x. x IN u ==> g x = z`) THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[VECTOR_SUB_EQ]; ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP IN_COMPONENTS_CONNECTED) THEN
+  REWRITE_TAC[CONNECTED_CLOPEN] THEN DISCH_THEN MATCH_MP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP IN_COMPONENTS_SUBSET) THEN CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    X_GEN_TAC `x:real^P` THEN STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o SPEC `(g1:real^P->real^M) x` o
+        MATCH_MP COVERING_SPACE_LOCAL_HOMEOMORPHISM) THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; SIMP_TAC[LEFT_IMP_EXISTS_THM]] THEN
+    MAP_EVERY X_GEN_TAC [`v:real^M->bool`; `w:real^N->bool`] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[VECTOR_SUB_EQ]) THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    REWRITE_TAC[homeomorphism] THEN
+    DISCH_THEN(X_CHOOSE_THEN `q:real^N->real^M` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `{x | x IN u /\ (g1:real^P->real^M) x IN v} INTER
+                {x | x IN u /\ (g2:real^P->real^M) x IN v}` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC OPEN_IN_INTER THEN ONCE_REWRITE_TAC[SET_RULE
+       `{x | x IN u /\ g x IN v} =
+        {x | x IN u /\ g x IN (v INTER IMAGE g u)}`] THEN
+      CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_IMP_OPEN_IN THEN
+      (CONJ_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ALL_TAC]) THEN
+      UNDISCH_TAC `open_in (subtopology euclidean c) (v:real^M->bool)` THEN
+      REWRITE_TAC[OPEN_IN_OPEN] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN ASM SET_TAC[];
+      REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_INTER; VECTOR_SUB_EQ] THEN
+      ASM SET_TAC[]];
+    MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE_CONSTANT THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]]);;
+
+let COVERING_SPACE_LIFT_UNIQUE = prove
+ (`!p:real^M->real^N f:real^P->real^N g1 g2 c s t a x.
+        covering_space (c,p) s /\
+        f continuous_on t /\ IMAGE f t SUBSET s /\
+        g1 continuous_on t /\ IMAGE g1 t SUBSET c /\
+        (!x. x IN t ==> f(x) = p(g1 x)) /\
+        g2 continuous_on t /\ IMAGE g2 t SUBSET c /\
+        (!x. x IN t ==> f(x) = p(g2 x)) /\
+        connected t /\ a IN t /\ g1(a) = g2(a) /\ x IN t
+        ==> g1(x) = g2(x)`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`p:real^M->real^N`; `f:real^P->real^N`;
+    `g1:real^P->real^M`; `g2:real^P->real^M`;
+    `c:real^M->bool`; `s:real^N->bool`; `t:real^P->bool`; `t:real^P->bool`;
+    `a:real^P`; `x:real^P`] COVERING_SPACE_LIFT_UNIQUE_GEN) THEN
+  ASM_REWRITE_TAC[IN_COMPONENTS_SELF] THEN ASM SET_TAC[]);;
+
+let COVERING_SPACE_LIFT_UNIQUE_IDENTITY = prove
+ (`!p:real^M->real^N c f s a.
+     covering_space (c,p) s /\
+     path_connected c /\
+     f continuous_on c /\ IMAGE f c SUBSET c /\
+     (!x. x IN c ==> p(f x) = p x) /\
+     a IN c /\ f(a) = a
+     ==> !x. x IN c ==> f x = x`,
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [path_connected]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`a:real^M`; `x:real^M`]) THEN
+  ASM_REWRITE_TAC[path; path_image; pathstart; pathfinish] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^M` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`p:real^M->real^N`; `(p:real^M->real^N) o (g:real^1->real^M)`;
+    `(f:real^M->real^M) o (g:real^1->real^M)`; `g:real^1->real^M`;
+    `c:real^M->bool`; `s:real^N->bool`;
+    `interval[vec 0:real^1,vec 1]`;
+    `vec 0:real^1`; `vec 1:real^1`]
+   COVERING_SPACE_LIFT_UNIQUE) THEN
+  ASM_REWRITE_TAC[o_THM; IMAGE_o] THEN DISCH_THEN MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[ENDS_IN_UNIT_INTERVAL; CONNECTED_INTERVAL] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [covering_space]) THEN
+  STRIP_TAC THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP (SET_RULE
+   `IMAGE p c = s ==> !x. x IN c ==> p(x) IN s`)) THEN
+  ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+  ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE]);;
+
+let COVERING_SPACE_LIFT_HOMOTOPY = prove
+ (`!p:real^M->real^N c s (h:real^(1,P)finite_sum->real^N) f u.
+        covering_space (c,p) s /\
+        h continuous_on (interval[vec 0,vec 1] PCROSS u) /\
+        IMAGE h (interval[vec 0,vec 1] PCROSS u) SUBSET s /\
+        (!y. y IN u ==> h (pastecart (vec 0) y) = p(f y)) /\
+        f continuous_on u /\ IMAGE f u SUBSET c
+        ==> ?k. k continuous_on (interval[vec 0,vec 1] PCROSS u) /\
+                IMAGE k (interval[vec 0,vec 1] PCROSS u) SUBSET c /\
+                (!y. y IN u ==> k(pastecart (vec 0) y) = f y) /\
+                (!z. z IN interval[vec 0,vec 1] PCROSS u ==> h z = p(k z))`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!y. y IN u
+        ==> ?v. open_in (subtopology euclidean u) v /\ y IN v /\
+                ?k:real^(1,P)finite_sum->real^M.
+                    k continuous_on (interval[vec 0,vec 1] PCROSS v) /\
+                    IMAGE k (interval[vec 0,vec 1] PCROSS v) SUBSET c /\
+                    (!y. y IN v ==> k(pastecart (vec 0) y) = f y) /\
+                    (!z. z IN interval[vec 0,vec 1] PCROSS v
+                         ==> h z :real^N = p(k z))`
+  MP_TAC THENL
+   [ALL_TAC;
+    GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV)
+     [RIGHT_IMP_EXISTS_THM; RIGHT_AND_EXISTS_THM] THEN
+    REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC
+     [`v:real^P->real^P->bool`; `fs:real^P->real^(1,P)finite_sum->real^M`] THEN
+    DISCH_THEN(LABEL_TAC "*") THEN
+    MP_TAC(ISPECL
+     [`fs:real^P->real^(1,P)finite_sum->real^M`;
+      `(\x. interval[vec 0,vec 1] PCROSS (v x))
+        :real^P->real^(1,P)finite_sum->bool`;
+      `(interval[vec 0,vec 1] PCROSS u):real^(1,P)finite_sum->bool`;
+      `u:real^P->bool`]
+      PASTING_LEMMA_EXISTS) THEN
+    ASM_SIMP_TAC[] THEN ANTS_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC MONO_EXISTS THEN
+      X_GEN_TAC `k:real^(1,P)finite_sum->real^M` THEN STRIP_TAC THEN
+      ASM_REWRITE_TAC[FORALL_IN_IMAGE; FORALL_IN_PCROSS; SUBSET] THEN
+      REPEAT CONJ_TAC THEN TRY(X_GEN_TAC `t:real^1`) THEN
+      X_GEN_TAC `y:real^P` THEN STRIP_TAC THENL
+       [FIRST_X_ASSUM(MP_TAC o SPECL
+         [`pastecart (t:real^1) (y:real^P)`; `y:real^P`]);
+        FIRST_X_ASSUM(MP_TAC o SPECL
+         [`pastecart (vec 0:real^1) (y:real^P)`; `y:real^P`]);
+        FIRST_X_ASSUM(MP_TAC o SPECL
+         [`pastecart (t:real^1) (y:real^P)`; `y:real^P`])] THEN
+      ASM_SIMP_TAC[PASTECART_IN_PCROSS; IN_INTER; ENDS_IN_UNIT_INTERVAL] THEN
+      DISCH_THEN SUBST1_TAC THEN
+      REMOVE_THEN "*" (MP_TAC o SPEC `y:real^P`) THEN
+      ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+      REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REWRITE_TAC[PASTECART_IN_PCROSS]] THEN
+    REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET; FORALL_IN_PCROSS; UNIONS_GSPEC; IN_ELIM_THM] THEN
+      MAP_EVERY X_GEN_TAC [`t:real^1`; `y:real^P`] THEN STRIP_TAC THEN
+      EXISTS_TAC `y:real^P` THEN ASM_SIMP_TAC[PASTECART_IN_PCROSS];
+      X_GEN_TAC `y:real^P` THEN DISCH_TAC THEN
+      REMOVE_THEN "*" (MP_TAC o SPEC `y:real^P`) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o CONJUNCT1) THEN
+      REWRITE_TAC[OPEN_IN_OPEN] THEN
+      DISCH_THEN(X_CHOOSE_THEN `t:real^P->bool` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `(:real^1) PCROSS (t:real^P->bool)` THEN
+      ASM_SIMP_TAC[REWRITE_RULE[GSYM PCROSS] OPEN_PCROSS; OPEN_UNIV] THEN
+      REWRITE_TAC[EXTENSION; FORALL_PASTECART; PASTECART_IN_PCROSS;
+                    IN_INTER; IN_UNIV] THEN
+      REPEAT GEN_TAC THEN CONV_TAC TAUT;
+      REWRITE_TAC[FORALL_PASTECART; IN_INTER; PASTECART_IN_PCROSS] THEN
+      MAP_EVERY X_GEN_TAC
+       [`x:real^P`; `z:real^P`; `t:real^1`; `y:real^P`] THEN
+      REWRITE_TAC[CONJ_ACI] THEN STRIP_TAC THEN
+      FIRST_ASSUM(MP_TAC o
+        ISPECL [`h:real^(1,P)finite_sum->real^N`;
+                `(fs:real^P->real^(1,P)finite_sum->real^M) x`;
+                `(fs:real^P->real^(1,P)finite_sum->real^M) z`;
+                `interval[vec 0:real^1,vec 1] PCROSS {y:real^P}`;
+                `pastecart (vec 0:real^1) (y:real^P)`;
+                `pastecart (t:real^1) (y:real^P)`] o
+        MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ] COVERING_SPACE_LIFT_UNIQUE)) THEN
+      DISCH_THEN MATCH_MP_TAC THEN
+      ASM_SIMP_TAC[PASTECART_IN_PCROSS; IN_SING; ENDS_IN_UNIT_INTERVAL] THEN
+      SIMP_TAC[REWRITE_RULE[GSYM PCROSS] CONNECTED_PCROSS;
+               CONNECTED_INTERVAL; CONNECTED_SING] THEN
+      CONJ_TAC THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        REWRITE_TAC[FORALL_PASTECART; SUBSET; PASTECART_IN_PCROSS] THEN
+        ASM_SIMP_TAC[IN_SING];
+        ALL_TAC] THEN
+      CONJ_TAC THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+         (REWRITE_RULE[IMP_CONJ_ALT] SUBSET_TRANS)) THEN
+        MATCH_MP_TAC IMAGE_SUBSET THEN
+        REWRITE_TAC[FORALL_PASTECART; SUBSET; PASTECART_IN_PCROSS] THEN
+        ASM_SIMP_TAC[IN_SING];
+        ALL_TAC] THEN
+      ONCE_REWRITE_TAC[TAUT `p /\ q /\ r /\ s <=> (p /\ q /\ r) /\ s`] THEN
+      CONJ_TAC THENL
+       [REMOVE_THEN "*" (MP_TAC o SPEC `x:real^P`);
+        REMOVE_THEN "*" (MP_TAC o SPEC `z:real^P`)] THEN
+      ASM_REWRITE_TAC[FORALL_IN_GSPEC; SUBSET; FORALL_IN_IMAGE] THEN
+      ASM_SIMP_TAC[FORALL_PASTECART; PASTECART_IN_PCROSS; IN_SING] THEN
+      STRIP_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+      REWRITE_TAC[FORALL_PASTECART; SUBSET; PASTECART_IN_PCROSS] THEN
+      ASM_SIMP_TAC[IN_SING]]] THEN
+  X_GEN_TAC `y:real^P` THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o last o CONJUNCTS o
+    GEN_REWRITE_RULE I [covering_space]) THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `uu:real^N->real^N->bool` THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `!t. t IN interval[vec 0,vec 1]
+        ==> ?k n i:real^N.
+                open_in (subtopology euclidean (interval[vec 0,vec 1])) k /\
+                open_in (subtopology euclidean u) n /\
+                t IN k /\ y IN n /\ i IN s /\
+                IMAGE (h:real^(1,P)finite_sum->real^N) (k PCROSS n) SUBSET uu i`
+  MP_TAC THENL
+   [X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `(h:real^(1,P)finite_sum->real^N) (pastecart t y) IN s`
+    ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o ONCE_REWRITE_RULE[FORALL_IN_IMAGE] o
+        GEN_REWRITE_RULE I [SUBSET]) THEN
+      ASM_REWRITE_TAC[PASTECART_IN_PCROSS];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `open_in (subtopology euclidean (interval[vec 0,vec 1] PCROSS u))
+              {z | z IN (interval[vec 0,vec 1] PCROSS u) /\
+                   (h:real^(1,P)finite_sum->real^N) z IN
+                   uu(h(pastecart t y))}`
+    MP_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN THEN
+      EXISTS_TAC `s:real^N->bool` THEN ASM_SIMP_TAC[];
+      ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+        PASTECART_IN_INTERIOR_SUBTOPOLOGY)) THEN
+    DISCH_THEN(MP_TAC o SPECL [`t:real^1`; `y:real^P`]) THEN
+    ASM_SIMP_TAC[IN_ELIM_THM; PASTECART_IN_PCROSS] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^1->bool` THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `n:real^P->bool` THEN
+    STRIP_TAC THEN
+    EXISTS_TAC `(h:real^(1,P)finite_sum->real^N) (pastecart t y)` THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [OPEN_IN_OPEN] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN
+  REWRITE_TAC[MESON[]
+   `(?x y. (P y /\ x = f y) /\ Q x) <=> ?y. P y /\ Q(f y)`] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`kk:real^1->real^1->bool`; `nn:real^1->real^P->bool`;
+    `xx:real^1->real^N`] THEN
+  DISCH_THEN(LABEL_TAC "+") THEN
+  MP_TAC(ISPEC `interval[vec 0:real^1,vec 1] PCROSS {y:real^P}`
+    COMPACT_IMP_HEINE_BOREL) THEN
+  SIMP_TAC[COMPACT_PCROSS; COMPACT_INTERVAL; COMPACT_SING] THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `IMAGE ((\i. kk i PCROSS nn i):real^1->real^(1,P)finite_sum->bool)
+          (interval[vec 0,vec 1])`) THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; OPEN_PCROSS] THEN ANTS_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_PCROSS; IN_SING] THEN
+    MAP_EVERY X_GEN_TAC [`t:real^1`; `z:real^P`] THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[UNIONS_IMAGE; IN_ELIM_THM; PASTECART_IN_PCROSS] THEN
+    ASM_MESON_TAC[IN_INTER];
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+     [TAUT `p /\ q /\ r <=> q /\ p /\ r`] THEN
+    REWRITE_TAC[EXISTS_FINITE_SUBSET_IMAGE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `tk:real^1->bool` STRIP_ASSUME_TAC)] THEN
+  ABBREV_TAC `n = INTERS (IMAGE (nn:real^1->real^P->bool) tk)` THEN
+  SUBGOAL_THEN `(y:real^P) IN n /\ open n` STRIP_ASSUME_TAC THENL
+   [EXPAND_TAC "n" THEN CONJ_TAC THENL
+     [REWRITE_TAC[INTERS_IMAGE; IN_ELIM_THM];
+      MATCH_MP_TAC OPEN_INTERS THEN REWRITE_TAC[FORALL_IN_IMAGE] THEN
+      ASM_SIMP_TAC[FINITE_IMAGE]] THEN
+    X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+    REMOVE_THEN "+" (MP_TAC o SPEC `t:real^1`) THEN
+    (ANTS_TAC THENL [ASM SET_TAC[]; SIMP_TAC[IN_INTER]]);
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`interval[vec 0:real^1,vec 1]`; `IMAGE (kk:real^1->real^1->bool) tk`]
+   LEBESGUE_COVERING_LEMMA) THEN
+  REWRITE_TAC[COMPACT_INTERVAL; FORALL_IN_IMAGE; IMAGE_EQ_EMPTY] THEN
+  MATCH_MP_TAC(TAUT
+   `q /\ (p ==> ~q) /\ (q ==> (r ==> s) ==> t)
+    ==> (~p /\ q /\ r ==> s) ==> t`) THEN
+  SIMP_TAC[UNIONS_0; IMAGE_CLAUSES; SUBSET_EMPTY; UNIT_INTERVAL_NONEMPTY] THEN
+  CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [UNIONS_IMAGE]) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_PCROSS; IMP_CONJ; IN_SING] THEN
+    REWRITE_TAC[RIGHT_FORALL_IMP_THM; FORALL_UNWIND_THM2] THEN
+    REWRITE_TAC[UNIONS_IMAGE; IN_ELIM_THM; PASTECART_IN_PCROSS] THEN
+    MESON_TAC[];
+    DISCH_TAC] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPEC `d:real` REAL_ARCH_INV) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N:num` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `!n. n <= N
+        ==> ?v k:real^(1,P)finite_sum->real^M.
+                open_in (subtopology euclidean u) v /\
+                y IN v /\
+                k continuous_on interval[vec 0,lift(&n / &N)] PCROSS v /\
+                IMAGE k (interval[vec 0,lift(&n / &N)] PCROSS v) SUBSET c /\
+                (!y. y IN v ==> k (pastecart (vec 0) y) = f y) /\
+                (!z. z IN interval[vec 0,lift(&n / &N)] PCROSS v
+                     ==> h z:real^N = p (k z))`
+  MP_TAC THENL
+   [ALL_TAC;
+    DISCH_THEN(MP_TAC o SPEC `N:num`) THEN REWRITE_TAC[LE_REFL] THEN
+    ASM_SIMP_TAC[REAL_DIV_REFL; REAL_OF_NUM_EQ; LIFT_NUM]] THEN
+  MATCH_MP_TAC num_INDUCTION THEN CONJ_TAC THENL
+   [DISCH_TAC THEN REWRITE_TAC[real_div; REAL_MUL_LZERO; LIFT_NUM] THEN
+    EXISTS_TAC `u:real^P->bool` THEN
+    EXISTS_TAC `(f o sndcart):real^(1,P)finite_sum->real^M` THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS; INTERVAL_SING] THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; IN_SING; o_THM] THEN
+    ASM_REWRITE_TAC[FORALL_UNWIND_THM2; SNDCART_PASTECART] THEN
+    REWRITE_TAC[OPEN_IN_SUBTOPOLOGY_REFL; TOPSPACE_EUCLIDEAN; SUBSET_UNIV] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+    SIMP_TAC[SNDCART_PASTECART];
+    ALL_TAC] THEN
+  X_GEN_TAC `m:num` THEN ASM_CASES_TAC `SUC m <= N` THEN
+  ASM_SIMP_TAC[ARITH_RULE `SUC m <= N ==> m <= N`; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`v:real^P->bool`; `k:real^(1,P)finite_sum->real^M`] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM
+   (MP_TAC o SPEC `interval[lift(&m / &N),lift(&(SUC m) / &N)]`) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[DIAMETER_INTERVAL; SUBSET_INTERVAL_1] THEN
+    REWRITE_TAC[LIFT_DROP; DROP_VEC; INTERVAL_EQ_EMPTY_1;
+                GSYM LIFT_SUB; NORM_LIFT] THEN
+    ASM_SIMP_TAC[REAL_LT_DIV2_EQ; REAL_LE_DIV2_EQ; REAL_OF_NUM_LT; LE_1;
+                 REAL_FIELD `&0 < x ==> a / x - b / x = (a - b) / x`] THEN
+    SIMP_TAC[GSYM NOT_LE; ARITH_RULE `m <= SUC m`; REAL_OF_NUM_SUB] THEN
+    ASM_SIMP_TAC[REAL_ABS_DIV; REAL_ABS_NUM; REAL_LE_DIV; REAL_POS;
+                 REAL_ABS_NUM; ARITH_RULE `SUC m - m = 1`] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&1 / n = inv(n)`; REAL_LT_IMP_LE] THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; LE_1] THEN
+    ASM_REWRITE_TAC[REAL_MUL_LID; REAL_OF_NUM_LE] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^1` STRIP_ASSUME_TAC) THEN
+  REMOVE_THEN "+" (MP_TAC o SPEC `t:real^1`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; STRIP_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(xx:real^1->real^N) t`) THEN
+  ASM_REWRITE_TAC[] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `vv:(real^M->bool)->bool` MP_TAC) THEN
+  ONCE_REWRITE_TAC[IMP_CONJ] THEN
+  GEN_REWRITE_TAC LAND_CONV [EXTENSION] THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `(k:real^(1,P)finite_sum->real^M) (pastecart (lift(&m / &N)) y)`) THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN MATCH_MP_TAC(TAUT
+   `q /\ (p ==> r) ==> (p <=> q) ==> r`) THEN
+  REPEAT(FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [IN_INTER])) THEN
+  SUBGOAL_THEN
+   `lift(&m / &N) IN interval[vec 0,lift (&m / &N)] /\
+    lift(&m / &N) IN interval[lift(&m / &N),lift(&(SUC m) / &N)]`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+    SIMP_TAC[REAL_LE_DIV; REAL_POS; REAL_LE_REFL] THEN
+    ASM_SIMP_TAC[REAL_LE_DIV2_EQ; LE_1; REAL_OF_NUM_LT; REAL_OF_NUM_LE] THEN
+    ARITH_TAC;
+    ALL_TAC] THEN
+  REPEAT CONJ_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    MATCH_MP_TAC FUN_IN_IMAGE THEN
+    ASM_REWRITE_TAC[PASTECART_IN_PCROSS];
+    FIRST_X_ASSUM(MP_TAC o SPEC `pastecart(lift(&m / &N)) (y:real^P)`) THEN
+    ASM_REWRITE_TAC[PASTECART_IN_PCROSS] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (SET_RULE `IMAGE h s SUBSET t ==> x IN s ==> h x IN t`)) THEN
+    ASM_REWRITE_TAC[PASTECART_IN_PCROSS; IN_INTER] THEN
+    ASM_SIMP_TAC[IN_INTERVAL_1; LIFT_DROP; REAL_LE_DIV; REAL_LE_LDIV_EQ;
+                 REAL_POS; REAL_OF_NUM_LT; LE_1; DROP_VEC] THEN
+    REWRITE_TAC[REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+    CONJ_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    ASM_REWRITE_TAC[];
+    GEN_REWRITE_TAC LAND_CONV [IN_UNIONS] THEN
+    DISCH_THEN(X_CHOOSE_THEN `w:real^M->bool` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (MP_TAC o SPEC `w:real^M->bool`) MP_TAC) THEN
+    DISCH_THEN(MP_TAC o SPEC `w:real^M->bool` o CONJUNCT2) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_TAC `p':real^N->real^M`) THEN
+    DISCH_TAC THEN UNDISCH_THEN `(w:real^M->bool) IN vv` (K ALL_TAC)] THEN
+  ABBREV_TAC `w' = (uu:real^N->real^N->bool)(xx(t:real^1))` THEN
+  SUBGOAL_THEN
+   `?n'. open_in (subtopology euclidean u) n' /\ y IN n' /\
+         IMAGE (k:real^(1,P)finite_sum->real^M) ({lift(&m / &N)} PCROSS n')
+         SUBSET w`
+  STRIP_ASSUME_TAC THENL
+   [EXISTS_TAC
+     `{z | z IN v /\ ((k:real^(1,P)finite_sum->real^M) o
+                     pastecart (lift(&m / &N))) z IN w}` THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+    ASM_SIMP_TAC[IN_ELIM_THM; IN_SING; o_THM] THEN
+    MATCH_MP_TAC OPEN_IN_TRANS THEN EXISTS_TAC `v:real^P->bool` THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN THEN
+    EXISTS_TAC `c:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[GSYM o_DEF] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_CONST;
+               CONTINUOUS_ON_ID] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET));
+      REWRITE_TAC[IMAGE_o] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `IMAGE k s SUBSET c ==> t SUBSET s ==> IMAGE k t SUBSET c`))] THEN
+    ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?q q':real^P->bool.
+        open_in (subtopology euclidean u) q /\
+        closed_in (subtopology euclidean u) q' /\
+        y IN q /\ y IN q' /\ q SUBSET q' /\
+        q SUBSET (u INTER nn(t:real^1)) INTER n' INTER v /\
+        q' SUBSET (u INTER nn(t:real^1)) INTER n' INTER v`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[SET_RULE
+     `y IN q /\ y IN q' /\ q SUBSET q' /\ q SUBSET s /\ q' SUBSET s <=>
+      y IN q /\ q SUBSET q' /\ q' SUBSET s`] THEN
+    UNDISCH_TAC `open_in (subtopology euclidean u) (v:real^P->bool)` THEN
+    UNDISCH_TAC `open_in (subtopology euclidean u) (n':real^P->bool)` THEN
+    REWRITE_TAC[OPEN_IN_OPEN] THEN
+    DISCH_THEN(X_CHOOSE_THEN `vo:real^P->bool` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `vx:real^P->bool` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPEC `nn(t:real^1) INTER vo INTER vx:real^P->bool`
+      OPEN_CONTAINS_CBALL) THEN
+    ASM_SIMP_TAC[OPEN_INTER] THEN DISCH_THEN(MP_TAC o SPEC `y:real^P`) THEN
+    ASM_REWRITE_TAC[IN_INTER] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `u INTER ball(y:real^P,e)` THEN
+    EXISTS_TAC `u INTER cball(y:real^P,e)` THEN
+    REWRITE_TAC[CLOSED_IN_CLOSED] THEN
+    CONJ_TAC THENL [MESON_TAC[OPEN_BALL]; ALL_TAC] THEN
+    CONJ_TAC THENL [MESON_TAC[CLOSED_CBALL]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[IN_INTER; CENTRE_IN_BALL] THEN
+    MP_TAC(ISPECL [`y:real^P`; `e:real`] BALL_SUBSET_CBALL) THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [homeomorphism]) THEN
+  EXISTS_TAC `q:real^P->bool` THEN ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPECL
+   [`\x:real^(1,P)finite_sum.
+       x IN interval[vec 0,lift(&m / &N)] PCROSS (q':real^P->bool)`;
+    `k:real^(1,P)finite_sum->real^M`;
+    `(p':real^N->real^M) o (h:real^(1,P)finite_sum->real^N)`;
+    `interval[vec 0,lift(&m / &N)] PCROSS (q':real^P->bool)`;
+    `interval[lift(&m / &N),lift(&(SUC m) / &N)] PCROSS (q':real^P->bool)`]
+   CONTINUOUS_ON_CASES_LOCAL) THEN
+  REWRITE_TAC[TAUT `~(p /\ ~p)`] THEN ANTS_TAC THENL
+   [REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[CLOSED_IN_CLOSED] THEN
+      EXISTS_TAC `interval[vec 0,lift(&m / &N)] PCROSS (:real^P)` THEN
+      SIMP_TAC[CLOSED_PCROSS; CLOSED_INTERVAL; CLOSED_UNIV] THEN
+      REWRITE_TAC[EXTENSION; IN_INTER; IN_UNION; FORALL_PASTECART] THEN
+      REWRITE_TAC[PASTECART_IN_PCROSS; IN_UNIV] THEN CONV_TAC TAUT;
+      REWRITE_TAC[CLOSED_IN_CLOSED] THEN EXISTS_TAC
+       `interval[lift(&m / &N),lift(&(SUC m) / &N)] PCROSS (:real^P)` THEN
+      SIMP_TAC[CLOSED_PCROSS; CLOSED_INTERVAL; CLOSED_UNIV] THEN
+      REWRITE_TAC[EXTENSION; IN_INTER; IN_UNION; FORALL_PASTECART] THEN
+      REWRITE_TAC[PASTECART_IN_PCROSS; IN_UNIV] THEN CONV_TAC TAUT;
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET; FORALL_PASTECART; PASTECART_IN_PCROSS] THEN
+      ASM SET_TAC[];
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET))
+      THENL
+       [ALL_TAC;
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `IMAGE k s SUBSET c ==> t SUBSET s ==> IMAGE k t SUBSET c`))] THEN
+      MATCH_MP_TAC PCROSS_MONO THEN
+      (CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]]) THEN
+      ASM_REWRITE_TAC[SUBSET_INTERVAL_1; LIFT_DROP; DROP_VEC;
+                      SUBSET_INTER] THEN
+      REWRITE_TAC[SUBSET_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+      ASM_SIMP_TAC[REAL_LE_MUL; REAL_POS; REAL_LE_DIV2_EQ; REAL_OF_NUM_LT;
+                   LE_1] THEN
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; REAL_OF_NUM_LT; LE_1;
+                   REAL_MUL_LZERO; REAL_MUL_LID; REAL_OF_NUM_LE] THEN
+      DISJ2_TAC THEN ARITH_TAC;
+      REWRITE_TAC[FORALL_PASTECART; PASTECART_IN_PCROSS] THEN
+      MAP_EVERY X_GEN_TAC [`r:real^1`; `z:real^P`] THEN
+      ASM_CASES_TAC `(z:real^P) IN q'` THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN DISCH_THEN(MP_TAC o MATCH_MP
+       (REAL_ARITH `(b <= x /\ x <= c) /\ (a <= x /\ x <= b) ==> x = b`)) THEN
+      REWRITE_TAC[DROP_EQ; o_THM] THEN DISCH_THEN SUBST1_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (MESON[]
+       `(!x. x IN w ==> p' (p x) = x)
+        ==> h z = p(k z) /\ k z IN w
+            ==> k z = p' (h z)`)) THEN
+      CONJ_TAC THENL
+       [FIRST_X_ASSUM MATCH_MP_TAC THEN
+        ASM_REWRITE_TAC[PASTECART_IN_PCROSS] THEN ASM SET_TAC[];
+        FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+        MATCH_MP_TAC FUN_IN_IMAGE THEN
+        REWRITE_TAC[PASTECART_IN_PCROSS; IN_SING] THEN ASM SET_TAC[]]];
+    SUBGOAL_THEN
+     `interval[vec 0,lift(&m / &N)] UNION
+      interval [lift(&m / &N),lift(&(SUC m) / &N)] =
+      interval[vec 0,lift(&(SUC m) / &N)]`
+    ASSUME_TAC THENL
+     [REWRITE_TAC[EXTENSION; IN_UNION; IN_INTERVAL_1] THEN GEN_TAC THEN
+      MATCH_MP_TAC(REAL_ARITH `a <= b /\ b <= c ==>
+       (a <= x /\ x <= b \/ b <= x /\ x <= c <=> a <= x /\ x <= c)`) THEN
+      SIMP_TAC[LIFT_DROP; DROP_VEC; REAL_LE_DIV; REAL_POS] THEN
+      ASM_SIMP_TAC[REAL_LE_DIV2_EQ; REAL_OF_NUM_LT; REAL_OF_NUM_LE; LE_1] THEN
+      ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `interval[vec 0,lift(&m / &N)] PCROSS (q':real^P->bool) UNION
+      interval [lift(&m / &N),lift(&(SUC m) / &N)] PCROSS q' =
+      interval[vec 0,lift(&(SUC m) / &N)] PCROSS q'`
+    SUBST1_TAC THENL
+     [SIMP_TAC[EXTENSION; IN_UNION; FORALL_PASTECART; PASTECART_IN_PCROSS] THEN
+      ASM SET_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC(MESON[CONTINUOUS_ON_SUBSET]
+     `t SUBSET s /\ (f continuous_on s ==> P f)
+      ==> f continuous_on s ==> ?g. g continuous_on t /\ P g`) THEN
+    ASM_SIMP_TAC[PCROSS_MONO; SUBSET_REFL] THEN DISCH_TAC THEN
+    REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+      MAP_EVERY X_GEN_TAC [`r:real^1`; `z:real^P`] THEN STRIP_TAC THEN
+      SUBGOAL_THEN `(z:real^P) IN q'` ASSUME_TAC THENL
+       [ASM SET_TAC[]; ASM_REWRITE_TAC[PASTECART_IN_PCROSS]] THEN
+      COND_CASES_TAC THEN REWRITE_TAC[o_THM] THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+        MATCH_MP_TAC FUN_IN_IMAGE THEN
+        REWRITE_TAC[PASTECART_IN_PCROSS; IN_SING] THEN ASM SET_TAC[];
+        FIRST_X_ASSUM(MATCH_MP_TAC o REWRITE_RULE[SUBSET] o
+          CONJUNCT1 o GEN_REWRITE_RULE I [open_in]) THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `IMAGE p w' = w ==> x IN w' ==> p x IN w`))];
+      X_GEN_TAC `z:real^P` THEN REWRITE_TAC[PASTECART_IN_PCROSS] THEN
+      DISCH_TAC THEN REWRITE_TAC[IN_INTERVAL_1; REAL_LE_REFL] THEN
+      SUBGOAL_THEN `(z:real^P) IN q'` ASSUME_TAC THENL
+       [ASM SET_TAC[]; ASM_REWRITE_TAC[LIFT_DROP; DROP_VEC]] THEN
+      SIMP_TAC[REAL_LE_DIV; REAL_POS] THEN ASM SET_TAC[];
+      REWRITE_TAC[FORALL_PASTECART; PASTECART_IN_PCROSS] THEN
+      MAP_EVERY X_GEN_TAC [`r:real^1`; `z:real^P`] THEN STRIP_TAC THEN
+      SUBGOAL_THEN `(z:real^P) IN q'` ASSUME_TAC THENL
+       [ASM SET_TAC[]; ASM_REWRITE_TAC[]] THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+       [FIRST_X_ASSUM MATCH_MP_TAC THEN
+        ASM_REWRITE_TAC[PASTECART_IN_PCROSS] THEN ASM SET_TAC[];
+        REWRITE_TAC[o_THM] THEN CONV_TAC SYM_CONV THEN
+        FIRST_X_ASSUM MATCH_MP_TAC]] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+      (SET_RULE `IMAGE h s SUBSET t ==> x IN s ==> h x IN t`)) THEN
+    ASM_REWRITE_TAC[PASTECART_IN_PCROSS; IN_INTER] THEN
+    REPEAT(CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]]) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+    REWRITE_TAC[IN_INTERVAL_1] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (REAL_ARITH `a <= x /\ x <= b ==> b <= c ==> a <= x /\ x <= c`)) THEN
+    ASM_SIMP_TAC[LIFT_DROP; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; LE_1] THEN
+    ASM_REWRITE_TAC[DROP_VEC; REAL_MUL_LID; REAL_OF_NUM_LE]]);;
+
+let COVERING_SPACE_LIFT_HOMOTOPIC_FUNCTION = prove
+ (`!p:real^M->real^N c s f f' g u:real^P->bool.
+        covering_space (c,p) s /\
+        g continuous_on u /\ IMAGE g u SUBSET c /\
+        (!y. y IN u ==> p(g y) = f y) /\
+        homotopic_with (\x. T) (u,s) f f'
+        ==> ?g'. g' continuous_on u /\ IMAGE g' u SUBSET c /\
+                 (!y. y IN u ==> p(g' y) = f' y)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `h:real^(1,P)finite_sum->real^N`
+    STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [homotopic_with]) THEN
+  FIRST_ASSUM(MP_TAC o
+    ISPECL [`h:real^(1,P)finite_sum->real^N`;
+            `g:real^P->real^M`; `u:real^P->bool`] o
+    MATCH_MP(ONCE_REWRITE_RULE[IMP_CONJ] COVERING_SPACE_LIFT_HOMOTOPY)) THEN
+  ASM_SIMP_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real^(1,P)finite_sum->real^M`
+        STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(k:real^(1,P)finite_sum->real^M) o
+              (\x. pastecart (vec 1) x)` THEN
+  ASM_REWRITE_TAC[IMAGE_o; o_THM] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_CONST;
+             CONTINUOUS_ON_ID] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS;
+                ENDS_IN_UNIT_INTERVAL];
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `IMAGE k s SUBSET c ==> t SUBSET s ==> IMAGE k t SUBSET c`)) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS;
+                ENDS_IN_UNIT_INTERVAL];
+    ASM_MESON_TAC[PASTECART_IN_PCROSS; ENDS_IN_UNIT_INTERVAL]]);;
+
+let COVERING_SPACE_LIFT_INESSENTIAL_FUNCTION = prove
+ (`!p:real^M->real^N c s f a u:real^P->bool.
+        covering_space (c,p) s /\ homotopic_with (\x. T) (u,s) f (\x. a)
+        ==> ?g. g continuous_on u /\ IMAGE g u SUBSET c /\
+                (!y. y IN u ==> p(g y) = f y)`,
+  ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN REPEAT GEN_TAC THEN DISCH_TAC THEN
+  ASM_CASES_TAC `u:real^P->bool = {}` THEN
+  ASM_REWRITE_TAC[NOT_IN_EMPTY; IMAGE_CLAUSES; EMPTY_SUBSET;
+                  CONTINUOUS_ON_EMPTY] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE
+     [TAUT `a /\ b /\ c /\ d /\ e ==> f <=> a /\ e ==> b /\ c /\ d ==> f`]
+     COVERING_SPACE_LIFT_HOMOTOPIC_FUNCTION)) THEN
+  FIRST_X_ASSUM(CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+  SUBGOAL_THEN `?b. b IN c /\ (p:real^M->real^N) b = a` CHOOSE_TAC THENL
+   [ASM SET_TAC[];
+    EXISTS_TAC `(\x. b):real^P->real^M`] THEN
+  REWRITE_TAC[CONTINUOUS_ON_CONST] THEN ASM SET_TAC[]);;
+
+let COVERING_SPACE_LIFT_HOMOTOPY_ALT = prove
+ (`!p:real^M->real^N c s (h:real^(P,1)finite_sum->real^N) f u.
+        covering_space (c,p) s /\
+        h continuous_on (u PCROSS interval[vec 0,vec 1]) /\
+        IMAGE h (u PCROSS interval[vec 0,vec 1]) SUBSET s /\
+        (!y. y IN u ==> h (pastecart y (vec 0)) = p(f y)) /\
+        f continuous_on u /\ IMAGE f u SUBSET c
+        ==> ?k. k continuous_on (u PCROSS interval[vec 0,vec 1]) /\
+                IMAGE k (u PCROSS interval[vec 0,vec 1]) SUBSET c /\
+                (!y. y IN u ==> k(pastecart y (vec 0)) = f y) /\
+                (!z. z IN u PCROSS interval[vec 0,vec 1] ==> h z = p(k z))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o ISPECL
+   [`(h:real^(P,1)finite_sum->real^N) o
+     (\z. pastecart (sndcart z) (fstcart z))`;
+    `f:real^P->real^M`; `u:real^P->bool`] o
+      MATCH_MP(ONCE_REWRITE_RULE[IMP_CONJ] COVERING_SPACE_LIFT_HOMOTOPY)) THEN
+  ASM_SIMP_TAC[o_THM; FSTCART_PASTECART; SNDCART_PASTECART] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_PASTECART; LINEAR_CONTINUOUS_ON;
+               LINEAR_FSTCART; LINEAR_SNDCART] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET));
+      REWRITE_TAC[IMAGE_o] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `IMAGE k s SUBSET c ==> t SUBSET s ==> IMAGE k t SUBSET c`))] THEN
+    SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS; FORALL_IN_PCROSS;
+             FSTCART_PASTECART; SNDCART_PASTECART];
+    DISCH_THEN(X_CHOOSE_THEN `k:real^(1,P)finite_sum->real^M`
+        STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(k:real^(1,P)finite_sum->real^M) o
+                (\z. pastecart (sndcart z) (fstcart z))` THEN
+    ASM_SIMP_TAC[o_THM; FSTCART_PASTECART; SNDCART_PASTECART;
+                 FORALL_IN_PCROSS; PASTECART_IN_PCROSS] THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_PASTECART; LINEAR_CONTINUOUS_ON;
+               LINEAR_FSTCART; LINEAR_SNDCART] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET));
+      REWRITE_TAC[IMAGE_o] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `IMAGE k s SUBSET c ==> t SUBSET s ==> IMAGE k t SUBSET c`));
+      MAP_EVERY X_GEN_TAC [`x:real^P`; `t:real^1`] THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `pastecart (t:real^1) (x:real^P)`)] THEN
+    ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS;
+                 FSTCART_PASTECART; SNDCART_PASTECART; FORALL_IN_PCROSS]]);;
+
+let COVERING_SPACE_LIFT_PATH_STRONG = prove
+ (`!p:real^M->real^N c s g a.
+     covering_space (c,p) s /\
+     path g /\ path_image g SUBSET s /\ pathstart g = p(a) /\ a IN c
+     ==> ?h. path h /\ path_image h SUBSET c /\ pathstart h = a /\
+             !t. t IN interval[vec 0,vec 1] ==> p(h t) = g t`,
+  REWRITE_TAC[path_image; path; pathstart] THEN
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o
+    ISPECL [`(g:real^1->real^N) o (fstcart:real^(1,P)finite_sum->real^1)`;
+            `(\y. a):real^P->real^M`; `{arb:real^P}`] o
+    MATCH_MP(ONCE_REWRITE_RULE[IMP_CONJ] COVERING_SPACE_LIFT_HOMOTOPY)) THEN
+  REWRITE_TAC[FORALL_IN_INSERT; NOT_IN_EMPTY; o_THM; FSTCART_PASTECART] THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[IMAGE_o; CONTINUOUS_ON_CONST] THEN
+    ASM_REWRITE_TAC[SET_RULE `IMAGE (\y. a) {b} SUBSET s <=> a IN s`] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[LINEAR_FSTCART; LINEAR_CONTINUOUS_ON] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET));
+      ALL_TAC] THEN
+    ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+    SIMP_TAC[FSTCART_PASTECART] THEN ASM SET_TAC[];
+    DISCH_THEN(X_CHOOSE_THEN `k:real^(1,P)finite_sum->real^M`
+        STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(k:real^(1,P)finite_sum->real^M) o (\t. pastecart t arb)` THEN
+    ASM_REWRITE_TAC[o_THM; IMAGE_o] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_PASTECART;
+               CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+      SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS; IN_SING];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `IMAGE k s SUBSET c ==> t SUBSET s ==> IMAGE k t SUBSET c`)) THEN
+      SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS; IN_SING];
+      X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `pastecart (t:real^1) (arb:real^P)`) THEN
+      ASM_SIMP_TAC[PASTECART_IN_PCROSS; FSTCART_PASTECART; IN_SING]]]);;
+
+let COVERING_SPACE_LIFT_PATH = prove
+ (`!p:real^M->real^N c s g.
+     covering_space (c,p) s /\ path g /\ path_image g SUBSET s
+     ==> ?h. path h /\ path_image h SUBSET c /\
+             !t. t IN interval[vec 0,vec 1] ==> p(h t) = g t`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+   `IMAGE g i SUBSET s ==> vec 0 IN i ==> g(vec 0) IN s`) o
+   GEN_REWRITE_RULE LAND_CONV [path_image]) THEN
+  REWRITE_TAC[ENDS_IN_UNIT_INTERVAL] THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+  REWRITE_TAC[IN_IMAGE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `a:real^M` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`p:real^M->real^N`; `c:real^M->bool`; `s:real^N->bool`;
+                `g:real^1->real^N`; `a:real^M`]
+    COVERING_SPACE_LIFT_PATH_STRONG) THEN
+  ASM_REWRITE_TAC[pathstart] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[]);;
+
+let COVERING_SPACE_LIFT_HOMOTOPIC_PATHS = prove
+ (`!p:real^M->real^N c s g1 g2 h1 h2.
+     covering_space (c,p) s /\
+     path g1 /\ path_image g1 SUBSET s /\
+     path g2 /\ path_image g2 SUBSET s /\
+     homotopic_paths s g1 g2 /\
+     path h1 /\ path_image h1 SUBSET c /\
+     (!t. t IN interval[vec 0,vec 1] ==> p(h1 t) = g1 t) /\
+     path h2 /\ path_image h2 SUBSET c /\
+     (!t. t IN interval[vec 0,vec 1] ==> p(h2 t) = g2 t) /\
+     pathstart h1 = pathstart h2
+     ==> homotopic_paths c h1 h2`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[HOMOTOPIC_PATHS] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopic_paths]) THEN
+  REWRITE_TAC[homotopic_with; pathstart; pathfinish] THEN
+  DISCH_THEN(X_CHOOSE_THEN
+   `h:real^(1,1)finite_sum->real^N` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o ISPECL
+   [`h:real^(1,1)finite_sum->real^N`; `(\x. pathstart h2):real^1->real^M`;
+    `interval[vec 0:real^1,vec 1]`] o
+   MATCH_MP(ONCE_REWRITE_RULE[IMP_CONJ] COVERING_SPACE_LIFT_HOMOTOPY_ALT)) THEN
+  ASM_SIMP_TAC[] THEN ANTS_TAC THENL
+   [REWRITE_TAC[CONTINUOUS_ON_CONST; SUBSET; FORALL_IN_IMAGE] THEN
+    ASM_MESON_TAC[pathstart; ENDS_IN_UNIT_INTERVAL; PATHSTART_IN_PATH_IMAGE;
+                  SUBSET];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^(1,1)finite_sum->real^M` THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[o_DEF] THEN
+  MATCH_MP_TAC(TAUT `(p /\ q) /\ (p /\ q ==> r) ==> p /\ q /\ r`) THEN
+  CONJ_TAC THENL
+   [CONJ_TAC THEN
+    FIRST_ASSUM(MATCH_MP_TAC o
+      REWRITE_RULE[RIGHT_FORALL_IMP_THM] o
+      ONCE_REWRITE_RULE[IMP_CONJ] o
+      REWRITE_RULE[CONJ_ASSOC] o MATCH_MP
+       (ONCE_REWRITE_RULE[IMP_CONJ] COVERING_SPACE_LIFT_UNIQUE)) THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC] THENL
+     [MAP_EVERY EXISTS_TAC [`g1:real^1->real^N`; `vec 0:real^1`];
+      MAP_EVERY EXISTS_TAC [`g2:real^1->real^N`; `vec 0:real^1`]] THEN
+    ASM_SIMP_TAC[ENDS_IN_UNIT_INTERVAL; UNIT_INTERVAL_NONEMPTY] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[path_image; pathstart; pathfinish; path]) THEN
+    ASM_REWRITE_TAC[CONNECTED_INTERVAL; pathstart; pathfinish] THEN
+    REWRITE_TAC[CONJ_ASSOC] THEN
+    (REPEAT CONJ_TAC THENL
+     [GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_CONST;
+               CONTINUOUS_ON_ID] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET));
+      GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM o_DEF] THEN
+      REWRITE_TAC[IMAGE_o] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `IMAGE k s SUBSET c ==> t SUBSET s ==> IMAGE k t SUBSET c`));
+      ASM_MESON_TAC[PASTECART_IN_PCROSS; ENDS_IN_UNIT_INTERVAL]] THEN
+     SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS; FORALL_IN_PCROSS;
+              FSTCART_PASTECART; SNDCART_PASTECART; ENDS_IN_UNIT_INTERVAL]);
+     STRIP_TAC THEN
+     REWRITE_TAC[TAUT `p ==> q /\ r <=> (p ==> q) /\ (p ==> r)`] THEN
+     REWRITE_TAC[FORALL_AND_THM] THEN CONJ_TAC THENL
+      [ASM_MESON_TAC[pathstart; ENDS_IN_UNIT_INTERVAL]; ALL_TAC] THEN
+     FIRST_ASSUM(MATCH_MP_TAC o
+      REWRITE_RULE[RIGHT_FORALL_IMP_THM] o
+      ONCE_REWRITE_RULE[IMP_CONJ] o
+      REWRITE_RULE[CONJ_ASSOC] o MATCH_MP
+       (ONCE_REWRITE_RULE[IMP_CONJ] COVERING_SPACE_LIFT_UNIQUE)) THEN
+     MAP_EVERY EXISTS_TAC
+      [`(\x. pathfinish g1):real^1->real^N`; `vec 0:real^1`] THEN
+     ASM_SIMP_TAC[ENDS_IN_UNIT_INTERVAL; CONNECTED_INTERVAL] THEN
+     REWRITE_TAC[CONTINUOUS_ON_CONST; pathfinish] THEN
+     REPEAT CONJ_TAC THENL
+      [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+       ASM_MESON_TAC[SUBSET; pathfinish; PATHFINISH_IN_PATH_IMAGE];
+       GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+       MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+       SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_CONST;
+                CONTINUOUS_ON_ID] THEN
+       FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+           CONTINUOUS_ON_SUBSET)) THEN
+       SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS; FORALL_IN_PCROSS;
+                FSTCART_PASTECART; SNDCART_PASTECART; ENDS_IN_UNIT_INTERVAL];
+       REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+       X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+       FIRST_X_ASSUM(MP_TAC o SPEC `pastecart (t:real^1) (vec 1:real^1)` o
+         REWRITE_RULE[FORALL_IN_IMAGE] o GEN_REWRITE_RULE I [SUBSET]) THEN
+       ASM_REWRITE_TAC[PASTECART_IN_PCROSS; ENDS_IN_UNIT_INTERVAL];
+       ASM_MESON_TAC[PASTECART_IN_PCROSS; ENDS_IN_UNIT_INTERVAL];
+       REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+       ASM_MESON_TAC[SUBSET; pathfinish; PATHFINISH_IN_PATH_IMAGE]]]);;
+
+let COVERING_SPACE_MONODROMY = prove
+ (`!p:real^M->real^N c s g1 g2 h1 h2.
+     covering_space (c,p) s /\
+     path g1 /\ path_image g1 SUBSET s /\
+     path g2 /\ path_image g2 SUBSET s /\
+     homotopic_paths s g1 g2 /\
+     path h1 /\ path_image h1 SUBSET c /\
+     (!t. t IN interval[vec 0,vec 1] ==> p(h1 t) = g1 t) /\
+     path h2 /\ path_image h2 SUBSET c /\
+     (!t. t IN interval[vec 0,vec 1] ==> p(h2 t) = g2 t) /\
+     pathstart h1 = pathstart h2
+     ==> pathfinish h1 = pathfinish h2`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP COVERING_SPACE_LIFT_HOMOTOPIC_PATHS) THEN
+  REWRITE_TAC[HOMOTOPIC_PATHS_IMP_PATHFINISH]);;
+
+let COVERING_SPACE_LIFT_HOMOTOPIC_PATH = prove
+ (`!p:real^M->real^N c s f f' g a b.
+        covering_space (c,p) s /\
+        homotopic_paths s f f' /\
+        path g /\ path_image g SUBSET c /\
+        pathstart g = a /\ pathfinish g = b /\
+        (!t. t IN interval[vec 0,vec 1] ==> p(g t) = f t)
+        ==> ?g'. path g' /\ path_image g' SUBSET c /\
+                 pathstart g' = a /\ pathfinish g' = b /\
+                 (!t. t IN interval[vec 0,vec 1] ==> p(g' t) = f' t)`,
+  ONCE_REWRITE_TAC[HOMOTOPIC_PATHS_SYM] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATH) THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_SUBSET) THEN
+  FIRST_ASSUM(MP_TAC o ISPECL [`f':real^1->real^N`; `a:real^M`] o
+   MATCH_MP(ONCE_REWRITE_RULE[IMP_CONJ] COVERING_SPACE_LIFT_PATH_STRONG)) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[pathstart; ENDS_IN_UNIT_INTERVAL;
+                    HOMOTOPIC_PATHS_IMP_PATHSTART];
+      ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; SUBSET]];
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g':real^1->real^M` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    SUBST1_TAC(SYM(ASSUME `pathfinish g:real^M = b`)) THEN
+    FIRST_ASSUM(MATCH_MP_TAC o
+     MATCH_MP(ONCE_REWRITE_RULE[IMP_CONJ] COVERING_SPACE_MONODROMY)) THEN
+    MAP_EVERY EXISTS_TAC [`f':real^1->real^N`; `f:real^1->real^N`] THEN
+    ASM_REWRITE_TAC[]]);;
+
+let COVERING_SPACE_INESSENTIAL_LOOP_LIFT_IS_LOOP = prove
+ (`!p:real^M->real^N c s g h a.
+        covering_space (c,p) s /\
+        path g /\ path_image g SUBSET s /\ pathfinish g = pathstart g /\
+        homotopic_paths s g (linepath(a,a)) /\
+        path h /\ path_image h SUBSET c /\
+        (!t. t IN interval[vec 0,vec 1] ==> p(h t) = g t)
+        ==> pathfinish h = pathstart h`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_SUBSET) THEN
+  REWRITE_TAC[PATH_IMAGE_LINEPATH; SEGMENT_REFL; SING_SUBSET] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHSTART) THEN
+  REWRITE_TAC[PATHSTART_LINEPATH] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o
+    ISPECL [`g:real^1->real^N`; `linepath(a:real^N,a)`;
+            `h:real^1->real^M`; `linepath(pathstart h:real^M,pathstart h)`] o
+    MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        COVERING_SPACE_MONODROMY)) THEN
+  ASM_REWRITE_TAC[PATH_LINEPATH; PATH_IMAGE_LINEPATH; SEGMENT_REFL] THEN
+  ASM_REWRITE_TAC[SING_SUBSET; PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+  DISCH_THEN MATCH_MP_TAC THEN REWRITE_TAC[LINEPATH_REFL] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; SUBSET];
+    REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [SYM th]) THEN
+    REWRITE_TAC[pathstart] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[ENDS_IN_UNIT_INTERVAL]]);;
+
+let COVERING_SPACE_SIMPLY_CONNECTED_LOOP_LIFT_IS_LOOP = prove
+ (`!p:real^M->real^N c s g h.
+        covering_space (c,p) s /\ simply_connected s /\
+        path g /\ path_image g SUBSET s /\ pathfinish g = pathstart g /\
+        path h /\ path_image h SUBSET c /\
+        (!t. t IN interval[vec 0,vec 1] ==> p(h t) = g t)
+        ==> pathfinish h = pathstart h`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o
+    MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        COVERING_SPACE_INESSENTIAL_LOOP_LIFT_IS_LOOP)) THEN
+  EXISTS_TAC `g:real^1->real^N` THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_PATH]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Lifting of general functions to covering space                            *)
+(* ------------------------------------------------------------------------- *)
+
+let COVERING_SPACE_LIFT_GENERAL = prove
+ (`!p:real^M->real^N c s f:real^P->real^N u a z.
+        covering_space (c,p) s /\ a IN c /\ z IN u /\
+        path_connected u /\ locally path_connected u /\
+        f continuous_on u /\ IMAGE f u SUBSET s /\ f z = p a /\
+        (!r. path r /\ path_image r SUBSET u /\
+             pathstart r = z /\ pathfinish r = z
+             ==> ?q. path q /\ path_image q SUBSET c /\
+                     pathstart q = a /\ pathfinish q = a /\
+                     homotopic_paths s (f o r) (p o q))
+        ==> ?g. g continuous_on u /\ IMAGE g u SUBSET c /\ g z = a /\
+                (!y. y IN u ==> p(g y) = f y)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!y. y IN u
+        ==> ?g h. path g /\ path_image g SUBSET u /\
+                  pathstart g = z /\ pathfinish g = y /\
+                  path h /\ path_image h SUBSET c /\ pathstart h = a /\
+                  (!t. t IN interval[vec 0,vec 1]
+                       ==> (p:real^M->real^N)(h t) = (f:real^P->real^N)(g t))`
+   (LABEL_TAC "*")
+  THENL
+   [X_GEN_TAC `y:real^P` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [path_connected]) THEN
+    DISCH_THEN(MP_TAC o SPECL [`z:real^P`; `y:real^P`]) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `g:real^1->real^P` THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC  COVERING_SPACE_LIFT_PATH_STRONG THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[GSYM o_DEF] THEN
+    ASM_REWRITE_TAC[PATH_IMAGE_COMPOSE; PATHSTART_COMPOSE] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC PATH_CONTINUOUS_IMAGE THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+      ASM SET_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?l. !y g h. path g /\ path_image g SUBSET u /\
+                pathstart g = z /\ pathfinish g = y /\
+                path h /\ path_image h SUBSET c /\ pathstart h = a /\
+                (!t. t IN interval[vec 0,vec 1]
+                     ==> (p:real^M->real^N)(h t) = (f:real^P->real^N)(g t))
+                ==> pathfinish h = l y`
+  MP_TAC THENL
+   [REWRITE_TAC[GSYM SKOLEM_THM] THEN X_GEN_TAC `y:real^P` THEN
+    MATCH_MP_TAC(MESON[]
+      `(!g h g' h'. P g h /\ P g' h' ==> f h = f h')
+       ==> ?z. !g h. P g h ==> f h = z`) THEN
+    REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(g ++ reversepath g'):real^1->real^P`) THEN
+    ASM_SIMP_TAC[PATH_JOIN; PATHSTART_JOIN; PATHFINISH_JOIN;
+      PATH_REVERSEPATH; PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH;
+      SUBSET_PATH_IMAGE_JOIN; PATH_IMAGE_REVERSEPATH] THEN
+    DISCH_THEN(X_CHOOSE_THEN `q:real^1->real^M` STRIP_ASSUME_TAC) THEN
+    FIRST_ASSUM(MP_TAC o
+     ISPECL [`(p:real^M->real^N) o (q:real^1->real^M)`;
+             `(f:real^P->real^N) o (g ++ reversepath g')`;
+             `q:real^1->real^M`; `pathstart q:real^M`; `pathfinish q:real^M`] o
+      MATCH_MP(ONCE_REWRITE_RULE[IMP_CONJ]
+       (ONCE_REWRITE_RULE[HOMOTOPIC_PATHS_SYM]
+         COVERING_SPACE_LIFT_HOMOTOPIC_PATH))) THEN
+    ASM_REWRITE_TAC[o_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `q':real^1->real^M` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `path(h ++ reversepath h':real^1->real^M)` MP_TAC THENL
+     [ALL_TAC;
+      ASM_SIMP_TAC[PATH_JOIN_EQ; PATH_REVERSEPATH; PATHSTART_REVERSEPATH]] THEN
+    MATCH_MP_TAC PATH_EQ THEN EXISTS_TAC `q':real^1->real^M` THEN
+    ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `t:real^1` THEN REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN
+    STRIP_TAC THEN REWRITE_TAC[joinpaths] THEN COND_CASES_TAC THENL
+     [FIRST_ASSUM(MP_TAC o
+        ISPECL [`(f:real^P->real^N) o (g:real^1->real^P) o (\t. &2 % t)`;
+                `q':real^1->real^M`;
+                `(h:real^1->real^M) o (\t. &2 % t)`;
+                `interval[vec 0,lift(&1 / &2)]`;
+                `vec 0:real^1`; `t:real^1`] o
+        MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ] COVERING_SPACE_LIFT_UNIQUE)) THEN
+      REWRITE_TAC[o_THM] THEN DISCH_THEN MATCH_MP_TAC THEN
+      REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_EQ THEN
+        EXISTS_TAC `(f:real^P->real^N) o (g ++ reversepath g')` THEN
+        CONJ_TAC THENL
+         [SIMP_TAC[IN_INTERVAL_1; LIFT_DROP; joinpaths; o_THM];
+          ALL_TAC] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+        EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN CONJ_TAC THENL
+         [ASM_MESON_TAC[HOMOTOPIC_PATHS_IMP_PATH; path];
+          REWRITE_TAC[SUBSET_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+          REAL_ARITH_TAC];
+        MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC
+         `path_image ((f:real^P->real^N) o (g ++ reversepath g'))` THEN
+        CONJ_TAC THENL[ALL_TAC; ASM_MESON_TAC[HOMOTOPIC_PATHS_IMP_SUBSET]] THEN
+        REWRITE_TAC[path_image] THEN MATCH_MP_TAC(SET_RULE
+         `(!x. x IN s ==> f x = g x) /\ s SUBSET t
+          ==> IMAGE f s SUBSET IMAGE g t`) THEN
+        REWRITE_TAC[SUBSET_INTERVAL_1; LIFT_DROP; DROP_VEC; IN_INTERVAL_1] THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV THEN SIMP_TAC[joinpaths; o_THM];
+        MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+        EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+        ASM_REWRITE_TAC[GSYM path] THEN
+        REWRITE_TAC[SUBSET_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+        REAL_ARITH_TAC;
+        MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC
+         `path_image(q':real^1->real^M)` THEN
+        ASM_REWRITE_TAC[] THEN REWRITE_TAC[path_image] THEN
+        MATCH_MP_TAC IMAGE_SUBSET THEN
+        REWRITE_TAC[SUBSET_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+        REAL_ARITH_TAC;
+        X_GEN_TAC `t':real^1` THEN
+        REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN STRIP_TAC THEN
+        FIRST_X_ASSUM(fun th ->
+         W(MP_TAC o PART_MATCH (lhand o rand) th o rand o snd)) THEN
+        ASM_SIMP_TAC[IN_INTERVAL_1; joinpaths; DROP_VEC] THEN
+        ANTS_TAC THENL [ASM_REAL_ARITH_TAC; SIMP_TAC[]];
+        MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        SIMP_TAC[CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+        EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+        ASM_SIMP_TAC[GSYM path] THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+        REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_CMUL; LIFT_DROP] THEN
+        REAL_ARITH_TAC;
+        MATCH_MP_TAC SUBSET_TRANS THEN
+        EXISTS_TAC `path_image(h:real^1->real^M)` THEN
+        CONJ_TAC THENL [ALL_TAC; ASM_SIMP_TAC[]] THEN
+        REWRITE_TAC[path_image; IMAGE_o] THEN MATCH_MP_TAC IMAGE_SUBSET THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1] THEN
+        REWRITE_TAC[DROP_VEC; DROP_CMUL; LIFT_DROP] THEN
+        REAL_ARITH_TAC;
+        X_GEN_TAC `t':real^1` THEN
+        REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN STRIP_TAC THEN
+        CONV_TAC SYM_CONV THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+        REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_CMUL] THEN
+        ASM_REAL_ARITH_TAC;
+        REWRITE_TAC[CONNECTED_INTERVAL];
+        REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN REAL_ARITH_TAC;
+        GEN_REWRITE_TAC LAND_CONV [GSYM pathstart] THEN
+        ASM_REWRITE_TAC[] THEN
+        SUBST1_TAC(SYM(ASSUME `pathstart h:real^M = a`)) THEN
+        REWRITE_TAC[pathstart] THEN AP_TERM_TAC THEN
+        REWRITE_TAC[VECTOR_MUL_RZERO];
+        REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+        ASM_REAL_ARITH_TAC];
+      FIRST_ASSUM(MP_TAC o
+        ISPECL [`(f:real^P->real^N) o reversepath(g':real^1->real^P) o
+                 (\t. &2 % t - vec 1)`;
+                `q':real^1->real^M`;
+                `reversepath(h':real^1->real^M) o (\t. &2 % t - vec 1)`;
+                `{t | &1 / &2 < drop t /\ drop t <= &1}`;
+                `vec 1:real^1`; `t:real^1`] o
+        MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ] COVERING_SPACE_LIFT_UNIQUE)) THEN
+      REWRITE_TAC[o_THM] THEN DISCH_THEN MATCH_MP_TAC THEN
+      REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_EQ THEN
+        EXISTS_TAC `(f:real^P->real^N) o (g ++ reversepath g')` THEN
+        CONJ_TAC THENL
+         [SIMP_TAC[IN_ELIM_THM; GSYM REAL_NOT_LE; joinpaths; o_THM];
+          ALL_TAC] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+        EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN CONJ_TAC THENL
+         [ASM_MESON_TAC[HOMOTOPIC_PATHS_IMP_PATH; path];
+          REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_INTERVAL_1; DROP_VEC] THEN
+          REAL_ARITH_TAC];
+        MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC
+         `path_image ((f:real^P->real^N) o (g ++ reversepath g'))` THEN
+        CONJ_TAC THENL[ALL_TAC; ASM_MESON_TAC[HOMOTOPIC_PATHS_IMP_SUBSET]] THEN
+        REWRITE_TAC[path_image] THEN MATCH_MP_TAC(SET_RULE
+         `(!x. x IN s ==> f x = g x) /\ s SUBSET t
+          ==> IMAGE f s SUBSET IMAGE g t`) THEN
+        SIMP_TAC[IN_ELIM_THM; GSYM REAL_NOT_LE; joinpaths; o_THM] THEN
+        REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_INTERVAL_1; DROP_VEC] THEN
+        REAL_ARITH_TAC;
+        MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+        EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+        ASM_REWRITE_TAC[GSYM path] THEN
+        REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_INTERVAL_1; DROP_VEC] THEN
+        REAL_ARITH_TAC;
+        MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC
+         `path_image(q':real^1->real^M)` THEN
+        ASM_REWRITE_TAC[] THEN REWRITE_TAC[path_image] THEN
+        MATCH_MP_TAC IMAGE_SUBSET THEN
+        REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_INTERVAL_1; DROP_VEC] THEN
+        REAL_ARITH_TAC;
+        X_GEN_TAC `t':real^1` THEN REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN
+        FIRST_X_ASSUM(fun th ->
+         W(MP_TAC o PART_MATCH (lhand o rand) th o rand o snd)) THEN
+        ASM_SIMP_TAC[IN_INTERVAL_1; joinpaths; DROP_VEC; GSYM REAL_NOT_LT] THEN
+        ANTS_TAC THENL [ASM_REAL_ARITH_TAC; SIMP_TAC[]];
+        MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID;
+                 CONTINUOUS_ON_CONST] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+        EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+        ASM_SIMP_TAC[GSYM path; PATH_REVERSEPATH] THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+        REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_CMUL; DROP_SUB] THEN
+        REAL_ARITH_TAC;
+        MATCH_MP_TAC SUBSET_TRANS THEN
+        EXISTS_TAC `path_image(reversepath h':real^1->real^M)` THEN
+        CONJ_TAC THENL [ALL_TAC; ASM_SIMP_TAC[PATH_IMAGE_REVERSEPATH]] THEN
+        REWRITE_TAC[path_image; IMAGE_o] THEN MATCH_MP_TAC IMAGE_SUBSET THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+        REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_CMUL; DROP_SUB] THEN
+        REAL_ARITH_TAC;
+        X_GEN_TAC `t':real^1` THEN REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN
+        REWRITE_TAC[reversepath] THEN CONV_TAC SYM_CONV THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN
+        REWRITE_TAC[IN_INTERVAL_1; DROP_SUB; DROP_VEC; DROP_CMUL] THEN
+        ASM_REAL_ARITH_TAC;
+        REWRITE_TAC[GSYM IS_INTERVAL_CONNECTED_1; IS_INTERVAL_1] THEN
+        REWRITE_TAC[IN_ELIM_THM] THEN REAL_ARITH_TAC;
+        REWRITE_TAC[IN_ELIM_THM; DROP_VEC] THEN REAL_ARITH_TAC;
+        GEN_REWRITE_TAC LAND_CONV [GSYM pathfinish] THEN
+        ASM_REWRITE_TAC[reversepath] THEN
+        SUBST1_TAC(SYM(ASSUME `pathstart h':real^M = a`)) THEN
+        REWRITE_TAC[pathstart] THEN AP_TERM_TAC THEN
+        REWRITE_TAC[GSYM DROP_EQ; DROP_SUB; DROP_CMUL; DROP_VEC] THEN
+        REAL_ARITH_TAC;
+        REWRITE_TAC[IN_ELIM_THM] THEN ASM_REAL_ARITH_TAC]];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `l:real^P->real^M` THEN
+  DISCH_THEN(LABEL_TAC "+") THEN
+  MATCH_MP_TAC(TAUT `(q ==> p) /\ q ==> p /\ q`) THEN REPEAT CONJ_TAC THENL
+   [STRIP_TAC;
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `y:real^P` THEN DISCH_TAC THEN
+    REMOVE_THEN "*" (MP_TAC o SPEC `y:real^P`) THEN
+    ASM_MESON_TAC[PATHFINISH_IN_PATH_IMAGE; SUBSET];
+    FIRST_ASSUM(MP_TAC o SPECL
+     [`z:real^P`; `linepath(z:real^P,z)`; `linepath(a:real^M,a)`]) THEN
+    REWRITE_TAC[PATH_LINEPATH; PATH_IMAGE_LINEPATH; SEGMENT_REFL] THEN
+    REWRITE_TAC[PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+    ASM_SIMP_TAC[LINEPATH_REFL; SING_SUBSET];
+    X_GEN_TAC `y:real^P` THEN DISCH_TAC THEN
+    REMOVE_THEN "*" (MP_TAC o SPEC `y:real^P`) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`g:real^1->real^P`; `h:real^1->real^M`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+     [`y:real^P`; `g:real^1->real^P`; `h:real^1->real^M`]) THEN
+    ASM_MESON_TAC[pathfinish; ENDS_IN_UNIT_INTERVAL]] THEN
+  FIRST_ASSUM(fun th ->
+   GEN_REWRITE_TAC I [MATCH_MP CONTINUOUS_ON_OPEN_GEN th]) THEN
+  X_GEN_TAC `n:real^M->bool` THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN X_GEN_TAC `y:real^P` THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [open_in]) THEN
+  FIRST_ASSUM(MP_TAC o SPEC `(f:real^P->real^N) y` o last o CONJUNCTS o
+        GEN_REWRITE_RULE I [covering_space]) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `w:real^N->bool` MP_TAC) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `vv:(real^M->bool)->bool` MP_TAC) THEN
+  ONCE_REWRITE_TAC[IMP_CONJ] THEN
+  GEN_REWRITE_TAC LAND_CONV [EXTENSION] THEN
+  DISCH_THEN(MP_TAC o SPEC `(l:real^P->real^M) y`) THEN
+  MATCH_MP_TAC(TAUT `q /\ (p ==> r) ==> (p <=> q) ==> r`) THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[IN_UNIONS]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `w':real^M->bool` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (MP_TAC o SPEC `w':real^M->bool`) MP_TAC) THEN
+  DISCH_THEN(MP_TAC o SPEC `w':real^M->bool` o CONJUNCT2) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_TAC `p':real^N->real^M`) THEN
+  DISCH_TAC THEN UNDISCH_THEN `(w':real^M->bool) IN vv` (K ALL_TAC) THEN
+  SUBGOAL_THEN
+   `?v. y IN v /\ y IN u /\ IMAGE (f:real^P->real^N) v SUBSET w /\
+        v SUBSET u /\ path_connected v /\ open_in (subtopology euclidean u) v`
+  STRIP_ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LOCALLY_PATH_CONNECTED]) THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`{x | x IN u /\ (f:real^P->real^N) x IN w}`; `y:real^P`]) THEN
+    ANTS_TAC THENL [ALL_TAC; MATCH_MP_TAC MONO_EXISTS THEN ASM SET_TAC[]] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(STRIP_ASSUME_TAC o
+   GEN_REWRITE_RULE I [homeomorphism]) THEN
+  SUBGOAL_THEN `(w':real^M->bool) SUBSET c /\ (w:real^N->bool) SUBSET s`
+  STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[open_in]; ALL_TAC] THEN
+  EXISTS_TAC
+   `v INTER
+    {x | x IN u /\ (f:real^P->real^N) x IN
+                   {x | x IN w /\ (p':real^N->real^M) x IN w' INTER n}}` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC OPEN_IN_INTER THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC OPEN_IN_TRANS THEN EXISTS_TAC `w:real^N->bool` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN THEN
+    EXISTS_TAC `w':real^M->bool` THEN ASM_REWRITE_TAC[SUBSET_REFL] THEN
+    UNDISCH_TAC `open_in (subtopology euclidean c) (n:real^M->bool)` THEN
+    REWRITE_TAC[OPEN_IN_OPEN] THEN MATCH_MP_TAC MONO_EXISTS THEN ASM SET_TAC[];
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  SIMP_TAC[SUBSET; IN_INTER; IN_ELIM_THM] THEN
+  X_GEN_TAC `y':real^P` THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [path_connected]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`y:real^P`; `y':real^P`]) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real^1->real^P` STRIP_ASSUME_TAC) THEN
+  REMOVE_THEN "*" (MP_TAC o SPEC `y:real^P`) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`pp:real^1->real^P`; `qq:real^1->real^M`] THEN
+  STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPECL
+   [`y':real^P`; `(pp:real^1->real^P) ++ r`;
+    `(qq:real^1->real^M) ++ ((p':real^N->real^M) o (f:real^P->real^N) o
+                            (r:real^1->real^P))`]) THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+   [`y:real^P`; `pp:real^1->real^P`; `qq:real^1->real^M`]) THEN
+  ASM_SIMP_TAC[o_THM; PATHSTART_JOIN; PATHFINISH_JOIN] THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `path_image ((pp:real^1->real^P) ++ r) SUBSET u`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC SUBSET_PATH_IMAGE_JOIN THEN ASM SET_TAC[]; ALL_TAC] THEN
+  ANTS_TAC THENL
+   [ALL_TAC;
+    ASM_REWRITE_TAC[PATHFINISH_COMPOSE] THEN ASM_MESON_TAC[]] THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_SIMP_TAC[PATH_JOIN];
+    ASM_SIMP_TAC[SUBSET_PATH_IMAGE_JOIN];
+    MATCH_MP_TAC PATH_JOIN_IMP THEN ASM_SIMP_TAC[PATHSTART_COMPOSE] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[o_ASSOC] THEN MATCH_MP_TAC PATH_CONTINUOUS_IMAGE THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      CONJ_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+             CONTINUOUS_ON_SUBSET)) THEN
+      ASM SET_TAC[];
+      REWRITE_TAC[pathfinish] THEN ASM SET_TAC[]];
+    MATCH_MP_TAC SUBSET_PATH_IMAGE_JOIN THEN ASM_SIMP_TAC[] THEN
+    REWRITE_TAC[PATH_IMAGE_COMPOSE] THEN ASM SET_TAC[];
+    X_GEN_TAC `tt:real^1` THEN REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN
+    STRIP_TAC THEN REWRITE_TAC[joinpaths; o_THM] THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[] THENL
+     [ABBREV_TAC `t:real^1 = &2 % tt`;
+      ABBREV_TAC `t:real^1 = &2 % tt - vec 1`] THEN
+    (SUBGOAL_THEN `t IN interval[vec 0:real^1,vec 1]` ASSUME_TAC THENL
+      [EXPAND_TAC "t" THEN
+       REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; DROP_CMUL; DROP_SUB] THEN
+       ASM_REAL_ARITH_TAC;
+       ALL_TAC]) THEN
+    ASM_SIMP_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[path_image]) THEN ASM SET_TAC[]]);;
+
+let COVERING_SPACE_LIFT_STRONGER = prove
+ (`!p:real^M->real^N c s f:real^P->real^N u a z.
+        covering_space (c,p) s /\ a IN c /\ z IN u /\
+        path_connected u /\ locally path_connected u /\
+        f continuous_on u /\ IMAGE f u SUBSET s /\ f z = p a /\
+        (!r. path r /\ path_image r SUBSET u /\
+             pathstart r = z /\ pathfinish r = z
+             ==> ?b. homotopic_paths s (f o r) (linepath(b,b)))
+        ==> ?g. g continuous_on u /\ IMAGE g u SUBSET c /\ g z = a /\
+                (!y. y IN u ==> p(g y) = f y)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        COVERING_SPACE_LIFT_GENERAL)) THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `r:real^1->real^P` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC  `r:real^1->real^P`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_TAC `b:real^N`) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_PATHS_IMP_PATHSTART) THEN
+  ASM_REWRITE_TAC[PATHSTART_COMPOSE; PATHSTART_LINEPATH] THEN
+  DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+  EXISTS_TAC `linepath(a:real^M,a)` THEN
+  REWRITE_TAC[PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+  ASM_REWRITE_TAC[PATH_IMAGE_LINEPATH; SEGMENT_REFL; SING_SUBSET] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[o_DEF; LINEPATH_REFL]) THEN
+  ASM_REWRITE_TAC[o_DEF; LINEPATH_REFL]);;
+
+let COVERING_SPACE_LIFT_STRONG = prove
+ (`!p:real^M->real^N c s f:real^P->real^N u a z.
+        covering_space (c,p) s /\ a IN c /\ z IN u /\
+        simply_connected u /\ locally path_connected u /\
+        f continuous_on u /\ IMAGE f u SUBSET s /\ f z = p a
+        ==> ?g. g continuous_on u /\ IMAGE g u SUBSET c /\ g z = a /\
+                (!y. y IN u ==> p(g y) = f y)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        COVERING_SPACE_LIFT_STRONGER)) THEN
+  ASM_SIMP_TAC[SIMPLY_CONNECTED_IMP_PATH_CONNECTED] THEN
+  X_GEN_TAC `r:real^1->real^P` THEN STRIP_TAC THEN
+  EXISTS_TAC `(f:real^P->real^N) z` THEN
+  SUBGOAL_THEN
+   `linepath(f z,f z) = (f:real^P->real^N) o linepath(z,z)`
+  SUBST1_TAC THENL [REWRITE_TAC[o_DEF; LINEPATH_REFL]; ALL_TAC] THEN
+  MATCH_MP_TAC HOMOTOPIC_PATHS_CONTINUOUS_IMAGE THEN
+  EXISTS_TAC `u:real^P->bool` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o CONJUNCT2 o GEN_REWRITE_RULE I
+   [SIMPLY_CONNECTED_EQ_HOMOTOPIC_PATHS]) THEN
+  ASM_REWRITE_TAC[PATH_LINEPATH; PATHSTART_LINEPATH; PATHFINISH_LINEPATH] THEN
+  ASM_REWRITE_TAC[PATH_IMAGE_LINEPATH; SEGMENT_REFL; SING_SUBSET]);;
+
+let COVERING_SPACE_LIFT = prove
+ (`!p:real^M->real^N c s f:real^P->real^N u.
+        covering_space (c,p) s /\
+        simply_connected u /\ locally path_connected u /\
+        f continuous_on u /\ IMAGE f u SUBSET s
+        ==> ?g. g continuous_on u /\ IMAGE g u SUBSET c /\
+                (!y. y IN u ==> p(g y) = f y)`,
+  MP_TAC COVERING_SPACE_LIFT_STRONG THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th THEN ASM_REWRITE_TAC[]) THEN
+  ASM_CASES_TAC `u:real^P->bool = {}` THEN
+  ASM_REWRITE_TAC[CONTINUOUS_ON_EMPTY; IMAGE_CLAUSES; EMPTY_SUBSET;
+                  NOT_IN_EMPTY] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^P`) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+  GEN_REWRITE_TAC LAND_CONV [EXTENSION] THEN
+  DISCH_THEN(MP_TAC o SPEC `(f:real^P->real^N) a`) THEN
+  MATCH_MP_TAC(TAUT `q /\ (p ==> r) ==> (p <=> q) ==> r`) THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[IN_IMAGE]] THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some additional lemmas about covering spaces.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let CARD_EQ_COVERING_MAP_FIBRES = prove
+ (`!p:real^M->real^N c s a b.
+        covering_space (c,p) s /\ path_connected s /\ a IN s /\ b IN s
+        ==> {x | x IN c /\ p(x) = a} =_c {x | x IN c /\ p(x) = b}`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REPEAT GEN_TAC THEN REPEAT DISCH_TAC THEN
+  REWRITE_TAC[GSYM CARD_LE_ANTISYM] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; FORALL_AND_THM;
+              TAUT `p ==> q /\ r <=> (p ==> q) /\ (p ==> r)`] THEN
+  GEN_REWRITE_TAC (LAND_CONV o funpow 2 BINDER_CONV o LAND_CONV)
+   [CONJ_SYM] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!a b. P a b) ==> (!a b. P a b) /\ (!a b. P b a)`) THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`a:real^N`; `b:real^N`] o
+    GEN_REWRITE_RULE I [path_connected]) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `g:real^1->real^N` THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!z. ?h. z IN c /\ p z = a
+            ==> path h /\ path_image h SUBSET c /\ pathstart h = z /\
+                !t. t IN interval[vec 0,vec 1]
+                    ==> (p:real^M->real^N)(h t) = g t`
+  MP_TAC THENL
+   [REWRITE_TAC[RIGHT_EXISTS_IMP_THM] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC COVERING_SPACE_LIFT_PATH_STRONG THEN
+    REWRITE_TAC[ETA_AX] THEN ASM_MESON_TAC[];
+    REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `h:real^M->real^1->real^M` THEN DISCH_TAC] THEN
+  REWRITE_TAC[le_c; IN_ELIM_THM] THEN
+  EXISTS_TAC `\z. pathfinish((h:real^M->real^1->real^M) z)` THEN
+  ASM_REWRITE_TAC[pathfinish] THEN CONJ_TAC THENL
+   [X_GEN_TAC `x:real^M` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN
+    ASM_REWRITE_TAC[SUBSET; path_image; pathstart; FORALL_IN_IMAGE] THEN
+    ASM_MESON_TAC[pathfinish; ENDS_IN_UNIT_INTERVAL];
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `y:real^M`] THEN STRIP_TAC THEN
+    MP_TAC(ISPECL
+     [`p:real^M->real^N`; `c:real^M->bool`; `s:real^N->bool`;
+      `reversepath(g:real^1->real^N)`; `reversepath(g:real^1->real^N)`;
+      `reversepath((h:real^M->real^1->real^M) x)`;
+      `reversepath((h:real^M->real^1->real^M) y)`]
+    COVERING_SPACE_MONODROMY) THEN
+    ASM_SIMP_TAC[PATHSTART_REVERSEPATH; PATHFINISH_REVERSEPATH] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[PATH_REVERSEPATH; PATH_IMAGE_REVERSEPATH;
+                 HOMOTOPIC_PATHS_REFL] THEN
+    ASM_REWRITE_TAC[pathfinish; reversepath; IN_INTERVAL_1; DROP_VEC] THEN
+    REPEAT STRIP_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`);
+      FIRST_X_ASSUM(MP_TAC o SPEC `y:real^M`)] THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(MATCH_MP_TAC o last o CONJUNCTS) THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_SUB; DROP_VEC] THEN ASM_REAL_ARITH_TAC]);;
+
+let COVERING_SPACE_INJECTIVE = prove
+ (`!p:real^M->real^N c s.
+        covering_space (c,p) s /\ path_connected c /\ simply_connected s
+        ==> (!x y. x IN c /\ y IN c /\ p x = p y ==> x = y)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP COVERING_SPACE_IMP_CONTINUOUS) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [path_connected]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`x:real^M`; `y:real^M`]) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^M` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        COVERING_SPACE_LIFT_PATH_STRONG)) THEN
+  GEN_REWRITE_TAC LAND_CONV [SWAP_FORALL_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(fun th ->
+    MP_TAC(SPEC `(p:real^M->real^N) o (g:real^1->real^M)` th) THEN
+    MP_TAC(SPEC `(p:real^M->real^N) o linepath(x:real^M,x)` th)) THEN
+  SUBGOAL_THEN
+   `(path ((p:real^M->real^N) o linepath(x,x)) /\
+     path (p o g)) /\
+    (path_image (p o linepath(x:real^M,x)) SUBSET s /\
+     path_image (p o g) SUBSET s)`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THENL
+     [CONJ_TAC THEN MATCH_MP_TAC PATH_CONTINUOUS_IMAGE THEN
+      REWRITE_TAC[PATH_LINEPATH; PATH_IMAGE_LINEPATH] THEN
+      ASM_REWRITE_TAC[CONTINUOUS_ON_SING; SEGMENT_REFL] THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+      REWRITE_TAC[PATH_IMAGE_COMPOSE; PATH_IMAGE_LINEPATH] THEN
+      REWRITE_TAC[SEGMENT_REFL] THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[PATHSTART_COMPOSE; PATHSTART_LINEPATH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h1:real^1->real^M` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `h2:real^1->real^M` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o
+    SPECL [`(p:real^M->real^N) o linepath(x:real^M,x)`;
+           `(p:real^M->real^N) o (g:real^1->real^M)`;
+           `h1:real^1->real^M`; `h2:real^1->real^M`] o
+  MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        COVERING_SPACE_MONODROMY)) THEN
+  ASM_SIMP_TAC[] THEN ANTS_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o CONJUNCT2 o
+        GEN_REWRITE_RULE I [SIMPLY_CONNECTED_EQ_HOMOTOPIC_PATHS]) THEN
+    ASM_REWRITE_TAC[PATHSTART_COMPOSE; PATHFINISH_COMPOSE] THEN
+    ASM_REWRITE_TAC[PATHSTART_LINEPATH; PATHFINISH_LINEPATH];
+    ALL_TAC] THEN
+  MATCH_MP_TAC EQ_IMP THEN BINOP_TAC THENL
+   [MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `pathfinish(linepath(x:real^M,x))` THEN
+    CONJ_TAC THENL [ALL_TAC; REWRITE_TAC[PATHFINISH_LINEPATH]];
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [SYM th])] THEN
+  REWRITE_TAC[pathfinish] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        COVERING_SPACE_LIFT_UNIQUE))
+  THENL
+   [EXISTS_TAC `(p:real^M->real^N) o (h1:real^1->real^M)`;
+    EXISTS_TAC `(p:real^M->real^N) o (h2:real^1->real^M)`] THEN
+  MAP_EVERY EXISTS_TAC [`interval[vec 0:real^1,vec 1]`; `vec 0:real^1`] THEN
+  REWRITE_TAC[CONNECTED_INTERVAL; ENDS_IN_UNIT_INTERVAL] THEN
+  ASM_REWRITE_TAC[GSYM path; PATH_LINEPATH; GSYM path_image] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[o_THM]) THEN ASM_REWRITE_TAC[o_THM] THEN
+  ASM_REWRITE_TAC[PATH_IMAGE_LINEPATH; SEGMENT_REFL; SING_SUBSET] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pathstart]) THEN
+  ASM_REWRITE_TAC[LINEPATH_REFL; PATH_IMAGE_COMPOSE] THEN
+  (CONJ_TAC THENL
+    [ASM_MESON_TAC[PATH_CONTINUOUS_IMAGE; CONTINUOUS_ON_SUBSET];
+     ASM SET_TAC[]]));;
+
+let COVERING_SPACE_HOMEOMORPHISM = prove
+ (`!p:real^M->real^N c s.
+        covering_space (c,p) s /\ path_connected c /\ simply_connected s
+        ==> ?q. homeomorphism (c,s) (p,q)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMEOMORPHISM_INJECTIVE_OPEN_MAP THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[COVERING_SPACE_IMP_CONTINUOUS];
+    ASM_MESON_TAC[COVERING_SPACE_IMP_SURJECTIVE];
+    ASM_MESON_TAC[COVERING_SPACE_INJECTIVE];
+    ASM_MESON_TAC[COVERING_SPACE_OPEN_MAP]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Results on finiteness of the number of sheets in a covering space.        *)
+(* ------------------------------------------------------------------------- *)
+
+let COVERING_SPACE_FIBRE_NO_LIMPT = prove
+ (`!p:real^M->real^N c s a b.
+        covering_space (c,p) s /\ a IN c
+        ==> ~(a limit_point_of {x | x IN c /\ p x = b})`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [covering_space]) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(p:real^M->real^N) a`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` MP_TAC) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `vv:(real^M->bool)->bool` MP_TAC) THEN
+  GEN_REWRITE_TAC I [IMP_CONJ] THEN
+  REWRITE_TAC[EXTENSION; IN_UNIONS; IN_ELIM_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `a:real^M`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^M->bool` STRIP_ASSUME_TAC) THEN
+  STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `t:real^M->bool`)) THEN
+  ASM_REWRITE_TAC[] THEN REPEAT DISCH_TAC THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `q:real^N->real^M` MP_TAC) THEN
+  REWRITE_TAC[homeomorphism] THEN STRIP_TAC THEN
+  UNDISCH_TAC `open_in (subtopology euclidean c) (t:real^M->bool)` THEN
+  REWRITE_TAC[OPEN_IN_OPEN] THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:real^M->bool` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `v:real^M->bool` o
+        GEN_REWRITE_RULE I [LIMPT_INFINITE_OPEN]) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[INFINITE]] THEN
+  MATCH_MP_TAC(MESON[FINITE_SING; FINITE_SUBSET]
+   `(?a. s SUBSET {a}) ==> FINITE s`) THEN
+  ASM SET_TAC[]);;
+
+let COVERING_SPACE_COUNTABLE_SHEETS = prove
+ (`!p:real^M->real^N c s b.
+        covering_space (c,p) s ==> COUNTABLE {x | x IN c /\ p x = b}`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[] (ONCE_REWRITE_RULE[GSYM CONTRAPOS_THM]
+        UNCOUNTABLE_CONTAINS_LIMIT_POINT)) THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[COVERING_SPACE_FIBRE_NO_LIMPT]);;
+
+let COVERING_SPACE_FINITE_EQ_COMPACT_FIBRE = prove
+ (`!p:real^M->real^N c s b.
+        covering_space (c,p) s
+        ==> (FINITE {x | x IN c /\ p x = b} <=>
+             compact {x | x IN c /\ p x = b})`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN SIMP_TAC[FINITE_IMP_COMPACT] THEN
+  DISCH_TAC THEN ASM_CASES_TAC `(b:real^N) IN s` THENL
+   [ONCE_REWRITE_TAC[TAUT `p <=> (~p ==> F)`] THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o
+     SPEC `{x | x IN c /\ (p:real^M->real^N) x = b}` o
+     GEN_REWRITE_RULE I [COMPACT_EQ_BOLZANO_WEIERSTRASS]) THEN
+    ASM_REWRITE_TAC[INFINITE; SUBSET_REFL; IN_ELIM_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `a:real^M` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`a:real^M`; `b:real^N`] o
+       MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        COVERING_SPACE_FIBRE_NO_LIMPT)) THEN
+    ASM_REWRITE_TAC[];
+    SUBGOAL_THEN `{x  | x IN c /\ (p:real^M->real^N) x = b} = {}`
+     (fun th -> REWRITE_TAC[th; FINITE_EMPTY]) THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+    ASM SET_TAC[]]);;
+
+let COVERING_SPACE_CLOSED_MAP = prove
+ (`!p:real^M->real^N c s t.
+        covering_space (c,p) s /\
+        (!b. b IN s ==> FINITE {x | x IN c /\ p x = b}) /\
+        closed_in (subtopology euclidean c) t
+        ==> closed_in (subtopology euclidean s) (IMAGE p t)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+  REWRITE_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN CONJ_TAC THENL
+   [ASM SET_TAC[]; ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN]] THEN
+  X_GEN_TAC `y:real^N` THEN REWRITE_TAC[IN_DIFF] THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `y:real^N` o last o CONJUNCTS o
+    GEN_REWRITE_RULE I [covering_space]) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `v:real^N->bool` THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `y:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `uu:(real^M->bool)->bool` STRIP_ASSUME_TAC) THEN
+  ASM_CASES_TAC `uu:(real^M->bool)->bool = {}` THENL
+   [ASM_REWRITE_TAC[UNIONS_0; NOT_IN_EMPTY] THEN ASM SET_TAC[]; ALL_TAC] THEN
+  EXISTS_TAC `INTERS {IMAGE (p:real^M->real^N) (u DIFF t) | u IN uu}` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC OPEN_IN_INTERS THEN
+    ASM_REWRITE_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE; IMAGE_EQ_EMPTY] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC FINITE_IMAGE THEN
+      SUBGOAL_THEN
+       `!u. u IN uu ==> ?x. x IN u /\ (p:real^M->real^N) x = y`
+      ASSUME_TAC THENL
+       [RULE_ASSUM_TAC(REWRITE_RULE[homeomorphism]) THEN ASM SET_TAC[];
+        ALL_TAC] THEN
+      SUBGOAL_THEN
+       `FINITE (IMAGE (\u. @x. x IN u /\ (p:real^M->real^N) x = y) uu)`
+      MP_TAC THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          FINITE_SUBSET)) THEN ASM SET_TAC[];
+        MATCH_MP_TAC EQ_IMP THEN MATCH_MP_TAC FINITE_IMAGE_INJ_EQ THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [pairwise]) THEN
+        REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN ASM SET_TAC[]];
+      X_GEN_TAC `u:real^M->bool` THEN DISCH_TAC THEN
+      MATCH_MP_TAC OPEN_IN_TRANS THEN EXISTS_TAC `v:real^N->bool` THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC HOMEOMORPHISM_IMP_OPEN_MAP THEN
+      ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN EXISTS_TAC `u:real^M->bool` THEN
+      ASM_SIMP_TAC[LEFT_EXISTS_AND_THM] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CLOSED_IN_CLOSED]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `k:real^M->bool` STRIP_ASSUME_TAC) THEN
+      ASM_REWRITE_TAC[OPEN_IN_OPEN] THEN
+      EXISTS_TAC `(:real^M) DIFF k` THEN
+      ASM_REWRITE_TAC[GSYM closed] THEN ASM SET_TAC[]];
+    REWRITE_TAC[IN_INTERS; FORALL_IN_GSPEC] THEN
+    X_GEN_TAC `u:real^M->bool` THEN DISCH_TAC THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `u:real^M->bool`)) THEN
+    ASM_REWRITE_TAC[homeomorphism] THEN ASM SET_TAC[];
+    REWRITE_TAC[SUBSET; INTERS_GSPEC; IN_DIFF; IN_ELIM_THM] THEN
+    X_GEN_TAC `z:real^N` THEN DISCH_TAC THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[IN_IMAGE]] THEN
+    DISCH_THEN(X_CHOOSE_THEN `w:real^M` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+    DISCH_THEN(MP_TAC o SPEC `w:real^M`) THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    MATCH_MP_TAC(TAUT `q /\ r /\ ~s ==> ~(s <=> q /\ r)`) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[homeomorphism]) THEN
+    REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+    REWRITE_TAC[IN_UNIONS] THEN ASM SET_TAC[]]);;
+
+let COVERING_SPACE_FINITE_SHEETS_EQ_CLOSED_MAP_STRONG = prove
+ (`!p:real^M->real^N c s.
+        covering_space (c,p) s /\ (!b. b IN s ==> b limit_point_of s)
+        ==> ((!b. b IN s ==> FINITE {x | x IN c /\ p x = b}) <=>
+             (!t. closed_in (subtopology euclidean c) t
+                  ==> closed_in (subtopology euclidean s) (IMAGE p t)))`,
+  let lemma = prove
+   (`!f:num->real^N.
+          (!n. ~(s = v n) ==> DISJOINT s (v n))
+          ==> (!n. f n IN v n) /\
+              (!m n. v m = v n <=> m = n)
+              ==> ?n. IMAGE f (:num) INTER s SUBSET {f n}`,
+    ASM_CASES_TAC `?n. s = (v:num->real^N->bool) n` THENL
+     [REPEAT STRIP_TAC THEN FIRST_X_ASSUM(fun th ->
+        MP_TAC th THEN MATCH_MP_TAC MONO_EXISTS);
+      RULE_ASSUM_TAC(REWRITE_RULE[NOT_EXISTS_THM]) THEN
+      ASM_REWRITE_TAC[]] THEN
+    ASM SET_TAC[]) in
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC COVERING_SPACE_CLOSED_MAP THEN
+    EXISTS_TAC `c:real^M->bool` THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[MESON[INFINITE] `FINITE s <=> ~INFINITE s`] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `b:real^N` o last o CONJUNCTS o
+    GEN_REWRITE_RULE I [covering_space]) THEN
+  ASM_REWRITE_TAC[NOT_EXISTS_THM] THEN X_GEN_TAC `t:real^N->bool` THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `vv:(real^M->bool)->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `(b:real^N) limit_point_of t` MP_TAC THENL
+   [MATCH_MP_TAC LIMPT_OF_OPEN_IN THEN ASM_MESON_TAC[];
+    PURE_REWRITE_TAC[LIMPT_SEQUENTIAL_INJ]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `y:num->real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `INFINITE(vv:(real^M->bool)->bool)` MP_TAC THENL
+   [FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CARD_LE_INFINITE)) THEN REWRITE_TAC[le_c] THEN
+    SUBGOAL_THEN
+      `!x. ?v. x IN c /\ (p:real^M->real^N) x = b ==> v IN vv /\ x IN v`
+    MP_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[SKOLEM_THM]] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^M->real^M->bool` THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN CONJ_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `y:real^M`] THEN STRIP_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
+    RULE_ASSUM_TAC(REWRITE_RULE[homeomorphism]) THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[INFINITE_CARD_LE; le_c; INJECTIVE_ON_ALT] THEN
+  REWRITE_TAC[IN_UNIV] THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:num->real^M->bool` STRIP_ASSUME_TAC) THEN
+  UNDISCH_THEN
+    `!u. u IN vv ==> ?q:real^N->real^M. homeomorphism (u,t) (p,q)`
+    (MP_TAC o GEN `n:num` o SPEC `(v:num->real^M->bool) n`) THEN
+  ASM_REWRITE_TAC[SKOLEM_THM; homeomorphism; FORALL_AND_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `q:num->real^N->real^M` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `closed_in (subtopology euclidean s)
+              (IMAGE (p:real^M->real^N) (IMAGE (\n. q n (y n:real^N)) (:num)))`
+  MP_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[CLOSED_IN_LIMPT; SUBSET; FORALL_IN_IMAGE] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; X_GEN_TAC `a:real^M`] THEN STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP LIMPT_OF_SEQUENCE_SUBSEQUENCE) THEN
+    DISCH_THEN(X_CHOOSE_THEN `r:num->num` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `(p:real^M->real^N) a = b` ASSUME_TAC THENL
+     [MATCH_MP_TAC(ISPEC `sequentially` LIM_UNIQUE) THEN
+      EXISTS_TAC
+       `(p:real^M->real^N) o (\n:num. q n (y n :real^N)) o (r:num->num)` THEN
+      REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC(GEN_ALL(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+        (fst(EQ_IMP_RULE(SPEC_ALL CONTINUOUS_ON_SEQUENTIALLY))))) THEN
+        EXISTS_TAC `c:real^M->bool` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+         [ASM_MESON_TAC[COVERING_SPACE_IMP_CONTINUOUS];
+          REWRITE_TAC[o_DEF] THEN ASM SET_TAC[]];
+        REWRITE_TAC[o_ASSOC] THEN MATCH_MP_TAC LIM_SUBSEQUENCE THEN
+        ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+         (REWRITE_RULE[IMP_CONJ_ALT] LIM_TRANSFORM_EVENTUALLY)) THEN
+        MATCH_MP_TAC ALWAYS_EVENTUALLY THEN REWRITE_TAC[o_DEF] THEN
+        ASM SET_TAC[]];
+      SUBGOAL_THEN `?u. u IN vv /\ (a:real^M) IN u` STRIP_ASSUME_TAC THENL
+       [ASM SET_TAC[]; ALL_TAC] THEN
+      SUBGOAL_THEN `?w:real^M->bool. open w /\ u = c INTER w`
+       (CHOOSE_THEN (CONJUNCTS_THEN2 ASSUME_TAC SUBST_ALL_TAC))
+      THENL [ASM_MESON_TAC[OPEN_IN_OPEN]; ALL_TAC] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_INTER]) THEN
+      FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIMPT_INFINITE_OPEN]) THEN
+      DISCH_THEN(MP_TAC o SPEC `w:real^M->bool`) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o MATCH_MP (MESON[]
+       `INFINITE s ==> !k. s INTER k = s ==> INFINITE(s INTER k)`)) THEN
+      DISCH_THEN(MP_TAC o SPEC `c:real^M->bool`) THEN ANTS_TAC THENL
+       [ASM SET_TAC[]; REWRITE_TAC[INTER_ASSOC]] THEN
+      ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+      REWRITE_TAC[INFINITE] THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [pairwise]) THEN
+      DISCH_THEN(MP_TAC o SPEC `c INTER w:real^M->bool`) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(MP_TAC o GEN `n:num` o SPEC `(v:num->real^M->bool) n`) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(MP_TAC o SPEC `\n. (q:num->real^N->real^M) n (y n)` o
+        MATCH_MP lemma) THEN
+      ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      MESON_TAC[FINITE_SUBSET; FINITE_SING; INTER_COMM]];
+    SUBGOAL_THEN
+     `IMAGE (p:real^M->real^N) (IMAGE (\n. q n (y n:real^N)) (:num)) =
+      IMAGE y (:num)`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[GSYM IMAGE_o; o_DEF] THEN ASM SET_TAC[]; ALL_TAC] THEN
+    REWRITE_TAC[CLOSED_IN_LIMPT] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `b:real^N`)) THEN
+    ASM_REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    REWRITE_TAC[LIMPT_SEQUENTIAL_INJ] THEN
+    EXISTS_TAC `y:num->real^N` THEN ASM SET_TAC[]]);;
+
+let COVERING_SPACE_FINITE_SHEETS_EQ_CLOSED_MAP = prove
+ (`!p:real^M->real^N c s.
+        covering_space (c,p) s /\ connected s /\ ~(?a. s = {a})
+        ==> ((!b. b IN s ==> FINITE {x | x IN c /\ p x = b}) <=>
+             (!t. closed_in (subtopology euclidean c) t
+                  ==> closed_in (subtopology euclidean s) (IMAGE p t)))`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [SUBGOAL_THEN `c:real^M->bool = {}` ASSUME_TAC THENL
+     [FIRST_ASSUM(MP_TAC o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+      ASM_REWRITE_TAC[IMAGE_EQ_EMPTY];
+      ASM_REWRITE_TAC[OPEN_IN_SUBTOPOLOGY_EMPTY; CLOSED_IN_SUBTOPOLOGY_EMPTY;
+                      IMAGE_EQ_EMPTY; NOT_IN_EMPTY]];
+    MATCH_MP_TAC COVERING_SPACE_FINITE_SHEETS_EQ_CLOSED_MAP_STRONG THEN
+    ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC CONNECTED_IMP_PERFECT THEN ASM SET_TAC[]]);;
+
+let COVERING_SPACE_FINITE_SHEETS_EQ_PROPER_MAP = prove
+ (`!p:real^M->real^N c s.
+        covering_space (c,p) s
+        ==> ((!b. b IN s ==> FINITE {x | x IN c /\ p x = b}) <=>
+             (!k. k SUBSET s /\ compact k
+                  ==> compact {x | x IN c /\ p(x) IN k}))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE `s = t ==> s SUBSET t`)) THEN
+  DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP PROPER_MAP th]) THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC
+   [GSYM(MATCH_MP COVERING_SPACE_FINITE_EQ_COMPACT_FIBRE th)]) THEN
+  REWRITE_TAC[TAUT `(p <=> q /\ p) <=> (p ==> q)`] THEN
+  ASM_MESON_TAC[COVERING_SPACE_CLOSED_MAP]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Special cases where one or both of the sets is compact.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let COVERING_SPACE_FINITE_SHEETS = prove
+ (`!p:real^M->real^N c s b.
+      covering_space (c,p) s /\ compact c ==> FINITE {x | x IN c /\ p x = b}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC BOLZANO_WEIERSTRASS_CONTRAPOS THEN
+  EXISTS_TAC `c:real^M->bool` THEN ASM_REWRITE_TAC[SUBSET_RESTRICT] THEN
+  ASM_MESON_TAC[COVERING_SPACE_FIBRE_NO_LIMPT]);;
+
+let COVERING_SPACE_COMPACT = prove
+ (`!p:real^M->real^N c s.
+        covering_space (c,p) s
+        ==> (compact c <=>
+             compact s /\ (!b. b IN s ==> FINITE {x | x IN c /\ p x = b}))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [ASM_MESON_TAC[covering_space; COMPACT_CONTINUOUS_IMAGE];
+    MATCH_MP_TAC COVERING_SPACE_FINITE_SHEETS THEN ASM_MESON_TAC[];
+    FIRST_ASSUM(MP_TAC o
+      MATCH_MP COVERING_SPACE_FINITE_SHEETS_EQ_PROPER_MAP) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `s:real^N->bool`) THEN
+    ASM_REWRITE_TAC[SUBSET_REFL] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP COVERING_SPACE_IMP_SURJECTIVE) THEN
+    SET_TAC[]]);;
diff --git a/Multivariate/polytope.ml b/Multivariate/polytope.ml
new file mode 100644 (file)
index 0000000..97c3d47
--- /dev/null
@@ -0,0 +1,5640 @@
+(* ========================================================================= *)
+(* Faces, extreme points, polytopes, polyhedra etc.                          *)
+(* ========================================================================= *)
+
+needs "Multivariate/paths.ml";;
+
+(* ------------------------------------------------------------------------- *)
+(* Faces of a (usually convex) set.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("face_of",(12,"right"));;
+
+let face_of = new_definition
+ `t face_of s <=>
+        t SUBSET s /\ convex t /\
+        !a b x. a IN s /\ b IN s /\ x IN t /\ x IN segment(a,b)
+                ==> a IN t /\ b IN t`;;
+
+let FACE_OF_TRANSLATION_EQ = prove
+ (`!a f s:real^N->bool.
+        (IMAGE (\x. a + x) f) face_of (IMAGE (\x. a + x) s) <=> f face_of s`,
+  REWRITE_TAC[face_of] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [FACE_OF_TRANSLATION_EQ];;
+
+let FACE_OF_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N c s.
+      linear f /\ (!x y. f x = f y ==> x = y)
+      ==> ((IMAGE f c) face_of (IMAGE f s) <=> c face_of s)`,
+  REWRITE_TAC[face_of; IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REPEAT STRIP_TAC THEN MP_TAC(end_itlist CONJ
+   (mapfilter (ISPEC `f:real^M->real^N`) (!invariant_under_linear))) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN ASM_REWRITE_TAC[]);;
+
+add_linear_invariants [FACE_OF_LINEAR_IMAGE];;
+
+let FACE_OF_REFL = prove
+ (`!s. convex s ==> s face_of s`,
+  SIMP_TAC[face_of] THEN SET_TAC[]);;
+
+let FACE_OF_REFL_EQ = prove
+ (`!s. s face_of s <=> convex s`,
+  SIMP_TAC[face_of] THEN SET_TAC[]);;
+
+let EMPTY_FACE_OF = prove
+ (`!s. {} face_of s`,
+  REWRITE_TAC[face_of; CONVEX_EMPTY] THEN SET_TAC[]);;
+
+let FACE_OF_EMPTY = prove
+ (`!s. s face_of {} <=> s = {}`,
+  REWRITE_TAC[face_of; SUBSET_EMPTY; NOT_IN_EMPTY] THEN
+  MESON_TAC[CONVEX_EMPTY]);;
+
+let FACE_OF_TRANS = prove
+ (`!s t u. s face_of t /\ t face_of u
+           ==> s face_of u`,
+  REWRITE_TAC[face_of] THEN SET_TAC[]);;
+
+let FACE_OF_FACE = prove
+ (`!f s t.
+        t face_of s
+        ==> (f face_of t <=> f face_of s /\ f SUBSET t)`,
+  REWRITE_TAC[face_of] THEN SET_TAC[]);;
+
+let FACE_OF_SUBSET = prove
+ (`!f s t. f face_of s /\ f SUBSET t /\ t SUBSET s ==> f face_of t`,
+  REWRITE_TAC[face_of] THEN SET_TAC[]);;
+
+let FACE_OF_SLICE = prove
+ (`!f s t.
+        f face_of s /\ convex t
+        ==> (f INTER t) face_of (s INTER t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[face_of; IN_INTER] THEN STRIP_TAC THEN
+  REPEAT CONJ_TAC THENL
+   [ASM SET_TAC[];
+    ASM_MESON_TAC[CONVEX_INTER];
+    ASM_MESON_TAC[]]);;
+
+let FACE_OF_INTER = prove
+ (`!s t1 t2. t1 face_of s /\ t2 face_of s
+             ==> (t1 INTER t2) face_of s`,
+  SIMP_TAC[face_of; CONVEX_INTER] THEN SET_TAC[]);;
+
+let FACE_OF_INTERS = prove
+ (`!P s. ~(P = {}) /\ (!t. t IN P ==> t face_of s)
+         ==> (INTERS P) face_of s`,
+  REWRITE_TAC[face_of] THEN REPEAT STRIP_TAC THENL
+   [ASM SET_TAC[]; ASM_SIMP_TAC[CONVEX_INTERS]; ASM SET_TAC[]; ASM SET_TAC[]]);;
+
+let FACE_OF_INTER_INTER = prove
+ (`!f t f' t'.
+     f face_of t /\ f' face_of t' ==> (f INTER f') face_of (t INTER t')`,
+  REWRITE_TAC[face_of; SUBSET; IN_INTER] THEN MESON_TAC[CONVEX_INTER]);;
+
+let FACE_OF_STILLCONVEX = prove
+ (`!s t:real^N->bool.
+        convex s
+        ==> (t face_of s <=>
+             t SUBSET s /\
+             convex(s DIFF t) /\
+             t = (affine hull t) INTER s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[face_of] THEN
+  ASM_CASES_TAC `(t:real^N->bool) SUBSET s` THEN ASM_REWRITE_TAC[] THEN
+  EQ_TAC THEN STRIP_TAC THENL
+   [CONJ_TAC THENL
+     [REPEAT(POP_ASSUM MP_TAC) THEN
+      REWRITE_TAC[CONVEX_CONTAINS_SEGMENT; open_segment; IN_DIFF] THEN
+      REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; SUBSET_DIFF] THEN SET_TAC[];
+      ALL_TAC] THEN
+    REWRITE_TAC[EXTENSION] THEN X_GEN_TAC `x:real^N` THEN EQ_TAC THENL
+     [ASM MESON_TAC[HULL_INC; SUBSET; IN_INTER]; ALL_TAC] THEN
+    ASM_CASES_TAC `t:real^N -> bool = {}` THEN
+    ASM_REWRITE_TAC[IN_INTER; AFFINE_HULL_EMPTY; NOT_IN_EMPTY] THEN
+    MP_TAC(ISPEC `t:real^N->bool` RELATIVE_INTERIOR_EQ_EMPTY) THEN
+    ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `y:real^N` THEN REWRITE_TAC[IN_RELATIVE_INTERIOR_CBALL] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    STRIP_TAC THEN ASM_CASES_TAC `x:real^N = y` THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `y:real^N`]) THEN
+    REWRITE_TAC[] THEN ONCE_REWRITE_TAC[SEGMENT_SYM] THEN
+    ASM_SIMP_TAC[LEFT_FORALL_IMP_THM; OPEN_SEGMENT_ALT] THEN
+    ANTS_TAC THENL [ALL_TAC; SIMP_TAC[]] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET]) THEN ASM_SIMP_TAC[] THEN
+    ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+    REWRITE_TAC[EXISTS_IN_GSPEC] THEN
+    EXISTS_TAC `min (&1 / &2) (e / norm(x - y:real^N))` THEN
+    REWRITE_TAC[REAL_LT_MIN; REAL_MIN_LT] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INTER; IN_CBALL; dist] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[NORM_MUL; VECTOR_ARITH
+       `y - ((&1 - u) % y + u % x):real^N = u % (y - x)`] THEN
+      ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+      REWRITE_TAC[NORM_SUB] THEN
+      MATCH_MP_TAC(REAL_ARITH `&0 < e ==> abs(min (&1 / &2) e) <= e`) THEN
+      ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; VECTOR_SUB_EQ];
+      MATCH_MP_TAC(REWRITE_RULE[AFFINE_ALT] AFFINE_AFFINE_HULL) THEN
+      ASM_SIMP_TAC[HULL_INC]];
+    CONJ_TAC THENL
+     [ONCE_ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONVEX_INTER THEN
+      ASM_SIMP_TAC[AFFINE_IMP_CONVEX; AFFINE_AFFINE_HULL];
+      ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`; `x:real^N`] THEN
+    SUBGOAL_THEN
+     `!a b x:real^N. a IN s /\ b IN s /\ x IN t /\ x IN segment(a,b) /\
+                     (a IN affine hull t ==> b IN affine hull t)
+                     ==> a IN t /\ b IN t`
+     (fun th -> MESON_TAC[th; SEGMENT_SYM]) THEN
+    REPEAT GEN_TAC THEN ASM_CASES_TAC `(a:real^N) IN affine hull t` THEN
+    ASM_REWRITE_TAC[] THENL [ASM SET_TAC[]; STRIP_TAC] THEN
+    ASM_CASES_TAC `a:real^N = b` THENL
+     [ASM_MESON_TAC[SEGMENT_REFL; NOT_IN_EMPTY]; ALL_TAC] THEN
+    SUBGOAL_THEN `(a:real^N) IN (s DIFF t) /\ b IN  (s DIFF t)`
+    STRIP_ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[IN_DIFF] THEN ONCE_ASM_REWRITE_TAC[] THEN
+      ASM_REWRITE_TAC[IN_INTER] THEN
+      UNDISCH_TAC `~((a:real^N) IN affine hull t)` THEN
+      UNDISCH_TAC `(x:real^N) IN segment(a,b)` THEN
+      ASM_SIMP_TAC[OPEN_SEGMENT_ALT; CONTRAPOS_THM; IN_ELIM_THM] THEN
+      DISCH_THEN(X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC) THEN
+      FIRST_X_ASSUM(MP_TAC o AP_TERM `(%) (inv(&1 - u)) :real^N->real^N`) THEN
+      REWRITE_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC] THEN
+      ASM_SIMP_TAC[REAL_MUL_LINV; REAL_ARITH `x < &1 ==> ~(&1 - x = &0)`] THEN
+      REWRITE_TAC[VECTOR_ARITH
+       `x:real^N = &1 % a + u % b <=> a = x + --u %  b`] THEN
+      DISCH_THEN SUBST1_TAC THEN DISCH_TAC THEN
+      MATCH_MP_TAC(REWRITE_RULE[affine] AFFINE_AFFINE_HULL) THEN
+      ASM_SIMP_TAC[HULL_INC] THEN
+      UNDISCH_TAC `u < &1` THEN CONV_TAC REAL_FIELD;
+      MP_TAC(ISPEC `s DIFF t:real^N->bool` CONVEX_CONTAINS_SEGMENT) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(MP_TAC o SPECL [`a:real^N`; `b:real^N`]) THEN
+      ASM_REWRITE_TAC[SUBSET; IN_DIFF] THEN
+      DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+      ASM_MESON_TAC[segment; IN_DIFF]]]);;
+
+let FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE_STRONG = prove
+ (`!s a:real^N b.
+        convex(s INTER {x | a dot x = b}) /\ (!x. x IN s ==> a dot x <= b)
+        ==> (s INTER {x | a dot x = b}) face_of s`,
+  MAP_EVERY X_GEN_TAC [`s:real^N->bool`; `c:real^N`; `d:real`] THEN
+  SIMP_TAC[face_of; INTER_SUBSET] THEN
+  STRIP_TAC THEN REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`; `x:real^N`] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `a <= x /\ b <= x /\ ~(a < x) /\ ~(b < x) ==> a = x /\ b = x`) THEN
+  ASM_SIMP_TAC[] THEN UNDISCH_TAC `(x:real^N) IN segment(a,b)` THEN
+  ASM_CASES_TAC `a:real^N = b` THEN
+  ASM_REWRITE_TAC[SEGMENT_REFL; NOT_IN_EMPTY] THEN
+  ASM_SIMP_TAC[OPEN_SEGMENT_ALT; IN_ELIM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC) THEN
+  CONJ_TAC THEN DISCH_TAC THEN UNDISCH_TAC `(c:real^N) dot x = d` THEN
+  MATCH_MP_TAC(REAL_ARITH `x < a ==> x = a ==> F`) THEN
+  SUBST1_TAC(REAL_ARITH `d = (&1 - u) * d + u * d`) THEN
+  ASM_REWRITE_TAC[DOT_RADD; DOT_RMUL] THENL
+   [MATCH_MP_TAC REAL_LTE_ADD2; MATCH_MP_TAC REAL_LET_ADD2] THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_LT_LMUL_EQ; REAL_SUB_LT]);;
+
+let FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE_STRONG = prove
+ (`!s a:real^N b.
+        convex(s INTER {x | a dot x = b}) /\ (!x. x IN s ==> a dot x >= b)
+        ==> (s INTER {x | a dot x = b}) face_of s`,
+  REWRITE_TAC[real_ge] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `--a:real^N`; `--b:real`]
+    FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE_STRONG) THEN
+  ASM_REWRITE_TAC[DOT_LNEG; REAL_EQ_NEG2; REAL_LE_NEG2]);;
+
+let FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE = prove
+ (`!s a:real^N b.
+        convex s /\ (!x. x IN s ==> a dot x <= b)
+        ==> (s INTER {x | a dot x = b}) face_of s`,
+  SIMP_TAC[FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE_STRONG;
+           CONVEX_INTER; CONVEX_HYPERPLANE]);;
+
+let FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE = prove
+ (`!s a:real^N b.
+        convex s /\ (!x. x IN s ==> a dot x >= b)
+        ==> (s INTER {x | a dot x = b}) face_of s`,
+  SIMP_TAC[FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE_STRONG;
+           CONVEX_INTER; CONVEX_HYPERPLANE]);;
+
+let FACE_OF_IMP_SUBSET = prove
+ (`!s t. t face_of s ==> t SUBSET s`,
+  SIMP_TAC[face_of]);;
+
+let FACE_OF_IMP_CONVEX = prove
+ (`!s t. t face_of s ==> convex t`,
+  SIMP_TAC[face_of]);;
+
+let FACE_OF_IMP_CLOSED = prove
+ (`!s t. convex s /\ closed s /\ t face_of s ==> closed t`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ASM_SIMP_TAC[FACE_OF_STILLCONVEX] THEN
+  STRIP_TAC THEN ONCE_ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[CLOSED_AFFINE; AFFINE_AFFINE_HULL; CLOSED_INTER]);;
+
+let FACE_OF_IMP_COMPACT = prove
+ (`!s t. convex s /\ compact s /\ t face_of s ==> compact t`,
+  SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN
+  ASM_MESON_TAC[BOUNDED_SUBSET; FACE_OF_IMP_SUBSET; FACE_OF_IMP_CLOSED]);;
+
+let FACE_OF_INTER_SUBFACE = prove
+ (`!c1 c2 d1 d2:real^N->bool.
+        (c1 INTER c2) face_of c1 /\ (c1 INTER c2) face_of c2 /\
+        d1 face_of c1 /\ d2 face_of c2
+        ==> (d1 INTER d2) face_of d1 /\ (d1 INTER d2) face_of d2`,
+ REPEAT STRIP_TAC THEN MATCH_MP_TAC FACE_OF_SUBSET THENL
+   [EXISTS_TAC `c1:real^N->bool`; EXISTS_TAC `c2:real^N->bool`] THEN
+  ASM_SIMP_TAC[FACE_OF_IMP_SUBSET; INTER_SUBSET] THEN
+  TRANS_TAC FACE_OF_TRANS `c1 INTER c2:real^N->bool` THEN
+  ASM_SIMP_TAC[FACE_OF_INTER_INTER]);;
+
+let SUBSET_OF_FACE_OF = prove
+ (`!s t u:real^N->bool.
+      t face_of s /\ u SUBSET s /\
+      ~(DISJOINT t (relative_interior u))
+      ==> u SUBSET t`,
+  REWRITE_TAC[DISJOINT] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[SUBSET] THEN X_GEN_TAC `c:real^N` THEN DISCH_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 `b:real^N` THEN
+  REWRITE_TAC[IN_RELATIVE_INTERIOR_CBALL] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[SUBSET; IN_CBALL; IN_INTER] THEN
+  ASM_CASES_TAC `c:real^N = b` THEN ASM_REWRITE_TAC[] THEN
+  ABBREV_TAC `d:real^N = b + e / norm(b - c) % (b - c)` THEN
+  DISCH_THEN(MP_TAC o SPEC `d:real^N`) THEN ANTS_TAC THENL
+   [EXPAND_TAC "d" THEN CONJ_TAC THENL
+     [REWRITE_TAC[NORM_ARITH `dist(b:real^N,b + e) = norm e`] THEN
+      REWRITE_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM] THEN
+      ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+      ASM_REAL_ARITH_TAC;
+      REWRITE_TAC[VECTOR_ARITH
+       `b + u % (b - c):real^N = (&1 - --u) % b + --u % c`] THEN
+      MATCH_MP_TAC(REWRITE_RULE[AFFINE_ALT] AFFINE_AFFINE_HULL) THEN
+      ASM_SIMP_TAC[HULL_INC]];
+    STRIP_TAC THEN
+    SUBGOAL_THEN `(d:real^N) IN t /\ c IN t` (fun th -> MESON_TAC[th]) THEN
+    FIRST_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [face_of]) THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN EXISTS_TAC `b:real^N` THEN
+    REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+    SUBGOAL_THEN `~(b:real^N = d)` ASSUME_TAC THENL
+     [EXPAND_TAC "d" THEN
+      REWRITE_TAC[VECTOR_ARITH `b:real^N = b + e <=> e = vec 0`] THEN
+      ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; VECTOR_SUB_EQ;
+                   VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ];
+      ASM_REWRITE_TAC[segment; IN_DIFF; IN_INSERT; NOT_IN_EMPTY] THEN
+      REWRITE_TAC[IN_ELIM_THM] THEN
+      EXISTS_TAC `(e / norm(b - c:real^N)) / (&1 + e / norm(b - c))` THEN
+      ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; VECTOR_SUB_EQ;
+                   REAL_ARITH `&0 < x ==> &0 < &1 + x`;
+                   REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; REAL_MUL_LID] THEN
+      REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID] THEN
+      ASM_SIMP_TAC[REAL_FIELD `&0 < n ==> (&1 + e / n) * n = n + e`;
+                   NORM_POS_LT; VECTOR_SUB_EQ; REAL_LE_ADDL] THEN
+      ASM_SIMP_TAC[NORM_POS_LT; REAL_LT_IMP_LE; VECTOR_SUB_EQ] THEN
+      EXPAND_TAC "d" THEN REWRITE_TAC[VECTOR_ARITH
+       `b:real^N = (&1 - u) % (b + e % (b - c)) + u % c <=>
+        (u - e * (&1 - u)) % (b - c) = vec 0`] THEN
+      ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ] THEN
+      MATCH_MP_TAC(REAL_FIELD
+       `&0 < e ==> e / (&1 + e) - e * (&1 - e / (&1 + e)) = &0`) THEN
+      ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; VECTOR_SUB_EQ]]]);;
+
+let FACE_OF_EQ = prove
+ (`!s t u:real^N->bool.
+        t face_of s /\ u face_of s /\
+        ~(DISJOINT (relative_interior t) (relative_interior u))
+        ==> t = u`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  CONJ_TAC THEN MATCH_MP_TAC SUBSET_OF_FACE_OF THEN
+  EXISTS_TAC `s:real^N->bool` THEN ASM_SIMP_TAC[FACE_OF_IMP_SUBSET] THENL
+   [MP_TAC(ISPEC `u:real^N->bool` RELATIVE_INTERIOR_SUBSET);
+    MP_TAC(ISPEC `t:real^N->bool` RELATIVE_INTERIOR_SUBSET)] THEN
+  ASM SET_TAC[]);;
+
+let FACE_OF_DISJOINT_RELATIVE_INTERIOR = prove
+ (`!f s:real^N->bool.
+        f face_of s /\ ~(f = s) ==> f INTER relative_interior s = {}`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `f:real^N->bool`; `s:real^N->bool`]
+        SUBSET_OF_FACE_OF) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP FACE_OF_IMP_SUBSET) THEN
+  ASM SET_TAC[]);;
+
+let FACE_OF_DISJOINT_INTERIOR = prove
+ (`!f s:real^N->bool.
+        f face_of s /\ ~(f = s) ==> f INTER interior s = {}`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP FACE_OF_DISJOINT_RELATIVE_INTERIOR) THEN
+  MP_TAC(ISPEC `s:real^N->bool` INTERIOR_SUBSET_RELATIVE_INTERIOR) THEN
+  SET_TAC[]);;
+
+let AFFINE_HULL_FACE_OF_DISJOINT_RELATIVE_INTERIOR = prove
+ (`!s f:real^N->bool.
+        convex s /\ f face_of s /\ ~(f = s)
+        ==> affine hull f INTER relative_interior s = {}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(SET_RULE
+   `!s f. a INTER s = f /\ r SUBSET s /\ f INTER r = {}
+          ==> a INTER r = {}`) THEN
+  MAP_EVERY EXISTS_TAC [`s:real^N->bool`; `f:real^N->bool`] THEN
+  ASM_SIMP_TAC[FACE_OF_DISJOINT_RELATIVE_INTERIOR;
+               RELATIVE_INTERIOR_SUBSET] THEN
+  UNDISCH_TAC `(f:real^N->bool) face_of s` THEN
+  ASM_SIMP_TAC[FACE_OF_STILLCONVEX] THEN MESON_TAC[]);;
+
+let FACE_OF_SUBSET_RELATIVE_BOUNDARY = prove
+ (`!s f:real^N->bool.
+        f face_of s /\ ~(f = s) ==> f SUBSET (s DIFF relative_interior s)`,
+  ASM_SIMP_TAC[SET_RULE `s SUBSET u DIFF t <=> s SUBSET u /\ s INTER t = {}`;
+               FACE_OF_DISJOINT_RELATIVE_INTERIOR; FACE_OF_IMP_SUBSET]);;
+
+let FACE_OF_SUBSET_RELATIVE_FRONTIER = prove
+ (`!s f:real^N->bool.
+        f face_of s /\ ~(f = s) ==> f SUBSET relative_frontier s`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP FACE_OF_SUBSET_RELATIVE_BOUNDARY) THEN
+  REWRITE_TAC[relative_frontier] THEN
+  MP_TAC(ISPEC `s:real^N->bool` CLOSURE_SUBSET) THEN SET_TAC[]);;
+
+let FACE_OF_AFF_DIM_LT = prove
+ (`!f s:real^N->bool.
+        convex s /\ f face_of s /\ ~(f = s) ==> aff_dim f < aff_dim s`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[INT_LT_LE; FACE_OF_IMP_SUBSET; AFF_DIM_SUBSET] THEN
+  REWRITE_TAC[IMP_CONJ; CONTRAPOS_THM] THEN
+  ASM_CASES_TAC `f:real^N->bool = {}` THENL
+   [CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN
+    ASM_REWRITE_TAC[AFF_DIM_EQ_MINUS1; AFF_DIM_EMPTY];
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC FACE_OF_EQ THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_SIMP_TAC[FACE_OF_REFL] THEN
+    MATCH_MP_TAC(SET_RULE `~(f = {}) /\ f SUBSET s ==> ~DISJOINT f s`) THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP FACE_OF_IMP_CONVEX) THEN
+    ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY] THEN
+    MATCH_MP_TAC SUBSET_RELATIVE_INTERIOR THEN
+    ASM_MESON_TAC[FACE_OF_IMP_SUBSET; AFF_DIM_EQ_AFFINE_HULL; INT_LE_REFL]]);;
+
+let FACE_OF_CONVEX_HULLS = prove
+ (`!f s:real^N->bool.
+        FINITE s /\ f SUBSET s /\
+        DISJOINT (affine hull f) (convex hull (s DIFF f))
+        ==> (convex hull f) face_of (convex hull s)`,
+  let lemma = prove
+   (`!s x y:real^N.
+          affine s /\ ~(k = &0) /\ ~(k = &1) /\ x IN s /\ inv(&1 - k) % y IN s
+          ==> inv(k) % (x - y) IN s`,
+    REWRITE_TAC[AFFINE_ALT] THEN REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+     `inv(k) % (x - y):real^N = (&1 - inv k) % inv(&1 - k) % y + inv(k) % x`
+     (fun th -> ASM_SIMP_TAC[th]) THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_ARITH
+     `k % (x - y):real^N = a % b % y + k % x <=> (a * b + k) % y = vec 0`] THEN
+    DISJ1_TAC THEN MAP_EVERY UNDISCH_TAC [`~(k = &0)`; `~(k = &1)`] THEN
+    CONV_TAC REAL_FIELD) in
+  REPEAT STRIP_TAC THEN REWRITE_TAC[face_of] THEN
+  SUBGOAL_THEN `FINITE(f:real^N->bool)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+  FIRST_ASSUM(ASSUME_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+  ASM_SIMP_TAC[HULL_MONO; CONVEX_CONVEX_HULL] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`; `w:real^N`] THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_SEGMENT]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
+   (X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC)) THEN
+  SUBGOAL_THEN `(w:real^N) IN affine hull f` ASSUME_TAC THENL
+   [ASM_MESON_TAC[CONVEX_HULL_SUBSET_AFFINE_HULL; SUBSET]; ALL_TAC] THEN
+  MAP_EVERY UNDISCH_TAC
+   [`(y:real^N) IN convex hull s`; `(x:real^N) IN convex hull s`] THEN
+  REWRITE_TAC[CONVEX_HULL_FINITE; IN_ELIM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N->real` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->real` STRIP_ASSUME_TAC) THEN
+  ABBREV_TAC `(c:real^N->real) = \x. (&1 - u) * a x + u * b x` THEN
+  SUBGOAL_THEN `!x:real^N. x IN s ==> &0 <= c x` ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN EXPAND_TAC "c" THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC REAL_LE_ADD THEN CONJ_TAC THEN MATCH_MP_TAC REAL_LE_MUL THEN
+    ASM_SIMP_TAC[] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_CASES_TAC `sum (s DIFF f:real^N->bool) c = &0` THENL
+   [SUBGOAL_THEN `!x:real^N. x IN (s DIFF f) ==> c x = &0` MP_TAC THENL
+     [MATCH_MP_TAC SUM_POS_EQ_0 THEN ASM_MESON_TAC[FINITE_DIFF; IN_DIFF];
+      ALL_TAC] THEN
+    EXPAND_TAC "c" THEN
+    ASM_SIMP_TAC[IN_DIFF; REAL_LE_MUL; REAL_LT_IMP_LE; REAL_SUB_LT;
+     REAL_ARITH `&0 <= x /\ &0 <= y ==> (x + y = &0 <=> x = &0 /\ y = &0)`;
+     REAL_ENTIRE; REAL_SUB_0; REAL_LT_IMP_NE] THEN
+    STRIP_TAC THEN CONJ_TAC THENL
+     [EXISTS_TAC `a:real^N->real`; EXISTS_TAC `b:real^N->real`] THEN
+    ASM_SIMP_TAC[] THEN CONJ_TAC THEN FIRST_X_ASSUM(fun th g ->
+      (GEN_REWRITE_TAC RAND_CONV [GSYM th] THEN CONV_TAC SYM_CONV THEN
+       (MATCH_MP_TAC SUM_SUPERSET ORELSE MATCH_MP_TAC VSUM_SUPERSET)) g) THEN
+    ASM_SIMP_TAC[VECTOR_MUL_LZERO];
+    ALL_TAC] THEN
+  ABBREV_TAC `k = sum (s DIFF f:real^N->bool) c` THEN
+  SUBGOAL_THEN `&0 < k` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[REAL_LT_LE] THEN EXPAND_TAC "k" THEN
+    MATCH_MP_TAC SUM_POS_LE THEN ASM_SIMP_TAC[FINITE_DIFF; IN_DIFF];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `k = &1` THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_DISJOINT]) THEN
+    MATCH_MP_TAC(TAUT `b ==> ~b ==> c`) THEN
+    EXISTS_TAC `w:real^N` THEN
+    ASM_REWRITE_TAC[CONVEX_HULL_FINITE; IN_ELIM_THM] THEN
+    EXISTS_TAC `c:real^N->real` THEN
+    ASM_SIMP_TAC[IN_DIFF; SUM_DIFF; VSUM_DIFF] THEN
+    SUBGOAL_THEN `vsum f (\x:real^N. c x % x) = vec 0` SUBST1_TAC THENL
+     [ALL_TAC;
+      EXPAND_TAC "c" THEN REWRITE_TAC[VECTOR_ADD_RDISTRIB] THEN
+      ASM_SIMP_TAC[VSUM_ADD; GSYM VECTOR_MUL_ASSOC; VSUM_LMUL] THEN
+      REWRITE_TAC[VECTOR_SUB_RZERO]] THEN
+    SUBGOAL_THEN `sum(s DIFF f) c = sum s c - sum f (c:real^N->real)`
+    MP_TAC THENL [ASM_MESON_TAC[SUM_DIFF]; ALL_TAC] THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `sum s (c:real^N->real) = &1` SUBST1_TAC THENL
+     [EXPAND_TAC "c" THEN REWRITE_TAC[VECTOR_ADD_RDISTRIB] THEN
+      ASM_SIMP_TAC[SUM_ADD; GSYM REAL_MUL_ASSOC; SUM_LMUL] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    REWRITE_TAC[REAL_ARITH `&1 = &1 - x <=> x = &0`] THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`c:real^N->real`;`f:real^N->bool`] SUM_POS_EQ_0) THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[FINITE_SUBSET; SUBSET]; ALL_TAC] THEN
+    SIMP_TAC[VECTOR_MUL_LZERO; VSUM_0];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_DISJOINT]) THEN
+  MATCH_MP_TAC(TAUT `b ==> ~b ==> c`) THEN
+  EXISTS_TAC `inv(k) % (w - vsum f (\x:real^N. c x % x))` THEN CONJ_TAC THENL
+   [ALL_TAC;
+    SUBGOAL_THEN `w = vsum f (\x:real^N. c x % x) +
+                      vsum (s DIFF f) (\x:real^N. c x % x)`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[VSUM_DIFF; VECTOR_ARITH `a + b - a:real^N = b`] THEN
+      EXPAND_TAC "c" THEN REWRITE_TAC[VECTOR_ADD_RDISTRIB] THEN
+      ASM_SIMP_TAC[VSUM_ADD; GSYM VECTOR_MUL_ASSOC; VSUM_LMUL];
+      REWRITE_TAC[VECTOR_ADD_SUB]] THEN
+    ASM_SIMP_TAC[GSYM VSUM_LMUL; FINITE_DIFF] THEN
+    REWRITE_TAC[CONVEX_HULL_FINITE; IN_ELIM_THM] THEN
+    EXISTS_TAC `\x. inv k * (c:real^N->real) x` THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_ASSOC] THEN
+    ASM_SIMP_TAC[IN_DIFF; REAL_LE_MUL; REAL_LE_INV_EQ; REAL_LT_IMP_LE] THEN
+    ASM_SIMP_TAC[SUM_LMUL; ETA_AX; REAL_MUL_LINV]] THEN
+  MATCH_MP_TAC lemma THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[AFFINE_AFFINE_HULL];
+    ASM_REWRITE_TAC[];
+    ASM_REWRITE_TAC[];
+    ASM_MESON_TAC[CONVEX_HULL_SUBSET_AFFINE_HULL; SUBSET];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM VSUM_LMUL; AFFINE_HULL_FINITE; IN_ELIM_THM] THEN
+  EXISTS_TAC `(\x. inv(&1 - k) * c x):real^N->real` THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC; SUM_LMUL] THEN
+  MATCH_MP_TAC(REAL_FIELD
+   `~(k = &1) /\ f = &1 - k ==> inv(&1 - k) * f = &1`) THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `sum(s DIFF f) c = sum s c - sum f (c:real^N->real)`
+  MP_TAC THENL [ASM_MESON_TAC[SUM_DIFF]; ALL_TAC] THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `sum s (c:real^N->real) = &1` SUBST1_TAC THENL
+   [EXPAND_TAC "c" THEN REWRITE_TAC[VECTOR_ADD_RDISTRIB] THEN
+    ASM_SIMP_TAC[SUM_ADD; GSYM REAL_MUL_ASSOC; SUM_LMUL];
+    ALL_TAC] THEN
+  REAL_ARITH_TAC);;
+
+let FACE_OF_CONVEX_HULL_INSERT = prove
+ (`!f s a:real^N.
+        FINITE s /\ ~(a IN affine hull s) /\ f face_of (convex hull s)
+        ==> f face_of (convex hull (a INSERT s))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC FACE_OF_TRANS THEN
+  EXISTS_TAC `convex hull s:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC FACE_OF_CONVEX_HULLS THEN
+  ASM_REWRITE_TAC[FINITE_INSERT; SET_RULE `s SUBSET a INSERT s`] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+   `~(a IN s) ==> t SUBSET {a} ==> DISJOINT s t`)) THEN
+  MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_SING] THEN SET_TAC[]);;
+
+let FACE_OF_AFFINE_TRIVIAL = prove
+ (`!s f:real^N->bool.
+        affine s /\ f face_of s ==> f = {} \/ f = s`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `f:real^N->bool = {}` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP FACE_OF_IMP_SUBSET) THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[SUBSET] THEN X_GEN_TAC `b:real^N` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `(b:real^N) IN f` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [face_of]) THEN
+  DISCH_THEN(MP_TAC o SPECL [`&2 % a - b:real^N`; `b:real^N`; `a:real^N`] o
+             CONJUNCT2 o CONJUNCT2) THEN
+  SUBGOAL_THEN `~(a:real^N = b)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  ASM_SIMP_TAC[IN_SEGMENT; VECTOR_ARITH `&2 % a - b:real^N = b <=> a = b`] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[VECTOR_ARITH `&2 % a - b:real^N = a + &1 % (a - b)`] THEN
+    MATCH_MP_TAC IN_AFFINE_ADD_MUL_DIFF THEN ASM SET_TAC[];
+    EXISTS_TAC `&1 / &2` THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    VECTOR_ARITH_TAC]);;
+
+let FACE_OF_AFFINE_EQ = prove
+ (`!s:real^N->bool f. affine s ==> (f face_of s <=> f = {} \/ f = s)`,
+  MESON_TAC[FACE_OF_AFFINE_TRIVIAL; EMPTY_FACE_OF; FACE_OF_REFL;
+            AFFINE_IMP_CONVEX]);;
+
+let INTERS_FACES_FINITE_BOUND = prove
+ (`!s f:(real^N->bool)->bool.
+        convex s /\ (!c. c IN f ==> c face_of s)
+        ==> ?f'. FINITE f' /\ f' SUBSET f /\ CARD f' <= dimindex(:N) + 1 /\
+                 INTERS f' = INTERS f`,
+  SUBGOAL_THEN
+   `!s f:(real^N->bool)->bool.
+        convex s /\ (!c. c IN f ==> c face_of s /\ ~(c = s))
+        ==> ?f'. FINITE f' /\ f' SUBSET f /\ CARD f' <= dimindex(:N) + 1 /\
+                 INTERS f' = INTERS f`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REPEAT STRIP_TAC THEN
+    ASM_CASES_TAC `(s:real^N->bool) IN f` THENL
+     [ALL_TAC; FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[]] THEN
+    FIRST_ASSUM(DISJ_CASES_THEN2 SUBST1_TAC MP_TAC o MATCH_MP (SET_RULE
+     `s IN f ==> f = {s} \/ ?t. ~(t = s) /\ t IN f`)) THENL
+     [EXISTS_TAC `{s:real^N->bool}` THEN
+      SIMP_TAC[FINITE_INSERT; FINITE_EMPTY; SUBSET_REFL; CARD_CLAUSES] THEN
+      ARITH_TAC;
+      DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC)] THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`s:real^N->bool`; `f DELETE
+      (s:real^N->bool)`]) THEN
+    ASM_SIMP_TAC[IN_DELETE; SUBSET_DELETE] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f':(real^N->bool)->bool` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `f = (s:real^N->bool) INSERT (f DELETE s)` MP_TAC THENL
+     [ASM SET_TAC[];
+      DISCH_THEN(fun th -> GEN_REWRITE_TAC (funpow 2 RAND_CONV) [th])] THEN
+    REWRITE_TAC[INTERS_INSERT] THEN
+    MATCH_MP_TAC(SET_RULE `t SUBSET s ==> t = s INTER t`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `t:real^N->bool`) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(ASSUME_TAC o MATCH_MP FACE_OF_IMP_SUBSET) THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `t:real^N->bool` THEN
+    ASM_REWRITE_TAC[] THEN REWRITE_TAC[SUBSET; IN_INTERS; IN_DELETE] THEN
+    ASM SET_TAC[]] THEN
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC
+   `!f':(real^N->bool)->bool.
+        FINITE f' /\ f' SUBSET f /\ CARD f' <= dimindex(:N) + 1
+        ==> ?c. c IN f /\ c INTER (INTERS f') PSUBSET (INTERS f')`
+  THENL
+   [ALL_TAC;
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM]) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+    SIMP_TAC[NOT_IMP; GSYM CONJ_ASSOC] THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    ASM_REWRITE_TAC[PSUBSET; INTER_SUBSET] THEN ASM SET_TAC[]] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE BINDER_CONV
+   [RIGHT_IMP_EXISTS_THM]) THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `c:((real^N->bool)->bool)->real^N->bool` THEN DISCH_TAC THEN
+  CHOOSE_TAC(prove_recursive_functions_exist num_RECURSION
+   `d 0 = {c {} :real^N->bool} /\ !n. d(SUC n) = c(d n) INSERT d n`) THEN
+  SUBGOAL_THEN `!n:num. ~(d n:(real^N->bool)->bool = {})` ASSUME_TAC THENL
+   [INDUCT_TAC THEN ASM_REWRITE_TAC[] THEN SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n. n <= dimindex(:N) + 1
+        ==> (d n) SUBSET (f:(real^N->bool)->bool) /\
+            FINITE(d n) /\ CARD(d n) <= n + 1`
+  ASSUME_TAC THENL
+   [INDUCT_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_SIMP_TAC[INSERT_SUBSET; CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY;
+      EMPTY_SUBSET; ARITH_RULE `SUC n <= m + 1 ==> n <= m + 1`] THEN
+    REPEAT STRIP_TAC THEN TRY ASM_ARITH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(d:num->(real^N->bool)->bool) n`) THEN
+    FIRST_X_ASSUM(MP_TAC o check (is_imp o concl)) THEN
+    ANTS_TAC THENL [ASM_ARITH_TAC; STRIP_TAC] THEN ASM_REWRITE_TAC[] THEN
+    ANTS_TAC THENL [ASM_ARITH_TAC; SIMP_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n. n <= dimindex(:N)
+        ==> (INTERS(d(SUC n)):real^N->bool) PSUBSET INTERS(d n)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[INTERS_INSERT] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(d:num->(real^N->bool)->bool) n`) THEN
+    ANTS_TAC THENL [ALL_TAC; SIMP_TAC[]] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `n:num`)) THEN
+    ASM_SIMP_TAC[ARITH_RULE `n <= N ==> n <= N + 1`] THEN
+    ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(CONJUNCTS_THEN(K ALL_TAC)) THEN
+  SUBGOAL_THEN
+   `!n. n <= dimindex(:N) + 1
+        ==> aff_dim(INTERS(d n):real^N->bool) < &(dimindex(:N)) - &n`
+  MP_TAC THENL
+   [INDUCT_TAC THENL
+     [DISCH_TAC THEN REWRITE_TAC[INT_SUB_RZERO] THEN
+      MATCH_MP_TAC INT_LTE_TRANS THEN
+      EXISTS_TAC `aff_dim(s:real^N->bool)` THEN
+      REWRITE_TAC[AFF_DIM_LE_UNIV] THEN
+      MATCH_MP_TAC FACE_OF_AFF_DIM_LT THEN
+      ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC FACE_OF_INTERS THEN ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY] o
+          SPEC `0`) THEN
+        DISCH_THEN(X_CHOOSE_TAC `e:real^N->bool`) THEN
+        FIRST_X_ASSUM(MP_TAC o SPEC `e:real^N->bool`) THEN
+        ANTS_TAC THENL [ASM SET_TAC[]; STRIP_TAC] THEN
+        MATCH_MP_TAC(SET_RULE
+         `!t. t PSUBSET s /\ u SUBSET t ==> ~(u = s)`) THEN
+        EXISTS_TAC `e:real^N->bool` THEN
+        FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP FACE_OF_IMP_SUBSET) THEN
+        ASM SET_TAC[]];
+      DISCH_TAC THEN REWRITE_TAC[GSYM INT_OF_NUM_SUC] THEN
+      MATCH_MP_TAC(INT_ARITH
+       `!d':int. d < d' /\ d' < m - n ==> d < m - (n + &1)`) THEN
+      EXISTS_TAC `aff_dim(INTERS(d(n:num)):real^N->bool)` THEN
+      ASM_SIMP_TAC[ARITH_RULE `SUC n <= k + 1 ==> n <= k + 1`] THEN
+      MATCH_MP_TAC FACE_OF_AFF_DIM_LT THEN
+      ASM_SIMP_TAC[ARITH_RULE `SUC n <= m + 1 ==> n <= m`;
+                   SET_RULE `s PSUBSET t ==> ~(s = t)`] THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC CONVEX_INTERS THEN
+        REPEAT STRIP_TAC THEN MATCH_MP_TAC FACE_OF_IMP_CONVEX THEN
+        EXISTS_TAC `s:real^N->bool` THEN
+        ASM_MESON_TAC[SUBSET; ARITH_RULE `SUC n <= m + 1 ==> n <= m + 1`];
+        ALL_TAC] THEN
+      MP_TAC(ISPECL [`INTERS(d(SUC n)):real^N->bool`;`s:real^N->bool`;
+                     `INTERS(d(n:num)):real^N->bool`] FACE_OF_FACE) THEN
+      ASM_SIMP_TAC[SET_RULE `s PSUBSET t ==> s SUBSET t`;
+                   ARITH_RULE `SUC n <= m + 1 ==> n <= m`] THEN
+      MATCH_MP_TAC(TAUT `a /\ b ==> (a ==> (c <=> b)) ==> c`) THEN
+      CONJ_TAC THEN MATCH_MP_TAC FACE_OF_INTERS THEN ASM_REWRITE_TAC[] THEN
+      ASM_MESON_TAC[SUBSET; ARITH_RULE `SUC n <= m + 1 ==> n <= m + 1`]];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `dimindex(:N) + 1`) THEN REWRITE_TAC[LE_REFL] THEN
+  MATCH_MP_TAC(TAUT `~p ==> p ==> q`) THEN REWRITE_TAC[INT_NOT_LT] THEN
+  REWRITE_TAC[GSYM INT_OF_NUM_ADD; INT_ARITH `d - (d + &1):int = -- &1`] THEN
+  REWRITE_TAC[AFF_DIM_GE]);;
+
+let INTERS_FACES_FINITE_ALTBOUND = prove
+ (`!s f:(real^N->bool)->bool.
+        (!c. c IN f ==> c face_of s)
+        ==> ?f'. FINITE f' /\ f' SUBSET f /\ CARD f' <= dimindex(:N) + 2 /\
+                 INTERS f' = INTERS f`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC
+   `!f':(real^N->bool)->bool.
+        FINITE f' /\ f' SUBSET f /\ CARD f' <= dimindex(:N) + 2
+        ==> ?c. c IN f /\ c INTER (INTERS f') PSUBSET (INTERS f')`
+  THENL
+   [ALL_TAC;
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM]) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+    SIMP_TAC[NOT_IMP; GSYM CONJ_ASSOC] THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    ASM_REWRITE_TAC[PSUBSET; INTER_SUBSET] THEN ASM SET_TAC[]] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE BINDER_CONV
+   [RIGHT_IMP_EXISTS_THM]) THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `c:((real^N->bool)->bool)->real^N->bool` THEN DISCH_TAC THEN
+  CHOOSE_TAC(prove_recursive_functions_exist num_RECURSION
+   `d 0 = {c {} :real^N->bool} /\ !n. d(SUC n) = c(d n) INSERT d n`) THEN
+  SUBGOAL_THEN `!n:num. ~(d n:(real^N->bool)->bool = {})` ASSUME_TAC THENL
+   [INDUCT_TAC THEN ASM_REWRITE_TAC[] THEN SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n. n <= dimindex(:N) + 2
+        ==> (d n) SUBSET (f:(real^N->bool)->bool) /\
+            FINITE(d n) /\ CARD(d n) <= n + 1`
+  ASSUME_TAC THENL
+   [INDUCT_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_SIMP_TAC[INSERT_SUBSET; CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY;
+      EMPTY_SUBSET; ARITH_RULE `SUC n <= m + 2 ==> n <= m + 2`] THEN
+    REPEAT STRIP_TAC THEN TRY ASM_ARITH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(d:num->(real^N->bool)->bool) n`) THEN
+    FIRST_X_ASSUM(MP_TAC o check (is_imp o concl)) THEN
+    ANTS_TAC THENL [ASM_ARITH_TAC; STRIP_TAC] THEN ASM_REWRITE_TAC[] THEN
+    ANTS_TAC THENL [ASM_ARITH_TAC; SIMP_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n. n <= dimindex(:N) + 1
+        ==> (INTERS(d(SUC n)):real^N->bool) PSUBSET INTERS(d n)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[INTERS_INSERT] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(d:num->(real^N->bool)->bool) n`) THEN
+    ANTS_TAC THENL [ALL_TAC; SIMP_TAC[]] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `n:num`)) THEN
+    ASM_SIMP_TAC[ARITH_RULE `n <= N + 1 ==> n <= N + 2`] THEN
+    ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(CONJUNCTS_THEN(K ALL_TAC)) THEN
+  SUBGOAL_THEN
+   `!n. n <= dimindex(:N) + 2
+        ==> aff_dim(INTERS(d n):real^N->bool) <= &(dimindex(:N)) - &n`
+  MP_TAC THENL
+   [INDUCT_TAC THEN REWRITE_TAC[INT_SUB_RZERO; AFF_DIM_LE_UNIV] THEN
+    DISCH_TAC THEN REWRITE_TAC[GSYM INT_OF_NUM_SUC] THEN
+    MATCH_MP_TAC(INT_ARITH
+     `!d':int. d < d' /\ d' <= m - n ==> d <= m - (n + &1)`) THEN
+    EXISTS_TAC `aff_dim(INTERS(d(n:num)):real^N->bool)` THEN
+    ASM_SIMP_TAC[ARITH_RULE `SUC n <= k + 2 ==> n <= k + 2`] THEN
+    MATCH_MP_TAC FACE_OF_AFF_DIM_LT THEN
+    ASM_SIMP_TAC[ARITH_RULE `SUC n <= m + 2 ==> n <= m + 1`;
+                 SET_RULE `s PSUBSET t ==> ~(s = t)`] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC CONVEX_INTERS THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC FACE_OF_IMP_CONVEX THEN
+      EXISTS_TAC `s:real^N->bool` THEN
+      ASM_MESON_TAC[SUBSET; ARITH_RULE `SUC n <= m + 2 ==> n <= m + 2`];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`INTERS(d(SUC n)):real^N->bool`;`s:real^N->bool`;
+                   `INTERS(d(n:num)):real^N->bool`] FACE_OF_FACE) THEN
+    ASM_SIMP_TAC[SET_RULE `s PSUBSET t ==> s SUBSET t`;
+                 ARITH_RULE `SUC n <= m + 2 ==> n <= m + 1`] THEN
+    MATCH_MP_TAC(TAUT `a /\ b ==> (a ==> (c <=> b)) ==> c`) THEN
+    CONJ_TAC THEN MATCH_MP_TAC FACE_OF_INTERS THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[SUBSET; ARITH_RULE `SUC n <= m + 2 ==> n <= m + 2`];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `dimindex(:N) + 2`) THEN REWRITE_TAC[LE_REFL] THEN
+  MATCH_MP_TAC(TAUT `~p ==> p ==> q`) THEN REWRITE_TAC[INT_NOT_LE] THEN
+  REWRITE_TAC[GSYM INT_OF_NUM_ADD; INT_ARITH
+    `d - (d + &2):int < i <=> -- &1 <= i`] THEN
+  REWRITE_TAC[AFF_DIM_GE]);;
+
+let FACES_OF_TRANSLATION = prove
+ (`!s a:real^N.
+        {f | f face_of IMAGE (\x. a + x) s} =
+        IMAGE (IMAGE (\x. a + x)) {f | f face_of s}`,
+  REPEAT GEN_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[IN_ELIM_THM; FACE_OF_TRANSLATION_EQ] THEN
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[EQ_SYM_EQ] THEN
+  ONCE_REWRITE_TAC[TRANSLATION_GALOIS] THEN
+  REWRITE_TAC[EXISTS_REFL]);;
+
+let FACES_OF_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> {t | t face_of (IMAGE f s)} = IMAGE (IMAGE f) {t | t face_of s}`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  REWRITE_TAC[face_of; SUBSET_IMAGE; SET_RULE
+   `{y | (?x. P x /\ y = f x) /\ Q y} = {f x |x| P x /\ Q(f x)}`] THEN
+  REWRITE_TAC[SET_RULE `IMAGE f {x | P x} = {f x | P x}`] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  FIRST_ASSUM(fun th ->
+   REWRITE_TAC[MATCH_MP CONVEX_LINEAR_IMAGE_EQ th;
+               MATCH_MP OPEN_SEGMENT_LINEAR_IMAGE th;
+               MATCH_MP (SET_RULE
+   `(!x y. f x = f y ==> x = y)  ==> (!s x. f x IN IMAGE f s <=> x IN s)`)
+   (CONJUNCT2 th)]));;
+
+let FACE_OF_CONIC = prove
+ (`!s f:real^N->bool. conic s /\ f face_of s ==> conic f`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[face_of; conic] THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `c:real`] THEN STRIP_TAC THEN
+  ASM_CASES_TAC `x:real^N = vec 0` THENL
+   [ASM_MESON_TAC[VECTOR_MUL_RZERO]; ALL_TAC] THEN
+  ASM_CASES_TAC `c = &1` THENL
+   [ASM_MESON_TAC[VECTOR_MUL_LID]; ALL_TAC] THEN
+  SUBGOAL_THEN `?d e. &0 <= d /\ &0 <= e /\ d < &1 /\ &1 < e /\ d < e /\
+                      (d = c \/ e = c)`
+  MP_TAC THENL
+   [FIRST_X_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+     `~(c = &1) ==> c < &1 \/ &1 < c`))
+    THENL
+     [MAP_EVERY EXISTS_TAC [`c:real`; `&2`] THEN ASM_REAL_ARITH_TAC;
+      MAP_EVERY EXISTS_TAC [`&1 / &2`; `c:real`] THEN ASM_REAL_ARITH_TAC];
+    DISCH_THEN(REPEAT_TCL CHOOSE_THEN
+      (REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC)) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`d % x :real^N`; `e % x:real^N`; `x:real^N`]) THEN
+    ANTS_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+    SUBGOAL_THEN `(x:real^N) IN s` ASSUME_TAC THENL
+     [ASM SET_TAC[]; ASM_SIMP_TAC[IN_SEGMENT]] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_RCANCEL; REAL_LT_IMP_NE] THEN
+    EXISTS_TAC `(&1 - d) / (e - d)`  THEN
+    ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_LT_RDIV_EQ; REAL_SUB_LT] THEN
+    REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC; GSYM VECTOR_ADD_RDISTRIB] THEN
+    REWRITE_TAC[VECTOR_ARITH `x:real^N = a % x <=> (a - &1) % x = vec 0`] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0] THEN
+    UNDISCH_TAC `d:real < e` THEN CONV_TAC REAL_FIELD]);;
+
+let FACE_OF_PCROSS = prove
+ (`!f s:real^M->bool f' s':real^N->bool.
+        f face_of s /\ f' face_of s' ==> (f PCROSS f') face_of (s PCROSS s')`,
+  REPEAT GEN_TAC THEN SIMP_TAC[face_of; CONVEX_PCROSS; PCROSS_MONO] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[IN_SEGMENT; FORALL_IN_PCROSS] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; GSYM CONJ_ASSOC] THEN
+  REWRITE_TAC[GSYM PASTECART_CMUL; PASTECART_ADD; PASTECART_INJ] THEN
+  REWRITE_TAC[PASTECART_IN_PCROSS] THEN
+  MAP_EVERY X_GEN_TAC
+   [`a:real^M`; `a':real^N`; `b:real^M`; `b':real^N`] THEN
+  MAP_EVERY ASM_CASES_TAC [`b:real^M = a`; `b':real^N = a'`] THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH `(&1 - u) % a + u % a:real^N = a`] THEN
+  ASM_MESON_TAC[]);;
+
+let FACE_OF_PCROSS_DECOMP = prove
+ (`!s:real^M->bool s':real^N->bool c.
+        c face_of (s PCROSS s') <=>
+        ?f f'. f face_of s /\ f' face_of s' /\ c = f PCROSS f'`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [ALL_TAC; STRIP_TAC THEN ASM_SIMP_TAC[FACE_OF_PCROSS]] THEN
+  ASM_CASES_TAC `c:real^(M,N)finite_sum->bool = {}` THENL
+   [ASM_MESON_TAC[EMPTY_FACE_OF; PCROSS_EMPTY]; DISCH_TAC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP FACE_OF_IMP_CONVEX) THEN
+  MAP_EVERY EXISTS_TAC
+   [`IMAGE fstcart (c:real^(M,N)finite_sum->bool)`;
+    `IMAGE sndcart (c:real^(M,N)finite_sum->bool)`] THEN
+  MATCH_MP_TAC(TAUT `(p /\ q ==> r) /\ p /\ q ==> p /\ q /\ r`) THEN
+  CONJ_TAC THENL
+   [STRIP_TAC THEN MATCH_MP_TAC FACE_OF_EQ THEN
+    EXISTS_TAC `(s:real^M->bool) PCROSS (s':real^N->bool)` THEN
+    ASM_SIMP_TAC[FACE_OF_PCROSS; RELATIVE_INTERIOR_PCROSS] THEN
+    ASM_SIMP_TAC[RELATIVE_INTERIOR_LINEAR_IMAGE_CONVEX;
+                 LINEAR_FSTCART; LINEAR_SNDCART] THEN
+    MATCH_MP_TAC(SET_RULE `~(s = {}) /\ s SUBSET t ==> ~DISJOINT s t`) THEN
+    ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY] THEN
+    REWRITE_TAC[SUBSET; FORALL_PASTECART; PASTECART_IN_PCROSS; IN_IMAGE] THEN
+    REWRITE_TAC[EXISTS_PASTECART; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    MESON_TAC[];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [face_of]) THEN
+  REWRITE_TAC[face_of] THEN
+  ASM_SIMP_TAC[CONVEX_LINEAR_IMAGE; LINEAR_FSTCART; LINEAR_SNDCART] THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `fstcart:real^(M,N)finite_sum->real^M` o
+        MATCH_MP IMAGE_SUBSET) THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `sndcart:real^(M,N)finite_sum->real^N` o
+        MATCH_MP IMAGE_SUBSET) THEN
+  REWRITE_TAC[IMAGE_FSTCART_PCROSS; IMAGE_SNDCART_PCROSS] THEN
+  REPEAT(DISCH_THEN(ASSUME_TAC o MATCH_MP (SET_RULE
+   `s SUBSET (if p then {} else t) ==> s SUBSET t`))) THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`; `x:real^M`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_IMAGE]) THEN
+    REWRITE_TAC[EXISTS_PASTECART; FSTCART_PASTECART] THEN
+    REWRITE_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM1] THEN
+    DISCH_THEN(X_CHOOSE_TAC `y:real^N`) THEN FIRST_X_ASSUM(MP_TAC o SPECL
+     [`pastecart (a:real^M) (y:real^N)`;
+      `pastecart (b:real^M) (y:real^N)`;
+      `pastecart (x:real^M) (y:real^N)`]) THEN
+    ASM_REWRITE_TAC[PASTECART_IN_PCROSS; IN_IMAGE; EXISTS_PASTECART] THEN
+    REWRITE_TAC[FSTCART_PASTECART; RIGHT_EXISTS_AND_THM; UNWIND_THM1] THEN
+    ANTS_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+    UNDISCH_TAC `(c:real^(M,N)finite_sum->bool) SUBSET s PCROSS s'` THEN
+    REWRITE_TAC[SUBSET] THEN
+    DISCH_THEN(MP_TAC o SPEC `pastecart (x:real^M) (y:real^N)`);
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`; `x:real^N`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_IMAGE]) THEN
+    REWRITE_TAC[EXISTS_PASTECART; SNDCART_PASTECART] THEN
+    REWRITE_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM1] THEN
+    DISCH_THEN(X_CHOOSE_TAC `y:real^M`) THEN FIRST_X_ASSUM(MP_TAC o SPECL
+     [`pastecart (y:real^M) (a:real^N)`;
+      `pastecart (y:real^M) (b:real^N)`;
+      `pastecart (y:real^M) (x:real^N)`]) THEN
+    ASM_REWRITE_TAC[PASTECART_IN_PCROSS; IN_IMAGE; EXISTS_PASTECART] THEN
+    REWRITE_TAC[SNDCART_PASTECART; RIGHT_EXISTS_AND_THM; UNWIND_THM1] THEN
+    ANTS_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+    UNDISCH_TAC `(c:real^(M,N)finite_sum->bool) SUBSET s PCROSS s'` THEN
+    REWRITE_TAC[SUBSET] THEN
+    DISCH_THEN(MP_TAC o SPEC `pastecart (y:real^M) (x:real^N)`)] THEN
+  ASM_REWRITE_TAC[PASTECART_IN_PCROSS] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_SEGMENT]) THEN
+  REWRITE_TAC[IN_SEGMENT; PASTECART_INJ] THEN
+  REWRITE_TAC[PASTECART_ADD; GSYM PASTECART_CMUL;
+              VECTOR_ARITH `(&1 - u) % a + u % a:real^N = a`] THEN
+  MESON_TAC[]);;
+
+let FACE_OF_PCROSS_EQ = prove
+ (`!f s:real^M->bool f' s':real^N->bool.
+        (f PCROSS f') face_of (s PCROSS s') <=>
+        f = {} \/ f' = {} \/ f face_of s /\ f' face_of s'`,
+  REPEAT GEN_TAC THEN MAP_EVERY ASM_CASES_TAC
+   [`f:real^M->bool = {}`; `f':real^N->bool = {}`] THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; EMPTY_FACE_OF] THEN
+  ASM_REWRITE_TAC[FACE_OF_PCROSS_DECOMP; PCROSS_EQ] THEN MESON_TAC[]);;
+
+let HYPERPLANE_FACE_OF_HALFSPACE_LE = prove
+ (`!a:real^N b. {x | a dot x = b} face_of {x | a dot x <= b}`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a:real = b <=> a <= b /\ a = b`] THEN
+  REWRITE_TAC[SET_RULE `{x | P x /\ Q x} = {x | P x} INTER {x | Q x}`] THEN
+  MATCH_MP_TAC FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE THEN
+  REWRITE_TAC[IN_ELIM_THM; CONVEX_HALFSPACE_LE]);;
+
+let HYPERPLANE_FACE_OF_HALFSPACE_GE = prove
+ (`!a:real^N b. {x | a dot x = b} face_of {x | a dot x >= b}`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a:real = b <=> a >= b /\ a = b`] THEN
+  REWRITE_TAC[SET_RULE `{x | P x /\ Q x} = {x | P x} INTER {x | Q x}`] THEN
+  MATCH_MP_TAC FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE THEN
+  REWRITE_TAC[IN_ELIM_THM; CONVEX_HALFSPACE_GE]);;
+
+let FACE_OF_HALFSPACE_LE = prove
+ (`!f a:real^N b.
+         f face_of {x | a dot x <= b} <=>
+         f = {} \/ f = {x | a dot x = b} \/ f = {x | a dot x <= b}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THENL
+   [ASM_SIMP_TAC[DOT_LZERO; SET_RULE `{x | p} = if p then UNIV else {}`] THEN
+    REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[FACE_OF_EMPTY]) THEN
+    ASM_SIMP_TAC[FACE_OF_AFFINE_EQ; AFFINE_UNIV; DISJ_ACI] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  EQ_TAC THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[EMPTY_FACE_OF; FACE_OF_REFL; CONVEX_HALFSPACE_LE;
+               HYPERPLANE_FACE_OF_HALFSPACE_LE] THEN
+  MATCH_MP_TAC(TAUT `(~r ==> p \/ q) ==> p \/ q \/ r`) THEN DISCH_TAC THEN
+  SUBGOAL_THEN `f face_of {x:real^N | a dot x = b}` MP_TAC THENL
+   [ASM_SIMP_TAC[GSYM FRONTIER_HALFSPACE_LE] THEN
+    ASM_SIMP_TAC[CONV_RULE(RAND_CONV SYM_CONV)
+                  (SPEC_ALL RELATIVE_FRONTIER_NONEMPTY_INTERIOR);
+                 INTERIOR_HALFSPACE_LE; HALFSPACE_EQ_EMPTY_LT] THEN
+    MATCH_MP_TAC FACE_OF_SUBSET THEN
+    EXISTS_TAC `{x:real^N | a dot x <= b}` THEN
+    ASM_SIMP_TAC[FACE_OF_SUBSET_RELATIVE_FRONTIER] THEN
+    ASM_SIMP_TAC[relative_frontier; CLOSURE_CLOSED; CLOSED_HALFSPACE_LE] THEN
+    SET_TAC[];
+    ASM_SIMP_TAC[FACE_OF_AFFINE_EQ; AFFINE_HYPERPLANE]]);;
+
+let FACE_OF_HALFSPACE_GE = prove
+ (`!f a:real^N b.
+         f face_of {x | a dot x >= b} <=>
+         f = {} \/ f = {x | a dot x = b} \/ f = {x | a dot x >= b}`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`f:real^N->bool`; `--a:real^N`; `--b:real`]
+        FACE_OF_HALFSPACE_LE) THEN
+  REWRITE_TAC[DOT_LNEG; REAL_LE_NEG2; REAL_EQ_NEG2; real_ge]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Exposed faces (faces that are intersection with supporting hyperplane).   *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("exposed_face_of",(12,"right"));;
+
+let exposed_face_of = new_definition
+ `t exposed_face_of s <=>
+    t face_of s /\
+    ?a b. s SUBSET {x | a dot x <= b} /\ t = s INTER {x | a dot x = b}`;;
+
+let EMPTY_EXPOSED_FACE_OF = prove
+ (`!s:real^N->bool. {} exposed_face_of s`,
+  GEN_TAC THEN REWRITE_TAC[exposed_face_of; EMPTY_FACE_OF] THEN
+  MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `&1:real`] THEN
+  REWRITE_TAC[DOT_LZERO] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN SET_TAC[]);;
+
+let EXPOSED_FACE_OF_REFL_EQ = prove
+ (`!s:real^N->bool. s exposed_face_of s <=> convex s`,
+  GEN_TAC THEN REWRITE_TAC[exposed_face_of; FACE_OF_REFL_EQ] THEN
+  ASM_CASES_TAC `convex(s:real^N->bool)` THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `&0:real`] THEN
+  REWRITE_TAC[DOT_LZERO] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN SET_TAC[]);;
+
+let EXPOSED_FACE_OF_REFL = prove
+ (`!s:real^N->bool. convex s ==> s exposed_face_of s`,
+  REWRITE_TAC[EXPOSED_FACE_OF_REFL_EQ]);;
+
+let EXPOSED_FACE_OF = prove
+ (`!s t. t exposed_face_of s <=>
+             t face_of s /\
+             (t = {} \/ t = s \/
+              ?a b. ~(a = vec 0) /\
+                    s SUBSET {x:real^N | a dot x <= b} /\
+                    t = s INTER {x | a dot x = b})`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[EMPTY_EXPOSED_FACE_OF; EMPTY_FACE_OF] THEN
+  ASM_CASES_TAC `t:real^N->bool = s` THEN
+  ASM_REWRITE_TAC[EXPOSED_FACE_OF_REFL_EQ; FACE_OF_REFL_EQ] THEN
+  REWRITE_TAC[exposed_face_of] THEN AP_TERM_TAC THEN
+  EQ_TAC THENL [REWRITE_TAC[LEFT_IMP_EXISTS_THM]; MESON_TAC[]] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real`] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY EXISTS_TAC [`a:real^N`; `b:real`] THEN
+  ASM_CASES_TAC `a:real^N = vec 0` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM SUBST_ALL_TAC THEN REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[DOT_LZERO] THEN SET_TAC[]);;
+
+let EXPOSED_FACE_OF_TRANSLATION_EQ = prove
+ (`!a f s:real^N->bool.
+        (IMAGE (\x. a + x) f) exposed_face_of (IMAGE (\x. a + x) s) <=>
+        f exposed_face_of s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[exposed_face_of; FACE_OF_TRANSLATION_EQ] THEN
+  MP_TAC(ISPEC `\x:real^N. a + x` QUANTIFY_SURJECTION_THM) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [MESON_TAC[VECTOR_ARITH `y + (x - y):real^N = x`]; ALL_TAC] THEN
+  DISCH_THEN(fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+    [last(CONJUNCTS th)]) THEN
+  REWRITE_TAC[end_itlist CONJ (!invariant_under_translation)] THEN
+  REWRITE_TAC[DOT_RADD] THEN ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
+  REWRITE_TAC[GSYM REAL_LE_SUB_LADD; GSYM REAL_EQ_SUB_LADD] THEN
+  AP_TERM_TAC THEN AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `c:real^N` THEN REWRITE_TAC[] THEN
+  EQ_TAC THEN DISCH_THEN(X_CHOOSE_THEN `b:real` STRIP_ASSUME_TAC) THENL
+   [EXISTS_TAC `b - (c:real^N) dot a`;
+    EXISTS_TAC `b + (c:real^N) dot a`] THEN
+  ASM_REWRITE_TAC[REAL_ARITH `(x + y) - y:real = x`]);;
+
+add_translation_invariants [EXPOSED_FACE_OF_TRANSLATION_EQ];;
+
+let EXPOSED_FACE_OF_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N c s.
+      linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+      ==> ((IMAGE f c) exposed_face_of (IMAGE f s) <=> c exposed_face_of s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[exposed_face_of] THEN
+  BINOP_TAC THENL [ASM_MESON_TAC[FACE_OF_LINEAR_IMAGE]; ALL_TAC] THEN
+  MP_TAC(ISPEC `f:real^M->real^N` QUANTIFY_SURJECTION_THM) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+    [last(CONJUNCTS th)]) THEN
+  ONCE_REWRITE_TAC[DOT_SYM] THEN ASM_SIMP_TAC[ADJOINT_WORKS] THEN
+  MP_TAC(end_itlist CONJ
+   (mapfilter (ISPEC `f:real^M->real^N`) (!invariant_under_linear))) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN AP_TERM_TAC THEN ABS_TAC THEN
+  EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `adjoint(f:real^M->real^N) a` THEN ASM_REWRITE_TAC[];
+    DISCH_THEN(X_CHOOSE_THEN `a:real^M` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPEC `adjoint(f:real^M->real^N)`
+      LINEAR_SURJECTIVE_RIGHT_INVERSE) THEN
+    ASM_SIMP_TAC[ADJOINT_SURJECTIVE; ADJOINT_LINEAR] THEN
+    REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `g:real^M->real^N` THEN STRIP_TAC THEN
+    EXISTS_TAC `(g:real^M->real^N) a` THEN ASM_REWRITE_TAC[]]);;
+
+let EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE = prove
+ (`!s a:real^N b.
+        convex s /\ (!x. x IN s ==> a dot x <= b)
+        ==> (s INTER {x | a dot x = b}) exposed_face_of s`,
+  SIMP_TAC[FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE; exposed_face_of] THEN
+  SET_TAC[]);;
+
+let EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE = prove
+ (`!s a:real^N b.
+        convex s /\ (!x. x IN s ==> a dot x >= b)
+        ==> (s INTER {x | a dot x = b}) exposed_face_of s`,
+  REWRITE_TAC[real_ge] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `--a:real^N`; `--b:real`]
+    EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE) THEN
+  ASM_REWRITE_TAC[DOT_LNEG; REAL_EQ_NEG2; REAL_LE_NEG2]);;
+
+let EXPOSED_FACE_OF_INTER = prove
+ (`!s t u:real^N->bool.
+        t exposed_face_of s /\ u exposed_face_of s
+        ==> (t INTER u) exposed_face_of s`,
+  REPEAT GEN_TAC THEN SIMP_TAC[exposed_face_of; FACE_OF_INTER] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`a':real^N`; `b':real`; `a:real^N`; `b:real`] THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  MAP_EVERY EXISTS_TAC [`a + a':real^N`; `b + b':real`] THEN
+  REWRITE_TAC[SET_RULE
+   `(s INTER t1) INTER (s INTER t2) = s INTER u <=>
+    !x. x IN s ==> (x IN t1 /\ x IN t2 <=> x IN u)`] THEN
+  ASM_SIMP_TAC[DOT_LADD; REAL_LE_ADD2; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`)) THEN
+  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let EXPOSED_FACE_OF_INTERS = prove
+ (`!P s:real^N->bool.
+        ~(P = {}) /\ (!t. t IN P ==> t exposed_face_of s)
+        ==> INTERS P exposed_face_of s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `P:(real^N->bool)->bool`]
+    INTERS_FACES_FINITE_ALTBOUND) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[exposed_face_of]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `Q:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SYM) THEN
+  ASM_CASES_TAC `Q:(real^N->bool)->bool = {}` THENL
+   [ASM_SIMP_TAC[INTERS_0] THEN
+    REWRITE_TAC[SET_RULE `INTERS s = UNIV <=> !t. t IN s ==> t = UNIV`] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    ASM_MESON_TAC[];
+    DISCH_THEN SUBST1_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o check (is_neg o concl)) THEN
+    SUBGOAL_THEN `!t:real^N->bool. t IN Q ==> t exposed_face_of s` MP_TAC THENL
+     [ASM SET_TAC[]; UNDISCH_TAC `FINITE(Q:(real^N->bool)->bool)`] THEN
+    SPEC_TAC(`Q:(real^N->bool)->bool`,`Q:(real^N->bool)->bool`) THEN
+    POP_ASSUM_LIST(K ALL_TAC) THEN
+    MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[FORALL_IN_INSERT] THEN
+    MAP_EVERY X_GEN_TAC [`t:real^N->bool`; `P:(real^N->bool)->bool`] THEN
+    DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[INTERS_INSERT] THEN
+    ASM_CASES_TAC `P:(real^N->bool)->bool = {}` THEN
+    ASM_SIMP_TAC[INTERS_0; INTER_UNIV; EXPOSED_FACE_OF_INTER]]);;
+
+let EXPOSED_FACE_OF_SUMS = prove
+ (`!s t f:real^N->bool.
+        convex s /\ convex t /\
+        f exposed_face_of {x + y | x IN s /\ y IN t}
+        ==> ?k l. k exposed_face_of s /\ l exposed_face_of t /\
+                  f = {x + y | x IN k /\ y IN l}`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXPOSED_FACE_OF]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_CASES_TAC `f:real^N->bool = {}` THENL
+   [DISCH_TAC THEN REPEAT (EXISTS_TAC `{}:real^N->bool`) THEN
+    ASM_REWRITE_TAC[EMPTY_EXPOSED_FACE_OF] THEN SET_TAC[];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `f = {x + y :real^N | x IN s /\ y IN t}` THENL
+   [DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC [`s:real^N->bool`; `t:real^N->bool`] THEN
+    ASM_SIMP_TAC[EXPOSED_FACE_OF_REFL];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N`; `z:real`] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_ELIM_THM] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN SUBST_ALL_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM SUBSET_INTER_ABSORPTION]) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  REWRITE_TAC[EXISTS_IN_GSPEC; IN_INTER] THEN
+  REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a0:real^N`; `b0:real^N`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+  EXISTS_TAC `s INTER {x:real^N | u dot x = u dot a0}` THEN
+  EXISTS_TAC `t INTER {y:real^N | u dot y = u dot b0}` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`a:real^N`; `b0:real^N`]) THEN
+    ASM_REWRITE_TAC[DOT_RADD] THEN REAL_ARITH_TAC;
+    MATCH_MP_TAC EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `b:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`a0:real^N`; `b:real^N`]) THEN
+    ASM_REWRITE_TAC[DOT_RADD] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_INTER; IMP_CONJ] THENL
+   [ALL_TAC; SIMP_TAC[IN_INTER; IN_ELIM_THM; DOT_RADD] THEN MESON_TAC[]] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  DISCH_TAC THEN DISCH_TAC THEN REWRITE_TAC[IN_ELIM_THM; DOT_RADD] THEN
+  DISCH_TAC THEN MAP_EVERY EXISTS_TAC [`a:real^N`; `b:real^N`] THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(MP_TAC o SPECL  [`a:real^N`; `b0:real^N`]) THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL  [`a0:real^N`; `b:real^N`]) THEN
+  ASM_REWRITE_TAC[DOT_RADD] THEN ASM_REAL_ARITH_TAC);;
+
+let EXPOSED_FACE_OF_PARALLEL = prove
+ (`!t s. t exposed_face_of s <=>
+         t face_of s /\
+          ?a b. s SUBSET {x:real^N | a dot x <= b} /\
+                t = s INTER {x | a dot x = b} /\
+                (~(t = {}) /\ ~(t = s) ==> ~(a = vec 0)) /\
+                (!w. w IN affine hull s /\ ~(t = s)
+                     ==> (w + a) IN affine hull s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[exposed_face_of] THEN
+  AP_TERM_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[LEFT_IMP_EXISTS_THM];
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN SIMP_TAC[]] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real`] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`affine hull s:real^N->bool`; `--a:real^N`; `--b:real`]
+        AFFINE_PARALLEL_SLICE) THEN
+  SIMP_TAC[AFFINE_AFFINE_HULL; DOT_LNEG; REAL_LE_NEG2; REAL_EQ_NEG2] THEN
+  DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC) THENL
+   [MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `&1`] THEN
+    REWRITE_TAC[DOT_LZERO; REAL_POS; SET_RULE `{x | T} = UNIV`] THEN
+    SIMP_TAC[SUBSET_UNIV; VECTOR_ADD_RID; REAL_ARITH `~(&0 = &1)`] THEN
+    REWRITE_TAC[EMPTY_GSPEC] THEN ASM_REWRITE_TAC[INTER_EMPTY] THEN
+    MATCH_MP_TAC(TAUT `p ==> p /\ ~(~p /\ q)`) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `s' INTER t' = {}
+      ==> s SUBSET s' /\ t SUBSET t' ==> s INTER t = {}`)) THEN
+    REWRITE_TAC[HULL_SUBSET] THEN SIMP_TAC[SUBSET; IN_ELIM_THM; REAL_LE_REFL];
+    SUBGOAL_THEN `t:real^N->bool = s` SUBST1_TAC THENL
+     [FIRST_X_ASSUM SUBST1_TAC THEN REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN
+      SUBGOAL_THEN `s SUBSET affine hull (s:real^N->bool)` MP_TAC THENL
+       [REWRITE_TAC[HULL_SUBSET]; ASM SET_TAC[]];
+      MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `&0`] THEN
+      REWRITE_TAC[DOT_LZERO; SET_RULE `{x | T} = UNIV`; REAL_LE_REFL] THEN
+      SET_TAC[]];
+    FIRST_X_ASSUM(X_CHOOSE_THEN `a':real^N` MP_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `b':real` STRIP_ASSUME_TAC) THEN
+    MAP_EVERY EXISTS_TAC [`--a':real^N`; `--b':real`] THEN
+    ASM_REWRITE_TAC[DOT_LNEG; REAL_LE_NEG2; REAL_EQ_NEG2] THEN
+    REPEAT CONJ_TAC THENL
+     [ONCE_REWRITE_TAC[REAL_ARITH `b <= a <=> ~(a <= b) \/ a = b`] THEN
+      MATCH_MP_TAC(SET_RULE
+       `!s'. s SUBSET s' /\
+            s SUBSET (UNIV DIFF (s' INTER {x | P x})) UNION
+                     (s' INTER {x | Q x})
+            ==> s SUBSET {x | ~P x \/ Q x}`) THEN
+      EXISTS_TAC `affine hull s:real^N->bool` THEN
+      ASM_REWRITE_TAC[HULL_SUBSET] THEN
+      MATCH_MP_TAC(SET_RULE
+       `s SUBSET s' /\ s SUBSET (UNIV DIFF {x | P x}) UNION {x | Q x}
+        ==> s SUBSET (UNIV DIFF (s' INTER {x | P x})) UNION
+                     (s' INTER {x | Q x})`) THEN
+      REWRITE_TAC[HULL_SUBSET] THEN MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `{x:real^N | a dot x <= b}` THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[SUBSET; IN_DIFF; IN_UNIV; IN_UNION; IN_ELIM_THM] THEN
+      REAL_ARITH_TAC;
+      FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `s' INTER a = s' INTER b
+        ==> s SUBSET s' ==> s INTER b = s INTER a`)) THEN
+      REWRITE_TAC[HULL_SUBSET];
+      ASM_REWRITE_TAC[VECTOR_NEG_EQ_0];
+      ONCE_REWRITE_TAC[VECTOR_ARITH
+       `w + --a:real^N = w + &1 % (w - (w + a))`] THEN
+      ASM_SIMP_TAC[IN_AFFINE_ADD_MUL_DIFF; AFFINE_AFFINE_HULL]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Extreme points of a set, which are its singleton faces.                   *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("extreme_point_of",(12,"right"));;
+
+let extreme_point_of = new_definition
+ `x extreme_point_of s <=>
+    x IN s /\ !a b. a IN s /\ b IN s ==> ~(x IN segment(a,b))`;;
+
+let EXTREME_POINT_OF_STILLCONVEX = prove
+ (`!s x:real^N.
+        convex s ==> (x extreme_point_of s <=> x IN s /\ convex(s DELETE x))`,
+  REWRITE_TAC[CONVEX_CONTAINS_SEGMENT; extreme_point_of; open_segment] THEN
+  REWRITE_TAC[IN_DIFF; IN_DELETE; IN_INSERT; NOT_IN_EMPTY; SUBSET_DELETE] THEN
+  SET_TAC[]);;
+
+let FACE_OF_SING = prove
+ (`!x s. {x} face_of s <=> x extreme_point_of s`,
+  SIMP_TAC[face_of; extreme_point_of; SING_SUBSET; CONVEX_SING; IN_SING] THEN
+  MESON_TAC[SEGMENT_REFL; NOT_IN_EMPTY]);;
+
+let EXTREME_POINT_NOT_IN_RELATIVE_INTERIOR = prove
+ (`!s x:real^N.
+        x extreme_point_of s /\ ~(s = {x})
+        ==> ~(x IN relative_interior s)`,
+  REPEAT GEN_TAC THEN CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN
+  REWRITE_TAC[GSYM FACE_OF_SING] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP FACE_OF_DISJOINT_RELATIVE_INTERIOR) THEN
+  SET_TAC[]);;
+
+let EXTREME_POINT_NOT_IN_INTERIOR = prove
+ (`!s x:real^N. x extreme_point_of s ==> ~(x IN interior s)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN ASM_CASES_TAC `s = {x:real^N}` THEN
+  ASM_SIMP_TAC[EMPTY_INTERIOR_FINITE; FINITE_SING; NOT_IN_EMPTY] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[SUBSET]
+    INTERIOR_SUBSET_RELATIVE_INTERIOR)) THEN
+  ASM_SIMP_TAC[EXTREME_POINT_NOT_IN_RELATIVE_INTERIOR]);;
+
+let EXTREME_POINT_OF_FACE = prove
+ (`!f s v. f face_of s
+           ==> (v extreme_point_of f <=> v extreme_point_of s /\ v IN f)`,
+  REWRITE_TAC[GSYM FACE_OF_SING; GSYM SING_SUBSET; FACE_OF_FACE]);;
+
+let EXTREME_POINT_OF_MIDPOINT = prove
+ (`!s x:real^N.
+        convex s
+        ==> (x extreme_point_of s <=>
+             x IN s /\
+             !a b. a IN s /\ b IN s /\ x = midpoint(a,b) ==> x = a /\ x = b)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[extreme_point_of] THEN
+  AP_TERM_TAC THEN EQ_TAC THEN
+  DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  DISCH_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o SPECL [`a:real^N`; `b:real^N`]) THEN
+    ASM_SIMP_TAC[MIDPOINT_IN_SEGMENT; MIDPOINT_REFL];
+    ALL_TAC] THEN
+  REWRITE_TAC[IN_SEGMENT] THEN DISCH_THEN(CONJUNCTS_THEN2
+    ASSUME_TAC (X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC)) THEN
+  ABBREV_TAC `d = min (&1 - u) u` THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+   [`x - d / &2 % (b - a):real^N`; `x + d / &2 % (b - a):real^N`]) THEN
+  REWRITE_TAC[NOT_IMP] THEN REPEAT CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONVEX_ALT]) THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH
+     `((&1 - u) % a + u % b) - d / &2 % (b - a):real^N =
+      (&1 - (u - d / &2)) % a + (u - d / &2) % b`] THEN
+    DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONVEX_ALT]) THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH
+     `((&1 - u) % a + u % b) + d / &2 % (b - a):real^N =
+      (&1 - (u + d / &2)) % a + (u + d / &2) % b`] THEN
+    DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[midpoint] THEN VECTOR_ARITH_TAC;
+    REWRITE_TAC[VECTOR_ARITH `x:real^N = x - d <=> d = vec 0`;
+                VECTOR_ARITH `x:real^N = x + d <=> d = vec 0`] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ] THEN ASM_REAL_ARITH_TAC]);;
+
+let EXTREME_POINT_OF_CONVEX_HULL = prove
+ (`!x:real^N s. x extreme_point_of (convex hull s) ==> x IN s`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[EXTREME_POINT_OF_STILLCONVEX; CONVEX_CONVEX_HULL] THEN
+  MP_TAC(ISPECL [`convex:(real^N->bool)->bool`; `s:real^N->bool`;
+                 `(convex hull s) DELETE (x:real^N)`] HULL_MINIMAL) THEN
+  MP_TAC(ISPECL [`convex:(real^N->bool)->bool`; `s:real^N->bool`]
+        HULL_SUBSET) THEN
+  ASM SET_TAC[]);;
+
+let EXTREME_POINTS_OF_CONVEX_HULL = prove
+ (`!s. {x | x extreme_point_of (convex hull s)} SUBSET s`,
+  REWRITE_TAC[SUBSET; IN_ELIM_THM; EXTREME_POINT_OF_CONVEX_HULL]);;
+
+let EXTREME_POINT_OF_EMPTY = prove
+ (`!x. ~(x extreme_point_of {})`,
+  REWRITE_TAC[extreme_point_of; NOT_IN_EMPTY]);;
+
+let EXTREME_POINT_OF_SING = prove
+ (`!a x. x extreme_point_of {a} <=> x = a`,
+  REWRITE_TAC[extreme_point_of; IN_SING] THEN
+  MESON_TAC[SEGMENT_REFL; NOT_IN_EMPTY]);;
+
+let EXTREME_POINT_OF_TRANSLATION_EQ = prove
+ (`!a:real^N x s.
+           (a + x) extreme_point_of (IMAGE (\x. a + x) s) <=>
+           x extreme_point_of s`,
+  REWRITE_TAC[extreme_point_of] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [EXTREME_POINT_OF_TRANSLATION_EQ];;
+
+let EXTREME_POINT_OF_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N.
+      linear f /\ (!x y. f x = f y ==> x = y)
+      ==> ((f x) extreme_point_of (IMAGE f s) <=> x extreme_point_of s)`,
+  REWRITE_TAC[GSYM FACE_OF_SING] THEN GEOM_TRANSFORM_TAC[]);;
+
+add_linear_invariants [EXTREME_POINT_OF_LINEAR_IMAGE];;
+
+let EXTREME_POINTS_OF_TRANSLATION = prove
+ (`!a s. {x:real^N | x extreme_point_of (IMAGE (\x. a + x) s)} =
+         IMAGE (\x. a + x) {x | x extreme_point_of s}`,
+  REPEAT GEN_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[VECTOR_ARITH `a + x:real^N = y <=> x = y - a`; EXISTS_REFL] THEN
+  REWRITE_TAC[IN_ELIM_THM; EXTREME_POINT_OF_TRANSLATION_EQ]);;
+
+let EXTREME_POINT_OF_INTER = prove
+ (`!x s t. x extreme_point_of s /\ x extreme_point_of t
+           ==> x extreme_point_of (s INTER t)`,
+  REWRITE_TAC[extreme_point_of; IN_INTER] THEN MESON_TAC[]);;
+
+let EXTREME_POINTS_OF_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> {y | y extreme_point_of (IMAGE f s)} =
+            IMAGE f {x | x extreme_point_of s}`,
+
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_SEGMENT_LINEAR_IMAGE) THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; FORALL_IN_GSPEC; SUBSET;
+              extreme_point_of; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[FUN_IN_IMAGE; IN_ELIM_THM; IMP_IMP; GSYM CONJ_ASSOC] THEN
+  ASM SET_TAC[]);;
+
+let EXTREME_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE = prove
+ (`!s a b c. (!x. x IN s ==> a dot x <= b) /\
+             s INTER {x | a dot x = b} = {c}
+             ==> c extreme_point_of s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM FACE_OF_SING] THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE_STRONG THEN
+  ASM_REWRITE_TAC[CONVEX_SING]);;
+
+let EXTREME_POINT_OF_INTER_SUPPORTING_HYPERPLANE_GE = prove
+ (`!s a b c. (!x. x IN s ==> a dot x >= b) /\
+             s INTER {x | a dot x = b} = {c}
+             ==> c extreme_point_of s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM FACE_OF_SING] THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE_STRONG THEN
+  ASM_REWRITE_TAC[CONVEX_SING]);;
+
+let EXPOSED_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE = prove
+ (`!s a b c:real^N.
+        (!x. x IN s ==> a dot x <= b) /\
+        s INTER {x | a dot x = b} = {c}
+        ==> {c} exposed_face_of s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[exposed_face_of] THEN CONJ_TAC THENL
+   [REWRITE_TAC[FACE_OF_SING] THEN
+    MATCH_MP_TAC EXTREME_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE;
+    ALL_TAC] THEN
+  MAP_EVERY EXISTS_TAC [`a:real^N`; `b:real`] THEN ASM SET_TAC[]);;
+
+let EXPOSED_POINT_OF_INTER_SUPPORTING_HYPERPLANE_GE = prove
+ (`!s a b c:real^N.
+        (!x. x IN s ==> a dot x >= b) /\
+        s INTER {x | a dot x = b} = {c}
+        ==> {c} exposed_face_of s`,
+  REWRITE_TAC[real_ge] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `--a:real^N`; `--b:real`; `c:real^N`]
+    EXPOSED_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE) THEN
+  ASM_REWRITE_TAC[DOT_LNEG; REAL_EQ_NEG2; REAL_LE_NEG2]);;
+
+let EXPOSED_POINT_OF_FURTHEST_POINT = prove
+ (`!s a b:real^N.
+        b IN s /\ (!x. x IN s ==> dist(a,x) <= dist(a,b))
+        ==> {b} exposed_face_of s`,
+  REPEAT GEN_TAC THEN GEOM_ORIGIN_TAC `a:real^N` THEN
+  REWRITE_TAC[DIST_0; NORM_LE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC EXPOSED_POINT_OF_INTER_SUPPORTING_HYPERPLANE_LE THEN
+  MAP_EVERY EXISTS_TAC [`b:real^N`; `(b:real^N) dot b`] THEN CONJ_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN
+    ASM_REWRITE_TAC[];
+    MATCH_MP_TAC SUBSET_ANTISYM THEN
+    ASM_REWRITE_TAC[IN_INTER; SING_SUBSET; IN_ELIM_THM] THEN
+    REWRITE_TAC[SUBSET; IN_SING; IN_INTER; IN_ELIM_THM] THEN
+    X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
+    CONV_TAC SYM_CONV THEN ASM_REWRITE_TAC[VECTOR_EQ] THEN
+    ASM_SIMP_TAC[GSYM REAL_LE_ANTISYM] THEN
+    UNDISCH_TAC `(b:real^N) dot x = b dot b`] THEN
+  MP_TAC(ISPEC `b - x:real^N` DOT_POS_LE) THEN
+  REWRITE_TAC[DOT_LSUB; DOT_RSUB; DOT_SYM] THEN REAL_ARITH_TAC);;
+
+let COLLINEAR_EXTREME_POINTS = prove
+ (`!s. collinear s
+       ==> FINITE {x:real^N | x extreme_point_of s} /\
+           CARD {x | x extreme_point_of s} <= 2`,
+  REWRITE_TAC[GSYM NOT_LT; TAUT `a /\ ~b <=> ~(a ==> b)`] THEN
+  REWRITE_TAC[ARITH_RULE `2 < n <=> 3 <= n`] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP CHOOSE_SUBSET_STRONG) THEN
+  CONV_TAC(ONCE_DEPTH_CONV HAS_SIZE_CONV) THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN REWRITE_TAC[NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`t:real^N->bool`; `a:real^N`; `b:real^N`; `c:real^N`] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM SUBST_ALL_TAC THEN
+  SUBGOAL_THEN
+   `(a:real^N) extreme_point_of s /\
+    b extreme_point_of s /\ c extreme_point_of s`
+  STRIP_ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `(a:real^N) IN s /\ b IN s /\ c IN s` STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[extreme_point_of]; ALL_TAC] THEN
+  SUBGOAL_THEN `collinear {a:real^N,b,c}` MP_TAC THENL
+   [MATCH_MP_TAC COLLINEAR_SUBSET THEN EXISTS_TAC `s:real^N->bool` THEN
+    ASM SET_TAC[];
+    REWRITE_TAC[COLLINEAR_BETWEEN_CASES; BETWEEN_IN_SEGMENT] THEN
+    ASM_SIMP_TAC[SEGMENT_CLOSED_OPEN; IN_INSERT; NOT_IN_EMPTY; IN_UNION] THEN
+    ASM_MESON_TAC[extreme_point_of]]);;
+
+let EXTREME_POINT_OF_CONIC = prove
+ (`!s x:real^N.
+        conic s /\ x extreme_point_of s ==> x = vec 0`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM FACE_OF_SING] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP FACE_OF_CONIC) THEN
+  SIMP_TAC[conic; IN_SING; VECTOR_MUL_EQ_0; REAL_SUB_0; VECTOR_ARITH
+    `c % x:real^N = x <=> (c - &1) % x = vec 0`] THEN
+  MESON_TAC[REAL_ARITH `&0 <= &0 /\ ~(&1 = &0)`]);;
+
+let EXTREME_POINT_OF_CONVEX_HULL_INSERT = prove
+ (`!s a:real^N.
+        FINITE s /\ ~(a IN convex hull s)
+        ==> a extreme_point_of (convex hull (a INSERT s))`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `(a:real^N) IN s` THEN ASM_SIMP_TAC[HULL_INC] THEN
+  STRIP_TAC THEN MP_TAC(ISPECL [`{a:real^N}`; `(a:real^N) INSERT s`]
+    FACE_OF_CONVEX_HULLS) THEN
+  ASM_REWRITE_TAC[FINITE_INSERT; AFFINE_HULL_SING; CONVEX_HULL_SING] THEN
+  REWRITE_TAC[FACE_OF_SING] THEN DISCH_THEN MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[SET_RULE `~(a IN s) ==> a INSERT s DIFF {a} = s`] THEN
+  ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Facets.                                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("facet_of",(12, "right"));;
+
+let facet_of = new_definition
+ `f facet_of s <=> f face_of s /\ ~(f = {}) /\ aff_dim f = aff_dim s - &1`;;
+
+let FACET_OF_EMPTY = prove
+ (`!s. ~(s facet_of {})`,
+  REWRITE_TAC[facet_of; FACE_OF_EMPTY] THEN CONV_TAC TAUT);;
+
+let FACET_OF_REFL = prove
+ (`!s. ~(s facet_of s)`,
+  REWRITE_TAC[facet_of; INT_ARITH `~(x:int = x - &1)`]);;
+
+let FACET_OF_IMP_FACE_OF = prove
+ (`!f s. f facet_of s ==> f face_of s`,
+  SIMP_TAC[facet_of]);;
+
+let FACET_OF_IMP_SUBSET = prove
+ (`!f s. f facet_of s ==> f SUBSET s`,
+  SIMP_TAC[FACET_OF_IMP_FACE_OF; FACE_OF_IMP_SUBSET]);;
+
+let FACET_OF_IMP_PROPER = prove
+ (`!f s. f facet_of s ==> ~(f = {}) /\ ~(f = s)`,
+  REWRITE_TAC[facet_of] THEN MESON_TAC[INT_ARITH `~(x - &1:int = x)`]);;
+
+let FACET_OF_TRANSLATION_EQ = prove
+ (`!a:real^N f s.
+        (IMAGE (\x. a + x) f) facet_of (IMAGE (\x. a + x) s) <=> f facet_of s`,
+  REWRITE_TAC[facet_of] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [FACET_OF_TRANSLATION_EQ];;
+
+let FACET_OF_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N c s.
+      linear f /\ (!x y. f x = f y ==> x = y)
+      ==> ((IMAGE f c) facet_of (IMAGE f s) <=> c facet_of s)`,
+  REWRITE_TAC[facet_of] THEN GEOM_TRANSFORM_TAC[]);;
+
+add_linear_invariants [FACET_OF_LINEAR_IMAGE];;
+
+let HYPERPLANE_FACET_OF_HALFSPACE_LE = prove
+ (`!a:real^N b.
+        ~(a = vec 0) ==> {x | a dot x = b} facet_of {x | a dot x <= b}`,
+  SIMP_TAC[facet_of; HYPERPLANE_FACE_OF_HALFSPACE_LE; HYPERPLANE_EQ_EMPTY;
+           AFF_DIM_HYPERPLANE; AFF_DIM_HALFSPACE_LE]);;
+
+let HYPERPLANE_FACET_OF_HALFSPACE_GE = prove
+ (`!a:real^N b.
+        ~(a = vec 0) ==> {x | a dot x = b} facet_of {x | a dot x >= b}`,
+  SIMP_TAC[facet_of; HYPERPLANE_FACE_OF_HALFSPACE_GE; HYPERPLANE_EQ_EMPTY;
+           AFF_DIM_HYPERPLANE; AFF_DIM_HALFSPACE_GE]);;
+
+let FACET_OF_HALFSPACE_LE = prove
+ (`!f a:real^N b.
+        f facet_of {x | a dot x <= b} <=>
+        ~(a = vec 0) /\ f = {x | a dot x = b}`,
+  REPEAT GEN_TAC THEN
+  EQ_TAC THEN ASM_SIMP_TAC[HYPERPLANE_FACET_OF_HALFSPACE_LE] THEN
+  SIMP_TAC[AFF_DIM_HALFSPACE_LE; facet_of; FACE_OF_HALFSPACE_LE] THEN
+  REWRITE_TAC[TAUT `(p \/ q) /\ ~p /\ r <=> (~p /\ q) /\ r`] THEN
+  ASM_CASES_TAC `a:real^N = vec 0` THENL
+   [ASM_REWRITE_TAC[DOT_LZERO; SET_RULE
+     `{x | p} = if p then UNIV else {}`] THEN
+    REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[TAUT `~(~p /\ p)`]) THEN
+    TRY ASM_REAL_ARITH_TAC THEN
+    DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+    ASM_REWRITE_TAC[AFF_DIM_UNIV] THEN TRY INT_ARITH_TAC THEN ASM SET_TAC[];
+    DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+    ASM_REWRITE_TAC[AFF_DIM_HALFSPACE_LE] THEN INT_ARITH_TAC]);;
+
+let FACET_OF_HALFSPACE_GE = prove
+ (`!f a:real^N b.
+        f facet_of {x | a dot x >= b} <=>
+        ~(a = vec 0) /\ f = {x | a dot x = b}`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`f:real^N->bool`; `--a:real^N`; `--b:real`]
+        FACET_OF_HALFSPACE_LE) THEN
+  SIMP_TAC[DOT_LNEG; REAL_LE_NEG2; REAL_EQ_NEG2; VECTOR_NEG_EQ_0; real_ge]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Edges, i.e. faces of affine dimension 1.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("edge_of",(12, "right"));;
+
+let edge_of = new_definition
+ `e edge_of s <=> e face_of s /\ aff_dim e = &1`;;
+
+let EDGE_OF_TRANSLATION_EQ = prove
+ (`!a:real^N f s.
+        (IMAGE (\x. a + x) f) edge_of (IMAGE (\x. a + x) s) <=> f edge_of s`,
+  REWRITE_TAC[edge_of] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [EDGE_OF_TRANSLATION_EQ];;
+
+let EDGE_OF_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N c s.
+      linear f /\ (!x y. f x = f y ==> x = y)
+      ==> ((IMAGE f c) edge_of (IMAGE f s) <=> c edge_of s)`,
+  REWRITE_TAC[edge_of] THEN GEOM_TRANSFORM_TAC[]);;
+
+add_linear_invariants [EDGE_OF_LINEAR_IMAGE];;
+
+let EDGE_OF_IMP_SUBSET = prove
+ (`!s t. s edge_of t ==> s SUBSET t`,
+  SIMP_TAC[edge_of; face_of]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Existence of extreme points.                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let DIFFERENT_NORM_3_COLLINEAR_POINTS = prove
+ (`!a b x:real^N.
+     ~(x IN segment(a,b) /\ norm(a) = norm(b) /\ norm(x) = norm(b))`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = b` THEN
+  ASM_SIMP_TAC[SEGMENT_REFL; NOT_IN_EMPTY; OPEN_SEGMENT_ALT] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN DISCH_THEN
+   (CONJUNCTS_THEN2 (X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC) MP_TAC) THEN
+  ASM_REWRITE_TAC[NORM_EQ] THEN REWRITE_TAC[VECTOR_ARITH
+   `(x + y:real^N) dot (x + y) = x dot x + &2 * x dot y + y dot y`] THEN
+  REWRITE_TAC[DOT_LMUL; DOT_RMUL] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (ASSUME_TAC o SYM) MP_TAC) THEN
+  UNDISCH_TAC `~(a:real^N = b)` THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM VECTOR_SUB_EQ] THEN
+  REWRITE_TAC[GSYM DOT_EQ_0; VECTOR_ARITH
+   `(a - b:real^N) dot (a - b) = a dot a + b dot b - &2 * a dot b`] THEN
+  ASM_REWRITE_TAC[REAL_RING `a + a - &2 * ab = &0 <=> ab = a`] THEN
+  SIMP_TAC[REAL_RING
+   `(&1 - u) * (&1 - u) * a + &2 * (&1 - u) * u * x + u * u * a = a <=>
+    x = a \/ u = &0 \/ u = &1`] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let EXTREME_POINT_EXISTS_CONVEX = prove
+ (`!s:real^N->bool.
+        compact s /\ convex s /\ ~(s = {}) ==> ?x. x extreme_point_of s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `vec 0:real^N`] DISTANCE_ATTAINS_SUP) THEN
+  ASM_REWRITE_TAC[DIST_0; extreme_point_of] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x:real^N` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`a:real^N`; `b:real^N`; `x:real^N`]
+     DIFFERENT_NORM_3_COLLINEAR_POINTS) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `a <= x /\ b <= x /\ (a < x ==> x < x) /\ (b < x ==> x < x)
+    ==> a = b /\ x = b`) THEN
+  ASM_SIMP_TAC[] THEN
+  UNDISCH_TAC `(x:real^N) IN segment(a,b)` THEN
+  ASM_CASES_TAC `a:real^N = b` THEN
+  ASM_REWRITE_TAC[SEGMENT_REFL; NOT_IN_EMPTY] THEN
+  ASM_SIMP_TAC[OPEN_SEGMENT_ALT; IN_ELIM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC) THEN
+  CONJ_TAC THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th]) THEN
+  MATCH_MP_TAC NORM_TRIANGLE_LT THEN REWRITE_TAC[NORM_MUL] THEN
+  ASM_SIMP_TAC[REAL_ARITH
+   `&0 < u /\ u < &1 ==> abs u = u /\ abs(&1 - u) = &1 - u`] THEN
+  SUBST1_TAC(REAL_RING `norm(x:real^N) = (&1 - u) * norm x + u * norm x`) THENL
+   [MATCH_MP_TAC REAL_LTE_ADD2; MATCH_MP_TAC REAL_LET_ADD2] THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_LT_LMUL_EQ; REAL_SUB_LT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Krein-Milman, the weaker form as in more general spaces first.            *)
+(* ------------------------------------------------------------------------- *)
+
+let KREIN_MILMAN = prove
+ (`!s:real^N->bool.
+        convex s /\ compact s
+        ==> s = closure(convex hull {x | x extreme_point_of s})`,
+  GEN_TAC THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[extreme_point_of; NOT_IN_EMPTY; EMPTY_GSPEC] THEN
+    REWRITE_TAC[CONVEX_HULL_EMPTY; CLOSURE_EMPTY];
+    ALL_TAC] THEN
+  STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC CLOSURE_MINIMAL THEN ASM_SIMP_TAC[COMPACT_IMP_CLOSED] THEN
+    MATCH_MP_TAC HULL_MINIMAL THEN
+    ASM_SIMP_TAC[SUBSET; IN_ELIM_THM; extreme_point_of]] THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+  X_GEN_TAC `u:real^N` THEN DISCH_TAC THEN
+  MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`closure(convex hull {x:real^N | x extreme_point_of s})`;
+                 `u:real^N`] SEPARATING_HYPERPLANE_CLOSED_POINT) THEN
+  ASM_SIMP_TAC[CONVEX_CLOSURE; CLOSED_CLOSURE; CONVEX_CONVEX_HULL] THEN
+  REWRITE_TAC[NOT_EXISTS_THM; TAUT `~(a /\ b) <=> a ==> ~b`] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real`] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\x:real^N. a dot x`; `s:real^N->bool`]
+    CONTINUOUS_ATTAINS_INF) THEN
+  ASM_REWRITE_TAC[CONTINUOUS_ON_LIFT_DOT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `m:real^N` STRIP_ASSUME_TAC) THEN
+  ABBREV_TAC `t = {x:real^N | x IN s /\ a dot x = a dot m}` THEN
+  SUBGOAL_THEN `?x:real^N. x extreme_point_of t` (X_CHOOSE_TAC `v:real^N`)
+  THENL
+   [MATCH_MP_TAC EXTREME_POINT_EXISTS_CONVEX THEN
+    EXPAND_TAC "t" THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+    REWRITE_TAC[SET_RULE `{x | x IN s /\ P x} = s INTER {x | P x}`] THEN
+    ASM_SIMP_TAC[CONVEX_INTER; CONVEX_HYPERPLANE; COMPACT_INTER_CLOSED;
+                 CLOSED_HYPERPLANE] THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(v:real^N) extreme_point_of s` ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM FACE_OF_SING] THEN MATCH_MP_TAC FACE_OF_TRANS THEN
+    EXISTS_TAC `t:real^N->bool` THEN ASM_SIMP_TAC[FACE_OF_SING] THEN
+    EXPAND_TAC "t" THEN
+    REWRITE_TAC[SET_RULE `{x | x IN s /\ P x} = s INTER {x | P x}`] THEN
+    MATCH_MP_TAC FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE THEN
+    ASM_SIMP_TAC[real_ge];
+    SUBGOAL_THEN `(a:real^N) dot v > b` MP_TAC THENL
+     [FIRST_X_ASSUM MATCH_MP_TAC THEN
+      MATCH_MP_TAC(REWRITE_RULE[SUBSET] CLOSURE_SUBSET) THEN
+      MATCH_MP_TAC HULL_INC THEN ASM_REWRITE_TAC[IN_ELIM_THM];
+      ALL_TAC] THEN
+    REWRITE_TAC[real_gt; REAL_NOT_LT] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `(a:real^N) dot u` THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `(a:real^N) dot m` THEN
+    ASM_SIMP_TAC[] THEN
+    UNDISCH_TAC `(v:real^N) extreme_point_of t` THEN EXPAND_TAC "t" THEN
+    SIMP_TAC[extreme_point_of; IN_ELIM_THM; REAL_LE_REFL]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Now the sharper form.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let KREIN_MILMAN_MINKOWSKI = prove
+ (`!s:real^N->bool.
+        convex s /\ compact s
+        ==> s = convex hull {x | x extreme_point_of s}`,
+  SUBGOAL_THEN
+   `!s:real^N->bool.
+        convex s /\ compact s /\ (vec 0) IN s
+        ==> (vec 0) IN convex hull {x | x extreme_point_of s}`
+  ASSUME_TAC THENL
+   [GEN_TAC THEN WF_INDUCT_TAC `dim(s:real^N->bool)` THEN STRIP_TAC THEN
+    ASM_CASES_TAC `(vec 0:real^N) IN relative_interior s` THENL
+     [MP_TAC(ISPEC `s:real^N->bool` KREIN_MILMAN) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+      UNDISCH_TAC `(vec 0:real^N) IN relative_interior s` THEN
+      FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC
+       (LAND_CONV o RAND_CONV o RAND_CONV) [th]) THEN
+      SIMP_TAC[CONVEX_RELATIVE_INTERIOR_CLOSURE; CONVEX_CONVEX_HULL] THEN
+      MESON_TAC[RELATIVE_INTERIOR_SUBSET; SUBSET];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `~(relative_interior(s:real^N->bool) = {})` ASSUME_TAC THENL
+     [ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY] THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`s:real^N->bool`; `vec 0:real^N`]
+          SUPPORTING_HYPERPLANE_RELATIVE_BOUNDARY) THEN
+    ASM_REWRITE_TAC[DOT_RZERO] THEN
+    DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`s:real^N->bool`; `a:real^N`; `&0`]
+      FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE) THEN
+    ASM_REWRITE_TAC[real_ge] THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `(vec 0:real^N) IN convex hull
+          {x | x extreme_point_of (s INTER {x | a dot x = &0})}`
+    MP_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC(SET_RULE `s SUBSET t ==> x IN s ==> x IN t`) THEN
+      MATCH_MP_TAC HULL_MONO THEN REWRITE_TAC[SUBSET] THEN
+      GEN_TAC THEN REWRITE_TAC[IN_ELIM_THM; GSYM FACE_OF_SING] THEN
+      ASM_MESON_TAC[FACE_OF_TRANS]] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IMP_IMP]) THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[CONVEX_INTER; CONVEX_HYPERPLANE; COMPACT_INTER_CLOSED;
+                 CLOSED_HYPERPLANE; IN_INTER; IN_ELIM_THM; DOT_RZERO] THEN
+    REWRITE_TAC[GSYM NOT_LE] THEN DISCH_TAC THEN
+    MP_TAC(ISPECL
+     [`s INTER {x:real^N | a dot x = &0}`; `s:real^N->bool`]
+          DIM_EQ_SPAN) THEN
+    ASM_REWRITE_TAC[INTER_SUBSET; EXTENSION; NOT_FORALL_THM] 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 `c:real^N` THEN DISCH_TAC THEN
+    MATCH_MP_TAC(TAUT `b /\ ~a ==> ~(a <=> b)`) THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[SUBSET; SPAN_INC; RELATIVE_INTERIOR_SUBSET]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!x:real^N. x IN span (s INTER {x | a dot x = &0}) ==> a dot x = &0`
+     (fun th -> ASM_MESON_TAC[th; REAL_LT_REFL]) THEN
+    MATCH_MP_TAC SPAN_INDUCT THEN SIMP_TAC[IN_INTER; IN_ELIM_THM] THEN
+    REWRITE_TAC[subspace; DOT_RZERO; DOT_RADD; DOT_RMUL; IN_ELIM_THM] THEN
+    CONV_TAC REAL_RING;
+    ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET] THEN X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE (\x:real^N. --a + x) s`) THEN
+    ASM_SIMP_TAC[CONVEX_TRANSLATION_EQ; COMPACT_TRANSLATION_EQ] THEN
+    REWRITE_TAC[IN_IMAGE; VECTOR_ARITH `vec 0:real^N = --a + x <=> x = a`] THEN
+    ASM_REWRITE_TAC[UNWIND_THM2] THEN
+    REWRITE_TAC[EXTREME_POINTS_OF_TRANSLATION; CONVEX_HULL_TRANSLATION] THEN
+    REWRITE_TAC[IN_IMAGE; VECTOR_ARITH `vec 0:real^N = --a + x <=> x = a`] THEN
+    REWRITE_TAC[UNWIND_THM2];
+    MATCH_MP_TAC HULL_MINIMAL THEN
+    ASM_SIMP_TAC[SUBSET; extreme_point_of; IN_ELIM_THM]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Applying it to convex hulls of explicitly indicated finite sets.          *)
+(* ------------------------------------------------------------------------- *)
+
+let KREIN_MILMAN_POLYTOPE = prove
+ (`!s. FINITE s
+       ==> convex hull s =
+           convex hull {x | x extreme_point_of (convex hull s)}`,
+  SIMP_TAC[KREIN_MILMAN_MINKOWSKI; CONVEX_CONVEX_HULL;
+           COMPACT_CONVEX_HULL; FINITE_IMP_COMPACT]);;
+
+let EXTREME_POINTS_OF_CONVEX_HULL_EQ = prove
+ (`!s:real^N->bool.
+        compact s /\
+        (!t. t PSUBSET s ==> ~(convex hull t = convex hull s))
+        ==> {x | x extreme_point_of (convex hull s)} = s`,
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC
+   `{x:real^N | x extreme_point_of (convex hull s)}`) THEN
+  MATCH_MP_TAC(SET_RULE
+   `P /\ t SUBSET s ==> (t PSUBSET s ==> ~P) ==> t = s`) THEN
+  REWRITE_TAC[EXTREME_POINTS_OF_CONVEX_HULL] THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC KREIN_MILMAN_MINKOWSKI THEN
+  ASM_SIMP_TAC[CONVEX_CONVEX_HULL; COMPACT_CONVEX_HULL]);;
+
+let EXTREME_POINT_OF_CONVEX_HULL_EQ = prove
+ (`!s x:real^N.
+        compact s /\
+        (!t. t PSUBSET s ==> ~(convex hull t = convex hull s))
+        ==> (x extreme_point_of (convex hull s) <=> x IN s)`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP EXTREME_POINTS_OF_CONVEX_HULL_EQ) THEN
+  SET_TAC[]);;
+
+let EXTREME_POINT_OF_CONVEX_HULL_CONVEX_INDEPENDENT = prove
+ (`!s x:real^N.
+        compact s /\
+        (!a. a IN s ==> ~(a IN convex hull (s DELETE a)))
+        ==> (x extreme_point_of (convex hull s) <=> x IN s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EXTREME_POINT_OF_CONVEX_HULL_EQ THEN
+  ASM_REWRITE_TAC[PSUBSET_MEMBER] THEN X_GEN_TAC `t:real^N->bool` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_TAC `a:real^N`)) THEN
+  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `a:real^N`) THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `s SUBSET convex hull (s DELETE (a:real^N))` MP_TAC THENL
+   [ALL_TAC; ASM SET_TAC[]] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `convex hull t:real^N->bool` THEN
+  CONJ_TAC THENL
+   [ASM_REWRITE_TAC[HULL_SUBSET];
+    MATCH_MP_TAC HULL_MONO THEN ASM SET_TAC[]]);;
+
+let EXTREME_POINT_OF_CONVEX_HULL_AFFINE_INDEPENDENT = prove
+ (`!s x. ~affine_dependent s
+         ==> (x extreme_point_of (convex hull s) <=> x IN s)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC EXTREME_POINT_OF_CONVEX_HULL_CONVEX_INDEPENDENT THEN
+  ASM_SIMP_TAC[AFFINE_INDEPENDENT_IMP_FINITE; FINITE_IMP_COMPACT] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [affine_dependent]) THEN
+  MESON_TAC[SUBSET; CONVEX_HULL_SUBSET_AFFINE_HULL]);;
+
+let EXTREME_POINT_OF_CONVEX_HULL_2 = prove
+ (`!a b x. x extreme_point_of (convex hull {a,b}) <=> x = a \/ x = b`,
+  REWRITE_TAC[SET_RULE `x = a \/ x = b <=> x IN {a,b}`] THEN
+  SIMP_TAC[EXTREME_POINT_OF_CONVEX_HULL_AFFINE_INDEPENDENT;
+           AFFINE_INDEPENDENT_2]);;
+
+let EXTREME_POINT_OF_SEGMENT = prove
+ (`!a b x:real^N. x extreme_point_of segment[a,b] <=> x = a \/ x = b`,
+  REWRITE_TAC[SEGMENT_CONVEX_HULL; EXTREME_POINT_OF_CONVEX_HULL_2]);;
+
+let FACE_OF_CONVEX_HULL_SUBSET = prove
+ (`!s t:real^N->bool.
+        compact s /\ t face_of (convex hull s)
+        ==> ?s'. s' SUBSET s /\ t = convex hull s'`,
+  REPEAT STRIP_TAC THEN EXISTS_TAC `{x:real^N | x extreme_point_of t}` THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN CONJ_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MATCH_MP_TAC EXTREME_POINT_OF_CONVEX_HULL THEN
+    ASM_MESON_TAC[FACE_OF_SING; FACE_OF_TRANS];
+    MATCH_MP_TAC KREIN_MILMAN_MINKOWSKI THEN
+    ASM_MESON_TAC[FACE_OF_IMP_CONVEX; FACE_OF_IMP_COMPACT;
+                  COMPACT_CONVEX_HULL; CONVEX_CONVEX_HULL]]);;
+
+let FACE_OF_CONVEX_HULL_AFFINE_INDEPENDENT = prove
+ (`!s t:real^N->bool.
+        ~affine_dependent s
+        ==> (t face_of (convex hull s) <=>
+             ?c. c SUBSET s /\ t = convex hull c)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ASM_MESON_TAC[AFFINE_INDEPENDENT_IMP_FINITE; FINITE_IMP_COMPACT;
+                  FACE_OF_CONVEX_HULL_SUBSET];
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC FACE_OF_CONVEX_HULLS THEN
+    ASM_SIMP_TAC[AFFINE_INDEPENDENT_IMP_FINITE] THEN
+    MATCH_MP_TAC(SET_RULE `
+     !t. u SUBSET t /\ DISJOINT s t ==> DISJOINT s u`) THEN
+    EXISTS_TAC `affine hull (s DIFF c:real^N->bool)` THEN
+    REWRITE_TAC[CONVEX_HULL_SUBSET_AFFINE_HULL] THEN
+    MATCH_MP_TAC DISJOINT_AFFINE_HULL THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM SET_TAC[]]);;
+
+let FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT = prove
+ (`!s t:real^N->bool.
+        ~affine_dependent s
+        ==> (t facet_of (convex hull s) <=>
+             ~(t = {}) /\ ?u. u IN s /\ t = convex hull (s DELETE u))`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[facet_of; FACE_OF_CONVEX_HULL_AFFINE_INDEPENDENT] THEN
+  REWRITE_TAC[AFF_DIM_CONVEX_HULL] THEN EQ_TAC THENL
+   [DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `c:real^N->bool` MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC SUBST_ALL_TAC) THEN
+    UNDISCH_TAC
+     `aff_dim(convex hull c:real^N->bool) = aff_dim(s:real^N->bool) - &1` THEN
+    SUBGOAL_THEN `~affine_dependent(c:real^N->bool)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[AFFINE_INDEPENDENT_SUBSET];
+      ASM_SIMP_TAC[AFF_DIM_AFFINE_INDEPENDENT; AFF_DIM_CONVEX_HULL]] THEN
+    REWRITE_TAC[INT_ARITH `x - &1:int = y - &1 - &1 <=> y = x + &1`] THEN
+    REWRITE_TAC[INT_OF_NUM_ADD; INT_OF_NUM_EQ] THEN DISCH_TAC THEN
+    SUBGOAL_THEN `(s DIFF c:real^N->bool) HAS_SIZE 1` MP_TAC THENL
+     [ASM_SIMP_TAC[HAS_SIZE; FINITE_DIFF; CARD_DIFF;
+                   AFFINE_INDEPENDENT_IMP_FINITE] THEN ARITH_TAC;
+      CONV_TAC(LAND_CONV HAS_SIZE_CONV) THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real^N` THEN
+      DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE
+       `s DIFF t = {a} ==> t SUBSET s ==> s = a INSERT t`)) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST_ALL_TAC THEN
+      UNDISCH_TAC `CARD((u:real^N) INSERT c) = CARD c + 1` THEN
+      ASM_SIMP_TAC[CARD_CLAUSES; AFFINE_INDEPENDENT_IMP_FINITE] THEN
+      COND_CASES_TAC THENL [ARITH_TAC; DISCH_THEN(K ALL_TAC)] THEN
+      CONJ_TAC THENL [ALL_TAC; AP_TERM_TAC] THEN ASM SET_TAC[]];
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^N` MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC) THEN
+    CONJ_TAC THENL [MESON_TAC[DELETE_SUBSET]; ALL_TAC] THEN
+    ASM_SIMP_TAC[AFF_DIM_CONVEX_HULL] THEN
+    SUBGOAL_THEN `~affine_dependent(s DELETE (u:real^N))` ASSUME_TAC THENL
+     [ASM_MESON_TAC[AFFINE_INDEPENDENT_SUBSET; DELETE_SUBSET];
+      ASM_SIMP_TAC[AFF_DIM_AFFINE_INDEPENDENT]] THEN
+    REWRITE_TAC[INT_ARITH `x - &1:int = y - &1 - &1 <=> y = x + &1`] THEN
+    REWRITE_TAC[INT_OF_NUM_ADD; INT_OF_NUM_EQ] THEN
+    ASM_SIMP_TAC[CARD_DELETE; AFFINE_INDEPENDENT_IMP_FINITE] THEN
+    MATCH_MP_TAC(ARITH_RULE `~(s = 0) ==> s = s - 1 + 1`) THEN
+    ASM_SIMP_TAC[CARD_EQ_0; AFFINE_INDEPENDENT_IMP_FINITE] THEN
+    ASM SET_TAC[]]);;
+
+let FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT_ALT = prove
+ (`!s t:real^N->bool.
+        ~affine_dependent s
+        ==> (t facet_of (convex hull s) <=>
+             2 <= CARD s /\ ?u. u IN s /\ t = convex hull (s DELETE u))`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN AP_TERM_TAC THEN
+  GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `u:real^N` THEN
+  ASM_CASES_TAC `t = convex hull (s DELETE (u:real^N))` THEN
+  ASM_REWRITE_TAC[CONVEX_HULL_EQ_EMPTY] THEN
+  ASM_CASES_TAC `(u:real^N) IN s` THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `CARD s = 1 + CARD(s DELETE (u:real^N))` SUBST1_TAC THENL
+   [ASM_SIMP_TAC[CARD_DELETE; AFFINE_INDEPENDENT_IMP_FINITE] THEN
+    MATCH_MP_TAC(ARITH_RULE `~(s = 0) ==> s = 1 + s - 1`) THEN
+    ASM_SIMP_TAC[CARD_EQ_0; AFFINE_INDEPENDENT_IMP_FINITE] THEN
+    ASM SET_TAC[];
+    REWRITE_TAC[ARITH_RULE `2 <= 1 + x <=> ~(x = 0)`] THEN
+    ASM_SIMP_TAC[CARD_EQ_0; AFFINE_INDEPENDENT_IMP_FINITE; FINITE_DELETE]]);;
+
+let SEGMENT_FACE_OF = prove
+ (`!s a b:real^N.
+    segment[a,b] face_of s ==> a extreme_point_of s /\ b extreme_point_of s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM FACE_OF_SING] THEN
+  MATCH_MP_TAC FACE_OF_TRANS THEN EXISTS_TAC `segment[a:real^N,b]` THEN
+  ASM_REWRITE_TAC[] THEN REWRITE_TAC[FACE_OF_SING; EXTREME_POINT_OF_SEGMENT]);;
+
+let SEGMENT_EDGE_OF = prove
+ (`!s a b:real^N.
+        segment[a,b] edge_of s
+        ==> ~(a = b) /\ a extreme_point_of s /\ b extreme_point_of s`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN CONJ_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[edge_of; SEGMENT_FACE_OF]] THEN
+  POP_ASSUM MP_TAC THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  SIMP_TAC[SEGMENT_REFL; edge_of; AFF_DIM_SING] THEN INT_ARITH_TAC);;
+
+let COMPACT_CONVEX_COLLINEAR_SEGMENT = prove
+ (`!s:real^N->bool.
+        ~(s = {}) /\ compact s /\ convex s /\ collinear s
+        ==> ?a b. s = segment[a,b]`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `s:real^N->bool` KREIN_MILMAN_MINKOWSKI) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP COLLINEAR_EXTREME_POINTS) THEN
+  REWRITE_TAC[ARITH_RULE `n <= 2 <=> n = 0 \/ n = 1 \/ n = 2`] THEN
+  REWRITE_TAC[LEFT_OR_DISTRIB; GSYM HAS_SIZE] THEN
+  CONV_TAC(ONCE_DEPTH_CONV HAS_SIZE_CONV) THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[CONVEX_HULL_EMPTY; SEGMENT_CONVEX_HULL] THEN
+  DISCH_THEN SUBST1_TAC THEN MESON_TAC[SET_RULE `{a} = {a,a}`]);;
+
+let KREIN_MILMAN_RELATIVE_FRONTIER = prove
+ (`!s:real^N->bool.
+        convex s /\ compact s /\ ~(?a. s = {a})
+        ==> s = convex hull (s DIFF relative_interior s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `convex hull {x:real^N | x extreme_point_of s}` THEN
+    CONJ_TAC THENL
+     [ASM_SIMP_TAC[GSYM KREIN_MILMAN_MINKOWSKI; SUBSET_REFL];
+      MATCH_MP_TAC HULL_MONO THEN SIMP_TAC[SUBSET; IN_ELIM_THM; IN_DIFF] THEN
+      ASM_MESON_TAC[EXTREME_POINT_NOT_IN_RELATIVE_INTERIOR; extreme_point_of]];
+    MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `convex hull s:real^N->bool` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HULL_MONO THEN SET_TAC[];
+      ASM_SIMP_TAC[HULL_P; SUBSET_REFL]]]);;
+
+let KREIN_MILMAN_FRONTIER = prove
+ (`!s:real^N->bool.
+        convex s /\ compact s
+        ==> s = convex hull (frontier s)`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[frontier; COMPACT_IMP_CLOSED; CLOSURE_CLOSED] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `convex hull {x:real^N | x extreme_point_of s}` THEN
+    CONJ_TAC THENL
+     [ASM_SIMP_TAC[GSYM KREIN_MILMAN_MINKOWSKI; SUBSET_REFL];
+      MATCH_MP_TAC HULL_MONO THEN SIMP_TAC[SUBSET; IN_ELIM_THM; IN_DIFF] THEN
+      ASM_MESON_TAC[EXTREME_POINT_NOT_IN_INTERIOR; extreme_point_of]];
+    MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `convex hull s:real^N->bool` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HULL_MONO THEN SET_TAC[];
+      ASM_SIMP_TAC[HULL_P; SUBSET_REFL]]]);;
+
+let EXTREME_POINT_OF_CONVEX_HULL_INSERT_EQ = prove
+ (`!s a x:real^N.
+        FINITE s /\ ~(a IN affine hull s)
+        ==> (x extreme_point_of (convex hull (a INSERT s)) <=>
+             x = a \/ x extreme_point_of (convex hull s))`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM AFFINE_HULL_CONVEX_HULL] THEN
+  STRIP_TAC THEN ONCE_REWRITE_TAC[SET_RULE `a INSERT s = {a} UNION s`] THEN
+  ONCE_REWRITE_TAC[HULL_UNION_RIGHT] THEN
+  MP_TAC(ISPEC `convex hull s:real^N->bool` KREIN_MILMAN_MINKOWSKI) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[CONVEX_CONVEX_HULL; COMPACT_CONVEX_HULL; FINITE_IMP_COMPACT];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] FINITE_SUBSET)) THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `{x:real^N | x extreme_point_of convex hull s}`) THEN
+  REWRITE_TAC[EXTREME_POINTS_OF_CONVEX_HULL] THEN
+  ABBREV_TAC `v = {x:real^N | x extreme_point_of (convex hull s)}` THEN
+  DISCH_TAC THEN DISCH_THEN SUBST_ALL_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE (RAND_CONV o RAND_CONV)
+   [AFFINE_HULL_CONVEX_HULL]) THEN
+  ASM_CASES_TAC `(a:real^N) IN v` THEN ASM_SIMP_TAC[HULL_INC] THEN
+  STRIP_TAC THEN REWRITE_TAC[GSYM HULL_UNION_RIGHT] THEN
+  REWRITE_TAC[SET_RULE `{a} UNION s = a INSERT s`] THEN EQ_TAC THENL
+   [DISCH_THEN(MP_TAC o MATCH_MP EXTREME_POINT_OF_CONVEX_HULL) THEN
+    ASM SET_TAC[];
+    STRIP_TAC THENL
+     [ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC EXTREME_POINT_OF_CONVEX_HULL_INSERT THEN
+      ASM_MESON_TAC[CONVEX_HULL_SUBSET_AFFINE_HULL; SUBSET];
+      REWRITE_TAC[GSYM FACE_OF_SING] THEN
+      MATCH_MP_TAC FACE_OF_TRANS THEN
+      EXISTS_TAC `convex hull v:real^N->bool` THEN
+      ASM_REWRITE_TAC[FACE_OF_SING] THEN
+      MATCH_MP_TAC FACE_OF_CONVEX_HULLS THEN
+      ASM_SIMP_TAC[FINITE_INSERT; AFFINE_HULL_SING; CONVEX_HULL_SING;
+               SET_RULE `~(a IN s) ==> a INSERT s DIFF s = {a}`] THEN
+      ASM SET_TAC[]]]);;
+
+let FACE_OF_CONVEX_HULL_INSERT_EQ = prove
+ (`!f s a:real^N.
+        FINITE s /\ ~(a IN affine hull s)
+        ==> (f face_of (convex hull (a INSERT s)) <=>
+             f face_of (convex hull s) \/
+             ?f'. f' face_of (convex hull s) /\
+                  f = convex hull (a INSERT f'))`,
+  let lemma = prove
+   (`!a b c p:real^N u v w x.
+          x % p = u % a + v % b + w % c
+          ==> !s. u + v + w = x /\ ~(x = &0) /\ affine s /\
+                  a IN s /\ b IN s /\ c IN s
+                  ==> p IN s`,
+    REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o AP_TERM `(%) (inv x):real^N->real^N`) THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; VECTOR_MUL_LID] THEN
+    DISCH_THEN SUBST1_TAC THEN
+    REWRITE_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC] THEN
+    MATCH_MP_TAC(SET_RULE `!t. x IN t /\ t SUBSET s ==> x IN s`) THEN
+    EXISTS_TAC `affine hull {a:real^N,b,c}` THEN
+    ASM_SIMP_TAC[HULL_MINIMAL; INSERT_SUBSET; EMPTY_SUBSET] THEN
+    REWRITE_TAC[AFFINE_HULL_3; IN_ELIM_THM] THEN MAP_EVERY EXISTS_TAC
+     [`inv x * u:real`; `inv x * v:real`; `inv x * w:real`] THEN
+    REWRITE_TAC[] THEN UNDISCH_TAC `u + v + w:real = x` THEN
+    UNDISCH_TAC `~(x = &0)` THEN CONV_TAC REAL_FIELD) in
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [DISCH_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+      FACE_OF_CONVEX_HULL_SUBSET)) THEN
+    ASM_SIMP_TAC[COMPACT_INSERT; FINITE_IMP_COMPACT] THEN
+    DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN ASM_CASES_TAC `(a:real^N) IN t` THENL
+     [ALL_TAC;
+      DISJ1_TAC THEN MATCH_MP_TAC FACE_OF_SUBSET THEN
+      EXISTS_TAC `convex hull ((a:real^N) INSERT s)` THEN
+      ASM_REWRITE_TAC[] THEN CONJ_TAC THEN MATCH_MP_TAC HULL_MONO THEN
+      ASM SET_TAC[]] THEN
+    DISJ2_TAC THEN
+    EXISTS_TAC `(convex hull t) INTER (convex hull s):real^N->bool` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC FACE_OF_SUBSET THEN
+      EXISTS_TAC `convex hull ((a:real^N) INSERT s)` THEN
+      SIMP_TAC[INTER_SUBSET; HULL_MONO; SET_RULE `s SUBSET (a INSERT s)`] THEN
+      MATCH_MP_TAC FACE_OF_INTER THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC FACE_OF_CONVEX_HULL_INSERT THEN
+      ASM_REWRITE_TAC[FACE_OF_REFL_EQ; CONVEX_CONVEX_HULL];
+      MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THEN
+      MATCH_MP_TAC HULL_MINIMAL THEN REWRITE_TAC[CONVEX_CONVEX_HULL] THEN
+      ASM_SIMP_TAC[INSERT_SUBSET; HULL_INC; INTER_SUBSET] THEN
+      REWRITE_TAC[SUBSET] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC HULL_INC THEN
+      ASM_CASES_TAC `x:real^N = a` THEN ASM_REWRITE_TAC[IN_INSERT] THEN
+      REWRITE_TAC[IN_INTER] THEN CONJ_TAC THEN MATCH_MP_TAC HULL_INC THEN
+      ASM SET_TAC[]];
+    ALL_TAC] THEN
+  DISCH_THEN(DISJ_CASES_THEN ASSUME_TAC) THENL
+   [MATCH_MP_TAC FACE_OF_CONVEX_HULL_INSERT THEN ASM_REWRITE_TAC[];
+    FIRST_X_ASSUM(X_CHOOSE_THEN `f':real^N->bool` MP_TAC)] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC SUBST1_TAC) THEN
+  SPEC_TAC(`f':real^N->bool`,`f:real^N->bool`) THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [UNDISCH_TAC `(f:real^N->bool) face_of convex hull s` THEN
+    ASM_SIMP_TAC[FACE_OF_EMPTY; CONVEX_HULL_EMPTY; FACE_OF_REFL_EQ] THEN
+    REWRITE_TAC[CONVEX_CONVEX_HULL];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `f:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[CONVEX_HULL_SING; FACE_OF_SING] THEN
+    MATCH_MP_TAC EXTREME_POINT_OF_CONVEX_HULL_INSERT THEN
+    ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[CONVEX_HULL_SUBSET_AFFINE_HULL; SUBSET];
+    ALL_TAC] THEN
+  REWRITE_TAC[face_of; CONVEX_CONVEX_HULL] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HULL_MINIMAL THEN
+    SIMP_TAC[INSERT_SUBSET; HULL_INC; IN_INSERT; CONVEX_CONVEX_HULL] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `convex hull s:real^N->bool` THEN
+    ASM_SIMP_TAC[HULL_MONO; SET_RULE `s SUBSET (a INSERT s)`] THEN
+    ASM_MESON_TAC[FACE_OF_IMP_SUBSET];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[CONVEX_HULL_INSERT_ALT] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  X_GEN_TAC `ub:real` THEN STRIP_TAC THEN
+  X_GEN_TAC `b:real^N` THEN STRIP_TAC THEN
+  X_GEN_TAC `uc:real` THEN STRIP_TAC THEN
+  X_GEN_TAC `c:real^N` THEN STRIP_TAC THEN
+  X_GEN_TAC `ux:real` THEN STRIP_TAC THEN
+  X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [face_of]) THEN
+  SUBGOAL_THEN `convex hull f:real^N->bool = f` SUBST_ALL_TAC THENL
+   [ASM_MESON_TAC[CONVEX_HULL_EQ]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_SEGMENT]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_THEN `v:real` MP_TAC)) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `(&1 - ux) % a + ux % x:real^N =
+    (&1 - v) % ((&1 - ub) % a + ub % b) + v % ((&1 - uc) % a + uc % c) <=>
+    ((&1 - ux) - ((&1 - v) * (&1 - ub) + v * (&1 - uc))) % a +
+    (ux % x - (((&1 - v) * ub) % b + (v * uc) % c)) = vec 0`] THEN
+  ASM_CASES_TAC `&1 - ux - ((&1 - v) * (&1 - ub) + v * (&1 - uc)) = &0` THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_LID] THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP (REAL_RING
+     `(&1 - ux) - ((&1 - v) * (&1 - ub) + v * (&1 - uc)) = &0
+      ==> (&1 - v) * ub + v * uc = ux`)) THEN
+    ASM_CASES_TAC `uc = &0` THENL
+     [UNDISCH_THEN `uc = &0` SUBST_ALL_TAC THEN
+      FIRST_X_ASSUM(SUBST_ALL_TAC o MATCH_MP (REAL_ARITH
+       `a + v * &0 = b ==> b = a`)) THEN
+      REWRITE_TAC[REAL_MUL_RZERO; VECTOR_MUL_LZERO; VECTOR_ADD_RID] THEN
+      REWRITE_TAC[VECTOR_SUB_EQ; VECTOR_MUL_LCANCEL; REAL_ENTIRE] THEN
+      STRIP_TAC THENL
+       [ASM_REAL_ARITH_TAC;
+        ASM_MESON_TAC[VECTOR_MUL_LZERO];
+        ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+        REWRITE_TAC[IN_ELIM_THM] THEN
+        MAP_EVERY EXISTS_TAC [`&0`; `x:real^N`] THEN
+        ASM_REWRITE_TAC[] THEN CONV_TAC VECTOR_ARITH];
+      ALL_TAC] THEN
+    ASM_CASES_TAC `ub = &0` THENL
+     [UNDISCH_THEN `ub = &0` SUBST_ALL_TAC THEN
+      FIRST_X_ASSUM(SUBST_ALL_TAC o MATCH_MP (REAL_ARITH
+       `v * &0 + a = b ==> b = a`)) THEN
+      REWRITE_TAC[REAL_MUL_RZERO; VECTOR_MUL_LZERO; VECTOR_ADD_LID] THEN
+      REWRITE_TAC[VECTOR_SUB_EQ; VECTOR_MUL_LCANCEL; REAL_ENTIRE] THEN
+      STRIP_TAC THENL
+       [ASM_REAL_ARITH_TAC;
+        ASM_MESON_TAC[VECTOR_MUL_LZERO];
+        ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+        REWRITE_TAC[IN_ELIM_THM] THEN
+        MAP_EVERY EXISTS_TAC [`&0`; `x:real^N`] THEN
+        ASM_REWRITE_TAC[] THEN CONV_TAC VECTOR_ARITH];
+      ALL_TAC] THEN
+    DISCH_THEN(fun th ->
+      SUBGOAL_THEN
+       `(b:real^N) IN f /\ (c:real^N) IN f`
+      MP_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN MP_TAC th) THEN
+    ASM_CASES_TAC `ux = &0` THENL
+     [DISCH_THEN(K ALL_TAC) THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      EXISTS_TAC `x:real^N` THEN ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o MATCH_MP (REAL_ARITH
+       `&1 - ux - a = &0 ==> ux = &0 ==> ~(a < &1)`)) THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(TAUT `p ==> ~p ==> q`) THEN
+      MATCH_MP_TAC REAL_LTE_TRANS THEN
+      EXISTS_TAC `(&1 - v) * &1 + v * &1` THEN
+      CONJ_TAC THENL [ALL_TAC; REAL_ARITH_TAC] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `x <= y /\ w <= z /\ ~(x = y /\ w = z) ==> x + w < y + z`) THEN
+      ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_SUB_LT; REAL_EQ_MUL_LCANCEL] THEN
+      REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+      ASM_SIMP_TAC[REAL_SUB_0; REAL_LT_IMP_NE] THEN
+      REWRITE_TAC[REAL_ARITH `&1 - x = &1 <=> x = &0`] THEN
+      DISCH_THEN(CONJUNCTS_THEN SUBST_ALL_TAC) THEN
+      ASM_MESON_TAC[VECTOR_MUL_LZERO];
+      ALL_TAC] THEN
+    REWRITE_TAC[VECTOR_SUB_EQ] THEN ASM_CASES_TAC `c:real^N = b` THENL
+     [ASM_REWRITE_TAC[GSYM VECTOR_ADD_RDISTRIB; VECTOR_MUL_LCANCEL] THEN
+      ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    DISCH_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    EXISTS_TAC `x:real^N` THEN ASM_REWRITE_TAC[IN_SEGMENT] THEN
+    EXISTS_TAC `(v * uc) / ux:real` THEN
+    ASM_SIMP_TAC[REAL_LT_RDIV_EQ; REAL_LT_LDIV_EQ; REAL_ARITH
+     `&0 <= x /\ ~(x = &0) ==> &0 < x`] THEN
+    REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_LT_MUL THEN ASM_REAL_ARITH_TAC;
+      EXPAND_TAC "ux" THEN REWRITE_TAC[REAL_ARITH `b < a + b <=> &0 < a`] THEN
+      MATCH_MP_TAC REAL_LT_MUL THEN ASM_REAL_ARITH_TAC;
+      FIRST_X_ASSUM(MP_TAC o AP_TERM `(%) (inv ux) :real^N->real^N`) THEN
+      ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV] THEN
+      REWRITE_TAC[VECTOR_MUL_LID] THEN DISCH_THEN SUBST1_TAC THEN
+      REWRITE_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC] THEN
+      BINOP_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+      REWRITE_TAC[REAL_ARITH `inv u * v * uc:real = (v * uc) / u`] THEN
+      UNDISCH_TAC `(&1 - v) * ub + v * uc = ux` THEN
+      UNDISCH_TAC `~(ux = &0)` THEN CONV_TAC REAL_FIELD];
+    DISCH_THEN(MP_TAC o MATCH_MP (VECTOR_ARITH
+     `a + (b - c):real^N = vec 0 ==> a = c + --b`)) THEN
+    REWRITE_TAC[GSYM VECTOR_ADD_ASSOC; GSYM VECTOR_MUL_LNEG] THEN
+    DISCH_THEN(MP_TAC o SPEC `affine hull s:real^N->bool` o
+      MATCH_MP lemma) THEN
+    ASM_REWRITE_TAC[AFFINE_AFFINE_HULL] THEN
+    MATCH_MP_TAC(TAUT `p ==> ~p ==> q`) THEN
+    CONJ_TAC THENL [CONV_TAC REAL_RING; REPEAT CONJ_TAC] THEN
+    MATCH_MP_TAC(REWRITE_RULE[SUBSET] CONVEX_HULL_SUBSET_AFFINE_HULL) THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Polytopes.                                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let polytope = new_definition
+ `polytope s <=> ?v. FINITE v /\ s = convex hull v`;;
+
+let POLYTOPE_TRANSLATION_EQ = prove
+ (`!a s. polytope (IMAGE (\x:real^N. a + x) s) <=> polytope s`,
+  REWRITE_TAC[polytope] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [POLYTOPE_TRANSLATION_EQ];;
+
+let POLYTOPE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N p.
+        linear f /\ polytope p ==> polytope(IMAGE f p)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[polytope] THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^M->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `IMAGE (f:real^M->real^N) s` THEN
+  ASM_SIMP_TAC[CONVEX_HULL_LINEAR_IMAGE; FINITE_IMAGE]);;
+
+let POLYTOPE_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+        ==> (polytope (IMAGE f s) <=> polytope s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[polytope] THEN
+  MP_TAC(ISPEC `f:real^M->real^N` QUANTIFY_SURJECTION_THM) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)[th]) THEN
+  MP_TAC(end_itlist CONJ
+   (mapfilter (ISPEC `f:real^M->real^N`) (!invariant_under_linear))) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN ASM_REWRITE_TAC[]);;
+
+let POLYTOPE_EMPTY = prove
+ (`polytope {}`,
+  REWRITE_TAC[polytope] THEN MESON_TAC[FINITE_EMPTY; CONVEX_HULL_EMPTY]);;
+
+let POLYTOPE_NEGATIONS = prove
+ (`!s:real^N->bool. polytope s ==> polytope(IMAGE (--) s)`,
+  SIMP_TAC[POLYTOPE_LINEAR_IMAGE; LINEAR_NEGATION]);;
+
+let POLYTOPE_CONVEX_HULL = prove
+ (`!s. FINITE s ==> polytope(convex hull s)`,
+  REWRITE_TAC[polytope] THEN MESON_TAC[]);;
+
+let POLYTOPE_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        polytope s /\ polytope t ==> polytope(s PCROSS t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[polytope] THEN
+  MESON_TAC[CONVEX_HULL_PCROSS; FINITE_PCROSS]);;
+
+let POLYTOPE_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        polytope(s PCROSS t) <=>
+        s = {} \/ t = {} \/ polytope s /\ polytope t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; POLYTOPE_EMPTY] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; POLYTOPE_EMPTY] THEN
+  EQ_TAC THEN REWRITE_TAC[POLYTOPE_PCROSS] THEN REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL [`fstcart:real^(M,N)finite_sum->real^M`;
+                    `(s:real^M->bool) PCROSS (t:real^N->bool)`]
+       POLYTOPE_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_FSTCART];
+    MP_TAC(ISPECL [`sndcart:real^(M,N)finite_sum->real^N`;
+                   `(s:real^M->bool) PCROSS (t:real^N->bool)`]
+       POLYTOPE_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_SNDCART]] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; EXISTS_PASTECART; PASTECART_IN_PCROSS;
+              FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  ASM SET_TAC[]);;
+
+let FACE_OF_POLYTOPE_POLYTOPE = prove
+ (`!f s:real^N->bool. polytope s /\ f face_of s ==> polytope f`,
+  REWRITE_TAC[polytope] THEN
+  MESON_TAC[FINITE_SUBSET; FACE_OF_CONVEX_HULL_SUBSET; FINITE_IMP_COMPACT]);;
+
+let FINITE_POLYTOPE_FACES = prove
+ (`!s:real^N->bool. polytope s ==> FINITE {f | f face_of s}`,
+  GEN_TAC THEN REWRITE_TAC[polytope; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `v:real^N->bool` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC FINITE_SUBSET THEN
+  EXISTS_TAC `IMAGE ((hull) convex) {t:real^N->bool | t SUBSET v}` THEN
+  ASM_SIMP_TAC[FINITE_POWERSET; FINITE_IMAGE] THEN
+  GEN_REWRITE_TAC I [SUBSET] THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; IN_IMAGE; IN_ELIM_THM] THEN
+  ASM_MESON_TAC[FACE_OF_CONVEX_HULL_SUBSET; FINITE_IMP_COMPACT]);;
+
+let FINITE_POLYTOPE_FACETS = prove
+ (`!s:real^N->bool. polytope s ==> FINITE {f | f facet_of s}`,
+  REWRITE_TAC[facet_of] THEN ONCE_REWRITE_TAC[SET_RULE
+   `{x | P x /\ Q x} = {x | x IN {x | P x} /\ Q x}`] THEN
+  SIMP_TAC[FINITE_RESTRICT; FINITE_POLYTOPE_FACES]);;
+
+let POLYTOPE_SCALING = prove
+ (`!c s:real^N->bool. polytope s ==> polytope (IMAGE (\x. c % x) s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[polytope] THEN DISCH_THEN
+   (X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `IMAGE (\x:real^N. c % x) u` THEN
+  ASM_SIMP_TAC[CONVEX_HULL_SCALING; FINITE_IMAGE]);;
+
+let POLYTOPE_SCALING_EQ = prove
+ (`!c s:real^N->bool.
+     ~(c = &0) ==> (polytope (IMAGE (\x. c % x) s) <=> polytope s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REWRITE_TAC[POLYTOPE_SCALING] THEN
+  DISCH_THEN(MP_TAC o SPEC `inv c:real` o MATCH_MP POLYTOPE_SCALING) THEN
+  ASM_SIMP_TAC[GSYM IMAGE_o; o_DEF; VECTOR_MUL_ASSOC;
+               REAL_MUL_LINV; VECTOR_MUL_LID; IMAGE_ID]);;
+
+let POLYTOPE_SUMS = prove
+ (`!s t:real^N->bool.
+        polytope s /\ polytope t ==> polytope {x + y | x IN s /\ y IN t}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[polytope] THEN DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `v:real^N->bool` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `{x + y:real^N | x IN u /\ y IN v}` THEN
+  ASM_SIMP_TAC[FINITE_PRODUCT_DEPENDENT; CONVEX_HULL_SUMS]);;
+
+let POLYTOPE_IMP_COMPACT = prove
+ (`!s. polytope s ==> compact s`,
+  SIMP_TAC[polytope; LEFT_IMP_EXISTS_THM; COMPACT_CONVEX_HULL;
+           FINITE_IMP_COMPACT; FINITE_INSERT; FINITE_EMPTY]);;
+
+let POLYTOPE_IMP_CONVEX = prove
+ (`!s. polytope s ==> convex s`,
+  SIMP_TAC[polytope; LEFT_IMP_EXISTS_THM; CONVEX_CONVEX_HULL]);;
+
+let POLYTOPE_IMP_CLOSED = prove
+ (`!s. polytope s ==> closed s`,
+  SIMP_TAC[POLYTOPE_IMP_COMPACT; COMPACT_IMP_CLOSED]);;
+
+let POLYTOPE_IMP_BOUNDED = prove
+ (`!s. polytope s ==> bounded s`,
+  SIMP_TAC[POLYTOPE_IMP_COMPACT; COMPACT_IMP_BOUNDED]);;
+
+let POLYTOPE_INTERVAL = prove
+ (`!a b. polytope(interval[a,b])`,
+  REWRITE_TAC[polytope] THEN MESON_TAC[CLOSED_INTERVAL_AS_CONVEX_HULL]);;
+
+let POLYTOPE_SING = prove
+ (`!a. polytope {a}`,
+  MESON_TAC[POLYTOPE_INTERVAL; INTERVAL_SING]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Polyhedra.                                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let polyhedron = new_definition
+ `polyhedron s <=>
+        ?f. FINITE f /\
+            s = INTERS f /\
+            (!h. h IN f ==> ?a b. ~(a = vec 0) /\ h = {x | a dot x <= b})`;;
+
+let POLYHEDRON_INTER = prove
+ (`!s t:real^N->bool.
+        polyhedron s /\ polyhedron t ==> polyhedron (s INTER t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[polyhedron] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_TAC `f:(real^N->bool)->bool`)
+   (X_CHOOSE_TAC `g:(real^N->bool)->bool`)) THEN
+  EXISTS_TAC `f UNION g:(real^N->bool)->bool` THEN
+  ASM_REWRITE_TAC[SET_RULE `INTERS(f UNION g) = INTERS f INTER INTERS g`] THEN
+  REWRITE_TAC[FINITE_UNION; IN_UNION] THEN
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[]);;
+
+let POLYHEDRON_UNIV = prove
+ (`polyhedron(:real^N)`,
+  REWRITE_TAC[polyhedron] THEN EXISTS_TAC `{}:(real^N->bool)->bool` THEN
+  REWRITE_TAC[INTERS_0; NOT_IN_EMPTY; FINITE_RULES]);;
+
+let POLYHEDRON_POSITIVE_ORTHANT = prove
+ (`polyhedron {x:real^N | !i. 1 <= i /\ i <= dimindex(:N) ==> &0 <= x$i}`,
+  REWRITE_TAC[polyhedron] THEN
+  EXISTS_TAC `IMAGE (\i. {x:real^N | &0 <= x$i}) (1..dimindex(:N))` THEN
+  SIMP_TAC[FINITE_IMAGE; FINITE_NUMSEG; FORALL_IN_IMAGE] THEN CONJ_TAC THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN REWRITE_TAC[INTERS_IMAGE] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_NUMSEG];
+    X_GEN_TAC `k:num` THEN REWRITE_TAC[IN_NUMSEG] THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`--basis k:real^N`; `&0`] THEN
+    ASM_SIMP_TAC[VECTOR_NEG_EQ_0; DOT_LNEG; DOT_BASIS; BASIS_NONZERO] THEN
+    REWRITE_TAC[REAL_ARITH `--x <= &0 <=> &0 <= x`]]);;
+
+let POLYHEDRON_INTERS = prove
+ (`!f:(real^N->bool)->bool.
+        FINITE f /\ (!s. s IN f ==> polyhedron s) ==> polyhedron(INTERS f)`,
+  REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[NOT_IN_EMPTY; INTERS_0; POLYHEDRON_UNIV] THEN
+  ASM_SIMP_TAC[INTERS_INSERT; FORALL_IN_INSERT; POLYHEDRON_INTER]);;
+
+let POLYHEDRON_EMPTY = prove
+ (`polyhedron({}:real^N->bool)`,
+  REWRITE_TAC[polyhedron] THEN
+  EXISTS_TAC `{{x:real^N | basis 1 dot x <= -- &1},
+               {x | --(basis 1) dot x <= -- &1}}` THEN
+  REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY; INTERS_2; FORALL_IN_INSERT] THEN
+  REWRITE_TAC[NOT_IN_EMPTY; INTER; IN_ELIM_THM; DOT_LNEG] THEN
+  REWRITE_TAC[REAL_ARITH `~(a <= -- &1 /\ --a <= -- &1)`; EMPTY_GSPEC] THEN
+  CONJ_TAC THENL
+   [MAP_EVERY EXISTS_TAC [`basis 1:real^N`; `-- &1`];
+    MAP_EVERY EXISTS_TAC [`--(basis 1):real^N`; `-- &1`]] THEN
+  SIMP_TAC[VECTOR_NEG_EQ_0; BASIS_NONZERO; DOT_LNEG;
+           DIMINDEX_GE_1; LE_REFL]);;
+
+let POLYHEDRON_HALFSPACE_LE = prove
+ (`!a b. polyhedron {x:real^N | a dot x <= b}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THENL
+   [ASM_SIMP_TAC[DOT_LZERO; SET_RULE `{x | p} = if p then UNIV else {}`] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[POLYHEDRON_EMPTY; POLYHEDRON_UNIV];
+    REWRITE_TAC[polyhedron] THEN EXISTS_TAC `{{x:real^N | a dot x <= b}}` THEN
+    REWRITE_TAC[FINITE_SING; INTERS_1; FORALL_IN_INSERT; NOT_IN_EMPTY] THEN
+    MAP_EVERY EXISTS_TAC [`a:real^N`; `b:real`] THEN ASM_REWRITE_TAC[]]);;
+
+let POLYHEDRON_HALFSPACE_GE = prove
+ (`!a b. polyhedron {x:real^N | a dot x >= b}`,
+  REWRITE_TAC[REAL_ARITH `a:real >= b <=> --a <= --b`] THEN
+  REWRITE_TAC[GSYM DOT_LNEG; POLYHEDRON_HALFSPACE_LE]);;
+
+let POLYHEDRON_HYPERPLANE = prove
+ (`!a b. polyhedron {x:real^N | a dot x = b}`,
+  REWRITE_TAC[REAL_ARITH `x:real = b <=> x <= b /\ x >= b`] THEN
+  REWRITE_TAC[SET_RULE `{x | P x /\ Q x} = {x | P x} INTER {x | Q x}`] THEN
+  SIMP_TAC[POLYHEDRON_INTER; POLYHEDRON_HALFSPACE_LE;
+           POLYHEDRON_HALFSPACE_GE]);;
+
+let AFFINE_IMP_POLYHEDRON = prove
+ (`!s:real^N->bool. affine s ==> polyhedron s`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPEC `s:real^N->bool`
+    AFFINE_HULL_FINITE_INTERSECTION_HYPERPLANES) THEN
+  ASM_SIMP_TAC[HULL_P; RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+  MATCH_MP_TAC POLYHEDRON_INTERS THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `h:real^N->bool` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `h:real^N->bool`) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o CONJUNCT2) THEN
+  REWRITE_TAC[POLYHEDRON_HYPERPLANE]);;
+
+let POLYHEDRON_IMP_CLOSED = prove
+ (`!s:real^N->bool. polyhedron s ==> closed s`,
+  REWRITE_TAC[polyhedron; RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC CLOSED_INTERS THEN
+  X_GEN_TAC `h:real^N->bool` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `h:real^N->bool`) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o CONJUNCT2) THEN
+  REWRITE_TAC[CLOSED_HALFSPACE_LE]);;
+
+let POLYHEDRON_IMP_CONVEX = prove
+ (`!s:real^N->bool. polyhedron s ==> convex s`,
+  REWRITE_TAC[polyhedron; RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC CONVEX_INTERS THEN
+  X_GEN_TAC `h:real^N->bool` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `h:real^N->bool`) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o CONJUNCT2) THEN
+  REWRITE_TAC[CONVEX_HALFSPACE_LE]);;
+
+let POLYHEDRON_AFFINE_HULL = prove
+ (`!s. polyhedron(affine hull s)`,
+  SIMP_TAC[AFFINE_IMP_POLYHEDRON; AFFINE_AFFINE_HULL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Canonical polyedron representation making facial structure explicit.      *)
+(* ------------------------------------------------------------------------- *)
+
+let POLYHEDRON_INTER_AFFINE = prove
+ (`!s. polyhedron s <=>
+        ?f. FINITE f /\
+            s = (affine hull s) INTER (INTERS f) /\
+            (!h. h IN f
+                 ==> ?a b. ~(a = vec 0) /\ h = {x:real^N | a dot x <= b})`,
+  GEN_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[polyhedron] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    GEN_TAC THEN STRIP_TAC THEN REPEAT CONJ_TAC THEN
+    TRY(FIRST_ASSUM ACCEPT_TAC) THEN
+    MATCH_MP_TAC(SET_RULE `s = t /\ s SUBSET u ==> s = u INTER t`) THEN
+    REWRITE_TAC[HULL_SUBSET] THEN ASM_REWRITE_TAC[];
+    STRIP_TAC THEN ONCE_ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC POLYHEDRON_INTER THEN REWRITE_TAC[POLYHEDRON_AFFINE_HULL] THEN
+    MATCH_MP_TAC POLYHEDRON_INTERS THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[POLYHEDRON_HALFSPACE_LE]]);;
+
+let POLYHEDRON_INTER_AFFINE_PARALLEL = prove
+ (`!s:real^N->bool.
+        polyhedron s <=>
+        ?f. FINITE f /\
+            s = (affine hull s) INTER (INTERS f) /\
+            (!h. h IN f
+                 ==> ?a b. ~(a = vec 0) /\ h = {x:real^N | a dot x <= b} /\
+                           (!x. x IN affine hull s
+                                ==> (x + a) IN affine hull s))`,
+  GEN_TAC THEN REWRITE_TAC[POLYHEDRON_INTER_AFFINE] THEN EQ_TAC THENL
+   [ALL_TAC; MATCH_MP_TAC MONO_EXISTS THEN MESON_TAC[]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:(real^N->bool)->bool` MP_TAC) THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [DISCH_THEN(K ALL_TAC) THEN EXISTS_TAC `{}:(real^N->bool)->bool` THEN
+    ASM_SIMP_TAC[AFFINE_HULL_EMPTY; INTER_EMPTY; NOT_IN_EMPTY; FINITE_EMPTY];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THENL
+   [ASM_REWRITE_TAC[NOT_IN_EMPTY; INTERS_0; INTER_UNIV] THEN
+    DISCH_THEN(ASSUME_TAC o SYM o CONJUNCT2) THEN
+    EXISTS_TAC `{}:(real^N->bool)->bool` THEN
+    ASM_REWRITE_TAC[NOT_IN_EMPTY; INTERS_0; INTER_UNIV; FINITE_EMPTY];
+    ALL_TAC] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 (ASSUME_TAC o GSYM) MP_TAC)) THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV)
+   [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`] THEN
+  DISCH_THEN(ASSUME_TAC o GSYM) THEN
+  SUBGOAL_THEN
+   `!h. h IN f /\ ~(affine hull s SUBSET h)
+        ==> ?a' b'. ~(a' = vec 0) /\
+                  affine hull s INTER {x:real^N | a' dot x <= b'} =
+                  affine hull s INTER h /\
+                  !w. w IN affine hull s ==> (w + a') IN affine hull s`
+  MP_TAC THENL
+   [GEN_TAC THEN STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o SPEC `h:real^N->bool`) THEN
+    REWRITE_TAC[ASSUME `(h:real^N->bool) IN f`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC o GSYM) THEN
+    MP_TAC(ISPECL [`affine hull s:real^N->bool`;
+                   `(a:(real^N->bool)->real^N) h`;
+                   `(b:(real^N->bool)->real) h`]
+                AFFINE_PARALLEL_SLICE) THEN
+    REWRITE_TAC[AFFINE_AFFINE_HULL] THEN MATCH_MP_TAC(TAUT
+     `~p /\ ~q /\ (r ==> r') ==> (p \/ q \/ r ==> r')`) THEN
+    ASM_SIMP_TAC[] THEN CONJ_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+    DISCH_TAC THEN
+    UNDISCH_TAC `~(s:real^N->bool = {})` THEN
+    EXPAND_TAC "s" THEN REWRITE_TAC[GSYM INTERS_INSERT] THEN
+    MATCH_MP_TAC(SET_RULE
+     `!t. t SUBSET s /\ INTERS t = {} ==> INTERS s = {}`) THEN
+    EXISTS_TAC `{affine hull s,h:real^N->bool}` THEN
+    ASM_REWRITE_TAC[INTERS_2] THEN ASM SET_TAC[];
+    ALL_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
+  FIRST_X_ASSUM(K ALL_TAC o SPEC `{}:real^N->bool`) THEN
+  MAP_EVERY X_GEN_TAC
+    [`a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`] THEN
+  DISCH_TAC THEN
+  EXISTS_TAC `IMAGE (\h:real^N->bool. {x:real^N | a h dot x <= b h})
+                    {h | h IN f /\ ~(affine hull s SUBSET h)}` THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FINITE_RESTRICT; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    X_GEN_TAC `h:real^N->bool` THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC
+     [`(a:(real^N->bool)->real^N) h`; `(b:(real^N->bool)->real) h`] THEN
+    ASM_MESON_TAC[]] THEN
+  FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [GSYM th]) THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN X_GEN_TAC `x:real^N` THEN
+  REWRITE_TAC[INTERS_IMAGE; IN_INTER; IN_ELIM_THM] THEN
+  ASM_CASES_TAC `(x:real^N) IN affine hull s` THEN
+  ASM_REWRITE_TAC[IN_INTERS] THEN AP_TERM_TAC THEN ABS_TAC THEN
+  ASM SET_TAC[]);;
+
+let POLYHEDRON_INTER_AFFINE_PARALLEL_MINIMAL = prove
+ (`!s. polyhedron s <=>
+        ?f. FINITE f /\
+            s = (affine hull s) INTER (INTERS f) /\
+            (!h. h IN f
+                 ==> ?a b. ~(a = vec 0) /\ h = {x:real^N | a dot x <= b} /\
+                           (!x. x IN affine hull s
+                                ==> (x + a) IN affine hull s)) /\
+            !f'. f' PSUBSET f ==> s PSUBSET (affine hull s) INTER (INTERS f')`,
+  GEN_TAC THEN REWRITE_TAC[POLYHEDRON_INTER_AFFINE_PARALLEL] THEN
+  EQ_TAC THENL [ALL_TAC; MATCH_MP_TAC MONO_EXISTS THEN MESON_TAC[]] THEN
+  GEN_REWRITE_TAC LAND_CONV
+   [MESON[HAS_SIZE]
+     `(?f. FINITE f /\ P f) <=> (?n f. f HAS_SIZE n /\ P f)`] THEN
+  GEN_REWRITE_TAC LAND_CONV [num_WOP] THEN
+  DISCH_THEN(X_CHOOSE_THEN `n:num` (CONJUNCTS_THEN2 MP_TAC ASSUME_TAC)) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN REWRITE_TAC[HAS_SIZE] THEN
+  X_GEN_TAC `f:(real^N->bool)->bool` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN
+  X_GEN_TAC `f':(real^N->bool)->bool` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `CARD(f':(real^N->bool)->bool)`) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[CARD_PSUBSET]; ALL_TAC] THEN
+  REWRITE_TAC[NOT_EXISTS_THM; HAS_SIZE] THEN
+  DISCH_THEN(MP_TAC o SPEC `f':(real^N->bool)->bool`) THEN
+  MATCH_MP_TAC(TAUT `a /\ c /\ (~b ==> d) ==> ~(a /\ b /\ c) ==> d`) THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[PSUBSET; FINITE_SUBSET]; ALL_TAC] THEN
+  CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM SET_TAC[];
+    MATCH_MP_TAC(SET_RULE `s SUBSET t ==> ~(s = t) ==> s PSUBSET t`) THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [th]) THEN
+    ASM SET_TAC[]]);;
+
+let POLYHEDRON_INTER_AFFINE_MINIMAL = prove
+ (`!s. polyhedron s <=>
+        ?f. FINITE f /\
+            s = (affine hull s) INTER (INTERS f) /\
+            (!h. h IN f
+                 ==> ?a b. ~(a = vec 0) /\ h = {x:real^N | a dot x <= b}) /\
+            !f'. f' PSUBSET f ==> s PSUBSET (affine hull s) INTER (INTERS f')`,
+  GEN_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[POLYHEDRON_INTER_AFFINE_PARALLEL_MINIMAL];
+    REWRITE_TAC[POLYHEDRON_INTER_AFFINE]] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN MESON_TAC[]);;
+
+let RELATIVE_INTERIOR_POLYHEDRON_EXPLICIT = prove
+ (`!s:real^N->bool f a b.
+        FINITE f /\
+        s = affine hull s INTER INTERS f /\
+        (!h. h IN f ==> ~(a h = vec 0) /\ h = {x | a h dot x <= b h}) /\
+        (!f'. f' PSUBSET f ==> s PSUBSET affine hull s INTER INTERS f')
+        ==> relative_interior s =
+                {x | x IN s /\ !h. h IN f ==> a h dot x < b h}`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (ASSUME_TAC o SYM) STRIP_ASSUME_TAC) THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN EQ_TAC THENL
+   [ALL_TAC;
+    STRIP_TAC THEN ASM_REWRITE_TAC[RELATIVE_INTERIOR; IN_ELIM_THM] THEN
+    EXISTS_TAC `INTERS {interior h | (h:real^N->bool) IN f}` THEN
+    ASM_SIMP_TAC[SIMPLE_IMAGE; OPEN_INTERS; FINITE_IMAGE; OPEN_INTERIOR;
+                 FORALL_IN_IMAGE; IN_INTERS] THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `h:real^N->bool` THEN DISCH_TAC THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `h:real^N->bool`)) THEN
+      ASM_REWRITE_TAC[] THEN REPEAT DISCH_TAC THEN
+      FIRST_ASSUM(SUBST1_TAC o CONJUNCT2) THEN
+      ASM_SIMP_TAC[INTERIOR_HALFSPACE_LE; IN_ELIM_THM];
+      FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [SYM th]) THEN
+      MATCH_MP_TAC(SET_RULE
+       `(!s. s IN f ==> i s SUBSET s)
+        ==> INTERS (IMAGE i f) INTER t SUBSET t INTER INTERS f`) THEN
+      REWRITE_TAC[INTERIOR_SUBSET]]] THEN
+  DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_RELATIVE_INTERIOR]) THEN
+  DISCH_TAC THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `i:real^N->bool` THEN
+  DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `f DELETE (i:real^N->bool)`) THEN ANTS_TAC THENL
+   [ASM SET_TAC[];
+    REWRITE_TAC[PSUBSET_ALT; IN_INTER; IN_INTERS; IN_DELETE]] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `(a:(real^N->bool)->real^N) i dot z > b i` ASSUME_TAC THENL
+   [UNDISCH_TAC `~((z:real^N) IN s)` THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM) THEN REWRITE_TAC[IN_INTER; IN_INTERS] THEN
+    ASM_REWRITE_TAC[REAL_ARITH `a:real > b <=> ~(a <= b)`] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~(z:real^N = x)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?l. &0 < l /\ l < &1 /\ (l % z + (&1 - l) % x:real^N) IN s`
+  STRIP_ASSUME_TAC THENL
+   [FIRST_ASSUM(X_CHOOSE_THEN `e:real` MP_TAC o CONJUNCT2) THEN
+    REWRITE_TAC[SUBSET; IN_INTER; IN_BALL; dist] THEN STRIP_TAC THEN
+    EXISTS_TAC `min (&1 / &2) (e / &2 / norm(z - x:real^N))` THEN
+    REWRITE_TAC[REAL_MIN_LT; REAL_LT_MIN] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN CONJ_TAC THENL
+     [REWRITE_TAC[VECTOR_ARITH
+       `x - (l % z + (&1 - l) % x):real^N = --l % (z - x)`] THEN
+      REWRITE_TAC[NORM_MUL; REAL_ABS_NEG] THEN
+      ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `&0 < a /\ &0 < b /\ b < c ==> abs(min a b) < c`) THEN
+      ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+      REWRITE_TAC[REAL_LT_01; real_div; REAL_MUL_ASSOC] THEN
+      MATCH_MP_TAC REAL_LT_RMUL THEN
+      ASM_REWRITE_TAC[REAL_LT_INV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+      UNDISCH_TAC `&0 < e` THEN REAL_ARITH_TAC;
+      ONCE_REWRITE_TAC[VECTOR_ADD_SYM] THEN
+      MATCH_MP_TAC(REWRITE_RULE[AFFINE_ALT] AFFINE_AFFINE_HULL) THEN
+      ASM SET_TAC[]];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LT_RCANCEL_IMP THEN EXISTS_TAC `&1 - l` THEN
+  ASM_REWRITE_TAC[REAL_SUB_LT] THEN
+  REWRITE_TAC[REAL_ARITH `a < b * (&1 - l) <=> l * b + a < b`] THEN
+  MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC
+   `l * (a:(real^N->bool)->real^N) i dot z + (a i dot x) * (&1 - l)` THEN
+  ASM_SIMP_TAC[REAL_LT_RADD; REAL_LT_LMUL_EQ; GSYM real_gt] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a * (&1 - b) = (&1 - b) * a`] THEN
+  REWRITE_TAC[GSYM DOT_RMUL; GSYM DOT_RADD] THEN ASM SET_TAC[]);;
+
+let FACET_OF_POLYHEDRON_EXPLICIT = prove
+ (`!s:real^N->bool f a b.
+        FINITE f /\
+        s = affine hull s INTER INTERS f /\
+        (!h. h IN f ==> ~(a h = vec 0) /\ h = {x | a h dot x <= b h}) /\
+        (!f'. f' PSUBSET f ==> s PSUBSET affine hull s INTER INTERS f')
+        ==> !c. c facet_of s <=>
+                ?h. h IN f /\ c = s INTER {x | a h dot x = b h}`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[INTER_EMPTY; AFFINE_HULL_EMPTY; SET_RULE `~(s PSUBSET s)`;
+                    FACET_OF_EMPTY] THEN
+    ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THEN
+    ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `h:real^N->bool`) THEN DISCH_THEN
+     (MP_TAC o SPEC `f DELETE (h:real^N->bool)` o last o CONJUNCTS) THEN
+    ASM SET_TAC[];
+    STRIP_TAC] THEN
+  SUBGOAL_THEN `polyhedron(s:real^N->bool)` ASSUME_TAC THENL
+   [REWRITE_TAC[POLYHEDRON_INTER_AFFINE] THEN
+    REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP POLYHEDRON_IMP_CONVEX) THEN
+  SUBGOAL_THEN
+   `!h:real^N->bool.
+       h IN f ==> (s INTER {x:real^N | a h dot x = b h}) facet_of s`
+  (LABEL_TAC "face") THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[facet_of] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC POLYHEDRON_IMP_CONVEX THEN
+        REWRITE_TAC[POLYHEDRON_INTER_AFFINE] THEN
+        REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN ASM_MESON_TAC[];
+        X_GEN_TAC `x:real^N` THEN FIRST_X_ASSUM SUBST1_TAC THEN
+        REWRITE_TAC[IN_INTER; IN_INTERS] THEN
+        DISCH_THEN(MP_TAC o SPEC `h:real^N->bool` o CONJUNCT2) THEN
+        ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+        FIRST_X_ASSUM(MP_TAC o SPEC `h:real^N->bool`) THEN
+        ASM_REWRITE_TAC[] THEN ASM SET_TAC[]];
+      ALL_TAC] THEN
+    MP_TAC(ISPEC `s:real^N->bool` RELATIVE_INTERIOR_EQ_EMPTY) THEN
+    ASM_SIMP_TAC[] THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `x:real^N`) THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_RELATIVE_INTERIOR]) THEN
+    DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o SPEC `f DELETE (h:real^N->bool)`) THEN
+    ANTS_TAC THENL
+     [ASM SET_TAC[];
+      REWRITE_TAC[PSUBSET_ALT; IN_INTER; IN_INTERS; IN_DELETE]] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `z:real^N` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `(a:(real^N->bool)->real^N) h dot z > b h` ASSUME_TAC THENL
+     [UNDISCH_TAC `~((z:real^N) IN s)` THEN
+      FIRST_ASSUM(SUBST1_TAC o SYM) THEN
+      REWRITE_TAC[IN_INTER; IN_INTERS] THEN
+      ASM_REWRITE_TAC[REAL_ARITH `a:real > b <=> ~(a <= b)`] THEN
+      ASM SET_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `~(z:real^N = x)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[]; ALL_TAC] THEN
+    MP_TAC(ISPECL [`s:real^N->bool`; `f:(real^N->bool)->bool`;
+                   `a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`]
+           RELATIVE_INTERIOR_POLYHEDRON_EXPLICIT) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN
+    GEN_REWRITE_TAC LAND_CONV [EXTENSION] THEN
+    DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM] THEN
+    DISCH_THEN(fun th ->
+      MP_TAC(SPEC `h:real^N->bool` th) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_TAC THEN ASSUME_TAC th) THEN
+    SUBGOAL_THEN `(a:(real^N->bool)->real^N) h dot x < a h dot z`
+    ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    ABBREV_TAC `l = (b h - (a:(real^N->bool)->real^N) h dot x) /
+                    (a h dot z - a h dot x)` THEN
+    SUBGOAL_THEN `&0 < l /\ l < &1` STRIP_ASSUME_TAC THENL
+     [EXPAND_TAC "l" THEN
+      ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_LT_RDIV_EQ; REAL_SUB_LT] THEN
+      ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    ABBREV_TAC `w:real^N = (&1 - l) % x + l % z:real^N` THEN
+    SUBGOAL_THEN
+     `!i. i IN f /\ ~(i = h) ==> (a:(real^N->bool)->real^N) i dot w < b i`
+    ASSUME_TAC THENL
+     [X_GEN_TAC `i:real^N->bool` THEN STRIP_TAC THEN EXPAND_TAC "w" THEN
+      REWRITE_TAC[DOT_RADD; DOT_RMUL] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `(&1 - l) * x < (&1 - l) * z /\ l * y <= l * z
+        ==> (&1 - l) * x + l * y < z`) THEN
+      ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_LT_IMP_LE;
+                   REAL_LT_LMUL_EQ; REAL_SUB_LT] THEN
+      UNDISCH_TAC `!t:real^N->bool. t IN f /\ ~(t = h) ==> z IN t` THEN
+      DISCH_THEN(MP_TAC o SPEC `i:real^N->bool`) THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `(a:(real^N->bool)->real^N) h dot w = b h` ASSUME_TAC THENL
+     [EXPAND_TAC "w" THEN REWRITE_TAC[VECTOR_ARITH
+         `(&1 - l) % x + l % z:real^N = x + l % (z - x)`] THEN
+      EXPAND_TAC "l" THEN REWRITE_TAC[DOT_RADD; DOT_RSUB; DOT_RMUL] THEN
+      ASM_SIMP_TAC[REAL_DIV_RMUL; REAL_LT_IMP_NE; REAL_SUB_0] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN `(w:real^N) IN s` ASSUME_TAC THENL
+     [FIRST_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [th]) THEN
+      REWRITE_TAC[IN_INTER; IN_INTERS] THEN CONJ_TAC THENL
+       [EXPAND_TAC "w" THEN
+        MATCH_MP_TAC(REWRITE_RULE[AFFINE_ALT] AFFINE_AFFINE_HULL) THEN
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC HULL_INC THEN
+        ASM_MESON_TAC[RELATIVE_INTERIOR_SUBSET; SUBSET];
+        ALL_TAC] THEN
+      X_GEN_TAC `i:real^N->bool` THEN DISCH_TAC THEN
+      ASM_CASES_TAC `i:real^N->bool = h` THENL
+       [ASM SET_TAC[REAL_LE_REFL]; ALL_TAC] THEN
+      SUBGOAL_THEN `convex(i:real^N->bool)` MP_TAC THENL
+       [REPEAT(FIRST_X_ASSUM(MP_TAC o C MATCH_MP
+         (ASSUME `(i:real^N->bool) IN f`))) THEN
+        REPEAT(DISCH_THEN(fun th -> ONCE_REWRITE_TAC[th])) THEN
+        REWRITE_TAC[CONVEX_HALFSPACE_LE];
+        ALL_TAC] THEN
+      REWRITE_TAC[CONVEX_ALT] THEN EXPAND_TAC "w" THEN
+      DISCH_THEN MATCH_MP_TAC THEN
+      ASM_SIMP_TAC[] THEN FIRST_X_ASSUM(MP_TAC o CONJUNCT1) THEN
+      FIRST_ASSUM(fun t -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [t]) THEN
+      REWRITE_TAC[IN_INTER; IN_INTERS] THEN ASM_SIMP_TAC[REAL_LT_IMP_LE];
+      ALL_TAC] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+    SUBGOAL_THEN
+     `affine hull (s INTER {x | (a:(real^N->bool)->real^N) h dot x = b h}) =
+      (affine hull s) INTER {x | a h dot x = b h}`
+    SUBST1_TAC THENL
+     [ALL_TAC;
+      SIMP_TAC[AFF_DIM_AFFINE_INTER_HYPERPLANE; AFFINE_AFFINE_HULL] THEN
+      COND_CASES_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      COND_CASES_TAC THENL [ASM SET_TAC[REAL_LT_REFL]; REFL_TAC]] THEN
+    MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[SUBSET_INTER] THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC HULL_MONO THEN SET_TAC[];
+      MATCH_MP_TAC(SET_RULE
+       `s SUBSET affine hull t /\ affine hull t = t ==> s SUBSET t`) THEN
+      REWRITE_TAC[AFFINE_HULL_EQ; AFFINE_HYPERPLANE] THEN
+      MATCH_MP_TAC HULL_MONO THEN SET_TAC[];
+      ALL_TAC] THEN
+    REWRITE_TAC[SUBSET; IN_INTER; IN_ELIM_THM] THEN
+    X_GEN_TAC `y:real^N` THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `?t. &0 < t /\
+          !j. j IN f /\ ~(j:real^N->bool = h)
+              ==> t * (a j dot y - a j dot w) <= b j - a j dot (w:real^N)`
+    STRIP_ASSUME_TAC THENL
+     [ASM_CASES_TAC `f DELETE (h:real^N->bool) = {}` THENL
+       [ASM_REWRITE_TAC[GSYM IN_DELETE; NOT_IN_EMPTY] THEN
+        EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01];
+        ALL_TAC] THEN
+      EXISTS_TAC `inf (IMAGE
+       (\j. if &0 < a j dot y - a j dot (w:real^N)
+            then (b j - a j dot w) / (a j dot y - a j dot w)
+            else &1) (f DELETE (h:real^N->bool)))` THEN
+      MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+       [ASM_SIMP_TAC[REAL_LT_INF_FINITE; FINITE_IMAGE; FINITE_DELETE;
+                     IMAGE_EQ_EMPTY; FORALL_IN_IMAGE; IN_DELETE] THEN
+        ONCE_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+        ASM_SIMP_TAC[REAL_LT_DIV; REAL_SUB_LT; REAL_LT_01; COND_ID];
+        REWRITE_TAC[REAL_SUB_LT] THEN DISCH_TAC] THEN
+      X_GEN_TAC `j:real^N->bool` THEN STRIP_TAC THEN
+      ASM_CASES_TAC `a j dot (w:real^N) < a(j:real^N->bool) dot y` THENL
+       [ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; REAL_INF_LE_FINITE; REAL_SUB_LT;
+                     FINITE_IMAGE; FINITE_DELETE; IMAGE_EQ_EMPTY] THEN
+        REWRITE_TAC[EXISTS_IN_IMAGE] THEN EXISTS_TAC `j:real^N->bool` THEN
+        ASM_REWRITE_TAC[IN_DELETE; REAL_LE_REFL];
+        MATCH_MP_TAC(REAL_ARITH `&0 <= --x /\ &0 < y ==> x <= y`) THEN
+        ASM_SIMP_TAC[REAL_SUB_LT; GSYM REAL_MUL_RNEG; REAL_LE_MUL_EQ] THEN
+        ASM_REAL_ARITH_TAC];
+      ALL_TAC] THEN
+    ABBREV_TAC `c:real^N = (&1 - t) % w + t % y` THEN
+    SUBGOAL_THEN `y:real^N = (&1 - inv t) % w + inv(t) % c` SUBST1_TAC THENL
+     [EXPAND_TAC "c" THEN
+      REWRITE_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC] THEN
+      ASM_SIMP_TAC[REAL_MUL_LINV; REAL_LT_IMP_NZ;
+                REAL_FIELD `&0 < x ==> inv x * (&1 - x) = inv x - &1`] THEN
+      VECTOR_ARITH_TAC;
+      ALL_TAC] THEN
+    MATCH_MP_TAC(REWRITE_RULE[AFFINE_ALT] AFFINE_AFFINE_HULL) THEN
+    CONJ_TAC THEN MATCH_MP_TAC HULL_INC THEN
+    ASM_REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN
+    MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+     [EXPAND_TAC "c" THEN REWRITE_TAC[DOT_RADD; DOT_RMUL] THEN
+      ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RING;
+      DISCH_TAC] THEN
+    FIRST_ASSUM(fun t -> GEN_REWRITE_TAC RAND_CONV [t]) THEN
+    REWRITE_TAC[IN_INTER; IN_INTERS] THEN CONJ_TAC THENL
+     [EXPAND_TAC "c" THEN
+      MATCH_MP_TAC(REWRITE_RULE[AFFINE_ALT] AFFINE_AFFINE_HULL) THEN
+      ASM_SIMP_TAC[HULL_INC];
+      ALL_TAC] THEN
+    X_GEN_TAC `j:real^N->bool` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC o C MATCH_MP
+      (ASSUME `(j:real^N->bool) IN f`)) THEN
+    DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    ASM_CASES_TAC `j:real^N->bool = h` THEN ASM_SIMP_TAC[REAL_EQ_IMP_LE] THEN
+    EXPAND_TAC "c" THEN REWRITE_TAC[DOT_RADD; DOT_RMUL] THEN
+    REWRITE_TAC[REAL_ARITH
+     `(&1 - t) * x + t * y <= z <=> t * (y - x) <= z - x`] THEN
+    ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  X_GEN_TAC `c:real^N->bool` THEN EQ_TAC THENL
+   [ALL_TAC; STRIP_TAC THEN ASM_SIMP_TAC[]] THEN
+  REWRITE_TAC[facet_of] THEN STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP FACE_OF_IMP_CONVEX) THEN
+  SUBGOAL_THEN `~(relative_interior(c:real^N->bool) = {})` MP_TAC THENL
+   [ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY]; ALL_TAC] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+  DISCH_THEN(X_CHOOSE_TAC `x:real^N`) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `f:(real^N->bool)->bool`;
+                 `a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`]
+         RELATIVE_INTERIOR_POLYHEDRON_EXPLICIT) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [EXTENSION] THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[IN_ELIM_THM] THEN
+  SUBGOAL_THEN `~(c:real^N->bool = s)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[INT_ARITH`~(i:int = i - &1)`]; ALL_TAC] THEN
+  SUBGOAL_THEN `~((x:real^N) IN relative_interior s)` ASSUME_TAC THENL
+   [UNDISCH_TAC `~(c:real^N->bool = s)` THEN REWRITE_TAC[CONTRAPOS_THM] THEN
+    DISCH_TAC THEN MATCH_MP_TAC FACE_OF_EQ THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_SIMP_TAC[FACE_OF_REFL] THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(x:real^N) IN s` MP_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o REWRITE_RULE[SUBSET] o MATCH_MP
+       FACE_OF_IMP_SUBSET) THEN
+    ASM_SIMP_TAC[REWRITE_RULE[SUBSET] RELATIVE_INTERIOR_SUBSET];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[] THEN DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  FIRST_ASSUM(fun t -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [t]) THEN
+  REWRITE_TAC[IN_INTER; IN_INTERS] THEN STRIP_TAC THEN
+  REWRITE_TAC[NOT_FORALL_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `i:real^N->bool` THEN REWRITE_TAC[NOT_IMP] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `(a:(real^N->bool)->real^N) i dot x = b i` ASSUME_TAC THENL
+   [MATCH_MP_TAC(REAL_ARITH `x <= y /\ ~(x < y) ==> x = y`) THEN
+    ASM_REWRITE_TAC[] THEN UNDISCH_THEN
+     `!t:real^N->bool. t IN f ==> x IN t` (MP_TAC o SPEC `i:real^N->bool`) THEN
+    ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MP_TAC o CONJUNCT2 o C MATCH_MP
+     (ASSUME `(i:real^N->bool) IN f`)) THEN SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `c SUBSET (s INTER {x:real^N | a(i:real^N->bool) dot x = b i})`
+  ASSUME_TAC THENL
+   [MATCH_MP_TAC SUBSET_OF_FACE_OF THEN EXISTS_TAC `s:real^N->bool` THEN
+    ASM_SIMP_TAC[FACE_OF_IMP_SUBSET] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[facet_of]) THEN ASM_SIMP_TAC[] THEN
+    REWRITE_TAC[DISJOINT; GSYM MEMBER_NOT_EMPTY] THEN
+    EXISTS_TAC `x:real^N` THEN ASM_REWRITE_TAC[IN_INTER; IN_ELIM_THM];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `c face_of (s INTER {x:real^N | a(i:real^N->bool) dot x = b i})`
+  ASSUME_TAC THENL
+   [MP_TAC(ISPECL [`c:real^N->bool`; `s:real^N->bool`;
+                   `s INTER {x:real^N | a(i:real^N->bool) dot x = b i}`]
+                FACE_OF_FACE) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[facet_of]) THEN ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `aff_dim(c:real^N->bool) <
+    aff_dim(s INTER {x:real^N | a(i:real^N->bool) dot x = b i})`
+  MP_TAC THENL
+   [MATCH_MP_TAC FACE_OF_AFF_DIM_LT THEN
+    ASM_SIMP_TAC[CONVEX_INTER; CONVEX_HYPERPLANE];
+    RULE_ASSUM_TAC(REWRITE_RULE[facet_of]) THEN ASM_SIMP_TAC[INT_LT_REFL]]);;
+
+let FACE_OF_POLYHEDRON_SUBSET_EXPLICIT = prove
+ (`!s:real^N->bool f a b.
+        FINITE f /\
+        s = affine hull s INTER INTERS f /\
+        (!h. h IN f ==> ~(a h = vec 0) /\ h = {x | a h dot x <= b h}) /\
+        (!f'. f' PSUBSET f ==> s PSUBSET affine hull s INTER INTERS f')
+        ==> !c. c face_of s /\ ~(c = {}) /\ ~(c = s)
+                ==> ?h. h IN f /\ c SUBSET (s INTER {x | a h dot x = b h})`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THENL
+   [DISCH_THEN(MP_TAC o SYM o CONJUNCT1 o CONJUNCT2) THEN
+    ASM_REWRITE_TAC[INTERS_0; INTER_UNIV; AFFINE_HULL_EQ] THEN
+    MESON_TAC[FACE_OF_AFFINE_TRIVIAL];
+    ALL_TAC] THEN
+  DISCH_THEN(fun th -> STRIP_ASSUME_TAC th THEN MP_TAC th) THEN
+  DISCH_THEN(ASSUME_TAC o MATCH_MP FACET_OF_POLYHEDRON_EXPLICIT) THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP FACE_OF_IMP_CONVEX) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP FACE_OF_IMP_SUBSET) THEN
+  SUBGOAL_THEN `polyhedron(s:real^N->bool)` ASSUME_TAC THENL
+   [REWRITE_TAC[POLYHEDRON_INTER_AFFINE] THEN
+    REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP POLYHEDRON_IMP_CONVEX) THEN
+  SUBGOAL_THEN
+   `!h:real^N->bool.
+        h IN f ==> (s INTER {x:real^N | a h dot x = b h}) face_of s`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE THEN CONJ_TAC THENL
+     [MATCH_MP_TAC POLYHEDRON_IMP_CONVEX THEN
+      REWRITE_TAC[POLYHEDRON_INTER_AFFINE] THEN
+      REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN ASM_MESON_TAC[];
+      X_GEN_TAC `x:real^N` THEN FIRST_X_ASSUM SUBST1_TAC THEN
+      REWRITE_TAC[IN_INTER; IN_INTERS] THEN
+      DISCH_THEN(MP_TAC o SPEC `h:real^N->bool` o CONJUNCT2) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `h:real^N->bool`) THEN
+      ASM_REWRITE_TAC[] THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~(relative_interior(c:real^N->bool) = {})` MP_TAC THENL
+   [ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY]; ALL_TAC] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+  DISCH_THEN(X_CHOOSE_TAC `x:real^N`) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `f:(real^N->bool)->bool`;
+                 `a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`]
+         RELATIVE_INTERIOR_POLYHEDRON_EXPLICIT) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [EXTENSION] THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[IN_ELIM_THM] THEN
+  SUBGOAL_THEN `~((x:real^N) IN relative_interior s)` ASSUME_TAC THENL
+   [UNDISCH_TAC `~(c:real^N->bool = s)` THEN REWRITE_TAC[CONTRAPOS_THM] THEN
+    DISCH_TAC THEN MATCH_MP_TAC FACE_OF_EQ THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_SIMP_TAC[FACE_OF_REFL] THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(x:real^N) IN s` MP_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o REWRITE_RULE[SUBSET] o MATCH_MP
+       FACE_OF_IMP_SUBSET) THEN
+    ASM_SIMP_TAC[REWRITE_RULE[SUBSET] RELATIVE_INTERIOR_SUBSET];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[] THEN DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  FIRST_ASSUM(fun t -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [t]) THEN
+  REWRITE_TAC[IN_INTER; IN_INTERS] THEN STRIP_TAC THEN
+  REWRITE_TAC[NOT_FORALL_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `i:real^N->bool` THEN REWRITE_TAC[NOT_IMP] THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `(a:(real^N->bool)->real^N) i dot x = b i` ASSUME_TAC THENL
+   [MATCH_MP_TAC(REAL_ARITH `x <= y /\ ~(x < y) ==> x = y`) THEN
+    ASM_REWRITE_TAC[] THEN UNDISCH_THEN
+     `!t:real^N->bool. t IN f ==> x IN t` (MP_TAC o SPEC `i:real^N->bool`) THEN
+    ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MP_TAC o CONJUNCT2 o C MATCH_MP
+     (ASSUME `(i:real^N->bool) IN f`)) THEN SET_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC SUBSET_OF_FACE_OF THEN EXISTS_TAC `s:real^N->bool` THEN
+  ASM_SIMP_TAC[FACE_OF_IMP_SUBSET] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[facet_of]) THEN ASM_SIMP_TAC[] THEN
+  REWRITE_TAC[DISJOINT; GSYM MEMBER_NOT_EMPTY] THEN
+  EXISTS_TAC `x:real^N` THEN ASM_REWRITE_TAC[IN_INTER; IN_ELIM_THM]);;
+
+let FACE_OF_POLYHEDRON_EXPLICIT = prove
+ (`!s:real^N->bool f a b.
+        FINITE f /\
+        s = affine hull s INTER INTERS f /\
+        (!h. h IN f ==> ~(a h = vec 0) /\ h = {x | a h dot x <= b h}) /\
+        (!f'. f' PSUBSET f ==> s PSUBSET affine hull s INTER INTERS f')
+        ==> !c. c face_of s /\ ~(c = {}) /\ ~(c = s)
+                ==> c = INTERS {s INTER {x | a h dot x = b h} |h|
+                                h IN f /\
+                                c SUBSET (s INTER {x | a h dot x = b h})}`,
+  let lemma = prove
+   (`!t s. (!a. P a ==> t SUBSET s INTER INTERS {f x | P x})
+           ==> t SUBSET INTERS {s INTER f x | P x}`,
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    REWRITE_TAC[INTERS_IMAGE] THEN SET_TAC[]) in
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(fun th -> STRIP_ASSUME_TAC th THEN MP_TAC th) THEN
+  DISCH_THEN(ASSUME_TAC o MATCH_MP FACET_OF_POLYHEDRON_EXPLICIT) THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP FACE_OF_IMP_CONVEX) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP FACE_OF_IMP_SUBSET) THEN
+  SUBGOAL_THEN `polyhedron(s:real^N->bool)` ASSUME_TAC THENL
+   [REWRITE_TAC[POLYHEDRON_INTER_AFFINE] THEN
+    REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP POLYHEDRON_IMP_CONVEX) THEN
+  SUBGOAL_THEN
+   `!h:real^N->bool.
+        h IN f ==> (s INTER {x:real^N | a h dot x = b h}) face_of s`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE THEN CONJ_TAC THENL
+     [MATCH_MP_TAC POLYHEDRON_IMP_CONVEX THEN
+      REWRITE_TAC[POLYHEDRON_INTER_AFFINE] THEN
+      REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN ASM_MESON_TAC[];
+      X_GEN_TAC `x:real^N` THEN FIRST_X_ASSUM SUBST1_TAC THEN
+      REWRITE_TAC[IN_INTER; IN_INTERS] THEN
+      DISCH_THEN(MP_TAC o SPEC `h:real^N->bool` o CONJUNCT2) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `h:real^N->bool`) THEN
+      ASM_REWRITE_TAC[] THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~(relative_interior(c:real^N->bool) = {})` MP_TAC THENL
+   [ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY]; ALL_TAC] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `z:real^N` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `(z:real^N) IN s` ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o REWRITE_RULE[SUBSET]) THEN
+    MATCH_MP_TAC(REWRITE_RULE[SUBSET] RELATIVE_INTERIOR_SUBSET) THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC FACE_OF_EQ THEN EXISTS_TAC `s:real^N->bool` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC FACE_OF_INTERS THEN ASM_SIMP_TAC[FORALL_IN_GSPEC] THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN REWRITE_TAC[IMAGE_EQ_EMPTY] THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+    MP_TAC(ISPECL [`s:real^N->bool`; `f:(real^N->bool)->bool`;
+                   `a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`]
+         FACE_OF_POLYHEDRON_SUBSET_EXPLICIT) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL[FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN
+    DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `{s INTER {x | a(h:real^N->bool) dot x = b h} |h|
+     h IN f /\ c SUBSET (s INTER {x:real^N | a h dot x = b h})} =
+    {s INTER {x | a(h:real^N->bool) dot x = b h} |h|
+     h IN f /\ z IN s INTER {x:real^N | a h dot x = b h}}`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `(!x. P x <=> Q x) ==> {f x | P x} = {f x | Q x}`) THEN
+    X_GEN_TAC `h:real^N->bool` THEN EQ_TAC THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o REWRITE_RULE[SUBSET]) THEN
+      MATCH_MP_TAC(REWRITE_RULE[SUBSET] RELATIVE_INTERIOR_SUBSET) THEN
+      ASM_REWRITE_TAC[];
+      MATCH_MP_TAC SUBSET_OF_FACE_OF THEN EXISTS_TAC `s:real^N->bool` THEN
+      ASM_SIMP_TAC[] THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  REWRITE_TAC[DISJOINT; GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+  EXISTS_TAC `z:real^N` THEN ASM_REWRITE_TAC[IN_ELIM_THM] THEN
+  SUBGOAL_THEN
+   `?e. &0 < e /\ !h. h IN f /\ a(h:real^N->bool) dot z < b h
+                      ==> ball(z,e) SUBSET {w:real^N | a h dot w < b h}`
+  (CHOOSE_THEN (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "*"))) THENL
+   [REWRITE_TAC[SET_RULE
+     `(!h. P h ==> s SUBSET t h) <=> s SUBSET INTERS (IMAGE t {h | P h})`] THEN
+    MATCH_MP_TAC(MESON[OPEN_CONTAINS_BALL]
+     `open s /\ x IN s ==> ?e. &0 < e /\ ball(x,e) SUBSET s`) THEN
+    SIMP_TAC[IN_INTERS; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+    MATCH_MP_TAC OPEN_INTERS THEN
+    ASM_SIMP_TAC[FORALL_IN_IMAGE; FINITE_IMAGE; FINITE_RESTRICT] THEN
+    REWRITE_TAC[OPEN_HALFSPACE_LT];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[IN_RELATIVE_INTERIOR] THEN
+  ASM_SIMP_TAC[IN_INTERS; FORALL_IN_GSPEC; IN_ELIM_THM; IN_INTER] THEN
+  EXISTS_TAC `e:real` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC lemma THEN X_GEN_TAC `i:real^N->bool` THEN STRIP_TAC THEN
+  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC (RAND_CONV o LAND_CONV) [th]) THEN
+  MATCH_MP_TAC(SET_RULE
+   `ae SUBSET as /\ ae SUBSET hs /\
+    b INTER hs SUBSET fs
+    ==> (b INTER ae) SUBSET (as INTER fs) INTER hs`) THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC HULL_MONO THEN
+    REWRITE_TAC[SUBSET; IN_INTERS; FORALL_IN_GSPEC] THEN ASM SET_TAC[];
+    SIMP_TAC[SET_RULE `s SUBSET INTERS f <=> !t. t IN f ==> s SUBSET t`] THEN
+    REWRITE_TAC[FORALL_IN_GSPEC] THEN X_GEN_TAC `j:real^N->bool` THEN
+    STRIP_TAC THEN MATCH_MP_TAC HULL_MINIMAL THEN
+    REWRITE_TAC[AFFINE_HYPERPLANE] THEN
+    REWRITE_TAC[SUBSET; IN_INTERS; FORALL_IN_GSPEC] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[SET_RULE `s SUBSET INTERS f <=> !t. t IN f ==> s SUBSET t`] THEN
+  X_GEN_TAC `j:real^N->bool` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `(a:(real^N->bool)->real^N) j dot z <= b j` MP_TAC THENL
+   [ASM SET_TAC[]; REWRITE_TAC[REAL_LE_LT]] THEN
+  STRIP_TAC THENL [ASM SET_TAC[REAL_LT_IMP_LE]; ALL_TAC] THEN
+  MATCH_MP_TAC(SET_RULE
+  `(?s. s IN f /\ s SUBSET t) ==> u INTER INTERS f SUBSET t`) THEN
+  REWRITE_TAC[EXISTS_IN_GSPEC] THEN EXISTS_TAC `j:real^N->bool` THEN
+  ASM SET_TAC[REAL_LE_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More general corollaries from the explicit representation.                *)
+(* ------------------------------------------------------------------------- *)
+
+let FACET_OF_POLYHEDRON = prove
+ (`!s:real^N->bool c.
+        polyhedron s /\ c facet_of s
+        ==> ?a b. ~(a = vec 0) /\
+                  s SUBSET {x | a dot x <= b} /\
+                  c = s INTER {x | a dot x = b}`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM
+   (MP_TAC o GEN_REWRITE_RULE I [POLYHEDRON_INTER_AFFINE_MINIMAL]) THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV)
+   [RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  SIMP_TAC[LEFT_IMP_EXISTS_THM; RIGHT_AND_EXISTS_THM; LEFT_AND_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`f:(real^N->bool)->bool`; `a:(real^N->bool)->real^N`;
+    `b:(real^N->bool)->real`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `f:(real^N->bool)->bool`;
+                 `a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`]
+        FACET_OF_POLYHEDRON_EXPLICIT) THEN
+  ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `c:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `i:real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(a:(real^N->bool)->real^N) i` THEN
+  EXISTS_TAC `(b:(real^N->bool)->real) i` THEN ASM_SIMP_TAC[] THEN
+  FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [th]) THEN
+  MATCH_MP_TAC(SET_RULE `t SUBSET u ==> (s INTER t) SUBSET u`) THEN
+  MATCH_MP_TAC(SET_RULE `t IN f ==> INTERS f SUBSET t`) THEN ASM_MESON_TAC[]);;
+
+let FACE_OF_POLYHEDRON = prove
+ (`!s:real^N->bool c.
+        polyhedron s /\ c face_of s /\ ~(c = {}) /\ ~(c = s)
+        ==> c = INTERS {f | f facet_of s /\ c SUBSET f}`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM
+   (MP_TAC o GEN_REWRITE_RULE I [POLYHEDRON_INTER_AFFINE_MINIMAL]) THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  SIMP_TAC[LEFT_IMP_EXISTS_THM; RIGHT_AND_EXISTS_THM; LEFT_AND_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`f:(real^N->bool)->bool`; `a:(real^N->bool)->real^N`;
+    `b:(real^N->bool)->real`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `f:(real^N->bool)->bool`;
+                 `a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`]
+         FACET_OF_POLYHEDRON_EXPLICIT) THEN
+  ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `f:(real^N->bool)->bool`;
+                 `a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`]
+         FACE_OF_POLYHEDRON_EXPLICIT) THEN
+  ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `c:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(fun th -> GEN_REWRITE_TAC LAND_CONV [th]) THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [EXTENSION] THEN
+  X_GEN_TAC `h:real^N->bool` THEN REWRITE_TAC[IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let FACE_OF_POLYHEDRON_SUBSET_FACET = prove
+ (`!s:real^N->bool c.
+        polyhedron s /\ c face_of s /\ ~(c = {}) /\ ~(c = s)
+        ==> ?f. f facet_of s /\ c SUBSET f`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP FACE_OF_IMP_SUBSET) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `c:real^N->bool`] FACE_OF_POLYHEDRON) THEN
+  ASM_CASES_TAC `{f:real^N->bool | f facet_of s /\ c SUBSET f} = {}` THEN
+  ASM SET_TAC[]);;
+
+let EXPOSED_FACE_OF_POLYHEDRON = prove
+ (`!s f:real^N->bool. polyhedron s ==> (f exposed_face_of s <=> f face_of s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL [SIMP_TAC[exposed_face_of]; ALL_TAC] THEN
+  DISCH_TAC THEN ASM_CASES_TAC `f:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[EMPTY_EXPOSED_FACE_OF] THEN
+  ASM_CASES_TAC `f:real^N->bool = s` THEN
+  ASM_SIMP_TAC[EXPOSED_FACE_OF_REFL; POLYHEDRON_IMP_CONVEX] THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `f:real^N->bool`] FACE_OF_POLYHEDRON) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
+  MATCH_MP_TAC EXPOSED_FACE_OF_INTERS THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; FORALL_IN_GSPEC] THEN
+  ASM_SIMP_TAC[FACE_OF_POLYHEDRON_SUBSET_FACET; IN_ELIM_THM] THEN
+  ASM_SIMP_TAC[exposed_face_of; FACET_OF_IMP_FACE_OF] THEN
+  ASM_MESON_TAC[FACET_OF_POLYHEDRON]);;
+
+let FACE_OF_POLYHEDRON_POLYHEDRON = prove
+ (`!s:real^N->bool c. polyhedron s /\ c face_of s ==> polyhedron c`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM
+   (MP_TAC o GEN_REWRITE_RULE I [POLYHEDRON_INTER_AFFINE_MINIMAL]) THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  SIMP_TAC[LEFT_IMP_EXISTS_THM; RIGHT_AND_EXISTS_THM; LEFT_AND_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`f:(real^N->bool)->bool`; `a:(real^N->bool)->real^N`;
+    `b:(real^N->bool)->real`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `f:(real^N->bool)->bool`;
+                 `a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`]
+         FACE_OF_POLYHEDRON_EXPLICIT) THEN
+  ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `c:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `c:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[POLYHEDRON_EMPTY] THEN
+  ASM_CASES_TAC `c:real^N->bool = s` THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC POLYHEDRON_INTERS THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FINITE_RESTRICT] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[IMAGE_ID] THEN
+  MATCH_MP_TAC POLYHEDRON_INTER THEN
+  ASM_REWRITE_TAC[POLYHEDRON_HYPERPLANE]);;
+
+let FINITE_POLYHEDRON_FACES = prove
+ (`!s:real^N->bool. polyhedron s ==> FINITE {f | f face_of s}`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM
+   (MP_TAC o GEN_REWRITE_RULE I [POLYHEDRON_INTER_AFFINE_MINIMAL]) THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  SIMP_TAC[LEFT_IMP_EXISTS_THM; RIGHT_AND_EXISTS_THM; LEFT_AND_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`f:(real^N->bool)->bool`; `a:(real^N->bool)->real^N`;
+    `b:(real^N->bool)->real`] THEN
+  STRIP_TAC THEN
+  MATCH_MP_TAC(MESON[FINITE_DELETE]
+   `!a b. FINITE (s DELETE a DELETE b) ==> FINITE s`) THEN
+  MAP_EVERY EXISTS_TAC [`{}:real^N->bool`; `s:real^N->bool`] THEN
+  MATCH_MP_TAC FINITE_SUBSET THEN
+  EXISTS_TAC
+   `{INTERS {s INTER {x:real^N | a(h:real^N->bool) dot x = b h} | h | h IN f'}
+    |f'| f' SUBSET f}` THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [SIMPLE_IMAGE_GEN] THEN
+  ASM_SIMP_TAC[FINITE_POWERSET; FINITE_IMAGE] THEN
+  GEN_REWRITE_TAC I [SUBSET] THEN REWRITE_TAC[IN_DELETE; IN_ELIM_THM] THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `f:(real^N->bool)->bool`;
+                 `a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`]
+         FACE_OF_POLYHEDRON_EXPLICIT) THEN
+  ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `c:real^N->bool` THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_TAC THEN EXISTS_TAC
+   `{h:real^N->bool |
+     h IN f /\ c SUBSET s INTER {x:real^N | a h dot x = b h}}` THEN
+  CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[IN_ELIM_THM] THEN FIRST_ASSUM ACCEPT_TAC);;
+
+let FINITE_POLYHEDRON_EXPOSED_FACES = prove
+ (`!s:real^N->bool. polyhedron s ==> FINITE {f | f exposed_face_of s}`,
+  SIMP_TAC[EXPOSED_FACE_OF_POLYHEDRON; FINITE_POLYHEDRON_FACES]);;
+
+let FINITE_POLYHEDRON_EXTREME_POINTS = prove
+ (`!s:real^N->bool. polyhedron s ==> FINITE {v | v extreme_point_of s}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM FACE_OF_SING] THEN
+  ONCE_REWRITE_TAC[SET_RULE `{v} face_of s <=> {v} IN {f | f face_of s}`] THEN
+  MATCH_MP_TAC FINITE_FINITE_PREIMAGE THEN
+  ASM_SIMP_TAC[FINITE_POLYHEDRON_FACES] THEN X_GEN_TAC `f:real^N->bool` THEN
+  DISCH_TAC THEN ASM_CASES_TAC `!a:real^N. ~({a} = f)` THEN
+  ASM_REWRITE_TAC[EMPTY_GSPEC; FINITE_EMPTY] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM]) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  GEN_TAC THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[SET_RULE `{v | {v} = {a}} = {a}`; FINITE_SING]);;
+
+let FINITE_POLYHEDRON_FACETS = prove
+ (`!s:real^N->bool. polyhedron s ==> FINITE {f | f facet_of s}`,
+  REWRITE_TAC[facet_of] THEN ONCE_REWRITE_TAC[SET_RULE
+   `{x | P x /\ Q x} = {x | x IN {x | P x} /\ Q x}`] THEN
+  SIMP_TAC[FINITE_RESTRICT; FINITE_POLYHEDRON_FACES]);;
+
+let RELATIVE_INTERIOR_OF_POLYHEDRON = prove
+ (`!s:real^N->bool.
+        polyhedron s
+        ==> relative_interior s = s DIFF UNIONS {f | f facet_of s}`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM
+   (MP_TAC o GEN_REWRITE_RULE I [POLYHEDRON_INTER_AFFINE_MINIMAL]) THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV)
+   [RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  SIMP_TAC[LEFT_IMP_EXISTS_THM; RIGHT_AND_EXISTS_THM; LEFT_AND_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`f:(real^N->bool)->bool`; `a:(real^N->bool)->real^N`;
+    `b:(real^N->bool)->real`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `f:(real^N->bool)->bool`;
+                 `a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`]
+        FACET_OF_POLYHEDRON_EXPLICIT) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `f:(real^N->bool)->bool`;
+                 `a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`]
+        RELATIVE_INTERIOR_POLYHEDRON_EXPLICIT) THEN
+  ASM_REWRITE_TAC[] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[]; DISCH_THEN SUBST1_TAC] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[]; DISCH_TAC] THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(SET_RULE
+   `(!x. x IN s ==> P x \/ x IN t) /\ (!x. x IN t ==> ~P x)
+    ==> {x | x IN s /\ P x} = s DIFF t`) THEN
+  REWRITE_TAC[FORALL_IN_UNIONS] THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ; FORALL_IN_GSPEC] THEN
+  CONJ_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    REWRITE_TAC[IN_UNIONS; IN_ELIM_THM] THEN
+    REWRITE_TAC[LEFT_AND_EXISTS_THM; TAUT `(a /\ b) /\ c <=> b /\ a /\ c`] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    ASM_REWRITE_TAC[UNWIND_THM2; IN_ELIM_THM; IN_INTER] THEN
+    MATCH_MP_TAC(SET_RULE
+     `(!x. P x ==> Q x \/ R x) ==> (!x. P x ==> Q x) \/ (?x. P x /\ R x)`) THEN
+    X_GEN_TAC `h:real^N->bool` THEN DISCH_TAC THEN
+    REWRITE_TAC[GSYM REAL_LE_LT] THEN
+    SUBGOAL_THEN `(x:real^N) IN INTERS f` MP_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    REWRITE_TAC[IN_INTERS] THEN
+    DISCH_THEN(MP_TAC o SPEC `h:real^N->bool`) THEN
+    SUBGOAL_THEN `h = {x:real^N | a h dot x <= b h}` MP_TAC THENL
+     [ASM_MESON_TAC[]; ASM_REWRITE_TAC[] THEN SET_TAC[]];
+    X_GEN_TAC `h:real^N->bool` THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real^N->bool` STRIP_ASSUME_TAC) THEN
+    X_GEN_TAC `x:real^N` THEN ASM_REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN
+    ASM_MESON_TAC[REAL_LT_REFL]]);;
+
+let RELATIVE_BOUNDARY_OF_POLYHEDRON = prove
+ (`!s:real^N->bool.
+        polyhedron s
+        ==> s DIFF relative_interior s = UNIONS {f | f facet_of s}`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[RELATIVE_INTERIOR_OF_POLYHEDRON] THEN
+  MATCH_MP_TAC(SET_RULE `f SUBSET s ==> s DIFF (s DIFF f) = f`) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_UNIONS; IN_ELIM_THM] THEN
+  MESON_TAC[FACET_OF_IMP_SUBSET; SUBSET]);;
+
+let RELATIVE_FRONTIER_OF_POLYHEDRON = prove
+ (`!s:real^N->bool.
+        polyhedron s ==> relative_frontier s = UNIONS {f | f facet_of s}`,
+  SIMP_TAC[relative_frontier; POLYHEDRON_IMP_CLOSED; CLOSURE_CLOSED] THEN
+  REWRITE_TAC[RELATIVE_BOUNDARY_OF_POLYHEDRON]);;
+
+let RELATIVE_FRONTIER_OF_POLYHEDRON_ALT = prove
+ (`!s:real^N->bool.
+        polyhedron s
+        ==> relative_frontier s = UNIONS {f | f face_of s /\ ~(f = s)}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[RELATIVE_FRONTIER_OF_POLYHEDRON; facet_of] THEN
+    MATCH_MP_TAC SUBSET_UNIONS THEN SIMP_TAC[SUBSET; IN_ELIM_THM] THEN
+    MESON_TAC[INT_ARITH `~(f - &1:int = f)`];
+    REWRITE_TAC[SUBSET; FORALL_IN_UNIONS; IN_ELIM_THM] THEN
+    MESON_TAC[REWRITE_RULE[SUBSET] FACE_OF_SUBSET_RELATIVE_FRONTIER]]);;
+
+let FACETS_OF_POLYHEDRON_EXPLICIT_DISTINCT = prove
+ (`!s:real^N->bool f a b.
+        FINITE f /\
+        s = affine hull s INTER INTERS f /\
+        (!h. h IN f ==> ~(a h = vec 0) /\ h = {x | a h dot x <= b h}) /\
+        (!f'. f' PSUBSET f ==> s PSUBSET affine hull s INTER INTERS f')
+        ==> !h1 h2. h1 IN f /\ h2 IN f /\
+                    s INTER {x | a h1 dot x = b h1} =
+                    s INTER {x | a h2 dot x = b h2}
+                    ==> h1 = h2`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[AFFINE_HULL_EMPTY; INTER_EMPTY; PSUBSET_IRREFL] THEN
+    ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THEN
+    ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN
+    ASM_MESON_TAC[SET_RULE `~(s = {}) ==> {} PSUBSET s`];
+    STRIP_TAC] THEN
+  SUBGOAL_THEN `polyhedron(s:real^N->bool)` ASSUME_TAC THENL
+   [REWRITE_TAC[POLYHEDRON_INTER_AFFINE] THEN
+    REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `~(relative_interior s:real^N->bool = {})` MP_TAC THENL
+   [ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY; POLYHEDRON_IMP_CONVEX];
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `z:real^N` MP_TAC)] THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  MP_TAC(ISPECL
+    [`s:real^N->bool`; `f:(real^N->bool)->bool`; `a:(real^N->bool)->real^N`;
+     `b:(real^N->bool)->real`] RELATIVE_INTERIOR_POLYHEDRON_EXPLICIT) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[] THEN ASM_MESON_TAC[]; DISCH_THEN SUBST1_TAC] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `f DELETE (h2:real^N->bool)`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[PSUBSET_ALT]] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_THEN `x:real^N` MP_TAC)) THEN
+  REWRITE_TAC[IN_INTER; IN_INTERS; IN_DELETE] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`segment[x:real^N,z]`; `s:real^N->bool`]
+        CONNECTED_INTER_RELATIVE_FRONTIER) THEN
+  PURE_REWRITE_TAC[relative_frontier] THEN ANTS_TAC THENL
+   [REWRITE_TAC[CONNECTED_SEGMENT; GSYM MEMBER_NOT_EMPTY] THEN
+    REPEAT CONJ_TAC THENL
+     [ASM_MESON_TAC[CONVEX_CONTAINS_SEGMENT; AFFINE_AFFINE_HULL;
+                    HULL_INC; AFFINE_IMP_CONVEX];
+      EXISTS_TAC `z:real^N` THEN ASM_REWRITE_TAC[IN_INTER; ENDS_IN_SEGMENT];
+      EXISTS_TAC `x:real^N` THEN ASM_REWRITE_TAC[IN_DIFF; ENDS_IN_SEGMENT]];
+    ALL_TAC] THEN
+  PURE_REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+  ASM_SIMP_TAC[POLYHEDRON_IMP_CLOSED; CLOSURE_CLOSED;
+         LEFT_IMP_EXISTS_THM; IN_INTER] THEN
+  X_GEN_TAC `y:real^N` THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(fun th -> STRIP_ASSUME_TAC(REWRITE_RULE[IN_DIFF] th) THEN
+        MP_TAC th) THEN
+  ASM_SIMP_TAC[RELATIVE_BOUNDARY_OF_POLYHEDRON] THEN
+  MP_TAC(ISPECL
+    [`s:real^N->bool`; `f:(real^N->bool)->bool`; `a:(real^N->bool)->real^N`;
+     `b:(real^N->bool)->real`] FACET_OF_POLYHEDRON_EXPLICIT) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[] THEN ASM_MESON_TAC[];
+    DISCH_THEN(fun th -> ONCE_REWRITE_TAC[th])] THEN
+  REWRITE_TAC[SET_RULE `{y | ?x. x IN s /\ y = f x} = IMAGE f s`] THEN
+  REWRITE_TAC[UNIONS_IMAGE; IN_ELIM_THM; IN_INTER] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h:real^N->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `?k:real^N->bool. k IN f /\ ~(k = h2) /\ a k dot (y:real^N) = b k`
+  STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `h:real^N->bool = h2` THENL
+     [EXISTS_TAC `h1:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+      UNDISCH_TAC `s INTER {x:real^N | a(h1:real^N->bool) dot x = b h1} =
+                   s INTER {x | a h2 dot x = b h2}` THEN
+      REWRITE_TAC[EXTENSION; IN_INTER; IN_ELIM_THM] THEN ASM_MESON_TAC[];
+      ASM_MESON_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(a:(real^N->bool)->real^N) k dot z < b k /\ a k dot x <= b k`
+  STRIP_ASSUME_TAC THENL [ASM_SIMP_TAC[] THEN ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `y IN segment(x:real^N,z)` MP_TAC THENL
+   [ASM_REWRITE_TAC[IN_OPEN_SEGMENT_ALT] THEN ASM_MESON_TAC[];
+    REWRITE_TAC[IN_SEGMENT] THEN STRIP_TAC] THEN
+  UNDISCH_TAC `(a:(real^N->bool)->real^N) k dot y = b k` THEN
+  ASM_REWRITE_TAC[DOT_RADD; DOT_RMUL] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `(&1 - u) * x <= (&1 - u) * b /\ u * y < u * b
+    ==> ~((&1 - u) * x + u * y = b)`) THEN
+  ASM_SIMP_TAC[REAL_LT_LMUL_EQ; REAL_LE_LMUL_EQ; REAL_SUB_LT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A characterization of polyhedra as having finitely many faces.            *)
+(* ------------------------------------------------------------------------- *)
+
+let POLYHEDRON_EQ_FINITE_EXPOSED_FACES = prove
+ (`!s:real^N->bool.
+    polyhedron s <=> closed s /\ convex s /\ FINITE {f | f exposed_face_of s}`,
+  GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[POLYHEDRON_IMP_CLOSED; POLYHEDRON_IMP_CONVEX;
+               FINITE_POLYHEDRON_EXPOSED_FACES] THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[POLYHEDRON_EMPTY] THEN
+  ABBREV_TAC
+   `f = {h:real^N->bool | h exposed_face_of s /\ ~(h = {}) /\ ~(h = s)}` THEN
+  SUBGOAL_THEN `FINITE(f:(real^N->bool)->bool)` ASSUME_TAC THENL
+   [EXPAND_TAC "f" THEN
+    ONCE_REWRITE_TAC[SET_RULE
+     `{x | P x /\ Q x} = {x | x IN {x | P x} /\ Q x}`] THEN
+    ASM_SIMP_TAC[FINITE_RESTRICT];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!h:real^N->bool.
+        h IN f
+        ==> h face_of s /\
+            ?a b. ~(a = vec 0) /\
+                  s SUBSET {x | a dot x <= b} /\
+                  h = s INTER {x | a dot x = b}`
+  MP_TAC THENL
+   [EXPAND_TAC "f" THEN REWRITE_TAC[EXPOSED_FACE_OF; IN_ELIM_THM] THEN
+    MESON_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM; FORALL_AND_THM;
+              TAUT `a ==> b /\ c <=> (a ==> b) /\ (a ==> c)`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:(real^N->bool)->real^N` MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:(real^N->bool)->real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `s = affine hull s INTER
+        INTERS {{x:real^N | a(h:real^N->bool) dot x <= b h} | h IN f}`
+  SUBST1_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC POLYHEDRON_INTER THEN REWRITE_TAC[POLYHEDRON_AFFINE_HULL] THEN
+    MATCH_MP_TAC POLYHEDRON_INTERS THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE; POLYHEDRON_HALFSPACE_LE]] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[SUBSET_INTER; HULL_SUBSET;
+              SET_RULE `s SUBSET INTERS f <=> !h. h IN f ==> s SUBSET h`] THEN
+  ASM_REWRITE_TAC[FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[SUBSET; IN_INTER; IN_INTERS; FORALL_IN_GSPEC] THEN
+  X_GEN_TAC `p:real^N` THEN REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN
+  MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+  SUBGOAL_THEN `~(relative_interior(s:real^N->bool) = {})` MP_TAC THENL
+   [ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY];
+    GEN_REWRITE_TAC LAND_CONV [GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `c:real^N`)] THEN
+  SUBGOAL_THEN
+   `?x:real^N. x IN segment[c,p] /\ x IN (s DIFF relative_interior s)`
+  MP_TAC THENL
+   [MP_TAC(ISPEC `segment[c:real^N,p]` CONNECTED_OPEN_IN) THEN
+    REWRITE_TAC[CONNECTED_SEGMENT; NOT_EXISTS_THM] THEN
+    DISCH_THEN(MP_TAC o SPECL
+     [`segment[c:real^N,p] INTER relative_interior s`;
+      `segment[c:real^N,p] INTER (UNIV DIFF s)`]) THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[IN_DIFF; NOT_EXISTS_THM] THEN DISCH_TAC THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC OPEN_IN_SUBTOPOLOGY_INTER_SUBSET THEN
+      EXISTS_TAC `affine hull s:real^N->bool` THEN
+      SIMP_TAC[OPEN_IN_RELATIVE_INTERIOR; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY;
+        OPEN_IN_SUBTOPOLOGY_REFL; SUBSET_UNIV; OPEN_IN_INTER;
+        TOPSPACE_EUCLIDEAN] THEN
+      REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+      SIMP_TAC[AFFINE_IMP_CONVEX; AFFINE_AFFINE_HULL] THEN
+      ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET] THEN
+      ASM_MESON_TAC[RELATIVE_INTERIOR_SUBSET; HULL_INC; SUBSET];
+      REWRITE_TAC[OPEN_IN_OPEN] THEN EXISTS_TAC `(:real^N) DIFF s` THEN
+      ASM_REWRITE_TAC[GSYM closed];
+     MP_TAC(ISPEC `s:real^N->bool` RELATIVE_INTERIOR_SUBSET) THEN ASM SET_TAC[];
+     MP_TAC(ISPEC `s:real^N->bool` RELATIVE_INTERIOR_SUBSET) THEN SET_TAC[];
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+      ASM_MESON_TAC[ENDS_IN_SEGMENT];
+      REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_DIFF; IN_INTER; IN_UNIV] THEN
+      ASM_MESON_TAC[ENDS_IN_SEGMENT]];
+    REWRITE_TAC[IN_SEGMENT; LEFT_AND_EXISTS_THM] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC; RIGHT_EXISTS_AND_THM; UNWIND_THM2] THEN
+    DISCH_THEN(X_CHOOSE_THEN `l:real` MP_TAC) THEN
+    ASM_CASES_TAC `l = &0` THEN
+    ASM_REWRITE_TAC[VECTOR_ADD_RID; VECTOR_MUL_LZERO; REAL_SUB_RZERO;
+                    VECTOR_MUL_LID; IN_DIFF] THEN
+    ASM_CASES_TAC `l = &1` THEN
+    ASM_REWRITE_TAC[VECTOR_ADD_LID; VECTOR_MUL_LZERO; REAL_SUB_REFL;
+                    VECTOR_MUL_LID; IN_DIFF] THEN
+    ASM_REWRITE_TAC[REAL_LE_LT] THEN STRIP_TAC] THEN
+  ABBREV_TAC `x:real^N = (&1 - l) % c + l % p` THEN
+  SUBGOAL_THEN `?h:real^N->bool. h IN f /\ x IN h` STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPECL [`s:real^N->bool`; `(&1 - l) % c + l % p:real^N`]
+      SUPPORTING_HYPERPLANE_RELATIVE_FRONTIER) THEN
+    ASM_SIMP_TAC[REWRITE_RULE[SUBSET] CLOSURE_SUBSET] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real^N` STRIP_ASSUME_TAC) THEN
+    EXPAND_TAC "f" THEN
+    EXISTS_TAC `s INTER {y:real^N | d dot y = d dot x}` THEN
+    ASM_REWRITE_TAC[IN_INTER; IN_ELIM_THM] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC EXPOSED_FACE_OF_INTER_SUPPORTING_HYPERPLANE_GE THEN
+      ASM_SIMP_TAC[real_ge; REWRITE_RULE[SUBSET] CLOSURE_SUBSET];
+      ASM SET_TAC[];
+      REWRITE_TAC[EXTENSION; IN_INTER; IN_ELIM_THM] THEN
+      DISCH_THEN(MP_TAC o SPEC `c:real^N`) THEN
+      ASM_MESON_TAC[SUBSET; REAL_LT_REFL; RELATIVE_INTERIOR_SUBSET]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `{y:real^N | a(h:real^N->bool) dot y = b h} face_of
+                {y | a h dot y <= b h}`
+  MP_TAC THENL
+   [MATCH_MP_TAC(MESON[]
+     `(t INTER s) face_of t /\ t INTER s = s ==> s face_of t`) THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC FACE_OF_INTER_SUPPORTING_HYPERPLANE_LE THEN
+      REWRITE_TAC[IN_ELIM_THM; CONVEX_HALFSPACE_LE];
+      SET_TAC[REAL_LE_REFL]];
+    ALL_TAC] THEN
+  REWRITE_TAC[face_of] THEN
+  DISCH_THEN(MP_TAC o SPECL [`c:real^N`; `p:real^N`; `x:real^N`] o
+        CONJUNCT2 o CONJUNCT2) THEN
+  ASM_SIMP_TAC[IN_ELIM_THM; NOT_IMP; GSYM CONJ_ASSOC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP (REWRITE_RULE[SUBSET]
+      RELATIVE_INTERIOR_SUBSET)) THEN
+  REPEAT CONJ_TAC THENL
+   [ASM SET_TAC[];
+    ASM SET_TAC[];
+    REWRITE_TAC[IN_SEGMENT] THEN ASM SET_TAC[];
+    STRIP_TAC] THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `h:real^N->bool`; `s:real^N->bool`]
+        SUBSET_OF_FACE_OF) THEN
+  ASM SET_TAC[]);;
+
+let POLYHEDRON_EQ_FINITE_FACES = prove
+ (`!s:real^N->bool.
+        polyhedron s <=>
+        closed s /\ convex s /\ FINITE {f | f face_of s}`,
+  GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[POLYHEDRON_IMP_CLOSED; POLYHEDRON_IMP_CONVEX;
+               FINITE_POLYHEDRON_FACES] THEN
+  REWRITE_TAC[POLYHEDRON_EQ_FINITE_EXPOSED_FACES] THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC FINITE_SUBSET THEN
+  EXISTS_TAC `{f:real^N->bool | f face_of s}` THEN
+  ASM_REWRITE_TAC[] THEN
+  SIMP_TAC[SUBSET; IN_ELIM_THM; exposed_face_of]);;
+
+let POLYHEDRON_TRANSLATION_EQ = prove
+ (`!a s. polyhedron (IMAGE (\x:real^N. a + x) s) <=> polyhedron s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[POLYHEDRON_EQ_FINITE_FACES] THEN
+  REWRITE_TAC[CLOSED_TRANSLATION_EQ] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[CONVEX_TRANSLATION_EQ] THEN AP_TERM_TAC THEN
+  MP_TAC(ISPEC `IMAGE (\x:real^N. a + x)` QUANTIFY_SURJECTION_THM) THEN
+  REWRITE_TAC[SURJECTIVE_IMAGE; EXISTS_REFL;
+    VECTOR_ARITH `a + x:real^N = y <=> x = y - a`] THEN
+  DISCH_THEN(fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th]) THEN
+  REWRITE_TAC[FACE_OF_TRANSLATION_EQ] THEN
+  MATCH_MP_TAC FINITE_IMAGE_INJ_EQ THEN
+  MATCH_MP_TAC(MESON[]
+   `(!x y. Q x y ==> R x y) ==> (!x y. P x /\ P y /\ Q x y ==> R x y)`) THEN
+  REWRITE_TAC[INJECTIVE_IMAGE] THEN VECTOR_ARITH_TAC);;
+
+add_translation_invariants [POLYHEDRON_TRANSLATION_EQ];;
+
+let POLYHEDRON_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+        ==> (polyhedron (IMAGE f s) <=> polyhedron s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[POLYHEDRON_EQ_FINITE_FACES] THEN
+  BINOP_TAC THENL
+   [ASM_MESON_TAC[CLOSED_INJECTIVE_LINEAR_IMAGE_EQ]; ALL_TAC] THEN
+  BINOP_TAC THENL [ASM_MESON_TAC[CONVEX_LINEAR_IMAGE_EQ]; ALL_TAC] THEN
+  MP_TAC(ISPEC `IMAGE (f:real^M->real^N)` QUANTIFY_SURJECTION_THM) THEN
+  ASM_REWRITE_TAC[SURJECTIVE_IMAGE] THEN
+  DISCH_THEN(fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th]) THEN
+  MP_TAC(ISPEC `f:real^M->real^N` FACE_OF_LINEAR_IMAGE) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC FINITE_IMAGE_INJ_EQ THEN
+  FIRST_ASSUM(ASSUME_TAC o GEN_REWRITE_RULE I [GSYM INJECTIVE_IMAGE]) THEN
+  ASM_REWRITE_TAC[IMP_CONJ]);;
+
+add_linear_invariants [POLYHEDRON_LINEAR_IMAGE_EQ];;
+
+let POLYHEDRON_NEGATIONS = prove
+ (`!s:real^N->bool. polyhedron s ==> polyhedron(IMAGE (--) s)`,
+  GEN_TAC THEN MATCH_MP_TAC EQ_IMP THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC POLYHEDRON_LINEAR_IMAGE_EQ THEN
+  REWRITE_TAC[VECTOR_ARITH `--x:real^N = y <=> x = --y`; EXISTS_REFL] THEN
+  REWRITE_TAC[LINEAR_NEGATION] THEN VECTOR_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relation between polytopes and polyhedra.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let POLYTOPE_EQ_BOUNDED_POLYHEDRON = prove
+ (`!s:real^N->bool. polytope s <=> polyhedron s /\ bounded s`,
+  GEN_TAC THEN EQ_TAC THENL
+   [SIMP_TAC[FINITE_POLYTOPE_FACES; POLYHEDRON_EQ_FINITE_FACES;
+             POLYTOPE_IMP_CLOSED; POLYTOPE_IMP_CONVEX; POLYTOPE_IMP_BOUNDED];
+    STRIP_TAC THEN REWRITE_TAC[polytope] THEN
+    EXISTS_TAC `{v:real^N | v extreme_point_of s}` THEN
+    ASM_SIMP_TAC[FINITE_POLYHEDRON_EXTREME_POINTS] THEN
+    MATCH_MP_TAC KREIN_MILMAN_MINKOWSKI THEN
+    ASM_SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; POLYHEDRON_IMP_CLOSED;
+                 POLYHEDRON_IMP_CONVEX]]);;
+
+let POLYTOPE_INTER = prove
+ (`!s t. polytope s /\ polytope t ==> polytope(s INTER t)`,
+  SIMP_TAC[POLYTOPE_EQ_BOUNDED_POLYHEDRON; POLYHEDRON_INTER; BOUNDED_INTER]);;
+
+let POLYTOPE_INTER_POLYHEDRON = prove
+ (`!s t:real^N->bool. polytope s /\ polyhedron t ==> polytope(s INTER t)`,
+  SIMP_TAC[POLYTOPE_EQ_BOUNDED_POLYHEDRON; POLYHEDRON_INTER] THEN
+  MESON_TAC[BOUNDED_SUBSET; INTER_SUBSET]);;
+
+let POLYHEDRON_INTER_POLYTOPE = prove
+ (`!s t:real^N->bool. polyhedron s /\ polytope t ==> polytope(s INTER t)`,
+  SIMP_TAC[POLYTOPE_EQ_BOUNDED_POLYHEDRON; POLYHEDRON_INTER] THEN
+  MESON_TAC[BOUNDED_SUBSET; INTER_SUBSET]);;
+
+let POLYTOPE_IMP_POLYHEDRON = prove
+ (`!p. polytope p ==> polyhedron p`,
+  SIMP_TAC[POLYTOPE_EQ_BOUNDED_POLYHEDRON]);;
+
+let POLYTOPE_FACET_EXISTS = prove
+ (`!p:real^N->bool. polytope p /\ &0 < aff_dim p ==> ?f. f facet_of p`,
+  GEN_TAC THEN ASM_CASES_TAC `p:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[AFF_DIM_EMPTY] THEN CONV_TAC INT_REDUCE_CONV THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPEC `p:real^N->bool` EXTREME_POINT_EXISTS_CONVEX) THEN
+  ASM_SIMP_TAC[POLYTOPE_IMP_COMPACT; POLYTOPE_IMP_CONVEX] THEN
+  DISCH_THEN(X_CHOOSE_TAC `v:real^N`) THEN
+  MP_TAC(ISPECL [`p:real^N->bool`; `{v:real^N}`]
+    FACE_OF_POLYHEDRON_SUBSET_FACET) THEN
+  ANTS_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
+  ASM_SIMP_TAC[POLYTOPE_IMP_POLYHEDRON; FACE_OF_SING; NOT_INSERT_EMPTY] THEN
+  ASM_MESON_TAC[AFF_DIM_SING; INT_LT_REFL]);;
+
+let POLYHEDRON_INTERVAL = prove
+ (`!a b. polyhedron(interval[a,b])`,
+  MESON_TAC[POLYTOPE_IMP_POLYHEDRON; POLYTOPE_INTERVAL]);;
+
+let POLYHEDRON_CONVEX_HULL = prove
+ (`!s. FINITE s ==> polyhedron(convex hull s)`,
+  SIMP_TAC[POLYTOPE_CONVEX_HULL; POLYTOPE_IMP_POLYHEDRON]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Polytope is union of convex hulls of facets plus any point inside.        *)
+(* ------------------------------------------------------------------------- *)
+
+let POLYTOPE_UNION_CONVEX_HULL_FACETS = prove
+ (`!s p:real^N->bool.
+        polytope p /\ &0 < aff_dim p /\ ~(s = {}) /\ s SUBSET p
+        ==> p = UNIONS { convex hull (s UNION f) | f facet_of p}`,
+  let lemma = SET_RULE `{f x | p x} = {y | ?x. p x /\ y = f x}` in
+  MATCH_MP_TAC SET_PROVE_CASES THEN REWRITE_TAC[] THEN
+  X_GEN_TAC `a:real^N` THEN ONCE_REWRITE_TAC[lemma] THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN ONCE_REWRITE_TAC[GSYM lemma] THEN
+  X_GEN_TAC `s:real^N->bool` THEN DISCH_THEN(K ALL_TAC) THEN
+  MP_TAC(SET_RULE `(vec 0:real^N) IN (vec 0 INSERT s)`) THEN
+  SPEC_TAC(`(vec 0:real^N) INSERT s`,`s:real^N->bool`) THEN
+  X_GEN_TAC `s:real^N->bool` THEN DISCH_TAC THEN
+  X_GEN_TAC `p:real^N->bool` THEN STRIP_TAC THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o
+   GEN_REWRITE_RULE I [POLYTOPE_EQ_BOUNDED_POLYHEDRON]) THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[SUBSET; FORALL_IN_UNIONS; IMP_CONJ] THEN
+    REWRITE_TAC[FORALL_IN_GSPEC; RIGHT_FORALL_IMP_THM] THEN
+    X_GEN_TAC `f:real^N->bool` THEN DISCH_TAC THEN
+    REWRITE_TAC[GSYM SUBSET] THEN MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `convex hull p:real^N->bool` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC HULL_MONO THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP FACET_OF_IMP_SUBSET) THEN ASM SET_TAC[];
+      ASM_MESON_TAC[CONVEX_HULL_EQ; POLYHEDRON_IMP_CONVEX; SUBSET_REFL]]] THEN
+  REWRITE_TAC[SUBSET] THEN X_GEN_TAC `v:real^N` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `v:real^N = vec 0` THENL
+   [MP_TAC(ISPEC `p:real^N->bool` POLYTOPE_FACET_EXISTS) THEN
+    ASM_REWRITE_TAC[IN_UNIONS; EXISTS_IN_GSPEC] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN DISCH_TAC THEN
+    ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[HULL_INC; IN_UNION];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `?t. &1 < t /\ ~((t % v:real^N) IN p)` STRIP_ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [BOUNDED_POS]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `max (&2) ((B + &1) / norm (v:real^N))` THEN
+    CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o
+     GEN_REWRITE_RULE BINDER_CONV [GSYM CONTRAPOS_THM]) THEN
+    ASM_SIMP_TAC[NORM_MUL; GSYM REAL_LE_RDIV_EQ; NORM_POS_LT] THEN
+    MATCH_MP_TAC(REAL_ARITH `a < b ==> ~(abs(max (&2) b) <= a)`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV2_EQ; NORM_POS_LT] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(vec 0:real^N) IN p` ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`segment[vec 0,t % v:real^N] INTER p`; `vec 0:real^N`]
+        DISTANCE_ATTAINS_SUP) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[COMPACT_INTER_CLOSED; POLYHEDRON_IMP_CLOSED; COMPACT_SEGMENT;
+                 GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+    ASM_MESON_TAC[ENDS_IN_SEGMENT];
+    REWRITE_TAC[IN_INTER; GSYM CONJ_ASSOC; IMP_CONJ] THEN
+    REWRITE_TAC[segment; FORALL_IN_GSPEC; EXISTS_IN_GSPEC] THEN
+    REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID; DIST_0] THEN
+    REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC; NORM_MUL; REAL_MUL_ASSOC] THEN
+    ASM_SIMP_TAC[REAL_LE_RMUL_EQ; NORM_POS_LT; LEFT_IMP_EXISTS_THM;
+                 REAL_ARITH `&1 < t ==> &0 < abs t`] THEN
+    X_GEN_TAC `u:real` THEN
+    ASM_CASES_TAC `u = &1` THEN ASM_REWRITE_TAC[VECTOR_MUL_LID] THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    ASM_SIMP_TAC[real_abs] THEN DISCH_TAC] THEN
+  SUBGOAL_THEN `inv(t) <= u` ASSUME_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[REAL_INV_LE_1; REAL_LT_IMP_LE; REAL_LE_INV_EQ;
+                 REAL_ARITH `&1 < t ==> &0 <= t`] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; VECTOR_MUL_LID;
+                 REAL_ARITH `&1 < t ==> ~(t = &0)`];
+    ALL_TAC] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP (REAL_ARITH `&1 < t ==> &0 < t`)) THEN
+  SUBGOAL_THEN `&0 < u /\ u < &1` STRIP_ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[REAL_LT_LE] THEN
+    DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+    UNDISCH_TAC `inv t <= &0` THEN REWRITE_TAC[REAL_NOT_LE] THEN
+    ASM_REWRITE_TAC[REAL_LT_INV_EQ];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(SET_RULE `!t. t SUBSET s /\ x IN t ==> x IN s`) THEN
+  EXISTS_TAC `convex hull {vec 0:real^N,u % t % v}` THEN CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[CONVEX_HULL_2; VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    MAP_EVERY EXISTS_TAC [`&1 - inv(u * t)`; `inv(u * t):real`] THEN
+    REWRITE_TAC[REAL_ARITH `&1 - x + x = &1`; REAL_SUB_LE; REAL_LE_INV_EQ] THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE; VECTOR_MUL_ASSOC] THEN
+    ASM_SIMP_TAC[GSYM REAL_MUL_ASSOC; REAL_ENTIRE; REAL_MUL_LINV;
+                 REAL_LT_IMP_NZ; VECTOR_MUL_LID] THEN
+    MATCH_MP_TAC REAL_INV_LE_1 THEN ASM_SIMP_TAC[GSYM REAL_LE_LDIV_EQ] THEN
+    ASM_REWRITE_TAC[real_div; REAL_MUL_LID]] THEN
+  SUBGOAL_THEN
+   `(u % t % v:real^N) IN (p DIFF relative_interior p)`
+  MP_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[RELATIVE_INTERIOR_OF_POLYHEDRON] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE
+     `x IN s DIFF (s DIFF t) ==> x IN t`)) THEN
+    REWRITE_TAC[IN_UNIONS; EXISTS_IN_GSPEC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `f:real^N->bool` STRIP_ASSUME_TAC) THEN
+    MATCH_MP_TAC(SET_RULE
+     `(?s. s IN f /\ t SUBSET s) ==> t SUBSET UNIONS f`) THEN
+    REWRITE_TAC[EXISTS_IN_GSPEC] THEN EXISTS_TAC `f:real^N->bool` THEN
+    ASM_SIMP_TAC[SUBSET_HULL; CONVEX_CONVEX_HULL] THEN
+    ASM_SIMP_TAC[HULL_INC; IN_UNION; INSERT_SUBSET; EMPTY_SUBSET]] THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_RELATIVE_INTERIOR] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[SUBSET; IN_BALL; IN_INTER; dist] THEN
+  ABBREV_TAC `k = min (e / &2 / norm(t % v:real^N)) (&1 - u)` THEN
+  SUBGOAL_THEN `&0 < k` ASSUME_TAC THENL
+   [EXPAND_TAC "k" THEN REWRITE_TAC[REAL_LT_MIN] THEN
+    ASM_REWRITE_TAC[REAL_SUB_LT] THEN MATCH_MP_TAC REAL_LT_DIV THEN
+    ASM_SIMP_TAC[REAL_HALF; NORM_POS_LT; VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `(u + k) % t % v:real^N`) THEN
+  REWRITE_TAC[VECTOR_ARITH `u % x - (u + k) % x:real^N = --k % x`] THEN
+  ONCE_REWRITE_TAC[NORM_MUL] THEN REWRITE_TAC[REAL_ABS_NEG; NOT_IMP] THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
+    ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; NORM_POS_LT; VECTOR_MUL_EQ_0;
+                 REAL_LT_IMP_NZ] THEN
+    ASM_SIMP_TAC[real_abs; REAL_LT_IMP_LE] THEN
+    EXPAND_TAC "k" THEN REAL_ARITH_TAC;
+    ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC] THEN
+    REPEAT(MATCH_MP_TAC SPAN_MUL) THEN ASM_SIMP_TAC[SPAN_SUPERSET];
+    DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `u + k:real`) THEN
+    ASM_REWRITE_TAC[NOT_IMP] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `&0 <= u /\ &0 < x /\ x <= &1 - u
+      ==> (&0 <= u + x /\ u + x <= &1) /\ ~(u + x <= u)`) THEN
+    ASM_REWRITE_TAC[] THEN EXPAND_TAC "k" THEN REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Finitely generated cone is polyhedral, and hence closed.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let POLYHEDRON_CONVEX_CONE_HULL = prove
+ (`!s:real^N->bool. FINITE s ==> polyhedron(convex_cone hull s)`,
+  GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN DISCH_TAC THENL
+   [ASM_REWRITE_TAC[CONVEX_CONE_HULL_EMPTY] THEN
+    ASM_SIMP_TAC[POLYTOPE_IMP_POLYHEDRON; POLYTOPE_SING];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+    `polyhedron(convex hull ((vec 0:real^N) INSERT s))`
+  MP_TAC THENL
+   [MATCH_MP_TAC POLYTOPE_IMP_POLYHEDRON THEN
+    REWRITE_TAC[polytope] THEN ASM_MESON_TAC[FINITE_INSERT];
+    REWRITE_TAC[polyhedron] THEN
+    DISCH_THEN(X_CHOOSE_THEN `f:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[SKOLEM_THM; RIGHT_IMP_EXISTS_THM]) THEN
+    FIRST_X_ASSUM(X_CHOOSE_THEN `a:(real^N->bool)->real^N` MP_TAC) THEN
+    DISCH_THEN(X_CHOOSE_TAC `b:(real^N->bool)->real`)] THEN
+  SUBGOAL_THEN `~(f:(real^N->bool)->bool = {})` ASSUME_TAC THENL
+   [DISCH_THEN SUBST_ALL_TAC THEN FIRST_X_ASSUM(MP_TAC o
+     GEN_REWRITE_RULE RAND_CONV [INTERS_0]) THEN
+    DISCH_THEN(MP_TAC o AP_TERM `bounded:(real^N->bool)->bool`) THEN
+    ASM_SIMP_TAC[NOT_BOUNDED_UNIV; BOUNDED_CONVEX_HULL; FINITE_IMP_BOUNDED;
+                 FINITE_INSERT; FINITE_EMPTY];
+    ALL_TAC] THEN
+  EXISTS_TAC `{h:real^N->bool | h IN f /\ b h = &0}` THEN
+  ASM_SIMP_TAC[FINITE_RESTRICT; IN_ELIM_THM] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    X_GEN_TAC `h:real^N->bool` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `h:real^N->bool`) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_TAC THEN ONCE_ASM_REWRITE_TAC[] THEN
+    MAP_EVERY EXISTS_TAC
+     [`(a:(real^N->bool)->real^N) h`; `(b:(real^N->bool)->real) h`] THEN
+    ASM_REWRITE_TAC[]] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HULL_MINIMAL THEN CONJ_TAC THENL
+     [MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `convex hull ((vec 0:real^N) INSERT s)` THEN CONJ_TAC THENL
+       [SIMP_TAC[SUBSET; HULL_INC; IN_INSERT]; ASM_REWRITE_TAC[]] THEN
+      MATCH_MP_TAC(SET_RULE `s SUBSET t ==> INTERS t SUBSET INTERS s`) THEN
+      SET_TAC[];
+      MATCH_MP_TAC CONVEX_CONE_INTERS THEN
+      X_GEN_TAC `h:real^N->bool` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+      STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `h:real^N->bool`) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o CONJUNCT2) THEN
+      REWRITE_TAC[CONVEX_CONE_HALFSPACE_LE]];
+    ALL_TAC] THEN
+  REWRITE_TAC[SUBSET; IN_INTERS; IN_ELIM_THM] THEN X_GEN_TAC `x:real^N` THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN `!h:real^N->bool. h IN f ==> ?t. &0 < t /\ (t % x) IN h`
+  MP_TAC THENL
+   [X_GEN_TAC `h:real^N->bool` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `(b:(real^N->bool)->real) h = &0` THENL
+     [EXISTS_TAC `&1` THEN ASM_SIMP_TAC[REAL_LT_01; VECTOR_MUL_LID];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `&0 < (b:(real^N->bool)->real) h` ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[REAL_LT_LE] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+      DISCH_THEN(MP_TAC o SPEC `vec 0:real^N`) THEN
+      SIMP_TAC[HULL_INC; IN_INSERT; IN_INTERS] THEN
+      DISCH_THEN(MP_TAC o SPEC `h:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN
+      SUBGOAL_THEN `h = {x:real^N | a h dot x <= b h}`
+       (fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th])
+      THENL [ASM_MESON_TAC[]; REWRITE_TAC[IN_ELIM_THM; DOT_RZERO]];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `(vec 0:real^N) IN interior h` MP_TAC THENL
+     [SUBGOAL_THEN `h = {x:real^N | a h dot x <= b h}` SUBST1_TAC THENL
+       [ASM_MESON_TAC[];
+        ASM_SIMP_TAC[INTERIOR_HALFSPACE_LE; IN_ELIM_THM; DOT_RZERO]];
+      REWRITE_TAC[IN_INTERIOR; SUBSET; IN_BALL_0; LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `e:real` THEN STRIP_TAC THEN
+      ASM_CASES_TAC `x:real^N = vec 0` THENL
+       [EXISTS_TAC `&1` THEN
+        ASM_SIMP_TAC[VECTOR_MUL_RZERO; REAL_LT_01; NORM_0];
+        EXISTS_TAC `e / &2 / norm(x:real^N)` THEN
+        ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; NORM_POS_LT] THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN
+        REWRITE_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NUM; REAL_ABS_NORM] THEN
+        ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0] THEN ASM_REAL_ARITH_TAC]];
+    ALL_TAC] THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `t:(real^N->bool)->real` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `x:real^N = inv(inf(IMAGE t (f:(real^N->bool)->bool))) %
+                           inf(IMAGE t f) % x`
+  SUBST1_TAC THENL
+   [GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_MUL_LID] THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC REAL_MUL_LINV THEN
+    MATCH_MP_TAC REAL_LT_IMP_NZ THEN
+    ASM_SIMP_TAC[REAL_LT_INF_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+    ASM_SIMP_TAC[FORALL_IN_IMAGE];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(REWRITE_RULE[conic] CONIC_CONVEX_CONE_HULL) THEN
+  ASM_SIMP_TAC[REAL_LE_INV_EQ; REAL_LE_INF_FINITE; FINITE_IMAGE;
+               IMAGE_EQ_EMPTY; REAL_LT_IMP_LE; FORALL_IN_IMAGE] THEN
+  MATCH_MP_TAC(SET_RULE `!s t. s SUBSET t /\ x IN s ==> x IN t`) THEN
+  EXISTS_TAC `convex hull ((vec 0:real^N) INSERT s)` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HULL_MINIMAL THEN
+    REWRITE_TAC[CONVEX_CONVEX_CONE_HULL] THEN
+    ASM_SIMP_TAC[INSERT_SUBSET; HULL_SUBSET; CONVEX_CONE_HULL_CONTAINS_0];
+    ASM_REWRITE_TAC[IN_INTERS] THEN X_GEN_TAC `h:real^N->bool` THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN `inf(IMAGE (t:(real^N->bool)->real) f) % x:real^N =
+                  (&1 - inf(IMAGE t f) / t h) % vec 0 +
+                  (inf(IMAGE t f) / t h) % t h % x`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[VECTOR_MUL_ASSOC; VECTOR_MUL_RZERO; VECTOR_ADD_LID;
+                   REAL_DIV_RMUL; REAL_LT_IMP_NZ];
+      ALL_TAC] THEN
+    MATCH_MP_TAC IN_CONVEX_SET THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ] THEN
+    REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID] THEN
+    ASM_SIMP_TAC[REAL_INF_LE_FINITE; REAL_LE_INF_FINITE;
+                 FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE; EXISTS_IN_IMAGE] THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN REPEAT CONJ_TAC THENL
+     [SUBGOAL_THEN `h = {x:real^N | a h dot x <= b h}` SUBST1_TAC THENL
+       [ASM_MESON_TAC[]; ASM_SIMP_TAC[CONVEX_HALFSPACE_LE]];
+      SUBGOAL_THEN `(vec 0:real^N) IN convex hull (vec 0 INSERT s)` MP_TAC
+      THENL [SIMP_TAC[HULL_INC; IN_INSERT]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[IN_INTERS] THEN ASM_MESON_TAC[];
+      ASM SET_TAC[REAL_LE_REFL]]]);;
+
+let CLOSED_CONVEX_CONE_HULL = prove
+ (`!s:real^N->bool. FINITE s ==> closed(convex_cone hull s)`,
+  MESON_TAC[POLYHEDRON_IMP_CLOSED; POLYHEDRON_CONVEX_CONE_HULL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* And conversely, a polyhedral cone is finitely generated.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let FINITELY_GENERATED_CONIC_POLYHEDRON = prove
+ (`!s:real^N->bool.
+        polyhedron s /\ conic s /\ ~(s = {})
+        ==> ?c. FINITE c /\ s = convex_cone hull c`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?p:real^N->bool. polytope p /\ vec 0 IN interior p`
+  STRIP_ASSUME_TAC THENL
+   [EXISTS_TAC `interval[--vec 1:real^N,vec 1:real^N]` THEN
+    REWRITE_TAC[POLYTOPE_INTERVAL; INTERIOR_CLOSED_INTERVAL] THEN
+    SIMP_TAC[IN_INTERVAL; VECTOR_NEG_COMPONENT; VEC_COMPONENT] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `polytope(s INTER p:real^N->bool)` MP_TAC THENL
+   [REWRITE_TAC[POLYTOPE_EQ_BOUNDED_POLYHEDRON] THEN
+    ASM_SIMP_TAC[BOUNDED_INTER; POLYTOPE_IMP_BOUNDED]THEN
+    ASM_SIMP_TAC[POLYHEDRON_INTER; POLYTOPE_IMP_POLYHEDRON];
+    REWRITE_TAC[polytope] THEN MATCH_MP_TAC MONO_EXISTS] THEN
+  X_GEN_TAC `c:real^N->bool` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[SUBSET_HULL; POLYHEDRON_IMP_CONVEX; convex_cone] THEN
+    MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `s INTER p:real^N->bool` THEN
+    REWRITE_TAC[INTER_SUBSET] THEN ASM_REWRITE_TAC[HULL_SUBSET]] THEN
+  REWRITE_TAC[SUBSET] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `?t. &0 < t /\ (t % x:real^N) IN p` STRIP_ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERIOR]) THEN
+    REWRITE_TAC[SUBSET; IN_BALL_0; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `e:real` THEN STRIP_TAC THEN
+    ASM_CASES_TAC `x:real^N = vec 0` THENL
+     [EXISTS_TAC `&1` THEN ASM_REWRITE_TAC[VECTOR_MUL_RZERO; REAL_LT_01] THEN
+      ASM_SIMP_TAC[NORM_0];
+      EXISTS_TAC `e / &2 / norm(x:real^N)` THEN
+      ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; NORM_POS_LT] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      REWRITE_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM; REAL_ABS_NUM] THEN
+      ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0] THEN ASM_REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `x:real^N = inv t % t % x` SUBST1_TAC THENL
+   [ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; VECTOR_MUL_LID;
+                 REAL_LT_IMP_NZ];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(REWRITE_RULE[conic] CONIC_CONVEX_CONE_HULL) THEN
+  ASM_SIMP_TAC[REAL_LE_INV_EQ; REAL_LT_IMP_LE] THEN
+  MATCH_MP_TAC(SET_RULE `!s. x IN s /\ s SUBSET t ==> x IN t`) THEN
+  EXISTS_TAC `convex hull c:real^N->bool` THEN
+  REWRITE_TAC[CONVEX_HULL_SUBSET_CONVEX_CONE_HULL] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[IN_INTER] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [conic]) THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_LE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Decomposition of polyhedron into cone plus polytope and more corollaries. *)
+(* ------------------------------------------------------------------------- *)
+
+let POLYHEDRON_POLYTOPE_SUMS = prove
+ (`!s t:real^N->bool.
+    polyhedron s /\ polytope t ==> polyhedron {x + y | x IN s /\ y IN t}`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[POLYHEDRON_EQ_FINITE_EXPOSED_FACES] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CLOSED_COMPACT_SUMS THEN
+    ASM_SIMP_TAC[POLYHEDRON_IMP_CLOSED; POLYTOPE_IMP_COMPACT];
+    MATCH_MP_TAC CONVEX_SUMS THEN
+    ASM_SIMP_TAC[POLYHEDRON_IMP_CONVEX; POLYTOPE_IMP_CONVEX];
+    MATCH_MP_TAC FINITE_SUBSET THEN
+    EXISTS_TAC `{ {x + y:real^N | x IN k /\ y IN l} |
+                  k exposed_face_of s /\ l exposed_face_of t}` THEN
+    CONJ_TAC THENL
+     [ONCE_REWRITE_TAC[SET_RULE `k exposed_face_of s <=>
+                                 k IN {f | f exposed_face_of s}`] THEN
+      MATCH_MP_TAC FINITE_PRODUCT_DEPENDENT THEN
+      ASM_SIMP_TAC[FINITE_POLYHEDRON_EXPOSED_FACES;
+                   POLYTOPE_IMP_POLYHEDRON];
+      REWRITE_TAC[SUBSET; IN_ELIM_THM; GSYM CONJ_ASSOC] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC EXPOSED_FACE_OF_SUMS THEN
+      ASM_SIMP_TAC[POLYHEDRON_IMP_CONVEX; POLYTOPE_IMP_CONVEX]]]);;
+
+let POLYHEDRON_AS_CONE_PLUS_CONV = prove
+ (`!s:real^N->bool.
+        polyhedron s <=> ?t u. FINITE t /\ FINITE u /\
+                               s = {x + y | x IN convex_cone hull t /\
+                                            y IN convex hull u}`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[polyhedron; LEFT_IMP_EXISTS_THM];
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC POLYHEDRON_POLYTOPE_SUMS THEN
+    ASM_SIMP_TAC[POLYTOPE_CONVEX_HULL; POLYHEDRON_CONVEX_CONE_HULL]] THEN
+  REWRITE_TAC[polyhedron; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `f:(real^N->bool)->bool` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (ASSUME_TAC o SYM) MP_TAC) THEN
+  GEN_REWRITE_TAC (LAND_CONV o REDEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN MAP_EVERY X_GEN_TAC
+   [`a:(real^N->bool)->real^N`; `b:(real^N->bool)->real`] THEN
+  ONCE_REWRITE_TAC[MESON[] `h = {x | P x} <=> {x | P x} = h`] THEN
+  DISCH_TAC THEN
+  ABBREV_TAC
+   `s':real^(N,1)finite_sum->bool =
+        {x | &0 <= drop(sndcart x) /\
+             !h:real^N->bool.
+                h IN f ==> a h dot (fstcart x) <= b h * drop(sndcart x)}` THEN
+  SUBGOAL_THEN
+   `?t u. FINITE t /\ FINITE u /\
+          (!y:real^(N,1)finite_sum. y IN t ==> drop(sndcart y) = &0) /\
+          (!y. y IN u ==> drop(sndcart y) = &1) /\
+          s' = convex_cone hull (t UNION u)`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPEC `s':real^(N,1)finite_sum->bool`
+        FINITELY_GENERATED_CONIC_POLYHEDRON) THEN
+    ANTS_TAC THENL
+     [EXPAND_TAC "s'" THEN REPEAT CONJ_TAC THENL
+       [REWRITE_TAC[polyhedron] THEN
+        EXISTS_TAC
+         `{ x:real^(N,1)finite_sum |
+            pastecart (vec 0) (--vec 1) dot x <= &0} INSERT
+          { {x | pastecart (a h) (--lift(b h)) dot x <= &0} |
+            (h:real^N->bool) IN f}` THEN
+        REWRITE_TAC[FINITE_INSERT; INTERS_INSERT; SIMPLE_IMAGE] THEN
+        ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_INSERT; FORALL_IN_IMAGE] THEN
+        REPEAT CONJ_TAC THENL
+         [EXPAND_TAC "s'" THEN
+          REWRITE_TAC[EXTENSION; IN_ELIM_THM; FORALL_PASTECART; IN_INTER;
+           DOT_PASTECART; INTERS_IMAGE; FSTCART_PASTECART;
+           SNDCART_PASTECART; DOT_1; GSYM drop; DROP_NEG; LIFT_DROP] THEN
+          REWRITE_TAC[DROP_VEC; DOT_LZERO; REAL_MUL_LNEG; GSYM real_sub] THEN
+          REWRITE_TAC[REAL_MUL_LID; REAL_ARITH `x - y <= &0 <=> x <= y`];
+          EXISTS_TAC `pastecart (vec 0) (--vec 1):real^(N,1)finite_sum` THEN
+          EXISTS_TAC `&0` THEN
+          REWRITE_TAC[PASTECART_EQ_VEC; VECTOR_NEG_EQ_0; VEC_EQ] THEN
+          ARITH_TAC;
+          X_GEN_TAC `h:real^N->bool` THEN DISCH_TAC THEN MAP_EVERY EXISTS_TAC
+           [`pastecart (a(h:real^N->bool)) (--lift(b h)):real^(N,1)finite_sum`;
+            `&0`] THEN
+          ASM_SIMP_TAC[PASTECART_EQ_VEC]];
+        REWRITE_TAC[conic; IN_ELIM_THM; FSTCART_CMUL; SNDCART_CMUL] THEN
+        SIMP_TAC[DROP_CMUL; DOT_RMUL; REAL_LE_MUL] THEN
+        MESON_TAC[REAL_LE_LMUL; REAL_MUL_AC];
+        REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+        EXISTS_TAC `vec 0:real^(N,1)finite_sum` THEN
+        REWRITE_TAC[IN_ELIM_THM; FSTCART_VEC; SNDCART_VEC] THEN
+        REWRITE_TAC[DROP_VEC; DOT_RZERO; REAL_LE_REFL; REAL_MUL_RZERO]];
+      DISCH_THEN(X_CHOOSE_THEN `c:real^(N,1)finite_sum->bool`
+        STRIP_ASSUME_TAC) THEN
+      MAP_EVERY EXISTS_TAC
+       [`{x:real^(N,1)finite_sum | x IN c /\ drop(sndcart x) = &0}`;
+        `IMAGE (\x. inv(drop(sndcart x)) % x)
+           {x:real^(N,1)finite_sum | x IN c /\ ~(drop(sndcart x) = &0)}`] THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; FINITE_RESTRICT; FORALL_IN_IMAGE] THEN
+      SIMP_TAC[IN_ELIM_THM; SNDCART_CMUL; DROP_CMUL; REAL_MUL_LINV] THEN
+      SUBGOAL_THEN
+       `!x:real^(N,1)finite_sum. x IN c ==> &0 <= drop(sndcart x)`
+      ASSUME_TAC THENL
+       [GEN_TAC THEN DISCH_TAC THEN
+        SUBGOAL_THEN `(x:real^(N,1)finite_sum) IN s'` MP_TAC THENL
+         [ASM_MESON_TAC[HULL_INC]; EXPAND_TAC "s'"] THEN
+        SIMP_TAC[IN_ELIM_THM];
+        ALL_TAC] THEN
+      MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THEN
+      MATCH_MP_TAC HULL_MINIMAL THEN
+      REWRITE_TAC[CONVEX_CONE_CONVEX_CONE_HULL; UNION_SUBSET] THEN
+      SIMP_TAC[SUBSET; IN_ELIM_THM; HULL_INC; FORALL_IN_IMAGE] THEN
+      X_GEN_TAC `x:real^(N,1)finite_sum` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `x:real^(N,1)finite_sum`) THEN
+      ASM_SIMP_TAC[CONVEX_CONE_HULL_MUL; HULL_INC; REAL_LE_INV_EQ] THEN
+      ASM_REWRITE_TAC[REAL_ARITH `&0 <= x <=> x = &0 \/ &0 < x`] THEN
+      STRIP_TAC THENL
+       [MATCH_MP_TAC HULL_INC THEN ASM_REWRITE_TAC[IN_UNION; IN_ELIM_THM];
+        SUBGOAL_THEN
+         `x:real^(N,1)finite_sum =
+                drop(sndcart x) % inv(drop(sndcart x)) % x`
+        SUBST1_TAC THENL
+         [ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; REAL_LT_IMP_NZ] THEN
+          REWRITE_TAC[VECTOR_MUL_LID];
+          MATCH_MP_TAC CONVEX_CONE_HULL_MUL THEN
+          ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN MATCH_MP_TAC HULL_INC THEN
+          REWRITE_TAC[IN_UNION] THEN DISJ2_TAC THEN
+          REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `x:real^(N,1)finite_sum` THEN
+          ASM_SIMP_TAC[IN_ELIM_THM; REAL_LT_IMP_NZ]]]];
+    EXISTS_TAC `IMAGE fstcart (t:real^(N,1)finite_sum->bool)` THEN
+    EXISTS_TAC `IMAGE fstcart (u:real^(N,1)finite_sum->bool)` THEN
+    ASM_SIMP_TAC[FINITE_IMAGE] THEN
+    SUBGOAL_THEN `s = {x:real^N | pastecart x (vec 1:real^1) IN s'}`
+    SUBST1_TAC THENL
+     [MAP_EVERY EXPAND_TAC ["s"; "s'"] THEN
+      REWRITE_TAC[IN_ELIM_THM; SNDCART_PASTECART; DROP_VEC; REAL_POS] THEN
+      GEN_REWRITE_TAC I [EXTENSION] THEN
+      REWRITE_TAC[FSTCART_PASTECART; IN_ELIM_THM; IN_INTERS; REAL_MUL_RID] THEN
+      ASM SET_TAC[];
+      ASM_REWRITE_TAC[CONVEX_CONE_HULL_UNION]] THEN
+    REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN X_GEN_TAC `z:real^N` THEN
+    SIMP_TAC[CONVEX_CONE_HULL_LINEAR_IMAGE; CONVEX_HULL_LINEAR_IMAGE;
+             LINEAR_FSTCART] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC; RIGHT_EXISTS_AND_THM] THEN
+    REWRITE_TAC[EXISTS_IN_IMAGE] THEN
+    AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+    X_GEN_TAC `a:real^(N,1)finite_sum` THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC(TAUT `(p ==> (q <=> r)) ==> (p /\ q <=> p /\ r)`) THEN
+    DISCH_TAC THEN AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+    X_GEN_TAC `b:real^(N,1)finite_sum` THEN REWRITE_TAC[PASTECART_EQ] THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; FSTCART_ADD;
+                SNDCART_ADD] THEN
+    ASM_CASES_TAC `fstcart(a:real^(N,1)finite_sum) +
+                   fstcart(b:real^(N,1)finite_sum) = z` THEN
+    ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `sndcart(a:real^(N,1)finite_sum) = vec 0` SUBST1_TAC THENL
+     [UNDISCH_TAC `(a:real^(N,1)finite_sum) IN convex_cone hull t` THEN
+      SPEC_TAC(`a:real^(N,1)finite_sum`,`a:real^(N,1)finite_sum`) THEN
+      MATCH_MP_TAC HULL_INDUCT THEN ASM_SIMP_TAC[GSYM DROP_EQ; DROP_VEC] THEN
+      REWRITE_TAC[convex_cone; convex; conic; IN_ELIM_THM] THEN
+      SIMP_TAC[SNDCART_ADD; SNDCART_CMUL; DROP_ADD; DROP_CMUL] THEN
+      REWRITE_TAC[REAL_MUL_RZERO; REAL_ADD_RID; GSYM MEMBER_NOT_EMPTY] THEN
+      EXISTS_TAC `vec 0:real^(N,1)finite_sum` THEN
+      REWRITE_TAC[IN_ELIM_THM; SNDCART_VEC; DROP_VEC];
+      REWRITE_TAC[VECTOR_ADD_LID]] THEN
+    ASM_CASES_TAC `u:real^(N,1)finite_sum->bool = {}` THENL
+     [ASM_REWRITE_TAC[CONVEX_CONE_HULL_EMPTY; CONVEX_HULL_EMPTY] THEN
+      REWRITE_TAC[IN_SING; NOT_IN_EMPTY] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+      ASM_REWRITE_TAC[SNDCART_VEC; VEC_EQ] THEN ARITH_TAC;
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[CONVEX_CONE_HULL_CONVEX_HULL_NONEMPTY; IN_ELIM_THM] THEN
+    SUBGOAL_THEN
+     `!y:real^(N,1)finite_sum. y IN convex hull u ==> sndcart y = vec 1`
+     (LABEL_TAC "*")
+    THENL
+     [MATCH_MP_TAC HULL_INDUCT THEN ASM_SIMP_TAC[GSYM DROP_EQ; DROP_VEC] THEN
+      REWRITE_TAC[convex; IN_ELIM_THM] THEN
+      SIMP_TAC[SNDCART_ADD; SNDCART_CMUL; DROP_ADD; DROP_CMUL] THEN
+      SIMP_TAC[REAL_MUL_RID];
+      ALL_TAC] THEN
+    EQ_TAC THEN REWRITE_TAC[LEFT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THENL
+     [MAP_EVERY X_GEN_TAC [`c:real`; `d:real^(N,1)finite_sum`] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+      ASM_SIMP_TAC[SNDCART_CMUL; VECTOR_MUL_EQ_0; VECTOR_ARITH
+       `x:real^N = c % x <=> (c - &1) % x = vec 0`] THEN
+      ASM_SIMP_TAC[REAL_SUB_0; VEC_EQ; ARITH_EQ; VECTOR_MUL_LID];
+      DISCH_TAC THEN ASM_SIMP_TAC[] THEN EXISTS_TAC `&1` THEN
+      ASM_REWRITE_TAC[REAL_POS; VECTOR_MUL_LID] THEN ASM_MESON_TAC[]]]);;
+
+let POLYHEDRON_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ polyhedron s ==> polyhedron(IMAGE f s)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[POLYHEDRON_AS_CONE_PLUS_CONV; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`t:real^M->bool`; `u:real^M->bool`] THEN STRIP_TAC THEN
+  EXISTS_TAC `IMAGE (f:real^M->real^N) t` THEN
+  EXISTS_TAC `IMAGE (f:real^M->real^N) u` THEN
+  ASM_SIMP_TAC[FINITE_IMAGE] THEN
+  ASM_SIMP_TAC[CONVEX_CONE_HULL_LINEAR_IMAGE; CONVEX_HULL_LINEAR_IMAGE] THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_ELIM_THM] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP LINEAR_ADD) THEN MESON_TAC[]);;
+
+let POLYHEDRON_SUMS = prove
+ (`!s t:real^N->bool.
+    polyhedron s /\ polyhedron t ==> polyhedron {x + y | x IN s /\ y IN t}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[POLYHEDRON_AS_CONE_PLUS_CONV] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC
+   [`t1:real^N->bool`; `u1:real^N->bool`;
+    `t2:real^N->bool`; `u2:real^N->bool`] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  EXISTS_TAC `t1 UNION t2:real^N->bool` THEN
+  EXISTS_TAC `{u + v:real^N | u IN u1 /\ v IN u2}` THEN
+  REWRITE_TAC[CONVEX_CONE_HULL_UNION; CONVEX_HULL_SUMS] THEN
+  ASM_SIMP_TAC[FINITE_PRODUCT_DEPENDENT; FINITE_UNION] THEN
+  REWRITE_TAC[SET_RULE
+   `{h x y | x IN {f a b | P a /\ Q b} /\
+             y IN {g a b | R a /\ S b}} =
+    {h (f a b) (g c d) | P a /\ Q b /\ R c /\ S d}`] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN MESON_TAC[VECTOR_ADD_AC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Farkas's lemma (2 variants) and stronger separation for polyhedra.        *)
+(* ------------------------------------------------------------------------- *)
+
+let FARKAS_LEMMA = prove
+ (`!A:real^N^M b.
+        (?x:real^N.
+            A ** x = b /\
+            (!i. 1 <= i /\ i <= dimindex(:N) ==> &0 <= x$i)) <=>
+        ~(?y:real^M.
+            b dot y < &0 /\
+            (!i. 1 <= i /\ i <= dimindex(:N) ==> &0 <= (transp A ** y)$i))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(TAUT
+   `(q ==> ~p) /\ (~p ==> q) ==> (p <=> ~q)`) THEN
+  CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `y dot ((A:real^N^M) ** x - b) = &0` MP_TAC THENL
+     [ASM_REWRITE_TAC[VECTOR_SUB_REFL; DOT_RZERO]; ALL_TAC] THEN
+    RULE_ASSUM_TAC(ONCE_REWRITE_RULE[DOT_SYM]) THEN
+    REWRITE_TAC[DOT_RSUB; REAL_SUB_0] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `y < &0 ==> &0 <= x ==> ~(x = y)`)) THEN
+    ONCE_REWRITE_TAC[GSYM DOT_LMUL_MATRIX] THEN
+    REWRITE_TAC[VECTOR_MATRIX_MUL_TRANSP; dot] THEN
+    MATCH_MP_TAC SUM_POS_LE THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; IN_NUMSEG; FINITE_NUMSEG];
+    DISCH_TAC THEN MP_TAC(ISPECL
+     [`{(A:real^N^M) ** (x:real^N) |
+        !i. 1 <= i /\ i <= dimindex(:N) ==> &0 <= x$i}`;
+      `b:real^M`] SEPARATING_HYPERPLANE_CLOSED_POINT) THEN
+    REWRITE_TAC[FORALL_IN_GSPEC] THEN ANTS_TAC THENL
+     [REWRITE_TAC[IN_ELIM_THM; CONJ_ASSOC] THEN
+      CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+      SIMP_TAC[CONVEX_POSITIVE_ORTHANT; CONVEX_LINEAR_IMAGE;
+               MATRIX_VECTOR_MUL_LINEAR] THEN
+      MATCH_MP_TAC POLYHEDRON_IMP_CLOSED THEN
+      MATCH_MP_TAC POLYHEDRON_LINEAR_IMAGE THEN
+      REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR; POLYHEDRON_POSITIVE_ORTHANT];
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `y:real^M` THEN
+      DISCH_THEN(X_CHOOSE_THEN `c:real` STRIP_ASSUME_TAC) THEN
+      ONCE_REWRITE_TAC[DOT_SYM] THEN
+      FIRST_ASSUM(MP_TAC o SPEC `vec 0:real^N`) THEN
+      REWRITE_TAC[MATRIX_VECTOR_MUL_RZERO; DOT_RZERO] THEN
+      REWRITE_TAC[real_gt; VEC_COMPONENT; REAL_LE_REFL] THEN
+      DISCH_TAC THEN CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+      X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+      ONCE_REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC
+       `c / (transp(A:real^N^M) ** (y:real^M))$k % basis k:real^N`) THEN
+      ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; BASIS_COMPONENT] THEN
+      ONCE_REWRITE_TAC[GSYM DOT_LMUL_MATRIX] THEN
+      ASM_SIMP_TAC[DOT_RMUL; DOT_BASIS; VECTOR_MATRIX_MUL_TRANSP] THEN
+      ASM_SIMP_TAC[REAL_FIELD `y < &0 ==> x / y * y = x`] THEN
+      REWRITE_TAC[REAL_LT_REFL; real_gt] THEN
+      GEN_TAC THEN COND_CASES_TAC THEN
+      ASM_REWRITE_TAC[REAL_MUL_RZERO; REAL_LE_REFL; REAL_MUL_RID] THEN
+      ONCE_REWRITE_TAC[REAL_ARITH `x / y:real = --x * -- inv y`] THEN
+      MATCH_MP_TAC REAL_LE_MUL THEN
+      REWRITE_TAC[REAL_ARITH `&0 <= --x <=> ~(&0 < x)`; REAL_LT_INV_EQ] THEN
+      ASM_REAL_ARITH_TAC]]);;
+
+let FARKAS_LEMMA_ALT = prove
+ (`!A:real^N^M b.
+        (?x:real^N.
+            (!i. 1 <= i /\ i <= dimindex(:M) ==> (A ** x)$i <= b$i)) <=>
+        ~(?y:real^M.
+            (!i. 1 <= i /\ i <= dimindex(:M) ==> &0 <= y$i) /\
+            y ** A = vec 0 /\ b dot y < &0)`,
+  REPEAT GEN_TAC THEN
+  MATCH_MP_TAC(TAUT `~(p /\ q) /\ (~p ==> q) ==> (p <=> ~q)`) THEN
+  REPEAT STRIP_TAC THENL
+   [SUBGOAL_THEN `&0 <= (b - (A:real^N^M) ** x) dot y` MP_TAC THENL
+     [REWRITE_TAC[dot] THEN MATCH_MP_TAC SUM_POS_LE THEN
+      REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_MUL THEN
+      ASM_SIMP_TAC[VECTOR_SUB_COMPONENT; REAL_SUB_LE];
+      REWRITE_TAC[DOT_LSUB; REAL_SUB_LE] THEN REWRITE_TAC[REAL_NOT_LE] THEN
+      GEN_REWRITE_TAC RAND_CONV [DOT_SYM] THEN
+      REWRITE_TAC[GSYM DOT_LMUL_MATRIX] THEN
+      ASM_REWRITE_TAC[DOT_LZERO]];
+    MP_TAC(ISPECL
+     [`{(A:real^N^M) ** (x:real^N) + s |x,s|
+        !i. 1 <= i /\ i <= dimindex(:M) ==> &0 <= s$i}`;
+      `b:real^M`] SEPARATING_HYPERPLANE_CLOSED_POINT) THEN
+    REWRITE_TAC[FORALL_IN_GSPEC] THEN ANTS_TAC THENL
+     [REWRITE_TAC[IN_ELIM_THM; CONJ_ASSOC] THEN CONJ_TAC THENL
+       [ONCE_REWRITE_TAC[SET_RULE
+         `{f x + y | x,y | P y} =
+          {z + y | z,y | z IN IMAGE (f:real^M->real^N) (:real^M) /\
+                         y IN {w | P w}}`] THEN
+        SIMP_TAC[CONVEX_SUMS; CONVEX_POSITIVE_ORTHANT; CONVEX_LINEAR_IMAGE;
+                 MATRIX_VECTOR_MUL_LINEAR; CONVEX_UNIV] THEN
+        MATCH_MP_TAC POLYHEDRON_IMP_CLOSED THEN
+        MATCH_MP_TAC POLYHEDRON_SUMS THEN
+        ASM_SIMP_TAC[POLYHEDRON_LINEAR_IMAGE; POLYHEDRON_UNIV;
+          MATRIX_VECTOR_MUL_LINEAR; POLYHEDRON_POSITIVE_ORTHANT];
+        POP_ASSUM MP_TAC THEN REWRITE_TAC[CONTRAPOS_THM] THEN
+        MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN
+        ASM_SIMP_TAC[VECTOR_ADD_COMPONENT; REAL_LE_ADDR]];
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `y:real^M` THEN
+      DISCH_THEN(X_CHOOSE_THEN `c:real` STRIP_ASSUME_TAC) THEN
+      ONCE_REWRITE_TAC[DOT_SYM] THEN
+      FIRST_ASSUM(MP_TAC o SPECL [`vec 0:real^N`; `vec 0:real^M`]) THEN
+      REWRITE_TAC[MATRIX_VECTOR_MUL_RZERO; VECTOR_ADD_RID; DOT_RZERO] THEN
+      REWRITE_TAC[real_gt; VEC_COMPONENT; REAL_LE_REFL] THEN
+      DISCH_TAC THEN REWRITE_TAC[CONJ_ASSOC] THEN
+      CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN CONJ_TAC THENL
+       [X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+        ONCE_REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN
+        FIRST_X_ASSUM(MP_TAC o SPECL
+         [`vec 0:real^N`; `--c / --((y:real^M)$k) % basis k:real^M`]) THEN
+        ASM_SIMP_TAC[MATRIX_VECTOR_MUL_RZERO; VECTOR_ADD_LID;
+                     DOT_RMUL; DOT_BASIS; REAL_FIELD
+                      `y < &0 ==> c / --y * y = --c`] THEN
+        SIMP_TAC[REAL_NEG_NEG; REAL_LT_REFL; VECTOR_MUL_COMPONENT; real_gt] THEN
+        ASM_SIMP_TAC[BASIS_COMPONENT] THEN REPEAT STRIP_TAC THEN
+        COND_CASES_TAC THEN
+        ASM_REWRITE_TAC[REAL_MUL_RZERO; REAL_MUL_RID; REAL_LE_REFL] THEN
+        MATCH_MP_TAC REAL_LE_DIV THEN ASM_REAL_ARITH_TAC;
+        FIRST_X_ASSUM(MP_TAC o SPECL
+         [`c / norm((y:real^M) ** (A:real^N^M)) pow 2 %
+           (transp A ** y)`; `vec 0:real^M`]) THEN
+        SIMP_TAC[VEC_COMPONENT; REAL_LE_REFL; VECTOR_ADD_RID] THEN
+        ONCE_REWRITE_TAC[GSYM DOT_LMUL_MATRIX] THEN
+        REWRITE_TAC[GSYM VECTOR_MATRIX_MUL_TRANSP; DOT_RMUL] THEN
+        ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN
+        ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_POW_2; DOT_EQ_0] THEN
+        REAL_ARITH_TAC]]]);;
+
+let SEPARATING_HYPERPLANE_POLYHEDRA = prove
+ (`!s t:real^N->bool.
+        polyhedron s /\ polyhedron t /\ ~(s = {}) /\ ~(t = {}) /\ DISJOINT s t
+        ==> ?a b. ~(a = vec 0) /\
+                  (!x. x IN s ==> a dot x < b) /\
+                  (!x. x IN t ==> a dot x > b)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `{x + y:real^N | x IN s /\ y IN IMAGE (--) t}`
+        SEPARATING_HYPERPLANE_CLOSED_0) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[CONVEX_SUMS; CONVEX_NEGATIONS; POLYHEDRON_IMP_CONVEX] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC POLYHEDRON_IMP_CLOSED THEN
+      MATCH_MP_TAC POLYHEDRON_SUMS THEN ASM_SIMP_TAC[POLYHEDRON_NEGATIONS];
+      REWRITE_TAC[IN_IMAGE; IN_ELIM_THM] THEN
+      REWRITE_TAC[VECTOR_ARITH `y = --x:real^N <=> --y = x`] THEN
+      REWRITE_TAC[UNWIND_THM1] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+      REWRITE_TAC[VECTOR_ARITH `vec 0:real^N = x + y <=> y = --x`] THEN
+      REWRITE_TAC[UNWIND_THM2; VECTOR_NEG_NEG] THEN ASM SET_TAC[]];
+    REWRITE_TAC[FORALL_IN_GSPEC; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; GSYM VECTOR_SUB; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `k:real`] THEN
+    REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; DOT_RSUB] THEN STRIP_TAC THEN
+    EXISTS_TAC `--a:real^N` THEN ASM_REWRITE_TAC[VECTOR_NEG_EQ_0] THEN
+    MP_TAC(ISPEC `IMAGE (\x:real^N. a dot x) s` INF) THEN
+    MP_TAC(ISPEC `IMAGE (\x:real^N. a dot x) t` SUP) THEN
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE; IMAGE_EQ_EMPTY] THEN
+    MAP_EVERY ABBREV_TAC
+     [`u = inf(IMAGE (\x:real^N. a dot x) s)`;
+      `v = sup(IMAGE (\x:real^N. a dot x) t)`] THEN
+    ANTS_TAC THENL
+     [MP_TAC(GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]
+        (ASSUME `~(s:real^N->bool = {})`)) THEN
+      DISCH_THEN(X_CHOOSE_TAC `z:real^N`) THEN
+      EXISTS_TAC `a dot (z:real^N) - k` THEN
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL [`z:real^N`; `x:real^N`]) THEN
+      ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+      STRIP_TAC] THEN
+    ANTS_TAC THENL
+     [MP_TAC(GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]
+        (ASSUME `~(t:real^N->bool = {})`)) THEN
+      DISCH_THEN(X_CHOOSE_TAC `z:real^N`) THEN
+      EXISTS_TAC `a dot (z:real^N) + k` THEN
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `z:real^N`]) THEN
+      ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+      STRIP_TAC] THEN
+    SUBGOAL_THEN `k <= u - v` ASSUME_TAC THENL
+     [REWRITE_TAC[REAL_LE_SUB_LADD] THEN EXPAND_TAC "u" THEN
+      MATCH_MP_TAC REAL_LE_INF THEN
+      ASM_REWRITE_TAC[IMAGE_EQ_EMPTY; FORALL_IN_IMAGE] THEN
+      GEN_TAC THEN DISCH_TAC THEN
+      ONCE_REWRITE_TAC[REAL_ARITH `k + v <= u <=> v <= u - k`] THEN
+      EXPAND_TAC "v" THEN MATCH_MP_TAC REAL_SUP_LE THEN
+      ASM_REWRITE_TAC[IMAGE_EQ_EMPTY; FORALL_IN_IMAGE] THEN
+      ASM_MESON_TAC[REAL_ARITH `x - y > k ==> y <= x - k`];
+      EXISTS_TAC `--((u + v) / &2)` THEN REWRITE_TAC[real_gt] THEN
+      REWRITE_TAC[DOT_LNEG; REAL_LT_NEG2] THEN REPEAT STRIP_TAC THENL
+       [MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `u:real`;
+        MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `v:real`] THEN
+      ASM_SIMP_TAC[] THEN ASM_REAL_ARITH_TAC]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relative and absolute frontier of a polytope.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let RELATIVE_BOUNDARY_OF_CONVEX_HULL = prove
+ (`!s:real^N->bool.
+        ~affine_dependent s
+        ==> (convex hull s) DIFF relative_interior(convex hull s) =
+            UNIONS { convex hull (s DELETE a) | a | a IN s}`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  REPEAT_TCL DISJ_CASES_THEN MP_TAC (ARITH_RULE
+    `CARD(s:real^N->bool) = 0 \/ CARD s = 1 \/ 2 <= CARD s`)
+  THENL
+   [ASM_SIMP_TAC[CARD_EQ_0; CONVEX_HULL_EMPTY] THEN SET_TAC[];
+    DISCH_TAC THEN MP_TAC(HAS_SIZE_CONV `(s:real^N->bool) HAS_SIZE 1`) THEN
+    ASM_SIMP_TAC[HAS_SIZE; LEFT_IMP_EXISTS_THM; CONVEX_HULL_SING] THEN
+    REWRITE_TAC[RELATIVE_INTERIOR_SING; DIFF_EQ_EMPTY] THEN
+    REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN REWRITE_TAC[EMPTY_UNIONS] THEN
+    REWRITE_TAC[FORALL_IN_GSPEC; IN_SING; FORALL_UNWIND_THM2] THEN
+    REWRITE_TAC[CONVEX_HULL_EQ_EMPTY] THEN SET_TAC[];
+    DISCH_TAC THEN
+    ASM_SIMP_TAC[POLYHEDRON_CONVEX_HULL; RELATIVE_BOUNDARY_OF_POLYHEDRON] THEN
+    ASM_SIMP_TAC[FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT_ALT] THEN
+    SET_TAC[]]);;
+
+let RELATIVE_FRONTIER_OF_CONVEX_HULL = prove
+ (`!s:real^N->bool.
+        ~affine_dependent s
+        ==> relative_frontier(convex hull s) =
+            UNIONS { convex hull (s DELETE a) | a | a IN s}`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_INDEPENDENT_IMP_FINITE) THEN
+  ASM_SIMP_TAC[relative_frontier; GSYM RELATIVE_BOUNDARY_OF_CONVEX_HULL] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN MATCH_MP_TAC CLOSURE_CLOSED THEN
+  ASM_SIMP_TAC[COMPACT_IMP_CLOSED; FINITE_IMP_COMPACT; COMPACT_CONVEX_HULL]);;
+
+let FRONTIER_OF_CONVEX_HULL = prove
+ (`!s:real^N->bool.
+        s HAS_SIZE (dimindex(:N) + 1)
+        ==> frontier(convex hull s) =
+               UNIONS { convex hull (s DELETE a) | a | a IN s}`,
+  REWRITE_TAC[HAS_SIZE] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `affine_dependent(s:real^N->bool)` THENL
+   [REWRITE_TAC[frontier] THEN MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `(convex hull s:real^N->bool) DIFF {}` THEN CONJ_TAC THENL
+     [BINOP_TAC THEN
+      ASM_SIMP_TAC[INTERIOR_CONVEX_HULL_EQ_EMPTY; frontier; HAS_SIZE] THEN
+      MATCH_MP_TAC CLOSURE_CLOSED THEN
+      ASM_SIMP_TAC[CLOSURE_CLOSED; COMPACT_IMP_CLOSED; COMPACT_CONVEX_HULL;
+                   FINITE_IMP_COMPACT; FINITE_INSERT; FINITE_EMPTY];
+      REWRITE_TAC[DIFF_EMPTY] THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+      CONJ_TAC THENL
+       [GEN_REWRITE_TAC LAND_CONV [CARATHEODORY_AFF_DIM] THEN
+        ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+        GEN_REWRITE_TAC I [SUBSET] THEN
+        REWRITE_TAC[IN_ELIM_THM; UNIONS_IMAGE] THEN
+        X_GEN_TAC `x:real^N` THEN
+        DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+        MP_TAC(ISPEC `s:real^N->bool` AFFINE_INDEPENDENT_IFF_CARD) THEN
+        ASM_REWRITE_TAC[GSYM INT_OF_NUM_ADD] THEN
+        REWRITE_TAC[INT_ARITH `(x + &1) - &1:int = x`] THEN DISCH_TAC THEN
+        SUBGOAL_THEN `(t:real^N->bool) PSUBSET s` ASSUME_TAC THENL
+         [ASM_REWRITE_TAC[PSUBSET] THEN
+          DISCH_THEN(MP_TAC o AP_TERM `CARD:(real^N->bool)->num`) THEN
+          MATCH_MP_TAC(ARITH_RULE `t:num < s ==> t = s ==> F`) THEN
+          ASM_REWRITE_TAC[ARITH_RULE `x < n + 1 <=> x <= n`] THEN
+          REWRITE_TAC[GSYM INT_OF_NUM_LE] THEN MATCH_MP_TAC INT_LE_TRANS THEN
+          EXISTS_TAC `aff_dim(s:real^N->bool) + &1` THEN
+          ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(INT_ARITH
+           `s:int <= n /\ ~(s = n) ==> s + &1 <= n`) THEN
+          ASM_REWRITE_TAC[AFF_DIM_LE_UNIV];
+          SUBGOAL_THEN `?a:real^N. a IN s /\ ~(a IN t)` MP_TAC THENL
+           [ASM SET_TAC[]; MATCH_MP_TAC MONO_EXISTS] THEN
+          X_GEN_TAC `a:real^N` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+          SUBGOAL_THEN
+           `(convex hull t) SUBSET convex hull (s DELETE (a:real^N))`
+          MP_TAC THENL
+           [MATCH_MP_TAC HULL_MONO THEN ASM SET_TAC[]; ASM SET_TAC[]]];
+        ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN REWRITE_TAC[UNIONS_IMAGE] THEN
+        REWRITE_TAC[SUBSET; IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+        ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+        REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; GSYM SUBSET] THEN
+        REPEAT STRIP_TAC THEN MATCH_MP_TAC HULL_MONO THEN SET_TAC[]]];
+    MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC
+     `(convex hull s) DIFF relative_interior(convex hull s):real^N->bool` THEN
+    CONJ_TAC THENL
+     [ASM_SIMP_TAC[GSYM RELATIVE_BOUNDARY_OF_CONVEX_HULL; frontier] THEN
+      BINOP_TAC THENL
+       [MATCH_MP_TAC CLOSURE_CLOSED THEN
+        ASM_SIMP_TAC[CLOSURE_CLOSED; COMPACT_IMP_CLOSED; COMPACT_CONVEX_HULL;
+                     FINITE_IMP_COMPACT; FINITE_INSERT; FINITE_EMPTY];
+        CONV_TAC SYM_CONV THEN MATCH_MP_TAC RELATIVE_INTERIOR_INTERIOR THEN
+        REWRITE_TAC[AFFINE_HULL_CONVEX_HULL] THEN
+        REWRITE_TAC[GSYM AFF_DIM_EQ_FULL] THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+          [AFFINE_INDEPENDENT_IFF_CARD]) THEN
+        ASM_REWRITE_TAC[GSYM INT_OF_NUM_ADD] THEN INT_ARITH_TAC];
+      ASM_SIMP_TAC[RELATIVE_BOUNDARY_OF_POLYHEDRON;
+                   POLYHEDRON_CONVEX_HULL; FINITE_INSERT; FINITE_EMPTY] THEN
+      ASM_SIMP_TAC[FACET_OF_CONVEX_HULL_AFFINE_INDEPENDENT_ALT] THEN
+      REWRITE_TAC[ARITH_RULE `2 <= n + 1 <=> 1 <= n`; DIMINDEX_GE_1] THEN
+      ASM SET_TAC[]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Special case of a triangle.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let RELATIVE_BOUNDARY_OF_TRIANGLE = prove
+ (`!a b c:real^N.
+        ~collinear {a,b,c}
+        ==> convex hull {a,b,c} DIFF relative_interior(convex hull {a,b,c}) =
+            segment[a,b] UNION segment[b,c] UNION segment[c,a]`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[SET_RULE `s UNION t UNION u = t UNION u UNION s`] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV
+   [COLLINEAR_3_EQ_AFFINE_DEPENDENT]) THEN
+  REWRITE_TAC[DE_MORGAN_THM; SEGMENT_CONVEX_HULL] THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[RELATIVE_BOUNDARY_OF_CONVEX_HULL] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+  REWRITE_TAC[IMAGE_CLAUSES; UNIONS_INSERT; UNIONS_0; UNION_EMPTY] THEN
+  REPEAT BINOP_TAC THEN REWRITE_TAC[] THEN ASM SET_TAC[]);;
+
+let RELATIVE_FRONTIER_OF_TRIANGLE = prove
+ (`!a b c:real^N.
+        ~collinear {a,b,c}
+        ==> relative_frontier(convex hull {a,b,c}) =
+            segment[a,b] UNION segment[b,c] UNION segment[c,a]`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[GSYM RELATIVE_BOUNDARY_OF_TRIANGLE; relative_frontier] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN MATCH_MP_TAC CLOSURE_CLOSED THEN
+  ASM_SIMP_TAC[COMPACT_IMP_CLOSED; FINITE_IMP_COMPACT; COMPACT_CONVEX_HULL;
+               FINITE_INSERT; FINITE_EMPTY]);;
+
+let FRONTIER_OF_TRIANGLE = prove
+ (`!a b c:real^2.
+        frontier(convex hull {a,b,c}) =
+            segment[a,b] UNION segment[b,c] UNION segment[c,a]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN
+  ONCE_REWRITE_TAC[SET_RULE `s UNION t UNION u = t UNION u UNION s`] THEN
+  MAP_EVERY (fun t -> ASM_CASES_TAC t THENL
+   [ASM_REWRITE_TAC[INSERT_AC; UNION_ACI] THEN
+    SIMP_TAC[GSYM SEGMENT_CONVEX_HULL; frontier; CLOSURE_SEGMENT;
+             INTERIOR_SEGMENT; DIMINDEX_2; LE_REFL; DIFF_EMPTY] THEN
+    REWRITE_TAC[CONVEX_HULL_SING] THEN
+    REWRITE_TAC[SET_RULE `s = s UNION {a} <=> a IN s`;
+                SET_RULE `s = {a} UNION s <=> a IN s`] THEN
+    REWRITE_TAC[ENDS_IN_SEGMENT];
+    ALL_TAC])
+   [`b:real^2 = a`; `c:real^2 = a`; `c:real^2 = b`] THEN
+  SUBGOAL_THEN `{a:real^2,b,c} HAS_SIZE (dimindex(:2) + 1)` ASSUME_TAC THENL
+   [SIMP_TAC[HAS_SIZE; CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN
+    ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; DIMINDEX_2] THEN
+    CONV_TAC NUM_REDUCE_CONV;
+    ASM_SIMP_TAC[FRONTIER_OF_CONVEX_HULL] THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+    REWRITE_TAC[IMAGE_CLAUSES; UNIONS_INSERT; UNIONS_0; UNION_EMPTY] THEN
+    REPEAT BINOP_TAC THEN REWRITE_TAC[] THEN ASM SET_TAC[]]);;
+
+let INSIDE_OF_TRIANGLE = prove
+ (`!a b c:real^2.
+        inside(segment[a,b] UNION segment[b,c] UNION segment[c,a]) =
+                interior(convex hull {a,b,c})`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM FRONTIER_OF_TRIANGLE] THEN
+  MATCH_MP_TAC INSIDE_FRONTIER_EQ_INTERIOR THEN
+  REWRITE_TAC[CONVEX_CONVEX_HULL] THEN MATCH_MP_TAC BOUNDED_CONVEX_HULL THEN
+  MATCH_MP_TAC FINITE_IMP_BOUNDED THEN
+  REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY]);;
+
+let INTERIOR_OF_TRIANGLE = prove
+ (`!a b c:real^2.
+        interior(convex hull {a,b,c}) =
+        (convex hull {a,b,c}) DIFF
+        (segment[a,b] UNION segment[b,c] UNION segment[c,a])`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM FRONTIER_OF_TRIANGLE; frontier] THEN
+  MATCH_MP_TAC(SET_RULE `i SUBSET s /\ c = s ==> i = s DIFF (c DIFF i)`) THEN
+  REWRITE_TAC[INTERIOR_SUBSET] THEN MATCH_MP_TAC CLOSURE_CONVEX_HULL THEN
+  SIMP_TAC[FINITE_IMP_COMPACT; FINITE_INSERT; FINITE_EMPTY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A ridge is the intersection of precisely two facets.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let POLYHEDRON_RIDGE_TWO_FACETS = prove
+ (`!p:real^N->bool r.
+    polyhedron p /\ r face_of p /\ ~(r = {}) /\ aff_dim r = aff_dim p - &2
+    ==> ?f1 f2. f1 face_of p /\ aff_dim f1 = aff_dim p - &1 /\
+                f2 face_of p /\ aff_dim f2 = aff_dim p - &1 /\
+                 ~(f1 = f2) /\ r SUBSET f1 /\ r SUBSET f2 /\ f1 INTER f2 = r /\
+                !f. f face_of p /\ aff_dim f = aff_dim p - &1 /\ r SUBSET f
+                    ==> f = f1 \/ f = f2`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`p:real^N->bool`; `r:real^N->bool`] FACE_OF_POLYHEDRON) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[INT_ARITH `~(p:int = p - &2)`]; ALL_TAC] THEN
+  SUBGOAL_THEN `&2 <= aff_dim(p:real^N->bool)` ASSUME_TAC THENL
+   [MP_TAC(ISPEC `r:real^N->bool` AFF_DIM_GE) THEN
+    MP_TAC(ISPEC `r:real^N->bool` AFF_DIM_EQ_MINUS1) THEN
+    ASM_REWRITE_TAC[] THEN INT_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `{f:real^N->bool | f facet_of p /\ r SUBSET f} =
+    {f | f face_of p /\ aff_dim f = aff_dim p - &1 /\ r SUBSET f}`
+  SUBST1_TAC THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM; facet_of] THEN
+    X_GEN_TAC `f:real^N->bool` THEN
+    ASM_CASES_TAC `f:real^N->bool = {}` THEN
+    ASM_REWRITE_TAC[AFF_DIM_EMPTY; GSYM CONJ_ASSOC] THEN ASM_INT_ARITH_TAC;
+    DISCH_THEN(MP_TAC o SYM)] THEN
+  ASM_CASES_TAC
+   `{f:real^N->bool | f face_of p /\ aff_dim f = aff_dim p - &1 /\ r SUBSET f}
+    = {}`
+  THENL
+   [ASM_REWRITE_TAC[INTERS_0] THEN DISCH_THEN(ASSUME_TAC o SYM) THEN
+    UNDISCH_TAC `aff_dim(r:real^N->bool) = aff_dim(p:real^N->bool) - &2` THEN
+    ASM_REWRITE_TAC[AFF_DIM_UNIV; DIMINDEX_3] THEN
+    MP_TAC(ISPEC `p:real^N->bool` AFF_DIM_LE_UNIV) THEN INT_ARITH_TAC;
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; IN_ELIM_THM] THEN
+  X_GEN_TAC `f1:real^N->bool` THEN STRIP_TAC THEN
+  ASM_CASES_TAC
+   `{f:real^N->bool | f face_of p /\ aff_dim f = aff_dim p - &1 /\ r SUBSET f}
+    = {f1}`
+  THENL
+   [ASM_REWRITE_TAC[INTERS_1] THEN
+    ASM_MESON_TAC[INT_ARITH `~(x - &2:int = x - &1)`];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+   `~(s = {a}) ==> a IN s ==> ?b. ~(b = a) /\ b IN s`)) THEN
+  ASM_REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `f2:real^N->bool` THEN STRIP_TAC THEN
+  ASM_CASES_TAC
+   `{f:real^N->bool | f face_of p /\ aff_dim f = aff_dim p - &1 /\ r SUBSET f}
+    = {f1,f2}`
+  THENL
+   [ASM_REWRITE_TAC[INTERS_2] THEN DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC [`f1:real^N->bool`; `f2:real^N->bool`] THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+   `~(s = {a,b})
+    ==> a IN s /\ b IN s ==> ?c. ~(c = a) /\ ~(c = b) /\ c IN s`)) THEN
+  ASM_REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `f3:real^N->bool` THEN STRIP_TAC THEN DISCH_TAC THEN
+  UNDISCH_TAC `aff_dim(r:real^N->bool) = aff_dim(p:real^N->bool) - &2` THEN
+  MATCH_MP_TAC(TAUT `~p ==> p ==> q`) THEN
+  MATCH_MP_TAC(INT_ARITH `~(p - &2:int <= x:int) ==> ~(x = p - &2)`) THEN
+  DISCH_TAC THEN SUBGOAL_THEN
+   `~(f1:real^N->bool = {}) /\
+    ~(f2:real^N->bool = {}) /\
+    ~(f3:real^N->bool = {})`
+  STRIP_ASSUME_TAC THENL
+   [REPEAT CONJ_TAC THEN DISCH_THEN SUBST_ALL_TAC THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[AFF_DIM_EMPTY]) THEN ASM_INT_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPEC `p:real^N->bool` POLYHEDRON_INTER_AFFINE_PARALLEL_MINIMAL) THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM; LEFT_AND_EXISTS_THM] THEN
+  ASM_REWRITE_TAC[NOT_EXISTS_THM] THEN MAP_EVERY X_GEN_TAC
+   [`f:(real^N->bool)->bool`; `a:(real^N->bool)->real^N`;
+    `b:(real^N->bool)->real`] THEN
+  ONCE_REWRITE_TAC[EQ_SYM_EQ] THEN
+  REWRITE_TAC[VECTOR_ARITH `vec 0:real^N = v <=> v = vec 0`] THEN
+  STRIP_TAC THEN MP_TAC(ISPECL
+   [`p:real^N->bool`; `f:(real^N->bool)->bool`; `a:(real^N->bool)->real^N`;
+    `b:(real^N->bool)->real`] FACET_OF_POLYHEDRON_EXPLICIT) THEN
+  ASM_SIMP_TAC[] THEN DISCH_THEN(fun th ->
+    MP_TAC(SPEC `f1:real^N->bool` th) THEN
+    MP_TAC(SPEC `f2:real^N->bool` th) THEN
+    MP_TAC(SPEC `f3:real^N->bool` th)) THEN
+  ASM_REWRITE_TAC[facet_of] THEN
+  DISCH_THEN(X_CHOOSE_THEN `h3:real^N->bool` (STRIP_ASSUME_TAC o GSYM)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `h2:real^N->bool` (STRIP_ASSUME_TAC o GSYM)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `h1:real^N->bool` (STRIP_ASSUME_TAC o GSYM)) THEN
+  SUBGOAL_THEN `~((a:(real^N->bool)->real^N) h1 = a h2) /\
+                 ~(a h2 = a h3) /\ ~(a h1 = a h3)`
+  STRIP_ASSUME_TAC THENL
+   [REPEAT CONJ_TAC THENL
+     [DISJ_CASES_TAC(REAL_ARITH
+       `b(h1:real^N->bool) <= b h2 \/ b h2 <= b h1`)
+      THENL
+       [FIRST_X_ASSUM(MP_TAC o SPEC `f DELETE (h2:real^N->bool)`);
+        FIRST_X_ASSUM(MP_TAC o SPEC `f DELETE (h1:real^N->bool)`)] THEN
+      (ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+       MATCH_MP_TAC(SET_RULE `(p ==> s = t) ==> s PSUBSET t ==> ~p`) THEN
+       DISCH_TAC THEN
+       FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [SYM th]) THEN
+       AP_TERM_TAC)
+      THENL
+       [SUBGOAL_THEN `f DELETE h2 = h1 INSERT (f DIFF {h1,h2}) /\
+                      f = (h2:real^N->bool) INSERT h1 INSERT (f DIFF {h1,h2})`
+         (fun th -> ONCE_REWRITE_TAC[th]) THENL [ASM SET_TAC[]; ALL_TAC];
+        SUBGOAL_THEN `f DELETE h1 = h2 INSERT (f DIFF {h1,h2}) /\
+                      f = (h1:real^N->bool) INSERT h2 INSERT (f DIFF {h1,h2})`
+         (fun th -> ONCE_REWRITE_TAC[th]) THENL [ASM SET_TAC[]; ALL_TAC]] THEN
+      REWRITE_TAC[INTERS_INSERT] THEN MATCH_MP_TAC(SET_RULE
+       `b SUBSET a ==> a INTER b INTER s = b INTER s`) THEN
+      FIRST_X_ASSUM(fun th ->
+       MP_TAC(SPEC `h1:real^N->bool` th) THEN
+       MP_TAC(SPEC `h2:real^N->bool` th)) THEN
+      ASM_REWRITE_TAC[IMP_IMP] THEN
+      DISCH_THEN(fun th -> ONCE_REWRITE_TAC[GSYM th]) THEN
+      REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN ASM_REAL_ARITH_TAC;
+      DISJ_CASES_TAC(REAL_ARITH
+       `b(h2:real^N->bool) <= b h3 \/ b h3 <= b h2`)
+      THENL
+       [FIRST_X_ASSUM(MP_TAC o SPEC `f DELETE (h3:real^N->bool)`);
+        FIRST_X_ASSUM(MP_TAC o SPEC `f DELETE (h2:real^N->bool)`)] THEN
+      (ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+       MATCH_MP_TAC(SET_RULE `(p ==> s = t) ==> s PSUBSET t ==> ~p`) THEN
+       DISCH_TAC THEN
+       FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [SYM th]) THEN
+       AP_TERM_TAC)
+      THENL
+       [SUBGOAL_THEN `f DELETE h3 = h2 INSERT (f DIFF {h2,h3}) /\
+                      f = (h3:real^N->bool) INSERT h2 INSERT (f DIFF {h2,h3})`
+         (fun th -> ONCE_REWRITE_TAC[th]) THENL [ASM SET_TAC[]; ALL_TAC];
+        SUBGOAL_THEN `f DELETE h2 = h3 INSERT (f DIFF {h2,h3}) /\
+                      f = (h2:real^N->bool) INSERT h3 INSERT (f DIFF {h2,h3})`
+         (fun th -> ONCE_REWRITE_TAC[th]) THENL [ASM SET_TAC[]; ALL_TAC]] THEN
+      REWRITE_TAC[INTERS_INSERT] THEN MATCH_MP_TAC(SET_RULE
+       `b SUBSET a ==> a INTER b INTER s = b INTER s`) THEN
+      FIRST_X_ASSUM(fun th ->
+       MP_TAC(SPEC `h2:real^N->bool` th) THEN
+       MP_TAC(SPEC `h3:real^N->bool` th)) THEN
+      ASM_REWRITE_TAC[IMP_IMP] THEN
+      DISCH_THEN(fun th -> ONCE_REWRITE_TAC[GSYM th]) THEN
+      REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN ASM_REAL_ARITH_TAC;
+      DISJ_CASES_TAC(REAL_ARITH
+       `b(h1:real^N->bool) <= b h3 \/ b h3 <= b h1`)
+      THENL
+       [FIRST_X_ASSUM(MP_TAC o SPEC `f DELETE (h3:real^N->bool)`);
+        FIRST_X_ASSUM(MP_TAC o SPEC `f DELETE (h1:real^N->bool)`)] THEN
+      (ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+       MATCH_MP_TAC(SET_RULE `(p ==> s = t) ==> s PSUBSET t ==> ~p`) THEN
+       DISCH_TAC THEN
+       FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [SYM th]) THEN
+       AP_TERM_TAC)
+      THENL
+       [SUBGOAL_THEN `f DELETE h3 = h1 INSERT (f DIFF {h1,h3}) /\
+                      f = (h3:real^N->bool) INSERT h1 INSERT (f DIFF {h1,h3})`
+         (fun th -> ONCE_REWRITE_TAC[th]) THENL [ASM SET_TAC[]; ALL_TAC];
+        SUBGOAL_THEN `f DELETE h1 = h3 INSERT (f DIFF {h1,h3}) /\
+                      f = (h1:real^N->bool) INSERT h3 INSERT (f DIFF {h1,h3})`
+         (fun th -> ONCE_REWRITE_TAC[th]) THENL [ASM SET_TAC[]; ALL_TAC]] THEN
+      REWRITE_TAC[INTERS_INSERT] THEN MATCH_MP_TAC(SET_RULE
+       `b SUBSET a ==> a INTER b INTER s = b INTER s`) THEN
+      FIRST_X_ASSUM(fun th ->
+       MP_TAC(SPEC `h1:real^N->bool` th) THEN
+       MP_TAC(SPEC `h3:real^N->bool` th)) THEN
+      ASM_REWRITE_TAC[IMP_IMP] THEN
+      DISCH_THEN(fun th -> ONCE_REWRITE_TAC[GSYM th]) THEN
+      REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN ASM_REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `~({x | a h1 dot x <= b h1} INTER {x | a h2 dot x <= b h2}
+      SUBSET {x | a h3 dot x <= b h3}) /\
+    ~({x | a h1 dot x <= b h1} INTER {x | a h3 dot x <= b h3}
+      SUBSET {x | a h2 dot x <= b h2}) /\
+    ~({x | a h2 dot x <= b h2} INTER {x | a h3 dot x <= b h3}
+      SUBSET {x:real^N | a(h1:real^N->bool) dot x <= b h1})`
+  MP_TAC THENL
+   [ASM_SIMP_TAC[] THEN REPEAT STRIP_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `f DELETE (h3:real^N->bool)`);
+      FIRST_X_ASSUM(MP_TAC o SPEC `f DELETE (h2:real^N->bool)`);
+      FIRST_X_ASSUM(MP_TAC o SPEC `f DELETE (h1:real^N->bool)`)] THEN
+    (ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+     FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC
+       (LAND_CONV o LAND_CONV) [SYM th]) THEN
+     MATCH_MP_TAC(SET_RULE `s = t ==> s PSUBSET t ==> F`) THEN
+     AP_TERM_TAC)
+    THENL
+     [SUBGOAL_THEN
+       `f DELETE (h3:real^N->bool) = h1 INSERT h2 INSERT (f DELETE h3) /\
+        f =  h1 INSERT h2 INSERT h3 INSERT (f DELETE h3)`
+       (fun th -> ONCE_REWRITE_TAC[th]) THENL [ASM SET_TAC[]; ALL_TAC];
+      SUBGOAL_THEN
+       `f DELETE (h2:real^N->bool) = h1 INSERT h3 INSERT (f DELETE h2) /\
+        f =  h2 INSERT h1 INSERT h3 INSERT (f DELETE h2)`
+       (fun th -> ONCE_REWRITE_TAC[th]) THENL [ASM SET_TAC[]; ALL_TAC];
+      SUBGOAL_THEN
+       `f DELETE (h1:real^N->bool) = h2 INSERT h3 INSERT (f DELETE h1) /\
+        f =  h1 INSERT h2 INSERT h3 INSERT (f DELETE h1)`
+       (fun th -> ONCE_REWRITE_TAC[th]) THENL [ASM SET_TAC[]; ALL_TAC]] THEN
+    REWRITE_TAC[INTERS_INSERT] THEN REWRITE_TAC[GSYM INTER_ASSOC] THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?w. (a:(real^N->bool)->real^N) h1 dot w < b h1 /\
+        a h2 dot w < b h2 /\ a h3 dot w < b h3`
+   (CHOOSE_THEN MP_TAC)
+  THENL
+   [SUBGOAL_THEN `~(relative_interior p :real^N->bool = {})` MP_TAC THENL
+     [ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY; POLYHEDRON_IMP_CONVEX] THEN
+      ASM SET_TAC[];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`p:real^N->bool`; `f:(real^N->bool)->bool`; `a:(real^N->bool)->real^N`;
+      `b:(real^N->bool)->real`] RELATIVE_INTERIOR_POLYHEDRON_EXPLICIT) THEN
+    ASM_SIMP_TAC[] THEN DISCH_THEN(K ALL_TAC) THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+    DISCH_THEN(MP_TAC o CONJUNCT2) THEN ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x. x IN r ==> (a h1) dot (x:real^N) = b h1 /\
+                   (a h2) dot x = b h2 /\
+                   (a (h3:real^N->bool)) dot x = b h3`
+  MP_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `?z:real^N. z IN r` CHOOSE_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  MAP_EVERY UNDISCH_TAC
+   [`~((a:(real^N->bool)->real^N) h1 = a h2)`;
+    `~((a:(real^N->bool)->real^N) h1 = a h3)`;
+    `~((a:(real^N->bool)->real^N) h2 = a h3)`;
+    `aff_dim(p:real^N->bool) - &2 <= aff_dim(r:real^N->bool)`] THEN
+  MAP_EVERY (fun t ->
+    FIRST_X_ASSUM(fun th -> MP_TAC(SPEC t th) THEN ASM_REWRITE_TAC[] THEN
+                            ASSUME_TAC th) THEN
+    DISCH_THEN(MP_TAC o SPEC `z:real^N` o CONJUNCT2 o CONJUNCT2))
+   [`h1:real^N->bool`; `h2:real^N->bool`; `h3:real^N->bool`] THEN
+  SUBGOAL_THEN `(z:real^N) IN (affine hull p)` ASSUME_TAC THENL
+   [MATCH_MP_TAC HULL_INC THEN ASM SET_TAC[];
+    ASM_REWRITE_TAC[]] THEN
+  UNDISCH_TAC `(z:real^N) IN (affine hull p)` THEN
+  SUBGOAL_THEN `(a h1) dot (z:real^N) = b h1 /\
+                (a h2) dot z = b h2 /\
+                (a (h3:real^N->bool)) dot z = b h3`
+  (REPEAT_TCL CONJUNCTS_THEN (SUBST1_TAC o SYM))
+  THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `(r:real^N->bool) SUBSET affine hull p` MP_TAC THENL
+   [ASM_MESON_TAC[FACE_OF_IMP_SUBSET; HULL_SUBSET; SUBSET_TRANS]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `~((a:(real^N->bool)->real^N) h1 = vec 0) /\
+    ~((a:(real^N->bool)->real^N) h2 = vec 0) /\
+    ~((a:(real^N->bool)->real^N) h3 = vec 0)`
+  MP_TAC THENL [ASM_SIMP_TAC[]; ALL_TAC] THEN
+  UNDISCH_TAC `(z:real^N) IN r` THEN POP_ASSUM_LIST(K ALL_TAC) THEN
+  MAP_EVERY SPEC_TAC
+   [`(a:(real^N->bool)->real^N) h1`,`a1:real^N`;
+    `(a:(real^N->bool)->real^N) h2`,`a2:real^N`;
+    `(a:(real^N->bool)->real^N) h3`,`a3:real^N`] THEN
+  REPEAT GEN_TAC THEN
+  GEN_GEOM_ORIGIN_TAC `z:real^N` ["a1"; "a2"; "a3"] THEN
+  REWRITE_TAC[VECTOR_ADD_RID; VECTOR_ADD_LID] THEN
+  REWRITE_TAC[DOT_RADD; IMAGE_CLAUSES;
+   REAL_ARITH `a + b:real <= a <=> b <= &0`;
+   REAL_ARITH `a + b:real < a <=> b < &0`;
+   REAL_ARITH `a + b:real = a <=> b = &0`] THEN
+
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `aff_dim(p:real^N->bool) = &(dim p)` SUBST_ALL_TAC THENL
+   [ASM_SIMP_TAC[AFF_DIM_DIM_0; HULL_INC]; ALL_TAC] THEN
+  SUBGOAL_THEN `aff_dim(r:real^N->bool) = &(dim r)` SUBST_ALL_TAC THENL
+   [ASM_SIMP_TAC[AFF_DIM_DIM_0; HULL_INC]; ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[INT_OF_NUM_ADD; INT_OF_NUM_LE;
+    INT_ARITH `p - &2:int <= q <=> p <= q + &2`]) THEN
+  MP_TAC(ISPECL
+   [`{a1:real^N,a2,a3}`; `r:real^N->bool`] DIM_ORTHOGONAL_SUM) THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[FORALL_IN_INSERT; NOT_IN_EMPTY] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (ARITH_RULE
+    `p <= r + 2 ==> u <= p /\ 3 <= t ==> ~(u = t + r)`)) THEN
+  SUBGOAL_THEN `affine hull p :real^N->bool = span p` SUBST_ALL_TAC THENL
+   [ASM_MESON_TAC[AFFINE_HULL_EQ_SPAN]; ALL_TAC] THEN
+  CONJ_TAC THENL
+   [GEN_REWRITE_TAC RAND_CONV [GSYM DIM_SPAN] THEN
+    MATCH_MP_TAC DIM_SUBSET THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  MP_TAC(ISPEC `{a1:real^N,a2,a3}` DEPENDENT_BIGGERSET_GENERAL) THEN
+  SIMP_TAC[CARD_CLAUSES; FINITE_INSERT; FINITE_EMPTY; ARITH] THEN
+  ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; ARITH] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM CONTRAPOS_THM] THEN
+  REWRITE_TAC[ARITH_RULE `~(3 > x) <=> 3 <= x`] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  REWRITE_TAC[dependent; EXISTS_IN_INSERT; NOT_IN_EMPTY] THEN
+  ASM_REWRITE_TAC[DELETE_INSERT; EMPTY_DELETE] THEN
+  REWRITE_TAC[SPAN_2; IN_ELIM_THM; IN_UNIV] THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ o rev) THEN
+  W(fun (asl,w) -> let fv = frees w
+                   and av = [`a1:real^N`; `a2:real^N`; `a3:real^N`] in
+     MAP_EVERY (fun t -> SPEC_TAC(t,t)) (subtract fv av @ av)) THEN
+  REWRITE_TAC[LEFT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!a1 a2 a3. P a1 a2 a3 ==> P a2 a1 a3 /\ P a3 a1 a2) /\
+    (!a1 a2 a3. Q a1 a2 a3 ==> ~(P a1 a2 a3))
+    ==> !a3 a2 a1. P a1 a2 a3
+                   ==> ~(Q a1 a2 a3 \/ Q a2 a1 a3 \/ Q a3 a1 a2)`) THEN
+  CONJ_TAC THENL
+   [REPEAT GEN_TAC THEN MATCH_MP_TAC(TAUT
+     `(p ==> q) /\ (p ==> r) ==> p ==> q /\ r`) THEN
+    CONJ_TAC THEN REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    REWRITE_TAC[CONJ_ACI] THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  REPEAT GEN_TAC THEN DISCH_THEN
+   (X_CHOOSE_THEN `u:real` (X_CHOOSE_TAC `v:real`)) THEN
+  REWRITE_TAC[NOT_EXISTS_THM] THEN REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `u = &0` THENL
+   [ASM_REWRITE_TAC[VECTOR_ADD_LID; VECTOR_MUL_LZERO] THEN
+    REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC (REAL_ARITH
+     `v = &0 \/ &0 < v \/ &0 < --v`)
+    THENL
+     [ASM_REWRITE_TAC[VECTOR_MUL_LZERO];
+      REWRITE_TAC[DOT_LMUL; REAL_ARITH `a * b <= &0 <=> &0 <= a * --b`] THEN
+      ASM_SIMP_TAC[REAL_LE_MUL_EQ] THEN
+      REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_INTER] THEN REAL_ARITH_TAC;
+      REWRITE_TAC[DOT_LMUL; REAL_ARITH `a * b < &0 <=> &0 < --a * b`] THEN
+      ASM_SIMP_TAC[REAL_LT_MUL_EQ] THEN REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `v = &0` THENL
+   [ASM_REWRITE_TAC[VECTOR_ADD_RID; VECTOR_MUL_LZERO] THEN
+    REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC (REAL_ARITH
+     `u = &0 \/ &0 < u \/ &0 < --u`)
+    THENL
+     [ASM_REWRITE_TAC[VECTOR_MUL_LZERO];
+      REWRITE_TAC[DOT_LMUL; REAL_ARITH `a * b <= &0 <=> &0 <= a * --b`] THEN
+      ASM_SIMP_TAC[REAL_LE_MUL_EQ] THEN
+      REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_INTER] THEN REAL_ARITH_TAC;
+      REWRITE_TAC[DOT_LMUL; REAL_ARITH `a * b < &0 <=> &0 < --a * b`] THEN
+      ASM_SIMP_TAC[REAL_LT_MUL_EQ] THEN REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN
+   `&0 < u /\ &0 < v \/ &0 < u /\ &0 < --v \/
+    &0 < --u /\ &0 < v \/ &0 < --u /\ &0 < --v`
+  STRIP_ASSUME_TAC THENL
+   [ASM_REAL_ARITH_TAC;
+    UNDISCH_TAC
+     `~({x | a2 dot x <= &0} INTER {x | a3 dot x <= &0} SUBSET
+        {x:real^N | a1 dot x <= &0})` THEN
+    ASM_REWRITE_TAC[SUBSET; IN_INTER; IN_ELIM_THM] THEN
+    REWRITE_TAC[DOT_LADD; DOT_LMUL] THEN
+    REWRITE_TAC[REAL_ARITH `x <= &0 <=> &0 <= --x`] THEN
+    REWRITE_TAC[REAL_NEG_ADD; GSYM REAL_MUL_RNEG] THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; REAL_LE_ADD; REAL_LT_IMP_LE];
+    UNDISCH_TAC
+     `~({x | a1 dot x <= &0} INTER {x | a3 dot x <= &0} SUBSET
+        {x:real^N | a2 dot x <= &0})` THEN
+    ASM_REWRITE_TAC[SUBSET; IN_INTER; IN_ELIM_THM] THEN
+    GEN_TAC THEN REWRITE_TAC[DOT_LADD; DOT_LMUL] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `(&0 < u * a2 <=> &0 < a2) /\ (&0 < --v * a3 <=> &0 < a3)
+      ==> u * a2 + v * a3 <= &0 /\ a3 <= &0 ==> a2 <= &0`) THEN
+    ASM_SIMP_TAC[REAL_LT_MUL_EQ];
+    UNDISCH_TAC
+     `~({x | a1 dot x <= &0} INTER {x | a2 dot x <= &0} SUBSET
+        {x:real^N | a3 dot x <= &0})` THEN
+    ASM_REWRITE_TAC[SUBSET; IN_INTER; IN_ELIM_THM] THEN
+    GEN_TAC THEN REWRITE_TAC[DOT_LADD; DOT_LMUL] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `(&0 < --u * a2 <=> &0 < a2) /\ (&0 < v * a3 <=> &0 < a3)
+      ==> u * a2 + v * a3 <= &0 /\ a2 <= &0 ==> a3 <= &0`) THEN
+    ASM_SIMP_TAC[REAL_LT_MUL_EQ];
+    UNDISCH_TAC `(a1:real^N) dot w < &0` THEN
+    ASM_REWRITE_TAC[DOT_LADD; DOT_LMUL] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `&0 < --u * --a /\ &0 < --v * --b ==> ~(u * a + v * b < &0)`) THEN
+    CONJ_TAC THEN MATCH_MP_TAC REAL_LT_MUL THEN ASM_REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Lower bounds on then number of 0 and n-1 dimensional faces.               *)
+(* ------------------------------------------------------------------------- *)
+
+let POLYTOPE_VERTEX_LOWER_BOUND = prove
+ (`!p:real^N->bool.
+        polytope p ==> aff_dim p + &1 <= &(CARD {v | v extreme_point_of p})`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC INT_LE_TRANS THEN
+  EXISTS_TAC `aff_dim(convex hull {v:real^N | v extreme_point_of p}) + &1` THEN
+  CONJ_TAC THENL
+   [ASM_SIMP_TAC[GSYM KREIN_MILMAN_MINKOWSKI; POLYTOPE_IMP_CONVEX;
+                 POLYTOPE_IMP_COMPACT; INT_LE_REFL];
+    REWRITE_TAC[AFF_DIM_CONVEX_HULL; GSYM INT_LE_SUB_LADD] THEN
+    MATCH_MP_TAC AFF_DIM_LE_CARD THEN
+    MATCH_MP_TAC FINITE_POLYHEDRON_EXTREME_POINTS THEN
+    ASM_SIMP_TAC[POLYTOPE_IMP_POLYHEDRON]]);;
+
+let POLYTOPE_FACET_LOWER_BOUND = prove
+ (`!p:real^N->bool.
+        polytope p /\ ~(aff_dim p = &0)
+        ==> aff_dim p + &1 <= &(CARD {f | f facet_of p})`,
+  GEN_TAC THEN ASM_CASES_TAC `p:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[AFF_DIM_EMPTY; FACET_OF_EMPTY; EMPTY_GSPEC; CARD_CLAUSES] THEN
+  CONV_TAC INT_REDUCE_CONV THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?n. {f:real^N->bool | f facet_of p} HAS_SIZE n /\ aff_dim p + &1 <= &n`
+    (fun th -> MESON_TAC[th; HAS_SIZE]) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real^N` MP_TAC) THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ o rev) THEN
+  GEOM_ORIGIN_TAC `z:real^N` THEN REPEAT GEN_TAC THEN REPEAT STRIP_TAC THEN
+  EXISTS_TAC `CARD {f:real^N->bool | f facet_of p}` THEN
+  ASM_SIMP_TAC[FINITE_POLYTOPE_FACETS; HAS_SIZE] THEN
+  UNDISCH_TAC `~(aff_dim(p:real^N->bool) = &0)` THEN
+  ASM_SIMP_TAC[AFF_DIM_DIM_0; HULL_INC; INT_OF_NUM_ADD; INT_OF_NUM_LE] THEN
+  REWRITE_TAC[INT_OF_NUM_EQ] THEN DISCH_TAC THEN
+  MP_TAC(ISPEC `p:real^N->bool` POLYHEDRON_INTER_AFFINE_PARALLEL_MINIMAL) THEN
+  ASM_SIMP_TAC[POLYTOPE_IMP_POLYHEDRON] THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM; LEFT_AND_EXISTS_THM] THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN MAP_EVERY X_GEN_TAC
+   [`H:(real^N->bool)->bool`; `a:(real^N->bool)->real^N`;
+    `b:(real^N->bool)->real`] THEN
+  ONCE_REWRITE_TAC[EQ_SYM_EQ] THEN
+  REWRITE_TAC[VECTOR_ARITH `vec 0:real^N = v <=> v = vec 0`] THEN
+  ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC] THEN
+  STRIP_TAC THEN MP_TAC(ISPECL
+   [`p:real^N->bool`; `H:(real^N->bool)->bool`; `a:(real^N->bool)->real^N`;
+    `b:(real^N->bool)->real`] FACET_OF_POLYHEDRON_EXPLICIT) THEN
+  ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC] THEN DISCH_THEN(K ALL_TAC) THEN
+  SUBGOAL_THEN `!h:real^N->bool. h IN H ==> &0 <= b h` ASSUME_TAC THENL
+   [UNDISCH_TAC `(vec 0:real^N) IN p` THEN EXPAND_TAC "p" THEN
+    REWRITE_TAC[IN_INTER; IN_INTERS] THEN DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `h:real^N->bool` THEN
+    ASM_CASES_TAC `(h:real^N->bool) IN H` THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `h:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(fun t -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM t]) THEN
+    REWRITE_TAC[IN_ELIM_THM; DOT_RZERO];
+    ALL_TAC] THEN
+  MATCH_MP_TAC LE_TRANS THEN
+  EXISTS_TAC `(CARD(H:(real^N->bool)->bool))` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC(ARITH_RULE `~(h <= a) ==> a + 1 <= h`) THEN DISCH_TAC THEN
+    ASM_CASES_TAC `H:(real^N->bool)->bool = {}` THENL
+     [UNDISCH_THEN `H:(real^N->bool)->bool = {}` SUBST_ALL_TAC THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[INTERS_0; INTER_UNIV]) THEN
+      UNDISCH_TAC `~(dim(p:real^N->bool) = 0)` THEN
+      REWRITE_TAC[DIM_EQ_0] THEN EXPAND_TAC "p" THEN
+      REWRITE_TAC[ASSUME `H:(real^N->bool)->bool = {}`; INTERS_0] THEN
+      REWRITE_TAC[INTER_UNIV] THEN
+      ASM_CASES_TAC `?n:real^N. n IN span p /\ ~(n = vec 0)` THENL
+       [ALL_TAC; ASM SET_TAC[]] THEN
+      FIRST_X_ASSUM(CHOOSE_THEN STRIP_ASSUME_TAC) THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP POLYTOPE_IMP_BOUNDED) THEN
+      REWRITE_TAC[BOUNDED_POS] THEN DISCH_THEN(X_CHOOSE_THEN `B:real`
+       (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+      DISCH_THEN(MP_TAC o SPEC `(B + &1) / norm n % n:real^N`) THEN
+      ANTS_TAC THENL [ASM_MESON_TAC[SPAN_MUL]; ALL_TAC] THEN
+      REWRITE_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM] THEN
+      ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0] THEN REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `h:real^N->bool`) THEN
+    SUBGOAL_THEN
+     `span(IMAGE (a:(real^N->bool)->real^N) (H DELETE h))
+      PSUBSET span(p)`
+    MP_TAC THENL
+     [REWRITE_TAC[PSUBSET] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC SPAN_SUBSET_SUBSPACE THEN
+        REWRITE_TAC[SUBSPACE_SPAN; SUBSET; FORALL_IN_IMAGE; IN_DELETE] THEN
+        ASM_MESON_TAC[SPAN_ADD; SPAN_SUPERSET; VECTOR_ADD_LID];
+        DISCH_THEN(MP_TAC o AP_TERM `dim:(real^N->bool)->num`) THEN
+        REWRITE_TAC[DIM_SPAN] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+         (ARITH_RULE `h <= p ==> h':num < h ==> ~(h' = p)`)) THEN
+        MATCH_MP_TAC LET_TRANS THEN
+        EXISTS_TAC `CARD(IMAGE (a:(real^N->bool)->real^N) (H DELETE h))` THEN
+        ASM_SIMP_TAC[DIM_LE_CARD; FINITE_DELETE; FINITE_IMAGE] THEN
+        MATCH_MP_TAC LET_TRANS THEN
+        EXISTS_TAC `CARD(H DELETE (h:real^N->bool))` THEN
+        ASM_SIMP_TAC[CARD_IMAGE_LE; FINITE_DELETE] THEN
+        ASM_SIMP_TAC[CARD_DELETE; ARITH_RULE `n - 1 < n <=> ~(n = 0)`] THEN
+        ASM_SIMP_TAC[CARD_EQ_0] THEN ASM SET_TAC[]];
+      DISCH_THEN(MP_TAC o MATCH_MP ORTHOGONAL_TO_SUBSPACE_EXISTS_GEN)] THEN
+    REWRITE_TAC[NOT_EXISTS_THM] THEN X_GEN_TAC `n:real^N` THEN STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP POLYTOPE_IMP_BOUNDED) THEN
+    REWRITE_TAC[BOUNDED_POS] THEN
+    DISCH_THEN(X_CHOOSE_THEN `B:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISJ_CASES_TAC(REAL_ARITH
+     `&0 <= (a:(real^N->bool)->real^N) h dot n \/
+      &0 <= --((a:(real^N->bool)->real^N) h dot n)`)
+    THENL
+     [DISCH_THEN(MP_TAC o SPEC `--(B + &1) / norm(n) % n:real^N`);
+      DISCH_THEN(MP_TAC o SPEC `(B + &1) / norm(n) % n:real^N`)] THEN
+    (ASM_SIMP_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM;
+                  REAL_DIV_RMUL; NORM_EQ_0; REAL_ABS_NEG;
+                  REAL_ARITH `~(abs(B + &1) <= B)`] THEN
+     EXPAND_TAC "p" THEN REWRITE_TAC[IN_INTER; IN_INTERS] THEN
+     ASM_SIMP_TAC[SPAN_MUL] THEN X_GEN_TAC `k:real^N->bool` THEN
+     DISCH_TAC THEN
+     SUBGOAL_THEN `k = {x:real^N | a k dot x <= b k}` SUBST1_TAC THENL
+      [ASM_SIMP_TAC[]; ALL_TAC] THEN
+     ASM_CASES_TAC `k:real^N->bool = h` THEN
+     ASM_REWRITE_TAC[IN_ELIM_THM; DOT_RMUL] THENL
+      [ALL_TAC;
+       MATCH_MP_TAC(REAL_ARITH `x = &0 /\ &0 <= y ==> x <= y`) THEN
+       ASM_SIMP_TAC[REAL_ENTIRE] THEN DISJ2_TAC THEN
+       FIRST_X_ASSUM(MP_TAC o SPEC `(a:(real^N->bool)->real^N) k`) THEN
+       REWRITE_TAC[orthogonal; DOT_SYM] THEN DISCH_THEN MATCH_MP_TAC THEN
+       MATCH_MP_TAC SPAN_SUPERSET THEN ASM SET_TAC[]]) THENL
+     [MATCH_MP_TAC(REAL_ARITH `&0 <= --x * y /\ &0 <= z ==> x * y <= z`);
+      MATCH_MP_TAC(REAL_ARITH `&0 <= x * --y /\ &0 <= z ==> x * y <= z`)] THEN
+    ASM_SIMP_TAC[] THEN MATCH_MP_TAC REAL_LE_MUL THEN
+    REWRITE_TAC[REAL_ARITH `--a / b:real = --(a / b)`; REAL_NEG_NEG] THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; NORM_POS_LT] THEN ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[SET_RULE `{f | ?h. h IN s /\ f = g h} = IMAGE g s`] THEN
+    MATCH_MP_TAC(ARITH_RULE `m:num = n ==> n <= m`) THEN
+    MATCH_MP_TAC CARD_IMAGE_INJ THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC FACETS_OF_POLYHEDRON_EXPLICIT_DISTINCT THEN
+    ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN; HULL_INC]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The notion of n-simplex where n is an integer >= -1.                      *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("simplex",(12,"right"));;
+
+let simplex = new_definition
+ `n simplex s <=> ?c. ~(affine_dependent c) /\
+                      &(CARD c):int = n + &1 /\
+                      s = convex hull c`;;
+
+let SIMPLEX = prove
+ (`n simplex s <=> ?c. FINITE c /\
+                       ~(affine_dependent c) /\
+                       &(CARD c):int = n + &1 /\
+                       s = convex hull c`,
+  REWRITE_TAC[simplex] THEN MESON_TAC[AFFINE_INDEPENDENT_IMP_FINITE]);;
+
+let CONVEX_SIMPLEX = prove
+ (`!n s. n simplex s ==> convex s`,
+  REWRITE_TAC[simplex] THEN MESON_TAC[CONVEX_CONVEX_HULL]);;
+
+let COMPACT_SIMPLEX = prove
+ (`!n s. n simplex s ==> compact s`,
+  REWRITE_TAC[SIMPLEX] THEN
+  MESON_TAC[FINITE_IMP_COMPACT; COMPACT_CONVEX_HULL]);;
+
+let SIMPLEX_IMP_POLYTOPE = prove
+ (`!n s. n simplex s ==> polytope s`,
+  REWRITE_TAC[simplex; polytope] THEN
+  MESON_TAC[AFFINE_INDEPENDENT_IMP_FINITE]);;
+
+let SIMPLEX_DIM_GE = prove
+ (`!n s. n simplex s ==> -- &1 <= n`,
+  REWRITE_TAC[simplex] THEN INT_ARITH_TAC);;
+
+let SIMPLEX_EMPTY = prove
+ (`!n. n simplex {} <=> n = -- &1`,
+  GEN_TAC THEN REWRITE_TAC[SIMPLEX] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
+  REWRITE_TAC[CONVEX_HULL_EQ_EMPTY; CONJ_ASSOC] THEN
+  ONCE_REWRITE_TAC[CONJ_SYM] THEN REWRITE_TAC[UNWIND_THM2] THEN
+  REWRITE_TAC[FINITE_EMPTY; CARD_CLAUSES; AFFINE_INDEPENDENT_EMPTY] THEN
+  INT_ARITH_TAC);;
+
+let SIMPLEX_MINUS_1 = prove
+ (`!s. (-- &1) simplex s <=> s = {}`,
+  GEN_TAC THEN REWRITE_TAC[SIMPLEX; INT_ADD_LINV; INT_OF_NUM_EQ] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b <=> ~(a ==> ~b)`] THEN
+  SIMP_TAC[CARD_EQ_0] THEN REWRITE_TAC[NOT_IMP] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c /\ d <=> c /\ a /\ b /\ d`] THEN
+  REWRITE_TAC[UNWIND_THM2; FINITE_EMPTY; AFFINE_INDEPENDENT_EMPTY] THEN
+  REWRITE_TAC[CONVEX_HULL_EMPTY]);;
+
+let AFF_DIM_SIMPLEX = prove
+ (`!s n. n simplex s ==> aff_dim s = n`,
+  REWRITE_TAC[simplex; INT_ARITH `x:int = n + &1 <=> n = x - &1`] THEN
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[AFF_DIM_CONVEX_HULL; AFF_DIM_AFFINE_INDEPENDENT]);;
+
+let SIMPLEX_EXTREME_POINTS = prove
+ (`!n s:real^N->bool.
+       n simplex s
+       ==> FINITE {v | v extreme_point_of s} /\
+           ~(affine_dependent {v | v extreme_point_of s}) /\
+           &(CARD {v | v extreme_point_of s}) = n + &1 /\
+           s = convex hull {v | v extreme_point_of s}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[SIMPLEX; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `c:real^N->bool` THEN DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THEN
+  SUBGOAL_THEN `{v:real^N | v extreme_point_of s} = c`
+   (fun th -> ASM_REWRITE_TAC[th]) THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC(SET_RULE `s SUBSET t /\ ~(s PSUBSET t) ==> s = t`) THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM; EXTREME_POINT_OF_CONVEX_HULL] THEN
+  ABBREV_TAC `c' = {v:real^N | v extreme_point_of (convex hull c)}` THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN `convex hull c:real^N->bool = convex hull c'` ASSUME_TAC THENL
+   [EXPAND_TAC "c'" THEN MATCH_MP_TAC KREIN_MILMAN_MINKOWSKI THEN
+    REWRITE_TAC[CONVEX_CONVEX_HULL] THEN MATCH_MP_TAC COMPACT_CONVEX_HULL THEN
+    ASM_MESON_TAC[HAS_SIZE; FINITE_IMP_COMPACT];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [PSUBSET_MEMBER]) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [affine_dependent]) THEN
+    REWRITE_TAC[] THEN EXISTS_TAC `a:real^N` THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `(a:real^N) IN convex hull c'` MP_TAC THENL
+     [ASM_MESON_TAC[HULL_INC]; ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[SUBSET]
+      CONVEX_HULL_SUBSET_AFFINE_HULL)) THEN
+    SUBGOAL_THEN `c' SUBSET (c DELETE (a:real^N))` MP_TAC THENL
+     [ASM SET_TAC[]; ASM_MESON_TAC[HULL_MONO; SUBSET]]]);;
+
+let SIMPLEX_FACE_OF_SIMPLEX = prove
+ (`!n s f:real^N->bool.
+        n simplex s /\ f face_of s ==> ?m. m <= n /\ m simplex f`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SIMPLEX]) THEN
+  REWRITE_TAC[HAS_SIZE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `c:real^N->bool` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM SUBST_ALL_TAC THEN
+  SUBGOAL_THEN `?c':real^N->bool. c' SUBSET c /\ f = convex hull c'`
+  STRIP_ASSUME_TAC THENL
+   [ASM_SIMP_TAC[FACE_OF_CONVEX_HULL_SUBSET; FINITE_IMP_COMPACT]; ALL_TAC] THEN
+  EXISTS_TAC `&(CARD(c':real^N->bool)) - &1:int` THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] CARD_SUBSET)) THEN
+    ASM_REWRITE_TAC[GSYM INT_OF_NUM_LE] THEN INT_ARITH_TAC;
+    REWRITE_TAC[simplex] THEN EXISTS_TAC `c':real^N->bool` THEN
+    ASM_REWRITE_TAC[INT_ARITH `a - &1 + &1:int = a`] THEN
+    ASM_MESON_TAC[AFFINE_DEPENDENT_MONO]]);;
+
+let FACE_OF_SIMPLEX_SUBSET = prove
+ (`!n s f:real^N->bool.
+        n simplex s /\ f face_of s
+        ==> ?c. c SUBSET {x | x extreme_point_of s} /\ f = convex hull c`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP SIMPLEX_EXTREME_POINTS) THEN
+  ABBREV_TAC `c = {x:real^N | x extreme_point_of s}` THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN SUBST_ALL_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN
+  ASM_MESON_TAC[FACE_OF_CONVEX_HULL_SUBSET; FINITE_IMP_COMPACT]);;
+
+let SUBSET_FACE_OF_SIMPLEX = prove
+ (`!s n c:real^N->bool.
+      n simplex s /\ c SUBSET {x | x extreme_point_of s}
+      ==> (convex hull c) face_of s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP SIMPLEX_EXTREME_POINTS) THEN
+  REWRITE_TAC[HAS_SIZE] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC FACE_OF_CONVEX_HULLS THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(SET_RULE `!t. u SUBSET t /\ DISJOINT s t ==> DISJOINT s u`) THEN
+  EXISTS_TAC `affine hull ({v:real^N | v extreme_point_of s} DIFF c)` THEN
+  REWRITE_TAC[CONVEX_HULL_SUBSET_AFFINE_HULL] THEN
+  MATCH_MP_TAC DISJOINT_AFFINE_HULL THEN
+  EXISTS_TAC `{v:real^N | v extreme_point_of s}` THEN
+  ASM_REWRITE_TAC[] THEN SET_TAC[]);;
+
+let FACES_OF_SIMPLEX = prove
+ (`!n s. n simplex s
+         ==> {f | f face_of s} =
+             {convex hull c | c SUBSET {v | v extreme_point_of s}}`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC I [EXTENSION] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  ASM_MESON_TAC[FACE_OF_SIMPLEX_SUBSET; SUBSET_FACE_OF_SIMPLEX]);;
+
+let HAS_SIZE_FACES_OF_SIMPLEX = prove
+ (`!n s:real^N->bool.
+        n simplex s
+        ==> {f | f face_of s} HAS_SIZE 2 EXP (num_of_int(n + &1))`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP FACES_OF_SIMPLEX) THEN
+  FIRST_X_ASSUM(STRIP_ASSUME_TAC o GSYM o MATCH_MP SIMPLEX_EXTREME_POINTS) THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN CONJ_TAC THENL
+   [REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ];
+    MATCH_MP_TAC HAS_SIZE_POWERSET THEN
+    ASM_REWRITE_TAC[HAS_SIZE; NUM_OF_INT_OF_NUM]] THEN
+  SUBGOAL_THEN
+   `!a b. a SUBSET {v:real^N | v extreme_point_of s} /\
+          b SUBSET {v | v extreme_point_of s} /\
+          convex hull a SUBSET convex hull b
+          ==> a SUBSET b`
+   (fun th -> MESON_TAC[th]) THEN
+  REPEAT STRIP_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 [affine_dependent]) THEN
+  REWRITE_TAC[NOT_EXISTS_THM] THEN DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN REWRITE_TAC[] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC(SET_RULE
+   `!s t u. x IN s /\ s SUBSET t /\ t SUBSET u /\ u SUBSET v ==> x IN v`) THEN
+  MAP_EVERY EXISTS_TAC
+   [`convex hull a:real^N->bool`; `convex hull b:real^N->bool`;
+    `affine hull b:real^N->bool`] THEN
+  ASM_SIMP_TAC[HULL_INC; CONVEX_HULL_SUBSET_AFFINE_HULL] THEN
+  MATCH_MP_TAC HULL_MONO THEN ASM SET_TAC[]);;
+
+let FINITE_FACES_OF_SIMPLEX = prove
+ (`!n s. n simplex s ==> FINITE {f | f face_of s}`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_SIZE_FACES_OF_SIMPLEX) THEN
+  SIMP_TAC[HAS_SIZE]);;
+
+let CARD_FACES_OF_SIMPLEX = prove
+ (`!n s. n simplex s ==> CARD {f | f face_of s} = 2 EXP (num_of_int(n + &1))`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_SIZE_FACES_OF_SIMPLEX) THEN
+  SIMP_TAC[HAS_SIZE]);;
+
+let CHOOSE_SIMPLEX = prove
+ (`!n. --(&1) <= n /\ n <= &(dimindex(:N)) ==> ?s:real^N->bool. n simplex s`,
+  X_GEN_TAC `d:int` THEN
+  REWRITE_TAC[INT_ARITH `--(&1):int <= n <=> n = --(&1) \/ &0 <= n`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 DISJ_CASES_TAC MP_TAC) THENL
+   [ASM_MESON_TAC[SIMPLEX_EMPTY]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM INT_OF_NUM_EXISTS]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `n:num` SUBST1_TAC) THEN
+  REWRITE_TAC[INT_OF_NUM_LE; GSYM DIM_UNIV] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP CHOOSE_SUBSPACE_OF_SUBSPACE) THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPEC `s:real^N->bool` BASIS_EXISTS) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `c:real^N->bool` THEN STRIP_TAC THEN
+  EXISTS_TAC `convex hull ((vec 0:real^N) INSERT c)` THEN
+  REWRITE_TAC[simplex] THEN EXISTS_TAC `(vec 0:real^N) INSERT c` THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP INDEPENDENT_NONZERO) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP INDEPENDENT_IMP_FINITE) THEN
+  ASM_SIMP_TAC[CARD_CLAUSES; GSYM INT_OF_NUM_SUC] THEN
+  ASM_SIMP_TAC[INDEPENDENT_IMP_AFFINE_DEPENDENT_0] THEN
+  ASM_MESON_TAC[HAS_SIZE]);;
+
+let CHOOSE_POLYTOPE = prove
+ (`!n. --(&1) <= n /\ n <= &(dimindex(:N))
+       ==> ?s:real^N->bool. polytope s /\ aff_dim s = n`,
+  MESON_TAC[CHOOSE_SIMPLEX; SIMPLEX_IMP_POLYTOPE; AFF_DIM_SIMPLEX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Simplicial complexes and triangulations.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let simplicial_complex = new_definition
+ `simplicial_complex c <=>
+        FINITE c /\
+        (!s. s IN c ==> ?n. n simplex s) /\
+        (!f s. s IN c /\ f face_of s ==> f IN c) /\
+        (!s s'. s IN c /\ s' IN c
+                ==> (s INTER s') face_of s /\ (s INTER s') face_of s')`;;
+
+let triangulation = new_definition
+ `triangulation(tr:(real^N->bool)->bool) <=>
+        FINITE tr /\
+        (!t. t IN tr ==> ?n. n simplex t) /\
+        (!t t'. t IN tr /\ t' IN tr
+                ==> (t INTER t') face_of t /\ (t INTER t') face_of t')`;;
+
+let SIMPLICIAL_COMPLEX_IMP_TRIANGULATION = prove
+ (`!tr. simplicial_complex tr ==> triangulation tr`,
+  REWRITE_TAC[triangulation; simplicial_complex] THEN MESON_TAC[]);;
+
+let TRIANGULATION_UNION = prove
+ (`!tr1 tr2.
+        triangulation(tr1 UNION tr2) <=>
+        triangulation tr1 /\ triangulation tr2 /\
+        (!s t. s IN tr1 /\ t IN tr2
+               ==> s INTER t face_of s /\ s INTER t face_of t)`,
+  REWRITE_TAC[triangulation; FINITE_UNION; IN_UNION] THEN
+  MESON_TAC[INTER_COMM]);;
+
+let TRIANGULATION_INTER_SIMPLEX = prove
+ (`!tr t t':real^N->bool.
+        triangulation tr /\ t IN tr /\ t' IN tr
+        ==> t INTER t' = convex hull ({x | x extreme_point_of t} INTER
+                                      {x | x extreme_point_of t'})`,
+  REWRITE_TAC[triangulation] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`t:real^N->bool`; `t':real^N->bool`]) THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(fun th -> MAP_EVERY (MP_TAC o C SPEC th)
+   [`t:real^N->bool`; `t':real^N->bool`]) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `m:int` THEN DISCH_TAC THEN X_GEN_TAC `n:int` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`m:int`; `t':real^N->bool`;
+                 `t INTER t':real^N->bool`] FACE_OF_SIMPLEX_SUBSET) THEN
+  MP_TAC(ISPECL [`n:int`; `t:real^N->bool`;
+                 `t INTER t':real^N->bool`] FACE_OF_SIMPLEX_SUBSET) THEN
+  ASM_SIMP_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real^N->bool` (STRIP_ASSUME_TAC o GSYM)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d':real^N->bool` (STRIP_ASSUME_TAC o GSYM)) THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC HULL_MINIMAL THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[CONVEX_INTER; CONVEX_SIMPLEX]] THEN
+    SIMP_TAC[SUBSET; IN_INTER; IN_ELIM_THM; extreme_point_of]] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `convex hull {x:real^N | x extreme_point_of (t INTER t')}` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC(SET_RULE `s = t ==> s SUBSET t`) THEN
+    MATCH_MP_TAC KREIN_MILMAN_MINKOWSKI THEN
+    ASM_MESON_TAC[COMPACT_INTER; CONVEX_INTER; COMPACT_SIMPLEX; CONVEX_SIMPLEX];
+    MATCH_MP_TAC HULL_MONO THEN REWRITE_TAC[SUBSET_INTER] THEN CONJ_TAC THENL
+     [SUBST1_TAC(SYM(ASSUME `convex hull d:real^N->bool = t INTER t'`));
+      SUBST1_TAC(SYM(ASSUME `convex hull d':real^N->bool = t INTER t'`))] THEN
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN GEN_TAC THEN
+    DISCH_THEN(MP_TAC o MATCH_MP EXTREME_POINT_OF_CONVEX_HULL) THEN
+    ASM SET_TAC[]]);;
+
+let TRIANGULATION_SIMPLICIAL_COMPLEX = prove
+ (`!tr. triangulation tr
+        ==> simplicial_complex {f:real^N->bool | ?t. t IN tr /\ f face_of t}`,
+  let lemma = prove
+   (`{f | ?t. t IN tr /\ P f t} = UNIONS (IMAGE (\t. {f | P f t}) tr)`,
+    GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_UNIONS; IN_IMAGE; LEFT_AND_EXISTS_THM] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC; UNWIND_THM2; IN_ELIM_THM]) in
+  REWRITE_TAC[triangulation; simplicial_complex] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN GEN_TAC THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP] THEN STRIP_TAC THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[lemma] THEN ASM_SIMP_TAC[FINITE_UNIONS; FINITE_IMAGE] THEN
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE] THEN
+    ASM_MESON_TAC[FINITE_FACES_OF_SIMPLEX];
+    ASM_MESON_TAC[SIMPLEX_FACE_OF_SIMPLEX];
+    ASM_MESON_TAC[FACE_OF_TRANS];
+    ASM_MESON_TAC[FACE_OF_INTER_SUBFACE]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Subdividing a cell complex (not necessarily simplicial).                  *)
+(* ------------------------------------------------------------------------- *)
+
+let CELL_COMPLEX_SUBDIVISION_EXISTS = prove
+ (`!m:(real^N->bool)->bool d e.
+     &0 < e /\
+     FINITE m /\
+     (!c. c IN m ==> polytope c) /\
+     (!c. c IN m ==> aff_dim c <= d) /\
+     (!c1 c2. c1 IN m /\ c2 IN m
+              ==> c1 INTER c2 face_of c1 /\ c1 INTER c2 face_of c2)
+     ==> ?m'. (!c. c IN m' ==> diameter c < e) /\
+              UNIONS m' = UNIONS m /\
+              FINITE m' /\
+              (!c. c IN m' ==> polytope c) /\
+              (!c. c IN m' ==> aff_dim c <= d) /\
+              (!c1 c2. c1 IN m' /\ c2 IN m'
+                       ==> c1 INTER c2 face_of c1 /\ c1 INTER c2 face_of c2)`,
+  let lemma1 = prove
+   (`a < abs(x - y)
+     ==> &0 < a
+         ==> ?n. integer n /\ (x < n * a /\ n * a < y \/
+                               y <  n * a /\ n * a < x)`,
+    REPEAT STRIP_TAC THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_LDIV_EQ; GSYM REAL_LT_RDIV_EQ] THEN
+    MATCH_MP_TAC INTEGER_EXISTS_BETWEEN_ABS_LT THEN
+    REWRITE_TAC[real_div; GSYM REAL_SUB_RDISTRIB; REAL_ABS_MUL] THEN
+    ASM_SIMP_TAC[REAL_ABS_INV; REAL_ARITH `&0 < x ==> abs x = x`] THEN
+    ASM_SIMP_TAC[GSYM real_div; REAL_LT_RDIV_EQ;
+                 REAL_MUL_LID; REAL_LT_IMP_LE])
+  and lemma2 = prove
+   (`!m:(real^N->bool)->bool d.
+        FINITE m /\
+        (!c. c IN m ==> polytope c) /\
+        (!c. c IN m ==> aff_dim c <= d) /\
+        (!c1 c2. c1 IN m /\ c2 IN m
+                 ==> c1 INTER c2 face_of c1 /\ c1 INTER c2 face_of c2)
+        ==> !i. FINITE i
+                ==> ?m'. UNIONS m' = UNIONS m /\
+                         FINITE m' /\
+                         (!c. c IN m' ==> polytope c) /\
+                         (!c. c IN m' ==> aff_dim c <= d) /\
+                         (!c1 c2. c1 IN m' /\ c2 IN m'
+                                  ==> c1 INTER c2 face_of c1 /\
+                                      c1 INTER c2 face_of c2) /\
+                         (!c x y. c IN m' /\ x IN c /\ y IN c
+                                  ==> !a b. (a,b) IN i
+                                            ==> a dot x <= b /\ a dot y <= b \/
+                                                a dot x >= b /\ a dot y >= b)`,
+    REPEAT GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+    REWRITE_TAC[NOT_IN_EMPTY; FORALL_PAIR_THM] THEN CONJ_TAC THENL
+     [EXISTS_TAC `m:(real^N->bool)->bool` THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real`; `i:(real^N#real)->bool`] THEN
+    GEN_REWRITE_TAC I [IMP_CONJ] THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:(real^N->bool)->bool` MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (SUBST1_TAC o SYM) MP_TAC) THEN
+    POP_ASSUM_LIST(K ALL_TAC) THEN REPEAT STRIP_TAC THEN
+    EXISTS_TAC `{c INTER {x:real^N | a dot x <= b} | c IN n} UNION
+                {c INTER {x:real^N | a dot x >= b} | c IN n}` THEN
+    REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[UNIONS_UNION; GSYM INTER_UNIONS; GSYM UNION_OVER_INTER] THEN
+      MATCH_MP_TAC(SET_RULE `(!x. x IN s) ==> t INTER s = t`) THEN
+      REWRITE_TAC[IN_UNION; IN_ELIM_THM] THEN REAL_ARITH_TAC;
+      ASM_SIMP_TAC[FINITE_UNION; SIMPLE_IMAGE; FINITE_IMAGE];
+      REWRITE_TAC[IN_UNION; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+      ASM_SIMP_TAC[POLYTOPE_INTER_POLYHEDRON; POLYHEDRON_HALFSPACE_LE;
+                   POLYHEDRON_HALFSPACE_GE];
+      REWRITE_TAC[IN_UNION; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+      ASM_MESON_TAC[INT_LE_TRANS; AFF_DIM_SUBSET; INTER_SUBSET];
+      REWRITE_TAC[IN_UNION; IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+      ASM_REWRITE_TAC[] THEN
+      ONCE_REWRITE_TAC[SET_RULE
+      `(s INTER t) INTER (s' INTER t') = (s INTER s') INTER (t INTER t')`] THEN
+      MATCH_MP_TAC FACE_OF_INTER_INTER THEN ASM_SIMP_TAC[] THEN
+      SIMP_TAC[SET_RULE `s INTER s = s`; FACE_OF_REFL; CONVEX_HALFSPACE_LE;
+               CONVEX_HALFSPACE_GE] THEN
+      REWRITE_TAC[INTER; IN_ELIM_THM; HYPERPLANE_FACE_OF_HALFSPACE_LE;
+                  HYPERPLANE_FACE_OF_HALFSPACE_GE;
+                  REAL_ARITH `a <= b /\ a >= b <=> a = b`;
+                  REAL_ARITH `a >= b /\ a <= b <=> a = b`];
+      REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; IN_UNION; FORALL_AND_THM;
+                  IN_INSERT;
+                  TAUT `p \/ q ==> r <=> (p ==> r) /\ (q ==> r)`] THEN
+      REWRITE_TAC[FORALL_IN_GSPEC; IN_INTER; IN_ELIM_THM; PAIR_EQ] THEN
+      SIMP_TAC[] THEN ASM_MESON_TAC[]]) in
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `bounded(UNIONS m:real^N->bool)` MP_TAC THENL
+   [ASM_SIMP_TAC[BOUNDED_UNIONS; POLYTOPE_IMP_BOUNDED]; ALL_TAC] THEN
+  REWRITE_TAC[BOUNDED_POS_LT; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `B:real` THEN REWRITE_TAC[] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`--B / (e / &2 / &(dimindex(:N)))`;
+                 `B / (e / &2 / &(dimindex(:N)))`] FINITE_INTSEG) THEN
+  ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; REAL_HALF;
+               REAL_LT_DIV; REAL_OF_NUM_LT; DIMINDEX_GE_1; LE_1] THEN
+  REWRITE_TAC[REAL_BOUNDS_LE] THEN ABBREV_TAC
+   `k = {i | integer i /\ abs(i * e / &2 / &(dimindex(:N))) <= B}` THEN
+  DISCH_TAC THEN
+  MP_TAC(ISPECL [`m:(real^N->bool)->bool`; `d:int`] lemma2) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC
+   `{ (basis i:real^N,j * e / &2 / &(dimindex(:N))) |
+      i IN 1..dimindex(:N) /\ j IN k}`) THEN
+  ASM_SIMP_TAC[FINITE_PRODUCT_DEPENDENT; FINITE_NUMSEG] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `n:(real^N->bool)->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `c:real^N->bool` THEN DISCH_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= e / &2 ==> x < e`) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC DIAMETER_LE THEN
+  CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN 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_BOUND_GEN THEN
+  REWRITE_TAC[FINITE_NUMSEG; CARD_NUMSEG_1; NUMSEG_EMPTY] THEN
+  REWRITE_TAC[NOT_LT; DIMINDEX_GE_1; IN_NUMSEG; VECTOR_SUB_COMPONENT] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP lemma1) THEN
+  ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV;
+               REAL_OF_NUM_LT; DIMINDEX_GE_1; LE_1] THEN
+  DISCH_THEN(X_CHOOSE_THEN `j:real` (CONJUNCTS_THEN ASSUME_TAC)) THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`c:real^N->bool`; `x:real^N`; `y:real^N`]) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o
+    SPECL [`basis i:real^N`; `j * e / &2 / &(dimindex(:N))`]) THEN
+  ASM_SIMP_TAC[DOT_BASIS; IN_ELIM_THM; NOT_IMP] THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+  MAP_EVERY EXISTS_TAC [`i:num`; `j:real`] THEN ASM_REWRITE_TAC[IN_NUMSEG] THEN
+  EXPAND_TAC "k" THEN ASM_REWRITE_TAC[IN_ELIM_THM] THEN
+  FIRST_X_ASSUM DISJ_CASES_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+   (REAL_ARITH `a < x /\ x < b
+                ==> abs a <= c /\ abs b <= c ==> abs x <= c`)) THEN
+  CONJ_TAC THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) COMPONENT_LE_NORM o lhand o snd) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+  MATCH_MP_TAC REAL_LT_IMP_LE THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM SET_TAC[]);;
diff --git a/Multivariate/realanalysis.ml b/Multivariate/realanalysis.ml
new file mode 100644 (file)
index 0000000..33509f8
--- /dev/null
@@ -0,0 +1,18887 @@
+(* ========================================================================= *)
+(* Some analytic concepts for R instead of R^1.                              *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(* ========================================================================= *)
+
+needs "Library/binomial.ml";;
+needs "Multivariate/measure.ml";;
+needs "Multivariate/polytope.ml";;
+needs "Multivariate/transcendentals.ml";;
+
+(* ------------------------------------------------------------------------- *)
+(* Open-ness and closedness of a set of reals.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let real_open = new_definition
+  `real_open s <=>
+      !x. x IN s ==> ?e. &0 < e /\ !x'. abs(x' - x) < e ==> x' IN s`;;
+
+let real_closed = new_definition
+ `real_closed s <=> real_open((:real) DIFF s)`;;
+
+let euclideanreal = new_definition
+ `euclideanreal = topology real_open`;;
+
+let REAL_OPEN_EMPTY = prove
+ (`real_open {}`,
+  REWRITE_TAC[real_open; NOT_IN_EMPTY]);;
+
+let REAL_OPEN_UNIV = prove
+ (`real_open(:real)`,
+  REWRITE_TAC[real_open; IN_UNIV] THEN MESON_TAC[REAL_LT_01]);;
+
+let REAL_OPEN_INTER = prove
+ (`!s t. real_open s /\ real_open t ==> real_open (s INTER t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_open; AND_FORALL_THM; IN_INTER] THEN
+  MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_TAC `d1:real`) (X_CHOOSE_TAC `d2:real`)) THEN
+  MP_TAC(SPECL [`d1:real`; `d2:real`] REAL_DOWN2) THEN
+  ASM_MESON_TAC[REAL_LT_TRANS]);;
+
+let REAL_OPEN_UNIONS = prove
+ (`(!s. s IN f ==> real_open s) ==> real_open(UNIONS f)`,
+  REWRITE_TAC[real_open; IN_UNIONS] THEN MESON_TAC[]);;
+
+let REAL_OPEN_IN = prove
+ (`!s. real_open s <=> open_in euclideanreal s`,
+  GEN_TAC THEN REWRITE_TAC[euclideanreal] THEN CONV_TAC SYM_CONV THEN
+  AP_THM_TAC THEN REWRITE_TAC[GSYM(CONJUNCT2 topology_tybij)] THEN
+  REWRITE_TAC[REWRITE_RULE[IN] istopology] THEN
+  REWRITE_TAC[REAL_OPEN_EMPTY; REAL_OPEN_INTER; SUBSET] THEN
+  MESON_TAC[IN; REAL_OPEN_UNIONS]);;
+
+let TOPSPACE_EUCLIDEANREAL = prove
+ (`topspace euclideanreal = (:real)`,
+  REWRITE_TAC[topspace; EXTENSION; IN_UNIV; IN_UNIONS; IN_ELIM_THM] THEN
+  MESON_TAC[REAL_OPEN_UNIV; IN_UNIV; REAL_OPEN_IN]);;
+
+let TOPSPACE_EUCLIDEANREAL_SUBTOPOLOGY = prove
+ (`!s. topspace (subtopology euclideanreal s) = s`,
+  REWRITE_TAC[TOPSPACE_EUCLIDEANREAL; TOPSPACE_SUBTOPOLOGY; INTER_UNIV]);;
+
+let REAL_CLOSED_IN = prove
+ (`!s. real_closed s <=> closed_in euclideanreal s`,
+  REWRITE_TAC[real_closed; closed_in; TOPSPACE_EUCLIDEANREAL;
+              REAL_OPEN_IN; SUBSET_UNIV]);;
+
+let REAL_OPEN_UNION = prove
+ (`!s t. real_open s /\ real_open t ==> real_open(s UNION t)`,
+  REWRITE_TAC[REAL_OPEN_IN; OPEN_IN_UNION]);;
+
+let REAL_OPEN_SUBREAL_OPEN = prove
+ (`!s. real_open s <=> !x. x IN s ==> ?t. real_open t /\ x IN t /\ t SUBSET s`,
+  REWRITE_TAC[REAL_OPEN_IN; GSYM OPEN_IN_SUBOPEN]);;
+
+let REAL_CLOSED_EMPTY = prove
+ (`real_closed {}`,
+  REWRITE_TAC[REAL_CLOSED_IN; CLOSED_IN_EMPTY]);;
+
+let REAL_CLOSED_UNIV = prove
+ (`real_closed(:real)`,
+  REWRITE_TAC[REAL_CLOSED_IN; GSYM TOPSPACE_EUCLIDEANREAL; CLOSED_IN_TOPSPACE]);;
+
+let REAL_CLOSED_UNION = prove
+ (`!s t. real_closed s /\ real_closed t ==> real_closed(s UNION t)`,
+  REWRITE_TAC[REAL_CLOSED_IN; CLOSED_IN_UNION]);;
+
+let REAL_CLOSED_INTER = prove
+ (`!s t. real_closed s /\ real_closed t ==> real_closed(s INTER t)`,
+  REWRITE_TAC[REAL_CLOSED_IN; CLOSED_IN_INTER]);;
+
+let REAL_CLOSED_INTERS = prove
+ (`!f. (!s. s IN f ==> real_closed s) ==> real_closed(INTERS f)`,
+  REWRITE_TAC[REAL_CLOSED_IN] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `f:(real->bool)->bool = {}` THEN
+  ASM_SIMP_TAC[CLOSED_IN_INTERS; INTERS_0] THEN
+  REWRITE_TAC[GSYM TOPSPACE_EUCLIDEANREAL; CLOSED_IN_TOPSPACE]);;
+
+let REAL_OPEN_REAL_CLOSED = prove
+ (`!s. real_open s <=> real_closed(UNIV DIFF s)`,
+  SIMP_TAC[REAL_OPEN_IN; REAL_CLOSED_IN; TOPSPACE_EUCLIDEANREAL; SUBSET_UNIV;
+           OPEN_IN_CLOSED_IN_EQ]);;
+
+let REAL_OPEN_DIFF = prove
+ (`!s t. real_open s /\ real_closed t ==> real_open(s DIFF t)`,
+  REWRITE_TAC[REAL_OPEN_IN; REAL_CLOSED_IN; OPEN_IN_DIFF]);;
+
+let REAL_CLOSED_DIFF = prove
+ (`!s t. real_closed s /\ real_open t ==> real_closed(s DIFF t)`,
+  REWRITE_TAC[REAL_OPEN_IN; REAL_CLOSED_IN; CLOSED_IN_DIFF]);;
+
+let REAL_OPEN_INTERS = prove
+ (`!s. FINITE s /\ (!t. t IN s ==> real_open t) ==> real_open(INTERS s)`,
+  REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[INTERS_INSERT; INTERS_0; REAL_OPEN_UNIV; IN_INSERT] THEN
+  MESON_TAC[REAL_OPEN_INTER]);;
+
+let REAL_CLOSED_UNIONS = prove
+ (`!s. FINITE s /\ (!t. t IN s ==> real_closed t) ==> real_closed(UNIONS s)`,
+  REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[UNIONS_INSERT; UNIONS_0; REAL_CLOSED_EMPTY; IN_INSERT] THEN
+  MESON_TAC[REAL_CLOSED_UNION]);;
+
+let REAL_OPEN = prove
+ (`!s. real_open s <=> open(IMAGE lift s)`,
+  REWRITE_TAC[real_open; open_def; FORALL_IN_IMAGE; FORALL_LIFT; DIST_LIFT;
+              LIFT_IN_IMAGE_LIFT]);;
+
+let REAL_CLOSED = prove
+ (`!s. real_closed s <=> closed(IMAGE lift s)`,
+  GEN_TAC THEN REWRITE_TAC[real_closed; REAL_OPEN; closed] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_IMAGE; IN_DIFF; IN_UNIV] THEN
+  MESON_TAC[LIFT_DROP]);;
+
+let REAL_CLOSED_HALFSPACE_LE = prove
+ (`!a. real_closed {x | x <= a}`,
+  GEN_TAC THEN SUBGOAL_THEN `closed {x | drop x <= a}` MP_TAC THENL
+   [REWRITE_TAC[drop; CLOSED_HALFSPACE_COMPONENT_LE]; ALL_TAC] THEN
+  MATCH_MP_TAC EQ_IMP THEN REWRITE_TAC[REAL_CLOSED] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_ELIM_THM] THEN MESON_TAC[LIFT_DROP]);;
+
+let REAL_CLOSED_HALFSPACE_GE = prove
+ (`!a. real_closed {x | x >= a}`,
+  GEN_TAC THEN SUBGOAL_THEN `closed {x | drop x >= a}` MP_TAC THENL
+   [REWRITE_TAC[drop; CLOSED_HALFSPACE_COMPONENT_GE]; ALL_TAC] THEN
+  MATCH_MP_TAC EQ_IMP THEN REWRITE_TAC[REAL_CLOSED] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_ELIM_THM] THEN MESON_TAC[LIFT_DROP]);;
+
+let REAL_OPEN_HALFSPACE_LT = prove
+ (`!a. real_open {x | x < a}`,
+  GEN_TAC THEN SUBGOAL_THEN `open {x | drop x < a}` MP_TAC THENL
+   [REWRITE_TAC[drop; OPEN_HALFSPACE_COMPONENT_LT]; ALL_TAC] THEN
+  MATCH_MP_TAC EQ_IMP THEN REWRITE_TAC[REAL_OPEN] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_ELIM_THM] THEN MESON_TAC[LIFT_DROP]);;
+
+let REAL_OPEN_HALFSPACE_GT = prove
+ (`!a. real_open {x | x > a}`,
+  GEN_TAC THEN SUBGOAL_THEN `open {x | drop x > a}` MP_TAC THENL
+   [REWRITE_TAC[drop; OPEN_HALFSPACE_COMPONENT_GT]; ALL_TAC] THEN
+  MATCH_MP_TAC EQ_IMP THEN REWRITE_TAC[REAL_OPEN] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_ELIM_THM] THEN MESON_TAC[LIFT_DROP]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Compactness of a set of reals.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let real_bounded = new_definition
+ `real_bounded s <=> ?B. !x. x IN s ==> abs(x) <= B`;;
+
+let REAL_BOUNDED = prove
+ (`real_bounded s <=> bounded(IMAGE lift s)`,
+  REWRITE_TAC[BOUNDED_LIFT; real_bounded]);;
+
+let REAL_BOUNDED_POS = prove
+ (`!s. real_bounded s <=> ?B. &0 < B /\ !x. x IN s ==> abs(x) <= B`,
+  REWRITE_TAC[real_bounded] THEN
+  MESON_TAC[REAL_ARITH `&0 < &1 + abs B /\ (x <= B ==> x <= &1 + abs B)`]);;
+
+let REAL_BOUNDED_POS_LT = prove
+ (`!s. real_bounded s <=> ?b. &0 < b /\ !x. x IN s ==> abs(x) < b`,
+  REWRITE_TAC[real_bounded] THEN
+  MESON_TAC[REAL_LT_IMP_LE;
+            REAL_ARITH `&0 < &1 + abs(y) /\ (x <= y ==> x < &1 + abs(y))`]);;
+
+let REAL_BOUNDED_SUBSET = prove
+ (`!s t. real_bounded t /\ s SUBSET t ==> real_bounded s`,
+  MESON_TAC[REAL_BOUNDED; BOUNDED_SUBSET; IMAGE_SUBSET]);;
+
+let REAL_BOUNDED_UNION = prove
+ (`!s t. real_bounded(s UNION t) <=> real_bounded s /\ real_bounded t`,
+  REWRITE_TAC[REAL_BOUNDED; IMAGE_UNION; BOUNDED_UNION]);;
+
+let real_compact = new_definition
+ `real_compact s <=> compact(IMAGE lift s)`;;
+
+let REAL_COMPACT_IMP_BOUNDED = prove
+ (`!s. real_compact s ==> real_bounded s`,
+  REWRITE_TAC[real_compact; REAL_BOUNDED; COMPACT_IMP_BOUNDED]);;
+
+let REAL_COMPACT_IMP_CLOSED = prove
+ (`!s. real_compact s ==> real_closed s`,
+  REWRITE_TAC[real_compact; REAL_CLOSED; COMPACT_IMP_CLOSED]);;
+
+let REAL_COMPACT_EQ_BOUNDED_CLOSED = prove
+ (`!s. real_compact s <=> real_bounded s /\ real_closed s`,
+  REWRITE_TAC[real_compact; REAL_BOUNDED; REAL_CLOSED] THEN
+  REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED]);;
+
+let REAL_COMPACT_UNION = prove
+ (`!s t. real_compact s /\ real_compact t ==> real_compact(s UNION t)`,
+  REWRITE_TAC[real_compact; IMAGE_UNION; COMPACT_UNION]);;
+
+let REAL_COMPACT_ATTAINS_INF = prove
+ (`!s. real_compact s /\ ~(s = {}) ==> ?x. x IN s /\ !y. y IN s ==> x <= y`,
+  REWRITE_TAC[real_compact; COMPACT_ATTAINS_INF]);;
+
+let REAL_COMPACT_ATTAINS_SUP = prove
+ (`!s. real_compact s /\ ~(s = {}) ==> ?x. x IN s /\ !y. y IN s ==> y <= x`,
+  REWRITE_TAC[real_compact; COMPACT_ATTAINS_SUP]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Limits of functions with real range.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("--->",(12,"right"));;
+
+let tendsto_real = new_definition
+  `(f ---> l) net <=> !e. &0 < e ==> eventually (\x. abs(f(x) - l) < e) net`;;
+
+let reallim = new_definition
+ `reallim net f = @l. (f ---> l) net`;;
+
+let TENDSTO_REAL = prove
+ (`(s ---> l) = ((lift o s) --> lift l)`,
+  REWRITE_TAC[FUN_EQ_THM; tendsto; tendsto_real; o_THM; DIST_LIFT]);;
+
+let REAL_TENDSTO = prove
+ (`(s --> l) = (drop o s ---> drop l)`,
+  REWRITE_TAC[TENDSTO_REAL; o_DEF; LIFT_DROP; ETA_AX]);;
+
+let REALLIM_COMPLEX = prove
+ (`(s ---> l) = ((Cx o s) --> Cx(l))`,
+  REWRITE_TAC[FUN_EQ_THM; tendsto; tendsto_real; o_THM; dist;
+              GSYM CX_SUB; COMPLEX_NORM_CX]);;
+
+let REALLIM_UNIQUE = prove
+ (`!net f l l'.
+         ~trivial_limit net /\ (f ---> l) net /\ (f ---> l') net ==> l = l'`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[TENDSTO_REAL] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LIM_UNIQUE) THEN REWRITE_TAC[LIFT_EQ]);;
+
+let REALLIM_CONST = prove
+ (`!net a. ((\x. a) ---> a) net`,
+  REWRITE_TAC[TENDSTO_REAL; o_DEF; LIM_CONST]);;
+
+let REALLIM_LMUL = prove
+ (`!f l c. (f ---> l) net ==> ((\x. c * f x) ---> c * l) net`,
+  REWRITE_TAC[TENDSTO_REAL; o_DEF; LIFT_CMUL; LIM_CMUL]);;
+
+let REALLIM_RMUL = prove
+ (`!f l c. (f ---> l) net ==> ((\x. f x * c) ---> l * c) net`,
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[REALLIM_LMUL]);;
+
+let REALLIM_LMUL_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[REALLIM_LMUL] THEN
+  DISCH_THEN(MP_TAC o SPEC `inv c:real` o MATCH_MP REALLIM_LMUL) THEN
+  ASM_SIMP_TAC[REAL_MUL_ASSOC; REAL_MUL_LINV; REAL_MUL_LID; ETA_AX]);;
+
+let REALLIM_RMUL_EQ = prove
+ (`!net f l c.
+        ~(c = &0) ==> (((\x. f x * c) ---> l * c) net <=> (f ---> l) net)`,
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[REALLIM_LMUL_EQ]);;
+
+let REALLIM_NEG = prove
+ (`!net f l. (f ---> l) net ==> ((\x. --(f x)) ---> --l) net`,
+  REWRITE_TAC[TENDSTO_REAL; o_DEF; LIFT_NEG; LIM_NEG]);;
+
+let REALLIM_NEG_EQ = prove
+ (`!net f l. ((\x. --(f x)) ---> --l) net <=> (f ---> l) net`,
+  REWRITE_TAC[TENDSTO_REAL; o_DEF; LIFT_NEG; LIM_NEG_EQ]);;
+
+let REALLIM_ADD = prove
+ (`!net:(A)net f g l m.
+    (f ---> l) net /\ (g ---> m) net ==> ((\x. f(x) + g(x)) ---> l + m) net`,
+  REWRITE_TAC[TENDSTO_REAL; o_DEF; LIFT_ADD; LIM_ADD]);;
+
+let REALLIM_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[TENDSTO_REAL; o_DEF; LIFT_SUB; LIM_SUB]);;
+
+let REALLIM_MUL = prove
+ (`!net:(A)net f g l m.
+    (f ---> l) net /\ (g ---> m) net ==> ((\x. f(x) * g(x)) ---> l * m) net`,
+  REWRITE_TAC[REALLIM_COMPLEX; o_DEF; CX_MUL; LIM_COMPLEX_MUL]);;
+
+let REALLIM_INV = prove
+ (`!net f l.
+         (f ---> l) net /\ ~(l = &0) ==> ((\x. inv(f x)) ---> inv l) net`,
+  REWRITE_TAC[REALLIM_COMPLEX; o_DEF; CX_INV; LIM_COMPLEX_INV; GSYM CX_INJ]);;
+
+let REALLIM_DIV = prove
+ (`!net:(A)net f g l m.
+    (f ---> l) net /\ (g ---> m) net /\ ~(m = &0)
+    ==> ((\x. f(x) / g(x)) ---> l / m) net`,
+  SIMP_TAC[real_div; REALLIM_MUL; REALLIM_INV]);;
+
+let REALLIM_ABS = prove
+ (`!net f l. (f ---> l) net ==> ((\x. abs(f x)) ---> abs l) net`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[tendsto_real] 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
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+  REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let REALLIM_POW = prove
+ (`!net f l n. (f ---> l) net ==> ((\x. f x pow n) ---> l pow n) net`,
+  REPLICATE_TAC 3 GEN_TAC THEN
+  INDUCT_TAC THEN ASM_SIMP_TAC[real_pow; REALLIM_CONST; REALLIM_MUL]);;
+
+let REALLIM_MAX = prove
+ (`!net:(A)net f g l m.
+    (f ---> l) net /\ (g ---> m) net
+    ==> ((\x. max (f x) (g x)) ---> max l m) net`,
+  REWRITE_TAC[REAL_ARITH `max x y = inv(&2) * ((x + y) + abs(x - y))`] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REALLIM_LMUL THEN
+  ASM_SIMP_TAC[REALLIM_ADD; REALLIM_ABS; REALLIM_SUB]);;
+
+let REALLIM_MIN = prove
+ (`!net:(A)net f g l m.
+    (f ---> l) net /\ (g ---> m) net
+    ==> ((\x. min (f x) (g x)) ---> min l m) net`,
+  REWRITE_TAC[REAL_ARITH `min x y = inv(&2) * ((x + y) - abs(x - y))`] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REALLIM_LMUL THEN
+  ASM_SIMP_TAC[REALLIM_ADD; REALLIM_ABS; REALLIM_SUB]);;
+
+let REALLIM_NULL = prove
+ (`!net f l. (f ---> l) net <=> ((\x. f(x) - l) ---> &0) net`,
+  REWRITE_TAC[tendsto_real; REAL_SUB_RZERO]);;
+
+let REALLIM_NULL_ADD = prove
+ (`!net:(A)net f g.
+    (f ---> &0) net /\ (g ---> &0) net ==> ((\x. f(x) + g(x)) ---> &0) net`,
+  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP REALLIM_ADD) THEN
+  REWRITE_TAC[REAL_ADD_LID]);;
+
+let REALLIM_NULL_LMUL = prove
+ (`!net f c. (f ---> &0) net ==> ((\x. c * f x) ---> &0) net`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o SPEC `c:real` o MATCH_MP REALLIM_LMUL) THEN
+  REWRITE_TAC[REAL_MUL_RZERO]);;
+
+let REALLIM_NULL_RMUL = prove
+ (`!net f c. (f ---> &0) net ==> ((\x. f x * c) ---> &0) net`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o SPEC `c:real` o MATCH_MP REALLIM_RMUL) THEN
+  REWRITE_TAC[REAL_MUL_LZERO]);;
+
+let REALLIM_NULL_POW = prove
+ (`!net f n. (f ---> &0) net /\ ~(n = 0) ==> ((\x. f x pow n) ---> &0) net`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2
+   (MP_TAC o SPEC `n:num` o MATCH_MP REALLIM_POW) ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[REAL_POW_ZERO]);;
+
+let REALLIM_NULL_LMUL_EQ = prove
+ (`!net f c.
+        ~(c = &0) ==> (((\x. c * f x) ---> &0) net <=> (f ---> &0) net)`,
+  MESON_TAC[REALLIM_LMUL_EQ; REAL_MUL_RZERO]);;
+
+let REALLIM_NULL_RMUL_EQ = prove
+ (`!net f c.
+        ~(c = &0) ==> (((\x. f x * c) ---> &0) net <=> (f ---> &0) net)`,
+  MESON_TAC[REALLIM_RMUL_EQ; REAL_MUL_LZERO]);;
+
+let REALLIM_RE = prove
+ (`!net f l. (f --> l) net ==> ((Re o f) ---> Re l) net`,
+  REWRITE_TAC[REALLIM_COMPLEX] THEN
+  REWRITE_TAC[tendsto; dist; o_THM; GSYM CX_SUB; COMPLEX_NORM_CX] THEN
+  REWRITE_TAC[GSYM RE_SUB; eventually] THEN
+  MESON_TAC[REAL_LET_TRANS; COMPLEX_NORM_GE_RE_IM]);;
+
+let REALLIM_IM = prove
+ (`!net f l. (f --> l) net ==> ((Im o f) ---> Im l) net`,
+  REWRITE_TAC[REALLIM_COMPLEX] THEN
+  REWRITE_TAC[tendsto; dist; o_THM; GSYM CX_SUB; COMPLEX_NORM_CX] THEN
+  REWRITE_TAC[GSYM IM_SUB; eventually] THEN
+  MESON_TAC[REAL_LET_TRANS; COMPLEX_NORM_GE_RE_IM]);;
+
+let REALLIM_TRANSFORM_EVENTUALLY = prove
+ (`!net f g l.
+        eventually (\x. f x = g x) net /\ (f ---> l) net ==> (g ---> l) net`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[TENDSTO_REAL] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LIM_TRANSFORM_EVENTUALLY) THEN
+  POP_ASSUM MP_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+  SIMP_TAC[o_THM]);;
+
+let REALLIM_TRANSFORM = prove
+ (`!net f g l.
+        ((\x. f x - g x) ---> &0) net /\ (f ---> l) net ==> (g ---> l) net`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF; LIFT_NUM; LIFT_SUB; LIM_TRANSFORM]);;
+
+let REALLIM_TRANSFORM_EQ = prove
+ (`!net f:A->real g l.
+     ((\x. f x - g x) ---> &0) net ==> ((f ---> l) net <=> (g ---> l) net)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF; LIFT_NUM; LIFT_SUB; LIM_TRANSFORM_EQ]);;
+
+let REAL_SEQ_OFFSET = prove
+ (`!f l k. (f ---> l) sequentially ==> ((\i. f (i + k)) ---> l) sequentially`,
+  REPEAT GEN_TAC THEN SIMP_TAC[TENDSTO_REAL; o_DEF] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SEQ_OFFSET) THEN SIMP_TAC[]);;
+
+let REAL_SEQ_OFFSET_REV = prove
+ (`!f l k. ((\i. f (i + k)) ---> l) sequentially ==> (f ---> l) sequentially`,
+  SIMP_TAC[TENDSTO_REAL; o_DEF] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SEQ_OFFSET_REV THEN EXISTS_TAC `k:num` THEN ASM_SIMP_TAC[]);;
+
+let REALLIM_TRANSFORM_STRADDLE = prove
+ (`!f g h a.
+        eventually (\n. f(n) <= g(n)) net /\ (f ---> a) net /\
+        eventually (\n. g(n) <= h(n)) net /\ (h ---> a) net
+        ==> (g ---> a) net`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[RIGHT_AND_FORALL_THM; tendsto_real; 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[] THEN
+  REWRITE_TAC[GSYM EVENTUALLY_AND] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+  REAL_ARITH_TAC);;
+
+let REALLIM_TRANSFORM_BOUND = prove
+ (`!f g. eventually (\n. abs(f n) <= g n) net /\ (g ---> &0) net
+         ==> (f ---> &0) net`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[RIGHT_AND_FORALL_THM; tendsto_real; 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[] THEN
+  REWRITE_TAC[GSYM EVENTUALLY_AND] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+  REAL_ARITH_TAC);;
+
+let REAL_CONVERGENT_IMP_BOUNDED = prove
+ (`!s l. (s ---> l) sequentially ==> real_bounded (IMAGE s (:num))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_BOUNDED; TENDSTO_REAL] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CONVERGENT_IMP_BOUNDED) THEN
+  REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE; IN_UNIV] THEN
+  REWRITE_TAC[o_DEF; NORM_LIFT]);;
+
+let REALLIM = prove
+ (`(f ---> l) net <=>
+        trivial_limit net \/
+        !e. &0 < e ==> ?y. (?x. netord(net) x y) /\
+                           !x. netord(net) x y ==> abs(f(x) -l) < e`,
+  REWRITE_TAC[tendsto_real; eventually] THEN MESON_TAC[]);;
+
+let REALLIM_NULL_ABS = prove
+ (`!net f. ((\x. abs(f x)) ---> &0) net <=> (f ---> &0) net`,
+  REWRITE_TAC[REALLIM; REAL_SUB_RZERO; REAL_ABS_ABS]);;
+
+let REALLIM_WITHIN_LE = prove
+ (`!f:real^N->real 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
+                                   ==> abs(f(x) - l) < e`,
+  REWRITE_TAC[tendsto_real; EVENTUALLY_WITHIN_LE]);;
+
+let REALLIM_WITHIN = prove
+ (`!f:real^N->real 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
+                    ==> abs(f(x) - l) < e`,
+  REWRITE_TAC[tendsto_real; EVENTUALLY_WITHIN] THEN MESON_TAC[]);;
+
+let REALLIM_AT = prove
+ (`!f l a:real^N.
+      (f ---> l) (at a) <=>
+              !e. &0 < e
+                  ==> ?d. &0 < d /\ !x. &0 < dist(x,a) /\ dist(x,a) < d
+                          ==> abs(f(x) - l) < e`,
+  REWRITE_TAC[tendsto_real; EVENTUALLY_AT] THEN MESON_TAC[]);;
+
+let REALLIM_AT_INFINITY = prove
+ (`!f l. (f ---> l) at_infinity <=>
+               !e. &0 < e ==> ?b. !x. norm(x) >= b ==> abs(f(x) - l) < e`,
+  REWRITE_TAC[tendsto_real; EVENTUALLY_AT_INFINITY] THEN MESON_TAC[]);;
+
+let REALLIM_SEQUENTIALLY = prove
+ (`!s l. (s ---> l) sequentially <=>
+          !e. &0 < e ==> ?N. !n. N <= n ==> abs(s(n) - l) < e`,
+  REWRITE_TAC[tendsto_real; EVENTUALLY_SEQUENTIALLY] THEN MESON_TAC[]);;
+
+let REALLIM_EVENTUALLY = prove
+ (`!net f l. eventually (\x. f x = l) net ==> (f ---> l) net`,
+  REWRITE_TAC[eventually; REALLIM] THEN
+  MESON_TAC[REAL_ARITH `abs(x - x) = &0`]);;
+
+let LIM_COMPONENTWISE = prove
+ (`!net f:A->real^N.
+        (f --> l) net <=>
+        !i. 1 <= i /\ i <= dimindex(:N) ==> ((\x. (f x)$i) ---> l$i) net`,
+  ONCE_REWRITE_TAC[LIM_COMPONENTWISE_LIFT] THEN
+  REWRITE_TAC[TENDSTO_REAL; o_DEF]);;
+
+let REALLIM_UBOUND = prove
+ (`!(net:A net) f l b.
+        (f ---> l) net /\
+        ~trivial_limit net /\
+        eventually (\x. f x <= b) net
+        ==> l <= b`,
+  REWRITE_TAC[FORALL_DROP; TENDSTO_REAL; LIFT_DROP] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(ISPEC `net:A net` LIM_DROP_UBOUND) THEN
+  EXISTS_TAC `lift o (f:A->real)` THEN
+  ASM_REWRITE_TAC[o_THM; LIFT_DROP]);;
+
+let REALLIM_LBOUND = prove
+ (`!(net:A net) f l b.
+        (f ---> l) net /\
+        ~trivial_limit net /\
+        eventually (\x. b <= f x) net
+        ==> b <= l`,
+  ONCE_REWRITE_TAC[GSYM REAL_LE_NEG2] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(ISPEC `net:A net` REALLIM_UBOUND) THEN
+  EXISTS_TAC `\a:A. --(f a:real)` THEN
+  ASM_REWRITE_TAC[REALLIM_NEG_EQ]);;
+
+let REALLIM_LE = prove
+ (`!net f g l m.
+           (f ---> l) net /\ (g ---> m) net /\
+           ~trivial_limit net /\
+           eventually (\x. f x <= g x) net
+           ==> l <= m`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (MP_TAC o MATCH_MP REALLIM_SUB o ONCE_REWRITE_RULE[CONJ_SYM]) MP_TAC) THEN
+  ONCE_REWRITE_TAC[GSYM REAL_SUB_LE] THEN
+  REWRITE_TAC[GSYM IMP_CONJ_ALT; GSYM CONJ_ASSOC] THEN
+  DISCH_THEN(ACCEPT_TAC o MATCH_MP REALLIM_LBOUND));;
+
+let REALLIM_CONST_EQ = prove
+ (`!net:(A net) c d. ((\x. c) ---> d) net <=> trivial_limit net \/ c = d`,
+  REWRITE_TAC[TENDSTO_REAL; LIM_CONST_EQ; o_DEF; LIFT_EQ]);;
+
+let REALLIM_SUM = prove
+ (`!f:A->B->real s.
+        FINITE s /\ (!i. i IN s ==> ((f i) ---> (l i)) net)
+        ==> ((\x. sum s (\i. f i x)) ---> sum s l) net`,
+  GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[SUM_CLAUSES; REALLIM_CONST; REALLIM_ADD; IN_INSERT; ETA_AX]);;
+
+let REALLIM_NULL_COMPARISON = prove
+ (`!net:(A)net f g.
+        eventually (\x. abs(f x) <= g x) net /\ (g ---> &0) net
+        ==> (f ---> &0) net`,
+  REWRITE_TAC[TENDSTO_REAL; LIFT_NUM; o_DEF] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC LIM_NULL_COMPARISON THEN
+  EXISTS_TAC `g:A->real` THEN ASM_REWRITE_TAC[NORM_LIFT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real series.                                                              *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("real_sums",(12,"right"));;
+
+let real_sums = new_definition
+ `(f real_sums l) s <=> ((\n. sum (s INTER (0..n)) f) ---> l) sequentially`;;
+
+let real_infsum = new_definition
+ `real_infsum s f = @l. (f real_sums l) s`;;
+
+let real_summable = new_definition
+ `real_summable s f = ?l. (f real_sums l) s`;;
+
+let REAL_SUMS = prove
+ (`(f real_sums l) = ((lift o f) sums (lift l))`,
+  REWRITE_TAC[FUN_EQ_THM; sums; real_sums; TENDSTO_REAL] THEN
+  SIMP_TAC[LIFT_SUM; FINITE_INTER_NUMSEG; o_DEF]);;
+
+let REAL_SUMS_RE = prove
+ (`!f l s. (f sums l) s ==> ((Re o f) real_sums (Re l)) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_sums; sums] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REALLIM_RE) THEN
+  SIMP_TAC[o_DEF; RE_VSUM; FINITE_INTER_NUMSEG]);;
+
+let REAL_SUMS_IM = prove
+ (`!f l s. (f sums l) s ==> ((Im o f) real_sums (Im l)) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_sums; sums] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REALLIM_IM) THEN
+  SIMP_TAC[o_DEF; IM_VSUM; FINITE_INTER_NUMSEG]);;
+
+let REAL_SUMS_COMPLEX = prove
+ (`!f l s. (f real_sums l) s <=> ((Cx o f) sums (Cx l)) s`,
+  REWRITE_TAC[real_sums; sums; REALLIM_COMPLEX] THEN
+  SIMP_TAC[o_DEF; VSUM_CX; FINITE_INTER; FINITE_NUMSEG]);;
+
+let REAL_SUMMABLE = prove
+ (`real_summable s f <=> summable s (lift o f)`,
+  REWRITE_TAC[real_summable; summable; REAL_SUMS; GSYM EXISTS_LIFT]);;
+
+let REAL_SUMMABLE_COMPLEX = prove
+ (`real_summable s f <=> summable s (Cx o f)`,
+  REWRITE_TAC[real_summable; summable; REAL_SUMS_COMPLEX] THEN
+  EQ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_TAC `l:complex`) THEN EXISTS_TAC `Re l` THEN
+  SUBGOAL_THEN `Cx(Re l) = l` (fun th -> ASM_REWRITE_TAC[th]) THEN
+  REWRITE_TAC[GSYM REAL] THEN MATCH_MP_TAC REAL_SERIES THEN
+  MAP_EVERY EXISTS_TAC [`Cx o (f:num->real)`; `s:num->bool`] THEN
+  ASM_REWRITE_TAC[o_THM; REAL_CX]);;
+
+let REAL_SERIES_CAUCHY = prove
+ (`(?l. (f real_sums l) s) <=>
+   (!e. &0 < e ==> ?N. !m n. m >= N ==> abs(sum(s INTER (m..n)) f) < e)`,
+  REWRITE_TAC[REAL_SUMS; SERIES_CAUCHY; GSYM EXISTS_LIFT] THEN
+  SIMP_TAC[NORM_REAL; GSYM drop; DROP_VSUM; FINITE_INTER_NUMSEG] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX]);;
+
+let REAL_SUMS_SUMMABLE = prove
+ (`!f l s. (f real_sums l) s ==> real_summable s f`,
+  REWRITE_TAC[real_summable] THEN MESON_TAC[]);;
+
+let REAL_SUMS_INFSUM = prove
+ (`!f s. (f real_sums (real_infsum s f)) s <=> real_summable s f`,
+  REWRITE_TAC[real_infsum; real_summable] THEN MESON_TAC[]);;
+
+let REAL_INFSUM_COMPLEX = prove
+ (`!f s. real_summable s f ==> real_infsum s f = Re(infsum s (Cx o f))`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[GSYM REAL_SUMS_INFSUM; REAL_SUMS_COMPLEX] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP INFSUM_UNIQUE) THEN
+  MESON_TAC[RE_CX]);;
+
+let REAL_SERIES_FROM = prove
+ (`!f l k. (f real_sums l) (from k) = ((\n. sum(k..n) f) ---> l) sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_sums] THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; numseg; from; IN_ELIM_THM; IN_INTER] THEN ARITH_TAC);;
+
+let REAL_SERIES_UNIQUE = prove
+ (`!f l l' s. (f real_sums l) s /\ (f real_sums l') s ==> l = l'`,
+  REWRITE_TAC[real_sums] THEN
+  MESON_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; REALLIM_UNIQUE]);;
+
+let REAL_INFSUM_UNIQUE = prove
+ (`!f l s. (f real_sums l) s ==> real_infsum s f = l`,
+  MESON_TAC[REAL_SERIES_UNIQUE; REAL_SUMS_INFSUM; real_summable]);;
+
+let REAL_SERIES_FINITE = prove
+ (`!f s. FINITE s ==> (f real_sums (sum s f)) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[num_FINITE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `n:num` THEN REWRITE_TAC[real_sums; REALLIM_SEQUENTIALLY] THEN
+  DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN EXISTS_TAC `n:num` THEN
+  X_GEN_TAC `m:num` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `s INTER (0..m) = s`
+   (fun th -> ASM_REWRITE_TAC[th; REAL_SUB_REFL; REAL_ABS_NUM]) THEN
+  REWRITE_TAC[EXTENSION; IN_INTER; IN_NUMSEG; LE_0] THEN
+  ASM_MESON_TAC[LE_TRANS]);;
+
+let REAL_SUMMABLE_IFF_EVENTUALLY = prove
+ (`!f g k. (?N. !n. N <= n /\ n IN k ==> f n = g n)
+           ==> (real_summable k f <=> real_summable k g)`,
+  REWRITE_TAC[REAL_SUMMABLE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SUMMABLE_IFF_EVENTUALLY THEN REWRITE_TAC[o_THM] THEN
+  ASM_MESON_TAC[]);;
+
+let REAL_SUMMABLE_EQ_EVENTUALLY = prove
+ (`!f g k. (?N. !n. N <= n /\ n IN k ==> f n = g n) /\ real_summable k f
+           ==> real_summable k g`,
+  MESON_TAC[REAL_SUMMABLE_IFF_EVENTUALLY]);;
+
+let REAL_SUMMABLE_IFF_COFINITE = prove
+ (`!f s t. FINITE((s DIFF t) UNION (t DIFF s))
+           ==> (real_summable s f <=> real_summable t f)`,
+  SIMP_TAC[REAL_SUMMABLE] THEN MESON_TAC[SUMMABLE_IFF_COFINITE]);;
+
+let REAL_SUMMABLE_EQ_COFINITE = prove
+ (`!f s t. FINITE((s DIFF t) UNION (t DIFF s)) /\ real_summable s f
+           ==> real_summable t f`,
+  MESON_TAC[REAL_SUMMABLE_IFF_COFINITE]);;
+
+let REAL_SUMMABLE_FROM_ELSEWHERE = prove
+ (`!f m n. real_summable (from m) f ==> real_summable (from n) f`,
+  REPEAT GEN_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_SUMMABLE_EQ_COFINITE) THEN
+  MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `0..(m+n)` THEN
+  SIMP_TAC[FINITE_NUMSEG; SUBSET; IN_NUMSEG; IN_UNION; IN_DIFF; IN_FROM] THEN
+  ARITH_TAC);;
+
+let REAL_SERIES_GOESTOZERO = prove
+ (`!s x. real_summable s x
+         ==> !e. &0 < e
+                 ==> eventually (\n. n IN s ==> abs(x n) < e) sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_SUMMABLE] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SERIES_GOESTOZERO) THEN
+  REWRITE_TAC[o_THM; NORM_LIFT]);;
+
+let REAL_SUMMABLE_IMP_TOZERO = prove
+ (`!f:num->real k.
+       real_summable k f
+       ==> ((\n. if n IN k then f(n) else &0) ---> &0) sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_SUMMABLE] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SUMMABLE_IMP_TOZERO) THEN
+  REWRITE_TAC[TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF; GSYM LIFT_NUM; GSYM COND_RAND]);;
+
+let REAL_SUMMABLE_IMP_BOUNDED = prove
+ (`!f:num->real k. real_summable k f ==> real_bounded (IMAGE f k)`,
+  REWRITE_TAC[REAL_BOUNDED; REAL_SUMMABLE; GSYM IMAGE_o;
+              SUMMABLE_IMP_BOUNDED]);;
+
+let REAL_SUMMABLE_IMP_REAL_SUMS_BOUNDED = prove
+ (`!f:num->real k.
+       real_summable (from k) f ==> real_bounded { sum(k..n) f | n IN (:num) }`,
+  REWRITE_TAC[real_summable; real_sums; LEFT_IMP_EXISTS_THM] THEN
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REAL_CONVERGENT_IMP_BOUNDED) THEN
+  REWRITE_TAC[FROM_INTER_NUMSEG; SIMPLE_IMAGE]);;
+
+let REAL_SERIES_0 = prove
+ (`!s. ((\n. &0) real_sums (&0)) s`,
+  REWRITE_TAC[real_sums; SUM_0; REALLIM_CONST]);;
+
+let REAL_SERIES_ADD = prove
+ (`!x x0 y y0 s.
+     (x real_sums x0) s /\ (y real_sums y0) s
+     ==> ((\n. x n + y n) real_sums (x0 + y0)) s`,
+  SIMP_TAC[real_sums; FINITE_INTER_NUMSEG; SUM_ADD; REALLIM_ADD]);;
+
+let REAL_SERIES_SUB = prove
+ (`!x x0 y y0 s.
+     (x real_sums x0) s /\ (y real_sums y0) s
+     ==> ((\n. x n - y n) real_sums (x0 - y0)) s`,
+  SIMP_TAC[real_sums; FINITE_INTER_NUMSEG; SUM_SUB; REALLIM_SUB]);;
+
+let REAL_SERIES_LMUL = prove
+ (`!x x0 c s. (x real_sums x0) s ==> ((\n. c * x n) real_sums (c * x0)) s`,
+  SIMP_TAC[real_sums; FINITE_INTER_NUMSEG; SUM_LMUL; REALLIM_LMUL]);;
+
+let REAL_SERIES_RMUL = prove
+ (`!x x0 c s. (x real_sums x0) s ==> ((\n. x n * c) real_sums (x0 * c)) s`,
+  SIMP_TAC[real_sums; FINITE_INTER_NUMSEG; SUM_RMUL; REALLIM_RMUL]);;
+
+let REAL_SERIES_NEG = prove
+ (`!x x0 s. (x real_sums x0) s ==> ((\n. --(x n)) real_sums (--x0)) s`,
+  SIMP_TAC[real_sums; FINITE_INTER_NUMSEG; SUM_NEG; REALLIM_NEG]);;
+
+let REAL_SUMS_IFF = prove
+ (`!f g k. (!x. x IN k ==> f x = g x)
+           ==> ((f real_sums l) k <=> (g real_sums l) k)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[real_sums] THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
+  MATCH_MP_TAC SUM_EQ THEN ASM_SIMP_TAC[IN_INTER]);;
+
+let REAL_SUMS_EQ = prove
+ (`!f g k. (!x. x IN k ==> f x = g x) /\ (f real_sums l) k
+           ==> (g real_sums l) k`,
+  MESON_TAC[REAL_SUMS_IFF]);;
+
+let REAL_SERIES_FINITE_SUPPORT = prove
+ (`!f s k.
+     FINITE (s INTER k) /\ (!x. ~(x IN s INTER k) ==> f x = &0)
+     ==> (f real_sums sum(s INTER k) f) k`,
+  REWRITE_TAC[real_sums; REALLIM_SEQUENTIALLY] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `\x:num. x` o MATCH_MP UPPER_BOUND_FINITE_SET) THEN
+  REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+  STRIP_TAC THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `sum (k INTER (0..n)) (f:num->real) = sum(s INTER k) f`
+   (fun th -> ASM_REWRITE_TAC[REAL_SUB_REFL; REAL_ABS_NUM; th]) THEN
+  MATCH_MP_TAC SUM_SUPERSET THEN
+  ASM_SIMP_TAC[SUBSET; IN_INTER; IN_NUMSEG; LE_0] THEN
+  ASM_MESON_TAC[IN_INTER; LE_TRANS]);;
+
+let REAL_SERIES_DIFFS = prove
+ (`!f k. (f ---> &0) sequentially
+         ==> ((\n. f(n) - f(n + 1)) real_sums f(k)) (from k)`,
+  REWRITE_TAC[real_sums; FROM_INTER_NUMSEG; SUM_DIFFS] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REALLIM_TRANSFORM_EVENTUALLY THEN
+  EXISTS_TAC `\n. (f:num->real) k - f(n + 1)` THEN CONJ_TAC THENL
+   [REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN EXISTS_TAC `k:num` THEN
+    SIMP_TAC[];
+    GEN_REWRITE_TAC LAND_CONV [GSYM REAL_SUB_RZERO] THEN
+    MATCH_MP_TAC REALLIM_SUB THEN REWRITE_TAC[REALLIM_CONST] THEN
+    MATCH_MP_TAC REAL_SEQ_OFFSET THEN ASM_REWRITE_TAC[]]);;
+
+let REAL_SERIES_TRIVIAL = prove
+ (`!f. (f real_sums &0) {}`,
+  REWRITE_TAC[real_sums; INTER_EMPTY; SUM_CLAUSES; REALLIM_CONST]);;
+
+let REAL_SERIES_RESTRICT = prove
+ (`!f k l:real.
+        ((\n. if n IN k then f(n) else &0) real_sums l) (:num) <=>
+        (f real_sums l) k`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_sums] THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; INTER_UNIV] THEN GEN_TAC THEN
+  MATCH_MP_TAC(MESON[] `sum s f = sum t f /\ sum t f = sum t g
+                        ==> sum s f = sum t g`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_SUPERSET THEN SET_TAC[];
+    MATCH_MP_TAC SUM_EQ THEN SIMP_TAC[IN_INTER]]);;
+
+let REAL_SERIES_SUM = prove
+ (`!f l k s. FINITE s /\ s SUBSET k /\ (!x. ~(x IN s) ==> f x = &0) /\
+             sum s f = l ==> (f real_sums l) k`,
+  REPEAT STRIP_TAC THEN EXPAND_TAC "l" THEN
+  SUBGOAL_THEN `s INTER k = s:num->bool` ASSUME_TAC THENL
+   [ASM SET_TAC[]; ASM_MESON_TAC [REAL_SERIES_FINITE_SUPPORT]]);;
+
+let REAL_SUMS_LE2 = prove
+ (`!f g s y z.
+        (f real_sums y) s /\ (g real_sums z) s /\
+        (!i. i IN s ==> f(i) <= g(i))
+        ==> y <= z`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_sums] THEN
+  ONCE_REWRITE_TAC[CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (MATCH_MP_TAC o MATCH_MP
+     (ONCE_REWRITE_RULE[IMP_CONJ]
+       (ONCE_REWRITE_RULE[CONJ_ASSOC] REALLIM_LE)))
+   ASSUME_TAC) THEN
+  ASM_SIMP_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+  ASM_SIMP_TAC[SUM_LE; FINITE_INTER; IN_INTER; FINITE_NUMSEG] THEN
+  REWRITE_TAC[EVENTUALLY_TRUE]);;
+
+let REAL_SUMS_REINDEX = prove
+ (`!k a l n.
+     ((\x. a(x + k)) real_sums l) (from n) <=> (a real_sums l) (from(n + k))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_sums; FROM_INTER_NUMSEG] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM SUM_OFFSET] THEN
+  REWRITE_TAC[REALLIM_SEQUENTIALLY] THEN
+  ASM_MESON_TAC[ARITH_RULE `N + k:num <= n ==> n = (n - k) + k /\ N <= n - k`;
+                ARITH_RULE `N + k:num <= n ==> N <= n + k`]);;
+
+let REAL_INFSUM = prove
+ (`!f s. real_summable s f ==> real_infsum s f = drop(infsum s (lift o f))`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[GSYM REAL_SUMS_INFSUM; REAL_SUMS] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP INFSUM_UNIQUE) THEN
+  MESON_TAC[LIFT_DROP]);;
+
+let REAL_PARTIAL_SUMS_LE_INFSUM = prove
+ (`!f s n.
+        (!i. i IN s ==> &0 <= f i) /\ real_summable s f
+        ==> sum (s INTER (0..n)) f <= real_infsum s f`,
+  REPEAT GEN_TAC THEN SIMP_TAC[REAL_INFSUM] THEN
+  REWRITE_TAC[REAL_SUMMABLE] THEN
+  GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o BINDER_CONV o RAND_CONV o RAND_CONV)
+   [GSYM LIFT_DROP] THEN
+  REWRITE_TAC[o_DEF] THEN DISCH_THEN(MP_TAC o MATCH_MP
+    PARTIAL_SUMS_DROP_LE_INFSUM) THEN
+  SIMP_TAC[DROP_VSUM; FINITE_INTER; FINITE_NUMSEG; o_DEF; LIFT_DROP; ETA_AX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Similar combining theorems just for summability.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_SUMMABLE_0 = prove
+ (`!s. real_summable s (\n. &0)`,
+  REWRITE_TAC[real_summable] THEN MESON_TAC[REAL_SERIES_0]);;
+
+let REAL_SUMMABLE_ADD = prove
+ (`!x y s. real_summable s x /\ real_summable s y
+           ==> real_summable s (\n. x n + y n)`,
+  REWRITE_TAC[real_summable] THEN MESON_TAC[REAL_SERIES_ADD]);;
+
+let REAL_SUMMABLE_SUB = prove
+ (`!x y s. real_summable s x /\ real_summable s y
+           ==> real_summable s (\n. x n - y n)`,
+  REWRITE_TAC[real_summable] THEN MESON_TAC[REAL_SERIES_SUB]);;
+
+let REAL_SUMMABLE_LMUL = prove
+ (`!s x c. real_summable s x ==> real_summable s (\n. c * x n)`,
+  REWRITE_TAC[real_summable] THEN MESON_TAC[REAL_SERIES_LMUL]);;
+
+let REAL_SUMMABLE_RMUL = prove
+ (`!s x c. real_summable s x ==> real_summable s (\n. x n * c)`,
+  REWRITE_TAC[real_summable] THEN MESON_TAC[REAL_SERIES_RMUL]);;
+
+let REAL_SUMMABLE_NEG = prove
+ (`!x s. real_summable s x ==> real_summable s (\n. --(x n))`,
+  REWRITE_TAC[real_summable] THEN MESON_TAC[REAL_SERIES_NEG]);;
+
+let REAL_SUMMABLE_IFF = prove
+ (`!f g k. (!x. x IN k ==> f x = g x)
+           ==> (real_summable k f <=> real_summable k g)`,
+  REWRITE_TAC[real_summable] THEN MESON_TAC[REAL_SUMS_IFF]);;
+
+let REAL_SUMMABLE_EQ = prove
+ (`!f g k. (!x. x IN k ==> f x = g x) /\ real_summable k f
+           ==> real_summable k g`,
+  REWRITE_TAC[real_summable] THEN MESON_TAC[REAL_SUMS_EQ]);;
+
+let REAL_SERIES_SUBSET = prove
+ (`!x s t l.
+        s SUBSET t /\
+        ((\i. if i IN s then x i else &0) real_sums l) t
+        ==> (x real_sums l) s`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[real_sums] THEN MATCH_MP_TAC EQ_IMP THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
+  ASM_SIMP_TAC[GSYM SUM_RESTRICT_SET; FINITE_INTER_NUMSEG] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN POP_ASSUM MP_TAC THEN SET_TAC[]);;
+
+let REAL_SUMMABLE_SUBSET = prove
+ (`!x s t.
+        s SUBSET t /\
+        real_summable t (\i. if i IN s then x i else &0)
+        ==> real_summable s x`,
+  REWRITE_TAC[real_summable] THEN MESON_TAC[REAL_SERIES_SUBSET]);;
+
+let REAL_SUMMABLE_TRIVIAL = prove
+ (`!f. real_summable {} f`,
+  GEN_TAC THEN REWRITE_TAC[real_summable] THEN EXISTS_TAC `&0` THEN
+  REWRITE_TAC[REAL_SERIES_TRIVIAL]);;
+
+let REAL_SUMMABLE_RESTRICT = prove
+ (`!f k.
+        real_summable (:num) (\n. if n IN k then f(n) else &0) <=>
+        real_summable k f`,
+  REWRITE_TAC[real_summable; REAL_SERIES_RESTRICT]);;
+
+let REAL_SUMS_FINITE_DIFF = prove
+ (`!f t s l.
+        t SUBSET s /\ FINITE t /\ (f real_sums l) s
+        ==> (f real_sums (l - sum t f)) (s DIFF t)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `f:num->real` o MATCH_MP REAL_SERIES_FINITE) THEN
+  ONCE_REWRITE_TAC[GSYM REAL_SERIES_RESTRICT] THEN
+  REWRITE_TAC[IMP_IMP] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REAL_SERIES_SUB) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `x:num` THEN REWRITE_TAC[IN_DIFF] THEN
+  FIRST_ASSUM(MP_TAC o SPEC `x:num` o GEN_REWRITE_RULE I [SUBSET]) THEN
+  MAP_EVERY ASM_CASES_TAC [`(x:num) IN s`; `(x:num) IN t`] THEN
+  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let REAL_SUMS_FINITE_UNION = prove
+ (`!f s t l.
+        FINITE t /\ (f real_sums l) s
+        ==> (f real_sums (l + sum (t DIFF s) f)) (s UNION t)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  FIRST_ASSUM(MP_TAC o SPEC `s:num->bool` o MATCH_MP FINITE_DIFF) THEN
+  DISCH_THEN(MP_TAC o ISPEC `f:num->real` o MATCH_MP REAL_SERIES_FINITE) THEN
+  ONCE_REWRITE_TAC[GSYM REAL_SERIES_RESTRICT] THEN
+  REWRITE_TAC[IMP_IMP] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REAL_SERIES_ADD) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `x:num` THEN
+  REWRITE_TAC[IN_DIFF; IN_UNION] THEN
+  MAP_EVERY ASM_CASES_TAC [`(x:num) IN s`; `(x:num) IN t`] THEN
+  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let REAL_SUMS_OFFSET = prove
+ (`!f l m n.
+        (f real_sums l) (from m) /\ m < n
+        ==> (f real_sums (l - sum(m..(n-1)) f)) (from n)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `from n = from m DIFF (m..(n-1))` SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_FROM; IN_DIFF; IN_NUMSEG] THEN ASM_ARITH_TAC;
+    MATCH_MP_TAC REAL_SUMS_FINITE_DIFF THEN ASM_REWRITE_TAC[FINITE_NUMSEG] THEN
+    SIMP_TAC[SUBSET; IN_FROM; IN_NUMSEG]]);;
+
+let REAL_SUMS_OFFSET_REV = prove
+ (`!f l m n.
+        (f real_sums l) (from m) /\ n < m
+        ==> (f real_sums (l + sum(n..m-1) f)) (from n)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:num->real`; `from m`; `n..m-1`; `l:real`]
+                REAL_SUMS_FINITE_UNION) THEN
+  ASM_REWRITE_TAC[FINITE_NUMSEG] THEN MATCH_MP_TAC EQ_IMP THEN
+  BINOP_TAC THENL [AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC; ALL_TAC] THEN
+  REWRITE_TAC[EXTENSION; IN_DIFF; IN_UNION; IN_FROM; IN_NUMSEG] THEN
+  ASM_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Similar combining theorems for infsum.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_INFSUM_0 = prove
+ (`real_infsum s (\i. &0) = &0`,
+  MATCH_MP_TAC REAL_INFSUM_UNIQUE THEN REWRITE_TAC[REAL_SERIES_0]);;
+
+let REAL_INFSUM_ADD = prove
+ (`!x y s. real_summable s x /\ real_summable s y
+           ==> real_infsum s (\i. x i + y i) =
+               real_infsum s x + real_infsum s y`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INFSUM_UNIQUE THEN
+  MATCH_MP_TAC REAL_SERIES_ADD THEN ASM_REWRITE_TAC[REAL_SUMS_INFSUM]);;
+
+let REAL_INFSUM_SUB = prove
+ (`!x y s. real_summable s x /\ real_summable s y
+           ==> real_infsum s (\i. x i - y i) =
+               real_infsum s x - real_infsum s y`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INFSUM_UNIQUE THEN
+  MATCH_MP_TAC REAL_SERIES_SUB THEN ASM_REWRITE_TAC[REAL_SUMS_INFSUM]);;
+
+let REAL_INFSUM_LMUL = prove
+ (`!s x c. real_summable s x
+           ==> real_infsum s (\n. c * x n) = c * real_infsum s x`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INFSUM_UNIQUE THEN
+  MATCH_MP_TAC REAL_SERIES_LMUL THEN ASM_REWRITE_TAC[REAL_SUMS_INFSUM]);;
+
+let REAL_INFSUM_RMUL = prove
+ (`!s x c. real_summable s x
+           ==> real_infsum s (\n. x n * c) = real_infsum s x * c`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INFSUM_UNIQUE THEN
+  MATCH_MP_TAC REAL_SERIES_RMUL THEN ASM_REWRITE_TAC[REAL_SUMS_INFSUM]);;
+
+let REAL_INFSUM_NEG = prove
+ (`!s x. real_summable s x
+         ==> real_infsum s (\n. --(x n)) = --(real_infsum s x)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INFSUM_UNIQUE THEN
+  MATCH_MP_TAC REAL_SERIES_NEG THEN ASM_REWRITE_TAC[REAL_SUMS_INFSUM]);;
+
+let REAL_INFSUM_EQ = prove
+ (`!f g k. real_summable k f /\ real_summable k g /\
+           (!x. x IN k ==> f x = g x)
+           ==> real_infsum k f = real_infsum k g`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[real_infsum] THEN AP_TERM_TAC THEN
+  ABS_TAC THEN ASM_MESON_TAC[REAL_SUMS_EQ; REAL_SUMS_INFSUM]);;
+
+let REAL_INFSUM_RESTRICT = prove
+ (`!k a. real_infsum (:num) (\n. if n IN k then a n else &0) =
+         real_infsum k a`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`a:num->real`; `k:num->bool`] REAL_SUMMABLE_RESTRICT) THEN
+  ASM_CASES_TAC `real_summable k a` THEN ASM_REWRITE_TAC[] THEN
+  STRIP_TAC THENL
+   [MATCH_MP_TAC REAL_INFSUM_UNIQUE THEN
+    ASM_REWRITE_TAC[REAL_SERIES_RESTRICT; REAL_SUMS_INFSUM];
+    RULE_ASSUM_TAC(REWRITE_RULE[real_summable; NOT_EXISTS_THM]) THEN
+    ASM_REWRITE_TAC[real_infsum]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Convergence tests for real series.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_SERIES_CAUCHY_UNIFORM = prove
+ (`!P:A->bool f k.
+        (?l. !e. &0 < e
+                 ==> ?N. !n x. N <= n /\ P x
+                               ==> abs(sum(k INTER (0..n)) (f x) -
+                                        l x) < e) <=>
+        (!e. &0 < e ==> ?N. !m n x. N <= m /\ P x
+                                    ==> abs(sum(k INTER (m..n)) (f x)) < e)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`P:A->bool`; `\x:A n:num. lift(f x n)`; `k:num->bool`]
+        SERIES_CAUCHY_UNIFORM) THEN
+  SIMP_TAC[VSUM_REAL; FINITE_INTER; FINITE_NUMSEG] THEN
+  REWRITE_TAC[NORM_LIFT; o_DEF; LIFT_DROP; ETA_AX] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_TAC `l:A->real`) THEN
+    EXISTS_TAC `lift o (l:A->real)` THEN
+    ASM_SIMP_TAC[o_THM; DIST_LIFT];
+    DISCH_THEN(X_CHOOSE_TAC `l:A->real^1`) THEN
+    EXISTS_TAC `drop o (l:A->real^1)` THEN
+    ASM_SIMP_TAC[SUM_VSUM; FINITE_INTER; FINITE_NUMSEG] THEN
+    REWRITE_TAC[o_THM; GSYM DROP_SUB; GSYM ABS_DROP] THEN
+    SIMP_TAC[GSYM dist; VSUM_REAL; FINITE_INTER; FINITE_NUMSEG] THEN
+    ASM_REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX]]);;
+
+let REAL_SERIES_COMPARISON = prove
+ (`!f g s. (?l. (g real_sums l) s) /\
+           (?N. !n. n >= N /\ n IN s ==> abs(f n) <= g n)
+           ==> ?l. (f real_sums l) s`,
+  REWRITE_TAC[REAL_SUMS; GSYM EXISTS_LIFT] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SERIES_COMPARISON THEN
+  EXISTS_TAC `g:num->real` THEN
+  REWRITE_TAC[NORM_LIFT; o_THM] THEN ASM_MESON_TAC[]);;
+
+let REAL_SUMMABLE_COMPARISON = prove
+ (`!f g s. real_summable s g /\
+           (?N. !n. n >= N /\ n IN s ==> abs(f n) <= g n)
+           ==> real_summable s f`,
+  REWRITE_TAC[real_summable; REAL_SERIES_COMPARISON]);;
+
+let REAL_SERIES_COMPARISON_UNIFORM = prove
+ (`!f g P s. (?l. (g real_sums l) s) /\
+             (?N. !n x. N <= n /\ n IN s /\ P x ==> abs(f x n) <= g n)
+             ==> ?l:A->real.
+                    !e. &0 < e
+                        ==> ?N. !n x. N <= n /\ P x
+                                      ==> abs(sum(s INTER (0..n)) (f x) -
+                                               l x) < e`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[GE; REAL_SERIES_CAUCHY; REAL_SERIES_CAUCHY_UNIFORM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (X_CHOOSE_TAC `N1:num`)) THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN
+  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_TAC `N2:num`) THEN
+  EXISTS_TAC `N1 + N2:num` THEN
+  MAP_EVERY X_GEN_TAC [`m:num`; `n:num`; `x:A`] THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `abs (sum (s INTER (m .. n)) g)` THEN CONJ_TAC THENL
+   [SIMP_TAC[GSYM LIFT_SUM; FINITE_INTER_NUMSEG; NORM_LIFT] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= a ==> x <= abs(a)`) THEN
+    MATCH_MP_TAC SUM_ABS_LE THEN
+    REWRITE_TAC[FINITE_INTER_NUMSEG; IN_INTER; IN_NUMSEG] THEN
+    ASM_MESON_TAC[ARITH_RULE `N1 + N2:num <= m /\ m <= x ==> N1 <= x`];
+    ASM_MESON_TAC[ARITH_RULE `N1 + N2:num <= m ==> N2 <= m`]]);;
+
+let REAL_SERIES_RATIO = prove
+ (`!c a s N.
+      c < &1 /\
+      (!n. n >= N ==> abs(a(SUC n)) <= c * abs(a(n)))
+      ==> ?l:real. (a real_sums l) s`,
+  REWRITE_TAC[REAL_SUMS; GSYM EXISTS_LIFT] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SERIES_RATIO THEN
+  REWRITE_TAC[o_THM; NORM_LIFT] THEN ASM_MESON_TAC[]);;
+
+let BOUNDED_PARTIAL_REAL_SUMS = prove
+ (`!f:num->real k.
+        real_bounded { sum(k..n) f | n IN (:num) }
+        ==> real_bounded { sum(m..n) f | m IN (:num) /\ n IN (:num) }`,
+  REWRITE_TAC[REAL_BOUNDED] THEN
+  REWRITE_TAC[SET_RULE `IMAGE f {g x | P x} = {f(g x) | P x}`;
+    SET_RULE `IMAGE f {g x y | P x /\ Q y} = {f(g x y) | P x /\ Q y}`] THEN
+  SIMP_TAC[LIFT_SUM; FINITE_INTER; FINITE_NUMSEG] THEN
+  REWRITE_TAC[BOUNDED_PARTIAL_SUMS]);;
+
+let REAL_SERIES_DIRICHLET = prove
+ (`!f:num->real g N k m.
+        real_bounded { sum (m..n) f | n IN (:num)} /\
+        (!n. N <= n ==> g(n + 1) <= g(n)) /\
+        (g ---> &0) sequentially
+        ==> real_summable (from k) (\n. g(n) * f(n))`,
+  REWRITE_TAC[REAL_SUMMABLE; REAL_BOUNDED; TENDSTO_REAL] THEN
+  REWRITE_TAC[LIFT_NUM; LIFT_CMUL; o_DEF] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SERIES_DIRICHLET THEN
+  MAP_EVERY EXISTS_TAC [`N:num`; `m:num`] THEN
+  ASM_REWRITE_TAC[o_DEF] THEN
+  SIMP_TAC[VSUM_REAL; FINITE_INTER; FINITE_NUMSEG] THEN
+  ASM_REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX] THEN
+  ASM_REWRITE_TAC[SET_RULE `{lift(f x) | P x} = IMAGE lift {f x | P x}`]);;
+
+let REAL_SERIES_ABSCONV_IMP_CONV = prove
+ (`!x:num->real k. real_summable k (\n. abs(x n)) ==> real_summable k x`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_SUMMABLE_COMPARISON THEN
+  EXISTS_TAC `\n:num. abs(x n)` THEN ASM_REWRITE_TAC[REAL_LE_REFL]);;
+
+let REAL_SUMS_GP = prove
+ (`!n x. abs(x) < &1
+         ==> ((\k. x pow k) real_sums (x pow n / (&1 - x))) (from n)`,
+  REPEAT STRIP_TAC THEN MP_TAC(SPECL [`n:num`; `Cx x`] SUMS_GP) THEN
+  ASM_REWRITE_TAC[REAL_SUMS_COMPLEX; GSYM CX_SUB; GSYM CX_POW; GSYM CX_DIV;
+                  o_DEF; COMPLEX_NORM_CX]);;
+
+let REAL_SUMMABLE_GP = prove
+ (`!x k. abs(x) < &1 ==> real_summable k (\n. x pow n)`,
+  REPEAT STRIP_TAC THEN MP_TAC(SPECL [`Cx x`; `k:num->bool`] SUMMABLE_GP) THEN
+  ASM_REWRITE_TAC[REAL_SUMMABLE_COMPLEX] THEN
+  ASM_REWRITE_TAC[COMPLEX_NORM_CX; o_DEF; CX_POW]);;
+
+let REAL_ABEL_LEMMA = prove
+ (`!a M r r0.
+        &0 <= r /\ r < r0 /\
+        (!n. n IN k ==> abs(a n) * r0 pow n <= M)
+        ==> real_summable k (\n. abs(a(n)) * r pow n)`,
+  REWRITE_TAC[REAL_SUMMABLE_COMPLEX] THEN
+  REWRITE_TAC[o_DEF; CX_MUL; CX_ABS] THEN REWRITE_TAC[GSYM CX_MUL] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ABEL_LEMMA THEN
+  REWRITE_TAC[COMPLEX_NORM_CX] THEN ASM_MESON_TAC[]);;
+
+let REAL_POWER_SERIES_CONV_IMP_ABSCONV = prove
+ (`!a k w z.
+        real_summable k (\n. a(n) * z pow n) /\ abs(w) < abs(z)
+        ==> real_summable k (\n. abs(a(n) * w pow n))`,
+  REWRITE_TAC[REAL_SUMMABLE_COMPLEX; o_DEF; CX_MUL; CX_ABS; CX_POW] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC POWER_SERIES_CONV_IMP_ABSCONV THEN
+  EXISTS_TAC `Cx z` THEN ASM_REWRITE_TAC[COMPLEX_NORM_CX]);;
+
+let POWER_REAL_SERIES_CONV_IMP_ABSCONV_WEAK = prove
+ (`!a k w z.
+        real_summable k (\n. a(n) * z pow n) /\ abs(w) < abs(z)
+        ==> real_summable k (\n. abs(a n) * w pow n)`,
+  REWRITE_TAC[REAL_SUMMABLE_COMPLEX; o_DEF; CX_MUL; CX_ABS; CX_POW] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC POWER_SERIES_CONV_IMP_ABSCONV_WEAK THEN
+  EXISTS_TAC `Cx z` THEN ASM_REWRITE_TAC[COMPLEX_NORM_CX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some real limits involving transcendentals.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let REALLIM_1_OVER_N = prove
+ (`((\n. inv(&n)) ---> &0) sequentially`,
+  REWRITE_TAC[REALLIM_COMPLEX; o_DEF; CX_INV; LIM_INV_N]);;
+
+let REALLIM_LOG_OVER_N = prove
+ (`((\n. log(&n) / &n) ---> &0) sequentially`,
+  REWRITE_TAC[REALLIM_COMPLEX] THEN MP_TAC LIM_LOG_OVER_N THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LIM_TRANSFORM_EVENTUALLY) THEN
+  REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN EXISTS_TAC `1` THEN
+  SIMP_TAC[o_DEF; CX_DIV; CX_LOG; REAL_OF_NUM_LT;
+           ARITH_RULE `1 <= n ==> 0 < n`]);;
+
+let REALLIM_1_OVER_LOG = prove
+ (`((\n. inv(log(&n))) ---> &0) sequentially`,
+  REWRITE_TAC[REALLIM_COMPLEX] THEN MP_TAC LIM_1_OVER_LOG THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LIM_TRANSFORM_EVENTUALLY) THEN
+  REWRITE_TAC[o_DEF; complex_div; COMPLEX_MUL_LID; CX_INV] THEN
+  REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN EXISTS_TAC `1` THEN
+  SIMP_TAC[CX_LOG; REAL_OF_NUM_LT; ARITH_RULE `1 <= n ==> 0 < n`]);;
+
+let REALLIM_POWN = prove
+ (`!z. abs(z) < &1 ==> ((\n. z pow n) ---> &0) sequentially`,
+  REWRITE_TAC[REALLIM_COMPLEX; o_DEF; CX_POW] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC LIM_POWN THEN
+  ASM_REWRITE_TAC[COMPLEX_NORM_CX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Nets for real limit.                                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let atreal = new_definition
+ `atreal a = mk_net(\x y. &0 < abs(x - a) /\ abs(x - a) <= abs(y - a))`;;
+
+let at_posinfinity = new_definition
+  `at_posinfinity = mk_net(\x y:real. x >= y)`;;
+
+let at_neginfinity = new_definition
+  `at_neginfinity = mk_net(\x y:real. x <= y)`;;
+
+let ATREAL = prove
+ (`!a x y.
+        netord(atreal a) x y <=> &0 < abs(x - a) /\ abs(x - a) <= abs(y - a)`,
+  GEN_TAC THEN NET_PROVE_TAC[atreal] THEN
+  MESON_TAC[REAL_LE_TOTAL; REAL_LE_REFL; REAL_LE_TRANS; REAL_LET_TRANS]);;
+
+let AT_POSINFINITY = prove
+ (`!x y. netord at_posinfinity x y <=> x >= y`,
+  NET_PROVE_TAC[at_posinfinity] THEN
+  REWRITE_TAC[real_ge; REAL_LE_REFL] THEN
+  MESON_TAC[REAL_LE_TOTAL; REAL_LE_REFL; REAL_LE_TRANS]);;
+
+let AT_NEGINFINITY = prove
+ (`!x y. netord at_neginfinity x y <=> x <= y`,
+  NET_PROVE_TAC[at_neginfinity] THEN
+  REWRITE_TAC[real_ge; REAL_LE_REFL] THEN
+  MESON_TAC[REAL_LE_TOTAL; REAL_LE_REFL; REAL_LE_TRANS]);;
+
+let WITHINREAL_UNIV = prove
+ (`!x. atreal x within (:real) = atreal x`,
+  REWRITE_TAC[within; atreal; IN_UNIV] THEN REWRITE_TAC[ETA_AX; net_tybij]);;
+
+let TRIVIAL_LIMIT_ATREAL = prove
+ (`!a. ~(trivial_limit (atreal a))`,
+  X_GEN_TAC `a:real` THEN SIMP_TAC[trivial_limit; ATREAL; DE_MORGAN_THM] THEN
+  CONJ_TAC THENL
+   [DISCH_THEN(MP_TAC o SPECL [`&0`; `&1`]) THEN REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`b:real`; `c:real`] THEN
+  ASM_CASES_TAC `b:real = c` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[GSYM DE_MORGAN_THM; GSYM NOT_EXISTS_THM] THEN
+  SUBGOAL_THEN `~(b:real = a) \/ ~(c = a)` DISJ_CASES_TAC THENL
+   [ASM_MESON_TAC[];
+    EXISTS_TAC `(a + b) / &2` THEN ASM_REAL_ARITH_TAC;
+    EXISTS_TAC `(a + c) / &2` THEN ASM_REAL_ARITH_TAC]);;
+
+let TRIVIAL_LIMIT_AT_POSINFINITY = prove
+ (`~(trivial_limit at_posinfinity)`,
+  REWRITE_TAC[trivial_limit; AT_POSINFINITY; DE_MORGAN_THM] THEN
+  CONJ_TAC THENL
+   [DISCH_THEN(MP_TAC o SPECL [`&0`; `&1`]) THEN REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[DE_MORGAN_THM; NOT_EXISTS_THM; real_ge; REAL_NOT_LE] THEN
+  MESON_TAC[REAL_LT_TOTAL; REAL_LT_ANTISYM]);;
+
+let TRIVIAL_LIMIT_AT_NEGINFINITY = prove
+ (`~(trivial_limit at_neginfinity)`,
+  REWRITE_TAC[trivial_limit; AT_NEGINFINITY; DE_MORGAN_THM] THEN
+  CONJ_TAC THENL
+   [DISCH_THEN(MP_TAC o SPECL [`&0`; `&1`]) THEN REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[DE_MORGAN_THM; NOT_EXISTS_THM; real_ge; REAL_NOT_LE] THEN
+  MESON_TAC[REAL_LT_TOTAL; REAL_LT_ANTISYM]);;
+
+let NETLIMIT_WITHINREAL = prove
+ (`!a s. ~(trivial_limit (atreal a within s))
+         ==> (netlimit (atreal a within s) = a)`,
+  REWRITE_TAC[trivial_limit; netlimit; ATREAL; WITHIN; DE_MORGAN_THM] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SELECT_UNIQUE THEN REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `!x. ~(&0 < abs(x - a) /\ abs(x - a) <= abs(a - a) /\ x IN s)`
+  ASSUME_TAC THENL [REAL_ARITH_TAC; ASM_MESON_TAC[]]);;
+
+let NETLIMIT_ATREAL = prove
+ (`!a. netlimit(atreal a) = a`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  MATCH_MP_TAC NETLIMIT_WITHINREAL THEN
+  SIMP_TAC[TRIVIAL_LIMIT_ATREAL; WITHINREAL_UNIV]);;
+
+let EVENTUALLY_WITHINREAL_LE = prove
+ (`!s a p.
+     eventually p (atreal a within s) <=>
+        ?d. &0 < d /\
+            !x. x IN s /\ &0 < abs(x - a) /\ abs(x - a) <= d ==> p(x)`,
+  REWRITE_TAC[eventually; ATREAL; WITHIN; trivial_limit] THEN
+  REWRITE_TAC[MESON[REAL_LT_01; REAL_LT_REFL] `~(!a b:real. a = b)`] THEN
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [DISCH_THEN(DISJ_CASES_THEN(X_CHOOSE_THEN `b:real` MP_TAC)) THENL
+     [DISCH_THEN(X_CHOOSE_THEN `c:real` STRIP_ASSUME_TAC) THEN
+      FIRST_X_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+       `~(b = c) ==> &0 < abs(b - a) \/ &0 < abs(c - a)`)) THEN
+      ASM_MESON_TAC[];
+      MESON_TAC[REAL_LTE_TRANS]];
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    ASM_CASES_TAC `?x. x IN s /\ &0 < abs(x - a) /\ abs(x - a) <= d` THENL
+     [DISJ2_TAC THEN FIRST_X_ASSUM(X_CHOOSE_TAC `b:real`) THEN
+      EXISTS_TAC `b:real` THEN ASM_MESON_TAC[REAL_LE_TRANS; REAL_LE_REFL];
+      DISJ1_TAC THEN MAP_EVERY EXISTS_TAC [`a + d:real`; `a:real`] THEN
+      ASM_SIMP_TAC[REAL_ADD_SUB; REAL_EQ_ADD_LCANCEL_0; REAL_LT_IMP_NZ] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_EXISTS_THM]) THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:real` THEN
+      ASM_CASES_TAC `(x:real) IN s` THEN ASM_REWRITE_TAC[] THEN
+      ASM_REAL_ARITH_TAC]]);;
+
+let EVENTUALLY_WITHINREAL = prove
+ (`!s a p.
+     eventually p (atreal a within s) <=>
+        ?d. &0 < d /\ !x. x IN s /\ &0 < abs(x - a) /\ abs(x - a) < d ==> p(x)`,
+  REWRITE_TAC[EVENTUALLY_WITHINREAL_LE] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> c ==> a /\ b ==> d`] THEN
+  REWRITE_TAC[APPROACHABLE_LT_LE]);;
+
+let EVENTUALLY_ATREAL = prove
+ (`!a p. eventually p (atreal a) <=>
+         ?d. &0 < d /\ !x. &0 < abs(x - a) /\ abs(x - a) < d ==> p(x)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[EVENTUALLY_WITHINREAL; IN_UNIV]);;
+
+let EVENTUALLY_AT_POSINFINITY = prove
+ (`!p. eventually p at_posinfinity <=> ?b. !x. x >= b ==> p x`,
+  REWRITE_TAC[eventually; TRIVIAL_LIMIT_AT_POSINFINITY; AT_POSINFINITY] THEN
+  MESON_TAC[REAL_ARITH `x >= x`]);;
+
+let EVENTUALLY_AT_NEGINFINITY = prove
+ (`!p. eventually p at_neginfinity <=> ?b. !x. x <= b ==> p x`,
+  REWRITE_TAC[eventually; TRIVIAL_LIMIT_AT_NEGINFINITY; AT_NEGINFINITY] THEN
+  MESON_TAC[REAL_LE_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Usual limit results with real domain and either vector or real range.     *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_WITHINREAL_LE = prove
+ (`!f:real->real^N l a s.
+        (f --> l) (atreal a within s) <=>
+           !e. &0 < e ==> ?d. &0 < d /\
+                              !x. x IN s /\ &0 < abs(x - a) /\ abs(x - a) <= d
+                                   ==> dist(f(x),l) < e`,
+  REWRITE_TAC[tendsto; EVENTUALLY_WITHINREAL_LE]);;
+
+let LIM_WITHINREAL = prove
+ (`!f:real->real^N l a s.
+      (f --> l) (atreal a within s) <=>
+        !e. &0 < e
+            ==> ?d. &0 < d /\
+                    !x. x IN s /\ &0 < abs(x - a) /\ abs(x - a) < d
+                    ==> dist(f(x),l) < e`,
+  REWRITE_TAC[tendsto; EVENTUALLY_WITHINREAL] THEN MESON_TAC[]);;
+
+let LIM_ATREAL = prove
+ (`!f l:real^N a.
+      (f --> l) (atreal a) <=>
+              !e. &0 < e
+                  ==> ?d. &0 < d /\ !x. &0 < abs(x - a) /\ abs(x - a) < d
+                          ==> dist(f(x),l) < e`,
+  REWRITE_TAC[tendsto; EVENTUALLY_ATREAL] THEN MESON_TAC[]);;
+
+let LIM_AT_POSINFINITY = prove
+ (`!f l. (f --> l) at_posinfinity <=>
+               !e. &0 < e ==> ?b. !x. x >= b ==> dist(f(x),l) < e`,
+  REWRITE_TAC[tendsto; EVENTUALLY_AT_POSINFINITY] THEN MESON_TAC[]);;
+
+let LIM_AT_NEGINFINITY = prove
+ (`!f l. (f --> l) at_neginfinity <=>
+               !e. &0 < e ==> ?b. !x. x <= b ==> dist(f(x),l) < e`,
+  REWRITE_TAC[tendsto; EVENTUALLY_AT_NEGINFINITY] THEN MESON_TAC[]);;
+
+let REALLIM_WITHINREAL_LE = prove
+ (`!f l a s.
+        (f ---> l) (atreal a within s) <=>
+           !e. &0 < e ==> ?d. &0 < d /\
+                              !x. x IN s /\ &0 < abs(x - a) /\ abs(x - a) <= d
+                                   ==> abs(f(x) - l) < e`,
+  REWRITE_TAC[tendsto_real; EVENTUALLY_WITHINREAL_LE]);;
+
+let REALLIM_WITHINREAL = prove
+ (`!f l a s.
+      (f ---> l) (atreal a within s) <=>
+        !e. &0 < e
+            ==> ?d. &0 < d /\
+                    !x. x IN s /\ &0 < abs(x - a) /\ abs(x - a) < d
+                    ==> abs(f(x) - l) < e`,
+  REWRITE_TAC[tendsto_real; EVENTUALLY_WITHINREAL] THEN MESON_TAC[]);;
+
+let REALLIM_ATREAL = prove
+ (`!f l a.
+      (f ---> l) (atreal a) <=>
+              !e. &0 < e
+                  ==> ?d. &0 < d /\ !x. &0 < abs(x - a) /\ abs(x - a) < d
+                          ==> abs(f(x) - l) < e`,
+  REWRITE_TAC[tendsto_real; EVENTUALLY_ATREAL] THEN MESON_TAC[]);;
+
+let REALLIM_AT_POSINFINITY = prove
+ (`!f l. (f ---> l) at_posinfinity <=>
+               !e. &0 < e ==> ?b. !x. x >= b ==> abs(f(x) - l) < e`,
+  REWRITE_TAC[tendsto_real; EVENTUALLY_AT_POSINFINITY] THEN MESON_TAC[]);;
+
+let REALLIM_AT_NEGINFINITY = prove
+ (`!f l. (f ---> l) at_neginfinity <=>
+               !e. &0 < e ==> ?b. !x. x <= b ==> abs(f(x) - l) < e`,
+  REWRITE_TAC[tendsto_real; EVENTUALLY_AT_NEGINFINITY] THEN MESON_TAC[]);;
+
+let LIM_ATREAL_WITHINREAL = prove
+ (`!f l a s. (f --> l) (atreal a) ==> (f --> l) (atreal a within s)`,
+  REWRITE_TAC[LIM_ATREAL; LIM_WITHINREAL] THEN MESON_TAC[]);;
+
+let REALLIM_ATREAL_WITHINREAL = prove
+ (`!f l a s. (f ---> l) (atreal a) ==> (f ---> l) (atreal a within s)`,
+  REWRITE_TAC[REALLIM_ATREAL; REALLIM_WITHINREAL] THEN MESON_TAC[]);;
+
+let REALLIM_WITHIN_SUBSET = prove
+ (`!f l a s t. (f ---> l) (at a within s) /\ t SUBSET s
+               ==> (f ---> l) (at a within t)`,
+  REWRITE_TAC[REALLIM_WITHIN; SUBSET] THEN MESON_TAC[]);;
+
+let REALLIM_WITHINREAL_SUBSET = prove
+ (`!f l a s t. (f ---> l) (atreal a within s) /\ t SUBSET s
+               ==> (f ---> l) (atreal a within t)`,
+  REWRITE_TAC[REALLIM_WITHINREAL; SUBSET] THEN MESON_TAC[]);;
+
+let LIM_WITHINREAL_SUBSET = prove
+ (`!f l a s t. (f --> l) (atreal a within s) /\ t SUBSET s
+               ==> (f --> l) (atreal a within t)`,
+  REWRITE_TAC[LIM_WITHINREAL; SUBSET] THEN MESON_TAC[]);;
+
+let REALLIM_ATREAL_ID = prove
+ (`((\x. x) ---> a) (atreal a)`,
+  REWRITE_TAC[REALLIM_ATREAL] THEN MESON_TAC[]);;
+
+let REALLIM_WITHINREAL_ID = prove
+ (`!a. ((\x. x) ---> a) (atreal a within s)`,
+  REWRITE_TAC[REALLIM_WITHINREAL] THEN MESON_TAC[]);;
+
+let LIM_TRANSFORM_WITHINREAL_SET = prove
+ (`!f a s t.
+        eventually (\x. x IN s <=> x IN t) (atreal a)
+        ==> ((f --> l) (atreal a within s) <=> (f --> l) (atreal a within t))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[EVENTUALLY_ATREAL; LIM_WITHINREAL] 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[]);;
+
+let REALLIM_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; REALLIM_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[]);;
+
+let REALLIM_TRANSFORM_WITHINREAL_SET = prove
+ (`!f a s t.
+        eventually (\x. x IN s <=> x IN t) (atreal a)
+        ==> ((f ---> l) (atreal a within s) <=>
+             (f ---> l) (atreal a within t))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[EVENTUALLY_ATREAL; REALLIM_WITHINREAL] 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[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relations between limits at real and complex limit points.                *)
+(* ------------------------------------------------------------------------- *)
+
+let TRIVIAL_LIMIT_WITHINREAL_WITHIN = prove
+ (`trivial_limit(atreal x within s) <=>
+        trivial_limit(at (lift x) within (IMAGE lift s))`,
+  REWRITE_TAC[trivial_limit; AT; WITHIN; ATREAL] THEN
+  REWRITE_TAC[FORALL_LIFT; EXISTS_LIFT; LIFT_EQ; DIST_LIFT] THEN
+  REWRITE_TAC[IN_IMAGE_LIFT_DROP; LIFT_DROP]);;
+
+let TRIVIAL_LIMIT_WITHINREAL_WITHINCOMPLEX = prove
+ (`trivial_limit(atreal x within s) <=>
+        trivial_limit(at (Cx x) within (real INTER IMAGE Cx s))`,
+  REWRITE_TAC[trivial_limit; AT; WITHIN; ATREAL] THEN
+  REWRITE_TAC[SET_RULE `x IN real INTER s <=> real x /\ x IN s`] THEN
+  REWRITE_TAC[TAUT `~(p /\ x /\ q) /\ ~(r /\ x /\ s) <=>
+                    x ==> ~(p /\ q) /\ ~(r /\ s)`] THEN
+  REWRITE_TAC[FORALL_REAL;
+    MESON[IN_IMAGE; CX_INJ] `Cx x IN IMAGE Cx s <=> x IN s`] THEN
+  REWRITE_TAC[dist; GSYM CX_SUB; o_THM; RE_CX; COMPLEX_NORM_CX] THEN
+  MATCH_MP_TAC(TAUT `~p /\ ~q /\ (r <=> s) ==> (p \/ r <=> q \/ s)`) THEN
+  REPEAT CONJ_TAC THEN TRY EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+   [DISCH_THEN(MP_TAC o SPECL [`&0`; `&1`]) THEN CONV_TAC REAL_RING;
+    DISCH_THEN(MP_TAC o SPECL [`Cx(&0)`; `Cx(&1)`]) THEN
+    CONV_TAC COMPLEX_RING;
+    MAP_EVERY X_GEN_TAC [`a:real`; `b:real`] THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`Cx a`; `Cx b`] THEN ASM_REWRITE_TAC[CX_INJ] THEN
+    ASM_REWRITE_TAC[GSYM CX_SUB; COMPLEX_NORM_CX];
+    MAP_EVERY X_GEN_TAC [`a:complex`; `b:complex`] THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `?d. &0 < d /\
+          !z. &0 < abs(z - x) /\ abs(z - x) <= d ==> ~(z IN s)`
+    STRIP_ASSUME_TAC THENL
+     [MATCH_MP_TAC(MESON[] `!a b. P a \/ P b ==> ?x. P x`) THEN
+      MAP_EVERY EXISTS_TAC [`norm(a - Cx x)`; `norm(b - Cx x)`] THEN
+      ASM_REWRITE_TAC[TAUT `a ==> ~b <=> ~(a /\ b)`] THEN
+      UNDISCH_TAC `~(a:complex = b)` THEN NORM_ARITH_TAC;
+      ALL_TAC] THEN
+    MAP_EVERY EXISTS_TAC [`x + d:real`; `x - d:real`] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < d ==> ~(x + d = x - d)`;
+                 REAL_ARITH `&0 < d ==> abs((x + d) - x) = d`;
+                 REAL_ARITH `&0 < d ==> abs(x - d - x) = d`] THEN
+    ASM_MESON_TAC[]]);;
+
+let LIM_WITHINREAL_WITHINCOMPLEX = prove
+ (`(f --> a) (atreal x within s) <=>
+   ((f o Re) --> a) (at(Cx x) within (real INTER IMAGE Cx s))`,
+  REWRITE_TAC[LIM_WITHINREAL; LIM_WITHIN] THEN
+  REWRITE_TAC[SET_RULE `x IN real INTER s <=> real x /\ x IN s`] THEN
+  REWRITE_TAC[IMP_CONJ; FORALL_REAL;
+    MESON[IN_IMAGE; CX_INJ] `Cx x IN IMAGE Cx s <=> x IN s`] THEN
+  REWRITE_TAC[dist; GSYM CX_SUB; o_THM; RE_CX; COMPLEX_NORM_CX]);;
+
+let LIM_ATREAL_ATCOMPLEX = prove
+ (`(f --> a) (atreal x) <=> ((f o Re) --> a) (at (Cx x) within real)`,
+  REWRITE_TAC[LIM_ATREAL; LIM_WITHIN] THEN
+  REWRITE_TAC[IMP_CONJ; FORALL_REAL; IN; dist; GSYM CX_SUB; COMPLEX_NORM_CX;
+              o_THM; RE_CX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Simpler theorems relating limits in real and real^1.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_WITHINREAL_WITHIN = prove
+ (`(f --> a) (atreal x within s) <=>
+        ((f o drop) --> a) (at (lift x) within (IMAGE lift s))`,
+  REWRITE_TAC[LIM_WITHINREAL; LIM_WITHIN] THEN
+  REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; DIST_LIFT; o_THM; LIFT_DROP]);;
+
+let LIM_ATREAL_AT = prove
+ (`(f --> a) (atreal x) <=> ((f o drop) --> a) (at (lift x))`,
+  REWRITE_TAC[LIM_ATREAL; LIM_AT; FORALL_LIFT] THEN
+  REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; DIST_LIFT; o_THM; LIFT_DROP]);;
+
+let REALLIM_WITHINREAL_WITHIN = prove
+ (`(f ---> a) (atreal x within s) <=>
+        ((f o drop) ---> a) (at (lift x) within (IMAGE lift s))`,
+  REWRITE_TAC[REALLIM_WITHINREAL; REALLIM_WITHIN] THEN
+  REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; DIST_LIFT; o_THM; LIFT_DROP]);;
+
+let REALLIM_ATREAL_AT = prove
+ (`(f ---> a) (atreal x) <=> ((f o drop) ---> a) (at (lift x))`,
+  REWRITE_TAC[REALLIM_ATREAL; REALLIM_AT; FORALL_LIFT] THEN
+  REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; DIST_LIFT; o_THM; LIFT_DROP]);;
+
+let REALLIM_WITHIN_OPEN = prove
+ (`!f:real^N->real l a s.
+        a IN s /\ open s
+        ==> ((f ---> l) (at a within s) <=> (f ---> l) (at a))`,
+  REWRITE_TAC[TENDSTO_REAL; LIM_WITHIN_OPEN]);;
+
+let LIM_WITHIN_REAL_OPEN = prove
+ (`!f:real->real^N l a s.
+        a IN s /\ real_open s
+        ==> ((f --> l) (atreal a within s) <=> (f --> l) (atreal a))`,
+  REWRITE_TAC[LIM_WITHINREAL_WITHIN; LIM_ATREAL_AT; REAL_OPEN] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC LIM_WITHIN_OPEN THEN ASM SET_TAC[]);;
+
+let REALLIM_WITHIN_REAL_OPEN = prove
+ (`!f l a s.
+        a IN s /\ real_open s
+        ==> ((f ---> l) (atreal a within s) <=> (f ---> l) (atreal a))`,
+  REWRITE_TAC[TENDSTO_REAL; LIM_WITHIN_REAL_OPEN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Additional congruence rules for simplifying limits.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_CONG_WITHINREAL = prove
+ (`(!x. ~(x = a) ==> f x = g x)
+   ==> (((\x. f x) --> l) (atreal a within s) <=>
+        ((g --> l) (atreal a within s)))`,
+  SIMP_TAC[LIM_WITHINREAL; GSYM REAL_ABS_NZ; REAL_SUB_0]);;
+
+let LIM_CONG_ATREAL = prove
+ (`(!x. ~(x = a) ==> f x = g x)
+   ==> (((\x. f x) --> l) (atreal a) <=> ((g --> l) (atreal a)))`,
+  SIMP_TAC[LIM_ATREAL; GSYM REAL_ABS_NZ; REAL_SUB_0]);;
+
+extend_basic_congs [LIM_CONG_WITHINREAL; LIM_CONG_ATREAL];;
+
+let REALLIM_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[REALLIM_WITHIN; GSYM DIST_NZ] THEN SIMP_TAC[]);;
+
+let REALLIM_CONG_AT = prove
+ (`(!x. ~(x = a) ==> f x = g x)
+   ==> (((\x. f x) ---> l) (at a) <=> ((g ---> l) (at a)))`,
+  REWRITE_TAC[REALLIM_AT; GSYM DIST_NZ] THEN SIMP_TAC[]);;
+
+extend_basic_congs [REALLIM_CONG_WITHIN; REALLIM_CONG_AT];;
+
+let REALLIM_CONG_WITHINREAL = prove
+ (`(!x. ~(x = a) ==> f x = g x)
+   ==> (((\x. f x) ---> l) (atreal a within s) <=>
+        ((g ---> l) (atreal a within s)))`,
+  SIMP_TAC[REALLIM_WITHINREAL; GSYM REAL_ABS_NZ; REAL_SUB_0]);;
+
+let REALLIM_CONG_ATREAL = prove
+ (`(!x. ~(x = a) ==> f x = g x)
+   ==> (((\x. f x) ---> l) (atreal a) <=> ((g ---> l) (atreal a)))`,
+  SIMP_TAC[REALLIM_ATREAL; GSYM REAL_ABS_NZ; REAL_SUB_0]);;
+
+extend_basic_congs [REALLIM_CONG_WITHINREAL; REALLIM_CONG_ATREAL];;
+
+(* ------------------------------------------------------------------------- *)
+(* Real version of Abel limit theorem.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_ABEL_LIMIT_THEOREM = prove
+ (`!s a. real_summable s a
+         ==> (!r. abs(r) < &1 ==> real_summable s (\i. a i * r pow i)) /\
+             ((\r. real_infsum s  (\i. a i * r pow i)) ---> real_infsum s a)
+             (atreal (&1) within {z | z <= &1})`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`&1`; `s:num->bool`; `Cx o (a:num->real)`]
+        ABEL_LIMIT_THEOREM) THEN
+  ASM_REWRITE_TAC[GSYM REAL_SUMMABLE_COMPLEX; REAL_LT_01] THEN STRIP_TAC THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [X_GEN_TAC `r:real` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `Cx r`) THEN
+    ASM_REWRITE_TAC[COMPLEX_NORM_CX; REAL_SUMMABLE_COMPLEX] THEN
+    REWRITE_TAC[o_DEF; CX_MUL; CX_POW];
+    DISCH_TAC] THEN
+  REWRITE_TAC[REALLIM_COMPLEX; LIM_WITHINREAL_WITHINCOMPLEX] THEN
+  MATCH_MP_TAC LIM_TRANSFORM_WITHIN THEN
+  EXISTS_TAC `\z. infsum s (\i. (Cx o a) i * z pow i)` THEN
+  EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN CONJ_TAC THENL
+   [REWRITE_TAC[IMP_CONJ; IN_INTER; IN_ELIM_THM; IN_IMAGE] THEN
+    REWRITE_TAC[IN; FORALL_REAL] THEN X_GEN_TAC `r:real` THEN
+    REWRITE_TAC[CX_INJ; UNWIND_THM1; dist; GSYM CX_SUB; COMPLEX_NORM_CX] THEN
+    DISCH_TAC THEN
+    ASM_SIMP_TAC[REAL_ARITH `r <= &1 ==> (&0 < abs(r - &1) <=> r < &1)`] THEN
+    REPEAT DISCH_TAC THEN SUBGOAL_THEN `abs(r) < &1` ASSUME_TAC THENL
+     [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    ASM_SIMP_TAC[REAL_INFSUM_COMPLEX; o_THM; RE_CX] THEN
+    CONV_TAC SYM_CONV THEN REWRITE_TAC[GSYM REAL; o_DEF; CX_MUL; CX_POW] THEN
+    MATCH_MP_TAC(ISPEC `sequentially` REAL_LIM) THEN
+    EXISTS_TAC `\n. vsum(s INTER (0..n)) (\i. Cx(a i) * Cx r pow i)` THEN
+    REWRITE_TAC[SEQUENTIALLY; TRIVIAL_LIMIT_SEQUENTIALLY; GSYM sums] THEN
+    SIMP_TAC[GSYM CX_POW; GSYM CX_MUL; REAL_VSUM; FINITE_INTER; FINITE_NUMSEG;
+             SUMS_INFSUM; REAL_CX; GE] THEN
+    CONJ_TAC THENL [ALL_TAC; MESON_TAC[LE_REFL]] THEN
+    ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+    ASM_SIMP_TAC[GSYM REAL_SUMMABLE_COMPLEX];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_INFSUM_COMPLEX] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIM_WITHIN]) THEN
+  REWRITE_TAC[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
+  REWRITE_TAC[REAL_MUL_LID; IN_ELIM_THM; IN_INTER; IN_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real`
+   (CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "*"))) THEN
+  EXISTS_TAC `min d (&1)` THEN ASM_REWRITE_TAC[REAL_LT_MIN; REAL_LT_01] THEN
+  REWRITE_TAC[IMP_CONJ; IN; FORALL_REAL] THEN
+  REWRITE_TAC[CX_INJ; UNWIND_THM1; dist; GSYM CX_SUB; COMPLEX_NORM_CX] THEN
+  X_GEN_TAC `r:real` THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[REAL_ARITH `r <= &1 ==> (&0 < abs(r - &1) <=> r < &1)`] THEN
+  REPEAT DISCH_TAC THEN SUBGOAL_THEN `abs(r) < &1` ASSUME_TAC THENL
+   [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  REMOVE_THEN "*" (MP_TAC o SPEC `Cx r`) THEN
+  REWRITE_TAC[CX_INJ; UNWIND_THM1; dist; GSYM CX_SUB; COMPLEX_NORM_CX] THEN
+  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  MATCH_MP_TAC(NORM_ARITH `b = a ==> norm(x - a) < e ==> norm(x - b) < e`) THEN
+  REWRITE_TAC[GSYM REAL] THEN
+  MATCH_MP_TAC(ISPEC `sequentially` REAL_LIM) THEN
+  EXISTS_TAC `\n. vsum(s INTER (0..n)) (Cx o a)` THEN
+  REWRITE_TAC[SEQUENTIALLY; TRIVIAL_LIMIT_SEQUENTIALLY; GSYM sums] THEN
+  SIMP_TAC[GSYM CX_POW; GSYM CX_MUL; REAL_VSUM; FINITE_INTER; FINITE_NUMSEG;
+           SUMS_INFSUM; REAL_CX; GE; o_DEF] THEN
+  CONJ_TAC THENL [ALL_TAC; MESON_TAC[LE_REFL]] THEN
+  ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+  ASM_SIMP_TAC[GSYM REAL_SUMMABLE_COMPLEX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Continuity of a function into the reals.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix ("real_continuous",(12,"right"));;
+
+let real_continuous = new_definition
+  `f real_continuous net <=> (f ---> f(netlimit net)) net`;;
+
+let REAL_CONTINUOUS_TRIVIAL_LIMIT = prove
+ (`!f net. trivial_limit net ==> f real_continuous net`,
+  SIMP_TAC[real_continuous; REALLIM]);;
+
+let REAL_CONTINUOUS_WITHIN = prove
+ (`!f x:real^N s.
+        f real_continuous (at x within s) <=>
+                (f ---> f(x)) (at x within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_continuous] THEN
+  ASM_CASES_TAC `trivial_limit(at(x:real^N) within s)` THENL
+   [ASM_REWRITE_TAC[REALLIM]; ASM_SIMP_TAC[NETLIMIT_WITHIN]]);;
+
+let REAL_CONTINUOUS_AT = prove
+ (`!f x. f real_continuous (at x) <=> (f ---> f(x)) (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_WITHIN; IN_UNIV]);;
+
+let REAL_CONTINUOUS_WITHINREAL = prove
+ (`!f x s. f real_continuous (atreal x within s) <=>
+                (f ---> f(x)) (atreal x within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_continuous] THEN
+  ASM_CASES_TAC `trivial_limit(atreal x within s)` THENL
+   [ASM_REWRITE_TAC[REALLIM]; ASM_SIMP_TAC[NETLIMIT_WITHINREAL]]);;
+
+let REAL_CONTINUOUS_ATREAL = prove
+ (`!f x. f real_continuous (atreal x) <=> (f ---> f(x)) (atreal x)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_WITHINREAL; IN_UNIV]);;
+
+let CONTINUOUS_WITHINREAL = prove
+ (`!f x s. f continuous (atreal x within s) <=>
+                 (f --> f(x)) (atreal x within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[continuous] THEN
+  ASM_CASES_TAC `trivial_limit(atreal x within s)` THENL
+   [ASM_REWRITE_TAC[LIM]; ASM_SIMP_TAC[NETLIMIT_WITHINREAL]]);;
+
+let CONTINUOUS_ATREAL = prove
+ (`!f x. f continuous (atreal x) <=> (f --> f(x)) (atreal x)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[CONTINUOUS_WITHINREAL; IN_UNIV]);;
+
+let real_continuous_within = prove
+ (`f real_continuous (at x within s) <=>
+        !e. &0 < e
+            ==> ?d. &0 < d /\
+                    (!x'. x' IN s /\ dist(x',x) < d ==> abs(f x' - f x) < e)`,
+  REWRITE_TAC[REAL_CONTINUOUS_WITHIN; REALLIM_WITHIN] THEN
+  REWRITE_TAC[GSYM DIST_NZ] THEN
+  EQ_TAC THEN 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 GEN_TAC THEN
+  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN MATCH_MP_TAC MONO_FORALL THEN
+  ASM_MESON_TAC[REAL_ARITH `abs(x - x) = &0`]);;
+
+let real_continuous_at = prove
+ (`f real_continuous (at x) <=>
+        !e. &0 < e
+            ==> ?d. &0 < d /\
+                    (!x'. dist(x',x) < d ==> abs(f x' - f x) < e)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[real_continuous_within; IN_UNIV]);;
+
+let real_continuous_withinreal = prove
+ (`f real_continuous (atreal x within s) <=>
+        !e. &0 < e
+            ==> ?d. &0 < d /\
+                    (!x'. x' IN s /\ abs(x' - x) < d ==> abs(f x' - f x) < e)`,
+  REWRITE_TAC[REAL_CONTINUOUS_WITHINREAL; REALLIM_WITHINREAL] THEN
+  REWRITE_TAC[REAL_ARITH `&0 < abs(x - y) <=> ~(x = y)`] THEN
+  EQ_TAC THEN 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 GEN_TAC THEN
+  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN MATCH_MP_TAC MONO_FORALL THEN
+  ASM_MESON_TAC[REAL_ARITH `abs(x - x) = &0`]);;
+
+let real_continuous_atreal = prove
+ (`f real_continuous (atreal x) <=>
+        !e. &0 < e
+            ==> ?d. &0 < d /\
+                    (!x'. abs(x' - x) < d ==> abs(f x' - f x) < e)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[real_continuous_withinreal; IN_UNIV]);;
+
+let REAL_CONTINUOUS_AT_WITHIN = prove
+ (`!f s x. f real_continuous (at x)
+           ==> f real_continuous (at x within s)`,
+  REWRITE_TAC[real_continuous_within; real_continuous_at] THEN
+  MESON_TAC[]);;
+
+let REAL_CONTINUOUS_ATREAL_WITHINREAL = prove
+ (`!f s x. f real_continuous (atreal x)
+           ==> f real_continuous (atreal x within s)`,
+  REWRITE_TAC[real_continuous_withinreal; real_continuous_atreal] THEN
+  MESON_TAC[]);;
+
+let REAL_CONTINUOUS_WITHINREAL_SUBSET = prove
+ (`!f s t. f real_continuous (atreal x within s) /\ t SUBSET s
+             ==> f real_continuous (atreal x within t)`,
+  REWRITE_TAC[REAL_CONTINUOUS_WITHINREAL; REALLIM_WITHINREAL_SUBSET]);;
+
+let REAL_CONTINUOUS_WITHIN_SUBSET = prove
+ (`!f s t. f real_continuous (at x within s) /\ t SUBSET s
+             ==> f real_continuous (at x within t)`,
+  REWRITE_TAC[REAL_CONTINUOUS_WITHIN; REALLIM_WITHIN_SUBSET]);;
+
+let CONTINUOUS_WITHINREAL_SUBSET = prove
+ (`!f s t. f continuous (atreal x within s) /\ t SUBSET s
+             ==> f continuous (atreal x within t)`,
+  REWRITE_TAC[CONTINUOUS_WITHINREAL; LIM_WITHINREAL_SUBSET]);;
+
+let continuous_withinreal = prove
+ (`f continuous (atreal x within s) <=>
+        !e. &0 < e
+            ==> ?d. &0 < d /\
+                    (!x'. x' IN s /\ abs(x' - x) < d ==> dist(f x',f x) < e)`,
+  REWRITE_TAC[CONTINUOUS_WITHINREAL; LIM_WITHINREAL] THEN
+  REWRITE_TAC[REAL_ARITH `&0 < abs(x - y) <=> ~(x = y)`] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `e:real` THEN
+  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `d:real` THEN
+  ASM_CASES_TAC `&0 < d` THEN ASM_REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN ABS_TAC THEN ASM_MESON_TAC[DIST_REFL]);;
+
+let continuous_atreal = prove
+ (`f continuous (atreal x) <=>
+        !e. &0 < e
+            ==> ?d. &0 < d /\
+                    (!x'. abs(x' - x) < d ==> dist(f x',f x) < e)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[continuous_withinreal; IN_UNIV]);;
+
+let CONTINUOUS_ATREAL_WITHINREAL = prove
+ (`!f x s. f continuous (atreal x) ==> f continuous (atreal x within s)`,
+  SIMP_TAC[continuous_atreal; continuous_withinreal] THEN MESON_TAC[]);;
+
+let CONTINUOUS_CX_ATREAL = prove
+ (`!x. Cx continuous (atreal x)`,
+  GEN_TAC THEN REWRITE_TAC[continuous_atreal; dist] THEN
+  REWRITE_TAC[COMPLEX_NORM_CX; GSYM CX_SUB] THEN MESON_TAC[]);;
+
+let CONTINUOUS_CX_WITHINREAL = prove
+ (`!s x. Cx continuous (atreal x within s)`,
+  SIMP_TAC[CONTINUOUS_ATREAL_WITHINREAL; CONTINUOUS_CX_ATREAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Arithmetic combining theorems.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_CONTINUOUS_CONST = prove
+ (`!net c. (\x. c) real_continuous net`,
+  REWRITE_TAC[real_continuous; REALLIM_CONST]);;
+
+let REAL_CONTINUOUS_LMUL = prove
+ (`!f c net. f real_continuous net ==> (\x. c * f(x)) real_continuous net`,
+  REWRITE_TAC[real_continuous; REALLIM_LMUL]);;
+
+let REAL_CONTINUOUS_RMUL = prove
+ (`!f c net. f real_continuous net ==> (\x. f(x) * c) real_continuous net`,
+  REWRITE_TAC[real_continuous; REALLIM_RMUL]);;
+
+let REAL_CONTINUOUS_NEG = prove
+ (`!f net. f real_continuous net ==> (\x. --(f x)) real_continuous net`,
+  REWRITE_TAC[real_continuous; REALLIM_NEG]);;
+
+let REAL_CONTINUOUS_ADD = prove
+ (`!f g net. f real_continuous net /\ g real_continuous net
+           ==> (\x. f(x) + g(x)) real_continuous net`,
+  REWRITE_TAC[real_continuous; REALLIM_ADD]);;
+
+let REAL_CONTINUOUS_SUB = prove
+ (`!f g net. f real_continuous net /\ g real_continuous net
+           ==> (\x. f(x) - g(x)) real_continuous net`,
+  REWRITE_TAC[real_continuous; REALLIM_SUB]);;
+
+let REAL_CONTINUOUS_MUL = prove
+ (`!net f g.
+     f real_continuous net /\ g real_continuous net
+     ==> (\x. f(x) * g(x)) real_continuous net`,
+  SIMP_TAC[real_continuous; REALLIM_MUL]);;
+
+let REAL_CONTINUOUS_INV = prove
+ (`!net f.
+    f real_continuous net /\ ~(f(netlimit net) = &0)
+    ==> (\x. inv(f x)) real_continuous net`,
+  SIMP_TAC[real_continuous; REALLIM_INV]);;
+
+let REAL_CONTINUOUS_DIV = prove
+ (`!net f g.
+    f real_continuous net /\ g real_continuous net /\ ~(g(netlimit net) = &0)
+    ==> (\x. f(x) / g(x)) real_continuous net`,
+  SIMP_TAC[real_continuous; REALLIM_DIV]);;
+
+let REAL_CONTINUOUS_POW = prove
+ (`!net f n. f real_continuous net ==> (\x. f(x) pow n) real_continuous net`,
+  SIMP_TAC[real_continuous; REALLIM_POW]);;
+
+let REAL_CONTINUOUS_ABS = prove
+ (`!net f. f real_continuous net ==> (\x. abs(f(x))) real_continuous net`,
+  REWRITE_TAC[real_continuous; REALLIM_ABS]);;
+
+let REAL_CONTINUOUS_MAX = prove
+ (`!f g net. f real_continuous net /\ g real_continuous net
+           ==> (\x. max (f x) (g x)) real_continuous net`,
+  REWRITE_TAC[real_continuous; REALLIM_MAX]);;
+
+let REAL_CONTINUOUS_MIN = prove
+ (`!f g net. f real_continuous net /\ g real_continuous net
+           ==> (\x. min (f x) (g x)) real_continuous net`,
+  REWRITE_TAC[real_continuous; REALLIM_MIN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some of these without netlimit, but with many different cases.            *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_CONTINUOUS_WITHIN_ID = prove
+ (`!x s. (\x. x) real_continuous (atreal x within s)`,
+  REWRITE_TAC[real_continuous_withinreal] THEN MESON_TAC[]);;
+
+let REAL_CONTINUOUS_AT_ID = prove
+ (`!x. (\x. x) real_continuous (atreal x)`,
+  REWRITE_TAC[real_continuous_atreal] THEN MESON_TAC[]);;
+
+let REAL_CONTINUOUS_INV_WITHIN = prove
+ (`!f s a. f real_continuous (at a within s) /\ ~(f a = &0)
+           ==> (\x. inv(f x)) real_continuous (at a within s)`,
+  MESON_TAC[REAL_CONTINUOUS_INV; REAL_CONTINUOUS_TRIVIAL_LIMIT;
+            NETLIMIT_WITHIN]);;
+
+let REAL_CONTINUOUS_INV_AT = prove
+ (`!f a. f real_continuous (at a) /\ ~(f a = &0)
+         ==> (\x. inv(f x)) real_continuous (at a)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_INV_WITHIN]);;
+
+let REAL_CONTINUOUS_INV_WITHINREAL = prove
+ (`!f s a. f real_continuous (atreal a within s) /\ ~(f a = &0)
+           ==> (\x. inv(f x)) real_continuous (atreal a within s)`,
+  MESON_TAC[REAL_CONTINUOUS_INV; REAL_CONTINUOUS_TRIVIAL_LIMIT;
+            NETLIMIT_WITHINREAL]);;
+
+let REAL_CONTINUOUS_INV_ATREAL = prove
+ (`!f a. f real_continuous (atreal a) /\ ~(f a = &0)
+         ==> (\x. inv(f x)) real_continuous (atreal a)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_INV_WITHINREAL]);;
+
+let REAL_CONTINUOUS_DIV_WITHIN = prove
+ (`!f s a. f real_continuous (at a within s) /\
+           g real_continuous (at a within s) /\ ~(g a = &0)
+           ==> (\x. f x / g x) real_continuous (at a within s)`,
+  MESON_TAC[REAL_CONTINUOUS_DIV; REAL_CONTINUOUS_TRIVIAL_LIMIT;
+            NETLIMIT_WITHIN]);;
+
+let REAL_CONTINUOUS_DIV_AT = prove
+ (`!f a. f real_continuous (at a) /\
+         g real_continuous (at a) /\ ~(g a = &0)
+         ==> (\x. f x / g x) real_continuous (at a)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_DIV_WITHIN]);;
+
+let REAL_CONTINUOUS_DIV_WITHINREAL = prove
+ (`!f s a. f real_continuous (atreal a within s) /\
+           g real_continuous (atreal a within s) /\ ~(g a = &0)
+           ==> (\x. f x / g x) real_continuous (atreal a within s)`,
+  MESON_TAC[REAL_CONTINUOUS_DIV; REAL_CONTINUOUS_TRIVIAL_LIMIT;
+            NETLIMIT_WITHINREAL]);;
+
+let REAL_CONTINUOUS_DIV_ATREAL = prove
+ (`!f a. f real_continuous (atreal a) /\
+         g real_continuous (atreal a) /\ ~(g a = &0)
+         ==> (\x. f x / g x) real_continuous (atreal a)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_DIV_WITHINREAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Composition of (real->real) o (real->real) functions.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_CONTINUOUS_WITHINREAL_COMPOSE = prove
+ (`!f g x s. f real_continuous (atreal x within s) /\
+             g real_continuous (atreal (f x) within IMAGE f s)
+             ==> (g o f) real_continuous (atreal x within s)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[real_continuous_withinreal; 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 REAL_CONTINUOUS_ATREAL_COMPOSE = prove
+ (`!f g x. f real_continuous (atreal x) /\ g real_continuous (atreal (f x))
+           ==> (g o f) real_continuous (atreal x)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[real_continuous_atreal; 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[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Composition of (real->real) o (real^N->real) functions.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_CONTINUOUS_WITHIN_COMPOSE = prove
+ (`!f g x s. f real_continuous (at x within s) /\
+             g real_continuous (atreal (f x) within IMAGE f s)
+             ==> (g o f) real_continuous (at x within s)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[real_continuous_withinreal; real_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 REAL_CONTINUOUS_AT_COMPOSE = prove
+ (`!f g x. f real_continuous (at x) /\
+           g real_continuous (atreal (f x) within IMAGE f (:real^N))
+           ==> (g o f) real_continuous (at x)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_WITHIN_COMPOSE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Composition of (real^N->real) o (real^M->real^N) functions.               *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_CONTINUOUS_CONTINUOUS_WITHIN_COMPOSE = prove
+ (`!f g x s. f continuous (at x within s) /\
+             g real_continuous (at (f x) within IMAGE f s)
+             ==> (g o f) real_continuous (at x within s)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[real_continuous_within; 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 REAL_CONTINUOUS_CONTINUOUS_AT_COMPOSE = prove
+ (`!f g x. f continuous (at x) /\
+           g real_continuous (at (f x) within IMAGE f (:real^N))
+           ==> (g o f) real_continuous (at x)`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[WITHIN_WITHIN; INTER_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS_WITHIN_COMPOSE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Composition of (real^N->real) o (real->real^N) functions.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_CONTINUOUS_CONTINUOUS_WITHINREAL_COMPOSE = prove
+ (`!f g x s. f continuous (atreal x within s) /\
+             g real_continuous (at (f x) within IMAGE f s)
+             ==> (g o f) real_continuous (atreal x within s)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[real_continuous_within; continuous_withinreal;
+              real_continuous_withinreal; 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 REAL_CONTINUOUS_CONTINUOUS_ATREAL_COMPOSE = prove
+ (`!f g x. f continuous (atreal x) /\
+           g real_continuous (at (f x) within IMAGE f (:real))
+           ==> (g o f) real_continuous (atreal x)`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS_WITHINREAL_COMPOSE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Composition of (real->real^N) o (real->real) functions.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_REAL_CONTINUOUS_WITHINREAL_COMPOSE = prove
+ (`!f g x s. f real_continuous (atreal x within s) /\
+             g continuous (atreal (f x) within IMAGE f s)
+             ==> (g o f) continuous (atreal x within s)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[real_continuous_within; continuous_withinreal;
+              real_continuous_withinreal; 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_REAL_CONTINUOUS_ATREAL_COMPOSE = prove
+ (`!f g x. f real_continuous (atreal x) /\
+           g continuous (atreal (f x) within IMAGE f (:real))
+           ==> (g o f) continuous (atreal x)`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[WITHIN_WITHIN; INTER_UNIV] THEN
+  REWRITE_TAC[CONTINUOUS_REAL_CONTINUOUS_WITHINREAL_COMPOSE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Composition of (real^M->real^N) o (real->real^M) functions.               *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_WITHINREAL_COMPOSE = prove
+ (`!f g x s. f continuous (atreal x within s) /\
+             g continuous (at (f x) within IMAGE f s)
+             ==> (g o f) continuous (atreal x within s)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[continuous_within; continuous_withinreal; 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_ATREAL_COMPOSE = prove
+ (`!f g x. f continuous (atreal x) /\
+           g continuous (at (f x) within IMAGE f (:real))
+           ==> (g o f) continuous (atreal x)`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[WITHIN_WITHIN; INTER_UNIV] THEN
+  REWRITE_TAC[CONTINUOUS_WITHINREAL_COMPOSE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Composition of (real->real^N) o (real^M->real) functions.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_REAL_CONTINUOUS_WITHIN_COMPOSE = prove
+ (`!f g x s. f real_continuous (at x within s) /\
+             g continuous (atreal (f x) within IMAGE f s)
+             ==> (g o f) continuous (at x within s)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[continuous_within; real_continuous_within; continuous_withinreal;
+              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_REAL_CONTINUOUS_AT_COMPOSE = prove
+ (`!f g x. f real_continuous (at x) /\
+           g continuous (atreal (f x) within IMAGE f (:real^M))
+           ==> (g o f) continuous (at x)`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[WITHIN_WITHIN; INTER_UNIV] THEN
+  REWRITE_TAC[CONTINUOUS_REAL_CONTINUOUS_WITHIN_COMPOSE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Continuity of a real->real function on a set.                             *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix ("real_continuous_on",(12,"right"));;
+
+let real_continuous_on = new_definition
+  `f real_continuous_on s <=>
+        !x. x IN s ==> !e. &0 < e
+                           ==> ?d. &0 < d /\
+                                   !x'. x' IN s /\ abs(x' - x) < d
+                                        ==> abs(f(x') - f(x)) < e`;;
+
+let REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN = prove
+ (`!f s. f real_continuous_on s <=>
+              !x. x IN s ==> f real_continuous (atreal x within s)`,
+  REWRITE_TAC[real_continuous_on; real_continuous_withinreal]);;
+
+let REAL_CONTINUOUS_ON_SUBSET = prove
+ (`!f s t. f real_continuous_on s /\ t SUBSET s ==> f real_continuous_on t`,
+  REWRITE_TAC[real_continuous_on; SUBSET] THEN MESON_TAC[]);;
+
+let REAL_CONTINUOUS_ON_COMPOSE = prove
+ (`!f g s. f real_continuous_on s /\ g real_continuous_on (IMAGE f s)
+           ==> (g o f) real_continuous_on s`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  MESON_TAC[IN_IMAGE; REAL_CONTINUOUS_WITHINREAL_COMPOSE]);;
+
+let REAL_CONTINUOUS_ON = prove
+ (`!f s. f real_continuous_on s <=>
+          (lift o f o drop) continuous_on (IMAGE lift s)`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+              CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+              REAL_CONTINUOUS_WITHINREAL; CONTINUOUS_WITHIN;
+              FORALL_IN_IMAGE; REALLIM_WITHINREAL_WITHIN; TENDSTO_REAL] THEN
+  REWRITE_TAC[o_THM; LIFT_DROP]);;
+
+let REAL_CONTINUOUS_ON_CONST = prove
+ (`!s c. (\x. c) real_continuous_on s`,
+  SIMP_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; REAL_CONTINUOUS_CONST]);;
+
+let REAL_CONTINUOUS_ON_ID = prove
+ (`!s. (\x. x) real_continuous_on s`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+              REAL_CONTINUOUS_WITHIN_ID]);;
+
+let REAL_CONTINUOUS_ON_LMUL = prove
+ (`!f c s. f real_continuous_on s ==> (\x. c * f(x)) real_continuous_on s`,
+  SIMP_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; REAL_CONTINUOUS_LMUL]);;
+
+let REAL_CONTINUOUS_ON_RMUL = prove
+ (`!f c s. f real_continuous_on s ==> (\x. f(x) * c) real_continuous_on s`,
+  SIMP_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; REAL_CONTINUOUS_RMUL]);;
+
+let REAL_CONTINUOUS_ON_NEG = prove
+ (`!f s. f real_continuous_on s
+         ==> (\x. --(f x)) real_continuous_on s`,
+  SIMP_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; REAL_CONTINUOUS_NEG]);;
+
+let REAL_CONTINUOUS_ON_ADD = prove
+ (`!f g s. f real_continuous_on s /\ g real_continuous_on s
+           ==> (\x. f(x) + g(x)) real_continuous_on s`,
+  SIMP_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; REAL_CONTINUOUS_ADD]);;
+
+let REAL_CONTINUOUS_ON_SUB = prove
+ (`!f g s. f real_continuous_on s /\ g real_continuous_on s
+           ==> (\x. f(x) - g(x)) real_continuous_on s`,
+  SIMP_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; REAL_CONTINUOUS_SUB]);;
+
+let REAL_CONTINUOUS_ON_MUL = prove
+ (`!f g s. f real_continuous_on s /\ g real_continuous_on s
+           ==> (\x. f(x) * g(x)) real_continuous_on s`,
+  SIMP_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; REAL_CONTINUOUS_MUL]);;
+
+let REAL_CONTINUOUS_ON_POW = prove
+ (`!f n s. f real_continuous_on s
+           ==> (\x. f(x) pow n) real_continuous_on s`,
+  SIMP_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; REAL_CONTINUOUS_POW]);;
+
+let REAL_CONTINUOUS_ON_EQ = prove
+ (`!f g s. (!x. x IN s ==> f(x) = g(x)) /\ f real_continuous_on s
+           ==> g real_continuous_on s`,
+  SIMP_TAC[real_continuous_on; IMP_CONJ]);;
+
+let REAL_CONTINUOUS_ON_UNION = prove
+ (`!f s t.
+         real_closed s /\ real_closed t /\
+         f real_continuous_on s /\ f real_continuous_on t
+         ==> f real_continuous_on (s UNION t)`,
+  REWRITE_TAC[REAL_CLOSED; REAL_CONTINUOUS_ON; IMAGE_UNION;
+              CONTINUOUS_ON_UNION]);;
+
+let REAL_CONTINUOUS_ON_UNION_OPEN = prove
+ (`!f s t.
+         real_open s /\ real_open t /\
+         f real_continuous_on s /\ f real_continuous_on t
+         ==> f real_continuous_on (s UNION t)`,
+  REWRITE_TAC[REAL_OPEN; REAL_CONTINUOUS_ON; IMAGE_UNION;
+              CONTINUOUS_ON_UNION_OPEN]);;
+
+let REAL_CONTINUOUS_ON_CASES = prove
+ (`!P f g s t.
+        real_closed s /\ real_closed t /\
+        f real_continuous_on s /\ g real_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) real_continuous_on (s UNION t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_CONTINUOUS_ON_UNION THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THEN MATCH_MP_TAC REAL_CONTINUOUS_ON_EQ THENL
+   [EXISTS_TAC `f:real->real`; EXISTS_TAC `g:real->real`] THEN
+  ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]);;
+
+let REAL_CONTINUOUS_ON_CASES_OPEN = prove
+ (`!P f g s t.
+        real_open s /\ real_open t /\
+        f real_continuous_on s /\ g real_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) real_continuous_on (s UNION t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_CONTINUOUS_ON_UNION_OPEN THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THEN MATCH_MP_TAC REAL_CONTINUOUS_ON_EQ THENL
+   [EXISTS_TAC `f:real->real`; EXISTS_TAC `g:real->real`] THEN
+  ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]);;
+
+let REAL_CONTINUOUS_ON_SUM = prove
+ (`!t f s.
+         FINITE s /\ (!a. a IN s ==> f a real_continuous_on t)
+         ==> (\x. sum s (\a. f a x)) real_continuous_on t`,
+  REPEAT GEN_TAC THEN SIMP_TAC[REAL_CONTINUOUS_ON; o_DEF; LIFT_SUM] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CONTINUOUS_ON_VSUM) THEN
+  REWRITE_TAC[]);;
+
+let REALLIM_CONTINUOUS_FUNCTION = prove
+ (`!f net g l.
+        f continuous (atreal l) /\ (g ---> l) net
+        ==> ((\x. f(g x)) --> f l) net`,
+  REWRITE_TAC[tendsto_real; tendsto; continuous_atreal; eventually] THEN
+  MESON_TAC[]);;
+
+let LIM_REAL_CONTINUOUS_FUNCTION = prove
+ (`!f net g l.
+        f real_continuous (at l) /\ (g --> l) net
+        ==> ((\x. f(g x)) ---> f l) net`,
+  REWRITE_TAC[tendsto_real; tendsto; real_continuous_at; eventually] THEN
+  MESON_TAC[]);;
+
+let REALLIM_REAL_CONTINUOUS_FUNCTION = prove
+ (`!f net g l.
+        f real_continuous (atreal l) /\ (g ---> l) net
+        ==> ((\x. f(g x)) ---> f l) net`,
+  REWRITE_TAC[tendsto_real; real_continuous_atreal; eventually] THEN
+  MESON_TAC[]);;
+
+let REAL_CONTINUOUS_ON_EQ_REAL_CONTINUOUS_AT = prove
+ (`!f s. real_open s
+         ==> (f real_continuous_on s <=>
+              !x. x IN s ==> f real_continuous atreal x)`,
+  SIMP_TAC[REAL_CONTINUOUS_ATREAL; REAL_CONTINUOUS_WITHINREAL;
+        REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; REALLIM_WITHIN_REAL_OPEN]);;
+
+let REAL_CONTINUOUS_ATTAINS_SUP = prove
+ (`!f s. real_compact s /\ ~(s = {}) /\ f real_continuous_on s
+         ==> ?x. x IN s /\ (!y. y IN s ==> f y <= f x)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(f:real->real) o drop`; `IMAGE lift s`]
+        CONTINUOUS_ATTAINS_SUP) THEN
+  ASM_REWRITE_TAC[GSYM REAL_CONTINUOUS_ON; GSYM real_compact] THEN
+  ASM_REWRITE_TAC[IMAGE_EQ_EMPTY; EXISTS_IN_IMAGE; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[o_THM; LIFT_DROP]);;
+
+let REAL_CONTINUOUS_ATTAINS_INF = prove
+ (`!f s. real_compact s /\ ~(s = {}) /\ f real_continuous_on s
+         ==> ?x. x IN s /\ (!y. y IN s ==> f x <= f y)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(f:real->real) o drop`; `IMAGE lift s`]
+        CONTINUOUS_ATTAINS_INF) THEN
+  ASM_REWRITE_TAC[GSYM REAL_CONTINUOUS_ON; GSYM real_compact] THEN
+  ASM_REWRITE_TAC[IMAGE_EQ_EMPTY; EXISTS_IN_IMAGE; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[o_THM; LIFT_DROP]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real version of uniform continuity.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix ("real_uniformly_continuous_on",(12,"right"));;
+
+let real_uniformly_continuous_on = new_definition
+  `f real_uniformly_continuous_on s <=>
+        !e. &0 < e
+            ==> ?d. &0 < d /\
+                    !x x'. x IN s /\ x' IN s /\ abs(x' - x) < d
+                           ==> abs(f x' - f x) < e`;;
+
+let REAL_UNIFORMLY_CONTINUOUS_ON = prove
+ (`!f s. f real_uniformly_continuous_on s <=>
+          (lift o f o drop) uniformly_continuous_on (IMAGE lift s)`,
+  REWRITE_TAC[real_uniformly_continuous_on; uniformly_continuous_on] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[o_THM; DIST_LIFT; LIFT_DROP]);;
+
+let REAL_UNIFORMLY_CONTINUOUS_IMP_REAL_CONTINUOUS = prove
+ (`!f s. f real_uniformly_continuous_on s ==> f real_continuous_on s`,
+  REWRITE_TAC[real_uniformly_continuous_on; real_continuous_on] THEN
+  MESON_TAC[]);;
+
+let REAL_UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY = prove
+ (`!f s. f real_uniformly_continuous_on s <=>
+                !x y. (!n. x(n) IN s) /\ (!n. y(n) IN s) /\
+                      ((\n. x(n) - y(n)) ---> &0) sequentially
+                      ==> ((\n. f(x(n)) - f(y(n))) ---> &0) sequentially`,
+  REWRITE_TAC[REAL_UNIFORMLY_CONTINUOUS_ON] THEN
+  REWRITE_TAC[UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY; REAL_TENDSTO] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP; IN_IMAGE_LIFT_DROP; DROP_SUB; DROP_VEC] THEN
+  REWRITE_TAC[FORALL_LIFT_FUN; o_THM; LIFT_DROP]);;
+
+let REAL_UNIFORMLY_CONTINUOUS_ON_SUBSET = prove
+ (`!f s t. f real_uniformly_continuous_on s /\ t SUBSET s
+           ==> f real_uniformly_continuous_on t`,
+  REWRITE_TAC[real_uniformly_continuous_on; SUBSET] THEN MESON_TAC[]);;
+
+let REAL_UNIFORMLY_CONTINUOUS_ON_COMPOSE = prove
+ (`!f g s. f real_uniformly_continuous_on s /\
+           g real_uniformly_continuous_on (IMAGE f s)
+           ==> (g o f) real_uniformly_continuous_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_UNIFORMLY_CONTINUOUS_ON] THEN
+  SUBGOAL_THEN
+   `IMAGE lift (IMAGE f s) = IMAGE (lift o f o drop) (IMAGE lift s)`
+  SUBST1_TAC THENL
+   [ALL_TAC;
+    DISCH_THEN(MP_TAC o MATCH_MP UNIFORMLY_CONTINUOUS_ON_COMPOSE)] THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; LIFT_DROP]);;
+
+let REAL_UNIFORMLY_CONTINUOUS_ON_CONST = prove
+ (`!s c. (\x. c) real_uniformly_continuous_on s`,
+  REWRITE_TAC[REAL_UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY; o_DEF;
+              REAL_SUB_REFL; REALLIM_CONST]);;
+
+let REAL_UNIFORMLY_CONTINUOUS_ON_LMUL = prove
+ (`!f c s. f real_uniformly_continuous_on s
+           ==> (\x. c * f(x)) real_uniformly_continuous_on s`,
+  REWRITE_TAC[REAL_UNIFORMLY_CONTINUOUS_ON] THEN
+  REWRITE_TAC[o_DEF; LIFT_CMUL; UNIFORMLY_CONTINUOUS_ON_CMUL]);;
+
+let REAL_UNIFORMLY_CONTINUOUS_ON_RMUL = prove
+ (`!f c s. f real_uniformly_continuous_on s
+           ==> (\x. f(x) * c) real_uniformly_continuous_on s`,
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  REWRITE_TAC[REAL_UNIFORMLY_CONTINUOUS_ON_LMUL]);;
+
+let REAL_UNIFORMLY_CONTINUOUS_ON_ID = prove
+ (`!s. (\x. x) real_uniformly_continuous_on s`,
+  REWRITE_TAC[real_uniformly_continuous_on] THEN MESON_TAC[]);;
+
+let REAL_UNIFORMLY_CONTINUOUS_ON_NEG = prove
+ (`!f s. f real_uniformly_continuous_on s
+         ==> (\x. --(f x)) real_uniformly_continuous_on s`,
+  ONCE_REWRITE_TAC[REAL_ARITH `--x = -- &1 * x`] THEN
+  REWRITE_TAC[REAL_UNIFORMLY_CONTINUOUS_ON_LMUL]);;
+
+let REAL_UNIFORMLY_CONTINUOUS_ON_ADD = prove
+ (`!f g s. f real_uniformly_continuous_on s /\
+           g real_uniformly_continuous_on s
+           ==> (\x. f(x) + g(x)) real_uniformly_continuous_on s`,
+  REWRITE_TAC[REAL_UNIFORMLY_CONTINUOUS_ON; o_DEF; LIFT_ADD] THEN
+  REWRITE_TAC[UNIFORMLY_CONTINUOUS_ON_ADD]);;
+
+let REAL_UNIFORMLY_CONTINUOUS_ON_SUB = prove
+ (`!f g s. f real_uniformly_continuous_on s /\
+           g real_uniformly_continuous_on s
+           ==> (\x. f(x) - g(x)) real_uniformly_continuous_on s`,
+  REWRITE_TAC[REAL_UNIFORMLY_CONTINUOUS_ON; o_DEF; LIFT_SUB] THEN
+  REWRITE_TAC[UNIFORMLY_CONTINUOUS_ON_SUB]);;
+
+let REAL_UNIFORMLY_CONTINUOUS_ON_SUM = prove
+ (`!t f s.
+         FINITE s /\ (!a. a IN s ==> f a real_uniformly_continuous_on t)
+         ==> (\x. sum s (\a. f a x)) real_uniformly_continuous_on t`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[REAL_UNIFORMLY_CONTINUOUS_ON; o_DEF; LIFT_SUM] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP UNIFORMLY_CONTINUOUS_ON_VSUM) THEN
+  REWRITE_TAC[]);;
+
+let REAL_COMPACT_UNIFORMLY_CONTINUOUS = prove
+ (`!f s. f real_continuous_on s /\ real_compact s
+         ==> f real_uniformly_continuous_on s`,
+  REWRITE_TAC[real_compact; REAL_CONTINUOUS_ON; REAL_UNIFORMLY_CONTINUOUS_ON;
+              COMPACT_UNIFORMLY_CONTINUOUS]);;
+
+let REAL_COMPACT_CONTINUOUS_IMAGE = prove
+ (`!f s. f real_continuous_on s /\ real_compact s
+         ==> real_compact (IMAGE f s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_compact; REAL_CONTINUOUS_ON] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP COMPACT_CONTINUOUS_IMAGE) THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; LIFT_DROP]);;
+
+let REAL_DINI = prove
+ (`!f g s.
+        real_compact s /\ (!n. (f n) real_continuous_on s) /\
+        g real_continuous_on s /\
+        (!x. x IN s ==> ((\n. (f n x)) ---> g x) sequentially) /\
+        (!n x. x IN s ==> f n x <= f (n + 1) x)
+        ==> !e. &0 < e
+                ==> eventually (\n. !x. x IN s ==> abs(f n x - g x) < e)
+                               sequentially`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n:num. lift o f n o drop`; `lift o g o drop`;
+                 `IMAGE lift s`] DINI) THEN
+  ASM_REWRITE_TAC[GSYM real_compact; GSYM REAL_CONTINUOUS_ON] THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; o_DEF; LIFT_DROP; REAL_TENDSTO] THEN
+  ASM_SIMP_TAC[GSYM LIFT_SUB; NORM_LIFT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Continuity versus componentwise continuity.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_COMPONENTWISE = prove
+ (`!net f:A->real^N.
+        f continuous net <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> (\x. (f x)$i) real_continuous net`,
+  REWRITE_TAC[real_continuous; continuous; LIM_COMPONENTWISE]);;
+
+let REAL_CONTINUOUS_COMPLEX_COMPONENTS_AT = prove
+ (`!z. Re real_continuous (at z) /\ Im real_continuous (at z)`,
+  GEN_TAC THEN MP_TAC(ISPECL
+   [`at(z:complex)`; `\z:complex. z`] CONTINUOUS_COMPONENTWISE) THEN
+  REWRITE_TAC[CONTINUOUS_AT_ID; DIMINDEX_2; FORALL_2] THEN
+  REWRITE_TAC[GSYM RE_DEF; GSYM IM_DEF; ETA_AX]);;
+
+let REAL_CONTINUOUS_COMPLEX_COMPONENTS_WITHIN = prove
+ (`!s z. Re real_continuous (at z within s) /\
+         Im real_continuous (at z within s)`,
+  MESON_TAC[REAL_CONTINUOUS_COMPLEX_COMPONENTS_AT;
+              REAL_CONTINUOUS_AT_WITHIN]);;
+
+let REAL_CONTINUOUS_NORM_AT = prove
+ (`!z. norm real_continuous (at z)`,
+  REWRITE_TAC[real_continuous_at; dist] THEN
+  GEN_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  EXISTS_TAC `e:real` THEN ASM_REWRITE_TAC[] THEN NORM_ARITH_TAC);;
+
+let REAL_CONTINUOUS_NORM_WITHIN = prove
+ (`!s z. norm real_continuous (at z within s)`,
+  MESON_TAC[REAL_CONTINUOUS_NORM_AT; REAL_CONTINUOUS_AT_WITHIN]);;
+
+let REAL_CONTINUOUS_DIST_AT = prove
+ (`!a z. (\x. dist(a,x)) real_continuous (at z)`,
+  REWRITE_TAC[real_continuous_at; dist] THEN
+  GEN_TAC THEN GEN_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  EXISTS_TAC `e:real` THEN ASM_REWRITE_TAC[] THEN NORM_ARITH_TAC);;
+
+let REAL_CONTINUOUS_DIST_WITHIN = prove
+ (`!a s z. (\x. dist(a,x)) real_continuous (at z within s)`,
+  MESON_TAC[REAL_CONTINUOUS_DIST_AT; REAL_CONTINUOUS_AT_WITHIN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Derivative of real->real function.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix ("has_real_derivative",(12,"right"));;
+parse_as_infix ("real_differentiable",(12,"right"));;
+parse_as_infix ("real_differentiable_on",(12,"right"));;
+
+let has_real_derivative = new_definition
+ `(f has_real_derivative f') net <=>
+        ((\x. inv(x - netlimit net) *
+              (f x - (f(netlimit net) + f' * (x - netlimit net))))
+         ---> &0) net`;;
+
+let real_differentiable = new_definition
+ `f real_differentiable net <=> ?f'. (f has_real_derivative f') net`;;
+
+let real_derivative = new_definition
+ `real_derivative f x = @f'. (f has_real_derivative f') (atreal x)`;;
+
+let higher_real_derivative = define
+ `higher_real_derivative 0 f = f /\
+  (!n. higher_real_derivative (SUC n) f =
+                real_derivative (higher_real_derivative n f))`;;
+
+let real_differentiable_on = new_definition
+ `f real_differentiable_on s <=>
+     !x. x IN s ==> ?f'. (f has_real_derivative f') (atreal x within s)`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic limit definitions in the useful cases.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_REAL_DERIVATIVE_WITHINREAL = prove
+ (`(f has_real_derivative f') (atreal a within s) <=>
+           ((\x. (f x - f a) / (x - a)) ---> f') (atreal a within s)`,
+  REWRITE_TAC[has_real_derivative] THEN
+  ASM_CASES_TAC `trivial_limit(atreal a within s)` THENL
+   [ASM_REWRITE_TAC[REALLIM]; ALL_TAC] THEN
+  ASM_SIMP_TAC[NETLIMIT_WITHINREAL] THEN
+  GEN_REWRITE_TAC RAND_CONV [REALLIM_NULL] THEN
+  REWRITE_TAC[REALLIM_WITHINREAL; REAL_SUB_RZERO] THEN
+  SIMP_TAC[REAL_FIELD
+   `&0 < abs(x - a) ==> (fy - fa) / (x - a) - f' =
+                        inv(x - a) * (fy - (fa + f' * (x - a)))`]);;
+
+let HAS_REAL_DERIVATIVE_ATREAL = prove
+ (`(f has_real_derivative f') (atreal a) <=>
+           ((\x. (f x - f a) / (x - a)) ---> f') (atreal a)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_DERIVATIVE_WITHINREAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relation to Frechet derivative.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_REAL_FRECHET_DERIVATIVE_WITHIN = prove
+ (`(f has_real_derivative f') (atreal x within s) <=>
+        ((lift o f o drop) has_derivative (\x. f' % x))
+        (at (lift x) within (IMAGE lift s))`,
+  REWRITE_TAC[has_derivative_within; HAS_REAL_DERIVATIVE_WITHINREAL] THEN
+  REWRITE_TAC[o_THM; LIFT_DROP; LIM_WITHIN; REALLIM_WITHINREAL] THEN
+  SIMP_TAC[LINEAR_COMPOSE_CMUL; LINEAR_ID; IMP_CONJ] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; DIST_LIFT; GSYM LIFT_SUB; LIFT_DROP;
+    NORM_ARITH `dist(x,vec 0) = norm x`; GSYM LIFT_CMUL; GSYM LIFT_ADD;
+    NORM_LIFT] THEN
+  SIMP_TAC[REAL_FIELD
+   `&0 < abs(y - x)
+    ==> fy - (fx + f' * (y - x)) = (y - x) * ((fy - fx) / (y - x) - f')`] THEN
+  REWRITE_TAC[REAL_ABS_MUL; REAL_MUL_ASSOC; REAL_ABS_INV; REAL_ABS_ABS] THEN
+  SIMP_TAC[REAL_LT_IMP_NZ; REAL_MUL_LINV; REAL_MUL_LID]);;
+
+let HAS_REAL_FRECHET_DERIVATIVE_AT = prove
+ (`(f has_real_derivative f') (atreal x) <=>
+        ((lift o f o drop) has_derivative (\x. f' % x)) (at (lift x))`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV; GSYM WITHIN_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_WITHIN] THEN
+  REWRITE_TAC[IMAGE_LIFT_UNIV]);;
+
+let HAS_REAL_VECTOR_DERIVATIVE_WITHIN = prove
+ (`(f has_real_derivative f') (atreal x within s) <=>
+        ((lift o f o drop) has_vector_derivative (lift f'))
+        (at (lift x) within (IMAGE lift s))`,
+  REWRITE_TAC[has_vector_derivative; HAS_REAL_FRECHET_DERIVATIVE_WITHIN] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; FORALL_LIFT; GSYM LIFT_CMUL] THEN
+  REWRITE_TAC[LIFT_DROP; LIFT_EQ; REAL_MUL_SYM]);;
+
+let HAS_REAL_VECTOR_DERIVATIVE_AT = prove
+ (`(f has_real_derivative f') (atreal x) <=>
+        ((lift o f o drop) has_vector_derivative (lift f')) (at (lift x))`,
+  REWRITE_TAC[has_vector_derivative; HAS_REAL_FRECHET_DERIVATIVE_AT] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; FORALL_LIFT; GSYM LIFT_CMUL] THEN
+  REWRITE_TAC[LIFT_DROP; LIFT_EQ; REAL_MUL_SYM]);;
+
+let REAL_DIFFERENTIABLE_AT = prove
+ (`!f a. f real_differentiable (atreal x) <=>
+         (lift o f o drop) differentiable (at(lift x))`,
+  REWRITE_TAC[real_differentiable; HAS_REAL_FRECHET_DERIVATIVE_AT] THEN
+  REWRITE_TAC[differentiable; has_derivative; LINEAR_SCALING] THEN
+  REWRITE_TAC[LINEAR_1; LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN REWRITE_TAC[UNWIND_THM2]);;
+
+let REAL_DIFFERENTIABLE_WITHIN = prove
+ (`!f a s.
+        f real_differentiable (atreal x within s) <=>
+        (lift o f o drop) differentiable (at(lift x) within IMAGE lift s)`,
+  REWRITE_TAC[real_differentiable; HAS_REAL_FRECHET_DERIVATIVE_WITHIN] THEN
+  REWRITE_TAC[differentiable; has_derivative; LINEAR_SCALING] THEN
+  REWRITE_TAC[LINEAR_1; LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN REWRITE_TAC[UNWIND_THM2]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relation to complex derivative.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_REAL_COMPLEX_DERIVATIVE_WITHIN = prove
+ (`(f has_real_derivative f') (atreal a within s) <=>
+        ((Cx o f o Re) has_complex_derivative (Cx f'))
+                (at (Cx a) within {z | real z /\ Re z IN s})`,
+  REWRITE_TAC[HAS_REAL_DERIVATIVE_WITHINREAL; HAS_COMPLEX_DERIVATIVE_WITHIN;
+              LIM_WITHIN; IN_ELIM_THM; IMP_CONJ; FORALL_REAL] THEN
+  REWRITE_TAC[RE_CX; dist; GSYM CX_SUB; COMPLEX_NORM_CX; o_THM; GSYM CX_DIV;
+              REALLIM_WITHINREAL] THEN
+  MESON_TAC[]);;
+
+let HAS_REAL_COMPLEX_DERIVATIVE_AT = prove
+ (`(f has_real_derivative f') (atreal a) <=>
+       ((Cx o f o Re) has_complex_derivative (Cx f')) (at (Cx a) within real)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_WITHIN] THEN
+  AP_TERM_TAC THEN AP_TERM_TAC THEN SET_TAC[]);;
+
+let REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE = prove
+ (`!f s. f real_differentiable_on s <=>
+         !x. x IN s ==> f real_differentiable (atreal x within s)`,
+  REWRITE_TAC[real_differentiable_on; real_differentiable]);;
+
+let REAL_DIFFERENTIABLE_ON_REAL_OPEN = prove
+ (`!f s. real_open s
+         ==> (f real_differentiable_on s <=>
+              !x. x IN s ==> ?f'. (f has_real_derivative f') (atreal x))`,
+  REWRITE_TAC[real_differentiable_on; HAS_REAL_DERIVATIVE_WITHINREAL;
+              HAS_REAL_DERIVATIVE_ATREAL] THEN
+  SIMP_TAC[REALLIM_WITHIN_REAL_OPEN]);;
+
+let REAL_DIFFERENTIABLE_ON_IMP_DIFFERENTIABLE_WITHIN = prove
+ (`!f s x. f real_differentiable_on s /\ x IN s
+           ==> f real_differentiable (atreal x within s)`,
+  MESON_TAC[REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE]);;
+
+let REAL_DIFFERENTIABLE_ON_IMP_DIFFERENTIABLE_ATREAL = prove
+ (`!f s x. f real_differentiable_on s /\ real_open s /\ x IN s
+           ==> f real_differentiable (atreal x)`,
+  MESON_TAC[REAL_DIFFERENTIABLE_ON_REAL_OPEN; real_differentiable]);;
+
+let HAS_COMPLEX_REAL_DERIVATIVE_WITHIN_GEN = prove
+ (`!f g h s d.
+        &0 < d /\ x IN s /\
+        (h has_complex_derivative Cx(g))
+        (at (Cx x) within {z | real z /\ Re(z) IN s}) /\
+        (!y. y IN s /\ abs(y - x) < d ==>  h(Cx y) = Cx(f y))
+        ==> (f has_real_derivative g) (atreal x within s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_WITHIN] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN THEN
+  MAP_EVERY EXISTS_TAC [`h:complex->complex`; `d:real`] THEN
+  ASM_REWRITE_TAC[IN_ELIM_THM; o_THM; REAL_CX; RE_CX; dist] THEN
+  X_GEN_TAC `w:complex` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `Re w`) THEN
+  FIRST_X_ASSUM(SUBST_ALL_TAC o SYM o GEN_REWRITE_RULE I [REAL]) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM CX_SUB; COMPLEX_NORM_CX]) THEN
+  ASM_REWRITE_TAC[RE_CX]);;
+
+let HAS_COMPLEX_REAL_DERIVATIVE_AT_GEN = prove
+ (`!f g h d.
+        &0 < d /\
+        (h has_complex_derivative Cx(g)) (at (Cx x) within real) /\
+        (!y. abs(y - x) < d ==>  h(Cx y) = Cx(f y))
+        ==> (f has_real_derivative g) (atreal x)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  MATCH_MP_TAC HAS_COMPLEX_REAL_DERIVATIVE_WITHIN_GEN THEN
+  MAP_EVERY EXISTS_TAC [`h:complex->complex`; `d:real`] THEN
+  ASM_REWRITE_TAC[IN_UNIV; ETA_AX; SET_RULE `{x | r x} = r`]);;
+
+let HAS_COMPLEX_REAL_DERIVATIVE_WITHIN = prove
+ (`!f g h s.
+        x IN s /\
+        (h has_complex_derivative Cx(g))
+        (at (Cx x) within {z | real z /\ Re(z) IN s}) /\
+        (!y. y IN s ==>  h(Cx y) = Cx(f y))
+        ==> (f has_real_derivative g) (atreal x within s)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_COMPLEX_REAL_DERIVATIVE_WITHIN_GEN THEN
+  MAP_EVERY EXISTS_TAC [`h:complex->complex`; `&1`] THEN
+  ASM_SIMP_TAC[REAL_LT_01]);;
+
+let HAS_COMPLEX_REAL_DERIVATIVE_AT = prove
+ (`!f g h.
+        (h has_complex_derivative Cx(g)) (at (Cx x) within real) /\
+        (!y. h(Cx y) = Cx(f y))
+        ==> (f has_real_derivative g) (atreal x)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  MATCH_MP_TAC HAS_COMPLEX_REAL_DERIVATIVE_WITHIN THEN
+  EXISTS_TAC `h:complex->complex` THEN
+  ASM_REWRITE_TAC[IN_UNIV; ETA_AX; SET_RULE `{x | r x} = r`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Caratheodory characterization.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_REAL_DERIVATIVE_CARATHEODORY_ATREAL = prove
+ (`!f f' z.
+        (f has_real_derivative f') (atreal z) <=>
+        ?g. (!w. f(w) - f(z) = g(w) * (w - z)) /\
+            g real_continuous atreal z /\ g(z) = f'`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[REAL_RING `w' - z':real = a <=> w' = z' + a`] THEN
+  SIMP_TAC[GSYM FUN_EQ_THM; HAS_REAL_DERIVATIVE_ATREAL;
+           REAL_CONTINUOUS_ATREAL] THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
+   [EXISTS_TAC `\w. if w = z then f':real else (f(w) - f(z)) / (w - z)` THEN
+    ASM_SIMP_TAC[FUN_EQ_THM; COND_RAND; COND_RATOR; REAL_SUB_REFL] THEN
+    CONV_TAC REAL_FIELD;
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN FIRST_X_ASSUM SUBST1_TAC THEN
+    ASM_SIMP_TAC[REAL_RING `(z + a) - (z + b * (w - w)):real = a`] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+      REALLIM_TRANSFORM)) THEN
+    SIMP_TAC[REALLIM_CONST; REAL_FIELD
+     `~(w = z) ==> x - (x * (w - z)) / (w - z) = &0`]]);;
+
+let HAS_REAL_DERIVATIVE_CARATHEODORY_WITHINREAL = prove
+ (`!f f' z s.
+        (f has_real_derivative f') (atreal z within s) <=>
+        ?g. (!w. f(w) - f(z) = g(w) * (w - z)) /\
+            g real_continuous (atreal z within s) /\ g(z) = f'`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[REAL_RING `w' - z':real = a <=> w' = z' + a`] THEN
+  SIMP_TAC[GSYM FUN_EQ_THM; HAS_REAL_DERIVATIVE_WITHINREAL;
+           REAL_CONTINUOUS_WITHINREAL] THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
+   [EXISTS_TAC `\w. if w = z then f':real else (f(w) - f(z)) / (w - z)` THEN
+    ASM_SIMP_TAC[FUN_EQ_THM; COND_RAND; COND_RATOR; REAL_SUB_REFL] THEN
+    CONV_TAC REAL_FIELD;
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN FIRST_X_ASSUM SUBST1_TAC THEN
+    ASM_SIMP_TAC[REAL_RING `(z + a) - (z + b * (w - w)):real = a`] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+      REALLIM_TRANSFORM)) THEN
+    SIMP_TAC[REALLIM_CONST; REAL_FIELD
+     `~(w = z) ==> x - (x * (w - z)) / (w - z) = &0`]]);;
+
+let REAL_DIFFERENTIABLE_CARATHEODORY_ATREAL = prove
+ (`!f z. f real_differentiable atreal z <=>
+         ?g. (!w. f(w) - f(z) = g(w) * (w - z)) /\ g real_continuous atreal z`,
+  SIMP_TAC[real_differentiable; HAS_REAL_DERIVATIVE_CARATHEODORY_ATREAL] THEN
+  MESON_TAC[]);;
+
+let REAL_DIFFERENTIABLE_CARATHEODORY_WITHINREAL = prove
+ (`!f z s.
+      f real_differentiable (atreal z within s) <=>
+      ?g. (!w. f(w) - f(z) = g(w) * (w - z)) /\
+          g real_continuous (atreal z within s)`,
+  SIMP_TAC[real_differentiable;
+           HAS_REAL_DERIVATIVE_CARATHEODORY_WITHINREAL] THEN
+  MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Property of being an interval (equivalent to convex or connected).        *)
+(* ------------------------------------------------------------------------- *)
+
+let is_realinterval = new_definition
+ `is_realinterval s <=>
+        !a b c. a IN s /\ b IN s /\ a <= c /\ c <= b ==> c IN s`;;
+
+let IS_REALINTERVAL_IS_INTERVAL = prove
+ (`!s. is_realinterval s <=> is_interval(IMAGE lift s)`,
+  REWRITE_TAC[IS_INTERVAL_1; is_realinterval] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[LIFT_DROP; IN_IMAGE; EXISTS_DROP; UNWIND_THM1] THEN
+  REWRITE_TAC[GSYM FORALL_DROP]);;
+
+let IS_REALINTERVAL_CONVEX = prove
+ (`!s. is_realinterval s <=> convex(IMAGE lift s)`,
+  REWRITE_TAC[IS_REALINTERVAL_IS_INTERVAL; IS_INTERVAL_CONVEX_1]);;
+
+let IS_REALINTERVAL_CONNECTED = prove
+ (`!s. is_realinterval s <=> connected(IMAGE lift s)`,
+  REWRITE_TAC[IS_REALINTERVAL_IS_INTERVAL; IS_INTERVAL_CONNECTED_1]);;
+
+let TRIVIAL_LIMIT_WITHIN_REALINTERVAL = prove
+ (`!s x. is_realinterval s /\ x IN s
+         ==> (trivial_limit(atreal x within s) <=> s = {x})`,
+  REWRITE_TAC[TRIVIAL_LIMIT_WITHINREAL_WITHIN; IS_REALINTERVAL_CONVEX] THEN
+  REWRITE_TAC[FORALL_DROP; GSYM IN_IMAGE_LIFT_DROP; LIFT_DROP] THEN
+  SIMP_TAC[TRIVIAL_LIMIT_WITHIN_CONVEX] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE_LIFT_DROP; IN_SING] THEN
+  MESON_TAC[LIFT_DROP]);;
+
+let IS_REALINTERVAL_EMPTY = prove
+ (`is_realinterval {}`,
+  REWRITE_TAC[is_realinterval; NOT_IN_EMPTY]);;
+
+let IS_REALINTERVAL_UNION = prove
+ (`!s t. is_realinterval s /\ is_realinterval t /\ ~(s INTER t = {})
+         ==> is_realinterval(s UNION t)`,
+  REWRITE_TAC[is_realinterval; IN_UNION; IN_INTER;
+              NOT_IN_EMPTY; EXTENSION] THEN
+  MESON_TAC[REAL_LE_TRANS; REAL_LE_TOTAL]);;
+
+let IS_REALINTERVAL_UNIV = prove
+ (`is_realinterval (:real)`,
+  REWRITE_TAC[is_realinterval; IN_UNIV]);;
+
+let IS_REAL_INTERVAL_CASES = prove
+ (`!s. is_realinterval s <=>
+        s = {} \/
+        s = (:real) \/
+        (?a. s = {x | a < x}) \/
+        (?a. s = {x | a <= x}) \/
+        (?b. s = {x | x <= b}) \/
+        (?b. s = {x | x < b}) \/
+        (?a b. s = {x | a < x /\ x < b}) \/
+        (?a b. s = {x | a < x /\ x <= b}) \/
+        (?a b. s = {x | a <= x /\ x < b}) \/
+        (?a b. s = {x | a <= x /\ x <= b})`,
+  REWRITE_TAC[IS_REALINTERVAL_IS_INTERVAL; IS_INTERVAL_1_CASES] THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE_LIFT_DROP; IN_ELIM_THM] THEN
+  REWRITE_TAC[GSYM FORALL_DROP; IN_UNIV; NOT_IN_EMPTY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some relations with the complex numbers can also be useful.               *)
+(* ------------------------------------------------------------------------- *)
+
+let IS_REALINTERVAL_CONVEX_COMPLEX = prove
+ (`!s. is_realinterval s <=> convex {z | real z /\ Re z IN s}`,
+  GEN_TAC THEN
+  REWRITE_TAC[GSYM IMAGE_CX; IS_REALINTERVAL_CONVEX] THEN EQ_TAC THENL
+   [DISCH_THEN(MP_TAC o ISPEC `Cx o drop` o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ] CONVEX_LINEAR_IMAGE)) THEN
+    REWRITE_TAC[GSYM IMAGE_o; GSYM o_ASSOC] THEN
+    ONCE_REWRITE_TAC[IMAGE_o] THEN REWRITE_TAC[IMAGE_LIFT_DROP] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    REWRITE_TAC[linear; o_THM; CX_ADD; CX_MUL; DROP_ADD; DROP_CMUL;
+                COMPLEX_CMUL];
+    DISCH_THEN(MP_TAC o ISPEC `lift o Re` o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ] CONVEX_LINEAR_IMAGE)) THEN
+    REWRITE_TAC[GSYM IMAGE_o; GSYM o_ASSOC] THEN
+    ONCE_REWRITE_TAC[IMAGE_o] THEN
+    REWRITE_TAC[o_DEF; RE_CX; SET_RULE `IMAGE (\x. x) s = s`] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    REWRITE_TAC[linear; o_THM; RE_CMUL;
+                RE_ADD; RE_MUL_CX; LIFT_ADD; LIFT_CMUL]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The same tricks to define closed and open intervals.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let open_real_interval = new_definition
+  `open_real_interval(a:real,b:real) = {x:real | a < x /\ x < b}`;;
+
+let closed_real_interval = define
+  `closed_real_interval[a:real,b:real] = {x:real | a <= x /\ x <= b}`;;
+
+make_overloadable "real_interval" `:A`;;
+
+overload_interface("real_interval",`open_real_interval`);;
+overload_interface("real_interval",`closed_real_interval`);;
+
+let real_interval = prove
+ (`real_interval(a,b) = {x | a < x /\ x < b} /\
+   real_interval[a,b] = {x | a <= x /\ x <= b}`,
+  REWRITE_TAC[open_real_interval; closed_real_interval]);;
+
+let IN_REAL_INTERVAL = prove
+ (`!a b x. (x IN real_interval[a,b] <=> a <= x /\ x <= b) /\
+           (x IN real_interval(a,b) <=> a < x /\ x < b)`,
+  REWRITE_TAC[real_interval; IN_ELIM_THM]);;
+
+let REAL_INTERVAL_INTERVAL = prove
+ (`real_interval[a,b] = IMAGE drop (interval[lift a,lift b]) /\
+   real_interval(a,b) = IMAGE drop (interval(lift a,lift b))`,
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_INTERVAL_1; IN_REAL_INTERVAL] THEN
+  REWRITE_TAC[EXISTS_LIFT; LIFT_DROP; UNWIND_THM1]);;
+
+let INTERVAL_REAL_INTERVAL = prove
+ (`interval[a,b] = IMAGE lift (real_interval[drop a,drop b]) /\
+   interval(a,b) = IMAGE lift (real_interval(drop a,drop b))`,
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_INTERVAL_1; IN_REAL_INTERVAL] THEN
+  REWRITE_TAC[EXISTS_DROP; LIFT_DROP; UNWIND_THM1]);;
+
+let EMPTY_AS_REAL_INTERVAL = prove
+ (`{} = real_interval[&1,&0]`,
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; LIFT_NUM; GSYM EMPTY_AS_INTERVAL] THEN
+  REWRITE_TAC[IMAGE_CLAUSES]);;
+
+let IMAGE_LIFT_REAL_INTERVAL = prove
+ (`IMAGE lift (real_interval[a,b]) = interval[lift a,lift b] /\
+   IMAGE lift (real_interval(a,b)) = interval(lift a,lift b)`,
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; GSYM IMAGE_o; o_DEF; LIFT_DROP] THEN
+  SET_TAC[]);;
+
+let IMAGE_DROP_INTERVAL = prove
+ (`IMAGE drop (interval[a,b]) = real_interval[drop a,drop b] /\
+   IMAGE drop (interval(a,b)) = real_interval(drop a,drop b)`,
+  REWRITE_TAC[INTERVAL_REAL_INTERVAL; GSYM IMAGE_o; o_DEF; LIFT_DROP] THEN
+  SET_TAC[]);;
+
+let SUBSET_REAL_INTERVAL = prove
+ (`!a b c d.
+        (real_interval[a,b] SUBSET real_interval[c,d] <=>
+                b < a \/ c <= a /\ a <= b /\ b <= d) /\
+        (real_interval[a,b] SUBSET real_interval(c,d) <=>
+                b < a \/ c < a /\ a <= b /\ b < d) /\
+        (real_interval(a,b) SUBSET real_interval[c,d] <=>
+                b <= a \/ c <= a /\ a < b /\ b <= d) /\
+        (real_interval(a,b) SUBSET real_interval(c,d) <=>
+                b <= a \/ c <= a /\ a < b /\ b <= d)`,
+  let lemma = prove
+   (`IMAGE drop s SUBSET IMAGE drop t <=> s SUBSET t`,
+    SET_TAC[LIFT_DROP]) in
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; lemma; SUBSET_INTERVAL_1] THEN
+  REWRITE_TAC[LIFT_DROP]);;
+
+let REAL_INTERVAL_OPEN_SUBSET_CLOSED = prove
+ (`!a b. real_interval(a,b) SUBSET real_interval[a,b]`,
+  REWRITE_TAC[SUBSET; IN_REAL_INTERVAL] THEN REAL_ARITH_TAC);;
+
+let REAL_INTERVAL_EQ_EMPTY = prove
+ (`(!a b. real_interval[a,b] = {} <=> b < a) /\
+   (!a b. real_interval(a,b) = {} <=> b <= a)`,
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; IMAGE_EQ_EMPTY] THEN
+  REWRITE_TAC[INTERVAL_EQ_EMPTY_1; LIFT_DROP]);;
+
+let REAL_INTERVAL_NE_EMPTY = prove
+ (`(!a b. ~(real_interval[a,b] = {}) <=> a <= b) /\
+   (!a b. ~(real_interval(a,b) = {}) <=> a < b)`,
+  REWRITE_TAC[REAL_INTERVAL_EQ_EMPTY; REAL_NOT_LE; REAL_NOT_LT]);;
+
+let REAL_OPEN_CLOSED_INTERVAL = prove
+ (`!a b. real_interval(a,b) = real_interval[a,b] DIFF {a,b}`,
+  SIMP_TAC[EXTENSION; IN_DIFF; IN_REAL_INTERVAL; IN_INSERT; NOT_IN_EMPTY] THEN
+  REAL_ARITH_TAC);;
+
+let REAL_CLOSED_OPEN_INTERVAL = prove
+ (`!a b. a <= b ==> real_interval[a,b] = real_interval(a,b) UNION {a,b}`,
+  SIMP_TAC[EXTENSION; IN_UNION; IN_REAL_INTERVAL; IN_INSERT; NOT_IN_EMPTY] THEN
+  REAL_ARITH_TAC);;
+
+let REAL_CLOSED_REAL_INTERVAL = prove
+ (`!a b. real_closed(real_interval[a,b])`,
+  REWRITE_TAC[REAL_CLOSED; IMAGE_LIFT_REAL_INTERVAL; CLOSED_INTERVAL]);;
+
+let REAL_OPEN_REAL_INTERVAL = prove
+ (`!a b. real_open(real_interval(a,b))`,
+  REWRITE_TAC[REAL_OPEN; IMAGE_LIFT_REAL_INTERVAL; OPEN_INTERVAL]);;
+
+let REAL_INTERVAL_SING = prove
+ (`!a. real_interval[a,a] = {a} /\ real_interval(a,a) = {}`,
+  REWRITE_TAC[EXTENSION; IN_SING; NOT_IN_EMPTY; IN_REAL_INTERVAL] THEN
+  REAL_ARITH_TAC);;
+
+let REAL_COMPACT_INTERVAL = prove
+ (`!a b. real_compact(real_interval[a,b])`,
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; real_compact] THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; LIFT_DROP; IMAGE_ID; COMPACT_INTERVAL]);;
+
+let IS_REALINTERVAL_INTERVAL = prove
+ (`!a b. is_realinterval(real_interval(a,b)) /\
+         is_realinterval(real_interval[a,b])`,
+  REWRITE_TAC[is_realinterval; IN_REAL_INTERVAL] THEN REAL_ARITH_TAC);;
+
+let REAL_BOUNDED_REAL_INTERVAL = prove
+ (`(!a b. real_bounded(real_interval[a,b])) /\
+   (!a b. real_bounded(real_interval(a,b)))`,
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL; REAL_BOUNDED; BOUNDED_INTERVAL]);;
+
+let ENDS_IN_REAL_INTERVAL = prove
+ (`(!a b. a IN real_interval[a,b] <=> ~(real_interval[a,b] = {})) /\
+   (!a b. b IN real_interval[a,b] <=> ~(real_interval[a,b] = {})) /\
+   (!a b. ~(a IN real_interval(a,b))) /\
+   (!a b. ~(b IN real_interval(a,b)))`,
+  REWRITE_TAC[IN_REAL_INTERVAL; REAL_INTERVAL_EQ_EMPTY] THEN REAL_ARITH_TAC);;
+
+let IMAGE_AFFINITY_REAL_INTERVAL = prove
+ (`!a b m c.
+         IMAGE (\x. m * x + c) (real_interval[a,b]) =
+         (if real_interval[a,b] = {}
+          then {}
+          else if &0 <= m
+               then real_interval[m * a + c,m * b + c]
+               else real_interval[m * b + c,m * a + c])`,
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; GSYM IMAGE_o; o_DEF; IMAGE_EQ_EMPTY] THEN
+  REWRITE_TAC[FORALL_DROP; LIFT_DROP; GSYM DROP_CMUL; GSYM DROP_ADD] THEN
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+  REWRITE_TAC[IMAGE_o; IMAGE_AFFINITY_INTERVAL] THEN
+  MESON_TAC[IMAGE_CLAUSES]);;
+
+let IMAGE_STRETCH_REAL_INTERVAL = prove
+ (`!a b m.
+         IMAGE (\x. m * x) (real_interval[a,b]) =
+         (if real_interval[a,b] = {}
+          then {}
+          else if &0 <= m
+               then real_interval[m * a,m * b]
+               else real_interval[m * b,m * a])`,
+  ONCE_REWRITE_TAC[REAL_ARITH `m * x = m * x + &0`] THEN
+  REWRITE_TAC[IMAGE_AFFINITY_REAL_INTERVAL]);;
+
+let REAL_INTERVAL_TRANSLATION = prove
+ (`(!c a b. real_interval[c + a,c + b] =
+            IMAGE (\x. c + x) (real_interval[a,b])) /\
+   (!c a b. real_interval(c + a,c + b) =
+            IMAGE (\x. c + x) (real_interval(a,b)))`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[REAL_ARITH `c + x:real = y <=> x = y - c`; EXISTS_REFL] THEN
+  REWRITE_TAC[IN_REAL_INTERVAL] THEN REAL_ARITH_TAC);;
+
+let IN_REAL_INTERVAL_REFLECT = prove
+ (`(!a b x. --x IN real_interval[--b,--a] <=> x IN real_interval[a,b]) /\
+   (!a b x. --x IN real_interval(--b,--a) <=> x IN real_interval(a,b))`,
+  REWRITE_TAC[IN_REAL_INTERVAL] THEN REAL_ARITH_TAC);;
+
+let REFLECT_REAL_INTERVAL = prove
+ (`(!a b. IMAGE (--) (real_interval[a,b]) = real_interval[--b,--a]) /\
+   (!a b. IMAGE (--) (real_interval(a,b)) = real_interval(--b,--a))`,
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_IMAGE; IN_REAL_INTERVAL] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `x:real = --y <=> --x = y`] THEN
+  REWRITE_TAC[UNWIND_THM1] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real continuity and differentiability.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_CONTINUOUS_CONTINUOUS = prove
+ (`f real_continuous net <=> (Cx o f) continuous net`,
+  REWRITE_TAC[real_continuous; continuous; REALLIM_COMPLEX; o_THM]);;
+
+let REAL_CONTINUOUS_CONTINUOUS1 = prove
+ (`f real_continuous net <=> (lift o f) continuous net`,
+  REWRITE_TAC[real_continuous; continuous; TENDSTO_REAL; o_THM]);;
+
+let REAL_CONTINUOUS_CONTINUOUS_ATREAL = prove
+ (`f real_continuous (atreal x) <=> (lift o f o drop) continuous (at(lift x))`,
+  REWRITE_TAC[REAL_CONTINUOUS_ATREAL; REALLIM_ATREAL_AT; CONTINUOUS_AT;
+              TENDSTO_REAL; o_THM; LIFT_DROP]);;
+
+let REAL_CONTINUOUS_CONTINUOUS_WITHINREAL = prove
+ (`f real_continuous (atreal x within s) <=>
+   (lift o f o drop) continuous (at(lift x) within IMAGE lift s)`,
+  REWRITE_TAC[REAL_CONTINUOUS_WITHINREAL; REALLIM_WITHINREAL_WITHIN] THEN
+  REWRITE_TAC[TENDSTO_REAL; CONTINUOUS_WITHIN; o_THM; LIFT_DROP]);;
+
+let REAL_COMPLEX_CONTINUOUS_WITHINREAL = prove
+ (`f real_continuous (atreal x within s) <=>
+       (Cx o f o Re) continuous (at (Cx x) within (real INTER IMAGE Cx s))`,
+  REWRITE_TAC[real_continuous; continuous; REALLIM_COMPLEX;
+         LIM_WITHINREAL_WITHINCOMPLEX; NETLIMIT_WITHINREAL; GSYM o_ASSOC] THEN
+  ASM_CASES_TAC `trivial_limit(at(Cx x) within (real INTER IMAGE Cx s))` THENL
+   [ASM_REWRITE_TAC[LIM];
+    ASM_SIMP_TAC[TRIVIAL_LIMIT_WITHINREAL_WITHINCOMPLEX;
+        NETLIMIT_WITHIN; NETLIMIT_WITHINREAL; RE_CX; o_THM]]);;
+
+let REAL_COMPLEX_CONTINUOUS_ATREAL = prove
+ (`f real_continuous (atreal x) <=>
+       (Cx o f o Re) continuous (at (Cx x) within real)`,
+  REWRITE_TAC[real_continuous; continuous; REALLIM_COMPLEX;
+              LIM_ATREAL_ATCOMPLEX; NETLIMIT_ATREAL; GSYM o_ASSOC] THEN
+  ASM_CASES_TAC `trivial_limit(at(Cx x) within real)` THENL
+   [ASM_REWRITE_TAC[LIM];
+    ASM_SIMP_TAC[NETLIMIT_WITHIN; RE_CX; o_THM]]);;
+
+let CONTINUOUS_CONTINUOUS_WITHINREAL = prove
+ (`!f x s. f continuous (atreal x within s) <=>
+           (f o drop) continuous (at (lift x) within IMAGE lift s)`,
+  REWRITE_TAC[REALLIM_WITHINREAL_WITHIN; CONTINUOUS_WITHIN;
+          CONTINUOUS_WITHINREAL; o_DEF; LIFT_DROP; LIM_WITHINREAL_WITHIN]);;
+
+let CONTINUOUS_CONTINUOUS_ATREAL = prove
+ (`!f x. f continuous (atreal x) <=> (f o drop) continuous (at (lift x))`,
+  REWRITE_TAC[REALLIM_ATREAL_AT; CONTINUOUS_AT;
+          CONTINUOUS_ATREAL; o_DEF; LIFT_DROP; LIM_ATREAL_AT]);;
+
+let REAL_CONTINUOUS_REAL_CONTINUOUS_WITHINREAL = prove
+ (`!f x s. f real_continuous (atreal x within s) <=>
+           (f o drop) real_continuous (at (lift x) within IMAGE lift s)`,
+  REWRITE_TAC[REALLIM_WITHINREAL_WITHIN; REAL_CONTINUOUS_WITHIN;
+              REAL_CONTINUOUS_WITHINREAL; o_DEF; LIFT_DROP;
+              LIM_WITHINREAL_WITHIN]);;
+
+let REAL_CONTINUOUS_REAL_CONTINUOUS_ATREAL = prove
+ (`!f x. f real_continuous (atreal x) <=>
+         (f o drop) real_continuous (at (lift x))`,
+  REWRITE_TAC[REALLIM_ATREAL_AT; REAL_CONTINUOUS_AT;
+          REAL_CONTINUOUS_ATREAL; o_DEF; LIFT_DROP; LIM_ATREAL_AT]);;
+let HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_WITHINREAL = prove
+ (`!f f' x s. (f has_real_derivative f') (atreal x within s)
+              ==> f real_continuous (atreal x within s)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_WITHIN;
+              REAL_COMPLEX_CONTINUOUS_WITHINREAL] THEN
+  DISCH_THEN(MP_TAC o
+    MATCH_MP HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_WITHIN) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INTER; IN_IMAGE] THEN
+  MESON_TAC[REAL; RE_CX; REAL_CX; IN]);;
+
+let REAL_DIFFERENTIABLE_IMP_CONTINUOUS_WITHINREAL = prove
+ (`!f x s. f real_differentiable (atreal x within s)
+           ==> f real_continuous (atreal x within s)`,
+  MESON_TAC[HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_WITHINREAL;
+            real_differentiable]);;
+
+let HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL = prove
+ (`!f f' x. (f has_real_derivative f') (atreal x)
+            ==> f real_continuous (atreal x)`,
+  REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_AT;
+              REAL_COMPLEX_CONTINUOUS_ATREAL;
+              HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_WITHIN]);;
+
+let REAL_DIFFERENTIABLE_IMP_CONTINUOUS_ATREAL = prove
+ (`!f x. f real_differentiable atreal x ==> f real_continuous atreal x`,
+  MESON_TAC[HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL; real_differentiable]);;
+
+let REAL_DIFFERENTIABLE_ON_IMP_REAL_CONTINUOUS_ON = prove
+ (`!f s. f real_differentiable_on s ==> f real_continuous_on s`,
+  REWRITE_TAC[real_differentiable_on;
+              REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  MESON_TAC[REAL_DIFFERENTIABLE_IMP_CONTINUOUS_WITHINREAL;
+            real_differentiable]);;
+
+let REAL_CONTINUOUS_AT_COMPONENT = prove
+ (`!i a. 1 <= i /\ i <= dimindex(:N)
+         ==> (\x:real^N. x$i) real_continuous at a`,
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS1; o_DEF;
+              CONTINUOUS_AT_LIFT_COMPONENT]);;
+
+let REAL_CONTINUOUS_AT_TRANSLATION = prove
+ (`!a z f:real^N->real.
+    f real_continuous at (a + z) <=> (\x. f(a + x)) real_continuous at z`,
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS1; o_DEF; CONTINUOUS_AT_TRANSLATION]);;
+
+add_translation_invariants [REAL_CONTINUOUS_AT_TRANSLATION];;
+
+let REAL_CONTINUOUS_AT_LINEAR_IMAGE = prove
+ (`!h:real^N->real^N z f:real^N->real.
+        linear h /\ (!x. norm(h x) = norm x)
+        ==> (f real_continuous at (h z) <=> (\x. f(h x)) real_continuous at z)`,
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS1; o_DEF;
+              CONTINUOUS_AT_LINEAR_IMAGE]);;
+
+add_linear_invariants [REAL_CONTINUOUS_AT_LINEAR_IMAGE];;
+
+let REAL_CONTINUOUS_AT_ARG = prove
+ (`!z. ~(real z /\ &0 <= Re z) ==> Arg real_continuous (at z)`,
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS; CONTINUOUS_AT_ARG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More basics about real derivatives.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_REAL_DERIVATIVE_WITHIN_SUBSET = prove
+ (`!f s t x. (f has_real_derivative f') (atreal x within s) /\ t SUBSET s
+             ==> (f has_real_derivative f') (atreal x within t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_WITHIN] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT]
+   HAS_COMPLEX_DERIVATIVE_WITHIN_SUBSET) THEN ASM SET_TAC[]);;
+
+let REAL_DIFFERENTIABLE_ON_SUBSET = prove
+ (`!f s t. f real_differentiable_on s /\ t SUBSET s
+           ==> f real_differentiable_on t`,
+  REWRITE_TAC[real_differentiable_on] THEN
+  MESON_TAC[SUBSET; HAS_REAL_DERIVATIVE_WITHIN_SUBSET]);;
+
+let REAL_DIFFERENTIABLE_WITHIN_SUBSET = prove
+ (`!f s t. f real_differentiable (atreal x within s) /\ t SUBSET s
+           ==> f real_differentiable (atreal x within t)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_WITHIN_SUBSET]);;
+
+let HAS_REAL_DERIVATIVE_ATREAL_WITHIN = prove
+ (`!f f' x s. (f has_real_derivative f') (atreal x)
+              ==> (f has_real_derivative f') (atreal x within s)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_WITHIN;
+              HAS_REAL_COMPLEX_DERIVATIVE_AT] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT]
+     HAS_COMPLEX_DERIVATIVE_WITHIN_SUBSET) THEN ASM SET_TAC[]);;
+
+let HAS_REAL_DERIVATIVE_WITHIN_REAL_OPEN = prove
+ (`!f f' a s.
+         a IN s /\ real_open s
+         ==> ((f has_real_derivative f') (atreal a within s) <=>
+              (f has_real_derivative f') (atreal a))`,
+  REPEAT GEN_TAC THEN
+  ASM_SIMP_TAC[HAS_REAL_DERIVATIVE_WITHINREAL; HAS_REAL_DERIVATIVE_ATREAL;
+               REALLIM_WITHIN_REAL_OPEN]);;
+
+let REAL_DIFFERENTIABLE_ATREAL_WITHIN = prove
+ (`!f s z. f real_differentiable (atreal z)
+           ==> f real_differentiable (atreal z within s)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_ATREAL_WITHIN]);;
+
+let HAS_REAL_DERIVATIVE_TRANSFORM_WITHIN = prove
+ (`!f f' g x s d.
+       &0 < d /\ x IN s /\
+       (!x'. x' IN s /\ abs(x' - x) < d ==> f x' = g x') /\
+       (f has_real_derivative f') (atreal x within s)
+       ==> (g has_real_derivative f') (atreal x within s)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_WITHIN] THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE
+    [TAUT `a /\ b /\ c /\ d ==> e <=> a /\ b /\ c ==> d ==> e`]
+    HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN) THEN
+  EXISTS_TAC `d:real` THEN ASM_REWRITE_TAC[IN_ELIM_THM; REAL_CX; RE_CX] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[o_THM] THEN AP_TERM_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (NORM_ARITH
+   `dist(a,b) < d ==> z <= norm(a - b) ==> z < d`)) THEN
+  W(MP_TAC o PART_MATCH (rand o rand) COMPLEX_NORM_GE_RE_IM o rand o snd) THEN
+  SIMP_TAC[RE_SUB; RE_CX]);;
+
+let HAS_REAL_DERIVATIVE_TRANSFORM_ATREAL = prove
+ (`!f f' g x d.
+       &0 < d /\ (!x'. abs(x' - x) < d ==> f x' = g x') /\
+       (f has_real_derivative f') (atreal x)
+       ==> (g has_real_derivative f') (atreal x)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_TRANSFORM_WITHIN; IN_UNIV]);;
+
+let HAS_REAL_DERIVATIVE_ZERO_CONSTANT = prove
+ (`!f s.
+        is_realinterval s /\
+        (!x. x IN s ==> (f has_real_derivative (&0)) (atreal x within s))
+        ==> ?c. !x. x IN s ==> f(x) = c`,
+  REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_WITHIN] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`Cx o f o Re`; `{z | real z /\ Re z IN s}`]
+    HAS_COMPLEX_DERIVATIVE_ZERO_CONSTANT) THEN
+  ASM_REWRITE_TAC[IN_ELIM_THM; IMP_CONJ; FORALL_REAL; RE_CX; o_THM] THEN
+  ASM_REWRITE_TAC[GSYM IS_REALINTERVAL_CONVEX_COMPLEX] THEN MESON_TAC[RE_CX]);;
+
+let HAS_REAL_DERIVATIVE_ZERO_UNIQUE = prove
+ (`!f s c a.
+        is_realinterval s /\ a IN s /\ f a = c /\
+        (!x. x IN s ==> (f has_real_derivative (&0)) (atreal x within s))
+        ==> !x. x IN s ==> f(x) = c`,
+  MESON_TAC[HAS_REAL_DERIVATIVE_ZERO_CONSTANT]);;
+
+let REAL_DIFF_CHAIN_WITHIN = prove
+ (`!f g f' g' x s.
+        (f has_real_derivative f') (atreal x within s) /\
+        (g has_real_derivative g') (atreal (f x) within (IMAGE f s))
+        ==> ((g o f) has_real_derivative (g' * f'))(atreal x within s)`,
+  REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_WITHIN] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `Cx o (g o f) o Re = (Cx o g o Re) o (Cx o f o Re)`
+  SUBST1_TAC THENL [REWRITE_TAC[FUN_EQ_THM; o_DEF; RE_CX]; ALL_TAC] THEN
+  REWRITE_TAC[CX_MUL] THEN MATCH_MP_TAC COMPLEX_DIFF_CHAIN_WITHIN THEN
+  ASM_REWRITE_TAC[o_THM; RE_CX] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] HAS_COMPLEX_DERIVATIVE_WITHIN_SUBSET)) THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[IN_ELIM_THM; o_THM; REAL_CX; RE_CX] THEN SET_TAC[]);;
+
+let REAL_DIFF_CHAIN_ATREAL = prove
+ (`!f g f' g' x.
+        (f has_real_derivative f') (atreal x) /\
+        (g has_real_derivative g') (atreal (f x))
+        ==> ((g o f) has_real_derivative (g' * f')) (atreal x)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  ASM_MESON_TAC[REAL_DIFF_CHAIN_WITHIN; SUBSET_UNIV;
+                HAS_REAL_DERIVATIVE_WITHIN_SUBSET]);;
+
+let HAS_REAL_DERIVATIVE_CHAIN = prove
+ (`!P f g.
+        (!x. P x ==> (g has_real_derivative g'(x)) (atreal x))
+        ==> (!x s. (f has_real_derivative f') (atreal x within s) /\ P(f x)
+                   ==> ((\x. g(f x)) has_real_derivative f' * g'(f x))
+                       (atreal x within s)) /\
+            (!x. (f has_real_derivative f') (atreal x) /\ P(f x)
+                 ==> ((\x. g(f x)) has_real_derivative f' * g'(f x))
+                     (atreal x))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM o_DEF] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_MESON_TAC[REAL_DIFF_CHAIN_WITHIN; REAL_DIFF_CHAIN_ATREAL;
+                HAS_REAL_DERIVATIVE_ATREAL_WITHIN]);;
+
+let HAS_REAL_DERIVATIVE_CHAIN_UNIV = prove
+ (`!f g. (!x. (g has_real_derivative g'(x)) (atreal x))
+         ==> (!x s. (f has_real_derivative f') (atreal x within s)
+                    ==> ((\x. g(f x)) has_real_derivative f' * g'(f x))
+                        (atreal x within s)) /\
+             (!x. (f has_real_derivative f') (atreal x)
+                  ==> ((\x. g(f x)) has_real_derivative f' * g'(f x))
+                      (atreal x))`,
+  MP_TAC(SPEC `\x:real. T` HAS_REAL_DERIVATIVE_CHAIN) THEN SIMP_TAC[]);;
+
+let REAL_DERIVATIVE_UNIQUE_ATREAL = prove
+ (`!f z f' f''.
+        (f has_real_derivative f') (atreal z) /\
+        (f has_real_derivative f'') (atreal z)
+        ==> f' = f''`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_AT] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP FRECHET_DERIVATIVE_UNIQUE_AT) THEN
+  DISCH_THEN(MP_TAC o C AP_THM `vec 1:real^1`) THEN
+  REWRITE_TAC[VECTOR_MUL_RCANCEL; VEC_EQ; ARITH_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some handy theorems about the actual differentition function.             *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_REAL_DERIVATIVE_DERIVATIVE = prove
+ (`!f f' x. (f has_real_derivative f') (atreal x)
+            ==> real_derivative f x = f'`,
+  REWRITE_TAC[real_derivative] THEN
+  MESON_TAC[REAL_DERIVATIVE_UNIQUE_ATREAL]);;
+
+let HAS_REAL_DERIVATIVE_DIFFERENTIABLE = prove
+ (`!f x. (f has_real_derivative (real_derivative f x)) (atreal x) <=>
+         f real_differentiable atreal x`,
+  REWRITE_TAC[real_differentiable; real_derivative] THEN MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Arithmetical combining theorems.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_REAL_DERIVATIVE_LMUL_WITHIN = prove
+ (`!f f' c x s.
+        (f has_real_derivative f') (atreal x within s)
+        ==> ((\x. c * f(x)) has_real_derivative (c * f')) (atreal x within s)`,
+  REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_WITHIN] THEN
+  REWRITE_TAC[o_DEF; CX_MUL; HAS_COMPLEX_DERIVATIVE_LMUL_WITHIN]);;
+
+let HAS_REAL_DERIVATIVE_LMUL_ATREAL = prove
+ (`!f f' c x.
+        (f has_real_derivative f') (atreal x)
+        ==> ((\x. c * f(x)) has_real_derivative (c * f')) (atreal x)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_DERIVATIVE_LMUL_WITHIN]);;
+
+let HAS_REAL_DERIVATIVE_RMUL_WITHIN = prove
+ (`!f f' c x s.
+        (f has_real_derivative f') (atreal x within s)
+        ==> ((\x. f(x) * c) has_real_derivative (f' * c)) (atreal x within s)`,
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  REWRITE_TAC[HAS_REAL_DERIVATIVE_LMUL_WITHIN]);;
+
+let HAS_REAL_DERIVATIVE_RMUL_ATREAL = prove
+ (`!f f' c x.
+        (f has_real_derivative f') (atreal x)
+        ==> ((\x. f(x) * c) has_real_derivative (f' * c)) (atreal x)`,
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  REWRITE_TAC[HAS_REAL_DERIVATIVE_LMUL_ATREAL]);;
+
+let HAS_REAL_DERIVATIVE_CDIV_WITHIN = prove
+ (`!f f' c x s.
+        (f has_real_derivative f') (atreal x within s)
+        ==> ((\x. f(x) / c) has_real_derivative (f' / c)) (atreal x within s)`,
+  SIMP_TAC[real_div; HAS_REAL_DERIVATIVE_RMUL_WITHIN]);;
+
+let HAS_REAL_DERIVATIVE_CDIV_ATREAL = prove
+ (`!f f' c x.
+        (f has_real_derivative f') (atreal x)
+        ==> ((\x. f(x) / c) has_real_derivative (f' / c)) (atreal x)`,
+  SIMP_TAC[real_div; HAS_REAL_DERIVATIVE_RMUL_ATREAL]);;
+
+let HAS_REAL_DERIVATIVE_ID = prove
+ (`!net. ((\x. x) has_real_derivative &1) net`,
+  REWRITE_TAC[has_real_derivative; TENDSTO_REAL;
+              REAL_ARITH `x - (a + &1 * (x - a)) = &0`] THEN
+  REWRITE_TAC[REAL_MUL_RZERO; LIM_CONST; o_DEF]);;
+
+let HAS_REAL_DERIVATIVE_CONST = prove
+ (`!c net. ((\x. c) has_real_derivative &0) net`,
+  REWRITE_TAC[has_real_derivative; REAL_MUL_LZERO; REAL_ADD_RID; REAL_SUB_REFL;
+              REAL_MUL_RZERO; REALLIM_CONST]);;
+
+let HAS_REAL_DERIVATIVE_NEG = prove
+ (`!f f' net. (f has_real_derivative f') net
+            ==> ((\x. --(f(x))) has_real_derivative (--f')) net`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_real_derivative] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REALLIM_NEG) THEN
+  REWRITE_TAC[REAL_NEG_0; REAL_ARITH
+   `a * (--b - (--c + --d * e:real)) = --(a * (b - (c + d * e)))`]);;
+
+let HAS_REAL_DERIVATIVE_ADD = prove
+ (`!f f' g g' net.
+        (f has_real_derivative f') net /\ (g has_real_derivative g') net
+        ==> ((\x. f(x) + g(x)) has_real_derivative (f' + g')) net`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_real_derivative] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REALLIM_ADD) THEN
+  REWRITE_TAC[GSYM REAL_ADD_LDISTRIB; REAL_ADD_RID] THEN
+  REWRITE_TAC[REAL_ARITH
+   `(fx - (fa + f' * (x - a))) + (gx - (ga + g' * (x - a))):real =
+    (fx + gx) - ((fa + ga) + (f' + g') * (x - a))`]);;
+
+let HAS_REAL_DERIVATIVE_SUB = prove
+ (`!f f' g g' net.
+        (f has_real_derivative f') net /\ (g has_real_derivative g') net
+        ==> ((\x. f(x) - g(x)) has_real_derivative (f' - g')) net`,
+  SIMP_TAC[real_sub; HAS_REAL_DERIVATIVE_ADD; HAS_REAL_DERIVATIVE_NEG]);;
+
+let HAS_REAL_DERIVATIVE_MUL_WITHIN = prove
+ (`!f f' g g' x s.
+        (f has_real_derivative f') (atreal x within s) /\
+        (g has_real_derivative g') (atreal x within s)
+        ==> ((\x. f(x) * g(x)) has_real_derivative
+             (f(x) * g' + f' * g(x))) (atreal x within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_WITHIN] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_COMPLEX_DERIVATIVE_MUL_WITHIN) THEN
+  REWRITE_TAC[o_DEF; CX_MUL; CX_ADD; RE_CX]);;
+
+let HAS_REAL_DERIVATIVE_MUL_ATREAL = prove
+ (`!f f' g g' x.
+        (f has_real_derivative f') (atreal x) /\
+        (g has_real_derivative g') (atreal x)
+        ==> ((\x. f(x) * g(x)) has_real_derivative
+             (f(x) * g' + f' * g(x))) (atreal x)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_DERIVATIVE_MUL_WITHIN]);;
+
+let HAS_REAL_DERIVATIVE_POW_WITHIN = prove
+ (`!f f' x s n. (f has_real_derivative f') (atreal x within s)
+                ==> ((\x. f(x) pow n) has_real_derivative
+                     (&n * f(x) pow (n - 1) * f')) (atreal x within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_WITHIN] THEN
+  DISCH_THEN(MP_TAC o SPEC `n:num` o
+    MATCH_MP HAS_COMPLEX_DERIVATIVE_POW_WITHIN) THEN
+  REWRITE_TAC[o_DEF; CX_MUL; CX_POW; RE_CX]);;
+
+let HAS_REAL_DERIVATIVE_POW_ATREAL = prove
+ (`!f f' x n. (f has_real_derivative f') (atreal x)
+              ==> ((\x. f(x) pow n) has_real_derivative
+                   (&n * f(x) pow (n - 1) * f')) (atreal x)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_DERIVATIVE_POW_WITHIN]);;
+
+let HAS_REAL_DERIVATIVE_INV_BASIC = prove
+ (`!x. ~(x = &0)
+         ==> ((inv) has_real_derivative (--inv(x pow 2))) (atreal x)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[HAS_REAL_COMPLEX_DERIVATIVE_AT] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_WITHIN THEN
+  EXISTS_TAC `inv:complex->complex` THEN
+  ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_INV_BASIC; CX_INJ; CX_NEG; CX_INV;
+               CX_POW; HAS_COMPLEX_DERIVATIVE_AT_WITHIN] THEN
+  SIMP_TAC[IN; FORALL_REAL; IMP_CONJ; o_DEF; REAL_CX; RE_CX; CX_INV] THEN
+  MESON_TAC[REAL_LT_01]);;
+
+let HAS_REAL_DERIVATIVE_INV_WITHIN = prove
+ (`!f f' x s. (f has_real_derivative f') (atreal x within s) /\
+              ~(f x = &0)
+              ==> ((\x. inv(f(x))) has_real_derivative (--f' / f(x) pow 2))
+                  (atreal x within s)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+  ASM_SIMP_TAC[REAL_FIELD
+   `~(g = &0) ==> --f / g pow 2 = --inv(g pow 2) * f`] THEN
+  MATCH_MP_TAC REAL_DIFF_CHAIN_WITHIN THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC HAS_REAL_DERIVATIVE_ATREAL_WITHIN THEN
+  ASM_SIMP_TAC[HAS_REAL_DERIVATIVE_INV_BASIC]);;
+
+let HAS_REAL_DERIVATIVE_INV_ATREAL = prove
+ (`!f f' x. (f has_real_derivative f') (atreal x) /\
+            ~(f x = &0)
+            ==> ((\x. inv(f(x))) has_real_derivative (--f' / f(x) pow 2))
+                (atreal x)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_DERIVATIVE_INV_WITHIN]);;
+
+let HAS_REAL_DERIVATIVE_DIV_WITHIN = prove
+ (`!f f' g g' x s.
+        (f has_real_derivative f') (atreal x within s) /\
+        (g has_real_derivative g') (atreal x within s) /\
+        ~(g(x) = &0)
+        ==> ((\x. f(x) / g(x)) has_real_derivative
+             (f' * g(x) - f(x) * g') / g(x) pow 2) (atreal x within s)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(fun th -> ASSUME_TAC(CONJUNCT2 th) THEN MP_TAC th) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_REAL_DERIVATIVE_INV_WITHIN) THEN
+  UNDISCH_TAC `(f has_real_derivative f') (atreal x within s)` THEN
+  REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_REAL_DERIVATIVE_MUL_WITHIN) THEN
+  REWRITE_TAC[GSYM real_div] THEN MATCH_MP_TAC EQ_IMP THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN
+  POP_ASSUM MP_TAC THEN CONV_TAC REAL_FIELD);;
+
+let HAS_REAL_DERIVATIVE_DIV_ATREAL = prove
+ (`!f f' g g' x.
+        (f has_real_derivative f') (atreal x) /\
+        (g has_real_derivative g') (atreal x) /\
+        ~(g(x) = &0)
+        ==> ((\x. f(x) / g(x)) has_real_derivative
+             (f' * g(x) - f(x) * g') / g(x) pow 2) (atreal x)`,
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  REWRITE_TAC[HAS_REAL_DERIVATIVE_DIV_WITHIN]);;
+
+let HAS_REAL_DERIVATIVE_SUM = prove
+ (`!f net s.
+         FINITE s /\ (!a. a IN s ==> (f a has_real_derivative f' a) net)
+         ==> ((\x. sum s (\a. f a x)) has_real_derivative (sum s f'))
+             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; SUM_CLAUSES] THEN
+  SIMP_TAC[HAS_REAL_DERIVATIVE_CONST; HAS_REAL_DERIVATIVE_ADD; ETA_AX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Same thing just for real differentiability.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_DIFFERENTIABLE_CONST = prove
+ (`!c net. (\z. c) real_differentiable net`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_CONST]);;
+
+let REAL_DIFFERENTIABLE_ID = prove
+ (`!net. (\z. z) real_differentiable net`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_ID]);;
+
+let REAL_DIFFERENTIABLE_NEG = prove
+ (`!f net.
+        f real_differentiable net
+        ==> (\z. --(f z)) real_differentiable net`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_NEG]);;
+
+let REAL_DIFFERENTIABLE_ADD = prove
+ (`!f g net.
+        f real_differentiable net /\
+        g real_differentiable net
+        ==> (\z. f z + g z) real_differentiable net`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_ADD]);;
+
+let REAL_DIFFERENTIABLE_SUB = prove
+ (`!f g net.
+        f real_differentiable net /\
+        g real_differentiable net
+        ==> (\z. f z - g z) real_differentiable net`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_SUB]);;
+
+let REAL_DIFFERENTIABLE_INV_WITHIN = prove
+ (`!f z s.
+        f real_differentiable (atreal z within s) /\ ~(f z = &0)
+        ==> (\z. inv(f z)) real_differentiable (atreal z within s)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_INV_WITHIN]);;
+
+let REAL_DIFFERENTIABLE_MUL_WITHIN = prove
+ (`!f g z s.
+        f real_differentiable (atreal z within s) /\
+        g real_differentiable (atreal z within s)
+        ==> (\z. f z * g z) real_differentiable (atreal z within s)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_MUL_WITHIN]);;
+
+let REAL_DIFFERENTIABLE_DIV_WITHIN = prove
+ (`!f g z s.
+        f real_differentiable (atreal z within s) /\
+        g real_differentiable (atreal z within s) /\
+        ~(g z = &0)
+        ==> (\z. f z / g z) real_differentiable (atreal z within s)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_DIV_WITHIN]);;
+
+let REAL_DIFFERENTIABLE_POW_WITHIN = prove
+ (`!f n z s.
+        f real_differentiable (atreal z within s)
+        ==> (\z. f z pow n) real_differentiable (atreal z within s)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_POW_WITHIN]);;
+
+let REAL_DIFFERENTIABLE_TRANSFORM_WITHIN = prove
+ (`!f g x s d.
+        &0 < d /\
+        x IN s /\
+        (!x'. x' IN s /\ abs(x' - x) < d ==> f x' = g x') /\
+        f real_differentiable (atreal x within s)
+        ==> g real_differentiable (atreal x within s)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_TRANSFORM_WITHIN]);;
+
+let REAL_DIFFERENTIABLE_TRANSFORM = prove
+ (`!f g s. (!x. x IN s ==> f x = g x) /\ f real_differentiable_on s
+           ==> g real_differentiable_on s`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[real_differentiable_on; GSYM real_differentiable] THEN
+  MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_DIFFERENTIABLE_TRANSFORM_WITHIN THEN
+  MAP_EVERY EXISTS_TAC [`f:real->real`; `&1`] THEN
+  ASM_SIMP_TAC[REAL_LT_01]);;
+
+let REAL_DIFFERENTIABLE_EQ = prove
+ (`!f g s. (!x. x IN s ==> f x = g x)
+           ==> (f real_differentiable_on s <=> g real_differentiable_on s)`,
+  MESON_TAC[REAL_DIFFERENTIABLE_TRANSFORM]);;
+
+let REAL_DIFFERENTIABLE_INV_ATREAL = prove
+ (`!f z.
+        f real_differentiable atreal z /\ ~(f z = &0)
+        ==> (\z. inv(f z)) real_differentiable atreal z`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_INV_ATREAL]);;
+
+let REAL_DIFFERENTIABLE_MUL_ATREAL = prove
+ (`!f g z.
+        f real_differentiable atreal z /\
+        g real_differentiable atreal z
+        ==> (\z. f z * g z) real_differentiable atreal z`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_MUL_ATREAL]);;
+
+let REAL_DIFFERENTIABLE_DIV_ATREAL = prove
+ (`!f g z.
+        f real_differentiable atreal z /\
+        g real_differentiable atreal z /\
+        ~(g z = &0)
+        ==> (\z. f z / g z) real_differentiable atreal z`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_DIV_ATREAL]);;
+
+let REAL_DIFFERENTIABLE_POW_ATREAL = prove
+ (`!f n z.
+        f real_differentiable atreal z
+        ==> (\z. f z pow n) real_differentiable atreal z`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_POW_ATREAL]);;
+
+let REAL_DIFFERENTIABLE_TRANSFORM_ATREAL = prove
+ (`!f g x d.
+        &0 < d /\
+        (!x'. abs(x' - x) < d ==> f x' = g x') /\
+        f real_differentiable atreal x
+        ==> g real_differentiable atreal x`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_TRANSFORM_ATREAL]);;
+
+let REAL_DIFFERENTIABLE_COMPOSE_WITHIN = prove
+ (`!f g x s.
+         f real_differentiable (atreal x within s) /\
+         g real_differentiable (atreal (f x) within IMAGE f s)
+         ==> (g o f) real_differentiable (atreal x within s)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[REAL_DIFF_CHAIN_WITHIN]);;
+
+let REAL_DIFFERENTIABLE_COMPOSE_ATREAL = prove
+ (`!f g x.
+         f real_differentiable (atreal x) /\
+         g real_differentiable (atreal (f x))
+         ==> (g o f) real_differentiable (atreal x)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[REAL_DIFF_CHAIN_ATREAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Same again for being differentiable on a set.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_DIFFERENTIABLE_ON_CONST = prove
+ (`!c s. (\z. c) real_differentiable_on s`,
+  REWRITE_TAC[REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE;
+              REAL_DIFFERENTIABLE_CONST]);;
+
+let REAL_DIFFERENTIABLE_ON_ID = prove
+ (`!s. (\z. z) real_differentiable_on s`,
+  REWRITE_TAC[REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE; REAL_DIFFERENTIABLE_ID]);;
+
+let REAL_DIFFERENTIABLE_ON_COMPOSE = prove
+ (`!f g s. f real_differentiable_on s /\ g real_differentiable_on (IMAGE f s)
+           ==> (g o f) real_differentiable_on s`,
+  SIMP_TAC[real_differentiable_on; GSYM real_differentiable;
+           FORALL_IN_IMAGE] THEN
+  MESON_TAC[REAL_DIFFERENTIABLE_COMPOSE_WITHIN]);;
+
+let REAL_DIFFERENTIABLE_ON_NEG = prove
+ (`!f s. f real_differentiable_on s ==> (\z. --(f z)) real_differentiable_on s`,
+  SIMP_TAC[REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE; REAL_DIFFERENTIABLE_NEG]);;
+
+let REAL_DIFFERENTIABLE_ON_ADD = prove
+ (`!f g s.
+        f real_differentiable_on s /\ g real_differentiable_on s
+        ==> (\z. f z + g z) real_differentiable_on s`,
+  SIMP_TAC[REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE; REAL_DIFFERENTIABLE_ADD]);;
+
+let REAL_DIFFERENTIABLE_ON_SUB = prove
+ (`!f g s.
+        f real_differentiable_on s /\ g real_differentiable_on s
+        ==> (\z. f z - g z) real_differentiable_on s`,
+  SIMP_TAC[REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE; REAL_DIFFERENTIABLE_SUB]);;
+
+let REAL_DIFFERENTIABLE_ON_MUL = prove
+ (`!f g s.
+        f real_differentiable_on s /\ g real_differentiable_on s
+        ==> (\z. f z * g z) real_differentiable_on s`,
+  SIMP_TAC[REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE;
+           REAL_DIFFERENTIABLE_MUL_WITHIN]);;
+
+let REAL_DIFFERENTIABLE_ON_INV = prove
+ (`!f s. f real_differentiable_on s /\ (!z. z IN s ==> ~(f z = &0))
+         ==> (\z. inv(f z)) real_differentiable_on s`,
+  SIMP_TAC[REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE;
+           REAL_DIFFERENTIABLE_INV_WITHIN]);;
+
+let REAL_DIFFERENTIABLE_ON_DIV = prove
+ (`!f g s.
+        f real_differentiable_on s /\ g real_differentiable_on s /\
+        (!z. z IN s ==> ~(g z = &0))
+        ==> (\z. f z / g z) real_differentiable_on s`,
+  SIMP_TAC[REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE;
+           REAL_DIFFERENTIABLE_DIV_WITHIN]);;
+
+let REAL_DIFFERENTIABLE_ON_POW = prove
+ (`!f s n. f real_differentiable_on s
+           ==> (\z. (f z) pow n) real_differentiable_on s`,
+  SIMP_TAC[REAL_DIFFERENTIABLE_ON_DIFFERENTIABLE;
+           REAL_DIFFERENTIABLE_POW_WITHIN]);;
+
+let REAL_DIFFERENTIABLE_ON_SUM = prove
+ (`!f s k. FINITE k /\ (!a. a IN k ==> (f a) real_differentiable_on s)
+           ==> (\x. sum k (\a. f a x)) real_differentiable_on s`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[SUM_CLAUSES] THEN
+  SIMP_TAC[REAL_DIFFERENTIABLE_ON_CONST; IN_INSERT; NOT_IN_EMPTY] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_DIFFERENTIABLE_ON_ADD THEN
+  ASM_SIMP_TAC[ETA_AX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Derivative (and continuity) theorems for real transcendental functions.   *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_REAL_DERIVATIVE_EXP = prove
+ (`!x. (exp has_real_derivative exp(x)) (atreal x)`,
+  GEN_TAC THEN MATCH_MP_TAC HAS_COMPLEX_REAL_DERIVATIVE_AT THEN
+  EXISTS_TAC `cexp` THEN
+  ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN;
+               HAS_COMPLEX_DERIVATIVE_CEXP; CX_EXP]);;
+
+let REAL_DIFFERENTIABLE_AT_EXP = prove
+ (`!x. exp real_differentiable (atreal x)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_EXP]);;
+
+let REAL_DIFFERENTIABLE_WITHIN_EXP = prove
+ (`!s x. exp real_differentiable (atreal x within s)`,
+  MESON_TAC[REAL_DIFFERENTIABLE_ATREAL_WITHIN;
+            REAL_DIFFERENTIABLE_AT_EXP]);;
+
+let REAL_CONTINUOUS_AT_EXP = prove
+ (`!x. exp real_continuous (atreal x)`,
+  MESON_TAC[HAS_REAL_DERIVATIVE_EXP;
+            HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL]);;
+
+let REAL_CONTINUOUS_WITHIN_EXP = prove
+ (`!s x. exp real_continuous (atreal x within s)`,
+  MESON_TAC[REAL_CONTINUOUS_ATREAL_WITHINREAL;
+            REAL_CONTINUOUS_AT_EXP]);;
+
+let REAL_CONTINUOUS_ON_EXP = prove
+ (`!s. exp real_continuous_on s`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+              REAL_CONTINUOUS_WITHIN_EXP]);;
+
+let HAS_REAL_DERIVATIVE_SIN = prove
+ (`!x. (sin has_real_derivative cos(x)) (atreal x)`,
+  GEN_TAC THEN MATCH_MP_TAC HAS_COMPLEX_REAL_DERIVATIVE_AT THEN
+  EXISTS_TAC `csin` THEN
+  ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN;
+               HAS_COMPLEX_DERIVATIVE_CSIN; CX_SIN; CX_COS]);;
+
+let REAL_DIFFERENTIABLE_AT_SIN = prove
+ (`!x. sin real_differentiable (atreal x)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_SIN]);;
+
+let REAL_DIFFERENTIABLE_WITHIN_SIN = prove
+ (`!s x. sin real_differentiable (atreal x within s)`,
+  MESON_TAC[REAL_DIFFERENTIABLE_ATREAL_WITHIN;
+            REAL_DIFFERENTIABLE_AT_SIN]);;
+
+let REAL_CONTINUOUS_AT_SIN = prove
+ (`!x. sin real_continuous (atreal x)`,
+  MESON_TAC[HAS_REAL_DERIVATIVE_SIN;
+            HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL]);;
+
+let REAL_CONTINUOUS_WITHIN_SIN = prove
+ (`!s x. sin real_continuous (atreal x within s)`,
+  MESON_TAC[REAL_CONTINUOUS_ATREAL_WITHINREAL;
+            REAL_CONTINUOUS_AT_SIN]);;
+
+let REAL_CONTINUOUS_ON_SIN = prove
+ (`!s. sin real_continuous_on s`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+              REAL_CONTINUOUS_WITHIN_SIN]);;
+
+let HAS_REAL_DERIVATIVE_COS = prove
+ (`!x. (cos has_real_derivative --sin(x)) (atreal x)`,
+  GEN_TAC THEN MATCH_MP_TAC HAS_COMPLEX_REAL_DERIVATIVE_AT THEN
+  EXISTS_TAC `ccos` THEN
+  ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN;
+               HAS_COMPLEX_DERIVATIVE_CCOS; CX_SIN; CX_COS; CX_NEG]);;
+
+let REAL_DIFFERENTIABLE_AT_COS = prove
+ (`!x. cos real_differentiable (atreal x)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_COS]);;
+
+let REAL_DIFFERENTIABLE_WITHIN_COS = prove
+ (`!s x. cos real_differentiable (atreal x within s)`,
+  MESON_TAC[REAL_DIFFERENTIABLE_ATREAL_WITHIN;
+            REAL_DIFFERENTIABLE_AT_COS]);;
+
+let REAL_CONTINUOUS_AT_COS = prove
+ (`!x. cos real_continuous (atreal x)`,
+  MESON_TAC[HAS_REAL_DERIVATIVE_COS;
+            HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL]);;
+
+let REAL_CONTINUOUS_WITHIN_COS = prove
+ (`!s x. cos real_continuous (atreal x within s)`,
+  MESON_TAC[REAL_CONTINUOUS_ATREAL_WITHINREAL;
+            REAL_CONTINUOUS_AT_COS]);;
+
+let REAL_CONTINUOUS_ON_COS = prove
+ (`!s. cos real_continuous_on s`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+              REAL_CONTINUOUS_WITHIN_COS]);;
+
+let HAS_REAL_DERIVATIVE_TAN = prove
+ (`!x. ~(cos x = &0)
+       ==> (tan has_real_derivative inv(cos(x) pow 2)) (atreal x)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_COMPLEX_REAL_DERIVATIVE_AT THEN
+  EXISTS_TAC `ctan` THEN REWRITE_TAC[CX_INV; CX_POW; CX_COS] THEN
+  ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN;
+               HAS_COMPLEX_DERIVATIVE_CTAN; GSYM CX_COS; CX_INJ; CX_TAN]);;
+
+let REAL_DIFFERENTIABLE_AT_TAN = prove
+ (`!x. ~(cos x = &0) ==> tan real_differentiable (atreal x)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_TAN]);;
+
+let REAL_DIFFERENTIABLE_WITHIN_TAN = prove
+ (`!s x. ~(cos x = &0) ==> tan real_differentiable (atreal x within s)`,
+  MESON_TAC[REAL_DIFFERENTIABLE_ATREAL_WITHIN;
+            REAL_DIFFERENTIABLE_AT_TAN]);;
+
+let REAL_CONTINUOUS_AT_TAN = prove
+ (`!x. ~(cos x = &0) ==> tan real_continuous (atreal x)`,
+  MESON_TAC[HAS_REAL_DERIVATIVE_TAN;
+            HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL]);;
+
+let REAL_CONTINUOUS_WITHIN_TAN = prove
+ (`!s x. ~(cos x = &0) ==> tan real_continuous (atreal x within s)`,
+  MESON_TAC[REAL_CONTINUOUS_ATREAL_WITHINREAL;
+            REAL_CONTINUOUS_AT_TAN]);;
+
+let REAL_CONTINUOUS_ON_TAN = prove
+ (`!s. (!x. x IN s ==> ~(cos x = &0)) ==> tan real_continuous_on s`,
+  MESON_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+            REAL_CONTINUOUS_WITHIN_TAN]);;
+
+let HAS_REAL_DERIVATIVE_LOG = prove
+ (`!x. &0 < x ==> (log has_real_derivative inv(x)) (atreal x)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_COMPLEX_REAL_DERIVATIVE_AT_GEN THEN
+  MAP_EVERY EXISTS_TAC [`clog`; `x:real`] THEN ASM_REWRITE_TAC[] THEN
+  REPEAT STRIP_TAC THENL
+   [REWRITE_TAC[CX_INV] THEN MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_AT_WITHIN THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_CLOG THEN ASM_REWRITE_TAC[RE_CX];
+    MATCH_MP_TAC(GSYM CX_LOG) THEN ASM_REAL_ARITH_TAC]);;
+
+let REAL_DIFFERENTIABLE_AT_LOG = prove
+ (`!x. &0 < x ==> log real_differentiable (atreal x)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_LOG]);;
+
+let REAL_DIFFERENTIABLE_WITHIN_LOG = prove
+ (`!s x. &0 < x ==> log real_differentiable (atreal x within s)`,
+  MESON_TAC[REAL_DIFFERENTIABLE_ATREAL_WITHIN;
+            REAL_DIFFERENTIABLE_AT_LOG]);;
+
+let REAL_CONTINUOUS_AT_LOG = prove
+ (`!x. &0 < x ==> log real_continuous (atreal x)`,
+  MESON_TAC[HAS_REAL_DERIVATIVE_LOG;
+            HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL]);;
+
+let REAL_CONTINUOUS_WITHIN_LOG = prove
+ (`!s x. &0 < x ==> log real_continuous (atreal x within s)`,
+  MESON_TAC[REAL_CONTINUOUS_ATREAL_WITHINREAL;
+            REAL_CONTINUOUS_AT_LOG]);;
+
+let REAL_CONTINUOUS_ON_LOG = prove
+ (`!s. (!x. x IN s ==> &0 < x) ==> log real_continuous_on s`,
+  MESON_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+            REAL_CONTINUOUS_WITHIN_LOG]);;
+
+let HAS_REAL_DERIVATIVE_SQRT = prove
+ (`!x. &0 < x ==> (sqrt has_real_derivative inv(&2 * sqrt x)) (atreal x)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_COMPLEX_REAL_DERIVATIVE_AT_GEN THEN
+  MAP_EVERY EXISTS_TAC [`csqrt`; `x:real`] THEN ASM_REWRITE_TAC[] THEN
+  REPEAT STRIP_TAC THENL
+   [ASM_SIMP_TAC[CX_INV; CX_MUL; CX_SQRT; REAL_LT_IMP_LE] THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_AT_WITHIN THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_CSQRT THEN
+    ASM_SIMP_TAC[RE_CX];
+    MATCH_MP_TAC(GSYM CX_SQRT) THEN ASM_REAL_ARITH_TAC]);;
+
+let REAL_DIFFERENTIABLE_AT_SQRT = prove
+ (`!x. &0 < x ==> sqrt real_differentiable (atreal x)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_SQRT]);;
+
+let REAL_DIFFERENTIABLE_WITHIN_SQRT = prove
+ (`!s x. &0 < x ==> sqrt real_differentiable (atreal x within s)`,
+  MESON_TAC[REAL_DIFFERENTIABLE_ATREAL_WITHIN;
+            REAL_DIFFERENTIABLE_AT_SQRT]);;
+
+let REAL_CONTINUOUS_AT_SQRT = prove
+ (`!x. &0 < x ==> sqrt real_continuous (atreal x)`,
+  MESON_TAC[HAS_REAL_DERIVATIVE_SQRT;
+            HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL]);;
+
+let REAL_CONTINUOUS_WITHIN_SQRT = prove
+ (`!s x. &0 < x ==> sqrt real_continuous (atreal x within s)`,
+  MESON_TAC[REAL_CONTINUOUS_ATREAL_WITHINREAL;
+            REAL_CONTINUOUS_AT_SQRT]);;
+
+let REAL_CONTINUOUS_WITHIN_SQRT_COMPOSE = prove
+ (`!f s a:real^N.
+        f real_continuous (at a within s) /\
+        (&0 < f a \/ !x. x IN s ==> &0 <= f x)
+        ==> (\x. sqrt(f x)) real_continuous (at a within s)`,
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS1; o_DEF] THEN
+  REWRITE_TAC[CONTINUOUS_WITHIN_SQRT_COMPOSE]);;
+
+let REAL_CONTINUOUS_AT_SQRT_COMPOSE = prove
+ (`!f a:real^N.
+        f real_continuous (at a) /\
+        (&0 < f a \/ !x. &0 <= f x)
+        ==> (\x. sqrt(f x)) real_continuous (at a)`,
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS1; o_DEF] THEN
+  REWRITE_TAC[CONTINUOUS_AT_SQRT_COMPOSE]);;
+
+let CONTINUOUS_WITHINREAL_SQRT_COMPOSE = prove
+ (`!f s a. (\x. lift(f x)) continuous (atreal a within s) /\
+           (&0 < f a \/ !x. x IN s ==> &0 <= f x)
+           ==> (\x. lift(sqrt(f x))) continuous (atreal a within s)`,
+  REWRITE_TAC[CONTINUOUS_CONTINUOUS_WITHINREAL] THEN
+  REWRITE_TAC[o_DEF] THEN REPEAT GEN_TAC THEN DISCH_TAC THEN
+  MATCH_MP_TAC CONTINUOUS_WITHIN_SQRT_COMPOSE THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; LIFT_DROP]);;
+
+let CONTINUOUS_ATREAL_SQRT_COMPOSE = prove
+ (`!f a. (\x. lift(f x)) continuous (atreal a) /\ (&0 < f a \/ !x. &0 <= f x)
+         ==> (\x. lift(sqrt(f x))) continuous (atreal a)`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`f:real->real`; `(:real)`; `a:real`]
+        CONTINUOUS_WITHINREAL_SQRT_COMPOSE) THEN
+  REWRITE_TAC[WITHINREAL_UNIV; IN_UNIV]);;
+
+let REAL_CONTINUOUS_WITHINREAL_SQRT_COMPOSE = prove
+ (`!f s a. f real_continuous (atreal a within s) /\
+           (&0 < f a \/ !x. x IN s ==> &0 <= f x)
+           ==> (\x. sqrt(f x)) real_continuous (atreal a within s)`,
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS1; o_DEF] THEN
+  REWRITE_TAC[CONTINUOUS_WITHINREAL_SQRT_COMPOSE]);;
+
+let REAL_CONTINUOUS_ATREAL_SQRT_COMPOSE = prove
+ (`!f a. f real_continuous (atreal a) /\
+         (&0 < f a \/ !x. &0 <= f x)
+         ==> (\x. sqrt(f x)) real_continuous (atreal a)`,
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS1; o_DEF] THEN
+  REWRITE_TAC[CONTINUOUS_ATREAL_SQRT_COMPOSE]);;
+
+let HAS_REAL_DERIVATIVE_ATN = prove
+ (`!x. (atn has_real_derivative inv(&1 + x pow 2)) (atreal x)`,
+  GEN_TAC THEN MATCH_MP_TAC HAS_COMPLEX_REAL_DERIVATIVE_AT THEN
+  EXISTS_TAC `catn` THEN REWRITE_TAC[CX_INV; CX_ADD; CX_ATN; CX_POW] THEN
+  ASM_SIMP_TAC[HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HAS_COMPLEX_DERIVATIVE_CATN;
+               IM_CX; REAL_ABS_NUM; REAL_LT_01]);;
+
+let REAL_DIFFERENTIABLE_AT_ATN = prove
+ (`!x. atn real_differentiable (atreal x)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_ATN]);;
+
+let REAL_DIFFERENTIABLE_WITHIN_ATN = prove
+ (`!s x. atn real_differentiable (atreal x within s)`,
+  MESON_TAC[REAL_DIFFERENTIABLE_ATREAL_WITHIN;
+            REAL_DIFFERENTIABLE_AT_ATN]);;
+
+let REAL_CONTINUOUS_AT_ATN = prove
+ (`!x. atn real_continuous (atreal x)`,
+  MESON_TAC[HAS_REAL_DERIVATIVE_ATN;
+            HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL]);;
+
+let REAL_CONTINUOUS_WITHIN_ATN = prove
+ (`!s x. atn real_continuous (atreal x within s)`,
+  MESON_TAC[REAL_CONTINUOUS_ATREAL_WITHINREAL;
+            REAL_CONTINUOUS_AT_ATN]);;
+
+let REAL_CONTINUOUS_ON_ATN = prove
+ (`!s. atn real_continuous_on s`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+              REAL_CONTINUOUS_WITHIN_ATN]);;
+
+let HAS_REAL_DERIVATIVE_ASN_COS = prove
+ (`!x. abs(x) < &1 ==> (asn has_real_derivative inv(cos(asn x))) (atreal x)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_COMPLEX_REAL_DERIVATIVE_AT_GEN THEN
+  MAP_EVERY EXISTS_TAC [`casn`; `&1 - abs x`] THEN
+  ASM_REWRITE_TAC[REAL_SUB_LT] THEN REPEAT STRIP_TAC THENL
+   [ASM_SIMP_TAC[CX_INV; CX_COS; CX_ASN; REAL_LT_IMP_LE] THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_AT_WITHIN THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_CASN THEN ASM_REWRITE_TAC[RE_CX];
+    MATCH_MP_TAC(GSYM CX_ASN) THEN ASM_REAL_ARITH_TAC]);;
+
+let HAS_REAL_DERIVATIVE_ASN = prove
+ (`!x. abs(x) < &1
+       ==> (asn has_real_derivative inv(sqrt(&1 - x pow 2))) (atreal x)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HAS_REAL_DERIVATIVE_ASN_COS) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  AP_TERM_TAC THEN MATCH_MP_TAC COS_ASN THEN ASM_REAL_ARITH_TAC);;
+
+let REAL_DIFFERENTIABLE_AT_ASN = prove
+ (`!x. abs(x) < &1 ==> asn real_differentiable (atreal x)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_ASN]);;
+
+let REAL_DIFFERENTIABLE_WITHIN_ASN = prove
+ (`!s x. abs(x) < &1 ==> asn real_differentiable (atreal x within s)`,
+  MESON_TAC[REAL_DIFFERENTIABLE_ATREAL_WITHIN;
+            REAL_DIFFERENTIABLE_AT_ASN]);;
+
+let REAL_CONTINUOUS_AT_ASN = prove
+ (`!x. abs(x) < &1 ==> asn real_continuous (atreal x)`,
+  MESON_TAC[HAS_REAL_DERIVATIVE_ASN;
+            HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL]);;
+
+let REAL_CONTINUOUS_WITHIN_ASN = prove
+ (`!s x. abs(x) < &1 ==> asn real_continuous (atreal x within s)`,
+  MESON_TAC[REAL_CONTINUOUS_ATREAL_WITHINREAL;
+            REAL_CONTINUOUS_AT_ASN]);;
+
+let HAS_REAL_DERIVATIVE_ACS_SIN = prove
+ (`!x. abs(x) < &1 ==> (acs has_real_derivative --inv(sin(acs x))) (atreal x)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_COMPLEX_REAL_DERIVATIVE_AT_GEN THEN
+  MAP_EVERY EXISTS_TAC [`cacs`; `&1 - abs x`] THEN
+  ASM_REWRITE_TAC[REAL_SUB_LT] THEN REPEAT STRIP_TAC THENL
+   [ASM_SIMP_TAC[CX_INV; CX_SIN; CX_ACS; CX_NEG; REAL_LT_IMP_LE] THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_AT_WITHIN THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_CACS THEN ASM_REWRITE_TAC[RE_CX];
+    MATCH_MP_TAC(GSYM CX_ACS) THEN ASM_REAL_ARITH_TAC]);;
+
+let HAS_REAL_DERIVATIVE_ACS = prove
+ (`!x. abs(x) < &1
+       ==> (acs has_real_derivative --inv(sqrt(&1 - x pow 2))) (atreal x)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HAS_REAL_DERIVATIVE_ACS_SIN) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  AP_TERM_TAC THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC SIN_ACS THEN ASM_REAL_ARITH_TAC);;
+
+let REAL_DIFFERENTIABLE_AT_ACS = prove
+ (`!x. abs(x) < &1 ==> acs real_differentiable (atreal x)`,
+  REWRITE_TAC[real_differentiable] THEN
+  MESON_TAC[HAS_REAL_DERIVATIVE_ACS]);;
+
+let REAL_DIFFERENTIABLE_WITHIN_ACS = prove
+ (`!s x. abs(x) < &1 ==> acs real_differentiable (atreal x within s)`,
+  MESON_TAC[REAL_DIFFERENTIABLE_ATREAL_WITHIN;
+            REAL_DIFFERENTIABLE_AT_ACS]);;
+
+let REAL_CONTINUOUS_AT_ACS = prove
+ (`!x. abs(x) < &1 ==> acs real_continuous (atreal x)`,
+  MESON_TAC[HAS_REAL_DERIVATIVE_ACS;
+            HAS_REAL_DERIVATIVE_IMP_CONTINUOUS_ATREAL]);;
+
+let REAL_CONTINUOUS_WITHIN_ACS = prove
+ (`!s x. abs(x) < &1 ==> acs real_continuous (atreal x within s)`,
+  MESON_TAC[REAL_CONTINUOUS_ATREAL_WITHINREAL;
+            REAL_CONTINUOUS_AT_ACS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence differentiation of the norm.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let DIFFERENTIABLE_NORM_AT = prove
+ (`!a:real^N. ~(a = vec 0) ==> (\x. lift(norm x)) differentiable (at a)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[vector_norm] THEN
+  SUBGOAL_THEN
+   `(\x:real^N. lift(sqrt(x dot x))) =
+    (lift o sqrt o drop) o (\x. lift(x dot x))`
+  SUBST1_TAC THENL [REWRITE_TAC[o_DEF; LIFT_DROP]; ALL_TAC] THEN
+  MATCH_MP_TAC DIFFERENTIABLE_CHAIN_AT THEN
+  REWRITE_TAC[DIFFERENTIABLE_SQNORM_AT; GSYM NORM_POW_2] THEN
+  MP_TAC(ISPEC `norm(a:real^N) pow 2` REAL_DIFFERENTIABLE_AT_SQRT) THEN
+  ASM_SIMP_TAC[REAL_POW_LT; NORM_POS_LT; REAL_DIFFERENTIABLE_AT]);;
+
+let DIFFERENTIABLE_ON_NORM = prove
+ (`!s:real^N->bool. ~(vec 0 IN s) ==> (\x. lift(norm x)) differentiable_on s`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC DIFFERENTIABLE_NORM_AT THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some somewhat sharper continuity theorems including endpoints.            *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_CONTINUOUS_WITHIN_SQRT_STRONG = prove
+ (`!x. sqrt real_continuous (atreal x within {t | &0 <= t})`,
+  GEN_TAC THEN REWRITE_TAC[REAL_COMPLEX_CONTINUOUS_WITHINREAL] THEN
+  ASM_CASES_TAC `x IN {t | &0 <= t}` THENL
+   [MATCH_MP_TAC CONTINUOUS_TRANSFORM_WITHIN THEN
+    MAP_EVERY EXISTS_TAC [`csqrt`; `&1`] THEN
+    REWRITE_TAC[IMAGE_CX; IN_ELIM_THM; REAL_LT_01;
+      CONTINUOUS_WITHIN_CSQRT_POSREAL;
+      SET_RULE `real INTER {z | real z /\ P z} = {z | real z /\ P z}`] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_ELIM_THM]) THEN
+    ASM_REWRITE_TAC[REAL_CX; RE_CX; IMP_CONJ; FORALL_REAL; o_THM] THEN
+    SIMP_TAC[CX_SQRT];
+    MATCH_MP_TAC CONTINUOUS_WITHIN_CLOSED_NONTRIVIAL THEN CONJ_TAC THENL
+     [SUBGOAL_THEN `real INTER IMAGE Cx {t | &0 <= t} =
+                    real INTER {t | Re t >= &0}`
+       (fun th -> SIMP_TAC[th; CLOSED_INTER; CLOSED_REAL;
+                           CLOSED_HALFSPACE_RE_GE]) THEN
+     REWRITE_TAC[EXTENSION; IMAGE_CX; IN_ELIM_THM; IN_CBALL; IN_INTER] THEN
+     REWRITE_TAC[real_ge; IN; CONJ_ACI];
+      MATCH_MP_TAC(SET_RULE
+       `(!x y. f x = f y ==> x = y) /\ ~(x IN s)
+        ==> ~(f x IN t INTER IMAGE f s)`) THEN
+      ASM_REWRITE_TAC[CX_INJ]]]);;
+
+let REAL_CONTINUOUS_ON_SQRT = prove
+ (`!s. (!x. x IN s ==> &0 <= x) ==> sqrt real_continuous_on s`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_CONTINUOUS_WITHINREAL_SUBSET THEN
+  EXISTS_TAC `{x | &0 <= x}` THEN
+  ASM_REWRITE_TAC[SUBSET; IN_ELIM_THM; REAL_CONTINUOUS_WITHIN_SQRT_STRONG]);;
+
+let REAL_CONTINUOUS_WITHIN_ASN_STRONG = prove
+ (`!x. asn real_continuous (atreal x within {t | abs(t) <= &1})`,
+  GEN_TAC THEN REWRITE_TAC[REAL_COMPLEX_CONTINUOUS_WITHINREAL] THEN
+  ASM_CASES_TAC `x IN {t | abs(t) <= &1}` THENL
+   [MATCH_MP_TAC CONTINUOUS_TRANSFORM_WITHIN THEN
+    MAP_EVERY EXISTS_TAC [`casn`; `&1`] THEN
+    REWRITE_TAC[IMAGE_CX; IN_ELIM_THM; CONTINUOUS_WITHIN_CASN_REAL; REAL_LT_01;
+     SET_RULE `real INTER {z | real z /\ P z} = {z | real z /\ P z}`] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_ELIM_THM]) THEN
+    ASM_REWRITE_TAC[REAL_CX; RE_CX; IMP_CONJ; FORALL_REAL; o_THM] THEN
+    SIMP_TAC[CX_ASN];
+    MATCH_MP_TAC CONTINUOUS_WITHIN_CLOSED_NONTRIVIAL THEN CONJ_TAC THENL
+     [SUBGOAL_THEN `real INTER IMAGE Cx {t | abs t <= &1} =
+                    real INTER cball(Cx(&0),&1)`
+       (fun th -> SIMP_TAC[th; CLOSED_INTER; CLOSED_REAL; CLOSED_CBALL]) THEN
+      REWRITE_TAC[EXTENSION; IMAGE_CX; IN_ELIM_THM; IN_CBALL; IN_INTER] THEN
+      REWRITE_TAC[dist; COMPLEX_SUB_LZERO; NORM_NEG; IN] THEN
+      MESON_TAC[REAL_NORM];
+      MATCH_MP_TAC(SET_RULE
+       `(!x y. f x = f y ==> x = y) /\ ~(x IN s)
+        ==> ~(f x IN t INTER IMAGE f s)`) THEN
+      ASM_REWRITE_TAC[CX_INJ]]]);;
+
+let REAL_CONTINUOUS_ON_ASN = prove
+ (`!s. (!x. x IN s ==> abs(x) <= &1) ==> asn real_continuous_on s`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_CONTINUOUS_WITHINREAL_SUBSET THEN
+  EXISTS_TAC `{x | abs(x) <= &1}` THEN
+  ASM_REWRITE_TAC[SUBSET; IN_ELIM_THM; REAL_CONTINUOUS_WITHIN_ASN_STRONG]);;
+
+let REAL_CONTINUOUS_WITHIN_ACS_STRONG = prove
+ (`!x. acs real_continuous (atreal x within {t | abs(t) <= &1})`,
+  GEN_TAC THEN REWRITE_TAC[REAL_COMPLEX_CONTINUOUS_WITHINREAL] THEN
+  ASM_CASES_TAC `x IN {t | abs(t) <= &1}` THENL
+   [MATCH_MP_TAC CONTINUOUS_TRANSFORM_WITHIN THEN
+    MAP_EVERY EXISTS_TAC [`cacs`; `&1`] THEN
+    REWRITE_TAC[IMAGE_CX; IN_ELIM_THM; CONTINUOUS_WITHIN_CACS_REAL; REAL_LT_01;
+     SET_RULE `real INTER {z | real z /\ P z} = {z | real z /\ P z}`] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_ELIM_THM]) THEN
+    ASM_REWRITE_TAC[REAL_CX; RE_CX; IMP_CONJ; FORALL_REAL; o_THM] THEN
+    SIMP_TAC[CX_ACS];
+    MATCH_MP_TAC CONTINUOUS_WITHIN_CLOSED_NONTRIVIAL THEN CONJ_TAC THENL
+     [SUBGOAL_THEN `real INTER IMAGE Cx {t | abs t <= &1} =
+                    real INTER cball(Cx(&0),&1)`
+       (fun th -> SIMP_TAC[th; CLOSED_INTER; CLOSED_REAL; CLOSED_CBALL]) THEN
+      REWRITE_TAC[EXTENSION; IMAGE_CX; IN_ELIM_THM; IN_CBALL; IN_INTER] THEN
+      REWRITE_TAC[dist; COMPLEX_SUB_LZERO; NORM_NEG; IN] THEN
+      MESON_TAC[REAL_NORM];
+      MATCH_MP_TAC(SET_RULE
+       `(!x y. f x = f y ==> x = y) /\ ~(x IN s)
+        ==> ~(f x IN t INTER IMAGE f s)`) THEN
+      ASM_REWRITE_TAC[CX_INJ]]]);;
+
+let REAL_CONTINUOUS_ON_ACS = prove
+ (`!s. (!x. x IN s ==> abs(x) <= &1) ==> acs real_continuous_on s`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_CONTINUOUS_WITHINREAL_SUBSET THEN
+  EXISTS_TAC `{x | abs(x) <= &1}` THEN
+  ASM_REWRITE_TAC[SUBSET; IN_ELIM_THM; REAL_CONTINUOUS_WITHIN_ACS_STRONG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Differentiation conversion.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let real_differentiation_theorems = ref [];;
+
+let add_real_differentiation_theorems =
+  let ETA_THM = prove
+   (`(f has_real_derivative f') net <=>
+     ((\x. f x) has_real_derivative f') net`,
+    REWRITE_TAC[ETA_AX]) in
+  let ETA_TWEAK =
+    PURE_REWRITE_RULE [IMP_CONJ] o
+    GEN_REWRITE_RULE (LAND_CONV o ONCE_DEPTH_CONV) [ETA_THM] o
+    SPEC_ALL in
+  fun l -> real_differentiation_theorems :=
+              !real_differentiation_theorems @ map ETA_TWEAK l;;
+
+add_real_differentiation_theorems
+ ([HAS_REAL_DERIVATIVE_LMUL_WITHIN; HAS_REAL_DERIVATIVE_LMUL_ATREAL;
+   HAS_REAL_DERIVATIVE_RMUL_WITHIN; HAS_REAL_DERIVATIVE_RMUL_ATREAL;
+   HAS_REAL_DERIVATIVE_CDIV_WITHIN; HAS_REAL_DERIVATIVE_CDIV_ATREAL;
+   HAS_REAL_DERIVATIVE_ID;
+   HAS_REAL_DERIVATIVE_CONST;
+   HAS_REAL_DERIVATIVE_NEG;
+   HAS_REAL_DERIVATIVE_ADD;
+   HAS_REAL_DERIVATIVE_SUB;
+   HAS_REAL_DERIVATIVE_MUL_WITHIN; HAS_REAL_DERIVATIVE_MUL_ATREAL;
+   HAS_REAL_DERIVATIVE_DIV_WITHIN; HAS_REAL_DERIVATIVE_DIV_ATREAL;
+   HAS_REAL_DERIVATIVE_POW_WITHIN; HAS_REAL_DERIVATIVE_POW_ATREAL;
+   HAS_REAL_DERIVATIVE_INV_WITHIN; HAS_REAL_DERIVATIVE_INV_ATREAL] @
+  (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+    (MATCH_MP HAS_REAL_DERIVATIVE_CHAIN_UNIV
+              HAS_REAL_DERIVATIVE_EXP))) @
+  (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+    (MATCH_MP HAS_REAL_DERIVATIVE_CHAIN_UNIV
+              HAS_REAL_DERIVATIVE_SIN))) @
+  (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+    (MATCH_MP HAS_REAL_DERIVATIVE_CHAIN_UNIV
+              HAS_REAL_DERIVATIVE_COS))) @
+  (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+    (MATCH_MP HAS_REAL_DERIVATIVE_CHAIN
+              HAS_REAL_DERIVATIVE_TAN))) @
+  (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+    (MATCH_MP HAS_REAL_DERIVATIVE_CHAIN
+              HAS_REAL_DERIVATIVE_LOG))) @
+  (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+    (MATCH_MP HAS_REAL_DERIVATIVE_CHAIN
+              HAS_REAL_DERIVATIVE_SQRT))) @
+  (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+    (MATCH_MP HAS_REAL_DERIVATIVE_CHAIN_UNIV
+              HAS_REAL_DERIVATIVE_ATN))) @
+  (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+    (MATCH_MP HAS_REAL_DERIVATIVE_CHAIN
+              HAS_REAL_DERIVATIVE_ASN))) @
+  (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+    (MATCH_MP HAS_REAL_DERIVATIVE_CHAIN
+              HAS_REAL_DERIVATIVE_ACS))));;
+
+let rec REAL_DIFF_CONV =
+  let partfn tm = let l,r = dest_comb tm in mk_pair(lhand l,r)
+  and is_deriv = can (term_match [] `(f has_real_derivative f') net`) in
+  let rec REAL_DIFF_CONV tm =
+    try tryfind (fun th -> PART_MATCH partfn th (partfn tm))
+                (!real_differentiation_theorems)
+    with Failure _ ->
+        let ith = tryfind (fun th ->
+         PART_MATCH (partfn o repeat (snd o dest_imp)) th (partfn tm))
+                    (!real_differentiation_theorems) in
+        REAL_DIFF_ELIM ith
+  and REAL_DIFF_ELIM th =
+    let tm = concl th in
+    if not(is_imp tm) then th else
+    let t = lhand tm in
+    if not(is_deriv t) then UNDISCH th
+    else REAL_DIFF_ELIM (MATCH_MP th (REAL_DIFF_CONV t)) in
+  REAL_DIFF_CONV;;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence a tactic.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_DIFF_TAC =
+  let pth = MESON[]
+   `(f has_real_derivative f') net
+    ==> f' = g'
+        ==> (f has_real_derivative g') net` in
+  W(fun (asl,w) -> let th = MATCH_MP pth (REAL_DIFF_CONV w) in
+       MATCH_MP_TAC(repeat (GEN_REWRITE_RULE I [IMP_IMP]) (DISCH_ALL th)));;
+
+let REAL_DIFFERENTIABLE_TAC =
+  let DISCH_FIRST th = DISCH (hd(hyp th)) th in
+  GEN_REWRITE_TAC I [real_differentiable] THEN
+  W(fun (asl,w) ->
+        let th = REAL_DIFF_CONV(snd(dest_exists w)) in
+        let f' = rand(rator(concl th)) in
+        EXISTS_TAC f' THEN
+        (if hyp th = [] then MATCH_ACCEPT_TAC th else
+         let th' = repeat (GEN_REWRITE_RULE I [IMP_IMP] o DISCH_FIRST)
+                          (DISCH_FIRST th) in
+         MATCH_MP_TAC th'));;
+
+(* ------------------------------------------------------------------------- *)
+(* Analytic results for real power function.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_REAL_DERIVATIVE_RPOW = prove
+ (`!x y.
+    &0 < x
+    ==> ((\x. x rpow y) has_real_derivative y * x rpow (y - &1)) (atreal x)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_REAL_DERIVATIVE_TRANSFORM_ATREAL THEN
+  EXISTS_TAC `\x. exp(y * log x)` THEN EXISTS_TAC `x:real` THEN
+  ASM_SIMP_TAC[rpow; REAL_ARITH
+    `&0 < x ==> (abs(y - x) < x <=> &0 < y /\ y < &2 * x)`] THEN
+  REAL_DIFF_TAC THEN
+  ASM_SIMP_TAC[REAL_SUB_RDISTRIB; REAL_EXP_SUB; REAL_MUL_LID; EXP_LOG] THEN
+  REAL_ARITH_TAC);;
+
+add_real_differentiation_theorems
+ (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+   (GEN `y:real` (MATCH_MP HAS_REAL_DERIVATIVE_CHAIN
+    (SPEC `y:real`
+      (ONCE_REWRITE_RULE[SWAP_FORALL_THM] HAS_REAL_DERIVATIVE_RPOW))))));;
+
+let REAL_DIFFERENTIABLE_AT_RPOW = prove
+ (`!x y. ~(x = &0) ==> (\x. x rpow y) real_differentiable atreal x`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[REAL_ARITH `~(x = &0) <=> &0 < x \/ &0 < --x`] THEN
+  STRIP_TAC THEN MATCH_MP_TAC REAL_DIFFERENTIABLE_TRANSFORM_ATREAL THEN
+  REWRITE_TAC[] THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  EXISTS_TAC `abs x` THENL
+   [EXISTS_TAC `\x. exp(y * log x)` THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < x ==> &0 < abs x`] THEN CONJ_TAC THENL
+     [X_GEN_TAC `z:real` THEN DISCH_TAC THEN
+      SUBGOAL_THEN `&0 < z` (fun th -> REWRITE_TAC[rpow; th]) THEN
+      ASM_REAL_ARITH_TAC;
+      REAL_DIFFERENTIABLE_TAC THEN ASM_REAL_ARITH_TAC];
+    ASM_CASES_TAC `?m n. ODD m /\ ODD n /\ abs y = &m / &n` THENL
+     [EXISTS_TAC `\x. --(exp(y * log(--x)))`;
+      EXISTS_TAC `\x. exp(y * log(--x))`] THEN
+    (ASM_SIMP_TAC[REAL_ARITH `&0 < --x ==> &0 < abs x`] THEN CONJ_TAC THENL
+      [X_GEN_TAC `z:real` THEN DISCH_TAC THEN
+       SUBGOAL_THEN `~(&0 < z) /\ ~(z = &0)`
+         (fun th -> ASM_REWRITE_TAC[rpow; th]) THEN
+       ASM_REAL_ARITH_TAC;
+       REAL_DIFFERENTIABLE_TAC THEN ASM_REAL_ARITH_TAC])]);;
+
+let REAL_CONTINUOUS_AT_RPOW = prove
+ (`!x y. (x = &0 ==> &0 <= y)
+         ==> (\x. x rpow y) real_continuous (atreal x)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `y = &0` THEN
+  ASM_REWRITE_TAC[RPOW_POW; real_pow; REAL_CONTINUOUS_CONST] THEN
+  ASM_CASES_TAC `x = &0` THENL
+   [ASM_REWRITE_TAC[real_continuous_atreal; RPOW_ZERO] THEN
+    REWRITE_TAC[REAL_SUB_RZERO; REAL_ABS_RPOW] THEN STRIP_TAC THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN EXISTS_TAC `e rpow inv(y)` THEN
+    ASM_SIMP_TAC[RPOW_POS_LT] THEN X_GEN_TAC `z:real` THEN DISCH_TAC THEN
+    MATCH_MP_TAC REAL_LTE_TRANS THEN
+    EXISTS_TAC `e rpow inv y rpow y` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC RPOW_LT2 THEN ASM_REAL_ARITH_TAC;
+      ASM_SIMP_TAC[RPOW_RPOW; REAL_LT_IMP_LE; REAL_MUL_LINV] THEN
+      REWRITE_TAC[RPOW_POW; REAL_POW_1; REAL_LE_REFL]];
+    ASM_SIMP_TAC[REAL_DIFFERENTIABLE_IMP_CONTINUOUS_ATREAL;
+                 REAL_DIFFERENTIABLE_AT_RPOW]]);;
+
+let REAL_CONTINUOUS_WITHIN_RPOW = prove
+ (`!s x y. (x = &0 ==> &0 <= y)
+           ==> (\x. x rpow y) real_continuous (atreal x within s)`,
+  MESON_TAC[REAL_CONTINUOUS_ATREAL_WITHINREAL;
+            REAL_CONTINUOUS_AT_RPOW]);;
+
+let REAL_CONTINUOUS_ON_RPOW = prove
+ (`!s y. (&0 IN s ==> &0 <= y) ==> (\x. x rpow y) real_continuous_on s`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_CONTINUOUS_WITHIN_RPOW THEN
+  ASM_MESON_TAC[]);;
+
+let REALLIM_RPOW = prove
+ (`!net f l n.
+        (f ---> l) net /\ (l = &0 ==> &0 <= n)
+        ==> ((\x. f x rpow n) ---> l rpow n) net`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC
+  (REWRITE_RULE[] (ISPEC `\x. x rpow n` REALLIM_REAL_CONTINUOUS_FUNCTION)) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_CONTINUOUS_AT_RPOW THEN
+  ASM_REWRITE_TAC[]);;
+
+let REALLIM_NULL_POW_EQ = prove
+ (`!net f n.
+        ~(n = 0)
+        ==> (((\x. f x pow n) ---> &0) net <=> (f ---> &0) net)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN ASM_SIMP_TAC[REALLIM_NULL_POW] THEN
+  DISCH_THEN(MP_TAC o ISPEC `(\x. x rpow (inv(&n))) o abs` o
+    MATCH_MP(REWRITE_RULE[IMP_CONJ_ALT] REALLIM_REAL_CONTINUOUS_FUNCTION)) THEN
+  REWRITE_TAC[o_THM] THEN
+  ASM_REWRITE_TAC[RPOW_ZERO; REAL_INV_EQ_0; REAL_OF_NUM_EQ; REAL_ABS_NUM] THEN
+  SIMP_TAC[GSYM RPOW_POW; RPOW_RPOW; REAL_ABS_POS; REAL_ABS_RPOW] THEN
+  ASM_SIMP_TAC[REAL_MUL_RINV; REAL_OF_NUM_EQ] THEN
+  REWRITE_TAC[REALLIM_NULL_ABS; RPOW_POW; REAL_POW_1] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM WITHINREAL_UNIV] THEN
+  MATCH_MP_TAC REAL_CONTINUOUS_WITHINREAL_COMPOSE THEN CONJ_TAC THENL
+   [GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN
+    MATCH_MP_TAC REAL_CONTINUOUS_ABS THEN
+    REWRITE_TAC[REAL_CONTINUOUS_WITHIN_ID];
+    MATCH_MP_TAC REAL_CONTINUOUS_WITHIN_RPOW THEN
+    REWRITE_TAC[REAL_LE_INV_EQ; REAL_POS]]);;
+
+let LIM_NULL_COMPLEX_POW_EQ = prove
+ (`!net f n.
+        ~(n = 0)
+        ==> (((\x. f x pow n) --> Cx(&0)) net <=> (f --> Cx(&0)) net)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM COMPLEX_VEC_0] THEN
+  ONCE_REWRITE_TAC[LIM_NULL_NORM] THEN
+  REWRITE_TAC[COMPLEX_NORM_POW; REAL_TENDSTO; o_DEF; LIFT_DROP] THEN
+  ASM_SIMP_TAC[REALLIM_NULL_POW_EQ; DROP_VEC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Intermediate Value Theorem.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_IVT_INCREASING = prove
+ (`!f a b y.
+        a <= b /\ f real_continuous_on real_interval[a,b] /\
+        f a <= y /\ y <= f b
+        ==> ?x. x IN real_interval [a,b] /\ f x = y`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `lift a`; `lift b`; `y:real`; `1`]
+        IVT_INCREASING_COMPONENT_ON_1) THEN
+  ASM_REWRITE_TAC[GSYM drop; o_THM; LIFT_DROP; DIMINDEX_1; LE_REFL] THEN
+  REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; EXISTS_IN_IMAGE; LIFT_DROP]);;
+
+let REAL_IVT_DECREASING = prove
+ (`!f a b y.
+        a <= b /\ f real_continuous_on real_interval[a,b] /\
+        f b <= y /\ y <= f a
+        ==> ?x. x IN real_interval [a,b] /\ f x = y`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `lift a`; `lift b`; `y:real`; `1`]
+        IVT_DECREASING_COMPONENT_ON_1) THEN
+  ASM_REWRITE_TAC[GSYM drop; o_THM; LIFT_DROP; DIMINDEX_1; LE_REFL] THEN
+  REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; EXISTS_IN_IMAGE; LIFT_DROP]);;
+
+let IS_REALINTERVAL_CONTINUOUS_IMAGE = prove
+ (`!s. f real_continuous_on s /\ is_realinterval s
+       ==> is_realinterval(IMAGE f s)`,
+  GEN_TAC THEN REWRITE_TAC[REAL_CONTINUOUS_ON; IS_REALINTERVAL_CONNECTED] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CONNECTED_CONTINUOUS_IMAGE) THEN
+  REWRITE_TAC[IMAGE_o; REWRITE_RULE[IMAGE_o] IMAGE_LIFT_DROP]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Zeroness (or sign at boundary) of derivative at local extremum.           *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_DERIVATIVE_POS_LEFT_MINIMUM = prove
+ (`!f f' a b e.
+        a < b /\ &0 < e /\
+        (f has_real_derivative f') (atreal a within real_interval[a,b]) /\
+        (!x. x IN real_interval[a,b] /\ abs(x - a) < e ==> f a <= f x)
+        ==> &0 <= f'`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `\x:real^1. f' % x`;
+                 `lift a`; `interval[lift a,lift b]`; `e:real`]
+        DROP_DIFFERENTIAL_POS_AT_MINIMUM) THEN
+  ASM_REWRITE_TAC[ENDS_IN_INTERVAL; CONVEX_INTERVAL; IN_INTER; IMP_CONJ] THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IMAGE_EQ_EMPTY;
+                  GSYM HAS_REAL_FRECHET_DERIVATIVE_WITHIN] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP; IN_BALL; DIST_LIFT;
+               REAL_INTERVAL_NE_EMPTY; REAL_LT_IMP_LE] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[REAL_ABS_SUB]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `b:real`) THEN
+  ASM_SIMP_TAC[ENDS_IN_REAL_INTERVAL; REAL_INTERVAL_NE_EMPTY;
+               REAL_LT_IMP_LE] THEN
+  ASM_SIMP_TAC[DROP_CMUL; DROP_SUB; LIFT_DROP; REAL_LE_MUL_EQ;
+               REAL_SUB_LT]);;
+
+let REAL_DERIVATIVE_NEG_LEFT_MAXIMUM = prove
+ (`!f f' a b e.
+        a < b /\ &0 < e /\
+        (f has_real_derivative f') (atreal a within real_interval[a,b]) /\
+        (!x. x IN real_interval[a,b] /\ abs(x - a) < e ==> f x <= f a)
+        ==> f' <= &0`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `\x:real^1. f' % x`;
+                 `lift a`; `interval[lift a,lift b]`; `e:real`]
+        DROP_DIFFERENTIAL_NEG_AT_MAXIMUM) THEN
+  ASM_REWRITE_TAC[ENDS_IN_INTERVAL; CONVEX_INTERVAL; IN_INTER; IMP_CONJ] THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IMAGE_EQ_EMPTY;
+                  GSYM HAS_REAL_FRECHET_DERIVATIVE_WITHIN] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP; IN_BALL; DIST_LIFT;
+               REAL_INTERVAL_NE_EMPTY; REAL_LT_IMP_LE] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[REAL_ABS_SUB]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `b:real`) THEN
+  ASM_SIMP_TAC[ENDS_IN_REAL_INTERVAL; REAL_INTERVAL_NE_EMPTY;
+               REAL_LT_IMP_LE] THEN
+  ASM_SIMP_TAC[DROP_CMUL; DROP_SUB; LIFT_DROP; REAL_LE_MUL_EQ;
+               REAL_SUB_LT; REAL_ARITH `f * ba <= &0 <=> &0 <= --f * ba`] THEN
+  REAL_ARITH_TAC);;
+
+let REAL_DERIVATIVE_POS_RIGHT_MAXIMUM = prove
+ (`!f f' a b e.
+        a < b /\ &0 < e /\
+        (f has_real_derivative f') (atreal b within real_interval[a,b]) /\
+        (!x. x IN real_interval[a,b] /\ abs(x - b) < e ==> f x <= f b)
+        ==> &0 <= f'`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `\x:real^1. f' % x`;
+                 `lift b`; `interval[lift a,lift b]`; `e:real`]
+        DROP_DIFFERENTIAL_NEG_AT_MAXIMUM) THEN
+  ASM_REWRITE_TAC[ENDS_IN_INTERVAL; CONVEX_INTERVAL; IN_INTER; IMP_CONJ] THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IMAGE_EQ_EMPTY;
+                  GSYM HAS_REAL_FRECHET_DERIVATIVE_WITHIN] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP; IN_BALL; DIST_LIFT;
+               REAL_INTERVAL_NE_EMPTY; REAL_LT_IMP_LE] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[REAL_ABS_SUB]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `a:real`) THEN
+  ASM_SIMP_TAC[ENDS_IN_REAL_INTERVAL; REAL_INTERVAL_NE_EMPTY;
+               REAL_LT_IMP_LE] THEN
+  ASM_SIMP_TAC[DROP_CMUL; DROP_SUB; LIFT_DROP; REAL_LE_MUL_EQ; REAL_SUB_LT;
+               REAL_ARITH `f * (a - b) <= &0 <=> &0 <= f * (b - a)`]);;
+
+let REAL_DERIVATIVE_NEG_RIGHT_MINIMUM = prove
+ (`!f f' a b e.
+        a < b /\ &0 < e /\
+        (f has_real_derivative f') (atreal b within real_interval[a,b]) /\
+        (!x. x IN real_interval[a,b] /\ abs(x - b) < e ==> f b <= f x)
+        ==> f' <= &0`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `\x:real^1. f' % x`;
+                 `lift b`; `interval[lift a,lift b]`; `e:real`]
+        DROP_DIFFERENTIAL_POS_AT_MINIMUM) THEN
+  ASM_REWRITE_TAC[ENDS_IN_INTERVAL; CONVEX_INTERVAL; IN_INTER; IMP_CONJ] THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IMAGE_EQ_EMPTY;
+                  GSYM HAS_REAL_FRECHET_DERIVATIVE_WITHIN] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP; IN_BALL; DIST_LIFT;
+               REAL_INTERVAL_NE_EMPTY; REAL_LT_IMP_LE] THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[REAL_ABS_SUB]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `a:real`) THEN
+  ASM_SIMP_TAC[ENDS_IN_REAL_INTERVAL; REAL_INTERVAL_NE_EMPTY;
+               REAL_LT_IMP_LE] THEN
+  ASM_SIMP_TAC[DROP_CMUL; DROP_SUB; LIFT_DROP] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `&0 <= f * (a - b) <=> &0 <= --f * (b - a)`] THEN
+  ASM_SIMP_TAC[REAL_LE_MUL_EQ; REAL_SUB_LT] THEN REAL_ARITH_TAC);;
+
+let REAL_DERIVATIVE_ZERO_MAXMIN = prove
+ (`!f f' x s.
+        x IN s /\ real_open s /\
+        (f has_real_derivative f') (atreal x) /\
+        ((!y. y IN s ==> f y <= f x) \/ (!y. y IN s ==> f x <= f y))
+        ==> f' = &0`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `\x:real^1. f' % x`;
+                 `lift x`; `IMAGE lift s`]
+        DIFFERENTIAL_ZERO_MAXMIN) THEN
+  ASM_REWRITE_TAC[GSYM HAS_REAL_FRECHET_DERIVATIVE_AT; GSYM REAL_OPEN] THEN
+  ASM_SIMP_TAC[FUN_IN_IMAGE; FORALL_IN_IMAGE] THEN
+  ASM_REWRITE_TAC[o_DEF; LIFT_DROP] THEN
+  DISCH_THEN(MP_TAC o C AP_THM `vec 1:real^1`) THEN
+  REWRITE_TAC[GSYM DROP_EQ; DROP_CMUL; DROP_VEC; REAL_MUL_RID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Rolle and Mean Value Theorem.                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_ROLLE = prove
+ (`!f f' a b.
+        a < b /\ f a = f b /\
+        f real_continuous_on real_interval[a,b] /\
+        (!x. x IN real_interval(a,b)
+             ==> (f has_real_derivative f'(x)) (atreal x))
+        ==> ?x. x IN real_interval(a,b) /\ f'(x) = &0`,
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; FORALL_IN_IMAGE; EXISTS_IN_IMAGE] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_ON; HAS_REAL_VECTOR_DERIVATIVE_AT] THEN
+  REWRITE_TAC[GSYM IMAGE_o; IMAGE_LIFT_DROP; has_vector_derivative] THEN
+  REWRITE_TAC[LIFT_DROP] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `\x:real^1 h:real^1. f'(drop x) % h`;
+                 `lift a`; `lift b`] ROLLE) THEN
+  ASM_REWRITE_TAC[o_THM; LIFT_DROP] THEN ANTS_TAC THENL
+   [X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `t:real^1`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC EQ_IMP THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN
+    REWRITE_TAC[FUN_EQ_THM; FORALL_LIFT; LIFT_DROP; GSYM LIFT_CMUL] THEN
+    REWRITE_TAC[REAL_MUL_AC];
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real^1` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o C AP_THM `lift(&1)`) THEN
+    REWRITE_TAC[GSYM LIFT_CMUL; GSYM LIFT_NUM; LIFT_EQ; REAL_MUL_RID]]);;
+
+let REAL_MVT = prove
+ (`!f f' a b.
+        a < b /\
+        f real_continuous_on real_interval[a,b] /\
+        (!x. x IN real_interval(a,b)
+             ==> (f has_real_derivative f'(x)) (atreal x))
+        ==> ?x. x IN real_interval(a,b) /\ f(b) - f(a) = f'(x) * (b - a)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`\x:real. f(x) - (f b - f a) / (b - a) * x`;
+                `(\x. f'(x) - (f b - f a) / (b - a)):real->real`;
+                 `a:real`; `b:real`]
+               REAL_ROLLE) THEN
+  ASM_SIMP_TAC[REAL_FIELD
+   `a < b ==> (fx - fba / (b - a) = &0 <=> fba = fx * (b - a))`] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[REAL_CONTINUOUS_ON_SUB; REAL_CONTINUOUS_ON_LMUL;
+               REAL_CONTINUOUS_ON_ID] THEN
+  CONJ_TAC THENL [UNDISCH_TAC `a < b` THEN CONV_TAC REAL_FIELD; ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_DERIVATIVE_SUB THEN
+  ASM_SIMP_TAC[] THEN GEN_REWRITE_TAC LAND_CONV [GSYM REAL_MUL_RID] THEN
+  ASM_SIMP_TAC[HAS_REAL_DERIVATIVE_LMUL_ATREAL; HAS_REAL_DERIVATIVE_ID]);;
+
+let REAL_MVT_SIMPLE = prove
+ (`!f f' a b.
+        a < b /\
+        (!x. x IN real_interval[a,b]
+             ==> (f has_real_derivative f'(x))
+                 (atreal x within real_interval[a,b]))
+        ==> ?x. x IN real_interval(a,b) /\ f(b) - f(a) = f'(x) * (b - a)`,
+  MP_TAC REAL_MVT THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_DIFFERENTIABLE_ON_IMP_REAL_CONTINUOUS_ON THEN
+    ASM_MESON_TAC[real_differentiable_on; real_differentiable];
+    ASM_MESON_TAC[HAS_REAL_DERIVATIVE_WITHIN_REAL_OPEN; REAL_OPEN_REAL_INTERVAL;
+                  REAL_INTERVAL_OPEN_SUBSET_CLOSED;
+                  HAS_REAL_DERIVATIVE_WITHIN_SUBSET; SUBSET]]);;
+
+let REAL_MVT_VERY_SIMPLE = prove
+ (`!f f' a b.
+        a <= b /\
+        (!x. x IN real_interval[a,b]
+             ==> (f has_real_derivative f'(x))
+                 (atreal x within real_interval[a,b]))
+        ==> ?x. x IN real_interval[a,b] /\ f(b) - f(a) = f'(x) * (b - a)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `b:real = a` THENL
+   [ASM_REWRITE_TAC[REAL_SUB_REFL; REAL_MUL_RZERO] THEN
+    REWRITE_TAC[REAL_INTERVAL_SING; IN_SING; EXISTS_REFL];
+    ASM_REWRITE_TAC[REAL_LE_LT] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP REAL_MVT_SIMPLE) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN
+    SIMP_TAC[REWRITE_RULE[SUBSET] REAL_INTERVAL_OPEN_SUBSET_CLOSED]]);;
+
+let REAL_ROLLE_SIMPLE = prove
+ (`!f f' a b.
+        a < b /\ f a = f b /\
+        (!x. x IN real_interval[a,b]
+             ==> (f has_real_derivative f'(x))
+                 (atreal x within real_interval[a,b]))
+        ==> ?x. x IN real_interval(a,b) /\ f'(x) = &0`,
+  MP_TAC REAL_MVT_SIMPLE THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) 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 MATCH_MP_TAC MONO_AND THEN
+  REWRITE_TAC[REAL_RING `a - a = b * (c - d) <=> b = &0 \/ c = d`] THEN
+  ASM_MESON_TAC[REAL_LT_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Cauchy MVT and l'Hospital's rule.                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_MVT_CAUCHY = prove
+ (`!f g f' g' a b.
+           a < b /\
+           f real_continuous_on real_interval[a,b] /\
+           g real_continuous_on real_interval[a,b] /\
+           (!x. x IN real_interval(a,b)
+                ==> (f has_real_derivative f' x) (atreal x) /\
+                    (g has_real_derivative g' x) (atreal x))
+           ==> ?x. x IN real_interval(a,b) /\
+                   (f b - f a) * g'(x) = (g b - g a) * f'(x)`,
+  REPEAT STRIP_TAC THEN MP_TAC(SPECL
+   [`\x. (f:real->real)(x) * (g(b:real) - g(a)) - g(x) * (f(b) - f(a))`;
+    `\x. (f':real->real)(x) * (g(b:real) - g(a)) - g'(x) * (f(b) - f(a))`;
+    `a:real`; `b:real`] REAL_MVT) THEN
+  ASM_SIMP_TAC[REAL_CONTINUOUS_ON_SUB; REAL_CONTINUOUS_ON_RMUL;
+               HAS_REAL_DERIVATIVE_SUB; HAS_REAL_DERIVATIVE_RMUL_ATREAL] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN
+  UNDISCH_TAC `a < b` THEN CONV_TAC REAL_FIELD);;
+
+let LHOSPITAL = prove
+ (`!f g f' g' c l d.
+        &0 < d /\
+        (!x. &0 < abs(x - c) /\ abs(x - c) < d
+             ==> (f has_real_derivative f'(x)) (atreal x) /\
+                 (g has_real_derivative g'(x)) (atreal x) /\
+                 ~(g'(x) = &0)) /\
+        (f ---> &0) (atreal c) /\ (g ---> &0) (atreal c) /\
+        ((\x. f'(x) / g'(x)) ---> l) (atreal c)
+        ==> ((\x. f(x) / g(x)) ---> l) (atreal c)`,
+  SUBGOAL_THEN
+    `!f g f' g' c l d.
+        &0 < d /\
+        (!x. &0 < abs(x - c) /\ abs(x - c) < d
+             ==> (f has_real_derivative f'(x)) (atreal x) /\
+                 (g has_real_derivative g'(x)) (atreal x) /\
+                 ~(g'(x) = &0)) /\
+        f(c) = &0 /\ g(c) = &0 /\
+        (f ---> &0) (atreal c) /\ (g ---> &0) (atreal c) /\
+        ((\x. f'(x) / g'(x)) ---> l) (atreal c)
+        ==> ((\x. f(x) / g(x)) ---> l) (atreal c)`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[TAUT `a ==> b /\ c <=> (a ==> b) /\ (a ==> c)`] THEN
+    REWRITE_TAC[FORALL_AND_THM] THEN REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+     `(!x. abs(x - c) < d ==> f real_continuous atreal x) /\
+      (!x. abs(x - c) < d ==> g real_continuous atreal x)`
+    STRIP_ASSUME_TAC THENL
+     [REWRITE_TAC[AND_FORALL_THM] THEN X_GEN_TAC `x:real` THEN
+      DISJ_CASES_TAC(REAL_ARITH `x = c \/ &0 < abs(x - c)`) THENL
+       [ASM_REWRITE_TAC[REAL_CONTINUOUS_ATREAL]; ALL_TAC] THEN
+      REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC REAL_DIFFERENTIABLE_IMP_CONTINUOUS_ATREAL THEN
+      REWRITE_TAC[real_differentiable] THEN ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!x.  &0 < abs(x - c) /\ abs(x - c) < d ==> ~(g x = &0)`
+    STRIP_ASSUME_TAC THENL
+     [REPEAT STRIP_TAC THEN
+      SUBGOAL_THEN `c < x \/ x < c` DISJ_CASES_TAC THENL
+       [ASM_REAL_ARITH_TAC;
+        MP_TAC(ISPECL [`g:real->real`; `g':real->real`; `c:real`; `x:real`]
+          REAL_ROLLE);
+        MP_TAC(ISPECL [`g:real->real`; `g':real->real`; `x:real`; `c:real`]
+          REAL_ROLLE)] THEN
+      ASM_REWRITE_TAC[NOT_IMP; NOT_EXISTS_THM] THEN
+      (REPEAT CONJ_TAC THENL
+        [REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+         REWRITE_TAC[IN_REAL_INTERVAL] THEN REPEAT STRIP_TAC THEN
+         MATCH_MP_TAC REAL_CONTINUOUS_ATREAL_WITHINREAL;
+         REWRITE_TAC[IN_REAL_INTERVAL] THEN REPEAT STRIP_TAC;
+         X_GEN_TAC `y:real` THEN REWRITE_TAC[IN_REAL_INTERVAL] THEN
+         DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+         REWRITE_TAC[]] THEN
+       FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC);
+      ALL_TAC] THEN
+    UNDISCH_TAC `((\x. f' x / g' x) ---> l) (atreal c)` THEN
+    REWRITE_TAC[REALLIM_ATREAL] 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 `k:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `min d k:real` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+    X_GEN_TAC `x:real` THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `?y. &0 < abs(y - c) /\ abs(y - c) < abs(x - c) /\
+          (f:real->real) x / g x = f' y / g' y`
+    STRIP_ASSUME_TAC THENL
+     [ALL_TAC; ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[REAL_LT_TRANS]] THEN
+    SUBGOAL_THEN `c < x \/ x < c` DISJ_CASES_TAC THENL
+     [ASM_REAL_ARITH_TAC;
+      MP_TAC(ISPECL
+       [`f:real->real`; `g:real->real`; `f':real->real`; `g':real->real`;
+        `c:real`; `x:real`] REAL_MVT_CAUCHY);
+      MP_TAC(ISPECL
+       [`f:real->real`; `g:real->real`; `f':real->real`; `g':real->real`;
+        `x:real`; `c:real`] REAL_MVT_CAUCHY)] THEN
+    (ASM_REWRITE_TAC[IN_REAL_INTERVAL] THEN ANTS_TAC THENL
+      [REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+        [CONJ_TAC THEN
+         REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+         REWRITE_TAC[IN_REAL_INTERVAL] THEN REPEAT STRIP_TAC THEN
+         MATCH_MP_TAC REAL_CONTINUOUS_ATREAL_WITHINREAL;
+         REPEAT STRIP_TAC] THEN
+       FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC;
+       MATCH_MP_TAC MONO_EXISTS THEN REWRITE_TAC[REAL_SUB_RZERO] THEN
+       GEN_TAC THEN STRIP_TAC THEN
+        REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+       MATCH_MP_TAC(REAL_FIELD
+        `f * g' = g * f' /\ ~(g = &0) /\ ~(g' = &0) ==> f / g = f' / g'`) THEN
+       CONJ_TAC THENL [ASM_REAL_ARITH_TAC; CONJ_TAC] THEN
+       FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC]);
+    REPEAT GEN_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`\x:real. if x = c then &0 else f(x)`;
+                `\x:real. if x = c then &0 else g(x)`;
+                `f':real->real`; `g':real->real`;
+                `c:real`; `l:real`; `d:real`]) THEN
+    REWRITE_TAC[] THEN MATCH_MP_TAC MONO_IMP THEN CONJ_TAC THEN
+    REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THEN
+    TRY(SIMP_TAC[REALLIM_ATREAL;REAL_ARITH `&0 < abs(x - c) ==> ~(x = c)`] THEN
+        NO_TAC) THEN
+    DISCH_TAC THEN X_GEN_TAC `x:real` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real`) THEN ASM_REWRITE_TAC[] THEN
+    REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THEN REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+          HAS_REAL_DERIVATIVE_TRANSFORM_ATREAL) THEN
+    EXISTS_TAC `abs(x - c)` THEN ASM_REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Darboux's theorem (intermediate value property for derivatives).          *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_DERIVATIVE_IVT_INCREASING = prove
+ (`!f f' a b.
+   a <= b /\
+   (!x. x IN real_interval[a,b]
+        ==> (f has_real_derivative f'(x)) (atreal x within real_interval[a,b]))
+   ==> !t. f'(a) <= t /\ t <= f'(b)
+           ==> ?x. x IN real_interval[a,b] /\ f' x = t`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN GEN_TAC THEN
+  ASM_CASES_TAC `(f':real->real) a = t` THENL
+   [ASM_MESON_TAC[ENDS_IN_REAL_INTERVAL; REAL_INTERVAL_NE_EMPTY];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `(f':real->real) b = t` THENL
+   [ASM_MESON_TAC[ENDS_IN_REAL_INTERVAL; REAL_INTERVAL_NE_EMPTY];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `b:real = a` THEN ASM_REWRITE_TAC[REAL_LE_ANTISYM] THEN
+  SUBGOAL_THEN `a < b` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_REWRITE_TAC[REAL_LE_LT] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\x:real. f x - t * x`; `real_interval[a,b]`]
+        REAL_CONTINUOUS_ATTAINS_INF) THEN
+  ASM_REWRITE_TAC[REAL_INTERVAL_NE_EMPTY; REAL_COMPACT_INTERVAL] THEN
+  ANTS_TAC THENL
+   [MATCH_MP_TAC REAL_DIFFERENTIABLE_ON_IMP_REAL_CONTINUOUS_ON THEN
+    MATCH_MP_TAC REAL_DIFFERENTIABLE_ON_SUB THEN
+    SIMP_TAC[REAL_DIFFERENTIABLE_ON_MUL; REAL_DIFFERENTIABLE_ON_ID;
+             REAL_DIFFERENTIABLE_ON_CONST] THEN
+    ASM_MESON_TAC[real_differentiable_on];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MP_TAC(SPECL
+   [`\x:real. f x - t * x`; `(f':real->real) x - t:real`;
+    `x:real`; `real_interval(a,b)`]
+        REAL_DERIVATIVE_ZERO_MAXMIN) THEN
+  ASM_REWRITE_TAC[REAL_SUB_0] THEN DISCH_THEN MATCH_MP_TAC THEN
+  REWRITE_TAC[REAL_OPEN_REAL_INTERVAL] THEN
+  ASM_SIMP_TAC[REAL_OPEN_CLOSED_INTERVAL; IN_DIFF] THEN
+  ASM_CASES_TAC `x:real = a` THENL
+   [FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    MP_TAC(ISPECL[`\x:real. f x - t * x`; `(f':real->real) a - t:real`;
+                  `a:real`; `b:real`; `&1`]
+        REAL_DERIVATIVE_POS_LEFT_MINIMUM) THEN
+    ASM_SIMP_TAC[REAL_LT_01; REAL_SUB_LE] THEN
+    MATCH_MP_TAC(TAUT `~q /\ p ==> (p ==> q) ==> r`) THEN
+    ASM_REWRITE_TAC[REAL_NOT_LE] THEN
+    MATCH_MP_TAC HAS_REAL_DERIVATIVE_SUB THEN
+    CONJ_TAC THENL [ALL_TAC; REAL_DIFF_TAC THEN REWRITE_TAC[REAL_MUL_RID]] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_NE_EMPTY];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `x:real = b` THENL
+   [FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    MP_TAC(ISPECL[`\x:real. f x - t * x`; `(f':real->real) b - t:real`;
+                  `a:real`; `b:real`; `&1`]
+        REAL_DERIVATIVE_NEG_RIGHT_MINIMUM) THEN
+    ASM_SIMP_TAC[REAL_LT_01; REAL_SUB_LE] THEN
+    MATCH_MP_TAC(TAUT `~q /\ p ==> (p ==> q) ==> r`) THEN
+    ASM_REWRITE_TAC[REAL_NOT_LE; REAL_SUB_LT] THEN
+    MATCH_MP_TAC HAS_REAL_DERIVATIVE_SUB THEN
+    CONJ_TAC THENL [ALL_TAC; REAL_DIFF_TAC THEN REWRITE_TAC[REAL_MUL_RID]] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_NE_EMPTY];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+  MATCH_MP_TAC HAS_REAL_DERIVATIVE_SUB THEN
+  CONJ_TAC THENL [ALL_TAC; REAL_DIFF_TAC THEN REWRITE_TAC[REAL_MUL_RID]] THEN
+  SUBGOAL_THEN
+   `(f has_real_derivative f' x) (atreal x within real_interval(a,b))`
+  MP_TAC THENL
+   [MATCH_MP_TAC HAS_REAL_DERIVATIVE_WITHIN_SUBSET THEN
+    EXISTS_TAC `real_interval[a,b]` THEN
+    ASM_SIMP_TAC[REAL_INTERVAL_OPEN_SUBSET_CLOSED];
+    MATCH_MP_TAC EQ_IMP THEN
+    MATCH_MP_TAC HAS_REAL_DERIVATIVE_WITHIN_REAL_OPEN THEN
+    REWRITE_TAC[REAL_OPEN_REAL_INTERVAL] THEN
+    ASM_REWRITE_TAC[REAL_OPEN_CLOSED_INTERVAL] THEN ASM SET_TAC[]]);;
+
+let REAL_DERIVATIVE_IVT_DECREASING = prove
+ (`!f f' a b t.
+   a <= b /\
+   (!x. x IN real_interval[a,b]
+        ==> (f has_real_derivative f'(x)) (atreal x within real_interval[a,b]))
+   ==> !t. f'(b) <= t /\ t <= f'(a)
+           ==> ?x. x IN real_interval[a,b] /\ f' x = t`,
+  REPEAT STRIP_TAC THEN MP_TAC(SPECL
+   [`\x. --((f:real->real) x)`; `\x. --((f':real->real) x)`;
+    `a:real`; `b:real`] REAL_DERIVATIVE_IVT_INCREASING) THEN
+  ASM_SIMP_TAC[HAS_REAL_DERIVATIVE_NEG] THEN
+  DISCH_THEN(MP_TAC o SPEC `--t:real`) THEN
+  ASM_REWRITE_TAC[REAL_LE_NEG2; REAL_EQ_NEG2]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Continuity and differentiability of inverse functions.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_REAL_DERIVATIVE_INVERSE_BASIC = prove
+ (`!f g f' t y.
+        (f has_real_derivative f') (atreal (g y)) /\
+        ~(f' = &0) /\
+        g real_continuous atreal y /\
+        real_open t /\
+        y IN t /\
+        (!z. z IN t ==> f (g z) = z)
+        ==> (g has_real_derivative inv(f')) (atreal y)`,
+  REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_AT; REAL_OPEN;
+              REAL_CONTINUOUS_CONTINUOUS_ATREAL] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_DERIVATIVE_INVERSE_BASIC THEN
+  MAP_EVERY EXISTS_TAC
+   [`lift o f o drop`; `\x:real^1. f' % x`; `IMAGE lift t`] THEN
+  ASM_REWRITE_TAC[o_THM; LIFT_DROP; LIFT_IN_IMAGE_LIFT] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; LIFT_DROP; LINEAR_COMPOSE_CMUL; LINEAR_ID] THEN
+  REWRITE_TAC[FUN_EQ_THM; I_THM; o_THM; VECTOR_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_MUL_LINV; VECTOR_MUL_LID]);;
+
+let HAS_REAL_DERIVATIVE_INVERSE_STRONG = prove
+ (`!f g f' s x.
+         real_open s /\
+         x IN s /\
+         f real_continuous_on s /\
+         (!x. x IN s ==> g (f x) = x) /\
+         (f has_real_derivative f') (atreal x) /\
+         ~(f' = &0)
+         ==> (g has_real_derivative inv(f')) (atreal (f x))`,
+  REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_AT; REAL_OPEN;
+              REAL_CONTINUOUS_ON] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `lift o f o drop` HAS_DERIVATIVE_INVERSE_STRONG) THEN
+  REWRITE_TAC[FORALL_LIFT; o_THM; LIFT_DROP] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`\x:real^1. f' % x`; `IMAGE lift s`] THEN
+  ASM_REWRITE_TAC[o_THM; LIFT_DROP; LIFT_IN_IMAGE_LIFT] THEN
+  ASM_SIMP_TAC[FUN_EQ_THM; I_THM; o_THM; VECTOR_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_MUL_RINV; VECTOR_MUL_LID]);;
+
+let HAS_REAL_DERIVATIVE_INVERSE_STRONG_X = prove
+ (`!f g f' s y.
+        real_open s /\ (g y) IN s /\ f real_continuous_on s /\
+        (!x. x IN s ==> (g(f(x)) = x)) /\
+        (f has_real_derivative f') (atreal (g y)) /\ ~(f' = &0) /\
+        f(g y) = y
+        ==> (g has_real_derivative inv(f')) (atreal y)`,
+  REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_AT; REAL_OPEN;
+              REAL_CONTINUOUS_ON] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `lift o f o drop` HAS_DERIVATIVE_INVERSE_STRONG_X) THEN
+  REWRITE_TAC[FORALL_LIFT; o_THM; LIFT_DROP] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`\x:real^1. f' % x`; `IMAGE lift s`] THEN
+  ASM_REWRITE_TAC[o_THM; LIFT_DROP; LIFT_IN_IMAGE_LIFT] THEN
+  ASM_SIMP_TAC[FUN_EQ_THM; I_THM; o_THM; VECTOR_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_MUL_RINV; VECTOR_MUL_LID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real differentiation of sequences and series.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_REAL_DERIVATIVE_SEQUENCE = prove
+ (`!s f f' g'.
+         is_realinterval s /\
+         (!n x. x IN s
+                ==> (f n has_real_derivative f' n x) (atreal x within s)) /\
+         (!e. &0 < e
+              ==> ?N. !n x. n >= N /\ x IN s ==> abs(f' n x - g' x) <= e) /\
+         (?x l. x IN s /\ ((\n. f n x) ---> l) sequentially)
+         ==> ?g. !x. x IN s
+                     ==> ((\n. f n x) ---> g x) sequentially /\
+                         (g has_real_derivative g' x) (atreal x within s)`,
+  REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_WITHIN; IS_REALINTERVAL_CONVEX;
+              TENDSTO_REAL] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`IMAGE lift s`;
+                 `\n:num. lift o f n o drop`;
+                 `\n:num x:real^1 h:real^1. f' n (drop x) % h`;
+                 `\x:real^1 h:real^1. g' (drop x) % h`]
+         HAS_DERIVATIVE_SEQUENCE) THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; LIFT_DROP] THEN ANTS_TAC THENL
+   [REWRITE_TAC[IMP_CONJ; RIGHT_EXISTS_AND_THM; RIGHT_FORALL_IMP_THM;
+                EXISTS_IN_IMAGE; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[EXISTS_LIFT; o_THM; LIFT_DROP] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[o_DEF]) THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+    REWRITE_TAC[GSYM VECTOR_SUB_RDISTRIB; NORM_MUL] THEN
+    ASM_MESON_TAC[REAL_LE_RMUL; NORM_POS_LE];
+    REWRITE_TAC[o_DEF; LIFT_DROP] THEN
+    DISCH_THEN(X_CHOOSE_TAC `g:real^1->real^1`) THEN
+    EXISTS_TAC `drop o g o lift` THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[ETA_AX]) THEN
+    ASM_REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX]]);;
+
+let HAS_REAL_DERIVATIVE_SERIES = prove
+ (`!s f f' g' k.
+         is_realinterval s /\
+         (!n x. x IN s
+                ==> (f n has_real_derivative f' n x) (atreal x within s)) /\
+         (!e. &0 < e
+              ==> ?N. !n x. n >= N /\ x IN s
+                            ==> abs(sum (k INTER (0..n)) (\i. f' i x) - g' x)
+                                    <= e) /\
+         (?x l. x IN s /\ ((\n. f n x) real_sums l) k)
+         ==> ?g. !x. x IN s
+                     ==> ((\n. f n x) real_sums g x) k /\
+                         (g has_real_derivative g' x) (atreal x within s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_sums] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  MATCH_MP_TAC HAS_REAL_DERIVATIVE_SEQUENCE THEN EXISTS_TAC
+   `\n:num x:real. sum(k INTER (0..n)) (\n. f' n x):real` THEN
+  ASM_SIMP_TAC[ETA_AX; FINITE_INTER_NUMSEG; HAS_REAL_DERIVATIVE_SUM]);;
+
+let REAL_DIFFERENTIABLE_BOUND = prove
+ (`!f f' s B.
+        is_realinterval s /\
+        (!x. x IN s ==> (f has_real_derivative f'(x)) (atreal x within s) /\
+                        abs(f' x) <= B)
+        ==> !x y. x IN s /\ y IN s ==> abs(f x - f y) <= B * abs(x - y)`,
+  REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_WITHIN; IS_REALINTERVAL_CONVEX;
+              o_DEF] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`lift o f o drop`; `\x h:real^1. f' (drop x) % h`;
+    `IMAGE lift s`; `B:real`]
+        DIFFERENTIABLE_BOUND) THEN
+  ASM_SIMP_TAC[o_DEF; FORALL_IN_IMAGE; LIFT_DROP] THEN ANTS_TAC THENL
+   [X_GEN_TAC `v:real` THEN DISCH_TAC THEN
+    MP_TAC(ISPEC `\h:real^1. f' (v:real) % h` ONORM) THEN
+    SIMP_TAC[LINEAR_COMPOSE_CMUL; LINEAR_ID] THEN
+    DISCH_THEN(MATCH_MP_TAC o CONJUNCT2) THEN
+    ASM_SIMP_TAC[NORM_MUL; REAL_LE_RMUL; NORM_POS_LE];
+    SIMP_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE; LIFT_DROP] THEN
+    ASM_SIMP_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; GSYM LIFT_SUB; NORM_LIFT]]);;
+
+let REAL_TAYLOR_MVT_POS = prove
+ (`!f a x n.
+    a < x /\
+    (!i t. t IN real_interval[a,x] /\ i <= n
+           ==> ((f i) has_real_derivative f (i + 1) t)
+               (atreal t within real_interval[a,x]))
+    ==> ?t. t IN real_interval(a,x) /\
+            f 0 x =
+              sum (0..n) (\i. f i a * (x - a) pow i / &(FACT i)) +
+              f (n + 1) t * (x - a) pow (n + 1) / &(FACT(n + 1))`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?B. sum (0..n) (\i. f i a * (x - a) pow i / &(FACT i)) +
+        B * (x - a) pow (n + 1) = f 0 x`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC(MESON[]
+     `a + (y - a) / x * x:real = y ==> ?b. a + b * x = y`) THEN
+    MATCH_MP_TAC(REAL_FIELD `~(x = &0) ==> a + (y - a) / x * x = y`) THEN
+    ASM_REWRITE_TAC[REAL_POW_EQ_0; REAL_SUB_0] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(SPECL [`\t. sum(0..n) (\i. f i t * (x - t) pow i / &(FACT i)) +
+                     B * (x - t) pow (n + 1)`;
+                `\t. (f (n + 1) t * (x - t) pow n / &(FACT n)) -
+                     B * &(n + 1) * (x - t) pow n`;
+                `a:real`; `x:real`]
+        REAL_ROLLE_SIMPLE) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [SIMP_TAC[SUM_CLAUSES_LEFT; LE_0] THEN
+      REWRITE_TAC[GSYM ADD1; real_pow; REAL_SUB_REFL; REAL_POW_ZERO;
+                  REAL_MUL_LZERO; REAL_MUL_RZERO; REAL_ADD_RID] THEN
+      CONV_TAC NUM_REDUCE_CONV THEN
+      REWRITE_TAC[NOT_SUC; REAL_MUL_RZERO; REAL_DIV_1; REAL_MUL_RID] THEN
+      REWRITE_TAC[REAL_ARITH `x = (x + y) + &0 <=> y = &0`] THEN
+      MATCH_MP_TAC SUM_EQ_0_NUMSEG THEN
+      SIMP_TAC[ARITH; ARITH_RULE `1 <= i ==> ~(i = 0)`] THEN
+      REWRITE_TAC[real_div; REAL_MUL_LZERO; REAL_MUL_RZERO];
+      ALL_TAC] THEN
+    X_GEN_TAC `t:real` THEN DISCH_TAC THEN REWRITE_TAC[real_sub] THEN
+    MATCH_MP_TAC HAS_REAL_DERIVATIVE_ADD THEN CONJ_TAC THENL
+     [ALL_TAC;
+      REAL_DIFF_TAC THEN REWRITE_TAC[ADD_SUB] THEN CONV_TAC REAL_RING] THEN
+    REWRITE_TAC[GSYM real_sub] THEN
+    MATCH_MP_TAC(MESON[]
+     `!g'. f' = g' /\ (f has_real_derivative g') net
+           ==> (f has_real_derivative f') net`) THEN
+    EXISTS_TAC
+     `sum (0..n) (\i. f i t * --(&i * (x - t) pow (i - 1)) / &(FACT i) +
+                                f (i + 1) t * (x - t) pow i / &(FACT i))` THEN
+    REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC HAS_REAL_DERIVATIVE_SUM THEN
+      REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+      X_GEN_TAC `m:num` THEN STRIP_TAC THEN
+      MATCH_MP_TAC HAS_REAL_DERIVATIVE_MUL_WITHIN THEN
+      ASM_SIMP_TAC[ETA_AX] THEN REAL_DIFF_TAC THEN REAL_ARITH_TAC] THEN
+    SIMP_TAC[SUM_CLAUSES_LEFT; LE_0; ARITH; FACT; REAL_DIV_1;
+             real_pow; REAL_MUL_LZERO; REAL_NEG_0; REAL_MUL_RZERO;
+             REAL_MUL_RID; REAL_ADD_LID] THEN
+    ASM_CASES_TAC `n = 0` THENL
+     [ASM_REWRITE_TAC[SUM_CLAUSES_NUMSEG; ARITH; FACT] THEN REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[SPECL [`f:num->real`; `1`] SUM_OFFSET_0; LE_1] THEN
+    REWRITE_TAC[ADD_SUB] THEN
+    REWRITE_TAC[GSYM ADD1; FACT; GSYM REAL_OF_NUM_MUL; GSYM REAL_OF_NUM_ADD;
+                GSYM REAL_OF_NUM_SUC] THEN
+    REWRITE_TAC[real_div; REAL_INV_MUL] THEN
+    REWRITE_TAC[REAL_ARITH `--(n * x) * (inv n * inv y):real =
+                            --(n / n) * x / y`] THEN
+    REWRITE_TAC[REAL_FIELD `--((&n + &1) / (&n + &1)) * x = --x`] THEN
+    REWRITE_TAC[GSYM REAL_INV_MUL; REAL_OF_NUM_MUL; REAL_OF_NUM_SUC] THEN
+    REWRITE_TAC[GSYM(CONJUNCT2 FACT)] THEN
+    REWRITE_TAC[REAL_ARITH `a * --b + c:real = c - a * b`] THEN
+    REWRITE_TAC[ADD1; GSYM real_div; SUM_DIFFS_ALT; LE_0] THEN
+    ASM_SIMP_TAC[ARITH_RULE `~(n = 0) ==> n - 1 + 1 = n`; FACT] THEN
+    REWRITE_TAC[ADD_CLAUSES] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [GSYM th]) THEN
+  REWRITE_TAC[REAL_EQ_ADD_LCANCEL] THEN
+  REWRITE_TAC[REAL_ARITH `a * b / c:real = a / c * b`] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP (REAL_ARITH
+   `a * x / f - B * k * x = &0 ==> (B * k - a / f) * x = &0`)) THEN
+  REWRITE_TAC[REAL_ENTIRE; REAL_POW_EQ_0; REAL_SUB_0] THEN
+  ASM_CASES_TAC `x:real = t` THENL
+   [ASM_MESON_TAC[IN_REAL_INTERVAL; REAL_LT_REFL]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[GSYM ADD1; FACT] THEN
+  REWRITE_TAC[GSYM REAL_OF_NUM_MUL; GSYM REAL_OF_NUM_ADD; ADD1] THEN
+  SUBGOAL_THEN `~(&(FACT n) = &0)` MP_TAC THENL
+   [REWRITE_TAC[REAL_OF_NUM_EQ; FACT_NZ]; CONV_TAC REAL_FIELD]);;
+
+let REAL_TAYLOR_MVT_NEG = prove
+ (`!f a x n.
+    x < a /\
+    (!i t. t IN real_interval[x,a] /\ i <= n
+           ==> ((f i) has_real_derivative f (i + 1) t)
+               (atreal t within real_interval[x,a]))
+    ==> ?t. t IN real_interval(x,a) /\
+            f 0 x =
+              sum (0..n) (\i. f i a * (x - a) pow i / &(FACT i)) +
+              f (n + 1) t * (x - a) pow (n + 1) / &(FACT(n + 1))`,
+  REWRITE_TAC[IN_REAL_INTERVAL] THEN REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[MESON[REAL_NEG_NEG] `(?x:real. P x) <=> (?x. P(--x))`] THEN
+  MP_TAC(SPECL [`\n x. (-- &1) pow n * (f:num->real->real) n (--x)`;
+                `--a:real`; `  --x:real`; `n:num`]
+        REAL_TAYLOR_MVT_POS) THEN
+  REWRITE_TAC[REAL_NEG_NEG] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `(x * y) * z / w:real = y * (x * z) / w`] THEN
+  REWRITE_TAC[GSYM REAL_POW_MUL] THEN
+  REWRITE_TAC[REAL_ARITH `-- &1 * (--x - --a) = x - a`] THEN
+  REWRITE_TAC[IN_REAL_INTERVAL; real_pow; REAL_MUL_LID] THEN
+  REWRITE_TAC[REAL_ARITH `--a < t /\ t < --x <=> x < --t /\ --t < a`] THEN
+  DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[REAL_LT_NEG2] THEN
+  MAP_EVERY X_GEN_TAC [`m:num`; `t:real`] THEN STRIP_TAC THEN
+  REWRITE_TAC[REAL_POW_ADD; GSYM REAL_MUL_ASSOC] THEN
+  MATCH_MP_TAC HAS_REAL_DERIVATIVE_LMUL_WITHIN THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `y pow 1 * x:real = x * y`] THEN
+  ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+  MATCH_MP_TAC REAL_DIFF_CHAIN_WITHIN THEN CONJ_TAC THENL
+   [GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+    REAL_DIFF_TAC THEN REFL_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `IMAGE (--) (real_interval[--a,--x]) = real_interval[x,a]`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_IMAGE; IN_REAL_INTERVAL] THEN
+    REWRITE_TAC[REAL_ARITH `x:real = --y <=> --x = y`; UNWIND_THM1] THEN
+    REAL_ARITH_TAC;
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC]);;
+
+let REAL_TAYLOR = prove
+ (`!f n s B.
+    is_realinterval s /\
+    (!i x. x IN s /\ i <= n
+           ==> ((f i) has_real_derivative f (i + 1) x) (atreal x within s)) /\
+    (!x. x IN s ==> abs(f (n + 1) x) <= B)
+    ==> !w z. w IN s /\ z IN s
+              ==> abs(f 0 z -
+                      sum (0..n) (\i. f i w * (z - w) pow i / &(FACT i)))
+                  <= B * abs(z - w) pow (n + 1) / &(FACT(n + 1))`,
+  REPEAT STRIP_TAC THEN
+  REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
+   (REAL_ARITH `w = z \/ w < z \/ z < w`)
+  THENL
+   [ASM_SIMP_TAC[SUM_CLAUSES_LEFT; LE_0; REAL_SUB_REFL; REAL_POW_ZERO;
+                 REAL_ABS_0; ARITH; ADD_EQ_0; real_div] THEN
+    REWRITE_TAC[REAL_MUL_LZERO; FACT; REAL_INV_1; REAL_MUL_RZERO] THEN
+    MATCH_MP_TAC(REAL_ARITH `y = &0 ==> abs(x - (x * &1 * &1 + y)) <= &0`) THEN
+    MATCH_MP_TAC SUM_EQ_0_NUMSEG THEN
+    SIMP_TAC[ARITH; LE_1; REAL_MUL_RZERO; REAL_MUL_LZERO];
+    MP_TAC(ISPECL [`f:num->real->real`; `w:real`; `z:real`; `n:num`]
+                  REAL_TAYLOR_MVT_POS) THEN
+    ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `real_interval[w,z] SUBSET s` ASSUME_TAC THENL
+     [SIMP_TAC[SUBSET; IN_REAL_INTERVAL] THEN ASM_MESON_TAC[is_realinterval];
+      ALL_TAC];
+    MP_TAC(ISPECL [`f:num->real->real`; `w:real`; `z:real`; `n:num`]
+                  REAL_TAYLOR_MVT_NEG) THEN
+    ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `real_interval[z,w] SUBSET s` ASSUME_TAC THENL
+     [SIMP_TAC[SUBSET; IN_REAL_INTERVAL] THEN ASM_MESON_TAC[is_realinterval];
+      ALL_TAC]] THEN
+ (ANTS_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`m:num`; `t:real`] THEN STRIP_TAC THEN
+    MATCH_MP_TAC HAS_REAL_DERIVATIVE_WITHIN_SUBSET THEN
+    EXISTS_TAC `s:real->bool` THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[SUBSET];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real`
+   (CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC)) THEN
+  REWRITE_TAC[REAL_ADD_SUB; REAL_ABS_MUL; REAL_ABS_DIV] THEN
+  REWRITE_TAC[REAL_ABS_POW; REAL_ABS_NUM] THEN
+  MATCH_MP_TAC REAL_LE_RMUL THEN
+  SIMP_TAC[REAL_LE_DIV; REAL_POS; REAL_POW_LE; REAL_ABS_POS] THEN
+  ASM_MESON_TAC[REAL_INTERVAL_OPEN_SUBSET_CLOSED; SUBSET]));;
+
+(* ------------------------------------------------------------------------- *)
+(* Comparing sums and "integrals" via real antiderivatives.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_SUM_INTEGRAL_UBOUND_INCREASING = prove
+ (`!f g m n.
+      m <= n /\
+      (!x. x IN real_interval[&m,&n + &1]
+           ==> (g has_real_derivative f(x))
+               (atreal x within real_interval[&m,&n + &1])) /\
+      (!x y. &m <= x /\ x <= y /\ y <= &n + &1 ==> f x <= f y)
+      ==> sum(m..n) (\k. f(&k)) <= g(&n + &1) - g(&m)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum(m..n) (\k. g(&(k + 1)) - g(&k))` THEN CONJ_TAC THENL
+   [ALL_TAC; ASM_SIMP_TAC[SUM_DIFFS_ALT; REAL_OF_NUM_ADD; REAL_LE_REFL]] THEN
+  MATCH_MP_TAC SUM_LE_NUMSEG THEN X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`g:real->real`; `f:real->real`; `&k`; `&(k + 1)`]
+                REAL_MVT_SIMPLE) THEN
+  ASM_REWRITE_TAC[REAL_OF_NUM_LT; ARITH_RULE `k < k + 1`] THEN
+  ASM_REWRITE_TAC[GSYM REAL_OF_NUM_ADD; REAL_ADD_SUB] THEN ANTS_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_DERIVATIVE_WITHIN_SUBSET THEN
+    EXISTS_TAC `real_interval[&m,&n + &1]` THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM MATCH_MP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_REAL_INTERVAL]);
+      REWRITE_TAC[SUBSET] THEN GEN_TAC] THEN
+    REWRITE_TAC[IN_REAL_INTERVAL] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM REAL_OF_NUM_LE]) THEN ASM_REAL_ARITH_TAC;
+    DISCH_THEN(X_CHOOSE_THEN `t:real`
+     (CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC)) THEN
+    REWRITE_TAC[REAL_MUL_RID] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_REAL_INTERVAL]) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM REAL_OF_NUM_LE]) THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let REAL_SUM_INTEGRAL_UBOUND_DECREASING = prove
+ (`!f g m n.
+      m <= n /\
+      (!x. x IN real_interval[&m - &1,&n]
+           ==> (g has_real_derivative f(x))
+               (atreal x within real_interval[&m - &1,&n])) /\
+      (!x y. &m - &1 <= x /\ x <= y /\ y <= &n ==> f y <= f x)
+      ==> sum(m..n) (\k. f(&k)) <= g(&n) - g(&m - &1)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum(m..n) (\k. g(&(k + 1) - &1) - g(&k - &1))` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_REWRITE_TAC[SUM_DIFFS_ALT] THEN
+    ASM_REWRITE_TAC[GSYM REAL_OF_NUM_ADD; REAL_ARITH `(x + &1) - &1 = x`] THEN
+    REWRITE_TAC[REAL_LE_REFL]] THEN
+  MATCH_MP_TAC SUM_LE_NUMSEG THEN X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`g:real->real`; `f:real->real`; `&k - &1`; `&k`]
+                REAL_MVT_SIMPLE) THEN
+  ASM_REWRITE_TAC[REAL_ARITH `k - &1 < k`] THEN ANTS_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_DERIVATIVE_WITHIN_SUBSET THEN
+    EXISTS_TAC `real_interval[&m - &1,&n]` THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM MATCH_MP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_REAL_INTERVAL]);
+      REWRITE_TAC[SUBSET] THEN GEN_TAC] THEN
+    REWRITE_TAC[IN_REAL_INTERVAL] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM REAL_OF_NUM_LE]) THEN ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[GSYM REAL_OF_NUM_ADD; REAL_ARITH `(a + &1) - &1 = a`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `t:real`
+     (CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC)) THEN
+    REWRITE_TAC[REAL_ARITH `a * (x - (x - &1)) = a`] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_REAL_INTERVAL]) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM REAL_OF_NUM_LE]) THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let REAL_SUM_INTEGRAL_LBOUND_INCREASING = prove
+ (`!f g m n.
+      m <= n /\
+      (!x. x IN real_interval[&m - &1,&n]
+           ==> (g has_real_derivative f(x))
+               (atreal x within real_interval[&m - &1,&n])) /\
+      (!x y. &m - &1 <= x /\ x <= y /\ y <= &n ==> f x <= f y)
+      ==> g(&n) - g(&m - &1) <= sum(m..n) (\k. f(&k))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\z. --((f:real->real) z)`;
+                 `\z. --((g:real->real) z)`;
+                 `m:num`; `n:num`] REAL_SUM_INTEGRAL_UBOUND_DECREASING) THEN
+  REWRITE_TAC[RE_NEG; RE_SUB; SUM_NEG; REAL_LE_NEG2;
+              REAL_ARITH `--x - --y:real = --(x - y)`] THEN
+  ASM_SIMP_TAC[HAS_REAL_DERIVATIVE_NEG]);;
+
+let REAL_SUM_INTEGRAL_LBOUND_DECREASING = prove
+ (`!f g m n.
+      m <= n /\
+      (!x. x IN real_interval[&m,&n + &1]
+           ==> (g has_real_derivative f(x))
+               (atreal x within  real_interval[&m,&n + &1])) /\
+      (!x y. &m <= x /\ x <= y /\ y <= &n + &1 ==> f y <= f x)
+      ==> g(&n + &1) - g(&m) <= sum(m..n) (\k. f(&k))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\z. --((f:real->real) z)`;
+                 `\z. --((g:real->real) z)`;
+                 `m:num`; `n:num`] REAL_SUM_INTEGRAL_UBOUND_INCREASING) THEN
+  REWRITE_TAC[RE_NEG; RE_SUB; SUM_NEG; REAL_LE_NEG2;
+              REAL_ARITH `--x - --y:real = --(x - y)`] THEN
+  ASM_SIMP_TAC[HAS_REAL_DERIVATIVE_NEG]);;
+
+let REAL_SUM_INTEGRAL_BOUNDS_INCREASING = prove
+ (`!f g m n.
+         m <= n /\
+         (!x. x IN real_interval[&m - &1,&n + &1]
+              ==> (g has_real_derivative f x)
+                  (atreal x within real_interval[&m - &1,&n + &1])) /\
+         (!x y. &m - &1 <= x /\ x <= y /\ y <= &n + &1 ==> f x <= f y)
+         ==> g(&n) - g(&m - &1) <= sum(m..n) (\k. f(&k)) /\
+             sum (m..n) (\k. f(&k)) <= g(&n + &1) - g(&m)`,
+  REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC REAL_SUM_INTEGRAL_LBOUND_INCREASING;
+    MATCH_MP_TAC REAL_SUM_INTEGRAL_UBOUND_INCREASING] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  TRY(MATCH_MP_TAC HAS_REAL_DERIVATIVE_WITHIN_SUBSET THEN
+      EXISTS_TAC `real_interval[&m - &1,&n + &1]` THEN CONJ_TAC) THEN
+  TRY(FIRST_X_ASSUM MATCH_MP_TAC) THEN
+  TRY(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_REAL_INTERVAL])) THEN
+  REWRITE_TAC[SUBSET; IN_REAL_INTERVAL] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM REAL_OF_NUM_LE]) THEN ASM_REAL_ARITH_TAC);;
+
+let REAL_SUM_INTEGRAL_BOUNDS_DECREASING = prove
+ (`!f g m n.
+      m <= n /\
+      (!x. x IN real_interval[&m - &1,&n + &1]
+           ==> (g has_real_derivative f(x))
+               (atreal x within real_interval[&m - &1,&n + &1])) /\
+      (!x y. &m - &1 <= x /\ x <= y /\ y <= &n + &1 ==> f y <= f x)
+      ==> g(&n + &1) - g(&m) <= sum(m..n) (\k. f(&k)) /\
+          sum(m..n) (\k. f(&k)) <= g(&n) - g(&m - &1)`,
+  REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC REAL_SUM_INTEGRAL_LBOUND_DECREASING;
+    MATCH_MP_TAC REAL_SUM_INTEGRAL_UBOUND_DECREASING] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  TRY(MATCH_MP_TAC HAS_REAL_DERIVATIVE_WITHIN_SUBSET THEN
+      EXISTS_TAC `real_interval[&m - &1,&n + &1]` THEN CONJ_TAC) THEN
+  TRY(FIRST_X_ASSUM MATCH_MP_TAC) THEN
+  TRY(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_REAL_INTERVAL])) THEN
+  REWRITE_TAC[SUBSET; IN_REAL_INTERVAL] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM REAL_OF_NUM_LE]) THEN ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relating different kinds of real limits.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_POSINFINITY_SEQUENTIALLY = prove
+ (`!f l. (f --> l) at_posinfinity ==> ((\n. f(&n)) --> l) sequentially`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[LIM_AT_POSINFINITY; LIM_SEQUENTIALLY] 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_TAC `B:real`) THEN
+  MP_TAC(ISPEC `B:real` REAL_ARCH_SIMPLE) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM REAL_OF_NUM_LE]) THEN ASM_REAL_ARITH_TAC);;
+
+let REALLIM_POSINFINITY_SEQUENTIALLY = prove
+ (`!f l. (f ---> l) at_posinfinity ==> ((\n. f(&n)) ---> l) sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[TENDSTO_REAL] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LIM_POSINFINITY_SEQUENTIALLY) THEN
+  REWRITE_TAC[o_DEF]);;
+
+let LIM_ZERO_POSINFINITY = prove
+ (`!f l. ((\x. f(&1 / x)) --> l) (atreal (&0)) ==> (f --> l) at_posinfinity`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[LIM_ATREAL; LIM_AT_POSINFINITY] 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
+  REWRITE_TAC[dist; REAL_SUB_RZERO; real_ge] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `&2 / d` THEN X_GEN_TAC `z:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `inv(z):real`) THEN
+  REWRITE_TAC[real_div; REAL_MUL_LINV; REAL_INV_INV] THEN
+  REWRITE_TAC[REAL_MUL_LID] THEN DISCH_THEN MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[REAL_ABS_INV; REAL_LT_INV_EQ] THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `a <= z ==> &0 < a ==> &0 < abs z`));
+    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_INV_INV] THEN
+    MATCH_MP_TAC REAL_LT_INV2 THEN ASM_REWRITE_TAC[REAL_LT_INV_EQ] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `&2 / d <= z ==> &0 < &2 / d ==> inv d < abs z`))] THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH]);;
+
+let LIM_ZERO_NEGINFINITY = prove
+ (`!f l. ((\x. f(&1 / x)) --> l) (atreal (&0)) ==> (f --> l) at_neginfinity`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[LIM_ATREAL; LIM_AT_NEGINFINITY] 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
+  REWRITE_TAC[dist; REAL_SUB_RZERO; real_ge] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `--(&2 / d)` THEN X_GEN_TAC `z:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `inv(z):real`) THEN
+  REWRITE_TAC[real_div; REAL_MUL_LINV; REAL_INV_INV] THEN
+  REWRITE_TAC[REAL_MUL_LID] THEN DISCH_THEN MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[REAL_ABS_INV; REAL_LT_INV_EQ] THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `z <= --a ==> &0 < a ==> &0 < abs z`));
+    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_INV_INV] THEN
+    MATCH_MP_TAC REAL_LT_INV2 THEN ASM_REWRITE_TAC[REAL_LT_INV_EQ] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `z <= --(&2 / d) ==> &0 < &2 / d ==> inv d < abs z`))] THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH]);;
+
+let REALLIM_ZERO_POSINFINITY = prove
+ (`!f l. ((\x. f(&1 / x)) ---> l) (atreal (&0)) ==> (f ---> l) at_posinfinity`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF; LIM_ZERO_POSINFINITY]);;
+
+let REALLIM_ZERO_NEGINFINITY = prove
+ (`!f l. ((\x. f(&1 / x)) ---> l) (atreal (&0)) ==> (f ---> l) at_neginfinity`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF; LIM_ZERO_NEGINFINITY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real segments (bidirectional intervals).                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let closed_real_segment = define
+ `closed_real_segment[a,b] = {(&1 - u) * a + u * b | &0 <= u /\ u <= &1}`;;
+
+let open_real_segment = new_definition
+ `open_real_segment(a,b) = closed_real_segment[a,b] DIFF {a,b}`;;
+
+make_overloadable "real_segment" `:A`;;
+
+overload_interface("real_segment",`open_real_segment`);;
+overload_interface("real_segment",`closed_real_segment`);;
+
+let real_segment = prove
+ (`real_segment[a,b] = {(&1 - u) * a + u * b | &0 <= u /\ u <= &1} /\
+   real_segment(a,b) = real_segment[a,b] DIFF {a,b}`,
+  REWRITE_TAC[open_real_segment; closed_real_segment]);;
+
+let REAL_SEGMENT_SEGMENT = prove
+ (`(!a b. real_segment[a,b] = IMAGE drop (segment[lift a,lift b])) /\
+   (!a b. real_segment(a,b) = IMAGE drop (segment(lift a,lift b)))`,
+  REWRITE_TAC[segment; real_segment] THEN
+  SIMP_TAC[IMAGE_DIFF_INJ; DROP_EQ; IMAGE_CLAUSES; LIFT_DROP] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; DROP_ADD; DROP_CMUL; LIFT_DROP]);;
+
+let SEGMENT_REAL_SEGMENT = prove
+ (`(!a b. segment[a,b] = IMAGE lift (real_segment[drop a,drop b])) /\
+   (!a b. segment(a,b) = IMAGE lift (real_segment(drop a,drop b)))`,
+  REWRITE_TAC[REAL_SEGMENT_SEGMENT; GSYM IMAGE_o] THEN
+  REWRITE_TAC[o_DEF; IMAGE_ID; LIFT_DROP]);;
+
+let IMAGE_LIFT_REAL_SEGMENT = prove
+ (`(!a b. IMAGE lift (real_segment[a,b]) = segment[lift a,lift b]) /\
+   (!a b. IMAGE lift (real_segment(a,b)) = segment(lift a,lift b))`,
+  REWRITE_TAC[SEGMENT_REAL_SEGMENT; LIFT_DROP]);;
+
+let REAL_SEGMENT_INTERVAL = prove
+ (`(!a b. real_segment[a,b] =
+          if a <= b then real_interval[a,b] else real_interval[b,a]) /\
+   (!a b. real_segment(a,b) =
+          if a <= b then real_interval(a,b) else real_interval(b,a))`,
+  REWRITE_TAC[REAL_SEGMENT_SEGMENT; SEGMENT_1; LIFT_DROP] THEN
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL] THEN
+  CONJ_TAC THEN REPEAT GEN_TAC THEN COND_CASES_TAC THEN REWRITE_TAC[]);;
+
+let REAL_CONTINUOUS_INJECTIVE_IFF_MONOTONIC = prove
+ (`!f s.
+        f real_continuous_on s /\ is_realinterval s
+        ==> ((!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) <=>
+             (!x y. x IN s /\ y IN s /\ x < y ==> f x < f y) \/
+             (!x y. x IN s /\ y IN s /\ x < y ==> f y < f x))`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[REAL_CONTINUOUS_ON; IS_REALINTERVAL_IS_INTERVAL] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CONTINUOUS_INJECTIVE_IFF_MONOTONIC) THEN
+  REWRITE_TAC[FORALL_LIFT; LIFT_IN_IMAGE_LIFT; o_THM; LIFT_DROP; LIFT_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Convex real->real functions.                                              *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix ("real_convex_on",(12,"right"));;
+
+let real_convex_on = new_definition
+  `(f:real->real) real_convex_on s <=>
+        !x y u v. x IN s /\ y IN s /\ &0 <= u /\ &0 <= v /\ (u + v = &1)
+                  ==> f(u * x + v * y) <= u * f(x) + v * f(y)`;;
+
+let REAL_CONVEX_ON = prove
+ (`!f s. f real_convex_on s <=> (f o drop) convex_on (IMAGE lift s)`,
+  REWRITE_TAC[real_convex_on; convex_on] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[o_THM; LIFT_DROP; DROP_ADD; DROP_CMUL]);;
+
+let REAL_CONVEX_ON_SUBSET = prove
+ (`!f s t. f real_convex_on t /\ s SUBSET t ==> f real_convex_on s`,
+  REWRITE_TAC[REAL_CONVEX_ON] THEN
+  MESON_TAC[CONVEX_ON_SUBSET; IMAGE_SUBSET]);;
+
+let REAL_CONVEX_ADD = prove
+ (`!s f g. f real_convex_on s /\ g real_convex_on s
+           ==> (\x. f(x) + g(x)) real_convex_on s`,
+  REWRITE_TAC[REAL_CONVEX_ON; o_DEF; CONVEX_ADD]);;
+
+let REAL_CONVEX_LMUL = prove
+ (`!s c f. &0 <= c /\ f real_convex_on s ==> (\x. c * f(x)) real_convex_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_CONVEX_ON; o_DEF] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CONVEX_CMUL) THEN REWRITE_TAC[]);;
+
+let REAL_CONVEX_RMUL = prove
+ (`!s c f. &0 <= c /\ f real_convex_on s ==> (\x. f(x) * c) real_convex_on s`,
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[REAL_CONVEX_LMUL]);;
+
+let REAL_CONVEX_LOWER = prove
+ (`!f s x y. f real_convex_on s /\
+             x IN s /\ y IN s /\ &0 <= u /\ &0 <= v /\ u + v = &1
+             ==> f(u * x + v * y) <= max (f(x)) (f(y))`,
+  REWRITE_TAC[REAL_CONVEX_ON] THEN
+  REWRITE_TAC[FORALL_DROP; GSYM IN_IMAGE_LIFT_DROP] THEN
+  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP CONVEX_LOWER) THEN
+  REWRITE_TAC[o_THM; DROP_ADD; DROP_CMUL]);;
+
+let REAL_CONVEX_LOCAL_GLOBAL_MINIMUM = prove
+ (`!f s t x.
+       f real_convex_on s /\ x IN t /\ real_open t /\ t SUBSET s /\
+       (!y. y IN t ==> f(x) <= f(y))
+       ==> !y. y IN s ==> f(x) <= f(y)`,
+  REWRITE_TAC[REAL_CONVEX_ON; REAL_OPEN] THEN
+  REWRITE_TAC[FORALL_DROP; GSYM IN_IMAGE_LIFT_DROP] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; LIFT_DROP] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`(f:real->real) o drop`; `IMAGE lift s`;
+                 `IMAGE lift t`; `x:real^1`] CONVEX_LOCAL_GLOBAL_MINIMUM) THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; LIFT_DROP; o_THM; IMAGE_SUBSET]);;
+
+let REAL_CONVEX_DISTANCE = prove
+ (`!s a. (\x. abs(a - x)) real_convex_on s`,
+  REWRITE_TAC[REAL_CONVEX_ON; o_DEF; FORALL_DROP; GSYM DROP_SUB] THEN
+  REWRITE_TAC[drop; GSYM NORM_REAL; GSYM dist; CONVEX_DISTANCE]);;
+
+let REAL_CONVEX_ON_JENSEN = prove
+ (`!f s. is_realinterval s
+         ==> (f real_convex_on s <=>
+                !k u x.
+                   (!i:num. 1 <= i /\ i <= k ==> &0 <= u(i) /\ x(i) IN s) /\
+                   (sum (1..k) u = &1)
+                   ==> f(sum (1..k) (\i. u(i) * x(i)))
+                           <= sum (1..k) (\i. u(i) * f(x(i))))`,
+  REWRITE_TAC[IS_REALINTERVAL_CONVEX; REAL_CONVEX_ON] THEN
+  SIMP_TAC[CONVEX_ON_JENSEN] THEN REPEAT STRIP_TAC THEN
+  SIMP_TAC[o_DEF; DROP_VSUM; FINITE_NUMSEG] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `k:num` THEN REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+  X_GEN_TAC `u:num->real` THEN REWRITE_TAC[] THEN EQ_TAC THEN DISCH_TAC THENL
+   [X_GEN_TAC `x:num->real` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `lift o (x:num->real)`) THEN
+    ASM_REWRITE_TAC[o_DEF; LIFT_DROP; IN_IMAGE_LIFT_DROP] THEN
+    REWRITE_TAC[DROP_CMUL; LIFT_DROP];
+    X_GEN_TAC `x:num->real^1` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `drop o (x:num->real^1)`) THEN
+    ASM_REWRITE_TAC[o_DEF; LIFT_DROP; IN_IMAGE_LIFT_DROP] THEN
+    ASM_REWRITE_TAC[DROP_CMUL; LIFT_DROP; GSYM IN_IMAGE_LIFT_DROP]]);;
+
+let REAL_CONVEX_ON_CONTINUOUS = prove
+ (`!f s. real_open s /\ f real_convex_on s ==> f real_continuous_on s`,
+  REWRITE_TAC[REAL_CONVEX_ON; REAL_OPEN; REAL_CONTINUOUS_ON] THEN
+  REWRITE_TAC[CONVEX_ON_CONTINUOUS]);;
+
+let REAL_CONVEX_ON_LEFT_SECANT_MUL = prove
+ (`!f s. f real_convex_on s <=>
+          !a b x. a IN s /\ b IN s /\ x IN real_segment[a,b]
+                  ==> (f x - f a) * abs(b - a) <= (f b - f a) * abs(x - a)`,
+  REWRITE_TAC[REAL_CONVEX_ON; CONVEX_ON_LEFT_SECANT_MUL] THEN
+  REWRITE_TAC[REAL_SEGMENT_SEGMENT] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP] THEN
+  REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB; LIFT_DROP]);;
+
+let REAL_CONVEX_ON_RIGHT_SEQUENT_MUL = prove
+ (`!f s. f real_convex_on s <=>
+          !a b x. a IN s /\ b IN s /\ x IN real_segment[a,b]
+                  ==> (f b - f a) * abs(b - x) <= (f b - f x) * abs(b - a)`,
+  REWRITE_TAC[REAL_CONVEX_ON; CONVEX_ON_RIGHT_SECANT_MUL] THEN
+  REWRITE_TAC[REAL_SEGMENT_SEGMENT] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP] THEN
+  REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB; LIFT_DROP]);;
+
+let REAL_CONVEX_ON_LEFT_SECANT = prove
+ (`!f s.
+      f real_convex_on s <=>
+        !a b x. a IN s /\ b IN s /\ x IN real_segment(a,b)
+                ==> (f x - f a) / abs(x - a) <= (f b - f a) / abs(b - a)`,
+  REWRITE_TAC[REAL_CONVEX_ON; CONVEX_ON_LEFT_SECANT] THEN
+  REWRITE_TAC[REAL_SEGMENT_SEGMENT] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP] THEN
+  REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB; LIFT_DROP]);;
+
+let REAL_CONVEX_ON_RIGHT_SEQUENT = prove
+ (`!f s.
+      f real_convex_on s <=>
+        !a b x. a IN s /\ b IN s /\ x IN real_segment(a,b)
+                ==> (f b - f a) / abs(b - a) <= (f b - f x) / abs(b - x)`,
+  REWRITE_TAC[REAL_CONVEX_ON; CONVEX_ON_RIGHT_SECANT] THEN
+  REWRITE_TAC[REAL_SEGMENT_SEGMENT] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP] THEN
+  REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB; LIFT_DROP]);;
+
+let REAL_CONVEX_ON_DERIVATIVE_SECANT_IMP = prove
+ (`!f f' s x y.
+        f real_convex_on s /\ real_segment[x,y] SUBSET s /\
+        (f has_real_derivative f') (atreal x within s)
+        ==> f' * (y - x) <= f y - f x`,
+  REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_WITHIN;
+              REAL_CONVEX_ON; REAL_SEGMENT_SEGMENT] THEN
+  REWRITE_TAC[SUBSET; IN_IMAGE_LIFT_DROP] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[FORALL_DROP] THEN
+  REWRITE_TAC[LIFT_DROP] THEN
+  REWRITE_TAC[GSYM IN_IMAGE_LIFT_DROP; GSYM SUBSET] THEN
+  ONCE_REWRITE_TAC[GSYM(REWRITE_CONV[LIFT_DROP]
+        `\x. lift(drop(f % x))`)] THEN
+  REWRITE_TAC[GSYM o_DEF] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CONVEX_ON_DERIVATIVE_SECANT_IMP) THEN
+  REWRITE_TAC[o_THM; DROP_CMUL; DROP_SUB; LIFT_DROP]);;
+
+let REAL_CONVEX_ON_SECANT_DERIVATIVE_IMP = prove
+ (`!f f' s x y.
+        f real_convex_on s /\ real_segment[x,y] SUBSET s /\
+        (f has_real_derivative f') (atreal y within s)
+        ==> f y - f x <= f' * (y - x)`,
+  REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_WITHIN;
+              REAL_CONVEX_ON; REAL_SEGMENT_SEGMENT] THEN
+  REWRITE_TAC[SUBSET; IN_IMAGE_LIFT_DROP] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[FORALL_DROP] THEN
+  REWRITE_TAC[LIFT_DROP] THEN
+  REWRITE_TAC[GSYM IN_IMAGE_LIFT_DROP; GSYM SUBSET] THEN
+  ONCE_REWRITE_TAC[GSYM(REWRITE_CONV[LIFT_DROP]
+        `\x. lift(drop(f % x))`)] THEN
+  REWRITE_TAC[GSYM o_DEF] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CONVEX_ON_SECANT_DERIVATIVE_IMP) THEN
+  REWRITE_TAC[o_THM; DROP_CMUL; DROP_SUB; LIFT_DROP]);;
+
+let REAL_CONVEX_ON_DERIVATIVES_IMP = prove
+ (`!f f'x f'y s x y.
+        f real_convex_on s /\ real_segment[x,y] SUBSET s /\
+        (f has_real_derivative f'x) (atreal x within s) /\
+        (f has_real_derivative f'y) (atreal y within s)
+        ==> f'x * (y - x) <= f'y * (y - x)`,
+  REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_WITHIN;
+              REAL_CONVEX_ON; REAL_SEGMENT_SEGMENT] THEN
+  REWRITE_TAC[SUBSET; IN_IMAGE_LIFT_DROP] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[FORALL_DROP] THEN
+  REWRITE_TAC[LIFT_DROP] THEN
+  REWRITE_TAC[GSYM IN_IMAGE_LIFT_DROP; GSYM SUBSET] THEN
+  ONCE_REWRITE_TAC[GSYM(REWRITE_CONV[LIFT_DROP]
+        `\x. lift(drop(f % x))`)] THEN
+  REWRITE_TAC[GSYM o_DEF] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CONVEX_ON_DERIVATIVES_IMP) THEN
+  REWRITE_TAC[o_THM; DROP_CMUL; DROP_SUB; LIFT_DROP]);;
+
+let REAL_CONVEX_ON_DERIVATIVE_INCREASING_IMP = prove
+ (`!f f'x f'y s x y.
+        f real_convex_on s /\ real_interval[x,y] SUBSET s /\
+        (f has_real_derivative f'x) (atreal x within s) /\
+        (f has_real_derivative f'y) (atreal y within s) /\
+        x < y
+        ==> f'x <= f'y`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real->real`; `f'x:real`; `f'y:real`; `s:real->bool`;
+                 `x:real`; `y:real`] REAL_CONVEX_ON_DERIVATIVES_IMP) THEN
+  ASM_REWRITE_TAC[REAL_SEGMENT_INTERVAL] THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LE_RMUL_EQ; REAL_SUB_LT]);;
+
+let REAL_CONVEX_ON_DERIVATIVE_SECANT = prove
+ (`!f f' s.
+        is_realinterval s /\
+        (!x. x IN s ==> (f has_real_derivative f'(x)) (atreal x within s))
+        ==> (f real_convex_on s <=>
+             !x y. x IN s /\ y IN s ==> f'(x) * (y - x) <= f y - f x)`,
+  REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_WITHIN;
+              REAL_CONVEX_ON; IS_REALINTERVAL_CONVEX] THEN
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[FORALL_DROP; GSYM IN_IMAGE_LIFT_DROP; LIFT_DROP] THEN
+  ONCE_REWRITE_TAC[GSYM(REWRITE_CONV[LIFT_DROP; o_DEF]
+        `lift o (\x. drop(f % x))`)] THEN
+  DISCH_THEN(SUBST1_TAC o MATCH_MP CONVEX_ON_DERIVATIVE_SECANT) THEN
+  REWRITE_TAC[DROP_CMUL; DROP_SUB; o_THM]);;
+
+let REAL_CONVEX_ON_SECANT_DERIVATIVE = prove
+ (`!f f' s.
+        is_realinterval s /\
+        (!x. x IN s ==> (f has_real_derivative f'(x)) (atreal x within s))
+        ==> (f real_convex_on s <=>
+             !x y. x IN s /\ y IN s ==> f y - f x <= f'(y) * (y - x))`,
+  REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_WITHIN;
+              REAL_CONVEX_ON; IS_REALINTERVAL_CONVEX] THEN
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[FORALL_DROP; GSYM IN_IMAGE_LIFT_DROP; LIFT_DROP] THEN
+  ONCE_REWRITE_TAC[GSYM(REWRITE_CONV[LIFT_DROP; o_DEF]
+        `lift o (\x. drop(f % x))`)] THEN
+  DISCH_THEN(SUBST1_TAC o MATCH_MP CONVEX_ON_SECANT_DERIVATIVE) THEN
+  REWRITE_TAC[DROP_CMUL; DROP_SUB; o_THM]);;
+
+let REAL_CONVEX_ON_DERIVATIVES = prove
+ (`!f f' s.
+        is_realinterval s /\
+        (!x. x IN s ==> (f has_real_derivative f'(x)) (atreal x within s))
+        ==> (f real_convex_on s <=>
+             !x y. x IN s /\ y IN s ==> f'(x) * (y - x) <= f'(y) * (y - x))`,
+  REWRITE_TAC[HAS_REAL_FRECHET_DERIVATIVE_WITHIN;
+              REAL_CONVEX_ON; IS_REALINTERVAL_CONVEX] THEN
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[FORALL_DROP; GSYM IN_IMAGE_LIFT_DROP; LIFT_DROP] THEN
+  ONCE_REWRITE_TAC[GSYM(REWRITE_CONV[LIFT_DROP; o_DEF]
+        `lift o (\x. drop(f % x))`)] THEN
+  DISCH_THEN(SUBST1_TAC o MATCH_MP CONVEX_ON_DERIVATIVES) THEN
+  REWRITE_TAC[DROP_CMUL; DROP_SUB; o_THM]);;
+
+let REAL_CONVEX_ON_DERIVATIVE_INCREASING = prove
+ (`!f f' s.
+        is_realinterval s /\
+        (!x. x IN s ==> (f has_real_derivative f'(x)) (atreal x within s))
+        ==> (f real_convex_on s <=>
+             !x y. x IN s /\ y IN s /\ x <= y ==> f'(x) <= f'(y))`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP REAL_CONVEX_ON_DERIVATIVES) THEN
+  EQ_TAC THEN DISCH_TAC THEN MAP_EVERY X_GEN_TAC [`x:real`; `y:real`] THEN
+  STRIP_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o SPECL [`x:real`; `y:real`]) THEN
+    ASM_CASES_TAC `x:real = y` THEN ASM_REWRITE_TAC[REAL_LE_REFL] THEN
+    ASM_SIMP_TAC[REAL_LE_RMUL_EQ; REAL_SUB_LT; REAL_LT_LE];
+    DISJ_CASES_TAC(REAL_ARITH `x <= y \/ y <= x`) THENL
+     [FIRST_X_ASSUM(MP_TAC o SPECL [`x:real`; `y:real`]);
+      FIRST_X_ASSUM(MP_TAC o SPECL [`y:real`; `x:real`])] THEN
+    ASM_CASES_TAC `x:real = y` THEN ASM_REWRITE_TAC[REAL_LE_REFL] THEN
+    ASM_SIMP_TAC[REAL_LE_RMUL_EQ; REAL_SUB_LT; REAL_LT_LE] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH
+     `a * (y - x) <= b * (y - x) <=> b * (x - y) <= a * (x - y)`] THEN
+    ASM_SIMP_TAC[REAL_LE_RMUL_EQ; REAL_SUB_LT; REAL_LT_LE]]);;
+
+let HAS_REAL_DERIVATIVE_INCREASING_IMP = prove
+ (`!f f' s a b.
+        is_realinterval s /\
+        (!x. x IN s ==> (f has_real_derivative f'(x)) (atreal x within s)) /\
+        (!x. x IN s ==> &0 <= f'(x)) /\
+        a IN s /\ b IN s /\ a <= b
+        ==> f(a) <= f(b)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `real_interval[a,b] SUBSET s` ASSUME_TAC THENL
+   [REWRITE_TAC[SUBSET; IN_REAL_INTERVAL] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [is_realinterval]) THEN
+    MAP_EVERY EXISTS_TAC [`a:real`; `b:real`] THEN ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`f:real->real`; `f':real->real`; `a:real`; `b:real`]
+    REAL_MVT_VERY_SIMPLE) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN X_GEN_TAC `z:real` THEN DISCH_TAC THEN
+    MATCH_MP_TAC HAS_REAL_DERIVATIVE_WITHIN_SUBSET THEN
+    EXISTS_TAC `s:real->bool` THEN ASM SET_TAC[];
+    DISCH_THEN(X_CHOOSE_THEN `z:real` MP_TAC) THEN STRIP_TAC THEN
+    GEN_REWRITE_TAC I [GSYM REAL_SUB_LE] THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_MUL THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ASM_REAL_ARITH_TAC]]);;
+
+let HAS_REAL_DERIVATIVE_INCREASING = prove
+ (`!f f' s. is_realinterval s /\ ~(?a. s = {a}) /\
+           (!x. x IN s ==> (f has_real_derivative f'(x)) (atreal x within s))
+           ==> ((!x. x IN s ==> &0 <= f'(x)) <=>
+                (!x y. x IN s /\ y IN s /\ x <= y ==> f(x) <= f(y)))`,
+  REWRITE_TAC[NOT_EXISTS_THM] THEN REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ASM_MESON_TAC[HAS_REAL_DERIVATIVE_INCREASING_IMP]; ALL_TAC] THEN
+  DISCH_TAC THEN X_GEN_TAC `x:real` THEN DISCH_TAC THEN
+  MATCH_MP_TAC(ISPEC `atreal x within s` REALLIM_LBOUND) THEN
+  EXISTS_TAC `\y:real. (f y - f x) / (y - x)` THEN
+  ASM_SIMP_TAC[GSYM HAS_REAL_DERIVATIVE_WITHINREAL] THEN
+  ASM_SIMP_TAC[TRIVIAL_LIMIT_WITHIN_REALINTERVAL] THEN
+  REWRITE_TAC[EVENTUALLY_WITHINREAL] THEN
+  EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN
+  X_GEN_TAC `y:real` THEN
+  REWRITE_TAC[REAL_ARITH `&0 < abs(y - x) <=> ~(y = x)`] THEN STRIP_TAC THEN
+  FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+   `~(y:real = x) ==> x < y \/ y < x`))
+  THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[GSYM REAL_NEG_SUB] THEN
+    REWRITE_TAC[real_div; REAL_INV_NEG; REAL_MUL_LNEG; REAL_MUL_RNEG] THEN
+    REWRITE_TAC[REAL_NEG_NEG; GSYM real_div]] THEN
+  MATCH_MP_TAC REAL_LE_DIV THEN
+  ASM_SIMP_TAC[REAL_SUB_LE; REAL_LT_IMP_LE]);;
+
+let REAL_CONVEX_ON_SECOND_DERIVATIVE = prove
+ (`!f f' f'' s.
+        is_realinterval s /\ ~(?a. s = {a}) /\
+        (!x. x IN s ==> (f has_real_derivative f'(x)) (atreal x within s)) /\
+        (!x. x IN s ==> (f' has_real_derivative f''(x)) (atreal x within s))
+        ==> (f real_convex_on s <=> !x. x IN s ==> &0 <= f''(x))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `!x y. x IN s /\ y IN s /\ x <= y ==> (f':real->real)(x) <= f'(y)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_CONVEX_ON_DERIVATIVE_INCREASING;
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC HAS_REAL_DERIVATIVE_INCREASING] THEN
+  ASM_REWRITE_TAC[]);;
+
+let REAL_CONVEX_ON_ASYM = prove
+ (`!s f. f real_convex_on s <=>
+         !x y u v.
+                x IN s /\ y IN s /\ x < y /\ &0 <= u /\ &0 <= v /\ u + v = &1
+                ==> f (u * x + v * y) <= u * f x + v * f y`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_convex_on] THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+  MATCH_MP_TAC REAL_WLOG_LT THEN
+  SIMP_TAC[GSYM REAL_ADD_RDISTRIB; REAL_MUL_LID; REAL_LE_REFL] THEN
+  ASM_MESON_TAC[REAL_ADD_SYM]);;
+
+let REAL_CONVEX_ON_EXP = prove
+ (`!s. exp real_convex_on s`,
+  GEN_TAC THEN MATCH_MP_TAC REAL_CONVEX_ON_SUBSET THEN
+  EXISTS_TAC `(:real)` THEN REWRITE_TAC[SUBSET_UNIV] THEN
+  MP_TAC(ISPECL [`exp`; `exp`; `exp`; `(:real)`]
+     REAL_CONVEX_ON_SECOND_DERIVATIVE) THEN
+  SIMP_TAC[HAS_REAL_DERIVATIVE_EXP; REAL_EXP_POS_LE;
+           HAS_REAL_DERIVATIVE_ATREAL_WITHIN; IS_REALINTERVAL_UNIV] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  MATCH_MP_TAC(SET_RULE
+   `&0 IN s /\ &1 IN s /\ ~(&1 = &0) ==> ~(?a. s = {a})`) THEN
+  REWRITE_TAC[IN_UNIV] THEN REAL_ARITH_TAC);;
+
+let REAL_CONVEX_ON_RPOW = prove
+ (`!s t. s SUBSET {x | &0 <= x} /\ &1 <= t
+         ==> (\x. x rpow t) real_convex_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_CONVEX_ON_SUBSET THEN
+  EXISTS_TAC `{x | &0 <= x}` THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `(\x. x rpow t) real_convex_on {x | &0 < x}` MP_TAC THENL
+   [MP_TAC(ISPECL
+     [`\x. x rpow t`; `\x. t * x rpow (t - &1)`;
+      `\x. t * (t - &1) * x rpow (t - &2)`; `{x | &0 < x}`]
+        REAL_CONVEX_ON_SECOND_DERIVATIVE) THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM] THEN ANTS_TAC THENL
+     [REPEAT CONJ_TAC THENL
+       [REWRITE_TAC[is_realinterval; IN_ELIM_THM] THEN REAL_ARITH_TAC;
+        MATCH_MP_TAC(SET_RULE
+         `&1 IN s /\ &2 IN s /\ ~(&1 = &2) ==> ~(?a. s = {a})`) THEN
+        REWRITE_TAC[IN_ELIM_THM] THEN REAL_ARITH_TAC;
+        REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN ASM_REAL_ARITH_TAC;
+        REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN
+        ASM_REWRITE_TAC[REAL_ARITH `t - &1 - &1 = t - &2`] THEN
+        ASM_REAL_ARITH_TAC];
+      DISCH_THEN SUBST1_TAC THEN REPEAT STRIP_TAC THEN
+      REPEAT(MATCH_MP_TAC REAL_LE_MUL THEN CONJ_TAC THENL
+       [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+      MATCH_MP_TAC RPOW_POS_LE THEN ASM_SIMP_TAC[REAL_LT_IMP_LE]];
+    REWRITE_TAC[REAL_CONVEX_ON_ASYM] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `x:real` THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN ASM_CASES_TAC `x = &0` THENL
+     [DISCH_THEN(K ALL_TAC) THEN ASM_REWRITE_TAC[REAL_MUL_RZERO] THEN
+      REPEAT STRIP_TAC THEN
+      ASM_SIMP_TAC[RPOW_ZERO; REAL_ARITH `&1 <= t ==> ~(t = &0)`] THEN
+      REWRITE_TAC[REAL_MUL_RZERO; REAL_ADD_LID] THEN
+      ASM_CASES_TAC `v = &0` THEN
+      ASM_SIMP_TAC[RPOW_ZERO; REAL_ARITH `&1 <= t ==> ~(t = &0)`;
+                   REAL_MUL_LZERO; REAL_LE_REFL] THEN
+      ASM_SIMP_TAC[RPOW_MUL; REAL_LT_LE] THEN
+      MATCH_MP_TAC REAL_LE_RMUL THEN
+      ASM_SIMP_TAC[RPOW_POS_LE; REAL_LT_IMP_LE] THEN
+       MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `exp(&1 * log v)` THEN
+      CONJ_TAC THENL
+       [ASM_SIMP_TAC[rpow; REAL_LT_LE; REAL_EXP_MONO_LE] THEN
+        ONCE_REWRITE_TAC[REAL_ARITH
+         `a * l <= b * l <=> --l * b <= --l * a`] THEN
+        MATCH_MP_TAC REAL_LE_LMUL THEN ASM_REWRITE_TAC[] THEN
+        ASM_SIMP_TAC[GSYM LOG_INV; REAL_LT_LE] THEN MATCH_MP_TAC LOG_POS THEN
+        MATCH_MP_TAC REAL_INV_1_LE THEN ASM_REAL_ARITH_TAC;
+        ASM_SIMP_TAC[REAL_MUL_LID; EXP_LOG; REAL_LT_LE; REAL_LE_REFL]];
+      ASM_MESON_TAC[REAL_LT_LE; REAL_LET_TRANS]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A couple of simple bounds that it's convenient to get this way.           *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_LE_X_SINH = prove
+ (`!x. &0 <= x ==> x <= (exp x - inv(exp x)) / &2`,
+  SUBGOAL_THEN
+   `!a b. a <= b
+          ==> exp a - inv(exp a) - &2 * a <= exp b - inv(exp b) - &2 * b`
+   (MP_TAC o SPEC `&0`)
+  THENL
+   [MP_TAC(ISPECL
+     [`\x. exp x - exp(--x) - &2 * x`; `\x. exp x + exp(--x) - &2`; `(:real)`]
+     HAS_REAL_DERIVATIVE_INCREASING) THEN
+    REWRITE_TAC[IN_ELIM_THM; IS_REALINTERVAL_UNIV; IN_UNIV] THEN ANTS_TAC THENL
+     [CONJ_TAC THENL [SET_TAC[REAL_ARITH `~(&1 = &0)`]; ALL_TAC] THEN
+      GEN_TAC THEN REAL_DIFF_TAC THEN REAL_ARITH_TAC;
+      SIMP_TAC[REAL_EXP_NEG] THEN DISCH_THEN(fun th -> SIMP_TAC[GSYM th]) THEN
+      X_GEN_TAC `x:real` THEN
+      SIMP_TAC[REAL_EXP_NZ; REAL_FIELD
+       `~(e = &0) ==> e + inv e - &2 = (e - &1) pow 2 / e`] THEN
+      SIMP_TAC[REAL_EXP_POS_LE; REAL_LE_DIV; REAL_LE_POW_2]];
+    MATCH_MP_TAC MONO_FORALL THEN REWRITE_TAC[REAL_EXP_0] THEN
+    REAL_ARITH_TAC]);;
+
+let REAL_LE_ABS_SINH = prove
+ (`!x. abs x <= abs((exp x - inv(exp x)) / &2)`,
+  GEN_TAC THEN ASM_CASES_TAC `&0 <= x` THENL
+   [MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ x <= y ==> abs x <= abs y`) THEN
+    ASM_SIMP_TAC[REAL_LE_X_SINH];
+    MATCH_MP_TAC(REAL_ARITH `~(&0 <= x) /\ --x <= --y ==> abs x <= abs y`) THEN
+    ASM_REWRITE_TAC[REAL_ARITH `--((a - b) / &2) = (b - a) / &2`] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `(exp(--x) - inv(exp(--x))) / &2` THEN
+    ASM_SIMP_TAC[REAL_LE_X_SINH; REAL_ARITH `~(&0 <= x) ==> &0 <= --x`] THEN
+    REWRITE_TAC[REAL_EXP_NEG; REAL_INV_INV] THEN REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Integrals of real->real functions; measures of real sets.                 *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("has_real_integral",(12,"right"));;
+parse_as_infix("real_integrable_on",(12,"right"));;
+parse_as_infix("absolutely_real_integrable_on",(12,"right"));;
+parse_as_infix("has_real_measure",(12,"right"));;
+
+let has_real_integral = new_definition
+ `(f has_real_integral y) s <=>
+        ((lift o f o drop) has_integral (lift y)) (IMAGE lift s)`;;
+
+let real_integrable_on = new_definition
+ `f real_integrable_on i <=> ?y. (f has_real_integral y) i`;;
+
+let real_integral = new_definition
+ `real_integral i f = @y. (f has_real_integral y) i`;;
+
+let real_negligible = new_definition
+ `real_negligible s <=> negligible (IMAGE lift s)`;;
+
+let absolutely_real_integrable_on = new_definition
+ `f absolutely_real_integrable_on s <=>
+        f real_integrable_on s /\ (\x. abs(f x)) real_integrable_on s`;;
+
+let has_real_measure = new_definition
+ `s has_real_measure m <=> ((\x. &1) has_real_integral m) s`;;
+
+let real_measurable = new_definition
+ `real_measurable s <=> ?m. s has_real_measure m`;;
+
+let real_measure = new_definition
+ `real_measure s = @m. s has_real_measure m`;;
+
+let HAS_REAL_INTEGRAL = prove
+ (`(f has_real_integral y) (real_interval[a,b]) <=>
+   ((lift o f o drop) has_integral (lift y)) (interval[lift a,lift b])`,
+  REWRITE_TAC[has_real_integral; IMAGE_LIFT_REAL_INTERVAL]);;
+
+let REAL_INTEGRABLE_INTEGRAL = prove
+ (`!f i. f real_integrable_on i
+         ==> (f has_real_integral (real_integral i f)) i`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_integrable_on; real_integral] THEN
+  CONV_TAC(RAND_CONV SELECT_CONV) THEN REWRITE_TAC[]);;
+
+let HAS_REAL_INTEGRAL_INTEGRABLE = prove
+ (`!f i s. (f has_real_integral i) s ==> f real_integrable_on s`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[]);;
+
+let HAS_REAL_INTEGRAL_INTEGRAL = prove
+ (`!f s. f real_integrable_on s <=>
+         (f has_real_integral (real_integral s f)) s`,
+  MESON_TAC[REAL_INTEGRABLE_INTEGRAL; HAS_REAL_INTEGRAL_INTEGRABLE]);;
+
+let HAS_REAL_INTEGRAL_UNIQUE = prove
+ (`!f i k1 k2.
+        (f has_real_integral k1) i /\ (f has_real_integral k2) i ==> k1 = k2`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_real_integral] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_UNIQUE) THEN
+  REWRITE_TAC[LIFT_EQ]);;
+
+let REAL_INTEGRAL_UNIQUE = prove
+ (`!f y k.
+      (f has_real_integral y) k ==> real_integral k f = y`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[real_integral] THEN
+  MATCH_MP_TAC SELECT_UNIQUE THEN ASM_MESON_TAC[HAS_REAL_INTEGRAL_UNIQUE]);;
+
+let HAS_REAL_INTEGRAL_INTEGRABLE_INTEGRAL = prove
+ (`!f i s.
+        (f has_real_integral i) s <=>
+        f real_integrable_on s /\ real_integral s f = i`,
+  MESON_TAC[REAL_INTEGRABLE_INTEGRAL; REAL_INTEGRAL_UNIQUE;
+            real_integrable_on]);;
+
+let REAL_INTEGRAL_EQ_HAS_INTEGRAL = prove
+ (`!s f y. f real_integrable_on s
+           ==> (real_integral s f = y <=> (f has_real_integral y) s)`,
+  MESON_TAC[REAL_INTEGRABLE_INTEGRAL; REAL_INTEGRAL_UNIQUE]);;
+
+let REAL_INTEGRABLE_ON = prove
+ (`f real_integrable_on s <=>
+        (lift o f o drop) integrable_on (IMAGE lift s)`,
+  REWRITE_TAC[real_integrable_on; has_real_integral; EXISTS_DROP;
+              integrable_on; LIFT_DROP]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_ON = prove
+ (`f absolutely_real_integrable_on s <=>
+        (lift o f o drop) absolutely_integrable_on (IMAGE lift s)`,
+  REWRITE_TAC[absolutely_real_integrable_on; REAL_INTEGRABLE_ON;
+              absolutely_integrable_on] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP; NORM_LIFT]);;
+
+let REAL_INTEGRAL = prove
+ (`f real_integrable_on s
+   ==> real_integral s f = drop(integral (IMAGE lift s) (lift o f o drop))`,
+  REWRITE_TAC[REAL_INTEGRABLE_ON] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+  REWRITE_TAC[has_real_integral; LIFT_DROP] THEN
+  ASM_REWRITE_TAC[GSYM HAS_INTEGRAL_INTEGRAL]);;
+
+let HAS_REAL_INTEGRAL_IS_0 = prove
+ (`!f s. (!x. x IN s ==> f(x) = &0) ==> (f has_real_integral &0) s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[has_real_integral; LIFT_NUM] THEN
+  MATCH_MP_TAC HAS_INTEGRAL_IS_0 THEN
+  ASM_REWRITE_TAC[LIFT_EQ; FORALL_IN_IMAGE; o_THM; LIFT_DROP; GSYM LIFT_NUM]);;
+
+let HAS_REAL_INTEGRAL_0 = prove
+ (`!s. ((\x. &0) has_real_integral &0) s`,
+  SIMP_TAC[HAS_REAL_INTEGRAL_IS_0]);;
+
+let HAS_REAL_INTEGRAL_0_EQ = prove
+ (`!i s. ((\x. &0) has_real_integral i) s <=> i = &0`,
+  MESON_TAC[HAS_REAL_INTEGRAL_UNIQUE; HAS_REAL_INTEGRAL_0]);;
+
+let HAS_REAL_INTEGRAL_LINEAR = prove
+ (`!f:real->real y s h:real->real.
+        (f has_real_integral y) s /\ linear(lift o h o drop)
+        ==> ((h o f) has_real_integral h(y)) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_real_integral] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_LINEAR) THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP]);;
+
+let HAS_REAL_INTEGRAL_LMUL = prove
+ (`!(f:real->real) k s c.
+        (f has_real_integral k) s
+        ==> ((\x. c * f(x)) has_real_integral (c * k)) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_real_integral] THEN
+  DISCH_THEN(MP_TAC o SPEC `c:real` o MATCH_MP HAS_INTEGRAL_CMUL) THEN
+  REWRITE_TAC[GSYM LIFT_CMUL; o_DEF]);;
+
+let HAS_REAL_INTEGRAL_RMUL = prove
+ (`!(f:real->real) k s c.
+        (f has_real_integral k) s
+        ==> ((\x. f(x) * c) has_real_integral (k * c)) s`,
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  REWRITE_TAC[HAS_REAL_INTEGRAL_LMUL]);;
+
+let HAS_REAL_INTEGRAL_NEG = prove
+ (`!f k s. (f has_real_integral k) s
+           ==> ((\x. --(f x)) has_real_integral (--k)) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_real_integral] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_NEG) THEN
+  REWRITE_TAC[o_DEF; LIFT_NEG]);;
+
+let HAS_REAL_INTEGRAL_ADD = prove
+ (`!f:real->real g k l s.
+        (f has_real_integral k) s /\ (g has_real_integral l) s
+        ==> ((\x. f(x) + g(x)) has_real_integral (k + l)) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_real_integral] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_ADD) THEN
+  REWRITE_TAC[o_DEF; LIFT_ADD]);;
+
+let HAS_REAL_INTEGRAL_SUB = prove
+ (`!f:real->real g k l s.
+        (f has_real_integral k) s /\ (g has_real_integral l) s
+        ==> ((\x. f(x) - g(x)) has_real_integral (k - l)) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_real_integral] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_SUB) THEN
+  REWRITE_TAC[o_DEF; LIFT_SUB]);;
+
+let REAL_INTEGRAL_0 = prove
+ (`!s. real_integral s (\x. &0) = &0`,
+  MESON_TAC[REAL_INTEGRAL_UNIQUE; HAS_REAL_INTEGRAL_0]);;
+
+let REAL_INTEGRAL_ADD = prove
+ (`!f:real->real g s.
+        f real_integrable_on s /\ g real_integrable_on s
+        ==> real_integral s (\x. f x + g x) =
+            real_integral s f + real_integral s g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_ADD THEN
+  ASM_SIMP_TAC[REAL_INTEGRABLE_INTEGRAL]);;
+
+let REAL_INTEGRAL_LMUL = prove
+ (`!f:real->real c s.
+        f real_integrable_on s
+        ==> real_integral s (\x. c * f(x)) = c * real_integral s f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_LMUL THEN
+  ASM_SIMP_TAC[REAL_INTEGRABLE_INTEGRAL]);;
+
+let REAL_INTEGRAL_RMUL = prove
+ (`!f:real->real c s.
+        f real_integrable_on s
+        ==> real_integral s (\x. f(x) * c) = real_integral s f * c`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_RMUL THEN
+  ASM_SIMP_TAC[REAL_INTEGRABLE_INTEGRAL]);;
+
+let REAL_INTEGRAL_NEG = prove
+ (`!f:real->real s.
+        f real_integrable_on s
+        ==> real_integral s (\x. --f(x)) = --real_integral s f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_NEG THEN
+  ASM_SIMP_TAC[REAL_INTEGRABLE_INTEGRAL]);;
+
+let REAL_INTEGRAL_SUB = prove
+ (`!f:real->real g s.
+        f real_integrable_on s /\ g real_integrable_on s
+        ==> real_integral s (\x. f x - g x) =
+            real_integral s f - real_integral s g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_SUB THEN
+  ASM_SIMP_TAC[REAL_INTEGRABLE_INTEGRAL]);;
+
+let REAL_INTEGRABLE_0 = prove
+ (`!s. (\x. &0) real_integrable_on s`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_0]);;
+
+let REAL_INTEGRABLE_ADD = prove
+ (`!f:real->real g s.
+        f real_integrable_on s /\ g real_integrable_on s
+        ==> (\x. f x + g x) real_integrable_on s`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_ADD]);;
+
+let REAL_INTEGRABLE_LMUL = prove
+ (`!f:real->real c s.
+        f real_integrable_on s
+        ==> (\x. c * f(x)) real_integrable_on s`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_LMUL]);;
+
+let REAL_INTEGRABLE_RMUL = prove
+ (`!f:real->real c s.
+        f real_integrable_on s
+        ==> (\x. f(x) * c) real_integrable_on s`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_RMUL]);;
+
+let REAL_INTEGRABLE_NEG = prove
+ (`!f:real->real s.
+        f real_integrable_on s ==> (\x. --f(x)) real_integrable_on s`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_NEG]);;
+
+let REAL_INTEGRABLE_SUB = prove
+ (`!f:real->real g s.
+        f real_integrable_on s /\ g real_integrable_on s
+        ==> (\x. f x - g x) real_integrable_on s`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_SUB]);;
+
+let REAL_INTEGRABLE_LINEAR = prove
+ (`!f h s. f real_integrable_on s /\
+           linear(lift o h o drop) ==> (h o f) real_integrable_on s`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_LINEAR]);;
+
+let REAL_INTEGRAL_LINEAR = prove
+ (`!f:real->real s h:real->real.
+        f real_integrable_on s /\ linear(lift o h o drop)
+        ==> real_integral s (h o f) = h(real_integral s f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_INTEGRAL_UNIQUE THEN
+  MAP_EVERY EXISTS_TAC
+   [`(h:real->real) o (f:real->real)`; `s:real->bool`] THEN
+  CONJ_TAC THENL [ALL_TAC; MATCH_MP_TAC HAS_REAL_INTEGRAL_LINEAR] THEN
+  ASM_SIMP_TAC[GSYM HAS_REAL_INTEGRAL_INTEGRAL; REAL_INTEGRABLE_LINEAR]);;
+
+let HAS_REAL_INTEGRAL_SUM = prove
+ (`!f:A->real->real s t.
+        FINITE t /\
+        (!a. a IN t ==> ((f a) has_real_integral (i a)) s)
+        ==> ((\x. sum t (\a. f a x)) has_real_integral (sum t i)) s`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[SUM_CLAUSES; HAS_REAL_INTEGRAL_0; IN_INSERT] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_INTEGRAL_ADD THEN
+  ASM_REWRITE_TAC[ETA_AX] THEN CONJ_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[]);;
+
+let REAL_INTEGRAL_SUM = prove
+ (`!f:A->real->real s t.
+        FINITE t /\
+        (!a. a IN t ==> (f a) real_integrable_on s)
+        ==> real_integral s (\x. sum t (\a. f a x)) =
+                sum t (\a. real_integral s (f a))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_SUM THEN
+  ASM_SIMP_TAC[REAL_INTEGRABLE_INTEGRAL]);;
+
+let REAL_INTEGRABLE_SUM = prove
+ (`!f:A->real->real s t.
+        FINITE t /\
+        (!a. a IN t ==> (f a) real_integrable_on s)
+        ==>  (\x. sum t (\a. f a x)) real_integrable_on s`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_SUM]);;
+
+let HAS_REAL_INTEGRAL_EQ = prove
+ (`!f:real->real g k s.
+        (!x. x IN s ==> (f(x) = g(x))) /\
+        (f has_real_integral k) s
+        ==> (g has_real_integral k) s`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_SUB_0] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (MP_TAC o MATCH_MP HAS_REAL_INTEGRAL_IS_0) MP_TAC) THEN
+  REWRITE_TAC[IMP_IMP] THEN DISCH_THEN
+   (MP_TAC o MATCH_MP HAS_REAL_INTEGRAL_SUB) THEN
+  SIMP_TAC[REAL_ARITH `x - (x - y:real) = y`; ETA_AX; REAL_SUB_RZERO]);;
+
+let REAL_INTEGRABLE_EQ = prove
+ (`!f:real->real g s.
+        (!x. x IN s ==> (f(x) = g(x))) /\
+        f real_integrable_on s
+        ==> g real_integrable_on s`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_EQ]);;
+
+let HAS_REAL_INTEGRAL_EQ_EQ = prove
+ (`!f:real->real g k s.
+        (!x. x IN s ==> (f(x) = g(x)))
+        ==> ((f has_real_integral k) s <=> (g has_real_integral k) s)`,
+  MESON_TAC[HAS_REAL_INTEGRAL_EQ]);;
+
+let HAS_REAL_INTEGRAL_NULL = prove
+ (`!f:real->real a b.
+    b <= a ==> (f has_real_integral &0) (real_interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[has_real_integral; REAL_INTERVAL_INTERVAL] THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; LIFT_DROP; LIFT_NUM] THEN
+  REWRITE_TAC[SET_RULE `IMAGE (\x. x) s = s`] THEN
+  MATCH_MP_TAC HAS_INTEGRAL_NULL THEN
+  ASM_REWRITE_TAC[CONTENT_EQ_0_1; LIFT_DROP]);;
+
+let HAS_REAL_INTEGRAL_NULL_EQ = prove
+ (`!f a b i. b <= a
+             ==> ((f has_real_integral i) (real_interval[a,b]) <=> i = &0)`,
+  ASM_MESON_TAC[REAL_INTEGRAL_UNIQUE; HAS_REAL_INTEGRAL_NULL]);;
+
+let REAL_INTEGRAL_NULL = prove
+ (`!f a b. b <= a
+           ==> real_integral(real_interval[a,b]) f = &0`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+  ASM_MESON_TAC[HAS_REAL_INTEGRAL_NULL]);;
+
+let REAL_INTEGRABLE_ON_NULL = prove
+ (`!f a b. b <= a
+           ==> f real_integrable_on real_interval[a,b]`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_NULL]);;
+
+let HAS_REAL_INTEGRAL_EMPTY = prove
+ (`!f. (f has_real_integral &0) {}`,
+  GEN_TAC THEN REWRITE_TAC[EMPTY_AS_REAL_INTERVAL] THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_NULL THEN REWRITE_TAC[REAL_POS]);;
+
+let HAS_REAL_INTEGRAL_EMPTY_EQ = prove
+ (`!f i. (f has_real_integral i) {} <=> i = &0`,
+  MESON_TAC[HAS_REAL_INTEGRAL_UNIQUE; HAS_REAL_INTEGRAL_EMPTY]);;
+
+let REAL_INTEGRABLE_ON_EMPTY = prove
+ (`!f. f real_integrable_on {}`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_EMPTY]);;
+
+let REAL_INTEGRAL_EMPTY = prove
+ (`!f. real_integral {} f = &0`,
+  MESON_TAC[EMPTY_AS_REAL_INTERVAL; REAL_INTEGRAL_UNIQUE;
+            HAS_REAL_INTEGRAL_EMPTY]);;
+
+let HAS_REAL_INTEGRAL_REFL = prove
+ (`!f a. (f has_real_integral &0) (real_interval[a,a])`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC HAS_REAL_INTEGRAL_NULL THEN
+  REWRITE_TAC[REAL_LE_REFL]);;
+
+let REAL_INTEGRABLE_ON_REFL = prove
+ (`!f a. f real_integrable_on real_interval[a,a]`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_REFL]);;
+
+let REAL_INTEGRAL_REFL = prove
+ (`!f a. real_integral (real_interval[a,a]) f = &0`,
+  MESON_TAC[REAL_INTEGRAL_UNIQUE; HAS_REAL_INTEGRAL_REFL]);;
+
+let HAS_REAL_INTEGRAL_CONST = prove
+ (`!a b c.
+        a <= b
+        ==> ((\x. c) has_real_integral (c * (b - a))) (real_interval[a,b])`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  REWRITE_TAC[has_real_integral; IMAGE_LIFT_REAL_INTERVAL] THEN
+  MP_TAC(ISPECL [`lift a`; `lift b`; `lift c`] HAS_INTEGRAL_CONST) THEN
+  ASM_SIMP_TAC[o_DEF; CONTENT_1; LIFT_DROP; LIFT_CMUL]);;
+
+let REAL_INTEGRABLE_CONST = prove
+ (`!a b c. (\x. c) real_integrable_on real_interval[a,b]`,
+  REWRITE_TAC[REAL_INTEGRABLE_ON; IMAGE_LIFT_REAL_INTERVAL;
+              o_DEF; INTEGRABLE_CONST]);;
+
+let REAL_INTEGRAL_CONST = prove
+ (`!a b c.
+        a <= b
+        ==> real_integral (real_interval [a,b]) (\x. c) = c * (b - a)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_REAL_INTEGRAL_CONST]);;
+
+let HAS_REAL_INTEGRAL_BOUND = prove
+ (`!f:real->real a b i B.
+        &0 <= B /\ a <= b /\
+        (f has_real_integral i) (real_interval[a,b]) /\
+        (!x. x IN real_interval[a,b] ==> abs(f x) <= B)
+        ==> abs i <= B * (b - a)`,
+  REWRITE_TAC[HAS_REAL_INTEGRAL; REAL_INTERVAL_INTERVAL; GSYM NORM_LIFT] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; LIFT_DROP] THEN REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV o BINOP_CONV) [GSYM LIFT_DROP] THEN
+  ASM_SIMP_TAC[GSYM CONTENT_1; LIFT_DROP] THEN
+  MATCH_MP_TAC HAS_INTEGRAL_BOUND THEN
+  EXISTS_TAC `lift o f o drop` THEN ASM_REWRITE_TAC[o_THM]);;
+
+let HAS_REAL_INTEGRAL_LE = prove
+ (`!f g s i j.
+        (f has_real_integral i) s /\ (g has_real_integral j) s /\
+        (!x. x IN s ==> f x <= g x)
+        ==> i <= j`,
+  REWRITE_TAC[has_real_integral] THEN REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC BINOP_CONV [GSYM LIFT_DROP] THEN
+  REWRITE_TAC[drop] THEN MATCH_MP_TAC
+   (ISPECL [`lift o f o drop`; `lift o g o drop`; `IMAGE lift s`]
+           HAS_INTEGRAL_COMPONENT_LE) THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; DIMINDEX_1; LE_REFL; o_THM; LIFT_DROP;
+                  GSYM drop]);;
+
+let REAL_INTEGRAL_LE = prove
+ (`!f:real->real g:real->real s.
+        f real_integrable_on s /\ g real_integrable_on s /\
+        (!x. x IN s ==> f x <= g x)
+        ==> real_integral s f <= real_integral s g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_INTEGRAL_LE THEN
+  ASM_MESON_TAC[REAL_INTEGRABLE_INTEGRAL]);;
+
+let HAS_REAL_INTEGRAL_POS = prove
+ (`!f:real->real s i.
+        (f has_real_integral i) s /\
+        (!x. x IN s ==> &0 <= f x)
+        ==> &0 <= i`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(\x. &0):real->real`; `f:real->real`;
+                 `s:real->bool`; `&0:real`;
+                 `i:real`] HAS_REAL_INTEGRAL_LE) THEN
+  ASM_SIMP_TAC[HAS_REAL_INTEGRAL_0]);;
+
+let REAL_INTEGRAL_POS = prove
+ (`!f:real->real s.
+        f real_integrable_on s /\
+        (!x. x IN s ==> &0 <= f x)
+        ==> &0 <= real_integral s f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_INTEGRAL_POS THEN
+  ASM_MESON_TAC[REAL_INTEGRABLE_INTEGRAL]);;
+
+let HAS_REAL_INTEGRAL_ISNEG = prove
+ (`!f:real->real s i.
+        (f has_real_integral i) s /\
+        (!x. x IN s ==> f x <= &0)
+        ==> i <= &0`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real->real`; `(\x. &0):real->real`;
+                 `s:real->bool`; `i:real`; `&0:real`;
+                ] HAS_REAL_INTEGRAL_LE) THEN
+  ASM_SIMP_TAC[HAS_REAL_INTEGRAL_0]);;
+
+let HAS_REAL_INTEGRAL_LBOUND = prove
+ (`!f:real->real a b i.
+        a <= b /\
+        (f has_real_integral i) (real_interval[a,b]) /\
+        (!x. x IN real_interval[a,b] ==> B <= f(x))
+        ==> B * (b - a) <= i`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(\x. B):real->real`; `f:real->real`;
+                 `real_interval[a,b]`;
+                  `B * (b - a):real`;
+                 `i:real`]
+                HAS_REAL_INTEGRAL_LE) THEN
+  ASM_SIMP_TAC[HAS_REAL_INTEGRAL_CONST]);;
+
+let HAS_REAL_INTEGRAL_UBOUND = prove
+ (`!f:real->real a b i.
+        a <= b /\
+        (f has_real_integral i) (real_interval[a,b]) /\
+        (!x. x IN real_interval[a,b] ==> f(x) <= B)
+        ==> i <= B * (b - a)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real->real`; `(\x. B):real->real`;
+                 `real_interval[a,b]`; `i:real`;
+                 `B * (b - a):real`]
+                HAS_REAL_INTEGRAL_LE) THEN
+  ASM_SIMP_TAC[HAS_REAL_INTEGRAL_CONST]);;
+
+let REAL_INTEGRAL_LBOUND = prove
+ (`!f:real->real a b.
+        a <= b /\
+        f real_integrable_on real_interval[a,b] /\
+        (!x. x IN real_interval[a,b] ==> B <= f(x))
+        ==> B * (b - a) <= real_integral(real_interval[a,b]) f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_INTEGRAL_LBOUND THEN
+  EXISTS_TAC `f:real->real` THEN
+  ASM_REWRITE_TAC[GSYM HAS_REAL_INTEGRAL_INTEGRAL]);;
+
+let REAL_INTEGRAL_UBOUND = prove
+ (`!f:real->real a b.
+        a <= b /\
+        f real_integrable_on real_interval[a,b] /\
+        (!x. x IN real_interval[a,b] ==> f(x) <= B)
+        ==> real_integral(real_interval[a,b]) f <= B * (b - a)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_INTEGRAL_UBOUND THEN
+  EXISTS_TAC `f:real->real` THEN
+  ASM_REWRITE_TAC[GSYM HAS_REAL_INTEGRAL_INTEGRAL]);;
+
+let REAL_INTEGRABLE_UNIFORM_LIMIT = prove
+ (`!f a b. (!e. &0 < e
+                ==> ?g. (!x. x IN real_interval[a,b] ==> abs(f x - g x) <= e) /\
+                        g real_integrable_on real_interval[a,b] )
+           ==> f real_integrable_on real_interval[a,b]`,
+  REWRITE_TAC[real_integrable_on; HAS_REAL_INTEGRAL; GSYM EXISTS_LIFT] THEN
+  REWRITE_TAC[GSYM integrable_on] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC INTEGRABLE_UNIFORM_LIMIT 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 `g:real->real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `lift o g o drop` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; FORALL_IN_IMAGE] THEN
+  ASM_SIMP_TAC[o_THM; LIFT_DROP; GSYM LIFT_SUB; NORM_LIFT]);;
+
+let HAS_REAL_INTEGRAL_NEGLIGIBLE = prove
+ (`!f s t.
+        real_negligible s /\ (!x. x IN (t DIFF s) ==> f x = &0)
+        ==> (f has_real_integral (&0)) t`,
+  REWRITE_TAC[has_real_integral; real_negligible; LIFT_NUM] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_NEGLIGIBLE THEN
+  EXISTS_TAC `IMAGE lift s` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[o_THM; IN_DIFF; IMP_CONJ; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[LIFT_IN_IMAGE_LIFT; LIFT_DROP] THEN ASM SET_TAC[LIFT_NUM]);;
+
+let HAS_REAL_INTEGRAL_SPIKE = prove
+ (`!f g s t y.
+        real_negligible s /\ (!x. x IN (t DIFF s) ==> g x = f x) /\
+        (f has_real_integral y) t
+        ==> (g has_real_integral y) t`,
+  REWRITE_TAC[has_real_integral; real_negligible] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_SPIKE THEN
+  MAP_EVERY EXISTS_TAC [`lift o f o drop`; `IMAGE lift s`] THEN
+  ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[o_THM; IN_DIFF; IMP_CONJ; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[LIFT_IN_IMAGE_LIFT; LIFT_DROP] THEN ASM SET_TAC[LIFT_NUM]);;
+
+let HAS_REAL_INTEGRAL_SPIKE_EQ = prove
+ (`!f g s t y.
+        real_negligible s /\ (!x. x IN (t DIFF s) ==> g x = f x)
+        ==> ((f has_real_integral y) t <=> (g has_real_integral y) t)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_SPIKE THENL
+   [EXISTS_TAC `f:real->real`; EXISTS_TAC `g:real->real`] THEN
+  EXISTS_TAC `s:real->bool` THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[REAL_ABS_SUB]);;
+
+let REAL_INTEGRABLE_SPIKE = prove
+ (`!f g s t.
+        real_negligible s /\ (!x. x IN (t DIFF s) ==> g x = f x)
+        ==> f real_integrable_on t ==> g real_integrable_on  t`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[real_integrable_on] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+  MP_TAC(SPEC_ALL HAS_REAL_INTEGRAL_SPIKE) THEN ASM_REWRITE_TAC[]);;
+
+let REAL_INTEGRAL_SPIKE = prove
+ (`!f:real->real g s t.
+        real_negligible s /\ (!x. x IN (t DIFF s) ==> g x = f x)
+        ==> real_integral t f = real_integral t g`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[real_integral] THEN
+  AP_TERM_TAC THEN ABS_TAC THEN MATCH_MP_TAC HAS_REAL_INTEGRAL_SPIKE_EQ THEN
+  ASM_MESON_TAC[]);;
+
+let REAL_NEGLIGIBLE_SUBSET = prove
+ (`!s:real->bool t:real->bool.
+        real_negligible s /\ t SUBSET s ==> real_negligible t`,
+  REWRITE_TAC[real_negligible] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `IMAGE lift s` THEN ASM_SIMP_TAC[IMAGE_SUBSET]);;
+
+let REAL_NEGLIGIBLE_DIFF = prove
+ (`!s t:real->bool. real_negligible s ==> real_negligible(s DIFF t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `s:real->bool` THEN ASM_REWRITE_TAC[SUBSET_DIFF]);;
+
+let REAL_NEGLIGIBLE_INTER = prove
+ (`!s t. real_negligible s \/ real_negligible t ==> real_negligible(s INTER t)`,
+  MESON_TAC[REAL_NEGLIGIBLE_SUBSET; INTER_SUBSET]);;
+
+let REAL_NEGLIGIBLE_UNION = prove
+ (`!s t:real->bool.
+       real_negligible s /\ real_negligible t ==> real_negligible (s UNION t)`,
+  SIMP_TAC[NEGLIGIBLE_UNION; IMAGE_UNION; real_negligible]);;
+
+let REAL_NEGLIGIBLE_UNION_EQ = prove
+ (`!s t:real->bool.
+        real_negligible (s UNION t) <=> real_negligible s /\ real_negligible t`,
+  MESON_TAC[REAL_NEGLIGIBLE_UNION; SUBSET_UNION; REAL_NEGLIGIBLE_SUBSET]);;
+
+let REAL_NEGLIGIBLE_SING = prove
+ (`!a:real. real_negligible {a}`,
+  REWRITE_TAC[real_negligible; NEGLIGIBLE_SING; IMAGE_CLAUSES]);;
+
+let REAL_NEGLIGIBLE_INSERT = prove
+ (`!a:real s. real_negligible(a INSERT s) <=> real_negligible s`,
+  REWRITE_TAC[real_negligible; NEGLIGIBLE_INSERT; IMAGE_CLAUSES]);;
+
+let REAL_NEGLIGIBLE_EMPTY = prove
+ (`real_negligible {}`,
+  REWRITE_TAC[real_negligible; NEGLIGIBLE_EMPTY; IMAGE_CLAUSES]);;
+
+let REAL_NEGLIGIBLE_FINITE = prove
+ (`!s. FINITE s ==> real_negligible s`,
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[REAL_NEGLIGIBLE_EMPTY; REAL_NEGLIGIBLE_INSERT]);;
+
+let REAL_NEGLIGIBLE_UNIONS = prove
+ (`!s. FINITE s /\ (!t. t IN s ==> real_negligible t)
+       ==> real_negligible(UNIONS s)`,
+  REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[UNIONS_0; UNIONS_INSERT; REAL_NEGLIGIBLE_EMPTY; IN_INSERT] THEN
+  SIMP_TAC[REAL_NEGLIGIBLE_UNION]);;
+
+let HAS_REAL_INTEGRAL_SPIKE_FINITE = prove
+ (`!f:real->real g s t y.
+        FINITE s /\ (!x. x IN (t DIFF s) ==> g x = f x) /\
+        (f has_real_integral y) t
+        ==> (g has_real_integral y) t`,
+  MESON_TAC[HAS_REAL_INTEGRAL_SPIKE; REAL_NEGLIGIBLE_FINITE]);;
+
+let HAS_REAL_INTEGRAL_SPIKE_FINITE_EQ = prove
+ (`!f:real->real g s y.
+        FINITE s /\ (!x. x IN (t DIFF s) ==> g x = f x)
+        ==> ((f has_real_integral y) t <=> (g has_real_integral y) t)`,
+  MESON_TAC[HAS_REAL_INTEGRAL_SPIKE_FINITE]);;
+
+let REAL_INTEGRABLE_SPIKE_FINITE = prove
+ (`!f:real->real g s.
+        FINITE s /\ (!x. x IN (t DIFF s) ==> g x = f x)
+        ==> f real_integrable_on t
+            ==> g real_integrable_on  t`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[real_integrable_on] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+  MP_TAC(SPEC_ALL HAS_REAL_INTEGRAL_SPIKE_FINITE) THEN ASM_REWRITE_TAC[]);;
+
+let REAL_NEGLIGIBLE_FRONTIER_INTERVAL = prove
+ (`!a b:real. real_negligible(real_interval[a,b] DIFF real_interval(a,b))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_interval; DIFF; IN_ELIM_THM] THEN
+  MATCH_MP_TAC REAL_NEGLIGIBLE_SUBSET THEN EXISTS_TAC `{(a:real),b}` THEN
+  ASM_SIMP_TAC[REAL_NEGLIGIBLE_FINITE; FINITE_RULES] THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_INSERT; NOT_IN_EMPTY] THEN
+  REAL_ARITH_TAC);;
+
+let HAS_REAL_INTEGRAL_SPIKE_INTERIOR = prove
+ (`!f:real->real g a b y.
+        (!x. x IN real_interval(a,b) ==> g x = f x) /\
+        (f has_real_integral y) (real_interval[a,b])
+        ==> (g has_real_integral y) (real_interval[a,b])`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN DISCH_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`]
+                           HAS_REAL_INTEGRAL_SPIKE) THEN
+  EXISTS_TAC `real_interval[a:real,b] DIFF real_interval(a,b)` THEN
+  REWRITE_TAC[REAL_NEGLIGIBLE_FRONTIER_INTERVAL] THEN ASM SET_TAC[]);;
+
+let HAS_REAL_INTEGRAL_SPIKE_INTERIOR_EQ = prove
+ (`!f:real->real g a b y.
+        (!x. x IN real_interval(a,b) ==> g x = f x)
+        ==> ((f has_real_integral y) (real_interval[a,b]) <=>
+             (g has_real_integral y) (real_interval[a,b]))`,
+  MESON_TAC[HAS_REAL_INTEGRAL_SPIKE_INTERIOR]);;
+
+let REAL_INTEGRABLE_SPIKE_INTERIOR = prove
+ (`!f:real->real g a b.
+        (!x. x IN real_interval(a,b) ==> g x = f x)
+        ==> f real_integrable_on (real_interval[a,b])
+            ==> g real_integrable_on  (real_interval[a,b])`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[real_integrable_on] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+  MP_TAC(SPEC_ALL HAS_REAL_INTEGRAL_SPIKE_INTERIOR) THEN ASM_REWRITE_TAC[]);;
+
+let REAL_INTEGRAL_EQ = prove
+ (`!f g s.
+        (!x. x IN s ==> f x = g x) ==> real_integral s f = real_integral s g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INTEGRAL_SPIKE THEN
+  EXISTS_TAC `{}:real->bool` THEN
+  ASM_SIMP_TAC[REAL_NEGLIGIBLE_EMPTY; IN_DIFF]);;
+
+let REAL_INTEGRAL_EQ_0 = prove
+ (`!f s. (!x. x IN s ==> f x = &0) ==> real_integral s f = &0`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `real_integral s (\x. &0)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_INTEGRAL_EQ THEN ASM_REWRITE_TAC[];
+    REWRITE_TAC[REAL_INTEGRAL_0]]);;
+
+let REAL_INTEGRABLE_CONTINUOUS = prove
+ (`!f a b.
+        f real_continuous_on real_interval[a,b]
+        ==> f real_integrable_on real_interval[a,b]`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON; real_integrable_on; has_real_integral;
+              GSYM integrable_on; GSYM EXISTS_LIFT] THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL; INTEGRABLE_CONTINUOUS]);;
+
+let REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS = prove
+ (`!f f' a b.
+        a <= b /\
+        (!x. x IN real_interval[a,b]
+             ==> (f has_real_derivative f'(x))
+                 (atreal x within real_interval[a,b]))
+        ==> (f' has_real_integral (f(b) - f(a))) (real_interval[a,b])`,
+  REWRITE_TAC[has_real_integral; HAS_REAL_VECTOR_DERIVATIVE_WITHIN] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL; LIFT_SUB] THEN
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; FORALL_IN_IMAGE; LIFT_DROP] THEN
+  GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o BINOP_CONV) [GSYM LIFT_DROP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP FUNDAMENTAL_THEOREM_OF_CALCULUS) THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP]);;
+
+let REAL_INTEGRABLE_SUBINTERVAL = prove
+ (`!f:real->real a b c d.
+        f real_integrable_on real_interval[a,b] /\
+        real_interval[c,d] SUBSET real_interval[a,b]
+        ==> f real_integrable_on real_interval[c,d]`,
+  REWRITE_TAC[real_integrable_on; HAS_REAL_INTEGRAL] THEN
+  REWRITE_TAC[EXISTS_DROP; GSYM integrable_on; LIFT_DROP] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_SUBINTERVAL THEN
+  MAP_EVERY EXISTS_TAC [`lift a`; `lift b`] THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL] THEN
+  ASM_SIMP_TAC[IMAGE_SUBSET]);;
+
+let HAS_REAL_INTEGRAL_COMBINE = prove
+ (`!f i j a b c.
+        a <= c /\ c <= b /\
+        (f has_real_integral i) (real_interval[a,c]) /\
+        (f has_real_integral j) (real_interval[c,b])
+        ==> (f has_real_integral (i + j)) (real_interval[a,b])`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_REAL_INTEGRAL; LIFT_ADD] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_COMBINE THEN
+  EXISTS_TAC `lift c` THEN ASM_REWRITE_TAC[LIFT_DROP]);;
+
+let REAL_INTEGRAL_COMBINE = prove
+ (`!f a b c.
+        a <= c /\ c <= b /\ f real_integrable_on (real_interval[a,b])
+        ==> real_integral(real_interval[a,c]) f +
+            real_integral(real_interval[c,b]) f =
+            real_integral(real_interval[a,b]) f`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_COMBINE THEN
+  EXISTS_TAC `c:real` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THEN
+  MATCH_MP_TAC REAL_INTEGRABLE_INTEGRAL THEN
+  MATCH_MP_TAC REAL_INTEGRABLE_SUBINTERVAL THEN
+  MAP_EVERY EXISTS_TAC [`a:real`; `b:real`] THEN
+  ASM_REWRITE_TAC[SUBSET_REAL_INTERVAL; REAL_LE_REFL]);;
+
+let REAL_INTEGRABLE_COMBINE = prove
+ (`!f a b c.
+        a <= c /\ c <= b /\
+        f real_integrable_on real_interval[a,c] /\
+        f real_integrable_on real_interval[c,b]
+        ==> f real_integrable_on real_interval[a,b]`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_COMBINE]);;
+
+let REAL_INTEGRABLE_ON_LITTLE_SUBINTERVALS = prove
+ (`!f:real->real a b.
+        (!x. x IN real_interval[a,b]
+             ==> ?d. &0 < d /\
+                     !u v. x IN real_interval[u,v] /\
+                           (!y. y IN real_interval[u,v]
+                                ==> abs(y - x) < d /\ y IN real_interval[a,b])
+                           ==> f real_integrable_on real_interval[u,v])
+        ==> f real_integrable_on real_interval[a,b]`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[real_integrable_on; HAS_REAL_INTEGRAL; EXISTS_DROP;
+              GSYM integrable_on; LIFT_DROP] THEN
+  DISCH_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_LITTLE_SUBINTERVALS THEN
+  REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; FORALL_IN_IMAGE] THEN
+  X_GEN_TAC `x:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `x:real`) THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[GSYM EXISTS_DROP; FORALL_LIFT] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  CONJ_TAC THENL
+   [ASM_MESON_TAC[IMAGE_LIFT_REAL_INTERVAL; LIFT_IN_IMAGE_LIFT];
+    REWRITE_TAC[REAL_INTERVAL_INTERVAL; FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `y:real^1` THEN DISCH_TAC THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `y:real^1` o REWRITE_RULE[SUBSET])) THEN
+    ASM_SIMP_TAC[IN_BALL; FUN_IN_IMAGE; dist; NORM_REAL] THEN
+    REWRITE_TAC[GSYM drop; DROP_SUB; LIFT_DROP] THEN SIMP_TAC[REAL_ABS_SUB]]);;
+
+let REAL_INTEGRAL_HAS_REAL_DERIVATIVE = prove
+ (`!f:real->real a b.
+     (f real_continuous_on real_interval[a,b])
+     ==> !x. x IN real_interval[a,b]
+             ==> ((\u. real_integral(real_interval[a,u]) f)
+                  has_real_derivative f(x))
+                 (atreal x within real_interval[a,b])`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[REAL_CONTINUOUS_ON; IMAGE_LIFT_REAL_INTERVAL] THEN
+  DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP INTEGRAL_HAS_VECTOR_DERIVATIVE) THEN
+  REWRITE_TAC[HAS_REAL_VECTOR_DERIVATIVE_WITHIN] THEN
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; LIFT_DROP] THEN
+  DISCH_TAC THEN X_GEN_TAC `x:real^1` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `x:real^1`) THEN
+  ASM_REWRITE_TAC[SET_RULE `IMAGE (\x. x) s = s`] THEN
+  MATCH_MP_TAC(REWRITE_RULE[TAUT
+    `a /\ b /\ c /\ d ==> e <=> a /\ b /\ c ==> d ==> e`]
+     HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN) THEN
+  EXISTS_TAC `&1` THEN ASM_REWRITE_TAC[REAL_LT_01] THEN
+  X_GEN_TAC `y:real^1` THEN STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM DROP_EQ] THEN
+  REWRITE_TAC[LIFT_DROP] THEN CONV_TAC SYM_CONV THEN
+  REWRITE_TAC[INTERVAL_REAL_INTERVAL; GSYM IMAGE_o; LIFT_DROP; o_DEF] THEN
+  REWRITE_TAC[GSYM o_DEF; SET_RULE `IMAGE (\x. x) s = s`] THEN
+  MATCH_MP_TAC REAL_INTEGRAL THEN
+  MATCH_MP_TAC REAL_INTEGRABLE_SUBINTERVAL THEN
+  MAP_EVERY EXISTS_TAC [`a:real`; `b:real`] THEN CONJ_TAC THENL
+   [REWRITE_TAC[REAL_INTEGRABLE_ON; IMAGE_LIFT_REAL_INTERVAL] THEN
+    MATCH_MP_TAC INTEGRABLE_CONTINUOUS THEN ASM_REWRITE_TAC[];
+    ASM_REWRITE_TAC[SUBSET_REAL_INTERVAL] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1])) THEN
+    REWRITE_TAC[LIFT_DROP] THEN REAL_ARITH_TAC]);;
+
+let REAL_ANTIDERIVATIVE_CONTINUOUS = prove
+ (`!f a b.
+     (f real_continuous_on real_interval[a,b])
+     ==> ?g. !x. x IN real_interval[a,b]
+                 ==> (g has_real_derivative f(x))
+                     (atreal x within real_interval[a,b])`,
+  MESON_TAC[REAL_INTEGRAL_HAS_REAL_DERIVATIVE]);;
+
+let REAL_ANTIDERIVATIVE_INTEGRAL_CONTINUOUS = prove
+ (`!f a b.
+     (f real_continuous_on real_interval[a,b])
+     ==> ?g. !u v. u IN real_interval[a,b] /\
+                   v IN real_interval[a,b] /\ u <= v
+                   ==> (f has_real_integral (g(v) - g(u)))
+                       (real_interval[u,v])`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP REAL_ANTIDERIVATIVE_CONTINUOUS) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real->real` THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS THEN
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:real` THEN
+  STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_DERIVATIVE_WITHIN_SUBSET THEN
+  EXISTS_TAC `real_interval[a:real,b]` THEN CONJ_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC; ALL_TAC] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[SUBSET_REAL_INTERVAL; IN_REAL_INTERVAL] THEN REAL_ARITH_TAC);;
+
+let HAS_REAL_INTEGRAL_AFFINITY = prove
+ (`!f:real->real i a b m c.
+        (f has_real_integral i) (real_interval[a,b]) /\ ~(m = &0)
+        ==> ((\x. f(m * x + c)) has_real_integral (inv(abs(m)) * i))
+            (IMAGE (\x. inv m * (x - c)) (real_interval[a,b]))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_REAL_INTEGRAL] THEN
+  DISCH_THEN(MP_TAC o SPEC `lift c` o MATCH_MP HAS_INTEGRAL_AFFINITY) THEN
+  REWRITE_TAC[DIMINDEX_1; REAL_POW_1; has_real_integral] THEN
+  REWRITE_TAC[o_DEF; DROP_ADD; DROP_CMUL; LIFT_DROP; LIFT_CMUL] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[INTERVAL_REAL_INTERVAL; GSYM IMAGE_o; LIFT_DROP] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; o_DEF; LIFT_CMUL; LIFT_SUB] THEN VECTOR_ARITH_TAC);;
+
+let REAL_INTEGRABLE_AFFINITY = prove
+ (`!f a b m c.
+        f real_integrable_on real_interval[a,b] /\ ~(m = &0)
+        ==> (\x. f(m * x + c)) real_integrable_on
+            (IMAGE (\x. inv m * (x - c)) (real_interval[a,b]))`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_AFFINITY]);;
+
+let HAS_REAL_INTEGRAL_STRETCH = prove
+ (`!f:real->real i a b m.
+        (f has_real_integral i) (real_interval[a,b]) /\ ~(m = &0)
+        ==> ((\x. f(m * x)) has_real_integral (inv(abs(m)) * i))
+            (IMAGE (\x. inv m * x) (real_interval[a,b]))`,
+  MP_TAC HAS_REAL_INTEGRAL_AFFINITY THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  DISCH_THEN(MP_TAC o SPEC `&0`) THEN
+  REWRITE_TAC[REAL_ADD_RID; REAL_SUB_RZERO]);;
+
+let REAL_INTEGRABLE_STRETCH = prove
+ (`!f a b m.
+        f real_integrable_on real_interval[a,b] /\ ~(m = &0)
+        ==> (\x. f(m * x)) real_integrable_on
+            (IMAGE (\x. inv m * x) (real_interval[a,b]))`,
+  REWRITE_TAC[real_integrable_on] THEN MESON_TAC[HAS_REAL_INTEGRAL_STRETCH]);;
+
+let HAS_REAL_INTEGRAL_REFLECT_LEMMA = prove
+ (`!f:real->real i a b.
+     (f has_real_integral i) (real_interval[a,b])
+     ==> ((\x. f(--x)) has_real_integral i) (real_interval[--b,--a])`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_REAL_INTEGRAL] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_INTEGRAL_REFLECT_LEMMA) THEN
+  REWRITE_TAC[LIFT_NEG; o_DEF; DROP_NEG]);;
+
+let HAS_REAL_INTEGRAL_REFLECT = prove
+ (`!f:real->real i a b.
+     ((\x. f(--x)) has_real_integral i) (real_interval[--b,--a]) <=>
+     (f has_real_integral i) (real_interval[a,b])`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_REAL_INTEGRAL_REFLECT_LEMMA) THEN
+  REWRITE_TAC[REAL_NEG_NEG; ETA_AX]);;
+
+let REAL_INTEGRABLE_REFLECT = prove
+ (`!f:real->real a b.
+     (\x. f(--x)) real_integrable_on (real_interval[--b,--a]) <=>
+     f real_integrable_on (real_interval[a,b])`,
+  REWRITE_TAC[real_integrable_on; HAS_REAL_INTEGRAL_REFLECT]);;
+
+let REAL_INTEGRAL_REFLECT = prove
+ (`!f:real->real a b.
+     real_integral (real_interval[--b,--a]) (\x. f(--x)) =
+     real_integral (real_interval[a,b]) f`,
+  REWRITE_TAC[real_integral; HAS_REAL_INTEGRAL_REFLECT]);;
+
+let REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR = prove
+ (`!f:real->real f' a b.
+        a <= b /\ f real_continuous_on real_interval[a,b] /\
+        (!x. x IN real_interval(a,b)
+             ==> (f has_real_derivative f'(x)) (atreal x))
+        ==> (f' has_real_integral (f(b) - f(a))) (real_interval[a,b])`,
+  REWRITE_TAC[has_real_integral; HAS_REAL_VECTOR_DERIVATIVE_AT] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL; LIFT_SUB] THEN
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; FORALL_IN_IMAGE; LIFT_DROP] THEN
+  GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o BINOP_CONV) [GSYM LIFT_DROP] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_ON; GSYM IMAGE_o; IMAGE_LIFT_DROP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR) THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP]);;
+
+let REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG = prove
+ (`!f f' s a b.
+        COUNTABLE s /\
+        a <= b /\ f real_continuous_on real_interval[a,b] /\
+        (!x. x IN real_interval(a,b) DIFF s
+             ==> (f has_real_derivative f'(x)) (atreal x))
+        ==> (f' has_real_integral (f(b) - f(a))) (real_interval[a,b])`,
+  REWRITE_TAC[has_real_integral; HAS_REAL_VECTOR_DERIVATIVE_AT] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL; LIFT_SUB] THEN
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; FORALL_IN_IMAGE; IMP_CONJ; IN_DIFF] THEN
+  SUBGOAL_THEN `!x. drop x IN s <=> x IN IMAGE lift s`
+    (fun th -> REWRITE_TAC[th]) THENL [SET_TAC[LIFT_DROP]; ALL_TAC] THEN
+  SUBGOAL_THEN `COUNTABLE s <=> COUNTABLE(IMAGE lift s)` SUBST1_TAC THENL
+   [EQ_TAC THEN SIMP_TAC[COUNTABLE_IMAGE] THEN
+    DISCH_THEN(MP_TAC o ISPEC `drop` o MATCH_MP COUNTABLE_IMAGE) THEN
+    REWRITE_TAC[GSYM IMAGE_o; IMAGE_LIFT_DROP];
+    ALL_TAC] THEN
+  REWRITE_TAC[IMP_IMP; GSYM IN_DIFF; GSYM CONJ_ASSOC] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_ON; GSYM IMAGE_o; IMAGE_LIFT_DROP] THEN
+  REWRITE_TAC[LIFT_DROP] THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o LAND_CONV o BINOP_CONV)
+   [GSYM LIFT_DROP] THEN
+  DISCH_THEN(MP_TAC o
+    MATCH_MP FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG) THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP]);;
+
+let REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS_STRONG = prove
+ (`!f f' s a b.
+        COUNTABLE s /\
+        a <= b /\ f real_continuous_on real_interval[a,b] /\
+        (!x. x IN real_interval[a,b] DIFF s
+             ==> (f has_real_derivative f'(x)) (atreal x))
+        ==> (f' has_real_integral (f(b) - f(a))) (real_interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_FUNDAMENTAL_THEOREM_OF_CALCULUS_INTERIOR_STRONG THEN
+  EXISTS_TAC `s:real->bool` THEN ASM_REWRITE_TAC[] THEN GEN_TAC THEN
+  DISCH_THEN(fun th -> FIRST_X_ASSUM MATCH_MP_TAC THEN MP_TAC th) THEN
+  SIMP_TAC[IN_REAL_INTERVAL; IN_DIFF] THEN REAL_ARITH_TAC);;
+
+let REAL_INDEFINITE_INTEGRAL_CONTINUOUS_RIGHT = prove
+ (`!f:real->real a b.
+        f real_integrable_on real_interval[a,b]
+        ==> (\x. real_integral (real_interval[a,x]) f)
+            real_continuous_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_CONTINUOUS_ON] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REAL_INTEGRABLE_ON]) THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP INDEFINITE_INTEGRAL_CONTINUOUS_RIGHT) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_EQ) THEN
+  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[o_DEF] THEN
+  GEN_REWRITE_TAC I [GSYM DROP_EQ] THEN
+  REWRITE_TAC[INTERVAL_REAL_INTERVAL; LIFT_DROP; GSYM o_DEF] THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC REAL_INTEGRAL THEN
+  MATCH_MP_TAC REAL_INTEGRABLE_SUBINTERVAL THEN
+  MAP_EVERY EXISTS_TAC [`a:real`; `b:real`] THEN
+  ASM_REWRITE_TAC[SUBSET_REAL_INTERVAL] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+  REWRITE_TAC[LIFT_DROP] THEN REAL_ARITH_TAC);;
+
+let REAL_INDEFINITE_INTEGRAL_CONTINUOUS_LEFT = prove
+ (`!f:real->real a b.
+        f real_integrable_on real_interval[a,b]
+        ==> (\x. real_integral (real_interval[x,b]) f)
+            real_continuous_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_CONTINUOUS_ON] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REAL_INTEGRABLE_ON]) THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP INDEFINITE_INTEGRAL_CONTINUOUS_LEFT) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_EQ) THEN
+  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[o_DEF] THEN
+  GEN_REWRITE_TAC I [GSYM DROP_EQ] THEN
+  REWRITE_TAC[INTERVAL_REAL_INTERVAL; LIFT_DROP; GSYM o_DEF] THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC REAL_INTEGRAL THEN
+  MATCH_MP_TAC REAL_INTEGRABLE_SUBINTERVAL THEN
+  MAP_EVERY EXISTS_TAC [`a:real`; `b:real`] THEN
+  ASM_REWRITE_TAC[SUBSET_REAL_INTERVAL] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERVAL_1]) THEN
+  REWRITE_TAC[LIFT_DROP] THEN REAL_ARITH_TAC);;
+
+let HAS_REAL_DERIVATIVE_ZERO_UNIQUE_STRONG_INTERVAL = prove
+ (`!f:real->real a b k y.
+        COUNTABLE k /\ f real_continuous_on real_interval[a,b] /\ f a = y /\
+        (!x. x IN (real_interval[a,b] DIFF k)
+             ==> (f has_real_derivative &0)
+                 (atreal x within real_interval[a,b]))
+        ==> !x. x IN real_interval[a,b] ==> f x = y`,
+  REWRITE_TAC[has_real_integral; HAS_REAL_VECTOR_DERIVATIVE_WITHIN] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL; LIFT_SUB] THEN
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; FORALL_IN_IMAGE; IMP_CONJ; IN_DIFF] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_ON; IMP_IMP; GSYM IMAGE_o; IMAGE_LIFT_DROP] THEN
+  REWRITE_TAC[GSYM IMP_CONJ; LIFT_DROP; has_vector_derivative] THEN
+  REWRITE_TAC[LIFT_NUM; VECTOR_MUL_RZERO] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`lift o f o drop`; `lift a`; `lift b`; `IMAGE lift k`; `lift y`]
+   HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_INTERVAL) THEN
+  ASM_SIMP_TAC[COUNTABLE_IMAGE; o_THM; LIFT_DROP; LIFT_EQ; IN_DIFF] THEN
+  DISCH_THEN MATCH_MP_TAC THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM SET_TAC[LIFT_DROP]);;
+
+let HAS_REAL_DERIVATIVE_ZERO_UNIQUE_STRONG_CONVEX = prove
+ (`!f:real->real s k c y.
+      is_realinterval s /\ COUNTABLE k /\ f real_continuous_on s /\
+      c IN s /\ f c = y /\
+      (!x. x IN (s DIFF k) ==> (f has_real_derivative &0) (atreal x within s))
+      ==> !x. x IN s ==> f x = y`,
+  REWRITE_TAC[has_real_integral; HAS_REAL_VECTOR_DERIVATIVE_WITHIN] THEN
+  REWRITE_TAC[IS_REALINTERVAL_CONVEX; REAL_CONTINUOUS_ON] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL; LIFT_SUB] THEN
+  REWRITE_TAC[REAL_INTERVAL_INTERVAL; FORALL_IN_IMAGE; IMP_CONJ; IN_DIFF] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_ON; IMP_IMP; GSYM IMAGE_o; IMAGE_LIFT_DROP] THEN
+  REWRITE_TAC[GSYM IMP_CONJ; LIFT_DROP; has_vector_derivative] THEN
+  REWRITE_TAC[LIFT_NUM; VECTOR_MUL_RZERO] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`lift o f o drop`; `IMAGE lift s`; `IMAGE lift k`; `lift c`; `lift y`]
+   HAS_DERIVATIVE_ZERO_UNIQUE_STRONG_CONVEX) THEN
+  ASM_SIMP_TAC[COUNTABLE_IMAGE; o_THM; LIFT_DROP; LIFT_EQ; IN_DIFF] THEN
+  ASM_REWRITE_TAC[LIFT_IN_IMAGE_LIFT; FORALL_IN_IMAGE; LIFT_DROP] THEN
+  ASM_SIMP_TAC[IMP_CONJ; FORALL_IN_IMAGE; LIFT_IN_IMAGE_LIFT]);;
+
+let HAS_REAL_DERIVATIVE_INDEFINITE_INTEGRAL = prove
+ (`!f a b.
+        f real_integrable_on real_interval[a,b]
+        ==> ?k. real_negligible k /\
+                !x. x IN real_interval[a,b] DIFF k
+                    ==> ((\x. real_integral(real_interval[a,x]) f)
+                         has_real_derivative
+                         f(x)) (atreal x within real_interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `lift a`; `lift b`]
+        HAS_VECTOR_DERIVATIVE_INDEFINITE_INTEGRAL) THEN
+  ASM_REWRITE_TAC[GSYM REAL_INTEGRABLE_ON; GSYM IMAGE_LIFT_REAL_INTERVAL] THEN
+  REWRITE_TAC[IN_DIFF; FORALL_IN_IMAGE; IMP_CONJ] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real^1->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `IMAGE drop k` THEN
+  ASM_REWRITE_TAC[real_negligible; HAS_REAL_VECTOR_DERIVATIVE_WITHIN] THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_o; IMAGE_LIFT_DROP] THEN
+  REWRITE_TAC[IN_IMAGE; GSYM LIFT_EQ; LIFT_DROP; UNWIND_THM1] THEN
+  X_GEN_TAC `x:real` THEN REPEAT DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `x:real`) THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[o_THM; LIFT_DROP] THEN MATCH_MP_TAC(REWRITE_RULE
+   [TAUT `a /\ b /\ c /\ d ==> e <=> a /\ b /\ c ==> d ==> e`]
+        HAS_VECTOR_DERIVATIVE_TRANSFORM_WITHIN) THEN
+  EXISTS_TAC `&1` THEN ASM_SIMP_TAC[FUN_IN_IMAGE; REAL_LT_01] THEN
+  REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE] THEN
+  X_GEN_TAC `y:real` THEN REPEAT DISCH_TAC THEN
+  REWRITE_TAC[GSYM DROP_EQ; LIFT_DROP; o_THM] THEN
+  REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL] THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC REAL_INTEGRAL THEN
+  MATCH_MP_TAC REAL_INTEGRABLE_SUBINTERVAL THEN
+  MAP_EVERY EXISTS_TAC [`a:real`; `b:real`] THEN
+  ASM_REWRITE_TAC[SUBSET_REAL_INTERVAL] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_REAL_INTERVAL]) THEN
+  ASM_REAL_ARITH_TAC);;
+
+let HAS_REAL_INTEGRAL_RESTRICT = prove
+ (`!f:real->real s t.
+        s SUBSET t
+        ==> (((\x. if x IN s then f x else &0) has_real_integral i) t <=>
+             (f has_real_integral i) s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[has_real_integral; o_DEF] THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `IMAGE lift s`; `IMAGE lift t`; `lift i`]
+        HAS_INTEGRAL_RESTRICT) THEN
+  ASM_SIMP_TAC[IMAGE_SUBSET; IN_IMAGE_LIFT_DROP; o_DEF] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN REWRITE_TAC[LIFT_NUM]);;
+
+let HAS_REAL_INTEGRAL_RESTRICT_UNIV = prove
+ (`!f:real->real s i.
+        ((\x. if x IN s then f x else &0) has_real_integral i) (:real) <=>
+         (f has_real_integral i) s`,
+  SIMP_TAC[HAS_REAL_INTEGRAL_RESTRICT; SUBSET_UNIV]);;
+
+let HAS_REAL_INTEGRAL_SPIKE_SET_EQ = prove
+ (`!f s t y.
+        real_negligible(s DIFF t UNION t DIFF s)
+        ==> ((f has_real_integral y) s <=> (f has_real_integral y) t)`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM HAS_REAL_INTEGRAL_RESTRICT_UNIV] THEN
+  MATCH_MP_TAC HAS_REAL_INTEGRAL_SPIKE_EQ THEN
+  EXISTS_TAC `s DIFF t UNION t DIFF s:real->bool` THEN
+  ASM_REWRITE_TAC[] THEN SET_TAC[]);;
+
+let HAS_REAL_INTEGRAL_SPIKE_SET = prove
+ (`!f s t y.
+        real_negligible(s DIFF t UNION t DIFF s) /\
+        (f has_real_integral y) s
+        ==> (f has_real_integral y) t`,
+  MESON_TAC[HAS_REAL_INTEGRAL_SPIKE_SET_EQ]);;
+
+let REAL_INTEGRABLE_SPIKE_SET = prove
+ (`!f s t.
+        real_negligible(s DIFF t UNION t DIFF s)
+        ==> f real_integrable_on s ==> f real_integrable_on t`,
+  REWRITE_TAC[real_integrable_on] THEN
+  MESON_TAC[HAS_REAL_INTEGRAL_SPIKE_SET_EQ]);;
+
+let REAL_INTEGRABLE_SPIKE_SET_EQ = prove
+ (`!f s t.
+        real_negligible(s DIFF t UNION t DIFF s)
+        ==> (f real_integrable_on s <=> f real_integrable_on t)`,
+  MESON_TAC[REAL_INTEGRABLE_SPIKE_SET; UNION_COMM]);;
+
+let REAL_INTEGRAL_SPIKE_SET = prove
+ (`!f s t.
+        real_negligible(s DIFF t UNION t DIFF s)
+        ==> real_integral s f = real_integral t f`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[real_integral] THEN
+  AP_TERM_TAC THEN ABS_TAC THEN MATCH_MP_TAC HAS_REAL_INTEGRAL_SPIKE_SET_EQ THEN
+  ASM_MESON_TAC[]);;
+
+let HAS_REAL_INTEGRAL_OPEN_INTERVAL = prove
+ (`!f a b y. (f has_real_integral y) (real_interval(a,b)) <=>
+             (f has_real_integral y) (real_interval[a,b])`,
+  REWRITE_TAC[has_real_integral; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REWRITE_TAC[HAS_INTEGRAL_OPEN_INTERVAL]);;
+
+let REAL_INTEGRABLE_ON_OPEN_INTERVAL = prove
+ (`!f a b. f real_integrable_on real_interval(a,b) <=>
+           f real_integrable_on real_interval[a,b]`,
+  REWRITE_TAC[real_integrable_on; HAS_REAL_INTEGRAL_OPEN_INTERVAL]);;
+
+let REAL_INTEGRAL_OPEN_INTERVAL = prove
+ (`!f a b. real_integral(real_interval(a,b)) f =
+           real_integral(real_interval[a,b]) f`,
+  REWRITE_TAC[real_integral; HAS_REAL_INTEGRAL_OPEN_INTERVAL]);;
+
+let HAS_REAL_INTEGRAL_ON_SUPERSET = prove
+ (`!f s t.
+        (!x. ~(x IN s) ==> f x = &0) /\ s SUBSET t /\ (f has_real_integral i) s
+        ==> (f has_real_integral i) t`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[SUBSET] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  ONCE_REWRITE_TAC[GSYM HAS_REAL_INTEGRAL_RESTRICT_UNIV] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_THM_TAC THEN
+  AP_TERM_TAC THEN ABS_TAC THEN ASM_MESON_TAC[]);;
+
+let REAL_INTEGRABLE_ON_SUPERSET = prove
+ (`!f s t.
+        (!x. ~(x IN s) ==> f x = &0) /\ s SUBSET t /\ f real_integrable_on s
+        ==> f real_integrable_on t`,
+  REWRITE_TAC[real_integrable_on] THEN
+  MESON_TAC[HAS_REAL_INTEGRAL_ON_SUPERSET]);;
+
+let REAL_INTEGRABLE_RESTRICT_UNIV = prove
+ (`!f s. (\x. if x IN s then f x else &0) real_integrable_on (:real) <=>
+         f real_integrable_on s`,
+  REWRITE_TAC[real_integrable_on; HAS_REAL_INTEGRAL_RESTRICT_UNIV]);;
+
+let REAL_INTEGRAL_RESTRICT_UNIV = prove
+ (`!f s.
+     real_integral (:real) (\x. if x IN s then f x else &0) =
+     real_integral s f`,
+  REWRITE_TAC[real_integral; HAS_REAL_INTEGRAL_RESTRICT_UNIV]);;
+
+let REAL_INTEGRAL_RESTRICT = prove
+ (`!f s t.
+        s SUBSET t
+        ==> real_integral t (\x. if x IN s then f x else &0) =
+            real_integral s f`,
+  SIMP_TAC[real_integral; HAS_REAL_INTEGRAL_RESTRICT]);;
+
+let HAS_REAL_INTEGRAL_RESTRICT_INTER = prove
+ (`!f s t.
+        ((\x. if x IN s then f x else &0) has_real_integral i) t <=>
+        (f has_real_integral i) (s INTER t)`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[GSYM HAS_REAL_INTEGRAL_RESTRICT_UNIV] THEN
+  REWRITE_TAC[IN_INTER] THEN AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN MESON_TAC[]);;
+
+let REAL_INTEGRAL_RESTRICT_INTER = prove
+ (`!f s t.
+        real_integral t (\x. if x IN s then f x else &0) =
+        real_integral (s INTER t) f`,
+  REWRITE_TAC[real_integral; HAS_REAL_INTEGRAL_RESTRICT_INTER]);;
+
+let REAL_INTEGRABLE_RESTRICT_INTER = prove
+ (`!f s t.
+        (\x. if x IN s then f x else &0) real_integrable_on t <=>
+        f real_integrable_on (s INTER t)`,
+  REWRITE_TAC[real_integrable_on; HAS_REAL_INTEGRAL_RESTRICT_INTER]);;
+
+let REAL_NEGLIGIBLE_ON_INTERVALS = prove
+ (`!s. real_negligible s <=>
+         !a b:real. real_negligible(s INTER real_interval[a,b])`,
+  GEN_TAC THEN REWRITE_TAC[real_negligible] THEN
+  GEN_REWRITE_TAC LAND_CONV [NEGLIGIBLE_ON_INTERVALS] THEN
+  REWRITE_TAC[FORALL_LIFT; GSYM IMAGE_LIFT_REAL_INTERVAL] THEN
+  REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN AP_TERM_TAC THEN SET_TAC[LIFT_DROP]);;
+
+let HAS_REAL_INTEGRAL_SUBSET_LE = prove
+ (`!f:real->real s t i j.
+        s SUBSET t /\ (f has_real_integral i) s /\ (f has_real_integral j) t /\
+        (!x. x IN t ==> &0 <= f x)
+        ==> i <= j`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_INTEGRAL_LE THEN
+  MAP_EVERY EXISTS_TAC
+   [`\x:real. if x IN s then f(x) else &0`;
+    `\x:real. if x IN t then f(x) else &0`; `(:real)`] THEN
+  ASM_REWRITE_TAC[HAS_REAL_INTEGRAL_RESTRICT_UNIV; IN_UNIV] THEN
+  X_GEN_TAC `x:real` THEN
+  REPEAT(COND_CASES_TAC THEN ASM_SIMP_TAC[REAL_LE_REFL]) THEN
+  ASM SET_TAC[]);;
+
+let REAL_INTEGRAL_SUBSET_LE = prove
+ (`!f:real->real s t.
+        s SUBSET t /\ f real_integrable_on s /\ f real_integrable_on t /\
+        (!x. x IN t ==> &0 <= f(x))
+        ==> real_integral s f <= real_integral t f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_INTEGRAL_SUBSET_LE THEN
+  ASM_MESON_TAC[REAL_INTEGRABLE_INTEGRAL]);;
+
+let REAL_INTEGRABLE_ON_SUBINTERVAL = prove
+ (`!f:real->real s a b.
+        f real_integrable_on s /\ real_interval[a,b] SUBSET s
+        ==> f real_integrable_on real_interval[a,b]`,
+  REWRITE_TAC[REAL_INTEGRABLE_ON; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_ON_SUBINTERVAL THEN
+  EXISTS_TAC `IMAGE lift s` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL] THEN
+  ASM_SIMP_TAC[IMAGE_SUBSET]);;
+
+let REAL_INTEGRABLE_STRADDLE = prove
+ (`!f s.
+        (!e. &0 < e
+             ==> ?g h i j. (g has_real_integral i) s /\
+                           (h has_real_integral j) s /\
+                           abs(i - j) < e /\
+                           !x. x IN s ==> g x <= f x /\ f x <= h x)
+        ==> f real_integrable_on s`,
+  REWRITE_TAC[REAL_INTEGRABLE_ON; has_real_integral] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRABLE_STRADDLE THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[EXISTS_DROP; FORALL_IN_IMAGE] THEN
+  SIMP_TAC[LEFT_IMP_EXISTS_THM; GSYM DROP_SUB; LIFT_DROP; GSYM ABS_DROP] THEN
+  MAP_EVERY X_GEN_TAC
+   [`g:real->real`; `h:real->real`; `i:real^1`; `j:real^1`] THEN
+  STRIP_TAC THEN MAP_EVERY EXISTS_TAC
+   [`lift o g o drop`; `lift o h o drop`; `i:real^1`; `j:real^1`] THEN
+  ASM_REWRITE_TAC[o_THM; LIFT_DROP]);;
+
+let HAS_REAL_INTEGRAL_STRADDLE_NULL = prove
+ (`!f g s. (!x. x IN s ==> &0 <= f x /\ f x <= g x) /\
+           (g has_real_integral &0) s
+           ==> (f has_real_integral &0) s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[HAS_REAL_INTEGRAL_INTEGRABLE_INTEGRAL] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_INTEGRABLE_STRADDLE THEN
+    GEN_TAC THEN DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC
+     [`(\x. &0):real->real`; `g:real->real`;
+      `&0:real`; `&0:real`] THEN
+    ASM_REWRITE_TAC[HAS_REAL_INTEGRAL_0; REAL_SUB_REFL; REAL_ABS_NUM];
+    DISCH_TAC THEN REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC(ISPECL [`f:real->real`; `g:real->real`]
+        HAS_REAL_INTEGRAL_LE);
+      MATCH_MP_TAC(ISPECL [`(\x. &0):real->real`; `f:real->real`]
+        HAS_REAL_INTEGRAL_LE)] THEN
+    EXISTS_TAC `s:real->bool` THEN
+    ASM_SIMP_TAC[GSYM HAS_REAL_INTEGRAL_INTEGRAL; HAS_REAL_INTEGRAL_0]]);;
+
+let HAS_REAL_INTEGRAL_UNION = prove
+ (`!f i j s t.
+        (f has_real_integral i) s /\ (f has_real_integral j) t /\
+        real_negligible(s INTER t)
+        ==> (f has_real_integral (i + j)) (s UNION t)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[has_real_integral; real_negligible; LIFT_ADD; IMAGE_UNION] THEN
+  DISCH_TAC THEN MATCH_MP_TAC HAS_INTEGRAL_UNION THEN POP_ASSUM MP_TAC THEN
+  REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THEN REWRITE_TAC[] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN SET_TAC[LIFT_DROP]);;
+
+let HAS_REAL_INTEGRAL_UNIONS = prove
+ (`!f:real->real i t.
+        FINITE t /\
+        (!s. s IN t ==> (f has_real_integral (i s)) s) /\
+        (!s s'. s IN t /\ s' IN t /\ ~(s = s') ==> real_negligible(s INTER s'))
+        ==> (f has_real_integral (sum t i)) (UNIONS t)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[has_real_integral; real_negligible; LIFT_ADD; IMAGE_UNIONS] THEN
+  SIMP_TAC[LIFT_SUM] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `\s. lift(i(IMAGE drop s))`;
+                 `IMAGE (IMAGE lift) t`]
+    HAS_INTEGRAL_UNIONS) THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM;
+               IMAGE_LIFT_DROP; GSYM IMAGE_o] THEN
+  ASM_SIMP_TAC[LIFT_EQ; SET_RULE
+   `(!x y. f x = f y <=> x = y)
+    ==> (IMAGE f s = IMAGE f t <=> s = t) /\
+        (IMAGE f s INTER IMAGE f t = IMAGE f (s INTER t))`] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) VSUM_IMAGE o lhand o snd) THEN
+  ANTS_TAC THENL [ASM SET_TAC[LIFT_DROP]; ALL_TAC] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[o_DEF; GSYM IMAGE_o; IMAGE_LIFT_DROP]);;
+
+let REAL_MONOTONE_CONVERGENCE_INCREASING = prove
+ (`!f:num->real->real g s.
+        (!k. (f k) real_integrable_on s) /\
+        (!k x. x IN s ==> f k x <= f (SUC k) x) /\
+        (!x. x IN s ==> ((\k. f k x) ---> g x) sequentially) /\
+        real_bounded {real_integral s (f k) | k IN (:num)}
+        ==> g real_integrable_on s /\
+            ((\k. real_integral s (f k)) ---> real_integral s g) sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_INTEGRABLE_ON; TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n x. lift(f (n:num) (drop x))`;
+                 `lift o g o drop`;  `IMAGE lift s`]
+                MONOTONE_CONVERGENCE_INCREASING) THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; LIFT_DROP; o_DEF] THEN
+  SUBGOAL_THEN
+   `!k:num. real_integral s (f k) =
+            drop(integral (IMAGE lift s) (lift o f k o drop))`
+   (fun th -> RULE_ASSUM_TAC(REWRITE_RULE[th]) THEN REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN MATCH_MP_TAC REAL_INTEGRAL THEN
+    ASM_REWRITE_TAC[REAL_INTEGRABLE_ON; o_DEF];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [real_bounded]) THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV; GSYM ABS_DROP] THEN
+  DISCH_THEN(X_CHOOSE_TAC `B:real`) THEN ANTS_TAC THENL
+   [REWRITE_TAC[bounded] THEN EXISTS_TAC `B:real` THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[o_DEF]) THEN
+    ASM_REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV];
+    ALL_TAC] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  ONCE_REWRITE_TAC[GSYM DROP_EQ] THEN REWRITE_TAC[LIFT_DROP] THEN
+  CONV_TAC SYM_CONV THEN REWRITE_TAC[GSYM o_DEF] THEN
+  MATCH_MP_TAC REAL_INTEGRAL THEN ASM_REWRITE_TAC[REAL_INTEGRABLE_ON; o_DEF]);;
+
+let REAL_MONOTONE_CONVERGENCE_DECREASING = prove
+ (`!f:num->real->real g s.
+        (!k. (f k) real_integrable_on s) /\
+        (!k x. x IN s ==> f (SUC k) x <= f k x) /\
+        (!x. x IN s ==> ((\k. f k x) ---> g x) sequentially) /\
+        real_bounded {real_integral s (f k) | k IN (:num)}
+        ==> g real_integrable_on s /\
+            ((\k. real_integral s (f k)) ---> real_integral s g) sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_INTEGRABLE_ON; TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n x. lift(f (n:num) (drop x))`;
+                 `lift o g o drop`;  `IMAGE lift s`]
+                MONOTONE_CONVERGENCE_DECREASING) THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; LIFT_DROP; o_DEF] THEN
+  SUBGOAL_THEN
+   `!k:num. real_integral s (f k) =
+            drop(integral (IMAGE lift s) (lift o f k o drop))`
+   (fun th -> RULE_ASSUM_TAC(REWRITE_RULE[th]) THEN REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN MATCH_MP_TAC REAL_INTEGRAL THEN
+    ASM_REWRITE_TAC[REAL_INTEGRABLE_ON; o_DEF];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [real_bounded]) THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV; GSYM ABS_DROP] THEN
+  DISCH_THEN(X_CHOOSE_TAC `B:real`) THEN ANTS_TAC THENL
+   [REWRITE_TAC[bounded] THEN EXISTS_TAC `B:real` THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[o_DEF]) THEN
+    ASM_REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV];
+    ALL_TAC] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  ONCE_REWRITE_TAC[GSYM DROP_EQ] THEN REWRITE_TAC[LIFT_DROP] THEN
+  CONV_TAC SYM_CONV THEN REWRITE_TAC[GSYM o_DEF] THEN
+  MATCH_MP_TAC REAL_INTEGRAL THEN ASM_REWRITE_TAC[REAL_INTEGRABLE_ON; o_DEF]);;
+
+let REAL_BEPPO_LEVI_INCREASING = prove
+ (`!f s. (!k. (f k) real_integrable_on s) /\
+         (!k x. x IN s ==> f k x <= f (SUC k) x) /\
+         real_bounded {real_integral s (f k) | k IN (:num)}
+         ==> ?g k. real_negligible k /\
+                   !x. x IN (s DIFF k) ==> ((\k. f k x) ---> g x) sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_INTEGRABLE_ON; TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n x. lift(f (n:num) (drop x))`;
+                 `IMAGE lift s`]
+                BEPPO_LEVI_INCREASING) THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; LIFT_DROP; o_DEF] THEN
+  SUBGOAL_THEN
+   `!k:num. real_integral s (f k) =
+            drop(integral (IMAGE lift s) (lift o f k o drop))`
+   (fun th -> RULE_ASSUM_TAC(REWRITE_RULE[th]) THEN REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN MATCH_MP_TAC REAL_INTEGRAL THEN
+    ASM_REWRITE_TAC[REAL_INTEGRABLE_ON; o_DEF];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [real_bounded]) THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV; GSYM ABS_DROP] THEN
+  DISCH_THEN(X_CHOOSE_TAC `B:real`) THEN ANTS_TAC THENL
+   [REWRITE_TAC[bounded] THEN EXISTS_TAC `B:real` THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[o_DEF]) THEN
+    ASM_REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV];
+    ALL_TAC] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; IN_DIFF; IMP_CONJ; FORALL_IN_IMAGE] THEN
+  MAP_EVERY X_GEN_TAC [`g:real^1->real^1`; `k:real^1->bool`] THEN
+  REWRITE_TAC[IMP_IMP; LIFT_DROP] THEN STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`drop o g o lift`; `IMAGE drop k`] THEN
+  ASM_REWRITE_TAC[real_negligible; GSYM IMAGE_o; IMAGE_LIFT_DROP] THEN
+  ASM_REWRITE_TAC[IN_IMAGE_LIFT_DROP; o_THM; LIFT_DROP]);;
+
+let REAL_BEPPO_LEVI_DECREASING = prove
+ (`!f s. (!k. (f k) real_integrable_on s) /\
+         (!k x. x IN s ==> f (SUC k) x <= f k x) /\
+         real_bounded {real_integral s (f k) | k IN (:num)}
+         ==> ?g k. real_negligible k /\
+                   !x. x IN (s DIFF k) ==> ((\k. f k x) ---> g x) sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_INTEGRABLE_ON; TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n x. lift(f (n:num) (drop x))`;
+                 `IMAGE lift s`]
+                BEPPO_LEVI_DECREASING) THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; LIFT_DROP; o_DEF] THEN
+  SUBGOAL_THEN
+   `!k:num. real_integral s (f k) =
+            drop(integral (IMAGE lift s) (lift o f k o drop))`
+   (fun th -> RULE_ASSUM_TAC(REWRITE_RULE[th]) THEN REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN MATCH_MP_TAC REAL_INTEGRAL THEN
+    ASM_REWRITE_TAC[REAL_INTEGRABLE_ON; o_DEF];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [real_bounded]) THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV; GSYM ABS_DROP] THEN
+  DISCH_THEN(X_CHOOSE_TAC `B:real`) THEN ANTS_TAC THENL
+   [REWRITE_TAC[bounded] THEN EXISTS_TAC `B:real` THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[o_DEF]) THEN
+    ASM_REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV];
+    ALL_TAC] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; IN_DIFF; IMP_CONJ; FORALL_IN_IMAGE] THEN
+  MAP_EVERY X_GEN_TAC [`g:real^1->real^1`; `k:real^1->bool`] THEN
+  REWRITE_TAC[IMP_IMP; LIFT_DROP] THEN STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`drop o g o lift`; `IMAGE drop k`] THEN
+  ASM_REWRITE_TAC[real_negligible; GSYM IMAGE_o; IMAGE_LIFT_DROP] THEN
+  ASM_REWRITE_TAC[IN_IMAGE_LIFT_DROP; o_THM; LIFT_DROP]);;
+
+let REAL_BEPPO_LEVI_MONOTONE_CONVERGENCE_INCREASING = prove
+ (`!f s.
+     (!k. (f k) real_integrable_on s) /\
+     (!k x. x IN s ==> f k x <= f (SUC k) x) /\
+     real_bounded {real_integral s (f k) | k IN (:num)}
+     ==> ?g k. real_negligible k /\
+               (!x. x IN (s DIFF k) ==> ((\k. f k x) ---> g x) sequentially) /\
+               g real_integrable_on s /\
+               ((\k. real_integral s (f k)) ---> real_integral s g)
+               sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_INTEGRABLE_ON; TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n x. lift(f (n:num) (drop x))`;
+                 `IMAGE lift s`]
+                BEPPO_LEVI_MONOTONE_CONVERGENCE_INCREASING) THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; LIFT_DROP; o_DEF] THEN
+  SUBGOAL_THEN
+   `!k:num. real_integral s (f k) =
+            drop(integral (IMAGE lift s) (lift o f k o drop))`
+   (fun th -> RULE_ASSUM_TAC(REWRITE_RULE[th]) THEN REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN MATCH_MP_TAC REAL_INTEGRAL THEN
+    ASM_REWRITE_TAC[REAL_INTEGRABLE_ON; o_DEF];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [real_bounded]) THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV; GSYM ABS_DROP] THEN
+  DISCH_THEN(X_CHOOSE_TAC `B:real`) THEN ANTS_TAC THENL
+   [REWRITE_TAC[bounded] THEN EXISTS_TAC `B:real` THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[o_DEF]) THEN
+    ASM_REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV];
+    ALL_TAC] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; IN_DIFF; IMP_CONJ; FORALL_IN_IMAGE] THEN
+  MAP_EVERY X_GEN_TAC [`g:real^1->real^1`; `k:real^1->bool`] THEN
+  REWRITE_TAC[IMP_IMP; LIFT_DROP] THEN STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`drop o g o lift`; `IMAGE drop k`] THEN
+  ASM_REWRITE_TAC[real_negligible; GSYM IMAGE_o; IMAGE_LIFT_DROP] THEN
+  ASM_REWRITE_TAC[IN_IMAGE_LIFT_DROP; o_THM; LIFT_DROP; ETA_AX] THEN
+  SUBGOAL_THEN
+   `real_integral s (drop o g o lift) =
+            drop(integral (IMAGE lift s) (lift o (drop o g o lift) o drop))`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC REAL_INTEGRAL THEN
+    ASM_REWRITE_TAC[REAL_INTEGRABLE_ON; o_DEF; LIFT_DROP; ETA_AX];
+    ASM_REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX]]);;
+
+let REAL_BEPPO_LEVI_MONOTONE_CONVERGENCE_DECREASING = prove
+ (`!f s.
+     (!k. (f k) real_integrable_on s) /\
+     (!k x. x IN s ==> f (SUC k) x <= f k x) /\
+     real_bounded {real_integral s (f k) | k IN (:num)}
+     ==> ?g k. real_negligible k /\
+               (!x. x IN (s DIFF k) ==> ((\k. f k x) ---> g x) sequentially) /\
+               g real_integrable_on s /\
+               ((\k. real_integral s (f k)) ---> real_integral s g)
+               sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_INTEGRABLE_ON; TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n x. lift(f (n:num) (drop x))`;
+                 `IMAGE lift s`]
+                BEPPO_LEVI_MONOTONE_CONVERGENCE_DECREASING) THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; LIFT_DROP; o_DEF] THEN
+  SUBGOAL_THEN
+   `!k:num. real_integral s (f k) =
+            drop(integral (IMAGE lift s) (lift o f k o drop))`
+   (fun th -> RULE_ASSUM_TAC(REWRITE_RULE[th]) THEN REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN MATCH_MP_TAC REAL_INTEGRAL THEN
+    ASM_REWRITE_TAC[REAL_INTEGRABLE_ON; o_DEF];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [real_bounded]) THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV; GSYM ABS_DROP] THEN
+  DISCH_THEN(X_CHOOSE_TAC `B:real`) THEN ANTS_TAC THENL
+   [REWRITE_TAC[bounded] THEN EXISTS_TAC `B:real` THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[o_DEF]) THEN
+    ASM_REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV];
+    ALL_TAC] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; IN_DIFF; IMP_CONJ; FORALL_IN_IMAGE] THEN
+  MAP_EVERY X_GEN_TAC [`g:real^1->real^1`; `k:real^1->bool`] THEN
+  REWRITE_TAC[IMP_IMP; LIFT_DROP] THEN STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`drop o g o lift`; `IMAGE drop k`] THEN
+  ASM_REWRITE_TAC[real_negligible; GSYM IMAGE_o; IMAGE_LIFT_DROP] THEN
+  ASM_REWRITE_TAC[IN_IMAGE_LIFT_DROP; o_THM; LIFT_DROP; ETA_AX] THEN
+  SUBGOAL_THEN
+   `real_integral s (drop o g o lift) =
+            drop(integral (IMAGE lift s) (lift o (drop o g o lift) o drop))`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC REAL_INTEGRAL THEN
+    ASM_REWRITE_TAC[REAL_INTEGRABLE_ON; o_DEF; LIFT_DROP; ETA_AX];
+    ASM_REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX]]);;
+
+let REAL_INTEGRAL_ABS_BOUND_INTEGRAL = prove
+ (`!f:real->real g s.
+        f real_integrable_on s /\ g real_integrable_on s /\
+        (!x. x IN s ==> abs(f x) <= g x)
+        ==> abs(real_integral s f) <= real_integral s g`,
+  SIMP_TAC[REAL_INTEGRAL; GSYM ABS_DROP] THEN
+  SIMP_TAC[REAL_INTEGRABLE_ON; INTEGRAL_NORM_BOUND_INTEGRAL] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP; NORM_LIFT]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_LE = prove
+ (`!f:real->real s.
+        f absolutely_real_integrable_on s
+        ==> abs(real_integral s f) <= real_integral s (\x. abs(f x))`,
+  SIMP_TAC[absolutely_real_integrable_on] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INTEGRAL_ABS_BOUND_INTEGRAL THEN
+  ASM_REWRITE_TAC[REAL_LE_REFL]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_0 = prove
+ (`!s. (\x. &0) absolutely_real_integrable_on s`,
+  REWRITE_TAC[absolutely_real_integrable_on; REAL_ABS_NUM;
+              REAL_INTEGRABLE_0]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_CONST = prove
+ (`!a b c. (\x. c) absolutely_real_integrable_on real_interval[a,b]`,
+  REWRITE_TAC[absolutely_real_integrable_on; REAL_INTEGRABLE_CONST]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_LMUL = prove
+ (`!f s c. f absolutely_real_integrable_on s
+           ==> (\x. c * f(x)) absolutely_real_integrable_on s`,
+  SIMP_TAC[absolutely_real_integrable_on;
+           REAL_INTEGRABLE_LMUL; REAL_ABS_MUL]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_RMUL = prove
+ (`!f s c. f absolutely_real_integrable_on s
+           ==> (\x. f(x) * c) absolutely_real_integrable_on s`,
+  SIMP_TAC[absolutely_real_integrable_on;
+           REAL_INTEGRABLE_RMUL; REAL_ABS_MUL]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_NEG = prove
+ (`!f s. f absolutely_real_integrable_on s
+         ==> (\x. --f(x)) absolutely_real_integrable_on s`,
+  SIMP_TAC[absolutely_real_integrable_on; REAL_INTEGRABLE_NEG; REAL_ABS_NEG]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_ABS = prove
+ (`!f s. f absolutely_real_integrable_on s
+         ==> (\x. abs(f x)) absolutely_real_integrable_on s`,
+  SIMP_TAC[absolutely_real_integrable_on; REAL_ABS_ABS]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_ON_SUBINTERVAL = prove
+ (`!f:real->real s a b.
+        f absolutely_real_integrable_on s /\ real_interval[a,b] SUBSET s
+        ==> f absolutely_real_integrable_on real_interval[a,b]`,
+  REWRITE_TAC[absolutely_real_integrable_on] THEN
+  MESON_TAC[REAL_INTEGRABLE_ON_SUBINTERVAL]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_RESTRICT_UNIV = prove
+ (`!f s. (\x. if x IN s then f x else &0)
+              absolutely_real_integrable_on (:real) <=>
+         f absolutely_real_integrable_on s`,
+  REWRITE_TAC[absolutely_real_integrable_on; REAL_INTEGRABLE_RESTRICT_UNIV;
+              COND_RAND; REAL_ABS_NUM]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_ADD = prove
+ (`!f:real->real g s.
+        f absolutely_real_integrable_on s /\
+        g absolutely_real_integrable_on s
+        ==> (\x. f(x) + g(x)) absolutely_real_integrable_on s`,
+  REWRITE_TAC[ABSOLUTELY_REAL_INTEGRABLE_ON] THEN
+  SIMP_TAC[o_DEF; LIFT_ADD; ABSOLUTELY_INTEGRABLE_ADD]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_SUB = prove
+ (`!f:real->real g s.
+        f absolutely_real_integrable_on s /\
+        g absolutely_real_integrable_on s
+        ==> (\x. f(x) - g(x)) absolutely_real_integrable_on s`,
+  REWRITE_TAC[ABSOLUTELY_REAL_INTEGRABLE_ON] THEN
+  SIMP_TAC[o_DEF; LIFT_SUB; ABSOLUTELY_INTEGRABLE_SUB]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_LINEAR = prove
+ (`!f h s.
+        f absolutely_real_integrable_on s /\ linear(lift o h o drop)
+        ==> (h o f) absolutely_real_integrable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[ABSOLUTELY_REAL_INTEGRABLE_ON] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP ABSOLUTELY_INTEGRABLE_LINEAR) THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_SUM = prove
+ (`!f:A->real->real s t.
+        FINITE t /\
+        (!a. a IN t ==> (f a) absolutely_real_integrable_on s)
+        ==>  (\x. sum t (\a. f a x)) absolutely_real_integrable_on s`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[SUM_CLAUSES; ABSOLUTELY_REAL_INTEGRABLE_0; IN_INSERT;
+           ABSOLUTELY_REAL_INTEGRABLE_ADD; ETA_AX]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_MAX = prove
+ (`!f:real->real g:real->real s.
+        f absolutely_real_integrable_on s /\ g absolutely_real_integrable_on s
+        ==> (\x. max (f x) (g x))
+            absolutely_real_integrable_on s`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[REAL_ARITH `max a b = &1 / &2 * ((a + b) + abs(a - b))`] THEN
+  MATCH_MP_TAC ABSOLUTELY_REAL_INTEGRABLE_LMUL THEN
+  ASM_SIMP_TAC[ABSOLUTELY_REAL_INTEGRABLE_SUB; ABSOLUTELY_REAL_INTEGRABLE_ADD;
+               ABSOLUTELY_REAL_INTEGRABLE_ABS]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_MIN = prove
+ (`!f:real->real g:real->real s.
+        f absolutely_real_integrable_on s /\ g absolutely_real_integrable_on s
+        ==> (\x. min (f x) (g x))
+            absolutely_real_integrable_on s`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[REAL_ARITH `min a b = &1 / &2 * ((a + b) - abs(a - b))`] THEN
+  MATCH_MP_TAC ABSOLUTELY_REAL_INTEGRABLE_LMUL THEN
+  ASM_SIMP_TAC[ABSOLUTELY_REAL_INTEGRABLE_SUB; ABSOLUTELY_REAL_INTEGRABLE_ADD;
+               ABSOLUTELY_REAL_INTEGRABLE_ABS]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_IMP_INTEGRABLE = prove
+ (`!f s. f absolutely_real_integrable_on s ==> f real_integrable_on s`,
+  SIMP_TAC[absolutely_real_integrable_on]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_CONTINUOUS = prove
+ (`!f a b.
+        f real_continuous_on real_interval[a,b]
+        ==> f absolutely_real_integrable_on real_interval[a,b]`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON; ABSOLUTELY_REAL_INTEGRABLE_ON;
+              has_real_integral;
+              GSYM integrable_on; GSYM EXISTS_LIFT] THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL; ABSOLUTELY_INTEGRABLE_CONTINUOUS]);;
+
+let NONNEGATIVE_ABSOLUTELY_REAL_INTEGRABLE = prove
+ (`!f s.
+        (!x. x IN s ==> &0 <= f(x)) /\
+        f real_integrable_on s
+        ==> f absolutely_real_integrable_on s`,
+  SIMP_TAC[absolutely_real_integrable_on] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_INTEGRABLE_EQ THEN
+  EXISTS_TAC `f:real->real` THEN ASM_SIMP_TAC[real_abs]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_INTEGRABLE_BOUND = prove
+ (`!f:real->real g s.
+        (!x. x IN s ==> abs(f x) <= g x) /\
+        f real_integrable_on s /\ g real_integrable_on s
+        ==> f absolutely_real_integrable_on s`,
+  REWRITE_TAC[REAL_INTEGRABLE_ON; ABSOLUTELY_REAL_INTEGRABLE_ON] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND THEN
+  EXISTS_TAC `lift o g o drop` THEN ASM_REWRITE_TAC[FORALL_IN_IMAGE] THEN
+  ASM_REWRITE_TAC[o_DEF; LIFT_DROP; NORM_LIFT]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_ABSOLUTELY_REAL_INTEGRABLE_BOUND = prove
+ (`!f:real->real g:real->real s.
+        (!x. x IN s ==> abs(f x) <= abs(g x)) /\
+        f real_integrable_on s /\ g absolutely_real_integrable_on s
+        ==> f absolutely_real_integrable_on s`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC ABSOLUTELY_REAL_INTEGRABLE_INTEGRABLE_BOUND THEN
+  EXISTS_TAC `\x:real. abs(g x)` THEN ASM_REWRITE_TAC[] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[absolutely_real_integrable_on]) THEN
+  ASM_REWRITE_TAC[]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_ABSOLUTELY_REAL_INTEGRABLE_UBOUND = prove
+ (`!f:real->real g:real->real s.
+        (!x. x IN s ==> f x <= g x) /\
+        f real_integrable_on s /\ g absolutely_real_integrable_on s
+        ==> f absolutely_real_integrable_on s`,
+  REWRITE_TAC[ABSOLUTELY_REAL_INTEGRABLE_ON; REAL_INTEGRABLE_ON] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC
+   ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_UBOUND THEN
+  EXISTS_TAC `lift o g o drop` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  ASM_REWRITE_TAC[IMP_IMP; DIMINDEX_1; FORALL_1; o_THM; LIFT_DROP;
+                  GSYM drop]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_ABSOLUTELY_REAL_INTEGRABLE_LBOUND = prove
+ (`!f:real->real g:real->real s.
+        (!x. x IN s ==> f x <= g x) /\
+        f absolutely_real_integrable_on s /\ g real_integrable_on s
+        ==> f absolutely_real_integrable_on s`,
+  REWRITE_TAC[ABSOLUTELY_REAL_INTEGRABLE_ON; REAL_INTEGRABLE_ON] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC
+   ABSOLUTELY_INTEGRABLE_ABSOLUTELY_INTEGRABLE_COMPONENT_LBOUND THEN
+  EXISTS_TAC `lift o f o drop` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  ASM_REWRITE_TAC[IMP_IMP; DIMINDEX_1; FORALL_1; o_THM; LIFT_DROP;
+                  GSYM drop]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_INF = prove
+ (`!fs s:real->bool k:A->bool.
+        FINITE k /\ ~(k = {}) /\
+        (!i. i IN k ==> (\x. fs x i) absolutely_real_integrable_on s)
+        ==> (\x. inf (IMAGE (fs x) k)) absolutely_real_integrable_on s`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[IMAGE_CLAUSES] THEN
+  SIMP_TAC[INF_INSERT_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+  MAP_EVERY X_GEN_TAC [`a:A`; `k:A->bool`] THEN
+  ASM_CASES_TAC `k:A->bool = {}` THEN ASM_REWRITE_TAC[] THEN
+  SIMP_TAC[IN_SING; LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ABSOLUTELY_REAL_INTEGRABLE_MIN THEN
+  CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INSERT] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[IN_INSERT]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_SUP = prove
+ (`!fs s:real->bool k:A->bool.
+        FINITE k /\ ~(k = {}) /\
+        (!i. i IN k ==> (\x. fs x i) absolutely_real_integrable_on s)
+        ==> (\x. sup (IMAGE (fs x) k)) absolutely_real_integrable_on s`,
+  GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[IMAGE_CLAUSES] THEN
+  SIMP_TAC[SUP_INSERT_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+  MAP_EVERY X_GEN_TAC [`a:A`; `k:A->bool`] THEN
+  ASM_CASES_TAC `k:A->bool = {}` THEN ASM_REWRITE_TAC[] THEN
+  SIMP_TAC[IN_SING; LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ABSOLUTELY_REAL_INTEGRABLE_MAX THEN
+  CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_INSERT] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[IN_INSERT]);;
+
+let REAL_DOMINATED_CONVERGENCE = prove
+ (`!f:num->real->real g h s.
+        (!k. (f k) real_integrable_on s) /\ h real_integrable_on s /\
+        (!k x. x IN s ==> abs(f k x) <= h x) /\
+        (!x. x IN s ==> ((\k. f k x) ---> g x) sequentially)
+        ==> g real_integrable_on s /\
+            ((\k. real_integral s (f k)) ---> real_integral s g) sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_INTEGRABLE_ON; TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n x. lift(f (n:num) (drop x))`;
+                 `lift o g o drop`;  `lift o h o drop`; `IMAGE lift s`]
+                DOMINATED_CONVERGENCE) THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; LIFT_DROP; o_DEF; NORM_LIFT] THEN
+  SUBGOAL_THEN
+   `!k:num. real_integral s (f k) =
+            drop(integral (IMAGE lift s) (lift o f k o drop))`
+   (fun th -> RULE_ASSUM_TAC(REWRITE_RULE[th]) THEN REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN MATCH_MP_TAC REAL_INTEGRAL THEN
+    ASM_REWRITE_TAC[REAL_INTEGRABLE_ON; o_DEF];
+    ALL_TAC] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  ONCE_REWRITE_TAC[GSYM DROP_EQ] THEN REWRITE_TAC[LIFT_DROP] THEN
+  CONV_TAC SYM_CONV THEN REWRITE_TAC[GSYM o_DEF] THEN
+  MATCH_MP_TAC REAL_INTEGRAL THEN ASM_REWRITE_TAC[REAL_INTEGRABLE_ON; o_DEF]);;
+
+let HAS_REAL_MEASURE_HAS_MEASURE = prove
+ (`!s m. s has_real_measure m <=> (IMAGE lift s) has_measure m`,
+  REWRITE_TAC[has_real_measure; has_measure; has_real_integral] THEN
+  REWRITE_TAC[o_DEF; LIFT_NUM]);;
+
+let REAL_MEASURABLE_MEASURABLE = prove
+ (`!s. real_measurable s <=> measurable(IMAGE lift s)`,
+  REWRITE_TAC[real_measurable; measurable; HAS_REAL_MEASURE_HAS_MEASURE]);;
+
+let REAL_MEASURE_MEASURE = prove
+ (`!s. real_measure s = measure (IMAGE lift s)`,
+  REWRITE_TAC[real_measure; measure; HAS_REAL_MEASURE_HAS_MEASURE]);;
+
+let HAS_REAL_MEASURE_MEASURE = prove
+ (`!s. real_measurable s <=> s has_real_measure (real_measure s)`,
+  REWRITE_TAC[real_measure; real_measurable] THEN MESON_TAC[]);;
+
+let HAS_REAL_MEASURE_UNIQUE = prove
+ (`!s m1 m2. s has_real_measure m1 /\ s has_real_measure m2 ==> m1 = m2`,
+  REWRITE_TAC[has_real_measure] THEN MESON_TAC[HAS_REAL_INTEGRAL_UNIQUE]);;
+
+let REAL_MEASURE_UNIQUE = prove
+ (`!s m. s has_real_measure m ==> real_measure s = m`,
+  MESON_TAC[HAS_REAL_MEASURE_UNIQUE; HAS_REAL_MEASURE_MEASURE;
+            real_measurable]);;
+
+let HAS_REAL_MEASURE_REAL_MEASURABLE_REAL_MEASURE = prove
+ (`!s m. s has_real_measure m <=> real_measurable s /\ real_measure s = m`,
+  REWRITE_TAC[HAS_REAL_MEASURE_MEASURE] THEN MESON_TAC[REAL_MEASURE_UNIQUE]);;
+
+let HAS_REAL_MEASURE_IMP_REAL_MEASURABLE = prove
+ (`!s m. s has_real_measure m ==> real_measurable s`,
+  REWRITE_TAC[real_measurable] THEN MESON_TAC[]);;
+
+let HAS_REAL_MEASURE = prove
+ (`!s m. s has_real_measure m <=>
+              ((\x. if x IN s then &1 else &0) has_real_integral m) (:real)`,
+  SIMP_TAC[HAS_REAL_INTEGRAL_RESTRICT_UNIV; has_real_measure]);;
+
+let REAL_MEASURABLE = prove
+ (`!s. real_measurable s <=> (\x. &1) real_integrable_on s`,
+  REWRITE_TAC[real_measurable; real_integrable_on;
+              has_real_measure; EXISTS_DROP; LIFT_DROP]);;
+
+let REAL_MEASURABLE_REAL_INTEGRABLE = prove
+ (`real_measurable s <=>
+    (\x. if x IN s then &1 else &0) real_integrable_on UNIV`,
+  REWRITE_TAC[real_measurable; real_integrable_on; HAS_REAL_MEASURE]);;
+
+let REAL_MEASURE_REAL_INTEGRAL = prove
+ (`!s. real_measurable s ==> real_measure s = real_integral s (\x. &1)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+  ASM_REWRITE_TAC[GSYM has_real_measure; GSYM HAS_REAL_MEASURE_MEASURE]);;
+
+let REAL_MEASURE_REAL_INTEGRAL_UNIV = prove
+ (`!s. real_measurable s
+       ==> real_measure s =
+           real_integral UNIV (\x. if x IN s then &1 else &0)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+  ASM_REWRITE_TAC[GSYM HAS_REAL_MEASURE; GSYM HAS_REAL_MEASURE_MEASURE]);;
+
+let REAL_INTEGRAL_REAL_MEASURE = prove
+ (`!s. real_measurable s ==> real_integral s (\x. &1) = real_measure s`,
+  SIMP_TAC[GSYM DROP_EQ; LIFT_DROP; REAL_MEASURE_REAL_INTEGRAL]);;
+
+let REAL_INTEGRAL_REAL_MEASURE_UNIV = prove
+ (`!s. real_measurable s
+       ==> real_integral UNIV (\x. if x IN s then &1 else &0) =
+           real_measure s`,
+  SIMP_TAC[REAL_MEASURE_REAL_INTEGRAL_UNIV]);;
+
+let HAS_REAL_MEASURE_REAL_INTERVAL = prove
+ (`(!a b. real_interval[a,b] has_real_measure (max (b - a) (&0))) /\
+   (!a b. real_interval(a,b) has_real_measure (max (b - a) (&0)))`,
+  REWRITE_TAC[HAS_REAL_MEASURE_HAS_MEASURE; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REWRITE_TAC[HAS_MEASURE_MEASURABLE_MEASURE; MEASURABLE_INTERVAL;
+              MEASURE_INTERVAL] THEN
+  REWRITE_TAC[CONTENT_CLOSED_INTERVAL_CASES; DIMINDEX_1; FORALL_1] THEN
+  REWRITE_TAC[PRODUCT_1; GSYM drop; LIFT_DROP] THEN REAL_ARITH_TAC);;
+
+let REAL_MEASURABLE_REAL_INTERVAL = prove
+ (`(!a b. real_measurable (real_interval[a,b])) /\
+   (!a b. real_measurable (real_interval(a,b)))`,
+  REWRITE_TAC[real_measurable] THEN
+  MESON_TAC[HAS_REAL_MEASURE_REAL_INTERVAL]);;
+
+let REAL_MEASURE_REAL_INTERVAL = prove
+ (`(!a b. real_measure(real_interval[a,b]) = max (b - a) (&0)) /\
+   (!a b. real_measure(real_interval(a,b)) = max (b - a) (&0))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_MEASURE_UNIQUE THEN
+  REWRITE_TAC[HAS_REAL_MEASURE_REAL_INTERVAL]);;
+
+let REAL_MEASURABLE_INTER = prove
+ (`!s t. real_measurable s /\ real_measurable t
+         ==> real_measurable (s INTER t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_MEASURABLE_MEASURABLE] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_INTER) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN SET_TAC[LIFT_DROP]);;
+
+let REAL_MEASURABLE_UNION = prove
+ (`!s t. real_measurable s /\ real_measurable t
+         ==> real_measurable (s UNION t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_MEASURABLE_MEASURABLE] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_UNION) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN SET_TAC[LIFT_DROP]);;
+
+let HAS_REAL_MEASURE_DISJOINT_UNION = prove
+ (`!s1 s2 m1 m2. s1 has_real_measure m1 /\ s2 has_real_measure m2 /\
+                 DISJOINT s1 s2
+                 ==> (s1 UNION s2) has_real_measure (m1 + m2)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[HAS_REAL_MEASURE_HAS_MEASURE; IMAGE_UNION] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_MEASURE_DISJOINT_UNION THEN
+  ASM SET_TAC[LIFT_DROP]);;
+
+let REAL_MEASURE_DISJOINT_UNION = prove
+ (`!s t. real_measurable s /\ real_measurable t /\ DISJOINT s t
+         ==> real_measure(s UNION t) = real_measure s + real_measure t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_REAL_MEASURE_DISJOINT_UNION;
+               GSYM HAS_REAL_MEASURE_MEASURE]);;
+
+let HAS_REAL_MEASURE_POS_LE = prove
+ (`!m s. s has_real_measure m ==> &0 <= m`,
+  REWRITE_TAC[HAS_REAL_MEASURE_HAS_MEASURE; HAS_MEASURE_POS_LE]);;
+
+let REAL_MEASURE_POS_LE = prove
+ (`!s. real_measurable s ==> &0 <= real_measure s`,
+  REWRITE_TAC[HAS_REAL_MEASURE_MEASURE; HAS_REAL_MEASURE_POS_LE]);;
+
+let HAS_REAL_MEASURE_SUBSET = prove
+ (`!s1 s2 m1 m2.
+        s1 has_real_measure m1 /\ s2 has_real_measure m2 /\ s1 SUBSET s2
+        ==> m1 <= m2`,
+  REWRITE_TAC[HAS_REAL_MEASURE_HAS_MEASURE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(ISPECL [`IMAGE lift s1`; `IMAGE lift s2`]
+    HAS_MEASURE_SUBSET) THEN
+  ASM SET_TAC[HAS_MEASURE_SUBSET]);;
+
+let REAL_MEASURE_SUBSET = prove
+ (`!s t. real_measurable s /\ real_measurable t /\ s SUBSET t
+         ==> real_measure s <= real_measure t`,
+  REWRITE_TAC[HAS_REAL_MEASURE_MEASURE] THEN
+  MESON_TAC[HAS_REAL_MEASURE_SUBSET]);;
+
+let HAS_REAL_MEASURE_0 = prove
+ (`!s. s has_real_measure &0 <=> real_negligible s`,
+  REWRITE_TAC[real_negligible; HAS_REAL_MEASURE_HAS_MEASURE] THEN
+  REWRITE_TAC[HAS_MEASURE_0]);;
+
+let REAL_MEASURE_EQ_0 = prove
+ (`!s. real_negligible s ==> real_measure s = &0`,
+  MESON_TAC[REAL_MEASURE_UNIQUE; HAS_REAL_MEASURE_0]);;
+
+let HAS_REAL_MEASURE_EMPTY = prove
+ (`{} has_real_measure &0`,
+  REWRITE_TAC[HAS_REAL_MEASURE_0; REAL_NEGLIGIBLE_EMPTY]);;
+
+let REAL_MEASURE_EMPTY = prove
+ (`real_measure {} = &0`,
+  SIMP_TAC[REAL_MEASURE_EQ_0; REAL_NEGLIGIBLE_EMPTY]);;
+
+let REAL_MEASURABLE_EMPTY = prove
+ (`real_measurable {}`,
+  REWRITE_TAC[real_measurable] THEN MESON_TAC[HAS_REAL_MEASURE_EMPTY]);;
+
+let REAL_MEASURABLE_REAL_MEASURE_EQ_0 = prove
+ (`!s. real_measurable s ==> (real_measure s = &0 <=> real_negligible s)`,
+  REWRITE_TAC[HAS_REAL_MEASURE_MEASURE; GSYM HAS_REAL_MEASURE_0] THEN
+  MESON_TAC[REAL_MEASURE_UNIQUE]);;
+
+let REAL_MEASURABLE_REAL_MEASURE_POS_LT = prove
+ (`!s. real_measurable s ==> (&0 < real_measure s <=> ~real_negligible s)`,
+  SIMP_TAC[REAL_LT_LE; REAL_MEASURE_POS_LE;
+           GSYM REAL_MEASURABLE_REAL_MEASURE_EQ_0] THEN
+  REWRITE_TAC[EQ_SYM_EQ]);;
+
+let REAL_NEGLIGIBLE_REAL_INTERVAL = prove
+ (`(!a b. real_negligible(real_interval[a,b]) <=> real_interval(a,b) = {}) /\
+   (!a b. real_negligible(real_interval(a,b)) <=> real_interval(a,b) = {})`,
+  REWRITE_TAC[real_negligible; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REWRITE_TAC[NEGLIGIBLE_INTERVAL] THEN
+  REWRITE_TAC[REAL_INTERVAL_EQ_EMPTY; INTERVAL_EQ_EMPTY_1; LIFT_DROP]);;
+
+let REAL_MEASURABLE_UNIONS = prove
+ (`!f. FINITE f /\ (!s. s IN f ==> real_measurable s)
+       ==> real_measurable (UNIONS f)`,
+  REWRITE_TAC[REAL_MEASURABLE_MEASURABLE; IMAGE_UNIONS] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_UNIONS THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE]);;
+
+let HAS_REAL_MEASURE_DIFF_SUBSET = prove
+ (`!s1 s2 m1 m2.
+        s1 has_real_measure m1 /\ s2 has_real_measure m2 /\ s2 SUBSET s1
+        ==> (s1 DIFF s2) has_real_measure (m1 - m2)`,
+  REWRITE_TAC[HAS_REAL_MEASURE_HAS_MEASURE] THEN REPEAT STRIP_TAC THEN
+  SIMP_TAC[IMAGE_DIFF_INJ; LIFT_EQ] THEN
+  MATCH_MP_TAC HAS_MEASURE_DIFF_SUBSET THEN
+  ASM_SIMP_TAC[IMAGE_SUBSET]);;
+
+let REAL_MEASURABLE_DIFF = prove
+ (`!s t. real_measurable s /\ real_measurable t
+         ==> real_measurable (s DIFF t)`,
+  SIMP_TAC[REAL_MEASURABLE_MEASURABLE; IMAGE_DIFF_INJ; LIFT_EQ] THEN
+  REWRITE_TAC[MEASURABLE_DIFF]);;
+
+let REAL_MEASURE_DIFF_SUBSET = prove
+ (`!s t. real_measurable s /\ real_measurable t /\ t SUBSET s
+         ==> real_measure(s DIFF t) = real_measure s - real_measure t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_REAL_MEASURE_DIFF_SUBSET; GSYM HAS_REAL_MEASURE_MEASURE]);;
+
+let HAS_REAL_MEASURE_UNION_REAL_NEGLIGIBLE = prove
+ (`!s t m.
+        s has_real_measure m /\ real_negligible t
+        ==> (s UNION t) has_real_measure m`,
+  REWRITE_TAC[HAS_REAL_MEASURE_HAS_MEASURE; real_negligible; IMAGE_UNION] THEN
+  REWRITE_TAC[HAS_MEASURE_UNION_NEGLIGIBLE]);;
+
+let HAS_REAL_MEASURE_DIFF_REAL_NEGLIGIBLE = prove
+ (`!s t m.
+        s has_real_measure m /\ real_negligible t
+        ==> (s DIFF t) has_real_measure m`,
+  REWRITE_TAC[HAS_REAL_MEASURE_HAS_MEASURE; real_negligible] THEN
+  SIMP_TAC[IMAGE_DIFF_INJ; LIFT_EQ] THEN
+  REWRITE_TAC[HAS_MEASURE_DIFF_NEGLIGIBLE]);;
+
+let HAS_REAL_MEASURE_UNION_REAL_NEGLIGIBLE_EQ = prove
+ (`!s t m.
+     real_negligible t
+     ==> ((s UNION t) has_real_measure m <=> s has_real_measure m)`,
+  REWRITE_TAC[HAS_REAL_MEASURE_HAS_MEASURE; real_negligible; IMAGE_UNION] THEN
+  REWRITE_TAC[HAS_MEASURE_UNION_NEGLIGIBLE_EQ]);;
+
+let HAS_REAL_MEASURE_DIFF_REAL_NEGLIGIBLE_EQ = prove
+ (`!s t m.
+     real_negligible t
+     ==> ((s DIFF t) has_real_measure m <=> s has_real_measure m)`,
+  REWRITE_TAC[HAS_REAL_MEASURE_HAS_MEASURE; real_negligible] THEN
+  SIMP_TAC[IMAGE_DIFF_INJ; LIFT_EQ] THEN
+  REWRITE_TAC[HAS_MEASURE_DIFF_NEGLIGIBLE_EQ]);;
+
+let HAS_REAL_MEASURE_ALMOST = prove
+ (`!s s' t m. s has_real_measure m /\ real_negligible t /\
+              s UNION t = s' UNION t
+              ==> s' has_real_measure m`,
+  REWRITE_TAC[HAS_REAL_MEASURE_HAS_MEASURE; real_negligible; IMAGE_UNION] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_MEASURE_ALMOST THEN
+  MAP_EVERY EXISTS_TAC [`IMAGE lift s`; `IMAGE lift t`] THEN ASM SET_TAC[]);;
+
+let HAS_REAL_MEASURE_ALMOST_EQ = prove
+ (`!s s' t. real_negligible t /\ s UNION t = s' UNION t
+            ==> (s has_real_measure m <=> s' has_real_measure m)`,
+  MESON_TAC[HAS_REAL_MEASURE_ALMOST]);;
+
+let REAL_MEASURABLE_ALMOST = prove
+ (`!s s' t. real_measurable s /\ real_negligible t /\ s UNION t = s' UNION t
+            ==> real_measurable s'`,
+  REWRITE_TAC[real_measurable] THEN MESON_TAC[HAS_REAL_MEASURE_ALMOST]);;
+
+let HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNION = prove
+ (`!s1 s2 m1 m2.
+        s1 has_real_measure m1 /\ s2 has_real_measure m2 /\
+        real_negligible(s1 INTER s2)
+        ==> (s1 UNION s2) has_real_measure (m1 + m2)`,
+  REWRITE_TAC[HAS_REAL_MEASURE_HAS_MEASURE; real_negligible; IMAGE_UNION] THEN
+  SIMP_TAC[IMAGE_INTER_INJ; LIFT_EQ] THEN
+  REWRITE_TAC[HAS_MEASURE_NEGLIGIBLE_UNION]);;
+
+let REAL_MEASURE_REAL_NEGLIGIBLE_UNION = prove
+ (`!s t. real_measurable s /\ real_measurable t /\ real_negligible(s INTER t)
+         ==> real_measure(s UNION t) = real_measure s + real_measure t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNION;
+               GSYM HAS_REAL_MEASURE_MEASURE]);;
+
+let HAS_REAL_MEASURE_REAL_NEGLIGIBLE_SYMDIFF = prove
+ (`!s t m.
+        s has_real_measure m /\
+        real_negligible((s DIFF t) UNION (t DIFF s))
+        ==> t has_real_measure m`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HAS_REAL_MEASURE_ALMOST THEN
+  MAP_EVERY EXISTS_TAC
+    [`s:real->bool`; `(s DIFF t) UNION (t DIFF s):real->bool`] THEN
+  ASM_REWRITE_TAC[] THEN SET_TAC[]);;
+
+let REAL_MEASURABLE_REAL_NEGLIGIBLE_SYMDIFF = prove
+ (`!s t. real_measurable s /\ real_negligible((s DIFF t) UNION (t DIFF s))
+         ==> real_measurable t`,
+  REWRITE_TAC[real_measurable] THEN
+  MESON_TAC[HAS_REAL_MEASURE_REAL_NEGLIGIBLE_SYMDIFF]);;
+
+let REAL_MEASURE_REAL_NEGLIGIBLE_SYMDIFF = prove
+ (`!s t. (real_measurable s \/ real_measurable t) /\
+         real_negligible((s DIFF t) UNION (t DIFF s))
+         ==> real_measure s = real_measure t`,
+  MESON_TAC[HAS_REAL_MEASURE_REAL_NEGLIGIBLE_SYMDIFF; REAL_MEASURE_UNIQUE;
+            UNION_COMM; HAS_REAL_MEASURE_MEASURE]);;
+
+let HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS = prove
+ (`!m f. FINITE f /\
+         (!s. s IN f ==> s has_real_measure (m s)) /\
+         (!s t. s IN f /\ t IN f /\ ~(s = t) ==> real_negligible(s INTER t))
+         ==> (UNIONS f) has_real_measure (sum f m)`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[SUM_CLAUSES; UNIONS_0; UNIONS_INSERT; HAS_REAL_MEASURE_EMPTY] THEN
+  REWRITE_TAC[IN_INSERT] THEN
+  MAP_EVERY X_GEN_TAC [`s:real->bool`; `f:(real->bool)->bool`] THEN
+  STRIP_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNION THEN
+  REPEAT(CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC]) THEN
+  REWRITE_TAC[INTER_UNIONS] THEN MATCH_MP_TAC REAL_NEGLIGIBLE_UNIONS THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[]);;
+
+let REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS = prove
+ (`!m f. FINITE f /\
+         (!s. s IN f ==> s has_real_measure (m s)) /\
+         (!s t. s IN f /\ t IN f /\ ~(s = t) ==> real_negligible(s INTER t))
+         ==> real_measure(UNIONS f) = sum f m`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS]);;
+
+let HAS_REAL_MEASURE_DISJOINT_UNIONS = prove
+ (`!m f. FINITE f /\
+         (!s. s IN f ==> s has_real_measure (m s)) /\
+         (!s t. s IN f /\ t IN f /\ ~(s = t) ==> DISJOINT s t)
+         ==> (UNIONS f) has_real_measure (sum f m)`,
+  REWRITE_TAC[DISJOINT] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS THEN
+  ASM_SIMP_TAC[REAL_NEGLIGIBLE_EMPTY]);;
+
+let REAL_MEASURE_DISJOINT_UNIONS = prove
+ (`!m f:(real->bool)->bool.
+        FINITE f /\
+        (!s. s IN f ==> s has_real_measure (m s)) /\
+        (!s t. s IN f /\ t IN f /\ ~(s = t) ==> DISJOINT s t)
+        ==> real_measure(UNIONS f) = sum f m`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_REAL_MEASURE_DISJOINT_UNIONS]);;
+
+let HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE = prove
+ (`!f:A->(real->bool) s.
+        FINITE s /\
+        (!x. x IN s ==> real_measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y)
+               ==> real_negligible((f x) INTER (f y)))
+        ==> (UNIONS (IMAGE f s)) has_real_measure
+            (sum s (\x. real_measure(f x)))`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `sum s (\x. real_measure(f x)) =
+    sum (IMAGE (f:A->real->bool) s) real_measure`
+  SUBST1_TAC THENL
+   [CONV_TAC SYM_CONV THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+    MATCH_MP_TAC SUM_IMAGE_NONZERO THEN ASM_REWRITE_TAC[] THEN
+    MAP_EVERY X_GEN_TAC [`x:A`; `y:A`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:A`; `y:A`]) THEN
+    ASM_SIMP_TAC[INTER_ACI; REAL_MEASURABLE_REAL_MEASURE_EQ_0];
+    MATCH_MP_TAC HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS THEN
+    ASM_SIMP_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ; FORALL_IN_IMAGE] THEN
+    ASM_MESON_TAC[FINITE_IMAGE; HAS_REAL_MEASURE_MEASURE]]);;
+
+let REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE = prove
+ (`!f:A->real->bool s.
+        FINITE s /\
+        (!x. x IN s ==> real_measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y)
+               ==> real_negligible((f x) INTER (f y)))
+        ==> real_measure(UNIONS (IMAGE f s)) = sum s (\x. real_measure(f x))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE]);;
+
+let HAS_REAL_MEASURE_DISJOINT_UNIONS_IMAGE = prove
+ (`!f:A->real->bool s.
+        FINITE s /\
+        (!x. x IN s ==> real_measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> DISJOINT (f x) (f y))
+        ==> (UNIONS (IMAGE f s)) has_real_measure
+            (sum s (\x. real_measure(f x)))`,
+  REWRITE_TAC[DISJOINT] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE THEN
+  ASM_SIMP_TAC[REAL_NEGLIGIBLE_EMPTY]);;
+
+let REAL_MEASURE_DISJOINT_UNIONS_IMAGE = prove
+ (`!f:A->real->bool s.
+        FINITE s /\
+        (!x. x IN s ==> real_measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> DISJOINT (f x) (f y))
+        ==> real_measure(UNIONS (IMAGE f s)) = sum s (\x. real_measure(f x))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_REAL_MEASURE_DISJOINT_UNIONS_IMAGE]);;
+
+let HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE_STRONG = prove
+ (`!f:A->real->bool s.
+        FINITE {x | x IN s /\ ~(f x = {})} /\
+        (!x. x IN s ==> real_measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y)
+               ==> real_negligible((f x) INTER (f y)))
+        ==> (UNIONS (IMAGE f s)) has_real_measure
+            (sum s (\x. real_measure(f x)))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:A->real->bool`;
+                 `{x | x IN s /\ ~((f:A->real->bool) x = {})}`]
+        HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE) THEN
+  ASM_SIMP_TAC[IN_ELIM_THM; FINITE_RESTRICT] THEN
+  MATCH_MP_TAC EQ_IMP THEN BINOP_TAC THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_UNIONS; IN_IMAGE; IN_ELIM_THM] THEN
+    MESON_TAC[NOT_IN_EMPTY];
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_SUPERSET THEN
+    SIMP_TAC[SUBSET; IN_ELIM_THM; TAUT `a /\ ~(a /\ b) <=> a /\ ~b`] THEN
+    REWRITE_TAC[REAL_MEASURE_EMPTY]]);;
+
+let REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE_STRONG = prove
+ (`!f:A->real->bool s.
+        FINITE {x | x IN s /\ ~(f x = {})} /\
+        (!x. x IN s ==> real_measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y)
+               ==> real_negligible((f x) INTER (f y)))
+        ==> real_measure(UNIONS (IMAGE f s)) = sum s (\x. real_measure(f x))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE_STRONG]);;
+
+let HAS_REAL_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG = prove
+ (`!f:A->real->bool s.
+        FINITE {x | x IN s /\ ~(f x = {})} /\
+        (!x. x IN s ==> real_measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> DISJOINT (f x) (f y))
+        ==> (UNIONS (IMAGE f s)) has_real_measure
+            (sum s (\x. real_measure(f x)))`,
+  REWRITE_TAC[DISJOINT] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE_STRONG THEN
+  ASM_SIMP_TAC[REAL_NEGLIGIBLE_EMPTY]);;
+
+let REAL_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG = prove
+ (`!f:A->real->bool s.
+        FINITE {x | x IN s /\ ~(f x = {})} /\
+        (!x. x IN s ==> real_measurable(f x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> DISJOINT (f x) (f y))
+        ==> real_measure(UNIONS (IMAGE f s)) = sum s (\x. real_measure(f x))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_REAL_MEASURE_DISJOINT_UNIONS_IMAGE_STRONG]);;
+
+let REAL_MEASURE_UNION = prove
+ (`!s t. real_measurable s /\ real_measurable t
+         ==> real_measure(s UNION t) =
+             real_measure(s) + real_measure(t) - real_measure(s INTER t)`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[SET_RULE
+   `s UNION t = (s INTER t) UNION (s DIFF t) UNION (t DIFF s)`] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a + b - c:real = c + (a - c) + (b - c)`] THEN
+  MP_TAC(ISPECL [`s DIFF t:real->bool`; `t DIFF s:real->bool`]
+        REAL_MEASURE_DISJOINT_UNION) THEN
+  ASM_SIMP_TAC[REAL_MEASURABLE_DIFF] THEN
+  ANTS_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`s INTER t:real->bool`;
+                 `(s DIFF t) UNION (t DIFF s):real->bool`]
+                REAL_MEASURE_DISJOINT_UNION) THEN
+  ASM_SIMP_TAC[REAL_MEASURABLE_DIFF;
+               REAL_MEASURABLE_UNION; REAL_MEASURABLE_INTER] THEN
+  ANTS_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+  REPEAT(DISCH_THEN SUBST1_TAC) THEN AP_TERM_TAC THEN BINOP_TAC THEN
+  REWRITE_TAC[REAL_EQ_SUB_LADD] THEN MATCH_MP_TAC EQ_TRANS THENL
+   [EXISTS_TAC `real_measure((s DIFF t) UNION (s INTER t):real->bool)`;
+    EXISTS_TAC `real_measure((t DIFF s) UNION (s INTER t):real->bool)`] THEN
+  (CONJ_TAC THENL
+    [CONV_TAC SYM_CONV THEN MATCH_MP_TAC REAL_MEASURE_DISJOINT_UNION THEN
+     ASM_SIMP_TAC[REAL_MEASURABLE_DIFF; REAL_MEASURABLE_INTER];
+     AP_TERM_TAC] THEN
+   SET_TAC[]));;
+
+let REAL_MEASURE_UNION_LE = prove
+ (`!s t. real_measurable s /\ real_measurable t
+         ==> real_measure(s UNION t) <= real_measure s + real_measure t`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[REAL_MEASURE_UNION] THEN
+  REWRITE_TAC[REAL_ARITH `a + b - c <= a + b <=> &0 <= c`] THEN
+  MATCH_MP_TAC REAL_MEASURE_POS_LE THEN ASM_SIMP_TAC[REAL_MEASURABLE_INTER]);;
+
+let REAL_MEASURE_UNIONS_LE = prove
+ (`!f. FINITE f /\ (!s. s IN f ==> real_measurable s)
+       ==> real_measure(UNIONS f) <= sum f (\s. real_measure s)`,
+  REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[UNIONS_0; UNIONS_INSERT; SUM_CLAUSES] THEN
+  REWRITE_TAC[REAL_MEASURE_EMPTY; REAL_LE_REFL] THEN
+  MAP_EVERY X_GEN_TAC [`s:real->bool`; `f:(real->bool)->bool`] THEN
+  REWRITE_TAC[IN_INSERT] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `real_measure(s) + real_measure(UNIONS f)` THEN
+  ASM_SIMP_TAC[REAL_MEASURE_UNION_LE; REAL_MEASURABLE_UNIONS] THEN
+  REWRITE_TAC[REAL_LE_LADD] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[]);;
+
+let REAL_MEASURE_UNIONS_LE_IMAGE = prove
+ (`!f:A->bool s:A->(real->bool).
+        FINITE f /\ (!a. a IN f ==> real_measurable(s a))
+        ==> real_measure(UNIONS (IMAGE s f)) <= sum f (\a. real_measure(s a))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum (IMAGE s (f:A->bool)) (\k:real->bool. real_measure k)` THEN
+  ASM_SIMP_TAC[REAL_MEASURE_UNIONS_LE; FORALL_IN_IMAGE; FINITE_IMAGE] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM o_DEF] THEN
+  REWRITE_TAC[ETA_AX] THEN MATCH_MP_TAC SUM_IMAGE_LE THEN
+  ASM_SIMP_TAC[REAL_MEASURE_POS_LE]);;
+
+let REAL_NEGLIGIBLE_OUTER = prove
+ (`!s. real_negligible s <=>
+       !e. &0 < e
+           ==> ?t. s SUBSET t /\ real_measurable t /\ real_measure t < e`,
+  REWRITE_TAC[real_negligible; REAL_MEASURABLE_MEASURABLE;
+              REAL_MEASURE_MEASURE; SUBSET_LIFT_IMAGE;
+              NEGLIGIBLE_OUTER; EXISTS_LIFT_IMAGE]);;
+
+let REAL_NEGLIGIBLE_OUTER_LE = prove
+ (`!s. real_negligible s <=>
+       !e. &0 < e
+           ==> ?t. s SUBSET t /\ real_measurable t /\ real_measure t <= e`,
+  REWRITE_TAC[real_negligible; REAL_MEASURABLE_MEASURABLE;
+              REAL_MEASURE_MEASURE; SUBSET_LIFT_IMAGE;
+              NEGLIGIBLE_OUTER_LE; EXISTS_LIFT_IMAGE]);;
+
+let REAL_MEASURABLE_INNER_OUTER = prove
+ (`!s. real_measurable s <=>
+                !e. &0 < e
+                    ==> ?t u. t SUBSET s /\ s SUBSET u /\
+                              real_measurable t /\ real_measurable u /\
+                              abs(real_measure t - real_measure u) < e`,
+  GEN_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+   [GEN_TAC THEN DISCH_TAC THEN REPEAT(EXISTS_TAC `s:real->bool`) THEN
+    ASM_REWRITE_TAC[SUBSET_REFL; REAL_SUB_REFL; REAL_ABS_NUM];
+    ALL_TAC] THEN
+  REWRITE_TAC[REAL_MEASURABLE_REAL_INTEGRABLE] THEN
+  MATCH_MP_TAC REAL_INTEGRABLE_STRADDLE THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`t:real->bool`; `u:real->bool`] THEN STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC
+   [`(\x. if x IN t then &1 else &0):real->real`;
+    `(\x. if x IN u then &1 else &0):real->real`;
+    `real_measure(t:real->bool)`;
+    `real_measure(u:real->bool)`] THEN
+  ASM_REWRITE_TAC[GSYM HAS_REAL_MEASURE; GSYM HAS_REAL_MEASURE_MEASURE] THEN
+  ASM_REWRITE_TAC[GSYM LIFT_SUB; NORM_LIFT] THEN REPEAT STRIP_TAC THEN
+  REPEAT(COND_CASES_TAC THEN
+         ASM_REWRITE_TAC[DROP_VEC; REAL_POS; REAL_LE_REFL]) THEN
+  ASM SET_TAC[]);;
+
+let HAS_REAL_MEASURE_INNER_OUTER = prove
+ (`!s m. s has_real_measure m <=>
+                (!e. &0 < e ==> ?t. t SUBSET s /\ real_measurable t /\
+                                    m - e < real_measure t) /\
+                (!e. &0 < e ==> ?u. s SUBSET u /\ real_measurable u /\
+                                    real_measure u < m + e)`,
+  REPEAT GEN_TAC THEN
+  GEN_REWRITE_TAC LAND_CONV
+      [HAS_REAL_MEASURE_REAL_MEASURABLE_REAL_MEASURE] THEN EQ_TAC THENL
+   [REPEAT STRIP_TAC THEN EXISTS_TAC `s:real->bool` THEN
+    ASM_REWRITE_TAC[SUBSET_REFL] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "t") (LABEL_TAC "u")) THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [GEN_REWRITE_TAC I [REAL_MEASURABLE_INNER_OUTER] THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    REMOVE_THEN "u" (MP_TAC o SPEC `e / &2`) THEN
+    REMOVE_THEN "t" (MP_TAC o SPEC `e / &2`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+    REWRITE_TAC[IMP_IMP; LEFT_AND_EXISTS_THM] THEN
+    REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(REAL_ARITH
+     `&0 < e /\ t <= u /\ m - e / &2 < t /\ u < m + e / &2
+                          ==> abs(t - u) < e`) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_MEASURE_SUBSET THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    DISCH_TAC THEN MATCH_MP_TAC(REAL_ARITH
+     `~(&0 < x - y) /\ ~(&0 < y - x) ==> x = y`) THEN
+    CONJ_TAC THEN DISCH_TAC THENL
+     [REMOVE_THEN "u" (MP_TAC o SPEC `real_measure(s:real->bool) - m`) THEN
+      ASM_REWRITE_TAC[REAL_SUB_ADD2; GSYM REAL_NOT_LE];
+      REMOVE_THEN "t" (MP_TAC o SPEC `m - real_measure(s:real->bool)`) THEN
+      ASM_REWRITE_TAC[REAL_SUB_SUB2; GSYM REAL_NOT_LE]] THEN
+    ASM_MESON_TAC[REAL_MEASURE_SUBSET]]);;
+
+let HAS_REAL_MEASURE_INNER_OUTER_LE = prove
+ (`!s:real->bool m.
+        s has_real_measure m <=>
+                (!e. &0 < e ==> ?t. t SUBSET s /\ real_measurable t /\
+                                    m - e <= real_measure t) /\
+                (!e. &0 < e ==> ?u. s SUBSET u /\ real_measurable u /\
+                                    real_measure u <= m + e)`,
+  REWRITE_TAC[HAS_REAL_MEASURE_INNER_OUTER] THEN
+  MESON_TAC[REAL_ARITH `&0 < e /\ m - e / &2 <= t ==> m - e < t`;
+            REAL_ARITH `&0 < e /\ u <= m + e / &2 ==> u < m + e`;
+            REAL_ARITH `&0 < e <=> &0 < e / &2`; REAL_LT_IMP_LE]);;
+
+let HAS_REAL_MEASURE_AFFINITY = prove
+ (`!s m c y. s has_real_measure y
+             ==> (IMAGE (\x. m * x + c) s) has_real_measure abs(m) * y`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HAS_REAL_MEASURE_HAS_MEASURE] THEN
+  DISCH_THEN(MP_TAC o SPECL [`m:real`; `lift c`] o MATCH_MP
+    HAS_MEASURE_AFFINITY) THEN
+  REWRITE_TAC[DIMINDEX_1; REAL_POW_1; GSYM IMAGE_o] THEN
+  MATCH_MP_TAC EQ_IMP THEN REPEAT(AP_THM_TAC THEN AP_TERM_TAC) THEN
+  SIMP_TAC[FUN_EQ_THM; FORALL_DROP; o_THM; LIFT_DROP; LIFT_ADD; LIFT_CMUL]);;
+
+let HAS_REAL_MEASURE_SCALING = prove
+ (`!s m y. s has_real_measure y
+           ==> (IMAGE (\x. m * x) s) has_real_measure abs(m) * y`,
+  ONCE_REWRITE_TAC[REAL_ARITH `m * x = m * x + &0`] THEN
+  REWRITE_TAC[REAL_ARITH `abs m * x + &0 = abs m * x`] THEN
+  REWRITE_TAC[HAS_REAL_MEASURE_AFFINITY]);;
+
+let HAS_REAL_MEASURE_TRANSLATION = prove
+ (`!s m a. s has_real_measure m ==> (IMAGE (\x. a + x) s) has_real_measure m`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a + x = &1 * x + a`] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [REAL_ARITH `m = abs(&1) * m`] THEN
+  REWRITE_TAC[HAS_REAL_MEASURE_AFFINITY]);;
+
+let REAL_NEGLIGIBLE_TRANSLATION = prove
+ (`!s a. real_negligible s ==> real_negligible (IMAGE (\x. a + x) s)`,
+  SIMP_TAC[GSYM HAS_REAL_MEASURE_0; HAS_REAL_MEASURE_TRANSLATION]);;
+
+let HAS_REAL_MEASURE_TRANSLATION_EQ = prove
+ (`!s m. (IMAGE (\x. a + x) s) has_real_measure m <=> s has_real_measure m`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  REWRITE_TAC[HAS_REAL_MEASURE_TRANSLATION] THEN
+  DISCH_THEN(MP_TAC o SPEC `--a:real` o
+    MATCH_MP HAS_REAL_MEASURE_TRANSLATION) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; REAL_ARITH `--a + a + b:real = b`] THEN
+  SET_TAC[]);;
+
+let REAL_NEGLIGIBLE_TRANSLATION_REV = prove
+ (`!s a. real_negligible (IMAGE (\x. a + x) s) ==> real_negligible s`,
+  SIMP_TAC[GSYM HAS_REAL_MEASURE_0; HAS_REAL_MEASURE_TRANSLATION_EQ]);;
+
+let REAL_NEGLIGIBLE_TRANSLATION_EQ = prove
+ (`!s a. real_negligible (IMAGE (\x. a + x) s) <=> real_negligible s`,
+  SIMP_TAC[GSYM HAS_REAL_MEASURE_0; HAS_REAL_MEASURE_TRANSLATION_EQ]);;
+
+let REAL_MEASURABLE_TRANSLATION = prove
+ (`!s. real_measurable (IMAGE (\x. a + x) s) <=> real_measurable s`,
+  REWRITE_TAC[real_measurable; HAS_REAL_MEASURE_TRANSLATION_EQ]);;
+
+let REAL_MEASURE_TRANSLATION = prove
+ (`!s. real_measurable s
+       ==> real_measure(IMAGE (\x. a + x) s) = real_measure s`,
+  REWRITE_TAC[HAS_REAL_MEASURE_MEASURE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_MEASURE_UNIQUE THEN
+  ASM_REWRITE_TAC[HAS_REAL_MEASURE_TRANSLATION_EQ]);;
+
+let HAS_REAL_MEASURE_SCALING_EQ = prove
+ (`!s m c. ~(c = &0)
+           ==> ((IMAGE (\x. c * x) s) has_real_measure (abs(c) * m) <=>
+                s has_real_measure m)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REWRITE_TAC[HAS_REAL_MEASURE_SCALING] THEN
+  DISCH_THEN(MP_TAC o SPEC `inv(c:real)` o
+    MATCH_MP HAS_REAL_MEASURE_SCALING) THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; GSYM REAL_ABS_MUL] THEN
+  REWRITE_TAC[GSYM REAL_POW_MUL; REAL_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[GSYM REAL_ABS_MUL; REAL_MUL_LINV] THEN
+  REWRITE_TAC[REAL_POW_ONE; REAL_ABS_NUM; REAL_MUL_LID] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN SET_TAC[]);;
+
+let REAL_MEASURABLE_SCALING = prove
+ (`!s c. real_measurable s ==> real_measurable (IMAGE (\x. c * x) s)`,
+  REWRITE_TAC[real_measurable] THEN MESON_TAC[HAS_REAL_MEASURE_SCALING]);;
+
+let REAL_MEASURABLE_SCALING_EQ = prove
+ (`!s c. ~(c = &0)
+         ==> (real_measurable (IMAGE (\x. c * x) s) <=> real_measurable s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REWRITE_TAC[REAL_MEASURABLE_SCALING] THEN
+  DISCH_THEN(MP_TAC o SPEC `inv c:real` o MATCH_MP REAL_MEASURABLE_SCALING) THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; GSYM REAL_ABS_MUL] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  ASM_SIMP_TAC[REAL_MUL_ASSOC; REAL_MUL_LINV; REAL_MUL_LID] THEN
+  SET_TAC[]);;
+
+let REAL_MEASURE_SCALING = prove
+ (`!s. real_measurable s
+       ==> real_measure(IMAGE (\x. c * x) s) = abs(c) * real_measure s`,
+  REWRITE_TAC[HAS_REAL_MEASURE_MEASURE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_MEASURE_UNIQUE THEN
+  ASM_SIMP_TAC[HAS_REAL_MEASURE_SCALING]);;
+
+let HAS_REAL_MEASURE_NESTED_UNIONS = prove
+ (`!s B. (!n. real_measurable(s n)) /\
+         (!n. real_measure(s n) <= B) /\
+         (!n. s(n) SUBSET s(SUC n))
+         ==> real_measurable(UNIONS { s(n) | n IN (:num) }) /\
+             ((\n. real_measure(s n))
+                   ---> real_measure(UNIONS { s(n) | n IN (:num) }))
+             sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[TENDSTO_REAL; o_DEF] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_SIMP_TAC[REAL_MEASURE_MEASURE] THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[REAL_MEASURABLE_MEASURABLE] THEN
+  REPEAT(DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC)) THEN
+  MP_TAC(ISPECL [`IMAGE lift o (s:num->real->bool)`; `B:real`]
+        HAS_MEASURE_NESTED_UNIONS) THEN
+  ASM_SIMP_TAC[o_THM; IMAGE_SUBSET] THEN
+  REWRITE_TAC[SET_RULE `{IMAGE f (s n) | P n} = IMAGE (IMAGE f) {s n | P n}`;
+              GSYM IMAGE_UNIONS] THEN
+  SIMP_TAC[REAL_MEASURE_MEASURE; REAL_MEASURABLE_MEASURABLE]);;
+
+let REAL_MEASURABLE_NESTED_UNIONS = prove
+ (`!s B. (!n. real_measurable(s n)) /\
+         (!n. real_measure(s n) <= B) /\
+         (!n. s(n) SUBSET s(SUC n))
+         ==> real_measurable(UNIONS { s(n) | n IN (:num) })`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_REAL_MEASURE_NESTED_UNIONS) THEN
+  SIMP_TAC[]);;
+
+let HAS_REAL_MEASURE_COUNTABLE_REAL_NEGLIGIBLE_UNIONS = prove
+ (`!s:num->real->bool B.
+        (!n. real_measurable(s n)) /\
+        (!m n. ~(m = n) ==> real_negligible(s m INTER s n)) /\
+        (!n. sum (0..n) (\k. real_measure(s k)) <= B)
+        ==> real_measurable(UNIONS { s(n) | n IN (:num) }) /\
+            ((\n. real_measure(s n)) real_sums
+             real_measure(UNIONS { s(n) | n IN (:num) })) (from 0)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n. UNIONS (IMAGE s (0..n)):real->bool`; `B:real`]
+               HAS_REAL_MEASURE_NESTED_UNIONS) THEN
+  REWRITE_TAC[real_sums; FROM_0; INTER_UNIV] THEN
+  SUBGOAL_THEN
+   `!n. (UNIONS (IMAGE s (0..n)):real->bool) has_real_measure
+        (sum(0..n) (\k. real_measure(s k)))`
+  MP_TAC THENL
+   [GEN_TAC THEN MATCH_MP_TAC HAS_REAL_MEASURE_REAL_NEGLIGIBLE_UNIONS_IMAGE THEN
+    ASM_SIMP_TAC[FINITE_NUMSEG];
+    ALL_TAC] THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN
+    ASSUME_TAC(GEN `n:num` (MATCH_MP REAL_MEASURE_UNIQUE
+     (SPEC `n:num` th)))) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [ASM_MESON_TAC[real_measurable]; ALL_TAC] THEN
+    GEN_TAC THEN MATCH_MP_TAC SUBSET_UNIONS THEN
+    MATCH_MP_TAC IMAGE_SUBSET THEN
+    REWRITE_TAC[SUBSET; IN_NUMSEG] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  SIMP_TAC[LIFT_SUM; FINITE_NUMSEG; o_DEF] THEN
+  SUBGOAL_THEN
+   `UNIONS {UNIONS (IMAGE s (0..n)) | n IN (:num)}:real->bool =
+    UNIONS (IMAGE s (:num))`
+   (fun th -> REWRITE_TAC[th] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+              REWRITE_TAC[]) THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN X_GEN_TAC `x:real` THEN
+  REWRITE_TAC[IN_UNIONS] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE; EXISTS_IN_UNIONS; IN_UNIV] THEN
+  REWRITE_TAC[IN_UNIONS; EXISTS_IN_IMAGE] THEN
+  REWRITE_TAC[IN_NUMSEG; LE_0] THEN MESON_TAC[LE_REFL]);;
+
+let REAL_NEGLIGIBLE_COUNTABLE_UNIONS = prove
+ (`!s:num->real->bool.
+        (!n. real_negligible(s n))
+        ==> real_negligible(UNIONS {s(n) | n IN (:num)})`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:num->real->bool`; `&0`]
+    HAS_REAL_MEASURE_COUNTABLE_REAL_NEGLIGIBLE_UNIONS) THEN
+  ASM_SIMP_TAC[REAL_MEASURE_EQ_0; SUM_0; REAL_LE_REFL; LIFT_NUM] THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[HAS_REAL_MEASURE_0; real_measurable; INTER_SUBSET;
+                  REAL_NEGLIGIBLE_SUBSET];
+    ALL_TAC] THEN
+  SIMP_TAC[GSYM REAL_MEASURABLE_REAL_MEASURE_EQ_0] THEN
+  STRIP_TAC THEN
+  MATCH_MP_TAC REAL_SERIES_UNIQUE THEN REWRITE_TAC[LIFT_NUM] THEN
+  MAP_EVERY EXISTS_TAC [`(\k. &0):num->real`; `from 0`] THEN
+  ASM_REWRITE_TAC[REAL_SERIES_0]);;
+
+let REAL_MEASURABLE_COUNTABLE_UNIONS_STRONG = prove
+ (`!s:num->real->bool B.
+        (!n. real_measurable(s n)) /\
+        (!n. real_measure(UNIONS {s k | k <= n}) <= B)
+        ==> real_measurable(UNIONS { s(n) | n IN (:num) })`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`\n. UNIONS (IMAGE s (0..n)):real->bool`; `B:real`]
+               REAL_MEASURABLE_NESTED_UNIONS) THEN
+  SUBGOAL_THEN
+   `UNIONS {UNIONS (IMAGE s (0..n)) | n IN (:num)}:real->bool =
+    UNIONS (IMAGE s (:num))`
+   (fun th -> REWRITE_TAC[th])
+  THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN X_GEN_TAC `x:real` THEN
+    REWRITE_TAC[IN_UNIONS] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+    REWRITE_TAC[EXISTS_IN_IMAGE; EXISTS_IN_UNIONS; IN_UNIV] THEN
+    REWRITE_TAC[IN_UNIONS; EXISTS_IN_IMAGE] THEN
+    REWRITE_TAC[IN_NUMSEG; LE_0] THEN MESON_TAC[LE_REFL];
+    ALL_TAC] THEN
+  DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [GEN_TAC THEN MATCH_MP_TAC REAL_MEASURABLE_UNIONS THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE; FINITE_NUMSEG];
+    ONCE_REWRITE_TAC[GSYM SIMPLE_IMAGE] THEN
+    ASM_REWRITE_TAC[IN_NUMSEG; LE_0];
+    GEN_TAC THEN MATCH_MP_TAC SUBSET_UNIONS THEN
+    MATCH_MP_TAC IMAGE_SUBSET THEN
+    REWRITE_TAC[SUBSET; IN_NUMSEG; LE_0] THEN ARITH_TAC]);;
+
+let HAS_REAL_MEASURE_COUNTABLE_REAL_NEGLIGIBLE_UNIONS_BOUNDED = prove
+ (`!s. (!n. real_measurable(s n)) /\
+       (!m n. ~(m = n) ==> real_negligible(s m INTER s n)) /\
+       real_bounded(UNIONS { s(n) | n IN (:num) })
+       ==> real_measurable(UNIONS { s(n) | n IN (:num) }) /\
+           ((\n. real_measure(s n)) real_sums
+            real_measure(UNIONS { s(n) | n IN (:num) })) (from 0)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[TENDSTO_REAL; o_DEF] THEN
+  REWRITE_TAC[REAL_BOUNDED] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_SIMP_TAC[REAL_MEASURE_MEASURE] THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[REAL_MEASURABLE_MEASURABLE; real_negligible] THEN
+  REPEAT(DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC)) THEN
+  MP_TAC(ISPEC `IMAGE lift o (s:num->real->bool)`
+        HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS_BOUNDED) THEN
+  ASM_SIMP_TAC[o_THM; IMAGE_SUBSET] THEN
+  REWRITE_TAC[SET_RULE `{IMAGE f (s n) | P n} = IMAGE (IMAGE f) {s n | P n}`;
+              GSYM IMAGE_UNIONS] THEN
+  ASM_SIMP_TAC[GSYM IMAGE_INTER_INJ; LIFT_EQ] THEN
+  SIMP_TAC[REAL_SUMS; o_DEF; REAL_MEASURE_MEASURE;
+           REAL_MEASURABLE_MEASURABLE]);;
+
+let REAL_MEASURABLE_COUNTABLE_UNIONS = prove
+ (`!s B. (!n. real_measurable(s n)) /\
+         (!n. sum (0..n) (\k. real_measure(s k)) <= B)
+         ==> real_measurable(UNIONS { s(n) | n IN (:num) })`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_MEASURABLE_COUNTABLE_UNIONS_STRONG THEN
+  EXISTS_TAC `B:real` THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `n:num` THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum(0..n) (\k. real_measure(s k:real->bool))` THEN
+  ASM_REWRITE_TAC[] THEN
+  W(MP_TAC o PART_MATCH (rand o rand) REAL_MEASURE_UNIONS_LE_IMAGE o
+       rand o snd) THEN
+  ASM_REWRITE_TAC[FINITE_NUMSEG] THEN
+  ONCE_REWRITE_TAC[GSYM SIMPLE_IMAGE] THEN
+  REWRITE_TAC[IN_NUMSEG; LE_0]);;
+
+let REAL_MEASURABLE_COUNTABLE_UNIONS_BOUNDED = prove
+ (`!s. (!n. real_measurable(s n)) /\
+       real_bounded(UNIONS { s(n) | n IN (:num) })
+       ==> real_measurable(UNIONS { s(n) | n IN (:num) })`,
+  REWRITE_TAC[REAL_MEASURABLE_MEASURABLE; REAL_BOUNDED] THEN
+  SIMP_TAC[IMAGE_INTER_INJ; LIFT_EQ; IMAGE_UNIONS] THEN
+  REWRITE_TAC[SET_RULE `IMAGE f {g x | x IN s} = {f(g x) | x IN s}`] THEN
+  REWRITE_TAC[MEASURABLE_COUNTABLE_UNIONS_BOUNDED]);;
+
+let REAL_MEASURABLE_COUNTABLE_INTERS = prove
+ (`!s. (!n. real_measurable(s n))
+       ==> real_measurable(INTERS { s(n) | n IN (:num) })`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `INTERS { s(n):real->bool | n IN (:num) } =
+                s 0 DIFF (UNIONS {s 0 DIFF s n | n IN (:num)})`
+  SUBST1_TAC THENL
+   [GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_INTERS; IN_DIFF; IN_UNIONS] THEN
+    REWRITE_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE; EXISTS_IN_IMAGE] THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_MEASURABLE_DIFF THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC REAL_MEASURABLE_COUNTABLE_UNIONS_STRONG THEN
+  EXISTS_TAC `real_measure(s 0:real->bool)` THEN
+  ASM_SIMP_TAC[REAL_MEASURABLE_DIFF; LE_0] THEN
+  GEN_TAC THEN MATCH_MP_TAC REAL_MEASURE_SUBSET THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[SUBSET; FORALL_IN_UNIONS; IN_ELIM_THM; IN_DIFF] THEN
+    MESON_TAC[IN_DIFF]] THEN
+  ONCE_REWRITE_TAC[GSYM IN_NUMSEG_0] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; FINITE_IMAGE; FINITE_NUMSEG;
+               REAL_MEASURABLE_DIFF; REAL_MEASURABLE_UNIONS]);;
+
+let REAL_NEGLIGIBLE_COUNTABLE = prove
+ (`!s. COUNTABLE s ==> real_negligible s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[real_negligible] THEN
+  MATCH_MP_TAC NEGLIGIBLE_COUNTABLE THEN ASM_SIMP_TAC[COUNTABLE_IMAGE]);;
+
+let REAL_MEASURABLE_COMPACT = prove
+ (`!s. real_compact s ==> real_measurable s`,
+  REWRITE_TAC[REAL_MEASURABLE_MEASURABLE; real_compact; MEASURABLE_COMPACT]);;
+
+let REAL_MEASURABLE_OPEN = prove
+ (`!s. real_bounded s /\ real_open s ==> real_measurable s`,
+  REWRITE_TAC[REAL_MEASURABLE_MEASURABLE; REAL_OPEN; REAL_BOUNDED;
+              MEASURABLE_OPEN]);;
+
+let HAS_REAL_INTEGRAL_NEGLIGIBLE_EQ = prove
+ (`!f s. (!x. x IN s ==> &0 <= f(x))
+         ==> ((f has_real_integral &0) s <=>
+              real_negligible {x | x IN s /\ ~(f x = &0)})`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC HAS_REAL_INTEGRAL_NEGLIGIBLE THEN
+    EXISTS_TAC `{x | x IN s /\ ~((f:real->real) x = &0)}` THEN
+    ASM_REWRITE_TAC[IN_DIFF; IN_ELIM_THM] THEN MESON_TAC[]] THEN
+  MATCH_MP_TAC REAL_NEGLIGIBLE_SUBSET THEN EXISTS_TAC
+   `UNIONS {{x:real | x IN s /\ abs(f x) >= &1 / (&n + &1)} |
+            n IN (:num)}` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_NEGLIGIBLE_COUNTABLE_UNIONS THEN
+    X_GEN_TAC `n:num` THEN REWRITE_TAC[GSYM HAS_REAL_MEASURE_0] THEN
+    REWRITE_TAC[HAS_REAL_MEASURE] THEN
+    MATCH_MP_TAC HAS_REAL_INTEGRAL_STRADDLE_NULL THEN
+    EXISTS_TAC `\x:real. if x IN s then (&n + &1) * f(x) else &0` THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[IN_UNIV; IN_ELIM_THM; real_ge] THEN
+      X_GEN_TAC `x:real` THEN COND_CASES_TAC THEN
+      ASM_SIMP_TAC[REAL_POS] THENL
+       [ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+        ASM_SIMP_TAC[GSYM REAL_LE_LDIV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+        MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ a <= abs x ==> a <= x`) THEN
+        ASM_SIMP_TAC[];
+        COND_CASES_TAC THEN REWRITE_TAC[REAL_POS] THEN
+        ASM_SIMP_TAC[REAL_POS; REAL_LE_MUL; REAL_LE_ADD]];
+      REWRITE_TAC[HAS_REAL_INTEGRAL_RESTRICT_UNIV] THEN
+      SUBST1_TAC(REAL_ARITH `&0 = (&n + &1) * &0`) THEN
+      MATCH_MP_TAC HAS_REAL_INTEGRAL_LMUL THEN ASM_REWRITE_TAC[]];
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN X_GEN_TAC `x:real` THEN
+    REWRITE_TAC[REAL_ABS_NZ] THEN ONCE_REWRITE_TAC[REAL_ARCH_INV] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (X_CHOOSE_THEN `n:num`
+      STRIP_ASSUME_TAC)) THEN
+    REWRITE_TAC[IN_UNIONS; EXISTS_IN_GSPEC] THEN
+    EXISTS_TAC `n - 1` THEN ASM_SIMP_TAC[IN_UNIV; IN_ELIM_THM; real_ge] THEN
+    ASM_SIMP_TAC[REAL_OF_NUM_ADD; SUB_ADD; LE_1] THEN
+    ASM_SIMP_TAC[real_div; REAL_MUL_LID; REAL_LT_IMP_LE]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Drop the k'th coordinate, or insert t at the k'th coordinate.             *)
+(* ------------------------------------------------------------------------- *)
+
+let dropout = new_definition
+ `(dropout:num->real^N->real^M) k x =
+        lambda i. if i < k then x$i else x$(i + 1)`;;
+
+let pushin = new_definition
+ `pushin k t x = lambda i. if i < k then x$i
+                           else if i = k then t
+                           else x$(i - 1)`;;
+
+let DROPOUT_PUSHIN = prove
+ (`!k t x.
+        dimindex(:M) + 1 = dimindex(:N)
+        ==> (dropout k:real^N->real^M) (pushin k t x) = x`,
+  REPEAT GEN_TAC THEN DISCH_THEN(ASSUME_TAC o SYM) THEN
+  ASM_SIMP_TAC[CART_EQ; dropout; pushin; LAMBDA_BETA;
+               ARITH_RULE `1 <= n + 1`; ADD_SUB;
+               ARITH_RULE `m <= n ==> m <= n + 1 /\ m + 1 <= n + 1`] THEN
+  ARITH_TAC);;
+
+let PUSHIN_DROPOUT = prove
+ (`!k x.
+        dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> pushin k (x$k) ((dropout k:real^N->real^M) x) = x`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN(ASSUME_TAC o GSYM)) THEN
+  ASM_SIMP_TAC[CART_EQ; dropout; pushin; LAMBDA_BETA;
+               ARITH_RULE `i <= n + 1 ==> i - 1 <= n`] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  ASM_CASES_TAC `i:num = k` THEN ASM_REWRITE_TAC[LT_REFL] THEN
+  FIRST_X_ASSUM(DISJ_CASES_TAC o MATCH_MP (ARITH_RULE
+   `~(i:num = k) ==> i < k \/ k < i`)) THEN
+  ASM_SIMP_TAC[ARITH_RULE `i:num < k ==> ~(k < i)`] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) LAMBDA_BETA o lhand o snd) THEN
+  (ANTS_TAC THENL [ASM_ARITH_TAC; DISCH_THEN SUBST1_TAC]) THEN
+  ASM_SIMP_TAC[ARITH_RULE `k < i ==> ~(i - 1 < k)`] THEN
+  AP_TERM_TAC THEN ASM_ARITH_TAC);;
+
+let DROPOUT_GALOIS = prove
+ (`!k x:real^N y:real^M.
+        dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> (y = dropout k x <=> (?t. x = pushin k t y))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [DISCH_THEN SUBST1_TAC THEN
+    EXISTS_TAC `(x:real^N)$k` THEN ASM_SIMP_TAC[PUSHIN_DROPOUT];
+    DISCH_THEN(X_CHOOSE_THEN `t:real` SUBST1_TAC) THEN
+    ASM_SIMP_TAC[DROPOUT_PUSHIN]]);;
+
+let IN_IMAGE_DROPOUT = prove
+ (`!x s.
+        dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> (x IN IMAGE (dropout k:real^N->real^M) s <=>
+             ?t. (pushin k t x) IN s)`,
+  SIMP_TAC[IN_IMAGE; DROPOUT_GALOIS] THEN MESON_TAC[]);;
+
+let CLOSED_INTERVAL_DROPOUT = prove
+ (`!k a b. dimindex(:M) + 1 = dimindex(:N) /\
+           1 <= k /\ k <= dimindex(:N) /\
+           a$k <= b$k
+           ==> interval[dropout k a,dropout k b] =
+               IMAGE (dropout k:real^N->real^M) (interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[EXTENSION; IN_IMAGE_DROPOUT; IN_INTERVAL] THEN
+  X_GEN_TAC `x:real^M` THEN
+  SIMP_TAC[pushin; dropout; LAMBDA_BETA] THEN EQ_TAC THENL
+   [DISCH_TAC THEN EXISTS_TAC `(a:real^N)$k` THEN X_GEN_TAC `i:num` THEN
+    STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN MATCH_MP_TAC THEN ASM_ARITH_TAC;
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_LE_REFL] THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `i - 1`) THEN
+      COND_CASES_TAC THENL [ASM_ARITH_TAC; ASM_REWRITE_TAC[]] THEN
+      ANTS_TAC THENL [ASM_ARITH_TAC; ASM_SIMP_TAC[SUB_ADD]]];
+    DISCH_THEN(X_CHOOSE_TAC `t:real`) THEN X_GEN_TAC `i:num` THEN
+    STRIP_TAC THEN COND_CASES_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN MATCH_MP_TAC THEN ASM_ARITH_TAC;
+      FIRST_X_ASSUM(MP_TAC o SPEC `i + 1`) THEN
+      ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+      ASM_REWRITE_TAC[ADD_SUB]]]);;
+
+let IMAGE_DROPOUT_CLOSED_INTERVAL = prove
+ (`!k a b. dimindex(:M) + 1 = dimindex(:N) /\
+           1 <= k /\ k <= dimindex(:N)
+           ==> IMAGE (dropout k:real^N->real^M) (interval[a,b]) =
+                  if a$k <= b$k then interval[dropout k a,dropout k b]
+                  else {}`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  ASM_SIMP_TAC[CLOSED_INTERVAL_DROPOUT; IMAGE_EQ_EMPTY] THEN
+  REWRITE_TAC[INTERVAL_EQ_EMPTY; GSYM REAL_NOT_LE] THEN ASM_MESON_TAC[]);;
+
+let LINEAR_DROPOUT = prove
+ (`!k. dimindex(:M) < dimindex(:N)
+       ==> linear(dropout k :real^N->real^M)`,
+  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP (ARITH_RULE
+   `m < n ==> !i:num. i <= m ==> i <= n /\ i + 1 <= n`)) THEN
+  SIMP_TAC[linear; CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+           dropout; LAMBDA_BETA] THEN
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+               ARITH_RULE `1 <= i + 1`]);;
+
+let DROPOUT_EQ = prove
+ (`!x y k. dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N) /\
+           x$k = y$k /\ (dropout k:real^N->real^M) x = dropout k y
+           ==> x = y`,
+  SIMP_TAC[CART_EQ; dropout; VEC_COMPONENT; LAMBDA_BETA; IN_ELIM_THM] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`; `k:num`] THEN
+  STRIP_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  ASM_CASES_TAC `i:num = k` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (ARITH_RULE
+   `~(i:num = k) ==> i < k \/ k < i`))
+  THENL
+   [FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_SIMP_TAC[];
+    FIRST_X_ASSUM(MP_TAC o SPEC `i - 1`) THEN
+    ASM_SIMP_TAC[SUB_ADD; ARITH_RULE `k < i ==> ~(i - 1 < k)`]] THEN
+  DISCH_THEN MATCH_MP_TAC THEN ASM_ARITH_TAC);;
+
+let DROPOUT_0 = prove
+ (`dropout k (vec 0:real^N) = vec 0`,
+  SIMP_TAC[dropout; VEC_COMPONENT; CART_EQ; COND_ID; LAMBDA_BETA]);;
+
+let DOT_DROPOUT = prove
+ (`!k x y:real^N.
+        dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> (dropout k x:real^M) dot (dropout k y) = x dot y - x$k * y$k`,
+  REPEAT STRIP_TAC THEN SIMP_TAC[dot; dropout; LAMBDA_BETA] THEN
+  REWRITE_TAC[TAUT `(if p then x else y:real) * (if p then a else b) =
+                    (if p then x * a else y * b)`] THEN
+  SIMP_TAC[SUM_CASES; FINITE_NUMSEG] THEN
+  SUBGOAL_THEN
+   `(!i. i IN 1..dimindex(:M) /\ i < k <=> i IN 1..k-1) /\
+    (!i.  i IN 1..dimindex(:M) /\ ~(i < k) <=> i IN k..dimindex(:M))`
+  (fun th -> REWRITE_TAC[th])
+  THENL [REWRITE_TAC[IN_NUMSEG] THEN ASM_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[SIMPLE_IMAGE; IMAGE_ID] THEN
+  REWRITE_TAC[GSYM(SPEC `1` SUM_OFFSET)] THEN
+  W(MP_TAC o PART_MATCH (rhs o rand) SUM_UNION o lhs o snd) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[FINITE_NUMSEG; DISJOINT_NUMSEG] THEN ARITH_TAC;
+    DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  MP_TAC(ISPECL [`\i. (x:real^N)$i * (y:real^N)$i`;
+                 `1..dimindex(:N)`;
+                 `k:num`] SUM_DELETE) THEN
+  ASM_REWRITE_TAC[IN_NUMSEG; FINITE_NUMSEG] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_NUMSEG; IN_UNION; IN_DELETE] THEN ASM_ARITH_TAC);;
+
+let DOT_PUSHIN = prove
+ (`!k a b x y:real^M.
+        dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> (pushin k a x:real^N) dot (pushin k b y) = x dot y + a * b`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `(dropout k (pushin k a (x:real^M):real^N):real^M) dot
+              (dropout k (pushin k b (y:real^M):real^N):real^M) +
+              a * b` THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_SIMP_TAC[DROPOUT_PUSHIN]] THEN
+  ASM_SIMP_TAC[DOT_DROPOUT] THEN
+  MATCH_MP_TAC(REAL_RING
+   `a':real = a /\ b' = b ==> x = x - a' * b' + a * b`) THEN
+  ASM_SIMP_TAC[pushin; LAMBDA_BETA; LT_REFL]);;
+
+let DROPOUT_ADD = prove
+ (`!k x y:real^N. dropout k (x + y) = dropout k x + dropout k y`,
+  SIMP_TAC[dropout; VECTOR_ADD_COMPONENT; CART_EQ; LAMBDA_BETA] THEN
+  MESON_TAC[]);;
+
+let DROPOUT_SUB = prove
+ (`!k x y:real^N. dropout k (x - y) = dropout k x - dropout k y`,
+  SIMP_TAC[dropout; VECTOR_SUB_COMPONENT; CART_EQ; LAMBDA_BETA] THEN
+  MESON_TAC[]);;
+
+let DROPOUT_MUL = prove
+ (`!k c x:real^N. dropout k (c % x) = c % dropout k x`,
+  SIMP_TAC[dropout; VECTOR_MUL_COMPONENT; CART_EQ; LAMBDA_BETA] THEN
+  MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Take slice of set s at x$k = t and drop the k'th coordinate.              *)
+(* ------------------------------------------------------------------------- *)
+
+let slice = new_definition
+ `slice k t s = IMAGE (dropout k) (s INTER {x | x$k = t})`;;
+
+let IN_SLICE = prove
+ (`!s:real^N->bool y:real^M.
+        dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> (y IN slice k t s <=> pushin k t y IN s)`,
+  SIMP_TAC[slice; IN_IMAGE_DROPOUT; IN_INTER; IN_ELIM_THM] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[pushin] THEN
+  ASM_SIMP_TAC[LAMBDA_BETA; LT_REFL] THEN MESON_TAC[]);;
+
+let INTERVAL_INTER_HYPERPLANE = prove
+ (`!k t a b:real^N.
+        1 <= k /\ k <= dimindex(:N)
+        ==> interval[a,b] INTER {x | x$k = t} =
+                if a$k <= t /\ t <= b$k
+                then interval[(lambda i. if i = k then t else a$i),
+                              (lambda i. if i = k then t else b$i)]
+                else {}`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_INTER; IN_INTERVAL; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [ALL_TAC; ASM_MESON_TAC[NOT_IN_EMPTY]] THEN
+  SIMP_TAC[IN_INTERVAL; LAMBDA_BETA] THEN
+  EQ_TAC THEN STRIP_TAC THENL [ASM_MESON_TAC[REAL_LE_ANTISYM]; ALL_TAC] THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[REAL_LE_ANTISYM]] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC);;
+
+let SLICE_INTERVAL = prove
+ (`!k a b t. dimindex(:M) + 1 = dimindex(:N) /\
+             1 <= k /\ k <= dimindex(:N)
+             ==> slice k t (interval[a,b]) =
+                 if a$k <= t /\ t <= b$k
+                 then interval[(dropout k:real^N->real^M) a,dropout k b]
+                 else {}`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[slice; INTERVAL_INTER_HYPERPLANE] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[IMAGE_CLAUSES] THEN
+  ASM_SIMP_TAC[IMAGE_DROPOUT_CLOSED_INTERVAL; LAMBDA_BETA; REAL_LE_REFL] THEN
+  MATCH_MP_TAC(MESON[]
+   `a = a' /\ b = b' ==> interval[a,b] = interval[a',b']`) THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; dropout] THEN
+  SUBGOAL_THEN
+   `!i. i <= dimindex(:M) ==> i <= dimindex(:N) /\ i + 1 <= dimindex(:N)`
+  MP_TAC THENL
+   [ASM_ARITH_TAC;
+    ASM_SIMP_TAC[LAMBDA_BETA; ARITH_RULE `1 <= i + 1`] THEN ARITH_TAC]);;
+
+let SLICE_DIFF = prove
+ (`!k a s t.
+        dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> (slice k a:(real^N->bool)->(real^M->bool)) (s DIFF t) =
+             (slice k a s) DIFF (slice k a t)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[slice] THEN
+  SIMP_TAC[SET_RULE `(s DIFF t) INTER u = (s INTER u) DIFF (t INTER u)`] THEN
+  MATCH_MP_TAC(SET_RULE
+   `(!x y. x IN a /\ y IN a /\ f x = f y ==> x = y)
+    ==> IMAGE f ((s INTER a) DIFF (t INTER a)) =
+        IMAGE f (s INTER a) DIFF IMAGE f (t INTER a)`) THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[DROPOUT_EQ]);;
+
+let SLICE_UNIV = prove
+ (`!k a. dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> slice k a (:real^N) = (:real^M)`,
+  REPEAT STRIP_TAC THEN
+  SIMP_TAC[EXTENSION; IN_UNIV; IN_IMAGE; slice; INTER_UNIV; IN_ELIM_THM] THEN
+  X_GEN_TAC `y:real^M` THEN EXISTS_TAC `(pushin k a:real^M->real^N) y` THEN
+  ASM_SIMP_TAC[DROPOUT_PUSHIN] THEN
+  ASM_SIMP_TAC[pushin; LAMBDA_BETA; LT_REFL]);;
+
+let SLICE_EMPTY = prove
+ (`!k a. slice k a {} = {}`,
+  REWRITE_TAC[slice; INTER_EMPTY; IMAGE_CLAUSES]);;
+
+let SLICE_SUBSET = prove
+ (`!s t k a. s SUBSET t ==> slice k a s SUBSET slice k a t`,
+  REWRITE_TAC[slice] THEN SET_TAC[]);;
+
+let SLICE_UNIONS = prove
+ (`!s k a. slice k a (UNIONS s) = UNIONS (IMAGE (slice k a) s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[slice; INTER_UNIONS; IMAGE_UNIONS] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN REWRITE_TAC[GSYM IMAGE_o] THEN
+  AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; o_THM; slice]);;
+
+let SLICE_UNION = prove
+ (`!k a s t.
+        dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> (slice k a:(real^N->bool)->(real^M->bool)) (s UNION t) =
+             (slice k a s) UNION (slice k a t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[slice; IMAGE_UNION;
+        SET_RULE `(s UNION t) INTER u = (s INTER u) UNION (t INTER u)`] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN REWRITE_TAC[GSYM IMAGE_o] THEN
+  AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; o_THM; slice]);;
+
+let SLICE_INTER = prove
+ (`!k a s t.
+        dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> (slice k a:(real^N->bool)->(real^M->bool)) (s INTER t) =
+             (slice k a s) INTER (slice k a t)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[slice] THEN
+  MATCH_MP_TAC(SET_RULE
+    `(!x y. x IN u /\ y IN u /\ f x = f y ==> x = y)
+     ==> IMAGE f ((s INTER t) INTER u) =
+         IMAGE f (s INTER u) INTER IMAGE f (t INTER u)`) THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[DROPOUT_EQ]);;
+
+let CONVEX_SLICE = prove
+ (`!k t s. dimindex(:M) < dimindex(:N) /\ convex s
+           ==> convex((slice k t:(real^N->bool)->(real^M->bool)) s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[slice] THEN
+  MATCH_MP_TAC CONVEX_LINEAR_IMAGE THEN ASM_SIMP_TAC[LINEAR_DROPOUT] THEN
+  MATCH_MP_TAC CONVEX_INTER THEN ASM_REWRITE_TAC[CONVEX_STANDARD_HYPERPLANE]);;
+
+let COMPACT_SLICE = prove
+ (`!k t s. dimindex(:M) < dimindex(:N) /\ compact s
+           ==> compact((slice k t:(real^N->bool)->(real^M->bool)) s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[slice] THEN
+  MATCH_MP_TAC COMPACT_LINEAR_IMAGE THEN ASM_SIMP_TAC[LINEAR_DROPOUT] THEN
+  REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC BOUNDED_INTER THEN ASM_SIMP_TAC[COMPACT_IMP_BOUNDED];
+    MATCH_MP_TAC CLOSED_INTER THEN
+    ASM_SIMP_TAC[COMPACT_IMP_CLOSED; CLOSED_STANDARD_HYPERPLANE]]);;
+
+let CLOSED_SLICE = prove
+ (`!k t s. dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N) /\
+           closed s
+           ==> closed((slice k t:(real^N->bool)->(real^M->bool)) s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[slice] THEN
+  SUBGOAL_THEN
+   `closed(IMAGE (dropout k:real^N->real^M)
+                 (IMAGE (\x. x - t % basis k)
+                        (s INTER {x | x$k = t})))`
+  MP_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[GSYM IMAGE_o] THEN MATCH_MP_TAC EQ_IMP THEN
+    AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    REWRITE_TAC[FUN_EQ_THM; o_THM; dropout] THEN
+    SUBGOAL_THEN
+     `!i. i <= dimindex(:M) ==> i <= dimindex(:N) /\ i + 1 <= dimindex(:N)`
+    MP_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+    SIMP_TAC[VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT; CART_EQ;
+             LAMBDA_BETA; BASIS_COMPONENT; ARITH_RULE `1 <= i + 1`] THEN
+    SIMP_TAC[ARITH_RULE `i:num < k ==> ~(i = k)`;
+             ARITH_RULE `~(i < k) ==> ~(i + 1 = k)`] THEN
+    REWRITE_TAC[REAL_MUL_RZERO; REAL_SUB_RZERO]] THEN
+  MATCH_MP_TAC CLOSED_INJECTIVE_IMAGE_SUBSET_SUBSPACE THEN
+  EXISTS_TAC `{x:real^N | x$k = &0}` THEN
+  ASM_SIMP_TAC[SUBSPACE_SPECIAL_HYPERPLANE; LINEAR_DROPOUT;
+               ARITH_RULE `m + 1 = n ==> m < n`] THEN
+  REPEAT CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[VECTOR_ARITH `x - t % b:real^N = --(t % b) + x`] THEN
+    ASM_SIMP_TAC[CLOSED_TRANSLATION_EQ; CLOSED_INTER;
+                 CLOSED_STANDARD_HYPERPLANE];
+    MATCH_MP_TAC(SET_RULE
+     `IMAGE f t SUBSET u ==> IMAGE f (s INTER t) SUBSET u`) THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+    ASM_SIMP_TAC[VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT; BASIS_COMPONENT;
+                 REAL_MUL_RID; REAL_SUB_REFL];
+    REWRITE_TAC[IN_ELIM_THM] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC DROPOUT_EQ THEN EXISTS_TAC `k:num` THEN
+    ASM_REWRITE_TAC[DROPOUT_0; VEC_COMPONENT]]);;
+
+let OPEN_SLICE = prove
+ (`!k t s. dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N) /\
+           open s
+           ==> open((slice k t:(real^N->bool)->(real^M->bool)) s)`,
+  REWRITE_TAC[OPEN_CLOSED] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `closed(slice k t ((:real^N) DIFF s):real^M->bool)`
+  MP_TAC THENL
+   [ASM_SIMP_TAC[CLOSED_SLICE];
+   ASM_SIMP_TAC[SLICE_DIFF; SLICE_UNIV]]);;
+
+let BOUNDED_SLICE = prove
+ (`!k t s. dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N) /\
+           bounded s
+           ==> bounded((slice k t:(real^N->bool)->(real^M->bool)) s)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+  MATCH_MP_TAC BOUNDED_SUBSET THEN
+  EXISTS_TAC `(slice k t:(real^N->bool)->(real^M->bool)) (interval[a,b])` THEN
+  ASM_SIMP_TAC[SLICE_SUBSET] THEN ASM_SIMP_TAC[SLICE_INTERVAL] THEN
+  MESON_TAC[BOUNDED_EMPTY; BOUNDED_INTERVAL]);;
+
+let SLICE_CBALL = prove
+ (`!k t x r.
+        dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> (slice k t:(real^N->bool)->(real^M->bool)) (cball(x,r)) =
+                if abs(t - x$k) <= r
+                then cball(dropout k x,sqrt(r pow 2 - (t - x$k) pow 2))
+                else {}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[slice] THEN COND_CASES_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[IMAGE_EQ_EMPTY] THEN
+    REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INTER; NOT_IN_EMPTY; IN_CBALL] THEN
+    X_GEN_TAC `y:real^N` THEN REWRITE_TAC[dist] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `~(a <= r) ==> a <= b ==> b <= r ==> F`)) THEN
+    ASM_MESON_TAC[VECTOR_SUB_COMPONENT; COMPONENT_LE_NORM; NORM_SUB]] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP(REAL_ARITH `abs(x) <= r ==> &0 <= r`)) THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_CBALL] THEN X_GEN_TAC `y:real^M` THEN
+  ASM_SIMP_TAC[DROPOUT_GALOIS; LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN REWRITE_TAC[UNWIND_THM2] THEN
+  REWRITE_TAC[IN_CBALL; IN_INTER; IN_ELIM_THM] THEN
+  ASM_SIMP_TAC[pushin; LAMBDA_BETA; LT_REFL] THEN
+  ONCE_REWRITE_TAC[CONJ_SYM] THEN REWRITE_TAC[UNWIND_THM2] THEN
+  ASM_REWRITE_TAC[dist; NORM_LE_SQUARE; GSYM pushin] THEN
+  ASM_SIMP_TAC[SQRT_POW_2; SQRT_POS_LE; REAL_SUB_LE; GSYM REAL_LE_SQUARE_ABS;
+               REAL_ARITH `abs(x) <= r ==> abs(x) <= abs(r)`] THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `(x - y:real^N) dot (x - y) = x dot x + y dot y - &2 * x dot y`] THEN
+  ASM_SIMP_TAC[DOT_DROPOUT; DOT_PUSHIN] THEN MATCH_MP_TAC(REAL_FIELD
+     `a = t * k + b
+      ==> (xx + (yy + t * t) - &2 * a <= r pow 2 <=>
+           xx - k * k + yy - &2 * b <= r pow 2 - (t - k) pow 2)`) THEN
+  SUBGOAL_THEN
+   `y:real^M = dropout k (pushin k t y:real^N)`
+   (fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [th])
+  THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC DROPOUT_PUSHIN THEN ASM_ARITH_TAC;
+    ASM_SIMP_TAC[DOT_DROPOUT] THEN
+    ASM_SIMP_TAC[pushin; LAMBDA_BETA; LT_REFL] THEN REAL_ARITH_TAC]);;
+
+let SLICE_BALL = prove
+ (`!k t x r.
+        dimindex(:M) + 1 = dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> (slice k t:(real^N->bool)->(real^M->bool)) (ball(x,r)) =
+                if abs(t - x$k) < r
+                then ball(dropout k x,sqrt(r pow 2 - (t - x$k) pow 2))
+                else {}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[slice] THEN COND_CASES_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[IMAGE_EQ_EMPTY] THEN
+    REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INTER; NOT_IN_EMPTY; IN_BALL] THEN
+    X_GEN_TAC `y:real^N` THEN REWRITE_TAC[dist] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `~(a < r) ==> a <= b ==> b < r ==> F`)) THEN
+    ASM_MESON_TAC[VECTOR_SUB_COMPONENT; COMPONENT_LE_NORM; NORM_SUB]] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP(REAL_ARITH `abs(x) < r ==> &0 < r`)) THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_BALL] THEN X_GEN_TAC `y:real^M` THEN
+  ASM_SIMP_TAC[DROPOUT_GALOIS; LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN REWRITE_TAC[UNWIND_THM2] THEN
+  REWRITE_TAC[IN_BALL; IN_INTER; IN_ELIM_THM] THEN
+  ASM_SIMP_TAC[pushin; LAMBDA_BETA; LT_REFL] THEN
+  ONCE_REWRITE_TAC[CONJ_SYM] THEN REWRITE_TAC[UNWIND_THM2] THEN
+  ASM_REWRITE_TAC[dist; NORM_LT_SQUARE; GSYM pushin] THEN
+  ASM_SIMP_TAC[SQRT_POW_2; SQRT_POS_LT; REAL_SUB_LT; GSYM REAL_LT_SQUARE_ABS;
+   REAL_LT_IMP_LE; REAL_ARITH `abs(x) < r ==> abs(x) < abs(r)`] THEN
+  REWRITE_TAC[VECTOR_ARITH
+   `(x - y:real^N) dot (x - y) = x dot x + y dot y - &2 * x dot y`] THEN
+  ASM_SIMP_TAC[DOT_DROPOUT; DOT_PUSHIN] THEN MATCH_MP_TAC(REAL_FIELD
+     `a = t * k + b
+      ==> (xx + (yy + t * t) - &2 * a < r pow 2 <=>
+           xx - k * k + yy - &2 * b < r pow 2 - (t - k) pow 2)`) THEN
+  SUBGOAL_THEN
+   `y:real^M = dropout k (pushin k t y:real^N)`
+   (fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [th])
+  THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC DROPOUT_PUSHIN THEN ASM_ARITH_TAC;
+    ASM_SIMP_TAC[DOT_DROPOUT] THEN
+    ASM_SIMP_TAC[pushin; LAMBDA_BETA; LT_REFL] THEN REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Weak but useful versions of Fubini's theorem.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let FUBINI_CLOSED_INTERVAL = prove
+ (`!k a b:real^N.
+        dimindex(:M) + 1 = dimindex(:N) /\
+        1 <= k /\ k <= dimindex(:N) /\
+        a$k <= b$k
+        ==> ((\t. measure (slice k t (interval[a,b]) :real^M->bool))
+             has_real_integral
+             (measure(interval[a,b]))) (:real)`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[SLICE_INTERVAL] THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN
+  REWRITE_TAC[MEASURE_EMPTY; MEASURE_INTERVAL] THEN
+  REWRITE_TAC[GSYM IN_REAL_INTERVAL] THEN
+  SIMP_TAC[HAS_REAL_INTEGRAL_RESTRICT; SUBSET_UNIV] THEN
+  SUBGOAL_THEN
+   `content(interval[a:real^N,b]) =
+    content(interval[dropout k a:real^M,dropout k b]) * (b$k - a$k)`
+  SUBST1_TAC THEN ASM_SIMP_TAC[HAS_REAL_INTEGRAL_CONST] THEN
+  REWRITE_TAC[CONTENT_CLOSED_INTERVAL_CASES] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RATOR_CONV) [COND_RAND] THEN
+  GEN_REWRITE_TAC RAND_CONV [COND_RATOR] THEN
+  REWRITE_TAC[REAL_MUL_LZERO] THEN MATCH_MP_TAC(TAUT
+   `(p <=> p') /\ x = x'
+    ==> (if p then x else y) = (if p' then x' else y)`) THEN
+  CONJ_TAC THENL
+   [SIMP_TAC[dropout; LAMBDA_BETA] THEN EQ_TAC THEN DISCH_TAC THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THENL
+     [COND_CASES_TAC THEN REWRITE_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_ARITH_TAC;
+      ASM_CASES_TAC `i:num = k` THEN ASM_REWRITE_TAC[] THEN
+      ASM_CASES_TAC `i:num < k` THENL
+       [FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[];
+        FIRST_X_ASSUM(MP_TAC o SPEC `i - 1`) THEN
+        COND_CASES_TAC THENL [ASM_ARITH_TAC; ASM_SIMP_TAC[SUB_ADD]]] THEN
+      DISCH_THEN MATCH_MP_TAC THEN ASM_ARITH_TAC];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `1..dimindex(:N) =
+                (1..(k-1)) UNION
+                (k INSERT (IMAGE (\x. x + 1) (k..dimindex(:M))))`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_NUMSEG; IN_UNION; IN_INSERT; IN_IMAGE] THEN
+    ASM_SIMP_TAC[ARITH_RULE
+     `1 <= k
+      ==> (x = y + 1 /\ k <= y /\ y <= n <=>
+           y = x - 1 /\ k + 1 <= x /\ x <= n + 1)`] THEN
+    REWRITE_TAC[CONJ_ASSOC; LEFT_EXISTS_AND_THM; EXISTS_REFL] THEN
+    ASM_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[SET_RULE `s UNION (x INSERT t) = x INSERT (s UNION t)`] THEN
+  SIMP_TAC[PRODUCT_CLAUSES; FINITE_NUMSEG; FINITE_UNION; FINITE_IMAGE] THEN
+  ASM_SIMP_TAC[IN_NUMSEG; IN_UNION; IN_IMAGE; ARITH_RULE
+   `1 <= k ==> ~(k <= k - 1)`] THEN
+  COND_CASES_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+  GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN AP_TERM_TAC THEN
+  MP_TAC(ISPECL [`1`; `k - 1`; `dimindex(:M)`] NUMSEG_COMBINE_R) THEN
+  ANTS_TAC THENL [ASM_ARITH_TAC; DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) PRODUCT_UNION o lhand o snd) THEN
+  SIMP_TAC[FINITE_NUMSEG; FINITE_IMAGE; IN_NUMSEG; SET_RULE
+            `DISJOINT s (IMAGE f t) <=> !x. x IN t ==> ~(f x IN s)`] THEN
+  ANTS_TAC THENL [ASM_ARITH_TAC; DISCH_THEN SUBST1_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) PRODUCT_UNION o rand o snd) THEN
+  SIMP_TAC[FINITE_NUMSEG; FINITE_IMAGE; IN_NUMSEG; SET_RULE
+            `DISJOINT s t <=> !x. ~(x IN s /\ x IN t)`] THEN
+  ANTS_TAC THENL [ASM_ARITH_TAC; DISCH_THEN SUBST1_TAC] THEN
+  ASM_SIMP_TAC[PRODUCT_IMAGE; EQ_ADD_RCANCEL; SUB_ADD] THEN
+  BINOP_TAC THEN MATCH_MP_TAC PRODUCT_EQ_NUMSEG THEN
+  SIMP_TAC[dropout; LAMBDA_BETA; o_THM] THEN
+  REPEAT STRIP_TAC THEN BINOP_TAC THEN
+  (W(MP_TAC o PART_MATCH (lhs o rand) LAMBDA_BETA o rand o snd) THEN
+   ANTS_TAC THENL [ASM_ARITH_TAC; DISCH_THEN SUBST1_TAC] THEN
+   REWRITE_TAC[] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+   ASM_ARITH_TAC));;
+
+let MEASURABLE_OUTER_INTERVALS_BOUNDED_EXPLICIT_SPECIAL = prove
+ (`!s a b e.
+        2 <= dimindex(:N) /\ 1 <= k /\ k <= dimindex(:N) /\
+        measurable s /\ s SUBSET interval[a,b] /\ &0 < e
+        ==> ?f:num->real^N->bool.
+              (!i. (f i) SUBSET interval[a,b] /\
+                   ?c d. c$k <= d$k /\ f i = interval[c,d]) /\
+              (!i j. ~(i = j) ==> negligible(f i INTER f j)) /\
+              s SUBSET UNIONS {f n | n IN (:num)} /\
+              measurable(UNIONS {f n | n IN (:num)}) /\
+              measure(UNIONS {f n | n IN (:num)}) <= measure s + e`,
+  let lemma = prove
+   (`UNIONS {if n IN s then f n else {} | n IN (:num)} =
+     UNIONS (IMAGE f s)`,
+   SIMP_TAC[EXTENSION; IN_UNIONS; IN_ELIM_THM; IN_UNIV; EXISTS_IN_IMAGE] THEN
+   MESON_TAC[NOT_IN_EMPTY]) in
+  REPEAT GEN_TAC THEN
+  REPLICATE_TAC 3 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP MEASURABLE_OUTER_INTERVALS_BOUNDED) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+  ASM_CASES_TAC `FINITE(d:(real^N->bool)->bool)` THENL
+   [FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [FINITE_INDEX_NUMSEG]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `f:num->real^N->bool`
+     (fun th -> SUBST_ALL_TAC(CONJUNCT2 th) THEN ASSUME_TAC(CONJUNCT1 th))) THEN
+     RULE_ASSUM_TAC(REWRITE_RULE[IMP_CONJ; FORALL_IN_IMAGE;
+       RIGHT_FORALL_IMP_THM; IN_UNIV]) THEN
+    EXISTS_TAC `\k. if k IN 1..CARD(d:(real^N->bool)->bool) then f k
+                    else ({}:real^N->bool)` THEN
+    REWRITE_TAC[] THEN CONJ_TAC THENL
+     [X_GEN_TAC `i:num` THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+       [ASM_MESON_TAC[REAL_NOT_LT; IN_NUMSEG; REAL_NOT_LE; INTERVAL_EQ_EMPTY];
+        REWRITE_TAC[EMPTY_SUBSET] THEN CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN
+        EXISTS_TAC `(lambda i. if i = k then &0 else &1):real^N` THEN
+        EXISTS_TAC `(lambda i. if i = k then &1 else &0):real^N` THEN
+        REWRITE_TAC[INTERVAL_EQ_EMPTY] THEN CONJ_TAC THENL
+         [SIMP_TAC[LAMBDA_BETA; ASSUME `1 <= k`; ASSUME `k <= dimindex(:N)`;
+                   REAL_POS];
+          ALL_TAC] THEN
+        SUBGOAL_THEN `?j. 1 <= j /\ j <= dimindex(:N) /\ ~(j = k)` MP_TAC THENL
+         [MATCH_MP_TAC(MESON[] `P(k - 1) \/ P(k + 1) ==> ?i. P i`) THEN
+          ASM_ARITH_TAC;
+          MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[LAMBDA_BETA] THEN
+          REAL_ARITH_TAC]];
+      ALL_TAC] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_REWRITE_TAC[lemma]] THEN
+    REPEAT GEN_TAC THEN
+      REPEAT(COND_CASES_TAC THEN
+             ASM_REWRITE_TAC[INTER_EMPTY; NEGLIGIBLE_EMPTY]);
+    MP_TAC(ISPEC `d:(real^N->bool)->bool` COUNTABLE_AS_INJECTIVE_IMAGE) THEN
+    ASM_REWRITE_TAC[INFINITE] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `f:num->real^N->bool` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC ASSUME_TAC) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IMP_CONJ; FORALL_IN_IMAGE;
+       RIGHT_FORALL_IMP_THM; IN_UNIV]) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM SIMPLE_IMAGE]) THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[REAL_NOT_LT; IN_NUMSEG; REAL_NOT_LE; INTERVAL_EQ_EMPTY];
+        ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`i:num`; `j:num`]] THEN
+  (DISCH_TAC THEN
+   SUBGOAL_THEN `negligible(interior((f:num->real^N->bool) i) INTER
+                            interior(f j))`
+   MP_TAC THENL [ASM_MESON_TAC[NEGLIGIBLE_EMPTY]; ALL_TAC] THEN
+   REWRITE_TAC[GSYM INTERIOR_INTER] THEN
+   REWRITE_TAC[GSYM HAS_MEASURE_0] THEN
+   MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT]
+     HAS_MEASURE_NEGLIGIBLE_SYMDIFF) THEN
+   SIMP_TAC[INTERIOR_SUBSET; SET_RULE
+      `interior(s) SUBSET s
+       ==> (interior s DIFF s) UNION (s DIFF interior s) =
+           s DIFF interior s`] THEN
+   SUBGOAL_THEN `(?c d. (f:num->real^N->bool) i = interval[c,d]) /\
+                 (?c d. (f:num->real^N->bool) j = interval[c,d])`
+   STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+   ASM_REWRITE_TAC[INTER_INTERVAL; NEGLIGIBLE_FRONTIER_INTERVAL;
+                   INTERIOR_CLOSED_INTERVAL]));;
+
+let REAL_MONOTONE_CONVERGENCE_INCREASING_AE = prove
+ (`!f:num->real->real g s.
+        (!k. (f k) real_integrable_on s) /\
+        (!k x. x IN s ==> f k x <= f (SUC k) x) /\
+        (?t. real_negligible t /\
+             !x. x IN (s DIFF t) ==> ((\k. f k x) ---> g x) sequentially) /\
+        real_bounded {real_integral s (f k) | k IN (:num)}
+        ==> g real_integrable_on s /\
+            ((\k. real_integral s (f k)) ---> real_integral s g) sequentially`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `g real_integrable_on (s DIFF t) /\
+    ((\k. real_integral (s DIFF t) (f k)) ---> real_integral (s DIFF t) g)
+    sequentially`
+  MP_TAC THENL
+   [MATCH_MP_TAC REAL_MONOTONE_CONVERGENCE_INCREASING THEN
+    REPEAT CONJ_TAC THENL
+     [UNDISCH_TAC `!k:num. f k real_integrable_on s` THEN
+      MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+      MATCH_MP_TAC REAL_INTEGRABLE_SPIKE_SET;
+      ASM_SIMP_TAC[IN_DIFF];
+      ASM_REWRITE_TAC[];
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [real_bounded]) THEN
+      REWRITE_TAC[real_bounded; FORALL_IN_GSPEC; IN_UNIV] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `B:real` THEN
+      MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN MATCH_MP_TAC EQ_IMP THEN
+      AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+      MATCH_MP_TAC REAL_INTEGRAL_SPIKE_SET];
+    MATCH_MP_TAC EQ_IMP THEN BINOP_TAC THENL
+     [MATCH_MP_TAC REAL_INTEGRABLE_SPIKE_SET_EQ THEN
+      MATCH_MP_TAC REAL_NEGLIGIBLE_SUBSET THEN
+      EXISTS_TAC `t:real->bool` THEN ASM_REWRITE_TAC[] THEN SET_TAC[];
+      AP_THM_TAC THEN BINOP_TAC THENL
+       [ABS_TAC; ALL_TAC] THEN
+      MATCH_MP_TAC REAL_INTEGRAL_SPIKE_SET]] THEN
+  MATCH_MP_TAC REAL_NEGLIGIBLE_SUBSET THEN
+  EXISTS_TAC `t:real->bool` THEN ASM_REWRITE_TAC[] THEN SET_TAC[]);;
+
+let FUBINI_SIMPLE_LEMMA = prove
+ (`!k s:real^N->bool e.
+        &0 < e /\
+        dimindex(:M) + 1 = dimindex(:N) /\
+        1 <= k /\ k <= dimindex(:N) /\
+        bounded s /\ measurable s /\
+        (!t. measurable(slice k t s:real^M->bool)) /\
+        (\t. measure (slice k t s:real^M->bool)) real_integrable_on (:real)
+        ==> real_integral(:real) (\t. measure (slice k t s :real^M->bool))
+                <= measure s + e`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `a:real^N`; `b:real^N`; `e:real`]
+        MEASURABLE_OUTER_INTERVALS_BOUNDED_EXPLICIT_SPECIAL) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [SUBGOAL_THEN `1 <= dimindex(:M)` MP_TAC THENL
+     [REWRITE_TAC[DIMINDEX_GE_1]; ASM_ARITH_TAC];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:num->(real^N->bool)` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `!t n:num. measurable((slice k t:(real^N->bool)->real^M->bool)
+                                     (d n))`
+  ASSUME_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`t:real`; `n:num`] THEN
+    FIRST_X_ASSUM(STRIP_ASSUME_TAC o CONJUNCT2 o SPEC `n:num`) THEN
+    ASM_SIMP_TAC[SLICE_INTERVAL] THEN
+    MESON_TAC[MEASURABLE_EMPTY; MEASURABLE_INTERVAL];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `measure(UNIONS {d n | n IN (:num)}:real^N->bool)` THEN
+  ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPECL
+       [`\n t. sum(0..n)
+           (\m. measure((slice k t:(real^N->bool)->real^M->bool)
+                       (d m)))`;
+        `\t. measure((slice k t:(real^N->bool)->real^M->bool)
+                   (UNIONS {d n | n IN (:num)}))`; `(:real)`]
+         REAL_MONOTONE_CONVERGENCE_INCREASING_AE) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [X_GEN_TAC `i:num` THEN MATCH_MP_TAC REAL_INTEGRABLE_SUM THEN
+      ASM_REWRITE_TAC[FINITE_NUMSEG] THEN X_GEN_TAC `j:num` THEN
+      DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o CONJUNCT2 o SPEC `j:num`) THEN
+      REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+      MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN STRIP_TAC THEN
+      MP_TAC(ISPECL [`k:num`; `u:real^N`; `v:real^N`]
+        FUBINI_CLOSED_INTERVAL) THEN
+      ASM_REWRITE_TAC[] THEN MESON_TAC[real_integrable_on];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [REPEAT STRIP_TAC THEN REWRITE_TAC[SUM_CLAUSES_NUMSEG; LE_0] THEN
+      REWRITE_TAC[REAL_LE_ADDR] THEN MATCH_MP_TAC MEASURE_POS_LE THEN
+      ASM_REWRITE_TAC[];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      REWRITE_TAC[real_bounded; FORALL_IN_GSPEC; IN_UNIV] THEN
+      EXISTS_TAC `measure(interval[a:real^N,b])` THEN X_GEN_TAC `i:num` THEN
+      W(MP_TAC o PART_MATCH (lhand o rand) REAL_INTEGRAL_SUM o
+        rand o lhand o snd) THEN
+      ANTS_TAC THENL
+       [REWRITE_TAC[FINITE_NUMSEG] THEN X_GEN_TAC `j:num` THEN DISCH_TAC THEN
+        SUBGOAL_THEN `?u v. u$k <= v$k /\
+                            (d:num->real^N->bool) j = interval[u,v]`
+        STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+        ASM_REWRITE_TAC[] THEN REWRITE_TAC[real_integrable_on] THEN
+        EXISTS_TAC `measure(interval[u:real^N,v])` THEN
+        MATCH_MP_TAC FUBINI_CLOSED_INTERVAL THEN ASM_REWRITE_TAC[];
+        ALL_TAC] THEN
+      DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `abs(sum(0..i) (\m. measure(d m:real^N->bool)))` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC REAL_EQ_IMP_LE THEN AP_TERM_TAC THEN
+        MATCH_MP_TAC SUM_EQ_NUMSEG THEN
+        X_GEN_TAC `j:num` THEN STRIP_TAC THEN REWRITE_TAC[] THEN
+        MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+        SUBGOAL_THEN `?u v. u$k <= v$k /\
+                            (d:num->real^N->bool) j = interval[u,v]`
+        STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+        ASM_REWRITE_TAC[] THEN
+        MATCH_MP_TAC FUBINI_CLOSED_INTERVAL THEN ASM_REWRITE_TAC[];
+        ALL_TAC] THEN
+      MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ x <= a ==> abs x <= a`) THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC SUM_POS_LE THEN REWRITE_TAC[FINITE_NUMSEG] THEN
+        ASM_MESON_TAC[MEASURE_POS_LE; MEASURABLE_INTERVAL];
+        ALL_TAC] THEN
+      W(MP_TAC o PART_MATCH (rhs o rand) MEASURE_NEGLIGIBLE_UNIONS_IMAGE o
+        lhand o snd) THEN
+      ANTS_TAC THENL
+       [ASM_SIMP_TAC[FINITE_NUMSEG] THEN ASM_MESON_TAC[MEASURABLE_INTERVAL];
+        ALL_TAC] THEN
+      DISCH_THEN(SUBST1_TAC o SYM) THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+      REWRITE_TAC[MEASURABLE_INTERVAL] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC MEASURABLE_UNIONS THEN
+        ASM_SIMP_TAC[FINITE_NUMSEG; FINITE_IMAGE; FORALL_IN_IMAGE] THEN
+        ASM_MESON_TAC[MEASURABLE_INTERVAL];
+        REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_IMAGE] THEN ASM_MESON_TAC[]]] THEN
+    EXISTS_TAC
+     `(IMAGE (\i. (interval_lowerbound(d i):real^N)$k) (:num)) UNION
+      (IMAGE (\i. (interval_upperbound(d i):real^N)$k) (:num))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_NEGLIGIBLE_COUNTABLE THEN
+      SIMP_TAC[COUNTABLE_UNION; COUNTABLE_IMAGE; NUM_COUNTABLE];
+      ALL_TAC] THEN
+    X_GEN_TAC `t:real` THEN
+    REWRITE_TAC[IN_DIFF; IN_UNION; IN_IMAGE] THEN
+    GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [IN_UNIV] THEN
+    REWRITE_TAC[DE_MORGAN_THM; NOT_EXISTS_THM] THEN DISCH_TAC THEN
+    MP_TAC(ISPEC `\n:num. (slice k t:(real^N->bool)->real^M->bool)
+                          (d n)`
+       HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS_BOUNDED) THEN
+    ASM_REWRITE_TAC[SLICE_UNIONS] THEN ANTS_TAC THENL
+     [ALL_TAC;
+      DISCH_THEN(MP_TAC o CONJUNCT2) THEN
+      GEN_REWRITE_TAC (LAND_CONV o RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+      REWRITE_TAC[GSYM REAL_SUMS; real_sums; FROM_INTER_NUMSEG] THEN
+      REWRITE_TAC[SIMPLE_IMAGE; GSYM IMAGE_o; o_DEF]] THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC BOUNDED_SUBSET THEN
+      EXISTS_TAC `(slice k t:(real^N->bool)->real^M->bool) (interval[a,b])` THEN
+      CONJ_TAC THENL
+       [ASM_SIMP_TAC[SLICE_INTERVAL] THEN
+        MESON_TAC[BOUNDED_INTERVAL; BOUNDED_EMPTY];
+        REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC] THEN
+        ASM_MESON_TAC[SLICE_SUBSET]]] THEN
+    MAP_EVERY X_GEN_TAC [`i:num`; `j:num`] THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`i:num`; `j:num`]) THEN
+    ASM_REWRITE_TAC[] THEN
+    ASM_CASES_TAC `(d:num->real^N->bool) i = {}` THENL
+     [ASM_REWRITE_TAC[INTER_EMPTY; NEGLIGIBLE_EMPTY; SLICE_EMPTY];
+      UNDISCH_TAC `~((d:num->real^N->bool) i = {})`] THEN
+    ASM_CASES_TAC `(d:num->real^N->bool) j = {}` THENL
+     [ASM_REWRITE_TAC[INTER_EMPTY; NEGLIGIBLE_EMPTY; SLICE_EMPTY];
+      UNDISCH_TAC `~((d:num->real^N->bool) j = {})`] THEN
+    FIRST_ASSUM(fun th ->
+      MAP_EVERY (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)
+       [SPEC `i:num` th; SPEC `j:num` th]) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`w:real^N`; `x:real^N`] THEN STRIP_TAC THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[SLICE_INTERVAL; INTERVAL_NE_EMPTY] THEN
+    DISCH_TAC THEN DISCH_TAC THEN
+    REPEAT(COND_CASES_TAC THEN
+           ASM_REWRITE_TAC[INTER_EMPTY; NEGLIGIBLE_EMPTY]) THEN
+    REWRITE_TAC[INTER_INTERVAL; NEGLIGIBLE_INTERVAL; INTERVAL_EQ_EMPTY] THEN
+    ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> ~(a /\ b ==> ~c)`] THEN
+    SIMP_TAC[LAMBDA_BETA] THEN REWRITE_TAC[NOT_IMP] THEN
+    DISCH_THEN(X_CHOOSE_THEN `l:num` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN `~(l:num = k)` ASSUME_TAC THENL
+     [FIRST_X_ASSUM(CONJUNCTS_THEN
+       (fun th -> MP_TAC(SPEC `i:num` th) THEN MP_TAC(SPEC `j:num` th))) THEN
+      ASM_SIMP_TAC[INTERVAL_LOWERBOUND; INTERVAL_UPPERBOUND] THEN
+      REWRITE_TAC[IMP_IMP] THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+      REWRITE_TAC[] THEN DISCH_THEN SUBST_ALL_TAC THEN ASM_REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (ARITH_RULE
+     `~(l:num = k) ==> l < k \/ k < l`))
+    THENL
+     [EXISTS_TAC `l:num` THEN
+      MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN
+      CONJ_TAC THENL [ASM_ARITH_TAC; SIMP_TAC[dropout; LAMBDA_BETA]] THEN
+      ASM_REWRITE_TAC[];
+      ALL_TAC] THEN
+    EXISTS_TAC `l - 1` THEN
+    MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN
+    CONJ_TAC THENL [ASM_ARITH_TAC; SIMP_TAC[dropout; LAMBDA_BETA]] THEN
+    ASM_SIMP_TAC[ARITH_RULE `k < l ==> ~(l - 1 < k)`] THEN
+    ASM_SIMP_TAC[SUB_ADD];
+    ALL_TAC] THEN
+  STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+   `real_integral (:real)
+        (\t. measure ((slice k t :(real^N->bool)->real^M->bool)
+                      (UNIONS {d n | n IN (:num)})))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_INTEGRAL_LE THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `t:real` THEN DISCH_TAC THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+    ASM_SIMP_TAC[SLICE_SUBSET; SLICE_UNIONS] THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN REWRITE_TAC[GSYM IMAGE_o] THEN
+    ONCE_REWRITE_TAC[GSYM SIMPLE_IMAGE] THEN
+    MATCH_MP_TAC MEASURABLE_COUNTABLE_UNIONS_BOUNDED THEN
+    ASM_REWRITE_TAC[o_THM] THEN
+    MATCH_MP_TAC BOUNDED_SUBSET THEN
+    EXISTS_TAC `(slice k t:(real^N->bool)->real^M->bool) (interval[a,b])` THEN
+    CONJ_TAC THENL
+     [ASM_SIMP_TAC[SLICE_INTERVAL] THEN
+      MESON_TAC[BOUNDED_INTERVAL; BOUNDED_EMPTY];
+      REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC] THEN
+      ASM_MESON_TAC[SLICE_SUBSET]];
+    MATCH_MP_TAC REAL_EQ_IMP_LE THEN
+    MATCH_MP_TAC(ISPEC `sequentially` REALLIM_UNIQUE) THEN
+    EXISTS_TAC `\n. real_integral (:real)
+       (\t. sum (0..n) (\m. measure((slice k t:(real^N->bool)->real^M->bool)
+
+                         (d m))))` THEN
+    ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+    MP_TAC(ISPEC `d:num->(real^N->bool)`
+     HAS_MEASURE_COUNTABLE_NEGLIGIBLE_UNIONS_BOUNDED) THEN
+    ANTS_TAC THENL
+     [ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[MEASURABLE_INTERVAL]; ALL_TAC] THEN
+      MATCH_MP_TAC BOUNDED_SUBSET THEN EXISTS_TAC `interval[a:real^N,b]` THEN
+      REWRITE_TAC[BOUNDED_INTERVAL; UNIONS_SUBSET; IN_ELIM_THM] THEN
+      ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    ASM_REWRITE_TAC[] THEN
+    GEN_REWRITE_TAC (LAND_CONV o RATOR_CONV o LAND_CONV) [GSYM o_DEF] THEN
+    REWRITE_TAC[GSYM REAL_SUMS] THEN
+    REWRITE_TAC[real_sums; FROM_INTER_NUMSEG] THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_THM_TAC THEN
+    AP_TERM_TAC THEN GEN_REWRITE_TAC I [FUN_EQ_THM] THEN
+    X_GEN_TAC `i:num` THEN REWRITE_TAC[] THEN
+    W(MP_TAC o PART_MATCH (lhand o rand) REAL_INTEGRAL_SUM o rand o snd) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[FINITE_NUMSEG] THEN X_GEN_TAC `j:num` THEN DISCH_TAC THEN
+      SUBGOAL_THEN `?u v. u$k <= v$k /\
+                          (d:num->real^N->bool) j = interval[u,v]`
+      STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[] THEN REWRITE_TAC[real_integrable_on] THEN
+      EXISTS_TAC `measure(interval[u:real^N,v])` THEN
+      MATCH_MP_TAC FUBINI_CLOSED_INTERVAL THEN ASM_REWRITE_TAC[];
+      ALL_TAC] THEN
+    DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC SUM_EQ_NUMSEG THEN
+    X_GEN_TAC `j:num` THEN STRIP_TAC THEN REWRITE_TAC[] THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN
+    SUBGOAL_THEN `?u v. u$k <= v$k /\
+                          (d:num->real^N->bool) j = interval[u,v]`
+    STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC FUBINI_CLOSED_INTERVAL THEN ASM_REWRITE_TAC[]]);;
+
+let FUBINI_SIMPLE = prove
+ (`!k s:real^N->bool.
+        dimindex(:M) + 1 = dimindex(:N) /\
+        1 <= k /\ k <= dimindex(:N) /\
+        bounded s /\
+        measurable s /\
+        (!t. measurable(slice k t s :real^M->bool)) /\
+        (\t. measure (slice k t s :real^M->bool)) real_integrable_on (:real)
+        ==> measure s =
+              real_integral(:real)(\t. measure (slice k t s :real^M->bool))`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[SLICE_EMPTY; MEASURE_EMPTY; REAL_INTEGRAL_0];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `~(interval[a:real^N,b] = {})` MP_TAC THENL
+   [ASM SET_TAC[]; REWRITE_TAC[INTERVAL_NE_EMPTY] THEN DISCH_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH `~(&0 < b - a) /\ ~(&0 < a - b) ==> a:real = b`) THEN
+  CONJ_TAC THEN MATCH_MP_TAC(MESON[]
+     `(!e. x - y = e ==> ~(&0 < e)) ==> ~(&0 < x - y)`) THEN
+  X_GEN_TAC `e:real` THEN REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL [`k:num`; `s:real^N->bool`; `e / &2`]
+      FUBINI_SIMPLE_LEMMA) THEN
+    ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`k:num`; `interval[a:real^N,b] DIFF s`; `e / &2`]
+    FUBINI_SIMPLE_LEMMA) THEN
+  ASM_REWRITE_TAC[NOT_IMP; GSYM CONJ_ASSOC] THEN
+  CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  CONJ_TAC THENL [SIMP_TAC[BOUNDED_DIFF; BOUNDED_INTERVAL]; ALL_TAC] THEN
+  CONJ_TAC THENL
+   [ASM_SIMP_TAC[MEASURABLE_DIFF; MEASURABLE_INTERVAL]; ALL_TAC] THEN
+  ASM_SIMP_TAC[SLICE_DIFF] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [X_GEN_TAC `t:real` THEN MATCH_MP_TAC MEASURABLE_DIFF THEN
+    ASM_SIMP_TAC[SLICE_INTERVAL] THEN
+    MESON_TAC[MEASURABLE_EMPTY; MEASURABLE_INTERVAL];
+    DISCH_TAC] THEN
+  SUBGOAL_THEN
+   `!t. measure(slice k t (interval[a:real^N,b]) DIFF
+                slice k t (s:real^N->bool) :real^M->bool) =
+        measure(slice k t (interval[a:real^N,b]):real^M->bool) -
+        measure(slice k t s :real^M->bool)`
+   (fun th -> REWRITE_TAC[th])
+  THENL
+   [X_GEN_TAC `t:real` THEN MATCH_MP_TAC MEASURE_DIFF_SUBSET THEN
+    ASM_SIMP_TAC[SLICE_SUBSET] THEN
+    ASM_SIMP_TAC[SLICE_INTERVAL] THEN
+    MESON_TAC[MEASURABLE_EMPTY; MEASURABLE_INTERVAL];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`k:num`; `a:real^N`; `b:real^N`] FUBINI_CLOSED_INTERVAL) THEN
+  ASM_SIMP_TAC[] THEN DISCH_TAC THEN CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_INTEGRABLE_SUB THEN ASM_MESON_TAC[real_integrable_on];
+    ALL_TAC] THEN
+  REWRITE_TAC[REAL_NOT_LE] THEN
+  ASM_SIMP_TAC[MEASURE_DIFF_SUBSET; MEASURABLE_INTERVAL] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) REAL_INTEGRAL_SUB o rand o snd) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[real_integrable_on]; DISCH_THEN SUBST1_TAC] THEN
+  FIRST_ASSUM(SUBST1_TAC o MATCH_MP REAL_INTEGRAL_UNIQUE) THEN
+  ASM_REAL_ARITH_TAC);;
+
+let FUBINI_SIMPLE_ALT = prove
+ (`!k s:real^N->bool.
+        dimindex(:M) + 1 = dimindex(:N) /\
+        1 <= k /\ k <= dimindex(:N) /\
+        bounded s /\
+        measurable s /\
+        (!t. measurable(slice k t s :real^M->bool)) /\
+        ((\t. measure (slice k t s :real^M->bool)) has_real_integral B) (:real)
+        ==> measure s = B`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `real_integral (:real)
+                 (\t. measure (slice k t (s:real^N->bool) :real^M->bool))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC FUBINI_SIMPLE THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[real_integrable_on];
+    MATCH_MP_TAC REAL_INTEGRAL_UNIQUE THEN ASM_REWRITE_TAC[]]);;
+
+let FUBINI_SIMPLE_COMPACT_STRONG = prove
+ (`!k s:real^N->bool.
+        dimindex(:M) + 1 = dimindex(:N) /\
+        1 <= k /\ k <= dimindex(:N) /\
+        compact s /\
+        ((\t. measure (slice k t s :real^M->bool)) has_real_integral B) (:real)
+        ==> measurable s /\ measure s = B`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[MEASURABLE_COMPACT] THEN
+  MATCH_MP_TAC FUBINI_SIMPLE_ALT THEN
+  EXISTS_TAC `k:num` THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[COMPACT_IMP_BOUNDED; MEASURABLE_COMPACT] THEN
+  GEN_TAC THEN MATCH_MP_TAC MEASURABLE_COMPACT THEN
+  MATCH_MP_TAC COMPACT_SLICE THEN ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC);;
+
+let FUBINI_SIMPLE_COMPACT = prove
+ (`!k s:real^N->bool.
+        dimindex(:M) + 1 = dimindex(:N) /\
+        1 <= k /\ k <= dimindex(:N) /\
+        compact s /\
+        ((\t. measure (slice k t s :real^M->bool)) has_real_integral B) (:real)
+        ==> measure s = B`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP FUBINI_SIMPLE_COMPACT_STRONG) THEN SIMP_TAC[]);;
+
+let FUBINI_SIMPLE_CONVEX_STRONG = prove
+ (`!k s:real^N->bool.
+        dimindex(:M) + 1 = dimindex(:N) /\
+        1 <= k /\ k <= dimindex(:N) /\
+        bounded s /\ convex s /\
+        ((\t. measure (slice k t s :real^M->bool)) has_real_integral B) (:real)
+        ==> measurable s /\ measure s = B`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[MEASURABLE_CONVEX] THEN
+  MATCH_MP_TAC FUBINI_SIMPLE_ALT THEN
+  EXISTS_TAC `k:num` THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[MEASURABLE_CONVEX] THEN
+  GEN_TAC THEN MATCH_MP_TAC MEASURABLE_CONVEX THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONVEX_SLICE; MATCH_MP_TAC BOUNDED_SLICE] THEN
+  ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC);;
+
+let FUBINI_SIMPLE_CONVEX = prove
+ (`!k s:real^N->bool.
+        dimindex(:M) + 1 = dimindex(:N) /\
+        1 <= k /\ k <= dimindex(:N) /\
+        bounded s /\ convex s /\
+        ((\t. measure (slice k t s :real^M->bool)) has_real_integral B) (:real)
+        ==> measure s = B`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP FUBINI_SIMPLE_CONVEX_STRONG) THEN SIMP_TAC[]);;
+
+let FUBINI_SIMPLE_OPEN_STRONG = prove
+ (`!k s:real^N->bool.
+        dimindex(:M) + 1 = dimindex(:N) /\
+        1 <= k /\ k <= dimindex(:N) /\
+        bounded s /\ open s /\
+        ((\t. measure (slice k t s :real^M->bool)) has_real_integral B) (:real)
+        ==> measurable s /\ measure s = B`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[MEASURABLE_OPEN] THEN
+  MATCH_MP_TAC FUBINI_SIMPLE_ALT THEN
+  EXISTS_TAC `k:num` THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[MEASURABLE_OPEN] THEN
+  GEN_TAC THEN MATCH_MP_TAC MEASURABLE_OPEN THEN CONJ_TAC THENL
+   [MATCH_MP_TAC BOUNDED_SLICE; MATCH_MP_TAC OPEN_SLICE] THEN
+  ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC);;
+
+let FUBINI_SIMPLE_OPEN = prove
+ (`!k s:real^N->bool.
+        dimindex(:M) + 1 = dimindex(:N) /\
+        1 <= k /\ k <= dimindex(:N) /\
+        bounded s /\ open s /\
+        ((\t. measure (slice k t s :real^M->bool)) has_real_integral B) (:real)
+        ==> measure s = B`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP FUBINI_SIMPLE_OPEN_STRONG) THEN SIMP_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Scaled integer, and hence rational, values are dense in the reals.        *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_OPEN_SET_RATIONAL = prove
+ (`!s. real_open s /\ ~(s = {}) ==> ?x. rational x /\ x IN s`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  MP_TAC(ISPEC `IMAGE lift s` OPEN_SET_RATIONAL_COORDINATES) THEN
+  ASM_REWRITE_TAC[GSYM REAL_OPEN; IMAGE_EQ_EMPTY; EXISTS_IN_IMAGE] THEN
+  SIMP_TAC[DIMINDEX_1; FORALL_1; GSYM drop; LIFT_DROP]);;
+
+let REAL_OPEN_RATIONAL = prove
+ (`!P. real_open {x | P x} /\ (?x. P x) ==> ?x. rational x /\ P x`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPEC `{x:real | P x}` REAL_OPEN_SET_RATIONAL) THEN
+  ASM_REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN ASM_MESON_TAC[]);;
+
+let REAL_OPEN_SET_EXISTS_RATIONAL = prove
+ (`!s. real_open s ==> ((?x. rational x /\ x IN s) <=> (?x. x IN s))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  ASM_MESON_TAC[REAL_OPEN_SET_RATIONAL; GSYM MEMBER_NOT_EMPTY]);;
+
+let REAL_OPEN_EXISTS_RATIONAL = prove
+ (`!P. real_open {x | P x} ==> ((?x. rational x /\ P x) <=> (?x. P x))`,
+  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP REAL_OPEN_SET_EXISTS_RATIONAL) THEN
+  REWRITE_TAC[IN_ELIM_THM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence a criterion for two functions to agree.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_ON_CONST_DYADIC_RATIONALS = prove
+ (`!f:real^M->real^N a.
+     f continuous_on (:real^M) /\
+     (!x. (!i. 1 <= i /\ i <= dimindex(:M) ==> integer(x$i)) ==> f(x) = a) /\
+     (!x. f(x) = a ==> f(inv(&2) % x) = a)
+     ==> !x. f(x) = a`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN MP_TAC(ISPECL
+   [`f:real^M->real^N`;
+    `{ inv(&2 pow n) % x:real^M |n,x|
+       !i. 1 <= i /\ i <= dimindex(:M) ==> integer(x$i) }`;
+    `a:real^N`] CONTINUOUS_CONSTANT_ON_CLOSURE) THEN
+  ASM_REWRITE_TAC[FORALL_IN_GSPEC; CLOSURE_DYADIC_RATIONALS; IN_UNIV] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  INDUCT_TAC THEN ASM_REWRITE_TAC[real_pow; REAL_INV_1; VECTOR_MUL_LID] THEN
+  ASM_SIMP_TAC[REAL_INV_MUL; GSYM VECTOR_MUL_ASSOC]);;
+
+let REAL_CONTINUOUS_ON_CONST_DYADIC_RATIONALS = prove
+ (`!f a.
+     f real_continuous_on (:real) /\
+     (!x. integer(x) ==> f(x) = a) /\
+     (!x. f(x) = a ==> f(x / &2) = a)
+     ==> !x. f(x) = a`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `lift a`]
+    CONTINUOUS_ON_CONST_DYADIC_RATIONALS) THEN
+  ASM_REWRITE_TAC[GSYM REAL_CONTINUOUS_ON; GSYM IMAGE_LIFT_UNIV] THEN
+  ASM_SIMP_TAC[o_THM; DIMINDEX_1; FORALL_1; GSYM drop; LIFT_EQ; DROP_CMUL;
+               REAL_ARITH `inv(&2) * x = x / &2`] THEN
+  ASM_MESON_TAC[LIFT_DROP]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Various sufficient conditions for additivity to imply linearity.          *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_ADDITIVE_IMP_LINEAR = prove
+ (`!f:real^M->real^N.
+        f continuous_on (:real^M) /\
+        (!x y. f(x + y) = f(x) + f(y))
+        ==> linear f`,
+  GEN_TAC THEN STRIP_TAC THEN
+  SUBGOAL_THEN `(f:real^M->real^N) (vec 0) = vec 0` ASSUME_TAC THENL
+   [FIRST_ASSUM(MP_TAC o repeat (SPEC `vec 0:real^M`)) THEN
+    REWRITE_TAC[VECTOR_ADD_LID] THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[linear] THEN
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN X_GEN_TAC `x:real^M` THEN
+  MP_TAC(ISPECL [`\c. norm((f:real^M->real^N)(c % x) - c % f(x))`; `&0`]
+        REAL_CONTINUOUS_ON_CONST_DYADIC_RATIONALS) THEN
+  REWRITE_TAC[NORM_EQ_0; VECTOR_SUB_EQ] THEN DISCH_THEN MATCH_MP_TAC THEN
+  REPEAT CONJ_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN]) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_UNIV; WITHIN_UNIV]) THEN
+    REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; IN_UNIV] THEN
+    GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC REAL_CONTINUOUS_CONTINUOUS_WITHINREAL_COMPOSE THEN
+    SIMP_TAC[REAL_CONTINUOUS_NORM_WITHIN] THEN MATCH_MP_TAC CONTINUOUS_SUB THEN
+    ASM_SIMP_TAC[REWRITE_RULE[GSYM REAL_CONTINUOUS_CONTINUOUS1]CONTINUOUS_VMUL;
+                 REAL_CONTINUOUS_WITHIN_ID; CONTINUOUS_AT_WITHIN;
+                 REWRITE_RULE[o_DEF] CONTINUOUS_WITHINREAL_COMPOSE];
+    MATCH_MP_TAC FORALL_INTEGER THEN CONJ_TAC THENL
+     [INDUCT_TAC THEN ASM_SIMP_TAC[VECTOR_MUL_LZERO; GSYM REAL_OF_NUM_SUC] THEN
+      ASM_REWRITE_TAC[VECTOR_ADD_RDISTRIB; VECTOR_MUL_LID];
+      X_GEN_TAC `c:real` THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL [`c % x:real^M`; `--(c % x):real^M`]) THEN
+      ASM_REWRITE_TAC[VECTOR_ADD_RINV; VECTOR_MUL_LNEG; IMP_IMP] THEN
+      VECTOR_ARITH_TAC];
+    X_GEN_TAC `c:real` THEN
+    FIRST_X_ASSUM(MP_TAC o funpow 2 (SPEC `c / &2 % x:real^M`)) THEN
+    REWRITE_TAC[VECTOR_ARITH `c / &2 % x + c / &2 % x:real^N = c % x`] THEN
+    REWRITE_TAC[IMP_IMP] THEN VECTOR_ARITH_TAC]);;
+
+let OSTROWSKI_THEOREM = prove
+ (`!f:real^M->real^N B s.
+        (!x y. f(x + y) = f(x) + f(y)) /\
+        (!x. x IN s ==> norm(f x) <= B) /\
+        measurable s /\ &0 < measure s
+        ==> linear f`,
+  REPEAT GEN_TAC THEN
+  REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC o
+    MATCH_MP STEINHAUS) THEN
+  SUBGOAL_THEN `!x y. (f:real^M->real^N)(x - y) = f x - f y` ASSUME_TAC THENL
+   [ASM_MESON_TAC[VECTOR_ARITH `x - y:real^M = z <=> x = y + z`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!n x. &n % (f:real^M->real^N) x = f(&n % x)` ASSUME_TAC THENL
+   [INDUCT_TAC THENL
+     [ASM_MESON_TAC[VECTOR_SUB_REFL; VECTOR_MUL_LZERO];
+      ASM_REWRITE_TAC[GSYM REAL_OF_NUM_SUC; VECTOR_ADD_RDISTRIB] THEN
+      REWRITE_TAC[VECTOR_MUL_LID]];
+    ALL_TAC] THEN
+  MATCH_MP_TAC CONTINUOUS_ADDITIVE_IMP_LINEAR THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `!x. norm(x) < d ==> norm((f:real^M->real^N) x) <= &2 * B`
+  ASSUME_TAC THENL
+   [X_GEN_TAC `z:real^M` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `z:real^M` o GEN_REWRITE_RULE I [SUBSET]) THEN
+    ASM_REWRITE_TAC[IN_BALL_0] THEN SPEC_TAC(`z:real^M`,`z:real^M`) THEN
+    ASM_REWRITE_TAC[FORALL_IN_GSPEC] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN(ANTE_RES_THEN MP_TAC)) THEN
+    CONV_TAC NORM_ARITH;
+    ALL_TAC] THEN
+  REWRITE_TAC[continuous_on; IN_UNIV; dist] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `e:real`] THEN DISCH_TAC THEN
+  MP_TAC(SPEC `e:real` REAL_ARCH) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `n:num` MP_TAC o SPEC `max (&1) (&2 * B)`) THEN
+  ASM_CASES_TAC `n = 0` THEN ASM_REWRITE_TAC[] THENL
+   [REAL_ARITH_TAC; DISCH_TAC] THEN
+  EXISTS_TAC `d / &n` THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; LE_1] THEN
+  X_GEN_TAC `y:real^M` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `norm(&n % (f:real^M->real^N)(y - x)) <= &2 * B` MP_TAC THENL
+   [ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    SIMP_TAC[NORM_MUL; REAL_ABS_NUM] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_OF_NUM_LT; LE_1];
+    SIMP_TAC[NORM_MUL; REAL_ABS_NUM] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; REAL_OF_NUM_LT; LE_1] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LET_TRANS) THEN
+    ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_OF_NUM_LT; LE_1] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let MEASURABLE_ADDITIVE_IMP_LINEAR = prove
+ (`!f:real^M->real^N.
+        f measurable_on (:real^M) /\ (!x y. f(x + y) = f(x) + f(y))
+        ==> linear f`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC OSTROWSKI_THEOREM THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP MEASURABLE_ON_NORM) THEN
+  REWRITE_TAC[MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE] THEN
+  REWRITE_TAC[DIMINDEX_1; FORALL_1; GSYM drop; LIFT_DROP] THEN
+  DISCH_TAC THEN
+  ASM_CASES_TAC `!b. negligible {x | norm((f:real^M->real^N) x) <= b}` THENL
+   [FIRST_X_ASSUM(MP_TAC o MATCH_MP NEGLIGIBLE_COUNTABLE_UNIONS o
+        GEN `n:num` o SPEC `&n:real`) THEN
+    REWRITE_TAC[UNIONS_GSPEC; IN_ELIM_THM; IN_UNIV; REAL_ARCH_SIMPLE] THEN
+    SIMP_TAC[SET_RULE `{x | T} = (:real^M)`; OPEN_NOT_NEGLIGIBLE;
+             OPEN_UNIV; UNIV_NOT_EMPTY];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM]) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `B:real` THEN
+    ONCE_REWRITE_TAC[NEGLIGIBLE_ON_INTERVALS] THEN
+    REWRITE_TAC[NOT_FORALL_THM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`] THEN DISCH_TAC THEN
+    EXISTS_TAC `{x:real^M | norm(f x:real^N) <= B} INTER interval[a,b]` THEN
+    ASM_SIMP_TAC[IN_ELIM_THM; IN_INTER] THEN
+    MATCH_MP_TAC(MESON[MEASURABLE_MEASURE_POS_LT]
+     `measurable s /\ ~negligible s ==> measurable s /\ &0 < measure s`) THEN
+    ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE THEN
+    ASM_REWRITE_TAC[MEASURABLE_INTERVAL]]);;
+
+let REAL_CONTINUOUS_ADDITIVE_IMP_LINEAR = prove
+ (`!f. f real_continuous_on (:real) /\
+       (!x y. f(x + y) = f(x) + f(y))
+       ==> !a x. f(a * x) = a * f(x)`,
+  GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(ISPEC `lift o f o drop` CONTINUOUS_ADDITIVE_IMP_LINEAR) THEN
+  ASM_REWRITE_TAC[GSYM REAL_CONTINUOUS_ON; GSYM IMAGE_LIFT_UNIV] THEN
+  ASM_REWRITE_TAC[linear; GSYM FORALL_DROP; o_THM; DROP_ADD; LIFT_DROP;
+                  DROP_CMUL; GSYM LIFT_ADD; GSYM LIFT_CMUL; LIFT_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Extending a continuous function in a periodic way.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_CONTINUOUS_FLOOR = prove
+ (`!x. ~(integer x) ==> floor real_continuous (atreal x)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[real_continuous_atreal] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  EXISTS_TAC `min (x - floor x) ((floor x + &1) - x)` THEN
+  ASM_REWRITE_TAC[REAL_LT_MIN; REAL_SUB_LT; REAL_FLOOR_LT; FLOOR] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x = y ==> abs(x - y) < e`) THEN
+  ASM_REWRITE_TAC[GSYM FLOOR_UNIQUE; FLOOR] THEN
+  MP_TAC(ISPEC `x:real` FLOOR) THEN ASM_REAL_ARITH_TAC);;
+
+let REAL_CONTINUOUS_FRAC = prove
+ (`!x. ~(integer x) ==> frac real_continuous (atreal x)`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN
+  REWRITE_TAC[FRAC_FLOOR] THEN MATCH_MP_TAC REAL_CONTINUOUS_SUB THEN
+  ASM_SIMP_TAC[REAL_CONTINUOUS_FLOOR; REAL_CONTINUOUS_AT_ID]);;
+
+let REAL_CONTINUOUS_ON_COMPOSE_FRAC = prove
+ (`!f. f real_continuous_on real_interval[&0,&1] /\ f(&1) = f(&0)
+       ==> (f o frac) real_continuous_on (:real)`,
+  REPEAT STRIP_TAC THEN
+  UNDISCH_TAC `f real_continuous_on real_interval[&0,&1]` THEN
+  REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; WITHINREAL_UNIV] THEN
+  DISCH_TAC THEN X_GEN_TAC `x:real` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `integer x` THENL
+   [ALL_TAC;
+    MATCH_MP_TAC REAL_CONTINUOUS_ATREAL_COMPOSE THEN
+    ASM_SIMP_TAC[REAL_CONTINUOUS_FRAC] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE LAND_CONV [IN_REAL_INTERVAL] o
+                  SPEC `frac x`) THEN
+    ASM_SIMP_TAC[FLOOR_FRAC; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[real_continuous_atreal; real_continuous_withinreal] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN
+    ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[IN_REAL_INTERVAL] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `min d (min (frac x) (&1 - frac x))` THEN
+    ASM_SIMP_TAC[REAL_LT_MIN; REAL_SUB_LT; FLOOR_FRAC; REAL_FRAC_POS_LT] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REAL_ARITH_TAC] THEN
+  ASM_SIMP_TAC[real_continuous_atreal; REAL_FRAC_ZERO; REAL_FLOOR_REFL] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE (BINDER_CONV o LAND_CONV)
+     [IN_REAL_INTERVAL]) THEN
+  DISCH_THEN(fun th -> MP_TAC(SPEC `&1` th) THEN MP_TAC(SPEC `&0` th)) THEN
+  REWRITE_TAC[REAL_LE_REFL; REAL_POS] THEN
+  REWRITE_TAC[IMP_IMP; real_continuous_withinreal; AND_FORALL_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `e:real`) THEN
+  ASM_REWRITE_TAC[IN_REAL_INTERVAL] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC)
+               (X_CHOOSE_THEN `d2:real` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `min (&1) (min d1 d2)` THEN
+  ASM_REWRITE_TAC[REAL_LT_01; REAL_LT_MIN; o_DEF] THEN
+  X_GEN_TAC `y:real` THEN STRIP_TAC THEN
+  DISJ_CASES_TAC(REAL_ARITH `x <= y \/ y < x`) THENL
+   [SUBGOAL_THEN `floor y = floor x` ASSUME_TAC THENL
+     [REWRITE_TAC[GSYM FLOOR_UNIQUE; FLOOR] THEN
+      ASM_SIMP_TAC[REAL_FLOOR_REFL] THEN ASM_REAL_ARITH_TAC;
+      ASM_SIMP_TAC[FRAC_FLOOR; REAL_FLOOR_REFL; REAL_SUB_REFL] THEN
+      FIRST_X_ASSUM(fun th -> MATCH_MP_TAC th THEN ASM_REAL_ARITH_TAC)];
+    SUBGOAL_THEN `floor y = floor x - &1` ASSUME_TAC THENL
+     [REWRITE_TAC[GSYM FLOOR_UNIQUE; FLOOR] THEN
+      ASM_SIMP_TAC[REAL_FLOOR_REFL; INTEGER_CLOSED] THEN ASM_REAL_ARITH_TAC;
+      ASM_SIMP_TAC[FRAC_FLOOR; REAL_FLOOR_REFL; REAL_SUB_REFL] THEN
+      FIRST_X_ASSUM(fun th -> MATCH_MP_TAC th THEN ASM_REAL_ARITH_TAC)]]);;
+
+let REAL_TIETZE_PERIODIC_INTERVAL = prove
+ (`!f a b.
+        f real_continuous_on real_interval[a,b] /\ f(a) = f(b)
+        ==> ?g. g real_continuous_on (:real) /\
+                (!x. x IN real_interval[a,b] ==> g(x) = f(x)) /\
+                (!x. g(x + (b - a)) = g x)`,
+  REPEAT STRIP_TAC THEN DISJ_CASES_TAC(REAL_ARITH `b:real <= a \/ a < b`) THENL
+   [EXISTS_TAC `\x:real. (f:real->real) a` THEN
+    REWRITE_TAC[IN_REAL_INTERVAL; REAL_CONTINUOUS_ON_CONST] THEN
+    ASM_MESON_TAC[REAL_LE_TRANS; REAL_LE_ANTISYM];
+    EXISTS_TAC `(f:real->real) o (\y. a + (b - a) * y) o frac o
+                (\x. (x - a) / (b - a))` THEN
+    REWRITE_TAC[o_THM] THEN REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[o_ASSOC] THEN MATCH_MP_TAC REAL_CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[real_div; REAL_CONTINUOUS_ON_RMUL; REAL_CONTINUOUS_ON_SUB;
+               REAL_CONTINUOUS_ON_CONST; REAL_CONTINUOUS_ON_ID] THEN
+      MATCH_MP_TAC REAL_CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `(:real)` THEN
+      REWRITE_TAC[SUBSET_UNIV] THEN
+      MATCH_MP_TAC REAL_CONTINUOUS_ON_COMPOSE_FRAC THEN
+      ASM_SIMP_TAC[o_THM; REAL_MUL_RZERO; REAL_MUL_RID; REAL_SUB_ADD2;
+                   REAL_ADD_RID] THEN
+      MATCH_MP_TAC REAL_CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[REAL_CONTINUOUS_ON_LMUL; REAL_CONTINUOUS_ON_ADD;
+               REAL_CONTINUOUS_ON_CONST; REAL_CONTINUOUS_ON_ID] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        REAL_CONTINUOUS_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_REAL_INTERVAL] THEN
+      ASM_SIMP_TAC[REAL_LE_ADDR; REAL_LE_MUL; REAL_LT_IMP_LE; REAL_SUB_LT] THEN
+      REWRITE_TAC[REAL_ARITH
+       `a + (b - a) * x <= b <=> &0 <= (b - a) * (&1 - x)`] THEN
+       ASM_SIMP_TAC[REAL_LE_ADDR; REAL_LE_MUL; REAL_LT_IMP_LE; REAL_SUB_LE];
+      X_GEN_TAC `x:real` THEN REWRITE_TAC[IN_REAL_INTERVAL] THEN
+      STRIP_TAC THEN ASM_CASES_TAC `x:real = b` THENL
+       [ASM_SIMP_TAC[REAL_DIV_REFL; REAL_LT_IMP_NZ; REAL_SUB_LT] THEN
+        ASM_REWRITE_TAC[FRAC_NUM; REAL_MUL_RZERO; REAL_ADD_RID];
+        SUBGOAL_THEN `frac((x - a) / (b - a)) = (x - a) / (b - a)`
+        SUBST1_TAC THENL
+         [REWRITE_TAC[REAL_FRAC_EQ] THEN
+          ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LT_LDIV_EQ; REAL_SUB_LT] THEN
+          ASM_REAL_ARITH_TAC;
+          AP_TERM_TAC THEN UNDISCH_TAC `a:real < b` THEN CONV_TAC REAL_FIELD]];
+      ASM_SIMP_TAC[REAL_FIELD
+        `a < b ==> ((x + b - a) - a) / (b - a) = &1 + (x - a) / (b - a)`] THEN
+      REWRITE_TAC[REAL_FRAC_ADD; FRAC_NUM; FLOOR_FRAC; REAL_ADD_LID]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A variant of REAL_CONTINUOUS_ADDITIVE_IMP_LINEAR for intervals.           *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_CONTINUOUS_ADDITIVE_EXTEND = prove
+ (`!f. f real_continuous_on real_interval[&0,&1] /\
+       (!x y. &0 <= x /\ &0 <= y /\ x + y <= &1
+              ==> f(x + y) = f(x) + f(y))
+       ==> ?g.  g real_continuous_on (:real) /\
+                (!x y. g(x + y) = g(x) + g(y)) /\
+                (!x. x IN real_interval[&0,&1] ==> g x = f x)`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN `f(&0) = &0` ASSUME_TAC THENL
+   [FIRST_ASSUM(MP_TAC o ISPECL [`&0`; `&0`]) THEN
+    REWRITE_TAC[REAL_ADD_LID] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  EXISTS_TAC `\x. f(&1) * floor(x) + f(frac x)` THEN
+  REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [UNDISCH_TAC `f real_continuous_on real_interval[&0,&1]` THEN
+    REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; WITHINREAL_UNIV] THEN
+    DISCH_TAC THEN X_GEN_TAC `x:real` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `integer x` THENL
+     [ALL_TAC;
+      MATCH_MP_TAC REAL_CONTINUOUS_ADD THEN CONJ_TAC THEN
+      ASM_SIMP_TAC[REAL_CONTINUOUS_LMUL; REAL_CONTINUOUS_FLOOR; ETA_AX] THEN
+      MATCH_MP_TAC(REWRITE_RULE[o_DEF] REAL_CONTINUOUS_ATREAL_COMPOSE) THEN
+      ASM_SIMP_TAC[REAL_CONTINUOUS_FRAC] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE LAND_CONV [IN_REAL_INTERVAL] o
+                    SPEC `frac x`) THEN
+      ASM_SIMP_TAC[FLOOR_FRAC; REAL_LT_IMP_LE] THEN
+      REWRITE_TAC[real_continuous_atreal; real_continuous_withinreal] THEN
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN
+      ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[IN_REAL_INTERVAL] THEN
+      DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `min d (min (frac x) (&1 - frac x))` THEN
+      ASM_SIMP_TAC[REAL_LT_MIN; REAL_SUB_LT; FLOOR_FRAC; REAL_FRAC_POS_LT] THEN
+      REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REAL_ARITH_TAC] THEN
+    ASM_SIMP_TAC[real_continuous_atreal; REAL_FRAC_ZERO; REAL_FLOOR_REFL] THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE (BINDER_CONV o LAND_CONV)
+       [IN_REAL_INTERVAL]) THEN
+    DISCH_THEN(fun th -> MP_TAC(SPEC `&1` th) THEN MP_TAC(SPEC `&0` th)) THEN
+    REWRITE_TAC[REAL_LE_REFL; REAL_POS] THEN
+    REWRITE_TAC[IMP_IMP; real_continuous_withinreal; AND_FORALL_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `e:real`) THEN
+    ASM_REWRITE_TAC[IN_REAL_INTERVAL] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC)
+                 (X_CHOOSE_THEN `d2:real` STRIP_ASSUME_TAC)) THEN
+    EXISTS_TAC `min (&1) (min d1 d2)` THEN
+    ASM_REWRITE_TAC[REAL_LT_01; REAL_LT_MIN] THEN
+    X_GEN_TAC `y:real` THEN STRIP_TAC THEN
+    DISJ_CASES_TAC(REAL_ARITH `x <= y \/ y < x`) THENL
+     [SUBGOAL_THEN `floor y = floor x` ASSUME_TAC THENL
+       [REWRITE_TAC[GSYM FLOOR_UNIQUE; FLOOR] THEN
+        ASM_SIMP_TAC[REAL_FLOOR_REFL] THEN ASM_REAL_ARITH_TAC;
+        ASM_SIMP_TAC[FRAC_FLOOR; REAL_FLOOR_REFL] THEN
+        REWRITE_TAC[REAL_ARITH `(a + x) - (a + &0) = x - &0`] THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC];
+      SUBGOAL_THEN `floor y = floor x - &1` ASSUME_TAC THENL
+       [REWRITE_TAC[GSYM FLOOR_UNIQUE; FLOOR] THEN
+        ASM_SIMP_TAC[REAL_FLOOR_REFL; INTEGER_CLOSED] THEN ASM_REAL_ARITH_TAC;
+        ASM_SIMP_TAC[FRAC_FLOOR; REAL_FLOOR_REFL] THEN
+        REWRITE_TAC[REAL_ARITH `(f1 * (x - &1) + f) - (f1 * x + &0) =
+                                f - f1`] THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC]];
+    REPEAT GEN_TAC THEN REWRITE_TAC[REAL_FLOOR_ADD; REAL_FRAC_ADD] THEN
+    COND_CASES_TAC THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; FLOOR_FRAC; REAL_LE_ADD] THENL
+     [REAL_ARITH_TAC; ALL_TAC] THEN
+    REWRITE_TAC[REAL_ARITH
+     `f1 * ((x + y) + &1) + g = (f1 * x + z) + f1 * y + h <=>
+      f1 / &2 + g / &2 = z / &2 + h / &2`] THEN
+    SUBGOAL_THEN
+     `!t. &0 <= t /\ t <= &1 ==> f(t) / &2 = f(t / &2)`
+    ASSUME_TAC THENL
+     [GEN_TAC THEN FIRST_ASSUM(MP_TAC o ISPECL [`t / &2`; `t / &2`]) THEN
+      REWRITE_TAC[REAL_HALF] THEN REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[REAL_POS; REAL_LE_REFL; FLOOR_FRAC; REAL_LT_IMP_LE;
+                 REAL_ARITH `~(x + y < &1) ==> &0 <= (x + y) - &1`;
+                 REAL_ARITH `x < &1 /\ y < &1 ==> (x + y) - &1 <= &1`] THEN
+    MATCH_MP_TAC(MESON[]
+     `f(a + b) = f a + f b /\ f(c + d) = f(c) + f(d) /\ a + b = c + d
+      ==> (f:real->real)(a) + f(b) = f(c) + f(d)`) THEN
+    REPEAT CONJ_TAC THEN TRY REAL_ARITH_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    MAP_EVERY (MP_TAC o C SPEC FLOOR_FRAC) [`x:real`; `y:real`] THEN
+    ASM_REAL_ARITH_TAC;
+    GEN_TAC THEN REWRITE_TAC[IN_REAL_INTERVAL] THEN ASM_CASES_TAC `x = &1` THEN
+    ASM_REWRITE_TAC[FLOOR_NUM; FRAC_NUM; REAL_MUL_RID; REAL_ADD_RID] THEN
+    STRIP_TAC THEN SUBGOAL_THEN `floor x = &0` ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[GSYM FLOOR_UNIQUE; INTEGER_CLOSED];
+      ASM_REWRITE_TAC[FRAC_FLOOR; REAL_SUB_RZERO]] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let REAL_CONTINUOUS_ADDITIVE_IMP_LINEAR_INTERVAL = prove
+ (`!f b. (f ---> &0) (atreal (&0) within {x | &0 <= x}) /\
+         (!x y. &0 <= x /\ &0 <= y /\ x + y <= b ==> f(x + y) = f(x) + f(y))
+         ==> !a x. &0 <= x /\ x <= b /\
+                   &0 <= a * x /\ a * x <= b
+                   ==> f(a * x) = a * f(x)`,
+  SUBGOAL_THEN
+   `!f. (f ---> &0) (atreal (&0) within {x | &0 <= x}) /\
+        (!x y. &0 <= x /\ &0 <= y /\ x + y <= &1 ==> f(x + y) = f(x) + f(y))
+        ==> !a x. &0 <= x /\ x <= &1 /\ &0 <= a * x /\ a * x <= &1
+                  ==> f(a * x) = a * f(x)`
+  ASSUME_TAC THENL
+   [SUBGOAL_THEN
+     `!f. f real_continuous_on real_interval[&0,&1] /\
+          (!x y. &0 <= x /\ &0 <= y /\ x + y <= &1 ==> f(x + y) = f(x) + f(y))
+          ==> !a x. &0 <= x /\ x <= &1 /\ &0 <= a * x /\ a * x <= &1
+                    ==> f(a * x) = a * f(x)`
+    (fun th -> GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC th) THENL
+     [REPEAT STRIP_TAC THEN
+      MP_TAC(ISPEC `f:real->real` REAL_CONTINUOUS_ADDITIVE_EXTEND) THEN
+      ASM_REWRITE_TAC[IN_REAL_INTERVAL] THEN
+      DISCH_THEN(X_CHOOSE_THEN `g:real->real` STRIP_ASSUME_TAC) THEN
+      MP_TAC(ISPEC `g:real->real` REAL_CONTINUOUS_ADDITIVE_IMP_LINEAR) THEN
+      ASM_MESON_TAC[];
+      ASM_REWRITE_TAC[real_continuous_on; IN_REAL_INTERVAL] THEN
+      X_GEN_TAC `x:real` THEN STRIP_TAC THEN
+      X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REALLIM_WITHINREAL]) THEN
+      DISCH_THEN(MP_TAC o SPEC `e:real`) THEN
+      ASM_REWRITE_TAC[REAL_SUB_RZERO] THEN REWRITE_TAC[IN_REAL_INTERVAL] THEN
+      DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `d:real` THEN ASM_SIMP_TAC[REAL_LT_MUL] THEN
+      X_GEN_TAC `y:real` THEN STRIP_TAC THEN
+      REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
+       (REAL_ARITH `y = x \/ y < x \/ x < y`) THENL
+       [ASM_REWRITE_TAC[REAL_SUB_REFL; REAL_ABS_NUM];
+        SUBGOAL_THEN `(f:real->real)(y + (x - y)) = f(y) + f(x - y)`
+        MP_TAC THENL
+         [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC;
+          REWRITE_TAC[REAL_SUB_ADD2] THEN DISCH_THEN SUBST1_TAC THEN
+          REWRITE_TAC[REAL_ADD_SUB2; REAL_ABS_NEG] THEN
+          FIRST_X_ASSUM MATCH_MP_TAC THEN
+          REWRITE_TAC[IN_ELIM_THM] THEN ASM_REAL_ARITH_TAC];
+        SUBGOAL_THEN `(f:real->real)(x + (y - x)) = f(x) + f(y - x)`
+        MP_TAC THENL
+         [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC;
+          REWRITE_TAC[REAL_SUB_ADD2] THEN DISCH_THEN SUBST1_TAC THEN
+          REWRITE_TAC[REAL_ADD_SUB] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+          REWRITE_TAC[IN_ELIM_THM] THEN ASM_REAL_ARITH_TAC]]];
+    REPEAT GEN_TAC THEN STRIP_TAC THEN REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
+     (REAL_ARITH `b < &0 \/ b = &0 \/ &0 < b`)
+    THENL
+     [ASM_REAL_ARITH_TAC;
+      ASM_SIMP_TAC[REAL_ARITH
+       `a <= x /\ x <= a /\ a <= y /\ y <= a <=> x = a /\ y = a`] THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL [`&0`; `&0`]) THEN
+      ASM_REWRITE_TAC[REAL_ADD_LID; REAL_LE_REFL] THEN CONV_TAC REAL_RING;
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o ISPEC `(\x. f(b * x)):real->real`) THEN
+    REWRITE_TAC[] THEN ANTS_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `a:real` THEN
+      DISCH_THEN(fun th -> X_GEN_TAC `x:real` THEN STRIP_TAC THEN
+                           MP_TAC(ISPEC `x / b:real` th)) THEN
+      ASM_SIMP_TAC[REAL_FIELD `&0 < b ==> b * a * x / b = a * x`;
+                   REAL_DIV_LMUL; REAL_LT_IMP_NZ] THEN
+      DISCH_THEN MATCH_MP_TAC THEN
+      REWRITE_TAC[REAL_ARITH `a * x / b:real = (a * x) / b`] THEN
+      ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ] THEN
+      ASM_REAL_ARITH_TAC] THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_ADD_LDISTRIB] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_SIMP_TAC[REAL_ARITH `b * x + b * y <= b <=> &0 <= b * (&1 - (x + y))`;
+                   REAL_LE_MUL; REAL_LT_IMP_LE; REAL_SUB_LE]] THEN
+    REWRITE_TAC[REALLIM_WITHINREAL] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REALLIM_WITHINREAL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[REAL_SUB_RZERO] THEN
+    REWRITE_TAC[REAL_SUB_RZERO; IN_ELIM_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `d / b:real` THEN ASM_SIMP_TAC[REAL_LT_DIV] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE; REAL_ABS_MUL] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 < b ==> abs b * x = x * b`] THEN
+    ASM_SIMP_TAC[REAL_LT_MUL; GSYM REAL_LT_RDIV_EQ]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More Steinhaus variants.                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let STEINHAUS_TRIVIAL = prove
+ (`!s e. ~(negligible s) /\ &0 < e
+         ==> ?x y:real^N. x IN s /\ y IN s /\ ~(x = y) /\ norm(x - y) < e`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[] THEN DISCH_TAC THEN
+  MATCH_MP_TAC NEGLIGIBLE_COUNTABLE THEN
+  MATCH_MP_TAC DISCRETE_IMP_COUNTABLE THEN
+  ASM_MESON_TAC[REAL_NOT_LT]);;
+
+let REAL_STEINHAUS = prove
+ (`!s. real_measurable s /\ &0 < real_measure s
+       ==> ?d. &0 < d /\
+               real_interval(--d,d) SUBSET {x - y | x IN s /\ y IN s}`,
+  GEN_TAC THEN SIMP_TAC[IMP_CONJ; REAL_MEASURE_MEASURE] THEN
+  REWRITE_TAC[IMP_IMP; REAL_MEASURABLE_MEASURABLE] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP STEINHAUS) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+  REWRITE_TAC[SUBSET; BALL_INTERVAL; IN_INTERVAL_1; IN_REAL_INTERVAL] THEN
+  REWRITE_TAC[SET_RULE `{g x y | x IN IMAGE f s /\ y IN IMAGE f t} =
+                        {g (f x) (f y) | x IN s /\ y IN t}`] THEN
+  REWRITE_TAC[GSYM LIFT_SUB] THEN
+  REWRITE_TAC[SET_RULE `{lift(f x y) | P x y} = IMAGE lift {f x y | P x y}`;
+              IN_IMAGE_LIFT_DROP; GSYM FORALL_DROP] THEN
+  REWRITE_TAC[DROP_SUB; DROP_VEC; LIFT_DROP; DROP_ADD] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Bernstein polynomials.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let bernstein = new_definition
+ `bernstein n k x = &(binom(n,k)) * x pow k * (&1 - x) pow (n - k)`;;
+
+let BERNSTEIN_CONV =
+  GEN_REWRITE_CONV I [bernstein] THENC
+  COMB2_CONV (RAND_CONV(RAND_CONV NUM_BINOM_CONV))
+             (RAND_CONV(RAND_CONV NUM_SUB_CONV)) THENC
+  REAL_POLY_CONV;;
+
+(* ------------------------------------------------------------------------- *)
+(* Lemmas about Bernstein polynomials.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let BERNSTEIN_POS = prove
+ (`!n k x. &0 <= x /\ x <= &1 ==> &0 <= bernstein n k x`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[bernstein] THEN
+  MATCH_MP_TAC REAL_LE_MUL THEN REWRITE_TAC[REAL_POS] THEN
+  MATCH_MP_TAC REAL_LE_MUL THEN CONJ_TAC THEN
+  MATCH_MP_TAC REAL_POW_LE THEN ASM_REAL_ARITH_TAC);;
+
+let SUM_BERNSTEIN = prove
+ (`!n. sum (0..n) (\k. bernstein n k x) = &1`,
+  REWRITE_TAC[bernstein; GSYM REAL_BINOMIAL_THEOREM] THEN
+  REWRITE_TAC[REAL_SUB_ADD2; REAL_POW_ONE]);;
+
+let BERNSTEIN_LEMMA = prove
+ (`!n x. sum(0..n) (\k. (&k - &n * x) pow 2 * bernstein n k x) =
+         &n * x * (&1 - x)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+    `!x y. sum(0..n) (\k. &(binom(n,k)) * x pow k * y pow (n - k)) =
+           (x + y) pow n`
+  (LABEL_TAC "0") THENL [ASM_REWRITE_TAC[REAL_BINOMIAL_THEOREM]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x y. sum(0..n) (\k. &k * &(binom(n,k)) * x pow (k - 1) * y pow (n - k)) =
+          &n * (x + y) pow (n - 1)`
+  (LABEL_TAC "1") THENL
+   [REPEAT GEN_TAC THEN MATCH_MP_TAC REAL_DERIVATIVE_UNIQUE_ATREAL THEN
+    MAP_EVERY EXISTS_TAC
+     [`\x. sum(0..n) (\k. &(binom(n,k)) * x pow k * y pow (n - k))`;
+      `x:real`] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC HAS_REAL_DERIVATIVE_SUM THEN REWRITE_TAC[FINITE_NUMSEG];
+      ASM_REWRITE_TAC[]] THEN
+    REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN CONV_TAC REAL_RING;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x y. sum(0..n)
+        (\k. &k * &(k - 1) * &(binom(n,k)) * x pow (k - 2) * y pow (n - k)) =
+          &n * &(n - 1) * (x + y) pow (n - 2)`
+  (LABEL_TAC "2") THENL
+   [REPEAT GEN_TAC THEN MATCH_MP_TAC REAL_DERIVATIVE_UNIQUE_ATREAL THEN
+    MAP_EVERY EXISTS_TAC
+     [`\x. sum(0..n) (\k. &k * &(binom(n,k)) * x pow (k - 1) * y pow (n - k))`;
+      `x:real`] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC HAS_REAL_DERIVATIVE_SUM THEN REWRITE_TAC[FINITE_NUMSEG];
+      ASM_REWRITE_TAC[]] THEN
+    REPEAT STRIP_TAC THEN REAL_DIFF_TAC THEN
+    REWRITE_TAC[ARITH_RULE `n - 1 - 1 = n - 2`] THEN CONV_TAC REAL_RING;
+    ALL_TAC] THEN
+  REWRITE_TAC[REAL_ARITH
+   `(a - b) pow 2 * x =
+    a * (a - &1) * x + (&1 - &2 * b) * a * x + b * b * x`] THEN
+  REWRITE_TAC[SUM_ADD_NUMSEG; SUM_LMUL; SUM_BERNSTEIN] THEN
+  SUBGOAL_THEN `sum(0..n) (\k. &k * bernstein n k x) = &n * x` SUBST1_TAC THENL
+   [REMOVE_THEN "1" (MP_TAC o SPECL [`x:real`; `&1 - x`]) THEN
+    REWRITE_TAC[REAL_SUB_ADD2; REAL_POW_ONE; bernstein; REAL_MUL_RID] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[GSYM SUM_RMUL] THEN
+    MATCH_MP_TAC SUM_EQ_NUMSEG THEN X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+    REWRITE_TAC[REAL_ARITH
+     `(k * b * xk * y) * x:real = k * b * (x * xk) * y`] THEN
+    REWRITE_TAC[GSYM(CONJUNCT2 real_pow)] THEN
+    DISJ_CASES_TAC(ARITH_RULE `k = 0 \/ SUC(k - 1) = k`) THEN
+    ASM_REWRITE_TAC[REAL_MUL_LZERO];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+  `sum(0..n) (\k. &k * (&k - &1) * bernstein n k x) = &n * (&n - &1) * x pow 2`
+  SUBST1_TAC THENL [ALL_TAC; CONV_TAC REAL_RING] THEN
+  REMOVE_THEN "2" (MP_TAC o SPECL [`x:real`; `&1 - x`]) THEN
+  REWRITE_TAC[REAL_SUB_ADD2; REAL_POW_ONE; bernstein; REAL_MUL_RID] THEN
+  ASM_CASES_TAC `n = 0` THEN
+  ASM_REWRITE_TAC[SUM_SING_NUMSEG; REAL_MUL_LZERO] THEN
+  ASM_SIMP_TAC[GSYM REAL_OF_NUM_SUB; LE_1; REAL_MUL_ASSOC] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[GSYM SUM_RMUL] THEN
+  MATCH_MP_TAC SUM_EQ_NUMSEG THEN X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+  REWRITE_TAC[REAL_ARITH `((((k * k1) * b) * xk) * y) * x2:real =
+                            k * k1 * b * y * (x2 * xk)`] THEN
+  REWRITE_TAC[GSYM REAL_POW_ADD; GSYM REAL_MUL_ASSOC] THEN
+  REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
+   (ARITH_RULE `k = 0 \/ k = 1 \/ 1 <= k /\ 2 + k - 2 = k`) THEN
+  ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID; SUB_REFL; REAL_SUB_REFL] THEN
+  ASM_SIMP_TAC[GSYM REAL_OF_NUM_SUB] THEN REWRITE_TAC[REAL_MUL_AC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Explicit Bernstein version of 1D Weierstrass approximation theorem        *)
+(* ------------------------------------------------------------------------- *)
+
+let BERNSTEIN_WEIERSTRASS = prove
+ (`!f e.
+      f real_continuous_on real_interval[&0,&1] /\ &0 < e
+      ==> ?N. !n x. N <= n /\ x IN real_interval[&0,&1]
+                    ==> abs(f x -
+                            sum(0..n) (\k. f(&k / &n) * bernstein n k x)) < e`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `real_bounded(IMAGE f (real_interval[&0,&1]))` MP_TAC THENL
+   [MATCH_MP_TAC REAL_COMPACT_IMP_BOUNDED THEN
+    MATCH_MP_TAC REAL_COMPACT_CONTINUOUS_IMAGE THEN
+    ASM_REWRITE_TAC[REAL_COMPACT_INTERVAL];
+    REWRITE_TAC[REAL_BOUNDED_POS; LEFT_IMP_EXISTS_THM; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[IN_REAL_INTERVAL] THEN X_GEN_TAC `M:real` THEN STRIP_TAC] THEN
+  SUBGOAL_THEN `f real_uniformly_continuous_on real_interval[&0,&1]`
+  MP_TAC THENL
+   [ASM_SIMP_TAC[REAL_COMPACT_UNIFORMLY_CONTINUOUS; REAL_COMPACT_INTERVAL];
+    REWRITE_TAC[real_uniformly_continuous_on] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
+    ASM_REWRITE_TAC[REAL_HALF; IN_REAL_INTERVAL] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC)] THEN
+  SUBGOAL_THEN
+   `!n x. 0 < n /\ &0 <= x /\ x <= &1
+          ==> abs(f x - sum(0..n) (\k. f(&k / &n) * bernstein n k x))
+                <= e / &2 + (&2 * M) / (d pow 2 * &n)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `abs(sum(0..n) (\k. (f x - f(&k / &n)) * bernstein n k x))` THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[REAL_SUB_RDISTRIB; SUM_SUB_NUMSEG; SUM_LMUL] THEN
+      REWRITE_TAC[SUM_BERNSTEIN; REAL_MUL_RID; REAL_LE_REFL];
+      ALL_TAC] THEN
+    W(MP_TAC o PART_MATCH lhand SUM_ABS_NUMSEG o lhand o snd) THEN
+    MATCH_MP_TAC(REAL_ARITH `a <= b ==> x <= a ==> x <= b`) THEN
+    REWRITE_TAC[REAL_ABS_MUL] THEN
+    ASM_SIMP_TAC[BERNSTEIN_POS; REAL_ARITH `&0 <= x ==> abs x = x`] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC
+     `sum(0..n) (\k. (e / &2 + &2 * M / d pow 2 * (x - &k / &n) pow 2) *
+                     bernstein n k x)` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC SUM_LE_NUMSEG THEN X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+      REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+      ASM_SIMP_TAC[BERNSTEIN_POS] THEN
+      SUBGOAL_THEN `&0 <= &k / &n /\ &k / &n <= &1` STRIP_ASSUME_TAC THENL
+       [ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; REAL_OF_NUM_LT] THEN
+        ASM_REWRITE_TAC[REAL_OF_NUM_MUL; REAL_OF_NUM_LE; MULT_CLAUSES];
+        ALL_TAC] THEN
+      DISJ_CASES_TAC(REAL_ARITH
+        `abs(x - &k / &n) < d \/ d <= abs(x - &k / &n)`)
+      THENL
+       [MATCH_MP_TAC(REAL_ARITH `x < e /\ &0 <= d ==> x <= e + d`) THEN
+        ASM_SIMP_TAC[REAL_ARITH `&0 <= &2 * x <=> &0 <= x`] THEN
+        ASM_SIMP_TAC[REAL_LE_MUL; REAL_LE_DIV; REAL_POW_2; REAL_LE_SQUARE;
+                     REAL_LT_IMP_LE];
+        MATCH_MP_TAC(REAL_ARITH `&0 < e /\ x <= d ==> x <= e / &2 + d`) THEN
+        ASM_REWRITE_TAC[] THEN
+        MATCH_MP_TAC(REAL_ARITH
+         `abs(x) <= M /\ abs(y) <= M /\ M * &1 <= M * b / d
+          ==> abs(x - y) <= &2 * M / d * b`) THEN
+        ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_POW_LT; REAL_LE_RDIV_EQ] THEN
+        REWRITE_TAC[REAL_MUL_LID; GSYM REAL_LE_SQUARE_ABS] THEN
+        ASM_REAL_ARITH_TAC];
+      REWRITE_TAC[REAL_ADD_RDISTRIB; SUM_ADD_NUMSEG; SUM_LMUL] THEN
+      REWRITE_TAC[SUM_BERNSTEIN; REAL_MUL_RID; REAL_LE_LADD] THEN
+      REWRITE_TAC[GSYM REAL_MUL_ASSOC; SUM_LMUL] THEN
+      REWRITE_TAC[real_div; REAL_INV_MUL; GSYM REAL_MUL_ASSOC] THEN
+      ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_OF_NUM_LT; ARITH; REAL_POW_LT;
+                   REAL_LT_INV_EQ] THEN
+      MATCH_MP_TAC REAL_LE_LCANCEL_IMP THEN EXISTS_TAC `&n pow 2` THEN
+      ASM_SIMP_TAC[GSYM SUM_LMUL; REAL_POW_LT; REAL_OF_NUM_LT; REAL_FIELD
+        `&0 < n ==> n pow 2 * inv(n) = n`] THEN
+      REWRITE_TAC[REAL_MUL_ASSOC; GSYM REAL_POW_MUL] THEN
+      ASM_SIMP_TAC[REAL_OF_NUM_LT; REAL_FIELD
+        `&0 < n ==> n * (x - k * inv n) = n * x - k`] THEN
+      ONCE_REWRITE_TAC[REAL_ARITH `(x - y:real) pow 2 = (y - x) pow 2`] THEN
+      REWRITE_TAC[BERNSTEIN_LEMMA; REAL_ARITH
+        `&n * x <= &n <=> &n * x <= &n * &1 * &1`] THEN
+      MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[REAL_POS] THEN
+      MATCH_MP_TAC REAL_LE_MUL2 THEN ASM_REAL_ARITH_TAC];
+    MP_TAC(ISPEC `(e / &4 * d pow 2) / (&2 * M)` REAL_ARCH_INV) THEN
+    ASM_SIMP_TAC[REAL_LT_RDIV_EQ; REAL_OF_NUM_LT; ARITH; REAL_LT_MUL] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_LDIV_EQ; REAL_POW_LT; REAL_MUL_LZERO] THEN
+    REWRITE_TAC[real_div; REAL_MUL_LZERO] THEN
+    REWRITE_TAC[REAL_ARITH `(x * &2 * m) * i = (&2 * m) * (i * x)`] THEN
+    REWRITE_TAC[GSYM REAL_INV_MUL] THEN
+    ASM_SIMP_TAC[GSYM real_div; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN STRIP_TAC THEN
+    MAP_EVERY X_GEN_TAC [`n:num`; `x:real`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`n:num`; `x:real`]) THEN ASM_SIMP_TAC[] THEN
+    ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `&0 < e /\ k < e / &4 ==> x <= e / &2 + k ==> x < e`) THEN
+    ASM_SIMP_TAC[] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `x < e ==> y <= x ==> y < e`)) THEN
+    ASM_SIMP_TAC[real_div; REAL_LE_LMUL_EQ; REAL_LT_MUL;
+                 REAL_OF_NUM_LT; ARITH] THEN
+    MATCH_MP_TAC REAL_LE_INV2 THEN
+    ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_LT_MUL; REAL_POW_LT;
+                 REAL_OF_NUM_LT; LE_1; REAL_OF_NUM_LE]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* General Stone-Weierstrass theorem.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let STONE_WEIERSTRASS_ALT = prove
+ (`!(P:(real^N->real)->bool) (s:real^N->bool).
+        compact s /\
+        (!c. P(\x. c)) /\
+        (!f g. P(f) /\ P(g) ==> P(\x. f x + g x)) /\
+        (!f g. P(f) /\ P(g) ==> P(\x. f x * g x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y)
+               ==> ?f. (!x. x IN s ==> f real_continuous (at x within s)) /\
+                       P(f) /\ ~(f x = f y))
+        ==> !f e. (!x. x IN s ==> f real_continuous (at x within s)) /\ &0 < e
+                  ==> ?g. P(g) /\ !x. x IN s ==> abs(f x - g x) < e`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN MAP_EVERY ABBREV_TAC
+   [`C = \f. !x:real^N. x IN s ==> f real_continuous at x within s`;
+    `A = \f. C f /\
+             !e. &0 < e
+               ==> ?g. P(g) /\ !x:real^N. x IN s ==> abs(f x - g x) < e`] THEN
+  SUBGOAL_THEN `!f:real^N->real. C(f) ==> A(f)` MP_TAC THENL
+   [ALL_TAC; MAP_EVERY EXPAND_TAC ["A"; "C"] THEN SIMP_TAC[]] THEN
+  SUBGOAL_THEN `!c:real. A(\x:real^N. c)` (LABEL_TAC "const") THENL
+   [MAP_EVERY EXPAND_TAC ["A"; "C"] THEN X_GEN_TAC `c:real` THEN
+    ASM_REWRITE_TAC[REAL_CONTINUOUS_CONST] THEN X_GEN_TAC `e:real` THEN
+    DISCH_TAC THEN EXISTS_TAC `(\x. c):real^N->real` THEN
+    ASM_REWRITE_TAC[REAL_SUB_REFL; REAL_ABS_0];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!f g:real^N->real. A(f) /\ A(g) ==> A(\x. f x + g x)`
+  (LABEL_TAC "add") THENL
+   [MAP_EVERY EXPAND_TAC ["A"; "C"] THEN SIMP_TAC[REAL_CONTINUOUS_ADD] THEN
+    MAP_EVERY X_GEN_TAC [`f:real^N->real`; `g:real^N->real`] THEN
+    DISCH_THEN(fun th -> REPEAT STRIP_TAC THEN MP_TAC th) THEN
+    DISCH_THEN(CONJUNCTS_THEN (MP_TAC o SPEC `e / &2` o CONJUNCT2)) THEN
+    ASM_REWRITE_TAC[REAL_HALF; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `g':real^N->real` THEN STRIP_TAC THEN
+    X_GEN_TAC `f':real^N->real` THEN STRIP_TAC THEN
+    EXISTS_TAC `(\x. f' x + g' x):real^N->real` THEN
+    ASM_SIMP_TAC[REAL_ARITH
+     `abs(f - f') < e / &2 /\ abs(g - g') < e / &2
+      ==> abs((f + g) - (f' + g')) < e`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!f:real^N->real. A(f) ==> C(f)` (LABEL_TAC "AC") THENL
+   [EXPAND_TAC "A" THEN SIMP_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `!f:real^N->real. C(f) ==> real_bounded(IMAGE f s)`
+  (LABEL_TAC "bound") THENL
+   [GEN_TAC THEN EXPAND_TAC "C" THEN
+    REWRITE_TAC[REAL_BOUNDED; GSYM IMAGE_o] THEN
+    REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS1] THEN
+    REWRITE_TAC[GSYM CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+    ASM_SIMP_TAC[COMPACT_IMP_BOUNDED; COMPACT_CONTINUOUS_IMAGE];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!f g:real^N->real. A(f) /\ A(g) ==> A(\x. f x * g x)`
+  (LABEL_TAC "mul") THENL
+   [MAP_EVERY X_GEN_TAC [`f:real^N->real`; `g:real^N->real`] THEN
+    DISCH_THEN(fun th -> STRIP_ASSUME_TAC th THEN MP_TAC th) THEN
+    MAP_EVERY EXPAND_TAC ["A"; "C"] THEN SIMP_TAC[REAL_CONTINUOUS_MUL] THEN
+    REWRITE_TAC[IMP_CONJ] THEN
+    MAP_EVERY (DISCH_THEN o LABEL_TAC) ["cf"; "af"; "cg"; "ag"] THEN
+    SUBGOAL_THEN
+     `real_bounded(IMAGE (f:real^N->real) s) /\
+      real_bounded(IMAGE (g:real^N->real) s)`
+    MP_TAC THENL
+     [ASM_SIMP_TAC[]; REWRITE_TAC[REAL_BOUNDED_POS_LT; FORALL_IN_IMAGE]] THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `Bf:real` STRIP_ASSUME_TAC)
+     (X_CHOOSE_THEN `Bg:real` STRIP_ASSUME_TAC)) THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    REMOVE_THEN "ag" (MP_TAC o SPEC `e / &2 / Bf`) THEN
+    ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `g':real^N->real` THEN STRIP_TAC THEN
+    REMOVE_THEN "af" (MP_TAC o SPEC `e / &2 / (Bg + e / &2 / Bf)`) THEN
+    ASM_SIMP_TAC[REAL_HALF; REAL_LT_DIV; REAL_LT_ADD] THEN
+    DISCH_THEN(X_CHOOSE_THEN `f':real^N->real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(\x. f'(x) * g'(x)):real^N->real` THEN
+    ASM_SIMP_TAC[REAL_ARITH
+     `f * g - f' * g':real = f * (g - g') + g' * (f - f')`] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `e = Bf * e / &2 / Bf +
+                      (Bg + e / &2 / Bf) * e / &2 / (Bg + e / &2 / Bf)`
+    SUBST1_TAC THENL
+     [MATCH_MP_TAC(REAL_ARITH `a = e / &2 /\ b = e / &2 ==> e = a + b`) THEN
+      CONJ_TAC THEN MAP_EVERY MATCH_MP_TAC [REAL_DIV_LMUL; REAL_LT_IMP_NZ] THEN
+      ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_ADD; REAL_HALF];
+      MATCH_MP_TAC(REAL_ARITH
+       `abs a < c /\ abs b < d ==> abs(a + b) < c + d`) THEN
+      REWRITE_TAC[REAL_ABS_MUL] THEN CONJ_TAC THEN
+      MATCH_MP_TAC REAL_LT_MUL2 THEN ASM_SIMP_TAC[REAL_ABS_POS] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `!g. abs(g) < Bg /\ abs(g - g') < e ==> abs(g') < Bg + e`) THEN
+      EXISTS_TAC `(g:real^N->real) x` THEN ASM_SIMP_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x y. x IN s /\ y IN s /\ ~(x = y)
+          ==> ?f:real^N->real. A(f) /\ ~(f x = f y)`
+  (LABEL_TAC "sep") THENL
+   [MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `y:real^N`]) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    MAP_EVERY EXPAND_TAC ["A"; "C"] THEN
+    ASM_MESON_TAC[REAL_SUB_REFL; REAL_ABS_0];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!f. A(f) ==> A(\x:real^N. abs(f x))` (LABEL_TAC "abs") THENL
+   [SUBGOAL_THEN `!f. A(f) /\ (!x. x IN s ==> abs(f x) <= &1 / &4)
+                      ==> A(\x:real^N. abs(f x))`
+    ASSUME_TAC THENL
+     [ALL_TAC;
+      REPEAT STRIP_TAC THEN
+      SUBGOAL_THEN `real_bounded(IMAGE (f:real^N->real) s)` MP_TAC THENL
+       [ASM_SIMP_TAC[]; REWRITE_TAC[REAL_BOUNDED_POS_LT; FORALL_IN_IMAGE]] THEN
+      DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+      SUBGOAL_THEN `A(\x:real^N. (&4 * B) * abs(inv(&4 * B) * f x)):bool`
+      MP_TAC THENL
+       [USE_THEN "mul" MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[REAL_ABS_MUL] THEN
+        ASM_SIMP_TAC[REAL_ARITH `&0 < B ==> abs(B) = B`;
+                     REAL_LT_INV_EQ; REAL_LT_MUL; REAL_OF_NUM_LT; ARITH] THEN
+        ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+        ASM_SIMP_TAC[GSYM real_div; REAL_LE_LDIV_EQ; REAL_LT_MUL;
+                     REAL_OF_NUM_LT; ARITH; REAL_MUL_ASSOC] THEN
+        CONV_TAC REAL_RAT_REDUCE_CONV THEN
+        ASM_SIMP_TAC[REAL_MUL_LID; REAL_LT_IMP_LE];
+        ASM_SIMP_TAC[REAL_ABS_MUL; REAL_ARITH `&0 < B ==> abs(B) = B`;
+                     REAL_LT_INV_EQ; REAL_LT_MUL; REAL_OF_NUM_LT; ARITH] THEN
+        ASM_SIMP_TAC[REAL_MUL_ASSOC; REAL_MUL_RINV; REAL_MUL_LID;
+                     REAL_ARITH `&0 < B ==> ~(&4 * B = &0)`]]] THEN
+    X_GEN_TAC `f:real^N->real` THEN MAP_EVERY EXPAND_TAC ["A"; "C"] THEN
+    DISCH_THEN(fun th -> CONJ_TAC THEN MP_TAC th) THENL
+     [DISCH_THEN(MP_TAC o CONJUNCT1 o CONJUNCT1) 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_ALT; o_DEF]
+        REAL_CONTINUOUS_WITHIN_COMPOSE) THEN
+      REWRITE_TAC[real_continuous_withinreal] THEN
+      MESON_TAC[ARITH_RULE `abs(x - y) < d ==> abs(abs x - abs y) < d`];
+      ALL_TAC] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(fun t -> X_GEN_TAC `e:real` THEN DISCH_TAC THEN MP_TAC t) THEN
+    DISCH_THEN(MP_TAC o SPEC `min (e / &2) (&1 / &4)`) THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    REWRITE_TAC[REAL_LT_MIN; FORALL_AND_THM;
+                TAUT `(a ==> b /\ c) <=> (a ==> b) /\ (a ==> c)`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `p:real^N->real` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`\x. abs(x - &1 / &2)`; `e / &2`]
+     BERNSTEIN_WEIERSTRASS) THEN
+    REWRITE_TAC[] THEN ANTS_TAC THENL
+     [ASM_REWRITE_TAC[real_continuous_on; REAL_HALF] THEN
+      MESON_TAC[ARITH_RULE
+       `abs(x - y) < d ==> abs(abs(x - a) - abs(y - a)) < d`];
+      ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:num` (MP_TAC o SPEC `n:num`)) THEN
+    REWRITE_TAC[LE_REFL] THEN DISCH_TAC THEN
+    EXISTS_TAC `\x:real^N. sum(0..n) (\k. abs(&k / &n - &1 / &2) *
+                                          bernstein n k (&1 / &2 + p x))` THEN
+    REWRITE_TAC[] THEN CONJ_TAC THENL
+     [SUBGOAL_THEN
+       `!m c z. P(\x:real^N.
+            sum(0..m) (\k. c k * bernstein (z m) k (&1 / &2 + p x)))`
+       (fun th -> REWRITE_TAC[th]) THEN
+      SUBGOAL_THEN
+       `!m k. P(\x:real^N. bernstein m k (&1 / &2 + p x))`
+      ASSUME_TAC THENL
+       [ALL_TAC; INDUCT_TAC THEN ASM_SIMP_TAC[SUM_CLAUSES_NUMSEG; LE_0]] THEN
+      REPEAT GEN_TAC THEN REWRITE_TAC[bernstein] THEN
+      REWRITE_TAC[REAL_ARITH `&1 - (&1 / &2 + p) = &1 / &2 + -- &1 * p`] THEN
+      REPEAT(FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]) THEN
+      SUBGOAL_THEN
+       `!f:real^N->real k. P(f) ==> P(\x. f(x) pow k)`
+       (fun th -> ASM_SIMP_TAC[th]) THEN
+      GEN_TAC THEN INDUCT_TAC THEN ASM_SIMP_TAC[real_pow];
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC(REAL_ARITH
+       `!p. abs(abs(p x) - s) < e / &2 /\
+            abs(f x - p x) < e / &2
+            ==> abs(abs(f x) - s) < e`) THEN
+      EXISTS_TAC `p:real^N->real` THEN ASM_SIMP_TAC[] THEN
+      GEN_REWRITE_TAC (PAT_CONV `\x. abs(abs x - a) < e`)
+        [REAL_ARITH `x = (&1 / &2 + x) - &1 / &2`] THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[IN_REAL_INTERVAL] THEN
+      MATCH_MP_TAC(REAL_ARITH
+       `!f. abs(f) <= &1 / &4 /\ abs(f - p) < &1 / &4
+            ==> &0 <= &1 / &2 + p /\ &1 / &2 + p <= &1`) THEN
+      EXISTS_TAC `(f:real^N->real) x` THEN ASM_SIMP_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!f:real^N->real g. A(f) /\ A(g) ==> A(\x. max (f x) (g x))`
+  (LABEL_TAC "max") THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_ARITH
+     `max a b = inv(&2) * (a + b + abs(a + -- &1 * b))`] THEN
+    REPEAT(FIRST_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[]);
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!f:real^N->real g. A(f) /\ A(g) ==> A(\x. min (f x) (g x))`
+  (LABEL_TAC "min") THENL
+   [ASM_SIMP_TAC[REAL_ARITH `min a b = -- &1 * (max(-- &1 * a) (-- &1 * b))`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!t. FINITE t /\ (!f. f IN t ==> A(f)) ==> A(\x:real^N. sup {f(x) | f IN t})`
+  (LABEL_TAC "sup") THENL
+   [REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+    ASM_SIMP_TAC[FORALL_IN_INSERT; SIMPLE_IMAGE; IMAGE_CLAUSES] THEN
+    ASM_SIMP_TAC[SUP_INSERT_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+    MAP_EVERY X_GEN_TAC [`f:real^N->real`; `t:(real^N->real)->bool`] THEN
+    ASM_CASES_TAC `t:(real^N->real)->bool = {}` THEN ASM_SIMP_TAC[ETA_AX];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!t. FINITE t /\ (!f. f IN t ==> A(f)) ==> A(\x:real^N. inf {f(x) | f IN t})`
+  (LABEL_TAC "inf") THENL
+   [REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+    ASM_SIMP_TAC[FORALL_IN_INSERT; SIMPLE_IMAGE; IMAGE_CLAUSES] THEN
+    ASM_SIMP_TAC[INF_INSERT_FINITE; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+    MAP_EVERY X_GEN_TAC [`f:real^N->real`; `t:(real^N->real)->bool`] THEN
+    ASM_CASES_TAC `t:(real^N->real)->bool = {}` THEN ASM_SIMP_TAC[ETA_AX];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!f:real^N->real e.
+      C(f) /\ &0 < e ==> ?g. A(g) /\ !x. x IN s ==> abs(f x - g x) < e`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    X_GEN_TAC `f:real^N->real` THEN DISCH_TAC THEN EXPAND_TAC "A" THEN
+    CONJ_TAC THENL [FIRST_X_ASSUM ACCEPT_TAC; ALL_TAC] THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`f:real^N->real`; `e / &2`]) THEN
+    ASM_REWRITE_TAC[REAL_HALF; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `h:real^N->real` THEN EXPAND_TAC "A" THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2` o CONJUNCT2) THEN
+    ASM_REWRITE_TAC[REAL_HALF] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    ASM_MESON_TAC[REAL_ARITH
+     `abs(f - h) < e / &2 /\ abs(h - g) < e / &2 ==> abs(f - g) < e`]] THEN
+  MAP_EVERY X_GEN_TAC [`f:real^N->real`; `e:real`] THEN EXPAND_TAC "C" THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x y. x IN s /\ y IN s
+          ==> ?h:real^N->real. A(h) /\ h(x) = f(x) /\ h(y) = f(y)`
+  MP_TAC THENL
+   [REPEAT STRIP_TAC THEN ASM_CASES_TAC `y:real^N = x` THENL
+     [EXISTS_TAC `\z:real^N. (f:real^N->real) x` THEN ASM_SIMP_TAC[];
+      SUBGOAL_THEN `?h:real^N->real. A(h) /\ ~(h x = h y)`
+      STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+      EXISTS_TAC `\z. (f y - f x) / (h y - h x) * (h:real^N->real)(z) +
+                      (f x - (f y - f x) / (h y - h x) * h(x))` THEN
+      ASM_SIMP_TAC[] THEN
+      UNDISCH_TAC `~((h:real^N->real) x = h y)` THEN CONV_TAC REAL_FIELD];
+      ALL_TAC] 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 `f2:real^N->real^N->real^N->real` THEN DISCH_TAC THEN
+  ABBREV_TAC `G = \x y.
+    {z | z IN s /\ (f2:real^N->real^N->real^N->real) x y z < f(z) + e}` THEN
+  SUBGOAL_THEN `!x y:real^N. x IN s /\ y IN s ==> x IN G x y /\ y IN G x y`
+  ASSUME_TAC THENL
+   [EXPAND_TAC "G" THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    ASM_SIMP_TAC[REAL_LT_ADDR];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x. x IN s ==> ?f1. A(f1) /\ f1 x = f x /\
+                        !y:real^N. y IN s ==> f1 y < f y + e`
+  MP_TAC THENL
+   [REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o
+     GEN_REWRITE_RULE I [COMPACT_EQ_HEINE_BOREL_SUBTOPOLOGY]) THEN
+    DISCH_THEN(MP_TAC o SPEC
+     `{(G:real^N->real^N->real^N->bool) x y | y IN s}`) THEN
+    REWRITE_TAC[SIMPLE_IMAGE; UNIONS_IMAGE; FORALL_IN_IMAGE; ETA_AX] THEN
+    ANTS_TAC THENL
+     [CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+      EXPAND_TAC "G" THEN REWRITE_TAC[] THEN X_GEN_TAC `w:real^N` THEN
+      DISCH_TAC THEN
+      MP_TAC(ISPECL [`lift o (\z:real^N. f2 (x:real^N) (w:real^N) z - f z)`;
+                     `s:real^N->bool`;
+                     `{x:real^1 | x$1 < e}`] CONTINUOUS_OPEN_IN_PREIMAGE) THEN
+      REWRITE_TAC[OPEN_HALFSPACE_COMPONENT_LT; IN_ELIM_THM] THEN
+      REWRITE_TAC[GSYM drop; LIFT_DROP; o_DEF] THEN
+      REWRITE_TAC[LIFT_SUB; GSYM REAL_CONTINUOUS_CONTINUOUS1;
+                  REAL_ARITH `x < y + e <=> x - y < e`] THEN
+      DISCH_THEN MATCH_MP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+      ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+      REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+      REWRITE_TAC[GSYM REAL_CONTINUOUS_CONTINUOUS1; ETA_AX] THEN
+      ASM_MESON_TAC[];
+      ALL_TAC] THEN
+    ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> b /\ a /\ c`] THEN
+    REWRITE_TAC[EXISTS_FINITE_SUBSET_IMAGE; UNIONS_IMAGE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\z:real^N. inf {f2 (x:real^N) (y:real^N) z | y IN t}` THEN
+    REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [GEN_REWRITE_TAC RAND_CONV [REAL_ARITH `x = min x x`] THEN
+      REWRITE_TAC[REAL_MIN_INF; INSERT_AC] THEN AP_TERM_TAC THEN ASM SET_TAC[];
+      REMOVE_THEN "inf" (MP_TAC o SPEC
+       `IMAGE (\y z. (f2:real^N->real^N->real^N->real) x y z) t`) THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE] THEN
+      REWRITE_TAC[SIMPLE_IMAGE; ETA_AX] THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      REWRITE_TAC[GSYM IMAGE_o; o_DEF];
+      SUBGOAL_THEN `~(t:real^N->bool = {})` ASSUME_TAC THENL
+       [ASM SET_TAC[]; ALL_TAC] THEN
+      ASM_SIMP_TAC[REAL_INF_LT_FINITE; SIMPLE_IMAGE;
+                   FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+      REWRITE_TAC[EXISTS_IN_IMAGE] THEN
+      X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+      UNDISCH_TAC
+       `s SUBSET {y:real^N | ?z:real^N. z IN t /\ y IN G (x:real^N) z}` THEN
+      REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+      DISCH_THEN(MP_TAC o SPEC `y:real^N`) THEN ASM_REWRITE_TAC[] THEN
+      EXPAND_TAC "G" THEN REWRITE_TAC[IN_ELIM_THM] THEN ASM_REWRITE_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 `f1:real^N->real^N->real` THEN DISCH_TAC] THEN
+  ABBREV_TAC `H = \x:real^N. {z:real^N | z IN s /\ f z - e < f1 x z}` THEN
+  SUBGOAL_THEN `!x:real^N. x IN s ==> x IN (H x)` ASSUME_TAC THENL
+   [EXPAND_TAC "H" THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    ASM_SIMP_TAC[REAL_ARITH `x - e < x <=> &0 < e`];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o
+  GEN_REWRITE_RULE I [COMPACT_EQ_HEINE_BOREL_SUBTOPOLOGY]) THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `{(H:real^N->real^N->bool) x | x IN s}`) THEN
+  REWRITE_TAC[SIMPLE_IMAGE; UNIONS_IMAGE; FORALL_IN_IMAGE; ETA_AX] THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN EXPAND_TAC "H" THEN
+    REWRITE_TAC[] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`lift o (\z:real^N. f z - f1 (x:real^N) z)`;
+                   `s:real^N->bool`;
+                   `{x:real^1 | x$1 < e}`] CONTINUOUS_OPEN_IN_PREIMAGE) THEN
+    REWRITE_TAC[OPEN_HALFSPACE_COMPONENT_LT; IN_ELIM_THM] THEN
+    REWRITE_TAC[GSYM drop; LIFT_DROP; o_DEF] THEN
+    GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV)
+     [REAL_ARITH `x - y < z <=> x - z < y`] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    REWRITE_TAC[LIFT_SUB; GSYM REAL_CONTINUOUS_CONTINUOUS1;
+                REAL_ARITH `x < y + e <=> x - y < e`] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+    ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+    REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+    REWRITE_TAC[GSYM REAL_CONTINUOUS_CONTINUOUS1; ETA_AX] THEN
+    ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> b /\ a /\ c`] THEN
+  REWRITE_TAC[EXISTS_FINITE_SUBSET_IMAGE; UNIONS_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\z:real^N. sup {f1 (x:real^N) z | x IN t}` THEN
+  REWRITE_TAC[] THEN CONJ_TAC THENL
+   [REMOVE_THEN "sup" (MP_TAC o SPEC `IMAGE (f1:real^N->real^N->real) t`) THEN
+    ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[SIMPLE_IMAGE; ETA_AX] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    REWRITE_TAC[GSYM IMAGE_o; o_DEF];
+    ALL_TAC] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `~(t:real^N->bool = {})` ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[SIMPLE_IMAGE; REAL_ARITH
+   `abs(f - s) < e <=> f - e < s /\ s < f + e`] THEN
+  ASM_SIMP_TAC[REAL_SUP_LT_FINITE; REAL_LT_SUP_FINITE;
+               FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE; FORALL_IN_IMAGE] THEN
+  CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  UNDISCH_TAC `s SUBSET {y:real^N | ?x:real^N. x IN t /\ y IN H x}` THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  EXPAND_TAC "H" THEN REWRITE_TAC[IN_ELIM_THM] THEN ASM_REWRITE_TAC[]);;
+
+let STONE_WEIERSTRASS = prove
+ (`!(P:(real^N->real)->bool) (s:real^N->bool).
+        compact s /\
+        (!f. P(f) ==> !x. x IN s ==> f real_continuous (at x within s)) /\
+        (!c. P(\x. c)) /\
+        (!f g. P(f) /\ P(g) ==> P(\x. f x + g x)) /\
+        (!f g. P(f) /\ P(g) ==> P(\x. f x * g x)) /\
+        (!x y. x IN s /\ y IN s /\ ~(x = y) ==> ?f. P(f) /\ ~(f x = f y))
+        ==> !f e. (!x. x IN s ==> f real_continuous (at x within s)) /\ &0 < e
+                  ==> ?g. P(g) /\ !x. x IN s ==> abs(f x - g x) < e`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC STONE_WEIERSTRASS_ALT THEN ASM_SIMP_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `y:real^N`]) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real and complex versions of Stone-Weierstrass theorem.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_STONE_WEIERSTRASS_ALT = prove
+ (`!P s. real_compact s /\
+         (!c. P (\x. c)) /\
+         (!f g. P f /\ P g ==> P (\x. f x + g x)) /\
+         (!f g. P f /\ P g ==> P (\x. f x * g x)) /\
+         (!x y. x IN s /\ y IN s /\ ~(x = y)
+                ==> ?f. f real_continuous_on s /\ P f /\ ~(f x = f y))
+         ==> !f e. f real_continuous_on s /\ &0 < e
+                   ==> ?g. P g /\ !x. x IN s ==> abs(f x - g x) < e`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`\f. (P:(real->real)->bool)(f o lift)`;
+    `IMAGE lift s`] STONE_WEIERSTRASS_ALT) THEN
+  ASM_SIMP_TAC[GSYM real_compact; o_DEF] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN ANTS_TAC THENL
+   [X_GEN_TAC `x:real` THEN DISCH_TAC THEN
+    X_GEN_TAC `y:real` THEN REWRITE_TAC[LIFT_EQ] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:real`; `y:real`]) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real->real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(g:real->real) o drop` THEN
+    ASM_REWRITE_TAC[o_THM; LIFT_DROP; ETA_AX] THEN
+    UNDISCH_TAC `g real_continuous_on s` THEN
+    REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+    REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS_WITHINREAL] THEN
+    REWRITE_TAC[real_continuous_within; continuous_within] THEN
+    REWRITE_TAC[o_THM; LIFT_DROP; DIST_LIFT];
+    DISCH_THEN(MP_TAC o SPEC `(f:real->real) o drop`) THEN ANTS_TAC THENL
+     [UNDISCH_TAC `f real_continuous_on s` THEN
+      REWRITE_TAC[REAL_CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+      REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS_WITHINREAL] THEN
+      REWRITE_TAC[real_continuous_within; continuous_within] THEN
+      REWRITE_TAC[o_THM; LIFT_DROP; DIST_LIFT];
+      DISCH_THEN(MP_TAC o SPEC `e:real`) THEN
+      ASM_REWRITE_TAC[o_DEF; LIFT_DROP] THEN
+      DISCH_THEN(X_CHOOSE_THEN `g:real^1->real` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `(g:real^1->real) o lift` THEN ASM_REWRITE_TAC[o_DEF]]]);;
+
+let REAL_STONE_WEIERSTRASS = prove
+ (`!P s. real_compact s /\
+         (!f. P f ==> f real_continuous_on s) /\
+         (!c. P (\x. c)) /\
+         (!f g. P f /\ P g ==> P (\x. f x + g x)) /\
+         (!f g. P f /\ P g ==> P (\x. f x * g x)) /\
+         (!x y. x IN s /\ y IN s /\ ~(x = y) ==> ?f. P f /\ ~(f x = f y))
+         ==> !f e. f real_continuous_on s /\ &0 < e
+                   ==> ?g. P g /\ !x. x IN s ==> abs(f x - g x) < e`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC REAL_STONE_WEIERSTRASS_ALT THEN ASM_SIMP_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`x:real`; `y:real`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`x:real`; `y:real`]) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN ASM_MESON_TAC[]);;
+
+let COMPLEX_STONE_WEIERSTRASS_ALT = prove
+ (`!P s. compact s /\
+         (!c. P (\x. c)) /\
+         (!f. P f ==> P(\x. cnj(f x))) /\
+         (!f g. P f /\ P g ==> P (\x. f x + g x)) /\
+         (!f g. P f /\ P g ==> P (\x. f x * g x)) /\
+         (!x y. x IN s /\ y IN s /\ ~(x = y)
+                ==> ?f. P f /\ f continuous_on s /\ ~(f x = f y))
+         ==> !f:real^N->complex e.
+                f continuous_on s /\ &0 < e
+                ==> ?g. P g /\ !x. x IN s ==> norm(f x - g x) < e`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  SUBGOAL_THEN `!f. P f ==> P(\x:real^N. Cx(Re(f x)))` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[CX_RE_CNJ; SIMPLE_COMPLEX_ARITH
+     `x / Cx(&2) = inv(Cx(&2)) * x`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!f. P f ==> P(\x:real^N. Cx(Im(f x)))` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[CX_IM_CNJ; SIMPLE_COMPLEX_ARITH
+     `x - y = x + --Cx(&1) * y /\ x / Cx(&2) = inv(Cx(&2)) * x`] THEN
+    REPEAT STRIP_TAC THEN REPEAT(FIRST_ASSUM MATCH_MP_TAC ORELSE CONJ_TAC) THEN
+    ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`\x. x IN {Re o f | P (f:real^N->complex)}`; `s:real^N->bool`]
+        STONE_WEIERSTRASS_ALT) THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[EXISTS_IN_GSPEC; IMP_IMP; GSYM CONJ_ASSOC] THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[IMP_IMP; RIGHT_IMP_FORALL_THM; IN_ELIM_THM] THEN
+    REPEAT CONJ_TAC THENL
+     [X_GEN_TAC `c:real` THEN EXISTS_TAC `\x:real^N. Cx(c)` THEN
+      ASM_REWRITE_TAC[FUN_EQ_THM; o_THM; RE_CX];
+      MAP_EVERY X_GEN_TAC [`f:real^N->complex`; `g:real^N->complex`] THEN
+      DISCH_TAC THEN EXISTS_TAC `(\x. f x + g x):real^N->complex` THEN
+      ASM_SIMP_TAC[o_THM; RE_ADD; FUN_EQ_THM];
+      MAP_EVERY X_GEN_TAC [`f:real^N->complex`; `g:real^N->complex`] THEN
+      STRIP_TAC THEN
+      EXISTS_TAC `\x:real^N. Cx(Re(f x)) * Cx(Re(g x))` THEN
+      ASM_SIMP_TAC[FUN_EQ_THM; RE_CX; o_THM; RE_MUL_CX];
+      MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL  [`x:real^N`; `y:real^N`]) THEN
+      ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `f:real^N->complex` THEN
+      REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+      GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [COMPLEX_EQ] THEN
+      REWRITE_TAC[DE_MORGAN_THM] THEN STRIP_TAC THENL
+       [EXISTS_TAC `\x:real^N. Re(f x)` THEN ASM_REWRITE_TAC[o_DEF] THEN
+        CONJ_TAC THENL
+         [ALL_TAC; EXISTS_TAC `f:real^N->complex` THEN ASM_REWRITE_TAC[]];
+        EXISTS_TAC `\x:real^N. Im(f x)` THEN ASM_REWRITE_TAC[o_DEF] THEN
+        CONJ_TAC THENL
+         [ALL_TAC;
+          EXISTS_TAC `\x:real^N. Cx(Im(f x))` THEN ASM_SIMP_TAC[RE_CX]]] THEN
+      X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN REWRITE_TAC[GSYM o_DEF] THEN
+      MATCH_MP_TAC REAL_CONTINUOUS_CONTINUOUS_WITHIN_COMPOSE THEN
+      SIMP_TAC[REAL_CONTINUOUS_COMPLEX_COMPONENTS_AT;
+               REAL_CONTINUOUS_AT_WITHIN] THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN]];
+    DISCH_THEN(LABEL_TAC "*") THEN X_GEN_TAC `f:real^N->complex` THEN
+    DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    REMOVE_THEN "*"
+     (fun th -> MP_TAC(ISPEC `Re o (f:real^N->complex)` th) THEN
+                MP_TAC(ISPEC `Im o (f:real^N->complex)` th)) THEN
+    MATCH_MP_TAC(TAUT `(p1 /\ p2) /\ (q1 /\ q2 ==> r)
+                       ==> (p1 ==> q1) ==> (p2 ==> q2) ==> r`) THEN
+    CONJ_TAC THENL
+     [CONJ_TAC THEN X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+      MATCH_MP_TAC REAL_CONTINUOUS_CONTINUOUS_WITHIN_COMPOSE THEN
+      SIMP_TAC[REAL_CONTINUOUS_COMPLEX_COMPONENTS_AT;
+               REAL_CONTINUOUS_AT_WITHIN] THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN];
+      ALL_TAC] THEN
+    REWRITE_TAC[AND_FORALL_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
+    ASM_REWRITE_TAC[REAL_HALF; o_THM] THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `g:real^N->complex` STRIP_ASSUME_TAC)
+     (X_CHOOSE_THEN `h:real^N->complex` STRIP_ASSUME_TAC)) THEN
+    EXISTS_TAC `\x:real^N. Cx(Re(h x)) + ii * Cx(Re(g x))` THEN
+    ASM_SIMP_TAC[] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o LAND_CONV) [COMPLEX_EXPAND] THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `norm(x1 - x2) < e / &2 /\ norm(y1 - y2) < e / &2
+      ==> norm((x1 + y1) - (x2 + y2)) < e`) THEN
+    ASM_SIMP_TAC[GSYM CX_SUB; COMPLEX_NORM_CX; GSYM COMPLEX_SUB_LDISTRIB;
+                 COMPLEX_NORM_MUL; COMPLEX_NORM_II; REAL_MUL_LID]]);;
+
+let COMPLEX_STONE_WEIERSTRASS = prove
+ (`!P s. compact s /\
+         (!f. P f ==> f continuous_on s) /\
+         (!c. P (\x. c)) /\
+         (!f. P f ==> P(\x. cnj(f x))) /\
+         (!f g. P f /\ P g ==> P (\x. f x + g x)) /\
+         (!f g. P f /\ P g ==> P (\x. f x * g x)) /\
+         (!x y. x IN s /\ y IN s /\ ~(x = y) ==> ?f. P f /\ ~(f x = f y))
+         ==> !f:real^N->complex e.
+                f continuous_on s /\ &0 < e
+                ==> ?g. P g /\ !x. x IN s ==> norm(f x - g x) < e`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC COMPLEX_STONE_WEIERSTRASS_ALT THEN ASM_SIMP_TAC[] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `y:real^N`]) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Stone-Weierstrass for R^n -> R polynomials.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let real_polynomial_function_RULES,
+    real_polynomial_function_INDUCT,
+    real_polynomial_function_CASES = new_inductive_definition
+ `(!i. 1 <= i /\ i <= dimindex(:N)
+       ==> real_polynomial_function(\x:real^N. x$i)) /\
+  (!c. real_polynomial_function(\x:real^N. c)) /\
+  (!f g. real_polynomial_function f /\ real_polynomial_function g
+         ==> real_polynomial_function(\x:real^N. f x + g x)) /\
+  (!f g. real_polynomial_function f /\ real_polynomial_function g
+         ==> real_polynomial_function(\x:real^N. f x * g x))`;;
+
+let REAL_CONTINUOUS_REAL_POLYMONIAL_FUNCTION = prove
+ (`!f x:real^N.
+        real_polynomial_function f ==> f real_continuous at x`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC real_polynomial_function_INDUCT THEN
+  SIMP_TAC[REAL_CONTINUOUS_ADD; REAL_CONTINUOUS_MUL;
+           REAL_CONTINUOUS_CONST; REAL_CONTINUOUS_AT_COMPONENT]);;
+
+let STONE_WEIERSTRASS_REAL_POLYNOMIAL_FUNCTION = prove
+ (`!f:real^N->real s e.
+        compact s /\
+        (!x. x IN s ==> f real_continuous at x within s) /\
+        &0 < e
+        ==> ?g. real_polynomial_function g /\
+                !x. x IN s ==> abs(f x - g x) < e`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+        STONE_WEIERSTRASS) THEN
+  ASM_REWRITE_TAC[real_polynomial_function_RULES] THEN
+  SIMP_TAC[REAL_CONTINUOUS_REAL_POLYMONIAL_FUNCTION;
+           REAL_CONTINUOUS_AT_WITHIN] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [CART_EQ] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN EXISTS_TAC `\x:real^N. x$i` THEN
+  ASM_SIMP_TAC[real_polynomial_function_RULES]);;
+
+(* ------------------------------------------------------------------------- *)
+(*  Stone-Weierstrass for real^M->real^N polynomials.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let vector_polynomial_function = new_definition
+ `vector_polynomial_function (f:real^M->real^N) <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> real_polynomial_function(\x. f(x)$i)`;;
+
+let VECTOR_POLYNOMIAL_FUNCTION_CONST = prove
+ (`!c. vector_polynomial_function(\x. c)`,
+  SIMP_TAC[vector_polynomial_function; real_polynomial_function_RULES]);;
+
+let VECTOR_POLYNOMIAL_FUNCTION_ID = prove
+ (`vector_polynomial_function(\x. x)`,
+  SIMP_TAC[vector_polynomial_function; real_polynomial_function_RULES]);;
+
+let VECTOR_POLYNOMIAL_FUNCTION_COMPONENT = prove
+ (`!f:real^M->real^N i.
+        1 <= i /\ i <= dimindex(:N) /\ vector_polynomial_function f
+        ==> vector_polynomial_function(\x. lift(f x$i))`,
+  SIMP_TAC[vector_polynomial_function; FORALL_1; DIMINDEX_1; GSYM drop;
+           LIFT_DROP]);;
+
+let VECTOR_POLYNOMIAL_FUNCTION_ADD = prove
+ (`!f g:real^M->real^N.
+        vector_polynomial_function f /\ vector_polynomial_function g
+        ==> vector_polynomial_function (\x. f x + g x)`,
+
+  REWRITE_TAC[vector_polynomial_function] THEN
+  SIMP_TAC[VECTOR_ADD_COMPONENT; real_polynomial_function_RULES]);;
+
+let VECTOR_POLYNOMIAL_FUNCTION_MUL = prove
+ (`!f g:real^M->real^N.
+        vector_polynomial_function(lift o f) /\ vector_polynomial_function g
+        ==> vector_polynomial_function (\x. f x % g x)`,
+  REWRITE_TAC[vector_polynomial_function; o_DEF; VECTOR_MUL_COMPONENT] THEN
+  REWRITE_TAC[FORALL_1; DIMINDEX_1; GSYM drop; LIFT_DROP; ETA_AX] THEN
+  SIMP_TAC[real_polynomial_function_RULES]);;
+
+let VECTOR_POLYNOMIAL_FUNCTION_CMUL = prove
+ (`!f:real^M->real^N c.
+        vector_polynomial_function f
+        ==> vector_polynomial_function (\x. c % f x)`,
+  SIMP_TAC[VECTOR_POLYNOMIAL_FUNCTION_CONST; VECTOR_POLYNOMIAL_FUNCTION_MUL;
+           ETA_AX; o_DEF]);;
+
+let VECTOR_POLYNOMIAL_FUNCTION_NEG = prove
+ (`!f:real^M->real^N.
+        vector_polynomial_function f
+        ==> vector_polynomial_function (\x. --(f x))`,
+  REWRITE_TAC[VECTOR_ARITH `--x:real^N = --(&1) % x`] THEN
+  REWRITE_TAC[VECTOR_POLYNOMIAL_FUNCTION_CMUL]);;
+
+let VECTOR_POLYNOMIAL_FUNCTION_SUB = prove
+ (`!f g:real^M->real^N.
+        vector_polynomial_function f /\ vector_polynomial_function g
+        ==> vector_polynomial_function (\x. f x - g x)`,
+  SIMP_TAC[VECTOR_SUB; VECTOR_POLYNOMIAL_FUNCTION_ADD;
+           VECTOR_POLYNOMIAL_FUNCTION_NEG]);;
+
+let VECTOR_POLYNOMIAL_FUNCTION_VSUM = prove
+ (`!f:real^M->A->real^N s.
+        FINITE s /\ (!i. i IN s ==> vector_polynomial_function (\x. f x i))
+        ==> vector_polynomial_function (\x. vsum s (f x))`,
+  GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; FORALL_IN_INSERT; VECTOR_POLYNOMIAL_FUNCTION_CONST;
+           VECTOR_POLYNOMIAL_FUNCTION_ADD]);;
+
+let CONTINUOUS_VECTOR_POLYNOMIAL_FUNCTION = prove
+ (`!f:real^M->real^N x.
+        vector_polynomial_function f ==> f continuous at x`,
+  REWRITE_TAC[vector_polynomial_function; CONTINUOUS_COMPONENTWISE] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_CONTINUOUS_REAL_POLYMONIAL_FUNCTION THEN
+  ASM_SIMP_TAC[]);;
+
+let CONTINUOUS_ON_VECTOR_POLYNOMIAL_FUNCTION = prove
+ (`!f:real^M->real^N s.
+        vector_polynomial_function f ==> f continuous_on s`,
+  SIMP_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON;
+           CONTINUOUS_VECTOR_POLYNOMIAL_FUNCTION]);;
+
+let HAS_VECTOR_DERIVATIVE_VECTOR_POLYNOMIAL_FUNCTION = prove
+ (`!p:real^1->real^N.
+        vector_polynomial_function p
+        ==> ?p'. vector_polynomial_function p' /\
+                 !x. (p has_vector_derivative p'(x)) (at x)`,
+  let lemma = prove
+   (`!p:real^1->real.
+          real_polynomial_function p
+          ==> ?p'. real_polynomial_function p' /\
+                 !x. ((p o lift) has_real_derivative (p'(lift x))) (atreal x)`,
+    MATCH_MP_TAC
+     (derive_strong_induction(real_polynomial_function_RULES,
+                              real_polynomial_function_INDUCT)) THEN
+    REWRITE_TAC[DIMINDEX_1; FORALL_1; o_DEF; GSYM drop; LIFT_DROP] THEN
+    CONJ_TAC THENL
+     [EXISTS_TAC `\x:real^1. &1` THEN
+      REWRITE_TAC[real_polynomial_function_RULES; HAS_REAL_DERIVATIVE_ID];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [X_GEN_TAC `c:real` THEN EXISTS_TAC `\x:real^1. &0` THEN
+      REWRITE_TAC[real_polynomial_function_RULES; HAS_REAL_DERIVATIVE_CONST];
+      ALL_TAC] THEN
+    CONJ_TAC THEN
+    MAP_EVERY X_GEN_TAC [`f:real^1->real`; `g:real^1->real`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (CONJUNCTS_THEN2 ASSUME_TAC
+       (X_CHOOSE_THEN `f':real^1->real` STRIP_ASSUME_TAC))
+     (CONJUNCTS_THEN2 ASSUME_TAC
+       (X_CHOOSE_THEN `g':real^1->real` STRIP_ASSUME_TAC)))
+    THENL
+     [EXISTS_TAC `\x. (f':real^1->real) x + g' x`;
+      EXISTS_TAC `\x. (f:real^1->real) x * g' x + f' x * g x`] THEN
+    ASM_SIMP_TAC[real_polynomial_function_RULES; HAS_REAL_DERIVATIVE_ADD;
+                 HAS_REAL_DERIVATIVE_MUL_ATREAL]) in
+  GEN_TAC THEN REWRITE_TAC[vector_polynomial_function] THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `!i. 1 <= i /\ i <= dimindex(:N)
+        ==> ?q. real_polynomial_function q /\
+                (!x. ((\x. lift(((p x):real^N)$i)) has_vector_derivative
+                      lift(q x)) (at x))`
+  MP_TAC THENL
+   [X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP lemma) THEN
+    REWRITE_TAC[HAS_REAL_VECTOR_DERIVATIVE_AT] THEN
+    REWRITE_TAC[o_DEF; LIFT_DROP; FORALL_DROP];
+    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 `q:num->real^1->real` THEN DISCH_TAC THEN
+    EXISTS_TAC `(\x. lambda i. (q:num->real^1->real) i x):real^1->real^N` THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; ETA_AX] THEN
+    REWRITE_TAC[has_vector_derivative; has_derivative_at] THEN
+    ONCE_REWRITE_TAC[LIM_COMPONENTWISE] THEN X_GEN_TAC `x:real^1` THEN
+    SIMP_TAC[LINEAR_VMUL_DROP; LINEAR_ID] THEN X_GEN_TAC `i:num` THEN
+    STRIP_TAC THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `i:num`)) THEN
+    ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^1`) THEN
+    REWRITE_TAC[has_vector_derivative; has_derivative_at] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; VEC_COMPONENT; VECTOR_SUB_COMPONENT;
+                 VECTOR_ADD_COMPONENT; LAMBDA_BETA; REAL_TENDSTO] THEN
+    SIMP_TAC[DROP_ADD; DROP_VEC; LIFT_DROP; DROP_CMUL; DROP_SUB; o_DEF]]);;
+
+let STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION = prove
+ (`!f:real^M->real^N s e.
+        compact s /\ f continuous_on s /\ &0 < e
+        ==> ?g. vector_polynomial_function g /\
+                !x. x IN s ==> norm(f x - g x) < e`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+   [CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN]) THEN
+  REWRITE_TAC[CONTINUOUS_COMPONENTWISE] THEN
+  REWRITE_TAC[IMP_IMP; RIGHT_IMP_FORALL_THM] THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `!i. 1 <= i /\ i <= dimindex(:N)
+        ==> ?g. real_polynomial_function g /\
+                !x. x IN s ==> abs((f:real^M->real^N) x$i - g x) <
+                               e / &(dimindex(:N))`
+  MP_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC STONE_WEIERSTRASS_REAL_POLYNOMIAL_FUNCTION THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; DIMINDEX_GE_1; LE_1];
+    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 `g:num->real^M->real` THEN DISCH_TAC THEN
+    EXISTS_TAC `(\x. lambda i. g i x):real^M->real^N` THEN
+    ASM_SIMP_TAC[vector_polynomial_function; LAMBDA_BETA; ETA_AX] THEN
+    X_GEN_TAC `x:real^M` THEN DISCH_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_LET_TRANS) THEN
+    MATCH_MP_TAC SUM_BOUND_LT_GEN THEN
+    REWRITE_TAC[FINITE_NUMSEG; CARD_NUMSEG_1; NUMSEG_EMPTY; NOT_LT] THEN
+    ASM_SIMP_TAC[IN_NUMSEG; DIMINDEX_GE_1; LAMBDA_BETA;
+                 VECTOR_SUB_COMPONENT]]);;
+
+let STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION_SUBSPACE = prove
+ (`!f:real^M->real^N s e t.
+        compact s /\ f continuous_on s /\ &0 < e /\
+        subspace t /\ IMAGE f s SUBSET t
+        ==> ?g. vector_polynomial_function g /\ IMAGE g s SUBSET t /\
+                !x. x IN s ==> norm(f x - g x) < e`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ORTHONORMAL_BASIS_SUBSPACE) THEN
+  DISCH_THEN(X_CHOOSE_THEN `bas:real^N->bool` MP_TAC) THEN
+  ASM_CASES_TAC `FINITE(bas:real^N->bool)` THENL
+   [ALL_TAC; ASM_MESON_TAC[HAS_SIZE]] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [FINITE_INDEX_NUMSEG]) THEN
+  ABBREV_TAC `n = CARD(bas:real^N->bool)` THEN
+  REWRITE_TAC[INJECTIVE_ON_ALT; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `b:num->real^N` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC) THEN
+  ASM_SIMP_TAC[REWRITE_RULE[INJECTIVE_ON_ALT] HAS_SIZE_IMAGE_INJ_EQ] THEN
+  REWRITE_TAC[HAS_SIZE; FINITE_NUMSEG; CARD_NUMSEG_1] THEN
+  ASM_CASES_TAC `dim(t:real^N->bool) = n` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN STRIP_TAC THEN
+  MP_TAC(ISPEC `t:real^N->bool` DIM_SUBSET_UNIV) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_TAC THEN MP_TAC(ISPECL
+   [`(\x. lambda i. (f x:real^N) dot (b i)):real^M->real^N`;
+    `s:real^M->bool`; `e:real`]
+   STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ONCE_REWRITE_TAC[CONTINUOUS_ON_COMPONENTWISE_LIFT] THEN
+    SIMP_TAC[LAMBDA_BETA] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC CONTINUOUS_ON_LIFT_DOT2 THEN
+    ASM_REWRITE_TAC[CONTINUOUS_ON_CONST];
+    DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^N` STRIP_ASSUME_TAC)] THEN
+  EXISTS_TAC `(\x. vsum(1..n) (\i. (g x:real^N)$i % b i)):real^M->real^N` THEN
+  REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC VECTOR_POLYNOMIAL_FUNCTION_VSUM THEN
+    REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC VECTOR_POLYNOMIAL_FUNCTION_MUL THEN
+    REWRITE_TAC[VECTOR_POLYNOMIAL_FUNCTION_CONST; o_DEF] THEN
+    MATCH_MP_TAC VECTOR_POLYNOMIAL_FUNCTION_COMPONENT THEN
+    ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC;
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSPACE_VSUM THEN
+    ASM_SIMP_TAC[SUBSPACE_MUL; FINITE_NUMSEG];
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN
+    ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[DOT_SYM] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_LET_TRANS) THEN
+    SUBGOAL_THEN
+     `vsum(IMAGE b (1..n)) (\v. (v dot f x) % v) = (f:real^M->real^N) x`
+     (fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [SYM th])
+    THENL
+     [MATCH_MP_TAC ORTHONORMAL_BASIS_EXPAND THEN
+      ASM_REWRITE_TAC[FORALL_IN_IMAGE] THEN ASM SET_TAC[];
+      ASM_SIMP_TAC[REWRITE_RULE[INJECTIVE_ON_ALT] VSUM_IMAGE;
+                   FINITE_NUMSEG] THEN
+      REWRITE_TAC[GSYM VSUM_SUB_NUMSEG; o_DEF; GSYM VECTOR_SUB_RDISTRIB] THEN
+      REWRITE_TAC[NORM_LE; GSYM NORM_POW_2] THEN
+      W(MP_TAC o PART_MATCH (lhs o rand) NORM_VSUM_PYTHAGOREAN o
+        lhand o snd) THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[PAIRWISE_IMAGE]) THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[pairwise]) THEN
+      ASM_SIMP_TAC[pairwise; ORTHOGONAL_MUL; FINITE_NUMSEG] THEN
+      DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[NORM_MUL] THEN
+      REWRITE_TAC[NORM_POW_2] THEN GEN_REWRITE_TAC RAND_CONV [dot] THEN
+      SIMP_TAC[GSYM REAL_POW_2; VECTOR_SUB_COMPONENT; LAMBDA_BETA] THEN
+      MATCH_MP_TAC SUM_LE_INCLUDED THEN EXISTS_TAC `\n:num. n` THEN
+      REWRITE_TAC[FINITE_NUMSEG; REAL_LE_POW_2] THEN
+      ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> q /\ p /\ r`] THEN
+      REWRITE_TAC[UNWIND_THM2] THEN
+      ONCE_REWRITE_TAC[TAUT `p ==> q /\ r <=> p ==> q /\ (q ==> r)`] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_NUMSEG]) THEN
+      ASM_SIMP_TAC[LAMBDA_BETA; UNWIND_THM2; IN_NUMSEG] THEN
+      REWRITE_TAC[REAL_MUL_RID; REAL_POW2_ABS; REAL_LE_REFL] THEN
+      ASM_ARITH_TAC]]);;
+
+let STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION_AFFINE = prove
+ (`!f:real^M->real^N s e t.
+        compact s /\ f continuous_on s /\ &0 < e /\
+        affine t /\ IMAGE f s SUBSET t
+        ==> ?g. vector_polynomial_function g /\ IMAGE g s SUBSET t /\
+                !x. x IN s ==> norm(f x - g x) < e`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[SUBSET_EMPTY; IMAGE_EQ_EMPTY] THENL
+   [MESON_TAC[VECTOR_POLYNOMIAL_FUNCTION_CONST; NOT_IN_EMPTY];
+    STRIP_TAC] THEN
+  MP_TAC(ISPEC `t:real^N->bool` AFFINE_TRANSLATION_SUBSPACE) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `u:real^N->bool`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM SUBST_ALL_TAC THEN
+  MP_TAC(ISPECL
+   [`(\x. f x - a):real^M->real^N`; `s:real^M->bool`; `e:real`;
+   `u:real^N->bool`] STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION_SUBSPACE) THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST] THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `\x:real^N. x - a` o MATCH_MP IMAGE_SUBSET) THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; VECTOR_ADD_SUB; IMAGE_ID] THEN
+  DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(\x. g x + a):real^M->real^N` THEN
+  ASM_SIMP_TAC[VECTOR_POLYNOMIAL_FUNCTION_ADD;
+               VECTOR_POLYNOMIAL_FUNCTION_CONST;
+               VECTOR_ARITH `a - (b + c):real^N = a - c - b`] THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `\x:real^N. a + x` o MATCH_MP IMAGE_SUBSET) THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF; VECTOR_ADD_AC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* One application is to pick a smooth approximation to a path, or just pick *)
+(* a smooth path anyway in an open connected set.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let PATH_VECTOR_POLYNOMIAL_FUNCTION = prove
+ (`!g:real^1->real^N. vector_polynomial_function g ==> path g`,
+  SIMP_TAC[path; CONTINUOUS_ON_VECTOR_POLYNOMIAL_FUNCTION]);;
+
+let PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION = prove
+ (`!g:real^1->real^N e.
+        path g /\ &0 < e
+        ==> ?p. vector_polynomial_function p /\
+                pathstart p = pathstart g /\
+                pathfinish p = pathfinish g /\
+                !t. t IN interval[vec 0,vec 1] ==> norm(p t - g t) < e`,
+  REWRITE_TAC[path] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`g:real^1->real^N`; `interval[vec 0:real^1,vec 1]`; `e / &4`]
+        STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION) THEN
+  ASM_REWRITE_TAC[COMPACT_INTERVAL; REAL_ARITH `&0 < x / &4 <=> &0 < x`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `q:real^1->real^N` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\t. (q:real^1->real^N)(t) + (g(vec 0:real^1) - q(vec 0)) +
+                drop t % ((g(vec 1) - q(vec 1)) - (g(vec 0) - q(vec 0)))` THEN
+  REWRITE_TAC[pathstart; pathfinish; DROP_VEC] THEN REPEAT CONJ_TAC THENL
+   [SIMP_TAC[vector_polynomial_function; VECTOR_ADD_COMPONENT;
+             VECTOR_MUL_COMPONENT; VECTOR_SUB_COMPONENT] THEN
+    REPEAT STRIP_TAC THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[vector_polynomial_function]) THEN
+    MATCH_MP_TAC(el 2 (CONJUNCTS real_polynomial_function_RULES)) THEN
+    ASM_SIMP_TAC[real_polynomial_function_RULES; drop; DIMINDEX_1; ARITH];
+    VECTOR_ARITH_TAC;
+    VECTOR_ARITH_TAC;
+    REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[VECTOR_SUB_LDISTRIB] THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `norm(x - a) < e / &4 /\ norm b < e / &4 /\ norm c <= &1 * e / &4 /\
+        norm d <= &1 * e / &4
+      ==> norm((a + b + c - d) - x:real^N) < e`) THEN
+    ASM_SIMP_TAC[NORM_MUL; IN_INTERVAL_1; DROP_VEC; REAL_POS] THEN
+    CONJ_TAC THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; IN_INTERVAL_1; DROP_VEC; REAL_POS;
+                 REAL_LE_REFL; NORM_POS_LE] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1; DROP_VEC]) THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let CONNECTED_OPEN_VECTOR_POLYNOMIAL_CONNECTED = prove
+ (`!s:real^N->bool.
+        open s /\ connected s
+        ==> !x y. x IN s /\ y IN s
+                  ==> ?g. vector_polynomial_function g /\
+                          path_image g SUBSET s /\
+                          pathstart g = x /\
+                          pathfinish g = y`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `path_connected(s:real^N->bool)` MP_TAC THENL
+   [ASM_SIMP_TAC[CONNECTED_OPEN_PATH_CONNECTED];
+    REWRITE_TAC[path_connected]] THEN
+  DISCH_THEN(MP_TAC o SPECL [`x:real^N`; `y:real^N`]) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `p:real^1->real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `?e. &0 < e /\ !x. x IN path_image p ==> ball(x:real^N,e) SUBSET s`
+  STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `s = (:real^N)` THEN ASM_REWRITE_TAC[SUBSET_UNIV] THENL
+     [MESON_TAC[REAL_LT_01]; ALL_TAC] THEN
+    EXISTS_TAC `setdist(path_image p,(:real^N) DIFF s)` THEN CONJ_TAC THENL
+     [ASM_REWRITE_TAC[REAL_ARITH `&0 < x <=> &0 <= x /\ ~(x = &0)`] THEN
+      ASM_SIMP_TAC[SETDIST_POS_LE; SETDIST_EQ_0_COMPACT_CLOSED;
+                   COMPACT_PATH_IMAGE; GSYM OPEN_CLOSED] THEN
+      ASM_SIMP_TAC[PATH_IMAGE_NONEMPTY] THEN ASM SET_TAC[];
+      X_GEN_TAC `z:real^N` THEN DISCH_TAC THEN REWRITE_TAC[SUBSET] THEN
+      X_GEN_TAC `w:real^N` THEN REWRITE_TAC[IN_BALL; GSYM REAL_NOT_LE] THEN
+      MATCH_MP_TAC(SET_RULE
+       `(w IN (UNIV DIFF s) ==> p) ==> (~p ==> w IN s)`) THEN
+      ASM_SIMP_TAC[SETDIST_LE_DIST]];
+    MP_TAC(ISPECL [`p:real^1->real^N`; `e:real`]
+      PATH_APPROX_VECTOR_POLYNOMIAL_FUNCTION) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `q:real^1->real^N` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[path_image; FORALL_IN_IMAGE; SUBSET] THEN RULE_ASSUM_TAC
+     (REWRITE_RULE[SUBSET; path_image; FORALL_IN_IMAGE;IN_BALL; dist]) THEN
+    ASM_MESON_TAC[NORM_SUB]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Lipschitz property for real and vector polynomials.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let LIPSCHITZ_REAL_POLYNOMIAL_FUNCTION = prove
+ (`!f:real^N->real s.
+        real_polynomial_function f /\ bounded s
+        ==> ?B. &0 < B /\
+                !x y. x IN s /\ y IN s ==> abs(f x - f y) <= B * norm(x - y)`,
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN GEN_TAC THEN
+  ASM_CASES_TAC `bounded(s:real^N->bool)` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN MESON_TAC[REAL_LT_01]; ALL_TAC] THEN
+  MATCH_MP_TAC real_polynomial_function_INDUCT THEN REPEAT CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN
+    ASM_SIMP_TAC[REAL_MUL_LID; GSYM VECTOR_SUB_COMPONENT; COMPONENT_LE_NORM];
+    GEN_TAC THEN EXISTS_TAC `&1` THEN
+    SIMP_TAC[REAL_LT_01; REAL_SUB_REFL; REAL_ABS_NUM; REAL_MUL_LID;
+             NORM_POS_LE];
+    ALL_TAC; ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`f:real^N->real`; `g:real^N->real`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+    (X_CHOOSE_THEN `B1:real` STRIP_ASSUME_TAC)
+    (X_CHOOSE_THEN `B2:real` STRIP_ASSUME_TAC))
+  THENL
+   [EXISTS_TAC `B1 + B2:real` THEN ASM_SIMP_TAC[REAL_LT_ADD] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC(REAL_ARITH
+     `abs(f - f') <= B1 * n /\ abs(g - g') <= B2 * n
+      ==> abs((f + g) - (f' + g')) <= (B1 + B2) * n`) THEN
+    ASM_SIMP_TAC[];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [BOUNDED_POS]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `B1 * (abs(g(a:real^N)) + B2 * &2 * B) +
+                B2 * (abs(f a) + B1 * &2 * B)` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_LT_ADD THEN CONJ_TAC THEN MATCH_MP_TAC REAL_LT_MUL THEN
+      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(REAL_ARITH
+       `&0 < x ==> &0 < abs a + x`) THEN
+      MATCH_MP_TAC REAL_LT_MUL THEN ASM_REAL_ARITH_TAC;
+      REPEAT STRIP_TAC THEN REWRITE_TAC[] THEN MATCH_MP_TAC(REAL_ARITH
+       `abs((f - f') * g) <= a * n /\ abs((g - g') * f') <= b * n
+        ==> abs(f * g - f' * g') <= (a + b) * n`) THEN
+      ONCE_REWRITE_TAC[REAL_ARITH `(a * b) * c:real = (a * c) * b`] THEN
+      REWRITE_TAC[REAL_ABS_MUL] THEN
+      CONJ_TAC THEN MATCH_MP_TAC REAL_LE_MUL2 THEN
+      ASM_SIMP_TAC[REAL_ABS_POS] THEN MATCH_MP_TAC(REAL_ARITH
+       `abs(g x - g a) <= C * norm(x - a) /\
+        C * norm(x - a:real^N) <= C * B ==> abs(g x) <= abs(g a) + C * B`) THEN
+      ASM_SIMP_TAC[REAL_LE_LMUL_EQ] THEN MATCH_MP_TAC(NORM_ARITH
+       `norm x <= B /\ norm a <= B ==> norm(x - a:real^N) <= &2 * B`) THEN
+      ASM_SIMP_TAC[]]]);;
+
+let LIPSCHITZ_VECTOR_POLYNOMIAL_FUNCTION = prove
+ (`!f:real^M->real^N s.
+        vector_polynomial_function f /\ bounded s
+        ==> ?B. &0 < B /\
+                !x y. x IN s /\ y IN s ==> norm(f x - f y) <= B * norm(x - y)`,
+  REWRITE_TAC[vector_polynomial_function] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?b. !i. 1 <= i /\ i <= dimindex(:N)
+            ==> &0 < (b:real^N)$i /\
+                !x y. x IN s /\ y IN s
+                      ==> abs((f:real^M->real^N) x$i - f y$i) <=
+                          b$i * norm(x - y)`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM LAMBDA_SKOLEM] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC LIPSCHITZ_REAL_POLYNOMIAL_FUNCTION THEN
+    ASM_SIMP_TAC[LIPSCHITZ_REAL_POLYNOMIAL_FUNCTION];
+    EXISTS_TAC `&1 + sum(1..dimindex(:N)) (\i. (b:real^N)$i)` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC(REAL_ARITH `&0 <= x ==> &0 < &1 + x`) THEN
+      MATCH_MP_TAC SUM_POS_LE_NUMSEG THEN ASM_SIMP_TAC[REAL_LT_IMP_LE];
+      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
+      REWRITE_TAC[REAL_ADD_RDISTRIB; GSYM SUM_RMUL; REAL_MUL_LID] THEN
+      MATCH_MP_TAC(NORM_ARITH `x <= y ==> x <= norm(a:real^N) + y`) THEN
+      MATCH_MP_TAC SUM_LE_NUMSEG THEN
+      ASM_SIMP_TAC[VECTOR_SUB_COMPONENT]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Differentiability of real and vector polynomial functions.                *)
+(* ------------------------------------------------------------------------- *)
+
+let DIFFERENTIABLE_REAL_POLYNOMIAL_FUNCTION_AT = prove
+ (`!f:real^N->real a.
+        real_polynomial_function f ==> (lift o f) differentiable (at a)`,
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN GEN_TAC THEN
+  MATCH_MP_TAC real_polynomial_function_INDUCT THEN
+  REWRITE_TAC[o_DEF; LIFT_ADD; LIFT_CMUL] THEN
+  REWRITE_TAC[DIFFERENTIABLE_LIFT_COMPONENT; DIFFERENTIABLE_CONST] THEN
+  SIMP_TAC[DIFFERENTIABLE_ADD] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC DIFFERENTIABLE_MUL_AT THEN
+  ASM_REWRITE_TAC[o_DEF]);;
+
+let DIFFERENTIABLE_ON_REAL_POLYNOMIAL_FUNCTION = prove
+ (`!f:real^N->real s.
+        real_polynomial_function f ==> (lift o f) differentiable_on s`,
+  SIMP_TAC[DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON;
+           DIFFERENTIABLE_REAL_POLYNOMIAL_FUNCTION_AT]);;
+
+let DIFFERENTIABLE_VECTOR_POLYNOMIAL_FUNCTION = prove
+ (`!f:real^M->real^N a.
+        vector_polynomial_function f ==> f differentiable (at a)`,
+  REWRITE_TAC[vector_polynomial_function] THEN REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[DIFFERENTIABLE_COMPONENTWISE_AT] THEN
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+  MATCH_MP_TAC DIFFERENTIABLE_REAL_POLYNOMIAL_FUNCTION_AT THEN
+  ASM_SIMP_TAC[]);;
+
+let DIFFERENTIABLE_ON_VECTOR_POLYNOMIAL_FUNCTION = prove
+ (`!f:real^M->real^N s.
+        vector_polynomial_function f ==> f differentiable_on s`,
+  SIMP_TAC[DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON;
+           DIFFERENTIABLE_VECTOR_POLYNOMIAL_FUNCTION]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Specific properties of complex measurable functions.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let MEASURABLE_ON_COMPLEX_MUL = prove
+ (`!f g:real^N->complex s.
+         f measurable_on s /\ g measurable_on s
+         ==> (\x. f x * g x) measurable_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MEASURABLE_ON_COMBINE THEN
+  ASM_REWRITE_TAC[COMPLEX_VEC_0; COMPLEX_MUL_LZERO] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN
+  CONJ_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN
+  REWRITE_TAC[LINEAR_FSTCART; LINEAR_SNDCART]);;
+
+let MEASURABLE_ON_COMPLEX_INV = prove
+ (`!f:real^N->real^2.
+     f measurable_on (:real^N) /\ negligible {x | f x = Cx(&0)}
+     ==> (\x. inv(f x)) measurable_on (:real^N)`,
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[measurable_on; IN_UNIV; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`k:real^N->bool`; `g:num->real^N->complex`] THEN
+  STRIP_TAC THEN EXISTS_TAC `k UNION {x:real^N | f x = Cx(&0)}` THEN
+  ASM_SIMP_TAC[NEGLIGIBLE_UNION] THEN
+  SUBGOAL_THEN
+   `!n. ?h. h continuous_on (:real^N) /\
+            !x. x IN {x | g n x IN (:complex) DIFF ball(Cx(&0),inv(&n + &1))}
+                ==> (h:real^N->complex) x = inv(g n x)`
+
+  MP_TAC THENL
+   [X_GEN_TAC `n:num` THEN MATCH_MP_TAC TIETZE_UNBOUNDED THEN CONJ_TAC THENL
+     [REWRITE_TAC[SUBTOPOLOGY_UNIV; GSYM CLOSED_IN] THEN
+      MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE_UNIV THEN
+      REWRITE_TAC[GSYM OPEN_CLOSED; OPEN_BALL; ETA_AX] THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; OPEN_UNIV; IN_UNIV];
+      REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+      GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC CONTINUOUS_AT_WITHIN THEN
+      MATCH_MP_TAC CONTINUOUS_COMPLEX_INV_AT THEN CONJ_TAC THENL
+       [REWRITE_TAC[ETA_AX] THEN
+        ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; OPEN_UNIV; IN_UNIV];
+        RULE_ASSUM_TAC(REWRITE_RULE[IN_ELIM_THM; IN_UNIV; IN_DIFF]) THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [IN_BALL]) THEN
+        SIMP_TAC[CONTRAPOS_THM; DIST_REFL; REAL_LT_INV_EQ] THEN
+        REAL_ARITH_TAC]];
+    REWRITE_TAC[SKOLEM_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `h:num->real^N->complex` THEN
+    REWRITE_TAC[FORALL_AND_THM; IN_ELIM_THM; IN_DIFF; IN_UNION; IN_UNIV] THEN
+    REWRITE_TAC[IN_BALL; DE_MORGAN_THM; REAL_NOT_LT] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:real^N` THEN
+    STRIP_TAC THEN MATCH_MP_TAC LIM_TRANSFORM THEN
+    EXISTS_TAC `\n. inv((g:num->real^N->complex) n x)` THEN
+    ASM_SIMP_TAC[o_DEF; LIM_COMPLEX_INV] THEN
+    MATCH_MP_TAC LIM_EVENTUALLY THEN
+    REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+    SUBGOAL_THEN `&0 < norm((f:real^N->complex) x)` ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[COMPLEX_NORM_NZ]; ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN
+    ASM_REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+    DISCH_THEN(MP_TAC o SPEC `norm((f:real^N->complex) x) / &2`) THEN
+    ASM_REWRITE_TAC[REAL_HALF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `N1:num` (LABEL_TAC "*")) THEN
+    MP_TAC(SPEC `norm((f:real^N->complex) x) / &2` REAL_ARCH_INV) THEN
+    ASM_REWRITE_TAC[REAL_HALF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `N2:num` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `N1 + N2 + 1` THEN X_GEN_TAC `n:num` THEN STRIP_TAC THEN
+    REWRITE_TAC[VECTOR_SUB_EQ] THEN CONV_TAC SYM_CONV THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN
+    REWRITE_TAC[GSYM COMPLEX_VEC_0; DIST_0] THEN
+    REMOVE_THEN "*" (MP_TAC o SPEC `n:num`) THEN
+    ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (NORM_ARITH
+     `dist(g,f) < norm(f) / &2 ==> norm(f) / &2 <= norm g`)) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_LE_TRANS) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `x < y ==> z <= x ==> z <= y`)) THEN
+    MATCH_MP_TAC REAL_LE_INV2 THEN
+    ASM_REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; REAL_OF_NUM_LT] THEN
+    ASM_ARITH_TAC]);;
+
+let MEASURABLE_ON_COMPLEX_DIV = prove
+ (`!f g:real^N->complex s.
+        f measurable_on s /\ g measurable_on (:real^N) /\
+        negligible {x | g(x) = Cx(&0)}
+        ==> (\x. f(x) / g(x)) measurable_on s`,
+  let lemma = prove
+   (`!f g:real^N->complex.
+        f measurable_on (:real^N) /\ g measurable_on (:real^N) /\
+        negligible {x | g(x) = Cx(&0)}
+        ==> (\x. f(x) / g(x)) measurable_on (:real^N)`,
+    REPEAT STRIP_TAC THEN REWRITE_TAC[complex_div] THEN
+    ASM_SIMP_TAC[MEASURABLE_ON_COMPLEX_MUL; MEASURABLE_ON_COMPLEX_INV]) in
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM MEASURABLE_ON_UNIV] THEN
+  REWRITE_TAC[IN_UNIV; ETA_AX] THEN DISCH_THEN(MP_TAC o MATCH_MP lemma) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; complex_div; COMPLEX_VEC_0] THEN
+  GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[COMPLEX_MUL_LZERO]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Measurable real->real functions.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("real_measurable_on",(12,"right"));;
+
+let real_measurable_on = new_definition
+ `f real_measurable_on s <=>
+        (lift o f o drop) measurable_on (IMAGE lift s)`;;
+
+let real_lebesgue_measurable = new_definition
+ `real_lebesgue_measurable s <=>
+      (\x. if x IN s then &1 else &0) real_measurable_on (:real)`;;
+
+let REAL_MEASURABLE_ON_UNIV = prove
+ (`(\x.  if x IN s then f(x) else &0) real_measurable_on (:real) <=>
+   f real_measurable_on s`,
+  REWRITE_TAC[real_measurable_on; o_DEF; IMAGE_LIFT_UNIV] THEN
+  SIMP_TAC[COND_RAND; LIFT_NUM; MEASURABLE_ON_UNIV; GSYM IN_IMAGE_LIFT_DROP]);;
+
+let REAL_LEBESGUE_MEASURABLE = prove
+ (`!s. real_lebesgue_measurable s <=> lebesgue_measurable (IMAGE lift s)`,
+  REWRITE_TAC[real_lebesgue_measurable; lebesgue_measurable; COND_RAND;
+    COND_RAND; real_measurable_on; indicator; IMAGE_LIFT_UNIV; o_DEF] THEN
+  REWRITE_TAC[LIFT_NUM; IN_IMAGE_LIFT_DROP]);;
+
+let REAL_MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE = prove
+ (`!f g s.
+        f real_measurable_on s /\
+        g real_integrable_on s /\
+        (!x. x IN s ==> abs(f x) <= g x)
+        ==> f real_integrable_on s`,
+  REWRITE_TAC[real_measurable_on; REAL_INTEGRABLE_ON] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE THEN
+  EXISTS_TAC `lift o g o drop` THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP; NORM_LIFT]);;
+
+let REAL_MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_ABSOLUTELY_INTEGRABLE = prove
+ (`!f g s.
+        f real_measurable_on s /\
+        g real_integrable_on s /\
+        (!x. x IN s ==> abs(f x) <= g x)
+        ==> f absolutely_real_integrable_on s`,
+  REWRITE_TAC[real_measurable_on; REAL_INTEGRABLE_ON;
+              ABSOLUTELY_REAL_INTEGRABLE_ON] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_ABSOLUTELY_INTEGRABLE THEN
+  EXISTS_TAC `lift o g o drop` THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP; NORM_LIFT]);;
+
+let INTEGRABLE_SUBINTERVALS_IMP_REAL_MEASURABLE = prove
+ (`!f. (!a b. f real_integrable_on real_interval[a,b])
+       ==> f real_measurable_on (:real)`,
+  REWRITE_TAC[real_measurable_on; REAL_INTEGRABLE_ON; IMAGE_LIFT_UNIV] THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC INTEGRABLE_SUBINTERVALS_IMP_MEASURABLE THEN
+  ASM_REWRITE_TAC[FORALL_LIFT]);;
+
+let INTEGRABLE_IMP_REAL_MEASURABLE = prove
+ (`!f:real->real s.
+        f real_integrable_on s ==> f real_measurable_on s`,
+  REWRITE_TAC[real_measurable_on; REAL_INTEGRABLE_ON] THEN
+  REWRITE_TAC[INTEGRABLE_IMP_MEASURABLE]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_REAL_MEASURABLE = prove
+ (`!f s. f absolutely_real_integrable_on s <=>
+         f real_measurable_on s /\ (\x. abs(f x)) real_integrable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[absolutely_real_integrable_on] THEN
+  MATCH_MP_TAC(TAUT `(a ==> b) /\ (b /\ c ==> a) ==> (a /\ c <=> b /\ c)`) THEN
+  REWRITE_TAC[INTEGRABLE_IMP_REAL_MEASURABLE] THEN STRIP_TAC THEN
+  MATCH_MP_TAC REAL_MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_INTEGRABLE THEN
+  EXISTS_TAC `\x. abs((f:real->real) x)` THEN ASM_REWRITE_TAC[REAL_LE_REFL]);;
+
+let REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS = prove
+ (`!f g. f real_measurable_on (:real) /\ g real_continuous_on (:real)
+         ==> (g o f) real_measurable_on (:real)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_CONTINUOUS_ON; real_measurable_on] THEN
+  REWRITE_TAC[IMAGE_LIFT_UNIV] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_COMPOSE_CONTINUOUS) THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS_0 = prove
+ (`!f:real->real g:real->real s.
+        f real_measurable_on s /\ g real_continuous_on (:real) /\ g(&0) = &0
+        ==> (g o f) real_measurable_on s`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_MEASURABLE_ON_UNIV] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> c ==> a /\ b ==> d`] THEN
+  DISCH_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; o_DEF] THEN ASM_MESON_TAC[]);;
+
+let REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS_OPEN_INTERVAL = prove
+ (`!f:real->real g:real->real a b.
+        f real_measurable_on (:real) /\
+        (!x. f(x) IN real_interval(a,b)) /\
+        g real_continuous_on real_interval(a,b)
+        ==> (g o f) real_measurable_on (:real)`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `lift o g o drop`; `lift a`; `lift b`]
+        MEASURABLE_ON_COMPOSE_CONTINUOUS_OPEN_INTERVAL) THEN
+  REWRITE_TAC[real_measurable_on; REAL_CONTINUOUS_ON] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP; IMAGE_LIFT_UNIV; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[GSYM FORALL_DROP] THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[INTERVAL_REAL_INTERVAL; LIFT_DROP] THEN ASM SET_TAC[]);;
+
+let REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET = prove
+ (`!f:real->real g:real->real s.
+        real_closed s /\
+        f real_measurable_on (:real) /\
+        (!x. f(x) IN s) /\
+        g real_continuous_on s
+        ==> (g o f) real_measurable_on (:real)`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `lift o g o drop`; `IMAGE lift s`]
+        MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET) THEN
+  REWRITE_TAC[real_measurable_on; REAL_CONTINUOUS_ON; REAL_CLOSED] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP; IMAGE_LIFT_UNIV; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[GSYM FORALL_DROP] THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[INTERVAL_REAL_INTERVAL; LIFT_DROP] THEN ASM SET_TAC[]);;
+
+let REAL_MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET_0 = prove
+ (`!f:real->real g:real->real s t.
+        real_closed s /\
+        f real_measurable_on t /\
+        (!x. f(x) IN s) /\
+        g real_continuous_on s /\
+        &0 IN s /\ g(&0) = &0
+        ==> (g o f) real_measurable_on t`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `lift o g o drop`;
+                 `IMAGE lift s`; `IMAGE lift t`]
+        MEASURABLE_ON_COMPOSE_CONTINUOUS_CLOSED_SET_0) THEN
+  REWRITE_TAC[real_measurable_on; REAL_CONTINUOUS_ON; REAL_CLOSED] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP; IMAGE_LIFT_UNIV; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[GSYM FORALL_DROP] THEN
+  ASM_SIMP_TAC[FUN_IN_IMAGE; LIFT_DROP; GSYM LIFT_NUM]);;
+
+let CONTINUOUS_IMP_REAL_MEASURABLE_ON = prove
+ (`!f. f real_continuous_on (:real) ==> f real_measurable_on (:real)`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON; real_measurable_on] THEN
+  REWRITE_TAC[CONTINUOUS_IMP_MEASURABLE_ON; IMAGE_LIFT_UNIV]);;
+
+let REAL_MEASURABLE_ON_CONST = prove
+ (`!k:real. (\x. k) real_measurable_on (:real)`,
+  SIMP_TAC[real_measurable_on; o_DEF; MEASURABLE_ON_CONST; IMAGE_LIFT_UNIV]);;
+
+let REAL_MEASURABLE_ON_0 = prove
+ (`!s. (\x. &0) real_measurable_on s`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_MEASURABLE_ON_UNIV] THEN
+  REWRITE_TAC[REAL_MEASURABLE_ON_CONST; COND_ID]);;
+
+let REAL_MEASURABLE_ON_LMUL = prove
+ (`!c f s. f real_measurable_on s ==> (\x. c * f x) real_measurable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_measurable_on] THEN
+  DISCH_THEN(MP_TAC o SPEC `c:real` o MATCH_MP MEASURABLE_ON_CMUL) THEN
+  REWRITE_TAC[o_DEF; LIFT_CMUL; LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_RMUL = prove
+ (`!c f s. f real_measurable_on s ==> (\x. f x * c) real_measurable_on s`,
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  REWRITE_TAC[REAL_MEASURABLE_ON_LMUL]);;
+
+let REAL_MEASURABLE_ON_NEG = prove
+ (`!f s. f real_measurable_on s ==> (\x. --(f x)) real_measurable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_measurable_on] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_NEG) THEN
+  REWRITE_TAC[o_DEF; LIFT_NEG; LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_NEG_EQ = prove
+ (`!f s. (\x. --(f x)) real_measurable_on s <=> f real_measurable_on s`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REAL_MEASURABLE_ON_NEG) THEN
+  REWRITE_TAC[REAL_NEG_NEG; ETA_AX]);;
+
+let REAL_MEASURABLE_ON_ABS = prove
+ (`!f s. f real_measurable_on s ==> (\x. abs(f x)) real_measurable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_measurable_on] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_NORM) THEN
+  REWRITE_TAC[o_DEF; NORM_LIFT]);;
+
+let REAL_MEASURABLE_ON_ADD = prove
+ (`!f g s. f real_measurable_on s /\ g real_measurable_on s
+           ==> (\x. f x + g x) real_measurable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_measurable_on] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_ADD) THEN
+  REWRITE_TAC[o_DEF; LIFT_ADD; LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_SUB = prove
+ (`!f g s.
+        f real_measurable_on s /\ g real_measurable_on s
+        ==> (\x. f x - g x) real_measurable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_measurable_on] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_SUB) THEN
+  REWRITE_TAC[o_DEF; LIFT_SUB; LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_MAX = prove
+ (`!f g s.
+        f real_measurable_on s /\ g real_measurable_on s
+        ==> (\x. max (f x) (g x)) real_measurable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_measurable_on] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_MAX) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  SIMP_TAC[FUN_EQ_THM; o_THM; CART_EQ; LAMBDA_BETA; DIMINDEX_1; FORALL_1] THEN
+  REWRITE_TAC[GSYM drop; LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_MIN = prove
+ (`!f g s.
+        f real_measurable_on s /\ g real_measurable_on s
+        ==> (\x. min (f x) (g x)) real_measurable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_measurable_on] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_MIN) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  SIMP_TAC[FUN_EQ_THM; o_THM; CART_EQ; LAMBDA_BETA; DIMINDEX_1; FORALL_1] THEN
+  REWRITE_TAC[GSYM drop; LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_MUL = prove
+ (`!f g s.
+        f real_measurable_on s /\ g real_measurable_on s
+        ==> (\x. f x * g x) real_measurable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_measurable_on] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_DROP_MUL) THEN
+  REWRITE_TAC[o_DEF; LIFT_CMUL; LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_SPIKE_SET = prove
+ (`!f:real->real s t.
+        real_negligible (s DIFF t UNION t DIFF s)
+        ==> f real_measurable_on s
+            ==> f real_measurable_on t`,
+  REWRITE_TAC[real_measurable_on; real_negligible] THEN
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  MATCH_MP_TAC MEASURABLE_ON_SPIKE_SET THEN POP_ASSUM MP_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] NEGLIGIBLE_SUBSET) THEN
+  SET_TAC[]);;
+
+let REAL_MEASURABLE_ON_RESTRICT = prove
+ (`!f s. f real_measurable_on (:real) /\
+         real_lebesgue_measurable s
+         ==> (\x. if x IN s then f(x) else &0) real_measurable_on (:real)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[real_measurable_on; REAL_LEBESGUE_MEASURABLE;
+              IMAGE_LIFT_UNIV] THEN
+  REWRITE_TAC[o_DEF; COND_RAND; LIFT_NUM; GSYM IN_IMAGE_LIFT_DROP] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP MEASURABLE_ON_RESTRICT) THEN
+  REWRITE_TAC[]);;
+
+let REAL_MEASURABLE_ON_LIMIT = prove
+ (`!f g s k.
+        (!n. (f n) real_measurable_on s) /\
+        real_negligible k /\
+        (!x. x IN s DIFF k ==> ((\n. f n x) ---> g x) sequentially)
+        ==> g real_measurable_on s`,
+  REWRITE_TAC[real_measurable_on; real_negligible; TENDSTO_REAL] THEN
+  REWRITE_TAC[o_DEF] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC MEASURABLE_ON_LIMIT THEN MAP_EVERY EXISTS_TAC
+   [`\n:num. lift o f n o drop`; `IMAGE lift k`] THEN
+  ASM_REWRITE_TAC[] THEN
+  SIMP_TAC[LIFT_DROP; SET_RULE `(!x. drop(lift x) = x)
+            ==> IMAGE lift s DIFF IMAGE lift t = IMAGE lift (s DIFF t)`] THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; o_DEF; LIFT_DROP]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_BOUNDED_MEASURABLE_PRODUCT = prove
+ (`!f g s. f real_measurable_on s /\ real_bounded (IMAGE f s) /\
+           g absolutely_real_integrable_on s
+
+           ==> (\x. f x * g x) absolutely_real_integrable_on s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REAL_BOUNDED_POS]) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; FORALL_IN_IMAGE] THEN
+  X_GEN_TAC `B:real` THEN STRIP_TAC THEN MATCH_MP_TAC
+   REAL_MEASURABLE_BOUNDED_BY_INTEGRABLE_IMP_ABSOLUTELY_INTEGRABLE THEN
+  EXISTS_TAC `\x. B * abs((g:real->real) x)` THEN
+  ASM_SIMP_TAC[REAL_MEASURABLE_ON_MUL; INTEGRABLE_IMP_REAL_MEASURABLE;
+    ABSOLUTELY_REAL_INTEGRABLE_IMP_INTEGRABLE; REAL_INTEGRABLE_LMUL;
+    ABSOLUTELY_REAL_INTEGRABLE_ABS] THEN
+  ASM_SIMP_TAC[REAL_ABS_MUL; REAL_LE_RMUL; REAL_ABS_POS]);;
+
+let REAL_COMPLEX_MEASURABLE_ON = prove
+ (`!f s. f real_measurable_on s <=>
+         (Cx o f o drop) measurable_on (IMAGE lift s)`,
+  ONCE_REWRITE_TAC[GSYM REAL_MEASURABLE_ON_UNIV;
+                   GSYM MEASURABLE_ON_UNIV] THEN
+  ONCE_REWRITE_TAC[MEASURABLE_ON_COMPONENTWISE] THEN
+  REWRITE_TAC[FORALL_2; DIMINDEX_2; GSYM RE_DEF; GSYM IM_DEF] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_measurable_on; IMAGE_LIFT_UNIV] THEN
+  REWRITE_TAC[o_DEF; IN_IMAGE_LIFT_DROP] THEN
+  REWRITE_TAC[COND_RAND; COND_RATOR; LIFT_NUM; COMPLEX_VEC_0] THEN
+  REWRITE_TAC[RE_CX; IM_CX; COND_ID; MEASURABLE_ON_CONST; LIFT_NUM]);;
+
+let REAL_MEASURABLE_ON_INV = prove
+ (`!f. f real_measurable_on (:real) /\ real_negligible {x | f x = &0}
+       ==> (\x. inv(f x)) real_measurable_on (:real)`,
+  GEN_TAC THEN REWRITE_TAC[REAL_COMPLEX_MEASURABLE_ON] THEN
+  REWRITE_TAC[o_DEF; CX_INV; IMAGE_LIFT_UNIV] THEN STRIP_TAC THEN
+  MATCH_MP_TAC MEASURABLE_ON_COMPLEX_INV THEN ASM_REWRITE_TAC[CX_INJ] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [real_negligible]) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[IN_ELIM_THM; LIFT_DROP] THEN MESON_TAC[LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_DIV = prove
+ (`!f g. f real_measurable_on s /\ g real_measurable_on (:real) /\
+         real_negligible {x | g(x) = &0}
+         ==> (\x. f(x) / g(x)) real_measurable_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_COMPLEX_MEASURABLE_ON] THEN
+  REWRITE_TAC[o_DEF; CX_DIV; IMAGE_LIFT_UNIV] THEN STRIP_TAC THEN
+  MATCH_MP_TAC MEASURABLE_ON_COMPLEX_DIV THEN ASM_REWRITE_TAC[CX_INJ] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [real_negligible]) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[IN_ELIM_THM; LIFT_DROP] THEN MESON_TAC[LIFT_DROP]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Properties of real Lebesgue measurable sets.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_MEASURABLE_IMP_REAL_LEBESGUE_MEASURABLE = prove
+ (`!s. real_measurable s ==> real_lebesgue_measurable s`,
+  REWRITE_TAC[REAL_LEBESGUE_MEASURABLE; REAL_MEASURABLE_MEASURABLE;
+              MEASURABLE_IMP_LEBESGUE_MEASURABLE]);;
+
+let REAL_LEBESGUE_MEASURABLE_EMPTY = prove
+ (`real_lebesgue_measurable {}`,
+  REWRITE_TAC[REAL_LEBESGUE_MEASURABLE; IMAGE_CLAUSES;
+              LEBESGUE_MEASURABLE_EMPTY]);;
+
+let REAL_LEBESGUE_MEASURABLE_UNIV = prove
+ (`real_lebesgue_measurable (:real)`,
+  REWRITE_TAC[REAL_LEBESGUE_MEASURABLE; IMAGE_LIFT_UNIV;
+              LEBESGUE_MEASURABLE_UNIV]);;
+
+let REAL_LEBESGUE_MEASURABLE_COMPACT = prove
+ (`!s. real_compact s ==> real_lebesgue_measurable s`,
+  SIMP_TAC[REAL_MEASURABLE_IMP_REAL_LEBESGUE_MEASURABLE;
+           REAL_MEASURABLE_COMPACT]);;
+
+let REAL_LEBESGUE_MEASURABLE_INTERVAL = prove
+ (`(!a b. real_lebesgue_measurable(real_interval[a,b])) /\
+   (!a b. real_lebesgue_measurable(real_interval(a,b)))`,
+  SIMP_TAC[REAL_MEASURABLE_IMP_REAL_LEBESGUE_MEASURABLE;
+           REAL_MEASURABLE_REAL_INTERVAL]);;
+
+let REAL_LEBESGUE_MEASURABLE_INTER = prove
+ (`!s t. real_lebesgue_measurable s /\ real_lebesgue_measurable t
+         ==> real_lebesgue_measurable(s INTER t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_LEBESGUE_MEASURABLE] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LEBESGUE_MEASURABLE_INTER) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN MP_TAC LIFT_DROP THEN SET_TAC[]);;
+
+let REAL_LEBESGUE_MEASURABLE_UNION = prove
+ (`!s t:real->bool.
+        real_lebesgue_measurable s /\ real_lebesgue_measurable t
+        ==> real_lebesgue_measurable(s UNION t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_LEBESGUE_MEASURABLE] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LEBESGUE_MEASURABLE_UNION) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN MP_TAC LIFT_DROP THEN SET_TAC[]);;
+
+let REAL_LEBESGUE_MEASURABLE_COMPL = prove
+ (`!s. real_lebesgue_measurable((:real) DIFF s) <=>
+       real_lebesgue_measurable s`,
+  GEN_TAC THEN REWRITE_TAC[REAL_LEBESGUE_MEASURABLE] THEN
+  GEN_REWRITE_TAC (RAND_CONV) [GSYM LEBESGUE_MEASURABLE_COMPL] THEN
+  AP_TERM_TAC THEN MP_TAC LIFT_DROP THEN SET_TAC[]);;
+
+let REAL_LEBESGUE_MEASURABLE_DIFF = prove
+ (`!s t:real->bool.
+        real_lebesgue_measurable s /\ real_lebesgue_measurable t
+        ==> real_lebesgue_measurable(s DIFF t)`,
+  ONCE_REWRITE_TAC[SET_RULE `s DIFF t = s INTER (UNIV DIFF t)`] THEN
+  SIMP_TAC[REAL_LEBESGUE_MEASURABLE_COMPL; REAL_LEBESGUE_MEASURABLE_INTER]);;
+
+let REAL_LEBESGUE_MEASURABLE_ON_SUBINTERVALS = prove
+ (`!s. real_lebesgue_measurable s <=>
+       !a b. real_lebesgue_measurable(s INTER real_interval[a,b])`,
+  GEN_TAC THEN REWRITE_TAC[REAL_LEBESGUE_MEASURABLE] THEN
+  GEN_REWRITE_TAC LAND_CONV [LEBESGUE_MEASURABLE_ON_SUBINTERVALS] THEN
+  REWRITE_TAC[FORALL_DROP; GSYM IMAGE_DROP_INTERVAL] THEN
+  REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN AP_TERM_TAC THEN
+  MP_TAC LIFT_DROP THEN SET_TAC[]);;
+
+let REAL_LEBESGUE_MEASURABLE_CLOSED = prove
+ (`!s. real_closed s ==> real_lebesgue_measurable s`,
+  REWRITE_TAC[REAL_LEBESGUE_MEASURABLE; REAL_CLOSED;
+              LEBESGUE_MEASURABLE_CLOSED]);;
+
+let REAL_LEBESGUE_MEASURABLE_OPEN = prove
+ (`!s. real_open s ==> real_lebesgue_measurable s`,
+  REWRITE_TAC[REAL_LEBESGUE_MEASURABLE; REAL_OPEN;
+              LEBESGUE_MEASURABLE_OPEN]);;
+
+let REAL_LEBESGUE_MEASURABLE_UNIONS = prove
+ (`!f. FINITE f /\ (!s. s IN f ==> real_lebesgue_measurable s)
+       ==> real_lebesgue_measurable (UNIONS f)`,
+  REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[UNIONS_0; UNIONS_INSERT; REAL_LEBESGUE_MEASURABLE_EMPTY] THEN
+  REWRITE_TAC[IN_INSERT] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_LEBESGUE_MEASURABLE_UNION THEN ASM_SIMP_TAC[]);;
+
+let REAL_LEBESGUE_MEASURABLE_COUNTABLE_UNIONS_EXPLICIT = prove
+ (`!s:num->real->bool.
+        (!n. real_lebesgue_measurable(s n))
+        ==> real_lebesgue_measurable(UNIONS {s n | n IN (:num)})`,
+  GEN_TAC THEN REWRITE_TAC[REAL_LEBESGUE_MEASURABLE] THEN DISCH_THEN(MP_TAC o
+    MATCH_MP LEBESGUE_MEASURABLE_COUNTABLE_UNIONS_EXPLICIT) THEN
+  REWRITE_TAC[IMAGE_UNIONS; SIMPLE_IMAGE] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN SET_TAC[]);;
+
+let REAL_LEBESGUE_MEASURABLE_COUNTABLE_UNIONS = prove
+ (`!f:(real->bool)->bool.
+        COUNTABLE f /\ (!s. s IN f ==> real_lebesgue_measurable s)
+        ==> real_lebesgue_measurable (UNIONS f)`,
+  GEN_TAC THEN ASM_CASES_TAC `f:(real->bool)->bool = {}` THEN
+  ASM_REWRITE_TAC[UNIONS_0; REAL_LEBESGUE_MEASURABLE_EMPTY] THEN STRIP_TAC THEN
+  MP_TAC(ISPEC `f:(real->bool)->bool` COUNTABLE_AS_IMAGE) THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  ONCE_REWRITE_TAC[GSYM SIMPLE_IMAGE] THEN
+  MATCH_MP_TAC REAL_LEBESGUE_MEASURABLE_COUNTABLE_UNIONS_EXPLICIT THEN
+  GEN_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[IN_IMAGE; IN_UNIV] THEN MESON_TAC[]);;
+
+let REAL_LEBESGUE_MEASURABLE_COUNTABLE_INTERS = prove
+ (`!f:(real->bool)->bool.
+        COUNTABLE f /\ (!s. s IN f ==> real_lebesgue_measurable s)
+        ==> real_lebesgue_measurable (INTERS f)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[INTERS_UNIONS; REAL_LEBESGUE_MEASURABLE_COMPL] THEN
+  MATCH_MP_TAC REAL_LEBESGUE_MEASURABLE_COUNTABLE_UNIONS THEN
+  ASM_SIMP_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE; COUNTABLE_IMAGE;
+               REAL_LEBESGUE_MEASURABLE_COMPL]);;
+
+let REAL_LEBESGUE_MEASURABLE_COUNTABLE_INTERS_EXPLICIT = prove
+ (`!s:num->real->bool.
+        (!n. real_lebesgue_measurable(s n))
+        ==> real_lebesgue_measurable(INTERS {s n | n IN (:num)})`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC REAL_LEBESGUE_MEASURABLE_COUNTABLE_INTERS THEN
+  ASM_SIMP_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE; COUNTABLE_IMAGE; NUM_COUNTABLE]);;
+
+let REAL_LEBESGUE_MEASURABLE_INTERS = prove
+ (`!f:(real->bool)->bool.
+        FINITE f /\ (!s. s IN f ==> real_lebesgue_measurable s)
+        ==> real_lebesgue_measurable (INTERS f)`,
+  SIMP_TAC[REAL_LEBESGUE_MEASURABLE_COUNTABLE_INTERS; FINITE_IMP_COUNTABLE]);;
+
+let REAL_LEBESGUE_MEASURABLE_IFF_MEASURABLE = prove
+ (`!s. real_bounded s ==> (real_lebesgue_measurable s <=> real_measurable s)`,
+  REWRITE_TAC[REAL_BOUNDED; REAL_LEBESGUE_MEASURABLE;
+              REAL_MEASURABLE_MEASURABLE] THEN
+  REWRITE_TAC[LEBESGUE_MEASURABLE_IFF_MEASURABLE]);;
+
+let REAL_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET = prove
+ (`!f s t. s SUBSET t /\ f real_measurable_on t /\
+           real_lebesgue_measurable s
+           ==> f real_measurable_on s`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[GSYM REAL_MEASURABLE_ON_UNIV] THEN
+  REWRITE_TAC[IN_UNIV] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REAL_MEASURABLE_ON_RESTRICT) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN ASM SET_TAC[]);;
+
+let REAL_MEASURABLE_ON_MEASURABLE_SUBSET = prove
+ (`!f s t. s SUBSET t /\ f real_measurable_on t /\ real_measurable s
+           ==> f real_measurable_on s`,
+  MESON_TAC[REAL_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET;
+            REAL_MEASURABLE_IMP_REAL_LEBESGUE_MEASURABLE]);;
+
+let REAL_CONTINUOUS_IMP_REAL_MEASURABLE_ON_CLOSED_SUBSET = prove
+ (`!f s. f real_continuous_on s /\ real_closed s ==> f real_measurable_on s`,
+  REWRITE_TAC[REAL_CONTINUOUS_ON; REAL_CLOSED; real_measurable_on] THEN
+  REWRITE_TAC[CONTINUOUS_IMP_MEASURABLE_ON_CLOSED_SUBSET]);;
+
+let REAL_MEASURABLE_ON_CASES = prove
+ (`!P f g s.
+        real_lebesgue_measurable {x | P x} /\
+        f real_measurable_on s /\ g real_measurable_on s
+        ==> (\x. if P x then f x else g x) real_measurable_on s`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_MEASURABLE_ON_UNIV] THEN
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x. (if x IN s then if P x then f x else g x else &0) =
+        (if x IN {x | P x} then if x IN s then f x else &0 else &0) +
+        (if x IN (:real) DIFF {x | P x}
+         then if x IN s then g x else &0 else &0)`
+   (fun th -> REWRITE_TAC[th])
+  THENL
+   [GEN_TAC THEN REWRITE_TAC[IN_UNIV; IN_ELIM_THM; IN_DIFF] THEN
+    MESON_TAC[REAL_ADD_LID; REAL_ADD_RID];
+    MATCH_MP_TAC REAL_MEASURABLE_ON_ADD THEN
+    CONJ_TAC THEN MATCH_MP_TAC REAL_MEASURABLE_ON_RESTRICT THEN
+    ASM_REWRITE_TAC[REAL_LEBESGUE_MEASURABLE_COMPL]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Various common equivalent forms of function measurability.                *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_LT = prove
+ (`!f. f real_measurable_on (:real) <=>
+        !a. real_lebesgue_measurable {x | f(x) < a}`,
+  REWRITE_TAC[real_measurable_on; REAL_LEBESGUE_MEASURABLE; IMAGE_LIFT_UNIV;
+   MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LT] THEN
+  REWRITE_TAC[DIMINDEX_1; FORALL_1; GSYM drop; o_DEF; LIFT_DROP] THEN
+  GEN_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN AP_TERM_TAC THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN MESON_TAC[LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_LE = prove
+ (`!f. f real_measurable_on (:real) <=>
+        !a. real_lebesgue_measurable {x | f(x) <= a}`,
+  REWRITE_TAC[real_measurable_on; REAL_LEBESGUE_MEASURABLE; IMAGE_LIFT_UNIV;
+   MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_LE] THEN
+  REWRITE_TAC[DIMINDEX_1; FORALL_1; GSYM drop; o_DEF; LIFT_DROP] THEN
+  GEN_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN AP_TERM_TAC THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN MESON_TAC[LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_GT = prove
+ (`!f. f real_measurable_on (:real) <=>
+        !a. real_lebesgue_measurable {x | f(x) > a}`,
+  REWRITE_TAC[real_measurable_on; REAL_LEBESGUE_MEASURABLE; IMAGE_LIFT_UNIV;
+   MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GT] THEN
+  REWRITE_TAC[DIMINDEX_1; FORALL_1; GSYM drop; o_DEF; LIFT_DROP] THEN
+  GEN_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN AP_TERM_TAC THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN MESON_TAC[LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_GE = prove
+ (`!f. f real_measurable_on (:real) <=>
+        !a. real_lebesgue_measurable {x | f(x) >= a}`,
+  REWRITE_TAC[real_measurable_on; REAL_LEBESGUE_MEASURABLE; IMAGE_LIFT_UNIV;
+   MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_COMPONENT_GE] THEN
+  REWRITE_TAC[DIMINDEX_1; FORALL_1; GSYM drop; o_DEF; LIFT_DROP] THEN
+  GEN_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN AP_TERM_TAC THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN MESON_TAC[LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_PREIMAGE_OPEN_INTERVAL = prove
+ (`!f. f real_measurable_on (:real) <=>
+       !a b. real_lebesgue_measurable {x | f(x) IN real_interval(a,b)}`,
+  REWRITE_TAC[real_measurable_on; REAL_LEBESGUE_MEASURABLE; IMAGE_LIFT_UNIV;
+              MEASURABLE_ON_PREIMAGE_OPEN_INTERVAL; FORALL_DROP] THEN
+  GEN_TAC THEN REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN AP_TERM_TAC THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[IN_ELIM_THM; o_DEF; GSYM IMAGE_DROP_INTERVAL; LIFT_DROP;
+              FORALL_DROP; IN_IMAGE] THEN MESON_TAC[LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_PREIMAGE_CLOSED_INTERVAL = prove
+ (`!f. f real_measurable_on (:real) <=>
+       !a b. real_lebesgue_measurable {x | f(x) IN real_interval[a,b]}`,
+  REWRITE_TAC[real_measurable_on; REAL_LEBESGUE_MEASURABLE; IMAGE_LIFT_UNIV;
+              MEASURABLE_ON_PREIMAGE_CLOSED_INTERVAL; FORALL_DROP] THEN
+  GEN_TAC THEN REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN AP_TERM_TAC THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[IN_ELIM_THM; o_DEF; GSYM IMAGE_DROP_INTERVAL; LIFT_DROP;
+              FORALL_DROP; IN_IMAGE] THEN MESON_TAC[LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_PREIMAGE_OPEN = prove
+ (`!f. f real_measurable_on (:real) <=>
+       !t. real_open t ==> real_lebesgue_measurable {x | f(x) IN t}`,
+  REWRITE_TAC[real_measurable_on; REAL_LEBESGUE_MEASURABLE; IMAGE_LIFT_UNIV;
+              MEASURABLE_ON_PREIMAGE_OPEN; REAL_OPEN] THEN
+  GEN_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+   [X_GEN_TAC `t:real->bool` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE lift t`) THEN
+    ASM_REWRITE_TAC[];
+    X_GEN_TAC `t:real^1->bool` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE drop t`) THEN
+    ASM_REWRITE_TAC[IMAGE_LIFT_DROP; GSYM IMAGE_o]] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THENL
+   [CONV_TAC SYM_CONV; ALL_TAC] THEN
+  MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[IN_IMAGE; o_DEF; IN_ELIM_THM] THEN MESON_TAC[LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_PREIMAGE_CLOSED = prove
+ (`!f. f real_measurable_on (:real) <=>
+       !t. real_closed t ==> real_lebesgue_measurable {x | f(x) IN t}`,
+  REWRITE_TAC[real_measurable_on; REAL_LEBESGUE_MEASURABLE; IMAGE_LIFT_UNIV;
+              MEASURABLE_ON_PREIMAGE_CLOSED; REAL_CLOSED] THEN
+  GEN_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+   [X_GEN_TAC `t:real->bool` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE lift t`) THEN
+    ASM_REWRITE_TAC[];
+    X_GEN_TAC `t:real^1->bool` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `IMAGE drop t`) THEN
+    ASM_REWRITE_TAC[IMAGE_LIFT_DROP; GSYM IMAGE_o]] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THENL
+   [CONV_TAC SYM_CONV; ALL_TAC] THEN
+  MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[IN_IMAGE; o_DEF; IN_ELIM_THM] THEN MESON_TAC[LIFT_DROP]);;
+
+let REAL_MEASURABLE_ON_SIMPLE_FUNCTION_LIMIT = prove
+ (`!f. f real_measurable_on (:real) <=>
+       ?g. (!n. (g n) real_measurable_on (:real)) /\
+           (!n. FINITE(IMAGE (g n) (:real))) /\
+           (!x. ((\n. g n x) ---> f x) sequentially)`,
+  GEN_TAC THEN REWRITE_TAC[real_measurable_on; IMAGE_LIFT_UNIV] THEN
+  GEN_REWRITE_TAC LAND_CONV [MEASURABLE_ON_SIMPLE_FUNCTION_LIMIT] THEN
+  EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `g:num->real^1->real^1` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\n:num. drop o g n o lift` THEN
+    REWRITE_TAC[TENDSTO_REAL] THEN REPEAT CONJ_TAC THENL
+     [ASM_REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX];
+      GEN_TAC THEN REWRITE_TAC[IMAGE_o; IMAGE_LIFT_UNIV] THEN
+      MATCH_MP_TAC FINITE_IMAGE THEN ASM_REWRITE_TAC[];
+      X_GEN_TAC `x:real` THEN REWRITE_TAC[TENDSTO_REAL] THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `lift x`) THEN
+      REWRITE_TAC[o_DEF; LIFT_DROP]];
+    DISCH_THEN(X_CHOOSE_THEN `g:num->real->real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\n:num. lift o g n o drop` THEN REPEAT CONJ_TAC THENL
+     [ASM_REWRITE_TAC[];
+      GEN_TAC THEN REWRITE_TAC[IMAGE_o; IMAGE_DROP_UNIV] THEN
+      MATCH_MP_TAC FINITE_IMAGE THEN ASM_REWRITE_TAC[];
+      X_GEN_TAC `x:real^1` THEN FIRST_X_ASSUM(MP_TAC o SPEC `drop x`) THEN
+      REWRITE_TAC[TENDSTO_REAL; o_DEF; LIFT_DROP]]]);;
+
+let REAL_LEBESGUE_MEASURABLE_PREIMAGE_OPEN = prove
+ (`!f t. f real_measurable_on (:real) /\ real_open t
+         ==> real_lebesgue_measurable {x | f(x) IN t}`,
+  SIMP_TAC[REAL_MEASURABLE_ON_PREIMAGE_OPEN]);;
+
+let REAL_LEBESGUE_MEASURABLE_PREIMAGE_CLOSED = prove
+ (`!f t. f real_measurable_on (:real) /\ real_closed t
+         ==> real_lebesgue_measurable {x | f(x) IN t}`,
+  SIMP_TAC[REAL_MEASURABLE_ON_PREIMAGE_CLOSED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Continuity of measure within a halfspace w.r.t. to the boundary.          *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_CONTINUOUS_MEASURE_IN_HALFSPACE_LE = prove
+ (`!(s:real^N->bool) a i.
+        measurable s /\ 1 <= i /\ i <= dimindex(:N)
+        ==> (\a. measure(s INTER {x | x$i <= a})) real_continuous atreal a`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS1] THEN
+  REWRITE_TAC[continuous_atreal; o_THM] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `?u v:real^N. abs(measure(s INTER interval[u,v]) - measure s) < e / &2 /\
+                 ~(interval(u,v) = {}) /\ u$i < a /\ a < v$i`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPECL [`s:real^N->bool`; `e / &2`] MEASURE_LIMIT) THEN
+    ASM_REWRITE_TAC[REAL_HALF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPEC `ball(vec 0:real^N,B)` BOUNDED_SUBSET_CLOSED_INTERVAL) THEN
+    REWRITE_TAC[BOUNDED_BALL; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`u:real^N`; `v:real^N`] THEN DISCH_TAC THEN
+    EXISTS_TAC `(lambda j. min (a - &1) ((u:real^N)$j)):real^N` THEN
+    EXISTS_TAC `(lambda j. max (a + &1) ((v:real^N)$j)):real^N` THEN
+    CONJ_TAC THENL
+     [FIRST_X_ASSUM MATCH_MP_TAC THEN FIRST_X_ASSUM
+       (MATCH_MP_TAC o MATCH_MP(REWRITE_RULE[IMP_CONJ] SUBSET_TRANS)) THEN
+      SIMP_TAC[SUBSET_INTERVAL; LAMBDA_BETA] THEN REAL_ARITH_TAC;
+      ASM_SIMP_TAC[INTERVAL_NE_EMPTY; LAMBDA_BETA] THEN REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`indicator(s:real^N->bool)`; `u:real^N`; `v:real^N`; `u:real^N`;
+    `(lambda j. if j = i then min ((v:real^N)$i) a else v$j):real^N`;
+    `e / &2`]
+      INDEFINITE_INTEGRAL_CONTINUOUS) THEN
+  ASM_REWRITE_TAC[REAL_HALF] THEN ANTS_TAC THENL
+   [ONCE_REWRITE_TAC[GSYM INTEGRABLE_RESTRICT_UNIV] THEN
+    REWRITE_TAC[indicator; MESON[]
+     `(if P then if Q then x else y else y) =
+      (if P /\ Q then x else y)`] THEN
+    REWRITE_TAC[GSYM IN_INTER; GSYM MEASURABLE_INTEGRABLE] THEN
+    ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_INTERVAL] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+    ASM_SIMP_TAC[IN_INTERVAL; LAMBDA_BETA; REAL_LE_REFL; REAL_LT_IMP_LE] THEN
+    X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `j:num`) THEN ASM_REWRITE_TAC[] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `min d (min (a - (u:real^N)$i) ((v:real^N)$i - a))` THEN
+  ASM_REWRITE_TAC[REAL_LT_MIN; REAL_SUB_LT] THEN
+  X_GEN_TAC `b:real` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`u:real^N`;
+   `(lambda j. if j = i then min ((v:real^N)$i) b else v$j):real^N`]) THEN
+  REWRITE_TAC[dist] THEN ANTS_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+    ASM_SIMP_TAC[IN_INTERVAL; LAMBDA_BETA; REAL_LE_REFL; REAL_LT_IMP_LE] THEN
+    ASM_SIMP_TAC[VECTOR_SUB_REFL; NORM_0; REAL_LT_IMP_LE] THEN CONJ_TAC THENL
+     [X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `j:num`) THEN ASM_REWRITE_TAC[] THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+      ASM_SIMP_TAC[NORM_LE_SQUARE; dot; REAL_LT_IMP_LE] THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+       `sum(1..dimindex(:N)) (\j. if j = i then d pow 2 else &0)` THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC SUM_LE_NUMSEG THEN X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+        ASM_SIMP_TAC[LAMBDA_BETA; VECTOR_SUB_COMPONENT] THEN
+        COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+        REWRITE_TAC[GSYM REAL_POW_2; GSYM REAL_LE_SQUARE_ABS] THEN
+        ASM_REAL_ARITH_TAC;
+        ASM_REWRITE_TAC[SUM_DELTA; IN_NUMSEG; REAL_LE_REFL]]];
+    SUBGOAL_THEN
+     `!b. integral
+           (interval[u:real^N,
+                     (lambda j. if j = i then min (v$i) b else (v:real^N)$j)])
+           (indicator s) =
+          lift(measure(s INTER interval[u,v] INTER {x | x$i <= b}))`
+     (fun th -> REWRITE_TAC[th])
+    THENL
+     [GEN_TAC THEN
+      ASM_SIMP_TAC[MEASURE_INTEGRAL; MEASURABLE_INTER_HALFSPACE_LE;
+                   MEASURABLE_INTER; MEASURABLE_INTERVAL; LIFT_DROP] THEN
+      ONCE_REWRITE_TAC[GSYM INTEGRAL_RESTRICT_UNIV] THEN
+      AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN GEN_TAC THEN
+      ASM_SIMP_TAC[INTERVAL_SPLIT; indicator] THEN
+      REWRITE_TAC[IN_INTER] THEN MESON_TAC[];
+      REWRITE_TAC[GSYM LIFT_SUB; NORM_LIFT] THEN
+      SUBGOAL_THEN
+       `!b. measure(s INTER {x:real^N | x$i <= b}) =
+            measure((s INTER interval[u,v]) INTER {x | x$i <= b}) +
+            measure((s DIFF interval[u,v]) INTER {x | x$i <= b})`
+       (fun th -> REWRITE_TAC[th])
+      THENL
+       [GEN_TAC THEN CONV_TAC SYM_CONV THEN
+        MATCH_MP_TAC MEASURE_NEGLIGIBLE_UNION_EQ THEN
+        ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_INTER_HALFSPACE_LE;
+                     MEASURABLE_INTERVAL; MEASURABLE_DIFF] THEN
+        CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+        MATCH_MP_TAC(MESON[NEGLIGIBLE_EMPTY] `s = {} ==> negligible s`) THEN
+        SET_TAC[];
+        REWRITE_TAC[GSYM INTER_ASSOC] THEN MATCH_MP_TAC(REAL_ARITH
+         `abs(nub - nua) < e / &2
+          ==> abs(mub - mua) < e / &2
+              ==> abs((mub + nub) - (mua + nua)) < e`) THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+         `y < e ==> x <= y ==> x < e`)) THEN
+        SUBGOAL_THEN
+         `abs(measure(s INTER interval [u,v]) - measure s) =
+          measure(s DIFF interval[u:real^N,v])`
+        SUBST1_TAC THENL
+         [MATCH_MP_TAC(REAL_ARITH
+           `x + z = y /\ &0 <= z ==> abs(x - y) = z`) THEN
+          ASM_SIMP_TAC[MEASURE_POS_LE; MEASURABLE_DIFF;
+                       MEASURABLE_INTERVAL] THEN
+          MATCH_MP_TAC MEASURE_NEGLIGIBLE_UNION_EQ THEN
+          ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_DIFF;
+                       MEASURABLE_INTERVAL] THEN
+          CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+          MATCH_MP_TAC(MESON[NEGLIGIBLE_EMPTY] `s = {} ==> negligible s`) THEN
+          SET_TAC[];
+          MATCH_MP_TAC(REAL_ARITH
+           `&0 <= x /\ x <= a /\ &0 <= y /\ y <= a ==> abs(x - y) <= a`) THEN
+          ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_INTER_HALFSPACE_LE;
+            MEASURABLE_INTERVAL; MEASURABLE_DIFF; MEASURE_POS_LE] THEN
+          CONJ_TAC THEN MATCH_MP_TAC MEASURE_SUBSET THEN
+          ASM_SIMP_TAC[MEASURABLE_INTER; MEASURABLE_INTER_HALFSPACE_LE;
+            MEASURABLE_INTERVAL; MEASURABLE_DIFF; MEASURE_POS_LE] THEN
+          SET_TAC[]]]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Second mean value theorem and monotone integrability.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_SECOND_MEAN_VALUE_THEOREM_FULL = prove
+ (`!f g a b.
+        ~(real_interval[a,b] = {}) /\
+        f real_integrable_on real_interval[a,b] /\
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> g x <= g y)
+        ==> ?c. c IN real_interval[a,b] /\
+                ((\x. g x * f x) has_real_integral
+                 (g(a) * real_integral (real_interval[a,c]) f +
+                  g(b) * real_integral (real_interval[c,b]) f))
+                (real_interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `(g:real->real) o drop`;
+                 `lift a`; `lift b`]
+    SECOND_MEAN_VALUE_THEOREM_FULL) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IMAGE_EQ_EMPTY] THEN
+  ASM_REWRITE_TAC[GSYM REAL_INTEGRABLE_ON] THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[HAS_REAL_INTEGRAL; IMAGE_LIFT_REAL_INTERVAL] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN
+  REWRITE_TAC[o_DEF; LIFT_CMUL; LIFT_ADD] THEN AP_TERM_TAC THEN
+  BINOP_TAC THEN AP_TERM_TAC THEN ONCE_REWRITE_TAC[GSYM DROP_EQ] THEN
+  REWRITE_TAC[LIFT_DROP] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) REAL_INTEGRAL o rand o snd) THEN
+  REWRITE_TAC[o_DEF] THEN ANTS_TAC THEN SIMP_TAC[IMAGE_LIFT_REAL_INTERVAL] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        REAL_INTEGRABLE_ON_SUBINTERVAL)) THEN
+  REWRITE_TAC[SUBSET_REAL_INTERVAL] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_REAL_INTERVAL; REAL_INTERVAL_EQ_EMPTY]) THEN
+  ASM_REAL_ARITH_TAC);;
+
+let REAL_SECOND_MEAN_VALUE_THEOREM = prove
+ (`!f g a b.
+        ~(real_interval[a,b] = {}) /\
+        f real_integrable_on real_interval[a,b] /\
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> g x <= g y)
+        ==> ?c. c IN real_interval[a,b] /\
+                real_integral (real_interval[a,b]) (\x. g x * f x) =
+                 g(a) * real_integral (real_interval[a,c]) f +
+                 g(b) * real_integral (real_interval[c,b]) f`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REAL_SECOND_MEAN_VALUE_THEOREM_FULL) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real` THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP REAL_INTEGRAL_UNIQUE) THEN
+  REWRITE_TAC[]);;
+
+let REAL_SECOND_MEAN_VALUE_THEOREM_GEN_FULL = prove
+ (`!f g a b u v.
+        ~(real_interval[a,b] = {}) /\
+        f real_integrable_on real_interval[a,b] /\
+        (!x. x IN real_interval(a,b) ==> u <= g x /\ g x <= v) /\
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> g x <= g y)
+        ==> ?c. c IN real_interval[a,b] /\
+                ((\x. g x * f x) has_real_integral
+                 (u * real_integral (real_interval[a,c]) f +
+                  v * real_integral (real_interval[c,b]) f))
+                (real_interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `(g:real->real) o drop`;
+                 `lift a`; `lift b`; `u:real`; `v:real`]
+    SECOND_MEAN_VALUE_THEOREM_GEN_FULL) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IMAGE_EQ_EMPTY] THEN
+  ASM_REWRITE_TAC[GSYM REAL_INTEGRABLE_ON] THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[HAS_REAL_INTEGRAL; IMAGE_LIFT_REAL_INTERVAL] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN
+  REWRITE_TAC[o_DEF; LIFT_CMUL; LIFT_ADD] THEN AP_TERM_TAC THEN
+  BINOP_TAC THEN AP_TERM_TAC THEN ONCE_REWRITE_TAC[GSYM DROP_EQ] THEN
+  REWRITE_TAC[LIFT_DROP] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) REAL_INTEGRAL o rand o snd) THEN
+  REWRITE_TAC[o_DEF] THEN ANTS_TAC THEN SIMP_TAC[IMAGE_LIFT_REAL_INTERVAL] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        REAL_INTEGRABLE_ON_SUBINTERVAL)) THEN
+  REWRITE_TAC[SUBSET_REAL_INTERVAL] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_REAL_INTERVAL; REAL_INTERVAL_EQ_EMPTY]) THEN
+  ASM_REAL_ARITH_TAC);;
+
+let REAL_SECOND_MEAN_VALUE_THEOREM_GEN = prove
+ (`!f g a b u v.
+        ~(real_interval[a,b] = {}) /\
+        f real_integrable_on real_interval[a,b] /\
+        (!x. x IN real_interval(a,b) ==> u <= g x /\ g x <= v) /\
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> g x <= g y)
+        ==> ?c. c IN real_interval[a,b] /\
+                real_integral (real_interval[a,b]) (\x. g x * f x) =
+                 u * real_integral (real_interval[a,c]) f +
+                 v * real_integral (real_interval[c,b]) f`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REAL_SECOND_MEAN_VALUE_THEOREM_GEN_FULL) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real` THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP REAL_INTEGRAL_UNIQUE) THEN
+  REWRITE_TAC[]);;
+
+let REAL_SECOND_MEAN_VALUE_THEOREM_BONNET_FULL = prove
+ (`!f g a b.
+        ~(real_interval[a,b] = {}) /\
+        f real_integrable_on real_interval[a,b] /\
+        (!x. x IN real_interval[a,b] ==> &0 <= g x) /\
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> g x <= g y)
+        ==> ?c. c IN real_interval[a,b] /\
+                ((\x. g x * f x) has_real_integral
+                 (g(b) * real_integral (real_interval[c,b]) f))
+                (real_interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `(g:real->real) o drop`;
+                 `lift a`; `lift b`]
+    SECOND_MEAN_VALUE_THEOREM_BONNET_FULL) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IMAGE_EQ_EMPTY] THEN
+  ASM_REWRITE_TAC[GSYM REAL_INTEGRABLE_ON] THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[HAS_REAL_INTEGRAL; IMAGE_LIFT_REAL_INTERVAL] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN
+  REWRITE_TAC[o_DEF; LIFT_CMUL; LIFT_ADD] THEN AP_TERM_TAC THEN
+  AP_TERM_TAC THEN ONCE_REWRITE_TAC[GSYM DROP_EQ] THEN
+  REWRITE_TAC[LIFT_DROP] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) REAL_INTEGRAL o rand o snd) THEN
+  REWRITE_TAC[o_DEF] THEN ANTS_TAC THEN SIMP_TAC[IMAGE_LIFT_REAL_INTERVAL] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        REAL_INTEGRABLE_ON_SUBINTERVAL)) THEN
+  REWRITE_TAC[SUBSET_REAL_INTERVAL] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_REAL_INTERVAL; REAL_INTERVAL_EQ_EMPTY]) THEN
+  ASM_REAL_ARITH_TAC);;
+
+let REAL_SECOND_MEAN_VALUE_THEOREM_BONNET = prove
+ (`!f g a b.
+        ~(real_interval[a,b] = {}) /\
+        f real_integrable_on real_interval[a,b] /\
+        (!x. x IN real_interval[a,b] ==> &0 <= g x) /\
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> g x <= g y)
+        ==> ?c. c IN real_interval[a,b] /\
+                real_integral (real_interval[a,b]) (\x. g x * f x) =
+                g(b) * real_integral (real_interval[c,b]) f`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REAL_SECOND_MEAN_VALUE_THEOREM_BONNET_FULL) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real` THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP REAL_INTEGRAL_UNIQUE) THEN
+  REWRITE_TAC[]);;
+
+let REAL_INTEGRABLE_INCREASING_PRODUCT = prove
+ (`!f g a b.
+        f real_integrable_on real_interval[a,b] /\
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> g(x) <= g(y))
+        ==> (\x. g(x) * f(x)) real_integrable_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `(g:real->real) o drop`;
+                 `lift a`; `lift b`]
+    INTEGRABLE_INCREASING_PRODUCT) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL;
+                  GSYM REAL_INTEGRABLE_ON] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[o_DEF; LIFT_DROP; REAL_INTEGRABLE_ON; LIFT_CMUL]);;
+
+let REAL_INTEGRABLE_INCREASING_PRODUCT_UNIV = prove
+ (`!f g B.
+        f real_integrable_on (:real) /\
+        (!x y. x <= y ==> g x <= g y) /\
+        (!x. abs(g x) <= B)
+         ==> (\x. g x * f x) real_integrable_on (:real)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `(g:real->real) o drop`; `B:real`]
+    INTEGRABLE_INCREASING_PRODUCT_UNIV) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_UNIV;
+                  GSYM REAL_INTEGRABLE_ON] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[o_DEF; LIFT_DROP; REAL_INTEGRABLE_ON; LIFT_CMUL]);;
+
+let REAL_INTEGRABLE_INCREASING = prove
+ (`!f a b.
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> f(x) <= f(y))
+        ==> f real_integrable_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `lift a`; `lift b`]
+    INTEGRABLE_INCREASING_1) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL;
+                  GSYM REAL_INTEGRABLE_ON] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[o_DEF; LIFT_DROP; REAL_INTEGRABLE_ON; LIFT_CMUL]);;
+
+let REAL_INTEGRABLE_DECREASING_PRODUCT = prove
+ (`!f g a b.
+        f real_integrable_on real_interval[a,b] /\
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> g(y) <= g(x))
+        ==> (\x. g(x) * f(x)) real_integrable_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `(g:real->real) o drop`;
+                 `lift a`; `lift b`]
+    INTEGRABLE_DECREASING_PRODUCT) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL;
+                  GSYM REAL_INTEGRABLE_ON] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[o_DEF; LIFT_DROP; REAL_INTEGRABLE_ON; LIFT_CMUL]);;
+
+let REAL_INTEGRABLE_DECREASING_PRODUCT_UNIV = prove
+ (`!f g B.
+        f real_integrable_on (:real) /\
+        (!x y. x <= y ==> g y <= g x) /\
+        (!x. abs(g x) <= B)
+         ==> (\x. g x * f x) real_integrable_on (:real)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `(g:real->real) o drop`; `B:real`]
+    INTEGRABLE_DECREASING_PRODUCT_UNIV) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_UNIV;
+                  GSYM REAL_INTEGRABLE_ON] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[o_DEF; LIFT_DROP; REAL_INTEGRABLE_ON; LIFT_CMUL]);;
+
+let REAL_INTEGRABLE_DECREASING = prove
+ (`!f a b.
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> f(y) <= f(x))
+        ==> f real_integrable_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `lift a`; `lift b`]
+    INTEGRABLE_DECREASING_1) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL;
+                  GSYM REAL_INTEGRABLE_ON] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[o_DEF; LIFT_DROP; REAL_INTEGRABLE_ON; LIFT_CMUL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Measurability and absolute integrability of monotone functions.           *)
+(* ------------------------------------------------------------------------- *)
+
+let REAL_MEASURABLE_ON_INCREASING_UNIV = prove
+ (`!f. (!x y. x <= y ==> f x <= f y) ==> f real_measurable_on (:real)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[REAL_MEASURABLE_ON_PREIMAGE_OPEN_HALFSPACE_LE] THEN
+  X_GEN_TAC `y:real` THEN
+  REPEAT_TCL STRIP_THM_THEN ASSUME_TAC
+   (SET_RULE `{x | (f:real->real) x <= y} = {} \/
+              {x | (f:real->real) x <= y} = UNIV \/
+              ?a b. f a <= y /\ ~(f b <= y)`) THEN
+  ASM_REWRITE_TAC[REAL_LEBESGUE_MEASURABLE_EMPTY;
+                  REAL_LEBESGUE_MEASURABLE_UNIV] THEN
+  MP_TAC(ISPEC `{x | (f:real->real) x <= y}` SUP) THEN
+  REWRITE_TAC[IN_ELIM_THM; EXTENSION; NOT_IN_EMPTY] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[REAL_LE_TOTAL; REAL_LE_TRANS]; ALL_TAC] THEN
+  ABBREV_TAC `s = sup {x | (f:real->real) x <= y}` THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+    `(!x. (f:real->real) x <= y <=> x < s) \/
+     (!x. (f:real->real) x <= y <=> x <= s)`
+  STRIP_ASSUME_TAC THENL
+   [ASM_CASES_TAC `(f:real->real) s <= y` THEN
+    ASM_MESON_TAC[REAL_LE_TRANS; REAL_NOT_LE; REAL_LE_ANTISYM; REAL_LE_TOTAL];
+    ASM_SIMP_TAC[REAL_OPEN_HALFSPACE_LT; REAL_LEBESGUE_MEASURABLE_OPEN];
+    ASM_SIMP_TAC[REAL_CLOSED_HALFSPACE_LE; REAL_LEBESGUE_MEASURABLE_CLOSED]]);;
+
+let REAL_MEASURABLE_ON_INCREASING = prove
+ (`!f a b. (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+                  ==> f x <= f y)
+           ==> f real_measurable_on real_interval[a,b]`,
+  REWRITE_TAC[IN_REAL_INTERVAL] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `real_interval[a,b] = {}` THENL
+   [ONCE_REWRITE_TAC[GSYM REAL_MEASURABLE_ON_UNIV] THEN
+    ASM_REWRITE_TAC[NOT_IN_EMPTY; REAL_MEASURABLE_ON_0];
+    RULE_ASSUM_TAC(REWRITE_RULE[REAL_INTERVAL_EQ_EMPTY; REAL_NOT_LT])] THEN
+  ABBREV_TAC `g = \x. if x < a then f(a)
+                      else if b < x then f(b)
+                      else (f:real->real) x` THEN
+  SUBGOAL_THEN `g real_measurable_on real_interval[a,b]` MP_TAC THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[GSYM REAL_MEASURABLE_ON_UNIV] THEN EXPAND_TAC "g" THEN
+    SIMP_TAC[IN_REAL_INTERVAL; GSYM REAL_NOT_LT]] THEN
+  MATCH_MP_TAC REAL_MEASURABLE_ON_LEBESGUE_MEASURABLE_SUBSET THEN
+  EXISTS_TAC `(:real)` THEN
+  REWRITE_TAC[SUBSET_UNIV; REAL_LEBESGUE_MEASURABLE_INTERVAL] THEN
+  MATCH_MP_TAC REAL_MEASURABLE_ON_INCREASING_UNIV THEN EXPAND_TAC "g" THEN
+  ASM_MESON_TAC[REAL_LT_LE; REAL_LE_TRANS; REAL_LE_TOTAL; REAL_LE_ANTISYM;
+                REAL_NOT_LT; REAL_LT_IMP_LE; REAL_LE_REFL]);;
+
+let REAL_MEASURABLE_ON_DECREASING_UNIV = prove
+ (`!f. (!x y. x <= y ==> f y <= f x) ==> f real_measurable_on (:real)`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC I [GSYM REAL_MEASURABLE_ON_NEG_EQ] THEN
+  MATCH_MP_TAC REAL_MEASURABLE_ON_INCREASING_UNIV THEN
+  ASM_SIMP_TAC[REAL_LE_NEG2]);;
+
+let REAL_MEASURABLE_ON_DECREASING = prove
+ (`!f a b. (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+                  ==> f y <= f x)
+           ==> f real_measurable_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC I [GSYM REAL_MEASURABLE_ON_NEG_EQ] THEN
+  MATCH_MP_TAC REAL_MEASURABLE_ON_INCREASING THEN
+  ASM_SIMP_TAC[REAL_LE_NEG2]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_INCREASING_PRODUCT = prove
+ (`!f g a b.
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> f x <= f y) /\
+        g absolutely_real_integrable_on real_interval[a,b]
+        ==> (\x. f x * g x) absolutely_real_integrable_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC ABSOLUTELY_REAL_INTEGRABLE_BOUNDED_MEASURABLE_PRODUCT THEN
+  ASM_SIMP_TAC[REAL_MEASURABLE_ON_INCREASING] THEN
+  REWRITE_TAC[real_bounded; FORALL_IN_IMAGE] THEN
+  EXISTS_TAC `abs((f:real->real) a) + abs((f:real->real) b)` THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC
+   (REAL_ARITH `a <= x /\ x <= b ==> abs x <= abs a + abs b`) THEN
+  CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[IN_REAL_INTERVAL; REAL_LE_TRANS; REAL_LE_REFL]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_INCREASING = prove
+ (`!f a b. (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+                  ==> f x <= f y)
+           ==> f absolutely_real_integrable_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ABS_CONV) [GSYM REAL_MUL_RID] THEN
+  MATCH_MP_TAC ABSOLUTELY_REAL_INTEGRABLE_INCREASING_PRODUCT THEN
+  ASM_REWRITE_TAC[ABSOLUTELY_REAL_INTEGRABLE_CONST]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_DECREASING_PRODUCT = prove
+ (`!f g a b.
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> f y <= f x) /\
+        g absolutely_real_integrable_on real_interval[a,b]
+        ==> (\x. f x * g x) absolutely_real_integrable_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC ABSOLUTELY_REAL_INTEGRABLE_BOUNDED_MEASURABLE_PRODUCT THEN
+  ASM_SIMP_TAC[REAL_MEASURABLE_ON_DECREASING] THEN
+  REWRITE_TAC[real_bounded; FORALL_IN_IMAGE] THEN
+  EXISTS_TAC `abs((f:real->real) a) + abs((f:real->real) b)` THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC
+   (REAL_ARITH `b <= x /\ x <= a ==> abs x <= abs a + abs b`) THEN
+  CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[IN_REAL_INTERVAL; REAL_LE_TRANS; REAL_LE_REFL]);;
+
+let ABSOLUTELY_REAL_INTEGRABLE_DECREASING = prove
+ (`!f a b. (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+                  ==> f y <= f x)
+           ==> f absolutely_real_integrable_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ABS_CONV) [GSYM REAL_MUL_RID] THEN
+  MATCH_MP_TAC ABSOLUTELY_REAL_INTEGRABLE_DECREASING_PRODUCT THEN
+  ASM_REWRITE_TAC[ABSOLUTELY_REAL_INTEGRABLE_CONST]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real functions of bounded variation.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("has_bounded_real_variation_on",(12,"right"));;
+
+let has_bounded_real_variation_on = new_definition
+ `f has_bounded_real_variation_on s <=>
+  (lift o f o drop) has_bounded_variation_on (IMAGE lift s)`;;
+
+let real_variation = new_definition
+ `real_variation s f = vector_variation (IMAGE lift s) (lift o f o drop)`;;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_EQ = prove
+ (`!f g s.
+        (!x. x IN s ==> f x = g x) /\ f has_bounded_real_variation_on s
+
+
+        ==> g has_bounded_real_variation_on s`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[IMP_CONJ; has_bounded_real_variation_on] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HAS_BOUNDED_VARIATION_ON_EQ) THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_SUBSET = prove
+ (`!f s t. f has_bounded_real_variation_on s /\ t SUBSET s
+           ==> f has_bounded_real_variation_on t`,
+  REWRITE_TAC[has_bounded_real_variation_on] THEN
+  MESON_TAC[HAS_BOUNDED_VARIATION_ON_SUBSET; IMAGE_SUBSET]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_LMUL = prove
+ (`!f c s. f has_bounded_real_variation_on s
+           ==> (\x. c * f x) has_bounded_real_variation_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_real_variation_on] THEN
+  REWRITE_TAC[o_DEF; LIFT_CMUL; HAS_BOUNDED_VARIATION_ON_CMUL]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_RMUL = prove
+ (`!f c s. f has_bounded_real_variation_on s
+           ==> (\x. f x * c) has_bounded_real_variation_on s`,
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  REWRITE_TAC[HAS_BOUNDED_REAL_VARIATION_ON_LMUL]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_NEG = prove
+ (`!f s. f has_bounded_real_variation_on s
+         ==> (\x. --f x) has_bounded_real_variation_on s`,
+  REWRITE_TAC[has_bounded_real_variation_on; o_DEF; LIFT_NEG] THEN
+  REWRITE_TAC[HAS_BOUNDED_VARIATION_ON_NEG]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_ADD = prove
+ (`!f g s. f has_bounded_real_variation_on s /\
+           g has_bounded_real_variation_on s
+           ==> (\x. f x + g x) has_bounded_real_variation_on s`,
+  REWRITE_TAC[has_bounded_real_variation_on; o_DEF; LIFT_ADD] THEN
+  REWRITE_TAC[HAS_BOUNDED_VARIATION_ON_ADD]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_SUB = prove
+ (`!f g s. f has_bounded_real_variation_on s /\
+           g has_bounded_real_variation_on s
+           ==> (\x. f x - g x) has_bounded_real_variation_on s`,
+  REWRITE_TAC[has_bounded_real_variation_on; o_DEF; LIFT_SUB] THEN
+  REWRITE_TAC[HAS_BOUNDED_VARIATION_ON_SUB]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_NULL = prove
+ (`!f a b. b <= a ==> f has_bounded_real_variation_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[has_bounded_real_variation_on] THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL] THEN
+  MATCH_MP_TAC HAS_BOUNDED_VARIATION_ON_NULL THEN
+  ASM_REWRITE_TAC[BOUNDED_INTERVAL; CONTENT_EQ_0_1; LIFT_DROP]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_EMPTY = prove
+ (`!f. f has_bounded_real_variation_on {}`,
+  REWRITE_TAC[IMAGE_CLAUSES; has_bounded_real_variation_on] THEN
+  REWRITE_TAC[HAS_BOUNDED_VARIATION_ON_EMPTY]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_ABS = prove
+ (`!f s. f has_bounded_real_variation_on s
+         ==> (\x. abs(f x)) has_bounded_real_variation_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_real_variation_on] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_BOUNDED_VARIATION_ON_NORM) THEN
+  REWRITE_TAC[o_DEF; NORM_REAL; GSYM drop; LIFT_DROP]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_MAX = prove
+ (`!f g s. f has_bounded_real_variation_on s /\
+           g has_bounded_real_variation_on s
+           ==> (\x. max (f x) (g x)) has_bounded_real_variation_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_real_variation_on] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_BOUNDED_VARIATION_ON_MAX) THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_MIN = prove
+ (`!f g s. f has_bounded_real_variation_on s /\
+           g has_bounded_real_variation_on s
+           ==> (\x. min (f x) (g x)) has_bounded_real_variation_on s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_real_variation_on] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_BOUNDED_VARIATION_ON_MIN) THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_IMP_BOUNDED_ON_INTERVAL = prove
+ (`!f a b. f has_bounded_real_variation_on real_interval[a,b]
+           ==> real_bounded(IMAGE f (real_interval[a,b]))`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[has_bounded_real_variation_on; REAL_BOUNDED] THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP
+    HAS_BOUNDED_VARIATION_ON_IMP_BOUNDED_ON_INTERVAL) THEN
+  REWRITE_TAC[IMAGE_o; IMAGE_DROP_INTERVAL; LIFT_DROP]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_MUL = prove
+ (`!f g a b.
+        f has_bounded_real_variation_on real_interval[a,b] /\
+        g has_bounded_real_variation_on real_interval[a,b]
+        ==> (\x. f x * g x) has_bounded_real_variation_on real_interval[a,b]`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_real_variation_on] THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HAS_BOUNDED_VARIATION_ON_MUL) THEN
+  REWRITE_TAC[o_DEF; LIFT_CMUL; LIFT_DROP]);;
+
+let REAL_VARIATION_POS_LE = prove
+ (`!f s. f has_bounded_real_variation_on s ==> &0 <= real_variation s f`,
+  REWRITE_TAC[real_variation; has_bounded_real_variation_on] THEN
+  REWRITE_TAC[VECTOR_VARIATION_POS_LE]);;
+
+let REAL_VARIATION_GE_ABS_FUNCTION = prove
+ (`!f s a b.
+        f has_bounded_real_variation_on s /\ real_segment[a,b] SUBSET s
+        ==> abs(f b - f a) <= real_variation s f`,
+  REWRITE_TAC[has_bounded_real_variation_on] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`lift o f o drop`; `IMAGE lift s`; `lift a`; `lift b`]
+   VECTOR_VARIATION_GE_NORM_FUNCTION) THEN
+  ASM_SIMP_TAC[GSYM IMAGE_LIFT_REAL_SEGMENT;
+               IMAGE_EQ_EMPTY; IMAGE_SUBSET] THEN
+  REWRITE_TAC[real_variation; o_THM; LIFT_DROP; GSYM LIFT_SUB; NORM_LIFT]);;
+
+let REAL_VARIATION_GE_FUNCTION = prove
+ (`!f s a b.
+        f has_bounded_real_variation_on s /\ real_segment[a,b] SUBSET s
+        ==> f b - f a <= real_variation s f`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH `abs x <= a ==> x <= a`) THEN
+  ASM_MESON_TAC[REAL_VARIATION_GE_ABS_FUNCTION]);;
+
+let REAL_VARIATION_MONOTONE = prove
+ (`!f s t. f has_bounded_real_variation_on s /\ t SUBSET s
+           ==> real_variation t f <= real_variation s f`,
+  REWRITE_TAC[has_bounded_real_variation_on; real_variation] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC VECTOR_VARIATION_MONOTONE THEN
+  ASM_SIMP_TAC[IMAGE_SUBSET]);;
+
+let REAL_VARIATION_NEG = prove
+ (`!f s. real_variation s (\x. --(f x)) = real_variation s f`,
+  SIMP_TAC[real_variation; o_DEF; LIFT_NEG; VECTOR_VARIATION_NEG]);;
+
+let REAL_VARIATION_TRIANGLE = prove
+ (`!f g s. f has_bounded_real_variation_on s /\
+           g has_bounded_real_variation_on s
+           ==> real_variation s (\x. f x + g x)
+               <= real_variation s f + real_variation s g`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[has_bounded_real_variation_on; real_variation] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP VECTOR_VARIATION_TRIANGLE) THEN
+  REWRITE_TAC[o_DEF; LIFT_ADD]);;
+
+let HAS_BOUNDED_REAL_VARIATION_ON_COMBINE = prove
+ (`!f a b c.
+        a <= c /\ c <= b
+        ==> (f has_bounded_real_variation_on real_interval[a,b] <=>
+             f has_bounded_real_variation_on real_interval[a,c] /\
+             f has_bounded_real_variation_on real_interval[c,b])`,
+  REWRITE_TAC[has_bounded_real_variation_on; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`lift o f o drop`; `lift a`; `lift b`; `lift c`]
+        HAS_BOUNDED_VARIATION_ON_COMBINE) THEN
+  ASM_REWRITE_TAC[LIFT_DROP; has_bounded_real_variation_on;
+      IMAGE_LIFT_REAL_INTERVAL]);;
+
+let REAL_VARIATION_COMBINE = prove
+ (`!f a b c.
+        a <= c /\ c <= b /\
+        f has_bounded_real_variation_on real_interval[a,b]
+        ==> real_variation (real_interval[a,c]) f +
+            real_variation (real_interval[c,b]) f =
+            real_variation (real_interval[a,b]) f`,
+  REWRITE_TAC[has_bounded_real_variation_on; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`lift o f o drop`; `lift a`; `lift b`; `lift c`]
+        VECTOR_VARIATION_COMBINE) THEN
+  ASM_REWRITE_TAC[LIFT_DROP; real_variation; IMAGE_LIFT_REAL_INTERVAL]);;
+
+let REAL_VARIATION_MINUS_FUNCTION_MONOTONE = prove
+ (`!f a b c d.
+        f has_bounded_real_variation_on real_interval[a,b] /\
+        real_interval[c,d] SUBSET real_interval[a,b] /\
+        ~(real_interval[c,d] = {})
+        ==> real_variation (real_interval[c,d]) f - (f d - f c) <=
+            real_variation (real_interval[a,b]) f - (f b - f a)`,
+  REWRITE_TAC[has_bounded_real_variation_on; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`lift o f o drop`; `lift a`; `lift b`; `lift c`; `lift d`]
+   VECTOR_VARIATION_MINUS_FUNCTION_MONOTONE) THEN
+  ASM_SIMP_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; real_variation;
+                IMAGE_EQ_EMPTY; IMAGE_SUBSET] THEN
+  REWRITE_TAC[o_THM; LIFT_DROP; DROP_SUB]);;
+
+let INCREASING_BOUNDED_REAL_VARIATION = prove
+ (`!f a b.
+      (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+             ==> f x <= f y)
+      ==> f has_bounded_real_variation_on real_interval[a,b]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[has_bounded_real_variation_on] THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL] THEN
+  MATCH_MP_TAC INCREASING_BOUNDED_VARIATION THEN
+  REWRITE_TAC[IN_INTERVAL_1; GSYM FORALL_DROP; o_THM; LIFT_DROP] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_REAL_INTERVAL]) THEN ASM_MESON_TAC[]);;
+
+let INCREASING_REAL_VARIATION = prove
+ (`!f a b.
+        ~(real_interval[a,b] = {}) /\
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> f x <= f y)
+        ==> real_variation (real_interval[a,b]) f = f b - f a`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[real_variation; IMAGE_LIFT_REAL_INTERVAL] THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `lift a`; `lift b`]
+        INCREASING_VECTOR_VARIATION) THEN
+  REWRITE_TAC[o_THM; LIFT_DROP] THEN DISCH_THEN MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IMAGE_EQ_EMPTY] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[LIFT_DROP] THEN ASM_MESON_TAC[]);;
+
+let HAS_BOUNDED_REAL_VARIATION_AFFINITY2_EQ = prove
+ (`!m c f s.
+        (\x. f (m * x + c)) has_bounded_real_variation_on
+
+
+        IMAGE (\x. inv m * x + --(inv m * c)) s <=>
+        m = &0 \/ f has_bounded_real_variation_on s`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`m:real`; `lift c`; `lift o f o drop`; `IMAGE lift s`]
+        HAS_BOUNDED_VARIATION_AFFINITY2_EQ) THEN
+  REWRITE_TAC[o_DEF; has_bounded_real_variation_on; GSYM IMAGE_o;
+   DROP_ADD; DROP_CMUL; LIFT_ADD; LIFT_CMUL; LIFT_NEG; LIFT_DROP]);;
+
+let REAL_VARIATION_AFFINITY2 = prove
+ (`!m c f s.
+        real_variation (IMAGE (\x. inv m * x + --(inv m * c)) s)
+                       (\x. f (m * x + c)) =
+        if m = &0 then &0 else real_variation s f`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`m:real`; `lift c`; `lift o f o drop`; `IMAGE lift s`]
+         VECTOR_VARIATION_AFFINITY2) THEN
+  REWRITE_TAC[o_DEF; real_variation; GSYM IMAGE_o;
+   DROP_ADD; DROP_CMUL; LIFT_ADD; LIFT_CMUL; LIFT_NEG; LIFT_DROP]);;
+
+let HAS_BOUNDED_REAL_VARIATION_AFFINITY_EQ = prove
+ (`!m c f s.
+        (\x. f (m * x + c)) has_bounded_real_variation_on s <=>
+        m = &0 \/ f has_bounded_real_variation_on IMAGE (\x. m * x + c) s`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`m:real`; `lift c`; `lift o f o drop`; `IMAGE lift s`]
+        HAS_BOUNDED_VARIATION_AFFINITY_EQ) THEN
+  REWRITE_TAC[o_DEF; has_bounded_real_variation_on; GSYM IMAGE_o;
+   DROP_ADD; DROP_CMUL; LIFT_ADD; LIFT_CMUL; LIFT_NEG; LIFT_DROP]);;
+
+let REAL_VARIATION_AFFINITY = prove
+ (`!m c f s.
+        real_variation s (\x. f (m * x + c)) =
+        if m = &0 then &0 else real_variation (IMAGE (\x. m * x + c) s) f`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`m:real`; `lift c`; `lift o f o drop`; `IMAGE lift s`]
+         VECTOR_VARIATION_AFFINITY) THEN
+  REWRITE_TAC[o_DEF; real_variation; GSYM IMAGE_o;
+   DROP_ADD; DROP_CMUL; LIFT_ADD; LIFT_CMUL; LIFT_NEG; LIFT_DROP]);;
+
+let HAS_BOUNDED_REAL_VARIATION_TRANSLATION2_EQ = prove
+ (`!a f s.
+      (\x. f(a + x)) has_bounded_real_variation_on (IMAGE (\x. --a + x) s) <=>
+      f has_bounded_real_variation_on s`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`lift a`; `lift o f o drop`; `IMAGE lift s`]
+        HAS_BOUNDED_VARIATION_TRANSLATION2_EQ) THEN
+  REWRITE_TAC[o_DEF; has_bounded_real_variation_on; GSYM IMAGE_o;
+              DROP_ADD; LIFT_DROP; LIFT_ADD; LIFT_NEG]);;
+
+let REAL_VARIATION_TRANSLATION2 = prove
+ (`!a f s. real_variation (IMAGE (\x. --a + x) s) (\x. f(a + x)) =
+           real_variation s f`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`lift a`; `lift o f o drop`; `IMAGE lift s`]
+        VECTOR_VARIATION_TRANSLATION2) THEN
+  REWRITE_TAC[o_DEF; real_variation; GSYM IMAGE_o;
+              DROP_ADD; LIFT_DROP; LIFT_ADD; LIFT_NEG]);;
+
+let HAS_BOUNDED_REAL_VARIATION_TRANSLATION_EQ = prove
+ (`!a f s. (\x. f(a + x)) has_bounded_real_variation_on s <=>
+           f has_bounded_real_variation_on (IMAGE (\x. a + x) s)`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`lift a`; `lift o f o drop`; `IMAGE lift s`]
+        HAS_BOUNDED_VARIATION_TRANSLATION_EQ) THEN
+  REWRITE_TAC[o_DEF; has_bounded_real_variation_on; GSYM IMAGE_o;
+              DROP_ADD; LIFT_DROP; LIFT_ADD; LIFT_NEG]);;
+
+let REAL_VARIATION_TRANSLATION = prove
+ (`!a f s. real_variation s (\x. f(a + x)) =
+           real_variation (IMAGE (\x. a + x) s) f`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`lift a`; `lift o f o drop`; `IMAGE lift s`]
+        VECTOR_VARIATION_TRANSLATION) THEN
+  REWRITE_TAC[o_DEF; real_variation; GSYM IMAGE_o;
+              DROP_ADD; LIFT_DROP; LIFT_ADD; LIFT_NEG]);;
+
+let HAS_BOUNDED_REAL_VARIATION_TRANSLATION_EQ_INTERVAL = prove
+ (`!a f u v.
+        (\x. f(a + x)) has_bounded_real_variation_on real_interval[u,v] <=>
+        f has_bounded_real_variation_on real_interval[a+u,a+v]`,
+  REWRITE_TAC[REAL_INTERVAL_TRANSLATION;
+              HAS_BOUNDED_REAL_VARIATION_TRANSLATION_EQ]);;
+
+let REAL_VARIATION_TRANSLATION_INTERVAL = prove
+ (`!a f u v.
+        real_variation (real_interval[u,v]) (\x. f(a + x)) =
+        real_variation (real_interval[a+u,a+v]) f`,
+  REWRITE_TAC[REAL_INTERVAL_TRANSLATION;
+                REAL_VARIATION_TRANSLATION]);;
+
+let HAS_BOUNDED_REAL_VARIATION_TRANSLATION = prove
+ (`!f s a. f has_bounded_real_variation_on s
+           ==> (\x. f(a + x)) has_bounded_real_variation_on
+               (IMAGE (\x. --a + x) s)`,
+  REWRITE_TAC[HAS_BOUNDED_REAL_VARIATION_TRANSLATION2_EQ]);;
+
+let HAS_BOUNDED_REAL_VARIATION_REFLECT2_EQ = prove
+ (`!f s. (\x. f(--x)) has_bounded_real_variation_on (IMAGE (--) s) <=>
+         f has_bounded_real_variation_on s`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `IMAGE lift s`]
+        HAS_BOUNDED_VARIATION_REFLECT2_EQ) THEN
+  REWRITE_TAC[o_DEF; has_bounded_real_variation_on; GSYM IMAGE_o;
+              DROP_NEG; LIFT_DROP; LIFT_NEG]);;
+
+let REAL_VARIATION_REFLECT2 = prove
+ (`!f s. real_variation (IMAGE (--) s) (\x. f(--x)) =
+         real_variation s f`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `IMAGE lift s`]
+        VECTOR_VARIATION_REFLECT2) THEN
+  REWRITE_TAC[o_DEF; real_variation; GSYM IMAGE_o;
+              DROP_NEG; LIFT_DROP; LIFT_NEG]);;
+
+let HAS_BOUNDED_REAL_VARIATION_REFLECT_EQ = prove
+ (`!f s. (\x. f(--x)) has_bounded_real_variation_on s <=>
+         f has_bounded_real_variation_on (IMAGE (--) s)`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `IMAGE lift s`]
+        HAS_BOUNDED_VARIATION_REFLECT_EQ) THEN
+  REWRITE_TAC[o_DEF; has_bounded_real_variation_on; GSYM IMAGE_o;
+              DROP_NEG; LIFT_DROP; LIFT_NEG]);;
+
+let REAL_VARIATION_REFLECT = prove
+ (`!f s. real_variation s (\x. f(--x)) =
+         real_variation (IMAGE (--) s) f`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`lift o f o drop`; `IMAGE lift s`]
+        VECTOR_VARIATION_REFLECT) THEN
+  REWRITE_TAC[o_DEF; real_variation; GSYM IMAGE_o;
+              DROP_NEG; LIFT_DROP; LIFT_NEG]);;
+
+let HAS_BOUNDED_REAL_VARIATION_REFLECT_EQ_INTERVAL = prove
+ (`!f u v. (\x. f(--x)) has_bounded_real_variation_on real_interval[u,v] <=>
+           f has_bounded_real_variation_on real_interval[--v,--u]`,
+  REWRITE_TAC[GSYM REFLECT_REAL_INTERVAL;
+              HAS_BOUNDED_REAL_VARIATION_REFLECT_EQ]);;
+
+let REAL_VARIATION_REFLECT_INTERVAL = prove
+ (`!f u v. real_variation (real_interval[u,v]) (\x. f(--x)) =
+           real_variation (real_interval[--v,--u]) f`,
+  REWRITE_TAC[GSYM REFLECT_REAL_INTERVAL; REAL_VARIATION_REFLECT]);;
+
+let HAS_BOUNDED_REAL_VARIATION_DARBOUX = prove
+ (`!f a b.
+     f has_bounded_real_variation_on real_interval[a,b] <=>
+     ?g h. (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+                  ==> g x <= g y) /\
+           (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+                  ==> h x <= h y) /\
+           (!x. f x = g x - h x)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_real_variation_on] THEN
+  REWRITE_TAC[HAS_BOUNDED_VARIATION_DARBOUX; IMAGE_LIFT_REAL_INTERVAL] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE;
+              GSYM IMAGE_LIFT_REAL_INTERVAL; LIFT_DROP] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; GSYM CONJ_ASSOC] THEN
+  EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM; o_THM] THENL
+   [MAP_EVERY X_GEN_TAC [`g:real^1->real^1`; `h:real^1->real^1`] THEN
+    STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`drop o g o lift`; `drop o h o lift`] THEN
+    ASM_REWRITE_TAC[o_THM] THEN REWRITE_TAC[GSYM LIFT_EQ; FORALL_DROP] THEN
+    ASM_REWRITE_TAC[LIFT_DROP; LIFT_SUB];
+    MAP_EVERY X_GEN_TAC [`g:real->real`; `h:real->real`] THEN
+    STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`lift o g o drop`; `lift o h o drop`] THEN
+    ASM_REWRITE_TAC[o_THM; LIFT_DROP] THEN REWRITE_TAC[LIFT_SUB]]);;
+
+let HAS_BOUNDED_REAL_VARIATION_DARBOUX_STRICT = prove
+ (`!f a b.
+     f has_bounded_real_variation_on real_interval[a,b] <=>
+     ?g h. (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x < y
+                  ==> g x < g y) /\
+           (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x < y
+                  ==> h x < h y) /\
+           (!x. f x = g x - h x)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_real_variation_on] THEN
+  REWRITE_TAC[HAS_BOUNDED_VARIATION_DARBOUX_STRICT;
+              IMAGE_LIFT_REAL_INTERVAL] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE;
+              GSYM IMAGE_LIFT_REAL_INTERVAL; LIFT_DROP] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; GSYM CONJ_ASSOC] THEN
+  EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM; o_THM] THENL
+   [MAP_EVERY X_GEN_TAC [`g:real^1->real^1`; `h:real^1->real^1`] THEN
+    STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`drop o g o lift`; `drop o h o lift`] THEN
+    ASM_REWRITE_TAC[o_THM] THEN REWRITE_TAC[GSYM LIFT_EQ; FORALL_DROP] THEN
+    ASM_REWRITE_TAC[LIFT_DROP; LIFT_SUB];
+    MAP_EVERY X_GEN_TAC [`g:real->real`; `h:real->real`] THEN
+    STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`lift o g o drop`; `lift o h o drop`] THEN
+    ASM_REWRITE_TAC[o_THM; LIFT_DROP] THEN REWRITE_TAC[LIFT_SUB]]);;
+
+let INCREASING_LEFT_LIMIT = prove
+ (`!f a b c.
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> f x <= f y) /\
+        c IN real_interval[a,b]
+       ==> ?l. (f ---> l) (atreal c within real_interval[a,c])`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[TENDSTO_REAL; GSYM EXISTS_LIFT] THEN
+  REWRITE_TAC[LIM_WITHINREAL_WITHIN; IMAGE_LIFT_REAL_INTERVAL] THEN
+  MATCH_MP_TAC INCREASING_LEFT_LIMIT_1 THEN EXISTS_TAC `lift b` THEN
+  SIMP_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP; FUN_IN_IMAGE]);;
+
+let DECREASING_LEFT_LIMIT = prove
+ (`!f a b c.
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> f y <= f x) /\
+        c IN real_interval[a,b]
+        ==> ?l. (f ---> l) (atreal c within real_interval[a,c])`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[TENDSTO_REAL; GSYM EXISTS_LIFT] THEN
+  REWRITE_TAC[LIM_WITHINREAL_WITHIN; IMAGE_LIFT_REAL_INTERVAL] THEN
+  MATCH_MP_TAC DECREASING_LEFT_LIMIT_1 THEN EXISTS_TAC `lift b` THEN
+  SIMP_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP; FUN_IN_IMAGE]);;
+
+let INCREASING_RIGHT_LIMIT = prove
+ (`!f a b c.
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> f x <= f y) /\
+        c IN real_interval[a,b]
+       ==> ?l. (f ---> l) (atreal c within real_interval[c,b])`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[TENDSTO_REAL; GSYM EXISTS_LIFT] THEN
+  REWRITE_TAC[LIM_WITHINREAL_WITHIN; IMAGE_LIFT_REAL_INTERVAL] THEN
+  MATCH_MP_TAC INCREASING_RIGHT_LIMIT_1 THEN EXISTS_TAC `lift a` THEN
+  SIMP_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP; FUN_IN_IMAGE]);;
+
+let DECREASING_RIGHT_LIMIT = prove
+ (`!f a b c.
+        (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+               ==> f y <= f x) /\
+        c IN real_interval[a,b]
+        ==> ?l. (f ---> l) (atreal c within real_interval[c,b])`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[TENDSTO_REAL; GSYM EXISTS_LIFT] THEN
+  REWRITE_TAC[LIM_WITHINREAL_WITHIN; IMAGE_LIFT_REAL_INTERVAL] THEN
+  MATCH_MP_TAC DECREASING_RIGHT_LIMIT_1 THEN EXISTS_TAC `lift a` THEN
+  SIMP_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_THM; LIFT_DROP; FUN_IN_IMAGE]);;
+
+let HAS_BOUNDED_REAL_VARIATION_LEFT_LIMIT = prove
+ (`!f a b c.
+        f has_bounded_real_variation_on real_interval[a,b] /\
+        c IN real_interval[a,b]
+        ==> ?l. (f ---> l) (atreal c within real_interval[a,c])`,
+  REWRITE_TAC[has_bounded_real_variation_on] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[TENDSTO_REAL; GSYM EXISTS_LIFT] THEN
+  REWRITE_TAC[LIM_WITHINREAL_WITHIN; IMAGE_LIFT_REAL_INTERVAL] THEN
+  MATCH_MP_TAC HAS_BOUNDED_VECTOR_VARIATION_LEFT_LIMIT THEN
+  EXISTS_TAC `lift b` THEN
+  ASM_SIMP_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; GSYM o_ASSOC; FUN_IN_IMAGE]);;
+
+let HAS_BOUNDED_REAL_VARIATION_RIGHT_LIMIT = prove
+ (`!f a b c.
+        f has_bounded_real_variation_on real_interval[a,b] /\
+        c IN real_interval[a,b]
+        ==> ?l. (f ---> l) (atreal c within real_interval[c,b])`,
+  REWRITE_TAC[has_bounded_real_variation_on] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[TENDSTO_REAL; GSYM EXISTS_LIFT] THEN
+  REWRITE_TAC[LIM_WITHINREAL_WITHIN; IMAGE_LIFT_REAL_INTERVAL] THEN
+  MATCH_MP_TAC HAS_BOUNDED_VECTOR_VARIATION_RIGHT_LIMIT THEN
+  EXISTS_TAC `lift a` THEN
+  ASM_SIMP_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; GSYM o_ASSOC; FUN_IN_IMAGE]);;
+
+let REAL_VARIATION_CONTINUOUS_LEFT = prove
+ (`!f a b c.
+        f has_bounded_real_variation_on real_interval[a,b] /\
+        c IN real_interval[a,b]
+        ==> ((\x. real_variation(real_interval[a,x]) f)
+             real_continuous (atreal c within real_interval[a,c]) <=>
+            f real_continuous (atreal c within real_interval[a,c]))`,
+  REWRITE_TAC[has_bounded_real_variation_on; real_variation] THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL;
+        REAL_CONTINUOUS_CONTINUOUS_WITHINREAL] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC VECTOR_VARIATION_CONTINUOUS_LEFT THEN
+  EXISTS_TAC `lift b` THEN ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; FUN_IN_IMAGE]);;
+
+let REAL_VARIATION_CONTINUOUS_RIGHT = prove
+ (`!f a b c.
+        f has_bounded_real_variation_on real_interval[a,b] /\
+        c IN real_interval[a,b]
+        ==> ((\x. real_variation(real_interval[a,x]) f)
+             real_continuous (atreal c within real_interval[c,b]) <=>
+            f real_continuous (atreal c within real_interval[c,b]))`,
+  REWRITE_TAC[has_bounded_real_variation_on; real_variation] THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL;
+        REAL_CONTINUOUS_CONTINUOUS_WITHINREAL] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC VECTOR_VARIATION_CONTINUOUS_RIGHT THEN
+  ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; FUN_IN_IMAGE]);;
+
+let REAL_VARIATION_CONTINUOUS = prove
+ (`!f a b c.
+        f has_bounded_real_variation_on real_interval[a,b] /\
+        c IN real_interval[a,b]
+        ==> ((\x. real_variation(real_interval[a,x]) f)
+             real_continuous (atreal c within real_interval[a,b]) <=>
+            f real_continuous (atreal c within real_interval[a,b]))`,
+  REWRITE_TAC[has_bounded_real_variation_on; real_variation] THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL;
+        REAL_CONTINUOUS_CONTINUOUS_WITHINREAL] THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC VECTOR_VARIATION_CONTINUOUS THEN
+  ASM_REWRITE_TAC[] THEN
+  ASM_SIMP_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; FUN_IN_IMAGE]);;
+
+let HAS_BOUNDED_REAL_VARIATION_DARBOUX_STRONG = prove
+ (`!f a b.
+     f has_bounded_real_variation_on real_interval[a,b]
+     ==> ?g h.
+          (!x. f x = g x - h x) /\
+          (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+                 ==> g x <= g y) /\
+          (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x <= y
+                 ==> h x <= h y) /\
+          (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x < y
+                 ==> g x < g y) /\
+          (!x y. x IN real_interval[a,b] /\ y IN real_interval[a,b] /\ x < y
+                 ==> h x < h y) /\
+          (!x. x IN real_interval[a,b] /\
+               f real_continuous (atreal x within real_interval[a,x])
+               ==> g real_continuous (atreal x within real_interval[a,x]) /\
+                   h real_continuous (atreal x within real_interval[a,x])) /\
+          (!x. x IN real_interval[a,b] /\
+               f real_continuous (atreal x within real_interval[x,b])
+               ==> g real_continuous (atreal x within real_interval[x,b]) /\
+                   h real_continuous (atreal x within real_interval[x,b])) /\
+          (!x. x IN real_interval[a,b] /\
+               f real_continuous (atreal x within real_interval[a,b])
+               ==> g real_continuous (atreal x within real_interval[a,b]) /\
+                   h real_continuous (atreal x within real_interval[a,b]))`,
+  REPEAT STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC
+   [`\x. x + real_variation (real_interval[a,x]) f`;
+    `\x. x + real_variation (real_interval[a,x]) f - f x`] THEN
+  REWRITE_TAC[REAL_ARITH `(x + l) - (x + l - f):real = f`] THEN
+  REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC REAL_LE_ADD2 THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC REAL_VARIATION_MONOTONE;
+    MATCH_MP_TAC REAL_LE_ADD2 THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `!x. a - (b - x) <= c - (d - x) ==> a - b <= c - d`) THEN
+    EXISTS_TAC `(f:real->real) a` THEN
+    MATCH_MP_TAC REAL_VARIATION_MINUS_FUNCTION_MONOTONE;
+    MATCH_MP_TAC REAL_LTE_ADD2 THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC REAL_VARIATION_MONOTONE;
+    MATCH_MP_TAC REAL_LTE_ADD2 THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `!x. a - (b - x) <= c - (d - x) ==> a - b <= c - d`) THEN
+    EXISTS_TAC `(f:real->real) a` THEN
+    MATCH_MP_TAC REAL_VARIATION_MINUS_FUNCTION_MONOTONE;
+    MATCH_MP_TAC REAL_CONTINUOUS_ADD THEN
+    REWRITE_TAC[REAL_CONTINUOUS_WITHIN_ID] THEN
+    MP_TAC(ISPECL [`f:real->real`; `a:real`; `b:real`; `x:real`]
+        REAL_VARIATION_CONTINUOUS_LEFT) THEN
+    ASM_REWRITE_TAC[];
+    MATCH_MP_TAC REAL_CONTINUOUS_ADD THEN
+    REWRITE_TAC[REAL_CONTINUOUS_WITHIN_ID] THEN
+    MATCH_MP_TAC REAL_CONTINUOUS_SUB THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPECL [`f:real->real`; `a:real`; `b:real`; `x:real`]
+        REAL_VARIATION_CONTINUOUS_LEFT) THEN
+    ASM_REWRITE_TAC[];
+    MATCH_MP_TAC REAL_CONTINUOUS_ADD THEN
+    REWRITE_TAC[REAL_CONTINUOUS_WITHIN_ID] THEN
+    MP_TAC(ISPECL [`f:real->real`; `a:real`; `b:real`; `x:real`]
+        REAL_VARIATION_CONTINUOUS_RIGHT) THEN
+    ASM_REWRITE_TAC[];
+    MATCH_MP_TAC REAL_CONTINUOUS_ADD THEN
+    REWRITE_TAC[REAL_CONTINUOUS_WITHIN_ID] THEN
+    MATCH_MP_TAC REAL_CONTINUOUS_SUB THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPECL [`f:real->real`; `a:real`; `b:real`; `x:real`]
+        REAL_VARIATION_CONTINUOUS_RIGHT) THEN
+    ASM_REWRITE_TAC[];
+    MATCH_MP_TAC REAL_CONTINUOUS_ADD THEN
+    REWRITE_TAC[REAL_CONTINUOUS_WITHIN_ID] THEN
+    MP_TAC(ISPECL [`f:real->real`; `a:real`; `b:real`; `x:real`]
+        REAL_VARIATION_CONTINUOUS) THEN
+    ASM_REWRITE_TAC[];
+    MATCH_MP_TAC REAL_CONTINUOUS_ADD THEN
+    REWRITE_TAC[REAL_CONTINUOUS_WITHIN_ID] THEN
+    MATCH_MP_TAC REAL_CONTINUOUS_SUB THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPECL [`f:real->real`; `a:real`; `b:real`; `x:real`]
+        REAL_VARIATION_CONTINUOUS) THEN
+    ASM_REWRITE_TAC[]] THEN
+  (CONJ_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+       HAS_BOUNDED_REAL_VARIATION_ON_SUBSET));
+      ALL_TAC] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_REAL_INTERVAL]) THEN
+    REWRITE_TAC[SUBSET_REAL_INTERVAL; REAL_INTERVAL_EQ_EMPTY] THEN
+    ASM_REAL_ARITH_TAC));;
+
+let HAS_BOUNDED_REAL_VARIATION_COUNTABLE_DISCONTINUITIES = prove
+ (`!f a b. f has_bounded_real_variation_on real_interval[a,b]
+           ==> COUNTABLE {x | x IN real_interval[a,b] /\
+                              ~(f real_continuous atreal x)}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[has_bounded_real_variation_on] THEN
+  REWRITE_TAC[REAL_CONTINUOUS_CONTINUOUS_ATREAL] THEN
+  REWRITE_TAC[IMAGE_LIFT_REAL_INTERVAL] THEN DISCH_THEN(MP_TAC o
+    MATCH_MP HAS_BOUNDED_VARIATION_COUNTABLE_DISCONTINUITIES) THEN
+  DISCH_THEN(MP_TAC o ISPEC `drop` o MATCH_MP COUNTABLE_IMAGE) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] COUNTABLE_SUBSET) THEN
+  REWRITE_TAC[SUBSET; IN_IMAGE; EXISTS_LIFT; LIFT_DROP; UNWIND_THM1] THEN
+  REWRITE_TAC[GSYM IMAGE_LIFT_REAL_INTERVAL; IN_ELIM_THM] THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE; GSYM CONJ_ASSOC; EXISTS_DROP; LIFT_DROP] THEN
+  MESON_TAC[LIFT_DROP]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Lebesgue density theorem. This isn't about R specifically, but it's most  *)
+(* naturally stated as a real limit so it ends up here in this file.         *)
+(* ------------------------------------------------------------------------- *)
+
+let LEBESGUE_DENSITY_THEOREM = prove
+ (`!s:real^N->bool.
+      lebesgue_measurable s
+      ==> ?k. negligible k /\
+              !x. ~(x IN k)
+                  ==> ((\e. measure(s INTER cball(x,e)) / measure(cball(x,e)))
+                       ---> (if x IN s then &1 else &0))
+                      (atreal(&0) within {e | &0 < e})`,
+  REPEAT STRIP_TAC THEN MP_TAC (ISPEC
+   `indicator(s:real^N->bool)` ABSOLUTELY_INTEGRABLE_LEBESGUE_POINTS) THEN
+  ANTS_TAC THENL
+   [REPEAT GEN_TAC THEN REWRITE_TAC[indicator] THEN
+    MATCH_MP_TAC NONNEGATIVE_ABSOLUTELY_INTEGRABLE THEN CONJ_TAC THENL
+     [MESON_TAC[VEC_COMPONENT; REAL_POS]; ALL_TAC] THEN
+    REWRITE_TAC[INTEGRABLE_RESTRICT_INTER] THEN
+    ONCE_REWRITE_TAC[GSYM INTEGRABLE_RESTRICT_UNIV] THEN
+    REWRITE_TAC[GSYM MEASURABLE_INTEGRABLE] THEN
+    MATCH_MP_TAC MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE THEN
+    ASM_REWRITE_TAC[MEASURABLE_INTERVAL];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^N->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[REALLIM_WITHINREAL; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+   [`x:real^N`; `e / &(dimindex(:N)) pow dimindex(:N)`]) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_POW_LT;
+               REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[REAL_SUB_RZERO] THEN X_GEN_TAC `h:real` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `h:real`) THEN
+  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  SIMP_TAC[REAL_LT_RDIV_EQ;  REAL_POW_LT;
+           REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] REAL_LET_TRANS) THEN
+  ASM_SIMP_TAC[MEASURE_CBALL_POS; REAL_FIELD
+   `&0 < y ==> x / y - a = inv(y) * (x - a * y)`] THEN
+  REWRITE_TAC[REAL_ABS_MUL; NORM_MUL] THEN ONCE_REWRITE_TAC
+   [REAL_ARITH `x <= (abs a * b) * c <=> x <= (abs(a) * c) * b`] THEN
+  MATCH_MP_TAC REAL_LE_MUL2 THEN REWRITE_TAC[REAL_ABS_POS] THEN
+  CONJ_TAC THENL
+   [SIMP_TAC[GSYM REAL_LE_LDIV_EQ; REAL_POW_LT;
+             REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1] THEN
+    REWRITE_TAC[REAL_ABS_INV; real_div; GSYM REAL_INV_MUL] THEN
+    MATCH_MP_TAC REAL_LE_INV2 THEN CONJ_TAC THENL
+     [REWRITE_TAC[GSYM REAL_ABS_NZ; CONTENT_EQ_0] THEN
+      REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; VEC_COMPONENT;
+                  VECTOR_SUB_COMPONENT] THEN ASM_REAL_ARITH_TAC;
+      SIMP_TAC[real_abs; CONTENT_POS_LE; MEASURE_POS_LE; MEASURABLE_CBALL] THEN
+      MATCH_MP_TAC REAL_LE_TRANS THEN
+      EXISTS_TAC `measure(interval[x - h / &(dimindex(:N)) % vec 1:real^N,
+                                   x + h / &(dimindex(:N)) % vec 1]) *
+                  &(dimindex (:N)) pow dimindex (:N)` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[MEASURE_INTERVAL; CONTENT_CLOSED_INTERVAL_CASES] THEN
+        REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; VEC_COMPONENT;
+                    VECTOR_SUB_COMPONENT; REAL_MUL_RID] THEN
+        ASM_SIMP_TAC[REAL_ARITH `x - h <= x + h <=> &0 <= h`;
+                     REAL_LE_DIV; REAL_POS; REAL_LT_IMP_LE] THEN
+        REWRITE_TAC[REAL_ARITH `(x + h) - (x - h) = &2 * h`;
+                    PRODUCT_CONST_NUMSEG_1; REAL_POW_DIV; REAL_POW_MUL] THEN
+        MATCH_MP_TAC(REAL_ARITH `x = y ==> y <= x`) THEN
+        REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN AP_TERM_TAC THEN
+        MATCH_MP_TAC REAL_DIV_RMUL THEN
+        REWRITE_TAC[REAL_POW_EQ_0; REAL_OF_NUM_EQ; DIMINDEX_NONZERO];
+        MATCH_MP_TAC REAL_LE_RMUL THEN SIMP_TAC[REAL_POS; REAL_POW_LE] THEN
+        MATCH_MP_TAC MEASURE_SUBSET THEN
+        REWRITE_TAC[MEASURABLE_INTERVAL; MEASURABLE_CBALL] THEN
+        REWRITE_TAC[SUBSET; IN_INTERVAL; IN_CBALL] THEN
+        X_GEN_TAC `y:real^N` THEN
+        REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; VEC_COMPONENT;
+                    VECTOR_SUB_COMPONENT; REAL_MUL_RID; REAL_ARITH
+                     `x - h <= y /\ y <= x + h <=> abs(x - y) <= h`] THEN
+        STRIP_TAC THEN REWRITE_TAC[dist] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+        EXISTS_TAC `sum(1..dimindex(:N)) (\i. abs((x - y:real^N)$i))` THEN
+        REWRITE_TAC[NORM_LE_L1] THEN MATCH_MP_TAC SUM_BOUND_GEN THEN
+        ASM_REWRITE_TAC[CARD_NUMSEG_1; VECTOR_SUB_COMPONENT; IN_NUMSEG] THEN
+        REWRITE_TAC[FINITE_NUMSEG; NUMSEG_EMPTY; NOT_LT; DIMINDEX_GE_1]]];
+    REWRITE_TAC[NORM_REAL; GSYM drop] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= y ==> x <= abs y`) THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `drop(integral (cball(x:real^N,h))
+                   (\t. lift(norm(indicator s t - indicator s x))))` THEN
+    CONJ_TAC THENL
+     [ASM_SIMP_TAC[MEASURE_INTEGRAL; MEASURABLE_CBALL;
+                   MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE] THEN
+      REWRITE_TAC[GSYM INTEGRAL_RESTRICT_INTER; GSYM DROP_CMUL] THEN
+      SIMP_TAC[GSYM INTEGRAL_CMUL; GSYM MEASURABLE; MEASURABLE_CBALL] THEN
+      REWRITE_TAC[GSYM DROP_SUB; COND_RATOR; COND_RAND] THEN
+      REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_MUL_LID] THEN
+      ASM_SIMP_TAC[GSYM INTEGRAL_SUB; INTEGRABLE_RESTRICT_INTER;
+                   GSYM MEASURABLE; MEASURABLE_CBALL; INTEGRABLE_ON_CONST;
+                   MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE] THEN
+      REWRITE_TAC[GSYM NORM_REAL; drop] THEN REWRITE_TAC[GSYM drop] THEN
+      MATCH_MP_TAC INTEGRAL_NORM_BOUND_INTEGRAL THEN
+      ASM_SIMP_TAC[INTEGRABLE_SUB; INTEGRABLE_RESTRICT_INTER;
+                   GSYM MEASURABLE; MEASURABLE_CBALL; INTEGRABLE_ON_CONST;
+                   MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE] THEN
+      CONJ_TAC THENL
+       [ALL_TAC;
+        GEN_TAC THEN DISCH_TAC THEN
+        REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[indicator]) THEN
+        REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB; LIFT_DROP; DROP_VEC] THEN
+        REAL_ARITH_TAC];
+      REWRITE_TAC[NORM_REAL; GSYM drop; LIFT_DROP] THEN
+      MATCH_MP_TAC INTEGRAL_SUBSET_DROP_LE THEN
+      REPEAT CONJ_TAC THENL
+       [REWRITE_TAC[SUBSET; IN_CBALL; IN_INTERVAL] THEN
+        REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; VEC_COMPONENT;
+                    VECTOR_SUB_COMPONENT; REAL_MUL_RID; REAL_ARITH
+                       `x - h <= y /\ y <= x + h <=> abs(x - y) <= h`] THEN
+        REWRITE_TAC[dist; GSYM VECTOR_SUB_COMPONENT] THEN
+        MESON_TAC[REAL_LE_TRANS; COMPONENT_LE_NORM];
+        ALL_TAC;
+        ALL_TAC;
+        REWRITE_TAC[LIFT_DROP; REAL_ABS_POS]]]] THEN
+  REWRITE_TAC[GSYM NORM_REAL; drop] THEN
+  MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_IMP_INTEGRABLE THEN
+  MATCH_MP_TAC ABSOLUTELY_INTEGRABLE_NORM THEN
+  MATCH_MP_TAC(INST_TYPE [`:1`,`:P`]
+    ABSOLUTELY_INTEGRABLE_INTEGRABLE_BOUND) THEN
+  EXISTS_TAC `(\x. vec 1):real^N->real^1` THEN
+
+  REWRITE_TAC[DROP_VEC; GSYM MEASURABLE; MEASURABLE_INTERVAL;
+              MEASURABLE_CBALL] THEN
+  (CONJ_TAC THENL
+    [GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[indicator] THEN
+     REPEAT(COND_CASES_TAC THEN
+            ASM_REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB; DROP_VEC]) THEN
+     CONV_TAC REAL_RAT_REDUCE_CONV;
+     ALL_TAC]) THEN
+  MATCH_MP_TAC INTEGRABLE_SUB THEN
+  REWRITE_TAC[INTEGRABLE_ON_CONST; MEASURABLE_INTERVAL; MEASURABLE_CBALL] THEN
+  REWRITE_TAC[indicator; INTEGRABLE_RESTRICT_INTER] THEN
+  REWRITE_TAC[GSYM MEASURABLE] THEN
+  ASM_SIMP_TAC[MEASURABLE_CBALL; MEASURABLE_INTERVAL;
+               MEASURABLE_LEGESGUE_MEASURABLE_INTER_MEASURABLE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Injective map into R is also an open map w.r.t. the universe, and this    *)
+(* is actually an implication in both directions for an interval. Compare    *)
+(* the local form in INJECTIVE_INTO_1D_IMP_OPEN_MAP (not a bi-implication).  *)
+(* ------------------------------------------------------------------------- *)
+
+let INJECTIVE_EQ_1D_OPEN_MAP_UNIV = prove
+ (`!f:real^1->real^1 s.
+        f continuous_on s /\ is_interval s
+        ==>  ((!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) <=>
+              (!t. open t /\ t SUBSET s ==> open(IMAGE f t)))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [ONCE_REWRITE_TAC[OPEN_SUBOPEN] THEN REWRITE_TAC[FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `x:real^1` THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `x:real^1`) THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[BALL_1] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `IMAGE (f:real^1->real^1)
+                      (segment (x - lift d,x + lift d))` THEN
+    MP_TAC(ISPECL
+     [`f:real^1->real^1`; `x - lift d`; `x + lift d`]
+     CONTINUOUS_INJECTIVE_IMAGE_OPEN_SEGMENT_1) THEN
+    REWRITE_TAC[SEGMENT_1; DROP_ADD; DROP_SUB; LIFT_DROP] THEN
+    ASM_CASES_TAC `drop x - d <= drop x + d` THENL
+     [ASM_REWRITE_TAC[] THEN REWRITE_TAC[GSYM SEGMENT_1];
+      ASM_REAL_ARITH_TAC] THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[SUBSET; CONTINUOUS_ON_SUBSET]; ALL_TAC] THEN
+    REPEAT STRIP_TAC THENL
+     [ASM_REWRITE_TAC[OPEN_SEGMENT_1];
+      MATCH_MP_TAC FUN_IN_IMAGE THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+      REWRITE_TAC[DROP_ADD; DROP_SUB; LIFT_DROP] THEN ASM_REAL_ARITH_TAC;
+      MATCH_MP_TAC IMAGE_SUBSET THEN
+      ASM_MESON_TAC[INTERVAL_OPEN_SUBSET_CLOSED; SUBSET_TRANS]];
+    MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`f:real^1->real^1`; `x:real^1`; `y:real^1`]
+        CONTINUOUS_IVT_LOCAL_EXTREMUM) THEN
+    ASM_REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[CONVEX_CONTAINS_SEGMENT_EQ; IS_INTERVAL_CONVEX_1;
+                    CONTINUOUS_ON_SUBSET];
+      DISCH_THEN(X_CHOOSE_TAC `z:real^1`) THEN
+      FIRST_ASSUM(MP_TAC o SPEC `segment(x:real^1,y)`) THEN
+      REWRITE_TAC[OPEN_SEGMENT_1; NOT_IMP] THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[CONVEX_CONTAINS_SEGMENT; IS_INTERVAL_CONVEX_1;
+                      SUBSET_TRANS; SEGMENT_OPEN_SUBSET_CLOSED];
+        FIRST_X_ASSUM(CONJUNCTS_THEN ASSUME_TAC) THEN
+        REWRITE_TAC[open_def; FORALL_IN_IMAGE] THEN
+        DISCH_THEN(MP_TAC o SPEC `z:real^1`) THEN ASM_REWRITE_TAC[] THEN
+        DISCH_THEN(X_CHOOSE_THEN `e:real`
+         (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+        FIRST_X_ASSUM DISJ_CASES_TAC THENL
+         [DISCH_THEN(MP_TAC o SPEC `(f:real^1->real^1) z + lift(e / &2)`);
+          DISCH_THEN(MP_TAC o SPEC `(f:real^1->real^1) z - lift(e / &2)`)] THEN
+        ASM_REWRITE_TAC[NORM_ARITH `dist(a + b:real^N,a) = norm b`;
+                        NORM_ARITH `dist(a - b:real^N,a) = norm b`; NORM_LIFT;
+                        REAL_ARITH `abs(e / &2) < e <=> &0 < e`] THEN
+        REWRITE_TAC[IN_IMAGE] THEN
+        DISCH_THEN(X_CHOOSE_THEN `w:real^1` (STRIP_ASSUME_TAC o GSYM)) THEN
+        FIRST_X_ASSUM(MP_TAC o SPEC `w:real^1`) THEN
+        ASM_SIMP_TAC[REWRITE_RULE[SUBSET] SEGMENT_OPEN_SUBSET_CLOSED] THEN
+        REWRITE_TAC[DROP_ADD; DROP_SUB; LIFT_DROP] THEN
+        ASM_REAL_ARITH_TAC]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Map f:S^m->S^n for m < n is nullhomotopic.                                *)
+(* ------------------------------------------------------------------------- *)
+
+let INESSENTIAL_SPHEREMAP_LOWDIM_GEN = prove
+ (`!f:real^M->real^N s t.
+     convex s /\ bounded s /\ convex t /\ bounded t /\ aff_dim s < aff_dim t /\
+     f continuous_on relative_frontier s /\
+     IMAGE f (relative_frontier s) SUBSET (relative_frontier t)
+     ==> ?c. homotopic_with (\z. T)
+                (relative_frontier s,relative_frontier t) f (\x. c)`,
+  let lemma1 = prove
+   (`!f:real^N->real^N s t.
+        subspace s /\ subspace t /\ dim s < dim t /\ s SUBSET t /\
+        f differentiable_on sphere(vec 0,&1) INTER s
+        ==> ~(IMAGE f (sphere(vec 0,&1) INTER s) = sphere(vec 0,&1) INTER t)`,
+    REPEAT STRIP_TAC THEN
+    ABBREV_TAC
+     `(g:real^N->real^N) =
+      \x. norm(x) % (f:real^N->real^N)(inv(norm x) % x)` THEN
+    SUBGOAL_THEN
+     `(g:real^N->real^N) differentiable_on s DELETE (vec 0)`
+    ASSUME_TAC THENL
+     [EXPAND_TAC "g" THEN MATCH_MP_TAC DIFFERENTIABLE_ON_MUL THEN
+      SIMP_TAC[o_DEF; DIFFERENTIABLE_ON_NORM; IN_DELETE] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC DIFFERENTIABLE_ON_COMPOSE THEN CONJ_TAC THENL
+       [MATCH_MP_TAC DIFFERENTIABLE_ON_MUL THEN
+        REWRITE_TAC[DIFFERENTIABLE_ON_ID] THEN
+        SUBGOAL_THEN
+         `lift o (\x:real^N. inv(norm x)) =
+          (lift o inv o drop) o (\x. lift(norm x))`
+        SUBST1_TAC THENL [REWRITE_TAC[o_DEF; LIFT_DROP]; ALL_TAC] THEN
+        MATCH_MP_TAC DIFFERENTIABLE_ON_COMPOSE THEN
+        SIMP_TAC[DIFFERENTIABLE_ON_NORM; IN_DELETE] THEN
+        MATCH_MP_TAC DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON THEN
+        SIMP_TAC[FORALL_IN_IMAGE; IN_DELETE; GSYM REAL_DIFFERENTIABLE_AT] THEN
+        REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN
+        MATCH_MP_TAC REAL_DIFFERENTIABLE_INV_ATREAL THEN
+        ASM_REWRITE_TAC[REAL_DIFFERENTIABLE_ID; NORM_EQ_0];
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            DIFFERENTIABLE_ON_SUBSET)) THEN
+        ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_SPHERE_0; IN_INTER;
+                     SUBSPACE_MUL; NORM_MUL; IN_DELETE] THEN
+        SIMP_TAC[REAL_ABS_INV; REAL_ABS_NORM; REAL_MUL_LINV; NORM_EQ_0]];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `IMAGE (g:real^N->real^N) (s DELETE vec 0) = t DELETE (vec 0)`
+    ASSUME_TAC THENL
+     [UNDISCH_TAC `IMAGE (f:real^N->real^N) (sphere (vec 0,&1) INTER s) =
+                   sphere (vec 0,&1) INTER t` THEN
+      REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_DELETE;
+                  IN_INTER; IN_SPHERE_0] THEN
+      EXPAND_TAC "g" THEN REWRITE_TAC[IN_IMAGE; IN_INTER; IN_SPHERE_0] THEN
+      SIMP_TAC[IN_DELETE; VECTOR_MUL_EQ_0; NORM_EQ_0] THEN
+      MATCH_MP_TAC(TAUT
+       `(p ==> r) /\ (p ==> q ==> s) ==> p /\ q ==> r /\ s`) THEN
+      CONJ_TAC THENL [ALL_TAC; DISCH_TAC] THEN
+      DISCH_THEN(fun th -> X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
+        MP_TAC(SPEC `inv(norm x) % x:real^N` th)) THEN
+      ASM_SIMP_TAC[SUBSPACE_MUL; NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM;
+                   REAL_MUL_LINV; NORM_EQ_0;
+                   NORM_ARITH `norm x = &1 ==> ~(x:real^N = vec 0)`] THEN
+      DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `norm(x:real^N) % y:real^N` THEN
+      ASM_SIMP_TAC[SUBSPACE_MUL; NORM_MUL; REAL_ABS_NORM; REAL_MUL_RID] THEN
+      ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; NORM_EQ_0] THEN
+      ASM_REWRITE_TAC[VECTOR_MUL_LID; VECTOR_MUL_EQ_0; NORM_EQ_0] THEN
+      ASM_SIMP_TAC[NORM_ARITH `norm x = &1 ==> ~(x:real^N = vec 0)`] THEN
+      UNDISCH_THEN `inv(norm x) % x = (f:real^N->real^N) y`
+       (SUBST1_TAC o SYM) THEN
+      ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; NORM_EQ_0] THEN
+      REWRITE_TAC[VECTOR_MUL_LID];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`t:real^N->bool`; `(:real^N)`]
+          DIM_SUBSPACE_ORTHOGONAL_TO_VECTORS) THEN
+    ASM_REWRITE_TAC[SUBSPACE_UNIV; DIM_UNIV; IN_UNIV; SUBSET_UNIV] THEN
+    ABBREV_TAC `t' = {y:real^N | !x. x IN t ==> orthogonal x y}` THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN `subspace(t':real^N->bool)` ASSUME_TAC THENL
+     [EXPAND_TAC "t'" THEN REWRITE_TAC[SUBSPACE_ORTHOGONAL_TO_VECTORS];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?fst snd. linear fst /\ linear snd /\
+                (!z. fst(z) IN t /\ snd z IN t' /\ fst z + snd z = z) /\
+                (!x y:real^N. x IN t /\ y IN t'
+                              ==> fst(x + y) = x /\ snd(x + y) = y)`
+    STRIP_ASSUME_TAC THENL
+     [MP_TAC(ISPEC `t:real^N->bool` ORTHOGONAL_SUBSPACE_DECOMP_EXISTS) THEN
+      REWRITE_TAC[SKOLEM_THM] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `fst:real^N->real^N` THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `snd:real^N->real^N` THEN
+      DISCH_THEN(MP_TAC o GSYM) THEN
+      ASM_SIMP_TAC[SPAN_OF_SUBSPACE; FORALL_AND_THM] THEN STRIP_TAC THEN
+      MATCH_MP_TAC(TAUT `r /\ (r ==> p /\ q /\ s) ==> p /\ q /\ r /\ s`) THEN
+      CONJ_TAC THENL
+       [EXPAND_TAC "t'" THEN REWRITE_TAC[IN_ELIM_THM] THEN
+        ASM_MESON_TAC[ORTHOGONAL_SYM];
+        DISCH_TAC] THEN
+      MATCH_MP_TAC(TAUT `r /\ (r ==> p /\ q) ==> p /\ q /\ r`) THEN
+      CONJ_TAC THENL
+       [REPEAT GEN_TAC THEN STRIP_TAC THEN
+        MATCH_MP_TAC ORTHOGONAL_SUBSPACE_DECOMP_UNIQUE THEN
+        MAP_EVERY EXISTS_TAC [`t:real^N->bool`; `t':real^N->bool`] THEN
+        ASM_SIMP_TAC[SPAN_OF_SUBSPACE] THEN ASM SET_TAC[];
+        DISCH_TAC] THEN
+      REWRITE_TAC[linear] THEN
+      MATCH_MP_TAC(TAUT `(p /\ r) /\ (q /\ s) ==> (p /\ q) /\ (r /\ s)`) THEN
+      REWRITE_TAC[AND_FORALL_THM] THEN CONJ_TAC THEN REPEAT GEN_TAC THEN
+      MATCH_MP_TAC ORTHOGONAL_SUBSPACE_DECOMP_UNIQUE THEN
+      MAP_EVERY EXISTS_TAC [`t:real^N->bool`; `t':real^N->bool`] THEN
+      ASM_SIMP_TAC[SPAN_OF_SUBSPACE; SUBSPACE_ADD; SUBSPACE_MUL] THEN
+      (CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+      ASM_REWRITE_TAC[GSYM VECTOR_ADD_LDISTRIB] THEN
+      ONCE_REWRITE_TAC[VECTOR_ARITH
+       `(x + y) + (x' + y'):real^N = (x + x') + (y + y')`] THEN
+      ASM_REWRITE_TAC[];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`\x:real^N. (g:real^N->real^N)(fst x) + snd x`;
+      `{x + y:real^N | x IN (s DELETE vec 0) /\ y IN t'}`]
+        NEGLIGIBLE_DIFFERENTIABLE_IMAGE_NEGLIGIBLE) THEN
+    REWRITE_TAC[LE_REFL; NOT_IMP] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC NEGLIGIBLE_LOWDIM THEN
+      MP_TAC(ISPECL [`s:real^N->bool`; `t':real^N->bool`] DIM_SUMS_INTER) THEN
+      ASM_REWRITE_TAC[IN_DELETE] THEN
+      FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (ARITH_RULE
+       `t' + t = n ==> s < t /\ d' <= d /\ i = 0
+           ==> d + i = s + t' ==> d' < n`)) THEN
+      ASM_REWRITE_TAC[DIM_EQ_0] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC DIM_SUBSET THEN SET_TAC[]; EXPAND_TAC "t'"] THEN
+      REWRITE_TAC[SUBSET; IN_INTER; IN_SING; IN_ELIM_THM] THEN
+      ASM_MESON_TAC[SUBSET; ORTHOGONAL_REFL];
+      MATCH_MP_TAC DIFFERENTIABLE_ON_ADD THEN
+      ASM_SIMP_TAC[DIFFERENTIABLE_ON_LINEAR] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC DIFFERENTIABLE_ON_COMPOSE THEN
+      ASM_SIMP_TAC[DIFFERENTIABLE_ON_LINEAR] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        DIFFERENTIABLE_ON_SUBSET)) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_GSPEC] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[SUBSET]) THEN ASM_SIMP_TAC[IN_DELETE];
+      SUBGOAL_THEN
+       `~negligible {x + y | x IN IMAGE (g:real^N->real^N) (s DELETE vec 0) /\
+                             y IN t'}`
+      MP_TAC THENL
+       [ASM_REWRITE_TAC[] THEN
+        SUBGOAL_THEN `negligible(t':real^N->bool)` MP_TAC THENL
+         [MATCH_MP_TAC NEGLIGIBLE_LOWDIM THEN ASM_ARITH_TAC;
+          REWRITE_TAC[TAUT `p ==> ~q <=> ~(p /\ q)`]] THEN
+        REWRITE_TAC[GSYM NEGLIGIBLE_UNION_EQ] THEN
+        MP_TAC NOT_NEGLIGIBLE_UNIV THEN MATCH_MP_TAC EQ_IMP THEN
+        AP_TERM_TAC THEN AP_TERM_TAC THEN
+        REWRITE_TAC[EXTENSION; IN_UNION; IN_UNIV; IN_ELIM_THM; IN_DELETE] THEN
+        X_GEN_TAC `z:real^N` THEN
+        REWRITE_TAC[TAUT `p \/ q <=> ~p ==> q`] THEN DISCH_TAC THEN
+        EXISTS_TAC `(fst:real^N->real^N) z` THEN
+        EXISTS_TAC `(snd:real^N->real^N) z` THEN
+        ASM_SIMP_TAC[] THEN ASM_MESON_TAC[VECTOR_ADD_LID];
+        REWRITE_TAC[CONTRAPOS_THM] THEN
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] NEGLIGIBLE_SUBSET) THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IMP_CONJ; RIGHT_FORALL_IMP_THM;
+                    FORALL_IN_IMAGE; IN_DELETE] THEN
+        X_GEN_TAC `x:real^N` THEN REPEAT DISCH_TAC THEN
+        X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+        REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `x + y:real^N` THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[SUBSET]) THEN ASM_SIMP_TAC[] THEN ASM
+        SET_TAC[]]]) in
+  let lemma2 = prove
+   (`!f:real^N->real^N s t.
+          subspace s /\ subspace t /\ dim s < dim t /\ s SUBSET t /\
+          f continuous_on sphere(vec 0,&1) INTER s /\
+          IMAGE f (sphere(vec 0,&1) INTER s) SUBSET sphere(vec 0,&1) INTER t
+          ==> ?c. homotopic_with (\x. T)
+                          (sphere(vec 0,&1) INTER s,sphere(vec 0,&1) INTER t)
+                          f (\x. c)`,
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`f:real^N->real^N`; `sphere(vec 0:real^N,&1) INTER s`;
+                   `&1 / &2`; `t:real^N->bool`;]
+          STONE_WEIERSTRASS_VECTOR_POLYNOMIAL_FUNCTION_SUBSPACE) THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ASM_SIMP_TAC[COMPACT_INTER_CLOSED; COMPACT_SPHERE; CLOSED_SUBSPACE] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[SUBSET; FORALL_IN_IMAGE]] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^N` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `!x. x IN sphere(vec 0,&1) INTER s ==> ~((g:real^N->real^N) x = vec 0)`
+    ASSUME_TAC THENL
+     [X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+      REWRITE_TAC[FORALL_IN_IMAGE; IN_SPHERE_0] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_SPHERE_0]) THEN
+      DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+      ASM_REWRITE_TAC[] THEN REWRITE_TAC[IN_INTER; IN_SPHERE_0] THEN
+      CONV_TAC NORM_ARITH;
+      ALL_TAC] THEN
+    SUBGOAL_THEN `(g:real^N->real^N) differentiable_on
+                  sphere(vec 0,&1) INTER s`
+    ASSUME_TAC THENL
+     [ASM_SIMP_TAC[DIFFERENTIABLE_ON_VECTOR_POLYNOMIAL_FUNCTION]; ALL_TAC] THEN
+    ABBREV_TAC `(h:real^N->real^N) = \x. inv(norm(g x)) % g x` THEN
+    SUBGOAL_THEN
+     `!x. x IN sphere(vec 0,&1) INTER s
+          ==> (h:real^N->real^N) x IN sphere(vec 0,&1) INTER t`
+    ASSUME_TAC THENL
+     [REPEAT STRIP_TAC THEN EXPAND_TAC "h" THEN
+      ASM_SIMP_TAC[SUBSPACE_MUL; IN_INTER; IN_SPHERE_0; NORM_MUL] THEN
+      REWRITE_TAC[REAL_ABS_INV; REAL_ABS_NORM] THEN
+      ASM_SIMP_TAC[REAL_MUL_LINV; NORM_EQ_0; GSYM IN_SPHERE_0];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `(h:real^N->real^N) differentiable_on sphere(vec 0,&1) INTER s`
+    ASSUME_TAC THENL
+     [EXPAND_TAC "h" THEN MATCH_MP_TAC DIFFERENTIABLE_ON_MUL THEN
+      ASM_SIMP_TAC[DIFFERENTIABLE_ON_VECTOR_POLYNOMIAL_FUNCTION; o_DEF] THEN
+      SUBGOAL_THEN
+       `(\x. lift(inv(norm((g:real^N->real^N) x)))) =
+        (lift o inv o drop) o (\x. lift(norm x)) o (g:real^N->real^N)`
+      SUBST1_TAC THENL [REWRITE_TAC[o_DEF; LIFT_DROP]; ALL_TAC] THEN
+      MATCH_MP_TAC DIFFERENTIABLE_ON_COMPOSE THEN CONJ_TAC THENL
+       [MATCH_MP_TAC DIFFERENTIABLE_ON_COMPOSE THEN
+        ASM_SIMP_TAC[DIFFERENTIABLE_ON_VECTOR_POLYNOMIAL_FUNCTION] THEN
+        MATCH_MP_TAC DIFFERENTIABLE_ON_NORM THEN
+        ASM_REWRITE_TAC[SET_RULE
+         `~(z IN IMAGE f s) <=> !x. x IN s ==> ~(f x = z)`];
+        MATCH_MP_TAC DIFFERENTIABLE_AT_IMP_DIFFERENTIABLE_ON THEN
+        REWRITE_TAC[GSYM REAL_DIFFERENTIABLE_AT] THEN
+        REWRITE_TAC[FORALL_IN_IMAGE; IN_SPHERE_0] THEN
+        X_GEN_TAC `x:real^N` THEN
+        ASM_CASES_TAC `x:real^N = vec 0` THEN
+        ASM_REWRITE_TAC[NORM_0; REAL_OF_NUM_EQ; ARITH_EQ] THEN DISCH_TAC THEN
+        REWRITE_TAC[GSYM REAL_DIFFERENTIABLE_AT; o_THM] THEN
+        GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN
+        MATCH_MP_TAC REAL_DIFFERENTIABLE_INV_ATREAL THEN
+        ASM_SIMP_TAC[REAL_DIFFERENTIABLE_ID; NORM_EQ_0; IN_SPHERE_0]];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?c. homotopic_with (\z. T)
+             (sphere(vec 0,&1) INTER s,sphere(vec 0,&1) INTER t)
+             (h:real^N->real^N) (\x. c)`
+    MP_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HOMOTOPIC_WITH_TRANS) THEN
+      SUBGOAL_THEN
+       `homotopic_with (\z. T)
+                       (sphere(vec 0:real^N,&1) INTER s,t DELETE (vec 0:real^N))
+                       f g`
+      MP_TAC THENL
+       [MATCH_MP_TAC HOMOTOPIC_WITH_LINEAR THEN
+        ASM_SIMP_TAC[CONTINUOUS_ON_VECTOR_POLYNOMIAL_FUNCTION] THEN
+        X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN REWRITE_TAC[SET_RULE
+          `s SUBSET t DELETE v <=> s SUBSET t /\ ~(v IN s)`] THEN
+        CONJ_TAC THENL
+         [REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+          ASM_SIMP_TAC[SUBSPACE_IMP_CONVEX] THEN ASM SET_TAC[];
+          DISCH_THEN(MP_TAC o MATCH_MP SEGMENT_BOUND) THEN
+          SUBGOAL_THEN
+           `(f:real^N->real^N) x IN sphere(vec 0,&1) /\
+            norm(f x - g x) < &1/ &2`
+          MP_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+          REWRITE_TAC[IN_SPHERE_0] THEN CONV_TAC NORM_ARITH];
+        DISCH_THEN(MP_TAC o
+          ISPECL [`\y:real^N. inv(norm y) % y`;
+                  `sphere(vec 0:real^N,&1) INTER t`] o
+          MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+          HOMOTOPIC_COMPOSE_CONTINUOUS_LEFT)) THEN
+        ASM_REWRITE_TAC[o_DEF] THEN ANTS_TAC THENL
+         [CONJ_TAC THENL
+           [MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+            REWRITE_TAC[o_DEF; CONTINUOUS_ON_ID] THEN
+            MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
+            SIMP_TAC[IN_DELETE; NORM_EQ_0] THEN
+            REWRITE_TAC[REWRITE_RULE[o_DEF] CONTINUOUS_ON_LIFT_NORM];
+            REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_DELETE; IN_INTER] THEN
+            ASM_SIMP_TAC[SUBSPACE_MUL; IN_SPHERE_0; NORM_MUL; REAL_ABS_MUL] THEN
+            SIMP_TAC[REAL_ABS_INV; REAL_ABS_NORM; REAL_MUL_LINV; NORM_EQ_0]];
+          MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_EQ) THEN
+          RULE_ASSUM_TAC(REWRITE_RULE
+           [SUBSET; IN_INTER; FORALL_IN_IMAGE; IN_SPHERE_0]) THEN
+          ASM_SIMP_TAC[IN_SPHERE_0; IN_INTER;
+                       REAL_INV_1; VECTOR_MUL_LID]]]] THEN
+    SUBGOAL_THEN
+     `?c. c IN (sphere(vec 0,&1) INTER t) DIFF
+               (IMAGE (h:real^N->real^N) (sphere(vec 0,&1) INTER s))`
+    MP_TAC THENL
+     [MATCH_MP_TAC(SET_RULE
+       `t SUBSET s /\ ~(t = s) ==> ?a. a IN s DIFF t`) THEN
+      CONJ_TAC THENL [ASM SET_TAC[]; MATCH_MP_TAC lemma1] THEN
+      ASM_REWRITE_TAC[];
+      REWRITE_TAC[LEFT_IMP_EXISTS_THM; IN_INTER; IN_DIFF; IN_IMAGE] THEN
+      REWRITE_TAC[SET_RULE
+       `~(?x. P x /\ x IN s /\ x IN t) <=>
+        (!x. x IN s INTER t ==> ~(P x))`] THEN
+      X_GEN_TAC `c:real^N` THEN STRIP_TAC] THEN
+    EXISTS_TAC `--c:real^N` THEN
+    SUBGOAL_THEN
+     `homotopic_with (\z. T)
+                     (sphere(vec 0:real^N,&1) INTER s,t DELETE (vec 0:real^N))
+                     h (\x. --c)`
+    MP_TAC THENL
+     [MATCH_MP_TAC HOMOTOPIC_WITH_LINEAR THEN
+      ASM_SIMP_TAC[DIFFERENTIABLE_IMP_CONTINUOUS_ON; CONTINUOUS_ON_CONST] THEN
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN REWRITE_TAC[SET_RULE
+        `s SUBSET t DELETE v <=> s SUBSET t /\ ~(v IN s)`] THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[SEGMENT_CONVEX_HULL] THEN MATCH_MP_TAC HULL_MINIMAL THEN
+        ASM_SIMP_TAC[SUBSPACE_IMP_CONVEX; INSERT_SUBSET; SUBSPACE_NEG] THEN
+        ASM SET_TAC[];
+        DISCH_TAC THEN MP_TAC(ISPECL
+         [`(h:real^N->real^N) x`; `vec 0:real^N`; `--c:real^N`]
+         MIDPOINT_BETWEEN) THEN
+        ASM_REWRITE_TAC[BETWEEN_IN_SEGMENT; DIST_0; NORM_NEG] THEN
+        SUBGOAL_THEN `((h:real^N->real^N) x) IN sphere(vec 0,&1) /\
+                      (c:real^N) IN sphere(vec 0,&1)`
+        MP_TAC THENL [ASM SET_TAC[]; SIMP_TAC[IN_SPHERE_0]] THEN
+        STRIP_TAC THEN REWRITE_TAC[midpoint; VECTOR_ARITH
+         `vec 0:real^N = inv(&2) % (x + --y) <=> x = y`] THEN
+        ASM SET_TAC[]];
+      DISCH_THEN(MP_TAC o
+        ISPECL [`\y:real^N. inv(norm y) % y`;
+                `sphere(vec 0:real^N,&1) INTER t`] o
+        MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+        HOMOTOPIC_COMPOSE_CONTINUOUS_LEFT)) THEN
+      ASM_REWRITE_TAC[o_DEF] THEN ANTS_TAC THENL
+       [CONJ_TAC THENL
+         [MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+          REWRITE_TAC[o_DEF; CONTINUOUS_ON_ID] THEN
+          MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
+          SIMP_TAC[IN_DELETE; NORM_EQ_0] THEN
+          REWRITE_TAC[REWRITE_RULE[o_DEF] CONTINUOUS_ON_LIFT_NORM];
+          REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_DELETE; IN_INTER] THEN
+          ASM_SIMP_TAC[SUBSPACE_MUL; IN_SPHERE_0; NORM_MUL; REAL_ABS_MUL] THEN
+          SIMP_TAC[REAL_ABS_INV; REAL_ABS_NORM; REAL_MUL_LINV; NORM_EQ_0]];
+        MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_EQ) THEN
+        RULE_ASSUM_TAC(REWRITE_RULE
+         [SUBSET; IN_INTER; FORALL_IN_IMAGE; IN_SPHERE_0]) THEN
+        ASM_SIMP_TAC[IN_SPHERE_0; IN_INTER; REAL_INV_1; VECTOR_MUL_LID;
+                     NORM_NEG]]]) in
+  let lemma3 = prove
+   (`!s:real^M->bool u:real^N->bool.
+          bounded s /\ convex s /\ subspace u /\ aff_dim s <= &(dim u)
+          ==> ?t. subspace t /\ t SUBSET u /\
+                  (~(s = {}) ==> aff_dim t = aff_dim s) /\
+                  (relative_frontier s) homeomorphic
+                  (sphere(vec 0,&1) INTER t)`,
+    REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^M->bool = {}` THENL
+     [STRIP_TAC THEN EXISTS_TAC `{vec 0:real^N}` THEN
+      ASM_REWRITE_TAC[SUBSPACE_TRIVIAL; RELATIVE_FRONTIER_EMPTY] THEN
+      ASM_SIMP_TAC[HOMEOMORPHIC_EMPTY;
+                   SET_RULE `s INTER {a} = {} <=> ~(a IN s)`;
+                   IN_SPHERE_0; NORM_0; SING_SUBSET; SUBSPACE_0] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV;
+      FIRST_X_ASSUM(X_CHOOSE_THEN `a:real^M` MP_TAC o
+          GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+      GEOM_ORIGIN_TAC `a:real^M` THEN
+      SIMP_TAC[AFF_DIM_DIM_0; HULL_INC; INT_OF_NUM_LE; GSYM DIM_UNIV] THEN
+      REPEAT STRIP_TAC] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP CHOOSE_SUBSPACE_OF_SUBSPACE) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real^N->bool` THEN
+    ASM_SIMP_TAC[SPAN_OF_SUBSPACE; AFF_DIM_DIM_SUBSPACE; INT_OF_NUM_EQ] THEN
+    STRIP_TAC THEN
+    TRANS_TAC HOMEOMORPHIC_TRANS
+     `relative_frontier(ball(vec 0:real^N,&1) INTER t)` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC HOMEOMORPHIC_RELATIVE_FRONTIERS_CONVEX_BOUNDED_SETS THEN
+      ASM_SIMP_TAC[CONVEX_INTER; BOUNDED_INTER; BOUNDED_BALL;
+                   SUBSPACE_IMP_CONVEX; CONVEX_BALL] THEN
+      ONCE_REWRITE_TAC[INTER_COMM] THEN
+      FIRST_ASSUM(ASSUME_TAC o MATCH_MP SUBSPACE_0) THEN
+      SUBGOAL_THEN `~(t INTER ball(vec 0:real^N,&1) = {})` ASSUME_TAC THENL
+       [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `vec 0:real^N` THEN
+        ASM_REWRITE_TAC[IN_INTER; CENTRE_IN_BALL; REAL_LT_01];
+        ASM_SIMP_TAC[AFF_DIM_CONVEX_INTER_OPEN; OPEN_BALL;
+                     SUBSPACE_IMP_CONVEX] THEN
+        ASM_SIMP_TAC[AFF_DIM_DIM_0; HULL_INC]];
+      MATCH_MP_TAC(MESON[HOMEOMORPHIC_REFL] `s = t ==> s homeomorphic t`) THEN
+      SIMP_TAC[GSYM FRONTIER_BALL; REAL_LT_01] THEN
+      MATCH_MP_TAC RELATIVE_FRONTIER_CONVEX_INTER_AFFINE THEN
+      ASM_SIMP_TAC[CONVEX_BALL; SUBSPACE_IMP_AFFINE;
+                   GSYM MEMBER_NOT_EMPTY] THEN
+      EXISTS_TAC `vec 0:real^N` THEN
+      ASM_SIMP_TAC[CENTRE_IN_BALL; INTERIOR_OPEN; OPEN_BALL;
+                   SUBSPACE_0; IN_INTER; REAL_LT_01]]) in
+    ONCE_REWRITE_TAC[MESON[] `(!a b c. P a b c) <=> (!b c a. P a b c)`] THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[IMP_IMP] THEN ONCE_REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
+    REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN REPEAT GEN_TAC THEN
+    ASM_CASES_TAC `s:real^M->bool = {}` THENL
+     [ASM_SIMP_TAC[HOMOTOPIC_WITH; RELATIVE_FRONTIER_EMPTY; PCROSS_EMPTY;
+                   NOT_IN_EMPTY; IMAGE_CLAUSES; CONTINUOUS_ON_EMPTY];
+      ALL_TAC] THEN
+    ASM_CASES_TAC `t:real^N->bool = {}` THEN
+    ASM_SIMP_TAC[AFF_DIM_EMPTY; GSYM INT_NOT_LE; AFF_DIM_GE] THEN
+    STRIP_TAC THEN
+    MP_TAC(ISPECL [`t:real^N->bool`; `(:real^N)`] lemma3) THEN
+    ASM_REWRITE_TAC[DIM_UNIV; SUBSPACE_UNIV; AFF_DIM_LE_UNIV] THEN
+    DISCH_THEN(X_CHOOSE_THEN `t':real^N->bool` STRIP_ASSUME_TAC) THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT) THEN
+    DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP
+      HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY_NULL th]) THEN
+    MP_TAC(ISPECL [`s:real^M->bool`; `t':real^N->bool`] lemma3) THEN
+    ASM_SIMP_TAC[GSYM AFF_DIM_DIM_SUBSPACE] THEN
+    ANTS_TAC THENL [ASM_INT_ARITH_TAC; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `s':real^N->bool` STRIP_ASSUME_TAC) THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT) THEN
+    DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP
+      HOMOTOPY_EQUIVALENT_COHOMOTOPIC_TRIVIALITY_NULL th]) THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC lemma2 THEN
+    ASM_SIMP_TAC[GSYM INT_OF_NUM_LT; GSYM AFF_DIM_DIM_SUBSPACE] THEN
+    ASM_INT_ARITH_TAC);;
+
+let INESSENTIAL_SPHEREMAP_LOWDIM = prove
+ (`!f:real^M->real^N a r b s.
+        dimindex(:M) < dimindex(:N) /\
+        f continuous_on sphere(a,r) /\
+        IMAGE f (sphere(a,r)) SUBSET (sphere(b,s))
+        ==> ?c. homotopic_with (\z. T) (sphere(a,r),sphere(b,s)) f (\x. c)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s <= &0` THEN
+  ASM_SIMP_TAC[NULLHOMOTOPIC_INTO_CONTRACTIBLE; CONTRACTIBLE_SPHERE] THEN
+  ASM_CASES_TAC `r <= &0` THEN
+  ASM_SIMP_TAC[NULLHOMOTOPIC_FROM_CONTRACTIBLE; CONTRACTIBLE_SPHERE] THEN
+  ASM_SIMP_TAC[GSYM FRONTIER_CBALL; INTERIOR_CBALL; BALL_EQ_EMPTY;
+               CONV_RULE(RAND_CONV SYM_CONV) (SPEC_ALL
+               RELATIVE_FRONTIER_NONEMPTY_INTERIOR)] THEN
+  STRIP_TAC THEN MATCH_MP_TAC INESSENTIAL_SPHEREMAP_LOWDIM_GEN THEN
+  ASM_REWRITE_TAC[CONVEX_CBALL; BOUNDED_CBALL; AFF_DIM_CBALL] THEN
+  ASM_REWRITE_TAC[GSYM REAL_NOT_LE; INT_OF_NUM_LT]);;
+
+let HOMEOMORPHIC_SPHERES_EQ,HOMOTOPY_EQUIVALENT_SPHERES_EQ =
+ (CONJ_PAIR o prove)
+ (`(!a:real^M b:real^N r s.
+        sphere(a,r) homeomorphic sphere(b,s) <=>
+        r < &0 /\ s < &0 \/ r = &0 /\ s = &0 \/
+        &0 < r /\ &0 < s /\ dimindex(:M) = dimindex(:N)) /\
+   (!a:real^M b:real^N r s.
+        sphere(a,r) homotopy_equivalent sphere(b,s) <=>
+        r < &0 /\ s < &0 \/ r = &0 /\ s = &0 \/
+        &0 < r /\ &0 < s /\ dimindex(:M) = dimindex(:N))`,
+  let lemma = prove
+   (`!a:real^M r b:real^N s.
+          dimindex(:M) < dimindex(:N) /\ &0 < r /\ &0 < s
+          ==> ~(sphere(a,r) homotopy_equivalent sphere(b,s))`,
+    REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o ISPEC `sphere(a:real^M,r)` o
+        MATCH_MP HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY) THEN
+    MATCH_MP_TAC(TAUT `~p /\ q ==> (p <=> q) ==> F`) THEN CONJ_TAC THENL
+     [SUBGOAL_THEN `~(sphere(a:real^M,r) = {})` MP_TAC THENL
+       [REWRITE_TAC[SPHERE_EQ_EMPTY] THEN ASM_REAL_ARITH_TAC;
+        REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; LEFT_IMP_EXISTS_THM]] THEN
+      X_GEN_TAC `c:real^M` THEN DISCH_TAC THEN
+      DISCH_THEN(MP_TAC o SPECL[`\a:real^M. a`; `(\a. c):real^M->real^M`]) THEN
+      SIMP_TAC[CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID;
+               IMAGE_ID; SUBSET_REFL] THEN
+      REWRITE_TAC[NOT_IMP] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      SUBGOAL_THEN `~(contractible(sphere(a:real^M,r)))` MP_TAC THENL
+       [REWRITE_TAC[CONTRACTIBLE_SPHERE] THEN ASM_REAL_ARITH_TAC;
+        REWRITE_TAC[contractible] THEN MESON_TAC[]];
+      MAP_EVERY X_GEN_TAC [`f:real^M->real^N`; `g:real^M->real^N`] THEN
+      STRIP_TAC THEN
+      MP_TAC(ISPEC `g:real^M->real^N` INESSENTIAL_SPHEREMAP_LOWDIM) THEN
+      MP_TAC(ISPEC `f:real^M->real^N` INESSENTIAL_SPHEREMAP_LOWDIM) THEN
+      ASM_REWRITE_TAC[IMP_IMP; AND_FORALL_THM] THEN DISCH_THEN
+       (MP_TAC o SPECL [`a:real^M`; `r:real`; `b:real^N`; `s:real`]) THEN
+      ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; IMP_CONJ; RIGHT_IMP_FORALL_THM] THEN
+      REPEAT GEN_TAC THEN REWRITE_TAC[IMP_IMP] THEN DISCH_THEN
+       (fun th -> CONJUNCTS_THEN (ASSUME_TAC o MATCH_MP
+                         HOMOTOPIC_WITH_IMP_SUBSET) th THEN
+                  MP_TAC th) THEN
+      MATCH_MP_TAC(MESON[HOMOTOPIC_WITH_TRANS; HOMOTOPIC_WITH_SYM]
+          `homotopic_with p (s,t) c d
+            ==> homotopic_with p (s,t) f c /\
+                homotopic_with p (s,t) g d
+                ==> homotopic_with p (s,t) f g`) THEN
+      REWRITE_TAC[HOMOTOPIC_CONSTANT_MAPS] THEN DISJ2_TAC THEN
+      MP_TAC(ISPECL [`b:real^N`; `s:real`] PATH_CONNECTED_SPHERE) THEN
+      ANTS_TAC THENL
+       [FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (ARITH_RULE
+         `m < n ==> 1 <= m ==> 2 <= n`)) THEN REWRITE_TAC[DIMINDEX_GE_1];
+        REWRITE_TAC[PATH_CONNECTED_IFF_PATH_COMPONENT] THEN
+        DISCH_THEN MATCH_MP_TAC THEN
+        SUBGOAL_THEN `~(sphere(a:real^M,r) = {})` MP_TAC THENL
+         [REWRITE_TAC[SPHERE_EQ_EMPTY] THEN ASM_REAL_ARITH_TAC;
+          ASM SET_TAC[]]]]) in
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN
+  MATCH_MP_TAC(TAUT
+   `(r ==> p) /\ (q ==> r) /\ (p ==> q) ==> (r <=> q) /\ (p <=> q)`) THEN
+  REWRITE_TAC[HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT] THEN
+  ASM_CASES_TAC `r < &0` THEN
+  ASM_SIMP_TAC[SPHERE_EMPTY; SPHERE_EQ_EMPTY;
+               HOMEOMORPHIC_EMPTY; HOMOTOPY_EQUIVALENT_EMPTY]
+  THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_CASES_TAC `s < &0` THEN
+  ASM_SIMP_TAC[SPHERE_EMPTY; SPHERE_EQ_EMPTY;
+               HOMEOMORPHIC_EMPTY; HOMOTOPY_EQUIVALENT_EMPTY]
+  THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_CASES_TAC `r = &0` THEN
+  ASM_SIMP_TAC[SPHERE_SING; REAL_LT_REFL; HOMEOMORPHIC_SING;
+               HOMOTOPY_EQUIVALENT_SING; CONTRACTIBLE_SPHERE;
+               ONCE_REWRITE_RULE[HOMOTOPY_EQUIVALENT_SYM]
+                   HOMOTOPY_EQUIVALENT_SING]
+  THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_CASES_TAC `s = &0` THEN
+  ASM_SIMP_TAC[SPHERE_SING; REAL_LT_REFL; HOMEOMORPHIC_SING;
+               HOMOTOPY_EQUIVALENT_SING; CONTRACTIBLE_SPHERE;
+               ONCE_REWRITE_RULE[HOMOTOPY_EQUIVALENT_SYM]
+                   HOMOTOPY_EQUIVALENT_SING]
+  THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  SUBGOAL_THEN `&0 < r /\ &0 < s` STRIP_ASSUME_TAC THENL
+   [ASM_REAL_ARITH_TAC; ASM_REWRITE_TAC[]] THEN
+  CONJ_TAC THENL
+   [DISCH_THEN(fun th ->
+      let t = `?a:real^M b:real^N. ~(sphere(a,r) homeomorphic sphere(b,s))` in
+      MP_TAC(DISCH t (GEOM_EQUAL_DIMENSION_RULE th (ASSUME t)))) THEN
+    ASM_SIMP_TAC[HOMEOMORPHIC_SPHERES] THEN MESON_TAC[];
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[ARITH_RULE `~(m:num = n) <=> m < n \/ n < m`] THEN
+    STRIP_TAC THENL [ALL_TAC; ONCE_REWRITE_TAC[HOMOTOPY_EQUIVALENT_SYM]] THEN
+    ASM_SIMP_TAC[lemma]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some technical lemmas about extending maps from cell complexes.           *)
+(* ------------------------------------------------------------------------- *)
+
+let EXTEND_MAP_CELL_COMPLEX_TO_SPHERE,
+    EXTEND_MAP_CELL_COMPLEX_TO_SPHERE_COFINITE = (CONJ_PAIR o prove)
+ (`(!f:real^M->real^N m s t.
+        FINITE m /\ (!c. c IN m ==> polytope c /\ aff_dim c < aff_dim t) /\
+        (!c1 c2. c1 IN m /\ c2 IN m
+                 ==> c1 INTER c2 face_of c1 /\ c1 INTER c2 face_of c2) /\
+        s SUBSET UNIONS m /\ closed s /\ convex t /\ bounded t /\
+        f continuous_on s /\ IMAGE f s SUBSET relative_frontier t
+        ==> ?g. g continuous_on UNIONS m /\
+                IMAGE g (UNIONS m) SUBSET relative_frontier t /\
+                !x. x IN s ==> g x = f x) /\
+   (!f:real^M->real^N m s t.
+        FINITE m /\ (!c. c IN m ==> polytope c /\ aff_dim c <= aff_dim t) /\
+        (!c1 c2. c1 IN m /\ c2 IN m
+                 ==> c1 INTER c2 face_of c1 /\ c1 INTER c2 face_of c2) /\
+        s SUBSET UNIONS m /\ closed s /\ convex t /\ bounded t /\
+        f continuous_on s /\ IMAGE f s SUBSET relative_frontier t
+        ==> ?k g. FINITE k /\ DISJOINT k s /\
+                  g continuous_on (UNIONS m DIFF k) /\
+                  IMAGE g (UNIONS m DIFF k) SUBSET relative_frontier t /\
+                  !x. x IN s ==> g x = f x)`,
+  let wemma = prove
+   (`!h:real^M->real^N k t f.
+          (!s. s IN f ==> ?g. g continuous_on s /\
+                              IMAGE g s SUBSET t /\
+                              !x. x IN s INTER k ==> g x = h x) /\
+          FINITE f /\ (!s. s IN f ==> closed s) /\
+          (!s t. s IN f /\ t IN f /\ ~(s = t) ==> (s INTER t) SUBSET k)
+          ==> ?g. g continuous_on (UNIONS f) /\
+                  IMAGE g (UNIONS f) SUBSET t /\
+                  !x. x IN (UNIONS f) INTER k ==> g x = h x`,
+    REPLICATE_TAC 3 GEN_TAC THEN
+    ONCE_REWRITE_TAC[TAUT `p /\ q /\ r ==> s <=> q ==> p /\ r ==> s`] THEN
+    MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+    REWRITE_TAC[UNIONS_0; IMAGE_CLAUSES; EMPTY_SUBSET; CONTINUOUS_ON_EMPTY;
+                INTER_EMPTY; NOT_IN_EMPTY] THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_INSERT] THEN
+    REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC; SUBSET_REFL] THEN
+    MAP_EVERY X_GEN_TAC [`s:real^M->bool`; `u:(real^M->bool)->bool`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC
+     (REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC)) THEN
+    ASM_SIMP_TAC[UNIONS_INSERT] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^N` STRIP_ASSUME_TAC) THEN
+    ASM_CASES_TAC `(s:real^M->bool) UNION UNIONS u = UNIONS u` THENL
+     [ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+    FIRST_X_ASSUM(X_CHOOSE_THEN `f:real^M->real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\x. if x IN s then (f:real^M->real^N) x else g x` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CASES THEN ASM_SIMP_TAC[CLOSED_UNIONS] THEN
+    ASM SET_TAC[]) in
+  let lemma = prove
+   (`!h:real^M->real^N k t f.
+          (!s. s IN f ==> ?g. g continuous_on s /\
+                              IMAGE g s SUBSET t /\
+                              !x. x IN s INTER k ==> g x = h x) /\
+          FINITE f /\ (!s. s IN f ==> closed s) /\
+          (!s t. s IN f /\ t IN f /\ ~(s SUBSET t) /\ ~(t SUBSET s)
+                 ==> (s INTER t) SUBSET k)
+          ==> ?g. g continuous_on (UNIONS f) /\
+                  IMAGE g (UNIONS f) SUBSET t /\
+                  !x. x IN (UNIONS f) INTER k ==> g x = h x`,
+    REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP UNIONS_MAXIMAL_SETS) THEN
+    MATCH_MP_TAC wemma THEN
+    ASM_SIMP_TAC[FINITE_RESTRICT; IN_ELIM_THM] THEN ASM SET_TAC[]) in
+  let zemma = prove
+   (`!f:real^M->real^N m n t.
+          FINITE m /\ (!c. c IN m ==> polytope c) /\
+          n SUBSET m /\ (!c. c IN m DIFF n ==> aff_dim c < aff_dim t) /\
+          (!c1 c2. c1 IN m /\ c2 IN m
+                   ==> (c1 INTER c2) face_of c1 /\ (c1 INTER c2) face_of c2) /\
+          convex t /\ bounded t /\
+          f continuous_on (UNIONS n) /\
+          IMAGE f (UNIONS n) SUBSET relative_frontier t
+          ==> ?g. g continuous_on (UNIONS m) /\
+                  IMAGE g (UNIONS m) SUBSET relative_frontier t /\
+                  (!x. x IN UNIONS n ==> g x = f x)`,
+    REPEAT STRIP_TAC THEN
+    ASM_CASES_TAC `m DIFF n:(real^M->bool)->bool = {}` THENL
+     [SUBGOAL_THEN `(UNIONS m:real^M->bool) SUBSET UNIONS n` ASSUME_TAC THENL
+       [ASM SET_TAC[]; EXISTS_TAC `f:real^M->real^N`] THEN
+      REWRITE_TAC[] THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ASM SET_TAC[]];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!i. &i <= aff_dim t
+          ==> ?g. g continuous_on
+                  (UNIONS
+                   (n UNION {d | ?c. c IN m /\ d face_of c /\
+                                      aff_dim d < &i})) /\
+                  IMAGE g (UNIONS
+                   (n UNION {d | ?c. c IN m /\ d face_of c /\
+                                      aff_dim d < &i}))
+                  SUBSET relative_frontier t /\
+                  (!x. x IN UNIONS n ==> g x = (f:real^M->real^N) x)`
+    MP_TAC THENL
+     [ALL_TAC;
+      MP_TAC(ISPEC `aff_dim(t:real^N->bool)` INT_OF_NUM_EXISTS) THEN
+      MATCH_MP_TAC(TAUT `q /\ (p ==> r) ==> (p <=> q) ==> r`) THEN
+      CONJ_TAC THENL
+       [ASM_MESON_TAC[AFF_DIM_GE; MEMBER_NOT_EMPTY;
+                      INT_ARITH `--(&1):int <= s /\ s < t ==> &0 <= t`];
+        ALL_TAC] THEN
+      DISCH_THEN(X_CHOOSE_TAC `i:num`) THEN
+      DISCH_THEN(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[INT_LE_REFL] THEN
+      SUBGOAL_THEN
+       `UNIONS (n UNION {d | ?c. c IN m /\ d face_of c /\ aff_dim d < &i}) =
+        UNIONS m:real^M->bool`
+       (fun th -> REWRITE_TAC[th]) THEN
+      FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+      MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+       [MATCH_MP_TAC UNIONS_MONO THEN REWRITE_TAC[IN_UNION] THEN
+        REWRITE_TAC[TAUT `p \/ q ==> r <=> (p ==> r) /\ (q ==> r)`] THEN
+        REWRITE_TAC[FORALL_AND_THM; FORALL_IN_GSPEC] THEN
+        CONJ_TAC THENL [ASM_MESON_TAC[SUBSET]; GEN_TAC] THEN
+        MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[FACE_OF_IMP_SUBSET];
+        MATCH_MP_TAC SUBSET_UNIONS THEN REWRITE_TAC[SUBSET; IN_UNION] THEN
+        X_GEN_TAC `d:real^M->bool` THEN DISCH_TAC THEN
+        ASM_CASES_TAC `(d:real^M->bool) IN n` THEN
+        ASM_SIMP_TAC[IN_ELIM_THM] THEN
+        EXISTS_TAC `d:real^M->bool` THEN
+        ASM_SIMP_TAC[FACE_OF_REFL; POLYTOPE_IMP_CONVEX] THEN
+        ASM SET_TAC[]]] THEN
+    MATCH_MP_TAC num_INDUCTION THEN CONJ_TAC THENL
+     [REWRITE_TAC[INT_ARITH `d < &0 <=> (--(&1) <= d ==> d:int = --(&1))`] THEN
+      REWRITE_TAC[AFF_DIM_GE; AFF_DIM_EQ_MINUS1] THEN
+      SUBGOAL_THEN
+       `{d:real^M->bool| ?c. c IN m /\ d face_of c /\ d = {}} = {{}}`
+       (fun th -> REWRITE_TAC[th])
+      THENL
+       [GEN_REWRITE_TAC I [EXTENSION] THEN X_GEN_TAC `d:real^M->bool` THEN
+        REWRITE_TAC[IN_SING; IN_ELIM_THM] THEN
+        ASM_CASES_TAC `d:real^M->bool = {}` THEN
+        ASM_REWRITE_TAC[EMPTY_FACE_OF] THEN ASM SET_TAC[];
+        REWRITE_TAC[UNIONS_UNION; UNIONS_1; UNION_EMPTY] THEN
+        ASM_MESON_TAC[]];
+      ALL_TAC] THEN
+    X_GEN_TAC `p:num` THEN REWRITE_TAC[GSYM INT_OF_NUM_SUC] THEN
+    REWRITE_TAC[INT_ARITH `p + &1 <= x <=> p:int < x`] THEN
+    DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+    ASM_SIMP_TAC[INT_LT_IMP_LE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `h:real^M->real^N` STRIP_ASSUME_TAC) THEN
+    REWRITE_TAC[INT_ARITH `x:int < p + &1 <=> x <= p`] THEN
+    SUBGOAL_THEN `~(t:real^N->bool = {})` ASSUME_TAC THENL
+     [ASM_MESON_TAC[AFF_DIM_EMPTY; INT_ARITH `~(&p:int < --(&1))`];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `~(relative_frontier t:real^N->bool = {})` ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[RELATIVE_FRONTIER_EQ_EMPTY] THEN DISCH_TAC THEN
+      MP_TAC(ISPEC `t:real^N->bool` AFFINE_BOUNDED_EQ_LOWDIM) THEN
+      ASM_REWRITE_TAC[] THEN ASM_INT_ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!d. d IN n UNION {d | ?c. c IN m /\ d face_of c /\ aff_dim d <= &p}
+          ==> ?g. (g:real^M->real^N) continuous_on d /\
+                  IMAGE g d SUBSET relative_frontier t /\
+                  !x. x IN d INTER
+                      UNIONS
+                    (n UNION {d | ?c. c IN m /\ d face_of c /\ aff_dim d < &p})
+                      ==> g x = h x`
+    MP_TAC THENL
+     [X_GEN_TAC `d:real^M->bool` THEN
+      ASM_CASES_TAC `(d:real^M->bool) SUBSET UNIONS
+                 (n UNION {d | ?c. c IN m /\ d face_of c /\ aff_dim d < &p})`
+      THENL
+       [DISCH_THEN(K ALL_TAC) THEN EXISTS_TAC `h:real^M->real^N` THEN
+        REWRITE_TAC[] THEN CONJ_TAC THENL
+         [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ASM SET_TAC[]];
+        ALL_TAC] THEN
+      ASM_CASES_TAC `?a:real^M. d = {a}` THENL
+       [FIRST_X_ASSUM(X_CHOOSE_THEN `a:real^M` SUBST_ALL_TAC) THEN
+        DISCH_THEN(K ALL_TAC) THEN ASM_SIMP_TAC[CONTINUOUS_ON_SING; SET_RULE
+         `~({a} SUBSET s) ==> ~(x IN {a} INTER s)`] THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE;
+                    FORALL_IN_INSERT; NOT_IN_EMPTY] THEN
+        MATCH_MP_TAC(MESON[] `(?c. P(\x. c)) ==> (?f. P f)`) THEN
+        ASM SET_TAC[];
+        ALL_TAC] THEN
+      SUBGOAL_THEN `~(d:real^M->bool = {})` ASSUME_TAC THENL
+       [ASM SET_TAC[]; ALL_TAC] THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+       `~(s SUBSET UNIONS f) ==> ~(s IN f)`)) THEN
+      REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP
+       (SET_RULE `~(d IN s UNION t) /\ d IN s UNION u
+                  ==> ~(d IN s) /\ d IN u DIFF t`)) THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+      DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE
+       `d IN
+        {d | ?c. c IN m /\ d face_of c /\ aff_dim d <= &p} DIFF
+        {d | ?c. c IN m /\ d face_of c /\ aff_dim d < &p}
+        ==> ?c. c IN m /\ d face_of c /\
+                (aff_dim d <= &p /\ ~(aff_dim d < &p))`)) THEN
+      REWRITE_TAC[INT_ARITH `d:int <= p /\ ~(d < p) <=> d = p`] THEN
+      DISCH_THEN(X_CHOOSE_THEN `c:real^M->bool` STRIP_ASSUME_TAC) THEN
+      MP_TAC(ISPECL [`h:real^M->real^N`; `relative_frontier d:real^M->bool`;
+        `t:real^N->bool`] NULLHOMOTOPIC_INTO_RELATIVE_FRONTIER_EXTENSION) THEN
+      ASM_REWRITE_TAC[CLOSED_RELATIVE_FRONTIER;
+                      RELATIVE_FRONTIER_EQ_EMPTY] THEN
+      SUBGOAL_THEN
+       `relative_frontier d SUBSET
+        UNIONS {e:real^M->bool | e face_of c /\ aff_dim e < &p}`
+      ASSUME_TAC THENL
+       [W(MP_TAC o PART_MATCH (lhs o rand) RELATIVE_FRONTIER_OF_POLYHEDRON o
+          lhand o snd) THEN
+        ANTS_TAC THENL
+         [ASM_MESON_TAC[POLYTOPE_IMP_POLYHEDRON; FACE_OF_POLYTOPE_POLYTOPE];
+          DISCH_THEN SUBST1_TAC] THEN
+        MATCH_MP_TAC SUBSET_UNIONS THEN
+        ASM_SIMP_TAC[SUBSET; FORALL_IN_GSPEC; IN_ELIM_THM; facet_of] THEN
+        X_GEN_TAC `f:real^M->bool` THEN REPEAT STRIP_TAC THENL
+         [ASM_MESON_TAC[FACE_OF_TRANS]; INT_ARITH_TAC];
+        ALL_TAC] THEN
+      ANTS_TAC THENL
+       [REPEAT CONJ_TAC THENL
+         [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN
+          ASM SET_TAC[];
+          ASM_MESON_TAC[AFFINE_BOUNDED_EQ_TRIVIAL; FACE_OF_POLYTOPE_POLYTOPE;
+                        POLYTOPE_IMP_BOUNDED];
+          ASM SET_TAC[]];
+        ALL_TAC] THEN
+      MATCH_MP_TAC(TAUT `p /\ (q ==> r) ==> (p <=> q) ==> r`) THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC INESSENTIAL_SPHEREMAP_LOWDIM_GEN THEN
+        ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+         [ASM_MESON_TAC[FACE_OF_POLYTOPE_POLYTOPE; POLYTOPE_IMP_CONVEX];
+          ASM_MESON_TAC[FACE_OF_POLYTOPE_POLYTOPE; POLYTOPE_IMP_BOUNDED];
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN
+          ASM SET_TAC[];
+          ASM SET_TAC[]];
+        MATCH_MP_TAC MONO_EXISTS] THEN
+      X_GEN_TAC `g:real^M->real^N` THEN STRIP_TAC THEN REPEAT CONJ_TAC THENL
+       [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNIV];
+        ASM SET_TAC[];
+        ALL_TAC] THEN
+      REWRITE_TAC[INTER_UNIONS] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+       (SET_RULE `(!x. x IN s ==> P x) ==> t SUBSET s
+                  ==> !x. x IN t ==> P x`)) THEN
+      REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC] THEN
+      X_GEN_TAC `e:real^M->bool` THEN DISCH_TAC THEN
+      MATCH_MP_TAC FACE_OF_SUBSET_RELATIVE_FRONTIER THEN CONJ_TAC THENL
+       [MATCH_MP_TAC(MESON[]
+         `(d INTER e) face_of d /\ (d INTER e) face_of e
+          ==> (d INTER e) face_of d`) THEN
+        MATCH_MP_TAC FACE_OF_INTER_SUBFACE THEN
+        EXISTS_TAC `c:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_UNION]) THEN
+        REWRITE_TAC[IN_ELIM_THM] THEN
+        STRIP_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+        ASM_MESON_TAC[FACE_OF_REFL; SUBSET; POLYTOPE_IMP_CONVEX];
+        REWRITE_TAC[SET_RULE `d INTER e = d <=> d SUBSET e`] THEN
+        DISCH_TAC THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_UNION]) THEN
+        REWRITE_TAC[IN_ELIM_THM] THEN
+        DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL [ASM SET_TAC[]; ALL_TAC] THEN
+        ASM_MESON_TAC[AFF_DIM_SUBSET; INT_NOT_LE]];
+      ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ] lemma)) THEN
+    ANTS_TAC THENL
+     [ALL_TAC;
+      MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN ASM SET_TAC[]] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[FINITE_UNION] THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+      MATCH_MP_TAC FINITE_SUBSET THEN
+      EXISTS_TAC `UNIONS {{d:real^M->bool | d face_of c} | c IN m}` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[FINITE_UNIONS; FORALL_IN_GSPEC] THEN
+        ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN ASM_SIMP_TAC[FINITE_IMAGE] THEN
+        ASM_MESON_TAC[FINITE_POLYTOPE_FACES];
+        REWRITE_TAC[UNIONS_GSPEC] THEN SET_TAC[]];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[IN_UNION; IN_ELIM_THM] THEN
+      ASM_MESON_TAC[FACE_OF_IMP_CLOSED; POLYTOPE_IMP_CLOSED;
+                    POLYTOPE_IMP_CONVEX; SUBSET];
+      ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`d:real^M->bool`; `e:real^M->bool`] THEN
+    REWRITE_TAC[IN_UNION; IN_ELIM_THM] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (DISJ_CASES_THEN2 ASSUME_TAC
+     (X_CHOOSE_THEN `c:real^M->bool` STRIP_ASSUME_TAC)) MP_TAC)
+    THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (DISJ_CASES_THEN2 ASSUME_TAC
+     (X_CHOOSE_THEN `k:real^M->bool` STRIP_ASSUME_TAC)) MP_TAC)
+    THENL [ASM SET_TAC[]; STRIP_TAC] THEN
+    REWRITE_TAC[UNIONS_UNION] THEN
+    MATCH_MP_TAC(SET_RULE `s SUBSET u ==> s SUBSET t UNION u`) THEN
+    MATCH_MP_TAC(SET_RULE `x IN s ==> x SUBSET UNIONS s`) THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN EXISTS_TAC `c:real^M->bool` THEN
+    ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `d INTER e face_of (d:real^M->bool) /\
+                  d INTER e face_of e`
+    STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[FACE_OF_INTER_SUBFACE]; ALL_TAC] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[FACE_OF_TRANS]; ALL_TAC] THEN
+    TRANS_TAC INT_LTE_TRANS `aff_dim(d:real^M->bool)` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC FACE_OF_AFF_DIM_LT THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[POLYTOPE_IMP_CONVEX; FACE_OF_IMP_CONVEX];
+      ASM SET_TAC[]]) in
+  let memma = prove
+   (`!h:real^M->real^N k t u f.
+          (!s. s IN f ==> ?a g. ~(a IN u) /\ g continuous_on (s DELETE a) /\
+                               IMAGE g (s DELETE a) SUBSET t /\
+                               !x. x IN s INTER k ==> g x = h x) /\
+          FINITE f /\ (!s. s IN f ==> closed s) /\
+          (!s t. s IN f /\ t IN f /\ ~(s = t) ==> (s INTER t) SUBSET k)
+          ==> ?c g. FINITE c /\ DISJOINT c u /\ CARD c <= CARD f /\
+                    g continuous_on (UNIONS f DIFF c) /\
+                    IMAGE g (UNIONS f DIFF c) SUBSET t /\
+                    !x. x IN (UNIONS f DIFF c) INTER k ==> g x = h x`,
+    REPLICATE_TAC 4 GEN_TAC THEN
+    ONCE_REWRITE_TAC[TAUT `p /\ q /\ r ==> s <=> q ==> p /\ r ==> s`] THEN
+    MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+    REWRITE_TAC[UNIONS_0; IMAGE_CLAUSES; EMPTY_SUBSET; CONTINUOUS_ON_EMPTY;
+                INTER_EMPTY; NOT_IN_EMPTY; EMPTY_DIFF] THEN
+    CONJ_TAC THENL
+     [MESON_TAC[DISJOINT_EMPTY; FINITE_EMPTY; CARD_CLAUSES; LE_REFL];
+      ALL_TAC] THEN
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_INSERT] THEN
+    REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC; SUBSET_REFL] THEN
+    MAP_EVERY X_GEN_TAC [`s:real^M->bool`; `u:(real^M->bool)->bool`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC
+     (REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC)) THEN
+    ASM_SIMP_TAC[UNIONS_INSERT] THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`c:real^M->bool`; `g:real^M->real^N`] THEN
+    STRIP_TAC THEN ASM_SIMP_TAC[CARD_CLAUSES] THEN
+    ASM_CASES_TAC `(s:real^M->bool) UNION UNIONS u = UNIONS u` THENL
+     [ASM_SIMP_TAC[] THEN ASM_MESON_TAC[ARITH_RULE `x <= y ==> x <= SUC y`];
+      ALL_TAC] THEN
+    FIRST_X_ASSUM(X_CHOOSE_THEN `a:real^M`
+     (X_CHOOSE_THEN `f:real^M->real^N` STRIP_ASSUME_TAC)) THEN
+    EXISTS_TAC `(a:real^M) INSERT c` THEN
+    ASM_SIMP_TAC[CARD_CLAUSES; FINITE_INSERT; RIGHT_EXISTS_AND_THM] THEN
+    REPEAT CONJ_TAC THENL [ASM SET_TAC[]; ASM_ARITH_TAC; ALL_TAC] THEN
+    EXISTS_TAC `\x. if x IN s then (f:real^M->real^N) x else g x` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+    EXISTS_TAC `(s DIFF ((a:real^M) INSERT c)) UNION
+                (UNIONS u DIFF ((a:real^M) INSERT c))` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[CLOSED_IN_CLOSED] THEN
+      EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[];
+      REWRITE_TAC[CLOSED_IN_CLOSED] THEN
+      EXISTS_TAC `UNIONS u:real^M->bool` THEN ASM_SIMP_TAC[CLOSED_UNIONS];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET));
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET));
+      ALL_TAC] THEN
+    ASM SET_TAC[]) in
+  let temma = prove
+   (`!h:real^M->real^N k t u f.
+          (!s. s IN f ==> ?a g. ~(a IN u) /\ g continuous_on (s DELETE a) /\
+                                IMAGE g (s DELETE a) SUBSET t /\
+                                !x. x IN s INTER k ==> g x = h x) /\
+          FINITE f /\ (!s. s IN f ==> closed s) /\
+          (!s t. s IN f /\ t IN f /\  ~(s SUBSET t) /\ ~(t SUBSET s)
+                 ==> (s INTER t) SUBSET k)
+          ==> ?c g. FINITE c /\ DISJOINT c u /\ CARD c <= CARD f /\
+                    g continuous_on (UNIONS f DIFF c) /\
+                    IMAGE g (UNIONS f DIFF c) SUBSET t /\
+                    !x. x IN (UNIONS f DIFF c) INTER k ==> g x = h x`,
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`h:real^M->real^N`; `k:real^M->bool`; `t:real^N->bool`;
+                   `u:real^M->bool`;
+                   `{t:real^M->bool | t IN f /\
+                                      (!u. u IN f ==> ~(t PSUBSET u))}`]
+          memma) THEN
+    ASM_SIMP_TAC[FINITE_RESTRICT; IN_ELIM_THM; UNIONS_MAXIMAL_SETS] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          LE_TRANS)) THEN
+    MATCH_MP_TAC CARD_SUBSET THEN
+    ASM_SIMP_TAC[] THEN SET_TAC[]) in
+  let bemma = prove
+   (`!f:real^M->real^N m n t.
+        FINITE m /\ (!c. c IN m ==> polytope c) /\
+        n SUBSET m /\ (!c. c IN m DIFF n ==> aff_dim c <= aff_dim t) /\
+        (!c1 c2. c1 IN m /\ c2 IN m
+                 ==> (c1 INTER c2) face_of c1 /\ (c1 INTER c2) face_of c2) /\
+        convex t /\ bounded t /\
+        f continuous_on (UNIONS n) /\
+        IMAGE f (UNIONS n) SUBSET relative_frontier t
+        ==> ?k g. FINITE k /\ DISJOINT k (UNIONS n) /\ CARD k <= CARD m /\
+                  g continuous_on (UNIONS m DIFF k) /\
+                  IMAGE g (UNIONS m DIFF k) SUBSET relative_frontier t /\
+                  (!x. x IN UNIONS n ==> g x = f x)`,
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`f:real^M->real^N`;
+         `n UNION {d:real^M->bool | ?c. c IN m DIFF n /\ d face_of c /\
+                                        aff_dim d < aff_dim(t:real^N->bool)}`;
+         `n:(real^M->bool)->bool`; `t:real^N->bool`] zemma) THEN
+    ASM_REWRITE_TAC[SUBSET_UNION; SET_RULE
+     `(n UNION m) DIFF n = m DIFF n`] THEN
+    SIMP_TAC[IN_DIFF; IN_ELIM_THM; LEFT_IMP_EXISTS_THM;
+             LEFT_AND_EXISTS_THM] THEN
+    ANTS_TAC THENL
+     [REPEAT CONJ_TAC THENL
+       [ASM_REWRITE_TAC[FINITE_UNION] THEN
+        CONJ_TAC THENL [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN
+        MATCH_MP_TAC FINITE_SUBSET THEN
+        EXISTS_TAC `UNIONS {{d:real^M->bool | d face_of c} | c IN m}` THEN
+        CONJ_TAC THENL
+         [REWRITE_TAC[FINITE_UNIONS; FORALL_IN_GSPEC] THEN
+          ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN ASM_SIMP_TAC[FINITE_IMAGE] THEN
+          ASM_MESON_TAC[FINITE_POLYTOPE_FACES];
+          REWRITE_TAC[UNIONS_GSPEC] THEN SET_TAC[]];
+        REWRITE_TAC[IN_UNION; IN_ELIM_THM] THEN
+        ASM_MESON_TAC[FACE_OF_POLYTOPE_POLYTOPE; SUBSET];
+        REWRITE_TAC[IN_UNION; IN_ELIM_THM] THEN
+        ASM_MESON_TAC[FACE_OF_INTER_SUBFACE; SUBSET; FACE_OF_REFL;
+                      POLYTOPE_IMP_CONVEX; FACE_OF_IMP_CONVEX]];
+      ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `h:real^M->real^N` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `!d. d IN m
+          ==> ?a g. ~(a IN UNIONS n) /\
+                    (g:real^M->real^N) continuous_on (d DELETE a) /\
+                    IMAGE g (d DELETE a) SUBSET relative_frontier t /\
+                    !x. x IN d INTER
+                         UNIONS
+                          (n UNION {d | ?c. (c IN m /\ ~(c IN n)) /\
+                                            d face_of c /\
+                                            aff_dim d < aff_dim t})
+                        ==> g x = h x`
+    MP_TAC THENL
+     [X_GEN_TAC `d:real^M->bool` THEN DISCH_TAC THEN
+      ASM_CASES_TAC `(d:real^M->bool) SUBSET
+                     UNIONS(n UNION {d | ?c. (c IN m /\ ~(c IN n)) /\
+                                             d face_of c /\
+                                     aff_dim d < aff_dim(t:real^N->bool)})`
+      THENL
+       [SUBGOAL_THEN `~(UNIONS n = (:real^M))` MP_TAC THENL
+         [MATCH_MP_TAC(MESON[NOT_BOUNDED_UNIV]
+           `bounded s ==> ~(s = UNIV)`) THEN
+          MATCH_MP_TAC BOUNDED_UNIONS THEN
+          ASM_MESON_TAC[POLYTOPE_IMP_BOUNDED; SUBSET; FINITE_SUBSET];
+          GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [EXTENSION]] THEN
+        REWRITE_TAC[IN_UNIV; NOT_FORALL_THM] THEN
+        MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^M` THEN
+        STRIP_TAC THEN EXISTS_TAC `h:real^M->real^N` THEN
+        ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+         [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET;
+                        SET_RULE `s SUBSET t ==> s DELETE a SUBSET t`];
+          ASM SET_TAC[]];
+        ALL_TAC] THEN
+      ASM_CASES_TAC `(d:real^M->bool) IN n` THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      DISJ_CASES_THEN MP_TAC (SPEC
+       `relative_interior(d:real^M->bool) = {}` EXCLUDED_MIDDLE)
+      THENL
+       [ASM_SIMP_TAC[RELATIVE_INTERIOR_EQ_EMPTY; POLYTOPE_IMP_CONVEX] THEN
+        ASM SET_TAC[];
+        REWRITE_TAC[GSYM MEMBER_NOT_EMPTY]] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^M` THEN STRIP_TAC THEN
+      SUBGOAL_THEN
+       `relative_frontier d SUBSET
+        UNIONS {e:real^M->bool | e face_of d /\
+                                 aff_dim e < aff_dim(t:real^N->bool)}`
+      ASSUME_TAC THENL
+       [W(MP_TAC o PART_MATCH (lhs o rand) RELATIVE_FRONTIER_OF_POLYHEDRON o
+          lhand o snd) THEN
+        ANTS_TAC THENL
+         [ASM_MESON_TAC[POLYTOPE_IMP_POLYHEDRON; FACE_OF_POLYTOPE_POLYTOPE];
+          DISCH_THEN SUBST1_TAC] THEN
+        MATCH_MP_TAC SUBSET_UNIONS THEN
+        ASM_SIMP_TAC[SUBSET; FORALL_IN_GSPEC; IN_ELIM_THM; facet_of] THEN
+        ASM_SIMP_TAC[INT_ARITH `d - &1:int < t <=> d <= t`; IN_DIFF];
+        ALL_TAC] THEN
+      MP_TAC(ISPECL [`d:real^M->bool`; `a:real^M`]
+          RELATIVE_FRONTIER_RETRACT_OF_PUNCTURED_AFFINE_HULL) THEN
+      ASM_SIMP_TAC[POLYTOPE_IMP_CONVEX; POLYTOPE_IMP_BOUNDED] THEN
+      REWRITE_TAC[retract_of; LEFT_IMP_EXISTS_THM; retraction] THEN
+      X_GEN_TAC `r:real^M->real^M` THEN STRIP_TAC THEN
+      EXISTS_TAC `(h:real^M->real^N) o (r:real^M->real^M)` THEN
+      REPEAT CONJ_TAC THENL
+       [REWRITE_TAC[IN_UNIONS] THEN
+        DISCH_THEN(X_CHOOSE_THEN `e:real^M->bool` STRIP_ASSUME_TAC) THEN
+        SUBGOAL_THEN
+         `e INTER d face_of e /\ e INTER d face_of (d:real^M->bool)`
+        MP_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+        DISCH_THEN(MP_TAC o MATCH_MP
+          (REWRITE_RULE[IMP_CONJ] FACE_OF_SUBSET_RELATIVE_FRONTIER) o
+          CONJUNCT2) THEN
+        REWRITE_TAC[NOT_IMP; relative_frontier] THEN
+        MP_TAC(ISPEC `d:real^M->bool` RELATIVE_INTERIOR_SUBSET) THEN
+        ASM SET_TAC[];
+        MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN
+        SIMP_TAC[HULL_SUBSET; SET_RULE
+                  `s SUBSET t ==> s DELETE a SUBSET t DELETE a`];
+        REWRITE_TAC[IMAGE_o] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `IMAGE h t SUBSET u ==> s SUBSET t ==> IMAGE h s SUBSET u`));
+        SIMP_TAC[INTER_UNIONS; o_THM] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+         (SET_RULE `(!x. x IN s ==> r x = x) ==> t SUBSET s
+                    ==> !x. x IN t ==> h(r x) = h x`)) THEN
+        REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC] THEN
+        X_GEN_TAC `e:real^M->bool` THEN DISCH_TAC THEN
+        MATCH_MP_TAC FACE_OF_SUBSET_RELATIVE_FRONTIER THEN
+        CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+        MATCH_MP_TAC(MESON[]
+         `(d INTER e) face_of d /\ (d INTER e) face_of e
+          ==> (d INTER e) face_of d`) THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_UNION]) THEN
+        REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THENL
+         [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+        MATCH_MP_TAC FACE_OF_INTER_SUBFACE THEN
+        MAP_EVERY EXISTS_TAC [`d:real^M->bool`; `c:real^M->bool`] THEN
+        ASM_SIMP_TAC[FACE_OF_REFL; POLYTOPE_IMP_CONVEX]] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `IMAGE r (h DELETE a) SUBSET t ==> d SUBSET h /\ t SUBSET u
+        ==> IMAGE r (d DELETE a) SUBSET u`)) THEN
+      REWRITE_TAC[HULL_SUBSET] THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ] temma)) THEN
+    ANTS_TAC THENL
+     [ALL_TAC;
+      REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM SET_TAC[]] THEN
+    ASM_SIMP_TAC[POLYTOPE_IMP_CLOSED] THEN
+    MAP_EVERY X_GEN_TAC [`d:real^M->bool`; `e:real^M->bool`] THEN
+    STRIP_TAC THEN REWRITE_TAC[UNIONS_UNION] THEN
+    ASM_CASES_TAC `(d:real^M->bool) IN n` THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC(SET_RULE `x IN s ==> x SUBSET t UNION UNIONS s`) THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN EXISTS_TAC `d:real^M->bool` THEN
+    ASM_REWRITE_TAC[] THEN
+    ASM_CASES_TAC `d INTER e:real^M->bool = d` THENL
+      [ASM SET_TAC[]; ALL_TAC] THEN
+    ASM_SIMP_TAC[] THEN TRANS_TAC INT_LTE_TRANS `aff_dim(d:real^M->bool)` THEN
+    ASM_SIMP_TAC[IN_DIFF] THEN MATCH_MP_TAC FACE_OF_AFF_DIM_LT THEN
+    ASM_MESON_TAC[POLYTOPE_IMP_CONVEX]) in
+  CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `compact(s:real^M->bool)` ASSUME_TAC THENL
+     [ASM_SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN
+      ASM_MESON_TAC[BOUNDED_SUBSET; BOUNDED_UNIONS; POLYTOPE_IMP_BOUNDED];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`f:real^M->real^N`; `s:real^M->bool`;
+                   `relative_frontier t:real^N->bool`]
+          NEIGHBOURHOOD_EXTENSION_INTO_ANR) THEN
+    ASM_SIMP_TAC[LEFT_FORALL_IMP_THM; ANR_RELATIVE_FRONTIER_CONVEX] THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`v:real^M->bool`; `g:real^M->real^N`] THEN
+    STRIP_TAC THEN
+    MP_TAC(ISPECL [`s:real^M->bool`; `(:real^M) DIFF v`]
+          SEPARATE_COMPACT_CLOSED) THEN
+    ASM_SIMP_TAC[GSYM OPEN_CLOSED; IN_DIFF; IN_UNIV] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    ONCE_REWRITE_TAC[TAUT `p /\ ~q ==> r <=> p /\ ~r ==> q`] THEN
+    REWRITE_TAC[REAL_NOT_LE; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`m:(real^M->bool)->bool`; `aff_dim(t:real^N->bool) - &1`;
+                   `d:real`] CELL_COMPLEX_SUBDIVISION_EXISTS) THEN
+    ASM_SIMP_TAC[INT_ARITH `x:int <= t - &1 <=> x < t`] THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:(real^M->bool)->bool` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL
+     [`g:real^M->real^N`; `n:(real^M->bool)->bool`;
+      `{c:real^M->bool | c IN n /\ c SUBSET v}`; `t:real^N->bool`]
+     zemma) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [ASM_SIMP_TAC[SUBSET_RESTRICT; IN_DIFF] THEN CONJ_TAC THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        ASM SET_TAC[];
+        ASM SET_TAC[]];
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `h:real^M->real^N` THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:real^M` THEN
+      DISCH_TAC THEN TRANS_TAC EQ_TRANS `(g:real^M->real^N) x` THEN
+      CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+      SUBGOAL_THEN `(x:real^M) IN UNIONS n` MP_TAC THENL
+       [ASM SET_TAC[]; ALL_TAC] THEN
+      REWRITE_TAC[IN_UNIONS] THEN MATCH_MP_TAC MONO_EXISTS THEN
+      X_GEN_TAC `c:real^M->bool` THEN STRIP_TAC THEN
+      ASM_REWRITE_TAC[IN_ELIM_THM] THEN REWRITE_TAC[SUBSET] THEN
+      X_GEN_TAC `y:real^M` THEN DISCH_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      EXISTS_TAC `x:real^M` THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC REAL_LET_TRANS THEN
+      EXISTS_TAC `diameter(c:real^M->bool)` THEN
+      ASM_SIMP_TAC[dist] THEN MATCH_MP_TAC DIAMETER_BOUNDED_BOUND THEN
+      ASM_SIMP_TAC[POLYTOPE_IMP_BOUNDED]];
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `compact(s:real^M->bool)` ASSUME_TAC THENL
+     [ASM_SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN
+      ASM_MESON_TAC[BOUNDED_SUBSET; BOUNDED_UNIONS; POLYTOPE_IMP_BOUNDED];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`f:real^M->real^N`; `s:real^M->bool`;
+                   `relative_frontier t:real^N->bool`]
+          NEIGHBOURHOOD_EXTENSION_INTO_ANR) THEN
+    ASM_SIMP_TAC[LEFT_FORALL_IMP_THM; ANR_RELATIVE_FRONTIER_CONVEX] THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`v:real^M->bool`; `g:real^M->real^N`] THEN
+    STRIP_TAC THEN
+    MP_TAC(ISPECL [`s:real^M->bool`; `(:real^M) DIFF v`]
+          SEPARATE_COMPACT_CLOSED) THEN
+    ASM_SIMP_TAC[GSYM OPEN_CLOSED; IN_DIFF; IN_UNIV] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    ONCE_REWRITE_TAC[TAUT `p /\ ~q ==> r <=> p /\ ~r ==> q`] THEN
+    REWRITE_TAC[REAL_NOT_LE; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `d:real` THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`m:(real^M->bool)->bool`; `aff_dim(t:real^N->bool)`;
+                   `d:real`] CELL_COMPLEX_SUBDIVISION_EXISTS) THEN
+    ASM_SIMP_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:(real^M->bool)->bool` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL
+     [`g:real^M->real^N`; `n:(real^M->bool)->bool`;
+      `{c:real^M->bool | c IN n /\ c SUBSET v}`; `t:real^N->bool`]
+     bemma) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [ASM_SIMP_TAC[SUBSET_RESTRICT; IN_DIFF] THEN CONJ_TAC THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        ASM SET_TAC[];
+        ASM SET_TAC[]];
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^M->bool` THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `h:real^M->real^N` THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+       [FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+         `DISJOINT k u ==> s SUBSET u ==> DISJOINT k s`)) THEN
+        REWRITE_TAC[SUBSET] THEN X_GEN_TAC `x:real^M` THEN DISCH_TAC;
+        X_GEN_TAC `x:real^M` THEN
+        DISCH_TAC THEN TRANS_TAC EQ_TRANS `(g:real^M->real^N) x` THEN
+        CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]] THEN
+      (SUBGOAL_THEN `(x:real^M) IN UNIONS n` MP_TAC THENL
+        [ASM SET_TAC[]; ALL_TAC] THEN
+       REWRITE_TAC[IN_UNIONS] THEN MATCH_MP_TAC MONO_EXISTS THEN
+       X_GEN_TAC `c:real^M->bool` THEN STRIP_TAC THEN
+       ASM_REWRITE_TAC[IN_ELIM_THM] THEN REWRITE_TAC[SUBSET] THEN
+       X_GEN_TAC `y:real^M` THEN DISCH_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+       EXISTS_TAC `x:real^M` THEN ASM_REWRITE_TAC[] THEN
+       MATCH_MP_TAC REAL_LET_TRANS THEN
+        EXISTS_TAC `diameter(c:real^M->bool)` THEN
+       ASM_SIMP_TAC[dist] THEN MATCH_MP_TAC DIAMETER_BOUNDED_BOUND THEN
+       ASM_SIMP_TAC[POLYTOPE_IMP_BOUNDED])]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Special cases and corollaries involving spheres.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE_SIMPLE = prove
+ (`!f:real^M->real^N s t u.
+        compact s /\ convex u /\ bounded u /\ aff_dim t <= aff_dim u /\
+        s SUBSET t /\ f continuous_on s /\ IMAGE f s SUBSET relative_frontier u
+        ==> ?k g. FINITE k /\ k SUBSET t /\ DISJOINT k s /\
+                  g continuous_on (t DIFF k) /\
+                  IMAGE g (t DIFF k) SUBSET relative_frontier u /\
+                  !x. x IN s ==> g x = f x`,
+  let lemma = prove
+   (`!f:A->B->bool P k.
+        INFINITE {x | P x} /\ FINITE k /\
+        (!x y. P x /\ P y /\ ~(x = y) ==> DISJOINT (f x) (f y))
+        ==> ?x. P x /\ DISJOINT k (f x)`,
+    REWRITE_TAC[INFINITE] THEN REPEAT STRIP_TAC THEN
+    REWRITE_TAC[SET_RULE `(?x. P x /\ DISJOINT k (f x)) <=>
+                          ~(!x. ?y. P x ==> y IN k /\ y IN f x)`] THEN
+    REWRITE_TAC[SKOLEM_THM] THEN
+    DISCH_THEN(X_CHOOSE_TAC `g:A->B`) THEN
+    MP_TAC(ISPECL [`g:A->B`; `{x:A | P x}`] FINITE_IMAGE_INJ_EQ) THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM; NOT_IMP] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+      (REWRITE_RULE[IMP_CONJ] FINITE_SUBSET)) THEN
+    ASM SET_TAC[]) in
+  SUBGOAL_THEN
+   `!f:real^M->real^N s t u.
+        compact s /\ convex u /\ bounded u /\ aff_dim t <= aff_dim u /\
+        s SUBSET t /\ f continuous_on s /\ IMAGE f s SUBSET relative_frontier u
+        ==> ?k g. FINITE k /\ DISJOINT k s /\
+                  g continuous_on (t DIFF k) /\
+                  IMAGE g (t DIFF k) SUBSET relative_frontier u /\
+                  !x. x IN s ==> g x = f x`
+  MP_TAC THENL
+   [ALL_TAC;
+    REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+    DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+    ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^M->real^N` THEN
+    DISCH_THEN(X_CHOOSE_THEN `k:real^M->bool` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `k INTER t:real^M->bool` THEN
+    ASM_SIMP_TAC[FINITE_INTER; INTER_SUBSET] THEN
+    REPEAT CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC; ASM SET_TAC[]] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN ASM SET_TAC[]] THEN
+  SUBGOAL_THEN
+   `!f:real^M->real^N s t u.
+        compact s /\ s SUBSET t /\ affine t /\
+        convex u /\ bounded u /\ aff_dim t <= aff_dim u /\
+        f continuous_on s /\ IMAGE f s SUBSET relative_frontier u
+        ==> ?k g. FINITE k /\ DISJOINT k s /\
+                  g continuous_on (t DIFF k) /\
+                  IMAGE g (t DIFF k) SUBSET relative_frontier u /\
+                  !x. x IN s ==> g x = f x`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+     `?k g. FINITE k /\ DISJOINT k s /\
+            g continuous_on (affine hull t DIFF k) /\
+            IMAGE g (affine hull t DIFF k) SUBSET relative_frontier u /\
+            !x. x IN s ==> g x = (f:real^M->real^N) x`
+    MP_TAC THENL
+     [FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_SIMP_TAC[AFF_DIM_AFFINE_HULL; AFFINE_AFFINE_HULL] THEN
+      TRANS_TAC SUBSET_TRANS `t:real^M->bool` THEN
+      ASM_REWRITE_TAC[HULL_SUBSET];
+      REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      CONJ_TAC THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET));
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+            SUBSET_TRANS)) THEN
+        MATCH_MP_TAC IMAGE_SUBSET] THEN
+      MATCH_MP_TAC(SET_RULE `s SUBSET t ==> s DIFF k SUBSET t DIFF k`) THEN
+      REWRITE_TAC[HULL_SUBSET]]] THEN
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^M->bool = {}` THENL
+   [ASM_CASES_TAC `relative_frontier(u:real^N->bool) = {}` THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[RELATIVE_FRONTIER_EQ_EMPTY]) THEN
+      UNDISCH_TAC `bounded(u:real^N->bool)` THEN
+      ASM_SIMP_TAC[AFFINE_BOUNDED_EQ_LOWDIM] THEN DISCH_TAC THEN
+      SUBGOAL_THEN `aff_dim(t:real^M->bool) <= &0` MP_TAC THENL
+       [ASM_INT_ARITH_TAC; ALL_TAC] THEN
+      SIMP_TAC[AFF_DIM_GE; INT_ARITH
+       `--(&1):int <= x ==> (x <= &0 <=> x = --(&1) \/ x = &0)`] THEN
+      REWRITE_TAC[AFF_DIM_EQ_MINUS1; AFF_DIM_EQ_0] THEN
+      DISCH_THEN(DISJ_CASES_THEN2 ASSUME_TAC (X_CHOOSE_TAC `a:real^M`)) THEN
+      EXISTS_TAC `{a:real^M}` THEN
+      ASM_REWRITE_TAC[DISJOINT_EMPTY; FINITE_SING; NOT_IN_EMPTY;
+                      EMPTY_DIFF; DIFF_EQ_EMPTY; IMAGE_CLAUSES;
+                      CONTINUOUS_ON_EMPTY; EMPTY_SUBSET];
+      EXISTS_TAC `{}:real^M->bool` THEN
+      FIRST_X_ASSUM(X_CHOOSE_TAC `y:real^N` o
+        GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+      ASM_SIMP_TAC[FINITE_EMPTY; DISJOINT_EMPTY; NOT_IN_EMPTY; DIFF_EMPTY] THEN
+      EXISTS_TAC `(\x. y):real^M->real^N` THEN
+      REWRITE_TAC[CONTINUOUS_ON_CONST] THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_IMP_BOUNDED) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP BOUNDED_SUBSET_CLOSED_INTERVAL_SYMMETRIC) THEN
+  REWRITE_TAC[INSERT_SUBSET] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^M` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`f:real^M->real^N`;
+    `{interval[--(b + vec 1):real^M,b + vec 1] INTER t}`;
+    `s:real^M->bool`; `u:real^N->bool`]
+   EXTEND_MAP_CELL_COMPLEX_TO_SPHERE_COFINITE) THEN
+  SUBGOAL_THEN
+   `interval[--b,b] SUBSET interval[--(b + vec 1):real^M,b + vec 1]`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[SUBSET_INTERVAL; VECTOR_ADD_COMPONENT; VECTOR_NEG_COMPONENT;
+                VEC_COMPONENT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FINITE_SING] THEN
+  REWRITE_TAC[FORALL_IN_INSERT; NOT_IN_EMPTY; IMP_IMP] THEN
+  REWRITE_TAC[INTER_IDEMPOT; UNIONS_1; FACE_OF_REFL_EQ; SUBSET_INTER] THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[HULL_SUBSET; COMPACT_IMP_CLOSED] THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC POLYTOPE_INTER_POLYHEDRON THEN
+      ASM_SIMP_TAC[POLYTOPE_INTERVAL; AFFINE_IMP_POLYHEDRON];
+      TRANS_TAC INT_LE_TRANS `aff_dim(t:real^M->bool)` THEN
+      ASM_SIMP_TAC[AFF_DIM_SUBSET; INTER_SUBSET];
+      ASM_SIMP_TAC[CONVEX_INTER; CONVEX_INTERVAL; AFFINE_IMP_CONVEX];
+      ASM SET_TAC[]];
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM]] THEN
+  MAP_EVERY X_GEN_TAC [`k:real^M->bool`; `g:real^M->real^N`] THEN
+  STRIP_TAC THEN EXISTS_TAC `k:real^M->bool` THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+   `?d:real. (&1 / &2 <= d /\ d <= &1) /\
+             DISJOINT k (frontier(interval[--(b + lambda i. d):real^M,
+                                             (b + lambda i. d)]))`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC lemma THEN
+    ASM_SIMP_TAC[INFINITE; FINITE_REAL_INTERVAL; REAL_NOT_LE] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    MATCH_MP_TAC REAL_WLOG_LT THEN REWRITE_TAC[] THEN
+    CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`x:real`; `y:real`] THEN REPEAT STRIP_TAC THEN
+    REWRITE_TAC[frontier] THEN MATCH_MP_TAC(SET_RULE
+     `c SUBSET i' ==> DISJOINT (c DIFF i) (c' DIFF i')`) THEN
+    REWRITE_TAC[INTERIOR_INTERVAL; CLOSURE_INTERVAL] THEN
+    SIMP_TAC[SUBSET_INTERVAL; VECTOR_NEG_COMPONENT; VECTOR_ADD_COMPONENT;
+             LAMBDA_BETA] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ABBREV_TAC `c:real^M = b + lambda i. d` THEN SUBGOAL_THEN
+   `interval[--b:real^M,b] SUBSET interval(--c,c) /\
+    interval[--b:real^M,b] SUBSET interval[--c,c] /\
+    interval[--c,c] SUBSET interval[--(b + vec 1):real^M,b + vec 1]`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[SUBSET_INTERVAL] THEN EXPAND_TAC "c" THEN REPEAT CONJ_TAC THEN
+    SIMP_TAC[VECTOR_NEG_COMPONENT; VECTOR_ADD_COMPONENT; LAMBDA_BETA] THEN
+    MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN MATCH_MP_TAC MONO_IMP THEN
+    REWRITE_TAC[VEC_COMPONENT] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  EXISTS_TAC
+   `(g:real^M->real^N) o
+    closest_point (interval[--c,c] INTER t)` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_CLOSEST_POINT THEN
+      ASM_SIMP_TAC[CONVEX_INTER; CLOSED_INTER; CLOSED_INTERVAL; CLOSED_AFFINE;
+        AFFINE_IMP_CONVEX; AFFINE_AFFINE_HULL; CONVEX_INTERVAL] THEN
+      ASM SET_TAC[];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET))];
+    REWRITE_TAC[IMAGE_o] THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+        SUBSET_TRANS)) THEN
+    MATCH_MP_TAC IMAGE_SUBSET;
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN REWRITE_TAC[o_THM] THEN
+    TRANS_TAC EQ_TRANS `(g:real^M->real^N) x` THEN
+    CONJ_TAC THENL [AP_TERM_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CLOSEST_POINT_SELF THEN
+    ASM_SIMP_TAC[IN_INTER; HULL_INC] THEN ASM SET_TAC[]] THEN
+  (REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_DIFF] THEN
+   X_GEN_TAC `x:real^M` THEN STRIP_TAC THEN CONJ_TAC THENL
+    [MATCH_MP_TAC(SET_RULE
+      `closest_point s x IN s /\ s SUBSET u ==> closest_point s x IN u`) THEN
+     CONJ_TAC THENL [MATCH_MP_TAC CLOSEST_POINT_IN_SET; ASM SET_TAC[]] THEN
+     ASM_SIMP_TAC[CLOSED_INTER; CLOSED_INTERVAL; CLOSED_AFFINE] THEN
+     ASM SET_TAC[];
+     ALL_TAC] THEN
+   ASM_CASES_TAC `x IN interval[--c:real^M,c]` THEN
+   ASM_SIMP_TAC[CLOSEST_POINT_SELF; IN_INTER] THEN
+   MATCH_MP_TAC(SET_RULE
+    `closest_point s x IN relative_frontier s /\
+     DISJOINT k (relative_frontier s)
+     ==> ~(closest_point s x IN k)`) THEN
+   CONJ_TAC THENL
+    [MATCH_MP_TAC CLOSEST_POINT_IN_RELATIVE_FRONTIER THEN
+     ASM_SIMP_TAC[CLOSED_INTER; CLOSED_AFFINE; CLOSED_INTERVAL] THEN
+     CONJ_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[IN_DIFF]] THEN CONJ_TAC THENL
+      [ALL_TAC; ASM_MESON_TAC[SUBSET; RELATIVE_INTERIOR_SUBSET; IN_INTER]] THEN
+     ONCE_REWRITE_TAC[INTER_COMM] THEN
+     W(MP_TAC o PART_MATCH (lhs o rand)
+       AFFINE_HULL_CONVEX_INTER_NONEMPTY_INTERIOR o rand o snd) THEN
+     ASM_SIMP_TAC[HULL_HULL; AFFINE_AFFINE_HULL; AFFINE_IMP_CONVEX] THEN
+     ASM_SIMP_TAC[HULL_P] THEN ANTS_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+     REWRITE_TAC[INTERIOR_INTERVAL] THEN ASM SET_TAC[];
+     W(MP_TAC o PART_MATCH (lhs o rand) RELATIVE_FRONTIER_CONVEX_INTER_AFFINE o
+       rand o snd) THEN
+     ANTS_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+     REWRITE_TAC[CONVEX_INTERVAL; AFFINE_AFFINE_HULL; INTERIOR_INTERVAL] THEN
+     ASM SET_TAC[]]));;
+
+let EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE_GEN = prove
+ (`!f:real^M->real^N s t u p.
+        compact s /\ convex u /\ bounded u /\
+        affine t /\ aff_dim t <= aff_dim u /\ s SUBSET t /\
+        f continuous_on s /\ IMAGE f s SUBSET relative_frontier u /\
+        (!c. c IN components(t DIFF s) /\ bounded c ==> ~(c INTER p = {}))
+        ==> ?k g. FINITE k /\ k SUBSET p /\ k SUBSET t /\ DISJOINT k s /\
+                  g continuous_on (t DIFF k) /\
+                  IMAGE g (t DIFF k) SUBSET relative_frontier u /\
+                  !x. x IN s ==> g x = f x`,
+  let lemma0 = prove
+   (`!u t s v. closed_in (subtopology euclidean u) v /\ t SUBSET u /\
+               s = v INTER t
+               ==> closed_in (subtopology euclidean t) s`,
+    REPEAT GEN_TAC THEN REWRITE_TAC[CLOSED_IN_CLOSED; LEFT_AND_EXISTS_THM] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN SET_TAC[]) in
+  let lemma1 = prove
+   (`!f:A->B->bool P k.
+        INFINITE {x | P x} /\ FINITE k /\
+        (!x y. P x /\ P y /\ ~(x = y) ==> DISJOINT (f x) (f y))
+        ==> ?x. P x /\ DISJOINT k (f x)`,
+    REWRITE_TAC[INFINITE] THEN REPEAT STRIP_TAC THEN
+    REWRITE_TAC[SET_RULE `(?x. P x /\ DISJOINT k (f x)) <=>
+                          ~(!x. ?y. P x ==> y IN k /\ y IN f x)`] THEN
+    REWRITE_TAC[SKOLEM_THM] THEN
+    DISCH_THEN(X_CHOOSE_TAC `g:A->B`) THEN
+    MP_TAC(ISPECL [`g:A->B`; `{x:A | P x}`] FINITE_IMAGE_INJ_EQ) THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM; NOT_IMP] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+      (REWRITE_RULE[IMP_CONJ] FINITE_SUBSET)) THEN
+    ASM SET_TAC[]) in
+  let lemma2 = prove
+   (`!f:real^M->real^N s t k p u.
+          FINITE k /\ affine u /\
+          f continuous_on ((u:real^M->bool) DIFF k) /\
+          IMAGE f ((u:real^M->bool) DIFF k) SUBSET t /\
+          (!c. c IN components((u:real^M->bool) DIFF s) /\ ~(c INTER k = {})
+               ==> ~(c INTER p = {})) /\
+          closed_in (subtopology euclidean u) s /\ DISJOINT k s /\ k SUBSET u
+          ==> ?g. g continuous_on ((u:real^M->bool) DIFF p) /\
+                  IMAGE g ((u:real^M->bool) DIFF p) SUBSET t /\
+                  !x. x IN s ==> g x = f x`,
+    REPEAT GEN_TAC THEN ASM_CASES_TAC `k:real^M->bool = {}` THENL
+     [ASM_REWRITE_TAC[DIFF_EMPTY] THEN REPEAT STRIP_TAC THEN
+      EXISTS_TAC `f:real^M->real^N` THEN REWRITE_TAC[] THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_DIFF]; ASM SET_TAC[]];
+      STRIP_TAC] THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN
+    SUBGOAL_THEN `~(((u:real^M->bool) DIFF s) INTER k = {})` MP_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o LAND_CONV o LAND_CONV)
+     [UNIONS_COMPONENTS] THEN
+    REWRITE_TAC[INTER_UNIONS; EMPTY_UNIONS; FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `co:real^M->bool` THEN STRIP_TAC THEN
+    SUBGOAL_THEN `locally connected (u:real^M->bool)` ASSUME_TAC THENL
+     [ASM_SIMP_TAC[AFFINE_IMP_CONVEX; CONVEX_IMP_LOCALLY_CONNECTED];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `!c. c IN components ((u:real^M->bool) DIFF s) /\ ~(c INTER k = {})
+          ==> ?a g. a IN c /\ a IN p /\
+                    g continuous_on (s UNION (c DELETE a)) /\
+                    IMAGE g (s UNION (c DELETE a)) SUBSET t /\
+                    !x. x IN s ==> g x = (f:real^M->real^N) x`
+    MP_TAC THENL
+     [X_GEN_TAC `c:real^M->bool` THEN STRIP_TAC THEN
+      FIRST_ASSUM(ASSUME_TAC o MATCH_MP IN_COMPONENTS_SUBSET) THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `c:real^M->bool`) THEN
+      ASM_REWRITE_TAC[] THEN REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^M` THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      SUBGOAL_THEN `open_in (subtopology euclidean u) (c:real^M->bool)`
+      MP_TAC THENL
+       [MATCH_MP_TAC OPEN_IN_TRANS THEN
+        EXISTS_TAC `u DIFF s:real^M->bool` THEN
+        ASM_SIMP_TAC[OPEN_IN_DIFF; OPEN_IN_REFL] THEN
+        MATCH_MP_TAC OPEN_IN_COMPONENTS_LOCALLY_CONNECTED THEN
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC LOCALLY_OPEN_SUBSET THEN
+        EXISTS_TAC `u:real^M->bool` THEN
+        ASM_SIMP_TAC[OPEN_IN_DIFF; OPEN_IN_REFL];
+        DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th)] THEN
+      REWRITE_TAC[OPEN_IN_CONTAINS_CBALL] THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `a:real^M`)) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+      SUBGOAL_THEN `ball(a:real^M,d) INTER u SUBSET c` ASSUME_TAC THENL
+       [ASM_MESON_TAC[BALL_SUBSET_CBALL; SUBSET_TRANS;
+                      SET_RULE `b SUBSET c ==> b INTER u SUBSET c INTER u`];
+        ALL_TAC] THEN
+      MP_TAC(ISPECL
+      [`ball(a:real^M,d) INTER u`; `c:real^M->bool`;
+        `s UNION c:real^M->bool`; `c INTER k:real^M->bool`]
+          HOMEOMORPHISM_GROUPING_POINTS_EXISTS_GEN) THEN
+      ASM_REWRITE_TAC[INTER_SUBSET; SUBSET_UNION; UNION_SUBSET] THEN
+      ANTS_TAC THENL
+       [REPEAT CONJ_TAC THENL
+         [MATCH_MP_TAC OPEN_IN_SUBSET_TRANS THEN
+          EXISTS_TAC `u:real^M->bool` THEN
+          ASM_SIMP_TAC[HULL_MINIMAL; HULL_SUBSET];
+          MP_TAC(ISPECL [`c:real^M->bool`; `u:real^M->bool`]
+             AFFINE_HULL_OPEN_IN) THEN
+          ASM_SIMP_TAC[HULL_P] THEN ASM SET_TAC[];
+          REWRITE_TAC[HULL_SUBSET];
+          ASM_MESON_TAC[IN_COMPONENTS_CONNECTED];
+          ASM_MESON_TAC[FINITE_SUBSET; INTER_SUBSET];
+          MATCH_MP_TAC OPEN_IN_SUBSET_TRANS THEN
+          EXISTS_TAC `u:real^M->bool` THEN
+          ASM_REWRITE_TAC[] THEN
+          ASM_MESON_TAC[OPEN_IN_OPEN_INTER; OPEN_BALL; INTER_COMM];
+          REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+          EXISTS_TAC `a:real^M` THEN REWRITE_TAC[CENTRE_IN_BALL] THEN
+          ASM SET_TAC[]];
+        REWRITE_TAC[IN_INTER; LEFT_IMP_EXISTS_THM]] THEN
+      MAP_EVERY X_GEN_TAC [`h:real^M->real^M`; `k:real^M->real^M`] THEN
+      REWRITE_TAC[homeomorphism] THEN STRIP_TAC THEN
+      MP_TAC(ISPECL [`cball(a:real^M,d) INTER u`; `a:real^M`]
+          RELATIVE_FRONTIER_RETRACT_OF_PUNCTURED_AFFINE_HULL) THEN
+      MP_TAC(ISPECL [`cball(a:real^M,d)`; `u:real^M->bool`]
+          RELATIVE_INTERIOR_CONVEX_INTER_AFFINE) THEN
+      MP_TAC(ISPECL [`cball(a:real^M,d)`; `u:real^M->bool`]
+          RELATIVE_FRONTIER_CONVEX_INTER_AFFINE) THEN
+      MP_TAC(ISPECL [`u:real^M->bool`; `cball(a:real^M,d)`]
+          (ONCE_REWRITE_RULE[INTER_COMM]
+             AFFINE_HULL_AFFINE_INTER_NONEMPTY_INTERIOR)) THEN
+      ASM_SIMP_TAC[CONVEX_CBALL; FRONTIER_CBALL; INTERIOR_CBALL] THEN
+      SUBGOAL_THEN `a IN ball(a:real^M,d) INTER u` ASSUME_TAC THENL
+       [ASM_REWRITE_TAC[CENTRE_IN_BALL; IN_INTER] THEN ASM SET_TAC[];
+        ALL_TAC] THEN
+      REPLICATE_TAC 3
+       (ANTS_TAC THENL [ASM SET_TAC[]; DISCH_THEN SUBST1_TAC]) THEN
+      ASM_SIMP_TAC[CONVEX_INTER; CONVEX_CBALL; AFFINE_IMP_CONVEX] THEN
+      ANTS_TAC THENL
+       [ASM_MESON_TAC[BOUNDED_SUBSET; INTER_SUBSET; BOUNDED_CBALL];
+        ALL_TAC] THEN
+      ASM_REWRITE_TAC[retract_of; retraction] THEN
+      DISCH_THEN(X_CHOOSE_THEN `r:real^M->real^M` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC
+       `(f:real^M->real^N) o (k:real^M->real^M) o
+        (\x. if x IN ball(a,d) then r x else x)` THEN
+      REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+       [ALL_TAC;
+        X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN REWRITE_TAC[o_THM] THEN
+        COND_CASES_TAC THENL
+         [ASM SET_TAC[]; AP_TERM_TAC THEN ASM SET_TAC[]]] THEN
+      ABBREV_TAC `j = \x:real^M. if x IN ball(a,d) then r x else x` THEN
+      SUBGOAL_THEN
+       `(j:real^M->real^M) continuous_on ((u:real^M->bool) DELETE a)`
+      ASSUME_TAC THENL
+       [EXPAND_TAC "j" THEN
+        SUBGOAL_THEN
+         `u DELETE (a:real^M) =
+          (cball(a,d) DELETE a) INTER u UNION
+          ((u:real^M->bool) DIFF ball(a,d))`
+         (fun th -> SUBST1_TAC th THEN
+                    MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN
+                    SUBST1_TAC(SYM th))
+        THENL
+         [MP_TAC(ISPECL [`a:real^M`; `d:real`] BALL_SUBSET_CBALL) THEN
+          ASM SET_TAC[];
+          ALL_TAC] THEN
+        REWRITE_TAC[IN_DIFF; IN_INTER; IN_DELETE; CONTINUOUS_ON_ID] THEN
+        REPEAT CONJ_TAC THENL
+         [ALL_TAC; ALL_TAC;
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN ASM SET_TAC[];
+          REWRITE_TAC[GSYM BALL_UNION_SPHERE] THEN ASM SET_TAC[]] THEN
+        REWRITE_TAC[CLOSED_IN_CLOSED] THENL
+         [EXISTS_TAC `cball(a:real^M,d)` THEN REWRITE_TAC[CLOSED_CBALL];
+          EXISTS_TAC `(:real^M) DIFF ball(a,d)` THEN
+          REWRITE_TAC[GSYM OPEN_CLOSED; OPEN_BALL]] THEN
+        MP_TAC(ISPECL [`a:real^M`; `d:real`] BALL_SUBSET_CBALL) THEN
+        MP_TAC(ISPECL [`a:real^M`; `d:real`] CENTRE_IN_BALL) THEN
+        ASM SET_TAC[];
+        ALL_TAC] THEN
+      SUBGOAL_THEN
+       `IMAGE (j:real^M->real^M) (s UNION c DELETE a) SUBSET
+        (s UNION c DIFF ball(a,d))`
+      ASSUME_TAC THENL
+       [EXPAND_TAC "j" THEN REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+        X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+        COND_CASES_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+        SUBGOAL_THEN `(r:real^M->real^M) x IN sphere(a,d)` MP_TAC THENL
+         [MP_TAC(ISPECL [`a:real^M`; `d:real`] CENTRE_IN_BALL) THEN
+          ASM SET_TAC[];
+          REWRITE_TAC[GSYM CBALL_DIFF_BALL] THEN ASM SET_TAC[]];
+        ALL_TAC] THEN
+      CONJ_TAC THENL
+       [REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC) THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET))
+        THENL [ASM SET_TAC[]; ASM SET_TAC[]; ALL_TAC];
+        ONCE_REWRITE_TAC[IMAGE_o] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+         (SET_RULE `IMAGE f u SUBSET t
+                    ==> s SUBSET u ==> IMAGE f s SUBSET t`))] THEN
+      REWRITE_TAC[IMAGE_o] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+        `s SUBSET u ==> IMAGE f u SUBSET t ==> IMAGE f s SUBSET t`)) THEN
+      REWRITE_TAC[SUBSET; IN_UNIV; IN_DIFF; FORALL_IN_IMAGE] THEN
+      ASM SET_TAC[];
+      ALL_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
+    MAP_EVERY X_GEN_TAC
+     [`a:(real^M->bool)->real^M`; `h:(real^M->bool)->real^M->real^N`] THEN
+    DISCH_TAC THEN MP_TAC(ISPECL
+     [`h:(real^M->bool)->real^M->real^N`;
+      `\c:real^M->bool. s UNION (c DELETE (a c))`;
+      `s UNION UNIONS
+       { c DELETE (a c) |
+         c IN components ((u:real^M->bool) DIFF s) /\ ~(c INTER k = {})}`;
+      `{c | c IN components ((u:real^M->bool) DIFF s) /\ ~(c INTER k = {})}`]
+     PASTING_LEMMA_EXISTS_CLOSED) THEN
+    SUBGOAL_THEN
+     `FINITE {c | c IN components((u:real^M->bool) DIFF s) /\
+                  ~(c INTER k = {})}`
+    ASSUME_TAC THENL
+     [MP_TAC(ISPECL
+       [`\c:real^M->bool. c INTER k`;
+        `{c | c IN components ((u:real^M->bool) DIFF s) /\ ~(c INTER k = {})}`]
+       FINITE_IMAGE_INJ_EQ) THEN
+      REWRITE_TAC[IN_ELIM_THM] THEN ANTS_TAC THENL
+       [MESON_TAC[COMPONENTS_EQ;
+                  SET_RULE
+                    `s INTER k = t INTER k /\ ~(s INTER k = {})
+                     ==> ~(s INTER t = {})`];
+        DISCH_THEN(SUBST1_TAC o SYM) THEN
+        REWRITE_TAC[GSYM SIMPLE_IMAGE; IN_ELIM_THM]] THEN
+      MP_TAC(ISPEC
+       `{c INTER k |c| c IN components((u:real^M->bool) DIFF s) /\
+                       ~(c INTER k = {})}`
+        FINITE_UNIONS) THEN
+      MATCH_MP_TAC(TAUT `p ==> (p <=> q /\ r) ==> q`) THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        FINITE_SUBSET)) THEN
+      REWRITE_TAC[UNIONS_GSPEC] THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM] THEN ANTS_TAC THENL
+     [REPEAT CONJ_TAC THENL
+       [REWRITE_TAC[UNIONS_GSPEC] THEN ASM SET_TAC[];
+        X_GEN_TAC `c:real^M->bool` THEN DISCH_TAC THEN ASM_SIMP_TAC[] THEN
+        MATCH_MP_TAC lemma0 THEN
+        MAP_EVERY EXISTS_TAC [`u:real^M->bool`; `s UNION c:real^M->bool`] THEN
+        REPEAT CONJ_TAC THENL
+         [MATCH_MP_TAC CLOSED_IN_UNION_COMPLEMENT_COMPONENT THEN
+          ASM_REWRITE_TAC[];
+          ASM_REWRITE_TAC[UNION_SUBSET; UNIONS_SUBSET; FORALL_IN_GSPEC] THEN
+          MESON_TAC[IN_COMPONENTS_SUBSET;
+                    SET_RULE `c SUBSET u DIFF s ==> c DELETE a SUBSET u`];
+          ASM_SIMP_TAC[CLOSED_UNION_COMPLEMENT_COMPONENT; UNIONS_GSPEC] THEN
+          MATCH_MP_TAC(SET_RULE
+           `~(a IN t) /\ c DELETE a SUBSET t
+            ==> s UNION c DELETE a = (s UNION c) INTER (s UNION t)`) THEN
+          CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+          REWRITE_TAC[IN_ELIM_THM; IN_DELETE] THEN
+          DISCH_THEN(X_CHOOSE_THEN `c':real^M->bool` STRIP_ASSUME_TAC) THEN
+          MP_TAC(ISPECL [`(u:real^M->bool) DIFF s`;
+                          `c:real^M->bool`; `c':real^M->bool`]
+            COMPONENTS_EQ) THEN
+          ASM_CASES_TAC `c':real^M->bool = c` THENL
+           [ASM_MESON_TAC[]; ALL_TAC] THEN
+          ASM SET_TAC[]];
+        MAP_EVERY X_GEN_TAC
+         [`c1:real^M->bool`; `c2:real^M->bool`; `x:real^M`] THEN
+        STRIP_TAC THEN ASM_CASES_TAC `c2:real^M->bool = c1` THEN
+        ASM_REWRITE_TAC[] THEN FIRST_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+          `x IN u INTER (s UNION c1 DELETE a) INTER (s UNION c2 DELETE b)
+           ==> (c1 INTER c2 = {}) ==> x IN s`)) THEN
+        ANTS_TAC THENL [ASM_MESON_TAC[COMPONENTS_EQ]; ASM_SIMP_TAC[]]];
+      DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^N` STRIP_ASSUME_TAC)] THEN
+    MP_TAC
+     (ISPECL [`\x. x IN s UNION
+                        UNIONS {c | c IN components((u:real^M->bool) DIFF s) /\
+                                    c INTER k = {}}`;
+              `f:real^M->real^N`;
+              `g:real^M->real^N`;
+              `s UNION
+               UNIONS {c | c IN components((u:real^M->bool) DIFF s) /\
+                           c INTER k = {}}`;
+              `s UNION
+               UNIONS { c DELETE (a c) |
+                        c IN components((u:real^M->bool) DIFF s) /\
+                        ~(c INTER k = {})}`]
+          CONTINUOUS_ON_CASES_LOCAL) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC lemma0 THEN EXISTS_TAC `u:real^M->bool` THEN
+        EXISTS_TAC `u DIFF
+                    UNIONS {c DELETE a c |
+                            c IN components ((u:real^M->bool) DIFF s) /\
+                            ~(c INTER k = {})}` THEN
+        REPEAT CONJ_TAC THENL
+          [MATCH_MP_TAC CLOSED_IN_DIFF THEN REWRITE_TAC[CLOSED_IN_REFL] THEN
+           MATCH_MP_TAC OPEN_IN_UNIONS THEN REWRITE_TAC[FORALL_IN_GSPEC] THEN
+           X_GEN_TAC `c:real^M->bool` THEN DISCH_TAC THEN
+           MATCH_MP_TAC OPEN_IN_DELETE THEN MATCH_MP_TAC OPEN_IN_TRANS THEN
+           EXISTS_TAC `u DIFF s:real^M->bool` THEN
+           ASM_SIMP_TAC[OPEN_IN_DIFF; OPEN_IN_REFL] THEN
+           MATCH_MP_TAC OPEN_IN_COMPONENTS_LOCALLY_CONNECTED THEN
+           ASM_REWRITE_TAC[] THEN MATCH_MP_TAC LOCALLY_OPEN_SUBSET THEN
+           EXISTS_TAC `u:real^M->bool` THEN
+           ASM_SIMP_TAC[OPEN_IN_DIFF; OPEN_IN_REFL];
+           ASM_REWRITE_TAC[UNION_SUBSET] THEN
+           REWRITE_TAC[UNIONS_SUBSET; IN_ELIM_THM] THEN
+           MESON_TAC[IN_COMPONENTS_SUBSET;
+                     SET_RULE `c SUBSET u DIFF s ==> c DELETE a SUBSET u /\
+                                                     c SUBSET u`];
+           REWRITE_TAC[SET_RULE
+            `(s UNION t) UNION (s UNION u) = (s UNION t) UNION u`] THEN
+           MATCH_MP_TAC(SET_RULE
+            `s SUBSET u /\ t INTER s = {}
+             ==> s = (u DIFF t) INTER (s UNION t)`) THEN
+           CONJ_TAC THENL
+            [ASM_REWRITE_TAC[UNION_SUBSET] THEN
+             REWRITE_TAC[UNIONS_SUBSET; IN_ELIM_THM] THEN
+             MESON_TAC[IN_COMPONENTS_SUBSET;
+                       SET_RULE `c SUBSET u DIFF s ==> c DELETE a SUBSET u /\
+                                                       c SUBSET u`];
+             ALL_TAC] THEN
+           REWRITE_TAC[EMPTY_UNION; SET_RULE
+            `c INTER (s UNION t) = (s INTER c) UNION (c INTER t)`] THEN
+           CONJ_TAC THENL
+            [MATCH_MP_TAC(SET_RULE
+              `t SUBSET UNIV DIFF s ==> s INTER t = {}`) THEN
+             REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC] THEN GEN_TAC THEN
+             DISCH_THEN(CONJUNCTS_THEN2
+               (MP_TAC o MATCH_MP IN_COMPONENTS_SUBSET)
+               MP_TAC) THEN ASM SET_TAC[];
+             REWRITE_TAC[INTER_UNIONS; EMPTY_UNIONS; FORALL_IN_GSPEC] THEN
+             X_GEN_TAC `c:real^M->bool` THEN STRIP_TAC THEN
+             X_GEN_TAC `c':real^M->bool` THEN STRIP_TAC THEN
+             MP_TAC(ISPECL [`(u:real^M->bool) DIFF s`;
+                            `c:real^M->bool`; `c':real^M->bool`]
+               COMPONENTS_EQ) THEN
+             ASM_CASES_TAC `c':real^M->bool = c` THENL
+              [ASM_MESON_TAC[]; ASM SET_TAC[]]]];
+        MATCH_MP_TAC lemma0 THEN EXISTS_TAC `u:real^M->bool` THEN
+        EXISTS_TAC
+         `UNIONS {s UNION c |c| c IN components ((u:real^M->bool) DIFF s) /\
+                                ~(c INTER k = {})}` THEN
+        REPEAT CONJ_TAC THENL
+         [MATCH_MP_TAC CLOSED_IN_UNIONS THEN REWRITE_TAC[FORALL_IN_GSPEC] THEN
+          ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+          ASM_SIMP_TAC[FINITE_IMAGE] THEN REPEAT STRIP_TAC THEN
+          MATCH_MP_TAC CLOSED_IN_UNION_COMPLEMENT_COMPONENT THEN
+          ASM_REWRITE_TAC[];
+          ASM_REWRITE_TAC[UNION_SUBSET] THEN
+          REWRITE_TAC[UNIONS_SUBSET; IN_ELIM_THM] THEN
+          MESON_TAC[IN_COMPONENTS_SUBSET;
+                    SET_RULE `c SUBSET u DIFF s ==> c DELETE a SUBSET u /\
+                                                    c SUBSET u`];
+          MATCH_MP_TAC(SET_RULE
+           `t SUBSET u /\ u INTER s SUBSET t ==> t = u INTER (s UNION t)`) THEN
+          CONJ_TAC THENL
+           [REWRITE_TAC[UNIONS_GSPEC] THEN ASM SET_TAC[]; ALL_TAC] THEN
+          MATCH_MP_TAC(SET_RULE
+           `u INTER t SUBSET s ==> u INTER (s UNION t) SUBSET s UNION v`) THEN
+          MATCH_MP_TAC(SET_RULE
+          `((UNIV DIFF s) INTER t) INTER u SUBSET s
+           ==> t INTER u SUBSET s`) THEN
+          GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o TOP_DEPTH_CONV)
+           [INTER_UNIONS] THEN
+          REWRITE_TAC[SET_RULE
+           `{g x | x IN {f y | P y}} = {g(f y) | P y}`] THEN
+          REWRITE_TAC[SET_RULE
+           `(UNIV DIFF s) INTER (s UNION c) = c DIFF s`] THEN
+          REWRITE_TAC[SET_RULE
+           `t INTER u SUBSET s <=> t INTER ((UNIV DIFF s) INTER u) = {}`] THEN
+          ONCE_REWRITE_TAC[INTER_UNIONS] THEN
+          REWRITE_TAC[EMPTY_UNIONS; FORALL_IN_GSPEC; INTER_UNIONS] THEN
+          X_GEN_TAC `c:real^M->bool` THEN STRIP_TAC THEN
+          X_GEN_TAC `c':real^M->bool` THEN STRIP_TAC THEN
+          MP_TAC(ISPECL [`(u:real^M->bool) DIFF s`;
+               `c:real^M->bool`; `c':real^M->bool`]
+            COMPONENTS_EQ) THEN
+          ASM_CASES_TAC `c':real^M->bool = c` THENL
+           [ASM_MESON_TAC[]; ASM SET_TAC[]]];
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        REWRITE_TAC[UNION_SUBSET] THEN
+        CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+        REWRITE_TAC[UNIONS_SUBSET; IN_ELIM_THM] THEN
+        GEN_TAC THEN
+        DISCH_THEN(CONJUNCTS_THEN2 (MP_TAC o MATCH_MP IN_COMPONENTS_SUBSET)
+          MP_TAC) THEN ASM SET_TAC[];
+        REWRITE_TAC[TAUT `p /\ ~p <=> F`] THEN X_GEN_TAC `x:real^M` THEN
+        REWRITE_TAC[IN_UNION] THEN
+        ASM_CASES_TAC `(x:real^M) IN s` THEN ASM_REWRITE_TAC[] THENL
+         [ASM SET_TAC[]; ALL_TAC] THEN
+        REWRITE_TAC[UNIONS_GSPEC; IN_ELIM_THM; IN_DELETE] THEN
+        DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `c:real^M->bool`)
+          (X_CHOOSE_TAC `c':real^M->bool`)) THEN
+        MP_TAC(ISPECL [`(u:real^M->bool) DIFF s`;
+                        `c:real^M->bool`; `c':real^M->bool`]
+            COMPONENTS_EQ) THEN
+        ASM_CASES_TAC `c':real^M->bool = c` THENL
+         [ASM_MESON_TAC[]; ASM SET_TAC[]]];
+      MATCH_MP_TAC(MESON[CONTINUOUS_ON_SUBSET]
+       `t SUBSET s /\ P f
+        ==> f continuous_on s ==> ?g. g continuous_on t /\ P g`) THEN
+      REWRITE_TAC[] THEN CONJ_TAC THENL
+       [REWRITE_TAC[SET_RULE
+         `(s UNION t) UNION (s UNION u) = s UNION (t UNION u)`] THEN
+        MATCH_MP_TAC(SET_RULE
+         `(u DIFF s) DIFF p SUBSET t
+          ==> u DIFF p SUBSET s UNION t`) THEN
+        GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [UNIONS_COMPONENTS] THEN
+        REWRITE_TAC[UNIONS_GSPEC] THEN ASM SET_TAC[];
+        SIMP_TAC[IN_UNION]] THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_DIFF; IN_UNION; IN_UNIV] THEN
+      X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+      ASM_CASES_TAC `(x:real^M) IN s` THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[IN_UNIONS; IN_ELIM_THM] THEN COND_CASES_TAC THENL
+       [ASM SET_TAC[]; ALL_TAC] THEN
+      SUBGOAL_THEN
+        `x IN ((u:real^M->bool) DIFF s)` MP_TAC THENL
+          [ASM SET_TAC[]; ALL_TAC] THEN
+      GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [UNIONS_COMPONENTS] THEN
+      REWRITE_TAC[IN_UNIONS] THEN
+      DISCH_THEN(X_CHOOSE_THEN `c:real^M->bool` STRIP_ASSUME_TAC) THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_EXISTS_THM]) THEN
+      DISCH_THEN(MP_TAC o SPEC `c:real^M->bool`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^M`; `c:real^M->bool`]) THEN
+      ASM_REWRITE_TAC[UNIONS_GSPEC] THEN ASM SET_TAC[]]) in
+  let lemma3 = prove
+   (`!f:real^M->real^N s t u p.
+          compact s /\ convex u /\ bounded u /\
+          affine t /\ aff_dim t <= aff_dim u /\ s SUBSET t /\
+          f continuous_on s /\ IMAGE f s SUBSET relative_frontier u /\
+          (!c. c IN components(t DIFF s) ==> ~(c INTER p = {}))
+          ==> ?k g. FINITE k /\ k SUBSET p /\ k SUBSET t /\ DISJOINT k s /\
+                    g continuous_on (t DIFF k) /\
+                    IMAGE g (t DIFF k) SUBSET relative_frontier u /\
+                    !x. x IN s ==> g x = f x`,
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`f:real^M->real^N`; `s:real^M->bool`;
+                   `t:real^M->bool`; `u:real^N->bool`]
+          EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE_SIMPLE) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`k:real^M->bool`; `g:real^M->real^N`] THEN
+    STRIP_TAC THEN
+    SUBGOAL_THEN
+     `!x. ?y. x IN k
+              ==> ?c. c IN components (t DIFF s:real^M->bool) /\
+                      x IN c /\ y IN c /\ y IN p`
+    MP_TAC THENL
+     [X_GEN_TAC `x:real^M` THEN REWRITE_TAC[RIGHT_EXISTS_IMP_THM] THEN
+      DISCH_TAC THEN
+      SUBGOAL_THEN `(x:real^M) IN (t DIFF s)` MP_TAC THENL
+       [ASM SET_TAC[]; ALL_TAC] THEN
+      GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [UNIONS_COMPONENTS] THEN
+      ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+      REWRITE_TAC[IN_UNIONS; RIGHT_EXISTS_AND_THM] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN ASM SET_TAC[];
+      REWRITE_TAC[SKOLEM_THM] THEN
+      DISCH_THEN(X_CHOOSE_THEN `h:real^M->real^M` (LABEL_TAC "*"))] THEN
+    EXISTS_TAC `IMAGE (h:real^M->real^M) k` THEN
+    MP_TAC(ISPECL
+     [`g:real^M->real^N`; `s:real^M->bool`;
+      `relative_frontier u:real^N->bool`; `k:real^M->bool`;
+      `IMAGE (h:real^M->real^M) k`; `t:real^M->bool`] lemma2) THEN
+    ASM_SIMP_TAC[AFFINE_AFFINE_HULL; FINITE_IMAGE] THEN ANTS_TAC THENL
+     [CONJ_TAC THENL
+       [X_GEN_TAC `c:real^M->bool` THEN STRIP_TAC THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+        ONCE_REWRITE_TAC[INTER_COMM] THEN
+        REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; EXISTS_IN_IMAGE; IN_INTER] THEN
+        MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x:real^M` THEN
+        STRIP_TAC THEN REMOVE_THEN "*" (MP_TAC o SPEC `x:real^M`) THEN
+        ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+        X_GEN_TAC `c':real^M->bool` THEN STRIP_TAC THEN
+        MP_TAC(ISPECL [`(t:real^M->bool) DIFF s`;
+                       `c:real^M->bool`; `c':real^M->bool`]
+          COMPONENTS_EQ) THEN
+        ASM_CASES_TAC `c':real^M->bool = c` THENL [ALL_TAC; ASM SET_TAC[]] THEN
+        ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+        MATCH_MP_TAC CLOSED_IN_SUBSET_TRANS THEN
+        EXISTS_TAC `(:real^M)` THEN
+        ASM_REWRITE_TAC[SUBTOPOLOGY_UNIV; GSYM CLOSED_IN] THEN
+        ASM_SIMP_TAC[COMPACT_IMP_CLOSED; SUBSET_UNIV]];
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `h:real^M->real^N` THEN
+      STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+      REWRITE_TAC[SET_RULE `DISJOINT s t <=> !x. x IN s ==> ~(x IN t)`] THEN
+      ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+      ASM_MESON_TAC[IN_COMPONENTS_SUBSET; SUBSET; IN_DIFF]]) in
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^M->bool = {}` THENL
+   [ASM_CASES_TAC `relative_frontier(u:real^N->bool) = {}` THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[RELATIVE_FRONTIER_EQ_EMPTY]) THEN
+      UNDISCH_TAC `bounded(u:real^N->bool)` THEN
+      ASM_SIMP_TAC[AFFINE_BOUNDED_EQ_LOWDIM] THEN DISCH_TAC THEN
+      SUBGOAL_THEN `aff_dim(t:real^M->bool) <= &0` MP_TAC THENL
+       [ASM_INT_ARITH_TAC; ALL_TAC] THEN
+      SIMP_TAC[AFF_DIM_GE; INT_ARITH
+       `--(&1):int <= x ==> (x <= &0 <=> x = --(&1) \/ x = &0)`] THEN
+      REWRITE_TAC[AFF_DIM_EQ_MINUS1; AFF_DIM_EQ_0] THEN
+      DISCH_THEN(DISJ_CASES_THEN2 ASSUME_TAC (X_CHOOSE_TAC `a:real^M`)) THENL
+       [EXISTS_TAC `{}:real^M->bool` THEN
+        ASM_REWRITE_TAC[EMPTY_DIFF; FINITE_EMPTY; CONTINUOUS_ON_EMPTY;
+                        IMAGE_CLAUSES; NOT_IN_EMPTY] THEN
+        SET_TAC[];
+        FIRST_X_ASSUM(MP_TAC o SPEC `{a:real^M}`) THEN
+        ASM_REWRITE_TAC[DIFF_EMPTY; IN_COMPONENTS_SELF] THEN
+        REWRITE_TAC[CONNECTED_SING; NOT_INSERT_EMPTY; BOUNDED_SING] THEN
+        DISCH_TAC THEN EXISTS_TAC `{a:real^M}` THEN
+        ASM_REWRITE_TAC[DIFF_EQ_EMPTY; CONTINUOUS_ON_EMPTY; NOT_IN_EMPTY;
+                        FINITE_SING; IMAGE_CLAUSES; EMPTY_SUBSET] THEN
+        ASM SET_TAC[]];
+      EXISTS_TAC `{}:real^M->bool` THEN
+      FIRST_X_ASSUM(X_CHOOSE_TAC `y:real^N` o
+        GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+      ASM_SIMP_TAC[FINITE_EMPTY; DISJOINT_EMPTY; NOT_IN_EMPTY; DIFF_EMPTY] THEN
+      EXISTS_TAC `(\x. y):real^M->real^N` THEN
+      REWRITE_TAC[CONTINUOUS_ON_CONST] THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_IMP_BOUNDED) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP BOUNDED_SUBSET_CLOSED_INTERVAL_SYMMETRIC) THEN
+  REWRITE_TAC[INSERT_SUBSET] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^M` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`f:real^M->real^N`; `s:real^M->bool`;
+    `t:real^M->bool`; `u:real^N->bool`;
+    `p UNION (UNIONS {c | c IN components (t DIFF s) /\ ~bounded c} DIFF
+              interval[--(b + vec 1):real^M,b + vec 1])`]
+        lemma3) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [X_GEN_TAC `c:real^M->bool` THEN STRIP_TAC THEN
+    ASM_CASES_TAC `bounded(c:real^M->bool)` THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `c:real^M->bool`) THEN
+      ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `~(c SUBSET interval[--(b + vec 1):real^M,b + vec 1])`
+    MP_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    ASM_MESON_TAC[BOUNDED_SUBSET; BOUNDED_INTERVAL];
+    ALL_TAC] THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`k:real^M->bool`; `g:real^M->real^N`] THEN
+  STRIP_TAC THEN
+  EXISTS_TAC `k INTER interval[--(b + vec 1):real^M,b + vec 1]` THEN
+  ASM_SIMP_TAC[FINITE_INTER; RIGHT_EXISTS_AND_THM] THEN
+  REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+  SUBGOAL_THEN
+   `interval[--b,b] SUBSET interval[--(b + vec 1):real^M,b + vec 1]`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[SUBSET_INTERVAL; VECTOR_ADD_COMPONENT; VECTOR_NEG_COMPONENT;
+                VEC_COMPONENT] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?d:real. (&1 / &2 <= d /\ d <= &1) /\
+             DISJOINT k (frontier(interval[--(b + lambda i. d):real^M,
+                                             (b + lambda i. d)]))`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC lemma1 THEN
+    ASM_SIMP_TAC[INFINITE; FINITE_REAL_INTERVAL; REAL_NOT_LE] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    MATCH_MP_TAC REAL_WLOG_LT THEN REWRITE_TAC[] THEN
+    CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`x:real`; `y:real`] THEN REPEAT STRIP_TAC THEN
+    REWRITE_TAC[frontier] THEN MATCH_MP_TAC(SET_RULE
+     `c SUBSET i' ==> DISJOINT (c DIFF i) (c' DIFF i')`) THEN
+    REWRITE_TAC[INTERIOR_INTERVAL; CLOSURE_INTERVAL] THEN
+    SIMP_TAC[SUBSET_INTERVAL; VECTOR_NEG_COMPONENT; VECTOR_ADD_COMPONENT;
+             LAMBDA_BETA] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ABBREV_TAC `c:real^M = b + lambda i. d` THEN SUBGOAL_THEN
+   `interval[--b:real^M,b] SUBSET interval(--c,c) /\
+    interval[--b:real^M,b] SUBSET interval[--c,c] /\
+    interval[--c,c] SUBSET interval[--(b + vec 1):real^M,b + vec 1]`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[SUBSET_INTERVAL] THEN EXPAND_TAC "c" THEN REPEAT CONJ_TAC THEN
+    SIMP_TAC[VECTOR_NEG_COMPONENT; VECTOR_ADD_COMPONENT; LAMBDA_BETA] THEN
+    MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN MATCH_MP_TAC MONO_IMP THEN
+    REWRITE_TAC[VEC_COMPONENT] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  EXISTS_TAC
+   `(g:real^M->real^N) o
+    closest_point (interval[--c,c] INTER t)` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_CLOSEST_POINT THEN
+      ASM_SIMP_TAC[CONVEX_INTER; CLOSED_INTER; CLOSED_INTERVAL; CLOSED_AFFINE;
+        AFFINE_IMP_CONVEX; AFFINE_AFFINE_HULL; CONVEX_INTERVAL] THEN
+      ASM SET_TAC[];
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET))];
+    REWRITE_TAC[IMAGE_o] THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+        SUBSET_TRANS)) THEN
+    MATCH_MP_TAC IMAGE_SUBSET;
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN REWRITE_TAC[o_THM] THEN
+    TRANS_TAC EQ_TRANS `(g:real^M->real^N) x` THEN
+    CONJ_TAC THENL [AP_TERM_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CLOSEST_POINT_SELF THEN
+    ASM_SIMP_TAC[IN_INTER; HULL_INC] THEN ASM SET_TAC[]] THEN
+  (REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_DIFF] THEN
+   X_GEN_TAC `x:real^M` THEN STRIP_TAC THEN CONJ_TAC THENL
+    [MATCH_MP_TAC(SET_RULE
+      `closest_point s x IN s /\ s SUBSET u ==> closest_point s x IN u`) THEN
+     CONJ_TAC THENL [MATCH_MP_TAC CLOSEST_POINT_IN_SET; ASM SET_TAC[]] THEN
+     ASM_SIMP_TAC[CLOSED_INTER; CLOSED_INTERVAL; CLOSED_AFFINE] THEN
+     ASM SET_TAC[];
+     ALL_TAC] THEN
+   ASM_CASES_TAC `x IN interval[--c:real^M,c]` THEN
+   ASM_SIMP_TAC[CLOSEST_POINT_SELF; IN_INTER] THENL
+    [ASM SET_TAC[]; ALL_TAC] THEN
+   MATCH_MP_TAC(SET_RULE
+    `closest_point s x IN relative_frontier s /\
+     DISJOINT k (relative_frontier s)
+     ==> ~(closest_point s x IN k)`) THEN
+   CONJ_TAC THENL
+    [MATCH_MP_TAC CLOSEST_POINT_IN_RELATIVE_FRONTIER THEN
+     ASM_SIMP_TAC[CLOSED_INTER; CLOSED_AFFINE; CLOSED_INTERVAL] THEN
+     CONJ_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[IN_DIFF]] THEN CONJ_TAC THENL
+      [ALL_TAC; ASM_MESON_TAC[SUBSET; RELATIVE_INTERIOR_SUBSET; IN_INTER]] THEN
+     ONCE_REWRITE_TAC[INTER_COMM] THEN
+     W(MP_TAC o PART_MATCH (lhs o rand)
+       AFFINE_HULL_CONVEX_INTER_NONEMPTY_INTERIOR o rand o snd) THEN
+     ASM_SIMP_TAC[HULL_HULL; AFFINE_AFFINE_HULL; AFFINE_IMP_CONVEX] THEN
+     ASM_SIMP_TAC[HULL_P] THEN ANTS_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+     REWRITE_TAC[INTERIOR_INTERVAL] THEN ASM SET_TAC[];
+     W(MP_TAC o PART_MATCH (lhs o rand) RELATIVE_FRONTIER_CONVEX_INTER_AFFINE o
+       rand o snd) THEN
+     ANTS_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+     REWRITE_TAC[CONVEX_INTERVAL; AFFINE_AFFINE_HULL; INTERIOR_INTERVAL] THEN
+     ASM SET_TAC[]]));;
+
+let EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE = prove
+ (`!f:real^M->real^N s t a r p.
+        compact s /\ affine t /\ aff_dim t <= &(dimindex(:N)) /\ s SUBSET t /\
+        &0 <= r /\ f continuous_on s /\ IMAGE f s SUBSET sphere(a,r) /\
+        (!c. c IN components(t DIFF s) /\ bounded c ==> ~(c INTER p = {}))
+        ==> ?k g. FINITE k /\ k SUBSET p /\ k SUBSET t /\ DISJOINT k s /\
+                  g continuous_on (t DIFF k) /\
+                  IMAGE g (t DIFF k) SUBSET sphere(a,r) /\
+                  !x. x IN s ==> g x = f x`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `r = &0` THENL
+   [ASM_SIMP_TAC[SPHERE_SING] THEN STRIP_TAC THEN
+    EXISTS_TAC `{}:real^M->bool` THEN
+    EXISTS_TAC `(\x. a):real^M->real^N` THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST; FINITE_EMPTY] THEN ASM SET_TAC[];
+    MP_TAC(ISPECL [`a:real^N`; `r:real`] RELATIVE_FRONTIER_CBALL) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+    STRIP_TAC THEN MATCH_MP_TAC EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE_GEN THEN
+    ASM_REWRITE_TAC[CONVEX_CBALL; BOUNDED_CBALL; AFF_DIM_CBALL] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC]);;
+
+let EXTEND_MAP_UNIV_TO_SPHERE_COFINITE = prove
+ (`!f:real^M->real^N s a r p.
+     dimindex(:M) <= dimindex(:N) /\ &0 <= r /\
+     compact s /\ f continuous_on s /\ IMAGE f s SUBSET sphere(a,r) /\
+     (!c. c IN components((:real^M) DIFF s) /\ bounded c
+          ==> ~(c INTER p = {}))
+     ==> ?k g. FINITE k /\ k SUBSET p /\ DISJOINT k s /\
+               g continuous_on ((:real^M) DIFF k) /\
+               IMAGE g ((:real^M) DIFF k) SUBSET sphere(a,r) /\
+               !x. x IN s ==> g x = f x`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `s:real^M->bool`; `(:real^M)`;
+                 `a:real^N`; `r:real`; `p:real^M->bool`]
+        EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE) THEN
+  ASM_REWRITE_TAC[AFFINE_UNIV; SUBSET_UNIV; AFF_DIM_UNIV; INT_OF_NUM_LE]);;
+
+let EXTEND_MAP_UNIV_TO_SPHERE_NO_BOUNDED_COMPONENT = prove
+ (`!f:real^M->real^N s a r.
+     dimindex(:M) <= dimindex(:N) /\ &0 <= r /\
+     compact s /\ f continuous_on s /\ IMAGE f s SUBSET sphere(a,r) /\
+     (!c. c IN components((:real^M) DIFF s) ==> ~bounded c)
+     ==> ?g. g continuous_on (:real^M) /\
+             IMAGE g (:real^M) SUBSET sphere(a,r) /\
+             !x. x IN s ==> g x = f x`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `s:real^M->bool`;  `a:real^N`; `r:real`;
+                 `{}:real^M->bool`] EXTEND_MAP_UNIV_TO_SPHERE_COFINITE) THEN
+  ASM_SIMP_TAC[IMP_CONJ; SUBSET_EMPTY; RIGHT_EXISTS_AND_THM] THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> q /\ p /\ r`] THEN
+  REWRITE_TAC[UNWIND_THM2; FINITE_EMPTY; DISJOINT_EMPTY; DIFF_EMPTY] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[]);;
+
+let EXTEND_MAP_SPHERE_TO_SPHERE_GEN = prove
+ (`!f:real^M->real^N c s t.
+        closed c /\ c SUBSET relative_frontier s /\ convex s /\ bounded s /\
+        convex t /\ bounded t /\ aff_dim s <= aff_dim t /\
+        f continuous_on c /\ IMAGE f c SUBSET relative_frontier t
+         ==> ?g. g continuous_on (relative_frontier s) /\
+                 IMAGE g (relative_frontier s) SUBSET relative_frontier t /\
+                 !x. x IN c ==> g x = f x`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?p:real^M->bool. polytope p /\ aff_dim p = aff_dim(s:real^M->bool)`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC CHOOSE_POLYTOPE THEN
+    ASM_REWRITE_TAC[AFF_DIM_GE; AFF_DIM_LE_UNIV];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`s:real^M->bool`; `p:real^M->bool`]
+        HOMEOMORPHIC_RELATIVE_FRONTIERS_CONVEX_BOUNDED_SETS) THEN
+  ASM_SIMP_TAC[POLYTOPE_IMP_CONVEX; POLYTOPE_IMP_BOUNDED; homeomorphic] THEN
+  REWRITE_TAC[HOMEOMORPHISM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`h:real^M->real^M`; `k:real^M->real^M`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`(f:real^M->real^N) o (k:real^M->real^M)`;
+    `{f:real^M->bool | f face_of p /\ ~(f = p)}`;
+    `IMAGE (h:real^M->real^M) c`;
+    `t:real^N->bool`] EXTEND_MAP_CELL_COMPLEX_TO_SPHERE) THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE] THEN
+  ASM_SIMP_TAC[GSYM RELATIVE_FRONTIER_OF_POLYHEDRON_ALT;
+               POLYTOPE_IMP_POLYHEDRON] THEN
+  REWRITE_TAC[IN_ELIM_THM; GSYM IMAGE_o; o_THM] THEN ANTS_TAC THENL
+   [REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC FINITE_SUBSET THEN
+      EXISTS_TAC `{f:real^M->bool | f face_of p}` THEN
+      ASM_SIMP_TAC[FINITE_POLYTOPE_FACES] THEN SET_TAC[];
+      ASM_MESON_TAC[FACE_OF_POLYTOPE_POLYTOPE;
+                    FACE_OF_AFF_DIM_LT; POLYTOPE_IMP_CONVEX; INT_LTE_TRANS];
+      ASM_MESON_TAC[FACE_OF_INTER; FACE_OF_SUBSET;
+                    INTER_SUBSET; FACE_OF_INTER; FACE_OF_IMP_SUBSET];
+      ASM SET_TAC[];
+      MATCH_MP_TAC COMPACT_IMP_CLOSED THEN
+      MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+      CONJ_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN
+      FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+        BOUNDED_SUBSET)) THEN
+      ASM_SIMP_TAC[BOUNDED_RELATIVE_FRONTIER];
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+      ASM SET_TAC[];
+      REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[]];
+    DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(g:real^M->real^N) o (h:real^M->real^M)` THEN
+    REWRITE_TAC[IMAGE_o; o_THM] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      CONTINUOUS_ON_SUBSET)) THEN
+    ASM SET_TAC[]]);;
+
+let EXTEND_MAP_SPHERE_TO_SPHERE = prove
+ (`!f:real^M->real^N c a r b s.
+        dimindex(:M) <= dimindex(:N) /\ closed c /\ c SUBSET sphere(a,r) /\
+        f continuous_on c /\ IMAGE f c SUBSET sphere(b,s) /\
+        (&0 <= r /\ c = {} ==> &0 <= s)
+        ==> ?g. g continuous_on sphere(a,r) /\
+                IMAGE g (sphere(a,r)) SUBSET sphere(b,s) /\
+                !x. x IN c ==> g x = f x`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `r < &0` THEN
+  ASM_SIMP_TAC[SPHERE_EMPTY; NOT_IN_EMPTY; CONTINUOUS_ON_EMPTY;
+               IMAGE_CLAUSES; EMPTY_SUBSET]
+  THENL [MESON_TAC[]; ASM_REWRITE_TAC[GSYM REAL_NOT_LT]] THEN
+  ASM_CASES_TAC `sphere(b:real^N,s) = {}` THENL
+   [FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SPHERE_EQ_EMPTY]) THEN
+    ASM SET_TAC[];
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [SPHERE_EQ_EMPTY])] THEN
+  REWRITE_TAC[REAL_NOT_LE] THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LT]) THEN
+  ASM_CASES_TAC `r = &0` THEN
+  ASM_SIMP_TAC[SPHERE_SING; CONTINUOUS_ON_SING; REAL_LE_REFL] THENL
+   [ASM_CASES_TAC `c:real^M->bool = {}` THENL
+     [DISCH_THEN(K ALL_TAC) THEN MATCH_MP_TAC(MESON[]
+       `(?c. P(\x. c)) ==> ?f. P f`) THEN ASM SET_TAC[];
+      DISCH_TAC THEN EXISTS_TAC `f:real^M->real^N` THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `s = &0` THENL
+   [ASM_SIMP_TAC[SPHERE_SING] THEN STRIP_TAC THEN
+    EXISTS_TAC `(\x. b):real^M->real^N` THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `c:real^M->bool`;
+                 `cball(a:real^M,r)`; `cball(b:real^N,s)`]
+        EXTEND_MAP_SPHERE_TO_SPHERE_GEN) THEN
+  ASM_REWRITE_TAC[CONVEX_CBALL; BOUNDED_CBALL; AFF_DIM_CBALL;
+                  RELATIVE_FRONTIER_CBALL] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[INT_OF_NUM_LE]) THEN
+  ASM_REAL_ARITH_TAC);;
+
+let EXTEND_MAP_SPHERE_TO_SPHERE_COFINITE_GEN = prove
+ (`!f:real^M->real^N s t u p.
+        convex t /\ bounded t /\ convex u /\ bounded u /\
+        aff_dim t <= aff_dim u + &1 /\
+        closed s /\ s SUBSET relative_frontier t /\
+        f continuous_on s /\ IMAGE f s SUBSET relative_frontier u /\
+        (!c. c IN components(relative_frontier t DIFF s) ==> ~(c INTER p = {}))
+        ==> ?k g. FINITE k /\ k SUBSET p /\
+                  k SUBSET relative_frontier t /\ DISJOINT k s /\
+                  g continuous_on (relative_frontier t DIFF k) /\
+                  IMAGE g (relative_frontier t DIFF k) SUBSET
+                  relative_frontier u /\
+                  !x. x IN s ==> g x = f x`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s = (relative_frontier t:real^M->bool)` THENL
+   [ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`{}:real^M->bool`; `f:real^M->real^N`] THEN
+    ASM_REWRITE_TAC[FINITE_EMPTY; DIFF_EMPTY] THEN SET_TAC[];
+    POP_ASSUM MP_TAC] THEN
+  ASM_CASES_TAC `relative_frontier t:real^M->bool = {}` THENL
+   [ASM SET_TAC[]; REPEAT STRIP_TAC] THEN
+  SUBGOAL_THEN
+   `?c q:real^M. c IN components (relative_frontier t DIFF s) /\
+                 q IN c /\ q IN relative_frontier t /\ ~(q IN s) /\ q IN p`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPEC `(relative_frontier t:real^M->bool) DIFF s`
+      UNIONS_COMPONENTS) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE
+     `s = u ==> ~(s = {}) ==> ~(u = {})`)) THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[EMPTY_UNIONS]] THEN
+    REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^M->bool` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `c:real^M->bool`) THEN
+    ASM_REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[GSYM IN_DIFF] THEN
+    ASM_MESON_TAC[SUBSET; IN_COMPONENTS_SUBSET];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `?af. affine af /\ aff_dim(t:real^M->bool) = aff_dim(af:real^M->bool) + &1`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPECL [`(:real^M)`; `aff_dim(t:real^M->bool) - &1`]
+        CHOOSE_AFFINE_SUBSET) THEN
+    REWRITE_TAC[SUBSET_UNIV; AFFINE_UNIV] THEN ANTS_TAC THENL
+     [MATCH_MP_TAC(INT_ARITH
+       `&0:int <= t /\ t <= n ==> --a <= t - a /\ t - &1 <= n`) THEN
+      REWRITE_TAC[AFF_DIM_LE_UNIV; AFF_DIM_UNIV; AFF_DIM_POS_LE] THEN
+      ASM_MESON_TAC[RELATIVE_FRONTIER_EMPTY; NOT_IN_EMPTY];
+      MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN INT_ARITH_TAC];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`t:real^M->bool`; `af:real^M->bool`; `q:real^M`]
+        HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE_GEN) THEN
+  ASM_REWRITE_TAC[homeomorphic; homeomorphism; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`h:real^M->real^M`; `k:real^M->real^M`] THEN
+  STRIP_TAC THEN MP_TAC(ISPECL
+   [`(f:real^M->real^N) o (k:real^M->real^M)`;
+    `IMAGE (h:real^M->real^M) s`;
+    `(af:real^M->bool)`;
+    `u:real^N->bool`;
+    `IMAGE (h:real^M->real^M) (p INTER relative_frontier t DELETE q)`]
+   EXTEND_MAP_AFFINE_TO_SPHERE_COFINITE_GEN) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN CONJ_TAC THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        ASM SET_TAC[];
+        ASM_MESON_TAC[COMPACT_EQ_BOUNDED_CLOSED; BOUNDED_SUBSET;
+                      COMPACT_RELATIVE_FRONTIER_BOUNDED]];
+      ASM_INT_ARITH_TAC;
+      ASM SET_TAC[];
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+      ASM SET_TAC[];
+      REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[];
+      X_GEN_TAC `l:real^M->bool` THEN STRIP_TAC THEN
+      SUBGOAL_THEN `~(l:real^M->bool = {})` ASSUME_TAC THENL
+       [ASM_MESON_TAC[IN_COMPONENTS_NONEMPTY]; ALL_TAC] THEN
+      SUBGOAL_THEN `?x:real^M. x IN l` STRIP_ASSUME_TAC THENL
+       [ASM SET_TAC[]; ALL_TAC] THEN
+      SUBGOAL_THEN `l SUBSET af DIFF IMAGE (h:real^M->real^M) s`
+      ASSUME_TAC THENL
+       [ASM_MESON_TAC[IN_COMPONENTS_SUBSET]; ALL_TAC] THEN
+      SUBGOAL_THEN `connected(l:real^M->bool)` ASSUME_TAC THENL
+       [ASM_MESON_TAC[IN_COMPONENTS_CONNECTED]; ALL_TAC] THEN
+      SUBGOAL_THEN
+       `?r. r IN components (relative_frontier t DIFF s) /\
+            IMAGE (k:real^M->real^M) l SUBSET r`
+      STRIP_ASSUME_TAC THENL
+       [REWRITE_TAC[IN_COMPONENTS; LEFT_AND_EXISTS_THM] THEN
+        EXISTS_TAC `connected_component (relative_frontier t DIFF s)
+                                        ((k:real^M->real^M) x)` THEN
+        EXISTS_TAC `(k:real^M->real^M) x` THEN REWRITE_TAC[] THEN
+        CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+        MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+        ASM_SIMP_TAC[FUN_IN_IMAGE] THEN
+        CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+        MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN ASM_REWRITE_TAC[] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        ASM SET_TAC[];
+        ALL_TAC] THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `r:real^M->bool`) THEN
+      ASM_REWRITE_TAC[] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM MEMBER_NOT_EMPTY] THEN
+      REWRITE_TAC[LEFT_IMP_EXISTS_THM; IN_INTER] THEN
+      X_GEN_TAC `z:real^M` THEN STRIP_TAC THEN
+      SUBGOAL_THEN `r SUBSET ((relative_frontier t:real^M->bool) DIFF s)`
+      ASSUME_TAC THENL [ASM_MESON_TAC[IN_COMPONENTS_SUBSET]; ALL_TAC] THEN
+      SUBGOAL_THEN `connected(r:real^M->bool)` ASSUME_TAC THENL
+       [ASM_MESON_TAC[IN_COMPONENTS_CONNECTED]; ALL_TAC] THEN
+      ASM_CASES_TAC `(q:real^M) IN r` THENL
+       [ALL_TAC;
+        REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+        EXISTS_TAC `(h:real^M->real^M) z` THEN REWRITE_TAC[IN_INTER] THEN
+        CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+        MATCH_MP_TAC(SET_RULE `!s. x IN s /\ s SUBSET t ==> x IN t`) THEN
+        EXISTS_TAC `IMAGE (h:real^M->real^M) r` THEN
+        ASM_SIMP_TAC[FUN_IN_IMAGE] THEN MATCH_MP_TAC COMPONENTS_MAXIMAL THEN
+        EXISTS_TAC `af DIFF IMAGE (h:real^M->real^M) s` THEN
+        ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+         [MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN ASM_REWRITE_TAC[] THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN
+          ASM SET_TAC[];
+          REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_DIFF; IN_ELIM_THM] THEN
+          X_GEN_TAC `y:real^M` THEN DISCH_TAC THEN
+          CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+          REWRITE_TAC[SET_RULE
+           `~(h y IN IMAGE h s) <=> !y'. y' IN s ==> ~(h y = h y')`] THEN
+          X_GEN_TAC `y':real^M` THEN DISCH_TAC THEN
+          DISCH_THEN(MP_TAC o AP_TERM `k:real^M->real^M`) THEN
+          MATCH_MP_TAC(MESON[]
+           `k(h y) = y /\ k(h y') = y' /\ ~(y = y')
+            ==> k(h y) = k(h y') ==> F`) THEN
+          ASM SET_TAC[];
+          ASM SET_TAC[]]] THEN
+      SUBGOAL_THEN
+       `?n. open_in (subtopology euclidean (relative_frontier t)) n /\
+            (q:real^M) IN n /\ n INTER IMAGE (k:real^M->real^M) l = {}`
+      STRIP_ASSUME_TAC THENL
+       [EXISTS_TAC `relative_frontier t DIFF
+                    IMAGE (k:real^M->real^M) (closure l)` THEN
+        SUBGOAL_THEN `closure l SUBSET (af:real^M->bool)` ASSUME_TAC THENL
+         [MATCH_MP_TAC CLOSURE_MINIMAL THEN
+          ASM_SIMP_TAC[CLOSED_AFFINE] THEN ASM SET_TAC[];
+          ALL_TAC] THEN
+        REPEAT CONJ_TAC THENL
+         [MATCH_MP_TAC OPEN_IN_DIFF THEN REWRITE_TAC[OPEN_IN_REFL] THEN
+          MATCH_MP_TAC CLOSED_SUBSET THEN
+          CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+          MATCH_MP_TAC COMPACT_IMP_CLOSED THEN
+          MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+          ASM_REWRITE_TAC[COMPACT_CLOSURE] THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN
+          ASM SET_TAC[];
+          ASM SET_TAC[];
+          MP_TAC(ISPEC `l:real^M->bool` CLOSURE_SUBSET) THEN SET_TAC[]];
+        ALL_TAC] THEN
+      FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN
+      SUBGOAL_THEN
+       `?w. connected w /\ w SUBSET r DELETE q /\
+            (k:real^M->real^M) x IN w /\ ~((n DELETE q) INTER w = {})`
+      STRIP_ASSUME_TAC THENL
+       [ALL_TAC;
+        MATCH_MP_TAC(TAUT `F ==> p`) THEN
+        SUBGOAL_THEN `IMAGE (h:real^M->real^M) w SUBSET l` MP_TAC THENL
+         [ALL_TAC; ASM SET_TAC[]] THEN
+        MATCH_MP_TAC COMPONENTS_MAXIMAL THEN
+        EXISTS_TAC `af DIFF IMAGE (h:real^M->real^M) s` THEN
+        ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+         [MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN ASM_REWRITE_TAC[] THEN
+          FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN
+          ASM SET_TAC[];
+          REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_DIFF; IN_ELIM_THM] THEN
+          X_GEN_TAC `y:real^M` THEN DISCH_TAC THEN
+          CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+          REWRITE_TAC[SET_RULE
+           `~(h y IN IMAGE h s) <=> !y'. y' IN s ==> ~(h y = h y')`] THEN
+          X_GEN_TAC `y':real^M` THEN DISCH_TAC THEN
+          DISCH_THEN(MP_TAC o AP_TERM `k:real^M->real^M`) THEN
+          MATCH_MP_TAC(MESON[]
+           `k(h y) = y /\ k(h y') = y' /\ ~(y = y')
+            ==> k(h y) = k(h y') ==> F`) THEN
+          ASM SET_TAC[];
+          ASM SET_TAC[]]] THEN
+      SUBGOAL_THEN `path_connected(r:real^M->bool)` MP_TAC THENL
+       [W(MP_TAC o PART_MATCH (lhand o rand) PATH_CONNECTED_EQ_CONNECTED_LPC o
+          snd) THEN
+        ANTS_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+        MATCH_MP_TAC LOCALLY_OPEN_SUBSET THEN
+        EXISTS_TAC `(relative_frontier t:real^M->bool)` THEN
+        ASM_SIMP_TAC[LOCALLY_PATH_CONNECTED_SPHERE_GEN] THEN
+        MATCH_MP_TAC OPEN_IN_TRANS THEN
+        EXISTS_TAC `(relative_frontier t:real^M->bool) DIFF s` THEN
+        CONJ_TAC THENL
+         [MATCH_MP_TAC OPEN_IN_COMPONENTS_LOCALLY_CONNECTED THEN
+          ASM_REWRITE_TAC[] THEN
+          MATCH_MP_TAC LOCALLY_OPEN_SUBSET THEN
+          EXISTS_TAC `(relative_frontier t:real^M->bool)` THEN
+          ASM_SIMP_TAC[LOCALLY_CONNECTED_SPHERE_GEN];
+          ALL_TAC] THEN
+        MATCH_MP_TAC OPEN_IN_DIFF THEN REWRITE_TAC[OPEN_IN_REFL] THEN
+        MATCH_MP_TAC CLOSED_SUBSET THEN ASM_REWRITE_TAC[];
+        ALL_TAC] THEN
+      REWRITE_TAC[PATH_CONNECTED_ARCWISE] THEN
+      DISCH_THEN(MP_TAC o SPECL [`(k:real^M->real^M) x`; `q:real^M`]) THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^M` STRIP_ASSUME_TAC) THEN
+      FIRST_X_ASSUM(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC o
+        GEN_REWRITE_RULE I [arc]) THEN
+      DISCH_TAC THEN
+      SUBGOAL_THEN
+       `open_in (subtopology euclidean (interval[vec 0,vec 1]))
+                {x | x IN interval[vec 0,vec 1] /\
+                     (g:real^1->real^M) x IN n}`
+      MP_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE_GEN THEN
+        EXISTS_TAC `(relative_frontier t:real^M->bool)` THEN
+        ASM_REWRITE_TAC[GSYM path; GSYM path_image] THEN
+        ASM SET_TAC[];
+        ALL_TAC] THEN
+      REWRITE_TAC[OPEN_IN_CONTAINS_CBALL] THEN
+      REWRITE_TAC[IN_ELIM_THM; SUBSET_RESTRICT] THEN
+      DISCH_THEN(MP_TAC o SPEC `vec 1:real^1`) THEN
+      REWRITE_TAC[ENDS_IN_UNIT_INTERVAL] THEN
+      ANTS_TAC THENL [ASM_MESON_TAC[pathfinish]; ALL_TAC] THEN
+      DISCH_THEN(X_CHOOSE_THEN `r:real`
+        (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+      ABBREV_TAC `t' = lift(&1 - min (&1 / &2) r)` THEN
+      SUBGOAL_THEN `t' IN interval[vec 0:real^1,vec 1]` ASSUME_TAC THENL
+       [EXPAND_TAC "t'" THEN SIMP_TAC[IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+        ASM_REAL_ARITH_TAC;
+        ALL_TAC] THEN
+      GEN_REWRITE_TAC LAND_CONV [SUBSET] THEN
+      DISCH_THEN(MP_TAC o SPEC `t':real^1`) THEN
+      ASM_REWRITE_TAC[IN_INTER; IN_ELIM_THM; IN_CBALL; DIST_REAL;
+                      DROP_VEC; GSYM drop] THEN
+      ANTS_TAC THENL
+       [EXPAND_TAC "t'" THEN REWRITE_TAC[LIFT_DROP] THEN ASM_REAL_ARITH_TAC;
+        DISCH_TAC] THEN
+      EXISTS_TAC `IMAGE (g:real^1->real^M) (interval[vec 0,t'])` THEN
+      REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN
+        REWRITE_TAC[CONNECTED_INTERVAL] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+        EXISTS_TAC `interval[vec 0:real^1,vec 1]` THEN
+        ASM_REWRITE_TAC[GSYM path; SUBSET_INTERVAL_1] THEN
+        ASM_REWRITE_TAC[REAL_LE_REFL; GSYM IN_INTERVAL_1];
+        REWRITE_TAC[SET_RULE
+         `s SUBSET t DELETE q <=> s SUBSET t /\ !x. x IN s ==> ~(x = q)`] THEN
+        CONJ_TAC THENL
+         [TRANS_TAC SUBSET_TRANS
+            `IMAGE (g:real^1->real^M) (interval[vec 0,vec 1])` THEN
+          CONJ_TAC THENL
+           [MATCH_MP_TAC IMAGE_SUBSET THEN
+            ASM_REWRITE_TAC[REAL_LE_REFL; GSYM IN_INTERVAL_1;
+                            SUBSET_INTERVAL_1];
+            ASM_REWRITE_TAC[GSYM path_image]];
+          REWRITE_TAC[FORALL_IN_IMAGE] THEN
+          X_GEN_TAC `t'':real^1` THEN DISCH_TAC THEN
+          FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC (RAND_CONV o RAND_CONV)
+           [SYM th]) THEN
+          REWRITE_TAC[pathfinish] THEN DISCH_TAC THEN
+          FIRST_X_ASSUM(MP_TAC o SPECL [`t'':real^1`; `vec 1:real^1`]) THEN
+          ASM_REWRITE_TAC[GSYM DROP_EQ] THEN
+          UNDISCH_TAC `t'' IN interval[vec 0:real^1,t']` THEN
+          EXPAND_TAC "t'" THEN
+          REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+          ASM_REAL_ARITH_TAC];
+        REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `vec 0:real^1` THEN
+        CONJ_TAC THENL [ASM_MESON_TAC[pathstart]; ALL_TAC] THEN
+        EXPAND_TAC "t'" THEN
+        REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+        ASM_REAL_ARITH_TAC;
+        REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+        ONCE_REWRITE_TAC[INTER_COMM] THEN
+        REWRITE_TAC[EXISTS_IN_IMAGE; IN_INTER] THEN
+        EXISTS_TAC `t':real^1` THEN CONJ_TAC THENL
+         [EXPAND_TAC "t'" THEN
+          REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+          ASM_REAL_ARITH_TAC;
+          ASM_REWRITE_TAC[IN_DELETE] THEN
+          FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC (RAND_CONV o RAND_CONV)
+           [SYM th]) THEN
+          REWRITE_TAC[pathfinish] THEN DISCH_TAC THEN
+          FIRST_X_ASSUM(MP_TAC o SPECL [`t':real^1`; `vec 1:real^1`]) THEN
+          ASM_REWRITE_TAC[GSYM DROP_EQ] THEN
+          EXPAND_TAC "t'" THEN
+          REWRITE_TAC[IN_INTERVAL_1; DROP_VEC; LIFT_DROP] THEN
+          ASM_REAL_ARITH_TAC]]];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[DOT_BASIS; LE_REFL; DIMINDEX_GE_1; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`tk:real^M->bool`; `g:real^M->real^N`] THEN
+  REWRITE_TAC[o_THM] THEN
+  STRIP_TAC THEN EXISTS_TAC `q INSERT IMAGE (k:real^M->real^M) tk` THEN
+  EXISTS_TAC `(g:real^M->real^N) o (h:real^M->real^M)` THEN
+  ASM_SIMP_TAC[FINITE_INSERT; FINITE_IMAGE; o_THM] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `a IN t /\ s SUBSET t DELETE a ==> a INSERT s SUBSET t`) THEN
+    ASM_REWRITE_TAC[] THEN
+    TRANS_TAC SUBSET_TRANS
+      `p INTER (relative_frontier t:real^M->bool) DELETE q` THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (SET_RULE `t SUBSET IMAGE h s ==> IMAGE k (IMAGE h s) SUBSET s
+            ==> IMAGE k t SUBSET s`)) THEN
+    REWRITE_TAC[GSYM IMAGE_o] THEN
+    MATCH_MP_TAC(SET_RULE
+     `(!x. x IN s ==> f x = x) ==> IMAGE f s SUBSET s`) THEN
+    REWRITE_TAC[o_THM] THEN ASM SET_TAC[];
+    ASM SET_TAC[];
+    ASM SET_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    ASM SET_TAC[];
+    REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[];
+    ASM SET_TAC[]]);;
+
+let EXTEND_MAP_SPHERE_TO_SPHERE_COFINITE = prove
+ (`!f:real^M->real^N s a d b e p.
+        dimindex(:M) <= dimindex(:N) + 1 /\
+        (&0 < d /\ s = {} ==> &0 <= e) /\
+        closed s /\ s SUBSET sphere(a,d) /\
+        f continuous_on s /\ IMAGE f s SUBSET sphere(b,e) /\
+        (!c. c IN components(sphere(a,d) DIFF s) ==> ~(c INTER p = {}))
+        ==> ?k g. FINITE k /\ k SUBSET p /\
+                  k SUBSET sphere(a,d) /\ DISJOINT k s /\
+                  g continuous_on (sphere(a,d) DIFF k) /\
+                  IMAGE g (sphere(a,d) DIFF k) SUBSET sphere(b,e) /\
+                  !x. x IN s ==> g x = f x`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s = sphere(a:real^M,d)` THENL
+   [ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`{}:real^M->bool`; `f:real^M->real^N`] THEN
+    ASM_REWRITE_TAC[FINITE_EMPTY; DIFF_EMPTY] THEN SET_TAC[];
+    POP_ASSUM MP_TAC] THEN
+  ASM_CASES_TAC `d < &0` THENL
+   [ASM_SIMP_TAC[SPHERE_EMPTY] THEN SET_TAC[]; ALL_TAC] THEN
+  ASM_CASES_TAC `d = &0` THENL
+   [ASM_SIMP_TAC[SPHERE_SING] THEN
+    ASM_CASES_TAC `s:real^M->bool = {}` THENL
+     [ASM_REWRITE_TAC[]; ASM SET_TAC[]] THEN
+    REPEAT STRIP_TAC THEN
+    EXISTS_TAC `{a:real^M}` THEN
+    REWRITE_TAC[FINITE_SING; CONTINUOUS_ON_EMPTY; DIFF_EQ_EMPTY] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `{a:real^M}`) THEN
+    REWRITE_TAC[DIFF_EMPTY; IN_COMPONENTS_SELF; CONNECTED_SING] THEN
+    REWRITE_TAC[IMAGE_CLAUSES] THEN SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `&0 < d` ASSUME_TAC THENL
+   [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_CASES_TAC `e = &0` THENL
+   [ASM_SIMP_TAC[SPHERE_SING] THEN REPEAT STRIP_TAC THEN
+    EXISTS_TAC `{}:real^M->bool` THEN
+    EXISTS_TAC `(\x. b):real^M->real^N` THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST; FINITE_EMPTY] THEN ASM SET_TAC[];
+    REPEAT STRIP_TAC] THEN
+  SUBGOAL_THEN `&0 <= e` ASSUME_TAC THENL
+   [ASM_CASES_TAC `s:real^M->bool = {}` THEN ASM_SIMP_TAC[] THEN
+    MP_TAC(SYM(ISPECL [`b:real^N`; `e:real`] SPHERE_EQ_EMPTY)) THEN
+    SIMP_TAC[GSYM REAL_NOT_LT] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `&0 < e` ASSUME_TAC THENL
+   [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`f:real^M->real^N`; `s:real^M->bool`; `cball(a:real^M,d)`;
+    `cball(b:real^N,e)`; `p:real^M->bool`]
+   EXTEND_MAP_SPHERE_TO_SPHERE_COFINITE_GEN) THEN
+  ASM_REWRITE_TAC[CONVEX_CBALL; BOUNDED_CBALL] THEN
+  REWRITE_TAC[AFF_DIM_CBALL] THEN
+  MP_TAC(ISPECL [`a:real^M`; `d:real`] RELATIVE_FRONTIER_CBALL) THEN
+  MP_TAC(ISPECL [`b:real^N`; `e:real`] RELATIVE_FRONTIER_CBALL) THEN
+  ASM_REWRITE_TAC[] THEN REPEAT(DISCH_THEN SUBST1_TAC) THEN
+  ASM_REWRITE_TAC[INT_OF_NUM_ADD; INT_OF_NUM_LE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Borsuk-style characterization of separation.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_ON_BORSUK_MAP = prove
+ (`!s a:real^N.
+        ~(a IN s) ==> (\x. inv(norm (x - a)) % (x - a)) continuous_on s`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC CONTINUOUS_ON_MUL THEN SIMP_TAC[o_DEF] THEN CONJ_TAC THENL
+    [MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV); ALL_TAC] THEN
+  SIMP_TAC[CONTINUOUS_ON_LIFT_NORM_COMPOSE; CONTINUOUS_ON_SUB;
+           CONTINUOUS_ON_ID; CONTINUOUS_ON_CONST] THEN
+  REWRITE_TAC[NORM_EQ_0; VECTOR_SUB_EQ] THEN ASM_MESON_TAC[]);;
+
+let BORSUK_MAP_INTO_SPHERE = prove
+ (`!s a:real^N.
+        IMAGE (\x. inv(norm (x - a)) % (x - a)) s SUBSET sphere(vec 0,&1) <=>
+        ~(a IN s)`,
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_SPHERE_0] THEN
+  REWRITE_TAC[NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+  REWRITE_TAC[REAL_FIELD `inv x * x = &1 <=> ~(x = &0)`] THEN
+  REWRITE_TAC[NORM_EQ_0; VECTOR_SUB_EQ] THEN MESON_TAC[]);;
+
+let BORSUK_MAPS_HOMOTOPIC_IN_PATH_COMPONENT = prove
+ (`!s a b. path_component ((:real^N) DIFF s) a b
+           ==> homotopic_with (\x. T) (s,sphere(vec 0,&1))
+                   (\x. inv(norm(x - a)) % (x - a))
+                   (\x. inv(norm(x - b)) % (x - b))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[path_component; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[path; path_image; pathstart; pathfinish; SUBSET;
+              FORALL_IN_IMAGE; IN_UNIV; IN_DIFF] THEN
+  X_GEN_TAC `g:real^1->real^N` THEN STRIP_TAC THEN
+  SIMP_TAC[HOMOTOPIC_WITH] THEN
+  EXISTS_TAC `\z. inv(norm(sndcart z - g(fstcart z))) %
+                  (sndcart z - (g:real^1->real^N)(fstcart z))` THEN
+  ASM_SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART; IN_SPHERE_0;
+               SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_MUL THEN REWRITE_TAC[o_DEF] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
+      ASM_SIMP_TAC[FORALL_IN_PCROSS; FSTCART_PASTECART; SNDCART_PASTECART;
+                   NORM_EQ_0; VECTOR_SUB_EQ] THEN CONJ_TAC
+      THENL [MATCH_MP_TAC CONTINUOUS_ON_LIFT_NORM_COMPOSE; ASM_MESON_TAC[]];
+      ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART] THEN
+    REWRITE_TAC[IMAGE_FSTCART_PCROSS] THEN ASM_MESON_TAC[CONTINUOUS_ON_EMPTY];
+    REPEAT STRIP_TAC THEN
+    REWRITE_TAC[NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+    MATCH_MP_TAC REAL_MUL_LINV THEN
+    ASM_REWRITE_TAC[NORM_EQ_0; VECTOR_SUB_EQ] THEN ASM_MESON_TAC[]]);;
+
+let NON_EXTENSIBLE_BORSUK_MAP = prove
+ (`!s c a:real^N.
+        compact s /\ c IN components((:real^N) DIFF s) /\ bounded c /\ a IN c
+        ==> ~(?g. g continuous_on (s UNION c) /\
+                  IMAGE g (s UNION c) SUBSET sphere (vec 0,&1) /\
+                  (!x. x IN s ==> g x = inv(norm(x - a)) % (x - a)))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP IN_COMPONENTS_SUBSET) THEN
+  REWRITE_TAC[SUBSET] THEN DISCH_THEN(MP_TAC o SPEC `a:real^N`) THEN
+  ASM_REWRITE_TAC[IN_DIFF] THEN STRIP_TAC THEN
+  SUBGOAL_THEN `c = connected_component ((:real^N) DIFF s) a` SUBST_ALL_TAC
+  THENL [ASM_MESON_TAC[IN_COMPONENTS; CONNECTED_COMPONENT_EQ]; ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`s UNION connected_component ((:real^N) DIFF s) a`; `a:real^N`]
+      BOUNDED_SUBSET_BALL) THEN
+  ASM_SIMP_TAC[BOUNDED_UNION; COMPACT_IMP_BOUNDED] THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o SPEC `a:real^N` o MATCH_MP NO_RETRACTION_CBALL) THEN
+  REWRITE_TAC[retract_of; retraction] THEN
+  EXISTS_TAC `\x. if x IN connected_component ((:real^N) DIFF s) a
+                  then a + r % g(x)
+                  else a + r % inv(norm(x - a)) % (x - a)` THEN
+  REWRITE_TAC[SPHERE_SUBSET_CBALL] THEN REPEAT CONJ_TAC THENL
+   [SUBGOAL_THEN `cball(a:real^N,r) =
+                  (s UNION connected_component ((:real^N) DIFF s) a) UNION
+                  (cball(a,r) DIFF connected_component ((:real^N) DIFF s) a)`
+    SUBST1_TAC THENL
+     [MP_TAC(ISPECL [`a:real^N`; `r:real`] BALL_SUBSET_CBALL) THEN ASM
+      SET_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CASES THEN REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC CLOSED_UNION_COMPLEMENT_COMPONENT THEN
+      ASM_SIMP_TAC[IN_COMPONENTS; COMPACT_IMP_CLOSED; IN_UNIV; IN_DIFF] THEN
+      ASM_MESON_TAC[];
+      MATCH_MP_TAC CLOSED_DIFF THEN
+      ASM_SIMP_TAC[CLOSED_CBALL; OPEN_CONNECTED_COMPONENT; GSYM closed;
+                   COMPACT_IMP_CLOSED];
+      MATCH_MP_TAC CONTINUOUS_ON_ADD THEN SIMP_TAC[CONTINUOUS_ON_CONST] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_CMUL THEN ASM_SIMP_TAC[CONTINUOUS_ON_CONST];
+      MATCH_MP_TAC CONTINUOUS_ON_ADD THEN SIMP_TAC[CONTINUOUS_ON_CONST] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_CMUL THEN
+      MATCH_MP_TAC CONTINUOUS_ON_BORSUK_MAP THEN
+      ASM_SIMP_TAC[CENTRE_IN_CBALL; IN_DIFF; REAL_LT_IMP_LE] THEN
+      REWRITE_TAC[IN] THEN REWRITE_TAC[CONNECTED_COMPONENT_REFL_EQ] THEN
+      ASM_REWRITE_TAC[IN_DIFF; IN_UNIV];
+      REPEAT STRIP_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM SET_TAC[]];
+
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+      REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+      ASM_REWRITE_TAC[IN_SPHERE; NORM_ARITH `dist(a:real^N,a + x) = norm x`;
+                      NORM_MUL] THEN
+      ASM_SIMP_TAC[REAL_ABS_INV; REAL_ABS_NORM; VECTOR_SUB_EQ;
+        REAL_FIELD `&0 < r ==> abs r = r /\ (r * x = r <=> x = &1)`;
+        REAL_FIELD `inv x * x = &1 <=> ~(x = &0)`; NORM_EQ_0]
+      THENL
+       [ONCE_REWRITE_TAC[GSYM IN_SPHERE_0] THEN ASM SET_TAC[];
+        UNDISCH_TAC `~(x IN connected_component ((:real^N) DIFF s) a)` THEN
+        SIMP_TAC[CONTRAPOS_THM; IN] THEN
+        ASM_REWRITE_TAC[CONNECTED_COMPONENT_REFL_EQ; IN_DIFF; IN_UNIV]];
+      SIMP_TAC[IN_SPHERE; ONCE_REWRITE_RULE[NORM_SUB] dist] THEN
+      ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; REAL_LT_IMP_NZ] THEN
+      REWRITE_TAC[VECTOR_ARITH `a + &1 % (x - a):real^N = x`] THEN
+      REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+       `s UNION t SUBSET u ==> !x. x IN t /\ ~(x IN u) ==> wev`)) THEN
+      EXISTS_TAC `x:real^N` THEN
+      ASM_REWRITE_TAC[ONCE_REWRITE_RULE[NORM_SUB] dist; IN_BALL;
+                      REAL_LT_REFL]]);;
+
+let BORSUK_MAP_ESSENTIAL_BOUNDED_COMPONENT = prove
+ (`!s a. compact s /\ ~(a IN s)
+         ==> (bounded(connected_component ((:real^N) DIFF s) a) <=>
+              ~(?c. homotopic_with (\x. T) (s,sphere(vec 0:real^N,&1))
+                                   (\x. inv(norm(x - a)) % (x - a)) (\x. c)))`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_SIMP_TAC[DIFF_EMPTY; CONNECTED_COMPONENT_UNIV; NOT_BOUNDED_UNIV] THEN
+    SIMP_TAC[HOMOTOPIC_WITH; NOT_IN_EMPTY; PCROSS_EMPTY; IMAGE_CLAUSES;
+             CONTINUOUS_ON_EMPTY; EMPTY_SUBSET];
+    ALL_TAC] THEN
+  EQ_TAC THENL
+   [ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[] THEN
+    REPEAT DISCH_TAC THEN
+    MP_TAC(ISPECL
+     [`\x:real^N. inv(norm(x - a)) % (x - a)`; `s:real^N->bool`;
+      `vec 0:real^N`; `&1`]
+     NULLHOMOTOPIC_INTO_SPHERE_EXTENSION) THEN
+    ASM_SIMP_TAC[COMPACT_IMP_CLOSED; NOT_IMP; CONTINUOUS_ON_BORSUK_MAP;
+                 BORSUK_MAP_INTO_SPHERE] THEN
+    MP_TAC(ISPECL [`s:real^N->bool`;
+        `connected_component ((:real^N) DIFF s) a`;
+        `a:real^N`] NON_EXTENSIBLE_BORSUK_MAP) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [GEN_REWRITE_TAC RAND_CONV [IN] THEN
+      REWRITE_TAC[CONNECTED_COMPONENT_REFL_EQ] THEN
+      ASM_REWRITE_TAC[IN_COMPONENTS; IN_DIFF; IN_UNIV] THEN ASM_MESON_TAC[];
+      REWRITE_TAC[CONTRAPOS_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+      GEN_TAC THEN MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
+       [MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNIV]; SET_TAC[]]];
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[] THEN
+    DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o SPEC `vec 0:real^N` o MATCH_MP BOUNDED_SUBSET_BALL o
+      MATCH_MP COMPACT_IMP_BOUNDED) THEN
+    DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `?b. b IN connected_component ((:real^N) DIFF s) a /\
+          ~(b IN ball(vec 0,r))`
+    MP_TAC THENL
+     [REWRITE_TAC[SET_RULE `(?b. b IN s /\ ~(b IN t)) <=> ~(s SUBSET t)`] THEN
+      ASM_MESON_TAC[BOUNDED_SUBSET; BOUNDED_BALL];
+      DISCH_THEN(X_CHOOSE_THEN `b:real^N` STRIP_ASSUME_TAC)] THEN
+    SUBGOAL_THEN
+     `?c. homotopic_with (\x. T) (ball(vec 0:real^N,r),sphere (vec 0,&1))
+                         (\x. inv (norm (x - b)) % (x - b)) (\x. c)`
+    MP_TAC THENL
+     [MATCH_MP_TAC NULLHOMOTOPIC_FROM_CONTRACTIBLE THEN
+      ASM_SIMP_TAC[CONTINUOUS_ON_BORSUK_MAP; BORSUK_MAP_INTO_SPHERE;
+                   CONVEX_IMP_CONTRACTIBLE; CONVEX_BALL];
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^N` THEN STRIP_TAC] THEN
+    MATCH_MP_TAC HOMOTOPIC_WITH_TRANS THEN
+    EXISTS_TAC `\x:real^N. inv(norm (x - b)) % (x - b)` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC BORSUK_MAPS_HOMOTOPIC_IN_PATH_COMPONENT THEN
+      ASM_SIMP_TAC[OPEN_PATH_CONNECTED_COMPONENT; GSYM closed;
+                   COMPACT_IMP_CLOSED] THEN  ASM_MESON_TAC[IN];
+      ASM_MESON_TAC[HOMOTOPIC_WITH_SUBSET_LEFT]]]);;
+
+let HOMOTOPIC_BORSUK_MAPS_IN_BOUNDED_COMPONENT = prove
+ (`!s a b.
+        compact s /\ ~(a IN s) /\ ~(b IN s) /\
+        bounded (connected_component ((:real^N) DIFF s) a) /\
+        homotopic_with (\x. T) (s,sphere(vec 0,&1))
+                               (\x. inv(norm(x - a)) % (x - a))
+                               (\x. inv(norm(x - b)) % (x - b))
+        ==> connected_component ((:real^N) DIFF s) a b`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC I [GSYM IN] THEN
+  MP_TAC(ISPECL
+   [`s:real^N->bool`; `connected_component ((:real^N) DIFF s) a`;
+    `a:real^N`] NON_EXTENSIBLE_BORSUK_MAP) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [GEN_REWRITE_TAC RAND_CONV [IN] THEN
+    REWRITE_TAC[CONNECTED_COMPONENT_REFL_EQ] THEN
+    ASM_REWRITE_TAC[IN_COMPONENTS; IN_DIFF; IN_UNIV] THEN ASM_MESON_TAC[];
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM]] THEN
+  DISCH_TAC THEN REWRITE_TAC[] THEN
+  MATCH_MP_TAC BORSUK_HOMOTOPY_EXTENSION THEN
+  EXISTS_TAC `\x:real^N. inv(norm(x - b)) % (x - b)` THEN
+  ASM_SIMP_TAC[COMPACT_IMP_CLOSED] THEN
+  ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_BORSUK_MAP; IN_UNION; BORSUK_MAP_INTO_SPHERE] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CLOSED_UNION_COMPLEMENT_COMPONENT THEN
+    ASM_SIMP_TAC[COMPACT_IMP_CLOSED; IN_COMPONENTS; IN_DIFF; IN_UNIV] THEN
+    ASM_MESON_TAC[];
+    EXISTS_TAC `(:real^N) DELETE (vec 0)` THEN
+    ASM_SIMP_TAC[SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE; REAL_LT_01;
+                 OPEN_DELETE; OPEN_UNIV]]);;
+
+let BORSUK_MAPS_HOMOTOPIC_IN_CONNECTED_COMPONENT_EQ = prove
+ (`!s a b. 2 <= dimindex(:N) /\ compact s /\ ~(a IN s) /\ ~(b IN s)
+           ==> (homotopic_with (\x. T) (s,sphere(vec 0,&1))
+                   (\x. inv(norm(x - a)) % (x - a))
+                   (\x. inv(norm(x - b)) % (x - b)) <=>
+                connected_component ((:real^N) DIFF s) a b)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [DISCH_TAC;
+    ASM_SIMP_TAC[GSYM OPEN_PATH_CONNECTED_COMPONENT; GSYM closed;
+                 COMPACT_IMP_CLOSED] THEN
+    REWRITE_TAC[BORSUK_MAPS_HOMOTOPIC_IN_PATH_COMPONENT]] THEN
+  ASM_CASES_TAC `bounded(connected_component ((:real^N) DIFF s) a)` THENL
+   [MATCH_MP_TAC HOMOTOPIC_BORSUK_MAPS_IN_BOUNDED_COMPONENT THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `bounded(connected_component ((:real^N) DIFF s) b)` THENL
+   [ONCE_REWRITE_TAC[CONNECTED_COMPONENT_SYM_EQ] THEN
+    MATCH_MP_TAC HOMOTOPIC_BORSUK_MAPS_IN_BOUNDED_COMPONENT THEN
+    ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN
+    ASM_REWRITE_TAC[];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`(:real^N) DIFF s`; `a:real^N`; `b:real^N`]
+        COBOUNDED_UNIQUE_UNBOUNDED_COMPONENT) THEN
+  ASM_REWRITE_TAC[CONNECTED_COMPONENT_EQ_EQ; IN_DIFF; IN_UNIV;
+                  SET_RULE `UNIV DIFF (UNIV DIFF s) = s`] THEN
+  ASM_SIMP_TAC[COMPACT_IMP_BOUNDED]);;
+
+let BORSUK_SEPARATION_THEOREM_GEN = prove
+ (`!s:real^N->bool.
+    compact s
+    ==> ((!c. c IN components((:real^N) DIFF s) ==> ~bounded c) <=>
+         (!f. f continuous_on s /\ IMAGE f s SUBSET sphere(vec 0:real^N,&1)
+              ==> ?c. homotopic_with (\x. T) (s,sphere(vec 0,&1)) f (\x. c)))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[NOT_FORALL_THM; components; EXISTS_IN_GSPEC; NOT_IMP;
+                IN_UNIV; IN_DIFF] THEN
+    DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `\x:real^N. inv(norm(x - a)) % (x - a)` THEN
+    ASM_SIMP_TAC[GSYM BORSUK_MAP_ESSENTIAL_BOUNDED_COMPONENT;
+                 CONTINUOUS_ON_BORSUK_MAP; BORSUK_MAP_INTO_SPHERE]] THEN
+  DISCH_TAC THEN X_GEN_TAC `f:real^N->real^N` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`f:real^N->real^N`; `s:real^N->bool`; `vec 0:real^N`; `&1:real`]
+        EXTEND_MAP_UNIV_TO_SPHERE_NO_BOUNDED_COMPONENT) THEN
+  ASM_REWRITE_TAC[LE_REFL; REAL_POS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^N` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`g:real^N->real^N`; `(:real^N)`; `sphere(vec 0:real^N,&1)`]
+        NULLHOMOTOPIC_FROM_CONTRACTIBLE) THEN
+  ASM_REWRITE_TAC[CONTRACTIBLE_UNIV] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+  DISCH_THEN(MP_TAC o SPEC `s:real^N->bool` o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] HOMOTOPIC_WITH_SUBSET_LEFT)) THEN
+  REWRITE_TAC[SUBSET_UNIV] THEN
+  MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+        HOMOTOPIC_WITH_EQ) THEN
+  ASM_SIMP_TAC[]);;
+
+let BORSUK_SEPARATION_THEOREM = prove
+ (`!s:real^N->bool.
+      2 <= dimindex(:N) /\ compact s
+      ==> (connected((:real^N) DIFF s) <=>
+           !f. f continuous_on s /\ IMAGE f s SUBSET sphere(vec 0:real^N,&1)
+               ==> ?c. homotopic_with (\x. T) (s,sphere(vec 0,&1)) f (\x. c))`,
+  SIMP_TAC[GSYM BORSUK_SEPARATION_THEOREM_GEN] THEN
+  X_GEN_TAC `s:real^N->bool` THEN STRIP_TAC THEN EQ_TAC THENL
+   [DISCH_TAC THEN
+    MP_TAC(ISPEC `(:real^N) DIFF s` COMPONENTS_EQ_SING) THEN
+    MP_TAC(ISPEC `(:real^N) DIFF s` COBOUNDED_IMP_UNBOUNDED) THEN
+    ASM_CASES_TAC `(:real^N) DIFF s = {}` THEN
+    ASM_SIMP_TAC[COMPACT_IMP_BOUNDED; SET_RULE `UNIV DIFF (UNIV DIFF s) = s`;
+                 BOUNDED_EMPTY; FORALL_IN_INSERT; NOT_IN_EMPTY];
+
+    REWRITE_TAC[components; FORALL_IN_GSPEC; IN_DIFF; IN_UNIV] THEN
+    DISCH_TAC THEN REWRITE_TAC[CONNECTED_EQ_CONNECTED_COMPONENT_EQ] THEN
+    REWRITE_TAC[IN_DIFF; IN_UNIV] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC COBOUNDED_UNIQUE_UNBOUNDED_COMPONENT THEN
+    ASM_SIMP_TAC[COMPACT_IMP_BOUNDED;
+                 SET_RULE `UNIV DIFF (UNIV DIFF s) = s`]]);;
+
+let HOMOTOPY_EQUIVALENT_SEPARATION = prove
+ (`!s t. compact s /\ compact t /\ s homotopy_equivalent t
+         ==> (connected((:real^N) DIFF s) <=> connected((:real^N) DIFF t))`,
+  let special = prove
+   (`!s:real^1->bool.
+          bounded s /\ connected((:real^1) DIFF s) ==> s = {}`,
+    REWRITE_TAC[GSYM IS_INTERVAL_CONNECTED_1] THEN REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP BOUNDED_SUBSET_OPEN_INTERVAL) THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM; EXTENSION; NOT_IN_EMPTY] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^1`; `b:real^1`] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IS_INTERVAL_1]) THEN
+    DISCH_THEN(MP_TAC o SPECL [`a:real^1`; `b:real^1`]) THEN
+    REWRITE_TAC[IN_UNIV; IN_DIFF; SUBSET; IN_INTERVAL_1] THEN
+    MESON_TAC[REAL_LT_REFL; REAL_LT_IMP_LE]) in
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `1 <= dimindex(:N)` MP_TAC THENL
+   [REWRITE_TAC[DIMINDEX_GE_1];
+    REWRITE_TAC[ARITH_RULE `1 <= n <=> n = 1 \/ 2 <= n`] THEN
+    REWRITE_TAC[GSYM DIMINDEX_1]] THEN
+  STRIP_TAC THENL
+   [ASSUME_TAC(GEOM_EQUAL_DIMENSION_RULE(ASSUME `dimindex(:N) = dimindex(:1)`)
+       special) THEN
+    EQ_TAC THEN DISCH_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `s:real^N->bool`);
+      FIRST_X_ASSUM(MP_TAC o SPEC `t:real^N->bool`)] THEN
+    ASM_SIMP_TAC[COMPACT_IMP_BOUNDED] THEN DISCH_TAC THEN
+    UNDISCH_TAC `(s:real^N->bool) homotopy_equivalent (t:real^N->bool)` THEN
+    ASM_REWRITE_TAC[HOMOTOPY_EQUIVALENT_EMPTY] THEN DISCH_TAC THEN
+    ASM_REWRITE_TAC[CONNECTED_UNIV; DIFF_EMPTY];
+    REPEAT STRIP_TAC THEN ASM_SIMP_TAC[BORSUK_SEPARATION_THEOREM] THEN
+    MATCH_MP_TAC HOMOTOPY_EQUIVALENT_COHOMOTOPIC_TRIVIALITY_NULL THEN
+    ASM_REWRITE_TAC[]]);;
+
+let JORDAN_BROUWER_SEPARATION = prove
+ (`!s a:real^N r.
+        &0 < r /\ s homeomorphic sphere(a,r) ==> ~connected((:real^N) DIFF s)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `sphere(a:real^N,r)`]
+        HOMOTOPY_EQUIVALENT_SEPARATION) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[HOMEOMORPHIC_COMPACTNESS; COMPACT_SPHERE;
+                  HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT];
+    DISCH_THEN SUBST1_TAC] THEN
+  DISCH_TAC THEN MP_TAC(ISPECL
+   [`(:real^N) DIFF sphere(a,r)`;
+    `ball(a:real^N,r)`] CONNECTED_INTER_FRONTIER) THEN
+  ASM_SIMP_TAC[FRONTIER_BALL; NOT_IMP] THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[GSYM CBALL_DIFF_BALL] THEN MATCH_MP_TAC(SET_RULE
+     `~(b = {})
+      ==> ~((UNIV DIFF (c DIFF b)) INTER b = {})`) THEN
+    ASM_SIMP_TAC[BALL_EQ_EMPTY; REAL_NOT_LE];
+    MATCH_MP_TAC(SET_RULE
+     `~(s UNION t = UNIV) ==> ~(UNIV DIFF t DIFF s = {})`) THEN
+    REWRITE_TAC[BALL_UNION_SPHERE] THEN
+    MESON_TAC[BOUNDED_CBALL; NOT_BOUNDED_UNIV];
+    SET_TAC[]]);;
+
+let JORDAN_BROUWER_FRONTIER = prove
+ (`!s t a:real^N r.
+     2 <= dimindex(:N) /\
+     s homeomorphic sphere(a,r) /\ t IN components((:real^N) DIFF s)
+     ==> frontier t = s`,
+  let lemma = prove
+   (`!s a r. 2 <= dimindex(:N) /\ &0 < r /\ s PSUBSET sphere(a,r)
+             ==> connected((:real^N) DIFF s)`,
+    REWRITE_TAC[PSUBSET_ALT; SUBSET; IN_SPHERE; GSYM REAL_LE_ANTISYM] THEN
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+     `(:real^N) DIFF s =
+      {x:real^N | dist(a,x) <= r /\ ~(x IN s)} UNION
+      {x:real^N | r <= dist(a,x) /\ ~(x IN s)}`
+    SUBST1_TAC THENL
+     [SET_TAC[REAL_LE_TOTAL]; MATCH_MP_TAC CONNECTED_UNION] THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC CONNECTED_INTERMEDIATE_CLOSURE THEN
+      EXISTS_TAC `ball(a:real^N,r)` THEN
+      ASM_SIMP_TAC[CONNECTED_BALL; CLOSURE_BALL; SUBSET; IN_BALL; IN_CBALL;
+                   IN_ELIM_THM] THEN
+      ASM_MESON_TAC[REAL_LT_IMP_LE; REAL_NOT_LE];
+      MATCH_MP_TAC CONNECTED_INTERMEDIATE_CLOSURE THEN
+      EXISTS_TAC `(:real^N) DIFF cball(a,r)` THEN
+      REWRITE_TAC[CLOSURE_COMPLEMENT; SUBSET; IN_DIFF; IN_UNIV;
+                  IN_BALL; IN_CBALL; IN_ELIM_THM; INTERIOR_CBALL] THEN
+      CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[REAL_LT_IMP_LE; REAL_NOT_LE]] THEN
+      MATCH_MP_TAC CONNECTED_OPEN_DIFF_CBALL THEN
+      ASM_REWRITE_TAC[SUBSET_UNIV; CONNECTED_UNIV; OPEN_UNIV];
+      ASM SET_TAC[]]) in
+  MAP_EVERY X_GEN_TAC
+   [`s:real^N->bool`; `c:real^N->bool`; `a:real^N`; `r:real`] THEN
+  ASM_CASES_TAC `r < &0` THENL
+   [ASM_SIMP_TAC[SPHERE_EMPTY; HOMEOMORPHIC_EMPTY; IMP_CONJ; DIFF_EMPTY] THEN
+    SIMP_TAC[snd(EQ_IMP_RULE(SPEC_ALL COMPONENTS_EQ_SING));
+             UNIV_NOT_EMPTY; CONNECTED_UNIV; IN_SING; FRONTIER_UNIV];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `r = &0` THENL
+   [ASM_SIMP_TAC[HOMEOMORPHIC_FINITE_STRONG; SPHERE_SING; FINITE_SING] THEN
+    SIMP_TAC[CARD_CLAUSES; FINITE_EMPTY; GSYM HAS_SIZE; NOT_IN_EMPTY] THEN
+    REWRITE_TAC[HAS_SIZE_CLAUSES; UNWIND_THM2; NOT_IN_EMPTY; IMP_CONJ] THEN
+    SIMP_TAC[LEFT_IMP_EXISTS_THM; CONNECTED_PUNCTURED_UNIVERSE; IN_SING;
+             snd(EQ_IMP_RULE(SPEC_ALL COMPONENTS_EQ_SING)); FRONTIER_SING;
+             SET_RULE `UNIV DIFF s = {} <=> s = UNIV`; FRONTIER_COMPLEMENT;
+             MESON[BOUNDED_SING; NOT_BOUNDED_UNIV] `~((:real^N) = {a})`];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `&0 < r` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC FRONTIER_MINIMAL_SEPARATING_CLOSED THEN
+  ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HOMEOMORPHIC_COMPACTNESS) THEN
+  SIMP_TAC[COMPACT_SPHERE; COMPACT_IMP_CLOSED] THEN DISCH_TAC THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[JORDAN_BROUWER_SEPARATION]; ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homeomorphic]) THEN
+  REWRITE_TAC[HOMEOMORPHISM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`f:real^N->real^N`; `g:real^N->real^N`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`t:real^N->bool`; `IMAGE (f:real^N->real^N) t`]
+        HOMOTOPY_EQUIVALENT_SEPARATION) THEN
+  ANTS_TAC THENL
+   [MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[COMPACT_EQ_BOUNDED_CLOSED; BOUNDED_SUBSET; PSUBSET];
+      DISCH_TAC THEN
+      SUBGOAL_THEN `t homeomorphic (IMAGE (f:real^N->real^N) t)` MP_TAC THENL
+       [REWRITE_TAC[homeomorphic] THEN MAP_EVERY EXISTS_TAC
+         [`f:real^N->real^N`; `g:real^N->real^N`] THEN
+        ASM_REWRITE_TAC[HOMEOMORPHISM] THEN REPEAT CONJ_TAC THEN
+        TRY(FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+          (REWRITE_RULE[IMP_CONJ] CONTINUOUS_ON_SUBSET))) THEN ASM SET_TAC[];
+        ASM_MESON_TAC[HOMEOMORPHIC_COMPACTNESS;
+                      HOMEOMORPHIC_IMP_HOMOTOPY_EQUIVALENT]]];
+      DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC lemma THEN
+      MAP_EVERY EXISTS_TAC [`a:real^N`; `r:real`] THEN ASM SET_TAC[]]);;
+
+let JORDAN_BROUWER_NONSEPARATION = prove
+ (`!s t a:real^N r.
+        2 <= dimindex(:N) /\
+        s homeomorphic sphere(a,r) /\ t PSUBSET s
+        ==> connected((:real^N) DIFF t)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!c. c IN components((:real^N) DIFF s)
+        ==> connected(c UNION (s DIFF t))`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC CONNECTED_INTERMEDIATE_CLOSURE THEN
+    EXISTS_TAC `c:real^N->bool` THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[IN_COMPONENTS_CONNECTED]; ALL_TAC] THEN
+    CONJ_TAC THENL [SET_TAC[]; REWRITE_TAC[UNION_SUBSET; CLOSURE_SUBSET]] THEN
+    SUBGOAL_THEN `s:real^N->bool = frontier c` SUBST1_TAC THENL
+     [ASM_MESON_TAC[JORDAN_BROUWER_FRONTIER]; ALL_TAC] THEN
+    REWRITE_TAC[frontier] THEN SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+    `~(components((:real^N) DIFF s) = {})`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[COMPONENTS_EQ_EMPTY; SET_RULE
+     `UNIV DIFF s = {} <=> s = UNIV`] THEN
+    ASM_MESON_TAC[NOT_BOUNDED_UNIV; COMPACT_EQ_BOUNDED_CLOSED;
+                  HOMEOMORPHIC_COMPACTNESS; COMPACT_SPHERE];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `(:real^N) DIFF t =
+    UNIONS {c UNION (s DIFF t) | c | c IN components((:real^N) DIFF s)}`
+  SUBST1_TAC THENL
+   [MP_TAC(ISPEC `(:real^N) DIFF s` UNIONS_COMPONENTS) THEN
+    REWRITE_TAC[UNIONS_GSPEC] THEN ASM SET_TAC[];
+    MATCH_MP_TAC CONNECTED_UNIONS THEN
+    ASM_REWRITE_TAC[FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[INTERS_GSPEC] THEN ASM SET_TAC[]]);;
+
+let JORDAN_BROUWER_ACCESSIBILITY = prove
+ (`!s c a:real^N r v x.
+        2 <= dimindex(:N) /\
+        s homeomorphic sphere(a,r) /\
+        c IN components((:real^N) DIFF s) /\ x IN c /\
+        open_in (subtopology euclidean s) v /\ ~(v = {})
+        ==> ?g. arc g /\
+                IMAGE g (interval[vec 0,vec 1] DELETE (vec 1)) SUBSET c /\
+                pathstart g = x /\
+                pathfinish g IN v`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HOMEOMORPHIC_COMPACTNESS) THEN
+  REWRITE_TAC[COMPACT_SPHERE] THEN
+  REWRITE_TAC[closed; COMPACT_EQ_BOUNDED_CLOSED] THEN STRIP_TAC THEN
+  MATCH_MP_TAC DENSE_ACCESSIBLE_FRONTIER_POINTS_CONNECTED THEN
+  ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[JORDAN_BROUWER_FRONTIER; OPEN_COMPONENTS;
+                IN_COMPONENTS_CONNECTED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Invariance of domain and corollaries.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let INVARIANCE_OF_DOMAIN = prove
+ (`!f:real^N->real^N s.
+        f continuous_on s /\ open s /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> open(IMAGE f s)`,
+  let lemma = prove
+   (`!f:real^N->real^N a r.
+          f continuous_on cball(a,r) /\ &0 < r /\
+          (!x y. x IN cball(a,r) /\ y IN cball(a,r) /\ f x = f y ==> x = y)
+          ==> open(IMAGE f (ball(a,r)))`,
+    REPEAT STRIP_TAC THEN ASM_CASES_TAC `dimindex(:N) = 1` THENL
+     [MP_TAC(ISPECL [`(:real^N)`; `(:real^1)`] ISOMETRIES_SUBSPACES) THEN
+      ASM_SIMP_TAC[SUBSPACE_UNIV; DIM_UNIV; DIMINDEX_1;
+                   LEFT_IMP_EXISTS_THM] THEN
+      MAP_EVERY X_GEN_TAC [`h:real^N->real^1`; `k:real^1->real^N`] THEN
+      REWRITE_TAC[IN_UNIV] THEN STRIP_TAC THEN
+      MP_TAC(ISPECL [`(h:real^N->real^1) o f o (k:real^1->real^N)`;
+                     `IMAGE (h:real^N->real^1) (cball(a,r))`]
+          INJECTIVE_EQ_1D_OPEN_MAP_UNIV) THEN
+      MATCH_MP_TAC(TAUT
+       `p /\ q /\ r /\ (s ==> t)
+        ==> (p /\ q ==> (r <=> s)) ==> t`) THEN
+      REPEAT CONJ_TAC THENL
+       [REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC) THEN
+        ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON; GSYM IMAGE_o] THEN
+        ASM_REWRITE_TAC[o_DEF; IMAGE_ID];
+        REWRITE_TAC[IS_INTERVAL_CONNECTED_1] THEN
+        MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN
+        ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON; CONNECTED_CBALL];
+        ASM_SIMP_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM;
+                     FORALL_IN_IMAGE; o_DEF] THEN
+        ASM SET_TAC[];
+        DISCH_THEN(MP_TAC o SPEC `IMAGE (h:real^N->real^1) (ball(a,r))`) THEN
+        ASM_SIMP_TAC[IMAGE_SUBSET; BALL_SUBSET_CBALL; GSYM IMAGE_o] THEN
+        ANTS_TAC THENL
+         [MP_TAC(ISPECL [`a:real^N`; `r:real`] OPEN_BALL); ALL_TAC] THEN
+        MATCH_MP_TAC EQ_IMP THENL
+         [CONV_TAC SYM_CONV;
+          REWRITE_TAC[GSYM o_ASSOC] THEN ONCE_REWRITE_TAC[IMAGE_o] THEN
+          ASM_REWRITE_TAC[o_DEF; ETA_AX]] THEN
+        MATCH_MP_TAC OPEN_BIJECTIVE_LINEAR_IMAGE_EQ THEN
+        ASM_MESON_TAC[]];
+       FIRST_ASSUM(MP_TAC o MATCH_MP (ARITH_RULE
+        `~(n = 1) ==> 1 <= n ==> 2 <= n`)) THEN
+       REWRITE_TAC[DIMINDEX_GE_1] THEN DISCH_TAC] THEN
+    REPEAT STRIP_TAC THEN
+    MP_TAC(ISPECL [`IMAGE (f:real^N->real^N) (sphere(a,r))`;
+                   `a:real^N`; `r:real`]
+          JORDAN_BROUWER_SEPARATION) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+      MATCH_MP_TAC HOMEOMORPHIC_COMPACT THEN EXISTS_TAC `f:real^N->real^N` THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET; SPHERE_SUBSET_CBALL;
+                    COMPACT_SPHERE];
+      DISCH_TAC] THEN
+    MP_TAC(ISPEC `(:real^N) DIFF IMAGE f (sphere(a:real^N,r))`
+      COBOUNDED_HAS_BOUNDED_COMPONENT) THEN
+    ASM_REWRITE_TAC[SET_RULE `UNIV DIFF (UNIV DIFF s) = s`] THEN
+    ANTS_TAC THENL
+     [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET; SPHERE_SUBSET_CBALL;
+        COMPACT_SPHERE; COMPACT_CONTINUOUS_IMAGE; COMPACT_IMP_BOUNDED];
+      DISCH_THEN(X_CHOOSE_THEN `c:real^N->bool` STRIP_ASSUME_TAC)] THEN
+    SUBGOAL_THEN
+     `IMAGE (f:real^N->real^N) (ball(a,r)) = c`
+    SUBST1_TAC THENL
+     [ALL_TAC;
+      FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+          OPEN_COMPONENTS)) THEN
+      REWRITE_TAC[GSYM closed] THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET; SPHERE_SUBSET_CBALL;
+        COMPACT_SPHERE; COMPACT_CONTINUOUS_IMAGE; COMPACT_IMP_CLOSED]] THEN
+    MATCH_MP_TAC(SET_RULE
+     `~(c = {}) /\ (~(c INTER t = {}) ==> t SUBSET c) /\ c SUBSET t
+      ==> t = c`) THEN
+    REPEAT STRIP_TAC THENL
+     [ASM_MESON_TAC[IN_COMPONENTS_NONEMPTY];
+      FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ]
+          COMPONENTS_MAXIMAL)) THEN
+      ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CONNECTED_CONTINUOUS_IMAGE THEN
+        REWRITE_TAC[CONNECTED_BALL] THEN
+        ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; BALL_SUBSET_CBALL];
+        REWRITE_TAC[GSYM CBALL_DIFF_SPHERE] THEN
+        MP_TAC(ISPECL [`a:real^N`; `r:real`] SPHERE_SUBSET_CBALL) THEN
+        ASM SET_TAC[]];
+      FIRST_ASSUM(MP_TAC o MATCH_MP IN_COMPONENTS_SUBSET) THEN
+      FIRST_ASSUM(MP_TAC o SPEC `(:real^N) DIFF IMAGE f (cball(a:real^N,r))` o
+        MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ] COMPONENTS_MAXIMAL)) THEN
+      SIMP_TAC[SET_RULE `UNIV DIFF t SUBSET UNIV DIFF s <=> s SUBSET t`;
+               IMAGE_SUBSET; SPHERE_SUBSET_CBALL] THEN
+      MATCH_MP_TAC(TAUT `p /\ ~r /\ (~q ==> s) ==> (p /\ q ==> r) ==> s`) THEN
+      REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC(INST_TYPE [`:N`,`:M`]
+          CONNECTED_COMPLEMENT_HOMEOMORPHIC_CONVEX_COMPACT) THEN
+        EXISTS_TAC `cball(a:real^N,r)` THEN
+        ASM_REWRITE_TAC[CONVEX_CBALL; COMPACT_CBALL] THEN
+        ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+        MATCH_MP_TAC HOMEOMORPHIC_COMPACT THEN
+        EXISTS_TAC `f:real^N->real^N` THEN ASM_REWRITE_TAC[COMPACT_CBALL];
+        DISCH_THEN(MP_TAC o
+          MATCH_MP(REWRITE_RULE[IMP_CONJ_ALT] BOUNDED_SUBSET)) THEN
+        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC COBOUNDED_IMP_UNBOUNDED THEN
+        REWRITE_TAC[SET_RULE `UNIV DIFF (UNIV DIFF s) = s`] THEN
+        ASM_MESON_TAC[COMPACT_IMP_BOUNDED; COMPACT_CONTINUOUS_IMAGE;
+                      COMPACT_CBALL];
+        REWRITE_TAC[GSYM CBALL_DIFF_SPHERE] THEN ASM SET_TAC[]]]) in
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[OPEN_SUBOPEN] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `a:real^N`) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `r:real` THEN STRIP_TAC THEN
+  EXISTS_TAC `IMAGE (f:real^N->real^N) (ball(a,r))` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC lemma THEN ASM_MESON_TAC[SUBSET; CONTINUOUS_ON_SUBSET];
+    ASM_SIMP_TAC[FUN_IN_IMAGE; CENTRE_IN_BALL];
+    MATCH_MP_TAC IMAGE_SUBSET THEN
+    ASM_MESON_TAC[BALL_SUBSET_CBALL; SUBSET_TRANS]]);;
+
+let INVARIANCE_OF_DOMAIN_SUBSPACES = prove
+ (`!f:real^M->real^N u v s.
+        subspace u /\ subspace v /\ dim v <= dim u /\
+        f continuous_on s /\ IMAGE f s SUBSET v /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+        open_in (subtopology euclidean u) s
+        ==> open_in (subtopology euclidean v) (IMAGE f s)`,
+  let lemma0 = prove
+   (`!f:real^M->real^M s u.
+          subspace s /\ dim s = dimindex(:N) /\
+          f continuous_on u /\ IMAGE f u SUBSET s /\
+          (!x y. x IN u /\ y IN u /\ f x = f y ==> x = y) /\
+          open_in (subtopology euclidean s) u
+          ==> open_in (subtopology euclidean s) (IMAGE f u)`,
+    REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`(:real^N)`; `s:real^M->bool`]
+      HOMEOMORPHIC_SUBSPACES) THEN
+    ASM_REWRITE_TAC[DIM_UNIV; SUBSPACE_UNIV] THEN
+    REWRITE_TAC[homeomorphic; homeomorphism; LEFT_IMP_EXISTS_THM; IN_UNIV] THEN
+    MAP_EVERY X_GEN_TAC [`h:real^N->real^M`; `k:real^M->real^N`] THEN
+    STRIP_TAC THEN MP_TAC(ISPECL
+     [`(k:real^M->real^N) o f o (h:real^N->real^M)`;
+      `IMAGE (k:real^M->real^N) u`] INVARIANCE_OF_DOMAIN) THEN
+    REWRITE_TAC[GSYM IMAGE_o; o_THM] THEN
+    SUBGOAL_THEN
+     `!t. open t <=>
+          open_in (subtopology euclidean (IMAGE (k:real^M->real^N) s)) t`
+     (fun th -> REWRITE_TAC[th])
+    THENL [ASM_REWRITE_TAC[SUBTOPOLOGY_UNIV; GSYM OPEN_IN]; ALL_TAC] THEN
+    ANTS_TAC THENL
+     [REPEAT CONJ_TAC THENL
+       [REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC) THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+            CONTINUOUS_ON_SUBSET)) THEN
+        FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN
+        REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[];
+        MATCH_MP_TAC HOMEOMORPHISM_IMP_OPEN_MAP THEN
+        MAP_EVERY EXISTS_TAC [`h:real^N->real^M`; `s:real^M->bool`] THEN
+        ASM_REWRITE_TAC[homeomorphism];
+        REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+        FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN
+        ASM_SIMP_TAC[SUBSET] THEN REPEAT STRIP_TAC THEN AP_TERM_TAC THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN ASM SET_TAC[]];
+      ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+      SUBGOAL_THEN
+       `IMAGE f u =
+        IMAGE (h:real^N->real^M) (IMAGE ((k o f o h) o (k:real^M->real^N)) u)`
+      SUBST1_TAC THENL
+       [REWRITE_TAC[GSYM IMAGE_o] THEN MATCH_MP_TAC(SET_RULE
+         `(!x. x IN s ==> f x = g x) ==> IMAGE f s = IMAGE g s`) THEN
+        REPEAT(FIRST_X_ASSUM(MP_TAC o MATCH_MP OPEN_IN_IMP_SUBSET)) THEN
+        ASM_SIMP_TAC[SUBSET; o_THM] THEN ASM SET_TAC[];
+        MATCH_MP_TAC HOMEOMORPHISM_IMP_OPEN_MAP THEN
+        MAP_EVERY EXISTS_TAC [`k:real^M->real^N`; `(:real^N)`] THEN
+        ASM_REWRITE_TAC[homeomorphism]]]) in
+  let lemma1 = prove
+   (`!f:real^N->real^N s u.
+          subspace s /\ f continuous_on u /\ IMAGE f u SUBSET s /\
+          (!x y. x IN u /\ y IN u /\ f x = f y ==> x = y) /\
+          open_in (subtopology euclidean s) u
+          ==> open_in (subtopology euclidean s) (IMAGE f u)`,
+    REWRITE_TAC[INJECTIVE_ON_ALT] THEN REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN
+    ABBREV_TAC `s' = {y:real^N | !x. x IN s ==> orthogonal x y}` THEN
+    SUBGOAL_THEN `subspace(s':real^N->bool)` ASSUME_TAC THENL
+      [EXPAND_TAC "s'" THEN REWRITE_TAC[SUBSPACE_ORTHOGONAL_TO_VECTORS];
+       FIRST_ASSUM(ASSUME_TAC o MATCH_MP SUBSPACE_IMP_NONEMPTY)] THEN
+    ABBREV_TAC `g:real^(N,N)finite_sum->real^(N,N)finite_sum =
+                  \z. pastecart (f(fstcart z)) (sndcart z)` THEN
+    SUBGOAL_THEN
+     `g continuous_on ((u:real^N->bool) PCROSS s') /\
+      IMAGE g (u PCROSS s') SUBSET (s:real^N->bool) PCROSS (s':real^N->bool) /\
+      (!w z. w IN u PCROSS s' /\ z IN u PCROSS s' ==> (g w = g z <=> w = z))`
+    STRIP_ASSUME_TAC THENL
+     [EXPAND_TAC "g" THEN REPEAT CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+        GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART;
+                 IMAGE_FSTCART_PCROSS] THEN
+        COND_CASES_TAC THEN ASM_REWRITE_TAC[CONTINUOUS_ON_EMPTY];
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS] THEN
+        SIMP_TAC[PASTECART_IN_PCROSS; SNDCART_PASTECART;
+                 FSTCART_PASTECART] THEN
+        ASM SET_TAC[];
+        EXPAND_TAC "g" THEN REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+        REWRITE_TAC[FORALL_IN_PCROSS; FSTCART_PASTECART;
+                    SNDCART_PASTECART] THEN
+        ASM_SIMP_TAC[PASTECART_INJ]];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `open_in (subtopology euclidean (s PCROSS s'))
+              (IMAGE (g:real^(N,N)finite_sum->real^(N,N)finite_sum)
+                     (u PCROSS s'))`
+    MP_TAC THENL
+     [MATCH_MP_TAC lemma0 THEN
+      ASM_SIMP_TAC[SUBSPACE_PCROSS; OPEN_IN_PCROSS_EQ; OPEN_IN_REFL] THEN
+      CONJ_TAC THENL [ASM_SIMP_TAC[DIM_PCROSS]; ASM_MESON_TAC[]] THEN
+      MP_TAC(ISPECL [`s:real^N->bool`; `(:real^N)`]
+        DIM_SUBSPACE_ORTHOGONAL_TO_VECTORS) THEN
+      ASM_REWRITE_TAC[SUBSET_UNIV; SUBSPACE_UNIV; IN_UNIV; DIM_UNIV] THEN
+      ARITH_TAC;
+      SUBGOAL_THEN
+       `IMAGE (g:real^(N,N)finite_sum->real^(N,N)finite_sum) (u PCROSS s') =
+        IMAGE f u PCROSS s'`
+      SUBST1_TAC THENL
+       [EXPAND_TAC "g" THEN
+        REWRITE_TAC[EXTENSION; EXISTS_PASTECART; PASTECART_IN_PCROSS;
+                    IN_IMAGE; FORALL_PASTECART; PASTECART_IN_PCROSS;
+                    FSTCART_PASTECART; SNDCART_PASTECART; PASTECART_INJ] THEN
+        ASM SET_TAC[];
+        ASM_SIMP_TAC[OPEN_IN_PCROSS_EQ; IMAGE_EQ_EMPTY] THEN
+        STRIP_TAC THEN ASM_SIMP_TAC[IMAGE_CLAUSES; OPEN_IN_EMPTY]]]) in
+  REWRITE_TAC[INJECTIVE_ON_ALT] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN
+  MP_TAC(ISPECL [`u:real^M->bool`; `dim(v:real^N->bool)`]
+    CHOOSE_SUBSPACE_OF_SUBSPACE) THEN ASM_SIMP_TAC[SPAN_OF_SUBSPACE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:real^M->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`v:real^N->bool`; `v:real^M->bool`]
+        HOMEOMORPHIC_SUBSPACES) THEN
+  ASM_REWRITE_TAC[homeomorphic; homeomorphism; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`h:real^N->real^M`; `k:real^M->real^N`] THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN
+   `IMAGE (f:real^M->real^N) s =
+    IMAGE (k:real^M->real^N) (IMAGE ((h:real^N->real^M) o f) s)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[GSYM IMAGE_o] THEN MATCH_MP_TAC(SET_RULE
+     `(!x. x IN u ==> f x = g x) ==> IMAGE f u = IMAGE g u`) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET]) THEN
+    ASM_SIMP_TAC[SUBSET; o_THM] THEN ASM SET_TAC[];
+    MATCH_MP_TAC HOMEOMORPHISM_IMP_OPEN_MAP THEN
+    MAP_EVERY EXISTS_TAC [`h:real^N->real^M`; `v:real^M->bool`] THEN
+    ASM_REWRITE_TAC[homeomorphism] THEN
+    MATCH_MP_TAC OPEN_IN_SUBSET_TRANS THEN EXISTS_TAC `u:real^M->bool` THEN
+    ASM_REWRITE_TAC[IMAGE_o] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    REWRITE_TAC[GSYM IMAGE_o] THEN MATCH_MP_TAC lemma1 THEN
+    ASM_REWRITE_TAC[IMAGE_o; o_THM] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+    ASM SET_TAC[]]);;
+
+let INVARIANCE_OF_DIMENSION_SUBSPACES = prove
+ (`!f:real^M->real^N u v s.
+      subspace u /\ subspace v /\
+      ~(s = {}) /\ open_in (subtopology euclidean u) s /\
+      f continuous_on s /\ IMAGE f s SUBSET v /\
+      (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+      ==> dim u <= dim v`,
+  REWRITE_TAC[GSYM NOT_LT] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`u:real^M->bool`; `dim(v:real^N->bool)`]
+    CHOOSE_SUBSPACE_OF_SUBSPACE) THEN
+  ASM_SIMP_TAC[SPAN_OF_SUBSPACE; LE_LT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^M->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`v:real^N->bool`; `t:real^M->bool`]
+        HOMEOMORPHIC_SUBSPACES) THEN
+  FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+  ASM_REWRITE_TAC[homeomorphic; homeomorphism; NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`h:real^N->real^M`; `k:real^M->real^N`] THEN
+  STRIP_TAC THEN MP_TAC(ISPECL
+   [`(h:real^N->real^M) o (f:real^M->real^N)`; `u:real^M->bool`;
+    `u:real^M->bool`; `s:real^M->bool`]
+        INVARIANCE_OF_DOMAIN_SUBSPACES) THEN
+  ASM_REWRITE_TAC[LE_LT; NOT_IMP] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+    REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[];
+    REWRITE_TAC[o_THM] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `IMAGE ((h:real^N->real^M) o (f:real^M->real^N)) s SUBSET t`
+  ASSUME_TAC THENL [REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[]; ALL_TAC] THEN
+  ABBREV_TAC `w = IMAGE ((h:real^N->real^M) o (f:real^M->real^N)) s` THEN
+  DISCH_TAC THEN UNDISCH_TAC `dim(t:real^M->bool) < dim(u:real^M->bool)` THEN
+  REWRITE_TAC[NOT_LT] THEN MP_TAC(ISPECL
+   [`w:real^M->bool`; `u:real^M->bool`] DIM_OPEN_IN) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[IMAGE_EQ_EMPTY]; DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  ASM_SIMP_TAC[DIM_SUBSET]);;
+
+let INVARIANCE_OF_DOMAIN_AFFINE_SETS = prove
+ (`!f:real^M->real^N u v s.
+        affine u /\ affine v /\ aff_dim v <= aff_dim u /\
+        f continuous_on s /\ IMAGE f s SUBSET v /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+        open_in (subtopology euclidean u) s
+        ==> open_in (subtopology euclidean v) (IMAGE f s)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[IMAGE_CLAUSES; OPEN_IN_EMPTY; INJECTIVE_ON_ALT] THEN
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?a:real^M b:real^N. a IN s /\ a IN u /\ b IN v`
+  STRIP_ASSUME_TAC THENL
+   [FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`(\x. --b + x) o (f:real^M->real^N) o (\x. a + x)`;
+    `IMAGE (\x:real^M. --a + x) u`; `IMAGE (\x:real^N. --b + x) v`;
+    `IMAGE (\x:real^M. --a + x) s`] INVARIANCE_OF_DOMAIN_SUBSPACES) THEN
+  REWRITE_TAC[IMAGE_o; INJECTIVE_ON_ALT; OPEN_IN_TRANSLATION_EQ] THEN
+  SIMP_TAC[IMP_CONJ; GSYM INT_OF_NUM_LE; GSYM AFF_DIM_DIM_SUBSPACE] THEN
+  ASM_REWRITE_TAC[AFF_DIM_TRANSLATION_EQ; RIGHT_FORALL_IMP_THM] THEN
+  SIMP_TAC[FORALL_IN_IMAGE; o_THM; GSYM IMAGE_o; IMP_IMP; GSYM CONJ_ASSOC] THEN
+  ANTS_TAC THENL
+   [ONCE_REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+     [CONJ_TAC THEN MATCH_MP_TAC AFFINE_IMP_SUBSPACE THEN
+      ASM_REWRITE_TAC[AFFINE_TRANSLATION_EQ] THEN REWRITE_TAC[IN_IMAGE;
+        VECTOR_ARITH `vec 0:real^N = --a + x <=> x = a`] THEN
+      ASM_MESON_TAC[];
+      REPEAT CONJ_TAC THENL
+       [REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+           SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID]);
+        REWRITE_TAC[GSYM o_ASSOC] THEN REWRITE_TAC[IMAGE_o] THEN
+        MATCH_MP_TAC IMAGE_SUBSET;
+        REWRITE_TAC[VECTOR_ARITH `a + x:real^N = a + y <=> x = y`]]];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[VECTOR_ARITH `a + --a + x:real^N = x`; GSYM IMAGE_o; o_DEF;
+               IMAGE_ID; ETA_AX]);;
+
+let INVARIANCE_OF_DIMENSION_AFFINE_SETS = prove
+ (`!f:real^M->real^N u v s.
+      affine u /\ affine v /\
+      ~(s = {}) /\ open_in (subtopology euclidean u) s /\
+      f continuous_on s /\ IMAGE f s SUBSET v /\
+      (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+      ==> aff_dim u <= aff_dim v`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[IMAGE_CLAUSES; OPEN_IN_EMPTY; INJECTIVE_ON_ALT] THEN
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?a:real^M b:real^N. a IN s /\ a IN u /\ b IN v`
+  STRIP_ASSUME_TAC THENL
+   [FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN
+    ASM SET_TAC[];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`(\x. --b + x) o (f:real^M->real^N) o (\x. a + x)`;
+    `IMAGE (\x:real^M. --a + x) u`; `IMAGE (\x:real^N. --b + x) v`;
+    `IMAGE (\x:real^M. --a + x) s`] INVARIANCE_OF_DIMENSION_SUBSPACES) THEN
+  REWRITE_TAC[IMAGE_o; INJECTIVE_ON_ALT; OPEN_IN_TRANSLATION_EQ] THEN
+  SIMP_TAC[IMP_CONJ; GSYM INT_OF_NUM_LE; GSYM AFF_DIM_DIM_SUBSPACE] THEN
+  ASM_REWRITE_TAC[AFF_DIM_TRANSLATION_EQ; RIGHT_FORALL_IMP_THM] THEN
+  SIMP_TAC[FORALL_IN_IMAGE; o_THM; GSYM IMAGE_o; IMP_IMP; GSYM CONJ_ASSOC] THEN
+  DISCH_THEN MATCH_MP_TAC THEN ONCE_REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC AFFINE_IMP_SUBSPACE THEN
+    ASM_REWRITE_TAC[AFFINE_TRANSLATION_EQ] THEN REWRITE_TAC[IN_IMAGE;
+      VECTOR_ARITH `vec 0:real^N = --a + x <=> x = a`] THEN
+    ASM_MESON_TAC[];
+    ASM_REWRITE_TAC[IMAGE_EQ_EMPTY] THEN REPEAT CONJ_TAC THENL
+     [REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+         SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID]);
+      REWRITE_TAC[GSYM o_ASSOC] THEN REWRITE_TAC[IMAGE_o] THEN
+      MATCH_MP_TAC IMAGE_SUBSET;
+      REWRITE_TAC[VECTOR_ARITH `a + x:real^N = a + y <=> x = y`]]] THEN
+  ASM_SIMP_TAC[VECTOR_ARITH `a + --a + x:real^N = x`; GSYM IMAGE_o; o_DEF;
+               IMAGE_ID; ETA_AX]);;
+
+let INVARIANCE_OF_DIMENSION = prove
+ (`!f:real^M->real^N s.
+        f continuous_on s /\ open s /\ ~(s = {}) /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> dimindex(:M) <= dimindex(:N)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM DIM_UNIV] THEN
+  MATCH_MP_TAC INVARIANCE_OF_DIMENSION_SUBSPACES THEN
+  MAP_EVERY EXISTS_TAC [`f:real^M->real^N`; `s:real^M->bool`] THEN
+  ASM_REWRITE_TAC[SUBSPACE_UNIV; SUBSET_UNIV; SUBTOPOLOGY_UNIV;
+                  GSYM OPEN_IN]);;
+
+let CONTINUOUS_INJECTIVE_IMAGE_SUBSPACE_DIM_LE = prove
+ (`!f:real^M->real^N s t.
+        subspace s /\ subspace t /\
+        f continuous_on s /\ IMAGE f s SUBSET t /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> dim(s) <= dim(t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INVARIANCE_OF_DIMENSION_SUBSPACES THEN
+  MAP_EVERY EXISTS_TAC [`f:real^M->real^N`; `s:real^M->bool`] THEN
+  ASM_REWRITE_TAC[OPEN_IN_REFL] THEN ASM_SIMP_TAC[SUBSPACE_IMP_NONEMPTY]);;
+
+let INVARIANCE_OF_DIMENSION_CONVEX_DOMAIN = prove
+ (`!f:real^M->real^N s t.
+
+        convex s /\ f continuous_on s /\ IMAGE f s SUBSET affine hull t /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> aff_dim(s) <= aff_dim(t)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[AFF_DIM_EMPTY; AFF_DIM_GE] THEN
+  MP_TAC(ISPECL
+   [`f:real^M->real^N`; `affine hull s:real^M->bool`;
+    `affine hull t:real^N->bool`; `relative_interior s:real^M->bool`]
+        INVARIANCE_OF_DIMENSION_AFFINE_SETS) THEN
+  ASM_REWRITE_TAC[AFFINE_AFFINE_HULL; AFF_DIM_AFFINE_HULL;
+                  OPEN_IN_RELATIVE_INTERIOR] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[RELATIVE_INTERIOR_EQ_EMPTY]; ALL_TAC] THEN
+  ASSUME_TAC(ISPEC `s:real^M->bool` RELATIVE_INTERIOR_SUBSET) THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ASM SET_TAC[]]);;
+
+let HOMEOMORPHIC_CONVEX_SETS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        convex s /\ convex t /\ s homeomorphic t ==> aff_dim s = aff_dim t`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homeomorphic]) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; GSYM INT_LE_ANTISYM; homeomorphism] THEN
+  MAP_EVERY X_GEN_TAC [`f:real^M->real^N`; `g:real^N->real^M`] THEN
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC INVARIANCE_OF_DIMENSION_CONVEX_DOMAIN THENL
+   [EXISTS_TAC `f:real^M->real^N`; EXISTS_TAC `g:real^N->real^M`] THEN
+  ASM_REWRITE_TAC[HULL_SUBSET] THEN ASM SET_TAC[]);;
+
+let HOMEOMORPHIC_CONVEX_COMPACT_SETS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        convex s /\ compact s /\ convex t /\ compact t
+        ==> (s homeomorphic t <=> aff_dim s = aff_dim t)`,
+  MESON_TAC[HOMEOMORPHIC_CONVEX_SETS; HOMEOMORPHIC_CONVEX_COMPACT_SETS]);;
+
+let INVARIANCE_OF_DOMAIN_GEN = prove
+ (`!f:real^M->real^N s.
+        dimindex(:N) <= dimindex(:M) /\ f continuous_on s /\ open s /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> open(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`f:real^M->real^N`; `(:real^M)`; `(:real^N)`; `s:real^M->bool`]
+   INVARIANCE_OF_DOMAIN_SUBSPACES) THEN
+  ASM_REWRITE_TAC[SUBTOPOLOGY_UNIV; GSYM OPEN_IN; SUBSPACE_UNIV;
+                  DIM_UNIV; SUBSET_UNIV]);;
+
+let INJECTIVE_INTO_1D_IMP_OPEN_MAP_UNIV = prove
+ (`!f:real^N->real^1 s t.
+        f continuous_on s /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+        open t /\ t SUBSET s
+        ==> open (IMAGE f t)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC INVARIANCE_OF_DOMAIN_GEN THEN
+  ASM_REWRITE_TAC[DIMINDEX_1; DIMINDEX_GE_1] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ASM SET_TAC[]]);;
+
+let CONTINUOUS_ON_INVERSE_OPEN = prove
+ (`!f:real^M->real^N g s.
+        dimindex(:N) <= dimindex(:M) /\
+        f continuous_on s /\ open s /\
+        (!x. x IN s ==> g(f x) = x)
+        ==> g continuous_on IMAGE f s`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[CONTINUOUS_OPEN_IN_PREIMAGE_EQ] THEN
+  X_GEN_TAC `t:real^M->bool` THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `{x | x IN IMAGE f s /\ g x IN t} = IMAGE (f:real^M->real^N) (s INTER t)`
+  SUBST1_TAC THENL [ASM SET_TAC[]; MATCH_MP_TAC OPEN_OPEN_IN_TRANS] THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL [ALL_TAC; SET_TAC[]] THEN
+  CONJ_TAC THEN MATCH_MP_TAC INVARIANCE_OF_DOMAIN_GEN THEN
+  ASM_SIMP_TAC[OPEN_INTER; IN_INTER] THEN
+  ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; INTER_SUBSET]);;
+
+let CONTINUOUS_ON_INVERSE_INTO_1D = prove
+ (`!f:real^N->real^1 g s t.
+        f continuous_on s /\
+        (path_connected s \/ compact s \/ open s) /\
+        IMAGE f s = t /\ (!x. x IN s ==> g(f x) = x)
+        ==> g continuous_on t`,
+  REPEAT STRIP_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_INVERSE_OPEN_MAP THEN
+    MAP_EVERY EXISTS_TAC [`f:real^N->real^1`; `s:real^N->bool`] THEN
+    ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM) THEN
+    MATCH_MP_TAC INJECTIVE_INTO_1D_IMP_OPEN_MAP THEN ASM SET_TAC[];
+    ASM_MESON_TAC[CONTINUOUS_ON_INVERSE];
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    MATCH_MP_TAC CONTINUOUS_ON_INVERSE_OPEN THEN
+    ASM_REWRITE_TAC[DIMINDEX_1; DIMINDEX_GE_1]]);;
+
+let REAL_CONTINUOUS_ON_INVERSE = prove
+ (`!f g s. f real_continuous_on s /\
+           (is_realinterval s \/ real_compact s \/ real_open s) /\
+           (!x. x IN s ==> g(f x) = x)
+           ==> g real_continuous_on (IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[REAL_CONTINUOUS_ON; real_compact; REAL_OPEN;
+              IS_REALINTERVAL_IS_INTERVAL] THEN
+  DISCH_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_INVERSE_INTO_1D THEN
+  MAP_EVERY EXISTS_TAC [`lift o f o drop`; `IMAGE lift s`] THEN
+  ASM_REWRITE_TAC[GSYM IS_INTERVAL_PATH_CONNECTED_1] THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE; o_DEF; LIFT_DROP; GSYM IMAGE_o]);;
+
+let REAL_CONTINUOUS_ON_INVERSE_ALT = prove
+ (`!f g s t. f real_continuous_on s /\
+             (is_realinterval s \/ real_compact s \/ real_open s) /\
+             IMAGE f s = t /\ (!x. x IN s ==> g(f x) = x)
+           ==> g real_continuous_on t`,
+  MESON_TAC[REAL_CONTINUOUS_ON_INVERSE]);;
+
+let INVARIANCE_OF_DOMAIN_HOMEOMORPHISM = prove
+ (`!f:real^M->real^N s.
+        dimindex(:N) <= dimindex(:M) /\ f continuous_on s /\ open s /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> ?g. homeomorphism (s,IMAGE f s) (f,g)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INJECTIVE_ON_LEFT_INVERSE]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^M` THEN
+  DISCH_TAC THEN ASM_REWRITE_TAC[homeomorphism] THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_INVERSE_OPEN] THEN ASM SET_TAC[]);;
+
+let INVARIANCE_OF_DOMAIN_HOMEOMORPHIC = prove
+ (`!f:real^M->real^N s.
+        dimindex(:N) <= dimindex(:M) /\ f continuous_on s /\ open s /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> s homeomorphic (IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP INVARIANCE_OF_DOMAIN_HOMEOMORPHISM) THEN
+  REWRITE_TAC[homeomorphic] THEN MESON_TAC[]);;
+
+let HOMEOMORPHIC_INTERVALS_EQ = prove
+ (`(!a b:real^M c d:real^N.
+        interval[a,b] homeomorphic interval[c,d] <=>
+        aff_dim(interval[a,b]) = aff_dim(interval[c,d])) /\
+   (!a b:real^M c d:real^N.
+        interval[a,b] homeomorphic interval(c,d) <=>
+        interval[a,b] = {} /\ interval(c,d) = {}) /\
+   (!a b:real^M c d:real^N.
+        interval(a,b) homeomorphic interval[c,d] <=>
+        interval(a,b) = {} /\ interval[c,d] = {}) /\
+   (!a b:real^M c d:real^N.
+        interval(a,b) homeomorphic interval(c,d) <=>
+        interval(a,b) = {} /\ interval(c,d) = {} \/
+        ~(interval(a,b) = {}) /\ ~(interval(c,d) = {}) /\
+        dimindex(:M) = dimindex(:N))`,
+  SIMP_TAC[HOMEOMORPHIC_CONVEX_COMPACT_SETS_EQ; CONVEX_INTERVAL;
+           COMPACT_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN EQ_TAC THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC[HOMEOMORPHIC_EMPTY] THENL
+   [FIRST_ASSUM(MP_TAC o MATCH_MP HOMEOMORPHIC_COMPACTNESS) THEN
+    REWRITE_TAC[COMPACT_INTERVAL_EQ] THEN ASM_MESON_TAC[HOMEOMORPHIC_EMPTY];
+    FIRST_ASSUM(MP_TAC o MATCH_MP HOMEOMORPHIC_COMPACTNESS) THEN
+    REWRITE_TAC[COMPACT_INTERVAL_EQ] THEN ASM_MESON_TAC[HOMEOMORPHIC_EMPTY];
+    MATCH_MP_TAC(TAUT
+     `(p <=> q) /\ (~p /\ ~q ==> r) ==> p /\ q \/ ~p /\ ~q /\ r`) THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[HOMEOMORPHIC_EMPTY]; STRIP_TAC] THEN
+    REWRITE_TAC[GSYM LE_ANTISYM] THEN CONJ_TAC THEN
+    MATCH_MP_TAC INVARIANCE_OF_DIMENSION THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homeomorphic]) THENL
+     [ALL_TAC; GEN_REWRITE_TAC LAND_CONV [SWAP_EXISTS_THM]] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+    REWRITE_TAC[homeomorphism] THEN STRIP_TAC THENL
+     [EXISTS_TAC `interval(a:real^M,b)`;
+      EXISTS_TAC `interval(c:real^N,d)`] THEN
+    ASM_REWRITE_TAC[OPEN_INTERVAL] THEN ASM SET_TAC[];
+    TRANS_TAC HOMEOMORPHIC_TRANS
+     `IMAGE ((\x. lambda i. x$i):real^M->real^N)
+            (interval(a,b))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC INVARIANCE_OF_DOMAIN_HOMEOMORPHIC THEN
+      REPEAT CONJ_TAC THENL
+       [ASM_MESON_TAC[LE_REFL];
+        MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN
+        SIMP_TAC[linear; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+                 LAMBDA_BETA; CART_EQ];
+        REWRITE_TAC[OPEN_INTERVAL];
+        SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN ASM_MESON_TAC[]];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `IMAGE ((\x. lambda i. x$i):real^M->real^N)
+            (interval(a,b)) =
+            interval((lambda i. a$i),(lambda i. b$i))`
+    SUBST1_TAC THENL
+     [MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+      SIMP_TAC[IN_INTERVAL; LAMBDA_BETA] THEN
+      CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+      X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+      EXISTS_TAC `(lambda i. (y:real^N)$i):real^M` THEN
+      SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN
+      FIRST_ASSUM(SUBST1_TAC o SYM) THEN   SIMP_TAC[CART_EQ; LAMBDA_BETA];
+      MATCH_MP_TAC HOMEOMORPHIC_OPEN_INTERVALS THEN
+      GEN_REWRITE_TAC I [TAUT `(p <=> q) <=> (~p <=> ~q)`] THEN
+      SIMP_TAC[INTERVAL_NE_EMPTY; LAMBDA_BETA] THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o
+        GEN_REWRITE_RULE I [INTERVAL_NE_EMPTY])) THEN
+      ASM_MESON_TAC[]]]);;
+
+let CONTINUOUS_IMAGE_SUBSET_INTERIOR = prove
+ (`!f:real^M->real^N s.
+        f continuous_on s /\ dimindex(:N) <= dimindex(:M) /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> IMAGE f (interior s) SUBSET interior(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTERIOR_MAXIMAL THEN
+  SIMP_TAC[IMAGE_SUBSET; INTERIOR_SUBSET] THEN
+  ASM_CASES_TAC `interior s:real^M->bool = {}` THENL
+   [ASM_REWRITE_TAC[INTERIOR_EMPTY; OPEN_EMPTY; IMAGE_CLAUSES];
+    MATCH_MP_TAC INVARIANCE_OF_DOMAIN_GEN] THEN
+  ASM_REWRITE_TAC[OPEN_INTERIOR] THEN
+  ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; INTERIOR_SUBSET; SUBSET]);;
+
+let HOMEOMORPHIC_INTERIORS_SAME_DIMENSION = prove
+ (`!s:real^M->bool t:real^N->bool.
+        dimindex(:M) = dimindex(:N) /\ s homeomorphic t
+        ==> (interior s) homeomorphic (interior t)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HOMEOMORPHIC_MINIMAL]) THEN
+  REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^M->real^N` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^M` THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[REWRITE_RULE[SUBSET] INTERIOR_SUBSET] THEN
+  REWRITE_TAC[SET_RULE `(!x. x IN s ==> f x IN t) <=> IMAGE f s SUBSET t`] THEN
+  REPEAT CONJ_TAC THENL
+   [SUBGOAL_THEN `t = IMAGE (f:real^M->real^N) s` SUBST1_TAC THENL
+     [ASM SET_TAC[];
+      MATCH_MP_TAC CONTINUOUS_IMAGE_SUBSET_INTERIOR THEN
+      ASM_MESON_TAC[LE_REFL]];
+    SUBGOAL_THEN `s = IMAGE (g:real^N->real^M) t` SUBST1_TAC THENL
+     [ASM SET_TAC[];
+      MATCH_MP_TAC CONTINUOUS_IMAGE_SUBSET_INTERIOR THEN
+      ASM_MESON_TAC[LE_REFL]];
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; INTERIOR_SUBSET];
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; INTERIOR_SUBSET]]);;
+
+let HOMEOMORPHIC_INTERIORS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homeomorphic t /\ (interior s = {} <=> interior t = {})
+        ==> (interior s) homeomorphic (interior t)`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `interior t:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[HOMEOMORPHIC_EMPTY] THEN STRIP_TAC THEN
+  MATCH_MP_TAC HOMEOMORPHIC_INTERIORS_SAME_DIMENSION THEN
+  ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM
+   (STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [HOMEOMORPHIC_MINIMAL]) THEN
+  REWRITE_TAC[GSYM LE_ANTISYM] THEN CONJ_TAC THEN
+  MATCH_MP_TAC INVARIANCE_OF_DIMENSION THENL
+   [MAP_EVERY EXISTS_TAC [`f:real^M->real^N`; `interior s:real^M->bool`];
+    MAP_EVERY EXISTS_TAC [`g:real^N->real^M`; `interior t:real^N->bool`]] THEN
+  ASM_REWRITE_TAC[OPEN_INTERIOR] THEN
+  ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; INTERIOR_SUBSET; SUBSET]);;
+
+let HOMEOMORPHIC_FRONTIERS_SAME_DIMENSION = prove
+ (`!s:real^M->bool t:real^N->bool.
+        dimindex(:M) = dimindex(:N) /\
+        s homeomorphic t /\ closed s /\ closed t
+        ==> (frontier s) homeomorphic (frontier t)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HOMEOMORPHIC_MINIMAL]) THEN
+  REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^M->real^N` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^M` THEN
+  ASM_SIMP_TAC[REWRITE_RULE[SUBSET] FRONTIER_SUBSET_CLOSED] THEN
+  STRIP_TAC THEN ONCE_REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[FRONTIER_SUBSET_CLOSED; CONTINUOUS_ON_SUBSET]] THEN
+  ASM_SIMP_TAC[frontier; CLOSURE_CLOSED] THEN
+  SUBGOAL_THEN
+   `(!x:real^M. x IN interior s ==> f x IN interior t) /\
+    (!y:real^N. y IN interior t ==> g y IN interior s)`
+  MP_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  REWRITE_TAC[SET_RULE `(!x. x IN s ==> f x IN t) <=> IMAGE f s SUBSET t`] THEN
+  CONJ_TAC THENL
+   [SUBGOAL_THEN `t = IMAGE (f:real^M->real^N) s` SUBST1_TAC THENL
+     [ASM SET_TAC[];
+      MATCH_MP_TAC CONTINUOUS_IMAGE_SUBSET_INTERIOR THEN
+      ASM_MESON_TAC[LE_REFL]];
+    SUBGOAL_THEN `s = IMAGE (g:real^N->real^M) t` SUBST1_TAC THENL
+     [ASM SET_TAC[];
+      MATCH_MP_TAC CONTINUOUS_IMAGE_SUBSET_INTERIOR THEN
+      ASM_MESON_TAC[LE_REFL]]]);;
+
+let HOMEOMORPHIC_FRONTIERS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homeomorphic t /\ closed s /\ closed t /\
+        (interior s = {} <=> interior t = {})
+        ==> (frontier s) homeomorphic (frontier t)`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `interior t:real^N->bool = {}` THENL
+   [ASM_SIMP_TAC[frontier; CLOSURE_CLOSED; DIFF_EMPTY]; STRIP_TAC] THEN
+  MATCH_MP_TAC HOMEOMORPHIC_FRONTIERS_SAME_DIMENSION THEN
+  ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM
+   (STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [HOMEOMORPHIC_MINIMAL]) THEN
+  REWRITE_TAC[GSYM LE_ANTISYM] THEN CONJ_TAC THEN
+  MATCH_MP_TAC INVARIANCE_OF_DIMENSION THENL
+   [MAP_EVERY EXISTS_TAC [`f:real^M->real^N`; `interior s:real^M->bool`];
+    MAP_EVERY EXISTS_TAC [`g:real^N->real^M`; `interior t:real^N->bool`]] THEN
+  ASM_REWRITE_TAC[OPEN_INTERIOR] THEN
+  ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; INTERIOR_SUBSET; SUBSET]);;
+
+let CONTINUOUS_IMAGE_SUBSET_RELATIVE_INTERIOR = prove
+ (`!f:real^M->real^N s t.
+        f continuous_on s /\ IMAGE f s SUBSET t /\ aff_dim t <= aff_dim s /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> IMAGE f (relative_interior s) SUBSET relative_interior(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC RELATIVE_INTERIOR_MAXIMAL THEN
+  SIMP_TAC[IMAGE_SUBSET; RELATIVE_INTERIOR_SUBSET] THEN
+  MATCH_MP_TAC INVARIANCE_OF_DOMAIN_AFFINE_SETS THEN
+  EXISTS_TAC `affine hull s:real^M->bool` THEN
+  ASM_REWRITE_TAC[AFFINE_AFFINE_HULL; AFF_DIM_AFFINE_HULL] THEN
+  REWRITE_TAC[OPEN_IN_RELATIVE_INTERIOR] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[AFF_DIM_SUBSET; INT_LE_TRANS]; ALL_TAC] THEN
+  ASSUME_TAC(ISPEC `s:real^M->bool` RELATIVE_INTERIOR_SUBSET) THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]; ALL_TAC; ASM SET_TAC[]] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `IMAGE (f:real^M->real^N) s` THEN
+  SIMP_TAC[IMAGE_SUBSET; RELATIVE_INTERIOR_SUBSET; HULL_SUBSET]);;
+
+let HOMEOMORPHIC_RELATIVE_INTERIORS_SAME_DIMENSION = prove
+ (`!s:real^M->bool t:real^N->bool.
+        aff_dim s = aff_dim t /\ s homeomorphic t
+        ==> (relative_interior s) homeomorphic (relative_interior t)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HOMEOMORPHIC_MINIMAL]) THEN
+  REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^M->real^N` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^M` THEN
+  STRIP_TAC THEN
+  ASM_SIMP_TAC[REWRITE_RULE[SUBSET] RELATIVE_INTERIOR_SUBSET] THEN
+  REWRITE_TAC[SET_RULE `(!x. x IN s ==> f x IN t) <=> IMAGE f s SUBSET t`] THEN
+  REPEAT CONJ_TAC THENL
+   [SUBGOAL_THEN `t = IMAGE (f:real^M->real^N) s` SUBST1_TAC THENL
+     [ASM SET_TAC[];
+      MATCH_MP_TAC CONTINUOUS_IMAGE_SUBSET_RELATIVE_INTERIOR THEN
+      EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[INT_LE_REFL] THEN
+      ASM SET_TAC[]];
+    SUBGOAL_THEN `s = IMAGE (g:real^N->real^M) t` SUBST1_TAC THENL
+     [ASM SET_TAC[];
+      MATCH_MP_TAC CONTINUOUS_IMAGE_SUBSET_RELATIVE_INTERIOR THEN
+      EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[INT_LE_REFL] THEN
+      ASM SET_TAC[]];
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; RELATIVE_INTERIOR_SUBSET];
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; RELATIVE_INTERIOR_SUBSET]]);;
+
+let HOMEOMORPHIC_RELATIVE_INTERIORS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homeomorphic t /\
+        (relative_interior s = {} <=> relative_interior t = {})
+        ==> (relative_interior s) homeomorphic (relative_interior t)`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `relative_interior t:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[HOMEOMORPHIC_EMPTY] THEN STRIP_TAC THEN
+  MATCH_MP_TAC HOMEOMORPHIC_RELATIVE_INTERIORS_SAME_DIMENSION THEN
+  ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM
+   (STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [HOMEOMORPHIC_MINIMAL]) THEN
+  ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+  REWRITE_TAC[GSYM INT_LE_ANTISYM] THEN CONJ_TAC THEN
+  MATCH_MP_TAC INVARIANCE_OF_DIMENSION_AFFINE_SETS THENL
+   [MAP_EVERY EXISTS_TAC
+     [`f:real^M->real^N`; `relative_interior s:real^M->bool`];
+    MAP_EVERY EXISTS_TAC
+     [`g:real^N->real^M`; `relative_interior t:real^N->bool`]] THEN
+  ASM_REWRITE_TAC[OPEN_IN_RELATIVE_INTERIOR; AFFINE_AFFINE_HULL] THEN
+  (REPEAT CONJ_TAC THENL
+    [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; RELATIVE_INTERIOR_SUBSET];
+     ASM_MESON_TAC[RELATIVE_INTERIOR_SUBSET; HULL_SUBSET; SET_RULE
+      `(!x. x IN s ==> f x IN t) /\ s' SUBSET s /\ t SUBSET t'
+       ==> IMAGE f s' SUBSET t'`];
+     ASM_MESON_TAC[RELATIVE_INTERIOR_SUBSET; SUBSET]]));;
+
+let HOMEOMORPHIC_RELATIVE_BOUNDARIES_SAME_DIMENSION = prove
+ (`!s:real^M->bool t:real^N->bool.
+        aff_dim s = aff_dim t /\ s homeomorphic t
+        ==> (s DIFF relative_interior s) homeomorphic
+            (t DIFF relative_interior t)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HOMEOMORPHIC_MINIMAL]) THEN
+  REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^M->real^N` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^M` THEN
+  STRIP_TAC THEN ASM_SIMP_TAC[IN_DIFF] THEN
+  ONCE_REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[SUBSET_DIFF; CONTINUOUS_ON_SUBSET]] THEN
+  SUBGOAL_THEN
+   `(!x:real^M. x IN relative_interior s ==> f x IN relative_interior t) /\
+    (!y:real^N. y IN relative_interior t ==> g y IN relative_interior s)`
+  MP_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  REWRITE_TAC[SET_RULE `(!x. x IN s ==> f x IN t) <=> IMAGE f s SUBSET t`] THEN
+  CONJ_TAC THENL
+   [SUBGOAL_THEN `t = IMAGE (f:real^M->real^N) s` SUBST1_TAC THENL
+     [ASM SET_TAC[];
+      MATCH_MP_TAC CONTINUOUS_IMAGE_SUBSET_RELATIVE_INTERIOR THEN
+      EXISTS_TAC `t:real^N->bool` THEN ASM_REWRITE_TAC[INT_LE_REFL] THEN
+      ASM SET_TAC[]];
+    SUBGOAL_THEN `s = IMAGE (g:real^N->real^M) t` SUBST1_TAC THENL
+     [ASM SET_TAC[];
+      MATCH_MP_TAC CONTINUOUS_IMAGE_SUBSET_RELATIVE_INTERIOR THEN
+      EXISTS_TAC `s:real^M->bool` THEN ASM_REWRITE_TAC[INT_LE_REFL] THEN
+      ASM SET_TAC[]]]);;
+
+let HOMEOMORPHIC_RELATIVE_BOUNDARIES = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homeomorphic t /\
+        (relative_interior s = {} <=> relative_interior t = {})
+        ==> (s DIFF relative_interior s) homeomorphic
+            (t DIFF relative_interior t)`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `relative_interior t:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[DIFF_EMPTY] THEN STRIP_TAC THEN
+  MATCH_MP_TAC HOMEOMORPHIC_RELATIVE_BOUNDARIES_SAME_DIMENSION THEN
+  ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM
+   (STRIP_ASSUME_TAC o GEN_REWRITE_RULE I [HOMEOMORPHIC_MINIMAL]) THEN
+  ONCE_REWRITE_TAC[GSYM AFF_DIM_AFFINE_HULL] THEN
+  REWRITE_TAC[GSYM INT_LE_ANTISYM] THEN CONJ_TAC THEN
+  MATCH_MP_TAC INVARIANCE_OF_DIMENSION_AFFINE_SETS THENL
+   [MAP_EVERY EXISTS_TAC
+     [`f:real^M->real^N`; `relative_interior s:real^M->bool`];
+    MAP_EVERY EXISTS_TAC
+     [`g:real^N->real^M`; `relative_interior t:real^N->bool`]] THEN
+  ASM_REWRITE_TAC[OPEN_IN_RELATIVE_INTERIOR; AFFINE_AFFINE_HULL] THEN
+  (REPEAT CONJ_TAC THENL
+    [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; RELATIVE_INTERIOR_SUBSET];
+     ASM_MESON_TAC[RELATIVE_INTERIOR_SUBSET; HULL_SUBSET; SET_RULE
+      `(!x. x IN s ==> f x IN t) /\ s' SUBSET s /\ t SUBSET t'
+       ==> IMAGE f s' SUBSET t'`];
+     ASM_MESON_TAC[RELATIVE_INTERIOR_SUBSET; SUBSET]]));;
+
+let UNIFORMLY_CONTINUOUS_HOMEOMORPHISM_UNIV_TRIVIAL = prove
+ (`!f g s:real^N->bool.
+        homeomorphism (s,(:real^N)) (f,g) /\ f uniformly_continuous_on s
+        ==> s = (:real^N)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homeomorphism; IN_UNIV] THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[NOT_IN_EMPTY] THENL [SET_TAC[]; STRIP_TAC] THEN
+  MP_TAC(ISPEC `s:real^N->bool` CLOPEN) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN CONJ_TAC THENL
+   [REWRITE_TAC[GSYM COMPLETE_EQ_CLOSED; complete] THEN
+    X_GEN_TAC `x:num->real^N` THEN STRIP_TAC THEN
+    SUBGOAL_THEN `cauchy ((f:real^N->real^N) o x)` MP_TAC THENL
+     [ASM_MESON_TAC[UNIFORMLY_CONTINUOUS_IMP_CAUCHY_CONTINUOUS]; ALL_TAC] THEN
+    REWRITE_TAC[GSYM CONVERGENT_EQ_CAUCHY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `l:real^N`) THEN
+    EXISTS_TAC `(g:real^N->real^N) l` THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC LIM_TRANSFORM_EVENTUALLY THEN
+    EXISTS_TAC `(g:real^N->real^N) o (f:real^N->real^N) o (x:num->real^N)` THEN
+    REWRITE_TAC[o_DEF] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC ALWAYS_EVENTUALLY THEN ASM SET_TAC[];
+      MATCH_MP_TAC LIM_CONTINUOUS_FUNCTION THEN ASM_SIMP_TAC[GSYM o_DEF] THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; OPEN_UNIV; IN_UNIV]];
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [SYM th]) THEN
+    MATCH_MP_TAC INVARIANCE_OF_DOMAIN THEN
+    ASM_REWRITE_TAC[OPEN_UNIV] THEN ASM SET_TAC[]]);;
+
+let INVARIANCE_OF_DOMAIN_SPHERE_AFFINE_SET_GEN = prove
+ (`!f:real^M->real^N u s t.
+        f continuous_on s /\ IMAGE f s SUBSET t /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+        bounded u /\ convex u /\ affine t /\ aff_dim t < aff_dim u /\
+        open_in (subtopology euclidean (relative_frontier u)) s
+        ==> open_in (subtopology euclidean t) (IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `relative_frontier u:real^M->bool = {}` THEN
+  ASM_SIMP_TAC[OPEN_IN_SUBTOPOLOGY_EMPTY; IMAGE_CLAUSES; OPEN_IN_EMPTY] THEN
+  STRIP_TAC THEN FIRST_ASSUM(ASSUME_TAC o MATCH_MP OPEN_IN_IMP_SUBSET) THEN
+  SUBGOAL_THEN
+   `?b c:real^M. b IN relative_frontier u /\ c IN relative_frontier u /\
+                 ~(b = c)`
+  STRIP_ASSUME_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `~(s = {} \/ ?x. s = {x}) ==> ?a b. a IN s /\ b IN s /\ ~(a = b)`) THEN
+    ASM_MESON_TAC[RELATIVE_FRONTIER_NOT_SING];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`(:real^M)`; `aff_dim(u:real^M->bool) - &1`]
+        CHOOSE_AFFINE_SUBSET) THEN
+  REWRITE_TAC[SUBSET_UNIV; AFFINE_UNIV] THEN ANTS_TAC THENL
+   [MATCH_MP_TAC(INT_ARITH
+     `&0:int <= t /\ t <= n ==> --a <= t - a /\ t - &1 <= n`) THEN
+    REWRITE_TAC[AFF_DIM_LE_UNIV; AFF_DIM_UNIV; AFF_DIM_POS_LE] THEN
+    ASM_MESON_TAC[RELATIVE_FRONTIER_EMPTY; NOT_IN_EMPTY];
+    DISCH_THEN(X_CHOOSE_THEN `af:real^M->bool` STRIP_ASSUME_TAC)] THEN
+  MP_TAC(ISPECL [`u:real^M->bool`; `af:real^M->bool`]
+        HOMEOMORPHIC_PUNCTURED_SPHERE_AFFINE_GEN) THEN
+  ASM_REWRITE_TAC[INT_ARITH `x - a + a:int = x`] THEN
+  DISCH_THEN(fun th ->
+    MP_TAC(SPEC `c:real^M` th) THEN MP_TAC(SPEC `b:real^M` th)) THEN
+  ASM_REWRITE_TAC[homeomorphic; homeomorphism; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`g:real^M->real^M`; `h:real^M->real^M`] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`j:real^M->real^M`; `k:real^M->real^M`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`(f:real^M->real^N) o (k:real^M->real^M)`;
+    `(af:real^M->bool)`;
+    `t:real^N->bool`; `IMAGE (j:real^M->real^M) (s DELETE c)`]
+   INVARIANCE_OF_DOMAIN_AFFINE_SETS) THEN
+  MP_TAC(ISPECL
+   [`(f:real^M->real^N) o (h:real^M->real^M)`;
+    `(af:real^M->bool)`;
+    `t:real^N->bool`; `IMAGE (g:real^M->real^M) (s DELETE b)`]
+   INVARIANCE_OF_DOMAIN_AFFINE_SETS) THEN
+  ASM_REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+  ASM_REWRITE_TAC[IMP_IMP; INT_ARITH `x:int <= y - &1 <=> x < y`] THEN
+  MATCH_MP_TAC(TAUT
+   `(p1 /\ p2) /\ (q1 /\ q2 ==> r) ==> (p1 ==> q1) /\ (p2 ==> q2) ==> r`) THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    ASM SET_TAC[];
+    REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[];
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; IN_DELETE]) THEN
+    ASM_SIMP_TAC[o_THM; IN_DELETE; IMP_CONJ] THEN ASM_MESON_TAC[];
+    MATCH_MP_TAC HOMEOMORPHISM_IMP_OPEN_MAP THEN MAP_EVERY EXISTS_TAC
+     [`h:real^M->real^M`; `relative_frontier u DELETE (b:real^M)`] THEN
+    ASM_SIMP_TAC[homeomorphism; DOT_BASIS; DIMINDEX_GE_1; LE_REFL] THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM; OPEN_IN_OPEN] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_IN_OPEN]) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN SET_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+    ASM SET_TAC[];
+    REWRITE_TAC[IMAGE_o] THEN ASM SET_TAC[];
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; IN_DELETE]) THEN
+    ASM_SIMP_TAC[o_THM; IN_DELETE; IMP_CONJ] THEN ASM_MESON_TAC[];
+    MATCH_MP_TAC HOMEOMORPHISM_IMP_OPEN_MAP THEN MAP_EVERY EXISTS_TAC
+     [`k:real^M->real^M`; `relative_frontier u DELETE (c:real^M)`] THEN
+    ASM_SIMP_TAC[homeomorphism; DOT_BASIS; DIMINDEX_GE_1; LE_REFL] THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM; OPEN_IN_OPEN] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_IN_OPEN]) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN SET_TAC[];
+    DISCH_THEN(MP_TAC o MATCH_MP OPEN_IN_UNION) THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+    MATCH_MP_TAC EQ_TRANS THEN
+    EXISTS_TAC `IMAGE (f:real^M->real^N)
+                      ((s DELETE b) UNION (s DELETE c))` THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[IMAGE_UNION] THEN BINOP_TAC; ASM SET_TAC[]] THEN
+    REWRITE_TAC[IMAGE_o] THEN AP_TERM_TAC THEN ASM SET_TAC[]]);;
+
+let INVARIANCE_OF_DOMAIN_SPHERE_AFFINE_SET = prove
+ (`!f:real^M->real^N a r s t.
+        f continuous_on s /\ IMAGE f s SUBSET t /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+        ~(r = &0) /\ affine t /\ aff_dim t < &(dimindex(:M)) /\
+        open_in (subtopology euclidean (sphere(a,r))) s
+        ==> open_in (subtopology euclidean t) (IMAGE f s)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `sphere(a:real^M,r) = {}` THEN
+  ASM_SIMP_TAC[OPEN_IN_SUBTOPOLOGY_EMPTY; OPEN_IN_EMPTY; IMAGE_CLAUSES] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[SPHERE_EQ_EMPTY; REAL_NOT_LT]) THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `cball(a:real^M,r)`;
+                 `s:real^M->bool`; `t:real^N->bool`]
+        INVARIANCE_OF_DOMAIN_SPHERE_AFFINE_SET_GEN) THEN
+  ASM_REWRITE_TAC[AFF_DIM_CBALL; RELATIVE_FRONTIER_CBALL;
+                  BOUNDED_CBALL; CONVEX_CBALL] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC);;
+
+let NO_EMBEDDING_SPHERE_LOWDIM = prove
+ (`!f:real^M->real^N a r.
+        &0 < r /\
+        f continuous_on sphere(a,r) /\
+        (!x y. x IN sphere(a,r) /\ y IN sphere(a,r) /\ f x = f y ==> x = y)
+        ==> dimindex(:M) <= dimindex(:N)`,
+  REWRITE_TAC[GSYM NOT_LT] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `IMAGE (f:real^M->real^N) (sphere(a:real^M,r))`
+        COMPACT_OPEN) THEN
+  ASM_SIMP_TAC[COMPACT_CONTINUOUS_IMAGE; IMAGE_EQ_EMPTY;
+               COMPACT_SPHERE; SPHERE_EQ_EMPTY;
+               REAL_ARITH `&0 < r ==> ~(r < &0)`] THEN
+  ONCE_REWRITE_TAC[OPEN_IN] THEN
+  ONCE_REWRITE_TAC[GSYM SUBTOPOLOGY_UNIV] THEN
+  MATCH_MP_TAC INVARIANCE_OF_DOMAIN_SPHERE_AFFINE_SET THEN
+  MAP_EVERY EXISTS_TAC [`a:real^M`; `r:real`] THEN
+  ASM_REWRITE_TAC[AFFINE_UNIV; SUBSET_UNIV; AFF_DIM_UNIV;
+                  OPEN_IN_REFL; INT_OF_NUM_LT] THEN
+  ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Dimension-based conditions for various homeomorphisms.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMEOMORPHIC_SUBSPACES_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        subspace s /\ subspace t ==> (s homeomorphic t <=> dim s = dim t)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[HOMEOMORPHIC_SUBSPACES]] THEN
+  REWRITE_TAC[homeomorphic; HOMEOMORPHISM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`f:real^M->real^N`; `g:real^N->real^M`] THEN
+  STRIP_TAC THEN REWRITE_TAC[GSYM LE_ANTISYM] THEN CONJ_TAC THEN
+  MATCH_MP_TAC CONTINUOUS_INJECTIVE_IMAGE_SUBSPACE_DIM_LE THEN
+  ASM_MESON_TAC[]);;
+
+let HOMEOMORPHIC_AFFINE_SETS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        affine s /\ affine t ==> (s homeomorphic t <=> aff_dim s = aff_dim t)`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[AFF_DIM_EMPTY; AFF_DIM_EQ_MINUS1; HOMEOMORPHIC_EMPTY] THEN
+  POP_ASSUM MP_TAC THEN
+  GEN_REWRITE_TAC (funpow 3 RAND_CONV) [EQ_SYM_EQ] THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_SIMP_TAC[AFF_DIM_EMPTY; AFF_DIM_EQ_MINUS1; HOMEOMORPHIC_EMPTY] THEN
+  POP_ASSUM MP_TAC THEN REWRITE_TAC
+   [GSYM MEMBER_NOT_EMPTY; LEFT_IMP_EXISTS_THM; RIGHT_IMP_FORALL_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^N`] THEN
+  GEOM_ORIGIN_TAC `a:real^M` THEN GEOM_ORIGIN_TAC `b:real^N` THEN
+  SIMP_TAC[AFFINE_EQ_SUBSPACE; HOMEOMORPHIC_SUBSPACES_EQ; AFF_DIM_DIM_0;
+           HULL_INC; INT_OF_NUM_EQ] THEN
+  MESON_TAC[]);;
+
+let HOMEOMORPHIC_HYPERPLANES_EQ = prove
+ (`!a:real^M b c:real^N d.
+        ~(a = vec 0) /\ ~(c = vec 0)
+        ==> ({x | a dot x = b} homeomorphic {x | c dot x = d} <=>
+             dimindex(:M) = dimindex(:N))`,
+  SIMP_TAC[HOMEOMORPHIC_AFFINE_SETS_EQ; AFFINE_HYPERPLANE] THEN
+  SIMP_TAC[AFF_DIM_HYPERPLANE; INT_OF_NUM_EQ;
+          INT_ARITH `x - &1:int = y - &1 <=> x = y`]);;
+
+let HOMEOMORPHIC_UNIV_UNIV = prove
+ (`(:real^M) homeomorphic (:real^N) <=> dimindex(:M) = dimindex(:N)`,
+  SIMP_TAC[HOMEOMORPHIC_SUBSPACES_EQ; DIM_UNIV; SUBSPACE_UNIV]);;
+
+let HOMEOMORPHIC_CBALLS_EQ = prove
+ (`!a:real^M b:real^N r s.
+        cball(a,r) homeomorphic cball(b,s) <=>
+        r < &0 /\ s < &0 \/ r = &0 /\ s = &0 \/
+        &0 < r /\ &0 < s /\ dimindex(:M) = dimindex(:N)`,
+  let lemma =
+    let d = `dimindex(:M) = dimindex(:N)`
+    and t = `?a:real^M b:real^N. ~(cball(a,r) homeomorphic cball(b,s))` in
+    DISCH d (DISCH t (GEOM_EQUAL_DIMENSION_RULE (ASSUME d) (ASSUME t))) in
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `r < &0` THENL
+   [ASM_SIMP_TAC[CBALL_EMPTY; HOMEOMORPHIC_EMPTY; CBALL_EQ_EMPTY] THEN
+    EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_CASES_TAC `r = &0` THEN ASM_REWRITE_TAC[REAL_LT_REFL] THENL
+   [ASM_SIMP_TAC[CBALL_TRIVIAL; FINITE_SING; HOMEOMORPHIC_FINITE_STRONG] THEN
+    REWRITE_TAC[FINITE_CBALL] THEN
+    ASM_CASES_TAC `s < &0` THEN
+    ASM_SIMP_TAC[CBALL_EMPTY; CARD_CLAUSES; FINITE_EMPTY;
+                 NOT_IN_EMPTY; ARITH; REAL_LT_IMP_NE] THEN
+    ASM_CASES_TAC `s = &0` THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+    ASM_SIMP_TAC[CBALL_TRIVIAL; CARD_CLAUSES; FINITE_EMPTY; NOT_IN_EMPTY;
+                 REAL_LE_REFL; ARITH];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `&0 < r` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_CASES_TAC `s <= &0` THEN
+  ASM_SIMP_TAC[HOMEOMORPHIC_FINITE_STRONG; FINITE_CBALL] THENL
+   [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  SUBGOAL_THEN `&0 < s` ASSUME_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN EQ_TAC THENL
+   [REWRITE_TAC[homeomorphic; HOMEOMORPHISM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`f:real^M->real^N`; `g:real^N->real^M`] THEN
+    STRIP_TAC THEN REWRITE_TAC[GSYM LE_ANTISYM] THEN CONJ_TAC THEN
+    MATCH_MP_TAC INVARIANCE_OF_DIMENSION THENL
+     [MAP_EVERY EXISTS_TAC [`f:real^M->real^N`; `ball(a:real^M,r)`] THEN
+      MP_TAC(ISPECL [`a:real^M`; `r:real`] BALL_SUBSET_CBALL);
+      MAP_EVERY EXISTS_TAC [`g:real^N->real^M`; `ball(b:real^N,s)`] THEN
+      MP_TAC(ISPECL [`b:real^N`; `s:real`] BALL_SUBSET_CBALL)] THEN
+    ASM_REWRITE_TAC[BALL_EQ_EMPTY; OPEN_BALL; REAL_NOT_LE] THEN
+    ASM_MESON_TAC[SUBSET; CONTINUOUS_ON_SUBSET];
+    DISCH_THEN(MP_TAC o MATCH_MP lemma) THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[NOT_EXISTS_THM] THEN ASM_SIMP_TAC[HOMEOMORPHIC_CBALLS]]);;
+
+let HOMEOMORPHIC_BALLS_EQ = prove
+ (`!a:real^M b:real^N r s.
+        ball(a,r) homeomorphic ball(b,s) <=>
+        r <= &0 /\ s <= &0 \/
+        &0 < r /\ &0 < s /\ dimindex(:M) = dimindex(:N)`,
+  let lemma =
+    let d = `dimindex(:M) = dimindex(:N)`
+    and t = `?a:real^M b:real^N. ~(ball(a,r) homeomorphic ball(b,s))` in
+    DISCH d (DISCH t (GEOM_EQUAL_DIMENSION_RULE (ASSUME d) (ASSUME t))) in
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `r <= &0` THENL
+   [ASM_SIMP_TAC[BALL_EMPTY; HOMEOMORPHIC_EMPTY; BALL_EQ_EMPTY] THEN
+    EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_CASES_TAC `s <= &0` THENL
+   [ASM_SIMP_TAC[BALL_EMPTY; HOMEOMORPHIC_EMPTY; BALL_EQ_EMPTY] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LE]) THEN
+  ASM_REWRITE_TAC[] THEN EQ_TAC THENL
+   [REWRITE_TAC[homeomorphic; HOMEOMORPHISM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`f:real^M->real^N`; `g:real^N->real^M`] THEN
+    STRIP_TAC THEN REWRITE_TAC[GSYM LE_ANTISYM] THEN CONJ_TAC THEN
+    MATCH_MP_TAC INVARIANCE_OF_DIMENSION THENL
+     [MAP_EVERY EXISTS_TAC [`f:real^M->real^N`; `ball(a:real^M,r)`];
+      MAP_EVERY EXISTS_TAC [`g:real^N->real^M`; `ball(b:real^N,s)`]] THEN
+    ASM_REWRITE_TAC[BALL_EQ_EMPTY; OPEN_BALL; REAL_NOT_LE] THEN
+    ASM SET_TAC[];
+    DISCH_THEN(MP_TAC o MATCH_MP lemma) THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[NOT_EXISTS_THM] THEN ASM_SIMP_TAC[HOMEOMORPHIC_BALLS]]);;
+
+let SIMPLY_CONNECTED_SPHERE_EQ = prove
+ (`!a:real^N r.
+        simply_connected(sphere(a,r)) <=> 3 <= dimindex(:N) \/ r <= &0`,
+  let hslemma = prove
+   (`!a:real^M r b:real^N s.
+        dimindex(:M) = dimindex(:N)
+        ==> &0 < r /\ &0 < s  ==> (sphere(a,r) homeomorphic sphere(b,s))`,
+    REPEAT STRIP_TAC THEN FIRST_ASSUM(fun th ->
+      let t = `?a:real^M b:real^N. ~(sphere(a,r) homeomorphic sphere(b,s))` in
+      MP_TAC(DISCH t (GEOM_EQUAL_DIMENSION_RULE th (ASSUME t)))) THEN
+    ASM_SIMP_TAC[HOMEOMORPHIC_SPHERES] THEN MESON_TAC[]) in
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `r < &0` THEN
+  ASM_SIMP_TAC[SPHERE_EMPTY; REAL_LT_IMP_LE; SIMPLY_CONNECTED_EMPTY] THEN
+  ASM_CASES_TAC `r = &0` THEN
+  ASM_SIMP_TAC[SPHERE_SING; REAL_LE_REFL; CONVEX_IMP_SIMPLY_CONNECTED;
+               CONVEX_SING] THEN
+  ASM_REWRITE_TAC[REAL_LE_LT] THEN
+  EQ_TAC THEN REWRITE_TAC[SIMPLY_CONNECTED_SPHERE] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  REWRITE_TAC[ARITH_RULE `~(3 <= n) <=> (1 <= n ==> n = 1 \/ n = 2)`] THEN
+  REWRITE_TAC[DIMINDEX_GE_1] THEN STRIP_TAC THENL
+   [DISCH_THEN(MP_TAC o MATCH_MP SIMPLY_CONNECTED_IMP_CONNECTED) THEN
+    ASM_REWRITE_TAC[CONNECTED_SPHERE_EQ; ARITH] THEN ASM_REAL_ARITH_TAC;
+    RULE_ASSUM_TAC(REWRITE_RULE[GSYM DIMINDEX_2]) THEN
+    FIRST_ASSUM(MP_TAC o ISPECL [`a:real^N`; `r:real`; `vec 0:real^2`;
+          `&1:real`] o MATCH_MP hslemma) THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    DISCH_THEN(SUBST1_TAC o MATCH_MP HOMEOMORPHIC_SIMPLY_CONNECTED_EQ) THEN
+    REWRITE_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_CIRCLEMAP] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `\x:real^2. x`) THEN
+    REWRITE_TAC[CONTINUOUS_ON_ID; IMAGE_ID; SUBSET_REFL] THEN
+    REWRITE_TAC[GSYM contractible; CONTRACTIBLE_SPHERE] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV]);;
+
+let NOT_SIMPLY_CONNECTED_CIRCLE = prove
+ (`!a:real^2 r. &0 < r ==> ~simply_connected(sphere(a,r))`,
+  REWRITE_TAC[SIMPLY_CONNECTED_SPHERE_EQ; DIMINDEX_2; ARITH] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* The power, squaring and exponential functions as covering maps.           *)
+(* ------------------------------------------------------------------------- *)
+
+let COVERING_SPACE_POW_PUNCTURED_PLANE = prove
+ (`!n. 0 < n
+       ==> covering_space ((:complex) DIFF {Cx(&0)},(\z. z pow n))
+                          ((:complex) DIFF {Cx (&0)})`,
+  let lemma = prove
+   (`!n. 0 < n
+         ==> ?e. &0 < e /\
+                 !w z. norm(w - z) < e * norm(z)
+                       ==> (w pow n = z pow n <=> w = z)`,
+    REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (ARITH_RULE
+     `0 < n ==> n = 1 \/ 2 <= n`)) THEN
+    ASM_SIMP_TAC[COMPLEX_POW_1] THENL [MESON_TAC[REAL_LT_01]; ALL_TAC] THEN
+    EXISTS_TAC `&2 * sin(pi / &n)` THEN CONJ_TAC THENL
+     [REWRITE_TAC[REAL_ARITH `&0 < &2 * x <=> &0 < x`] THEN
+      MATCH_MP_TAC SIN_POS_PI THEN
+      ASM_SIMP_TAC[REAL_LT_DIV; PI_POS; REAL_OF_NUM_LT] THEN
+      REWRITE_TAC[REAL_ARITH `x / y < x <=> &0 < x * (&1 - inv y)`] THEN
+      MATCH_MP_TAC REAL_LT_MUL THEN REWRITE_TAC[PI_POS; REAL_SUB_LT] THEN
+      MATCH_MP_TAC REAL_INV_LT_1 THEN REWRITE_TAC[REAL_OF_NUM_LT] THEN
+      ASM_ARITH_TAC;
+      ALL_TAC] THEN
+    REPEAT GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THENL
+     [ASM_REWRITE_TAC[COMPLEX_NORM_0; COMPLEX_SUB_RZERO] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[] THEN
+      SIMP_TAC[NORM_ARITH `norm(w) < x * &0 <=> F`];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_LDIV_EQ; COMPLEX_NORM_NZ] THEN
+    ASM_SIMP_TAC[COMPLEX_POW_EQ_0; COMPLEX_FIELD
+     `~(z = Cx(&0)) ==> (w = z <=> w / z = Cx(&1))`] THEN
+    REWRITE_TAC[GSYM COMPLEX_NORM_DIV; GSYM COMPLEX_POW_DIV] THEN
+    ASM_SIMP_TAC[COMPLEX_FIELD
+     `~(z = Cx(&0)) ==> (w - z) / z = w / z - Cx(&1)`] THEN
+    ASM_CASES_TAC `w / z = Cx(&0)` THENL
+     [ASM_REWRITE_TAC[COMPLEX_SUB_LZERO; NORM_NEG; COMPLEX_NORM_CX] THEN
+      ASM_SIMP_TAC[COMPLEX_POW_ZERO; LE_1];
+      UNDISCH_TAC `~(w / z = Cx(&0))` THEN
+      UNDISCH_THEN `~(z = Cx(&0))` (K ALL_TAC) THEN
+      REPEAT(POP_ASSUM MP_TAC) THEN
+      SPEC_TAC(`w / z:complex`,`z:complex`) THEN REPEAT STRIP_TAC] THEN
+    EQ_TAC THEN SIMP_TAC[COMPLEX_POW_ONE] THEN DISCH_TAC THEN
+    UNDISCH_TAC `norm(z - Cx(&1)) < &2 * sin (pi / &n)` THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[REAL_NOT_LT] THEN
+    DISCH_TAC THEN MP_TAC(SPEC `n:num` COMPLEX_ROOTS_UNITY) THEN
+    ASM_SIMP_TAC[LE_1; EXTENSION; IN_ELIM_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `j:num` MP_TAC) THEN
+    REWRITE_TAC[COMPLEX_RING `t * p * ii * q = ii * (t * p * q)`] THEN
+    REWRITE_TAC[GSYM CX_MUL] THEN ASM_CASES_TAC `j = 0` THENL
+     [ASM_REWRITE_TAC[real_div; REAL_MUL_LZERO; REAL_MUL_RZERO; CEXP_0;
+                      COMPLEX_MUL_RZERO];
+      STRIP_TAC THEN ASM_REWRITE_TAC[DIST_CEXP_II_1]] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= y ==> &2 * x <= &2 * abs y`) THEN
+    REWRITE_TAC[REAL_ARITH `(&2 * x) / &2 = x`] THEN
+    ASM_CASES_TAC `&j / &n <= &1 / &2` THENL
+     [ALL_TAC;
+      SUBGOAL_THEN `sin(pi * &j / &n) = sin(pi * &(n - j) / &n)`
+      SUBST1_TAC THENL
+       [ASM_SIMP_TAC[GSYM REAL_OF_NUM_SUB; LT_IMP_LE; REAL_OF_NUM_LT;
+           REAL_FIELD `&0 < n ==> pi * (n - j) / n = pi - pi * j / n`] THEN
+        REWRITE_TAC[SIN_SUB; COS_PI; SIN_PI] THEN REAL_ARITH_TAC;
+        ALL_TAC]] THEN
+    MATCH_MP_TAC SIN_MONO_LE THEN
+    REWRITE_TAC[REAL_ARITH `--(pi / &2) = pi * --(&1 / &2)`; real_div] THEN
+    SIMP_TAC[REAL_LE_LMUL_EQ; PI_POS] THEN
+    ASM_SIMP_TAC[GSYM real_div; REAL_LE_RDIV_EQ; REAL_MUL_LINV; REAL_LT_IMP_NZ;
+                 REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; REAL_OF_NUM_LT; LE_1;
+                 ARITH_RULE `j < n ==> 1 <= n - j`; REAL_OF_NUM_LE;
+                 REAL_ARITH `&0 <= x ==> --(&1 / &2) <= x`;
+                 REAL_POS; REAL_LE_INV_EQ] THEN
+    ASM_SIMP_TAC[GSYM REAL_OF_NUM_SUB; LT_IMP_LE] THEN
+    REWRITE_TAC[REAL_ARITH `n - j <= inv(&2) * n <=> inv(&2) * n <= j`] THEN
+    ASM_SIMP_TAC[GSYM REAL_LE_LDIV_EQ; GSYM REAL_LE_RDIV_EQ;
+                 REAL_OF_NUM_LT] THEN
+    ASM_REAL_ARITH_TAC) in
+  REPEAT STRIP_TAC THEN
+  SIMP_TAC[covering_space; CONTINUOUS_ON_COMPLEX_POW; CONTINUOUS_ON_ID] THEN
+  SIMP_TAC[OPEN_IN_OPEN_EQ; OPEN_DIFF; OPEN_UNIV; CLOSED_SING] THEN
+  MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_IMAGE; IN_DIFF; IN_UNIV; IN_SING] THEN
+    ASM_MESON_TAC[COMPLEX_POW_EQ_0; EXISTS_COMPLEX_ROOT; LE_1];
+    DISCH_THEN(fun th -> GEN_REWRITE_TAC
+        (BINDER_CONV o LAND_CONV o RAND_CONV) [GSYM th])] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; IN_UNIV; IN_DIFF; IN_SING] THEN
+  SIMP_TAC[SUBSET_UNIV; SET_RULE `s SUBSET UNIV DIFF {a} <=> ~(a IN s)`] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  MP_TAC(SPEC `n:num` lemma) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  ABBREV_TAC `d = (min (&1 / &2) (e / &4)) * norm(z:complex)` THEN
+  SUBGOAL_THEN `&0 < d` ASSUME_TAC THENL
+   [EXPAND_TAC "d" THEN MATCH_MP_TAC REAL_LT_MUL THEN
+    ASM_REWRITE_TAC[COMPLEX_NORM_NZ] THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!w x y. w pow n = z pow n /\ x IN ball(w,d) /\ y IN ball(w,d)
+            ==> (x pow n = y pow n <=> x = y)`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[IN_BALL] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `norm(z pow n) = norm(w pow n)` MP_TAC THENL
+     [ASM_MESON_TAC[]; REWRITE_TAC[COMPLEX_NORM_POW]] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+     (REWRITE_RULE[CONJ_ASSOC] REAL_POW_EQ))) THEN
+    ASM_SIMP_TAC[LE_1; NORM_POS_LE] THEN
+    ASM_CASES_TAC `w = Cx(&0)` THENL
+     [ASM_MESON_TAC[COMPLEX_NORM_ZERO]; DISCH_THEN SUBST_ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `&2 * d` THEN CONJ_TAC THENL
+     [MAP_EVERY UNDISCH_TAC
+       [`dist(w:complex,x) < d`; `dist(w:complex,y) < d`] THEN
+      CONV_TAC NORM_ARITH;
+      ALL_TAC] THEN
+    EXPAND_TAC "d" THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `&2 * e / &4 * norm(w:complex)` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[REAL_POS] THEN
+      MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_ARITH
+     `&2 * e / &4 * x <= e * y <=> e * x <= e * &2 * y`] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (NORM_ARITH
+     `dist(z,y) < d ==> d <= &1 / &2 * norm(z)
+                        ==> norm(z) <= &2 * norm y`)) THEN
+    EXPAND_TAC "d" THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+    REWRITE_TAC[NORM_POS_LE] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  EXISTS_TAC `IMAGE (\w. w pow n) (ball(z,d))` THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[IN_IMAGE] THEN ASM_MESON_TAC[CENTRE_IN_BALL];
+    MATCH_MP_TAC INVARIANCE_OF_DOMAIN THEN
+    SIMP_TAC[OPEN_BALL; CONTINUOUS_ON_COMPLEX_POW; CONTINUOUS_ON_ID] THEN
+    ASM_MESON_TAC[];
+    REWRITE_TAC[SET_RULE
+     `~(z IN IMAGE f s) <=> (!x. x IN s ==> ~(f x = z))`] THEN
+    X_GEN_TAC `w:complex` THEN
+    ASM_SIMP_TAC[IN_BALL; COMPLEX_POW_EQ_0; LE_1] THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    SIMP_TAC[GSYM COMPLEX_VEC_0; DIST_0] THEN DISCH_TAC THEN
+    EXPAND_TAC "d" THEN
+    REWRITE_TAC[REAL_ARITH `~(z < e * z) <=> &0 <= z * (&1 - e)`] THEN
+    MATCH_MP_TAC REAL_LE_MUL THEN CONV_TAC NORM_ARITH;
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!z'. z' pow n = z pow n
+         ==> IMAGE (\w. w pow n) (ball(z',d)) =
+             IMAGE (\w. w pow n) (ball(z,d))`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_IMAGE; IN_BALL] THEN
+    X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `w = Cx(&0)` THENL
+     [ASM_MESON_TAC[COMPLEX_POW_EQ_0; LE_1]; ALL_TAC] THEN
+    X_GEN_TAC `x:complex` THEN  EQ_TAC THEN
+    DISCH_THEN(X_CHOOSE_THEN `y:complex` STRIP_ASSUME_TAC) THENL
+     [EXISTS_TAC `z / w * y:complex`;
+      EXISTS_TAC `w / z * y:complex`] THEN
+    ASM_SIMP_TAC[COMPLEX_POW_MUL; COMPLEX_POW_DIV; COMPLEX_DIV_REFL;
+                 COMPLEX_POW_EQ_0; LE_1; COMPLEX_MUL_LID; dist] THEN
+    ASM_SIMP_TAC[COMPLEX_FIELD
+     `~(w = Cx(&0)) ==> z - z / w * y = z / w * (w - y)`] THEN
+    REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_DIV] THEN
+    (SUBGOAL_THEN `norm(z pow n) = norm(w pow n)` MP_TAC THENL
+     [ASM_MESON_TAC[]; REWRITE_TAC[COMPLEX_NORM_POW]]) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+     (REWRITE_RULE[CONJ_ASSOC] REAL_POW_EQ))) THEN
+    ASM_SIMP_TAC[LE_1; NORM_POS_LE; REAL_DIV_REFL; COMPLEX_NORM_ZERO] THEN
+    ASM_REWRITE_TAC[REAL_MUL_LID; GSYM dist];
+    ALL_TAC] THEN
+  EXISTS_TAC `{ ball(z',d) | z' pow n = z pow n}` THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[UNIONS_GSPEC; EXTENSION; IN_ELIM_THM] THEN
+    X_GEN_TAC `x:complex` THEN EQ_TAC THENL
+     [DISCH_THEN(X_CHOOSE_THEN `w:complex` STRIP_ASSUME_TAC) THEN
+      CONJ_TAC THENL
+       [DISCH_TAC THEN UNDISCH_TAC `x IN ball(w:complex,d)` THEN
+        ASM_REWRITE_TAC[IN_BALL; GSYM COMPLEX_VEC_0; DIST_0] THEN
+        SUBGOAL_THEN `norm(w pow n) = norm(z pow n)` MP_TAC THENL
+         [ASM_MESON_TAC[]; REWRITE_TAC[COMPLEX_NORM_POW]] THEN
+        DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+         (REWRITE_RULE[CONJ_ASSOC] REAL_POW_EQ))) THEN
+        ASM_SIMP_TAC[LE_1; NORM_POS_LE; REAL_NOT_LT] THEN DISCH_TAC THEN
+        EXPAND_TAC "d" THEN REWRITE_TAC[REAL_ARITH
+         `e * z <= z <=> &0 <= z * (&1 - e)`] THEN
+        MATCH_MP_TAC REAL_LE_MUL THEN CONV_TAC NORM_ARITH;
+        SUBGOAL_THEN `IMAGE (\w. w pow n) (ball(z,d)) =
+                  IMAGE (\w. w pow n) (ball(w,d))`
+        SUBST1_TAC THENL [ASM_MESON_TAC[]; ASM SET_TAC[]]];
+      STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_IMAGE]) THEN
+      REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `y:complex` THEN
+      REWRITE_TAC[IN_BALL] THEN STRIP_TAC THEN
+      ASM_CASES_TAC `y = Cx(&0)` THENL
+       [ASM_MESON_TAC[COMPLEX_POW_EQ_0; LE_1]; ALL_TAC] THEN
+      EXISTS_TAC `x / y * z:complex` THEN
+      REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_DIV] THEN
+      ASM_SIMP_TAC[COMPLEX_POW_MUL; COMPLEX_POW_DIV; COMPLEX_DIV_REFL;
+                   COMPLEX_POW_EQ_0; LE_1; COMPLEX_MUL_LID; dist] THEN
+      ASM_SIMP_TAC[COMPLEX_FIELD
+       `~(y = Cx(&0)) ==> x / y * z - x = x / y * (z - y)`] THEN
+      REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_DIV] THEN
+      SUBGOAL_THEN `norm(y pow n) = norm(x pow n)` MP_TAC THENL
+       [ASM_MESON_TAC[]; REWRITE_TAC[COMPLEX_NORM_POW]] THEN
+      REWRITE_TAC[COMPLEX_POW_MUL; COMPLEX_POW_DIV] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+       (REWRITE_RULE[CONJ_ASSOC] REAL_POW_EQ))) THEN
+      ASM_SIMP_TAC[LE_1; NORM_POS_LE; REAL_DIV_REFL; COMPLEX_NORM_ZERO] THEN
+      ASM_REWRITE_TAC[REAL_MUL_LID; GSYM dist]];
+    X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+    REWRITE_TAC[OPEN_BALL; IN_BALL; REAL_NOT_LT; dist; COMPLEX_SUB_RZERO] THEN
+    SUBGOAL_THEN `norm(w pow n) = norm(z pow n)` MP_TAC THENL
+     [ASM_MESON_TAC[]; REWRITE_TAC[COMPLEX_NORM_POW]] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+     (REWRITE_RULE[CONJ_ASSOC] REAL_POW_EQ))) THEN
+    ASM_SIMP_TAC[LE_1; NORM_POS_LE] THEN DISCH_THEN SUBST1_TAC THEN
+    EXPAND_TAC "d" THEN
+    REWRITE_TAC[REAL_ARITH `e * z <= z <=> &0 <= z * (&1 - e)`] THEN
+    MATCH_MP_TAC REAL_LE_MUL THEN CONV_TAC NORM_ARITH;
+    REWRITE_TAC[pairwise; IMP_CONJ; FORALL_IN_GSPEC; RIGHT_FORALL_IMP_THM] THEN
+    X_GEN_TAC `u:complex` THEN DISCH_TAC THEN
+    X_GEN_TAC `v:complex` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `v:complex = u` THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(K ALL_TAC) THEN
+    REWRITE_TAC[SET_RULE `DISJOINT s t <=> !x. x IN s /\ x IN t ==> F`] THEN
+    X_GEN_TAC `x:complex` THEN REWRITE_TAC[IN_BALL] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (NORM_ARITH
+     `dist(u,x) < d /\ dist(v,x) < d ==> dist(u,v) < &2 * d`)) THEN
+    REWRITE_TAC[REAL_NOT_LT] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `e * norm(z:complex)` THEN CONJ_TAC THENL
+     [EXPAND_TAC "d" THEN REWRITE_TAC[REAL_MUL_ASSOC] THEN
+      MATCH_MP_TAC REAL_LE_RMUL THEN
+      REWRITE_TAC[NORM_POS_LE] THEN ASM_REAL_ARITH_TAC;
+      ONCE_REWRITE_TAC[GSYM REAL_NOT_LT] THEN REWRITE_TAC[dist]] THEN
+    SUBGOAL_THEN `norm(z pow n) = norm(v pow n)` MP_TAC THENL
+     [ASM_MESON_TAC[]; REWRITE_TAC[COMPLEX_NORM_POW]] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+     (REWRITE_RULE[CONJ_ASSOC] REAL_POW_EQ))) THEN
+    ASM_SIMP_TAC[LE_1; NORM_POS_LE] THEN ASM_MESON_TAC[];
+    X_GEN_TAC `w:complex` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `IMAGE (\w. w pow n) (ball(z,d)) =
+                  IMAGE (\w. w pow n) (ball(w,d))`
+    SUBST1_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC INVARIANCE_OF_DOMAIN_HOMEOMORPHISM THEN
+    SIMP_TAC[LE_REFL; OPEN_BALL; CONTINUOUS_ON_COMPLEX_POW;
+             CONTINUOUS_ON_ID] THEN
+    ASM_MESON_TAC[]]);;
+
+let COVERING_SPACE_SQUARE_PUNCTURED_PLANE = prove
+ (`covering_space ((:complex) DIFF {Cx(&0)},(\z. z pow 2))
+                  ((:complex) DIFF {Cx (&0)})`,
+  SIMP_TAC[COVERING_SPACE_POW_PUNCTURED_PLANE; ARITH]);;
+
+let COVERING_SPACE_CEXP_PUNCTURED_PLANE = prove
+ (`covering_space((:complex),cexp) ((:complex) DIFF {Cx(&0)})`,
+  SIMP_TAC[covering_space; IN_UNIV; CONTINUOUS_ON_CEXP; IN_DIFF; IN_SING] THEN
+  CONJ_TAC THENL [SET_TAC[CEXP_CLOG; CEXP_NZ]; ALL_TAC] THEN
+  SIMP_TAC[OPEN_IN_OPEN_EQ; OPEN_DIFF; OPEN_UNIV; CLOSED_SING] THEN
+  SIMP_TAC[SUBSET_UNIV; SET_RULE `s SUBSET UNIV DIFF {a} <=> ~(a IN s)`] THEN
+  X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+  EXISTS_TAC `IMAGE cexp (ball(clog z,&1))` THEN
+  REWRITE_TAC[SET_RULE `~(z IN IMAGE f s) <=> !x. x IN s ==> ~(f x = z)`] THEN
+  REWRITE_TAC[CEXP_NZ] THEN CONJ_TAC THENL
+   [REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `clog z` THEN
+    ASM_SIMP_TAC[CEXP_CLOG; CENTRE_IN_BALL; REAL_LT_01];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!x y. x IN cball(clog z,&1) /\ y IN cball(clog z,&1) /\ cexp x = cexp y
+          ==> x = y`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[IN_CBALL] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC COMPLEX_EQ_CEXP THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `norm(x - y:complex)` THEN
+    REWRITE_TAC[GSYM IM_SUB; COMPLEX_NORM_GE_RE_IM] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `&2` THEN CONJ_TAC THENL
+     [REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC NORM_ARITH;
+      MP_TAC PI_APPROX_32 THEN REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC INVARIANCE_OF_DOMAIN THEN
+    REWRITE_TAC[OPEN_BALL; CONTINUOUS_ON_CEXP] THEN
+    ASM_MESON_TAC[SUBSET; BALL_SUBSET_CBALL];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`cball(clog z,&1)`; `cexp`;
+                 `IMAGE cexp (cball(clog z,&1))`] HOMEOMORPHISM_COMPACT) THEN
+  ASM_REWRITE_TAC[COMPACT_CBALL; CONTINUOUS_ON_CEXP] THEN
+  REWRITE_TAC[homeomorphism; LEFT_IMP_EXISTS_THM; FORALL_IN_IMAGE] THEN
+  X_GEN_TAC `l:complex->complex` THEN STRIP_TAC THEN
+  EXISTS_TAC `{ IMAGE (\x. x + Cx (&2 * n * pi) * ii)
+                      (ball(clog z,&1))
+                | integer n}` THEN
+  SIMP_TAC[FORALL_IN_GSPEC; OPEN_BALL;
+           ONCE_REWRITE_RULE[VECTOR_ADD_SYM] OPEN_TRANSLATION] THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[UNIONS_GSPEC; IN_IMAGE; CEXP_EQ] THEN SET_TAC[];
+    REWRITE_TAC[pairwise; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[FORALL_IN_GSPEC] THEN
+    X_GEN_TAC `m:real` THEN DISCH_TAC THEN
+    X_GEN_TAC `n:real` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `m:real = n` THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+    REWRITE_TAC[IN_BALL; dist; SET_RULE
+     `DISJOINT (IMAGE f s) (IMAGE g s) <=>
+      !x y. x IN s /\ y IN s ==> ~(f x = g y)`] THEN
+    REPEAT GEN_TAC THEN MATCH_MP_TAC(NORM_ARITH
+     `&2 <= norm(m - n)
+      ==> norm(c - x) < &1 /\ norm(c - y) < &1 ==> ~(x + m = y + n)`) THEN
+    REWRITE_TAC[GSYM COMPLEX_SUB_RDISTRIB; COMPLEX_NORM_MUL] THEN
+    REWRITE_TAC[COMPLEX_NORM_II; GSYM CX_SUB; COMPLEX_NORM_CX] THEN
+    REWRITE_TAC[GSYM REAL_SUB_LDISTRIB; GSYM REAL_SUB_RDISTRIB] THEN
+    REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_NUM; REAL_ABS_PI; REAL_MUL_RID] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `&2 * &1 * pi` THEN
+    CONJ_TAC THENL [MP_TAC PI_APPROX_32 THEN REAL_ARITH_TAC; ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN
+    SIMP_TAC[REAL_LE_RMUL_EQ; PI_POS; REAL_POS] THEN
+    MATCH_MP_TAC REAL_ABS_INTEGER_LEMMA THEN
+    ASM_SIMP_TAC[REAL_SUB_0; INTEGER_CLOSED];
+    X_GEN_TAC `n:real` THEN DISCH_TAC THEN
+    EXISTS_TAC `(\x. x + Cx(&2 * n * pi) * ii) o (l:complex->complex)` THEN
+    ASM_REWRITE_TAC[CONTINUOUS_ON_CEXP; o_THM; IMAGE_o; FORALL_IN_IMAGE] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[INJECTIVE_ON_ALT]) THEN
+    ASM_SIMP_TAC[CEXP_ADD; CEXP_INTEGER_2PI; COMPLEX_MUL_RID;
+                 REWRITE_RULE[SUBSET] BALL_SUBSET_CBALL] THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC(SET_RULE
+       `(!x. e(f x) = e x) ==> IMAGE e (IMAGE f s) = IMAGE e s`) THEN
+      ASM_SIMP_TAC[CEXP_ADD; CEXP_INTEGER_2PI; COMPLEX_MUL_RID];
+      MATCH_MP_TAC(SET_RULE
+       `(!x. x IN s ==> l(e x) = x)
+        ==> IMAGE t (IMAGE l (IMAGE e s)) = IMAGE t s`) THEN
+      ASM_SIMP_TAC[REWRITE_RULE[SUBSET] BALL_SUBSET_CBALL];
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_ID;
+               CONTINUOUS_ON_CONST] THEN
+      ASM_MESON_TAC[BALL_SUBSET_CBALL; IMAGE_SUBSET;
+                    CONTINUOUS_ON_SUBSET]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence the Borsukian results about mappings into circle.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let INESSENTIAL_EQ_CONTINUOUS_LOGARITHM = prove
+ (`!f:real^N->complex s.
+      (?a. homotopic_with (\h. T) (s,(:complex) DIFF {Cx(&0)}) f (\t. a)) <=>
+      (?g. g continuous_on s /\ (!x. x IN s ==> f x = cexp(g x)))`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [DISCH_THEN(CHOOSE_THEN
+     (MP_TAC o CONJ COVERING_SPACE_CEXP_PUNCTURED_PLANE)) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP COVERING_SPACE_LIFT_INESSENTIAL_FUNCTION) THEN
+    REWRITE_TAC[SUBSET_UNIV] THEN MESON_TAC[];
+    DISCH_THEN(X_CHOOSE_THEN `g:real^N->complex` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `?a. homotopic_with (\h. T) (s,(:complex) DIFF {Cx(&0)})
+              (cexp o g) (\x:real^N. a)`
+    MP_TAC THENL
+     [MATCH_MP_TAC NULLHOMOTOPIC_THROUGH_CONTRACTIBLE THEN
+      EXISTS_TAC `(:complex)` THEN ASM_REWRITE_TAC[SUBSET_UNIV] THEN
+      ASM_SIMP_TAC[STARLIKE_IMP_CONTRACTIBLE; STARLIKE_UNIV] THEN
+      REWRITE_TAC[CONTINUOUS_ON_CEXP; SUBSET; FORALL_IN_IMAGE] THEN
+      REWRITE_TAC[IN_UNIV; IN_DIFF; IN_SING; CEXP_NZ];
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:complex` THEN
+      MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_EQ) THEN
+      ASM_SIMP_TAC[o_THM]]]);;
+
+let INESSENTIAL_IMP_CONTINUOUS_LOGARITHM_CIRCLE = prove
+ (`!f:real^N->complex s.
+        (?a. homotopic_with (\h. T) (s,sphere(vec 0,&1)) f (\t. a))
+        ==> ?g. g continuous_on s /\ !x. x IN s ==> f x = cexp(g x)`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[sphere; GSYM INESSENTIAL_EQ_CONTINUOUS_LOGARITHM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:complex` THEN
+  REWRITE_TAC[homotopic_with] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+    (REWRITE_RULE[IMP_CONJ] SUBSET_TRANS)) THEN
+  SIMP_TAC[SUBSET; DIST_0; FORALL_IN_GSPEC; IN_UNIV; IN_DIFF; IN_SING] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  SIMP_TAC[COMPLEX_NORM_CX] THEN REAL_ARITH_TAC);;
+
+let INESSENTIAL_EQ_CONTINUOUS_LOGARITHM_CIRCLE = prove
+ (`!f:real^N->complex s.
+        (?a. homotopic_with (\h. T) (s,sphere(vec 0,&1)) f (\t. a)) <=>
+        (?g. (Cx o g) continuous_on s /\
+             !x. x IN s ==> f x = cexp(ii * Cx(g x)))`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [DISCH_TAC THEN FIRST_ASSUM(MP_TAC o
+      MATCH_MP INESSENTIAL_IMP_CONTINUOUS_LOGARITHM_CIRCLE) THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real^N->complex` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `Im o (g:real^N->complex)` THEN CONJ_TAC THENL
+     [REWRITE_TAC[o_ASSOC] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      ASM_REWRITE_TAC[CONTINUOUS_ON_CX_IM];
+      FIRST_X_ASSUM(CHOOSE_THEN (MP_TAC o CONJUNCT1 o
+        MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET)) THEN
+      ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_SPHERE_0; NORM_CEXP] THEN
+      REWRITE_TAC[EULER; o_THM; RE_MUL_II; IM_MUL_II] THEN
+      SIMP_TAC[RE_CX; IM_CX; REAL_NEG_0; REAL_EXP_0]];
+    DISCH_THEN(X_CHOOSE_THEN `g:real^N->real` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `?a. homotopic_with (\h. T) (s,sphere(vec 0,&1))
+              ((cexp o (\z. ii * z)) o (Cx o g)) (\x:real^N. a)`
+    MP_TAC THENL
+     [MATCH_MP_TAC NULLHOMOTOPIC_THROUGH_CONTRACTIBLE THEN
+      EXISTS_TAC `{z | Im z = &0}` THEN ASM_REWRITE_TAC[] THEN
+      ASM_SIMP_TAC[CONTINUOUS_ON_COMPOSE; CONTINUOUS_ON_CEXP; CONJ_ASSOC;
+                   CONTINUOUS_ON_COMPLEX_LMUL; CONTINUOUS_ON_ID] THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM; IN_SPHERE_0;
+                    o_THM; IM_CX] THEN
+        SIMP_TAC[NORM_CEXP; RE_MUL_II; REAL_EXP_0; REAL_NEG_0];
+        MATCH_MP_TAC STARLIKE_IMP_CONTRACTIBLE THEN
+        MATCH_MP_TAC CONVEX_IMP_STARLIKE THEN CONJ_TAC THENL
+         [REWRITE_TAC[IM_DEF; CONVEX_STANDARD_HYPERPLANE];
+          REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+          MESON_TAC[IM_CX]]];
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:complex` THEN
+      MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_EQ) THEN
+      ASM_SIMP_TAC[o_THM]]]);;
+
+let HOMOTOPIC_CIRCLEMAPS_DIV,HOMOTOPIC_CIRCLEMAPS_DIV_1 = (CONJ_PAIR o prove)
+ (`(!f g:real^N->real^2 s.
+    homotopic_with (\x. T) (s,sphere(vec 0,&1)) f g <=>
+    f continuous_on s /\ IMAGE f s SUBSET sphere(vec 0,&1) /\
+    g continuous_on s /\ IMAGE g s SUBSET sphere(vec 0,&1) /\
+    ?c. homotopic_with (\x. T) (s,sphere(vec 0,&1)) (\x. f x / g x) (\x. c)) /\
+   (!f g:real^N->real^2 s.
+    homotopic_with (\x. T) (s,sphere(vec 0,&1)) f g <=>
+    f continuous_on s /\ IMAGE f s SUBSET sphere(vec 0,&1) /\
+    g continuous_on s /\ IMAGE g s SUBSET sphere(vec 0,&1) /\
+    homotopic_with (\x. T) (s,sphere(vec 0,&1)) (\x. f x / g x) (\x. Cx(&1)))`,
+  let lemma = prove
+   (`!f g h:real^N->real^2 s.
+          homotopic_with (\x. T) (s,sphere(vec 0,&1)) f g
+          ==> h continuous_on s /\ (!x. x IN s ==> h(x) IN sphere(vec 0,&1))
+               ==> homotopic_with (\x. T) (s,sphere(vec 0,&1))
+                                          (\x. f x * h x) (\x. g x * h x)`,
+    REWRITE_TAC[IN_SPHERE_0] THEN REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homotopic_with]) THEN
+    ASM_SIMP_TAC[HOMOTOPIC_WITH; LEFT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_SPHERE_0; FORALL_IN_PCROSS] THEN
+    X_GEN_TAC `k:real^((1,N)finite_sum)->real^2` THEN STRIP_TAC THEN
+    EXISTS_TAC `\z. (k:real^(1,N)finite_sum->real^2) z * h(sndcart z)` THEN
+    ASM_SIMP_TAC[COMPLEX_NORM_MUL; SNDCART_PASTECART; REAL_MUL_LID] THEN
+    ASM_REWRITE_TAC[SNDCART_PASTECART] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN
+    ASM_REWRITE_TAC[GSYM o_DEF] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART; IMAGE_SNDCART_PCROSS] THEN
+    ASM_REWRITE_TAC[UNIT_INTERVAL_NONEMPTY]) in
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN MATCH_MP_TAC
+   (TAUT `(q <=> r) /\ (p <=> r) ==> (p <=> q) /\ (p <=> r)`) THEN
+  CONJ_TAC THENL
+   [REPEAT(MATCH_MP_TAC(TAUT `(p ==> (q <=> r)) ==> (p /\ q <=> p /\ r)`) THEN
+           DISCH_TAC) THEN
+    EQ_TAC THENL
+     [ALL_TAC; DISCH_TAC THEN EXISTS_TAC `Cx(&1)` THEN ASM_MESON_TAC[]] THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `c:complex` THEN
+    DISCH_THEN(fun th -> ASSUME_TAC(MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET th) THEN
+        MP_TAC th) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_TRANS) THEN
+    REWRITE_TAC[HOMOTOPIC_CONSTANT_MAPS] THEN
+    ASM_CASES_TAC `s:real^N->bool = {}` THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPECL [`vec 0:real^2`; `&1`] PATH_CONNECTED_SPHERE) THEN
+    REWRITE_TAC[DIMINDEX_2; LE_REFL; PATH_CONNECTED_IFF_PATH_COMPONENT] THEN
+    DISCH_THEN MATCH_MP_TAC THEN CONJ_TAC THENL
+     [ASM SET_TAC[]; REWRITE_TAC[IN_SPHERE_0; COMPLEX_NORM_CX; REAL_ABS_NUM]];
+    EQ_TAC THEN STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP lemma) THENL
+     [FIRST_ASSUM(STRIP_ASSUME_TAC o
+         MATCH_MP HOMOTOPIC_WITH_IMP_CONTINUOUS) THEN
+      FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET) THEN
+      DISCH_THEN(MP_TAC o SPEC `\x. inv((g:real^N->complex) x)`);
+      DISCH_THEN(MP_TAC o SPEC `g:real^N->complex`)] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; FORALL_IN_IMAGE; IN_SPHERE_0]) THEN
+    ASM_SIMP_TAC[IN_SPHERE_0; COMPLEX_NORM_INV; REAL_INV_1] THEN
+    ASM_SIMP_TAC[GSYM COMPLEX_NORM_ZERO; REAL_OF_NUM_EQ; ARITH_EQ;
+                 CONTINUOUS_ON_COMPLEX_INV] THEN
+    ASM_REWRITE_TAC[SUBSET; IN_SPHERE_0; FORALL_IN_IMAGE] THEN
+    MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+     HOMOTOPIC_WITH_EQ) THEN
+    ASM_SIMP_TAC[COMPLEX_DIV_RMUL; COMPLEX_MUL_LID; COMPLEX_MUL_RINV;
+                 GSYM complex_div; COMPLEX_DIV_REFL;
+                 GSYM COMPLEX_NORM_ZERO; REAL_OF_NUM_EQ; ARITH_EQ]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* In particular, complex logs exist on various "well-behaved" sets.         *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_LOGARITHM_ON_CONTRACTIBLE = prove
+ (`!f:real^N->complex s.
+        f continuous_on s /\ contractible s /\
+        (!x. x IN s ==> ~(f x = Cx(&0)))
+        ==> ?g. g continuous_on s /\ !x. x IN s ==> f x = cexp(g x)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[GSYM INESSENTIAL_EQ_CONTINUOUS_LOGARITHM] THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC NULLHOMOTOPIC_FROM_CONTRACTIBLE THEN
+  ASM_REWRITE_TAC[] THEN ASM SET_TAC[]);;
+
+let CONTINUOUS_LOGARITHM_ON_SIMPLY_CONNECTED = prove
+ (`!f:real^N->complex s.
+        f continuous_on s /\ simply_connected s /\ locally path_connected s /\
+        (!x. x IN s ==> ~(f x = Cx(&0)))
+        ==> ?g. g continuous_on s /\ !x. x IN s ==> f x = cexp(g x)`,
+  REPEAT STRIP_TAC THEN MP_TAC
+  (ISPECL [`f:real^N->complex`; `s:real^N->bool`]
+    (MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ] COVERING_SPACE_LIFT)
+        COVERING_SPACE_CEXP_PUNCTURED_PLANE)) THEN
+  ASM_REWRITE_TAC[IN_UNIV] THEN ASM SET_TAC[]);;
+
+let CONTINUOUS_LOGARITHM_ON_CBALL = prove
+ (`!f:real^N->complex a r.
+        f continuous_on cball(a,r) /\
+        (!z. z IN cball(a,r) ==> ~(f z = Cx(&0)))
+        ==> ?h. h continuous_on cball(a,r) /\
+                !z. z IN cball(a,r) ==> f z = cexp(h z)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `cball(a:real^N,r) = {}` THEN
+  ASM_REWRITE_TAC[CONTINUOUS_ON_EMPTY; NOT_IN_EMPTY] THEN
+  MATCH_MP_TAC CONTINUOUS_LOGARITHM_ON_CONTRACTIBLE THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC STARLIKE_IMP_CONTRACTIBLE THEN
+  MATCH_MP_TAC CONVEX_IMP_STARLIKE THEN
+  ASM_REWRITE_TAC[CONVEX_CBALL]);;
+
+let CONTINUOUS_LOGARITHM_ON_BALL = prove
+ (`!f:real^N->complex a r.
+        f continuous_on ball(a,r) /\
+        (!x. x IN ball(a,r) ==> ~(f x = Cx(&0)))
+        ==> ?h. h continuous_on ball(a,r) /\
+                !x. x IN ball(a,r) ==> f x = cexp(h x)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `ball(a:real^N,r) = {}` THEN
+  ASM_REWRITE_TAC[CONTINUOUS_ON_EMPTY; NOT_IN_EMPTY] THEN
+  MATCH_MP_TAC CONTINUOUS_LOGARITHM_ON_CONTRACTIBLE THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC STARLIKE_IMP_CONTRACTIBLE THEN
+  MATCH_MP_TAC CONVEX_IMP_STARLIKE THEN
+  ASM_REWRITE_TAC[CONVEX_BALL]);;
+
+let CONTINUOUS_SQRT_ON_CONTRACTIBLE = prove
+ (`!f:real^N->complex s.
+        f continuous_on s /\ contractible s /\
+        (!x. x IN s ==> ~(f x = Cx(&0)))
+        ==> ?g. g continuous_on s /\ !x. x IN s ==> f x = (g x) pow 2`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP CONTINUOUS_LOGARITHM_ON_CONTRACTIBLE) THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->complex` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\z:real^N. cexp(g z / Cx(&2))` THEN
+  ASM_SIMP_TAC[GSYM CEXP_N; COMPLEX_RING `Cx(&2) * z / Cx(&2) = z`] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  REWRITE_TAC[CONTINUOUS_ON_CEXP] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_DIV THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_CONST] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let CONTINUOUS_SQRT_ON_SIMPLY_CONNECTED = prove
+ (`!f:real^N->complex s.
+        f continuous_on s /\ simply_connected s /\ locally path_connected s /\
+        (!x. x IN s ==> ~(f x = Cx(&0)))
+        ==> ?g. g continuous_on s /\ !x. x IN s ==> f x = (g x) pow 2`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP CONTINUOUS_LOGARITHM_ON_SIMPLY_CONNECTED) THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->complex` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\z:real^N. cexp(g z / Cx(&2))` THEN
+  ASM_SIMP_TAC[GSYM CEXP_N; COMPLEX_RING `Cx(&2) * z / Cx(&2) = z`] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  REWRITE_TAC[CONTINUOUS_ON_CEXP] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_DIV THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_CONST] THEN
+  CONV_TAC COMPLEX_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* Analogously, holomorphic logarithms and square roots.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTRACTIBLE_IMP_HOLOMORPHIC_LOG,SIMPLY_CONNECTED_IMP_HOLOMORPHIC_LOG =
+ (CONJ_PAIR o prove)
+ (`(!s:complex->bool.
+      contractible s
+      ==> !f. f holomorphic_on s /\ (!z. z IN s ==> ~(f z = Cx(&0)))
+              ==> ?g. g holomorphic_on s /\ !z. z IN s ==> f z = cexp(g z)) /\
+   (!s:complex->bool.
+      simply_connected s /\ locally path_connected s
+      ==> !f. f holomorphic_on s /\ (!z. z IN s ==> ~(f z = Cx(&0)))
+              ==> ?g. g holomorphic_on s /\ !z. z IN s ==> f z = cexp(g z))`,
+  REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL [`f:complex->complex`; `s:complex->bool`]
+        CONTINUOUS_LOGARITHM_ON_CONTRACTIBLE);
+    MP_TAC(ISPECL [`f:complex->complex`; `s:complex->bool`]
+        CONTINUOUS_LOGARITHM_ON_SIMPLY_CONNECTED)] THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_IMP_CONTINUOUS_ON] THEN
+ (MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:complex->complex` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  UNDISCH_TAC `f holomorphic_on s` THEN
+  REWRITE_TAC[holomorphic_on] THEN MATCH_MP_TAC MONO_FORALL THEN
+  X_GEN_TAC `z:complex` THEN ASM_CASES_TAC `(z:complex) IN s` THEN
+  ASM_REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f':complex` MP_TAC) THEN
+  DISCH_THEN(MP_TAC o
+   ISPECL [`\x. (cexp(g x) - cexp(g z)) / (x - z)`; `&1`] o
+   MATCH_MP (REWRITE_RULE [TAUT `p /\ q /\ r ==> s <=> r ==> p /\ q ==> s`]
+    LIM_TRANSFORM_WITHIN)) THEN
+  ASM_SIMP_TAC[REAL_LT_01] THEN
+  DISCH_THEN(MP_TAC o
+    SPECL [`\x:complex. if g x = g z then cexp(g z)
+                        else (cexp(g x) - cexp(g z)) / (g x - g z)`;
+           `cexp(g(z:complex))`] o
+    MATCH_MP (REWRITE_RULE[IMP_CONJ] LIM_COMPLEX_DIV)) THEN
+  REWRITE_TAC[CEXP_NZ] THEN ANTS_TAC THENL
+   [SUBGOAL_THEN
+     `(\x. if g x = g z then cexp(g z)
+           else (cexp(g x) - cexp(g(z:complex))) / (g x - g z)) =
+      (\y. if y = g z then cexp(g z) else (cexp y - cexp(g z)) / (y - g z)) o g`
+    SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+    MATCH_MP_TAC LIM_COMPOSE_AT THEN
+    EXISTS_TAC `(g:complex->complex) z` THEN REPEAT CONJ_TAC THENL
+     [ASM_MESON_TAC[CONTINUOUS_ON];
+      REWRITE_TAC[EVENTUALLY_TRUE];
+      ONCE_REWRITE_TAC[LIM_AT_ZERO] THEN
+      SIMP_TAC[COMPLEX_VEC_0; COMPLEX_ADD_SUB; COMPLEX_EQ_ADD_LCANCEL_0] THEN
+      MP_TAC(SPEC `cexp(g(z:complex))` (MATCH_MP LIM_COMPLEX_LMUL
+       LIM_CEXP_MINUS_1)) THEN REWRITE_TAC[COMPLEX_MUL_RID] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LIM_TRANSFORM_EVENTUALLY) THEN
+      SIMP_TAC[EVENTUALLY_AT; GSYM DIST_NZ; CEXP_ADD] THEN
+      EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN
+      SIMPLE_COMPLEX_ARITH_TAC];
+    DISCH_THEN(fun th ->
+        EXISTS_TAC `f' / cexp(g(z:complex))` THEN MP_TAC th) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ]
+        LIM_TRANSFORM_EVENTUALLY) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+     [CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN]) THEN
+    DISCH_THEN(MP_TAC o SPEC `z:complex`) THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[CONTINUOUS_WITHIN; tendsto] THEN
+    DISCH_THEN(MP_TAC o SPEC `&2 * pi`) THEN
+    REWRITE_TAC[REAL_ARITH `&0 < &2 * x <=> &0 < x`; PI_POS] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+    X_GEN_TAC `w:complex` THEN REWRITE_TAC[dist] THEN DISCH_TAC THEN
+    COND_CASES_TAC THENL
+     [ASM_REWRITE_TAC[COMPLEX_SUB_REFL; complex_div; COMPLEX_MUL_LZERO];
+      ASM_CASES_TAC `w:complex = z` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+      SUBGOAL_THEN `~(cexp(g(w:complex)) = cexp(g z))` MP_TAC THENL
+       [UNDISCH_TAC `~((g:complex->complex) w = g z)` THEN
+        REWRITE_TAC[CONTRAPOS_THM] THEN
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] COMPLEX_EQ_CEXP) THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+         REAL_LET_TRANS)) THEN
+        REWRITE_TAC[GSYM IM_SUB; COMPLEX_NORM_GE_RE_IM];
+        REPEAT(FIRST_X_ASSUM(MP_TAC o check(is_neg o concl))) THEN
+        CONV_TAC COMPLEX_FIELD]]]));;
+
+let CONTRACTIBLE_IMP_HOLOMORPHIC_SQRT,SIMPLY_CONNECTED_IMP_HOLOMORPHIC_SQRT =
+ (CONJ_PAIR o prove)
+ (`(!s:complex->bool.
+      contractible s
+      ==> !f. f holomorphic_on s /\ (!z. z IN s ==> ~(f z = Cx(&0)))
+              ==> ?g. g holomorphic_on s /\  !z. z IN s ==> f z = g z pow 2) /\
+   (!s:complex->bool.
+      simply_connected s /\ locally path_connected s
+      ==> !f. f holomorphic_on s /\ (!z. z IN s ==> ~(f z = Cx(&0)))
+              ==> ?g. g holomorphic_on s /\  !z. z IN s ==> f z = g z pow 2)`,
+  CONJ_TAC THEN GEN_TAC THENL
+   [DISCH_THEN(ASSUME_TAC o MATCH_MP CONTRACTIBLE_IMP_HOLOMORPHIC_LOG);
+    DISCH_THEN(ASSUME_TAC o
+      MATCH_MP SIMPLY_CONNECTED_IMP_HOLOMORPHIC_LOG)] THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `f:complex->complex`) THEN ASM_SIMP_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\z:complex. cexp(g z / Cx(&2))` THEN
+  ASM_SIMP_TAC[GSYM CEXP_N; COMPLEX_RING `Cx(&2) * z / Cx(&2) = z`] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN
+  REWRITE_TAC[HOLOMORPHIC_ON_CEXP] THEN
+  MATCH_MP_TAC HOLOMORPHIC_ON_DIV THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_CONST] THEN
+  CONV_TAC COMPLEX_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* Related theorems about holomorphic inverse cosines.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTRACTIBLE_IMP_HOLOMORPHIC_ACS = prove
+ (`!f s. f holomorphic_on s /\ contractible s /\
+         (!z. z IN s ==> ~(f z = Cx(&1)) /\ ~(f z = --Cx(&1)))
+         ==> ?g. g holomorphic_on s /\ !z. z IN s ==> f z = ccos(g z)`,
+   REPEAT STRIP_TAC THEN
+   FIRST_ASSUM(MP_TAC o SPEC `\z:complex. Cx(&1) - f(z) pow 2` o
+     MATCH_MP CONTRACTIBLE_IMP_HOLOMORPHIC_SQRT) THEN
+   ASM_SIMP_TAC[HOLOMORPHIC_ON_SUB; HOLOMORPHIC_ON_CONST; HOLOMORPHIC_ON_POW;
+                COMPLEX_RING `~(Cx(&1) - z pow 2 = Cx(&0)) <=>
+                              ~(z = Cx(&1)) /\ ~(z = --Cx(&1))`] THEN
+   REWRITE_TAC[COMPLEX_RING
+    `Cx(&1) - w pow 2 = z pow 2 <=>
+     (w + ii * z) * (w - ii * z) = Cx(&1)`] THEN
+   DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC) THEN
+   FIRST_ASSUM(MP_TAC o SPEC `\z:complex. f(z) + ii * g(z)` o
+       MATCH_MP CONTRACTIBLE_IMP_HOLOMORPHIC_LOG) THEN
+   ASM_SIMP_TAC[HOLOMORPHIC_ON_ADD; HOLOMORPHIC_ON_MUL; HOLOMORPHIC_ON_CONST;
+     COMPLEX_RING `(a + b) * (a - b) = Cx(&1) ==> ~(a + b = Cx(&0))`] THEN
+   DISCH_THEN(X_CHOOSE_THEN `h:complex->complex` STRIP_ASSUME_TAC) THEN
+   EXISTS_TAC `\z:complex. --ii * h(z)` THEN
+   ASM_SIMP_TAC[HOLOMORPHIC_ON_MUL; HOLOMORPHIC_ON_CONST; ccos] THEN
+   X_GEN_TAC `z:complex` THEN
+   DISCH_TAC THEN REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`)) THEN
+   ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+   FIRST_X_ASSUM(MP_TAC o MATCH_MP (COMPLEX_FIELD
+    `a * b = Cx(&1) ==> b = inv a`)) THEN
+   ASM_SIMP_TAC[GSYM CEXP_NEG] THEN
+   FIRST_X_ASSUM(ASSUME_TAC o SYM) THEN DISCH_THEN(ASSUME_TAC o SYM) THEN
+   ASM_REWRITE_TAC[COMPLEX_RING `ii * --ii * z = z`;
+                   COMPLEX_RING `--ii * --ii * z = --z`] THEN
+   CONV_TAC COMPLEX_RING);;
+
+let CONTRACTIBLE_IMP_HOLOMORPHIC_ACS_BOUNDED = prove
+ (`!f s a.
+        f holomorphic_on s /\ contractible s /\ a IN s /\
+        (!z. z IN s ==> ~(f z = Cx(&1)) /\ ~(f z = --Cx(&1)))
+        ==> ?g. g holomorphic_on s /\ norm(g a) <= pi + norm(f a) /\
+                !z. z IN s ==> f z = ccos(g z)`,
+  let lemma = prove
+    (`!w. ?v. ccos(v) = w /\ norm(v) <= pi + norm(w)`,
+     GEN_TAC THEN EXISTS_TAC `cacs w` THEN ABBREV_TAC `v = cacs w` THEN
+     MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+      [ASM_MESON_TAC[CCOS_CACS]; DISCH_THEN(SUBST1_TAC o SYM)] THEN
+     SIMP_TAC[NORM_LE_SQUARE; PI_POS_LE; NORM_POS_LE; REAL_LE_ADD] THEN
+     MATCH_MP_TAC(REAL_ARITH
+      `&0 <= b * c /\ a <= b pow 2 + c pow 2 ==> a <= (b + c) pow 2`) THEN
+     SIMP_TAC[REAL_LE_MUL; PI_POS_LE; NORM_POS_LE] THEN
+     REWRITE_TAC[COMPLEX_SQNORM; GSYM NORM_POW_2; NORM_CCOS_POW_2] THEN
+     MATCH_MP_TAC REAL_LE_ADD2 THEN REWRITE_TAC[GSYM REAL_LE_SQUARE_ABS] THEN
+     EXPAND_TAC "v" THEN REWRITE_TAC[REAL_ABS_PI; RE_CACS_BOUND] THEN
+     MATCH_MP_TAC(REAL_ARITH
+      `&0 <= c /\ x <= (d / &2) pow 2 ==> x <= c + d pow 2 / &4`) THEN
+     REWRITE_TAC[REAL_LE_POW_2; GSYM REAL_LE_SQUARE_ABS; REAL_LE_ABS_SINH]) in
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:complex->complex`; `s:complex->bool`]
+        CONTRACTIBLE_IMP_HOLOMORPHIC_ACS) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPEC `(f:complex->complex) a` lemma) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:complex` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `ccos b = ccos(g(a:complex))` MP_TAC THENL
+   [ASM_MESON_TAC[]; REWRITE_TAC[CCOS_EQ]] THEN
+  DISCH_THEN(X_CHOOSE_THEN `n:real` (STRIP_ASSUME_TAC o GSYM)) THENL
+   [EXISTS_TAC `\z:complex. g z + Cx(&2 * n * pi)`;
+    EXISTS_TAC `\z:complex. --(g z) + Cx(&2 * n * pi)`] THEN
+  ASM_SIMP_TAC[HOLOMORPHIC_ON_ADD; HOLOMORPHIC_ON_NEG;
+               HOLOMORPHIC_ON_CONST] THEN
+  CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN REWRITE_TAC[CCOS_EQ] THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Another interesting equivalent of an inessential mapping into C-{0}       *)
+(* ------------------------------------------------------------------------- *)
+
+let INESSENTIAL_EQ_EXTENSIBLE = prove
+ (`!f s.
+   closed s
+   ==> ((?a. homotopic_with (\h. T) (s,(:complex) DIFF {Cx(&0)}) f (\t. a)) <=>
+        (?g. g continuous_on (:real^N) /\
+             (!x. x IN s ==> g x = f x) /\ (!x. ~(g x = Cx(&0)))))`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_TAC `a:complex`) THEN
+    ASM_CASES_TAC `s:real^N->bool = {}` THENL
+     [EXISTS_TAC `\x:real^N. Cx(&1)` THEN
+      ASM_REWRITE_TAC[CONTINUOUS_ON_CONST; NOT_IN_EMPTY] THEN
+      CONV_TAC COMPLEX_RING;
+      ALL_TAC] THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_CONTINUOUS) THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET) THEN
+    FIRST_ASSUM(MP_TAC o
+      SPECL [`(:real^N)`; `(:complex) DIFF {Cx(&0)}`] o
+      MATCH_MP(ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+        (REWRITE_RULE[CONJ_ASSOC] BORSUK_HOMOTOPY_EXTENSION)) o
+      GEN_REWRITE_RULE I [HOMOTOPIC_WITH_SYM]) THEN
+    ASM_SIMP_TAC[CLOSED_UNIV; CONTINUOUS_ON_CONST; OPEN_DIFF; CLOSED_SING;
+                 OPEN_UNIV; RETRACT_OF_REFL] THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; MATCH_MP_TAC MONO_EXISTS] THEN
+    ASM SET_TAC[];
+    DISCH_THEN(X_CHOOSE_THEN `g:real^N->complex` STRIP_ASSUME_TAC) THEN
+    REWRITE_TAC[INESSENTIAL_EQ_CONTINUOUS_LOGARITHM] THEN
+    MP_TAC(ISPECL [`vec 0:real^N`; `&1`] HOMEOMORPHIC_BALL_UNIV) THEN
+    REWRITE_TAC[REAL_LT_01; homeomorphic; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`h:real^N->real^N`; `k:real^N->real^N`] THEN
+    REWRITE_TAC[homeomorphism; IN_UNIV] THEN STRIP_TAC THEN
+    MP_TAC(ISPECL [`(g:real^N->complex) o (h:real^N->real^N)`;
+                   `vec 0:real^N`; `&1`] CONTINUOUS_LOGARITHM_ON_BALL) THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_COMPOSE; o_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `j:real^N->complex` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(j:real^N->complex) o (k:real^N->real^N)` THEN
+    ASM_SIMP_TAC[o_THM] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+      CONTINUOUS_ON_SUBSET)) THEN ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Unicoherence.                                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let INESSENTIAL_IMP_UNICOHERENT = prove
+ (`!u:real^N->bool.
+        (!f. f continuous_on u /\ IMAGE f u SUBSET sphere(vec 0,&1)
+             ==> ?a. homotopic_with (\h. T)
+                       (u,(:complex) DIFF {Cx (&0)}) f (\t. a))
+        ==> !s t. connected s /\ connected t /\ s UNION t = u /\
+                  closed_in (subtopology euclidean u) s /\
+                  closed_in (subtopology euclidean u) t
+                  ==> connected (s INTER t)`,
+  REWRITE_TAC[sphere; DIST_0; INESSENTIAL_EQ_CONTINUOUS_LOGARITHM] THEN
+  REPEAT STRIP_TAC THEN SIMP_TAC[CONNECTED_CLOSED_IN_EQ; NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`v:real^N->bool`; `w:real^N->bool`] THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `closed_in (subtopology euclidean u) (v:real^N->bool) /\
+    closed_in (subtopology euclidean u) (w:real^N->bool)`
+  STRIP_ASSUME_TAC THENL
+   [ASM_MESON_TAC[CLOSED_IN_INTER; CLOSED_IN_TRANS]; ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`v:real^N->bool`; `w:real^N->bool`; `u:real^N->bool`;
+    `vec 0:real^1`; `vec 1:real^1`] URYSOHN_LOCAL) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `q:real^N->real^1` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `?g:real^N->real^2.
+        g continuous_on u /\ IMAGE g u SUBSET {x | norm x = &1} /\
+        (!x. x IN s ==> g(x) = cexp(Cx pi * ii * Cx(drop(q x)))) /\
+        (!x. x IN t ==> g(x) = inv(cexp(Cx pi * ii * Cx(drop(q x)))))`
+  (DESTRUCT_TAC "@g. cont circle s t") THENL
+   [EXISTS_TAC
+     `\x. if (x:real^N) IN s then cexp(Cx pi * ii * Cx(drop(q x)))
+          else inv(cexp(Cx pi * ii * Cx(drop(q x))))` THEN
+    SUBGOAL_THEN
+     `!x:real^N.
+        x IN s INTER t
+        ==> cexp(Cx pi * ii * Cx(drop(q x))) =
+            inv(cexp(Cx pi * ii * Cx(drop (q x))))`
+    ASSUME_TAC THENL
+     [SUBST1_TAC(SYM(ASSUME `v UNION w:real^N->bool = s INTER t`)) THEN
+      REWRITE_TAC[IN_UNION] THEN REPEAT STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+      REWRITE_TAC[DROP_VEC; COMPLEX_MUL_RZERO; CEXP_0; COMPLEX_INV_1] THEN
+      REWRITE_TAC[COMPLEX_MUL_RID; EULER] THEN
+      REWRITE_TAC[RE_MUL_CX; IM_MUL_CX; RE_MUL_II; IM_MUL_II] THEN
+      REWRITE_TAC[RE_II; IM_II; REAL_MUL_RZERO; REAL_MUL_RID] THEN
+      REWRITE_TAC[REAL_EXP_0; COMPLEX_MUL_LID; COS_PI; SIN_PI] THEN
+      REWRITE_TAC[COMPLEX_MUL_RZERO; COMPLEX_ADD_RID] THEN
+      CONV_TAC COMPLEX_RING;
+      ALL_TAC] THEN
+    SIMP_TAC[] THEN REPEAT CONJ_TAC THENL
+     [EXPAND_TAC "u" THEN MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN
+      ASM_REWRITE_TAC[SET_RULE
+       `P /\ ~P \/ x IN t /\ x IN s <=> x IN s INTER t`] THEN
+      CONJ_TAC THENL
+       [ALL_TAC;
+        MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_INV THEN REWRITE_TAC[CEXP_NZ]] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      REWRITE_TAC[CONTINUOUS_ON_CEXP] THEN
+      REWRITE_TAC[COMPLEX_MUL_ASSOC] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN
+      REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_CX_DROP THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNION];
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+      REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+      REWRITE_TAC[COMPLEX_NORM_INV; NORM_CEXP] THEN
+      REWRITE_TAC[RE_MUL_CX; RE_MUL_II; IM_CX] THEN
+      REWRITE_TAC[REAL_MUL_RZERO; REAL_NEG_0; REAL_EXP_0; REAL_INV_1];
+      GEN_TAC THEN DISCH_TAC THEN COND_CASES_TAC THEN
+      ASM_REWRITE_TAC[] THEN ASM SET_TAC[]];
+     FIRST_X_ASSUM(MP_TAC o SPEC `g:real^N->complex`) THEN
+     ASM_REWRITE_TAC[] THEN
+     DISCH_THEN(X_CHOOSE_THEN `h:real^N->complex` STRIP_ASSUME_TAC)] THEN
+  SUBGOAL_THEN
+   `(?n. integer n /\
+         !x:real^N. x IN s
+                    ==> h(x) - Cx pi * ii * Cx (drop (q x)) =
+                        Cx(&2 * n * pi) * ii) /\
+    (?n. integer n /\
+         !x:real^N. x IN t
+                    ==> h(x) + Cx pi * ii * Cx (drop (q x)) =
+                        Cx(&2 * n * pi) * ii)`
+  (CONJUNCTS_THEN2
+    (X_CHOOSE_THEN `m:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC))
+    (X_CHOOSE_THEN `n:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)))
+  THENL
+   [CONJ_TAC THEN MATCH_MP_TAC(MESON[]
+     `(?x. x IN s) /\
+      (!x. x IN s ==> ?n. P n /\ f x = k n) /\
+      (?a. !x. x IN s ==> f x = a)
+      ==> (?n. P n /\ !x. x IN s ==> f x = k n)`) THEN
+    (CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+    MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN
+   (CONJ_TAC THENL
+     [REWRITE_TAC[COMPLEX_RING `a + b:complex = c <=> a = --b + c`;
+                  COMPLEX_RING `a - b:complex = c <=> a = b + c`] THEN
+      REWRITE_TAC[GSYM CEXP_EQ; CEXP_NEG] THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    DISCH_THEN(LABEL_TAC "*") THEN
+    MATCH_MP_TAC CONTINUOUS_DISCRETE_RANGE_CONSTANT THEN
+    ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [(MATCH_MP_TAC CONTINUOUS_ON_ADD ORELSE
+       MATCH_MP_TAC CONTINUOUS_ON_SUB) THEN
+      CONJ_TAC THENL
+       [ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNION]; ALL_TAC] THEN
+      REWRITE_TAC[COMPLEX_MUL_ASSOC] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN
+      REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_CX_DROP THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; SUBSET_UNION];
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN EXISTS_TAC `&2 * pi` THEN
+      REWRITE_TAC[REAL_ARITH `&0 < &2 * x <=> &0 < x`; PI_POS] THEN
+      X_GEN_TAC `y:real^N` THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+      REMOVE_THEN "*" (fun th ->
+       MP_TAC(SPEC `y:real^N` th) THEN MP_TAC(SPEC `x:real^N` th)) THEN
+      ASM_REWRITE_TAC[] THEN STRIP_TAC THEN STRIP_TAC THEN
+      ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[COMPLEX_EQ_MUL_RCANCEL; II_NZ; GSYM COMPLEX_SUB_RDISTRIB;
+            COMPLEX_NORM_MUL; CX_INJ; COMPLEX_NORM_II; REAL_MUL_RID] THEN
+      REWRITE_TAC[GSYM CX_SUB; COMPLEX_NORM_CX] THEN
+      REWRITE_TAC[REAL_EQ_MUL_LCANCEL; GSYM REAL_SUB_LDISTRIB] THEN
+      REWRITE_TAC[GSYM REAL_SUB_RDISTRIB; REAL_ABS_MUL] THEN
+      REWRITE_TAC[REAL_EQ_MUL_RCANCEL; PI_NZ; REAL_ABS_PI] THEN
+      REWRITE_TAC[REAL_ABS_NUM; REAL_OF_NUM_EQ; ARITH_EQ] THEN
+      DISCH_TAC THEN REWRITE_TAC[REAL_ARITH
+       `&2 * p <= &2 * a * p <=> &0 <= &2 * p * (a - &1)`] THEN
+      MATCH_MP_TAC REAL_LE_MUL THEN REWRITE_TAC[REAL_POS] THEN
+      MATCH_MP_TAC REAL_LE_MUL THEN REWRITE_TAC[PI_POS_LE; REAL_SUB_LE] THEN
+      MATCH_MP_TAC REAL_ABS_INTEGER_LEMMA THEN
+      ASM_SIMP_TAC[INTEGER_CLOSED; REAL_SUB_0]]);
+      ALL_TAC] THEN
+  GEN_REWRITE_TAC I [TAUT `p ==> q ==> F <=> ~(p /\ q)`] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE
+   `(!x. x IN s ==> P x) /\ (!x. x IN t ==> Q x)
+    ==> ~(v = {}) /\ ~(w = {}) /\ v UNION w SUBSET s INTER t
+         ==> ~(!y z. y IN v /\ z IN w ==> ~(P y /\ Q y /\ P z /\ Q z))`)) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ASM_SIMP_TAC[]] THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP (COMPLEX_RING
+   `y + p = n /\ y - p = m /\ z + q = n /\ z - q = m ==> q:complex = p`)) THEN
+  REWRITE_TAC[DROP_VEC; COMPLEX_MUL_RZERO; COMPLEX_ENTIRE; CX_INJ] THEN
+  REWRITE_TAC[PI_NZ; II_NZ; REAL_OF_NUM_EQ; ARITH_EQ]);;
+
+let CONTRACTIBLE_IMP_UNICOHERENT = prove
+ (`!u:real^N->bool.
+        contractible u
+        ==> !s t. connected s /\ connected t /\ s UNION t = u /\
+                  closed_in (subtopology euclidean u) s /\
+                  closed_in (subtopology euclidean u) t
+                  ==> connected (s INTER t)`,
+  GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC INESSENTIAL_IMP_UNICOHERENT THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC NULLHOMOTOPIC_FROM_CONTRACTIBLE THEN
+  ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+   (REWRITE_RULE[IMP_CONJ] SUBSET_TRANS)) THEN
+  REWRITE_TAC[SUBSET; IN_SPHERE_0; IN_DIFF; IN_UNIV; IN_SING] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  SIMP_TAC[COMPLEX_NORM_0] THEN REAL_ARITH_TAC);;
+
+let CONVEX_IMP_UNICOHERENT = prove
+ (`!u:real^N->bool.
+        convex u
+        ==> !s t. connected s /\ connected t /\ s UNION t = u /\
+                  closed_in (subtopology euclidean u) s /\
+                  closed_in (subtopology euclidean u) t
+                  ==> connected (s INTER t)`,
+  GEN_TAC THEN DISCH_TAC THEN
+  ASM_CASES_TAC `u:real^N->bool = {}` THEN
+  ASM_SIMP_TAC[EMPTY_UNION; INTER_EMPTY; CONNECTED_EMPTY] THEN
+  MATCH_MP_TAC CONTRACTIBLE_IMP_UNICOHERENT THEN
+  ASM_SIMP_TAC[CONVEX_IMP_STARLIKE; STARLIKE_IMP_CONTRACTIBLE]);;
+
+let UNICOHERENT_UNIV = prove
+ (`!s t. closed s /\ closed t /\ connected s /\ connected t /\
+         s UNION t = (:real^N)
+         ==> connected(s INTER t)`,
+  MP_TAC(ISPEC `(:real^N)` CONVEX_IMP_UNICOHERENT) THEN
+  REWRITE_TAC[CONVEX_UNIV; SUBTOPOLOGY_UNIV; GSYM CLOSED_IN] THEN
+  REWRITE_TAC[CONJ_ACI]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Another simple case where sphere maps are nullhomotopic.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let INESSENTIAL_SPHEREMAP_2 = prove
+ (`!f:real^M->real^N a r b s.
+        2 < dimindex(:M) /\ dimindex(:N) = 2 /\
+        f continuous_on sphere(a,r) /\
+        IMAGE f (sphere(a,r)) SUBSET (sphere(b,s))
+        ==> ?c. homotopic_with (\z. T) (sphere(a,r),sphere(b,s)) f (\x. c)`,
+  let lemma = prove
+   (`!f:real^N->real^2 a r.
+          2 < dimindex(:N) /\
+          f continuous_on sphere(a,r) /\
+          IMAGE f (sphere(a,r)) SUBSET (sphere(vec 0,&1))
+          ==> ?c. homotopic_with (\z. T) (sphere(a,r),sphere(vec 0,&1))
+                                 f (\x. c)`,
+    REPEAT STRIP_TAC THEN
+    REWRITE_TAC[INESSENTIAL_EQ_CONTINUOUS_LOGARITHM_CIRCLE] THEN
+    MP_TAC(ISPECL [`f:real^N->real^2`; `sphere(a:real^N,r)`]
+          CONTINUOUS_LOGARITHM_ON_SIMPLY_CONNECTED) THEN
+    ASM_SIMP_TAC[SIMPLY_CONNECTED_SPHERE_EQ; LOCALLY_PATH_CONNECTED_SPHERE] THEN
+    ANTS_TAC THENL
+     [ASM_REWRITE_TAC[ARITH_RULE `3 <= n <=> 2 < n`] THEN FIRST_X_ASSUM
+       (MATCH_MP_TAC o MATCH_MP (SET_RULE
+          `IMAGE f s SUBSET t ==> (!x. P x ==> ~(x IN t))
+          ==> !x. x IN s ==> ~P(f x)`)) THEN
+      SIMP_TAC[COMPLEX_NORM_0; IN_SPHERE_0] THEN REAL_ARITH_TAC;
+      DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^2` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `Im o (g:real^N->real^2)` THEN CONJ_TAC THENL
+       [REWRITE_TAC[o_ASSOC] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        ASM_REWRITE_TAC[CONTINUOUS_ON_CX_IM];
+        X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+        ASM_SIMP_TAC[] THEN AP_TERM_TAC THEN
+        REWRITE_TAC[o_DEF; COMPLEX_EQ; RE_MUL_II; IM_MUL_II; RE_CX; IM_CX] THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+        REWRITE_TAC[FORALL_IN_IMAGE] THEN
+        DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+        ASM_SIMP_TAC[IN_SPHERE_0; NORM_CEXP; REAL_EXP_EQ_1] THEN
+        REAL_ARITH_TAC]])
+  and hslemma = prove
+   (`!a:real^M r b:real^N s.
+        dimindex(:M) = dimindex(:N) /\ &0 < r /\ &0 < s
+        ==> (sphere(a,r) homeomorphic sphere(b,s))`,
+    REPEAT STRIP_TAC THEN FIRST_ASSUM(fun th ->
+      let t = `?a:real^M b:real^N. ~(sphere(a,r) homeomorphic sphere(b,s))` in
+      MP_TAC(DISCH t (GEOM_EQUAL_DIMENSION_RULE th (ASSUME t)))) THEN
+    ASM_SIMP_TAC[HOMEOMORPHIC_SPHERES] THEN MESON_TAC[]) in
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s <= &0` THEN
+  ASM_SIMP_TAC[NULLHOMOTOPIC_INTO_CONTRACTIBLE; CONTRACTIBLE_SPHERE] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[REAL_NOT_LE]) THEN
+  SUBGOAL_THEN
+   `(sphere(b:real^N,s)) homeomorphic (sphere(vec 0:real^2,&1))`
+  MP_TAC THENL
+   [ASM_SIMP_TAC[hslemma; REAL_LT_01; DIMINDEX_2];
+    REWRITE_TAC[homeomorphic; LEFT_IMP_EXISTS_THM]] THEN
+  MAP_EVERY X_GEN_TAC [`h:real^N->real^2`; `k:real^2->real^N`] THEN
+  REWRITE_TAC[homeomorphism] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL
+   [`(h:real^N->real^2) o (f:real^M->real^N)`;
+    `a:real^M`; `r:real`] lemma) THEN
+  ASM_REWRITE_TAC[IMAGE_o] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [MATCH_MP_TAC CONTINUOUS_ON_COMPOSE; ASM SET_TAC[]] THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET];
+    DISCH_THEN(X_CHOOSE_THEN `c:real^2` (fun th ->
+      EXISTS_TAC `(k:real^2->real^N) c` THEN MP_TAC th)) THEN
+    DISCH_THEN(MP_TAC o ISPEC `k:real^2->real^N` o MATCH_MP
+     (ONCE_REWRITE_RULE[IMP_CONJ] HOMOTOPIC_COMPOSE_CONTINUOUS_LEFT)) THEN
+    DISCH_THEN(MP_TAC o SPEC `sphere(b:real^N,s)`) THEN
+    ASM_REWRITE_TAC[SUBSET_REFL] THEN
+    MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_EQ) THEN
+    REWRITE_TAC[o_DEF] THEN ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Janiszewski's theorem.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let JANISZEWSKI = prove
+ (`!s t a b:real^2.
+        compact s /\ closed t /\ connected(s INTER t) /\
+        connected_component ((:real^2) DIFF s) a b /\
+        connected_component ((:real^2) DIFF t) a b
+        ==> connected_component ((:real^2) DIFF (s UNION t)) a b`,
+  let lemma = prove
+   (`!s t a b:real^2.
+          compact s /\ compact t /\ connected(s INTER t) /\
+          connected_component ((:real^2) DIFF s) a b /\
+          connected_component ((:real^2) DIFF t) a b
+          ==> connected_component ((:real^2) DIFF (s UNION t)) a b`,
+    REPEAT GEN_TAC THEN
+    REPLICATE_TAC 3 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+    FIRST_X_ASSUM(CONJUNCTS_THEN(MP_TAC o MATCH_MP CONNECTED_COMPONENT_IN)) THEN
+    REWRITE_TAC[IN_DIFF; IN_UNIV] THEN STRIP_TAC THEN STRIP_TAC THEN
+    ASM_SIMP_TAC[GSYM BORSUK_MAPS_HOMOTOPIC_IN_CONNECTED_COMPONENT_EQ;
+                 DIMINDEX_2; LE_REFL; COMPACT_UNION; IN_UNION] THEN
+    ONCE_REWRITE_TAC[HOMOTOPIC_CIRCLEMAPS_DIV] THEN
+    REWRITE_TAC[INESSENTIAL_EQ_CONTINUOUS_LOGARITHM_CIRCLE] THEN
+    ASM_SIMP_TAC[BORSUK_MAP_INTO_SPHERE; CONTINUOUS_ON_BORSUK_MAP;
+                 IN_UNION] THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `g:real^2->real` STRIP_ASSUME_TAC)
+     (X_CHOOSE_THEN `h:real^2->real` STRIP_ASSUME_TAC)) THEN
+    SUBGOAL_THEN
+     `closed_in (subtopology euclidean (s UNION t)) s /\
+      closed_in (subtopology euclidean (s UNION t)) (t:real^2->bool)`
+    STRIP_ASSUME_TAC THENL
+     [REWRITE_TAC[CLOSED_IN_CLOSED] THEN CONJ_TAC THENL
+       [EXISTS_TAC `s:real^2->bool`; EXISTS_TAC `t:real^2->bool`] THEN
+      ASM_SIMP_TAC[COMPACT_IMP_CLOSED] THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    ASM_CASES_TAC `s INTER t:real^2->bool = {}` THENL
+     [EXISTS_TAC `(\x. if x IN s then g x else h x):real^2->real` THEN
+      CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+      REWRITE_TAC[o_DEF; COND_RAND] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN
+      ASM_REWRITE_TAC[GSYM o_DEF] THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL
+     [`\x:real^2. lift(g x) - lift(h x)`; `s INTER t:real^2->bool`]
+     CONTINUOUS_DISCRETE_RANGE_CONSTANT) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+     [CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+        REWRITE_TAC[GSYM CONTINUOUS_ON_CX_LIFT] THEN
+        REWRITE_TAC[GSYM o_DEF] THEN
+        ASM_MESON_TAC[CONTINUOUS_ON_SUBSET; INTER_SUBSET];
+        REWRITE_TAC[o_DEF]] THEN
+      X_GEN_TAC `x:real^2` THEN REWRITE_TAC[IN_INTER] THEN STRIP_TAC THEN
+      EXISTS_TAC `&2 * pi` THEN
+      REWRITE_TAC[REAL_ARITH `&0 < &2 * x <=> &0 < x`; PI_POS] THEN
+      X_GEN_TAC `y:real^2` THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+      ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[REAL_NOT_LE] THEN
+      REWRITE_TAC[GSYM LIFT_SUB; LIFT_EQ; NORM_LIFT] THEN DISCH_TAC THEN
+      ONCE_REWRITE_TAC[REAL_RING `a - b:real = c - d <=> a - c = b - d`] THEN
+      REWRITE_TAC[GSYM CX_INJ] THEN
+      MATCH_MP_TAC(COMPLEX_RING `ii * w = ii * z ==> w = z`) THEN
+      MATCH_MP_TAC COMPLEX_EQ_CEXP THEN CONJ_TAC THENL
+       [REWRITE_TAC[IM_MUL_II; RE_CX] THEN ASM_REAL_ARITH_TAC;
+        REWRITE_TAC[CX_SUB; COMPLEX_SUB_LDISTRIB; CEXP_SUB] THEN
+        ASM_MESON_TAC[]];
+      REWRITE_TAC[EXISTS_LIFT; GSYM LIFT_SUB; LIFT_EQ; IN_INTER] THEN
+      REWRITE_TAC[REAL_EQ_SUB_RADD; LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `z:real` THEN DISCH_TAC THEN
+      EXISTS_TAC `(\x. if x IN s then g x else z + h x):real^2->real` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[o_DEF; COND_RAND] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN
+        ASM_SIMP_TAC[TAUT `~(p /\ ~p)`; CX_ADD; GSYM o_DEF] THEN
+        REWRITE_TAC[o_DEF; CX_ADD] THEN MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
+        ASM_REWRITE_TAC[CONTINUOUS_ON_CONST; GSYM o_DEF];
+        X_GEN_TAC `x:real^2` THEN REWRITE_TAC[] THEN
+        COND_CASES_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+        ASM_SIMP_TAC[] THEN DISCH_TAC THEN
+        SUBGOAL_THEN
+         `?w:real^2. cexp(ii * Cx(h w)) = cexp (ii * Cx(z + h w))`
+         (CHOOSE_THEN MP_TAC) THENL [ASM SET_TAC[]; ALL_TAC] THEN
+        REWRITE_TAC[CX_ADD; COMPLEX_ADD_LDISTRIB; CEXP_ADD] THEN
+        REWRITE_TAC[COMPLEX_FIELD `a = b * a <=> a = Cx(&0) \/ b = Cx(&1)`;
+                    CEXP_NZ]]]) in
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?c:real^2->bool.
+       compact c /\ connected c /\ a IN c /\ b IN c /\ c INTER t = {}`
+  STRIP_ASSUME_TAC THENL
+   [SUBGOAL_THEN `path_component((:real^2) DIFF t) a b` MP_TAC THENL
+     [ASM_MESON_TAC[OPEN_PATH_CONNECTED_COMPONENT; closed; COMPACT_IMP_CLOSED];
+      REWRITE_TAC[path_component; SET_RULE
+        `s SUBSET UNIV DIFF t <=> s INTER t = {}`]] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real^1->real^2` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `path_image(g:real^1->real^2)` THEN
+    ASM_SIMP_TAC[CONNECTED_PATH_IMAGE; COMPACT_PATH_IMAGE] THEN
+    ASM_MESON_TAC[PATHSTART_IN_PATH_IMAGE; PATHFINISH_IN_PATH_IMAGE];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`c UNION s:real^2->bool`; `vec 0:real^2`]
+        BOUNDED_SUBSET_BALL) THEN
+  ASM_SIMP_TAC[BOUNDED_UNION; COMPACT_IMP_BOUNDED; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `r:real` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^2->bool`;
+                 `(t INTER cball(vec 0,r)) UNION sphere(vec 0:real^2,r)`;
+                 `a:real^2`; `b:real^2`] lemma) THEN
+  ASM_SIMP_TAC[COMPACT_UNION; CLOSED_INTER_COMPACT;
+               COMPACT_SPHERE; COMPACT_CBALL] THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [UNDISCH_TAC `connected(s INTER t:real^2->bool)` THEN
+      MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC;
+      REWRITE_TAC[connected_component] THEN EXISTS_TAC `c:real^2->bool`] THEN
+    MP_TAC(ISPECL [`vec 0:real^2`; `r:real`] CBALL_DIFF_SPHERE) THEN
+    ASM SET_TAC[];
+    REWRITE_TAC[connected_component] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `u:real^2->bool` THEN
+    SIMP_TAC[SET_RULE `s SUBSET UNIV DIFF t <=> s INTER t = {}`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL
+     [`u:real^2->bool`; `cball(vec 0:real^2,r)`] CONNECTED_INTER_FRONTIER) THEN
+    ASM_REWRITE_TAC[FRONTIER_CBALL] THEN
+    MP_TAC(ISPECL [`vec 0:real^2`; `r:real`] BALL_SUBSET_CBALL) THEN
+    ASM SET_TAC[]]);;
+
+let JANISZEWSKI_GEN = prove
+ (`!s t a b:real^N.
+        dimindex(:N) <= 2 /\
+        compact s /\ closed t /\ connected(s INTER t) /\
+        connected_component ((:real^N) DIFF s) a b /\
+        connected_component ((:real^N) DIFF t) a b
+        ==> connected_component ((:real^N) DIFF (s UNION t)) a b`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `dimindex(:N) = 1` THENL
+   [ASM_SIMP_TAC[CONNECTED_COMPONENT_1_GEN] THEN SET_TAC[];
+    ASM_SIMP_TAC[ARITH_RULE `1 <= n /\ ~(n = 1) ==> (n <= 2 <=> n = 2)`;
+                 DIMINDEX_GE_1] THEN
+    ONCE_REWRITE_TAC[IMP_CONJ] THEN REWRITE_TAC[GSYM DIMINDEX_2] THEN
+    DISCH_THEN(fun th ->
+     MATCH_ACCEPT_TAC(GEOM_EQUAL_DIMENSION_RULE th JANISZEWSKI))]);;
diff --git a/Multivariate/tarski.ml b/Multivariate/tarski.ml
new file mode 100644 (file)
index 0000000..8e9d031
--- /dev/null
@@ -0,0 +1,261 @@
+(* ========================================================================= *)
+(* Proof that Tarski's axioms for geometry hold in Euclidean space.          *)
+(* ========================================================================= *)
+
+needs "Multivariate/convex.ml";;
+
+(* ------------------------------------------------------------------------- *)
+(* Axiom 1 (reflexivity for equidistance).                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let TARSKI_AXIOM_1_EUCLIDEAN = prove
+ (`!a b:real^2. dist(a,b) = dist(b,a)`,
+  NORM_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Axiom 2 (transitivity for equidistance).                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let TARSKI_AXIOM_2_EUCLIDEAN = prove
+ (`!a b p q r s.
+        dist(a,b) = dist(p,q) /\ dist(a,b) = dist(r,s)
+        ==> dist(p,q) = dist(r,s)`,
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Axiom 3 (identity for equidistance).                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let TARSKI_AXIOM_3_EUCLIDEAN = prove
+ (`!a b c. dist(a,b) = dist(c,c) ==> a = b`,
+  NORM_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Axiom 4 (segment construction).                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let TARSKI_AXIOM_4_EUCLIDEAN = prove
+ (`!a q b c:real^2. ?x:real^2. between a (q,x) /\ dist(a,x) = dist(b,c)`,
+  GEOM_ORIGIN_TAC `a:real^2` THEN REPEAT GEN_TAC THEN
+  REWRITE_TAC[DIST_0] THEN ASM_CASES_TAC `q:real^2 = vec 0` THENL
+   [ASM_SIMP_TAC[BETWEEN_REFL; VECTOR_CHOOSE_SIZE; DIST_POS_LE];
+    EXISTS_TAC `--(dist(b:real^2,c) / norm(q) % q):real^2` THEN
+    REWRITE_TAC[between; DIST_0] THEN
+    REWRITE_TAC[dist; NORM_MUL; NORM_NEG; REAL_ABS_DIV; REAL_ABS_NORM;
+                VECTOR_ARITH `q - --(a % q) = (&1 + a) % q`] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC(REAL_RING `a = &1 + b ==> a * q = q + b * q`) THEN
+      SIMP_TAC[REAL_ABS_REFL; REAL_POS; REAL_LE_ADD; REAL_LE_DIV; NORM_POS_LE];
+      ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Axiom 5 (five-segments axiom).                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let TARSKI_AXIOM_5_EUCLIDEAN = prove
+ (`!a b c x:real^2 a' b' c' x':real^2.
+        ~(a = b) /\
+        dist(a,b) = dist(a',b') /\
+        dist(a,c) = dist(a',c') /\
+        dist(b,c) = dist(b',c') /\
+        between b (a,x) /\ between b' (a',x') /\ dist(b,x) = dist(b',x')
+        ==> dist(c,x) = dist(c',x')`,
+  let lemma = prove
+   (`!a b x y:real^N.
+      ~(b = a) /\ between b (a,x) /\ between b (a,y) /\ dist(b,x) = dist(b,y)
+      ==> x = y`,
+    REPEAT STRIP_TAC THEN REPEAT(FIRST_X_ASSUM(MP_TAC o MATCH_MP (REWRITE_RULE
+     [IMP_CONJ] BETWEEN_EXISTS_EXTENSION))) THEN ASM_SIMP_TAC[] THEN
+    REPEAT STRIP_TAC THEN UNDISCH_TAC `dist(b:real^N,x) = dist(b,y)` THEN
+    ASM_REWRITE_TAC[NORM_ARITH `dist(b:real^N,b + x) = norm x`; NORM_MUL] THEN
+    ASM_SIMP_TAC[REAL_EQ_MUL_RCANCEL; NORM_EQ_0; real_abs; VECTOR_SUB_EQ]) in
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`a:real^2`; `b:real^2`; `c:real^2`; `a':real^2`; `b':real^2`; `c':real^2`]
+   RIGID_TRANSFORMATION_BETWEEN_3) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[DIST_EQ_0; DIST_SYM]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real^2`
+   (X_CHOOSE_THEN `f:real^2->real^2` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC))) THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN SUBST_ALL_TAC) THEN
+  SUBGOAL_THEN `x' = k + (f:real^2->real^2) x` SUBST1_TAC THENL
+   [MATCH_MP_TAC lemma THEN MAP_EVERY EXISTS_TAC
+      [`k + (f:real^2->real^2) a`; `k + (f:real^2->real^2) b`];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[NORM_ARITH `dist(a + x:real^N,a + y) = dist(x,y)`;
+    BETWEEN_TRANSLATION; VECTOR_ARITH `a + x:real^N = a + y <=> x = y`] THEN
+  ASM_MESON_TAC[BETWEEN_TRANSLATION; orthogonal_transformation;
+                NORM_ARITH `dist(a + x:real^N,a + y) = dist(x,y)`;
+                ORTHOGONAL_TRANSFORMATION_ISOMETRY; BETWEEN_LINEAR_IMAGE_EQ;
+                DIST_EQ_0; ORTHOGONAL_TRANSFORMATION_INJECTIVE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Axiom 6 (identity for between-ness).                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let TARSKI_AXIOM_6_EUCLIDEAN = prove
+ (`!a b. between b (a,a) ==> a = b`,
+  SIMP_TAC[BETWEEN_REFL_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Axiom 7 (Pasch's axiom).                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let TARSKI_AXIOM_7_EUCLIDEAN = prove
+ (`!a b c p q:real^2.
+        between p (a,c) /\ between q (b,c)
+        ==> ?x. between x (p,b) /\ between x (q,a)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `q:real^2 = c` THENL
+   [ASM_MESON_TAC[BETWEEN_REFL; BETWEEN_SYM]; POP_ASSUM MP_TAC] THEN
+  ASM_CASES_TAC `p:real^2 = a /\ b:real^2 = q` THENL
+   [ASM_MESON_TAC[BETWEEN_REFL; BETWEEN_SYM]; POP_ASSUM MP_TAC] THEN
+  GEOM_ORIGIN_TAC `a:real^2` THEN GEOM_NORMALIZE_TAC `q:real^2` THEN
+  CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[CONJ_SYM] THEN REWRITE_TAC[BETWEEN_REFL_EQ] THEN
+    REWRITE_TAC[UNWIND_THM2; between; DIST_0] THEN NORM_ARITH_TAC;
+    ALL_TAC] THEN
+  GEOM_BASIS_MULTIPLE_TAC 1 `q:real^2` THEN SIMP_TAC
+   [NORM_MUL; NORM_BASIS; real_abs; DIMINDEX_2; ARITH; REAL_MUL_RID] THEN
+  GEN_TAC THEN REPEAT(DISCH_THEN(K ALL_TAC)) THEN SIMP_TAC[VECTOR_MUL_LID] THEN
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[BETWEEN_SYM] THEN DISCH_TAC THEN
+  DISCH_TAC THEN DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC o
+     REWRITE_RULE[BETWEEN_IN_SEGMENT; IN_SEGMENT])
+   (MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ] BETWEEN_EXISTS_EXTENSION))) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `e:real` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[BETWEEN_IN_SEGMENT; IN_SEGMENT] THEN
+  REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+  SUBGOAL_THEN `&0 < &1 - d + e` ASSUME_TAC THENL
+   [ASM_CASES_TAC `d = &1 /\ e = &0` THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o check (is_eq o concl))) THEN
+    ASM_REWRITE_TAC[REAL_SUB_REFL; VECTOR_MUL_LZERO; VECTOR_MUL_RZERO] THEN
+    ASM_REWRITE_TAC[VECTOR_ADD_RID; IMP_IMP];
+    EXISTS_TAC `(&1 - d + e - d * e) / (&1 - d + e) % basis 1:real^2` THEN
+    CONJ_TAC THENL
+     [EXISTS_TAC `e / (&1 - d + e)` THEN
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ] THEN
+      REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+      SIMP_TAC[CART_EQ; DIMINDEX_2; FORALL_2; BASIS_COMPONENT; VEC_COMPONENT;
+       ARITH; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+       VECTOR_SUB_COMPONENT] THEN
+      UNDISCH_TAC `&0 < &1 - d + e` THEN CONV_TAC REAL_FIELD;
+      EXISTS_TAC `(&1 - d + e - d * e) / (&1 - d + e)` THEN
+      ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ] THEN
+      SUBGOAL_THEN `&0 <= (&1 - d) * (&1 + e) /\ &0 <= d * e` MP_TAC THENL
+       [CONJ_TAC THEN MATCH_MP_TAC REAL_LE_MUL; ALL_TAC] THEN
+      ASM_REAL_ARITH_TAC]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Axiom 8 (lower 2-dimensional axiom).                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let TARSKI_AXIOM_8_EUCLIDEAN = prove
+ (`?a b c:real^2. ~between b (a,c) /\ ~between c (b,a) /\ ~between a (c,b)`,
+  REWRITE_TAC[GSYM DE_MORGAN_THM] THEN ONCE_REWRITE_TAC[BETWEEN_SYM] THEN
+  REWRITE_TAC[GSYM COLLINEAR_BETWEEN_CASES; COLLINEAR_3_2D] THEN
+  MAP_EVERY EXISTS_TAC
+   [`vec 0:real^2`; `basis 1:real^2`; `basis 2:real^2`] THEN
+  SIMP_TAC[BASIS_COMPONENT; VEC_COMPONENT; DIMINDEX_2; ARITH] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+(* ------------------------------------------------------------------------- *)
+(* Axiom 9 (upper 2-dimensional axiom).                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let TARSKI_AXIOM_9_EUCLIDEAN = prove
+ (`!p q a b c:real^2.
+        ~(p = q) /\
+        dist(a,p) = dist(a,q) /\ dist(b,p) = dist(b,q) /\ dist(c,p) = dist(c,q)
+        ==> between b (a,c) \/ between c (b,a) \/ between a (c,b)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[BETWEEN_SYM] THEN
+  REWRITE_TAC[GSYM COLLINEAR_BETWEEN_CASES] THEN
+  REWRITE_TAC[dist; NORM_EQ; NORM_ARITH
+    `~(p = q) <=> ~(norm(p - q) = &0)`] THEN
+  ONCE_REWRITE_TAC[REAL_RING `~(x = &0) <=> ~(x pow 2 = &0)`] THEN
+  REWRITE_TAC[NORM_POW_2; COLLINEAR_3_2D] THEN
+  REWRITE_TAC[DOT_2; VECTOR_SUB_COMPONENT] THEN
+  CONV_TAC REAL_FIELD);;
+
+(* ------------------------------------------------------------------------- *)
+(* Axiom 10 (Euclidean axiom).                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let TARSKI_AXIOM_10_EUCLIDEAN = prove
+ (`!a b c d t:real^N.
+        between d (a,t) /\ between d (b,c) /\ ~(a = d)
+        ==> ?x y. between b (a,x) /\ between c (a,y) /\ between t (x,y)`,
+  REPEAT GEN_TAC THEN GEOM_ORIGIN_TAC `a:real^N` THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`vec 0:real^N`; `d:real^N`; `t:real^N`]
+        BETWEEN_EXISTS_EXTENSION) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; VECTOR_ARITH
+   `d + u % (d - vec 0):real^N = (&1 + u) % d`] THEN
+  X_GEN_TAC `u:real` THEN STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`(&1 + u) % b:real^N`; `(&1 + u) % c:real^N`] THEN
+  ASM_REWRITE_TAC[between; dist; GSYM VECTOR_SUB_LDISTRIB] THEN
+  ASM_REWRITE_TAC[VECTOR_SUB_LZERO; NORM_NEG;
+                  VECTOR_ARITH `b - (&1 + u) % b:real^N = --(u % b)`] THEN
+  ASM_SIMP_TAC[NORM_MUL; REAL_LE_ADD; REAL_POS; real_abs] THEN
+  REWRITE_TAC[GSYM REAL_ADD_LDISTRIB; REAL_EQ_MUL_LCANCEL] THEN
+  ASM_REWRITE_TAC[GSYM dist; GSYM between] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Axiom 11 (Continuity).                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let TARSKI_AXIOM_11_EUCLIDEAN = prove
+ (`!X Y:real^2->bool.
+        (?a. !x y. x IN X /\ y IN Y ==> between x (a,y))
+        ==> (?b. !x y. x IN X /\ y IN Y ==> between b (x,y))`,
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN GEOM_ORIGIN_TAC `a:real^2` THEN
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `!x:real^2. x IN X ==> x = vec 0` THENL
+   [ASM_MESON_TAC[BETWEEN_REFL]; POP_ASSUM MP_TAC] THEN
+  ASM_CASES_TAC `Y:real^2->bool = {}` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN
+  SUBGOAL_THEN `?c:real^2. c IN Y` (CHOOSE_THEN MP_TAC) THENL
+   [ASM SET_TAC[]; REPEAT(POP_ASSUM MP_TAC)] THEN
+  GEOM_BASIS_MULTIPLE_TAC 1 `c:real^2` THEN
+  X_GEN_TAC `c:real` THEN DISCH_TAC THEN REPEAT GEN_TAC THEN
+  DISCH_TAC THEN DISCH_TAC THEN REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real^2` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(LABEL_TAC "*") THEN
+  SUBGOAL_THEN `X SUBSET IMAGE (\c. c % basis 1:real^2) {c | &0 <= c} /\
+                Y SUBSET IMAGE (\c. c % basis 1:real^2) {c | &0 <= c}`
+  MP_TAC THENL
+   [REWRITE_TAC[SUBSET; IN_IMAGE; IN_ELIM_THM] THEN
+    MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+     [X_GEN_TAC `x:real^2` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+       [`x:real^2`; `c % basis 1:real^2`]) THEN
+      ASM_REWRITE_TAC[BETWEEN_IN_SEGMENT; IN_SEGMENT] THEN
+      REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID; IN_ELIM_THM] THEN
+      ASM_MESON_TAC[VECTOR_MUL_ASSOC; REAL_LE_MUL];
+      DISCH_THEN(MP_TAC o SPEC `z:real^2`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+      UNDISCH_TAC `~(z:real^2 = vec 0)` THEN
+      ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; DE_MORGAN_THM] THEN
+      STRIP_TAC THEN X_GEN_TAC `y:real^2` THEN DISCH_TAC THEN
+      REMOVE_THEN "*" (MP_TAC o SPECL [`z:real^2`; `y:real^2`]) THEN
+      ASM_REWRITE_TAC[VECTOR_MUL_ASSOC] THEN
+      REWRITE_TAC[BETWEEN_IN_SEGMENT; IN_SEGMENT] THEN
+      REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID; IN_ELIM_THM] THEN
+      DISCH_THEN(X_CHOOSE_THEN `u:real` MP_TAC) THEN
+      ASM_CASES_TAC `u = &0` THEN
+      ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_MUL_EQ_0] THEN
+      STRIP_TAC THEN EXISTS_TAC `inv(u) * d:real` THEN
+      ASM_REWRITE_TAC[GSYM VECTOR_MUL_ASSOC] THEN
+      ASM_SIMP_TAC[REAL_LE_MUL; REAL_LE_INV_EQ; VECTOR_MUL_ASSOC] THEN
+      ASM_SIMP_TAC[REAL_MUL_LINV; VECTOR_MUL_LID]];
+    REWRITE_TAC[SUBSET_IMAGE] THEN REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+    DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `s:real->bool` STRIP_ASSUME_TAC)
+     (X_CHOOSE_THEN `t:real->bool` STRIP_ASSUME_TAC)) THEN
+    REMOVE_THEN "*" MP_TAC THEN
+    ASM_REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+    DISCH_THEN(fun th ->
+      EXISTS_TAC `sup s % basis 1 :real^2` THEN MP_TAC th) THEN
+    REWRITE_TAC[between; dist; NORM_ARITH `norm(vec 0 - x) = norm x`] THEN
+    REWRITE_TAC[GSYM VECTOR_SUB_RDISTRIB; NORM_MUL] THEN
+    SIMP_TAC[NORM_BASIS; DIMINDEX_GE_1; LE_REFL; REAL_MUL_RID] THEN
+    ASM_SIMP_TAC[REAL_ARITH
+     `&0 <= x /\ &0 <= y ==> (abs y = abs x + abs(x - y) <=> x <= y)`] THEN
+    DISCH_TAC THEN X_GEN_TAC `x:real` THEN DISCH_TAC THEN
+    X_GEN_TAC `y:real` THEN DISCH_TAC THEN MATCH_MP_TAC(REAL_ARITH
+     `x <= s /\ s <= y ==> abs(x - y) = abs(x - s) + abs(s - y)`) THEN
+    MP_TAC(SPEC `s:real->bool` SUP) THEN
+    ASM_MESON_TAC[IMAGE_EQ_EMPTY; MEMBER_NOT_EMPTY]]);;
diff --git a/Multivariate/topology.ml b/Multivariate/topology.ml
new file mode 100644 (file)
index 0000000..cc11bb9
--- /dev/null
@@ -0,0 +1,17240 @@
+(* ========================================================================= *)
+(* Elementary topology in Euclidean space.                                   *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(*              (c) Copyright, Valentina Bruno 2010                          *)
+(* ========================================================================= *)
+
+needs "Library/card.ml";;
+needs "Multivariate/determinants.ml";;
+
+(* ------------------------------------------------------------------------- *)
+(* General notion of a topology.                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let istopology = new_definition
+ `istopology L <=>
+        {} IN L /\
+        (!s t. s IN L /\ t IN L ==> (s INTER t) IN L) /\
+        (!k. k SUBSET L ==> (UNIONS k) IN L)`;;
+
+let topology_tybij_th = prove
+ (`?t:(A->bool)->bool. istopology t`,
+  EXISTS_TAC `UNIV:(A->bool)->bool` THEN REWRITE_TAC[istopology; IN_UNIV]);;
+
+let topology_tybij =
+  new_type_definition "topology" ("topology","open_in") topology_tybij_th;;
+
+let ISTOPOLOGY_OPEN_IN = prove
+ (`istopology(open_in top)`,
+  MESON_TAC[topology_tybij]);;
+
+let TOPOLOGY_EQ = prove
+ (`!top1 top2. top1 = top2 <=> !s. open_in top1 s <=> open_in top2 s`,
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC RAND_CONV [GSYM FUN_EQ_THM] THEN
+  REWRITE_TAC[ETA_AX] THEN MESON_TAC[topology_tybij]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Infer the "universe" from union of all sets in the topology.              *)
+(* ------------------------------------------------------------------------- *)
+
+let topspace = new_definition
+ `topspace top = UNIONS {s | open_in top s}`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Main properties of open sets.                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let OPEN_IN_CLAUSES = prove
+ (`!top:(A)topology.
+        open_in top {} /\
+        (!s t. open_in top s /\ open_in top t ==> open_in top (s INTER t)) /\
+        (!k. (!s. s IN k ==> open_in top s) ==> open_in top (UNIONS k))`,
+  SIMP_TAC[IN; SUBSET; SIMP_RULE[istopology; IN; SUBSET] ISTOPOLOGY_OPEN_IN]);;
+
+let OPEN_IN_SUBSET = prove
+ (`!top s. open_in top s ==> s SUBSET (topspace top)`,
+  REWRITE_TAC[topspace] THEN SET_TAC[]);;
+
+let OPEN_IN_EMPTY = prove
+ (`!top. open_in top {}`,
+  REWRITE_TAC[OPEN_IN_CLAUSES]);;
+
+let OPEN_IN_INTER = prove
+ (`!top s t. open_in top s /\ open_in top t ==> open_in top (s INTER t)`,
+  REWRITE_TAC[OPEN_IN_CLAUSES]);;
+
+let OPEN_IN_UNIONS = prove
+ (`!top k. (!s. s IN k ==> open_in top s) ==> open_in top (UNIONS k)`,
+  REWRITE_TAC[OPEN_IN_CLAUSES]);;
+
+let OPEN_IN_UNION = prove
+ (`!top s t. open_in top s /\ open_in top t ==> open_in top (s UNION t)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM UNIONS_2] THEN
+  MATCH_MP_TAC OPEN_IN_UNIONS THEN ASM SET_TAC[]);;
+
+let OPEN_IN_TOPSPACE = prove
+ (`!top. open_in top (topspace top)`,
+  SIMP_TAC[topspace; OPEN_IN_UNIONS; IN_ELIM_THM]);;
+
+let OPEN_IN_INTERS = prove
+ (`!top s:(A->bool)->bool.
+        FINITE s /\ ~(s = {}) /\ (!t. t IN s ==> open_in top t)
+        ==> open_in top (INTERS s)`,
+  GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[INTERS_INSERT; IMP_IMP; NOT_INSERT_EMPTY; FORALL_IN_INSERT] THEN
+  MAP_EVERY X_GEN_TAC [`s:A->bool`; `f:(A->bool)->bool`] THEN
+  ASM_CASES_TAC `f:(A->bool)->bool = {}` THEN
+  ASM_SIMP_TAC[INTERS_0; INTER_UNIV] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC OPEN_IN_INTER THEN ASM_SIMP_TAC[]);;
+
+let OPEN_IN_SUBOPEN = prove
+ (`!top s:A->bool.
+        open_in top s <=>
+        !x. x IN s ==> ?t. open_in top t /\ x IN t /\ t SUBSET s`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL [MESON_TAC[SUBSET_REFL]; ALL_TAC] THEN
+  REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+  REWRITE_TAC[TAUT `a ==> b /\ c <=> (a ==> b) /\ (a ==> c)`] THEN
+  REWRITE_TAC[FORALL_AND_THM; LEFT_IMP_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[GSYM FORALL_IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP OPEN_IN_UNIONS) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Closed sets.                                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let closed_in = new_definition
+ `closed_in top s <=>
+        s SUBSET (topspace top) /\ open_in top (topspace top DIFF s)`;;
+
+let CLOSED_IN_SUBSET = prove
+ (`!top s. closed_in top s ==> s SUBSET (topspace top)`,
+  MESON_TAC[closed_in]);;
+
+let CLOSED_IN_EMPTY = prove
+ (`!top. closed_in top {}`,
+  REWRITE_TAC[closed_in; EMPTY_SUBSET; DIFF_EMPTY; OPEN_IN_TOPSPACE]);;
+
+let CLOSED_IN_TOPSPACE = prove
+ (`!top. closed_in top (topspace top)`,
+  REWRITE_TAC[closed_in; SUBSET_REFL; DIFF_EQ_EMPTY; OPEN_IN_EMPTY]);;
+
+let CLOSED_IN_UNION = prove
+ (`!top s t. closed_in top s /\ closed_in top t ==> closed_in top (s UNION t)`,
+  SIMP_TAC[closed_in; UNION_SUBSET; OPEN_IN_INTER;
+           SET_RULE `u DIFF (s UNION t) = (u DIFF s) INTER (u DIFF t)`]);;
+
+let CLOSED_IN_INTERS = prove
+ (`!top k:(A->bool)->bool.
+        ~(k = {}) /\ (!s. s IN k ==> closed_in top s)
+        ==> closed_in top (INTERS k)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[closed_in] THEN REPEAT STRIP_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `topspace top DIFF INTERS k :A->bool =
+                UNIONS {topspace top DIFF s | s IN k}` SUBST1_TAC
+  THENL [ALL_TAC; MATCH_MP_TAC OPEN_IN_UNIONS THEN ASM SET_TAC[]] THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+  REWRITE_TAC[IN_UNIONS; IN_INTERS; IN_DIFF; EXISTS_IN_IMAGE] THEN
+  MESON_TAC[]);;
+
+let CLOSED_IN_INTER = prove
+ (`!top s t. closed_in top s /\ closed_in top t ==> closed_in top (s INTER t)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM INTERS_2] THEN
+  MATCH_MP_TAC CLOSED_IN_INTERS THEN ASM SET_TAC[]);;
+
+let OPEN_IN_CLOSED_IN_EQ = prove
+ (`!top s. open_in top s <=>
+           s SUBSET topspace top /\ closed_in top (topspace top DIFF s)`,
+  REWRITE_TAC[closed_in; SET_RULE `(u DIFF s) SUBSET u`] THEN
+  REWRITE_TAC[SET_RULE `u DIFF (u DIFF s) = u INTER s`] THEN
+  MESON_TAC[OPEN_IN_SUBSET; SET_RULE `s SUBSET t ==> t INTER s = s`]);;
+
+let OPEN_IN_CLOSED_IN = prove
+ (`!s. s SUBSET topspace top
+       ==> (open_in top s <=> closed_in top (topspace top DIFF s))`,
+  SIMP_TAC[OPEN_IN_CLOSED_IN_EQ]);;
+
+let OPEN_IN_DIFF = prove
+ (`!top s t:A->bool.
+      open_in top s /\ closed_in top t ==> open_in top (s DIFF t)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `s DIFF t :A->bool = s INTER (topspace top DIFF t)`
+  SUBST1_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o MATCH_MP OPEN_IN_SUBSET) THEN SET_TAC[];
+    MATCH_MP_TAC OPEN_IN_INTER THEN ASM_MESON_TAC[closed_in]]);;
+
+let CLOSED_IN_DIFF = prove
+ (`!top s t:A->bool.
+        closed_in top s /\ open_in top t ==> closed_in top (s DIFF t)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `s DIFF t :A->bool = s INTER (topspace top DIFF t)`
+  SUBST1_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o MATCH_MP CLOSED_IN_SUBSET) THEN SET_TAC[];
+    MATCH_MP_TAC CLOSED_IN_INTER THEN ASM_MESON_TAC[OPEN_IN_CLOSED_IN_EQ]]);;
+
+let CLOSED_IN_UNIONS = prove
+ (`!top s. FINITE s /\ (!t. t IN s ==> closed_in top t)
+           ==> closed_in top (UNIONS s)`,
+  GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[UNIONS_INSERT; UNIONS_0; CLOSED_IN_EMPTY; IN_INSERT] THEN
+  MESON_TAC[CLOSED_IN_UNION]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Subspace topology.                                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let subtopology = new_definition
+ `subtopology top u = topology {s INTER u | open_in top s}`;;
+
+let ISTOPLOGY_SUBTOPOLOGY = prove
+ (`!top u:A->bool. istopology {s INTER u | open_in top s}`,
+  REWRITE_TAC[istopology; SET_RULE
+   `{s INTER u | open_in top s} =
+    IMAGE (\s. s INTER u) {s | open_in top s}`] THEN
+  REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[SUBSET_IMAGE; IN_IMAGE; IN_ELIM_THM; SUBSET] THEN
+  REPEAT GEN_TAC THEN REPEAT CONJ_TAC THENL
+   [EXISTS_TAC `{}:A->bool` THEN REWRITE_TAC[OPEN_IN_EMPTY; INTER_EMPTY];
+    SIMP_TAC[SET_RULE `(s INTER u) INTER t INTER u = (s INTER t) INTER u`] THEN
+    ASM_MESON_TAC[OPEN_IN_INTER];
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`f:(A->bool)->bool`; `g:(A->bool)->bool`] THEN
+    STRIP_TAC THEN EXISTS_TAC `UNIONS g :A->bool` THEN
+    ASM_SIMP_TAC[OPEN_IN_UNIONS; INTER_UNIONS] THEN SET_TAC[]]);;
+
+let OPEN_IN_SUBTOPOLOGY = prove
+ (`!top u s. open_in (subtopology top u) s <=>
+                ?t. open_in top t /\ s = t INTER u`,
+  REWRITE_TAC[subtopology] THEN
+  SIMP_TAC[REWRITE_RULE[CONJUNCT2 topology_tybij] ISTOPLOGY_SUBTOPOLOGY] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM]);;
+
+let TOPSPACE_SUBTOPOLOGY = prove
+ (`!top u. topspace(subtopology top u) = topspace top INTER u`,
+  REWRITE_TAC[topspace; OPEN_IN_SUBTOPOLOGY; INTER_UNIONS] THEN
+  REPEAT STRIP_TAC THEN AP_TERM_TAC THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN REWRITE_TAC[IN_ELIM_THM]);;
+
+let CLOSED_IN_SUBTOPOLOGY = prove
+ (`!top u s. closed_in (subtopology top u) s <=>
+                ?t:A->bool. closed_in top t /\ s = t INTER u`,
+  REWRITE_TAC[closed_in; TOPSPACE_SUBTOPOLOGY] THEN
+  REWRITE_TAC[SUBSET_INTER; OPEN_IN_SUBTOPOLOGY; RIGHT_AND_EXISTS_THM] THEN
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:A->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `topspace top DIFF t :A->bool` THEN
+  ASM_SIMP_TAC[CLOSED_IN_TOPSPACE; OPEN_IN_DIFF; CLOSED_IN_DIFF;
+               OPEN_IN_TOPSPACE] THEN
+  ASM SET_TAC[]);;
+
+let OPEN_IN_SUBTOPOLOGY_EMPTY = prove
+ (`!top s. open_in (subtopology top {}) s <=> s = {}`,
+  REWRITE_TAC[OPEN_IN_SUBTOPOLOGY; INTER_EMPTY] THEN
+  MESON_TAC[OPEN_IN_EMPTY]);;
+
+let CLOSED_IN_SUBTOPOLOGY_EMPTY = prove
+ (`!top s. closed_in (subtopology top {}) s <=> s = {}`,
+  REWRITE_TAC[CLOSED_IN_SUBTOPOLOGY; INTER_EMPTY] THEN
+  MESON_TAC[CLOSED_IN_EMPTY]);;
+
+let OPEN_IN_SUBTOPOLOGY_REFL = prove
+ (`!top u:A->bool. open_in (subtopology top u) u <=> u SUBSET topspace top`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_IN_SUBTOPOLOGY] THEN EQ_TAC THENL
+   [REPEAT STRIP_TAC THEN ONCE_ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(SET_RULE `s SUBSET u ==> s INTER t SUBSET u`) THEN
+    ASM_SIMP_TAC[OPEN_IN_SUBSET];
+    DISCH_TAC THEN EXISTS_TAC `topspace top:A->bool` THEN
+    REWRITE_TAC[OPEN_IN_TOPSPACE] THEN ASM SET_TAC[]]);;
+
+let CLOSED_IN_SUBTOPOLOGY_REFL = prove
+ (`!top u:A->bool. closed_in (subtopology top u) u <=> u SUBSET topspace top`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[CLOSED_IN_SUBTOPOLOGY] THEN EQ_TAC THENL
+   [REPEAT STRIP_TAC THEN ONCE_ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(SET_RULE `s SUBSET u ==> s INTER t SUBSET u`) THEN
+    ASM_SIMP_TAC[CLOSED_IN_SUBSET];
+    DISCH_TAC THEN EXISTS_TAC `topspace top:A->bool` THEN
+    REWRITE_TAC[CLOSED_IN_TOPSPACE] THEN ASM SET_TAC[]]);;
+
+let SUBTOPOLOGY_SUPERSET = prove
+ (`!top s:A->bool. topspace top SUBSET s ==> subtopology top s = top`,
+  REPEAT GEN_TAC THEN SIMP_TAC[TOPOLOGY_EQ; OPEN_IN_SUBTOPOLOGY] THEN
+  DISCH_TAC THEN X_GEN_TAC `u:A->bool` THEN EQ_TAC THENL
+   [DISCH_THEN(CHOOSE_THEN(CONJUNCTS_THEN2 MP_TAC SUBST1_TAC)) THEN
+    DISCH_THEN(fun th -> MP_TAC th THEN
+      ASSUME_TAC(MATCH_MP OPEN_IN_SUBSET th)) THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN ASM SET_TAC[];
+    DISCH_TAC THEN EXISTS_TAC `u:A->bool` THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP OPEN_IN_SUBSET) THEN ASM SET_TAC[]]);;
+
+let SUBTOPOLOGY_TOPSPACE = prove
+ (`!top. subtopology top (topspace top) = top`,
+  SIMP_TAC[SUBTOPOLOGY_SUPERSET; SUBSET_REFL]);;
+
+let SUBTOPOLOGY_UNIV = prove
+ (`!top. subtopology top UNIV = top`,
+  SIMP_TAC[SUBTOPOLOGY_SUPERSET; SUBSET_UNIV]);;
+
+let OPEN_IN_IMP_SUBSET = prove
+ (`!top s t. open_in (subtopology top s) t ==> t SUBSET s`,
+  REWRITE_TAC[OPEN_IN_SUBTOPOLOGY] THEN SET_TAC[]);;
+
+let CLOSED_IN_IMP_SUBSET = prove
+ (`!top s t. closed_in (subtopology top s) t ==> t SUBSET s`,
+  REWRITE_TAC[closed_in; TOPSPACE_SUBTOPOLOGY] THEN SET_TAC[]);;
+
+let OPEN_IN_SUBTOPOLOGY_UNION = prove
+ (`!top s t u:A->bool.
+        open_in (subtopology top t) s /\ open_in (subtopology top u) s
+        ==> open_in (subtopology top (t UNION u)) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_IN_SUBTOPOLOGY] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `s':A->bool` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `t':A->bool` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `s' INTER t':A->bool` THEN ASM_SIMP_TAC[OPEN_IN_INTER] THEN
+  ASM SET_TAC[]);;
+
+let CLOSED_IN_SUBTOPOLOGY_UNION = prove
+ (`!top s t u:A->bool.
+        closed_in (subtopology top t) s /\ closed_in (subtopology top u) s
+        ==> closed_in (subtopology top (t UNION u)) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[CLOSED_IN_SUBTOPOLOGY] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `s':A->bool` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `t':A->bool` STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `s' INTER t':A->bool` THEN ASM_SIMP_TAC[CLOSED_IN_INTER] THEN
+  ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The universal Euclidean versions are what we use most of the time.        *)
+(* ------------------------------------------------------------------------- *)
+
+let open_def = new_definition
+  `open s <=> !x. x IN s ==> ?e. &0 < e /\ !x'. dist(x',x) < e ==> x' IN s`;;
+
+let closed = new_definition
+  `closed(s:real^N->bool) <=> open(UNIV DIFF s)`;;
+
+let euclidean = new_definition
+ `euclidean = topology open`;;
+
+let OPEN_EMPTY = prove
+ (`open {}`,
+  REWRITE_TAC[open_def; NOT_IN_EMPTY]);;
+
+let OPEN_UNIV = prove
+ (`open(:real^N)`,
+  REWRITE_TAC[open_def; IN_UNIV] THEN MESON_TAC[REAL_LT_01]);;
+
+let OPEN_INTER = prove
+ (`!s t. open s /\ open t ==> open (s INTER t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[open_def; AND_FORALL_THM; IN_INTER] THEN
+  MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_TAC `d1:real`) (X_CHOOSE_TAC `d2:real`)) THEN
+  MP_TAC(SPECL [`d1:real`; `d2:real`] REAL_DOWN2) THEN
+  ASM_MESON_TAC[REAL_LT_TRANS]);;
+
+let OPEN_UNIONS = prove
+ (`(!s. s IN f ==> open s) ==> open(UNIONS f)`,
+  REWRITE_TAC[open_def; IN_UNIONS] THEN MESON_TAC[]);;
+
+let OPEN_EXISTS_IN = prove
+ (`!P Q:A->real^N->bool.
+        (!a. P a ==> open {x | Q a x}) ==> open {x | ?a. P a /\ Q a x}`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `open(UNIONS {{x | Q (a:A) (x:real^N)} | P a})` MP_TAC THENL
+   [MATCH_MP_TAC OPEN_UNIONS THEN ASM_REWRITE_TAC[FORALL_IN_GSPEC];
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN REWRITE_TAC[UNIONS_GSPEC] THEN
+    SET_TAC[]]);;
+
+let OPEN_EXISTS = prove
+ (`!Q:A->real^N->bool. (!a. open {x | Q a x}) ==> open {x | ?a. Q a x}`,
+  MP_TAC(ISPEC `\x:A. T` OPEN_EXISTS_IN) THEN REWRITE_TAC[]);;
+
+let OPEN_IN = prove
+ (`!s:real^N->bool. open s <=> open_in euclidean s`,
+  GEN_TAC THEN REWRITE_TAC[euclidean] THEN CONV_TAC SYM_CONV THEN
+  AP_THM_TAC THEN REWRITE_TAC[GSYM(CONJUNCT2 topology_tybij)] THEN
+  REWRITE_TAC[REWRITE_RULE[IN] istopology] THEN
+  REWRITE_TAC[OPEN_EMPTY; OPEN_INTER; SUBSET] THEN
+  MESON_TAC[IN; OPEN_UNIONS]);;
+
+let TOPSPACE_EUCLIDEAN = prove
+ (`topspace euclidean = (:real^N)`,
+  REWRITE_TAC[topspace; EXTENSION; IN_UNIV; IN_UNIONS; IN_ELIM_THM] THEN
+  MESON_TAC[OPEN_UNIV; IN_UNIV; OPEN_IN]);;
+
+let TOPSPACE_EUCLIDEAN_SUBTOPOLOGY = prove
+ (`!s. topspace (subtopology euclidean s) = s`,
+  REWRITE_TAC[TOPSPACE_EUCLIDEAN; TOPSPACE_SUBTOPOLOGY; INTER_UNIV]);;
+
+let OPEN_IN_REFL = prove
+ (`!s:real^N->bool. open_in (subtopology euclidean s) s`,
+  REWRITE_TAC[OPEN_IN_SUBTOPOLOGY_REFL; TOPSPACE_EUCLIDEAN; SUBSET_UNIV]);;
+
+let CLOSED_IN_REFL = prove
+ (`!s:real^N->bool. closed_in (subtopology euclidean s) s`,
+  REWRITE_TAC[CLOSED_IN_SUBTOPOLOGY_REFL; TOPSPACE_EUCLIDEAN; SUBSET_UNIV]);;
+
+let CLOSED_IN = prove
+ (`!s:real^N->bool. closed s <=> closed_in euclidean s`,
+  REWRITE_TAC[closed; closed_in; TOPSPACE_EUCLIDEAN; OPEN_IN; SUBSET_UNIV]);;
+
+let OPEN_UNION = prove
+ (`!s t. open s /\ open t ==> open(s UNION t)`,
+  REWRITE_TAC[OPEN_IN; OPEN_IN_UNION]);;
+
+let OPEN_SUBOPEN = prove
+ (`!s. open s <=> !x. x IN s ==> ?t. open t /\ x IN t /\ t SUBSET s`,
+  REWRITE_TAC[OPEN_IN; GSYM OPEN_IN_SUBOPEN]);;
+
+let CLOSED_EMPTY = prove
+ (`closed {}`,
+  REWRITE_TAC[CLOSED_IN; CLOSED_IN_EMPTY]);;
+
+let CLOSED_UNIV = prove
+ (`closed(UNIV:real^N->bool)`,
+  REWRITE_TAC[CLOSED_IN; GSYM TOPSPACE_EUCLIDEAN; CLOSED_IN_TOPSPACE]);;
+
+let CLOSED_UNION = prove
+ (`!s t. closed s /\ closed t ==> closed(s UNION t)`,
+  REWRITE_TAC[CLOSED_IN; CLOSED_IN_UNION]);;
+
+let CLOSED_INTER = prove
+ (`!s t. closed s /\ closed t ==> closed(s INTER t)`,
+  REWRITE_TAC[CLOSED_IN; CLOSED_IN_INTER]);;
+
+let CLOSED_INTERS = prove
+ (`!f. (!s:real^N->bool. s IN f ==> closed s) ==> closed(INTERS f)`,
+  REWRITE_TAC[CLOSED_IN] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THEN
+  ASM_SIMP_TAC[CLOSED_IN_INTERS; INTERS_0] THEN
+  REWRITE_TAC[GSYM TOPSPACE_EUCLIDEAN; CLOSED_IN_TOPSPACE]);;
+
+let CLOSED_FORALL_IN = prove
+ (`!P Q:A->real^N->bool.
+        (!a. P a ==> closed {x | Q a x}) ==> closed {x | !a. P a ==> Q a x}`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `closed(INTERS {{x | Q (a:A) (x:real^N)} | P a})` MP_TAC THENL
+   [MATCH_MP_TAC CLOSED_INTERS THEN ASM_REWRITE_TAC[FORALL_IN_GSPEC];
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN REWRITE_TAC[INTERS_GSPEC] THEN
+    SET_TAC[]]);;
+
+let CLOSED_FORALL = prove
+ (`!Q:A->real^N->bool. (!a. closed {x | Q a x}) ==> closed {x | !a. Q a x}`,
+  MP_TAC(ISPEC `\x:A. T` CLOSED_FORALL_IN) THEN REWRITE_TAC[]);;
+
+let OPEN_CLOSED = prove
+ (`!s:real^N->bool. open s <=> closed(UNIV DIFF s)`,
+  SIMP_TAC[OPEN_IN; CLOSED_IN; TOPSPACE_EUCLIDEAN; SUBSET_UNIV;
+           OPEN_IN_CLOSED_IN_EQ]);;
+
+let OPEN_DIFF = prove
+ (`!s t. open s /\ closed t ==> open(s DIFF t)`,
+  REWRITE_TAC[OPEN_IN; CLOSED_IN; OPEN_IN_DIFF]);;
+
+let CLOSED_DIFF = prove
+ (`!s t. closed s /\ open t ==> closed(s DIFF t)`,
+  REWRITE_TAC[OPEN_IN; CLOSED_IN; CLOSED_IN_DIFF]);;
+
+let OPEN_INTERS = prove
+ (`!s. FINITE s /\ (!t. t IN s ==> open t) ==> open(INTERS s)`,
+  REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[INTERS_INSERT; INTERS_0; OPEN_UNIV; IN_INSERT] THEN
+  MESON_TAC[OPEN_INTER]);;
+
+let CLOSED_UNIONS = prove
+ (`!s. FINITE s /\ (!t. t IN s ==> closed t) ==> closed(UNIONS s)`,
+  REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[UNIONS_INSERT; UNIONS_0; CLOSED_EMPTY; IN_INSERT] THEN
+  MESON_TAC[CLOSED_UNION]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Open and closed balls and spheres.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let ball = new_definition
+  `ball(x,e) = { y | dist(x,y) < e}`;;
+
+let cball = new_definition
+  `cball(x,e) = { y | dist(x,y) <= e}`;;
+
+let sphere = new_definition
+  `sphere(x,e) = { y | dist(x,y) = e}`;;
+
+let IN_BALL = prove
+ (`!x y e. y IN ball(x,e) <=> dist(x,y) < e`,
+  REWRITE_TAC[ball; IN_ELIM_THM]);;
+
+let IN_CBALL = prove
+ (`!x y e. y IN cball(x,e) <=> dist(x,y) <= e`,
+  REWRITE_TAC[cball; IN_ELIM_THM]);;
+
+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 BALL_SUBSET_CBALL = prove
+ (`!x e. ball(x,e) SUBSET cball(x,e)`,
+  REWRITE_TAC[IN_BALL; IN_CBALL; SUBSET] THEN REAL_ARITH_TAC);;
+
+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 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_BALL = prove
+ (`!x e. open(ball(x,e))`,
+  REWRITE_TAC[open_def; ball; IN_ELIM_THM] THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+  MESON_TAC[REAL_SUB_LT; REAL_LT_SUB_LADD; REAL_ADD_SYM; REAL_LET_TRANS;
+            DIST_TRIANGLE_ALT]);;
+
+let CENTRE_IN_BALL = prove
+ (`!x e. x IN ball(x,e) <=> &0 < e`,
+  MESON_TAC[IN_BALL; DIST_REFL]);;
+
+let OPEN_CONTAINS_BALL = prove
+ (`!s. open s <=> !x. x IN s ==> ?e. &0 < e /\ ball(x,e) SUBSET s`,
+  REWRITE_TAC[open_def; SUBSET; IN_BALL] THEN REWRITE_TAC[DIST_SYM]);;
+
+let OPEN_CONTAINS_BALL_EQ = prove
+ (`!s. open s ==> (!x. x IN s <=> ?e. &0 < e /\ ball(x,e) SUBSET s)`,
+  MESON_TAC[OPEN_CONTAINS_BALL; SUBSET; CENTRE_IN_BALL]);;
+
+let BALL_EQ_EMPTY = prove
+ (`!x e. (ball(x,e) = {}) <=> e <= &0`,
+  REWRITE_TAC[EXTENSION; IN_BALL; NOT_IN_EMPTY; REAL_NOT_LT] THEN
+  MESON_TAC[DIST_POS_LE; REAL_LE_TRANS; DIST_REFL]);;
+
+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)`,
+  MESON_TAC[OPEN_CONTAINS_CBALL; SUBSET; REAL_LT_IMP_LE; CENTRE_IN_CBALL]);;
+
+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]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic "localization" results are handy for connectedness.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let OPEN_IN_OPEN = prove
+ (`!s:real^N->bool u.
+        open_in (subtopology euclidean u) s <=> ?t. open t /\ (s = u INTER t)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[OPEN_IN_SUBTOPOLOGY; GSYM OPEN_IN] THEN
+  REWRITE_TAC[INTER_ACI]);;
+
+let OPEN_IN_INTER_OPEN = prove
+ (`!s t u:real^N->bool.
+        open_in (subtopology euclidean u) s /\ open t
+        ==> open_in (subtopology euclidean u) (s INTER t)`,
+  REWRITE_TAC[OPEN_IN_OPEN] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[INTER_ASSOC] THEN ASM_MESON_TAC[OPEN_INTER]);;
+
+let OPEN_IN_OPEN_INTER = prove
+ (`!u s. open s ==> open_in (subtopology euclidean u) (u INTER s)`,
+  REWRITE_TAC[OPEN_IN_OPEN] THEN MESON_TAC[]);;
+
+let OPEN_OPEN_IN_TRANS = prove
+ (`!s t. open s /\ open t /\ t SUBSET s
+         ==> open_in (subtopology euclidean s) t`,
+  MESON_TAC[OPEN_IN_OPEN_INTER; SET_RULE `t SUBSET s ==> t = s INTER t`]);;
+
+let OPEN_SUBSET = prove
+ (`!s t:real^N->bool.
+        s SUBSET t /\ open s ==> open_in (subtopology euclidean t) s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[OPEN_IN_OPEN] THEN
+  EXISTS_TAC `s:real^N->bool` THEN ASM SET_TAC[]);;
+
+let CLOSED_IN_CLOSED = prove
+ (`!s:real^N->bool u.
+    closed_in (subtopology euclidean u) s <=> ?t. closed t /\ (s = u INTER t)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CLOSED_IN_SUBTOPOLOGY; GSYM CLOSED_IN] THEN
+  REWRITE_TAC[INTER_ACI]);;
+
+let CLOSED_SUBSET_EQ = prove
+ (`!u s:real^N->bool.
+        closed s ==> (closed_in (subtopology euclidean u) s <=> s SUBSET u)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+   [FIRST_ASSUM(MP_TAC o MATCH_MP CLOSED_IN_SUBSET) THEN
+    REWRITE_TAC[TOPSPACE_EUCLIDEAN_SUBTOPOLOGY];
+    REWRITE_TAC[CLOSED_IN_CLOSED] THEN EXISTS_TAC `s:real^N->bool` THEN
+    ASM SET_TAC[]]);;
+
+let CLOSED_IN_INTER_CLOSED = prove
+ (`!s t u:real^N->bool.
+        closed_in (subtopology euclidean u) s /\ closed t
+        ==> closed_in (subtopology euclidean u) (s INTER t)`,
+  REWRITE_TAC[CLOSED_IN_CLOSED] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[INTER_ASSOC] THEN ASM_MESON_TAC[CLOSED_INTER]);;
+
+let CLOSED_IN_CLOSED_INTER = prove
+ (`!u s. closed s ==> closed_in (subtopology euclidean u) (u INTER s)`,
+  REWRITE_TAC[CLOSED_IN_CLOSED] THEN MESON_TAC[]);;
+
+let CLOSED_CLOSED_IN_TRANS = prove
+ (`!s t. closed s /\ closed t /\ t SUBSET s
+         ==> closed_in (subtopology euclidean s) t`,
+  MESON_TAC[CLOSED_IN_CLOSED_INTER; SET_RULE `t SUBSET s ==> t = s INTER t`]);;
+
+let CLOSED_SUBSET = prove
+ (`!s t:real^N->bool.
+        s SUBSET t /\ closed s ==> closed_in (subtopology euclidean t) s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CLOSED_IN_CLOSED] THEN
+  EXISTS_TAC `s:real^N->bool` THEN ASM SET_TAC[]);;
+
+let OPEN_IN_SUBSET_TRANS = prove
+ (`!s t u:real^N->bool.
+        open_in (subtopology euclidean u) s /\ s SUBSET t /\ t SUBSET u
+        ==> open_in (subtopology euclidean t) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_IN_OPEN; LEFT_AND_EXISTS_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SET_TAC[]);;
+
+let CLOSED_IN_SUBSET_TRANS = prove
+ (`!s t u:real^N->bool.
+        closed_in (subtopology euclidean u) s /\ s SUBSET t /\ t SUBSET u
+        ==> closed_in (subtopology euclidean t) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[CLOSED_IN_CLOSED; LEFT_AND_EXISTS_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SET_TAC[]);;
+
+let open_in = prove
+ (`!u s:real^N->bool.
+        open_in (subtopology euclidean u) s <=>
+          s SUBSET u /\
+          !x. x IN s ==> ?e. &0 < e /\
+                             !x'. x' IN u /\ dist(x',x) < e ==> x' IN s`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[OPEN_IN_SUBTOPOLOGY; GSYM OPEN_IN] THEN EQ_TAC THENL
+   [REWRITE_TAC[open_def] THEN ASM SET_TAC[INTER_SUBSET; IN_INTER];
+    ALL_TAC] THEN
+  DISCH_THEN(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] THEN DISCH_THEN(X_CHOOSE_TAC `d:real^N->real`) THEN
+  EXISTS_TAC `UNIONS {b | ?x:real^N. (b = ball(x,d x)) /\ x IN s}` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC OPEN_UNIONS THEN
+    ASM_SIMP_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM; OPEN_BALL];
+    GEN_REWRITE_TAC I [EXTENSION] THEN
+    REWRITE_TAC[IN_INTER; IN_UNIONS; IN_ELIM_THM] THEN
+    ASM_MESON_TAC[SUBSET; DIST_REFL; DIST_SYM; IN_BALL]]);;
+
+let OPEN_IN_CONTAINS_BALL = prove
+ (`!s t:real^N->bool.
+        open_in (subtopology euclidean t) s <=>
+        s SUBSET t /\
+        !x. x IN s ==> ?e. &0 < e /\ ball(x,e) INTER t SUBSET s`,
+  REWRITE_TAC[open_in; INTER; SUBSET; IN_ELIM_THM; IN_BALL] THEN
+  MESON_TAC[DIST_SYM]);;
+
+let OPEN_IN_CONTAINS_CBALL = prove
+ (`!s t:real^N->bool.
+        open_in (subtopology euclidean t) s <=>
+        s SUBSET t /\
+        !x. x IN s ==> ?e. &0 < e /\ cball(x,e) INTER t SUBSET s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_IN_CONTAINS_BALL] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[IN_BALL; IN_INTER; SUBSET; IN_CBALL] THEN
+  MESON_TAC[REAL_ARITH `&0 < e ==> &0 < e / &2 /\ (x <= e / &2 ==> x < e)`;
+            REAL_LT_IMP_LE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* These "transitivity" results are handy too.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let OPEN_IN_TRANS = prove
+ (`!s t u. open_in (subtopology euclidean t) s /\
+           open_in (subtopology euclidean u) t
+           ==> open_in (subtopology euclidean u) s`,
+  ASM_MESON_TAC[OPEN_IN_OPEN; OPEN_IN; OPEN_INTER; INTER_ASSOC]);;
+
+let OPEN_IN_OPEN_TRANS = prove
+ (`!s t. open_in (subtopology euclidean t) s /\ open t ==> open s`,
+  REWRITE_TAC[ONCE_REWRITE_RULE[GSYM SUBTOPOLOGY_UNIV] OPEN_IN] THEN
+  REWRITE_TAC[OPEN_IN_TRANS]);;
+
+let CLOSED_IN_TRANS = prove
+ (`!s t u. closed_in (subtopology euclidean t) s /\
+           closed_in (subtopology euclidean u) t
+           ==> closed_in (subtopology euclidean u) s`,
+  ASM_MESON_TAC[CLOSED_IN_CLOSED; CLOSED_IN; CLOSED_INTER; INTER_ASSOC]);;
+
+let CLOSED_IN_CLOSED_TRANS = prove
+ (`!s t. closed_in (subtopology euclidean t) s /\ closed t ==> closed s`,
+  REWRITE_TAC[ONCE_REWRITE_RULE[GSYM SUBTOPOLOGY_UNIV] CLOSED_IN] THEN
+  REWRITE_TAC[CLOSED_IN_TRANS]);;
+
+let OPEN_IN_SUBTOPOLOGY_INTER_SUBSET = prove
+ (`!s u v. open_in (subtopology euclidean u) (u INTER s) /\ v SUBSET u
+           ==> open_in (subtopology euclidean v) (v INTER s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_IN_OPEN; LEFT_AND_EXISTS_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SET_TAC[]);;
+
+let OPEN_IN_OPEN_EQ = prove
+ (`!s t. open s
+         ==> (open_in (subtopology euclidean s) t <=> open t /\ t SUBSET s)`,
+  MESON_TAC[OPEN_OPEN_IN_TRANS; OPEN_IN_OPEN_TRANS; open_in]);;
+
+let CLOSED_IN_CLOSED_EQ = prove
+ (`!s t. closed s
+         ==> (closed_in (subtopology euclidean s) t <=>
+              closed t /\ t SUBSET s)`,
+  MESON_TAC[CLOSED_CLOSED_IN_TRANS; CLOSED_IN_CLOSED_TRANS; closed_in;
+            TOPSPACE_EUCLIDEAN_SUBTOPOLOGY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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];;
+
+let OPEN_IN_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s t.
+          linear f /\ (!x y. f x = f y ==> x = y)
+          ==> (open_in (subtopology euclidean (IMAGE f t)) (IMAGE f s) <=>
+               open_in (subtopology euclidean t) s)`,
+  REWRITE_TAC[open_in; FORALL_IN_IMAGE; IMP_CONJ; SUBSET] THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP (SET_RULE
+   `(!x y. f x = f y ==> x = y) ==> (!x s. f x IN IMAGE f s <=> x IN s)`)) THEN
+  ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPEC `f:real^M->real^N` LINEAR_BOUNDED_POS) THEN
+  MP_TAC(ISPEC `f:real^M->real^N` LINEAR_INJECTIVE_BOUNDED_BELOW_POS) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `B2:real` THEN STRIP_TAC THEN
+  X_GEN_TAC `B1:real` THEN STRIP_TAC THEN
+  AP_TERM_TAC THEN AP_TERM_TAC THEN
+  GEN_REWRITE_TAC I [FUN_EQ_THM] THEN X_GEN_TAC `x:real^M` THEN
+  REWRITE_TAC[] THEN AP_TERM_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o GSYM o MATCH_MP LINEAR_SUB) THEN
+  ASM_REWRITE_TAC[dist; IMP_IMP] THEN EQ_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THENL
+   [EXISTS_TAC `e / B1:real`; EXISTS_TAC `e * B2:real`] THEN
+  ASM_SIMP_TAC[REAL_LT_MUL; REAL_LT_DIV] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THENL
+   [MATCH_MP_TAC(REAL_ARITH
+     `norm(f x) <= B1 * norm(x) /\ norm(x) * B1 < e ==> norm(f x) < e`) THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ];
+    MATCH_MP_TAC(REAL_ARITH
+     `norm x <= norm (f x :real^N) / B2 /\ norm(f x) / B2 < e
+      ==> norm x < e`) THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LT_LDIV_EQ]]);;
+
+add_linear_invariants [OPEN_IN_INJECTIVE_LINEAR_IMAGE];;
+
+let CLOSED_IN_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s t.
+          linear f /\ (!x y. f x = f y ==> x = y)
+          ==> (closed_in (subtopology euclidean (IMAGE f t)) (IMAGE f s) <=>
+               closed_in (subtopology euclidean t) s)`,
+  REWRITE_TAC[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN
+  GEOM_TRANSFORM_TAC[]);;
+
+add_linear_invariants [CLOSED_IN_INJECTIVE_LINEAR_IMAGE];;
+
+(* ------------------------------------------------------------------------- *)
+(* Connectedness.                                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let connected = new_definition
+  `connected s <=>
+      ~(?e1 e2. open e1 /\ open e2 /\ s SUBSET (e1 UNION e2) /\
+                (e1 INTER e2 INTER s = {}) /\
+                ~(e1 INTER s = {}) /\ ~(e2 INTER s = {}))`;;
+
+let CONNECTED_CLOSED = prove
+ (`!s:real^N->bool.
+        connected s <=>
+        ~(?e1 e2. closed e1 /\ closed e2 /\ s SUBSET (e1 UNION e2) /\
+                  (e1 INTER e2 INTER s = {}) /\
+                  ~(e1 INTER s = {}) /\ ~(e2 INTER s = {}))`,
+  GEN_TAC THEN REWRITE_TAC[connected] THEN AP_TERM_TAC THEN
+  EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `v:real^N->bool`] THEN STRIP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`(:real^N) DIFF v`; `(:real^N) DIFF u`] THEN
+  ASM_REWRITE_TAC[GSYM closed; GSYM OPEN_CLOSED] THEN ASM SET_TAC[]);;
+
+let CONNECTED_OPEN_IN = prove
+ (`!s. connected s <=>
+           ~(?e1 e2.
+                 open_in (subtopology euclidean s) e1 /\
+                 open_in (subtopology euclidean s) e2 /\
+                 s SUBSET e1 UNION e2 /\
+                 e1 INTER e2 = {} /\
+                 ~(e1 = {}) /\
+                 ~(e2 = {}))`,
+  GEN_TAC THEN REWRITE_TAC[connected; OPEN_IN_OPEN] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM; RIGHT_AND_EXISTS_THM] THEN
+  CONV_TAC(ONCE_DEPTH_CONV UNWIND_CONV) THEN
+  AP_TERM_TAC THEN REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+  SET_TAC[]);;
+
+let CONNECTED_OPEN_IN_EQ = prove
+ (`!s. connected s <=>
+           ~(?e1 e2.
+                 open_in (subtopology euclidean s) e1 /\
+                 open_in (subtopology euclidean s) e2 /\
+                 e1 UNION e2 = s /\ e1 INTER e2 = {} /\
+                 ~(e1 = {}) /\ ~(e2 = {}))`,
+  GEN_TAC THEN REWRITE_TAC[CONNECTED_OPEN_IN] THEN
+  AP_TERM_TAC THEN REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[SUBSET_REFL] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[OPEN_IN_CLOSED_IN_EQ;
+   TOPSPACE_EUCLIDEAN_SUBTOPOLOGY]) THEN
+  ASM SET_TAC[]);;
+
+let CONNECTED_CLOSED_IN = prove
+ (`!s. connected s <=>
+           ~(?e1 e2.
+                 closed_in (subtopology euclidean s) e1 /\
+                 closed_in (subtopology euclidean s) e2 /\
+                 s SUBSET e1 UNION e2 /\
+                 e1 INTER e2 = {} /\
+                 ~(e1 = {}) /\
+                 ~(e2 = {}))`,
+  GEN_TAC THEN REWRITE_TAC[CONNECTED_CLOSED; CLOSED_IN_CLOSED] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM; RIGHT_AND_EXISTS_THM] THEN
+  CONV_TAC(ONCE_DEPTH_CONV UNWIND_CONV) THEN
+  AP_TERM_TAC THEN REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+  SET_TAC[]);;
+
+let CONNECTED_CLOSED_IN_EQ = prove
+ (`!s. connected s <=>
+           ~(?e1 e2.
+                 closed_in (subtopology euclidean s) e1 /\
+                 closed_in (subtopology euclidean s) e2 /\
+
+                 e1 UNION e2 = s /\ e1 INTER e2 = {} /\
+                 ~(e1 = {}) /\ ~(e2 = {}))`,
+  GEN_TAC THEN REWRITE_TAC[CONNECTED_CLOSED_IN] THEN
+  AP_TERM_TAC THEN REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+  EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[SUBSET_REFL] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[closed_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY]) THEN
+  ASM SET_TAC[]);;
+
+let CONNECTED_CLOPEN = prove
+ (`!s. connected s <=>
+        !t. open_in (subtopology euclidean s) t /\
+            closed_in (subtopology euclidean s) t ==> t = {} \/ t = s`,
+  GEN_TAC THEN REWRITE_TAC[connected; OPEN_IN_OPEN; CLOSED_IN_CLOSED] THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o BINDER_CONV) [GSYM EXISTS_DIFF] THEN
+  ONCE_REWRITE_TAC[TAUT `(~a <=> b) <=> (a <=> ~b)`] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; GSYM CONJ_ASSOC; DE_MORGAN_THM] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c /\ d <=> b /\ a /\ c /\ d`] THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN REWRITE_TAC[GSYM closed] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN AP_TERM_TAC THEN ABS_TAC THEN
+  REWRITE_TAC[LEFT_AND_EXISTS_THM; RIGHT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN AP_TERM_TAC THEN ABS_TAC THEN
+  REWRITE_TAC[TAUT `(a /\ b) /\ (c /\ d) /\ e <=> a /\ c /\ b /\ d /\ e`] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM2] THEN
+  AP_TERM_TAC THEN AP_TERM_TAC THEN SET_TAC[]);;
+
+let CONNECTED_CLOSED_SET = prove
+ (`!s:real^N->bool.
+        closed s
+        ==> (connected s <=>
+             ~(?e1 e2. closed e1 /\ closed e2 /\ ~(e1 = {}) /\ ~(e2 = {}) /\
+                       e1 UNION e2 = s /\ e1 INTER e2 = {}))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[CONNECTED_CLOSED; CONTRAPOS_THM] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    SIMP_TAC[] THEN SET_TAC[];
+    REWRITE_TAC[CONNECTED_CLOSED_IN; CONTRAPOS_THM; LEFT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[CLOSED_IN_CLOSED; LEFT_IMP_EXISTS_THM; IMP_CONJ] THEN
+    REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN REWRITE_TAC[IMP_IMP] THEN
+    MAP_EVERY X_GEN_TAC
+     [`e1:real^N->bool`; `e2:real^N->bool`;
+      `u:real^N->bool`; `v:real^N->bool`] THEN
+    STRIP_TAC THEN MAP_EVERY (C UNDISCH_THEN SUBST_ALL_TAC)
+     [`e1:real^N->bool = s INTER u`;
+      `e2:real^N->bool = s INTER v`] THEN
+    MAP_EVERY EXISTS_TAC
+     [`s INTER u:real^N->bool`; `s INTER v:real^N->bool`] THEN
+    ASM_SIMP_TAC[CLOSED_INTER] THEN ASM SET_TAC[]]);;
+
+let CONNECTED_OPEN_SET = prove
+ (`!s:real^N->bool.
+        open s
+        ==> (connected s <=>
+             ~(?e1 e2. open e1 /\ open e2 /\ ~(e1 = {}) /\ ~(e2 = {}) /\
+                       e1 UNION e2 = s /\ e1 INTER e2 = {}))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[connected; CONTRAPOS_THM] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    SIMP_TAC[] THEN SET_TAC[];
+    REWRITE_TAC[CONNECTED_OPEN_IN; CONTRAPOS_THM; LEFT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[OPEN_IN_OPEN; LEFT_IMP_EXISTS_THM; IMP_CONJ] THEN
+    REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN REWRITE_TAC[IMP_IMP] THEN
+    MAP_EVERY X_GEN_TAC
+     [`e1:real^N->bool`; `e2:real^N->bool`;
+      `u:real^N->bool`; `v:real^N->bool`] THEN
+    STRIP_TAC THEN MAP_EVERY (C UNDISCH_THEN SUBST_ALL_TAC)
+     [`e1:real^N->bool = s INTER u`;
+      `e2:real^N->bool = s INTER v`] THEN
+    MAP_EVERY EXISTS_TAC
+     [`s INTER u:real^N->bool`; `s INTER v:real^N->bool`] THEN
+    ASM_SIMP_TAC[OPEN_INTER] THEN ASM SET_TAC[]]);;
+
+let CONNECTED_EMPTY = prove
+ (`connected {}`,
+  REWRITE_TAC[connected; INTER_EMPTY]);;
+
+let CONNECTED_SING = prove
+ (`!a. connected{a}`,
+  REWRITE_TAC[connected] THEN SET_TAC[]);;
+
+let CONNECTED_UNIONS = prove
+ (`!P:(real^N->bool)->bool.
+        (!s. s IN P ==> connected s) /\ ~(INTERS P = {})
+        ==> connected(UNIONS P)`,
+  GEN_TAC THEN REWRITE_TAC[connected; NOT_EXISTS_THM] THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`e1:real^N->bool`; `e2:real^N->bool`] THEN
+  STRIP_TAC THEN UNDISCH_TAC `~(INTERS P :real^N->bool = {})` THEN
+  PURE_REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTERS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `(a:real^N) IN e1 \/ a IN e2` STRIP_ASSUME_TAC THENL
+   [ASM SET_TAC[];
+    UNDISCH_TAC `~(e2 INTER UNIONS P:real^N->bool = {})`;
+    UNDISCH_TAC `~(e1 INTER UNIONS P:real^N->bool = {})`] THEN
+  PURE_REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_INTER; IN_UNIONS] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N`
+   (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^N->bool` STRIP_ASSUME_TAC) THEN
+  UNDISCH_TAC `!t:real^N->bool. t IN P ==> a IN t` THEN
+  DISCH_THEN(MP_TAC o SPEC `s:real^N->bool`) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `s:real^N->bool`) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(MP_TAC o SPECL [`e1:real^N->bool`; `e2:real^N->bool`]) THEN
+  ASM SET_TAC[]);;
+
+let CONNECTED_UNION = prove
+ (`!s t:real^N->bool.
+        connected s /\ connected t /\ ~(s INTER t = {})
+        ==> connected (s UNION t)`,
+  REWRITE_TAC[GSYM UNIONS_2; GSYM INTERS_2] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CONNECTED_UNIONS THEN
+  ASM SET_TAC[]);;
+
+let CONNECTED_DIFF_OPEN_FROM_CLOSED = prove
+ (`!s t u:real^N->bool.
+        s SUBSET t /\ t SUBSET u /\
+        open s /\ closed t /\ connected u /\ connected(t DIFF s)
+        ==> connected(u DIFF s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[connected; NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`v:real^N->bool`; `w:real^N->bool`] THEN STRIP_TAC THEN
+  UNDISCH_TAC `connected(t DIFF s:real^N->bool)` THEN SIMP_TAC[connected] THEN
+  MAP_EVERY EXISTS_TAC [`v:real^N->bool`; `w:real^N->bool`] THEN
+  ASM_REWRITE_TAC[] THEN
+  REPLICATE_TAC 2 (CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+  MAP_EVERY (fun t -> SPEC_TAC(t,t)) [`v:real^N->bool`; `w:real^N->bool`] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!v w. P v w ==> P w v) /\ (!w v. P v w /\ Q w ==> F)
+    ==> !w v. P v w ==> ~(Q v) /\ ~(Q w)`) THEN
+  CONJ_TAC THENL [SIMP_TAC[CONJ_ACI; INTER_ACI; UNION_ACI]; ALL_TAC] THEN
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [connected]) THEN SIMP_TAC[] THEN
+  MAP_EVERY EXISTS_TAC [`v UNION s:real^N->bool`; `w DIFF t:real^N->bool`] THEN
+  ASM_SIMP_TAC[OPEN_UNION; OPEN_DIFF] THEN ASM SET_TAC[]);;
+
+let CONNECTED_DISJOINT_UNIONS_OPEN_UNIQUE = prove
+ (`!f:(real^N->bool)->bool f'.
+         pairwise DISJOINT f /\ pairwise DISJOINT f' /\
+        (!s. s IN f ==> open s /\ connected s /\ ~(s = {})) /\
+        (!s. s IN f' ==> open s /\ connected s /\ ~(s = {})) /\
+        UNIONS f = UNIONS f'
+        ==> f = f'`,
+  GEN_REWRITE_TAC (funpow 2 BINDER_CONV o RAND_CONV) [EXTENSION] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!s t. P s t ==> P t s) /\ (!s t x. P s t /\ x IN s ==> x IN t)
+    ==> (!s t. P s t ==> (!x. x IN s <=> x IN t))`) THEN
+  CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  GEN_TAC THEN GEN_TAC THEN X_GEN_TAC `s:real^N->bool` THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?t a:real^N. t IN f' /\ a IN s /\ a IN t` STRIP_ASSUME_TAC
+  THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `s:real^N->bool = t` (fun th -> ASM_REWRITE_TAC[th]) THEN
+  REWRITE_TAC[EXTENSION] THEN POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
+  MAP_EVERY (fun t -> SPEC_TAC(t,t))
+   [`s:real^N->bool`; `t:real^N->bool`;
+    `f:(real^N->bool)->bool`; `f':(real^N->bool)->bool`] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!f f' s t. P f f' s t ==> P f' f t s) /\
+    (!f f' s t x. P f f' s t /\ x IN s ==> x IN t)
+    ==> (!f' f t s. P f f' s t ==> (!x. x IN s <=> x IN t))`) THEN
+  CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  REPLICATE_TAC 4 GEN_TAC THEN X_GEN_TAC `b:real^N` THEN STRIP_TAC THEN
+  UNDISCH_TAC
+   `!s:real^N->bool. s IN f ==> open s /\ connected s /\ ~(s = {})` THEN
+  DISCH_THEN(MP_TAC o SPEC `s:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN
+  STRIP_TAC THEN ASM_CASES_TAC `(b:real^N) IN t` THEN
+  ASM_REWRITE_TAC[] THEN
+  UNDISCH_TAC `connected(s:real^N->bool)` THEN
+  REWRITE_TAC[connected] THEN
+  MAP_EVERY EXISTS_TAC
+   [`t:real^N->bool`; `UNIONS(f' DELETE (t:real^N->bool))`] THEN
+  REPEAT STRIP_TAC THENL
+   [ASM_SIMP_TAC[];
+    MATCH_MP_TAC OPEN_UNIONS THEN ASM_SIMP_TAC[IN_DELETE];
+    REWRITE_TAC[GSYM UNIONS_INSERT] THEN ASM SET_TAC[];
+    MATCH_MP_TAC(SET_RULE `t INTER u = {} ==> t INTER u INTER s = {}`) THEN
+    REWRITE_TAC[INTER_UNIONS; EMPTY_UNIONS; FORALL_IN_GSPEC] THEN
+    REWRITE_TAC[IN_DELETE; GSYM DISJOINT] THEN ASM_MESON_TAC[pairwise];
+    ASM SET_TAC[];
+    ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Sort of induction principle for connected sets.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let CONNECTED_INDUCTION = prove
+ (`!P Q s:real^N->bool.
+        connected s /\
+        (!t a. open_in (subtopology euclidean s) t /\ a IN t
+               ==> ?z. z IN t /\ P z) /\
+        (!a. a IN s
+             ==> ?t. open_in (subtopology euclidean s) t /\ a IN t /\
+                     !x y. x IN t /\ y IN t /\ P x /\ P y /\ Q x ==> Q y)
+        ==> !a b. a IN s /\ b IN s /\ P a /\ P b /\ Q a ==> Q b`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC I [TAUT `p <=> ~ ~p`] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONNECTED_OPEN_IN]) THEN
+  REWRITE_TAC[] THEN MAP_EVERY EXISTS_TAC
+   [`{b:real^N | ?t. open_in (subtopology euclidean s) t /\ b IN t /\
+                     !x. x IN t /\ P x ==> Q x}`;
+    `{b:real^N | ?t. open_in (subtopology euclidean s) t /\ b IN t /\
+                     !x. x IN t /\ P x ==> ~(Q x)}`] THEN
+  REPEAT CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN
+    X_GEN_TAC `c:real^N` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN ASM SET_TAC[];
+    ONCE_REWRITE_TAC[OPEN_IN_SUBOPEN] THEN
+    X_GEN_TAC `c:real^N` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN ASM SET_TAC[];
+    REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_UNION] THEN
+    X_GEN_TAC `c:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `c:real^N`) THEN ASM SET_TAC[];
+    REWRITE_TAC[EXTENSION; IN_INTER; NOT_IN_EMPTY; IN_ELIM_THM] THEN
+    X_GEN_TAC `c:real^N` THEN DISCH_THEN(CONJUNCTS_THEN2
+     (X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC)
+     (X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC)) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`t INTER u:real^N->bool`; `c:real^N`]) THEN
+    ASM_SIMP_TAC[OPEN_IN_INTER] THEN ASM SET_TAC[];
+    ASM SET_TAC[];
+    ASM SET_TAC[]]);;
+
+let CONNECTED_EQUIVALENCE_RELATION_GEN = prove
+ (`!P R s:real^N->bool.
+        connected s /\
+        (!x y. R x y ==> R y x) /\
+        (!x y z. R x y /\ R y z ==> R x z) /\
+        (!t a. open_in (subtopology euclidean s) t /\ a IN t
+               ==> ?z. z IN t /\ P z) /\
+        (!a. a IN s
+             ==> ?t. open_in (subtopology euclidean s) t /\ a IN t /\
+                     !x y. x IN t /\ y IN t /\ P x /\ P y ==> R x y)
+        ==> !a b. a IN s /\ b IN s /\ P a /\ P b ==> R a b`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!a:real^N. a IN s /\ P a
+               ==> !b c. b IN s /\ c IN s /\ P b /\ P c /\ R a b ==> R a c`
+  MP_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+  GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC CONNECTED_INDUCTION THEN
+  ASM_MESON_TAC[]);;
+
+let CONNECTED_INDUCTION_SIMPLE = prove
+ (`!P s:real^N->bool.
+        connected s /\
+        (!a. a IN s
+             ==> ?t. open_in (subtopology euclidean s) t /\ a IN t /\
+                     !x y. x IN t /\ y IN t /\ P x ==> P y)
+        ==> !a b. a IN s /\ b IN s /\ P a ==> P b`,
+  MP_TAC(ISPEC `\x:real^N. T` CONNECTED_INDUCTION) THEN
+  REWRITE_TAC[] THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN MESON_TAC[]);;
+
+let CONNECTED_EQUIVALENCE_RELATION = prove
+ (`!R s:real^N->bool.
+        connected s /\
+        (!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. a IN s /\ b IN s ==> R a b`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!a:real^N. a IN s ==> !b c. b IN s /\ c IN s /\ R a b ==> R a c`
+  MP_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+  GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC CONNECTED_INDUCTION_SIMPLE THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Limit points.                                                             *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix ("limit_point_of",(12,"right"));;
+
+let limit_point_of = new_definition
+ `x limit_point_of s <=>
+        !t. x IN t /\ open t ==> ?y. ~(y = x) /\ y IN s /\ y IN t`;;
+
+let LIMPT_SUBSET = prove
+ (`!x s t. x limit_point_of s /\ s SUBSET t ==> x limit_point_of t`,
+  REWRITE_TAC[limit_point_of; SUBSET] THEN MESON_TAC[]);;
+
+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_LIMPT = prove
+ (`!s. closed s <=> !x. x limit_point_of s ==> x IN s`,
+  REWRITE_TAC[closed] THEN ONCE_REWRITE_TAC[OPEN_SUBOPEN] THEN
+  REWRITE_TAC[limit_point_of; IN_DIFF; IN_UNIV; SUBSET] THEN MESON_TAC[]);;
+
+let LIMPT_EMPTY = prove
+ (`!x. ~(x limit_point_of {})`,
+  REWRITE_TAC[LIMPT_APPROACHABLE; NOT_IN_EMPTY] THEN MESON_TAC[REAL_LT_01]);;
+
+let NO_LIMIT_POINT_IMP_CLOSED = prove
+ (`!s. ~(?x. x limit_point_of s) ==> closed s`,
+  MESON_TAC[CLOSED_LIMPT]);;
+
+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})`,
+  SIMP_TAC[LIMIT_POINT_FINITE; FINITE_SING]);;
+
+let LIMIT_POINT_UNION = prove
+ (`!s t x:real^N. x limit_point_of (s UNION t) <=>
+                  x limit_point_of s \/ x limit_point_of t`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [ALL_TAC; MESON_TAC[LIMPT_SUBSET; SUBSET_UNION]] THEN
+  REWRITE_TAC[LIMPT_APPROACHABLE; IN_UNION] THEN DISCH_TAC THEN
+  MATCH_MP_TAC(TAUT `(~a ==> b) ==> a \/ b`) THEN
+  REWRITE_TAC[NOT_FORALL_THM; LEFT_IMP_EXISTS_THM; NOT_IMP] THEN
+  X_GEN_TAC `e:real` THEN STRIP_TAC THEN X_GEN_TAC `d:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `min d e`) THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+  ASM_MESON_TAC[]);;
+
+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}`,
+  REWRITE_TAC[CLOSED_LIMPT; IN_ELIM_THM; LIMPT_OF_LIMPTS]);;
+
+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 = new_definition
+  `interior s = {x | ?t. open t /\ x IN t /\ t SUBSET s}`;;
+
+let INTERIOR_EQ = prove
+ (`!s. (interior s = s) <=> open s`,
+  GEN_TAC THEN REWRITE_TAC[EXTENSION; interior; IN_ELIM_THM] THEN
+  GEN_REWRITE_TAC RAND_CONV [OPEN_SUBOPEN] THEN MESON_TAC[SUBSET]);;
+
+let INTERIOR_OPEN = prove
+ (`!s. open s ==> (interior s = s)`,
+  MESON_TAC[INTERIOR_EQ]);;
+
+let INTERIOR_EMPTY = prove
+ (`interior {} = {}`,
+  SIMP_TAC[INTERIOR_OPEN; OPEN_EMPTY]);;
+
+let INTERIOR_UNIV = prove
+ (`interior(:real^N) = (:real^N)`,
+  SIMP_TAC[INTERIOR_OPEN; OPEN_UNIV]);;
+
+let OPEN_INTERIOR = prove
+ (`!s. open(interior s)`,
+  GEN_TAC THEN REWRITE_TAC[interior] THEN GEN_REWRITE_TAC I [OPEN_SUBOPEN] THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let INTERIOR_INTERIOR = prove
+ (`!s. interior(interior s) = interior s`,
+  MESON_TAC[INTERIOR_EQ; OPEN_INTERIOR]);;
+
+let INTERIOR_SUBSET = prove
+ (`!s. (interior s) SUBSET s`,
+  REWRITE_TAC[SUBSET; interior; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let SUBSET_INTERIOR = prove
+ (`!s t. s SUBSET t ==> (interior s) SUBSET (interior t)`,
+  REWRITE_TAC[interior; SUBSET; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let INTERIOR_MAXIMAL = prove
+ (`!s t. t SUBSET s /\ open t ==> t SUBSET (interior s)`,
+  REWRITE_TAC[interior; SUBSET; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let INTERIOR_MAXIMAL_EQ = prove
+ (`!s t:real^N->bool. open s ==> (s SUBSET interior t <=> s SUBSET t)`,
+  MESON_TAC[INTERIOR_MAXIMAL; SUBSET_TRANS; INTERIOR_SUBSET]);;
+
+let INTERIOR_UNIQUE = prove
+ (`!s t. t SUBSET s /\ open t /\ (!t'. t' SUBSET s /\ open t' ==> t' SUBSET t)
+         ==> (interior s = t)`,
+  MESON_TAC[SUBSET_ANTISYM; INTERIOR_MAXIMAL; INTERIOR_SUBSET;
+            OPEN_INTERIOR]);;
+
+let IN_INTERIOR = prove
+ (`!x s. x IN interior s <=> ?e. &0 < e /\ ball(x,e) SUBSET s`,
+  REWRITE_TAC[interior; IN_ELIM_THM] THEN
+  MESON_TAC[OPEN_CONTAINS_BALL; SUBSET_TRANS; CENTRE_IN_BALL; OPEN_BALL]);;
+
+let OPEN_SUBSET_INTERIOR = prove
+ (`!s t. open s ==> (s SUBSET interior t <=> s SUBSET t)`,
+  MESON_TAC[INTERIOR_MAXIMAL; INTERIOR_SUBSET; SUBSET_TRANS]);;
+
+let INTERIOR_INTER = prove
+ (`!s t:real^N->bool. interior(s INTER t) = interior s INTER interior t`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET_INTER] THEN CONJ_TAC THEN
+    MATCH_MP_TAC SUBSET_INTERIOR THEN REWRITE_TAC[INTER_SUBSET];
+    MATCH_MP_TAC INTERIOR_MAXIMAL THEN SIMP_TAC[OPEN_INTER; OPEN_INTERIOR] THEN
+    MATCH_MP_TAC(SET_RULE
+      `s SUBSET s' /\ t SUBSET t' ==> s INTER t SUBSET s' INTER t'`) THEN
+    REWRITE_TAC[INTERIOR_SUBSET]]);;
+
+let INTERIOR_FINITE_INTERS = prove
+ (`!s:(real^N->bool)->bool.
+        FINITE s ==> interior(INTERS s) = INTERS(IMAGE interior s)`,
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[INTERS_0; INTERS_INSERT; INTERIOR_UNIV; IMAGE_CLAUSES] THEN
+  SIMP_TAC[INTERIOR_INTER]);;
+
+let INTERIOR_INTERS_SUBSET = prove
+ (`!f. interior(INTERS f) SUBSET INTERS (IMAGE interior f)`,
+  REWRITE_TAC[SUBSET; IN_INTERIOR; IN_INTERS; FORALL_IN_IMAGE] THEN
+  MESON_TAC[]);;
+
+let UNION_INTERIOR_SUBSET = prove
+ (`!s t:real^N->bool.
+        interior s UNION interior t SUBSET interior(s UNION t)`,
+  SIMP_TAC[INTERIOR_MAXIMAL_EQ; OPEN_UNION; OPEN_INTERIOR] THEN
+  REPEAT GEN_TAC THEN MATCH_MP_TAC(SET_RULE
+   `s SUBSET s' /\ t SUBSET t' ==> (s UNION t) SUBSET (s' UNION t')`) THEN
+  REWRITE_TAC[INTERIOR_SUBSET]);;
+
+let INTERIOR_EQ_EMPTY = prove
+ (`!s:real^N->bool. interior s = {} <=> !t. open t /\ t SUBSET s ==> t = {}`,
+  MESON_TAC[INTERIOR_MAXIMAL_EQ; SUBSET_EMPTY;
+            OPEN_INTERIOR; INTERIOR_SUBSET]);;
+
+let INTERIOR_EQ_EMPTY_ALT = prove
+ (`!s:real^N->bool.
+        interior s = {} <=>
+        !t. open t /\ ~(t = {}) ==> ~(t DIFF s = {})`,
+  GEN_TAC THEN REWRITE_TAC[INTERIOR_EQ_EMPTY] THEN SET_TAC[]);;
+
+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]);;
+
+let INTERIOR_CLOSED_UNION_EMPTY_INTERIOR = prove
+ (`!s t:real^N->bool.
+        closed(s) /\ interior(t) = {}
+        ==> interior(s UNION t) = interior(s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  SIMP_TAC[SUBSET_INTERIOR; SUBSET_UNION] THEN
+  REWRITE_TAC[SUBSET; IN_INTERIOR; IN_INTER; IN_UNION] THEN
+  X_GEN_TAC `x:real^N` THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `e:real` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `y:real^N` THEN STRIP_TAC THEN
+  SUBGOAL_THEN `(y:real^N) limit_point_of s`
+   (fun th -> ASM_MESON_TAC[CLOSED_LIMPT; th]) THEN
+  REWRITE_TAC[IN_INTERIOR; NOT_IN_EMPTY; LIMPT_APPROACHABLE] THEN
+  X_GEN_TAC `d:real` THEN DISCH_TAC THEN
+  SUBGOAL_THEN
+   `?z:real^N. ~(z IN t) /\ ~(z = y) /\ dist(z,y) < d /\ dist(x,z) < e`
+   (fun th -> ASM_MESON_TAC[th; IN_BALL]) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_BALL]) THEN
+  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+  REWRITE_TAC[IN_INTERIOR; NOT_IN_EMPTY; NOT_EXISTS_THM] THEN
+  ABBREV_TAC `k = min d (e - dist(x:real^N,y))` THEN
+  SUBGOAL_THEN `&0 < k` ASSUME_TAC THENL
+   [ASM_ARITH_TAC; ALL_TAC] THEN
+  SUBGOAL_THEN `?w:real^N. dist(y,w) = k / &2` CHOOSE_TAC THENL
+   [ASM_SIMP_TAC[VECTOR_CHOOSE_DIST; REAL_HALF; REAL_LT_IMP_LE]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPECL [`w:real^N`; `k / &4`]) THEN
+  ASM_SIMP_TAC[SUBSET; NOT_FORALL_THM; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH;
+               NOT_IMP; IN_BALL] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `z:real^N` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN ASM_REWRITE_TAC[] THEN
+  ASM_NORM_ARITH_TAC);;
+
+let INTERIOR_UNION_EQ_EMPTY = prove
+ (`!s t:real^N->bool.
+        closed s \/ closed t
+        ==> (interior(s UNION t) = {} <=>
+             interior s = {} /\ interior t = {})`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN EQ_TAC THENL
+   [ASM_MESON_TAC[SUBSET_UNION; SUBSET_INTERIOR; SUBSET_EMPTY];
+    ASM_MESON_TAC[UNION_COMM; INTERIOR_CLOSED_UNION_EMPTY_INTERIOR]]);;
+
+let INTERIOR_UNIONS_OPEN_SUBSETS = prove
+ (`!s:real^N->bool. UNIONS {t | open t /\ t SUBSET s} = interior s`,
+  GEN_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC INTERIOR_UNIQUE THEN
+  SIMP_TAC[OPEN_UNIONS; IN_ELIM_THM] THEN SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Closure of a set.                                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let closure = new_definition
+  `closure s = s UNION {x | x limit_point_of s}`;;
+
+let CLOSURE_INTERIOR = prove
+ (`!s:real^N->bool. closure s = UNIV DIFF (interior (UNIV DIFF s))`,
+  REWRITE_TAC[EXTENSION; closure; IN_UNION; IN_DIFF; IN_UNIV; interior;
+              IN_ELIM_THM; limit_point_of; SUBSET] THEN
+  MESON_TAC[]);;
+
+let INTERIOR_CLOSURE = prove
+ (`!s:real^N->bool. interior s = UNIV DIFF (closure (UNIV DIFF s))`,
+  let lemma = prove(`!s t. UNIV DIFF (UNIV DIFF t) = t`,SET_TAC[]) in
+  REWRITE_TAC[CLOSURE_INTERIOR; lemma]);;
+
+let CLOSED_CLOSURE = prove
+ (`!s. closed(closure s)`,
+  let lemma = prove(`UNIV DIFF (UNIV DIFF s) = s`,SET_TAC[]) in
+  REWRITE_TAC[closed; CLOSURE_INTERIOR; lemma; OPEN_INTERIOR]);;
+
+let CLOSURE_HULL = prove
+ (`!s. closure s = closed hull s`,
+  GEN_TAC THEN MATCH_MP_TAC(GSYM HULL_UNIQUE) THEN
+  REWRITE_TAC[CLOSED_CLOSURE; SUBSET] THEN
+  REWRITE_TAC[closure; IN_UNION; IN_ELIM_THM; CLOSED_LIMPT] THEN
+  MESON_TAC[limit_point_of]);;
+
+let CLOSURE_EQ = prove
+ (`!s. (closure s = s) <=> closed s`,
+  SIMP_TAC[CLOSURE_HULL; HULL_EQ; CLOSED_INTERS]);;
+
+let CLOSURE_CLOSED = prove
+ (`!s. closed s ==> (closure s = s)`,
+  MESON_TAC[CLOSURE_EQ]);;
+
+let CLOSURE_CLOSURE = prove
+ (`!s. closure(closure s) = closure s`,
+  REWRITE_TAC[CLOSURE_HULL; HULL_HULL]);;
+
+let CLOSURE_SUBSET = prove
+ (`!s. s SUBSET (closure s)`,
+  REWRITE_TAC[CLOSURE_HULL; HULL_SUBSET]);;
+
+let SUBSET_CLOSURE = prove
+ (`!s t. s SUBSET t ==> (closure s) SUBSET (closure t)`,
+  REWRITE_TAC[CLOSURE_HULL; HULL_MONO]);;
+
+let CLOSURE_UNION = prove
+ (`!s t:real^N->bool. closure(s UNION t) = closure s UNION closure t`,
+  REWRITE_TAC[LIMIT_POINT_UNION; closure] THEN SET_TAC[]);;
+
+let CLOSURE_INTER_SUBSET = prove
+ (`!s t. closure(s INTER t) SUBSET closure(s) INTER closure(t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[SUBSET_INTER] THEN
+  CONJ_TAC THEN MATCH_MP_TAC SUBSET_CLOSURE THEN SET_TAC[]);;
+
+let CLOSURE_INTERS_SUBSET = prove
+ (`!f. closure(INTERS f) SUBSET INTERS(IMAGE closure f)`,
+  REWRITE_TAC[SET_RULE `s SUBSET INTERS f <=> !t. t IN f ==> s SUBSET t`] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SUBSET_CLOSURE THEN ASM SET_TAC[]);;
+
+let CLOSURE_MINIMAL = prove
+ (`!s t. s SUBSET t /\ closed t ==> (closure s) SUBSET t`,
+  REWRITE_TAC[HULL_MINIMAL; CLOSURE_HULL]);;
+
+let CLOSURE_MINIMAL_EQ = prove
+ (`!s t:real^N->bool. closed t ==> (closure s SUBSET t <=> s SUBSET t)`,
+  MESON_TAC[SUBSET_TRANS; CLOSURE_SUBSET; CLOSURE_MINIMAL]);;
+
+let CLOSURE_UNIQUE = prove
+ (`!s t. s SUBSET t /\ closed t /\
+         (!t'. s SUBSET t' /\ closed t' ==> t SUBSET t')
+         ==> (closure s = t)`,
+  REWRITE_TAC[CLOSURE_HULL; HULL_UNIQUE]);;
+
+let CLOSURE_EMPTY = prove
+ (`closure {} = {}`,
+  SIMP_TAC[CLOSURE_CLOSED; CLOSED_EMPTY]);;
+
+let CLOSURE_UNIV = prove
+ (`closure(:real^N) = (:real^N)`,
+  SIMP_TAC[CLOSURE_CLOSED; CLOSED_UNIV]);;
+
+let CLOSURE_UNIONS = prove
+ (`!f. FINITE f ==> closure(UNIONS f) = UNIONS {closure s | s IN f}`,
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[UNIONS_0; UNIONS_INSERT; SET_RULE `{f x | x IN {}} = {}`;
+     SET_RULE `{f x | x IN a INSERT s} = (f a) INSERT {f x | x IN s}`] THEN
+  SIMP_TAC[CLOSURE_EMPTY; CLOSURE_UNION]);;
+
+let CLOSURE_EQ_EMPTY = prove
+ (`!s. closure s = {} <=> s = {}`,
+  GEN_TAC THEN EQ_TAC THEN SIMP_TAC[CLOSURE_EMPTY] THEN
+  MATCH_MP_TAC(SET_RULE `s SUBSET t ==> t = {} ==> s = {}`) THEN
+  REWRITE_TAC[CLOSURE_SUBSET]);;
+
+let CLOSURE_SUBSET_EQ = prove
+ (`!s:real^N->bool. closure s SUBSET s <=> closed s`,
+  GEN_TAC THEN REWRITE_TAC[GSYM CLOSURE_EQ] THEN
+  MP_TAC(ISPEC `s:real^N->bool` CLOSURE_SUBSET) THEN SET_TAC[]);;
+
+let OPEN_INTER_CLOSURE_EQ_EMPTY = prove
+ (`!s t:real^N->bool.
+        open s ==> (s INTER (closure t) = {} <=> s INTER t = {})`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [MP_TAC(ISPEC `t:real^N->bool` CLOSURE_SUBSET) THEN SET_TAC[]; ALL_TAC] THEN
+  DISCH_TAC THEN REWRITE_TAC[CLOSURE_INTERIOR] THEN
+  MATCH_MP_TAC(SET_RULE `s SUBSET t ==> s INTER (UNIV DIFF t) = {}`) THEN
+  ASM_SIMP_TAC[OPEN_SUBSET_INTERIOR] THEN ASM SET_TAC[]);;
+
+let OPEN_INTER_CLOSURE_SUBSET = prove
+ (`!s t:real^N->bool.
+        open s ==> (s INTER (closure t)) SUBSET closure(s INTER t)`,
+  REPEAT STRIP_TAC THEN
+  SIMP_TAC[SUBSET; IN_INTER; closure; IN_UNION; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  DISJ2_TAC THEN REWRITE_TAC[LIMPT_APPROACHABLE] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [open_def]) THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIMPT_APPROACHABLE]) THEN
+  DISCH_THEN(MP_TAC o SPEC `min d e`) THEN
+  ASM_REWRITE_TAC[REAL_LT_MIN; IN_INTER] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN ASM_MESON_TAC[]);;
+
+let CLOSURE_OPEN_INTER_SUPERSET = prove
+ (`!s t:real^N->bool.
+        open s /\ s SUBSET closure t ==> closure(s INTER t) = closure s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  SIMP_TAC[SUBSET_CLOSURE; INTER_SUBSET] THEN
+  MATCH_MP_TAC CLOSURE_MINIMAL THEN REWRITE_TAC[CLOSED_CLOSURE] THEN
+  W(MP_TAC o PART_MATCH (rand o rand)
+    OPEN_INTER_CLOSURE_SUBSET o rand o snd) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] SUBSET_TRANS) THEN ASM SET_TAC[]);;
+
+let CLOSURE_COMPLEMENT = prove
+ (`!s:real^N->bool. closure(UNIV DIFF s) = UNIV DIFF interior(s)`,
+  REWRITE_TAC[SET_RULE `s = UNIV DIFF t <=> UNIV DIFF s = t`] THEN
+  REWRITE_TAC[GSYM INTERIOR_CLOSURE]);;
+
+let INTERIOR_COMPLEMENT = prove
+ (`!s:real^N->bool. interior(UNIV DIFF s) = UNIV DIFF closure(s)`,
+  REWRITE_TAC[SET_RULE `s = UNIV DIFF t <=> UNIV DIFF s = t`] THEN
+  REWRITE_TAC[GSYM CLOSURE_INTERIOR]);;
+
+let CONNECTED_INTERMEDIATE_CLOSURE = prove
+ (`!s t:real^N->bool.
+        connected s /\ s SUBSET t /\ t SUBSET closure s ==> connected t`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[connected; NOT_EXISTS_THM] THEN
+  STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`u:real^N->bool`; `v:real^N->bool`] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`u:real^N->bool`; `v:real^N->bool`]) THEN
+  ASM_REWRITE_TAC[] THEN ASSUME_TAC(ISPEC `s:real^N->bool` CLOSURE_SUBSET) THEN
+  REPLICATE_TAC 2 (CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+  REWRITE_TAC[GSYM DE_MORGAN_THM] THEN STRIP_TAC THENL
+   [SUBGOAL_THEN `(closure s) SUBSET ((:real^N) DIFF u)` MP_TAC THENL
+     [MATCH_MP_TAC CLOSURE_MINIMAL THEN ASM_REWRITE_TAC[GSYM OPEN_CLOSED];
+      ALL_TAC];
+    SUBGOAL_THEN `(closure s) SUBSET ((:real^N) DIFF v)` MP_TAC THENL
+     [MATCH_MP_TAC CLOSURE_MINIMAL THEN ASM_REWRITE_TAC[GSYM OPEN_CLOSED];
+      ALL_TAC]] THEN
+  ASM SET_TAC[]);;
+
+let CONNECTED_CLOSURE = prove
+ (`!s:real^N->bool. connected s ==> connected(closure s)`,
+  MESON_TAC[CONNECTED_INTERMEDIATE_CLOSURE; CLOSURE_SUBSET; SUBSET_REFL]);;
+
+let CONNECTED_UNION_STRONG = prove
+ (`!s t:real^N->bool.
+        connected s /\ connected t /\ ~(closure s INTER t = {})
+        ==> connected(s UNION t)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `p:real^N`) THEN
+  SUBGOAL_THEN `s UNION t = ((p:real^N) INSERT s) UNION t` SUBST1_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC CONNECTED_UNION THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CONNECTED_INTERMEDIATE_CLOSURE THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+    MP_TAC(ISPEC `s:real^N->bool` CLOSURE_SUBSET) THEN ASM SET_TAC[];
+    ASM SET_TAC[]]);;
+
+let INTERIOR_DIFF = prove
+ (`!s t. interior(s DIFF t) = interior(s) DIFF closure(t)`,
+  ONCE_REWRITE_TAC[SET_RULE `s DIFF t = s INTER (UNIV DIFF t)`] THEN
+  REWRITE_TAC[INTERIOR_INTER; CLOSURE_INTERIOR] THEN SET_TAC[]);;
+
+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]);;
+
+let CLOSED_IN_LIMPT = prove
+ (`!s t. closed_in (subtopology euclidean t) s <=>
+         s SUBSET t /\ !x:real^N. x limit_point_of s /\ x IN t ==> x IN s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[CLOSED_IN_CLOSED] THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+    ASM_SIMP_TAC[IN_INTER] THEN
+    ASM_MESON_TAC[CLOSED_LIMPT; LIMPT_SUBSET; INTER_SUBSET];
+    STRIP_TAC THEN EXISTS_TAC `closure s :real^N->bool` THEN
+    REWRITE_TAC[CLOSED_CLOSURE] THEN REWRITE_TAC[closure] THEN
+    ASM SET_TAC[]]);;
+
+let INTERIOR_CLOSURE_IDEMP = prove
+ (`!s:real^N->bool.
+        interior(closure(interior(closure s))) = interior(closure s)`,
+  GEN_TAC THEN MATCH_MP_TAC INTERIOR_UNIQUE THEN
+  ASM_MESON_TAC[OPEN_INTERIOR; CLOSURE_SUBSET; CLOSURE_CLOSURE; SUBSET_TRANS;
+                OPEN_SUBSET_INTERIOR;SUBSET_CLOSURE; INTERIOR_SUBSET]);;
+
+let CLOSURE_INTERIOR_IDEMP = prove
+ (`!s:real^N->bool.
+        closure(interior(closure(interior s))) = closure(interior s)`,
+  GEN_TAC THEN
+  ONCE_REWRITE_TAC[SET_RULE `s = t <=> UNIV DIFF s = UNIV DIFF t`] THEN
+  REWRITE_TAC[GSYM INTERIOR_COMPLEMENT; GSYM CLOSURE_COMPLEMENT] THEN
+  REWRITE_TAC[INTERIOR_CLOSURE_IDEMP]);;
+
+let NOWHERE_DENSE_UNION = prove
+ (`!s t:real^N->bool.
+        interior(closure(s UNION t)) = {} <=>
+        interior(closure s) = {} /\ interior(closure t) = {}`,
+  SIMP_TAC[CLOSURE_UNION; INTERIOR_UNION_EQ_EMPTY; CLOSED_CLOSURE]);;
+
+let NOWHERE_DENSE = prove
+ (`!s:real^N->bool.
+        interior(closure s) = {} <=>
+        !t. open t /\ ~(t = {})
+            ==> ?u. open u /\ ~(u = {}) /\ u SUBSET t /\ u INTER s = {}`,
+  GEN_TAC THEN REWRITE_TAC[INTERIOR_EQ_EMPTY_ALT] THEN EQ_TAC THEN
+  DISCH_TAC THEN X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THENL
+   [EXISTS_TAC `t DIFF closure s:real^N->bool` THEN
+    ASM_SIMP_TAC[OPEN_DIFF; CLOSED_CLOSURE] THEN
+    MP_TAC(ISPEC `s:real^N->bool` CLOSURE_SUBSET) THEN SET_TAC[];
+    FIRST_X_ASSUM(MP_TAC o SPEC `t:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`u:real^N->bool`; `s:real^N->bool`]
+        OPEN_INTER_CLOSURE_EQ_EMPTY) THEN
+    ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Frontier (aka boundary).                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let frontier = new_definition
+  `frontier s = (closure s) DIFF (interior s)`;;
+
+let FRONTIER_CLOSED = prove
+ (`!s. closed(frontier s)`,
+  SIMP_TAC[frontier; CLOSED_DIFF; CLOSED_CLOSURE; OPEN_INTERIOR]);;
+
+let FRONTIER_CLOSURES = prove
+ (`!s:real^N->bool. frontier s = (closure s) INTER (closure(UNIV DIFF s))`,
+  let lemma = prove(`s DIFF (UNIV DIFF t) = s INTER t`,SET_TAC[]) in
+  REWRITE_TAC[frontier; INTERIOR_CLOSURE; lemma]);;
+
+let FRONTIER_STRADDLE = prove
+ (`!a:real^N s.
+     a IN frontier s <=>
+        !e. &0 < e ==> (?x. x IN s /\ dist(a,x) < e) /\
+                       (?x. ~(x IN s) /\ dist(a,x) < e)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[FRONTIER_CLOSURES; IN_INTER] THEN
+  REWRITE_TAC[closure; IN_UNION; IN_ELIM_THM; limit_point_of;
+              IN_UNIV; IN_DIFF] THEN
+  ASM_MESON_TAC[IN_BALL; SUBSET; OPEN_CONTAINS_BALL;
+                CENTRE_IN_BALL; OPEN_BALL; DIST_REFL]);;
+
+let FRONTIER_SUBSET_CLOSED = prove
+ (`!s. closed s ==> (frontier s) SUBSET s`,
+  MESON_TAC[frontier; CLOSURE_CLOSED; SUBSET_DIFF]);;
+
+let FRONTIER_EMPTY = prove
+ (`frontier {} = {}`,
+  REWRITE_TAC[frontier; CLOSURE_EMPTY; EMPTY_DIFF]);;
+
+let FRONTIER_UNIV = prove
+ (`frontier(:real^N) = {}`,
+  REWRITE_TAC[frontier; CLOSURE_UNIV; INTERIOR_UNIV] THEN SET_TAC[]);;
+
+let FRONTIER_SUBSET_EQ = prove
+ (`!s:real^N->bool. (frontier s) SUBSET s <=> closed s`,
+  GEN_TAC THEN EQ_TAC THEN SIMP_TAC[FRONTIER_SUBSET_CLOSED] THEN
+  REWRITE_TAC[frontier] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE
+   `s DIFF t SUBSET u ==> t SUBSET u ==> s SUBSET u`)) THEN
+  REWRITE_TAC[INTERIOR_SUBSET; CLOSURE_SUBSET_EQ]);;
+
+let FRONTIER_COMPLEMENT = prove
+ (`!s:real^N->bool. frontier(UNIV DIFF s) = frontier s`,
+  REWRITE_TAC[frontier; CLOSURE_COMPLEMENT; INTERIOR_COMPLEMENT] THEN
+  SET_TAC[]);;
+
+let FRONTIER_DISJOINT_EQ = prove
+ (`!s. (frontier s) INTER s = {} <=> open s`,
+  ONCE_REWRITE_TAC[GSYM FRONTIER_COMPLEMENT; OPEN_CLOSED] THEN
+  REWRITE_TAC[GSYM FRONTIER_SUBSET_EQ] THEN SET_TAC[]);;
+
+let FRONTIER_INTER_SUBSET = prove
+ (`!s t. frontier(s INTER t) SUBSET frontier(s) UNION frontier(t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[frontier; INTERIOR_INTER] THEN
+  MATCH_MP_TAC(SET_RULE
+   `cst SUBSET cs INTER ct
+    ==> cst DIFF (s INTER t) SUBSET (cs DIFF s) UNION (ct DIFF t)`) THEN
+  REWRITE_TAC[CLOSURE_INTER_SUBSET]);;
+
+let FRONTIER_UNION_SUBSET = prove
+ (`!s t:real^N->bool. frontier(s UNION t) SUBSET frontier s UNION frontier t`,
+  ONCE_REWRITE_TAC[GSYM FRONTIER_COMPLEMENT] THEN
+  REWRITE_TAC[SET_RULE `u DIFF (s UNION t) = (u DIFF s) INTER (u DIFF t)`] THEN
+  REWRITE_TAC[FRONTIER_INTER_SUBSET]);;
+
+let FRONTIER_INTERIORS = prove
+ (`!s. frontier s = (:real^N) DIFF interior(s) DIFF interior((:real^N) DIFF s)`,
+  REWRITE_TAC[frontier; CLOSURE_INTERIOR] THEN SET_TAC[]);;
+
+let FRONTIER_FRONTIER_SUBSET = prove
+ (`!s:real^N->bool. frontier(frontier s) SUBSET frontier s`,
+  GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [frontier] THEN
+  SIMP_TAC[CLOSURE_CLOSED; FRONTIER_CLOSED] THEN SET_TAC[]);;
+
+let INTERIOR_FRONTIER = prove
+ (`!s:real^N->bool.
+        interior(frontier s) = interior(closure s) DIFF closure(interior s)`,
+  ONCE_REWRITE_TAC[SET_RULE `s DIFF t = s INTER (UNIV DIFF t)`] THEN
+  REWRITE_TAC[GSYM INTERIOR_COMPLEMENT; GSYM INTERIOR_INTER; frontier] THEN
+  GEN_TAC THEN AP_TERM_TAC THEN SET_TAC[]);;
+
+let INTERIOR_FRONTIER_EMPTY = prove
+ (`!s:real^N->bool. open s \/ closed s ==> interior(frontier s) = {}`,
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[INTERIOR_FRONTIER] THEN
+  ASM_SIMP_TAC[CLOSURE_CLOSED; INTERIOR_OPEN] THEN
+  REWRITE_TAC[SET_RULE `s DIFF t = {} <=> s SUBSET t`] THEN
+  REWRITE_TAC[INTERIOR_SUBSET; CLOSURE_SUBSET]);;
+
+let FRONTIER_FRONTIER_FRONTIER = prove
+ (`!s:real^N->bool. frontier(frontier(frontier s)) = frontier(frontier s)`,
+  GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [frontier] THEN
+  SIMP_TAC[CLOSURE_CLOSED; FRONTIER_CLOSED; INTERIOR_FRONTIER_EMPTY] THEN
+  SET_TAC[]);;
+
+let CONNECTED_INTER_FRONTIER = prove
+ (`!s t:real^N->bool.
+        connected s /\ ~(s INTER t = {}) /\ ~(s DIFF t = {})
+        ==> ~(s INTER frontier t = {})`,
+  REWRITE_TAC[FRONTIER_INTERIORS] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [CONNECTED_OPEN_IN]) THEN
+  REWRITE_TAC[] THEN MAP_EVERY EXISTS_TAC
+   [`s INTER interior t:real^N->bool`;
+    `s INTER (interior((:real^N) DIFF t))`] THEN
+  SIMP_TAC[OPEN_IN_OPEN_INTER; OPEN_INTERIOR] THEN
+  MAP_EVERY (MP_TAC o C ISPEC INTERIOR_SUBSET)
+   [`t:real^N->bool`; `(:real^N) DIFF t`] THEN
+  ASM SET_TAC[]);;
+
+let INTERIOR_CLOSED_EQ_EMPTY_AS_FRONTIER = prove
+ (`!s:real^N->bool.
+        closed s /\ interior s = {} <=> ?t. open t /\ s = frontier t`,
+  GEN_TAC THEN EQ_TAC THEN STRIP_TAC THENL
+   [EXISTS_TAC `(:real^N) DIFF s` THEN
+    ASM_SIMP_TAC[OPEN_DIFF; OPEN_UNIV; FRONTIER_COMPLEMENT] THEN
+    ASM_SIMP_TAC[frontier; CLOSURE_CLOSED; DIFF_EMPTY];
+    ASM_SIMP_TAC[FRONTIER_CLOSED; INTERIOR_FRONTIER_EMPTY]]);;
+
+let FRONTIER_UNION = prove
+ (`!s t:real^N->bool.
+        closure s INTER closure t = {}
+        ==> frontier(s UNION t) = frontier(s) UNION frontier(t)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN REWRITE_TAC[FRONTIER_UNION_SUBSET] THEN
+  GEN_REWRITE_TAC RAND_CONV [frontier] THEN
+  REWRITE_TAC[CLOSURE_UNION] THEN MATCH_MP_TAC(SET_RULE
+   `(fs SUBSET cs /\ ft SUBSET ct) /\ k INTER fs = {} /\ k INTER ft = {}
+    ==> (fs UNION ft) SUBSET (cs UNION ct) DIFF k`) THEN
+  CONJ_TAC THENL [REWRITE_TAC[frontier] THEN SET_TAC[]; ALL_TAC] THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[UNION_COMM] THEN
+    RULE_ASSUM_TAC(ONCE_REWRITE_RULE[INTER_COMM])] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+   `s INTER t = {} ==> s' SUBSET s /\ s' INTER u INTER (UNIV DIFF t) = {}
+      ==> u INTER s' = {}`)) THEN
+  REWRITE_TAC[frontier; SUBSET_DIFF; GSYM INTERIOR_COMPLEMENT] THEN
+  REWRITE_TAC[GSYM INTERIOR_INTER; SET_RULE
+   `(s UNION t) INTER (UNIV DIFF t) = s DIFF t`] THEN
+  MATCH_MP_TAC(SET_RULE
+    `ti SUBSET si ==> (c DIFF si) INTER ti = {}`) THEN
+  SIMP_TAC[SUBSET_INTERIOR; SUBSET_DIFF]);;
+
+let CLOSURE_UNION_FRONTIER = prove
+ (`!s:real^N->bool. closure s = s UNION frontier s`,
+  GEN_TAC THEN REWRITE_TAC[frontier] THEN
+  MP_TAC(ISPEC `s:real^N->bool` INTERIOR_SUBSET) THEN
+  MP_TAC(ISPEC `s:real^N->bool` CLOSURE_SUBSET) THEN
+  SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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)`,
+  REWRITE_TAC[WITHIN; AT; in_direction; IN_ELIM_THM; CONJ_ACI]);;
+
+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)`,
+  REWRITE_TAC[trivial_limit; AT_INFINITY; real_ge] THEN
+  MESON_TAC[REAL_LE_REFL; VECTOR_CHOOSE_SIZE; REAL_LT_01; REAL_LT_LE]);;
+
+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 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 = 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_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_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`]]);;
+
+let LIMPT_OF_CONDENSATION_POINTS = prove
+ (`!x:real^N s.
+        x limit_point_of {y | y condensation_point_of s}
+        ==> x condensation_point_of s`,
+  REWRITE_TAC[LIMPT_APPROACHABLE; CONDENSATION_POINT_INFINITE_BALL] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN DISCH_TAC THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
+  ASM_REWRITE_TAC[REAL_HALF; CONTRAPOS_THM] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] COUNTABLE_SUBSET) THEN
+  SIMP_TAC[SUBSET; IN_INTER; IN_BALL] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC);;
+
+let CLOSED_CONDENSATION_POINTS = prove
+ (`!s:real^N->bool. closed {x | x condensation_point_of s}`,
+  SIMP_TAC[CLOSED_LIMPT; LIMPT_OF_CONDENSATION_POINTS; IN_ELIM_THM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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)`,
+  MESON_TAC[LIM_CMUL_EQ; VECTOR_MUL_RZERO]);;
+
+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.
+        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]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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)`,
+  SIMP_TAC[LIM_CASES_FINITE_SEQUENTIALLY; LIM_CASES_COFINITE_SEQUENTIALLY;
+           NOT_LE; NOT_LT; FINITE_NUMSEG_LT; FINITE_NUMSEG_LE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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`,
+  MESON_TAC[CLOSURE_SEQUENTIAL; CLOSURE_CLOSED]);;
+
+let CLOSED_SEQUENTIAL_LIMITS = prove
+ (`!s. closed s <=>
+       !x l. (!n. x(n) IN s) /\ (x --> l) sequentially ==> l IN s`,
+  MESON_TAC[CLOSURE_SEQUENTIAL; CLOSURE_CLOSED;
+            CLOSED_LIMPT; LIMPT_SEQUENTIAL; IN_DELETE]);;
+
+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)`,
+  MESON_TAC[CLOSURE_CLOSED; CLOSURE_APPROACHABLE]);;
+
+let IN_CLOSURE_DELETE = prove
+ (`!s x:real^N. x IN closure(s DELETE x) <=> x limit_point_of s`,
+  SIMP_TAC[CLOSURE_APPROACHABLE; LIMPT_APPROACHABLE; IN_DELETE; CONJ_ASSOC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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`,
+  REWRITE_TAC[interior; IN_ELIM_THM] THEN
+  MESON_TAC[OPEN_CONTAINS_CBALL; SUBSET_TRANS;
+            BALL_SUBSET_CBALL; CENTRE_IN_BALL; OPEN_BALL]);;
+
+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_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`,
+  REWRITE_TAC[EXTENSION; IN_CBALL; NOT_IN_EMPTY; REAL_NOT_LE] THEN
+  MESON_TAC[DIST_POS_LE; DIST_REFL; REAL_LTE_TRANS]);;
+
+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)`,
+  MESON_TAC[BOUNDED_SUBSET; INTERIOR_SUBSET]);;
+
+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))`,
+  MESON_TAC[BALL_SUBSET_CBALL; BOUNDED_CBALL; BOUNDED_SUBSET]);;
+
+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)`,
+  MESON_TAC[BOUNDED_SUBSET; INTER_SUBSET]);;
+
+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)`,
+  MESON_TAC[BOUNDED_SUBSET_BALL; SUBSET_TRANS; BALL_SUBSET_CBALL]);;
+
+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 relation 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);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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 IN s /\ 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_SIMP_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`,
+  GEN_TAC THEN EQ_TAC THENL
+   [SIMP_TAC[COMPACT_EQ_HEINE_BOREL; HEINE_BOREL_IMP_BOLZANO_WEIERSTRASS];
+    SIMP_TAC[BOLZANO_WEIERSTRASS_IMP_BOUNDED; BOLZANO_WEIERSTRASS_IMP_CLOSED;
+             BOUNDED_CLOSED_IMP_COMPACT]]);;
+
+let COMPACT_EQ_BOUNDED_CLOSED = prove
+ (`!s:real^N->bool. compact s <=> bounded s /\ closed s`,
+  GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[BOUNDED_CLOSED_IMP_COMPACT] THEN
+  SIMP_TAC[COMPACT_EQ_BOLZANO_WEIERSTRASS; BOLZANO_WEIERSTRASS_IMP_BOUNDED;
+           BOLZANO_WEIERSTRASS_IMP_CLOSED]);;
+
+let COMPACT_IMP_BOUNDED = prove
+ (`!s. compact s ==> bounded s`,
+  SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED]);;
+
+let COMPACT_IMP_CLOSED = prove
+ (`!s. compact s ==> closed s`,
+  SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED]);;
+
+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`,
+  SIMP_TAC[IMP_CONJ; COMPACT_EQ_BOUNDED_CLOSED; CLOSED_IN_CLOSED_EQ] THEN
+  MESON_TAC[BOUNDED_SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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`,
+  REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED; CLOSED_CLOSURE; BOUNDED_CLOSURE_EQ]);;
+
+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[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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)`,
+  SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; BOUNDED_UNION; CLOSED_UNION]);;
+
+let COMPACT_INTER = prove
+ (`!s t. compact s /\ compact t ==> compact (s INTER t)`,
+  SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; BOUNDED_INTER; CLOSED_INTER]);;
+
+let COMPACT_INTER_CLOSED = prove
+ (`!s t. compact s /\ closed t ==> compact (s INTER t)`,
+  SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; CLOSED_INTER] THEN
+  MESON_TAC[BOUNDED_SUBSET; INTER_SUBSET]);;
+
+let CLOSED_INTER_COMPACT = prove
+ (`!s t. closed s /\ compact t ==> compact (s INTER t)`,
+  MESON_TAC[COMPACT_INTER_CLOSED; INTER_COMM]);;
+
+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`,
+  MESON_TAC[BOLZANO_WEIERSTRASS_IMP_CLOSED; INFINITE; FINITE_SUBSET]);;
+
+let FINITE_IMP_CLOSED_IN = prove
+ (`!s t. FINITE s /\ s SUBSET t ==> closed_in (subtopology euclidean t) s`,
+  SIMP_TAC[CLOSED_SUBSET_EQ; FINITE_IMP_CLOSED]);;
+
+let FINITE_IMP_COMPACT = prove
+ (`!s. FINITE s ==> compact s`,
+  SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; FINITE_IMP_CLOSED; FINITE_IMP_BOUNDED]);;
+
+let COMPACT_SING = prove
+ (`!a. compact {a}`,
+  SIMP_TAC[FINITE_IMP_COMPACT; FINITE_RULES]);;
+
+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}`,
+  MESON_TAC[COMPACT_EQ_BOUNDED_CLOSED; COMPACT_SING]);;
+
+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}`,
+  SIMP_TAC[CLOSURE_CLOSED; CLOSED_SING]);;
+
+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))`,
+  REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED; BOUNDED_CBALL; CLOSED_CBALL]);;
+
+let COMPACT_FRONTIER_BOUNDED = prove
+ (`!s. bounded s ==> compact(frontier s)`,
+  SIMP_TAC[frontier; COMPACT_EQ_BOUNDED_CLOSED;
+           CLOSED_DIFF; OPEN_INTERIOR; CLOSED_CLOSURE] THEN
+  MESON_TAC[SUBSET_DIFF; BOUNDED_SUBSET; BOUNDED_CLOSURE]);;
+
+let COMPACT_FRONTIER = prove
+ (`!s. compact s ==> compact (frontier s)`,
+  MESON_TAC[COMPACT_EQ_BOUNDED_CLOSED; COMPACT_FRONTIER_BOUNDED]);;
+
+let BOUNDED_FRONTIER = prove
+ (`!s:real^N->bool. bounded s ==> bounded(frontier s)`,
+  MESON_TAC[COMPACT_FRONTIER_BOUNDED; COMPACT_IMP_BOUNDED]);;
+
+let FRONTIER_SUBSET_COMPACT = prove
+ (`!s. compact s ==> frontier s SUBSET s`,
+  MESON_TAC[FRONTIER_SUBSET_CLOSED; COMPACT_EQ_BOUNDED_CLOSED]);;
+
+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)`,
+  SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; CLOSED_UNIONS; BOUNDED_UNIONS]);;
+
+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))`,
+  SIMP_TAC[COMPACT_SPHERE; COMPACT_IMP_BOUNDED]);;
+
+let CLOSED_SPHERE = prove
+ (`!a r. closed(sphere(a,r))`,
+  SIMP_TAC[COMPACT_SPHERE; COMPACT_IMP_CLOSED]);;
+
+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_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_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_THEN `s:real^N->bool` STRIP_ASSUME_TAC)
+        ASSUME_TAC) THEN
+  MATCH_MP_TAC(SET_RULE `!s. ~(s INTER f = {}) ==> ~(f = {})`) THEN
+  EXISTS_TAC `s:real^N->bool` THEN MATCH_MP_TAC COMPACT_IMP_FIP THEN
+  ASM_SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN
+  GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC COMPACT_IMP_FIP THEN
+  ASM_SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[SUBSET]; ALL_TAC] THEN
+  GEN_TAC THEN STRIP_TAC THEN REWRITE_TAC[GSYM INTERS_INSERT] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[FINITE_INSERT] THEN ASM SET_TAC[]);;
+
+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 STRIP_TAC THEN
+  ASM_CASES_TAC `f:(real^N->bool)->bool = {}` THEN
+  ASM_REWRITE_TAC[INTERS_0; UNIV_NOT_EMPTY] THEN
+  MATCH_MP_TAC CLOSED_FIP THEN
+  ASM_SIMP_TAC[COMPACT_IMP_CLOSED] THEN
+  ASM_MESON_TAC[MEMBER_NOT_EMPTY; COMPACT_IMP_BOUNDED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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)`,
+  SIMP_TAC[LIM_AT_WITHIN; CONTINUOUS_AT; CONTINUOUS_WITHIN]);;
+
+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]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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)`,
+  SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_BALL; continuous_within; IN_INTER] THEN
+  MESON_TAC[DIST_SYM]);;
+
+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)`,
+  REWRITE_TAC[continuous_on; continuous_within]);;
+
+let CONTINUOUS_ON = prove
+ (`!f (s:real^N->bool).
+        f continuous_on s <=> !x. x IN s ==> (f --> f(x)) (at x within s)`,
+  REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_WITHIN]);;
+
+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)))`,
+  SIMP_TAC[CONTINUOUS_ON; CONTINUOUS_AT; LIM_WITHIN_OPEN]);;
+
+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`,
+  SIMP_TAC[uniformly_continuous_on; IMP_CONJ]);;
+
+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 {}`,
+  MESON_TAC[CONTINUOUS_ON_SING; EMPTY_SUBSET; CONTINUOUS_ON_SUBSET]);;
+
+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`,
+  MESON_TAC[CONTINUOUS_ON_NO_LIMPT; LIMIT_POINT_FINITE]);;
+
+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`,
+  SIMP_TAC[CONTRACTION_IMP_CONTINUOUS_ON; REAL_LE_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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`,
+  REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+              CONTINUOUS_WITHIN_SEQUENTIALLY] THEN MESON_TAC[]);;
+
+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`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_CONST]);;
+
+let CONTINUOUS_ON_CMUL = prove
+ (`!f c s. f continuous_on s ==> (\x. c % f(x)) continuous_on s`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_CMUL]);;
+
+let CONTINUOUS_ON_NEG = prove
+ (`!f s. f continuous_on s
+         ==> (\x. --(f x)) continuous_on s`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_NEG]);;
+
+let CONTINUOUS_ON_ADD = prove
+ (`!f g s. f continuous_on s /\ g continuous_on s
+           ==> (\x. f(x) + g(x)) continuous_on s`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_ADD]);;
+
+let CONTINUOUS_ON_SUB = prove
+ (`!f g s. f continuous_on s /\ g continuous_on s
+           ==> (\x. f(x) - g(x)) continuous_on s`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_SUB]);;
+
+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`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_ABS]);;
+
+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`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_MAX]);;
+
+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`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_MIN]);;
+
+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`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_VSUM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Same thing for uniform continuity, using sequential formulations.         *)
+(* ------------------------------------------------------------------------- *)
+
+let UNIFORMLY_CONTINUOUS_ON_CONST = prove
+ (`!s c. (\x. c) uniformly_continuous_on s`,
+  REWRITE_TAC[UNIFORMLY_CONTINUOUS_ON_SEQUENTIALLY; o_DEF;
+              VECTOR_SUB_REFL; LIM_CONST]);;
+
+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`,
+  REWRITE_TAC[VECTOR_SUB] THEN
+  SIMP_TAC[UNIFORMLY_CONTINUOUS_ON_NEG; UNIFORMLY_CONTINUOUS_ON_ADD]);;
+
+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)`,
+  ONCE_REWRITE_TAC[GSYM WITHIN_UNIV] THEN
+  MESON_TAC[CONTINUOUS_WITHIN_COMPOSE; IN_IMAGE; CONTINUOUS_WITHIN_SUBSET;
+            SUBSET_UNIV; IN_UNIV]);;
+
+let CONTINUOUS_ON_COMPOSE = prove
+ (`!f g s. f continuous_on s /\ g continuous_on (IMAGE f s)
+           ==> (g o f) continuous_on s`,
+  REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  MESON_TAC[IN_IMAGE; CONTINUOUS_WITHIN_COMPOSE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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}`,
+  MESON_TAC[CONTINUOUS_ON_CLOSED_GEN]);;
+
+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[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Quotient maps are occasionally useful.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+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[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More properties of open and closed maps.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+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[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Two equivalent characterizations of a proper/perfect map.                 *)
+(* ------------------------------------------------------------------------- *)
+
+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 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]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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`,
+  SIMP_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON; CONTINUOUS_AT_LIFT_DOT]);;
+
+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}`,
+  ONCE_REWRITE_TAC[GSYM BOUNDED_CLOSURE_EQ] THEN
+  REWRITE_TAC[CLOSURE_HALFSPACE_COMPONENT_LT;
+              UNBOUNDED_HALFSPACE_COMPONENT_LE]);;
+
+let UNBOUNDED_HALFSPACE_COMPONENT_GT = prove
+ (`!a k. ~bounded {x:real^N | x$k > a}`,
+  ONCE_REWRITE_TAC[GSYM BOUNDED_CLOSURE_EQ] THEN
+  REWRITE_TAC[CLOSURE_HALFSPACE_COMPONENT_GT;
+              UNBOUNDED_HALFSPACE_COMPONENT_GE]);;
+
+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 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`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_WITHIN_LIFT_SQRT]);;
+
+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]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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)`,
+  SIMP_TAC[CONTINUOUS_AT_WITHIN; LINEAR_CONTINUOUS_AT]);;
+
+let LINEAR_CONTINUOUS_ON = prove
+ (`!f:real^M->real^N s. linear f ==> f continuous_on s`,
+  MESON_TAC[LINEAR_CONTINUOUS_AT; CONTINUOUS_AT_IMP_CONTINUOUS_ON]);;
+
+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`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+           LINEAR_CONTINUOUS_COMPOSE]);;
+
+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`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+           CONTINUOUS_LIFT_COMPONENT_COMPOSE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN;
+           BILINEAR_CONTINUOUS_COMPOSE]);;
+
+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[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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)`,
+  MESON_TAC[CONTINUOUS_LEVELSET_OPEN_IN_CASES]);;
+
+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`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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_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 COMPACT_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s. compact s /\ linear f ==> compact(IMAGE f s)`,
+  SIMP_TAC[LINEAR_CONTINUOUS_ON; COMPACT_CONTINUOUS_IMAGE]);;
+
+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`,
+  REWRITE_TAC[connected] THEN GEOM_TRANSLATE_TAC[]);;
+
+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)`,
+  SIMP_TAC[LINEAR_CONTINUOUS_ON; CONNECTED_CONTINUOUS_IMAGE]);;
+
+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];;
+
+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[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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`,
+  MESON_TAC[CONNECTED_CONNECTED_COMPONENT_SET]);;
+
+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 = {}`,
+  REWRITE_TAC[CONNECTED_COMPONENT_EQ_EMPTY; NOT_IN_EMPTY]);;
+
+let CONNECTED_COMPONENT_EQ = prove
+ (`!s x y. y IN connected_component s x
+           ==> (connected_component s y = connected_component s x)`,
+  REWRITE_TAC[EXTENSION; IN] THEN
+  MESON_TAC[CONNECTED_COMPONENT_SYM; CONNECTED_COMPONENT_TRANS]);;
+
+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`,
+  MESON_TAC[CONNECTED_COMPONENT_SYM]);;
+
+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`,
+  SIMP_TAC[CONNECTED_COMPONENT_EQ_EQ] THEN
+  REWRITE_TAC[CONNECTED_IFF_CONNECTED_COMPONENT]);;
+
+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 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]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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_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 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_CLOSED_GEN = prove
+ (`!f:real^M->real^N s.
+        FINITE(components s) /\
+        (!c. c IN components s
+             ==> closed_in (subtopology euclidean s) c /\ 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]]);;
+
+let CONTINUOUS_ON_COMPONENTS_CLOSED = prove
+ (`!f:real^M->real^N s.
+        closed s /\ FINITE(components s) /\
+        (!c. c IN components s ==> f continuous_on c)
+        ==> f continuous_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_COMPONENTS_CLOSED_GEN THEN
+  ASM_SIMP_TAC[] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSED_SUBSET THEN
+  ASM_MESON_TAC[CLOSED_COMPONENTS; IN_COMPONENTS_SUBSET]);;
+
+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 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 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]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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`,
+  REWRITE_TAC[open_def; FORALL_LIFT; LIFT_IN_IMAGE_LIFT; DIST_LIFT]);;
+
+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`,
+  REWRITE_TAC[LIMPT_APPROACHABLE; EXISTS_LIFT; LIFT_IN_IMAGE_LIFT;
+              LIFT_EQ; DIST_LIFT]);;
+
+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`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_LIFT_NORM_COMPOSE]);;
+
+let CONTINUOUS_AT_LIFT_NORM = prove
+ (`!x. (lift o norm) continuous (at x)`,
+  REWRITE_TAC[CONTINUOUS_AT_LIFT_RANGE; NORM_LIFT] THEN
+  MESON_TAC[REAL_ABS_SUB_NORM; REAL_LET_TRANS]);;
+
+let CONTINUOUS_ON_LIFT_NORM = prove
+ (`!s. (lift o norm) continuous_on s`,
+  REWRITE_TAC[CONTINUOUS_ON_LIFT_RANGE; NORM_LIFT] THEN
+  MESON_TAC[REAL_ABS_SUB_NORM; REAL_LET_TRANS]);;
+
+let CONTINUOUS_AT_LIFT_COMPONENT = prove
+ (`!i a. 1 <= i /\ i <= dimindex(:N)
+         ==> (\x:real^N. lift(x$i)) continuous (at a)`,
+  SIMP_TAC[continuous_at; DIST_LIFT; GSYM VECTOR_SUB_COMPONENT] THEN
+  MESON_TAC[dist; REAL_LET_TRANS; COMPONENT_LE_NORM]);;
+
+let CONTINUOUS_ON_LIFT_COMPONENT = prove
+ (`!i s. 1 <= i /\ i <= dimindex(:N)
+         ==> (\x:real^N. lift(x$i)) continuous_on s`,
+  SIMP_TAC[continuous_on; DIST_LIFT; GSYM VECTOR_SUB_COMPONENT] THEN
+  MESON_TAC[dist; REAL_LET_TRANS; COMPONENT_LE_NORM]);;
+
+let CONTINUOUS_AT_LIFT_INFNORM = prove
+ (`!x:real^N. (lift o infnorm) continuous (at x)`,
+  REWRITE_TAC[CONTINUOUS_AT; LIM_AT; o_THM; DIST_LIFT] THEN
+  MESON_TAC[REAL_LET_TRANS; dist; REAL_ABS_SUB_INFNORM; INFNORM_LE_NORM]);;
+
+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`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_LIFT_PRODUCT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_AT_WITHIN_INV]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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`,
+  REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED; CLOSED_PCROSS_EQ;
+              BOUNDED_PCROSS_EQ] THEN
+  MESON_TAC[]);;
+
+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]]);;
+
+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`,
+  SIMP_TAC[CONTINUOUS_ON; LIM_PASTECART]);;
+
+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`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* 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_TRANSLATION_EQ = prove
+ (`!a s. compact (IMAGE (\x:real^N. a + x) s) <=> compact s`,
+  REWRITE_TAC[COMPACT_EQ_HEINE_BOREL] THEN GEOM_TRANSLATE_TAC[]);;
+
+let COMPACT_TRANSLATION = prove
+ (`!s a:real^N. compact s ==> compact (IMAGE (\x. a + x) s)`,
+  REWRITE_TAC[COMPACT_TRANSLATION_EQ]);;
+
+add_translation_invariants [COMPACT_TRANSLATION_EQ];;
+
+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 LEBESGUE_COVERING_LEMMA = prove
+ (`!s:real^N->bool c.
+        compact s /\ ~(c = {}) /\ s SUBSET UNIONS c /\ (!b. b IN c ==> open b)
+        ==> ?d. &0 < d /\
+                !t. t SUBSET s /\ diameter t <= d
+                    ==> ?b. b IN c /\ t SUBSET b`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP HEINE_BOREL_LEMMA) THEN
+  DISCH_THEN(MP_TAC o SPEC `c:(real^N->bool)->bool`) THEN ASM_SIMP_TAC[] THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `e:real` THEN
+  STRIP_TAC THEN EXISTS_TAC `e / &2` THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPEC `t:real^N->bool` DIAMETER_SUBSET_CBALL_NONEMPTY) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[BOUNDED_SUBSET; COMPACT_IMP_BOUNDED]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `x:real^N` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; MATCH_MP_TAC MONO_EXISTS] THEN
+  X_GEN_TAC `b:real^N->bool` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `cball(x:real^N,diameter(t:real^N->bool))` THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `ball(x:real^N,e)` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[SUBSET; IN_CBALL; IN_BALL] THEN
+  MAP_EVERY UNDISCH_TAC [`&0 < e`; `diameter(t:real^N->bool) <= e / &2`] THEN
+  NORM_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Related results with closure as the conclusion.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let CLOSED_SCALING = prove
+ (`!s:real^N->bool c. closed s ==> closed (IMAGE (\x. c % x) s)`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s :real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[CLOSED_EMPTY; IMAGE_CLAUSES] THEN
+  ASM_CASES_TAC `c = &0` THENL
+   [SUBGOAL_THEN `IMAGE (\x:real^N. c % x) s = {(vec 0)}`
+     (fun th -> REWRITE_TAC[th; CLOSED_SING]) THEN
+    ASM_REWRITE_TAC[EXTENSION; IN_IMAGE; IN_SING; VECTOR_MUL_LZERO] THEN
+    ASM_MESON_TAC[MEMBER_NOT_EMPTY];
+    ALL_TAC] THEN
+  REWRITE_TAC[CLOSED_SEQUENTIAL_LIMITS; IN_IMAGE; SKOLEM_THM] THEN
+  STRIP_TAC THEN X_GEN_TAC `x:num->real^N` THEN X_GEN_TAC `l:real^N` THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `y:num->real^N` MP_TAC) THEN
+  REWRITE_TAC[FORALL_AND_THM] THEN STRIP_TAC THEN
+  EXISTS_TAC `inv(c) % l :real^N` THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; VECTOR_MUL_LID] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN EXISTS_TAC `\n:num. inv(c) % x n:real^N` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; VECTOR_MUL_LID];
+    MATCH_MP_TAC LIM_CMUL THEN
+    FIRST_ASSUM(fun th -> REWRITE_TAC[SYM(SPEC_ALL th)]) THEN
+    ASM_REWRITE_TAC[ETA_AX]]);;
+
+let CLOSED_NEGATIONS = prove
+ (`!s:real^N->bool. closed s ==> closed (IMAGE (--) s)`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `IMAGE (--) s = IMAGE (\x:real^N. --(&1) % x) s`
+  SUBST1_TAC THEN SIMP_TAC[CLOSED_SCALING] THEN
+  REWRITE_TAC[VECTOR_ARITH `--(&1) % x = --x`] THEN REWRITE_TAC[ETA_AX]);;
+
+let COMPACT_CLOSED_SUMS = prove
+ (`!s:real^N->bool t.
+        compact s /\ closed t ==> closed {x + y | x IN s /\ y IN t}`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[compact; IN_ELIM_THM; CLOSED_SEQUENTIAL_LIMITS] THEN
+  STRIP_TAC THEN X_GEN_TAC `f:num->real^N` THEN X_GEN_TAC `l:real^N` THEN
+  REWRITE_TAC[SKOLEM_THM; FORALL_AND_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:num->real^N` MP_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:num->real^N` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o check(is_imp o concl) o SPEC `a:num->real^N`) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `la:real^N` (X_CHOOSE_THEN `sub:num->num`
+        STRIP_ASSUME_TAC)) THEN
+  MAP_EVERY EXISTS_TAC [`la:real^N`; `l - la:real^N`] THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH `a + (b - a) = b:real^N`] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  EXISTS_TAC `\n. (f o (sub:num->num)) n - (a o sub) n:real^N` THEN
+  CONJ_TAC THENL [ASM_REWRITE_TAC[VECTOR_ADD_SUB; o_THM]; ALL_TAC] THEN
+  MATCH_MP_TAC LIM_SUB THEN ASM_SIMP_TAC[LIM_SUBSEQUENCE; ETA_AX]);;
+
+let CLOSED_COMPACT_SUMS = prove
+ (`!s:real^N->bool t.
+        closed s /\ compact t ==> closed {x + y | x IN s /\ y IN t}`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `{x + y:real^N | x IN s /\ y IN t} = {y + x | y IN t /\ x IN s}`
+  SUBST1_TAC THEN  SIMP_TAC[COMPACT_CLOSED_SUMS] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN MESON_TAC[VECTOR_ADD_SYM]);;
+
+let COMPACT_CLOSED_DIFFERENCES = prove
+ (`!s:real^N->bool t.
+        compact s /\ closed t ==> closed {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_CLOSED_SUMS; CLOSED_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 CLOSED_COMPACT_DIFFERENCES = prove
+ (`!s:real^N->bool t.
+        closed s /\ compact t ==> closed {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; CLOSED_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 CLOSED_TRANSLATION_EQ = prove
+ (`!a s. closed (IMAGE (\x:real^N. a + x) s) <=> closed s`,
+  REWRITE_TAC[closed] THEN GEOM_TRANSLATE_TAC[]);;
+
+let CLOSED_TRANSLATION = prove
+ (`!s a:real^N. closed s ==> closed (IMAGE (\x. a + x) s)`,
+  REWRITE_TAC[CLOSED_TRANSLATION_EQ]);;
+
+add_translation_invariants [CLOSED_TRANSLATION_EQ];;
+
+let COMPLETE_TRANSLATION_EQ = prove
+ (`!a s. complete(IMAGE (\x:real^N. a + x) s) <=> complete s`,
+  REWRITE_TAC[COMPLETE_EQ_CLOSED; CLOSED_TRANSLATION_EQ]);;
+
+add_translation_invariants [COMPLETE_TRANSLATION_EQ];;
+
+let TRANSLATION_UNIV = prove
+ (`!a. IMAGE (\x. a + x) (:real^N) = (:real^N)`,
+  CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN GEOM_TRANSLATE_TAC[]);;
+
+let TRANSLATION_DIFF = prove
+ (`!s t:real^N->bool.
+        IMAGE (\x. a + x) (s DIFF t) =
+        (IMAGE (\x. a + x) s) DIFF (IMAGE (\x. a + x) t)`,
+  REWRITE_TAC[EXTENSION; IN_DIFF; IN_IMAGE] THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `x:real^N = a + y <=> y = x - a`] THEN
+  REWRITE_TAC[UNWIND_THM2]);;
+
+let CLOSURE_TRANSLATION = prove
+ (`!a s. closure(IMAGE (\x:real^N. a + x) s) = IMAGE (\x. a + x) (closure s)`,
+  REWRITE_TAC[CLOSURE_INTERIOR] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [CLOSURE_TRANSLATION];;
+
+let FRONTIER_TRANSLATION = prove
+ (`!a s. frontier(IMAGE (\x:real^N. a + x) s) = IMAGE (\x. a + x) (frontier s)`,
+  REWRITE_TAC[frontier] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [FRONTIER_TRANSLATION];;
+
+(* ------------------------------------------------------------------------- *)
+(* Separation between points and sets.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let SEPARATE_POINT_CLOSED = prove
+ (`!s a:real^N.
+        closed s /\ ~(a IN s)
+        ==> ?d. &0 < d /\ !x. x IN s ==> d <= dist(a,x)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [EXISTS_TAC `&1` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY; REAL_LT_01];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `a:real^N`] DISTANCE_ATTAINS_INF) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `b:real^N` THEN
+  STRIP_TAC THEN EXISTS_TAC `dist(a:real^N,b)` THEN
+  ASM_MESON_TAC[DIST_POS_LT]);;
+
+let SEPARATE_COMPACT_CLOSED = prove
+ (`!s t:real^N->bool.
+        compact s /\ closed t /\ s INTER t = {}
+        ==> ?d. &0 < d /\ !x y. x IN s /\ y IN t ==> d <= dist(x,y)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`{x - y:real^N | x IN s /\ y IN t}`; `vec 0:real^N`]
+                SEPARATE_POINT_CLOSED) THEN
+  ASM_SIMP_TAC[COMPACT_CLOSED_DIFFERENCES; IN_ELIM_THM] THEN
+  REWRITE_TAC[VECTOR_ARITH `vec 0 = x - y <=> x = y`] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MESON_TAC[NORM_ARITH `dist(vec 0,x - y) = dist(x,y)`]);;
+
+let SEPARATE_CLOSED_COMPACT = prove
+ (`!s t:real^N->bool.
+        closed s /\ compact t /\ s INTER t = {}
+        ==> ?d. &0 < d /\ !x y. x IN s /\ y IN t ==> d <= dist(x,y)`,
+  ONCE_REWRITE_TAC[DIST_SYM; INTER_COMM] THEN
+  MESON_TAC[SEPARATE_COMPACT_CLOSED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Representing sets as the union of a chain of compact sets.                *)
+(* ------------------------------------------------------------------------- *)
+
+let CLOSED_UNION_COMPACT_SUBSETS = prove
+ (`!s. closed s
+       ==> ?f:num->real^N->bool.
+                (!n. compact(f n)) /\
+                (!n. (f n) SUBSET s) /\
+                (!n. (f n) SUBSET f(n + 1)) /\
+                UNIONS {f n | n IN (:num)} = s /\
+                (!k. compact k /\ k SUBSET s
+                     ==> ?N. !n. n >= N ==> k SUBSET (f n))`,
+  REPEAT STRIP_TAC THEN
+  EXISTS_TAC `\n. s INTER cball(vec 0:real^N,&n)` THEN
+  ASM_SIMP_TAC[INTER_SUBSET; COMPACT_CBALL; CLOSED_INTER_COMPACT] THEN
+  REPEAT CONJ_TAC THENL
+   [GEN_TAC THEN MATCH_MP_TAC(SET_RULE
+     `t SUBSET u ==> s INTER t SUBSET s INTER u`) THEN
+    REWRITE_TAC[SUBSET_BALLS; DIST_REFL; GSYM REAL_OF_NUM_ADD] THEN
+    REAL_ARITH_TAC;
+    REWRITE_TAC[EXTENSION; UNIONS_GSPEC; IN_ELIM_THM; IN_UNIV; IN_INTER] THEN
+    X_GEN_TAC `x:real^N` THEN REWRITE_TAC[IN_CBALL_0] THEN
+    MESON_TAC[REAL_ARCH_SIMPLE];
+    X_GEN_TAC `k:real^N->bool` THEN SIMP_TAC[SUBSET_INTER] THEN
+    REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_IMP_BOUNDED) THEN DISCH_THEN
+     (MP_TAC o SPEC `vec 0:real^N` o MATCH_MP BOUNDED_SUBSET_CBALL) THEN
+    DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPEC `r:real` REAL_ARCH_SIMPLE) THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `N:num` THEN REWRITE_TAC[GSYM REAL_OF_NUM_GE] THEN
+
+    REPEAT STRIP_TAC THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        SUBSET_TRANS)) THEN
+    REWRITE_TAC[SUBSET_BALLS; DIST_REFL] THEN ASM_REAL_ARITH_TAC]);;
+
+let OPEN_UNION_COMPACT_SUBSETS = prove
+ (`!s. open s
+       ==> ?f:num->real^N->bool.
+                (!n. compact(f n)) /\
+                (!n. (f n) SUBSET s) /\
+                (!n. (f n) SUBSET interior(f(n + 1))) /\
+                UNIONS {f n | n IN (:num)} = s /\
+                (!k. compact k /\ k SUBSET s
+                     ==> ?N. !n. n >= N ==> k SUBSET (f n))`,
+  GEN_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [DISCH_TAC THEN EXISTS_TAC `(\n. {}):num->real^N->bool` THEN
+    ASM_SIMP_TAC[EMPTY_SUBSET; SUBSET_EMPTY; COMPACT_EMPTY] THEN
+    REWRITE_TAC[EXTENSION; UNIONS_GSPEC; IN_ELIM_THM; NOT_IN_EMPTY];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `a:real^N`) THEN STRIP_TAC] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!f. p1 f /\ p3 f /\ p4 f ==> p5 f) /\
+    (?f. p1 f /\ p2 f /\ p3 f /\ (p2 f ==> p4 f))
+    ==> ?f. p1 f /\ p2 f /\ p3 f /\ p4 f /\ p5 f`) THEN
+  CONJ_TAC THENL
+   [X_GEN_TAC `f:num->real^N->bool` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    X_GEN_TAC `k:real^N->bool` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [COMPACT_EQ_HEINE_BOREL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `{interior(f n):real^N->bool | n IN (:num)}`) THEN
+    REWRITE_TAC[FORALL_IN_GSPEC; OPEN_INTERIOR] THEN ANTS_TAC THENL
+     [FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        SUBSET_TRANS)) THEN
+      REWRITE_TAC[SUBSET; UNIONS_GSPEC; IN_ELIM_THM] THEN ASM SET_TAC[];
+      ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> q /\ p /\ r`] THEN
+      REWRITE_TAC[SIMPLE_IMAGE; EXISTS_FINITE_SUBSET_IMAGE] THEN
+      REWRITE_TAC[SUBSET_UNIV] THEN
+      DISCH_THEN(X_CHOOSE_THEN `i:num->bool` STRIP_ASSUME_TAC) THEN
+      FIRST_ASSUM(MP_TAC o SPEC `\n:num. n` o
+        MATCH_MP UPPER_BOUND_FINITE_SET) THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+      REWRITE_TAC[GE] 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]
+        SUBSET_TRANS)) THEN
+      REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_IMAGE] THEN
+      X_GEN_TAC `m:num` THEN DISCH_TAC THEN MATCH_MP_TAC SUBSET_TRANS THEN
+      EXISTS_TAC `(f:num->real^N->bool) m` THEN
+      REWRITE_TAC[INTERIOR_SUBSET] THEN
+      SUBGOAL_THEN `!m n. m <= n ==> (f:num->real^N->bool) m SUBSET f n`
+       (fun th -> ASM_MESON_TAC[th; LE_TRANS]) THEN
+      MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN
+      ASM_MESON_TAC[SUBSET; ADD1; INTERIOR_SUBSET]];
+    EXISTS_TAC
+     `\n. cball(a,&n) DIFF
+         {x + e | x IN (:real^N) DIFF s /\ e IN ball(vec 0,inv(&n + &1))}` THEN
+    REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [X_GEN_TAC `n:num` THEN MATCH_MP_TAC COMPACT_DIFF THEN
+      SIMP_TAC[COMPACT_CBALL; OPEN_SUMS; OPEN_BALL];
+      GEN_TAC THEN MATCH_MP_TAC(SET_RULE
+       `(UNIV DIFF s) SUBSET t ==> c DIFF t SUBSET s`) THEN
+      REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+      MAP_EVERY EXISTS_TAC [`x:real^N`; `vec 0:real^N`] THEN
+      ASM_REWRITE_TAC[VECTOR_ADD_RID; CENTRE_IN_BALL; REAL_LT_INV_EQ] THEN
+      REAL_ARITH_TAC;
+      GEN_TAC THEN REWRITE_TAC[INTERIOR_DIFF] THEN MATCH_MP_TAC(SET_RULE
+       `s SUBSET s' /\ t' SUBSET t ==> (s DIFF t) SUBSET (s' DIFF t')`) THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[INTERIOR_CBALL; SUBSET; IN_BALL; IN_CBALL] THEN
+        REWRITE_TAC[GSYM REAL_OF_NUM_ADD] THEN REAL_ARITH_TAC;
+        MATCH_MP_TAC SUBSET_TRANS THEN
+        EXISTS_TAC `{x + e | x IN (:real^N) DIFF s /\
+                             e IN cball(vec 0,inv(&n + &2))}` THEN
+        CONJ_TAC THENL
+         [MATCH_MP_TAC CLOSURE_MINIMAL THEN
+          ASM_SIMP_TAC[CLOSED_COMPACT_SUMS; COMPACT_CBALL;
+                       GSYM OPEN_CLOSED] THEN
+          MATCH_MP_TAC(SET_RULE
+           `t SUBSET t'
+            ==> {f x y | x IN s /\ y IN t} SUBSET
+                {f x y | x IN s /\ y IN t'}`) THEN
+          REWRITE_TAC[SUBSET; IN_BALL; IN_CBALL; GSYM REAL_OF_NUM_ADD] THEN
+          REAL_ARITH_TAC;
+          MATCH_MP_TAC(SET_RULE
+           `t SUBSET t'
+            ==> {f x y | x IN s /\ y IN t} SUBSET
+                {f x y | x IN s /\ y IN t'}`) THEN
+          REWRITE_TAC[SUBSET; IN_BALL; IN_CBALL; GSYM REAL_OF_NUM_ADD] THEN
+          GEN_TAC THEN MATCH_MP_TAC(REAL_ARITH
+           `a < b ==> x <= a ==> x < b`) THEN
+          MATCH_MP_TAC REAL_LT_INV2 THEN REAL_ARITH_TAC]];
+      DISCH_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+      ASM_REWRITE_TAC[UNIONS_SUBSET; FORALL_IN_GSPEC] THEN
+      REWRITE_TAC[SUBSET; UNIONS_GSPEC; IN_UNIV; IN_ELIM_THM] THEN
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN REWRITE_TAC[IN_DIFF] THEN
+      REWRITE_TAC[IN_ELIM_THM; IN_UNIV; IN_BALL_0] THEN
+      REWRITE_TAC[VECTOR_ARITH `x:real^N = y + e <=> e = x - y`] THEN
+      REWRITE_TAC[TAUT `(p /\ q) /\ r <=> r /\ p /\ q`; UNWIND_THM2] THEN
+      REWRITE_TAC[MESON[] `~(?x. ~P x /\ Q x) <=> !x. Q x ==> P x`] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+      DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+      ASM_REWRITE_TAC[SUBSET; IN_BALL; dist] THEN
+      DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+      FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [REAL_ARCH_INV]) THEN
+      DISCH_THEN(X_CHOOSE_THEN `N1:num` STRIP_ASSUME_TAC) THEN
+      MP_TAC(ISPEC `norm(x - a:real^N)` REAL_ARCH_SIMPLE) THEN
+      DISCH_THEN(X_CHOOSE_TAC `N2:num`) THEN EXISTS_TAC `N1 + N2:num` THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[IN_CBALL] THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+        UNDISCH_TAC `norm(x - a:real^N) <= &N2` THEN
+        REWRITE_TAC[dist; GSYM REAL_OF_NUM_ADD] THEN REAL_ARITH_TAC;
+        REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+        SUBGOAL_THEN `inv(&(N1 + N2) + &1) <= inv(&N1)` MP_TAC THENL
+         [MATCH_MP_TAC REAL_LE_INV2 THEN
+          ASM_SIMP_TAC[REAL_OF_NUM_LT; LE_1] THEN
+          REWRITE_TAC[GSYM REAL_OF_NUM_ADD] THEN REAL_ARITH_TAC;
+          ASM_REAL_ARITH_TAC]]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A cute way of denoting open and closed intervals using overloading.       *)
+(* ------------------------------------------------------------------------- *)
+
+let open_interval = new_definition
+  `open_interval(a:real^N,b:real^N) =
+        {x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
+                        ==> a$i < x$i /\ x$i < b$i}`;;
+
+let closed_interval = new_definition
+  `closed_interval(l:(real^N#real^N)list) =
+         {x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
+                         ==> FST(HD l)$i <= x$i /\ x$i <= SND(HD l)$i}`;;
+
+make_overloadable "interval" `:A`;;
+
+overload_interface("interval",`open_interval`);;
+overload_interface("interval",`closed_interval`);;
+
+let interval = prove
+ (`(interval (a,b) = {x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
+                                     ==> a$i < x$i /\ x$i < b$i}) /\
+   (interval [a,b] = {x:real^N | !i. 1 <= i /\ i <= dimindex(:N)
+                                     ==> a$i <= x$i /\ x$i <= b$i})`,
+  REWRITE_TAC[open_interval; closed_interval; HD; FST; SND]);;
+
+let IN_INTERVAL = prove
+ (`(!x:real^N.
+        x IN interval (a,b) <=>
+                !i. 1 <= i /\ i <= dimindex(:N)
+                    ==> a$i < x$i /\ x$i < b$i) /\
+   (!x:real^N.
+        x IN interval [a,b] <=>
+                !i. 1 <= i /\ i <= dimindex(:N)
+                    ==> a$i <= x$i /\ x$i <= b$i)`,
+  REWRITE_TAC[interval; IN_ELIM_THM]);;
+
+let IN_INTERVAL_REFLECT = prove
+ (`(!a b x. (--x) IN interval[--b,--a] <=> x IN interval[a,b]) /\
+   (!a b x. (--x) IN interval(--b,--a) <=> x IN interval(a,b))`,
+  SIMP_TAC[IN_INTERVAL; REAL_LT_NEG2; REAL_LE_NEG2; VECTOR_NEG_COMPONENT] THEN
+  MESON_TAC[]);;
+
+let REFLECT_INTERVAL = prove
+ (`(!a b:real^N. IMAGE (--) (interval[a,b]) = interval[--b,--a]) /\
+   (!a b:real^N. IMAGE (--) (interval(a,b)) = interval(--b,--a))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  REWRITE_TAC[IN_INTERVAL_REFLECT] THEN MESON_TAC[VECTOR_NEG_NEG]);;
+
+let INTERVAL_EQ_EMPTY = prove
+ (`((interval [a:real^N,b] = {}) <=>
+    ?i. 1 <= i /\ i <= dimindex(:N) /\ b$i < a$i) /\
+   ((interval (a:real^N,b) = {}) <=>
+    ?i. 1 <= i /\ i <= dimindex(:N) /\ b$i <= a$i)`,
+  REWRITE_TAC[EXTENSION; IN_INTERVAL; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; GSYM CONJ_ASSOC] THEN
+  CONJ_TAC THEN EQ_TAC THENL
+   [MESON_TAC[REAL_LE_REFL; REAL_NOT_LE];
+    MESON_TAC[REAL_LE_TRANS; REAL_NOT_LE];
+    ALL_TAC;
+    MESON_TAC[REAL_LT_TRANS; REAL_NOT_LT]] THEN
+  SUBGOAL_THEN `!a b. ?c. a < b ==> a < c /\ c < b`
+  (MP_TAC o REWRITE_RULE[SKOLEM_THM]) THENL
+   [MESON_TAC[REAL_LT_BETWEEN]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_TAC `mid:real->real->real`) THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `(lambda i. mid ((a:real^N)$i) ((b:real^N)$i)):real^N`) THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> ~(a /\ b ==> ~c)`] THEN
+  SIMP_TAC[LAMBDA_BETA] THEN ASM_MESON_TAC[REAL_NOT_LT]);;
+
+let INTERVAL_NE_EMPTY = prove
+ (`(~(interval [a:real^N,b] = {}) <=>
+    !i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= b$i) /\
+   (~(interval (a:real^N,b) = {}) <=>
+    !i. 1 <= i /\ i <= dimindex(:N) ==> a$i < b$i)`,
+  REWRITE_TAC[INTERVAL_EQ_EMPTY] THEN MESON_TAC[REAL_NOT_LE]);;
+
+let SUBSET_INTERVAL_IMP = prove
+ (`((!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= c$i /\ d$i <= b$i)
+    ==> interval[c,d] SUBSET interval[a:real^N,b]) /\
+   ((!i. 1 <= i /\ i <= dimindex(:N) ==> a$i < c$i /\ d$i < b$i)
+    ==> interval[c,d] SUBSET interval(a:real^N,b)) /\
+   ((!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= c$i /\ d$i <= b$i)
+    ==> interval(c,d) SUBSET interval[a:real^N,b]) /\
+   ((!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= c$i /\ d$i <= b$i)
+    ==> interval(c,d) SUBSET interval(a:real^N,b))`,
+  REWRITE_TAC[SUBSET; IN_INTERVAL] THEN REPEAT CONJ_TAC THEN
+  DISCH_TAC THEN GEN_TAC THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[IMP_IMP; AND_FORALL_THM] THEN MATCH_MP_TAC MONO_FORALL THEN
+  GEN_TAC THEN DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let INTERVAL_SING = prove
+ (`interval[a,a] = {a} /\ interval(a,a) = {}`,
+  REWRITE_TAC[EXTENSION; IN_SING; NOT_IN_EMPTY; IN_INTERVAL] THEN
+  REWRITE_TAC[REAL_LE_ANTISYM; REAL_LT_ANTISYM; CART_EQ; EQ_SYM_EQ] THEN
+  MESON_TAC[DIMINDEX_GE_1; LE_REFL]);;
+
+let SUBSET_INTERVAL = prove
+ (`(interval[c,d] SUBSET interval[a:real^N,b] <=>
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> c$i <= d$i)
+        ==> (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= c$i /\ d$i <= b$i)) /\
+   (interval[c,d] SUBSET interval(a:real^N,b) <=>
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> c$i <= d$i)
+        ==> (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i < c$i /\ d$i < b$i)) /\
+   (interval(c,d) SUBSET interval[a:real^N,b] <=>
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> c$i < d$i)
+        ==> (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= c$i /\ d$i <= b$i)) /\
+   (interval(c,d) SUBSET interval(a:real^N,b) <=>
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> c$i < d$i)
+        ==> (!i. 1 <= i /\ i <= dimindex(:N) ==> a$i <= c$i /\ d$i <= b$i))`,
+  let lemma = prove
+   (`(!x:real^N. (!i. 1 <= i /\ i <= dimindex(:N) ==> Q i (x$i))
+                 ==> (!i. 1 <= i /\ i <= dimindex(:N) ==> R i (x$i)))
+     ==> (!i. 1 <= i /\ i <= dimindex(:N) ==> ?y. Q i y)
+         ==> !i y. 1 <= i /\ i <= dimindex(:N) /\ Q i y ==> R i y`,
+    DISCH_TAC THEN REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `f:num->real` STRIP_ASSUME_TAC) THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o
+     SPEC `(lambda j. if j = i then y else f j):real^N`) THEN
+    SIMP_TAC[LAMBDA_BETA] THEN ASM_MESON_TAC[]) in
+  REPEAT STRIP_TAC THEN
+  (MATCH_MP_TAC(TAUT
+    `(~q ==> p) /\ (q ==> (p <=> r)) ==> (p <=> q ==> r)`) THEN
+   CONJ_TAC THENL
+    [DISCH_TAC THEN MATCH_MP_TAC(SET_RULE `s = {} ==> s SUBSET t`) THEN
+     REWRITE_TAC[INTERVAL_EQ_EMPTY] THEN ASM_MESON_TAC[REAL_NOT_LT];
+     ALL_TAC] THEN
+   DISCH_TAC THEN EQ_TAC THEN REWRITE_TAC[SUBSET_INTERVAL_IMP] THEN
+   REWRITE_TAC[SUBSET; IN_INTERVAL] THEN
+   DISCH_THEN(MP_TAC o MATCH_MP lemma) THEN ANTS_TAC THENL
+    [ASM_MESON_TAC[REAL_LT_BETWEEN; REAL_LE_BETWEEN]; ALL_TAC] THEN
+   MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+   DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+   FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
+   ASM_REWRITE_TAC[] THEN POP_ASSUM_LIST(K ALL_TAC) THEN STRIP_TAC)
+  THENL
+   [ASM_MESON_TAC[REAL_LE_TRANS; REAL_LE_REFL];
+    ASM_MESON_TAC[REAL_LE_TRANS; REAL_LE_REFL];
+    ALL_TAC; ALL_TAC] THEN
+  (REPEAT STRIP_TAC THENL
+    [FIRST_X_ASSUM(MP_TAC o SPEC
+      `((c:real^N)$i + min ((a:real^N)$i) ((d:real^N)$i)) / &2`) THEN
+     POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
+     FIRST_X_ASSUM(MP_TAC o SPEC
+      `(max ((b:real^N)$i) ((c:real^N)$i) + (d:real^N)$i) / &2`) THEN
+     POP_ASSUM MP_TAC THEN REAL_ARITH_TAC]));;
+
+let DISJOINT_INTERVAL = prove
+ (`!a b c d:real^N.
+        (interval[a,b] INTER interval[c,d] = {} <=>
+          ?i. 1 <= i /\ i <= dimindex(:N) /\
+              (b$i < a$i \/ d$i < c$i \/ b$i < c$i \/ d$i < a$i)) /\
+        (interval[a,b] INTER interval(c,d) = {} <=>
+          ?i. 1 <= i /\ i <= dimindex(:N) /\
+              (b$i < a$i \/ d$i <= c$i \/ b$i <= c$i \/ d$i <= a$i)) /\
+        (interval(a,b) INTER interval[c,d] = {} <=>
+          ?i. 1 <= i /\ i <= dimindex(:N) /\
+              (b$i <= a$i \/ d$i < c$i \/ b$i <= c$i \/ d$i <= a$i)) /\
+        (interval(a,b) INTER interval(c,d) = {} <=>
+          ?i. 1 <= i /\ i <= dimindex(:N) /\
+              (b$i <= a$i \/ d$i <= c$i \/ b$i <= c$i \/ d$i <= a$i))`,
+  REWRITE_TAC[EXTENSION; IN_INTER; IN_INTERVAL; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[AND_FORALL_THM; NOT_FORALL_THM] THEN
+  REWRITE_TAC[TAUT `~((p ==> q) /\ (p ==> r)) <=> p /\ (~q \/ ~r)`] THEN
+  REWRITE_TAC[DE_MORGAN_THM] THEN REPEAT STRIP_TAC THEN
+  (EQ_TAC THENL
+    [DISCH_THEN(MP_TAC o SPEC
+      `(lambda i. (max ((a:real^N)$i) ((c:real^N)$i) +
+                   min ((b:real^N)$i) ((d:real^N)$i)) / &2):real^N`) THEN
+     MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+     DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+     ASM_SIMP_TAC[LAMBDA_BETA] THEN REAL_ARITH_TAC;
+     DISCH_THEN(fun th -> GEN_TAC THEN MP_TAC th) THEN
+     MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN SIMP_TAC[] THEN
+     REAL_ARITH_TAC]));;
+
+let ENDS_IN_INTERVAL = prove
+ (`(!a b. a IN interval[a,b] <=> ~(interval[a,b] = {})) /\
+   (!a b. b IN interval[a,b] <=> ~(interval[a,b] = {})) /\
+   (!a b. ~(a IN interval(a,b))) /\
+   (!a b. ~(b IN interval(a,b)))`,
+  REWRITE_TAC[IN_INTERVAL; INTERVAL_NE_EMPTY] THEN
+  REWRITE_TAC[REAL_LE_REFL; REAL_LT_REFL] THEN
+  MESON_TAC[DIMINDEX_GE_1; LE_REFL]);;
+
+let ENDS_IN_UNIT_INTERVAL = prove
+ (`vec 0 IN interval[vec 0,vec 1] /\
+   vec 1 IN interval[vec 0,vec 1] /\
+   ~(vec 0 IN interval(vec 0,vec 1)) /\
+   ~(vec 1 IN interval(vec 0,vec 1))`,
+  REWRITE_TAC[ENDS_IN_INTERVAL; INTERVAL_NE_EMPTY; VEC_COMPONENT] THEN
+  REWRITE_TAC[REAL_POS]);;
+
+let INTER_INTERVAL = prove
+ (`interval[a,b] INTER interval[c,d] =
+        interval[(lambda i. max (a$i) (c$i)),(lambda i. min (b$i) (d$i))]`,
+  REWRITE_TAC[EXTENSION; IN_INTER; IN_INTERVAL] THEN
+  SIMP_TAC[LAMBDA_BETA; REAL_MAX_LE; REAL_LE_MIN] THEN MESON_TAC[]);;
+
+let INTERVAL_OPEN_SUBSET_CLOSED = prove
+ (`!a b. interval(a,b) SUBSET interval[a,b]`,
+  REWRITE_TAC[SUBSET; IN_INTERVAL] THEN MESON_TAC[REAL_LT_IMP_LE]);;
+
+let OPEN_INTERVAL_LEMMA = prove
+ (`!a b x. a < x /\ x < b
+           ==> ?d. &0 < d /\ !x'. abs(x' - x) < d ==> a < x' /\ x' < b`,
+  REPEAT STRIP_TAC THEN
+  EXISTS_TAC `min (x - a) (b - x)` THEN REWRITE_TAC[REAL_LT_MIN] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let OPEN_INTERVAL = prove
+ (`!a:real^N b. open(interval (a,b))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[open_def; interval; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `!i. 1 <= i /\ i <= dimindex(:N)
+                    ==> ?d. &0 < d /\
+                            !x'. abs(x' - (x:real^N)$i) < d
+                                 ==> (a:real^N)$i < x' /\ x' < (b:real^N)$i`
+  MP_TAC THENL [ASM_SIMP_TAC[OPEN_INTERVAL_LEMMA]; ALL_TAC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:num->real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `inf (IMAGE d (1..dimindex(:N)))` THEN
+  SIMP_TAC[REAL_LT_INF_FINITE; FINITE_IMAGE; FINITE_NUMSEG;
+           IMAGE_EQ_EMPTY; NOT_INSERT_EMPTY; NUMSEG_EMPTY;
+           ARITH_RULE `n < 1 <=> (n = 0)`; DIMINDEX_NONZERO] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; IN_NUMSEG; dist] THEN
+  ASM_MESON_TAC[COMPONENT_LE_NORM; REAL_LET_TRANS; VECTOR_SUB_COMPONENT]);;
+
+let CLOSED_INTERVAL = prove
+ (`!a:real^N b. closed(interval [a,b])`,
+  REWRITE_TAC[CLOSED_LIMPT; LIMPT_APPROACHABLE; IN_INTERVAL] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o SPEC `(a:real^N)$i - (x:real^N)$i`);
+    FIRST_X_ASSUM(MP_TAC o SPEC `(x:real^N)$i - (b:real^N)$i`)] THEN
+  ASM_REWRITE_TAC[REAL_SUB_LT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `z:real^N` MP_TAC) THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[dist; REAL_NOT_LT] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `abs((z - x :real^N)$i)` THEN
+  ASM_SIMP_TAC[COMPONENT_LE_NORM] THEN
+  ASM_SIMP_TAC[VECTOR_SUB_COMPONENT] THEN
+  ASM_SIMP_TAC[REAL_ARITH `x < a /\ a <= z ==> a - x <= abs(z - x)`;
+               REAL_ARITH `z <= b /\ b < x ==> x - b <= abs(z - x)`]);;
+
+let INTERIOR_CLOSED_INTERVAL = prove
+ (`!a:real^N b. interior(interval [a,b]) = interval (a,b)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC INTERIOR_MAXIMAL THEN
+    REWRITE_TAC[INTERVAL_OPEN_SUBSET_CLOSED; OPEN_INTERVAL]] THEN
+  REWRITE_TAC[interior; SUBSET; IN_INTERVAL; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^N->bool` STRIP_ASSUME_TAC) THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[REAL_LT_LE] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [open_def]) THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THENL
+   [(let t = `x - (e / &2) % basis i :real^N` in
+     DISCH_THEN(MP_TAC o SPEC t) THEN FIRST_X_ASSUM(MP_TAC o SPEC t));
+    (let t = `x + (e / &2) % basis i :real^N` in
+     DISCH_THEN(MP_TAC o SPEC t) THEN FIRST_X_ASSUM(MP_TAC o SPEC t))] THEN
+  REWRITE_TAC[dist; VECTOR_ADD_SUB; VECTOR_ARITH `x - y - x = --y:real^N`] THEN
+  ASM_SIMP_TAC[NORM_MUL; NORM_BASIS; NORM_NEG; REAL_MUL_RID;
+               REAL_ARITH `&0 < e ==> abs(e / &2) < e`] THEN
+  MATCH_MP_TAC(TAUT `~b ==> (a ==> b) ==> ~a`) THEN
+  REWRITE_TAC[NOT_FORALL_THM] THEN EXISTS_TAC `i:num` THEN
+  ASM_SIMP_TAC[DE_MORGAN_THM; VECTOR_SUB_COMPONENT; VECTOR_ADD_COMPONENT] THENL
+   [DISJ1_TAC THEN REWRITE_TAC[REAL_ARITH `a <= a - b <=> ~(&0 < b)`];
+    DISJ2_TAC THEN REWRITE_TAC[REAL_ARITH `a + b <= a <=> ~(&0 < b)`]] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_COMPONENT; basis; LAMBDA_BETA; REAL_MUL_RID] THEN
+  ASM_REWRITE_TAC[REAL_HALF]);;
+
+let INTERIOR_INTERVAL = prove
+ (`(!a b. interior(interval[a,b]) = interval(a,b)) /\
+   (!a b. interior(interval(a,b)) = interval(a,b))`,
+  SIMP_TAC[INTERIOR_CLOSED_INTERVAL; INTERIOR_OPEN; OPEN_INTERVAL]);;
+
+let BOUNDED_CLOSED_INTERVAL = prove
+ (`!a b:real^N. bounded (interval [a,b])`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[bounded; interval] THEN
+  EXISTS_TAC `sum(1..dimindex(:N))
+                 (\i. abs((a:real^N)$i) + abs((b:real^N)$i))` THEN
+  X_GEN_TAC `x:real^N` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum(1..dimindex(:N)) (\i. abs((x:real^N)$i))` THEN
+  REWRITE_TAC[NORM_LE_L1] THEN MATCH_MP_TAC SUM_LE THEN
+  ASM_SIMP_TAC[FINITE_NUMSEG; IN_NUMSEG; REAL_ARITH
+   `a <= x /\ x <= b ==> abs(x) <= abs(a) + abs(b)`]);;
+
+let BOUNDED_INTERVAL = prove
+ (`(!a b. bounded (interval [a,b])) /\ (!a b. bounded (interval (a,b)))`,
+  MESON_TAC[BOUNDED_CLOSED_INTERVAL; BOUNDED_SUBSET;
+            INTERVAL_OPEN_SUBSET_CLOSED]);;
+
+let NOT_INTERVAL_UNIV = prove
+ (`(!a b. ~(interval[a,b] = UNIV)) /\
+   (!a b. ~(interval(a,b) = UNIV))`,
+  MESON_TAC[BOUNDED_INTERVAL; NOT_BOUNDED_UNIV]);;
+
+let COMPACT_INTERVAL = prove
+ (`!a b. compact (interval [a,b])`,
+  SIMP_TAC[COMPACT_EQ_BOUNDED_CLOSED; BOUNDED_INTERVAL; CLOSED_INTERVAL]);;
+
+let OPEN_INTERVAL_MIDPOINT = prove
+ (`!a b:real^N.
+        ~(interval(a,b) = {}) ==> (inv(&2) % (a + b)) IN interval(a,b)`,
+  REWRITE_TAC[INTERVAL_NE_EMPTY; IN_INTERVAL] THEN
+  SIMP_TAC[VECTOR_MUL_COMPONENT; VECTOR_ADD_COMPONENT] THEN
+  REPEAT GEN_TAC THEN MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let OPEN_CLOSED_INTERVAL_CONVEX = prove
+ (`!a b x y:real^N e.
+        x IN interval(a,b) /\ y IN interval[a,b] /\ &0 < e /\ e <= &1
+        ==> (e % x + (&1 - e) % y) IN interval(a,b)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC(TAUT
+   `(c /\ d ==> a /\ b ==> e) ==> a /\ b /\ c /\ d ==> e`) THEN
+  STRIP_TAC THEN REWRITE_TAC[IN_INTERVAL; AND_FORALL_THM] THEN
+  SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  MATCH_MP_TAC MONO_FORALL THEN
+  GEN_TAC THEN DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+  SUBST1_TAC(REAL_ARITH `(a:real^N)$i = e * a$i + (&1 - e) * a$i`) THEN
+  SUBST1_TAC(REAL_ARITH `(b:real^N)$i = e * b$i + (&1 - e) * b$i`) THEN
+  CONJ_TAC THEN MATCH_MP_TAC REAL_LTE_ADD2 THEN
+  ASM_SIMP_TAC[REAL_LT_LMUL_EQ; REAL_LE_LMUL; REAL_SUB_LE]);;
+
+let CLOSURE_OPEN_INTERVAL = prove
+ (`!a b:real^N.
+     ~(interval(a,b) = {}) ==> closure(interval(a,b)) = interval[a,b]`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CLOSURE_MINIMAL THEN
+    REWRITE_TAC[INTERVAL_OPEN_SUBSET_CLOSED; CLOSED_INTERVAL];
+    ALL_TAC] THEN
+  REWRITE_TAC[SUBSET; closure; IN_UNION] THEN X_GEN_TAC `x:real^N` THEN
+  DISCH_TAC THEN MATCH_MP_TAC(TAUT `(~b ==> c) ==> b \/ c`) THEN DISCH_TAC THEN
+  REWRITE_TAC[IN_ELIM_THM; LIMPT_SEQUENTIAL] THEN
+  ABBREV_TAC `(c:real^N) = inv(&2) % (a + b)` THEN
+  EXISTS_TAC `\n. (x:real^N) + inv(&n + &1) % (c - x)` THEN CONJ_TAC THENL
+   [X_GEN_TAC `n:num` THEN REWRITE_TAC[IN_DELETE] THEN
+    REWRITE_TAC[VECTOR_ARITH `x + a = x <=> a = vec 0`] THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0; REAL_INV_EQ_0] THEN
+    REWRITE_TAC[VECTOR_SUB_EQ; REAL_ARITH `~(&n + &1 = &0)`] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[OPEN_INTERVAL_MIDPOINT]] THEN
+    REWRITE_TAC[VECTOR_ARITH `x + a % (y - x) = a % y + (&1 - a) % x`] THEN
+    MATCH_MP_TAC OPEN_CLOSED_INTERVAL_CONVEX THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[OPEN_INTERVAL_MIDPOINT]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[REAL_LT_INV_EQ; REAL_ARITH `&0 < &n + &1`] THEN
+    MATCH_MP_TAC REAL_INV_LE_1 THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [VECTOR_ARITH `x:real^N = x + &0 % (c - x)`] THEN
+  MATCH_MP_TAC LIM_ADD THEN REWRITE_TAC[LIM_CONST] THEN
+  MATCH_MP_TAC LIM_VMUL THEN REWRITE_TAC[LIM_CONST] THEN
+  REWRITE_TAC[LIM_SEQUENTIALLY; o_THM; DIST_LIFT; REAL_SUB_RZERO] 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 X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+  REWRITE_TAC[REAL_ABS_INV] THEN MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `inv(&N)` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC REAL_LE_INV2 THEN UNDISCH_TAC `N:num <= n` THEN
+  UNDISCH_TAC `~(N = 0)` THEN
+  REWRITE_TAC[GSYM LT_NZ; GSYM REAL_OF_NUM_LE; GSYM REAL_OF_NUM_LT] THEN
+  REAL_ARITH_TAC);;
+
+let CLOSURE_INTERVAL = prove
+ (`(!a b. closure(interval[a,b]) = interval[a,b]) /\
+   (!a b. closure(interval(a,b)) =
+          if interval(a,b) = {} then {} else interval[a,b])`,
+  SIMP_TAC[CLOSURE_CLOSED; CLOSED_INTERVAL] THEN REPEAT GEN_TAC THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[CLOSURE_OPEN_INTERVAL; CLOSURE_EMPTY]);;
+
+let BOUNDED_SUBSET_OPEN_INTERVAL_SYMMETRIC = prove
+ (`!s:real^N->bool. bounded s ==> ?a. s SUBSET interval(--a,a)`,
+  REWRITE_TAC[BOUNDED_POS; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`s:real^N->bool`; `B:real`] THEN STRIP_TAC THEN
+  EXISTS_TAC `(lambda i. B + &1):real^N` THEN
+  REWRITE_TAC[SUBSET] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  SIMP_TAC[IN_INTERVAL; LAMBDA_BETA; REAL_BOUNDS_LT; VECTOR_NEG_COMPONENT] THEN
+  ASM_MESON_TAC[COMPONENT_LE_NORM;
+                REAL_ARITH `x <= y ==> a <= x ==> a < y + &1`]);;
+
+let BOUNDED_SUBSET_OPEN_INTERVAL = prove
+ (`!s:real^N->bool. bounded s ==> ?a b. s SUBSET interval(a,b)`,
+  MESON_TAC[BOUNDED_SUBSET_OPEN_INTERVAL_SYMMETRIC]);;
+
+let BOUNDED_SUBSET_CLOSED_INTERVAL_SYMMETRIC = prove
+ (`!s:real^N->bool. bounded s ==> ?a. s SUBSET interval[--a,a]`,
+  GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP BOUNDED_SUBSET_OPEN_INTERVAL_SYMMETRIC) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN
+  SIMP_TAC[IN_BALL; IN_INTERVAL; SUBSET; REAL_LT_IMP_LE]);;
+
+let BOUNDED_SUBSET_CLOSED_INTERVAL = prove
+ (`!s:real^N->bool. bounded s ==> ?a b. s SUBSET interval[a,b]`,
+  MESON_TAC[BOUNDED_SUBSET_CLOSED_INTERVAL_SYMMETRIC]);;
+
+let FRONTIER_CLOSED_INTERVAL = prove
+ (`!a b. frontier(interval[a,b]) = interval[a,b] DIFF interval(a,b)`,
+  SIMP_TAC[frontier; INTERIOR_CLOSED_INTERVAL; CLOSURE_CLOSED;
+           CLOSED_INTERVAL]);;
+
+let FRONTIER_OPEN_INTERVAL = prove
+ (`!a b. frontier(interval(a,b)) =
+                if interval(a,b) = {} then {}
+                else interval[a,b] DIFF interval(a,b)`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[FRONTIER_EMPTY] THEN
+  ASM_SIMP_TAC[frontier; CLOSURE_OPEN_INTERVAL; INTERIOR_OPEN;
+               OPEN_INTERVAL]);;
+
+let INTER_INTERVAL_MIXED_EQ_EMPTY = prove
+ (`!a b c d:real^N.
+        ~(interval(c,d) = {})
+        ==> (interval(a,b) INTER interval[c,d] = {} <=>
+             interval(a,b) INTER interval(c,d) = {})`,
+  SIMP_TAC[GSYM CLOSURE_OPEN_INTERVAL; OPEN_INTER_CLOSURE_EQ_EMPTY;
+           OPEN_INTERVAL]);;
+
+let INTERVAL_TRANSLATION = prove
+ (`(!c a b. interval[c + a,c + b] = IMAGE (\x. c + x) (interval[a,b])) /\
+   (!c a b. interval(c + a,c + b) = IMAGE (\x. c + x) (interval(a,b)))`,
+  REWRITE_TAC[interval] THEN CONJ_TAC THEN GEOM_TRANSLATE_TAC[] THEN
+  REWRITE_TAC[VECTOR_ADD_COMPONENT; REAL_LT_LADD; REAL_LE_LADD]);;
+
+add_translation_invariants
+ [CONJUNCT1 INTERVAL_TRANSLATION; CONJUNCT2 INTERVAL_TRANSLATION];;
+
+let EMPTY_AS_INTERVAL = prove
+ (`{} = interval[vec 1,vec 0]`,
+  SIMP_TAC[EXTENSION; NOT_IN_EMPTY; IN_INTERVAL; VEC_COMPONENT] THEN
+  GEN_TAC THEN DISCH_THEN(MP_TAC o SPEC `1`) THEN
+  REWRITE_TAC[LE_REFL; DIMINDEX_GE_1] THEN REAL_ARITH_TAC);;
+
+let UNIT_INTERVAL_NONEMPTY = prove
+ (`~(interval[vec 0:real^N,vec 1] = {}) /\
+   ~(interval(vec 0:real^N,vec 1) = {})`,
+  SIMP_TAC[INTERVAL_NE_EMPTY; VEC_COMPONENT; REAL_LT_01; REAL_POS]);;
+
+let IMAGE_STRETCH_INTERVAL = prove
+ (`!a b:real^N m.
+    IMAGE (\x. lambda k. m(k) * x$k) (interval[a,b]) =
+        if interval[a,b] = {} then {}
+        else interval[(lambda k. min (m(k) * a$k) (m(k) * b$k)):real^N,
+                      (lambda k. max (m(k) * a$k) (m(k) * b$k))]`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[IMAGE_CLAUSES] THEN
+  ASM_SIMP_TAC[EXTENSION; IN_IMAGE; CART_EQ; IN_INTERVAL; AND_FORALL_THM;
+               TAUT `(a ==> b) /\ (a ==> c) <=> a ==> b /\ c`;
+                LAMBDA_BETA; GSYM LAMBDA_SKOLEM] THEN
+  X_GEN_TAC `x:real^N` THEN MATCH_MP_TAC(MESON[]
+   `(!x. p x ==> (q x <=> r x))
+    ==> ((!x. p x ==> q x) <=> (!x. p x ==> r x))`) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INTERVAL_NE_EMPTY]) THEN
+  MATCH_MP_TAC MONO_FORALL THEN
+  X_GEN_TAC `k:num` THEN ASM_CASES_TAC `1 <= k /\ k <= dimindex(:N)` THEN
+  ASM_REWRITE_TAC[] THEN ASM_CASES_TAC `(m:num->real) k = &0` THENL
+   [ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_MAX_ACI; REAL_MIN_ACI] THEN
+    ASM_MESON_TAC[REAL_LE_ANTISYM; REAL_LE_REFL];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_FIELD `~(m = &0) ==> (x = m * y <=> y = x / m)`] THEN
+  REWRITE_TAC[UNWIND_THM2] THEN FIRST_X_ASSUM(DISJ_CASES_TAC o MATCH_MP
+   (REAL_ARITH `~(z = &0) ==> &0 < z \/ &0 < --z`))
+  THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[GSYM REAL_LE_NEG2] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    REWRITE_TAC[REAL_ARITH `--(max a b) = min (--a) (--b)`;
+                REAL_ARITH `--(min a b) = max (--a) (--b)`; real_div;
+                GSYM REAL_MUL_RNEG; GSYM REAL_INV_NEG] THEN
+    REWRITE_TAC[GSYM real_div]] THEN
+  ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ] THEN
+  ASM_SIMP_TAC[real_min; real_max; REAL_LE_LMUL_EQ; REAL_LE_RMUL_EQ] THEN
+  REAL_ARITH_TAC);;
+
+let INTERVAL_IMAGE_STRETCH_INTERVAL = prove
+ (`!a b:real^N m. ?u v:real^N.
+     IMAGE (\x. lambda k. m k * x$k) (interval[a,b]) = interval[u,v]`,
+  REWRITE_TAC[IMAGE_STRETCH_INTERVAL] THEN MESON_TAC[EMPTY_AS_INTERVAL]);;
+
+let CLOSED_INTERVAL_IMAGE_UNIT_INTERVAL = prove
+ (`!a b:real^N.
+        ~(interval[a,b] = {})
+        ==> interval[a,b] = IMAGE (\x:real^N. a + x)
+                                  (IMAGE (\x. (lambda i. (b$i - a$i) * x$i))
+                                         (interval[vec 0:real^N,vec 1]))`,
+  REWRITE_TAC[INTERVAL_NE_EMPTY] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[IMAGE_STRETCH_INTERVAL; UNIT_INTERVAL_NONEMPTY] THEN
+  REWRITE_TAC[GSYM INTERVAL_TRANSLATION] THEN
+  REWRITE_TAC[EXTENSION; IN_INTERVAL] THEN
+  SIMP_TAC[LAMBDA_BETA; VECTOR_ADD_COMPONENT; VEC_COMPONENT] THEN
+  GEN_TAC THEN REWRITE_TAC[REAL_MUL_RZERO; REAL_MUL_RID] THEN
+  MATCH_MP_TAC(MESON[] `(!x. P x <=> Q x) ==> ((!x. P x) <=> (!x. Q x))`) THEN
+  POP_ASSUM MP_TAC THEN MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `i:num` THEN
+  ASM_CASES_TAC `1 <= i /\ i <= dimindex(:N)` THEN ASM_REWRITE_TAC[] THEN
+  REAL_ARITH_TAC);;
+
+let SUMS_INTERVALS = prove
+ (`(!a b c d:real^N.
+        ~(interval[a,b] = {}) /\ ~(interval[c,d] = {})
+        ==> {x + y | x IN interval[a,b] /\ y IN interval[c,d]} =
+            interval[a+c,b+d]) /\
+   (!a b c d:real^N.
+        ~(interval(a,b) = {}) /\ ~(interval(c,d) = {})
+        ==> {x + y | x IN interval(a,b) /\ y IN interval(c,d)} =
+            interval(a+c,b+d))`,
+  CONJ_TAC THEN REPEAT GEN_TAC THEN REWRITE_TAC[INTERVAL_NE_EMPTY] THEN
+  STRIP_TAC THEN REWRITE_TAC[EXTENSION; IN_INTERVAL; IN_ELIM_THM] THEN
+  REWRITE_TAC[TAUT `(a /\ b) /\ c <=> c /\ a /\ b`] THEN
+  REWRITE_TAC[VECTOR_ARITH `x:real^N = y + z <=> z = x - y`] THEN
+  REWRITE_TAC[UNWIND_THM2; VECTOR_ADD_COMPONENT; VECTOR_SUB_COMPONENT] THEN
+  (X_GEN_TAC `x:real^N` THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC);
+    DISCH_TAC THEN
+    REWRITE_TAC[AND_FORALL_THM; GSYM LAMBDA_SKOLEM;
+                TAUT `(p ==> q) /\ (p ==> r) <=> p ==> q /\ r`] THEN
+    REWRITE_TAC[REAL_ARITH
+     `((a <= y /\ y <= b) /\ c <= x - y /\ x - y <= d <=>
+       max a (x - d) <= y /\ y <= min b (x - c)) /\
+      ((a < y /\ y < b) /\ c < x - y /\ x - y < d <=>
+       max a (x - d) < y /\ y < min b (x - c))`] THEN
+    REWRITE_TAC[GSYM REAL_LE_BETWEEN; GSYM REAL_LT_BETWEEN]] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `i:num`)) THEN
+  ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC));;
+
+let PCROSS_INTERVAL = prove
+ (`!a b:real^M c d:real^N.
+        interval[a,b] PCROSS interval[c,d] =
+        interval[pastecart a c,pastecart b d]`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[PCROSS] THEN
+  REWRITE_TAC[EXTENSION; FORALL_PASTECART; IN_ELIM_PASTECART_THM] THEN
+  SIMP_TAC[IN_INTERVAL; pastecart; LAMBDA_BETA; DIMINDEX_FINITE_SUM] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^M`; `y:real^N`] THEN EQ_TAC THEN STRIP_TAC THENL
+   [X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    COND_CASES_TAC THEN ASM_SIMP_TAC[] THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC;
+    CONJ_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+      DISCH_THEN MATCH_MP_TAC THEN ASM_ARITH_TAC;
+      FIRST_X_ASSUM(MP_TAC o SPEC `i + dimindex(:M)`) THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[ADD_SUB] THENL
+       [ASM_ARITH_TAC;
+        DISCH_THEN MATCH_MP_TAC THEN ASM_ARITH_TAC]]]);;
+
+let OPEN_CONTAINS_INTERVAL,OPEN_CONTAINS_OPEN_INTERVAL = (CONJ_PAIR o prove)
+ (`(!s:real^N->bool.
+        open s <=>
+        !x. x IN s ==> ?a b. x IN interval(a,b) /\ interval[a,b] SUBSET s) /\
+   (!s:real^N->bool.
+        open s <=>
+        !x. x IN s ==> ?a b. x IN interval(a,b) /\ interval(a,b) SUBSET s)`,
+  REWRITE_TAC[AND_FORALL_THM] THEN GEN_TAC THEN
+  MATCH_MP_TAC(TAUT
+   `(q ==> r) /\ (r ==> p) /\ (p ==> q) ==> (p <=> q) /\ (p <=> r)`) THEN
+  REPEAT CONJ_TAC THENL
+   [MESON_TAC[SUBSET_TRANS; INTERVAL_OPEN_SUBSET_CLOSED];
+    DISCH_TAC THEN REWRITE_TAC[OPEN_CONTAINS_BALL] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN STRIP_TAC THEN
+    MP_TAC(ISPEC `interval(a:real^N,b)` OPEN_CONTAINS_BALL) THEN
+    REWRITE_TAC[OPEN_INTERVAL] THEN
+    DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[SUBSET_TRANS; INTERVAL_OPEN_SUBSET_CLOSED];
+    DISCH_TAC THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o SPEC `x:real^N` o
+      GEN_REWRITE_RULE I [OPEN_CONTAINS_CBALL]) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `x - e / &(dimindex(:N)) % vec 1:real^N` THEN
+    EXISTS_TAC `x + e / &(dimindex(:N)) % vec 1:real^N` THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `b SUBSET s ==> x IN i /\ j SUBSET b ==> x IN i /\ j SUBSET s`)) THEN
+    SIMP_TAC[IN_INTERVAL; VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT; IN_CBALL;
+             VEC_COMPONENT; VECTOR_ADD_COMPONENT; SUBSET; REAL_MUL_RID] THEN
+    REWRITE_TAC[REAL_ARITH `x - e < x /\ x < x + e <=> &0 < e`;
+                REAL_ARITH `x - e <= y /\ y <= x + e <=> abs(x - y) <= e`] THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1] THEN
+    X_GEN_TAC `y:real^N` THEN REWRITE_TAC[GSYM VECTOR_SUB_COMPONENT] THEN
+    DISCH_TAC THEN REWRITE_TAC[dist] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum(1..dimindex(:N)) (\i. abs((x - y:real^N)$i))` THEN
+    REWRITE_TAC[NORM_LE_L1] THEN MATCH_MP_TAC SUM_BOUND_GEN THEN
+    ASM_SIMP_TAC[CARD_NUMSEG_1; IN_NUMSEG; FINITE_NUMSEG] THEN
+    REWRITE_TAC[NUMSEG_EMPTY; NOT_LT; DIMINDEX_GE_1]]);;
+
+let DIAMETER_INTERVAL = prove
+ (`(!a b:real^N.
+        diameter(interval[a,b]) =
+        if interval[a,b] = {} then &0 else norm(b - a)) /\
+   (!a b:real^N.
+        diameter(interval(a,b)) =
+        if interval(a,b) = {} then &0 else norm(b - a))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `interval[a:real^N,b] = {}` THENL
+   [ASM_MESON_TAC[INTERVAL_OPEN_SUBSET_CLOSED; SUBSET_EMPTY; DIAMETER_EMPTY];
+    ASM_REWRITE_TAC[]] THEN
+  MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+   [REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN
+    ASM_SIMP_TAC[DIAMETER_BOUNDED_BOUND;
+                 ENDS_IN_INTERVAL; BOUNDED_INTERVAL] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+     `diameter(cball(inv(&2) % (a + b):real^N,norm(b - a) / &2))` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC DIAMETER_SUBSET THEN REWRITE_TAC[BOUNDED_CBALL] THEN
+      REWRITE_TAC[SUBSET; IN_INTERVAL; IN_CBALL] THEN
+      GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[dist] THEN
+      REWRITE_TAC[GSYM NORM_MUL; REAL_ARITH `x / &2 = abs(inv(&2)) * x`] THEN
+      MATCH_MP_TAC NORM_LE_COMPONENTWISE THEN
+      X_GEN_TAC `i:num` THEN DISCH_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
+      ASM_REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_SUB_COMPONENT;
+                      VECTOR_MUL_COMPONENT] THEN
+      REAL_ARITH_TAC;
+      REWRITE_TAC[DIAMETER_CBALL] THEN NORM_ARITH_TAC];
+    DISCH_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[DIAMETER_EMPTY] THEN
+    SUBGOAL_THEN `interval[a:real^N,b] = closure(interval(a,b))`
+    SUBST_ALL_TAC THEN ASM_REWRITE_TAC[CLOSURE_INTERVAL] THEN
+    ASM_MESON_TAC[DIAMETER_CLOSURE; BOUNDED_INTERVAL]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some special cases for intervals in R^1.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let INTERVAL_CASES_1 = prove
+ (`!x:real^1. x IN interval[a,b] ==> x IN interval(a,b) \/ (x = a) \/ (x = b)`,
+  REWRITE_TAC[CART_EQ; IN_INTERVAL; FORALL_DIMINDEX_1] THEN REAL_ARITH_TAC);;
+
+let IN_INTERVAL_1 = prove
+ (`!a b x:real^1.
+        (x IN interval[a,b] <=> drop a <= drop x /\ drop x <= drop b) /\
+        (x IN interval(a,b) <=> drop a < drop x /\ drop x < drop b)`,
+  REWRITE_TAC[IN_INTERVAL; drop; CONJ_ASSOC; DIMINDEX_1; LE_ANTISYM] THEN
+  MESON_TAC[]);;
+
+let INTERVAL_EQ_EMPTY_1 = prove
+ (`!a b:real^1.
+        (interval[a,b] = {} <=> drop b < drop a) /\
+        (interval(a,b) = {} <=> drop b <= drop a)`,
+  REWRITE_TAC[INTERVAL_EQ_EMPTY; drop; CONJ_ASSOC; DIMINDEX_1; LE_ANTISYM] THEN
+  MESON_TAC[]);;
+
+let INTERVAL_NE_EMPTY_1 = prove
+ (`(!a b:real^1. ~(interval[a,b] = {}) <=> drop a <= drop b) /\
+   (!a b:real^1. ~(interval(a,b) = {}) <=> drop a < drop b)`,
+  REWRITE_TAC[INTERVAL_EQ_EMPTY_1] THEN REAL_ARITH_TAC);;
+
+let SUBSET_INTERVAL_1 = prove
+ (`!a b c d.
+        (interval[a,b] SUBSET interval[c,d] <=>
+                drop b < drop a \/
+                drop c <= drop a /\ drop a <= drop b /\ drop b <= drop d) /\
+        (interval[a,b] SUBSET interval(c,d) <=>
+                drop b < drop a \/
+                drop c < drop a /\ drop a <= drop b /\ drop b < drop d) /\
+        (interval(a,b) SUBSET interval[c,d] <=>
+                drop b <= drop a \/
+                drop c <= drop a /\ drop a < drop b /\ drop b <= drop d) /\
+        (interval(a,b) SUBSET interval(c,d) <=>
+                drop b <= drop a \/
+                drop c <= drop a /\ drop a < drop b /\ drop b <= drop d)`,
+  REWRITE_TAC[SUBSET_INTERVAL; FORALL_1; DIMINDEX_1; drop] THEN
+  REAL_ARITH_TAC);;
+
+let EQ_INTERVAL_1 = prove
+ (`!a b c d:real^1.
+       (interval[a,b] = interval[c,d] <=>
+          drop b < drop a /\ drop d < drop c \/
+          drop a = drop c /\ drop b = drop d)`,
+  REWRITE_TAC[SET_RULE `s = t <=> s SUBSET t /\ t SUBSET s`] THEN
+  REWRITE_TAC[SUBSET_INTERVAL_1] THEN REAL_ARITH_TAC);;
+
+let DISJOINT_INTERVAL_1 = prove
+ (`!a b c d:real^1.
+        (interval[a,b] INTER interval[c,d] = {} <=>
+          drop b < drop a \/ drop d < drop c \/
+          drop b < drop c \/ drop d < drop a) /\
+        (interval[a,b] INTER interval(c,d) = {} <=>
+          drop b < drop a \/ drop d <= drop c \/
+          drop b <= drop c \/ drop d <= drop a) /\
+        (interval(a,b) INTER interval[c,d] = {} <=>
+          drop b <= drop a \/ drop d < drop c \/
+          drop b <= drop c \/ drop d <= drop a) /\
+        (interval(a,b) INTER interval(c,d) = {} <=>
+          drop b <= drop a \/ drop d <= drop c \/
+          drop b <= drop c \/ drop d <= drop a)`,
+  REWRITE_TAC[DISJOINT_INTERVAL; CONJ_ASSOC; DIMINDEX_1; LE_ANTISYM;
+              UNWIND_THM1; drop]);;
+
+let OPEN_CLOSED_INTERVAL_1 = prove
+ (`!a b:real^1. interval(a,b) = interval[a,b] DIFF {a,b}`,
+  REWRITE_TAC[EXTENSION; IN_INTERVAL_1; IN_DIFF; IN_INSERT; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[GSYM DROP_EQ] THEN REAL_ARITH_TAC);;
+
+let CLOSED_OPEN_INTERVAL_1 = prove
+ (`!a b:real^1. drop a <= drop b ==> interval[a,b] = interval(a,b) UNION {a,b}`,
+  REWRITE_TAC[EXTENSION; IN_INTERVAL_1; IN_UNION; IN_INSERT; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[GSYM DROP_EQ] THEN REAL_ARITH_TAC);;
+
+let BALL_1 = prove
+ (`!x:real^1 r. cball(x,r) = interval[x - lift r,x + lift r] /\
+                ball(x,r) = interval(x - lift r,x + lift r)`,
+  REWRITE_TAC[EXTENSION; IN_BALL; IN_CBALL; IN_INTERVAL_1] THEN
+  REWRITE_TAC[dist; NORM_REAL; GSYM drop; DROP_SUB; LIFT_DROP; DROP_ADD] THEN
+  REAL_ARITH_TAC);;
+
+let SPHERE_1 = prove
+ (`!a:real^1 r. sphere(a,r) = if r < &0 then {} else {a - lift r,a + lift r}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[sphere] THEN COND_CASES_TAC THEN
+  REWRITE_TAC[DIST_REAL; GSYM drop; FORALL_DROP] THEN
+  REWRITE_TAC[EXTENSION; IN_INSERT; NOT_IN_EMPTY; IN_ELIM_THM] THEN
+  REWRITE_TAC[GSYM DROP_EQ; DROP_ADD; DROP_SUB; LIFT_DROP] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let FINITE_SPHERE_1 = prove
+ (`!a:real^1 r. FINITE(sphere(a,r))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[SPHERE_1] THEN
+  MESON_TAC[FINITE_INSERT; FINITE_EMPTY]);;
+
+let FINITE_INTERVAL_1 = prove
+ (`(!a b. FINITE(interval[a,b]) <=> drop b <= drop a) /\
+   (!a b. FINITE(interval(a,b)) <=> drop b <= drop a)`,
+  REWRITE_TAC[OPEN_CLOSED_INTERVAL_1] THEN
+  REWRITE_TAC[SET_RULE `s DIFF {a,b} = s DELETE a DELETE b`] THEN
+  REWRITE_TAC[FINITE_DELETE] THEN REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `interval[a,b] = IMAGE lift {x | drop a <= x /\ x <= drop b}`
+  SUBST1_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+    CONJ_TAC THENL [MESON_TAC[LIFT_DROP]; ALL_TAC] THEN
+    REWRITE_TAC[IN_INTERVAL_1; IN_ELIM_THM; LIFT_DROP];
+    SIMP_TAC[FINITE_IMAGE_INJ_EQ; LIFT_EQ; FINITE_REAL_INTERVAL]]);;
+
+let BALL_INTERVAL = prove
+ (`!x:real^1 e. ball(x,e) = interval(x - lift e,x + lift e)`,
+  REWRITE_TAC[EXTENSION; IN_BALL; IN_INTERVAL_1; DIST_REAL] THEN
+  REWRITE_TAC[GSYM drop; DROP_SUB; DROP_ADD; LIFT_DROP] THEN REAL_ARITH_TAC);;
+
+let CBALL_INTERVAL = prove
+ (`!x:real^1 e. cball(x,e) = interval[x - lift e,x + lift e]`,
+  REWRITE_TAC[EXTENSION; IN_CBALL; IN_INTERVAL_1; DIST_REAL] THEN
+  REWRITE_TAC[GSYM drop; DROP_SUB; DROP_ADD; LIFT_DROP] THEN REAL_ARITH_TAC);;
+
+let BALL_INTERVAL_0 = prove
+ (`!e. ball(vec 0:real^1,e) = interval(--lift e,lift e)`,
+  GEN_TAC THEN REWRITE_TAC[BALL_INTERVAL] THEN AP_TERM_TAC THEN
+  BINOP_TAC THEN VECTOR_ARITH_TAC);;
+
+let CBALL_INTERVAL_0 = prove
+ (`!e. cball(vec 0:real^1,e) = interval[--lift e,lift e]`,
+  GEN_TAC THEN REWRITE_TAC[CBALL_INTERVAL] THEN AP_TERM_TAC THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN BINOP_TAC THEN VECTOR_ARITH_TAC);;
+
+let INTER_INTERVAL_1 = prove
+ (`!a b c d:real^1.
+        interval[a,b] INTER interval[c,d] =
+        interval[lift(max (drop a) (drop c)),lift(min (drop b) (drop d))]`,
+  REWRITE_TAC[EXTENSION; IN_INTER; IN_INTERVAL_1; real_max; real_min] THEN
+  REPEAT GEN_TAC THEN
+  REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[LIFT_DROP]) THEN
+  ASM_REAL_ARITH_TAC);;
+
+let CLOSED_DIFF_OPEN_INTERVAL_1 = prove
+ (`!a b:real^1.
+        interval[a,b] DIFF interval(a,b) =
+        if interval[a,b] = {} then {} else {a,b}`,
+  REWRITE_TAC[EXTENSION; IN_DIFF; INTERVAL_EQ_EMPTY_1; IN_INTERVAL_1] THEN
+  REPEAT GEN_TAC THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[NOT_IN_EMPTY; IN_INSERT; NOT_IN_EMPTY] THEN
+  REWRITE_TAC[GSYM DROP_EQ] THEN ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Intervals in general, including infinite and mixtures of open and closed. *)
+(* ------------------------------------------------------------------------- *)
+
+let is_interval = new_definition
+  `is_interval(s:real^N->bool) <=>
+        !a b x. a IN s /\ b IN s /\
+                (!i. 1 <= i /\ i <= dimindex(:N)
+                     ==> (a$i <= x$i /\ x$i <= b$i) \/
+                         (b$i <= x$i /\ x$i <= a$i))
+                ==> x IN s`;;
+
+let IS_INTERVAL_INTERVAL = prove
+ (`!a:real^N b. is_interval(interval (a,b)) /\ is_interval(interval [a,b])`,
+  REWRITE_TAC[is_interval; IN_INTERVAL] THEN
+  MESON_TAC[REAL_LT_TRANS; REAL_LE_TRANS; REAL_LET_TRANS; REAL_LTE_TRANS]);;
+
+let IS_INTERVAL_EMPTY = prove
+ (`is_interval {}`,
+  REWRITE_TAC[is_interval; NOT_IN_EMPTY]);;
+
+let IS_INTERVAL_UNIV = prove
+ (`is_interval(UNIV:real^N->bool)`,
+  REWRITE_TAC[is_interval; IN_UNIV]);;
+
+let IS_INTERVAL_TRANSLATION_EQ = prove
+ (`!a:real^N s. is_interval(IMAGE (\x. a + x) s) <=> is_interval s`,
+  REWRITE_TAC[is_interval] THEN GEOM_TRANSLATE_TAC[] THEN
+  REWRITE_TAC[VECTOR_ADD_COMPONENT; REAL_LT_LADD; REAL_LE_LADD]);;
+
+add_translation_invariants [IS_INTERVAL_TRANSLATION_EQ];;
+
+let IS_INTERVAL_TRANSLATION = prove
+ (`!s a:real^N. is_interval s ==> is_interval(IMAGE (\x. a + x) s)`,
+  REWRITE_TAC[IS_INTERVAL_TRANSLATION_EQ]);;
+
+let IS_INTERVAL_POINTWISE = prove
+ (`!s:real^N->bool x.
+        is_interval s /\
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> ?a. a IN s /\ a$i = x$i)
+        ==> x IN s`,
+  REWRITE_TAC[is_interval] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+    `!n. ?y:real^N. (!i. 1 <= i /\ i <= n ==> y$i = (x:real^N)$i) /\ y IN s`
+  MP_TAC THENL
+   [INDUCT_TAC THEN REWRITE_TAC[ARITH_RULE `~(1 <= i /\ i <= 0)`] THENL
+     [ASM_MESON_TAC[DIMINDEX_GE_1; LE_REFL]; ALL_TAC] THEN
+    FIRST_X_ASSUM(X_CHOOSE_TAC `y:real^N`) THEN
+    ASM_CASES_TAC `SUC n <= dimindex(:N)` THENL
+     [FIRST_X_ASSUM(MP_TAC o SPEC `SUC n`) THEN
+      ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+      DISCH_THEN(X_CHOOSE_THEN `z:real^N` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC
+       `(lambda i. if i <= n then (y:real^N)$i else (z:real^N)$i):real^N` THEN
+      CONJ_TAC THENL
+       [X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+        SUBGOAL_THEN `i <= dimindex(:N)` ASSUME_TAC THENL
+         [ASM_ARITH_TAC; ASM_SIMP_TAC[LAMBDA_BETA]] THEN
+        COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+        SUBGOAL_THEN `i = SUC n` (fun th -> ASM_REWRITE_TAC[th]) THEN
+        ASM_ARITH_TAC;
+        FIRST_X_ASSUM(ASSUME_TAC o CONJUNCT2) THEN
+        FIRST_X_ASSUM MATCH_MP_TAC THEN
+        MAP_EVERY EXISTS_TAC [`y:real^N`; `z:real^N`] THEN
+        ASM_SIMP_TAC[LAMBDA_BETA] THEN REAL_ARITH_TAC];
+      EXISTS_TAC `y:real^N` THEN ASM_REWRITE_TAC[] THEN
+      SUBGOAL_THEN `y:real^N = x` (fun th -> REWRITE_TAC[th]) THEN
+      REWRITE_TAC[CART_EQ] THEN
+      ASM_MESON_TAC[ARITH_RULE `i <= N /\ ~(SUC n <= N) ==> i <= n`]];
+    DISCH_THEN(MP_TAC o SPEC `dimindex(:N)`) THEN
+    REWRITE_TAC[GSYM CART_EQ] THEN MESON_TAC[]]);;
+
+let IS_INTERVAL_COMPACT = prove
+ (`!s:real^N->bool. is_interval s /\ compact s <=> ?a b. s = interval[a,b]`,
+  GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[IS_INTERVAL_INTERVAL; COMPACT_INTERVAL] THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_MESON_TAC[EMPTY_AS_INTERVAL]; ALL_TAC] THEN
+  EXISTS_TAC `(lambda i. inf { (x:real^N)$i | x IN s}):real^N` THEN
+  EXISTS_TAC `(lambda i. sup { (x:real^N)$i | x IN s}):real^N` THEN
+  SIMP_TAC[EXTENSION; IN_INTERVAL; LAMBDA_BETA] THEN X_GEN_TAC `x:real^N` THEN
+  EQ_TAC THENL
+   [DISCH_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    MP_TAC(ISPEC `{ (x:real^N)$i | x IN s}` INF) THEN
+    MP_TAC(ISPEC `{ (x:real^N)$i | x IN s}` SUP) THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+    ASM_REWRITE_TAC[IMAGE_EQ_EMPTY; FORALL_IN_IMAGE] THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_IMP_BOUNDED) THEN
+    REWRITE_TAC[bounded] THEN
+    ASM_MESON_TAC[COMPONENT_LE_NORM; REAL_LE_TRANS; MEMBER_NOT_EMPTY;
+                  REAL_ARITH `abs(x) <= B ==> --B <= x /\ x <= B`];
+    DISCH_TAC THEN MATCH_MP_TAC IS_INTERVAL_POINTWISE THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    SUBGOAL_THEN
+     `?a b:real^N. a IN s /\ b IN s /\ a$i <= (x:real^N)$i /\ x$i <= b$i`
+    STRIP_ASSUME_TAC THENL
+     [MP_TAC(ISPECL [`\x:real^N. x$i`; `s:real^N->bool`]
+        CONTINUOUS_ATTAINS_INF) THEN
+      ASM_SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT; o_DEF] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN STRIP_TAC THEN
+      MP_TAC(ISPECL [`\x:real^N. x$i`; `s:real^N->bool`]
+        CONTINUOUS_ATTAINS_SUP) THEN
+      ASM_SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT; o_DEF] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:real^N` THEN STRIP_TAC THEN
+      ASM_REWRITE_TAC[] THEN CONJ_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THENL
+       [EXISTS_TAC `inf {(x:real^N)$i | x IN s}` THEN ASM_SIMP_TAC[] THEN
+        MATCH_MP_TAC REAL_LE_INF THEN ASM SET_TAC[];
+        EXISTS_TAC `sup {(x:real^N)$i | x IN s}` THEN ASM_SIMP_TAC[] THEN
+        MATCH_MP_TAC REAL_SUP_LE THEN ASM SET_TAC[]];
+      EXISTS_TAC
+       `(lambda j. if j = i then (x:real^N)$i else (a:real^N)$j):real^N` THEN
+      ASM_SIMP_TAC[LAMBDA_BETA] THEN
+      FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[is_interval]) THEN
+      MAP_EVERY EXISTS_TAC
+       [`a:real^N`;
+        `(lambda j. if j = i then (b:real^N)$i else (a:real^N)$j):real^N`] THEN
+      ASM_SIMP_TAC[LAMBDA_BETA] THEN CONJ_TAC THENL
+       [FIRST_X_ASSUM(MATCH_MP_TAC o REWRITE_RULE[is_interval]) THEN
+        MAP_EVERY EXISTS_TAC [`a:real^N`; `b:real^N`] THEN
+        ASM_SIMP_TAC[LAMBDA_BETA];
+        ALL_TAC] THEN
+      GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+      ASM_REAL_ARITH_TAC]]);;
+
+let IS_INTERVAL_1 = prove
+ (`!s:real^1->bool.
+        is_interval s <=>
+          !a b x. a IN s /\ b IN s /\ drop a <= drop x /\ drop x <= drop b
+                  ==> x IN s`,
+  REWRITE_TAC[is_interval; DIMINDEX_1; FORALL_1; GSYM drop] THEN
+  REWRITE_TAC[FORALL_LIFT; LIFT_DROP] THEN MESON_TAC[]);;
+
+let IS_INTERVAL_1_CASES = prove
+ (`!s:real^1->bool.
+        is_interval s <=>
+        s = {} \/
+        s = (:real^1) \/
+        (?a. s = {x | a < drop x}) \/
+        (?a. s = {x | a <= drop x}) \/
+        (?b. s = {x | drop x <= b}) \/
+        (?b. s = {x | drop x < b}) \/
+        (?a b. s = {x | a < drop x /\ drop x < b}) \/
+        (?a b. s = {x | a < drop x /\ drop x <= b}) \/
+        (?a b. s = {x | a <= drop x /\ drop x < b}) \/
+        (?a b. s = {x | a <= drop x /\ drop x <= b})`,
+  GEN_TAC THEN REWRITE_TAC[IS_INTERVAL_1] THEN EQ_TAC THENL
+   [DISCH_TAC;
+    STRIP_TAC THEN ASM_REWRITE_TAC[IN_ELIM_THM; IN_UNIV; NOT_IN_EMPTY] THEN
+    REAL_ARITH_TAC] THEN
+  ASM_CASES_TAC `s:real^1->bool = {}` THEN ASM_REWRITE_TAC[] THEN
+  MP_TAC(ISPEC `IMAGE drop s` SUP) THEN
+  MP_TAC(ISPEC `IMAGE drop s` INF) THEN
+  ASM_REWRITE_TAC[IMAGE_EQ_EMPTY; FORALL_IN_IMAGE] THEN
+  ASM_CASES_TAC `?a. !x. x IN s ==> a <= drop x` THEN
+  ASM_CASES_TAC `?b. !x. x IN s ==> drop x <= b` THEN
+  ASM_REWRITE_TAC[] THENL
+   [STRIP_TAC THEN STRIP_TAC THEN
+    MAP_EVERY ASM_CASES_TAC
+     [`inf(IMAGE drop s) IN IMAGE drop s`; `sup(IMAGE drop s) IN IMAGE drop s`]
+    THENL
+     [REPLICATE_TAC 8 DISJ2_TAC;
+      REPLICATE_TAC 7 DISJ2_TAC THEN DISJ1_TAC;
+      REPLICATE_TAC 6 DISJ2_TAC THEN DISJ1_TAC;
+      REPLICATE_TAC 5 DISJ2_TAC THEN DISJ1_TAC] THEN
+    MAP_EVERY EXISTS_TAC [`inf(IMAGE drop s)`; `sup(IMAGE drop s)`];
+    STRIP_TAC THEN ASM_CASES_TAC `inf(IMAGE drop s) IN IMAGE drop s` THENL
+     [REPLICATE_TAC 2 DISJ2_TAC THEN DISJ1_TAC;
+      DISJ2_TAC THEN DISJ1_TAC] THEN
+    EXISTS_TAC `inf(IMAGE drop s)`;
+    STRIP_TAC THEN ASM_CASES_TAC `sup(IMAGE drop s) IN IMAGE drop s` THENL
+     [REPLICATE_TAC 3 DISJ2_TAC THEN DISJ1_TAC;
+      REPLICATE_TAC 4 DISJ2_TAC THEN DISJ1_TAC] THEN
+    EXISTS_TAC `sup(IMAGE drop s)`;
+    DISJ1_TAC] THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_UNIV] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN_IMAGE]) THEN
+  REWRITE_TAC[GSYM REAL_NOT_LE] THEN
+  ASM_MESON_TAC[REAL_LE_TRANS; REAL_LE_TOTAL; REAL_LE_ANTISYM]);;
+
+let IS_INTERVAL_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        is_interval s /\ is_interval t ==> is_interval(s PCROSS t)`,
+  REWRITE_TAC[is_interval; DIMINDEX_FINITE_SUM] THEN
+  REWRITE_TAC[FORALL_PASTECART; PASTECART_IN_PCROSS] THEN
+  REPEAT GEN_TAC THEN
+  MATCH_MP_TAC(MESON[]
+   `(!a b a' b' x x'. P a b x /\ Q a' b' x' ==> R a b x a' b' x')
+    ==> (!a b x. P a b x) /\ (!a' b' x'. Q a' b' x')
+        ==> (!a a' b b' x x'. R a b x a' b' x')`) THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `i:num` THEN STRIP_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
+    ASM_SIMP_TAC[pastecart; LAMBDA_BETA; DIMINDEX_FINITE_SUM;
+                 ARITH_RULE `x:num <= m ==> x <= m + n`];
+    FIRST_X_ASSUM(MP_TAC o SPEC `dimindex(:M) + i`) THEN
+    ASM_SIMP_TAC[pastecart; LAMBDA_BETA; DIMINDEX_FINITE_SUM;
+                 ARITH_RULE `x:num <= n ==> m + x <= m + n`;
+                 ARITH_RULE `1 <= x ==> 1 <= m + x`] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[ADD_SUB2] THEN ASM_ARITH_TAC]);;
+
+let IS_INTERVAL_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        is_interval(s PCROSS t) <=>
+        s = {} \/ t = {} \/ is_interval s /\ is_interval t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; IS_INTERVAL_EMPTY] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[PCROSS_EMPTY; IS_INTERVAL_EMPTY] THEN
+  EQ_TAC THEN REWRITE_TAC[IS_INTERVAL_PCROSS] THEN
+  REWRITE_TAC[is_interval] THEN
+  REWRITE_TAC[FORALL_PASTECART; PASTECART_IN_PCROSS] THEN
+  STRIP_TAC THEN CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M`; `x:real^M`] THEN
+    STRIP_TAC THEN UNDISCH_TAC `~(t:real^N->bool = {})` THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `y:real^N`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`a:real^M`; `y:real^N`; `b:real^M`;
+      `y:real^N`; `x:real^M`; `y:real^N`]);
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`; `x:real^N`] THEN
+    STRIP_TAC THEN UNDISCH_TAC `~(s:real^M->bool = {})` THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `w:real^M`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL
+     [`w:real^M`; `a:real^N`; `w:real^M`;
+      `b:real^N`; `w:real^M`; `x:real^N`])] THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_MP_TAC THEN
+  SIMP_TAC[pastecart; LAMBDA_BETA] THEN
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_LE_REFL] THEN
+  ASM_MESON_TAC[DIMINDEX_FINITE_SUM; ARITH_RULE
+      `1 <= i /\ i <= m + n /\ ~(i <= m) ==> 1 <= i - m /\ i - m <= n`]);;
+
+let IS_INTERVAL_INTER = prove
+ (`!s t:real^N->bool.
+        is_interval s /\ is_interval t ==> is_interval(s INTER t)`,
+  REWRITE_TAC[is_interval; IN_INTER] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`; `x:real^N`] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`a:real^N`; `b:real^N`] THEN ASM_REWRITE_TAC[]);;
+
+let INTERVAL_SUBSET_IS_INTERVAL = prove
+ (`!s a b:real^N.
+     is_interval s
+     ==> (interval[a,b] SUBSET s <=> interval[a,b] = {} \/ a IN s /\ b IN s)`,
+  REWRITE_TAC[is_interval] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `interval[a:real^N,b] = {}` THEN
+  ASM_REWRITE_TAC[EMPTY_SUBSET] THEN
+  EQ_TAC THENL [ASM_MESON_TAC[ENDS_IN_INTERVAL; SUBSET]; ALL_TAC] THEN
+  REWRITE_TAC[SUBSET; IN_INTERVAL] THEN ASM_MESON_TAC[]);;
+
+let INTERVAL_CONTAINS_COMPACT_NEIGHBOURHOOD = prove
+ (`!s x:real^N.
+        is_interval s /\ x IN s
+        ==> ?a b d. &0 < d /\ x IN interval[a,b] /\
+                    interval[a,b] SUBSET s /\
+                    ball(x,d) INTER s SUBSET interval[a,b]`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[INTERVAL_SUBSET_IS_INTERVAL] THEN
+  SUBGOAL_THEN
+   `!i. 1 <= i /\ i <= dimindex(:N)
+        ==> ?a. (?y. y IN s /\ y$i = a) /\
+                (a < x$i \/ a = (x:real^N)$i /\
+                            !y:real^N. y IN s ==> a <= y$i)`
+  MP_TAC THENL [ASM_MESON_TAC[REAL_NOT_LT]; REWRITE_TAC[LAMBDA_SKOLEM]] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!i. 1 <= i /\ i <= dimindex(:N)
+        ==> ?b. (?y. y IN s /\ y$i = b) /\
+                (x$i < b \/ b = (x:real^N)$i /\
+                            !y:real^N. y IN s ==> y$i <= b)`
+  MP_TAC THENL [ASM_MESON_TAC[REAL_NOT_LT]; REWRITE_TAC[LAMBDA_SKOLEM]] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:real^N` THEN STRIP_TAC THEN
+  EXISTS_TAC `min (inf (IMAGE (\i. if a$i < x$i
+                                   then (x:real^N)$i - (a:real^N)$i else &1)
+                              (1..dimindex(:N))))
+                  (inf (IMAGE (\i. if x$i < b$i
+                                   then (b:real^N)$i - x$i else &1)
+                              (1..dimindex(:N))))` THEN
+  REWRITE_TAC[REAL_LT_MIN; SUBSET; IN_BALL; IN_INTER] THEN
+  SIMP_TAC[REAL_LT_INF_FINITE; IMAGE_EQ_EMPTY; FINITE_IMAGE;
+           FINITE_NUMSEG; NUMSEG_EMPTY; GSYM NOT_LE; DIMINDEX_GE_1] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; IN_INTERVAL] THEN REPEAT CONJ_TAC THENL
+   [MESON_TAC[REAL_SUB_LT; REAL_LT_01];
+    MESON_TAC[REAL_SUB_LT; REAL_LT_01];
+    ASM_MESON_TAC[REAL_LE_LT];
+    DISJ2_TAC THEN CONJ_TAC THEN MATCH_MP_TAC IS_INTERVAL_POINTWISE THEN
+    ASM_MESON_TAC[];
+    X_GEN_TAC `y:real^N` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    REWRITE_TAC[AND_FORALL_THM] THEN MATCH_MP_TAC MONO_FORALL THEN
+    X_GEN_TAC `i:num` THEN DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+    ASM_REWRITE_TAC[IN_NUMSEG] THEN MATCH_MP_TAC MONO_AND THEN CONJ_TAC THEN
+    (COND_CASES_TAC THENL [REWRITE_TAC[dist]; ASM_MESON_TAC[]]) THEN
+    DISCH_TAC THEN MP_TAC(ISPECL [`x - y:real^N`; `i:num`]
+      COMPONENT_LE_NORM) THEN
+    ASM_REWRITE_TAC[VECTOR_SUB_COMPONENT] THEN ASM_REAL_ARITH_TAC]);;
+
+let IS_INTERVAL_SUMS = prove
+ (`!s t:real^N->bool.
+        is_interval s /\ is_interval t
+        ==> is_interval {x + y | x IN s /\ y IN t}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[is_interval] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  MAP_EVERY X_GEN_TAC
+   [`a:real^N`; `a':real^N`; `b:real^N`; `b':real^N`; `y:real^N`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (MP_TAC o SPECL [`a:real^N`; `b:real^N`]) MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (MP_TAC o SPECL [`a':real^N`; `b':real^N`]) STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[IMP_IMP; IN_ELIM_THM] THEN  ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `z:real^N = x + y <=> y = z - x`] THEN
+  REWRITE_TAC[UNWIND_THM2] THEN MATCH_MP_TAC(MESON[]
+   `(?x. P x /\ Q(f x))
+    ==> (!x. P x ==> x IN s) /\ (!x. Q x ==> x IN t)
+        ==> ?x. x IN s /\ f x IN t`) THEN
+  REWRITE_TAC[VECTOR_SUB_COMPONENT; AND_FORALL_THM;
+              TAUT `(p ==> q) /\ (p ==> r) <=> p ==> q /\ r`] THEN
+  REWRITE_TAC[GSYM LAMBDA_SKOLEM] THEN
+  X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
+  ASM_REWRITE_TAC[VECTOR_ADD_COMPONENT] THEN
+  REWRITE_TAC[REAL_ARITH
+   `c <= y - x /\ y - x <= d <=> y - d <= x /\ x <= y - c`] THEN
+  REWRITE_TAC[REAL_ARITH
+  `a <= x /\ x <= b \/ b <= x /\ x <= a <=> min a b <= x /\ x <= max a b`] THEN
+  ONCE_REWRITE_TAC[TAUT `(p /\ q) /\ (r /\ s) <=> (p /\ r) /\ (q /\ s)`] THEN
+  REWRITE_TAC[GSYM REAL_LE_MIN; GSYM REAL_MAX_LE] THEN
+  REWRITE_TAC[GSYM REAL_LE_BETWEEN] THEN REAL_ARITH_TAC);;
+
+let IS_INTERVAL_SING = prove
+ (`!a:real^N. is_interval {a}`,
+  SIMP_TAC[is_interval; IN_SING; IMP_CONJ; CART_EQ; REAL_LE_ANTISYM]);;
+
+let IS_INTERVAL_SCALING = prove
+ (`!s:real^N->bool c. is_interval s ==> is_interval(IMAGE (\x. c % x) s)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `c = &0` THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+    SUBGOAL_THEN `IMAGE ((\x. vec 0):real^N->real^N) s = {} \/
+                  IMAGE ((\x. vec 0):real^N->real^N) s = {vec 0}`
+    STRIP_ASSUME_TAC THENL
+     [SET_TAC[];
+      ASM_REWRITE_TAC[IS_INTERVAL_EMPTY];
+      ASM_REWRITE_TAC[IS_INTERVAL_SING]];
+    REWRITE_TAC[is_interval; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE] THEN
+    GEN_REWRITE_TAC (BINOP_CONV o REDEPTH_CONV) [RIGHT_IMP_FORALL_THM] THEN
+    REWRITE_TAC[IMP_IMP; VECTOR_MUL_COMPONENT] THEN
+    MAP_EVERY (fun t -> MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC t)
+     [`a:real^N`; `b:real^N`] THEN
+    DISCH_THEN(fun th -> X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
+                         MP_TAC(SPEC `inv(c) % x:real^N` th)) THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_COMPONENT; IN_IMAGE] THEN ANTS_TAC THENL
+     [X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN ASM_REWRITE_TAC[] THEN
+      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM real_div] THEN
+      FIRST_X_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+       `~(c = &0) ==> &0 < c \/ &0 < --c`)) THEN
+      ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ] THEN
+      GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [GSYM REAL_LE_NEG2] THEN
+      ASM_SIMP_TAC[GSYM REAL_MUL_RNEG; GSYM REAL_LE_RDIV_EQ; GSYM
+                   REAL_LE_LDIV_EQ] THEN
+      REWRITE_TAC[real_div; REAL_INV_NEG] THEN REAL_ARITH_TAC;
+      DISCH_TAC THEN EXISTS_TAC `inv c % x:real^N` THEN
+      ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; VECTOR_MUL_LID]]]);;
+
+let IS_INTERVAL_SCALING_EQ = prove
+ (`!s:real^N->bool c.
+        is_interval(IMAGE (\x. c % x) s) <=> c = &0 \/ is_interval s`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `c = &0` THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+    SUBGOAL_THEN `IMAGE ((\x. vec 0):real^N->real^N) s = {} \/
+                  IMAGE ((\x. vec 0):real^N->real^N) s = {vec 0}`
+    STRIP_ASSUME_TAC THENL
+     [SET_TAC[];
+      ASM_REWRITE_TAC[IS_INTERVAL_EMPTY];
+      ASM_REWRITE_TAC[IS_INTERVAL_SING]];
+    ASM_REWRITE_TAC[] THEN EQ_TAC THEN REWRITE_TAC[IS_INTERVAL_SCALING] THEN
+    DISCH_THEN(MP_TAC o SPEC `inv c:real` o MATCH_MP IS_INTERVAL_SCALING) THEN
+    ASM_SIMP_TAC[GSYM IMAGE_o; VECTOR_MUL_ASSOC; o_DEF; REAL_MUL_LINV;
+                 VECTOR_MUL_LID; IMAGE_ID]]);;
+
+let lemma = prove
+ (`!c. &0 < c
+       ==> !s:real^N->bool. is_interval(IMAGE (\x. c % x) s) <=>
+                            is_interval s`,
+  SIMP_TAC[IS_INTERVAL_SCALING_EQ; REAL_LT_IMP_NZ]) in
+add_scaling_theorems [lemma];;
+
+(* ------------------------------------------------------------------------- *)
+(* Line segments, with same open/closed overloading as for intervals.        *)
+(* ------------------------------------------------------------------------- *)
+
+let closed_segment = define
+ `closed_segment[a,b] = {(&1 - u) % a + u % b | &0 <= u /\ u <= &1}`;;
+
+let open_segment = new_definition
+ `open_segment(a,b) = closed_segment[a,b] DIFF {a,b}`;;
+
+let OPEN_SEGMENT_ALT = prove
+ (`!a b:real^N.
+        ~(a = b)
+        ==> open_segment(a,b) = {(&1 - u) % a + u % b | &0 < u /\ u < &1}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[open_segment; closed_segment] THEN
+  REWRITE_TAC[EXTENSION; IN_DIFF; IN_INSERT; NOT_IN_EMPTY; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN
+  X_GEN_TAC `u:real` THEN ASM_CASES_TAC `x:real^N = (&1 - u) % a + u % b` THEN
+  ASM_REWRITE_TAC[REAL_LE_LT;
+    VECTOR_ARITH `(&1 - u) % a + u % b = a <=> u % (b - a) = vec 0`;
+    VECTOR_ARITH `(&1 - u) % a + u % b = b <=> (&1 - u) % (b - a) = vec 0`;
+    VECTOR_MUL_EQ_0; REAL_SUB_0; VECTOR_SUB_EQ] THEN
+  REAL_ARITH_TAC);;
+
+make_overloadable "segment" `:A`;;
+
+overload_interface("segment",`open_segment`);;
+overload_interface("segment",`closed_segment`);;
+
+let segment = prove
+ (`segment[a,b] = {(&1 - u) % a + u % b | &0 <= u /\ u <= &1} /\
+   segment(a,b) = segment[a,b] DIFF {a,b}`,
+  REWRITE_TAC[open_segment; closed_segment]);;
+
+let SEGMENT_REFL = prove
+ (`(!a. segment[a,a] = {a}) /\
+   (!a. segment(a,a) = {})`,
+  REWRITE_TAC[segment; VECTOR_ARITH `(&1 - u) % a + u % a = a`] THEN
+  SET_TAC[REAL_POS]);;
+
+let IN_SEGMENT = prove
+ (`!a b x:real^N.
+        (x IN segment[a,b] <=>
+         ?u. &0 <= u /\ u <= &1 /\ x = (&1 - u) % a + u % b) /\
+        (x IN segment(a,b) <=>
+         ~(a = b) /\ ?u. &0 < u /\ u < &1 /\ x = (&1 - u) % a + u % b)`,
+  REPEAT STRIP_TAC THENL
+   [REWRITE_TAC[segment; IN_ELIM_THM; CONJ_ASSOC]; ALL_TAC] THEN
+  ASM_CASES_TAC `a:real^N = b` THEN
+  ASM_REWRITE_TAC[SEGMENT_REFL; NOT_IN_EMPTY] THEN
+  ASM_SIMP_TAC[OPEN_SEGMENT_ALT; IN_ELIM_THM; CONJ_ASSOC]);;
+
+let SEGMENT_SYM = prove
+ (`(!a b:real^N. segment[a,b] = segment[b,a]) /\
+   (!a b:real^N. segment(a,b) = segment(b,a))`,
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN
+  SIMP_TAC[open_segment] THEN
+  CONJ_TAC THENL [ALL_TAC; SIMP_TAC[INSERT_AC]] THEN
+  REWRITE_TAC[EXTENSION; IN_SEGMENT] THEN REPEAT GEN_TAC THEN EQ_TAC THEN
+  DISCH_THEN(X_CHOOSE_TAC `u:real`) THEN EXISTS_TAC `&1 - u` THEN
+  ASM_REWRITE_TAC[] THEN
+  REPEAT CONJ_TAC THEN TRY ASM_ARITH_TAC THEN VECTOR_ARITH_TAC);;
+
+let ENDS_IN_SEGMENT = prove
+ (`!a b. a IN segment[a,b] /\ b IN segment[a,b]`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[segment; IN_ELIM_THM] THENL
+   [EXISTS_TAC `&0`; EXISTS_TAC `&1`] THEN
+  (CONJ_TAC THENL [REAL_ARITH_TAC; VECTOR_ARITH_TAC]));;
+
+let ENDS_NOT_IN_SEGMENT = prove
+ (`!a b. ~(a IN segment(a,b)) /\ ~(b IN segment(a,b))`,
+  REWRITE_TAC[open_segment] THEN SET_TAC[]);;
+
+let SEGMENT_CLOSED_OPEN = prove
+ (`!a b. segment[a,b] = segment(a,b) UNION {a,b}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[open_segment] THEN MATCH_MP_TAC(SET_RULE
+   `a IN s /\ b IN s ==> s = (s DIFF {a,b}) UNION {a,b}`) THEN
+  REWRITE_TAC[ENDS_IN_SEGMENT]);;
+
+let MIDPOINT_IN_SEGMENT = prove
+ (`(!a b:real^N. midpoint(a,b) IN segment[a,b]) /\
+   (!a b:real^N. midpoint(a,b) IN segment(a,b) <=> ~(a = b))`,
+  REWRITE_TAC[IN_SEGMENT] THEN REPEAT STRIP_TAC THENL
+   [ALL_TAC; ASM_CASES_TAC `a:real^N = b` THEN ASM_REWRITE_TAC[]] THEN
+  EXISTS_TAC `&1 / &2` THEN REWRITE_TAC[midpoint] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN VECTOR_ARITH_TAC);;
+
+let BETWEEN_IN_SEGMENT = prove
+ (`!x a b:real^N. between x (a,b) <=> x IN segment[a,b]`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[between] THEN
+  ASM_CASES_TAC `a:real^N = b` THEN
+  ASM_REWRITE_TAC[SEGMENT_REFL; IN_SING] THENL [NORM_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[segment; IN_ELIM_THM] THEN EQ_TAC THENL
+   [DISCH_THEN(ASSUME_TAC o SYM) THEN
+    EXISTS_TAC `dist(a:real^N,x) / dist(a,b)` THEN
+    ASM_SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; DIST_POS_LT] THEN CONJ_TAC
+    THENL [FIRST_ASSUM(SUBST1_TAC o SYM) THEN NORM_ARITH_TAC; ALL_TAC] THEN
+    MATCH_MP_TAC VECTOR_MUL_LCANCEL_IMP THEN EXISTS_TAC `dist(a:real^N,b)` THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; VECTOR_ADD_LDISTRIB; REAL_SUB_LDISTRIB;
+                 REAL_DIV_LMUL; DIST_EQ_0] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [DIST_TRIANGLE_EQ] o SYM) THEN
+    FIRST_ASSUM(SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[dist; REAL_ARITH `(a + b) * &1 - a = b`] THEN
+    VECTOR_ARITH_TAC;
+    STRIP_TAC THEN ASM_REWRITE_TAC[dist] THEN
+    REWRITE_TAC[VECTOR_ARITH `a - ((&1 - u) % a + u % b) = u % (a - b)`;
+                VECTOR_ARITH `((&1 - u) % a + u % b) - b = (&1 - u) % (a - b)`;
+                NORM_MUL; GSYM REAL_ADD_LDISTRIB] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD]);;
+
+let IN_SEGMENT_COMPONENT = prove
+ (`!a b x:real^N i.
+        x IN segment[a,b] /\ 1 <= i /\ i <= dimindex(:N)
+        ==> min (a$i) (b$i) <= x$i /\ x$i <= max (a$i) (b$i)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_SEGMENT]) THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  SIMP_TAC[REAL_ARITH `c <= u * a + t * b <=> u * --a + t * --b <= --c`] THEN
+  MATCH_MP_TAC REAL_CONVEX_BOUND_LE THEN ASM_REAL_ARITH_TAC);;
+
+let SEGMENT_1 = prove
+ (`(!a b. segment[a,b] =
+          if drop a <= drop b then interval[a,b] else interval[b,a]) /\
+   (!a b. segment(a,b) =
+          if drop a <= drop b then interval(a,b) else interval(b,a))`,
+  CONJ_TAC THEN REPEAT GEN_TAC THEN REWRITE_TAC[open_segment] THEN
+  COND_CASES_TAC THEN
+  REWRITE_TAC[IN_DIFF; IN_INSERT; NOT_IN_EMPTY;
+              EXTENSION; GSYM BETWEEN_IN_SEGMENT; between; IN_INTERVAL_1] THEN
+  REWRITE_TAC[GSYM DROP_EQ; DIST_REAL; GSYM drop] THEN ASM_REAL_ARITH_TAC);;
+
+let OPEN_SEGMENT_1 = prove
+ (`!a b:real^1. open(segment(a,b))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[SEGMENT_1] THEN
+  COND_CASES_TAC THEN REWRITE_TAC[OPEN_INTERVAL]);;
+
+let SEGMENT_TRANSLATION = prove
+ (`(!c a b. segment[c + a,c + b] = IMAGE (\x. c + x) (segment[a,b])) /\
+   (!c a b. segment(c + a,c + b) = IMAGE (\x. c + x) (segment(a,b)))`,
+  REWRITE_TAC[EXTENSION; IN_SEGMENT; IN_IMAGE] THEN
+  REWRITE_TAC[VECTOR_ARITH `(&1 - u) % (c + a) + u % (c + b) =
+                            c + (&1 - u) % a + u % b`] THEN
+  REWRITE_TAC[VECTOR_ARITH `c + a:real^N = c + b <=> a = b`] THEN
+  MESON_TAC[]);;
+
+add_translation_invariants
+ [CONJUNCT1 SEGMENT_TRANSLATION; CONJUNCT2 SEGMENT_TRANSLATION];;
+
+let CLOSED_SEGMENT_LINEAR_IMAGE = prove
+ (`!f a b. linear f
+           ==> segment[f a,f b] = IMAGE f (segment[a,b])`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[EXTENSION; IN_IMAGE; IN_SEGMENT] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP LINEAR_CMUL th)]) THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP LINEAR_ADD th)]) THEN
+  MESON_TAC[]);;
+
+add_linear_invariants [CLOSED_SEGMENT_LINEAR_IMAGE];;
+
+let OPEN_SEGMENT_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N a b.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> segment(f a,f b) = IMAGE f (segment(a,b))`,
+  REWRITE_TAC[open_segment] THEN GEOM_TRANSFORM_TAC[]);;
+
+add_linear_invariants [OPEN_SEGMENT_LINEAR_IMAGE];;
+
+let IN_OPEN_SEGMENT = prove
+ (`!a b x:real^N.
+        x IN segment(a,b) <=> x IN segment[a,b] /\ ~(x = a) /\ ~(x = b)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[open_segment; IN_DIFF] THEN SET_TAC[]);;
+
+let IN_OPEN_SEGMENT_ALT = prove
+ (`!a b x:real^N.
+        x IN segment(a,b) <=>
+        x IN segment[a,b] /\ ~(x = a) /\ ~(x = b) /\ ~(a = b)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = b` THEN
+  ASM_REWRITE_TAC[SEGMENT_REFL; IN_SING; NOT_IN_EMPTY] THEN
+  ASM_MESON_TAC[IN_OPEN_SEGMENT]);;
+
+let COLLINEAR_DIST_IN_CLOSED_SEGMENT = prove
+ (`!a b x. collinear {x,a,b} /\
+           dist(x,a) <= dist(a,b) /\ dist(x,b) <= dist(a,b)
+           ==> x IN segment[a,b]`,
+  REWRITE_TAC[GSYM BETWEEN_IN_SEGMENT; COLLINEAR_DIST_BETWEEN]);;
+
+let COLLINEAR_DIST_IN_OPEN_SEGMENT = prove
+ (`!a b x. collinear {x,a,b} /\
+           dist(x,a) < dist(a,b) /\ dist(x,b) < dist(a,b)
+           ==> x IN segment(a,b)`,
+  REWRITE_TAC[IN_OPEN_SEGMENT] THEN
+  MESON_TAC[COLLINEAR_DIST_IN_CLOSED_SEGMENT; REAL_LT_LE; DIST_SYM]);;
+
+let SEGMENT_SCALAR_MULTIPLE = prove
+ (`(!a b v. segment[a % v,b % v] =
+            {x % v:real^N | a <= x /\ x <= b \/ b <= x /\ x <= a}) /\
+   (!a b v. ~(v = vec 0)
+            ==> segment(a % v,b % v) =
+                {x % v:real^N | a < x /\ x < b \/ b < x /\ x < a})`,
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN REPEAT STRIP_TAC THENL
+   [REPEAT GEN_TAC THEN
+    MP_TAC(SPECL [`a % basis 1:real^1`; `b % basis 1:real^1`]
+     (CONJUNCT1 SEGMENT_1)) THEN
+    REWRITE_TAC[segment; VECTOR_MUL_ASSOC; GSYM VECTOR_ADD_RDISTRIB] THEN
+    REWRITE_TAC[SET_RULE `{f x % b | p x} = IMAGE (\a. a % b) {f x | p x}`] THEN
+    DISCH_TAC THEN AP_TERM_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o AP_TERM `IMAGE drop`) THEN
+    REWRITE_TAC[GSYM IMAGE_o; o_DEF; DROP_CMUL] THEN
+    SIMP_TAC[drop; BASIS_COMPONENT; DIMINDEX_GE_1; LE_REFL] THEN
+    REWRITE_TAC[REAL_MUL_RID; IMAGE_ID] THEN DISCH_THEN SUBST1_TAC THEN
+    MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+    CONJ_TAC THENL [MESON_TAC[LIFT_DROP]; ALL_TAC] THEN
+    REWRITE_TAC[FORALL_LIFT; LIFT_DROP] THEN GEN_TAC THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP] THEN
+    SIMP_TAC[drop; VECTOR_MUL_COMPONENT; BASIS_COMPONENT; DIMINDEX_GE_1;
+             LE_REFL; IN_ELIM_THM] THEN ASM_REAL_ARITH_TAC;
+    ASM_REWRITE_TAC[open_segment] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_RCANCEL; SET_RULE
+     `(!x y. x % v = y % v <=> x = y)
+      ==> {x % v | P x} DIFF {a % v,b % v} =
+          {x % v | P x /\ ~(x = a) /\ ~(x = b)}`] THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN AP_TERM_TAC THEN
+    REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN REAL_ARITH_TAC]);;
+
+let FINITE_INTER_COLLINEAR_OPEN_SEGMENTS = prove
+ (`!a b c d:real^N.
+        collinear{a,b,c}
+        ==> (FINITE(segment(a,b) INTER segment(c,d)) <=>
+             segment(a,b) INTER segment(c,d) = {})`,
+  REPEAT GEN_TAC THEN ABBREV_TAC `m:real^N = b - a` THEN POP_ASSUM MP_TAC THEN
+  GEOM_NORMALIZE_TAC `m:real^N` THEN
+  SIMP_TAC[VECTOR_SUB_EQ; SEGMENT_REFL; INTER_EMPTY; FINITE_EMPTY] THEN
+  X_GEN_TAC `m:real^N` THEN DISCH_TAC THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(SUBST_ALL_TAC o SYM) THEN POP_ASSUM MP_TAC THEN
+  GEOM_ORIGIN_TAC `a:real^N` THEN GEOM_BASIS_MULTIPLE_TAC 1 `b:real^N` THEN
+  X_GEN_TAC `b:real` THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN
+  SIMP_TAC[VECTOR_SUB_RZERO; NORM_MUL; NORM_BASIS; DIMINDEX_GE_1; LE_REFL] THEN
+  ASM_REWRITE_TAC[real_abs; REAL_MUL_RID] THEN DISCH_THEN SUBST_ALL_TAC THEN
+  POP_ASSUM(K ALL_TAC) THEN
+  ASM_CASES_TAC `collinear{vec 0:real^N,&1 % basis 1,y}` THENL
+   [POP_ASSUM MP_TAC THEN
+    SIMP_TAC[COLLINEAR_LEMMA_ALT; BASIS_NONZERO; DIMINDEX_GE_1; LE_REFL] THEN
+    MATCH_MP_TAC(TAUT
+     `~a /\ (b ==> c ==> d) ==> a \/ b ==> a \/ c ==> d`) THEN
+    CONJ_TAC THENL
+     [SIMP_TAC[VECTOR_MUL_LID; BASIS_NONZERO; DIMINDEX_GE_1; LE_REFL];
+      REWRITE_TAC[LEFT_IMP_EXISTS_THM]] THEN
+    X_GEN_TAC `b:real` THEN DISCH_THEN SUBST_ALL_TAC THEN
+    X_GEN_TAC `a:real` THEN DISCH_THEN SUBST_ALL_TAC THEN
+    REWRITE_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RID] THEN
+    SUBST1_TAC(VECTOR_ARITH `vec 0:real^N = &0 % basis 1`) THEN
+    SIMP_TAC[SEGMENT_SCALAR_MULTIPLE; BASIS_NONZERO; DIMINDEX_GE_1; LE_REFL;
+     VECTOR_MUL_RCANCEL; IMAGE_EQ_EMPTY; FINITE_IMAGE_INJ_EQ; SET_RULE
+     `(!x y. x % v = y % v <=> x = y)
+      ==> {x % v | P x} INTER {x % v | Q x} =
+          IMAGE (\x. x % v) {x | P x /\ Q x}`] THEN
+    REWRITE_TAC[REAL_ARITH `(&0 < x /\ x < &1 \/ &1 < x /\ x < &0) /\
+                            (b < x /\ x < a \/ a < x /\ x < b) <=>
+                       max (&0) (min a b) < x /\ x < min (&1) (max a b)`] THEN
+    SIMP_TAC[FINITE_REAL_INTERVAL; EXTENSION; NOT_IN_EMPTY; IN_ELIM_THM] THEN
+    SIMP_TAC[GSYM REAL_LT_BETWEEN; GSYM NOT_EXISTS_THM] THEN REAL_ARITH_TAC;
+    DISCH_TAC THEN ASM_CASES_TAC
+     `segment(vec 0:real^N,&1 % basis 1) INTER segment (x,y) = {}` THEN
+    ASM_REWRITE_TAC[FINITE_EMPTY] THEN DISCH_THEN(K ALL_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    REWRITE_TAC[open_segment; IN_DIFF; NOT_IN_EMPTY;
+                DE_MORGAN_THM; IN_INTER; IN_INSERT] THEN
+    DISCH_THEN(X_CHOOSE_THEN `p:real^N` STRIP_ASSUME_TAC) THEN
+    UNDISCH_TAC `~collinear{vec 0:real^N,&1 % basis 1, y}` THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[VECTOR_MUL_LID]) THEN
+    REWRITE_TAC[VECTOR_MUL_LID] THEN
+    MATCH_MP_TAC COLLINEAR_SUBSET THEN
+    EXISTS_TAC `{p,x:real^N, y, vec 0, basis 1}` THEN
+    CONJ_TAC THENL [ALL_TAC; SET_TAC[]] THEN
+    MP_TAC(ISPECL [`{y:real^N,vec 0,basis 1}`; `p:real^N`; `x:real^N`]
+        COLLINEAR_TRIPLES) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
+    REWRITE_TAC[FORALL_IN_INSERT; NOT_IN_EMPTY] THEN CONJ_TAC THENL
+     [ONCE_REWRITE_TAC[SET_RULE `{p,x,y} = {x,p,y}`] THEN
+      MATCH_MP_TAC BETWEEN_IMP_COLLINEAR THEN
+      ASM_REWRITE_TAC[BETWEEN_IN_SEGMENT];
+      ALL_TAC] THEN
+    ASM_SIMP_TAC[GSYM COLLINEAR_4_3] THEN
+    ONCE_REWRITE_TAC[SET_RULE `{p,x,z,w} = {w,z,p,x}`] THEN
+    SIMP_TAC[COLLINEAR_4_3; BASIS_NONZERO; DIMINDEX_GE_1; ARITH] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o MATCH_MP BETWEEN_IMP_COLLINEAR o
+        GEN_REWRITE_RULE I [GSYM BETWEEN_IN_SEGMENT])) THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN SIMP_TAC[INSERT_AC]]);;
+
+let DIST_IN_CLOSED_SEGMENT,DIST_IN_OPEN_SEGMENT = (CONJ_PAIR o prove)
+ (`(!a b x:real^N.
+    x IN segment[a,b] ==> dist(x,a) <= dist(a,b) /\ dist(x,b) <= dist(a,b)) /\
+   (!a b x:real^N.
+    x IN segment(a,b) ==> dist(x,a) < dist(a,b) /\ dist(x,b) < dist(a,b))`,
+  SIMP_TAC[IN_SEGMENT; RIGHT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM; dist;
+           VECTOR_ARITH
+    `((&1 - u) % a + u % b) - a:real^N = u % (b - a) /\
+     ((&1 - u) % a + u % b) - b = --(&1 - u) % (b - a)`] THEN
+  REWRITE_TAC[NORM_MUL; REAL_ABS_NEG; NORM_SUB] THEN CONJ_TAC THEN
+  REPEAT GEN_TAC THEN STRIP_TAC THENL
+   [REWRITE_TAC[REAL_ARITH `x * y <= y <=> x * y <= &1 * y`] THEN
+    CONJ_TAC THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+    REWRITE_TAC[NORM_POS_LE] THEN ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[REAL_ARITH `x * y < y <=> x * y < &1 * y`] THEN
+    ASM_SIMP_TAC[REAL_LT_RMUL_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Limit component bounds.                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_COMPONENT_UBOUND = prove
+ (`!net:(A)net f (l:real^N) b k.
+        ~(trivial_limit net) /\ (f --> l) net /\
+        eventually (\x. (f x)$k <= b) net /\
+        1 <= k /\ k <= dimindex(:N)
+        ==> l$k <= b`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`net:(A)net`; `f:A->real^N`; `{y:real^N | basis k dot y <= b}`; `l:real^N`]
+   LIM_IN_CLOSED_SET) THEN
+  ASM_SIMP_TAC[CLOSED_HALFSPACE_LE; IN_ELIM_THM; DOT_BASIS]);;
+
+let LIM_COMPONENT_LBOUND = prove
+ (`!net:(A)net f (l:real^N) b k.
+        ~(trivial_limit net) /\ (f --> l) net /\
+        eventually (\x. b <= (f x)$k) net /\
+        1 <= k /\ k <= dimindex(:N)
+        ==> b <= l$k`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`net:(A)net`; `f:A->real^N`; `{y:real^N | b <= basis k dot y}`; `l:real^N`]
+   LIM_IN_CLOSED_SET) THEN
+  ASM_SIMP_TAC[REWRITE_RULE[real_ge] CLOSED_HALFSPACE_GE;
+               IN_ELIM_THM; DOT_BASIS]);;
+
+let LIM_COMPONENT_EQ = prove
+ (`!net f:A->real^N i l b.
+        (f --> l) net /\ 1 <= i /\ i <= dimindex(:N) /\
+        ~(trivial_limit net) /\ eventually (\x. f(x)$i = b) net
+        ==> l$i = b`,
+  REWRITE_TAC[GSYM REAL_LE_ANTISYM; EVENTUALLY_AND] THEN
+  MESON_TAC[LIM_COMPONENT_UBOUND; LIM_COMPONENT_LBOUND]);;
+
+let LIM_COMPONENT_LE = prove
+ (`!net:(A)net f:A->real^N g:A->real^N k l m.
+         ~(trivial_limit net) /\ (f --> l) net /\ (g --> m) net /\
+        eventually (\x. (f x)$k <= (g x)$k) net /\
+        1 <= k /\ k <= dimindex(:N)
+        ==> l$k <= m$k`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_SUB_LE] THEN
+  REWRITE_TAC[GSYM VECTOR_SUB_COMPONENT; LIM_COMPONENT_LBOUND] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> b /\ a ==> c ==> d`] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LIM_SUB) THEN POP_ASSUM MP_TAC THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC; LIM_COMPONENT_LBOUND]);;
+
+let LIM_DROP_LE = prove
+ (`!net:(A)net f g l m.
+         ~(trivial_limit net) /\ (f --> l) net /\ (g --> m) net /\
+        eventually (\x. drop(f x) <= drop(g x)) net
+        ==> drop l <= drop m`,
+  REWRITE_TAC[drop] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(ISPEC `net:(A)net` LIM_COMPONENT_LE) THEN
+  MAP_EVERY EXISTS_TAC [`f:A->real^1`; `g:A->real^1`] THEN
+  ASM_REWRITE_TAC[DIMINDEX_1; LE_REFL]);;
+
+let LIM_DROP_UBOUND = prove
+ (`!net f:A->real^1 l b.
+        (f --> l) net /\
+        ~(trivial_limit net) /\ eventually (\x. drop(f x) <= b) net
+        ==> drop l <= b`,
+  SIMP_TAC[drop] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC LIM_COMPONENT_UBOUND THEN
+  REWRITE_TAC[LE_REFL; DIMINDEX_1] THEN ASM_MESON_TAC[]);;
+
+let LIM_DROP_LBOUND = prove
+ (`!net f:A->real^1 l b.
+        (f --> l) net /\
+        ~(trivial_limit net) /\ eventually (\x. b <= drop(f x)) net
+        ==> b <= drop l`,
+  SIMP_TAC[drop] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC LIM_COMPONENT_LBOUND THEN
+  REWRITE_TAC[LE_REFL; DIMINDEX_1] THEN ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Also extending closed bounds to closures.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let IMAGE_CLOSURE_SUBSET = prove
+ (`!f (s:real^N->bool) (t:real^M->bool).
+      f continuous_on closure s /\ closed t /\ IMAGE f s SUBSET t
+      ==> IMAGE f (closure s) SUBSET t`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `closure s SUBSET {x | (f:real^N->real^M) x IN t}` MP_TAC
+  THENL [MATCH_MP_TAC SUBSET_TRANS; SET_TAC []]  THEN
+  EXISTS_TAC `{x | x IN closure s /\ (f:real^N->real^M) x IN t}` THEN
+  CONJ_TAC THENL
+  [MATCH_MP_TAC CLOSURE_MINIMAL; SET_TAC[]] THEN
+  ASM_SIMP_TAC[CONTINUOUS_CLOSED_PREIMAGE; CLOSED_CLOSURE] THEN
+  MP_TAC (ISPEC `s:real^N->bool` CLOSURE_SUBSET) THEN ASM SET_TAC[]);;
+
+let CLOSURE_IMAGE_CLOSURE = prove
+ (`!f:real^M->real^N s.
+        f continuous_on closure s
+        ==> closure(IMAGE f (closure s)) = closure(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+  SIMP_TAC[SUBSET_CLOSURE; IMAGE_SUBSET; CLOSURE_SUBSET] THEN
+  SIMP_TAC[CLOSURE_MINIMAL_EQ; CLOSED_CLOSURE] THEN
+  MATCH_MP_TAC IMAGE_CLOSURE_SUBSET THEN
+  ASM_REWRITE_TAC[CLOSED_CLOSURE; CLOSURE_SUBSET]);;
+
+let CONTINUOUS_ON_CLOSURE_NORM_LE = prove
+ (`!f:real^N->real^M s x b.
+      f continuous_on (closure s) /\
+      (!y. y IN s ==> norm(f y) <= b) /\
+      x IN (closure s)
+      ==> norm(f x) <= b`,
+  REWRITE_TAC [GSYM IN_CBALL_0] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `IMAGE (f:real^N->real^M) (closure s) SUBSET cball(vec 0,b)`
+    MP_TAC THENL
+  [MATCH_MP_TAC IMAGE_CLOSURE_SUBSET; ASM SET_TAC []] THEN
+  ASM_REWRITE_TAC [CLOSED_CBALL] THEN ASM SET_TAC []);;
+
+let CONTINUOUS_ON_CLOSURE_COMPONENT_LE = prove
+ (`!f:real^N->real^M s x b k.
+      f continuous_on (closure s) /\
+      (!y. y IN s ==> (f y)$k <= b) /\
+      x IN (closure s)
+      ==> (f x)$k <= b`,
+  REWRITE_TAC [GSYM IN_CBALL_0] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `IMAGE (f:real^N->real^M) (closure s) SUBSET {x | x$k <= b}`
+  MP_TAC THENL
+   [MATCH_MP_TAC IMAGE_CLOSURE_SUBSET; ASM SET_TAC []] THEN
+  ASM_REWRITE_TAC[CLOSED_HALFSPACE_COMPONENT_LE] THEN ASM SET_TAC[]);;
+
+let CONTINUOUS_ON_CLOSURE_COMPONENT_GE = prove
+ (`!f:real^N->real^M s x b k.
+      f continuous_on (closure s) /\
+      (!y. y IN s ==> b <= (f y)$k) /\
+      x IN (closure s)
+      ==> b <= (f x)$k`,
+  REWRITE_TAC [GSYM IN_CBALL_0] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `IMAGE (f:real^N->real^M) (closure s) SUBSET {x | x$k >= b}`
+  MP_TAC THENL
+   [MATCH_MP_TAC IMAGE_CLOSURE_SUBSET; ASM SET_TAC [real_ge]] THEN
+  ASM_REWRITE_TAC[CLOSED_HALFSPACE_COMPONENT_GE] THEN ASM SET_TAC[real_ge]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Limits relative to a union.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_WITHIN_UNION = prove
+ (`(f --> l) (at x within (s UNION t)) <=>
+   (f --> l) (at x within s) /\ (f --> l) (at x within t)`,
+  REWRITE_TAC[LIM_WITHIN; IN_UNION; AND_FORALL_THM] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `e:real` THEN
+  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
+  EQ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN DISCH_THEN
+   (CONJUNCTS_THEN2 (X_CHOOSE_TAC `d:real`) (X_CHOOSE_TAC `k:real`)) THEN
+  EXISTS_TAC `min d k` THEN ASM_REWRITE_TAC[REAL_LT_MIN] THEN
+  ASM_MESON_TAC[]);;
+
+let CONTINUOUS_ON_UNION = prove
+ (`!f s t. closed s /\ closed t /\ f continuous_on s /\ f continuous_on t
+           ==> f continuous_on (s UNION t)`,
+  REWRITE_TAC[CONTINUOUS_ON; CLOSED_LIMPT; IN_UNION; LIM_WITHIN_UNION] THEN
+  MESON_TAC[LIM; TRIVIAL_LIMIT_WITHIN]);;
+
+let CONTINUOUS_ON_CASES = prove
+ (`!P f g:real^M->real^N s t.
+        closed s /\ closed 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 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_UNION_LOCAL = prove
+ (`!f:real^M->real^N s.
+        closed_in (subtopology euclidean (s UNION t)) s /\
+        closed_in (subtopology euclidean (s UNION t)) t /\
+        f continuous_on s /\ f continuous_on t
+        ==> f continuous_on (s UNION t)`,
+  REWRITE_TAC[CONTINUOUS_ON; CLOSED_IN_LIMPT; IN_UNION; LIM_WITHIN_UNION] THEN
+  MESON_TAC[LIM; TRIVIAL_LIMIT_WITHIN]);;
+
+let CONTINUOUS_ON_CASES_LOCAL = prove
+ (`!P f g:real^M->real^N s t.
+        closed_in (subtopology euclidean (s UNION t)) s /\
+        closed_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 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_LE = prove
+ (`!f g:real^M->real^N h s a.
+        f continuous_on {t | t IN s /\ h t <= a} /\
+        g continuous_on {t | t IN s /\ a <= h t} /\
+        (lift o h) continuous_on s /\
+        (!t. t IN s /\ h t = a ==> f t = g t)
+        ==> (\t. if h t <= a then f(t) else g(t)) continuous_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC
+   `{t | t IN s /\ (h:real^M->real) t <= a} UNION
+    {t | t IN s /\ a <= h t}` THEN
+  CONJ_TAC THENL
+   [ALL_TAC; SIMP_TAC[SUBSET; IN_UNION; IN_ELIM_THM; REAL_LE_TOTAL]] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[IN_ELIM_THM; GSYM CONJ_ASSOC; REAL_LE_ANTISYM] THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[]] THEN
+  CONJ_TAC THENL
+   [SUBGOAL_THEN
+     `{t | t IN s /\ (h:real^M->real) t <= a} =
+      {t | t IN ({t | t IN s /\ h t <= a} UNION {t | t IN s /\ a <= h t}) /\
+           (lift o h) t IN {x | x$1 <= a}}`
+     (fun th -> GEN_REWRITE_TAC RAND_CONV [th])
+    THENL
+     [REWRITE_TAC[GSYM drop; o_THM; IN_ELIM_THM; LIFT_DROP; EXTENSION;
+                  IN_UNION] THEN
+      GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      ASM_REAL_ARITH_TAC;
+      MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE THEN
+      ASM_REWRITE_TAC[CLOSED_HALFSPACE_COMPONENT_LE; ETA_AX] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+      SET_TAC[]];
+    SUBGOAL_THEN
+     `{t | t IN s /\ a <= (h:real^M->real) t} =
+      {t | t IN ({t | t IN s /\ h t <= a} UNION {t | t IN s /\ a <= h t}) /\
+           (lift o h) t IN {x | x$1 >= a}}`
+     (fun th -> GEN_REWRITE_TAC RAND_CONV [th])
+    THENL
+     [REWRITE_TAC[GSYM drop; o_THM; IN_ELIM_THM; LIFT_DROP; EXTENSION;
+                  IN_UNION] THEN
+      GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      ASM_REAL_ARITH_TAC;
+      MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE THEN
+      ASM_REWRITE_TAC[CLOSED_HALFSPACE_COMPONENT_GE; ETA_AX] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN
+      SET_TAC[]]]);;
+
+let CONTINUOUS_ON_CASES_1 = prove
+ (`!f g:real^1->real^N s a.
+        f continuous_on {t | t IN s /\ drop t <= a} /\
+        g continuous_on {t | t IN s /\ a <= drop t} /\
+        (lift a IN s ==> f(lift a) = g(lift a))
+        ==> (\t. if drop t <= a then f(t) else g(t)) continuous_on s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_CASES_LE THEN
+  ASM_REWRITE_TAC[o_DEF; LIFT_DROP; CONTINUOUS_ON_ID] THEN
+  REWRITE_TAC[GSYM LIFT_EQ; LIFT_DROP] THEN ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Componentwise limits and continuity.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_COMPONENTWISE_LIFT = prove
+ (`!net f:A->real^N.
+        (f --> l) net <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> ((\x. lift((f x)$i)) --> lift(l$i)) net`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[tendsto] THEN EQ_TAC THENL
+   [DISCH_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    X_GEN_TAC `e:real` THEN
+    DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e:real`) THEN
+    ASM_SIMP_TAC[GSYM VECTOR_SUB_COMPONENT] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+    GEN_TAC THEN REWRITE_TAC[dist] THEN MATCH_MP_TAC(REAL_ARITH
+     `y <= x ==> x < e ==> y < e`) THEN
+    ASM_SIMP_TAC[COMPONENT_LE_NORM; GSYM LIFT_SUB; NORM_LIFT;
+                 GSYM VECTOR_SUB_COMPONENT];
+    GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [RIGHT_IMP_FORALL_THM] THEN
+    ONCE_REWRITE_TAC[IMP_IMP] THEN ONCE_REWRITE_TAC[IMP_CONJ_ALT] THEN
+    ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+    REWRITE_TAC[GSYM IN_NUMSEG; RIGHT_FORALL_IMP_THM] THEN
+    SIMP_TAC[FORALL_EVENTUALLY; FINITE_NUMSEG; NUMSEG_EMPTY;
+             GSYM NOT_LE; DIMINDEX_GE_1] THEN
+    REWRITE_TAC[DIST_LIFT; GSYM VECTOR_SUB_COMPONENT] THEN
+    DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `e / &(dimindex(:N))`) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] EVENTUALLY_MONO) THEN
+    X_GEN_TAC `x:A` THEN SIMP_TAC[GSYM VECTOR_SUB_COMPONENT; dist] THEN
+    DISCH_TAC THEN W(MP_TAC o PART_MATCH lhand NORM_LE_L1 o lhand o snd) THEN
+    MATCH_MP_TAC(REAL_ARITH `s < e ==> n <= s ==> n < e`) THEN
+    MATCH_MP_TAC SUM_BOUND_LT_GEN THEN
+    ASM_SIMP_TAC[FINITE_NUMSEG; NUMSEG_EMPTY; GSYM NOT_LE; DIMINDEX_GE_1;
+                 CARD_NUMSEG_1; GSYM IN_NUMSEG]]);;
+
+let CONTINUOUS_COMPONENTWISE_LIFT = prove
+ (`!net f:A->real^N.
+        f continuous net <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> (\x. lift((f x)$i)) continuous net`,
+  REWRITE_TAC[continuous; GSYM LIM_COMPONENTWISE_LIFT]);;
+
+let CONTINUOUS_ON_COMPONENTWISE_LIFT = prove
+ (`!f:real^M->real^N s.
+        f continuous_on s <=>
+        !i. 1 <= i /\ i <= dimindex(:N)
+            ==> (\x. lift((f x)$i)) continuous_on s`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+   [CONTINUOUS_COMPONENTWISE_LIFT] THEN
+  MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some more convenient intermediate-value theorem formulations.             *)
+(* ------------------------------------------------------------------------- *)
+
+let CONNECTED_IVT_HYPERPLANE = prove
+ (`!s x y:real^N a b.
+        connected s /\
+        x IN s /\ y IN s /\ a dot x <= b /\ b <= a dot y
+        ==> ?z. z IN s /\ a dot z = b`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [connected]) THEN
+  REWRITE_TAC[NOT_EXISTS_THM] THEN DISCH_THEN(MP_TAC o SPECL
+   [`{x:real^N | a dot x < b}`; `{x:real^N | a dot x > b}`]) THEN
+  REWRITE_TAC[OPEN_HALFSPACE_LT; OPEN_HALFSPACE_GT] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN STRIP_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INTER; NOT_IN_EMPTY; SUBSET;
+              IN_UNION; REAL_LT_LE; real_gt] THEN
+  ASM_MESON_TAC[REAL_LE_TOTAL; REAL_LE_ANTISYM]);;
+
+let CONNECTED_IVT_COMPONENT = prove
+ (`!s x y:real^N a k.
+        connected s /\ x IN s /\ y IN s /\
+        1 <= k /\ k <= dimindex(:N) /\ x$k <= a /\ a <= y$k
+        ==> ?z. z IN s /\ z$k = a`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPECL
+   [`s:real^N->bool`; `x:real^N`; `y:real^N`; `(basis k):real^N`;
+    `a:real`] CONNECTED_IVT_HYPERPLANE) THEN
+  ASM_SIMP_TAC[DOT_BASIS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Also more convenient formulations of monotone convergence.                *)
+(* ------------------------------------------------------------------------- *)
+
+let BOUNDED_INCREASING_CONVERGENT = prove
+ (`!s:num->real^1.
+        bounded {s n | n IN (:num)} /\ (!n. drop(s n) <= drop(s(SUC n)))
+        ==> ?l. (s --> l) sequentially`,
+  GEN_TAC THEN
+  REWRITE_TAC[bounded; IN_ELIM_THM; ABS_DROP; LIM_SEQUENTIALLY; dist;
+              DROP_SUB; IN_UNIV; GSYM EXISTS_DROP] THEN
+  DISCH_TAC THEN MATCH_MP_TAC CONVERGENT_BOUNDED_MONOTONE THEN
+  REWRITE_TAC[LEFT_EXISTS_AND_THM] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  DISJ1_TAC THEN MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN
+  ASM_REWRITE_TAC[REAL_LE_TRANS; REAL_LE_REFL]);;
+
+let BOUNDED_DECREASING_CONVERGENT = prove
+ (`!s:num->real^1.
+        bounded {s n | n IN (:num)} /\ (!n. drop(s(SUC n)) <= drop(s(n)))
+        ==> ?l. (s --> l) sequentially`,
+  GEN_TAC THEN REWRITE_TAC[bounded; FORALL_IN_GSPEC] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  MP_TAC(ISPEC `\n. --((s:num->real^1) n)` BOUNDED_INCREASING_CONVERGENT) THEN
+  ASM_SIMP_TAC[bounded; FORALL_IN_GSPEC; NORM_NEG; DROP_NEG; REAL_LE_NEG2] THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [GSYM LIM_NEG_EQ] THEN
+  REWRITE_TAC[VECTOR_NEG_NEG; ETA_AX] THEN MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Since we'll use some cardinality reasoning, add invariance theorems.      *)
+(* ------------------------------------------------------------------------- *)
+
+let card_translation_invariants = (CONJUNCTS o prove)
+ (`(!a (s:real^N->bool) (t:A->bool).
+     IMAGE (\x. a + x) s =_c t <=> s =_c t) /\
+   (!a (s:A->bool) (t:real^N->bool).
+     s =_c IMAGE (\x. a + x) t <=> s =_c t) /\
+   (!a (s:real^N->bool) (t:A->bool).
+     IMAGE (\x. a + x) s <_c t <=> s <_c t) /\
+   (!a (s:A->bool) (t:real^N->bool).
+     s <_c IMAGE (\x. a + x) t <=> s <_c t) /\
+   (!a (s:real^N->bool) (t:A->bool).
+     IMAGE (\x. a + x) s <=_c t <=> s <=_c t) /\
+   (!a (s:A->bool) (t:real^N->bool).
+     s <=_c IMAGE (\x. a + x) t <=> s <=_c t) /\
+   (!a (s:real^N->bool) (t:A->bool).
+     IMAGE (\x. a + x) s >_c t <=> s >_c t) /\
+   (!a (s:A->bool) (t:real^N->bool).
+     s >_c IMAGE (\x. a + x) t <=> s >_c t) /\
+   (!a (s:real^N->bool) (t:A->bool).
+     IMAGE (\x. a + x) s >=_c t <=> s >=_c t) /\
+   (!a (s:A->bool) (t:real^N->bool).
+     s >=_c IMAGE (\x. a + x) t <=> s >=_c t)`,
+  REWRITE_TAC[gt_c; ge_c] THEN REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC CARD_EQ_CONG;
+    MATCH_MP_TAC CARD_EQ_CONG;
+    MATCH_MP_TAC CARD_LT_CONG;
+    MATCH_MP_TAC CARD_LT_CONG;
+    MATCH_MP_TAC CARD_LE_CONG;
+    MATCH_MP_TAC CARD_LE_CONG;
+    MATCH_MP_TAC CARD_LT_CONG;
+    MATCH_MP_TAC CARD_LT_CONG;
+    MATCH_MP_TAC CARD_LE_CONG;
+    MATCH_MP_TAC CARD_LE_CONG] THEN
+  REWRITE_TAC[CARD_EQ_REFL] THEN MATCH_MP_TAC CARD_EQ_IMAGE THEN
+  SIMP_TAC[VECTOR_ARITH `a + x:real^N = a + y <=> x = y`]) in
+add_translation_invariants card_translation_invariants;;
+
+let card_linear_invariants = (CONJUNCTS o prove)
+ (`(!(f:real^M->real^N) s (t:A->bool).
+     linear f /\ (!x y. f x = f y ==> x = y)
+     ==> (IMAGE f s =_c t <=> s =_c t)) /\
+   (!(f:real^M->real^N) (s:A->bool) t.
+     linear f /\ (!x y. f x = f y ==> x = y)
+     ==> (s =_c IMAGE f t <=> s =_c t)) /\
+   (!(f:real^M->real^N) s (t:A->bool).
+     linear f /\ (!x y. f x = f y ==> x = y)
+     ==> (IMAGE f s <_c t <=> s <_c t)) /\
+   (!(f:real^M->real^N) (s:A->bool) t.
+     linear f /\ (!x y. f x = f y ==> x = y)
+     ==> (s <_c IMAGE f t <=> s <_c t)) /\
+   (!(f:real^M->real^N) s (t:A->bool).
+     linear f /\ (!x y. f x = f y ==> x = y)
+     ==> (IMAGE f s <=_c t <=> s <=_c t)) /\
+   (!(f:real^M->real^N) (s:A->bool) t.
+     linear f /\ (!x y. f x = f y ==> x = y)
+     ==> (s <=_c IMAGE f t <=> s <=_c t)) /\
+   (!(f:real^M->real^N) s (t:A->bool).
+     linear f /\ (!x y. f x = f y ==> x = y)
+     ==> (IMAGE f s >_c t <=> s >_c t)) /\
+   (!(f:real^M->real^N) (s:A->bool) t.
+     linear f /\ (!x y. f x = f y ==> x = y)
+     ==> (s >_c IMAGE f t <=> s >_c t)) /\
+   (!(f:real^M->real^N) s (t:A->bool).
+     linear f /\ (!x y. f x = f y ==> x = y)
+     ==> (IMAGE f s >=_c t <=> s >=_c t)) /\
+   (!(f:real^M->real^N) (s:A->bool) t.
+     linear f /\ (!x y. f x = f y ==> x = y)
+     ==> (s >=_c IMAGE f t <=> s >=_c t))`,
+  REWRITE_TAC[gt_c; ge_c] THEN REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC CARD_EQ_CONG;
+    MATCH_MP_TAC CARD_EQ_CONG;
+    MATCH_MP_TAC CARD_LT_CONG;
+    MATCH_MP_TAC CARD_LT_CONG;
+    MATCH_MP_TAC CARD_LE_CONG;
+    MATCH_MP_TAC CARD_LE_CONG;
+    MATCH_MP_TAC CARD_LT_CONG;
+    MATCH_MP_TAC CARD_LT_CONG;
+    MATCH_MP_TAC CARD_LE_CONG;
+    MATCH_MP_TAC CARD_LE_CONG] THEN
+  REWRITE_TAC[CARD_EQ_REFL] THEN MATCH_MP_TAC CARD_EQ_IMAGE THEN
+  ASM_MESON_TAC[]) in
+add_linear_invariants card_linear_invariants;;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic homeomorphism definitions.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let homeomorphism = new_definition
+  `homeomorphism (s,t) (f,g) <=>
+     (!x. x IN s ==> (g(f(x)) = x)) /\ (IMAGE f s = t) /\ f continuous_on s /\
+     (!y. y IN t ==> (f(g(y)) = y)) /\ (IMAGE g t = s) /\ g continuous_on t`;;
+
+parse_as_infix("homeomorphic",(12,"right"));;
+
+let homeomorphic = new_definition
+  `s homeomorphic t <=> ?f g. homeomorphism (s,t) (f,g)`;;
+
+let HOMEOMORPHISM = prove
+ (`!s:real^M->bool t:real^N->bool f g.
+        homeomorphism (s,t) (f,g) <=>
+         f continuous_on s /\ IMAGE f s SUBSET t /\
+         g continuous_on t /\ IMAGE g t SUBSET s /\
+         (!x. x IN s ==> g (f x) = x) /\
+         (!y. y IN t ==> f (g y) = y)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homeomorphism] THEN
+  EQ_TAC THEN SIMP_TAC[] THEN SET_TAC[]);;
+
+let HOMEOMORPHISM_OF_SUBSETS = prove
+ (`!f g s t s' t'.
+    homeomorphism (s,t) (f,g) /\ s' SUBSET s /\ t' SUBSET t /\ IMAGE f s' = t'
+    ==> homeomorphism (s',t') (f,g)`,
+  REWRITE_TAC[homeomorphism] THEN
+  REPEAT STRIP_TAC THEN
+  TRY(MATCH_MP_TAC CONTINUOUS_ON_SUBSET) THEN ASM SET_TAC[]);;
+
+let HOMEOMORPHISM_ID = prove
+ (`!s:real^N->bool. homeomorphism (s,s) ((\x. x),(\x. x))`,
+  REWRITE_TAC[homeomorphism; IMAGE_ID; CONTINUOUS_ON_ID]);;
+
+let HOMEOMORPHISM_I = prove
+ (`!s:real^N->bool. homeomorphism (s,s) (I,I)`,
+  REWRITE_TAC[I_DEF; HOMEOMORPHISM_ID]);;
+
+let HOMEOMORPHIC_REFL = prove
+ (`!s:real^N->bool. s homeomorphic s`,
+  REWRITE_TAC[homeomorphic] THEN MESON_TAC[HOMEOMORPHISM_I]);;
+
+let HOMEOMORPHISM_SYM = prove
+ (`!f:real^M->real^N g s t.
+        homeomorphism (s,t) (f,g) <=> homeomorphism (t,s) (g,f)`,
+  REWRITE_TAC[homeomorphism] THEN MESON_TAC[]);;
+
+let HOMEOMORPHIC_SYM = prove
+ (`!s t. s homeomorphic t <=> t homeomorphic s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homeomorphic; homeomorphism] THEN
+  GEN_REWRITE_TAC RAND_CONV [SWAP_EXISTS_THM] THEN
+  REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN CONV_TAC TAUT);;
+
+let HOMEOMORPHISM_COMPOSE = prove
+ (`!f:real^M->real^N g h:real^N->real^P k s t u.
+        homeomorphism (s,t) (f,g) /\ homeomorphism (t,u) (h,k)
+        ==> homeomorphism (s,u) (h o f,g o k)`,
+  SIMP_TAC[homeomorphism; CONTINUOUS_ON_COMPOSE; IMAGE_o; o_THM] THEN
+  SET_TAC[]);;
+
+let HOMEOMORPHIC_TRANS = prove
+ (`!s:real^M->bool t:real^N->bool u:real^P->bool.
+        s homeomorphic t /\ t homeomorphic u ==> s homeomorphic u`,
+  REWRITE_TAC[homeomorphic] THEN MESON_TAC[HOMEOMORPHISM_COMPOSE]);;
+
+let HOMEOMORPHIC_IMP_CARD_EQ = prove
+ (`!s:real^M->bool t:real^N->bool. s homeomorphic t ==> s =_c t`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homeomorphic; homeomorphism; eq_c] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SET_TAC[]);;
+
+let HOMEOMORPHIC_EMPTY = prove
+ (`(!s. (s:real^N->bool) homeomorphic ({}:real^M->bool) <=> s = {}) /\
+   (!s. ({}:real^M->bool) homeomorphic (s:real^N->bool) <=> s = {})`,
+  REWRITE_TAC[homeomorphic; homeomorphism; IMAGE_CLAUSES; IMAGE_EQ_EMPTY] THEN
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[continuous_on; NOT_IN_EMPTY]);;
+
+let HOMEOMORPHIC_MINIMAL = prove
+ (`!s t. s homeomorphic t <=>
+            ?f g. (!x. x IN s ==> f(x) IN t /\ (g(f(x)) = x)) /\
+                  (!y. y IN t ==> g(y) IN s /\ (f(g(y)) = y)) /\
+                  f continuous_on s /\ g continuous_on t`,
+  REWRITE_TAC[homeomorphic; homeomorphism; EXTENSION; IN_IMAGE] THEN
+  REPEAT GEN_TAC THEN REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN MESON_TAC[]);;
+
+let HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_SELF = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (IMAGE f s) homeomorphic s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INJECTIVE_LEFT_INVERSE]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN DISCH_TAC THEN
+  EXISTS_TAC `f:real^M->real^N` THEN
+  ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON; FORALL_IN_IMAGE; FUN_IN_IMAGE] THEN
+  ASM_SIMP_TAC[continuous_on; IMP_CONJ; FORALL_IN_IMAGE] THEN
+  X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPEC `f:real^M->real^N` LINEAR_INJECTIVE_BOUNDED_BELOW_POS) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `e * B:real` THEN ASM_SIMP_TAC[REAL_LT_MUL] THEN
+  X_GEN_TAC `y:real^M` THEN ASM_SIMP_TAC[dist; GSYM LINEAR_SUB] THEN
+  DISCH_TAC THEN ASM_SIMP_TAC[GSYM REAL_LT_LDIV_EQ] THEN
+  MATCH_MP_TAC(REAL_ARITH `a <= b ==> b < x ==> a < x`) THEN
+  ASM_SIMP_TAC[REAL_LE_RDIV_EQ]);;
+
+let HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_LEFT_EQ = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> ((IMAGE f s) homeomorphic t <=> s homeomorphic t)`,
+  REPEAT GEN_TAC THEN DISCH_THEN(ASSUME_TAC o SPEC `s:real^M->bool` o
+    MATCH_MP HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_SELF) THEN
+  EQ_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [HOMEOMORPHIC_SYM]);
+    POP_ASSUM MP_TAC] THEN
+  REWRITE_TAC[IMP_IMP; HOMEOMORPHIC_TRANS]);;
+
+let HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (s homeomorphic (IMAGE f t) <=> s homeomorphic t)`,
+  ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+  REWRITE_TAC[HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_LEFT_EQ]);;
+
+add_linear_invariants
+  [HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_LEFT_EQ;
+   HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ];;
+
+let HOMEOMORPHIC_TRANSLATION_SELF = prove
+ (`!a:real^N s. (IMAGE (\x. a + x) s) homeomorphic s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
+  EXISTS_TAC `\x:real^N. x - a` THEN
+  EXISTS_TAC `\x:real^N. a + x` THEN
+  SIMP_TAC[FORALL_IN_IMAGE; CONTINUOUS_ON_SUB; CONTINUOUS_ON_ID;
+           CONTINUOUS_ON_CONST; CONTINUOUS_ON_ADD; VECTOR_ADD_SUB] THEN
+  REWRITE_TAC[IN_IMAGE] THEN MESON_TAC[]);;
+
+let HOMEOMORPHIC_TRANSLATION_LEFT_EQ = prove
+ (`!a:real^N s t.
+      (IMAGE (\x. a + x) s) homeomorphic t <=> s homeomorphic t`,
+  MESON_TAC[HOMEOMORPHIC_TRANSLATION_SELF;
+            HOMEOMORPHIC_SYM; HOMEOMORPHIC_TRANS]);;
+
+let HOMEOMORPHIC_TRANSLATION_RIGHT_EQ = prove
+ (`!a:real^N s t.
+      s homeomorphic (IMAGE (\x. a + x) t) <=> s homeomorphic t`,
+  ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+  REWRITE_TAC[HOMEOMORPHIC_TRANSLATION_LEFT_EQ]);;
+
+add_translation_invariants
+  [HOMEOMORPHIC_TRANSLATION_LEFT_EQ;
+   HOMEOMORPHIC_TRANSLATION_RIGHT_EQ];;
+
+let HOMEOMORPHISM_IMP_QUOTIENT_MAP = prove
+ (`!f:real^M->real^N g s t.
+    homeomorphism (s,t) (f,g)
+    ==> !u. u SUBSET t
+            ==> (open_in (subtopology euclidean s) {x | x IN s /\ f x IN u} <=>
+                 open_in (subtopology euclidean t) u)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homeomorphism] 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[SUBSET_REFL]);;
+
+let HOMEOMORPHIC_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool s':real^P->bool t':real^Q->bool.
+        s homeomorphic s' /\ t homeomorphic t'
+        ==> (s PCROSS t) homeomorphic (s' PCROSS t')`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homeomorphic; HOMEOMORPHISM] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `f:real^M->real^P`
+     (X_CHOOSE_THEN `f':real^P->real^M` STRIP_ASSUME_TAC))
+   (X_CHOOSE_THEN `g:real^N->real^Q`
+     (X_CHOOSE_THEN `g':real^Q->real^N` STRIP_ASSUME_TAC))) THEN
+  MAP_EVERY EXISTS_TAC
+   [`(\z. pastecart (f(fstcart z)) (g(sndcart z)))
+     :real^(M,N)finite_sum->real^(P,Q)finite_sum`;
+    `(\z. pastecart (f'(fstcart z)) (g'(sndcart z)))
+     :real^(P,Q)finite_sum->real^(M,N)finite_sum`] THEN
+  ASM_SIMP_TAC[FORALL_IN_PCROSS; FSTCART_PASTECART; SNDCART_PASTECART;
+               SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS] THEN
+  CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+  CONJ_TAC THEN ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  SIMP_TAC[LINEAR_FSTCART; LINEAR_SNDCART; LINEAR_CONTINUOUS_ON] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; FORALL_IN_PCROSS; SUBSET] THEN
+  SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART]);;
+
+let HOMEOMORPHIC_PCROSS_SYM = prove
+ (`!s:real^M->bool t:real^N->bool. (s PCROSS t) homeomorphic (t PCROSS s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homeomorphic; homeomorphism] THEN
+  EXISTS_TAC `(\z. pastecart (sndcart z) (fstcart z))
+              :real^(M,N)finite_sum->real^(N,M)finite_sum` THEN
+  EXISTS_TAC `(\z. pastecart (sndcart z) (fstcart z))
+              :real^(N,M)finite_sum->real^(M,N)finite_sum` THEN
+  REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ; SUBSET; FORALL_IN_IMAGE] THEN
+  SIMP_TAC[CONTINUOUS_ON_PASTECART; LINEAR_CONTINUOUS_ON;
+           LINEAR_FSTCART; LINEAR_SNDCART] THEN
+  REWRITE_TAC[FORALL_IN_PCROSS; FSTCART_PASTECART; SNDCART_PASTECART;
+    IN_IMAGE; EXISTS_PASTECART; PASTECART_INJ; PASTECART_IN_PCROSS] THEN
+  MESON_TAC[]);;
+
+let HOMEOMORPHIC_PCROSS_ASSOC = prove
+ (`!s:real^M->bool t:real^N->bool u:real^P->bool.
+        (s PCROSS (t PCROSS u)) homeomorphic ((s PCROSS t) PCROSS u)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homeomorphic; HOMEOMORPHISM] THEN
+  MAP_EVERY EXISTS_TAC
+   [`\z:real^(M,(N,P)finite_sum)finite_sum.
+        pastecart (pastecart (fstcart z) (fstcart(sndcart z)))
+                  (sndcart(sndcart z))`;
+    `\z:real^((M,N)finite_sum,P)finite_sum.
+        pastecart (fstcart(fstcart z))
+                  (pastecart (sndcart(fstcart z)) (sndcart z))`] THEN
+  REWRITE_TAC[FORALL_IN_PCROSS; SUBSET; FORALL_IN_IMAGE;
+              RIGHT_FORALL_IMP_THM; IMP_CONJ] THEN
+  SIMP_TAC[FSTCART_PASTECART; SNDCART_PASTECART; PASTECART_IN_PCROSS] THEN
+  CONJ_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN
+  REPEAT(MATCH_MP_TAC LINEAR_PASTECART THEN CONJ_TAC) THEN
+  TRY(GEN_REWRITE_TAC RAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC LINEAR_COMPOSE) THEN
+  REWRITE_TAC[LINEAR_FSTCART; LINEAR_SNDCART]);;
+
+let HOMEOMORPHIC_SCALING_LEFT = prove
+ (`!c. &0 < c
+       ==> !s t. (IMAGE (\x. c % x) s) homeomorphic t <=> s homeomorphic t`,
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN REPEAT GEN_TAC THEN DISCH_TAC THEN
+  MATCH_MP_TAC HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_LEFT_EQ THEN
+  ASM_SIMP_TAC[VECTOR_MUL_LCANCEL; REAL_LT_IMP_NZ; LINEAR_SCALING]);;
+
+let HOMEOMORPHIC_SCALING_RIGHT = prove
+ (`!c. &0 < c
+       ==> !s t. s homeomorphic (IMAGE (\x. c % x) t) <=> s homeomorphic t`,
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN REPEAT GEN_TAC THEN DISCH_TAC THEN
+  MATCH_MP_TAC HOMEOMORPHIC_INJECTIVE_LINEAR_IMAGE_RIGHT_EQ THEN
+  ASM_SIMP_TAC[VECTOR_MUL_LCANCEL; REAL_LT_IMP_NZ; LINEAR_SCALING]);;
+
+let HOMEOMORPHIC_SUBSPACES = prove
+ (`!s:real^M->bool t:real^N->bool.
+        subspace s /\ subspace t /\ dim s = dim t ==> s homeomorphic t`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[homeomorphic; HOMEOMORPHISM] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP ISOMETRIES_SUBSPACES) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^M->real^N` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^M` THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTER; IN_CBALL_0] THEN
+  SIMP_TAC[LINEAR_CONTINUOUS_ON] THEN ASM SET_TAC[]);;
+
+let HOMEOMORPHIC_FINITE = prove
+ (`!s:real^M->bool t:real^N->bool.
+        FINITE s /\ FINITE t ==> (s homeomorphic t <=> CARD s = CARD t)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [DISCH_THEN(MP_TAC o MATCH_MP HOMEOMORPHIC_IMP_CARD_EQ) THEN
+    ASM_SIMP_TAC[CARD_EQ_CARD];
+    STRIP_TAC THEN REWRITE_TAC[homeomorphic; HOMEOMORPHISM] THEN
+    MP_TAC(ISPECL [`s:real^M->bool`; `t:real^N->bool`]
+        CARD_EQ_BIJECTIONS) THEN
+    ASM_REWRITE_TAC[] THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_FINITE] THEN ASM SET_TAC[]]);;
+
+let HOMEOMORPHIC_FINITE_STRONG = prove
+ (`!s:real^M->bool t:real^N->bool.
+        FINITE s \/ FINITE t
+        ==> (s homeomorphic t <=> FINITE s /\ FINITE t /\ CARD s = CARD t)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN EQ_TAC THEN
+  SIMP_TAC[HOMEOMORPHIC_FINITE] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP CARD_FINITE_CONG o MATCH_MP
+    HOMEOMORPHIC_IMP_CARD_EQ) THEN
+  FIRST_X_ASSUM DISJ_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[HOMEOMORPHIC_FINITE]);;
+
+let HOMEOMORPHIC_SING = prove
+ (`!a:real^M b:real^N. {a} homeomorphic {b}`,
+  SIMP_TAC[HOMEOMORPHIC_FINITE; FINITE_SING; CARD_SING]);;
+
+let HOMEOMORPHIC_PCROSS_SING = prove
+ (`(!s:real^M->bool a:real^N. s homeomorphic (s PCROSS {a})) /\
+   (!s:real^M->bool a:real^N. s homeomorphic ({a} PCROSS s))`,
+  MATCH_MP_TAC(TAUT `(p ==> q) /\ p ==> p /\ q`) THEN CONJ_TAC THENL
+   [MESON_TAC[HOMEOMORPHIC_PCROSS_SYM; HOMEOMORPHIC_TRANS]; ALL_TAC] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[homeomorphic; HOMEOMORPHISM] THEN
+  EXISTS_TAC `\x. (pastecart x a:real^(M,N)finite_sum)` THEN
+  EXISTS_TAC `fstcart:real^(M,N)finite_sum->real^M` THEN
+  SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+  SIMP_TAC[LINEAR_FSTCART; LINEAR_CONTINUOUS_ON; SUBSET; FORALL_IN_IMAGE] THEN
+  REWRITE_TAC[FORALL_IN_PCROSS; PASTECART_IN_PCROSS; IN_SING] THEN
+  SIMP_TAC[FSTCART_PASTECART]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Inverse function property for open/closed maps.                           *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_ON_INVERSE_OPEN_MAP = prove
+ (`!f:real^M->real^N g s t.
+        f continuous_on s /\ IMAGE f s = t /\ (!x. x IN s ==> g(f x) = x) /\
+        (!u. open_in (subtopology euclidean s) u
+             ==> open_in (subtopology euclidean t) (IMAGE f u))
+        ==> g continuous_on t`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`g:real^N->real^M`; `t:real^N->bool`; `s:real^M->bool`]
+        CONTINUOUS_ON_OPEN_GEN) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; DISCH_THEN SUBST1_TAC] THEN
+  X_GEN_TAC `u:real^M->bool` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `u:real^M->bool`) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  FIRST_ASSUM(MP_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [open_in]) THEN
+  ASM SET_TAC[]);;
+
+let CONTINUOUS_ON_INVERSE_CLOSED_MAP = prove
+ (`!f:real^M->real^N g s t.
+        f continuous_on s /\ IMAGE f s = t /\ (!x. x IN s ==> g(f x) = x) /\
+        (!u. closed_in (subtopology euclidean s) u
+             ==> closed_in (subtopology euclidean t) (IMAGE f u))
+        ==> g continuous_on t`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`g:real^N->real^M`; `t:real^N->bool`; `s:real^M->bool`]
+        CONTINUOUS_ON_CLOSED_GEN) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; DISCH_THEN SUBST1_TAC] THEN
+  X_GEN_TAC `u:real^M->bool` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `u:real^M->bool`) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  FIRST_ASSUM(MP_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [closed_in]) THEN
+  REWRITE_TAC[TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN ASM SET_TAC[]);;
+
+let HOMEOMORPHISM_INJECTIVE_OPEN_MAP = prove
+ (`!f:real^M->real^N s t.
+        f continuous_on s /\ IMAGE f s = t /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+        (!u. open_in (subtopology euclidean s) u
+             ==> open_in (subtopology euclidean t) (IMAGE f u))
+        ==> ?g. homeomorphism (s,t) (f,g)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INJECTIVE_ON_LEFT_INVERSE]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^M` THEN
+  DISCH_TAC THEN ASM_SIMP_TAC[homeomorphism] THEN
+  REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+  MATCH_MP_TAC CONTINUOUS_ON_INVERSE_OPEN_MAP THEN ASM_MESON_TAC[]);;
+
+let HOMEOMORPHISM_INJECTIVE_CLOSED_MAP = prove
+ (`!f:real^M->real^N s t.
+        f continuous_on s /\ IMAGE f s = t /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+        (!u. closed_in (subtopology euclidean s) u
+             ==> closed_in (subtopology euclidean t) (IMAGE f u))
+        ==> ?g. homeomorphism (s,t) (f,g)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INJECTIVE_ON_LEFT_INVERSE]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^M` THEN
+  DISCH_TAC THEN ASM_SIMP_TAC[homeomorphism] THEN
+  REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+  MATCH_MP_TAC CONTINUOUS_ON_INVERSE_CLOSED_MAP THEN ASM_MESON_TAC[]);;
+
+let HOMEOMORPHISM_IMP_OPEN_MAP = prove
+ (`!f:real^M->real^N g s t u.
+        homeomorphism (s,t) (f,g) /\ open_in (subtopology euclidean s) u
+        ==> open_in (subtopology euclidean t) (IMAGE f u)`,
+  REWRITE_TAC[homeomorphism] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `IMAGE (f:real^M->real^N) u =
+                 {y | y IN t /\ g(y) IN u}`
+  SUBST1_TAC THENL
+   [FIRST_ASSUM(MP_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [open_in]) THEN
+    ASM SET_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ON_IMP_OPEN_IN THEN ASM_REWRITE_TAC[]]);;
+
+let HOMEOMORPHISM_IMP_CLOSED_MAP = prove
+ (`!f:real^M->real^N g s t u.
+        homeomorphism (s,t) (f,g) /\ closed_in (subtopology euclidean s) u
+        ==> closed_in (subtopology euclidean t) (IMAGE f u)`,
+  REWRITE_TAC[homeomorphism] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `IMAGE (f:real^M->real^N) u =
+                 {y | y IN t /\ g(y) IN u}`
+  SUBST1_TAC THENL
+   [FIRST_ASSUM(MP_TAC o CONJUNCT1 o GEN_REWRITE_RULE I [closed_in]) THEN
+    REWRITE_TAC[TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN ASM SET_TAC[];
+    MATCH_MP_TAC CONTINUOUS_ON_IMP_CLOSED_IN THEN ASM_REWRITE_TAC[]]);;
+
+let HOMEOMORPHISM_INJECTIVE_OPEN_MAP_EQ = prove
+ (`!f:real^M->real^N s t.
+        f continuous_on s /\ IMAGE f s = t /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> ((?g. homeomorphism (s,t) (f,g)) <=>
+             !u. open_in (subtopology euclidean s) u
+                 ==> open_in (subtopology euclidean t) (IMAGE f u))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC HOMEOMORPHISM_IMP_OPEN_MAP THEN ASM_MESON_TAC[];
+    MATCH_MP_TAC HOMEOMORPHISM_INJECTIVE_OPEN_MAP THEN
+    ASM_REWRITE_TAC[]]);;
+
+let HOMEOMORPHISM_INJECTIVE_CLOSED_MAP_EQ = prove
+ (`!f:real^M->real^N s t.
+        f continuous_on s /\ IMAGE f s = t /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> ((?g. homeomorphism (s,t) (f,g)) <=>
+             !u. closed_in (subtopology euclidean s) u
+                 ==> closed_in (subtopology euclidean t) (IMAGE f u))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC HOMEOMORPHISM_IMP_CLOSED_MAP THEN ASM_MESON_TAC[];
+    MATCH_MP_TAC HOMEOMORPHISM_INJECTIVE_CLOSED_MAP THEN
+    ASM_REWRITE_TAC[]]);;
+
+let INJECTIVE_MAP_OPEN_IFF_CLOSED = prove
+ (`!f:real^M->real^N s t.
+        f continuous_on s /\ IMAGE f s = t /\
+        (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
+        ==> ((!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) (IMAGE f u)))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `?g:real^N->real^M. homeomorphism (s,t) (f,g)` THEN
+  CONJ_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC HOMEOMORPHISM_INJECTIVE_OPEN_MAP_EQ;
+    MATCH_MP_TAC HOMEOMORPHISM_INJECTIVE_CLOSED_MAP_EQ] THEN
+  ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relatively weak hypotheses if the domain of the function is compact.      *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_IMP_CLOSED_MAP = prove
+ (`!f:real^M->real^N s t.
+        f continuous_on s /\ IMAGE f s = t /\ compact s
+        ==> !u. closed_in (subtopology euclidean s) u
+                ==> closed_in (subtopology euclidean t) (IMAGE f u)`,
+  SIMP_TAC[CLOSED_IN_CLOSED_EQ; COMPACT_IMP_CLOSED] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSED_CLOSED_IN_TRANS THEN
+  EXPAND_TAC "t" THEN REWRITE_TAC[CONJ_ASSOC] THEN
+  CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  CONJ_TAC THEN MATCH_MP_TAC COMPACT_IMP_CLOSED THEN
+  MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[COMPACT_EQ_BOUNDED_CLOSED; CLOSED_IN_CLOSED_TRANS;
+                BOUNDED_SUBSET; CONTINUOUS_ON_SUBSET]);;
+
+let CONTINUOUS_ON_INVERSE = prove
+ (`!f:real^M->real^N g s.
+        f continuous_on s /\ compact s /\ (!x. x IN s ==> (g(f(x)) = x))
+        ==> g continuous_on (IMAGE f s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CONTINUOUS_ON_CLOSED] THEN
+  SUBGOAL_THEN `IMAGE g (IMAGE (f:real^M->real^N) s) = s` SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_IMAGE] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+  X_GEN_TAC `t:real^M->bool` THEN DISCH_TAC THEN
+  REWRITE_TAC[CLOSED_IN_CLOSED] THEN
+  EXISTS_TAC `IMAGE (f:real^M->real^N) t` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC COMPACT_IMP_CLOSED THEN
+    MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+    FIRST_ASSUM(MP_TAC o MATCH_MP CLOSED_IN_SUBSET) THEN
+    REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN
+    ASM_MESON_TAC[COMPACT_EQ_BOUNDED_CLOSED; CLOSED_IN_CLOSED_TRANS;
+                  BOUNDED_SUBSET; CONTINUOUS_ON_SUBSET];
+    REWRITE_TAC[EXTENSION; IN_INTER; IN_ELIM_THM; IN_IMAGE] THEN
+    ASM_MESON_TAC[CLOSED_IN_SUBSET; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY; SUBSET]]);;
+
+let HOMEOMORPHISM_COMPACT = prove
+ (`!s f t. compact s /\ f continuous_on s /\ (IMAGE f s = t) /\
+           (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y))
+           ==> ?g. homeomorphism(s,t) (f,g)`,
+  REWRITE_TAC[INJECTIVE_ON_LEFT_INVERSE] THEN REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN ASM_SIMP_TAC[EXTENSION; homeomorphism] THEN
+  FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+  ASM_MESON_TAC[CONTINUOUS_ON_INVERSE; IN_IMAGE]);;
+
+let HOMEOMORPHIC_COMPACT = prove
+ (`!s f t. compact s /\ f continuous_on s /\ (IMAGE f s = t) /\
+           (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y))
+           ==> s homeomorphic t`,
+  REWRITE_TAC[homeomorphic] THEN MESON_TAC[HOMEOMORPHISM_COMPACT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Lemmas about composition of homeomorphisms.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMEOMORPHISM_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 /\
+        g continuous_on t /\ IMAGE g t SUBSET u /\
+        (?h. homeomorphism (s,u) (g o f,h))
+        ==> (?f'. homeomorphism (s,t) (f,f')) /\
+            (?g'. homeomorphism (t,u) (g,g'))`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[homeomorphism; o_THM]) THEN
+  MATCH_MP_TAC(TAUT `q /\ (q ==> p) ==> p /\ q`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HOMEOMORPHISM_INJECTIVE_OPEN_MAP THEN
+    REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+    MATCH_MP_TAC OPEN_MAP_FROM_COMPOSITION_SURJECTIVE THEN
+    MAP_EVERY EXISTS_TAC [`f:real^M->real^N`; `s:real^M->bool`] THEN
+    ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC HOMEOMORPHISM_IMP_OPEN_MAP THEN
+    MAP_EVERY EXISTS_TAC [`h:real^P->real^M`; `s:real^M->bool`] THEN
+    ASM_REWRITE_TAC[homeomorphism; o_THM];
+    REWRITE_TAC[homeomorphism; o_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g':real^P->real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(h:real^P->real^M) o (g:real^N->real^P)` THEN
+    ASM_SIMP_TAC[o_THM; IMAGE_o] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]]);;
+
+let HOMEOMORPHISM_FROM_COMPOSITION_INJECTIVE = 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 /\
+        (!x y. x IN t /\ y IN t /\ g x = g y ==> x = y) /\
+        (?h. homeomorphism (s,u) (g o f,h))
+        ==> (?f'. homeomorphism (s,t) (f,f')) /\
+            (?g'. homeomorphism (t,u) (g,g'))`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[homeomorphism; o_THM]) THEN
+  MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC HOMEOMORPHISM_INJECTIVE_OPEN_MAP THEN
+    REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+    MATCH_MP_TAC OPEN_MAP_FROM_COMPOSITION_INJECTIVE THEN
+    MAP_EVERY EXISTS_TAC [`g:real^N->real^P`; `u:real^P->bool`] THEN
+    ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC HOMEOMORPHISM_IMP_OPEN_MAP THEN
+    MAP_EVERY EXISTS_TAC [`h:real^P->real^M`; `s:real^M->bool`] THEN
+    ASM_REWRITE_TAC[homeomorphism; o_THM];
+    REWRITE_TAC[homeomorphism; o_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `f':real^N->real^M` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(f:real^M->real^N) o (h:real^P->real^M)` THEN
+    ASM_SIMP_TAC[o_THM; IMAGE_o] THEN
+    REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    ASM_MESON_TAC[CONTINUOUS_ON_SUBSET]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Preservation of topological properties.                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMEOMORPHIC_COMPACTNESS = prove
+ (`!s t. s homeomorphic t ==> (compact s <=> compact t)`,
+  REWRITE_TAC[homeomorphic; homeomorphism] THEN
+  MESON_TAC[COMPACT_CONTINUOUS_IMAGE]);;
+
+let HOMEOMORPHIC_CONNECTEDNESS = prove
+ (`!s t. s homeomorphic t ==> (connected s <=> connected t)`,
+  REWRITE_TAC[homeomorphic; homeomorphism] THEN
+  MESON_TAC[CONNECTED_CONTINUOUS_IMAGE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Results on translation, scaling etc.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMEOMORPHIC_SCALING = prove
+ (`!s:real^N->bool c. ~(c = &0) ==> s homeomorphic (IMAGE (\x. c % x) s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
+  MAP_EVERY EXISTS_TAC [`\x:real^N. c % x`; `\x:real^N. inv(c) % x`] THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_CMUL; CONTINUOUS_ON_ID; FORALL_IN_IMAGE] THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; REAL_MUL_RINV] THEN
+  SIMP_TAC[VECTOR_MUL_LID; IN_IMAGE; REAL_MUL_LID] THEN MESON_TAC[]);;
+
+let HOMEOMORPHIC_TRANSLATION = prove
+ (`!s a:real^N. s homeomorphic (IMAGE (\x. a + x) s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
+  MAP_EVERY EXISTS_TAC [`\x:real^N. a +  x`; `\x:real^N. --a + x`] THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID] THEN
+  SIMP_TAC[VECTOR_ADD_ASSOC; VECTOR_ADD_LINV; VECTOR_ADD_RINV;
+           FORALL_IN_IMAGE; VECTOR_ADD_LID] THEN
+  REWRITE_TAC[IN_IMAGE] THEN MESON_TAC[]);;
+
+let HOMEOMORPHIC_AFFINITY = prove
+ (`!s a:real^N c. ~(c = &0) ==> s homeomorphic (IMAGE (\x. a + c % x) s)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HOMEOMORPHIC_TRANS THEN
+  EXISTS_TAC `IMAGE (\x:real^N. c % x) s` THEN
+  ASM_SIMP_TAC[HOMEOMORPHIC_SCALING] 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
+  REWRITE_TAC[IMAGE_o; HOMEOMORPHIC_TRANSLATION]);;
+
+let [HOMEOMORPHIC_BALLS; HOMEOMORPHIC_CBALLS; HOMEOMORPHIC_SPHERES] =
+  (CONJUNCTS o prove)
+ (`(!a:real^N b:real^N d e.
+      &0 < d /\ &0 < e ==> ball(a,d) homeomorphic ball(b,e)) /\
+   (!a:real^N b:real^N d e.
+      &0 < d /\ &0 < e ==> cball(a,d) homeomorphic cball(b,e)) /\
+   (!a:real^N b:real^N d e.
+      &0 < d /\ &0 < e ==> sphere(a,d) homeomorphic sphere(b,e))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
+  EXISTS_TAC `\x:real^N. b + (e / d) % (x - a)` THEN
+  EXISTS_TAC `\x:real^N. a + (d / e) % (x - b)` THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_SUB; CONTINUOUS_ON_CMUL;
+    CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID; IN_BALL; IN_CBALL; IN_SPHERE] THEN
+  REWRITE_TAC[dist; VECTOR_ARITH `a - (a + b) = --b:real^N`; NORM_NEG] THEN
+  REWRITE_TAC[real_div; VECTOR_ARITH
+   `a + d % ((b + e % (x - a)) - b) = (&1 - d * e) % a + (d * e) % x`] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH
+    `(e * d') * (d * e') = (d * d') * (e * e')`] THEN
+  ASM_SIMP_TAC[REAL_MUL_RINV; REAL_LT_IMP_NZ; REAL_MUL_LID; REAL_SUB_REFL] THEN
+  REWRITE_TAC[NORM_MUL; VECTOR_MUL_LZERO; VECTOR_MUL_LID; VECTOR_ADD_LID] THEN
+  ASM_SIMP_TAC[REAL_ABS_MUL; REAL_ABS_INV; REAL_ARITH
+   `&0 < x ==> (abs x = x)`] THEN
+  GEN_REWRITE_TAC(BINOP_CONV o BINDER_CONV o funpow 2 RAND_CONV)
+        [GSYM REAL_MUL_RID] THEN
+  ONCE_REWRITE_TAC[AC REAL_MUL_AC `(a * b) * c = (a * c) * b`] THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL_EQ; GSYM real_div; REAL_LE_LDIV_EQ; REAL_MUL_LID;
+    GSYM REAL_MUL_ASSOC; REAL_LT_LMUL_EQ; REAL_LT_LDIV_EQ; NORM_SUB] THEN
+  ASM_SIMP_TAC[REAL_DIV_REFL; REAL_LT_IMP_NZ; REAL_MUL_RID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homeomorphism of one-point compactifications.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMEOMORPHIC_ONE_POINT_COMPACTIFICATIONS = prove
+ (`!s:real^M->bool t:real^N->bool a b.
+        compact s /\ compact t /\ a IN s /\ b IN t /\
+        (s DELETE a) homeomorphic (t DELETE b)
+        ==> s homeomorphic t`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC HOMEOMORPHIC_COMPACT THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [homeomorphic]) THEN
+  REWRITE_TAC[HOMEOMORPHISM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`f:real^M->real^N`; `g:real^N->real^M`] THEN
+  STRIP_TAC THEN
+  EXISTS_TAC `\x. if x = a then b else (f:real^M->real^N) x` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `x:real^M = a` THEN ASM_REWRITE_TAC[] THENL
+   [REWRITE_TAC[continuous_within] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`b:real^N`; `e:real`] CENTRE_IN_BALL) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+      `closed_in (subtopology euclidean s)
+                 { x | x IN (s DELETE a) /\
+                       (f:real^M->real^N)(x) IN t DIFF ball(b,e)}`
+    MP_TAC THENL
+     [MATCH_MP_TAC CLOSED_SUBSET THEN CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+      MATCH_MP_TAC COMPACT_IMP_CLOSED THEN SUBGOAL_THEN
+       `{x | x IN s DELETE a /\ f x IN t DIFF ball(b,e)} =
+        IMAGE (g:real^N->real^M) (t DIFF ball (b,e))`
+      SUBST1_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+      ASM_SIMP_TAC[COMPACT_DIFF; OPEN_BALL] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        CONTINUOUS_ON_SUBSET)) THEN ASM SET_TAC[];
+      REWRITE_TAC[closed_in; open_in; TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN
+      DISCH_THEN(MP_TAC o SPEC `a:real^M` o last o CONJUNCTS) THEN
+      ASM_REWRITE_TAC[IN_ELIM_THM; IN_DIFF; IN_DELETE] THEN
+      SIMP_TAC[IMP_CONJ; DE_MORGAN_THM] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN
+      ASM_REWRITE_TAC[] THEN COND_CASES_TAC THEN
+      ASM_REWRITE_TAC[DIST_REFL] THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_BALL]) THEN ASM SET_TAC[]];
+    UNDISCH_TAC `(f:real^M->real^N) continuous_on (s DELETE a)` THEN
+    REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+    DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[IN_DELETE] THEN
+    REWRITE_TAC[continuous_within] THEN
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN
+    ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[IN_DELETE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `min d (dist(a:real^M,x))` THEN
+    ASM_REWRITE_TAC[REAL_LT_MIN; GSYM DIST_NZ] THEN
+    ASM_MESON_TAC[REAL_LT_REFL]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homeomorphisms between open intervals in real^1 and then in real^N.       *)
+(* Could prove similar things for closed intervals, but they drop out of     *)
+(* later stuff in "convex.ml" even more easily.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMEOMORPHIC_OPEN_INTERVALS_1 = prove
+ (`!a b c d.
+        drop a < drop b /\ drop c < drop d
+        ==> interval(a,b) homeomorphic interval(c,d)`,
+  SUBGOAL_THEN
+   `!a b. drop a < drop b
+          ==> interval(vec 0:real^1,vec 1) homeomorphic interval(a,b)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
+    EXISTS_TAC `(\x. a + drop x % (b - a)):real^1->real^1` THEN
+    EXISTS_TAC `(\x. inv(drop b - drop a) % (x - a)):real^1->real^1` THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; GSYM DROP_EQ] THEN
+    REWRITE_TAC[DROP_ADD; DROP_CMUL; DROP_NEG; DROP_VEC; DROP_SUB] THEN
+    REWRITE_TAC[REAL_ARITH `inv b * a:real = a / b`] THEN
+    ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_LT_RDIV_EQ; REAL_SUB_LT;
+       REAL_LT_ADDR; REAL_EQ_LDIV_EQ; REAL_DIV_RMUL; REAL_LT_IMP_NZ;
+       REAL_LT_MUL; REAL_MUL_LZERO; REAL_ADD_SUB; REAL_LT_RMUL_EQ;
+       REAL_ARITH `a + x < b <=> x < &1 * (b - a)`] THEN
+    REPEAT CONJ_TAC THENL
+     [REAL_ARITH_TAC;
+      MATCH_MP_TAC CONTINUOUS_ON_ADD THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_VMUL THEN
+      REWRITE_TAC[o_DEF; LIFT_DROP; CONTINUOUS_ON_ID];
+      MATCH_MP_TAC CONTINUOUS_ON_CMUL THEN
+      ASM_SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID]];
+    REPEAT STRIP_TAC THEN
+    FIRST_ASSUM(MP_TAC o SPECL [`a:real^1`; `b:real^1`]) THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`c:real^1`; `d:real^1`]) THEN
+    ASM_REWRITE_TAC[GSYM IMP_CONJ_ALT] THEN
+    GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [HOMEOMORPHIC_SYM] THEN
+    REWRITE_TAC[HOMEOMORPHIC_TRANS]]);;
+
+let HOMEOMORPHIC_OPEN_INTERVAL_UNIV_1 = prove
+ (`!a b. drop a < drop b ==> interval(a,b) homeomorphic (:real^1)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`a:real^1`; `b:real^1`; `--vec 1:real^1`; `vec 1:real^1`]
+        HOMEOMORPHIC_OPEN_INTERVALS_1) THEN
+  ASM_REWRITE_TAC[DROP_VEC; DROP_NEG] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] HOMEOMORPHIC_TRANS) THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN
+  REWRITE_TAC[HOMEOMORPHIC_MINIMAL; IN_UNIV] THEN
+  EXISTS_TAC `\x:real^1. inv(&1 - norm x) % x` THEN
+  EXISTS_TAC `\y. if &0 <= drop y then inv(&1 + drop y) % y
+                  else inv(&1 - drop y) % y` THEN
+  REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [X_GEN_TAC `x:real^1` THEN REWRITE_TAC[IN_INTERVAL_1] THEN
+    REWRITE_TAC[DROP_NEG; DROP_VEC; DROP_CMUL; NORM_REAL; GSYM drop] THEN
+    SIMP_TAC[REAL_LE_MUL_EQ; REAL_LT_INV_EQ; REAL_LE_MUL_EQ; REAL_ARITH
+     `--a < x /\ x < a ==> &0 < a - abs x`] THEN
+    SIMP_TAC[real_abs; VECTOR_MUL_ASSOC] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+    GEN_REWRITE_TAC RAND_CONV [GSYM VECTOR_MUL_LID] THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD;
+    X_GEN_TAC `y:real^1` THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[IN_INTERVAL_1; DROP_NEG; DROP_VEC; REAL_BOUNDS_LT] THEN
+    REWRITE_TAC[DROP_CMUL; REAL_ABS_MUL; REAL_ABS_INV] THEN
+    REWRITE_TAC[GSYM(ONCE_REWRITE_RULE[REAL_MUL_SYM] real_div)] THEN
+    ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_ARITH `&0 <= x ==> &0 < abs(&1 + x)`;
+                 REAL_ARITH `~(&0 <= x) ==> &0 < abs(&1 - x)`] THEN
+    (CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+    REWRITE_TAC[NORM_REAL; VECTOR_MUL_ASSOC] THEN
+    REWRITE_TAC[GSYM drop; DROP_CMUL; REAL_ABS_MUL] THEN
+    ASM_REWRITE_TAC[real_abs; REAL_LE_INV_EQ] THEN
+    ASM_SIMP_TAC[REAL_ARITH `&0 <= x ==> &0 <= &1 + x`;
+                 REAL_ARITH `~(&0 <= x) ==> &0 <= &1 - x`] THEN
+    GEN_REWRITE_TAC RAND_CONV [GSYM VECTOR_MUL_LID] THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD;
+    MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN
+    X_GEN_TAC `x:real^1` THEN
+    REWRITE_TAC[IN_INTERVAL_1; DROP_NEG; DROP_VEC] THEN
+    DISCH_TAC THEN MATCH_MP_TAC CONTINUOUS_MUL THEN
+    REWRITE_TAC[CONTINUOUS_AT_ID] THEN
+    ONCE_REWRITE_TAC[GSYM o_DEF] THEN MATCH_MP_TAC CONTINUOUS_INV THEN
+    REWRITE_TAC[NETLIMIT_AT; o_DEF; LIFT_SUB; LIFT_DROP] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_SUB THEN
+      SIMP_TAC[CONTINUOUS_CONST; REWRITE_RULE[o_DEF] CONTINUOUS_AT_LIFT_NORM];
+      REWRITE_TAC[NORM_REAL; GSYM drop] THEN ASM_REAL_ARITH_TAC];
+    SUBGOAL_THEN `(:real^1) = {x | x$1 >= &0} UNION {x | x$1 <= &0}`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[EXTENSION; IN_UNION; IN_UNION; IN_ELIM_THM; IN_UNIV] THEN
+      REAL_ARITH_TAC;
+      MATCH_MP_TAC CONTINUOUS_ON_CASES THEN
+      REWRITE_TAC[CLOSED_HALFSPACE_COMPONENT_LE; CLOSED_HALFSPACE_COMPONENT_GE;
+                  IN_ELIM_THM] THEN
+      REWRITE_TAC[GSYM drop; REAL_NOT_LE; real_ge; REAL_LET_ANTISYM] THEN
+      SIMP_TAC[REAL_LE_ANTISYM; REAL_SUB_RZERO; REAL_ADD_RID] THEN
+      CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN
+      X_GEN_TAC `y:real^1` THEN REWRITE_TAC[IN_ELIM_THM; real_ge] THEN
+      DISCH_TAC THEN MATCH_MP_TAC CONTINUOUS_MUL THEN
+      REWRITE_TAC[CONTINUOUS_AT_ID] THEN
+      ONCE_REWRITE_TAC[GSYM o_DEF] THEN MATCH_MP_TAC CONTINUOUS_INV THEN
+      REWRITE_TAC[NETLIMIT_AT; o_DEF; LIFT_ADD; LIFT_SUB; LIFT_DROP] THEN
+      ASM_SIMP_TAC[CONTINUOUS_ADD; CONTINUOUS_AT_ID; CONTINUOUS_SUB;
+                   CONTINUOUS_CONST] THEN
+      ASM_REAL_ARITH_TAC]]);;
+
+let HOMEOMORPHIC_OPEN_INTERVALS = prove
+ (`!a b:real^N c d:real^N.
+        (interval(a,b) = {} <=> interval(c,d) = {})
+        ==> interval(a,b) homeomorphic interval(c,d)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `interval(c:real^N,d) = {}` THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN ASM_REWRITE_TAC[HOMEOMORPHIC_REFL] THEN
+  SUBGOAL_THEN
+   `!i. 1 <= i /\ i <= dimindex(:N)
+        ==> interval(lift((a:real^N)$i),lift((b:real^N)$i)) homeomorphic
+            interval(lift((c:real^N)$i),lift((d:real^N)$i))`
+  MP_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+    ASM_SIMP_TAC[HOMEOMORPHIC_OPEN_INTERVALS_1; LIFT_DROP];
+    ALL_TAC] THEN
+  REWRITE_TAC[HOMEOMORPHIC_MINIMAL; IN_INTERVAL_1; LIFT_DROP] THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`f:num->real^1->real^1`; `g:num->real^1->real^1`] THEN
+  DISCH_TAC THEN
+  EXISTS_TAC
+   `(\x. lambda i.
+       drop((f:num->real^1->real^1) i (lift(x$i)))):real^N->real^N` THEN
+  EXISTS_TAC
+   `(\x. lambda i.
+       drop((g:num->real^1->real^1) i (lift(x$i)))):real^N->real^N` THEN
+  ASM_SIMP_TAC[IN_INTERVAL; LAMBDA_BETA; CART_EQ; LIFT_DROP] THEN
+  ONCE_REWRITE_TAC[CONTINUOUS_ON_COMPONENTWISE_LIFT] THEN
+  SIMP_TAC[LAMBDA_BETA; LIFT_DROP] THEN CONJ_TAC THEN REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_SUBSET THENL
+   [EXISTS_TAC `interval(lift((a:real^N)$i),lift((b:real^N)$i))`;
+    EXISTS_TAC `interval(lift((c:real^N)$i),lift((d:real^N)$i))`] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1] THEN
+  ASM_SIMP_TAC[LIFT_DROP; IN_INTERVAL]);;
+
+let HOMEOMORPHIC_OPEN_INTERVAL_UNIV = prove
+ (`!a b:real^N.
+        ~(interval(a,b) = {})
+        ==> interval(a,b) homeomorphic (:real^N)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!i. 1 <= i /\ i <= dimindex(:N)
+        ==> interval(lift((a:real^N)$i),lift((b:real^N)$i)) homeomorphic
+            (:real^1)`
+  MP_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[INTERVAL_NE_EMPTY]) THEN
+    ASM_SIMP_TAC[HOMEOMORPHIC_OPEN_INTERVAL_UNIV_1; LIFT_DROP];
+    ALL_TAC] THEN
+  REWRITE_TAC[HOMEOMORPHIC_MINIMAL; IN_INTERVAL_1; LIFT_DROP] THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM; IN_UNIV] THEN
+  MAP_EVERY X_GEN_TAC [`f:num->real^1->real^1`; `g:num->real^1->real^1`] THEN
+  DISCH_TAC THEN
+  EXISTS_TAC
+   `(\x. lambda i.
+       drop((f:num->real^1->real^1) i (lift(x$i)))):real^N->real^N` THEN
+  EXISTS_TAC
+   `(\x. lambda i.
+       drop((g:num->real^1->real^1) i (lift(x$i)))):real^N->real^N` THEN
+  ASM_SIMP_TAC[IN_INTERVAL; LAMBDA_BETA; CART_EQ; LIFT_DROP; IN_UNIV] THEN
+  ONCE_REWRITE_TAC[CONTINUOUS_ON_COMPONENTWISE_LIFT] THEN
+  SIMP_TAC[LAMBDA_BETA; LIFT_DROP] THEN CONJ_TAC THEN REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_SUBSET THENL
+   [EXISTS_TAC `interval(lift((a:real^N)$i),lift((b:real^N)$i))`;
+    EXISTS_TAC `(:real^1)`] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTERVAL_1; IN_UNIV] THEN
+  ASM_SIMP_TAC[LIFT_DROP; IN_INTERVAL]);;
+
+let HOMEOMORPHIC_BALL_UNIV = prove
+ (`!a:real^N r. &0 < r ==> ball(a,r) homeomorphic (:real^N)`,
+  REPEAT GEN_TAC THEN GEOM_ORIGIN_TAC `a:real^N` THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?y:real^N. r = norm(y)` (CHOOSE_THEN SUBST_ALL_TAC) THENL
+   [ASM_MESON_TAC[VECTOR_CHOOSE_SIZE; REAL_LT_IMP_LE]; POP_ASSUM MP_TAC] THEN
+  REWRITE_TAC[NORM_POS_LT] THEN GEOM_NORMALIZE_TAC `y:real^N` THEN
+  SIMP_TAC[] THEN GEN_TAC THEN REPEAT(DISCH_THEN(K ALL_TAC)) THEN
+  REWRITE_TAC[HOMEOMORPHIC_MINIMAL] THEN
+  EXISTS_TAC `\z:real^N. inv(&1 - norm(z)) % z` THEN
+  EXISTS_TAC `\z:real^N. inv(&1 + norm(z)) % z` THEN
+  REWRITE_TAC[IN_BALL; IN_UNIV; DIST_0; VECTOR_MUL_ASSOC; VECTOR_MUL_EQ_0;
+              VECTOR_ARITH `a % x:real^N = x <=> (a - &1) % x = vec 0`] THEN
+  REPEAT CONJ_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN DISJ1_TAC THEN
+    REWRITE_TAC[GSYM REAL_INV_MUL; REAL_SUB_0; REAL_INV_EQ_1] THEN
+    REWRITE_TAC[NORM_MUL; REAL_ABS_INV] THEN
+    ASM_SIMP_TAC[REAL_ARITH `x < &1 ==> abs(&1 - x) = &1 - x`] THEN
+    POP_ASSUM MP_TAC THEN CONV_TAC REAL_FIELD;
+    X_GEN_TAC `y:real^N` THEN REWRITE_TAC[NORM_MUL; REAL_ABS_INV] THEN
+    ASM_SIMP_TAC[NORM_POS_LE; REAL_ARITH
+     `&0 <= y ==> inv(abs(&1 + y)) * z = z / (&1 + y)`] THEN
+    ASM_SIMP_TAC[NORM_POS_LE; REAL_LT_LDIV_EQ; REAL_ARITH
+      `&0 <= y ==> &0 < &1 + y`] THEN
+    CONJ_TAC THENL [REAL_ARITH_TAC; DISJ1_TAC] THEN
+    REWRITE_TAC[GSYM REAL_INV_MUL; REAL_SUB_0; REAL_INV_EQ_1] THEN
+    MP_TAC(ISPEC `y:real^N` NORM_POS_LE) THEN CONV_TAC REAL_FIELD;
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN REWRITE_TAC[CONTINUOUS_ON_ID] THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_INV THEN
+    SIMP_TAC[IN_BALL_0; REAL_SUB_0; REAL_ARITH `x < &1 ==> ~(&1 = x)`] THEN
+    REWRITE_TAC[o_DEF; LIFT_SUB] THEN MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_LIFT_NORM_COMPOSE THEN
+    REWRITE_TAC[CONTINUOUS_ON_ID];
+    MATCH_MP_TAC CONTINUOUS_ON_MUL THEN REWRITE_TAC[CONTINUOUS_ON_ID] THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM o_DEF] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_INV THEN
+    SIMP_TAC[NORM_POS_LE; REAL_ARITH `&0 <= x ==> ~(&1 + x = &0)`] THEN
+    REWRITE_TAC[o_DEF; LIFT_ADD] THEN MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
+    REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_LIFT_NORM_COMPOSE THEN
+    REWRITE_TAC[CONTINUOUS_ON_ID]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Cardinalities of various useful sets.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let CARD_EQ_EUCLIDEAN = prove
+ (`(:real^N) =_c (:real)`,
+  MATCH_MP_TAC CARD_EQ_CART THEN REWRITE_TAC[real_INFINITE]);;
+
+let UNCOUNTABLE_EUCLIDEAN = prove
+ (`~COUNTABLE(:real^N)`,
+  MATCH_MP_TAC CARD_EQ_REAL_IMP_UNCOUNTABLE THEN
+  REWRITE_TAC[CARD_EQ_EUCLIDEAN]);;
+
+let CARD_EQ_INTERVAL = prove
+ (`(!a b:real^N. ~(interval(a,b) = {}) ==> interval[a,b] =_c (:real)) /\
+   (!a b:real^N. ~(interval(a,b) = {}) ==> interval(a,b) =_c (:real))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `interval(a:real^N,b) = {}` THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THEN REWRITE_TAC[GSYM CARD_LE_ANTISYM] THEN CONJ_TAC THENL
+   [TRANS_TAC CARD_LE_TRANS `(:real^N)` THEN
+    REWRITE_TAC[CARD_LE_UNIV] THEN MATCH_MP_TAC CARD_EQ_IMP_LE THEN
+    REWRITE_TAC[CARD_EQ_EUCLIDEAN];
+    TRANS_TAC CARD_LE_TRANS `interval(a:real^N,b)` THEN
+    SIMP_TAC[CARD_LE_SUBSET; INTERVAL_OPEN_SUBSET_CLOSED];
+    TRANS_TAC CARD_LE_TRANS `(:real^N)` THEN
+    REWRITE_TAC[CARD_LE_UNIV] THEN MATCH_MP_TAC CARD_EQ_IMP_LE THEN
+    REWRITE_TAC[CARD_EQ_EUCLIDEAN];
+    ALL_TAC] THEN
+  TRANS_TAC CARD_LE_TRANS `(:real^N)` THEN
+  SIMP_TAC[ONCE_REWRITE_RULE[CARD_EQ_SYM] CARD_EQ_IMP_LE;
+           CARD_EQ_EUCLIDEAN] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP HOMEOMORPHIC_OPEN_INTERVAL_UNIV) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP HOMEOMORPHIC_IMP_CARD_EQ) THEN
+  MESON_TAC[CARD_EQ_IMP_LE; CARD_EQ_SYM]);;
+
+let UNCOUNTABLE_INTERVAL = prove
+ (`(!a b. ~(interval(a,b) = {}) ==> ~COUNTABLE(interval[a,b])) /\
+   (!a b. ~(interval(a,b) = {}) ==> ~COUNTABLE(interval(a,b)))`,
+  SIMP_TAC[CARD_EQ_REAL_IMP_UNCOUNTABLE; CARD_EQ_INTERVAL]);;
+
+let COUNTABLE_OPEN_INTERVAL = prove
+ (`!a b. COUNTABLE(interval(a,b)) <=> interval(a,b) = {}`,
+  MESON_TAC[COUNTABLE_EMPTY; UNCOUNTABLE_INTERVAL]);;
+
+let CARD_EQ_OPEN = prove
+ (`!s:real^N->bool. open s /\ ~(s = {}) ==> s =_c (:real)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM CARD_LE_ANTISYM] THEN CONJ_TAC THENL
+   [TRANS_TAC CARD_LE_TRANS `(:real^N)` THEN
+    REWRITE_TAC[CARD_LE_UNIV] THEN MATCH_MP_TAC CARD_EQ_IMP_LE THEN
+    REWRITE_TAC[CARD_EQ_EUCLIDEAN];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_INTERVAL]) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `c:real^N`) THEN
+    DISCH_THEN(MP_TAC o SPEC `c:real^N`) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+    ASM_CASES_TAC `interval(a:real^N,b) = {}` THEN
+    ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN STRIP_TAC THEN
+    TRANS_TAC CARD_LE_TRANS `interval[a:real^N,b]` THEN
+    ASM_SIMP_TAC[CARD_LE_SUBSET] THEN MATCH_MP_TAC CARD_EQ_IMP_LE THEN
+    ONCE_REWRITE_TAC[CARD_EQ_SYM] THEN ASM_SIMP_TAC[CARD_EQ_INTERVAL]]);;
+
+let UNCOUNTABLE_OPEN = prove
+ (`!s:real^N->bool. open s /\ ~(s = {}) ==> ~(COUNTABLE s)`,
+  SIMP_TAC[CARD_EQ_OPEN; CARD_EQ_REAL_IMP_UNCOUNTABLE]);;
+
+let CARD_EQ_BALL = prove
+ (`!a:real^N r. &0 < r ==> ball(a,r) =_c (:real)`,
+  SIMP_TAC[CARD_EQ_OPEN; OPEN_BALL; BALL_EQ_EMPTY; GSYM REAL_NOT_LT]);;
+
+let CARD_EQ_CBALL = prove
+ (`!a:real^N r. &0 < r ==> cball(a,r) =_c (:real)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM CARD_LE_ANTISYM] THEN CONJ_TAC THENL
+   [TRANS_TAC CARD_LE_TRANS `(:real^N)` THEN
+    REWRITE_TAC[CARD_LE_UNIV] THEN MATCH_MP_TAC CARD_EQ_IMP_LE THEN
+    REWRITE_TAC[CARD_EQ_EUCLIDEAN];
+    TRANS_TAC CARD_LE_TRANS `ball(a:real^N,r)` THEN
+    SIMP_TAC[CARD_LE_SUBSET; BALL_SUBSET_CBALL] THEN
+    MATCH_MP_TAC CARD_EQ_IMP_LE THEN
+    ONCE_REWRITE_TAC[CARD_EQ_SYM] THEN ASM_SIMP_TAC[CARD_EQ_BALL]]);;
+
+let FINITE_IMP_NOT_OPEN = prove
+ (`!s:real^N->bool. FINITE s /\ ~(s = {}) ==> ~(open s)`,
+  MESON_TAC[UNCOUNTABLE_OPEN; FINITE_IMP_COUNTABLE]);;
+
+let OPEN_IMP_INFINITE = prove
+ (`!s. open s ==> s = {} \/ INFINITE s`,
+  MESON_TAC[FINITE_IMP_NOT_OPEN; INFINITE]);;
+
+let EMPTY_INTERIOR_FINITE = prove
+ (`!s:real^N->bool. FINITE s ==> interior s = {}`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPEC `s:real^N->bool` OPEN_INTERIOR) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] FINITE_IMP_NOT_OPEN) THEN
+  MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `s:real^N->bool` THEN
+  ASM_REWRITE_TAC[INTERIOR_SUBSET]);;
+
+let CARD_EQ_CONNECTED = prove
+ (`!s a b:real^N.
+        connected s /\ a IN s /\ b IN s /\ ~(a = b) ==> s =_c (:real)`,
+  GEOM_ORIGIN_TAC `b:real^N` THEN GEOM_NORMALIZE_TAC `a:real^N` THEN
+  REWRITE_TAC[NORM_EQ_SQUARE; REAL_POS; REAL_POW_ONE] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM CARD_LE_ANTISYM] THEN CONJ_TAC THENL
+   [TRANS_TAC CARD_LE_TRANS `(:real^N)` THEN
+    SIMP_TAC[CARD_LE_UNIV; CARD_EQ_EUCLIDEAN; CARD_EQ_IMP_LE];
+    TRANS_TAC CARD_LE_TRANS `interval[vec 0:real^1,vec 1]` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC(ONCE_REWRITE_RULE[CARD_EQ_SYM] CARD_EQ_IMP_LE) THEN
+      SIMP_TAC[UNIT_INTERVAL_NONEMPTY; CARD_EQ_INTERVAL];
+      REWRITE_TAC[LE_C] THEN EXISTS_TAC `\x:real^N. lift(a dot x)` THEN
+      SIMP_TAC[FORALL_LIFT; LIFT_EQ; IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+      X_GEN_TAC `t:real` THEN STRIP_TAC THEN
+      MATCH_MP_TAC CONNECTED_IVT_HYPERPLANE THEN
+      MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `a:real^N`] THEN
+      ASM_REWRITE_TAC[DOT_RZERO]]]);;
+
+let UNCOUNTABLE_CONNECTED = prove
+ (`!s a b:real^N.
+        connected s /\ a IN s /\ b IN s /\ ~(a = b) ==> ~COUNTABLE s`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC CARD_EQ_REAL_IMP_UNCOUNTABLE THEN
+  MATCH_MP_TAC CARD_EQ_CONNECTED THEN
+  ASM_MESON_TAC[]);;
+
+let CARD_LT_IMP_DISCONNECTED = prove
+ (`!s x:real^N. s <_c (:real) /\ x IN s ==> connected_component s x = {x}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[SET_RULE
+   `s = {a} <=> a IN s /\ !a b. a IN s /\ b IN s /\ ~(a = b) ==> F`] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[IN] THEN
+  ASM_REWRITE_TAC[CONNECTED_COMPONENT_REFL_EQ] THEN
+  MP_TAC(ISPECL [`connected_component s (x:real^N)`; `a:real^N`; `b:real^N`]
+        CARD_EQ_CONNECTED) THEN
+  ASM_REWRITE_TAC[CONNECTED_CONNECTED_COMPONENT] THEN
+  DISCH_TAC THEN UNDISCH_TAC `(s:real^N->bool) <_c (:real)` THEN
+  REWRITE_TAC[CARD_NOT_LT] THEN
+  TRANS_TAC CARD_LE_TRANS `connected_component s (x:real^N)` THEN
+  ASM_SIMP_TAC[ONCE_REWRITE_RULE[CARD_EQ_SYM] CARD_EQ_IMP_LE] THEN
+  MATCH_MP_TAC CARD_LE_SUBSET THEN REWRITE_TAC[CONNECTED_COMPONENT_SUBSET]);;
+
+let COUNTABLE_IMP_DISCONNECTED = prove
+ (`!s x:real^N. COUNTABLE s /\ x IN s ==> connected_component s x = {x}`,
+  SIMP_TAC[CARD_LT_IMP_DISCONNECTED; COUNTABLE_IMP_CARD_LT_REAL]);;
+
+let CONNECTED_CARD_EQ_IFF_NONTRIVIAL = prove
+ (`!s:real^N->bool.
+        connected s ==> (s =_c (:real) <=> ~(?a. s SUBSET {a}))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [ALL_TAC; MATCH_MP_TAC CARD_EQ_CONNECTED THEN ASM SET_TAC[]] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP(REWRITE_RULE[IMP_CONJ_ALT] FINITE_SUBSET)) THEN
+  REWRITE_TAC[FINITE_SING] THEN
+  ASM_MESON_TAC[CARD_EQ_REAL_IMP_UNCOUNTABLE; FINITE_IMP_COUNTABLE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* "Iff" forms of constancy of function from connected set into a set that   *)
+(* is smaller than R, or countable, or finite, or disconnected, or discrete. *)
+(* ------------------------------------------------------------------------- *)
+
+let [CONTINUOUS_DISCONNECTED_RANGE_CONSTANT_EQ;
+     CONTINUOUS_DISCRETE_RANGE_CONSTANT_EQ;
+     CONTINUOUS_FINITE_RANGE_CONSTANT_EQ] = (CONJUNCTS o prove)
+  (`(!s. connected s <=>
+         !f:real^M->real^N t.
+            f continuous_on s /\ IMAGE f s SUBSET t /\
+            (!y. y IN t ==> connected_component t y = {y})
+            ==> ?a. !x. x IN s ==> f x = a) /\
+    (!s. connected s <=>
+         !f:real^M->real^N.
+            f continuous_on s /\
+            (!x. x IN s
+                 ==> ?e. &0 < e /\
+                         !y. y IN s /\ ~(f y = f x) ==> e <= norm(f y - f x))
+            ==> ?a. !x. x IN s ==> f x = a) /\
+    (!s. connected s <=>
+         !f:real^M->real^N.
+            f continuous_on s /\ FINITE(IMAGE f s)
+            ==> ?a. !x. x IN s ==> f x = a)`,
+  REWRITE_TAC[AND_FORALL_THM] THEN X_GEN_TAC `s:real^M->bool` THEN
+  MATCH_MP_TAC(TAUT
+   `(s ==> t) /\ (t ==> u) /\ (u ==> v) /\ (v ==> s)
+    ==> (s <=> t) /\ (s <=> u) /\ (s <=> v)`) THEN
+  REPEAT CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^M->bool = {}` THEN
+    ASM_REWRITE_TAC[NOT_IN_EMPTY] THEN
+    FIRST_X_ASSUM(X_CHOOSE_TAC `x:real^M` o
+        GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN
+    EXISTS_TAC `(f:real^M->real^N) x` THEN
+    MATCH_MP_TAC(SET_RULE
+     `IMAGE f s SUBSET {a} ==> !y. y IN s ==> f y = a`) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(f:real^M->real^N) x`) THEN
+    ANTS_TAC THENL [ASM SET_TAC[]; DISCH_THEN(SUBST1_TAC o SYM)] THEN
+    MATCH_MP_TAC CONNECTED_COMPONENT_MAXIMAL THEN
+    ASM_SIMP_TAC[CONNECTED_CONTINUOUS_IMAGE] THEN ASM SET_TAC[];
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    EXISTS_TAC `IMAGE (f:real^M->real^N) s` THEN
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE; SUBSET_REFL] THEN
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^M`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    MATCH_MP_TAC(SET_RULE
+     `(!y. y IN s /\ f y IN connected_component (IMAGE f s) a ==> f y = a) /\
+      connected_component (IMAGE f s) a SUBSET (IMAGE f s) /\
+      connected_component (IMAGE f s) a a
+      ==> connected_component (IMAGE f s) a = {a}`) THEN
+    REWRITE_TAC[CONNECTED_COMPONENT_SUBSET; CONNECTED_COMPONENT_REFL_EQ] THEN
+    ASM_SIMP_TAC[FUN_IN_IMAGE] THEN X_GEN_TAC `y:real^M` THEN STRIP_TAC THEN
+    MP_TAC(ISPEC `connected_component (IMAGE (f:real^M->real^N) s) (f x)`
+        CONNECTED_CLOSED) THEN
+    REWRITE_TAC[CONNECTED_CONNECTED_COMPONENT] THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN
+    ASM_REWRITE_TAC[] THEN MAP_EVERY EXISTS_TAC
+     [`cball((f:real^M->real^N) x,e / &2)`;
+      `(:real^N) DIFF ball((f:real^M->real^N) x,e)`] THEN
+    REWRITE_TAC[GSYM OPEN_CLOSED; OPEN_BALL; CLOSED_CBALL] THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET; IN_CBALL; IN_UNION; IN_DIFF; IN_BALL; IN_UNIV] THEN
+      MATCH_MP_TAC(MESON[SUBSET; CONNECTED_COMPONENT_SUBSET]
+       `(!x. x IN s ==> P x)
+        ==> (!x. x IN connected_component s y ==> P x)`) THEN
+      REWRITE_TAC[FORALL_IN_IMAGE] THEN X_GEN_TAC `z:real^M` THEN
+      DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `z:real^M`) THEN
+      ASM_REWRITE_TAC[] THEN CONV_TAC NORM_ARITH;
+      MATCH_MP_TAC(SET_RULE
+       `(!x. x IN s /\ x IN t ==> F) ==> s INTER t INTER u = {}`) THEN
+      REWRITE_TAC[IN_BALL; IN_CBALL; IN_DIFF; IN_UNIV] THEN
+      UNDISCH_TAC `&0 < e` THEN CONV_TAC NORM_ARITH;
+      EXISTS_TAC `(f:real^M->real^N) x` THEN
+      ASM_SIMP_TAC[CENTRE_IN_CBALL; REAL_HALF; REAL_LT_IMP_LE; IN_INTER] THEN
+      REWRITE_TAC[IN] THEN
+      ASM_SIMP_TAC[CONNECTED_COMPONENT_REFL_EQ; FUN_IN_IMAGE];
+      EXISTS_TAC `(f:real^M->real^N) y` THEN
+      ASM_REWRITE_TAC[IN_INTER; IN_DIFF; IN_UNIV; IN_BALL; REAL_NOT_LT] THEN
+      ASM_SIMP_TAC[ONCE_REWRITE_RULE[DIST_SYM] dist]];
+    MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `f:real^M->real^N` THEN
+    DISCH_THEN(fun th -> STRIP_TAC THEN MATCH_MP_TAC th) THEN
+    ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `IMAGE (f:real^M->real^N) s DELETE (f x) = {}` THENL
+     [EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    EXISTS_TAC
+     `inf{norm(z - f x) |z| z IN IMAGE (f:real^M->real^N) s DELETE (f x)}` THEN
+    REWRITE_TAC[SIMPLE_IMAGE] THEN
+    ASM_SIMP_TAC[REAL_LT_INF_FINITE; REAL_INF_LE_FINITE; FINITE_DELETE;
+                 FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; EXISTS_IN_IMAGE] THEN
+    REWRITE_TAC[IN_DELETE; NORM_POS_LT; VECTOR_SUB_EQ; IN_IMAGE] THEN
+    MESON_TAC[REAL_LE_REFL];
+    REWRITE_TAC[CONNECTED_CLOSED_IN_EQ] THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`t:real^M->bool`; `u:real^M->bool`] THEN
+    STRIP_TAC THEN DISCH_THEN(MP_TAC o SPEC
+     `(\x. if x IN t then vec 0 else basis 1):real^M->real^N`) THEN
+    REWRITE_TAC[NOT_IMP] THEN REPEAT CONJ_TAC THENL
+     [EXPAND_TAC "s" THEN MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN
+      ASM_REWRITE_TAC[CONTINUOUS_ON_CONST] THEN ASM SET_TAC[];
+      MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `{vec 0:real^N,basis 1}` THEN
+      REWRITE_TAC[FINITE_INSERT; FINITE_EMPTY] THEN SET_TAC[];
+      SUBGOAL_THEN `?a b:real^M. a IN s /\ a IN t /\ b IN s /\ ~(b IN t)`
+      STRIP_ASSUME_TAC THENL
+       [ASM SET_TAC[]; DISCH_THEN(CHOOSE_THEN MP_TAC)] THEN
+      DISCH_THEN(fun th -> MP_TAC(SPEC `a:real^M` th) THEN
+                           MP_TAC(SPEC `b:real^M` th)) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+      CONV_TAC(RAND_CONV SYM_CONV) THEN
+      SIMP_TAC[BASIS_NONZERO; LE_REFL; DIMINDEX_GE_1; REAL_LE_REFL]]]);;
+
+let CONTINUOUS_DISCONNECTED_RANGE_CONSTANT = prove
+ (`!f:real^M->real^N s.
+        connected s /\
+        f continuous_on s /\ IMAGE f s SUBSET t /\
+        (!y. y IN t ==> connected_component t y = {y})
+        ==> ?a. !x. x IN s ==> f x = a`,
+  MESON_TAC[CONTINUOUS_DISCONNECTED_RANGE_CONSTANT_EQ]);;
+
+let CONTINUOUS_DISCRETE_RANGE_CONSTANT = prove
+ (`!f:real^M->real^N s.
+        connected s /\
+        f continuous_on s /\
+        (!x. x IN s
+             ==> ?e. &0 < e /\
+                     !y. y IN s /\ ~(f y = f x) ==> e <= norm(f y - f x))
+        ==> ?a. !x. x IN s ==> f x = a`,
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONTINUOUS_DISCRETE_RANGE_CONSTANT_EQ]);;
+
+let CONTINUOUS_FINITE_RANGE_CONSTANT = prove
+ (`!f:real^M->real^N s.
+        connected s /\
+        f continuous_on s /\
+        FINITE(IMAGE f s)
+        ==> ?a. !x. x IN s ==> f x = a`,
+  MESON_TAC[CONTINUOUS_FINITE_RANGE_CONSTANT_EQ]);;
+
+let CONTINUOUS_COUNTABLE_RANGE_CONSTANT_EQ = prove
+ (`!s. connected s <=>
+         !f:real^M->real^N.
+            f continuous_on s /\ COUNTABLE(IMAGE f s)
+            ==> ?a. !x. x IN s ==> f x = a`,
+  GEN_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[CONTINUOUS_DISCONNECTED_RANGE_CONSTANT_EQ];
+    REWRITE_TAC[CONTINUOUS_FINITE_RANGE_CONSTANT_EQ]] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[FINITE_IMP_COUNTABLE] THEN
+  EXISTS_TAC `IMAGE (f:real^M->real^N) s` THEN
+  ASM_SIMP_TAC[COUNTABLE_IMP_DISCONNECTED; SUBSET_REFL]);;
+
+let CONTINUOUS_CARD_LT_RANGE_CONSTANT_EQ = prove
+ (`!s. connected s <=>
+         !f:real^M->real^N.
+            f continuous_on s /\ (IMAGE f s) <_c (:real)
+            ==> ?a. !x. x IN s ==> f x = a`,
+  GEN_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[CONTINUOUS_DISCONNECTED_RANGE_CONSTANT_EQ];
+    REWRITE_TAC[CONTINUOUS_COUNTABLE_RANGE_CONSTANT_EQ]] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_SIMP_TAC[COUNTABLE_IMP_CARD_LT_REAL] THEN
+  EXISTS_TAC `IMAGE (f:real^M->real^N) s` THEN
+  ASM_SIMP_TAC[CARD_LT_IMP_DISCONNECTED; SUBSET_REFL]);;
+
+let CONTINUOUS_COUNTABLE_RANGE_CONSTANT = prove
+ (`!f:real^M->real^N s.
+        connected s /\ f continuous_on s /\ COUNTABLE(IMAGE f s)
+        ==> ?a. !x. x IN s ==> f x = a`,
+  MESON_TAC[CONTINUOUS_COUNTABLE_RANGE_CONSTANT_EQ]);;
+
+let CONTINUOUS_CARD_LT_RANGE_CONSTANT = prove
+ (`!f:real^M->real^N s.
+        connected s /\ f continuous_on s /\ (IMAGE f s) <_c (:real)
+        ==> ?a. !x. x IN s ==> f x = a`,
+  MESON_TAC[CONTINUOUS_CARD_LT_RANGE_CONSTANT_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homeomorphism of hyperplanes.                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMEOMORPHIC_HYPERPLANES = prove
+ (`!a:real^N b c:real^N d.
+        ~(a = vec 0) /\ ~(c = vec 0)
+        ==> {x | a dot x = b} homeomorphic {x | c dot x = d}`,
+  let lemma = prove
+   (`~(a = vec 0)
+     ==> {x:real^N | a dot x = b} homeomorphic {x:real^N | x$1 = &0}`,
+    REPEAT STRIP_TAC THEN SUBGOAL_THEN `?c:real^N. a dot c = b`
+    STRIP_ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [CART_EQ]) THEN
+      REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; VEC_COMPONENT] THEN
+      DISCH_THEN(X_CHOOSE_THEN `k:num` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `b / (a:real^N)$k % basis k:real^N` THEN
+      ASM_SIMP_TAC[DOT_RMUL; DOT_BASIS; REAL_DIV_RMUL];
+      FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+      ABBREV_TAC `p = {x:real^N | x$1 = &0}` THEN
+      GEOM_ORIGIN_TAC `c:real^N` THEN
+      REWRITE_TAC[VECTOR_ADD_RID; DOT_RADD; DOT_RZERO; REAL_EQ_ADD_LCANCEL_0;
+                  REAL_ADD_RID] THEN
+      REPEAT STRIP_TAC THEN UNDISCH_TAC `~(a:real^N = vec 0)` THEN
+      GEOM_BASIS_MULTIPLE_TAC 1 `a:real^N` THEN
+      SIMP_TAC[VECTOR_MUL_EQ_0; DE_MORGAN_THM; DOT_LMUL; REAL_ENTIRE] THEN
+      SIMP_TAC[DOT_BASIS; LE_REFL; DIMINDEX_GE_1] THEN
+      EXPAND_TAC "p" THEN REWRITE_TAC[HOMEOMORPHIC_REFL]]) in
+  REPEAT STRIP_TAC THEN
+  TRANS_TAC HOMEOMORPHIC_TRANS `{x:real^N | x$1 = &0}` THEN
+  ASM_SIMP_TAC[lemma] THEN ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+  ASM_SIMP_TAC[lemma]);;
+
+let HOMEOMORPHIC_HYPERPLANE_STANDARD_HYPERPLANE = prove
+ (`!a:real^N b k c.
+        ~(a = vec 0) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> {x | a dot x = b} homeomorphic {x:real^N | x$k = c}`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `{x:real^N | x$k = c} = {x | basis k dot x = c}` SUBST1_TAC
+  THENL [ASM_SIMP_TAC[DOT_BASIS]; MATCH_MP_TAC HOMEOMORPHIC_HYPERPLANES] THEN
+  ASM_SIMP_TAC[BASIS_NONZERO]);;
+
+let HOMEOMORPHIC_STANDARD_HYPERPLANE_HYPERPLANE = prove
+ (`!a:real^N b k c.
+        ~(a = vec 0) /\ 1 <= k /\ k <= dimindex(:N)
+        ==> {x:real^N | x$k = c} homeomorphic {x | a dot x = b}`,
+  ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN
+  REWRITE_TAC[HOMEOMORPHIC_HYPERPLANE_STANDARD_HYPERPLANE]);;
+
+let HOMEOMORPHIC_HYPERPLANE_UNIV = prove
+ (`!a b. ~(a = vec 0) /\ dimindex(:N) = dimindex(:M) + 1
+         ==> {x:real^N | a dot x = b} homeomorphic (:real^M)`,
+  REPEAT STRIP_TAC THEN TRANS_TAC HOMEOMORPHIC_TRANS
+   `{x:real^N | basis(dimindex(:N)) dot x = &0}` THEN
+  ASM_SIMP_TAC[HOMEOMORPHIC_HYPERPLANES; BASIS_NONZERO;
+               LE_REFL; DIMINDEX_GE_1] THEN
+  REWRITE_TAC[homeomorphic; HOMEOMORPHISM] THEN
+  EXISTS_TAC `(\x. lambda i. x$i):real^N->real^M` THEN
+  EXISTS_TAC `(\x. lambda i. if i <= dimindex(:M) then x$i else &0)
+              :real^M->real^N` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN
+    SIMP_TAC[linear; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT;
+             VECTOR_MUL_COMPONENT];
+    REWRITE_TAC[SUBSET_UNIV];
+    MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN
+    SIMP_TAC[linear; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT;
+             VECTOR_MUL_COMPONENT] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+    REAL_ARITH_TAC;
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM; IN_UNIV] THEN
+    ASM_SIMP_TAC[DOT_BASIS; LAMBDA_BETA; LE_REFL; ARITH_RULE `1 <= n + 1`;
+                 ARITH_RULE `~(m + 1 <= m)`];
+    ASM_SIMP_TAC[IN_ELIM_THM; LAMBDA_BETA; DOT_BASIS; LE_REFL; CART_EQ;
+                 ARITH_RULE `1 <= n + 1`] THEN
+    GEN_TAC THEN DISCH_TAC THEN X_GEN_TAC `i:num` THEN
+    ASM_CASES_TAC `i = dimindex(:M) + 1` THEN ASM_REWRITE_TAC[COND_ID] THEN
+    COND_CASES_TAC THEN REWRITE_TAC[] THEN ASM_ARITH_TAC;
+    ASM_SIMP_TAC[LAMBDA_BETA; CART_EQ; IN_UNIV; LE_REFL;
+                 ARITH_RULE `i <= n ==> i <= n + 1`]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* "Isometry" (up to constant bounds) of injective linear map etc.           *)
+(* ------------------------------------------------------------------------- *)
+
+let CAUCHY_ISOMETRIC = prove
+ (`!f s e x.
+        &0 < e /\ subspace s /\
+        linear f /\ (!x. x IN s ==> norm(f x) >= e * norm(x)) /\
+        (!n. x(n) IN s) /\ cauchy(f o x)
+        ==> cauchy x`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[real_ge] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[CAUCHY; dist; o_THM] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP LINEAR_SUB th)]) THEN
+  DISCH_THEN(fun th -> X_GEN_TAC `d:real` THEN DISCH_TAC THEN MP_TAC th) THEN
+  DISCH_THEN(MP_TAC o SPEC `d * e`) THEN ASM_SIMP_TAC[REAL_LT_MUL] THEN
+  ASM_MESON_TAC[REAL_LE_RDIV_EQ; REAL_MUL_SYM; REAL_LET_TRANS; SUBSPACE_SUB;
+                REAL_LT_LDIV_EQ]);;
+
+let COMPLETE_ISOMETRIC_IMAGE = prove
+ (`!f:real^M->real^N s e.
+        &0 < e /\ subspace s /\
+        linear f /\ (!x. x IN s ==> norm(f x) >= e * norm(x)) /\
+        complete s
+        ==> complete(IMAGE f s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[complete; EXISTS_IN_IMAGE] THEN
+  STRIP_TAC THEN X_GEN_TAC `g:num->real^N` THEN
+  REWRITE_TAC[IN_IMAGE; SKOLEM_THM; FORALL_AND_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `x:num->real^M` MP_TAC) THEN
+  GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM FUN_EQ_THM] THEN
+  REWRITE_TAC[GSYM o_DEF] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `x:num->real^M`) THEN
+  ASM_MESON_TAC[CAUCHY_ISOMETRIC; LINEAR_CONTINUOUS_AT;
+                CONTINUOUS_AT_SEQUENTIALLY]);;
+
+let INJECTIVE_IMP_ISOMETRIC = prove
+ (`!f:real^M->real^N s.
+        closed s /\ subspace s /\
+        linear f /\ (!x. x IN s /\ (f x = vec 0) ==> (x = vec 0))
+        ==> ?e. &0 < e /\ !x. x IN s ==> norm(f x) >= e * norm(x)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s SUBSET {vec 0 :real^M}` THENL
+   [EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01; REAL_MUL_LID; real_ge] THEN
+    ASM_MESON_TAC[SUBSET; IN_SING; NORM_0; LINEAR_0; REAL_LE_REFL];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [SUBSET]) THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; IN_SING] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^M` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL
+   [`{(f:real^M->real^N) x | x IN s /\ norm(x) = norm(a:real^M)}`;
+    `vec 0:real^N`] DISTANCE_ATTAINS_INF) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+    CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+    MATCH_MP_TAC COMPACT_IMP_CLOSED THEN
+    SUBST1_TAC(SET_RULE
+     `{f x | x IN s /\ norm(x) = norm(a:real^M)} =
+      IMAGE (f:real^M->real^N) (s INTER {x | norm x = norm a})`) THEN
+    MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+    ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON] THEN
+    MATCH_MP_TAC CLOSED_INTER_COMPACT THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN
+     `{x:real^M | norm x = norm(a:real^M)} = frontier(cball(vec 0,norm a))`
+    SUBST1_TAC THENL
+     [ASM_SIMP_TAC[FRONTIER_CBALL; NORM_POS_LT; dist; VECTOR_SUB_LZERO;
+                   NORM_NEG; sphere];
+      ASM_SIMP_TAC[COMPACT_FRONTIER; COMPACT_CBALL]];
+    ALL_TAC] THEN
+  ONCE_REWRITE_TAC[SET_RULE `{f x | P x} = IMAGE f {x | P x}`] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; EXISTS_IN_IMAGE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^M` MP_TAC) THEN
+  REWRITE_TAC[IN_ELIM_THM; dist; VECTOR_SUB_LZERO; NORM_NEG] THEN
+  STRIP_TAC THEN REWRITE_TAC[CLOSED_LIMPT; LIMPT_APPROACHABLE] THEN
+  EXISTS_TAC `norm((f:real^M->real^N) b) / norm(b)` THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[REAL_LT_DIV; NORM_POS_LT; NORM_EQ_0]; ALL_TAC] THEN
+  X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `x:real^M = vec 0` THENL
+   [FIRST_ASSUM(fun th -> ASM_REWRITE_TAC[MATCH_MP LINEAR_0 th]) THEN
+    REWRITE_TAC[NORM_0; REAL_MUL_RZERO; real_ge; REAL_LE_REFL];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(norm(a:real^M) / norm(x)) % x:real^M`) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM] THEN
+    ASM_SIMP_TAC[REAL_DIV_RMUL; NORM_EQ_0] THEN ASM_MESON_TAC[subspace];
+    ALL_TAC] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP LINEAR_CMUL th]) THEN
+  ASM_REWRITE_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM; real_ge] THEN
+  ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; NORM_POS_LT] THEN
+  REWRITE_TAC[real_div; REAL_MUL_AC]);;
+
+let CLOSED_INJECTIVE_IMAGE_SUBSPACE = prove
+ (`!f s. subspace s /\
+         linear f /\
+         (!x. x IN s /\ f(x) = vec 0 ==> x = vec 0) /\
+         closed s
+         ==> closed(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM COMPLETE_EQ_CLOSED] THEN
+  MATCH_MP_TAC COMPLETE_ISOMETRIC_IMAGE THEN
+  ASM_REWRITE_TAC[COMPLETE_EQ_CLOSED] THEN
+  MATCH_MP_TAC INJECTIVE_IMP_ISOMETRIC THEN
+  ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relating linear images to open/closed/interior/closure.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let OPEN_SURJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N.
+        linear f /\ (!y. ?x. f x = y)
+        ==> !s. open s ==> open(IMAGE f s)`,
+  GEN_TAC THEN STRIP_TAC THEN
+  REWRITE_TAC[open_def; FORALL_IN_IMAGE] THEN
+  FIRST_ASSUM(MP_TAC o GEN `k:num` o SPEC `basis k:real^N`) THEN
+  REWRITE_TAC[SKOLEM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:num->real^M` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `bounded(IMAGE (b:num->real^M) (1..dimindex(:N)))` MP_TAC THENL
+   [SIMP_TAC[FINITE_IMP_BOUNDED; FINITE_IMAGE; FINITE_NUMSEG]; ALL_TAC] THEN
+  REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE; IN_NUMSEG] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  X_GEN_TAC `s:real^M->bool` THEN MATCH_MP_TAC MONO_FORALL THEN
+  X_GEN_TAC `x:real^M` THEN ASM_CASES_TAC `(x:real^M) IN s` THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `e / B / &(dimindex(:N))` THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; DIMINDEX_GE_1; LE_1] THEN
+  X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN REWRITE_TAC[IN_IMAGE] THEN
+  ABBREV_TAC `u = y - (f:real^M->real^N) x` THEN
+  EXISTS_TAC `x + vsum(1..dimindex(:N)) (\i. (u:real^N)$i % b i):real^M` THEN
+  ASM_SIMP_TAC[LINEAR_ADD; LINEAR_VSUM; FINITE_NUMSEG; o_DEF;
+               LINEAR_CMUL; BASIS_EXPANSION] THEN
+  CONJ_TAC THENL [EXPAND_TAC "u" THEN VECTOR_ARITH_TAC; ALL_TAC] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN
+  REWRITE_TAC[NORM_ARITH `dist(x + y,x) = norm y`] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `(dist(y,(f:real^M->real^N) x) * &(dimindex(:N))) * B` THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_OF_NUM_LT; DIMINDEX_GE_1; LE_1] THEN
+  MATCH_MP_TAC VSUM_NORM_TRIANGLE THEN REWRITE_TAC[FINITE_NUMSEG] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `(a * b) * c:real = b * a * c`] THEN
+  GEN_REWRITE_TAC(RAND_CONV o LAND_CONV o RAND_CONV) [GSYM CARD_NUMSEG_1] THEN
+  MATCH_MP_TAC SUM_BOUND THEN REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+  X_GEN_TAC `k:num` THEN STRIP_TAC THEN REWRITE_TAC[NORM_MUL; dist] THEN
+  MATCH_MP_TAC REAL_LE_MUL2 THEN REWRITE_TAC[REAL_ABS_POS; NORM_POS_LE] THEN
+  ASM_SIMP_TAC[COMPONENT_LE_NORM]);;
+
+let OPEN_BIJECTIVE_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+        ==> (open(IMAGE f s) <=> open s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [DISCH_TAC; ASM_MESON_TAC[OPEN_SURJECTIVE_LINEAR_IMAGE]] THEN
+  SUBGOAL_THEN `s = {x | (f:real^M->real^N) x IN IMAGE f s}`
+  SUBST1_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC CONTINUOUS_OPEN_PREIMAGE_UNIV THEN
+  ASM_SIMP_TAC[LINEAR_CONTINUOUS_AT]);;
+
+add_linear_invariants [OPEN_BIJECTIVE_LINEAR_IMAGE_EQ];;
+
+let CLOSED_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> !s. closed s ==> closed(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `f:real^M->real^N` LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^M` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC CLOSED_IN_CLOSED_TRANS THEN
+  EXISTS_TAC `IMAGE (f:real^M->real^N) (:real^M)` THEN
+  CONJ_TAC THENL
+   [MP_TAC(ISPECL [`g:real^N->real^M`; `IMAGE (f:real^M->real^N) (:real^M)`;
+                   `IMAGE (g:real^N->real^M) (IMAGE (f:real^M->real^N) s)`]
+        CONTINUOUS_CLOSED_IN_PREIMAGE) THEN
+    ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON] THEN ANTS_TAC THENL
+     [ASM_REWRITE_TAC[GSYM IMAGE_o; IMAGE_I]; ALL_TAC] THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [FUN_EQ_THM]) THEN
+    REWRITE_TAC[EXTENSION; o_THM; I_THM] THEN SET_TAC[];
+    MATCH_MP_TAC CLOSED_INJECTIVE_IMAGE_SUBSPACE THEN
+    ASM_REWRITE_TAC[IN_UNIV; SUBSPACE_UNIV; CLOSED_UNIV] THEN
+    X_GEN_TAC `x:real^M` THEN
+    DISCH_THEN(MP_TAC o AP_TERM `g:real^N->real^M`) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[FUN_EQ_THM; I_THM; o_THM]) THEN
+    ASM_MESON_TAC[LINEAR_0]]);;
+
+let CLOSED_INJECTIVE_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (closed(IMAGE f s) <=> closed s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [DISCH_TAC; ASM_MESON_TAC[CLOSED_INJECTIVE_LINEAR_IMAGE]] THEN
+  SUBGOAL_THEN `s = {x | (f:real^M->real^N) x IN IMAGE f s}`
+  SUBST1_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE_UNIV THEN
+  ASM_SIMP_TAC[LINEAR_CONTINUOUS_AT]);;
+
+add_linear_invariants [CLOSED_INJECTIVE_LINEAR_IMAGE_EQ];;
+
+let CLOSURE_LINEAR_IMAGE_SUBSET = prove
+ (`!f:real^M->real^N s.
+        linear f ==> IMAGE f (closure s) SUBSET closure(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC IMAGE_CLOSURE_SUBSET THEN
+  ASM_SIMP_TAC[CLOSED_CLOSURE; CLOSURE_SUBSET; LINEAR_CONTINUOUS_ON]);;
+
+let CLOSURE_INJECTIVE_LINEAR_IMAGE  = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> closure(IMAGE f s) = IMAGE f (closure s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  ASM_SIMP_TAC[CLOSURE_LINEAR_IMAGE_SUBSET] THEN
+  MATCH_MP_TAC CLOSURE_MINIMAL THEN
+  SIMP_TAC[CLOSURE_SUBSET; IMAGE_SUBSET] THEN
+  ASM_MESON_TAC[CLOSED_INJECTIVE_LINEAR_IMAGE; CLOSED_CLOSURE]);;
+
+add_linear_invariants [CLOSURE_INJECTIVE_LINEAR_IMAGE];;
+
+let CLOSURE_BOUNDED_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ bounded s
+        ==> closure(IMAGE f s) = IMAGE f (closure s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  ASM_SIMP_TAC[CLOSURE_LINEAR_IMAGE_SUBSET] THEN
+  MATCH_MP_TAC CLOSURE_MINIMAL THEN
+  SIMP_TAC[CLOSURE_SUBSET; IMAGE_SUBSET] THEN
+  MATCH_MP_TAC COMPACT_IMP_CLOSED THEN
+  MATCH_MP_TAC COMPACT_LINEAR_IMAGE THEN
+  ASM_REWRITE_TAC[COMPACT_CLOSURE]);;
+
+let LINEAR_INTERIOR_IMAGE_SUBSET = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+       ==> interior(IMAGE f s) SUBSET IMAGE f (interior s)`,
+  MESON_TAC[INTERIOR_IMAGE_SUBSET; LINEAR_CONTINUOUS_AT]);;
+
+let LINEAR_IMAGE_SUBSET_INTERIOR = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!y. ?x. f x = y)
+        ==> IMAGE f (interior s) SUBSET interior(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTERIOR_MAXIMAL THEN
+  ASM_SIMP_TAC[OPEN_SURJECTIVE_LINEAR_IMAGE; OPEN_INTERIOR;
+               IMAGE_SUBSET; INTERIOR_SUBSET]);;
+
+let INTERIOR_BIJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+        ==> interior(IMAGE f s) = IMAGE f (interior s)`,
+  REWRITE_TAC[interior] THEN GEOM_TRANSFORM_TAC[]);;
+
+add_linear_invariants [INTERIOR_BIJECTIVE_LINEAR_IMAGE];;
+
+let FRONTIER_BIJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+        ==> frontier(IMAGE f s) = IMAGE f (frontier s)`,
+  REWRITE_TAC[frontier] THEN GEOM_TRANSFORM_TAC[]);;
+
+add_linear_invariants [FRONTIER_BIJECTIVE_LINEAR_IMAGE];;
+
+(* ------------------------------------------------------------------------- *)
+(* Corollaries, reformulations and special cases for M = N.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let IN_INTERIOR_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N g s x.
+        linear f /\ linear g /\ (f o g = I) /\ x IN interior s
+        ==> (f x) IN interior (IMAGE f s)`,
+  REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `s:real^M->bool`]
+    LINEAR_IMAGE_SUBSET_INTERIOR) THEN
+  ASM_REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+  ASM_MESON_TAC[]);;
+
+let LINEAR_OPEN_MAPPING = prove
+ (`!f:real^M->real^N g.
+        linear f /\ linear g /\ (f o g = I)
+        ==> !s. open s ==> open(IMAGE f s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN DISCH_TAC THEN
+  MATCH_MP_TAC OPEN_SURJECTIVE_LINEAR_IMAGE THEN
+  ASM_MESON_TAC[]);;
+
+let INTERIOR_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^N->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> interior(IMAGE f s) = IMAGE f (interior s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTERIOR_BIJECTIVE_LINEAR_IMAGE THEN
+  ASM_MESON_TAC[LINEAR_INJECTIVE_IMP_SURJECTIVE]);;
+
+let INTERIOR_SURJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^N->real^N s.
+        linear f /\ (!y. ?x. f x = y)
+        ==> interior(IMAGE f s) = IMAGE f (interior s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INTERIOR_BIJECTIVE_LINEAR_IMAGE THEN
+  ASM_MESON_TAC[LINEAR_SURJECTIVE_IMP_INJECTIVE]);;
+
+let CLOSURE_SURJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^N->real^N s.
+        linear f /\ (!y. ?x. f x = y)
+        ==> closure(IMAGE f s) = IMAGE f (closure s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSURE_INJECTIVE_LINEAR_IMAGE THEN
+  ASM_MESON_TAC[LINEAR_SURJECTIVE_IMP_INJECTIVE]);;
+
+let FRONTIER_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^N->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> frontier(IMAGE f s) = IMAGE f (frontier s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC FRONTIER_BIJECTIVE_LINEAR_IMAGE THEN
+  ASM_MESON_TAC[LINEAR_INJECTIVE_IMP_SURJECTIVE]);;
+
+let FRONTIER_SURJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^N->real^N.
+        linear f /\ (!y. ?x. f x = y)
+        ==> frontier(IMAGE f s) = IMAGE f (frontier s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC FRONTIER_BIJECTIVE_LINEAR_IMAGE THEN
+  ASM_MESON_TAC[LINEAR_SURJECTIVE_IMP_INJECTIVE]);;
+
+let COMPLETE_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> !s. complete s ==> complete(IMAGE f s)`,
+  REWRITE_TAC[COMPLETE_EQ_CLOSED; CLOSED_INJECTIVE_LINEAR_IMAGE]);;
+
+let COMPLETE_INJECTIVE_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (complete(IMAGE f s) <=> complete s)`,
+  REWRITE_TAC[COMPLETE_EQ_CLOSED; CLOSED_INJECTIVE_LINEAR_IMAGE_EQ]);;
+
+add_linear_invariants [COMPLETE_INJECTIVE_LINEAR_IMAGE_EQ];;
+
+let LIMPT_INJECTIVE_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> ((f x) limit_point_of (IMAGE f s) <=> x limit_point_of s)`,
+  REWRITE_TAC[LIMPT_APPROACHABLE; EXISTS_IN_IMAGE] THEN
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN X_GEN_TAC `e:real` THEN
+  DISCH_TAC THENL
+   [MP_TAC(ISPEC `f:real^M->real^N` LINEAR_INJECTIVE_BOUNDED_BELOW_POS);
+    MP_TAC(ISPEC `f:real^M->real^N` LINEAR_BOUNDED_POS)] THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THENL
+   [FIRST_X_ASSUM(MP_TAC o SPEC `e * B:real`);
+    FIRST_X_ASSUM(MP_TAC o SPEC `e / B:real`)] THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_MUL; dist; GSYM LINEAR_SUB] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+  REPEAT(MATCH_MP_TAC MONO_AND THEN
+         CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC]) THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_LDIV_EQ; REAL_LT_RDIV_EQ] THEN
+  MATCH_MP_TAC(REAL_ARITH `a <= b ==> b < x ==> a < x`) THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN ASM_SIMP_TAC[REAL_LE_RDIV_EQ]);;
+
+add_linear_invariants [LIMPT_INJECTIVE_LINEAR_IMAGE_EQ];;
+
+let LIMPT_TRANSLATION_EQ = prove
+ (`!a s x. (a + x) limit_point_of (IMAGE (\y. a + y) s) <=> x limit_point_of s`,
+  REWRITE_TAC[limit_point_of] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [LIMPT_TRANSLATION_EQ];;
+
+let OPEN_OPEN_LEFT_PROJECTION = prove
+ (`!s t:real^(M,N)finite_sum->bool.
+        open s /\ open t ==> open {x | x IN s /\ ?y. pastecart x y IN t}`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `{x | x IN s /\ ?y. (pastecart x y:real^(M,N)finite_sum) IN t} =
+    s INTER IMAGE fstcart t`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INTER; IN_IMAGE] THEN
+    MESON_TAC[FSTCART_PASTECART; PASTECART_FST_SND];
+    MATCH_MP_TAC OPEN_INTER THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_IMP; RIGHT_IMP_FORALL_THM]
+      OPEN_SURJECTIVE_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_FSTCART] THEN MESON_TAC[FSTCART_PASTECART]]);;
+
+let OPEN_OPEN_RIGHT_PROJECTION = prove
+ (`!s t:real^(M,N)finite_sum->bool.
+        open s /\ open t ==> open {y | y IN s /\ ?x. pastecart x y IN t}`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `{y | y IN s /\ ?x. (pastecart x y:real^(M,N)finite_sum) IN t} =
+    s INTER IMAGE sndcart t`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INTER; IN_IMAGE] THEN
+    MESON_TAC[SNDCART_PASTECART; PASTECART_FST_SND];
+    MATCH_MP_TAC OPEN_INTER THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_IMP; RIGHT_IMP_FORALL_THM]
+      OPEN_SURJECTIVE_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_SNDCART] THEN MESON_TAC[SNDCART_PASTECART]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Even more special cases.                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let INTERIOR_NEGATIONS = prove
+ (`!s. interior(IMAGE (--) s) = IMAGE (--) (interior s)`,
+  GEN_TAC THEN MATCH_MP_TAC INTERIOR_INJECTIVE_LINEAR_IMAGE THEN
+  REWRITE_TAC[linear] THEN REPEAT CONJ_TAC THEN VECTOR_ARITH_TAC);;
+
+let SYMMETRIC_INTERIOR = prove
+ (`!s:real^N->bool.
+        (!x. x IN s ==> --x IN s)
+        ==> !x. x IN interior s ==> (--x) IN interior s`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP(ISPEC `(--):real^N->real^N` FUN_IN_IMAGE)) THEN
+  REWRITE_TAC[GSYM INTERIOR_NEGATIONS] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE] THEN ASM_MESON_TAC[VECTOR_NEG_NEG]);;
+
+let CLOSURE_NEGATIONS = prove
+ (`!s. closure(IMAGE (--) s) = IMAGE (--) (closure s)`,
+  GEN_TAC THEN MATCH_MP_TAC CLOSURE_INJECTIVE_LINEAR_IMAGE THEN
+  REWRITE_TAC[linear] THEN REPEAT CONJ_TAC THEN VECTOR_ARITH_TAC);;
+
+let SYMMETRIC_CLOSURE = prove
+ (`!s:real^N->bool.
+        (!x. x IN s ==> --x IN s)
+        ==> !x. x IN closure s ==> (--x) IN closure s`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP(ISPEC `(--):real^N->real^N` FUN_IN_IMAGE)) THEN
+  REWRITE_TAC[GSYM CLOSURE_NEGATIONS] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE] THEN ASM_MESON_TAC[VECTOR_NEG_NEG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some properties of a canonical subspace.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let SUBSPACE_SUBSTANDARD = prove
+ (`!d. subspace
+         {x:real^N | !i. d < i /\ i <= dimindex(:N) ==> x$i = &0}`,
+  GEN_TAC THEN ASM_CASES_TAC `d <= dimindex(:N)` THENL
+   [MP_TAC(ARITH_RULE `!i. d < i ==> 1 <= i`) THEN
+    SIMP_TAC[subspace; IN_ELIM_THM; REAL_MUL_RZERO; REAL_ADD_LID;
+             VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; VEC_COMPONENT];
+    ASM_SIMP_TAC[ARITH_RULE `~(d:num <= e) ==> (d < i /\ i <= e <=> F)`] THEN
+    REWRITE_TAC[SET_RULE `{x | T} = UNIV`; SUBSPACE_UNIV]]);;
+
+let CLOSED_SUBSTANDARD = prove
+ (`!d. closed
+        {x:real^N | !i. d < i /\ i <= dimindex(:N) ==> x$i = &0}`,
+  GEN_TAC THEN
+  SUBGOAL_THEN
+   `{x:real^N | !i. d < i /\ i <= dimindex(:N) ==> x$i = &0} =
+    INTERS {{x | basis i dot x = &0} | d < i /\ i <= dimindex(:N)}`
+  SUBST1_TAC THENL
+   [ALL_TAC;
+    SIMP_TAC[CLOSED_INTERS; CLOSED_HYPERPLANE; IN_ELIM_THM;
+             LEFT_IMP_EXISTS_THM]] THEN
+  GEN_REWRITE_TAC I [EXTENSION] THEN REWRITE_TAC[IN_INTERS; IN_ELIM_THM] THEN
+  SIMP_TAC[LEFT_IMP_EXISTS_THM; IN_ELIM_THM] THEN
+  MP_TAC(ARITH_RULE `!i. d < i ==> 1 <= i`) THEN
+  SIMP_TAC[DOT_BASIS] THEN MESON_TAC[]);;
+
+let DIM_SUBSTANDARD = prove
+ (`!d. d <= dimindex(:N)
+       ==> (dim {x:real^N | !i. d < i /\ i <= dimindex(:N)
+                                ==> x$i = &0} =
+            d)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC DIM_UNIQUE THEN
+  EXISTS_TAC `IMAGE (basis:num->real^N) (1..d)` THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM; IN_NUMSEG] THEN
+    MESON_TAC[BASIS_COMPONENT; ARITH_RULE `d < i ==> 1 <= i`; NOT_LT];
+    ALL_TAC;
+    MATCH_MP_TAC INDEPENDENT_MONO THEN
+    EXISTS_TAC `{basis i :real^N | 1 <= i /\ i <= dimindex(:N)}` THEN
+    REWRITE_TAC[INDEPENDENT_STDBASIS]THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM; IN_NUMSEG] THEN
+    ASM_MESON_TAC[LE_TRANS];
+    MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN REWRITE_TAC[HAS_SIZE_NUMSEG_1] THEN
+    REWRITE_TAC[IN_NUMSEG] THEN ASM_MESON_TAC[LE_TRANS; BASIS_INJ]] THEN
+  POP_ASSUM MP_TAC THEN SPEC_TAC(`d:num`,`d:num`) THEN
+  INDUCT_TAC THENL
+   [REWRITE_TAC[ARITH_RULE `0 < i <=> 1 <= i`; SPAN_STDBASIS] THEN
+    SUBGOAL_THEN `IMAGE basis (1 .. 0) :real^N->bool = {}` SUBST1_TAC THENL
+     [REWRITE_TAC[IMAGE_EQ_EMPTY; NUMSEG_EMPTY; ARITH]; ALL_TAC] THEN
+    DISCH_TAC THEN REWRITE_TAC[SPAN_EMPTY; SUBSET; IN_ELIM_THM; IN_SING] THEN
+    SIMP_TAC[CART_EQ; VEC_COMPONENT];
+    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
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN DISCH_TAC THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `x - (x$(SUC d)) % basis(SUC d) :real^N`) THEN
+  ANTS_TAC THENL
+   [X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    FIRST_ASSUM(ASSUME_TAC o MATCH_MP(ARITH_RULE `d < i ==> 1 <= i`)) THEN
+    ASM_SIMP_TAC[VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+    ASM_SIMP_TAC[BASIS_COMPONENT] THEN COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[REAL_MUL_RID; REAL_SUB_REFL] THEN
+    ASM_REWRITE_TAC[REAL_MUL_RZERO; REAL_SUB_RZERO] THEN
+    ASM_MESON_TAC[ARITH_RULE `d < i /\ ~(i = SUC d) ==> SUC d < i`];
+    ALL_TAC] THEN
+  DISCH_TAC THEN
+  SUBST1_TAC(VECTOR_ARITH
+   `x = (x - (x$(SUC d)) % basis(SUC d)) +
+        x$(SUC d) % basis(SUC d) :real^N`) THEN
+  MATCH_MP_TAC SPAN_ADD THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[SPAN_MONO; SUBSET_IMAGE; SUBSET; SUBSET_NUMSEG; LE_REFL; LE];
+    MATCH_MP_TAC SPAN_MUL THEN MATCH_MP_TAC SPAN_SUPERSET THEN
+    REWRITE_TAC[IN_IMAGE; IN_NUMSEG] THEN
+    MESON_TAC[LE_REFL; ARITH_RULE `1 <= SUC d`]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence closure and completeness of all subspaces.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let CLOSED_SUBSPACE = prove
+ (`!s:real^N->bool. subspace s ==> closed s`,
+  REPEAT STRIP_TAC THEN ABBREV_TAC `d = dim(s:real^N->bool)` THEN
+  MP_TAC(MATCH_MP DIM_SUBSTANDARD
+    (ISPEC `s:real^N->bool` DIM_SUBSET_UNIV)) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL
+   [`{x:real^N | !i. d < i /\ i <= dimindex(:N)
+                                ==> x$i = &0}`;
+    `s:real^N->bool`] SUBSPACE_ISOMORPHISM) THEN
+  ASM_REWRITE_TAC[SUBSPACE_SUBSTANDARD] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:real^N->real^N` MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (SUBST_ALL_TAC o SYM) STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC(ISPEC `f:real^N->real^N` CLOSED_INJECTIVE_IMAGE_SUBSPACE) THEN
+  ASM_REWRITE_TAC[SUBSPACE_SUBSTANDARD; CLOSED_SUBSTANDARD] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[LINEAR_0]] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  ASM_MESON_TAC[VEC_COMPONENT; ARITH_RULE `d < i ==> 1 <= i`]);;
+
+let COMPLETE_SUBSPACE = prove
+ (`!s:real^N->bool. subspace s ==> complete s`,
+  REWRITE_TAC[COMPLETE_EQ_CLOSED; CLOSED_SUBSPACE]);;
+
+let CLOSED_SPAN = prove
+ (`!s. closed(span s)`,
+  SIMP_TAC[CLOSED_SUBSPACE; SUBSPACE_SPAN]);;
+
+let DIM_CLOSURE = prove
+ (`!s:real^N->bool. dim(closure s) = dim s`,
+  GEN_TAC THEN REWRITE_TAC[GSYM LE_ANTISYM] THEN CONJ_TAC THENL
+   [GEN_REWRITE_TAC RAND_CONV [GSYM DIM_SPAN]; ALL_TAC] THEN
+  MATCH_MP_TAC DIM_SUBSET THEN REWRITE_TAC[CLOSURE_SUBSET] THEN
+  MATCH_MP_TAC CLOSURE_MINIMAL THEN
+  SIMP_TAC[CLOSED_SUBSPACE; SUBSPACE_SPAN; SPAN_INC]);;
+
+let CLOSED_BOUNDEDPREIM_CONTINUOUS_IMAGE = prove
+ (`!f:real^M->real^N s.
+      closed s /\ f continuous_on s /\
+      (!e. bounded {x | x IN s /\ norm(f x) <= e})
+      ==> closed(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CLOSED_INTERS_COMPACT] THEN
+  REWRITE_TAC[SET_RULE
+   `cball(vec 0,e) INTER IMAGE (f:real^M->real^N) s =
+    IMAGE f (s INTER {x | x IN s /\ f x IN cball(vec 0,e)})`] THEN
+  X_GEN_TAC `e:real` THEN MATCH_MP_TAC COMPACT_CONTINUOUS_IMAGE THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN EXISTS_TAC `s:real^M->bool` THEN
+    ASM_REWRITE_TAC[] THEN SET_TAC[];
+    MATCH_MP_TAC CLOSED_INTER_COMPACT THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN CONJ_TAC THENL
+     [ASM_REWRITE_TAC[IN_CBALL_0];
+      ASM_SIMP_TAC[CONTINUOUS_CLOSED_PREIMAGE; CLOSED_CBALL]]]);;
+
+let CLOSED_INJECTIVE_IMAGE_SUBSET_SUBSPACE = prove
+ (`!f:real^M->real^N s t.
+        closed s /\ s SUBSET t /\ subspace t /\
+        linear f /\
+        (!x. x IN t /\ f(x) = vec 0 ==> x = vec 0)
+        ==> closed(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSED_BOUNDEDPREIM_CONTINUOUS_IMAGE THEN
+  ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON] THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `t:real^M->bool`]
+    INJECTIVE_IMP_ISOMETRIC) THEN
+  ASM_SIMP_TAC[CLOSED_SUBSPACE; real_ge] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  X_GEN_TAC `e:real` THEN MATCH_MP_TAC BOUNDED_SUBSET THEN
+  EXISTS_TAC `cball(vec 0:real^M,e / B)` THEN
+  REWRITE_TAC[BOUNDED_CBALL] THEN
+  ASM_SIMP_TAC[SUBSET; IN_ELIM_THM; IN_CBALL_0; REAL_LE_RDIV_EQ] THEN
+  ASM_MESON_TAC[SUBSET; REAL_LE_TRANS]);;
+
+let BASIS_COORDINATES_LIPSCHITZ = prove
+ (`!b:real^N->bool.
+        independent b
+        ==> ?B. &0 < B /\
+                !c v. v IN b
+                      ==> abs(c v) <= B * norm(vsum b (\v. c(v) % v))`,
+  X_GEN_TAC `k:real^N->bool` THEN DISCH_TAC THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP INDEPENDENT_BOUND) THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `b:num->real^N` STRIP_ASSUME_TAC o
+        GEN_REWRITE_RULE I [FINITE_INDEX_NUMSEG]) THEN
+  ABBREV_TAC `n = CARD(k:real^N->bool)` THEN
+  MP_TAC(ISPECL
+   [`(\x. vsum(1..n) (\i. x$i % b i)):real^N->real^N`;
+    `span(IMAGE basis (1..n)):real^N->bool`]
+        INJECTIVE_IMP_ISOMETRIC) THEN
+  REWRITE_TAC[SUBSPACE_SPAN] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [SIMP_TAC[CLOSED_SUBSPACE; SUBSPACE_SPAN]; ALL_TAC] THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC LINEAR_COMPOSE_VSUM THEN
+      REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC LINEAR_VMUL_COMPONENT THEN
+      SIMP_TAC[LINEAR_ID] THEN ASM_ARITH_TAC;
+      ALL_TAC] THEN
+    X_GEN_TAC `x:real^N` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_SPAN_IMAGE_BASIS]) THEN
+    REWRITE_TAC[IN_NUMSEG] THEN DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INJECTIVE_ON_LEFT_INVERSE]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `c:real^N->num`) THEN
+    SUBGOAL_THEN
+     `vsum(1..n) (\i. (x:real^N)$i % b i:real^N) = vsum k (\v. x$(c v) % v)`
+    SUBST1_TAC THENL
+     [MATCH_MP_TAC VSUM_EQ_GENERAL_INVERSES THEN
+      MAP_EVERY EXISTS_TAC [`b:num->real^N`; `c:real^N->num`] THEN
+      ASM SET_TAC[];
+      ALL_TAC] THEN
+    DISCH_TAC THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INDEPENDENT_EXPLICIT]) THEN
+    DISCH_THEN(MP_TAC o SPEC `\v:real^N. (x:real^N)$(c v)` o CONJUNCT2) THEN
+    ASM_REWRITE_TAC[] THEN ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    REWRITE_TAC[CART_EQ; FORALL_IN_IMAGE; VEC_COMPONENT] THEN
+    ASM_MESON_TAC[IN_NUMSEG];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `inv(B:real)` THEN ASM_REWRITE_TAC[REAL_LT_INV_EQ] THEN
+  ASM_REWRITE_TAC[FORALL_IN_IMAGE; IN_NUMSEG] THEN
+  MAP_EVERY X_GEN_TAC [`c:real^N->real`; `j:num`] THEN STRIP_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `inv B * x = x / B`] THEN
+  ASM_SIMP_TAC[REAL_LE_RDIV_EQ] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) VSUM_IMAGE o rand o rand o snd) THEN
+  ASM_REWRITE_TAC[FINITE_NUMSEG] THEN DISCH_THEN SUBST1_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC
+   `(lambda i. if 1 <= i /\ i <= n then c(b i:real^N) else &0):real^N`) THEN
+  SIMP_TAC[IN_SPAN_IMAGE_BASIS; LAMBDA_BETA] THEN
+  ANTS_TAC THENL [MESON_TAC[IN_NUMSEG]; ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH `x = v /\ u <= y ==> x >= y ==> u <= v`) THEN
+  CONJ_TAC THENL
+   [AP_TERM_TAC THEN MATCH_MP_TAC VSUM_EQ_NUMSEG THEN
+    SUBGOAL_THEN `!i. i <= n ==> i <= dimindex(:N)` MP_TAC THENL
+     [ASM_ARITH_TAC; SIMP_TAC[LAMBDA_BETA] THEN DISCH_THEN(K ALL_TAC)] THEN
+    REWRITE_TAC[o_THM];
+    GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
+    ASM_SIMP_TAC[REAL_LE_RMUL_EQ] THEN
+    MP_TAC(ISPECL
+     [`(lambda i. if 1 <= i /\ i <= n then c(b i:real^N) else &0):real^N`;
+      `j:num`] COMPONENT_LE_NORM) THEN
+    SIMP_TAC[LAMBDA_BETA] THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN MATCH_MP_TAC THEN ASM_ARITH_TAC]);;
+
+let BASIS_COORDINATES_CONTINUOUS = prove
+ (`!b:real^N->bool e.
+        independent b /\ &0 < e
+        ==> ?d. &0 < d /\
+                !c. norm(vsum b (\v. c(v) % v)) < d
+                    ==> !v. v IN b ==> abs(c v) < e`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP BASIS_COORDINATES_LIPSCHITZ) THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `e / B:real` THEN ASM_SIMP_TAC[REAL_LT_DIV] THEN
+  X_GEN_TAC `c:real^N->real` THEN DISCH_TAC THEN
+  X_GEN_TAC `v:real^N` THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `B * norm(vsum b (\v:real^N. c v % v))` THEN
+  ASM_SIMP_TAC[] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Affine transformations of intervals.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let AFFINITY_INVERSES = prove
+ (`!m c. ~(m = &0)
+         ==> (\x. m % x + c) o (\x. inv(m) % x + (--(inv(m) % c))) = I /\
+             (\x. inv(m) % x + (--(inv(m) % c))) o (\x. m % x + c) = I`,
+  REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN
+  REWRITE_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_RNEG] THEN
+  SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; REAL_MUL_RINV] THEN
+  REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC);;
+
+let REAL_AFFINITY_LE = prove
+ (`!m c x y. &0 < m ==> (m * x + c <= y <=> x <= inv(m) * y + --(c / m))`,
+  REWRITE_TAC[REAL_ARITH `m * x + c <= y <=> x * m <= y - c`] THEN
+  SIMP_TAC[GSYM REAL_LE_RDIV_EQ] THEN REAL_ARITH_TAC);;
+
+let REAL_LE_AFFINITY = prove
+ (`!m c x y. &0 < m ==> (y <= m * x + c <=> inv(m) * y + --(c / m) <= x)`,
+  REWRITE_TAC[REAL_ARITH `y <= m * x + c <=> y - c <= x * m`] THEN
+  SIMP_TAC[GSYM REAL_LE_LDIV_EQ] THEN REAL_ARITH_TAC);;
+
+let REAL_AFFINITY_LT = prove
+ (`!m c x y. &0 < m ==> (m * x + c < y <=> x < inv(m) * y + --(c / m))`,
+  SIMP_TAC[REAL_LE_AFFINITY; GSYM REAL_NOT_LE]);;
+
+let REAL_LT_AFFINITY = prove
+ (`!m c x y. &0 < m ==> (y < m * x + c <=> inv(m) * y + --(c / m) < x)`,
+  SIMP_TAC[REAL_AFFINITY_LE; GSYM REAL_NOT_LE]);;
+
+let REAL_AFFINITY_EQ = prove
+ (`!m c x y. ~(m = &0) ==> (m * x + c = y <=> x = inv(m) * y + --(c / m))`,
+  CONV_TAC REAL_FIELD);;
+
+let REAL_EQ_AFFINITY = prove
+ (`!m c x y. ~(m = &0) ==> (y = m * x + c  <=> inv(m) * y + --(c / m) = x)`,
+  CONV_TAC REAL_FIELD);;
+
+let VECTOR_AFFINITY_EQ = prove
+ (`!m c x y. ~(m = &0)
+             ==> (m % x + c = y <=> x = inv(m) % y + --(inv(m) % c))`,
+  SIMP_TAC[CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+           real_div; VECTOR_NEG_COMPONENT; REAL_AFFINITY_EQ] THEN
+  REWRITE_TAC[REAL_MUL_AC]);;
+
+let VECTOR_EQ_AFFINITY = prove
+ (`!m c x y. ~(m = &0)
+             ==> (y = m % x + c <=> inv(m) % y + --(inv(m) % c) = x)`,
+  SIMP_TAC[CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+           real_div; VECTOR_NEG_COMPONENT; REAL_EQ_AFFINITY] THEN
+  REWRITE_TAC[REAL_MUL_AC]);;
+
+let IMAGE_AFFINITY_INTERVAL = prove
+ (`!a b:real^N m c.
+        IMAGE (\x. m % x + c) (interval[a,b]) =
+            if interval[a,b] = {} then {}
+            else if &0 <= m then interval[m % a + c,m % b + c]
+            else interval[m % b + c,m % a + c]`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[IMAGE_CLAUSES] THEN
+  ASM_CASES_TAC `m = &0` THEN ASM_REWRITE_TAC[REAL_LE_LT] THENL
+   [ASM_REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_LID; COND_ID] THEN
+    REWRITE_TAC[INTERVAL_SING] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+   `~(x = &0) ==> &0 < x \/ &0 < --x`)) THEN
+  ASM_SIMP_TAC[EXTENSION; IN_IMAGE; REAL_ARITH `&0 < --x ==> ~(&0 < x)`] THENL
+   [ALL_TAC;
+    ONCE_REWRITE_TAC[VECTOR_ARITH `x = m % y + c <=> c = (--m) % y + x`]] THEN
+  ASM_SIMP_TAC[VECTOR_EQ_AFFINITY; REAL_LT_IMP_NZ; UNWIND_THM1] THEN
+  SIMP_TAC[IN_INTERVAL; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+           VECTOR_NEG_COMPONENT] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM REAL_LT_INV_EQ]) THEN
+  SIMP_TAC[REAL_AFFINITY_LE; REAL_LE_AFFINITY; real_div] THEN
+  DISCH_THEN(K ALL_TAC) THEN REWRITE_TAC[REAL_INV_INV] THEN
+  REWRITE_TAC[REAL_MUL_LNEG; REAL_NEGNEG] THEN
+  ASM_SIMP_TAC[REAL_FIELD `&0 < m ==> (inv m * x) * m = x`] THEN
+  GEN_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN AP_TERM_TAC THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Existence of eigenvectors. The proof is only in this file because it uses *)
+(* a few simple results about continuous functions (at least                 *)
+(* CONTINUOUS_ON_LIFT_DOT2, CONTINUOUS_ATTAINS_SUP and CLOSED_SUBSPACE).     *)
+(* ------------------------------------------------------------------------- *)
+
+let SELF_ADJOINT_HAS_EIGENVECTOR_IN_SUBSPACE = prove
+ (`!f:real^N->real^N s.
+        linear f /\ adjoint f = f /\
+        subspace s /\ ~(s = {vec 0}) /\ (!x. x IN s ==> f x IN s)
+        ==> ?v c. v IN s /\ norm(v) = &1 /\ f(v) = c % v`,
+  let lemma = prove
+   (`!a b. (!x. a * x <= b * x pow 2) ==> &0 <= b ==> a = &0`,
+    REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[REAL_LE_LT] THEN
+    ASM_CASES_TAC `b = &0` THEN ASM_REWRITE_TAC[] THENL
+     [FIRST_X_ASSUM(fun t -> MP_TAC(SPEC `&1` t) THEN
+        MP_TAC(SPEC `-- &1` t)) THEN ASM_REAL_ARITH_TAC;
+      DISCH_TAC THEN  FIRST_X_ASSUM(MP_TAC o SPEC `a / &2 / b`) THEN
+      ASM_SIMP_TAC[REAL_FIELD
+       `&0 < b ==> (b * (a / b) pow 2) = a pow 2 / b`] THEN
+      REWRITE_TAC[real_div; REAL_MUL_ASSOC] THEN SIMP_TAC[GSYM real_div] THEN
+      ASM_SIMP_TAC[REAL_LE_DIV2_EQ] THEN
+      REWRITE_TAC[REAL_LT_SQUARE; REAL_ARITH
+        `(a * a) / &2 <= (a / &2) pow 2 <=> ~(&0 < a * a)`]]) in
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\x:real^N. (f x) dot x`;
+                 `s INTER sphere(vec 0:real^N,&1)`]
+        CONTINUOUS_ATTAINS_SUP) THEN
+  REWRITE_TAC[EXISTS_IN_GSPEC; FORALL_IN_GSPEC; o_DEF] THEN ANTS_TAC THENL
+   [ASM_SIMP_TAC[CONTINUOUS_ON_LIFT_DOT2; LINEAR_CONTINUOUS_ON;
+                   CONTINUOUS_ON_ID] THEN
+    ASM_SIMP_TAC[COMPACT_SPHERE; CLOSED_INTER_COMPACT; CLOSED_SUBSPACE] THEN
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+      `~(s = {a}) ==> a IN s ==> ?b. ~(b = a) /\ b IN s`)) THEN
+    ASM_SIMP_TAC[SUBSPACE_0; IN_SPHERE_0; GSYM MEMBER_NOT_EMPTY; IN_INTER] THEN
+    DISCH_THEN(X_CHOOSE_THEN `x:real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `inv(norm x) % x:real^N` THEN
+    ASM_REWRITE_TAC[IN_ELIM_THM; VECTOR_SUB_RZERO; NORM_MUL] THEN
+    ASM_SIMP_TAC[SUBSPACE_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+    ASM_SIMP_TAC[REAL_MUL_LINV; NORM_EQ_0];
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `v:real^N` THEN
+    REWRITE_TAC[IN_INTER; IN_SPHERE_0] THEN STRIP_TAC THEN
+    ABBREV_TAC `c = (f:real^N->real^N) v dot v` THEN
+    EXISTS_TAC `c:real` THEN ASM_REWRITE_TAC[]] THEN
+  ABBREV_TAC `p = \x y:real^N. c * (x dot y) - (f x) dot y` THEN
+  SUBGOAL_THEN `!x:real^N. x IN s ==> &0 <= p x x` (LABEL_TAC "POSDEF") THENL
+   [X_GEN_TAC `x:real^N` THEN EXPAND_TAC "p" THEN REWRITE_TAC[] THEN
+    ASM_CASES_TAC `x:real^N = vec 0` THEN DISCH_TAC THEN
+    ASM_REWRITE_TAC[DOT_RZERO; REAL_MUL_RZERO; REAL_SUB_LE; REAL_LE_REFL] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `inv(norm x) % x:real^N`) THEN
+    ASM_SIMP_TAC[SUBSPACE_MUL] THEN
+    ASM_SIMP_TAC[LINEAR_CMUL; NORM_MUL; REAL_ABS_INV; DOT_RMUL] THEN
+    ASM_SIMP_TAC[REAL_ABS_NORM; REAL_MUL_LINV; NORM_EQ_0; DOT_LMUL] THEN
+    ASM_SIMP_TAC[GSYM REAL_LE_LDIV_EQ; DOT_POS_LT] THEN
+    REWRITE_TAC[GSYM NORM_POW_2; real_div; REAL_INV_POW] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!y:real^N. y IN s ==> !a. p v y * a <= p y y * a pow 2`
+  MP_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    REMOVE_THEN "POSDEF" (MP_TAC o SPEC `v - (&2 * a) % y:real^N`) THEN
+    EXPAND_TAC "p" THEN ASM_SIMP_TAC[SUBSPACE_SUB; SUBSPACE_MUL] THEN
+    ASM_SIMP_TAC[LINEAR_SUB; LINEAR_CMUL] THEN
+    REWRITE_TAC[DOT_LSUB; DOT_LMUL] THEN
+    REWRITE_TAC[DOT_RSUB; DOT_RMUL] THEN
+    SUBGOAL_THEN `f y dot (v:real^N) = f v dot y` SUBST1_TAC THENL
+     [ASM_MESON_TAC[ADJOINT_CLAUSES; DOT_SYM]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[GSYM NORM_POW_2] THEN REWRITE_TAC[NORM_POW_2] THEN
+    MATCH_MP_TAC(REAL_ARITH
+        `&4 * (z - y) = x ==> &0 <= x ==> y <= z`) THEN
+    REWRITE_TAC[DOT_SYM] THEN CONV_TAC REAL_RING;
+    DISCH_THEN(MP_TAC o GEN `y:real^N` o DISCH `(y:real^N) IN s` o
+      MATCH_MP lemma o C MP (ASSUME `(y:real^N) IN s`) o SPEC `y:real^N`) THEN
+    ASM_SIMP_TAC[] THEN EXPAND_TAC "p" THEN
+    REWRITE_TAC[GSYM DOT_LMUL; GSYM DOT_LSUB] THEN
+    DISCH_THEN(MP_TAC o SPEC `c % v - f v:real^N`) THEN
+    ASM_SIMP_TAC[SUBSPACE_MUL; SUBSPACE_SUB; DOT_EQ_0; VECTOR_SUB_EQ]]);;
+
+let SELF_ADJOINT_HAS_EIGENVECTOR = prove
+ (`!f:real^N->real^N.
+        linear f /\ adjoint f = f ==> ?v c. norm(v) = &1 /\ f(v) = c % v`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^N->real^N`; `(:real^N)`]
+        SELF_ADJOINT_HAS_EIGENVECTOR_IN_SUBSPACE) THEN
+  ASM_REWRITE_TAC[SUBSPACE_UNIV; IN_UNIV] THEN DISCH_THEN MATCH_MP_TAC THEN
+  MATCH_MP_TAC(SET_RULE `!a. ~(a IN s) ==> ~(UNIV = s)`) THEN
+  EXISTS_TAC `vec 1:real^N` THEN
+  REWRITE_TAC[IN_SING; VEC_EQ; ARITH_EQ]);;
+
+let SELF_ADJOINT_HAS_EIGENVECTOR_BASIS_OF_SUBSPACE = prove
+ (`!f:real^N->real^N s.
+        linear f /\ adjoint f = f /\
+        subspace s /\ (!x. x IN s ==> f x IN s)
+        ==> ?b. b SUBSET s /\
+                pairwise orthogonal b /\
+                (!x. x IN b ==> norm x = &1 /\ ?c. f(x) = c % x) /\
+                independent b /\
+                span b = s /\
+                b HAS_SIZE dim s`,
+  let lemma = prove
+   (`!f:real^N->real^N s.
+          linear f /\ adjoint f = f /\ subspace s /\ (!x. x IN s ==> f x IN s)
+          ==> ?b. b SUBSET s /\ b HAS_SIZE dim s /\
+                  pairwise orthogonal b /\
+                  (!x. x IN b ==> norm x = &1 /\ ?c. f(x) = c % x)`,
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN REWRITE_TAC[IMP_IMP] THEN
+    GEN_TAC THEN STRIP_TAC THEN GEN_TAC THEN
+    WF_INDUCT_TAC `dim(s:real^N->bool)` THEN STRIP_TAC THEN
+    ASM_CASES_TAC `dim(s:real^N->bool) = 0` THENL
+     [EXISTS_TAC `{}:real^N->bool` THEN
+      ASM_SIMP_TAC[HAS_SIZE_CLAUSES; NOT_IN_EMPTY;
+                   PAIRWISE_EMPTY; EMPTY_SUBSET];
+      ALL_TAC] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [DIM_EQ_0]) THEN
+    DISCH_THEN(ASSUME_TAC o MATCH_MP (SET_RULE
+     `~(s SUBSET {a}) ==> ~(s = {a})`)) THEN
+    MP_TAC(ISPECL [`f:real^N->real^N`; `s:real^N->bool`]
+      SELF_ADJOINT_HAS_EIGENVECTOR_IN_SUBSPACE) THEN
+    ASM_REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `v:real^N` MP_TAC) THEN
+    ASM_CASES_TAC `v:real^N = vec 0` THEN ASM_REWRITE_TAC[NORM_0] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `{y:real^N | y IN s /\ orthogonal v y}`) THEN
+    REWRITE_TAC[SUBSPACE_ORTHOGONAL_TO_VECTOR; IN_ELIM_THM] THEN
+    MP_TAC(ISPECL [`span {v:real^N}`; `s:real^N->bool`]
+          DIM_SUBSPACE_ORTHOGONAL_TO_VECTORS) THEN
+    REWRITE_TAC[ONCE_REWRITE_RULE[ORTHOGONAL_SYM] ORTHOGONAL_TO_SPAN_EQ] THEN
+    ASM_REWRITE_TAC[SUBSPACE_SPAN; IN_SING; FORALL_UNWIND_THM2] THEN
+    ANTS_TAC THENL
+     [MATCH_MP_TAC SPAN_SUBSET_SUBSPACE THEN ASM SET_TAC[];
+      DISCH_THEN(SUBST1_TAC o SYM)] THEN
+    ASM_REWRITE_TAC[DIM_SPAN; DIM_SING; ARITH_RULE `n < n + 1`] THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[SET_RULE `{x | x IN s /\ P x} = s INTER {x | P x}`] THEN
+      ASM_SIMP_TAC[SUBSPACE_INTER; SUBSPACE_ORTHOGONAL_TO_VECTOR] THEN
+      REWRITE_TAC[orthogonal] THEN X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
+      MATCH_MP_TAC EQ_TRANS THEN
+      EXISTS_TAC `(f:real^N->real^N) v dot x` THEN CONJ_TAC THENL
+       [ASM_MESON_TAC[ADJOINT_CLAUSES];
+        ASM_MESON_TAC[DOT_LMUL; REAL_MUL_RZERO]];
+      DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `(v:real^N) INSERT b` THEN
+      ASM_REWRITE_TAC[FORALL_IN_INSERT] THEN
+      CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      ASM_REWRITE_TAC[PAIRWISE_INSERT] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE; SUBSET; IN_ELIM_THM]) THEN
+      CONJ_TAC THENL
+       [ASM_SIMP_TAC[HAS_SIZE; FINITE_INSERT; CARD_CLAUSES] THEN
+        COND_CASES_TAC THEN ASM_REWRITE_TAC[ADD1] THEN
+        ASM_MESON_TAC[ORTHOGONAL_REFL];
+        RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; IN_ELIM_THM]) THEN
+        ASM_MESON_TAC[ORTHOGONAL_SYM]]]) in
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^N->real^N`; `s:real^N->bool`] lemma) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `b:real^N->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC PAIRWISE_ORTHOGONAL_INDEPENDENT THEN
+    ASM_MESON_TAC[NORM_ARITH `~(norm(vec 0:real^N) = &1)`];
+    DISCH_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[SPAN_SUBSET_SUBSPACE];
+      MATCH_MP_TAC CARD_GE_DIM_INDEPENDENT THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN
+      ASM_REWRITE_TAC[LE_REFL]]]);;
+
+let SELF_ADJOINT_HAS_EIGENVECTOR_BASIS = prove
+ (`!f:real^N->real^N.
+        linear f /\ adjoint f = f
+        ==> ?b. pairwise orthogonal b /\
+                (!x. x IN b ==> norm x = &1 /\ ?c. f(x) = c % x) /\
+                independent b /\
+                span b = (:real^N) /\
+                b HAS_SIZE (dimindex(:N))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^N->real^N`; `(:real^N)`]
+        SELF_ADJOINT_HAS_EIGENVECTOR_BASIS_OF_SUBSPACE) THEN
+  ASM_REWRITE_TAC[SUBSPACE_UNIV; IN_UNIV; DIM_UNIV; SUBSET_UNIV]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Diagonalization of symmetric matrix.                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let SYMMETRIC_MATRIX_DIAGONALIZABLE_EXPLICIT = prove
+ (`!A:real^N^N.
+    transp A = A
+    ==> ?P d. orthogonal_matrix P /\
+              transp P ** A ** P = (lambda i j. if i = j then d i else &0)`,
+  let lemma1 = prove
+   (`!A:real^N^N P:real^N^N d.
+       A ** P = P ** (lambda i j. if i = j then d i else &0) <=>
+       !i. 1 <= i /\ i <= dimindex(:N)
+           ==> A ** column i P = d i % column i P`,
+    SIMP_TAC[CART_EQ; matrix_mul; matrix_vector_mul; LAMBDA_BETA;
+             column; VECTOR_MUL_COMPONENT] THEN
+    REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[COND_RAND] THEN
+    SIMP_TAC[REAL_MUL_RZERO; SUM_DELTA; IN_NUMSEG] THEN
+    EQ_TAC THEN STRIP_TAC THEN ASM_SIMP_TAC[] THEN
+    REWRITE_TAC[REAL_MUL_SYM]) in
+  let lemma2 = prove
+   (`!A:real^N^N P:real^N^N d.
+          orthogonal_matrix P /\
+          transp P ** A ** P = (lambda i j. if i = j then d i else &0) <=>
+          orthogonal_matrix P /\
+          !i. 1 <= i /\ i <= dimindex(:N)
+              ==> A ** column i P = d i % column i P`,
+    REPEAT GEN_TAC THEN REWRITE_TAC[GSYM lemma1; orthogonal_matrix] THEN
+    ABBREV_TAC `D:real^N^N = lambda i j. if i = j then d i else &0` THEN
+    MESON_TAC[MATRIX_MUL_ASSOC; MATRIX_MUL_LID]) in
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[lemma2] THEN REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+  REWRITE_TAC[GSYM SKOLEM_THM] THEN
+  MP_TAC(ISPEC `\x:real^N. (A:real^N^N) ** x`
+    SELF_ADJOINT_HAS_EIGENVECTOR_BASIS) THEN
+  ASM_SIMP_TAC[MATRIX_SELF_ADJOINT; MATRIX_VECTOR_MUL_LINEAR;
+               MATRIX_OF_MATRIX_VECTOR_MUL] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` MP_TAC) THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN ONCE_REWRITE_TAC[IMP_CONJ_ALT] THEN
+  REWRITE_TAC[HAS_SIZE] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [FINITE_INDEX_NUMSEG]) THEN
+  ASM_REWRITE_TAC[IN_NUMSEG; TAUT
+   `p /\ q /\ x = y ==> a = b <=> p /\ q /\ ~(a = b) ==> ~(x = y)`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:num->real^N` STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[PAIRWISE_IMAGE; FORALL_IN_IMAGE] THEN
+  ASM_SIMP_TAC[pairwise; IN_NUMSEG] THEN STRIP_TAC THEN
+  EXISTS_TAC `transp(lambda i. f i):real^N^N` THEN
+  SIMP_TAC[COLUMN_TRANSP; ORTHOGONAL_MATRIX_TRANSP] THEN
+  SIMP_TAC[ORTHOGONAL_MATRIX_ORTHONORMAL_ROWS_INDEXED; row] THEN
+  SIMP_TAC[LAMBDA_ETA; LAMBDA_BETA; pairwise; IN_NUMSEG] THEN
+  ASM_MESON_TAC[]);;
+
+let SYMMETRIC_MATRIX_IMP_DIAGONALIZABLE = prove
+ (`!A:real^N^N.
+     transp A = A
+     ==> ?P. orthogonal_matrix P /\ diagonal_matrix(transp P ** A ** P)`,
+  GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SYMMETRIC_MATRIX_DIAGONALIZABLE_EXPLICIT) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SIMP_TAC[diagonal_matrix; LAMBDA_BETA]);;
+
+let SYMMETRIC_MATRIX_EQ_DIAGONALIZABLE = prove
+ (`!A:real^N^N.
+     transp A = A <=>
+     ?P. orthogonal_matrix P /\ diagonal_matrix(transp P ** A ** P)`,
+  GEN_TAC THEN EQ_TAC THEN
+  REWRITE_TAC[SYMMETRIC_MATRIX_IMP_DIAGONALIZABLE] THEN
+  REWRITE_TAC[orthogonal_matrix] THEN
+  DISCH_THEN(X_CHOOSE_THEN `P:real^N^N` STRIP_ASSUME_TAC) THEN
+  ABBREV_TAC `D:real^N^N = transp P ** (A:real^N^N) ** P` THEN
+  SUBGOAL_THEN `A:real^N^N = P ** (D:real^N^N) ** transp P` SUBST1_TAC THENL
+   [EXPAND_TAC "D" THEN REWRITE_TAC[MATRIX_MUL_ASSOC] THEN
+    ASM_REWRITE_TAC[MATRIX_MUL_LID] THEN
+    ASM_REWRITE_TAC[GSYM MATRIX_MUL_ASSOC; MATRIX_MUL_RID];
+    REWRITE_TAC[MATRIX_TRANSP_MUL; TRANSP_TRANSP; MATRIX_MUL_ASSOC] THEN
+    ASM_MESON_TAC[TRANSP_DIAGONAL_MATRIX]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some matrix identities are easier to deduce for invertible matrices. We   *)
+(* can then extend by continuity, which is why this material needs to be     *)
+(* here after basic topological notions have been defined.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_LIFT_DET = prove
+ (`!(A:A->real^N^N) net.
+        (!i j. 1 <= i /\ i <= dimindex(:N) /\
+               1 <= j /\ j <= dimindex(:N)
+               ==> (\x. lift(A x$i$j)) continuous net)
+        ==> (\x. lift(det(A x))) continuous net`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[det] THEN
+  SIMP_TAC[LIFT_SUM; FINITE_PERMUTATIONS; FINITE_NUMSEG; o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_VSUM THEN
+  SIMP_TAC[FINITE_PERMUTATIONS; FINITE_NUMSEG; LIFT_CMUL; IN_ELIM_THM] THEN
+  X_GEN_TAC `p:num->num` THEN DISCH_TAC THEN
+  MATCH_MP_TAC CONTINUOUS_CMUL THEN
+  MATCH_MP_TAC CONTINUOUS_LIFT_PRODUCT THEN
+  REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP PERMUTES_IMAGE) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE `s = t ==> s SUBSET t`)) THEN
+  ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_NUMSEG]);;
+
+let CONTINUOUS_ON_LIFT_DET = prove
+ (`!A:real^M->real^N^N s.
+        (!i j. 1 <= i /\ i <= dimindex(:N) /\
+               1 <= j /\ j <= dimindex(:N)
+               ==> (\x. lift(A x$i$j)) continuous_on s)
+        ==> (\x. lift(det(A x))) continuous_on s`,
+  SIMP_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN; CONTINUOUS_LIFT_DET]);;
+
+let NEARBY_INVERTIBLE_MATRIX = prove
+ (`!A:real^N^N.
+     ?e. &0 < e /\ !x. ~(x = &0) /\ abs x < e ==> invertible(A + x %% mat 1)`,
+  GEN_TAC THEN MP_TAC(ISPEC `A:real^N^N` CHARACTERISTIC_POLYNOMIAL) THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:num->real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`dimindex(:N)`; `a:num->real`] REAL_POLYFUN_FINITE_ROOTS) THEN
+  MATCH_MP_TAC(TAUT `q /\ (p ==> r) ==> (p <=> q) ==> r`) THEN CONJ_TAC THENL
+   [EXISTS_TAC `dimindex(:N)` THEN ASM_REWRITE_TAC[IN_NUMSEG] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o ISPEC `lift` o MATCH_MP FINITE_IMAGE) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP LIMIT_POINT_FINITE) THEN
+  DISCH_THEN(MP_TAC o SPEC `lift(&0)`) THEN
+  REWRITE_TAC[LIMPT_APPROACHABLE; EXISTS_IN_IMAGE; EXISTS_IN_GSPEC] THEN
+  REWRITE_TAC[DIST_LIFT; LIFT_EQ; REAL_SUB_RZERO; NOT_FORALL_THM; NOT_IMP] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `e:real` THEN
+  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[NOT_EXISTS_THM] THEN
+  DISCH_THEN(fun th -> X_GEN_TAC `x:real` THEN STRIP_TAC THEN
+                MP_TAC(SPEC `--x:real` th)) THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM o SPEC `--x:real`) THEN
+  ASM_REWRITE_TAC[REAL_NEG_EQ_0; REAL_ABS_NEG] THEN
+  ONCE_REWRITE_TAC[GSYM INVERTIBLE_NEG] THEN
+  REWRITE_TAC[INVERTIBLE_DET_NZ; CONTRAPOS_THM] THEN
+  REWRITE_TAC[MATRIX_SUB; MATRIX_NEG_MINUS1] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `--x = -- &1 * x`] THEN
+  REWRITE_TAC[GSYM MATRIX_CMUL_ADD_LDISTRIB; GSYM MATRIX_CMUL_ASSOC] THEN
+  REWRITE_TAC[MATRIX_CMUL_LID; MATRIX_ADD_SYM]);;
+
+let MATRIX_WLOG_INVERTIBLE = prove
+ (`!P. (!A:real^N^N. invertible A ==> P A) /\
+       (!A:real^N^N. ?d. &0 < d /\
+                         closed {x | x IN cball(vec 0,d) /\
+                                     P(A + drop x %% mat 1)})
+       ==> !A:real^N^N. P A`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o SPEC `vec 0:real^1` o
+    GEN_REWRITE_RULE I [CLOSED_LIMPT]) THEN
+  ASM_SIMP_TAC[IN_ELIM_THM; DROP_VEC; MATRIX_CMUL_LZERO; MATRIX_ADD_RID] THEN
+  ANTS_TAC THENL [ALL_TAC; CONV_TAC TAUT] THEN
+  MP_TAC(ISPEC `A:real^N^N` NEARBY_INVERTIBLE_MATRIX) THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[LIMPT_APPROACHABLE] THEN X_GEN_TAC `k:real` THEN
+  DISCH_TAC THEN REWRITE_TAC[EXISTS_LIFT; IN_ELIM_THM] THEN
+  REWRITE_TAC[GSYM LIFT_NUM; IN_CBALL_0; NORM_LIFT; DIST_LIFT] THEN
+  REWRITE_TAC[REAL_SUB_RZERO; LIFT_EQ; LIFT_DROP] THEN
+  EXISTS_TAC `min d ((min e k) / &2)` THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+  CONJ_TAC THENL [ASM_REAL_ARITH_TAC; FIRST_X_ASSUM MATCH_MP_TAC] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REAL_ARITH_TAC);;
+
+let SYLVESTER_DETERMINANT_IDENTITY = prove
+ (`!A:real^N^M B:real^M^N. det(mat 1 + A ** B) = det(mat 1 + B ** A)`,
+  let lemma1 = prove
+   (`!A:real^N^N B:real^N^N. det(mat 1 + A ** B) = det(mat 1 + B ** A)`,
+    ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN GEN_TAC THEN
+    MATCH_MP_TAC MATRIX_WLOG_INVERTIBLE THEN CONJ_TAC THENL
+     [REPEAT STRIP_TAC THEN
+      SUBGOAL_THEN `det((mat 1 + A ** B) ** A:real^N^N) =
+                    det(A ** (mat 1 + B ** A))`
+      MP_TAC THENL
+       [REWRITE_TAC[MATRIX_ADD_RDISTRIB; MATRIX_ADD_LDISTRIB] THEN
+        REWRITE_TAC[MATRIX_MUL_LID; MATRIX_MUL_RID; MATRIX_MUL_ASSOC];
+        REWRITE_TAC[DET_MUL] THEN
+        FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INVERTIBLE_DET_NZ]) THEN
+        CONV_TAC REAL_RING];
+      X_GEN_TAC `A:real^N^N` THEN EXISTS_TAC `&1` THEN
+      REWRITE_TAC[REAL_LT_01; SET_RULE
+       `{x | x IN s /\ P x} = s INTER {x | P x}`] THEN
+      MATCH_MP_TAC CLOSED_INTER THEN REWRITE_TAC[CLOSED_CBALL] THEN
+      ONCE_REWRITE_TAC[GSYM REAL_SUB_0] THEN
+      REWRITE_TAC[GSYM LIFT_EQ; LIFT_NUM] THEN
+      REWRITE_TAC[SET_RULE `{x | f x = a} = {x | f x IN {a}}`] THEN
+      MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE_UNIV THEN
+      REWRITE_TAC[CLOSED_SING; LIFT_SUB] THEN X_GEN_TAC `x:real^1` THEN
+      REWRITE_TAC[o_DEF; LIFT_SUB] THEN MATCH_MP_TAC CONTINUOUS_SUB THEN
+      CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_LIFT_DET THEN
+      MAP_EVERY X_GEN_TAC [`i:num`; `j:num`] THEN STRIP_TAC THEN
+      ASM_SIMP_TAC[MATRIX_ADD_COMPONENT; LIFT_ADD] THEN
+      MATCH_MP_TAC CONTINUOUS_ADD THEN
+      ASM_SIMP_TAC[matrix_mul; LAMBDA_BETA; CONTINUOUS_CONST] THEN
+      SIMP_TAC[LIFT_SUM; FINITE_NUMSEG; o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_VSUM THEN
+      REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN X_GEN_TAC `k:num` THEN
+      DISCH_TAC THENL [ONCE_REWRITE_TAC[REAL_MUL_SYM]; ALL_TAC] THEN
+      REWRITE_TAC[LIFT_CMUL] THEN MATCH_MP_TAC CONTINUOUS_CMUL THEN
+      REWRITE_TAC[MATRIX_ADD_COMPONENT; MATRIX_CMUL_COMPONENT; LIFT_ADD] THEN
+      MATCH_MP_TAC CONTINUOUS_ADD THEN REWRITE_TAC[CONTINUOUS_CONST] THEN
+      REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] LIFT_CMUL] THEN
+      MATCH_MP_TAC CONTINUOUS_CMUL THEN
+      REWRITE_TAC[LIFT_DROP; CONTINUOUS_AT_ID]]) in
+  let lemma2 = prove
+   (`!A:real^N^M B:real^M^N.
+          dimindex(:M) <= dimindex(:N)
+          ==> det(mat 1 + A ** B) = det(mat 1 + B ** A)`,
+    REPEAT STRIP_TAC THEN
+    MAP_EVERY ABBREV_TAC
+     [`A':real^N^N =
+          lambda i j. if i <= dimindex(:M) then (A:real^N^M)$i$j
+                      else &0`;
+      `B':real^N^N =
+          lambda i j. if j <= dimindex(:M) then (B:real^M^N)$i$j
+                      else &0`] THEN
+    MP_TAC(ISPECL [`A':real^N^N`; `B':real^N^N`] lemma1) THEN
+    SUBGOAL_THEN
+     `(B':real^N^N) ** (A':real^N^N) = (B:real^M^N) ** (A:real^N^M)`
+    SUBST1_TAC THENL
+     [MAP_EVERY EXPAND_TAC ["A'"; "B'"] THEN
+      SIMP_TAC[CART_EQ; LAMBDA_BETA; matrix_mul] THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC SUM_EQ_SUPERSET THEN
+      ASM_SIMP_TAC[IN_NUMSEG; REAL_MUL_LZERO; FINITE_NUMSEG; SUBSET_NUMSEG;
+                   LE_REFL; TAUT `(p /\ q) /\ ~(p /\ r) <=> p /\ q /\ ~r`];
+      DISCH_THEN(SUBST1_TAC o SYM)] THEN
+    REWRITE_TAC[det] THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+     `sum {p | p permutes 1..dimindex(:N) /\ !i. dimindex(:M) < i ==> p i = i}
+          (\p. sign p * product (1..dimindex(:N))
+                     (\i. (mat 1 + (A':real^N^N) ** (B':real^N^N))$i$p i))` THEN
+    CONJ_TAC THENL
+     [ALL_TAC;
+      CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_SUPERSET THEN
+      CONJ_TAC THENL [SET_TAC[]; SIMP_TAC[IN_ELIM_THM; IMP_CONJ]] THEN
+      X_GEN_TAC `p:num->num` THEN REPEAT STRIP_TAC THEN
+      REWRITE_TAC[REAL_ENTIRE; PRODUCT_EQ_0_NUMSEG] THEN DISJ2_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_FORALL_THM]) THEN
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:num` THEN
+      REWRITE_TAC[NOT_IMP] THEN STRIP_TAC THEN
+      FIRST_ASSUM(MP_TAC o SPEC `k:num` o CONJUNCT1 o
+        GEN_REWRITE_RULE I [permutes]) THEN
+      ASM_REWRITE_TAC[IN_NUMSEG] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP PERMUTES_IMAGE) THEN
+      DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE `s = t ==> s SUBSET t`)) THEN
+      ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_NUMSEG] THEN
+      DISCH_THEN(MP_TAC o SPEC `k:num`) THEN ASM_SIMP_TAC[] THEN STRIP_TAC THEN
+      ASM_SIMP_TAC[MATRIX_ADD_COMPONENT; MAT_COMPONENT; REAL_ADD_LID] THEN
+      ASM_SIMP_TAC[matrix_mul; LAMBDA_BETA] THEN
+      MATCH_MP_TAC SUM_EQ_0_NUMSEG THEN REPEAT STRIP_TAC THEN
+      REWRITE_TAC[REAL_ENTIRE] THEN DISJ1_TAC THEN EXPAND_TAC "A'" THEN
+      ASM_SIMP_TAC[LAMBDA_BETA; GSYM NOT_LT]] THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_EQ_GENERAL THEN
+    EXISTS_TAC `\f:num->num. f` THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    CONJ_TAC THEN X_GEN_TAC `p:num->num` THEN STRIP_TAC THENL
+     [REWRITE_TAC[MESON[] `(?!x. P x /\ x = y) <=> P y`] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC PERMUTES_SUBSET THEN
+        EXISTS_TAC `1..dimindex(:M)` THEN
+        ASM_REWRITE_TAC[SUBSET_NUMSEG; LE_REFL];
+        X_GEN_TAC `k:num` THEN DISCH_TAC THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o CONJUNCT1 o
+          GEN_REWRITE_RULE I [permutes]) THEN
+        ASM_REWRITE_TAC[IN_NUMSEG; DE_MORGAN_THM; NOT_LE]];
+      MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+       [MATCH_MP_TAC PERMUTES_SUPERSET THEN
+        EXISTS_TAC `1..dimindex(:N)` THEN
+        ASM_REWRITE_TAC[IN_DIFF; IN_NUMSEG] THEN ASM_MESON_TAC[NOT_LE];
+        DISCH_TAC] THEN
+      AP_TERM_TAC THEN FIRST_ASSUM(SUBST1_TAC o MATCH_MP (ARITH_RULE
+       `m:num <= n ==> n = m + (n - m)`)) THEN
+      SIMP_TAC[PRODUCT_ADD_SPLIT; ARITH_RULE `1 <= n + 1`] THEN
+      MATCH_MP_TAC(REAL_RING `x = y /\ z = &1 ==> x = y * z`) THEN
+      CONJ_TAC THENL
+       [MATCH_MP_TAC PRODUCT_EQ_NUMSEG THEN
+        X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+        SUBGOAL_THEN `i <= dimindex(:N)` ASSUME_TAC THENL
+         [ASM_ARITH_TAC; ALL_TAC] THEN
+        MP_TAC(ISPECL [`p:num->num`; `1..dimindex(:M)`] PERMUTES_IMAGE) THEN
+        ASM_REWRITE_TAC[] THEN
+        DISCH_THEN(MP_TAC o MATCH_MP (SET_RULE `s = t ==> s SUBSET t`)) THEN
+        ASM_SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_NUMSEG] THEN
+        DISCH_THEN(MP_TAC o SPEC `i:num`) THEN
+        ASM_REWRITE_TAC[] THEN STRIP_TAC THEN
+        SUBGOAL_THEN `(p:num->num) i <= dimindex(:N)` ASSUME_TAC THENL
+         [ASM_ARITH_TAC; ALL_TAC] THEN
+        ASM_SIMP_TAC[MATRIX_ADD_COMPONENT; MAT_COMPONENT] THEN
+        AP_TERM_TAC THEN ASM_SIMP_TAC[matrix_mul; LAMBDA_BETA] THEN
+        MATCH_MP_TAC SUM_EQ_NUMSEG THEN REPEAT STRIP_TAC THEN
+        MAP_EVERY EXPAND_TAC ["A'"; "B'"] THEN
+        ASM_SIMP_TAC[LAMBDA_BETA];
+        MATCH_MP_TAC PRODUCT_EQ_1_NUMSEG THEN
+        ASM_SIMP_TAC[ARITH_RULE `n + 1 <= i ==> n < i`] THEN
+        ASM_SIMP_TAC[ARITH_RULE `m:num <= n ==> m + (n - m) = n`] THEN
+        X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+        SUBGOAL_THEN `1 <= i` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+        ASM_SIMP_TAC[MATRIX_ADD_COMPONENT; MAT_COMPONENT] THEN
+        ASM_SIMP_TAC[REAL_EQ_ADD_LCANCEL_0; matrix_mul; LAMBDA_BETA] THEN
+        MATCH_MP_TAC SUM_EQ_0_NUMSEG THEN REPEAT STRIP_TAC THEN
+        REWRITE_TAC[REAL_ENTIRE] THEN DISJ1_TAC THEN EXPAND_TAC "A'" THEN
+        ASM_SIMP_TAC[LAMBDA_BETA; ARITH_RULE `m + 1 <= i ==> ~(i <= m)`]]]) in
+  REPEAT GEN_TAC THEN DISJ_CASES_TAC (ARITH_RULE
+   `dimindex(:M) <= dimindex(:N) \/ dimindex(:N) <= dimindex(:M)`)
+  THENL [ALL_TAC; CONV_TAC SYM_CONV] THEN
+  MATCH_MP_TAC lemma2 THEN ASM_REWRITE_TAC[]);;
+
+let COFACTOR_MATRIX_MUL = prove
+ (`!A B:real^N^N. cofactor(A ** B) = cofactor(A) ** cofactor(B)`,
+  MATCH_MP_TAC MATRIX_WLOG_INVERTIBLE THEN CONJ_TAC THENL
+   [GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC MATRIX_WLOG_INVERTIBLE THEN
+    CONJ_TAC THENL
+     [ASM_SIMP_TAC[COFACTOR_MATRIX_INV; GSYM INVERTIBLE_DET_NZ;
+                   INVERTIBLE_MATRIX_MUL] THEN
+      REWRITE_TAC[DET_MUL; MATRIX_MUL_LMUL] THEN
+      REWRITE_TAC[MATRIX_MUL_RMUL; MATRIX_CMUL_ASSOC;
+                  GSYM MATRIX_TRANSP_MUL] THEN
+      ASM_SIMP_TAC[MATRIX_INV_MUL];
+      GEN_TAC THEN EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01]];
+    X_GEN_TAC `A:real^N^N` THEN EXISTS_TAC `&1` THEN
+    REWRITE_TAC[REAL_LT_01] THEN REWRITE_TAC[RIGHT_AND_FORALL_THM] THEN
+    MATCH_MP_TAC CLOSED_FORALL THEN GEN_TAC] THEN
+  REWRITE_TAC[SET_RULE
+   `{x | x IN s /\ P x} = s INTER {x | P x}`] THEN
+  MATCH_MP_TAC CLOSED_INTER THEN REWRITE_TAC[CLOSED_CBALL] THEN
+  REWRITE_TAC[CART_EQ] THEN
+  MATCH_MP_TAC CLOSED_FORALL_IN THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  MATCH_MP_TAC CLOSED_FORALL_IN THEN X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM REAL_SUB_0] THEN
+  REWRITE_TAC[GSYM LIFT_EQ; LIFT_NUM] THEN
+  REWRITE_TAC[SET_RULE `{x | f x = a} = {x | f x IN {a}}`] THEN
+  MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE_UNIV THEN
+  REWRITE_TAC[CLOSED_SING; LIFT_SUB] THEN X_GEN_TAC `x:real^1` THEN
+  ASM_SIMP_TAC[matrix_mul; LAMBDA_BETA; cofactor; LIFT_SUM;
+               FINITE_NUMSEG; o_DEF] THEN
+  (MATCH_MP_TAC CONTINUOUS_SUB THEN CONJ_TAC THENL
+    [ALL_TAC;
+     MATCH_MP_TAC CONTINUOUS_VSUM THEN
+     REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+     X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+     REWRITE_TAC[LIFT_CMUL] THEN MATCH_MP_TAC CONTINUOUS_MUL THEN
+     REWRITE_TAC[o_DEF] THEN CONJ_TAC]) THEN
+  MATCH_MP_TAC CONTINUOUS_LIFT_DET THEN
+  MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[LAMBDA_BETA; CONTINUOUS_CONST] THEN
+  REPEAT(W(fun (asl,w) ->
+   let t = find_term is_cond w in
+   ASM_CASES_TAC (lhand(rator t)) THEN ASM_REWRITE_TAC[CONTINUOUS_CONST])) THEN
+  SIMP_TAC[LIFT_SUM; FINITE_NUMSEG; o_DEF] THEN
+  TRY(MATCH_MP_TAC CONTINUOUS_VSUM THEN REWRITE_TAC[FINITE_NUMSEG] THEN
+      REWRITE_TAC[IN_NUMSEG] THEN X_GEN_TAC `p:num` THEN STRIP_TAC) THEN
+  REWRITE_TAC[LIFT_CMUL] THEN
+  TRY(MATCH_MP_TAC CONTINUOUS_MUL THEN
+      REWRITE_TAC[o_DEF; CONTINUOUS_CONST]) THEN
+  REWRITE_TAC[MATRIX_ADD_COMPONENT; LIFT_ADD] THEN
+  MATCH_MP_TAC CONTINUOUS_ADD THEN REWRITE_TAC[CONTINUOUS_CONST] THEN
+  REWRITE_TAC[MATRIX_CMUL_COMPONENT; LIFT_CMUL; o_DEF] THEN
+  MATCH_MP_TAC CONTINUOUS_MUL THEN
+  REWRITE_TAC[CONTINUOUS_CONST; o_DEF; LIFT_DROP; CONTINUOUS_AT_ID]);;
+
+let DET_COFACTOR = prove
+ (`!A:real^N^N. det(cofactor A) = det(A) pow (dimindex(:N) - 1)`,
+  MATCH_MP_TAC MATRIX_WLOG_INVERTIBLE THEN CONJ_TAC THEN
+  X_GEN_TAC `A:real^N^N` THENL
+   [REWRITE_TAC[INVERTIBLE_DET_NZ] THEN STRIP_TAC THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_FIELD
+     `~(a = &0) ==> a * x = a * y ==> x = y`)) THEN
+    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM DET_TRANSP] THEN
+    REWRITE_TAC[GSYM DET_MUL; MATRIX_MUL_RIGHT_COFACTOR] THEN
+    REWRITE_TAC[DET_CMUL; GSYM(CONJUNCT2 real_pow); DET_I; REAL_MUL_RID] THEN
+    SIMP_TAC[DIMINDEX_GE_1; ARITH_RULE `1 <= n ==> SUC(n - 1) = n`];
+    ALL_TAC] THEN
+  EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN
+  REWRITE_TAC[SET_RULE
+   `{x | x IN s /\ P x} = s INTER {x | P x}`] THEN
+  MATCH_MP_TAC CLOSED_INTER THEN REWRITE_TAC[CLOSED_CBALL] THEN
+  ONCE_REWRITE_TAC[GSYM REAL_SUB_0] THEN
+  REWRITE_TAC[GSYM LIFT_EQ; LIFT_NUM] THEN
+  REWRITE_TAC[SET_RULE `{x | f x = a} = {x | f x IN {a}}`] THEN
+  MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE_UNIV THEN
+  REWRITE_TAC[CLOSED_SING; LIFT_SUB] THEN X_GEN_TAC `x:real^1` THEN
+  MATCH_MP_TAC CONTINUOUS_SUB THEN
+  CONJ_TAC THENL [ALL_TAC; MATCH_MP_TAC CONTINUOUS_LIFT_POW] THEN
+  MATCH_MP_TAC CONTINUOUS_LIFT_DET THEN
+  MAP_EVERY X_GEN_TAC [`i:num`; `j:num`] THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[MATRIX_ADD_COMPONENT; MATRIX_CMUL_COMPONENT; LIFT_ADD;
+               LIFT_CMUL; LIFT_DROP; CONTINUOUS_ADD; CONTINUOUS_CONST;
+               CONTINUOUS_MUL; o_DEF; LIFT_DROP; CONTINUOUS_AT_ID] THEN
+  ASM_SIMP_TAC[cofactor; LAMBDA_BETA] THEN
+  MATCH_MP_TAC CONTINUOUS_LIFT_DET THEN
+  MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN STRIP_TAC THEN
+  ASM_SIMP_TAC[LAMBDA_BETA] THEN
+  REPEAT(W(fun (asl,w) ->
+   let t = find_term is_cond w in
+   ASM_CASES_TAC (lhand(rator t)) THEN ASM_REWRITE_TAC[CONTINUOUS_CONST])) THEN
+  ASM_SIMP_TAC[MATRIX_ADD_COMPONENT; MATRIX_CMUL_COMPONENT; LIFT_ADD;
+               LIFT_CMUL; LIFT_DROP; CONTINUOUS_ADD; CONTINUOUS_CONST;
+               CONTINUOUS_MUL; o_DEF; LIFT_DROP; CONTINUOUS_AT_ID]);;
+
+let INVERTIBLE_COFACTOR = prove
+ (`!A:real^N^N. invertible(cofactor A) <=> dimindex(:N) = 1 \/ invertible A`,
+  SIMP_TAC[DET_COFACTOR; INVERTIBLE_DET_NZ; REAL_POW_EQ_0; DE_MORGAN_THM;
+           DIMINDEX_GE_1; ARITH_RULE `1 <= n ==> (n - 1 = 0 <=> n = 1)`;
+           DISJ_ACI]);;
+
+let COFACTOR_COFACTOR = prove
+ (`!A:real^N^N.
+     2 <= dimindex(:N)
+     ==> cofactor(cofactor A) = (det(A) pow (dimindex(:N) - 2)) %% A`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN DISCH_TAC THEN
+  MATCH_MP_TAC MATRIX_WLOG_INVERTIBLE THEN CONJ_TAC THEN
+  X_GEN_TAC `A:real^N^N` THENL
+   [REWRITE_TAC[INVERTIBLE_DET_NZ] THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`A:real^N^N`; `transp(cofactor A):real^N^N`]
+        COFACTOR_MATRIX_MUL) THEN
+    REWRITE_TAC[MATRIX_MUL_RIGHT_COFACTOR; COFACTOR_CMUL; COFACTOR_I] THEN
+    REWRITE_TAC[COFACTOR_TRANSP] THEN
+    DISCH_THEN(MP_TAC o AP_TERM `transp:real^N^N->real^N^N`) THEN
+    REWRITE_TAC[MATRIX_TRANSP_MUL; TRANSP_TRANSP; TRANSP_MATRIX_CMUL] THEN
+    REWRITE_TAC[TRANSP_MAT] THEN
+    DISCH_THEN(MP_TAC o AP_TERM `(\x. x ** A):real^N^N->real^N^N`) THEN
+    REWRITE_TAC[GSYM MATRIX_MUL_ASSOC; MATRIX_MUL_LEFT_COFACTOR] THEN
+    REWRITE_TAC[MATRIX_MUL_LMUL; MATRIX_MUL_RMUL] THEN
+    REWRITE_TAC[MATRIX_MUL_LID; MATRIX_MUL_RID] THEN
+    DISCH_THEN(MP_TAC o AP_TERM `\x:real^N^N. inv(det(A:real^N^N)) %% x`) THEN
+    ASM_SIMP_TAC[MATRIX_CMUL_ASSOC; REAL_MUL_LINV; MATRIX_CMUL_LID] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    ASM_SIMP_TAC[REAL_POW_SUB; ARITH_RULE `2 <= n ==> 1 <= n`] THEN
+    REWRITE_TAC[REAL_POW_2; real_div; REAL_INV_POW] THEN REAL_ARITH_TAC;
+    POP_ASSUM(K ALL_TAC)] THEN
+  EXISTS_TAC `&1` THEN REWRITE_TAC[REAL_LT_01] THEN
+  REWRITE_TAC[SET_RULE
+   `{x | x IN s /\ P x} = s INTER {x | P x}`] THEN
+  MATCH_MP_TAC CLOSED_INTER THEN REWRITE_TAC[CLOSED_CBALL] THEN
+  REWRITE_TAC[CART_EQ] THEN
+  MATCH_MP_TAC CLOSED_FORALL_IN THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+  MATCH_MP_TAC CLOSED_FORALL_IN THEN X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM REAL_SUB_0] THEN
+  REWRITE_TAC[GSYM LIFT_EQ; LIFT_NUM] THEN
+  REWRITE_TAC[SET_RULE `{x | f x = a} = {x | f x IN {a}}`] THEN
+  MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE_UNIV THEN
+  REWRITE_TAC[CLOSED_SING; LIFT_SUB] THEN X_GEN_TAC `x:real^1` THEN
+  MATCH_MP_TAC CONTINUOUS_SUB THEN CONJ_TAC THENL
+   [REPLICATE_TAC 2
+     (ONCE_REWRITE_TAC[cofactor] THEN ASM_SIMP_TAC[LAMBDA_BETA] THEN
+      MATCH_MP_TAC CONTINUOUS_LIFT_DET THEN REPEAT STRIP_TAC THEN
+      ASM_SIMP_TAC[LAMBDA_BETA] THEN
+      REPEAT(W(fun (asl,w) ->
+       let t = find_term is_cond w in
+       ASM_CASES_TAC (lhand(rator t)) THEN
+       ASM_REWRITE_TAC[CONTINUOUS_CONST])));
+    REWRITE_TAC[MATRIX_CMUL_COMPONENT; LIFT_CMUL] THEN
+    MATCH_MP_TAC CONTINUOUS_MUL THEN REWRITE_TAC[o_DEF] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_LIFT_POW THEN
+      MATCH_MP_TAC CONTINUOUS_LIFT_DET THEN REPEAT STRIP_TAC;
+      ALL_TAC]] THEN
+  REWRITE_TAC[MATRIX_ADD_COMPONENT; MATRIX_CMUL_COMPONENT] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  REWRITE_TAC[LIFT_ADD; LIFT_CMUL; LIFT_DROP] THEN
+  SIMP_TAC[CONTINUOUS_ADD; CONTINUOUS_CONST; CONTINUOUS_CMUL;
+           CONTINUOUS_AT_ID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Infinite sums of vectors. Allow general starting point (and more).        *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("sums",(12,"right"));;
+
+let sums = new_definition
+  `(f sums l) s = ((\n. vsum(s INTER (0..n)) f) --> l) sequentially`;;
+
+let infsum = new_definition
+ `infsum s f = @l. (f sums l) s`;;
+
+let summable = new_definition
+ `summable s f = ?l. (f sums l) s`;;
+
+let SUMS_SUMMABLE = prove
+ (`!f l s. (f sums l) s ==> summable s f`,
+  REWRITE_TAC[summable] THEN MESON_TAC[]);;
+
+let SUMS_INFSUM = prove
+ (`!f s. (f sums (infsum s f)) s <=> summable s f`,
+  REWRITE_TAC[infsum; summable] THEN MESON_TAC[]);;
+
+let SUMS_LIM = prove
+ (`!f:num->real^N s.
+      (f sums lim sequentially (\n. vsum (s INTER (0..n)) f)) s
+      <=> summable s f`,
+  GEN_TAC THEN GEN_TAC THEN EQ_TAC THENL [MESON_TAC[summable];
+  REWRITE_TAC[summable; sums] THEN STRIP_TAC THEN REWRITE_TAC[lim] THEN
+  ASM_MESON_TAC[]]);;
+
+let FINITE_INTER_NUMSEG = prove
+ (`!s m n. FINITE(s INTER (m..n))`,
+  MESON_TAC[FINITE_SUBSET; FINITE_NUMSEG; INTER_SUBSET]);;
+
+let SERIES_FROM = prove
+ (`!f l k. (f sums l) (from k) = ((\n. vsum(k..n) f) --> l) sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[sums] THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; numseg; from; IN_ELIM_THM; IN_INTER] THEN ARITH_TAC);;
+
+let SERIES_UNIQUE = prove
+ (`!f:num->real^N l l' s. (f sums l) s /\ (f sums l') s ==> (l = l')`,
+  REWRITE_TAC[sums] THEN MESON_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; LIM_UNIQUE]);;
+
+let INFSUM_UNIQUE = prove
+ (`!f:num->real^N l s. (f sums l) s ==> infsum s f = l`,
+  MESON_TAC[SERIES_UNIQUE; SUMS_INFSUM; summable]);;
+
+let SERIES_FINITE = prove
+ (`!f s. FINITE s ==> (f sums (vsum s f)) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[num_FINITE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `n:num` THEN REWRITE_TAC[sums; LIM_SEQUENTIALLY] THEN
+  DISCH_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN EXISTS_TAC `n:num` THEN
+  X_GEN_TAC `m:num` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `s INTER (0..m) = s`
+   (fun th -> ASM_REWRITE_TAC[th; DIST_REFL]) THEN
+  REWRITE_TAC[EXTENSION; IN_INTER; IN_NUMSEG; LE_0] THEN
+  ASM_MESON_TAC[LE_TRANS]);;
+
+let SERIES_LINEAR = prove
+ (`!f h l s. (f sums l) s /\ linear h ==> ((\n. h(f n)) sums h l) s`,
+  SIMP_TAC[sums; LIM_LINEAR; FINITE_INTER; FINITE_NUMSEG;
+           GSYM(REWRITE_RULE[o_DEF] LINEAR_VSUM)]);;
+
+let SERIES_0 = prove
+ (`!s. ((\n. vec 0) sums (vec 0)) s`,
+  REWRITE_TAC[sums; VSUM_0; LIM_CONST]);;
+
+let SERIES_ADD = prove
+ (`!x x0 y y0 s.
+     (x sums x0) s /\ (y sums y0) s ==> ((\n. x n + y n) sums (x0 + y0)) s`,
+  SIMP_TAC[sums; FINITE_INTER_NUMSEG; VSUM_ADD; LIM_ADD]);;
+
+let SERIES_SUB = prove
+ (`!x x0 y y0 s.
+     (x sums x0) s /\ (y sums y0) s ==> ((\n. x n - y n) sums (x0 - y0)) s`,
+  SIMP_TAC[sums; FINITE_INTER_NUMSEG; VSUM_SUB; LIM_SUB]);;
+
+let SERIES_CMUL = prove
+ (`!x x0 c s. (x sums x0) s ==> ((\n. c % x n) sums (c % x0)) s`,
+  SIMP_TAC[sums; FINITE_INTER_NUMSEG; VSUM_LMUL; LIM_CMUL]);;
+
+let SERIES_NEG = prove
+ (`!x x0 s. (x sums x0) s ==> ((\n. --(x n)) sums (--x0)) s`,
+  SIMP_TAC[sums; FINITE_INTER_NUMSEG; VSUM_NEG; LIM_NEG]);;
+
+let SUMS_IFF = prove
+ (`!f g k. (!x. x IN k ==> f x = g x) ==> ((f sums l) k <=> (g sums l) k)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[sums] THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
+  MATCH_MP_TAC VSUM_EQ THEN ASM_SIMP_TAC[IN_INTER]);;
+
+let SUMS_EQ = prove
+ (`!f g k. (!x. x IN k ==> f x = g x) /\ (f sums l) k ==> (g sums l) k`,
+  MESON_TAC[SUMS_IFF]);;
+
+let SUMS_0 = prove
+ (`!f:num->real^N s. (!n. n IN s ==> f n = vec 0) ==> (f sums vec 0) s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUMS_EQ THEN
+  EXISTS_TAC `\n:num. vec 0:real^N` THEN ASM_SIMP_TAC[SERIES_0]);;
+
+let SERIES_FINITE_SUPPORT = prove
+ (`!f:num->real^N s k.
+     FINITE (s INTER k) /\ (!x. ~(x IN s INTER k) ==> f x = vec 0)
+     ==> (f sums vsum (s INTER k) f) k`,
+  REWRITE_TAC[sums; LIM_SEQUENTIALLY] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `\x:num. x` o MATCH_MP UPPER_BOUND_FINITE_SET) THEN
+  REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+  STRIP_TAC THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `vsum (k INTER (0..n)) (f:num->real^N) = vsum(s INTER k) f`
+   (fun th -> ASM_REWRITE_TAC[DIST_REFL; th]) THEN
+  MATCH_MP_TAC VSUM_SUPERSET THEN
+  ASM_SIMP_TAC[SUBSET; IN_INTER; IN_NUMSEG; LE_0] THEN
+  ASM_MESON_TAC[IN_INTER; LE_TRANS]);;
+
+let SERIES_COMPONENT = prove
+ (`!f s l:real^N k. (f sums l) s /\ 1 <= k /\ k <= dimindex(:N)
+                    ==> ((\i. lift(f(i)$k)) sums lift(l$k)) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[sums] THEN STRIP_TAC THEN
+  ONCE_REWRITE_TAC[GSYM o_DEF] THEN
+  ASM_SIMP_TAC[GSYM LIFT_SUM; GSYM VSUM_COMPONENT;
+               FINITE_INTER; FINITE_NUMSEG] THEN
+  ASM_SIMP_TAC[o_DEF; LIM_COMPONENT]);;
+
+let SERIES_DIFFS = prove
+ (`!f:num->real^N k.
+        (f --> vec 0) sequentially
+        ==> ((\n. f(n) - f(n + 1)) sums f(k)) (from k)`,
+  REWRITE_TAC[sums; FROM_INTER_NUMSEG; VSUM_DIFFS] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC LIM_TRANSFORM_EVENTUALLY THEN
+  EXISTS_TAC `\n. (f:num->real^N) k - f(n + 1)` THEN CONJ_TAC THENL
+   [REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN EXISTS_TAC `k:num` THEN
+    SIMP_TAC[];
+    GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_SUB_RZERO] THEN
+    MATCH_MP_TAC LIM_SUB THEN REWRITE_TAC[LIM_CONST] THEN
+    MATCH_MP_TAC SEQ_OFFSET THEN ASM_REWRITE_TAC[]]);;
+
+let SERIES_TRIVIAL = prove
+ (`!f. (f sums vec 0) {}`,
+  REWRITE_TAC[sums; INTER_EMPTY; VSUM_CLAUSES; LIM_CONST]);;
+
+let SERIES_RESTRICT = prove
+ (`!f k l:real^N.
+        ((\n. if n IN k then f(n) else vec 0) sums l) (:num) <=>
+        (f sums l) k`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[sums] THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; INTER_UNIV] THEN GEN_TAC THEN
+  MATCH_MP_TAC(MESON[] `vsum s f = vsum t f /\ vsum t f = vsum t g
+                        ==> vsum s f = vsum t g`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC VSUM_SUPERSET THEN SET_TAC[];
+    MATCH_MP_TAC VSUM_EQ THEN SIMP_TAC[IN_INTER]]);;
+
+let SERIES_VSUM = prove
+ (`!f l k s. FINITE s /\ s SUBSET k /\ (!x. ~(x IN s) ==> f x = vec 0) /\
+             vsum s f = l ==> (f sums l) k`,
+  REPEAT STRIP_TAC THEN EXPAND_TAC "l" THEN
+  SUBGOAL_THEN `s INTER k = s:num->bool` ASSUME_TAC THENL
+   [ASM SET_TAC []; ASM_MESON_TAC [SERIES_FINITE_SUPPORT]]);;
+
+let SUMS_REINDEX = prove
+ (`!k a l n. ((\x. a(x + k)) sums l) (from n) <=> (a sums l) (from(n + k))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[sums; FROM_INTER_NUMSEG] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM VSUM_OFFSET] THEN
+  REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+  ASM_MESON_TAC[ARITH_RULE `N + k:num <= n ==> n = (n - k) + k /\ N <= n - k`;
+                ARITH_RULE `N + k:num <= n ==> N <= n + k`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Similar combining theorems just for summability.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let SUMMABLE_LINEAR = prove
+ (`!f h s. summable s f /\ linear h ==> summable s (\n. h(f n))`,
+  REWRITE_TAC[summable] THEN MESON_TAC[SERIES_LINEAR]);;
+
+let SUMMABLE_0 = prove
+ (`!s. summable s (\n. vec 0)`,
+  REWRITE_TAC[summable] THEN MESON_TAC[SERIES_0]);;
+
+let SUMMABLE_ADD = prove
+ (`!x y s. summable s x /\ summable s y ==> summable s (\n. x n + y n)`,
+  REWRITE_TAC[summable] THEN MESON_TAC[SERIES_ADD]);;
+
+let SUMMABLE_SUB = prove
+ (`!x y s. summable s x /\ summable s y ==> summable s (\n. x n - y n)`,
+  REWRITE_TAC[summable] THEN MESON_TAC[SERIES_SUB]);;
+
+let SUMMABLE_CMUL = prove
+ (`!s x c. summable s x ==> summable s (\n. c % x n)`,
+  REWRITE_TAC[summable] THEN MESON_TAC[SERIES_CMUL]);;
+
+let SUMMABLE_NEG = prove
+ (`!x s. summable s x ==> summable s (\n. --(x n))`,
+  REWRITE_TAC[summable] THEN MESON_TAC[SERIES_NEG]);;
+
+let SUMMABLE_IFF = prove
+ (`!f g k. (!x. x IN k ==> f x = g x) ==> (summable k f <=> summable k g)`,
+  REWRITE_TAC[summable] THEN MESON_TAC[SUMS_IFF]);;
+
+let SUMMABLE_EQ = prove
+ (`!f g k. (!x. x IN k ==> f x = g x) /\ summable k f ==> summable k g`,
+  REWRITE_TAC[summable] THEN MESON_TAC[SUMS_EQ]);;
+
+let SUMMABLE_COMPONENT = prove
+ (`!f:num->real^N s k.
+        summable s f /\ 1 <= k /\ k <= dimindex(:N)
+        ==> summable s (\i. lift(f(i)$k))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(X_CHOOSE_TAC `l:real^N` o REWRITE_RULE[summable]) THEN
+  REWRITE_TAC[summable] THEN EXISTS_TAC `lift((l:real^N)$k)` THEN
+  ASM_SIMP_TAC[SERIES_COMPONENT]);;
+
+let SERIES_SUBSET = prove
+ (`!x s t l.
+        s SUBSET t /\
+        ((\i. if i IN s then x i else vec 0) sums l) t
+        ==> (x sums l) s`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[sums] THEN MATCH_MP_TAC EQ_IMP THEN
+  AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
+  ASM_SIMP_TAC[GSYM VSUM_RESTRICT_SET; FINITE_INTER_NUMSEG] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN POP_ASSUM MP_TAC THEN SET_TAC[]);;
+
+let SUMMABLE_SUBSET = prove
+ (`!x s t.
+        s SUBSET t /\
+        summable t (\i. if i IN s then x i else vec 0)
+        ==> summable s x`,
+  REWRITE_TAC[summable] THEN MESON_TAC[SERIES_SUBSET]);;
+
+let SUMMABLE_TRIVIAL = prove
+ (`!f:num->real^N. summable {} f`,
+  GEN_TAC THEN REWRITE_TAC[summable] THEN EXISTS_TAC `vec 0:real^N` THEN
+  REWRITE_TAC[SERIES_TRIVIAL]);;
+
+let SUMMABLE_RESTRICT = prove
+ (`!f:num->real^N k.
+        summable (:num) (\n. if n IN k then f(n) else vec 0) <=>
+        summable k f`,
+  REWRITE_TAC[summable; SERIES_RESTRICT]);;
+
+let SUMS_FINITE_DIFF = prove
+ (`!f:num->real^N t s l.
+        t SUBSET s /\ FINITE t /\ (f sums l) s
+        ==> (f sums (l - vsum t f)) (s DIFF t)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `f:num->real^N` o MATCH_MP SERIES_FINITE) THEN
+  ONCE_REWRITE_TAC[GSYM SERIES_RESTRICT] THEN
+  REWRITE_TAC[IMP_IMP] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SERIES_SUB) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `x:num` THEN REWRITE_TAC[IN_DIFF] THEN
+  FIRST_ASSUM(MP_TAC o SPEC `x:num` o GEN_REWRITE_RULE I [SUBSET]) THEN
+  MAP_EVERY ASM_CASES_TAC [`(x:num) IN s`; `(x:num) IN t`] THEN
+  ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC);;
+
+let SUMS_FINITE_UNION = prove
+ (`!f:num->real^N s t l.
+        FINITE t /\ (f sums l) s
+        ==> (f sums (l + vsum (t DIFF s) f)) (s UNION t)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  FIRST_ASSUM(MP_TAC o SPEC `s:num->bool` o MATCH_MP FINITE_DIFF) THEN
+  DISCH_THEN(MP_TAC o ISPEC `f:num->real^N` o MATCH_MP SERIES_FINITE) THEN
+  ONCE_REWRITE_TAC[GSYM SERIES_RESTRICT] THEN
+  REWRITE_TAC[IMP_IMP] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SERIES_ADD) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `x:num` THEN
+  REWRITE_TAC[IN_DIFF; IN_UNION] THEN
+  MAP_EVERY ASM_CASES_TAC [`(x:num) IN s`; `(x:num) IN t`] THEN
+  ASM_REWRITE_TAC[] THEN VECTOR_ARITH_TAC);;
+
+let SUMS_OFFSET = prove
+ (`!f:num->real^N l m n.
+        (f sums l) (from m) /\ m < n
+        ==> (f sums (l - vsum(m..(n-1)) f)) (from n)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `from n = from m DIFF (m..(n-1))` SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_FROM; IN_DIFF; IN_NUMSEG] THEN ASM_ARITH_TAC;
+    MATCH_MP_TAC SUMS_FINITE_DIFF THEN ASM_REWRITE_TAC[FINITE_NUMSEG] THEN
+    SIMP_TAC[SUBSET; IN_FROM; IN_NUMSEG]]);;
+
+let SUMS_OFFSET_REV = prove
+ (`!f:num->real^N l m n.
+        (f sums l) (from m) /\ n < m
+        ==> (f sums (l + vsum(n..m-1) f)) (from n)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:num->real^N`; `from m`; `n..m-1`; `l:real^N`]
+                SUMS_FINITE_UNION) THEN
+  ASM_REWRITE_TAC[FINITE_NUMSEG] THEN MATCH_MP_TAC EQ_IMP THEN
+  BINOP_TAC THENL [AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC; ALL_TAC] THEN
+  REWRITE_TAC[EXTENSION; IN_DIFF; IN_UNION; IN_FROM; IN_NUMSEG] THEN
+  ASM_ARITH_TAC);;
+
+let SUMMABLE_REINDEX = prove
+ (`!k a n. summable (from n) (\x. a (x + k)) <=> summable (from(n + k)) a`,
+  REWRITE_TAC[summable; GSYM SUMS_REINDEX]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Similar combining theorems for infsum.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let INFSUM_LINEAR = prove
+ (`!f h s. summable s f /\ linear h
+           ==> infsum s (\n. h(f n)) = h(infsum s f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INFSUM_UNIQUE THEN
+  MATCH_MP_TAC SERIES_LINEAR THEN ASM_REWRITE_TAC[SUMS_INFSUM]);;
+
+let INFSUM_0 = prove
+ (`infsum s (\i. vec 0) = vec 0`,
+  MATCH_MP_TAC INFSUM_UNIQUE THEN REWRITE_TAC[SERIES_0]);;
+
+let INFSUM_ADD = prove
+ (`!x y s. summable s x /\ summable s y
+           ==> infsum s (\i. x i + y i) = infsum s x + infsum s y`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INFSUM_UNIQUE THEN
+  MATCH_MP_TAC SERIES_ADD THEN ASM_REWRITE_TAC[SUMS_INFSUM]);;
+
+let INFSUM_SUB = prove
+ (`!x y s. summable s x /\ summable s y
+           ==> infsum s (\i. x i - y i) = infsum s x - infsum s y`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INFSUM_UNIQUE THEN
+  MATCH_MP_TAC SERIES_SUB THEN ASM_REWRITE_TAC[SUMS_INFSUM]);;
+
+let INFSUM_CMUL = prove
+ (`!s x c. summable s x ==> infsum s (\n. c % x n) = c % infsum s x`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INFSUM_UNIQUE THEN
+  MATCH_MP_TAC SERIES_CMUL THEN ASM_REWRITE_TAC[SUMS_INFSUM]);;
+
+let INFSUM_NEG = prove
+ (`!s x. summable s x ==> infsum s (\n. --(x n)) = --(infsum s x)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INFSUM_UNIQUE THEN
+  MATCH_MP_TAC SERIES_NEG THEN ASM_REWRITE_TAC[SUMS_INFSUM]);;
+
+let INFSUM_EQ = prove
+ (`!f g k. summable k f /\ summable k g /\ (!x. x IN k ==> f x = g x)
+           ==> infsum k f = infsum k g`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[infsum] THEN
+  AP_TERM_TAC THEN ABS_TAC THEN ASM_MESON_TAC[SUMS_EQ; SUMS_INFSUM]);;
+
+let INFSUM_RESTRICT = prove
+ (`!k a:num->real^N.
+        infsum (:num) (\n. if n IN k then a n else vec 0) = infsum k a`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`a:num->real^N`; `k:num->bool`] SUMMABLE_RESTRICT) THEN
+  ASM_CASES_TAC `summable k (a:num->real^N)` THEN ASM_REWRITE_TAC[] THEN
+  STRIP_TAC THENL
+   [MATCH_MP_TAC INFSUM_UNIQUE THEN
+    ASM_REWRITE_TAC[SERIES_RESTRICT; SUMS_INFSUM];
+    RULE_ASSUM_TAC(REWRITE_RULE[summable; NOT_EXISTS_THM]) THEN
+    ASM_REWRITE_TAC[infsum]]);;
+
+let PARTIAL_SUMS_COMPONENT_LE_INFSUM = prove
+ (`!f:num->real^N s k n.
+        1 <= k /\ k <= dimindex(:N) /\
+        (!i. i IN s ==> &0 <= (f i)$k) /\
+        summable s f
+        ==> (vsum (s INTER (0..n)) f)$k <= (infsum s f)$k`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM SUMS_INFSUM] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[sums; LIM_SEQUENTIALLY] THEN DISCH_TAC THEN
+  REWRITE_TAC[GSYM REAL_NOT_LT] THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC
+   `vsum (s INTER (0..n)) (f:num->real^N)$k - (infsum s f)$k`) THEN
+  ASM_REWRITE_TAC[REAL_SUB_LT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N:num` (MP_TAC o SPEC `N + n:num`)) THEN
+  REWRITE_TAC[LE_ADD; REAL_NOT_LT; dist] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `abs((vsum (s INTER (0..N + n)) f - infsum s f:real^N)$k)` THEN
+  ASM_SIMP_TAC[COMPONENT_LE_NORM] THEN REWRITE_TAC[VECTOR_SUB_COMPONENT] THEN
+  MATCH_MP_TAC(REAL_ARITH `s < a /\ a <= b ==> a - s <= abs(b - s)`) THEN
+  ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[ADD_SYM] THEN
+  SIMP_TAC[NUMSEG_ADD_SPLIT; LE_0; UNION_OVER_INTER] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) VSUM_UNION o lhand o rand o snd) THEN
+  ANTS_TAC THENL
+   [SIMP_TAC[FINITE_INTER; FINITE_NUMSEG; DISJOINT; EXTENSION] THEN
+    REWRITE_TAC[IN_INTER; NOT_IN_EMPTY; IN_NUMSEG] THEN ARITH_TAC;
+    DISCH_THEN SUBST1_TAC THEN
+    REWRITE_TAC[REAL_LE_ADDR; VECTOR_ADD_COMPONENT] THEN
+    ASM_SIMP_TAC[VSUM_COMPONENT] THEN MATCH_MP_TAC SUM_POS_LE THEN
+    ASM_SIMP_TAC[FINITE_INTER; IN_INTER; FINITE_NUMSEG]]);;
+
+let PARTIAL_SUMS_DROP_LE_INFSUM = prove
+ (`!f s n.
+        (!i. i IN s ==> &0 <= drop(f i)) /\
+        summable s f
+        ==> drop(vsum (s INTER (0..n)) f) <= drop(infsum s f)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[drop] THEN
+  MATCH_MP_TAC PARTIAL_SUMS_COMPONENT_LE_INFSUM THEN
+  ASM_REWRITE_TAC[DIMINDEX_1; LE_REFL; GSYM drop]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Cauchy criterion for series.                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let SEQUENCE_CAUCHY_WLOG = prove
+ (`!P s. (!m n:num. P m /\ P n ==> dist(s m,s n) < e) <=>
+         (!m n. P m /\ P n /\ m <= n ==> dist(s m,s n) < e)`,
+  MESON_TAC[DIST_SYM; LE_CASES]);;
+
+let VSUM_DIFF_LEMMA = prove
+ (`!f:num->real^N k m n.
+        m <= n
+        ==> vsum(k INTER (0..n)) f - vsum(k INTER (0..m)) f =
+            vsum(k INTER (m+1..n)) f`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:num->real^N`; `k INTER (0..n)`; `k INTER (0..m)`]
+    VSUM_DIFF) THEN
+  ANTS_TAC THENL
+   [SIMP_TAC[FINITE_INTER; FINITE_NUMSEG] THEN MATCH_MP_TAC
+     (SET_RULE `s SUBSET t ==> (u INTER s SUBSET u INTER t)`) THEN
+    REWRITE_TAC[SUBSET; IN_NUMSEG] THEN POP_ASSUM MP_TAC THEN ARITH_TAC;
+    DISCH_THEN(SUBST1_TAC o SYM) THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    REWRITE_TAC[SET_RULE
+     `(k INTER s) DIFF (k INTER t) = k INTER (s DIFF t)`] THEN
+    AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_DIFF; IN_NUMSEG] THEN
+    POP_ASSUM MP_TAC THEN ARITH_TAC]);;
+
+let NORM_VSUM_TRIVIAL_LEMMA = prove
+ (`!e. &0 < e ==> (P ==> norm(vsum(s INTER (m..n)) f) < e <=>
+                   P ==> n < m \/ norm(vsum(s INTER (m..n)) f) < e)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `n:num < m` THEN ASM_REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o GEN_REWRITE_RULE I [GSYM NUMSEG_EMPTY]) THEN
+  ASM_REWRITE_TAC[VSUM_CLAUSES; NORM_0; INTER_EMPTY]);;
+
+let SERIES_CAUCHY = prove
+ (`!f s. (?l. (f sums l) s) =
+         !e. &0 < e
+             ==> ?N. !m n. m >= N
+                           ==> norm(vsum(s INTER (m..n)) f) < e`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[sums; CONVERGENT_EQ_CAUCHY; cauchy] THEN
+  REWRITE_TAC[SEQUENCE_CAUCHY_WLOG] THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+  SIMP_TAC[dist; VSUM_DIFF_LEMMA; NORM_VSUM_TRIVIAL_LEMMA] THEN
+  REWRITE_TAC[GE; TAUT `a ==> b \/ c <=> a /\ ~b ==> c`] THEN
+  REWRITE_TAC[NOT_LT; ARITH_RULE
+   `(N <= m /\ N <= n /\ m <= n) /\ m + 1 <= n <=>
+    N + 1 <= m + 1 /\ m + 1 <= n`] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `e:real` THEN
+  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
+  EQ_TAC THEN DISCH_THEN(X_CHOOSE_TAC `N:num`) THENL
+   [EXISTS_TAC `N + 1`; EXISTS_TAC `N:num`] THEN
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[ARITH_RULE `N + 1 <= m + 1 ==> N <= m + 1`] THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`m - 1`; `n:num`]) THEN
+  SUBGOAL_THEN `m - 1 + 1 = m` SUBST_ALL_TAC THENL
+   [ALL_TAC; ANTS_TAC THEN SIMP_TAC[]] THEN
+  ASM_ARITH_TAC);;
+
+let SUMMABLE_CAUCHY = prove
+ (`!f s. summable s f <=>
+         !e. &0 < e
+             ==> ?N. !m n. m >= N ==> norm(vsum(s INTER (m..n)) f) < e`,
+  REWRITE_TAC[summable; GSYM SERIES_CAUCHY]);;
+
+let SUMMABLE_IFF_EVENTUALLY = prove
+ (`!f g k. (?N. !n. N <= n /\ n IN k ==> f n = g n)
+           ==> (summable k f <=> summable k g)`,
+  REWRITE_TAC[summable; SERIES_CAUCHY] THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `N0:num` STRIP_ASSUME_TAC) THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `e:real` THEN
+  AP_TERM_TAC THEN EQ_TAC THEN
+  DISCH_THEN(X_CHOOSE_THEN `N1:num`
+   (fun th -> EXISTS_TAC `N0 + N1:num` THEN MP_TAC th)) THEN
+  REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+  (ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC]) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC VSUM_EQ THEN ASM_SIMP_TAC[IN_INTER; IN_NUMSEG] THEN
+  REPEAT STRIP_TAC THENL [ALL_TAC; CONV_TAC SYM_CONV] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+  ASM_ARITH_TAC);;
+
+let SUMMABLE_EQ_EVENTUALLY = prove
+ (`!f g k. (?N. !n. N <= n /\ n IN k ==> f n = g n) /\ summable k f
+           ==> summable k g`,
+  MESON_TAC[SUMMABLE_IFF_EVENTUALLY]);;
+
+let SUMMABLE_IFF_COFINITE = prove
+ (`!f s t. FINITE((s DIFF t) UNION (t DIFF s))
+           ==> (summable s f <=> summable t f)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM SUMMABLE_RESTRICT] THEN
+  MATCH_MP_TAC SUMMABLE_IFF_EVENTUALLY THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `\x:num.x` o MATCH_MP UPPER_BOUND_FINITE_SET) THEN
+  DISCH_THEN(X_CHOOSE_THEN `N:num` MP_TAC) THEN REWRITE_TAC[IN_UNIV] THEN
+  DISCH_TAC THEN EXISTS_TAC `N + 1` THEN
+  REWRITE_TAC[ARITH_RULE `N + 1 <= n <=> ~(n <= N)`] THEN ASM SET_TAC[]);;
+
+let SUMMABLE_EQ_COFINITE = prove
+ (`!f s t. FINITE((s DIFF t) UNION (t DIFF s)) /\ summable s f
+           ==> summable t f`,
+  MESON_TAC[SUMMABLE_IFF_COFINITE]);;
+
+let SUMMABLE_FROM_ELSEWHERE = prove
+ (`!f m n. summable (from m) f ==> summable (from n) f`,
+  REPEAT GEN_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] SUMMABLE_EQ_COFINITE) THEN
+  MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `0..(m+n)` THEN
+  SIMP_TAC[FINITE_NUMSEG; SUBSET; IN_NUMSEG; IN_UNION; IN_DIFF; IN_FROM] THEN
+  ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Uniform vesion of Cauchy criterion.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let SERIES_CAUCHY_UNIFORM = prove
+ (`!P f:A->num->real^N k.
+        (?l. !e. &0 < e
+                 ==> ?N. !n x. N <= n /\ P x
+                               ==> dist(vsum(k INTER (0..n)) (f x),
+                                        l x) < e) <=>
+        (!e. &0 < e ==> ?N. !m n x. N <= m /\ P x
+                                    ==> norm(vsum(k INTER (m..n)) (f x)) < e)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[sums; UNIFORMLY_CONVERGENT_EQ_CAUCHY; cauchy] THEN
+  ONCE_REWRITE_TAC[MESON[]
+   `(!m n:num y. N <= m /\ N <= n /\ P y ==> Q m n y) <=>
+    (!y. P y ==> !m n. N <= m /\ N <= n ==> Q m n y)`] THEN
+  REWRITE_TAC[SEQUENCE_CAUCHY_WLOG] THEN ONCE_REWRITE_TAC[DIST_SYM] THEN
+  SIMP_TAC[dist; VSUM_DIFF_LEMMA; NORM_VSUM_TRIVIAL_LEMMA] THEN
+  REWRITE_TAC[GE; TAUT `a ==> b \/ c <=> a /\ ~b ==> c`] THEN
+  REWRITE_TAC[NOT_LT; ARITH_RULE
+   `(N <= m /\ N <= n /\ m <= n) /\ m + 1 <= n <=>
+    N + 1 <= m + 1 /\ m + 1 <= n`] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `e:real` THEN
+  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
+  EQ_TAC THEN DISCH_THEN(X_CHOOSE_TAC `N:num`) THENL
+   [EXISTS_TAC `N + 1`; EXISTS_TAC `N:num`] THEN
+  REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[ARITH_RULE `N + 1 <= m + 1 ==> N <= m + 1`] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `x:A`) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(MP_TAC o SPECL [`m - 1`; `n:num`]) THEN
+  SUBGOAL_THEN `m - 1 + 1 = m` SUBST_ALL_TAC THENL
+   [ALL_TAC; ANTS_TAC THEN SIMP_TAC[]] THEN
+  ASM_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* So trivially, terms of a convergent series go to zero.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let SERIES_GOESTOZERO = prove
+ (`!s x. summable s x
+         ==> !e. &0 < e
+                 ==> eventually (\n. n IN s ==> norm(x n) < e) sequentially`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[summable; SERIES_CAUCHY] THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN
+  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN DISCH_TAC THEN
+  X_GEN_TAC `n:num` THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`n:num`; `n:num`]) THEN
+  ASM_SIMP_TAC[NUMSEG_SING; GE; SET_RULE `n IN s ==> s INTER {n} = {n}`] THEN
+  REWRITE_TAC[VSUM_SING]);;
+
+let SUMMABLE_IMP_TOZERO = prove
+ (`!f:num->real^N k.
+       summable k f
+       ==> ((\n. if n IN k then f(n) else vec 0) --> vec 0) sequentially`,
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM SUMMABLE_RESTRICT] THEN
+  REWRITE_TAC[summable; LIM_SEQUENTIALLY; INTER_UNIV; sums] THEN
+  DISCH_THEN(X_CHOOSE_TAC `l:real^N`) THEN X_GEN_TAC `e:real` THEN
+  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
+  ASM_REWRITE_TAC[REAL_HALF; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `N:num` THEN DISCH_TAC THEN EXISTS_TAC `N + 1` THEN
+  X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(fun th ->
+    MP_TAC(SPEC `n - 1` th) THEN MP_TAC(SPEC `n:num` th)) THEN
+  ASM_SIMP_TAC[ARITH_RULE `N + 1 <= n ==> N <= n /\ N <= n - 1`] THEN
+  ABBREV_TAC `m = n - 1` THEN
+  SUBGOAL_THEN `n = SUC m` SUBST1_TAC THENL
+   [ASM_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[VSUM_CLAUSES_NUMSEG; LE_0] THEN
+  REWRITE_TAC[NORM_ARITH `dist(x,vec 0) = norm x`] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[NORM_0] THEN CONV_TAC NORM_ARITH);;
+
+let SUMMABLE_IMP_BOUNDED = prove
+ (`!f:num->real^N k. summable k f ==> bounded (IMAGE f k)`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP SUMMABLE_IMP_TOZERO) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CONVERGENT_IMP_BOUNDED) THEN
+  REWRITE_TAC[BOUNDED_POS; FORALL_IN_IMAGE; IN_UNIV] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN MESON_TAC[REAL_LT_IMP_LE; NORM_0]);;
+
+let SUMMABLE_IMP_SUMS_BOUNDED = prove
+ (`!f:num->real^N k.
+       summable (from k) f ==> bounded { vsum(k..n) f | n IN (:num) }`,
+  REWRITE_TAC[summable; sums; LEFT_IMP_EXISTS_THM] THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CONVERGENT_IMP_BOUNDED) THEN
+  REWRITE_TAC[FROM_INTER_NUMSEG; SIMPLE_IMAGE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Comparison test.                                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let SERIES_COMPARISON = prove
+ (`!f g s. (?l. ((lift o g) sums l) s) /\
+           (?N. !n. n >= N /\ n IN s ==> norm(f n) <= g n)
+           ==> ?l:real^N. (f sums l) s`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[SERIES_CAUCHY] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (X_CHOOSE_TAC `N1:num`)) THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN
+  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_TAC `N2:num`) THEN
+  EXISTS_TAC `N1 + N2:num` THEN
+  MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `norm (vsum (s INTER (m .. n)) (lift o g))` THEN CONJ_TAC THENL
+   [SIMP_TAC[GSYM LIFT_SUM; FINITE_INTER_NUMSEG; NORM_LIFT] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= a ==> x <= abs(a)`) THEN
+    MATCH_MP_TAC VSUM_NORM_LE THEN
+    REWRITE_TAC[FINITE_INTER_NUMSEG; IN_INTER; IN_NUMSEG] THEN
+    ASM_MESON_TAC[ARITH_RULE `m >= N1 + N2:num /\ m <= x ==> x >= N1`];
+    ASM_MESON_TAC[ARITH_RULE `m >= N1 + N2:num ==> m >= N2`]]);;
+
+let SUMMABLE_COMPARISON = prove
+ (`!f g s. summable s (lift o g) /\
+           (?N. !n. n >= N /\ n IN s ==> norm(f n) <= g n)
+           ==> summable s f`,
+  REWRITE_TAC[summable; SERIES_COMPARISON]);;
+
+let SERIES_LIFT_ABSCONV_IMP_CONV = prove
+ (`!x:num->real^N k. summable k (\n. lift(norm(x n))) ==> summable k x`,
+  REWRITE_TAC[summable] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SERIES_COMPARISON THEN
+  EXISTS_TAC `\n:num. norm(x n:real^N)` THEN
+  ASM_REWRITE_TAC[o_DEF; REAL_LE_REFL] THEN ASM_MESON_TAC[]);;
+
+let SUMMABLE_SUBSET_ABSCONV = prove
+ (`!x:num->real^N s t.
+        summable s (\n. lift(norm(x n))) /\ t SUBSET s
+        ==> summable t (\n. lift(norm(x n)))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUMMABLE_SUBSET THEN
+  EXISTS_TAC `s:num->bool` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[summable] THEN MATCH_MP_TAC SERIES_COMPARISON THEN
+  EXISTS_TAC `\n:num. norm(x n:real^N)` THEN
+  ASM_REWRITE_TAC[o_DEF; GSYM summable] THEN
+  EXISTS_TAC `0` THEN REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  REWRITE_TAC[REAL_LE_REFL; NORM_LIFT; REAL_ABS_NORM; NORM_0; NORM_POS_LE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Uniform version of comparison test.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let SERIES_COMPARISON_UNIFORM = prove
+ (`!f g P s. (?l. ((lift o g) sums l) s) /\
+             (?N. !n x. N <= n /\ n IN s /\ P x ==> norm(f x n) <= g n)
+             ==> ?l:A->real^N.
+                    !e. &0 < e
+                        ==> ?N. !n x. N <= n /\ P x
+                                      ==> dist(vsum(s INTER (0..n)) (f x),
+                                               l x) < e`,
+  REPEAT GEN_TAC THEN SIMP_TAC[GE; SERIES_CAUCHY; SERIES_CAUCHY_UNIFORM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (X_CHOOSE_TAC `N1:num`)) THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `e:real` THEN
+  MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_TAC `N2:num`) THEN
+  EXISTS_TAC `N1 + N2:num` THEN
+  MAP_EVERY X_GEN_TAC [`m:num`; `n:num`; `x:A`] THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `norm (vsum (s INTER (m .. n)) (lift o g))` THEN CONJ_TAC THENL
+   [SIMP_TAC[GSYM LIFT_SUM; FINITE_INTER_NUMSEG; NORM_LIFT] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= a ==> x <= abs(a)`) THEN
+    MATCH_MP_TAC VSUM_NORM_LE THEN
+    REWRITE_TAC[FINITE_INTER_NUMSEG; IN_INTER; IN_NUMSEG] THEN
+    ASM_MESON_TAC[ARITH_RULE `N1 + N2:num <= m /\ m <= x ==> N1 <= x`];
+    ASM_MESON_TAC[ARITH_RULE `N1 + N2:num <= m ==> N2 <= m`]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Ratio test.                                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let SERIES_RATIO = prove
+ (`!c a s N.
+      c < &1 /\
+      (!n. n >= N ==> norm(a(SUC n)) <= c * norm(a(n)))
+      ==> ?l:real^N. (a sums l) s`,
+  REWRITE_TAC[GE] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SERIES_COMPARISON THEN
+  DISJ_CASES_TAC(REAL_ARITH `c <= &0 \/ &0 < c`) THENL
+   [EXISTS_TAC `\n:num. &0` THEN REWRITE_TAC[o_DEF; LIFT_NUM] THEN
+    CONJ_TAC THENL [MESON_TAC[SERIES_0]; ALL_TAC] THEN
+    EXISTS_TAC `N + 1` THEN REWRITE_TAC[GE] THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `c * norm(a(n - 1):real^N)` THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[ARITH_RULE `N + 1 <= n ==> SUC(n - 1) = n /\ N <= n - 1`];
+      ALL_TAC] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= --c * x ==> c * x <= &0`) THEN
+    MATCH_MP_TAC REAL_LE_MUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+    UNDISCH_TAC `c <= &0` THEN REAL_ARITH_TAC;
+    ASSUME_TAC(MATCH_MP REAL_LT_IMP_LE (ASSUME `&0 < c`))] THEN
+  EXISTS_TAC `\n. norm(a(N):real^N) * c pow (n - N)` THEN
+  REWRITE_TAC[] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    EXISTS_TAC `N:num` THEN
+    SIMP_TAC[GE; LE_EXISTS; IMP_CONJ; ADD_SUB2; LEFT_IMP_EXISTS_THM] THEN
+    SUBGOAL_THEN `!d:num. norm(a(N + d):real^N) <= norm(a N) * c pow d`
+     (fun th -> MESON_TAC[th]) THEN INDUCT_TAC THEN
+    REWRITE_TAC[ADD_CLAUSES; real_pow; REAL_MUL_RID; REAL_LE_REFL] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `c * norm((a:num->real^N) (N + d))` THEN
+    ASM_SIMP_TAC[LE_ADD] THEN ASM_MESON_TAC[REAL_LE_LMUL; REAL_MUL_AC]] THEN
+  GEN_REWRITE_TAC I [SERIES_CAUCHY] THEN X_GEN_TAC `e:real` THEN
+  SIMP_TAC[GSYM LIFT_SUM; FINITE_INTER; NORM_LIFT; FINITE_NUMSEG] THEN
+  DISCH_TAC THEN SIMP_TAC[SUM_LMUL; FINITE_INTER; FINITE_NUMSEG] THEN
+  ASM_CASES_TAC `(a:num->real^N) N = vec 0` THENL
+   [ASM_REWRITE_TAC[NORM_0; REAL_MUL_LZERO; REAL_ABS_NUM]; ALL_TAC] THEN
+  MP_TAC(SPECL [`c:real`; `((&1 - c) * e) / norm((a:num->real^N) N)`]
+               REAL_ARCH_POW_INV) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_LT_MUL; REAL_SUB_LT; NORM_POS_LT; GE] THEN
+  DISCH_THEN(X_CHOOSE_TAC `M:num`) THEN EXISTS_TAC `N + M:num` THEN
+  MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN DISCH_TAC THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `abs(norm((a:num->real^N) N) *
+                  sum(m..n) (\i. c pow (i - N)))` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[REAL_ABS_MUL] THEN MATCH_MP_TAC REAL_LE_LMUL THEN
+    REWRITE_TAC[REAL_ABS_POS] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ x <= y ==> abs x <= abs y`) THEN
+    ASM_SIMP_TAC[SUM_POS_LE; FINITE_INTER_NUMSEG; REAL_POW_LE] THEN
+    MATCH_MP_TAC SUM_SUBSET THEN ASM_SIMP_TAC[REAL_POW_LE] THEN
+    REWRITE_TAC[FINITE_INTER_NUMSEG; FINITE_NUMSEG] THEN
+    REWRITE_TAC[IN_INTER; IN_DIFF] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_NORM] THEN
+  DISJ_CASES_TAC(ARITH_RULE `n:num < m \/ m <= n`) THENL
+   [ASM_SIMP_TAC[SUM_TRIV_NUMSEG; REAL_ABS_NUM; REAL_MUL_RZERO]; ALL_TAC] THEN
+  SUBGOAL_THEN `m = 0 + m /\ n = (n - m) + m` (CONJUNCTS_THEN SUBST1_TAC) THENL
+   [UNDISCH_TAC `m:num <= n` THEN ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[SUM_OFFSET] THEN UNDISCH_TAC `N + M:num <= m` THEN
+  SIMP_TAC[LE_EXISTS] THEN DISCH_THEN(X_CHOOSE_THEN `d:num` SUBST_ALL_TAC) THEN
+  REWRITE_TAC[ARITH_RULE `(i + (N + M) + d) - N:num = (M + d) + i`] THEN
+  ONCE_REWRITE_TAC[REAL_POW_ADD] THEN REWRITE_TAC[SUM_LMUL; SUM_GP] THEN
+  ASM_SIMP_TAC[LT; REAL_LT_IMP_NE] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; NORM_POS_LT; REAL_ABS_MUL] THEN
+  REWRITE_TAC[REAL_ABS_POW] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_ABS_DIV; REAL_POW_LT; REAL_ARITH
+   `&0 < c /\ c < &1 ==> &0 < abs c /\ &0 < abs(&1 - c)`; REAL_LT_LDIV_EQ] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `&0 < x /\ x <= &1 /\ &1 <= e ==> abs(c pow 0 - x) < e`) THEN
+  ASM_SIMP_TAC[REAL_POW_LT; REAL_POW_1_LE; REAL_LT_IMP_LE] THEN
+  ASM_SIMP_TAC[REAL_ARITH `c < &1 ==> x * abs(&1 - c) = (&1 - c) * x`] THEN
+  REWRITE_TAC[real_div; REAL_INV_MUL; REAL_POW_ADD; REAL_MUL_ASSOC] THEN
+  REWRITE_TAC[REAL_ARITH
+   `(((a * b) * c) * d) * e = (e * ((a * b) * c)) * d`] THEN
+  ASM_SIMP_TAC[GSYM real_div; REAL_LE_RDIV_EQ; REAL_POW_LT; REAL_MUL_LID;
+               REAL_ARITH `&0 < c ==> abs c = c`] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+   `xm < e ==> &0 <= (d - &1) * e ==> xm <= d * e`)) THEN
+  MATCH_MP_TAC REAL_LE_MUL THEN CONJ_TAC THENL
+   [REWRITE_TAC[REAL_SUB_LE; GSYM REAL_POW_INV] THEN
+    MATCH_MP_TAC REAL_POW_LE_1 THEN
+    MATCH_MP_TAC REAL_INV_1_LE THEN ASM_SIMP_TAC[REAL_LT_IMP_LE];
+    MATCH_MP_TAC REAL_LT_IMP_LE THEN
+    ASM_SIMP_TAC[REAL_SUB_LT; REAL_LT_MUL; REAL_LT_DIV; NORM_POS_LT]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Ostensibly weaker versions of the boundedness of partial sums.            *)
+(* ------------------------------------------------------------------------- *)
+
+let BOUNDED_PARTIAL_SUMS = prove
+ (`!f:num->real^N k.
+        bounded { vsum(k..n) f | n IN (:num) }
+        ==> bounded { vsum(m..n) f | m IN (:num) /\ n IN (:num) }`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `bounded { vsum(0..n) f:real^N | n IN (:num) }` MP_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [BOUNDED_POS]) THEN
+    REWRITE_TAC[bounded] THEN
+    REWRITE_TAC[SIMPLE_IMAGE; FORALL_IN_IMAGE; IN_UNIV] THEN
+    DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `sum { i:num | i < k} (\i. norm(f i:real^N)) + B` THEN
+    X_GEN_TAC `i:num` THEN ASM_CASES_TAC `i:num < k` THENL
+     [MATCH_MP_TAC(REAL_ARITH
+       `!y. x <= y /\ y <= a /\ &0 < b ==> x <= a + b`) THEN
+      EXISTS_TAC `sum (0..i) (\i. norm(f i:real^N))` THEN
+      ASM_SIMP_TAC[VSUM_NORM; FINITE_NUMSEG] THEN
+      MATCH_MP_TAC SUM_SUBSET THEN
+      REWRITE_TAC[FINITE_NUMSEG; FINITE_NUMSEG_LT; NORM_POS_LE] THEN
+      REWRITE_TAC[IN_DIFF; IN_NUMSEG; IN_ELIM_THM] THEN ASM_ARITH_TAC;
+      ALL_TAC] THEN
+    ASM_CASES_TAC `k = 0` THENL
+     [FIRST_X_ASSUM SUBST_ALL_TAC THEN MATCH_MP_TAC(REAL_ARITH
+       `x <= B /\ &0 <= b ==> x <= b + B`) THEN
+      ASM_SIMP_TAC[SUM_POS_LE; FINITE_NUMSEG_LT; NORM_POS_LE];
+      ALL_TAC] THEN
+    MP_TAC(ISPECL [`f:num->real^N`; `0`; `k:num`; `i:num`]
+      VSUM_COMBINE_L) THEN
+    ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[NUMSEG_LT] THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `norm(x) <= a /\ norm(y) <= b ==> norm(x + y) <= a + b`) THEN
+    ASM_SIMP_TAC[VSUM_NORM; FINITE_NUMSEG];
+    ALL_TAC] THEN
+  DISCH_THEN(fun th ->
+    MP_TAC(MATCH_MP BOUNDED_DIFFS (W CONJ th)) THEN MP_TAC th) THEN
+  REWRITE_TAC[IMP_IMP; GSYM BOUNDED_UNION] THEN
+  MATCH_MP_TAC(REWRITE_RULE[TAUT `a /\ b ==> c <=> b ==> a ==> c`]
+        BOUNDED_SUBSET) THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_UNION; LEFT_IMP_EXISTS_THM; IN_UNIV] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `m:num`; `n:num`] THEN
+  DISCH_THEN SUBST1_TAC THEN
+  ASM_CASES_TAC `m = 0` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  ASM_CASES_TAC `n:num < m` THENL
+   [DISJ2_TAC THEN REPEAT(EXISTS_TAC `vsum(0..0) (f:num->real^N)`) THEN
+    ASM_SIMP_TAC[VSUM_TRIV_NUMSEG; VECTOR_SUB_REFL] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  DISJ2_TAC THEN MAP_EVERY EXISTS_TAC
+   [`vsum(0..n) (f:num->real^N)`; `vsum(0..(m-1)) (f:num->real^N)`] THEN
+  CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`f:num->real^N`; `0`; `m:num`; `n:num`]
+      VSUM_COMBINE_L) THEN
+  ANTS_TAC THENL [ASM_ARITH_TAC; VECTOR_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* General Dirichlet convergence test (could make this uniform on a set).    *)
+(* ------------------------------------------------------------------------- *)
+
+let SUMMABLE_BILINEAR_PARTIAL_PRE = prove
+ (`!f g h:real^M->real^N->real^P l k.
+        bilinear h /\
+        ((\n. h (f(n + 1)) (g(n))) --> l) sequentially /\
+        summable (from k) (\n. h (f(n + 1) - f(n)) (g(n)))
+        ==> summable (from k) (\n. h (f n) (g(n) - g(n - 1)))`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[summable; sums; FROM_INTER_NUMSEG] THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  FIRST_ASSUM(fun th ->
+   REWRITE_TAC[MATCH_MP BILINEAR_VSUM_PARTIAL_PRE th]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `l':real^P`) THEN
+  EXISTS_TAC `l - (h:real^M->real^N->real^P) (f k) (g(k - 1)) - l'` THEN
+  REWRITE_TAC[LIM_CASES_SEQUENTIALLY] THEN
+  REPEAT(MATCH_MP_TAC LIM_SUB THEN ASM_REWRITE_TAC[LIM_CONST]));;
+
+let SERIES_DIRICHLET_BILINEAR = prove
+ (`!f g h:real^M->real^N->real^P k m p l.
+        bilinear h /\
+        bounded { vsum (m..n) f | n IN (:num)} /\
+        summable (from p) (\n. lift(norm(g(n + 1) - g(n)))) /\
+        ((\n. h (g(n + 1)) (vsum(1..n) f)) --> l) sequentially
+        ==> summable (from k) (\n. h (g n) (f n))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUMMABLE_FROM_ELSEWHERE THEN
+  EXISTS_TAC `1` THEN
+  FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP BOUNDED_PARTIAL_SUMS) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [BOUNDED_POS]) THEN
+  SIMP_TAC[IN_ELIM_THM; IN_UNIV; LEFT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[MESON[] `(!x a b. x = f a b ==> p a b) <=> (!a b. p a b)`] THEN
+  X_GEN_TAC `B:real` THEN STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP BILINEAR_BOUNDED_POS) THEN
+  DISCH_THEN(X_CHOOSE_THEN `C:real` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC SUMMABLE_EQ THEN
+  EXISTS_TAC `\n. (h:real^M->real^N->real^P)
+                  (g n) (vsum (1..n) f - vsum (1..n-1) f)` THEN
+  SIMP_TAC[IN_FROM; GSYM NUMSEG_RREC] THEN
+  SIMP_TAC[VSUM_CLAUSES; FINITE_NUMSEG; IN_NUMSEG;
+           ARITH_RULE `1 <= n ==> ~(n <= n - 1)`] THEN
+  CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN ASM_SIMP_TAC[BILINEAR_RADD; BILINEAR_RSUB] THEN
+    VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC SUMMABLE_FROM_ELSEWHERE THEN EXISTS_TAC `p:num` THEN
+  MP_TAC(ISPECL [`g:num->real^M`; `\n. vsum(1..n) f:real^N`;
+                 `h:real^M->real^N->real^P`; `l:real^P`; `p:num`]
+         SUMMABLE_BILINEAR_PARTIAL_PRE) THEN
+  REWRITE_TAC[] THEN DISCH_THEN MATCH_MP_TAC THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+    `summable (from p) (lift o (\n. C * B * norm(g(n + 1) - g(n):real^M)))`
+  MP_TAC THENL [ASM_SIMP_TAC[o_DEF; LIFT_CMUL; SUMMABLE_CMUL]; ALL_TAC] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] SUMMABLE_COMPARISON) THEN
+  EXISTS_TAC `0` THEN REWRITE_TAC[IN_FROM; GE; LE_0] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+   `C * norm(g(n + 1) - g(n):real^M) * norm(vsum (1..n) f:real^N)` THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL_EQ] THEN
+  GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL; NORM_POS_LE]);;
+
+let SERIES_DIRICHLET = prove
+ (`!f:num->real^N g N k m.
+        bounded { vsum (m..n) f | n IN (:num)} /\
+        (!n. N <= n ==> g(n + 1) <= g(n)) /\
+        ((lift o g) --> vec 0) sequentially
+        ==> summable (from k) (\n. g(n) % f(n))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:num->real^N`; `lift o (g:num->real)`;
+                 `\x y:real^N. drop x % y`] SERIES_DIRICHLET_BILINEAR) THEN
+  REWRITE_TAC[o_THM; LIFT_DROP] THEN DISCH_THEN MATCH_MP_TAC THEN
+  MAP_EVERY EXISTS_TAC [`m:num`; `N:num`; `vec 0:real^N`] THEN CONJ_TAC THENL
+   [REWRITE_TAC[bilinear; linear; DROP_ADD; DROP_CMUL] THEN
+    REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[GSYM LIFT_SUB; NORM_LIFT] THEN
+  FIRST_ASSUM(MP_TAC o SPEC `1` o MATCH_MP SEQ_OFFSET) THEN
+  REWRITE_TAC[o_THM] THEN DISCH_TAC THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SUMMABLE_EQ_EVENTUALLY THEN
+    EXISTS_TAC `\n. lift(g(n) - g(n + 1))` THEN REWRITE_TAC[] THEN
+    CONJ_TAC THENL
+     [ASM_MESON_TAC[REAL_ARITH `b <= a ==> abs(b - a) = a - b`];
+      REWRITE_TAC[summable; sums; FROM_INTER_NUMSEG; VSUM_DIFFS; LIFT_SUB] THEN
+      REWRITE_TAC[LIM_CASES_SEQUENTIALLY] THEN
+      EXISTS_TAC `lift(g(N:num)) - vec 0` THEN
+      MATCH_MP_TAC LIM_SUB THEN ASM_REWRITE_TAC[LIM_CONST]];
+    MATCH_MP_TAC LIM_NULL_VMUL_BOUNDED THEN ASM_REWRITE_TAC[o_DEF] THEN
+    REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+    FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP BOUNDED_PARTIAL_SUMS) THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [BOUNDED_POS]) THEN
+    SIMP_TAC[IN_ELIM_THM; IN_UNIV] THEN MESON_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Rearranging absolutely convergent series.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let SERIES_INJECTIVE_IMAGE_STRONG = prove
+ (`!x:num->real^N s f.
+        summable (IMAGE f s) (\n. lift(norm(x n))) /\
+        (!m n. m IN s /\ n IN s /\ f m = f n ==> m = n)
+        ==> ((\n. vsum (IMAGE f s INTER (0..n)) x -
+                  vsum (s INTER (0..n)) (x o f)) --> vec 0)
+            sequentially`,
+  let lemma = prove
+   (`!f:A->real^N s t.
+          FINITE s /\ FINITE t
+          ==> vsum s f - vsum t f = vsum (s DIFF t) f - vsum (t DIFF s) f`,
+    REPEAT STRIP_TAC THEN
+    ONCE_REWRITE_TAC[SET_RULE `s DIFF t = s DIFF (s INTER t)`] THEN
+    ASM_SIMP_TAC[VSUM_DIFF; INTER_SUBSET] THEN
+    REWRITE_TAC[INTER_COMM] THEN VECTOR_ARITH_TAC) in
+  REPEAT STRIP_TAC THEN REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SUMMABLE_CAUCHY]) THEN
+  SIMP_TAC[VSUM_REAL; FINITE_INTER; FINITE_NUMSEG] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [o_DEF] THEN
+  REWRITE_TAC[NORM_LIFT; LIFT_DROP] THEN
+  SIMP_TAC[real_abs; SUM_POS_LE; NORM_POS_LE; FINITE_INTER; FINITE_NUMSEG] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
+  ASM_REWRITE_TAC[dist; GE; VECTOR_SUB_RZERO; REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N:num` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INJECTIVE_ON_LEFT_INVERSE]) THEN
+  DISCH_THEN(X_CHOOSE_TAC `g:num->num`) THEN
+  MP_TAC(ISPECL [`g:num->num`; `0..N`] UPPER_BOUND_FINITE_SET) THEN
+  REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG; LE_0] THEN
+  DISCH_THEN(X_CHOOSE_TAC `P:num`) THEN
+  EXISTS_TAC `MAX N P` THEN X_GEN_TAC `n:num` THEN
+  SIMP_TAC[ARITH_RULE `MAX a b <= c <=> a <= c /\ b <= c`] THEN DISCH_TAC THEN
+  W(MP_TAC o PART_MATCH (rand o rand) VSUM_IMAGE o rand o
+    rand o lhand o snd) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[FINITE_INTER; FINITE_NUMSEG; IN_INTER];
+    DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) lemma o rand o lhand o snd) THEN
+  SIMP_TAC[FINITE_INTER; FINITE_IMAGE; FINITE_NUMSEG] THEN
+  DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC(NORM_ARITH
+   `norm a < e / &2 /\ norm b < e / &2 ==> norm(a - b:real^N) < e`) THEN
+  CONJ_TAC THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) VSUM_NORM o lhand o snd) THEN
+  SIMP_TAC[FINITE_DIFF; FINITE_IMAGE; FINITE_INTER; FINITE_NUMSEG] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LET_TRANS) THEN
+  MATCH_MP_TAC REAL_LET_TRANS THENL
+   [EXISTS_TAC
+     `sum(IMAGE (f:num->num) s INTER (N..n)) (\i. norm(x i :real^N))` THEN
+    ASM_SIMP_TAC[LE_REFL] THEN MATCH_MP_TAC SUM_SUBSET_SIMPLE THEN
+    SIMP_TAC[NORM_POS_LE; FINITE_INTER; FINITE_NUMSEG] THEN
+    MATCH_MP_TAC(SET_RULE
+     `(!x. x IN s /\ f(x) IN n /\ ~(x IN m) ==> f x IN t)
+      ==> (IMAGE f s INTER n) DIFF (IMAGE f (s INTER m)) SUBSET
+          IMAGE f s INTER t`) THEN
+    ASM_SIMP_TAC[IN_NUMSEG; LE_0; NOT_LE] THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+    MATCH_MP_TAC LT_IMP_LE THEN ONCE_REWRITE_TAC[GSYM NOT_LE] THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE BINDER_CONV
+     [GSYM CONTRAPOS_THM]) THEN
+    ASM_SIMP_TAC[] THEN ASM_ARITH_TAC;
+    MP_TAC(ISPECL [`f:num->num`; `0..n`] UPPER_BOUND_FINITE_SET) THEN
+    REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG; LE_0] THEN
+    DISCH_THEN(X_CHOOSE_TAC `p:num`) THEN
+    EXISTS_TAC
+     `sum(IMAGE (f:num->num) s INTER (N..p)) (\i. norm(x i :real^N))` THEN
+    ASM_SIMP_TAC[LE_REFL] THEN MATCH_MP_TAC SUM_SUBSET_SIMPLE THEN
+    SIMP_TAC[NORM_POS_LE; FINITE_INTER; FINITE_NUMSEG] THEN
+    MATCH_MP_TAC(SET_RULE
+     `(!x. x IN s /\ x IN n /\ ~(f x IN m) ==> f x IN t)
+      ==> (IMAGE f (s INTER n) DIFF (IMAGE f s) INTER m) SUBSET
+          (IMAGE f s INTER t)`) THEN
+    ASM_SIMP_TAC[IN_NUMSEG; LE_0] THEN ASM_ARITH_TAC]);;
+
+let SERIES_INJECTIVE_IMAGE = prove
+ (`!x:num->real^N s f l.
+        summable (IMAGE f s) (\n. lift(norm(x n))) /\
+        (!m n. m IN s /\ n IN s /\ f m = f n ==> m = n)
+        ==> (((x o f) sums l) s <=> (x sums l) (IMAGE f s))`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN REWRITE_TAC[sums] THEN
+  MATCH_MP_TAC LIM_TRANSFORM_EQ THEN REWRITE_TAC[] THEN
+  MATCH_MP_TAC SERIES_INJECTIVE_IMAGE_STRONG THEN
+  ASM_REWRITE_TAC[]);;
+
+let SERIES_REARRANGE_EQ = prove
+ (`!x:num->real^N s p l.
+        summable s (\n. lift(norm(x n))) /\ p permutes s
+        ==> (((x o p) sums l) s <=> (x sums l) s)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`x:num->real^N`; `s:num->bool`; `p:num->num`; `l:real^N`]
+        SERIES_INJECTIVE_IMAGE) THEN
+  ASM_SIMP_TAC[PERMUTES_IMAGE] THEN
+  ASM_MESON_TAC[PERMUTES_INJECTIVE]);;
+
+let SERIES_REARRANGE = prove
+ (`!x:num->real^N s p l.
+        summable s (\n. lift(norm(x n))) /\ p permutes s /\ (x sums l) s
+        ==> ((x o p) sums l) s`,
+  MESON_TAC[SERIES_REARRANGE_EQ]);;
+
+let SUMMABLE_REARRANGE = prove
+ (`!x s p.
+        summable s (\n. lift(norm(x n))) /\ p permutes s
+        ==> summable s (x o p)`,
+  MESON_TAC[SERIES_LIFT_ABSCONV_IMP_CONV; summable; SERIES_REARRANGE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Banach fixed point theorem (not really topological...)                    *)
+(* ------------------------------------------------------------------------- *)
+
+let BANACH_FIX = prove
+ (`!f s c. complete s /\ ~(s = {}) /\
+           &0 <= c /\ c < &1 /\
+           (IMAGE f s) SUBSET s /\
+           (!x y. x IN s /\ y IN s ==> dist(f(x),f(y)) <= c * dist(x,y))
+           ==> ?!x:real^N. x IN s /\ (f x = x)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[EXISTS_UNIQUE_THM] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `dist((f:real^N->real^N) x,f y) <= c * dist(x,y)` MP_TAC THENL
+     [ASM_MESON_TAC[]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[REAL_ARITH `a <= c * a <=> &0 <= --a * (&1 - c)`] THEN
+    ASM_SIMP_TAC[GSYM REAL_LE_LDIV_EQ; REAL_SUB_LT; real_div] THEN
+    REWRITE_TAC[REAL_MUL_LZERO; REAL_ARITH `&0 <= --x <=> ~(&0 < x)`] THEN
+    MESON_TAC[DIST_POS_LT]] THEN
+  STRIP_ASSUME_TAC(prove_recursive_functions_exist num_RECURSION
+    `(z 0 = @x:real^N. x IN s) /\ (!n. z(SUC n) = f(z n))`) THEN
+  SUBGOAL_THEN `!n. (z:num->real^N) n IN s` ASSUME_TAC THENL
+   [INDUCT_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[MEMBER_NOT_EMPTY; SUBSET; IN_IMAGE];
+    ALL_TAC] THEN
+  UNDISCH_THEN `z 0 = @x:real^N. x IN s` (K ALL_TAC) THEN
+  SUBGOAL_THEN `?x:real^N. x IN s /\ (z --> x) sequentially` MP_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    ABBREV_TAC `e = dist(f(a:real^N),a)` THEN
+    SUBGOAL_THEN `~(&0 < e)` (fun th -> ASM_MESON_TAC[th; DIST_POS_LT]) THEN
+    DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LIM_SEQUENTIALLY]) THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
+    ASM_REWRITE_TAC[REAL_HALF] THEN DISCH_THEN(X_CHOOSE_TAC `N:num`) THEN
+    SUBGOAL_THEN
+     `dist(f(z N),a:real^N) < e / &2 /\ dist(f(z(N:num)),f(a)) < e / &2`
+     (fun th -> ASM_MESON_TAC[th; DIST_TRIANGLE_HALF_R; REAL_LT_REFL]) THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[ARITH_RULE `N <= SUC N`]; ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `c * dist((z:num->real^N) N,a)` THEN ASM_SIMP_TAC[] THEN
+    MATCH_MP_TAC(REAL_ARITH `x < y /\ c * x <= &1 * x ==> c * x < y`) THEN
+    ASM_SIMP_TAC[LE_REFL; REAL_LE_RMUL; DIST_POS_LE; REAL_LT_IMP_LE]] THEN
+  FIRST_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [complete]) THEN
+  ASM_REWRITE_TAC[CAUCHY] THEN
+  SUBGOAL_THEN `!n. dist(z(n):real^N,z(SUC n)) <= c pow n * dist(z(0),z(1))`
+  ASSUME_TAC THENL
+   [INDUCT_TAC THEN
+    REWRITE_TAC[real_pow; ARITH; REAL_MUL_LID; REAL_LE_REFL] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `c * dist(z(n):real^N,z(SUC n))` THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN ASM_SIMP_TAC[REAL_LE_LMUL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!m n:num. (&1 - c) * dist(z(m):real^N,z(m+n))
+                <= c pow m * dist(z(0),z(1)) * (&1 - c pow n)`
+  ASSUME_TAC THENL
+   [GEN_TAC THEN INDUCT_TAC THENL
+     [REWRITE_TAC[ADD_CLAUSES; DIST_REFL; REAL_MUL_RZERO] THEN
+      MATCH_MP_TAC REAL_LE_MUL THEN
+      ASM_SIMP_TAC[REAL_LE_MUL; REAL_POW_LE; DIST_POS_LE; REAL_SUB_LE;
+                   REAL_POW_1_LE; REAL_LT_IMP_LE];
+      ALL_TAC] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC
+    `(&1 - c) * (dist(z m:real^N,z(m + n)) + dist(z(m + n),z(m + SUC n)))` THEN
+    ASM_SIMP_TAC[REAL_LE_LMUL; REAL_SUB_LE; REAL_LT_IMP_LE; DIST_TRIANGLE] THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+      `c * x <= y ==> c * x' + y <= y' ==> c * (x + x') <= y'`)) THEN
+    REWRITE_TAC[REAL_ARITH
+     `q + a * b * (&1 - x) <= a * b * (&1 - y) <=> q <= a * b * (x - y)`] THEN
+    REWRITE_TAC[ADD_CLAUSES; real_pow] THEN
+    REWRITE_TAC[REAL_ARITH `a * b * (d - c * d) = (&1 - c) * a * d * b`] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN
+    ASM_SIMP_TAC[REAL_SUB_LE; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[GSYM REAL_POW_ADD; REAL_MUL_ASSOC] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  ASM_CASES_TAC `(z:num->real^N) 0 = z 1` THENL
+   [FIRST_X_ASSUM SUBST_ALL_TAC THEN EXISTS_TAC `0` THEN
+    REWRITE_TAC[GE; LE_0] THEN X_GEN_TAC `n:num` THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`0`; `n:num`]) THEN
+    REWRITE_TAC[ADD_CLAUSES; DIST_REFL; REAL_MUL_LZERO; REAL_MUL_RZERO] THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    ASM_CASES_TAC `(z:num->real^N) 0 = z n` THEN
+    ASM_REWRITE_TAC[DIST_REFL; REAL_NOT_LE] THEN
+    ASM_SIMP_TAC[REAL_LT_MUL; DIST_POS_LT; REAL_SUB_LT];
+    ALL_TAC] THEN
+  MP_TAC(SPECL [`c:real`; `e * (&1 - c) / dist((z:num->real^N) 0,z 1)`]
+   REAL_ARCH_POW_INV) THEN
+  ASM_SIMP_TAC[REAL_LT_MUL; REAL_LT_DIV; REAL_SUB_LT; DIST_POS_LT] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+  REWRITE_TAC[real_div; GE; REAL_MUL_ASSOC] THEN
+  ASM_SIMP_TAC[REAL_LT_RDIV_EQ; GSYM real_div; DIST_POS_LT] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_LDIV_EQ; REAL_SUB_LT] THEN DISCH_TAC THEN
+  REWRITE_TAC[LE_EXISTS; LEFT_IMP_EXISTS_THM] THEN
+  GEN_TAC THEN X_GEN_TAC `d:num` THEN DISCH_THEN SUBST_ALL_TAC THEN
+  ONCE_REWRITE_TAC[DIST_SYM] THEN
+  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP(REAL_ARITH
+    `d < e ==> x <= d ==> x < e`)) THEN
+  ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_SUB_LT] THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`N:num`; `d:num`]) THEN
+  MATCH_MP_TAC(REAL_ARITH
+  `(c * d) * e <= (c * d) * &1 ==> x * y <= c * d * e ==> y * x <= c * d`) THEN
+  MATCH_MP_TAC REAL_LE_LMUL THEN
+  ASM_SIMP_TAC[REAL_LE_MUL; REAL_POW_LE; DIST_POS_LE; REAL_ARITH
+   `&0 <= x ==> &1 - x <= &1`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Edelstein fixed point theorem.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let EDELSTEIN_FIX = prove
+ (`!f s. compact s /\ ~(s = {}) /\ (IMAGE f s) SUBSET s /\
+         (!x y. x IN s /\ y IN s /\ ~(x = y) ==> dist(f(x),f(y)) < dist(x,y))
+         ==> ?!x:real^N. x IN s /\ f x = x`,
+  MAP_EVERY X_GEN_TAC [`g:real^N->real^N`; `s:real^N->bool`] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[EXISTS_UNIQUE_THM] THEN CONJ_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[REAL_LT_REFL]] THEN
+  SUBGOAL_THEN
+   `!x y. x IN s /\ y IN s ==> dist((g:real^N->real^N)(x),g(y)) <= dist(x,y)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN ASM_CASES_TAC `x:real^N = y` THEN
+    ASM_SIMP_TAC[DIST_REFL; REAL_LE_LT];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `?x:real^N. x IN s /\ ~(g x = x)` THENL
+   [ALL_TAC; ASM SET_TAC[]] THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `x:real^N` STRIP_ASSUME_TAC) THEN
+  ABBREV_TAC `y = (g:real^N->real^N) x` THEN
+  SUBGOAL_THEN `(y:real^N) IN s` ASSUME_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP COMPACT_PCROSS o W CONJ) THEN
+  REWRITE_TAC[compact; PCROSS] THEN
+  (STRIP_ASSUME_TAC o prove_general_recursive_function_exists)
+    `?f:num->real^N->real^N.
+        (!z. f 0 z = z) /\ (!z n. f (SUC n) z = g(f n z))` THEN
+  SUBGOAL_THEN `!n z. z IN s ==> (f:num->real^N->real^N) n z IN s`
+  STRIP_ASSUME_TAC THENL [INDUCT_TAC THEN ASM SET_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!m n w z. m <= n /\ w IN s /\ z IN s
+              ==> dist((f:num->real^N->real^N) n w,f n z) <= dist(f m w,f m z)`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ] THEN
+    MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; FORALL_IN_IMAGE]) THEN
+    ASM_SIMP_TAC[REAL_LE_REFL] THEN MESON_TAC[REAL_LE_TRANS];
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `\n:num. pastecart (f n (x:real^N)) (f n y:real^N)`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; REWRITE_TAC[LEFT_IMP_EXISTS_THM]] THEN
+  MAP_EVERY X_GEN_TAC [`l:real^(N,N)finite_sum`; `s:num->num`] THEN
+  REWRITE_TAC[o_DEF; IN_ELIM_THM] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC SUBST_ALL_TAC) THEN
+  SUBGOAL_THEN
+   `(\x:real^(N,N)finite_sum. fstcart x) continuous_on UNIV /\
+    (\x:real^(N,N)finite_sum. sndcart x) continuous_on UNIV`
+  MP_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN
+    REWRITE_TAC[ETA_AX; LINEAR_FSTCART; LINEAR_SNDCART];
+    ALL_TAC] THEN
+  REWRITE_TAC[CONTINUOUS_ON_SEQUENTIALLY; IN_UNIV] THEN
+  DISCH_THEN(CONJUNCTS_THEN(fun th -> FIRST_ASSUM(MP_TAC o MATCH_MP th))) THEN
+  REWRITE_TAC[o_DEF; FSTCART_PASTECART; SNDCART_PASTECART; IMP_IMP] THEN
+  ONCE_REWRITE_TAC[CONJ_SYM] THEN
+  DISCH_THEN(fun th -> CONJUNCTS_THEN2 (LABEL_TAC "A") (LABEL_TAC "B") th THEN
+    MP_TAC(MATCH_MP LIM_SUB th)) THEN
+  REWRITE_TAC[] THEN DISCH_THEN(LABEL_TAC "AB") THEN
+  SUBGOAL_THEN
+   `!n. dist(a:real^N,b) <= dist((f:num->real^N->real^N) n x,f n y)`
+  STRIP_ASSUME_TAC THENL
+   [X_GEN_TAC `N:num` THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN
+    ONCE_REWRITE_TAC[GSYM REAL_SUB_LT] THEN DISCH_TAC THEN
+    USE_THEN "AB" (MP_TAC o REWRITE_RULE[LIM_SEQUENTIALLY]) THEN
+    DISCH_THEN(fun th -> FIRST_X_ASSUM(MP_TAC o MATCH_MP th)) THEN
+    REWRITE_TAC[NOT_EXISTS_THM] THEN X_GEN_TAC `M:num` THEN
+    DISCH_THEN(MP_TAC o SPEC `M + N:num`) THEN REWRITE_TAC[LE_ADD] THEN
+    MATCH_MP_TAC(NORM_ARITH
+     `dist(fx,fy) <= dist(x,y)
+      ==> ~(dist(fx - fy,a - b) < dist(a,b) - dist(x,y))`) THEN
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `M + N:num` o MATCH_MP MONOTONE_BIGGER) THEN
+    ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `b:real^N = a` SUBST_ALL_TAC THENL
+   [MATCH_MP_TAC(TAUT `(~p ==> F) ==> p`) THEN DISCH_TAC THEN
+    ABBREV_TAC `e = dist(a,b) - dist((g:real^N->real^N) a,g b)` THEN
+    SUBGOAL_THEN `&0 < e` ASSUME_TAC THENL
+     [ASM_MESON_TAC[REAL_SUB_LT]; ALL_TAC] THEN
+    SUBGOAL_THEN
+     `?n. dist((f:num->real^N->real^N) n x,a) < e / &2 /\
+          dist(f n y,b) < e / &2`
+    STRIP_ASSUME_TAC THENL
+     [MAP_EVERY (fun s -> USE_THEN s (MP_TAC o SPEC `e / &2` o
+        REWRITE_RULE[LIM_SEQUENTIALLY])) ["A"; "B"] THEN
+      ASM_REWRITE_TAC[REAL_HALF] THEN
+      DISCH_THEN(X_CHOOSE_TAC `M:num`) THEN
+      DISCH_THEN(X_CHOOSE_TAC `N:num`) THEN
+      EXISTS_TAC `(s:num->num) (M + N)` THEN
+      CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ARITH_TAC;
+      ALL_TAC] THEN
+    SUBGOAL_THEN `dist(f (SUC n) x,(g:real^N->real^N) a) +
+                  dist((f:num->real^N->real^N) (SUC n) y,g b) < e`
+    MP_TAC THENL
+     [ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC(REAL_ARITH `x < e / &2 /\ y < e / &2 ==> x + y < e`) THEN
+      CONJ_TAC THEN FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+       `dist(x,y) < e
+        ==> dist(g x,g y) <= dist(x,y) ==> dist(g x,g y) < e`)) THEN
+      ASM_SIMP_TAC[];
+      ALL_TAC] THEN
+    MP_TAC(SPEC `SUC n` (ASSUME
+    `!n. dist (a:real^N,b) <=
+         dist ((f:num->real^N->real^N) n x,f n y)`)) THEN
+    EXPAND_TAC "e" THEN NORM_ARITH_TAC;
+    ALL_TAC] THEN
+  EXISTS_TAC `a:real^N` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(ISPEC `sequentially` LIM_UNIQUE) THEN
+  EXISTS_TAC `\n:num. (f:num->real^N->real^N) (SUC(s n)) x` THEN
+  REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY] THEN CONJ_TAC THENL
+   [ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `(g:real^N->real^N) continuous_on s` MP_TAC THENL
+     [REWRITE_TAC[continuous_on] THEN ASM_MESON_TAC[REAL_LET_TRANS];
+      ALL_TAC] THEN
+    REWRITE_TAC[CONTINUOUS_ON_SEQUENTIALLY; o_DEF] THEN
+    DISCH_THEN MATCH_MP_TAC THEN ASM_SIMP_TAC[];
+    SUBGOAL_THEN `!n. (f:num->real^N->real^N) (SUC n) x = f n y`
+     (fun th -> ASM_SIMP_TAC[th]) THEN
+    INDUCT_TAC THEN ASM_REWRITE_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Dini's theorem.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let DINI = prove
+ (`!f:num->real^N->real^1 g s.
+        compact s /\ (!n. (f n) continuous_on s) /\ g continuous_on s /\
+        (!x. x IN s ==> ((\n. (f n x)) --> g x) sequentially) /\
+        (!n x. x IN s ==> drop(f n x) <= drop(f (n + 1) x))
+        ==> !e. &0 < e
+                ==> eventually (\n. !x. x IN s ==> norm(f n x - g x) < e)
+                               sequentially`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x:real^N m n:num. x IN s /\ m <= n ==> drop(f m x) <= drop(f n x)`
+  ASSUME_TAC THENL
+   [GEN_TAC THEN ASM_CASES_TAC `(x:real^N) IN s` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN ASM_SIMP_TAC[ADD1] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!n:num x:real^N. x IN s ==> drop(f n x) <= drop(g x)`
+  ASSUME_TAC THENL
+   [REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC(ISPEC `sequentially` LIM_DROP_LE) THEN
+    EXISTS_TAC `\m:num. (f:num->real^N->real^1) n x` THEN
+    EXISTS_TAC `\m:num. (f:num->real^N->real^1) m x` THEN
+    ASM_SIMP_TAC[LIM_CONST; TRIVIAL_LIMIT_SEQUENTIALLY] THEN
+    REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[LIM_SEQUENTIALLY; dist]) THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I
+   [COMPACT_EQ_HEINE_BOREL_SUBTOPOLOGY]) THEN
+  DISCH_THEN(MP_TAC o SPEC
+   `IMAGE (\n. { x | x IN s /\ norm((f:num->real^N->real^1) n x - g x) < e})
+          (:num)`) THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; IN_UNIV] THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> q /\ p /\ r`] THEN
+  REWRITE_TAC[EXISTS_FINITE_SUBSET_IMAGE; SUBSET_UNION; UNIONS_IMAGE] THEN
+  REWRITE_TAC[IN_UNIV; IN_ELIM_THM; EVENTUALLY_SEQUENTIALLY] THEN
+  SIMP_TAC[SUBSET; IN_UNIV; IN_ELIM_THM] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[LE_REFL]] THEN
+    X_GEN_TAC `n:num` THEN REWRITE_TAC[GSYM IN_BALL_0] THEN
+    MATCH_MP_TAC CONTINUOUS_OPEN_IN_PREIMAGE THEN
+    ASM_SIMP_TAC[OPEN_BALL; CONTINUOUS_ON_SUB; ETA_AX];
+
+    DISCH_THEN(X_CHOOSE_THEN `k:num->bool` (CONJUNCTS_THEN2
+     (MP_TAC o SPEC `\n:num. n` o MATCH_MP UPPER_BOUND_FINITE_SET)
+     (LABEL_TAC "*"))) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+    REWRITE_TAC[] THEN STRIP_TAC THEN X_GEN_TAC `n:num` THEN
+    DISCH_TAC THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    REMOVE_THEN "*" (MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `m:num` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB] THEN MATCH_MP_TAC(REAL_ARITH
+     `m <= n /\ n <= g ==> abs(m - g) < e ==> abs(n - g) < e`) THEN
+    ASM_MESON_TAC[LE_TRANS]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Closest point of a (closed) set to a point.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let closest_point = new_definition
+ `closest_point s a = @x. x IN s /\ !y. y IN s ==> dist(a,x) <= dist(a,y)`;;
+
+let CLOSEST_POINT_EXISTS = prove
+ (`!s a. closed s /\ ~(s = {})
+         ==> (closest_point s a) IN s /\
+             !y. y IN s ==> dist(a,closest_point s a) <= dist(a,y)`,
+  REWRITE_TAC[closest_point] THEN CONV_TAC(ONCE_DEPTH_CONV SELECT_CONV) THEN
+  REWRITE_TAC[DISTANCE_ATTAINS_INF]);;
+
+let CLOSEST_POINT_IN_SET = prove
+ (`!s a. closed s /\ ~(s = {}) ==> (closest_point s a) IN s`,
+  MESON_TAC[CLOSEST_POINT_EXISTS]);;
+
+let CLOSEST_POINT_LE = prove
+ (`!s a x. closed s /\ x IN s ==> dist(a,closest_point s a) <= dist(a,x)`,
+  MESON_TAC[CLOSEST_POINT_EXISTS; MEMBER_NOT_EMPTY]);;
+
+let CLOSEST_POINT_SELF = prove
+ (`!s x:real^N. x IN s ==> closest_point s x = x`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[closest_point] THEN
+  MATCH_MP_TAC SELECT_UNIQUE THEN REWRITE_TAC[] THEN GEN_TAC THEN EQ_TAC THENL
+   [STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN
+    ASM_SIMP_TAC[DIST_LE_0; DIST_REFL];
+    STRIP_TAC THEN ASM_REWRITE_TAC[DIST_REFL; DIST_POS_LE]]);;
+
+let CLOSEST_POINT_REFL = prove
+ (`!s x:real^N. closed s /\ ~(s = {}) ==> (closest_point s x = x <=> x IN s)`,
+  MESON_TAC[CLOSEST_POINT_IN_SET; CLOSEST_POINT_SELF]);;
+
+let DIST_CLOSEST_POINT_LIPSCHITZ = prove
+ (`!s x y:real^N.
+        closed s /\ ~(s = {})
+        ==> abs(dist(x,closest_point s x) - dist(y,closest_point s y))
+            <= dist(x,y)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP CLOSEST_POINT_EXISTS) THEN
+  DISCH_THEN(fun th ->
+    CONJUNCTS_THEN2 ASSUME_TAC
+     (MP_TAC o SPEC `closest_point s (y:real^N)`) (SPEC `x:real^N` th) THEN
+    CONJUNCTS_THEN2 ASSUME_TAC
+     (MP_TAC o SPEC `closest_point s (x:real^N)`) (SPEC `y:real^N` th)) THEN
+  ASM_REWRITE_TAC[] THEN NORM_ARITH_TAC);;
+
+let CONTINUOUS_AT_DIST_CLOSEST_POINT = prove
+ (`!s x:real^N.
+        closed s /\ ~(s = {})
+        ==> (\x. lift(dist(x,closest_point s x))) continuous (at x)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[continuous_at; DIST_LIFT] THEN
+  ASM_MESON_TAC[DIST_CLOSEST_POINT_LIPSCHITZ; REAL_LET_TRANS]);;
+
+let CONTINUOUS_ON_DIST_CLOSEST_POINT = prove
+ (`!s t. closed s /\ ~(s = {})
+         ==> (\x. lift(dist(x,closest_point s x))) continuous_on t`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON;
+            CONTINUOUS_AT_DIST_CLOSEST_POINT]);;
+
+let UNIFORMLY_CONTINUOUS_ON_DIST_CLOSEST_POINT = prove
+ (`!s t:real^N->bool.
+        closed s /\ ~(s = {})
+        ==> (\x. lift(dist(x,closest_point s x))) uniformly_continuous_on t`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[uniformly_continuous_on; DIST_LIFT] THEN
+  ASM_MESON_TAC[DIST_CLOSEST_POINT_LIPSCHITZ; REAL_LET_TRANS]);;
+
+let SEGMENT_TO_CLOSEST_POINT = prove
+ (`!s a:real^N.
+        closed s /\ ~(s = {})
+        ==> segment(a,closest_point s a) INTER s = {}`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[SET_RULE `s INTER t = {} <=> !x. x IN s ==> ~(x IN t)`] THEN
+  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP DIST_IN_OPEN_SEGMENT) THEN
+  MATCH_MP_TAC(TAUT `(r ==> ~p) ==> p /\ q ==> ~r`) THEN
+  ASM_MESON_TAC[CLOSEST_POINT_EXISTS; REAL_NOT_LT; DIST_SYM]);;
+
+let SEGMENT_TO_POINT_EXISTS = prove
+ (`!s a:real^N.
+        closed s /\ ~(s = {}) ==> ?b. b IN s /\ segment(a,b) INTER s = {}`,
+  MESON_TAC[SEGMENT_TO_CLOSEST_POINT; CLOSEST_POINT_EXISTS]);;
+
+let CLOSEST_POINT_IN_INTERIOR = prove
+ (`!s x:real^N.
+        closed s /\ ~(s = {})
+        ==> ((closest_point s x) IN interior s <=> x IN interior s)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `(x:real^N) IN s` THEN
+  ASM_SIMP_TAC[CLOSEST_POINT_SELF] THEN
+  MATCH_MP_TAC(TAUT `~q /\ ~p ==> (p <=> q)`) THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[INTERIOR_SUBSET; SUBSET]; STRIP_TAC] THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [IN_INTERIOR_CBALL]) THEN
+  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `closest_point s (x:real^N) IN s` ASSUME_TAC THENL
+   [ASM_MESON_TAC[INTERIOR_SUBSET; SUBSET]; ALL_TAC] THEN
+  SUBGOAL_THEN `~(closest_point s (x:real^N) = x)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `x:real^N`;
+   `closest_point s x -
+    (min (&1) (e / norm(closest_point s x - x))) %
+    (closest_point s x - x):real^N`]
+    CLOSEST_POINT_LE) THEN
+  ASM_REWRITE_TAC[dist; NOT_IMP; VECTOR_ARITH
+   `x - (y - e % (y - x)):real^N = (&1 - e) % (x - y)`] THEN
+  CONJ_TAC THENL
+   [FIRST_X_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    REWRITE_TAC[IN_CBALL; NORM_ARITH `dist(a:real^N,a - x) = norm x`] THEN
+    REWRITE_TAC[NORM_MUL; REAL_ABS_DIV; REAL_ABS_NORM] THEN
+    ASM_SIMP_TAC[GSYM REAL_LE_RDIV_EQ; NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= a ==> abs(min (&1) a) <= a`) THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_LE_DIV; NORM_POS_LE];
+    REWRITE_TAC[NORM_MUL; REAL_ARITH
+     `~(n <= a * n) <=> &0 < (&1 - a) * n`] THEN
+    MATCH_MP_TAC REAL_LT_MUL THEN
+    ASM_SIMP_TAC[NORM_POS_LT; VECTOR_SUB_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `&0 < e /\ e <= &1 ==> &0 < &1 - abs(&1 - e)`) THEN
+    REWRITE_TAC[REAL_MIN_LE; REAL_LT_MIN; REAL_LT_01; REAL_LE_REFL] THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; NORM_POS_LT; VECTOR_SUB_EQ]]);;
+
+let CLOSEST_POINT_IN_FRONTIER = prove
+ (`!s x:real^N.
+        closed s /\ ~(s = {}) /\ ~(x IN interior s)
+        ==> (closest_point s x) IN frontier s`,
+  SIMP_TAC[frontier; IN_DIFF; CLOSEST_POINT_IN_INTERIOR] THEN
+  SIMP_TAC[CLOSEST_POINT_IN_SET; CLOSURE_CLOSED]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More general infimum of distance between two sets.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let setdist = new_definition
+ `setdist(s,t) =
+        if s = {} \/ t = {} then &0
+        else inf {dist(x,y) | x IN s /\ y IN t}`;;
+
+let SETDIST_EMPTY = prove
+ (`(!t. setdist({},t) = &0) /\ (!s. setdist(s,{}) = &0)`,
+  REWRITE_TAC[setdist]);;
+
+let SETDIST_POS_LE = prove
+ (`!s t. &0 <= setdist(s,t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[setdist] THEN
+  COND_CASES_TAC THEN REWRITE_TAC[REAL_LE_REFL] THEN
+  MATCH_MP_TAC REAL_LE_INF THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; DIST_POS_LE] THEN ASM SET_TAC[]);;
+
+let REAL_LE_SETDIST = prove
+  (`!s t:real^N->bool d.
+        ~(s = {}) /\ ~(t = {}) /\
+        (!x y. x IN s /\ y IN t ==> d <= dist(x,y))
+        ==> d <= setdist(s,t)`,
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[setdist] THEN
+  MP_TAC(ISPEC `{dist(x:real^N,y) | x IN s /\ y IN t}` INF) THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [ASM SET_TAC[]; MESON_TAC[DIST_POS_LE]]; ALL_TAC] THEN
+  ASM_MESON_TAC[]);;
+
+let SETDIST_LE_DIST = prove
+ (`!s t x y:real^N. x IN s /\ y IN t ==> setdist(s,t) <= dist(x,y)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[setdist] THEN
+  COND_CASES_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPEC `{dist(x:real^N,y) | x IN s /\ y IN t}` INF) THEN
+  REWRITE_TAC[FORALL_IN_GSPEC] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [ASM SET_TAC[]; MESON_TAC[DIST_POS_LE]]; ALL_TAC] THEN
+  ASM_MESON_TAC[]);;
+
+let REAL_LE_SETDIST_EQ = prove
+ (`!d s t:real^N->bool.
+        d <= setdist(s,t) <=>
+        (!x y. x IN s /\ y IN t ==> d <= dist(x,y)) /\
+        (s = {} \/ t = {} ==> d <= &0)`,
+  REPEAT GEN_TAC THEN MAP_EVERY ASM_CASES_TAC
+   [`s:real^N->bool = {}`; `t:real^N->bool = {}`] THEN
+  ASM_REWRITE_TAC[SETDIST_EMPTY; NOT_IN_EMPTY] THEN
+  ASM_MESON_TAC[REAL_LE_SETDIST; SETDIST_LE_DIST; REAL_LE_TRANS]);;
+
+let SETDIST_REFL = prove
+ (`!s:real^N->bool. setdist(s,s) = &0`,
+  GEN_TAC THEN REWRITE_TAC[GSYM REAL_LE_ANTISYM; SETDIST_POS_LE] THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [ASM_REWRITE_TAC[setdist; REAL_LE_REFL]; ALL_TAC] THEN
+  ASM_MESON_TAC[SETDIST_LE_DIST; MEMBER_NOT_EMPTY; DIST_REFL]);;
+
+let SETDIST_SYM = prove
+ (`!s t. setdist(s,t) = setdist(t,s)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[setdist; DISJ_SYM] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+  MESON_TAC[DIST_SYM]);;
+
+let SETDIST_TRIANGLE = prove
+ (`!s a t:real^N->bool.
+        setdist(s,t) <= setdist(s,{a}) + setdist({a},t)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `s:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[SETDIST_EMPTY; REAL_ADD_LID; SETDIST_POS_LE] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THEN
+  ASM_REWRITE_TAC[SETDIST_EMPTY; REAL_ADD_RID; SETDIST_POS_LE] THEN
+  ONCE_REWRITE_TAC[GSYM REAL_LE_SUB_RADD] THEN
+  MATCH_MP_TAC REAL_LE_SETDIST THEN
+  ASM_REWRITE_TAC[NOT_INSERT_EMPTY; IN_SING; IMP_CONJ;
+                  RIGHT_FORALL_IMP_THM; FORALL_UNWIND_THM2] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `x - y <= z <=> x - z <= y`] THEN
+  MATCH_MP_TAC REAL_LE_SETDIST THEN
+  ASM_REWRITE_TAC[NOT_INSERT_EMPTY; IN_SING; IMP_CONJ;
+                  RIGHT_FORALL_IMP_THM; FORALL_UNWIND_THM2] THEN
+  X_GEN_TAC `y:real^N` THEN STRIP_TAC THEN
+  REWRITE_TAC[REAL_LE_SUB_RADD] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `dist(x:real^N,y)` THEN
+  ASM_SIMP_TAC[SETDIST_LE_DIST] THEN CONV_TAC NORM_ARITH);;
+
+let SETDIST_SINGS = prove
+ (`!x y. setdist({x},{y}) = dist(x,y)`,
+  REWRITE_TAC[setdist; NOT_INSERT_EMPTY] THEN
+  REWRITE_TAC[SET_RULE `{f x y | x IN {a} /\ y IN {b}} = {f a b}`] THEN
+  SIMP_TAC[INF_INSERT_FINITE; FINITE_EMPTY]);;
+
+let SETDIST_LIPSCHITZ = prove
+ (`!s t x y:real^N. abs(setdist({x},s) - setdist({y},s)) <= dist(x,y)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM SETDIST_SINGS] THEN
+  REWRITE_TAC[REAL_ARITH
+   `abs(x - y) <= z <=> x <= z + y /\ y <= z + x`] THEN
+  MESON_TAC[SETDIST_TRIANGLE; SETDIST_SYM]);;
+
+let CONTINUOUS_AT_LIFT_SETDIST = prove
+ (`!s x:real^N. (\y. lift(setdist({y},s))) continuous (at x)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[continuous_at; DIST_LIFT] THEN
+  ASM_MESON_TAC[SETDIST_LIPSCHITZ; REAL_LET_TRANS]);;
+
+let CONTINUOUS_ON_LIFT_SETDIST = prove
+ (`!s t:real^N->bool. (\y. lift(setdist({y},s))) continuous_on t`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON;
+            CONTINUOUS_AT_LIFT_SETDIST]);;
+
+let UNIFORMLY_CONTINUOUS_ON_LIFT_SETDIST = prove
+ (`!s t:real^N->bool.
+         (\y. lift(setdist({y},s))) uniformly_continuous_on t`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[uniformly_continuous_on; DIST_LIFT] THEN
+  ASM_MESON_TAC[SETDIST_LIPSCHITZ; REAL_LET_TRANS]);;
+
+let SETDIST_DIFFERENCES = prove
+ (`!s t. setdist(s,t) = setdist({vec 0},{x - y:real^N | x IN s /\ y IN t})`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[setdist; NOT_INSERT_EMPTY;
+     SET_RULE `{f x y | x IN s /\ y IN t} = {} <=> s = {} \/ t = {}`] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_SING] THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC; RIGHT_EXISTS_AND_THM; UNWIND_THM2; DIST_0] THEN
+  REWRITE_TAC[dist] THEN MESON_TAC[]);;
+
+let SETDIST_SUBSET_RIGHT = prove
+ (`!s t u:real^N->bool.
+    ~(t = {}) /\ t SUBSET u ==> setdist(s,u) <= setdist(s,t)`,
+  REPEAT STRIP_TAC THEN
+  MAP_EVERY ASM_CASES_TAC [`s:real^N->bool = {}`; `u:real^N->bool = {}`] THEN
+  ASM_REWRITE_TAC[SETDIST_EMPTY; SETDIST_POS_LE; REAL_LE_REFL] THEN
+  ASM_REWRITE_TAC[setdist] THEN MATCH_MP_TAC REAL_LE_INF_SUBSET THEN
+  ASM_REWRITE_TAC[FORALL_IN_GSPEC; SUBSET] THEN
+  REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+  MESON_TAC[DIST_POS_LE]);;
+
+let SETDIST_SUBSET_LEFT = prove
+ (`!s t u:real^N->bool.
+    ~(s = {}) /\ s SUBSET t ==> setdist(t,u) <= setdist(s,u)`,
+  MESON_TAC[SETDIST_SUBSET_RIGHT; SETDIST_SYM]);;
+
+let SETDIST_CLOSURE = prove
+ (`(!s t:real^N->bool. setdist(closure s,t) = setdist(s,t)) /\
+   (!s t:real^N->bool. setdist(s,closure t) = setdist(s,t))`,
+  GEN_REWRITE_TAC RAND_CONV [SWAP_FORALL_THM] THEN
+  GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [SETDIST_SYM] THEN
+  REWRITE_TAC[] THEN
+  REWRITE_TAC[MESON[REAL_LE_ANTISYM]
+   `x:real = y <=> !d. d <= x <=> d <= y`] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_LE_SETDIST_EQ] THEN
+  MAP_EVERY ASM_CASES_TAC [`s:real^N->bool = {}`; `t:real^N->bool = {}`] THEN
+  ASM_REWRITE_TAC[CLOSURE_EQ_EMPTY; CLOSURE_EMPTY; NOT_IN_EMPTY] THEN
+  MATCH_MP_TAC(SET_RULE
+   `s SUBSET c /\
+    (!y. Q y /\ (!x. x IN s ==> P x y) ==> (!x. x IN c ==> P x y))
+   ==> ((!x y. x IN c /\ Q y ==> P x y) <=>
+        (!x y. x IN s /\ Q y ==> P x y))`) THEN
+  REWRITE_TAC[CLOSURE_SUBSET] THEN GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC CONTINUOUS_GE_ON_CLOSURE THEN
+  ASM_REWRITE_TAC[o_DEF; dist] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_LIFT_NORM_COMPOSE THEN
+  SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; CONTINUOUS_ON_ID]);;
+
+let SETDIST_COMPACT_CLOSED = prove
+ (`!s t:real^N->bool.
+        compact s /\ closed t /\ ~(s = {}) /\ ~(t = {})
+        ==> ?x y. x IN s /\ y IN t /\ dist(x,y) = setdist(s,t)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!x y. P x /\ Q y ==> S x y) /\ (?x y. P x /\ Q y /\ R x y)
+    ==> ?x y. P x /\ Q y /\ R x y /\ S x y`) THEN
+  SIMP_TAC[SETDIST_LE_DIST] THEN
+  ASM_REWRITE_TAC[REAL_LE_SETDIST_EQ] THEN
+  MP_TAC(ISPECL [`{x - y:real^N | x IN s /\ y IN t}`; `vec 0:real^N`]
+        DISTANCE_ATTAINS_INF) THEN
+  ASM_SIMP_TAC[COMPACT_CLOSED_DIFFERENCES; EXISTS_IN_GSPEC; FORALL_IN_GSPEC;
+               DIST_0; GSYM CONJ_ASSOC] THEN
+  REWRITE_TAC[dist] THEN DISCH_THEN MATCH_MP_TAC THEN ASM SET_TAC[]);;
+
+let SETDIST_CLOSED_COMPACT = prove
+ (`!s t:real^N->bool.
+        closed s /\ compact t /\ ~(s = {}) /\ ~(t = {})
+        ==> ?x y. x IN s /\ y IN t /\ dist(x,y) = setdist(s,t)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!x y. P x /\ Q y ==> S x y) /\ (?x y. P x /\ Q y /\ R x y)
+    ==> ?x y. P x /\ Q y /\ R x y /\ S x y`) THEN
+  SIMP_TAC[SETDIST_LE_DIST] THEN
+  ASM_REWRITE_TAC[REAL_LE_SETDIST_EQ] THEN
+  MP_TAC(ISPECL [`{x - y:real^N | x IN s /\ y IN t}`; `vec 0:real^N`]
+        DISTANCE_ATTAINS_INF) THEN
+  ASM_SIMP_TAC[CLOSED_COMPACT_DIFFERENCES; EXISTS_IN_GSPEC; FORALL_IN_GSPEC;
+               DIST_0; GSYM CONJ_ASSOC] THEN
+  REWRITE_TAC[dist] THEN DISCH_THEN MATCH_MP_TAC THEN ASM SET_TAC[]);;
+
+let SETDIST_EQ_0_COMPACT_CLOSED = prove
+ (`!s t:real^N->bool.
+        compact s /\ closed t
+        ==> (setdist(s,t) = &0 <=> s = {} \/ t = {} \/ ~(s INTER t = {}))`,
+  REPEAT STRIP_TAC THEN
+  MAP_EVERY ASM_CASES_TAC [`s:real^N->bool = {}`; `t:real^N->bool = {}`] THEN
+  ASM_REWRITE_TAC[SETDIST_EMPTY] THEN EQ_TAC THENL
+   [MP_TAC(ISPECL [`s:real^N->bool`; `t:real^N->bool`]
+      SETDIST_COMPACT_CLOSED) THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[EXTENSION; IN_INTER; NOT_IN_EMPTY] THEN MESON_TAC[DIST_EQ_0];
+    REWRITE_TAC[GSYM REAL_LE_ANTISYM; SETDIST_POS_LE] THEN
+    REWRITE_TAC[EXTENSION; IN_INTER; NOT_IN_EMPTY] THEN
+    MESON_TAC[SETDIST_LE_DIST; DIST_EQ_0]]);;
+
+let SETDIST_EQ_0_CLOSED_COMPACT = prove
+ (`!s t:real^N->bool.
+        closed s /\ compact t
+        ==> (setdist(s,t) = &0 <=> s = {} \/ t = {} \/ ~(s INTER t = {}))`,
+  ONCE_REWRITE_TAC[SETDIST_SYM] THEN
+  SIMP_TAC[SETDIST_EQ_0_COMPACT_CLOSED] THEN SET_TAC[]);;
+
+let SETDIST_EQ_0_BOUNDED = prove
+ (`!s t:real^N->bool.
+        (bounded s \/ bounded t)
+        ==> (setdist(s,t) = &0 <=>
+             s = {} \/ t = {} \/ ~(closure(s) INTER closure(t) = {}))`,
+  REPEAT GEN_TAC THEN
+  MAP_EVERY ASM_CASES_TAC [`s:real^N->bool = {}`; `t:real^N->bool = {}`] THEN
+  ASM_REWRITE_TAC[SETDIST_EMPTY] THEN STRIP_TAC THEN
+  ONCE_REWRITE_TAC[MESON[SETDIST_CLOSURE]
+   `setdist(s,t) = setdist(closure s,closure t)`] THEN
+  ASM_SIMP_TAC[SETDIST_EQ_0_COMPACT_CLOSED; SETDIST_EQ_0_CLOSED_COMPACT;
+               COMPACT_CLOSURE; CLOSED_CLOSURE; CLOSURE_EQ_EMPTY]);;
+
+
+let SETDIST_TRANSLATION = prove
+ (`!a:real^N s t.
+        setdist(IMAGE (\x. a + x) s,IMAGE (\x. a + x) t) = setdist(s,t)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[SETDIST_DIFFERENCES] THEN
+  AP_TERM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[SET_RULE
+   `{f x y | x IN IMAGE g s /\ y IN IMAGE g t} =
+    {f (g x) (g y) | x IN s /\ y IN t}`] THEN
+  REWRITE_TAC[VECTOR_ARITH `(a + x) - (a + y):real^N = x - y`]);;
+
+add_translation_invariants [SETDIST_TRANSLATION];;
+
+let SETDIST_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x. norm(f x) = norm x)
+        ==> setdist(IMAGE f s,IMAGE f t) = setdist(s,t)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[setdist; IMAGE_EQ_EMPTY] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[dist] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[SET_RULE
+   `{f x y | x IN IMAGE g s /\ y IN IMAGE g t} =
+    {f (g x) (g y) | x IN s /\ y IN t}`] THEN
+  FIRST_X_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP LINEAR_SUB th)]) THEN
+  ASM_REWRITE_TAC[]);;
+
+add_linear_invariants [SETDIST_LINEAR_IMAGE];;
+
+let SETDIST_UNIQUE = prove
+ (`!s t a b:real^N d.
+        a IN s /\ b IN t /\ dist(a,b) = d /\
+        (!x y. x IN s /\ y IN t ==> dist(a,b) <= dist(x,y))
+        ==> setdist(s,t) = d`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[SETDIST_LE_DIST];
+    MATCH_MP_TAC REAL_LE_SETDIST THEN ASM SET_TAC[]]);;
+
+let SETDIST_CLOSEST_POINT = prove
+ (`!a:real^N s.
+      closed s /\ ~(s = {}) ==> setdist({a},s) = dist(a,closest_point s a)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SETDIST_UNIQUE THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; IN_SING; UNWIND_THM2] THEN
+  EXISTS_TAC `closest_point s (a:real^N)` THEN
+  ASM_MESON_TAC[CLOSEST_POINT_EXISTS; DIST_SYM]);;
+
+let SETDIST_EQ_0_SING = prove
+ (`(!s x:real^N. setdist({x},s) = &0 <=> s = {} \/ x IN closure s) /\
+   (!s x:real^N. setdist(s,{x}) = &0 <=> s = {} \/ x IN closure s)`,
+  SIMP_TAC[SETDIST_EQ_0_BOUNDED; BOUNDED_SING; CLOSURE_SING] THEN SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Use set distance for an easy proof of separation properties.              *)
+(* ------------------------------------------------------------------------- *)
+
+let SEPARATION_CLOSURES = prove
+ (`!s t:real^N->bool.
+        s INTER closure(t) = {} /\ t INTER closure(s) = {}
+        ==> ?u v. DISJOINT u v /\ open u /\ open v /\
+                  s SUBSET u /\ t SUBSET v`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:real^N->bool = {}` THENL
+   [MAP_EVERY EXISTS_TAC [`{}:real^N->bool`; `(:real^N)`] THEN
+    ASM_REWRITE_TAC[OPEN_EMPTY; OPEN_UNIV] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THENL
+   [MAP_EVERY EXISTS_TAC [`(:real^N)`; `{}:real^N->bool`] THEN
+    ASM_REWRITE_TAC[OPEN_EMPTY; OPEN_UNIV] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  EXISTS_TAC `{x | x IN (:real^N) /\
+                   lift(setdist({x},t) - setdist({x},s)) IN
+                   {x | &0 < x$1}}` THEN
+  EXISTS_TAC `{x | x IN (:real^N) /\
+                   lift(setdist({x},t) - setdist({x},s)) IN
+                   {x | x$1 < &0}}` THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[SET_RULE `DISJOINT s t <=> !x. x IN s /\ x IN t ==> F`] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_UNIV] THEN REAL_ARITH_TAC;
+    MATCH_MP_TAC CONTINUOUS_OPEN_PREIMAGE THEN
+    SIMP_TAC[REWRITE_RULE[real_gt] OPEN_HALFSPACE_COMPONENT_GT; OPEN_UNIV] THEN
+    SIMP_TAC[LIFT_SUB; CONTINUOUS_ON_SUB; CONTINUOUS_ON_LIFT_SETDIST];
+    MATCH_MP_TAC CONTINUOUS_OPEN_PREIMAGE THEN
+    SIMP_TAC[OPEN_HALFSPACE_COMPONENT_LT; OPEN_UNIV] THEN
+    SIMP_TAC[LIFT_SUB; CONTINUOUS_ON_SUB; CONTINUOUS_ON_LIFT_SETDIST];
+    REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_UNIV; GSYM drop; LIFT_DROP] THEN
+    GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC(REAL_ARITH
+     `&0 <= x /\ y = &0 /\ ~(x = &0) ==> &0 < x - y`);
+    REWRITE_TAC[SUBSET; IN_ELIM_THM; IN_UNIV; GSYM drop; LIFT_DROP] THEN
+    GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC(REAL_ARITH
+     `&0 <= y /\ x = &0 /\ ~(y = &0) ==> x - y < &0`)] THEN
+  ASM_SIMP_TAC[SETDIST_POS_LE; SETDIST_EQ_0_BOUNDED; BOUNDED_SING] THEN
+  ASM_SIMP_TAC[CLOSED_SING; CLOSURE_CLOSED; NOT_INSERT_EMPTY;
+               REWRITE_RULE[SUBSET] CLOSURE_SUBSET;
+               SET_RULE `{a} INTER s = {} <=> ~(a IN s)`] THEN
+  ASM SET_TAC[]);;
+
+let SEPARATION_NORMAL = prove
+ (`!s t:real^N->bool.
+        closed s /\ closed t /\ s INTER t = {}
+        ==> ?u v. open u /\ open v /\
+                  s SUBSET u /\ t SUBSET v /\ u INTER v = {}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM DISJOINT] THEN
+  ONCE_REWRITE_TAC[TAUT
+    `a /\ b /\ c /\ d /\ e <=> e /\ a /\ b /\ c /\ d`] THEN
+  MATCH_MP_TAC SEPARATION_CLOSURES THEN
+  ASM_SIMP_TAC[CLOSURE_CLOSED] THEN ASM SET_TAC[]);;
+
+let SEPARATION_NORMAL_COMPACT = prove
+ (`!s t:real^N->bool.
+        compact s /\ closed t /\ s INTER t = {}
+        ==> ?u v. open u /\ compact(closure u) /\ open v /\
+                  s SUBSET u /\ t SUBSET v /\ u INTER v = {}`,
+  REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED; CLOSED_CLOSURE] THEN
+  REPEAT STRIP_TAC THEN FIRST_ASSUM
+   (MP_TAC o SPEC `vec 0:real^N` o MATCH_MP BOUNDED_SUBSET_BALL) THEN
+  DISCH_THEN(X_CHOOSE_THEN `r:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `t UNION ((:real^N) DIFF ball(vec 0,r))`]
+        SEPARATION_NORMAL) THEN
+  ASM_SIMP_TAC[CLOSED_UNION; GSYM OPEN_CLOSED; OPEN_BALL] THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  CONJ_TAC THENL [MATCH_MP_TAC BOUNDED_CLOSURE; ASM SET_TAC[]] THEN
+  MATCH_MP_TAC BOUNDED_SUBSET THEN EXISTS_TAC `ball(vec 0:real^N,r)` THEN
+  REWRITE_TAC[BOUNDED_BALL] THEN ASM SET_TAC[]);;
+
+let SEPARATION_HAUSDORFF = prove
+ (`!x:real^N y.
+      ~(x = y)
+      ==> ?u v. open u /\ open v /\ x IN u /\ y IN v /\ (u INTER v = {})`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`{x:real^N}`; `{y:real^N}`] SEPARATION_NORMAL) THEN
+  REWRITE_TAC[SING_SUBSET; CLOSED_SING] THEN
+  DISCH_THEN MATCH_MP_TAC THEN ASM SET_TAC[]);;
+
+let SEPARATION_T2 = prove
+ (`!x:real^N y.
+        ~(x = y) <=> ?u v. open u /\ open v /\ x IN u /\ y IN v /\
+                           (u INTER v = {})`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN ASM_SIMP_TAC[SEPARATION_HAUSDORFF] THEN
+  REWRITE_TAC[EXTENSION; IN_INTER; NOT_IN_EMPTY] THEN MESON_TAC[]);;
+
+let SEPARATION_T1 = prove
+ (`!x:real^N y.
+        ~(x = y) <=> ?u v. open u /\ open v /\ x IN u /\ ~(y IN u) /\
+                           ~(x IN v) /\ y IN v`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ASM_SIMP_TAC[SEPARATION_T2; EXTENSION; NOT_IN_EMPTY; IN_INTER];
+    ALL_TAC] THEN MESON_TAC[]);;
+
+let SEPARATION_T0 = prove
+ (`!x:real^N y. ~(x = y) <=> ?u. open u /\ ~(x IN u <=> y IN u)`,
+  MESON_TAC[SEPARATION_T1]);;
+
+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
+  ASM_CASES_TAC `s:real^M->bool = {}` THEN
+  ASM_CASES_TAC `t:real^(M,N)finite_sum->bool = {}` THEN
+  ASM_REWRITE_TAC[NOT_IN_EMPTY; EMPTY_GSPEC; CLOSED_EMPTY] THEN
+  REWRITE_TAC[closed; open_def; IN_DIFF; IN_UNIV; IN_ELIM_THM] THEN
+  X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+  EXISTS_TAC `setdist({pastecart (x:real^M) (y:real^N) | x IN s},t)` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[REAL_LT_LE; SETDIST_POS_LE] THEN
+    ONCE_REWRITE_TAC[EQ_SYM_EQ] THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) SETDIST_EQ_0_COMPACT_CLOSED o
+      rand o snd) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[SET_RULE
+       `{pastecart x y | P x} = {pastecart x z | P x /\ z IN {y}}`] THEN
+      REWRITE_TAC[GSYM PCROSS] THEN
+      ASM_SIMP_TAC[COMPACT_PCROSS; COMPACT_SING];
+      DISCH_THEN SUBST1_TAC THEN ASM_REWRITE_TAC[] THEN ASM SET_TAC[]];
+    X_GEN_TAC `z:real^N` THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+    REWRITE_TAC[REAL_NOT_LT] THEN
+    DISCH_THEN(X_CHOOSE_THEN `w:real^M` STRIP_ASSUME_TAC) THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `dist(pastecart (w:real^M) (y:real^N),pastecart w z)` THEN
+    CONJ_TAC THENL
+     [MATCH_MP_TAC SETDIST_LE_DIST THEN ASM SET_TAC[];
+      REWRITE_TAC[DIST_PASTECART_CANCEL; REAL_LE_REFL; DIST_SYM]]]);;
+
+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 REWRITE_TAC[PCROSS; CLOSED_IN_CLOSED] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM; CONJ_ASSOC] THEN
+  DISCH_THEN(CHOOSE_THEN(CONJUNCTS_THEN2 MP_TAC SUBST1_TAC)) THEN
+  DISCH_THEN(MP_TAC o MATCH_MP CLOSED_COMPACT_PROJECTION) THEN
+  MATCH_MP_TAC(MESON[]
+   `P p==> (closed p ==> ?t. closed t /\ P t)`) THEN
+  REWRITE_TAC[IN_ELIM_PASTECART_THM; IN_INTER] THEN SET_TAC[]);;
+
+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]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Urysohn's lemma (for real^N, where the proof is easy using distances).    *)
+(* ------------------------------------------------------------------------- *)
+
+let URYSOHN_LOCAL_STRONG = prove
+ (`!s t u a b.
+        closed_in (subtopology euclidean u) s /\
+        closed_in (subtopology euclidean u) t /\
+        s INTER t = {} /\ ~(a = b)
+        ==> ?f:real^N->real^M.
+               f continuous_on u /\
+               (!x. x IN u ==> f(x) IN segment[a,b]) /\
+               (!x. x IN u ==> (f x = a <=> x IN s)) /\
+               (!x. x IN u ==> (f x = b <=> x IN t))`,
+  let lemma = prove
+   (`!s t u a b.
+          closed_in (subtopology euclidean u) s /\
+          closed_in (subtopology euclidean u) t /\
+          s INTER t = {} /\ ~(s = {}) /\ ~(t = {}) /\ ~(a = b)
+          ==> ?f:real^N->real^M.
+                 f continuous_on u /\
+                 (!x. x IN u ==> f(x) IN segment[a,b]) /\
+                 (!x. x IN u ==> (f x = a <=> x IN s)) /\
+                 (!x. x IN u ==> (f x = b <=> x IN t))`,
+    REPEAT STRIP_TAC THEN EXISTS_TAC
+      `\x:real^N. a + setdist({x},s) / (setdist({x},s) + setdist({x},t)) %
+                      (b - a:real^M)` THEN REWRITE_TAC[] THEN
+    SUBGOAL_THEN
+     `(!x:real^N. x IN u ==> (setdist({x},s) = &0 <=> x IN s)) /\
+      (!x:real^N. x IN u ==> (setdist({x},t) = &0 <=> x IN t))`
+    STRIP_ASSUME_TAC THENL
+     [ASM_REWRITE_TAC[SETDIST_EQ_0_SING] THEN CONJ_TAC THENL
+       [MP_TAC(ISPEC `s:real^N->bool` CLOSED_IN_CLOSED);
+        MP_TAC(ISPEC `t:real^N->bool` CLOSED_IN_CLOSED)] THEN
+      DISCH_THEN(MP_TAC o SPEC `u:real^N->bool`) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `v:real^N->bool`
+       (CONJUNCTS_THEN2 ASSUME_TAC SUBST_ALL_TAC)) THEN
+      ASM_MESON_TAC[CLOSURE_CLOSED; INTER_SUBSET; SUBSET_CLOSURE; SUBSET;
+                    IN_INTER; CLOSURE_SUBSET];
+      ALL_TAC] THEN
+    SUBGOAL_THEN `!x:real^N. x IN u ==> &0 < setdist({x},s) + setdist({x},t)`
+    ASSUME_TAC THENL
+     [REPEAT STRIP_TAC THEN MATCH_MP_TAC(REAL_ARITH
+        `&0 <= x /\ &0 <= y /\ ~(x = &0 /\ y = &0) ==> &0 < x + y`) THEN
+      REWRITE_TAC[SETDIST_POS_LE] THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+      REWRITE_TAC[real_div; GSYM VECTOR_MUL_ASSOC] THEN
+      REPEAT(MATCH_MP_TAC CONTINUOUS_ON_MUL THEN CONJ_TAC) THEN
+      REWRITE_TAC[CONTINUOUS_ON_CONST; o_DEF] THEN
+      REWRITE_TAC[CONTINUOUS_ON_LIFT_SETDIST] THEN
+      MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_ON_INV) THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_NZ] THEN
+      REWRITE_TAC[LIFT_ADD] THEN MATCH_MP_TAC CONTINUOUS_ON_ADD THEN
+      REWRITE_TAC[CONTINUOUS_ON_LIFT_SETDIST];
+      X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+      REWRITE_TAC[segment; IN_ELIM_THM] THEN
+      REWRITE_TAC[VECTOR_MUL_EQ_0; LEFT_OR_DISTRIB; VECTOR_ARITH
+       `a + x % (b - a):real^N = (&1 - u) % a + u % b <=>
+        (x - u) % (b - a) = vec 0`;
+       EXISTS_OR_THM] THEN
+      DISJ1_TAC THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN
+      REWRITE_TAC[REAL_SUB_0; UNWIND_THM1] THEN
+      ASM_SIMP_TAC[REAL_LE_DIV; REAL_LE_ADD; SETDIST_POS_LE; REAL_LE_LDIV_EQ;
+                   REAL_ARITH `a <= &1 * (a + b) <=> &0 <= b`];
+      REWRITE_TAC[VECTOR_ARITH `a + x:real^N = a <=> x = vec 0`];
+      REWRITE_TAC[VECTOR_ARITH `a + x % (b - a):real^N = b <=>
+                                (x - &1) % (b - a) = vec 0`]] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_EQ] THEN
+    ASM_SIMP_TAC[REAL_SUB_0; REAL_EQ_LDIV_EQ;
+                 REAL_MUL_LZERO; REAL_MUL_LID] THEN
+    REWRITE_TAC[REAL_ARITH `x:real = x + y <=> y = &0`] THEN
+    ASM_REWRITE_TAC[]) in
+  MATCH_MP_TAC(MESON[]
+   `(!s t. P s t <=> P t s) /\
+    (!s t. ~(s = {}) /\ ~(t = {}) ==> P s t) /\
+    P {} {} /\ (!t. ~(t = {}) ==> P {} t)
+    ==> !s t. P s t`) THEN
+  REPEAT CONJ_TAC THENL
+   [REPEAT GEN_TAC THEN
+    GEN_REWRITE_TAC (RAND_CONV o BINDER_CONV) [SWAP_FORALL_THM] THEN
+    REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+    REWRITE_TAC[SEGMENT_SYM; INTER_COMM; CONJ_ACI; EQ_SYM_EQ];
+    SIMP_TAC[lemma];
+    REPEAT STRIP_TAC THEN EXISTS_TAC `(\x. midpoint(a,b)):real^N->real^M` THEN
+    ASM_SIMP_TAC[NOT_IN_EMPTY; CONTINUOUS_ON_CONST; MIDPOINT_IN_SEGMENT] THEN
+    REWRITE_TAC[midpoint] THEN CONJ_TAC THEN GEN_TAC THEN DISCH_TAC THEN
+    UNDISCH_TAC `~(a:real^M = b)` THEN REWRITE_TAC[CONTRAPOS_THM] THEN
+    VECTOR_ARITH_TAC;
+    REPEAT STRIP_TAC THEN ASM_CASES_TAC `t:real^N->bool = u` THENL
+     [EXISTS_TAC `(\x. b):real^N->real^M` THEN
+      ASM_REWRITE_TAC[NOT_IN_EMPTY; ENDS_IN_SEGMENT; IN_UNIV;
+                      CONTINUOUS_ON_CONST];
+      SUBGOAL_THEN `?c:real^N. c IN u /\ ~(c IN t)` STRIP_ASSUME_TAC THENL
+       [REPEAT(FIRST_X_ASSUM(MP_TAC o MATCH_MP CLOSED_IN_SUBSET)) THEN
+        REWRITE_TAC[TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN ASM SET_TAC[];
+        ALL_TAC] THEN
+      MP_TAC(ISPECL [`{c:real^N}`; `t:real^N->bool`; `u:real^N->bool`;
+                     `midpoint(a,b):real^M`; `b:real^M`] lemma) THEN
+      ASM_REWRITE_TAC[CLOSED_IN_SING; MIDPOINT_EQ_ENDPOINT] THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[NOT_IN_EMPTY] THEN
+      X_GEN_TAC `f:real^N->real^M` THEN STRIP_TAC THEN CONJ_TAC THENL
+       [SUBGOAL_THEN
+         `segment[midpoint(a,b):real^M,b] SUBSET segment[a,b]` MP_TAC
+        THENL
+         [REWRITE_TAC[SUBSET; IN_SEGMENT; midpoint] THEN GEN_TAC THEN
+          DISCH_THEN(X_CHOOSE_THEN `u:real` STRIP_ASSUME_TAC) THEN
+          EXISTS_TAC `(&1 + u) / &2` THEN ASM_REWRITE_TAC[] THEN
+          REPEAT(CONJ_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC]) THEN
+          VECTOR_ARITH_TAC;
+          ASM SET_TAC[]];
+        SUBGOAL_THEN `~(a IN segment[midpoint(a,b):real^M,b])` MP_TAC THENL
+         [ALL_TAC; ASM_MESON_TAC[]] THEN
+        DISCH_THEN(MP_TAC o CONJUNCT2 o MATCH_MP DIST_IN_CLOSED_SEGMENT) THEN
+        REWRITE_TAC[DIST_MIDPOINT] THEN
+        UNDISCH_TAC `~(a:real^M = b)` THEN NORM_ARITH_TAC]]]);;
+
+let URYSOHN_LOCAL = prove
+ (`!s t u a b.
+        closed_in (subtopology euclidean u) s /\
+        closed_in (subtopology euclidean u) t /\
+        s INTER t = {}
+        ==> ?f:real^N->real^M.
+               f continuous_on u /\
+               (!x. x IN u ==> f(x) IN segment[a,b]) /\
+               (!x. x IN s ==> f x = a) /\
+               (!x. x IN t ==> f x = b)`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `a:real^M = b` THENL
+   [EXISTS_TAC `(\x. b):real^N->real^M` THEN
+    ASM_REWRITE_TAC[ENDS_IN_SEGMENT; CONTINUOUS_ON_CONST];
+    MP_TAC(ISPECL [`s:real^N->bool`; `t:real^N->bool`; `u:real^N->bool`;
+                   `a:real^M`; `b:real^M`] URYSOHN_LOCAL_STRONG) THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o MATCH_MP CLOSED_IN_SUBSET)) THEN
+    REWRITE_TAC[TOPSPACE_EUCLIDEAN_SUBTOPOLOGY] THEN SET_TAC[]]);;
+
+let URYSOHN_STRONG = prove
+ (`!s t a b.
+        closed s /\ closed t /\ s INTER t = {} /\ ~(a = b)
+        ==> ?f:real^N->real^M.
+               f continuous_on (:real^N) /\ (!x. f(x) IN segment[a,b]) /\
+               (!x. f x = a <=> x IN s) /\ (!x. f x = b <=> x IN t)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[CLOSED_IN] THEN
+  ONCE_REWRITE_TAC[GSYM SUBTOPOLOGY_UNIV] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP URYSOHN_LOCAL_STRONG) THEN
+  REWRITE_TAC[IN_UNIV]);;
+
+let URYSOHN = prove
+ (`!s t a b.
+        closed s /\ closed t /\ s INTER t = {}
+        ==> ?f:real^N->real^M.
+               f continuous_on (:real^N) /\ (!x. f(x) IN segment[a,b]) /\
+               (!x. x IN s ==> f x = a) /\ (!x. x IN t ==> f x = b)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[CLOSED_IN] THEN
+  ONCE_REWRITE_TAC[GSYM SUBTOPOLOGY_UNIV] THEN DISCH_THEN
+   (MP_TAC o ISPECL [`a:real^M`; `b:real^M`] o MATCH_MP URYSOHN_LOCAL) THEN
+  REWRITE_TAC[IN_UNIV]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Tietze extension theorem, likewise just for real^N.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let TIETZE_STEP = prove
+ (`!f:real^N->real^1 u s B.
+        &0 < B /\ closed_in (subtopology euclidean u) s /\
+        f continuous_on s /\
+        (!x. x IN s ==> norm(f x) <= B)
+        ==> ?g. g continuous_on u /\
+                (!x. x IN u ==> norm(g x) <= B / &3) /\
+                (!x. x IN s ==> norm(f x - g x) <= &2 / &3 * B)`,
+  REWRITE_TAC[NORM_REAL; GSYM drop; DROP_SUB] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`{x:real^N | x IN s /\ f x IN {y | drop y <= --(B / &3)}}`;
+                 `{x:real^N | x IN s /\ f x IN {y | drop y >= B / &3}}`;
+                 `u:real^N->bool`;
+                 `lift(--(B / &3))`; `lift(B / &3)`] URYSOHN_LOCAL) THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+     [ALL_TAC;
+      REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY; IN_INTER] THEN
+      ASM_REAL_ARITH_TAC] THEN
+    CONJ_TAC THEN MATCH_MP_TAC CLOSED_IN_TRANS THEN
+    EXISTS_TAC `s:real^N->bool` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE THEN
+    ASM_REWRITE_TAC[] THENL
+     [MP_TAC(ISPECL [`lift(&1)`; `--(B / &3)`] CLOSED_HALFSPACE_LE);
+      MP_TAC(ISPECL [`lift(&1)`; `B / &3`] CLOSED_HALFSPACE_GE)] THEN
+    REWRITE_TAC[DOT_1; GSYM drop; LIFT_DROP; REAL_MUL_LID];
+    ASM_SIMP_TAC[SEGMENT_1; IN_ELIM_THM; LIFT_DROP; IN_INTERVAL_1;
+                 REAL_ARITH `&0 < B ==> --(B / &3) <= B / &3`] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^1` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[NORM_REAL; GSYM drop] THEN
+    ASM_SIMP_TAC[GSYM REAL_BOUNDS_LE] THEN X_GEN_TAC `x:real^N` THEN
+    DISCH_TAC THEN REWRITE_TAC[DROP_SUB; REAL_BOUNDS_LE] THEN
+    FIRST_ASSUM(ASSUME_TAC o REWRITE_RULE[SUBSET] o MATCH_MP
+      CLOSED_IN_IMP_SUBSET) THEN
+    REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
+     (REAL_ARITH `drop(f x) <= --(B / &3) \/ drop(f x) >= B / &3 \/
+                  abs(drop(f(x:real^N))) <= B / &3`)
+    THENL
+     [UNDISCH_THEN
+       `!x:real^N. x IN s /\ drop(f x) <= --(B / &3) ==> g x = lift(--(B / &3))`
+       (MP_TAC o SPEC `x:real^N`);
+      UNDISCH_THEN
+       `!x:real^N. x IN s /\ drop(f x) >= B / &3 ==> g x = lift(B / &3)`
+       (MP_TAC o SPEC `x:real^N`);
+      MATCH_MP_TAC(REAL_ARITH
+       `abs(f) <= B / &3 /\ --(B / &3) <= g /\ g <= B / &3
+        ==> abs(f - g) <= &2 / &3 * B`)] THEN
+    ASM_SIMP_TAC[] THEN DISCH_THEN SUBST_ALL_TAC THEN
+    UNDISCH_THEN `!x:real^N. x IN s ==> abs(drop(f x)) <= B`
+        (MP_TAC o SPEC `x:real^N`) THEN
+    ASM_REWRITE_TAC[LIFT_DROP] THEN ASM_REAL_ARITH_TAC]);;
+
+let TIETZE = prove
+ (`!f:real^N->real^1 u s B.
+        &0 <= B /\
+        closed_in (subtopology euclidean u) s /\
+        f continuous_on s /\
+        (!x. x IN s ==> norm(f x) <= B)
+        ==> ?g. g continuous_on u /\
+                (!x. x IN s ==> g x = f x) /\
+                (!x. x IN u ==> norm(g x) <= B)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP (REAL_ARITH
+   `&0 <= B ==> B = &0 \/ &0 < B`)) THEN
+  DISCH_THEN(DISJ_CASES_THEN2 SUBST_ALL_TAC ASSUME_TAC) THENL
+   [EXISTS_TAC `\x:real^N. (vec 0:real^1)` THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_CONST; NORM_0; REAL_LE_REFL] THEN
+    ASM_MESON_TAC[NORM_LE_0];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL [`f:real^N->real^1`; `u:real^N->bool`;
+       `s:real^N->bool`; `B:real`]
+        TIETZE_STEP) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g0:real^N->real^1` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `?g. (g 0 = (g0:real^N->real^1)) /\
+        (!n. g(SUC n) =
+               @h. h continuous_on u /\
+                   (!x. x IN u ==>
+                        norm(h x) <= &2 pow SUC n * B / &3 pow (SUC n + 1)) /\
+                   (!x. x IN s ==> norm(f x - vsum(0..n) (\i. g i x) - h x)
+                       <= &2 pow (SUC n + 1) * B / &3 pow (SUC n + 1)))`
+  STRIP_ASSUME_TAC THENL
+   [SIMP_TAC[VSUM_REAL; FINITE_NUMSEG; o_DEF] THEN
+    W(ACCEPT_TAC o prove_general_recursive_function_exists o snd);
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!n. (!m. m < n ==> g m continuous_on u) /\
+        g n continuous_on u /\
+        (!x. x IN u ==> norm(g n x:real^1) <= &2 pow n * B / &3 pow (n + 1)) /\
+        (!x:real^N. x IN s ==> norm(f x - vsum(0..n) (\i. g i x))
+        <= &2 pow (n + 1) * B / &3 pow (n + 1))`
+  ASSUME_TAC THENL
+   [INDUCT_TAC THEN ASM_REWRITE_TAC[VSUM_CLAUSES_NUMSEG; LT] THENL
+     [CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+      ASM_REWRITE_TAC[REAL_MUL_LID; REAL_ARITH `&2 * B / &3 = &2 / &3 * B`];
+      ALL_TAC] THEN
+    ASM_REWRITE_TAC[MESON[] `(!m:num. m = n \/ m < n ==> P m) <=>
+                             (!m. m < n ==> P m) /\ P n`] THEN
+    REWRITE_TAC[LE_0; VECTOR_ARITH `f - (g + h):real^1 = f - g - h`] THEN
+    CONV_TAC SELECT_CONV THEN
+    REWRITE_TAC[REAL_POW_ADD; REAL_ARITH
+     `(&2 pow (SUC n) * &2 pow 1) * B = &2 * &2 pow (SUC n) * B`] THEN
+    REWRITE_TAC[real_div; REAL_INV_MUL; REAL_POW_1] THEN
+    REWRITE_TAC[REAL_ARITH `a * b * inv c * inv d = (a * b / c) / d`] THEN
+    REWRITE_TAC[REAL_ARITH `&2 * x / &3 = &2 / &3 * x`] THEN
+    MATCH_MP_TAC TIETZE_STEP THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; ADD1; REAL_LT_MUL; REAL_POW_LT;
+                 REAL_OF_NUM_LT; ARITH] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_SUB THEN ASM_REWRITE_TAC[ETA_AX] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_VSUM THEN
+    REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG; LE_0] THEN REWRITE_TAC[LE_LT] THEN
+    GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+    EXISTS_TAC `u:real^N->bool` THEN ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  ABBREV_TAC `(h:num->real^N->real^1) = \n x. vsum(0..n) (\i. g i x)` THEN
+  SUBGOAL_THEN
+   `?k:real^N->real^1.
+     !e. &0 < e
+         ==> ?N:num. !n x.
+                 N <= n /\ x IN u ==> dist(vsum (from 0 INTER (0..n))
+                                                  (\i. g i x),k x) < e`
+  MP_TAC THENL
+   [REWRITE_TAC[SERIES_CAUCHY_UNIFORM]; ALL_TAC] THEN
+  REWRITE_TAC[FROM_0; INTER_UNIV; IN_UNIV] THENL
+   [X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    MP_TAC(ISPECL [`&2 / &3`; `e / B`] REAL_ARCH_POW_INV) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`m:num`; `n:num`; `x:real^N`] THEN DISCH_TAC THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `sum(m..n) (\i. &2 pow i * B / &3 pow (i + 1))` THEN
+    ASM_SIMP_TAC[VSUM_NORM_LE; FINITE_NUMSEG] THEN
+    REWRITE_TAC[REAL_POW_ADD; real_div; REAL_INV_MUL] THEN
+    REWRITE_TAC[REAL_ARITH `x * B * inv y * inv(&3 pow 1) = B / &3 * x / y`;
+                SUM_LMUL; GSYM REAL_POW_DIV] THEN
+    REWRITE_TAC[SUM_GP] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    COND_CASES_TAC THENL
+     [ASM_REWRITE_TAC[real_div; REAL_MUL_LZERO; REAL_MUL_RZERO]; ALL_TAC] THEN
+    REWRITE_TAC[REAL_ARITH `B / &3 * x / (&1 / &3) < e <=> x * B < e`] THEN
+    ASM_SIMP_TAC[GSYM REAL_LT_RDIV_EQ] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < y /\ x < e ==> x - y < e`) THEN
+    ASM_SIMP_TAC[REAL_POW_LT; REAL_LT_DIV; REAL_OF_NUM_LT; ARITH] THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `(&2 / &3) pow N` THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_POW_MONO_INV THEN
+    ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real^N->real^1` THEN
+  DISCH_TAC THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC(ISPEC `sequentially` CONTINUOUS_UNIFORM_LIMIT) THEN
+    EXISTS_TAC `\n x:real^N. vsum (0..n) (\i. g i x :real^1)` THEN
+    ASM_REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; EVENTUALLY_SEQUENTIALLY] THEN
+    ASM_REWRITE_TAC[IN_UNIV; IMP_IMP; RIGHT_IMP_FORALL_THM; GSYM dist] THEN
+    EXISTS_TAC `0` THEN REPEAT STRIP_TAC THEN
+    MATCH_MP_TAC CONTINUOUS_ON_VSUM THEN ASM_REWRITE_TAC[FINITE_NUMSEG];
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MATCH_MP_TAC(NORM_ARITH `~(&0 < norm(x - y)) ==> x = y`) THEN
+    DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `norm((k:real^N->real^1) x - f x) / &2`) THEN
+    ASM_REWRITE_TAC[REAL_HALF; NOT_EXISTS_THM] THEN
+    X_GEN_TAC `N1:num` THEN DISCH_THEN(LABEL_TAC "*") THEN
+    MP_TAC(ISPECL [`&2 / &3`; `norm((k:real^N->real^1) x - f x) / &2 / B`]
+        REAL_ARCH_POW_INV) THEN
+    ASM_SIMP_TAC[REAL_LT_DIV; REAL_HALF] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_SIMP_TAC[REAL_LT_RDIV_EQ] THEN
+    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `N2:num` (LABEL_TAC "+")) THEN
+    REMOVE_THEN "*" (MP_TAC o SPECL [`N1 + N2:num`; `x:real^N`]) THEN
+    REWRITE_TAC[LE_ADD; NOT_IMP] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN MATCH_MP_TAC(NORM_ARITH
+     `norm(f - s) < norm(k - f) / &2
+      ==> ~(dist(s,k) < norm(k - f) / &2)`) THEN
+    MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `B * (&2 / &3) pow N2` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `&2 pow ((N1 + N2) + 1) * B / &3 pow ((N1 + N2) + 1)` THEN
+    ASM_SIMP_TAC[] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `x * B / y = B * x / y`] THEN
+    ASM_SIMP_TAC[REAL_LE_LMUL_EQ; GSYM REAL_POW_DIV] THEN
+    MATCH_MP_TAC REAL_POW_MONO_INV THEN
+    ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN ARITH_TAC;
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MATCH_MP_TAC(ISPEC `sequentially` LIM_NORM_UBOUND) THEN
+    EXISTS_TAC `\n. vsum(0..n) (\i. (g:num->real^N->real^1) i x)` THEN
+    REWRITE_TAC[TRIVIAL_LIMIT_SEQUENTIALLY; EVENTUALLY_SEQUENTIALLY] THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[LIM_SEQUENTIALLY] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+    EXISTS_TAC `0` THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `sum(0..n) (\i. &2 pow i * B / &3 pow (i + 1))` THEN
+    ASM_SIMP_TAC[VSUM_NORM_LE; FINITE_NUMSEG] THEN
+    REWRITE_TAC[REAL_POW_ADD; real_div; REAL_INV_MUL] THEN
+    REWRITE_TAC[REAL_ARITH `x * B * inv y * inv(&3 pow 1) = B / &3 * x / y`;
+                SUM_LMUL; GSYM REAL_POW_DIV] THEN
+    REWRITE_TAC[REAL_ARITH `B / &3 * x <= B <=> B * x / &3 <= B * &1`] THEN
+    ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN
+    REWRITE_TAC[SUM_GP] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    COND_CASES_TAC THENL
+     [SIMP_TAC[real_div; REAL_MUL_LZERO; REAL_MUL_RZERO; REAL_POS];
+      ALL_TAC] THEN
+    REWRITE_TAC[REAL_ARITH `x / (&1 / &3) <= &3 <=> x <= &1`] THEN
+    REWRITE_TAC[REAL_ARITH `&1 - x <= &1 <=> &0 <= x`] THEN
+    MATCH_MP_TAC REAL_POW_LE THEN CONV_TAC REAL_RAT_REDUCE_CONV]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The same result for intervals in real^1.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let TIETZE_CLOSED_INTERVAL_1 = prove
+ (`!f:real^N->real^1 u s a b.
+        drop a <= drop b /\
+        closed_in (subtopology euclidean u) s /\
+        f continuous_on s /\
+        (!x. x IN s ==> f x IN interval[a,b])
+        ==> ?g. g continuous_on u /\
+                (!x. x IN s ==> g x = f x) /\
+                (!x. x IN u ==> g(x) IN interval[a,b])`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\x. (f:real^N->real^1)(x) - inv(&2) % (a + b)`;
+             `u:real^N->bool`; `s:real^N->bool`; `(drop(b) - drop(a)) / &2`]
+        TIETZE) THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL [ASM_ARITH_TAC; ALL_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
+    REWRITE_TAC[IN_INTERVAL_1; NORM_REAL; GSYM drop] THEN
+    REWRITE_TAC[DROP_ADD; DROP_CMUL; DROP_SUB] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^1` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `\x. (g:real^N->real^1)(x) + inv(&2) % (a + b)` THEN
+  REPEAT CONJ_TAC THENL
+   [ASM_SIMP_TAC[CONTINUOUS_ON_ADD; CONTINUOUS_ON_CONST];
+    REPEAT STRIP_TAC THEN ASM_SIMP_TAC[] THEN VECTOR_ARITH_TAC;
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN UNDISCH_TAC
+     `!x. x IN u ==> norm((g:real^N->real^1) x) <= (drop b - drop a) / &2` THEN
+    DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[IN_INTERVAL_1; NORM_REAL; GSYM drop] THEN
+    REWRITE_TAC[DROP_ADD; DROP_CMUL; DROP_SUB] THEN REAL_ARITH_TAC]);;
+
+let TIETZE_OPEN_INTERVAL_1 = prove
+ (`!f:real^N->real^1 u s a b.
+        drop a < drop b /\
+        closed_in (subtopology euclidean u) s /\
+        f continuous_on s /\
+        (!x. x IN s ==> f x IN interval(a,b))
+        ==> ?g. g continuous_on u /\
+                (!x. x IN s ==> g x = f x) /\
+                (!x. x IN u ==> g(x) IN interval(a,b))`,
+  REWRITE_TAC[IN_INTERVAL_1] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^N->real^1`; `u:real^N->bool`; `s:real^N->bool`;
+                 `a:real^1`; `b:real^1`] TIETZE_CLOSED_INTERVAL_1) THEN
+  ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ASM_MESON_TAC[IN_INTERVAL_1; REAL_LT_IMP_LE]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^1` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`s:real^N->bool`;
+                 `{x | x IN u /\ (g:real^N->real^1) x IN {a,b}}`;
+                 `u:real^N->bool`;
+                 `vec 1:real^1`; `vec 0:real^1`] URYSOHN_LOCAL) THEN
+  ASM_REWRITE_TAC[SEGMENT_1; DROP_VEC; REAL_OF_NUM_LE; ARITH] THEN
+  REWRITE_TAC[IN_INTERVAL_1; DROP_VEC] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_CLOSED_IN_PREIMAGE THEN
+      ASM_SIMP_TAC[FINITE_IMP_CLOSED; FINITE_INSERT; FINITE_EMPTY] THEN
+      ASM_MESON_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_AT; OPEN_UNIV; IN_UNIV];
+      RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+      ASM SET_TAC[REAL_LT_REFL]];
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `h:real^N->real^1` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(\x. &1 / &2 % (a + b) +
+                    drop(h x) % (g x - &1 / &2 % (a + b))):real^N->real^1` THEN
+    ASM_SIMP_TAC[DROP_CMUL; DROP_VEC; VECTOR_MUL_LID] THEN
+    REWRITE_TAC[VECTOR_ARITH `a + x - a:real^N = x`] THEN CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_ON_ADD THEN REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_MUL THEN
+      ASM_SIMP_TAC[CONTINUOUS_ON_SUB; CONTINUOUS_ON_CONST; ETA_AX] THEN
+      ASM_REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX];
+      ALL_TAC] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    REWRITE_TAC[DROP_ADD; DROP_CMUL; DROP_SUB] THEN
+    REWRITE_TAC[REAL_ARITH
+     `a < &1 / &2 * (a + b) + x /\ &1 / &2 * (a + b) + x < b <=>
+      abs(x) < &1 * (b - a) / &2`] THEN
+    ASM_CASES_TAC `(g:real^N->real^1) x IN {a,b}` THENL
+     [ASM_SIMP_TAC[DROP_VEC; REAL_MUL_LZERO] THEN ASM_REAL_ARITH_TAC;
+      REWRITE_TAC[REAL_ABS_MUL] THEN MATCH_MP_TAC(REAL_ARITH
+       `y < a /\ abs(x) * y <= &1 * y ==> abs(x) * y < a`) THEN
+      CONJ_TAC THENL
+       [REWRITE_TAC[REAL_MUL_LID] THEN MATCH_MP_TAC(REAL_ARITH
+         `a < x /\ x < b ==> abs(x - &1 / &2 * (a + b)) < (b - a) / &2`) THEN
+        RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL_1]) THEN
+        ASM_REWRITE_TAC[REAL_LT_LE; DROP_EQ] THEN ASM SET_TAC[];
+        MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[REAL_ABS_POS] THEN
+        REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`)) THEN
+        FIRST_ASSUM(MP_TAC o MATCH_MP CLOSED_IN_IMP_SUBSET) THEN
+        ASM_SIMP_TAC[SUBSET] THEN REAL_ARITH_TAC]]]);;
+
+let TIETZE_UNBOUNDED_1 = prove
+ (`!f:real^N->real^1 u s.
+        closed_in (subtopology euclidean u) s  /\ f continuous_on s
+        ==> ?g. g continuous_on u /\ (!x. x IN s ==> g x = f x)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`vec 0:real^1`; `vec 1:real^1`]
+    HOMEOMORPHIC_OPEN_INTERVAL_UNIV) THEN
+  REWRITE_TAC[INTERVAL_NE_EMPTY; VEC_COMPONENT; REAL_LT_01] THEN
+  REWRITE_TAC[HOMEOMORPHIC_MINIMAL; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`h:real^1->real^1`; `k:real^1->real^1`] THEN
+  REWRITE_TAC[IN_UNIV] THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`(k:real^1->real^1) o (f:real^N->real^1)`; `u:real^N->bool`;
+                 `s:real^N->bool`; `vec 0:real^1`; `vec 1:real^1`]
+        TIETZE_OPEN_INTERVAL_1) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[DROP_VEC; REAL_LT_01; o_THM] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+    EXISTS_TAC `(:real^1)` THEN ASM_REWRITE_TAC[SUBSET_UNIV];
+    DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^1` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(h:real^1->real^1) o (g:real^N->real^1)` THEN
+    ASM_SIMP_TAC[o_THM] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN ASM_REWRITE_TAC[] THEN
+   MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+   EXISTS_TAC `interval(vec 0:real^1,vec 1)` THEN
+   ASM_REWRITE_TAC[SUBSET_UNIV] THEN ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Now for general intervals in real^N by componentwise extension.           *)
+(* ------------------------------------------------------------------------- *)
+
+let TIETZE_CLOSED_INTERVAL = prove
+ (`!f:real^M->real^N u s a b.
+        ~(interval[a,b] = {}) /\
+        closed_in (subtopology euclidean u) s /\
+        f continuous_on s /\
+        (!x. x IN s ==> f x IN interval[a,b])
+        ==> ?g. g continuous_on u /\
+                (!x. x IN s ==> g x = f x) /\
+                (!x. x IN u ==> g(x) IN interval[a,b])`,
+  REWRITE_TAC[INTERVAL_NE_EMPTY] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!i. 1 <= i /\ i <= dimindex(:N)
+        ==> ?g. g continuous_on u /\
+                (!x. x IN s ==> g x = lift((f:real^M->real^N)(x)$i)) /\
+                (!x. x IN u ==>
+                      g(x) IN interval[lift((a:real^N)$i),lift((b:real^N)$i)])`
+  MP_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC TIETZE_CLOSED_INTERVAL_1 THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL]) THEN
+    ASM_SIMP_TAC[IN_INTERVAL_1; LIFT_DROP] THEN
+    SUBGOAL_THEN `(\x. lift((f:real^M->real^N) x$i)) = (\x. lift(x$i)) o f`
+    SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT; CONTINUOUS_ON_COMPOSE];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; IN_INTERVAL_1; LIFT_DROP] THEN
+  DISCH_THEN(X_CHOOSE_TAC `g:num->real^M->real^1`) THEN
+  EXISTS_TAC `(\x. lambda i. drop(g i x)):real^M->real^N` THEN
+  SIMP_TAC[CART_EQ; IN_INTERVAL; LAMBDA_BETA] THEN CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[CONTINUOUS_ON_COMPONENTWISE_LIFT] THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; LIFT_DROP; ETA_AX];
+    ASM_SIMP_TAC[LIFT_DROP]]);;
+
+let TIETZE_OPEN_INTERVAL = prove
+ (`!f:real^M->real^N u s a b.
+        ~(interval(a,b) = {}) /\
+        closed_in (subtopology euclidean u) s /\
+        f continuous_on s /\
+        (!x. x IN s ==> f x IN interval(a,b))
+        ==> ?g. g continuous_on u /\
+                (!x. x IN s ==> g x = f x) /\
+                (!x. x IN u ==> g(x) IN interval(a,b))`,
+  REWRITE_TAC[INTERVAL_NE_EMPTY] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!i. 1 <= i /\ i <= dimindex(:N)
+        ==> ?g. g continuous_on u /\
+                (!x. x IN s ==> g x = lift((f:real^M->real^N)(x)$i)) /\
+                (!x. x IN u ==>
+                      g(x) IN interval(lift((a:real^N)$i),lift((b:real^N)$i)))`
+  MP_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC TIETZE_OPEN_INTERVAL_1 THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL]) THEN
+    ASM_SIMP_TAC[IN_INTERVAL_1; LIFT_DROP] THEN
+    SUBGOAL_THEN `(\x. lift((f:real^M->real^N) x$i)) = (\x. lift(x$i)) o f`
+    SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT; CONTINUOUS_ON_COMPOSE];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; IN_INTERVAL_1; LIFT_DROP] THEN
+  DISCH_THEN(X_CHOOSE_TAC `g:num->real^M->real^1`) THEN
+  EXISTS_TAC `(\x. lambda i. drop(g i x)):real^M->real^N` THEN
+  SIMP_TAC[CART_EQ; IN_INTERVAL; LAMBDA_BETA] THEN CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[CONTINUOUS_ON_COMPONENTWISE_LIFT] THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; LIFT_DROP; ETA_AX];
+    ASM_SIMP_TAC[LIFT_DROP]]);;
+
+let TIETZE_UNBOUNDED = prove
+ (`!f:real^M->real^N u s.
+        closed_in (subtopology euclidean u) s /\ f continuous_on s
+        ==> ?g. g continuous_on u /\
+                (!x. x IN s ==> g x = f x)`,
+  REWRITE_TAC[INTERVAL_NE_EMPTY] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!i. 1 <= i /\ i <= dimindex(:N)
+        ==> ?g. g continuous_on u /\
+                (!x. x IN s ==> g x = lift((f:real^M->real^N)(x)$i))`
+  MP_TAC THENL
+   [REPEAT STRIP_TAC THEN MATCH_MP_TAC TIETZE_UNBOUNDED_1 THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[IN_INTERVAL]) THEN
+    ASM_SIMP_TAC[IN_INTERVAL_1; LIFT_DROP] THEN
+    SUBGOAL_THEN `(\x. lift((f:real^M->real^N) x$i)) = (\x. lift(x$i)) o f`
+    SUBST1_TAC THENL [REWRITE_TAC[o_DEF]; ALL_TAC] THEN
+    ASM_SIMP_TAC[CONTINUOUS_ON_LIFT_COMPONENT; CONTINUOUS_ON_COMPOSE];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; IN_INTERVAL_1; LIFT_DROP] THEN
+  DISCH_THEN(X_CHOOSE_TAC `g:num->real^M->real^1`) THEN
+  EXISTS_TAC `(\x. lambda i. drop(g i x)):real^M->real^N` THEN
+  SIMP_TAC[CART_EQ; IN_INTERVAL; LAMBDA_BETA] THEN CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[CONTINUOUS_ON_COMPONENTWISE_LIFT] THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; LIFT_DROP; ETA_AX];
+    ASM_SIMP_TAC[LIFT_DROP]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Countability of some relevant sets.                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let COUNTABLE_INTEGER = prove
+ (`COUNTABLE integer`,
+  MATCH_MP_TAC COUNTABLE_SUBSET THEN EXISTS_TAC
+   `IMAGE (\n. (&n:real)) (:num) UNION IMAGE (\n. --(&n)) (:num)` THEN
+  SIMP_TAC[COUNTABLE_IMAGE; COUNTABLE_UNION; NUM_COUNTABLE] THEN
+  REWRITE_TAC[SUBSET; IN_UNION; IN_IMAGE; IN_UNIV] THEN
+  REWRITE_TAC[IN; INTEGER_CASES]);;
+
+let CARD_EQ_INTEGER = prove
+ (`integer =_c (:num)`,
+  REWRITE_TAC[GSYM CARD_LE_ANTISYM; GSYM COUNTABLE_ALT; COUNTABLE_INTEGER] THEN
+  REWRITE_TAC[le_c] THEN EXISTS_TAC `real_of_num` THEN
+  REWRITE_TAC[IN_UNIV; REAL_OF_NUM_EQ] THEN
+  REWRITE_TAC[IN; INTEGER_CLOSED]);;
+
+let COUNTABLE_RATIONAL = prove
+ (`COUNTABLE rational`,
+  MATCH_MP_TAC COUNTABLE_SUBSET THEN
+  EXISTS_TAC `IMAGE (\(x,y). x / y) (integer CROSS integer)` THEN
+  SIMP_TAC[COUNTABLE_IMAGE; COUNTABLE_CROSS; COUNTABLE_INTEGER] THEN
+  REWRITE_TAC[SUBSET; IN_IMAGE; EXISTS_PAIR_THM; IN_CROSS] THEN
+  REWRITE_TAC[rational; IN] THEN MESON_TAC[]);;
+
+let CARD_EQ_RATIONAL = prove
+ (`rational =_c (:num)`,
+  REWRITE_TAC[GSYM CARD_LE_ANTISYM; GSYM COUNTABLE_ALT; COUNTABLE_RATIONAL] THEN
+  REWRITE_TAC[le_c] THEN EXISTS_TAC `real_of_num` THEN
+  REWRITE_TAC[IN_UNIV; REAL_OF_NUM_EQ] THEN
+  REWRITE_TAC[IN; RATIONAL_CLOSED]);;
+
+let COUNTABLE_INTEGER_COORDINATES = prove
+ (`COUNTABLE { x:real^N | !i. 1 <= i /\ i <= dimindex(:N) ==> integer(x$i) }`,
+  MATCH_MP_TAC COUNTABLE_CART THEN
+  REWRITE_TAC[SET_RULE `{x | P x} = P`; COUNTABLE_INTEGER]);;
+
+let COUNTABLE_RATIONAL_COORDINATES = prove
+ (`COUNTABLE { x:real^N | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i) }`,
+  MATCH_MP_TAC COUNTABLE_CART THEN
+  REWRITE_TAC[SET_RULE `{x | P x} = P`; COUNTABLE_RATIONAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Density of points with rational, or just dyadic rational, coordinates.    *)
+(* ------------------------------------------------------------------------- *)
+
+let CLOSURE_DYADIC_RATIONALS = prove
+ (`closure { inv(&2 pow n) % x |n,x|
+             !i. 1 <= i /\ i <= dimindex(:N) ==> integer(x$i) } = (:real^N)`,
+  REWRITE_TAC[EXTENSION; CLOSURE_APPROACHABLE; IN_UNIV; EXISTS_IN_GSPEC] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `e:real`] THEN DISCH_TAC THEN
+  MP_TAC(SPECL [`inv(&2)`; `e / &(dimindex(:N))`] REAL_ARCH_POW_INV) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1;
+               REAL_POW_INV; REAL_LT_RDIV_EQ] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN MATCH_MP_TAC MONO_EXISTS THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+  EXISTS_TAC `(lambda i. floor(&2 pow n * (x:real^N)$i)):real^N` THEN
+  ASM_SIMP_TAC[LAMBDA_BETA; FLOOR; dist; NORM_MUL] THEN
+  MATCH_MP_TAC(MATCH_MP (REWRITE_RULE[IMP_CONJ] REAL_LET_TRANS)
+   (SPEC_ALL NORM_LE_L1)) THEN
+  SIMP_TAC[LAMBDA_BETA; VECTOR_SUB_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `&(dimindex(:N)) * inv(&2 pow n)` THEN ASM_REWRITE_TAC[] THEN
+  GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o RAND_CONV) [GSYM CARD_NUMSEG_1] THEN
+  MATCH_MP_TAC SUM_BOUND THEN REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+  X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_RID] THEN
+  SIMP_TAC[REAL_ABS_MUL; REAL_POW_EQ_0; REAL_OF_NUM_EQ; ARITH;
+    REAL_FIELD `~(a = &0) ==> inv a * b - x = inv a * (b - a * x)`] THEN
+  MATCH_MP_TAC REAL_LE_MUL2 THEN REWRITE_TAC[REAL_ABS_POS] THEN
+  REWRITE_TAC[REAL_LE_REFL; REAL_ABS_POW; REAL_ABS_INV; REAL_ABS_NUM] THEN
+  MP_TAC(SPEC `&2 pow n * (x:real^N)$k` FLOOR) THEN REAL_ARITH_TAC);;
+
+let CLOSURE_RATIONAL_COORDINATES = prove
+ (`closure { x | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i) } =
+   (:real^N)`,
+  MATCH_MP_TAC(SET_RULE `!s. s SUBSET t /\ s = UNIV ==> t = UNIV`) THEN
+  EXISTS_TAC
+   `closure { inv(&2 pow n) % x:real^N |n,x|
+              !i. 1 <= i /\ i <= dimindex(:N) ==> integer(x$i) }` THEN
+
+  CONJ_TAC THENL [ALL_TAC; REWRITE_TAC[CLOSURE_DYADIC_RATIONALS]] THEN
+  MATCH_MP_TAC SUBSET_CLOSURE THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_ELIM_THM; VECTOR_MUL_COMPONENT] THEN
+  ASM_SIMP_TAC[RATIONAL_CLOSED]);;
+
+let CLOSURE_DYADIC_RATIONALS_IN_OPEN_SET = prove
+ (`!s:real^N->bool.
+        open s
+        ==> closure(s INTER
+                    { inv(&2 pow n) % x | n,x |
+                      !i. 1 <= i /\ i <= dimindex(:N) ==> integer(x$i) }) =
+            closure s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSURE_OPEN_INTER_SUPERSET THEN
+  ASM_REWRITE_TAC[CLOSURE_DYADIC_RATIONALS; SUBSET_UNIV]);;
+
+let CLOSURE_RATIONALS_IN_OPEN_SET = prove
+ (`!s:real^N->bool.
+        open s
+        ==> closure(s INTER
+                    { inv(&2 pow n) % x | n,x |
+                      !i. 1 <= i /\ i <= dimindex(:N) ==> integer(x$i) }) =
+            closure s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CLOSURE_OPEN_INTER_SUPERSET THEN
+  ASM_REWRITE_TAC[CLOSURE_DYADIC_RATIONALS; SUBSET_UNIV]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Various separability-type properties.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let UNIV_SECOND_COUNTABLE = prove
+ (`?b. COUNTABLE b /\ (!c. c IN b ==> open c) /\
+       !s:real^N->bool. open s ==> ?u. u SUBSET b /\ s = UNIONS u`,
+  EXISTS_TAC
+   `IMAGE (\(v:real^N,q). ball(v,q))
+          ({v | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(v$i)} CROSS
+           rational)` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC COUNTABLE_IMAGE THEN MATCH_MP_TAC COUNTABLE_CROSS THEN
+    REWRITE_TAC[COUNTABLE_RATIONAL] THEN MATCH_MP_TAC COUNTABLE_CART THEN
+    REWRITE_TAC[COUNTABLE_RATIONAL; SET_RULE `{x | P x} = P`];
+    REWRITE_TAC[FORALL_IN_IMAGE; CROSS; FORALL_IN_GSPEC; OPEN_BALL];
+    REPEAT STRIP_TAC THEN
+    ASM_CASES_TAC `s:real^N->bool = {}` THENL
+     [EXISTS_TAC `{}:(real^N->bool)->bool` THEN
+      ASM_REWRITE_TAC[UNIONS_0; EMPTY_SUBSET];
+      ALL_TAC] THEN
+    EXISTS_TAC `{c | c IN IMAGE (\(v:real^N,q). ball(v,q))
+          ({v | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(v$i)} CROSS
+           rational) /\ c SUBSET s}` THEN
+    CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL [ALL_TAC; SET_TAC[]] THEN
+    REWRITE_TAC[SUBSET; IN_UNIONS; IN_ELIM_THM] THEN
+    REWRITE_TAC[GSYM CONJ_ASSOC; EXISTS_IN_IMAGE] THEN
+    REWRITE_TAC[CROSS; EXISTS_PAIR_THM; EXISTS_IN_GSPEC] THEN
+    REWRITE_TAC[IN_ELIM_PAIR_THM] THEN X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [OPEN_CONTAINS_BALL]) THEN
+    DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+    ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; SUBSET; IN_BALL] THEN
+    X_GEN_TAC `e:real` THEN STRIP_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    MP_TAC(REWRITE_RULE[EXTENSION; IN_UNIV] CLOSURE_RATIONAL_COORDINATES) THEN
+    REWRITE_TAC[CLOSURE_APPROACHABLE] THEN
+    DISCH_THEN(MP_TAC o SPECL [`x:real^N`; `e / &4`]) THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; REWRITE_TAC[IN_ELIM_THM]] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `y:real^N` THEN STRIP_TAC THEN
+    SUBGOAL_THEN `?x. rational x /\ e / &3 < x /\ x < e / &2`
+     (X_CHOOSE_THEN `q:real` STRIP_ASSUME_TAC)
+    THENL
+     [MP_TAC(ISPECL [`&5 / &12 * e`; `e / &12`] RATIONAL_APPROXIMATION) THEN
+      ANTS_TAC THENL [ASM_REAL_ARITH_TAC; MATCH_MP_TAC MONO_EXISTS] THEN
+      SIMP_TAC[] THEN REAL_ARITH_TAC;
+      EXISTS_TAC `q:real` THEN ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+       [ASM_REWRITE_TAC[IN];
+        REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+        REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC;
+        ASM_REAL_ARITH_TAC]]]);;
+
+let UNIV_SECOND_COUNTABLE_SEQUENCE = prove
+ (`?b:num->real^N->bool.
+        (!m n. b m = b n <=> m = n) /\
+        (!n. open(b n)) /\
+        (!s. open s ==> ?k. s = UNIONS {b n | n IN k})`,
+  X_CHOOSE_THEN `bb:(real^N->bool)->bool` STRIP_ASSUME_TAC
+    UNIV_SECOND_COUNTABLE THEN
+  MP_TAC(ISPEC `bb:(real^N->bool)->bool` COUNTABLE_AS_INJECTIVE_IMAGE) THEN
+  ANTS_TAC THENL
+   [ASM_REWRITE_TAC[INFINITE] THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `INFINITE {ball(vec 0:real^N,inv(&n + &1)) | n IN (:num)}`
+    MP_TAC THENL
+     [REWRITE_TAC[SIMPLE_IMAGE] THEN MATCH_MP_TAC(REWRITE_RULE
+       [RIGHT_IMP_FORALL_THM; IMP_IMP] INFINITE_IMAGE_INJ) THEN
+      REWRITE_TAC[num_INFINITE] THEN MATCH_MP_TAC WLOG_LT THEN SIMP_TAC[] THEN
+      CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+      MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN DISCH_TAC THEN
+      REWRITE_TAC[EXTENSION] THEN
+      DISCH_THEN(MP_TAC o SPEC `inv(&n + &1) % basis 1:real^N`) THEN
+      REWRITE_TAC[IN_BALL; DIST_0; NORM_MUL; REAL_ABS_INV] THEN
+      SIMP_TAC[NORM_BASIS; DIMINDEX_GE_1; LE_REFL; REAL_MUL_RID] THEN
+      ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN
+      REWRITE_TAC[REAL_ARITH `abs(&n + &1) = &n + &1`; REAL_LT_REFL] THEN
+      MATCH_MP_TAC REAL_LT_INV2 THEN
+      REWRITE_TAC[REAL_OF_NUM_LT; REAL_OF_NUM_ADD] THEN ASM_ARITH_TAC;
+      REWRITE_TAC[INFINITE; SIMPLE_IMAGE] THEN
+      MATCH_MP_TAC FINITE_SUBSET THEN
+      EXISTS_TAC `IMAGE UNIONS {u | u SUBSET bb} :(real^N->bool)->bool` THEN
+      ASM_SIMP_TAC[FINITE_IMAGE; FINITE_POWERSET] THEN
+      GEN_REWRITE_TAC I [SUBSET] THEN SIMP_TAC[FORALL_IN_IMAGE; IN_UNIV] THEN
+      X_GEN_TAC `n:num` THEN REWRITE_TAC[IN_IMAGE; IN_ELIM_THM] THEN
+      ASM_MESON_TAC[OPEN_BALL]];
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:num->real^N->bool` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 SUBST_ALL_TAC ASSUME_TAC) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[FORALL_IN_IMAGE; IN_UNIV]) THEN
+    REPEAT(CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC]) THEN
+    X_GEN_TAC `s:real^N->bool` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `s:real^N->bool`) THEN
+    ASM_REWRITE_TAC[SUBSET_IMAGE; LEFT_AND_EXISTS_THM; SUBSET_UNIV] THEN
+    ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[SIMPLE_IMAGE]]);;
+
+let SUBSET_SECOND_COUNTABLE = prove
+ (`!s:real^N->bool.
+       ?b. COUNTABLE b /\
+           (!c. c IN b ==> ~(c = {}) /\ open_in(subtopology euclidean s) c) /\
+           !t. open_in(subtopology euclidean s) t
+               ==> ?u. u SUBSET b /\ t = UNIONS u`,
+  GEN_TAC THEN
+  SUBGOAL_THEN
+   `?b. COUNTABLE b /\
+           (!c:real^N->bool. c IN b ==> open_in(subtopology euclidean s) c) /\
+           !t. open_in(subtopology euclidean s) t
+               ==> ?u. u SUBSET b /\ t = UNIONS u`
+  STRIP_ASSUME_TAC THENL
+   [X_CHOOSE_THEN `B:(real^N->bool)->bool` STRIP_ASSUME_TAC
+      UNIV_SECOND_COUNTABLE THEN
+    EXISTS_TAC `{s INTER c :real^N->bool | c IN B}` THEN
+    ASM_SIMP_TAC[SIMPLE_IMAGE; COUNTABLE_IMAGE] THEN
+    ASM_SIMP_TAC[FORALL_IN_IMAGE; EXISTS_SUBSET_IMAGE; OPEN_IN_OPEN_INTER] THEN
+    REWRITE_TAC[OPEN_IN_OPEN] THEN
+    X_GEN_TAC `t:real^N->bool` THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    SUBGOAL_THEN `?b. b SUBSET B /\ u:real^N->bool = UNIONS b`
+    STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    EXISTS_TAC `b:(real^N->bool)->bool` THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[INTER_UNIONS] THEN AP_TERM_TAC THEN SET_TAC[];
+    EXISTS_TAC `b DELETE ({}:real^N->bool)` THEN
+    ASM_SIMP_TAC[COUNTABLE_DELETE; IN_DELETE; SUBSET_DELETE] THEN
+    X_GEN_TAC `t:real^N->bool` THEN DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `u DELETE ({}:real^N->bool)` THEN
+    REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+    FIRST_X_ASSUM SUBST_ALL_TAC THEN
+    REWRITE_TAC[EXTENSION; IN_UNIONS] THEN
+    GEN_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
+    REWRITE_TAC[IN_DELETE] THEN SET_TAC[]]);;
+
+let SEPARABLE = prove
+ (`!s:real^N->bool.
+        ?t. COUNTABLE t /\ t SUBSET s /\ s SUBSET closure t`,
+  MP_TAC SUBSET_SECOND_COUNTABLE THEN
+  MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `s:real^N->bool` THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; LEFT_AND_EXISTS_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:(real^N->bool)->bool`
+   (CONJUNCTS_THEN2 ASSUME_TAC (CONJUNCTS_THEN2 MP_TAC ASSUME_TAC))) 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 `f:(real^N->bool)->real^N` THEN DISCH_TAC THEN
+  EXISTS_TAC `IMAGE (f:(real^N->bool)->real^N) B` THEN
+  ASM_SIMP_TAC[COUNTABLE_IMAGE] THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    X_GEN_TAC `c:real^N->bool` THEN 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 MATCH_MP OPEN_IN_SUBSET) THEN
+    REWRITE_TAC[TOPSPACE_SUBTOPOLOGY; TOPSPACE_EUCLIDEAN] THEN ASM SET_TAC[];
+    REWRITE_TAC[SUBSET; CLOSURE_APPROACHABLE; EXISTS_IN_IMAGE] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+    UNDISCH_THEN
+     `!t:real^N->bool.
+        open_in (subtopology euclidean s) t
+        ==> (?u. u SUBSET B /\ t = UNIONS u)`
+     (MP_TAC o SPEC `s INTER ball(x:real^N,e)`) THEN
+    SIMP_TAC[OPEN_IN_OPEN_INTER; OPEN_BALL; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `b:(real^N->bool)->bool` THEN
+    ASM_CASES_TAC `b:(real^N->bool)->bool = {}` THENL
+     [MATCH_MP_TAC(TAUT `~b ==> a /\ b ==> c`) THEN
+      ASM_REWRITE_TAC[EXTENSION; IN_INTER; NOT_IN_EMPTY; UNIONS_0] THEN
+      ASM_MESON_TAC[CENTRE_IN_BALL];
+      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 `c:real^N->bool` THEN
+      DISCH_TAC THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [EXTENSION]) THEN
+      DISCH_THEN(MP_TAC o SPEC `(f:(real^N->bool)->real^N) c`) THEN
+      ONCE_REWRITE_TAC[DIST_SYM] THEN REWRITE_TAC[IN_INTER; IN_BALL] THEN
+      MATCH_MP_TAC(TAUT `a /\ c ==> (a /\ b <=> c) ==> b`) THEN
+      CONJ_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `c:real^N->bool`) THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; STRIP_TAC] THEN
+      FIRST_X_ASSUM(MP_TAC o MATCH_MP OPEN_IN_SUBSET) THEN
+      REWRITE_TAC[TOPSPACE_SUBTOPOLOGY; TOPSPACE_EUCLIDEAN] THEN
+      ASM SET_TAC[]]]);;
+
+let OPEN_SET_RATIONAL_COORDINATES = prove
+ (`!s. open s /\ ~(s = {})
+       ==> ?x:real^N. x IN s /\
+                      !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `~(closure { x | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i) } INTER
+    (s:real^N->bool) = {})`
+  MP_TAC THENL
+   [ASM_REWRITE_TAC[CLOSURE_RATIONAL_COORDINATES; INTER_UNIV]; ALL_TAC] THEN
+  REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; CLOSURE_APPROACHABLE; IN_INTER;
+              IN_ELIM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `a:real^N` o REWRITE_RULE[open_def]) THEN
+  ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]);;
+
+let OPEN_COUNTABLE_UNION_OPEN_INTERVALS,
+    OPEN_COUNTABLE_UNION_CLOSED_INTERVALS = (CONJ_PAIR o prove)
+ (`(!s:real^N->bool.
+        open s
+        ==> ?D. COUNTABLE D /\
+                (!i. i IN D ==> i SUBSET s /\ ?a b. i = interval(a,b)) /\
+                UNIONS D = s) /\
+   (!s:real^N->bool.
+        open s
+        ==> ?D. COUNTABLE D /\
+                (!i. i IN D ==> i SUBSET s /\ ?a b. i = interval[a,b]) /\
+                UNIONS D = s)`,
+  REPEAT STRIP_TAC THENL
+   [EXISTS_TAC
+     `{i | i IN IMAGE (\(a:real^N,b). interval(a,b))
+            ({x | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i)} CROSS
+             {x | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i)}) /\
+           i SUBSET s}`;
+    EXISTS_TAC
+     `{i | i IN IMAGE (\(a:real^N,b). interval[a,b])
+            ({x | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i)} CROSS
+             {x | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i)}) /\
+           i SUBSET s}`] THEN
+  (SIMP_TAC[COUNTABLE_RESTRICT; COUNTABLE_IMAGE; COUNTABLE_CROSS;
+           COUNTABLE_RATIONAL_COORDINATES] THEN
+   REWRITE_TAC[IN_ELIM_THM; UNIONS_GSPEC; IMP_CONJ; GSYM CONJ_ASSOC] THEN
+   REWRITE_TAC[FORALL_IN_IMAGE; EXISTS_IN_IMAGE] THEN
+   REWRITE_TAC[FORALL_PAIR_THM; EXISTS_PAIR_THM; IN_CROSS; IN_ELIM_THM] THEN
+   CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+   REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+   X_GEN_TAC `x:real^N` THEN EQ_TAC THENL [SET_TAC[]; DISCH_TAC] THEN
+   FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N` o REWRITE_RULE[open_def]) THEN
+   ASM_REWRITE_TAC[] THEN
+   DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+   SUBGOAL_THEN
+    `!i. 1 <= i /\ i <= dimindex(:N)
+         ==> ?a b. rational a /\ rational b /\
+                   a < (x:real^N)$i /\ (x:real^N)$i < b /\
+                   abs(b - a) < e / &(dimindex(:N))`
+   MP_TAC THENL
+    [REPEAT STRIP_TAC THEN MATCH_MP_TAC RATIONAL_APPROXIMATION_STRADDLE THEN
+     ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; LE_1; DIMINDEX_GE_1];
+     REWRITE_TAC[LAMBDA_SKOLEM]] THEN
+   MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+   MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:real^N` THEN
+   DISCH_TAC THEN ASM_SIMP_TAC[SUBSET; IN_INTERVAL; REAL_LT_IMP_LE] THEN
+   X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+   REWRITE_TAC[dist] THEN MP_TAC(ISPEC `y - x:real^N` NORM_LE_L1) THEN
+   MATCH_MP_TAC(REAL_ARITH `s < e ==> n <= s ==> n < e`) THEN
+   MATCH_MP_TAC SUM_BOUND_LT_GEN THEN
+   REWRITE_TAC[FINITE_NUMSEG; NUMSEG_EMPTY; NOT_LT; CARD_NUMSEG_1] THEN
+   REWRITE_TAC[DIMINDEX_GE_1; IN_NUMSEG; VECTOR_SUB_COMPONENT] THEN
+   X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+   REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `k:num`)) THEN ASM_REWRITE_TAC[] THEN
+   ASM_REAL_ARITH_TAC));;
+
+let LINDELOF = prove
+ (`!f:(real^N->bool)->bool.
+        (!s. s IN f ==> open s)
+        ==> ?f'. f' SUBSET f /\ COUNTABLE f' /\ UNIONS f' = UNIONS f`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?b. COUNTABLE b /\
+        (!c:real^N->bool. c IN b ==> open c) /\
+        (!s. open s ==> ?u. u SUBSET b /\ s = UNIONS u)`
+  STRIP_ASSUME_TAC THENL [ASM_REWRITE_TAC[UNIV_SECOND_COUNTABLE]; ALL_TAC] THEN
+  ABBREV_TAC
+   `d = {s:real^N->bool | s IN b /\ ?u. u IN f /\ s SUBSET u}` THEN
+  SUBGOAL_THEN
+   `COUNTABLE d /\ UNIONS f :real^N->bool = UNIONS d`
+  STRIP_ASSUME_TAC THENL
+   [EXPAND_TAC "d" THEN ASM_SIMP_TAC[COUNTABLE_RESTRICT] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!s:real^N->bool. ?u. s IN d ==> u IN f /\ s SUBSET u`
+  MP_TAC THENL [EXPAND_TAC "d" THEN SET_TAC[]; ALL_TAC] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `g:(real^N->bool)->(real^N->bool)` THEN STRIP_TAC THEN
+  EXISTS_TAC `IMAGE (g:(real^N->bool)->(real^N->bool)) d` THEN
+  ASM_SIMP_TAC[COUNTABLE_IMAGE; UNIONS_IMAGE] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN ASM SET_TAC[]);;
+
+let LINDELOF_OPEN_IN = prove
+ (`!f u:real^N->bool.
+        (!s. s IN f ==> open_in (subtopology euclidean u) s)
+        ==> ?f'. f' SUBSET f /\ COUNTABLE f' /\ UNIONS f' = UNIONS f`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[OPEN_IN_OPEN] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `v:(real^N->bool)->real^N->bool` THEN DISCH_TAC THEN
+  MP_TAC(ISPEC `IMAGE (v:(real^N->bool)->real^N->bool) f` LINDELOF) THEN
+  ASM_SIMP_TAC[FORALL_IN_IMAGE] THEN
+  ONCE_REWRITE_TAC[TAUT `p /\ q /\ r <=> q /\ p /\ r`] THEN
+  REWRITE_TAC[EXISTS_COUNTABLE_SUBSET_IMAGE] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f':(real^N->bool)->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN
+  `!f'. f' SUBSET f ==> UNIONS f' = (u:real^N->bool) INTER UNIONS (IMAGE v f')`
+  MP_TAC THENL [ASM SET_TAC[]; ASM_SIMP_TAC[SUBSET_REFL]]);;
+
+let COUNTABLE_DISJOINT_OPEN_SUBSETS = prove
+ (`!f. (!s:real^N->bool. s IN f ==> open s) /\ pairwise DISJOINT f
+       ==> COUNTABLE f`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP LINDELOF) THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:(real^N->bool)->bool` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC COUNTABLE_SUBSET THEN
+  EXISTS_TAC `({}:real^N->bool) INSERT g` THEN
+  ASM_REWRITE_TAC[COUNTABLE_INSERT] THEN
+  REWRITE_TAC[SUBSET; IN_INSERT] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[EXTENSION; SUBSET] THEN
+  REWRITE_TAC[IN_UNIONS; pairwise] THEN
+  REWRITE_TAC[SET_RULE `DISJOINT s t <=> !x. ~(x IN s /\ x IN t)`] THEN
+  REWRITE_TAC[NOT_IN_EMPTY] THEN MESON_TAC[]);;
+
+let CARD_EQ_OPEN_SETS = prove
+ (`{s:real^N->bool | open s} =_c (:real)`,
+  REWRITE_TAC[GSYM CARD_LE_ANTISYM] THEN CONJ_TAC THENL
+   [X_CHOOSE_THEN `b:(real^N->bool)->bool` STRIP_ASSUME_TAC
+      UNIV_SECOND_COUNTABLE THEN
+    TRANS_TAC CARD_LE_TRANS `{s:(real^N->bool)->bool | s SUBSET b}` THEN
+    CONJ_TAC THENL
+     [REWRITE_TAC[LE_C] THEN
+      EXISTS_TAC `UNIONS:((real^N->bool)->bool)->real^N->bool` THEN
+      REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[];
+      TRANS_TAC CARD_LE_TRANS `{s | s SUBSET (:num)}` THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CARD_LE_POWERSET THEN ASM_REWRITE_TAC[GSYM COUNTABLE_ALT];
+        REWRITE_TAC[SUBSET_UNIV; UNIV_GSPEC] THEN
+        MESON_TAC[CARD_EQ_IMP_LE; CARD_EQ_SYM; CARD_EQ_REAL]]];
+    REWRITE_TAC[le_c; IN_UNIV; IN_ELIM_THM] THEN
+    EXISTS_TAC `\x. ball(x % basis 1:real^N,&1)` THEN
+    REWRITE_TAC[OPEN_BALL; GSYM SUBSET_ANTISYM_EQ; SUBSET_BALLS] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[NORM_ARITH `dist(p:real^N,q) + &1 <= &1 <=> p = q`] THEN
+    REWRITE_TAC[VECTOR_MUL_RCANCEL; EQ_SYM_EQ] THEN
+    SIMP_TAC[BASIS_NONZERO; DIMINDEX_GE_1; ARITH]]);;
+
+let CARD_EQ_CLOSED_SETS = prove
+ (`{s:real^N->bool | closed s} =_c (:real)`,
+  SUBGOAL_THEN
+   `{s:real^N->bool | closed s} =
+    IMAGE (\s. (:real^N) DIFF s) {s | open s}`
+  SUBST1_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+    REWRITE_TAC[IN_ELIM_THM; GSYM OPEN_CLOSED] THEN
+    MESON_TAC[SET_RULE `UNIV DIFF (UNIV DIFF s) = s`];
+    TRANS_TAC CARD_EQ_TRANS `{s:real^N->bool | open s}` THEN
+    REWRITE_TAC[CARD_EQ_OPEN_SETS] THEN
+    MATCH_MP_TAC CARD_EQ_IMAGE THEN SET_TAC[]]);;
+
+let CARD_EQ_COMPACT_SETS = prove
+ (`{s:real^N->bool | compact s} =_c (:real)`,
+  REWRITE_TAC[GSYM CARD_LE_ANTISYM] THEN CONJ_TAC THENL
+   [TRANS_TAC CARD_LE_TRANS `{s:real^N->bool | closed s}` THEN
+    SIMP_TAC[CARD_EQ_IMP_LE; CARD_EQ_CLOSED_SETS] THEN
+    MATCH_MP_TAC CARD_LE_SUBSET THEN
+    SIMP_TAC[SUBSET; IN_ELIM_THM; COMPACT_IMP_CLOSED];
+    REWRITE_TAC[le_c; IN_UNIV; IN_ELIM_THM] THEN
+    EXISTS_TAC `\x. {x % basis 1:real^N}` THEN
+    REWRITE_TAC[COMPACT_SING; SET_RULE `{x} = {y} <=> x = y`] THEN
+    SIMP_TAC[VECTOR_MUL_RCANCEL; BASIS_NONZERO; DIMINDEX_GE_1; ARITH]]);;
+
+let COUNTABLE_NON_CONDENSATION_POINTS = prove
+ (`!s:real^N->bool. COUNTABLE(s DIFF {x | x condensation_point_of s})`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[condensation_point_of] THEN
+  MATCH_MP_TAC COUNTABLE_SUBSET THEN
+  X_CHOOSE_THEN `b:(real^N->bool)->bool` STRIP_ASSUME_TAC
+   UNIV_SECOND_COUNTABLE THEN
+  EXISTS_TAC
+   `s INTER UNIONS { u:real^N->bool | u IN b /\ COUNTABLE(s INTER u)}` THEN
+  REWRITE_TAC[INTER_UNIONS; IN_ELIM_THM] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC COUNTABLE_UNIONS THEN SIMP_TAC[FORALL_IN_GSPEC] THEN
+    ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+    ASM_SIMP_TAC[COUNTABLE_IMAGE; COUNTABLE_RESTRICT];
+    SIMP_TAC[SUBSET; UNIONS_GSPEC; IN_ELIM_THM; IN_INTER; IN_DIFF] THEN
+    X_GEN_TAC `x:real^N` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    REWRITE_TAC[NOT_FORALL_THM; NOT_IMP; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN
+    SUBGOAL_THEN `?u:real^N->bool. x IN u /\ u IN b /\ u SUBSET t` MP_TAC THENL
+     [ASM SET_TAC[]; MATCH_MP_TAC MONO_EXISTS] THEN
+    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC COUNTABLE_SUBSET THEN
+    EXISTS_TAC `s INTER t:real^N->bool` THEN ASM SET_TAC[]]);;
+
+let CARD_EQ_CONDENSATION_POINTS_IN_SET = prove
+ (`!s:real^N->bool.
+     ~(COUNTABLE s) ==> {x | x IN s /\ x condensation_point_of s} =_c s`,
+  REPEAT STRIP_TAC THEN
+  TRANS_TAC CARD_EQ_TRANS
+   `(s DIFF {x | x condensation_point_of s}) +_c
+    {x:real^N | x IN s /\ x condensation_point_of s}` THEN
+  CONJ_TAC THENL
+   [ONCE_REWRITE_TAC[CARD_EQ_SYM] THEN MATCH_MP_TAC CARD_ADD_ABSORB THEN
+    MATCH_MP_TAC(TAUT `p /\ (p ==> q) ==> p /\ q`) THEN CONJ_TAC THENL
+     [POP_ASSUM MP_TAC THEN REWRITE_TAC[INFINITE; CONTRAPOS_THM] THEN
+      DISCH_THEN(MP_TAC o CONJ (SPEC `s:real^N->bool`
+       COUNTABLE_NON_CONDENSATION_POINTS) o MATCH_MP FINITE_IMP_COUNTABLE) THEN
+      REWRITE_TAC[GSYM COUNTABLE_UNION] THEN MATCH_MP_TAC EQ_IMP THEN
+      AP_TERM_TAC THEN SET_TAC[];
+      REWRITE_TAC[INFINITE_CARD_LE] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] CARD_LE_TRANS) THEN
+      REWRITE_TAC[GSYM COUNTABLE_ALT; COUNTABLE_NON_CONDENSATION_POINTS]];
+    ONCE_REWRITE_TAC[CARD_EQ_SYM] THEN
+    W(MP_TAC o PART_MATCH (rand o rand) CARD_DISJOINT_UNION o rand o snd) THEN
+    ANTS_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN AP_TERM_TAC THEN SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A discrete set is countable, and an uncountable set has a limit point.    *)
+(* ------------------------------------------------------------------------- *)
+
+let DISCRETE_IMP_COUNTABLE = prove
+ (`!s:real^N->bool.
+        (!x. x IN s ==> ?e. &0 < e /\
+                            !y. y IN s /\ ~(y = x) ==> e <= norm(y - x))
+        ==> COUNTABLE s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `!x. x IN s
+        ==> ?q. (!i. 1 <= i /\ i <= dimindex(:N) ==> rational(q$i)) /\
+                !y:real^N. y IN s /\ ~(y = x) ==> norm(x - q) < norm(y - q)`
+  MP_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
+    MP_TAC(SET_RULE `x IN (:real^N)`) THEN
+    REWRITE_TAC[GSYM CLOSURE_RATIONAL_COORDINATES] THEN
+    REWRITE_TAC[CLOSURE_APPROACHABLE; IN_ELIM_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `q:real^N` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    X_GEN_TAC `y:real^N` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `y:real^N`) THEN ASM_REWRITE_TAC[] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC;
+    POP_ASSUM(K ALL_TAC) THEN
+    REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `q:real^N->real^N` THEN DISCH_TAC THEN
+    MP_TAC(ISPECL
+     [`s:real^N->bool`;
+      `{ x:real^N | !i. 1 <= i /\ i <= dimindex(:N) ==> rational(x$i) }`;
+      `(:num)`] CARD_LE_TRANS) THEN
+    REWRITE_TAC[COUNTABLE; ge_c] THEN DISCH_THEN MATCH_MP_TAC THEN
+    SIMP_TAC[REWRITE_RULE[COUNTABLE; ge_c] COUNTABLE_RATIONAL_COORDINATES] THEN
+    REWRITE_TAC[le_c] THEN EXISTS_TAC `q:real^N->real^N` THEN
+    ASM_SIMP_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[REAL_LT_ANTISYM]]);;
+
+let UNCOUNTABLE_CONTAINS_LIMIT_POINT = prove
+ (`!s. ~(COUNTABLE s) ==> ?x. x IN s /\ x limit_point_of s`,
+  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP
+   (ONCE_REWRITE_RULE[GSYM CONTRAPOS_THM] DISCRETE_IMP_COUNTABLE)) THEN
+  REWRITE_TAC[LIMPT_APPROACHABLE; GSYM REAL_NOT_LT; dist] THEN
+  MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The Brouwer reduction theorem.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let BROUWER_REDUCTION_THEOREM_GEN = prove
+ (`!P s:real^N->bool.
+        (!f. (!n. closed(f n) /\ P(f n)) /\ (!n. f(SUC n) SUBSET f(n))
+              ==> P(INTERS {f n | n IN (:num)})) /\
+        closed s /\ P s
+        ==> ?t. t SUBSET s /\ closed t /\ P t /\
+                (!u. u SUBSET s /\ closed u /\ P u ==> ~(u PSUBSET t))`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN
+   `?b:num->real^N->bool.
+        (!m n. b m = b n <=> m = n) /\
+        (!n. open (b n)) /\
+        (!s. open s ==> (?k. s = UNIONS {b n | n IN k}))`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[UNIV_SECOND_COUNTABLE_SEQUENCE]; ALL_TAC] THEN
+  X_CHOOSE_THEN `a:num->real^N->bool` MP_TAC
+   (prove_recursive_functions_exist num_RECURSION
+   `a 0 = (s:real^N->bool) /\
+    (!n. a(SUC n) =
+         if ?u. u SUBSET a(n) /\ closed u /\ P u /\ u INTER (b n) = {}
+         then @u. u SUBSET a(n) /\ closed u /\ P u /\ u INTER (b n) = {}
+         else a(n))`) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (LABEL_TAC "base") (LABEL_TAC "step")) THEN
+  EXISTS_TAC `INTERS {a n :real^N->bool | n IN (:num)}` THEN
+  SUBGOAL_THEN `!n. (a:num->real^N->bool)(SUC n) SUBSET a(n)` ASSUME_TAC THENL
+   [GEN_TAC THEN ASM_REWRITE_TAC[] THEN
+    COND_CASES_TAC THEN REWRITE_TAC[SUBSET_REFL] THEN
+    FIRST_X_ASSUM(MP_TAC o SELECT_RULE) THEN MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!n. (a:num->real^N->bool) n SUBSET s` ASSUME_TAC THENL
+   [INDUCT_TAC THEN ASM_MESON_TAC[SUBSET_REFL; SUBSET_TRANS]; ALL_TAC] THEN
+  SUBGOAL_THEN `!n. closed((a:num->real^N->bool) n) /\ P(a n)` ASSUME_TAC THENL
+   [INDUCT_TAC THEN ASM_REWRITE_TAC[] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+    FIRST_X_ASSUM(MP_TAC o SELECT_RULE) THEN MESON_TAC[];
+    ALL_TAC] THEN
+  REPEAT CONJ_TAC THENL
+   [ASM SET_TAC[];
+    MATCH_MP_TAC CLOSED_INTERS THEN
+    ASM_REWRITE_TAC[FORALL_IN_GSPEC; IN_UNIV] THEN SET_TAC[];
+    FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[];
+    X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN
+    REWRITE_TAC[PSUBSET_ALT] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    REWRITE_TAC[INTERS_GSPEC; EXISTS_IN_GSPEC; IN_UNIV] THEN
+    DISCH_THEN(X_CHOOSE_THEN `x:real^N` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `?n. x IN (b:num->real^N->bool)(n) /\ t INTER b n = {}`
+    STRIP_ASSUME_TAC THENL
+     [MP_TAC(ISPEC `(:real^N) DIFF t` OPEN_CONTAINS_BALL) THEN
+      ASM_REWRITE_TAC[GSYM closed] THEN
+      DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN
+      ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; LEFT_IMP_EXISTS_THM] THEN
+      REWRITE_TAC[SET_RULE `s SUBSET UNIV DIFF t <=> t INTER s = {}`] THEN
+      X_GEN_TAC `e:real` THEN
+      DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+      MP_TAC(ISPECL [`x:real^N`; `e:real`] CENTRE_IN_BALL) THEN
+      FIRST_X_ASSUM(MP_TAC o SPEC `ball(x:real^N,e)`) THEN
+      ASM_REWRITE_TAC[OPEN_BALL; LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `k:num->bool` THEN DISCH_THEN SUBST1_TAC THEN
+      REWRITE_TAC[IN_UNIONS; INTER_UNIONS; EMPTY_UNIONS; FORALL_IN_GSPEC] THEN
+      SET_TAC[];
+      REMOVE_THEN "step" (MP_TAC o SPEC `n:num`) THEN
+      COND_CASES_TAC THENL
+       [DISCH_THEN(ASSUME_TAC o SYM) THEN
+        FIRST_X_ASSUM(MP_TAC o SELECT_RULE) THEN ASM_REWRITE_TAC[] THEN
+        ASM SET_TAC[];
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [NOT_EXISTS_THM]) THEN
+        DISCH_THEN(MP_TAC o SPEC `t:real^N->bool`) THEN ASM_REWRITE_TAC[] THEN
+        ASM SET_TAC[]]]]);;
+
+let BROUWER_REDUCTION_THEOREM = prove
+ (`!P s:real^N->bool.
+        (!f. (!n. compact(f n) /\ ~(f n = {}) /\ P(f n)) /\
+             (!n. f(SUC n) SUBSET f(n))
+             ==> P(INTERS {f n | n IN (:num)})) /\
+        compact s /\ ~(s = {}) /\ P s
+        ==> ?t. t SUBSET s /\ compact t /\ ~(t = {}) /\ P t /\
+                (!u. u SUBSET s /\ closed u /\ ~(u = {}) /\ P u
+                     ==> ~(u PSUBSET t))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`\t:real^N->bool. ~(t = {}) /\ t SUBSET s /\ P t`;
+                 `s:real^N->bool`]
+        BROUWER_REDUCTION_THEOREM_GEN) THEN
+  ASM_SIMP_TAC[COMPACT_IMP_CLOSED; SUBSET_REFL] THEN ANTS_TAC THENL
+   [GEN_TAC THEN STRIP_TAC THEN
+    SUBGOAL_THEN `!n. compact((f:num->real^N->bool) n)` ASSUME_TAC THENL
+     [ASM_MESON_TAC[COMPACT_EQ_BOUNDED_CLOSED; BOUNDED_SUBSET]; ALL_TAC] THEN
+    REPEAT CONJ_TAC THENL
+     [MATCH_MP_TAC COMPACT_NEST THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC TRANSITIVE_STEPWISE_LE THEN ASM_SIMP_TAC[] THEN SET_TAC[];
+      ASM SET_TAC[];
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]];
+    MATCH_MP_TAC MONO_EXISTS THEN ASM_SIMP_TAC[] THEN
+    ASM_MESON_TAC[COMPACT_EQ_BOUNDED_CLOSED; BOUNDED_SUBSET]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The Arzela-Ascoli theorem.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let SUBSEQUENCE_DIAGONALIZATION_LEMMA = prove
+ (`!P:num->(num->A)->bool.
+    (!i r:num->A. ?k. (!m n. m < n ==> k m < k n) /\ P i (r o k)) /\
+    (!i r:num->A k1 k2 N.
+        P i (r o k1) /\ (!j. N <= j ==> ?j'. j <= j' /\ k2 j = k1 j')
+        ==> P i (r o k2))
+    ==> !r:num->A. ?k. (!m n. m < n ==> k m < k n) /\ (!i. P i (r o k))`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [SKOLEM_THM] THEN
+  REWRITE_TAC[FORALL_AND_THM; TAUT
+   `(p ==> q /\ r) <=> (p ==> q) /\ (p ==> r)`] THEN
+  DISCH_THEN(X_CHOOSE_THEN
+   `kk:num->(num->A)->num->num` STRIP_ASSUME_TAC) THEN
+  X_GEN_TAC `r:num->A` THEN
+  (STRIP_ASSUME_TAC o prove_recursive_functions_exist num_RECURSION)
+    `(rr 0 = (kk:num->(num->A)->num->num) 0 r) /\
+     (!n. rr(SUC n) = rr n o kk (SUC n) (r o rr n))` THEN
+  EXISTS_TAC `\n. (rr:num->num->num) n n` THEN REWRITE_TAC[ETA_AX] THEN
+  SUBGOAL_THEN
+   `(!i. (!m n. m < n ==> (rr:num->num->num) i m < rr i n)) /\
+    (!i. (P:num->(num->A)->bool) i (r o rr i))`
+  STRIP_ASSUME_TAC THENL
+   [REWRITE_TAC[AND_FORALL_THM] THEN
+    INDUCT_TAC THEN ASM_REWRITE_TAC[o_ASSOC] THEN
+    REWRITE_TAC[o_THM] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!i j n. i <= j ==> (rr:num->num->num) i n <= rr j n`
+  ASSUME_TAC THENL
+   [REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [LE_EXISTS] THEN
+    SIMP_TAC[LEFT_IMP_EXISTS_THM] THEN SPEC_TAC(`j:num`,`j:num`) THEN
+    ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN SIMP_TAC[FORALL_UNWIND_THM2] THEN
+    INDUCT_TAC THEN REWRITE_TAC[ADD_CLAUSES; LE_REFL] THEN
+    ASM_REWRITE_TAC[] THEN FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ] LE_TRANS)) THEN REWRITE_TAC[o_THM] THEN
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (MESON[LE_LT]
+       `!f:num->num.
+        (!m n. m < n ==> f m < f n) ==> (!m n. m <= n ==> f m <= f n)`) o
+       SPEC `i + d:num`) THEN
+    SPEC_TAC(`n:num`,`n:num`) THEN MATCH_MP_TAC MONOTONE_BIGGER THEN
+    ASM_SIMP_TAC[];
+    ALL_TAC] THEN
+  CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN DISCH_TAC THEN
+    MATCH_MP_TAC LET_TRANS THEN
+    EXISTS_TAC `(rr:num->num->num) n m` THEN
+    ASM_MESON_TAC[LT_IMP_LE];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `!m n i. n <= m ==> ?j. i <= j /\ (rr:num->num->num) m i = rr n j`
+  ASSUME_TAC THENL
+   [ALL_TAC;
+    X_GEN_TAC `i:num` THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    EXISTS_TAC `(rr:num->num->num) i` THEN ASM_REWRITE_TAC[] THEN
+    EXISTS_TAC `i:num` THEN ASM_MESON_TAC[]] THEN
+  SUBGOAL_THEN
+   `!p d i. ?j. i <= j /\ (rr:num->num->num) (p + d) i = rr p j`
+   (fun th -> MESON_TAC[LE_EXISTS; th]) THEN
+  X_GEN_TAC `p:num` THEN  MATCH_MP_TAC num_INDUCTION THEN
+  ASM_REWRITE_TAC[ADD_CLAUSES] THEN CONJ_TAC THENL
+   [MESON_TAC[LE_REFL]; ALL_TAC] THEN
+  X_GEN_TAC `d:num` THEN DISCH_THEN(LABEL_TAC "+") THEN
+  X_GEN_TAC `i:num` THEN ASM_REWRITE_TAC[o_THM] THEN
+  REMOVE_THEN "+" (MP_TAC o SPEC
+   `(kk:num->(num->A)->num->num) (SUC(p + d))
+        ((r:num->A) o (rr:num->num->num) (p + d)) i`) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `j:num` THEN
+  MATCH_MP_TAC MONO_AND THEN REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LE_TRANS) THEN
+  SPEC_TAC(`i:num`,`i:num`) THEN MATCH_MP_TAC MONOTONE_BIGGER THEN
+  ASM_REWRITE_TAC[o_THM] THEN ASM_MESON_TAC[]);;
+
+let FUNCTION_CONVERGENT_SUBSEQUENCE = prove
+ (`!f:num->real^M->real^N s M.
+        COUNTABLE s /\ (!n x. x IN s ==> norm(f n x) <= M)
+        ==> ?k. (!m n:num. m < n ==> k m < k n) /\
+                !x. x IN s ==> ?l. ((\n. f (k n) x) --> l) sequentially`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THENL
+   [EXISTS_TAC `\n:num. n` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY];
+    ALL_TAC] THEN
+  MP_TAC(ISPEC `s:real^M->bool` COUNTABLE_AS_IMAGE) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `X:num->real^M` THEN DISCH_THEN SUBST_ALL_TAC THEN
+  MP_TAC(ISPEC
+    `\i r. ?l. ((\n. ((f:num->real^M->real^N) o (r:num->num)) n
+                     ((X:num->real^M) i)) --> l) sequentially`
+   SUBSEQUENCE_DIAGONALIZATION_LEMMA) THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; o_THM; IN_UNIV] THEN
+  ANTS_TAC THENL [ALL_TAC; DISCH_THEN MATCH_ACCEPT_TAC] THEN CONJ_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[FORALL_IN_IMAGE; IN_UNIV]) THEN
+    MAP_EVERY X_GEN_TAC [`i:num`; `r:num->num`] THEN
+    MP_TAC(ISPEC `cball(vec 0:real^N,M)` compact) THEN
+    REWRITE_TAC[COMPACT_CBALL] THEN DISCH_THEN(MP_TAC o SPEC
+     `\n. (f:num->real^M->real^N) ((r:num->num) n) (X(i:num))`) THEN
+    ASM_REWRITE_TAC[IN_CBALL_0; o_DEF] THEN MESON_TAC[];
+    REPEAT GEN_TAC THEN REWRITE_TAC[LIM_SEQUENTIALLY; GE] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+    MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+    MATCH_MP_TAC MONO_IMP THEN REWRITE_TAC[] THEN
+    ASM_MESON_TAC[LE_TRANS; ARITH_RULE `MAX a b <= c <=> a <= c /\ b <= c`]]);;
+
+let ARZELA_ASCOLI = prove
+ (`!f:num->real^M->real^N s M.
+        compact s /\
+        (!n x. x IN s ==> norm(f n x) <= M) /\
+        (!x e. x IN s /\ &0 < e
+               ==> ?d. &0 < d /\
+                       !n y. y IN s /\ norm(x - y) < d
+                             ==> norm(f n x - f n y) < e)
+        ==> ?g. g continuous_on s /\
+                ?r. (!m n:num. m < n ==> r m < r n) /\
+                    !e. &0 < e
+                        ==> ?N. !n x. n >= N /\ x IN s
+                                      ==> norm(f(r n) x - g x) < e`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GE] THEN
+  MATCH_MP_TAC(MESON[]
+   `(!k g. V k g ==> N g) /\ (?k. M k /\ ?g. V k g)
+    ==> ?g. N g /\ ?k. M k /\ V k g`) THEN
+  CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`k:num->num`; `g:real^M->real^N`] THEN
+    STRIP_TAC THEN MATCH_MP_TAC(ISPEC `sequentially`
+      CONTINUOUS_UNIFORM_LIMIT) THEN
+    EXISTS_TAC `(f:num->real^M->real^N) o (k:num->num)` THEN
+    ASM_SIMP_TAC[EVENTUALLY_SEQUENTIALLY; o_THM; TRIVIAL_LIMIT_SEQUENTIALLY;
+                 RIGHT_IMP_FORALL_THM; IMP_IMP] THEN
+    EXISTS_TAC `0` THEN REWRITE_TAC[continuous_on; dist] THEN
+    ASM_MESON_TAC[NORM_SUB];
+    ALL_TAC] THEN
+  MP_TAC(ISPECL
+   [`IMAGE (f:num->real^M->real^N) (:num)`;
+    `s:real^M->bool`]
+   COMPACT_UNIFORMLY_EQUICONTINUOUS) THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE; IN_UNIV] THEN
+  ANTS_TAC THENL
+   [REWRITE_TAC[dist] THEN ONCE_REWRITE_TAC[NORM_SUB] THEN ASM_MESON_TAC[];
+    ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(K ALL_TAC o SPEC `x:real^M`)] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
+  REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC; dist] THEN
+  DISCH_THEN(ASSUME_TAC o ONCE_REWRITE_RULE[NORM_SUB]) THEN
+  REWRITE_TAC[GSYM dist; UNIFORMLY_CONVERGENT_EQ_CAUCHY] THEN
+  X_CHOOSE_THEN `r:real^M->bool` STRIP_ASSUME_TAC
+   (ISPEC `s:real^M->bool` SEPARABLE) THEN
+  MP_TAC(ISPECL [`f:num->real^M->real^N`; `r:real^M->bool`; `M:real`]
+        FUNCTION_CONVERGENT_SUBSEQUENCE) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:num->num` THEN
+  REWRITE_TAC[CONVERGENT_EQ_CAUCHY; cauchy] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "*")) THEN
+  ASM_REWRITE_TAC[] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `e / &3`) THEN
+  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [COMPACT_EQ_HEINE_BOREL]) THEN
+  DISCH_THEN(MP_TAC o SPEC `IMAGE (\x:real^M. ball(x,d)) r`) THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; OPEN_BALL] THEN
+  ONCE_REWRITE_TAC[TAUT `a /\ b /\ c <=> b /\ a /\ c`] THEN
+  REWRITE_TAC[EXISTS_FINITE_SUBSET_IMAGE] THEN ANTS_TAC THENL
+   [MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `closure r:real^M->bool` THEN
+    ASM_REWRITE_TAC[] THEN REWRITE_TAC[SUBSET; CLOSURE_APPROACHABLE] THEN
+    X_GEN_TAC `x:real^M` THEN DISCH_THEN(MP_TAC o SPEC `d:real`) THEN
+    ASM_REWRITE_TAC[UNIONS_IMAGE; IN_ELIM_THM; IN_BALL];
+    DISCH_THEN(X_CHOOSE_THEN `t:real^M->bool` STRIP_ASSUME_TAC)] THEN
+  REMOVE_THEN "*" MP_TAC THEN REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN
+  GEN_REWRITE_TAC LAND_CONV [SWAP_FORALL_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &3`) THEN
+  ASM_REWRITE_TAC[REAL_ARITH `&0 < e / &3 <=> &0 < e`] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [RIGHT_IMP_EXISTS_THM] THEN
+  REWRITE_TAC[SKOLEM_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `M:real^M->num` THEN DISCH_THEN(LABEL_TAC "*") THEN
+  MP_TAC(ISPECL [`M:real^M->num`; `t:real^M->bool`]
+    UPPER_BOUND_FINITE_SET) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+  DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`m:num`; `n:num`; `x:real^M`] THEN STRIP_TAC THEN
+  UNDISCH_TAC `s SUBSET UNIONS (IMAGE (\x:real^M. ball (x,d)) t)` THEN
+  REWRITE_TAC[SUBSET; UNIONS_IMAGE; IN_ELIM_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN
+  ASM_REWRITE_TAC[IN_BALL; LEFT_IMP_EXISTS_THM; dist] THEN
+  X_GEN_TAC `y:real^M` THEN STRIP_TAC THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `norm(f (k(m:num)) y - f (k m) x) < e / &3 /\
+    norm(f (k n) y - f (k n) x) < e / &3 /\
+    norm(f (k m) y - f (k n) y) < e / &3
+    ==> norm(f (k m) x - f (k n) x :real^M) < e`) THEN
+  ASM_SIMP_TAC[] THEN REMOVE_THEN "*" (MP_TAC o SPEC `y:real^M`) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPECL [`m:num`; `n:num`]) THEN
+  ASM_REWRITE_TAC[dist; GE] THEN ASM_MESON_TAC[SUBSET; LE_TRANS]);;
diff --git a/Multivariate/transcendentals.ml b/Multivariate/transcendentals.ml
new file mode 100644 (file)
index 0000000..b9c4cbe
--- /dev/null
@@ -0,0 +1,6553 @@
+(* ========================================================================= *)
+(* Complex transcendentals and their real counterparts.                      *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(* ========================================================================= *)
+
+needs "Multivariate/determinants.ml";;
+needs "Multivariate/canal.ml";;
+
+prioritize_complex();;
+
+(* ------------------------------------------------------------------------- *)
+(* The complex exponential function.                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let cexp = new_definition
+ `cexp z = infsum (from 0) (\n. z pow n / Cx(&(FACT n)))`;;
+
+let CEXP_0 = prove
+ (`cexp(Cx(&0)) = Cx(&1)`,
+  REWRITE_TAC[cexp] THEN MATCH_MP_TAC INFSUM_UNIQUE THEN
+  MP_TAC(ISPECL [`\i. Cx(&0) pow i / Cx(&(FACT i))`; `{0}`; `from 0`]
+         SERIES_FINITE_SUPPORT) THEN
+  SIMP_TAC[FROM_0; INTER_UNIV; FINITE_INSERT; FINITE_RULES] THEN ANTS_TAC THENL
+   [INDUCT_TAC THEN REWRITE_TAC[IN_SING; NOT_SUC] THEN
+    REWRITE_TAC[complex_div; complex_pow; COMPLEX_MUL_LZERO; COMPLEX_VEC_0];
+    REWRITE_TAC[VSUM_SING; FACT; COMPLEX_DIV_1; complex_pow]]);;
+
+let CEXP_CONVERGES_UNIFORMLY_CAUCHY = prove
+ (`!R e. &0 < e /\ &0 < R
+         ==> ?N. !m n z. m >= N /\ norm(z) <= R
+                         ==> norm(vsum(m..n) (\i. z pow i / Cx(&(FACT i))))
+                                     < e`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`&1 / &2`; `\i. Cx(R) pow i / Cx(&(FACT i))`;
+                 `from 0`] SERIES_RATIO) THEN
+  REWRITE_TAC[SERIES_CAUCHY; LEFT_FORALL_IMP_THM] THEN
+  MP_TAC(SPEC `&2 * norm(Cx(R))` REAL_ARCH_SIMPLE) THEN
+  REWRITE_TAC[COMPLEX_NORM_CX; COMPLEX_NORM_DIV; COMPLEX_NORM_POW] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  MATCH_MP_TAC(TAUT `(a ==> b) /\ (c ==> d) ==> a ==> (b ==> c) ==> d`) THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN DISCH_TAC THEN
+    X_GEN_TAC `n:num` THEN REWRITE_TAC[GE] THEN DISCH_TAC THEN
+    SIMP_TAC[FACT; real_pow; GSYM REAL_OF_NUM_MUL; real_div; REAL_INV_MUL] THEN
+    REWRITE_TAC[REAL_ARITH
+     `(z * zn) * (is * ik) <= (&1 * inv(&2)) * zn * ik <=>
+      &0 <= (&1 - (&2 * z) * is) * zn * ik`] THEN
+    MATCH_MP_TAC REAL_LE_MUL THEN
+    SIMP_TAC[REAL_LE_MUL; REAL_POS; REAL_POW_LE; REAL_SUB_LE;
+             REAL_LE_INV_EQ; REAL_ABS_POS] THEN
+    ASM_SIMP_TAC[GSYM real_div; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; LT_0] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN
+    REWRITE_TAC[GSYM REAL_OF_NUM_LE; GSYM REAL_OF_NUM_SUC] THEN
+    REAL_ARITH_TAC;
+    DISCH_THEN(MP_TAC o SPEC `e:real`) THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+    REWRITE_TAC[FROM_0; INTER_UNIV] THEN
+    REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+    DISCH_THEN(fun th -> REPEAT STRIP_TAC THEN MP_TAC th) THEN
+    ASM_SIMP_TAC[GSYM CX_DIV; GSYM CX_POW; VSUM_CX_NUMSEG; COMPLEX_NORM_CX] THEN
+    MATCH_MP_TAC(REAL_ARITH `x <= y ==> y < e ==> x < e`) THEN
+    SUBGOAL_THEN `abs (sum (m..n) (\i. R pow i / &(FACT i))) =
+                  sum (m..n) (\i. R pow i / &(FACT i))`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[REAL_ABS_REFL] THEN MATCH_MP_TAC SUM_POS_LE_NUMSEG THEN
+      ASM_SIMP_TAC[REAL_LT_IMP_LE;REAL_LT_DIV; REAL_OF_NUM_LT;
+                   FACT_LT; REAL_POW_LT];
+      ALL_TAC] THEN
+    MATCH_MP_TAC VSUM_NORM_LE THEN REWRITE_TAC[IN_NUMSEG; FINITE_NUMSEG] THEN
+    X_GEN_TAC `i:num` THEN
+    REWRITE_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_POW; COMPLEX_NORM_CX] THEN
+    SIMP_TAC[REAL_ABS_NUM; REAL_LE_DIV2_EQ; REAL_OF_NUM_LT; FACT_LT] THEN
+    ASM_SIMP_TAC[REAL_POW_LE2; NORM_POS_LE]]);;
+
+let CEXP_CONVERGES = prove
+ (`!z. ((\n. z pow n / Cx(&(FACT n))) sums cexp(z)) (from 0)`,
+  GEN_TAC THEN REWRITE_TAC[cexp; SUMS_INFSUM; summable; SERIES_CAUCHY] THEN
+  REWRITE_TAC[FROM_0; INTER_UNIV] THEN
+  MP_TAC(SPEC `norm(z:complex) + &1` CEXP_CONVERGES_UNIFORMLY_CAUCHY) THEN
+  SIMP_TAC[REAL_ARITH `&0 <= x ==> &0 < x + &1`; NORM_POS_LE] THEN
+  MESON_TAC[REAL_ARITH `x <= x + &1`]);;
+
+let CEXP_CONVERGES_UNIQUE = prove
+ (`!w z. ((\n. z pow n / Cx(&(FACT n))) sums w) (from 0) <=> w = cexp(z)`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN SIMP_TAC[CEXP_CONVERGES] THEN
+  DISCH_THEN(MP_TAC o C CONJ (SPEC `z:complex` CEXP_CONVERGES)) THEN
+  REWRITE_TAC[SERIES_UNIQUE]);;
+
+let CEXP_CONVERGES_UNIFORMLY = prove
+ (`!R e. &0 < R /\ &0 < e
+         ==> ?N. !n z. n >= N /\ norm(z) < R
+                       ==> norm(vsum(0..n) (\i. z pow i / Cx(&(FACT i))) -
+                                cexp(z)) <= e`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`R:real`; `e / &2`] CEXP_CONVERGES_UNIFORMLY_CAUCHY) THEN
+  ASM_REWRITE_TAC[REAL_HALF] THEN MATCH_MP_TAC MONO_EXISTS THEN
+  X_GEN_TAC `N:num` THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`n:num`; `z:complex`] THEN STRIP_TAC THEN
+  MP_TAC(SPEC `z:complex` CEXP_CONVERGES) THEN
+  REWRITE_TAC[sums; LIM_SEQUENTIALLY; FROM_0; INTER_UNIV; dist] THEN
+  DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `M:num` (MP_TAC o SPEC `n + M + 1`)) THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`n + 1`; `n + M + 1`; `z:complex`]) THEN
+  ASM_SIMP_TAC[ARITH_RULE `(n >= N ==> n + 1 >= N) /\ M <= n + M + 1`] THEN
+  ASM_SIMP_TAC[REAL_LT_IMP_LE; VSUM_ADD_SPLIT; LE_0] THEN
+  CONV_TAC(ONCE_DEPTH_CONV(ALPHA_CONV `i:num`)) THEN NORM_ARITH_TAC);;
+
+let HAS_COMPLEX_DERIVATIVE_CEXP = prove
+ (`!z. (cexp has_complex_derivative cexp(z)) (at z)`,
+  REPEAT GEN_TAC THEN MP_TAC(ISPECL
+   [`ball(Cx(&0),norm(z:complex) + &1)`;
+    `\n z. z pow n / Cx(&(FACT n))`;
+    `\n z. if n = 0 then Cx(&0) else z pow (n-1) / Cx(&(FACT(n-1)))`;
+    `cexp:complex->complex`;
+    `(from 0)`]
+   HAS_COMPLEX_DERIVATIVE_SERIES) THEN
+  REWRITE_TAC[CONVEX_BALL; OPEN_BALL; IN_BALL; dist] THEN
+  SIMP_TAC[HAS_COMPLEX_DERIVATIVE_WITHIN_OPEN; OPEN_BALL; IN_BALL;
+           dist; COMPLEX_SUB_LZERO; COMPLEX_SUB_RZERO; NORM_NEG] THEN
+  ANTS_TAC THEN REPEAT CONJ_TAC THENL
+   [X_GEN_TAC `n:num` THEN REPEAT STRIP_TAC THEN COMPLEX_DIFF_TAC THEN
+    SPEC_TAC(`n:num`,`n:num`) THEN INDUCT_TAC THEN
+    REWRITE_TAC[ARITH; complex_div; COMPLEX_MUL_LZERO] THEN
+    MP_TAC(SPECL [`&n + &1`; `&0`] CX_INJ) THEN
+    REWRITE_TAC[NOT_SUC; SUC_SUB1; GSYM REAL_OF_NUM_SUC; FACT;
+         CX_ADD; CX_MUL; GSYM REAL_OF_NUM_MUL; COMPLEX_INV_MUL] THEN
+    REWRITE_TAC[REAL_ARITH `~(&n + &1 = &0)`] THEN
+    ABBREV_TAC `a = inv(Cx(&(FACT n)))` THEN CONV_TAC COMPLEX_FIELD;
+    REPEAT STRIP_TAC THEN
+    MP_TAC(SPECL [`norm(z:complex) + &1`; `e:real`]
+       CEXP_CONVERGES_UNIFORMLY) THEN
+    ASM_SIMP_TAC[NORM_POS_LE; REAL_ARITH `&0 <= x ==> &0 < x + &1`] THEN
+    DISCH_THEN(X_CHOOSE_TAC `N:num`) THEN EXISTS_TAC `N + 1` THEN
+    MAP_EVERY X_GEN_TAC [`n:num`; `w:complex`] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`n - 1`; `w:complex`]) THEN
+    ASM_SIMP_TAC[ARITH_RULE `n >= m + 1 ==> n - 1 >= m`] THEN
+    REWRITE_TAC[FROM_0; INTER_UNIV] THEN MATCH_MP_TAC EQ_IMP THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN
+    SUBGOAL_THEN `0..n = 0 INSERT (IMAGE SUC (0..n-1))` SUBST1_TAC THENL
+     [REWRITE_TAC[EXTENSION; IN_INSERT; IN_IMAGE; IN_NUMSEG] THEN
+      INDUCT_TAC THEN REWRITE_TAC[LE_0; NOT_SUC; SUC_INJ; UNWIND_THM1] THEN
+      UNDISCH_TAC `n >= N + 1` THEN ARITH_TAC;
+      ALL_TAC] THEN
+    SIMP_TAC[VSUM_CLAUSES; FINITE_IMAGE; FINITE_NUMSEG] THEN
+    REWRITE_TAC[IN_IMAGE; NOT_SUC; COMPLEX_ADD_LID] THEN
+    SIMP_TAC[VSUM_IMAGE; FINITE_NUMSEG; SUC_INJ] THEN
+    MATCH_MP_TAC VSUM_EQ THEN SIMP_TAC[IN_NUMSEG; NOT_SUC; o_THM; SUC_SUB1];
+    MAP_EVERY EXISTS_TAC [`Cx(&0)`; `cexp(Cx(&0))`] THEN
+    REWRITE_TAC[CEXP_CONVERGES; COMPLEX_NORM_0] THEN
+    SIMP_TAC[REAL_ARITH `&0 <= z ==> &0 < z + &1`; NORM_POS_LE];
+    DISCH_THEN(X_CHOOSE_THEN `g:complex->complex` MP_TAC) THEN
+    REWRITE_TAC[CEXP_CONVERGES_UNIQUE] THEN STRIP_TAC THEN
+    MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_AT THEN
+    MAP_EVERY EXISTS_TAC [`g:complex->complex`; `&1`] THEN
+    REWRITE_TAC[REAL_LT_01] THEN CONJ_TAC THENL
+     [ALL_TAC;
+      FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN
+      ANTS_TAC THENL [REAL_ARITH_TAC; SIMP_TAC[]]] THEN
+    POP_ASSUM MP_TAC THEN MATCH_MP_TAC MONO_FORALL THEN
+    X_GEN_TAC `w:complex` THEN MATCH_MP_TAC MONO_IMP THEN SIMP_TAC[] THEN
+    NORM_ARITH_TAC]);;
+
+let COMPLEX_DIFFERENTIABLE_AT_CEXP = prove
+ (`!z. cexp complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CEXP]);;
+
+let COMPLEX_DIFFERENTIABLE_WITHIN_CEXP = prove
+ (`!s z. cexp complex_differentiable (at z within s)`,
+  MESON_TAC[COMPLEX_DIFFERENTIABLE_AT_WITHIN;
+            COMPLEX_DIFFERENTIABLE_AT_CEXP]);;
+
+let CONTINUOUS_AT_CEXP = prove
+ (`!z. cexp continuous at z`,
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CEXP;
+            HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT]);;
+
+let CONTINUOUS_WITHIN_CEXP = prove
+ (`!s z. cexp continuous (at z within s)`,
+  MESON_TAC[CONTINUOUS_AT_WITHIN; CONTINUOUS_AT_CEXP]);;
+
+let CONTINUOUS_ON_CEXP = prove
+ (`!s. cexp continuous_on s`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON; CONTINUOUS_AT_CEXP]);;
+
+let HOLOMORPHIC_ON_CEXP = prove
+ (`!s. cexp holomorphic_on s`,
+  REWRITE_TAC [holomorphic_on] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HAS_COMPLEX_DERIVATIVE_CEXP]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Add it to the database.                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+add_complex_differentiation_theorems
+ (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+   (MATCH_MP HAS_COMPLEX_DERIVATIVE_CHAIN_UNIV
+             HAS_COMPLEX_DERIVATIVE_CEXP)));;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence the main results.                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let CEXP_ADD_MUL = prove
+ (`!w z. cexp(w + z) * cexp(--z) = cexp(w)`,
+  GEN_TAC THEN
+  ONCE_REWRITE_TAC[SET_RULE `(!x. P x) <=> (!x. x IN UNIV ==> P x)`] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_ZERO_UNIQUE THEN
+  EXISTS_TAC `Cx(&0)` THEN REWRITE_TAC[OPEN_UNIV; CONVEX_UNIV; IN_UNIV] THEN
+  REWRITE_TAC[COMPLEX_ADD_RID; COMPLEX_NEG_0; CEXP_0; COMPLEX_MUL_RID] THEN
+  GEN_TAC THEN COMPLEX_DIFF_TAC THEN CONV_TAC COMPLEX_RING);;
+
+let CEXP_NEG_RMUL = prove
+ (`!z. cexp(z) * cexp(--z) = Cx(&1)`,
+  MP_TAC(SPEC `Cx(&0)` CEXP_ADD_MUL) THEN MATCH_MP_TAC MONO_FORALL THEN
+  SIMP_TAC[COMPLEX_ADD_LID; CEXP_0]);;
+
+let CEXP_NEG_LMUL = prove
+ (`!z. cexp(--z) * cexp(z) = Cx(&1)`,
+  ONCE_REWRITE_TAC[COMPLEX_MUL_SYM] THEN REWRITE_TAC[CEXP_NEG_RMUL]);;
+
+let CEXP_NEG = prove
+ (`!z. cexp(--z) = inv(cexp z)`,
+  MP_TAC CEXP_NEG_LMUL THEN MATCH_MP_TAC MONO_FORALL THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CEXP_ADD = prove
+ (`!w z. cexp(w + z) = cexp(w) * cexp(z)`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(SPECL [`w:complex`; `z:complex`] CEXP_ADD_MUL) THEN
+  MP_TAC(SPEC `z:complex` CEXP_NEG_LMUL) THEN CONV_TAC COMPLEX_FIELD);;
+
+let CEXP_SUB = prove
+ (`!w z. cexp(w - z) = cexp(w) / cexp(z)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[complex_sub; complex_div; CEXP_ADD; CEXP_NEG]);;
+
+let CEXP_NZ = prove
+ (`!z. ~(cexp(z) = Cx(&0))`,
+  MP_TAC CEXP_NEG_LMUL THEN MATCH_MP_TAC MONO_FORALL THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CEXP_N = prove
+ (`!n x. cexp(Cx(&n) * x) = cexp(x) pow n`,
+  INDUCT_TAC THEN REWRITE_TAC[GSYM REAL_OF_NUM_SUC; CX_ADD] THEN
+  REWRITE_TAC[COMPLEX_MUL_LZERO; complex_pow; CEXP_0] THEN
+  ASM_REWRITE_TAC[COMPLEX_ADD_RDISTRIB; CEXP_ADD; COMPLEX_MUL_LID] THEN
+  REWRITE_TAC[COMPLEX_MUL_AC]);;
+
+let CEXP_VSUM = prove
+ (`!f s. FINITE s ==> cexp(vsum s f) = cproduct s (\x. cexp(f x))`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; CPRODUCT_CLAUSES; CEXP_ADD; COMPLEX_VEC_0; CEXP_0]);;
+
+let LIM_CEXP_MINUS_1 = prove
+ (`((\z. (cexp(z) - Cx(&1)) / z) --> Cx(&1)) (at (Cx(&0)))`,
+  MP_TAC(COMPLEX_DIFF_CONV
+      `((\z. cexp(z) - Cx(&1)) has_complex_derivative f') (at(Cx(&0)))`) THEN
+  REWRITE_TAC[HAS_COMPLEX_DERIVATIVE_AT; CEXP_0; COMPLEX_SUB_REFL] THEN
+  REWRITE_TAC[COMPLEX_MUL_LID; COMPLEX_SUB_RZERO]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Crude bounds on complex exponential function, usable to get tighter ones. *)
+(* ------------------------------------------------------------------------- *)
+
+let CEXP_BOUND_BLEMMA = prove
+ (`!B. (!z. norm(z) <= &1 / &2 ==> norm(cexp z) <= B)
+       ==> !z. norm(z) <= &1 / &2 ==> norm(cexp z) <= &1 + B / &2`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`cexp`; `cexp`; `cball(Cx(&0),&1 / &2)`; `B:real`]
+                COMPLEX_DIFFERENTIABLE_BOUND) THEN
+  ASM_SIMP_TAC[CONVEX_CBALL; IN_CBALL; dist; COMPLEX_SUB_LZERO; NORM_NEG;
+    HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HAS_COMPLEX_DERIVATIVE_CEXP] THEN
+  DISCH_THEN(MP_TAC o SPECL [`z:complex`; `Cx(&0)`]) THEN
+  REWRITE_TAC[COMPLEX_NORM_0; CEXP_0; COMPLEX_SUB_RZERO] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `norm(y) = &1 /\ d <= e ==> norm(x - y) <= d ==> norm(x) <= &1 + e`) THEN
+  REWRITE_TAC[COMPLEX_NORM_CX; real_div; REAL_ABS_NUM] THEN
+  MATCH_MP_TAC REAL_LE_LMUL THEN FIRST_X_ASSUM(MP_TAC o SPEC `Cx(&0)`) THEN
+  REWRITE_TAC[COMPLEX_NORM_CX] THEN POP_ASSUM MP_TAC THEN
+  NORM_ARITH_TAC);;
+
+let CEXP_BOUND_HALF = prove
+ (`!z. norm(z) <= &1 / &2 ==> norm(cexp z) <= &2`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`IMAGE cexp (cball(Cx(&0),&1 / &2))`; `Cx(&0)`]
+    DISTANCE_ATTAINS_SUP) THEN
+  SIMP_TAC[COMPACT_CONTINUOUS_IMAGE; COMPACT_CBALL; CONTINUOUS_ON_CEXP;
+           IMAGE_EQ_EMPTY; CBALL_EQ_EMPTY; FORALL_IN_IMAGE; EXISTS_IN_IMAGE;
+           IN_CBALL; dist; COMPLEX_SUB_LZERO; NORM_NEG] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  DISCH_THEN(X_CHOOSE_THEN `w:complex` STRIP_ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o SPEC `w:complex` o MATCH_MP CEXP_BOUND_BLEMMA) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `z:complex`) THEN
+  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let CEXP_BOUND_LEMMA = prove
+ (`!z. norm(z) <= &1 / &2 ==> norm(cexp z) <= &1 + &2 * norm(z)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`cexp`; `cexp`; `cball(Cx(&0),&1 / &2)`; `&2`]
+                COMPLEX_DIFFERENTIABLE_BOUND) THEN
+  ASM_SIMP_TAC[CONVEX_CBALL; IN_CBALL; dist; COMPLEX_SUB_LZERO; NORM_NEG;
+               HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HAS_COMPLEX_DERIVATIVE_CEXP;
+               CEXP_BOUND_HALF] THEN
+  DISCH_THEN(MP_TAC o SPECL [`z:complex`; `Cx(&0)`]) THEN
+  REWRITE_TAC[COMPLEX_NORM_0; CEXP_0; COMPLEX_SUB_RZERO] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `norm(y) = &1 ==> norm(x - y) <= d ==> norm(x) <= &1 + d`) THEN
+  REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_NUM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex trig functions.                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let ccos = new_definition
+  `ccos z = (cexp(ii * z) + cexp(--ii * z)) / Cx(&2)`;;
+
+let csin = new_definition
+  `csin z = (cexp(ii * z) - cexp(--ii * z)) / (Cx(&2) * ii)`;;
+
+let CSIN_0 = prove
+ (`csin(Cx(&0)) = Cx(&0)`,
+  REWRITE_TAC[csin; COMPLEX_MUL_RZERO; COMPLEX_SUB_REFL] THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CCOS_0 = prove
+ (`ccos(Cx(&0)) = Cx(&1)`,
+  REWRITE_TAC[ccos; COMPLEX_MUL_RZERO; CEXP_0] THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CSIN_CIRCLE = prove
+ (`!z. csin(z) pow 2 + ccos(z) pow 2 = Cx(&1)`,
+  GEN_TAC THEN REWRITE_TAC[csin; ccos] THEN
+  MP_TAC(SPEC `ii * z` CEXP_NEG_LMUL) THEN
+  REWRITE_TAC[COMPLEX_MUL_LNEG] THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CSIN_ADD = prove
+ (`!w z. csin(w + z) = csin(w) * ccos(z) + ccos(w) * csin(z)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[csin; ccos; COMPLEX_ADD_LDISTRIB; CEXP_ADD] THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CCOS_ADD = prove
+ (`!w z. ccos(w + z) = ccos(w) * ccos(z) - csin(w) * csin(z)`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[csin; ccos; COMPLEX_ADD_LDISTRIB; CEXP_ADD] THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CSIN_NEG = prove
+ (`!z. csin(--z) = --(csin(z))`,
+  REWRITE_TAC[csin; COMPLEX_MUL_LNEG; COMPLEX_MUL_RNEG; COMPLEX_NEG_NEG] THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CCOS_NEG = prove
+ (`!z. ccos(--z) = ccos(z)`,
+  REWRITE_TAC[ccos; COMPLEX_MUL_LNEG; COMPLEX_MUL_RNEG; COMPLEX_NEG_NEG] THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CSIN_DOUBLE = prove
+ (`!z. csin(Cx(&2) * z) = Cx(&2) * csin(z) * ccos(z)`,
+  REWRITE_TAC[COMPLEX_RING `Cx(&2) * x = x + x`; CSIN_ADD] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let CCOS_DOUBLE = prove
+ (`!z. ccos(Cx(&2) * z) = (ccos(z) pow 2) - (csin(z) pow 2)`,
+  REWRITE_TAC[COMPLEX_RING `Cx(&2) * x = x + x`; CCOS_ADD] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let CSIN_SUB = prove
+ (`!w z. csin(w - z) = csin(w) * ccos(z) - ccos(w) * csin(z)`,
+  REWRITE_TAC[complex_sub; COMPLEX_MUL_RNEG; CSIN_ADD; CSIN_NEG; CCOS_NEG]);;
+
+let CCOS_SUB = prove
+ (`!w z. ccos(w - z) = ccos(w) * ccos(z) + csin(w) * csin(z)`,
+  REWRITE_TAC[complex_sub; CCOS_ADD; CSIN_NEG; CCOS_NEG;
+              COMPLEX_MUL_RNEG; COMPLEX_NEG_NEG]);;
+
+let COMPLEX_MUL_CSIN_CSIN = prove
+ (`!w z. csin(w) * csin(z) = (ccos(w - z) - ccos(w + z)) / Cx(&2)`,
+  REWRITE_TAC[CCOS_ADD; CCOS_SUB] THEN CONV_TAC COMPLEX_RING);;
+
+let COMPLEX_MUL_CSIN_CCOS = prove
+ (`!w z. csin(w) * ccos(z) = (csin(w + z) + csin(w - z)) / Cx(&2)`,
+  REWRITE_TAC[CSIN_ADD; CSIN_SUB] THEN CONV_TAC COMPLEX_RING);;
+
+let COMPLEX_MUL_CCOS_CSIN = prove
+ (`!w z. ccos(w) * csin(z) = (csin(w + z) - csin(w - z)) / Cx(&2)`,
+  REWRITE_TAC[CSIN_ADD; CSIN_SUB] THEN CONV_TAC COMPLEX_RING);;
+
+let COMPLEX_MUL_CCOS_CCOS = prove
+ (`!w z. ccos(w) * ccos(z) = (ccos(w - z) + ccos(w + z)) / Cx(&2)`,
+  REWRITE_TAC[CCOS_ADD; CCOS_SUB] THEN CONV_TAC COMPLEX_RING);;
+
+let COMPLEX_ADD_CSIN = prove
+ (`!w z. csin(w) + csin(z) =
+         Cx(&2) * csin((w + z) / Cx(&2)) * ccos((w - z) / Cx(&2))`,
+  SIMP_TAC[COMPLEX_MUL_CSIN_CCOS; COMPLEX_RING `Cx(&2) * x / Cx(&2) = x`] THEN
+  REPEAT GEN_TAC THEN BINOP_TAC THEN AP_TERM_TAC THEN CONV_TAC COMPLEX_RING);;
+
+let COMPLEX_SUB_CSIN = prove
+ (`!w z. csin(w) - csin(z) =
+         Cx(&2) * csin((w - z) / Cx(&2)) * ccos((w + z) / Cx(&2))`,
+  SIMP_TAC[COMPLEX_MUL_CSIN_CCOS; COMPLEX_RING `Cx(&2) * x / Cx(&2) = x`] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[complex_sub; GSYM CSIN_NEG] THEN
+  BINOP_TAC THEN AP_TERM_TAC THEN CONV_TAC COMPLEX_RING);;
+
+let COMPLEX_ADD_CCOS = prove
+ (`!w z. ccos(w) + ccos(z) =
+         Cx(&2) * ccos((w + z) / Cx(&2)) * ccos((w - z) / Cx(&2))`,
+  SIMP_TAC[COMPLEX_MUL_CCOS_CCOS; COMPLEX_RING `Cx(&2) * x / Cx(&2) = x`] THEN
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [COMPLEX_ADD_SYM] THEN
+  BINOP_TAC THEN AP_TERM_TAC THEN CONV_TAC COMPLEX_RING);;
+
+let COMPLEX_SUB_CCOS = prove
+ (`!w z. ccos(w) - ccos(z) =
+         Cx(&2) * csin((w + z) / Cx(&2)) * csin((z - w) / Cx(&2))`,
+  SIMP_TAC[COMPLEX_MUL_CSIN_CSIN; COMPLEX_RING `Cx(&2) * x / Cx(&2) = x`] THEN
+  REPEAT GEN_TAC THEN BINOP_TAC THEN AP_TERM_TAC THEN CONV_TAC COMPLEX_RING);;
+
+let CCOS_DOUBLE_CCOS = prove
+ (`!z. ccos(Cx(&2) * z) = Cx(&2) * ccos z pow 2 - Cx(&1)`,
+  GEN_TAC THEN REWRITE_TAC[COMPLEX_RING `Cx(&2) * x = x + x`; CCOS_ADD] THEN
+  MP_TAC(SPEC `z:complex` CSIN_CIRCLE) THEN CONV_TAC COMPLEX_RING);;
+
+let CCOS_DOUBLE_CSIN = prove
+ (`!z. ccos(Cx(&2) * z) = Cx(&1) - Cx(&2) * csin z pow 2`,
+  GEN_TAC THEN REWRITE_TAC[COMPLEX_RING `Cx(&2) * x = x + x`; CCOS_ADD] THEN
+  MP_TAC(SPEC `z:complex` CSIN_CIRCLE) THEN CONV_TAC COMPLEX_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* Euler and de Moivre formulas.                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let CEXP_EULER = prove
+ (`!z. cexp(ii * z) = ccos(z) + ii * csin(z)`,
+  REWRITE_TAC[ccos; csin] THEN CONV_TAC COMPLEX_FIELD);;
+
+let DEMOIVRE = prove
+ (`!z n. (ccos z + ii * csin z) pow n =
+         ccos(Cx(&n) * z) + ii * csin(Cx(&n) * z)`,
+  REWRITE_TAC[GSYM CEXP_EULER; GSYM CEXP_N] THEN
+  REWRITE_TAC[COMPLEX_MUL_AC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real exponential function. Same names as old Library/transc.ml.           *)
+(* ------------------------------------------------------------------------- *)
+
+let exp = new_definition `exp(x) = Re(cexp(Cx x))`;;
+
+let CNJ_CEXP = prove
+ (`!z. cnj(cexp z) = cexp(cnj z)`,
+  GEN_TAC THEN MATCH_MP_TAC SERIES_UNIQUE THEN
+  MAP_EVERY EXISTS_TAC [`\n. cnj(z pow n / Cx(&(FACT n)))`; `from 0`] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[SUMS_CNJ; CEXP_CONVERGES];
+    REWRITE_TAC[CNJ_DIV; CNJ_CX; CNJ_POW; CEXP_CONVERGES]]);;
+
+let REAL_EXP = prove
+ (`!z. real z ==> real(cexp z)`,
+  SIMP_TAC[REAL_CNJ; CNJ_CEXP]);;
+
+let CX_EXP = prove
+ (`!x. Cx(exp x) = cexp(Cx x)`,
+  REWRITE_TAC[exp] THEN MESON_TAC[REAL; REAL_CX; REAL_EXP]);;
+
+let REAL_EXP_ADD = prove
+ (`!x y. exp(x + y) = exp(x) * exp(y)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_MUL; CX_EXP; CX_ADD; CEXP_ADD]);;
+
+let REAL_EXP_0 = prove
+ (`exp(&0) = &1`,
+  REWRITE_TAC[GSYM CX_INJ; CX_EXP; CEXP_0]);;
+
+let REAL_EXP_ADD_MUL = prove
+ (`!x y. exp(x + y) * exp(--x) = exp(y)`,
+  ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
+  REWRITE_TAC[GSYM CX_INJ; CX_MUL; CX_EXP; CX_ADD; CX_NEG; CEXP_ADD_MUL]);;
+
+let REAL_EXP_NEG_MUL = prove
+ (`!x. exp(x) * exp(--x) = &1`,
+  REWRITE_TAC[GSYM CX_INJ; CX_MUL; CX_EXP; CX_NEG; CEXP_NEG_RMUL]);;
+
+let REAL_EXP_NEG_MUL2 = prove
+ (`!x. exp(--x) * exp(x) = &1`,
+  REWRITE_TAC[GSYM CX_INJ; CX_MUL; CX_EXP; CX_NEG; CEXP_NEG_LMUL]);;
+
+let REAL_EXP_NEG = prove
+ (`!x. exp(--x) = inv(exp(x))`,
+  REWRITE_TAC[GSYM CX_INJ; CX_INV; CX_EXP; CX_NEG; CEXP_NEG]);;
+
+let REAL_EXP_N = prove
+ (`!n x. exp(&n * x) = exp(x) pow n`,
+  REWRITE_TAC[GSYM CX_INJ; CX_EXP; CX_POW; CX_MUL; CEXP_N]);;
+
+let REAL_EXP_SUB = prove
+ (`!x y. exp(x - y) = exp(x) / exp(y)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_SUB; CX_DIV; CX_EXP; CEXP_SUB]);;
+
+let REAL_EXP_NZ = prove
+ (`!x. ~(exp(x) = &0)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_EXP; CEXP_NZ]);;
+
+let REAL_EXP_POS_LE = prove
+ (`!x. &0 <= exp(x)`,
+  GEN_TAC THEN SUBST1_TAC(REAL_ARITH `x = x / &2 + x / &2`) THEN
+  REWRITE_TAC[REAL_EXP_ADD; REAL_LE_SQUARE]);;
+
+let REAL_EXP_POS_LT = prove
+ (`!x. &0 < exp(x)`,
+  REWRITE_TAC[REAL_LT_LE; REAL_EXP_NZ; REAL_EXP_POS_LE]);;
+
+let REAL_EXP_LE_X = prove
+ (`!x. &0 <= x ==> &1 + x <= exp(x)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[exp; RE_DEF] THEN
+  MATCH_MP_TAC(MATCH_MP
+   (ONCE_REWRITE_RULE[TAUT `a /\ b /\ c ==> d <=> b ==> a /\ c ==> d`]
+        LIM_COMPONENT_LBOUND)
+   (REWRITE_RULE[sums] (SPEC `Cx x` CEXP_CONVERGES))) THEN
+  SIMP_TAC[DIMINDEX_2; ARITH; TRIVIAL_LIMIT_SEQUENTIALLY;
+           VSUM_COMPONENT; EVENTUALLY_SEQUENTIALLY; FROM_0; INTER_UNIV] THEN
+  REWRITE_TAC[GSYM CX_DIV; GSYM RE_DEF; RE_CX; GSYM CX_POW] THEN
+  EXISTS_TAC `1` THEN SIMP_TAC[SUM_CLAUSES_LEFT; LE_0; ADD_CLAUSES] THEN
+  CONV_TAC NUM_REDUCE_CONV THEN
+  SIMP_TAC[real_pow; REAL_POW_1; REAL_DIV_1; REAL_LE_ADDR; REAL_ADD_ASSOC] THEN
+  ASM_SIMP_TAC[SUM_POS_LE_NUMSEG; REAL_LE_DIV; REAL_POW_LE; REAL_POS]);;
+
+let REAL_EXP_LT_1 = prove
+ (`!x. &0 < x ==> &1 < exp(x)`,
+  MP_TAC REAL_EXP_LE_X THEN MATCH_MP_TAC MONO_FORALL THEN REAL_ARITH_TAC);;
+
+let REAL_EXP_MONO_IMP = prove
+ (`!x y. x < y ==> exp(x) < exp(y)`,
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM REAL_SUB_LT] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REAL_EXP_LT_1) THEN
+  SIMP_TAC[REAL_EXP_SUB; REAL_LT_RDIV_EQ; REAL_EXP_POS_LT; REAL_MUL_LID]);;
+
+let REAL_EXP_MONO_LT = prove
+ (`!x y. exp(x) < exp(y) <=> x < y`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC(REAL_ARITH
+   `(x < y ==> f < g) /\ (x = y ==> f = g) /\ (y < x ==> g < f)
+    ==> (f < g <=> x < y)`) THEN
+  SIMP_TAC[REAL_EXP_MONO_IMP]);;
+
+let REAL_EXP_MONO_LE = prove
+ (`!x y. exp(x) <= exp(y) <=> x <= y`,
+  REWRITE_TAC[GSYM REAL_NOT_LT; REAL_EXP_MONO_LT]);;
+
+let REAL_EXP_INJ = prove
+ (`!x y. (exp(x) = exp(y)) <=> (x = y)`,
+  REWRITE_TAC[GSYM REAL_LE_ANTISYM; REAL_EXP_MONO_LE]);;
+
+let REAL_EXP_EQ_1 = prove
+ (`!x. exp(x) = &1 <=> x = &0`,
+  ONCE_REWRITE_TAC[GSYM REAL_EXP_0] THEN REWRITE_TAC[REAL_EXP_INJ]);;
+
+let REAL_ABS_EXP = prove
+ (`!x. abs(exp x) = exp x`,
+  REWRITE_TAC[real_abs; REAL_EXP_POS_LE]);;
+
+let REAL_EXP_SUM = prove
+ (`!f s. FINITE s ==> exp(sum s f) = product s (\x. exp(f x))`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[SUM_CLAUSES; PRODUCT_CLAUSES; REAL_EXP_ADD; REAL_EXP_0]);;
+
+let REAL_EXP_BOUND_LEMMA = prove
+ (`!x. &0 <= x /\ x <= inv(&2) ==> exp(x) <= &1 + &2 * x`,
+  REPEAT STRIP_TAC THEN MP_TAC(SPEC `Cx x` CEXP_BOUND_LEMMA) THEN
+  REWRITE_TAC[GSYM CX_EXP; COMPLEX_NORM_CX; RE_CX] THEN
+  ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real trig functions, their reality,  derivatives of complex versions.     *)
+(* ------------------------------------------------------------------------- *)
+
+let sin = new_definition `sin(x) = Re(csin(Cx x))`;;
+
+let cos = new_definition `cos(x) = Re(ccos(Cx x))`;;
+
+let CNJ_CSIN = prove
+ (`!z. cnj(csin z) = csin(cnj z)`,
+  REWRITE_TAC[csin; CNJ_DIV; CNJ_SUB; CNJ_MUL; CNJ_CX; CNJ_CEXP;
+              CNJ_NEG; CNJ_II; COMPLEX_NEG_NEG] THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CNJ_CCOS = prove
+ (`!z. cnj(ccos z) = ccos(cnj z)`,
+  REWRITE_TAC[ccos; CNJ_DIV; CNJ_ADD; CNJ_MUL; CNJ_CX; CNJ_CEXP;
+              CNJ_NEG; CNJ_II; COMPLEX_NEG_NEG; COMPLEX_ADD_AC]);;
+
+let REAL_SIN = prove
+ (`!z. real z ==> real(csin z)`,
+  SIMP_TAC[REAL_CNJ; CNJ_CSIN]);;
+
+let REAL_COS = prove
+ (`!z. real z ==> real(ccos z)`,
+  SIMP_TAC[REAL_CNJ; CNJ_CCOS]);;
+
+let CX_SIN = prove
+ (`!x. Cx(sin x) = csin(Cx x)`,
+  REWRITE_TAC[sin] THEN MESON_TAC[REAL; REAL_CX; REAL_SIN]);;
+
+let CX_COS = prove
+ (`!x. Cx(cos x) = ccos(Cx x)`,
+  REWRITE_TAC[cos] THEN MESON_TAC[REAL; REAL_CX; REAL_COS]);;
+
+let HAS_COMPLEX_DERIVATIVE_CSIN = prove
+ (`!z. (csin has_complex_derivative ccos z) (at z)`,
+  GEN_TAC THEN GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+  REWRITE_TAC[csin; ccos] THEN COMPLEX_DIFF_TAC THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let COMPLEX_DIFFERENTIABLE_AT_CSIN = prove
+ (`!z. csin complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CSIN]);;
+
+let COMPLEX_DIFFERENTIABLE_WITHIN_CSIN = prove
+ (`!s z. csin complex_differentiable (at z within s)`,
+  MESON_TAC[COMPLEX_DIFFERENTIABLE_AT_WITHIN;
+            COMPLEX_DIFFERENTIABLE_AT_CSIN]);;
+
+add_complex_differentiation_theorems
+ (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+   (MATCH_MP HAS_COMPLEX_DERIVATIVE_CHAIN_UNIV
+             HAS_COMPLEX_DERIVATIVE_CSIN)));;
+
+let HAS_COMPLEX_DERIVATIVE_CCOS = prove
+ (`!z. (ccos has_complex_derivative --csin z) (at z)`,
+  GEN_TAC THEN GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+  REWRITE_TAC[csin; ccos] THEN COMPLEX_DIFF_TAC THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let COMPLEX_DIFFERENTIABLE_AT_CCOS = prove
+ (`!z. ccos complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CCOS]);;
+
+let COMPLEX_DIFFERENTIABLE_WITHIN_CCOS = prove
+ (`!s z. ccos complex_differentiable (at z within s)`,
+  MESON_TAC[COMPLEX_DIFFERENTIABLE_AT_WITHIN;
+            COMPLEX_DIFFERENTIABLE_AT_CCOS]);;
+
+add_complex_differentiation_theorems
+ (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+   (MATCH_MP HAS_COMPLEX_DERIVATIVE_CHAIN_UNIV
+             HAS_COMPLEX_DERIVATIVE_CCOS)));;
+
+let CONTINUOUS_AT_CSIN = prove
+ (`!z. csin continuous at z`,
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CSIN;
+            HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT]);;
+
+let CONTINUOUS_WITHIN_CSIN = prove
+ (`!s z. csin continuous (at z within s)`,
+  MESON_TAC[CONTINUOUS_AT_WITHIN; CONTINUOUS_AT_CSIN]);;
+
+let CONTINUOUS_ON_CSIN = prove
+ (`!s. csin continuous_on s`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON; CONTINUOUS_AT_CSIN]);;
+
+let HOLOMORPHIC_ON_CSIN = prove
+ (`!s. csin holomorphic_on s`,
+  REWRITE_TAC [holomorphic_on] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HAS_COMPLEX_DERIVATIVE_CSIN]);;
+
+let CONTINUOUS_AT_CCOS = prove
+ (`!z. ccos continuous at z`,
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CCOS;
+            HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT]);;
+
+let CONTINUOUS_WITHIN_CCOS = prove
+ (`!s z. ccos continuous (at z within s)`,
+  MESON_TAC[CONTINUOUS_AT_WITHIN; CONTINUOUS_AT_CCOS]);;
+
+let CONTINUOUS_ON_CCOS = prove
+ (`!s. ccos continuous_on s`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON; CONTINUOUS_AT_CCOS]);;
+
+let HOLOMORPHIC_ON_CCOS = prove
+ (`!s. ccos holomorphic_on s`,
+  REWRITE_TAC [holomorphic_on] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HAS_COMPLEX_DERIVATIVE_CCOS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Slew of theorems for compatibility with old transc.ml file.               *)
+(* ------------------------------------------------------------------------- *)
+
+let SIN_0 = prove
+ (`sin(&0) = &0`,
+  REWRITE_TAC[GSYM CX_INJ; CX_SIN; CSIN_0]);;
+
+let COS_0 = prove
+ (`cos(&0) = &1`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CCOS_0]);;
+
+let SIN_CIRCLE = prove
+ (`!x. (sin(x) pow 2) + (cos(x) pow 2) = &1`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CX_SIN; CX_ADD; CX_POW; CSIN_CIRCLE]);;
+
+let SIN_ADD = prove
+ (`!x y. sin(x + y) = sin(x) * cos(y) + cos(x) * sin(y)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CX_SIN; CX_ADD; CX_MUL; CSIN_ADD]);;
+
+let COS_ADD = prove
+ (`!x y. cos(x + y) = cos(x) * cos(y) - sin(x) * sin(y)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CX_SIN; CX_ADD; CX_SUB; CX_MUL; CCOS_ADD]);;
+
+let SIN_NEG = prove
+ (`!x. sin(--x) = --(sin(x))`,
+  REWRITE_TAC[GSYM CX_INJ; CX_SIN; CX_NEG; CSIN_NEG]);;
+
+let COS_NEG = prove
+ (`!x. cos(--x) = cos(x)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CX_NEG; CCOS_NEG]);;
+
+let SIN_DOUBLE = prove
+ (`!x. sin(&2 * x) = &2 * sin(x) * cos(x)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_SIN; CX_COS; CX_MUL; CSIN_DOUBLE]);;
+
+let COS_DOUBLE = prove
+ (`!x. cos(&2 * x) = (cos(x) pow 2) - (sin(x) pow 2)`,
+  SIMP_TAC[GSYM CX_INJ; CX_SIN; CX_COS; CX_SUB; CX_MUL; CX_POW; CCOS_DOUBLE]);;
+
+let COS_DOUBLE_COS = prove
+ (`!x. cos(&2 * x) = &2 * cos(x) pow 2 - &1`,
+  MP_TAC SIN_CIRCLE THEN MATCH_MP_TAC MONO_FORALL THEN
+  REWRITE_TAC[COS_DOUBLE] THEN REAL_ARITH_TAC);;
+
+let (SIN_BOUND,COS_BOUND) = (CONJ_PAIR o prove)
+ (`(!x. abs(sin x) <= &1) /\ (!x. abs(cos x) <= &1)`,
+  CONJ_TAC THEN GEN_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_ABS_NUM] THEN
+  ONCE_REWRITE_TAC[REAL_LE_SQUARE_ABS] THEN
+  MP_TAC(SPEC `x:real` SIN_CIRCLE) THEN
+  MAP_EVERY (MP_TAC o C SPEC REAL_LE_SQUARE) [`sin x`; `cos x`] THEN
+  REAL_ARITH_TAC);;
+
+let SIN_BOUNDS = prove
+ (`!x. --(&1) <= sin(x) /\ sin(x) <= &1`,
+  MP_TAC SIN_BOUND THEN MATCH_MP_TAC MONO_FORALL THEN REAL_ARITH_TAC);;
+
+let COS_BOUNDS = prove
+ (`!x. --(&1) <= cos(x) /\ cos(x) <= &1`,
+  MP_TAC COS_BOUND THEN MATCH_MP_TAC MONO_FORALL THEN REAL_ARITH_TAC);;
+
+let COS_ABS = prove
+ (`!x. cos(abs x) = cos(x)`,
+  REWRITE_TAC[real_abs] THEN MESON_TAC[COS_NEG]);;
+
+let SIN_SUB = prove
+ (`!w z. sin(w - z) = sin(w) * cos(z) - cos(w) * sin(z)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_SIN; CX_COS; CX_SUB; CX_MUL; CSIN_SUB]);;
+
+let COS_SUB = prove
+ (`!w z. cos(w - z) = cos(w) * cos(z) + sin(w) * sin(z)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_SIN; CX_COS; CX_SUB; CX_ADD; CX_MUL; CCOS_SUB]);;
+
+let REAL_MUL_SIN_SIN = prove
+ (`!x y. sin(x) * sin(y) = (cos(x - y) - cos(x + y)) / &2`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CX_SIN; CX_ADD; CX_SUB; CX_MUL; CX_DIV] THEN
+  REWRITE_TAC[COMPLEX_MUL_CSIN_CSIN]);;
+
+let REAL_MUL_SIN_COS = prove
+ (`!x y. sin(x) * cos(y) = (sin(x + y) + sin(x - y)) / &2`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CX_SIN; CX_ADD; CX_SUB; CX_MUL; CX_DIV] THEN
+  REWRITE_TAC[COMPLEX_MUL_CSIN_CCOS]);;
+
+let REAL_MUL_COS_SIN = prove
+ (`!x y. cos(x) * sin(y) = (sin(x + y) - sin(x - y)) / &2`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CX_SIN; CX_ADD; CX_SUB; CX_MUL; CX_DIV] THEN
+  REWRITE_TAC[COMPLEX_MUL_CCOS_CSIN]);;
+
+let REAL_MUL_COS_COS = prove
+ (`!x y. cos(x) * cos(y) = (cos(x - y) + cos(x + y)) / &2`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CX_SIN; CX_ADD; CX_SUB; CX_MUL; CX_DIV] THEN
+  REWRITE_TAC[COMPLEX_MUL_CCOS_CCOS]);;
+
+let REAL_ADD_SIN = prove
+ (`!x y. sin(x) + sin(y) = &2 * sin((x + y) / &2) * cos((x - y) / &2)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CX_SIN; CX_ADD; CX_SUB; CX_MUL; CX_DIV] THEN
+  REWRITE_TAC[COMPLEX_ADD_CSIN]);;
+
+let REAL_SUB_SIN = prove
+ (`!x y. sin(x) - sin(y) = &2 * sin((x - y) / &2) * cos((x + y) / &2)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CX_SIN; CX_ADD; CX_SUB; CX_MUL; CX_DIV] THEN
+  REWRITE_TAC[COMPLEX_SUB_CSIN]);;
+
+let REAL_ADD_COS = prove
+ (`!x y. cos(x) + cos(y) = &2 * cos((x + y) / &2) * cos((x - y) / &2)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CX_SIN; CX_ADD; CX_SUB; CX_MUL; CX_DIV] THEN
+  REWRITE_TAC[COMPLEX_ADD_CCOS]);;
+
+let REAL_SUB_COS = prove
+ (`!x y. cos(x) - cos(y) = &2 * sin((x + y) / &2) * sin((y - x) / &2)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CX_SIN; CX_ADD; CX_SUB; CX_MUL; CX_DIV] THEN
+  REWRITE_TAC[COMPLEX_SUB_CCOS]);;
+
+let COS_DOUBLE_SIN = prove
+ (`!x. cos(&2 * x) = &1 - &2 * sin x pow 2`,
+  GEN_TAC THEN REWRITE_TAC[REAL_RING `&2 * x = x + x`; COS_ADD] THEN
+  MP_TAC(SPEC `x:real` SIN_CIRCLE) THEN CONV_TAC REAL_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* Get a nice real/imaginary separation in Euler's formula.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let EULER = prove
+ (`!z. cexp(z) = Cx(exp(Re z)) * (Cx(cos(Im z)) + ii * Cx(sin(Im z)))`,
+  GEN_TAC THEN GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [COMPLEX_EXPAND] THEN
+  REWRITE_TAC[CEXP_ADD; CEXP_EULER; GSYM CX_SIN; GSYM CX_COS; GSYM CX_EXP]);;
+
+let RE_CEXP = prove
+ (`!z. Re(cexp z) = exp(Re z) * cos(Im z)`,
+  REWRITE_TAC[EULER; RE_ADD; RE_MUL_CX; RE_MUL_II; IM_CX; RE_CX] THEN
+  REAL_ARITH_TAC);;
+
+let IM_CEXP = prove
+ (`!z. Im(cexp z) = exp(Re z) * sin(Im z)`,
+  REWRITE_TAC[EULER; IM_ADD; IM_MUL_CX; IM_MUL_II; IM_CX; RE_CX] THEN
+  REAL_ARITH_TAC);;
+
+let RE_CSIN = prove
+ (`!z. Re(csin z) = (exp(Im z) + exp(--(Im z))) / &2 * sin(Re z)`,
+  GEN_TAC THEN REWRITE_TAC[csin] THEN
+  SIMP_TAC[COMPLEX_FIELD `x / (Cx(&2) * ii) = ii * --(x / Cx(&2))`] THEN
+  REWRITE_TAC[IM_MUL_II; IM_DIV_CX; RE_NEG; IM_SUB; IM_CEXP;
+              RE_MUL_II; COMPLEX_MUL_LNEG; IM_NEG] THEN
+  REWRITE_TAC[REAL_NEG_NEG; SIN_NEG] THEN CONV_TAC REAL_RING);;
+
+let IM_CSIN = prove
+ (`!z. Im(csin z) = (exp(Im z) - exp(--(Im z))) / &2 * cos(Re z)`,
+  GEN_TAC THEN REWRITE_TAC[csin] THEN
+  SIMP_TAC[COMPLEX_FIELD `x / (Cx(&2) * ii) = ii * --(x / Cx(&2))`] THEN
+  REWRITE_TAC[IM_MUL_II; RE_DIV_CX; RE_NEG; RE_SUB; RE_CEXP;
+              RE_MUL_II; COMPLEX_MUL_LNEG; IM_NEG] THEN
+  REWRITE_TAC[REAL_NEG_NEG; COS_NEG] THEN CONV_TAC REAL_RING);;
+
+let RE_CCOS = prove
+ (`!z. Re(ccos z) = (exp(Im z) + exp(--(Im z))) / &2 * cos(Re z)`,
+  GEN_TAC THEN REWRITE_TAC[ccos] THEN
+  REWRITE_TAC[RE_DIV_CX; RE_ADD; RE_CEXP; COMPLEX_MUL_LNEG;
+              RE_MUL_II; IM_MUL_II; RE_NEG; IM_NEG; COS_NEG] THEN
+  REWRITE_TAC[REAL_NEG_NEG] THEN CONV_TAC REAL_RING);;
+
+let IM_CCOS = prove
+ (`!z. Im(ccos z) = (exp(--(Im z)) - exp(Im z)) / &2 * sin(Re z)`,
+  GEN_TAC THEN REWRITE_TAC[ccos] THEN
+  REWRITE_TAC[IM_DIV_CX; IM_ADD; IM_CEXP; COMPLEX_MUL_LNEG;
+              RE_MUL_II; IM_MUL_II; RE_NEG; IM_NEG; SIN_NEG] THEN
+  REWRITE_TAC[REAL_NEG_NEG] THEN CONV_TAC REAL_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some special intermediate value theorems over the reals.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let IVT_INCREASING_RE = prove
+ (`!f a b y.
+        a <= b /\
+        (!x. a <= x /\ x <= b ==> f continuous at (Cx x)) /\
+        Re(f(Cx a)) <= y /\ y <= Re(f(Cx b))
+        ==> ?x. a <= x /\ x <= b /\ Re(f(Cx x)) = y`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(f:complex->complex) o Cx o drop`;
+                 `lift a`; `lift b`; `y:real`; `1`]
+        IVT_INCREASING_COMPONENT_1) THEN
+  REWRITE_TAC[EXISTS_DROP; GSYM drop; LIFT_DROP; o_THM; GSYM RE_DEF] THEN
+  ASM_REWRITE_TAC[IN_INTERVAL_1; GSYM CONJ_ASSOC; LIFT_DROP] THEN
+  DISCH_THEN MATCH_MP_TAC THEN REWRITE_TAC[DIMINDEX_2; ARITH] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_AT_COMPOSE THEN
+  ASM_SIMP_TAC[o_THM] THEN REWRITE_TAC[continuous_at; o_THM] THEN
+  REWRITE_TAC[dist; GSYM CX_SUB; GSYM DROP_SUB; COMPLEX_NORM_CX] THEN
+  REWRITE_TAC[GSYM ABS_DROP] THEN MESON_TAC[]);;
+
+let IVT_DECREASING_RE = prove
+ (`!f a b y.
+        a <= b /\
+        (!x. a <= x /\ x <= b ==> f continuous at (Cx x)) /\
+        Re(f(Cx b)) <= y /\ y <= Re(f(Cx a))
+        ==> ?x. a <= x /\ x <= b /\ Re(f(Cx x)) = y`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_EQ_NEG2] THEN
+  REWRITE_TAC[GSYM RE_NEG] THEN MATCH_MP_TAC IVT_INCREASING_RE THEN
+  ASM_SIMP_TAC[CONTINUOUS_NEG; RE_NEG; REAL_LE_NEG2]);;
+
+let IVT_INCREASING_IM = prove
+ (`!f a b y.
+        a <= b /\
+        (!x. a <= x /\ x <= b ==> f continuous at (Cx x)) /\
+        Im(f(Cx a)) <= y /\ y <= Im(f(Cx b))
+        ==> ?x. a <= x /\ x <= b /\ Im(f(Cx x)) = y`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_EQ_NEG2] THEN
+  REWRITE_TAC[SYM(CONJUNCT2(SPEC_ALL RE_MUL_II))] THEN
+  MATCH_MP_TAC IVT_DECREASING_RE THEN
+  ASM_SIMP_TAC[CONTINUOUS_COMPLEX_MUL; ETA_AX; CONTINUOUS_CONST] THEN
+  ASM_REWRITE_TAC[RE_MUL_II; REAL_LE_NEG2]);;
+
+let IVT_DECREASING_IM = prove
+ (`!f a b y.
+        a <= b /\
+        (!x. a <= x /\ x <= b ==> f continuous at (Cx x)) /\
+        Im(f(Cx b)) <= y /\ y <= Im(f(Cx a))
+        ==> ?x. a <= x /\ x <= b /\ Im(f(Cx x)) = y`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_EQ_NEG2] THEN
+  REWRITE_TAC[GSYM IM_NEG] THEN MATCH_MP_TAC IVT_INCREASING_IM THEN
+  ASM_SIMP_TAC[CONTINUOUS_NEG; IM_NEG; REAL_LE_NEG2]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some minimal properties of real logs help to define complex logs.         *)
+(* ------------------------------------------------------------------------- *)
+
+let log_def = new_definition
+ `log y = @x. exp(x) = y`;;
+
+let EXP_LOG = prove
+ (`!x. &0 < x ==> exp(log x) = x`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[log_def] THEN CONV_TAC SELECT_CONV THEN
+  SUBGOAL_THEN `?y. --inv(x) <= y /\ y <= x /\ Re(cexp(Cx y)) = x`
+  MP_TAC THENL [ALL_TAC; MESON_TAC[CX_EXP; RE_CX]] THEN
+  MATCH_MP_TAC IVT_INCREASING_RE THEN
+  SIMP_TAC[GSYM CX_EXP; RE_CX; CONTINUOUS_AT_CEXP] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC(REAL_ARITH `&0 < x /\ &0 < y ==> --y <= x`) THEN
+    ASM_SIMP_TAC[REAL_LT_INV_EQ];
+    ONCE_REWRITE_TAC[GSYM REAL_INV_INV] THEN MATCH_MP_TAC REAL_LE_INV2 THEN
+    ASM_REWRITE_TAC[REAL_EXP_NEG; REAL_INV_INV; REAL_LT_INV_EQ];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH `&1 + x <= y ==> x <= y`) THEN
+  ASM_SIMP_TAC[REAL_EXP_LE_X; REAL_LE_INV_EQ; REAL_LT_IMP_LE]);;
+
+let LOG_EXP = prove
+ (`!x. log(exp x) = x`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_EXP_INJ] THEN
+  SIMP_TAC[EXP_LOG; REAL_EXP_POS_LT]);;
+
+let REAL_EXP_LOG = prove
+ (`!x. (exp(log x) = x) <=> &0 < x`,
+  MESON_TAC[EXP_LOG; REAL_EXP_POS_LT]);;
+
+let LOG_MUL = prove
+ (`!x y. &0 < x /\ &0 < y ==> (log(x * y) = log(x) + log(y))`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_EXP_INJ] THEN
+  ASM_SIMP_TAC[REAL_EXP_ADD; REAL_LT_MUL; EXP_LOG]);;
+
+let LOG_INJ = prove
+ (`!x y. &0 < x /\ &0 < y ==> (log(x) = log(y) <=> x = y)`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM REAL_EXP_INJ] THEN
+  ASM_SIMP_TAC[EXP_LOG]);;
+
+let LOG_1 = prove
+ (`log(&1) = &0`,
+  ONCE_REWRITE_TAC[GSYM REAL_EXP_INJ] THEN
+  REWRITE_TAC[REAL_EXP_0; REAL_EXP_LOG; REAL_LT_01]);;
+
+let LOG_INV = prove
+ (`!x. &0 < x ==> (log(inv x) = --(log x))`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_EXP_INJ] THEN
+  ASM_SIMP_TAC[REAL_EXP_NEG; EXP_LOG; REAL_LT_INV_EQ]);;
+
+let LOG_DIV = prove
+ (`!x y. &0 < x /\ &0 < y ==> log(x / y) = log(x) - log(y)`,
+  SIMP_TAC[real_div; real_sub; LOG_MUL; LOG_INV; REAL_LT_INV_EQ]);;
+
+let LOG_MONO_LT = prove
+ (`!x y. &0 < x /\ &0 < y ==> (log(x) < log(y) <=> x < y)`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM REAL_EXP_MONO_LT] THEN
+  ASM_SIMP_TAC[EXP_LOG]);;
+
+let LOG_MONO_LT_IMP = prove
+ (`!x y. &0 < x /\ x < y ==> log(x) < log(y)`,
+  MESON_TAC[LOG_MONO_LT; REAL_LT_TRANS]);;
+
+let LOG_MONO_LE = prove
+ (`!x y. &0 < x /\ &0 < y ==> (log(x) <= log(y) <=> x <= y)`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM REAL_EXP_MONO_LE] THEN
+  ASM_SIMP_TAC[EXP_LOG]);;
+
+let LOG_MONO_LE_IMP = prove
+ (`!x y. &0 < x /\ x <= y ==> log(x) <= log(y)`,
+  MESON_TAC[LOG_MONO_LE; REAL_LT_IMP_LE; REAL_LTE_TRANS]);;
+
+let LOG_POW = prove
+ (`!n x. &0 < x ==> (log(x pow n) = &n * log(x))`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_EXP_INJ] THEN
+  ASM_SIMP_TAC[REAL_EXP_N; EXP_LOG; REAL_POW_LT]);;
+
+let LOG_LE = prove
+ (`!x. &0 <= x ==> log(&1 + x) <= x`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_EXP_MONO_LE] THEN
+  ASM_SIMP_TAC[EXP_LOG; REAL_ARITH `&0 <= x ==> &0 < &1 + x`; REAL_EXP_LE_X]);;
+
+let LOG_LT_X = prove
+ (`!x. &0 < x ==> log(x) < x`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_EXP_MONO_LT] THEN
+  ASM_SIMP_TAC[EXP_LOG] THEN MP_TAC(SPEC `x:real` REAL_EXP_LE_X) THEN
+  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC);;
+
+let LOG_POS = prove
+ (`!x. &1 <= x ==> &0 <= log(x)`,
+  REWRITE_TAC[GSYM LOG_1] THEN
+  SIMP_TAC[LOG_MONO_LE; ARITH_RULE `&1 <= x ==> &0 < x`; REAL_LT_01]);;
+
+let LOG_POS_LT = prove
+ (`!x. &1 < x ==> &0 < log(x)`,
+  REWRITE_TAC[GSYM LOG_1] THEN
+  SIMP_TAC[LOG_MONO_LT; ARITH_RULE `&1 < x ==> &0 < x`; REAL_LT_01]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Deduce periodicity just from derivative and zero values.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let SIN_NEARZERO = prove
+ (`?x. &0 < x /\ !y. &0 < y /\ y <= x ==> &0 < sin(y)`,
+  MP_TAC(SPEC `&1 / &2` (CONJUNCT2
+   (REWRITE_RULE[has_complex_derivative; HAS_DERIVATIVE_AT_ALT]
+    (ISPEC `Cx(&0)` HAS_COMPLEX_DERIVATIVE_CSIN)))) THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[CSIN_0; COMPLEX_SUB_RZERO; CCOS_0; COMPLEX_MUL_LZERO;
+              COMPLEX_MUL_LID] 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` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `Cx y`) THEN
+  ASM_REWRITE_TAC[GSYM CX_SIN; COMPLEX_NORM_CX; GSYM CX_SUB] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let SIN_NONTRIVIAL = prove
+ (`?x. &0 < x /\ ~(sin x = &0)`,
+  MESON_TAC[REAL_LE_REFL; REAL_LT_REFL; SIN_NEARZERO]);;
+
+let COS_NONTRIVIAL = prove
+ (`?x. &0 < x /\ ~(cos x = &1)`,
+  MP_TAC SIN_NONTRIVIAL THEN MATCH_MP_TAC MONO_EXISTS THEN
+  MP_TAC SIN_CIRCLE THEN MATCH_MP_TAC MONO_FORALL THEN
+  CONV_TAC REAL_FIELD);;
+
+let COS_DOUBLE_BOUND = prove
+ (`!x. &0 <= cos x ==> &2 * (&1 - cos x) <= &1 - cos(&2 * x)`,
+  REWRITE_TAC[COS_DOUBLE_COS] THEN REWRITE_TAC[REAL_ARITH
+   `&2 * (&1 - a) <= &1 - (&2 * b - &1) <=> b <= &1 * a`] THEN
+  SIMP_TAC[REAL_POW_2; REAL_LE_RMUL; COS_BOUNDS]);;
+
+let COS_GOESNEGATIVE_LEMMA = prove
+ (`!x. cos(x) < &1 ==> ?n. cos(&2 pow n * x) < &0`,
+  GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC(TAUT `(~p ==> p) ==> p`) THEN
+  REWRITE_TAC[NOT_EXISTS_THM; REAL_NOT_LT] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `!n.  &2  pow n * (&1 - cos x) <= &1 - cos(&2 pow n * x)`
+  ASSUME_TAC THENL
+   [INDUCT_TAC THEN REWRITE_TAC[real_pow; REAL_MUL_LID; REAL_LE_REFL] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `&2 * (&1 - cos(&2 pow n * x))` THEN
+    ASM_SIMP_TAC[GSYM REAL_MUL_ASSOC; REAL_LE_LMUL; REAL_POS; COS_DOUBLE_BOUND];
+    MP_TAC(ISPEC `&1 / (&1 - cos(x))` REAL_ARCH_POW2) THEN
+    ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_SUB_LT] THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:num` MP_TAC) THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `n:num`)) THEN REAL_ARITH_TAC]);;
+
+let COS_GOESNEGATIVE = prove
+ (`?x. &0 < x /\ cos(x) < &0`,
+  X_CHOOSE_TAC `x:real` COS_NONTRIVIAL THEN
+  MP_TAC(SPEC `x:real` COS_GOESNEGATIVE_LEMMA) THEN ANTS_TAC THENL
+   [MP_TAC(SPEC `x:real` COS_BOUNDS) THEN
+    ASM_REAL_ARITH_TAC;
+    ASM_MESON_TAC[REAL_LT_MUL; REAL_POW_LT; REAL_ARITH `&0 < &2`]]);;
+
+let COS_HASZERO = prove
+ (`?x. &0 < x /\ cos(x) = &0`,
+  X_CHOOSE_THEN `z:real` STRIP_ASSUME_TAC COS_GOESNEGATIVE THEN
+  SUBGOAL_THEN `?x. &0 <= x /\ x <= z /\ Re(ccos(Cx x)) = &0` MP_TAC THENL
+   [MATCH_MP_TAC IVT_DECREASING_RE THEN
+    ASM_SIMP_TAC[GSYM CX_COS; RE_CX; REAL_LT_IMP_LE; COS_0; REAL_POS] THEN
+    MESON_TAC[HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT;
+              HAS_COMPLEX_DERIVATIVE_CCOS];
+    MATCH_MP_TAC MONO_EXISTS THEN REWRITE_TAC[GSYM CX_COS; RE_CX] THEN
+    MESON_TAC[COS_0; REAL_LE_LT; REAL_ARITH `~(&1 = &0)`]]);;
+
+let SIN_HASZERO = prove
+ (`?x. &0 < x /\ sin(x) = &0`,
+  X_CHOOSE_THEN `x:real` STRIP_ASSUME_TAC COS_HASZERO THEN
+  EXISTS_TAC `&2 * x` THEN ASM_SIMP_TAC[SIN_DOUBLE] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let SIN_HASZERO_MINIMAL = prove
+ (`?p. &0 < p /\ sin p = &0 /\ !x. &0 < x /\ x < p ==> ~(sin x = &0)`,
+  X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC SIN_NEARZERO THEN
+  MP_TAC(ISPECL
+    [`{z | z IN IMAGE Cx {x | x >= e} /\ csin z IN {Cx(&0)}}`; `Cx(&0)`]
+    DISTANCE_ATTAINS_INF) THEN
+  ANTS_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[IN_ELIM_THM; GSYM CONJ_ASSOC; IMP_CONJ] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE; EXISTS_IN_IMAGE] THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_SING; real_ge; GSYM CX_COS; CX_INJ] THEN
+    REWRITE_TAC[dist; GSYM CX_SUB; GSYM CX_SIN; CX_INJ; COMPLEX_NORM_CX] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN
+    REWRITE_TAC[REAL_ARITH `abs(&0 - x) = abs x`] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+     [ALL_TAC;
+      X_GEN_TAC `x:real` THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `x:real`))] THEN
+    ASM_REAL_ARITH_TAC] THEN
+  X_CHOOSE_TAC `a:real` SIN_HASZERO THEN CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN EXISTS_TAC `Cx a` THEN
+    ASM_REWRITE_TAC[IN_SING; IN_IMAGE; IN_ELIM_THM; GSYM CX_SIN] THEN
+    ASM_MESON_TAC[REAL_ARITH `x >= w \/ x <= w`; REAL_LT_REFL]] THEN
+  MATCH_MP_TAC CONTINUOUS_CLOSED_PREIMAGE THEN
+  REWRITE_TAC[CONTINUOUS_ON_CSIN; CLOSED_SING] THEN
+  SUBGOAL_THEN
+   `IMAGE Cx {x | x >= e} = {z | Im(z) = &0} INTER {z | Re(z) >= e}`
+   (fun th -> SIMP_TAC[th; CLOSED_INTER; CLOSED_HALFSPACE_IM_EQ;
+                           CLOSED_HALFSPACE_RE_GE]) THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_INTER; IN_ELIM_THM] THEN
+  REWRITE_TAC[FORALL_COMPLEX; COMPLEX_EQ; RE; IM; RE_CX; IM_CX] THEN
+  MESON_TAC[]);;
+
+let pi = new_definition
+ `pi = @p. &0 < p /\ sin(p) = &0 /\ !x. &0 < x /\ x < p ==> ~(sin(x) = &0)`;;
+
+let PI_WORKS = prove
+ (`&0 < pi /\ sin(pi) = &0 /\ !x. &0 < x /\ x < pi ==> ~(sin x = &0)`,
+  REWRITE_TAC[pi] THEN CONV_TAC SELECT_CONV THEN
+  REWRITE_TAC[SIN_HASZERO_MINIMAL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Now more relatively easy consequences.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let PI_POS = prove
+ (`&0 < pi`,
+  REWRITE_TAC[PI_WORKS]);;
+
+let PI_POS_LE = prove
+ (`&0 <= pi`,
+  REWRITE_TAC[REAL_LE_LT; PI_POS]);;
+
+let PI_NZ = prove
+ (`~(pi = &0)`,
+  SIMP_TAC[PI_POS; REAL_LT_IMP_NZ]);;
+
+let REAL_ABS_PI = prove
+ (`abs pi = pi`,
+  REWRITE_TAC[real_abs; PI_POS_LE]);;
+
+let SIN_PI = prove
+ (`sin(pi) = &0`,
+  REWRITE_TAC[PI_WORKS]);;
+
+let SIN_POS_PI = prove
+ (`!x. &0 < x /\ x < pi ==> &0 < sin(x)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_NOT_LE] THEN DISCH_TAC THEN
+  X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC SIN_NEARZERO THEN
+  MP_TAC(ISPECL [`csin`; `e:real`; `x:real`; `&0`] IVT_DECREASING_RE) THEN
+  ASM_SIMP_TAC[NOT_IMP; CONTINUOUS_AT_CSIN; GSYM CX_SIN; RE_CX; SIN_0] THEN
+  ASM_MESON_TAC[REAL_LE_TOTAL; REAL_LET_ANTISYM; PI_WORKS; REAL_LET_TRANS;
+                REAL_LTE_TRANS]);;
+
+let COS_PI2 = prove
+ (`cos(pi / &2) = &0`,
+  MP_TAC(SYM(SPEC `pi / &2` SIN_DOUBLE)) THEN
+  REWRITE_TAC[REAL_HALF; SIN_PI; REAL_ENTIRE; REAL_OF_NUM_EQ; ARITH] THEN
+  MATCH_MP_TAC(REAL_ARITH `&0 < y ==> y = &0 \/ z = &0 ==> z = &0`) THEN
+  MATCH_MP_TAC SIN_POS_PI THEN MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+let COS_PI = prove
+ (`cos(pi) = -- &1`,
+  ONCE_REWRITE_TAC[REAL_ARITH `pi = &2 * pi / &2`] THEN
+  REWRITE_TAC[COS_DOUBLE_COS; COS_PI2] THEN REAL_ARITH_TAC);;
+
+let SIN_PI2 = prove
+ (`sin(pi / &2) = &1`,
+  MP_TAC(SPEC `pi / &2` SIN_CIRCLE) THEN
+  REWRITE_TAC[COS_PI2; REAL_POW_2; REAL_ADD_RID; REAL_MUL_LZERO] THEN
+  REWRITE_TAC[REAL_RING `x * x = &1 <=> x = &1 \/ x = -- &1`] THEN
+  MP_TAC(SPEC `pi / &2` SIN_POS_PI) THEN MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+let SIN_COS = prove
+ (`!x. sin(x) = cos(pi / &2 - x)`,
+  REWRITE_TAC[COS_SUB; COS_PI2; SIN_PI2] THEN REAL_ARITH_TAC);;
+
+let COS_SIN = prove
+ (`!x. cos(x) = sin(pi / &2 - x)`,
+  REWRITE_TAC[SIN_SUB; COS_PI2; SIN_PI2] THEN REAL_ARITH_TAC);;
+
+let SIN_PERIODIC_PI = prove
+ (`!x. sin(x + pi) = --(sin(x))`,
+  REWRITE_TAC[SIN_ADD; SIN_PI; COS_PI] THEN REAL_ARITH_TAC);;
+
+let COS_PERIODIC_PI = prove
+ (`!x. cos(x + pi) = --(cos(x))`,
+  REWRITE_TAC[COS_ADD; SIN_PI; COS_PI] THEN REAL_ARITH_TAC);;
+
+let SIN_PERIODIC = prove
+ (`!x. sin(x + &2 * pi) = sin(x)`,
+  REWRITE_TAC[REAL_MUL_2; REAL_ADD_ASSOC; SIN_PERIODIC_PI; REAL_NEG_NEG]);;
+
+let COS_PERIODIC = prove
+ (`!x. cos(x + &2 * pi) = cos(x)`,
+  REWRITE_TAC[REAL_MUL_2; REAL_ADD_ASSOC; COS_PERIODIC_PI; REAL_NEG_NEG]);;
+
+let SIN_NPI = prove
+ (`!n. sin(&n * pi) = &0`,
+  INDUCT_TAC THEN
+  ASM_REWRITE_TAC[GSYM REAL_OF_NUM_SUC; REAL_MUL_LID; REAL_ADD_RDISTRIB;
+                  REAL_NEG_0; SIN_PERIODIC_PI; REAL_MUL_LZERO; SIN_0]);;
+
+let COS_NPI = prove
+ (`!n. cos(&n * pi) = --(&1) pow n`,
+  INDUCT_TAC THEN
+  ASM_REWRITE_TAC[real_pow; REAL_MUL_LZERO; COS_0; COS_PERIODIC_PI;
+    REAL_MUL_LID; REAL_MUL_LNEG; GSYM REAL_OF_NUM_SUC; REAL_ADD_RDISTRIB]);;
+
+let COS_POS_PI2 = prove
+ (`!x. &0 < x /\ x < pi / &2 ==> &0 < cos(x)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_NOT_LE] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`ccos`; `&0`; `x:real`; `&0`] IVT_DECREASING_RE) THEN
+  ASM_SIMP_TAC[CONTINUOUS_AT_CCOS; REAL_LT_IMP_LE; GSYM CX_COS; RE_CX] THEN
+  REWRITE_TAC[COS_0; REAL_POS] THEN DISCH_THEN(X_CHOOSE_TAC `y:real`) THEN
+  MP_TAC(SPEC `y:real` SIN_DOUBLE) THEN ASM_REWRITE_TAC[REAL_MUL_RZERO] THEN
+  MATCH_MP_TAC(last(CONJUNCTS PI_WORKS)) THEN REPEAT(POP_ASSUM MP_TAC) THEN
+  ASM_CASES_TAC `y = &0` THEN ASM_REWRITE_TAC[COS_0] THEN
+  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC);;
+
+let SIN_POS_PI2 = prove
+ (`!x. &0 < x /\ x < pi / &2 ==> &0 < sin(x)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SIN_POS_PI THEN
+  ASM_REAL_ARITH_TAC);;
+
+let COS_POS_PI = prove
+ (`!x. --(pi / &2) < x /\ x < pi / &2 ==> &0 < cos(x)`,
+  GEN_TAC THEN MP_TAC(SPEC `abs x` COS_POS_PI2) THEN REWRITE_TAC[COS_ABS] THEN
+  ASM_CASES_TAC `x = &0` THEN ASM_REWRITE_TAC[COS_0] THEN
+  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC);;
+
+let COS_POS_PI_LE = prove
+ (`!x. --(pi / &2) <= x /\ x <= pi / &2 ==> &0 <= cos(x)`,
+  REWRITE_TAC[REAL_LE_LT] THEN MESON_TAC[COS_PI2; COS_NEG; COS_POS_PI]);;
+
+let SIN_POS_PI_LE = prove
+ (`!x. &0 <= x /\ x <= pi ==> &0 <= sin(x)`,
+  REWRITE_TAC[REAL_LE_LT] THEN MESON_TAC[SIN_0; SIN_PI; SIN_POS_PI]);;
+
+let SIN_PIMUL_EQ_0 = prove
+ (`!n. sin(n * pi) = &0 <=> integer(n)`,
+  SUBGOAL_THEN `!n. integer n ==> sin(n * pi) = &0 /\ ~(cos(n * pi) = &0)`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[INTEGER_CASES] THEN GEN_TAC THEN STRIP_TAC THEN CONJ_TAC THEN
+    ASM_SIMP_TAC[REAL_MUL_LNEG; COS_NPI; SIN_NPI;
+                 SIN_NEG; COS_NEG; REAL_POW_EQ_0] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  GEN_TAC THEN EQ_TAC THEN ASM_SIMP_TAC[] THEN
+  SUBST1_TAC(last(CONJUNCTS(SPEC `n:real` FLOOR_FRAC))) THEN
+  ASM_SIMP_TAC[REAL_ADD_RDISTRIB; FLOOR; SIN_ADD; REAL_MUL_LZERO] THEN
+  ASM_SIMP_TAC[REAL_ADD_LID; REAL_ENTIRE; FLOOR] THEN
+  DISCH_TAC THEN MP_TAC(SPEC `frac n * pi` SIN_POS_PI) THEN
+  ASM_SIMP_TAC[REAL_LT_REFL; GSYM REAL_LT_RDIV_EQ; GSYM REAL_LT_LDIV_EQ;
+               PI_POS; REAL_DIV_REFL; REAL_LT_IMP_NZ] THEN
+  MP_TAC(SPEC `n:real` FLOOR_FRAC) THEN ASM_CASES_TAC `frac n = &0` THEN
+  ASM_REWRITE_TAC[FLOOR; REAL_ADD_RID] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let SIN_EQ_0 = prove
+ (`!x. sin(x) = &0 <=> ?n. integer n /\ x = n * pi`,
+  GEN_TAC THEN MP_TAC(SPEC `x / pi` SIN_PIMUL_EQ_0) THEN
+  SIMP_TAC[REAL_DIV_RMUL; REAL_LT_IMP_NZ; GSYM REAL_EQ_LDIV_EQ; PI_POS] THEN
+  ONCE_REWRITE_TAC[CONJ_SYM] THEN REWRITE_TAC[UNWIND_THM1]);;
+
+let COS_EQ_0 = prove
+ (`!x. cos(x) = &0 <=> ?n. integer n /\ x = (n + &1 / &2) * pi`,
+  GEN_TAC THEN REWRITE_TAC[COS_SIN; SIN_EQ_0] THEN
+  EQ_TAC THEN DISCH_THEN(X_CHOOSE_THEN `n:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `--n:real` THEN ASM_REWRITE_TAC[INTEGER_NEG] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let SIN_ZERO_PI = prove
+ (`!x. sin(x) = &0 <=> (?n. x = &n * pi) \/ (?n. x = --(&n * pi))`,
+  REWRITE_TAC[SIN_EQ_0; INTEGER_CASES] THEN MESON_TAC[REAL_MUL_LNEG]);;
+
+let COS_ZERO_PI = prove
+ (`!x. cos(x) = &0 <=>
+       (?n. x = (&n + &1 / &2) * pi) \/ (?n. x = --((&n + &1 / &2) * pi))`,
+  GEN_TAC THEN REWRITE_TAC[COS_EQ_0; INTEGER_CASES; RIGHT_OR_DISTRIB] THEN
+  REWRITE_TAC[EXISTS_OR_THM; LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN SIMP_TAC[UNWIND_THM2] THEN EQ_TAC THEN
+  DISCH_THEN(DISJ_CASES_THEN (X_CHOOSE_THEN `n:num` SUBST1_TAC)) THENL
+   [DISJ1_TAC THEN EXISTS_TAC `n:num`;
+    ASM_CASES_TAC `n = 0` THENL
+     [DISJ1_TAC THEN EXISTS_TAC `0`;
+      DISJ2_TAC THEN EXISTS_TAC `n - 1`];
+    DISJ1_TAC THEN EXISTS_TAC `n:num`;
+    DISJ2_TAC THEN EXISTS_TAC `n + 1`] THEN
+  ASM_SIMP_TAC[GSYM REAL_OF_NUM_SUB; GSYM REAL_OF_NUM_ADD;
+               ARITH_RULE `1 <= n <=> ~(n = 0)`] THEN
+  REAL_ARITH_TAC);;
+
+let SIN_ZERO = prove
+ (`!x. (sin(x) = &0) <=> (?n. EVEN n /\ x = &n * (pi / &2)) \/
+                         (?n. EVEN n /\ x = --(&n * (pi / &2)))`,
+  REWRITE_TAC[SIN_ZERO_PI; EVEN_EXISTS; LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN REWRITE_TAC[UNWIND_THM2] THEN
+  SIMP_TAC[GSYM REAL_OF_NUM_MUL; REAL_ARITH `(&2 * x) * y / &2 = x * y`]);;
+
+let COS_ZERO = prove
+ (`!x. cos(x) = &0 <=> (?n. ~EVEN n /\ (x = &n * (pi / &2))) \/
+                       (?n. ~EVEN n /\ (x = --(&n * (pi / &2))))`,
+  REWRITE_TAC[COS_ZERO_PI; NOT_EVEN; ODD_EXISTS; LEFT_AND_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN REWRITE_TAC[UNWIND_THM2] THEN
+  SIMP_TAC[GSYM REAL_OF_NUM_MUL; GSYM REAL_OF_NUM_SUC;
+           REAL_ARITH `(&2 * x + &1) * y / &2 = (x + &1 / &2) * y`]);;
+
+let COS_ONE_2PI = prove
+ (`!x. (cos(x) = &1) <=> (?n. x = &n * &2 * pi) \/ (?n. x = --(&n * &2 * pi))`,
+  GEN_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+   [FIRST_ASSUM(MP_TAC o SPEC `sin(x)` o MATCH_MP (REAL_RING
+     `c = &1 ==> !s. s pow 2 + c pow 2 = &1 ==> s = &0`)) THEN
+    REWRITE_TAC[SIN_ZERO_PI; SIN_CIRCLE] THEN
+    DISCH_THEN(DISJ_CASES_THEN(X_CHOOSE_THEN `n:num` SUBST_ALL_TAC)) THEN
+    POP_ASSUM MP_TAC THEN REWRITE_TAC[COS_NEG; COS_NPI; REAL_POW_NEG] THEN
+    COND_CASES_TAC THEN REWRITE_TAC[REAL_POW_ONE] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    FIRST_X_ASSUM(MP_TAC o REWRITE_RULE[EVEN_EXISTS]) THEN
+    REWRITE_TAC[OR_EXISTS_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    SIMP_TAC[GSYM REAL_OF_NUM_MUL] THEN REAL_ARITH_TAC;
+    FIRST_X_ASSUM (DISJ_CASES_THEN CHOOSE_TAC) THEN
+    ASM_REWRITE_TAC[COS_NEG; REAL_MUL_ASSOC; REAL_OF_NUM_MUL; COS_NPI;
+                    REAL_POW_NEG; EVEN_MULT; ARITH; REAL_POW_ONE]]);;
+
+let SIN_COS_SQRT = prove
+ (`!x. &0 <= sin(x) ==> (sin(x) = sqrt(&1 - (cos(x) pow 2)))`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC SQRT_UNIQUE THEN
+  ASM_REWRITE_TAC[SIN_CIRCLE; REAL_EQ_SUB_LADD]);;
+
+let SIN_EQ_0_PI = prove
+ (`!x. --pi < x /\ x < pi /\ sin(x) = &0 ==> x = &0`,
+  GEN_TAC THEN REWRITE_TAC[SIN_EQ_0; CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC
+   (X_CHOOSE_THEN `n:real` STRIP_ASSUME_TAC)) THEN
+  ASM_REWRITE_TAC[REAL_ARITH
+   `--p < n * p /\ n * p < p <=> -- &1 * p < n * p /\ n * p < &1 * p`] THEN
+  SIMP_TAC[REAL_ENTIRE; REAL_LT_IMP_NZ; REAL_LT_RMUL_EQ; PI_POS] THEN
+  MP_TAC(SPEC `n:real` REAL_ABS_INTEGER_LEMMA) THEN
+  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let COS_TREBLE_COS = prove
+ (`!x. cos(&3 * x) = &4 * cos(x) pow 3 - &3 * cos x`,
+  GEN_TAC THEN REWRITE_TAC[COS_ADD; REAL_ARITH `&3 * x = &2 * x + x`] THEN
+  REWRITE_TAC[SIN_DOUBLE; COS_DOUBLE_COS] THEN
+  MP_TAC(SPEC `x:real` SIN_CIRCLE) THEN CONV_TAC REAL_RING);;
+
+let COS_PI6 = prove
+ (`cos(pi / &6) = sqrt(&3) / &2`,
+  MP_TAC(ISPEC `pi / &6` COS_TREBLE_COS) THEN
+  REWRITE_TAC[REAL_ARITH `&3 * x / &6 = x / &2`; COS_PI2] THEN
+  REWRITE_TAC[REAL_RING `&0 = &4 * c pow 3 - &3 * c <=>
+                         c = &0 \/ (&2 * c) pow 2 = &3`] THEN
+  SUBGOAL_THEN `&0 < cos(pi / &6)` ASSUME_TAC THENL
+   [MATCH_MP_TAC COS_POS_PI THEN MP_TAC PI_POS THEN REAL_ARITH_TAC;
+    DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL
+     [ASM_MESON_TAC[REAL_LT_REFL]; ALL_TAC] THEN
+    DISCH_THEN(MP_TAC o AP_TERM `sqrt`) THEN
+    ASM_SIMP_TAC[POW_2_SQRT; REAL_LE_MUL; REAL_LT_IMP_LE; REAL_POS] THEN
+    REAL_ARITH_TAC]);;
+
+let SIN_PI6 = prove
+ (`sin(pi / &6) = &1 / &2`,
+  MP_TAC(SPEC `pi / &6` SIN_CIRCLE) THEN REWRITE_TAC[COS_PI6] THEN
+  SIMP_TAC[REAL_POW_DIV; SQRT_POW_2; REAL_POS] THEN MATCH_MP_TAC(REAL_FIELD
+   `~(s + &1 / &2 = &0) ==> s pow 2 + &3 / &2 pow 2 = &1 ==> s = &1 / &2`) THEN
+  MATCH_MP_TAC(REAL_ARITH `&0 < x ==> ~(x + &1 / &2 = &0)`) THEN
+  MATCH_MP_TAC SIN_POS_PI THEN MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+let SIN_POS_PI_REV = prove
+ (`!x. &0 <= x /\ x <= &2 * pi /\ &0 < sin x ==> &0 < x /\ x < pi`,
+  GEN_TAC THEN ASM_CASES_TAC `x = &0` THEN
+  ASM_REWRITE_TAC[SIN_0; REAL_LT_REFL] THEN
+  ASM_CASES_TAC `x = pi` THEN
+  ASM_REWRITE_TAC[SIN_PI; REAL_LT_REFL] THEN
+  ASM_CASES_TAC `x = &2 * pi` THEN
+  ASM_REWRITE_TAC[SIN_NPI; REAL_LT_REFL] THEN
+  REPEAT STRIP_TAC THENL [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[GSYM REAL_NOT_LE] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `&0 < sin(&2 * pi - x)` MP_TAC THENL
+   [MATCH_MP_TAC SIN_POS_PI THEN ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[SIN_SUB; SIN_NPI; COS_NPI] THEN ASM_REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Prove totality of trigs.                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let SIN_TOTAL_POS = prove
+ (`!y. &0 <= y /\ y <= &1
+       ==> ?x. &0 <= x /\ x <= pi / &2 /\ sin(x) = y`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`csin`; `&0`; `pi / &2`; `y:real`] IVT_INCREASING_RE) THEN
+  ASM_REWRITE_TAC[GSYM CX_SIN; RE_CX; SIN_0; SIN_PI2] THEN
+  SIMP_TAC[CONTINUOUS_AT_CSIN; PI_POS; REAL_ARITH `&0 < x ==> &0 <= x / &2`]);;
+
+let SINCOS_TOTAL_PI2 = prove
+ (`!x y. &0 <= x /\ &0 <= y /\ x pow 2 + y pow 2 = &1
+         ==> ?t. &0 <= t /\ t <= pi / &2 /\ x = cos t /\ y = sin t`,
+  REPEAT STRIP_TAC THEN MP_TAC(SPEC `y:real` SIN_TOTAL_POS) THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
+     `x pow 2 + y pow 2 = &1
+      ==> (&1 < y ==> &1 pow 2 < y pow 2) /\ &0 <= x * x
+          ==> y <= &1`)) THEN
+    SIMP_TAC[REAL_LE_SQUARE; REAL_POW_LT2; REAL_POS; ARITH];
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `t:real` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `x = cos t \/ x = --(cos t)` MP_TAC THENL
+     [MP_TAC(SPEC `t:real` SIN_CIRCLE);
+      MP_TAC(SPEC `t:real` COS_POS_PI_LE)] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC REAL_FIELD]);;
+
+let SINCOS_TOTAL_PI = prove
+ (`!x y. &0 <= y /\ x pow 2 + y pow 2 = &1
+         ==> ?t. &0 <= t /\ t <= pi /\ x = cos t /\ y = sin t`,
+  REPEAT STRIP_TAC THEN DISJ_CASES_TAC(REAL_ARITH `&0 <= x \/ &0 <= --x`) THENL
+   [MP_TAC(SPECL [`x:real`; `y:real`] SINCOS_TOTAL_PI2);
+    MP_TAC(SPECL [`--x:real`; `y:real`] SINCOS_TOTAL_PI2)] THEN
+  ASM_REWRITE_TAC[REAL_POW_NEG; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THENL
+   [EXISTS_TAC `t:real`; EXISTS_TAC `pi - t`] THEN
+  ASM_REWRITE_TAC[SIN_SUB; COS_SUB; SIN_PI; COS_PI] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let SINCOS_TOTAL_2PI = prove
+ (`!x y. x pow 2 + y pow 2 = &1
+         ==> ?t. &0 <= t /\ t < &2 * pi /\ x = cos t /\ y = sin t`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `x = &1 /\ y = &0` THENL
+   [EXISTS_TAC `&0` THEN ASM_REWRITE_TAC[SIN_0; COS_0] THEN
+    MP_TAC PI_POS THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISJ_CASES_TAC(REAL_ARITH `&0 <= y \/ &0 <= --y`) THENL
+   [MP_TAC(SPECL [`x:real`; `y:real`] SINCOS_TOTAL_PI);
+    MP_TAC(SPECL [`x:real`; `--y:real`] SINCOS_TOTAL_PI)] THEN
+  ASM_REWRITE_TAC[REAL_POW_NEG; ARITH] THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THENL
+   [EXISTS_TAC `t:real`; EXISTS_TAC `&2 * pi - t`] THEN
+  ASM_REWRITE_TAC[SIN_SUB; COS_SUB; SIN_NPI; COS_NPI] THENL
+   [MP_TAC PI_POS THEN ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN ASM_CASES_TAC `t = &0` THEN
+  ASM_REWRITE_TAC[SIN_0; COS_0] THEN POP_ASSUM MP_TAC THEN REAL_ARITH_TAC);;
+
+let CIRCLE_SINCOS = prove
+ (`!x y. x pow 2 + y pow 2 = &1 ==> ?t. x = cos(t) /\ y = sin(t)`,
+  MESON_TAC[SINCOS_TOTAL_2PI]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Polar representation.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let CX_PI_NZ = prove
+ (`~(Cx pi = Cx(&0))`,
+  SIMP_TAC[CX_INJ; REAL_LT_IMP_NZ; PI_POS]);;
+
+let COMPLEX_UNIMODULAR_POLAR = prove
+ (`!z. (norm z = &1) ==> ?x. z = complex(cos(x),sin(x))`,
+  GEN_TAC THEN
+  DISCH_THEN(MP_TAC o C AP_THM `2` o AP_TERM `(pow):real->num->real`) THEN
+  REWRITE_TAC[complex_norm] THEN
+  SIMP_TAC[REAL_POW_2; REWRITE_RULE[REAL_POW_2] SQRT_POW_2;
+           REAL_LE_SQUARE; REAL_LE_ADD] THEN
+  REWRITE_TAC[GSYM REAL_POW_2; REAL_MUL_LID] THEN
+  DISCH_THEN(X_CHOOSE_TAC `t:real` o MATCH_MP CIRCLE_SINCOS) THEN
+  EXISTS_TAC `t:real` THEN ASM_REWRITE_TAC[COMPLEX_EQ; RE; IM]);;
+
+let SIN_INTEGER_2PI = prove
+ (`!n. integer n ==> sin((&2 * pi) * n) = &0`,
+  REWRITE_TAC[SIN_EQ_0; REAL_ARITH `(&2 * pi) * n = (&2 * n) * pi`] THEN
+  MESON_TAC[INTEGER_CLOSED]);;
+
+let SIN_INTEGER_PI = prove
+ (`!n. integer n ==> sin (n * pi) = &0`,
+  REWRITE_TAC[INTEGER_CASES] THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[REAL_MUL_LNEG; SIN_NPI; SIN_NEG; REAL_NEG_0]);;
+
+let COS_INTEGER_2PI = prove
+ (`!n. integer n ==> cos((&2 * pi) * n) = &1`,
+  REWRITE_TAC[INTEGER_CASES; REAL_ARITH `(&2 * pi) * n = (&2 * n) * pi`] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[REAL_MUL_RNEG; REAL_OF_NUM_MUL] THEN
+  SIMP_TAC[COS_NEG; COS_NPI; REAL_POW_NEG; REAL_MUL_LNEG;
+           ARITH; EVEN_MULT; REAL_POW_ONE]);;
+
+let SINCOS_PRINCIPAL_VALUE = prove
+ (`!x. ?y. (--pi < y /\ y <= pi) /\ (sin(y) = sin(x) /\ cos(y) = cos(x))`,
+  GEN_TAC THEN EXISTS_TAC `pi - (&2 * pi) * frac((pi - x) / (&2 * pi))` THEN
+  CONJ_TAC THENL
+   [SIMP_TAC[REAL_ARITH `--p < p - x <=> x < (&2 * p) * &1`;
+             REAL_ARITH `p - x <= p <=> (&2 * p) * &0 <= x`;
+             REAL_LT_LMUL_EQ; REAL_LE_LMUL_EQ; REAL_LT_MUL;
+             PI_POS; REAL_OF_NUM_LT; ARITH; FLOOR_FRAC];
+   REWRITE_TAC[FRAC_FLOOR; REAL_SUB_LDISTRIB] THEN
+   SIMP_TAC[REAL_DIV_LMUL; REAL_ENTIRE; REAL_OF_NUM_EQ; ARITH; REAL_LT_IMP_NZ;
+    PI_POS; REAL_ARITH `a - (a - b - c):real = b + c`; SIN_ADD; COS_ADD] THEN
+   SIMP_TAC[FLOOR_FRAC; SIN_INTEGER_2PI; COS_INTEGER_2PI] THEN
+   CONV_TAC REAL_RING]);;
+
+let CEXP_COMPLEX = prove
+ (`!r t. cexp(complex(r,t)) = Cx(exp r) * complex(cos t,sin t)`,
+  REPEAT GEN_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [COMPLEX_EXPAND] THEN
+  REWRITE_TAC[RE; IM; CEXP_ADD; CEXP_EULER; CX_EXP] THEN
+  REWRITE_TAC[COMPLEX_TRAD; CX_SIN; CX_COS]);;
+
+let NORM_COSSIN = prove
+ (`!t. norm(complex(cos t,sin t)) = &1`,
+  REWRITE_TAC[complex_norm; RE; IM] THEN ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
+  REWRITE_TAC[SIN_CIRCLE; SQRT_1]);;
+
+let NORM_CEXP = prove
+ (`!z. norm(cexp z) = exp(Re z)`,
+  REWRITE_TAC[FORALL_COMPLEX; CEXP_COMPLEX; COMPLEX_NORM_MUL] THEN
+  REWRITE_TAC[NORM_COSSIN; RE; COMPLEX_NORM_CX] THEN
+  MP_TAC REAL_EXP_POS_LT THEN MATCH_MP_TAC MONO_FORALL THEN REAL_ARITH_TAC);;
+
+let NORM_CEXP_II = prove
+ (`!t. norm (cexp (ii * Cx t)) = &1`,
+  REWRITE_TAC [NORM_CEXP; RE_MUL_II; IM_CX; REAL_NEG_0; REAL_EXP_0]);;
+
+let NORM_CEXP_IMAGINARY = prove
+ (`!z. norm(cexp z) = &1 ==> Re(z) = &0`,
+  REWRITE_TAC[NORM_CEXP; REAL_EXP_EQ_1]);;
+
+let CEXP_EQ_1 = prove
+ (`!z. cexp z = Cx(&1) <=> Re(z) = &0 /\ ?n. integer n /\ Im(z) = &2 * n * pi`,
+  REWRITE_TAC[FORALL_COMPLEX; CEXP_COMPLEX; RE; IM] THEN
+  MAP_EVERY X_GEN_TAC [`x:real`; `y:real`] THEN EQ_TAC THENL
+   [DISCH_TAC THEN FIRST_ASSUM(MP_TAC o AP_TERM `norm:complex->real`) THEN
+    SIMP_TAC[COMPLEX_NORM_MUL; CX_EXP; NORM_CEXP; RE_CX; COMPLEX_NORM_CX] THEN
+    REWRITE_TAC[NORM_COSSIN; REAL_ABS_NUM; REAL_ABS_EXP; REAL_MUL_RID] THEN
+    REWRITE_TAC[REAL_EXP_EQ_1] THEN DISCH_THEN SUBST_ALL_TAC THEN
+    POP_ASSUM MP_TAC THEN REWRITE_TAC[REAL_EXP_0; COMPLEX_MUL_LID] THEN
+    REWRITE_TAC[COMPLEX_EQ; RE; IM; RE_CX; IM_CX] THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [SIN_EQ_0]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `m:real`
+     (CONJUNCTS_THEN2 ASSUME_TAC SUBST_ALL_TAC)) THEN
+    EXISTS_TAC `m / &2` THEN CONJ_TAC THENL [ALL_TAC; REAL_ARITH_TAC] THEN
+    ONCE_REWRITE_TAC[GSYM INTEGER_ABS] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE LAND_CONV [GSYM COS_ABS]) THEN
+    REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_DIV; REAL_ABS_NUM] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [integer]) THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:num` SUBST_ALL_TAC) THEN
+    SIMP_TAC[real_abs; PI_POS; REAL_LT_IMP_LE; COS_NPI] THEN
+    REWRITE_TAC[REAL_POW_NEG; REAL_POW_ONE] THEN
+    COND_CASES_TAC THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    FIRST_X_ASSUM(CHOOSE_THEN SUBST1_TAC o REWRITE_RULE[EVEN_EXISTS]) THEN
+    REWRITE_TAC[GSYM REAL_OF_NUM_MUL; REAL_ARITH `(&2 * x) / &2 = x`] THEN
+    REWRITE_TAC[INTEGER_CLOSED];
+    DISCH_THEN(CONJUNCTS_THEN2 SUBST1_TAC (X_CHOOSE_TAC `n:real`)) THEN
+    ASM_SIMP_TAC[REAL_EXP_0; COMPLEX_MUL_LID] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `&2 * x * y = (&2 * y) * x`] THEN
+    ASM_SIMP_TAC[SIN_INTEGER_2PI; COS_INTEGER_2PI] THEN
+    SIMPLE_COMPLEX_ARITH_TAC]);;
+
+let CEXP_EQ = prove
+ (`!w z. cexp w = cexp z <=> ?n. integer n /\ w = z + Cx(&2 * n * pi) * ii`,
+  SIMP_TAC[CEXP_NZ; COMPLEX_FIELD
+   `~(z = Cx(&0)) ==> (w = z <=> w / z = Cx(&1))`] THEN
+  REWRITE_TAC[GSYM CEXP_SUB; CEXP_EQ_1; RE_SUB; IM_SUB; REAL_SUB_0] THEN
+  SIMP_TAC[COMPLEX_EQ; RE_ADD; IM_ADD; RE_MUL_II; IM_MUL_II; RE_CX; IM_CX] THEN
+  REWRITE_TAC[REAL_NEG_0; REAL_ADD_RID; REAL_EQ_SUB_RADD] THEN
+  MESON_TAC[REAL_ADD_SYM]);;
+
+let COMPLEX_EQ_CEXP = prove
+ (`!w z. abs(Im w - Im z) < &2 * pi /\ cexp w = cexp z ==> w = z`,
+  SIMP_TAC[CEXP_NZ; GSYM CEXP_SUB; CEXP_EQ_1; COMPLEX_FIELD
+   `~(a = Cx(&0)) /\ ~(b = Cx(&0)) ==> (a = b <=> a / b = Cx(&1))`] THEN
+  REPEAT GEN_TAC THEN DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_X_ASSUM(X_CHOOSE_THEN `n:real` STRIP_ASSUME_TAC) THEN
+  UNDISCH_TAC `abs(Im w - Im z) < &2 * pi` THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN
+  ASM_REWRITE_TAC[GSYM IM_SUB; REAL_ABS_MUL; REAL_ABS_PI; REAL_ABS_NUM] THEN
+  SIMP_TAC[REAL_MUL_ASSOC; REAL_LT_RMUL_EQ; PI_POS] THEN
+  MATCH_MP_TAC(REAL_ARITH `&1 <= x ==> ~(&2 * x < &2)`) THEN
+  MATCH_MP_TAC REAL_ABS_INTEGER_LEMMA THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN SUBST_ALL_TAC THEN UNDISCH_TAC `~(w:complex = z)` THEN
+  REWRITE_TAC[] THEN ONCE_REWRITE_TAC[GSYM COMPLEX_SUB_0] THEN
+  ASM_REWRITE_TAC[COMPLEX_EQ; RE_CX; IM_CX; REAL_MUL_LZERO; REAL_MUL_RZERO]);;
+
+let CEXP_INTEGER_2PI = prove
+ (`!n. integer n ==> cexp(Cx(&2 * n * pi) * ii) = Cx(&1)`,
+  REWRITE_TAC[CEXP_EQ_1; IM_MUL_II; RE_MUL_II; RE_CX; IM_CX] THEN
+  REWRITE_TAC[REAL_NEG_0] THEN MESON_TAC[]);;
+
+let SIN_COS_EQ = prove
+ (`!x y. sin y = sin x /\ cos y = cos x <=>
+         ?n. integer n /\ y = x + &2 * n * pi`,
+  REPEAT GEN_TAC THEN MP_TAC(ISPECL [`ii * Cx y`; `ii * Cx x`] CEXP_EQ) THEN
+  REWRITE_TAC[CEXP_EULER; GSYM CX_SIN; GSYM CX_COS] THEN
+  REWRITE_TAC[COMPLEX_RING `ii * y = ii * x + z * ii <=> y = x + z`] THEN
+  REWRITE_TAC[GSYM CX_ADD; CX_INJ] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[COMPLEX_EQ; RE_ADD; IM_ADD; RE_MUL_II; IM_MUL_II; RE_CX; IM_CX;
+              REAL_NEG_0; REAL_ADD_LID; REAL_ADD_RID] THEN
+  MESON_TAC[]);;
+
+let SIN_COS_INJ = prove
+ (`!x y. sin x = sin y /\ cos x = cos y /\ abs(x - y) < &2 * pi ==> x = y`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM CX_INJ] THEN
+  MATCH_MP_TAC(COMPLEX_RING `ii * x = ii * y ==> x = y`) THEN
+  MATCH_MP_TAC COMPLEX_EQ_CEXP THEN
+  ASM_REWRITE_TAC[CEXP_EULER; GSYM CX_SIN; GSYM CX_COS] THEN
+  ASM_REWRITE_TAC[IM_MUL_II; RE_CX]);;
+
+let CEXP_II_NE_1 = prove
+ (`!x. &0 < x /\ x < &2 * pi ==> ~(cexp(ii * Cx x) = Cx(&1))`,
+  GEN_TAC THEN STRIP_TAC THEN REWRITE_TAC[CEXP_EQ_1] THEN
+  REWRITE_TAC[RE_MUL_II; IM_CX; IM_MUL_II; IM_CX; REAL_NEG_0; RE_CX] THEN
+  DISCH_THEN(X_CHOOSE_THEN `n:real`
+   (CONJUNCTS_THEN2 ASSUME_TAC SUBST_ALL_TAC)) THEN
+  UNDISCH_TAC `&0 < &2 * n * pi` THEN ASM_CASES_TAC `n = &0` THEN
+  ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_RZERO; REAL_LT_REFL] THEN
+  MP_TAC(ISPEC `n:real` REAL_ABS_INTEGER_LEMMA) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o MATCH_MP (REAL_ARITH
+   `&2 * n * pi < &2 * pi ==> &0 < (&1 - n) * &2 * pi`)) THEN
+  ASM_SIMP_TAC[REAL_LT_MUL_EQ; PI_POS; REAL_LT_MUL; REAL_OF_NUM_LT; ARITH] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let CSIN_EQ_0 = prove
+ (`!z. csin z = Cx(&0) <=> ?n. integer n /\ z = Cx(n * pi)`,
+  GEN_TAC THEN REWRITE_TAC[csin; COMPLEX_MUL_LNEG; CEXP_NEG] THEN
+  SIMP_TAC[CEXP_NZ; COMPLEX_FIELD `~(z = Cx(&0))
+        ==> ((z - inv z) / (Cx(&2) * ii) = Cx(&0) <=> z pow 2 = Cx(&1))`] THEN
+  REWRITE_TAC[GSYM CEXP_N; CEXP_EQ_1] THEN
+  REWRITE_TAC[RE_MUL_CX; IM_MUL_CX; RE_MUL_II; IM_MUL_II] THEN
+  REWRITE_TAC[COMPLEX_EQ; IM_CX; RE_CX; RIGHT_AND_EXISTS_THM] THEN
+  EQ_TAC THEN MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN REAL_ARITH_TAC);;
+
+let CCOS_EQ_0 = prove
+ (`!z. ccos z = Cx(&0) <=> ?n. integer n /\ z = Cx((n + &1 / &2) * pi)`,
+  GEN_TAC THEN MP_TAC(SPEC `z - Cx(pi / &2)` CSIN_EQ_0) THEN
+  REWRITE_TAC[CSIN_SUB; GSYM CX_SIN; GSYM CX_COS; SIN_PI2; COS_PI2] THEN
+  SIMP_TAC[COMPLEX_RING `s * Cx(&0) - c * Cx(&1) = Cx(&0) <=> c = Cx(&0)`] THEN
+  REWRITE_TAC[REAL_ADD_RDISTRIB; COMPLEX_EQ_SUB_RADD; CX_ADD] THEN
+  REWRITE_TAC[REAL_ARITH `&1 / &2 * x = x / &2`]);;
+
+let CCOS_EQ_1 = prove
+ (`!z. ccos z = Cx(&1) <=> ?n. integer n /\ z = Cx(&2 * n * pi)`,
+  GEN_TAC THEN GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o RAND_CONV)
+   [COMPLEX_RING `z = Cx(&2) * z / Cx(&2)`] THEN
+  REWRITE_TAC[CCOS_DOUBLE_CSIN; COMPLEX_RING
+   `a - Cx(&2) * s pow 2 = a <=> s = Cx(&0)`] THEN
+  REWRITE_TAC[CSIN_EQ_0; CX_MUL] THEN
+  EQ_TAC THEN MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let CSIN_EQ_1 = prove
+ (`!z. csin z = Cx(&1) <=> ?n. integer n /\ z = Cx((&2 * n + &1 / &2) * pi)`,
+  GEN_TAC THEN MP_TAC(SPEC `z - Cx(pi / &2)` CCOS_EQ_1) THEN
+  REWRITE_TAC[CCOS_SUB; GSYM CX_SIN; GSYM CX_COS; SIN_PI2; COS_PI2] THEN
+  SIMP_TAC[COMPLEX_RING `s * Cx(&0) + c * Cx(&1) = Cx(&1) <=> c = Cx(&1)`] THEN
+  REWRITE_TAC[REAL_ADD_RDISTRIB; COMPLEX_EQ_SUB_RADD; CX_ADD] THEN
+  REWRITE_TAC[REAL_MUL_ASSOC; REAL_ARITH `&1 / &2 * x = x / &2`]);;
+
+let CSIN_EQ_MINUS1 = prove
+ (`!z. csin z = --Cx(&1) <=>
+       ?n. integer n /\ z = Cx((&2 * n + &3 / &2) * pi)`,
+  GEN_TAC THEN REWRITE_TAC[COMPLEX_RING `z:complex = --w <=> --z = w`] THEN
+  REWRITE_TAC[GSYM CSIN_NEG; CSIN_EQ_1] THEN
+  REWRITE_TAC[COMPLEX_RING `--z:complex = w <=> z = --w`] THEN
+  EQ_TAC THEN DISCH_THEN(X_CHOOSE_THEN `n:real` STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[GSYM CX_NEG; CX_INJ] THEN
+  EXISTS_TAC `--(n + &1)` THEN
+  ASM_SIMP_TAC[INTEGER_CLOSED] THEN REAL_ARITH_TAC);;
+
+let CCOS_EQ_MINUS1 = prove
+ (`!z. ccos z = --Cx(&1) <=>
+       ?n. integer n /\ z = Cx((&2 * n + &1) * pi)`,
+  GEN_TAC THEN MP_TAC(SPEC `z - Cx(pi / &2)` CSIN_EQ_1) THEN
+  REWRITE_TAC[CSIN_SUB; GSYM CX_SIN; GSYM CX_COS; SIN_PI2; COS_PI2] THEN
+  SIMP_TAC[COMPLEX_RING
+    `s * Cx(&0) - c * Cx(&1) = Cx(&1) <=> c = --Cx(&1)`] THEN
+  REWRITE_TAC[REAL_ADD_RDISTRIB; COMPLEX_EQ_SUB_RADD; GSYM CX_ADD] THEN
+  DISCH_TAC THEN EQ_TAC THEN MATCH_MP_TAC MONO_EXISTS THEN
+  SIMP_TAC[CX_INJ] THEN REAL_ARITH_TAC);;
+
+let COS_EQ_1 = prove
+ (`!x. cos x = &1 <=> ?n. integer n /\ x = &2 * n * pi`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CCOS_EQ_1]);;
+
+let SIN_EQ_1 = prove
+ (`!x. sin x = &1 <=> ?n. integer n /\ x = (&2 * n + &1 / &2) * pi`,
+  REWRITE_TAC[GSYM CX_INJ; CX_SIN; CSIN_EQ_1]);;
+
+let SIN_EQ_MINUS1 = prove
+ (`!x. sin x = --(&1) <=> ?n. integer n /\ x = (&2 * n + &3 / &2) * pi`,
+  REWRITE_TAC[GSYM CX_INJ; CX_NEG; CX_SIN; CSIN_EQ_MINUS1]);;
+
+let COS_EQ_MINUS1 = prove
+ (`!x. cos x = --(&1) <=>
+       ?n. integer n /\ x = (&2 * n + &1) * pi`,
+  REWRITE_TAC[GSYM CX_INJ; CX_NEG; CX_COS; CCOS_EQ_MINUS1]);;
+
+let DIST_CEXP_II_1 = prove
+ (`!z. norm(cexp(ii * Cx t) - Cx(&1)) = &2 * abs(sin(t / &2))`,
+  GEN_TAC THEN REWRITE_TAC[NORM_EQ_SQUARE] THEN
+  CONJ_TAC THENL [REAL_ARITH_TAC; REWRITE_TAC[GSYM NORM_POW_2]] THEN
+  REWRITE_TAC[CEXP_EULER; COMPLEX_SQNORM; GSYM CX_COS; GSYM CX_SIN] THEN
+  REWRITE_TAC[IM_ADD; RE_ADD; IM_SUB; RE_SUB; IM_MUL_II; RE_MUL_II] THEN
+  REWRITE_TAC[RE_CX; IM_CX; REAL_POW2_ABS; REAL_POW_MUL] THEN
+  MP_TAC(ISPEC `t / &2` COS_DOUBLE_SIN) THEN
+  REWRITE_TAC[REAL_ARITH `&2 * t / &2 = t`] THEN
+  MP_TAC(SPEC `t:real` SIN_CIRCLE) THEN CONV_TAC REAL_RING);;
+
+let CX_SINH = prove
+ (`Cx((exp x - inv(exp x)) / &2) = --ii * csin(ii * Cx x)`,
+  REWRITE_TAC[csin; COMPLEX_RING `--ii * ii * z = z /\ ii * ii * z = --z`] THEN
+  REWRITE_TAC[CEXP_NEG; GSYM CX_EXP; GSYM CX_INV; CX_SUB; CX_DIV] THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CX_COSH = prove
+ (`Cx((exp x + inv(exp x)) / &2) = ccos(ii * Cx x)`,
+  REWRITE_TAC[ccos; COMPLEX_RING `--ii * ii * z = z /\ ii * ii * z = --z`] THEN
+  REWRITE_TAC[CEXP_NEG; GSYM CX_EXP; GSYM CX_INV; CX_ADD; CX_DIV] THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let NORM_CCOS_POW_2 = prove
+ (`!z. norm(ccos z) pow 2 =
+       cos(Re z) pow 2 + (exp(Im z) - inv(exp(Im z))) pow 2 / &4`,
+  REWRITE_TAC[FORALL_COMPLEX; RE; IM] THEN
+  REWRITE_TAC[COMPLEX_TRAD; CCOS_ADD; COMPLEX_SQNORM] THEN
+  SIMP_TAC[RE_SUB; IM_SUB; GSYM CX_COS; GSYM CX_SIN; IM_MUL_CX; RE_MUL_CX] THEN
+  REWRITE_TAC[ccos; csin; CEXP_NEG; COMPLEX_FIELD
+   `--ii * ii * z = z /\ ii * ii * z = --z /\
+    z / (Cx(&2) * ii) = --(ii * z / Cx(&2))`] THEN
+  REWRITE_TAC[RE_ADD; RE_SUB; IM_ADD; IM_SUB; RE_MUL_II; IM_MUL_II;
+              RE_DIV_CX; IM_DIV_CX; RE_NEG; IM_NEG] THEN
+  REWRITE_TAC[GSYM CX_EXP; GSYM CX_INV; IM_CX; RE_CX] THEN
+  MAP_EVERY X_GEN_TAC [`x:real`; `y:real`] THEN
+  MP_TAC(SPEC `x:real` SIN_CIRCLE) THEN MP_TAC(SPEC `y:real` REAL_EXP_NZ) THEN
+  CONV_TAC REAL_FIELD);;
+
+let NORM_CSIN_POW_2 = prove
+ (`!z. norm(csin z) pow 2 =
+       (exp(&2 * Im z) + inv(exp(&2 * Im z)) - &2 * cos(&2 * Re z)) / &4`,
+  REWRITE_TAC[FORALL_COMPLEX; RE; IM] THEN
+  REWRITE_TAC[COMPLEX_TRAD; CSIN_ADD; COMPLEX_SQNORM] THEN
+  SIMP_TAC[RE_ADD; IM_ADD; GSYM CX_SIN; GSYM CX_SIN; IM_MUL_CX; RE_MUL_CX;
+           GSYM CX_COS] THEN
+  REWRITE_TAC[ccos; csin; CEXP_NEG; COMPLEX_FIELD
+   `--ii * ii * z = z /\ ii * ii * z = --z /\
+    z / (Cx(&2) * ii) = --(ii * z / Cx(&2))`] THEN
+  REWRITE_TAC[RE_ADD; RE_SUB; IM_ADD; IM_SUB; RE_MUL_II; IM_MUL_II;
+              RE_DIV_CX; IM_DIV_CX; RE_NEG; IM_NEG] THEN
+  REWRITE_TAC[GSYM CX_EXP; GSYM CX_INV; IM_CX; RE_CX] THEN
+  REWRITE_TAC[REAL_EXP_N; COS_DOUBLE] THEN
+  MAP_EVERY X_GEN_TAC [`x:real`; `y:real`] THEN
+  MP_TAC(SPEC `x:real` SIN_CIRCLE) THEN MP_TAC(SPEC `y:real` REAL_EXP_NZ) THEN
+  CONV_TAC REAL_FIELD);;
+
+let CSIN_EQ = prove
+ (`!w z. csin w = csin z <=>
+         ?n. integer n /\
+             (w = z + Cx(&2 * n * pi) \/ w = --z + Cx((&2 * n + &1) * pi))`,
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM COMPLEX_SUB_0] THEN
+  REWRITE_TAC[COMPLEX_SUB_CSIN; COMPLEX_ENTIRE; CSIN_EQ_0; CCOS_EQ_0] THEN
+  REWRITE_TAC[CX_INJ; REAL_OF_NUM_EQ; ARITH_EQ; OR_EXISTS_THM] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `n:real` THEN
+  ASM_CASES_TAC `integer(n)` THEN
+  ASM_REWRITE_TAC[COMPLEX_FIELD `a / Cx(&2) = b <=> a = Cx(&2) * b`] THEN
+  REWRITE_TAC[GSYM CX_MUL; REAL_ARITH
+    `&2 * (n + &1 / &2) * pi = (&2 * n + &1) * pi`] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let CCOS_EQ = prove
+ (`!w z. ccos(w) = ccos(z) <=>
+         ?n. integer n /\
+             (w = z + Cx(&2 * n * pi) \/ w = --z + Cx(&2 * n * pi))`,
+  REPEAT GEN_TAC THEN CONV_TAC(LAND_CONV SYM_CONV) THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM COMPLEX_SUB_0] THEN
+  REWRITE_TAC[COMPLEX_SUB_CCOS; COMPLEX_ENTIRE; CSIN_EQ_0] THEN
+  REWRITE_TAC[CX_INJ; REAL_OF_NUM_EQ; ARITH_EQ; OR_EXISTS_THM] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `n:real` THEN
+  ASM_CASES_TAC `integer(n)` THEN ASM_REWRITE_TAC[CX_MUL] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let SIN_EQ = prove
+ (`!x y. sin x = sin y <=>
+         ?n. integer n /\
+             (x = y + &2 * n * pi \/ x = --y + (&2 * n + &1) * pi)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_SIN; CSIN_EQ] THEN
+  REWRITE_TAC[GSYM CX_ADD; GSYM CX_NEG; CX_INJ]);;
+
+let COS_EQ = prove
+ (`!x y. cos x = cos y <=>
+         ?n. integer n /\
+             (x = y + &2 * n * pi \/ x = --y + &2 * n * pi)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_COS; CCOS_EQ] THEN
+  REWRITE_TAC[GSYM CX_ADD; GSYM CX_NEG; CX_INJ]);;
+
+let NORM_CCOS_LE = prove
+ (`!z. norm(ccos z) <= exp(norm z)`,
+  GEN_TAC THEN REWRITE_TAC[ccos] THEN
+  REWRITE_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_CX; REAL_ABS_NUM] THEN
+  REWRITE_TAC[REAL_ARITH `x / &2 <= y <=> x <= &2 * y`] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `norm(a) + norm(b) <= d ==> norm(a + b) <= d`) THEN
+  REWRITE_TAC[NORM_CEXP; COMPLEX_MUL_LNEG; RE_NEG; REAL_EXP_NEG] THEN
+  REWRITE_TAC[COMPLEX_NORM_CX; RE_MUL_II; REAL_ABS_NUM] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `exp(&0) = &1 /\ (exp(&0) <= w \/ exp(&0) <= z) /\ (w <= u /\ z <= u)
+    ==> w + z <= &2 * u`) THEN
+  REWRITE_TAC[GSYM REAL_EXP_NEG; REAL_EXP_MONO_LE] THEN
+  REWRITE_TAC[REAL_EXP_0] THEN
+  MP_TAC(SPEC `z:complex` COMPLEX_NORM_GE_RE_IM) THEN
+  REAL_ARITH_TAC);;
+
+let NORM_CCOS_PLUS1_LE = prove
+ (`!z. norm(Cx(&1) + ccos z) <= &2 * exp(norm z)`,
+  GEN_TAC THEN REWRITE_TAC[ccos] THEN
+  REWRITE_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_CX; REAL_ABS_NUM; COMPLEX_RING
+   `Cx(&1) + (z + z') / Cx(&2) = (Cx(&2) + z + z') / Cx(&2)`] THEN
+  REWRITE_TAC[REAL_ARITH `x / &2 <= &2 * y <=> x <= &4 * y`] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `norm(a) + norm(b) + norm(c) <= d ==> norm(a + b + c) <= d`) THEN
+  REWRITE_TAC[NORM_CEXP; COMPLEX_MUL_LNEG; RE_NEG; REAL_EXP_NEG] THEN
+  REWRITE_TAC[COMPLEX_NORM_CX; RE_MUL_II; REAL_ABS_NUM] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `exp(&0) = &1 /\ (exp(&0) <= w \/ exp(&0) <= z) /\ (w <= u /\ z <= u)
+    ==> &2 + w + z <= &4 * u`) THEN
+  REWRITE_TAC[GSYM REAL_EXP_NEG; REAL_EXP_MONO_LE] THEN
+  REWRITE_TAC[REAL_EXP_0] THEN
+  MP_TAC(SPEC `z:complex` COMPLEX_NORM_GE_RE_IM) THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Taylor series for complex exponential.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let TAYLOR_CEXP = prove
+ (`!n z. norm(cexp z - vsum(0..n) (\k. z pow k / Cx(&(FACT k))))
+         <= exp(abs(Re z)) * (norm z) pow (n + 1) / &(FACT n)`,
+  REPEAT GEN_TAC THEN MP_TAC(ISPECL
+   [`\k:num. cexp`; `n:num`; `segment[Cx(&0),z]`; `exp(abs(Re z))`]
+        COMPLEX_TAYLOR) THEN
+  REWRITE_TAC[CONVEX_SEGMENT; NORM_CEXP; REAL_EXP_MONO_LE] THEN ANTS_TAC THENL
+   [REWRITE_TAC[IN_SEGMENT] THEN REPEAT STRIP_TAC THENL
+     [GEN_REWRITE_TAC(RATOR_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+      COMPLEX_DIFF_TAC THEN REWRITE_TAC[COMPLEX_MUL_LID];
+      ASM_REWRITE_TAC[GSYM COMPLEX_VEC_0; VECTOR_MUL_RZERO] THEN
+      REWRITE_TAC[VECTOR_ADD_LID; COMPLEX_CMUL; COMPLEX_NORM_MUL] THEN
+      GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
+      MATCH_MP_TAC(REAL_ARITH `abs x <= a ==> x <= a`) THEN
+      REWRITE_TAC[RE_MUL_CX; REAL_ABS_MUL] THEN MATCH_MP_TAC REAL_LE_RMUL THEN
+      ASM_REAL_ARITH_TAC];
+    DISCH_THEN(MP_TAC o SPECL [`Cx(&0)`; `z:complex`]) THEN
+    SIMP_TAC[ENDS_IN_SEGMENT; COMPLEX_SUB_RZERO; CEXP_0; COMPLEX_MUL_LID]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Approximation to e.                                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let E_APPROX_32 = prove
+ (`abs(exp(&1) - &11674931555 / &4294967296) <= inv(&2 pow 32)`,
+  let lemma = prove
+   (`abs(e - x) <= e * d
+     ==> &0 <= d /\ d < &1
+         ==> abs(e - x) <= x * d / (&1 - d)`,
+    DISCH_THEN(fun th -> STRIP_TAC THEN ASSUME_TAC th THEN MP_TAC th) THEN
+    MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] REAL_LE_TRANS) THEN
+    ASM_SIMP_TAC[REAL_ARITH `e * d <= x * d / i <=> d * e <= d * x / i`] THEN
+    MATCH_MP_TAC REAL_LE_LMUL THEN ASM_REWRITE_TAC[] THEN
+   ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_SUB_LT] THEN ASM_REAL_ARITH_TAC) in
+  MP_TAC(ISPECL [`14`; `Cx(&1)`] TAYLOR_CEXP) THEN
+  SIMP_TAC[GSYM CX_EXP; RE_CX; COMPLEX_NORM_CX; REAL_ABS_NUM;
+           REAL_POW_ONE; GSYM CX_DIV; GSYM CX_POW] THEN
+  CONV_TAC(ONCE_DEPTH_CONV EXPAND_VSUM_CONV) THEN
+  REWRITE_TAC[GSYM CX_ADD; GSYM CX_SUB; COMPLEX_NORM_CX] THEN
+  CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  DISCH_THEN(MP_TAC o MATCH_MP lemma) THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Taylor series for complex sine and cosine.                                *)
+(* ------------------------------------------------------------------------- *)
+
+let TAYLOR_CSIN_RAW = prove
+ (`!n z. norm(csin z -
+              vsum(0..n) (\k. if ODD k
+                              then --ii * (ii * z) pow k / Cx(&(FACT k))
+                              else Cx(&0)))
+         <= exp(abs(Im z)) * (norm z) pow (n + 1) / &(FACT n)`,
+  MP_TAC TAYLOR_CEXP THEN MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `n:num` THEN
+  DISCH_TAC THEN X_GEN_TAC `z:complex` THEN REWRITE_TAC[csin] THEN
+  REWRITE_TAC[COMPLEX_FIELD
+    `a / (Cx(&2) * ii) - b = (a - Cx(&2) * ii * b) / (Cx(&2) * ii)`] THEN
+  FIRST_ASSUM(fun th ->
+    MP_TAC(SPEC `ii * z` th) THEN MP_TAC(SPEC `--ii * z` th)) THEN
+  REWRITE_TAC[COMPLEX_MUL_LNEG; RE_NEG; REAL_ABS_NEG; RE_MUL_II] THEN
+  REWRITE_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_MUL; COMPLEX_NORM_CX; NORM_NEG;
+              COMPLEX_NORM_II; REAL_ABS_NUM; REAL_MUL_RID; REAL_MUL_LID;
+              REAL_ARITH `x / &2 <= y <=> x <= &2 * y`] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `sp - sn = s2
+    ==> norm(en - sn) <= d
+        ==> norm(ep - sp) <= d ==> norm(ep - en - s2) <= &2 * d`) THEN
+  SIMP_TAC[GSYM VSUM_SUB; GSYM VSUM_COMPLEX_LMUL; FINITE_NUMSEG] THEN
+  MATCH_MP_TAC VSUM_EQ THEN X_GEN_TAC `k:num` THEN DISCH_TAC THEN
+  REWRITE_TAC[COMPLEX_POW_NEG; GSYM NOT_EVEN] THEN ASM_CASES_TAC `EVEN k` THEN
+  ASM_REWRITE_TAC[COMPLEX_SUB_REFL; COMPLEX_MUL_RZERO] THEN
+  REWRITE_TAC[COMPLEX_RING `Cx(&2) * ii * --(ii * z) = Cx(&2) * z`] THEN
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let TAYLOR_CSIN = prove
+ (`!n z. norm(csin z -
+              vsum(0..n) (\k. --Cx(&1) pow k *
+                              z pow (2 * k + 1) / Cx(&(FACT(2 * k + 1)))))
+         <= exp(abs(Im z)) * norm(z) pow (2 * n + 3) / &(FACT(2 * n + 2))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`SUC(2 * n + 1)`; `z:complex`] TAYLOR_CSIN_RAW) THEN
+  SIMP_TAC[VSUM_CLAUSES_NUMSEG; VSUM_PAIR_0; ODD_ADD; ODD_MULT; ARITH_ODD;
+           LE_0; ODD; COMPLEX_ADD_LID; COMPLEX_ADD_RID] THEN
+  SIMP_TAC[ARITH_RULE `SUC(2 * n + 1) = 2 * n + 2`; GSYM ADD_ASSOC; ARITH] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `s = t ==> norm(x - s) <= e ==> norm(x - t) <= e`) THEN
+  MATCH_MP_TAC VSUM_EQ THEN X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+  REWRITE_TAC[COMPLEX_POW_MUL; complex_div; COMPLEX_MUL_ASSOC] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[COMPLEX_POW_ADD; GSYM COMPLEX_POW_POW] THEN
+  REWRITE_TAC[COMPLEX_POW_II_2] THEN CONV_TAC COMPLEX_RING);;
+
+let TAYLOR_CCOS_RAW = prove
+ (`!n z. norm(ccos z -
+              vsum(0..n) (\k. if EVEN k
+                              then (ii * z) pow k / Cx(&(FACT k))
+                              else Cx(&0)))
+         <= exp(abs(Im z)) * (norm z) pow (n + 1) / &(FACT n)`,
+  MP_TAC TAYLOR_CEXP THEN MATCH_MP_TAC MONO_FORALL THEN X_GEN_TAC `n:num` THEN
+  DISCH_TAC THEN X_GEN_TAC `z:complex` THEN REWRITE_TAC[ccos] THEN
+  REWRITE_TAC[COMPLEX_FIELD
+    `a / Cx(&2) - b = (a - Cx(&2) * b) / Cx(&2)`] THEN
+  FIRST_ASSUM(fun th ->
+    MP_TAC(SPEC `ii * z` th) THEN MP_TAC(SPEC `--ii * z` th)) THEN
+  REWRITE_TAC[COMPLEX_MUL_LNEG; RE_NEG; REAL_ABS_NEG; RE_MUL_II] THEN
+  REWRITE_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_MUL; COMPLEX_NORM_CX; NORM_NEG;
+              COMPLEX_NORM_II; REAL_ABS_NUM; REAL_MUL_RID; REAL_MUL_LID;
+              REAL_ARITH `x / &2 <= y <=> x <= &2 * y`] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `sp + sn = s2
+    ==> norm(en - sn) <= d
+        ==> norm(ep - sp) <= d ==> norm((ep + en) - s2) <= &2 * d`) THEN
+  SIMP_TAC[GSYM VSUM_ADD; GSYM VSUM_COMPLEX_LMUL; FINITE_NUMSEG] THEN
+  MATCH_MP_TAC VSUM_EQ THEN X_GEN_TAC `k:num` THEN DISCH_TAC THEN
+  REWRITE_TAC[COMPLEX_POW_NEG; GSYM NOT_EVEN] THEN ASM_CASES_TAC `EVEN k` THEN
+  ASM_REWRITE_TAC[COMPLEX_ADD_RINV; COMPLEX_MUL_RZERO] THEN
+  SIMPLE_COMPLEX_ARITH_TAC);;
+
+let TAYLOR_CCOS = prove
+ (`!n z. norm(ccos z -
+              vsum(0..n) (\k. --Cx(&1) pow k *
+                              z pow (2 * k) / Cx(&(FACT(2 * k)))))
+         <= exp(abs(Im z)) * norm(z) pow (2 * n + 2) / &(FACT(2 * n + 1))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`2 * n + 1`; `z:complex`] TAYLOR_CCOS_RAW) THEN
+  SIMP_TAC[VSUM_PAIR_0; EVEN_ADD; EVEN_MULT; ARITH_EVEN;
+           LE_0; EVEN; COMPLEX_ADD_LID; COMPLEX_ADD_RID] THEN
+  SIMP_TAC[ARITH_RULE `(2 * n + 1) + 1 = 2 * n + 2`] THEN
+  MATCH_MP_TAC(NORM_ARITH
+   `s = t ==> norm(x - s) <= e ==> norm(x - t) <= e`) THEN
+  MATCH_MP_TAC VSUM_EQ THEN X_GEN_TAC `k:num` THEN STRIP_TAC THEN
+  REWRITE_TAC[COMPLEX_POW_MUL; complex_div; COMPLEX_MUL_ASSOC] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[GSYM COMPLEX_POW_POW; COMPLEX_POW_II_2]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The argument of a complex number, where 0 <= arg(z) < 2 pi                *)
+(* ------------------------------------------------------------------------- *)
+
+let Arg_DEF = new_definition
+ `Arg z = if z = Cx(&0) then &0
+          else @t. &0 <= t /\ t < &2 * pi /\
+                   z = Cx(norm(z)) * cexp(ii * Cx t)`;;
+
+let ARG_0 = prove
+ (`Arg(Cx(&0)) = &0`,
+  REWRITE_TAC[Arg_DEF]);;
+
+let ARG = prove
+ (`!z. &0 <= Arg(z) /\ Arg(z) < &2 * pi /\
+       z = Cx(norm z) * cexp(ii * Cx(Arg z))`,
+  GEN_TAC THEN REWRITE_TAC[Arg_DEF] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[COMPLEX_NORM_0; COMPLEX_MUL_LZERO] THEN
+  SIMP_TAC[REAL_LE_REFL; REAL_LT_MUL; PI_POS; REAL_ARITH `&0 < &2`] THEN
+  CONV_TAC SELECT_CONV THEN
+  MP_TAC(SPECL [`Re(z) / norm z`; `Im(z) / norm z`]
+        SINCOS_TOTAL_2PI) THEN
+  ASM_SIMP_TAC[COMPLEX_SQNORM; COMPLEX_NORM_ZERO; REAL_FIELD
+    `~(z = &0) /\ x pow 2 + y pow 2 = z pow 2
+      ==> (x / z) pow 2 + (y / z) pow 2 = &1`] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN
+  ASM_SIMP_TAC[COMPLEX_NORM_ZERO; REAL_FIELD
+   `~(z = &0) ==> (x / z = y <=> x = z * y)`] THEN
+  REWRITE_TAC[COMPLEX_EQ; RE_MUL_CX; IM_MUL_CX; CEXP_EULER; RE_ADD; IM_ADD;
+        RE_MUL_II; IM_MUL_II; GSYM CX_SIN; GSYM CX_COS; RE_CX; IM_CX] THEN
+  REAL_ARITH_TAC);;
+
+let COMPLEX_NORM_EQ_1_CEXP = prove
+ (`!z. norm z = &1 <=> (?t. z = cexp(ii * Cx t))`,
+  GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN
+  ASM_REWRITE_TAC [NORM_CEXP; RE_MUL_II; IM_CX; REAL_NEG_0; REAL_EXP_0] THEN
+  MP_TAC (SPEC `z:complex` ARG) THEN ASM_REWRITE_TAC [COMPLEX_MUL_LID] THEN
+  MESON_TAC[]);;
+
+let ARG_UNIQUE = prove
+ (`!a r z. &0 < r /\ Cx r * cexp(ii * Cx a) = z /\ &0 <= a /\ a < &2 * pi
+           ==> Arg z = a`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM CX_INJ] THEN
+  MATCH_MP_TAC(COMPLEX_RING `ii * x = ii * y ==> x = y`) THEN
+  MATCH_MP_TAC COMPLEX_EQ_CEXP THEN CONJ_TAC THENL
+   [REWRITE_TAC[IM_MUL_II; RE_CX] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= x /\ x < p /\ &0 <= y /\ y < p
+                             ==> abs(x - y) < p`) THEN
+    ASM_SIMP_TAC[ARG];
+    MATCH_MP_TAC(COMPLEX_RING
+     `!a b. Cx a = Cx b /\ ~(Cx b = Cx(&0)) /\
+            Cx a * w = Cx b * z ==> w = z`) THEN
+    MAP_EVERY EXISTS_TAC [`norm(z:complex)`; `r:real`] THEN
+    ASM_REWRITE_TAC[GSYM ARG] THEN ASM_SIMP_TAC[CX_INJ; REAL_LT_IMP_NZ] THEN
+    EXPAND_TAC "z" THEN
+    REWRITE_TAC[NORM_CEXP_II; COMPLEX_NORM_MUL; COMPLEX_NORM_CX] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let ARG_MUL_CX = prove
+ (`!r z. &0 < r ==> Arg(Cx r * z) = Arg(z)`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `z = Cx(&0)` THEN ASM_REWRITE_TAC[COMPLEX_MUL_RZERO] THEN
+  MATCH_MP_TAC ARG_UNIQUE THEN EXISTS_TAC `r * norm(z:complex)` THEN
+  ASM_REWRITE_TAC[CX_MUL; GSYM COMPLEX_MUL_ASSOC; GSYM ARG] THEN
+  ASM_SIMP_TAC[REAL_LT_MUL; COMPLEX_NORM_NZ]);;
+
+let ARG_DIV_CX = prove
+ (`!r z. &0 < r ==> Arg(z / Cx r) = Arg(z)`,
+  REWRITE_TAC[ONCE_REWRITE_RULE[COMPLEX_MUL_SYM] complex_div] THEN
+  SIMP_TAC[GSYM CX_INV; ARG_MUL_CX; REAL_LT_INV_EQ]);;
+
+let ARG_LT_NZ = prove
+ (`!z. &0 < Arg z <=> ~(Arg z = &0)`,
+  MP_TAC ARG THEN MATCH_MP_TAC MONO_FORALL THEN REAL_ARITH_TAC);;
+
+let ARG_LE_PI = prove
+ (`!z. Arg z <= pi <=> &0 <= Im z`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THENL
+   [ASM_REWRITE_TAC[Arg_DEF; IM_CX; REAL_LE_REFL; PI_POS_LE]; ALL_TAC] THEN
+  GEN_REWRITE_TAC (funpow 3 RAND_CONV) [ARG] THEN
+  ASM_SIMP_TAC[IM_MUL_CX; CEXP_EULER; REAL_LE_MUL_EQ; COMPLEX_NORM_NZ] THEN
+  REWRITE_TAC[IM_ADD; GSYM CX_SIN; GSYM CX_COS; IM_CX; IM_MUL_II; RE_CX] THEN
+  REWRITE_TAC[REAL_ADD_LID] THEN EQ_TAC THEN SIMP_TAC[ARG; SIN_POS_PI_LE] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `&0 < sin(&2 * pi - Arg z)` MP_TAC THENL
+   [MATCH_MP_TAC SIN_POS_PI THEN MP_TAC(SPEC `z:complex` ARG) THEN
+    ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[SIN_SUB; SIN_NPI; COS_NPI] THEN REAL_ARITH_TAC]);;
+
+let ARG_LT_PI = prove
+ (`!z. &0 < Arg z /\ Arg z < pi <=> &0 < Im z`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THENL
+   [ASM_REWRITE_TAC[Arg_DEF; IM_CX; REAL_LT_REFL; PI_POS_LE]; ALL_TAC] THEN
+  GEN_REWRITE_TAC (funpow 3 RAND_CONV) [ARG] THEN
+  ASM_SIMP_TAC[IM_MUL_CX; CEXP_EULER; REAL_LT_MUL_EQ; COMPLEX_NORM_NZ] THEN
+  REWRITE_TAC[IM_ADD; GSYM CX_SIN; GSYM CX_COS; IM_CX; IM_MUL_II; RE_CX] THEN
+  REWRITE_TAC[REAL_ADD_LID] THEN EQ_TAC THEN SIMP_TAC[SIN_POS_PI] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  ASM_CASES_TAC `Arg z = &0` THEN
+  ASM_REWRITE_TAC[SIN_0; REAL_LT_REFL] THEN
+  ASM_SIMP_TAC[ARG; REAL_ARITH `~(x = &0) ==> (&0 < x <=> &0 <= x)`] THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN `&0 <= sin(&2 * pi - Arg z)` MP_TAC THENL
+   [MATCH_MP_TAC SIN_POS_PI_LE THEN MP_TAC(SPEC `z:complex` ARG) THEN
+    ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[SIN_SUB; SIN_NPI; COS_NPI] THEN REAL_ARITH_TAC]);;
+
+let ARG_EQ_0 = prove
+ (`!z. Arg z = &0 <=> real z /\ &0 <= Re z`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THENL
+   [ASM_REWRITE_TAC[REAL_CX; RE_CX; Arg_DEF; REAL_LE_REFL]; ALL_TAC] THEN
+  CONV_TAC(RAND_CONV(SUBS_CONV[last(CONJUNCTS(SPEC `z:complex` ARG))])) THEN
+  ASM_SIMP_TAC[RE_MUL_CX; REAL_MUL_CX; REAL_LE_MUL_EQ; COMPLEX_NORM_NZ] THEN
+  ASM_REWRITE_TAC[COMPLEX_NORM_ZERO; CEXP_EULER] THEN
+  REWRITE_TAC[real; RE_ADD; IM_ADD; RE_MUL_II; IM_MUL_II;
+              GSYM CX_SIN; GSYM CX_COS; RE_CX; IM_CX] THEN
+  REWRITE_TAC[REAL_ADD_RID; REAL_ADD_LID; REAL_NEG_0] THEN
+  EQ_TAC THEN SIMP_TAC[SIN_0; COS_0; REAL_POS] THEN
+  ASM_CASES_TAC `Arg z = pi` THENL
+   [ASM_REWRITE_TAC[COS_PI] THEN REAL_ARITH_TAC; ALL_TAC] THEN
+  MP_TAC(SPEC `z:complex` ARG) THEN REWRITE_TAC[CONJ_ASSOC] THEN
+  DISCH_THEN(MP_TAC o CONJUNCT1) THEN DISCH_THEN(STRIP_ASSUME_TAC o MATCH_MP
+   (REAL_ARITH `&0 <= x /\ x < &2 * pi
+                ==> --pi < x /\ x < pi \/ --pi < x - pi /\ x - pi < pi`)) THEN
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[SIN_EQ_0_PI] THEN
+  UNDISCH_TAC `~(Arg z = pi)` THEN ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  DISCH_TAC THEN REWRITE_TAC[REAL_ARITH `x = pi <=> x - pi = &0`] THEN
+  MATCH_MP_TAC SIN_EQ_0_PI THEN ASM_REWRITE_TAC[SIN_SUB; SIN_PI] THEN
+  REAL_ARITH_TAC);;
+
+let ARG_NUM = prove
+ (`!n. Arg(Cx(&n)) = &0`,
+  REWRITE_TAC[ARG_EQ_0; REAL_CX; RE_CX; REAL_POS]);;
+
+let ARG_EQ_PI = prove
+ (`!z. Arg z = pi <=> real z /\ Re z < &0`,
+  SIMP_TAC[ARG; PI_POS; REAL_ARITH
+    `&0 < pi /\ &0 <= z
+     ==> (z = pi <=> z <= pi /\ ~(z = &0) /\ ~(&0 < z /\ z < pi))`] THEN
+  REWRITE_TAC[ARG_EQ_0; ARG; ARG_LT_PI; ARG_LE_PI; real] THEN
+  REAL_ARITH_TAC);;
+
+let ARG_EQ_0_PI = prove
+ (`!z. Arg z = &0 \/ Arg z = pi <=> real z`,
+  REWRITE_TAC[ARG_EQ_0; ARG_EQ_PI; real] THEN REAL_ARITH_TAC);;
+
+let ARG_INV = prove
+ (`!z. ~(real z /\ &0 <= Re z) ==> Arg(inv z) = &2 * pi - Arg z`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THEN
+  ASM_REWRITE_TAC[REAL_CX; RE_CX; REAL_LE_REFL] THEN
+  REWRITE_TAC[real] THEN STRIP_TAC THEN MATCH_MP_TAC ARG_UNIQUE THEN
+  EXISTS_TAC `inv(norm(z:complex))` THEN
+  ASM_SIMP_TAC[COMPLEX_NORM_NZ; REAL_LT_INV_EQ] THEN
+  REWRITE_TAC[CX_SUB; CX_MUL; COMPLEX_SUB_LDISTRIB; CEXP_SUB] THEN
+  SUBST1_TAC(SPEC `Cx(&2) * Cx pi` CEXP_EULER) THEN
+  REWRITE_TAC[GSYM CX_MUL; GSYM CX_SIN; GSYM CX_COS] THEN
+  REWRITE_TAC[SIN_NPI; COS_NPI; COMPLEX_MUL_RZERO; COMPLEX_ADD_RID] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[complex_div; COMPLEX_MUL_LID; CX_INV; GSYM COMPLEX_INV_MUL] THEN
+  REWRITE_TAC[GSYM ARG] THEN
+  MP_TAC(SPEC `z:complex` ARG_EQ_0) THEN ASM_REWRITE_TAC[real] THEN
+  MP_TAC(SPEC `z:complex` ARG) THEN REAL_ARITH_TAC);;
+
+let ARG_EQ = prove
+ (`!w z. ~(w = Cx(&0)) /\ ~(z = Cx(&0))
+         ==> (Arg w = Arg z <=> ?x. &0 < x /\ w = Cx(x) * z)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [ALL_TAC; STRIP_TAC THEN ASM_SIMP_TAC[ARG_MUL_CX]] THEN
+  DISCH_TAC THEN
+  MAP_EVERY (MP_TAC o CONJUNCT2 o CONJUNCT2 o C SPEC ARG)
+   [`z:complex`; `w:complex`] THEN
+  ASM_REWRITE_TAC[IMP_IMP] THEN
+  DISCH_THEN(fun th -> CONV_TAC(SUBS_CONV(CONJUNCTS th))) THEN
+  EXISTS_TAC `norm(w:complex) / norm(z:complex)` THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; COMPLEX_NORM_NZ; CX_DIV] THEN
+  REWRITE_TAC[COMPLEX_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+  ASM_SIMP_TAC[COMPLEX_DIV_RMUL; COMPLEX_NORM_ZERO; CX_INJ]);;
+
+let ARG_INV_EQ_0 = prove
+ (`!z. Arg(inv z) = &0 <=> Arg z = &0`,
+  GEN_TAC THEN REWRITE_TAC[ARG_EQ_0; REAL_INV_EQ] THEN
+  MATCH_MP_TAC(TAUT `(a ==> (b <=> c)) ==> (a /\ b <=> a /\ c)`) THEN
+  REWRITE_TAC[real] THEN DISCH_TAC THEN ASM_REWRITE_TAC[complex_inv; RE] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[REAL_ADD_RID] THEN
+  ASM_CASES_TAC `Re z = &0` THEN ASM_REWRITE_TAC[real_div; REAL_MUL_LZERO] THEN
+  ASM_SIMP_TAC[REAL_FIELD `~(x = &0) ==> x * inv(x pow 2) = inv x`] THEN
+  REWRITE_TAC[REAL_LE_INV_EQ]);;
+
+let ARG_LE_DIV_SUM = prove
+ (`!w z. ~(w = Cx(&0)) /\ ~(z = Cx(&0)) /\ Arg(w) <= Arg(z)
+         ==> Arg(z) = Arg(w) + Arg(z / w)`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a:real = b + c <=> c = a - b`] THEN
+  MATCH_MP_TAC ARG_UNIQUE THEN EXISTS_TAC `norm(z / w)`THEN
+  ASM_SIMP_TAC[ARG; REAL_ARITH
+   `&0 <= a /\ a < &2 * pi /\ &0 <= b /\ b <= a ==> a - b < &2 * pi`] THEN
+  ASM_REWRITE_TAC[REAL_SUB_LE] THEN
+  ASM_SIMP_TAC[COMPLEX_NORM_DIV; CX_DIV] THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; COMPLEX_NORM_NZ] THEN
+  REWRITE_TAC[COMPLEX_SUB_LDISTRIB; CEXP_SUB; CX_SUB] THEN
+  REWRITE_TAC[complex_div] THEN
+  ONCE_REWRITE_TAC[COMPLEX_RING
+   `(a * b) * (c * d):complex = (a * c) * (b * d)`] THEN
+  REWRITE_TAC[GSYM COMPLEX_INV_MUL] THEN ASM_SIMP_TAC[GSYM ARG]);;
+
+let ARG_LE_DIV_SUM_EQ = prove
+ (`!w z. ~(w = Cx(&0)) /\ ~(z = Cx(&0))
+         ==> (Arg(w) <= Arg(z) <=> Arg(z) = Arg(w) + Arg(z / w))`,
+  MESON_TAC[ARG_LE_DIV_SUM; REAL_LE_ADDR; ARG]);;
+
+let REAL_SUB_ARG = prove
+ (`!w z. ~(w = Cx(&0)) /\ ~(z = Cx(&0))
+         ==> Arg w - Arg z = if Arg(z) <= Arg(w) then Arg(w / z)
+                             else Arg(w / z) - &2 * pi`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THENL
+   [MP_TAC(ISPECL [`z:complex`; `w:complex`] ARG_LE_DIV_SUM) THEN
+    ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+    MP_TAC(ISPECL [`w:complex`; `z:complex`] ARG_LE_DIV_SUM) THEN
+    ASM_REWRITE_TAC[] THEN
+    ANTS_TAC THENL [ASM_REAL_ARITH_TAC; DISCH_THEN SUBST1_TAC] THEN
+    REWRITE_TAC[REAL_ARITH `a - (a + b):real = --b`] THEN
+    GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [GSYM COMPLEX_INV_DIV] THEN
+    MATCH_MP_TAC(REAL_ARITH `x = &2 * pi - y ==> --x = y - &2 * pi`) THEN
+    MATCH_MP_TAC ARG_INV THEN REWRITE_TAC[GSYM ARG_EQ_0] THEN
+    ONCE_REWRITE_TAC[GSYM COMPLEX_INV_DIV] THEN
+    REWRITE_TAC[ARG_INV_EQ_0] THEN
+    MP_TAC(ISPECL [`w:complex`; `z:complex`] ARG_LE_DIV_SUM) THEN
+    ASM_REWRITE_TAC[] THEN ASM_REAL_ARITH_TAC]);;
+
+let REAL_ADD_ARG = prove
+ (`!w z. ~(w = Cx(&0)) /\ ~(z = Cx(&0))
+         ==> Arg(w) + Arg(z) =
+             if Arg w + Arg z < &2 * pi
+             then Arg(w * z)
+             else Arg(w * z) + &2 * pi`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`w * z:complex`; `z:complex`] REAL_SUB_ARG) THEN
+  MP_TAC(SPECL [`z:complex`; `w * z:complex`] ARG_LE_DIV_SUM_EQ) THEN
+  ASM_SIMP_TAC[COMPLEX_ENTIRE; COMPLEX_FIELD
+   `~(z = Cx(&0)) ==> (w * z) / z = w`] THEN
+  ASM_CASES_TAC `Arg (w * z) = Arg z + Arg w` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_MESON_TAC[ARG; REAL_ADD_SYM];
+    SIMP_TAC[REAL_ARITH `wz - z = w - &2 * pi <=> w + z = wz + &2 * pi`] THEN
+    REWRITE_TAC[REAL_ARITH `w + p < p <=> ~(&0 <= w)`; ARG]]);;
+
+let ARG_MUL = prove
+ (`!w z. ~(w = Cx(&0)) /\ ~(z = Cx(&0))
+         ==> Arg(w * z) = if Arg w + Arg z < &2 * pi
+                          then Arg w + Arg z
+                          else (Arg w + Arg z) - &2 * pi`,
+  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP REAL_ADD_ARG) THEN
+  REAL_ARITH_TAC);;
+
+let ARG_CNJ = prove
+ (`!z. Arg(cnj z) = if real z /\ &0 <= Re z then Arg z else &2 * pi - Arg z`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THEN
+  ASM_REWRITE_TAC[CNJ_CX; ARG_0; REAL_CX; RE_CX; REAL_LE_REFL] THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[REAL_IMP_CNJ] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `Arg(inv z)` THEN CONJ_TAC THENL
+   [REWRITE_TAC[COMPLEX_INV_CNJ] THEN
+    ASM_SIMP_TAC[GSYM CX_POW; ARG_DIV_CX; REAL_POW_LT; COMPLEX_NORM_NZ];
+    ASM_SIMP_TAC[ARG_INV]]);;
+
+let ARG_REAL = prove
+ (`!z. real z ==> Arg z = if &0 <= Re z then &0 else pi`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[ARG_EQ_PI; ARG_EQ_0] THEN ASM_REAL_ARITH_TAC);;
+
+let ARG_CEXP = prove
+ (`!z. &0 <= Im z /\ Im z < &2 * pi ==> Arg(cexp(z)) = Im z`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ARG_UNIQUE THEN
+  EXISTS_TAC `exp(Re z)` THEN
+  ASM_REWRITE_TAC[CX_EXP; GSYM CEXP_ADD; REAL_EXP_POS_LT] THEN
+  REWRITE_TAC[GSYM COMPLEX_EXPAND]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Properties of 2-D rotations, and their interpretation using cexp.         *)
+(* ------------------------------------------------------------------------- *)
+
+let rotate2d = new_definition
+ `(rotate2d:real->real^2->real^2) t x =
+        vector[x$1 * cos(t) - x$2 * sin(t);
+               x$1 * sin(t) + x$2 * cos(t)]`;;
+
+let LINEAR_ROTATE2D = prove
+ (`!t. linear(rotate2d t)`,
+  SIMP_TAC[linear; CART_EQ; DIMINDEX_2; FORALL_2; VECTOR_2;
+           VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; rotate2d] THEN
+  REAL_ARITH_TAC);;
+
+let ROTATE2D_ADD_VECTORS = prove
+ (`!t w z. rotate2d t (w + z) = rotate2d t w + rotate2d t z`,
+  SIMP_TAC[LINEAR_ADD; LINEAR_ROTATE2D]);;
+
+let ROTATE2D_SUB = prove
+ (`!t w z. rotate2d t (w - z) = rotate2d t w - rotate2d t z`,
+  SIMP_TAC[LINEAR_SUB; LINEAR_ROTATE2D]);;
+
+let NORM_ROTATE2D = prove
+ (`!t z. norm(rotate2d t z) = norm z`,
+  REWRITE_TAC[NORM_EQ; rotate2d; DIMINDEX_2; DOT_2; VECTOR_2] THEN
+  REPEAT GEN_TAC THEN MP_TAC(ISPEC `t:real` SIN_CIRCLE) THEN
+  CONV_TAC REAL_RING);;
+
+let ROTATE2D_0 = prove
+ (`!t. rotate2d t (Cx(&0)) = Cx(&0)`,
+  REWRITE_TAC[GSYM COMPLEX_NORM_ZERO; NORM_ROTATE2D; COMPLEX_NORM_0]);;
+
+let ROTATE2D_EQ_0 = prove
+ (`!t z. rotate2d t z = Cx(&0) <=> z = Cx(&0)`,
+  REWRITE_TAC[GSYM COMPLEX_NORM_ZERO; NORM_ROTATE2D]);;
+
+let ROTATE2D_ZERO = prove
+ (`!z. rotate2d (&0) z = z`,
+  REWRITE_TAC[rotate2d; SIN_0; COS_0] THEN
+  REWRITE_TAC[CART_EQ; DIMINDEX_2; FORALL_2; VECTOR_2] THEN
+  REAL_ARITH_TAC);;
+
+let ORTHOGONAL_TRANSFORMATION_ROTATE2D = prove
+ (`!t. orthogonal_transformation(rotate2d t)`,
+  REWRITE_TAC[ORTHOGONAL_TRANSFORMATION; LINEAR_ROTATE2D; NORM_ROTATE2D]);;
+
+let ROTATE2D_POLAR = prove
+ (`!r t s. rotate2d t (vector[r * cos(s); r * sin(s)]) =
+                        vector[r * cos(t + s); r * sin(t + s)]`,
+  SIMP_TAC[rotate2d; DIMINDEX_2; VECTOR_2; CART_EQ; FORALL_2] THEN
+  REWRITE_TAC[SIN_ADD; COS_ADD] THEN REAL_ARITH_TAC);;
+
+let MATRIX_ROTATE2D = prove
+ (`!t. matrix(rotate2d t) = vector[vector[cos t;--(sin t)];
+                                   vector[sin t; cos t]]`,
+  SIMP_TAC[MATRIX_EQ; MATRIX_WORKS; LINEAR_ROTATE2D] THEN
+  SIMP_TAC[matrix_vector_mul; rotate2d; CART_EQ; DIMINDEX_2; FORALL_2;
+           LAMBDA_BETA; VECTOR_2; ARITH; SUM_2] THEN
+  REAL_ARITH_TAC);;
+
+let DET_MATRIX_ROTATE2D = prove
+ (`!t. det(matrix(rotate2d t)) = &1`,
+  GEN_TAC THEN REWRITE_TAC[MATRIX_ROTATE2D; DET_2; VECTOR_2] THEN
+  MP_TAC(SPEC `t:real` SIN_CIRCLE) THEN REAL_ARITH_TAC);;
+
+let ROTATION_ROTATE2D = prove
+ (`!f. orthogonal_transformation f /\ det(matrix f) = &1
+       ==> ?t. &0 <= t /\ t < &2 * pi /\ f = rotate2d t`,
+  REWRITE_TAC[ORTHOGONAL_TRANSFORMATION_MATRIX] THEN
+  REWRITE_TAC[matrix_mul; orthogonal_matrix; transp] THEN
+  SIMP_TAC[DIMINDEX_2; SUM_2; FORALL_2; LAMBDA_BETA; ARITH;
+           CART_EQ; mat; DET_2] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(matrix f)$1$1 pow 2 + (matrix f)$2$1 pow 2 = &1 /\
+                (matrix f)$1$2 = --((matrix f)$2$1) /\
+                (matrix f:real^2^2)$2$2 = (matrix f)$1$1`
+  STRIP_ASSUME_TAC THENL
+   [REPEAT(FIRST_X_ASSUM(MP_TAC o SYM)) THEN CONV_TAC REAL_RING;
+    FIRST_X_ASSUM(MP_TAC o MATCH_MP SINCOS_TOTAL_2PI) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC LINEAR_EQ_MATRIX THEN
+    ASM_REWRITE_TAC[LINEAR_ROTATE2D; MATRIX_ROTATE2D] THEN
+    ASM_SIMP_TAC[CART_EQ; DIMINDEX_2; FORALL_2; VECTOR_2]]);;
+
+let ROTATE2D_ADD = prove
+ (`!s t x. rotate2d (s + t) x = rotate2d s (rotate2d t x)`,
+  SIMP_TAC[CART_EQ; rotate2d; LAMBDA_BETA; DIMINDEX_2; ARITH;
+           FORALL_2; VECTOR_2] THEN
+  REWRITE_TAC[SIN_ADD; COS_ADD] THEN REAL_ARITH_TAC);;
+
+let ROTATE2D_COMPLEX = prove
+ (`!t z. rotate2d t z = cexp(ii * Cx t) * z`,
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC RAND_CONV [complex_mul] THEN
+  REWRITE_TAC[CEXP_EULER; rotate2d; GSYM CX_SIN; GSYM CX_COS;
+              RE_ADD; IM_ADD; RE_MUL_II; IM_MUL_II; IM_CX; RE_CX] THEN
+  REWRITE_TAC[CART_EQ; FORALL_2; VECTOR_2; DIMINDEX_2] THEN
+  REWRITE_TAC[GSYM RE_DEF; GSYM IM_DEF; RE; IM] THEN
+  REAL_ARITH_TAC);;
+
+let ROTATE2D_PI2 = prove
+ (`!z. rotate2d (pi / &2) z = ii * z`,
+  REWRITE_TAC[ROTATE2D_COMPLEX; CEXP_EULER; SIN_PI2; COS_PI2; GSYM CX_SIN;
+              GSYM CX_COS] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let ROTATE2D_PI = prove
+ (`!z. rotate2d pi z = --z`,
+  REWRITE_TAC[ROTATE2D_COMPLEX; CEXP_EULER; SIN_PI; COS_PI; GSYM CX_SIN;
+              GSYM CX_COS] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let ROTATE2D_NPI = prove
+ (`!n z. rotate2d (&n * pi) z = --Cx(&1) pow n * z`,
+  REWRITE_TAC[ROTATE2D_COMPLEX; CEXP_EULER; SIN_NPI; COS_NPI; GSYM CX_SIN;
+              GSYM CX_COS; CX_NEG; CX_POW] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let ROTATE2D_2PI = prove
+ (`!z. rotate2d (&2 * pi) z = z`,
+  REWRITE_TAC[ROTATE2D_NPI] THEN CONV_TAC COMPLEX_RING);;
+
+let ARG_ROTATE2D = prove
+ (`!t z. ~(z = Cx(&0)) /\ &0 <= t + Arg z /\ t + Arg z < &2 * pi
+         ==> Arg(rotate2d t z) = t + Arg z`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ARG_UNIQUE THEN
+  EXISTS_TAC `norm(z:complex)` THEN
+  ASM_SIMP_TAC[ARG; ROTATE2D_COMPLEX; REAL_LE_ADD; COMPLEX_NORM_NZ] THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [ARG] THEN
+  REWRITE_TAC[CX_ADD; COMPLEX_ADD_LDISTRIB; CEXP_ADD] THEN
+  REWRITE_TAC[COMPLEX_MUL_AC]);;
+
+let ARG_ROTATE2D_UNIQUE = prove
+ (`!t a z. ~(z = Cx(&0)) /\ Arg(rotate2d t z) = a
+           ==> ?n. integer n /\ t = &2 * n * pi + (a - Arg z)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(last(CONJUNCTS(ISPEC `rotate2d t z` ARG))) THEN
+  ASM_REWRITE_TAC[NORM_ROTATE2D] THEN
+  REWRITE_TAC[ROTATE2D_COMPLEX] THEN
+  GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o RAND_CONV) [ARG] THEN
+  ASM_REWRITE_TAC[COMPLEX_RING `a * z * b = z * c <=> z = Cx(&0) \/ a * b = c`;
+                  CX_INJ; COMPLEX_NORM_ZERO; GSYM CEXP_ADD; CEXP_EQ] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN MATCH_MP_TAC MONO_AND THEN
+  REWRITE_TAC[GSYM CX_ADD; GSYM CX_SUB; CX_INJ; COMPLEX_RING
+   `ii * t + ii * z = ii * a + n * ii <=> t = n + (a - z)`]);;
+
+let ARG_ROTATE2D_UNIQUE_2PI = prove
+ (`!s t z. ~(z = Cx(&0)) /\
+           &0 <= s /\ s < &2 * pi /\ &0 <= t /\ t < &2 * pi /\
+           Arg(rotate2d s z) = Arg(rotate2d t z)
+           ==> s = t`,
+  REPEAT STRIP_TAC THEN ABBREV_TAC `a = Arg(rotate2d t z)` THEN
+  MP_TAC(ISPECL [`s:real`; `a:real`; `z:complex`] ARG_ROTATE2D_UNIQUE) THEN
+  MP_TAC(ISPECL [`t:real`; `a:real`; `z:complex`] ARG_ROTATE2D_UNIQUE) THEN
+  ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC SIN_COS_INJ THEN
+  REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+   [ASM_REWRITE_TAC[SIN_COS_EQ; REAL_RING
+     `x + az:real = (y + az) + z <=> x - y = z`] THEN
+    REWRITE_TAC[GSYM REAL_SUB_LDISTRIB; GSYM REAL_SUB_RDISTRIB] THEN
+    ASM_MESON_TAC[INTEGER_CLOSED];
+    ASM_REAL_ARITH_TAC]);;
+
+let COMPLEX_DIV_ROTATION = prove
+ (`!f w z. orthogonal_transformation f /\ det(matrix f) = &1
+           ==> f w / f z = w / z`,
+  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP ROTATION_ROTATE2D) THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[ROTATE2D_COMPLEX] THEN
+  SIMP_TAC[complex_div; COMPLEX_INV_MUL; CEXP_NZ; COMPLEX_FIELD
+   `~(a = Cx(&0)) ==> (a * w) * (inv a * z) = w * z`]);;
+
+let th = prove
+ (`!f w z. linear f /\ (!x. norm(f x) = norm x) /\
+           (2 <= dimindex(:2) ==> det(matrix f) = &1)
+           ==> f w / f z = w / z`,
+  REWRITE_TAC[CONJ_ASSOC; GSYM ORTHOGONAL_TRANSFORMATION;
+              DIMINDEX_2; LE_REFL; COMPLEX_DIV_ROTATION]) in
+add_linear_invariants [th];;
+
+let th = prove
+ (`!f t z. linear f /\ (!x. norm(f x) = norm x) /\
+           (2 <= dimindex(:2) ==> det(matrix f) = &1)
+           ==> rotate2d t (f z) = f(rotate2d t z)`,
+  REWRITE_TAC[DIMINDEX_2; LE_REFL] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(SPEC `f:complex->complex` ROTATION_ROTATE2D) THEN
+  ASM_REWRITE_TAC[ORTHOGONAL_TRANSFORMATION] THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real` STRIP_ASSUME_TAC) THEN
+  ASM_REWRITE_TAC[GSYM ROTATE2D_ADD] THEN REWRITE_TAC[REAL_ADD_SYM]) in
+add_linear_invariants [th];;
+
+let ROTATION_ROTATE2D_EXISTS_GEN = prove
+ (`!x y. ?t. &0 <= t /\ t < &2 * pi /\ norm(y) % rotate2d t x = norm(x) % y`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`norm(y:real^2) % x:real^2`; `norm(x:real^2) % y:real^2`]
+               ROTATION_EXISTS) THEN
+  ASM_REWRITE_TAC[DIMINDEX_2; NORM_MUL; ARITH; REAL_ABS_NORM;
+                  EQT_INTRO(SPEC_ALL REAL_MUL_SYM); CONJ_ASSOC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:real^2->real^2` (CONJUNCTS_THEN ASSUME_TAC)) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ROTATION_ROTATE2D) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[LINEAR_CMUL; LINEAR_ROTATE2D]);;
+
+let ROTATION_ROTATE2D_EXISTS = prove
+ (`!x y. norm x = norm y ==> ?t. &0 <= t /\ t < &2 * pi /\ rotate2d t x = y`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `norm(y:complex) = &0` THENL
+   [ASM_REWRITE_TAC[] THEN DISCH_TAC THEN EXISTS_TAC `&0` THEN
+    SIMP_TAC[REAL_LT_MUL; PI_POS; REAL_OF_NUM_LT; ARITH; REAL_LE_REFL] THEN
+    ASM_MESON_TAC[COMPLEX_NORM_ZERO; ROTATE2D_0];
+    DISCH_TAC THEN
+    MP_TAC(ISPECL [`x:complex`; `y:complex`] ROTATION_ROTATE2D_EXISTS_GEN) THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_LCANCEL]]);;
+
+let ROTATION_ROTATE2D_EXISTS_ORTHOGONAL = prove
+ (`!e1 e2. norm(e1) = &1 /\ norm(e2) = &1 /\ orthogonal e1 e2
+           ==> e1 = rotate2d (pi / &2) e2 \/ e2 = rotate2d (pi / &2) e1`,
+  REWRITE_TAC[NORM_EQ_1; orthogonal] THEN
+  SIMP_TAC[DOT_2; CART_EQ; FORALL_2; DIMINDEX_2; rotate2d; VECTOR_2] THEN
+  REWRITE_TAC[COS_PI2; SIN_PI2; REAL_MUL_RZERO; REAL_ADD_RID;
+              REAL_SUB_LZERO; REAL_SUB_RZERO; REAL_MUL_RID] THEN
+  CONV_TAC REAL_RING);;
+
+let ROTATION_ROTATE2D_EXISTS_ORTHOGONAL_ORIENTED = prove
+ (`!e1 e2. norm(e1) = &1 /\ norm(e2) = &1 /\ orthogonal e1 e2 /\
+           &0 < e1$1 * e2$2 - e1$2 * e2$1
+           ==> e2 = rotate2d (pi / &2) e1`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[CONJ_ASSOC] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC] THEN DISCH_TAC THEN
+  FIRST_ASSUM(DISJ_CASES_THEN SUBST_ALL_TAC o MATCH_MP
+    ROTATION_ROTATE2D_EXISTS_ORTHOGONAL) THEN
+  REWRITE_TAC[] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM REAL_NOT_LE]) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN DISCH_THEN(K ALL_TAC) THEN
+  SIMP_TAC[DOT_2; CART_EQ; FORALL_2; DIMINDEX_2; rotate2d; VECTOR_2] THEN
+  REWRITE_TAC[COS_PI2; SIN_PI2; REAL_MUL_RZERO; REAL_ADD_RID;
+              REAL_SUB_LZERO; REAL_SUB_RZERO; REAL_MUL_RID] THEN
+  REWRITE_TAC[REAL_ARITH `--x * x - y * y <= &0 <=> &0 <= x * x + y * y`] THEN
+  MATCH_MP_TAC REAL_LE_ADD THEN REWRITE_TAC[REAL_LE_SQUARE]);;
+
+let ROTATE2D_EQ = prove
+ (`!t x y. rotate2d t x = rotate2d t y <=> x = y`,
+  MESON_TAC[ORTHOGONAL_TRANSFORMATION_INJECTIVE;
+            ORTHOGONAL_TRANSFORMATION_ROTATE2D]);;
+
+let ROTATE2D_SUB_ARG = prove
+ (`!w z. ~(w = Cx(&0)) /\ ~(z = Cx(&0))
+         ==> rotate2d(Arg w - Arg z) = rotate2d(Arg(w / z))`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[REAL_SUB_ARG] THEN
+  COND_CASES_TAC THEN REWRITE_TAC[real_sub; ROTATE2D_ADD; FUN_EQ_THM] THEN
+  GEN_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[ROTATE2D_COMPLEX] THEN
+  REWRITE_TAC[EULER; RE_MUL_II; IM_MUL_II; RE_CX; IM_CX; COS_NEG; SIN_NEG] THEN
+  REWRITE_TAC[SIN_NPI; COS_NPI; REAL_EXP_NEG; REAL_EXP_0; CX_NEG] THEN
+  REWRITE_TAC[COMPLEX_NEG_0; COMPLEX_MUL_RZERO; COMPLEX_ADD_RID] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[COMPLEX_MUL_LID]);;
+
+let ROTATION_MATRIX_ROTATE2D = prove
+ (`!t. rotation_matrix(matrix(rotate2d t))`,
+  SIMP_TAC[ROTATION_MATRIX_2; MATRIX_ROTATE2D; VECTOR_2] THEN
+  MESON_TAC[SIN_CIRCLE; REAL_ADD_SYM]);;
+
+let ROTATION_MATRIX_ROTATE2D_EQ = prove
+ (`!A:real^2^2. rotation_matrix A <=> ?t. A = matrix(rotate2d t)`,
+  GEN_TAC THEN EQ_TAC THEN
+  SIMP_TAC[LEFT_IMP_EXISTS_THM; ROTATION_MATRIX_ROTATE2D] THEN
+  REWRITE_TAC[ROTATION_MATRIX_2; MATRIX_ROTATE2D] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP SINCOS_TOTAL_2PI) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[CART_EQ; DIMINDEX_2; FORALL_2; VECTOR_2] THEN
+  ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homotopy staying within the set of orthogonal transformations             *)
+(* ------------------------------------------------------------------------- *)
+
+let NULLHOMOTOPIC_ORTHOGONAL_TRANSFORMATION = prove
+ (`!f:real^N->real^N.
+       orthogonal_transformation f /\ det(matrix f) = &1
+       ==> homotopic_with orthogonal_transformation ((:real^N),(:real^N)) f I`,
+  let lemma0 = prove
+   (`!a x:real^N.
+          2 <= dimindex(:N) /\ a IN span {basis 1,basis 2}
+          ==> reflect_along (vector[a$1; a$2]:real^2) (lambda i. x$i) =
+              (lambda i. reflect_along a x$i)`,
+    REPEAT STRIP_TAC THEN
+    SIMP_TAC[CART_EQ; LAMBDA_BETA; reflect_along; VECTOR_SUB_COMPONENT;
+             VECTOR_MUL_COMPONENT; DIMINDEX_2; FORALL_2; VECTOR_2; ARITH] THEN
+    CONJ_TAC THEN AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
+    AP_TERM_TAC THEN BINOP_TAC THEN REWRITE_TAC[dot] THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_EQ_SUPERSET THEN
+    ASM_SIMP_TAC[FINITE_NUMSEG; IN_NUMSEG; FORALL_2; DIMINDEX_2; LAMBDA_BETA;
+                 ARITH; VECTOR_2; SUBSET_NUMSEG] THEN
+    REWRITE_TAC[ARITH_RULE
+     `(1 <= i /\ i <= n) /\ ~(1 <= i /\ i <= 2) <=>
+      1 <= i /\ 3 <= i /\ i <= n`] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [SPAN_2]) THEN
+    REWRITE_TAC[IN_ELIM_THM; IN_UNIV] THEN
+    STRIP_TAC THEN
+    ASM_REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+    SIMP_TAC[BASIS_COMPONENT] THEN
+    REPEAT STRIP_TAC THEN
+    REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_MUL_RZERO]) THEN
+    ASM_ARITH_TAC) in
+  let lemma1 = prove
+   (`!a b:real^2 r.
+          ~(a = vec 0) /\ ~(b = vec 0)
+          ==> homotopic_with orthogonal_transformation ((:real^2),(:real^2))
+                             (reflect_along a o reflect_along b) I`,
+    REPEAT STRIP_TAC THEN
+    MP_TAC(SPEC `reflect_along (a:real^2) o reflect_along b`
+          ROTATION_ROTATE2D) THEN
+    ANTS_TAC THENL
+     [REPEAT(FIRST_X_ASSUM(MP_TAC o
+        MATCH_MP ROTOINVERSION_MATRIX_REFLECT_ALONG)) THEN
+      REWRITE_TAC[rotoinversion_matrix] THEN
+      SIMP_TAC[ORTHOGONAL_MATRIX_MATRIX;
+               ORTHGOONAL_TRANSFORMATION_REFLECT_ALONG;
+               ORTHOGONAL_TRANSFORMATION_COMPOSE; MATRIX_COMPOSE;
+               LINEAR_REFLECT_ALONG; DET_MUL] THEN
+      CONV_TAC REAL_RAT_REDUCE_CONV;
+      DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THEN
+      ONCE_REWRITE_TAC[HOMOTOPIC_WITH_SYM] THEN
+      ASM_REWRITE_TAC[homotopic_with] THEN
+      EXISTS_TAC `\z. rotate2d (drop(fstcart z) * t) (sndcart z)` THEN
+      SIMP_TAC[ORTHOGONAL_TRANSFORMATION_ROTATE2D; SNDCART_PASTECART;
+               ETA_AX; FSTCART_PASTECART; DROP_VEC; I_THM; NORM_ROTATE2D;
+               REAL_MUL_LZERO; REAL_MUL_LID; SUBSET; FORALL_IN_IMAGE; IN_UNIV;
+               FORALL_IN_PCROSS; IN_SPHERE_0; ROTATE2D_ZERO] THEN
+      REWRITE_TAC[ROTATE2D_COMPLEX] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN
+      SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+      GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+      REWRITE_TAC[CONTINUOUS_ON_CEXP; CX_MUL] THEN
+      ONCE_REWRITE_TAC[COMPLEX_RING `ii * x * t = (ii * t) * x`] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_LMUL THEN
+      MATCH_MP_TAC CONTINUOUS_ON_CX_DROP THEN
+      SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART]]) in
+  let lemma2 = prove
+   (`!a b:real^N r.
+          2 <= dimindex(:N) /\
+          ~(a = vec 0) /\ ~(b = vec 0) /\
+          {a,b} SUBSET span {basis 1,basis 2}
+          ==> homotopic_with orthogonal_transformation ((:real^N),(:real^N))
+                             (reflect_along a o reflect_along b) I`,
+    REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN
+      `homotopic_with orthogonal_transformation
+        ((:real^N),(:real^N))
+        ((\z. (lambda i. if i <= 2 then (fstcart z)$i
+                         else (sndcart z)$i):real^N) o
+         (\z. pastecart
+               (((reflect_along (vector [(a:real^N)$1; a$2]) o
+                 reflect_along (vector [(b:real^N)$1; b$2]))
+                  :real^2->real^2)(fstcart z))
+               (sndcart z)) o
+         (\z:real^N. pastecart ((lambda i. z$i) :real^2) z))
+        ((\z. (lambda i. if i <= 2 then (fstcart z)$i
+                         else (sndcart z)$i):real^N) o
+         I o
+         (\z:real^N. pastecart ((lambda i. z$i) :real^2) z))`
+    MP_TAC THENL
+     [MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+      EXISTS_TAC `(:real^2) PCROSS (:real^N)` THEN
+      REWRITE_TAC[SUBSET_UNIV] THEN CONJ_TAC THENL
+       [ALL_TAC;
+        MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN
+        ONCE_REWRITE_TAC[LINEAR_COMPONENTWISE] THEN
+        SIMP_TAC[LAMBDA_BETA] THEN X_GEN_TAC `i:num` THEN
+        STRIP_TAC THEN ASM_CASES_TAC `i <= 2` THEN ASM_REWRITE_TAC[] THEN
+        REWRITE_TAC[linear; FSTCART_ADD; FSTCART_CMUL;
+                            SNDCART_ADD; SNDCART_CMUL] THEN
+        REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+        REWRITE_TAC[LIFT_ADD; LIFT_CMUL]] THEN
+      MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+      EXISTS_TAC `(:real^2) PCROSS (:real^N)` THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_UNIV; PASTECART_IN_PCROSS] THEN
+      CONJ_TAC THENL
+       [ALL_TAC;
+        MATCH_MP_TAC LINEAR_CONTINUOUS_ON THEN
+        MATCH_MP_TAC LINEAR_PASTECART THEN REWRITE_TAC[LINEAR_ID] THEN
+        SIMP_TAC[linear; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT;
+                 VECTOR_MUL_COMPONENT]] THEN
+      SUBGOAL_THEN
+       `I = \z:real^(2,N)finite_sum. pastecart (fstcart z) (sndcart z)`
+      SUBST1_TAC THENL
+       [REWRITE_TAC[PASTECART_FST_SND; I_DEF]; ALL_TAC] THEN
+      MATCH_MP_TAC HOMOTOPIC_WITH_PCROSS THEN
+      EXISTS_TAC `orthogonal_transformation:(real^2->real^2)->bool` THEN
+      EXISTS_TAC `\f:real^N->real^N. f = I` THEN REPEAT CONJ_TAC THENL
+       [REWRITE_TAC[GSYM I_DEF; ETA_AX] THEN MATCH_MP_TAC lemma1 THEN
+        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INSERT_SUBSET]) THEN
+        REWRITE_TAC[SING_SUBSET; SPAN_2; IN_ELIM_THM; IN_UNIV] THEN
+        DISCH_THEN(REPEAT_TCL STRIP_THM_THEN SUBST_ALL_TAC) THEN
+        POP_ASSUM_LIST(MP_TAC o end_itlist CONJ o rev) THEN
+        REWRITE_TAC[CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+                    DIMINDEX_2; FORALL_2; VECTOR_2] THEN
+        SIMP_TAC[BASIS_COMPONENT; ARITH; DIMINDEX_2; VEC_COMPONENT;
+                 DIMINDEX_GE_1; LE_REFL] THEN
+        MATCH_MP_TAC(TAUT
+         `(r ==> q) /\ (s ==> p) ==> a /\ ~p /\ ~q ==> ~s /\ ~r`) THEN
+        SIMP_TAC[REAL_MUL_RZERO; REAL_MUL_LZERO; REAL_MUL_RID;
+                 REAL_ADD_LID; REAL_ADD_RID];
+        REWRITE_TAC[HOMOTOPIC_WITH_REFL; SUBSET_UNIV; I_DEF] THEN
+        REWRITE_TAC[CONTINUOUS_ON_ID];
+        SIMP_TAC[o_DEF; FSTCART_PASTECART; SNDCART_PASTECART;
+                 LAMBDA_BETA; DIMINDEX_2; ARITH; I_THM] THEN
+        REWRITE_TAC[ORTHOGONAL_TRANSFORMATION; NORM_EQ] THEN
+        X_GEN_TAC `f:real^2->real^2` THEN GEN_TAC THEN STRIP_TAC THEN
+        CONJ_TAC THENL
+         [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [linear]) THEN
+          SIMP_TAC[linear; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT;
+                   VECTOR_MUL_COMPONENT; DIMINDEX_2; ARITH] THEN
+          MATCH_MP_TAC MONO_AND THEN CONJ_TAC THEN
+          DISCH_THEN(ASSUME_TAC o GSYM) THEN GEN_TAC THEN
+          GEN_TAC THEN X_GEN_TAC `i:num` THEN STRIP_TAC THEN
+          COND_CASES_TAC THEN ASM_SIMP_TAC[] THEN
+          AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+          SIMP_TAC[CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT;
+                   VECTOR_MUL_COMPONENT];
+          X_GEN_TAC `v:real^N` THEN REWRITE_TAC[dot; GSYM REAL_POW_2] THEN
+          SUBGOAL_THEN `dimindex(:N) = 2 + (dimindex(:N) - 2)` SUBST1_TAC THENL
+           [ASM_ARITH_TAC; ALL_TAC] THEN
+          ASM_SIMP_TAC[SUM_ADD_SPLIT; ARITH_RULE `1 <= n + 1`] THEN
+          BINOP_TAC THENL
+           [RULE_ASSUM_TAC(REWRITE_RULE[dot; DIMINDEX_2; GSYM REAL_POW_2]) THEN
+            FIRST_X_ASSUM(MP_TAC o SPEC `(lambda i. (v:real^N)$i):real^2`) THEN
+            MATCH_MP_TAC EQ_IMP THEN BINOP_TAC THEN
+            MATCH_MP_TAC SUM_EQ_NUMSEG THEN
+            FIRST_ASSUM(MP_TAC o MATCH_MP (ARITH_RULE
+             `2 <= n ==> !i. i <= 2 ==> i <= n`)) THEN
+            SIMP_TAC[LAMBDA_BETA; DIMINDEX_2];
+            ASM_SIMP_TAC[ARITH_RULE `2 <= n ==> 2 + n - 2 = n`] THEN
+            MATCH_MP_TAC SUM_EQ_NUMSEG THEN
+            SIMP_TAC[ARITH_RULE `2 + 1 <= i ==> 1 <= i`;
+                     LAMBDA_BETA; DIMINDEX_2] THEN
+            REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+            ASM_ARITH_TAC]]];
+      MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_EQ) THEN
+      REWRITE_TAC[IN_UNIV; GSYM FUN_EQ_THM] THEN
+      SIMP_TAC[o_DEF; FSTCART_PASTECART; SNDCART_PASTECART;
+               LAMBDA_BETA; DIMINDEX_2; ARITH; I_THM] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[INSERT_SUBSET; EMPTY_SUBSET]) THEN
+      ASM_SIMP_TAC[lemma0] THEN
+      SIMP_TAC[CART_EQ; LAMBDA_BETA; DIMINDEX_2; ARITH; COND_ID] THEN
+      MAP_EVERY X_GEN_TAC [`x:real^N`; `i:num`] THEN STRIP_TAC THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+      SUBGOAL_THEN `(a:real^N)$i = &0 /\ (b:real^N)$i = &0` ASSUME_TAC THENL
+       [FIRST_X_ASSUM(CONJUNCTS_THEN MP_TAC) THEN
+        REWRITE_TAC[SPAN_2; IN_ELIM_THM; IN_UNIV] THEN REPEAT STRIP_TAC THEN
+        ASM_SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+                     BASIS_COMPONENT] THEN
+        REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+        (REAL_ARITH_TAC ORELSE ASM_ARITH_TAC);
+        ASM_REWRITE_TAC[reflect_along; VECTOR_SUB_COMPONENT; REAL_MUL_RZERO;
+                        VECTOR_MUL_COMPONENT; REAL_SUB_RZERO]]]) in
+  let lemma3 = prove
+   (`!a b:real^N r.
+          ~(a = vec 0) /\ ~(b = vec 0)
+          ==> homotopic_with orthogonal_transformation ((:real^N),(:real^N))
+                             (reflect_along a o reflect_along b) I`,
+    REPEAT STRIP_TAC THEN ASM_CASES_TAC `dimindex(:N) = 1` THENL
+     [ASM_SIMP_TAC[o_DEF; I_DEF; REFLECT_ALONG_1D; VECTOR_NEG_NEG] THEN
+      REWRITE_TAC[HOMOTOPIC_WITH_REFL; SUBSET_UNIV; CONTINUOUS_ON_ID] THEN
+      REWRITE_TAC[ORTHOGONAL_TRANSFORMATION_ID];
+      FIRST_X_ASSUM(MP_TAC o MATCH_MP(ARITH_RULE
+       `~(n = 1) ==> 1 <= n ==> 2 <= n`)) THEN
+      REWRITE_TAC[DIMINDEX_GE_1] THEN DISCH_TAC] THEN
+    MP_TAC(ISPECL [`span{a:real^N,b}`; `span{basis 1:real^N,basis 2}`]
+          ORTHOGONAL_TRANSFORMATION_INTO_SUBSPACE) THEN
+    REWRITE_TAC[SUBSPACE_SPAN; DIM_SPAN] THEN ANTS_TAC THENL
+     [ASM_REWRITE_TAC[DIM_INSERT; SPAN_SING; SPAN_EMPTY;
+                      IN_SING; DIM_EMPTY] THEN
+      MATCH_MP_TAC(ARITH_RULE `m <= 2 /\ n = 2 ==> m <= n`) THEN
+      CONJ_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+      ASM_SIMP_TAC[BASIS_NONZERO; ARITH] THEN
+      REWRITE_TAC[IN_ELIM_THM; IN_UNIV] THEN
+      COND_CASES_TAC THEN REWRITE_TAC[] THEN
+      FIRST_X_ASSUM(CHOOSE_THEN (MP_TAC o AP_TERM `(\x:real^N. x$1)`)) THEN
+      ASM_SIMP_TAC[BASIS_COMPONENT; VECTOR_MUL_COMPONENT;
+                   ARITH; DIMINDEX_GE_1] THEN
+      REAL_ARITH_TAC;
+      DISCH_THEN(X_CHOOSE_THEN `f:real^N->real^N` STRIP_ASSUME_TAC) THEN
+      MP_TAC(ISPEC `f:real^N->real^N` ORTHOGONAL_TRANSFORMATION_INVERSE_o) THEN
+      ASM_REWRITE_TAC[] THEN
+      DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^N` STRIP_ASSUME_TAC)] THEN
+    SUBGOAL_THEN
+     `homotopic_with orthogonal_transformation ((:real^N),(:real^N))
+       (g o (f o (reflect_along a o reflect_along b) o (g:real^N->real^N)) o f)
+       (g o (f o I o (g:real^N->real^N)) o f)`
+    MP_TAC THENL
+     [ALL_TAC;
+      ASM_REWRITE_TAC[o_ASSOC] THEN ASM_REWRITE_TAC[GSYM o_ASSOC; I_O_ID]] THEN
+    MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+    EXISTS_TAC `(:real^N)` THEN REWRITE_TAC[SUBSET_UNIV] THEN
+    ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_LINEAR; LINEAR_CONTINUOUS_ON] THEN
+    MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+    EXISTS_TAC `(:real^N)` THEN REWRITE_TAC[SUBSET_UNIV] THEN
+    ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_LINEAR; LINEAR_CONTINUOUS_ON] THEN
+    ASM_REWRITE_TAC[I_O_ID] THEN
+    MP_TAC(ISPEC `f:real^N->real^N` REFLECT_ALONG_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[GSYM ORTHOGONAL_TRANSFORMATION] THEN
+    DISCH_THEN(ASSUME_TAC o GSYM) THEN
+    SUBGOAL_THEN
+     `!h:real^N->real^N.
+          orthogonal_transformation (g o h o (f:real^N->real^N)) <=>
+          orthogonal_transformation h`
+     (fun th -> REWRITE_TAC[th; ETA_AX])
+    THENL
+     [GEN_TAC THEN EQ_TAC THEN
+      ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_COMPOSE] THEN
+      DISCH_TAC THEN
+      SUBGOAL_THEN `h:real^N->real^N = f o (g o h o f) o (g:real^N->real^N)`
+      SUBST1_TAC THENL
+       [ALL_TAC; ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_COMPOSE]] THEN
+      ASM_REWRITE_TAC[o_ASSOC] THEN ASM_REWRITE_TAC[GSYM o_ASSOC; I_O_ID];
+      ALL_TAC] THEN
+    SUBGOAL_THEN
+     `(f:real^N->real^N) o (reflect_along a o reflect_along b) o g =
+      reflect_along (f a) o reflect_along (f b)`
+    SUBST1_TAC THENL
+     [RULE_ASSUM_TAC(REWRITE_RULE[FUN_EQ_THM; o_THM; I_THM]) THEN
+      ASM_REWRITE_TAC[o_DEF];
+      MATCH_MP_TAC lemma2 THEN RULE_ASSUM_TAC
+       (REWRITE_RULE[GSYM NORM_EQ_0; ORTHOGONAL_TRANSFORMATION]) THEN
+      ASM_REWRITE_TAC[GSYM NORM_EQ_0] THEN
+      FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT]
+         SUBSET_TRANS)) THEN
+      ASM_SIMP_TAC[GSYM SPAN_LINEAR_IMAGE; IMAGE_CLAUSES] THEN
+      REWRITE_TAC[SPAN_INC]]) in
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  MP_TAC(ISPECL [`f:real^N->real^N`; `dimindex(:N)`]
+        ORTHOGONAL_TRANSFORMATION_GENERATED_BY_REFLECTIONS) THEN
+  ASM_REWRITE_TAC[ARITH_RULE `n:num <= a + n`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `l:(real^N)list` STRIP_ASSUME_TAC) THEN
+  UNDISCH_TAC `ALL (\v:real^N. ~(v = vec 0)) l` THEN
+  UNDISCH_TAC `orthogonal_transformation(f:real^N->real^N)` THEN
+  MATCH_MP_TAC(TAUT `r /\ (p /\ q ==> s) ==> r ==> p ==> q ==> s`) THEN
+  ASM_REWRITE_TAC[IMP_IMP] THEN
+  SPEC_TAC(`l:(real^N)list`,`l:(real^N)list`) THEN
+  POP_ASSUM_LIST(K ALL_TAC) THEN GEN_TAC THEN
+  WF_INDUCT_TAC `LENGTH(l:(real^N)list)` THEN POP_ASSUM MP_TAC THEN
+  SPEC_TAC(`l:(real^N)list`,`l:(real^N)list`) THEN
+  MATCH_MP_TAC list_INDUCT THEN
+  REWRITE_TAC[ALL; ITLIST; HOMOTOPIC_WITH_REFL] THEN
+  REWRITE_TAC[REWRITE_RULE[GSYM I_DEF] CONTINUOUS_ON_ID;
+              ORTHOGONAL_TRANSFORMATION_I; SUBSET_UNIV] THEN
+  X_GEN_TAC `a:real^N` THEN MATCH_MP_TAC list_INDUCT THEN
+  REWRITE_TAC[ALL; ITLIST; I_O_ID; DET_MATRIX_REFLECT_ALONG] THEN
+  REWRITE_TAC[ORTHGOONAL_TRANSFORMATION_REFLECT_ALONG] THEN
+  CONJ_TAC THENL [MESON_TAC[REAL_ARITH `~(-- &1 = &1)`]; ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`b:real^N`; `l:(real^N)list`] THEN
+  REPLICATE_TAC 2 (DISCH_THEN(K ALL_TAC)) THEN
+  DISCH_THEN(MP_TAC o SPEC `l:(real^N)list`) THEN
+  REWRITE_TAC[LENGTH; ARITH_RULE `n < SUC(SUC n)`] THEN
+  SIMP_TAC[LINEAR_COMPOSE; LINEAR_REFLECT_ALONG; MATRIX_COMPOSE;
+     ORTHGOONAL_TRANSFORMATION_REFLECT_ALONG;
+     ORTHOGONAL_TRANSFORMATION_COMPOSE; ORTHOGONAL_TRANSFORMATION_LINEAR] THEN
+  DISCH_THEN(fun th ->
+    DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN MP_TAC th) THEN
+  ASM_SIMP_TAC[DET_MUL; DET_MATRIX_REFLECT_ALONG; REAL_ARITH
+   `-- &1 * -- &1 * x = x`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
+  ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HOMOTOPIC_WITH_TRANS) THEN
+  GEN_REWRITE_TAC RAND_CONV [MESON[I_O_ID] `f = I o f`] THEN
+  REWRITE_TAC[o_ASSOC] THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+  EXISTS_TAC `(:real^N)` THEN REWRITE_TAC[SUBSET_UNIV] THEN
+  ASM_SIMP_TAC[LINEAR_CONTINUOUS_ON; ORTHOGONAL_TRANSFORMATION_LINEAR] THEN
+  ABBREV_TAC `g = ITLIST (\v:real^N h. reflect_along v o h) l I` THEN
+  SUBGOAL_THEN
+   `(\f:real^N->real^N.
+        orthogonal_transformation (f o g)) = orthogonal_transformation`
+  SUBST1_TAC THENL [ALL_TAC; MATCH_MP_TAC lemma3 THEN ASM_REWRITE_TAC[]] THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `f:real^N->real^N` THEN
+  EQ_TAC THEN ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_COMPOSE] THEN
+  DISCH_TAC THEN
+  MP_TAC(ISPEC `g:real^N->real^N` ORTHOGONAL_TRANSFORMATION_INVERSE_o) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `h:real^N->real^N` THEN
+  STRIP_TAC THEN
+  SUBGOAL_THEN `f = ((f:real^N->real^N) o (g:real^N->real^N)) o h`
+  SUBST1_TAC THENL
+   [ASM_REWRITE_TAC[GSYM o_ASSOC; I_O_ID];
+    ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_COMPOSE]]);;
+
+let HOMOTOPIC_SPECIAL_ORTHOGONAL_TRANSFORMATIONS,
+    HOMOTOPIC_ORTHOGONAL_TRANSFORMATIONS = (CONJ_PAIR o prove)
+ (`(!f g. homotopic_with
+            (\h. orthogonal_transformation h /\ det(matrix h) = det(matrix f))
+            ((:real^N),(:real^N)) f g <=>
+          homotopic_with
+            orthogonal_transformation ((:real^N),(:real^N)) f g) /\
+   !f g. homotopic_with orthogonal_transformation ((:real^N),(:real^N)) f g <=>
+         orthogonal_transformation f /\ orthogonal_transformation g /\
+         det(matrix f) = det(matrix g)`,
+  REWRITE_TAC[AND_FORALL_THM] THEN REPEAT GEN_TAC THEN MATCH_MP_TAC(TAUT
+   `(u ==> s) /\ (s ==> t) /\ (t ==> u)
+    ==> (u <=> t) /\ (t <=> s)`) THEN
+  REPEAT CONJ_TAC THENL
+   [DISCH_THEN(MP_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_PROPERTY) THEN MESON_TAC[];
+    STRIP_TAC THEN
+    MP_TAC(ISPEC `g:real^N->real^N` ORTHOGONAL_TRANSFORMATION_INVERSE_o) THEN
+    ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(X_CHOOSE_THEN `h:real^N->real^N` STRIP_ASSUME_TAC) THEN
+    SUBGOAL_THEN
+     `(f:real^N->real^N) = g o (h:real^N->real^N) o f /\ g = g o I`
+     (fun th -> ONCE_REWRITE_TAC[th])
+    THENL [ASM_REWRITE_TAC[o_ASSOC; I_O_ID]; ALL_TAC] THEN
+    MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_LEFT THEN
+    EXISTS_TAC `(:real^N)` THEN REWRITE_TAC[SUBSET_UNIV] THEN
+    ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_LINEAR; LINEAR_CONTINUOUS_ON] THEN
+    SUBGOAL_THEN
+      `!k:real^N->real^N.
+          orthogonal_transformation (g o k) <=> orthogonal_transformation k`
+      (fun th -> REWRITE_TAC[th; ETA_AX])
+    THENL
+     [GEN_TAC THEN EQ_TAC THEN
+      ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_COMPOSE] THEN DISCH_THEN
+       (MP_TAC o SPEC `h:real^N->real^N` o MATCH_MP (ONCE_REWRITE_RULE
+         [IMP_CONJ_ALT] ORTHOGONAL_TRANSFORMATION_COMPOSE)) THEN
+      ASM_SIMP_TAC[o_ASSOC; I_O_ID];
+      MATCH_MP_TAC NULLHOMOTOPIC_ORTHOGONAL_TRANSFORMATION THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o AP_TERM
+       `\f:real^N->real^N. det(matrix f)`)) THEN
+      ASM_SIMP_TAC[MATRIX_COMPOSE; ORTHOGONAL_TRANSFORMATION_LINEAR;
+                   ORTHOGONAL_TRANSFORMATION_COMPOSE; DET_MUL;
+                   MATRIX_I; DET_I]];
+    REWRITE_TAC[homotopic_with] THEN MATCH_MP_TAC MONO_EXISTS THEN
+    X_GEN_TAC `k:real^(1,N)finite_sum->real^N` THEN
+    STRIP_TAC THEN ASM_SIMP_TAC[] THEN MP_TAC(ISPECL
+     [`\t. lift(
+       det(matrix((k:real^(1,N)finite_sum->real^N) o pastecart t)))`;
+      `interval[vec 0:real^1,vec 1]`]
+     CONTINUOUS_DISCRETE_RANGE_CONSTANT) THEN
+    REWRITE_TAC[CONNECTED_INTERVAL] THEN ANTS_TAC THENL
+     [CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_LIFT_DET THEN
+        SIMP_TAC[matrix; LAMBDA_BETA; o_DEF] THEN
+        MAP_EVERY X_GEN_TAC [`i:num`; `j:num`] THEN STRIP_TAC THEN
+        MATCH_MP_TAC CONTINUOUS_ON_LIFT_COMPONENT_COMPOSE THEN
+        ASM_REWRITE_TAC[] THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        SIMP_TAC[CONTINUOUS_ON_PASTECART; CONTINUOUS_ON_CONST;
+                 CONTINUOUS_ON_ID] THEN
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        SIMP_TAC[SUBSET; FORALL_IN_IMAGE; PASTECART_IN_PCROSS; IN_UNIV];
+        X_GEN_TAC `t:real^1` THEN DISCH_TAC THEN EXISTS_TAC `&1` THEN
+        REWRITE_TAC[REAL_LT_01] THEN X_GEN_TAC `u:real^1` THEN
+        DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+        REWRITE_TAC[GSYM LIFT_SUB; NORM_LIFT; LIFT_EQ] THEN
+        SUBGOAL_THEN
+         `orthogonal_transformation
+           ((k:real^(1,N)finite_sum->real^N) o pastecart t) /\
+          orthogonal_transformation (k o pastecart u)`
+        MP_TAC THENL [ASM_SIMP_TAC[o_DEF]; ALL_TAC] THEN
+        DISCH_THEN(CONJUNCTS_THEN
+          (STRIP_ASSUME_TAC o MATCH_MP DET_ORTHOGONAL_MATRIX o
+                    MATCH_MP ORTHOGONAL_MATRIX_MATRIX)) THEN
+        ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV];
+      REWRITE_TAC[o_DEF; LEFT_IMP_EXISTS_THM] THEN
+      X_GEN_TAC `a:real^1` THEN DISCH_TAC THEN
+      REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM FUN_EQ_THM])) THEN
+      REPEAT(DISCH_THEN(SUBST1_TAC o SYM)) THEN
+      ASM_SIMP_TAC[ENDS_IN_UNIT_INTERVAL; GSYM LIFT_EQ]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex tangent function.                                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let ctan = new_definition
+ `ctan z = csin z / ccos z`;;
+
+let CTAN_0 = prove
+ (`ctan(Cx(&0)) = Cx(&0)`,
+  REWRITE_TAC[ctan; CSIN_0; CCOS_0; COMPLEX_DIV_1]);;
+
+let CTAN_NEG = prove
+ (`!z. ctan(--z) = --(ctan z)`,
+  REWRITE_TAC[ctan; CSIN_NEG; CCOS_NEG; complex_div; COMPLEX_MUL_LNEG]);;
+
+let CTAN_ADD = prove
+ (`!w z. ~(ccos(w) = Cx(&0)) /\
+         ~(ccos(z) = Cx(&0)) /\
+         ~(ccos(w + z) = Cx(&0))
+         ==> ctan(w + z) = (ctan w + ctan z) / (Cx(&1) - ctan(w) * ctan(z))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[ctan; CSIN_ADD; CCOS_ADD] THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CTAN_DOUBLE = prove
+ (`!z. ~(ccos(z) = Cx(&0)) /\ ~(ccos(Cx(&2) * z) = Cx(&0))
+       ==> ctan(Cx(&2) * z) =
+           (Cx(&2) * ctan z) / (Cx(&1) - ctan(z) pow 2)`,
+  SIMP_TAC[COMPLEX_MUL_2; CTAN_ADD; COMPLEX_POW_2]);;
+
+let CTAN_SUB = prove
+ (`!w z. ~(ccos(w) = Cx(&0)) /\
+         ~(ccos(z) = Cx(&0)) /\
+         ~(ccos(w - z) = Cx(&0))
+         ==> ctan(w - z) = (ctan w - ctan z) / (Cx(&1) + ctan(w) * ctan(z))`,
+  SIMP_TAC[complex_sub; CTAN_ADD; CCOS_NEG; CTAN_NEG] THEN
+  REWRITE_TAC[COMPLEX_MUL_RNEG; COMPLEX_NEG_NEG]);;
+
+let COMPLEX_ADD_CTAN = prove
+ (`!w z. ~(ccos(w) = Cx(&0)) /\
+         ~(ccos(z) = Cx(&0))
+         ==> ctan(w) + ctan(z) = csin(w + z) / (ccos(w) * ccos(z))`,
+  REWRITE_TAC[ctan; CSIN_ADD] THEN CONV_TAC COMPLEX_FIELD);;
+
+let COMPLEX_SUB_CTAN = prove
+ (`!w z. ~(ccos(w) = Cx(&0)) /\
+         ~(ccos(z) = Cx(&0))
+         ==> ctan(w) - ctan(z) = csin(w - z) / (ccos(w) * ccos(z))`,
+  REWRITE_TAC[ctan; CSIN_SUB] THEN CONV_TAC COMPLEX_FIELD);;
+
+(* ------------------------------------------------------------------------- *)
+(* Analytic properties of tangent function.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_COMPLEX_DERIVATIVE_CTAN = prove
+ (`!z. ~(ccos z = Cx(&0))
+       ==> (ctan has_complex_derivative (inv(ccos(z) pow 2))) (at z)`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+  REWRITE_TAC[ctan] THEN COMPLEX_DIFF_TAC THEN
+  MP_TAC(SPEC `z:complex` CSIN_CIRCLE) THEN
+  POP_ASSUM MP_TAC THEN CONV_TAC COMPLEX_FIELD);;
+
+let COMPLEX_DIFFERENTIABLE_AT_CTAN = prove
+ (`!z. ~(ccos z = Cx(&0)) ==> ctan complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CTAN]);;
+
+let COMPLEX_DIFFERENTIABLE_WITHIN_CTAN = prove
+ (`!s z. ~(ccos z = Cx(&0))
+         ==> ctan complex_differentiable (at z within s)`,
+  MESON_TAC[COMPLEX_DIFFERENTIABLE_AT_WITHIN;
+            COMPLEX_DIFFERENTIABLE_AT_CTAN]);;
+
+add_complex_differentiation_theorems
+ (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+   (MATCH_MP HAS_COMPLEX_DERIVATIVE_CHAIN
+             HAS_COMPLEX_DERIVATIVE_CTAN)));;
+
+let CONTINUOUS_AT_CTAN = prove
+ (`!z. ~(ccos z = Cx(&0)) ==> ctan continuous at z`,
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CTAN;
+            HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT]);;
+
+let CONTINUOUS_WITHIN_CTAN = prove
+ (`!s z. ~(ccos z = Cx(&0)) ==> ctan continuous (at z within s)`,
+  MESON_TAC[CONTINUOUS_AT_WITHIN; CONTINUOUS_AT_CTAN]);;
+
+let CONTINUOUS_ON_CTAN = prove
+ (`!s. (!z. z IN s ==> ~(ccos z = Cx(&0))) ==> ctan continuous_on s`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON; CONTINUOUS_AT_CTAN]);;
+
+let HOLOMORPHIC_ON_CTAN = prove
+ (`!s. (!z. z IN s ==> ~(ccos z = Cx(&0))) ==> ctan holomorphic_on s`,
+  REWRITE_TAC [holomorphic_on] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HAS_COMPLEX_DERIVATIVE_CTAN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real tangent function.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let tan_def = new_definition
+ `tan(x) = Re(ctan(Cx x))`;;
+
+let CNJ_CTAN = prove
+ (`!z. cnj(ctan z) = ctan(cnj z)`,
+  REWRITE_TAC[ctan; CNJ_DIV; CNJ_CSIN; CNJ_CCOS]);;
+
+let REAL_TAN = prove
+ (`!z. real z ==> real(ctan z)`,
+  SIMP_TAC[REAL_CNJ; CNJ_CTAN]);;
+
+let CX_TAN = prove
+ (`!x. Cx(tan x) = ctan(Cx x)`,
+  REWRITE_TAC[tan_def] THEN MESON_TAC[REAL; REAL_CX; REAL_TAN]);;
+
+let tan = prove
+ (`!x. tan x = sin x / cos x`,
+  REWRITE_TAC[GSYM CX_INJ; CX_DIV; CX_TAN; CX_SIN; CX_COS; ctan]);;
+
+let TAN_0 = prove
+ (`tan(&0) = &0`,
+  REWRITE_TAC[GSYM CX_INJ; CX_TAN; CTAN_0]);;
+
+let TAN_PI = prove
+ (`tan(pi) = &0`,
+  REWRITE_TAC[tan; SIN_PI; real_div; REAL_MUL_LZERO]);;
+
+let TAN_NPI = prove
+ (`!n. tan(&n * pi) = &0`,
+  REWRITE_TAC[tan; SIN_NPI; real_div; REAL_MUL_LZERO]);;
+
+let TAN_NEG = prove
+ (`!x. tan(--x) = --(tan x)`,
+  REWRITE_TAC[GSYM CX_INJ; CX_TAN; CX_NEG; CTAN_NEG]);;
+
+let TAN_PERIODIC_PI = prove
+ (`!x. tan(x + pi) = tan(x)`,
+  REWRITE_TAC[tan; SIN_PERIODIC_PI; COS_PERIODIC_PI; real_div] THEN
+  REWRITE_TAC[REAL_MUL_LNEG; REAL_INV_NEG; REAL_MUL_RNEG; REAL_NEG_NEG]);;
+
+let TAN_PERIODIC_NPI = prove
+ (`!x n. tan(x + &n * pi) = tan(x)`,
+  GEN_TAC THEN INDUCT_TAC THEN REWRITE_TAC[REAL_MUL_LZERO; REAL_ADD_RID] THEN
+  REWRITE_TAC[GSYM REAL_OF_NUM_SUC; REAL_ADD_RDISTRIB; REAL_MUL_LID] THEN
+  ASM_REWRITE_TAC[REAL_ADD_ASSOC; TAN_PERIODIC_PI]);;
+
+let TAN_ADD = prove
+ (`!x y. ~(cos(x) = &0) /\ ~(cos(y) = &0) /\ ~(cos(x + y) = &0)
+         ==> tan(x + y) = (tan(x) + tan(y)) / (&1 - tan(x) * tan(y))`,
+  REWRITE_TAC[GSYM CX_INJ; CX_TAN; CX_SIN; CX_COS; CTAN_ADD;
+              CX_DIV; CX_ADD; CX_SUB; CX_MUL]);;
+
+let TAN_SUB = prove
+ (`!x y. ~(cos(x) = &0) /\ ~(cos(y) = &0) /\ ~(cos(x - y) = &0)
+         ==> tan(x - y) = (tan(x) - tan(y)) / (&1 + tan(x) * tan(y))`,
+  REWRITE_TAC[GSYM CX_INJ; CX_TAN; CX_SIN; CX_COS; CX_ADD; CTAN_SUB;
+              CX_DIV; CX_ADD; CX_SUB; CX_MUL]);;
+
+let TAN_DOUBLE = prove
+ (`!x. ~(cos(x) = &0) /\ ~(cos(&2 * x) = &0)
+       ==> tan(&2 * x) = (&2 * tan(x)) / (&1 - (tan(x) pow 2))`,
+  SIMP_TAC[REAL_MUL_2; TAN_ADD; REAL_POW_2]);;
+
+let REAL_ADD_TAN = prove
+ (`!x y. ~(cos(x) = &0) /\ ~(cos(y) = &0)
+         ==> tan(x) + tan(y) = sin(x + y) / (cos(x) * cos(y))`,
+  REWRITE_TAC[GSYM CX_INJ; CX_TAN; CX_SIN; CX_COS; CX_MUL; CX_ADD; CX_DIV] THEN
+  REWRITE_TAC[COMPLEX_ADD_CTAN]);;
+
+let REAL_SUB_TAN = prove
+ (`!x y. ~(cos(x) = &0) /\ ~(cos(y) = &0)
+         ==> tan(x) - tan(y) = sin(x - y) / (cos(x) * cos(y))`,
+  REWRITE_TAC[GSYM CX_INJ; CX_TAN; CX_SIN; CX_COS; CX_MUL; CX_SUB; CX_DIV] THEN
+  REWRITE_TAC[COMPLEX_SUB_CTAN]);;
+
+let TAN_PI4 = prove
+ (`tan(pi / &4) = &1`,
+  REWRITE_TAC[tan; SIN_COS; REAL_ARITH `p / &2 - p / &4 = p / &4`] THEN
+  MATCH_MP_TAC REAL_DIV_REFL THEN REWRITE_TAC[COS_EQ_0; PI_NZ; REAL_FIELD
+   `p / &4 = (n + &1 / &2) * p <=> p = &0 \/ n = -- &1 / &4`] THEN
+  ONCE_REWRITE_TAC[CONJ_SYM] THEN REWRITE_TAC[UNWIND_THM2] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+   REAL_ABS_INTEGER_LEMMA)) THEN
+  REAL_ARITH_TAC);;
+
+let TAN_POS_PI2 = prove
+ (`!x. &0 < x /\ x < pi / &2 ==> &0 < tan x`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[tan] THEN
+  MATCH_MP_TAC REAL_LT_DIV THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SIN_POS_PI; MATCH_MP_TAC COS_POS_PI] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let TAN_POS_PI2_LE = prove
+ (`!x. &0 <= x /\ x < pi / &2 ==> &0 <= tan x`,
+  REWRITE_TAC[REAL_LE_LT] THEN MESON_TAC[TAN_0; TAN_POS_PI2]);;
+
+let COS_TAN = prove
+ (`!x. abs(x) < pi / &2 ==> cos(x) = &1 / sqrt(&1 + tan(x) pow 2)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(REAL_FIELD
+   `sqrt(s) pow 2 = s /\ c pow 2 * s = &1 /\ ~(&1 + c * sqrt s = &0)
+    ==> c = &1 / sqrt s`) THEN
+  SUBGOAL_THEN `&0 < &1 + tan x pow 2` ASSUME_TAC THENL
+   [MP_TAC(SPEC `tan x` REAL_LE_SQUARE) THEN REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_SIMP_TAC[SQRT_POW_2; REAL_LT_IMP_LE] THEN CONJ_TAC THENL
+   [REWRITE_TAC[tan] THEN
+    MATCH_MP_TAC(REAL_FIELD
+     `s pow 2 + c pow 2 = &1 /\ &0 < c
+      ==> c pow 2 * (&1 + (s / c) pow 2) = &1`) THEN
+    ASM_SIMP_TAC[SIN_CIRCLE; COS_POS_PI; REAL_BOUNDS_LT];
+    MATCH_MP_TAC(REAL_ARITH `&0 < x ==> ~(&1 + x = &0)`) THEN
+    ASM_SIMP_TAC[SIN_CIRCLE; COS_POS_PI; REAL_BOUNDS_LT; SQRT_POS_LT;
+                 REAL_LT_MUL]]);;
+
+let SIN_TAN = prove
+ (`!x. abs(x) < pi / &2 ==> sin(x) = tan(x) / sqrt(&1 + tan(x) pow 2)`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a / b = a * &1 / b`] THEN
+  ASM_SIMP_TAC[GSYM COS_TAN] THEN
+  ASM_SIMP_TAC[tan; REAL_DIV_RMUL; REAL_LT_IMP_NZ; COS_POS_PI;
+               REAL_BOUNDS_LT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Monotonicity theorems for the basic trig functions.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let SIN_MONO_LT = prove
+ (`!x y. --(pi / &2) <= x /\ x < y /\ y <= pi / &2 ==> sin(x) < sin(y)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_SUB_LT] THEN
+  REWRITE_TAC[REAL_SUB_SIN; REAL_ARITH `&0 < &2 * x <=> &0 < x`] THEN
+  MATCH_MP_TAC REAL_LT_MUL THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SIN_POS_PI; MATCH_MP_TAC COS_POS_PI] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let SIN_MONO_LE = prove
+ (`!x y. --(pi / &2) <= x /\ x <= y /\ y <= pi / &2 ==> sin(x) <= sin(y)`,
+  MESON_TAC[SIN_MONO_LT; REAL_LE_LT]);;
+
+let SIN_MONO_LT_EQ = prove
+ (`!x y. --(pi / &2) <= x /\ x <= pi / &2 /\ --(pi / &2) <= y /\ y <= pi / &2
+         ==> (sin(x) < sin(y) <=> x < y)`,
+  MESON_TAC[REAL_NOT_LE; SIN_MONO_LT; SIN_MONO_LE]);;
+
+let SIN_MONO_LE_EQ = prove
+ (`!x y. --(pi / &2) <= x /\ x <= pi / &2 /\ --(pi / &2) <= y /\ y <= pi / &2
+         ==> (sin(x) <= sin(y) <=> x <= y)`,
+  MESON_TAC[REAL_NOT_LE; SIN_MONO_LT; SIN_MONO_LE]);;
+
+let SIN_INJ_PI = prove
+ (`!x y. --(pi / &2) <= x /\ x <= pi / &2 /\
+         --(pi / &2) <= y /\ y <= pi / &2 /\
+         sin(x) = sin(y)
+         ==> x = y`,
+  REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN MESON_TAC[SIN_MONO_LE_EQ]);;
+
+let COS_MONO_LT = prove
+ (`!x y. &0 <= x /\ x < y /\ y <= pi ==> cos(y) < cos(x)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_SUB_LT] THEN
+  REWRITE_TAC[REAL_SUB_COS; REAL_ARITH `&0 < &2 * x <=> &0 < x`] THEN
+  MATCH_MP_TAC REAL_LT_MUL THEN CONJ_TAC THEN MATCH_MP_TAC SIN_POS_PI THEN
+  ASM_REAL_ARITH_TAC);;
+
+let COS_MONO_LE = prove
+ (`!x y. &0 <= x /\ x <= y /\ y <= pi ==> cos(y) <= cos(x)`,
+  MESON_TAC[COS_MONO_LT; REAL_LE_LT]);;
+
+let COS_MONO_LT_EQ = prove
+ (`!x y. &0 <= x /\ x <= pi /\ &0 <= y /\ y <= pi
+         ==> (cos(x) < cos(y) <=> y < x)`,
+  MESON_TAC[REAL_NOT_LE; COS_MONO_LT; COS_MONO_LE]);;
+
+let COS_MONO_LE_EQ = prove
+ (`!x y. &0 <= x /\ x <= pi /\ &0 <= y /\ y <= pi
+         ==> (cos(x) <= cos(y) <=> y <= x)`,
+  MESON_TAC[REAL_NOT_LE; COS_MONO_LT; COS_MONO_LE]);;
+
+let COS_INJ_PI = prove
+ (`!x y. &0 <= x /\ x <= pi /\ &0 <= y /\ y <= pi /\ cos(x) = cos(y)
+         ==> x = y`,
+  REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN MESON_TAC[COS_MONO_LE_EQ]);;
+
+let TAN_MONO_LT = prove
+ (`!x y. --(pi / &2) < x /\ x < y /\ y < pi / &2 ==> tan(x) < tan(y)`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC I [GSYM REAL_SUB_LT] THEN
+  SUBGOAL_THEN `&0 < cos(x) /\ &0 < cos(y)` STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC COS_POS_PI;
+    ASM_SIMP_TAC[REAL_LT_IMP_NZ; REAL_SUB_TAN] THEN
+    MATCH_MP_TAC REAL_LT_DIV THEN ASM_SIMP_TAC[REAL_LT_MUL] THEN
+    MATCH_MP_TAC SIN_POS_PI] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let TAN_MONO_LE = prove
+ (`!x y. --(pi / &2) < x /\ x <= y /\ y < pi / &2 ==> tan(x) <= tan(y)`,
+  REWRITE_TAC[REAL_LE_LT] THEN MESON_TAC[TAN_MONO_LT]);;
+
+let TAN_MONO_LT_EQ = prove
+ (`!x y. --(pi / &2) < x /\ x < pi / &2 /\ --(pi / &2) < y /\ y < pi / &2
+         ==> (tan(x) < tan(y) <=> x < y)`,
+  MESON_TAC[REAL_NOT_LE; TAN_MONO_LT; TAN_MONO_LE]);;
+
+let TAN_MONO_LE_EQ = prove
+ (`!x y. --(pi / &2) < x /\ x < pi / &2 /\ --(pi / &2) < y /\ y < pi / &2
+         ==> (tan(x) <= tan(y) <=> x <= y)`,
+  MESON_TAC[REAL_NOT_LE; TAN_MONO_LT; TAN_MONO_LE]);;
+
+let TAN_BOUND_PI2 = prove
+ (`!x. abs(x) < pi / &4 ==> abs(tan x) < &1`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM TAN_PI4] THEN
+  REWRITE_TAC[GSYM TAN_NEG; REAL_ARITH `abs(x) < a <=> --a < x /\ x < a`] THEN
+  CONJ_TAC THEN MATCH_MP_TAC TAN_MONO_LT THEN
+  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC);;
+
+let TAN_COT = prove
+ (`!x. tan(pi / &2 - x) = inv(tan x)`,
+  REWRITE_TAC[tan; SIN_SUB; COS_SUB; SIN_PI2; COS_PI2; REAL_INV_DIV] THEN
+  GEN_TAC THEN BINOP_TAC THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Approximation to pi.                                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let SIN_PI6_STRADDLE = prove
+ (`!a b. &0 <= a /\ a <= b /\ b <= &4 /\
+         sin(a / &6) <= &1 / &2 /\ &1 / &2 <= sin(b / &6)
+         ==> a <= pi /\ pi <= b`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(SPECL [`pi / &6`; `b / &6`] SIN_MONO_LE_EQ) THEN
+  MP_TAC(SPECL [`a / &6`; `pi / &6`] SIN_MONO_LE_EQ) THEN
+  ASM_REWRITE_TAC[SIN_PI6] THEN
+  SUBGOAL_THEN `!x. &0 < x /\ x < &7 / &5 ==> &0 < sin x`
+  MP_TAC THENL
+   [REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`0`; `Cx(x)`] TAYLOR_CSIN) THEN
+    REWRITE_TAC[VSUM_SING_NUMSEG] THEN CONV_TAC NUM_REDUCE_CONV THEN
+    REWRITE_TAC[COMPLEX_DIV_1; COMPLEX_POW_1; complex_pow] THEN
+    REWRITE_TAC[COMPLEX_MUL_LID; GSYM CX_SIN; GSYM CX_SUB] THEN
+    REWRITE_TAC[IM_CX; COMPLEX_NORM_CX; REAL_ABS_NUM; REAL_EXP_0] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `e + d < a ==> abs(s - a) <= d ==> e < s`) THEN
+    ASM_SIMP_TAC[real_abs; real_pow; REAL_MUL_LID; REAL_LT_IMP_LE] THEN
+    SIMP_TAC[REAL_ARITH `&0 + x pow 3 / &2 < x <=> x * x pow 2 < x * &2`] THEN
+    ASM_SIMP_TAC[REAL_LT_LMUL_EQ] THEN
+    MATCH_MP_TAC REAL_LT_TRANS THEN EXISTS_TAC `(&7 / &5) pow 2` THEN
+    ASM_SIMP_TAC[REAL_POW_LT2; ARITH_EQ; REAL_LT_IMP_LE] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV;
+    DISCH_THEN(MP_TAC o SPEC `pi`) THEN
+    SIMP_TAC[SIN_PI; REAL_LT_REFL; PI_POS; REAL_NOT_LT] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let PI_APPROX_32 = prove
+ (`abs(pi - &13493037705 / &4294967296) <= inv(&2 pow 32)`,
+  REWRITE_TAC[REAL_ARITH `abs(x - a) <= e <=> a - e <= x /\ x <= a + e`] THEN
+  MATCH_MP_TAC SIN_PI6_STRADDLE THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  CONJ_TAC THENL
+   [MP_TAC(SPECL [`5`; `Cx(&1686629713 / &3221225472)`] TAYLOR_CSIN);
+    MP_TAC(SPECL [`5`; `Cx(&6746518853 / &12884901888)`] TAYLOR_CSIN)] THEN
+  CONV_TAC(ONCE_DEPTH_CONV EXPAND_VSUM_CONV) THEN CONV_TAC NUM_REDUCE_CONV THEN
+  REWRITE_TAC[GSYM CX_POW; GSYM CX_DIV; GSYM CX_ADD; GSYM CX_SUB;
+              GSYM CX_NEG; GSYM CX_MUL; GSYM CX_SIN; COMPLEX_NORM_CX] THEN
+  REWRITE_TAC[IM_CX; REAL_ABS_NUM; REAL_EXP_0] THEN REAL_ARITH_TAC);;
+
+let PI2_BOUNDS = prove
+ (`&0 < pi / &2 /\ pi / &2 < &2`,
+  MP_TAC PI_APPROX_32 THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex logarithms (the conventional principal value).                    *)
+(* ------------------------------------------------------------------------- *)
+
+let clog = new_definition
+ `clog z = @w. cexp(w) = z /\ --pi < Im(w) /\ Im(w) <= pi`;;
+
+let EXISTS_COMPLEX' = prove
+ (`!P. (?z. P (Re z) (Im z)) <=> ?x y. P x y`,
+  MESON_TAC[RE; IM; COMPLEX]);;
+
+let CLOG_WORKS = prove
+ (`!z. ~(z = Cx(&0))
+       ==> cexp(clog z) = z /\ --pi < Im(clog z) /\ Im(clog z) <= pi`,
+  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[clog] THEN CONV_TAC SELECT_CONV THEN
+  MP_TAC(SPEC `z / Cx(norm z)` COMPLEX_UNIMODULAR_POLAR) THEN ANTS_TAC THENL
+   [ASM_SIMP_TAC[COMPLEX_NORM_DIV; COMPLEX_NORM_CX] THEN
+    ASM_SIMP_TAC[REAL_ABS_NORM; REAL_DIV_REFL; COMPLEX_NORM_ZERO];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `x:real` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPEC `x:real` SINCOS_PRINCIPAL_VALUE) THEN
+  DISCH_THEN(X_CHOOSE_THEN `y:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `complex(log(norm(z:complex)),y)` THEN
+  ASM_REWRITE_TAC[RE; IM; CEXP_COMPLEX] THEN
+  REPEAT(FIRST_X_ASSUM(SUBST_ALL_TAC o SYM)) THEN
+  ASM_SIMP_TAC[EXP_LOG; COMPLEX_NORM_NZ; COMPLEX_DIV_LMUL;
+               COMPLEX_NORM_ZERO; CX_INJ]);;
+
+let CEXP_CLOG = prove
+ (`!z. ~(z = Cx(&0)) ==> cexp(clog z) = z`,
+  SIMP_TAC[CLOG_WORKS]);;
+
+let CLOG_CEXP = prove
+ (`!z. --pi < Im(z) /\ Im(z) <= pi ==> clog(cexp z) = z`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[clog] THEN
+  MATCH_MP_TAC SELECT_UNIQUE THEN X_GEN_TAC `w:complex` THEN
+  EQ_TAC THEN ASM_SIMP_TAC[] THEN REWRITE_TAC[CEXP_EQ] THEN
+  REWRITE_TAC[IMP_CONJ] THEN DISCH_THEN(X_CHOOSE_THEN `n:real`
+    (CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC)) THEN
+  REWRITE_TAC[IM_ADD; IM_MUL_II; RE_CX] THEN REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `n = &0` THEN ASM_REWRITE_TAC[REAL_MUL_LZERO] THEN
+  REWRITE_TAC[REAL_MUL_RZERO; COMPLEX_ADD_RID; COMPLEX_MUL_LZERO] THEN
+  SUBGOAL_THEN `abs(n * pi) < &1 * pi` MP_TAC THENL
+   [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_SIMP_TAC[REAL_ABS_MUL; REAL_LT_RMUL_EQ; PI_POS; REAL_ABS_PI] THEN
+  ASM_MESON_TAC[REAL_ABS_INTEGER_LEMMA; REAL_NOT_LT]);;
+
+let CLOG_EQ = prove
+ (`!w z. ~(w = Cx(&0)) /\ ~(z = Cx(&0)) ==> (clog w = clog z <=> w = z)`,
+  MESON_TAC[CEXP_CLOG]);;
+
+let CLOG_UNIQUE = prove
+ (`!w z. --pi < Im(z) /\ Im(z) <= pi /\ cexp(z) = w ==> clog w = z`,
+  MESON_TAC[CLOG_CEXP]);;
+
+let RE_CLOG = prove
+ (`!z. ~(z = Cx(&0)) ==> Re(clog z) = log(norm z)`,
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM
+   (MP_TAC o AP_TERM `norm:complex->real` o MATCH_MP CEXP_CLOG) THEN
+  REWRITE_TAC[NORM_CEXP] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[LOG_EXP]);;
+
+let EXISTS_COMPLEX_ROOT = prove
+ (`!a n. ~(n = 0) ==> ?z. z pow n = a`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `a = Cx(&0)` THENL
+   [EXISTS_TAC `Cx(&0)` THEN ASM_REWRITE_TAC[COMPLEX_POW_ZERO];
+    EXISTS_TAC `cexp(clog(a) / Cx(&n))` THEN REWRITE_TAC[GSYM CEXP_N] THEN
+    ASM_SIMP_TAC[COMPLEX_DIV_LMUL; CX_INJ; REAL_OF_NUM_EQ; CEXP_CLOG]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Derivative of clog away from the branch cut.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let HAS_COMPLEX_DERIVATIVE_CLOG = prove
+ (`!z. (Im(z) = &0 ==> &0 < Re(z))
+       ==> (clog has_complex_derivative inv(z)) (at z)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_INVERSE_STRONG_X THEN
+  EXISTS_TAC `cexp` THEN
+  EXISTS_TAC `{w | --pi < Im(w) /\ Im(w) < pi}` THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  ASM_CASES_TAC `z = Cx(&0)` THENL
+   [FIRST_X_ASSUM SUBST_ALL_TAC THEN POP_ASSUM MP_TAC THEN
+     ASM_REWRITE_TAC[RE_CX; IM_CX; REAL_LT_REFL];
+     ALL_TAC] THEN
+  ASM_SIMP_TAC[CONTINUOUS_ON_CEXP; CEXP_CLOG; CLOG_CEXP; REAL_LT_IMP_LE] THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[SET_RULE `{x | p x /\ q x} = {x | p x} INTER {x | q x}`] THEN
+    MATCH_MP_TAC OPEN_INTER THEN
+    REWRITE_TAC[REAL_ARITH `--x < w <=> w > --x`] THEN
+    REWRITE_TAC[OPEN_HALFSPACE_IM_LT; OPEN_HALFSPACE_IM_GT];
+    ASM_SIMP_TAC[CLOG_WORKS];
+    ASM_SIMP_TAC[CLOG_WORKS; REAL_LT_LE] THEN
+    DISCH_THEN(fun th ->
+      FIRST_X_ASSUM(SUBST_ALL_TAC o SYM o MATCH_MP CEXP_CLOG) THEN
+      POP_ASSUM MP_TAC THEN ASSUME_TAC th) THEN
+    ASM_REWRITE_TAC[EULER; COS_PI; SIN_PI; COMPLEX_MUL_RZERO] THEN
+    REWRITE_TAC[COMPLEX_ADD_RID; CX_NEG; COMPLEX_MUL_RNEG] THEN
+    REWRITE_TAC[COMPLEX_MUL_RID; IM_NEG; IM_CX; RE_NEG; RE_CX] THEN
+    MP_TAC(SPEC `Re(clog z)` REAL_EXP_POS_LT) THEN REAL_ARITH_TAC;
+    ASM_MESON_TAC[HAS_COMPLEX_DERIVATIVE_CEXP; CEXP_CLOG]]);;
+
+let COMPLEX_DIFFERENTIABLE_AT_CLOG = prove
+ (`!z. (Im(z) = &0 ==> &0 < Re(z)) ==> clog complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CLOG]);;
+
+let COMPLEX_DIFFERENTIABLE_WITHIN_CLOG = prove
+ (`!s z. (Im(z) = &0 ==> &0 < Re(z))
+         ==> clog complex_differentiable (at z within s)`,
+  MESON_TAC[COMPLEX_DIFFERENTIABLE_AT_WITHIN;
+            COMPLEX_DIFFERENTIABLE_AT_CLOG]);;
+
+add_complex_differentiation_theorems
+ (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+   (MATCH_MP HAS_COMPLEX_DERIVATIVE_CHAIN
+             HAS_COMPLEX_DERIVATIVE_CLOG)));;
+
+let CONTINUOUS_AT_CLOG = prove
+ (`!z. (Im(z) = &0 ==> &0 < Re(z)) ==> clog continuous at z`,
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CLOG;
+            HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT]);;
+
+let CONTINUOUS_WITHIN_CLOG = prove
+ (`!s z. (Im(z) = &0 ==> &0 < Re(z)) ==> clog continuous (at z within s)`,
+  MESON_TAC[CONTINUOUS_AT_WITHIN; CONTINUOUS_AT_CLOG]);;
+
+let CONTINUOUS_ON_CLOG = prove
+ (`!s. (!z. z IN s /\ Im(z) = &0 ==> &0 < Re(z)) ==> clog continuous_on s`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON; CONTINUOUS_AT_CLOG]);;
+
+let HOLOMORPHIC_ON_CLOG = prove
+ (`!s. (!z. z IN s /\ Im(z) = &0 ==> &0 < Re(z)) ==> clog holomorphic_on s`,
+  REWRITE_TAC [holomorphic_on] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HAS_COMPLEX_DERIVATIVE_CLOG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relation to real log.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let CX_LOG = prove
+ (`!z. &0 < z ==> Cx(log z) = clog(Cx z)`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(fun th ->
+   GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV)
+     [SYM(MATCH_MP EXP_LOG th)]) THEN
+  REWRITE_TAC[CX_EXP] THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC CLOG_CEXP THEN REWRITE_TAC[IM_CX] THEN
+  MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Quadrant-type results for clog.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let RE_CLOG_POS_LT = prove
+ (`!z. ~(z = Cx(&0)) ==> (abs(Im(clog z)) < pi / &2 <=> &0 < Re(z))`,
+  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP CLOG_WORKS) THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+    (fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [SYM th])
+    MP_TAC) THEN
+  SIMP_TAC[RE_CEXP; REAL_LT_MUL_EQ; REAL_EXP_POS_LT] THEN
+  SPEC_TAC(`clog z`,`z:complex`) THEN GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+   `--p < x /\ x <= p
+    ==> --(p / &2) < x /\ x < p / &2 \/
+        --(p / &2) <= p + x /\ p + x <= p / &2 \/
+        --(p / &2) <= x - p /\ x - p <= p / &2`)) THEN
+  DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC) THEN
+  (FIRST_ASSUM(MP_TAC o MATCH_MP COS_POS_PI) ORELSE
+   FIRST_ASSUM(MP_TAC o MATCH_MP COS_POS_PI_LE)) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[COS_ADD; COS_SUB; COS_PI; SIN_PI] THEN
+  REAL_ARITH_TAC);;
+
+let RE_CLOG_POS_LE = prove
+ (`!z. ~(z = Cx(&0)) ==> (abs(Im(clog z)) <= pi / &2 <=> &0 <= Re(z))`,
+  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP CLOG_WORKS) THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+    (fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [SYM th])
+    MP_TAC) THEN
+  SIMP_TAC[RE_CEXP; REAL_LE_MUL_EQ; REAL_EXP_POS_LT] THEN
+  SPEC_TAC(`clog z`,`z:complex`) THEN GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+   `--p < x /\ x <= p
+    ==> --(p / &2) <= x /\ x <= p / &2 \/
+        --(p / &2) < p + x /\ p + x < p / &2 \/
+        --(p / &2) < x - p /\ x - p < p / &2`)) THEN
+  DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC) THEN
+  (FIRST_ASSUM(MP_TAC o MATCH_MP COS_POS_PI) ORELSE
+   FIRST_ASSUM(MP_TAC o MATCH_MP COS_POS_PI_LE)) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[COS_ADD; COS_SUB; COS_PI; SIN_PI] THEN
+  REAL_ARITH_TAC);;
+
+let IM_CLOG_POS_LT = prove
+ (`!z. ~(z = Cx(&0)) ==> (&0 < Im(clog z) /\ Im(clog z) < pi <=> &0 < Im(z))`,
+  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP CLOG_WORKS) THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+    (fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [SYM th])
+    MP_TAC) THEN
+  SIMP_TAC[IM_CEXP; REAL_LT_MUL_EQ; REAL_EXP_POS_LT] THEN
+  SPEC_TAC(`clog z`,`z:complex`) THEN GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+   `--p < x /\ x <= p
+    ==> &0 < x /\ x < p \/
+        &0 <= x + p /\ x + p <= p \/
+        &0 <= x - p /\ x - p <= p`)) THEN
+  DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC) THEN
+  (FIRST_ASSUM(MP_TAC o MATCH_MP SIN_POS_PI) ORELSE
+   FIRST_ASSUM(MP_TAC o MATCH_MP SIN_POS_PI_LE)) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[SIN_ADD; SIN_SUB; COS_PI; SIN_PI] THEN
+  REAL_ARITH_TAC);;
+
+let IM_CLOG_POS_LE = prove
+ (`!z. ~(z = Cx(&0)) ==> (&0 <= Im(clog z) <=> &0 <= Im(z))`,
+  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP CLOG_WORKS) THEN
+  DISCH_THEN(CONJUNCTS_THEN2
+    (fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [SYM th])
+    MP_TAC) THEN
+  SIMP_TAC[IM_CEXP; REAL_LE_MUL_EQ; REAL_EXP_POS_LT] THEN
+  SPEC_TAC(`clog z`,`z:complex`) THEN GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH
+   `--p < x /\ x <= p
+    ==> &0 <= x /\ x <= p \/
+        &0 < x + p /\ x + p < p \/
+        &0 < p - x /\ p - x < p`)) THEN
+  DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC) THEN
+  (FIRST_ASSUM(MP_TAC o MATCH_MP SIN_POS_PI) ORELSE
+   FIRST_ASSUM(MP_TAC o MATCH_MP SIN_POS_PI_LE)) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[SIN_ADD; SIN_SUB; COS_PI; SIN_PI] THEN
+  REAL_ARITH_TAC);;
+
+let RE_CLOG_POS_LT_IMP = prove
+ (`!z. &0 < Re(z) ==> abs(Im(clog z)) < pi / &2`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THEN
+  ASM_SIMP_TAC[RE_CLOG_POS_LT; RE_CX; REAL_LT_REFL]);;
+
+let IM_CLOG_POS_LT_IMP = prove
+ (`!z. &0 < Im(z) ==> &0 < Im(clog z) /\ Im(clog z) < pi`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THEN
+  ASM_SIMP_TAC[IM_CLOG_POS_LT; IM_CX; REAL_LT_REFL]);;
+
+let IM_CLOG_EQ_0 = prove
+ (`!z. ~(z = Cx(&0)) ==> (Im(clog z) = &0 <=> &0 < Re(z) /\ Im(z) = &0)`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV)
+   [REAL_ARITH `z = &0 <=> &0 <= z /\ ~(&0 < z)`] THEN
+  ASM_SIMP_TAC[GSYM RE_CLOG_POS_LT; GSYM IM_CLOG_POS_LE;
+               GSYM IM_CLOG_POS_LT] THEN
+  MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+let IM_CLOG_EQ_PI = prove
+ (`!z. ~(z = Cx(&0)) ==> (Im(clog z) = pi <=> Re(z) < &0 /\ Im(z) = &0)`,
+  SIMP_TAC[PI_POS; RE_CLOG_POS_LE; IM_CLOG_POS_LE; IM_CLOG_POS_LT; CLOG_WORKS;
+           REAL_ARITH `&0 < pi ==> (x = pi <=> (&0 <= x /\ x <= pi) /\
+                            ~(abs x <= pi / &2) /\ ~(&0 < x /\ x < pi))`] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Various properties.                                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let CNJ_CLOG = prove
+ (`!z. (Im z = &0 ==> &0 < Re z) ==> cnj(clog z) = clog(cnj z)`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THEN
+  ASM_REWRITE_TAC[RE_CX; IM_CX; REAL_LT_REFL] THEN
+  DISCH_TAC THEN MATCH_MP_TAC COMPLEX_EQ_CEXP THEN
+  REWRITE_TAC[GSYM CNJ_CEXP] THEN
+  ASM_SIMP_TAC[CEXP_CLOG; CNJ_EQ_CX; IM_CNJ] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `(--p < x /\ x <= p) /\ (--p < y /\ y <= p) /\
+    ~(x = p /\ y = p)
+    ==> abs(--x - y) < &2 * p`) THEN
+  ASM_SIMP_TAC[IM_CLOG_EQ_PI; CNJ_EQ_CX; CLOG_WORKS] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let CLOG_INV = prove
+ (`!z. (Im(z) = &0 ==> &0 < Re z) ==> clog(inv z) = --(clog z)`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THEN
+  ASM_REWRITE_TAC[RE_CX; IM_CX; REAL_LT_REFL] THEN
+  STRIP_TAC THEN MATCH_MP_TAC COMPLEX_EQ_CEXP THEN
+  ASM_SIMP_TAC[CEXP_CLOG; CEXP_NEG; COMPLEX_INV_EQ_0] THEN
+  REWRITE_TAC[IM_NEG; REAL_SUB_RNEG] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `--pi < x /\ x <= pi /\ --pi < y /\ y <= pi /\
+    ~(x = pi /\ y = pi) ==> abs(x + y) < &2 * pi`) THEN
+  ASM_SIMP_TAC[CLOG_WORKS; COMPLEX_INV_EQ_0; IM_CLOG_EQ_PI] THEN
+  UNDISCH_TAC `Im z = &0 ==> &0 < Re z` THEN
+  ASM_CASES_TAC `Im z = &0` THEN ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
+
+let CLOG_1 = prove
+ (`clog(Cx(&1)) = Cx(&0)`,
+  REWRITE_TAC[GSYM CEXP_0] THEN MATCH_MP_TAC CLOG_CEXP THEN
+  REWRITE_TAC[IM_CX] THEN MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+let CLOG_NEG_1 = prove
+ (`clog(--Cx(&1)) = ii * Cx pi`,
+  MATCH_MP_TAC COMPLEX_EQ_CEXP THEN REWRITE_TAC[GSYM CX_NEG] THEN
+  SIMP_TAC[CEXP_EULER; GSYM CX_COS; GSYM CX_SIN; IM_MUL_II; IM_CX; RE_CX] THEN
+  REWRITE_TAC[COS_PI; SIN_PI; COMPLEX_MUL_RZERO; COMPLEX_ADD_RID] THEN
+  SIMP_TAC[CLOG_WORKS; COMPLEX_RING `~(Cx(-- &1) = Cx(&0))`;
+           REAL_ARITH `--pi < x /\ x <= pi ==> abs(x - pi) < &2 * pi`]);;
+
+let CLOG_II = prove
+ (`clog ii = ii * Cx(pi / &2)`,
+  MP_TAC(SPEC `ii * Cx(pi / &2)` CLOG_CEXP) THEN
+  SIMP_TAC[CEXP_EULER; GSYM CX_COS; GSYM CX_SIN; IM_MUL_II; IM_CX; RE_CX] THEN
+  REWRITE_TAC[COS_PI2; SIN_PI2] THEN ANTS_TAC THENL
+   [MP_TAC PI_POS THEN REAL_ARITH_TAC;
+    REWRITE_TAC[COMPLEX_ADD_LID; COMPLEX_MUL_RID]]);;
+
+let CLOG_NEG_II = prove
+ (`clog(--ii) = --ii * Cx(pi / &2)`,
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [COMPLEX_FIELD `--ii = inv ii`] THEN
+  SIMP_TAC[CLOG_INV; RE_II; IM_II; REAL_OF_NUM_EQ; ARITH; CLOG_II] THEN
+  REWRITE_TAC[COMPLEX_MUL_LNEG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relation between square root and exp/log, and hence its derivative.       *)
+(* ------------------------------------------------------------------------- *)
+
+let CSQRT_CEXP_CLOG = prove
+ (`!z. ~(z = Cx(&0)) ==> csqrt z = cexp(clog(z) / Cx(&2))`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CSQRT_UNIQUE THEN
+  REWRITE_TAC[GSYM CEXP_N; RE_CEXP; IM_CEXP] THEN
+  ASM_SIMP_TAC[COMPLEX_DIV_LMUL; CX_INJ; REAL_OF_NUM_EQ; ARITH; CEXP_CLOG] THEN
+  SIMP_TAC[REAL_LT_MUL_EQ; REAL_EXP_POS_LT; REAL_LE_MUL_EQ] THEN
+  REWRITE_TAC[REAL_ENTIRE; REAL_EXP_NZ; IM_DIV_CX] THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o CONJUNCT2 o MATCH_MP CLOG_WORKS) THEN
+  FIRST_X_ASSUM(DISJ_CASES_TAC o REWRITE_RULE[REAL_LE_LT]) THENL
+   [DISJ1_TAC THEN MATCH_MP_TAC COS_POS_PI THEN
+    ASM_REAL_ARITH_TAC;
+    DISJ2_TAC THEN ASM_REWRITE_TAC[COS_PI2; SIN_PI2; REAL_POS]]);;
+
+let CNJ_CSQRT = prove
+ (`!z. (Im z = &0 ==> &0 <= Re(z)) ==> cnj(csqrt z) = csqrt(cnj z)`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THEN
+  ASM_REWRITE_TAC[CSQRT_0; CNJ_CX] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `Im z = &0 ==> &0 < Re(z)` ASSUME_TAC THENL
+   [REPEAT(POP_ASSUM MP_TAC) THEN
+    REWRITE_TAC[COMPLEX_EQ; IM_CX; RE_CX] THEN REAL_ARITH_TAC;
+    ASM_REWRITE_TAC[RE_CX; IM_CX; REAL_LT_REFL] THEN
+    ASM_SIMP_TAC[CSQRT_CEXP_CLOG; CNJ_CEXP; CNJ_CLOG;
+                 CNJ_DIV; CNJ_EQ_CX; CNJ_CX]]);;
+
+let HAS_COMPLEX_DERIVATIVE_CSQRT = prove
+ (`!z. (Im z = &0 ==> &0 < Re(z))
+       ==> (csqrt has_complex_derivative inv(Cx(&2) * csqrt z)) (at z)`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THEN
+  ASM_REWRITE_TAC[IM_CX; RE_CX; REAL_LT_REFL] THEN DISCH_TAC THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_AT THEN
+  MAP_EVERY EXISTS_TAC [`\z. cexp(clog(z) / Cx(&2))`; `norm(z:complex)`] THEN
+  ASM_REWRITE_TAC[COMPLEX_NORM_NZ] THEN CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+    MATCH_MP_TAC CSQRT_CEXP_CLOG THEN REWRITE_TAC[GSYM COMPLEX_VEC_0] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN NORM_ARITH_TAC;
+    COMPLEX_DIFF_TAC THEN ASM_SIMP_TAC[GSYM CSQRT_CEXP_CLOG] THEN
+    UNDISCH_TAC `~(z = Cx(&0))` THEN MP_TAC(SPEC `z:complex` CSQRT) THEN
+    CONV_TAC COMPLEX_FIELD]);;
+
+let COMPLEX_DIFFERENTIABLE_AT_CSQRT = prove
+ (`!z. (Im z = &0 ==> &0 < Re(z)) ==> csqrt complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CSQRT]);;
+
+let COMPLEX_DIFFERENTIABLE_WITHIN_CSQRT = prove
+ (`!s z. (Im z = &0 ==> &0 < Re(z))
+         ==> csqrt complex_differentiable (at z within s)`,
+  MESON_TAC[COMPLEX_DIFFERENTIABLE_AT_WITHIN;
+            COMPLEX_DIFFERENTIABLE_AT_CSQRT]);;
+
+add_complex_differentiation_theorems
+ (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+   (MATCH_MP HAS_COMPLEX_DERIVATIVE_CHAIN
+             HAS_COMPLEX_DERIVATIVE_CSQRT)));;
+
+let CONTINUOUS_AT_CSQRT = prove
+ (`!z. (Im z = &0 ==> &0 < Re(z)) ==> csqrt continuous at z`,
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CSQRT;
+            HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT]);;
+
+let CONTINUOUS_WITHIN_CSQRT = prove
+ (`!s z. (Im z = &0 ==> &0 < Re(z)) ==> csqrt continuous (at z within s)`,
+  MESON_TAC[CONTINUOUS_AT_WITHIN; CONTINUOUS_AT_CSQRT]);;
+
+let CONTINUOUS_ON_CSQRT = prove
+ (`!s. (!z. z IN s /\ Im z = &0 ==> &0 < Re(z)) ==> csqrt continuous_on s`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON; CONTINUOUS_AT_CSQRT]);;
+
+let HOLOMORPHIC_ON_CSQRT = prove
+ (`!s. (!z. z IN s /\ Im(z) = &0 ==> &0 < Re(z)) ==> csqrt holomorphic_on s`,
+  REWRITE_TAC [holomorphic_on] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HAS_COMPLEX_DERIVATIVE_CSQRT]);;
+
+let CONTINUOUS_WITHIN_CSQRT_POSREAL = prove
+ (`!z. csqrt continuous (at z within {w | real w /\ &0 <= Re(w)})`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `Im z = &0 ==> &0 < Re(z)` THENL
+   [ASM_SIMP_TAC[CONTINUOUS_WITHIN_CSQRT]; ALL_TAC] THEN
+  POP_ASSUM MP_TAC THEN REWRITE_TAC[NOT_IMP; REAL_NOT_LT] THEN
+  REWRITE_TAC[REAL_ARITH `x <= &0 <=> x < &0 \/ x = &0`] THEN STRIP_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_WITHIN_CLOSED_NONTRIVIAL THEN
+    REWRITE_TAC[SET_RULE `{x | P x /\ Q x} = {x | P x} INTER {x | Q x}`] THEN
+    SIMP_TAC[CLOSED_REAL_SET; CLOSED_INTER; IN_INTER; IN_ELIM_THM;
+             REWRITE_RULE[real_ge] CLOSED_HALFSPACE_RE_GE] THEN
+    ASM_REAL_ARITH_TAC;
+    SUBGOAL_THEN `z = Cx(&0)` SUBST_ALL_TAC THENL
+     [ASM_REWRITE_TAC[COMPLEX_EQ; RE_CX; IM_CX]; ALL_TAC] THEN
+    REWRITE_TAC[continuous_within] THEN
+    REWRITE_TAC[IN_ELIM_THM; IMP_CONJ; FORALL_REAL; RE_CX] THEN
+    SIMP_TAC[GSYM CX_SQRT; REAL_LE_REFL] THEN
+    SIMP_TAC[dist; GSYM CX_SUB; COMPLEX_NORM_CX; SQRT_0; REAL_SUB_RZERO] THEN
+    X_GEN_TAC `e:real` THEN STRIP_TAC THEN EXISTS_TAC `(e:real) pow 2` THEN
+    ASM_SIMP_TAC[REAL_POW_LT] THEN REPEAT STRIP_TAC THEN
+    SUBGOAL_THEN `e = sqrt(e pow 2)` SUBST1_TAC THENL
+     [ASM_SIMP_TAC[POW_2_SQRT; REAL_LT_IMP_LE];
+      ASM_SIMP_TAC[real_abs; SQRT_POS_LE]] THEN
+    MATCH_MP_TAC SQRT_MONO_LT THEN ASM_REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex powers.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("cpow",(24,"left"));;
+
+let cpow = new_definition
+ `w cpow z = if w = Cx(&0) then Cx(&0)
+             else cexp(z * clog w)`;;
+
+let CPOW_0 = prove
+ (`!z. Cx(&0) cpow z = Cx(&0)`,
+  REWRITE_TAC[cpow]);;
+
+let CPOW_N = prove
+ (`!z. z cpow (Cx(&n)) = if z = Cx(&0) then Cx(&0) else z pow n`,
+  GEN_TAC THEN REWRITE_TAC[cpow] THEN COND_CASES_TAC THEN
+  ASM_SIMP_TAC[CEXP_N; CEXP_CLOG]);;
+
+let CPOW_1 = prove
+ (`!z. Cx(&1) cpow z = Cx(&1)`,
+  REWRITE_TAC[cpow; CX_INJ; REAL_OF_NUM_EQ; ARITH_EQ; CLOG_1] THEN
+  REWRITE_TAC[CEXP_0; COMPLEX_MUL_RZERO]);;
+
+let CPOW_ADD = prove
+ (`!w z1 z2. w cpow (z1 + z2) = w cpow z1 * w cpow z2`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[cpow] THEN
+  ASM_CASES_TAC `w = Cx(&0)` THEN ASM_REWRITE_TAC[COMPLEX_MUL_RZERO] THEN
+  REWRITE_TAC[COMPLEX_ADD_RDISTRIB; CEXP_ADD]);;
+
+let CPOW_NEG = prove
+ (`!w z. w cpow (--z) = inv(w cpow z)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[cpow] THEN ASM_CASES_TAC `w = Cx(&0)` THEN
+  ASM_REWRITE_TAC[COMPLEX_MUL_RZERO; COMPLEX_INV_0] THEN
+  REWRITE_TAC[COMPLEX_MUL_LNEG; CEXP_NEG]);;
+
+let CPOW_SUB = prove
+ (`!w z1 z2. w cpow (z1 - z2) = w cpow z1 / w cpow z2`,
+  REWRITE_TAC[complex_sub; complex_div; CPOW_ADD; CPOW_NEG]);;
+
+let CPOW_EQ_0 = prove
+ (`!w z. w cpow z = Cx(&0) <=> w = Cx(&0)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[cpow] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[CEXP_NZ]);;
+
+let NORM_CPOW_REAL = prove
+ (`!w z. real w /\ &0 < Re w ==> norm(w cpow z) = exp(Re z * log(Re w))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(SUBST_ALL_TAC o SYM o GEN_REWRITE_RULE I [REAL]) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[RE_CX]) THEN
+  ASM_SIMP_TAC[cpow; CX_INJ; REAL_LT_IMP_NZ] THEN
+  ASM_SIMP_TAC[NORM_CEXP; GSYM CX_LOG; RE_MUL_CX; RE_CX]);;
+
+let CPOW_REAL_REAL = prove
+ (`!w z. real w /\ real z /\ &0 < Re w
+         ==> w cpow z = Cx(exp(Re z * log(Re w)))`,
+  REPEAT STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(SUBST_ALL_TAC o SYM o GEN_REWRITE_RULE I [REAL])) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[RE_CX]) THEN
+  ASM_SIMP_TAC[cpow; CX_INJ; REAL_LT_IMP_NZ] THEN
+  ASM_SIMP_TAC[NORM_CEXP; GSYM CX_LOG; RE_MUL_CX; RE_CX; CX_EXP; CX_MUL]);;
+
+let NORM_CPOW_REAL_MONO = prove
+ (`!w z1 z2. real w /\ &1 < Re w
+             ==> (norm(w cpow z1) <= norm(w cpow z2) <=> Re(z1) <= Re(z2))`,
+  SIMP_TAC[NORM_CPOW_REAL; REAL_ARITH `&1 < x ==> &0 < x`] THEN
+  SIMP_TAC[REAL_EXP_MONO_LE; REAL_LE_RMUL_EQ; LOG_POS_LT]);;
+
+let CPOW_MUL_REAL = prove
+ (`!x y z. real x /\ real y /\ &0 <= Re x /\ &0 <= Re y
+           ==> (x * y) cpow z = x cpow z * y cpow z`,
+  REPEAT STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(SUBST_ALL_TAC o SYM o GEN_REWRITE_RULE I [REAL])) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN REWRITE_TAC[RE_CX; IM_CX] THEN
+  REWRITE_TAC[REAL_ARITH `&0 <= x <=> x = &0 \/ &0 < x`] THEN
+  REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[COMPLEX_MUL_LZERO; COMPLEX_MUL_RZERO; CPOW_0] THEN
+  ASM_SIMP_TAC[cpow; COMPLEX_ENTIRE; CX_INJ; REAL_LT_IMP_NZ] THEN
+  REWRITE_TAC[GSYM CEXP_ADD; GSYM COMPLEX_ADD_LDISTRIB] THEN
+  ASM_SIMP_TAC[GSYM CX_LOG; GSYM CX_ADD; GSYM CX_MUL; REAL_LT_MUL] THEN
+  ASM_SIMP_TAC[LOG_MUL]);;
+
+let HAS_COMPLEX_DERIVATIVE_CPOW = prove
+ (`!s z. (Im z = &0 ==> &0 < Re z)
+         ==> ((\z. z cpow s) has_complex_derivative
+              (s * z cpow (s - Cx(&1)))) (at z)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THEN
+  ASM_REWRITE_TAC[IM_CX; RE_CX; REAL_LT_REFL] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[cpow] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_TRANSFORM_AT THEN
+  MAP_EVERY EXISTS_TAC [`\z. cexp (s * clog z)`; `norm(z:complex)`] THEN
+  ASM_REWRITE_TAC[COMPLEX_NORM_NZ] THEN CONJ_TAC THENL
+   [GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[dist] THEN
+    REWRITE_TAC[COMPLEX_SUB_LZERO; NORM_NEG; REAL_LT_REFL];
+    COMPLEX_DIFF_TAC THEN ASM_REWRITE_TAC[CEXP_SUB; COMPLEX_SUB_RDISTRIB] THEN
+    ASM_SIMP_TAC[CEXP_CLOG; COMPLEX_MUL_LID] THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC COMPLEX_FIELD]);;
+
+add_complex_differentiation_theorems
+ (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+   (GEN `s:complex`
+     (MATCH_MP HAS_COMPLEX_DERIVATIVE_CHAIN
+               (SPEC `s:complex` HAS_COMPLEX_DERIVATIVE_CPOW)))));;
+
+let HAS_COMPLEX_DERIVATIVE_CPOW_RIGHT = prove
+ (`!w z. ~(w = Cx(&0))
+         ==> ((\z. w cpow z) has_complex_derivative clog(w) * w cpow z) (at z)`,
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[cpow] THEN
+  COMPLEX_DIFF_TAC THEN REWRITE_TAC[COMPLEX_MUL_LID]);;
+
+add_complex_differentiation_theorems
+ (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+   (GEN `s:complex`
+     (MATCH_MP HAS_COMPLEX_DERIVATIVE_CHAIN
+               (SPEC `s:complex` HAS_COMPLEX_DERIVATIVE_CPOW_RIGHT)))));;
+
+let COMPLEX_DIFFERENTIABLE_CPOW_RIGHT = prove
+ (`!w z. ~(w = Cx(&0)) ==> (\z. w cpow z) complex_differentiable (at z)`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CPOW_RIGHT]);;
+
+let HOLOMORPHIC_ON_CPOW_RIGHT = prove
+ (`!w f s. ~(w = Cx(&0)) /\ f holomorphic_on s
+           ==> (\z. w cpow (f z)) holomorphic_on s`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM o_DEF] THEN
+  MATCH_MP_TAC HOLOMORPHIC_ON_COMPOSE THEN ASM_REWRITE_TAC[] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN
+  REWRITE_TAC[holomorphic_on; GSYM complex_differentiable] THEN
+  ASM_SIMP_TAC[COMPLEX_DIFFERENTIABLE_CPOW_RIGHT;
+               COMPLEX_DIFFERENTIABLE_AT_WITHIN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Product rule.                                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let CLOG_MUL = prove
+ (`!w z. ~(w = Cx(&0)) /\ ~(z = Cx(&0))
+           ==> clog(w * z) =
+                if Im(clog w + clog z) <= --pi then
+                  (clog(w) + clog(z)) + ii * Cx(&2 * pi)
+                else if Im(clog w + clog z) > pi then
+                  (clog(w) + clog(z)) - ii * Cx(&2 * pi)
+                else clog(w) + clog(z)`,
+  REPEAT STRIP_TAC THEN
+  REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+  MATCH_MP_TAC CLOG_UNIQUE THEN
+  ASM_SIMP_TAC[CEXP_ADD; CEXP_SUB; CEXP_EULER; CEXP_CLOG; CONJ_ASSOC;
+               GSYM CX_SIN; GSYM CX_COS; COS_NPI; SIN_NPI] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  TRY(CONJ_TAC THENL [ALL_TAC; CONV_TAC COMPLEX_FIELD]) THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o MATCH_MP CLOG_WORKS)) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[IM_ADD; IM_SUB; IM_MUL_II; RE_CX] THEN
+  REAL_ARITH_TAC);;
+
+let CLOG_MUL_SIMPLE = prove
+ (`!w z. ~(w = Cx(&0)) /\ ~(z = Cx(&0)) /\
+         --pi < Im(clog(w)) + Im(clog(z)) /\
+         Im(clog(w)) + Im(clog(z)) <= pi
+         ==> clog(w * z) = clog(w) + clog(z)`,
+  SIMP_TAC[CLOG_MUL; IM_ADD] THEN REAL_ARITH_TAC);;
+
+let CLOG_NEG = prove
+ (`!z. ~(z = Cx(&0))
+       ==> clog(--z) = if Im(z) <= &0 /\ ~(Re(z) < &0 /\ Im(z) = &0)
+                       then clog(z) + ii * Cx(pi)
+                       else clog(z) - ii * Cx(pi)`,
+  REPEAT STRIP_TAC THEN
+  SUBST1_TAC(SIMPLE_COMPLEX_ARITH `--z = --Cx(&1) * z`) THEN
+  ASM_SIMP_TAC[CLOG_MUL; COMPLEX_RING `~(--Cx(&1) = Cx(&0))`] THEN
+  REWRITE_TAC[CLOG_NEG_1; IM_ADD; IM_MUL_II; RE_CX] THEN
+  ASM_SIMP_TAC[CLOG_WORKS; REAL_ARITH
+   `--p < x /\ x <= p ==> ~(p + x <= --p)`] THEN
+  REWRITE_TAC[REAL_ARITH `p + x > p <=> &0 < x`] THEN
+  ASM_SIMP_TAC[GSYM IM_CLOG_EQ_PI] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `Im z <= &0 <=> ~(&0 < Im z)`] THEN
+  ASM_SIMP_TAC[GSYM IM_CLOG_POS_LT] THEN
+  ASM_SIMP_TAC[CLOG_WORKS; REAL_ARITH `x <= p ==> (x < p <=> ~(x = p))`] THEN
+  REWRITE_TAC[TAUT `~(a /\ ~b) /\ ~b <=> ~a /\ ~b`] THEN
+  ASM_CASES_TAC `Im(clog z) = pi` THEN ASM_REWRITE_TAC[PI_POS] THEN
+  ASM_CASES_TAC `&0 < Im(clog z)` THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[CX_MUL] THEN CONV_TAC COMPLEX_RING);;
+
+let CLOG_MUL_II = prove
+ (`!z. ~(z = Cx(&0))
+       ==> clog(ii * z) = if &0 <= Re(z) \/ Im(z) < &0
+                          then clog(z) + ii * Cx(pi / &2)
+                          else clog(z) - ii * Cx(&3 * pi / &2)`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[CLOG_MUL; II_NZ; CLOG_II] THEN
+  REWRITE_TAC[IM_ADD; IM_MUL_II; RE_CX] THEN
+  ASM_SIMP_TAC[CLOG_WORKS; REAL_ARITH
+   `--p < x /\ x <= p ==> ~(p / &2 + x <= --p)`] THEN
+  REWRITE_TAC[REAL_ARITH `p / &2 + x > p <=> p / &2 < x`] THEN
+  REWRITE_TAC[REAL_ARITH `Im z < &0 <=> ~(&0 <= Im z)`] THEN
+  ASM_SIMP_TAC[GSYM RE_CLOG_POS_LE; GSYM IM_CLOG_POS_LE] THEN
+  MATCH_MP_TAC(MESON[]
+   `(p <=> ~q) /\ x = a /\ y = b
+    ==> ((if p then x else y) = (if q then b else a))`) THEN
+  CONJ_TAC THENL
+   [MP_TAC PI_POS THEN REAL_ARITH_TAC;
+    REWRITE_TAC[CX_MUL; CX_DIV] THEN CONV_TAC COMPLEX_RING]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Unwinding number gives another version of log-product formula.            *)
+(* Note that in this special case the unwinding number is -1, 0 or 1.        *)
+(* ------------------------------------------------------------------------- *)
+
+let unwinding = new_definition
+ `unwinding(z) = (z - clog(cexp z)) / (Cx(&2 * pi) * ii)`;;
+
+let UNWINDING_2PI = prove
+ (`Cx(&2 * pi) * ii * unwinding(z) = z - clog(cexp z)`,
+  REWRITE_TAC[unwinding; COMPLEX_MUL_ASSOC] THEN
+  MATCH_MP_TAC COMPLEX_DIV_LMUL THEN
+  REWRITE_TAC[COMPLEX_ENTIRE; CX_INJ; II_NZ] THEN
+  MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+let CLOG_MUL_UNWINDING = prove
+ (`!w z. ~(w = Cx(&0)) /\ ~(z = Cx(&0))
+           ==> clog(w * z) =
+               clog(w) + clog(z) -
+               Cx(&2 * pi) * ii * unwinding(clog w + clog z)`,
+  REWRITE_TAC[UNWINDING_2PI;
+    COMPLEX_RING `w + z - ((w + z) - c) = c:complex`] THEN
+  ASM_SIMP_TAC[CEXP_ADD; CEXP_CLOG]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Complex arctangent (branch cut gives standard bounds in real case).       *)
+(* ------------------------------------------------------------------------- *)
+
+let catn = new_definition
+ `catn z = (ii / Cx(&2)) * clog((Cx(&1) - ii * z) / (Cx(&1) + ii * z))`;;
+
+let IM_COMPLEX_DIV_LEMMA = prove
+ (`!z. Im((Cx(&1) - ii * z) / (Cx(&1) + ii * z)) = &0 <=> Re z = &0`,
+  REWRITE_TAC[IM_COMPLEX_DIV_EQ_0] THEN
+  REWRITE_TAC[complex_mul;  IM; RE; IM_CNJ; RE_CNJ; RE_CX; IM_CX; RE_II; IM_II;
+              RE_SUB; RE_ADD; IM_SUB; IM_ADD] THEN
+  REAL_ARITH_TAC);;
+
+let RE_COMPLEX_DIV_LEMMA = prove
+ (`!z. &0 < Re((Cx(&1) - ii * z) / (Cx(&1) + ii * z)) <=> norm(z) < &1`,
+  REWRITE_TAC[RE_COMPLEX_DIV_GT_0; NORM_LT_SQUARE; REAL_LT_01] THEN
+  REWRITE_TAC[GSYM NORM_POW_2; COMPLEX_SQNORM] THEN
+  REWRITE_TAC[complex_mul;  IM; RE; IM_CNJ; RE_CNJ; RE_CX; IM_CX; RE_II; IM_II;
+              RE_SUB; RE_ADD; IM_SUB; IM_ADD] THEN
+  REAL_ARITH_TAC);;
+
+let CTAN_CATN = prove
+ (`!z. ~(z pow 2 = --Cx(&1)) ==> ctan(catn z) = z`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[catn; ctan; csin; ccos;
+              COMPLEX_RING `--i * i / Cx(&2) * z = --(i * i) / Cx(&2) * z`;
+              COMPLEX_RING `i * i / Cx(&2) * z =  (i * i) / Cx(&2) * z`] THEN
+  REWRITE_TAC[COMPLEX_POW_II_2; GSYM COMPLEX_POW_2] THEN
+  REWRITE_TAC[COMPLEX_RING `--Cx(&1) / Cx(&2) * x = --(Cx(&1) / Cx(&2) * x)`;
+              CEXP_NEG] THEN
+  SUBGOAL_THEN
+  `~(cexp(Cx(&1) / Cx(&2) *
+          (clog((Cx(&1) - ii * z) / (Cx(&1) + ii * z)))) pow 2 = --Cx(&1))`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[GSYM CEXP_N; CEXP_SUB; COMPLEX_RING
+     `Cx(&2) * Cx(&1) / Cx(&2) * z = z`] THEN
+    ASM_SIMP_TAC[CEXP_CLOG; COMPLEX_POW_II_2;
+      COMPLEX_FIELD `~(w = Cx(&0)) /\ ~(z = Cx(&0)) ==> ~(w / z = Cx(&0))`;
+      COMPLEX_FIELD `~(w = Cx(&0)) ==> (x / w = y <=> x = y * w)`;
+      COMPLEX_FIELD
+     `ii pow 2 = --Cx(&1) /\ ~(z pow 2 = --Cx(&1))
+      ==> ~(Cx(&1) - ii * z = Cx(&0)) /\ ~(Cx(&1) + ii * z = Cx(&0))`] THEN
+    POP_ASSUM MP_TAC THEN CONV_TAC COMPLEX_FIELD;
+    ALL_TAC] THEN
+  REWRITE_TAC[COMPLEX_RING `-- --Cx (&1) / Cx (&2) = Cx(&1) / Cx(&2)`] THEN
+  ASM_SIMP_TAC[CEXP_NZ; COMPLEX_FIELD
+    `~(z = Cx(&0)) /\ ~(z pow 2 = --Cx(&1))
+     ==> ((inv(z) - z) / (Cx(&2) * ii)) / ((inv(z) + z) / Cx(&2)) =
+         inv ii * ((Cx(&1) - z pow 2) / (Cx(&1) + z pow 2))`] THEN
+  ASM_SIMP_TAC[GSYM CEXP_N; CEXP_SUB;
+               COMPLEX_RING `Cx(&2) * Cx(&1) / Cx(&2) * z = z`] THEN
+  ASM_SIMP_TAC[CEXP_CLOG; COMPLEX_FIELD
+     `~(z pow 2 = --Cx(&1))
+      ==> ~((Cx(&1) - ii * z) / (Cx(&1) + ii * z) = Cx(&0))`] THEN
+  UNDISCH_TAC `~(z pow 2 = --Cx(&1))` THEN CONV_TAC COMPLEX_FIELD);;
+
+let CATN_CTAN = prove
+ (`!z. abs(Re z) < pi / &2 ==> catn(ctan z) = z`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[catn; ctan; csin; ccos] THEN
+  ASM_SIMP_TAC[COMPLEX_FIELD
+   `ii * (a / (Cx(&2) * ii)) / (b / Cx(&2)) = a / b`] THEN
+  SIMP_TAC[COMPLEX_FIELD
+   `ii / Cx(&2) * x = y <=> x = Cx(&2) * --(ii * y)`] THEN
+  SUBGOAL_THEN `~(cexp(ii * z) pow 2 = --Cx(&1))` ASSUME_TAC THENL
+   [SUBGOAL_THEN `--Cx(&1) = cexp(ii * Cx pi)` SUBST1_TAC THENL
+     [REWRITE_TAC[CEXP_EULER; GSYM CX_SIN; GSYM CX_COS; SIN_PI; COS_PI] THEN
+      CONV_TAC COMPLEX_RING;
+      ALL_TAC] THEN
+    REWRITE_TAC[GSYM CEXP_N; CEXP_EQ] THEN
+    DISCH_THEN(X_CHOOSE_THEN `n:real` STRIP_ASSUME_TAC) THEN
+    FIRST_X_ASSUM(MP_TAC o AP_TERM `Im`) THEN
+    REWRITE_TAC[IM_MUL_CX; IM_MUL_II; IM_ADD; RE_CX; IM_II; REAL_MUL_RID] THEN
+    MATCH_MP_TAC(REAL_ARITH
+     `abs(z) < p / &2 /\ (w = &0 \/ abs(w) >= &2 * p)
+      ==> ~(&2 * z = p + w)`) THEN
+    ASM_REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_PI; REAL_ABS_NUM] THEN
+    SIMP_TAC[real_ge; REAL_MUL_ASSOC; REAL_LE_RMUL_EQ; PI_POS] THEN
+    REWRITE_TAC[REAL_ENTIRE; PI_NZ] THEN
+    MP_TAC(SPEC `n:real` REAL_ABS_INTEGER_LEMMA) THEN
+    ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+    ASM_SIMP_TAC[CEXP_NEG; CEXP_NZ; COMPLEX_MUL_LNEG; COMPLEX_FIELD
+     `~(w = Cx(&0)) /\ ~(w pow 2 = --Cx(&1))
+      ==> (Cx(&1) - (w - inv w) / (w + inv w)) /
+          (Cx(&1) + (w - inv w) / (w + inv w)) =
+           inv(w) pow 2`] THEN
+    REWRITE_TAC[GSYM CEXP_N; GSYM CEXP_NEG] THEN
+    MATCH_MP_TAC CLOG_CEXP THEN REWRITE_TAC[IM_MUL_CX; IM_NEG; IM_MUL_II] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let RE_CATN_BOUNDS = prove
+ (`!z. (Re z = &0 ==> abs(Im z) < &1) ==> abs(Re(catn z)) < pi / &2`,
+  REWRITE_TAC[catn; complex_div; GSYM CX_INV; GSYM COMPLEX_MUL_ASSOC] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[RE_MUL_II; IM_MUL_CX] THEN
+  MATCH_MP_TAC(REAL_ARITH `abs x < p ==> abs(--(inv(&2) * x)) < p / &2`) THEN
+  MATCH_MP_TAC(REAL_ARITH `(--p < x /\ x <= p) /\ ~(x = p) ==> abs x < p`) THEN
+  SUBGOAL_THEN `~(z = ii) /\ ~(z = --ii)` STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN
+    DISCH_THEN(fun th -> POP_ASSUM MP_TAC THEN SUBST1_TAC th) THEN
+    REWRITE_TAC[RE_II; IM_II; RE_NEG; IM_NEG] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[GSYM complex_div] THEN CONJ_TAC THENL
+   [SUBGOAL_THEN `~((Cx(&1) - ii * z) / (Cx(&1) + ii * z) = Cx(&0))`
+     (fun th -> MESON_TAC[th; CLOG_WORKS]) THEN
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC COMPLEX_FIELD;
+    ALL_TAC] THEN
+  DISCH_TAC THEN
+  MP_TAC(ISPEC `clog((Cx(&1) - ii * z) / (Cx(&1) + ii * z))` EULER) THEN
+  ASM_REWRITE_TAC[SIN_PI; COS_PI; CX_NEG] THEN
+  REWRITE_TAC[COMPLEX_RING
+   `x = y * (--Cx(&1) + z * Cx(&0)) <=> x + y = Cx(&0)`] THEN
+  REWRITE_TAC[CX_EXP] THEN
+  ASM_SIMP_TAC[CEXP_CLOG; COMPLEX_FIELD
+     `~(z = ii) /\ ~(z = --ii)
+      ==> ~((Cx(&1) - ii * z) / (Cx(&1) + ii * z) = Cx(&0))`] THEN
+  REWRITE_TAC[GSYM CX_EXP] THEN DISCH_THEN(MP_TAC o AP_TERM `Im`) THEN
+  REWRITE_TAC[IM_ADD; IM_CX; REAL_ADD_RID; IM_COMPLEX_DIV_LEMMA] THEN
+  DISCH_TAC THEN UNDISCH_TAC `Re z = &0 ==> abs (Im z) < &1` THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  SUBGOAL_THEN `ii * z = --Cx(Im z)` SUBST_ALL_TAC THENL
+   [ASM_REWRITE_TAC[COMPLEX_EQ; RE_NEG; IM_NEG; RE_MUL_II; IM_MUL_II;
+                    RE_CX; IM_CX; REAL_NEG_0];
+    ALL_TAC] THEN
+  UNDISCH_TAC
+   `Im(clog((Cx(&1) - --Cx(Im z)) / (Cx(&1) + --Cx(Im z)))) = pi` THEN
+  REWRITE_TAC[COMPLEX_SUB_RNEG; GSYM complex_sub] THEN
+  REWRITE_TAC[GSYM CX_ADD; GSYM CX_SUB; GSYM CX_DIV] THEN
+  SUBGOAL_THEN `&0 < (&1 + Im z) / (&1 - Im z)` ASSUME_TAC THENL
+   [MATCH_MP_TAC REAL_LT_DIV THEN ASM_REAL_ARITH_TAC;
+    ASM_SIMP_TAC[GSYM CX_LOG; IM_CX; PI_NZ]]);;
+
+let HAS_COMPLEX_DERIVATIVE_CATN = prove
+ (`!z. (Re z = &0 ==> abs(Im z) < &1)
+       ==> (catn has_complex_derivative inv(Cx(&1) + z pow 2)) (at z)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `~(z = ii) /\ ~(z = --ii)` STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN
+    DISCH_THEN(fun th -> POP_ASSUM MP_TAC THEN SUBST1_TAC th) THEN
+    REWRITE_TAC[RE_II; IM_II; RE_NEG; IM_NEG] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC (RATOR_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+  REWRITE_TAC[catn] THEN COMPLEX_DIFF_TAC THEN
+  REWRITE_TAC[RE_SUB; RE_ADD; IM_SUB; IM_ADD;
+              RE_CX; RE_MUL_II; IM_CX; IM_MUL_II] THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC] THEN CONJ_TAC THENL
+   [ASM_REWRITE_TAC[IM_COMPLEX_DIV_LEMMA; RE_COMPLEX_DIV_LEMMA] THEN
+    SIMP_TAC[complex_norm] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    ASM_REWRITE_TAC[REAL_ADD_LID; POW_2_SQRT_ABS];
+    REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC COMPLEX_FIELD]);;
+
+let COMPLEX_DIFFERENTIABLE_AT_CATN = prove
+ (`!z. (Re z = &0 ==> abs(Im z) < &1) ==> catn complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CATN]);;
+
+let COMPLEX_DIFFERENTIABLE_WITHIN_CATN = prove
+ (`!s z. (Re z = &0 ==> abs(Im z) < &1)
+         ==> catn complex_differentiable (at z within s)`,
+  MESON_TAC[COMPLEX_DIFFERENTIABLE_AT_WITHIN;
+            COMPLEX_DIFFERENTIABLE_AT_CATN]);;
+
+add_complex_differentiation_theorems
+ (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+   (MATCH_MP HAS_COMPLEX_DERIVATIVE_CHAIN
+             HAS_COMPLEX_DERIVATIVE_CATN)));;
+
+let CONTINUOUS_AT_CATN = prove
+ (`!z. (Re z = &0 ==> abs(Im z) < &1) ==> catn continuous at z`,
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CATN;
+            HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT]);;
+
+let CONTINUOUS_WITHIN_CATN = prove
+ (`!s z. (Re z = &0 ==> abs(Im z) < &1) ==> catn continuous (at z within s)`,
+  MESON_TAC[CONTINUOUS_AT_WITHIN; CONTINUOUS_AT_CATN]);;
+
+let CONTINUOUS_ON_CATN = prove
+ (`!s. (!z. z IN s /\ Re z = &0 ==> abs(Im z) < &1) ==> catn continuous_on s`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON; CONTINUOUS_AT_CATN]);;
+
+let HOLOMORPHIC_ON_CATN = prove
+ (`!s. (!z. z IN s /\ Re z = &0 ==> abs(Im z) < &1) ==> catn holomorphic_on s`,
+  REWRITE_TAC [holomorphic_on] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HAS_COMPLEX_DERIVATIVE_CATN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real arctangent.                                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let atn = new_definition
+ `atn(x) = Re(catn(Cx x))`;;
+
+let CX_ATN = prove
+ (`!x. Cx(atn x) = catn(Cx x)`,
+  GEN_TAC THEN REWRITE_TAC[atn; catn; GSYM REAL; real] THEN
+  REWRITE_TAC[complex_div; IM_MUL_II; GSYM CX_INV; GSYM COMPLEX_MUL_ASSOC] THEN
+  REWRITE_TAC[RE_MUL_CX; REAL_ARITH `inv(&2) * x = &0 <=> x = &0`] THEN
+  MATCH_MP_TAC NORM_CEXP_IMAGINARY THEN
+  SUBGOAL_THEN `~(Cx(&1) - ii * Cx(x) = Cx(&0)) /\
+                ~(Cx(&1) + ii * Cx(x) = Cx(&0))`
+  STRIP_ASSUME_TAC THENL
+   [CONJ_TAC THEN DISCH_THEN(MP_TAC o AP_TERM `Re`) THEN
+    REWRITE_TAC[RE_ADD; RE_SUB; RE_MUL_II; IM_CX; RE_CX] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[CEXP_SUB; CEXP_CLOG; COMPLEX_FIELD
+   `~(a = Cx(&0)) /\ ~(b = Cx(&0)) ==> ~(a * inv b = Cx(&0))`] THEN
+  REWRITE_TAC[GSYM complex_div; COMPLEX_NORM_DIV] THEN
+  MATCH_MP_TAC(REAL_FIELD `~(b = &0) /\ a = b ==> a / b = &1`) THEN
+  ASM_REWRITE_TAC[COMPLEX_NORM_ZERO] THEN
+  MATCH_MP_TAC(MESON[COMPLEX_NORM_CNJ] `cnj a = b ==> norm a = norm b`) THEN
+  REWRITE_TAC[CNJ_SUB; CNJ_MUL; CNJ_MUL; CNJ_II; CNJ_CX] THEN
+  CONV_TAC COMPLEX_RING);;
+
+let ATN_TAN = prove
+ (`!y. tan(atn y) = y`,
+  GEN_TAC THEN REWRITE_TAC[tan_def; atn] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `Re(ctan(catn(Cx y)))` THEN
+  CONJ_TAC THENL [REWRITE_TAC[GSYM CX_ATN; RE_CX]; ALL_TAC] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM RE_CX] THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC CTAN_CATN THEN MATCH_MP_TAC(COMPLEX_RING
+   `~(z = ii) /\ ~(z = --ii) ==> ~(z pow 2 = --Cx(&1))`) THEN
+  CONJ_TAC THEN DISCH_THEN(MP_TAC o AP_TERM `Im`) THEN
+  REWRITE_TAC[IM_II; IM_CX; IM_NEG] THEN REAL_ARITH_TAC);;
+
+let ATN_BOUND = prove
+ (`!y. abs(atn y) < pi / &2`,
+  GEN_TAC THEN REWRITE_TAC[atn] THEN MATCH_MP_TAC RE_CATN_BOUNDS THEN
+  REWRITE_TAC[IM_CX] THEN CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let ATN_BOUNDS = prove
+ (`!y. --(pi / &2) < atn(y) /\ atn(y) < (pi / &2)`,
+  MP_TAC ATN_BOUND THEN MATCH_MP_TAC MONO_FORALL THEN REAL_ARITH_TAC);;
+
+let TAN_ATN = prove
+ (`!x. --(pi / &2) < x /\ x < pi / &2 ==> atn(tan(x)) = x`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[tan_def; atn] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `Re(catn(ctan(Cx x)))` THEN
+  CONJ_TAC THENL [REWRITE_TAC[GSYM CX_TAN; RE_CX]; ALL_TAC] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM RE_CX] THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC CATN_CTAN THEN REWRITE_TAC[RE_CX] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let ATN_0 = prove
+ (`atn(&0) = &0`,
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [SYM TAN_0] THEN
+  MATCH_MP_TAC TAN_ATN THEN MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+let ATN_1 = prove
+ (`atn(&1) = pi / &4`,
+  MP_TAC(AP_TERM `atn` TAN_PI4) THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC TAN_ATN THEN MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+let ATN_NEG = prove
+ (`!x. atn(--x) = --(atn x)`,
+  GEN_TAC THEN MP_TAC(SPEC `atn(x)` TAN_NEG) THEN REWRITE_TAC[ATN_TAN] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN MATCH_MP_TAC TAN_ATN THEN
+  MP_TAC(SPEC `x:real` ATN_BOUNDS) THEN REAL_ARITH_TAC);;
+
+let ATN_MONO_LT = prove
+ (`!x y. x < y ==> atn(x) < atn(y)`,
+  REPEAT GEN_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINOP_CONV) [GSYM ATN_TAN] THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[REAL_NOT_LT] THEN
+  SIMP_TAC[TAN_MONO_LE; ATN_BOUNDS]);;
+
+let ATN_MONO_LT_EQ = prove
+ (`!x y. atn(x) < atn(y) <=> x < y`,
+  MESON_TAC[REAL_NOT_LE; REAL_LE_LT; ATN_MONO_LT]);;
+
+let ATN_MONO_LE_EQ = prove
+ (`!x y. atn(x) <= atn(y) <=> x <= y`,
+  REWRITE_TAC[GSYM REAL_NOT_LT; ATN_MONO_LT_EQ]);;
+
+let ATN_INJ = prove
+ (`!x y. (atn x = atn y) <=> (x = y)`,
+  REWRITE_TAC[GSYM REAL_LE_ANTISYM; ATN_MONO_LE_EQ]);;
+
+let ATN_POS_LT = prove
+ (`&0 < atn(x) <=> &0 < x`,
+  MESON_TAC[ATN_0; ATN_MONO_LT_EQ]);;
+
+let ATN_POS_LE = prove
+ (`&0 <= atn(x) <=> &0 <= x`,
+  MESON_TAC[ATN_0; ATN_MONO_LE_EQ]);;
+
+let ATN_LT_PI4_POS = prove
+ (`!x. x < &1 ==> atn(x) < pi / &4`,
+  SIMP_TAC[GSYM ATN_1; ATN_MONO_LT]);;
+
+let ATN_LT_PI4_NEG = prove
+ (`!x. --(&1) < x ==> --(pi / &4) < atn(x)`,
+  SIMP_TAC[GSYM ATN_1; GSYM ATN_NEG; ATN_MONO_LT]);;
+
+let ATN_LT_PI4 = prove
+ (`!x. abs(x) < &1 ==> abs(atn x) < pi / &4`,
+  GEN_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `(&0 < x ==> &0 < y) /\
+    (x < &0 ==> y < &0) /\
+    ((x = &0) ==> (y = &0)) /\
+    (x < a ==> y < b) /\
+    (--a < x ==> --b < y)
+    ==> abs(x) < a ==> abs(y) < b`) THEN
+  SIMP_TAC[ATN_LT_PI4_POS; ATN_LT_PI4_NEG; ATN_0] THEN CONJ_TAC THEN
+  GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [GSYM ATN_0] THEN
+  SIMP_TAC[ATN_MONO_LT]);;
+
+let ATN_LE_PI4 = prove
+ (`!x. abs(x) <= &1 ==> abs(atn x) <= pi / &4`,
+  REWRITE_TAC[REAL_LE_LT] THEN REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[ATN_LT_PI4] THEN DISJ2_TAC THEN
+  FIRST_ASSUM(DISJ_CASES_THEN SUBST1_TAC o MATCH_MP
+    (REAL_ARITH `(abs(x) = a) ==> (x = a) \/ (x = --a)`)) THEN
+  ASM_REWRITE_TAC[ATN_1; ATN_NEG] THEN
+  REWRITE_TAC[REAL_ABS_DIV; REAL_ABS_NUM; REAL_ABS_NEG] THEN
+  SIMP_TAC[real_abs; REAL_LT_IMP_LE; PI_POS]);;
+
+let COS_ATN_NZ = prove
+ (`!x. ~(cos(atn(x)) = &0)`,
+  GEN_TAC THEN MATCH_MP_TAC REAL_LT_IMP_NZ THEN
+  MATCH_MP_TAC COS_POS_PI THEN REWRITE_TAC[ATN_BOUNDS]);;
+
+let TAN_SEC = prove
+ (`!x. ~(cos(x) = &0) ==> (&1 + (tan(x) pow 2) = inv(cos x) pow 2)`,
+  MP_TAC SIN_CIRCLE THEN MATCH_MP_TAC MONO_FORALL THEN REWRITE_TAC[tan] THEN
+  CONV_TAC REAL_FIELD);;
+
+let COS_ATN = prove
+ (`!x. cos(atn x) = &1 / sqrt(&1 + x pow 2)`,
+  SIMP_TAC[COS_TAN; ATN_BOUND; ATN_TAN]);;
+
+let SIN_ATN = prove
+ (`!x. sin(atn x) = x / sqrt(&1 + x pow 2)`,
+  SIMP_TAC[SIN_TAN; ATN_BOUND; ATN_TAN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some bound theorems where a bit of simple calculus is handy.              *)
+(* ------------------------------------------------------------------------- *)
+
+let ATN_ABS_LE_X = prove
+ (`!x. abs(atn x) <= abs x`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`catn`; `\z. inv(Cx(&1) + z pow 2)`; `real`; `&1`]
+      COMPLEX_MVT) THEN
+  REWRITE_TAC[CONVEX_REAL; IN] THEN ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [REWRITE_TAC[real] THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_AT_WITHIN THEN
+      MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_CATN THEN
+      ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+      GEN_TAC THEN REWRITE_TAC[REAL] THEN
+      DISCH_THEN(SUBST1_TAC o SYM) THEN
+      REWRITE_TAC[GSYM CX_POW; GSYM CX_ADD; GSYM CX_INV; COMPLEX_NORM_CX] THEN
+      REWRITE_TAC[REAL_ABS_INV] THEN MATCH_MP_TAC REAL_INV_LE_1 THEN
+      MP_TAC(SPEC `Re z` REAL_LE_SQUARE) THEN REAL_ARITH_TAC];
+    DISCH_THEN(MP_TAC o SPECL [`Cx(&0)`; `Cx(x)`]) THEN
+    REWRITE_TAC[GSYM CX_ATN; COMPLEX_SUB_RZERO; REAL_CX; ATN_0] THEN
+    REWRITE_TAC[COMPLEX_NORM_CX; REAL_MUL_LID]]);;
+
+let ATN_LE_X = prove
+ (`!x. &0 <= x ==> atn(x) <= x`,
+  MP_TAC ATN_ABS_LE_X THEN MATCH_MP_TAC MONO_FORALL THEN REAL_ARITH_TAC);;
+
+let TAN_ABS_GE_X = prove
+ (`!x. abs(x) < pi / &2 ==> abs(x) <= abs(tan x)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `abs(atn(tan x))` THEN REWRITE_TAC[ATN_ABS_LE_X] THEN
+  MATCH_MP_TAC REAL_EQ_IMP_LE THEN AP_TERM_TAC THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC TAN_ATN THEN
+  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Probably not very useful, but for compatibility with old analysis theory. *)
+(* ------------------------------------------------------------------------- *)
+
+let TAN_TOTAL = prove
+ (`!y. ?!x. --(pi / &2) < x /\ x < (pi / &2) /\ tan(x) = y`,
+  MESON_TAC[TAN_ATN; ATN_TAN; ATN_BOUNDS]);;
+
+let TAN_TOTAL_POS = prove
+ (`!y. &0 <= y ==> ?x. &0 <= x /\ x < pi / &2 /\ tan(x) = y`,
+  MESON_TAC[ATN_TAN; ATN_BOUNDS; ATN_POS_LE]);;
+
+let TAN_TOTAL_LEMMA = prove
+ (`!y. &0 < y ==> ?x. &0 < x /\ x < pi / &2 /\ y < tan(x)`,
+  REPEAT STRIP_TAC THEN EXISTS_TAC `atn(y + &1)` THEN
+  REWRITE_TAC[ATN_TAN; ATN_BOUNDS; ATN_POS_LT] THEN
+  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some slightly ad hoc lemmas useful here.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let RE_POW_2 = prove
+ (`Re(z pow 2) = Re(z) pow 2 - Im(z) pow 2`,
+  REWRITE_TAC[COMPLEX_POW_2; complex_mul; RE] THEN REAL_ARITH_TAC);;
+
+let IM_POW_2 = prove
+ (`Im(z pow 2) = &2 * Re(z) * Im(z)`,
+  REWRITE_TAC[COMPLEX_POW_2; complex_mul; IM] THEN REAL_ARITH_TAC);;
+
+let ABS_SQUARE_LT_1 = prove
+ (`!x. x pow 2 < &1 <=> abs(x) < &1`,
+  ONCE_REWRITE_TAC[GSYM REAL_ABS_NUM] THEN
+  REWRITE_TAC[REAL_LT_SQUARE_ABS] THEN REAL_ARITH_TAC);;
+
+let ABS_SQUARE_LE_1 = prove
+ (`!x. x pow 2 <= &1 <=> abs(x) <= &1`,
+  ONCE_REWRITE_TAC[GSYM REAL_ABS_NUM] THEN
+  REWRITE_TAC[REAL_LT_SQUARE_ABS; GSYM REAL_NOT_LT] THEN REAL_ARITH_TAC);;
+
+let ABS_SQUARE_EQ_1 = prove
+ (`!x. x pow 2 = &1 <=> abs(x) = &1`,
+  REWRITE_TAC[REAL_RING `x pow 2 = &1 <=> x = &1 \/ x = -- &1`] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Inverse sine.                                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let casn = new_definition
+ `casn z = --ii * clog(ii * z + csqrt(Cx(&1) - z pow 2))`;;
+
+let CASN_BODY_LEMMA = prove
+ (`!z. ~(ii * z + csqrt(Cx(&1) - z pow 2) = Cx(&0))`,
+  GEN_TAC THEN MP_TAC(SPEC `Cx(&1) - z pow 2` CSQRT) THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CSIN_CASN = prove
+ (`!z. csin(casn z) = z`,
+  GEN_TAC THEN REWRITE_TAC[csin; casn; COMPLEX_MUL_LNEG; COMPLEX_MUL_RNEG] THEN
+  REWRITE_TAC[COMPLEX_MUL_ASSOC; COMPLEX_NEG_NEG] THEN
+  REWRITE_TAC[COMPLEX_POW_II_2; GSYM COMPLEX_POW_2] THEN
+  REWRITE_TAC[COMPLEX_NEG_NEG; COMPLEX_MUL_LNEG; COMPLEX_MUL_LID] THEN
+  REWRITE_TAC[CEXP_NEG] THEN
+  ASM_SIMP_TAC[CASN_BODY_LEMMA; CEXP_CLOG; COMPLEX_FIELD
+     `~(z = Cx(&0))
+      ==> ((z - inv z) / (Cx(&2) * ii) = c <=>
+           z pow 2 - Cx(&1) = Cx(&2) * ii * c * z)`] THEN
+  MP_TAC(SPEC `Cx(&1) - z pow 2` CSQRT) THEN CONV_TAC COMPLEX_FIELD);;
+
+let CASN_CSIN = prove
+ (`!z. abs(Re z) < pi / &2 \/ (abs(Re z) = pi / &2 /\ Im z = &0)
+       ==> casn(csin z) = z`,
+  GEN_TAC THEN DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  REWRITE_TAC[csin; casn; COMPLEX_MUL_LNEG; CEXP_NEG] THEN
+  SIMP_TAC[CEXP_NZ; COMPLEX_FIELD
+    `~(z = Cx(&0))
+     ==> Cx(&1) - ((z - inv z) / (Cx(&2) * ii)) pow 2 =
+         ((z + inv z) / Cx(&2)) pow 2`] THEN
+  SUBGOAL_THEN
+   `csqrt(((cexp(ii * z) + inv(cexp(ii * z))) / Cx(&2)) pow 2) =
+    (cexp(ii * z) + inv(cexp(ii * z))) / Cx(&2)`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC POW_2_CSQRT THEN REWRITE_TAC[GSYM CEXP_NEG] THEN
+    REWRITE_TAC[complex_div; GSYM CX_INV; RE_MUL_CX; IM_MUL_CX] THEN
+    REWRITE_TAC[REAL_ARITH
+     `&0 < r * inv(&2) \/ r * inv(&2) = &0 /\ &0 <= i * inv(&2) <=>
+      &0 < r \/ r = &0 /\ &0 <= i`] THEN
+    REWRITE_TAC[RE_ADD; IM_ADD; RE_CEXP; IM_CEXP] THEN
+    REWRITE_TAC[RE_MUL_II; RE_NEG; IM_MUL_II; IM_NEG] THEN
+    REWRITE_TAC[SIN_NEG; COS_NEG; REAL_NEG_NEG] THEN
+    REWRITE_TAC[REAL_MUL_RNEG; GSYM real_sub] THEN
+    REWRITE_TAC[GSYM REAL_ADD_RDISTRIB; GSYM REAL_SUB_RDISTRIB] THEN
+    FIRST_X_ASSUM(DISJ_CASES_THEN STRIP_ASSUME_TAC) THENL
+     [DISJ1_TAC THEN MATCH_MP_TAC REAL_LT_MUL THEN
+      ASM_SIMP_TAC[REAL_LT_ADD; REAL_EXP_POS_LT] THEN
+      MATCH_MP_TAC COS_POS_PI THEN POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
+      DISJ2_TAC THEN ASM_REWRITE_TAC[SIN_PI2; COS_PI2] THEN
+      REWRITE_TAC[REAL_EXP_NEG; REAL_EXP_0; REAL_INV_1; REAL_SUB_REFL] THEN
+      REWRITE_TAC[REAL_MUL_LZERO; REAL_LE_REFL; REAL_ENTIRE] THEN
+      FIRST_X_ASSUM(DISJ_CASES_THEN SUBST1_TAC o MATCH_MP (REAL_ARITH
+       `abs(x) = p ==> x = p \/ x = --p`)) THEN
+      REWRITE_TAC[COS_PI2; COS_NEG] THEN REAL_ARITH_TAC];
+    ALL_TAC] THEN
+  SIMP_TAC[COMPLEX_FIELD
+   `ii * (a - b) / (Cx(&2) * ii) + (a + b) / Cx(&2) = a`] THEN
+  SIMP_TAC[COMPLEX_FIELD `--(ii * w) = z <=> w = ii * z`] THEN
+  MATCH_MP_TAC CLOG_CEXP THEN REWRITE_TAC[IM_MUL_II] THEN
+  MP_TAC PI_POS THEN POP_ASSUM MP_TAC THEN REAL_ARITH_TAC);;
+
+let CASN_UNIQUE = prove
+ (`!w z. csin(z) = w /\
+         (abs(Re z) < pi / &2 \/ (abs(Re z) = pi / &2 /\ Im z = &0))
+         ==> casn w = z`,
+  MESON_TAC[CASN_CSIN]);;
+
+let CASN_0 = prove
+ (`casn(Cx(&0)) = Cx(&0)`,
+  REWRITE_TAC[casn; COMPLEX_MUL_RZERO; COMPLEX_ADD_LID; COMPLEX_POW_2;
+              COMPLEX_SUB_RZERO; CSQRT_1; CLOG_1; COMPLEX_MUL_RZERO]);;
+
+let CASN_1 = prove
+ (`casn(Cx(&1)) = Cx(pi / &2)`,
+  REWRITE_TAC[casn; GSYM CX_POW; GSYM CX_SUB] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[CSQRT_0; COMPLEX_MUL_RID; COMPLEX_ADD_RID] THEN
+  REWRITE_TAC[CLOG_II] THEN CONV_TAC COMPLEX_RING);;
+
+let CASN_NEG_1 = prove
+ (`casn(--Cx(&1)) = --Cx(pi / &2)`,
+  REWRITE_TAC[casn; GSYM CX_NEG; GSYM CX_POW; GSYM CX_SUB] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[CSQRT_0; COMPLEX_MUL_RID; COMPLEX_ADD_RID] THEN
+  REWRITE_TAC[CX_NEG; COMPLEX_MUL_RID; COMPLEX_MUL_RNEG] THEN
+  REWRITE_TAC[CLOG_NEG_II] THEN CONV_TAC COMPLEX_RING);;
+
+let HAS_COMPLEX_DERIVATIVE_CASN = prove
+ (`!z. (Im z = &0 ==> abs(Re z) < &1)
+       ==> (casn has_complex_derivative inv(ccos(casn z))) (at z)`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_INVERSE_BASIC THEN
+  EXISTS_TAC `csin` THEN
+  REWRITE_TAC[CSIN_CASN; HAS_COMPLEX_DERIVATIVE_CSIN; CONTINUOUS_AT_CSIN] THEN
+  EXISTS_TAC `ball(z:complex,&1)` THEN
+  REWRITE_TAC[OPEN_BALL; CENTRE_IN_BALL; REAL_LT_01] THEN CONJ_TAC THENL
+   [DISCH_THEN(MP_TAC o MATCH_MP (COMPLEX_RING
+     `ccos z = Cx(&0) ==> csin(z) pow 2 + ccos(z) pow 2 = Cx(&1)
+                          ==> csin(z) pow 2 = Cx(&1)`)) THEN
+    REWRITE_TAC[CSIN_CASN; CSIN_CIRCLE] THEN
+    REWRITE_TAC[COMPLEX_RING
+     `z pow 2 = Cx(&1) <=> z = Cx(&1) \/ z = --Cx(&1)`] THEN
+    DISCH_THEN(DISJ_CASES_THEN SUBST_ALL_TAC) THEN
+    POP_ASSUM MP_TAC THEN REWRITE_TAC[RE_CX; IM_CX; RE_NEG; IM_NEG] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN REWRITE_TAC[casn] THEN
+  MATCH_MP_TAC CONTINUOUS_COMPLEX_MUL THEN REWRITE_TAC[CONTINUOUS_CONST] THEN
+  ONCE_REWRITE_TAC[GSYM o_DEF] THEN MATCH_MP_TAC CONTINUOUS_AT_COMPOSE THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ADD THEN
+    SIMP_TAC[CONTINUOUS_COMPLEX_MUL; CONTINUOUS_CONST; CONTINUOUS_AT_ID] THEN
+    ONCE_REWRITE_TAC[GSYM o_DEF] THEN MATCH_MP_TAC CONTINUOUS_AT_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_COMPLEX_POW; CONTINUOUS_SUB;
+             CONTINUOUS_CONST; CONTINUOUS_AT_ID] THEN
+    MATCH_MP_TAC CONTINUOUS_AT_CSQRT THEN
+    REWRITE_TAC[RE_SUB; IM_SUB; RE_CX; IM_CX; RE_POW_2; IM_POW_2] THEN
+    REWRITE_TAC[REAL_RING `&0 - &2 * x * y = &0 <=> x = &0 \/ y = &0`] THEN
+    STRIP_TAC THEN
+    ASM_REWRITE_TAC[REAL_POW_2; REAL_MUL_LZERO; REAL_SUB_RZERO;
+                    REAL_ARITH `&1 - (&0 - x) = &1 + x`] THEN
+    ASM_SIMP_TAC[REAL_LE_SQUARE; REAL_ARITH `&0 <= x ==> &0 < &1 + x`] THEN
+    REWRITE_TAC[REAL_ARITH `&0 < &1 - x * x <=> x pow 2 < &1 pow 2`] THEN
+    ONCE_REWRITE_TAC[GSYM REAL_POW2_ABS] THEN MATCH_MP_TAC REAL_POW_LT2 THEN
+    ASM_SIMP_TAC[REAL_ABS_POS; REAL_ABS_NUM; ARITH];
+    ALL_TAC] THEN
+  MATCH_MP_TAC CONTINUOUS_AT_CLOG THEN
+  REWRITE_TAC[IM_ADD; IM_MUL_II; RE_ADD; RE_MUL_II] THEN
+  ASM_CASES_TAC `Im z = &0` THENL
+   [DISCH_THEN(K ALL_TAC) THEN ASM_REWRITE_TAC[csqrt] THEN
+    ASM_REWRITE_TAC[IM_SUB; RE_SUB; IM_CX; RE_CX; IM_POW_2; RE_POW_2;
+                    REAL_MUL_RZERO; REAL_SUB_REFL] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[REAL_ARITH `&0 <= &1 - (z pow 2 - &0) <=> z pow 2 <= &1 pow 2`;
+                GSYM REAL_LE_SQUARE_ABS] THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_ABS_NUM; RE; REAL_ADD_LID] THEN
+    MATCH_MP_TAC SQRT_POS_LT THEN
+    REWRITE_TAC[REAL_ARITH `&0 < &1 - (z pow 2 - &0) <=> z pow 2 < &1 pow 2`;
+                GSYM REAL_LT_SQUARE_ABS] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  REWRITE_TAC[csqrt; IM_SUB; RE_SUB; IM_CX; RE_CX; IM_POW_2; RE_POW_2] THEN
+  REWRITE_TAC[REAL_RING `&0 - &2 * x * y = &0 <=> x = &0 \/ y = &0`] THEN
+  ASM_CASES_TAC `Re z = &0` THEN ASM_REWRITE_TAC[RE; IM] THENL
+   [CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[REAL_ARITH `&1 - (&0 - x) = &1 + x`] THEN
+    SIMP_TAC[REAL_POW_2; REAL_LE_ADD; REAL_LE_SQUARE; REAL_POS] THEN
+    REWRITE_TAC[RE; IM; REAL_ADD_LID; REAL_ARITH `&0 < --x + y <=> x < y`] THEN
+    MATCH_MP_TAC REAL_LT_RSQRT THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_TAC THEN REWRITE_TAC[REAL_ARITH `&0 < --x + y <=> x < y`] THEN
+  MATCH_MP_TAC REAL_LT_RSQRT THEN
+  REWRITE_TAC[REAL_POW_2; REAL_ARITH
+   `a < (n + &1 - (b - a)) / &2 <=> (a + b) - &1 < n`] THEN
+  REWRITE_TAC[complex_norm] THEN MATCH_MP_TAC REAL_LT_RSQRT THEN
+  REWRITE_TAC[RE_SUB; IM_SUB; RE_CX; IM_CX; RE_POW_2; IM_POW_2] THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o
+    GEN_REWRITE_RULE I [GSYM REAL_LT_SQUARE])) THEN
+  REAL_ARITH_TAC);;
+
+let COMPLEX_DIFFERENTIABLE_AT_CASN = prove
+ (`!z. (Im z = &0 ==> abs(Re z) < &1) ==> casn complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CASN]);;
+
+let COMPLEX_DIFFERENTIABLE_WITHIN_CASN = prove
+ (`!s z. (Im z = &0 ==> abs(Re z) < &1)
+         ==> casn complex_differentiable (at z within s)`,
+  MESON_TAC[COMPLEX_DIFFERENTIABLE_AT_WITHIN;
+            COMPLEX_DIFFERENTIABLE_AT_CASN]);;
+
+add_complex_differentiation_theorems
+ (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+   (MATCH_MP HAS_COMPLEX_DERIVATIVE_CHAIN
+             HAS_COMPLEX_DERIVATIVE_CASN)));;
+
+let CONTINUOUS_AT_CASN = prove
+ (`!z. (Im z = &0 ==> abs(Re z) < &1) ==> casn continuous at z`,
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CASN;
+            HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT]);;
+
+let CONTINUOUS_WITHIN_CASN = prove
+ (`!s z. (Im z = &0 ==> abs(Re z) < &1) ==> casn continuous (at z within s)`,
+  MESON_TAC[CONTINUOUS_AT_WITHIN; CONTINUOUS_AT_CASN]);;
+
+let CONTINUOUS_ON_CASN = prove
+ (`!s. (!z. z IN s /\ Im z = &0 ==> abs(Re z) < &1) ==> casn continuous_on s`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON; CONTINUOUS_AT_CASN]);;
+
+let HOLOMORPHIC_ON_CASN = prove
+ (`!s. (!z. z IN s /\ Im z = &0 ==> abs(Re z) < &1) ==> casn holomorphic_on s`,
+  REWRITE_TAC [holomorphic_on] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HAS_COMPLEX_DERIVATIVE_CASN]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Inverse cosine.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let cacs = new_definition
+ `cacs z = --ii * clog(z + ii * csqrt(Cx(&1) - z pow 2))`;;
+
+let CACS_BODY_LEMMA = prove
+ (`!z. ~(z + ii * csqrt(Cx(&1) - z pow 2) = Cx(&0))`,
+  GEN_TAC THEN MP_TAC(SPEC `Cx(&1) - z pow 2` CSQRT) THEN
+  CONV_TAC COMPLEX_FIELD);;
+
+let CCOS_CACS = prove
+ (`!z. ccos(cacs z) = z`,
+  GEN_TAC THEN REWRITE_TAC[ccos; cacs; COMPLEX_MUL_LNEG; COMPLEX_MUL_RNEG] THEN
+  REWRITE_TAC[COMPLEX_MUL_ASSOC; COMPLEX_NEG_NEG] THEN
+  REWRITE_TAC[COMPLEX_POW_II_2; GSYM COMPLEX_POW_2] THEN
+  REWRITE_TAC[COMPLEX_NEG_NEG; COMPLEX_MUL_LNEG; COMPLEX_MUL_LID] THEN
+  REWRITE_TAC[CEXP_NEG] THEN
+  ASM_SIMP_TAC[CACS_BODY_LEMMA; CEXP_CLOG; COMPLEX_POW_II_2; COMPLEX_FIELD
+     `~(z = Cx(&0))
+      ==> ((z + inv z) / Cx(&2) = c <=>
+           z pow 2 + Cx(&1) = Cx(&2) * c * z)`] THEN
+  MP_TAC(SPEC `Cx(&1) - z pow 2` CSQRT) THEN CONV_TAC COMPLEX_FIELD);;
+
+let CACS_CCOS = prove
+ (`!z. &0 < Re z /\ Re z < pi \/
+       Re(z) = &0 /\ &0 <= Im(z) \/
+       Re(z) = pi /\ Im(z) <= &0
+       ==> cacs(ccos z) = z`,
+  GEN_TAC THEN DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  REWRITE_TAC[ccos; cacs; COMPLEX_MUL_LNEG; CEXP_NEG] THEN
+  SIMP_TAC[CEXP_NZ; COMPLEX_FIELD
+    `~(z = Cx(&0))
+     ==> Cx(&1) - ((z + inv z) / Cx(&2)) pow 2 =
+         --(((z - inv z) / Cx(&2)) pow 2)`] THEN
+  SUBGOAL_THEN
+   `csqrt(--(((cexp(ii * z) - inv(cexp(ii * z))) / Cx(&2)) pow 2)) =
+    --ii * (cexp(ii * z) - inv(cexp(ii * z))) / Cx(&2)`
+  SUBST1_TAC THENL
+   [SIMP_TAC[COMPLEX_FIELD `--(x pow 2) = (--ii * x) pow 2`] THEN
+    MATCH_MP_TAC POW_2_CSQRT THEN REWRITE_TAC[GSYM CEXP_NEG] THEN
+    REWRITE_TAC[complex_div; GSYM CX_INV; RE_MUL_CX; IM_MUL_CX; RE_NEG; IM_NEG;
+                COMPLEX_MUL_LNEG; RE_MUL_II; IM_MUL_II; RE_SUB; IM_SUB] THEN
+    REWRITE_TAC[REAL_NEG_NEG; REAL_NEG_EQ_0] THEN
+    REWRITE_TAC[REAL_ARITH
+     `&0 < r * inv(&2) \/ r * inv(&2) = &0 /\ &0 <= --(i * inv(&2)) <=>
+      &0 < r \/ r = &0 /\ &0 <= --i`] THEN
+    REWRITE_TAC[RE_ADD; IM_ADD; RE_CEXP; IM_CEXP] THEN
+    REWRITE_TAC[RE_MUL_II; RE_NEG; IM_MUL_II; IM_NEG] THEN
+    REWRITE_TAC[SIN_NEG; COS_NEG; REAL_NEG_NEG] THEN
+    REWRITE_TAC[REAL_MUL_RNEG; GSYM real_sub; REAL_SUB_RNEG; REAL_NEG_SUB] THEN
+    REWRITE_TAC[GSYM REAL_ADD_RDISTRIB; GSYM REAL_SUB_RDISTRIB] THEN
+    ASM_SIMP_TAC[REAL_LT_ADD; REAL_EXP_POS_LT; REAL_LT_MUL_EQ] THEN
+    POP_ASSUM(REPEAT_TCL DISJ_CASES_THEN STRIP_ASSUME_TAC) THEN
+    ASM_SIMP_TAC[SIN_POS_PI] THEN DISJ2_TAC THEN
+    REWRITE_TAC[SIN_PI; REAL_MUL_RZERO; COS_PI; SIN_0; COS_0] THEN
+    REWRITE_TAC[REAL_MUL_RID; REAL_MUL_RNEG] THEN
+    REWRITE_TAC[REAL_NEG_SUB; REAL_SUB_LE; REAL_EXP_MONO_LE] THEN
+    ASM_REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  SIMP_TAC[COMPLEX_FIELD
+   `(e + e') / Cx(&2) + ii * --ii * (e - e') / Cx(&2) = e`] THEN
+  SIMP_TAC[COMPLEX_FIELD `--(ii * w) = z <=> w = ii * z`] THEN
+  MATCH_MP_TAC CLOG_CEXP THEN REWRITE_TAC[IM_MUL_II] THEN
+  MP_TAC PI_POS THEN ASM_REAL_ARITH_TAC);;
+
+let CACS_UNIQUE = prove
+ (`!w z.
+       ccos z = w /\
+       (&0 < Re z /\ Re z < pi \/
+        Re(z) = &0 /\ &0 <= Im(z) \/
+        Re(z) = pi /\ Im(z) <= &0)
+       ==> cacs(w) = z`,
+  MESON_TAC[CACS_CCOS]);;
+
+let CACS_0 = prove
+ (`cacs(Cx(&0)) = Cx(pi / &2)`,
+  MATCH_MP_TAC CACS_UNIQUE THEN
+  REWRITE_TAC[RE_CX; IM_CX; GSYM CX_COS; COS_PI2] THEN
+  MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+let CACS_1 = prove
+ (`cacs(Cx(&1)) = Cx(&0)`,
+  MATCH_MP_TAC CACS_UNIQUE THEN
+  REWRITE_TAC[RE_CX; IM_CX; GSYM CX_COS; COS_0; REAL_LE_REFL]);;
+
+let CACS_NEG_1 = prove
+ (`cacs(--Cx(&1)) = Cx pi`,
+  MATCH_MP_TAC CACS_UNIQUE THEN
+  REWRITE_TAC[RE_CX; IM_CX; GSYM CX_COS; COS_PI; CX_NEG; REAL_LE_REFL]);;
+
+let HAS_COMPLEX_DERIVATIVE_CACS = prove
+ (`!z. (Im z = &0 ==> abs(Re z) < &1)
+       ==> (cacs has_complex_derivative --inv(csin(cacs z))) (at z)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[COMPLEX_NEG_INV] THEN
+  MATCH_MP_TAC HAS_COMPLEX_DERIVATIVE_INVERSE_BASIC THEN
+  EXISTS_TAC `ccos` THEN
+  REWRITE_TAC[CCOS_CACS; HAS_COMPLEX_DERIVATIVE_CCOS; CONTINUOUS_AT_CCOS] THEN
+  EXISTS_TAC `ball(z:complex,&1)` THEN
+  REWRITE_TAC[OPEN_BALL; CENTRE_IN_BALL; REAL_LT_01] THEN CONJ_TAC THENL
+   [DISCH_THEN(MP_TAC o MATCH_MP (COMPLEX_RING
+     `--(csin z) = Cx(&0) ==> csin(z) pow 2 + ccos(z) pow 2 = Cx(&1)
+                              ==> ccos(z) pow 2 = Cx(&1)`)) THEN
+    REWRITE_TAC[CCOS_CACS; CSIN_CIRCLE] THEN
+    REWRITE_TAC[COMPLEX_RING
+     `z pow 2 = Cx(&1) <=> z = Cx(&1) \/ z = --Cx(&1)`] THEN
+    DISCH_THEN(DISJ_CASES_THEN SUBST_ALL_TAC) THEN
+    POP_ASSUM MP_TAC THEN REWRITE_TAC[RE_CX; IM_CX; RE_NEG; IM_NEG] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM ETA_AX] THEN REWRITE_TAC[cacs] THEN
+  MATCH_MP_TAC CONTINUOUS_COMPLEX_MUL THEN REWRITE_TAC[CONTINUOUS_CONST] THEN
+  ONCE_REWRITE_TAC[GSYM o_DEF] THEN MATCH_MP_TAC CONTINUOUS_AT_COMPOSE THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ADD THEN REWRITE_TAC[CONTINUOUS_AT_ID] THEN
+    MATCH_MP_TAC CONTINUOUS_COMPLEX_MUL THEN REWRITE_TAC[CONTINUOUS_CONST] THEN
+    ONCE_REWRITE_TAC[GSYM o_DEF] THEN MATCH_MP_TAC CONTINUOUS_AT_COMPOSE THEN
+    SIMP_TAC[CONTINUOUS_COMPLEX_POW; CONTINUOUS_SUB;
+             CONTINUOUS_CONST; CONTINUOUS_AT_ID] THEN
+    MATCH_MP_TAC CONTINUOUS_AT_CSQRT THEN
+    REWRITE_TAC[RE_SUB; IM_SUB; RE_CX; IM_CX; RE_POW_2; IM_POW_2] THEN
+    REWRITE_TAC[REAL_RING `&0 - &2 * x * y = &0 <=> x = &0 \/ y = &0`] THEN
+    STRIP_TAC THEN
+    ASM_REWRITE_TAC[REAL_POW_2; REAL_MUL_LZERO; REAL_SUB_RZERO;
+                    REAL_ARITH `&1 - (&0 - x) = &1 + x`] THEN
+    ASM_SIMP_TAC[REAL_LE_SQUARE; REAL_ARITH `&0 <= x ==> &0 < &1 + x`] THEN
+    REWRITE_TAC[REAL_ARITH `&0 < &1 - x * x <=> x pow 2 < &1 pow 2`] THEN
+    ONCE_REWRITE_TAC[GSYM REAL_POW2_ABS] THEN MATCH_MP_TAC REAL_POW_LT2 THEN
+    ASM_SIMP_TAC[REAL_ABS_POS; REAL_ABS_NUM; ARITH];
+    ALL_TAC] THEN
+  MATCH_MP_TAC CONTINUOUS_AT_CLOG THEN
+  REWRITE_TAC[IM_ADD; IM_MUL_II; RE_ADD; RE_MUL_II] THEN
+  ASM_CASES_TAC `Im z = &0` THENL
+   [ASM_REWRITE_TAC[csqrt] THEN
+    ASM_REWRITE_TAC[IM_SUB; RE_SUB; IM_CX; RE_CX; IM_POW_2; RE_POW_2;
+                    REAL_MUL_RZERO; REAL_SUB_REFL] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[REAL_ARITH `&0 <= &1 - (z pow 2 - &0) <=> z pow 2 <= &1 pow 2`;
+                GSYM REAL_LE_SQUARE_ABS] THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; REAL_ABS_NUM; RE; REAL_ADD_LID] THEN
+    REWRITE_TAC[GSYM real_sub; IM; REAL_SUB_LT; REAL_SUB_RZERO] THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 < x ==> x = &0 ==> &0 < y`) THEN
+    MATCH_MP_TAC SQRT_POS_LT THEN
+    ASM_SIMP_TAC[REAL_SUB_LT; ABS_SQUARE_LT_1];
+    ALL_TAC] THEN
+  REWRITE_TAC[csqrt; IM_SUB; RE_SUB; IM_CX; RE_CX; IM_POW_2; RE_POW_2] THEN
+  REWRITE_TAC[REAL_RING `&0 - &2 * x * y = &0 <=> x = &0 \/ y = &0`] THEN
+  ASM_CASES_TAC `Re z = &0` THEN ASM_REWRITE_TAC[RE; IM] THENL
+   [CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[REAL_ARITH `&1 - (&0 - x) = &1 + x`] THEN
+    SIMP_TAC[REAL_POW_2; REAL_LE_ADD; REAL_LE_SQUARE; REAL_POS] THEN
+    REWRITE_TAC[RE; IM; REAL_ADD_LID] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH `a + b = &0 ==> a = --b`)) THEN
+    DISCH_THEN(MP_TAC o AP_TERM `\x:real. x pow 2`) THEN
+    SIMP_TAC[SQRT_POW_2; REAL_POW_NEG; ARITH; REAL_LE_SQUARE; REAL_LE_ADD;
+             REAL_POS] THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP (REAL_ARITH `a + b = &0 ==> a = --b`)) THEN
+  DISCH_THEN(MP_TAC o AP_TERM `\x:real. x pow 2`) THEN
+  SUBGOAL_THEN `&0 < (norm(Cx (&1) - z pow 2) +
+                      &1 - (Re z pow 2 - Im z pow 2)) / &2`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[REAL_ARITH `&0 < (x + y - z) / &2 <=> z - y < x`] THEN
+    REWRITE_TAC[complex_norm] THEN MATCH_MP_TAC REAL_LT_RSQRT THEN
+    REWRITE_TAC[RE_SUB; IM_SUB; RE_CX; IM_CX; RE_POW_2; IM_POW_2] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o
+     GEN_REWRITE_RULE I [GSYM REAL_LT_SQUARE])) THEN
+    REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP REAL_LT_MUL) THEN
+    REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[SQRT_POW_2; REAL_POW_NEG; ARITH; REAL_LT_IMP_LE] THEN
+  REWRITE_TAC[REAL_POW_2; REAL_ARITH
+   `a = (n + &1 - (b - a)) / &2 <=> (a + b) - &1 = n`] THEN
+  REWRITE_TAC[complex_norm] THEN
+  DISCH_THEN(MP_TAC o AP_TERM `\x:real. x pow 2`) THEN
+  SIMP_TAC[SQRT_POW_2; REWRITE_RULE[GSYM REAL_POW_2] REAL_LE_SQUARE;
+           REAL_LE_ADD] THEN
+  REWRITE_TAC[RE_SUB; RE_CX; RE_POW_2; IM_SUB; IM_CX; IM_POW_2] THEN
+  REPEAT(FIRST_X_ASSUM(MP_TAC o
+   GEN_REWRITE_RULE I [GSYM REAL_LT_SQUARE])) THEN
+  REAL_ARITH_TAC);;
+
+let COMPLEX_DIFFERENTIABLE_AT_CACS = prove
+ (`!z. (Im z = &0 ==> abs(Re z) < &1) ==> cacs complex_differentiable at z`,
+  REWRITE_TAC[complex_differentiable] THEN
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CACS]);;
+
+let COMPLEX_DIFFERENTIABLE_WITHIN_CACS = prove
+ (`!s z. (Im z = &0 ==> abs(Re z) < &1)
+         ==> cacs complex_differentiable (at z within s)`,
+  MESON_TAC[COMPLEX_DIFFERENTIABLE_AT_WITHIN;
+            COMPLEX_DIFFERENTIABLE_AT_CACS]);;
+
+add_complex_differentiation_theorems
+ (CONJUNCTS(REWRITE_RULE[FORALL_AND_THM]
+   (MATCH_MP HAS_COMPLEX_DERIVATIVE_CHAIN
+             HAS_COMPLEX_DERIVATIVE_CACS)));;
+
+let CONTINUOUS_AT_CACS = prove
+ (`!z. (Im z = &0 ==> abs(Re z) < &1) ==> cacs continuous at z`,
+  MESON_TAC[HAS_COMPLEX_DERIVATIVE_CACS;
+            HAS_COMPLEX_DERIVATIVE_IMP_CONTINUOUS_AT]);;
+
+let CONTINUOUS_WITHIN_CACS = prove
+ (`!s z. (Im z = &0 ==> abs(Re z) < &1) ==> cacs continuous (at z within s)`,
+  MESON_TAC[CONTINUOUS_AT_WITHIN; CONTINUOUS_AT_CACS]);;
+
+let CONTINUOUS_ON_CACS = prove
+ (`!s. (!z. z IN s /\ Im z = &0 ==> abs(Re z) < &1) ==> cacs continuous_on s`,
+  MESON_TAC[CONTINUOUS_AT_IMP_CONTINUOUS_ON; CONTINUOUS_AT_CACS]);;
+
+let HOLOMORPHIC_ON_CACS = prove
+ (`!s. (!z. z IN s /\ Im z = &0 ==> abs(Re z) < &1) ==> cacs holomorphic_on s`,
+  REWRITE_TAC [holomorphic_on] THEN
+  MESON_TAC [HAS_COMPLEX_DERIVATIVE_AT_WITHIN; HAS_COMPLEX_DERIVATIVE_CACS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some crude range theorems (could be sharpened).                           *)
+(* ------------------------------------------------------------------------- *)
+
+let CASN_RANGE_LEMMA = prove
+ (`!z. abs (Re z) < &1 ==> &0 < Re(ii * z + csqrt(Cx(&1) - z pow 2))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[RE_ADD; RE_MUL_II] THEN
+  REWRITE_TAC[REAL_ARITH `&0 < --i + r <=> i < r`] THEN
+  REWRITE_TAC[csqrt; IM_SUB; RE_SUB; COMPLEX_POW_2; RE_CX; IM_CX] THEN
+  REWRITE_TAC[complex_mul; RE; IM] THEN REWRITE_TAC[GSYM complex_mul] THEN
+  REWRITE_TAC[REAL_ARITH `r * i + i * r = &2 * r * i`] THEN
+  REWRITE_TAC[REAL_SUB_LZERO; REAL_NEG_EQ_0; REAL_ABS_NEG] THEN
+  REWRITE_TAC[REAL_NEG_SUB; REAL_ENTIRE; REAL_OF_NUM_EQ; ARITH] THEN
+  MAP_EVERY ASM_CASES_TAC [`Re z = &0`; `Im z = &0`] THEN
+  ASM_REWRITE_TAC[REAL_SUB_LZERO; REAL_SUB_RZERO] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN
+  REWRITE_TAC[RE; SQRT_1] THEN CONV_TAC REAL_RAT_REDUCE_CONV THENL
+   [REWRITE_TAC[REAL_ARITH `&1 - (&0 - z) = &1 + z`] THEN
+    SIMP_TAC[REAL_LE_ADD; REAL_POS; REAL_LE_SQUARE; RE] THEN
+    MATCH_MP_TAC REAL_LT_RSQRT THEN REAL_ARITH_TAC;
+    SUBGOAL_THEN `Re(z) pow 2 < &1 pow 2` MP_TAC THENL
+     [ONCE_REWRITE_TAC[GSYM REAL_POW2_ABS] THEN MATCH_MP_TAC REAL_POW_LT2 THEN
+      ASM_REWRITE_TAC[REAL_ABS_POS; REAL_ABS_NUM; ARITH];
+      REWRITE_TAC[REAL_POW_ONE] THEN STRIP_TAC] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[RE] THEN
+    TRY(MATCH_MP_TAC SQRT_POS_LT) THEN ASM_REAL_ARITH_TAC;
+    MATCH_MP_TAC REAL_LT_RSQRT THEN
+    REWRITE_TAC[REAL_POW_2; REAL_ARITH
+     `a < (n + &1 - (b - a)) / &2 <=> (a + b) - &1 < n`] THEN
+    REWRITE_TAC[complex_norm] THEN MATCH_MP_TAC REAL_LT_RSQRT THEN
+    REWRITE_TAC[RE_SUB; IM_SUB; RE_CX; IM_CX] THEN
+    REWRITE_TAC[complex_mul; RE; IM] THEN
+    REPEAT(FIRST_X_ASSUM(MP_TAC o
+      GEN_REWRITE_RULE I [GSYM REAL_LT_SQUARE])) THEN
+    REAL_ARITH_TAC]);;
+
+let CACS_RANGE_LEMMA = prove
+ (`!z. abs(Re z) < &1 ==> &0 < Im(z + ii * csqrt(Cx(&1) - z pow 2))`,
+  REPEAT STRIP_TAC THEN MP_TAC(SPEC `--z:complex` CASN_RANGE_LEMMA) THEN
+  ASM_SIMP_TAC[IM_NEG; RE_NEG; IM_ADD; RE_ADD; IM_MUL_II; RE_MUL_II;
+               COMPLEX_POW_NEG; ARITH; REAL_ABS_NEG] THEN
+  REAL_ARITH_TAC);;
+
+let RE_CASN = prove
+ (`!z. Re(casn z) = Im(clog(ii * z + csqrt(Cx(&1) - z pow 2)))`,
+  REWRITE_TAC[casn; COMPLEX_MUL_LNEG; RE_NEG; RE_MUL_II; REAL_NEGNEG]);;
+
+let RE_CACS = prove
+ (`!z. Re(cacs z) = Im(clog(z + ii * csqrt(Cx(&1) - z pow 2)))`,
+  REWRITE_TAC[cacs; COMPLEX_MUL_LNEG; RE_NEG; RE_MUL_II; REAL_NEGNEG]);;
+
+let CASN_BOUNDS = prove
+ (`!z. abs(Re z) < &1 ==> abs(Re(casn z)) < pi / &2`,
+  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[RE_CASN] THEN
+  MATCH_MP_TAC RE_CLOG_POS_LT_IMP THEN ASM_SIMP_TAC[CASN_RANGE_LEMMA]);;
+
+let CACS_BOUNDS = prove
+ (`!z. abs(Re z) < &1 ==> &0 < Re(cacs z) /\ Re(cacs z) < pi`,
+  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[RE_CACS] THEN
+  MATCH_MP_TAC IM_CLOG_POS_LT_IMP THEN ASM_SIMP_TAC[CACS_RANGE_LEMMA]);;
+
+let RE_CACS_BOUNDS = prove
+ (`!z. --pi < Re(cacs z) /\ Re(cacs z) <= pi`,
+  REWRITE_TAC[RE_CACS] THEN SIMP_TAC[CLOG_WORKS; CACS_BODY_LEMMA]);;
+
+let RE_CACS_BOUND = prove
+ (`!z. abs(Re(cacs z)) <= pi`,
+  MP_TAC RE_CACS_BOUNDS THEN MATCH_MP_TAC MONO_FORALL THEN REAL_ARITH_TAC);;
+
+let RE_CASN_BOUNDS = prove
+ (`!z. --pi < Re(casn z) /\ Re(casn z) <= pi`,
+  REWRITE_TAC[RE_CASN] THEN SIMP_TAC[CLOG_WORKS; CASN_BODY_LEMMA]);;
+
+let RE_CASN_BOUND = prove
+ (`!z. abs(Re(casn z)) <= pi`,
+  MP_TAC RE_CASN_BOUNDS THEN MATCH_MP_TAC MONO_FORALL THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Interrelations between the two functions.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let CCOS_CASN_NZ = prove
+ (`!z. ~(z pow 2 = Cx(&1)) ==> ~(ccos(casn z) = Cx(&0))`,
+  REWRITE_TAC[ccos; casn; CEXP_NEG; COMPLEX_RING `ii * --ii * z = z`;
+              COMPLEX_RING `--ii * --ii * z = --z`] THEN
+  SIMP_TAC[CEXP_CLOG; CASN_BODY_LEMMA;
+           COMPLEX_FIELD `~(x = Cx(&0))
+                          ==> ((x + inv(x)) / Cx(&2) = Cx(&0) <=>
+                                x pow 2 = --Cx(&1))`] THEN
+  SIMP_TAC[CSQRT; COMPLEX_FIELD
+              `s pow 2 = Cx(&1) - z pow 2
+               ==> ((ii * z + s) pow 2 = --Cx(&1) <=>
+                    ii * s * z = Cx(&1) - z pow 2)`] THEN
+  GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC(COMPLEX_RING
+   `~(x pow 2 + y pow 2 = Cx(&0)) ==> ~(ii * x = y)`) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  MP_TAC(SPEC `Cx(&1) - z pow 2` CSQRT) THEN CONV_TAC COMPLEX_RING);;
+
+let CSIN_CACS_NZ = prove
+ (`!z. ~(z pow 2 = Cx(&1)) ==> ~(csin(cacs z) = Cx(&0))`,
+  REWRITE_TAC[csin; cacs; CEXP_NEG; COMPLEX_RING `ii * --ii * z = z`;
+              COMPLEX_RING `--ii * --ii * z = --z`] THEN
+  SIMP_TAC[CEXP_CLOG; CACS_BODY_LEMMA;
+           COMPLEX_FIELD `~(x = Cx(&0))
+                          ==> ((x - inv(x)) / (Cx(&2) * ii) = Cx(&0) <=>
+                                x pow 2 = Cx(&1))`] THEN
+  SIMP_TAC[CSQRT; COMPLEX_FIELD
+              `s pow 2 = Cx(&1) - z pow 2
+               ==> ((z + ii * s) pow 2 = Cx(&1) <=>
+                    ii * s * z = Cx(&1) - z pow 2)`] THEN
+  GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC(COMPLEX_RING
+   `~(x pow 2 + y pow 2 = Cx(&0)) ==> ~(ii * x = y)`) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  MP_TAC(SPEC `Cx(&1) - z pow 2` CSQRT) THEN CONV_TAC COMPLEX_RING);;
+
+let CCOS_CSIN_CSQRT = prove
+ (`!z. &0 < cos(Re z) \/ cos(Re z) = &0 /\ Im(z) * sin(Re z) <= &0
+       ==> ccos(z) = csqrt(Cx(&1) - csin(z) pow 2)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC CSQRT_UNIQUE THEN
+  REWRITE_TAC[COMPLEX_EQ_SUB_LADD] THEN ONCE_REWRITE_TAC[COMPLEX_ADD_SYM] THEN
+  REWRITE_TAC[CSIN_CIRCLE] THEN REWRITE_TAC[RE_CCOS; IM_CCOS] THEN
+  ASM_SIMP_TAC[REAL_LT_MUL_EQ; REAL_HALF; REAL_LT_ADD; REAL_EXP_POS_LT] THEN
+  DISJ2_TAC THEN REWRITE_TAC[REAL_MUL_RZERO] THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP(REAL_ARITH
+   `x * y <= &0 ==> &0 <= --x * y`)) THEN
+  REWRITE_TAC[REAL_MUL_POS_LE] THEN
+  SIMP_TAC[REAL_ARITH `x / &2 = &0 <=> x = &0`; REAL_LT_RDIV_EQ; REAL_ADD_LID;
+           REAL_SUB_LT; REAL_LT_LDIV_EQ; REAL_OF_NUM_LT; ARITH; REAL_MUL_LZERO;
+           REAL_SUB_0; REAL_EXP_MONO_LT; REAL_LT_SUB_RADD; REAL_EXP_INJ] THEN
+  REAL_ARITH_TAC);;
+
+let CSIN_CCOS_CSQRT = prove
+ (`!z. &0 < sin(Re z) \/ sin(Re z) = &0 /\ &0 <= Im(z) * cos(Re z)
+       ==> csin(z) = csqrt(Cx(&1) - ccos(z) pow 2)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC CSQRT_UNIQUE THEN
+  REWRITE_TAC[COMPLEX_EQ_SUB_LADD] THEN ONCE_REWRITE_TAC[COMPLEX_ADD_SYM] THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[COMPLEX_ADD_SYM] CSIN_CIRCLE] THEN
+  REWRITE_TAC[RE_CSIN; IM_CSIN] THEN
+  ASM_SIMP_TAC[REAL_LT_MUL_EQ; REAL_HALF; REAL_LT_ADD; REAL_EXP_POS_LT] THEN
+  DISJ2_TAC THEN REWRITE_TAC[REAL_MUL_RZERO] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN
+  REWRITE_TAC[REAL_MUL_POS_LE] THEN
+  SIMP_TAC[REAL_ARITH `x / &2 = &0 <=> x = &0`; REAL_LT_RDIV_EQ; REAL_ADD_LID;
+           REAL_SUB_LT; REAL_LT_LDIV_EQ; REAL_OF_NUM_LT; ARITH; REAL_MUL_LZERO;
+
+           REAL_SUB_0; REAL_EXP_MONO_LT; REAL_LT_SUB_RADD; REAL_EXP_INJ] THEN
+  REAL_ARITH_TAC);;
+
+let CASN_CACS_SQRT_POS = prove
+ (`!z. (&0 < Re z \/ Re z = &0 /\ &0 <= Im z)
+       ==> casn(z) = cacs(csqrt(Cx(&1) - z pow 2))`,
+  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[casn; cacs] THEN
+  AP_TERM_TAC THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC(COMPLEX_RING `w = z ==> ii * z + s = s + ii * w`) THEN
+  MATCH_MP_TAC CSQRT_UNIQUE THEN
+  ASM_REWRITE_TAC[CSQRT] THEN CONV_TAC COMPLEX_RING);;
+
+let CACS_CASN_SQRT_POS = prove
+ (`!z. (&0 < Re z \/ Re z = &0 /\ &0 <= Im z)
+       ==> cacs(z) = casn(csqrt(Cx(&1) - z pow 2))`,
+  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[casn; cacs] THEN
+  AP_TERM_TAC THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC(COMPLEX_RING `w = z ==> z + ii * s = ii * s + w`) THEN
+  MATCH_MP_TAC CSQRT_UNIQUE THEN
+  ASM_REWRITE_TAC[CSQRT] THEN CONV_TAC COMPLEX_RING);;
+
+let CSIN_CACS = prove
+ (`!z. &0 < Re z \/ Re(z) = &0 /\ &0 <= Im z
+       ==> csin(cacs z) = csqrt(Cx(&1) - z pow 2)`,
+  GEN_TAC THEN DISCH_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM CSIN_CASN] THEN
+  AP_TERM_TAC THEN MATCH_MP_TAC CACS_CASN_SQRT_POS THEN
+  ASM_REWRITE_TAC[]);;
+
+let CCOS_CASN = prove
+ (`!z. &0 < Re z \/ Re(z) = &0 /\ &0 <= Im z
+       ==> ccos(casn z) = csqrt(Cx(&1) - z pow 2)`,
+  GEN_TAC THEN DISCH_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM CCOS_CACS] THEN
+  AP_TERM_TAC THEN MATCH_MP_TAC CASN_CACS_SQRT_POS THEN
+  ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real arcsin.                                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let asn = new_definition `asn(x) = Re(casn(Cx x))`;;
+
+let REAL_ASN = prove
+ (`!z. real z /\ abs(Re z) <= &1 ==> real(casn z)`,
+  GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  GEN_REWRITE_TAC LAND_CONV [REAL] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN SPEC_TAC(`Re z`,`x:real`) THEN
+  REWRITE_TAC[real; casn; COMPLEX_MUL_LNEG; IM_NEG; IM_MUL_II] THEN
+  GEN_TAC THEN REWRITE_TAC[RE_CX; REAL_NEG_EQ_0] THEN DISCH_TAC THEN
+  MATCH_MP_TAC NORM_CEXP_IMAGINARY THEN
+  SIMP_TAC[CEXP_CLOG; CASN_BODY_LEMMA; NORM_EQ_SQUARE] THEN
+  REWRITE_TAC[DOT_SQUARE_NORM; COMPLEX_SQNORM] THEN
+  REWRITE_TAC[RE_ADD; IM_ADD; RE_MUL_II; IM_MUL_II; RE_CX; IM_CX] THEN
+  ASM_SIMP_TAC[GSYM CX_POW; GSYM CX_SUB; GSYM CX_SQRT; REAL_SUB_LE;
+               ABS_SQUARE_LE_1; RE_CX; IM_CX; REAL_NEG_0; REAL_ADD_LID;
+               SQRT_POW_2] THEN
+  REAL_ARITH_TAC);;
+
+let CX_ASN = prove
+ (`!x. abs(x) <= &1 ==> Cx(asn x) = casn(Cx x)`,
+  REWRITE_TAC[asn] THEN MESON_TAC[REAL; RE_CX; REAL_CX; REAL_ASN]);;
+
+let SIN_ASN = prove
+ (`!y. --(&1) <= y /\ y <= &1 ==> sin(asn(y)) = y`,
+  REWRITE_TAC[REAL_ARITH `--(&1) <= y /\ y <= &1 <=> abs(y) <= &1`] THEN
+  ONCE_REWRITE_TAC[GSYM CX_INJ] THEN SIMP_TAC[CX_ASN; CX_SIN; CSIN_CASN]);;
+
+let ASN_SIN = prove
+ (`!x. --(pi / &2) <= x /\ x <= pi / &2 ==> asn(sin(x)) = x`,
+  ONCE_REWRITE_TAC[GSYM CX_INJ] THEN SIMP_TAC[CX_ASN; SIN_BOUND; CX_SIN] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CASN_CSIN THEN
+  REWRITE_TAC[IM_CX; RE_CX] THEN REPEAT(POP_ASSUM MP_TAC) THEN
+  REAL_ARITH_TAC);;
+
+let ASN_BOUNDS_LT = prove
+ (`!y. --(&1) < y /\ y < &1 ==> --(pi / &2) < asn(y) /\ asn(y) < pi / &2`,
+  GEN_TAC THEN REWRITE_TAC[asn] THEN
+  MP_TAC(SPEC `Cx y` CASN_BOUNDS) THEN
+  REWRITE_TAC[RE_CX] THEN REAL_ARITH_TAC);;
+
+let ASN_0 = prove
+ (`asn(&0) = &0`,
+  REWRITE_TAC[asn; CASN_0; RE_CX]);;
+
+let ASN_1 = prove
+ (`asn(&1) = pi / &2`,
+  REWRITE_TAC[asn; CASN_1; RE_CX]);;
+
+let ASN_NEG_1 = prove
+ (`asn(-- &1) = --(pi / &2)`,
+  REWRITE_TAC[asn; CX_NEG; CASN_NEG_1; RE_CX; RE_NEG]);;
+
+let ASN_BOUNDS = prove
+ (`!y. --(&1) <= y /\ y <= &1 ==> --(pi / &2) <= asn(y) /\ asn(y) <= pi / &2`,
+  REWRITE_TAC[REAL_LE_LT] THEN REPEAT STRIP_TAC THEN
+  MAP_EVERY MP_TAC [ASN_1; ASN_NEG_1; SPEC `y:real` ASN_BOUNDS_LT] THEN
+  ASM_REWRITE_TAC[] THEN REPEAT(POP_ASSUM MP_TAC) THEN
+  MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+let ASN_NEG = prove
+ (`!x. -- &1 <= x /\ x <= &1 ==> asn(--x) = --asn(x)`,
+  GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o RAND_CONV)
+     [GSYM(MATCH_MP SIN_ASN th)]) THEN
+  REWRITE_TAC[GSYM SIN_NEG] THEN MATCH_MP_TAC ASN_SIN THEN
+  REWRITE_TAC[REAL_ARITH `--a <= --x /\ --x <= a <=> --a <= x /\ x <= a`] THEN
+  ASM_SIMP_TAC[ASN_BOUNDS]);;
+
+let COS_ASN_NZ = prove
+ (`!x. --(&1) < x /\ x < &1 ==> ~(cos(asn(x)) = &0)`,
+  ONCE_REWRITE_TAC[GSYM CX_INJ] THEN SIMP_TAC[CX_ASN; CX_COS;
+    REAL_ARITH `--(&1) < x /\ x < &1 ==> abs(x) <= &1`] THEN
+  GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC CCOS_CASN_NZ THEN
+  SIMP_TAC[COMPLEX_RING `x pow 2 = Cx(&1) <=> x = Cx(&1) \/ x = --Cx(&1)`] THEN
+  REWRITE_TAC[GSYM CX_NEG; CX_INJ] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let ASN_MONO_LT_EQ = prove
+ (`!x y. abs(x) <= &1 /\ abs(y) <= &1 ==> (asn(x) < asn(y) <=> x < y)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `sin(asn(x)) < sin(asn(y))` THEN CONJ_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC SIN_MONO_LT_EQ THEN
+    ONCE_REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THEN MATCH_MP_TAC ASN_BOUNDS;
+    BINOP_TAC THEN MATCH_MP_TAC SIN_ASN] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let ASN_MONO_LE_EQ = prove
+ (`!x y. abs(x) <= &1 /\ abs(y) <= &1 ==> (asn(x) <= asn(y) <=> x <= y)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN
+  ASM_SIMP_TAC[ASN_MONO_LT_EQ]);;
+
+let ASN_MONO_LT = prove
+ (`!x y. --(&1) <= x /\ x < y /\ y <= &1 ==> asn(x) < asn(y)`,
+  MP_TAC ASN_MONO_LT_EQ THEN REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  REAL_ARITH_TAC);;
+
+let ASN_MONO_LE = prove
+ (`!x y. --(&1) <= x /\ x <= y /\ y <= &1 ==> asn(x) <= asn(y)`,
+  MP_TAC ASN_MONO_LE_EQ THEN REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  REAL_ARITH_TAC);;
+
+let COS_ASN = prove
+ (`!x. --(&1) <= x /\ x <= &1 ==> cos(asn x) = sqrt(&1 - x pow 2)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(GSYM SQRT_UNIQUE) THEN
+  ASM_SIMP_TAC[ASN_BOUNDS; COS_POS_PI_LE; REAL_EQ_SUB_RADD] THEN
+  ASM_MESON_TAC[SIN_ASN; SIN_CIRCLE; REAL_ADD_SYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real arccosine.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let acs = new_definition `acs(x) = Re(cacs(Cx x))`;;
+
+let REAL_ACS = prove
+ (`!z. real z /\ abs(Re z) <= &1 ==> real(cacs z)`,
+  GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  GEN_REWRITE_TAC LAND_CONV [REAL] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN SPEC_TAC(`Re z`,`x:real`) THEN
+  REWRITE_TAC[real; cacs; COMPLEX_MUL_LNEG; IM_NEG; IM_MUL_II] THEN
+  GEN_TAC THEN REWRITE_TAC[RE_CX; REAL_NEG_EQ_0] THEN DISCH_TAC THEN
+  MATCH_MP_TAC NORM_CEXP_IMAGINARY THEN
+  SIMP_TAC[CEXP_CLOG; CACS_BODY_LEMMA; NORM_EQ_SQUARE] THEN
+  REWRITE_TAC[DOT_SQUARE_NORM; COMPLEX_SQNORM] THEN
+  REWRITE_TAC[RE_ADD; IM_ADD; RE_MUL_II; IM_MUL_II; RE_CX; IM_CX] THEN
+  ASM_SIMP_TAC[GSYM CX_POW; GSYM CX_SUB; GSYM CX_SQRT; REAL_SUB_LE;
+               ABS_SQUARE_LE_1; RE_CX; IM_CX; REAL_NEG_0; REAL_ADD_LID;
+               SQRT_POW_2] THEN
+  REAL_ARITH_TAC);;
+
+let CX_ACS = prove
+ (`!x. abs(x) <= &1 ==> Cx(acs x) = cacs(Cx x)`,
+  REWRITE_TAC[acs] THEN MESON_TAC[REAL; RE_CX; REAL_CX; REAL_ACS]);;
+
+let COS_ACS = prove
+ (`!y. --(&1) <= y /\ y <= &1 ==> cos(acs(y)) = y`,
+  REWRITE_TAC[REAL_ARITH `--(&1) <= y /\ y <= &1 <=> abs(y) <= &1`] THEN
+  ONCE_REWRITE_TAC[GSYM CX_INJ] THEN SIMP_TAC[CX_ACS; CX_COS; CCOS_CACS]);;
+
+let ACS_COS = prove
+ (`!x. &0 <= x /\ x <= pi ==> acs(cos(x)) = x`,
+  ONCE_REWRITE_TAC[GSYM CX_INJ] THEN SIMP_TAC[CX_ACS; COS_BOUND; CX_COS] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CACS_CCOS THEN
+  REWRITE_TAC[IM_CX; RE_CX] THEN ASM_REAL_ARITH_TAC);;
+
+let ACS_BOUNDS_LT = prove
+ (`!y. --(&1) < y /\ y < &1 ==> &0 < acs(y) /\ acs(y) < pi`,
+  GEN_TAC THEN REWRITE_TAC[acs] THEN
+  MP_TAC(SPEC `Cx y` CACS_BOUNDS) THEN
+  REWRITE_TAC[RE_CX] THEN REAL_ARITH_TAC);;
+
+let ACS_0 = prove
+ (`acs(&0) = pi / &2`,
+  REWRITE_TAC[acs; CACS_0; RE_CX]);;
+
+let ACS_1 = prove
+ (`acs(&1) = &0`,
+  REWRITE_TAC[acs; CACS_1; RE_CX]);;
+
+let ACS_NEG_1 = prove
+ (`acs(-- &1) = pi`,
+  REWRITE_TAC[acs; CX_NEG; CACS_NEG_1; RE_CX; RE_NEG]);;
+
+let ACS_BOUNDS = prove
+ (`!y. --(&1) <= y /\ y <= &1 ==> &0 <= acs(y) /\ acs(y) <= pi`,
+  REWRITE_TAC[REAL_LE_LT] THEN REPEAT STRIP_TAC THEN
+  MAP_EVERY MP_TAC [ACS_1; ACS_NEG_1; SPEC `y:real` ACS_BOUNDS_LT] THEN
+  ASM_REWRITE_TAC[] THEN REPEAT(POP_ASSUM MP_TAC) THEN
+  MP_TAC PI_POS THEN REAL_ARITH_TAC);;
+
+let ACS_NEG = prove
+ (`!x. -- &1 <= x /\ x <= &1 ==> acs(--x) = pi - acs(x)`,
+  GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o RAND_CONV)
+     [GSYM(MATCH_MP COS_ACS th)]) THEN
+  ONCE_REWRITE_TAC[GSYM COS_NEG] THEN REWRITE_TAC[GSYM COS_PERIODIC_PI] THEN
+  REWRITE_TAC[REAL_ARITH `--x + y:real = y - x`] THEN MATCH_MP_TAC ACS_COS THEN
+  SIMP_TAC[REAL_ARITH `&0 <= p - x /\ p - x <= p <=> &0 <= x /\ x <= p`] THEN
+  ASM_SIMP_TAC[ACS_BOUNDS]);;
+
+let SIN_ACS_NZ = prove
+ (`!x. --(&1) < x /\ x < &1 ==> ~(sin(acs(x)) = &0)`,
+  ONCE_REWRITE_TAC[GSYM CX_INJ] THEN SIMP_TAC[CX_ACS; CX_SIN;
+    REAL_ARITH `--(&1) < x /\ x < &1 ==> abs(x) <= &1`] THEN
+  GEN_TAC THEN STRIP_TAC THEN MATCH_MP_TAC CSIN_CACS_NZ THEN
+  SIMP_TAC[COMPLEX_RING `x pow 2 = Cx(&1) <=> x = Cx(&1) \/ x = --Cx(&1)`] THEN
+  REWRITE_TAC[GSYM CX_NEG; CX_INJ] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let ACS_MONO_LT_EQ = prove
+ (`!x y. abs(x) <= &1 /\ abs(y) <= &1 ==> (acs(x) < acs(y) <=> y < x)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `cos(acs(y)) < cos(acs(x))` THEN CONJ_TAC THENL
+   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC COS_MONO_LT_EQ THEN
+    ONCE_REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THEN MATCH_MP_TAC ACS_BOUNDS;
+    BINOP_TAC THEN MATCH_MP_TAC COS_ACS] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let ACS_MONO_LE_EQ = prove
+ (`!x y. abs(x) <= &1 /\ abs(y) <= &1 ==> (acs(x) <= acs(y) <=> y <= x)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN
+  ASM_SIMP_TAC[ACS_MONO_LT_EQ]);;
+
+let ACS_MONO_LT = prove
+ (`!x y. --(&1) <= x /\ x < y /\ y <= &1 ==> acs(y) < acs(x)`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(SPECL [`y:real`; `x:real`] ACS_MONO_LT_EQ) THEN
+  REAL_ARITH_TAC);;
+
+let ACS_MONO_LE = prove
+ (`!x y. --(&1) <= x /\ x <= y /\ y <= &1 ==> acs(y) <= acs(x)`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(SPECL [`y:real`; `x:real`] ACS_MONO_LE_EQ) THEN
+  REAL_ARITH_TAC);;
+
+let SIN_ACS = prove
+ (`!x. --(&1) <= x /\ x <= &1 ==> sin(acs x) = sqrt(&1 - x pow 2)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(GSYM SQRT_UNIQUE) THEN
+  ASM_SIMP_TAC[ACS_BOUNDS; SIN_POS_PI_LE; REAL_EQ_SUB_RADD] THEN
+  ASM_MESON_TAC[COS_ACS; SIN_CIRCLE]);;
+
+let ACS_INJ = prove
+ (`!x y. abs(x) <= &1 /\ abs(y) <= &1 ==> (acs x = acs y <=> x = y)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN
+  ASM_SIMP_TAC[ACS_MONO_LE_EQ] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some interrelationships among the real inverse trig functions.            *)
+(* ------------------------------------------------------------------------- *)
+
+let ACS_ATN = prove
+ (`!x. -- &1 < x /\ x < &1 ==> acs(x) = pi / &2 - atn(x / sqrt(&1 - x pow 2))`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `x:real = p - y <=> y - (p - x) = &0`] THEN
+  MATCH_MP_TAC SIN_EQ_0_PI THEN
+  ASM_SIMP_TAC[ATN_BOUND; ACS_BOUNDS; REAL_LT_IMP_LE; REAL_ARITH
+   `abs(x) < pi / &2 /\ &0 <= y /\ y <= pi
+    ==> --pi < x - (pi / &2 - y) /\ x - (pi / &2 - y) < pi`] THEN
+  SUBGOAL_THEN `tan(atn(x / sqrt(&1 - x pow 2))) = tan(pi / &2 - acs x)`
+  MP_TAC THENL
+   [REWRITE_TAC[TAN_COT; ATN_TAN] THEN REWRITE_TAC[tan] THEN
+    ASM_SIMP_TAC[SIN_ACS; COS_ACS; REAL_LT_IMP_LE; REAL_INV_DIV];
+    ALL_TAC] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM REAL_SUB_0] THEN
+  ASM_SIMP_TAC[SIN_ACS_NZ; GSYM SIN_COS; COS_ATN_NZ; REAL_SUB_TAN; REAL_FIELD
+   `~(y = &0) /\ ~(z = &0) ==> (x / (y * z) = &0 <=> x = &0)`]);;
+
+let ASN_PLUS_ACS = prove
+ (`!x. -- &1 <= x /\ x <= &1 ==> asn(x) + acs(x) = pi / &2`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `x + y:real = p <=> x = p - y`] THEN
+  MATCH_MP_TAC SIN_INJ_PI THEN
+  ASM_SIMP_TAC[SIN_PI2; COS_PI2; SIN_SUB; REAL_MUL_LZERO; REAL_SUB_RZERO] THEN
+  ASM_SIMP_TAC[SIN_ASN; COS_ACS; REAL_MUL_LID] THEN
+  REWRITE_TAC[REAL_ARITH `--p <= p - x <=> x <= &2 * p`;
+              REAL_ARITH `p - x <= p <=> &0 <= x`] THEN
+  ASM_SIMP_TAC[ASN_BOUNDS; ACS_BOUNDS; REAL_ARITH `&2 * x / &2 = x`]);;
+
+let ASN_ACS = prove
+ (`!x. -- &1 <= x /\ x <= &1 ==> asn(x) = pi / &2 - acs(x)`,
+  SIMP_TAC[REAL_EQ_SUB_LADD; ASN_PLUS_ACS]);;
+
+let ACS_ASN = prove
+ (`!x. -- &1 <= x /\ x <= &1 ==> acs(x) = pi / &2 - asn(x)`,
+  SIMP_TAC[ASN_ACS] THEN REAL_ARITH_TAC);;
+
+let ASN_ATN = prove
+ (`!x. -- &1 < x /\ x < &1 ==> asn(x) = atn(x / sqrt(&1 - x pow 2))`,
+  SIMP_TAC[ASN_ACS; REAL_LT_IMP_LE; ACS_ATN] THEN REAL_ARITH_TAC);;
+
+let ASN_ACS_SQRT_POS = prove
+ (`!x. &0 <= x /\ x <= &1 ==> asn(x) = acs(sqrt(&1 - x pow 2))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[asn; acs] THEN
+  ASM_SIMP_TAC[CX_SQRT; REAL_SUB_LE; REAL_POW_1_LE; CX_SUB; CX_POW] THEN
+  AP_TERM_TAC THEN MATCH_MP_TAC CASN_CACS_SQRT_POS THEN
+  ASM_REWRITE_TAC[RE_CX; IM_CX] THEN ASM_REAL_ARITH_TAC);;
+
+let ASN_ACS_SQRT_NEG = prove
+ (`!x. -- &1 <= x /\ x <= &0 ==> asn(x) = --acs(sqrt(&1 - x pow 2))`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `x = --y <=> (--x:real) = y`] THEN
+  ASM_SIMP_TAC[GSYM ASN_NEG; REAL_ARITH `x <= &0 ==> x <= &1`] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `(x:real) pow 2 = (--x) pow 2`] THEN
+  MATCH_MP_TAC ASN_ACS_SQRT_POS THEN ASM_REAL_ARITH_TAC);;
+
+let ACS_ASN_SQRT_POS = prove
+ (`!x. &0 <= x /\ x <= &1 ==> acs(x) = asn(sqrt(&1 - x pow 2))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[asn; acs] THEN
+  ASM_SIMP_TAC[CX_SQRT; REAL_SUB_LE; REAL_POW_1_LE; CX_SUB; CX_POW] THEN
+  AP_TERM_TAC THEN MATCH_MP_TAC CACS_CASN_SQRT_POS THEN
+  ASM_REWRITE_TAC[RE_CX; IM_CX] THEN ASM_REAL_ARITH_TAC);;
+
+let ACS_ASN_SQRT_NEG = prove
+ (`!x. -- &1 <= x /\ x <= &0 ==> acs(x) = pi - asn(sqrt(&1 - x pow 2))`,
+  REPEAT STRIP_TAC THEN MP_TAC(SPEC `--x:real` ACS_ASN_SQRT_POS) THEN
+  ANTS_TAC THENL [ASM_REAL_ARITH_TAC; SIMP_TAC[REAL_POW_NEG; ARITH]] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM REAL_NEG_NEG] THEN
+  MATCH_MP_TAC ACS_NEG THEN ASM_REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* More delicate continuity results for arcsin and arccos.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let CONTINUOUS_ON_CASN_REAL = prove
+ (`casn continuous_on {w | real w /\ abs(Re w) <= &1}`,
+  MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+  EXISTS_TAC `IMAGE csin {z | real z /\ abs(Re z) <= pi / &2}` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_INVERSE THEN
+    REWRITE_TAC[CONTINUOUS_ON_CSIN] THEN CONJ_TAC THENL
+     [REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC BOUNDED_SUBSET THEN
+        EXISTS_TAC `cball(Cx(&0),pi / &2)` THEN
+        REWRITE_TAC[BOUNDED_CBALL; SUBSET; IN_ELIM_THM; IN_CBALL] THEN
+        REWRITE_TAC[dist; COMPLEX_SUB_LZERO; NORM_NEG; real] THEN
+        X_GEN_TAC `z:complex` THEN
+        MP_TAC(SPEC `z:complex` COMPLEX_NORM_LE_RE_IM) THEN REAL_ARITH_TAC;
+        SIMP_TAC[SET_RULE `{x | P x /\ Q x} = {x | P x} INTER {x | Q x}`;
+                  GSYM REAL_BOUNDS_LE] THEN
+        SIMP_TAC[CLOSED_INTER; CLOSED_REAL_SET; CLOSED_HALFSPACE_RE_LE;
+                 REWRITE_RULE[real_ge] CLOSED_HALFSPACE_RE_GE]];
+      SIMP_TAC[SUBSET; IMP_CONJ; FORALL_REAL; IN_ELIM_THM; RE_CX] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC CASN_CSIN THEN
+      REWRITE_TAC[RE_CX; IM_CX] THEN ASM_REAL_ARITH_TAC];
+    SIMP_TAC[SUBSET; IMP_CONJ; FORALL_REAL; IN_ELIM_THM; RE_CX; IN_IMAGE] THEN
+    X_GEN_TAC `x:real` THEN DISCH_TAC THEN
+    EXISTS_TAC `Cx(asn x)` THEN
+    ASM_SIMP_TAC[RE_CX; ASN_BOUNDS; REAL_BOUNDS_LE; REAL_CX; SIN_ASN;
+                 GSYM CX_SIN] THEN
+    ASM_MESON_TAC[REAL_BOUNDS_LE; ASN_BOUNDS]]);;
+
+let CONTINUOUS_WITHIN_CASN_REAL = prove
+ (`!z. casn continuous (at z within {w | real w /\ abs(Re w) <= &1})`,
+  GEN_TAC THEN ASM_CASES_TAC `z IN {w | real w /\ abs(Re w) <= &1}` THENL
+   [ASM_SIMP_TAC[REWRITE_RULE[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN]
+      CONTINUOUS_ON_CASN_REAL];
+    MATCH_MP_TAC CONTINUOUS_WITHIN_CLOSED_NONTRIVIAL THEN
+    ASM_REWRITE_TAC[] THEN REWRITE_TAC[GSYM REAL_BOUNDS_LE] THEN
+    ASM_SIMP_TAC[SET_RULE `{x | P x /\ Q x} = {x | P x} INTER {x | Q x}`] THEN
+    SIMP_TAC[CLOSED_INTER; CLOSED_REAL_SET; CLOSED_HALFSPACE_RE_LE;
+             REWRITE_RULE[real_ge] CLOSED_HALFSPACE_RE_GE]]);;
+
+let CONTINUOUS_ON_CACS_REAL = prove
+ (`cacs continuous_on {w | real w /\ abs(Re w) <= &1}`,
+  MATCH_MP_TAC CONTINUOUS_ON_SUBSET THEN
+  EXISTS_TAC `IMAGE ccos {z | real z /\ &0 <= Re z /\ Re z <= pi}` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_INVERSE THEN
+    REWRITE_TAC[CONTINUOUS_ON_CCOS] THEN CONJ_TAC THENL
+     [REWRITE_TAC[COMPACT_EQ_BOUNDED_CLOSED] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC BOUNDED_SUBSET THEN
+        EXISTS_TAC `cball(Cx(&0),&2 * pi)` THEN
+        REWRITE_TAC[BOUNDED_CBALL; SUBSET; IN_ELIM_THM; IN_CBALL] THEN
+        REWRITE_TAC[dist; COMPLEX_SUB_LZERO; NORM_NEG; real] THEN
+        X_GEN_TAC `z:complex` THEN
+        MP_TAC(SPEC `z:complex` COMPLEX_NORM_LE_RE_IM) THEN REAL_ARITH_TAC;
+        SIMP_TAC[SET_RULE `{x | P x /\ Q x} = {x | P x} INTER {x | Q x}`] THEN
+        SIMP_TAC[CLOSED_INTER; CLOSED_REAL_SET; CLOSED_HALFSPACE_RE_LE;
+                 REWRITE_RULE[real_ge] CLOSED_HALFSPACE_RE_GE]];
+      SIMP_TAC[SUBSET; IMP_CONJ; FORALL_REAL; IN_ELIM_THM; RE_CX] THEN
+      REPEAT STRIP_TAC THEN MATCH_MP_TAC CACS_CCOS THEN
+      REWRITE_TAC[RE_CX; IM_CX] THEN ASM_REAL_ARITH_TAC];
+    SIMP_TAC[SUBSET; IMP_CONJ; FORALL_REAL; IN_ELIM_THM; RE_CX; IN_IMAGE] THEN
+    X_GEN_TAC `x:real` THEN DISCH_TAC THEN
+    EXISTS_TAC `Cx(acs x)` THEN
+    ASM_SIMP_TAC[RE_CX; ACS_BOUNDS; REAL_BOUNDS_LE; REAL_CX; COS_ACS;
+                 GSYM CX_COS]]);;
+
+let CONTINUOUS_WITHIN_CACS_REAL = prove
+ (`!z. cacs continuous (at z within {w | real w /\ abs(Re w) <= &1})`,
+  GEN_TAC THEN ASM_CASES_TAC `z IN {w | real w /\ abs(Re w) <= &1}` THENL
+   [ASM_SIMP_TAC[REWRITE_RULE[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN]
+      CONTINUOUS_ON_CACS_REAL];
+    MATCH_MP_TAC CONTINUOUS_WITHIN_CLOSED_NONTRIVIAL THEN
+    ASM_REWRITE_TAC[] THEN REWRITE_TAC[GSYM REAL_BOUNDS_LE] THEN
+    ASM_SIMP_TAC[SET_RULE `{x | P x /\ Q x} = {x | P x} INTER {x | Q x}`] THEN
+    SIMP_TAC[CLOSED_INTER; CLOSED_REAL_SET; CLOSED_HALFSPACE_RE_LE;
+             REWRITE_RULE[real_ge] CLOSED_HALFSPACE_RE_GE]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some limits, most involving sequences of transcendentals.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let LIM_LOG_OVER_POWER = prove
+ (`!s. &0 < Re s
+       ==> ((\n. clog(Cx(&n)) / Cx(&n) cpow s) --> Cx(&0)) sequentially`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[LIM_SEQUENTIALLY] THEN
+  FIRST_ASSUM(MP_TAC o SPEC `&2` o MATCH_MP REAL_ARCH) THEN
+  DISCH_THEN(X_CHOOSE_THEN `N:num` MP_TAC) THEN
+  ASM_CASES_TAC `N = 0` THEN
+  ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_OF_NUM_LT; ARITH] THEN DISCH_TAC THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  MP_TAC(ISPEC `(&N / e) pow N + &1` REAL_ARCH_SIMPLE) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `M:num` THEN
+  ASM_CASES_TAC `M = 0` THENL
+   [ASM_REWRITE_TAC[] THEN MATCH_MP_TAC(TAUT `~a ==> a ==> b`) THEN
+    MATCH_MP_TAC(REAL_ARITH `&0 <= x ==> ~(x + &1 <= &0)`) THEN
+    ASM_SIMP_TAC[REAL_POW_LE; REAL_POS; REAL_LT_IMP_LE; REAL_LE_DIV];
+    ALL_TAC] THEN
+  STRIP_TAC THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+  SUBGOAL_THEN `~(n = 0)` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[dist; COMPLEX_SUB_RZERO; COMPLEX_NORM_DIV] THEN
+  ASM_SIMP_TAC[NORM_CPOW_REAL; REAL_CX; RE_CX; REAL_OF_NUM_LT; LT_NZ] THEN
+  ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_EXP_POS_LT] THEN
+  ASM_SIMP_TAC[GSYM CX_LOG; REAL_OF_NUM_LT; LT_NZ; COMPLEX_NORM_CX] THEN
+  ASM_SIMP_TAC[real_abs; LOG_POS; REAL_OF_NUM_LE;
+               ARITH_RULE `~(n = 0) ==> 1 <= n`] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN
+  EXISTS_TAC `&N * log(exp(log(&n) / &N))` THEN CONJ_TAC THENL
+   [ASM_SIMP_TAC[LOG_EXP; REAL_LE_REFL; REAL_DIV_LMUL; REAL_OF_NUM_EQ];
+    ALL_TAC] THEN
+  MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `&N * exp(log(&n) / &N)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC REAL_LE_LMUL THEN REWRITE_TAC[REAL_POS] THEN
+    MATCH_MP_TAC REAL_LE_TRANS THEN
+    EXISTS_TAC `log(&1 + exp(log(&n) / &N))` THEN CONJ_TAC THENL
+     [MATCH_MP_TAC LOG_MONO_LE_IMP THEN
+      REWRITE_TAC[REAL_EXP_POS_LT] THEN REAL_ARITH_TAC;
+      MATCH_MP_TAC LOG_LE THEN REWRITE_TAC[REAL_EXP_POS_LE]];
+    ALL_TAC] THEN
+  SIMP_TAC[GSYM REAL_LT_RDIV_EQ; REAL_EXP_POS_LT] THEN
+  REWRITE_TAC[real_div; GSYM REAL_MUL_ASSOC; GSYM REAL_EXP_NEG;
+              GSYM REAL_EXP_ADD] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM REAL_LT_LDIV_EQ] THEN
+  MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `exp(log(&n) / &N)` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[REAL_EXP_MONO_LE] THEN
+    REWRITE_TAC[REAL_ARITH
+     `l / n <= r * l + --(l * inv n) <=>  &0 <= l * (r - &2 / n)`] THEN
+    MATCH_MP_TAC REAL_LE_MUL THEN
+    ASM_SIMP_TAC[LOG_POS; REAL_OF_NUM_LE; ARITH_RULE `1 <= n <=> ~(n = 0)`;
+                 REAL_SUB_LE; REAL_LE_LDIV_EQ; REAL_OF_NUM_LT; LT_NZ] THEN
+    ASM_REAL_ARITH_TAC] THEN
+  W(MP_TAC o PART_MATCH (rand o rand) LOG_MONO_LT o snd) THEN
+  ASM_SIMP_TAC[REAL_LT_DIV; REAL_OF_NUM_LT; LT_NZ; REAL_EXP_POS_LT] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[LOG_EXP] THEN
+  ASM_SIMP_TAC[REAL_LT_RDIV_EQ; REAL_OF_NUM_LT; LT_NZ] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM LOG_POW; REAL_LT_DIV; REAL_OF_NUM_LT; LT_NZ] THEN
+  MATCH_MP_TAC LOG_MONO_LT_IMP THEN
+  ASM_SIMP_TAC[REAL_POW_LT; REAL_LT_DIV; REAL_OF_NUM_LT; LT_NZ] THEN
+  MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `&M` THEN
+  ASM_REWRITE_TAC[REAL_OF_NUM_LE] THEN ASM_REAL_ARITH_TAC);;
+
+let LIM_LOG_OVER_N = prove
+ (`((\n. clog(Cx(&n)) / Cx(&n)) --> Cx(&0)) sequentially`,
+  MP_TAC(SPEC `Cx(&1)` LIM_LOG_OVER_POWER) THEN SIMP_TAC[RE_CX; REAL_LT_01] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LIM_TRANSFORM_EVENTUALLY) THEN
+  REWRITE_TAC[EVENTUALLY_SEQUENTIALLY; CPOW_N; CX_INJ] THEN EXISTS_TAC `1` THEN
+  SIMP_TAC[COMPLEX_POW_1; REAL_OF_NUM_EQ; ARITH_RULE `1 <= n <=> ~(n = 0)`]);;
+
+let LIM_1_OVER_POWER = prove
+ (`!s. &0 < Re s
+       ==> ((\n. Cx(&1) / Cx(&n) cpow s) --> Cx(&0)) sequentially`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC LIM_NULL_COMPLEX_BOUND THEN
+  EXISTS_TAC `\n. clog(Cx(&n)) / Cx(&n) cpow s` THEN
+  ASM_SIMP_TAC[LIM_LOG_OVER_POWER] THEN
+  REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN
+  MP_TAC(ISPEC `exp(&1)` REAL_ARCH_SIMPLE) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `N:num` THEN
+  ASM_CASES_TAC `N = 0` THENL
+   [ASM_SIMP_TAC[GSYM REAL_NOT_LT; REAL_EXP_POS_LT]; ALL_TAC] THEN
+  DISCH_TAC THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+  REWRITE_TAC[complex_div; COMPLEX_NORM_MUL] THEN
+  MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+  SUBGOAL_THEN `~(n = 0)` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM CX_LOG; REAL_OF_NUM_LT; LT_NZ;
+               COMPLEX_NORM_CX; REAL_ABS_NUM] THEN
+  MATCH_MP_TAC(REAL_ARITH `x <= y ==> x <= abs y`) THEN
+  ONCE_REWRITE_TAC[GSYM REAL_EXP_MONO_LE] THEN
+  ASM_SIMP_TAC[EXP_LOG; REAL_OF_NUM_LT; LT_NZ] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[GSYM REAL_OF_NUM_LE]) THEN ASM_REAL_ARITH_TAC);;
+
+let LIM_1_OVER_N = prove
+ (`((\n. Cx(&1) / Cx(&n)) --> Cx(&0)) sequentially`,
+  MP_TAC(SPEC `Cx(&1)` LIM_1_OVER_POWER) THEN SIMP_TAC[RE_CX; REAL_LT_01] THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] LIM_TRANSFORM_EVENTUALLY) THEN
+  REWRITE_TAC[EVENTUALLY_SEQUENTIALLY; CPOW_N; CX_INJ] THEN EXISTS_TAC `1` THEN
+  SIMP_TAC[COMPLEX_POW_1; REAL_OF_NUM_EQ; ARITH_RULE `1 <= n <=> ~(n = 0)`]);;
+
+let LIM_INV_N = prove
+ (`((\n. inv(Cx(&n))) --> Cx(&0)) sequentially`,
+  MP_TAC LIM_1_OVER_N THEN REWRITE_TAC[complex_div; COMPLEX_MUL_LID]);;
+
+let LIM_1_OVER_LOG = prove
+ (`((\n. Cx(&1) / clog(Cx(&n))) --> Cx(&0)) sequentially`,
+  REWRITE_TAC[LIM_SEQUENTIALLY] THEN X_GEN_TAC `e:real` THEN
+  DISCH_TAC THEN X_CHOOSE_TAC `N:num` (SPEC `exp(inv e)` REAL_ARCH_SIMPLE) THEN
+  EXISTS_TAC `N + 1` THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
+  REWRITE_TAC[dist; COMPLEX_SUB_RZERO; COMPLEX_MUL_LID; complex_div] THEN
+  SUBGOAL_THEN `0 < n` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+  RULE_ASSUM_TAC(REWRITE_RULE
+   [GSYM REAL_OF_NUM_LT; GSYM REAL_OF_NUM_LE; GSYM REAL_OF_NUM_ADD]) THEN
+  ASM_SIMP_TAC[GSYM CX_LOG; COMPLEX_NORM_CX; COMPLEX_NORM_INV] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM REAL_INV_INV] THEN
+  MATCH_MP_TAC REAL_LT_INV2 THEN ASM_REWRITE_TAC[REAL_LT_INV_EQ] THEN
+  MATCH_MP_TAC(REAL_ARITH `a < x ==> a < abs x`) THEN
+  ONCE_REWRITE_TAC[GSYM REAL_EXP_MONO_LT] THEN
+  ASM_SIMP_TAC[EXP_LOG] THEN ASM_REAL_ARITH_TAC);;
+
+let LIM_N_TIMES_POWN = prove
+ (`!z. norm(z) < &1 ==> ((\n. Cx(&n) * z pow n) --> Cx(&0)) sequentially`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THEN
+  ASM_SIMP_TAC[COMPLEX_POW_ZERO; LIM_CASES_FINITE_SEQUENTIALLY; LIM_CONST;
+               COND_RAND; FINITE_SING; SING_GSPEC; COMPLEX_MUL_RZERO] THEN
+  MP_TAC LIM_LOG_OVER_N THEN
+  REWRITE_TAC[LIM_SEQUENTIALLY; dist; COMPLEX_SUB_RZERO] THEN
+  DISCH_THEN(MP_TAC o SPEC `log(inv(norm(z:complex))) / &2`) THEN
+  ASM_SIMP_TAC[LOG_POS_LT; REAL_INV_1_LT; COMPLEX_NORM_NZ; REAL_HALF] THEN
+  DISCH_THEN(X_CHOOSE_THEN `N1:num` (LABEL_TAC "+")) THEN
+  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `N2:num` STRIP_ASSUME_TAC o
+              GEN_REWRITE_RULE I [REAL_ARCH_INV]) THEN
+  EXISTS_TAC `MAX 1 (MAX N1 N2)` THEN
+  REWRITE_TAC[ARITH_RULE `MAX a b <= c <=> a <= c /\ b <= c`] THEN
+  X_GEN_TAC `n:num` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `n:num`) THEN
+  ASM_SIMP_TAC[GSYM CX_LOG; REAL_OF_NUM_LT; LE_1; GSYM CX_DIV;
+               COMPLEX_NORM_CX; REAL_ABS_DIV; REAL_ABS_NUM] THEN
+  ASM_SIMP_TAC[REAL_LT_RDIV_EQ; REAL_OF_NUM_LT; ARITH; real_abs;
+               LOG_POS; REAL_OF_NUM_LE] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `a / b * &2 = (&2 * a) / b`] THEN
+  ASM_SIMP_TAC[REAL_LT_LDIV_EQ; REAL_OF_NUM_LT; LE_1] THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [REAL_MUL_SYM] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM REAL_EXP_MONO_LT] THEN
+  ASM_SIMP_TAC[REAL_EXP_N; EXP_LOG; REAL_OF_NUM_LT; LE_1;
+               REAL_LT_INV_EQ; COMPLEX_NORM_NZ] THEN
+  REWRITE_TAC[REAL_POW_INV] THEN
+  GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM REAL_MUL_LID] THEN
+  ASM_SIMP_TAC[GSYM real_div; REAL_LT_RDIV_EQ; REAL_POW_LT; COMPLEX_NORM_NZ;
+               COMPLEX_NORM_MUL; COMPLEX_NORM_NUM; COMPLEX_NORM_POW] THEN
+  DISCH_TAC THEN MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `inv(&N2)` THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `inv(&n)` THEN
+  ASM_SIMP_TAC[REAL_LE_INV2; REAL_OF_NUM_LE; REAL_OF_NUM_LT; LE_1] THEN
+  MATCH_MP_TAC REAL_LE_LCANCEL_IMP THEN EXISTS_TAC `&n` THEN
+  ASM_SIMP_TAC[REAL_MUL_RINV; REAL_LT_IMP_NZ; REAL_OF_NUM_LT; LE_1] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let LIM_N_OVER_POWN = prove
+ (`!z. &1 < norm(z) ==> ((\n. Cx(&n) / z pow n) --> Cx(&0)) sequentially`,
+  ASM_SIMP_TAC[complex_div; GSYM COMPLEX_POW_INV; COMPLEX_NORM_INV;
+               REAL_INV_LT_1; LIM_N_TIMES_POWN]);;
+
+let LIM_POWN = prove
+ (`!z. norm(z) < &1 ==> ((\n. z pow n) --> Cx(&0)) sequentially`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC LIM_NULL_COMPARISON_COMPLEX THEN
+  EXISTS_TAC `\n. Cx(&n) * z pow n` THEN ASM_SIMP_TAC[LIM_N_TIMES_POWN] THEN
+  REWRITE_TAC[EVENTUALLY_SEQUENTIALLY] THEN EXISTS_TAC `1` THEN
+  REWRITE_TAC[COMPLEX_NORM_MUL; COMPLEX_NORM_CX; REAL_ABS_NUM] THEN
+  REWRITE_TAC[REAL_ARITH `a <= n * a <=> &0 <= (n - &1) * a`] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_MUL THEN
+  ASM_REWRITE_TAC[NORM_POS_LE; REAL_SUB_LE; REAL_OF_NUM_LE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Roots of unity.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let COMPLEX_ROOT_POLYFUN = prove
+ (`!n z a.
+        1 <= n
+        ==> (z pow n = a <=>
+             vsum(0..n) (\i. (if i = 0 then --a else if i = n then Cx(&1)
+                              else Cx(&0)) * z pow i) = Cx(&0))`,
+  ASM_SIMP_TAC[VSUM_CLAUSES_RIGHT; LE_1; LE_0] THEN
+  SIMP_TAC[VSUM_CLAUSES_LEFT; LE_0; ADD_CLAUSES] THEN
+  ASM_SIMP_TAC[LE_1; ARITH_RULE `1 <= n /\ 1 <= i /\ i <= n - 1
+                           ==> ~(i = n)`] THEN
+  REWRITE_TAC[COMPLEX_MUL_LZERO; complex_pow; COMPLEX_MUL_RID] THEN
+  REWRITE_TAC[GSYM COMPLEX_VEC_0; VSUM_0; VECTOR_ADD_RID] THEN
+  REWRITE_TAC[COMPLEX_VEC_0] THEN CONV_TAC COMPLEX_RING);;
+
+let COMPLEX_ROOT_UNITY = prove
+ (`!n j. ~(n = 0)
+         ==> cexp(Cx(&2) * Cx pi * ii * Cx(&j / &n)) pow n = Cx(&1)`,
+  REWRITE_TAC[GSYM CEXP_N; CX_DIV] THEN
+  ASM_SIMP_TAC[CX_INJ; complex_div; REAL_OF_NUM_EQ; COMPLEX_FIELD
+    `~(n = Cx(&0)) ==> n * t * p * ii * j * inv(n) = j * (ii * t * p)`] THEN
+  REWRITE_TAC[CEXP_N; GSYM CX_MUL] THEN
+  REWRITE_TAC[CEXP_EULER; GSYM CX_MUL; GSYM CX_SIN; GSYM CX_COS] THEN
+  REWRITE_TAC[COS_NPI; SIN_NPI; REAL_POW_NEG; COMPLEX_MUL_RZERO;
+              REAL_POW_ONE; ARITH_EVEN; COMPLEX_ADD_RID; COMPLEX_POW_ONE]);;
+
+let COMPLEX_ROOT_UNITY_EQ = prove
+ (`!n j k. ~(n = 0)
+           ==> (cexp(Cx(&2) * Cx pi * ii * Cx(&j / &n)) =
+                cexp(Cx(&2) * Cx pi * ii * Cx(&k / &n)) <=> (j == k) (mod n))`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CEXP_EQ; num_congruent; CX_MUL] THEN
+  REWRITE_TAC[COMPLEX_RING
+   `t * p * ii * j = t * p * ii * k + (t * n * p) * ii <=>
+        (t * p * ii = Cx(&0)) \/ j - k = n`] THEN
+  SIMP_TAC[COMPLEX_ENTIRE; II_NZ; CX_INJ; PI_NZ; REAL_OF_NUM_EQ; ARITH] THEN
+  REWRITE_TAC[GSYM CX_SUB; CX_INJ] THEN
+  ASM_SIMP_TAC[REAL_OF_NUM_EQ; REAL_FIELD
+   `~(n = &0) ==> (j / n - k / n = m <=> j - k = n * m)`] THEN
+  REWRITE_TAC[int_congruent] THEN
+  REWRITE_TAC[int_eq; int_sub_th; int_mul_th; int_of_num_th] THEN
+  MESON_TAC[int_abstr; int_rep]);;
+
+let COMPLEX_ROOT_UNITY_EQ_1 = prove
+ (`!n j. ~(n = 0)
+         ==> (cexp(Cx(&2) * Cx pi * ii * Cx(&j / &n)) = Cx(&1) <=>
+              n divides j)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `Cx(&1) = cexp(Cx(&2) * Cx pi * ii * Cx(&n / &n))`
+  SUBST1_TAC THENL
+   [ASM_SIMP_TAC[REAL_DIV_REFL; REAL_OF_NUM_EQ; COMPLEX_MUL_RID] THEN
+    ONCE_REWRITE_TAC[COMPLEX_RING `t * p * ii = ii * t * p`] THEN
+    REWRITE_TAC[CEXP_EULER; GSYM CX_MUL; GSYM CX_SIN; GSYM CX_COS] THEN
+    REWRITE_TAC[COS_NPI; SIN_NPI] THEN SIMPLE_COMPLEX_ARITH_TAC;
+    ASM_SIMP_TAC[COMPLEX_ROOT_UNITY_EQ] THEN CONV_TAC NUMBER_RULE]);;
+
+let FINITE_CARD_COMPLEX_ROOTS_UNITY = prove
+ (`!n. 1 <= n
+       ==> FINITE {z | z pow n = Cx(&1)} /\ CARD {z | z pow n = Cx(&1)} <= n`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN ASM_SIMP_TAC[COMPLEX_ROOT_POLYFUN] THEN
+  MATCH_MP_TAC COMPLEX_POLYFUN_ROOTBOUND THEN
+  DISCH_THEN(MP_TAC o SPEC `n:num`) THEN
+  ASM_SIMP_TAC[IN_NUMSEG; LE_1; LE_0; LE_REFL] THEN CONV_TAC COMPLEX_RING);;
+
+let FINITE_COMPLEX_ROOTS_UNITY = prove
+ (`!n. ~(n = 0) ==> FINITE {z | z pow n = Cx(&1)}`,
+  SIMP_TAC[FINITE_CARD_COMPLEX_ROOTS_UNITY; LE_1]);;
+
+let FINITE_CARD_COMPLEX_ROOTS_UNITY_EXPLICIT = prove
+ (`!n. 1 <= n
+       ==> FINITE {cexp(Cx(&2) * Cx pi * ii * Cx(&j / &n)) | j | j < n} /\
+           CARD {cexp(Cx(&2) * Cx pi * ii * Cx(&j / &n)) | j | j < n} = n`,
+  let lemma = prove (* So we don't need to load number theories yet *)
+   (`!x y n:num. (x == y) (mod n) /\ x < y + n /\ y < x + n ==> x = y`,
+    REWRITE_TAC[num_congruent; GSYM INT_OF_NUM_EQ; GSYM INT_OF_NUM_LT] THEN
+    REWRITE_TAC[GSYM INT_OF_NUM_ADD] THEN
+    REWRITE_TAC[INT_ARITH `x < y + n /\ y < x + n <=> abs(x - y:int) < n`] THEN
+    REPEAT GEN_TAC THEN REWRITE_TAC[int_congruent] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `d:int`) MP_TAC) THEN
+    ONCE_REWRITE_TAC[GSYM INT_SUB_0] THEN
+    ASM_SIMP_TAC[INT_ABS_MUL; INT_ENTIRE; INT_ABS_NUM;
+                 INT_ARITH `n * x:int < n <=> n * x < n * &1`] THEN
+    DISJ_CASES_TAC(INT_ARITH `&n:int = &0 \/ &0:int < &n`) THEN
+    ASM_SIMP_TAC[INT_LT_LMUL_EQ] THEN INT_ARITH_TAC) in
+  REWRITE_TAC[GSYM HAS_SIZE] THEN
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC [SIMPLE_IMAGE_GEN] THEN
+  MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  ASM_SIMP_TAC[HAS_SIZE_NUMSEG_LT; COMPLEX_ROOT_UNITY_EQ; LE_1] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC lemma THEN EXISTS_TAC `n:num` THEN
+  ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC);;
+
+let COMPLEX_ROOTS_UNITY = prove
+ (`!n. 1 <= n
+       ==> {z | z pow n = Cx(&1)} =
+           {cexp(Cx(&2) * Cx pi * ii * Cx(&j / &n)) | j | j < n}`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC CARD_SUBSET_LE THEN
+  ASM_SIMP_TAC[FINITE_CARD_COMPLEX_ROOTS_UNITY;
+               FINITE_CARD_COMPLEX_ROOTS_UNITY_EXPLICIT] THEN
+  GEN_REWRITE_TAC LAND_CONV [SIMPLE_IMAGE_GEN] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+  ASM_SIMP_TAC[COMPLEX_ROOT_UNITY; LE_1]);;
+
+let CARD_COMPLEX_ROOTS_UNITY = prove
+ (`!n. 1 <= n ==> CARD {z | z pow n = Cx(&1)} = n`,
+  SIMP_TAC[COMPLEX_ROOTS_UNITY; FINITE_CARD_COMPLEX_ROOTS_UNITY_EXPLICIT]);;
+
+let HAS_SIZE_COMPLEX_ROOTS_UNITY = prove
+ (`!n. 1 <= n ==> {z | z pow n = Cx(&1)} HAS_SIZE n`,
+  SIMP_TAC[HAS_SIZE; CARD_COMPLEX_ROOTS_UNITY; FINITE_COMPLEX_ROOTS_UNITY;
+           LE_1]);;
+
+let COMPLEX_NOT_ROOT_UNITY = prove
+ (`!n. 1 <= n ==> ?u. norm u = &1 /\ ~(u pow n = Cx(&1))`,
+  GEN_TAC THEN DISCH_TAC THEN
+  ABBREV_TAC `u = cexp (Cx pi * ii * Cx (&1 / &n))` THEN
+  EXISTS_TAC `u : complex` THEN CONJ_TAC THEN EXPAND_TAC "u" THEN
+  REWRITE_TAC [NORM_CEXP; RE_MUL_CX; RE_II; REAL_MUL_LZERO;
+               REAL_MUL_RZERO; REAL_EXP_0] THEN
+  EXPAND_TAC "u" THEN REWRITE_TAC[GSYM CEXP_N] THEN
+  ASM_SIMP_TAC[CX_DIV; LE_1; CX_INJ; REAL_OF_NUM_EQ; COMPLEX_FIELD
+       `~(n = Cx(&0)) ==> n * p * i * Cx(&1) / n = i * p`] THEN
+  REWRITE_TAC[CEXP_EULER; RE_CX; IM_CX; GSYM CX_COS; GSYM CX_SIN] THEN
+  REWRITE_TAC[COS_PI; SIN_PI] THEN CONV_TAC COMPLEX_RING);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relation between clog and Arg, and hence continuity of Arg.               *)
+(* ------------------------------------------------------------------------- *)
+
+let ARG_CLOG = prove
+ (`!z. &0 < Arg z ==> Arg z = Im(clog(--z)) + pi`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THENL
+   [ASM_REWRITE_TAC[Arg_DEF; REAL_LT_REFL]; ALL_TAC] THEN
+  DISCH_TAC THEN MP_TAC(last(CONJUNCTS(SPEC `z:complex` ARG))) THEN
+  ASM_SIMP_TAC[CX_INJ; COMPLEX_NORM_ZERO; COMPLEX_FIELD
+   `~(z = Cx(&0)) ==> (w = z * a <=> a = w / z)`] THEN
+  DISCH_THEN(MP_TAC o AP_TERM `( * ) (cexp(--(ii * Cx pi)))`) THEN
+  REWRITE_TAC[GSYM CEXP_ADD] THEN DISCH_THEN(MP_TAC o AP_TERM `clog`) THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) CLOG_CEXP o lhand o lhand o snd) THEN
+  REWRITE_TAC[IM_ADD; IM_MUL_II; RE_CX; IM_NEG] THEN
+  ASM_SIMP_TAC[REAL_LT_ADDR; ARG; REAL_ARITH
+    `z < &2 * pi ==> --pi + z <= pi`] THEN
+  DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[CEXP_NEG; CEXP_EULER] THEN
+  REWRITE_TAC[GSYM CX_SIN; GSYM CX_COS; SIN_PI; COS_PI] THEN
+  REWRITE_TAC[CX_NEG; COMPLEX_MUL_RZERO; COMPLEX_ADD_RID;
+              SIMPLE_COMPLEX_ARITH `inv(--Cx(&1)) * z / w = --z / w`] THEN
+  DISCH_THEN(MP_TAC o AP_TERM `Im`) THEN
+  REWRITE_TAC[IM_ADD; IM_NEG; IM_MUL_II; RE_CX] THEN
+  MATCH_MP_TAC(REAL_RING `w = z ==> --pi + x = w ==> x = z + pi`) THEN
+  REWRITE_TAC[complex_div] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) CLOG_MUL_SIMPLE o rand o lhand o snd) THEN
+  ASM_SIMP_TAC[CX_INJ; REAL_INV_EQ_0; COMPLEX_NORM_ZERO; COMPLEX_NEG_EQ_0;
+    GSYM CX_INV; GSYM CX_LOG; REAL_LT_INV_EQ; COMPLEX_NORM_NZ; IM_CX] THEN
+  ASM_SIMP_TAC[REAL_ADD_RID; CLOG_WORKS; COMPLEX_NEG_EQ_0] THEN
+  DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[IM_ADD; IM_CX; REAL_ADD_RID]);;
+
+let CONTINUOUS_AT_ARG = prove
+ (`!z. ~(real z /\ &0 <= Re z) ==> (Cx o Arg) continuous (at z)`,
+  let lemma = prove
+   (`(\z. Cx(Im(f z) + pi)) = (Cx o Im) o (\z. f z + ii * Cx pi)`,
+    REWRITE_TAC[FUN_EQ_THM; o_DEF; IM_ADD; IM_CX; IM_MUL_II; RE_CX]) in
+  REPEAT STRIP_TAC THEN REWRITE_TAC[CONTINUOUS_AT] THEN
+  MATCH_MP_TAC LIM_TRANSFORM_WITHIN_OPEN THEN
+  EXISTS_TAC `\z. Cx(Im(clog(--z)) + pi)` THEN
+  EXISTS_TAC `(:complex) DIFF {z | real z /\ &0 <= Re z}` THEN
+  ASM_REWRITE_TAC[IN_DIFF; IN_UNIV; IN_ELIM_THM; GSYM closed] THEN
+  ASM_SIMP_TAC[o_THM; ARG_CLOG; ARG_LT_NZ; ARG_EQ_0] THEN CONJ_TAC THENL
+   [REWRITE_TAC[SET_RULE `{z | P z /\ Q z} = P INTER {z | Q z}`] THEN
+    MATCH_MP_TAC CLOSED_INTER THEN
+    REWRITE_TAC[CLOSED_REAL; GSYM real_ge; CLOSED_HALFSPACE_RE_GE];
+    REWRITE_TAC[GSYM CONTINUOUS_AT; lemma] THEN
+    MATCH_MP_TAC CONTINUOUS_AT_COMPOSE THEN
+    REWRITE_TAC[CONTINUOUS_AT_CX_IM] THEN
+    MATCH_MP_TAC CONTINUOUS_ADD THEN REWRITE_TAC[CONTINUOUS_CONST] THEN
+    MATCH_MP_TAC(REWRITE_RULE[o_DEF] CONTINUOUS_AT_COMPOSE) THEN
+    GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM ETA_AX] THEN
+    SIMP_TAC[CONTINUOUS_NEG; CONTINUOUS_AT_ID] THEN
+    MATCH_MP_TAC CONTINUOUS_AT_CLOG THEN POP_ASSUM MP_TAC THEN
+    REWRITE_TAC[real; IM_NEG; RE_NEG] THEN REAL_ARITH_TAC]);;
+
+let CONTINUOUS_WITHIN_UPPERHALF_ARG = prove
+ (`!z. ~(z = Cx(&0))
+       ==> (Cx o Arg) continuous (at z) within {z | &0 <= Im z}`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `real z /\ &0 <= Re z` THEN
+  ASM_SIMP_TAC[CONTINUOUS_AT_ARG; CONTINUOUS_AT_WITHIN] THEN
+  FIRST_X_ASSUM(CONJUNCTS_THEN2
+   (ASSUME_TAC o GEN_REWRITE_RULE I [real]) MP_TAC) THEN
+  SUBGOAL_THEN `~(Re z = &0)` ASSUME_TAC THENL
+   [DISCH_TAC THEN UNDISCH_TAC `~(z = Cx(&0))` THEN
+    ASM_REWRITE_TAC[COMPLEX_EQ; RE_CX; IM_CX];
+    GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT]] THEN
+  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
+  MP_TAC(ISPEC `rotate2d (pi / &2) z` CONTINUOUS_AT_ARG) THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[ROTATE2D_PI2; real; IM_MUL_II]; ALL_TAC] THEN
+  REWRITE_TAC[continuous_at; continuous_within] THEN
+  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 `d:real` THEN
+  REWRITE_TAC[o_THM; dist; GSYM CX_SUB; COMPLEX_NORM_CX] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[IN_ELIM_THM] THEN
+  X_GEN_TAC `w:complex` THEN STRIP_TAC THEN
+  SUBGOAL_THEN `Arg z = &0` ASSUME_TAC THENL
+   [ASM_SIMP_TAC[ARG_EQ_0; real; REAL_LT_IMP_LE]; ALL_TAC] THEN
+  ASM_CASES_TAC `Arg w = &0` THEN
+  ASM_REWRITE_TAC[REAL_SUB_REFL; REAL_ABS_NUM] THEN
+  SUBGOAL_THEN `&0 < Arg w` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[ARG; REAL_LT_LE]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `rotate2d (pi / &2) w`) THEN
+  ASM_REWRITE_TAC[GSYM ROTATE2D_SUB; NORM_ROTATE2D] THEN
+  MP_TAC(ISPECL [`pi / &2`; `z:complex`] ARG_ROTATE2D) THEN ANTS_TAC THENL
+   [ASM_REWRITE_TAC[] THEN MP_TAC PI_POS THEN ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+  DISCH_THEN SUBST1_TAC THEN ASM_REWRITE_TAC[REAL_ADD_RID] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `w' = p + w ==> abs(w' - p) < e ==> abs(w - &0) < e`) THEN
+  MATCH_MP_TAC ARG_ROTATE2D THEN CONJ_TAC THENL
+   [DISCH_TAC THEN UNDISCH_TAC `&0 < Arg w` THEN
+    ASM_REWRITE_TAC[Arg_DEF; REAL_LT_REFL];
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM ARG_LE_PI]) THEN
+    MP_TAC(SPEC `w:complex` ARG) THEN REAL_ARITH_TAC]);;
+
+let CONTINUOUS_ON_UPPERHALF_ARG = prove
+ (`(Cx o Arg) continuous_on ({z | &0 <= Im z} DIFF {Cx(&0)})`,
+  REWRITE_TAC[CONTINUOUS_ON_EQ_CONTINUOUS_WITHIN] THEN
+  X_GEN_TAC `z:complex` THEN REWRITE_TAC[IN_DIFF; IN_SING; IN_ELIM_THM] THEN
+  STRIP_TAC THEN FIRST_ASSUM(MP_TAC o
+    MATCH_MP CONTINUOUS_WITHIN_UPPERHALF_ARG) THEN
+  MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] CONTINUOUS_WITHIN_SUBSET) THEN
+  SET_TAC[]);;
+
+let CONTINUOUS_ON_COMPOSE_ARG = prove
+ (`!s p:real->real^N.
+        (p o drop) continuous_on interval[vec 0,lift(&2 * pi)] /\
+        p(&2 * pi) = p(&0) /\ ~(Cx(&0) IN s)
+        ==> (\z. p(Arg z)) continuous_on s`,
+  let ulemma = prove
+   (`!s. s INTER {z | &0 <= Im z} UNION s INTER {z | Im z <= &0} = s`,
+    SET_TAC[REAL_LE_TOTAL]) in
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_EQ THEN
+  EXISTS_TAC
+   `\z. if &0 <= Im z then p(Arg z)
+        else p(&2 * pi - Arg(cnj z)):real^N` THEN
+  REWRITE_TAC[IN_UNIV; IN_SING; IN_DIFF] THEN CONJ_TAC THENL
+   [X_GEN_TAC `z:complex` THEN DISCH_TAC THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[ARG_CNJ] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_SUB_SUB2] THEN
+    SUBGOAL_THEN `Arg z = &0`
+     (fun th -> ASM_REWRITE_TAC[REAL_SUB_RZERO; th]) THEN
+    ASM_REWRITE_TAC[ARG_EQ_0];
+    GEN_REWRITE_TAC RAND_CONV [GSYM ulemma] THEN
+    MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN REWRITE_TAC[ulemma] THEN
+    SIMP_TAC[CLOSED_IN_CLOSED_INTER; CLOSED_HALFSPACE_IM_LE;
+             REWRITE_RULE[real_ge] CLOSED_HALFSPACE_IM_GE] THEN
+    REWRITE_TAC[IN_INTER; IN_DIFF; IN_UNIV; IN_SING; IN_ELIM_THM] THEN
+    SIMP_TAC[GSYM CONJ_ASSOC; REAL_LE_ANTISYM; TAUT `~(p /\ ~p)`] THEN
+    REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+     [GEN_REWRITE_TAC (BINOP_CONV o LAND_CONV) [GSYM o_DEF] THEN
+      SUBGOAL_THEN `(p:real->real^N) = (p o drop) o lift` SUBST1_TAC THENL
+       [REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX]; ALL_TAC] THEN
+      ONCE_REWRITE_TAC[GSYM o_ASSOC] THEN
+      CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+       [REWRITE_TAC[o_DEF; GSYM CONTINUOUS_ON_CX_LIFT] THEN
+        MP_TAC CONTINUOUS_ON_UPPERHALF_ARG THEN REWRITE_TAC[o_DEF] THEN
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] CONTINUOUS_ON_SUBSET) THEN
+        ASM SET_TAC[];
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTER; IN_ELIM_THM] THEN
+        REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP; o_THM; DROP_VEC] THEN
+        SIMP_TAC[ARG; REAL_LT_IMP_LE];
+        REWRITE_TAC[o_DEF; LIFT_SUB] THEN MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+        REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+        GEN_REWRITE_TAC (LAND_CONV o TOP_DEPTH_CONV) [GSYM o_DEF] THEN
+        REWRITE_TAC[o_ASSOC] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        REWRITE_TAC[CONTINUOUS_ON_CNJ; o_DEF; GSYM CONTINUOUS_ON_CX_LIFT] THEN
+        MP_TAC CONTINUOUS_ON_UPPERHALF_ARG THEN REWRITE_TAC[o_DEF] THEN
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] CONTINUOUS_ON_SUBSET) THEN
+        SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTER; IN_ELIM_THM; IN_DIFF] THEN
+        SIMP_TAC[IN_SING; CNJ_EQ_0; IM_CNJ; REAL_NEG_GE0] THEN ASM SET_TAC[];
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_INTER; IN_ELIM_THM] THEN
+        REWRITE_TAC[IN_INTERVAL_1; LIFT_DROP; o_THM; DROP_VEC] THEN
+        X_GEN_TAC `z:complex` THEN STRIP_TAC THEN
+        MP_TAC(SPEC `cnj z` ARG) THEN REAL_ARITH_TAC];
+      REWRITE_TAC[GSYM ARG_EQ_0_PI; GSYM real; ARG_CNJ] THEN
+      REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_SUB_SUB2; REAL_SUB_RZERO] THEN
+      ASM_REWRITE_TAC[REAL_ARITH `&2 * x - x = x`]]]);;
+
+let OPEN_ARG_LTT = prove
+ (`!s t. &0 <= s /\ t <= &2 * pi ==> open {z | s < Arg z /\ Arg z < t}`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`Cx o Arg`; `(:complex) DIFF {z | real z /\ &0 <= Re z}`;
+                   `{z | Re(z) > s} INTER {z | Re(z) < t}`]
+           CONTINUOUS_OPEN_PREIMAGE) THEN
+  ASM_SIMP_TAC[OPEN_INTER; OPEN_HALFSPACE_RE_GT; OPEN_HALFSPACE_RE_LT] THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THENL
+     [MATCH_MP_TAC CONTINUOUS_AT_IMP_CONTINUOUS_ON THEN
+      REWRITE_TAC[IN_DIFF; IN_UNIV; IN_ELIM_THM; CONTINUOUS_AT_ARG];
+      REWRITE_TAC[GSYM closed] THEN
+      REWRITE_TAC[SET_RULE `{z | P z /\ Q z} = P INTER {z | Q z}`] THEN
+      MATCH_MP_TAC CLOSED_INTER THEN
+      REWRITE_TAC[CLOSED_REAL; GSYM real_ge; CLOSED_HALFSPACE_RE_GE]];
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN REWRITE_TAC[EXTENSION] THEN
+    ASM_SIMP_TAC[IN_DIFF; IN_INTER; IN_UNIV; IN_ELIM_THM; o_THM; RE_CX;
+                 GSYM ARG_EQ_0] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let OPEN_ARG_GT = prove
+ (`!t. open {z | t < Arg z}`,
+  GEN_TAC THEN DISJ_CASES_TAC(REAL_ARITH `t < &0 \/ &0 <= t`) THENL
+   [SUBGOAL_THEN `{z | t < Arg z} = (:complex)`
+     (fun th -> SIMP_TAC[th; OPEN_UNIV]) THEN
+    REWRITE_TAC[EXTENSION; IN_UNIV; IN_ELIM_THM] THEN
+    MP_TAC ARG THEN MATCH_MP_TAC MONO_FORALL THEN ASM_REAL_ARITH_TAC;
+    MP_TAC(ISPECL [`t:real`; `&2 * pi`] OPEN_ARG_LTT) THEN
+    ASM_REWRITE_TAC[ARG; REAL_LE_REFL]]);;
+
+let CLOSED_ARG_LE = prove
+ (`!t. closed {z | Arg z <= t}`,
+  REWRITE_TAC[closed; DIFF; IN_UNIV; IN_ELIM_THM] THEN
+  REWRITE_TAC[REAL_NOT_LE; OPEN_ARG_GT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relation between Arg and arctangent in upper halfplane.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let ARG_ATAN_UPPERHALF = prove
+ (`!z. &0 < Im z ==> Arg(z) = pi / &2 - atn(Re z / Im z)`,
+  GEN_TAC THEN ASM_CASES_TAC `z = Cx(&0)` THEN
+  ASM_REWRITE_TAC[IM_CX; REAL_LT_REFL] THEN DISCH_TAC THEN
+  MATCH_MP_TAC ARG_UNIQUE THEN EXISTS_TAC `norm(z:complex)` THEN
+  ASM_REWRITE_TAC[COMPLEX_NORM_NZ] THEN CONJ_TAC THENL
+   [ALL_TAC; MP_TAC(ISPEC `Re z / Im z` ATN_BOUNDS) THEN REAL_ARITH_TAC] THEN
+  REWRITE_TAC[CEXP_EULER; GSYM CX_SIN; GSYM CX_COS] THEN
+  REWRITE_TAC[SIN_SUB; COS_SUB; SIN_PI2; COS_PI2] THEN
+  REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_LID; SIN_ATN; COS_ATN] THEN
+  SUBGOAL_THEN `sqrt(&1 + (Re z / Im z) pow 2) = norm(z) / Im z`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC SQRT_UNIQUE THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; NORM_POS_LE; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[REAL_POW_DIV; COMPLEX_SQNORM] THEN
+    UNDISCH_TAC `&0 < Im z` THEN CONV_TAC REAL_FIELD;
+    REWRITE_TAC[REAL_ADD_LID; REAL_SUB_RZERO; real_div] THEN
+    REWRITE_TAC[COMPLEX_EQ; RE_MUL_CX; IM_MUL_CX; RE_MUL_II; IM_MUL_II;
+                RE_ADD; IM_ADD; RE_CX; IM_CX] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM COMPLEX_NORM_NZ]) THEN
+    POP_ASSUM MP_TAC THEN CONV_TAC REAL_FIELD]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real n'th roots.                                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let root = new_definition
+ `root(n) x = @u:real. (&0 <= x ==> &0 <= u) /\ u pow n = x`;;
+
+let ROOT_0 = prove
+ (`!n. ~(n = 0) ==> root n (&0) = &0`,
+  SIMP_TAC[root; REAL_LT_REFL; REAL_POW_EQ_0; REAL_LE_REFL; SELECT_REFL;
+           REAL_ARITH `&0 <= u /\ u = &0 <=> u = &0`]);;
+
+let ROOT_1 = prove
+ (`!n. ~(n = 0) ==> root n (&1) = &1`,
+  SIMP_TAC[root; REAL_POS; REAL_POW_EQ_1; CONJ_ASSOC] THEN
+  REWRITE_TAC[REAL_ARITH `&0 <= u /\ abs u = &1 <=> u = &1`] THEN
+  SIMP_TAC[TAUT `a /\ b <=> ~(a ==> ~b)`] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV);;
+
+let ROOT_2 = prove
+ (`!x. root 2 x = sqrt x`,
+  GEN_TAC THEN REWRITE_TAC[sqrt; root] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `y:real` THEN
+  ASM_CASES_TAC `x:real = y pow 2` THEN
+  ASM_REWRITE_TAC[REAL_POW_2; REAL_LE_SQUARE] THEN REAL_ARITH_TAC);;
+
+let ROOT_WORKS = prove
+ (`!n x. ODD n \/ ~(n = 0) /\ &0 <= x
+         ==> (&0 <= x ==> &0 <= root n x) /\ (root n x) pow n = x`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `n = 0` THEN ASM_REWRITE_TAC[ARITH] THEN DISCH_TAC THEN
+  REWRITE_TAC[root] THEN CONV_TAC SELECT_CONV THEN
+  REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
+   (REAL_ARITH `x = &0 \/ &0 < x \/ &0 < --x`)
+  THENL
+   [EXISTS_TAC `&0` THEN ASM_REWRITE_TAC[REAL_POW_ZERO];
+    EXISTS_TAC `exp(log x / &n)` THEN REWRITE_TAC[REAL_EXP_POS_LE] THEN
+    ASM_SIMP_TAC[GSYM REAL_EXP_N; REAL_DIV_LMUL; REAL_OF_NUM_EQ; EXP_LOG];
+    FIRST_X_ASSUM(DISJ_CASES_THEN ASSUME_TAC) THENL
+     [ALL_TAC; ASM_REAL_ARITH_TAC] THEN
+    EXISTS_TAC `--exp(log(--x) / &n)` THEN REWRITE_TAC[REAL_POW_NEG] THEN
+    ASM_SIMP_TAC[GSYM NOT_ODD; REAL_ARITH `&0 < --x ==> ~(&0 <= x)`] THEN
+    ASM_SIMP_TAC[GSYM REAL_EXP_N; REAL_DIV_LMUL; REAL_OF_NUM_EQ; EXP_LOG;
+                 REAL_NEG_NEG]]);;
+
+let REAL_POW_ROOT = prove
+ (`!n x. ODD n \/ ~(n = 0) /\ &0 <= x ==> (root n x) pow n = x`,
+  SIMP_TAC[ROOT_WORKS]);;
+
+let ROOT_POS_LE = prove
+ (`!n x. ~(n = 0) /\ &0 <= x ==> &0 <= root n x`,
+  SIMP_TAC[ROOT_WORKS]);;
+
+let ROOT_POS_LT = prove
+ (`!n x. ~(n = 0) /\ &0 < x ==> &0 < root n x`,
+  REPEAT GEN_TAC THEN SIMP_TAC[REAL_LT_LE; ROOT_POS_LE] THEN STRIP_TAC THEN
+  DISCH_THEN(ASSUME_TAC o SYM) THEN
+  MP_TAC(SPECL [`n:num`; `x:real`] REAL_POW_ROOT) THEN
+  ASM_REWRITE_TAC[REAL_POW_ZERO]);;
+
+let REAL_ROOT_POW = prove
+ (`!n x. ODD n \/ ~(n = 0) /\ &0 <= x ==> root n (x pow n) = x`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[root] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM SELECT_REFL] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `y:real` THEN
+  MP_TAC(SPECL [`n:num`; `&0`; `x:real`] REAL_POW_LE2_ODD_EQ) THEN
+  POP_ASSUM MP_TAC THEN REWRITE_TAC[REAL_POW_EQ_EQ; GSYM NOT_EVEN] THEN
+  ASM_CASES_TAC `n = 0` THEN ASM_REWRITE_TAC[ARITH] THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[REAL_POW_LE; REAL_POW_ZERO] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let ROOT_UNIQUE = prove
+ (`!n x y. y pow n = x /\ (ODD n \/ ~(n = 0) /\ &0 <= y) ==> root n x = y`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
+  UNDISCH_THEN `(y:real) pow n = x` (SUBST_ALL_TAC o SYM) THEN
+  MATCH_MP_TAC REAL_ROOT_POW THEN ASM_REWRITE_TAC[]);;
+
+let REAL_ROOT_MUL = prove
+ (`!n x y. ~(n = 0) /\ &0 <= x /\ &0 <= y
+           ==> root n (x * y) = root n x * root n y`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ROOT_UNIQUE THEN
+  ASM_SIMP_TAC[REAL_POW_MUL; REAL_POW_ROOT; REAL_LE_MUL; ROOT_POS_LE]);;
+
+let REAL_ROOT_INV = prove
+ (`!n x. ~(n = 0) /\ &0 <= x ==> root n (inv x) = inv(root n x)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC ROOT_UNIQUE THEN
+  ASM_SIMP_TAC[REAL_POW_INV; REAL_POW_ROOT; REAL_LE_INV_EQ; ROOT_POS_LE]);;
+
+let REAL_ROOT_DIV = prove
+ (`!n x y. ~(n = 0) /\ &0 <= x /\ &0 <= y
+           ==> root n (x / y) = root n x / root n y`,
+  SIMP_TAC[real_div; REAL_ROOT_MUL; REAL_ROOT_INV; REAL_LE_INV_EQ]);;
+
+let ROOT_MONO_LT = prove
+ (`!n x y. ~(n = 0) /\ &0 <= x /\ x < y ==> root n x < root n y`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `(&0 <= x /\ &0 <= y ==> (v <= u ==> y <= x))
+    ==> &0 <= x /\ x < y ==> u < v`) THEN
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `(root n y) pow n <= (root n x) pow n` MP_TAC THENL
+   [MATCH_MP_TAC REAL_POW_LE2 THEN ASM_SIMP_TAC[ROOT_POS_LE];
+    ASM_SIMP_TAC[REAL_POW_ROOT]]);;
+
+let ROOT_MONO_LE = prove
+ (`!n x y. ~(n = 0) /\ &0 <= x /\ x <= y ==> root n x <= root n y`,
+  MESON_TAC[ROOT_MONO_LT; REAL_LE_LT]);;
+
+let ROOT_MONO_LT_EQ = prove
+ (`!n x y. ~(n = 0) /\ &0 <= x /\ &0 <= y ==> (root n x < root n y <=> x < y)`,
+  MESON_TAC[ROOT_MONO_LT; REAL_NOT_LT; ROOT_MONO_LE]);;
+
+let ROOT_MONO_LE_EQ = prove
+ (`!n x y. ~(n = 0) /\ &0 <= x /\ &0 <= y
+           ==> (root n x <= root n y <=> x <= y)`,
+  MESON_TAC[ROOT_MONO_LT; REAL_NOT_LT; ROOT_MONO_LE]);;
+
+let ROOT_INJ = prove
+ (`!n x y. ~(n = 0) /\ &0 <= x /\ &0 <= y ==> (root n x = root n y <=> x = y)`,
+  SIMP_TAC[GSYM REAL_LE_ANTISYM; ROOT_MONO_LE_EQ]);;
+
+let REAL_ROOT_LE = prove
+ (`!n x y. ~(n = 0) /\ &0 <= x /\ &0 <= y
+           ==> (root n x <= y <=> x <= y pow n)`,
+  MESON_TAC[REAL_ROOT_POW; REAL_POW_LE; ROOT_MONO_LE_EQ]);;
+
+let REAL_LE_ROOT = prove
+ (`!n x y. ~(n = 0) /\ &0 <= x /\ &0 <= y
+           ==> (x <= root n y <=> x pow n <= y)`,
+  MESON_TAC[REAL_ROOT_POW; REAL_POW_LE; ROOT_MONO_LE_EQ]);;
+
+let LOG_ROOT = prove
+ (`!n x. ~(n = 0) /\ &0 < x ==> log(root n x) = log x / &n`,
+  SIMP_TAC[REAL_EQ_RDIV_EQ; REAL_OF_NUM_LT; LE_1] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  SIMP_TAC[GSYM LOG_POW; ROOT_POS_LT; REAL_POW_ROOT; REAL_LT_IMP_LE]);;
+
+let ROOT_EXP_LOG = prove
+ (`!n x. ~(n = 0) /\ &0 < x ==> root n x = exp(log x / &n)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ROOT_POS_LT) THEN
+  REWRITE_TAC[GSYM REAL_EXP_LOG] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+  AP_TERM_TAC THEN ASM_SIMP_TAC[LOG_ROOT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Real power function. This involves a few arbitrary choices.               *)
+(*                                                                           *)
+(* The value of x^y is unarguable when x > 0.                                *)
+(*                                                                           *)
+(* We make 0^0 = 1 to agree with "pow", but otherwise 0^y = 0.               *)
+(*                                                                           *)
+(* There is a sensible real value for (-x)^(p/q) where q is odd and either   *)
+(* p is even [(-x)^y = x^y] or odd [(-x)^y = -x^y].                          *)
+(*                                                                           *)
+(* In all other cases, we return (-x)^y = -x^y. This is meaningless but at   *)
+(* least it covers half the cases above without another case split.          *)
+(*                                                                           *)
+(* As for laws of indices, we do have x^-y = 1/x^y. Of course we can't  have *)
+(* x^(yz) = x^y^z or x^(y+z) = x^y x^z since then (-1)^(1/2)^2 = -1.         *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("rpow",(24,"left"));;
+
+let rpow = new_definition
+  `x rpow y = if &0 < x then exp(y * log x)
+               else if x = &0 then if y = &0 then &1 else &0
+               else if ?m n. ODD(m) /\ ODD(n) /\ (abs y = &m / &n)
+                    then --(exp(y * log(--x)))
+                    else exp(y * log(--x))`;;
+
+let RPOW_POW = prove
+ (`!x n. x rpow &n = x pow n`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[rpow] THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[REAL_EXP_N; EXP_LOG] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_POW_ZERO; REAL_OF_NUM_EQ] THEN
+  ASM_SIMP_TAC[EXP_LOG; REAL_ARITH `~(&0 < x) /\ ~(x = &0) ==> &0 < --x`] THEN
+  REWRITE_TAC[REAL_POW_NEG; REAL_ABS_NUM] THEN
+  SUBGOAL_THEN `(?p q. ODD(p) /\ ODD(q) /\ &n = &p / &q) <=> ODD n`
+   (fun th -> SIMP_TAC[th; GSYM NOT_ODD; REAL_NEG_NEG; COND_ID]) THEN
+  EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+   [REPEAT GEN_TAC THEN ASM_CASES_TAC `q = 0` THEN
+    ASM_REWRITE_TAC[ARITH_ODD] THEN
+    REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+    ASM_SIMP_TAC[REAL_OF_NUM_EQ; REAL_FIELD
+     `~(q = &0) ==> (n = p / q <=> q * n = p)`] THEN
+    REWRITE_TAC[REAL_OF_NUM_MUL; REAL_OF_NUM_EQ] THEN
+    ASM_MESON_TAC[ODD_MULT];
+    DISCH_TAC THEN MAP_EVERY EXISTS_TAC [`n:num`; `1`] THEN
+    ASM_REWRITE_TAC[REAL_DIV_1; ARITH_ODD]]);;
+
+let RPOW_NEG = prove
+ (`!x y. x rpow (--y) = inv(x rpow y)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[rpow] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_MUL_LNEG; REAL_EXP_NEG] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_NEG_EQ_0] THENL
+   [COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_INV_0; REAL_INV_1];
+    REWRITE_TAC[REAL_ABS_NEG] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_INV_NEG]]);;
+
+let RPOW_ZERO = prove
+ (`!y. &0 rpow y = if y = &0 then &1 else &0`,
+  REWRITE_TAC[rpow; REAL_LT_REFL]);;
+
+let RPOW_POS_LT = prove
+ (`!x y. &0 < x ==> &0 < x rpow y`,
+  SIMP_TAC[rpow; REAL_EXP_POS_LT]);;
+
+let RPOW_POS_LE = prove
+ (`!x y. &0 <= x ==> &0 <= x rpow y`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `x = &0` THENL
+   [ASM_REWRITE_TAC[RPOW_ZERO] THEN MESON_TAC[REAL_POS];
+    ASM_SIMP_TAC[RPOW_POS_LT; REAL_LE_LT]]);;
+
+let RPOW_LT2 = prove
+ (`!x y z. &0 <= x /\ x < y /\ &0 < z ==> x rpow z < y rpow z`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `x = &0` THEN
+  ASM_SIMP_TAC[RPOW_ZERO; REAL_LT_IMP_NZ; RPOW_POS_LT] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[rpow] THEN
+  ASM_CASES_TAC `&0 < x /\ &0 < y` THENL
+   [ALL_TAC; MATCH_MP_TAC(TAUT `F ==> p`) THEN ASM_REAL_ARITH_TAC] THEN
+  ASM_SIMP_TAC[REAL_EXP_MONO_LT; REAL_LT_LMUL_EQ] THEN
+  MATCH_MP_TAC LOG_MONO_LT_IMP THEN ASM_REAL_ARITH_TAC);;
+
+let RPOW_LE2 = prove
+ (`!x y z. &0 <= x /\ x <= y /\ &0 <= z ==> x rpow z <= y rpow z`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `z = &0` THEN
+  ASM_REWRITE_TAC[RPOW_POW; real_pow; REAL_LE_REFL] THEN
+  ASM_CASES_TAC `x:real = y` THEN ASM_REWRITE_TAC[REAL_LE_REFL] THEN
+  ASM_MESON_TAC[RPOW_LT2; REAL_LE_LT]);;
+
+let REAL_ABS_RPOW = prove
+ (`!x y. abs(x rpow y) = abs(x) rpow y`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[rpow] THEN
+  ASM_CASES_TAC `x = &0` THEN ASM_REWRITE_TAC[REAL_ABS_NUM; REAL_LT_REFL] THENL
+   [REAL_ARITH_TAC; ALL_TAC] THEN
+  ASM_REWRITE_TAC[GSYM REAL_ABS_NZ; REAL_ABS_ZERO] THEN
+  COND_CASES_TAC THEN
+  ASM_SIMP_TAC[REAL_ABS_EXP; REAL_ARITH `&0 < x ==> abs x = x`] THEN
+  COND_CASES_TAC THEN REWRITE_TAC[REAL_ABS_NEG; REAL_ABS_EXP] THEN
+  AP_TERM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN ASM_REAL_ARITH_TAC);;
+
+let RPOW_ONE = prove
+ (`!z. &1 rpow z = &1`,
+  REWRITE_TAC[rpow; REAL_LT_01; LOG_1; REAL_MUL_RZERO; REAL_EXP_0]);;
+
+let RPOW_RPOW = prove
+ (`!x y z. &0 <= x ==> x rpow y rpow z = x rpow (y * z)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[REAL_LE_LT] THEN
+  ASM_CASES_TAC `x = &0` THEN ASM_REWRITE_TAC[] THENL
+   [ASM_REWRITE_TAC[RPOW_ZERO; REAL_ENTIRE] THEN
+    ASM_CASES_TAC `y = &0` THEN ASM_REWRITE_TAC[RPOW_ZERO; RPOW_ONE];
+    SIMP_TAC[rpow; REAL_EXP_POS_LT; LOG_EXP] THEN
+    REWRITE_TAC[REAL_MUL_AC]]);;
+
+let RPOW_LNEG = prove
+ (`!x y. --x rpow y =
+         if ?m n. ODD m /\ ODD n /\ abs y = &m / &n
+         then --(x rpow y) else x rpow y`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[rpow] THEN
+  ASM_CASES_TAC `x = &0` THEN
+  ASM_REWRITE_TAC[REAL_NEG_0; REAL_ABS_NUM; REAL_LT_REFL] THENL
+   [ASM_CASES_TAC `y = &0` THEN ASM_REWRITE_TAC[REAL_NEG_0; COND_ID] THEN
+    REWRITE_TAC[REAL_ARITH `abs(&0) = m / n <=> m * inv n = &0`] THEN
+    SIMP_TAC[REAL_ENTIRE; REAL_INV_EQ_0; REAL_OF_NUM_EQ] THEN MESON_TAC[ODD];
+    ASM_SIMP_TAC[REAL_ARITH `~(x = &0) ==> (&0 < --x <=> ~(&0 < x))`] THEN
+    ASM_REWRITE_TAC[REAL_NEG_EQ_0] THEN
+    ASM_CASES_TAC `&0 < x` THEN ASM_REWRITE_TAC[REAL_NEG_NEG; COND_ID]]);;
+
+let RPOW_EQ_0 = prove
+ (`!x y. x rpow y = &0 <=> x = &0 /\ ~(y = &0)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[rpow] THEN
+  ASM_CASES_TAC `x = &0` THEN ASM_REWRITE_TAC[REAL_LT_REFL] THEN
+  REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_NEG_EQ_0; REAL_EXP_NZ]) THEN
+  REAL_ARITH_TAC);;
+
+let RPOW_MUL = prove
+ (`!x y z. (x * y) rpow z = x rpow z * y rpow z`,
+  SUBGOAL_THEN
+    `!x y z. &0 <= x /\ &0 <= y ==> (x * y) rpow z = x rpow z * y rpow z`
+  ASSUME_TAC THENL
+   [REPEAT GEN_TAC THEN REWRITE_TAC[REAL_LE_LT] THEN
+    ASM_CASES_TAC `z = &0` THEN
+    ASM_REWRITE_TAC[RPOW_POW; real_pow; REAL_MUL_LID] THEN
+    ASM_CASES_TAC `x = &0` THEN ASM_REWRITE_TAC[REAL_MUL_LZERO; RPOW_ZERO] THEN
+    ASM_CASES_TAC `y = &0` THEN ASM_REWRITE_TAC[REAL_MUL_RZERO; RPOW_ZERO] THEN
+    SIMP_TAC[rpow; REAL_LT_MUL; LOG_MUL; REAL_ADD_LDISTRIB; REAL_EXP_ADD];
+    REPEAT GEN_TAC THEN
+    REPEAT_TCL DISJ_CASES_THEN (ANTE_RES_THEN (MP_TAC o SPEC `z:real`))
+     (REAL_ARITH `&0 <= x /\ &0 <= y \/ &0 <= x /\ &0 <= --y \/
+                  &0 <= --x /\ &0 <= y \/ &0 <= --x /\ &0 <= --y`) THEN
+    REWRITE_TAC[RPOW_LNEG; REAL_MUL_RNEG; REAL_MUL_LNEG] THEN
+    COND_CASES_TAC THEN
+    ASM_REWRITE_TAC[REAL_MUL_RNEG; REAL_MUL_LNEG; REAL_EQ_NEG2]]);;
+
+let RPOW_INV = prove
+ (`!x y. inv(x) rpow y = inv(x rpow y)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[rpow; REAL_LT_INV_EQ] THEN
+  SIMP_TAC[LOG_INV; REAL_MUL_RNEG; REAL_EXP_NEG] THEN
+  COND_CASES_TAC THEN REWRITE_TAC[] THEN
+  REWRITE_TAC[REAL_INV_EQ_0] THEN
+  REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_INV_1; REAL_INV_0]) THEN
+  ASM_SIMP_TAC[GSYM REAL_INV_NEG; LOG_INV;
+               REAL_ARITH `~(&0 < x) /\ ~(x = &0) ==> &0 < --x`] THEN
+  REWRITE_TAC[REAL_MUL_RNEG; REAL_EXP_NEG; REAL_INV_NEG]);;
+
+let REAL_INV_RPOW = prove
+ (`!x y. inv(x rpow y) = inv(x) rpow y`,
+  REWRITE_TAC[RPOW_INV]);;
+
+let RPOW_ADD = prove
+ (`!x y z. &0 < x ==> x rpow (y + z) = x rpow y * x rpow z`,
+  REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[rpow; REAL_ADD_RDISTRIB; REAL_EXP_ADD]);;
+
+let RPOW_ADD_ALT = prove
+ (`!x y z. &0 <= x /\ (x = &0 /\ y + z = &0 ==> y = &0 \/ z = &0)
+           ==> x rpow (y + z) = x rpow y * x rpow z`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `x = &0` THEN ASM_SIMP_TAC[REAL_LE_LT; RPOW_ADD] THEN
+  REWRITE_TAC[RPOW_ZERO] THEN
+  ASM_CASES_TAC `y = &0` THEN
+  ASM_REWRITE_TAC[REAL_MUL_LID; REAL_ADD_LID] THEN
+  ASM_CASES_TAC `y + z = &0` THEN ASM_REWRITE_TAC[] THEN
+  ASM_REAL_ARITH_TAC);;
+
+let RPOW_SQRT = prove
+ (`!x. &0 <= x ==> x rpow (&1 / &2) = sqrt x`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(REAL_RING
+   `x pow 2 = y pow 2 /\ (x + y = &0 ==> x = &0 /\ y = &0)
+    ==> x = y`) THEN
+  CONJ_TAC THENL
+   [ASM_SIMP_TAC[SQRT_POW_2] THEN
+    ASM_SIMP_TAC[GSYM RPOW_POW; RPOW_RPOW] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[RPOW_POW; REAL_POW_1];
+    MATCH_MP_TAC(REAL_ARITH
+     `&0 <= x /\ &0 <= y ==> x + y = &0 ==> x = &0 /\ y = &0`) THEN
+    ASM_SIMP_TAC[SQRT_POS_LE; RPOW_POS_LE]]);;
+
+let RPOW_MONO = prove
+ (`!a b x. &1 <= x /\ a <= b ==> x rpow a <= x rpow b`,
+  SIMP_TAC[rpow; REAL_ARITH `&1 <= x ==> &0 < x`] THEN
+  SIMP_TAC[REAL_EXP_MONO_LE; LOG_POS; REAL_LE_RMUL]);;
+
+let RPOW_MONO_INV = prove
+ (`!a b x. &0 < x /\ x <= &1 /\ b <= a ==> x rpow a <= x rpow b`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC BINOP_CONV [GSYM REAL_INV_INV] THEN
+  MATCH_MP_TAC REAL_LE_INV2 THEN
+  ASM_SIMP_TAC[REAL_LT_INV_EQ; RPOW_POS_LT; GSYM RPOW_INV] THEN
+  MATCH_MP_TAC RPOW_MONO THEN
+  ASM_SIMP_TAC[REAL_INV_1_LE]);;
+
+let RPOW_1_LE = prove
+ (`!a x. &0 <= x /\ x <= &1 /\ &0 <= a ==> x rpow a <= &1`,
+  REPEAT STRIP_TAC THEN  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `&1 rpow a` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC RPOW_LE2 THEN ASM_REAL_ARITH_TAC;
+    REWRITE_TAC[RPOW_ONE; REAL_LE_REFL]]);;
+
+let REAL_ROOT_RPOW = prove
+ (`!n x. ~(n = 0) /\ (&0 <= x \/ ODD n) ==> root n x = x rpow (inv(&n))`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `x = &0` THEN
+  ASM_SIMP_TAC[ROOT_0; RPOW_ZERO; REAL_INV_EQ_0; REAL_OF_NUM_EQ] THEN
+  ASM_CASES_TAC `&0 <= x` THEN ASM_REWRITE_TAC[] THEN STRIP_TAC THENL
+   [ASM_SIMP_TAC[ROOT_EXP_LOG; rpow; REAL_LT_LE] THEN AP_TERM_TAC THEN
+    REAL_ARITH_TAC;
+    ASM_REWRITE_TAC[rpow] THEN COND_CASES_TAC THENL
+     [ASM_REAL_ARITH_TAC; ALL_TAC] THEN
+    REWRITE_TAC[REAL_ABS_INV; REAL_ABS_NUM] THEN
+    REWRITE_TAC[REAL_ARITH `inv x = &1 / x`] THEN
+    COND_CASES_TAC THENL [ALL_TAC; ASM_MESON_TAC[ARITH]] THEN
+    MATCH_MP_TAC ROOT_UNIQUE THEN
+    ASM_REWRITE_TAC[REAL_POW_NEG; GSYM REAL_EXP_N; GSYM NOT_ODD] THEN
+    ASM_SIMP_TAC[REAL_OF_NUM_EQ; REAL_FIELD
+      `~(n = &0) ==> n * &1 / n * x = x`] THEN
+    ONCE_REWRITE_TAC[REAL_ARITH `--x:real = y <=> x = --y`] THEN
+    MATCH_MP_TAC EXP_LOG THEN ASM_REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Formulation of loop homotopy in terms of maps out of S^1                  *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMOTOPIC_CIRCLEMAPS_IMP_HOMOTOPIC_LOOPS = prove
+ (`!f:complex->real^N g s.
+        homotopic_with (\h. T) (sphere(vec 0,&1),s) f g
+        ==> homotopic_loops s (f o cexp o (\t. Cx(&2 * pi * drop t) * ii))
+                              (g o cexp o (\t. Cx(&2 * pi * drop t) * ii))`,
+  REWRITE_TAC[homotopic_loops; sphere; DIST_0] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC HOMOTOPIC_WITH_COMPOSE_CONTINUOUS_RIGHT THEN
+  EXISTS_TAC `{z:complex | norm z = &1}` THEN
+  REWRITE_TAC[pathstart; pathfinish; o_THM; DROP_VEC] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `&2 * pi * n = &2 * n * pi`] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; o_THM; IN_ELIM_THM] THEN
+  ASM_SIMP_TAC[CEXP_INTEGER_2PI; INTEGER_CLOSED] THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[COMPLEX_MUL_SYM] NORM_CEXP_II] THEN
+  MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN REWRITE_TAC[CONTINUOUS_ON_CEXP] THEN
+  REWRITE_TAC[CX_MUL] THEN
+  REPEAT(MATCH_MP_TAC CONTINUOUS_ON_COMPLEX_MUL THEN
+         REWRITE_TAC[CONTINUOUS_ON_CONST]) THEN
+  SIMP_TAC[CONTINUOUS_ON_CX_DROP; CONTINUOUS_ON_ID]);;
+
+let HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_CIRCLEMAPS = prove
+ (`!p q s:real^N->bool.
+        homotopic_loops s p q
+        ==> homotopic_with (\h. T) (sphere(vec 0,&1),s)
+                                   (p o (\z. lift(Arg z / (&2 * pi))))
+                                   (q o (\z. lift(Arg z / (&2 * pi))))`,
+ let ulemma = prove
+   (`!s. s INTER (UNIV PCROSS {z | &0 <= Im z}) UNION
+         s INTER (UNIV PCROSS {z | Im z <= &0}) = s`,
+    REWRITE_TAC[EXTENSION; FORALL_PASTECART; IN_INTER; IN_UNION;
+                 PASTECART_IN_PCROSS] THEN
+    SET_TAC[REAL_LE_TOTAL]) in
+  REPEAT GEN_TAC THEN REWRITE_TAC[homotopic_loops; sphere; DIST_0] THEN
+  GEN_REWRITE_TAC LAND_CONV [homotopic_with] THEN
+  SIMP_TAC[pathstart; pathfinish; LEFT_IMP_EXISTS_THM; HOMOTOPIC_WITH] THEN
+  X_GEN_TAC `h:real^(1,1)finite_sum->real^N` THEN STRIP_TAC THEN
+  EXISTS_TAC `\w. (h:real^(1,1)finite_sum->real^N)
+                  (pastecart (fstcart w)
+                             (lift(Arg(sndcart w) / (&2 * pi))))` THEN
+  ASM_REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART; o_THM] THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC CONTINUOUS_ON_EQ THEN
+    EXISTS_TAC
+     `(\z. if &0 <= Im(sndcart z)
+           then h (pastecart (fstcart z) (lift(Arg(sndcart z) / (&2 * pi))))
+           else h (pastecart (fstcart z)
+                             (vec 1 - lift(Arg(cnj(sndcart z)) / (&2 * pi)))))
+      :real^(1,2)finite_sum->real^N` THEN
+    REWRITE_TAC[FORALL_IN_PCROSS; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN CONJ_TAC THENL
+     [MAP_EVERY X_GEN_TAC [`t:real^1`; `z:complex`] THEN STRIP_TAC THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[ARG_CNJ] THEN
+      COND_CASES_TAC THENL [ASM_MESON_TAC[real; REAL_LE_REFL]; ALL_TAC] THEN
+      SIMP_TAC[PI_POS; LIFT_SUB; LIFT_NUM; REAL_FIELD
+        `&0 < pi ==> (&2 * pi - z) / (&2 * pi) = &1 - z / (&2 * pi)`] THEN
+      REWRITE_TAC[VECTOR_ARITH `a - (a - b):real^N = b`];
+      GEN_REWRITE_TAC RAND_CONV [GSYM ulemma] THEN
+      MATCH_MP_TAC CONTINUOUS_ON_CASES_LOCAL THEN REWRITE_TAC[ulemma] THEN
+      SIMP_TAC[CLOSED_IN_CLOSED_INTER; CLOSED_HALFSPACE_IM_LE; CLOSED_UNIV;
+        CLOSED_PCROSS; REWRITE_RULE[real_ge] CLOSED_HALFSPACE_IM_GE] THEN
+      REWRITE_TAC[FORALL_PASTECART; PASTECART_IN_PCROSS; IN_INTER; IN_DIFF;
+       FSTCART_PASTECART; SNDCART_PASTECART; IN_UNIV; IN_SING; IN_ELIM_THM;
+       GSYM CONJ_ASSOC; REAL_LE_ANTISYM; TAUT `~(p /\ ~p)`] THEN
+      REWRITE_TAC[CONJ_ASSOC] THEN CONJ_TAC THENL
+       [ALL_TAC;
+        REWRITE_TAC[GSYM ARG_EQ_0_PI; GSYM real; ARG_CNJ] THEN
+        REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+        SIMP_TAC[REAL_ARITH `&2 * x - x = x`; COND_ID; GSYM LIFT_NUM; PI_POS;
+         GSYM LIFT_SUB; REAL_FIELD
+          `&0 < pi ==> &1 - pi / (&2 * pi) = pi / (&2 * pi)`] THEN
+        COND_CASES_TAC THEN
+        SIMP_TAC[REAL_SUB_RZERO; REAL_DIV_REFL; REAL_ENTIRE; REAL_OF_NUM_EQ;
+                 ARITH_EQ; PI_NZ] THEN
+        SIMP_TAC[real_div; REAL_MUL_LZERO; REAL_SUB_REFL; REAL_SUB_RZERO] THEN
+        ASM_SIMP_TAC[LIFT_NUM]] THEN
+      GEN_REWRITE_TAC (BINOP_CONV o LAND_CONV) [GSYM o_DEF] THEN
+      CONJ_TAC THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN CONJ_TAC THENL
+       [MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART] THEN
+        REWRITE_TAC[real_div; REWRITE_RULE[REAL_MUL_SYM] LIFT_CMUL] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_VMUL THEN
+        GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM o_DEF] THEN
+        REWRITE_TAC[o_ASSOC] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART] THEN
+        REWRITE_TAC[o_DEF; GSYM CONTINUOUS_ON_CX_LIFT] THEN
+        MP_TAC CONTINUOUS_ON_UPPERHALF_ARG THEN REWRITE_TAC[o_DEF] THEN
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] CONTINUOUS_ON_SUBSET) THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_PASTECART; IN_INTER;
+                    PASTECART_IN_PCROSS; IN_ELIM_THM; SNDCART_PASTECART] THEN
+        MAP_EVERY X_GEN_TAC [`t:real^1`; `z:complex`] THEN
+        SIMP_TAC[IN_DIFF; IN_ELIM_THM; IN_SING] THEN
+        ASM_CASES_TAC `z = Cx(&0)` THEN ASM_REWRITE_TAC[COMPLEX_NORM_0] THEN
+        REWRITE_TAC[REAL_OF_NUM_EQ; ARITH_EQ];
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_PASTECART; IN_INTER;
+                    PASTECART_IN_PCROSS; IN_ELIM_THM; SNDCART_PASTECART;
+                    FSTCART_PASTECART] THEN
+        SIMP_TAC[IN_INTERVAL_1; LIFT_DROP; DROP_VEC] THEN
+        SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; PI_POS; REAL_MUL_LZERO;
+             REAL_MUL_LID; REAL_ARITH `&0 < &2 * x <=> &0 < x`] THEN
+        SIMP_TAC[ARG; REAL_LT_IMP_LE];
+        MATCH_MP_TAC CONTINUOUS_ON_PASTECART THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_FSTCART] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_SUB THEN
+        REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+        REWRITE_TAC[real_div; REWRITE_RULE[REAL_MUL_SYM] LIFT_CMUL] THEN
+        MATCH_MP_TAC CONTINUOUS_ON_VMUL THEN
+        GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM o_DEF] THEN
+        REWRITE_TAC[o_ASSOC] THEN MATCH_MP_TAC CONTINUOUS_ON_COMPOSE THEN
+        GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [GSYM o_DEF] THEN
+        SIMP_TAC[LINEAR_CONTINUOUS_ON; LINEAR_SNDCART; CONTINUOUS_ON_COMPOSE;
+                 CONTINUOUS_ON_CNJ] THEN
+        REWRITE_TAC[o_DEF; GSYM CONTINUOUS_ON_CX_LIFT] THEN
+        MP_TAC CONTINUOUS_ON_UPPERHALF_ARG THEN REWRITE_TAC[o_DEF] THEN
+        MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] CONTINUOUS_ON_SUBSET) THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_PASTECART; IN_INTER;
+                    PASTECART_IN_PCROSS; IN_ELIM_THM; SNDCART_PASTECART] THEN
+        MAP_EVERY X_GEN_TAC [`t:real^1`; `z:complex`] THEN
+        SIMP_TAC[IN_DIFF; IN_ELIM_THM; IN_SING] THEN
+        SIMP_TAC[IM_CNJ; REAL_NEG_GE0; CNJ_EQ_0] THEN
+        ASM_CASES_TAC `z = Cx(&0)` THEN ASM_REWRITE_TAC[COMPLEX_NORM_0] THEN
+        REWRITE_TAC[REAL_OF_NUM_EQ; ARITH_EQ];
+        FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+          CONTINUOUS_ON_SUBSET)) THEN
+        REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_PASTECART; IN_INTER;
+                    PASTECART_IN_PCROSS; IN_ELIM_THM; SNDCART_PASTECART;
+                    FSTCART_PASTECART] THEN
+        SIMP_TAC[IN_INTERVAL_1; DROP_SUB; DROP_VEC; LIFT_DROP] THEN
+        REWRITE_TAC[REAL_ARITH `&0 <= &1 - x /\ &1 - x <= &1 <=>
+                                &0 <= x /\ x <= &1`] THEN
+        SIMP_TAC[REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; PI_POS; REAL_MUL_LZERO;
+             REAL_MUL_LID; REAL_ARITH `&0 < &2 * x <=> &0 < x`] THEN
+        SIMP_TAC[ARG; REAL_LT_IMP_LE]]];
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; FORALL_IN_PCROSS; IN_ELIM_THM] THEN
+    REWRITE_TAC[FSTCART_PASTECART; SNDCART_PASTECART] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (SET_RULE
+     `IMAGE h s SUBSET t ==> y IN s ==> h y IN t`)) THEN
+    ASM_REWRITE_TAC[PASTECART_IN_PCROSS; IN_INTERVAL_1; LIFT_DROP] THEN
+    SIMP_TAC[DROP_VEC; REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ; PI_POS;
+             REAL_ARITH `&0 < &2 * x <=> &0 < x`] THEN
+    SIMP_TAC[REAL_MUL_LZERO; REAL_MUL_LID; ARG; REAL_LT_IMP_LE]]);;
+
+let SIMPLY_CONNECTED_EQ_HOMOTOPIC_CIRCLEMAPS,
+    SIMPLY_CONNECTED_EQ_CONTRACTIBLE_CIRCLEMAP =
+ (CONJ_PAIR o prove)
+ (`(!s:real^N->bool.
+        simply_connected s <=>
+        !f g:complex->real^N.
+              f continuous_on sphere(vec 0,&1) /\
+              IMAGE f (sphere(vec 0,&1)) SUBSET s /\
+              g continuous_on sphere(vec 0,&1) /\
+              IMAGE g (sphere(vec 0,&1)) SUBSET s
+              ==> homotopic_with (\h. T) (sphere(vec 0,&1),s) f g) /\
+   (!s:real^N->bool.
+      simply_connected s <=>
+      path_connected s /\
+      !f:real^2->real^N.
+              f continuous_on sphere(vec 0,&1) /\
+              IMAGE f (sphere(vec 0,&1)) SUBSET s
+              ==> ?a. homotopic_with (\h. T) (sphere(vec 0,&1),s) f (\x. a))`,
+  REWRITE_TAC[AND_FORALL_THM] THEN GEN_TAC THEN MATCH_MP_TAC(TAUT
+   `(p ==> q) /\ (q ==> r) /\ (r ==> p) ==> (p <=> q) /\ (p <=> r)`) THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[simply_connected] THEN DISCH_TAC THEN
+    MAP_EVERY X_GEN_TAC [`f:complex->real^N`; `g:complex->real^N`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
+     [`(f:complex->real^N) o cexp o (\t. Cx(&2 * pi * drop t) * ii)`;
+      `(g:complex->real^N) o cexp o (\t. Cx(&2 * pi * drop t) * ii)`]) THEN
+    ONCE_REWRITE_TAC[TAUT `p1 /\ q1 /\ r1 /\ p2 /\ q2 /\ r2 <=>
+                           (p1 /\ r1 /\ q1) /\ (p2 /\ r2 /\ q2)`] THEN
+    REWRITE_TAC[GSYM HOMOTOPIC_LOOPS_REFL] THEN
+    ASM_SIMP_TAC[HOMOTOPIC_CIRCLEMAPS_IMP_HOMOTOPIC_LOOPS;
+                 HOMOTOPIC_WITH_REFL] THEN
+    DISCH_THEN(MP_TAC o MATCH_MP HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_CIRCLEMAPS) THEN
+    MATCH_MP_TAC(ONCE_REWRITE_RULE[IMP_CONJ_ALT] HOMOTOPIC_WITH_EQ) THEN
+    REWRITE_TAC[IN_SPHERE_0; LIFT_DROP; o_DEF] THEN X_GEN_TAC `z:complex` THEN
+    REPEAT STRIP_TAC THEN AP_TERM_TAC THEN MP_TAC(SPEC `z:complex` ARG) THEN
+    ASM_REWRITE_TAC[COMPLEX_MUL_LID] THEN
+    DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THEN SIMP_TAC[PI_POS;
+      REAL_FIELD `&0 < pi ==> &2 * pi * x / (&2 * pi) = x`] THEN
+    ASM_MESON_TAC[COMPLEX_MUL_SYM];
+    DISCH_TAC THEN CONJ_TAC THENL
+     [REWRITE_TAC[PATH_CONNECTED_EQ_HOMOTOPIC_POINTS] THEN
+      MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N`] THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(MP_TAC o SPECL
+       [`(\x. a):complex->real^N`; `(\x. b):complex->real^N`]) THEN
+      REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+      ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN DISCH_THEN
+       (MP_TAC o MATCH_MP HOMOTOPIC_CIRCLEMAPS_IMP_HOMOTOPIC_LOOPS) THEN
+      REWRITE_TAC[o_DEF; LINEPATH_REFL];
+      X_GEN_TAC `f:complex->real^N` THEN STRIP_TAC THEN
+      EXISTS_TAC `f(Cx(&1)):real^N` THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      ASM_REWRITE_TAC[CONTINUOUS_ON_CONST] THEN
+      RULE_ASSUM_TAC(REWRITE_RULE[SUBSET; FORALL_IN_IMAGE; IN_SPHERE_0]) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_SPHERE_0] THEN
+      REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      REWRITE_TAC[COMPLEX_NORM_CX] THEN REAL_ARITH_TAC];
+    STRIP_TAC THEN
+    ASM_REWRITE_TAC[SIMPLY_CONNECTED_EQ_CONTRACTIBLE_LOOP_SOME] THEN
+    X_GEN_TAC `p:real^1->real^N` THEN STRIP_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC
+     `(p:real^1->real^N) o (\z. lift(Arg z / (&2 * pi)))`) THEN
+    ANTS_TAC THENL
+     [MP_TAC(ISPECL [`s:real^N->bool`; `p:real^1->real^N`]
+        HOMOTOPIC_LOOPS_REFL) THEN
+      ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o MATCH_MP
+        HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_CIRCLEMAPS) THEN
+      SIMP_TAC[HOMOTOPIC_WITH_REFL];
+      MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^N` THEN
+      STRIP_TAC THEN FIRST_ASSUM
+       (MP_TAC o MATCH_MP HOMOTOPIC_CIRCLEMAPS_IMP_HOMOTOPIC_LOOPS) THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP HOMOTOPIC_WITH_IMP_SUBSET) THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_SPHERE_0; o_DEF] THEN
+      DISCH_THEN(MP_TAC o SPEC `Cx(&1)` o CONJUNCT2) THEN
+      REWRITE_TAC[COMPLEX_NORM_CX; REAL_ABS_NUM] THEN
+      STRIP_TAC THEN ASM_REWRITE_TAC[LINEPATH_REFL] THEN
+      MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] HOMOTOPIC_LOOPS_TRANS) THEN
+      MATCH_MP_TAC HOMOTOPIC_LOOPS_EQ THEN ASM_REWRITE_TAC[] THEN
+      REWRITE_TAC[IN_INTERVAL_1; FORALL_LIFT; LIFT_DROP; DROP_VEC] THEN
+      X_GEN_TAC `t:real` THEN STRIP_TAC THEN ASM_CASES_TAC `t = &1` THENL
+       [ASM_REWRITE_TAC[REAL_ARITH `&2 * pi * &1 = &2 * &1 * pi`] THEN
+        SIMP_TAC[CEXP_INTEGER_2PI; INTEGER_CLOSED; ARG_NUM] THEN
+        REWRITE_TAC[real_div; REAL_MUL_LZERO; LIFT_NUM] THEN
+        ASM_MESON_TAC[pathstart; pathfinish];
+        AP_TERM_TAC THEN AP_TERM_TAC THEN SIMP_TAC[PI_POS; REAL_FIELD
+         `&0 < pi ==> (t = x / (&2 * pi) <=> x = &2 * pi * t)`] THEN
+        MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `Im(Cx (&2 * pi * t) * ii)` THEN
+        CONJ_TAC THENL [MATCH_MP_TAC ARG_CEXP; ALL_TAC] THEN
+        SIMP_TAC[IM_MUL_II; RE_CX; REAL_ARITH
+          `a < &2 * pi <=> a < &2 * pi * &1`] THEN
+        ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_LMUL_EQ; REAL_OF_NUM_LT; ARITH;
+                     PI_POS; REAL_LT_IMP_LE; REAL_POS; REAL_LE_MUL] THEN
+        ASM_REWRITE_TAC[REAL_LT_LE]]]]);;
+
+let HOMOTOPY_EQUIVALENT_SIMPLE_CONNECTEDNESS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s homotopy_equivalent t
+        ==> (simply_connected s <=> simply_connected t)`,
+  REWRITE_TAC[SIMPLY_CONNECTED_EQ_HOMOTOPIC_CIRCLEMAPS] THEN
+  REWRITE_TAC[HOMOTOPY_EQUIVALENT_HOMOTOPIC_TRIVIALITY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Homeomorphism of simple closed curves to circles.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let HOMEOMORPHIC_SIMPLE_PATH_IMAGE_CIRCLE = prove
+ (`!g:real^1->real^N a:real^2 r.
+        simple_path g /\ pathfinish g = pathstart g /\ &0 < r
+        ==> (path_image g) homeomorphic sphere(a,r)`,
+  REPEAT STRIP_TAC THEN
+  TRANS_TAC HOMEOMORPHIC_TRANS `sphere(vec 0:real^2,&1)` THEN
+  ASM_SIMP_TAC[HOMEOMORPHIC_SPHERES; REAL_LT_01] THEN MP_TAC(ISPECL
+   [`g:real^1->real^N`; `g:real^1->real^N`; `path_image(g:real^1->real^N)`]
+   HOMOTOPIC_LOOPS_IMP_HOMOTOPIC_CIRCLEMAPS) THEN
+  REWRITE_TAC[HOMOTOPIC_LOOPS_REFL; HOMOTOPIC_WITH_REFL; SUBSET_REFL] THEN
+  ASM_SIMP_TAC[SIMPLE_PATH_IMP_PATH] THEN STRIP_TAC THEN
+  ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM] THEN REWRITE_TAC[homeomorphic] THEN
+  EXISTS_TAC `(g:real^1->real^N) o (\z. lift(Arg z / (&2 * pi)))` THEN
+  MATCH_MP_TAC HOMEOMORPHISM_COMPACT THEN
+  ASM_REWRITE_TAC[COMPACT_SPHERE] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SUBSET_ANTISYM THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[SUBSET; path_image; FORALL_IN_IMAGE; IN_INTERVAL_1] THEN
+    X_GEN_TAC `t:real^1` THEN REWRITE_TAC[DROP_VEC] THEN STRIP_TAC THEN
+    REWRITE_TAC[IN_IMAGE; o_THM; IN_SPHERE_0] THEN
+    ASM_CASES_TAC `t:real^1 = vec 1` THENL
+     [EXISTS_TAC `Cx(&1)` THEN
+      ASM_REWRITE_TAC[ARG_NUM; COMPLEX_NORM_CX; real_div; REAL_MUL_LZERO] THEN
+      REWRITE_TAC[LIFT_NUM; REAL_ABS_NUM] THEN
+      ASM_MESON_TAC[pathstart; pathfinish];
+      EXISTS_TAC `cexp(ii * Cx(&2 * pi * drop t))` THEN
+      REWRITE_TAC[NORM_CEXP_II] THEN AP_TERM_TAC THEN
+      W(MP_TAC o PART_MATCH (lhand o rand) ARG_CEXP o
+        lhand o rand o rand o snd) THEN
+      REWRITE_TAC[IM_MUL_II; RE_CX] THEN ANTS_TAC THENL
+       [ASM_SIMP_TAC[REAL_LE_MUL; PI_POS_LE; REAL_POS] THEN
+        SIMP_TAC[REAL_ARITH `&2 * pi * x < &2 * pi <=> pi * x < pi * &1`;
+                 REAL_LT_LMUL_EQ; PI_POS] THEN
+        ASM_REWRITE_TAC[REAL_LT_LE] THEN
+        ASM_REWRITE_TAC[GSYM LIFT_EQ; LIFT_DROP; LIFT_NUM];
+        DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[GSYM DROP_EQ; LIFT_DROP] THEN
+        MP_TAC PI_POS THEN CONV_TAC REAL_FIELD]];
+    MAP_EVERY X_GEN_TAC [`w:complex`; `z:complex`] THEN
+    REWRITE_TAC[IN_SPHERE_0] THEN STRIP_TAC THEN
+    MAP_EVERY (SUBST1_TAC o last o CONJUNCTS o C SPEC ARG)
+     [`w:complex`; `z:complex`] THEN
+    FIRST_X_ASSUM(MP_TAC o SYM o SYM) THEN
+    ASM_REWRITE_TAC[o_DEF; COMPLEX_MUL_LID] THEN DISCH_TAC THEN
+    AP_TERM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    MATCH_MP_TAC(REAL_FIELD
+     `&0 < pi /\ x / (&2 * pi) = y / (&2 * pi) ==> x = y`) THEN
+    REWRITE_TAC[PI_POS; GSYM LIFT_EQ] THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [simple_path]) THEN
+    DISCH_THEN(MP_TAC  o SPECL
+     [`lift(Arg w / (&2 * pi))`; `lift(Arg z / (&2 * pi))`] o CONJUNCT2) THEN
+    ASM_REWRITE_TAC[GSYM LIFT_NUM; IN_INTERVAL_1; LIFT_DROP; LIFT_EQ] THEN
+    ASM_SIMP_TAC[REAL_LE_RDIV_EQ; REAL_LE_LDIV_EQ; PI_POS;
+                 REAL_ARITH `&0 < &2 * x <=> &0 < x`;
+                 REAL_FIELD `&0 < y ==> (x / y = &1 <=> x = y)`] THEN
+    SIMP_TAC[REAL_MUL_LZERO; REAL_MUL_LID; ARG; REAL_LT_IMP_LE;
+             REAL_LT_IMP_NE]]);;
+
+let HOMEOMORPHIC_SIMPLE_PATH_IMAGES = prove
+ (`!g:real^1->real^M h:real^1->real^N.
+        simple_path g /\ pathfinish g = pathstart g /\
+        simple_path h /\ pathfinish h = pathstart h
+        ==> (path_image g) homeomorphic (path_image h)`,
+  REPEAT STRIP_TAC THEN
+  TRANS_TAC HOMEOMORPHIC_TRANS `sphere(vec 0:real^2,&1)` THEN
+  CONJ_TAC THENL [ALL_TAC; ONCE_REWRITE_TAC[HOMEOMORPHIC_SYM]] THEN
+  MATCH_MP_TAC HOMEOMORPHIC_SIMPLE_PATH_IMAGE_CIRCLE THEN
+  ASM_REWRITE_TAC[REAL_LT_01]);;
+
+let ANR_PATH_IMAGE_SIMPLE_PATH = prove
+ (`!g:real^1->real^N.
+        simple_path g ==> ?t. open t /\ (path_image g) retract_of t`,
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `pathfinish g:real^N = pathstart g` THENL
+   [MP_TAC(ISPECL [`g:real^1->real^N`; `vec 0:real^2`; `&1`]
+        HOMEOMORPHIC_SIMPLE_PATH_IMAGE_CIRCLE) THEN
+    ASM_REWRITE_TAC[REAL_LT_01] THEN
+    DISCH_THEN(SUBST1_TAC o MATCH_MP HOMEOMORPHIC_ANRNESS) THEN
+    EXISTS_TAC `(:real^2) DELETE (vec 0)` THEN
+    SIMP_TAC[OPEN_DELETE; OPEN_UNIV] THEN
+    MATCH_MP_TAC SPHERE_RETRACT_OF_PUNCTURED_UNIVERSE THEN
+    REWRITE_TAC[REAL_LT_01];
+    EXISTS_TAC `(:real^N)` THEN REWRITE_TAC[OPEN_UNIV] THEN
+    MATCH_MP_TAC ABSOLUTE_RETRACT_PATH_IMAGE_ARC THEN
+    ASM_REWRITE_TAC[ARC_SIMPLE_PATH; SUBSET_UNIV]]);;
diff --git a/Multivariate/vectors.ml b/Multivariate/vectors.ml
new file mode 100644 (file)
index 0000000..55d018e
--- /dev/null
@@ -0,0 +1,8489 @@
+(* ========================================================================= *)
+(* Real vectors in Euclidean space, and elementary linear algebra.           *)
+(*                                                                           *)
+(*              (c) Copyright, John Harrison 1998-2008                       *)
+(* ========================================================================= *)
+
+needs "Multivariate/misc.ml";;
+
+(* ------------------------------------------------------------------------- *)
+(* Some common special cases.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let FORALL_1 = prove
+ (`(!i. 1 <= i /\ i <= 1 ==> P i) <=> P 1`,
+  MESON_TAC[LE_ANTISYM]);;
+
+let FORALL_2 = prove
+ (`!P. (!i. 1 <= i /\ i <= 2 ==> P i) <=> P 1 /\ P 2`,
+  MESON_TAC[ARITH_RULE `1 <= i /\ i <= 2 <=> i = 1 \/ i = 2`]);;
+
+let FORALL_3 = prove
+ (`!P. (!i. 1 <= i /\ i <= 3 ==> P i) <=> P 1 /\ P 2 /\ P 3`,
+  MESON_TAC[ARITH_RULE `1 <= i /\ i <= 3 <=> i = 1 \/ i = 2 \/ i = 3`]);;
+
+let FORALL_4 = prove
+ (`!P. (!i. 1 <= i /\ i <= 4 ==> P i) <=> P 1 /\ P 2 /\ P 3 /\ P 4`,
+  MESON_TAC[ARITH_RULE `1 <= i /\ i <= 4 <=>
+    i = 1 \/ i = 2 \/ i = 3 \/ i = 4`]);;
+
+let SUM_1 = prove
+ (`sum(1..1) f = f(1)`,
+  REWRITE_TAC[SUM_SING_NUMSEG]);;
+
+let SUM_2 = prove
+ (`!t. sum(1..2) t = t(1) + t(2)`,
+  REWRITE_TAC[num_CONV `2`; SUM_CLAUSES_NUMSEG] THEN
+  REWRITE_TAC[SUM_SING_NUMSEG; ARITH; REAL_ADD_ASSOC]);;
+
+let SUM_3 = prove
+ (`!t. sum(1..3) t = t(1) + t(2) + t(3)`,
+  REWRITE_TAC[num_CONV `3`; num_CONV `2`; SUM_CLAUSES_NUMSEG] THEN
+  REWRITE_TAC[SUM_SING_NUMSEG; ARITH; REAL_ADD_ASSOC]);;
+
+let SUM_4 = prove
+ (`!t. sum(1..4) t = t(1) + t(2) + t(3) + t(4)`,
+  SIMP_TAC[num_CONV `4`; num_CONV `3`; num_CONV `2`; SUM_CLAUSES_NUMSEG] THEN
+  REWRITE_TAC[SUM_SING_NUMSEG; ARITH; REAL_ADD_ASSOC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic componentwise operations on vectors.                                *)
+(* ------------------------------------------------------------------------- *)
+
+let vector_add = new_definition
+  `(vector_add:real^N->real^N->real^N) x y = lambda i. x$i + y$i`;;
+
+let vector_sub = new_definition
+  `(vector_sub:real^N->real^N->real^N) x y = lambda i. x$i - y$i`;;
+
+let vector_neg = new_definition
+  `(vector_neg:real^N->real^N) x = lambda i. --(x$i)`;;
+
+overload_interface ("+",`(vector_add):real^N->real^N->real^N`);;
+overload_interface ("-",`(vector_sub):real^N->real^N->real^N`);;
+overload_interface ("--",`(vector_neg):real^N->real^N`);;
+
+prioritize_real();;
+
+let prioritize_vector = let ty = `:real^N` in
+  fun () -> prioritize_overload ty;;
+
+(* ------------------------------------------------------------------------- *)
+(* Also the scalar-vector multiplication.                                    *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("%",(21,"right"));;
+
+let vector_mul = new_definition
+  `((%):real->real^N->real^N) c x = lambda i. c * x$i`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Vectors corresponding to small naturals. Perhaps should overload "&"?     *)
+(* ------------------------------------------------------------------------- *)
+
+let vec = new_definition
+  `(vec:num->real^N) n = lambda i. &n`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Dot products.                                                             *)
+(* ------------------------------------------------------------------------- *)
+
+parse_as_infix("dot",(20,"right"));;
+
+let dot = new_definition
+  `(x:real^N) dot (y:real^N) = sum(1..dimindex(:N)) (\i. x$i * y$i)`;;
+
+let DOT_1 = prove
+ (`(x:real^1) dot (y:real^1) = x$1 * y$1`,
+  REWRITE_TAC[dot; DIMINDEX_1; SUM_1]);;
+
+let DOT_2 = prove
+ (`(x:real^2) dot (y:real^2) = x$1 * y$1 + x$2 * y$2`,
+  REWRITE_TAC[dot; DIMINDEX_2; SUM_2]);;
+
+let DOT_3 = prove
+ (`(x:real^3) dot (y:real^3) = x$1 * y$1 + x$2 * y$2 + x$3 * y$3`,
+  REWRITE_TAC[dot; DIMINDEX_3; SUM_3]);;
+
+let DOT_4 = prove
+ (`(x:real^4) dot (y:real^4) = x$1 * y$1 + x$2 * y$2 + x$3 * y$3 + x$4 * y$4`,
+  REWRITE_TAC[dot; DIMINDEX_4; SUM_4]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A naive proof procedure to lift really trivial arithmetic stuff from R.   *)
+(* ------------------------------------------------------------------------- *)
+
+let VECTOR_ARITH_TAC =
+  let RENAMED_LAMBDA_BETA th =
+    if fst(dest_fun_ty(type_of(funpow 3 rand (concl th)))) = aty
+    then INST_TYPE [aty,bty; bty,aty] LAMBDA_BETA else LAMBDA_BETA in
+  POP_ASSUM_LIST(K ALL_TAC) THEN
+  REPEAT(GEN_TAC ORELSE CONJ_TAC ORELSE DISCH_TAC ORELSE EQ_TAC) THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN REWRITE_TAC[IMP_IMP; GSYM CONJ_ASSOC] THEN
+  REWRITE_TAC[dot; GSYM SUM_ADD_NUMSEG; GSYM SUM_SUB_NUMSEG;
+              GSYM SUM_LMUL; GSYM SUM_RMUL; GSYM SUM_NEG] THEN
+  (MATCH_MP_TAC SUM_EQ_NUMSEG ORELSE MATCH_MP_TAC SUM_EQ_0_NUMSEG ORELSE
+   GEN_REWRITE_TAC ONCE_DEPTH_CONV [CART_EQ]) THEN
+  REWRITE_TAC[AND_FORALL_THM] THEN TRY EQ_TAC THEN
+  TRY(MATCH_MP_TAC MONO_FORALL) THEN GEN_TAC THEN
+  REWRITE_TAC[TAUT `(a ==> b) /\ (a ==> c) <=> a ==> b /\ c`;
+              TAUT `(a ==> b) \/ (a ==> c) <=> a ==> b \/ c`] THEN
+  TRY(MATCH_MP_TAC(TAUT `(a ==> b ==> c) ==> (a ==> b) ==> (a ==> c)`)) THEN
+  REWRITE_TAC[vector_add; vector_sub; vector_neg; vector_mul; vec] THEN
+  DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP(RENAMED_LAMBDA_BETA th) th]) THEN
+  REAL_ARITH_TAC;;
+
+let VECTOR_ARITH tm = prove(tm,VECTOR_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Obvious "component-pushing".                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let VEC_COMPONENT = prove
+ (`!k i. (vec k :real^N)$i = &k`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:N) /\ !z:real^N. z$i = z$k`
+  CHOOSE_TAC THENL
+   [REWRITE_TAC[FINITE_INDEX_INRANGE];
+    ASM_SIMP_TAC[vec; CART_EQ; LAMBDA_BETA]]);;
+
+let VECTOR_ADD_COMPONENT = prove
+ (`!x:real^N y i. (x + y)$i = x$i + y$i`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:N) /\ !z:real^N. z$i = z$k`
+  CHOOSE_TAC THENL
+   [REWRITE_TAC[FINITE_INDEX_INRANGE];
+    ASM_SIMP_TAC[vector_add; CART_EQ; LAMBDA_BETA]]);;
+
+let VECTOR_SUB_COMPONENT = prove
+ (`!x:real^N y i. (x - y)$i = x$i - y$i`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:N) /\ !z:real^N. z$i = z$k`
+  CHOOSE_TAC THENL
+   [REWRITE_TAC[FINITE_INDEX_INRANGE];
+    ASM_SIMP_TAC[vector_sub; CART_EQ; LAMBDA_BETA]]);;
+
+let VECTOR_NEG_COMPONENT = prove
+ (`!x:real^N i. (--x)$i = --(x$i)`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:N) /\ !z:real^N. z$i = z$k`
+  CHOOSE_TAC THENL
+   [REWRITE_TAC[FINITE_INDEX_INRANGE];
+    ASM_SIMP_TAC[vector_neg; CART_EQ; LAMBDA_BETA]]);;
+
+let VECTOR_MUL_COMPONENT = prove
+ (`!c x:real^N i. (c % x)$i = c * x$i`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:N) /\ !z:real^N. z$i = z$k`
+  CHOOSE_TAC THENL
+   [REWRITE_TAC[FINITE_INDEX_INRANGE];
+    ASM_SIMP_TAC[vector_mul; CART_EQ; LAMBDA_BETA]]);;
+
+let COND_COMPONENT = prove
+ (`(if b then x else y)$i = if b then x$i else y$i`,
+  MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some frequently useful arithmetic lemmas over vectors.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let VECTOR_ADD_SYM = VECTOR_ARITH `!x y:real^N. x + y = y + x`;;
+
+let VECTOR_ADD_LID = VECTOR_ARITH `!x. vec 0 + x = x`;;
+
+let VECTOR_ADD_RID = VECTOR_ARITH `!x. x + vec 0 = x`;;
+
+let VECTOR_SUB_REFL = VECTOR_ARITH `!x. x - x = vec 0`;;
+
+let VECTOR_ADD_LINV = VECTOR_ARITH `!x. --x + x = vec 0`;;
+
+let VECTOR_ADD_RINV = VECTOR_ARITH `!x. x + --x = vec 0`;;
+
+let VECTOR_SUB_RADD = VECTOR_ARITH `!x y. x - (x + y) = --y:real^N`;;
+
+let VECTOR_NEG_SUB = VECTOR_ARITH `!x:real^N y. --(x - y) = y - x`;;
+
+let VECTOR_SUB_EQ = VECTOR_ARITH `!x y. (x - y = vec 0) <=> (x = y)`;;
+
+let VECTOR_MUL_ASSOC = VECTOR_ARITH `!a b x. a % (b % x) = (a * b) % x`;;
+
+let VECTOR_MUL_LID = VECTOR_ARITH `!x. &1 % x = x`;;
+
+let VECTOR_MUL_LZERO = VECTOR_ARITH `!x. &0 % x = vec 0`;;
+
+let VECTOR_SUB_ADD = VECTOR_ARITH `(x - y) + y = x:real^N`;;
+
+let VECTOR_SUB_ADD2 = VECTOR_ARITH `y + (x - y) = x:real^N`;;
+
+let VECTOR_ADD_LDISTRIB = VECTOR_ARITH `c % (x + y) = c % x + c % y`;;
+
+let VECTOR_SUB_LDISTRIB = VECTOR_ARITH `c % (x - y) = c % x - c % y`;;
+
+let VECTOR_ADD_RDISTRIB = VECTOR_ARITH `(a + b) % x = a % x + b % x`;;
+
+let VECTOR_SUB_RDISTRIB = VECTOR_ARITH `(a - b) % x = a % x - b % x`;;
+
+let VECTOR_ADD_SUB = VECTOR_ARITH `(x + y:real^N) - x = y`;;
+
+let VECTOR_EQ_ADDR = VECTOR_ARITH `(x + y = x) <=> (y = vec 0)`;;
+
+let VECTOR_SUB = VECTOR_ARITH `x - y = x + --(y:real^N)`;;
+
+let VECTOR_SUB_RZERO = VECTOR_ARITH `x - vec 0 = x`;;
+
+let VECTOR_MUL_RZERO = VECTOR_ARITH `c % vec 0 = vec 0`;;
+
+let VECTOR_NEG_MINUS1 = VECTOR_ARITH `--x = (--(&1)) % x`;;
+
+let VECTOR_ADD_ASSOC = VECTOR_ARITH `(x:real^N) + y + z = (x + y) + z`;;
+
+let VECTOR_SUB_LZERO = VECTOR_ARITH `vec 0 - x = --x`;;
+
+let VECTOR_NEG_NEG = VECTOR_ARITH `--(--(x:real^N)) = x`;;
+
+let VECTOR_MUL_LNEG = VECTOR_ARITH `--c % x = --(c % x)`;;
+
+let VECTOR_MUL_RNEG = VECTOR_ARITH `c % --x = --(c % x)`;;
+
+let VECTOR_NEG_0 = VECTOR_ARITH `--(vec 0) = vec 0`;;
+
+let VECTOR_NEG_EQ_0 = VECTOR_ARITH `--x = vec 0 <=> x = vec 0`;;
+
+let VECTOR_EQ_NEG2 = VECTOR_ARITH `!x y:real^N. --x = --y <=> x = y`;;
+
+let VECTOR_ADD_AC = VECTOR_ARITH
+  `(m + n = n + m:real^N) /\
+   ((m + n) + p = m + n + p) /\
+   (m + n + p = n + m + p)`;;
+
+let VEC_EQ = prove
+ (`!m n. (vec m = vec n) <=> (m = n)`,
+  SIMP_TAC[CART_EQ; VEC_COMPONENT; REAL_OF_NUM_EQ] THEN
+  MESON_TAC[LE_REFL; DIMINDEX_GE_1]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Infinitude of Euclidean space.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let EUCLIDEAN_SPACE_INFINITE = prove
+ (`INFINITE(:real^N)`,
+  REWRITE_TAC[INFINITE] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o ISPEC `vec:num->real^N` o
+    MATCH_MP (REWRITE_RULE[IMP_CONJ_ALT] FINITE_IMAGE_INJ)) THEN
+  REWRITE_TAC[VEC_EQ; SET_RULE `{x | f x IN UNIV} = UNIV`] THEN
+  REWRITE_TAC[GSYM INFINITE; num_INFINITE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Properties of the dot product.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let DOT_SYM = VECTOR_ARITH `!x y. x dot y = y dot x`;;
+
+let DOT_LADD = VECTOR_ARITH `!x y z. (x + y) dot z = (x dot z) + (y dot z)`;;
+
+let DOT_RADD = VECTOR_ARITH `!x y z. x dot (y + z) = (x dot y) + (x dot z)`;;
+
+let DOT_LSUB = VECTOR_ARITH `!x y z. (x - y) dot z = (x dot z) - (y dot z)`;;
+
+let DOT_RSUB = VECTOR_ARITH `!x y z. x dot (y - z) = (x dot y) - (x dot z)`;;
+
+let DOT_LMUL = VECTOR_ARITH `!c x y. (c % x) dot y = c * (x dot y)`;;
+
+let DOT_RMUL = VECTOR_ARITH `!c x y. x dot (c % y) = c * (x dot y)`;;
+
+let DOT_LNEG = VECTOR_ARITH `!x y. (--x) dot y = --(x dot y)`;;
+
+let DOT_RNEG = VECTOR_ARITH `!x y. x dot (--y) = --(x dot y)`;;
+
+let DOT_LZERO = VECTOR_ARITH `!x. (vec 0) dot x = &0`;;
+
+let DOT_RZERO = VECTOR_ARITH `!x. x dot (vec 0) = &0`;;
+
+let DOT_POS_LE = prove
+ (`!x. &0 <= x dot x`,
+  SIMP_TAC[dot; SUM_POS_LE_NUMSEG; REAL_LE_SQUARE]);;
+
+let DOT_EQ_0 = prove
+ (`!x:real^N. ((x dot x = &0) <=> (x = vec 0))`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL [ALL_TAC; MESON_TAC[DOT_LZERO]] THEN
+  SIMP_TAC[dot; CART_EQ; vec; LAMBDA_BETA] THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[GSYM(REWRITE_CONV[REAL_ENTIRE] `x * x = &0`)] THEN
+  MATCH_MP_TAC SUM_POS_EQ_0_NUMSEG THEN ASM_REWRITE_TAC[REAL_LE_SQUARE]);;
+
+let DOT_POS_LT = prove
+ (`!x. (&0 < x dot x) <=> ~(x = vec 0)`,
+  REWRITE_TAC[REAL_LT_LE; DOT_POS_LE] THEN MESON_TAC[DOT_EQ_0]);;
+
+let FORALL_DOT_EQ_0 = prove
+ (`(!y. (!x. x dot y = &0) <=> y = vec 0) /\
+   (!x. (!y. x dot y = &0) <=> x = vec 0)`,
+  MESON_TAC[DOT_LZERO; DOT_RZERO; DOT_EQ_0]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Introduce norms, but defer many properties till we get square roots.      *)
+(* ------------------------------------------------------------------------- *)
+
+make_overloadable "norm" `:A->real`;;
+overload_interface("norm",`vector_norm:real^N->real`);;
+
+let vector_norm = new_definition
+  `norm x = sqrt(x dot x)`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Useful for the special cases of 1 dimension.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let FORALL_DIMINDEX_1 = prove
+ (`(!i. 1 <= i /\ i <= dimindex(:1) ==> P i) <=> P 1`,
+  MESON_TAC[DIMINDEX_1; LE_ANTISYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The collapse of the general concepts to the real line R^1.                *)
+(* ------------------------------------------------------------------------- *)
+
+let VECTOR_ONE = prove
+ (`!x:real^1. x = lambda i. x$1`,
+  SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN MESON_TAC[DIMINDEX_1; LE_ANTISYM]);;
+
+let FORALL_REAL_ONE = prove
+ (`(!x:real^1. P x) <=> (!x. P(lambda i. x))`,
+  EQ_TAC THEN SIMP_TAC[] THEN DISCH_TAC THEN GEN_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(x:real^1)$1`) THEN
+  REWRITE_TAC[GSYM VECTOR_ONE]);;
+
+let NORM_REAL = prove
+ (`!x:real^1. norm(x) = abs(x$1)`,
+  REWRITE_TAC[vector_norm; dot; DIMINDEX_1; SUM_SING_NUMSEG;
+              GSYM REAL_POW_2; POW_2_SQRT_ABS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Metric function.                                                          *)
+(* ------------------------------------------------------------------------- *)
+
+override_interface("dist",`distance:real^N#real^N->real`);;
+
+let dist = new_definition
+  `dist(x,y) = norm(x - y)`;;
+
+let DIST_REAL = prove
+ (`!x:real^1 y. dist(x,y) = abs(x$1 - y$1)`,
+  SIMP_TAC[dist; NORM_REAL; vector_sub; LAMBDA_BETA; LE_REFL; DIMINDEX_1]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A connectedness or intermediate value lemma with several applications.    *)
+(* ------------------------------------------------------------------------- *)
+
+let CONNECTED_REAL_LEMMA = prove
+ (`!f:real->real^N a b e1 e2.
+        a <= b /\ f(a) IN e1 /\ f(b) IN e2 /\
+        (!e x. a <= x /\ x <= b /\ &0 < e
+               ==> ?d. &0 < d /\
+                       !y. abs(y - x) < d ==> dist(f(y),f(x)) < e) /\
+        (!y. y IN e1 ==> ?e. &0 < e /\ !y'. dist(y',y) < e ==> y' IN e1) /\
+        (!y. y IN e2 ==> ?e. &0 < e /\ !y'. dist(y',y) < e ==> y' IN e2) /\
+        ~(?x. a <= x /\ x <= b /\ f(x) IN e1 /\ f(x) IN e2)
+        ==> ?x. a <= x /\ x <= b /\ ~(f(x) IN e1) /\ ~(f(x) IN e2)`,
+  let tac = ASM_MESON_TAC[REAL_LT_IMP_LE; REAL_LE_TOTAL; REAL_LE_ANTISYM] in
+  REWRITE_TAC[EXTENSION; NOT_IN_EMPTY] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(SPEC `\c. !x. a <= x /\ x <= c ==> (f(x):real^N) IN e1`
+              REAL_COMPLETE) THEN
+  REWRITE_TAC[] THEN ANTS_TAC THENL [tac; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x:real` THEN STRIP_TAC THEN
+  SUBGOAL_THEN `a <= x /\ x <= b` STRIP_ASSUME_TAC THENL [tac; ALL_TAC] THEN
+  ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `!z. a <= z /\ z < x ==> (f(z):real^N) IN e1` ASSUME_TAC THENL
+   [ASM_MESON_TAC[REAL_NOT_LT; REAL_LT_IMP_LE]; ALL_TAC] THEN
+  REPEAT STRIP_TAC THENL
+   [SUBGOAL_THEN
+     `?d. &0 < d /\ !y. abs(y - x) < d ==> (f(y):real^N) IN e1`
+    STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    ASM_MESON_TAC[REAL_ARITH `z <= x + e /\ e < d ==> z < x \/ abs(z - x) < d`;
+                  REAL_ARITH `&0 < e ==> ~(x + e <= x)`; REAL_DOWN];
+    SUBGOAL_THEN
+     `?d. &0 < d /\ !y. abs(y - x) < d ==> (f(y):real^N) IN e2`
+    STRIP_ASSUME_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+    MP_TAC(SPECL [`x - a`; `d:real`] REAL_DOWN2) THEN ANTS_TAC THENL
+     [ASM_MESON_TAC[REAL_LT_LE; REAL_SUB_LT]; ALL_TAC] THEN
+    ASM_MESON_TAC[REAL_ARITH `e < x - a ==> a <= x - e`;
+                  REAL_ARITH `&0 < e /\ x <= b ==> x - e <= b`;
+      REAL_ARITH `&0 < e /\ e < d ==> x - e < x /\ abs((x - e) - x) < d`]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* One immediately useful corollary is the existence of square roots!        *)
+(* ------------------------------------------------------------------------- *)
+
+let SQUARE_BOUND_LEMMA = prove
+ (`!x. x < (&1 + x) * (&1 + x)`,
+  GEN_TAC THEN REWRITE_TAC[REAL_POW_2] THEN
+  MAP_EVERY (fun t -> MP_TAC(SPEC t REAL_LE_SQUARE)) [`x:real`; `&1 + x`] THEN
+  REAL_ARITH_TAC);;
+
+let SQUARE_CONTINUOUS = prove
+ (`!x e. &0 < e
+         ==> ?d. &0 < d /\ !y. abs(y - x) < d ==> abs(y * y - x * x) < e`,
+  REPEAT STRIP_TAC THEN ASM_CASES_TAC `x = &0` THENL
+   [ASM_REWRITE_TAC[REAL_MUL_LZERO; REAL_SUB_RZERO] THEN
+    EXISTS_TAC `inv(&1 + inv(e))` THEN
+    ASM_SIMP_TAC[REAL_LT_INV_EQ; REAL_LT_ADD; REAL_LT_01] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC  REAL_LTE_TRANS THEN
+    EXISTS_TAC `inv(&1 + inv(e)) * inv(&1 + inv(e))` THEN
+    ASM_SIMP_TAC[REAL_ABS_MUL; REAL_LT_MUL2; REAL_ABS_POS] THEN
+    REWRITE_TAC[GSYM REAL_INV_MUL] THEN
+    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_INV_INV] THEN
+    MATCH_MP_TAC REAL_LE_INV2 THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_LE; SQUARE_BOUND_LEMMA; REAL_LT_INV_EQ];
+    MP_TAC(SPECL [`abs(x)`; `e / (&3 * abs(x))`] REAL_DOWN2)THEN
+    ASM_SIMP_TAC[GSYM REAL_ABS_NZ; REAL_LT_DIV; REAL_LT_MUL; REAL_OF_NUM_LT;
+                 ARITH; REAL_LT_RDIV_EQ] THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real` THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `y:real` THEN
+    REWRITE_TAC[REAL_ARITH `x * x - y * y = (x - y) * (x + y)`] THEN
+    DISCH_TAC THEN MATCH_MP_TAC REAL_LET_TRANS THEN
+    EXISTS_TAC `d * &3 * abs(x)` THEN ASM_REWRITE_TAC[REAL_ABS_MUL] THEN
+    MATCH_MP_TAC REAL_LE_MUL2 THEN
+    ASM_SIMP_TAC[REAL_ABS_POS; REAL_LT_IMP_LE] THEN
+    MAP_EVERY UNDISCH_TAC [`abs (y - x) < d`; `d < abs(x)`] THEN
+    REAL_ARITH_TAC]);;
+
+let SQRT_WORKS = prove
+ (`!x. &0 <= x ==> &0 <= sqrt(x) /\ (sqrt(x) pow 2 = x)`,
+  GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [REAL_LE_LT] THEN STRIP_TAC THENL
+   [ALL_TAC;
+    ASM_MESON_TAC[SQRT_0; REAL_POW_2; REAL_LE_REFL; REAL_MUL_LZERO]] THEN
+  REWRITE_TAC[sqrt] THEN CONV_TAC SELECT_CONV THEN
+  MP_TAC(ISPECL [`(\u. lambda i. u):real->real^1`; `&0`; `&1 + x`;
+            `{u:real^1 | u$1 * u$1 < x}`; `{u:real^1 | u$1 * u$1 > x}`]
+         CONNECTED_REAL_LEMMA) THEN
+  SIMP_TAC[LAMBDA_BETA; LE_REFL; DIMINDEX_1; DIST_REAL;
+           EXTENSION; IN_INTER; IN_ELIM_THM; NOT_IN_EMPTY;
+           REAL_MUL_LZERO; FORALL_REAL_ONE; real_gt] THEN
+  ANTS_TAC THENL [ALL_TAC; ASM_MESON_TAC[REAL_POW_2; REAL_LT_TOTAL]] THEN
+  ASM_SIMP_TAC[REAL_LT_ANTISYM; REAL_ARITH `&0 < x ==> &0 <= &1 + x`] THEN
+  REWRITE_TAC[SQUARE_BOUND_LEMMA] THEN
+  MESON_TAC[SQUARE_CONTINUOUS; REAL_SUB_LT;
+            REAL_ARITH `abs(z2 - x2) < y - x2 ==> z2 < y`;
+            REAL_ARITH `abs(z2 - x2) < x2 - y ==> y < z2`]);;
+
+let SQRT_POS_LE = prove
+ (`!x. &0 <= x ==> &0 <= sqrt(x)`,
+  MESON_TAC[SQRT_WORKS]);;
+
+let SQRT_POW_2 = prove
+ (`!x. &0 <= x ==> (sqrt(x) pow 2 = x)`,
+  MESON_TAC[SQRT_WORKS]);;
+
+let SQRT_MUL = prove
+ (`!x y. &0 <= x /\ &0 <= y
+           ==> (sqrt(x * y) = sqrt x * sqrt y)`,
+  ASM_MESON_TAC[REAL_POW_2; SQRT_WORKS; REAL_LE_MUL; SQRT_UNIQUE;
+                REAL_ARITH `(x * y) * (x * y) = (x * x) * y * y`]);;
+
+let SQRT_INV = prove
+ (`!x. &0 <= x ==> (sqrt (inv x) = inv(sqrt x))`,
+  MESON_TAC[SQRT_UNIQUE; SQRT_WORKS; REAL_POW_INV; REAL_LE_INV_EQ]);;
+
+let SQRT_DIV = prove
+ (`!x y. &0 <= x /\ &0 <= y ==> (sqrt (x / y) = sqrt x / sqrt y)`,
+  SIMP_TAC[real_div; SQRT_MUL; SQRT_INV; REAL_LE_INV_EQ]);;
+
+let SQRT_POW2 = prove
+ (`!x. (sqrt(x) pow 2 = x) <=> &0 <= x`,
+  MESON_TAC[REAL_POW_2; REAL_LE_SQUARE; SQRT_POW_2]);;
+
+let SQRT_MONO_LT = prove
+ (`!x y. &0 <= x /\ x < y ==> sqrt(x) < sqrt(y)`,
+  REWRITE_TAC[GSYM REAL_NOT_LE] THEN
+  MESON_TAC[REAL_LT_IMP_LE; REAL_NOT_LE; REAL_LE_TRANS;
+            REAL_POW_LE2; SQRT_WORKS]);;
+
+let SQRT_MONO_LE = prove
+ (`!x y. &0 <= x /\ x <= y ==> sqrt(x) <= sqrt(y)`,
+  MESON_TAC[REAL_LE_LT; SQRT_MONO_LT]);;
+
+let SQRT_MONO_LT_EQ = prove
+ (`!x y. &0 <= x /\ &0 <= y ==> (sqrt(x) < sqrt(y) <=> x < y)`,
+  MESON_TAC[REAL_NOT_LT; SQRT_MONO_LT; SQRT_MONO_LE]);;
+
+let SQRT_MONO_LE_EQ = prove
+ (`!x y. &0 <= x /\ &0 <= y ==> (sqrt(x) <= sqrt(y) <=> x <= y)`,
+  MESON_TAC[REAL_NOT_LT; SQRT_MONO_LT; SQRT_MONO_LE]);;
+
+let SQRT_INJ = prove
+ (`!x y. &0 <= x /\ &0 <= y ==> ((sqrt(x) = sqrt(y)) <=> (x = y))`,
+  SIMP_TAC[GSYM REAL_LE_ANTISYM; SQRT_MONO_LE_EQ]);;
+
+let SQRT_LT_0 = prove
+ (`!x. &0 <= x ==> (&0 < sqrt x <=> &0 < x)`,
+  MESON_TAC[SQRT_0; REAL_LE_REFL; SQRT_MONO_LT_EQ]);;
+
+let SQRT_EQ_0 = prove
+ (`!x. &0 <= x ==> ((sqrt x = &0) <=> (x = &0))`,
+  MESON_TAC[SQRT_INJ; SQRT_0; REAL_LE_REFL]);;
+
+let SQRT_POS_LT = prove
+ (`!x. &0 < x ==> &0 < sqrt(x)`,
+  MESON_TAC[REAL_LT_LE; SQRT_POS_LE; SQRT_EQ_0]);;
+
+let REAL_LE_LSQRT = prove
+ (`!x y. &0 <= x /\ &0 <= y /\ x <= y pow 2 ==> sqrt(x) <= y`,
+  MESON_TAC[SQRT_MONO_LE; REAL_POW_LE; POW_2_SQRT]);;
+
+let REAL_LE_RSQRT = prove
+ (`!x y. x pow 2 <= y ==> x <= sqrt(y)`,
+  MESON_TAC[REAL_LE_TOTAL; SQRT_MONO_LE; SQRT_POS_LE; REAL_POW_2;
+            REAL_LE_SQUARE; REAL_LE_TRANS; POW_2_SQRT]);;
+
+let REAL_LT_LSQRT = prove
+ (`!x y. &0 <= x /\ &0 <= y /\ x < y pow 2 ==> sqrt x < y`,
+  MESON_TAC[SQRT_MONO_LT; REAL_POW_LE; POW_2_SQRT]);;
+
+let REAL_LT_RSQRT = prove
+ (`!x y. x pow 2 < y ==> x < sqrt(y)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC(REAL_ARITH `abs x < a ==> x < a`) THEN
+  REWRITE_TAC[GSYM POW_2_SQRT_ABS] THEN MATCH_MP_TAC SQRT_MONO_LT THEN
+  ASM_REWRITE_TAC[REAL_POW_2; REAL_LE_SQUARE]);;
+
+let SQRT_EVEN_POW2 = prove
+ (`!n. EVEN n ==> (sqrt(&2 pow n) = &2 pow (n DIV 2))`,
+  SIMP_TAC[EVEN_EXISTS; LEFT_IMP_EXISTS_THM; DIV_MULT; ARITH_EQ] THEN
+  MESON_TAC[SQRT_UNIQUE; REAL_POW_POW; MULT_SYM; REAL_POW_LE; REAL_POS]);;
+
+let REAL_DIV_SQRT = prove
+ (`!x. &0 <= x ==> (x / sqrt(x) = sqrt(x))`,
+  REWRITE_TAC[REAL_LE_LT] THEN REPEAT STRIP_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[SQRT_0; real_div; REAL_MUL_LZERO]] THEN
+  ASM_SIMP_TAC[REAL_EQ_LDIV_EQ; SQRT_POS_LT; GSYM REAL_POW_2] THEN
+  ASM_SIMP_TAC[SQRT_POW_2; REAL_LT_IMP_LE]);;
+
+let REAL_RSQRT_LE = prove
+ (`!x y. &0 <= x /\ &0 <= y /\ x <= sqrt y ==> x pow 2 <= y`,
+  MESON_TAC[REAL_POW_LE2; SQRT_POW_2]);;
+
+let REAL_LSQRT_LE = prove
+ (`!x y. &0 <= x /\ sqrt x <= y ==> x <= y pow 2`,
+  MESON_TAC[REAL_POW_LE2; SQRT_POS_LE; REAL_LE_TRANS; SQRT_POW_2]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence derive more interesting properties of the norm.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let NORM_0 = prove
+ (`norm(vec 0) = &0`,
+  REWRITE_TAC[vector_norm; DOT_LZERO; SQRT_0]);;
+
+let NORM_POS_LE = prove
+ (`!x. &0 <= norm x`,
+  GEN_TAC THEN SIMP_TAC[DOT_POS_LE; vector_norm; SQRT_POS_LE]);;
+
+let NORM_NEG = prove
+ (`!x. norm(--x) = norm x`,
+  REWRITE_TAC[vector_norm; DOT_LNEG; DOT_RNEG; REAL_NEG_NEG]);;
+
+let NORM_SUB = prove
+ (`!x y. norm(x - y) = norm(y - x)`,
+  MESON_TAC[NORM_NEG; VECTOR_NEG_SUB]);;
+
+let NORM_MUL = prove
+ (`!a x. norm(a % x) = abs(a) * norm x`,
+  REWRITE_TAC[vector_norm; DOT_LMUL; DOT_RMUL; REAL_MUL_ASSOC] THEN
+  SIMP_TAC[SQRT_MUL; SQRT_POS_LE; DOT_POS_LE; REAL_LE_SQUARE] THEN
+  REWRITE_TAC[GSYM REAL_POW_2; POW_2_SQRT_ABS]);;
+
+let NORM_EQ_0_DOT = prove
+ (`!x. (norm x = &0) <=> (x dot x = &0)`,
+  SIMP_TAC[vector_norm; SQRT_EQ_0; DOT_POS_LE]);;
+
+let NORM_EQ_0 = prove
+ (`!x. (norm x = &0) <=> (x = vec 0)`,
+  SIMP_TAC[vector_norm; DOT_EQ_0; SQRT_EQ_0; DOT_POS_LE]);;
+
+let NORM_POS_LT = prove
+ (`!x. &0 < norm x <=> ~(x = vec 0)`,
+  MESON_TAC[REAL_LT_LE; NORM_POS_LE; NORM_EQ_0]);;
+
+let NORM_POW_2 = prove
+ (`!x. norm(x) pow 2 = x dot x`,
+  SIMP_TAC[vector_norm; SQRT_POW_2; DOT_POS_LE]);;
+
+let NORM_EQ_0_IMP = prove
+ (`!x. (norm x = &0) ==> (x = vec 0)`,
+  MESON_TAC[NORM_EQ_0]);;
+
+let NORM_LE_0 = prove
+ (`!x. norm x <= &0 <=> (x = vec 0)`,
+  MESON_TAC[REAL_LE_ANTISYM; NORM_EQ_0; NORM_POS_LE]);;
+
+let VECTOR_MUL_EQ_0 = prove
+ (`!a x. (a % x = vec 0) <=> (a = &0) \/ (x = vec 0)`,
+  REWRITE_TAC[GSYM NORM_EQ_0; NORM_MUL; REAL_ABS_ZERO; REAL_ENTIRE]);;
+
+let VECTOR_MUL_LCANCEL = prove
+ (`!a x y. (a % x = a % y) <=> (a = &0) \/ (x = y)`,
+  MESON_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_LDISTRIB; VECTOR_SUB_EQ]);;
+
+let VECTOR_MUL_RCANCEL = prove
+ (`!a b x. (a % x = b % x) <=> (a = b) \/ (x = vec 0)`,
+  MESON_TAC[VECTOR_MUL_EQ_0; VECTOR_SUB_RDISTRIB; REAL_SUB_0; VECTOR_SUB_EQ]);;
+
+let VECTOR_MUL_LCANCEL_IMP = prove
+ (`!a x y. ~(a = &0) /\ (a % x = a % y) ==> (x = y)`,
+  MESON_TAC[VECTOR_MUL_LCANCEL]);;
+
+let VECTOR_MUL_RCANCEL_IMP = prove
+ (`!a b x. ~(x = vec 0) /\ (a % x = b % x) ==> (a = b)`,
+  MESON_TAC[VECTOR_MUL_RCANCEL]);;
+
+let NORM_CAUCHY_SCHWARZ = prove
+ (`!(x:real^N) y. x dot y <= norm(x) * norm(y)`,
+  REPEAT STRIP_TAC THEN MAP_EVERY ASM_CASES_TAC
+   [`norm(x:real^N) = &0`; `norm(y:real^N) = &0`] THEN
+  ASM_SIMP_TAC[NORM_EQ_0_IMP; DOT_LZERO; DOT_RZERO;
+               REAL_MUL_LZERO; REAL_MUL_RZERO] THEN
+  MP_TAC(ISPEC `norm(y:real^N) % x - norm(x:real^N) % y` DOT_POS_LE) THEN
+  REWRITE_TAC[DOT_RSUB; DOT_LSUB; DOT_LMUL; DOT_RMUL; GSYM NORM_POW_2;
+              REAL_POW_2; REAL_LE_REFL] THEN
+  REWRITE_TAC[DOT_SYM; REAL_ARITH
+   `&0 <= y * (y * x * x - x * d) - x * (y * d - x * y * y) <=>
+    x * y * d <= x * y * x * y`] THEN
+  ASM_SIMP_TAC[REAL_LE_LMUL_EQ; REAL_LT_LE; NORM_POS_LE]);;
+
+let NORM_CAUCHY_SCHWARZ_ABS = prove
+ (`!x:real^N y. abs(x dot y) <= norm(x) * norm(y)`,
+  REPEAT GEN_TAC THEN MP_TAC(ISPEC `x:real^N` NORM_CAUCHY_SCHWARZ) THEN
+  DISCH_THEN(fun th -> MP_TAC(SPEC `y:real^N` th) THEN
+        MP_TAC(SPEC `--(y:real^N)` th)) THEN
+  REWRITE_TAC[DOT_RNEG; NORM_NEG] THEN REAL_ARITH_TAC);;
+
+let REAL_ABS_NORM = prove
+ (`!x. abs(norm x) = norm x`,
+  REWRITE_TAC[NORM_POS_LE; REAL_ABS_REFL]);;
+
+let NORM_CAUCHY_SCHWARZ_DIV = prove
+ (`!x:real^N y. abs((x dot y) / (norm x * norm y)) <= &1`,
+  REPEAT GEN_TAC THEN
+  MAP_EVERY ASM_CASES_TAC [`x:real^N = vec 0`; `y:real^N = vec 0`] THEN
+  ASM_REWRITE_TAC[NORM_0; REAL_MUL_LZERO; REAL_MUL_RZERO; real_div;
+             REAL_INV_1; DOT_LZERO; DOT_RZERO; REAL_ABS_NUM; REAL_POS] THEN
+  ASM_SIMP_TAC[GSYM real_div; REAL_ABS_DIV; REAL_LE_LDIV_EQ; REAL_LT_MUL;
+     REAL_ABS_INV; NORM_POS_LT; REAL_ABS_MUL; REAL_ABS_NORM] THEN
+  REWRITE_TAC[REAL_MUL_LID; NORM_CAUCHY_SCHWARZ_ABS]);;
+
+let NORM_TRIANGLE = prove
+ (`!x y. norm(x + y) <= norm(x) + norm(y)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[vector_norm] THEN
+  MATCH_MP_TAC REAL_LE_LSQRT THEN
+  SIMP_TAC[GSYM vector_norm; DOT_POS_LE; NORM_POS_LE; REAL_LE_ADD] THEN
+  REWRITE_TAC[DOT_LADD; DOT_RADD; REAL_POW_2; GSYM NORM_POW_2] THEN
+  SIMP_TAC[NORM_CAUCHY_SCHWARZ; DOT_SYM; REAL_ARITH
+   `d <= x * y ==> (x * x + d) + (d + y * y) <= (x + y) * (x + y)`]);;
+
+let NORM_TRIANGLE_SUB = prove
+ (`!x y:real^N. norm(x) <= norm(y) + norm(x - y)`,
+  MESON_TAC[NORM_TRIANGLE; VECTOR_SUB_ADD2]);;
+
+let NORM_TRIANGLE_LE = prove
+ (`!x y. norm(x) + norm(y) <= e ==> norm(x + y) <= e`,
+  MESON_TAC[REAL_LE_TRANS; NORM_TRIANGLE]);;
+
+let NORM_TRIANGLE_LT = prove
+ (`!x y. norm(x) + norm(y) < e ==> norm(x + y) < e`,
+  MESON_TAC[REAL_LET_TRANS; NORM_TRIANGLE]);;
+
+let COMPONENT_LE_NORM = prove
+ (`!x:real^N i. 1 <= i /\  i <= dimindex(:N)
+                 ==> abs(x$i) <= norm x`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[vector_norm] THEN
+  MATCH_MP_TAC REAL_LE_RSQRT THEN REWRITE_TAC[GSYM REAL_ABS_POW] THEN
+  REWRITE_TAC[real_abs; REAL_POW_2; REAL_LE_SQUARE] THEN
+  SUBGOAL_THEN
+   `x$i * (x:real^N)$i =
+     sum(1..dimindex(:N)) (\k. if k = i then x$i * x$i else &0)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[SUM_DELTA] THEN ASM_REWRITE_TAC[IN_NUMSEG]; ALL_TAC] THEN
+  REWRITE_TAC[dot] THEN MATCH_MP_TAC SUM_LE THEN
+  REWRITE_TAC[FINITE_NUMSEG] THEN
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[REAL_LE_REFL; REAL_LE_SQUARE]);;
+
+let NORM_BOUND_COMPONENT_LE = prove
+ (`!x:real^N e. norm(x) <= e
+                ==> !i. 1 <= i /\ i <= dimindex(:N) ==> abs(x$i) <= e`,
+  MESON_TAC[COMPONENT_LE_NORM; REAL_LE_TRANS]);;
+
+let NORM_BOUND_COMPONENT_LT = prove
+ (`!x:real^N e. norm(x) < e
+                ==> !i. 1 <= i /\ i <= dimindex(:N) ==> abs(x$i) < e`,
+  MESON_TAC[COMPONENT_LE_NORM; REAL_LET_TRANS]);;
+
+let NORM_LE_L1 = prove
+ (`!x:real^N. norm x <= sum(1..dimindex(:N)) (\i. abs(x$i))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[vector_norm; dot] THEN
+  MATCH_MP_TAC REAL_LE_LSQRT THEN REWRITE_TAC[REAL_POW_2] THEN
+  SIMP_TAC[SUM_POS_LE; FINITE_NUMSEG; REAL_LE_SQUARE; REAL_ABS_POS] THEN
+  SPEC_TAC(`dimindex(:N)`,`n:num`) THEN INDUCT_TAC THEN
+  REWRITE_TAC[SUM_CLAUSES_NUMSEG; ARITH_EQ; ARITH_RULE `1 <= SUC n`] THEN
+  SIMP_TAC[REAL_MUL_LZERO; REAL_LE_REFL] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `a2 <= a * a /\ &0 <= a * b /\ b2 <= b * b
+    ==> a2 + b2 <= (a + b) * (a + b)`) THEN
+  ASM_SIMP_TAC[SUM_POS_LE; REAL_LE_MUL; REAL_ABS_POS; FINITE_NUMSEG] THEN
+  REWRITE_TAC[GSYM REAL_ABS_MUL] THEN REAL_ARITH_TAC);;
+
+let REAL_ABS_SUB_NORM = prove
+ (`abs(norm(x) - norm(y)) <= norm(x - y)`,
+  REWRITE_TAC[REAL_ARITH `abs(x - y) <= a <=> x <= y + a /\ y <= x + a`] THEN
+  MESON_TAC[NORM_TRIANGLE_SUB; NORM_SUB]);;
+
+let NORM_LE = prove
+ (`!x y. norm(x) <= norm(y) <=> x dot x <= y dot y`,
+  REWRITE_TAC[vector_norm] THEN MESON_TAC[SQRT_MONO_LE_EQ; DOT_POS_LE]);;
+
+let NORM_LT = prove
+ (`!x y. norm(x) < norm(y) <=> x dot x < y dot y`,
+  REWRITE_TAC[vector_norm] THEN MESON_TAC[SQRT_MONO_LT_EQ; DOT_POS_LE]);;
+
+let NORM_EQ = prove
+ (`!x y. (norm x = norm y) <=> (x dot x = y dot y)`,
+  REWRITE_TAC[GSYM REAL_LE_ANTISYM; NORM_LE]);;
+
+let NORM_EQ_1 = prove
+ (`!x. norm(x) = &1 <=> x dot x = &1`,
+  GEN_TAC THEN GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM SQRT_1] THEN
+  SIMP_TAC[vector_norm; SQRT_INJ; DOT_POS_LE; REAL_POS]);;
+
+let NORM_LE_COMPONENTWISE = prove
+ (`!x:real^N y:real^N.
+        (!i. 1 <= i /\ i <= dimindex(:N) ==> abs(x$i) <= abs(y$i))
+        ==> norm(x) <= norm(y)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[NORM_LE; dot] THEN
+  MATCH_MP_TAC SUM_LE_NUMSEG THEN
+  ASM_SIMP_TAC[GSYM REAL_POW_2; GSYM REAL_LE_SQUARE_ABS]);;
+
+let L1_LE_NORM = prove
+ (`!x:real^N.
+    sum(1..dimindex(:N)) (\i. abs(x$i)) <= sqrt(&(dimindex(:N))) * norm x`,
+  let lemma = prove
+   (`!x n. &n * sum(1..n) (\i. x i pow 2) - (sum(1..n) x) pow 2 =
+           sum(1..n) (\i. sum(i+1..n) (\j. (x i - x j) pow 2))`,
+    GEN_TAC THEN CONV_TAC(BINDER_CONV SYM_CONV) THEN INDUCT_TAC THEN
+    REWRITE_TAC[SUM_CLAUSES_NUMSEG; ARITH; ARITH_RULE `1 <= SUC n`] THEN
+    CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    SIMP_TAC[ARITH_RULE `i <= n ==> i + 1 <= SUC n`; SUM_TRIV_NUMSEG;
+             ARITH_RULE `~(n + 1 <= n)`; ARITH_RULE `n < SUC n + 1`] THEN
+    ASM_REWRITE_TAC[SUM_ADD_NUMSEG; REAL_ADD_RID] THEN
+    REWRITE_TAC[REAL_ARITH
+     `(x - y) pow 2 = (x pow 2 + y pow 2) - &2 * x * y`] THEN
+    REWRITE_TAC[SUM_ADD_NUMSEG; SUM_SUB_NUMSEG; SUM_LMUL; SUM_RMUL;
+                GSYM REAL_OF_NUM_SUC; SUM_CONST_NUMSEG; ADD_SUB] THEN
+    REAL_ARITH_TAC) in
+  GEN_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH `&0 <= y /\ abs x <= abs y ==> x <= y`) THEN
+  SIMP_TAC[REAL_LE_MUL; NORM_POS_LE; SQRT_POS_LE; REAL_POS] THEN
+  REWRITE_TAC[REAL_LE_SQUARE_ABS; REAL_POW_MUL] THEN
+  SIMP_TAC[SQRT_POW_2; REAL_POS; NORM_POW_2; dot] THEN
+  REWRITE_TAC[GSYM REAL_POW_2] THEN
+  GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [GSYM REAL_POW2_ABS] THEN
+  ONCE_REWRITE_TAC[GSYM REAL_SUB_LE] THEN REWRITE_TAC[lemma] THEN
+  SIMP_TAC[SUM_POS_LE_NUMSEG; REAL_LE_POW_2]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Squaring equations and inequalities involving norms.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let DOT_SQUARE_NORM = prove
+ (`!x. x dot x = norm(x) pow 2`,
+  SIMP_TAC[vector_norm; SQRT_POW_2; DOT_POS_LE]);;
+
+let NORM_EQ_SQUARE = prove
+ (`!x:real^N. norm(x) = a <=> &0 <= a /\ x dot x = a pow 2`,
+  REWRITE_TAC[DOT_SQUARE_NORM] THEN
+  ONCE_REWRITE_TAC[REAL_RING `x pow 2 = a pow 2 <=> x = a \/ x + a = &0`] THEN
+  GEN_TAC THEN MP_TAC(ISPEC `x:real^N` NORM_POS_LE) THEN REAL_ARITH_TAC);;
+
+let NORM_LE_SQUARE = prove
+ (`!x:real^N. norm(x) <= a <=> &0 <= a /\ x dot x <= a pow 2`,
+  REWRITE_TAC[DOT_SQUARE_NORM; GSYM REAL_LE_SQUARE_ABS] THEN
+  GEN_TAC THEN MP_TAC(ISPEC `x:real^N` NORM_POS_LE) THEN REAL_ARITH_TAC);;
+
+let NORM_GE_SQUARE = prove
+ (`!x:real^N. norm(x) >= a <=> a <= &0 \/ x dot x >= a pow 2`,
+  REWRITE_TAC[real_ge; DOT_SQUARE_NORM; GSYM REAL_LE_SQUARE_ABS] THEN
+  GEN_TAC THEN MP_TAC(ISPEC `x:real^N` NORM_POS_LE) THEN REAL_ARITH_TAC);;
+
+let NORM_LT_SQUARE = prove
+ (`!x:real^N. norm(x) < a <=> &0 < a /\ x dot x < a pow 2`,
+  REWRITE_TAC[REAL_ARITH `x < a <=> ~(x >= a)`; NORM_GE_SQUARE] THEN
+  REAL_ARITH_TAC);;
+
+let NORM_GT_SQUARE = prove
+ (`!x:real^N. norm(x) > a <=> a < &0 \/ x dot x > a pow 2`,
+  REWRITE_TAC[REAL_ARITH `x > a <=> ~(x <= a)`; NORM_LE_SQUARE] THEN
+  REAL_ARITH_TAC);;
+
+let NORM_LT_SQUARE_ALT = prove
+ (`!x:real^N. norm(x) < a <=> &0 <= a /\ x dot x < a pow 2`,
+  REWRITE_TAC[REAL_ARITH `x < a <=> ~(x >= a)`; NORM_GE_SQUARE] THEN
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a = &0` THENL
+   [ASM_REWRITE_TAC[real_ge] THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
+    REWRITE_TAC[DOT_POS_LE];
+    ASM_REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* General linear decision procedure for normed spaces.                      *)
+(* ------------------------------------------------------------------------- *)
+
+let NORM_ARITH =
+  let find_normedterms =
+    let augment_norm b tm acc =
+      match tm with
+        Comb(Const("vector_norm",_),v) -> insert (b,v) acc
+      | _ -> acc in
+    let rec find_normedterms tm acc =
+      match tm with
+        Comb(Comb(Const("real_add",_),l),r) ->
+            find_normedterms l (find_normedterms r acc)
+      | Comb(Comb(Const("real_mul",_),c),n) ->
+            if not (is_ratconst c) then acc else
+            augment_norm (rat_of_term c >=/ Int 0) n acc
+      | _ -> augment_norm true tm acc in
+    find_normedterms in
+  let lincomb_neg t = mapf minus_num t in
+  let lincomb_cmul c t = if c =/ Int 0 then undefined else mapf (( */ ) c) t in
+  let lincomb_add l r = combine (+/) (fun x -> x =/ Int 0) l r in
+  let lincomb_sub l r = lincomb_add l (lincomb_neg r) in
+  let lincomb_eq l r = lincomb_sub l r = undefined in
+  let rec vector_lincomb tm =
+    match tm with
+        Comb(Comb(Const("vector_add",_),l),r) ->
+          lincomb_add (vector_lincomb l) (vector_lincomb r)
+      | Comb(Comb(Const("vector_sub",_),l),r) ->
+          lincomb_sub (vector_lincomb l) (vector_lincomb r)
+      | Comb(Comb(Const("%",_),l),r) ->
+          lincomb_cmul (rat_of_term l) (vector_lincomb r)
+      | Comb(Const("vector_neg",_),t) ->
+          lincomb_neg (vector_lincomb t)
+      | Comb(Const("vec",_),n) when is_numeral n & dest_numeral n =/ Int 0 ->
+          undefined
+      | _ -> (tm |=> Int 1) in
+  let vector_lincombs tms =
+    itlist (fun t fns ->
+                  if can (assoc t) fns then fns else
+                  let f = vector_lincomb t in
+                  try let _,f' = find (fun (_,f') -> lincomb_eq f f') fns in
+                      (t,f')::fns
+                  with Failure _ -> (t,f)::fns) tms [] in
+  let rec replacenegnorms fn tm =
+    match tm with
+      Comb(Comb(Const("real_add",_),l),r) ->
+          BINOP_CONV (replacenegnorms fn) tm
+    | Comb(Comb(Const("real_mul",_),c),n) when rat_of_term c </ Int 0 ->
+          RAND_CONV fn tm
+    | _ -> REFL tm in
+  let flip v eq =
+    if defined eq v then (v |-> minus_num(apply eq v)) eq else eq in
+  let rec allsubsets s =
+    match s with
+      [] -> [[]]
+    | (a::t) -> let res = allsubsets t in
+                map (fun b -> a::b) res @ res in
+  let evaluate env lin =
+    foldr (fun x c s -> s +/ c */ apply env x) lin (Int 0) in
+  let rec solve (vs,eqs) =
+    match (vs,eqs) with
+      [],[] -> (0 |=> Int 1)
+    | _,eq::oeqs ->
+          let v = hd(intersect vs (dom eq)) in
+          let c = apply eq v in
+          let vdef = lincomb_cmul (Int(-1) // c) eq in
+          let eliminate eqn =
+            if not(defined eqn v) then eqn else
+            lincomb_add (lincomb_cmul (apply eqn v) vdef) eqn in
+          let soln = solve (subtract vs [v],map eliminate oeqs) in
+          (v |-> evaluate soln (undefine v vdef)) soln in
+  let rec combinations k l =
+    if k = 0 then [[]] else
+    match l with
+      [] -> []
+    | h::t -> map (fun c -> h::c) (combinations (k - 1) t) @
+              combinations k t in
+  let vertices vs eqs =
+    let vertex cmb =
+      let soln = solve(vs,cmb) in
+      map (fun v -> tryapplyd soln v (Int 0)) vs in
+    let rawvs = mapfilter vertex (combinations (length vs) eqs) in
+    let unset = filter (forall (fun c -> c >=/ Int 0)) rawvs in
+    itlist (insert' (forall2 (=/))) unset [] in
+  let subsumes l m = forall2 (fun x y -> abs_num x <=/ abs_num y) l m in
+  let rec subsume todo dun =
+    match todo with
+      [] -> dun
+    | v::ovs -> let dun' = if exists (fun w -> subsumes w v) dun then dun
+                           else v::(filter (fun w -> not(subsumes v w)) dun) in
+                subsume ovs dun' in
+  let NORM_CMUL_RULE =
+    let MATCH_pth = (MATCH_MP o prove)
+     (`!b x. b >= norm(x) ==> !c. abs(c) * b >= norm(c % x)`,
+      SIMP_TAC[NORM_MUL; real_ge; REAL_LE_LMUL; REAL_ABS_POS]) in
+    fun c th -> ISPEC(term_of_rat c) (MATCH_pth th) in
+  let NORM_ADD_RULE =
+    let MATCH_pth = (MATCH_MP o prove)
+     (`!b1 b2 x1 x2. b1 >= norm(x1) /\ b2 >= norm(x2)
+                     ==> b1 + b2 >= norm(x1 + x2)`,
+      REWRITE_TAC[real_ge] THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC NORM_TRIANGLE_LE THEN ASM_SIMP_TAC[REAL_LE_ADD2]) in
+    fun th1 th2 -> MATCH_pth (CONJ th1 th2) in
+  let INEQUALITY_CANON_RULE =
+    CONV_RULE(LAND_CONV REAL_POLY_CONV) o
+    CONV_RULE(LAND_CONV REAL_RAT_REDUCE_CONV) o
+    GEN_REWRITE_RULE I [REAL_ARITH `s >= t <=> s - t >= &0`] in
+  let NORM_CANON_CONV =
+    let APPLY_pth1 = GEN_REWRITE_CONV I
+     [VECTOR_ARITH `x:real^N = &1 % x`]
+    and APPLY_pth2 = GEN_REWRITE_CONV I
+     [VECTOR_ARITH `x - y:real^N = x + --y`]
+    and APPLY_pth3 = GEN_REWRITE_CONV I
+     [VECTOR_ARITH `--x:real^N = -- &1 % x`]
+    and APPLY_pth4 = GEN_REWRITE_CONV I
+     [VECTOR_ARITH `&0 % x:real^N = vec 0`;
+      VECTOR_ARITH `c % vec 0:real^N = vec 0`]
+    and APPLY_pth5 = GEN_REWRITE_CONV I
+     [VECTOR_ARITH `c % (d % x) = (c * d) % x`]
+    and APPLY_pth6 = GEN_REWRITE_CONV I
+     [VECTOR_ARITH `c % (x + y) = c % x + c % y`]
+    and APPLY_pth7 = GEN_REWRITE_CONV I
+     [VECTOR_ARITH `vec 0 + x = x`;
+      VECTOR_ARITH `x + vec 0 = x`]
+    and APPLY_pth8 =
+     GEN_REWRITE_CONV I [VECTOR_ARITH `c % x + d % x = (c + d) % x`] THENC
+     LAND_CONV REAL_RAT_ADD_CONV THENC
+     GEN_REWRITE_CONV TRY_CONV [VECTOR_ARITH `&0 % x = vec 0`]
+    and APPLY_pth9 =
+     GEN_REWRITE_CONV I
+      [VECTOR_ARITH `(c % x + z) + d % x = (c + d) % x + z`;
+       VECTOR_ARITH `c % x + (d % x + z) = (c + d) % x + z`;
+       VECTOR_ARITH `(c % x + w) + (d % x + z) = (c + d) % x + (w + z)`] THENC
+     LAND_CONV(LAND_CONV REAL_RAT_ADD_CONV)
+    and APPLY_ptha =
+     GEN_REWRITE_CONV I [VECTOR_ARITH `&0 % x + y = y`]
+    and APPLY_pthb =
+     GEN_REWRITE_CONV I
+      [VECTOR_ARITH `c % x + d % y = c % x + d % y`;
+       VECTOR_ARITH `(c % x + z) + d % y = c % x + (z + d % y)`;
+       VECTOR_ARITH `c % x + (d % y + z) = c % x + (d % y + z)`;
+       VECTOR_ARITH `(c % x + w) + (d % y + z) = c % x + (w + (d % y + z))`]
+    and APPLY_pthc =
+     GEN_REWRITE_CONV I
+      [VECTOR_ARITH `c % x + d % y = d % y + c % x`;
+       VECTOR_ARITH `(c % x + z) + d % y = d % y + (c % x + z)`;
+       VECTOR_ARITH `c % x + (d % y + z) = d % y + (c % x + z)`;
+       VECTOR_ARITH `(c % x + w) + (d % y + z) = d % y + ((c % x + w) + z)`]
+    and APPLY_pthd =
+     GEN_REWRITE_CONV TRY_CONV
+      [VECTOR_ARITH `x + vec 0 = x`] in
+    let headvector tm =
+      match tm with
+        Comb(Comb(Const("vector_add",_),Comb(Comb(Const("%",_),l),v)),r) -> v
+      | Comb(Comb(Const("%",_),l),v) -> v
+      | _ -> failwith "headvector: non-canonical term" in
+    let rec VECTOR_CMUL_CONV tm =
+     ((APPLY_pth5 THENC LAND_CONV REAL_RAT_MUL_CONV) ORELSEC
+      (APPLY_pth6 THENC BINOP_CONV VECTOR_CMUL_CONV)) tm
+    and VECTOR_ADD_CONV tm =
+      try APPLY_pth7 tm with Failure _ ->
+      try APPLY_pth8 tm with Failure _ ->
+      match tm with
+        Comb(Comb(Const("vector_add",_),lt),rt) ->
+          let l = headvector lt and r = headvector rt in
+          if l < r then (APPLY_pthb THENC
+                         RAND_CONV VECTOR_ADD_CONV THENC
+                         APPLY_pthd) tm
+          else if r < l then (APPLY_pthc THENC
+                              RAND_CONV VECTOR_ADD_CONV THENC
+                              APPLY_pthd) tm else
+          (APPLY_pth9 THENC
+            ((APPLY_ptha THENC VECTOR_ADD_CONV) ORELSEC
+             RAND_CONV VECTOR_ADD_CONV THENC
+             APPLY_pthd)) tm
+      | _ -> REFL tm in
+    let rec VECTOR_CANON_CONV tm =
+      match tm with
+        Comb(Comb(Const("vector_add",_),l),r) ->
+          let lth = VECTOR_CANON_CONV l and rth = VECTOR_CANON_CONV r in
+          let th = MK_COMB(AP_TERM (rator(rator tm)) lth,rth) in
+          CONV_RULE (RAND_CONV VECTOR_ADD_CONV) th
+      | Comb(Comb(Const("%",_),l),r) ->
+          let rth = AP_TERM (rator tm) (VECTOR_CANON_CONV r) in
+          CONV_RULE (RAND_CONV(APPLY_pth4 ORELSEC VECTOR_CMUL_CONV)) rth
+      | Comb(Comb(Const("vector_sub",_),l),r) ->
+          (APPLY_pth2 THENC VECTOR_CANON_CONV) tm
+      | Comb(Const("vector_neg",_),t) ->
+          (APPLY_pth3 THENC VECTOR_CANON_CONV) tm
+      | Comb(Const("vec",_),n) when is_numeral n & dest_numeral n =/ Int 0 ->
+          REFL tm
+      | _ -> APPLY_pth1 tm in
+    fun tm ->
+      match tm with
+       Comb(Const("vector_norm",_),e) -> RAND_CONV VECTOR_CANON_CONV tm
+      | _ -> failwith "NORM_CANON_CONV" in
+  let REAL_VECTOR_COMBO_PROVER =
+    let pth_zero = prove(`norm(vec 0:real^N) = &0`,REWRITE_TAC[NORM_0])
+    and tv_n = mk_vartype "N" in
+    fun translator (nubs,ges,gts) ->
+      let sources = map (rand o rand o concl) nubs
+      and rawdests = itlist (find_normedterms o lhand o concl) (ges @ gts) [] in
+      if not (forall fst rawdests) then failwith "Sanity check" else
+      let dests = setify (map snd rawdests) in
+      let srcfuns = map vector_lincomb sources
+      and destfuns = map vector_lincomb dests in
+      let vvs = itlist (union o dom) (srcfuns @ destfuns) [] in
+      let n = length srcfuns in
+      let nvs = 1--n in
+      let srccombs = zip srcfuns nvs in
+      let consider d =
+        let coefficients x =
+            let inp = if defined d x then 0 |=> minus_num(apply d x)
+                      else undefined in
+          itlist (fun (f,v) g -> if defined f x then (v |-> apply f x) g else g)
+                 srccombs inp in
+        let equations = map coefficients vvs
+        and inequalities = map (fun n -> (n |=> Int 1)) nvs in
+        let plausiblevertices f =
+          let flippedequations = map (itlist flip f) equations in
+          let constraints = flippedequations @ inequalities in
+          let rawverts = vertices nvs constraints in
+          let check_solution v =
+            let f = itlist2 (|->) nvs v (0 |=> Int 1) in
+            forall (fun e -> evaluate f e =/ Int 0) flippedequations in
+          let goodverts = filter check_solution rawverts in
+          let signfixups = map (fun n -> if mem n f then -1 else 1) nvs in
+          map (map2 (fun s c -> Int s */ c) signfixups) goodverts in
+        let allverts = itlist (@) (map plausiblevertices (allsubsets nvs)) [] in
+        subsume allverts [] in
+      let compute_ineq v =
+        let ths = mapfilter (fun (v,t) -> if v =/ Int 0 then fail()
+                                          else  NORM_CMUL_RULE v t)
+                            (zip v nubs) in
+        INEQUALITY_CANON_RULE (end_itlist NORM_ADD_RULE ths) in
+      let ges' = mapfilter compute_ineq (itlist ((@) o consider) destfuns []) @
+                 map INEQUALITY_CANON_RULE nubs @ ges in
+      let zerodests = filter
+        (fun t -> dom(vector_lincomb t) = []) (map snd rawdests) in
+      REAL_LINEAR_PROVER translator
+       (map (fun t -> INST_TYPE [last(snd(dest_type(type_of t))),tv_n] pth_zero)
+            zerodests,
+        map (CONV_RULE(ONCE_DEPTH_CONV NORM_CANON_CONV THENC
+                       LAND_CONV REAL_POLY_CONV)) ges',
+        map (CONV_RULE(ONCE_DEPTH_CONV NORM_CANON_CONV THENC
+                       LAND_CONV REAL_POLY_CONV)) gts) in
+  let REAL_VECTOR_INEQ_PROVER =
+    let pth = prove
+     (`norm(x) = n ==> norm(x) >= &0 /\ n >= norm(x)`,
+      DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+      REWRITE_TAC[real_ge; NORM_POS_LE] THEN REAL_ARITH_TAC) in
+    let NORM_MP = MATCH_MP pth in
+    fun translator (ges,gts) ->
+    let ntms = itlist find_normedterms (map (lhand o concl) (ges @ gts)) [] in
+    let lctab = vector_lincombs (map snd (filter (not o fst) ntms)) in
+    let asl = map (fun (t,_) ->
+       ASSUME(mk_eq(mk_icomb(mk_const("vector_norm",[]),t),
+                    genvar `:real`))) lctab in
+    let replace_conv = GEN_REWRITE_CONV TRY_CONV asl in
+    let replace_rule = CONV_RULE (LAND_CONV (replacenegnorms replace_conv)) in
+    let ges' =
+       itlist (fun th ths -> CONJUNCT1(NORM_MP th)::ths)
+              asl (map replace_rule ges)
+    and gts' = map replace_rule gts
+    and nubs = map (CONJUNCT2 o NORM_MP) asl in
+    let th1 = REAL_VECTOR_COMBO_PROVER translator (nubs,ges',gts') in
+    let th2 = INST
+     (map (fun th -> let l,r = dest_eq(concl th) in (l,r)) asl) th1 in
+    itlist PROVE_HYP (map (REFL o lhand o concl) asl) th2 in
+  let REAL_VECTOR_PROVER =
+    let rawrule =
+      GEN_REWRITE_RULE I [REAL_ARITH `x = &0 <=> x >= &0 /\ --x >= &0`] in
+    let splitequation th acc =
+      let th1,th2 = CONJ_PAIR(rawrule th) in
+      th1::CONV_RULE(LAND_CONV REAL_POLY_NEG_CONV) th2::acc in
+    fun translator (eqs,ges,gts) ->
+      REAL_VECTOR_INEQ_PROVER translator
+         (itlist splitequation eqs ges,gts) in
+  let pth = prove
+   (`(!x y:real^N. x = y <=> norm(x - y) <= &0) /\
+     (!x y:real^N. ~(x = y) <=> ~(norm(x - y) <= &0))`,
+    REWRITE_TAC[NORM_LE_0; VECTOR_SUB_EQ]) in
+  let conv1 = GEN_REWRITE_CONV TRY_CONV [pth] in
+  let conv2 tm = (conv1 tm,conv1(mk_neg tm)) in
+  let init = GEN_REWRITE_CONV ONCE_DEPTH_CONV [DECIMAL] THENC
+             REAL_RAT_REDUCE_CONV THENC
+             GEN_REWRITE_CONV ONCE_DEPTH_CONV [dist] THENC
+             GEN_NNF_CONV true (conv1,conv2)
+  and pure = GEN_REAL_ARITH REAL_VECTOR_PROVER in
+  fun tm -> let th = init tm in EQ_MP (SYM th) (pure(rand(concl th)));;
+
+let NORM_ARITH_TAC = CONV_TAC NORM_ARITH;;
+
+let ASM_NORM_ARITH_TAC =
+  REPEAT(FIRST_X_ASSUM(MP_TAC o check (not o is_forall o concl))) THEN
+  NORM_ARITH_TAC;;
+
+(* ------------------------------------------------------------------------- *)
+(* Dot product in terms of the norm rather than conversely.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let DOT_NORM = prove
+ (`!x y. x dot y = (norm(x + y) pow 2 - norm(x) pow 2 - norm(y) pow 2) / &2`,
+  REWRITE_TAC[NORM_POW_2; DOT_LADD; DOT_RADD; DOT_SYM] THEN REAL_ARITH_TAC);;
+
+let DOT_NORM_NEG = prove
+ (`!x y. x dot y = ((norm(x) pow 2 + norm(y) pow 2) - norm(x - y) pow 2) / &2`,
+  REWRITE_TAC[NORM_POW_2; DOT_LADD; DOT_RADD; DOT_LSUB; DOT_RSUB; DOT_SYM] THEN
+  REAL_ARITH_TAC);;
+
+let DOT_NORM_SUB = prove
+ (`!x y. x dot y = ((norm(x) pow 2 + norm(y) pow 2) - norm(x - y) pow 2) / &2`,
+  REWRITE_TAC[NORM_POW_2; DOT_LSUB; DOT_RSUB; DOT_SYM] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Equality of vectors in terms of dot products.                             *)
+(* ------------------------------------------------------------------------- *)
+
+let VECTOR_EQ = prove
+ (`!x y. (x = y) <=> (x dot x = x dot y) /\ (y dot y = x dot x)`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL [SIMP_TAC[]; ALL_TAC] THEN
+  ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+  REWRITE_TAC[GSYM DOT_EQ_0] THEN
+  SIMP_TAC[DOT_LSUB; DOT_RSUB; DOT_SYM] THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence more metric properties.                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let DIST_REFL = prove
+ (`!x. dist(x,x) = &0`,
+  NORM_ARITH_TAC);;
+
+let DIST_SYM = prove
+ (`!x y. dist(x,y) = dist(y,x)`,
+  NORM_ARITH_TAC);;
+
+let DIST_POS_LE = prove
+ (`!x y. &0 <= dist(x,y)`,
+  NORM_ARITH_TAC);;
+
+let DIST_TRIANGLE = prove
+ (`!x:real^N y z. dist(x,z) <= dist(x,y) + dist(y,z)`,
+  NORM_ARITH_TAC);;
+
+let DIST_TRIANGLE_ALT = prove
+ (`!x y z. dist(y,z) <= dist(x,y) + dist(x,z)`,
+  NORM_ARITH_TAC);;
+
+let DIST_EQ_0 = prove
+ (`!x y. (dist(x,y) = &0) <=> (x = y)`,
+  NORM_ARITH_TAC);;
+
+let DIST_POS_LT = prove
+ (`!x y. ~(x = y) ==> &0 < dist(x,y)`,
+  NORM_ARITH_TAC);;
+
+let DIST_NZ = prove
+ (`!x y. ~(x = y) <=> &0 < dist(x,y)`,
+  NORM_ARITH_TAC);;
+
+let DIST_TRIANGLE_LE = prove
+ (`!x y z e. dist(x,z) + dist(y,z) <= e ==> dist(x,y) <= e`,
+  NORM_ARITH_TAC);;
+
+let DIST_TRIANGLE_LT = prove
+ (`!x y z e. dist(x,z) + dist(y,z) < e ==> dist(x,y) < e`,
+  NORM_ARITH_TAC);;
+
+let DIST_TRIANGLE_HALF_L = prove
+ (`!x1 x2 y. dist(x1,y) < e / &2 /\ dist(x2,y) < e / &2 ==> dist(x1,x2) < e`,
+  NORM_ARITH_TAC);;
+
+let DIST_TRIANGLE_HALF_R = prove
+ (`!x1 x2 y. dist(y,x1) < e / &2 /\ dist(y,x2) < e / &2 ==> dist(x1,x2) < e`,
+  NORM_ARITH_TAC);;
+
+let DIST_TRIANGLE_ADD = prove
+ (`!x x' y y'. dist(x + y,x' + y') <= dist(x,x') + dist(y,y')`,
+  NORM_ARITH_TAC);;
+
+let DIST_MUL = prove
+ (`!x y c. dist(c % x,c % y) = abs(c) * dist(x,y)`,
+  REWRITE_TAC[dist; GSYM VECTOR_SUB_LDISTRIB; NORM_MUL]);;
+
+let DIST_TRIANGLE_ADD_HALF = prove
+ (`!x x' y y':real^N.
+    dist(x,x') < e / &2 /\ dist(y,y') < e / &2 ==> dist(x + y,x' + y') < e`,
+  NORM_ARITH_TAC);;
+
+let DIST_LE_0 = prove
+ (`!x y. dist(x,y) <= &0 <=> x = y`,
+  NORM_ARITH_TAC);;
+
+let DIST_EQ = prove
+ (`!w x y z. dist(w,x) = dist(y,z) <=> dist(w,x) pow 2 = dist(y,z) pow 2`,
+  REWRITE_TAC[dist; NORM_POW_2; NORM_EQ]);;
+
+let DIST_0 = prove
+ (`!x. dist(x,vec 0) = norm(x) /\ dist(vec 0,x) = norm(x)`,
+  NORM_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Sums of vectors.                                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let NEUTRAL_VECTOR_ADD = prove
+ (`neutral(+) = vec 0:real^N`,
+  REWRITE_TAC[neutral] THEN MATCH_MP_TAC SELECT_UNIQUE THEN
+  REWRITE_TAC[VECTOR_ARITH `x + y = y <=> x = vec 0`;
+              VECTOR_ARITH `x + y = x <=> y = vec 0`]);;
+
+let MONOIDAL_VECTOR_ADD = prove
+ (`monoidal((+):real^N->real^N->real^N)`,
+  REWRITE_TAC[monoidal; NEUTRAL_VECTOR_ADD] THEN
+  REPEAT CONJ_TAC THEN VECTOR_ARITH_TAC);;
+
+let vsum = new_definition
+  `(vsum:(A->bool)->(A->real^N)->real^N) s f = lambda i. sum s (\x. f(x)$i)`;;
+
+let VSUM_CLAUSES = prove
+ (`(!f. vsum {} f = vec 0) /\
+   (!x f s. FINITE s
+            ==> (vsum (x INSERT s) f =
+                 if x IN s then vsum s f else f(x) + vsum s f))`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT; SUM_CLAUSES] THEN
+  SIMP_TAC[VEC_COMPONENT] THEN REPEAT STRIP_TAC THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[LAMBDA_BETA; VECTOR_ADD_COMPONENT]);;
+
+let VSUM = prove
+ (`!f s. FINITE s ==> vsum s f = iterate (+) s f`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  ASM_SIMP_TAC[VSUM_CLAUSES; ITERATE_CLAUSES; MONOIDAL_VECTOR_ADD] THEN
+  REWRITE_TAC[NEUTRAL_VECTOR_ADD]);;
+
+let VSUM_EQ_0 = prove
+ (`!f s. (!x:A. x IN s ==> (f(x) = vec 0)) ==> (vsum s f = vec 0)`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; vec; SUM_EQ_0]);;
+
+let VSUM_0 = prove
+ (`vsum s (\x. vec 0) = vec 0`,
+  SIMP_TAC[VSUM_EQ_0]);;
+
+let VSUM_LMUL = prove
+ (`!f c s.  vsum s (\x. c % f(x)) = c % vsum s f`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VECTOR_MUL_COMPONENT; SUM_LMUL]);;
+
+let VSUM_RMUL = prove
+ (`!c s v. vsum s (\x. c x % v) = (sum s c) % v`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VECTOR_MUL_COMPONENT; SUM_RMUL]);;
+
+let VSUM_ADD = prove
+ (`!f g s. FINITE s ==> (vsum s (\x. f x + g x) = vsum s f + vsum s g)`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT; SUM_ADD]);;
+
+let VSUM_SUB = prove
+ (`!f g s. FINITE s ==> (vsum s (\x. f x - g x) = vsum s f - vsum s g)`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VECTOR_SUB_COMPONENT; SUM_SUB]);;
+
+let VSUM_CONST = prove
+ (`!c s. FINITE s ==> (vsum s (\n. c) = &(CARD s) % c)`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; SUM_CONST; VECTOR_MUL_COMPONENT]);;
+
+let VSUM_COMPONENT = prove
+ (`!s f i. 1 <= i /\ i <= dimindex(:N)
+           ==> ((vsum s (f:A->real^N))$i = sum s (\x. f(x)$i))`,
+  SIMP_TAC[vsum; LAMBDA_BETA]);;
+
+let VSUM_IMAGE = prove
+ (`!f g s. FINITE s /\ (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y))
+           ==> (vsum (IMAGE f s) g = vsum s (g o f))`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA] THEN REPEAT STRIP_TAC THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) SUM_IMAGE o lhs o snd) THEN
+  ASM_REWRITE_TAC[o_DEF]);;
+
+let VSUM_UNION = prove
+ (`!f s t. FINITE s /\ FINITE t /\ DISJOINT s t
+           ==> (vsum (s UNION t) f = vsum s f + vsum t f)`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; SUM_UNION; VECTOR_ADD_COMPONENT]);;
+
+let VSUM_DIFF = prove
+ (`!f s t. FINITE s /\ t SUBSET s
+           ==> (vsum (s DIFF t) f = vsum s f - vsum t f)`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; SUM_DIFF; VECTOR_SUB_COMPONENT]);;
+
+let VSUM_DELETE = prove
+ (`!f s a. FINITE s /\ a IN s
+           ==> vsum (s DELETE a) f = vsum s f - f a`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; SUM_DELETE; VECTOR_SUB_COMPONENT]);;
+
+let VSUM_INCL_EXCL = prove
+ (`!s t (f:A->real^N).
+        FINITE s /\ FINITE t
+        ==> vsum s f + vsum t f = vsum (s UNION t) f + vsum (s INTER t) f`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT] THEN
+  SIMP_TAC[SUM_INCL_EXCL]);;
+
+let VSUM_NEG = prove
+ (`!f s. vsum s (\x. --f x) = --vsum s f`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; SUM_NEG; VECTOR_NEG_COMPONENT]);;
+
+let VSUM_EQ = prove
+ (`!f g s. (!x. x IN s ==> (f x = g x)) ==> (vsum s f = vsum s g)`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ THEN ASM_SIMP_TAC[]);;
+
+let VSUM_SUPERSET = prove
+ (`!f:A->real^N u v.
+        u SUBSET v /\ (!x. x IN v /\ ~(x IN u) ==> (f(x) = vec 0))
+        ==> (vsum v f = vsum u f)`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VEC_COMPONENT; SUM_SUPERSET]);;
+
+let VSUM_EQ_SUPERSET = prove
+ (`!f s t:A->bool.
+        FINITE t /\ t SUBSET s /\
+        (!x. x IN t ==> (f x = g x)) /\
+        (!x. x IN s /\ ~(x IN t) ==> f(x) = vec 0)
+        ==> vsum s f = vsum t g`,
+  MESON_TAC[VSUM_SUPERSET; VSUM_EQ]);;
+
+let VSUM_UNION_RZERO = prove
+ (`!f:A->real^N u v.
+        FINITE u /\ (!x. x IN v /\ ~(x IN u) ==> (f(x) = vec 0))
+        ==> (vsum (u UNION v) f = vsum u f)`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VEC_COMPONENT; SUM_UNION_RZERO]);;
+
+let VSUM_UNION_LZERO = prove
+ (`!f:A->real^N u v.
+        FINITE v /\ (!x. x IN u /\ ~(x IN v) ==> (f(x) = vec 0))
+        ==> (vsum (u UNION v) f = vsum v f)`,
+  MESON_TAC[VSUM_UNION_RZERO; UNION_COMM]);;
+
+let VSUM_RESTRICT = prove
+ (`!f s. FINITE s
+         ==> (vsum s (\x. if x IN s then f(x) else vec 0) = vsum s f)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC VSUM_EQ THEN ASM_SIMP_TAC[]);;
+
+let VSUM_RESTRICT_SET = prove
+ (`!P s f. vsum {x | x IN s /\ P x} f =
+           vsum s (\x. if P x then f x else vec 0)`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VEC_COMPONENT; SUM_RESTRICT_SET;
+           COND_COMPONENT]);;
+
+let VSUM_CASES = prove
+ (`!s P f g. FINITE s
+             ==> vsum s (\x:A. if P x then (f x):real^N else g x) =
+                 vsum {x | x IN s /\ P x} f + vsum {x | x IN s /\ ~P x} g`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT; SUM_CASES;
+           COND_COMPONENT]);;
+
+let VSUM_SING = prove
+ (`!f x. vsum {x} f = f(x)`,
+  SIMP_TAC[VSUM_CLAUSES; FINITE_RULES; NOT_IN_EMPTY; VECTOR_ADD_RID]);;
+
+let VSUM_NORM = prove
+ (`!f s. FINITE s ==> norm(vsum s f) <= sum s (\x. norm(f x))`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES; NORM_0; REAL_LE_REFL] THEN
+  NORM_ARITH_TAC);;
+
+let VSUM_NORM_LE = prove
+ (`!s f:A->real^N g.
+        FINITE s /\ (!x. x IN s ==> norm(f x) <= g(x))
+        ==> norm(vsum s f) <= sum s g`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum s (\x:A. norm(f x :real^N))` THEN
+  ASM_SIMP_TAC[VSUM_NORM; SUM_LE]);;
+
+let VSUM_NORM_TRIANGLE = prove
+ (`!s f b. FINITE s /\ sum s (\a. norm(f a)) <= b
+           ==> norm(vsum s f) <= b`,
+  MESON_TAC[VSUM_NORM; REAL_LE_TRANS]);;
+
+let VSUM_NORM_BOUND = prove
+ (`!s f b. FINITE s /\ (!x:A. x IN s ==> norm(f(x)) <= b)
+           ==> norm(vsum s f) <= &(CARD s) * b`,
+  SIMP_TAC[GSYM SUM_CONST; VSUM_NORM_LE]);;
+
+let VSUM_CLAUSES_NUMSEG = prove
+ (`(!m. vsum(m..0) f = if m = 0 then f(0) else vec 0) /\
+   (!m n. vsum(m..SUC n) f = if m <= SUC n then vsum(m..n) f + f(SUC n)
+                             else vsum(m..n) f)`,
+  REWRITE_TAC[NUMSEG_CLAUSES] THEN REPEAT STRIP_TAC THEN
+  COND_CASES_TAC THEN
+  ASM_SIMP_TAC[VSUM_SING; VSUM_CLAUSES; FINITE_NUMSEG; IN_NUMSEG] THEN
+  REWRITE_TAC[ARITH_RULE `~(SUC n <= n)`; VECTOR_ADD_AC]);;
+
+let VSUM_CLAUSES_RIGHT = prove
+ (`!f m n. 0 < n /\ m <= n ==> vsum(m..n) f = vsum(m..n-1) f + (f n):real^N`,
+  GEN_TAC THEN GEN_TAC THEN INDUCT_TAC THEN
+  SIMP_TAC[LT_REFL; VSUM_CLAUSES_NUMSEG; SUC_SUB1]);;
+
+let VSUM_CMUL_NUMSEG = prove
+ (`!f c m n. vsum (m..n) (\x. c % f x) = c % vsum (m..n) f`,
+  SIMP_TAC[VSUM_LMUL; FINITE_NUMSEG]);;
+
+let VSUM_EQ_NUMSEG = prove
+ (`!f g m n.
+         (!x. m <= x /\ x <= n ==> (f x = g x))
+         ==> (vsum(m .. n) f = vsum(m .. n) g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC VSUM_EQ THEN
+  ASM_SIMP_TAC[FINITE_NUMSEG; IN_NUMSEG]);;
+
+let VSUM_IMAGE_GEN = prove
+ (`!f:A->B g s.
+        FINITE s
+        ==> (vsum s g =
+             vsum (IMAGE f s) (\y. vsum {x | x IN s /\ (f(x) = y)} g))`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; SUM_IMAGE_GEN]);;
+
+let VSUM_GROUP = prove
+ (`!f:A->B g s t.
+        FINITE s /\ IMAGE f s SUBSET t
+        ==> vsum t (\y. vsum {x | x IN s /\ f(x) = y} g) = vsum s g`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; SUM_GROUP]);;
+
+let VSUM_VMUL = prove
+ (`!f v s. FINITE s ==> ((sum s f) % v = vsum s (\x. f(x) % v))`,
+  GEN_TAC THEN GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  ASM_SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES] THEN
+  REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[VECTOR_ADD_RDISTRIB] THEN
+  VECTOR_ARITH_TAC);;
+
+let VSUM_DELTA = prove
+ (`!s a. vsum s (\x. if x = a then b else vec 0) =
+         if a IN s then b else vec 0`,
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; VSUM_COMPONENT; COND_COMPONENT] THEN
+  SIMP_TAC[VEC_COMPONENT; SUM_DELTA]);;
+
+let VSUM_ADD_NUMSEG = prove
+ (`!f g m n. vsum(m..n) (\i. f i + g i) = vsum(m..n) f + vsum(m..n) g`,
+  SIMP_TAC[VSUM_ADD; FINITE_NUMSEG]);;
+
+let VSUM_SUB_NUMSEG = prove
+ (`!f g m n. vsum(m..n) (\i. f i - g i) = vsum(m..n) f - vsum(m..n) g`,
+  SIMP_TAC[VSUM_SUB; FINITE_NUMSEG]);;
+
+let VSUM_ADD_SPLIT = prove
+ (`!f m n p.
+       m <= n + 1 ==> vsum(m..n + p) f = vsum(m..n) f + vsum(n + 1..n + p) f`,
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; VSUM_COMPONENT; VECTOR_ADD_COMPONENT;
+           SUM_ADD_SPLIT]);;
+
+let VSUM_VSUM_PRODUCT = prove
+ (`!s:A->bool t:A->B->bool x.
+        FINITE s /\ (!i. i IN s ==> FINITE(t i))
+        ==> vsum s (\i. vsum (t i) (x i)) =
+            vsum {i,j | i IN s /\ j IN t i} (\(i,j). x i j)`,
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; VSUM_COMPONENT; COND_COMPONENT] THEN
+  SIMP_TAC[SUM_SUM_PRODUCT] THEN REPEAT STRIP_TAC THEN AP_TERM_TAC THEN
+  REWRITE_TAC[FUN_EQ_THM; FORALL_PAIR_THM]);;
+
+let VSUM_IMAGE_NONZERO = prove
+ (`!d:B->real^N i:A->B s.
+    FINITE s /\
+    (!x y. x IN s /\ y IN s /\ ~(x = y) /\ i x = i y ==> d(i x) = vec 0)
+    ==> vsum (IMAGE i s) d = vsum s (d o i)`,
+  GEN_TAC THEN GEN_TAC THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[IMAGE_CLAUSES; VSUM_CLAUSES; FINITE_IMAGE] THEN
+  MAP_EVERY X_GEN_TAC [`a:A`; `s:A->bool`] THEN
+  REWRITE_TAC[IN_INSERT] THEN REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `vsum s ((d:B->real^N) o (i:A->B)) = vsum (IMAGE i s) d`
+  SUBST1_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[o_THM] THEN
+  REWRITE_TAC[VECTOR_ARITH `a = x + a <=> x = vec 0`] THEN
+  ASM_MESON_TAC[IN_IMAGE]);;
+
+let VSUM_UNION_NONZERO = prove
+ (`!f s t. FINITE s /\ FINITE t /\ (!x. x IN s INTER t ==> f(x) = vec 0)
+           ==> vsum (s UNION t) f = vsum s f + vsum t f`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT] THEN
+  SIMP_TAC[VEC_COMPONENT; SUM_UNION_NONZERO]);;
+
+let VSUM_UNIONS_NONZERO = prove
+ (`!f s. FINITE s /\ (!t:A->bool. t IN s ==> FINITE t) /\
+         (!t1 t2 x. t1 IN s /\ t2 IN s /\ ~(t1 = t2) /\ x IN t1 /\ x IN t2
+                    ==> f x = vec 0)
+         ==> vsum (UNIONS s) f = vsum s (\t. vsum t f)`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[UNIONS_0; UNIONS_INSERT; VSUM_CLAUSES; IN_INSERT] THEN
+  MAP_EVERY X_GEN_TAC [`t:A->bool`; `s:(A->bool)->bool`] THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
+  ONCE_REWRITE_TAC[IMP_CONJ] THEN ASM_SIMP_TAC[VSUM_CLAUSES] THEN
+  ANTS_TAC THENL  [ASM_MESON_TAC[]; DISCH_THEN(SUBST_ALL_TAC o SYM)] THEN
+  STRIP_TAC THEN MATCH_MP_TAC VSUM_UNION_NONZERO THEN
+  ASM_SIMP_TAC[FINITE_UNIONS; IN_INTER; IN_UNIONS] THEN ASM_MESON_TAC[]);;
+
+let VSUM_CLAUSES_LEFT = prove
+ (`!f m n. m <= n ==> vsum(m..n) f = f m + vsum(m + 1..n) f`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT] THEN
+  SIMP_TAC[VEC_COMPONENT; SUM_CLAUSES_LEFT]);;
+
+let VSUM_DIFFS = prove
+ (`!m n. vsum(m..n) (\k. f(k) - f(k + 1)) =
+          if m <= n then f(m) - f(n + 1) else vec 0`,
+  GEN_TAC THEN INDUCT_TAC THEN ASM_SIMP_TAC[VSUM_CLAUSES_NUMSEG; LE] THEN
+  ASM_CASES_TAC `m = SUC n` THEN
+  ASM_REWRITE_TAC[ARITH_RULE `~(SUC n <= n)`; VECTOR_ADD_LID] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
+  REWRITE_TAC[GSYM ADD1] THEN VECTOR_ARITH_TAC);;
+
+let VSUM_DIFFS_ALT = prove
+ (`!m n. vsum(m..n) (\k. f(k + 1) - f(k)) =
+          if m <= n then f(n + 1) - f(m) else vec 0`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM VECTOR_NEG_SUB] THEN
+  SIMP_TAC[VSUM_NEG; VSUM_DIFFS] THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[VECTOR_NEG_SUB; VECTOR_NEG_0]);;
+
+let VSUM_DELETE_CASES = prove
+ (`!x f s.
+        FINITE(s:A->bool)
+        ==> vsum(s DELETE x) f = if x IN s then vsum s f - f x else vsum s f`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  ASM_SIMP_TAC[SET_RULE `~(x IN s) ==> s DELETE x = s`] THEN
+  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV)
+   [MATCH_MP (SET_RULE `x IN s ==> s = x INSERT (s DELETE x)`) th]) THEN
+  ASM_SIMP_TAC[VSUM_CLAUSES; FINITE_DELETE; IN_DELETE] THEN VECTOR_ARITH_TAC);;
+
+let VSUM_EQ_GENERAL = prove
+  (`!s:A->bool t:B->bool (f:A->real^N) g h.
+        (!y. y IN t ==> ?!x. x IN s /\ h x = y) /\
+        (!x. x IN s ==> h x IN t /\ g(h x) = f x)
+        ==> vsum s f = vsum t g`,
+   SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA] THEN
+   REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ_GENERAL THEN
+   EXISTS_TAC `h:A->B` THEN ASM_MESON_TAC[]);;
+
+let VSUM_EQ_GENERAL_INVERSES = prove
+ (`!s t (f:A->real^N) (g:B->real^N) h k.
+        (!y. y IN t ==> k y IN s /\ h (k y) = y) /\
+        (!x. x IN s ==> h x IN t /\ k (h x) = x /\ g (h x) = f x)
+        ==> vsum s f = vsum t g`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ_GENERAL_INVERSES THEN
+  MAP_EVERY EXISTS_TAC [`h:A->B`; `k:B->A`] THEN ASM_MESON_TAC[]);;
+
+let VSUM_NORM_ALLSUBSETS_BOUND = prove
+ (`!f:A->real^N p e.
+        FINITE p /\
+        (!q. q SUBSET p ==> norm(vsum q f) <= e)
+        ==> sum p (\x. norm(f x)) <= &2 * &(dimindex(:N)) * e`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC
+   `sum p (\x:A. sum (1..dimindex(:N)) (\i. abs((f x:real^N)$i)))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_LE THEN ASM_SIMP_TAC[NORM_LE_L1]; ALL_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhand o rand) SUM_SWAP o lhand o snd) THEN
+  ASM_REWRITE_TAC[FINITE_NUMSEG] THEN DISCH_THEN SUBST1_TAC THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `&2 * &n * e = &n * &2 * e`] THEN
+  GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o RAND_CONV)
+   [GSYM CARD_NUMSEG_1] THEN
+  MATCH_MP_TAC SUM_BOUND THEN REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+  X_GEN_TAC `k:num` THEN STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `sum {x:A | x IN p /\ &0 <= (f x:real^N)$k} (\x. abs((f x)$k)) +
+              sum {x | x IN p /\ (f x)$k < &0} (\x. abs((f x)$k))` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC(REAL_ARITH `a = b ==> b <= a`) THEN
+    MATCH_MP_TAC SUM_UNION_EQ THEN
+    ASM_SIMP_TAC[EXTENSION; NOT_IN_EMPTY; IN_INTER; IN_UNION; IN_ELIM_THM] THEN
+    CONJ_TAC THEN X_GEN_TAC `x:A` THEN ASM_CASES_TAC `(x:A) IN p` THEN
+    ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC(REAL_ARITH `x <= e /\ y <= e ==> x + y <= &2 * e`) THEN
+  GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [GSYM REAL_ABS_NEG] THEN
+  CONJ_TAC THEN MATCH_MP_TAC(REAL_ARITH
+   `!g. sum s g = sum s f /\ sum s g <= e ==> sum s f <= e`)
+  THENL
+   [EXISTS_TAC `\x. ((f:A->real^N) x)$k`;
+    EXISTS_TAC `\x. --(((f:A->real^N) x)$k)`] THEN
+  (CONJ_TAC THENL
+    [MATCH_MP_TAC SUM_EQ THEN REWRITE_TAC[IN_ELIM_THM] THEN REAL_ARITH_TAC;
+     ALL_TAC]) THEN
+  ASM_SIMP_TAC[GSYM VSUM_COMPONENT; SUM_NEG; FINITE_RESTRICT] THEN
+  MATCH_MP_TAC(REAL_ARITH `abs(x) <= e ==> x <= e`) THEN
+  REWRITE_TAC[REAL_ABS_NEG] THEN
+  MATCH_MP_TAC(REAL_ARITH
+   `abs((vsum q f)$k) <= norm(vsum q f) /\
+    norm(vsum q f) <= e
+    ==> abs((vsum q f)$k) <= e`) THEN
+  ASM_SIMP_TAC[COMPONENT_LE_NORM] THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN SET_TAC[]);;
+
+let DOT_LSUM = prove
+ (`!s f y. FINITE s ==> (vsum s f) dot y = sum s (\x. f(x) dot y)`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  ASM_SIMP_TAC[VSUM_CLAUSES; SUM_CLAUSES; DOT_LZERO; DOT_LADD]);;
+
+let DOT_RSUM = prove
+ (`!s f x. FINITE s ==> x dot (vsum s f) = sum s (\y. x dot f(y))`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  ASM_SIMP_TAC[VSUM_CLAUSES; SUM_CLAUSES; DOT_RZERO; DOT_RADD]);;
+
+let VSUM_OFFSET = prove
+ (`!f m p. vsum(m + p..n + p) f = vsum(m..n) (\i. f (i + p))`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VEC_COMPONENT; SUM_OFFSET]);;
+
+let VSUM_OFFSET_0 = prove
+ (`!f m n. m <= n ==> vsum(m..n) f = vsum(0..n - m) (\i. f (i + m))`,
+  SIMP_TAC[vsum; CART_EQ; LAMBDA_BETA; VEC_COMPONENT; SUM_OFFSET_0]);;
+
+let VSUM_TRIV_NUMSEG = prove
+ (`!f m n. n < m ==> vsum(m..n) f = vec 0`,
+  SIMP_TAC[GSYM NUMSEG_EMPTY; VSUM_CLAUSES]);;
+
+let VSUM_CONST_NUMSEG = prove
+ (`!c m n. vsum(m..n) (\n. c) = &((n + 1) - m) % c`,
+  SIMP_TAC[VSUM_CONST; FINITE_NUMSEG; CARD_NUMSEG]);;
+
+let VSUM_SUC = prove
+ (`!f m n. vsum (SUC n..SUC m) f = vsum (n..m) (f o SUC)`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `SUC n..SUC m = IMAGE SUC (n..m)` SUBST1_TAC THENL
+   [REWRITE_TAC [ADD1; NUMSEG_OFFSET_IMAGE] THEN
+    REWRITE_TAC [ONE; ADD_SUC; ADD_0; ETA_AX];
+    SIMP_TAC [VSUM_IMAGE; FINITE_NUMSEG; SUC_INJ]]);;
+
+let VSUM_BIJECTION = prove
+ (`!f:A->real^N p s:A->bool.
+                (!x. x IN s ==> p(x) IN s) /\
+                (!y. y IN s ==> ?!x. x IN s /\ p(x) = y)
+                ==> vsum s f = vsum s (f o p)`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN
+  MATCH_MP_TAC VSUM_EQ_GENERAL THEN EXISTS_TAC `p:A->A` THEN
+  ASM_REWRITE_TAC[o_THM]);;
+
+let VSUM_PARTIAL_SUC = prove
+ (`!f g:num->real^N m n.
+        vsum (m..n) (\k. f(k) % (g(k + 1) - g(k))) =
+            if m <= n then f(n + 1) % g(n + 1) - f(m) % g(m) -
+                           vsum (m..n) (\k. (f(k + 1) - f(k)) % g(k + 1))
+            else vec 0`,
+  GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN INDUCT_TAC THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[VSUM_TRIV_NUMSEG; GSYM NOT_LE] THEN
+  ASM_REWRITE_TAC[VSUM_CLAUSES_NUMSEG] THENL
+   [COND_CASES_TAC THEN ASM_SIMP_TAC[ARITH] THENL
+     [VECTOR_ARITH_TAC; ASM_ARITH_TAC];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LE]) THEN
+  DISCH_THEN(DISJ_CASES_THEN2 SUBST_ALL_TAC ASSUME_TAC) THEN
+  ASM_SIMP_TAC[GSYM NOT_LT; VSUM_TRIV_NUMSEG; ARITH_RULE `n < SUC n`] THEN
+  ASM_SIMP_TAC[GSYM ADD1; ADD_CLAUSES] THEN VECTOR_ARITH_TAC);;
+
+let VSUM_PARTIAL_PRE = prove
+ (`!f g:num->real^N m n.
+        vsum (m..n) (\k. f(k) % (g(k) - g(k - 1))) =
+            if m <= n then f(n + 1) % g(n) - f(m) % g(m - 1) -
+                           vsum (m..n) (\k. (f(k + 1) - f(k)) % g(k))
+            else vec 0`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`f:num->real`; `\k. (g:num->real^N)(k - 1)`;
+                 `m:num`; `n:num`] VSUM_PARTIAL_SUC) THEN
+  REWRITE_TAC[ADD_SUB] THEN DISCH_THEN SUBST1_TAC THEN
+  COND_CASES_TAC THEN REWRITE_TAC[]);;
+
+let VSUM_COMBINE_L = prove
+ (`!f m n p.
+        0 < n /\ m <= n /\ n <= p + 1
+        ==> vsum(m..n - 1) f + vsum(n..p) f = vsum(m..p) f`,
+  SIMP_TAC[CART_EQ; VECTOR_ADD_COMPONENT; VSUM_COMPONENT; SUM_COMBINE_L]);;
+
+let VSUM_COMBINE_R = prove
+ (`!f m n p.
+        m <= n + 1 /\ n <= p
+        ==> vsum(m..n) f + vsum(n + 1..p) f = vsum(m..p) f`,
+  SIMP_TAC[CART_EQ; VECTOR_ADD_COMPONENT; VSUM_COMPONENT; SUM_COMBINE_R]);;
+
+let VSUM_INJECTION = prove
+ (`!f p s.
+         FINITE s /\
+         (!x. x IN s ==> p x IN s) /\
+         (!x y. x IN s /\ y IN s /\ p x = p y ==> x = y)
+         ==> vsum s (f o p) = vsum s f`,
+  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP SUM_INJECTION) THEN
+  SIMP_TAC[CART_EQ; VSUM_COMPONENT; o_DEF]);;
+
+let VSUM_SWAP = prove
+ (`!f s t.
+         FINITE s /\ FINITE t
+         ==> vsum s (\i. vsum t (f i)) = vsum t (\j. vsum s (\i. f i j))`,
+   SIMP_TAC[CART_EQ; VSUM_COMPONENT] THEN REPEAT STRIP_TAC THEN
+   W(MP_TAC o PART_MATCH (lhs o rand) SUM_SWAP o lhs o snd) THEN
+   ASM_REWRITE_TAC[]);;
+
+let VSUM_SWAP_NUMSEG = prove
+  (`!a b c d f.
+         vsum (a..b) (\i. vsum (c..d) (f i)) =
+         vsum (c..d) (\j. vsum (a..b) (\i. f i j))`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC VSUM_SWAP THEN REWRITE_TAC[FINITE_NUMSEG]);;
+
+let VSUM_ADD_GEN = prove
+ (`!f g s.
+       FINITE {x | x IN s /\ ~(f x = vec 0)} /\
+       FINITE {x | x IN s /\ ~(g x = vec 0)}
+       ==> vsum s (\x. f x + g x) = vsum s f + vsum s g`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  SIMP_TAC[CART_EQ; vsum; LAMBDA_BETA; VECTOR_ADD_COMPONENT] THEN
+  REPEAT GEN_TAC THEN DISCH_THEN(K ALL_TAC) THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_ADD_GEN THEN
+  POP_ASSUM MP_TAC THEN MATCH_MP_TAC MONO_AND THEN
+  CONJ_TAC THEN MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ_ALT] FINITE_SUBSET) THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN GEN_TAC THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[DE_MORGAN_THM] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[VEC_COMPONENT]);;
+
+let VSUM_CASES_1 = prove
+ (`!s a. FINITE s /\ a IN s
+         ==> vsum s (\x. if x = a then y else f(x)) = vsum s f + (y - f a)`,
+  REPEAT STRIP_TAC THEN ASM_SIMP_TAC[VSUM_CASES] THEN
+  ASM_SIMP_TAC[GSYM DELETE; VSUM_DELETE] THEN
+  ASM_SIMP_TAC[SET_RULE `a IN s ==> {x | x IN s /\ x = a} = {a}`] THEN
+  REWRITE_TAC[VSUM_SING] THEN VECTOR_ARITH_TAC);;
+
+let VSUM_SING_NUMSEG = prove
+ (`vsum(n..n) f = f n`,
+  REWRITE_TAC[NUMSEG_SING; VSUM_SING]);;
+
+let VSUM_1 = prove
+ (`vsum(1..1) f = f(1)`,
+  REWRITE_TAC[VSUM_SING_NUMSEG]);;
+
+let VSUM_2 = prove
+ (`!t. vsum(1..2) t = t(1) + t(2)`,
+  REWRITE_TAC[num_CONV `2`; VSUM_CLAUSES_NUMSEG] THEN
+  REWRITE_TAC[VSUM_SING_NUMSEG; ARITH; REAL_ADD_ASSOC]);;
+
+let VSUM_3 = prove
+ (`!t. vsum(1..3) t = t(1) + t(2) + t(3)`,
+  REWRITE_TAC[num_CONV `3`; num_CONV `2`; VSUM_CLAUSES_NUMSEG] THEN
+  REWRITE_TAC[VSUM_SING_NUMSEG; ARITH; VECTOR_ADD_ASSOC]);;
+
+let VSUM_4 = prove
+ (`!t. vsum(1..4) t = t(1) + t(2) + t(3) + t(4)`,
+  SIMP_TAC[num_CONV `4`; num_CONV `3`; num_CONV `2`; VSUM_CLAUSES_NUMSEG] THEN
+  REWRITE_TAC[VSUM_SING_NUMSEG; ARITH; VECTOR_ADD_ASSOC]);;
+
+let VSUM_PAIR = prove
+ (`!f:num->real^N m n.
+        vsum(2*m..2*n+1) f = vsum(m..n) (\i. f(2*i) + f(2*i+1))`,
+  SIMP_TAC[CART_EQ; VSUM_COMPONENT; VECTOR_ADD_COMPONENT; SUM_PAIR]);;
+
+let VSUM_PAIR_0 = prove
+ (`!f:num->real^N n. vsum(0..2*n+1) f = vsum(0..n) (\i. f(2*i) + f(2*i+1))`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`f:num->real^N`; `0`; `n:num`] VSUM_PAIR) THEN
+  ASM_REWRITE_TAC[ARITH]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Add useful congruences to the simplifier.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let th = prove
+ (`(!f g s.   (!x. x IN s ==> f(x) = g(x))
+              ==> vsum s (\i. f(i)) = vsum s g) /\
+   (!f g a b. (!i. a <= i /\ i <= b ==> f(i) = g(i))
+              ==> vsum(a..b) (\i. f(i)) = vsum(a..b) g) /\
+   (!f g p.   (!x. p x ==> f x = g x)
+              ==> vsum {y | p y} (\i. f(i)) = vsum {y | p y} g)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC VSUM_EQ THEN
+  ASM_SIMP_TAC[IN_ELIM_THM; IN_NUMSEG]) in
+  extend_basic_congs (map SPEC_ALL (CONJUNCTS th));;
+
+(* ------------------------------------------------------------------------- *)
+(* A conversion for evaluation of `vsum(m..n) f` for numerals m and n.       *)
+(* ------------------------------------------------------------------------- *)
+
+let EXPAND_VSUM_CONV =
+  let pth_0,pth_1 = (CONJ_PAIR o prove)
+   (`vsum(0..0) (f:num->real^N) = f(0) /\
+     vsum(0..SUC n) f = vsum(0..n) f + f(SUC n)`,
+    REWRITE_TAC[VSUM_CLAUSES_NUMSEG; LE_0; VECTOR_ADD_AC]) in
+  let conv_0 = REWR_CONV pth_0 and conv_1 = REWR_CONV pth_1 in
+  let rec conv tm =
+    try (LAND_CONV(RAND_CONV num_CONV) THENC conv_1 THENC
+         NUM_REDUCE_CONV THENC LAND_CONV conv) tm
+    with Failure _ -> conv_0 tm in
+  conv THENC
+  (REDEPTH_CONV BETA_CONV) THENC
+  GEN_REWRITE_CONV TOP_DEPTH_CONV [GSYM VECTOR_ADD_ASSOC];;
+
+(* ------------------------------------------------------------------------- *)
+(* Basis vectors in coordinate directions.                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let basis = new_definition
+  `basis k = lambda i. if i = k then &1 else &0`;;
+
+let NORM_BASIS = prove
+ (`!k. 1 <= k /\ k <= dimindex(:N)
+       ==> (norm(basis k :real^N) = &1)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[basis; dot; vector_norm] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM SQRT_1] THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `sum (1..dimindex(:N)) (\i. if i = k then &1 else &0)` THEN
+  CONJ_TAC THENL
+   [MATCH_MP_TAC SUM_EQ_NUMSEG THEN
+    ASM_SIMP_TAC[LAMBDA_BETA; IN_NUMSEG; EQ_SYM_EQ] THEN
+    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN REAL_ARITH_TAC;
+    ASM_REWRITE_TAC[SUM_DELTA; IN_NUMSEG]]);;
+
+let NORM_BASIS_1 = prove
+ (`norm(basis 1) = &1`,
+  SIMP_TAC[NORM_BASIS; ARITH_EQ; ARITH_RULE `1 <= k <=> ~(k = 0)`;
+           DIMINDEX_NONZERO]);;
+
+let VECTOR_CHOOSE_SIZE = prove
+ (`!c. &0 <= c ==> ?x:real^N. norm(x) = c`,
+  REPEAT STRIP_TAC THEN EXISTS_TAC `c % basis 1 :real^N` THEN
+  ASM_REWRITE_TAC[NORM_MUL; real_abs; NORM_BASIS_1; REAL_MUL_RID]);;
+
+let VECTOR_CHOOSE_DIST = prove
+ (`!x e. &0 <= e ==> ?y:real^N. dist(x,y) = e`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `?c:real^N. norm(c) = e` CHOOSE_TAC THENL
+   [ASM_SIMP_TAC[VECTOR_CHOOSE_SIZE]; ALL_TAC] THEN
+  EXISTS_TAC `x - c:real^N` THEN REWRITE_TAC[dist] THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH `x - (x - c) = c:real^N`]);;
+
+let BASIS_INJ = prove
+ (`!i j. 1 <= i /\ i <= dimindex(:N) /\
+         1 <= j /\ j <= dimindex(:N) /\
+         (basis i :real^N = basis j)
+         ==> (i = j)`,
+  SIMP_TAC[basis; CART_EQ; LAMBDA_BETA] THEN REPEAT GEN_TAC THEN
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `i:num`) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  ASM_SIMP_TAC[REAL_OF_NUM_EQ; ARITH_EQ]);;
+
+let BASIS_INJ_EQ = prove
+ (`!i j. 1 <= i /\ i <= dimindex(:N) /\ 1 <= j /\ j <= dimindex(:N)
+         ==> (basis i:real^N = basis j <=> i = j)`,
+  MESON_TAC[BASIS_INJ]);;
+
+let BASIS_NE = prove
+ (`!i j. 1 <= i /\ i <= dimindex(:N) /\
+         1 <= j /\ j <= dimindex(:N) /\
+         ~(i = j)
+         ==> ~(basis i :real^N = basis j)`,
+  MESON_TAC[BASIS_INJ]);;
+
+let BASIS_COMPONENT = prove
+ (`!k i. 1 <= i /\ i <= dimindex(:N)
+         ==> ((basis k :real^N)$i = if i = k then &1 else &0)`,
+  SIMP_TAC[basis; LAMBDA_BETA] THEN MESON_TAC[]);;
+
+let BASIS_EXPANSION = prove
+ (`!x:real^N. vsum(1..dimindex(:N)) (\i. x$i % basis i) = x`,
+  SIMP_TAC[CART_EQ; VSUM_COMPONENT; VECTOR_MUL_COMPONENT; BASIS_COMPONENT] THEN
+  ONCE_REWRITE_TAC[COND_RAND] THEN REWRITE_TAC[REAL_MUL_RZERO] THEN
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
+  ASM_SIMP_TAC[SUM_DELTA; IN_NUMSEG; REAL_MUL_RID]);;
+
+let BASIS_EXPANSION_UNIQUE = prove
+ (`!f x:real^N. (vsum(1..dimindex(:N)) (\i. f(i) % basis i) = x) <=>
+                (!i. 1 <= i /\ i <= dimindex(:N) ==> f(i) = x$i)`,
+  SIMP_TAC[CART_EQ; VSUM_COMPONENT; VECTOR_MUL_COMPONENT; BASIS_COMPONENT] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[COND_RAND; REAL_MUL_RZERO; REAL_MUL_RID] THEN
+  GEN_REWRITE_TAC (LAND_CONV o BINDER_CONV o RAND_CONV o LAND_CONV o
+                   ONCE_DEPTH_CONV) [EQ_SYM_EQ] THEN
+  SIMP_TAC[SUM_DELTA; IN_NUMSEG]);;
+
+let DOT_BASIS = prove
+ (`!x:real^N i.
+        1 <= i /\ i <= dimindex(:N)
+        ==> ((basis i) dot x = x$i) /\ (x dot (basis i) = x$i)`,
+  SIMP_TAC[dot; basis; LAMBDA_BETA] THEN
+  REWRITE_TAC[COND_RATOR; COND_RAND] THEN
+  REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_RZERO] THEN
+  SIMP_TAC[SUM_DELTA; IN_NUMSEG; REAL_MUL_LID; REAL_MUL_RID]);;
+
+let DOT_BASIS_BASIS = prove
+ (`!i j. 1 <= i /\ i <= dimindex(:N) /\
+         1 <= j /\ j <= dimindex(:N)
+         ==> (basis i:real^N) dot (basis j) = if i = j then &1 else &0`,
+  SIMP_TAC[DOT_BASIS; BASIS_COMPONENT]);;
+
+let DOT_BASIS_BASIS_UNEQUAL = prove
+ (`!i j. ~(i = j) ==> (basis i) dot (basis j) = &0`,
+  SIMP_TAC[basis; dot; LAMBDA_BETA] THEN ONCE_REWRITE_TAC[COND_RAND] THEN
+  SIMP_TAC[SUM_0; REAL_MUL_RZERO; REAL_MUL_LZERO; COND_ID]);;
+
+let BASIS_EQ_0 = prove
+ (`!i. (basis i :real^N = vec 0) <=> ~(i IN 1..dimindex(:N))`,
+  SIMP_TAC[CART_EQ; BASIS_COMPONENT; VEC_COMPONENT; IN_NUMSEG] THEN
+  MESON_TAC[REAL_ARITH `~(&1 = &0)`]);;
+
+let BASIS_NONZERO = prove
+ (`!k. 1 <= k /\ k <= dimindex(:N)
+       ==> ~(basis k :real^N = vec 0)`,
+  REWRITE_TAC[BASIS_EQ_0; IN_NUMSEG]);;
+
+let VECTOR_EQ_LDOT = prove
+ (`!y z. (!x. x dot y = x dot z) <=> y = z`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN SIMP_TAC[] THEN
+  REWRITE_TAC[CART_EQ] THEN MESON_TAC[DOT_BASIS]);;
+
+let VECTOR_EQ_RDOT = prove
+ (`!x y. (!z. x dot z = y dot z) <=> x = y`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN SIMP_TAC[] THEN
+  REWRITE_TAC[CART_EQ] THEN MESON_TAC[DOT_BASIS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Orthogonality.                                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let orthogonal = new_definition
+  `orthogonal x y <=> (x dot y = &0)`;;
+
+let ORTHOGONAL_0 = prove
+ (`!x. orthogonal (vec 0) x /\ orthogonal x (vec 0)`,
+  REWRITE_TAC[orthogonal; DOT_LZERO; DOT_RZERO]);;
+
+let ORTHOGONAL_REFL = prove
+ (`!x. orthogonal x x <=> x = vec 0`,
+  REWRITE_TAC[orthogonal; DOT_EQ_0]);;
+
+let ORTHOGONAL_SYM = prove
+ (`!x y. orthogonal x y <=> orthogonal y x`,
+  REWRITE_TAC[orthogonal; DOT_SYM]);;
+
+let ORTHOGONAL_LNEG = prove
+ (`!x y. orthogonal (--x) y <=> orthogonal x y`,
+  REWRITE_TAC[orthogonal; DOT_LNEG; REAL_NEG_EQ_0]);;
+
+let ORTHOGONAL_RNEG = prove
+ (`!x y. orthogonal x (--y) <=> orthogonal x y`,
+  REWRITE_TAC[orthogonal; DOT_RNEG; REAL_NEG_EQ_0]);;
+
+let ORTHOGONAL_MUL = prove
+ (`(!a x y:real^N. orthogonal (a % x) y <=> a = &0 \/ orthogonal x y) /\
+   (!a x y:real^N. orthogonal x (a % y) <=> a = &0 \/ orthogonal x y)`,
+  REWRITE_TAC[orthogonal; DOT_LMUL; DOT_RMUL; REAL_ENTIRE]);;
+
+let ORTHOGONAL_BASIS = prove
+ (`!x:real^N i. 1 <= i /\ i <= dimindex(:N)
+                ==> (orthogonal (basis i) x <=> (x$i = &0))`,
+  REPEAT STRIP_TAC THEN SIMP_TAC[orthogonal; dot; basis; LAMBDA_BETA] THEN
+  REWRITE_TAC[COND_RAND; COND_RATOR; REAL_MUL_LZERO] THEN
+  ASM_SIMP_TAC[SUM_DELTA; IN_NUMSEG; REAL_MUL_LID]);;
+
+let ORTHOGONAL_BASIS_BASIS = prove
+ (`!i j. 1 <= i /\ i <= dimindex(:N) /\
+         1 <= j /\ j <= dimindex(:N)
+         ==> (orthogonal (basis i :real^N) (basis j) <=> ~(i = j))`,
+  ASM_SIMP_TAC[ORTHOGONAL_BASIS] THEN ASM_SIMP_TAC[BASIS_COMPONENT] THEN
+  MESON_TAC[REAL_ARITH `~(&1 = &0)`]);;
+
+let ORTHOGONAL_CLAUSES = prove
+ (`(!a. orthogonal a (vec 0)) /\
+   (!a x c. orthogonal a x ==> orthogonal a (c % x)) /\
+   (!a x. orthogonal a x ==> orthogonal a (--x)) /\
+   (!a x y. orthogonal a x /\ orthogonal a y ==> orthogonal a (x + y)) /\
+   (!a x y. orthogonal a x /\ orthogonal a y ==> orthogonal a (x - y)) /\
+   (!a. orthogonal (vec 0) a) /\
+   (!a x c. orthogonal x a ==> orthogonal (c % x) a) /\
+   (!a x. orthogonal x a ==> orthogonal (--x) a) /\
+   (!a x y. orthogonal x a /\ orthogonal y a ==> orthogonal (x + y) a) /\
+   (!a x y. orthogonal x a /\ orthogonal y a ==> orthogonal (x - y) a)`,
+  REWRITE_TAC[orthogonal; DOT_RNEG; DOT_RMUL; DOT_RADD; DOT_RSUB;
+    DOT_LZERO; DOT_RZERO; DOT_LNEG; DOT_LMUL; DOT_LADD; DOT_LSUB] THEN
+  SIMP_TAC[] THEN REAL_ARITH_TAC);;
+
+let ORTHOGONAL_RVSUM = prove
+ (`!f:A->real^N s x.
+        FINITE s /\
+        (!y. y IN s ==> orthogonal x (f y))
+        ==> orthogonal x (vsum s f)`,
+  GEN_TAC THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[NOT_IN_EMPTY; FORALL_IN_INSERT; ORTHOGONAL_CLAUSES; VSUM_CLAUSES]);;
+
+let ORTHOGONAL_LVSUM = prove
+ (`!f:A->real^N s y.
+        FINITE s /\
+        (!x. x IN s ==> orthogonal (f x) y)
+        ==> orthogonal (vsum s f) y`,
+  GEN_TAC THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM; IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[NOT_IN_EMPTY; FORALL_IN_INSERT; ORTHOGONAL_CLAUSES; VSUM_CLAUSES]);;
+
+let NORM_ADD_PYTHAGOREAN = prove
+ (`!a b:real^N.
+        orthogonal a b
+        ==> norm(a + b) pow 2 = norm(a) pow 2 + norm(b) pow 2`,
+  SIMP_TAC[NORM_POW_2; orthogonal; DOT_LADD; DOT_RADD; DOT_SYM] THEN
+  REAL_ARITH_TAC);;
+
+let NORM_VSUM_PYTHAGOREAN = prove
+ (`!k u:A->real^N.
+        FINITE k /\ pairwise (\i j. orthogonal (u i) (u j)) k
+        ==> norm(vsum k u) pow 2 = sum k (\i. norm(u i) pow 2)`,
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN GEN_TAC THEN SIMP_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; SUM_CLAUSES; NORM_0] THEN
+  CONV_TAC REAL_RAT_REDUCE_CONV THEN REWRITE_TAC[PAIRWISE_INSERT] THEN
+  REWRITE_TAC[pairwise] THEN REPEAT GEN_TAC THEN
+  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC NORM_ADD_PYTHAGOREAN THEN MATCH_MP_TAC ORTHOGONAL_RVSUM THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Explicit vector construction from lists.                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let VECTOR_1 = prove
+ (`(vector[x]:A^1)$1 = x`,
+  SIMP_TAC[vector; LAMBDA_BETA; DIMINDEX_1; ARITH; LENGTH; EL; HD; TL]);;
+
+let VECTOR_2 = prove
+ (`(vector[x;y]:A^2)$1 = x /\
+   (vector[x;y]:A^2)$2 = y`,
+  SIMP_TAC[vector; LAMBDA_BETA; DIMINDEX_2; ARITH; LENGTH; EL] THEN
+  REWRITE_TAC[num_CONV `1`; HD; TL; EL]);;
+
+let VECTOR_3 = prove
+ (`(vector[x;y;z]:A^3)$1 = x /\
+   (vector[x;y;z]:A^3)$2 = y /\
+   (vector[x;y;z]:A^3)$3 = z`,
+  SIMP_TAC[vector; LAMBDA_BETA; DIMINDEX_3; ARITH; LENGTH; EL] THEN
+  REWRITE_TAC[num_CONV `2`; num_CONV `1`; HD; TL; EL]);;
+
+let VECTOR_4 = prove
+ (`(vector[w;x;y;z]:A^4)$1 = w /\
+   (vector[w;x;y;z]:A^4)$2 = x /\
+   (vector[w;x;y;z]:A^4)$3 = y /\
+   (vector[w;x;y;z]:A^4)$4 = z`,
+  SIMP_TAC[vector; LAMBDA_BETA; DIMINDEX_4; ARITH; LENGTH; EL] THEN
+  REWRITE_TAC[num_CONV `3`; num_CONV `2`; num_CONV `1`; HD; TL; EL]);;
+
+let FORALL_VECTOR_1 = prove
+ (`(!v:A^1. P v) <=> !x. P(vector[x])`,
+  EQ_TAC THEN SIMP_TAC[] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(v:A^1)$1`) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[CART_EQ; FORALL_1; VECTOR_1; DIMINDEX_1]);;
+
+let FORALL_VECTOR_2 = prove
+ (`(!v:A^2. P v) <=> !x y. P(vector[x;y])`,
+  EQ_TAC THEN SIMP_TAC[] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL [`(v:A^2)$1`; `(v:A^2)$2`]) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[CART_EQ; FORALL_2; VECTOR_2; DIMINDEX_2]);;
+
+let FORALL_VECTOR_3 = prove
+ (`(!v:A^3. P v) <=> !x y z. P(vector[x;y;z])`,
+  EQ_TAC THEN SIMP_TAC[] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+    [`(v:A^3)$1`; `(v:A^3)$2`; `(v:A^3)$3`]) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[CART_EQ; FORALL_3; VECTOR_3; DIMINDEX_3]);;
+
+let FORALL_VECTOR_4 = prove
+ (`(!v:A^4. P v) <=> !w x y z. P(vector[w;x;y;z])`,
+  EQ_TAC THEN SIMP_TAC[] THEN REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+    [`(v:A^4)$1`; `(v:A^4)$2`; `(v:A^4)$3`; `(v:A^4)$4`]) THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[CART_EQ; FORALL_4; VECTOR_4; DIMINDEX_4]);;
+
+let EXISTS_VECTOR_1 = prove
+ (`(?v:A^1. P v) <=> ?x. P(vector[x])`,
+  REWRITE_TAC[MESON[] `(?x. P x) <=> ~(!x. ~P x)`] THEN
+  REWRITE_TAC[FORALL_VECTOR_1]);;
+
+let EXISTS_VECTOR_2 = prove
+ (`(?v:A^2. P v) <=> ?x y. P(vector[x;y])`,
+  REWRITE_TAC[MESON[] `(?x. P x) <=> ~(!x. ~P x)`] THEN
+  REWRITE_TAC[FORALL_VECTOR_2]);;
+
+let EXISTS_VECTOR_3 = prove
+ (`(?v:A^3. P v) <=> ?x y z. P(vector[x;y;z])`,
+  REWRITE_TAC[MESON[] `(?x. P x) <=> ~(!x. ~P x)`] THEN
+  REWRITE_TAC[FORALL_VECTOR_3]);;
+
+let EXISTS_VECTOR_4 = prove
+ (`(?v:A^4. P v) <=> ?w x y z. P(vector[w;x;y;z])`,
+  REWRITE_TAC[MESON[] `(?x. P x) <=> ~(!x. ~P x)`] THEN
+  REWRITE_TAC[FORALL_VECTOR_4]);;
+
+let VECTOR_EXPAND_1 = prove
+ (`!x:real^1. x = vector[x$1]`,
+  SIMP_TAC[CART_EQ; DIMINDEX_1; FORALL_1; VECTOR_1]);;
+
+let VECTOR_EXPAND_2 = prove
+ (`!x:real^2. x = vector[x$1;x$2]`,
+  SIMP_TAC[CART_EQ; DIMINDEX_2; FORALL_2; VECTOR_2]);;
+
+let VECTOR_EXPAND_3 = prove
+ (`!x:real^3. x = vector[x$1;x$2;x$3]`,
+  SIMP_TAC[CART_EQ; DIMINDEX_3; FORALL_3; VECTOR_3]);;
+
+let VECTOR_EXPAND_4 = prove
+ (`!x:real^4. x = vector[x$1;x$2;x$3;x$4]`,
+  SIMP_TAC[CART_EQ; DIMINDEX_4; FORALL_4; VECTOR_4]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Linear functions.                                                         *)
+(* ------------------------------------------------------------------------- *)
+
+let linear = new_definition
+  `linear (f:real^M->real^N) <=>
+        (!x y. f(x + y) = f(x) + f(y)) /\
+        (!c x. f(c % x) = c % f(x))`;;
+
+let LINEAR_COMPOSE_CMUL = prove
+ (`!f c. linear f ==> linear (\x. c % f(x))`,
+  SIMP_TAC[linear] THEN REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC);;
+
+let LINEAR_COMPOSE_NEG = prove
+ (`!f. linear f ==> linear (\x. --(f(x)))`,
+  SIMP_TAC[linear] THEN REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC);;
+
+let LINEAR_COMPOSE_ADD = prove
+ (`!f g. linear f /\ linear g ==> linear (\x. f(x) + g(x))`,
+  SIMP_TAC[linear] THEN REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC);;
+
+let LINEAR_COMPOSE_SUB = prove
+ (`!f g. linear f /\ linear g ==> linear (\x. f(x) - g(x))`,
+  SIMP_TAC[linear] THEN REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC);;
+
+let LINEAR_COMPOSE = prove
+ (`!f g. linear f /\ linear g ==> linear (g o f)`,
+  SIMP_TAC[linear; o_THM]);;
+
+let LINEAR_ID = prove
+ (`linear (\x. x)`,
+  REWRITE_TAC[linear]);;
+
+let LINEAR_I = prove
+ (`linear I`,
+  REWRITE_TAC[I_DEF; LINEAR_ID]);;
+
+let LINEAR_ZERO = prove
+ (`linear (\x. vec 0)`,
+  REWRITE_TAC[linear] THEN CONJ_TAC THEN VECTOR_ARITH_TAC);;
+
+let LINEAR_NEGATION = prove
+ (`linear(--)`,
+  REWRITE_TAC[linear] THEN VECTOR_ARITH_TAC);;
+
+let LINEAR_COMPOSE_VSUM = prove
+ (`!f s. FINITE s /\ (!a. a IN s ==> linear(f a))
+         ==> linear(\x. vsum s (\a. f a x))`,
+  GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; LINEAR_ZERO] THEN
+  ASM_SIMP_TAC[ETA_AX; IN_INSERT; LINEAR_COMPOSE_ADD]);;
+
+let LINEAR_VMUL_COMPONENT = prove
+ (`!f:real^M->real^N v k.
+     linear f /\ 1 <= k /\ k <= dimindex(:N)
+     ==> linear (\x. f(x)$k % v)`,
+  SIMP_TAC[linear; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC);;
+
+let LINEAR_0 = prove
+ (`!f. linear f ==> (f(vec 0) = vec 0)`,
+  MESON_TAC[VECTOR_MUL_LZERO; linear]);;
+
+let LINEAR_CMUL = prove
+ (`!f c x. linear f ==> (f(c % x) = c % f(x))`,
+  SIMP_TAC[linear]);;
+
+let LINEAR_NEG = prove
+ (`!f x. linear f ==> (f(--x) = --(f x))`,
+  ONCE_REWRITE_TAC[VECTOR_NEG_MINUS1] THEN SIMP_TAC[LINEAR_CMUL]);;
+
+let LINEAR_ADD = prove
+ (`!f x y. linear f ==> (f(x + y) = f(x) + f(y))`,
+  SIMP_TAC[linear]);;
+
+let LINEAR_SUB = prove
+ (`!f x y. linear f ==> (f(x - y) = f(x) - f(y))`,
+  SIMP_TAC[VECTOR_SUB; LINEAR_ADD; LINEAR_NEG]);;
+
+let LINEAR_VSUM = prove
+ (`!f g s. linear f /\ FINITE s ==> (f(vsum s g) = vsum s (f o g))`,
+  GEN_TAC THEN GEN_TAC THEN SIMP_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  DISCH_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES] THEN FIRST_ASSUM(fun th ->
+    SIMP_TAC[MATCH_MP LINEAR_0 th; MATCH_MP LINEAR_ADD th; o_THM]));;
+
+let LINEAR_VSUM_MUL = prove
+ (`!f s c v.
+        linear f /\ FINITE s
+        ==> f(vsum s (\i. c i % v i)) = vsum s (\i. c(i) % f(v i))`,
+  SIMP_TAC[LINEAR_VSUM; o_DEF; LINEAR_CMUL]);;
+
+let LINEAR_INJECTIVE_0 = prove
+ (`!f. linear f
+       ==> ((!x y. (f(x) = f(y)) ==> (x = y)) <=>
+            (!x. (f(x) = vec 0) ==> (x = vec 0)))`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [GSYM VECTOR_SUB_EQ] THEN
+  ASM_SIMP_TAC[GSYM LINEAR_SUB] THEN MESON_TAC[VECTOR_SUB_RZERO]);;
+
+let LINEAR_BOUNDED = prove
+ (`!f:real^M->real^N. linear f ==> ?B. !x. norm(f x) <= B * norm(x)`,
+  REPEAT STRIP_TAC THEN EXISTS_TAC
+   `sum(1..dimindex(:M)) (\i. norm((f:real^M->real^N)(basis i)))` THEN
+  GEN_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o funpow 2 RAND_CONV) [GSYM BASIS_EXPANSION] THEN
+  ASM_SIMP_TAC[LINEAR_VSUM; FINITE_NUMSEG] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM SUM_LMUL] THEN
+  MATCH_MP_TAC VSUM_NORM_LE THEN
+  SIMP_TAC[FINITE_CROSS; FINITE_NUMSEG; IN_NUMSEG] THEN
+  ASM_SIMP_TAC[o_DEF; NORM_MUL; LINEAR_CMUL] THEN
+  ASM_SIMP_TAC[REAL_LE_RMUL; NORM_POS_LE; COMPONENT_LE_NORM]);;
+
+let LINEAR_BOUNDED_POS = prove
+ (`!f:real^M->real^N. linear f ==> ?B. &0 < B /\ !x. norm(f x) <= B * norm(x)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(X_CHOOSE_TAC `B:real` o MATCH_MP LINEAR_BOUNDED) THEN
+  EXISTS_TAC `abs(B) + &1` THEN CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+  POP_ASSUM MP_TAC THEN MATCH_MP_TAC MONO_FORALL THEN GEN_TAC THEN
+  MATCH_MP_TAC(REAL_ARITH `a <= b ==> x <= a ==> x <= b`) THEN
+  MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+  REAL_ARITH_TAC);;
+
+let SYMMETRIC_LINEAR_IMAGE = prove
+ (`!f s. (!x. x IN s ==> --x IN s) /\ linear f
+          ==> !x. x IN (IMAGE f s) ==> --x IN (IMAGE f s)`,
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN
+  SIMP_TAC[GSYM LINEAR_NEG] THEN SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Bilinear functions.                                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let bilinear = new_definition
+  `bilinear f <=> (!x. linear(\y. f x y)) /\ (!y. linear(\x. f x y))`;;
+
+let BILINEAR_LADD = prove
+ (`!h x y z. bilinear h ==> h (x + y) z = (h x z) + (h y z)`,
+  SIMP_TAC[bilinear; linear]);;
+
+let BILINEAR_RADD = prove
+ (`!h x y z. bilinear h ==> h x (y + z) = (h x y) + (h x z)`,
+  SIMP_TAC[bilinear; linear]);;
+
+let BILINEAR_LMUL = prove
+ (`!h c x y. bilinear h ==> h (c % x) y = c % (h x y)`,
+  SIMP_TAC[bilinear; linear]);;
+
+let BILINEAR_RMUL = prove
+ (`!h c x y. bilinear h ==> h x (c % y) = c % (h x y)`,
+  SIMP_TAC[bilinear; linear]);;
+
+let BILINEAR_LNEG = prove
+ (`!h x y. bilinear h ==> h (--x) y = --(h x y)`,
+  ONCE_REWRITE_TAC[VECTOR_NEG_MINUS1] THEN SIMP_TAC[BILINEAR_LMUL]);;
+
+let BILINEAR_RNEG = prove
+ (`!h x y. bilinear h ==> h x (--y) = --(h x y)`,
+  ONCE_REWRITE_TAC[VECTOR_NEG_MINUS1] THEN SIMP_TAC[BILINEAR_RMUL]);;
+
+let BILINEAR_LZERO = prove
+ (`!h x. bilinear h ==> h (vec 0) x = vec 0`,
+  ONCE_REWRITE_TAC[VECTOR_ARITH `x = vec 0 <=> x + x = x`] THEN
+  SIMP_TAC[GSYM BILINEAR_LADD; VECTOR_ADD_LID]);;
+
+let BILINEAR_RZERO = prove
+ (`!h x. bilinear h ==> h x (vec 0) = vec 0`,
+  ONCE_REWRITE_TAC[VECTOR_ARITH `x = vec 0 <=> x + x = x`] THEN
+  SIMP_TAC[GSYM BILINEAR_RADD; VECTOR_ADD_LID]);;
+
+let BILINEAR_LSUB = prove
+ (`!h x y z. bilinear h ==> h (x - y) z = (h x z) - (h y z)`,
+  SIMP_TAC[VECTOR_SUB; BILINEAR_LNEG; BILINEAR_LADD]);;
+
+let BILINEAR_RSUB = prove
+ (`!h x y z. bilinear h ==> h x (y - z) = (h x y) - (h x z)`,
+  SIMP_TAC[VECTOR_SUB; BILINEAR_RNEG; BILINEAR_RADD]);;
+
+let BILINEAR_VSUM = prove
+ (`!h:real^M->real^N->real^P.
+       bilinear h /\ FINITE s /\ FINITE t
+       ==> h (vsum s f) (vsum t g) = vsum (s CROSS t) (\(i,j). h (f i) (g j))`,
+  REPEAT GEN_TAC THEN SIMP_TAC[bilinear; ETA_AX] THEN
+  ONCE_REWRITE_TAC[TAUT `(a /\ b) /\ c /\ d <=> (a /\ d) /\ (b /\ c)`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
+  ONCE_REWRITE_TAC[LEFT_AND_FORALL_THM] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_ALL o MATCH_MP LINEAR_VSUM o SPEC_ALL) THEN
+  SIMP_TAC[] THEN ASM_SIMP_TAC[LINEAR_VSUM; o_DEF; VSUM_VSUM_PRODUCT] THEN
+  REWRITE_TAC[GSYM CROSS]);;
+
+let BILINEAR_BOUNDED = prove
+ (`!h:real^M->real^N->real^P.
+        bilinear h ==> ?B. !x y. norm(h x y) <= B * norm(x) * norm(y)`,
+  REPEAT STRIP_TAC THEN
+  EXISTS_TAC `sum ((1..dimindex(:M)) CROSS (1..dimindex(:N)))
+                  (\(i,j). norm((h:real^M->real^N->real^P)
+                                (basis i) (basis j)))` THEN
+  REPEAT GEN_TAC THEN GEN_REWRITE_TAC
+   (LAND_CONV o RAND_CONV o BINOP_CONV) [GSYM BASIS_EXPANSION] THEN
+  ASM_SIMP_TAC[BILINEAR_VSUM; FINITE_NUMSEG] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM SUM_LMUL] THEN
+  MATCH_MP_TAC VSUM_NORM_LE THEN
+  SIMP_TAC[FINITE_CROSS; FINITE_NUMSEG; FORALL_PAIR_THM; IN_CROSS] THEN
+  REWRITE_TAC[IN_NUMSEG] THEN REPEAT STRIP_TAC THEN
+  ASM_SIMP_TAC[BILINEAR_LMUL; NORM_MUL] THEN
+  ASM_SIMP_TAC[BILINEAR_RMUL; NORM_MUL; REAL_MUL_ASSOC] THEN
+  MATCH_MP_TAC REAL_LE_RMUL THEN REWRITE_TAC[NORM_POS_LE] THEN
+  ASM_SIMP_TAC[COMPONENT_LE_NORM; REAL_ABS_POS; REAL_LE_MUL2]);;
+
+let BILINEAR_BOUNDED_POS = prove
+ (`!h. bilinear h
+       ==> ?B. &0 < B /\ !x y. norm(h x y) <= B * norm(x) * norm(y)`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(X_CHOOSE_TAC `B:real` o MATCH_MP BILINEAR_BOUNDED) THEN
+  EXISTS_TAC `abs(B) + &1` THEN CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+  POP_ASSUM MP_TAC THEN REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN
+  MATCH_MP_TAC(REAL_ARITH `a <= b ==> x <= a ==> x <= b`) THEN
+  REPEAT(MATCH_MP_TAC REAL_LE_RMUL THEN
+         SIMP_TAC[NORM_POS_LE; REAL_LE_MUL]) THEN
+  REAL_ARITH_TAC);;
+
+let BILINEAR_VSUM_PARTIAL_SUC = prove
+ (`!f g h:real^M->real^N->real^P m n.
+        bilinear h
+        ==> vsum (m..n) (\k. h (f k) (g(k + 1) - g(k))) =
+                if m <= n then h (f(n + 1)) (g(n + 1)) - h (f m) (g m) -
+                               vsum (m..n) (\k. h (f(k + 1) - f(k)) (g(k + 1)))
+                else vec 0`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN REPEAT GEN_TAC THEN DISCH_TAC THEN
+  GEN_TAC THEN INDUCT_TAC THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[VSUM_TRIV_NUMSEG; GSYM NOT_LE] THEN
+  ASM_REWRITE_TAC[VSUM_CLAUSES_NUMSEG] THENL
+   [COND_CASES_TAC THEN ASM_SIMP_TAC[ARITH] THENL
+     [ASM_SIMP_TAC[BILINEAR_RSUB; BILINEAR_LSUB] THEN VECTOR_ARITH_TAC;
+      ASM_ARITH_TAC];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LE]) THEN
+  DISCH_THEN(DISJ_CASES_THEN2 SUBST_ALL_TAC ASSUME_TAC) THEN
+  ASM_SIMP_TAC[GSYM NOT_LT; VSUM_TRIV_NUMSEG; ARITH_RULE `n < SUC n`] THEN
+  ASM_SIMP_TAC[GSYM ADD1; ADD_CLAUSES] THEN
+  ASM_SIMP_TAC[BILINEAR_RSUB; BILINEAR_LSUB] THEN VECTOR_ARITH_TAC);;
+
+let BILINEAR_VSUM_PARTIAL_PRE = prove
+ (`!f g h:real^M->real^N->real^P m n.
+        bilinear h
+        ==> vsum (m..n) (\k. h (f k) (g(k) - g(k - 1))) =
+                if m <= n then h (f(n + 1)) (g(n)) - h (f m) (g(m - 1)) -
+                               vsum (m..n) (\k. h (f(k + 1) - f(k)) (g(k)))
+                else vec 0`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o ISPECL [`f:num->real^M`; `\k. (g:num->real^N)(k - 1)`;
+                 `m:num`; `n:num`] o MATCH_MP BILINEAR_VSUM_PARTIAL_SUC) THEN
+   REWRITE_TAC[ADD_SUB] THEN DISCH_THEN SUBST1_TAC THEN
+  COND_CASES_TAC THEN REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Adjoints.                                                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let adjoint = new_definition
+ `adjoint(f:real^M->real^N) = @f'. !x y. f(x) dot y = x dot f'(y)`;;
+
+let ADJOINT_WORKS = prove
+ (`!f:real^M->real^N. linear f ==> !x y. f(x) dot y = x dot (adjoint f)(y)`,
+  GEN_TAC THEN DISCH_TAC THEN SIMP_TAC[adjoint] THEN CONV_TAC SELECT_CONV THEN
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN ONCE_REWRITE_TAC[GSYM SKOLEM_THM] THEN
+  X_GEN_TAC `y:real^N` THEN
+  EXISTS_TAC `(lambda i. (f:real^M->real^N) (basis i) dot y):real^M` THEN
+  X_GEN_TAC `x:real^M` THEN
+  GEN_REWRITE_TAC (funpow 2 LAND_CONV o RAND_CONV) [GSYM BASIS_EXPANSION] THEN
+  ASM_SIMP_TAC[LINEAR_VSUM; FINITE_NUMSEG] THEN
+  SIMP_TAC[dot; LAMBDA_BETA; VSUM_COMPONENT; GSYM SUM_LMUL; GSYM SUM_RMUL] THEN
+  GEN_REWRITE_TAC RAND_CONV [SUM_SWAP_NUMSEG] THEN
+  ASM_SIMP_TAC[o_THM; VECTOR_MUL_COMPONENT; LINEAR_CMUL; REAL_MUL_ASSOC]);;
+
+let ADJOINT_LINEAR = prove
+ (`!f:real^M->real^N. linear f ==> linear(adjoint f)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[linear; GSYM VECTOR_EQ_LDOT] THEN
+  ASM_SIMP_TAC[DOT_RMUL; DOT_RADD; GSYM ADJOINT_WORKS]);;
+
+let ADJOINT_CLAUSES = prove
+ (`!f:real^M->real^N.
+     linear f ==> (!x y. x dot (adjoint f)(y) = f(x) dot y) /\
+                  (!x y. (adjoint f)(y) dot x = y dot f(x))`,
+  MESON_TAC[ADJOINT_WORKS; DOT_SYM]);;
+
+let ADJOINT_ADJOINT = prove
+ (`!f:real^M->real^N. linear f ==> adjoint(adjoint f) = f`,
+  SIMP_TAC[FUN_EQ_THM; GSYM VECTOR_EQ_LDOT; ADJOINT_CLAUSES; ADJOINT_LINEAR]);;
+
+let ADJOINT_UNIQUE = prove
+ (`!f f'. linear f /\ (!x y. f'(x) dot y = x dot f(y))
+          ==> f' = adjoint f`,
+  SIMP_TAC[FUN_EQ_THM; GSYM VECTOR_EQ_RDOT; ADJOINT_CLAUSES]);;
+
+let ADJOINT_COMPOSE = prove
+ (`!f g:real^N->real^N.
+        linear f /\ linear g ==> adjoint(f o g) = adjoint g o adjoint f`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC ADJOINT_UNIQUE THEN
+  ASM_SIMP_TAC[LINEAR_COMPOSE; o_THM; ADJOINT_CLAUSES]);;
+
+let SELF_ADJOINT_COMPOSE = prove
+ (`!f g:real^N->real^N.
+        linear f /\ linear g /\ adjoint f = f /\ adjoint g = g
+        ==> (adjoint(f o g) = f o g <=> f o g = g o f)`,
+  SIMP_TAC[ADJOINT_COMPOSE] THEN MESON_TAC[]);;
+
+let SELF_ADJOINT_ORTHOGONAL_EIGENVECTORS = prove
+ (`!f:real^N->real^N v w a b.
+        linear f /\ adjoint f = f /\ f v = a % v /\ f w = b % w /\ ~(a = b)
+        ==> orthogonal v w`,
+  REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o SPECL [`v:real^N`; `w:real^N`] o
+        MATCH_MP ADJOINT_WORKS) THEN
+  ASM_REWRITE_TAC[DOT_LMUL; DOT_RMUL; orthogonal; REAL_EQ_MUL_RCANCEL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Matrix notation. NB: an MxN matrix is of type real^N^M, not real^M^N.     *)
+(* We could define a special type if we're going to use them a lot.          *)
+(* ------------------------------------------------------------------------- *)
+
+overload_interface ("--",`(matrix_neg):real^N^M->real^N^M`);;
+overload_interface ("+",`(matrix_add):real^N^M->real^N^M->real^N^M`);;
+overload_interface ("-",`(matrix_sub):real^N^M->real^N^M->real^N^M`);;
+
+make_overloadable "**" `:A->B->C`;;
+
+overload_interface ("**",`(matrix_mul):real^N^M->real^P^N->real^P^M`);;
+overload_interface ("**",`(matrix_vector_mul):real^N^M->real^N->real^M`);;
+overload_interface ("**",`(vector_matrix_mul):real^M->real^N^M->real^N`);;
+
+parse_as_infix("%%",(21,"right"));;
+
+prioritize_real();;
+
+let matrix_cmul = new_definition
+  `((%%):real->real^N^M->real^N^M) c A = lambda i j. c * A$i$j`;;
+
+let matrix_neg = new_definition
+  `!A:real^N^M. --A = lambda i j. --(A$i$j)`;;
+
+let matrix_add = new_definition
+  `!A:real^N^M B:real^N^M. A + B = lambda i j. A$i$j + B$i$j`;;
+
+let matrix_sub = new_definition
+  `!A:real^N^M B:real^N^M. A - B = lambda i j. A$i$j - B$i$j`;;
+
+let matrix_mul = new_definition
+  `!A:real^N^M B:real^P^N.
+        A ** B =
+          lambda i j. sum(1..dimindex(:N)) (\k. A$i$k * B$k$j)`;;
+
+let matrix_vector_mul = new_definition
+  `!A:real^N^M x:real^N.
+        A ** x = lambda i. sum(1..dimindex(:N)) (\j. A$i$j * x$j)`;;
+
+let vector_matrix_mul = new_definition
+  `!A:real^N^M x:real^M.
+        x ** A = lambda j. sum(1..dimindex(:M)) (\i. A$i$j * x$i)`;;
+
+let mat = new_definition
+  `(mat:num->real^N^M) k = lambda i j. if i = j then &k else &0`;;
+
+let transp = new_definition
+  `(transp:real^N^M->real^M^N) A = lambda i j. A$j$i`;;
+
+let row = new_definition
+ `(row:num->real^N^M->real^N) i A = lambda j. A$i$j`;;
+
+let column = new_definition
+ `(column:num->real^N^M->real^M) j A = lambda i. A$i$j`;;
+
+let rows = new_definition
+ `rows(A:real^N^M) = { row i A | 1 <= i /\ i <= dimindex(:M)}`;;
+
+let columns = new_definition
+ `columns(A:real^N^M) = { column i A | 1 <= i /\ i <= dimindex(:N)}`;;
+
+let MATRIX_CMUL_COMPONENT = prove
+ (`!c A:real^N^M i. (c %% A)$i$j = c * A$i$j`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:M) /\ !A:real^N^M. A$i = A$k`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  SUBGOAL_THEN `?l. 1 <= l /\ l <= dimindex(:N) /\ !z:real^N. z$j = z$l`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  ASM_SIMP_TAC[matrix_cmul; CART_EQ; LAMBDA_BETA]);;
+
+let MATRIX_ADD_COMPONENT = prove
+ (`!A B:real^N^M i j. (A + B)$i$j = A$i$j + B$i$j`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:M) /\ !A:real^N^M. A$i = A$k`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  SUBGOAL_THEN `?l. 1 <= l /\ l <= dimindex(:N) /\ !z:real^N. z$j = z$l`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  ASM_SIMP_TAC[matrix_add; LAMBDA_BETA]);;
+
+let MATRIX_SUB_COMPONENT = prove
+ (`!A B:real^N^M i j. (A - B)$i$j = A$i$j - B$i$j`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:M) /\ !A:real^N^M. A$i = A$k`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  SUBGOAL_THEN `?l. 1 <= l /\ l <= dimindex(:N) /\ !z:real^N. z$j = z$l`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  ASM_SIMP_TAC[matrix_sub; LAMBDA_BETA]);;
+
+let MATRIX_NEG_COMPONENT = prove
+ (`!A:real^N^M i j. (--A)$i$j = --(A$i$j)`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:M) /\ !A:real^N^M. A$i = A$k`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  SUBGOAL_THEN `?l. 1 <= l /\ l <= dimindex(:N) /\ !z:real^N. z$j = z$l`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  ASM_SIMP_TAC[matrix_neg; LAMBDA_BETA]);;
+
+let TRANSP_COMPONENT = prove
+ (`!A:real^N^M i j. (transp A)$i$j = A$j$i`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:N) /\
+                    (!A:real^M^N. A$i = A$k) /\ (!z:real^N. z$i = z$k)`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE_2]; ALL_TAC] THEN
+  SUBGOAL_THEN `?l. 1 <= l /\ l <= dimindex(:M) /\
+                    (!A:real^N^M. A$j = A$l) /\ (!z:real^M. z$j = z$l)`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE_2]; ALL_TAC] THEN
+  ASM_SIMP_TAC[transp; LAMBDA_BETA]);;
+
+let MAT_COMPONENT = prove
+ (`!n i j.
+        1 <= i /\ i <= dimindex(:M) /\
+        1 <= j /\ j <= dimindex(:N)
+        ==> (mat n:real^N^M)$i$j = if i = j then &n else &0`,
+  SIMP_TAC[mat; LAMBDA_BETA]);;
+
+let MAT_0_COMPONENT = prove
+ (`!i j. (mat 0:real^N^M)$i$j = &0`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?k. 1 <= k /\ k <= dimindex(:M) /\ !A:real^N^M. A$i = A$k`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  SUBGOAL_THEN `?l. 1 <= l /\ l <= dimindex(:N) /\ !z:real^N. z$j = z$l`
+  CHOOSE_TAC THENL [REWRITE_TAC[FINITE_INDEX_INRANGE]; ALL_TAC] THEN
+  ASM_SIMP_TAC[mat; COND_ID; LAMBDA_BETA]);;
+
+let MATRIX_CMUL_ASSOC = prove
+ (`!a b X:real^M^N. a %% (b %% X) = (a * b) %% X`,
+  SIMP_TAC[CART_EQ; matrix_cmul; LAMBDA_BETA; REAL_MUL_ASSOC]);;
+
+let MATRIX_CMUL_LID = prove
+ (`!X:real^M^N. &1 %% X = X`,
+  SIMP_TAC[CART_EQ; matrix_cmul; LAMBDA_BETA; REAL_MUL_LID]);;
+
+let MATRIX_ADD_SYM = prove
+ (`!A:real^N^M B. A + B = B + A`,
+  SIMP_TAC[matrix_add; CART_EQ; LAMBDA_BETA; REAL_ADD_AC]);;
+
+let MATRIX_ADD_ASSOC = prove
+ (`!A:real^N^M B C. A + (B + C) = (A + B) + C`,
+  SIMP_TAC[matrix_add; CART_EQ; LAMBDA_BETA; REAL_ADD_AC]);;
+
+let MATRIX_ADD_LID = prove
+ (`!A. mat 0 + A = A`,
+  SIMP_TAC[matrix_add; mat; COND_ID; CART_EQ; LAMBDA_BETA; REAL_ADD_LID]);;
+
+let MATRIX_ADD_RID = prove
+ (`!A. A + mat 0 = A`,
+  SIMP_TAC[matrix_add; mat; COND_ID; CART_EQ; LAMBDA_BETA; REAL_ADD_RID]);;
+
+let MATRIX_ADD_LNEG = prove
+ (`!A. --A + A = mat 0`,
+  SIMP_TAC[matrix_neg; matrix_add; mat; COND_ID;
+           CART_EQ; LAMBDA_BETA; REAL_ADD_LINV]);;
+
+let MATRIX_ADD_RNEG = prove
+ (`!A. A + --A = mat 0`,
+  SIMP_TAC[matrix_neg; matrix_add; mat; COND_ID;
+           CART_EQ; LAMBDA_BETA; REAL_ADD_RINV]);;
+
+let MATRIX_SUB = prove
+ (`!A:real^N^M B. A - B = A + --B`,
+  SIMP_TAC[matrix_neg; matrix_add; matrix_sub; CART_EQ; LAMBDA_BETA;
+           real_sub]);;
+
+let MATRIX_SUB_REFL = prove
+ (`!A. A - A = mat 0`,
+  REWRITE_TAC[MATRIX_SUB; MATRIX_ADD_RNEG]);;
+
+let MATRIX_ADD_LDISTRIB = prove
+ (`!A:real^N^M B:real^P^N C. A ** (B + C) = A ** B + A ** C`,
+  SIMP_TAC[matrix_mul; matrix_add; CART_EQ; LAMBDA_BETA;
+           GSYM SUM_ADD_NUMSEG] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ_NUMSEG THEN
+  ASM_SIMP_TAC[LAMBDA_BETA; REAL_ADD_LDISTRIB]);;
+
+let MATRIX_MUL_LID = prove
+ (`!A:real^N^M. mat 1 ** A = A`,
+  REWRITE_TAC[matrix_mul;
+   GEN_REWRITE_RULE (RAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ]
+    (SPEC_ALL mat)] THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN REWRITE_TAC[COND_RATOR; COND_RAND] THEN
+  SIMP_TAC[SUM_DELTA; REAL_MUL_LZERO; IN_NUMSEG; REAL_MUL_LID]);;
+
+let MATRIX_MUL_RID = prove
+ (`!A:real^N^M. A ** mat 1 = A`,
+  REWRITE_TAC[matrix_mul; mat] THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN REWRITE_TAC[COND_RATOR; COND_RAND] THEN
+  SIMP_TAC[SUM_DELTA; REAL_MUL_RZERO; IN_NUMSEG; REAL_MUL_RID]);;
+
+let MATRIX_MUL_ASSOC = prove
+ (`!A:real^N^M B:real^P^N C:real^Q^P. A ** B ** C = (A ** B) ** C`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[matrix_mul; CART_EQ; LAMBDA_BETA; GSYM SUM_LMUL; GSYM SUM_RMUL] THEN
+  REWRITE_TAC[REAL_MUL_ASSOC] THEN REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [SUM_SWAP_NUMSEG] THEN REWRITE_TAC[]);;
+
+let MATRIX_MUL_LZERO = prove
+ (`!A. (mat 0:real^N^M) ** (A:real^P^N) = mat 0`,
+  SIMP_TAC[matrix_mul; mat; CART_EQ; LAMBDA_BETA; COND_ID; REAL_MUL_LZERO] THEN
+  REWRITE_TAC[SUM_0]);;
+
+let MATRIX_MUL_RZERO = prove
+ (`!A. (A:real^N^M) ** (mat 0:real^P^N) = mat 0`,
+  SIMP_TAC[matrix_mul; mat; CART_EQ; LAMBDA_BETA; COND_ID; REAL_MUL_RZERO] THEN
+  REWRITE_TAC[SUM_0]);;
+
+let MATRIX_ADD_RDISTRIB = prove
+ (`!A:real^N^M B C:real^P^N. (A + B) ** C = A ** C + B ** C`,
+  SIMP_TAC[matrix_mul; matrix_add; CART_EQ; LAMBDA_BETA] THEN
+  REWRITE_TAC[REAL_ADD_RDISTRIB; SUM_ADD_NUMSEG]);;
+
+let MATRIX_SUB_LDISTRIB = prove
+ (`!A:real^N^M B C:real^P^N. A ** (B - C) = A ** B - A ** C`,
+  SIMP_TAC[matrix_mul; matrix_sub; CART_EQ; LAMBDA_BETA] THEN
+  REWRITE_TAC[REAL_SUB_LDISTRIB; SUM_SUB_NUMSEG]);;
+
+let MATRIX_SUB_RDISTRIB = prove
+ (`!A:real^N^M B C:real^P^N. (A - B) ** C = A ** C - B ** C`,
+  SIMP_TAC[matrix_mul; matrix_sub; CART_EQ; LAMBDA_BETA] THEN
+  REWRITE_TAC[REAL_SUB_RDISTRIB; SUM_SUB_NUMSEG]);;
+
+let MATRIX_MUL_LMUL = prove
+ (`!A:real^N^M B:real^P^N c. (c %% A) ** B = c %% (A ** B)`,
+  SIMP_TAC[matrix_mul; matrix_cmul; CART_EQ; LAMBDA_BETA] THEN
+  REWRITE_TAC[GSYM REAL_MUL_ASSOC; SUM_LMUL]);;
+
+let MATRIX_MUL_RMUL = prove
+ (`!A:real^N^M B:real^P^N c. A ** (c %% B) = c %% (A ** B)`,
+  SIMP_TAC[matrix_mul; matrix_cmul; CART_EQ; LAMBDA_BETA] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `A * c * B:real = c * A * B`] THEN
+  REWRITE_TAC[SUM_LMUL]);;
+
+let MATRIX_CMUL_ADD_LDISTRIB = prove
+ (`!A:real^N^M B c. c %% (A + B) = c %% A + c %% B`,
+  SIMP_TAC[matrix_cmul; matrix_add; CART_EQ; LAMBDA_BETA] THEN
+  REWRITE_TAC[REAL_ADD_LDISTRIB]);;
+
+let MATRIX_CMUL_SUB_LDISTRIB = prove
+ (`!A:real^N^M B c. c %% (A - B) = c %% A - c %% B`,
+  SIMP_TAC[matrix_cmul; matrix_sub; CART_EQ; LAMBDA_BETA] THEN
+  REWRITE_TAC[REAL_SUB_LDISTRIB]);;
+
+let MATRIX_CMUL_ADD_RDISTRIB = prove
+ (`!A:real^N^M b c. (b + c) %% A = b %% A + c %% A`,
+  SIMP_TAC[matrix_cmul; matrix_add; CART_EQ; LAMBDA_BETA] THEN
+  REWRITE_TAC[REAL_ADD_RDISTRIB]);;
+
+let MATRIX_CMUL_SUB_RDISTRIB = prove
+ (`!A:real^N^M b c. (b - c) %% A = b %% A - c %% A`,
+  SIMP_TAC[matrix_cmul; matrix_sub; CART_EQ; LAMBDA_BETA] THEN
+  REWRITE_TAC[REAL_SUB_RDISTRIB]);;
+
+let MATRIX_CMUL_RZERO = prove
+ (`!c. c %% mat 0 = mat 0`,
+  SIMP_TAC[matrix_cmul; mat; CART_EQ; LAMBDA_BETA; COND_ID; REAL_MUL_RZERO]);;
+
+let MATRIX_CMUL_LZERO = prove
+ (`!A. &0 %% A = mat 0`,
+  SIMP_TAC[matrix_cmul; mat; CART_EQ; LAMBDA_BETA; COND_ID; REAL_MUL_LZERO]);;
+
+let MATRIX_NEG_MINUS1 = prove
+ (`!A:real^N^M. --A = --(&1) %% A`,
+  REWRITE_TAC[matrix_cmul; matrix_neg; CART_EQ; LAMBDA_BETA] THEN
+  REWRITE_TAC[GSYM REAL_NEG_MINUS1]);;
+
+let MATRIX_ADD_AC = prove
+ (`(A:real^N^M) + B = B + A /\
+   (A + B) + C = A + (B + C) /\
+   A + (B + C) = B + (A + C)`,
+  MESON_TAC[MATRIX_ADD_ASSOC; MATRIX_ADD_SYM]);;
+
+let MATRIX_NEG_ADD = prove
+ (`!A B:real^N^M. --(A + B) = --A + --B`,
+  SIMP_TAC[matrix_neg; matrix_add; CART_EQ; LAMBDA_BETA; REAL_NEG_ADD]);;
+
+let MATRIX_NEG_SUB = prove
+ (`!A B:real^N^M. --(A - B) = B - A`,
+  SIMP_TAC[matrix_neg; matrix_sub; CART_EQ; LAMBDA_BETA; REAL_NEG_SUB]);;
+
+let MATRIX_NEG_0 = prove
+ (`--(mat 0) = mat 0`,
+  SIMP_TAC[CART_EQ; mat; matrix_neg; LAMBDA_BETA; REAL_NEG_0; COND_ID]);;
+
+let MATRIX_SUB_RZERO = prove
+ (`!A:real^N^M. A - mat 0 = A`,
+  SIMP_TAC[CART_EQ; mat; matrix_sub; LAMBDA_BETA; REAL_SUB_RZERO; COND_ID]);;
+
+let MATRIX_SUB_LZERO = prove
+ (`!A:real^N^M. mat 0 - A = --A`,
+  SIMP_TAC[CART_EQ; mat; matrix_sub; matrix_neg;
+           LAMBDA_BETA; REAL_SUB_LZERO; COND_ID]);;
+
+let MATRIX_NEG_EQ_0 = prove
+ (`!A:real^N^M. --A = mat 0 <=> A = mat 0`,
+  SIMP_TAC[CART_EQ; matrix_neg; mat; LAMBDA_BETA; REAL_NEG_EQ_0; COND_ID]);;
+
+let MATRIX_VECTOR_MUL_ASSOC = prove
+ (`!A:real^N^M B:real^P^N x:real^P. A ** B ** x = (A ** B) ** x`,
+  REPEAT GEN_TAC THEN
+  SIMP_TAC[matrix_mul; matrix_vector_mul;
+           CART_EQ; LAMBDA_BETA; GSYM SUM_LMUL; GSYM SUM_RMUL] THEN
+  REWRITE_TAC[REAL_MUL_ASSOC] THEN REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [SUM_SWAP_NUMSEG] THEN REWRITE_TAC[]);;
+
+let MATRIX_VECTOR_MUL_LID = prove
+ (`!x:real^N. mat 1 ** x = x`,
+  REWRITE_TAC[matrix_vector_mul;
+   GEN_REWRITE_RULE (RAND_CONV o ONCE_DEPTH_CONV) [EQ_SYM_EQ]
+    (SPEC_ALL mat)] THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN REWRITE_TAC[COND_RATOR; COND_RAND] THEN
+  SIMP_TAC[SUM_DELTA; REAL_MUL_LZERO; IN_NUMSEG; REAL_MUL_LID]);;
+
+let MATRIX_VECTOR_MUL_LZERO = prove
+ (`!x:real^N. mat 0 ** x = vec 0`,
+  SIMP_TAC[mat; matrix_vector_mul; CART_EQ; VEC_COMPONENT; LAMBDA_BETA;
+           COND_ID; REAL_MUL_LZERO; SUM_0]);;
+
+let MATRIX_VECTOR_MUL_RZERO = prove
+ (`!A:real^M^N. A ** vec 0 = vec 0`,
+  SIMP_TAC[mat; matrix_vector_mul; CART_EQ; VEC_COMPONENT; LAMBDA_BETA;
+           COND_ID; REAL_MUL_RZERO; SUM_0]);;
+
+let MATRIX_VECTOR_MUL_ADD_LDISTRIB = prove
+ (`!A:real^M^N x:real^M y. A ** (x + y) = A ** x + A ** y`,
+  SIMP_TAC[CART_EQ; matrix_vector_mul; VECTOR_ADD_COMPONENT; LAMBDA_BETA;
+           SUM_ADD_NUMSEG; REAL_ADD_LDISTRIB]);;
+
+let MATRIX_VECTOR_MUL_SUB_LDISTRIB = prove
+ (`!A:real^M^N x:real^M y. A ** (x - y) = A ** x - A ** y`,
+  SIMP_TAC[CART_EQ; matrix_vector_mul; VECTOR_SUB_COMPONENT; LAMBDA_BETA;
+           SUM_SUB_NUMSEG; REAL_SUB_LDISTRIB]);;
+
+let MATRIX_VECTOR_MUL_ADD_RDISTRIB = prove
+ (`!A:real^M^N B x. (A + B) ** x = (A ** x) + (B ** x)`,
+  SIMP_TAC[CART_EQ; matrix_vector_mul; matrix_add; LAMBDA_BETA;
+           VECTOR_ADD_COMPONENT; REAL_ADD_RDISTRIB; SUM_ADD_NUMSEG]);;
+
+let MATRIX_VECTOR_MUL_SUB_RDISTRIB = prove
+ (`!A:real^M^N B x. (A - B) ** x = (A ** x) - (B ** x)`,
+  SIMP_TAC[CART_EQ; matrix_vector_mul; matrix_sub; LAMBDA_BETA;
+           VECTOR_SUB_COMPONENT; REAL_SUB_RDISTRIB; SUM_SUB_NUMSEG]);;
+
+let MATRIX_VECTOR_MUL_RMUL = prove
+ (`!A:real^M^N x:real^M c. A ** (c % x) = c % (A ** x)`,
+  SIMP_TAC[CART_EQ; VECTOR_MUL_COMPONENT; matrix_vector_mul; LAMBDA_BETA] THEN
+  REWRITE_TAC[GSYM SUM_LMUL] THEN REWRITE_TAC[REAL_MUL_AC]);;
+
+let MATRIX_MUL_LNEG = prove
+ (`!A:real^N^M B:real^P^N. (--A) ** B = --(A ** B)`,
+  REWRITE_TAC[MATRIX_NEG_MINUS1; MATRIX_MUL_LMUL]);;
+
+let MATRIX_MUL_RNEG = prove
+ (`!A:real^N^M B:real^P^N. A ** --B = --(A ** B)`,
+  REWRITE_TAC[MATRIX_NEG_MINUS1; MATRIX_MUL_RMUL]);;
+
+let MATRIX_NEG_NEG = prove
+ (`!A:real^N^N. --(--A) = A`,
+  SIMP_TAC[CART_EQ; MATRIX_NEG_COMPONENT; REAL_NEG_NEG]);;
+
+let MATRIX_TRANSP_MUL = prove
+ (`!A B. transp(A ** B) = transp(B) ** transp(A)`,
+  SIMP_TAC[matrix_mul; transp; CART_EQ; LAMBDA_BETA] THEN
+  REWRITE_TAC[REAL_MUL_AC]);;
+
+let SYMMETRIC_MATRIX_MUL = prove
+ (`!A B:real^N^N.
+        transp(A) = A /\ transp(B) = B
+        ==> (transp(A ** B) = A ** B <=> A ** B = B ** A)`,
+  SIMP_TAC[MATRIX_TRANSP_MUL] THEN MESON_TAC[]);;
+
+let MATRIX_EQ = prove
+ (`!A:real^N^M B. (A = B) = !x:real^N. A ** x = B ** x`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o GEN `i:num` o SPEC `(basis i):real^N`) THEN
+  SIMP_TAC[CART_EQ; matrix_vector_mul; LAMBDA_BETA; basis] THEN
+  SIMP_TAC[SUM_DELTA; COND_RAND; REAL_MUL_RZERO] THEN
+  REWRITE_TAC[TAUT `(if p then b else T) <=> p ==> b`] THEN
+  SIMP_TAC[REAL_MUL_RID; IN_NUMSEG]);;
+
+let MATRIX_VECTOR_MUL_COMPONENT = prove
+ (`!A:real^N^M x k.
+    1 <= k /\ k <= dimindex(:M) ==> ((A ** x)$k = (A$k) dot x)`,
+  SIMP_TAC[matrix_vector_mul; LAMBDA_BETA; dot]);;
+
+let DOT_LMUL_MATRIX = prove
+ (`!A:real^N^M x:real^M y:real^N. (x ** A) dot y = x dot (A ** y)`,
+  SIMP_TAC[dot; matrix_vector_mul; vector_matrix_mul; dot; LAMBDA_BETA] THEN
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM SUM_LMUL] THEN
+  REWRITE_TAC[GSYM SUM_RMUL] THEN
+  GEN_REWRITE_TAC RAND_CONV [SUM_SWAP_NUMSEG] THEN REWRITE_TAC[REAL_MUL_AC]);;
+
+let TRANSP_MATRIX_CMUL = prove
+ (`!A:real^M^N c. transp(c %% A) = c %% transp A`,
+  SIMP_TAC[CART_EQ; transp; MATRIX_CMUL_COMPONENT; LAMBDA_BETA]);;
+
+let TRANSP_MATRIX_ADD = prove
+ (`!A B:real^N^M. transp(A + B) = transp A + transp B`,
+  SIMP_TAC[CART_EQ; transp; LAMBDA_BETA; matrix_add]);;
+
+let TRANSP_MATRIX_SUB = prove
+ (`!A B:real^N^M. transp(A - B) = transp A - transp B`,
+  SIMP_TAC[CART_EQ; transp; LAMBDA_BETA; matrix_sub]);;
+
+let TRANSP_MATRIX_NEG = prove
+ (`!A:real^N^M. transp(--A) = --(transp A)`,
+  SIMP_TAC[CART_EQ; transp; LAMBDA_BETA; matrix_neg]);;
+
+let TRANSP_MAT = prove
+ (`!n. transp(mat n) = mat n`,
+  SIMP_TAC[transp; mat; LAMBDA_BETA; CART_EQ; EQ_SYM_EQ]);;
+
+let TRANSP_TRANSP = prove
+ (`!A:real^N^M. transp(transp A) = A`,
+  SIMP_TAC[CART_EQ; transp; LAMBDA_BETA]);;
+
+let SYMMETRIX_MATRIX_CONJUGATE = prove
+ (`!A B:real^N^N. transp B = B
+                  ==> transp(transp A ** B ** A) = transp A ** B ** A`,
+  SIMP_TAC[MATRIX_TRANSP_MUL; TRANSP_TRANSP; MATRIX_MUL_ASSOC]);;
+
+let TRANSP_EQ = prove
+ (`!A B:real^M^N. transp A = transp B <=> A = B`,
+  MESON_TAC[TRANSP_TRANSP]);;
+
+let ROW_TRANSP = prove
+ (`!A:real^N^M i.
+        1 <= i /\ i <= dimindex(:N) ==> row i (transp A) = column i A`,
+  SIMP_TAC[row; column; transp; CART_EQ; LAMBDA_BETA]);;
+
+let COLUMN_TRANSP = prove
+ (`!A:real^N^M i.
+        1 <= i /\ i <= dimindex(:M) ==> column i (transp A) = row i A`,
+  SIMP_TAC[row; column; transp; CART_EQ; LAMBDA_BETA]);;
+
+let ROWS_TRANSP = prove
+ (`!A:real^N^M. rows(transp A) = columns A`,
+  REWRITE_TAC[rows; columns; EXTENSION; IN_ELIM_THM] THEN
+  MESON_TAC[ROW_TRANSP]);;
+
+let COLUMNS_TRANSP = prove
+ (`!A:real^N^M. columns(transp A) = rows A`,
+  MESON_TAC[TRANSP_TRANSP; ROWS_TRANSP]);;
+
+let VECTOR_MATRIX_MUL_TRANSP = prove
+ (`!A:real^M^N x:real^N. x ** A = transp A ** x`,
+  REWRITE_TAC[matrix_vector_mul; vector_matrix_mul; transp] THEN
+  SIMP_TAC[LAMBDA_BETA; CART_EQ]);;
+
+let MATRIX_VECTOR_MUL_TRANSP = prove
+ (`!A:real^M^N x:real^M. A ** x = x ** transp A`,
+  REWRITE_TAC[VECTOR_MATRIX_MUL_TRANSP; TRANSP_TRANSP]);;
+
+let FINITE_ROWS = prove
+ (`!A:real^N^M. FINITE(rows A)`,
+  REWRITE_TAC[rows] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+  SIMP_TAC[GSYM numseg; FINITE_IMAGE; FINITE_NUMSEG]);;
+
+let FINITE_COLUMNS = prove
+ (`!A:real^N^M. FINITE(columns A)`,
+  REWRITE_TAC[columns] THEN ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+  SIMP_TAC[GSYM numseg; FINITE_IMAGE; FINITE_NUMSEG]);;
+
+let MATRIX_EQUAL_ROWS = prove
+ (`!A B:real^N^M.
+        A = B <=> !i. 1 <= i /\ i <= dimindex(:M) ==> row i A = row i B`,
+  SIMP_TAC[row; CART_EQ; LAMBDA_BETA]);;
+
+let MATRIX_EQUAL_COLUMNS = prove
+ (`!A B:real^N^M.
+        A = B <=> !i. 1 <= i /\ i <= dimindex(:N) ==> column i A = column i B`,
+  SIMP_TAC[column; CART_EQ; LAMBDA_BETA] THEN MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Two sometimes fruitful ways of looking at matrix-vector multiplication.   *)
+(* ------------------------------------------------------------------------- *)
+
+let MATRIX_MUL_DOT = prove
+ (`!A:real^N^M x. A ** x = lambda i. A$i dot x`,
+  REWRITE_TAC[matrix_vector_mul; dot] THEN SIMP_TAC[CART_EQ; LAMBDA_BETA]);;
+
+let MATRIX_MUL_VSUM = prove
+ (`!A:real^N^M x. A ** x = vsum(1..dimindex(:N)) (\i. x$i % column i A)`,
+  SIMP_TAC[matrix_vector_mul; CART_EQ; VSUM_COMPONENT; LAMBDA_BETA;
+           VECTOR_MUL_COMPONENT; column; REAL_MUL_AC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Slightly gruesome lemmas: better to define sums over vectors really...    *)
+(* ------------------------------------------------------------------------- *)
+
+let VECTOR_COMPONENTWISE = prove
+ (`!x:real^N.
+    x = lambda j. sum(1..dimindex(:N))
+                     (\i. x$i * (basis i :real^N)$j)`,
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; basis] THEN
+  ONCE_REWRITE_TAC[ARITH_RULE `(m:num = n) <=> (n = m)`] THEN
+  SIMP_TAC[COND_RAND; REAL_MUL_RZERO; SUM_DELTA; IN_NUMSEG] THEN
+  REWRITE_TAC[REAL_MUL_RID; COND_ID]);;
+
+let LINEAR_COMPONENTWISE_EXPANSION = prove
+ (`!f:real^M->real^N.
+      linear(f)
+      ==> !x j. 1 <= j /\ j <= dimindex(:N)
+                ==> (f x $j =
+                     sum(1..dimindex(:M)) (\i. x$i * f(basis i)$j))`,
+  REWRITE_TAC[linear] THEN REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o RAND_CONV)
+   [VECTOR_COMPONENTWISE] THEN
+  SPEC_TAC(`dimindex(:M)`,`n:num`) THEN
+  INDUCT_TAC THEN REWRITE_TAC[SUM_CLAUSES_NUMSEG; ARITH] THENL
+   [REWRITE_TAC[GSYM vec] THEN
+    GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o RAND_CONV)
+     [GSYM VECTOR_MUL_LZERO] THEN
+    ASM_REWRITE_TAC[] THEN REWRITE_TAC[VECTOR_MUL_LZERO] THEN
+    ASM_SIMP_TAC[vec; LAMBDA_BETA];
+    REWRITE_TAC[ARITH_RULE `1 <= SUC n`] THEN
+    ASSUM_LIST(fun thl -> REWRITE_TAC(map GSYM thl)) THEN
+    SIMP_TAC[GSYM VECTOR_MUL_COMPONENT;
+             ASSUME `1 <= j`; ASSUME `j <= dimindex(:N)`] THEN
+    ASSUM_LIST(fun thl -> REWRITE_TAC(map GSYM thl)) THEN
+    SIMP_TAC[GSYM VECTOR_ADD_COMPONENT;
+             ASSUME `1 <= j`; ASSUME `j <= dimindex(:N)`] THEN
+    ASSUM_LIST(fun thl -> REWRITE_TAC(map GSYM thl)) THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
+    ASM_SIMP_TAC[CART_EQ; VECTOR_ADD_COMPONENT; LAMBDA_BETA] THEN
+    SIMP_TAC[VECTOR_MUL_COMPONENT]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Inverse matrices (not necessarily square, but it's vacuous otherwise).    *)
+(* ------------------------------------------------------------------------- *)
+
+let invertible = new_definition
+  `invertible(A:real^N^M) <=>
+        ?A':real^M^N. (A ** A' = mat 1) /\ (A' ** A = mat 1)`;;
+
+let matrix_inv = new_definition
+  `matrix_inv(A:real^N^M) =
+        @A':real^M^N. (A ** A' = mat 1) /\ (A' ** A = mat 1)`;;
+
+let MATRIX_INV = prove
+ (`!A:real^N^M.
+    invertible A ==> A ** matrix_inv A = mat 1 /\ matrix_inv A ** A = mat 1`,
+  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[matrix_inv; invertible] THEN
+  CONV_TAC SELECT_CONV THEN ASM_REWRITE_TAC[GSYM invertible]);;
+
+let MATRIX_INV_UNIQUE = prove
+ (`!A:real^N^M B. A ** B = mat 1 /\ B ** A = mat 1 ==> matrix_inv A = B`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPEC `A:real^N^M` MATRIX_INV) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[invertible]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o
+    AP_TERM `(( ** ):real^M^N->real^M^M->real^M^N) B` o CONJUNCT1) THEN
+  ASM_REWRITE_TAC[MATRIX_MUL_ASSOC; MATRIX_MUL_LID; MATRIX_MUL_RID]);;
+
+let INVERTIBLE_NEG = prove
+ (`!A:real^N^M. invertible(--A) <=> invertible A`,
+  REWRITE_TAC[invertible] THEN
+  MESON_TAC[MATRIX_MUL_LNEG; MATRIX_MUL_RNEG; MATRIX_NEG_NEG]);;
+
+let MATRIX_INV_I = prove
+ (`matrix_inv(mat 1:real^N^N) = mat 1`,
+  MATCH_MP_TAC MATRIX_INV_UNIQUE THEN
+  REWRITE_TAC[MATRIX_MUL_LID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Correspondence between matrices and linear operators.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let matrix = new_definition
+  `(matrix:(real^M->real^N)->real^M^N) f = lambda i j. f(basis j)$i`;;
+
+let MATRIX_VECTOR_MUL_LINEAR = prove
+ (`!A:real^N^M. linear(\x. A ** x)`,
+  REWRITE_TAC[linear; matrix_vector_mul] THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT;
+    VECTOR_MUL_COMPONENT] THEN
+  REWRITE_TAC[GSYM SUM_ADD_NUMSEG; GSYM SUM_LMUL; REAL_ADD_LDISTRIB] THEN
+  REWRITE_TAC[REAL_ADD_AC; REAL_MUL_AC]);;
+
+let MATRIX_WORKS = prove
+ (`!f:real^M->real^N. linear f ==> !x. matrix f ** x = f(x)`,
+  REWRITE_TAC[matrix; matrix_vector_mul] THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN GEN_TAC THEN DISCH_TAC THEN
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  ASM_SIMP_TAC[GSYM LINEAR_COMPONENTWISE_EXPANSION]);;
+
+let MATRIX_VECTOR_MUL = prove
+ (`!f:real^M->real^N. linear f ==> f = \x. matrix f ** x`,
+  SIMP_TAC[FUN_EQ_THM; MATRIX_WORKS]);;
+
+let MATRIX_OF_MATRIX_VECTOR_MUL = prove
+ (`!A:real^N^M. matrix(\x. A ** x) = A`,
+  SIMP_TAC[MATRIX_EQ; MATRIX_VECTOR_MUL_LINEAR; MATRIX_WORKS]);;
+
+let MATRIX_COMPOSE = prove
+ (`!f g. linear f /\ linear g ==> (matrix(g o f) = matrix g ** matrix f)`,
+  SIMP_TAC[MATRIX_EQ; MATRIX_WORKS; LINEAR_COMPOSE;
+           GSYM MATRIX_VECTOR_MUL_ASSOC; o_THM]);;
+
+let MATRIX_VECTOR_COLUMN = prove
+ (`!A:real^N^M x.
+        A ** x = vsum(1..dimindex(:N)) (\i. x$i % (transp A)$i)`,
+  REWRITE_TAC[matrix_vector_mul; transp] THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA; VSUM_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  REWRITE_TAC[REAL_MUL_AC]);;
+
+let MATRIX_MUL_COMPONENT = prove
+ (`!i. 1 <= i /\ i <= dimindex(:N)
+       ==> ((A:real^N^N) ** (B:real^N^N))$i = transp B ** A$i`,
+  SIMP_TAC[matrix_mul; LAMBDA_BETA; matrix_vector_mul; vector_matrix_mul;
+       transp; CART_EQ] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ_NUMSEG THEN
+  REWRITE_TAC[REAL_MUL_AC]);;
+
+let ADJOINT_MATRIX = prove
+ (`!A:real^N^M. adjoint(\x. A ** x) = (\x. transp A ** x)`,
+  GEN_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC ADJOINT_UNIQUE THEN
+  REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR] THEN REPEAT GEN_TAC THEN
+  SIMP_TAC[transp; dot; LAMBDA_BETA; matrix_vector_mul;
+           GSYM SUM_LMUL; GSYM SUM_RMUL] THEN
+  GEN_REWRITE_TAC LAND_CONV [SUM_SWAP_NUMSEG] THEN REWRITE_TAC[REAL_MUL_AC]);;
+
+let MATRIX_ADJOINT = prove
+ (`!f. linear f ==> matrix(adjoint f) = transp(matrix f)`,
+  GEN_TAC THEN DISCH_THEN
+   (fun th -> GEN_REWRITE_TAC (LAND_CONV o funpow 2 RAND_CONV)
+                [MATCH_MP MATRIX_VECTOR_MUL th]) THEN
+  REWRITE_TAC[ADJOINT_MATRIX; MATRIX_OF_MATRIX_VECTOR_MUL]);;
+
+let MATRIX_ID = prove
+ (`matrix(\x. x) = mat 1`,
+  SIMP_TAC[MATRIX_EQ; LINEAR_ID; MATRIX_WORKS; MATRIX_VECTOR_MUL_LID]);;
+
+let MATRIX_I = prove
+ (`matrix I = mat 1`,
+  REWRITE_TAC[I_DEF; MATRIX_ID]);;
+
+let LINEAR_EQ_MATRIX = prove
+ (`!f g. linear f /\ linear g /\ matrix f = matrix g ==> f = g`,
+  REPEAT STRIP_TAC THEN
+  REPEAT(FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP MATRIX_VECTOR_MUL)) THEN
+  ASM_REWRITE_TAC[]);;
+
+let MATRIX_SELF_ADJOINT = prove
+ (`!f. linear f ==> (adjoint f = f <=> transp(matrix f) = matrix f)`,
+  SIMP_TAC[GSYM MATRIX_ADJOINT] THEN
+  MESON_TAC[LINEAR_EQ_MATRIX; ADJOINT_LINEAR]);;
+
+let LINEAR_MATRIX_EXISTS = prove
+ (`!f:real^M->real^N. linear f <=> ?A:real^M^N. f = \x. A ** x`,
+  GEN_TAC THEN EQ_TAC THEN
+  SIMP_TAC[MATRIX_VECTOR_MUL_LINEAR; LEFT_IMP_EXISTS_THM] THEN
+  DISCH_TAC THEN EXISTS_TAC `matrix(f:real^M->real^N)` THEN
+  ASM_SIMP_TAC[GSYM MATRIX_VECTOR_MUL]);;
+
+let LINEAR_1 = prove
+ (`!f:real^1->real^1. linear f <=> ?c. f = \x. c % x`,
+  SIMP_TAC[LINEAR_MATRIX_EXISTS; EXISTS_VECTOR_1] THEN
+  SIMP_TAC[FUN_EQ_THM; CART_EQ; FORALL_1; DIMINDEX_1; VECTOR_1;
+           matrix_vector_mul; SUM_1; CART_EQ; LAMBDA_BETA;
+           VECTOR_MUL_COMPONENT]);;
+
+let SYMMETRIC_MATRIX = prove
+ (`!A:real^N^N. transp A = A <=> adjoint(\x. A ** x) = \x. A ** x`,
+  SIMP_TAC[MATRIX_SELF_ADJOINT; MATRIX_VECTOR_MUL_LINEAR] THEN
+  REWRITE_TAC[MATRIX_OF_MATRIX_VECTOR_MUL]);;
+
+let SYMMETRIC_MATRIX_ORTHOGONAL_EIGENVECTORS = prove
+ (`!A:real^N^N v w a b.
+        transp A = A /\ A ** v = a % v /\ A ** w = b % w /\ ~(a = b)
+        ==> orthogonal v w`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[SYMMETRIC_MATRIX] THEN
+  DISCH_THEN(MATCH_MP_TAC o MATCH_MP (ONCE_REWRITE_RULE[IMP_CONJ_ALT]
+        SELF_ADJOINT_ORTHOGONAL_EIGENVECTORS)) THEN
+  REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Operator norm.                                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let onorm = new_definition
+ `onorm (f:real^M->real^N) = sup { norm(f x) | norm(x) = &1 }`;;
+
+let NORM_BOUND_GENERALIZE = prove
+ (`!f:real^M->real^N b.
+        linear f
+        ==> ((!x. (norm(x) = &1) ==> norm(f x) <= b) <=>
+             (!x. norm(f x) <= b * norm(x)))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[REAL_MUL_RID]] THEN
+  X_GEN_TAC `x:real^M` THEN ASM_CASES_TAC `x:real^M = vec 0` THENL
+   [ASM_REWRITE_TAC[NORM_0; REAL_MUL_RZERO] THEN
+    ASM_MESON_TAC[LINEAR_0; NORM_0; REAL_LE_REFL];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[GSYM REAL_LE_LDIV_EQ; NORM_POS_LT; real_div] THEN
+  MATCH_MP_TAC(REAL_ARITH `abs(a * b) <= c ==> b * a <= c`) THEN
+  REWRITE_TAC[REAL_ABS_MUL; REAL_ABS_NORM; GSYM NORM_MUL] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[GSYM(MATCH_MP LINEAR_CMUL th)]) THEN
+  ASM_SIMP_TAC[NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM; REAL_MUL_LINV;
+               NORM_EQ_0]);;
+
+let ONORM = prove
+ (`!f:real^M->real^N.
+        linear f
+        ==> (!x. norm(f x) <= onorm f * norm(x)) /\
+            (!b. (!x. norm(f x) <= b * norm(x)) ==> onorm f <= b)`,
+  GEN_TAC THEN DISCH_TAC THEN
+  MP_TAC(SPEC `{ norm((f:real^M->real^N) x) | norm(x) = &1 }` SUP) THEN
+  SIMP_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+  REWRITE_TAC[LEFT_FORALL_IMP_THM; RIGHT_EXISTS_AND_THM; EXISTS_REFL] THEN
+  ASM_SIMP_TAC[NORM_BOUND_GENERALIZE; GSYM onorm; GSYM MEMBER_NOT_EMPTY] THEN
+  DISCH_THEN MATCH_MP_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  ASM_MESON_TAC[VECTOR_CHOOSE_SIZE; LINEAR_BOUNDED; REAL_POS]);;
+
+let ONORM_POS_LE = prove
+ (`!f. linear f ==> &0 <= onorm f`,
+  MESON_TAC[ONORM; VECTOR_CHOOSE_SIZE; REAL_POS; REAL_MUL_RID; NORM_POS_LE;
+            REAL_LE_TRANS]);;
+
+let ONORM_EQ_0 = prove
+ (`!f:real^M->real^N. linear f ==> ((onorm f = &0) <=> (!x. f x = vec 0))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THEN
+  MP_TAC(SPEC `f:real^M->real^N` ONORM) THEN
+  ASM_SIMP_TAC[GSYM REAL_LE_ANTISYM; ONORM_POS_LE; NORM_0; REAL_MUL_LZERO;
+               NORM_LE_0; REAL_LE_REFL]);;
+
+let ONORM_CONST = prove
+ (`!y:real^N. onorm(\x:real^M. y) = norm(y)`,
+  GEN_TAC THEN REWRITE_TAC[onorm] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `sup {norm(y:real^N)}` THEN
+  CONJ_TAC THENL
+   [AP_TERM_TAC THEN MATCH_MP_TAC(SET_RULE
+     `(?x. P x) ==> {f y | x | P x} = {f y}`) THEN
+    EXISTS_TAC `basis 1 :real^M` THEN
+    SIMP_TAC[NORM_BASIS; DIMINDEX_GE_1; LE_REFL];
+    MATCH_MP_TAC REAL_SUP_UNIQUE THEN SET_TAC[REAL_LE_REFL]]);;
+
+let ONORM_POS_LT = prove
+ (`!f. linear f ==> (&0 < onorm f <=> ~(!x. f x = vec 0))`,
+  SIMP_TAC[GSYM ONORM_EQ_0; ONORM_POS_LE;
+           REAL_ARITH `(&0 < x <=> ~(x = &0)) <=> &0 <= x`]);;
+
+let ONORM_COMPOSE = prove
+ (`!f g. linear f /\ linear g ==> onorm(f o g) <= onorm f * onorm g`,
+  MESON_TAC[ONORM; LINEAR_COMPOSE; o_THM; REAL_MUL_ASSOC; REAL_LE_TRANS; ONORM;
+            REAL_LE_LMUL; ONORM_POS_LE]);;
+
+let ONORM_NEG_LEMMA = prove
+ (`!f. linear f ==> onorm(\x. --(f x)) <= onorm f`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP ONORM o
+    MATCH_MP LINEAR_COMPOSE_NEG) THEN
+  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_SIMP_TAC[NORM_NEG; ONORM]);;
+
+let ONORM_NEG = prove
+ (`!f:real^M->real^N. linear f ==> (onorm(\x. --(f x)) = onorm f)`,
+  REPEAT STRIP_TAC THEN  REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN
+  ASM_SIMP_TAC[ONORM_NEG_LEMMA] THEN
+  SUBGOAL_THEN `f:real^M->real^N = \x. --(--(f x))`
+   (fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th]) THEN
+  ASM_SIMP_TAC[ONORM_NEG_LEMMA; LINEAR_COMPOSE_NEG] THEN
+  REWRITE_TAC[VECTOR_NEG_NEG; ETA_AX]);;
+
+let ONORM_TRIANGLE = prove
+ (`!f:real^M->real^N g.
+        linear f /\ linear g ==> onorm(\x. f x + g x) <= onorm f + onorm g`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MATCH_MP_TAC o CONJUNCT2 o MATCH_MP ONORM o MATCH_MP
+              LINEAR_COMPOSE_ADD) THEN
+  REWRITE_TAC[REAL_ADD_RDISTRIB] THEN
+  ASM_MESON_TAC[REAL_LE_ADD2; REAL_LE_TRANS; NORM_TRIANGLE; ONORM]);;
+
+let ONORM_TRIANGLE_LE = prove
+ (`!f g. linear f /\ linear g /\ onorm(f) + onorm(g) <= e
+         ==> onorm(\x. f x + g x) <= e`,
+  MESON_TAC[REAL_LE_TRANS; ONORM_TRIANGLE]);;
+
+let ONORM_TRIANGLE_LT = prove
+ (`!f g. linear f /\ linear g /\ onorm(f) + onorm(g) < e
+         ==> onorm(\x. f x + g x) < e`,
+  MESON_TAC[REAL_LET_TRANS; ONORM_TRIANGLE]);;
+
+let ONORM_ID = prove
+ (`onorm(\x:real^N. x) = &1`,
+  REWRITE_TAC[onorm] THEN
+  SUBGOAL_THEN `{norm(x:real^N) | norm x = &1} = {&1}`
+   (fun th -> REWRITE_TAC[th; SUP_SING]) THEN
+  SUBGOAL_THEN `norm(basis 1:real^N) = &1` MP_TAC THENL
+   [SIMP_TAC[NORM_BASIS; DIMINDEX_GE_1; LE_REFL]; SET_TAC[]]);;
+
+let ONORM_I = prove
+ (`onorm(I:real^N->real^N) = &1`,
+  REWRITE_TAC[I_DEF; ONORM_ID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* It's handy to "lift" from R to R^1 and "drop" from R^1 to R.              *)
+(* ------------------------------------------------------------------------- *)
+
+let lift = new_definition
+ `(lift:real->real^1) x = lambda i. x`;;
+
+let drop = new_definition
+ `(drop:real^1->real) x = x$1`;;
+
+let LIFT_COMPONENT = prove
+ (`!x. (lift x)$1 = x`,
+  SIMP_TAC[lift; LAMBDA_BETA; DIMINDEX_1; LE_ANTISYM]);;
+
+let LIFT_DROP = prove
+ (`(!x. lift(drop x) = x) /\ (!x. drop(lift x) = x)`,
+  SIMP_TAC[lift; drop; CART_EQ; LAMBDA_BETA; DIMINDEX_1; LE_ANTISYM]);;
+
+let IMAGE_LIFT_DROP = prove
+ (`(!s. IMAGE (lift o drop) s = s) /\ (!s. IMAGE (drop o lift) s = s)`,
+  REWRITE_TAC[o_DEF; LIFT_DROP] THEN SET_TAC[]);;
+
+let IN_IMAGE_LIFT_DROP = prove
+ (`(!x s. x IN IMAGE lift s <=> drop x IN s) /\
+   (!x s. x IN IMAGE drop s <=> lift x IN s)`,
+  REWRITE_TAC[IN_IMAGE] THEN MESON_TAC[LIFT_DROP]);;
+
+let FORALL_LIFT = prove
+ (`(!x. P x) = (!x. P(lift x))`,
+  MESON_TAC[LIFT_DROP]);;
+
+let EXISTS_LIFT = prove
+ (`(?x. P x) = (?x. P(lift x))`,
+  MESON_TAC[LIFT_DROP]);;
+
+let FORALL_DROP = prove
+ (`(!x. P x) = (!x. P(drop x))`,
+  MESON_TAC[LIFT_DROP]);;
+
+let EXISTS_DROP = prove
+ (`(?x. P x) = (?x. P(drop x))`,
+  MESON_TAC[LIFT_DROP]);;
+
+let FORALL_LIFT_FUN = prove
+ (`!P:(A->real^1)->bool. (!f. P f) <=> (!f. P(lift o f))`,
+  GEN_TAC THEN EQ_TAC THEN SIMP_TAC[] THEN DISCH_TAC THEN
+  X_GEN_TAC `f:A->real^1` THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `drop o (f:A->real^1)`) THEN
+  REWRITE_TAC[o_DEF; LIFT_DROP; ETA_AX]);;
+
+let FORALL_DROP_FUN = prove
+ (`!P:(A->real)->bool. (!f. P f) <=> (!f. P(drop o f))`,
+  REWRITE_TAC[FORALL_LIFT_FUN; o_DEF; LIFT_DROP; ETA_AX]);;
+
+let EXISTS_LIFT_FUN = prove
+ (`!P:(A->real^1)->bool. (?f. P f) <=> (?f. P(lift o f))`,
+  ONCE_REWRITE_TAC[MESON[] `(?x. P x) <=> ~(!x. ~P x)`] THEN
+  REWRITE_TAC[FORALL_LIFT_FUN]);;
+
+let EXISTS_DROP_FUN = prove
+ (`!P:(A->real)->bool. (?f. P f) <=> (?f. P(drop o f))`,
+  ONCE_REWRITE_TAC[MESON[] `(?x. P x) <=> ~(!x. ~P x)`] THEN
+  REWRITE_TAC[FORALL_DROP_FUN]);;
+
+let LIFT_EQ = prove
+ (`!x y. (lift x = lift y) <=> (x = y)`,
+  MESON_TAC[LIFT_DROP]);;
+
+let DROP_EQ = prove
+ (`!x y. (drop x = drop y) <=> (x = y)`,
+  MESON_TAC[LIFT_DROP]);;
+
+let LIFT_IN_IMAGE_LIFT = prove
+ (`!x s. (lift x) IN (IMAGE lift s) <=> x IN s`,
+  REWRITE_TAC[IN_IMAGE] THEN MESON_TAC[LIFT_DROP]);;
+
+let FORALL_LIFT_IMAGE = prove
+ (`!P. (!s. P s) <=> (!s. P(IMAGE lift s))`,
+  MESON_TAC[IMAGE_LIFT_DROP; IMAGE_o]);;
+
+let EXISTS_LIFT_IMAGE = prove
+ (`!P. (?s. P s) <=> (?s. P(IMAGE lift s))`,
+  MESON_TAC[IMAGE_LIFT_DROP; IMAGE_o]);;
+
+let SUBSET_LIFT_IMAGE = prove
+ (`!s t. IMAGE lift s SUBSET IMAGE lift t <=> s SUBSET t`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[IMAGE_SUBSET] THEN
+  DISCH_THEN(MP_TAC o ISPEC `drop` o MATCH_MP IMAGE_SUBSET) THEN
+  REWRITE_TAC[GSYM IMAGE_o; IMAGE_LIFT_DROP]);;
+
+let FORALL_DROP_IMAGE = prove
+ (`!P. (!s. P s) <=> (!s. P(IMAGE drop s))`,
+  MESON_TAC[IMAGE_LIFT_DROP; IMAGE_o]);;
+
+let EXISTS_DROP_IMAGE = prove
+ (`!P. (?s. P s) <=> (?s. P(IMAGE drop s))`,
+  MESON_TAC[IMAGE_LIFT_DROP; IMAGE_o]);;
+
+let SUBSET_DROP_IMAGE = prove
+ (`!s t. IMAGE drop s SUBSET IMAGE drop t <=> s SUBSET t`,
+  REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[IMAGE_SUBSET] THEN
+  DISCH_THEN(MP_TAC o ISPEC `lift` o MATCH_MP IMAGE_SUBSET) THEN
+  REWRITE_TAC[GSYM IMAGE_o; IMAGE_LIFT_DROP]);;
+
+let DROP_IN_IMAGE_DROP = prove
+ (`!x s. (drop x) IN (IMAGE drop s) <=> x IN s`,
+  REWRITE_TAC[IN_IMAGE] THEN MESON_TAC[LIFT_DROP]);;
+
+let LIFT_NUM = prove
+ (`!n. lift(&n) = vec n`,
+  SIMP_TAC[CART_EQ; lift; vec; LAMBDA_BETA]);;
+
+let LIFT_ADD = prove
+ (`!x y. lift(x + y) = lift x + lift y`,
+  SIMP_TAC[CART_EQ; lift; LAMBDA_BETA; VECTOR_ADD_COMPONENT]);;
+
+let LIFT_SUB = prove
+ (`!x y. lift(x - y) = lift x - lift y`,
+  SIMP_TAC[CART_EQ; lift; LAMBDA_BETA; VECTOR_SUB_COMPONENT]);;
+
+let LIFT_CMUL = prove
+ (`!x c. lift(c * x) = c % lift(x)`,
+  SIMP_TAC[CART_EQ; lift; LAMBDA_BETA; VECTOR_MUL_COMPONENT]);;
+
+let LIFT_NEG = prove
+ (`!x. lift(--x) = --(lift x)`,
+  SIMP_TAC[CART_EQ; lift; LAMBDA_BETA; VECTOR_NEG_COMPONENT]);;
+
+let LIFT_EQ_CMUL = prove
+ (`!x. lift x = x % vec 1`,
+  REWRITE_TAC[GSYM LIFT_NUM; GSYM LIFT_CMUL; REAL_MUL_RID]);;
+
+let LIFT_SUM = prove
+ (`!k x. FINITE k ==> (lift(sum k x) = vsum k (lift o x))`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES; o_THM; LIFT_ADD; LIFT_NUM]);;
+
+let DROP_LAMBDA = prove
+ (`!x. drop(lambda i. x i) = x 1`,
+  SIMP_TAC[drop; LAMBDA_BETA; DIMINDEX_1; LE_REFL]);;
+
+let DROP_VEC = prove
+ (`!n. drop(vec n) = &n`,
+  MESON_TAC[LIFT_DROP; LIFT_NUM]);;
+
+let DROP_ADD = prove
+ (`!x y. drop(x + y) = drop x + drop y`,
+  MESON_TAC[LIFT_DROP; LIFT_ADD]);;
+
+let DROP_SUB = prove
+ (`!x y. drop(x - y) = drop x - drop y`,
+  MESON_TAC[LIFT_DROP; LIFT_SUB]);;
+
+let DROP_CMUL = prove
+ (`!x c. drop(c % x) = c * drop(x)`,
+  MESON_TAC[LIFT_DROP; LIFT_CMUL]);;
+
+let DROP_NEG = prove
+ (`!x. drop(--x) = --(drop x)`,
+  MESON_TAC[LIFT_DROP; LIFT_NEG]);;
+
+let DROP_VSUM = prove
+ (`!k x. FINITE k ==> (drop(vsum k x) = sum k (drop o x))`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[SUM_CLAUSES; VSUM_CLAUSES; o_THM; DROP_ADD; DROP_VEC]);;
+
+let NORM_1 = prove
+ (`!x. norm x = abs(drop x)`,
+  REWRITE_TAC[drop; NORM_REAL]);;
+
+let NORM_1_POS = prove
+ (`!x. &0 <= drop x ==> norm x = drop x`,
+  SIMP_TAC[NORM_1; real_abs]);;
+
+let NORM_LIFT = prove
+ (`!x. norm(lift x) = abs(x)`,
+  SIMP_TAC[lift; NORM_REAL; LIFT_COMPONENT]);;
+
+let DIST_LIFT = prove
+ (`!x y. dist(lift x,lift y) = abs(x - y)`,
+  REWRITE_TAC[DIST_REAL; LIFT_COMPONENT]);;
+
+let ABS_DROP = prove
+ (`!x. norm x = abs(drop x)`,
+  REWRITE_TAC[FORALL_LIFT; LIFT_DROP; NORM_LIFT]);;
+
+let LINEAR_VMUL_DROP = prove
+ (`!f v. linear f ==> linear (\x. drop(f x) % v)`,
+  SIMP_TAC[drop; LINEAR_VMUL_COMPONENT; DIMINDEX_1; LE_REFL]);;
+
+let LINEAR_FROM_REALS = prove
+ (`!f:real^1->real^N. linear f ==> f = \x. drop x % column 1 (matrix f)`,
+  GEN_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN
+  DISCH_THEN(fun th -> REWRITE_TAC[GSYM(MATCH_MP MATRIX_WORKS th)]) THEN
+  SIMP_TAC[CART_EQ; matrix_vector_mul; vector_mul; LAMBDA_BETA;
+           DIMINDEX_1; SUM_SING_NUMSEG; drop; column] THEN
+  REWRITE_TAC[REAL_MUL_AC]);;
+
+let LINEAR_TO_REALS = prove
+ (`!f:real^N->real^1. linear f ==> f = \x. lift(row 1 (matrix f) dot x)`,
+  GEN_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN
+  DISCH_THEN(fun th -> REWRITE_TAC[GSYM(MATCH_MP MATRIX_WORKS th)]) THEN
+  SIMP_TAC[CART_EQ; matrix_vector_mul; dot; LAMBDA_BETA;
+           DIMINDEX_1; SUM_SING_NUMSEG; lift; row; LE_ANTISYM]);;
+
+let DROP_EQ_0 = prove
+ (`!x. drop x = &0 <=> x = vec 0`,
+  REWRITE_TAC[GSYM DROP_EQ; DROP_VEC]);;
+
+let VSUM_REAL = prove
+ (`!f s. FINITE s ==> vsum s f = lift(sum s (drop o f))`,
+  SIMP_TAC[LIFT_SUM; o_DEF; LIFT_DROP; ETA_AX]);;
+
+let DROP_WLOG_LE = prove
+ (`(!x y. P x y <=> P y x) /\ (!x y. drop x <= drop y ==> P x y)
+   ==> (!x y. P x y)`,
+  MESON_TAC[REAL_LE_TOTAL]);;
+
+let IMAGE_LIFT_UNIV = prove
+ (`IMAGE lift (:real) = (:real^1)`,
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_UNIV] THEN MESON_TAC[LIFT_DROP]);;
+
+let IMAGE_DROP_UNIV = prove
+ (`IMAGE drop (:real^1) = (:real)`,
+  REWRITE_TAC[EXTENSION; IN_IMAGE; IN_UNIV] THEN MESON_TAC[LIFT_DROP]);;
+
+let SUM_VSUM = prove
+ (`!f s. FINITE s ==> sum s f = drop(vsum s (lift o f))`,
+  SIMP_TAC[VSUM_REAL; o_DEF; LIFT_DROP; ETA_AX]);;
+
+let LINEAR_LIFT_DOT = prove
+ (`!a. linear(\x. lift(a dot x))`,
+  REWRITE_TAC[linear; DOT_RMUL; DOT_RADD; LIFT_ADD; LIFT_CMUL]);;
+
+let LINEAR_LIFT_COMPONENT = prove
+ (`!k. linear(\x:real^N. lift(x$k))`,
+  REPEAT GEN_TAC THEN
+  SUBGOAL_THEN `?j. 1 <= j /\ j <= dimindex(:N) /\ !z:real^N. z$k = z$j`
+  CHOOSE_TAC THENL
+   [REWRITE_TAC[FINITE_INDEX_INRANGE];
+    MP_TAC(ISPEC `basis j:real^N` LINEAR_LIFT_DOT) THEN
+    ASM_SIMP_TAC[DOT_BASIS]]);;
+
+let BILINEAR_DROP_MUL = prove
+ (`bilinear (\x y:real^N. drop x % y)`,
+  REWRITE_TAC[bilinear; linear] THEN
+  REWRITE_TAC[DROP_ADD; DROP_CMUL] THEN VECTOR_ARITH_TAC);;
+
+let LINEAR_COMPONENTWISE = prove
+ (`!f:real^M->real^N.
+        linear f <=>
+        !i. 1 <= i /\ i <= dimindex(:N) ==> linear(\x. lift(f(x)$i))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[linear] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [CART_EQ] THEN
+  SIMP_TAC[GSYM LIFT_CMUL; GSYM LIFT_ADD; LIFT_EQ] THEN
+  REWRITE_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN
+  MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Pasting vectors.                                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_FSTCART = prove
+ (`linear fstcart`,
+  SIMP_TAC[linear; fstcart; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT;
+           VECTOR_MUL_COMPONENT; DIMINDEX_FINITE_SUM;
+           ARITH_RULE `x <= a ==> x <= a + b:num`]);;
+
+let LINEAR_SNDCART = prove
+ (`linear sndcart`,
+  SIMP_TAC[linear; sndcart; CART_EQ; LAMBDA_BETA; VECTOR_ADD_COMPONENT;
+           VECTOR_MUL_COMPONENT; DIMINDEX_FINITE_SUM;
+           ARITH_RULE `x <= a ==> x <= a + b:num`;
+           ARITH_RULE `x <= b ==> x + a <= a + b:num`]);;
+
+let FSTCART_VEC = prove
+ (`!n. fstcart(vec n) = vec n`,
+  SIMP_TAC[vec; fstcart; LAMBDA_BETA; CART_EQ; DIMINDEX_FINITE_SUM;
+           ARITH_RULE `m <= n:num ==> m <= n + p`]);;
+
+let FSTCART_ADD = prove
+ (`!x:real^(M,N)finite_sum y. fstcart(x + y) = fstcart(x) + fstcart(y)`,
+  REWRITE_TAC[REWRITE_RULE[linear] LINEAR_FSTCART]);;
+
+let FSTCART_CMUL = prove
+ (`!x:real^(M,N)finite_sum c. fstcart(c % x) = c % fstcart(x)`,
+  REWRITE_TAC[REWRITE_RULE[linear] LINEAR_FSTCART]);;
+
+let FSTCART_NEG = prove
+ (`!x:real^(M,N)finite_sum. --(fstcart x) = fstcart(--x)`,
+  ONCE_REWRITE_TAC[VECTOR_ARITH `--x = --(&1) % x`] THEN
+  REWRITE_TAC[FSTCART_CMUL]);;
+
+let FSTCART_SUB = prove
+ (`!x:real^(M,N)finite_sum y. fstcart(x - y) = fstcart(x) - fstcart(y)`,
+  REWRITE_TAC[VECTOR_SUB; FSTCART_NEG; FSTCART_ADD]);;
+
+let FSTCART_VSUM = prove
+ (`!k x. FINITE k ==> (fstcart(vsum k x) = vsum k (\i. fstcart(x i)))`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; FINITE_RULES; FSTCART_ADD; FSTCART_VEC]);;
+
+let SNDCART_VEC = prove
+ (`!n. sndcart(vec n) = vec n`,
+  SIMP_TAC[vec; sndcart; LAMBDA_BETA; CART_EQ; DIMINDEX_FINITE_SUM;
+           ARITH_RULE `x <= a ==> x <= a + b:num`;
+           ARITH_RULE `x <= b ==> x + a <= a + b:num`]);;
+
+let SNDCART_ADD = prove
+ (`!x:real^(M,N)finite_sum y. sndcart(x + y) = sndcart(x) + sndcart(y)`,
+  REWRITE_TAC[REWRITE_RULE[linear] LINEAR_SNDCART]);;
+
+let SNDCART_CMUL = prove
+ (`!x:real^(M,N)finite_sum c. sndcart(c % x) = c % sndcart(x)`,
+  REWRITE_TAC[REWRITE_RULE[linear] LINEAR_SNDCART]);;
+
+let SNDCART_NEG = prove
+ (`!x:real^(M,N)finite_sum. --(sndcart x) = sndcart(--x)`,
+  ONCE_REWRITE_TAC[VECTOR_ARITH `--x = --(&1) % x`] THEN
+  REWRITE_TAC[SNDCART_CMUL]);;
+
+let SNDCART_SUB = prove
+ (`!x:real^(M,N)finite_sum y. sndcart(x - y) = sndcart(x) - sndcart(y)`,
+  REWRITE_TAC[VECTOR_SUB; SNDCART_NEG; SNDCART_ADD]);;
+
+let SNDCART_VSUM = prove
+ (`!k x. FINITE k ==> (sndcart(vsum k x) = vsum k (\i. sndcart(x i)))`,
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[VSUM_CLAUSES; FINITE_RULES; SNDCART_ADD; SNDCART_VEC]);;
+
+let PASTECART_VEC = prove
+ (`!n. pastecart (vec n) (vec n) = vec n`,
+  REWRITE_TAC[PASTECART_EQ; FSTCART_VEC; SNDCART_VEC;
+              FSTCART_PASTECART; SNDCART_PASTECART]);;
+
+let PASTECART_ADD = prove
+ (`!x1 y1 x2:real^M y2:real^N.
+     pastecart x1 y1 + pastecart x2 y2 = pastecart (x1 + x2) (y1 + y2)`,
+  REWRITE_TAC[PASTECART_EQ; FSTCART_ADD; SNDCART_ADD;
+              FSTCART_PASTECART; SNDCART_PASTECART]);;
+
+let PASTECART_CMUL = prove
+ (`!x1 y1 c. pastecart (c % x1) (c % y1) = c % pastecart x1 y1`,
+  REWRITE_TAC[PASTECART_EQ; FSTCART_CMUL; SNDCART_CMUL;
+              FSTCART_PASTECART; SNDCART_PASTECART]);;
+
+let PASTECART_NEG = prove
+ (`!x:real^M y:real^N. pastecart (--x) (--y) = --(pastecart x y)`,
+  ONCE_REWRITE_TAC[VECTOR_ARITH `--x = --(&1) % x`] THEN
+  REWRITE_TAC[PASTECART_CMUL]);;
+
+let PASTECART_SUB = prove
+ (`!x1 y1 x2:real^M y2:real^N.
+     pastecart x1 y1 - pastecart x2 y2 = pastecart (x1 - x2) (y1 - y2)`,
+  REWRITE_TAC[VECTOR_SUB; GSYM PASTECART_NEG; PASTECART_ADD]);;
+
+let PASTECART_VSUM = prove
+ (`!k x y. FINITE k ==> (pastecart (vsum k x) (vsum k y) =
+                         vsum k (\i. pastecart (x i) (y i)))`,
+  SIMP_TAC[PASTECART_EQ; FSTCART_VSUM; SNDCART_VSUM;
+           FSTCART_PASTECART; SNDCART_PASTECART; ETA_AX]);;
+
+let PASTECART_EQ_VEC = prove
+ (`!x y n. pastecart x y = vec n <=> x = vec n /\ y = vec n`,
+  REWRITE_TAC[PASTECART_EQ; FSTCART_VEC; SNDCART_VEC;
+              FSTCART_PASTECART; SNDCART_PASTECART]);;
+
+let NORM_FSTCART = prove
+ (`!x. norm(fstcart x) <= norm x`,
+  GEN_TAC THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM PASTECART_FST_SND] THEN
+  SIMP_TAC[SQRT_MONO_LE_EQ; DOT_POS_LE; vector_norm] THEN
+  SIMP_TAC[pastecart; dot; DIMINDEX_FINITE_SUM; LAMBDA_BETA; DIMINDEX_NONZERO;
+           SUM_ADD_SPLIT; REAL_LE_ADDR; SUM_POS_LE; FINITE_NUMSEG;
+           REAL_LE_SQUARE; ARITH_RULE `x <= a ==> x <= a + b:num`;
+           ARITH_RULE `~(d = 0) ==> 1 <= d + 1`]);;
+
+let DIST_FSTCART = prove
+ (`!x y. dist(fstcart x,fstcart y) <= dist(x,y)`,
+  REWRITE_TAC[dist; GSYM FSTCART_SUB; NORM_FSTCART]);;
+
+let NORM_SNDCART = prove
+ (`!x. norm(sndcart x) <= norm x`,
+  GEN_TAC THEN
+  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM PASTECART_FST_SND] THEN
+  SIMP_TAC[SQRT_MONO_LE_EQ; DOT_POS_LE; vector_norm] THEN
+  SIMP_TAC[pastecart; dot; DIMINDEX_FINITE_SUM; LAMBDA_BETA; DIMINDEX_NONZERO;
+           SUM_ADD_SPLIT; ARITH_RULE `x <= a ==> x <= a + b:num`;
+           ARITH_RULE `~(d = 0) ==> 1 <= d + 1`] THEN
+  ONCE_REWRITE_TAC[ADD_SYM] THEN REWRITE_TAC[NUMSEG_OFFSET_IMAGE] THEN
+  SIMP_TAC[SUM_IMAGE; FINITE_NUMSEG; EQ_ADD_RCANCEL; o_DEF; ADD_SUB] THEN
+  SIMP_TAC[ARITH_RULE `1 <= x ==> ~(x + a <= a)`; SUM_POS_LE; FINITE_NUMSEG;
+           REAL_LE_ADDL; REAL_LE_SQUARE]);;
+
+let DIST_SNDCART = prove
+ (`!x y. dist(sndcart x,sndcart y) <= dist(x,y)`,
+  REWRITE_TAC[dist; GSYM SNDCART_SUB; NORM_SNDCART]);;
+
+let DOT_PASTECART = prove
+ (`!x1 x2 y1 y2. (pastecart x1 x2) dot (pastecart y1 y2) =
+                x1 dot y1 + x2 dot y2`,
+  SIMP_TAC[pastecart; dot; LAMBDA_BETA; DIMINDEX_FINITE_SUM] THEN
+  SIMP_TAC[SUM_ADD_SPLIT; ARITH_RULE `~(d = 0) ==> 1 <= d + 1`;
+           DIMINDEX_NONZERO; REAL_LE_LADD] THEN
+  ONCE_REWRITE_TAC[ADD_SYM] THEN REWRITE_TAC[NUMSEG_OFFSET_IMAGE] THEN
+  SIMP_TAC[SUM_IMAGE; FINITE_NUMSEG; EQ_ADD_RCANCEL; o_DEF; ADD_SUB] THEN
+  SIMP_TAC[ARITH_RULE `1 <= x ==> ~(x + a <= a)`; REAL_LE_REFL]);;
+
+let SQNORM_PASTECART = prove
+ (`!x y. norm(pastecart x y) pow 2 = norm(x) pow 2 + norm(y) pow 2`,
+  REWRITE_TAC[NORM_POW_2; DOT_PASTECART]);;
+
+let NORM_PASTECART = prove
+ (`!x y. norm(pastecart x y) = sqrt(norm(x) pow 2 + norm(y) pow 2)`,
+  REWRITE_TAC[NORM_EQ_SQUARE] THEN
+  SIMP_TAC[SQRT_POS_LE; SQRT_POW_2; REAL_LE_ADD; REAL_LE_POW_2] THEN
+  REWRITE_TAC[DOT_PASTECART; NORM_POW_2]);;
+
+let NORM_PASTECART_LE = prove
+ (`!x y. norm(pastecart x y) <= norm(x) + norm(y)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC TRIANGLE_LEMMA THEN
+  REWRITE_TAC[NORM_POS_LE; NORM_POW_2; DOT_PASTECART; REAL_LE_REFL]);;
+
+let NORM_LE_PASTECART = prove
+ (`!x:real^M y:real^N.
+    norm(x) <= norm(pastecart x y) /\
+    norm(y) <= norm(pastecart x y)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[NORM_PASTECART] THEN CONJ_TAC THEN
+  MATCH_MP_TAC REAL_LE_RSQRT THEN
+  REWRITE_TAC[REAL_LE_ADDL; REAL_LE_ADDR; REAL_LE_POW_2]);;
+
+let NORM_PASTECART_0 = prove
+ (`(!x. norm(pastecart x (vec 0)) = norm x) /\
+   (!y. norm(pastecart (vec 0) y) = norm y)`,
+  REWRITE_TAC[NORM_EQ_SQUARE; NORM_POW_2; NORM_POS_LE] THEN
+  REWRITE_TAC[DOT_PASTECART; DOT_LZERO; REAL_ADD_LID; REAL_ADD_RID]);;
+
+let DIST_PASTECART_CANCEL = prove
+ (`(!x x' y. dist(pastecart x y,pastecart x' y) = dist(x,x')) /\
+   (!x y y'. dist(pastecart x y,pastecart x y') = dist(y,y'))`,
+  REWRITE_TAC[dist; PASTECART_SUB; VECTOR_SUB_REFL; NORM_PASTECART_0]);;
+
+let LINEAR_PASTECART = prove
+ (`!f:real^M->real^N g:real^M->real^P.
+        linear f /\ linear g ==> linear (\x. pastecart (f x) (g x))`,
+  SIMP_TAC[linear; PASTECART_ADD; GSYM PASTECART_CMUL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A bit of linear algebra.                                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let subspace = new_definition
+ `subspace s <=>
+        vec(0) IN s /\
+        (!x y. x IN s /\ y IN s ==> (x + y) IN s) /\
+        (!c x. x IN s ==> (c % x) IN s)`;;
+
+let span = new_definition
+  `span s = subspace hull s`;;
+
+let dependent = new_definition
+ `dependent s <=> ?a. a IN s /\ a IN span(s DELETE a)`;;
+
+let independent = new_definition
+ `independent s <=> ~(dependent s)`;;
+
+(* ------------------------------------------------------------------------- *)
+(* Closure properties of subspaces.                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let SUBSPACE_UNIV = prove
+ (`subspace(UNIV:real^N->bool)`,
+  REWRITE_TAC[subspace; IN_UNIV]);;
+
+let SUBSPACE_IMP_NONEMPTY = prove
+ (`!s. subspace s ==> ~(s = {})`,
+  REWRITE_TAC[subspace] THEN SET_TAC[]);;
+
+let SUBSPACE_0 = prove
+ (`subspace s ==> vec(0) IN s`,
+  SIMP_TAC[subspace]);;
+
+let SUBSPACE_ADD = prove
+ (`!x y s. subspace s /\ x IN s /\ y IN s ==> (x + y) IN s`,
+  SIMP_TAC[subspace]);;
+
+let SUBSPACE_MUL = prove
+ (`!x c s. subspace s /\ x IN s ==> (c % x) IN s`,
+  SIMP_TAC[subspace]);;
+
+let SUBSPACE_NEG = prove
+ (`!x s. subspace s /\ x IN s ==> (--x) IN s`,
+  SIMP_TAC[VECTOR_ARITH `--x = --(&1) % x`; SUBSPACE_MUL]);;
+
+let SUBSPACE_SUB = prove
+ (`!x y s. subspace s /\ x IN s /\ y IN s ==> (x - y) IN s`,
+  SIMP_TAC[VECTOR_SUB; SUBSPACE_ADD; SUBSPACE_NEG]);;
+
+let SUBSPACE_VSUM = prove
+ (`!s f t. subspace s /\ FINITE t /\ (!x. x IN t ==> f(x) IN s)
+           ==> (vsum t f) IN s`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  ASM_SIMP_TAC[VSUM_CLAUSES; SUBSPACE_0; IN_INSERT; SUBSPACE_ADD]);;
+
+let SUBSPACE_LINEAR_IMAGE = prove
+ (`!f s. linear f /\ subspace s ==> subspace(IMAGE f s)`,
+  REWRITE_TAC[subspace; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN REWRITE_TAC[IN_IMAGE] THEN
+  MESON_TAC[linear; LINEAR_0]);;
+
+let SUBSPACE_LINEAR_PREIMAGE = prove
+ (`!f s. linear f /\ subspace s ==> subspace {x | f(x) IN s}`,
+  REWRITE_TAC[subspace; IN_ELIM_THM] THEN
+  MESON_TAC[linear; LINEAR_0]);;
+
+let SUBSPACE_TRIVIAL = prove
+ (`subspace {vec 0}`,
+  SIMP_TAC[subspace; IN_SING] THEN CONJ_TAC THEN VECTOR_ARITH_TAC);;
+
+let SUBSPACE_INTER = prove
+ (`!s t. subspace s /\ subspace t ==> subspace (s INTER t)`,
+  REWRITE_TAC[subspace; IN_INTER] THEN MESON_TAC[]);;
+
+let SUBSPACE_INTERS = prove
+ (`!f. (!s. s IN f ==> subspace s) ==> subspace(INTERS f)`,
+  SIMP_TAC[subspace; IMP_CONJ; RIGHT_FORALL_IMP_THM; IN_INTERS]);;
+
+let LINEAR_INJECTIVE_0_SUBSPACE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ subspace s
+         ==> ((!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) <=>
+              (!x. x IN s /\ f x = vec 0 ==> x = vec 0))`,
+  REPEAT STRIP_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [GSYM VECTOR_SUB_EQ] THEN
+  ASM_SIMP_TAC[GSYM LINEAR_SUB] THEN
+  ASM_MESON_TAC[VECTOR_SUB_RZERO; SUBSPACE_SUB; SUBSPACE_0]);;
+
+let SUBSPACE_UNION_CHAIN = prove
+ (`!s t:real^N->bool.
+        subspace s /\ subspace t /\ subspace(s UNION t)
+         ==> s SUBSET t \/ t SUBSET s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[SET_RULE
+   `s SUBSET t \/ t SUBSET s <=>
+    ~(?x y. x IN s /\ ~(x IN t) /\ y IN t /\ ~(y IN s))`] THEN
+  STRIP_TAC THEN SUBGOAL_THEN `(x + y:real^N) IN s UNION t` MP_TAC THENL
+   [MATCH_MP_TAC SUBSPACE_ADD THEN ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    REWRITE_TAC[IN_UNION; DE_MORGAN_THM] THEN
+    ASM_MESON_TAC[SUBSPACE_SUB; VECTOR_ARITH
+     `(x + y) - x:real^N = y /\ (x + y) - y = x`]]);;
+
+let SUBSPACE_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        subspace s /\ subspace t ==> subspace(s PCROSS t)`,
+  REWRITE_TAC[subspace; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[FORALL_IN_PCROSS; GSYM PASTECART_CMUL; PASTECART_ADD] THEN
+  REWRITE_TAC[GSYM PASTECART_VEC; PASTECART_IN_PCROSS] THEN SIMP_TAC[]);;
+
+let SUBSPACE_PCROSS_EQ = prove
+ (`!s:real^M->bool t:real^N->bool.
+        subspace(s PCROSS t) <=> subspace s /\ subspace t`,
+  REPEAT GEN_TAC THEN
+  ASM_CASES_TAC `s:real^M->bool = {}` THENL
+   [ASM_MESON_TAC[PCROSS_EMPTY; SUBSPACE_IMP_NONEMPTY]; ALL_TAC] THEN
+  ASM_CASES_TAC `t:real^N->bool = {}` THENL
+   [ASM_MESON_TAC[PCROSS_EMPTY; SUBSPACE_IMP_NONEMPTY]; ALL_TAC] THEN
+  EQ_TAC THEN REWRITE_TAC[SUBSPACE_PCROSS] THEN REPEAT STRIP_TAC THENL
+   [MP_TAC(ISPECL [`fstcart:real^(M,N)finite_sum->real^M`;
+     `(s:real^M->bool) PCROSS (t:real^N->bool)`] SUBSPACE_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_FSTCART];
+    MP_TAC(ISPECL [`sndcart:real^(M,N)finite_sum->real^N`;
+     `(s:real^M->bool) PCROSS (t:real^N->bool)`] SUBSPACE_LINEAR_IMAGE) THEN
+    ASM_REWRITE_TAC[LINEAR_SNDCART]] THEN
+  MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_IMAGE; EXISTS_PASTECART; PASTECART_IN_PCROSS;
+              FSTCART_PASTECART; SNDCART_PASTECART] THEN
+  ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Lemmas.                                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let SPAN_SPAN = prove
+ (`!s. span(span s) = span s`,
+  REWRITE_TAC[span; HULL_HULL]);;
+
+let SPAN_MONO = prove
+ (`!s t. s SUBSET t ==> span s SUBSET span t`,
+  REWRITE_TAC[span; HULL_MONO]);;
+
+let SUBSPACE_SPAN = prove
+ (`!s. subspace(span s)`,
+  GEN_TAC THEN REWRITE_TAC[span] THEN MATCH_MP_TAC P_HULL THEN
+  SIMP_TAC[subspace; IN_INTERS]);;
+
+let SPAN_CLAUSES = prove
+ (`(!a s. a IN s ==> a IN span s) /\
+   (vec(0) IN span s) /\
+   (!x y s. x IN span s /\ y IN span s ==> (x + y) IN span s) /\
+   (!x c s. x IN span s ==> (c % x) IN span s)`,
+  MESON_TAC[span; HULL_SUBSET; SUBSET; SUBSPACE_SPAN; subspace]);;
+
+let SPAN_INDUCT = prove
+ (`!s h. (!x. x IN s ==> x IN h) /\ subspace h ==> !x. x IN span(s) ==> h(x)`,
+  REWRITE_TAC[span] THEN MESON_TAC[SUBSET; HULL_MINIMAL; IN]);;
+
+let SPAN_EMPTY = prove
+ (`span {} = {vec 0}`,
+  REWRITE_TAC[span] THEN MATCH_MP_TAC HULL_UNIQUE THEN
+  SIMP_TAC[subspace; SUBSET; IN_SING; NOT_IN_EMPTY] THEN
+  REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC);;
+
+let INDEPENDENT_EMPTY = prove
+ (`independent {}`,
+  REWRITE_TAC[independent; dependent; NOT_IN_EMPTY]);;
+
+let INDEPENDENT_NONZERO = prove
+ (`!s. independent s ==> ~(vec 0 IN s)`,
+  REWRITE_TAC[independent; dependent] THEN MESON_TAC[SPAN_CLAUSES]);;
+
+let INDEPENDENT_MONO = prove
+ (`!s t. independent t /\ s SUBSET t ==> independent s`,
+  REWRITE_TAC[independent; dependent] THEN
+  ASM_MESON_TAC[SPAN_MONO; SUBSET; IN_DELETE]);;
+
+let DEPENDENT_MONO = prove
+ (`!s t:real^N->bool. dependent s /\ s SUBSET t ==> dependent t`,
+  ONCE_REWRITE_TAC[TAUT `p /\ q ==> r <=> ~r /\ q ==> ~p`] THEN
+  REWRITE_TAC[GSYM independent; INDEPENDENT_MONO]);;
+
+let SPAN_SUBSPACE = prove
+ (`!b s. b SUBSET s /\ s SUBSET (span b) /\ subspace s ==> (span b = s)`,
+  MESON_TAC[SUBSET_ANTISYM; span; HULL_MINIMAL]);;
+
+let SPAN_INDUCT_ALT = prove
+ (`!s h. h(vec 0) /\
+         (!c x y. x IN s /\ h(y) ==> h(c % x + y))
+          ==> !x:real^N. x IN span(s) ==> h(x)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o prove_inductive_relations_exist o concl) THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `!x:real^N. x IN span(s) ==> g(x)`
+   (fun th -> ASM_MESON_TAC[th]) THEN
+  MATCH_MP_TAC SPAN_INDUCT THEN REWRITE_TAC[subspace; IN_ELIM_THM] THEN
+  REWRITE_TAC[IN; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN
+  REPEAT CONJ_TAC THEN TRY(FIRST_X_ASSUM MATCH_MP_TAC) THEN
+  REWRITE_TAC[VECTOR_ADD_LDISTRIB; VECTOR_MUL_ASSOC] THEN
+  ASM_MESON_TAC[IN; VECTOR_ADD_LID; VECTOR_ADD_ASSOC; VECTOR_ADD_SYM;
+                VECTOR_MUL_LID; VECTOR_MUL_RZERO]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Individual closure properties.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let SPAN_SUPERSET = prove
+ (`!x. x IN s ==> x IN span s`,
+  MESON_TAC[SPAN_CLAUSES]);;
+
+let SPAN_INC = prove
+ (`!s. s SUBSET span s`,
+  REWRITE_TAC[SUBSET; SPAN_SUPERSET]);;
+
+let SPAN_UNION_SUBSET = prove
+ (`!s t. span s UNION span t SUBSET span(s UNION t)`,
+  REWRITE_TAC[span; HULL_UNION_SUBSET]);;
+
+let SPAN_UNIV = prove
+ (`span(:real^N) = (:real^N)`,
+  SIMP_TAC[SPAN_INC; SET_RULE `UNIV SUBSET s ==> s = UNIV`]);;
+
+let SPAN_0 = prove
+ (`vec(0) IN span s`,
+  MESON_TAC[SUBSPACE_SPAN; SUBSPACE_0]);;
+
+let SPAN_ADD = prove
+ (`!x y s. x IN span s /\ y IN span s ==> (x + y) IN span s`,
+  MESON_TAC[SUBSPACE_SPAN; SUBSPACE_ADD]);;
+
+let SPAN_MUL = prove
+ (`!x c s. x IN span s ==> (c % x) IN span s`,
+  MESON_TAC[SUBSPACE_SPAN; SUBSPACE_MUL]);;
+
+let SPAN_MUL_EQ = prove
+ (`!x:real^N c s. ~(c = &0) ==> ((c % x) IN span s <=> x IN span s)`,
+  REPEAT(STRIP_TAC ORELSE EQ_TAC) THEN ASM_SIMP_TAC[SPAN_MUL] THEN
+  SUBGOAL_THEN `(inv(c) % c % x:real^N) IN span s` MP_TAC THENL
+   [ASM_SIMP_TAC[SPAN_MUL];
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; VECTOR_MUL_LID]]);;
+
+let SPAN_NEG = prove
+ (`!x s. x IN span s ==> (--x) IN span s`,
+  MESON_TAC[SUBSPACE_SPAN; SUBSPACE_NEG]);;
+
+let SPAN_NEG_EQ = prove
+ (`!x s. --x IN span s <=> x IN span s`,
+  MESON_TAC[SPAN_NEG; VECTOR_NEG_NEG]);;
+
+let SPAN_SUB = prove
+ (`!x y s. x IN span s /\ y IN span s ==> (x - y) IN span s`,
+  MESON_TAC[SUBSPACE_SPAN; SUBSPACE_SUB]);;
+
+let SPAN_VSUM = prove
+ (`!s f t. FINITE t /\ (!x. x IN t ==> f(x) IN span(s))
+           ==> (vsum t f) IN span(s)`,
+  MESON_TAC[SUBSPACE_SPAN; SUBSPACE_VSUM]);;
+
+let SPAN_ADD_EQ = prove
+ (`!s x y. x IN span s ==> ((x + y) IN span s <=> y IN span s)`,
+  MESON_TAC[SPAN_ADD; SPAN_SUB; VECTOR_ARITH `(x + y) - x:real^N = y`]);;
+
+let SPAN_EQ_SELF = prove
+ (`!s. span s = s <=> subspace s`,
+  GEN_TAC THEN EQ_TAC THENL [MESON_TAC[SUBSPACE_SPAN]; ALL_TAC] THEN
+  DISCH_TAC THEN MATCH_MP_TAC SPAN_SUBSPACE THEN
+  ASM_REWRITE_TAC[SUBSET_REFL; SPAN_INC]);;
+
+let SPAN_OF_SUBSPACE = prove
+ (`!s:real^N->bool. subspace s ==> span s = s`,
+  REWRITE_TAC[SPAN_EQ_SELF]);;
+
+let SPAN_SUBSET_SUBSPACE = prove
+ (`!s t:real^N->bool. s SUBSET t /\ subspace t ==> span s SUBSET t`,
+  MESON_TAC[SPAN_MONO; SPAN_EQ_SELF]);;
+
+let SUBSPACE_TRANSLATION_SELF = prove
+ (`!s a. subspace s /\ a IN s ==> IMAGE (\x. a + x) s = s`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SURJECTIVE_IMAGE_EQ THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM o GEN_REWRITE_RULE I [GSYM SPAN_EQ_SELF]) THEN
+  ASM_SIMP_TAC[SPAN_ADD_EQ; SPAN_CLAUSES] THEN
+  REWRITE_TAC[VECTOR_ARITH `a + x:real^N = y <=> x = y - a`; EXISTS_REFL]);;
+
+let SUBSPACE_TRANSLATION_SELF_EQ = prove
+ (`!s a:real^N. subspace s ==> (IMAGE (\x. a + x) s = s <=> a IN s)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN
+  ASM_SIMP_TAC[SUBSPACE_TRANSLATION_SELF] THEN
+  DISCH_THEN(MP_TAC o AP_TERM `\s. (a:real^N) IN s`) THEN
+  REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+  REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `vec 0:real^N` THEN
+  ASM_MESON_TAC[subspace; VECTOR_ADD_RID]);;
+
+let SUBSPACE_SUMS = prove
+ (`!s t. subspace s /\ subspace t
+         ==> subspace {x + y | x IN s /\ y IN t}`,
+  REWRITE_TAC[subspace; FORALL_IN_GSPEC; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN REPEAT STRIP_TAC THENL
+   [ASM_MESON_TAC[VECTOR_ADD_LID];
+    ONCE_REWRITE_TAC[VECTOR_ARITH
+     `(x + y) + (x' + y'):real^N = (x + x') + (y + y')`] THEN
+    ASM_MESON_TAC[];
+    REWRITE_TAC[VECTOR_ADD_LDISTRIB] THEN ASM_MESON_TAC[]]);;
+
+let SPAN_UNION = prove
+ (`!s t. span(s UNION t) = {x + y:real^N | x IN span s /\ y IN span t}`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SPAN_SUBSET_SUBSPACE THEN
+    SIMP_TAC[SUBSPACE_SUMS; SUBSPACE_SPAN] THEN
+    REWRITE_TAC[SUBSET; IN_UNION; IN_ELIM_THM] THEN
+    X_GEN_TAC `x:real^N` THEN STRIP_TAC THENL
+     [MAP_EVERY EXISTS_TAC [`x:real^N`; `vec 0:real^N`] THEN
+      ASM_SIMP_TAC[SPAN_SUPERSET; SPAN_0; VECTOR_ADD_RID];
+      MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `x:real^N`] THEN
+      ASM_SIMP_TAC[SPAN_SUPERSET; SPAN_0; VECTOR_ADD_LID]];
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC SPAN_ADD THEN
+    ASM_MESON_TAC[SPAN_MONO; SUBSET_UNION; SUBSET]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Mapping under linear image.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let SPAN_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s. linear f ==> (span(IMAGE f s) = IMAGE f (span s))`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC I [EXTENSION] THEN
+  X_GEN_TAC `x:real^N` THEN EQ_TAC THENL
+   [SPEC_TAC(`x:real^N`,`x:real^N`) THEN MATCH_MP_TAC SPAN_INDUCT THEN
+    REWRITE_TAC[SET_RULE `(\x. x IN s) = s`] THEN
+    ASM_SIMP_TAC[SUBSPACE_SPAN; SUBSPACE_LINEAR_IMAGE] THEN
+    REWRITE_TAC[FORALL_IN_IMAGE] THEN REWRITE_TAC[IN_IMAGE] THEN
+    MESON_TAC[SPAN_SUPERSET; SUBSET];
+    SPEC_TAC(`x:real^N`,`x:real^N`) THEN REWRITE_TAC[FORALL_IN_IMAGE] THEN
+    MATCH_MP_TAC SPAN_INDUCT THEN
+    REWRITE_TAC[SET_RULE `(\x. f x IN span(s)) = {x | f(x) IN span s}`] THEN
+    ASM_SIMP_TAC[SUBSPACE_LINEAR_PREIMAGE; SUBSPACE_SPAN] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    MESON_TAC[SPAN_SUPERSET; SUBSET; IN_IMAGE]]);;
+
+let DEPENDENT_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (dependent(IMAGE f s) <=> dependent s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[dependent; EXISTS_IN_IMAGE] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `a:real^M` THEN
+  ASM_CASES_TAC `(a:real^M) IN s` THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `(f:real^M->real^N) a IN span(IMAGE f (s DELETE a))` THEN
+  CONJ_TAC THENL
+   [AP_TERM_TAC THEN AP_TERM_TAC THEN ASM SET_TAC[];
+    ASM_SIMP_TAC[SPAN_LINEAR_IMAGE] THEN ASM SET_TAC[]]);;
+
+let DEPENDENT_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
+        dependent(s)
+        ==> dependent(IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[dependent; EXISTS_IN_IMAGE] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `a:real^M` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  SUBGOAL_THEN `IMAGE (f:real^M->real^N) s DELETE f a = IMAGE f (s DELETE a)`
+   (fun th -> ASM_SIMP_TAC[FUN_IN_IMAGE; SPAN_LINEAR_IMAGE; th]) THEN
+  ASM SET_TAC[]);;
+
+let INDEPENDENT_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (independent(IMAGE f s) <=> independent s)`,
+  REWRITE_TAC[independent; TAUT `(~p <=> ~q) <=> (p <=> q)`] THEN
+  REWRITE_TAC[DEPENDENT_LINEAR_IMAGE_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The key breakdown property.                                               *)
+(* ------------------------------------------------------------------------- *)
+
+let SPAN_BREAKDOWN = prove
+ (`!b s a:real^N.
+      b IN s /\ a IN span s ==> ?k. (a - k % b) IN span(s DELETE b)`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REPEAT GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC SPAN_INDUCT THEN
+  REWRITE_TAC[subspace; IN_ELIM_THM] THEN CONJ_TAC THENL
+   [GEN_TAC THEN DISCH_TAC THEN ASM_CASES_TAC `a:real^N = b`; ALL_TAC] THEN
+  ASM_MESON_TAC[SPAN_CLAUSES; IN_DELETE; VECTOR_ARITH
+   `(a - &1 % a = vec 0) /\ (a - &0 % b = a) /\
+    ((x + y) - (k1 + k2) % b = (x - k1 % b) + (y - k2 % b)) /\
+    (c % x - (c * k) % y = c % (x - k % y))`]);;
+
+let SPAN_BREAKDOWN_EQ = prove
+ (`!a:real^N s. (x IN span(a INSERT s) <=> (?k. (x - k % a) IN span s))`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [DISCH_THEN(MP_TAC o CONJ(SET_RULE `(a:real^N) IN (a INSERT s)`)) THEN
+    DISCH_THEN(MP_TAC o MATCH_MP SPAN_BREAKDOWN) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `k:real` THEN
+    SPEC_TAC(`x - k % a:real^N`,`y:real^N`) THEN
+    REWRITE_TAC[GSYM SUBSET] THEN MATCH_MP_TAC SPAN_MONO THEN SET_TAC[];
+    DISCH_THEN(X_CHOOSE_TAC `k:real`) THEN
+    SUBST1_TAC(VECTOR_ARITH `x = (x - k % a) + k % a:real^N`) THEN
+    MATCH_MP_TAC SPAN_ADD THEN
+    ASM_MESON_TAC[SPAN_MONO; SUBSET; IN_INSERT; SPAN_CLAUSES]]);;
+
+let SPAN_INSERT_0 = prove
+ (`!s. span(vec 0 INSERT s) = span s`,
+  SIMP_TAC[EXTENSION; SPAN_BREAKDOWN_EQ; VECTOR_MUL_RZERO; VECTOR_SUB_RZERO]);;
+
+let SPAN_SING = prove
+ (`!a. span {a} = {u % a | u IN (:real)}`,
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; SPAN_BREAKDOWN_EQ; SPAN_EMPTY] THEN
+  REWRITE_TAC[IN_UNIV; IN_SING; VECTOR_SUB_EQ]);;
+
+let SPAN_2 = prove
+ (`!a b. span {a,b} = {u % a + v % b | u IN (:real) /\ v IN (:real)}`,
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; SPAN_BREAKDOWN_EQ; SPAN_EMPTY] THEN
+  REWRITE_TAC[IN_UNIV; IN_SING; VECTOR_SUB_EQ] THEN
+  REWRITE_TAC[VECTOR_ARITH `x - y:real^N = z <=> x = y + z`]);;
+
+let SPAN_3 = prove
+ (`!a b c. span {a,b,c} =
+      {u % a + v % b + w % c | u IN (:real) /\ v IN (:real) /\ w IN (:real)}`,
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM; SPAN_BREAKDOWN_EQ; SPAN_EMPTY] THEN
+  REWRITE_TAC[IN_UNIV; IN_SING; VECTOR_SUB_EQ] THEN
+  REWRITE_TAC[VECTOR_ARITH `x - y:real^N = z <=> x = y + z`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence some "reversal" results.                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let IN_SPAN_INSERT = prove
+ (`!a b:real^N s.
+        a IN span(b INSERT s) /\ ~(a IN span s) ==> b IN span(a INSERT s)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`b:real^N`; `(b:real^N) INSERT s`; `a:real^N`]
+    SPAN_BREAKDOWN) THEN ASM_REWRITE_TAC[IN_INSERT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real` MP_TAC) THEN ASM_CASES_TAC `k = &0` THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH `a - &0 % b = a`; DELETE_INSERT] THENL
+   [ASM_MESON_TAC[SPAN_MONO; SUBSET; DELETE_SUBSET]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `inv(k)` o MATCH_MP SPAN_MUL) THEN
+  ASM_SIMP_TAC[VECTOR_SUB_LDISTRIB; VECTOR_MUL_ASSOC; REAL_MUL_LINV] THEN
+  DISCH_TAC THEN SUBST1_TAC(VECTOR_ARITH
+   `b:real^N = inv(k) % a - (inv(k) % a - &1 % b)`) THEN
+  MATCH_MP_TAC SPAN_SUB THEN
+  ASM_MESON_TAC[SPAN_CLAUSES; IN_INSERT; SUBSET; IN_DELETE; SPAN_MONO]);;
+
+let IN_SPAN_DELETE = prove
+ (`!a b s.
+         a IN span s /\ ~(a IN span (s DELETE b))
+         ==> b IN span (a INSERT (s DELETE b))`,
+  ASM_MESON_TAC[IN_SPAN_INSERT; SPAN_MONO; SUBSET; IN_INSERT; IN_DELETE]);;
+
+let EQ_SPAN_INSERT_EQ = prove
+ (`!s x y:real^N. (x - y) IN span s ==> span(x INSERT s) = span(y INSERT s)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[SPAN_BREAKDOWN_EQ; EXTENSION] THEN
+  ASM_MESON_TAC[SPAN_ADD; SPAN_SUB; SPAN_MUL;
+                VECTOR_ARITH `(z - k % y) - k % (x - y) = z - k % x`;
+                VECTOR_ARITH `(z - k % x) + k % (x - y) = z - k % y`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Transitivity property.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let SPAN_TRANS = prove
+ (`!x y:real^N s. x IN span(s) /\ y IN span(x INSERT s) ==> y IN span(s)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(SPECL [`x:real^N`; `(x:real^N) INSERT s`; `y:real^N`]
+         SPAN_BREAKDOWN) THEN
+  ASM_REWRITE_TAC[IN_INSERT] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN
+  SUBST1_TAC(VECTOR_ARITH `y:real^N = (y - k % x) + k % x`) THEN
+  MATCH_MP_TAC SPAN_ADD THEN ASM_SIMP_TAC[SPAN_MUL] THEN
+  ASM_MESON_TAC[SPAN_MONO; SUBSET; IN_INSERT; IN_DELETE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* An explicit expansion is sometimes needed.                                *)
+(* ------------------------------------------------------------------------- *)
+
+let SPAN_EXPLICIT = prove
+ (`!(p:real^N -> bool).
+        span p =
+         {y | ?s u. FINITE s /\ s SUBSET p /\
+                    vsum s (\v. u v % v) = y}`,
+  GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [ALL_TAC;
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+    REPEAT STRIP_TAC THEN FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    MATCH_MP_TAC SPAN_VSUM THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[SPAN_SUPERSET; SPAN_MUL]] THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+  MATCH_MP_TAC SPAN_INDUCT_ALT THEN CONJ_TAC THENL
+   [EXISTS_TAC `{}:real^N->bool` THEN
+    REWRITE_TAC[FINITE_RULES; VSUM_CLAUSES; EMPTY_SUBSET; NOT_IN_EMPTY];
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`c:real`; `x:real^N`; `y:real^N`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`s:real^N->bool`; `u:real^N->real`] THEN
+  STRIP_TAC THEN EXISTS_TAC `(x:real^N) INSERT s` THEN
+  EXISTS_TAC `\y. if y = x then (if x IN s then (u:real^N->real) y + c else c)
+                  else u y` THEN
+  ASM_SIMP_TAC[FINITE_INSERT; IN_INSERT; VSUM_CLAUSES] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
+  FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
+   [FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP (SET_RULE
+     `x IN s ==> s = x INSERT (s DELETE x)`)) THEN
+    ASM_SIMP_TAC[VSUM_CLAUSES; FINITE_INSERT; FINITE_DELETE; IN_DELETE] THEN
+    MATCH_MP_TAC(VECTOR_ARITH
+      `y = z ==> (c + d) % x + y = d % x + c % x + z`);
+    AP_TERM_TAC] THEN
+  MATCH_MP_TAC VSUM_EQ THEN ASM_MESON_TAC[IN_DELETE]);;
+
+let DEPENDENT_EXPLICIT = prove
+ (`!p. dependent (p:real^N -> bool) <=>
+                ?s u. FINITE s /\ s SUBSET p /\
+                      (?v. v IN s /\ ~(u v = &0)) /\
+                      vsum s (\v. u v % v) = vec 0`,
+  GEN_TAC THEN REWRITE_TAC[dependent; SPAN_EXPLICIT; IN_ELIM_THM] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM; LEFT_AND_EXISTS_THM] THEN
+  EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+   [MAP_EVERY X_GEN_TAC [`a:real^N`; `s:real^N->bool`; `u:real^N->real`] THEN
+    STRIP_TAC THEN MAP_EVERY EXISTS_TAC
+     [`(a:real^N) INSERT s`;
+      `\y. if y = a then -- &1 else (u:real^N->real) y`;
+      `a:real^N`] THEN
+    ASM_REWRITE_TAC[IN_INSERT; INSERT_SUBSET; FINITE_INSERT] THEN
+    CONJ_TAC THENL [ASM SET_TAC[]; CONV_TAC REAL_RAT_REDUCE_CONV] THEN
+    ASM_SIMP_TAC[VSUM_CLAUSES] THEN
+    COND_CASES_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    REWRITE_TAC[VECTOR_ARITH `-- &1 % a + s = vec 0 <=> a = s`] THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV [SYM th]) THEN
+    MATCH_MP_TAC VSUM_EQ THEN ASM SET_TAC[];
+    MAP_EVERY X_GEN_TAC [`s:real^N->bool`; `u:real^N->real`; `a:real^N`] THEN
+    STRIP_TAC THEN MAP_EVERY EXISTS_TAC
+     [`a:real^N`; `s DELETE (a:real^N)`;
+      `\i. --((u:real^N->real) i) / (u a)`] THEN
+    ASM_SIMP_TAC[VSUM_DELETE; FINITE_DELETE] THEN
+    REPEAT(CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+    REWRITE_TAC[real_div] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_LNEG; GSYM VECTOR_MUL_ASSOC; VSUM_LMUL;
+                    VSUM_NEG; VECTOR_MUL_RNEG; VECTOR_MUL_RZERO] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV] THEN VECTOR_ARITH_TAC]);;
+
+let DEPENDENT_FINITE = prove
+ (`!s:real^N->bool.
+        FINITE s
+        ==> (dependent s <=> ?u. (?v. v IN s /\ ~(u v = &0)) /\
+                                 vsum s (\v. u(v) % v) = vec 0)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[DEPENDENT_EXPLICIT] THEN EQ_TAC THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+   [MAP_EVERY X_GEN_TAC [`t:real^N->bool`; `u:real^N->real`] THEN
+    DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+    EXISTS_TAC `\v:real^N. if v IN t then u(v) else &0` THEN
+    REWRITE_TAC[] THEN CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+    ONCE_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_LZERO; GSYM VSUM_RESTRICT_SET] THEN
+    ASM_SIMP_TAC[SET_RULE `t SUBSET s ==> {x | x IN s /\ x IN t} = t`];
+    GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
+    MAP_EVERY EXISTS_TAC [`s:real^N->bool`; `u:real^N->real`] THEN
+    ASM_REWRITE_TAC[SUBSET_REFL]]);;
+
+let SPAN_FINITE = prove
+ (`!s:real^N->bool.
+        FINITE s ==> span s = {y | ?u. vsum s (\v. u v % v) = y}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[SPAN_EXPLICIT; EXTENSION; IN_ELIM_THM] THEN
+  X_GEN_TAC `y:real^N` THEN EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+   [MAP_EVERY X_GEN_TAC [`t:real^N->bool`; `u:real^N->real`] THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    EXISTS_TAC `\x:real^N. if x IN t then u(x) else &0` THEN
+    REWRITE_TAC[COND_RAND; COND_RATOR; VECTOR_MUL_LZERO] THEN
+    ASM_SIMP_TAC[GSYM VSUM_RESTRICT_SET] THEN
+    ASM_SIMP_TAC[SET_RULE `t SUBSET s ==> {x | x IN s /\ x IN t} = t`];
+    X_GEN_TAC `u:real^N->real` THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+    MAP_EVERY EXISTS_TAC [`s:real^N->bool`; `u:real^N->real`] THEN
+    ASM_REWRITE_TAC[SUBSET_REFL]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Standard bases are a spanning set, and obviously finite.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let SPAN_STDBASIS = prove
+ (`span {basis i :real^N | 1 <= i /\ i <= dimindex(:N)} = UNIV`,
+  REWRITE_TAC[EXTENSION; IN_UNIV] THEN X_GEN_TAC `x:real^N` THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM BASIS_EXPANSION] THEN
+  MATCH_MP_TAC SPAN_VSUM THEN SIMP_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SPAN_MUL THEN
+  MATCH_MP_TAC SPAN_SUPERSET THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  ASM_MESON_TAC[]);;
+
+let HAS_SIZE_STDBASIS = prove
+ (`{basis i :real^N | 1 <= i /\ i <= dimindex(:N)} HAS_SIZE
+        dimindex(:N)`,
+  ONCE_REWRITE_TAC[SET_RULE `{f x | P x} = IMAGE f {x | P x}`] THEN
+  MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN
+  REWRITE_TAC[GSYM numseg; HAS_SIZE_NUMSEG_1; IN_NUMSEG] THEN
+  MESON_TAC[BASIS_INJ]);;
+
+let FINITE_STDBASIS = prove
+ (`FINITE {basis i :real^N | 1 <= i /\ i <= dimindex(:N)}`,
+  MESON_TAC[HAS_SIZE_STDBASIS; HAS_SIZE]);;
+
+let CARD_STDBASIS = prove
+ (`CARD {basis i :real^N | 1 <= i /\ i <= dimindex(:N)} =
+        dimindex(:N)`,
+   MESON_TAC[HAS_SIZE_STDBASIS; HAS_SIZE]);;
+
+let IN_SPAN_IMAGE_BASIS = prove
+ (`!x:real^N s.
+        x IN span(IMAGE basis s) <=>
+          !i. 1 <= i /\ i <= dimindex(:N) /\ ~(i IN s) ==> x$i = &0`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [SPEC_TAC(`x:real^N`,`x:real^N`) THEN MATCH_MP_TAC SPAN_INDUCT THEN
+    SIMP_TAC[subspace; IN_ELIM_THM; VEC_COMPONENT; VECTOR_ADD_COMPONENT;
+             VECTOR_MUL_COMPONENT; REAL_MUL_RZERO; REAL_ADD_RID] THEN
+    SIMP_TAC[FORALL_IN_IMAGE; BASIS_COMPONENT] THEN MESON_TAC[];
+    DISCH_TAC THEN REWRITE_TAC[SPAN_EXPLICIT; IN_ELIM_THM] THEN
+    EXISTS_TAC `(IMAGE basis ((1..dimindex(:N)) INTER s)):real^N->bool` THEN
+    SIMP_TAC[FINITE_IMAGE; FINITE_INTER; FINITE_NUMSEG] THEN
+    REWRITE_TAC[RIGHT_EXISTS_AND_THM] THEN
+    CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+    EXISTS_TAC `\v:real^N. x dot v` THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) VSUM_IMAGE o lhand o snd) THEN
+    ANTS_TAC THENL
+     [SIMP_TAC[FINITE_IMAGE; FINITE_INTER; FINITE_NUMSEG] THEN
+      REWRITE_TAC[IN_INTER; IN_NUMSEG] THEN MESON_TAC[BASIS_INJ];
+      DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[]] THEN
+    REWRITE_TAC[o_DEF] THEN
+    SIMP_TAC[CART_EQ; VSUM_COMPONENT; VECTOR_MUL_COMPONENT;
+             BASIS_COMPONENT] THEN
+    ONCE_REWRITE_TAC[COND_RAND] THEN
+    ONCE_REWRITE_TAC[MESON[]
+     `(if x = y then p else q) = (if y = x then p else q)`] THEN
+    SIMP_TAC[SUM_DELTA; REAL_MUL_RZERO; IN_INTER; IN_NUMSEG; DOT_BASIS] THEN
+    ASM_MESON_TAC[REAL_MUL_RID]]);;
+
+let INDEPENDENT_STDBASIS = prove
+ (`independent {basis i :real^N | 1 <= i /\ i <= dimindex(:N)}`,
+  REWRITE_TAC[independent; dependent] THEN
+  ONCE_REWRITE_TAC[SET_RULE `{f x | P x} = IMAGE f {x | P x}`] THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE] THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:num` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  SUBGOAL_THEN
+   `IMAGE basis {i | 1 <= i /\ i <= dimindex(:N)} DELETE
+           (basis k:real^N) =
+    IMAGE basis ({i | 1 <= i /\ i <= dimindex(:N)} DELETE k)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_IMAGE; IN_DELETE; IN_ELIM_THM] THEN
+    GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[BASIS_INJ];
+    ALL_TAC] THEN
+  REWRITE_TAC[IN_SPAN_IMAGE_BASIS] THEN DISCH_THEN(MP_TAC o SPEC `k:num`) THEN
+  ASM_SIMP_TAC[IN_DELETE; BASIS_COMPONENT; REAL_OF_NUM_EQ; ARITH]);;
+
+(* ------------------------------------------------------------------------- *)
+(* This is useful for building a basis step-by-step.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let INDEPENDENT_INSERT = prove
+ (`!a:real^N s. independent(a INSERT s) <=>
+                  if a IN s then independent s
+                  else independent s /\ ~(a IN span s)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `(a:real^N) IN s` THEN
+  ASM_SIMP_TAC[SET_RULE `x IN s ==> (x INSERT s = s)`] THEN
+  EQ_TAC THENL
+   [DISCH_TAC THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[INDEPENDENT_MONO; SUBSET; IN_INSERT];
+      POP_ASSUM MP_TAC THEN REWRITE_TAC[independent; dependent] THEN
+      ASM_MESON_TAC[IN_INSERT; SET_RULE
+        `~(a IN s) ==> ((a INSERT s) DELETE a = s)`]];
+    ALL_TAC] THEN
+  REWRITE_TAC[independent; dependent; NOT_EXISTS_THM] THEN
+  STRIP_TAC THEN X_GEN_TAC `b:real^N` THEN
+  REWRITE_TAC[IN_INSERT] THEN ASM_CASES_TAC `b:real^N = a` THEN
+  ASM_SIMP_TAC[SET_RULE `~(a IN s) ==> ((a INSERT s) DELETE a = s)`] THEN
+  ASM_SIMP_TAC[SET_RULE
+    `~(a IN s) /\ ~(b = a)
+     ==> ((a INSERT s) DELETE b = a INSERT (s DELETE b))`] THEN
+  ASM_MESON_TAC[IN_SPAN_INSERT; SET_RULE
+    `b IN s ==> (b INSERT (s DELETE b) = s)`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The degenerate case of the Exchange Lemma.                                *)
+(* ------------------------------------------------------------------------- *)
+
+let SPANNING_SUBSET_INDEPENDENT = prove
+ (`!s t:real^N->bool.
+        t SUBSET s /\ independent s /\ s SUBSET span(t) ==> (s = t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  ASM_REWRITE_TAC[] THEN REWRITE_TAC[SUBSET] THEN
+  X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [independent]) THEN
+  REWRITE_TAC[dependent; NOT_EXISTS_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `a:real^N`) THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[SPAN_MONO; SUBSET; IN_DELETE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The general case of the Exchange Lemma, the key to what follows.          *)
+(* ------------------------------------------------------------------------- *)
+
+let EXCHANGE_LEMMA = prove
+ (`!s t:real^N->bool.
+        FINITE t /\ independent s /\ s SUBSET span t
+        ==> ?t'. t' HAS_SIZE (CARD t) /\
+                 s SUBSET t' /\ t' SUBSET (s UNION t) /\ s SUBSET (span t')`,
+  REPEAT GEN_TAC THEN
+  WF_INDUCT_TAC `CARD(t DIFF s :real^N->bool)` THEN
+  ASM_CASES_TAC `(s:real^N->bool) SUBSET t` THENL
+   [ASM_MESON_TAC[HAS_SIZE; SUBSET_UNION]; ALL_TAC] THEN
+  ASM_CASES_TAC `t SUBSET (s:real^N->bool)` THENL
+   [ASM_MESON_TAC[SPANNING_SUBSET_INDEPENDENT; HAS_SIZE]; ALL_TAC] THEN
+  STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o REWRITE_RULE[SUBSET] o check(is_neg o concl)) THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N` STRIP_ASSUME_TAC) THEN
+  ASM_CASES_TAC `s SUBSET span(t DELETE (b:real^N))` THENL
+   [FIRST_X_ASSUM(MP_TAC o
+     SPECL [`t DELETE (b:real^N)`; `s:real^N->bool`]) THEN
+    ASM_REWRITE_TAC[SET_RULE `s DELETE a DIFF t = (s DIFF t) DELETE a`] THEN
+    ASM_SIMP_TAC[CARD_DELETE; FINITE_DIFF; IN_DIFF; FINITE_DELETE;
+                 CARD_EQ_0; ARITH_RULE `n - 1 < n <=> ~(n = 0)`] THEN
+    ANTS_TAC THENL
+     [UNDISCH_TAC `~((s:real^N->bool) SUBSET t)` THEN ASM SET_TAC[];
+      ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(b:real^N) INSERT u` THEN
+    ASM_SIMP_TAC[SUBSET_INSERT; INSERT_SUBSET; IN_UNION] THEN CONJ_TAC THENL
+     [UNDISCH_TAC `(u:real^N->bool) HAS_SIZE CARD(t:real^N->bool) - 1` THEN
+      SIMP_TAC[HAS_SIZE; FINITE_RULES; CARD_CLAUSES] THEN STRIP_TAC THEN
+      COND_CASES_TAC THENL
+       [ASM_MESON_TAC[SUBSET; IN_UNION; IN_DELETE]; ALL_TAC] THEN
+      ASM_MESON_TAC[ARITH_RULE `~(n = 0) ==> (SUC(n - 1) = n)`;
+                    CARD_EQ_0; MEMBER_NOT_EMPTY];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [UNDISCH_TAC `u SUBSET s UNION t DELETE (b:real^N)` THEN SET_TAC[];
+      ASM_MESON_TAC[SUBSET; SPAN_MONO; IN_INSERT]];
+    ALL_TAC] THEN
+  UNDISCH_TAC `~(s SUBSET span (t DELETE (b:real^N)))` THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [SUBSET] THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `~(a:real^N = b)` ASSUME_TAC THENL
+    [ASM_MESON_TAC[]; ALL_TAC] THEN
+  SUBGOAL_THEN `~((a:real^N) IN t)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[IN_DELETE; SPAN_CLAUSES]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+   [`(a:real^N) INSERT (t DELETE b)`; `s:real^N->bool`]) THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[SET_RULE
+     `a IN s ==> ((a INSERT (t DELETE b) DIFF s) = (t DIFF s) DELETE b)`] THEN
+    ASM_SIMP_TAC[CARD_DELETE; FINITE_DELETE; FINITE_DIFF; IN_DIFF] THEN
+    ASM_SIMP_TAC[ARITH_RULE `n - 1 < n <=> ~(n = 0)`; CARD_EQ_0;
+                 FINITE_DIFF] THEN
+    UNDISCH_TAC `~((s:real^N->bool) SUBSET t)` THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ANTS_TAC THENL
+   [ASM_SIMP_TAC[FINITE_RULES; FINITE_DELETE] THEN
+    REWRITE_TAC[SUBSET] THEN X_GEN_TAC `x:real^N` THEN
+    DISCH_TAC THEN MATCH_MP_TAC SPAN_TRANS THEN EXISTS_TAC `b:real^N` THEN
+    ASM_MESON_TAC[IN_SPAN_DELETE; SUBSET; SPAN_MONO;
+                  SET_RULE `t SUBSET (b INSERT (a INSERT (t DELETE b)))`];
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `u:real^N->bool` THEN
+  ASM_SIMP_TAC[HAS_SIZE; CARD_CLAUSES; CARD_DELETE; FINITE_DELETE; IN_DELETE;
+               ARITH_RULE `(SUC(n - 1) = n) <=> ~(n = 0)`;
+               CARD_EQ_0] THEN
+  UNDISCH_TAC `(b:real^N) IN t` THEN ASM SET_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* This implies corresponding size bounds.                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let INDEPENDENT_SPAN_BOUND = prove
+ (`!s t. FINITE t /\ independent s /\ s SUBSET span(t)
+         ==> FINITE s /\ CARD(s) <= CARD(t)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP EXCHANGE_LEMMA) THEN
+  ASM_MESON_TAC[HAS_SIZE; CARD_SUBSET; FINITE_SUBSET]);;
+
+let INDEPENDENT_BOUND = prove
+ (`!s:real^N->bool.
+        independent s ==> FINITE s /\ CARD(s) <= dimindex(:N)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[GSYM CARD_STDBASIS] THEN
+  MATCH_MP_TAC INDEPENDENT_SPAN_BOUND THEN
+  ASM_REWRITE_TAC[FINITE_STDBASIS; SPAN_STDBASIS; SUBSET_UNIV]);;
+
+let DEPENDENT_BIGGERSET = prove
+ (`!s:real^N->bool. (FINITE s ==> CARD(s) > dimindex(:N)) ==> dependent s`,
+  MP_TAC INDEPENDENT_BOUND THEN MATCH_MP_TAC MONO_FORALL THEN
+  REWRITE_TAC[GT; GSYM NOT_LE; independent] THEN MESON_TAC[]);;
+
+let INDEPENDENT_IMP_FINITE = prove
+ (`!s:real^N->bool. independent s ==> FINITE s`,
+  SIMP_TAC[INDEPENDENT_BOUND]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Explicit formulation of independence.                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let INDEPENDENT_EXPLICIT = prove
+ (`!b:real^N->bool.
+        independent b <=>
+            FINITE b /\
+            !c. vsum b (\v. c(v) % v) = vec 0 ==> !v. v IN b ==> c(v) = &0`,
+  GEN_TAC THEN
+  ASM_CASES_TAC `FINITE(b:real^N->bool)` THENL
+   [ALL_TAC; ASM_MESON_TAC[INDEPENDENT_BOUND]] THEN
+  ASM_SIMP_TAC[independent; DEPENDENT_FINITE] THEN MESON_TAC[]);;
+
+let INDEPENDENT_SING = prove
+ (`!x. independent {x} <=> ~(x = vec 0)`,
+  REWRITE_TAC[INDEPENDENT_INSERT; NOT_IN_EMPTY; SPAN_EMPTY] THEN
+  REWRITE_TAC[INDEPENDENT_EMPTY] THEN SET_TAC[]);;
+
+let DEPENDENT_SING = prove
+ (`!x. dependent {x} <=> x = vec 0`,
+  MESON_TAC[independent; INDEPENDENT_SING]);;
+
+let DEPENDENT_2 = prove
+ (`!a b:real^N.
+        dependent {a,b} <=>
+                if a = b then a = vec 0
+                else ?x y. x % a + y % b = vec 0 /\ ~(x = &0 /\ y = &0)`,
+  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN
+  ASM_REWRITE_TAC[DEPENDENT_SING; SET_RULE `{x,x} = {x}`] THEN
+  SIMP_TAC[DEPENDENT_FINITE; VSUM_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN
+  ASM_REWRITE_TAC[IN_SING; NOT_IN_EMPTY; VECTOR_ADD_RID; EXISTS_IN_INSERT] THEN
+  EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+   [X_GEN_TAC `u:real^N->real` THEN STRIP_TAC THEN
+    MAP_EVERY EXISTS_TAC [`(u:real^N->real) a`; `(u:real^N->real) b`] THEN
+    ASM_REWRITE_TAC[];
+    MAP_EVERY X_GEN_TAC [`x:real`; `y:real`] THEN DISCH_TAC THEN EXISTS_TAC
+     `\v:real^N. if v = a then x else if v = b then y else z:real` THEN
+    ASM_MESON_TAC[]]);;
+
+let DEPENDENT_3 = prove
+ (`!a b c:real^N.
+        ~(a = b) /\ ~(a = c) /\ ~(b = c)
+        ==> (dependent {a,b,c} <=>
+             ?x y z. x % a + y % b + z % c = vec 0 /\
+                     ~(x = &0 /\ y = &0 /\ z = &0))`,
+  REPEAT STRIP_TAC THEN
+  SIMP_TAC[DEPENDENT_FINITE; VSUM_CLAUSES; FINITE_INSERT; FINITE_EMPTY] THEN
+  ASM_REWRITE_TAC[IN_SING; NOT_IN_EMPTY; VECTOR_ADD_RID; IN_INSERT] THEN
+  EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+   [X_GEN_TAC `u:real^N->real` THEN STRIP_TAC THEN MAP_EVERY EXISTS_TAC
+     [`(u:real^N->real) a`; `(u:real^N->real) b`; `(u:real^N->real) c`];
+    MAP_EVERY X_GEN_TAC [`x:real`; `y:real`; `z:real`] THEN DISCH_TAC THEN
+    EXISTS_TAC
+     `\v:real^N. if v = a then x else if v = b then y else z:real`] THEN
+  ASM_MESON_TAC[]);;
+
+let INDEPENDENT_2 = prove
+ (`!a b:real^N x y.
+        independent{a,b} /\ ~(a = b)
+        ==> (x % a + y % b = vec 0 <=> x = &0 /\ y = &0)`,
+  SIMP_TAC[IMP_CONJ_ALT; independent; DEPENDENT_2] THEN
+  MESON_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_LID]);;
+
+let INDEPENDENT_3 = prove
+ (`!a b c:real^N x y z.
+        independent{a,b,c} /\ ~(a = b) /\ ~(a = c) /\ ~(b = c)
+        ==> (x % a + y % b + z % c = vec 0 <=> x = &0 /\ y = &0 /\ z = &0)`,
+  SIMP_TAC[IMP_CONJ_ALT; independent; DEPENDENT_3] THEN
+  MESON_TAC[VECTOR_MUL_LZERO; VECTOR_ADD_LID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence we can create a maximal independent subset.                         *)
+(* ------------------------------------------------------------------------- *)
+
+let MAXIMAL_INDEPENDENT_SUBSET_EXTEND = prove
+ (`!s v:real^N->bool.
+        s SUBSET v /\ independent s
+        ==> ?b. s SUBSET b /\ b SUBSET v /\ independent b /\
+                v SUBSET (span b)`,
+  REPEAT GEN_TAC THEN
+  WF_INDUCT_TAC `dimindex(:N) - CARD(s:real^N->bool)` THEN
+  REPEAT STRIP_TAC THEN
+  ASM_CASES_TAC `v SUBSET (span(s:real^N->bool))` THENL
+   [ASM_MESON_TAC[SUBSET_REFL]; ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [SUBSET]) THEN
+  REWRITE_TAC[NOT_FORALL_THM; NOT_IMP] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPEC `(a:real^N) INSERT s`) THEN
+  REWRITE_TAC[IMP_IMP] THEN ANTS_TAC THENL
+   [ALL_TAC; MESON_TAC[INSERT_SUBSET]] THEN
+  SUBGOAL_THEN `independent ((a:real^N) INSERT s)` ASSUME_TAC THENL
+   [ASM_REWRITE_TAC[INDEPENDENT_INSERT; COND_ID]; ALL_TAC] THEN
+  ASM_REWRITE_TAC[INSERT_SUBSET] THEN
+  MATCH_MP_TAC(ARITH_RULE `(b = a + 1) /\ b <= n ==> n - b < n - a`) THEN
+  ASM_SIMP_TAC[CARD_CLAUSES; INDEPENDENT_BOUND] THEN
+  ASM_MESON_TAC[SPAN_SUPERSET; ADD1]);;
+
+let MAXIMAL_INDEPENDENT_SUBSET = prove
+ (`!v:real^N->bool. ?b. b SUBSET v /\ independent b /\ v SUBSET (span b)`,
+  MP_TAC(SPEC `EMPTY:real^N->bool` MAXIMAL_INDEPENDENT_SUBSET_EXTEND) THEN
+  REWRITE_TAC[EMPTY_SUBSET; INDEPENDENT_EMPTY]);;
+
+(* ------------------------------------------------------------------------- *)
+(* A kind of closed graph property for linearity.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_SUBSPACE_GRAPH = prove
+ (`!f:real^M->real^N.
+        linear f <=> subspace {pastecart x (f x) | x IN (:real^M)}`,
+  REWRITE_TAC[linear; subspace; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[FORALL_IN_GSPEC; GSYM(SPEC `0` PASTECART_VEC); IN_UNIV] THEN
+  REWRITE_TAC[IN_ELIM_THM; PASTECART_INJ; UNWIND_THM1; PASTECART_ADD;
+              GSYM PASTECART_CMUL] THEN
+  MESON_TAC[VECTOR_MUL_LZERO]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Notion of dimension.                                                      *)
+(* ------------------------------------------------------------------------- *)
+
+let dim = new_definition
+  `dim v = @n. ?b. b SUBSET v /\ independent b /\ v SUBSET (span b) /\
+                   b HAS_SIZE n`;;
+
+let BASIS_EXISTS = prove
+ (`!v. ?b. b SUBSET v /\ independent b /\ v SUBSET (span b) /\
+           b HAS_SIZE (dim v)`,
+  GEN_TAC THEN REWRITE_TAC[dim] THEN CONV_TAC SELECT_CONV THEN
+  MESON_TAC[MAXIMAL_INDEPENDENT_SUBSET; HAS_SIZE; INDEPENDENT_BOUND]);;
+
+let BASIS_EXISTS_FINITE = prove
+ (`!v. ?b. FINITE b /\
+           b SUBSET v /\
+           independent b /\
+           v SUBSET (span b) /\
+           b HAS_SIZE (dim v)`,
+  MESON_TAC[BASIS_EXISTS; INDEPENDENT_IMP_FINITE]);;
+
+let BASIS_SUBSPACE_EXISTS = prove
+ (`!s:real^N->bool.
+        subspace s
+        ==> ?b. FINITE b /\
+                b SUBSET s /\
+                independent b /\
+                span b = s /\
+                b HAS_SIZE dim s`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `s:real^N->bool` BASIS_EXISTS) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+  ASM_MESON_TAC[SPAN_EQ_SELF; SPAN_MONO; INDEPENDENT_IMP_FINITE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Consequences of independence or spanning for cardinality.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let INDEPENDENT_CARD_LE_DIM = prove
+ (`!v b:real^N->bool.
+        b SUBSET v /\ independent b ==> FINITE b /\ CARD(b) <= dim v`,
+  MESON_TAC[BASIS_EXISTS; INDEPENDENT_SPAN_BOUND; HAS_SIZE;SUBSET_TRANS]);;
+
+let SPAN_CARD_GE_DIM = prove
+ (`!v b:real^N->bool.
+        v SUBSET (span b) /\ FINITE b ==> dim(v) <= CARD(b)`,
+  MESON_TAC[BASIS_EXISTS; INDEPENDENT_SPAN_BOUND; HAS_SIZE;SUBSET_TRANS]);;
+
+let BASIS_CARD_EQ_DIM = prove
+ (`!v b. b SUBSET v /\ v SUBSET (span b) /\ independent b
+         ==> FINITE b /\ (CARD b = dim v)`,
+  MESON_TAC[LE_ANTISYM; INDEPENDENT_CARD_LE_DIM; SPAN_CARD_GE_DIM]);;
+
+let BASIS_HAS_SIZE_DIM = prove
+ (`!v b. independent b /\ span b = v ==> b HAS_SIZE (dim v)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[HAS_SIZE] THEN
+  MATCH_MP_TAC BASIS_CARD_EQ_DIM THEN ASM_REWRITE_TAC[SUBSET_REFL] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN REWRITE_TAC[SPAN_INC]);;
+
+let DIM_UNIQUE = prove
+ (`!v b. b SUBSET v /\ v SUBSET (span b) /\ independent b /\ b HAS_SIZE n
+         ==> (dim v = n)`,
+  MESON_TAC[BASIS_CARD_EQ_DIM; HAS_SIZE]);;
+
+let DIM_LE_CARD = prove
+ (`!s. FINITE s ==> dim s <= CARD s`,
+  GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC SPAN_CARD_GE_DIM THEN
+  ASM_REWRITE_TAC[SPAN_INC; SUBSET_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More lemmas about dimension.                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let DIM_UNIV = prove
+ (`dim(:real^N) = dimindex(:N)`,
+  MATCH_MP_TAC DIM_UNIQUE THEN
+  EXISTS_TAC `{basis i :real^N | 1 <= i /\ i <= dimindex(:N)}` THEN
+  REWRITE_TAC[SUBSET_UNIV; SPAN_STDBASIS; HAS_SIZE_STDBASIS;
+              INDEPENDENT_STDBASIS]);;
+
+let DIM_SUBSET = prove
+ (`!s t:real^N->bool. s SUBSET t ==> dim(s) <= dim(t)`,
+  MESON_TAC[BASIS_EXISTS; INDEPENDENT_SPAN_BOUND; SUBSET; HAS_SIZE]);;
+
+let DIM_SUBSET_UNIV = prove
+ (`!s:real^N->bool. dim(s) <= dimindex(:N)`,
+  GEN_TAC THEN REWRITE_TAC[GSYM DIM_UNIV] THEN
+  MATCH_MP_TAC DIM_SUBSET THEN REWRITE_TAC[SUBSET_UNIV]);;
+
+let BASIS_HAS_SIZE_UNIV = prove
+ (`!b. independent b /\ span b = (:real^N) ==> b HAS_SIZE (dimindex(:N))`,
+  REWRITE_TAC[GSYM DIM_UNIV; BASIS_HAS_SIZE_DIM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Converses to those.                                                       *)
+(* ------------------------------------------------------------------------- *)
+
+let CARD_GE_DIM_INDEPENDENT = prove
+ (`!v b:real^N->bool.
+        b SUBSET v /\ independent b /\ dim v <= CARD(b)
+        ==> v SUBSET (span b)`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `!a:real^N. ~(a IN v /\ ~(a IN span b))` MP_TAC THENL
+   [ALL_TAC; SET_TAC[]] THEN
+  X_GEN_TAC `a:real^N` THEN STRIP_TAC THEN
+  SUBGOAL_THEN `independent((a:real^N) INSERT b)` ASSUME_TAC THENL
+   [ASM_MESON_TAC[INDEPENDENT_INSERT]; ALL_TAC] THEN
+  MP_TAC(ISPECL [`v:real^N->bool`; `(a:real^N) INSERT b`]
+                INDEPENDENT_CARD_LE_DIM) THEN
+  ASM_SIMP_TAC[INSERT_SUBSET; CARD_CLAUSES; INDEPENDENT_BOUND] THEN
+  ASM_MESON_TAC[SPAN_SUPERSET; SUBSET; ARITH_RULE
+    `x <= y ==> ~(SUC y <= x)`]);;
+
+let CARD_LE_DIM_SPANNING = prove
+ (`!v b:real^N->bool.
+        v SUBSET (span b) /\ FINITE b /\ CARD(b) <= dim v
+        ==> independent b`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[independent; dependent] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `dim(v:real^N->bool) <= CARD(b DELETE (a:real^N))` MP_TAC THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[CARD_DELETE] THEN MATCH_MP_TAC
+     (ARITH_RULE `b <= n /\ ~(b = 0) ==> ~(n <= b - 1)`) THEN
+    ASM_SIMP_TAC[CARD_EQ_0] THEN ASM_MESON_TAC[MEMBER_NOT_EMPTY]] THEN
+  MATCH_MP_TAC SPAN_CARD_GE_DIM THEN ASM_SIMP_TAC[FINITE_DELETE] THEN
+  REWRITE_TAC[SUBSET] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC SPAN_TRANS THEN EXISTS_TAC `a:real^N` THEN
+  ASM_SIMP_TAC[SET_RULE `a IN b ==> (a INSERT (b DELETE a) = b)`] THEN
+  ASM_MESON_TAC[SUBSET]);;
+
+let CARD_EQ_DIM = prove
+ (`!v b. b SUBSET v /\ b HAS_SIZE (dim v)
+         ==> (independent b <=> v SUBSET (span b))`,
+  REWRITE_TAC[HAS_SIZE; GSYM LE_ANTISYM] THEN
+  MESON_TAC[CARD_LE_DIM_SPANNING; CARD_GE_DIM_INDEPENDENT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More general size bound lemmas.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let INDEPENDENT_BOUND_GENERAL = prove
+ (`!s:real^N->bool. independent s ==> FINITE s /\ CARD(s) <= dim(s)`,
+  MESON_TAC[INDEPENDENT_CARD_LE_DIM; INDEPENDENT_BOUND; SUBSET_REFL]);;
+
+let DEPENDENT_BIGGERSET_GENERAL = prove
+ (`!s:real^N->bool. (FINITE s ==> CARD(s) > dim(s)) ==> dependent s`,
+  MP_TAC INDEPENDENT_BOUND_GENERAL THEN MATCH_MP_TAC MONO_FORALL THEN
+  REWRITE_TAC[GT; GSYM NOT_LE; independent] THEN MESON_TAC[]);;
+
+let DIM_SPAN = prove
+ (`!s:real^N->bool. dim(span s) = dim s`,
+  GEN_TAC THEN REWRITE_TAC[GSYM LE_ANTISYM] THEN CONJ_TAC THENL
+   [ALL_TAC;
+    MATCH_MP_TAC DIM_SUBSET THEN MESON_TAC[SUBSET; SPAN_SUPERSET]] THEN
+  MP_TAC(ISPEC `s:real^N->bool` BASIS_EXISTS) THEN
+  REWRITE_TAC[HAS_SIZE] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC SPAN_CARD_GE_DIM THEN ASM_REWRITE_TAC[] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM SPAN_SPAN] THEN
+  MATCH_MP_TAC SPAN_MONO THEN ASM_REWRITE_TAC[]);;
+
+let DIM_INSERT_0 = prove
+ (`!s:real^N->bool. dim(vec 0 INSERT s) = dim s`,
+  ONCE_REWRITE_TAC[GSYM DIM_SPAN] THEN
+  REWRITE_TAC[SPAN_INSERT_0]);;
+
+let DIM_EQ_CARD = prove
+ (`!s:real^N->bool. independent s ==> dim s = CARD s`,
+  REPEAT STRIP_TAC THEN MP_TAC
+   (ISPECL [`span s:real^N->bool`; `s:real^N->bool`] BASIS_CARD_EQ_DIM) THEN
+  ASM_SIMP_TAC[SUBSET_REFL; SPAN_INC; DIM_SPAN]);;
+
+let SUBSET_LE_DIM = prove
+ (`!s t:real^N->bool. s SUBSET (span t) ==> dim s <= dim t`,
+  MESON_TAC[DIM_SPAN; DIM_SUBSET]);;
+
+let SPAN_EQ_DIM = prove
+ (`!s t. span s = span t ==> dim s = dim t`,
+  MESON_TAC[DIM_SPAN]);;
+
+let SPANS_IMAGE = prove
+ (`!f b v. linear f /\ v SUBSET (span b)
+           ==> (IMAGE f v) SUBSET span(IMAGE f b)`,
+  SIMP_TAC[SPAN_LINEAR_IMAGE; IMAGE_SUBSET]);;
+
+let DIM_LINEAR_IMAGE_LE = prove
+ (`!f:real^M->real^N s. linear f ==> dim(IMAGE f s) <= dim s`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPEC `s:real^M->bool` BASIS_EXISTS) THEN
+  REWRITE_TAC[HAS_SIZE] THEN STRIP_TAC THEN FIRST_ASSUM(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `CARD(IMAGE (f:real^M->real^N) b)` THEN
+  ASM_SIMP_TAC[CARD_IMAGE_LE] THEN MATCH_MP_TAC SPAN_CARD_GE_DIM THEN
+  ASM_MESON_TAC[SPAN_LINEAR_IMAGE; SPANS_IMAGE; SUBSET_IMAGE; FINITE_IMAGE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Some stepping theorems.                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let DIM_EMPTY = prove
+ (`dim({}:real^N->bool) = 0`,
+  MATCH_MP_TAC DIM_UNIQUE THEN EXISTS_TAC `{}:real^N->bool` THEN
+  REWRITE_TAC[SUBSET_REFL; SPAN_EMPTY; INDEPENDENT_EMPTY; HAS_SIZE_0;
+              EMPTY_SUBSET]);;
+
+let DIM_INSERT = prove
+ (`!x:real^N s. dim(x INSERT s) = if x IN span s then dim s else dim s + 1`,
+  REPEAT GEN_TAC THEN COND_CASES_TAC THENL
+   [MATCH_MP_TAC SPAN_EQ_DIM THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+    ASM_MESON_TAC[SPAN_TRANS; SUBSET; SPAN_MONO; IN_INSERT];
+    ALL_TAC] THEN
+  X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC
+   (ISPEC `span s:real^N->bool` BASIS_EXISTS) THEN
+  ONCE_REWRITE_TAC[GSYM DIM_SPAN] THEN
+  MATCH_MP_TAC DIM_UNIQUE THEN
+  EXISTS_TAC `(x:real^N) INSERT b` THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[INSERT_SUBSET] THEN
+    ASM_MESON_TAC[SUBSET; SPAN_MONO; IN_INSERT; SPAN_SUPERSET];
+    REWRITE_TAC[SUBSET; SPAN_BREAKDOWN_EQ] THEN
+    ASM_MESON_TAC[SUBSET];
+    REWRITE_TAC[INDEPENDENT_INSERT] THEN
+    ASM_MESON_TAC[SUBSET; SPAN_SUPERSET; SPAN_MONO; SPAN_SPAN];
+    RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN
+    ASM_SIMP_TAC[HAS_SIZE; CARD_CLAUSES; FINITE_INSERT; ADD1] THEN
+    ASM_MESON_TAC[SUBSET; SPAN_SUPERSET; SPAN_MONO; SPAN_SPAN]]);;
+
+let DIM_SING = prove
+ (`!x. dim{x} = if x = vec 0 then 0 else 1`,
+  REWRITE_TAC[DIM_INSERT; DIM_EMPTY; SPAN_EMPTY; IN_SING; ARITH]);;
+
+let DIM_EQ_0 = prove
+ (`!s:real^N->bool. dim s = 0 <=> s SUBSET {vec 0}`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN DISCH_TAC THENL
+   [MATCH_MP_TAC(SET_RULE
+     `~(?b. ~(b = a) /\ {b} SUBSET s) ==> s SUBSET {a}`) THEN
+    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o MATCH_MP DIM_SUBSET);
+    MATCH_MP_TAC(ARITH_RULE `!m. m = 0 /\ n <= m ==> n = 0`) THEN
+    EXISTS_TAC `dim{vec 0:real^N}` THEN ASM_SIMP_TAC[DIM_SUBSET]] THEN
+  ASM_REWRITE_TAC[DIM_SING; ARITH]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Choosing a subspace of a given dimension.                                 *)
+(* ------------------------------------------------------------------------- *)
+
+let CHOOSE_SUBSPACE_OF_SUBSPACE = prove
+ (`!s:real^N->bool n.
+        n <= dim s ==> ?t. subspace t /\ t SUBSET span s /\ dim t = n`,
+  GEN_TAC THEN INDUCT_TAC THENL
+   [DISCH_TAC THEN EXISTS_TAC `{vec 0:real^N}` THEN
+    REWRITE_TAC[SUBSPACE_TRIVIAL; DIM_SING; SING_SUBSET; SPAN_0];
+    DISCH_THEN(fun th -> POP_ASSUM MP_TAC THEN ASSUME_TAC th) THEN
+    ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
+    DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+    ASM_CASES_TAC `span (s:real^N->bool) SUBSET span t` THENL
+     [SUBGOAL_THEN `dim(s:real^N->bool) = dim(t:real^N->bool)` MP_TAC THENL
+       [ALL_TAC; ASM_ARITH_TAC] THEN MATCH_MP_TAC SPAN_EQ_DIM THEN
+      MATCH_MP_TAC SUBSET_ANTISYM THEN ASM_REWRITE_TAC[] THEN
+      MATCH_MP_TAC SPAN_SUBSET_SUBSPACE THEN ASM_REWRITE_TAC[SUBSPACE_SPAN];
+      FIRST_ASSUM(X_CHOOSE_THEN `y:real^N` STRIP_ASSUME_TAC o MATCH_MP(SET_RULE
+       `~(s SUBSET t) ==> ?a. a IN s /\ ~(a IN t)`)) THEN
+      EXISTS_TAC `span((y:real^N) INSERT t)` THEN
+      REWRITE_TAC[SUBSPACE_SPAN] THEN CONJ_TAC THENL
+       [MATCH_MP_TAC SPAN_SUBSET_SUBSPACE THEN
+        ASM_REWRITE_TAC[SUBSPACE_SPAN] THEN ASM SET_TAC[];
+        ASM_REWRITE_TAC[DIM_SPAN; DIM_INSERT; ADD1]]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Relation between bases and injectivity/surjectivity of map.               *)
+(* ------------------------------------------------------------------------- *)
+
+let SPANNING_SURJECTIVE_IMAGE = prove
+ (`!f:real^M->real^N s.
+        UNIV SUBSET (span s) /\ linear f /\ (!y. ?x. f(x) = y)
+        ==> UNIV SUBSET span(IMAGE f s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `IMAGE (f:real^M->real^N) UNIV` THEN
+  ASM_SIMP_TAC[SPANS_IMAGE] THEN
+  REWRITE_TAC[SUBSET; IN_UNIV; IN_IMAGE] THEN ASM_MESON_TAC[]);;
+
+let INDEPENDENT_INJECTIVE_IMAGE_GEN = prove
+ (`!f:real^M->real^N s.
+        independent s /\ linear f /\
+        (!x y. x IN span s /\ y IN span s /\ f(x) = f(y) ==> x = y)
+        ==> independent (IMAGE f s)`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
+  REWRITE_TAC[independent; DEPENDENT_EXPLICIT] THEN
+  REWRITE_TAC[CONJ_ASSOC; FINITE_SUBSET_IMAGE] THEN
+  REWRITE_TAC[MESON[]
+     `(?s u. ((?t. p t /\ s = f t) /\ q s u) /\ r s u) <=>
+      (?t u. p t /\ q (f t) u /\ r (f t) u)`] THEN
+  REWRITE_TAC[EXISTS_IN_IMAGE; LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`t:real^M->bool`; `u:real^N->real`] THEN
+  DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN
+  MAP_EVERY EXISTS_TAC
+   [`t:real^M->bool`; `(u:real^N->real) o (f:real^M->real^N)`] THEN
+  ASM_REWRITE_TAC[o_THM] THEN
+  FIRST_ASSUM MATCH_MP_TAC THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC SPAN_VSUM THEN ASM_REWRITE_TAC[] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC SPAN_MUL THEN
+    MATCH_MP_TAC SPAN_SUPERSET THEN ASM SET_TAC[];
+    REWRITE_TAC[SPAN_0];
+    ASM_SIMP_TAC[LINEAR_VSUM] THEN
+    FIRST_ASSUM(SUBST1_TAC o MATCH_MP LINEAR_0) THEN
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN CONV_TAC SYM_CONV THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) VSUM_IMAGE o lhand o snd) THEN
+    ASM_SIMP_TAC[o_DEF; LINEAR_CMUL] THEN DISCH_THEN MATCH_MP_TAC THEN
+    ASM_MESON_TAC[SPAN_SUPERSET; SUBSET]]);;
+
+let INDEPENDENT_INJECTIVE_IMAGE = prove
+ (`!f:real^M->real^N s.
+        independent s /\ linear f /\ (!x y. (f(x) = f(y)) ==> (x = y))
+        ==> independent (IMAGE f s)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC INDEPENDENT_INJECTIVE_IMAGE_GEN THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Picking an orthogonal replacement for a spanning set.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let VECTOR_SUB_PROJECT_ORTHOGONAL = prove
+ (`!b:real^N x. b dot (x - ((b dot x) / (b dot b)) % b) = &0`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `b = vec 0 :real^N` THENL
+   [ASM_REWRITE_TAC[DOT_LZERO]; ALL_TAC] THEN
+  ASM_SIMP_TAC[DOT_RSUB; DOT_RMUL] THEN
+  ASM_SIMP_TAC[REAL_SUB_REFL; REAL_DIV_RMUL; DOT_EQ_0]);;
+
+let BASIS_ORTHOGONAL = prove
+ (`!b:real^N->bool.
+        FINITE b
+        ==> ?c. FINITE c /\ CARD c <= CARD b /\
+                span c = span b /\ pairwise orthogonal c`,
+  REWRITE_TAC[pairwise; orthogonal] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  CONJ_TAC THENL
+   [EXISTS_TAC `{}:real^N->bool` THEN
+    REWRITE_TAC[FINITE_RULES; NOT_IN_EMPTY; LE_REFL];
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `b:real^N->bool`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_THEN `c:real^N->bool` STRIP_ASSUME_TAC)
+        STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `(a - vsum c (\x. ((x dot a) / (x dot x)) % x):real^N)
+              INSERT c` THEN
+  ASM_SIMP_TAC[FINITE_RULES; CARD_CLAUSES] THEN REPEAT CONJ_TAC THENL
+   [ASM_ARITH_TAC;
+    REWRITE_TAC[EXTENSION; SPAN_BREAKDOWN_EQ] THEN
+    FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN GEN_TAC THEN
+    AP_TERM_TAC THEN ABS_TAC THEN REWRITE_TAC[VECTOR_SUB_LDISTRIB] THEN
+    REWRITE_TAC[VECTOR_ARITH `a - (x - y):real^N = y + (a - x)`] THEN
+    MATCH_MP_TAC SPAN_ADD_EQ THEN MATCH_MP_TAC SPAN_MUL THEN
+    MATCH_MP_TAC SPAN_VSUM THEN ASM_REWRITE_TAC[] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC SPAN_MUL THEN
+    ASM_SIMP_TAC[SPAN_SUPERSET];
+    REWRITE_TAC[IN_INSERT] THEN REPEAT STRIP_TAC THENL
+     [ASM_MESON_TAC[];
+      FIRST_X_ASSUM SUBST_ALL_TAC;
+      FIRST_X_ASSUM SUBST_ALL_TAC;
+      ASM_MESON_TAC[]] THEN
+    REWRITE_TAC[DOT_LSUB; DOT_RSUB; REAL_SUB_0] THEN
+    FIRST_ASSUM(SUBST1_TAC o MATCH_MP (SET_RULE
+     `x IN s ==> s = x INSERT (s DELETE x)`)) THEN
+    ASM_SIMP_TAC[VSUM_CLAUSES; FINITE_DELETE; IN_DELETE] THEN
+    REWRITE_TAC[DOT_LADD; DOT_RADD; DOT_LMUL; DOT_RMUL] THEN
+    MATCH_MP_TAC(REAL_ARITH `s = &0 /\ a = b ==> b = a + s`) THEN
+    ASM_SIMP_TAC[DOT_LSUM; DOT_RSUM; FINITE_DELETE] THEN
+    (CONJ_TAC THENL
+      [MATCH_MP_TAC SUM_EQ_0 THEN
+       ASM_SIMP_TAC[DOT_LMUL; DOT_RMUL; IN_DELETE;
+                    REAL_MUL_RZERO; REAL_MUL_LZERO];
+       W(MP_TAC o PART_MATCH (lhand o rand) REAL_DIV_RMUL o lhand o snd) THEN
+       REWRITE_TAC[DOT_SYM] THEN
+       MATCH_MP_TAC(TAUT `(p ==> q) ==> (~p ==> q) ==> q`) THEN
+       SIMP_TAC[] THEN SIMP_TAC[DOT_EQ_0; DOT_RZERO; DOT_LZERO] THEN
+       REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_RZERO]])]);;
+
+let ORTHOGONAL_BASIS_EXISTS = prove
+ (`!v:real^N->bool.
+        ?b. independent b /\
+            b SUBSET span v /\
+            v SUBSET span b /\
+            b HAS_SIZE dim v /\
+            pairwise orthogonal b`,
+  GEN_TAC THEN MP_TAC(ISPEC `v:real^N->bool` BASIS_EXISTS) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(SPEC `b:real^N->bool` BASIS_ORTHOGONAL) THEN
+  ANTS_TAC THENL [ASM_MESON_TAC[HAS_SIZE]; ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^N->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC CARD_LE_DIM_SPANNING THEN ASM_REWRITE_TAC[] THEN
+    EXISTS_TAC `span(v):real^N->bool` THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[SPAN_SPAN; SPAN_MONO];
+      ASM_MESON_TAC[LE_TRANS; HAS_SIZE; DIM_SPAN]];
+    ASM_MESON_TAC[SUBSET_TRANS; SPAN_INC; SPAN_SPAN; SPAN_MONO];
+    RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN
+    ASM_REWRITE_TAC[HAS_SIZE; GSYM LE_ANTISYM] THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[LE_TRANS]; ALL_TAC] THEN
+    ONCE_REWRITE_TAC[GSYM DIM_SPAN] THEN MATCH_MP_TAC SPAN_CARD_GE_DIM THEN
+    ASM_REWRITE_TAC[] THEN
+    ASM_MESON_TAC[SPAN_SPAN; SPAN_MONO; SUBSET_TRANS; SPAN_INC]]);;
+
+let SPAN_EQ = prove
+ (`!s t. span s = span t <=> s SUBSET span t /\ t SUBSET span s`,
+  REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ] THEN
+  MESON_TAC[SUBSET_TRANS; SPAN_SPAN; SPAN_MONO; SPAN_INC]);;
+
+let SPAN_EQ_INSERT = prove
+ (`!s x. span(x INSERT s) = span s <=> x IN span s`,
+  REWRITE_TAC[SPAN_EQ; INSERT_SUBSET] THEN
+  MESON_TAC[SPAN_INC; SUBSET; SET_RULE `s SUBSET (x INSERT s)`]);;
+
+(* ------------------------------------------------------------------------- *)
+(* We can extend a linear basis-basis injection to the whole set.            *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_INDEP_IMAGE_LEMMA = prove
+ (`!f b. linear(f:real^M->real^N) /\
+         FINITE b /\
+         independent (IMAGE f b) /\
+         (!x y. x IN b /\ y IN b /\ (f x = f y) ==> (x = y))
+         ==> !x. x IN span b ==> (f(x) = vec 0) ==> (x = vec 0)`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  GEN_TAC THEN DISCH_TAC THEN
+  GEN_REWRITE_TAC (BINDER_CONV o RAND_CONV) [IMP_IMP] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  CONJ_TAC THENL [SIMP_TAC[IN_SING; SPAN_EMPTY]; ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M->bool`] THEN STRIP_TAC THEN
+  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o check (is_imp o concl)) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[INDEPENDENT_MONO; IMAGE_CLAUSES; SUBSET; IN_INSERT];
+    ALL_TAC] THEN
+  DISCH_TAC THEN X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+  MP_TAC(ISPECL [`a:real^M`; `(a:real^M) INSERT b`; `x:real^M`]
+    SPAN_BREAKDOWN) THEN
+  ASM_REWRITE_TAC[IN_INSERT] THEN
+  SIMP_TAC[ASSUME `~((a:real^M) IN b)`; SET_RULE
+    `~(a IN b) ==> ((a INSERT b) DELETE a = b)`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN DISCH_TAC THEN
+  SUBGOAL_THEN `(f:real^M->real^N)(x - k % a) IN span(IMAGE f b)` MP_TAC THENL
+   [ASM_MESON_TAC[SPAN_LINEAR_IMAGE; IN_IMAGE]; ALL_TAC] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP LINEAR_SUB th]) THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP LINEAR_CMUL th]) THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH `vec 0 - k % x = (--k) % x`] THEN
+  ASM_CASES_TAC `k = &0` THENL
+   [ASM_MESON_TAC[VECTOR_ARITH `x - &0 % y = x`]; ALL_TAC] THEN
+  DISCH_THEN(MP_TAC o SPEC `--inv(k)` o MATCH_MP SPAN_MUL) THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LNEG; REAL_MUL_RNEG] THEN
+  SIMP_TAC[REAL_NEGNEG; REAL_MUL_LINV; ASSUME `~(k = &0)`] THEN
+  REWRITE_TAC[VECTOR_MUL_LID] THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [independent]) THEN
+  REWRITE_TAC[dependent; NOT_EXISTS_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `(f:real^M->real^N) a`) THEN
+  SUBGOAL_THEN
+   `IMAGE (f:real^M->real^N) (a INSERT b) DELETE f a =
+    IMAGE f ((a INSERT b) DELETE a)`
+  SUBST1_TAC THENL
+   [REWRITE_TAC[EXTENSION; IN_IMAGE; IN_DELETE; IN_INSERT] THEN
+    ASM_MESON_TAC[IN_INSERT];
+    ALL_TAC] THEN
+  ASM_REWRITE_TAC[DELETE_INSERT] THEN
+  SIMP_TAC[SET_RULE `~(a IN b) ==> (b DELETE a = b)`;
+           ASSUME `~(a:real^M IN b)`] THEN
+  SIMP_TAC[IMAGE_CLAUSES; IN_INSERT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* We can extend a linear mapping from basis.                                *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_INDEPENDENT_EXTEND_LEMMA = prove
+ (`!f b. FINITE b
+         ==> independent b
+             ==> ?g:real^M->real^N.
+                        (!x y. x IN span b /\ y IN span b
+                                ==> (g(x + y) = g(x) + g(y))) /\
+                        (!x c. x IN span b ==> (g(c % x) = c % g(x))) /\
+                        (!x. x IN b ==> (g x = f x))`,
+  GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  REWRITE_TAC[NOT_IN_EMPTY; INDEPENDENT_INSERT] THEN CONJ_TAC THENL
+   [REPEAT STRIP_TAC THEN EXISTS_TAC `(\x. vec 0):real^M->real^N` THEN
+    SIMP_TAC[SPAN_EMPTY] THEN REPEAT STRIP_TAC THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  SIMP_TAC[] THEN MAP_EVERY X_GEN_TAC [`a:real^M`; `b:real^M->bool`] 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 `g:real^M->real^N` STRIP_ASSUME_TAC) THEN
+  ABBREV_TAC `h = \z:real^M. @k. (z - k % a) IN span b` THEN
+  SUBGOAL_THEN `!z:real^M. z IN span(a INSERT b)
+                    ==> (z - h(z) % a) IN span(b) /\
+                        !k. (z - k % a) IN span(b) ==> (k = h(z))`
+  MP_TAC THENL
+   [GEN_TAC THEN DISCH_TAC THEN
+    MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+     [EXPAND_TAC "h" THEN CONV_TAC SELECT_CONV THEN
+      ASM_MESON_TAC[SPAN_BREAKDOWN_EQ];
+      ALL_TAC] THEN
+    REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP] THEN GEN_TAC THEN
+    DISCH_THEN(MP_TAC o MATCH_MP SPAN_SUB) THEN
+    REWRITE_TAC[VECTOR_ARITH `(z - a % v) - (z - b % v) = (b - a) % v`] THEN
+    ASM_CASES_TAC `k = (h:real^M->real) z` THEN ASM_REWRITE_TAC[] THEN
+    DISCH_THEN(MP_TAC o SPEC `inv(k - (h:real^M->real) z)` o
+               MATCH_MP SPAN_MUL) THEN
+    ASM_SIMP_TAC[REAL_MUL_LINV; VECTOR_MUL_ASSOC; REAL_SUB_0] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_LID];
+    ALL_TAC] THEN
+  REWRITE_TAC[TAUT `(a ==> b /\ c) <=> (a ==> b) /\ (a ==> c)`] THEN
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP] THEN
+  GEN_REWRITE_TAC LAND_CONV [FORALL_AND_THM] THEN STRIP_TAC THEN
+  EXISTS_TAC `\z:real^M. h(z) % (f:real^M->real^N)(a) + g(z - h(z) % a)` THEN
+  REPEAT CONJ_TAC THENL
+   [MAP_EVERY X_GEN_TAC [`x:real^M`; `y:real^M`] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `(h:real^M->real)(x + y) = h(x) + h(y)` ASSUME_TAC THENL
+     [CONV_TAC SYM_CONV THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      REWRITE_TAC[VECTOR_ARITH
+       `(x + y) - (k + l) % a = (x - k % a) + (y - l % a)`] THEN
+      CONJ_TAC THEN MATCH_MP_TAC SPAN_ADD THEN ASM_REWRITE_TAC[] THEN
+      ASM_SIMP_TAC[];
+      ALL_TAC] THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH
+       `(x + y) - (k + l) % a = (x - k % a) + (y - l % a)`] THEN
+    ASM_SIMP_TAC[] THEN VECTOR_ARITH_TAC;
+    MAP_EVERY X_GEN_TAC [`x:real^M`; `c:real`] THEN STRIP_TAC THEN
+    SUBGOAL_THEN `(h:real^M->real)(c % x) = c * h(x)` ASSUME_TAC THENL
+     [CONV_TAC SYM_CONV THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+      REWRITE_TAC[VECTOR_ARITH
+       `c % x - (c * k) % a = c % (x - k % a)`] THEN
+      CONJ_TAC THEN MATCH_MP_TAC SPAN_MUL THEN ASM_REWRITE_TAC[] THEN
+      ASM_SIMP_TAC[];
+      ALL_TAC] THEN
+    ASM_REWRITE_TAC[VECTOR_ARITH
+       `c % x - (c * k) % a = c % (x - k % a)`] THEN
+    ASM_SIMP_TAC[] THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  X_GEN_TAC `x:real^M` THEN REWRITE_TAC[IN_INSERT] THEN
+  DISCH_THEN(DISJ_CASES_THEN2 SUBST_ALL_TAC ASSUME_TAC) THENL
+   [SUBGOAL_THEN `&1 = h(a:real^M)` (SUBST1_TAC o SYM) THENL
+     [FIRST_X_ASSUM MATCH_MP_TAC; ALL_TAC] THEN
+    REWRITE_TAC[VECTOR_ARITH `a - &1 % a = vec 0`; SPAN_0] THENL
+     [ASM_MESON_TAC[SPAN_SUPERSET; SUBSET; IN_INSERT]; ALL_TAC] THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`vec 0:real^M`; `vec 0:real^M`]) THEN
+    REWRITE_TAC[SPAN_0; VECTOR_ADD_LID] THEN
+    REWRITE_TAC[VECTOR_ARITH `(a = a + a) <=> (a = vec 0)`] THEN
+    DISCH_THEN SUBST1_TAC THEN VECTOR_ARITH_TAC;
+    ALL_TAC] THEN
+  SUBGOAL_THEN `&0 = h(x:real^M)` (SUBST1_TAC o SYM) THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC; ALL_TAC] THEN
+  REWRITE_TAC[VECTOR_ADD_LID; VECTOR_MUL_LZERO; VECTOR_SUB_RZERO] THEN
+  ASM_MESON_TAC[SUBSET; IN_INSERT; SPAN_SUPERSET]);;
+
+let LINEAR_INDEPENDENT_EXTEND = prove
+ (`!f b. independent b
+         ==> ?g:real^M->real^N. linear g /\ (!x. x IN b ==> (g x = f x))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`b:real^M->bool`; `(:real^M)`]
+           MAXIMAL_INDEPENDENT_SUBSET_EXTEND) THEN
+  ASM_REWRITE_TAC[SUBSET_UNIV; UNIV_SUBSET] THEN
+  REWRITE_TAC[EXTENSION; IN_UNIV] THEN
+  DISCH_THEN(X_CHOOSE_THEN `c:real^M->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `c:real^M->bool`]
+    LINEAR_INDEPENDENT_EXTEND_LEMMA) THEN
+  ASM_SIMP_TAC[INDEPENDENT_BOUND; linear] THEN
+  ASM_MESON_TAC[SUBSET]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Linear functions are equal on a subspace if they are on a spanning set.   *)
+(* ------------------------------------------------------------------------- *)
+
+let SUBSPACE_KERNEL = prove
+ (`!f. linear f ==> subspace {x | f(x) = vec 0}`,
+  REWRITE_TAC[subspace; IN_ELIM_THM] THEN
+  SIMP_TAC[LINEAR_ADD; LINEAR_CMUL; VECTOR_ADD_LID; VECTOR_MUL_RZERO] THEN
+  MESON_TAC[LINEAR_0]);;
+
+let LINEAR_EQ_0_SPAN = prove
+ (`!f:real^M->real^N b.
+        linear f /\ (!x. x IN b ==> f(x) = vec 0)
+        ==> !x. x IN span(b) ==> f(x) = vec 0`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[IN]) THEN
+  MATCH_MP_TAC SPAN_INDUCT THEN ASM_REWRITE_TAC[IN] THEN
+  MP_TAC(ISPEC `f:real^M->real^N` SUBSPACE_KERNEL) THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC EQ_IMP THEN
+  AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM]);;
+
+let LINEAR_EQ_0 = prove
+ (`!f b s. linear f /\ s SUBSET (span b) /\ (!x. x IN b ==> f(x) = vec 0)
+           ==> !x. x IN s ==> f(x) = vec 0`,
+  MESON_TAC[LINEAR_EQ_0_SPAN; SUBSET]);;
+
+let LINEAR_EQ = prove
+ (`!f g b s. linear f /\ linear g /\ s SUBSET (span b) /\
+             (!x. x IN b ==> f(x) = g(x))
+              ==> !x. x IN s ==> f(x) = g(x)`,
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+  STRIP_TAC THEN MATCH_MP_TAC LINEAR_EQ_0 THEN
+  ASM_MESON_TAC[LINEAR_COMPOSE_SUB]);;
+
+let LINEAR_EQ_STDBASIS = prove
+ (`!f:real^M->real^N g.
+        linear f /\ linear g /\
+        (!i. 1 <= i /\ i <= dimindex(:M)
+             ==> f(basis i) = g(basis i))
+        ==> f = g`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `!x. x IN UNIV ==> (f:real^M->real^N) x = g x`
+   (fun th -> MP_TAC th THEN REWRITE_TAC[FUN_EQ_THM; IN_UNIV]) THEN
+  MATCH_MP_TAC LINEAR_EQ THEN
+  EXISTS_TAC `{basis i :real^M | 1 <= i /\ i <= dimindex(:M)}` THEN
+  ASM_REWRITE_TAC[SPAN_STDBASIS; SUBSET_REFL; IN_ELIM_THM] THEN
+  ASM_MESON_TAC[]);;
+
+let SUBSPACE_LINEAR_FIXED_POINTS = prove
+ (`!f:real^N->real^N. linear f ==> subspace {x | f(x) = x}`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+  MATCH_MP_TAC SUBSPACE_KERNEL THEN
+  ASM_SIMP_TAC[LINEAR_COMPOSE_SUB; LINEAR_ID]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Similar results for bilinear functions.                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let BILINEAR_EQ = prove
+ (`!f:real^M->real^N->real^P g b c s.
+        bilinear f /\ bilinear g /\
+        s SUBSET (span b) /\ t SUBSET (span c) /\
+        (!x y. x IN b /\ y IN c ==> f x y = g x y)
+         ==> !x y. x IN s /\ y IN t ==> f x y = g x y`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+    `!x:real^M. x IN span b
+                ==> !y:real^N. y IN span c ==> (f x y :real^P = g x y)`
+    (fun th -> ASM_MESON_TAC[th; SUBSET]) THEN
+  MATCH_MP_TAC SPAN_INDUCT THEN REWRITE_TAC[subspace; IN_ELIM_THM] THEN
+  CONJ_TAC THENL
+   [GEN_TAC THEN DISCH_TAC;
+    ASM_SIMP_TAC[BILINEAR_LADD; BILINEAR_LMUL] THEN
+    ASM_MESON_TAC[BILINEAR_LZERO]] THEN
+  MATCH_MP_TAC SPAN_INDUCT THEN REWRITE_TAC[subspace; IN_ELIM_THM] THEN
+  ASM_SIMP_TAC[BILINEAR_RADD; BILINEAR_RMUL] THEN
+  ASM_MESON_TAC[BILINEAR_RZERO]);;
+
+let BILINEAR_EQ_STDBASIS = prove
+ (`!f:real^M->real^N->real^P g.
+        bilinear f /\ bilinear g /\
+        (!i j. 1 <= i /\ i <= dimindex(:M) /\ 1 <= j /\ j <= dimindex(:N)
+             ==> f (basis i) (basis j) = g (basis i) (basis j))
+        ==> f = g`,
+  REPEAT STRIP_TAC THEN SUBGOAL_THEN
+   `!x y. x IN UNIV /\ y IN UNIV ==> (f:real^M->real^N->real^P) x y = g x y`
+   (fun th -> MP_TAC th THEN REWRITE_TAC[FUN_EQ_THM; IN_UNIV]) THEN
+  MATCH_MP_TAC BILINEAR_EQ THEN
+  EXISTS_TAC `{basis i :real^M | 1 <= i /\ i <= dimindex(:M)}` THEN
+  EXISTS_TAC `{basis i :real^N | 1 <= i /\ i <= dimindex(:N)}` THEN
+  ASM_REWRITE_TAC[SPAN_STDBASIS; SUBSET_REFL; IN_ELIM_THM] THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Detailed theorems about left and right invertibility in general case.     *)
+(* ------------------------------------------------------------------------- *)
+
+let LEFT_INVERTIBLE_TRANSP = prove
+ (`!A:real^N^M.
+    (?B:real^N^M. B ** transp A = mat 1) <=> (?B:real^M^N. A ** B = mat 1)`,
+  MESON_TAC[MATRIX_TRANSP_MUL; TRANSP_MAT; TRANSP_TRANSP]);;
+
+let RIGHT_INVERTIBLE_TRANSP = prove
+ (`!A:real^N^M.
+    (?B:real^N^M. transp A ** B = mat 1) <=> (?B:real^M^N. B ** A = mat 1)`,
+  MESON_TAC[MATRIX_TRANSP_MUL; TRANSP_MAT; TRANSP_TRANSP]);;
+
+let INVERTIBLE_TRANSP = prove
+ (`!A:real^N^M. invertible(transp A) <=> invertible A`,
+  GEN_TAC THEN REWRITE_TAC[invertible] THEN
+  GEN_REWRITE_TAC LAND_CONV [MESON[TRANSP_TRANSP]
+    `(?A:real^M^N. P A) <=> (?A:real^N^M. P(transp A))`] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [GSYM TRANSP_MAT] THEN
+  REWRITE_TAC[GSYM MATRIX_TRANSP_MUL; TRANSP_EQ] THEN MESON_TAC[]);;
+
+let LINEAR_INJECTIVE_LEFT_INVERSE = prove
+ (`!f:real^M->real^N.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> ?g. linear g /\ g o f = I`,
+  REWRITE_TAC[INJECTIVE_LEFT_INVERSE] THEN REPEAT STRIP_TAC THEN SUBGOAL_THEN
+   `?h. linear(h:real^N->real^M) /\
+        !x. x IN IMAGE (f:real^M->real^N)
+               {basis i | 1 <= i /\ i <= dimindex(:M)} ==> h x = g x`
+  MP_TAC THENL
+   [MATCH_MP_TAC LINEAR_INDEPENDENT_EXTEND THEN
+    MATCH_MP_TAC INDEPENDENT_INJECTIVE_IMAGE THEN
+    ASM_MESON_TAC[INJECTIVE_LEFT_INVERSE; INDEPENDENT_STDBASIS];
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `h:real^N->real^M` THEN
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE; IN_ELIM_THM] THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC LINEAR_EQ_STDBASIS THEN
+    ASM_SIMP_TAC[I_DEF; LINEAR_COMPOSE; LINEAR_ID; o_THM] THEN
+    ASM_MESON_TAC[]]);;
+
+let LINEAR_SURJECTIVE_RIGHT_INVERSE = prove
+ (`!f:real^M->real^N.
+        linear f /\ (!y. ?x. f x = y) ==> ?g. linear g /\ f o g = I`,
+  REWRITE_TAC[SURJECTIVE_RIGHT_INVERSE] THEN REPEAT STRIP_TAC THEN SUBGOAL_THEN
+   `?h. linear(h:real^N->real^M) /\
+        !x. x IN {basis i | 1 <= i /\ i <= dimindex(:N)} ==> h x = g x`
+  MP_TAC THENL
+   [MATCH_MP_TAC LINEAR_INDEPENDENT_EXTEND THEN
+    REWRITE_TAC[INDEPENDENT_STDBASIS];
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `h:real^N->real^M` THEN
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE; IN_ELIM_THM] THEN STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC LINEAR_EQ_STDBASIS THEN
+    ASM_SIMP_TAC[I_DEF; LINEAR_COMPOSE; LINEAR_ID; o_THM] THEN
+    ASM_MESON_TAC[]]);;
+
+let MATRIX_LEFT_INVERTIBLE_INJECTIVE = prove
+ (`!A:real^N^M.
+        (?B:real^M^N. B ** A = mat 1) <=>
+        !x y:real^N. A ** x = A ** y ==> x = y`,
+  GEN_TAC THEN EQ_TAC THENL
+   [STRIP_TAC THEN REPEAT GEN_TAC THEN
+    DISCH_THEN(MP_TAC o AP_TERM `\x:real^M. (B:real^M^N) ** x`) THEN
+    ASM_REWRITE_TAC[MATRIX_VECTOR_MUL_ASSOC; MATRIX_VECTOR_MUL_LID];
+    DISCH_TAC THEN MP_TAC(ISPEC
+     `\x:real^N. (A:real^N^M) ** x` LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+    ASM_REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR; FUN_EQ_THM; I_THM; o_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `matrix(g):real^M^N` THEN
+    REWRITE_TAC[MATRIX_EQ; MATRIX_VECTOR_MUL_LID] THEN
+    ASM_MESON_TAC[MATRIX_VECTOR_MUL_ASSOC; MATRIX_WORKS]]);;
+
+let MATRIX_LEFT_INVERTIBLE_KER = prove
+ (`!A:real^N^M.
+        (?B:real^M^N. B ** A = mat 1) <=> !x. A ** x = vec 0 ==> x = vec 0`,
+  GEN_TAC THEN REWRITE_TAC[MATRIX_LEFT_INVERTIBLE_INJECTIVE] THEN
+  MATCH_MP_TAC LINEAR_INJECTIVE_0 THEN REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR]);;
+
+let MATRIX_RIGHT_INVERTIBLE_SURJECTIVE = prove
+ (`!A:real^N^M.
+        (?B:real^M^N. A ** B = mat 1) <=> !y. ?x. A ** x = y`,
+  GEN_TAC THEN EQ_TAC THENL
+   [STRIP_TAC THEN X_GEN_TAC `y:real^M` THEN
+    EXISTS_TAC `(B:real^M^N) ** (y:real^M)` THEN
+    ASM_REWRITE_TAC[MATRIX_VECTOR_MUL_ASSOC; MATRIX_VECTOR_MUL_LID];
+    DISCH_TAC THEN MP_TAC(ISPEC
+     `\x:real^N. (A:real^N^M) ** x` LINEAR_SURJECTIVE_RIGHT_INVERSE) THEN
+    ASM_REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR; FUN_EQ_THM; I_THM; o_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real^M->real^N` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `matrix(g):real^M^N` THEN
+    REWRITE_TAC[MATRIX_EQ; MATRIX_VECTOR_MUL_LID] THEN
+    ASM_MESON_TAC[MATRIX_VECTOR_MUL_ASSOC; MATRIX_WORKS]]);;
+
+let MATRIX_LEFT_INVERTIBLE_INDEPENDENT_COLUMNS = prove
+ (`!A:real^N^M. (?B:real^M^N. B ** A = mat 1) <=>
+                !c. vsum(1..dimindex(:N)) (\i. c(i) % column i A) = vec 0 ==>
+                    !i. 1 <= i /\ i <= dimindex(:N) ==> c(i) = &0`,
+  GEN_TAC THEN REWRITE_TAC[MATRIX_LEFT_INVERTIBLE_KER; MATRIX_MUL_VSUM] THEN
+  EQ_TAC THEN DISCH_TAC THENL
+   [X_GEN_TAC `c:num->real` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(lambda i. c(i)):real^N`);
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `\i. (x:real^N)$i`)] THEN
+  ASM_SIMP_TAC[LAMBDA_BETA; CART_EQ; VEC_COMPONENT]);;
+
+let MATRIX_RIGHT_INVERTIBLE_INDEPENDENT_ROWS = prove
+ (`!A:real^N^M. (?B:real^M^N. A ** B = mat 1) <=>
+                !c. vsum(1..dimindex(:M)) (\i. c(i) % row i A) = vec 0 ==>
+                    !i. 1 <= i /\ i <= dimindex(:M) ==> c(i) = &0`,
+  ONCE_REWRITE_TAC[GSYM LEFT_INVERTIBLE_TRANSP] THEN
+  REWRITE_TAC[MATRIX_LEFT_INVERTIBLE_INDEPENDENT_COLUMNS] THEN
+  SIMP_TAC[COLUMN_TRANSP]);;
+
+let MATRIX_RIGHT_INVERTIBLE_SPAN_COLUMNS = prove
+ (`!A:real^N^M. (?B:real^M^N. A ** B = mat 1) <=> span(columns A) = (:real^M)`,
+  GEN_TAC THEN REWRITE_TAC[MATRIX_RIGHT_INVERTIBLE_SURJECTIVE] THEN
+  REWRITE_TAC[MATRIX_MUL_VSUM; EXTENSION; IN_UNIV] THEN
+  AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN X_GEN_TAC `y:real^M` THEN
+  EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `x:real^N` (SUBST1_TAC o SYM)) THEN
+    MATCH_MP_TAC SPAN_VSUM THEN REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+    X_GEN_TAC `i:num` THEN STRIP_TAC THEN MATCH_MP_TAC SPAN_MUL THEN
+    MATCH_MP_TAC(CONJUNCT1 SPAN_CLAUSES) THEN
+    REWRITE_TAC[columns; IN_ELIM_THM] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  SPEC_TAC(`y:real^M`,`y:real^M`) THEN MATCH_MP_TAC SPAN_INDUCT_ALT THEN
+  CONJ_TAC THENL
+   [EXISTS_TAC `vec 0 :real^N` THEN
+    SIMP_TAC[VEC_COMPONENT; VECTOR_MUL_LZERO; VSUM_0];
+    ALL_TAC] THEN
+  MAP_EVERY X_GEN_TAC [`c:real`; `y1:real^M`; `y2:real^M`] THEN
+  REWRITE_TAC[columns; IN_ELIM_THM] THEN DISCH_THEN(CONJUNCTS_THEN2
+   (X_CHOOSE_THEN `i:num` STRIP_ASSUME_TAC)
+   (X_CHOOSE_THEN `x:real^N` (SUBST1_TAC o SYM))) THEN
+  EXISTS_TAC `(lambda j. if j = i then c + (x:real^N)$i else x$j):real^N` THEN
+  SUBGOAL_THEN `1..dimindex(:N) = i INSERT ((1..dimindex(:N)) DELETE i)`
+  SUBST1_TAC THENL [ASM_MESON_TAC[INSERT_DELETE; IN_NUMSEG]; ALL_TAC] THEN
+  SIMP_TAC[VSUM_CLAUSES; FINITE_DELETE; FINITE_NUMSEG; IN_DELETE] THEN
+  ASM_SIMP_TAC[LAMBDA_BETA; VECTOR_ADD_RDISTRIB; VECTOR_ADD_ASSOC] THEN
+  AP_TERM_TAC THEN MATCH_MP_TAC VSUM_EQ THEN
+  SIMP_TAC[FINITE_DELETE; IN_DELETE; FINITE_NUMSEG; LAMBDA_BETA; IN_NUMSEG]);;
+
+let MATRIX_LEFT_INVERTIBLE_SPAN_ROWS = prove
+ (`!A:real^N^M. (?B:real^M^N. B ** A = mat 1) <=> span(rows A) = (:real^N)`,
+  MESON_TAC[RIGHT_INVERTIBLE_TRANSP; COLUMNS_TRANSP;
+            MATRIX_RIGHT_INVERTIBLE_SPAN_COLUMNS]);;
+
+(* ------------------------------------------------------------------------- *)
+(* An injective map real^N->real^N is also surjective.                       *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_INJECTIVE_IMP_SURJECTIVE = prove
+ (`!f:real^N->real^N.
+        linear f /\ (!x y. (f(x) = f(y)) ==> (x = y))
+        ==> !y. ?x. f(x) = y`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `(:real^N)` BASIS_EXISTS) THEN
+  REWRITE_TAC[SUBSET_UNIV; HAS_SIZE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `UNIV SUBSET span(IMAGE (f:real^N->real^N) b)` MP_TAC THENL
+   [MATCH_MP_TAC CARD_GE_DIM_INDEPENDENT THEN
+    ASM_MESON_TAC[INDEPENDENT_INJECTIVE_IMAGE; LE_REFL;
+                  SUBSET_UNIV; CARD_IMAGE_INJ];
+    ASM_SIMP_TAC[SPAN_LINEAR_IMAGE] THEN
+    ASM_MESON_TAC[SUBSET; IN_IMAGE; IN_UNIV]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* And vice versa.                                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_SURJECTIVE_IMP_INJECTIVE = prove
+ (`!f:real^N->real^N.
+        linear f /\ (!y. ?x. f(x) = y)
+        ==> !x y. (f(x) = f(y)) ==> (x = y)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MP_TAC(ISPEC `(:real^N)` BASIS_EXISTS) THEN
+  REWRITE_TAC[SUBSET_UNIV; HAS_SIZE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `!x. x IN span b ==> (f:real^N->real^N) x = vec 0 ==> x = vec 0`
+   (fun th -> ASM_MESON_TAC[th; LINEAR_INJECTIVE_0; SUBSET; IN_UNIV]) THEN
+  MATCH_MP_TAC LINEAR_INDEP_IMAGE_LEMMA THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC CARD_LE_DIM_SPANNING THEN
+    EXISTS_TAC `(:real^N)` THEN
+    ASM_SIMP_TAC[SUBSET_UNIV; FINITE_IMAGE; SPAN_LINEAR_IMAGE] THEN
+    REWRITE_TAC[SUBSET; IN_UNIV; IN_IMAGE] THEN
+    ASM_MESON_TAC[CARD_IMAGE_LE; SUBSET; IN_UNIV];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `dim(:real^N) <= CARD(IMAGE (f:real^N->real^N) b)`
+  MP_TAC THENL
+   [MATCH_MP_TAC SPAN_CARD_GE_DIM THEN
+    ASM_SIMP_TAC[SUBSET_UNIV; FINITE_IMAGE] THEN
+    ASM_SIMP_TAC[SPAN_LINEAR_IMAGE] THEN MATCH_MP_TAC SUBSET_TRANS THEN
+    EXISTS_TAC `IMAGE (f:real^N->real^N) UNIV` THEN
+    ASM_SIMP_TAC[IMAGE_SUBSET] THEN
+    ASM_REWRITE_TAC[SUBSET; IN_IMAGE; IN_UNIV] THEN ASM_MESON_TAC[];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o ISPEC `f:real^N->real^N` o
+                MATCH_MP CARD_IMAGE_LE) THEN
+  ASM_REWRITE_TAC[IMP_IMP; LE_ANTISYM] THEN DISCH_TAC THEN
+  MP_TAC(ISPECL
+   [`b:real^N->bool`; `IMAGE (f:real^N->real^N) b`; `f:real^N->real^N`]
+   SURJECTIVE_IFF_INJECTIVE_GEN) THEN
+  ASM_SIMP_TAC[FINITE_IMAGE; INDEPENDENT_BOUND; SUBSET_REFL] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN MESON_TAC[]);;
+
+let LINEAR_SURJECTIVE_IFF_INJECTIVE = prove
+ (`!f:real^N->real^N.
+      linear f ==> ((!y. ?x. f x = y) <=> (!x y. f x = f y ==> x = y))`,
+  MESON_TAC[LINEAR_INJECTIVE_IMP_SURJECTIVE;
+            LINEAR_SURJECTIVE_IMP_INJECTIVE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Hence either is enough for isomorphism.                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let LEFT_RIGHT_INVERSE_EQ = prove
+ (`!f:A->A g h. f o g = I /\ g o h = I ==> f = h`,
+  MESON_TAC[o_ASSOC; I_O_ID]);;
+
+let ISOMORPHISM_EXPAND = prove
+ (`!f g. f o g = I /\ g o f = I <=> (!x. f(g x) = x) /\ (!x. g(f x) = x)`,
+  REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM]);;
+
+let LINEAR_INJECTIVE_ISOMORPHISM = prove
+ (`!f:real^N->real^N.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> ?f'. linear f' /\ (!x. f'(f x) = x) /\ (!x. f(f' x) = x)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[GSYM ISOMORPHISM_EXPAND] THEN
+  MP_TAC(ISPEC `f:real^N->real^N` LINEAR_SURJECTIVE_RIGHT_INVERSE) THEN
+  MP_TAC(ISPEC `f:real^N->real^N` LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+  MP_TAC(ISPEC `f:real^N->real^N` LINEAR_INJECTIVE_IMP_SURJECTIVE) THEN
+  ASM_REWRITE_TAC[] THEN SIMP_TAC[] THEN MESON_TAC[LEFT_RIGHT_INVERSE_EQ]);;
+
+let LINEAR_SURJECTIVE_ISOMORPHISM = prove
+ (`!f:real^N->real^N.
+        linear f /\ (!y. ?x. f x = y)
+        ==> ?f'. linear f' /\ (!x. f'(f x) = x) /\ (!x. f(f' x) = x)`,
+  REPEAT STRIP_TAC THEN
+  REWRITE_TAC[GSYM ISOMORPHISM_EXPAND] THEN
+  MP_TAC(ISPEC `f:real^N->real^N` LINEAR_SURJECTIVE_RIGHT_INVERSE) THEN
+  MP_TAC(ISPEC `f:real^N->real^N` LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+  MP_TAC(ISPEC `f:real^N->real^N` LINEAR_SURJECTIVE_IMP_INJECTIVE) THEN
+  ASM_REWRITE_TAC[] THEN SIMP_TAC[] THEN MESON_TAC[LEFT_RIGHT_INVERSE_EQ]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Left and right inverses are the same for R^N->R^N.                        *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_INVERSE_LEFT = prove
+ (`!f:real^N->real^N f'.
+        linear f /\ linear f' ==> ((f o f' = I) <=> (f' o f = I))`,
+  SUBGOAL_THEN
+   `!f:real^N->real^N f'.
+        linear f /\ linear f' /\ (f o f' = I) ==> (f' o f = I)`
+   (fun th -> MESON_TAC[th]) THEN
+  REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `f:real^N->real^N` LINEAR_SURJECTIVE_ISOMORPHISM) THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Moreover, a one-sided inverse is automatically linear.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let LEFT_INVERSE_LINEAR = prove
+ (`!f g:real^N->real^N. linear f /\ (g o f = I) ==> linear g`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN
+  STRIP_TAC THEN SUBGOAL_THEN
+   `?h:real^N->real^N. linear h /\ (!x. h(f x) = x) /\ (!x. f(h x) = x)`
+  CHOOSE_TAC THENL
+   [MATCH_MP_TAC LINEAR_INJECTIVE_ISOMORPHISM THEN ASM_MESON_TAC[];
+    SUBGOAL_THEN `g:real^N->real^N = h` (fun th -> ASM_REWRITE_TAC[th]) THEN
+    REWRITE_TAC[FUN_EQ_THM] THEN ASM_MESON_TAC[]]);;
+
+let RIGHT_INVERSE_LINEAR = prove
+ (`!f g:real^N->real^N. linear f /\ (f o g = I) ==> linear g`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN
+  STRIP_TAC THEN SUBGOAL_THEN
+   `?h:real^N->real^N. linear h /\ (!x. h(f x) = x) /\ (!x. f(h x) = x)`
+  CHOOSE_TAC THENL [ASM_MESON_TAC[LINEAR_SURJECTIVE_ISOMORPHISM]; ALL_TAC] THEN
+  SUBGOAL_THEN `g:real^N->real^N = h` (fun th -> ASM_REWRITE_TAC[th]) THEN
+  REWRITE_TAC[FUN_EQ_THM] THEN ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Without (ostensible) constraints on types, though dimensions must match.  *)
+(* ------------------------------------------------------------------------- *)
+
+let LEFT_RIGHT_INVERSE_LINEAR = prove
+ (`!f g:real^M->real^N.
+        linear f /\ g o f = I /\ f o g = I ==> linear g`,
+  REWRITE_TAC[linear; FUN_EQ_THM; o_THM; I_THM] THEN MESON_TAC[]);;
+
+let LINEAR_BIJECTIVE_LEFT_RIGHT_INVERSE = prove
+ (`!f:real^M->real^N.
+        linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+        ==> ?g. linear g /\ (!x. g(f x) = x) /\ (!y. f(g y) = y)`,
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [BIJECTIVE_LEFT_RIGHT_INVERSE]) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC LEFT_RIGHT_INVERSE_LINEAR THEN
+  EXISTS_TAC `f:real^M->real^N` THEN
+  ASM_REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* The same result in terms of square matrices.                              *)
+(* ------------------------------------------------------------------------- *)
+
+let MATRIX_LEFT_RIGHT_INVERSE = prove
+ (`!A:real^N^N A':real^N^N. (A ** A' = mat 1) <=> (A' ** A = mat 1)`,
+  SUBGOAL_THEN
+    `!A:real^N^N A':real^N^N. (A ** A' = mat 1) ==> (A' ** A = mat 1)`
+    (fun th -> MESON_TAC[th]) THEN
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `\x:real^N. A:(real^N^N) ** x`
+    LINEAR_SURJECTIVE_ISOMORPHISM) THEN
+  REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR] THEN ANTS_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN EXISTS_TAC `(A':real^N^N) ** (x:real^N)` THEN
+    ASM_REWRITE_TAC[MATRIX_VECTOR_MUL_ASSOC; MATRIX_VECTOR_MUL_LID];
+    ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f':real^N->real^N` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `matrix (f':real^N->real^N) ** (A:real^N^N) = mat 1`
+  MP_TAC THENL
+   [ASM_SIMP_TAC[MATRIX_EQ; MATRIX_WORKS; GSYM MATRIX_VECTOR_MUL_ASSOC;
+                 MATRIX_VECTOR_MUL_LID];
+    ALL_TAC] THEN
+  DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
+  DISCH_THEN(MP_TAC o AP_TERM `(\m:real^N^N. m ** (A':real^N^N))`) THEN
+  REWRITE_TAC[GSYM MATRIX_MUL_ASSOC] THEN
+  ASM_REWRITE_TAC[MATRIX_MUL_RID; MATRIX_MUL_LID] THEN ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Invertibility of matrices and corresponding linear functions.             *)
+(* ------------------------------------------------------------------------- *)
+
+let MATRIX_LEFT_INVERTIBLE = prove
+ (`!f:real^M->real^N.
+    linear f ==> ((?B:real^N^M. B ** matrix f = mat 1) <=>
+                  (?g. linear g /\ g o f = I))`,
+  GEN_TAC THEN DISCH_TAC THEN EQ_TAC THEN STRIP_TAC THENL
+   [EXISTS_TAC `\y:real^N. (B:real^N^M) ** y` THEN
+    REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR] THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV)
+                [MATCH_MP MATRIX_VECTOR_MUL th]) THEN
+    ASM_REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM; MATRIX_VECTOR_MUL_ASSOC;
+                    MATRIX_VECTOR_MUL_LID];
+    EXISTS_TAC `matrix(g:real^N->real^M)` THEN
+    ASM_SIMP_TAC[GSYM MATRIX_COMPOSE; MATRIX_I]]);;
+
+let MATRIX_RIGHT_INVERTIBLE = prove
+ (`!f:real^M->real^N.
+    linear f ==> ((?B:real^N^M. matrix f ** B = mat 1) <=>
+                  (?g. linear g /\ f o g = I))`,
+  GEN_TAC THEN DISCH_TAC THEN EQ_TAC THEN STRIP_TAC THENL
+   [EXISTS_TAC `\y:real^N. (B:real^N^M) ** y` THEN
+    REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR] THEN
+    FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC (LAND_CONV o LAND_CONV)
+                [MATCH_MP MATRIX_VECTOR_MUL th]) THEN
+    ASM_REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM; MATRIX_VECTOR_MUL_ASSOC;
+                    MATRIX_VECTOR_MUL_LID];
+    EXISTS_TAC `matrix(g:real^N->real^M)` THEN
+    ASM_SIMP_TAC[GSYM MATRIX_COMPOSE; MATRIX_I]]);;
+
+let INVERTIBLE_LEFT_INVERSE = prove
+ (`!A:real^N^N. invertible(A) <=> ?B:real^N^N. B ** A = mat 1`,
+  MESON_TAC[invertible; MATRIX_LEFT_RIGHT_INVERSE]);;
+
+let INVERTIBLE_RIGHT_INVERSE = prove
+ (`!A:real^N^N. invertible(A) <=> ?B:real^N^N. A ** B = mat 1`,
+  MESON_TAC[invertible; MATRIX_LEFT_RIGHT_INVERSE]);;
+
+let MATRIX_INVERTIBLE = prove
+ (`!f:real^N->real^N.
+        linear f
+        ==> (invertible(matrix f) <=>
+             ?g. linear g /\ f o g = I /\ g o f = I)`,
+  SIMP_TAC[INVERTIBLE_LEFT_INVERSE; MATRIX_LEFT_INVERTIBLE] THEN
+  MESON_TAC[LINEAR_INVERSE_LEFT]);;
+
+let MATRIX_INV_UNIQUE_LEFT = prove
+ (`!A:real^N^N B. A ** B = mat 1 ==> matrix_inv B = A`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MATRIX_INV_UNIQUE THEN
+  ASM_MESON_TAC[MATRIX_LEFT_RIGHT_INVERSE]);;
+
+let MATRIX_INV_UNIQUE_RIGHT = prove
+ (`!A:real^N^N B. A ** B = mat 1 ==> matrix_inv A = B`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MATRIX_INV_UNIQUE THEN
+  ASM_MESON_TAC[MATRIX_LEFT_RIGHT_INVERSE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Left-invertible linear transformation has a lower bound.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_INVERTIBLE_BOUNDED_BELOW_POS = prove
+ (`!f:real^M->real^N g.
+        linear f /\ linear g /\ (g o f = I)
+        ==> ?B. &0 < B /\ !x. B * norm(x) <= norm(f x)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `g:real^N->real^M` LINEAR_BOUNDED_POS) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `B:real` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `inv B:real` THEN ASM_REWRITE_TAC[REAL_LT_INV_EQ] THEN
+  X_GEN_TAC `x:real^M` THEN MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `inv(B) * norm(((g:real^N->real^M) o (f:real^M->real^N)) x)` THEN
+  CONJ_TAC THENL [ASM_SIMP_TAC[I_THM; REAL_LE_REFL]; ALL_TAC] THEN
+  REWRITE_TAC[REAL_ARITH `inv B * x = x / B`] THEN
+  ASM_SIMP_TAC[o_THM; REAL_LE_LDIV_EQ] THEN
+  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN ASM_REWRITE_TAC[]);;
+
+let LINEAR_INVERTIBLE_BOUNDED_BELOW = prove
+ (`!f:real^M->real^N g.
+        linear f /\ linear g /\ (g o f = I)
+        ==> ?B. !x. B * norm(x) <= norm(f x)`,
+  MESON_TAC[LINEAR_INVERTIBLE_BOUNDED_BELOW_POS]);;
+
+let LINEAR_INJECTIVE_BOUNDED_BELOW_POS = prove
+ (`!f:real^M->real^N.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> ?B. &0 < B /\ !x. norm(x) * B <= norm(f x)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
+  MATCH_MP_TAC LINEAR_INVERTIBLE_BOUNDED_BELOW_POS THEN
+  ASM_MESON_TAC[LINEAR_INJECTIVE_LEFT_INVERSE]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Preservation of dimension by injective map.                               *)
+(* ------------------------------------------------------------------------- *)
+
+let DIM_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s.
+        linear f /\ (!x y. f x = f y ==> x = y) ==> dim(IMAGE f s) = dim s`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM LE_ANTISYM] THEN
+  CONJ_TAC THENL [ASM_MESON_TAC[DIM_LINEAR_IMAGE_LE]; ALL_TAC] THEN
+  MP_TAC(ISPEC `f:real^M->real^N` LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+  ASM_REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^M` STRIP_ASSUME_TAC) THEN
+  MATCH_MP_TAC LE_TRANS THEN
+  EXISTS_TAC `dim(IMAGE (g:real^N->real^M) (IMAGE (f:real^M->real^N) s))` THEN
+  CONJ_TAC THENL
+   [ASM_REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID; LE_REFL];
+    MATCH_MP_TAC DIM_LINEAR_IMAGE_LE THEN ASM_REWRITE_TAC[]]);;
+
+let LINEAR_INJECTIVE_DIMINDEX_LE = prove
+ (`!f:real^M->real^N.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> dimindex(:M) <= dimindex(:N)`,
+  REWRITE_TAC[GSYM DIM_UNIV] THEN REPEAT GEN_TAC THEN DISCH_THEN
+   (SUBST1_TAC o SYM o SPEC `(:real^M)` o
+    MATCH_MP DIM_INJECTIVE_LINEAR_IMAGE) THEN
+  MATCH_MP_TAC DIM_SUBSET THEN REWRITE_TAC[SUBSET_UNIV]);;
+
+let LINEAR_SURJECTIVE_DIMINDEX_LE = prove
+ (`!f:real^M->real^N.
+        linear f /\ (!y. ?x. f x = y)
+        ==> dimindex(:N) <= dimindex(:M)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN FIRST_ASSUM
+   (MP_TAC o MATCH_MP LINEAR_SURJECTIVE_RIGHT_INVERSE) THEN
+  REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `g:real^N->real^M` THEN STRIP_TAC THEN
+  MATCH_MP_TAC LINEAR_INJECTIVE_DIMINDEX_LE THEN
+  EXISTS_TAC `g:real^N->real^M` THEN ASM_MESON_TAC[]);;
+
+let LINEAR_BIJECTIVE_DIMINDEX_EQ = prove
+ (`!f:real^M->real^N.
+        linear f /\ (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+        ==> dimindex(:M) = dimindex(:N)`,
+  REWRITE_TAC[GSYM LE_ANTISYM] THEN REPEAT STRIP_TAC THENL
+   [MATCH_MP_TAC LINEAR_INJECTIVE_DIMINDEX_LE;
+    MATCH_MP_TAC LINEAR_SURJECTIVE_DIMINDEX_LE] THEN
+  EXISTS_TAC `f:real^M->real^N` THEN ASM_REWRITE_TAC[]);;
+
+let INVERTIBLE_IMP_SQUARE_MATRIX = prove
+ (`!A:real^N^M. invertible A ==> dimindex(:M) = dimindex(:N)`,
+  GEN_TAC THEN REWRITE_TAC[invertible; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `B:real^M^N` THEN STRIP_TAC THEN
+  MATCH_MP_TAC LINEAR_BIJECTIVE_DIMINDEX_EQ THEN
+  EXISTS_TAC `\x:real^M. (B:real^M^N) ** x` THEN
+  ASM_REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR;
+                  GSYM MATRIX_LEFT_INVERTIBLE_INJECTIVE;
+                  GSYM MATRIX_RIGHT_INVERTIBLE_SURJECTIVE] THEN
+  ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Considering an n-element vector as an n-by-1 or 1-by-n matrix.            *)
+(* ------------------------------------------------------------------------- *)
+
+let rowvector = new_definition
+ `(rowvector:real^N->real^N^1) v = lambda i j. v$j`;;
+
+let columnvector = new_definition
+ `(columnvector:real^N->real^1^N) v = lambda i j. v$i`;;
+
+let TRANSP_COLUMNVECTOR = prove
+ (`!v. transp(columnvector v) = rowvector v`,
+  SIMP_TAC[transp; columnvector; rowvector; CART_EQ; LAMBDA_BETA]);;
+
+let TRANSP_ROWVECTOR = prove
+ (`!v. transp(rowvector v) = columnvector v`,
+  SIMP_TAC[transp; columnvector; rowvector; CART_EQ; LAMBDA_BETA]);;
+
+let DOT_ROWVECTOR_COLUMNVECTOR = prove
+ (`!A:real^N^M v:real^N. columnvector(A ** v) = A ** columnvector v`,
+  REWRITE_TAC[rowvector; columnvector; matrix_mul; matrix_vector_mul] THEN
+  SIMP_TAC[CART_EQ; LAMBDA_BETA]);;
+
+let DOT_MATRIX_PRODUCT = prove
+ (`!x y:real^N. x dot y = (rowvector x ** columnvector y)$1$1`,
+  REWRITE_TAC[matrix_mul; columnvector; rowvector; dot] THEN
+  SIMP_TAC[LAMBDA_BETA; DIMINDEX_1; LE_REFL]);;
+
+let DOT_MATRIX_VECTOR_MUL = prove
+ (`!A:real^N^N B:real^N^N x:real^N y:real^N.
+      (A ** x) dot (B ** y) =
+      ((rowvector x) ** (transp(A) ** B) ** (columnvector y))$1$1`,
+  REWRITE_TAC[DOT_MATRIX_PRODUCT] THEN
+  ONCE_REWRITE_TAC[GSYM TRANSP_COLUMNVECTOR] THEN
+  REWRITE_TAC[DOT_ROWVECTOR_COLUMNVECTOR; MATRIX_TRANSP_MUL] THEN
+  REWRITE_TAC[MATRIX_MUL_ASSOC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Rank of a matrix. Equivalence of row and column rank is taken from        *)
+(* George Mackiw's paper, Mathematics Magazine 1995, p. 285.                 *)
+(* ------------------------------------------------------------------------- *)
+
+let MATRIX_VECTOR_MUL_IN_COLUMNSPACE = prove
+ (`!A:real^M^N x:real^M. (A ** x) IN span(columns A)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[MATRIX_VECTOR_COLUMN; columns] THEN
+  MATCH_MP_TAC SPAN_VSUM THEN
+  SIMP_TAC[FINITE_NUMSEG; IN_NUMSEG; transp; LAMBDA_BETA] THEN
+  X_GEN_TAC `k:num` THEN STRIP_TAC THEN MATCH_MP_TAC SPAN_MUL THEN
+  MATCH_MP_TAC SPAN_SUPERSET THEN
+  REWRITE_TAC[IN_ELIM_THM; column] THEN EXISTS_TAC `k:num` THEN
+  ASM_REWRITE_TAC[]);;
+
+let SUBSPACE_ORTHOGONAL_TO_VECTOR = prove
+ (`!x. subspace {y | orthogonal x y}`,
+  SIMP_TAC[subspace; IN_ELIM_THM; ORTHOGONAL_CLAUSES]);;
+
+let SUBSPACE_ORTHOGONAL_TO_VECTORS = prove
+ (`!s. subspace {y | (!x. x IN s ==> orthogonal x y)}`,
+  SIMP_TAC[subspace; IN_ELIM_THM; ORTHOGONAL_CLAUSES]);;
+
+let ORTHOGONAL_TO_SPAN = prove
+ (`!s x. (!y. y IN s ==> orthogonal x y)
+         ==> !y. y IN span(s) ==> orthogonal x y`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC SPAN_INDUCT THEN
+  REWRITE_TAC[SET_RULE `(\y. orthogonal x y) = {y | orthogonal x y}`] THEN
+  ASM_SIMP_TAC[SUBSPACE_ORTHOGONAL_TO_VECTOR; IN_ELIM_THM]);;
+
+let ORTHOGONAL_TO_SPAN_EQ = prove
+ (`!s x. (!y. y IN span(s) ==> orthogonal x y) <=>
+         (!y. y IN s ==> orthogonal x y)`,
+  MESON_TAC[SPAN_SUPERSET; ORTHOGONAL_TO_SPAN]);;
+
+let ORTHOGONAL_TO_SPANS_EQ = prove
+ (`!s t. (!x y. x IN span(s) /\ y IN span(t) ==> orthogonal x y) <=>
+         (!x y. x IN s /\ y IN t ==> orthogonal x y)`,
+  MESON_TAC[ORTHOGONAL_TO_SPAN_EQ; ORTHOGONAL_SYM]);;
+
+let ORTHOGONAL_NULLSPACE_ROWSPACE = prove
+ (`!A:real^M^N x y:real^M.
+        A ** x = vec 0 /\ y IN span(rows A) ==> orthogonal x y`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REPEAT GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC SPAN_INDUCT THEN
+  REWRITE_TAC[SET_RULE `(\y. orthogonal x y) = {y | orthogonal x y}`] THEN
+  REWRITE_TAC[SUBSPACE_ORTHOGONAL_TO_VECTOR; rows; FORALL_IN_GSPEC] THEN
+  X_GEN_TAC `k:num` THEN STRIP_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  FIRST_X_ASSUM(MP_TAC o AP_TERM `\y:real^N. y$k`) THEN
+  ASM_SIMP_TAC[MATRIX_VECTOR_MUL_COMPONENT; VEC_COMPONENT; row; dot;
+               orthogonal; LAMBDA_BETA] THEN
+  REWRITE_TAC[REAL_MUL_SYM]);;
+
+let NULLSPACE_INTER_ROWSPACE = prove
+ (`!A:real^M^N x:real^M. A ** x = vec 0 /\ x IN span(rows A) <=> x = vec 0`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [MESON_TAC[ORTHOGONAL_NULLSPACE_ROWSPACE; ORTHOGONAL_REFL];
+    SIMP_TAC[MATRIX_VECTOR_MUL_RZERO; SPAN_0]]);;
+
+let MATRIX_VECTOR_MUL_INJECTIVE_ON_ROWSPACE = prove
+ (`!A:real^M^N x y:real^M.
+        x IN span(rows A) /\ y IN span(rows A) /\ A ** x = A ** y ==> x = y`,
+  ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+  REWRITE_TAC[GSYM MATRIX_VECTOR_MUL_SUB_LDISTRIB] THEN
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM NULLSPACE_INTER_ROWSPACE] THEN
+  ASM_SIMP_TAC[SPAN_SUB]);;
+
+let DIM_ROWS_LE_DIM_COLUMNS = prove
+ (`!A:real^M^N. dim(rows A) <= dim(columns A)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM DIM_SPAN] THEN
+  X_CHOOSE_THEN `b:real^M->bool` STRIP_ASSUME_TAC
+   (ISPEC `span(rows(A:real^M^N))` BASIS_EXISTS) THEN
+  SUBGOAL_THEN `FINITE(IMAGE (\x:real^M. (A:real^M^N) ** x) b) /\
+                CARD (IMAGE (\x:real^M. (A:real^M^N) ** x) b) <=
+                dim(span(columns A))`
+  MP_TAC THENL
+   [MATCH_MP_TAC INDEPENDENT_CARD_LE_DIM THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; MATRIX_VECTOR_MUL_IN_COLUMNSPACE] THEN
+    MATCH_MP_TAC INDEPENDENT_INJECTIVE_IMAGE_GEN THEN
+    ASM_REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR] THEN
+    SUBGOAL_THEN `span(b) = span(rows(A:real^M^N))` SUBST1_TAC THENL
+     [ALL_TAC; ASM_MESON_TAC[MATRIX_VECTOR_MUL_INJECTIVE_ON_ROWSPACE]] THEN
+    MATCH_MP_TAC SUBSET_ANTISYM THEN ASM_REWRITE_TAC[] THEN
+    GEN_REWRITE_TAC RAND_CONV [GSYM SPAN_SPAN] THEN
+    ASM_SIMP_TAC[SPAN_MONO];
+    DISCH_THEN(MP_TAC o CONJUNCT2) THEN MATCH_MP_TAC EQ_IMP THEN
+    AP_THM_TAC THEN AP_TERM_TAC THEN
+    FIRST_ASSUM(CONJUNCTS_THEN2 ASSUME_TAC (SUBST1_TAC o SYM) o
+      GEN_REWRITE_RULE I [HAS_SIZE]) THEN
+    MATCH_MP_TAC CARD_IMAGE_INJ THEN ASM_REWRITE_TAC[] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC
+     (ISPEC `A:real^M^N` MATRIX_VECTOR_MUL_INJECTIVE_ON_ROWSPACE) THEN
+    ASM SET_TAC[]]);;
+
+let rank = new_definition
+ `rank(A:real^M^N) = dim(columns A)`;;
+
+let RANK_ROW = prove
+ (`!A:real^M^N. rank(A) = dim(rows A)`,
+  GEN_TAC THEN REWRITE_TAC[rank] THEN
+  MP_TAC(ISPEC `A:real^M^N` DIM_ROWS_LE_DIM_COLUMNS) THEN
+  MP_TAC(ISPEC `transp(A:real^M^N)` DIM_ROWS_LE_DIM_COLUMNS) THEN
+  REWRITE_TAC[ROWS_TRANSP; COLUMNS_TRANSP] THEN ARITH_TAC);;
+
+let RANK_TRANSP = prove
+ (`!A:real^M^N. rank(transp A) = rank A`,
+  GEN_TAC THEN GEN_REWRITE_TAC RAND_CONV [RANK_ROW] THEN
+  REWRITE_TAC[rank; COLUMNS_TRANSP]);;
+
+let MATRIX_VECTOR_MUL_BASIS = prove
+ (`!A:real^M^N k. 1 <= k /\ k <= dimindex(:M)
+                 ==> A ** (basis k) = column k A`,
+  SIMP_TAC[CART_EQ; column; MATRIX_VECTOR_MUL_COMPONENT; DOT_BASIS;
+           LAMBDA_BETA]);;
+
+let COLUMNS_IMAGE_BASIS = prove
+ (`!A:real^M^N.
+     columns A = IMAGE (\x. A ** x) {basis i | 1 <= i /\ i <= dimindex(:M)}`,
+  GEN_TAC THEN REWRITE_TAC[columns] THEN
+  ONCE_REWRITE_TAC[SIMPLE_IMAGE_GEN] THEN
+  REWRITE_TAC[GSYM IMAGE_o; o_DEF] THEN
+  MATCH_MP_TAC(SET_RULE
+    `(!x. x IN s ==> f x = g x) ==> IMAGE f s = IMAGE g s`) THEN
+  SIMP_TAC[IN_ELIM_THM; MATRIX_VECTOR_MUL_BASIS]);;
+
+let RANK_DIM_IM = prove
+ (`!A:real^M^N. rank A = dim(IMAGE (\x. A ** x) (:real^M))`,
+  GEN_TAC THEN REWRITE_TAC[rank] THEN
+  MATCH_MP_TAC SPAN_EQ_DIM THEN REWRITE_TAC[COLUMNS_IMAGE_BASIS] THEN
+  SIMP_TAC[SPAN_LINEAR_IMAGE; MATRIX_VECTOR_MUL_LINEAR] THEN
+  AP_TERM_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM SPAN_SPAN] THEN
+  REWRITE_TAC[SPAN_STDBASIS]);;
+
+let DIM_EQ_SPAN = prove
+ (`!s t:real^N->bool. s SUBSET t /\ dim t <= dim s ==> span s = span t`,
+  REPEAT STRIP_TAC THEN
+  X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC
+   (ISPEC `span s:real^N->bool` BASIS_EXISTS) THEN
+  MP_TAC(ISPECL [`span t:real^N->bool`; `b:real^N->bool`]
+    CARD_GE_DIM_INDEPENDENT) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN
+  ASM_REWRITE_TAC[DIM_SPAN] THEN
+  ASM_MESON_TAC[SPAN_MONO; SPAN_SPAN; SUBSET_TRANS; SUBSET_ANTISYM]);;
+
+let DIM_EQ_FULL = prove
+ (`!s:real^N->bool. dim s = dimindex(:N) <=> span s = (:real^N)`,
+  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM DIM_SPAN] THEN EQ_TAC THEN
+  SIMP_TAC[DIM_UNIV] THEN DISCH_TAC THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM SPAN_UNIV] THEN MATCH_MP_TAC DIM_EQ_SPAN THEN
+  ASM_REWRITE_TAC[SUBSET_UNIV; DIM_UNIV] THEN
+  ASM_MESON_TAC[LE_REFL; DIM_SPAN]);;
+
+let DIM_PSUBSET = prove
+ (`!s t. (span s) PSUBSET (span t) ==> dim s < dim t`,
+  ONCE_REWRITE_TAC[GSYM DIM_SPAN] THEN
+  SIMP_TAC[PSUBSET; DIM_SUBSET; LT_LE] THEN
+  MESON_TAC[EQ_IMP_LE; DIM_EQ_SPAN; SPAN_SPAN]);;
+
+let RANK_BOUND = prove
+ (`!A:real^M^N. rank(A) <= MIN (dimindex(:M)) (dimindex(:N))`,
+  GEN_TAC THEN REWRITE_TAC[ARITH_RULE `x <= MIN a b <=> x <= a /\ x <= b`] THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[DIM_SUBSET_UNIV; RANK_ROW];
+    REWRITE_TAC[DIM_SUBSET_UNIV; rank]]);;
+
+let FULL_RANK_INJECTIVE = prove
+ (`!A:real^M^N.
+        rank A = dimindex(:M) <=>
+        (!x y:real^M. A ** x = A ** y ==> x = y)`,
+  REWRITE_TAC[GSYM MATRIX_LEFT_INVERTIBLE_INJECTIVE] THEN
+  REWRITE_TAC[MATRIX_LEFT_INVERTIBLE_SPAN_ROWS] THEN
+  REWRITE_TAC[RANK_ROW; DIM_EQ_FULL]);;
+
+let FULL_RANK_SURJECTIVE = prove
+ (`!A:real^M^N.
+        rank A = dimindex(:N) <=> (!y:real^N. ?x:real^M. A ** x = y)`,
+  REWRITE_TAC[GSYM MATRIX_RIGHT_INVERTIBLE_SURJECTIVE] THEN
+  REWRITE_TAC[GSYM LEFT_INVERTIBLE_TRANSP] THEN
+  REWRITE_TAC[MATRIX_LEFT_INVERTIBLE_INJECTIVE] THEN
+  REWRITE_TAC[GSYM FULL_RANK_INJECTIVE; RANK_TRANSP]);;
+
+let RANK_I = prove
+ (`rank(mat 1:real^N^N) = dimindex(:N)`,
+  REWRITE_TAC[FULL_RANK_INJECTIVE; MATRIX_VECTOR_MUL_LID]);;
+
+let MATRIX_FULL_LINEAR_EQUATIONS = prove
+ (`!A:real^M^N b:real^N.
+        rank A = dimindex(:N) ==> ?x. A ** x = b`,
+  SIMP_TAC[FULL_RANK_SURJECTIVE]);;
+
+let MATRIX_NONFULL_LINEAR_EQUATIONS_EQ = prove
+ (`!A:real^M^N.
+        (?x. ~(x = vec 0) /\ A ** x = vec 0) <=> ~(rank A = dimindex(:M))`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[FULL_RANK_INJECTIVE] THEN
+  SIMP_TAC[LINEAR_INJECTIVE_0; MATRIX_VECTOR_MUL_LINEAR] THEN
+  MESON_TAC[]);;
+
+let MATRIX_NONFULL_LINEAR_EQUATIONS = prove
+ (`!A:real^M^N.
+        ~(rank A = dimindex(:M)) ==> ?x. ~(x = vec 0) /\ A ** x = vec 0`,
+  REWRITE_TAC[MATRIX_NONFULL_LINEAR_EQUATIONS_EQ]);;
+
+let MATRIX_TRIVIAL_LINEAR_EQUATIONS = prove
+ (`!A:real^M^N.
+        dimindex(:N) < dimindex(:M)
+        ==> ?x. ~(x = vec 0) /\ A ** x = vec 0`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC MATRIX_NONFULL_LINEAR_EQUATIONS THEN
+  MATCH_MP_TAC(ARITH_RULE
+   `!a. x <= MIN b a /\ a < b ==> ~(x = b)`) THEN
+  EXISTS_TAC `dimindex(:N)` THEN ASM_REWRITE_TAC[RANK_BOUND]);;
+
+let RANK_EQ_0 = prove
+ (`!A:real^M^N. rank A = 0 <=> A = mat 0`,
+  REWRITE_TAC[RANK_DIM_IM; DIM_EQ_0; SUBSET; FORALL_IN_IMAGE; IN_SING;
+              IN_UNIV] THEN
+  GEN_TAC THEN GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [CART_EQ] THEN
+  SIMP_TAC[CART_EQ; MATRIX_MUL_DOT; VEC_COMPONENT; LAMBDA_BETA; mat] THEN
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM; FORALL_DOT_EQ_0; COND_ID] THEN
+  REWRITE_TAC[CART_EQ; VEC_COMPONENT]);;
+
+let RANK_0 = prove
+ (`rank(mat 0) = 0`,
+  REWRITE_TAC[RANK_EQ_0]);;
+
+let RANK_MUL_LE_RIGHT = prove
+ (`!A:real^N^M B:real^P^N. rank(A ** B) <= rank(B)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC LE_TRANS THEN
+  EXISTS_TAC `dim(IMAGE (\y. (A:real^N^M) ** y)
+                        (IMAGE (\x. (B:real^P^N) ** x) (:real^P)))` THEN
+  REWRITE_TAC[RANK_DIM_IM] THEN CONJ_TAC THENL
+   [REWRITE_TAC[GSYM IMAGE_o; o_DEF; MATRIX_VECTOR_MUL_ASSOC; LE_REFL];
+    MATCH_MP_TAC DIM_LINEAR_IMAGE_LE THEN
+    REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR]]);;
+
+let RANK_MUL_LE_LEFT = prove
+ (`!A:real^N^M B:real^P^N. rank(A ** B) <= rank(A)`,
+  ONCE_REWRITE_TAC[GSYM RANK_TRANSP] THEN
+  REWRITE_TAC[MATRIX_TRANSP_MUL] THEN
+  REWRITE_TAC[RANK_MUL_LE_RIGHT]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Basic lemmas about hyperplanes and halfspaces.                            *)
+(* ------------------------------------------------------------------------- *)
+
+let HYPERPLANE_EQ_EMPTY = prove
+ (`!a:real^N b. {x | a dot x = b} = {} <=> a = vec 0 /\ ~(b = &0)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY] THEN
+  ASM_CASES_TAC `a:real^N = vec 0` THEN ASM_REWRITE_TAC[DOT_LZERO] THENL
+   [MESON_TAC[];
+    DISCH_THEN(MP_TAC o SPEC `b / (a dot a) % a:real^N`) THEN
+    ASM_SIMP_TAC[DOT_RMUL; REAL_DIV_RMUL; DOT_EQ_0]]);;
+
+let HYPERPLANE_EQ_UNIV = prove
+ (`!a b. {x | a dot x = b} = (:real^N) <=> a = vec 0 /\ b = &0`,
+  REPEAT GEN_TAC THEN  REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_UNIV] THEN
+  ASM_CASES_TAC `a:real^N = vec 0` THEN ASM_REWRITE_TAC[DOT_LZERO] THENL
+   [MESON_TAC[];
+    DISCH_THEN(MP_TAC o SPEC `(b + &1) / (a dot a) % a:real^N`) THEN
+    ASM_SIMP_TAC[DOT_RMUL; REAL_DIV_RMUL; DOT_EQ_0] THEN REAL_ARITH_TAC]);;
+
+let HALFSPACE_EQ_EMPTY_LT = prove
+ (`!a:real^N b. {x | a dot x < b} = {} <=> a = vec 0 /\ b <= &0`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THENL
+   [ASM_SIMP_TAC[DOT_LZERO; SET_RULE `{x | p} = if p then UNIV else {}`] THEN
+    COND_CASES_TAC THEN REWRITE_TAC[UNIV_NOT_EMPTY] THEN ASM_REAL_ARITH_TAC;
+    ASM_REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+    EXISTS_TAC `(b - &1) / (a dot a) % a:real^N` THEN
+    ASM_SIMP_TAC[DOT_RMUL; REAL_DIV_RMUL; DOT_EQ_0] THEN
+    REAL_ARITH_TAC]);;
+
+let HALFSPACE_EQ_EMPTY_GT = prove
+ (`!a:real^N b. {x | a dot x > b} = {} <=> a = vec 0 /\ b >= &0`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`--a:real^N`; `--b:real`] HALFSPACE_EQ_EMPTY_LT) THEN
+  SIMP_TAC[real_gt; DOT_LNEG; REAL_LT_NEG2; VECTOR_NEG_EQ_0] THEN
+  DISCH_TAC THEN AP_TERM_TAC THEN REAL_ARITH_TAC);;
+
+let HALFSPACE_EQ_EMPTY_LE = prove
+ (`!a:real^N b. {x | a dot x <= b} = {} <=> a = vec 0 /\ b < &0`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THENL
+   [ASM_SIMP_TAC[DOT_LZERO; SET_RULE `{x | p} = if p then UNIV else {}`] THEN
+    COND_CASES_TAC THEN REWRITE_TAC[UNIV_NOT_EMPTY] THEN ASM_REAL_ARITH_TAC;
+    ASM_REWRITE_TAC[GSYM MEMBER_NOT_EMPTY; IN_ELIM_THM] THEN
+    EXISTS_TAC `(b - &1) / (a dot a) % a:real^N` THEN
+    ASM_SIMP_TAC[DOT_RMUL; REAL_DIV_RMUL; DOT_EQ_0] THEN
+    REAL_ARITH_TAC]);;
+
+let HALFSPACE_EQ_EMPTY_GE = prove
+ (`!a:real^N b. {x | a dot x >= b} = {} <=> a = vec 0 /\ b > &0`,
+  REPEAT GEN_TAC THEN
+  MP_TAC(ISPECL [`--a:real^N`; `--b:real`] HALFSPACE_EQ_EMPTY_LE) THEN
+  SIMP_TAC[real_ge; DOT_LNEG; REAL_LE_NEG2; VECTOR_NEG_EQ_0] THEN
+  DISCH_TAC THEN AP_TERM_TAC THEN REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* A non-injective linear function maps into a hyperplane.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let ADJOINT_INJECTIVE = prove
+ (`!f:real^M->real^N.
+        linear f
+        ==> ((!x y. adjoint f x = adjoint f y ==> x = y) <=>
+             (!y. ?x. f x = y))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o GSYM o MATCH_MP MATRIX_WORKS o MATCH_MP
+   ADJOINT_LINEAR) THEN
+  FIRST_ASSUM(ASSUME_TAC o GSYM o MATCH_MP MATRIX_WORKS) THEN
+  ASM_REWRITE_TAC[GSYM FULL_RANK_INJECTIVE; GSYM FULL_RANK_SURJECTIVE] THEN
+  ASM_SIMP_TAC[MATRIX_ADJOINT; RANK_TRANSP]);;
+
+let ADJOINT_SURJECTIVE = prove
+ (`!f:real^M->real^N.
+        linear f
+        ==> ((!y. ?x. adjoint f x = y) <=> (!x y. f x = f y ==> x = y))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV)
+   [GSYM(MATCH_MP ADJOINT_ADJOINT th)]) THEN
+  ASM_SIMP_TAC[ADJOINT_INJECTIVE; ADJOINT_LINEAR]);;
+
+let ADJOINT_INJECTIVE_INJECTIVE = prove
+ (`!f:real^N->real^N.
+        linear f
+        ==> ((!x y. adjoint f x = adjoint f y ==> x = y) <=>
+             (!x y. f x = f y ==> x = y))`,
+  SIMP_TAC[ADJOINT_INJECTIVE] THEN
+  MESON_TAC[LINEAR_INJECTIVE_IMP_SURJECTIVE;
+            LINEAR_SURJECTIVE_IMP_INJECTIVE]);;
+
+let ADJOINT_INJECTIVE_INJECTIVE_0 = prove
+ (`!f:real^N->real^N.
+        linear f
+        ==> ((!x. adjoint f x = vec 0 ==> x = vec 0) <=>
+             (!x. f x = vec 0 ==> x = vec 0))`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ADJOINT_INJECTIVE_INJECTIVE) THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP ADJOINT_LINEAR) THEN
+  ASM_MESON_TAC[LINEAR_INJECTIVE_0]);;
+
+let LINEAR_SINGULAR_INTO_HYPERPLANE = prove
+ (`!f:real^N->real^N.
+        linear f
+        ==> (~(!x y. f(x) = f(y) ==> x = y) <=>
+             ?a. ~(a = vec 0) /\ !x. a dot f(x) = &0)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[DOT_SYM] THEN
+  ASM_SIMP_TAC[ADJOINT_WORKS; FORALL_DOT_EQ_0] THEN
+  REWRITE_TAC[MESON[] `(?a. ~p a /\ q a) <=> ~(!a. q a ==> p a)`] THEN
+  ASM_SIMP_TAC[ADJOINT_INJECTIVE_INJECTIVE_0; LINEAR_INJECTIVE_0]);;
+
+let LINEAR_SINGULAR_IMAGE_HYPERPLANE = prove
+ (`!f:real^N->real^N.
+        linear f /\ ~(!x y. f(x) = f(y) ==> x = y)
+        ==> ?a. ~(a = vec 0) /\ !s. IMAGE f s SUBSET {x | a dot x = &0}`,
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  ASM_SIMP_TAC[LINEAR_SINGULAR_INTO_HYPERPLANE] THEN
+  SIMP_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let LOWDIM_EXPAND_DIMENSION = prove
+ (`!s:real^N->bool n.
+        dim s <= n /\ n <= dimindex(:N)
+        ==> ?t. dim(t) = n /\ span s SUBSET span t`,
+  GEN_TAC THEN
+  GEN_REWRITE_TAC (BINDER_CONV o LAND_CONV o LAND_CONV) [LE_EXISTS] THEN
+  SIMP_TAC[LEFT_AND_EXISTS_THM; LEFT_IMP_EXISTS_THM; IMP_CONJ] THEN
+  ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN
+  REWRITE_TAC[RIGHT_FORALL_IMP_THM; LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN
+  INDUCT_TAC THENL [MESON_TAC[ADD_CLAUSES; SUBSET_REFL]; ALL_TAC] THEN
+  REWRITE_TAC[ARITH_RULE `s + SUC d <= n <=> s + d < n`] THEN
+  DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o check (is_imp o concl)) THEN
+  ASM_SIMP_TAC[LT_IMP_LE; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN
+  REWRITE_TAC[ADD_CLAUSES] THEN FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+  SUBGOAL_THEN `~(span t = (:real^N))` MP_TAC THENL
+   [REWRITE_TAC[GSYM DIM_EQ_FULL] THEN ASM_ARITH_TAC; ALL_TAC] THEN
+  REWRITE_TAC[EXTENSION; IN_UNIV; NOT_FORALL_THM; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `a:real^N` THEN DISCH_TAC THEN
+  EXISTS_TAC `(a:real^N) INSERT t` THEN ASM_REWRITE_TAC[DIM_INSERT; ADD1] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN EXISTS_TAC `span(t:real^N->bool)` THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC SPAN_MONO THEN SET_TAC[]);;
+
+let LOWDIM_EXPAND_BASIS = prove
+ (`!s:real^N->bool n.
+        dim s <= n /\ n <= dimindex(:N)
+        ==> ?b. b HAS_SIZE n /\ independent b /\ span s SUBSET span b`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC o
+    MATCH_MP LOWDIM_EXPAND_DIMENSION) THEN
+  MP_TAC(ISPEC `t:real^N->bool` BASIS_EXISTS) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `b:real^N->bool` THEN
+  ASM_REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  ASM_MESON_TAC[SPAN_SPAN; SUBSET_TRANS; SPAN_MONO]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Orthogonal bases, Gram-Schmidt process, and related theorems.             *)
+(* ------------------------------------------------------------------------- *)
+
+let SPAN_DELETE_0 = prove
+ (`!s:real^N->bool. span(s DELETE vec 0) = span s`,
+  GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  SIMP_TAC[DELETE_SUBSET; SPAN_MONO] THEN
+  MATCH_MP_TAC SUBSET_TRANS THEN
+  EXISTS_TAC `span((vec 0:real^N) INSERT (s DELETE vec 0))` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SPAN_MONO THEN SET_TAC[];
+    SIMP_TAC[SUBSET; SPAN_BREAKDOWN_EQ; VECTOR_MUL_RZERO; VECTOR_SUB_RZERO]]);;
+
+let SPAN_IMAGE_SCALE = prove
+ (`!c s. FINITE s /\ (!x. x IN s ==> ~(c x = &0))
+         ==> span (IMAGE (\x:real^N. c(x) % x) s) = span s`,
+  GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN
+  MATCH_MP_TAC FINITE_INDUCT_STRONG THEN
+  SIMP_TAC[IMAGE_CLAUSES; SPAN_BREAKDOWN_EQ; EXTENSION; FORALL_IN_INSERT] THEN
+  MAP_EVERY X_GEN_TAC [`x:real^N`; `t:real^N->bool`] THEN
+  STRIP_TAC THEN STRIP_TAC THEN X_GEN_TAC `y:real^N` THEN
+  REWRITE_TAC[VECTOR_MUL_ASSOC] THEN EQ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_TAC `k:real`) THEN
+  EXISTS_TAC `k / (c:real^N->real) x` THEN
+  ASM_SIMP_TAC[REAL_DIV_RMUL]);;
+
+let PAIRWISE_ORTHOGONAL_INDEPENDENT = prove
+ (`!s:real^N->bool.
+        pairwise orthogonal s /\ ~(vec 0 IN s) ==> independent s`,
+  REWRITE_TAC[pairwise; orthogonal] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[independent; dependent] THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^N` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
+  REWRITE_TAC[SPAN_EXPLICIT; IN_ELIM_THM; NOT_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`t:real^N->bool`; `u:real^N->real`] THEN
+  REWRITE_TAC[SUBSET; IN_DELETE] THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o AP_TERM `\x:real^N. a dot x`) THEN
+  ASM_SIMP_TAC[DOT_RSUM; DOT_RMUL; REAL_MUL_RZERO; SUM_0] THEN
+  ASM_MESON_TAC[DOT_EQ_0]);;
+
+let PAIRWISE_ORTHOGONAL_IMP_FINITE = prove
+ (`!s:real^N->bool. pairwise orthogonal s ==> FINITE s`,
+  REPEAT STRIP_TAC THEN
+  SUBGOAL_THEN `independent (s DELETE (vec 0:real^N))` MP_TAC THENL
+   [MATCH_MP_TAC PAIRWISE_ORTHOGONAL_INDEPENDENT THEN
+    REWRITE_TAC[IN_DELETE] THEN MATCH_MP_TAC PAIRWISE_MONO THEN
+    EXISTS_TAC `s:real^N->bool` THEN
+    ASM_SIMP_TAC[SUBSET; IN_DELETE];
+    DISCH_THEN(MP_TAC o MATCH_MP INDEPENDENT_IMP_FINITE) THEN
+    REWRITE_TAC[FINITE_DELETE]]);;
+
+let GRAM_SCHMIDT_STEP = prove
+ (`!s a x.
+        pairwise orthogonal s /\ x IN span s
+        ==> orthogonal x (a - vsum s (\b:real^N. (b dot a) / (b dot b) % b))`,
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[ONCE_REWRITE_RULE[ORTHOGONAL_SYM] ORTHOGONAL_TO_SPAN_EQ] THEN
+  X_GEN_TAC `s:real^N->bool` THEN STRIP_TAC THEN
+  MAP_EVERY X_GEN_TAC [`a:real^N`; `x:real^N`] THEN DISCH_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP PAIRWISE_ORTHOGONAL_IMP_FINITE) THEN
+  REWRITE_TAC[orthogonal; DOT_RSUB] THEN ASM_SIMP_TAC[DOT_RSUM] THEN
+  REWRITE_TAC[REAL_SUB_0; DOT_RMUL] THEN MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `sum s (\y:real^N. if y = x then y dot a else &0)` THEN
+  CONJ_TAC THENL [ASM_SIMP_TAC[SUM_DELTA; DOT_SYM]; ALL_TAC] THEN
+  MATCH_MP_TAC SUM_EQ THEN X_GEN_TAC `y:real^N` THEN DISCH_TAC THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pairwise; orthogonal]) THEN
+  ASM_CASES_TAC `x:real^N = y` THEN ASM_SIMP_TAC[DOT_LMUL; REAL_MUL_RZERO] THEN
+  ASM_CASES_TAC `y:real^N = vec 0` THEN
+  ASM_SIMP_TAC[REAL_DIV_RMUL; DOT_EQ_0; DOT_LZERO; REAL_MUL_RZERO]);;
+
+let ORTHOGONAL_EXTENSION = prove
+ (`!s t:real^N->bool.
+        pairwise orthogonal s
+        ==> ?u. pairwise orthogonal (s UNION u) /\
+                span (s UNION u) = span (s UNION t)`,
+  let lemma = prove
+   (`!t s:real^N->bool.
+        FINITE t /\ FINITE s /\ pairwise orthogonal s
+        ==> ?u. pairwise orthogonal (s UNION u) /\
+                span (s UNION u) = span (s UNION t)`,
+    REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+    MATCH_MP_TAC FINITE_INDUCT_STRONG THEN CONJ_TAC THENL
+     [REPEAT STRIP_TAC THEN EXISTS_TAC `{}:real^N->bool` THEN
+      ASM_REWRITE_TAC[UNION_EMPTY];
+      ALL_TAC] THEN
+    MAP_EVERY X_GEN_TAC [`a:real^N`; `t:real^N->bool`] THEN
+    REWRITE_TAC[pairwise; orthogonal] THEN REPEAT STRIP_TAC THEN
+    ABBREV_TAC `a' = a - vsum s (\b:real^N. (b dot a) / (b dot b) % b)` THEN
+    FIRST_X_ASSUM(MP_TAC o SPEC `(a':real^N) INSERT s`) THEN
+    ASM_REWRITE_TAC[FINITE_INSERT] THEN ANTS_TAC THENL
+     [SUBGOAL_THEN `!x:real^N. x IN s ==> a' dot x = &0`
+       (fun th -> REWRITE_TAC[IN_INSERT] THEN ASM_MESON_TAC[DOT_SYM; th]) THEN
+      REPEAT STRIP_TAC THEN EXPAND_TAC "a'" THEN
+      REWRITE_TAC[GSYM orthogonal] THEN ONCE_REWRITE_TAC[ORTHOGONAL_SYM] THEN
+      MATCH_MP_TAC GRAM_SCHMIDT_STEP THEN
+      ASM_SIMP_TAC[pairwise; orthogonal; SPAN_CLAUSES];
+      DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+      EXISTS_TAC `(a':real^N) INSERT u` THEN
+      ASM_REWRITE_TAC[SET_RULE `s UNION a INSERT u = a INSERT s UNION u`] THEN
+      REWRITE_TAC[SET_RULE `(x INSERT s) UNION t = x INSERT (s UNION t)`] THEN
+      MATCH_MP_TAC EQ_SPAN_INSERT_EQ THEN EXPAND_TAC "a'" THEN
+      REWRITE_TAC[VECTOR_ARITH `a - x - a:real^N = --x`] THEN
+      MATCH_MP_TAC SPAN_NEG THEN MATCH_MP_TAC SPAN_VSUM THEN
+      ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+      MATCH_MP_TAC SPAN_MUL THEN ASM_SIMP_TAC[SPAN_SUPERSET; IN_UNION]]) in
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `span t:real^N->bool` BASIS_SUBSPACE_EXISTS) THEN
+  REWRITE_TAC[SUBSPACE_SPAN; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `b:real^N->bool` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`b:real^N->bool`; `s:real^N->bool`] lemma) THEN
+  ANTS_TAC THENL
+   [ASM_MESON_TAC[HAS_SIZE; PAIRWISE_ORTHOGONAL_IMP_FINITE];
+    MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+    ASM_REWRITE_TAC[SPAN_UNION]]);;
+
+let ORTHOGONAL_EXTENSION_STRONG = prove
+ (`!s t:real^N->bool.
+        pairwise orthogonal s
+        ==> ?u. DISJOINT u (vec 0 INSERT s) /\
+                pairwise orthogonal (s UNION u) /\
+                span (s UNION u) = span (s UNION t)`,
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o
+    SPEC `t:real^N->bool` o MATCH_MP ORTHOGONAL_EXTENSION) THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `u DIFF ((vec 0:real^N) INSERT s)` THEN REPEAT CONJ_TAC THENL
+   [SET_TAC[];
+    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        PAIRWISE_MONO)) THEN SET_TAC[];
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    GEN_REWRITE_TAC BINOP_CONV [GSYM SPAN_DELETE_0] THEN
+    AP_TERM_TAC THEN SET_TAC[]]);;
+
+let ORTHONORMAL_EXTENSION = prove
+ (`!s t:real^N->bool.
+        pairwise orthogonal s /\ (!x. x IN s ==> norm x = &1)
+        ==> ?u. DISJOINT u s /\
+                pairwise orthogonal (s UNION u) /\
+                (!x. x IN u ==> norm x = &1) /\
+                span(s UNION u) = span(s UNION t)`,
+  REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o
+    SPEC `t:real^N->bool` o MATCH_MP ORTHOGONAL_EXTENSION_STRONG) THEN
+  REWRITE_TAC[SET_RULE `DISJOINT u s <=> !x. x IN u ==> ~(x IN s)`] THEN
+  REWRITE_TAC[IN_INSERT; DE_MORGAN_THM; pairwise] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `IMAGE (\x:real^N. inv(norm x) % x) u` THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REPEAT CONJ_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    ASM_CASES_TAC `norm(x:real^N) = &1` THEN
+    ASM_SIMP_TAC[REAL_INV_1; VECTOR_MUL_LID] THEN DISCH_TAC THEN
+    FIRST_X_ASSUM(MP_TAC o SPECL [`x:real^N`; `inv(norm x) % x:real^N`]) THEN
+    ASM_REWRITE_TAC[IN_UNION; VECTOR_MUL_EQ_0; REAL_SUB_0; REAL_INV_EQ_1;
+      VECTOR_ARITH `x:real^N = a % x <=> (a - &1) % x = vec 0`] THEN
+    ASM_CASES_TAC `x:real^N = vec 0` THENL
+     [ASM_MESON_TAC[VECTOR_MUL_RZERO];
+      ASM_REWRITE_TAC[orthogonal; DOT_RMUL; REAL_ENTIRE; DOT_EQ_0] THEN
+      ASM_REWRITE_TAC[REAL_INV_EQ_0; NORM_EQ_0]];
+    REWRITE_TAC[IN_UNION; IN_IMAGE] THEN REPEAT STRIP_TAC THEN
+    ASM_SIMP_TAC[orthogonal; DOT_LMUL; DOT_RMUL; REAL_ENTIRE; DOT_EQ_0;
+                 REAL_INV_EQ_0; NORM_EQ_0] THEN
+    REWRITE_TAC[GSYM orthogonal] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
+    ASM_REWRITE_TAC[IN_UNION] THEN DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
+    ASM SET_TAC[];
+    ASM_SIMP_TAC[NORM_MUL; REAL_MUL_LINV; NORM_EQ_0; REAL_ABS_INV;
+                 REAL_ABS_NORM];
+    FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+    REWRITE_TAC[SPAN_EQ; UNION_SUBSET] THEN
+    SIMP_TAC[SUBSET; FORALL_IN_IMAGE; SPAN_SUPERSET; SPAN_MUL; IN_UNION] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `x:real^N = norm(x) % inv(norm x) % x`
+     (fun th -> GEN_REWRITE_TAC LAND_CONV [th])
+    THENL
+     [ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RINV; NORM_EQ_0; VECTOR_MUL_LID];
+      MATCH_MP_TAC SPAN_MUL THEN MATCH_MP_TAC SPAN_SUPERSET THEN
+      REWRITE_TAC[IN_UNION; IN_IMAGE] THEN ASM_MESON_TAC[]]]);;
+
+let VECTOR_IN_ORTHOGONAL_SPANNINGSET = prove
+ (`!a. ?s. a IN s /\ pairwise orthogonal s /\ span s = (:real^N)`,
+  GEN_TAC THEN
+  MP_TAC(ISPECL [`{a:real^N}`; `(IMAGE basis (1..dimindex(:N))):real^N->bool`]
+                 ORTHOGONAL_EXTENSION) THEN
+  REWRITE_TAC[PAIRWISE_SING] THEN
+  DISCH_THEN(X_CHOOSE_THEN `u:real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `{a:real^N} UNION u` THEN ASM_REWRITE_TAC[IN_UNION; IN_SING] THEN
+  MATCH_MP_TAC(SET_RULE `!s. s = UNIV /\ s SUBSET t ==> t = UNIV`) THEN
+  EXISTS_TAC `span {basis i:real^N | 1 <= i /\ i <= dimindex (:N)}` THEN
+  CONJ_TAC THENL [REWRITE_TAC[SPAN_STDBASIS]; MATCH_MP_TAC SPAN_MONO] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; GSYM IN_NUMSEG] THEN SET_TAC[]);;
+
+let VECTOR_IN_ORTHOGONAL_BASIS = prove
+ (`!a. ~(a = vec 0)
+       ==> ?s. a IN s /\ ~(vec 0 IN s) /\
+               pairwise orthogonal s /\
+               independent s /\
+               s HAS_SIZE (dimindex(:N)) /\
+               span s = (:real^N)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `a:real^N` VECTOR_IN_ORTHOGONAL_SPANNINGSET) THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `s DELETE (vec 0:real^N)` THEN ASM_REWRITE_TAC[IN_DELETE] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[pairwise]) THEN
+    ASM_SIMP_TAC[pairwise; IN_DELETE];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC PAIRWISE_ORTHOGONAL_INDEPENDENT THEN ASM_SIMP_TAC[IN_DELETE];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[SPAN_DELETE_0];
+    DISCH_TAC THEN ASM_SIMP_TAC[BASIS_HAS_SIZE_UNIV]]);;
+
+let VECTOR_IN_ORTHONORMAL_BASIS = prove
+ (`!a. norm a = &1
+       ==> ?s. a IN s /\
+               pairwise orthogonal s /\
+               (!x. x IN s ==> norm x = &1) /\
+               independent s /\
+               s HAS_SIZE (dimindex(:N)) /\
+               span s = (:real^N)`,
+  GEN_TAC THEN ASM_CASES_TAC `a:real^N = vec 0` THEN
+  ASM_REWRITE_TAC[NORM_0; REAL_OF_NUM_EQ; ARITH_EQ] THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP VECTOR_IN_ORTHOGONAL_BASIS) THEN
+  DISCH_THEN(X_CHOOSE_THEN `s:real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `IMAGE (\x:real^N. inv(norm x) % x) s` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `a:real^N` THEN
+    ASM_REWRITE_TAC[REAL_INV_1; VECTOR_MUL_LID];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REWRITE_TAC[pairwise; IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[pairwise]) THEN
+    ASM_MESON_TAC[ORTHOGONAL_CLAUSES];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REWRITE_TAC[FORALL_IN_IMAGE; NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+    ASM_MESON_TAC[REAL_MUL_LINV; NORM_EQ_0];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC PAIRWISE_ORTHOGONAL_INDEPENDENT THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[IN_IMAGE] THEN ONCE_REWRITE_TAC[EQ_SYM_EQ] THEN
+    SIMP_TAC[VECTOR_MUL_EQ_0; REAL_INV_EQ_0; NORM_EQ_0] THEN ASM_MESON_TAC[];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+   [ALL_TAC; ASM_SIMP_TAC[BASIS_HAS_SIZE_UNIV]] THEN
+  UNDISCH_THEN `span s = (:real^N)` (SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC SPAN_IMAGE_SCALE THEN
+  REWRITE_TAC[REAL_INV_EQ_0; NORM_EQ_0] THEN
+  ASM_MESON_TAC[HAS_SIZE]);;
+
+let BESSEL_INEQUALITY = prove
+ (`!s x:real^N.
+        pairwise orthogonal s /\ (!x. x IN s ==> norm x = &1)
+        ==> sum s (\e. (e dot x) pow 2) <= norm(x) pow 2`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP PAIRWISE_ORTHOGONAL_IMP_FINITE) THEN
+  MP_TAC(ISPEC `x - vsum s (\e. (e dot x) % e):real^N` DOT_POS_LE) THEN
+  REWRITE_TAC[NORM_POW_2; VECTOR_ARITH
+   `(a - b:real^N) dot (a - b) = a dot a + b dot b - &2 * b dot a`] THEN
+  ASM_SIMP_TAC[DOT_LSUM; REAL_POW_2; DOT_LMUL] THEN
+  MATCH_MP_TAC(REAL_ARITH `t = s ==> &0 <= x + t - &2 * s ==> s <= x`) THEN
+  MATCH_MP_TAC SUM_EQ THEN X_GEN_TAC `e:real^N` THEN DISCH_TAC THEN
+  ASM_SIMP_TAC[DOT_RSUM] THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `sum s (\k:real^N. if k = e then e dot x else &0)` THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_SIMP_TAC[SUM_DELTA]] THEN
+  MATCH_MP_TAC SUM_EQ THEN X_GEN_TAC `k:real^N` THEN DISCH_TAC THEN
+  REWRITE_TAC[DOT_RMUL] THEN COND_CASES_TAC THENL
+   [ASM_REWRITE_TAC[REAL_RING `a * x = a <=> a = &0 \/ x = &1`] THEN
+    DISJ2_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `e:real^N`) THEN
+    ASM_REWRITE_TAC[NORM_EQ_SQUARE] THEN REAL_ARITH_TAC;
+    RULE_ASSUM_TAC(REWRITE_RULE[pairwise; orthogonal]) THEN
+    ASM_SIMP_TAC[REAL_ENTIRE]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Analogous theorems for existence of orthonormal basis for a subspace.     *)
+(* ------------------------------------------------------------------------- *)
+
+let ORTHOGONAL_SPANNINGSET_SUBSPACE = prove
+ (`!s:real^N->bool.
+        subspace s
+        ==> ?b. b SUBSET s /\ pairwise orthogonal b /\ span b = s`,
+  REPEAT STRIP_TAC THEN MP_TAC(ISPEC `s:real^N->bool` BASIS_EXISTS) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL[`{}:real^N->bool`; `b:real^N->bool`] ORTHOGONAL_EXTENSION) THEN
+  REWRITE_TAC[PAIRWISE_EMPTY; UNION_EMPTY] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `c:real^N->bool` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SPAN_SUBSPACE THEN ASM_REWRITE_TAC[];
+    DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_MESON_TAC[SPAN_INC]]);;
+
+let ORTHOGONAL_BASIS_SUBSPACE = prove
+ (`!s:real^N->bool.
+        subspace s
+        ==> ?b. ~(vec 0 IN b) /\
+                b SUBSET s /\
+                pairwise orthogonal b /\
+                independent b /\
+                b HAS_SIZE (dim s) /\
+                span b = s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ORTHOGONAL_SPANNINGSET_SUBSPACE) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `b DELETE (vec 0:real^N)` THEN ASM_REWRITE_TAC[IN_DELETE] THEN
+  CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [RULE_ASSUM_TAC(REWRITE_RULE[pairwise]) THEN
+    ASM_SIMP_TAC[pairwise; IN_DELETE];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC PAIRWISE_ORTHOGONAL_INDEPENDENT THEN ASM_SIMP_TAC[IN_DELETE];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[SPAN_DELETE_0];
+    DISCH_TAC THEN ASM_SIMP_TAC[BASIS_HAS_SIZE_DIM]]);;
+
+let ORTHONORMAL_BASIS_SUBSPACE = prove
+ (`!s:real^N->bool.
+        subspace s
+        ==> ?b. b SUBSET s /\
+                pairwise orthogonal b /\
+                (!x. x IN b ==> norm x = &1) /\
+                independent b /\
+                b HAS_SIZE (dim s) /\
+                span b = s`,
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ORTHOGONAL_BASIS_SUBSPACE) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+  EXISTS_TAC `IMAGE (\x:real^N. inv(norm x) % x) b` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN
+    ASM_MESON_TAC[SPAN_MUL; SPAN_INC; SUBSET];
+    ALL_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REWRITE_TAC[pairwise; IMP_CONJ; RIGHT_FORALL_IMP_THM; FORALL_IN_IMAGE] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[pairwise]) THEN
+    ASM_MESON_TAC[ORTHOGONAL_CLAUSES];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [REWRITE_TAC[FORALL_IN_IMAGE; NORM_MUL; REAL_ABS_INV; REAL_ABS_NORM] THEN
+    ASM_MESON_TAC[REAL_MUL_LINV; NORM_EQ_0];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC(TAUT `a /\ (a ==> b) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC PAIRWISE_ORTHOGONAL_INDEPENDENT THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[IN_IMAGE] THEN ONCE_REWRITE_TAC[EQ_SYM_EQ] THEN
+    SIMP_TAC[VECTOR_MUL_EQ_0; REAL_INV_EQ_0; NORM_EQ_0] THEN ASM_MESON_TAC[];
+    DISCH_TAC] THEN
+  MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+   [ALL_TAC; ASM_SIMP_TAC[BASIS_HAS_SIZE_DIM]] THEN
+  UNDISCH_THEN `span b = (s:real^N->bool)` (SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC SPAN_IMAGE_SCALE THEN
+  REWRITE_TAC[REAL_INV_EQ_0; NORM_EQ_0] THEN
+  ASM_MESON_TAC[HAS_SIZE]);;
+
+let ORTHOGONAL_TO_SUBSPACE_EXISTS_GEN = prove
+ (`!s t:real^N->bool.
+        span s PSUBSET span t
+        ==> ?x. ~(x = vec 0) /\ x IN span t /\
+                (!y. y IN span s ==> orthogonal x y)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `span s:real^N->bool` ORTHOGONAL_BASIS_SUBSPACE) THEN
+  REWRITE_TAC[SUBSPACE_SPAN] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [PSUBSET_ALT]) THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
+   (X_CHOOSE_THEN `u:real^N` STRIP_ASSUME_TAC)) THEN
+  MP_TAC(ISPECL [`b:real^N->bool`; `{u:real^N}`] ORTHOGONAL_EXTENSION) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `ns:real^N->bool` MP_TAC) THEN
+  ASM_CASES_TAC `ns SUBSET (vec 0:real^N) INSERT b` THENL
+   [DISCH_THEN(MP_TAC o AP_TERM `(IN) (u:real^N)` o CONJUNCT2) THEN
+    SIMP_TAC[SPAN_SUPERSET; IN_UNION; IN_SING] THEN
+    MATCH_MP_TAC(TAUT `~p ==> p ==> q`) THEN
+    SUBGOAL_THEN `~(u IN span (b UNION {vec 0:real^N}))` MP_TAC THENL
+     [ASM_REWRITE_TAC[SET_RULE `s UNION {a} = a INSERT s`; SPAN_INSERT_0];
+      MATCH_MP_TAC(SET_RULE `s SUBSET t ==> ~(x IN t) ==> ~(x IN s)`) THEN
+      MATCH_MP_TAC SPAN_MONO THEN ASM SET_TAC[]];
+    ALL_TAC] THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP (SET_RULE
+   `~(s SUBSET t) ==> ?z. z IN s /\ ~(z IN t)`)) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM; IN_INSERT; DE_MORGAN_THM] THEN
+  X_GEN_TAC `n:real^N` THEN STRIP_TAC THEN
+  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
+  REWRITE_TAC[pairwise; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  DISCH_THEN(MP_TAC o SPEC `n:real^N`) THEN ASM_REWRITE_TAC[IN_UNION] THEN
+  REWRITE_TAC[IMP_IMP] THEN DISCH_TAC THEN EXISTS_TAC `n:real^N` THEN
+  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [SUBGOAL_THEN `(n:real^N) IN span (b UNION ns)` MP_TAC THENL
+     [MATCH_MP_TAC SPAN_SUPERSET THEN ASM SET_TAC[];
+      ASM_REWRITE_TAC[] THEN SPEC_TAC(`n:real^N`,`n:real^N`) THEN
+      REWRITE_TAC[GSYM SUBSET] THEN
+      MATCH_MP_TAC SPAN_SUBSET_SUBSPACE THEN REWRITE_TAC[SUBSPACE_SPAN] THEN
+      ASM_REWRITE_TAC[SET_RULE
+       `s UNION {a} SUBSET t <=> s SUBSET t /\ a IN t`] THEN
+      ASM_MESON_TAC[SPAN_INC; SUBSET_TRANS]];
+    MATCH_MP_TAC SPAN_INDUCT THEN
+    REWRITE_TAC[SET_RULE `(\y. orthogonal n y) = {y | orthogonal n y}`] THEN
+    REWRITE_TAC[SUBSPACE_ORTHOGONAL_TO_VECTOR] THEN ASM SET_TAC[]]);;
+
+let ORTHOGONAL_TO_SUBSPACE_EXISTS = prove
+ (`!s:real^N->bool. dim s < dimindex(:N)
+                    ==> ?x. ~(x = vec 0) /\ !y. y IN s ==> orthogonal x y`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `(:real^N)`]
+        ORTHOGONAL_TO_SUBSPACE_EXISTS_GEN) THEN
+  ANTS_TAC THENL [REWRITE_TAC[PSUBSET]; MESON_TAC[SPAN_SUPERSET]] THEN
+  REWRITE_TAC[SPAN_UNIV; SUBSET_UNIV] THEN
+  ASM_MESON_TAC[DIM_SPAN; DIM_UNIV; LT_REFL]);;
+
+let ORTHOGONAL_TO_VECTOR_EXISTS = prove
+ (`!x:real^N. 2 <= dimindex(:N) ==> ?y. ~(y = vec 0) /\ orthogonal x y`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `{x:real^N}` ORTHOGONAL_TO_SUBSPACE_EXISTS) THEN
+  SIMP_TAC[DIM_SING; IN_SING; LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN
+  ANTS_TAC THENL [ASM_ARITH_TAC; MESON_TAC[ORTHOGONAL_SYM]]);;
+
+let SPAN_NOT_UNIV_ORTHOGONAL = prove
+ (`!s. ~(span s = (:real^N))
+         ==> ?a. ~(a = vec 0) /\ !x. x IN span s ==> a dot x = &0`,
+  REWRITE_TAC[GSYM DIM_EQ_FULL; GSYM LE_ANTISYM; DIM_SUBSET_UNIV;
+              NOT_LE] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM orthogonal] THEN
+  MATCH_MP_TAC ORTHOGONAL_TO_SUBSPACE_EXISTS THEN ASM_REWRITE_TAC[DIM_SPAN]);;
+
+let SPAN_NOT_UNIV_SUBSET_HYPERPLANE = prove
+ (`!s. ~(span s = (:real^N))
+       ==> ?a. ~(a = vec 0) /\ span s SUBSET {x | a dot x = &0}`,
+  REWRITE_TAC[SUBSET; IN_ELIM_THM; SPAN_NOT_UNIV_ORTHOGONAL]);;
+
+let LOWDIM_SUBSET_HYPERPLANE = prove
+ (`!s. dim s < dimindex(:N)
+       ==> ?a:real^N. ~(a = vec 0) /\ span s SUBSET {x | a dot x = &0}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SPAN_NOT_UNIV_SUBSET_HYPERPLANE THEN
+  REWRITE_TAC[GSYM SUBSET_ANTISYM_EQ; SUBSET_UNIV] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP DIM_SUBSET) THEN
+  ASM_REWRITE_TAC[NOT_LE; DIM_SPAN; DIM_UNIV]);;
+
+let VECTOR_EQ_DOT_SPAN = prove
+ (`!b x y:real^N.
+        (!v. v IN b ==> v dot x = v dot y) /\ x IN span b /\ y IN span b
+        ==> x = y`,
+  ONCE_REWRITE_TAC[GSYM REAL_SUB_0; GSYM VECTOR_SUB_EQ] THEN
+  REWRITE_TAC[GSYM DOT_RSUB; GSYM ORTHOGONAL_REFL; GSYM orthogonal] THEN
+  MESON_TAC[ORTHOGONAL_TO_SPAN; SPAN_SUB; ORTHOGONAL_SYM]);;
+
+let ORTHONORMAL_BASIS_EXPAND = prove
+ (`!b x:real^N.
+        pairwise orthogonal b /\ (!v. v IN b ==> norm v = &1) /\ x IN span b
+   ==> vsum b (\v. (v dot x) % v) = x`,
+  REWRITE_TAC[NORM_EQ_1] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC VECTOR_EQ_DOT_SPAN THEN EXISTS_TAC `b:real^N->bool` THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP PAIRWISE_ORTHOGONAL_IMP_FINITE) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[pairwise; orthogonal]) THEN
+  ASM_SIMP_TAC[SPAN_VSUM; SPAN_MUL; DOT_RSUM; DOT_RMUL; SPAN_SUPERSET] THEN
+  X_GEN_TAC `v:real^N` THEN DISCH_TAC THEN
+  TRANS_TAC EQ_TRANS `sum b (\w:real^N. if w = v then v dot x else &0)` THEN
+  CONJ_TAC THENL [ALL_TAC; ASM_SIMP_TAC[SUM_DELTA]] THEN
+  MATCH_MP_TAC SUM_EQ THEN ASM_REWRITE_TAC[] THEN
+  X_GEN_TAC `w:real^N` THEN DISCH_TAC THEN
+  COND_CASES_TAC THEN ASM_SIMP_TAC[REAL_MUL_RID; REAL_MUL_RZERO]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Decomposing a vector into parts in orthogonal subspaces.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let ORTHOGONAL_SUBSPACE_DECOMP_UNIQUE = prove
+ (`!s t x y x' y':real^N.
+        (!a b. a IN s /\ b IN t ==> orthogonal a b) /\
+        x IN span s /\ x' IN span s /\ y IN span t /\ y' IN span t /\
+        x + y = x' + y'
+        ==> x = x' /\ y = y'`,
+  REWRITE_TAC[VECTOR_ARITH `x + y:real^N = x' + y' <=> x - x' = y' - y`] THEN
+  ONCE_REWRITE_TAC[GSYM ORTHOGONAL_TO_SPANS_EQ] THEN
+  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[VECTOR_ARITH
+   `x:real^N = x' /\ y:real^N = y' <=> x - x' = vec 0 /\ y' - y = vec 0`] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[GSYM ORTHOGONAL_REFL] THEN
+  FIRST_X_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [SYM th]) THEN
+  ASM_MESON_TAC[ORTHOGONAL_CLAUSES; ORTHOGONAL_SYM]);;
+
+let ORTHOGONAL_SUBSPACE_DECOMP_EXISTS = prove
+ (`!s x:real^N. ?y z. y IN span s /\ (!w. w IN span s ==> orthogonal z w) /\
+                      x = y + z`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `span s:real^N->bool` ORTHOGONAL_BASIS_SUBSPACE) THEN
+  REWRITE_TAC[SUBSPACE_SPAN; LEFT_IMP_EXISTS_THM] THEN
+  X_GEN_TAC `t:real^N->bool` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  EXISTS_TAC `vsum t (\b:real^N. (b dot x) / (b dot b) % b)` THEN
+  EXISTS_TAC `x - vsum t (\b:real^N. (b dot x) / (b dot b) % b)` THEN
+  REPEAT CONJ_TAC THENL
+   [MATCH_MP_TAC SPAN_VSUM THEN
+    ASM_SIMP_TAC[INDEPENDENT_IMP_FINITE; SPAN_CLAUSES];
+    REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[ORTHOGONAL_SYM] THEN
+    MATCH_MP_TAC GRAM_SCHMIDT_STEP THEN ASM_SIMP_TAC[];
+    VECTOR_ARITH_TAC]);;
+
+let ORTHOGONAL_SUBSPACE_DECOMP = prove
+ (`!s x. ?!(y,z). y IN span s /\
+                  z IN {z:real^N | !x. x IN span s ==> orthogonal z x} /\
+                  x = y + z`,
+  REWRITE_TAC[EXISTS_UNIQUE_DEF; IN_ELIM_THM] THEN
+  REWRITE_TAC[EXISTS_PAIRED_THM; FORALL_PAIRED_THM] THEN
+  REWRITE_TAC[FORALL_PAIR_THM; ORTHOGONAL_SUBSPACE_DECOMP_EXISTS] THEN
+  REPEAT STRIP_TAC THEN REWRITE_TAC[PAIR_EQ] THEN
+  MATCH_MP_TAC ORTHOGONAL_SUBSPACE_DECOMP_UNIQUE THEN
+  MAP_EVERY EXISTS_TAC
+   [`s:real^N->bool`; `{z:real^N | !x. x IN span s ==> orthogonal z x}`] THEN
+  ASM_SIMP_TAC[SPAN_CLAUSES; IN_ELIM_THM] THEN
+  ASM_MESON_TAC[SPAN_CLAUSES; ORTHOGONAL_SYM]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Existence of isometry between subspaces of same dimension.                *)
+(* ------------------------------------------------------------------------- *)
+
+let ISOMETRY_SUBSET_SUBSPACE = prove
+ (`!s:real^M->bool t:real^N->bool.
+        subspace s /\ subspace t /\ dim s <= dim t
+        ==> ?f. linear f /\ IMAGE f s SUBSET t /\
+                (!x. x IN s ==> norm(f x) = norm(x))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `t:real^N->bool` ORTHONORMAL_BASIS_SUBSPACE) THEN
+  MP_TAC(ISPEC `s:real^M->bool` ORTHONORMAL_BASIS_SUBSPACE) THEN
+  ASM_REWRITE_TAC[HAS_SIZE] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^M->bool` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `c:real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`b:real^M->bool`; `c:real^N->bool`] CARD_LE_INJ) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM; INJECTIVE_ON_ALT] THEN
+  X_GEN_TAC `fb:real^M->real^N` THEN STRIP_TAC THEN
+  MP_TAC(ISPECL [`fb:real^M->real^N`; `b:real^M->bool`]
+    LINEAR_INDEPENDENT_EXTEND) THEN
+  ASM_REWRITE_TAC[IMP_IMP; LEFT_AND_EXISTS_THM; INJECTIVE_ON_ALT] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^M->real^N` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
+   [REWRITE_TAC[SYM(ASSUME `span b:real^M->bool = s`)] THEN
+    ASM_SIMP_TAC[GSYM SPAN_LINEAR_IMAGE] THEN
+    REWRITE_TAC[SYM(ASSUME `span c:real^N->bool = t`)] THEN
+    MATCH_MP_TAC SPAN_MONO THEN ASM SET_TAC[];
+    UNDISCH_THEN `span b:real^M->bool = s` (SUBST1_TAC o SYM) THEN
+    ASM_SIMP_TAC[SPAN_FINITE] THEN
+    REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`z:real^M`; `u:real^M->real`] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_SIMP_TAC[LINEAR_VSUM] THEN
+    REWRITE_TAC[o_DEF; NORM_EQ_SQUARE; NORM_POS_LE; GSYM NORM_POW_2] THEN
+    ASM_SIMP_TAC[LINEAR_CMUL] THEN
+    W(MP_TAC o PART_MATCH (lhand o rand)
+      NORM_VSUM_PYTHAGOREAN o rand o snd) THEN
+    W(MP_TAC o PART_MATCH (lhand o rand)
+      NORM_VSUM_PYTHAGOREAN o lhand o rand o snd) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[pairwise]) THEN
+    ASM_SIMP_TAC[pairwise; ORTHOGONAL_CLAUSES] THEN ANTS_TAC THENL
+     [REPEAT STRIP_TAC THEN REWRITE_TAC[ORTHOGONAL_MUL] THEN ASM SET_TAC[];
+      REPEAT(DISCH_THEN SUBST1_TAC) THEN ASM_SIMP_TAC[NORM_MUL] THEN
+      MATCH_MP_TAC SUM_EQ THEN ASM SET_TAC[]]]);;
+
+let ISOMETRIES_SUBSPACES = prove
+ (`!s:real^M->bool t:real^N->bool.
+        subspace s /\ subspace t /\ dim s = dim t
+        ==> ?f g. linear f /\ linear g /\
+                  IMAGE f s = t /\ IMAGE g t = s /\
+                  (!x. x IN s ==> norm(f x) = norm x) /\
+                  (!y. y IN t ==> norm(g y) = norm y) /\
+                  (!x. x IN s ==> g(f x) = x) /\
+                  (!y. y IN t ==> f(g y) = y)`,
+  REPEAT STRIP_TAC THEN ABBREV_TAC `n = dim(t:real^N->bool)` THEN
+  MP_TAC(ISPEC `t:real^N->bool` ORTHONORMAL_BASIS_SUBSPACE) THEN
+  MP_TAC(ISPEC `s:real^M->bool` ORTHONORMAL_BASIS_SUBSPACE) THEN
+  ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^M->bool` STRIP_ASSUME_TAC) THEN
+  DISCH_THEN(X_CHOOSE_THEN `c:real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`b:real^M->bool`; `c:real^N->bool`] CARD_EQ_BIJECTIONS) THEN
+  RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN
+  ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`fb:real^M->real^N`; `gb:real^N->real^M`] THEN
+  STRIP_TAC THEN
+  MP_TAC(ISPECL [`gb:real^N->real^M`; `c:real^N->bool`]
+    LINEAR_INDEPENDENT_EXTEND) THEN
+  MP_TAC(ISPECL [`fb:real^M->real^N`; `b:real^M->bool`]
+    LINEAR_INDEPENDENT_EXTEND) THEN
+  ASM_REWRITE_TAC[IMP_IMP; LEFT_AND_EXISTS_THM] THEN
+  REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^M->real^N` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `g:real^N->real^M` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[SYM(ASSUME `span b:real^M->bool = s`)] THEN
+    ASM_SIMP_TAC[GSYM SPAN_LINEAR_IMAGE] THEN
+    REWRITE_TAC[SYM(ASSUME `span c:real^N->bool = t`)] THEN
+    AP_TERM_TAC THEN ASM SET_TAC[];
+    REWRITE_TAC[SYM(ASSUME `span c:real^N->bool = t`)] THEN
+    ASM_SIMP_TAC[GSYM SPAN_LINEAR_IMAGE] THEN
+    REWRITE_TAC[SYM(ASSUME `span b:real^M->bool = s`)] THEN
+    AP_TERM_TAC THEN ASM SET_TAC[];
+    UNDISCH_THEN `span b:real^M->bool = s` (SUBST1_TAC o SYM) THEN
+    ASM_SIMP_TAC[SPAN_FINITE] THEN
+    REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`z:real^M`; `u:real^M->real`] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_SIMP_TAC[LINEAR_VSUM] THEN
+    REWRITE_TAC[o_DEF; NORM_EQ_SQUARE; NORM_POS_LE; GSYM NORM_POW_2] THEN
+    ASM_SIMP_TAC[LINEAR_CMUL] THEN
+    W(MP_TAC o PART_MATCH (lhand o rand)
+      NORM_VSUM_PYTHAGOREAN o rand o snd) THEN
+    W(MP_TAC o PART_MATCH (lhand o rand)
+      NORM_VSUM_PYTHAGOREAN o lhand o rand o snd) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[pairwise]) THEN
+    ASM_SIMP_TAC[pairwise; ORTHOGONAL_CLAUSES] THEN ANTS_TAC THENL
+     [REPEAT STRIP_TAC THEN REWRITE_TAC[ORTHOGONAL_MUL] THEN ASM SET_TAC[];
+      REPEAT(DISCH_THEN SUBST1_TAC) THEN
+      ASM_SIMP_TAC[NORM_MUL]];
+    UNDISCH_THEN `span c:real^N->bool = t` (SUBST1_TAC o SYM) THEN
+    ASM_SIMP_TAC[SPAN_FINITE] THEN
+    REWRITE_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN
+    MAP_EVERY X_GEN_TAC [`z:real^N`; `u:real^N->real`] THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_SIMP_TAC[LINEAR_VSUM] THEN
+    REWRITE_TAC[o_DEF; NORM_EQ_SQUARE; NORM_POS_LE; GSYM NORM_POW_2] THEN
+    ASM_SIMP_TAC[LINEAR_CMUL] THEN
+    W(MP_TAC o PART_MATCH (lhand o rand)
+      NORM_VSUM_PYTHAGOREAN o rand o snd) THEN
+    W(MP_TAC o PART_MATCH (lhand o rand)
+      NORM_VSUM_PYTHAGOREAN o lhand o rand o snd) THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[pairwise]) THEN
+    ASM_SIMP_TAC[pairwise; ORTHOGONAL_CLAUSES] THEN ANTS_TAC THENL
+     [REPEAT STRIP_TAC THEN REWRITE_TAC[ORTHOGONAL_MUL] THEN ASM SET_TAC[];
+      REPEAT(DISCH_THEN SUBST1_TAC) THEN
+      ASM_SIMP_TAC[NORM_MUL]];
+    REWRITE_TAC[SYM(ASSUME `span b:real^M->bool = s`)] THEN
+    MATCH_MP_TAC SPAN_INDUCT THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[SUBSET; IN]; ALL_TAC] THEN
+    REWRITE_TAC[subspace; IN] THEN ASM_MESON_TAC[linear; LINEAR_0];
+    REWRITE_TAC[SYM(ASSUME `span c:real^N->bool = t`)] THEN
+    MATCH_MP_TAC SPAN_INDUCT THEN
+    CONJ_TAC THENL [ASM_MESON_TAC[SUBSET; IN]; ALL_TAC] THEN
+    REWRITE_TAC[subspace; IN] THEN ASM_MESON_TAC[linear; LINEAR_0]]);;
+
+let ISOMETRY_SUBSPACES = prove
+ (`!s:real^M->bool t:real^N->bool.
+        subspace s /\ subspace t /\ dim s = dim t
+        ==> ?f:real^M->real^N. linear f /\ IMAGE f s = t /\
+                               (!x. x IN s ==> norm(f x) = norm(x))`,
+  REPEAT GEN_TAC THEN
+  DISCH_THEN(MP_TAC o MATCH_MP ISOMETRIES_SUBSPACES) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN MESON_TAC[]);;
+
+let ISOMETRY_UNIV_SUBSPACE = prove
+ (`!s. subspace s /\ dimindex(:M) = dim s
+       ==> ?f:real^M->real^N.
+                linear f /\ IMAGE f (:real^M) = s /\
+                (!x. norm(f x) = norm(x))`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`(:real^M)`; `s:real^N->bool`] ISOMETRY_SUBSPACES) THEN
+  ASM_REWRITE_TAC[SUBSPACE_UNIV; IN_UNIV; DIM_UNIV]);;
+
+let ISOMETRY_UNIV_SUPERSET_SUBSPACE = prove
+ (`!s. subspace s /\ dim s <= dimindex(:M) /\ dimindex(:M) <= dimindex(:N)
+       ==> ?f:real^M->real^N.
+                linear f /\ s SUBSET (IMAGE f (:real^M)) /\
+                (!x. norm(f x) = norm(x))`,
+  GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP LOWDIM_EXPAND_DIMENSION) THEN
+  DISCH_THEN(X_CHOOSE_THEN `t:real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`(:real^M)`; `span t:real^N->bool`] ISOMETRY_SUBSPACES) THEN
+  ASM_REWRITE_TAC[SUBSPACE_SPAN; SUBSPACE_UNIV; DIM_UNIV; DIM_SPAN] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN SIMP_TAC[IN_UNIV] THEN
+  ASM_MESON_TAC[SUBSET; SPAN_INC]);;
+
+let ISOMETRY_UNIV_UNIV = prove
+ (`dimindex(:M) <= dimindex(:N)
+   ==> ?f:real^M->real^N. linear f /\ (!x. norm(f x) = norm(x))`,
+  DISCH_TAC THEN
+  MP_TAC(ISPEC `{vec 0:real^N}`ISOMETRY_UNIV_SUPERSET_SUBSPACE) THEN
+  ASM_REWRITE_TAC[SUBSPACE_TRIVIAL] THEN
+  ANTS_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
+  MATCH_MP_TAC(ARITH_RULE `x = 0 /\ 1 <= y ==> x <= y`) THEN
+  ASM_REWRITE_TAC[DIM_EQ_0; DIMINDEX_GE_1] THEN SET_TAC[]);;
+
+let SUBSPACE_ISOMORPHISM = prove
+ (`!s t. subspace s /\ subspace t /\ dim(s) = dim(t)
+         ==> ?f:real^M->real^N.
+                linear f /\ (IMAGE f s = t) /\
+                (!x y. x IN s /\ y IN s /\ f x = f y ==> (x = y))`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(MP_TAC o MATCH_MP ISOMETRY_SUBSPACES) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN
+  ASM_SIMP_TAC[LINEAR_INJECTIVE_0_SUBSPACE] THEN MESON_TAC[NORM_EQ_0]);;
+
+let ISOMORPHISMS_UNIV_UNIV = prove
+ (`dimindex(:M) = dimindex(:N)
+   ==> ?f:real^M->real^N g.
+            linear f /\ linear g /\
+            (!x. norm(f x) = norm x) /\ (!y. norm(g y) = norm y) /\
+            (!x. g(f x) = x) /\ (!y. f(g y) = y)`,
+  REPEAT STRIP_TAC THEN
+  EXISTS_TAC `(\x. lambda i. x$i):real^M->real^N` THEN
+  EXISTS_TAC `(\x. lambda i. x$i):real^N->real^M` THEN
+  SIMP_TAC[vector_norm; dot; LAMBDA_BETA] THEN
+  SIMP_TAC[linear; CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+           LAMBDA_BETA] THEN
+  FIRST_ASSUM SUBST1_TAC THEN SIMP_TAC[LAMBDA_BETA] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN SIMP_TAC[LAMBDA_BETA]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Properties of special hyperplanes.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let SUBSPACE_HYPERPLANE = prove
+ (`!a. subspace {x:real^N | a dot x = &0}`,
+  SIMP_TAC[subspace; DOT_RADD; DOT_RMUL; IN_ELIM_THM; REAL_ADD_LID;
+           REAL_MUL_RZERO; DOT_RZERO]);;
+
+let SUBSPACE_SPECIAL_HYPERPLANE = prove
+ (`!k. subspace {x:real^N | x$k = &0}`,
+  SIMP_TAC[subspace; IN_ELIM_THM; VEC_COMPONENT;
+           VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT] THEN REAL_ARITH_TAC);;
+
+let SPECIAL_HYPERPLANE_SPAN = prove
+ (`!k. 1 <= k /\ k <= dimindex(:N)
+       ==> {x:real^N | x$k = &0} =
+           span(IMAGE basis ((1..dimindex(:N)) DELETE k))`,
+  REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC SPAN_SUBSPACE THEN
+  ASM_SIMP_TAC[SUBSPACE_SPECIAL_HYPERPLANE] THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+    ASM_SIMP_TAC[BASIS_COMPONENT; IN_DELETE];
+    REWRITE_TAC[SUBSET; IN_ELIM_THM] THEN
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM BASIS_EXPANSION] THEN
+    SIMP_TAC[SPAN_FINITE; FINITE_IMAGE; FINITE_DELETE; FINITE_NUMSEG] THEN
+    REWRITE_TAC[IN_ELIM_THM] THEN
+    EXISTS_TAC `\v:real^N. x dot v` THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) VSUM_IMAGE o lhs o snd) THEN
+    ANTS_TAC THENL
+     [REWRITE_TAC[FINITE_DELETE; FINITE_NUMSEG; IN_NUMSEG; IN_DELETE] THEN
+      MESON_TAC[BASIS_INJ];
+      DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[o_DEF] THEN
+      ASM_SIMP_TAC[VSUM_DELETE; FINITE_NUMSEG; IN_NUMSEG; DOT_BASIS] THEN
+      REWRITE_TAC[VECTOR_MUL_LZERO; VECTOR_SUB_RZERO]]]);;
+
+let DIM_SPECIAL_HYPERPLANE = prove
+ (`!k. 1 <= k /\ k <= dimindex(:N)
+       ==> dim {x:real^N | x$k = &0} = dimindex(:N) - 1`,
+  SIMP_TAC[SPECIAL_HYPERPLANE_SPAN] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC DIM_UNIQUE THEN
+  EXISTS_TAC `IMAGE (basis:num->real^N) ((1..dimindex(:N)) DELETE k)` THEN
+  REWRITE_TAC[SUBSET_REFL; SPAN_INC] THEN CONJ_TAC THENL
+   [MATCH_MP_TAC INDEPENDENT_MONO THEN
+    EXISTS_TAC `{basis i:real^N | 1 <= i /\ i <= dimindex(:N)}` THEN
+    REWRITE_TAC[INDEPENDENT_STDBASIS; SUBSET; FORALL_IN_IMAGE] THEN
+    REWRITE_TAC[IN_DELETE; IN_NUMSEG; IN_ELIM_THM] THEN MESON_TAC[];
+    MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN CONJ_TAC THENL
+     [REWRITE_TAC[FINITE_DELETE; FINITE_NUMSEG; IN_NUMSEG; IN_DELETE] THEN
+      MESON_TAC[BASIS_INJ];
+      ASM_SIMP_TAC[HAS_SIZE; FINITE_DELETE; FINITE_NUMSEG; CARD_DELETE;
+                   FINITE_IMAGE; IN_NUMSEG; CARD_NUMSEG_1]]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More theorems about dimensions of different subspaces.                    *)
+(* ------------------------------------------------------------------------- *)
+
+let DIM_IMAGE_KERNEL_GEN = prove
+ (`!f:real^M->real^N s.
+        linear f /\ subspace s
+        ==> dim(IMAGE f s) + dim {x | x IN s /\  f x = vec 0} = dim(s)`,
+  REPEAT STRIP_TAC THEN MP_TAC
+   (ISPEC `{x | x IN s /\ (f:real^M->real^N) x = vec 0}` BASIS_EXISTS) THEN
+  DISCH_THEN(X_CHOOSE_THEN `v:real^M->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`v:real^M->bool`; `s:real^M->bool`]
+    MAXIMAL_INDEPENDENT_SUBSET_EXTEND) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `w:real^M->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `span(w:real^M->bool) = s`
+   (fun th -> GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [SYM th] THEN
+              ASSUME_TAC th)
+  THENL [ASM_SIMP_TAC[SPAN_SUBSPACE]; ALL_TAC] THEN
+  SUBGOAL_THEN `subspace {x | x IN s /\ (f:real^M->real^N) x = vec 0}`
+  ASSUME_TAC THENL
+   [REWRITE_TAC[SET_RULE `{x | x IN s /\ P x} = s INTER {x | P x}`] THEN
+    ASM_SIMP_TAC[SUBSPACE_INTER; SUBSPACE_KERNEL];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `{x | x IN s /\ (f:real^M->real^N) x = vec 0} = span v`
+  ASSUME_TAC THENL
+   [ASM_MESON_TAC[SUBSET_ANTISYM; SPAN_SUBSET_SUBSPACE; SUBSPACE_KERNEL];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[DIM_SPAN; DIM_EQ_CARD] THEN
+  SUBGOAL_THEN
+   `!x. x IN span(w DIFF v) /\ (f:real^M->real^N) x = vec 0 ==> x = vec 0`
+  (LABEL_TAC "*") THENL
+   [MATCH_MP_TAC(SET_RULE
+     `!t. s SUBSET t /\ (!x. x IN s /\ x IN t /\ P x ==> Q x)
+          ==> (!x. x IN s /\ P x ==> Q x)`) THEN
+    EXISTS_TAC `s:real^M->bool` THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[SPAN_MONO; SUBSET_DIFF]; ALL_TAC] THEN
+    ASM_SIMP_TAC[SPAN_FINITE; IN_ELIM_THM; IMP_CONJ; FINITE_DIFF;
+                 INDEPENDENT_IMP_FINITE; LEFT_IMP_EXISTS_THM] THEN
+    GEN_TAC THEN X_GEN_TAC `u:real^M->real` THEN
+    DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[IMP_IMP] THEN
+    ONCE_REWRITE_TAC[SET_RULE
+     `y IN s /\ f y = a <=> y IN {x | x IN s /\ f x = a}`] THEN
+    ASM_REWRITE_TAC[] THEN
+    ASM_SIMP_TAC[SPAN_FINITE; INDEPENDENT_IMP_FINITE; IN_ELIM_THM] THEN
+    DISCH_THEN(X_CHOOSE_TAC `t:real^M->real`) THEN
+    MP_TAC(ISPEC `w:real^M->bool` INDEPENDENT_EXPLICIT) THEN
+    ASM_REWRITE_TAC[] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+    DISCH_THEN(MP_TAC o SPEC
+     `(\x. if x IN w DIFF v then --u x else t x):real^M->real`) THEN
+    ASM_REWRITE_TAC[COND_RAND] THEN ONCE_REWRITE_TAC[COND_RATOR] THEN
+    ASM_SIMP_TAC[VSUM_CASES; INDEPENDENT_IMP_FINITE] THEN
+    REWRITE_TAC[SET_RULE `{x | x IN w /\ x IN (w DIFF v)} = w DIFF v`] THEN
+    SIMP_TAC[ASSUME `(v:real^M->bool) SUBSET w`; SET_RULE
+     `v SUBSET w ==> {x | x IN w /\ ~(x IN (w DIFF v))} = v`] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_LNEG; VSUM_NEG; VECTOR_ADD_LINV] THEN
+    DISCH_THEN(fun th -> MATCH_MP_TAC VSUM_EQ_0 THEN MP_TAC th) THEN
+    REWRITE_TAC[REAL_NEG_EQ_0; VECTOR_MUL_EQ_0; IN_DIFF] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `!x y. x IN (w DIFF v) /\ y IN (w DIFF v) /\
+                      (f:real^M->real^N) x = f y ==> x = y`
+  ASSUME_TAC THENL
+   [REMOVE_THEN "*" MP_TAC THEN
+    ASM_SIMP_TAC[GSYM LINEAR_INJECTIVE_0_SUBSPACE; SUBSPACE_SPAN] THEN
+    MP_TAC(ISPEC `w DIFF v:real^M->bool` SPAN_INC) THEN SET_TAC[];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `IMAGE (f:real^M->real^N) s = span(IMAGE f (w DIFF v))`
+  SUBST1_TAC THENL
+   [MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+     [ALL_TAC;
+      ASM_MESON_TAC[SUBSPACE_LINEAR_IMAGE; SPAN_MONO; IMAGE_SUBSET;
+                    SUBSET_TRANS; SUBSET_DIFF; SPAN_EQ_SELF]] THEN
+    SIMP_TAC[SUBSET; FORALL_IN_IMAGE] THEN X_GEN_TAC `x:real^M` THEN
+    DISCH_TAC THEN UNDISCH_TAC `span w:real^M->bool = s` THEN
+    REWRITE_TAC[EXTENSION] THEN DISCH_THEN(MP_TAC o SPEC `x:real^M`) THEN
+    ASM_REWRITE_TAC[] THEN
+    REMOVE_THEN "*" (MP_TAC o SPEC `x:real^M`) THEN
+    (CONV_TAC o GEN_SIMPLIFY_CONV TOP_DEPTH_SQCONV (basic_ss []) 4)
+     [IN_UNIV; SPAN_FINITE; INDEPENDENT_IMP_FINITE; IN_ELIM_THM;
+      FINITE_IMAGE; FINITE_DIFF; ASSUME `independent(w:real^M->bool)`] THEN
+    REWRITE_TAC[IMP_CONJ; LEFT_IMP_EXISTS_THM] THEN DISCH_TAC THEN
+    X_GEN_TAC `u:real^M->real` THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
+    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [INJECTIVE_ON_LEFT_INVERSE]) THEN
+    DISCH_THEN(X_CHOOSE_TAC `g:real^N->real^M`) THEN
+    EXISTS_TAC `(u:real^M->real) o (g:real^N->real^M)` THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) VSUM_IMAGE o lhand o snd) THEN
+    ASM_REWRITE_TAC[] THEN
+    ASM_SIMP_TAC[FINITE_DIFF; INDEPENDENT_IMP_FINITE; LINEAR_VSUM] THEN
+    DISCH_THEN SUBST1_TAC THEN ASM_REWRITE_TAC[o_DEF] THEN
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_EQ_SUPERSET THEN
+    SIMP_TAC[SUBSET_DIFF; FINITE_DIFF; INDEPENDENT_IMP_FINITE;
+             LINEAR_CMUL; IN_DIFF; TAUT `a /\ ~(a /\ ~b) <=> a /\ b`;
+             ASSUME `independent(w:real^M->bool)`;
+             ASSUME `linear(f:real^M->real^N)`] THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0] THEN ASM SET_TAC[];
+    SUBGOAL_THEN `independent(IMAGE (f:real^M->real^N) (w DIFF v))`
+    ASSUME_TAC THENL
+     [MATCH_MP_TAC INDEPENDENT_INJECTIVE_IMAGE_GEN THEN
+      ASM_SIMP_TAC[LINEAR_INJECTIVE_0_SUBSPACE; SUBSPACE_SPAN] THEN
+      ASM_MESON_TAC[INDEPENDENT_MONO; SUBSET_DIFF];
+      ASM_SIMP_TAC[DIM_SPAN; DIM_EQ_CARD] THEN
+      W(MP_TAC o PART_MATCH (lhs o rand) CARD_IMAGE_INJ o
+        lhand o lhand o snd) THEN
+      ASM_REWRITE_TAC[] THEN
+      ASM_SIMP_TAC[FINITE_DIFF; CARD_DIFF; INDEPENDENT_IMP_FINITE] THEN
+      DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC SUB_ADD THEN
+      ASM_MESON_TAC[CARD_SUBSET; INDEPENDENT_IMP_FINITE]]]);;
+
+let DIM_IMAGE_KERNEL = prove
+ (`!f:real^M->real^N.
+        linear f
+        ==> dim(IMAGE f (:real^M)) + dim {x | f x = vec 0} = dimindex(:M)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`f:real^M->real^N`; `(:real^M)`] DIM_IMAGE_KERNEL_GEN) THEN
+  ASM_REWRITE_TAC[SUBSPACE_UNIV; IN_UNIV; DIM_UNIV]);;
+
+let DIM_SUMS_INTER = prove
+ (`!s t:real^N->bool.
+    subspace s /\ subspace t
+    ==> dim {x + y | x IN s /\ y IN t} + dim(s INTER t) = dim(s) + dim(t)`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `s INTER t:real^N->bool` BASIS_EXISTS) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`b:real^N->bool`; `s:real^N->bool`]
+    MAXIMAL_INDEPENDENT_SUBSET_EXTEND) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `c:real^N->bool` STRIP_ASSUME_TAC) THEN
+  MP_TAC(ISPECL [`b:real^N->bool`; `t:real^N->bool`]
+    MAXIMAL_INDEPENDENT_SUBSET_EXTEND) THEN
+  ANTS_TAC THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  DISCH_THEN(X_CHOOSE_THEN `d:real^N->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN `(c:real^N->bool) INTER d = b` ASSUME_TAC THENL
+   [MATCH_MP_TAC SUBSET_ANTISYM THEN ASM_REWRITE_TAC[SUBSET_INTER] THEN
+    REWRITE_TAC[SUBSET; IN_INTER] THEN X_GEN_TAC `x:real^N` THEN
+    STRIP_TAC THEN MP_TAC(ISPEC `c:real^N->bool` independent) THEN
+    ASM_REWRITE_TAC[dependent; NOT_EXISTS_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `x:real^N`) THEN ASM_REWRITE_TAC[] THEN
+    ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN STRIP_TAC THEN
+    REWRITE_TAC[] THEN
+    SUBGOAL_THEN `(x:real^N) IN span b` MP_TAC THENL
+     [ASM_MESON_TAC[SUBSET; IN_INTER; SPAN_INC];
+      MP_TAC(ISPECL [`b:real^N->bool`; `c DELETE (x:real^N)`] SPAN_MONO) THEN
+      ASM SET_TAC[]];
+    ALL_TAC] THEN
+  SUBGOAL_THEN
+   `dim (s INTER t:real^N->bool) = CARD(b:real^N->bool) /\
+    dim s = CARD c /\ dim t = CARD d /\
+    dim {x + y:real^N | x IN s /\ y IN t} = CARD(c UNION d:real^N->bool)`
+  (REPEAT_TCL CONJUNCTS_THEN SUBST1_TAC) THENL
+   [ALL_TAC;
+    ASM_SIMP_TAC[CARD_UNION_GEN; INDEPENDENT_IMP_FINITE] THEN
+    MATCH_MP_TAC(ARITH_RULE `b:num <= c ==> (c + d) - b + b = c + d`) THEN
+    ASM_SIMP_TAC[CARD_SUBSET; INDEPENDENT_IMP_FINITE]] THEN
+  REPEAT CONJ_TAC THEN MATCH_MP_TAC DIM_UNIQUE THENL
+   [EXISTS_TAC `b:real^N->bool`;
+    EXISTS_TAC `c:real^N->bool`;
+    EXISTS_TAC `d:real^N->bool`;
+    EXISTS_TAC `c UNION d:real^N->bool`] THEN
+  ASM_SIMP_TAC[HAS_SIZE; INDEPENDENT_IMP_FINITE; FINITE_UNION] THEN
+  REWRITE_TAC[UNION_SUBSET; GSYM CONJ_ASSOC] THEN
+  REWRITE_TAC[SUBSET; IN_ELIM_THM; FORALL_IN_GSPEC] THEN REPEAT CONJ_TAC THENL
+   [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC [`x:real^N`; `vec 0:real^N`] THEN
+    ASM_SIMP_TAC[SUBSPACE_0; VECTOR_ADD_RID] THEN ASM SET_TAC[];
+    X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+    MAP_EVERY EXISTS_TAC [`vec 0:real^N`; `x:real^N`] THEN
+    ASM_SIMP_TAC[SUBSPACE_0; VECTOR_ADD_LID] THEN ASM SET_TAC[];
+    MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+    MATCH_MP_TAC SPAN_ADD THEN CONJ_TAC THENL
+     [MP_TAC(ISPECL[`c:real^N->bool`; `c UNION d:real^N->bool`] SPAN_MONO);
+      MP_TAC(ISPECL[`d:real^N->bool`; `c UNION d:real^N->bool`] SPAN_MONO)] THEN
+    REWRITE_TAC[SUBSET_UNION] THEN REWRITE_TAC[SUBSET] THEN
+    DISCH_THEN MATCH_MP_TAC THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[INDEPENDENT_EXPLICIT; FINITE_UNION; INDEPENDENT_IMP_FINITE] THEN
+  X_GEN_TAC `a:real^N->real` THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+   [SET_RULE `s UNION t = s UNION (t DIFF s)`] THEN
+  ASM_SIMP_TAC[VSUM_UNION; SET_RULE `DISJOINT c (d DIFF c)`;
+               INDEPENDENT_IMP_FINITE; FINITE_DIFF; FINITE_UNION] THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN
+   `(vsum (d DIFF c) (\v:real^N. a v % v)) IN span b`
+  MP_TAC THENL
+   [FIRST_ASSUM(MATCH_MP_TAC o GEN_REWRITE_RULE I [SUBSET]) THEN
+    REWRITE_TAC[IN_INTER] THEN CONJ_TAC THENL
+     [FIRST_X_ASSUM(SUBST1_TAC o MATCH_MP (VECTOR_ARITH
+       `a + b = vec 0 ==> b = --a`)) THEN
+      MATCH_MP_TAC SUBSPACE_NEG THEN ASM_REWRITE_TAC[];
+      ALL_TAC] THEN
+    MATCH_MP_TAC SUBSPACE_VSUM THEN
+    ASM_SIMP_TAC[FINITE_DIFF; INDEPENDENT_IMP_FINITE] THEN
+    REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSPACE_MUL THEN
+    ASM_REWRITE_TAC[] THEN ASM SET_TAC[];
+    ALL_TAC] THEN
+  ASM_SIMP_TAC[SPAN_FINITE; INDEPENDENT_IMP_FINITE; IN_ELIM_THM] THEN
+  DISCH_THEN(X_CHOOSE_TAC `e:real^N->real`) THEN
+  MP_TAC(ISPEC `c:real^N->bool` INDEPENDENT_EXPLICIT) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
+   (MP_TAC o SPEC `(\x. if x IN b then a x + e x else a x):real^N->real`)) THEN
+  REWRITE_TAC[] THEN ONCE_REWRITE_TAC[COND_RAND] THEN
+  ONCE_REWRITE_TAC[COND_RATOR] THEN ASM_SIMP_TAC[VSUM_CASES] THEN
+  REWRITE_TAC[VECTOR_ADD_RDISTRIB; GSYM DIFF] THEN
+  ASM_SIMP_TAC[SET_RULE `b SUBSET c ==> {x | x IN c /\ x IN b} = b`] THEN
+  ASM_SIMP_TAC[VSUM_ADD; INDEPENDENT_IMP_FINITE] THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `(a + b) + c:real^N = (a + c) + b`] THEN
+  ASM_SIMP_TAC[GSYM VSUM_UNION; FINITE_DIFF; INDEPENDENT_IMP_FINITE;
+               SET_RULE `DISJOINT b (c DIFF b)`] THEN
+  ASM_SIMP_TAC[SET_RULE `b SUBSET c ==> b UNION (c DIFF b) = c`] THEN
+  DISCH_TAC THEN
+  SUBGOAL_THEN `!v:real^N. v IN (c DIFF b) ==> a v = &0` ASSUME_TAC THENL
+   [ASM SET_TAC[]; ALL_TAC] THEN
+  MP_TAC(ISPEC `d:real^N->bool` INDEPENDENT_EXPLICIT) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
+   (MP_TAC o SPEC `a:real^N->real`)) THEN
+  SUBGOAL_THEN `d:real^N->bool = b UNION (d DIFF c)`
+   (fun th -> GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o ONCE_DEPTH_CONV) [th])
+  THENL [ASM SET_TAC[]; ALL_TAC] THEN
+  ANTS_TAC THENL [ALL_TAC; ASM SET_TAC[]] THEN
+  ASM_SIMP_TAC[VSUM_UNION; FINITE_DIFF; INDEPENDENT_IMP_FINITE;
+               SET_RULE `c INTER d = b ==> DISJOINT b (d DIFF c)`] THEN
+  SUBGOAL_THEN `vsum b (\x:real^N. a x % x) = vsum c (\x. a x % x)`
+   (fun th -> ASM_REWRITE_TAC[th]) THEN
+  CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_SUPERSET THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0] THEN ASM_MESON_TAC[]);;
+
+let DIM_KERNEL_COMPOSE = prove
+ (`!f:real^M->real^N g:real^N->real^P.
+        linear f /\ linear g
+        ==> dim {x | (g o f) x = vec 0} <=
+                dim {x | f(x) = vec 0} +
+                dim {y | g(y) = vec 0}`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPEC `{x | (f:real^M->real^N) x = vec 0}` BASIS_EXISTS_FINITE) THEN
+  DISCH_THEN(X_CHOOSE_THEN `b:real^M->bool` STRIP_ASSUME_TAC) THEN
+  SUBGOAL_THEN
+   `?c. FINITE c /\
+        IMAGE f c SUBSET {y | g(y):real^P = vec 0} /\
+        independent (IMAGE (f:real^M->real^N) c) /\
+        IMAGE f (:real^M) INTER {y | g(y) = vec 0} SUBSET span(IMAGE f c) /\
+        (!x y. x IN c /\ y IN c ==> (f x = f y <=> x = y)) /\
+        (IMAGE f c) HAS_SIZE dim (IMAGE f (:real^M) INTER {y | g(y) = vec 0})`
+  STRIP_ASSUME_TAC THENL
+   [MP_TAC(ISPEC `IMAGE (f:real^M->real^N) (:real^M) INTER
+                 {x | (g:real^N->real^P) x = vec 0}` BASIS_EXISTS_FINITE) THEN
+    REWRITE_TAC[SUBSET_INTER; GSYM CONJ_ASSOC; EXISTS_FINITE_SUBSET_IMAGE] THEN
+    DISCH_THEN(X_CHOOSE_THEN `c:real^M->bool` STRIP_ASSUME_TAC) THEN
+    MP_TAC(ISPECL [`f:real^M->real^N`; `c:real^M->bool`]
+        IMAGE_INJECTIVE_IMAGE_OF_SUBSET) THEN
+    MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `d:real^M->bool` THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
+     (CONJUNCTS_THEN2 SUBST_ALL_TAC ASSUME_TAC)) THEN
+    ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[FINITE_SUBSET];
+    ALL_TAC] THEN
+  MATCH_MP_TAC LE_TRANS THEN
+  EXISTS_TAC `dim(span(b UNION c:real^M->bool))` THEN CONJ_TAC THENL
+   [MATCH_MP_TAC DIM_SUBSET THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; o_THM] THEN
+    X_GEN_TAC `x:real^M` THEN DISCH_TAC THEN
+    SUBGOAL_THEN `(f:real^M->real^N) x IN span(IMAGE f c)` MP_TAC THENL
+     [ASM SET_TAC[]; ALL_TAC] THEN
+    ASM_SIMP_TAC[SPAN_LINEAR_IMAGE; IN_IMAGE; LEFT_IMP_EXISTS_THM] THEN
+    X_GEN_TAC `y:real^M` THEN STRIP_TAC THEN
+    SUBST1_TAC(VECTOR_ARITH `x:real^M = y + (x - y)`) THEN
+    MATCH_MP_TAC SPAN_ADD THEN CONJ_TAC THENL
+     [ASM_MESON_TAC[SUBSET_UNION; SPAN_MONO; SUBSET]; ALL_TAC] THEN
+    MATCH_MP_TAC(SET_RULE
+     `!t. x IN t /\ t SUBSET s ==> x IN s`) THEN
+    EXISTS_TAC `{x | (f:real^M->real^N) x = vec 0}` THEN CONJ_TAC THENL
+     [REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[LINEAR_SUB; VECTOR_SUB_EQ];
+      ASM_MESON_TAC[SUBSET_TRANS; SUBSET_UNION; SPAN_MONO]];
+    REWRITE_TAC[DIM_SPAN] THEN MATCH_MP_TAC LE_TRANS THEN
+    EXISTS_TAC `CARD(b UNION c:real^M->bool)` THEN
+    ASM_SIMP_TAC[DIM_LE_CARD; FINITE_UNION; INDEPENDENT_IMP_FINITE] THEN
+    MATCH_MP_TAC LE_TRANS THEN
+    EXISTS_TAC `CARD(b:real^M->bool) + CARD(c:real^M->bool)` THEN
+    ASM_SIMP_TAC[CARD_UNION_LE] THEN MATCH_MP_TAC LE_ADD2 THEN CONJ_TAC THENL
+     [ASM_SIMP_TAC[GSYM DIM_EQ_CARD; DIM_SUBSET]; ALL_TAC] THEN
+    MATCH_MP_TAC LE_TRANS THEN
+    EXISTS_TAC `dim(IMAGE (f:real^M->real^N) c)` THEN CONJ_TAC THENL
+     [ASM_SIMP_TAC[DIM_EQ_CARD] THEN
+      ASM_MESON_TAC[CARD_IMAGE_INJ; LE_REFL];
+      ASM_SIMP_TAC[GSYM DIM_EQ_CARD; DIM_SUBSET]]]);;
+
+let DIM_ORTHOGONAL_SUM = prove
+ (`!s t:real^N->bool.
+        (!x y. x IN s /\ y IN t ==> x dot y = &0)
+        ==> dim(s UNION t) = dim(s) + dim(t)`,
+  REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM DIM_SPAN] THEN
+  REWRITE_TAC[SPAN_UNION] THEN
+  SIMP_TAC[GSYM DIM_SUMS_INTER; SUBSPACE_SPAN] THEN
+  REWRITE_TAC[ARITH_RULE `x = x + y <=> y = 0`] THEN
+  REWRITE_TAC[DIM_EQ_0; SUBSET; IN_INTER] THEN
+  SUBGOAL_THEN
+   `!x:real^N. x IN span s ==> !y:real^N. y IN span t ==> x dot y = &0`
+  MP_TAC THENL
+   [MATCH_MP_TAC SPAN_INDUCT THEN CONJ_TAC THENL
+     [X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN
+      MATCH_MP_TAC SPAN_INDUCT THEN ASM_SIMP_TAC[IN_ELIM_THM] THEN
+      SIMP_TAC[subspace; IN_ELIM_THM; DOT_RMUL; DOT_RADD; DOT_RZERO] THEN
+      REAL_ARITH_TAC;
+      SIMP_TAC[subspace; IN_ELIM_THM; DOT_LMUL; DOT_LADD; DOT_LZERO] THEN
+      REAL_ARITH_TAC];
+    REWRITE_TAC[IN_SING] THEN MESON_TAC[DOT_EQ_0]]);;
+
+let DIM_SUBSPACE_ORTHOGONAL_TO_VECTORS = prove
+ (`!s t:real^N->bool.
+        subspace s /\ subspace t /\ s SUBSET t
+        ==> dim {y | y IN t /\ !x. x IN s ==> orthogonal x y} + dim s = dim t`,
+  REPEAT STRIP_TAC THEN
+  W(MP_TAC o PART_MATCH (rand o rand) DIM_ORTHOGONAL_SUM o lhand o snd) THEN
+  ANTS_TAC THENL
+   [SIMP_TAC[IN_ELIM_THM; orthogonal] THEN MESON_TAC[DOT_SYM];
+    DISCH_THEN(SUBST1_TAC o SYM)] THEN
+  ONCE_REWRITE_TAC[GSYM DIM_SPAN] THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [MATCH_MP_TAC SPAN_MONO THEN ASM SET_TAC[]; ALL_TAC] THEN
+  MATCH_MP_TAC SPAN_SUBSET_SUBSPACE THEN REWRITE_TAC[SUBSPACE_SPAN] THEN
+  REWRITE_TAC[SPAN_UNION; SUBSET; IN_ELIM_THM] THEN
+  X_GEN_TAC `x:real^N` THEN DISCH_TAC THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  MP_TAC(ISPECL [`s:real^N->bool`; `x:real^N`]
+        ORTHOGONAL_SUBSPACE_DECOMP_EXISTS) THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `y:real^N` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `z:real^N` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[VECTOR_ADD_SYM] THEN
+  MATCH_MP_TAC SPAN_SUPERSET THEN REWRITE_TAC[IN_ELIM_THM] THEN CONJ_TAC THENL
+   [FIRST_ASSUM(SUBST1_TAC o MATCH_MP (VECTOR_ARITH
+     `x:real^N = y + z ==> z = x - y`)) THEN
+    MATCH_MP_TAC SUBSPACE_SUB THEN
+    ASM_MESON_TAC[SUBSET; SPAN_EQ_SELF];
+    ASM_MESON_TAC[SPAN_SUPERSET; ORTHOGONAL_SYM]]);;
+
+let DIM_SPECIAL_SUBSPACE = prove
+ (`!k. dim {x:real^N |
+            !i. 1 <= i /\ i <= dimindex(:N) /\ i IN k ==> x$i = &0} =
+       CARD((1..dimindex(:N)) DIFF k)`,
+  GEN_TAC THEN MATCH_MP_TAC DIM_UNIQUE THEN
+  EXISTS_TAC `IMAGE (basis:num->real^N) ((1..dimindex(:N)) DIFF k)` THEN
+  REPEAT CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_ELIM_THM] THEN
+    SIMP_TAC[BASIS_COMPONENT; IN_DIFF; IN_NUMSEG] THEN MESON_TAC[];
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN X_GEN_TAC `x:real^N` THEN
+    DISCH_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM BASIS_EXPANSION] THEN
+    MATCH_MP_TAC SPAN_VSUM THEN REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN
+    X_GEN_TAC `j:num` THEN STRIP_TAC THEN
+    ASM_CASES_TAC `(x:real^N)$j = &0` THEN
+    ASM_REWRITE_TAC[SPAN_0; VECTOR_MUL_LZERO] THEN
+    MATCH_MP_TAC SPAN_MUL THEN MATCH_MP_TAC SPAN_SUPERSET THEN
+    REWRITE_TAC[IN_IMAGE] THEN EXISTS_TAC `j:num` THEN
+    REWRITE_TAC[IN_NUMSEG; IN_DIFF] THEN ASM_MESON_TAC[];
+    MATCH_MP_TAC PAIRWISE_ORTHOGONAL_INDEPENDENT THEN
+    REWRITE_TAC[pairwise; IMP_CONJ; RIGHT_FORALL_IMP_THM;
+      SET_RULE `~(a IN IMAGE f s) <=> (!x. x IN s ==> ~(f x = a))`] THEN
+    SIMP_TAC[FORALL_IN_IMAGE; ORTHOGONAL_BASIS_BASIS; BASIS_INJ_EQ;
+             IN_DIFF; IN_NUMSEG; BASIS_NONZERO];
+    SIMP_TAC[HAS_SIZE; FINITE_IMAGE; FINITE_DIFF; FINITE_NUMSEG] THEN
+    MATCH_MP_TAC CARD_IMAGE_INJ THEN
+    SIMP_TAC[FINITE_DIFF; FINITE_NUMSEG; IMP_CONJ; RIGHT_FORALL_IMP_THM;
+      SET_RULE `~(a IN IMAGE f s) <=> (!x. x IN s ==> ~(f x = a))`] THEN
+    SIMP_TAC[FORALL_IN_IMAGE; ORTHOGONAL_BASIS_BASIS; BASIS_INJ_EQ;
+             IN_DIFF; IN_NUMSEG; BASIS_NONZERO]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More about product spaces.                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let PASTECART_AS_ORTHOGONAL_SUM = prove
+ (`!x:real^M y:real^N.
+        pastecart x y = pastecart x (vec 0) + pastecart (vec 0) y`,
+  REWRITE_TAC[PASTECART_ADD; VECTOR_ADD_LID; VECTOR_ADD_RID]);;
+
+let PCROSS_AS_ORTHOGONAL_SUM = prove
+ (`!s:real^M->bool t:real^N->bool.
+        s PCROSS t =
+        {u + v | u IN IMAGE (\x. pastecart x (vec 0)) s /\
+                 v IN IMAGE (\y. pastecart (vec 0) y) t}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[PCROSS] THEN
+  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV)
+   [PASTECART_AS_ORTHOGONAL_SUM] THEN
+  SET_TAC[]);;
+
+let DIM_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        subspace s /\ subspace t ==> dim(s PCROSS t) = dim s + dim t`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[PCROSS_AS_ORTHOGONAL_SUM] THEN
+  W(MP_TAC o PART_MATCH (lhand o lhand o rand) DIM_SUMS_INTER o
+        lhand o snd) THEN
+  ANTS_TAC THENL
+   [CONJ_TAC THEN MATCH_MP_TAC SUBSPACE_LINEAR_IMAGE;
+    MATCH_MP_TAC(ARITH_RULE `c = d /\ b = 0 ==> a + b = c ==> a = d`) THEN
+    CONJ_TAC THENL
+     [BINOP_TAC THEN MATCH_MP_TAC DIM_INJECTIVE_LINEAR_IMAGE THEN
+      SIMP_TAC[PASTECART_INJ];
+      REWRITE_TAC[DIM_EQ_0; SUBSET; IN_INTER; IN_IMAGE; IN_SING] THEN
+      REWRITE_TAC[PASTECART_EQ; FSTCART_PASTECART; SNDCART_PASTECART] THEN
+      MESON_TAC[FSTCART_VEC; SNDCART_VEC]]] THEN
+  ASM_REWRITE_TAC[linear; GSYM PASTECART_VEC] THEN
+  REWRITE_TAC[PASTECART_ADD; GSYM PASTECART_CMUL; PASTECART_INJ] THEN
+  VECTOR_ARITH_TAC);;
+
+let SPAN_PCROSS_SUBSET = prove
+ (`!s:real^M->bool t:real^N->bool.
+        span(s PCROSS t) SUBSET (span s) PCROSS (span t)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC SPAN_SUBSET_SUBSPACE THEN
+  SIMP_TAC[SUBSPACE_PCROSS; SUBSPACE_SPAN; PCROSS_MONO; SPAN_INC]);;
+
+let SPAN_PCROSS = prove
+ (`!s:real^M->bool t:real^N->bool.
+        ~(s = {}) /\ ~(t = {}) /\ (vec 0 IN s \/ vec 0 IN t)
+        ==> span(s PCROSS t) = (span s) PCROSS (span t)`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN
+  REWRITE_TAC[SPAN_PCROSS_SUBSET] THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_PCROSS] THEN
+  ONCE_REWRITE_TAC[PASTECART_AS_ORTHOGONAL_SUM] THEN
+  SUBGOAL_THEN
+   `(!x:real^M. x IN span s ==> pastecart x (vec 0) IN span(s PCROSS t)) /\
+    (!y:real^N. y IN span t ==> pastecart (vec 0) y IN span(s PCROSS t))`
+   (fun th -> ASM_MESON_TAC[th; SPAN_ADD]) THEN
+  CONJ_TAC THEN MATCH_MP_TAC SPAN_INDUCT THEN REWRITE_TAC[IN_ELIM_THM] THEN
+  (CONJ_TAC THENL
+    [REWRITE_TAC[IN_ELIM_THM] THEN
+     ASM_SIMP_TAC[SPAN_SUPERSET; PASTECART_IN_PCROSS];
+     REWRITE_TAC[subspace; IN_ELIM_THM; PASTECART_VEC; SPAN_0] THEN
+     CONJ_TAC THEN REPEAT GEN_TAC THENL
+      [DISCH_THEN(MP_TAC o MATCH_MP SPAN_ADD) THEN
+       REWRITE_TAC[PASTECART_ADD; VECTOR_ADD_LID];
+       DISCH_THEN(MP_TAC o MATCH_MP SPAN_MUL) THEN
+       SIMP_TAC[GSYM PASTECART_CMUL; VECTOR_MUL_RZERO]]])
+  THENL
+   [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`) THEN
+    SUBGOAL_THEN
+     `pastecart x (vec 0) =
+      pastecart (x:real^M) (y:real^N) - pastecart (vec 0) y`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[PASTECART_SUB; PASTECART_INJ] THEN VECTOR_ARITH_TAC;
+      MATCH_MP_TAC SPAN_SUB THEN
+      ASM_SIMP_TAC[SPAN_SUPERSET; PASTECART_IN_PCROSS]];
+    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
+    SUBGOAL_THEN
+     `pastecart (vec 0) y =
+      pastecart (x:real^M) (y:real^N) - pastecart x (vec 0)`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[PASTECART_SUB; PASTECART_INJ] THEN VECTOR_ARITH_TAC;
+      MATCH_MP_TAC SPAN_SUB THEN
+      ASM_SIMP_TAC[SPAN_SUPERSET; PASTECART_IN_PCROSS]]]);;
+
+let DIM_PCROSS_STRONG = prove
+ (`!s:real^M->bool t:real^N->bool.
+        ~(s = {}) /\ ~(t = {}) /\ (vec 0 IN s \/ vec 0 IN t)
+        ==> dim(s PCROSS t) = dim s + dim t`,
+  ONCE_REWRITE_TAC[GSYM DIM_SPAN] THEN
+  SIMP_TAC[SPAN_PCROSS; DIM_PCROSS; SUBSPACE_SPAN]);;
+
+let SPAN_SUMS = prove
+ (`!s t:real^N->bool.
+        ~(s = {}) /\ ~(t = {}) /\ vec 0 IN (s UNION t)
+        ==> span {x + y | x IN s /\ y IN t} =
+            {x + y | x IN span s /\ y IN span t}`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[GSYM SPAN_UNION] THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN
+  CONJ_TAC THEN MATCH_MP_TAC SPAN_SUBSET_SUBSPACE THEN
+  REWRITE_TAC[SUBSPACE_SPAN; SUBSET; FORALL_IN_GSPEC] THEN
+  SIMP_TAC[SPAN_ADD; IN_UNION; SPAN_SUPERSET] THEN
+  X_GEN_TAC `x:real^N` THEN STRIP_TAC THEN
+  FIRST_X_ASSUM(DISJ_CASES_TAC o GEN_REWRITE_RULE I [IN_UNION]) THENL
+   [UNDISCH_TAC `~(t:real^N->bool = {})` THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `y:real^N`) THEN
+    SUBST1_TAC(VECTOR_ARITH `x:real^N = (x + y) - (vec 0 + y)`) THEN
+    MATCH_MP_TAC SPAN_SUB THEN CONJ_TAC THEN MATCH_MP_TAC SPAN_SUPERSET THEN
+    ASM SET_TAC[];
+    MATCH_MP_TAC SPAN_SUPERSET THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    ASM_MESON_TAC[VECTOR_ADD_RID];
+    MATCH_MP_TAC SPAN_SUPERSET THEN REWRITE_TAC[IN_ELIM_THM] THEN
+    ASM_MESON_TAC[VECTOR_ADD_LID];
+    UNDISCH_TAC `~(s:real^N->bool = {})` THEN
+    REWRITE_TAC[GSYM MEMBER_NOT_EMPTY] THEN
+    DISCH_THEN(X_CHOOSE_TAC `y:real^N`) THEN
+    SUBST1_TAC(VECTOR_ARITH `x:real^N = (y + x) - (y + vec 0)`) THEN
+    MATCH_MP_TAC SPAN_SUB THEN CONJ_TAC THEN MATCH_MP_TAC SPAN_SUPERSET THEN
+    ASM SET_TAC[]]);;
+
+(* ------------------------------------------------------------------------- *)
+(* More about rank from the rank/nullspace formula.                          *)
+(* ------------------------------------------------------------------------- *)
+
+let RANK_NULLSPACE = prove
+ (`!A:real^M^N. rank A + dim {x | A ** x = vec 0} = dimindex(:M)`,
+  GEN_TAC THEN REWRITE_TAC[RANK_DIM_IM] THEN
+  MATCH_MP_TAC DIM_IMAGE_KERNEL THEN
+  REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR]);;
+
+let RANK_SYLVESTER = prove
+ (`!A:real^N^M B:real^P^N.
+        rank(A) + rank(B) <= rank(A ** B) + dimindex(:N)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC(ARITH_RULE
+    `!ia ib iab p:num.
+        ra + ia = n /\
+        rb + ib = p /\
+        rab + iab = p /\
+        iab <= ia + ib
+        ==> ra + rb <= rab + n`) THEN
+  MAP_EVERY EXISTS_TAC
+   [`dim {x | (A:real^N^M) ** x = vec 0}`;
+    `dim {x | (B:real^P^N) ** x = vec 0}`;
+    `dim {x | ((A:real^N^M) ** (B:real^P^N)) ** x = vec 0}`;
+    `dimindex(:P)`] THEN
+  REWRITE_TAC[RANK_NULLSPACE] THEN
+  REWRITE_TAC[GSYM MATRIX_VECTOR_MUL_ASSOC] THEN
+  ONCE_REWRITE_TAC[ADD_SYM] THEN
+  MATCH_MP_TAC(REWRITE_RULE[o_DEF] DIM_KERNEL_COMPOSE) THEN
+  CONJ_TAC THEN GEN_REWRITE_TAC RAND_CONV [GSYM ETA_AX] THEN
+  REWRITE_TAC[MATRIX_VECTOR_MUL_LINEAR]);;
+
+let RANK_GRAM = prove
+ (`!A:real^M^N. rank(transp A ** A) = rank A`,
+  GEN_TAC THEN MATCH_MP_TAC(ARITH_RULE
+   `!n n' k. r + n:num = k /\ r' + n' = k /\ n = n' ==> r = r'`) THEN
+  MAP_EVERY EXISTS_TAC
+   [`dim {x | (transp A ** (A:real^M^N)) ** x = vec 0}`;
+    `dim {x | (A:real^M^N) ** x = vec 0}`;
+    `dimindex(:M)`] THEN
+  REWRITE_TAC[RANK_NULLSPACE] THEN AP_TERM_TAC THEN
+  MATCH_MP_TAC SUBSET_ANTISYM THEN
+  SIMP_TAC[SUBSET; IN_ELIM_THM; GSYM MATRIX_VECTOR_MUL_ASSOC;
+           MATRIX_VECTOR_MUL_RZERO] THEN
+  X_GEN_TAC `x:real^M` THEN
+  DISCH_THEN(MP_TAC o AP_TERM `(dot) (x:real^M)`) THEN
+  ONCE_REWRITE_TAC[GSYM DOT_LMUL_MATRIX] THEN
+  REWRITE_TAC[VECTOR_MATRIX_MUL_TRANSP; TRANSP_TRANSP; DOT_RZERO] THEN
+  REWRITE_TAC[DOT_EQ_0]);;
+
+let RANK_TRIANGLE = prove
+ (`!A B:real^M^N. rank(A + B) <= rank(A) + rank(B)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[RANK_DIM_IM] THEN
+  MP_TAC(ISPECL [`IMAGE (\x. (A:real^M^N) ** x) (:real^M)`;
+                 `IMAGE (\x. (B:real^M^N) ** x) (:real^M)`]
+                DIM_SUMS_INTER) THEN
+  ASM_SIMP_TAC[SUBSPACE_LINEAR_IMAGE; SUBSPACE_UNIV;
+               MATRIX_VECTOR_MUL_LINEAR] THEN
+  DISCH_THEN(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC(ARITH_RULE `x:num <= y ==> x <= y + z`) THEN
+  MATCH_MP_TAC DIM_SUBSET THEN
+  REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_UNIV;
+              MATRIX_VECTOR_MUL_ADD_RDISTRIB] THEN
+  REWRITE_TAC[IN_ELIM_THM; IN_IMAGE; IN_UNIV] THEN MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Infinity norm.                                                            *)
+(* ------------------------------------------------------------------------- *)
+
+let infnorm = define
+ `infnorm (x:real^N) = sup { abs(x$i) | 1 <= i /\ i <= dimindex(:N) }`;;
+
+let NUMSEG_DIMINDEX_NONEMPTY = prove
+ (`?i. i IN 1..dimindex(:N)`,
+  REWRITE_TAC[MEMBER_NOT_EMPTY; NUMSEG_EMPTY; NOT_LT; DIMINDEX_GE_1]);;
+
+let INFNORM_SET_IMAGE = prove
+ (`{abs(x$i) | 1 <= i /\ i <= dimindex(:N)} =
+   IMAGE (\i. abs(x$i)) (1..dimindex(:N))`,
+  REWRITE_TAC[numseg] THEN SET_TAC[]);;
+
+let INFNORM_SET_LEMMA = prove
+ (`FINITE {abs((x:real^N)$i) | 1 <= i /\ i <= dimindex(:N)} /\
+   ~({abs(x$i) | 1 <= i /\ i <= dimindex(:N)} = {})`,
+  SIMP_TAC[INFNORM_SET_IMAGE; FINITE_NUMSEG; FINITE_IMAGE; IMAGE_EQ_EMPTY] THEN
+  REWRITE_TAC[NUMSEG_EMPTY; NOT_LT; DIMINDEX_GE_1]);;
+
+let INFNORM_POS_LE = prove
+ (`!x. &0 <= infnorm x`,
+  REWRITE_TAC[infnorm] THEN
+  SIMP_TAC[REAL_LE_SUP_FINITE; INFNORM_SET_LEMMA] THEN
+  REWRITE_TAC[INFNORM_SET_IMAGE; NUMSEG_DIMINDEX_NONEMPTY;
+              EXISTS_IN_IMAGE; REAL_ABS_POS]);;
+
+let INFNORM_TRIANGLE = prove
+ (`!x y. infnorm(x + y) <= infnorm x + infnorm y`,
+  REWRITE_TAC[infnorm] THEN
+  SIMP_TAC[REAL_SUP_LE_FINITE; INFNORM_SET_LEMMA] THEN
+  ONCE_REWRITE_TAC[GSYM REAL_LE_SUB_RADD] THEN
+  SIMP_TAC[REAL_LE_SUP_FINITE; INFNORM_SET_LEMMA] THEN
+  ONCE_REWRITE_TAC[REAL_ARITH `x - y <= z <=> x - z <= y`] THEN
+  SIMP_TAC[REAL_LE_SUP_FINITE; INFNORM_SET_LEMMA] THEN
+  REWRITE_TAC[INFNORM_SET_IMAGE; FORALL_IN_IMAGE; EXISTS_IN_IMAGE] THEN
+  SIMP_TAC[VECTOR_ADD_COMPONENT; GSYM IN_NUMSEG] THEN
+  MESON_TAC[NUMSEG_DIMINDEX_NONEMPTY;
+            REAL_ARITH `abs(x + y) - abs(x) <= abs(y)`]);;
+
+let INFNORM_EQ_0 = prove
+ (`!x. infnorm x = &0 <=> x = vec 0`,
+  REWRITE_TAC[GSYM REAL_LE_ANTISYM; INFNORM_POS_LE] THEN
+  SIMP_TAC[infnorm; REAL_SUP_LE_FINITE; INFNORM_SET_LEMMA] THEN
+  SIMP_TAC[FORALL_IN_IMAGE; INFNORM_SET_IMAGE; CART_EQ; VEC_COMPONENT] THEN
+  REWRITE_TAC[IN_NUMSEG; REAL_ARITH `abs(x) <= &0 <=> x = &0`]);;
+
+let INFNORM_0 = prove
+ (`infnorm(vec 0) = &0`,
+  REWRITE_TAC[INFNORM_EQ_0]);;
+
+let INFNORM_NEG = prove
+ (`!x. infnorm(--x) = infnorm x`,
+  GEN_TAC THEN REWRITE_TAC[infnorm] THEN AP_TERM_TAC THEN
+  REWRITE_TAC[EXTENSION; IN_ELIM_THM] THEN
+  MESON_TAC[REAL_ABS_NEG; VECTOR_NEG_COMPONENT]);;
+
+let INFNORM_SUB = prove
+ (`!x y. infnorm(x - y) = infnorm(y - x)`,
+  MESON_TAC[INFNORM_NEG; VECTOR_NEG_SUB]);;
+
+let REAL_ABS_SUB_INFNORM = prove
+ (`abs(infnorm x - infnorm y) <= infnorm(x - y)`,
+  MATCH_MP_TAC(REAL_ARITH
+    `nx <= n + ny /\ ny <= n + nx ==> abs(nx - ny) <= n`) THEN
+  MESON_TAC[INFNORM_SUB; VECTOR_SUB_ADD2; INFNORM_TRIANGLE; VECTOR_ADD_SYM]);;
+
+let REAL_ABS_INFNORM = prove
+ (`!x. abs(infnorm x) = infnorm x`,
+  REWRITE_TAC[real_abs; INFNORM_POS_LE]);;
+
+let COMPONENT_LE_INFNORM = prove
+ (`!x:real^N i. 1 <= i /\ i <= dimindex (:N) ==> abs(x$i) <= infnorm x`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[infnorm] THEN
+  MP_TAC(SPEC `{ abs((x:real^N)$i) | 1 <= i /\ i <= dimindex(:N) }`
+              SUP_FINITE) THEN
+  REWRITE_TAC[INFNORM_SET_LEMMA] THEN
+  SIMP_TAC[INFNORM_SET_IMAGE; FORALL_IN_IMAGE; IN_NUMSEG]);;
+
+let INFNORM_MUL_LEMMA = prove
+ (`!a x. infnorm(a % x) <= abs a * infnorm x`,
+  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [infnorm] THEN
+  SIMP_TAC[REAL_SUP_LE_FINITE; INFNORM_SET_LEMMA] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE; INFNORM_SET_IMAGE] THEN
+  SIMP_TAC[REAL_ABS_MUL; VECTOR_MUL_COMPONENT; IN_NUMSEG] THEN
+  SIMP_TAC[COMPONENT_LE_INFNORM; REAL_LE_LMUL; REAL_ABS_POS]);;
+
+let INFNORM_MUL = prove
+ (`!a x:real^N. infnorm(a % x) = abs a * infnorm x`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a = &0` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_LZERO; INFNORM_0; REAL_ABS_0; REAL_MUL_LZERO] THEN
+  REWRITE_TAC[GSYM REAL_LE_ANTISYM; INFNORM_MUL_LEMMA] THEN
+  GEN_REWRITE_TAC (LAND_CONV o funpow 2 RAND_CONV) [GSYM VECTOR_MUL_LID] THEN
+  FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP REAL_MUL_LINV) THEN
+  REWRITE_TAC[GSYM VECTOR_MUL_ASSOC] THEN
+  MATCH_MP_TAC REAL_LE_TRANS THEN
+  EXISTS_TAC `abs(a) * abs(inv a) * infnorm(a % x:real^N)` THEN
+  ASM_SIMP_TAC[INFNORM_MUL_LEMMA; REAL_LE_LMUL; REAL_ABS_POS] THEN
+  ASM_SIMP_TAC[REAL_MUL_ASSOC; GSYM REAL_ABS_MUL; REAL_MUL_RINV] THEN
+  REAL_ARITH_TAC);;
+
+let INFNORM_POS_LT = prove
+ (`!x. &0 < infnorm x <=> ~(x = vec 0)`,
+  MESON_TAC[REAL_LT_LE; INFNORM_POS_LE; INFNORM_EQ_0]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Prove that it differs only up to a bound from Euclidean norm.             *)
+(* ------------------------------------------------------------------------- *)
+
+let INFNORM_LE_NORM = prove
+ (`!x. infnorm(x) <= norm(x)`,
+  SIMP_TAC[infnorm; REAL_SUP_LE_FINITE; INFNORM_SET_LEMMA] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN MESON_TAC[COMPONENT_LE_NORM]);;
+
+let NORM_LE_INFNORM = prove
+ (`!x:real^N. norm(x) <= sqrt(&(dimindex(:N))) * infnorm(x)`,
+  GEN_TAC THEN GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o funpow 2 RAND_CONV)
+   [GSYM CARD_NUMSEG_1] THEN
+  REWRITE_TAC[vector_norm] THEN MATCH_MP_TAC REAL_LE_LSQRT THEN
+  SIMP_TAC[DOT_POS_LE; SQRT_POS_LE; REAL_POS; REAL_LE_MUL; INFNORM_POS_LE;
+           SQRT_POW_2; REAL_POW_MUL] THEN
+  REWRITE_TAC[dot] THEN MATCH_MP_TAC SUM_BOUND THEN
+  REWRITE_TAC[FINITE_NUMSEG; IN_NUMSEG] THEN REPEAT STRIP_TAC THEN
+  REWRITE_TAC[GSYM REAL_POW_2] THEN ONCE_REWRITE_TAC[GSYM REAL_POW2_ABS] THEN
+  MATCH_MP_TAC REAL_POW_LE2 THEN REWRITE_TAC[REAL_ABS_POS] THEN
+  MATCH_MP_TAC(REAL_ARITH `x <= y ==> x <= abs(y)`) THEN
+  SIMP_TAC[infnorm; REAL_LE_SUP_FINITE; INFNORM_SET_LEMMA] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[REAL_LE_REFL]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Equality in Cauchy-Schwarz and triangle inequalities.                     *)
+(* ------------------------------------------------------------------------- *)
+
+let NORM_CAUCHY_SCHWARZ_EQ = prove
+ (`!x:real^N y. x dot y = norm(x) * norm(y) <=> norm(x) % y = norm(y) % x`,
+  REPEAT STRIP_TAC THEN
+  MAP_EVERY ASM_CASES_TAC [`x:real^N = vec 0`; `y:real^N = vec 0`] THEN
+  ASM_REWRITE_TAC[NORM_0; REAL_MUL_LZERO; REAL_MUL_RZERO;
+    DOT_LZERO; DOT_RZERO; VECTOR_MUL_LZERO; VECTOR_MUL_RZERO] THEN
+  MP_TAC(ISPEC `norm(y:real^N) % x - norm(x:real^N) % y` DOT_EQ_0) THEN
+  REWRITE_TAC[DOT_RSUB; DOT_LSUB; DOT_LMUL; DOT_RMUL; GSYM NORM_POW_2;
+              REAL_POW_2; VECTOR_SUB_EQ] THEN
+  REWRITE_TAC[DOT_SYM; REAL_ARITH
+   `y * (y * x * x - x * d) - x * (y * d - x * y * y) =
+    &2 * x * y * (x * y - d)`] THEN
+  ASM_SIMP_TAC[REAL_ENTIRE; NORM_EQ_0; REAL_SUB_0; REAL_OF_NUM_EQ; ARITH] THEN
+  REWRITE_TAC[EQ_SYM_EQ]);;
+
+let NORM_CAUCHY_SCHWARZ_ABS_EQ = prove
+ (`!x:real^N y. abs(x dot y) = norm(x) * norm(y) <=>
+                norm(x) % y = norm(y) % x \/ norm(x) % y = --norm(y) % x`,
+  SIMP_TAC[REAL_ARITH `&0 <= a ==> (abs x = a <=> x = a \/ --x = a)`;
+           REAL_LE_MUL; NORM_POS_LE; GSYM DOT_RNEG] THEN
+  REPEAT GEN_TAC THEN
+  GEN_REWRITE_TAC (LAND_CONV o funpow 3 RAND_CONV) [GSYM NORM_NEG] THEN
+  REWRITE_TAC[NORM_CAUCHY_SCHWARZ_EQ] THEN REWRITE_TAC[NORM_NEG] THEN
+  BINOP_TAC THEN VECTOR_ARITH_TAC);;
+
+let NORM_TRIANGLE_EQ = prove
+ (`!x y:real^N. norm(x + y) = norm(x) + norm(y) <=> norm(x) % y = norm(y) % x`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM NORM_CAUCHY_SCHWARZ_EQ] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `norm(x + y:real^N) pow 2 = (norm(x) + norm(y)) pow 2` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[REAL_RING `x pow 2 = y pow 2 <=> x = y \/ x + y = &0`] THEN
+    MAP_EVERY (MP_TAC o C ISPEC NORM_POS_LE)
+     [`x + y:real^N`; `x:real^N`; `y:real^N`] THEN
+    REAL_ARITH_TAC;
+    REWRITE_TAC[NORM_POW_2; DOT_LADD; DOT_RADD; REAL_ARITH
+     `(x + y) pow 2 = x pow 2 + y pow 2 + &2 * x * y`] THEN
+    REWRITE_TAC[DOT_SYM] THEN REAL_ARITH_TAC]);;
+
+let DIST_TRIANGLE_EQ = prove
+ (`!x y z. dist(x,z) = dist(x,y) + dist(y,z) <=>
+                norm (x - y) % (y - z) = norm (y - z) % (x - y)`,
+  REWRITE_TAC[GSYM NORM_TRIANGLE_EQ] THEN NORM_ARITH_TAC);;
+
+let NORM_CROSS_MULTIPLY = prove
+ (`!a b x y:real^N.
+        a % x = b % y /\ &0 < a /\ &0 < b
+        ==> norm y % x = norm x % y`,
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC) THEN
+  ASM_CASES_TAC `y:real^N = vec 0` THEN
+  ASM_SIMP_TAC[VECTOR_MUL_EQ_0; REAL_LT_IMP_NZ; VECTOR_MUL_RZERO] THEN
+  DISCH_THEN(MP_TAC o AP_TERM `\x:real^N. inv(a) % x`) THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; REAL_LT_IMP_NZ; VECTOR_MUL_LID;
+               NORM_MUL; REAL_ABS_MUL; REAL_ABS_INV] THEN
+  ASM_SIMP_TAC[real_abs; REAL_LT_IMP_LE; REAL_MUL_AC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Collinearity.                                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let collinear = new_definition
+ `collinear s <=> ?u. !x y. x IN s /\ y IN s ==> ?c. x - y = c % u`;;
+
+let COLLINEAR_SUBSET = prove
+ (`!s t. collinear t /\ s SUBSET t ==> collinear s`,
+  REWRITE_TAC[collinear] THEN SET_TAC[]);;
+
+let COLLINEAR_EMPTY = prove
+ (`collinear {}`,
+  REWRITE_TAC[collinear; NOT_IN_EMPTY]);;
+
+let COLLINEAR_SING = prove
+ (`!x. collinear {x}`,
+  SIMP_TAC[collinear; IN_SING; VECTOR_SUB_REFL] THEN
+  MESON_TAC[VECTOR_MUL_LZERO]);;
+
+let COLLINEAR_2 = prove
+ (`!x y:real^N. collinear {x,y}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[collinear; IN_INSERT; NOT_IN_EMPTY] THEN
+  EXISTS_TAC `x - y:real^N` THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
+   [EXISTS_TAC `&0`; EXISTS_TAC `&1`; EXISTS_TAC `-- &1`; EXISTS_TAC `&0`] THEN
+  VECTOR_ARITH_TAC);;
+
+let COLLINEAR_SMALL = prove
+ (`!s. FINITE s /\ CARD s <= 2 ==> collinear s`,
+  REWRITE_TAC[ARITH_RULE `s <= 2 <=> s = 0 \/ s = 1 \/ s = 2`] THEN
+  REWRITE_TAC[LEFT_OR_DISTRIB; GSYM HAS_SIZE] THEN
+  CONV_TAC(ONCE_DEPTH_CONV HAS_SIZE_CONV) THEN
+  REPEAT STRIP_TAC THEN
+  ASM_REWRITE_TAC[COLLINEAR_EMPTY; COLLINEAR_SING; COLLINEAR_2]);;
+
+let COLLINEAR_3 = prove
+ (`!x y z. collinear {x,y,z} <=> collinear {vec 0,x - y,z - y}`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[collinear; FORALL_IN_INSERT; IMP_CONJ; RIGHT_FORALL_IMP_THM;
+              NOT_IN_EMPTY] THEN
+  AP_TERM_TAC THEN ABS_TAC THEN
+  MESON_TAC[VECTOR_ARITH `x - y = (x - y) - vec 0`;
+            VECTOR_ARITH `y - x = vec 0 - (x - y)`;
+            VECTOR_ARITH `x - z:real^N = (x - y) - (z - y)`]);;
+
+let COLLINEAR_LEMMA = prove
+ (`!x y:real^N. collinear {vec 0,x,y} <=>
+                   x = vec 0 \/ y = vec 0 \/ ?c. y = c % x`,
+  REPEAT GEN_TAC THEN
+  MAP_EVERY ASM_CASES_TAC [`x:real^N = vec 0`; `y:real^N = vec 0`] THEN
+  TRY(ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_SING; COLLINEAR_2] THEN NO_TAC) THEN
+  ASM_REWRITE_TAC[collinear] THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `u:real^N`
+     (fun th -> MP_TAC(SPECL [`x:real^N`; `vec 0:real^N`] th) THEN
+                MP_TAC(SPECL [`y:real^N`; `vec 0:real^N`] th))) THEN
+    REWRITE_TAC[IN_INSERT; VECTOR_SUB_RZERO] THEN
+    DISCH_THEN(X_CHOOSE_THEN `e:real` SUBST_ALL_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `d:real` SUBST_ALL_TAC) THEN
+    EXISTS_TAC `e / d` THEN REWRITE_TAC[VECTOR_MUL_ASSOC] THEN
+    RULE_ASSUM_TAC(REWRITE_RULE[VECTOR_MUL_EQ_0; DE_MORGAN_THM]) THEN
+    ASM_SIMP_TAC[REAL_DIV_RMUL];
+    STRIP_TAC THEN EXISTS_TAC `x:real^N` THEN ASM_REWRITE_TAC[] THEN
+    REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN REPEAT STRIP_TAC THEN
+    ASM_REWRITE_TAC[] THENL
+     [EXISTS_TAC `&0`; EXISTS_TAC `-- &1`; EXISTS_TAC `--c`;
+      EXISTS_TAC `&1`; EXISTS_TAC `&0`; EXISTS_TAC `&1 - c`;
+      EXISTS_TAC `c:real`; EXISTS_TAC `c - &1`; EXISTS_TAC `&0`] THEN
+    VECTOR_ARITH_TAC]);;
+
+let COLLINEAR_LEMMA_ALT = prove
+ (`!x y. collinear {vec 0,x,y} <=> x = vec 0 \/ ?c. y = c % x`,
+  REWRITE_TAC[COLLINEAR_LEMMA] THEN MESON_TAC[VECTOR_MUL_LZERO]);;
+
+let NORM_CAUCHY_SCHWARZ_EQUAL = prove
+ (`!x y:real^N. abs(x dot y) = norm(x) * norm(y) <=> collinear {vec 0,x,y}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[NORM_CAUCHY_SCHWARZ_ABS_EQ] THEN
+  MAP_EVERY ASM_CASES_TAC [`x:real^N = vec 0`; `y:real^N = vec 0`] THEN
+  TRY(ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_SING; COLLINEAR_2; NORM_0;
+                      VECTOR_MUL_LZERO; VECTOR_MUL_RZERO] THEN NO_TAC) THEN
+  ASM_REWRITE_TAC[COLLINEAR_LEMMA] THEN EQ_TAC THENL
+   [STRIP_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o AP_TERM
+       `(%) (inv(norm(x:real^N))):real^N->real^N`);
+      FIRST_X_ASSUM(MP_TAC o AP_TERM
+       `(%) (--inv(norm(x:real^N))):real^N->real^N`)] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LNEG] THEN
+    ASM_SIMP_TAC[REAL_MUL_LINV; NORM_EQ_0; VECTOR_MUL_LNEG; VECTOR_MUL_LID;
+                 VECTOR_ARITH `--x = --y <=> x:real^N = y`] THEN
+    MESON_TAC[];
+    STRIP_TAC THEN ASM_REWRITE_TAC[NORM_MUL; VECTOR_MUL_ASSOC] THEN
+    MATCH_MP_TAC(MESON[]
+      `t = a \/ t = b ==> t % x = a % x \/ t % x = b % x`) THEN
+    REWRITE_TAC[GSYM REAL_MUL_LNEG;
+                REAL_ARITH `x * c = d * x <=> x * (c - d) = &0`] THEN
+    ASM_REWRITE_TAC[REAL_ENTIRE; NORM_EQ_0] THEN REAL_ARITH_TAC]);;
+
+let DOT_CAUCHY_SCHWARZ_EQUAL = prove
+ (`!x y:real^N.
+        (x dot y) pow 2 = (x dot x) * (y dot y) <=>
+        collinear {vec 0,x,y}`,
+  REWRITE_TAC[GSYM NORM_CAUCHY_SCHWARZ_EQUAL] THEN
+  REPEAT GEN_TAC THEN MATCH_MP_TAC(REAL_ARITH
+   `&0 <= y /\ (u:real = v <=> x = abs y) ==> (u = v <=> x = y)`) THEN
+  SIMP_TAC[NORM_POS_LE; REAL_LE_MUL] THEN
+  REWRITE_TAC[REAL_EQ_SQUARE_ABS] THEN REWRITE_TAC[REAL_POW_MUL; NORM_POW_2]);;
+
+let COLLINEAR_3_EXPAND = prove
+ (`!a b c:real^N. collinear{a,b,c} <=> a = c \/ ?u. b = u % a + (&1 - u) % c`,
+  REPEAT GEN_TAC THEN
+  ONCE_REWRITE_TAC[SET_RULE `{a,b,c} = {a,c,b}`] THEN
+  ONCE_REWRITE_TAC[COLLINEAR_3] THEN
+  REWRITE_TAC[COLLINEAR_LEMMA; VECTOR_SUB_EQ] THEN
+  ASM_CASES_TAC `a:real^N = c` THEN ASM_REWRITE_TAC[] THEN
+  ASM_CASES_TAC `b:real^N = c` THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH `u % c + (&1 - u) % c = c`] THENL
+   [EXISTS_TAC `&0` THEN VECTOR_ARITH_TAC;
+    AP_TERM_TAC THEN ABS_TAC THEN VECTOR_ARITH_TAC]);;
+
+let COLLINEAR_TRIPLES = prove
+ (`!s a b:real^N.
+        ~(a = b)
+        ==> (collinear(a INSERT b INSERT s) <=>
+             !x. x IN s ==> collinear{a,b,x})`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
+     (REWRITE_RULE[IMP_CONJ] COLLINEAR_SUBSET)) THEN
+    ASM SET_TAC[];
+    ONCE_REWRITE_TAC[SET_RULE `{a,b,x} = {a,x,b}`] THEN
+    ASM_REWRITE_TAC[COLLINEAR_3_EXPAND] THEN DISCH_TAC THEN
+    SUBGOAL_THEN
+     `!x:real^N. x IN (a INSERT b INSERT s) ==> ?u. x = u % a + (&1 - u) % b`
+    MP_TAC THENL
+     [ASM_REWRITE_TAC[FORALL_IN_INSERT] THEN CONJ_TAC THENL
+       [EXISTS_TAC `&1` THEN VECTOR_ARITH_TAC;
+        EXISTS_TAC `&0` THEN VECTOR_ARITH_TAC];
+      POP_ASSUM_LIST(K ALL_TAC) THEN DISCH_TAC THEN
+      REWRITE_TAC[collinear] THEN EXISTS_TAC `b - a:real^N` THEN
+      MAP_EVERY X_GEN_TAC [`x:real^N`; `y:real^N`] THEN STRIP_TAC THEN
+      FIRST_X_ASSUM(fun th -> MP_TAC(SPEC `x:real^N` th) THEN MP_TAC(SPEC
+        `y:real^N` th)) THEN
+      ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN
+      ASM_REWRITE_TAC[VECTOR_ARITH
+       `(u % a + (&1 - u) % b) - (v % a + (&1 - v) % b):real^N =
+        (v - u) % (b - a)`] THEN
+      MESON_TAC[]]]);;
+
+let COLLINEAR_4_3 = prove
+ (`!a b c d:real^N.
+        ~(a = b)
+        ==> (collinear {a,b,c,d} <=> collinear{a,b,c} /\ collinear{a,b,d})`,
+  REPEAT STRIP_TAC THEN
+  MP_TAC(ISPECL [`{c:real^N,d}`; `a:real^N`; `b:real^N`]
+    COLLINEAR_TRIPLES) THEN
+  ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[FORALL_IN_INSERT; NOT_IN_EMPTY]);;
+
+let COLLINEAR_3_TRANS = prove
+ (`!a b c d:real^N.
+        collinear{a,b,c} /\ collinear{b,c,d} /\ ~(b = c) ==> collinear{a,b,d}`,
+  REPEAT STRIP_TAC THEN MATCH_MP_TAC COLLINEAR_SUBSET THEN
+  EXISTS_TAC `{b:real^N,c,a,d}` THEN ASM_SIMP_TAC[COLLINEAR_4_3] THEN
+  CONJ_TAC THENL [ALL_TAC; SET_TAC[]] THEN
+  REPEAT(POP_ASSUM MP_TAC) THEN SIMP_TAC[INSERT_AC]);;
+
+let ORTHOGONAL_TO_ORTHOGONAL_2D = prove
+ (`!x y z:real^2.
+     ~(x = vec 0) /\ orthogonal x y /\ orthogonal x z
+     ==> collinear {vec 0,y,z}`,
+  REWRITE_TAC[orthogonal; GSYM DOT_CAUCHY_SCHWARZ_EQUAL; GSYM DOT_EQ_0] THEN
+  REWRITE_TAC[DOT_2] THEN CONV_TAC REAL_RING);;
+
+let COLLINEAR_3_2D = prove
+ (`!x y z:real^2. collinear{x,y,z} <=>
+                  (z$1 - x$1) * (y$2 - x$2) = (y$1 - x$1) * (z$2 - x$2)`,
+  ONCE_REWRITE_TAC[COLLINEAR_3] THEN
+  REWRITE_TAC[GSYM DOT_CAUCHY_SCHWARZ_EQUAL] THEN
+  REWRITE_TAC[DOT_2; VECTOR_SUB_COMPONENT] THEN CONV_TAC REAL_RING);;
+
+let COLLINEAR_3_DOT_MULTIPLES = prove
+ (`!a b c:real^N.
+        collinear {a,b,c} <=>
+        ((b - a) dot (b - a)) % (c - a) = ((c - a) dot (b - a)) % (b - a)`,
+  REWRITE_TAC[VECTOR_SUB_RZERO] THEN
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `b:real^N = a` THENL
+   [ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC; DOT_RZERO; VECTOR_MUL_LZERO;
+                    VECTOR_SUB_REFL];
+    ONCE_REWRITE_TAC[COLLINEAR_3] THEN
+    POP_ASSUM MP_TAC THEN ONCE_REWRITE_TAC[GSYM VECTOR_SUB_EQ] THEN
+    REWRITE_TAC[GSYM DOT_CAUCHY_SCHWARZ_EQUAL; GSYM DOT_EQ_0] THEN
+    REWRITE_TAC[GSYM DOT_EQ_0; DOT_RSUB; DOT_LSUB; DOT_RMUL; DOT_LMUL] THEN
+    REWRITE_TAC[DOT_SYM] THEN CONV_TAC REAL_RING]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Between-ness.                                                             *)
+(* ------------------------------------------------------------------------- *)
+
+let between = new_definition
+ `between x (a,b) <=> dist(a,b) = dist(a,x) + dist(x,b)`;;
+
+let BETWEEN_REFL = prove
+ (`!a b. between a (a,b) /\ between b (a,b) /\ between a (a,a)`,
+  REWRITE_TAC[between] THEN NORM_ARITH_TAC);;
+
+let BETWEEN_REFL_EQ = prove
+ (`!a x. between x (a,a) <=> x = a`,
+  REWRITE_TAC[between] THEN NORM_ARITH_TAC);;
+
+let BETWEEN_SYM = prove
+ (`!a b x. between x (a,b) <=> between x (b,a)`,
+  REWRITE_TAC[between] THEN NORM_ARITH_TAC);;
+
+let BETWEEN_ANTISYM = prove
+ (`!a b c. between a (b,c) /\ between b (a,c) ==> a = b`,
+  REWRITE_TAC[between; DIST_SYM] THEN NORM_ARITH_TAC);;
+
+let BETWEEN_TRANS = prove
+ (`!a b c d. between a (b,c) /\ between d (a,c) ==> between d (b,c)`,
+  REWRITE_TAC[between; DIST_SYM] THEN NORM_ARITH_TAC);;
+
+let BETWEEN_TRANS_2 = prove
+ (`!a b c d. between a (b,c) /\ between d (a,b) ==> between a (c,d)`,
+  REWRITE_TAC[between; DIST_SYM] THEN NORM_ARITH_TAC);;
+
+let BETWEEN_NORM = prove
+ (`!a b x:real^N.
+     between x (a,b) <=> norm(x - a) % (b - x) = norm(b - x) % (x - a)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[between; DIST_TRIANGLE_EQ] THEN
+  REWRITE_TAC[NORM_SUB] THEN VECTOR_ARITH_TAC);;
+
+let BETWEEN_DOT = prove
+ (`!a b x:real^N.
+     between x (a,b) <=> (x - a) dot (b - x) = norm(x - a) * norm(b - x)`,
+  REWRITE_TAC[BETWEEN_NORM; NORM_CAUCHY_SCHWARZ_EQ]);;
+
+let BETWEEN_EXISTS_EXTENSION = prove
+ (`!a b x:real^N.
+        between b (a,x) /\ ~(b = a) ==> ?d. &0 <= d /\ x = b + d % (b - a)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[BETWEEN_NORM] THEN STRIP_TAC THEN
+  EXISTS_TAC `norm(x - b:real^N) / norm(b - a)` THEN
+  SIMP_TAC[REAL_LE_DIV; NORM_POS_LE] THEN FIRST_X_ASSUM
+   (MP_TAC o AP_TERM `(%) (inv(norm(b - a:real^N))):real^N->real^N`) THEN
+  ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_MUL_LINV; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+  VECTOR_ARITH_TAC);;
+
+let BETWEEN_IMP_COLLINEAR = prove
+ (`!a b x:real^N. between x (a,b) ==> collinear {a,x,b}`,
+  REPEAT GEN_TAC THEN MAP_EVERY
+   (fun t -> ASM_CASES_TAC t THEN
+             TRY(ASM_REWRITE_TAC[INSERT_AC; COLLINEAR_2] THEN NO_TAC))
+   [`x:real^N = a`; `x:real^N = b`; `a:real^N = b`] THEN
+  ONCE_REWRITE_TAC[COLLINEAR_3; BETWEEN_NORM] THEN
+  DISCH_TAC THEN REWRITE_TAC[COLLINEAR_LEMMA] THEN
+  REPEAT DISJ2_TAC THEN EXISTS_TAC `--(norm(b - x:real^N) / norm(x - a))` THEN
+  MATCH_MP_TAC VECTOR_MUL_LCANCEL_IMP THEN EXISTS_TAC `norm(x - a:real^N)` THEN
+  ASM_REWRITE_TAC[VECTOR_MUL_ASSOC; REAL_MUL_RNEG] THEN
+  ASM_SIMP_TAC[REAL_DIV_LMUL; NORM_EQ_0; VECTOR_SUB_EQ] THEN
+  VECTOR_ARITH_TAC);;
+
+let COLLINEAR_BETWEEN_CASES = prove
+ (`!a b c:real^N.
+        collinear {a,b,c} <=>
+        between a (b,c) \/ between b (c,a) \/ between c (a,b)`,
+  REPEAT STRIP_TAC THEN EQ_TAC THENL
+   [REWRITE_TAC[COLLINEAR_3_EXPAND] THEN
+    ASM_CASES_TAC `c:real^N = a` THEN ASM_REWRITE_TAC[BETWEEN_REFL] THEN
+    STRIP_TAC THEN ASM_REWRITE_TAC[between; dist] THEN
+    REWRITE_TAC[VECTOR_ARITH `(u % a + (&1 - u) % c) - c = --u % (c - a)`;
+      VECTOR_ARITH `(u % a + (&1 - u) % c) - a = (&1 - u) % (c - a)`;
+      VECTOR_ARITH `c - (u % a + (&1 - u) % c) = u % (c - a)`;
+      VECTOR_ARITH `a - (u % a + (&1 - u) % c) = (u - &1) % (c - a)`] THEN
+    REWRITE_TAC[NORM_MUL] THEN
+    SUBST1_TAC(NORM_ARITH `norm(a - c:real^N) = norm(c - a)`) THEN
+    REWRITE_TAC[REAL_ARITH `a * c + c = (a + &1) * c`; GSYM REAL_ADD_RDISTRIB;
+                REAL_ARITH `c + a * c = (a + &1) * c`] THEN
+    ASM_REWRITE_TAC[REAL_EQ_MUL_RCANCEL;
+                    REAL_RING `n = x * n <=> n = &0 \/ x = &1`] THEN
+    ASM_REWRITE_TAC[NORM_EQ_0; VECTOR_SUB_EQ] THEN REAL_ARITH_TAC;
+    DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN (MP_TAC o MATCH_MP
+      BETWEEN_IMP_COLLINEAR)) THEN
+    REWRITE_TAC[INSERT_AC]]);;
+
+let COLLINEAR_DIST_BETWEEN = prove
+ (`!a b x. collinear {x,a,b} /\
+           dist(x,a) <= dist(a,b) /\ dist(x,b) <= dist(a,b)
+           ==> between x (a,b)`,
+  SIMP_TAC[COLLINEAR_BETWEEN_CASES; between; DIST_SYM] THEN NORM_ARITH_TAC);;
+
+let BETWEEN_COLLINEAR_DIST_EQ = prove
+ (`!a b x:real^N.
+        between x (a,b) <=>
+        collinear {a, x, b} /\
+        dist(x,a) <= dist(a,b) /\ dist(x,b) <= dist(a,b)`,
+  REPEAT GEN_TAC THEN EQ_TAC THENL
+   [SIMP_TAC[BETWEEN_IMP_COLLINEAR] THEN REWRITE_TAC[between] THEN
+    NORM_ARITH_TAC;
+    MESON_TAC[COLLINEAR_DIST_BETWEEN; INSERT_AC]]);;
+
+let COLLINEAR_1 = prove
+ (`!s:real^1->bool. collinear s`,
+  GEN_TAC THEN MATCH_MP_TAC COLLINEAR_SUBSET THEN
+  EXISTS_TAC `(vec 0:real^1) INSERT (vec 1) INSERT s` THEN
+  CONJ_TAC THENL [ALL_TAC; SET_TAC[]] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) COLLINEAR_TRIPLES o snd) THEN
+  REWRITE_TAC[VEC_EQ; ARITH_EQ] THEN DISCH_THEN SUBST1_TAC THEN
+  REWRITE_TAC[COLLINEAR_BETWEEN_CASES] THEN
+  REWRITE_TAC[between; DIST_REAL; GSYM drop; DROP_VEC; REAL_ABS_NUM] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Midpoint between two points.                                              *)
+(* ------------------------------------------------------------------------- *)
+
+let midpoint = new_definition
+ `midpoint(a,b) = inv(&2) % (a + b)`;;
+
+let MIDPOINT_REFL = prove
+ (`!x. midpoint(x,x) = x`,
+  REWRITE_TAC[midpoint] THEN VECTOR_ARITH_TAC);;
+
+let MIDPOINT_SYM = prove
+ (`!a b. midpoint(a,b) = midpoint(b,a)`,
+  REWRITE_TAC[midpoint; VECTOR_ADD_SYM]);;
+
+let DIST_MIDPOINT = prove
+ (`!a b. dist(a,midpoint(a,b)) = dist(a,b) / &2 /\
+         dist(b,midpoint(a,b)) = dist(a,b) / &2 /\
+         dist(midpoint(a,b),a) = dist(a,b) / &2 /\
+         dist(midpoint(a,b),b) = dist(a,b) / &2`,
+  REWRITE_TAC[midpoint] THEN NORM_ARITH_TAC);;
+
+let MIDPOINT_EQ_ENDPOINT = prove
+ (`!a b. (midpoint(a,b) = a <=> a = b) /\
+         (midpoint(a,b) = b <=> a = b) /\
+         (a = midpoint(a,b) <=> a = b) /\
+         (b = midpoint(a,b) <=> a = b)`,
+  REWRITE_TAC[midpoint] THEN NORM_ARITH_TAC);;
+
+let BETWEEN_MIDPOINT = prove
+ (`!a b. between (midpoint(a,b)) (a,b) /\ between (midpoint(a,b)) (b,a)`,
+  REWRITE_TAC[between; midpoint] THEN NORM_ARITH_TAC);;
+
+let MIDPOINT_LINEAR_IMAGE = prove
+ (`!f a b. linear f ==> midpoint(f a,f b) = f(midpoint(a,b))`,
+  SIMP_TAC[midpoint; LINEAR_ADD; LINEAR_CMUL]);;
+
+let COLLINEAR_MIDPOINT = prove
+ (`!a b. collinear{a,midpoint(a,b),b}`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[COLLINEAR_3_EXPAND; midpoint] THEN
+  DISJ2_TAC THEN EXISTS_TAC `&1 / &2` THEN VECTOR_ARITH_TAC);;
+
+let MIDPOINT_COLLINEAR = prove
+ (`!a b c:real^N.
+        ~(a = c)
+        ==> (b = midpoint(a,c) <=> collinear{a,b,c} /\ dist(a,b) = dist(b,c))`,
+  REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC(TAUT `(a ==> b) /\ (b ==> (a <=> c)) ==> (a <=> b /\ c)`) THEN
+  SIMP_TAC[COLLINEAR_MIDPOINT] THEN ASM_REWRITE_TAC[COLLINEAR_3_EXPAND] THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[midpoint; dist] THEN
+  REWRITE_TAC
+   [VECTOR_ARITH `a - (u % a + (&1 - u) % c) = (&1 - u) % (a - c)`;
+    VECTOR_ARITH `(u % a + (&1 - u) % c) - c = u % (a - c)`;
+    VECTOR_ARITH `u % a + (&1 - u) % c = inv (&2) % (a + c) <=>
+                  (u - &1 / &2) % (a - c) = vec 0`] THEN
+  ASM_SIMP_TAC[NORM_MUL; REAL_EQ_MUL_RCANCEL; NORM_EQ_0; VECTOR_SUB_EQ;
+               VECTOR_MUL_EQ_0] THEN
+  REAL_ARITH_TAC);;
+
+let MIDPOINT_BETWEEN = prove
+ (`!a b c:real^N.
+        b = midpoint (a,c) <=> between b (a,c) /\ dist (a,b) = dist (b,c)`,
+  REPEAT GEN_TAC THEN ASM_CASES_TAC `a:real^N = c` THENL
+   [ASM_SIMP_TAC[BETWEEN_REFL_EQ; MIDPOINT_REFL; DIST_SYM]; ALL_TAC] THEN
+  EQ_TAC THEN SIMP_TAC[BETWEEN_MIDPOINT; DIST_MIDPOINT] THEN
+  ASM_MESON_TAC[MIDPOINT_COLLINEAR; BETWEEN_IMP_COLLINEAR]);;
+
+(* ------------------------------------------------------------------------- *)
+(* General "one way" lemma for properties preserved by injective map.        *)
+(* ------------------------------------------------------------------------- *)
+
+let WLOG_LINEAR_INJECTIVE_IMAGE_2 = prove
+ (`!P Q. (!f s. P s /\ linear f ==> Q(IMAGE f s)) /\
+         (!g t. Q t /\ linear g ==> P(IMAGE g t))
+         ==> !f:real^M->real^N.
+                linear f /\ (!x y. f x = f y ==> x = y)
+                ==> !s. Q(IMAGE f s) <=> P s`,
+  REPEAT STRIP_TAC THEN EQ_TAC THEN ASM_SIMP_TAC[] THEN DISCH_TAC THEN
+  MP_TAC(ISPEC `f:real^M->real^N` LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+  ASM_REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN
+  DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^M` STRIP_ASSUME_TAC) THEN
+  FIRST_X_ASSUM(MP_TAC o SPECL
+   [`g:real^N->real^M`; `IMAGE (f:real^M->real^N) s`]) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID]);;
+
+let WLOG_LINEAR_INJECTIVE_IMAGE_2_ALT = prove
+ (`!P Q f s. (!h u. P u /\ linear h ==> Q(IMAGE h u)) /\
+             (!g t. Q t /\ linear g ==> P(IMAGE g t)) /\
+             linear f /\ (!x y. f x = f y ==> x = y)
+             ==> (Q(IMAGE f s) <=> P s)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+     WLOG_LINEAR_INJECTIVE_IMAGE_2) THEN
+  ASM_REWRITE_TAC[]);;
+
+let WLOG_LINEAR_INJECTIVE_IMAGE = prove
+ (`!P. (!f s. P s /\ linear f ==> P(IMAGE f s))
+       ==> !f:real^N->real^N. linear f /\ (!x y. f x = f y ==> x = y)
+                              ==> !s. P(IMAGE f s) <=> P s`,
+  GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC WLOG_LINEAR_INJECTIVE_IMAGE_2 THEN
+  ASM_REWRITE_TAC[]);;
+
+let WLOG_LINEAR_INJECTIVE_IMAGE_ALT = prove
+ (`!P f s. (!g t. P t /\ linear g ==> P(IMAGE g t)) /\
+           linear f /\ (!x y. f x = f y ==> x = y)
+           ==> (P(IMAGE f s) <=> P s)`,
+  REPEAT GEN_TAC THEN STRIP_TAC THEN
+  MATCH_MP_TAC(REWRITE_RULE[RIGHT_IMP_FORALL_THM; IMP_IMP]
+     WLOG_LINEAR_INJECTIVE_IMAGE) THEN
+  ASM_REWRITE_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Inference rule to apply it conveniently.                                  *)
+(*                                                                           *)
+(*   |- !f s. P s /\ linear f ==> P(IMAGE f s)  [or /\ commuted]             *)
+(* ---------------------------------------------------------------           *)
+(*   |- !f s. linear f /\ (!x y. f x = f y ==> x = y)                        *)
+(*            ==> (Q(IMAGE f s) <=> P s)                                     *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_INVARIANT_RULE th =
+  let [f;s] = fst(strip_forall(concl th)) in
+  let (rm,rn) = dest_fun_ty (type_of f) in
+  let m = last(snd(dest_type rm)) and n = last(snd(dest_type rn)) in
+  let th' = INST_TYPE [m,n; n,m] th in
+  let th0 = CONJ th th' in
+  let th1 = try MATCH_MP WLOG_LINEAR_INJECTIVE_IMAGE_2 th0
+            with Failure _ ->
+                MATCH_MP WLOG_LINEAR_INJECTIVE_IMAGE_2
+            (GEN_REWRITE_RULE (BINOP_CONV o ONCE_DEPTH_CONV) [CONJ_SYM] th0) in
+  GEN_REWRITE_RULE BINDER_CONV [RIGHT_IMP_FORALL_THM] th1;;
+
+(* ------------------------------------------------------------------------- *)
+(* Immediate application.                                                    *)
+(* ------------------------------------------------------------------------- *)
+
+let SUBSPACE_LINEAR_IMAGE_EQ = prove
+ (`!f s. linear f /\ (!x y. f x = f y ==> x = y)
+         ==> (subspace (IMAGE f s) <=> subspace s)`,
+  MATCH_ACCEPT_TAC(LINEAR_INVARIANT_RULE SUBSPACE_LINEAR_IMAGE));;
+
+(* ------------------------------------------------------------------------- *)
+(* Storage of useful "invariance under linear map / translation" theorems.   *)
+(* ------------------------------------------------------------------------- *)
+
+let invariant_under_linear = ref([]:thm list);;
+
+let invariant_under_translation = ref([]:thm list);;
+
+let scaling_theorems = ref([]:thm list);;
+
+(* ------------------------------------------------------------------------- *)
+(* Scaling theorems and derivation from linear invariance.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let LINEAR_SCALING = prove
+ (`!c. linear(\x:real^N. c % x)`,
+  REWRITE_TAC[linear] THEN VECTOR_ARITH_TAC);;
+
+let INJECTIVE_SCALING = prove
+ (`!c. (!x y:real^N. c % x = c % y ==> x = y) <=> ~(c = &0)`,
+  GEN_TAC THEN REWRITE_TAC[VECTOR_MUL_LCANCEL] THEN
+  ASM_CASES_TAC `c:real = &0` THEN ASM_REWRITE_TAC[] THEN
+  DISCH_THEN(MP_TAC o SPECL [`vec 0:real^N`; `vec 1:real^N`]) THEN
+  REWRITE_TAC[VEC_EQ; ARITH]);;
+
+let SURJECTIVE_SCALING = prove
+ (`!c. (!y:real^N. ?x. c % x = y) <=> ~(c = &0)`,
+  ASM_SIMP_TAC[LINEAR_SURJECTIVE_IFF_INJECTIVE; LINEAR_SCALING] THEN
+  REWRITE_TAC[INJECTIVE_SCALING]);;
+
+let SCALING_INVARIANT =
+  let pths = (CONJUNCTS o UNDISCH o prove)
+   (`&0 < c
+     ==> linear(\x:real^N. c % x) /\
+         (!x y:real^N. c % x = c % y ==> x = y) /\
+         (!y:real^N. ?x. c % x = y)`,
+    SIMP_TAC[REAL_LT_IMP_NZ; LINEAR_SCALING;
+             INJECTIVE_SCALING; SURJECTIVE_SCALING])
+  and sc_tm = `\x:real^N. c % x`
+  and sa_tm = `&0:real < c`
+  and c_tm = `c:real` in
+  fun th ->
+    let ith = BETA_RULE(ISPEC sc_tm th) in
+    let avs,bod = strip_forall(concl ith) in
+    let cjs = conjuncts(lhand bod) in
+    let cths = map (fun t -> find(fun th -> aconv (concl th) t) pths) cjs in
+    let oth = MP (SPECL avs ith) (end_itlist CONJ cths) in
+    GEN c_tm (DISCH sa_tm (GENL avs oth));;
+
+let scaling_theorems = ref([]:thm list);;
+
+(* ------------------------------------------------------------------------- *)
+(* Augmentation of the lists. The "add_linear_invariants" also updates       *)
+(* the scaling theorems automatically, so only a few of those will need      *)
+(* to be added explicitly.                                                   *)
+(* ------------------------------------------------------------------------- *)
+
+let add_scaling_theorems thl =
+  (scaling_theorems := (!scaling_theorems) @ thl);;
+
+let add_linear_invariants thl =
+  ignore(mapfilter (fun th -> add_scaling_theorems[SCALING_INVARIANT th]) thl);
+  (invariant_under_linear := (!invariant_under_linear) @ thl);;
+
+let add_translation_invariants thl =
+ (invariant_under_translation := (!invariant_under_translation) @ thl);;
+
+(* ------------------------------------------------------------------------- *)
+(* Start with some basic set equivalences.                                   *)
+(* We give them all an injectivity hypothesis even if it's not necessary.    *)
+(* For just the intersection theorem we add surjectivity (more manageable    *)
+(* than assuming that the set isn't empty).                                  *)
+(* ------------------------------------------------------------------------- *)
+
+let th_sets = prove
+ (`!f. (!x y. f x = f y ==> x = y)
+       ==> (if p then f x else f y) = f(if p then x else y) /\
+           (if p then IMAGE f s else IMAGE f t) =
+           IMAGE f (if p then s else t) /\
+           (f x) INSERT (IMAGE f s) = IMAGE f (x INSERT s) /\
+           (IMAGE f s) DELETE (f x) = IMAGE f (s DELETE x) /\
+           (IMAGE f s) INTER (IMAGE f t) = IMAGE f (s INTER t) /\
+           (IMAGE f s) UNION (IMAGE f t) = IMAGE f (s UNION t) /\
+           UNIONS(IMAGE (IMAGE f) u) = IMAGE f (UNIONS u) /\
+           (IMAGE f s) DIFF (IMAGE f t) = IMAGE f (s DIFF t) /\
+           (IMAGE f s (f x) <=> s x) /\
+           ((f x) IN (IMAGE f s) <=> x IN s) /\
+           ((f o xs) (n:num) = f(xs n)) /\
+           ((f o pt) (tt:real^1) = f(pt tt)) /\
+           (DISJOINT (IMAGE f s) (IMAGE f t) <=> DISJOINT s t) /\
+           ((IMAGE f s) SUBSET (IMAGE f t) <=> s SUBSET t) /\
+           ((IMAGE f s) PSUBSET (IMAGE f t) <=> s PSUBSET t) /\
+           (IMAGE f s = IMAGE f t <=> s = t) /\
+           ((IMAGE f s) HAS_SIZE n <=> s HAS_SIZE n) /\
+           (FINITE(IMAGE f s) <=> FINITE s) /\
+           (INFINITE(IMAGE f s) <=> INFINITE s)`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[IMAGE_UNIONS] THEN
+  REWRITE_TAC[o_THM; MESON[IN] `IMAGE f s y <=> y IN IMAGE f s`] THEN
+  REPLICATE_TAC 2 (CONJ_TAC THENL [MESON_TAC[]; ALL_TAC]) THEN
+  REWRITE_TAC[INFINITE; TAUT `(~p <=> ~q) <=> (p <=> q)`] THEN
+  REPLICATE_TAC 11 (CONJ_TAC THENL [ASM SET_TAC[]; ALL_TAC]) THEN
+  REWRITE_TAC[HAS_SIZE] THEN
+  ASM_MESON_TAC[FINITE_IMAGE_INJ_EQ; CARD_IMAGE_INJ]) in
+let f = `f:real^M->real^N`
+and imf = `IMAGE (f:real^M->real^N)`
+and a = `a:real^N`
+and ima = `IMAGE (\x:real^N. a + x)`
+and vth = VECTOR_ARITH `!x y. a + x:real^N = a + y ==> x = y` in
+let th1 = UNDISCH(ISPEC f th_sets)
+and th1' = UNDISCH
+ (GEN_REWRITE_RULE LAND_CONV [INJECTIVE_IMAGE] (ISPEC imf th_sets))
+and th2 = MATCH_MP th_sets vth
+and th2' = MATCH_MP
+  (BETA_RULE(GEN_REWRITE_RULE LAND_CONV [INJECTIVE_IMAGE] (ISPEC ima th_sets)))
+  vth in
+let fn a th = GENL (a::subtract (frees(concl th)) [a]) th in
+add_linear_invariants(map (fn f o DISCH_ALL) (CONJUNCTS th1 @ CONJUNCTS th1')),
+add_translation_invariants(map (fn a) (CONJUNCTS th2 @ CONJUNCTS th2'));;
+
+let th_set = prove
+ (`!f:A->B s. (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y)
+              ==> INTERS (IMAGE (IMAGE f) s) = IMAGE f (INTERS s)`,
+  REWRITE_TAC[INTERS_IMAGE] THEN SET_TAC[]) in
+let th_vec = prove
+ (`!a:real^N s.
+    INTERS (IMAGE (IMAGE (\x. a + x)) s) = IMAGE (\x. a + x) (INTERS s)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC th_set THEN
+  REWRITE_TAC[VECTOR_ARITH `a + x:real^N = a + y <=> x = y`] THEN
+  REWRITE_TAC[VECTOR_ARITH `a + x:real^N = y <=> x = y - a`; EXISTS_REFL]) in
+add_linear_invariants [th_set],add_translation_invariants[th_vec];;
+
+(* ------------------------------------------------------------------------- *)
+(* Now add arithmetical equivalences.                                        *)
+(* ------------------------------------------------------------------------- *)
+
+let PRESERVES_NORM_PRESERVES_DOT = prove
+ (`!f:real^M->real^N x y.
+     linear f /\ (!x. norm(f x) = norm x)
+     ==> (f x) dot (f y) = x dot y`,
+  REWRITE_TAC[NORM_EQ] THEN REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o SPEC `x + y:real^M`) THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP LINEAR_ADD th]) THEN
+  ASM_REWRITE_TAC[DOT_LADD; DOT_RADD] THEN
+  REWRITE_TAC[DOT_SYM] THEN REAL_ARITH_TAC);;
+
+let PRESERVES_NORM_INJECTIVE = prove
+ (`!f:real^M->real^N.
+     linear f /\ (!x. norm(f x) = norm x)
+     ==> !x y. f x = f y ==> x = y`,
+  SIMP_TAC[LINEAR_INJECTIVE_0; GSYM NORM_EQ_0]);;
+
+let ORTHOGONAL_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N x y.
+     linear f /\ (!x. norm(f x) = norm x)
+     ==> (orthogonal (f x) (f y) <=> orthogonal x y)`,
+  SIMP_TAC[orthogonal; PRESERVES_NORM_PRESERVES_DOT]);;
+
+add_linear_invariants
+ [GSYM LINEAR_ADD;
+  GSYM LINEAR_CMUL;
+  GSYM LINEAR_SUB;
+  GSYM LINEAR_NEG;
+  MIDPOINT_LINEAR_IMAGE;
+  MESON[] `!f:real^M->real^N x.
+                (!x. norm(f x) = norm x) ==> norm(f x) = norm x`;
+  PRESERVES_NORM_PRESERVES_DOT;
+  MESON[dist; LINEAR_SUB]
+    `!f:real^M->real^N x y.
+        linear f /\ (!x. norm(f x) = norm x)
+        ==> dist(f x,f y) = dist(x,y)`;
+  MESON[] `!f:real^M->real^N x y.
+                (!x y. f x = f y ==> x = y) ==> (f x = f y <=> x = y)`;
+  SUBSPACE_LINEAR_IMAGE_EQ;
+  ORTHOGONAL_LINEAR_IMAGE_EQ;
+  SPAN_LINEAR_IMAGE;
+  DEPENDENT_LINEAR_IMAGE_EQ;
+  INDEPENDENT_LINEAR_IMAGE_EQ;
+  DIM_INJECTIVE_LINEAR_IMAGE];;
+
+add_translation_invariants
+ [VECTOR_ARITH `!a x y. a + x:real^N = a + y <=> x = y`;
+  NORM_ARITH `!a x y. dist(a + x,a + y) = dist(x,y)`;
+  VECTOR_ARITH `!a x y. &1 / &2 % ((a + x) + (a + y)) = a + &1 / &2 % (x + y)`;
+  VECTOR_ARITH `!a x y. inv(&2) % ((a + x) + (a + y)) = a + inv(&2) % (x + y)`;
+  VECTOR_ARITH `!a x y. (a + x) - (a + y):real^N = x - y`;
+  (EQT_ELIM o (REWRITE_CONV[midpoint] THENC(EQT_INTRO o NORM_ARITH)))
+               `!a x y. midpoint(a + x,a + y) = a + midpoint(x,y)`;
+  (EQT_ELIM o (REWRITE_CONV[between] THENC(EQT_INTRO o NORM_ARITH)))
+               `!a x y z. between (a + x) (a + y,a + z) <=> between x (y,z)`];;
+
+let th = prove
+ (`!a s b c:real^N. (a + b) + c IN IMAGE (\x. a + x) s <=> (b + c) IN s`,
+  REWRITE_TAC[IN_IMAGE; VECTOR_ARITH
+    `(a + b) + c:real^N = a + x <=> x = b + c`] THEN
+  MESON_TAC[]) in
+add_translation_invariants [th];;
+
+(* ------------------------------------------------------------------------- *)
+(* A few for lists.                                                          *)
+(* ------------------------------------------------------------------------- *)
+
+let MEM_TRANSLATION = prove
+ (`!a:real^N x l. MEM (a + x) (MAP (\x. a + x) l) <=> MEM x l`,
+  REWRITE_TAC[MEM_MAP; VECTOR_ARITH `a + x:real^N = a + y <=> x = y`] THEN
+  MESON_TAC[]);;
+
+add_translation_invariants [MEM_TRANSLATION];;
+
+let MEM_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N x l.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (MEM (f x) (MAP f l) <=> MEM x l)`,
+  REWRITE_TAC[MEM_MAP] THEN MESON_TAC[]);;
+
+add_linear_invariants [MEM_LINEAR_IMAGE];;
+
+let LENGTH_TRANSLATION = prove
+ (`!a:real^N l. LENGTH(MAP (\x. a + x) l) = LENGTH l`,
+  REWRITE_TAC[LENGTH_MAP]) in
+add_translation_invariants [LENGTH_TRANSLATION];;
+
+let LENGTH_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N l. linear f ==> LENGTH(MAP f l) = LENGTH l`,
+  REWRITE_TAC[LENGTH_MAP]) in
+add_linear_invariants [LENGTH_LINEAR_IMAGE];;
+
+let CONS_TRANSLATION = prove
+ (`!a:real^N h t.
+     CONS ((\x. a + x) h) (MAP (\x. a + x) t) = MAP (\x. a + x) (CONS h t)`,
+  REWRITE_TAC[MAP]) in
+add_translation_invariants [CONS_TRANSLATION];;
+
+let CONS_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N h t.
+     linear f ==> CONS (f h) (MAP f t) = MAP f (CONS h t)`,
+  REWRITE_TAC[MAP]) in
+add_linear_invariants [CONS_LINEAR_IMAGE];;
+
+let APPEND_TRANSLATION = prove
+ (`!a:real^N l1 l2.
+     APPEND (MAP (\x. a + x) l1) (MAP (\x. a + x) l2) =
+     MAP (\x. a + x) (APPEND l1 l2)`,
+  REWRITE_TAC[MAP_APPEND]) in
+add_translation_invariants [APPEND_TRANSLATION];;
+
+let APPEND_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N l1 l2.
+     linear f ==> APPEND (MAP f l1) (MAP f l2) = MAP f (APPEND l1 l2)`,
+  REWRITE_TAC[MAP_APPEND]) in
+add_linear_invariants [APPEND_LINEAR_IMAGE];;
+
+let REVERSE_TRANSLATION = prove
+ (`!a:real^N l. REVERSE(MAP (\x. a + x) l) = MAP (\x. a + x) (REVERSE l)`,
+  REWRITE_TAC[MAP_REVERSE]) in
+add_translation_invariants [REVERSE_TRANSLATION];;
+
+let REVERSE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N l. linear f ==> REVERSE(MAP f l) = MAP f (REVERSE l)`,
+  REWRITE_TAC[MAP_REVERSE]) in
+add_linear_invariants [REVERSE_LINEAR_IMAGE];;
+
+(* ------------------------------------------------------------------------- *)
+(* A few scaling theorems that don't come from invariance theorems. Most are *)
+(* artificially weak with 0 < c hypotheses, so we don't bind them to names.  *)
+(* ------------------------------------------------------------------------- *)
+
+let DOT_SCALING = prove
+ (`!c. &0 < c ==> !x y. (c % x) dot (c % y) = c pow 2 * (x dot y)`,
+  REWRITE_TAC[DOT_LMUL; DOT_RMUL] THEN REAL_ARITH_TAC) in
+add_scaling_theorems [DOT_SCALING];;
+
+let DIST_SCALING = prove
+ (`!c. &0 < c ==> !x y. dist(c % x,c % y) = c * dist(x,y)`,
+  SIMP_TAC[DIST_MUL; REAL_ARITH `&0 < c ==> abs c = c`]) in
+add_scaling_theorems [DIST_SCALING];;
+
+let ORTHOGONAL_SCALING = prove
+ (`!c. &0 < c ==> !x y. orthogonal (c % x) (c % y) <=> orthogonal x y`,
+  REWRITE_TAC[orthogonal; DOT_LMUL; DOT_RMUL] THEN CONV_TAC REAL_FIELD) in
+add_scaling_theorems [ORTHOGONAL_SCALING];;
+
+let NORM_SCALING = prove
+ (`!c. &0 < c ==> !x. norm(c % x) = c * norm x`,
+  SIMP_TAC[NORM_MUL; REAL_ARITH `&0 < c ==> abs c = c`]) in
+add_scaling_theorems [NORM_SCALING];;
+
+add_scaling_theorems
+  [REAL_ARITH `!c. &0 < c ==> !a b. a * c * b = c * a * b`;
+   REAL_ARITH `!c. &0 < c ==> !a b. c * a + c * b = c * (a + b)`;
+   REAL_ARITH `!c. &0 < c ==> !a b. c * a - c * b = c * (a - b)`;
+   REAL_FIELD `!c. &0 < c ==> !a b. c * a = c * b <=> a = b`;
+   MESON[REAL_LT_LMUL_EQ] `!c. &0 < c ==> !a b. c * a < c * b <=> a < b`;
+   MESON[REAL_LE_LMUL_EQ] `!c. &0 < c ==> !a b. c * a <= c * b <=> a <= b`;
+   MESON[REAL_LT_LMUL_EQ; real_gt]
+     `!c. &0 < c ==> !a b. c * a > c * b <=> a > b`;
+   MESON[REAL_LE_LMUL_EQ; real_ge]
+     `!c. &0 < c ==> !a b. c * a >= c * b <=> a >= b`;
+   MESON[REAL_POW_MUL]
+    `!c. &0 < c ==> !a n. (c * a) pow n = c pow n * a pow n`;
+   REAL_ARITH `!c. &0 < c ==> !a b n. a * c pow n * b = c pow n * a * b`;
+   REAL_ARITH
+    `!c. &0 < c ==> !a b n. c pow n * a + c pow n * b = c pow n * (a + b)`;
+   REAL_ARITH
+    `!c. &0 < c ==> !a b n. c pow n * a - c pow n * b = c pow n * (a - b)`;
+   MESON[REAL_POW_LT; REAL_EQ_LCANCEL_IMP; REAL_LT_IMP_NZ]
+    `!c. &0 < c ==> !a b n. c pow n * a = c pow n * b <=> a = b`;
+   MESON[REAL_LT_LMUL_EQ; REAL_POW_LT]
+     `!c. &0 < c ==> !a b n. c pow n * a < c pow n * b <=> a < b`;
+   MESON[REAL_LE_LMUL_EQ; REAL_POW_LT]
+     `!c. &0 < c ==> !a b n. c pow n * a <= c pow n * b <=> a <= b`;
+   MESON[REAL_LT_LMUL_EQ; real_gt; REAL_POW_LT]
+     `!c. &0 < c ==> !a b n. c pow n * a > c pow n * b <=> a > b`;
+   MESON[REAL_LE_LMUL_EQ; real_ge; REAL_POW_LT]
+     `!c. &0 < c ==> !a b n. c pow n * a >= c pow n * b <=> a >= b`];;
+
+(* ------------------------------------------------------------------------- *)
+(* Theorem deducing quantifier mappings from surjectivity.                   *)
+(* ------------------------------------------------------------------------- *)
+
+let QUANTIFY_SURJECTION_THM = prove
+ (`!f:A->B.
+        (!y. ?x. f x = y)
+        ==> ((!P. (!x. P x) <=> (!x. P (f x))) /\
+             (!P. (?x. P x) <=> (?x. P (f x))) /\
+             (!Q. (!s. Q s) <=> (!s. Q(IMAGE f s))) /\
+             (!Q. (?s. Q s) <=> (?s. Q(IMAGE f s)))) /\
+            (!P. {x | P x} = IMAGE f {x | P(f x)})`,
+  GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [SURJECTIVE_RIGHT_INVERSE] THEN
+  DISCH_THEN(X_CHOOSE_TAC `g:B->A`) THEN
+  SUBGOAL_THEN `!s. IMAGE (f:A->B) (IMAGE g s) = s` ASSUME_TAC THENL
+   [ASM SET_TAC[]; CONJ_TAC THENL [ASM MESON_TAC[]; ASM SET_TAC[]]]);;
+
+let QUANTIFY_SURJECTION_HIGHER_THM = prove
+ (`!f:A->B.
+        (!y. ?x. f x = y)
+        ==> ((!P. (!x. P x) <=> (!x. P (f x))) /\
+             (!P. (?x. P x) <=> (?x. P (f x))) /\
+             (!Q. (!s. Q s) <=> (!s. Q(IMAGE f s))) /\
+             (!Q. (?s. Q s) <=> (?s. Q(IMAGE f s))) /\
+             (!Q. (!s. Q s) <=> (!s. Q(IMAGE (IMAGE f) s))) /\
+             (!Q. (?s. Q s) <=> (?s. Q(IMAGE (IMAGE f) s))) /\
+             (!P. (!g:real^1->B. P g) <=> (!g. P(f o g))) /\
+             (!P. (?g:real^1->B. P g) <=> (?g. P(f o g))) /\
+             (!P. (!g:num->B. P g) <=> (!g. P(f o g))) /\
+             (!P. (?g:num->B. P g) <=> (?g. P(f o g))) /\
+             (!Q. (!l. Q l) <=> (!l. Q(MAP f l))) /\
+             (!Q. (?l. Q l) <=> (?l. Q(MAP f l)))) /\
+            ((!P. {x | P x} = IMAGE f {x | P(f x)}) /\
+             (!Q. {s | Q s} = IMAGE (IMAGE f) {s | Q(IMAGE f s)}) /\
+             (!R. {l | R l} = IMAGE (MAP f) {l | R(MAP f l)}))`,
+  GEN_TAC THEN DISCH_TAC THEN CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN
+  ASM_REWRITE_TAC[GSYM SURJECTIVE_FORALL_THM; GSYM SURJECTIVE_EXISTS_THM;
+            GSYM SURJECTIVE_IMAGE_THM; SURJECTIVE_IMAGE; SURJECTIVE_MAP] THEN
+  REWRITE_TAC[FUN_EQ_THM; o_THM; GSYM SKOLEM_THM] THEN ASM_MESON_TAC[]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Apply such quantifier and set expansions once per level at depth.         *)
+(* In the PARTIAL version, avoid expanding named variables in list.          *)
+(* ------------------------------------------------------------------------- *)
+
+let PARTIAL_EXPAND_QUANTS_CONV avoid th =
+  let ath,sth = CONJ_PAIR th in
+  let conv1 = GEN_REWRITE_CONV I [ath]
+  and conv2 = GEN_REWRITE_CONV I [sth] in
+  let conv1' tm =
+    let th = conv1 tm in
+    if mem (fst(dest_var(fst(dest_abs(rand tm))))) avoid
+    then failwith "Not going to expand this variable" else th in
+  let rec conv tm =
+   ((conv1' THENC BINDER_CONV conv) ORELSEC
+    (conv2 THENC
+     RAND_CONV(RAND_CONV(ABS_CONV(BINDER_CONV(LAND_CONV conv))))) ORELSEC
+    SUB_CONV conv) tm in
+  conv;;
+
+let EXPAND_QUANTS_CONV = PARTIAL_EXPAND_QUANTS_CONV [];;
diff --git a/Multivariate/wlog.ml b/Multivariate/wlog.ml
new file mode 100644 (file)
index 0000000..14c6104
--- /dev/null
@@ -0,0 +1,389 @@
+(* ========================================================================= *)
+(* Geometric "without loss of generality" tactics to pick convenient coords. *)
+(* ========================================================================= *)
+
+needs "Multivariate/determinants.ml";;
+needs "Multivariate/convex.ml";;
+
+(* ------------------------------------------------------------------------- *)
+(* Flyspeck definition of plane, and its invariance theorems.                *)
+(* ------------------------------------------------------------------------- *)
+
+let plane = new_definition
+  `plane x = (?u v w. ~(collinear {u,v,w}) /\ x = affine hull {u,v,w})`;;
+
+let PLANE_TRANSLATION_EQ = prove
+ (`!a:real^N s. plane(IMAGE (\x. a + x) s) <=> plane s`,
+  REWRITE_TAC[plane] THEN GEOM_TRANSLATE_TAC[]);;
+
+let PLANE_TRANSLATION = prove
+ (`!a:real^N s. plane s ==> plane(IMAGE (\x. a + x) s)`,
+  REWRITE_TAC[PLANE_TRANSLATION_EQ]);;
+
+add_translation_invariants [PLANE_TRANSLATION_EQ];;
+
+let PLANE_LINEAR_IMAGE_EQ = prove
+ (`!f:real^M->real^N p.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (plane(IMAGE f p) <=> plane p)`,
+  REPEAT STRIP_TAC THEN REWRITE_TAC[plane] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `?u. u IN IMAGE f (:real^M) /\
+        ?v. v IN IMAGE f (:real^M) /\
+            ?w. w IN IMAGE (f:real^M->real^N) (:real^M) /\
+                ~collinear {u, v, w} /\ IMAGE f p = affine hull {u, v, w}` THEN
+  CONJ_TAC THENL
+   [REWRITE_TAC[RIGHT_AND_EXISTS_THM; IN_IMAGE; IN_UNIV] THEN
+    REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN
+    EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
+    SUBGOAL_THEN `{u,v,w} SUBSET IMAGE (f:real^M->real^N) p` MP_TAC THENL
+     [ASM_REWRITE_TAC[HULL_SUBSET]; SET_TAC[]];
+    REWRITE_TAC[EXISTS_IN_IMAGE; IN_UNIV] THEN
+    REWRITE_TAC[SET_RULE `{f a,f b,f c} = IMAGE f {a,b,c}`] THEN
+    ASM_SIMP_TAC[AFFINE_HULL_LINEAR_IMAGE] THEN
+    REPEAT(AP_TERM_TAC THEN ABS_TAC) THEN BINOP_TAC THENL
+     [ASM_MESON_TAC[COLLINEAR_LINEAR_IMAGE_EQ]; ASM SET_TAC[]]]);;
+
+let PLANE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N p.
+        linear f /\ plane p /\ (!x y. f x = f y ==> x = y)
+        ==> plane(IMAGE f p)`,
+  MESON_TAC[PLANE_LINEAR_IMAGE_EQ]);;
+
+add_linear_invariants [PLANE_LINEAR_IMAGE_EQ];;
+
+(* ------------------------------------------------------------------------- *)
+(* Rotating and translating so a given plane in R^3 becomes {x | x$3 = &0}.  *)
+(* ------------------------------------------------------------------------- *)
+
+let ROTATION_PLANE_HORIZONTAL = prove
+ (`!s. plane s
+       ==>  ?a f. orthogonal_transformation f /\ det(matrix f) = &1 /\
+                  IMAGE f (IMAGE (\x. a + x) s) = {z:real^3 | z$3 = &0}`,
+  let lemma = prove
+   (`span {z:real^3 | z$3 = &0} = {z:real^3 | z$3 = &0}`,
+    REWRITE_TAC[SPAN_EQ_SELF; subspace; IN_ELIM_THM] THEN
+    SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; VEC_COMPONENT;
+             DIMINDEX_3; ARITH] THEN REAL_ARITH_TAC) in
+  REPEAT STRIP_TAC THEN
+  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [plane]) THEN
+  REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN
+  MAP_EVERY X_GEN_TAC [`a:real^3`; `b:real^3`; `c:real^3`] THEN
+  MAP_EVERY (fun t ->
+    ASM_CASES_TAC t THENL [ASM_REWRITE_TAC[COLLINEAR_2; INSERT_AC];
+                           ALL_TAC])
+   [`a:real^3 = b`; `a:real^3 = c`; `b:real^3 = c`] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC) THEN
+  ASM_SIMP_TAC[AFFINE_HULL_INSERT_SPAN; IN_INSERT; NOT_IN_EMPTY] THEN
+  EXISTS_TAC `--a:real^3` THEN
+  REWRITE_TAC[SET_RULE `IMAGE (\x:real^3. --a + x) {a + x | x | x IN s} =
+                        IMAGE (\x. --a + a + x) s`] THEN
+  REWRITE_TAC[VECTOR_ARITH `--a + a + x:real^3 = x`; IMAGE_ID] THEN
+  REWRITE_TAC[SET_RULE `{x - a:real^x | x = b \/ x = c} = {b - a,c - a}`] THEN
+  MP_TAC(ISPEC `span{b - a:real^3,c - a}`
+    ROTATION_LOWDIM_HORIZONTAL) THEN
+  REWRITE_TAC[DIMINDEX_3] THEN ANTS_TAC THENL
+   [MATCH_MP_TAC LET_TRANS THEN
+    EXISTS_TAC `CARD{b - a:real^3,c - a}` THEN
+    SIMP_TAC[DIM_SPAN; DIM_LE_CARD; FINITE_RULES] THEN
+    SIMP_TAC[CARD_CLAUSES; FINITE_RULES] THEN ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `f:real^3->real^3` THEN
+  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP ORTHOGONAL_TRANSFORMATION_LINEAR) THEN
+  ASM_SIMP_TAC[GSYM SPAN_LINEAR_IMAGE] THEN
+  GEN_REWRITE_TAC RAND_CONV [GSYM lemma] THEN
+  MATCH_MP_TAC DIM_EQ_SPAN THEN CONJ_TAC THENL
+   [ASM_MESON_TAC[IMAGE_SUBSET; SPAN_INC; SUBSET_TRANS]; ALL_TAC] THEN
+  MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `2` THEN CONJ_TAC THENL
+   [MP_TAC(ISPECL [`{z:real^3 | z$3 = &0}`; `(:real^3)`] DIM_EQ_SPAN) THEN
+    REWRITE_TAC[SUBSET_UNIV; DIM_UNIV; DIMINDEX_3; lemma] THEN
+    MATCH_MP_TAC(TAUT `~r /\ (~p ==> q) ==> (q ==> r) ==> p`) THEN
+    REWRITE_TAC[ARITH_RULE `~(x <= 2) <=> 3 <= x`] THEN
+    REWRITE_TAC[EXTENSION; SPAN_UNIV; IN_ELIM_THM] THEN
+    DISCH_THEN(MP_TAC o SPEC `vector[&0;&0;&1]:real^3`) THEN
+    REWRITE_TAC[IN_UNIV; VECTOR_3] THEN REAL_ARITH_TAC;
+    ALL_TAC] THEN
+  MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `dim {b - a:real^3,c - a}` THEN
+  CONJ_TAC THENL
+   [ALL_TAC; ASM_MESON_TAC[LE_REFL; DIM_INJECTIVE_LINEAR_IMAGE;
+             ORTHOGONAL_TRANSFORMATION_INJECTIVE]] THEN
+  MP_TAC(ISPEC `{b - a:real^3,c - a}` INDEPENDENT_BOUND_GENERAL) THEN
+  SIMP_TAC[CARD_CLAUSES; FINITE_RULES; IN_SING; NOT_IN_EMPTY] THEN
+  ASM_REWRITE_TAC[VECTOR_ARITH `b - a:real^3 = c - a <=> b = c`; ARITH] THEN
+  DISCH_THEN MATCH_MP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE (RAND_CONV o RAND_CONV)
+    [SET_RULE `{a,b,c} = {b,a,c}`]) THEN
+  REWRITE_TAC[] THEN ONCE_REWRITE_TAC[COLLINEAR_3] THEN
+  REWRITE_TAC[independent; CONTRAPOS_THM; dependent] THEN
+  REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; RIGHT_OR_DISTRIB] THEN
+  REWRITE_TAC[EXISTS_OR_THM; UNWIND_THM2] THEN
+  ASM_SIMP_TAC[SET_RULE `~(a = b) ==> {a,b} DELETE b = {a}`;
+               SET_RULE `~(a = b) ==> {a,b} DELETE a = {b}`;
+               VECTOR_ARITH `b - a:real^3 = c - a <=> b = c`] THEN
+  REWRITE_TAC[SPAN_BREAKDOWN_EQ; SPAN_EMPTY; IN_SING] THEN
+  ONCE_REWRITE_TAC[VECTOR_SUB_EQ] THEN MESON_TAC[COLLINEAR_LEMMA; INSERT_AC]);;
+
+let ROTATION_HORIZONTAL_PLANE = prove
+ (`!p. plane p
+       ==>  ?a f. orthogonal_transformation f /\ det(matrix f) = &1 /\
+                  IMAGE (\x. a + x) (IMAGE f {z:real^3 | z$3 = &0}) = p`,
+  REPEAT STRIP_TAC THEN
+  FIRST_X_ASSUM(MP_TAC o MATCH_MP ROTATION_PLANE_HORIZONTAL) THEN
+  DISCH_THEN(X_CHOOSE_THEN `a:real^3`
+   (X_CHOOSE_THEN `f:real^3->real^3` STRIP_ASSUME_TAC)) THEN
+  FIRST_ASSUM(X_CHOOSE_THEN `g:real^3->real^3` STRIP_ASSUME_TAC o MATCH_MP
+    ORTHOGONAL_TRANSFORMATION_INVERSE) THEN
+  MAP_EVERY EXISTS_TAC [`--a:real^3`; `g:real^3->real^3`] THEN
+  FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_o; o_DEF; IMAGE_ID;
+                  VECTOR_ARITH `--a + a + x:real^3 = x`] THEN
+  MATCH_MP_TAC(REAL_RING `!f. f * g = &1 /\ f = &1 ==> g = &1`) THEN
+  EXISTS_TAC `det(matrix(f:real^3->real^3))` THEN
+  REWRITE_TAC[GSYM DET_MUL] THEN
+  ASM_SIMP_TAC[GSYM MATRIX_COMPOSE; ORTHOGONAL_TRANSFORMATION_LINEAR] THEN
+  ASM_REWRITE_TAC[o_DEF; MATRIX_ID; DET_I]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Apply plane rotation to a goal.                                           *)
+(* ------------------------------------------------------------------------- *)
+
+let GEOM_HORIZONTAL_PLANE_RULE =
+  let ifn = MATCH_MP
+   (TAUT `(p ==> (x <=> x')) /\ (~p ==> (x <=> T)) ==> (x' ==> x)`)
+  and pth = prove
+   (`!a f. orthogonal_transformation (f:real^N->real^N)
+           ==> ((!P. (!x. P x) <=> (!x. P (a + f x))) /\
+                (!P. (?x. P x) <=> (?x. P (a + f x))) /\
+                (!Q. (!s. Q s) <=> (!s. Q (IMAGE (\x. a + x) (IMAGE f s)))) /\
+                (!Q. (?s. Q s) <=> (?s. Q (IMAGE (\x. a + x) (IMAGE f s))))) /\
+               (!P. {x | P x} =
+                    IMAGE (\x. a + x) (IMAGE f {x | P(a + f x)}))`,
+    REPEAT GEN_TAC THEN DISCH_TAC THEN
+    MP_TAC(ISPEC `(\x. a + x) o (f:real^N->real^N)`
+      QUANTIFY_SURJECTION_THM) THEN REWRITE_TAC[o_THM; IMAGE_o] THEN
+    DISCH_THEN MATCH_MP_TAC THEN
+    ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_SURJECTIVE;
+                  VECTOR_ARITH `a + (x - a:real^N) = x`])
+  and cth = prove
+   (`!a f. {} = IMAGE (\x:real^3. a + x) (IMAGE f {})`,
+    REWRITE_TAC[IMAGE_CLAUSES])
+  and oth = prove
+   (`!f:real^3->real^3.
+        orthogonal_transformation f /\ det(matrix f) = &1
+        ==> linear f /\
+            (!x y. f x = f y ==> x = y) /\
+            (!y. ?x. f x = y) /\
+            (!x. norm(f x) = norm x) /\
+            (2 <= dimindex(:3) ==> det(matrix f) = &1)`,
+    GEN_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_LINEAR];
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_INJECTIVE];
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_SURJECTIVE];
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION]])
+  and fth = MESON[]
+   `(!a f. q a f ==> (p <=> p' a f))
+    ==> ((?a f. q a f) ==> (p <=> !a f. q a f ==> p' a f))` in
+  fun tm ->
+    let x,bod = dest_forall tm in
+    let th1 = EXISTS_GENVAR_RULE
+      (UNDISCH(ISPEC x ROTATION_HORIZONTAL_PLANE)) in
+    let [a;f],tm1 = strip_exists(concl th1) in
+    let [th_orth;th_det;th_im] = CONJUNCTS(ASSUME tm1) in
+    let th2 = PROVE_HYP th_orth (UNDISCH(ISPECL [a;f] pth)) in
+    let th3 = (EXPAND_QUANTS_CONV(ASSUME(concl th2)) THENC
+               SUBS_CONV[GSYM th_im; ISPECL [a;f] cth]) bod in
+    let th4 = PROVE_HYP th2 th3 in
+    let th5 = TRANSLATION_INVARIANTS a in
+    let th6 = GEN_REWRITE_RULE (RAND_CONV o REDEPTH_CONV)
+                [ASSUME(concl th5)] th4 in
+    let th7 = PROVE_HYP th5 th6 in
+    let th8s = CONJUNCTS(MATCH_MP oth (CONJ th_orth th_det)) in
+    let th9 = LINEAR_INVARIANTS f th8s in
+    let th10 = GEN_REWRITE_RULE (RAND_CONV o REDEPTH_CONV) [th9] th7 in
+    let th11 = if intersect (frees(concl th10)) [a;f] = []
+               then PROVE_HYP th1 (itlist SIMPLE_CHOOSE [a;f] th10)
+               else MP (MATCH_MP fth (GENL [a;f] (DISCH_ALL th10))) th1 in
+    let th12 = REWRITE_CONV[ASSUME(mk_neg(hd(hyp th11)))] bod in
+    let th13 = ifn(CONJ (DISCH_ALL th11) (DISCH_ALL th12)) in
+    let th14 = MATCH_MP MONO_FORALL (GEN x th13) in
+    GEN_REWRITE_RULE (TRY_CONV o LAND_CONV) [FORALL_SIMP] th14;;
+
+let GEOM_HORIZONTAL_PLANE_TAC p =
+  W(fun (asl,w) ->
+        let avs,bod = strip_forall w
+        and avs' = subtract (frees w) (freesl(map (concl o snd) asl)) in
+        let avs,bod = strip_forall w in
+        MAP_EVERY X_GEN_TAC avs THEN
+        MAP_EVERY (fun t -> SPEC_TAC(t,t)) (rev(subtract (avs@avs') [p])) THEN
+        SPEC_TAC(p,p) THEN
+        W(MATCH_MP_TAC o GEOM_HORIZONTAL_PLANE_RULE o snd));;
+
+(* ------------------------------------------------------------------------- *)
+(* Injection from real^2 -> real^3 plane with zero last coordinate.          *)
+(* ------------------------------------------------------------------------- *)
+
+let pad2d3d = new_definition
+ `(pad2d3d:real^2->real^3) x = lambda i. if i < 3 then x$i else &0`;;
+
+let FORALL_PAD2D3D_THM = prove
+ (`!P. (!y:real^3. y$3 = &0 ==> P y) <=> (!x. P(pad2d3d x))`,
+  GEN_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
+   [FIRST_X_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[pad2d3d] THEN
+    SIMP_TAC[LAMBDA_BETA; DIMINDEX_3; ARITH; LT_REFL];
+    FIRST_X_ASSUM(MP_TAC o SPEC `(lambda i. (y:real^3)$i):real^2`) THEN
+    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
+    SIMP_TAC[CART_EQ; pad2d3d; DIMINDEX_3; ARITH; LAMBDA_BETA; DIMINDEX_2;
+             ARITH_RULE `i < 3 <=> i <= 2`] THEN
+    REWRITE_TAC[ARITH_RULE `i <= 3 <=> i <= 2 \/ i = 3`] THEN
+    ASM_MESON_TAC[]]);;
+
+let QUANTIFY_PAD2D3D_THM = prove
+ (`(!P. (!y:real^3. y$3 = &0 ==> P y) <=> (!x. P(pad2d3d x))) /\
+   (!P. (?y:real^3. y$3 = &0 /\ P y) <=> (?x. P(pad2d3d x)))`,
+  REWRITE_TAC[MESON[] `(?y. P y) <=> ~(!x. ~P x)`] THEN
+  REWRITE_TAC[GSYM FORALL_PAD2D3D_THM] THEN MESON_TAC[]);;
+
+let LINEAR_PAD2D3D = prove
+ (`linear pad2d3d`,
+  REWRITE_TAC[linear; pad2d3d] THEN
+  SIMP_TAC[CART_EQ; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+           LAMBDA_BETA; DIMINDEX_2; DIMINDEX_3; ARITH;
+           ARITH_RULE `i < 3 ==> i <= 2`] THEN
+  REPEAT STRIP_TAC THEN REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN
+  REAL_ARITH_TAC);;
+
+let INJECTIVE_PAD2D3D = prove
+ (`!x y. pad2d3d x = pad2d3d y ==> x = y`,
+  SIMP_TAC[CART_EQ; pad2d3d; LAMBDA_BETA; DIMINDEX_3; DIMINDEX_2] THEN
+  REWRITE_TAC[ARITH_RULE `i < 3 <=> i <= 2`] THEN
+  MESON_TAC[ARITH_RULE `i <= 2 ==> i <= 3`]);;
+
+let NORM_PAD2D3D = prove
+ (`!x. norm(pad2d3d x) = norm x`,
+  SIMP_TAC[NORM_EQ; DOT_2; DOT_3; pad2d3d; LAMBDA_BETA;
+           DIMINDEX_2; DIMINDEX_3; ARITH] THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Apply 3D->2D conversion to a goal. Take care to preserve variable names.  *)
+(* ------------------------------------------------------------------------- *)
+
+let PAD2D3D_QUANTIFY_CONV =
+  let gv = genvar `:real^2` in
+  let pth = CONV_RULE (BINOP_CONV(BINDER_CONV(RAND_CONV(GEN_ALPHA_CONV gv))))
+                      QUANTIFY_PAD2D3D_THM in
+  let conv1 = GEN_REWRITE_CONV I [pth]
+  and dest_quant tm = try dest_forall tm with Failure _ -> dest_exists tm in
+  fun tm ->
+    let th = conv1 tm in
+    let name = fst(dest_var(fst(dest_quant tm))) in
+    let ty = snd(dest_var(fst(dest_quant(rand(concl th))))) in
+    CONV_RULE(RAND_CONV(GEN_ALPHA_CONV(mk_var(name,ty)))) th;;
+
+let PAD2D3D_TAC =
+  let pad2d3d_tm = `pad2d3d`
+  and pths = [LINEAR_PAD2D3D; INJECTIVE_PAD2D3D; NORM_PAD2D3D]
+  and cth = prove
+   (`{} = IMAGE pad2d3d {} /\
+     vec 0 = pad2d3d(vec 0)`,
+    REWRITE_TAC[IMAGE_CLAUSES] THEN MESON_TAC[LINEAR_PAD2D3D; LINEAR_0]) in
+  let lasttac =
+    GEN_REWRITE_TAC REDEPTH_CONV [LINEAR_INVARIANTS pad2d3d_tm pths] in
+  fun gl -> (GEN_REWRITE_TAC ONCE_DEPTH_CONV [cth] THEN
+             CONV_TAC(DEPTH_CONV PAD2D3D_QUANTIFY_CONV) THEN
+             lasttac) gl;;
+
+(* ------------------------------------------------------------------------- *)
+(* Rotating so a given line from the origin becomes the x-axis.              *)
+(* ------------------------------------------------------------------------- *)
+
+let ROTATION_HORIZONTAL_LINE = prove
+ (`!a:real^N.
+        ?b f. orthogonal_transformation f /\ det(matrix f) = &1 /\ f b = a /\
+              (!k. 1 < k /\ k <= dimindex(:N) ==> b$k = &0)`,
+  GEN_TAC THEN ASM_CASES_TAC `dimindex(:N) = 1` THENL
+   [MAP_EVERY EXISTS_TAC [`a:real^N`; `\x:real^N. x`] THEN
+    ASM_SIMP_TAC[DET_I; MATRIX_ID; ORTHOGONAL_TRANSFORMATION_ID; LTE_ANTISYM];
+    EXISTS_TAC `norm(a:real^N) % (basis 1):real^N` THEN
+    SIMP_TAC[VECTOR_MUL_COMPONENT; LT_IMP_LE; BASIS_COMPONENT] THEN
+    SIMP_TAC[ARITH_RULE `1 < k ==> ~(k = 1)`; REAL_MUL_RZERO] THEN
+    MATCH_MP_TAC ROTATION_EXISTS THEN
+    SIMP_TAC[NORM_MUL; NORM_BASIS; LE_REFL; DIMINDEX_GE_1] THEN
+    REWRITE_TAC[REAL_ABS_NORM; REAL_MUL_RID] THEN
+    MATCH_MP_TAC(ARITH_RULE `~(n = 1) /\ 1 <= n ==> 2 <= n`) THEN
+    ASM_REWRITE_TAC[DIMINDEX_GE_1]]);;
+
+let GEOM_HORIZONTAL_LINE_RULE =
+  let pth = prove
+   (`!f. orthogonal_transformation (f:real^N->real^N)
+         ==> (vec 0 = f(vec 0) /\ {} = IMAGE f {}) /\
+             ((!P. (!x. P x) <=> (!x. P (f x))) /\
+              (!P. (?x. P x) <=> (?x. P (f x))) /\
+              (!Q. (!s. Q s) <=> (!s. Q (IMAGE f s))) /\
+              (!Q. (?s. Q s) <=> (?s. Q (IMAGE f s)))) /\
+             (!P. {x | P x} = IMAGE f {x | P(f x)})`,
+    REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[IMAGE_CLAUSES] THEN
+    CONJ_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o MATCH_MP ORTHOGONAL_TRANSFORMATION_LINEAR) THEN
+      MESON_TAC[LINEAR_0];
+      MATCH_MP_TAC QUANTIFY_SURJECTION_THM THEN
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_SURJECTIVE]])
+  and oth = prove
+   (`!f:real^N->real^N.
+        orthogonal_transformation f /\ det(matrix f) = &1
+        ==> linear f /\
+            (!x y. f x = f y ==> x = y) /\
+            (!y. ?x. f x = y) /\
+            (!x. norm(f x) = norm x) /\
+            (2 <= dimindex(:N) ==> det(matrix f) = &1)`,
+    GEN_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
+     [ASM_SIMP_TAC[ORTHOGONAL_TRANSFORMATION_LINEAR];
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_INJECTIVE];
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION_SURJECTIVE];
+      ASM_MESON_TAC[ORTHOGONAL_TRANSFORMATION]])
+    and sth = prove
+   (`((!k. 1 < k /\ k <= dimindex(:2) ==> b$k = &0) <=> b$2 = &0) /\
+     ((!k. 1 < k /\ k <= dimindex(:3) ==> b$k = &0) <=> b$2 = &0 /\ b$3 = &0)`,
+    REWRITE_TAC[DIMINDEX_2; DIMINDEX_3;
+                ARITH_RULE `k <= 3 <=> k = 3 \/ k <= 2`;
+                ARITH_RULE `k <= 2 <=> k = 2 \/ ~(1 < k)`] THEN
+    MESON_TAC[ARITH_RULE `1 < 2 /\ 1 < 3`]) in
+  let sfn = GEN_REWRITE_RULE ONCE_DEPTH_CONV [sth] in
+  fun tm ->
+    let x,bod = dest_forall tm in
+    let th1 = EXISTS_GENVAR_RULE
+     (sfn(ISPEC x ROTATION_HORIZONTAL_LINE)) in
+    let [a;f],tm1 = strip_exists(concl th1) in
+    let th_orth,th2 = CONJ_PAIR(ASSUME tm1) in
+    let th_det,th2a = CONJ_PAIR th2 in
+    let th_works,th_zero = CONJ_PAIR th2a in
+    let thc,thq = CONJ_PAIR(PROVE_HYP th2 (UNDISCH(ISPEC f pth))) in
+    let th3 = CONV_RULE(RAND_CONV(SUBS_CONV(GSYM th_works::CONJUNCTS thc)))
+               (EXPAND_QUANTS_CONV(ASSUME(concl thq)) bod) in
+    let th4 = PROVE_HYP thq th3 in
+    let thps = CONJUNCTS(MATCH_MP oth (CONJ th_orth th_det)) in
+    let th5 = LINEAR_INVARIANTS f thps in
+    let th6 = PROVE_HYP th_orth
+     (GEN_REWRITE_RULE (RAND_CONV o REDEPTH_CONV) [th5] th4) in
+    let ntm = mk_forall(a,mk_imp(concl th_zero,rand(concl th6))) in
+    let th7 = MP(SPEC a (ASSUME ntm)) th_zero in
+    let th8 = DISCH ntm (EQ_MP (SYM th6) th7) in
+    if intersect (frees(concl th8)) [a;f] = [] then
+      let th9 = PROVE_HYP th1 (itlist SIMPLE_CHOOSE [a;f] th8) in
+      let th10 = DISCH ntm (GEN x (UNDISCH th9)) in
+      CONV_RULE(LAND_CONV (GEN_ALPHA_CONV x)) th10
+    else
+      let mtm = list_mk_forall([a;f],mk_imp(hd(hyp th8),rand(concl th6))) in
+      let th9 = EQ_MP (SYM th6) (UNDISCH(SPECL [a;f] (ASSUME mtm))) in
+      let th10 = itlist SIMPLE_CHOOSE [a;f] (DISCH mtm th9) in
+      let th11 = GEN x (PROVE_HYP th1 th10) in
+      MATCH_MP MONO_FORALL th11;;
+
+let GEOM_HORIZONTAL_LINE_TAC l (asl,w as gl) =
+  let avs,bod = strip_forall w
+  and avs' = subtract (frees w) (freesl(map (concl o snd) asl)) in
+  (MAP_EVERY X_GEN_TAC avs THEN
+   MAP_EVERY (fun t -> SPEC_TAC(t,t)) (rev(subtract (avs@avs') [l])) THEN
+   SPEC_TAC(l,l) THEN
+   W(MATCH_MP_TAC o GEOM_HORIZONTAL_LINE_RULE o snd)) gl;;
diff --git a/Multivariate/wlog_examples.ml b/Multivariate/wlog_examples.ml
new file mode 100644 (file)
index 0000000..2b3deeb
--- /dev/null
@@ -0,0 +1,744 @@
+(* ========================================================================= *)
+(* Examples of using the "without loss of generality" tactics.               *)
+(* ========================================================================= *)
+
+needs "Multivariate/wlog.ml";;
+
+(* ------------------------------------------------------------------------- *)
+(* Example 1.                                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let lemma = prove
+ (`(?y. y pow 2 = a) <=> &0 <= a`,
+  MESON_TAC[SQRT_POW_2; REAL_LE_SQUARE; REAL_POW_2]);;
+
+let TRUONG_1 = prove
+ (`!u1:real^3 u2 p a b.
+     ~(u1 = u2) /\
+     plane p /\
+     {u1,u2} SUBSET p /\
+     dist(u1,u2) <= a + b /\
+     abs(a - b) < dist(u1,u2) /\
+     &0 <= a /\
+     &0 <= b
+     ==> (?d1 d2.
+              {d1, d2} SUBSET p /\
+              &1 / &2 % (d1 + d2) IN affine hull {u1, u2} /\
+              dist(d1,u1) = a /\
+              dist(d1,u2) = b /\
+              dist(d2,u1) = a /\
+              dist(d2,u2) = b)`,
+  (*** First, rotate the plane p to the special case z$3 = &0 ***)
+
+  GEOM_HORIZONTAL_PLANE_TAC `p:real^3->bool` THEN
+
+  (*** Now reshuffle the goal to have explicit restricted quantifiers ***)
+
+  ONCE_REWRITE_TAC[TAUT
+   `a /\ b /\ c /\ d ==> e <=> c /\ a /\ b /\ d ==> e`] THEN
+  REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET] THEN
+  REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[GSYM CONJ_ASSOC; RIGHT_EXISTS_AND_THM] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+
+  (*** Now replace quantifiers over real^3 with those over real^2 ***)
+
+  PAD2D3D_TAC THEN
+
+  (*** Tidy the goal a little ***)
+
+  REWRITE_TAC[RIGHT_IMP_FORALL_THM; IMP_IMP; GSYM CONJ_ASSOC] THEN
+
+  (*** Choose u1 as the origin ***)
+
+  GEOM_ORIGIN_TAC `u1:real^2` THEN
+
+  (*** Rotate the point u2 onto the x-axis ***)
+
+  GEOM_HORIZONTAL_LINE_TAC `u2:real^2` THEN
+
+  (*** Only now introduce coordinates ***)
+
+  X_GEN_TAC `u2:real^2` THEN DISCH_TAC THEN
+  MAP_EVERY X_GEN_TAC [`a:real`; `b:real`] THEN
+  REWRITE_TAC[dist; VECTOR_SUB_RZERO; VECTOR_SUB_LZERO; NORM_NEG] THEN
+  SIMP_TAC[GSYM real_gt; NORM_GT_SQUARE; NORM_EQ_SQUARE; NORM_LE_SQUARE] THEN
+  REWRITE_TAC[real_gt; REAL_ARITH `~(abs x < &0)`] THEN
+  ASM_SIMP_TAC[DOT_2; REAL_MUL_RZERO; REAL_ADD_RID; CART_EQ; DIMINDEX_2;
+               FORALL_2; AFFINE_HULL_2; CART_EQ; VECTOR_MUL_COMPONENT;
+               VECTOR_SUB_COMPONENT; VEC_COMPONENT; ARITH; IN_ELIM_THM;
+               VECTOR_ADD_COMPONENT; REAL_SUB_RZERO; REAL_ADD_LID;
+               REAL_POW2_ABS] THEN
+  DISCH_THEN(CONJUNCTS_THEN2 (ASSUME_TAC o GSYM) STRIP_ASSUME_TAC) THEN
+  REWRITE_TAC[EXISTS_VECTOR_2] THEN
+  MATCH_MP_TAC(MESON[]
+   `(?x y:real. P x y x (--y)) ==> (?x y x' y'. P x y x' y')`) THEN
+  SIMP_TAC[AFFINE_HULL_2; IN_ELIM_THM; CART_EQ; DIMINDEX_2; FORALL_2; VECTOR_2;
+        VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; VEC_COMPONENT; ARITH] THEN
+  ASM_REWRITE_TAC[REAL_MUL_RZERO; REAL_ADD_LID; REAL_ADD_RINV] THEN
+  ASM_SIMP_TAC[REAL_FIELD
+   `~(a = &0)
+    ==> (u + v = &1 /\ b = v * a <=> u = &1 - b / a /\ v = b / a)`] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; LEFT_EXISTS_AND_THM; EXISTS_REFL] THEN
+  ABBREV_TAC `u = (u2:real^2)$1` THEN
+  REWRITE_TAC[REAL_ARITH `x + --y * --y:real = x + y * y`] THEN
+  REWRITE_TAC[TAUT `a /\ b /\ a /\ b <=> a /\ b`] THEN
+
+  (*** Now finally dive in and solve the algebraic problem ***)
+
+  ASM_SIMP_TAC[REAL_FIELD
+   `~(u = &0)
+    ==> (x * x + y * y = a pow 2 /\ (x - u) * (x - u) + y * y = b pow 2 <=>
+         x = (u pow 2 + a pow 2 - b pow 2) / (&2 * u) /\
+         y pow 2 = b pow 2 - (x - u) pow 2)`] THEN
+  REWRITE_TAC[RIGHT_EXISTS_AND_THM; UNWIND_THM2; lemma] THEN
+  ASM_SIMP_TAC[REAL_SUB_LE; REAL_FIELD
+   `(u pow 2 + a - b) / (&2 * u) - u = (a - b - u pow 2) / (&2 * u)`] THEN
+  REWRITE_TAC[GSYM REAL_LE_SQUARE_ABS] THEN
+  ASM_SIMP_TAC[REAL_ABS_DIV; REAL_LE_LDIV_EQ;
+               REAL_ARITH `~(u = &0) ==> &0 < abs(&2 * u)`] THEN
+  REWRITE_TAC[GSYM REAL_ABS_MUL; REAL_LE_SQUARE_ABS] THEN
+
+  (*** Can just use SOS: this proof was found by SOS_RULE ***)
+
+  MAP_EVERY UNDISCH_TAC
+   [`u * u <= (a + b) pow 2`; `(a - b) pow 2 < u * u`] THEN
+  DISCH_THEN(MP_TAC o MATCH_MP REAL_LT_IMP_LE) THEN
+  ONCE_REWRITE_TAC[GSYM REAL_SUB_LE] THEN
+  REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP REAL_LE_MUL) THEN
+  REAL_ARITH_TAC);;
+
+(* ------------------------------------------------------------------------- *)
+(* Definition of "opposite" for example 2, and its invariance theorems.      *)
+(* ------------------------------------------------------------------------- *)
+
+let opposite = new_definition
+  `opposite a b p <=>
+        (&1 / &2 % (a + b)) IN p /\
+        (!x y:real^N. {x,y} SUBSET p ==> (x - y) dot (a - b) = &0)`;;
+
+let OPPOSITE_TRANSLATION_EQ = prove
+ (`!c a b p. opposite (c + a) (c + b) (IMAGE (\x. c + x) p) <=>
+             opposite a b p`,
+  REWRITE_TAC[opposite] THEN GEOM_TRANSLATE_TAC[]);;
+
+add_translation_invariants [OPPOSITE_TRANSLATION_EQ];;
+
+let OPPOSITE_LINEAR_IMAGE_EQ = prove
+ (`!f a b p. linear f /\ (!x. norm(f x) = norm x)
+             ==> (opposite (f a) (f b) (IMAGE f p) <=> opposite a b p)`,
+  SIMP_TAC[opposite; INSERT_SUBSET; EMPTY_SUBSET; GSYM orthogonal] THEN
+  REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; RIGHT_FORALL_IMP_THM] THEN
+  SIMP_TAC[GSYM LINEAR_ADD; GSYM LINEAR_SUB; ORTHOGONAL_LINEAR_IMAGE_EQ] THEN
+  SIMP_TAC[GSYM LINEAR_CMUL; IN_IMAGE] THEN
+  MESON_TAC[PRESERVES_NORM_INJECTIVE]);;
+
+add_linear_invariants [OPPOSITE_LINEAR_IMAGE_EQ];;
+
+(* ------------------------------------------------------------------------- *)
+(* Example 2.                                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let AFFINE_PLANE = prove
+ (`!p. plane p ==> affine p`,
+  SIMP_TAC[plane; LEFT_IMP_EXISTS_THM; AFFINE_AFFINE_HULL]);;
+
+let lemma = prove
+ (`!a b:real^2.
+        a$2 <= &0 /\ &0 <= b$2 ==> ?x. x IN convex hull {a,b} /\ x$2 = &0`,
+  REPEAT GEN_TAC THEN DISCH_TAC THEN
+  FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+   `a <= &0 /\ &0 <= b ==> a = &0 /\ b = &0 \/ &0 < b - a`))
+  THENL
+   [EXISTS_TAC `a:real^2` THEN ASM_SIMP_TAC[HULL_INC; IN_INSERT];
+    REWRITE_TAC[CONVEX_HULL_2_ALT; EXISTS_IN_GSPEC] THEN
+    SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; VECTOR_SUB_COMPONENT;
+             DIMINDEX_2; ARITH] THEN
+    EXISTS_TAC `--(a$2) / ((b:real^2)$2 - (a:real^2)$2)` THEN
+    ASM_SIMP_TAC[REAL_LT_IMP_NZ; REAL_DIV_RMUL;
+                 REAL_LE_LDIV_EQ; REAL_LE_RDIV_EQ] THEN
+    ASM_REAL_ARITH_TAC]);;
+
+let TRUONG_OPPOSITE_LEMMA = prove
+ (`!p a b bb m x y:real^3.
+     plane p /\
+     {a, b, bb, m, x, y} SUBSET p /\
+     ~(x = y) /\ m IN affine hull {x,y} /\ midpoint(b,bb) = m
+     ==> ~(convex hull {a, b} INTER affine hull {x, y} = {}) \/
+         ~(convex hull {a, bb} INTER affine hull {x, y} = {})`,
+
+  (*** Make the plane p the xy-plane ***)
+
+  GEOM_HORIZONTAL_PLANE_TAC `p:real^3->bool` THEN
+
+  (*** Rewrite with explicit restricted quantifiers ***)
+
+  REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN DISCH_THEN(K ALL_TAC) THEN
+
+  (*** Now replace quantifiers over real^3 with those over real^2 ***)
+
+  PAD2D3D_TAC THEN
+
+  (*** Let x be the origin, and y on the x-axis ***)
+
+  GEOM_ORIGIN_TAC `x:real^2` THEN
+  GEOM_HORIZONTAL_LINE_TAC `y:real^2` THEN
+
+  (*** Make a few simplifications ***)
+
+  GEN_TAC THEN DISCH_TAC THEN REPEAT GEN_TAC THEN
+  ASM_SIMP_TAC[CART_EQ; DIMINDEX_2; FORALL_2; VEC_COMPONENT] THEN
+  DISCH_THEN(ASSUME_TAC o GSYM) THEN
+  SIMP_TAC[midpoint; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+           DIMINDEX_2; ARITH] THEN
+
+  (*** Show aff{x,y} is now exactly the x-axis ***)
+
+  SUBGOAL_THEN `affine hull {vec 0,y} = {u:real^2 | u$2 = &0}` SUBST1_TAC THENL
+   [MATCH_MP_TAC HULL_UNIQUE THEN
+    REWRITE_TAC[affine; INSERT_SUBSET; EMPTY_SUBSET; IN_ELIM_THM] THEN
+    ASM_SIMP_TAC[VEC_COMPONENT; DIMINDEX_2; ARITH; VECTOR_ADD_COMPONENT;
+                 VECTOR_MUL_COMPONENT; REAL_MUL_RZERO; REAL_ADD_RID] THEN
+    X_GEN_TAC `s:real^2->bool` THEN STRIP_TAC THEN
+    REWRITE_TAC[SUBSET; FORALL_IN_GSPEC] THEN X_GEN_TAC `u:real^2` THEN
+    DISCH_TAC THEN
+    SUBGOAL_THEN `u = (&1 - u$1 / (y:real^2)$1) % vec 0 +
+                  (u$1 / (y:real^2)$1) % y`
+    SUBST1_TAC THENL
+     [REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+      ASM_SIMP_TAC[CART_EQ; VECTOR_MUL_COMPONENT; DIMINDEX_2; ARITH;
+                   FORALL_2; REAL_MUL_RZERO; REAL_DIV_RMUL];
+      FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
+      REAL_ARITH_TAC];
+    ALL_TAC] THEN
+
+  (*** Simplify a bit more ***)
+
+  SIMP_TAC[IN_ELIM_THM; REAL_ARITH `inv(&2) * (x + y) = &0 <=> y = --x`] THEN
+  REPEAT STRIP_TAC THEN
+
+  (*** Finally, make a 4-way case split then apply the lemma to each ***)
+
+  REWRITE_TAC[SET_RULE `~(s INTER t = {}) <=> ?x. x IN s /\ x IN t`] THEN
+  REWRITE_TAC[IN_ELIM_THM] THEN
+  FIRST_ASSUM(MP_TAC o SPEC `(a:real^2)$2` o MATCH_MP (REAL_ARITH
+   `b' = --b ==> !a. a <= &0 /\ &0 <= b \/ a <= &0 /\ &0 <= b' \/
+                     b <= &0 /\ &0 <= a \/ b' <= &0 /\ &0 <= a`)) THEN
+  MESON_TAC[lemma; SET_RULE `{a,b} = {b,a}`]);;
+
+let TRUONG_OPPOSITE_THM = prove
+ (`!a b bb x y:real^3 p.
+     ~(x = y) /\
+     plane p /\
+     {a, b, x, y} SUBSET p /\
+     opposite b bb (affine hull {x, y})
+     ==> ~(convex hull {a, b} INTER affine hull {x, y} = {}) \/
+         ~(convex hull {a, bb} INTER affine hull {x, y} = {})`,
+  REWRITE_TAC[opposite; INSERT_SUBSET; EMPTY_SUBSET] THEN REPEAT STRIP_TAC THEN
+  MATCH_MP_TAC TRUONG_OPPOSITE_LEMMA THEN
+  MAP_EVERY EXISTS_TAC [`p:real^3->bool`; `&1 / &2 % (b + bb):real^3`] THEN
+  ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; midpoint] THEN
+  CONJ_TAC THENL [ALL_TAC; VECTOR_ARITH_TAC]  THEN
+  FIRST_ASSUM(ASSUME_TAC o MATCH_MP AFFINE_PLANE) THEN
+  MATCH_MP_TAC(TAUT `b /\ (b ==> a) ==> a /\ b`) THEN CONJ_TAC THENL
+   [MATCH_MP_TAC(SET_RULE `!t. x IN t /\ t SUBSET s ==> x IN s`) THEN
+    EXISTS_TAC `affine hull {x:real^3,y}` THEN ASM_REWRITE_TAC[] THEN
+    MATCH_MP_TAC HULL_MINIMAL THEN ASM_SIMP_TAC[INSERT_SUBSET; EMPTY_SUBSET];
+    DISCH_TAC THEN SUBST1_TAC(VECTOR_ARITH
+      `bb:real^3 = -- &1 % b + &2 % &1 / &2 % (b + bb)`) THEN
+    FIRST_X_ASSUM(MATCH_MP_TAC o REWRITE_RULE[affine]) THEN
+    ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC]);;
+
+(* ------------------------------------------------------------------------- *)
+(* Affsign variants for example 3, and invariance theorems.                  *)
+(* ------------------------------------------------------------------------- *)
+
+let lin_combo = new_definition
+  `lin_combo V f = vsum V (\v. f v % (v:real^N))`;;
+
+let affsign = new_definition
+  `affsign sgn s t (v:real^A) <=>
+     (?f. (v = lin_combo (s UNION t) f) /\
+          (!w. t w ==> sgn (f w)) /\
+          (sum (s UNION t) f = &1))`;;
+
+let sgn_gt = new_definition `sgn_gt = (\t. (&0 < t))`;;
+let sgn_ge = new_definition `sgn_ge = (\t. (&0 <= t))`;;
+let sgn_lt = new_definition `sgn_lt = (\t. (t < &0))`;;
+let sgn_le = new_definition `sgn_le = (\t. (t <= &0))`;;
+
+let aff_gt_def = new_definition `aff_gt = affsign sgn_gt`;;
+let aff_ge_def = new_definition `aff_ge = affsign sgn_ge`;;
+let aff_lt_def = new_definition `aff_lt = affsign sgn_lt`;;
+let aff_le_def = new_definition `aff_le = affsign sgn_le`;;
+
+let AFFSIGN = prove
+ (`affsign sgn s t =
+        {y | ?f. y = vsum (s UNION t) (\v. f v % v) /\
+                (!w. w IN t ==> sgn(f w)) /\
+                sum (s UNION t) f = &1}`,
+  REWRITE_TAC[FUN_EQ_THM; affsign; lin_combo; IN_ELIM_THM] THEN
+  REWRITE_TAC[IN]);;
+
+let AFFSIGN_ALT = prove
+ (`affsign sgn s t =
+        {y | ?f. (!w. w IN (s UNION t) ==> w IN t ==> sgn(f w)) /\
+                 sum (s UNION t) f = &1 /\
+                 vsum (s UNION t) (\v. f v % v) = y}`,
+  REWRITE_TAC[SET_RULE `(w IN (s UNION t) ==> w IN t ==> P w) <=>
+                        (w IN t ==> P w)`] THEN
+  REWRITE_TAC[AFFSIGN; EXTENSION; IN_ELIM_THM] THEN MESON_TAC[]);;
+
+let IN_AFFSIGN = prove
+ (`y IN affsign sgn s t <=>
+        ?u. (!x. x IN t ==> sgn(u x)) /\
+            sum (s UNION t) u = &1 /\
+            vsum (s UNION t) (\x. u(x) % x) = y`,
+  REWRITE_TAC[AFFSIGN; IN_ELIM_THM] THEN SET_TAC[]);;
+
+let AFFSIGN_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N sgn s t v.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> (affsign sgn (IMAGE f s) (IMAGE f t) =
+             IMAGE f (affsign sgn s t))`,
+  let lemma0 = prove
+   (`vsum s (\x. u x % x) = vsum {x | x IN s /\ ~(u x = &0)} (\x. u x % x)`,
+    MATCH_MP_TAC VSUM_SUPERSET THEN SIMP_TAC[SUBSET; IN_ELIM_THM] THEN
+    REWRITE_TAC[TAUT `p /\ ~(p /\ ~q) <=> p /\ q`] THEN
+    SIMP_TAC[o_THM; VECTOR_MUL_LZERO]) in
+  let lemma1 = prove
+   (`!f:real^M->real^N s.
+           linear f /\ (!x y. f x = f y ==> x = y)
+           ==> (sum(IMAGE f s) u = &1 /\ vsum(IMAGE f s) (\x. u x % x) = y <=>
+                sum s (u o f) = &1 /\ f(vsum s (\x. (u o f) x % x)) = y)`,
+    REPEAT STRIP_TAC THEN
+    W(MP_TAC o PART_MATCH (lhs o rand) SUM_IMAGE o funpow 3 lhand o snd) THEN
+    ANTS_TAC THENL [ASM_MESON_TAC[]; DISCH_THEN SUBST1_TAC] THEN
+    MATCH_MP_TAC(MESON[] `(p ==> z = x) ==> (p /\ x = y <=> p /\ z = y)`) THEN
+    DISCH_TAC THEN ONCE_REWRITE_TAC[lemma0] THEN
+    SUBGOAL_THEN
+     `{y | y IN IMAGE (f:real^M->real^N) s /\ ~(u y = &0)} =
+      IMAGE f {x | x IN s /\ ~(u(f x) = &0)}`
+    SUBST1_TAC THENL [ASM SET_TAC[]; CONV_TAC SYM_CONV] THEN
+    SUBGOAL_THEN `FINITE {x | x IN s /\ ~(u((f:real^M->real^N) x) = &0)}`
+    ASSUME_TAC THENL
+     [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE
+       (LAND_CONV o RATOR_CONV o RATOR_CONV) [sum]) THEN
+      ONCE_REWRITE_TAC[ITERATE_EXPAND_CASES] THEN
+      REWRITE_TAC[GSYM sum; support; NEUTRAL_REAL_ADD; o_THM] THEN
+      COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_OF_NUM_EQ; ARITH_EQ];
+      W(MP_TAC o PART_MATCH (lhs o rand) VSUM_IMAGE o lhand o snd) THEN
+      ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ALL_TAC] THEN
+      DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[o_DEF] THEN
+      ASM_SIMP_TAC[LINEAR_VSUM; o_DEF; GSYM LINEAR_CMUL]]) in
+  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[EXTENSION; IN_AFFSIGN] THEN
+  REWRITE_TAC[FORALL_IN_IMAGE] THEN REWRITE_TAC[IN_IMAGE; IN_AFFSIGN] THEN
+  REWRITE_TAC[GSYM IMAGE_UNION] THEN
+  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP lemma1 th]) THEN
+  X_GEN_TAC `y:real^N` THEN EQ_TAC THENL
+   [DISCH_THEN(X_CHOOSE_THEN `u:real^N->real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `vsum (s UNION t) (\x. (u o (f:real^M->real^N)) x % x)` THEN
+    ASM_REWRITE_TAC[] THEN
+    EXISTS_TAC `(u:real^N->real) o (f:real^M->real^N)` THEN
+    ASM_REWRITE_TAC[] THEN ASM_REWRITE_TAC[o_THM];
+    MP_TAC(ISPEC `f:real^M->real^N` LINEAR_INJECTIVE_LEFT_INVERSE) THEN
+    ASM_REWRITE_TAC[FUN_EQ_THM; o_THM; I_THM] THEN
+    DISCH_THEN(X_CHOOSE_THEN `g:real^N->real^M` STRIP_ASSUME_TAC) THEN
+    DISCH_THEN(X_CHOOSE_THEN `x:real^M`
+     (CONJUNCTS_THEN2 SUBST1_TAC MP_TAC)) THEN
+    DISCH_THEN(X_CHOOSE_THEN `u:real^M->real` STRIP_ASSUME_TAC) THEN
+    EXISTS_TAC `(u:real^M->real) o (g:real^N->real^M)` THEN
+    ASM_REWRITE_TAC[o_DEF; ETA_AX]]);;
+
+let AFF_GE_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> aff_ge (IMAGE f s) (IMAGE f t) = IMAGE f (aff_ge s t)`,
+  REWRITE_TAC[aff_ge_def; AFFSIGN_INJECTIVE_LINEAR_IMAGE]);;
+
+let AFF_GT_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> aff_gt (IMAGE f s) (IMAGE f t) = IMAGE f (aff_gt s t)`,
+  REWRITE_TAC[aff_gt_def; AFFSIGN_INJECTIVE_LINEAR_IMAGE]);;
+
+let AFF_LE_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> aff_le (IMAGE f s) (IMAGE f t) = IMAGE f (aff_le s t)`,
+  REWRITE_TAC[aff_le_def; AFFSIGN_INJECTIVE_LINEAR_IMAGE]);;
+
+let AFF_LT_INJECTIVE_LINEAR_IMAGE = prove
+ (`!f:real^M->real^N s t.
+        linear f /\ (!x y. f x = f y ==> x = y)
+        ==> aff_lt (IMAGE f s) (IMAGE f t) = IMAGE f (aff_lt s t)`,
+  REWRITE_TAC[aff_lt_def; AFFSIGN_INJECTIVE_LINEAR_IMAGE]);;
+
+add_linear_invariants
+  [AFFSIGN_INJECTIVE_LINEAR_IMAGE;
+   AFF_GE_INJECTIVE_LINEAR_IMAGE;
+   AFF_GT_INJECTIVE_LINEAR_IMAGE;
+   AFF_LE_INJECTIVE_LINEAR_IMAGE;
+   AFF_LT_INJECTIVE_LINEAR_IMAGE];;
+
+let IN_AFFSIGN_TRANSLATION = prove
+ (`!sgn s t a v:real^N.
+        affsign sgn s t v
+        ==> affsign sgn (IMAGE (\x. a + x) s) (IMAGE (\x. a + x) t) (a + v)`,
+  REPEAT GEN_TAC THEN REWRITE_TAC[affsign; lin_combo] THEN
+  ONCE_REWRITE_TAC[SET_RULE `(!x. s x ==> p x) <=> (!x. x IN s ==> p x)`] THEN
+  DISCH_THEN(X_CHOOSE_THEN `f:real^N->real`
+   (CONJUNCTS_THEN2 SUBST_ALL_TAC STRIP_ASSUME_TAC)) THEN
+  EXISTS_TAC `\x. (f:real^N->real)(x - a)` THEN
+  ASM_REWRITE_TAC[GSYM IMAGE_UNION] THEN REPEAT CONJ_TAC THENL
+   [ALL_TAC;
+    ASM_REWRITE_TAC[FORALL_IN_IMAGE; ETA_AX;
+                    VECTOR_ARITH `(a + x) - a:real^N = x`];
+    W(MP_TAC o PART_MATCH (lhs o rand) SUM_IMAGE o lhs o snd) THEN
+    SIMP_TAC[VECTOR_ARITH `a + x:real^N = a + y <=> x = y`] THEN
+    ASM_REWRITE_TAC[o_DEF; VECTOR_ADD_SUB; ETA_AX]] THEN
+  MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC
+   `a + vsum {x | x IN s UNION t /\ ~(f x = &0)} (\v:real^N. f v % v)` THEN
+  CONJ_TAC THENL
+   [AP_TERM_TAC THEN MATCH_MP_TAC VSUM_SUPERSET THEN
+    REWRITE_TAC[VECTOR_MUL_EQ_0; SUBSET; IN_ELIM_THM] THEN MESON_TAC[];
+    ALL_TAC] THEN
+  MATCH_MP_TAC EQ_TRANS THEN
+  EXISTS_TAC `vsum (IMAGE (\x:real^N. a + x)
+                          {x | x IN s UNION t /\ ~(f x = &0)})
+                   (\v. f(v - a) % v)` THEN
+  CONJ_TAC THENL
+   [ALL_TAC;
+    CONV_TAC SYM_CONV THEN MATCH_MP_TAC VSUM_SUPERSET THEN
+    CONJ_TAC THENL [SET_TAC[]; ALL_TAC] THEN
+    ASM_REWRITE_TAC[IMP_CONJ; FORALL_IN_IMAGE; VECTOR_MUL_EQ_0] THEN
+    REWRITE_TAC[VECTOR_ADD_SUB] THEN SET_TAC[]] THEN
+  SUBGOAL_THEN `FINITE {x:real^N | x IN s UNION t /\ ~(f x = &0)}`
+  ASSUME_TAC THENL
+   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE
+     (LAND_CONV o RATOR_CONV o RATOR_CONV) [sum]) THEN
+    ONCE_REWRITE_TAC[ITERATE_EXPAND_CASES] THEN
+    REWRITE_TAC[GSYM sum; support; NEUTRAL_REAL_ADD] THEN
+    COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_OF_NUM_EQ; ARITH_EQ];
+    ALL_TAC] THEN
+  W(MP_TAC o PART_MATCH (lhs o rand) VSUM_IMAGE o rhs o snd) THEN
+  ASM_SIMP_TAC[VECTOR_ARITH `a + x:real^N = a + y <=> x = y`] THEN
+  DISCH_THEN(K ALL_TAC) THEN REWRITE_TAC[o_DEF; VECTOR_ADD_SUB] THEN
+  ASM_SIMP_TAC[VECTOR_ADD_LDISTRIB; VSUM_ADD] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[VSUM_RMUL] THEN
+  GEN_REWRITE_TAC LAND_CONV [GSYM VECTOR_MUL_LID] THEN
+  AP_THM_TAC THEN AP_TERM_TAC THEN FIRST_X_ASSUM(SUBST1_TAC o SYM) THEN
+  MATCH_MP_TAC SUM_SUPERSET THEN SET_TAC[]);;
+
+let AFFSIGN_TRANSLATION = prove
+ (`!a:real^N sgn s t.
+        affsign sgn (IMAGE (\x. a + x) s) (IMAGE (\x. a + x) t) =
+        IMAGE (\x. a + x) (affsign sgn s t)`,
+  REPEAT GEN_TAC THEN MATCH_MP_TAC SUBSET_ANTISYM THEN CONJ_TAC THENL
+   [REWRITE_TAC[SUBSET; IN] THEN GEN_TAC THEN
+    DISCH_THEN(MP_TAC o SPEC `--a:real^N` o
+      MATCH_MP IN_AFFSIGN_TRANSLATION) THEN
+    REWRITE_TAC[GSYM IMAGE_o; o_DEF; VECTOR_ARITH `--a + a + x:real^N = x`;
+                IMAGE_ID] THEN
+    DISCH_TAC THEN REWRITE_TAC[IMAGE; IN_ELIM_THM] THEN
+    EXISTS_TAC `--a + x:real^N` THEN ASM_REWRITE_TAC[IN] THEN VECTOR_ARITH_TAC;
+    REWRITE_TAC[SUBSET; FORALL_IN_IMAGE] THEN GEN_TAC THEN REWRITE_TAC[IN] THEN
+    DISCH_THEN(MP_TAC o SPEC `a:real^N` o MATCH_MP IN_AFFSIGN_TRANSLATION) THEN
+    REWRITE_TAC[]]);;
+
+let AFF_GE_TRANSLATION = prove
+ (`!a:real^N s t.
+        aff_ge (IMAGE (\x. a + x) s) (IMAGE (\x. a + x) t) =
+        IMAGE (\x. a + x) (aff_ge s t)`,
+  REWRITE_TAC[aff_ge_def; AFFSIGN_TRANSLATION]);;
+
+let AFF_GT_TRANSLATION = prove
+ (`!a:real^N s t.
+        aff_gt (IMAGE (\x. a + x) s) (IMAGE (\x. a + x) t) =
+        IMAGE (\x. a + x) (aff_gt s t)`,
+  REWRITE_TAC[aff_gt_def; AFFSIGN_TRANSLATION]);;
+
+let AFF_LE_TRANSLATION = prove
+ (`!a:real^N s t.
+        aff_le (IMAGE (\x. a + x) s) (IMAGE (\x. a + x) t) =
+        IMAGE (\x. a + x) (aff_le s t)`,
+  REWRITE_TAC[aff_le_def; AFFSIGN_TRANSLATION]);;
+
+let AFF_LT_TRANSLATION = prove
+ (`!a:real^N s t.
+        aff_lt (IMAGE (\x. a + x) s) (IMAGE (\x. a + x) t) =
+        IMAGE (\x. a + x) (aff_lt s t)`,
+  REWRITE_TAC[aff_lt_def; AFFSIGN_TRANSLATION]);;
+
+add_translation_invariants
+  [AFFSIGN_TRANSLATION;
+   AFF_GE_TRANSLATION;
+   AFF_GT_TRANSLATION;
+   AFF_LE_TRANSLATION;
+   AFF_LT_TRANSLATION];;
+
+(* ------------------------------------------------------------------------- *)
+(* Example 3.                                                                *)
+(* ------------------------------------------------------------------------- *)
+
+let NOT_COPLANAR_NOT_COLLINEAR = prove
+ (`!v1 v2 v3 w:real^N. ~coplanar {v1, v2, v3, w} ==> ~collinear {v1, v2, v3}`,
+  REPEAT GEN_TAC THEN
+  REWRITE_TAC[COLLINEAR_AFFINE_HULL; coplanar; CONTRAPOS_THM] THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `x:real^N` THEN
+  MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `y:real^N` THEN
+  REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET] THEN STRIP_TAC THEN
+  EXISTS_TAC `w:real^N` THEN ASM_SIMP_TAC[HULL_INC; IN_INSERT] THEN
+  REPEAT CONJ_TAC THEN
+  MATCH_MP_TAC(SET_RULE `!t. t SUBSET s /\ x IN t ==> x IN s`) THEN
+  EXISTS_TAC `affine hull {x:real^N,y}` THEN
+  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC HULL_MONO THEN SET_TAC[]);;
+
+let AFFSIGN = prove
+ (`affsign sgn s t =
+        {y | ?f. y = vsum (s UNION t) (\v. f v % v) /\
+                (!w. w IN t ==> sgn(f w)) /\
+                sum (s UNION t) f = &1}`,
+  REWRITE_TAC[FUN_EQ_THM; affsign; lin_combo; IN_ELIM_THM] THEN
+  REWRITE_TAC[IN]);;
+
+let IN_AFFSIGN = prove
+ (`y IN affsign sgn s t <=>
+        ?u. (!x. x IN (s UNION t) ==> x IN t ==> sgn(u x)) /\
+            sum (s UNION t) u = &1 /\
+            vsum (s UNION t) (\x. u(x) % x) = y`,
+  REWRITE_TAC[AFFSIGN; IN_ELIM_THM] THEN SET_TAC[]);;
+
+let LEMMA = prove
+ (`!v1 v2 v3 w:real^3 p.
+     plane p /\ {v1, v2, v3} SUBSET p /\
+     ~coplanar {v1, v2, v3, w}
+     ==> (?n n'. norm(n - n') = &1 /\
+                (!x. x IN aff_ge {v1, v2, v3} {w} <=>
+                     (?xx h.
+                          xx IN affine hull {v1, v2, v3} /\
+                          &0 <= h /\
+                          x - xx = h % (n - n'))) /\
+                (!x y.
+                     {x, y} SUBSET affine hull {v1, v2, v3}
+                     ==> (n - n') dot (x - y) = &0))`,
+  GEOM_HORIZONTAL_PLANE_TAC `p:real^3->bool` THEN
+  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
+  REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; IN_ELIM_THM] THEN
+  MAP_EVERY (fun t ->
+   ASM_CASES_TAC t THENL [ASM_REWRITE_TAC[INSERT_AC; COPLANAR_3]; ALL_TAC])
+   [`v1:real^3 = v2`; `v1:real^3 = v3`; `v2:real^3 = v3`;
+    `v1:real^3 = w`; `v2:real^3 = w`; `v3:real^3 = w`] THEN
+  STRIP_TAC THEN
+  ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN
+  EXISTS_TAC `vec 0:real^3` THEN REWRITE_TAC[VECTOR_SUB_RZERO] THEN
+  SUBGOAL_THEN `~((w:real^3)$3 = &0)` ASSUME_TAC THENL
+   [DISCH_TAC THEN UNDISCH_TAC `~coplanar{v1:real^3,v2,v3,w}` THEN
+    REWRITE_TAC[coplanar] THEN
+    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [plane]) THEN
+    REPEAT(MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC) THEN
+    DISCH_THEN(SUBST1_TAC o SYM o CONJUNCT2) THEN
+    ASM_REWRITE_TAC[INSERT_SUBSET; EMPTY_SUBSET; IN_ELIM_THM];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `(vec 0:real^3) IN affine hull {v1,v2,v3}` ASSUME_TAC THENL
+   [MP_TAC(ISPEC `{v1:real^3,v2,v3}` DEPENDENT_BIGGERSET_GENERAL) THEN
+    ANTS_TAC THENL
+     [DISCH_THEN(K ALL_TAC) THEN REWRITE_TAC[GT] THEN
+      MATCH_MP_TAC LET_TRANS THEN EXISTS_TAC `dim {z:real^3 | z$3 = &0}` THEN
+      CONJ_TAC THENL [MATCH_MP_TAC DIM_SUBSET THEN ASM SET_TAC[]; ALL_TAC] THEN
+      SIMP_TAC[DIM_SPECIAL_HYPERPLANE; DIMINDEX_3; ARITH] THEN
+      REWRITE_TAC[GSYM NOT_LE] THEN DISCH_TAC THEN
+      FIRST_ASSUM(MP_TAC o MATCH_MP NOT_COPLANAR_NOT_COLLINEAR) THEN
+      REWRITE_TAC[] THEN MATCH_MP_TAC COLLINEAR_SMALL THEN
+      ASM_REWRITE_TAC[FINITE_INSERT; FINITE_RULES];
+      ALL_TAC] THEN
+    REWRITE_TAC[DEPENDENT_AFFINE_DEPENDENT_CASES] THEN
+    ASM_MESON_TAC[AFFINE_DEPENDENT_IMP_COLLINEAR_3;
+                  NOT_COPLANAR_NOT_COLLINEAR];
+    ALL_TAC] THEN
+  SUBGOAL_THEN `affine hull {v1,v2,v3} = {z:real^3 | z$3 = &0}`
+  ASSUME_TAC THENL
+   [ASM_SIMP_TAC[AFFINE_HULL_EQ_SPAN] THEN
+    MATCH_MP_TAC(SET_RULE
+     `!s. t SUBSET u /\ s SUBSET t /\ u SUBSET s ==> t = u`) THEN
+    EXISTS_TAC `span {x - v1:real^3 | x IN {v2,v3}}` THEN CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET] THEN MATCH_MP_TAC SPAN_INDUCT THEN
+      REWRITE_TAC[SET_RULE `(\x. x IN s) = s`] THEN
+      SIMP_TAC[SUBSPACE_SPECIAL_HYPERPLANE; DIMINDEX_3; ARITH] THEN
+      ASM_SIMP_TAC[FORALL_IN_INSERT; NOT_IN_EMPTY; IN_ELIM_THM];
+      ALL_TAC] THEN
+    CONJ_TAC THENL
+     [GEN_REWRITE_TAC RAND_CONV [GSYM SPAN_SPAN] THEN
+      MATCH_MP_TAC SPAN_MONO THEN
+      REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; FORALL_IN_INSERT; NOT_IN_EMPTY] THEN
+      MESON_TAC[SPAN_SUB; SPAN_INC; IN_INSERT; SUBSET];
+      ALL_TAC] THEN
+    MATCH_MP_TAC CARD_GE_DIM_INDEPENDENT THEN REPEAT CONJ_TAC THENL
+     [REWRITE_TAC[SUBSET; FORALL_IN_GSPEC; IN_ELIM_THM;
+                  FORALL_IN_INSERT; NOT_IN_EMPTY] THEN
+      ASM_SIMP_TAC[VECTOR_SUB_COMPONENT; DIMINDEX_3; ARITH; REAL_SUB_REFL];
+      REWRITE_TAC[independent] THEN
+      DISCH_THEN(MP_TAC o MATCH_MP (REWRITE_RULE[IMP_CONJ]
+        DEPENDENT_IMP_AFFINE_DEPENDENT)) THEN
+      ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN
+      ASM_MESON_TAC[AFFINE_DEPENDENT_IMP_COLLINEAR_3;
+                    NOT_COPLANAR_NOT_COLLINEAR];
+      SIMP_TAC[DIM_SPECIAL_HYPERPLANE; DIMINDEX_3; ARITH] THEN
+      ONCE_REWRITE_TAC[SIMPLE_IMAGE] THEN
+      SIMP_TAC[CARD_IMAGE_INJ; FINITE_INSERT; FINITE_RULES;
+               VECTOR_ARITH `x - a:real^N = y - a <=> x = y`] THEN
+      ASM_SIMP_TAC[CARD_CLAUSES; FINITE_INSERT; FINITE_RULES;
+                   IN_INSERT; NOT_IN_EMPTY; ARITH]];
+    ALL_TAC] THEN
+  FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
+   `~(x = &0) ==> &0 < x \/ &0 < --x`))
+  THENL
+   [EXISTS_TAC `basis 3:real^3`; EXISTS_TAC `--(basis 3):real^3`] THEN
+  ASM_SIMP_TAC[NORM_BASIS; DIMINDEX_3; ARITH; IN_ELIM_THM; DOT_BASIS;
+               NORM_NEG; DOT_LNEG; DIMINDEX_3; ARITH; VECTOR_SUB_COMPONENT;
+               REAL_SUB_REFL; REAL_NEG_0] THEN
+  X_GEN_TAC `x:real^3` THEN
+  REWRITE_TAC[aff_ge_def; IN_AFFSIGN; sgn_ge] THEN
+  REWRITE_TAC[SET_RULE `{a,b,c} UNION {d} = {a,b,c,d}`] THEN
+  REWRITE_TAC[SET_RULE `x IN {a} <=> a = x`] THEN
+  SIMP_TAC[AFFINE_HULL_FINITE_STEP_GEN; REAL_LE_ADD; FINITE_INSERT;
+           CONJUNCT1 FINITE_RULES; REAL_ARITH `&0 <= x / &2 <=> &0 <= x`;
+           RIGHT_EXISTS_AND_THM] THEN
+  ASM_REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN
+  REWRITE_TAC[REAL_ARITH `x - y:real = z <=> x = y + z`] THEN
+  REWRITE_TAC[VECTOR_ARITH `x - y:real^3 = z <=> x = y + z`] THEN
+  REWRITE_TAC[VECTOR_ADD_RID; REAL_ADD_RID] THEN
+  REWRITE_TAC[REAL_ARITH `&1 = x + y <=> x + y = &1`] THEN
+  EQ_TAC THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THENL
+   [MAP_EVERY X_GEN_TAC [`a:real`; `b:real`; `c:real`; `h:real`] THEN
+    STRIP_TAC THEN
+    EXISTS_TAC `a % v1 + b % v2 + c % v3 +
+                h % ((w:real^3)$1 % basis 1 + w$2 % basis 2):real^3` THEN
+    EXISTS_TAC `h * (w:real^3)$3` THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE] THEN
+    ASM_SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; BASIS_COMPONENT;
+                 DIMINDEX_3; ARITH; REAL_MUL_RZERO; REAL_ADD_RID] THEN
+    REWRITE_TAC[GSYM VECTOR_MUL_ASSOC; GSYM VECTOR_ADD_LDISTRIB;
+                GSYM VECTOR_ADD_ASSOC] THEN
+    REPLICATE_TAC 4 AP_TERM_TAC THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM BASIS_EXPANSION] THEN
+    REWRITE_TAC[DIMINDEX_3] THEN CONV_TAC(ONCE_DEPTH_CONV NUMSEG_CONV) THEN
+    SIMP_TAC[VSUM_CLAUSES; FINITE_INSERT; CONJUNCT1 FINITE_RULES] THEN
+    REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; ARITH_EQ; VECTOR_ADD_RID];
+
+    MAP_EVERY X_GEN_TAC [`y:real^3`; `h:real`] THEN STRIP_TAC THEN
+    UNDISCH_TAC `(vec 0:real^3) IN affine hull {v1,v2,v3}` THEN
+    SUBGOAL_THEN `(y - h / (w:real^3)$3 % (w$1 % basis 1 + w$2 % basis 2))
+                  IN affine hull {v1:real^3,v2,v3}` MP_TAC THENL
+     [ASM_SIMP_TAC[IN_ELIM_THM; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+            VECTOR_SUB_COMPONENT; BASIS_COMPONENT; ARITH; DIMINDEX_3] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    SIMP_TAC[AFFINE_HULL_FINITE; FINITE_INSERT; CONJUNCT1 FINITE_RULES;
+             AFFINE_HULL_FINITE_STEP; IN_ELIM_THM] THEN
+    REWRITE_TAC[REAL_ARITH `x - y:real = z <=> x = y + z`] THEN
+    REWRITE_TAC[VECTOR_ARITH `x - y:real^3 = z <=> x = y + z`] THEN
+    REWRITE_TAC[VECTOR_ADD_RID; REAL_ADD_RID; LEFT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[REAL_ARITH `&1 = x + y <=> x + y = &1`] THEN
+    MAP_EVERY X_GEN_TAC [`a:real`; `b:real`; `c:real`] THEN STRIP_TAC THEN
+    MAP_EVERY X_GEN_TAC [`a':real`; `b':real`; `c':real`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (ASSUME_TAC o SYM)) THEN
+    MAP_EVERY EXISTS_TAC
+     [`a + (&1 - (a + b + c + h / (w:real^3)$3)) * a'`;
+      `b + (&1 - (a + b + c + h / (w:real^3)$3)) * b'`;
+      `c + (&1 - (a + b + c + h / (w:real^3)$3)) * c'`; `h / (w:real^3)$3`] THEN
+    ASM_REWRITE_TAC[REAL_ARITH
+     `(a + x * a') + (b + x * b') + (c + x * c') + h:real =
+      (a + b + c + h) + x * (a' + b' + c')`] THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; REAL_LT_IMP_LE] THEN
+    CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+    REWRITE_TAC[VECTOR_ARITH
+     `(a + x * a') % v1 + (b + x * b') % v2 + (c + x * c') % v3 + h:real^N =
+      (a % v1 + b % v2 + c % v3) + x % (a' % v1 + b' % v2 + c' % v3) + h`] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+    REWRITE_TAC[VECTOR_ARITH `(x + a) + y:real^3 = a + z <=> x + y = z`] THEN
+    GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM BASIS_EXPANSION] THEN
+    REWRITE_TAC[DIMINDEX_3] THEN CONV_TAC(ONCE_DEPTH_CONV NUMSEG_CONV) THEN
+    SIMP_TAC[VSUM_CLAUSES; FINITE_INSERT; CONJUNCT1 FINITE_RULES] THEN
+    REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; ARITH_EQ; VECTOR_ADD_RID] THEN
+    REWRITE_TAC[VECTOR_ADD_LDISTRIB; GSYM VECTOR_ADD_ASSOC] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_DIV_RMUL; REAL_LT_IMP_NZ];
+
+    MAP_EVERY X_GEN_TAC [`a:real`; `b:real`; `c:real`; `h:real`] THEN
+    STRIP_TAC THEN
+    EXISTS_TAC `a % v1 + b % v2 + c % v3 +
+                h % ((w:real^3)$1 % basis 1 + w$2 % basis 2):real^3` THEN
+    EXISTS_TAC `h * --((w:real^3)$3)` THEN
+    ASM_SIMP_TAC[REAL_LE_MUL; REAL_LT_IMP_LE] THEN
+    REWRITE_TAC[VECTOR_ARITH `(x * --y) % --z:real^N = (x * y) % z`] THEN
+    ASM_SIMP_TAC[VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT; BASIS_COMPONENT;
+                 DIMINDEX_3; ARITH; REAL_MUL_RZERO; REAL_ADD_RID] THEN
+    REWRITE_TAC[GSYM VECTOR_MUL_ASSOC; GSYM VECTOR_ADD_LDISTRIB;
+                GSYM VECTOR_ADD_ASSOC] THEN
+    REPLICATE_TAC 4 AP_TERM_TAC THEN
+    GEN_REWRITE_TAC LAND_CONV [GSYM BASIS_EXPANSION] THEN
+    REWRITE_TAC[DIMINDEX_3] THEN CONV_TAC(ONCE_DEPTH_CONV NUMSEG_CONV) THEN
+    SIMP_TAC[VSUM_CLAUSES; FINITE_INSERT; CONJUNCT1 FINITE_RULES] THEN
+    REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; ARITH_EQ; VECTOR_ADD_RID];
+
+    MAP_EVERY X_GEN_TAC [`y:real^3`; `h:real`] THEN STRIP_TAC THEN
+    UNDISCH_TAC `(vec 0:real^3) IN affine hull {v1,v2,v3}` THEN
+    SUBGOAL_THEN `(y - h / --((w:real^3)$3) % (w$1 % basis 1 + w$2 % basis 2))
+                  IN affine hull {v1:real^3,v2,v3}` MP_TAC THENL
+     [ASM_SIMP_TAC[IN_ELIM_THM; VECTOR_ADD_COMPONENT; VECTOR_MUL_COMPONENT;
+            VECTOR_SUB_COMPONENT; BASIS_COMPONENT; ARITH; DIMINDEX_3] THEN
+      REAL_ARITH_TAC;
+      ALL_TAC] THEN
+    SIMP_TAC[AFFINE_HULL_FINITE; FINITE_INSERT; CONJUNCT1 FINITE_RULES;
+             AFFINE_HULL_FINITE_STEP; IN_ELIM_THM] THEN
+    REWRITE_TAC[REAL_ARITH `x - y:real = z <=> x = y + z`] THEN
+    REWRITE_TAC[VECTOR_ARITH `x - y:real^3 = z <=> x = y + z`] THEN
+    REWRITE_TAC[VECTOR_ADD_RID; REAL_ADD_RID; LEFT_IMP_EXISTS_THM] THEN
+    REWRITE_TAC[REAL_ARITH `&1 = x + y <=> x + y = &1`] THEN
+    MAP_EVERY X_GEN_TAC [`a:real`; `b:real`; `c:real`] THEN STRIP_TAC THEN
+    MAP_EVERY X_GEN_TAC [`a':real`; `b':real`; `c':real`] THEN
+    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (ASSUME_TAC o SYM)) THEN
+    MAP_EVERY EXISTS_TAC
+     [`a + (&1 - (a + b + c + h / --((w:real^3)$3))) * a'`;
+      `b + (&1 - (a + b + c + h / --((w:real^3)$3))) * b'`;
+      `c + (&1 - (a + b + c + h / --((w:real^3)$3))) * c'`;
+      `h / --((w:real^3)$3)`] THEN
+    ASM_REWRITE_TAC[REAL_ARITH
+     `(a + x * a') + (b + x * b') + (c + x * c') + h:real =
+      (a + b + c + h) + x * (a' + b' + c')`] THEN
+    ASM_SIMP_TAC[REAL_LE_DIV; REAL_LT_IMP_LE] THEN
+    CONJ_TAC THENL [REAL_ARITH_TAC; ALL_TAC] THEN
+    REWRITE_TAC[VECTOR_ARITH
+     `(a + x * a') % v1 + (b + x * b') % v2 + (c + x * c') % v3 + h:real^N =
+      (a % v1 + b % v2 + c % v3) + x % (a' % v1 + b' % v2 + c' % v3) + h`] THEN
+    ASM_REWRITE_TAC[VECTOR_MUL_RZERO; VECTOR_ADD_LID] THEN
+    REWRITE_TAC[VECTOR_ARITH `(x + a) + y:real^3 = a + z <=> x + y = z`] THEN
+    GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM BASIS_EXPANSION] THEN
+    REWRITE_TAC[DIMINDEX_3] THEN CONV_TAC(ONCE_DEPTH_CONV NUMSEG_CONV) THEN
+    SIMP_TAC[VSUM_CLAUSES; FINITE_INSERT; CONJUNCT1 FINITE_RULES] THEN
+    REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; ARITH_EQ; VECTOR_ADD_RID] THEN
+    REWRITE_TAC[VECTOR_ADD_LDISTRIB; GSYM VECTOR_ADD_ASSOC] THEN
+    REWRITE_TAC[real_div; REAL_INV_NEG; REAL_MUL_RNEG] THEN
+    REWRITE_TAC[VECTOR_MUL_RNEG; VECTOR_MUL_LNEG; GSYM real_div] THEN
+    ASM_SIMP_TAC[VECTOR_MUL_ASSOC; REAL_DIV_RMUL; REAL_LT_IMP_NZ]]);;
+
+let THEOREM = prove
+ (`!v1 v2 v3 w:real^3.
+     ~coplanar {v1, v2, v3, w}
+     ==> (?nor. norm nor = &1 /\
+                (!x. x IN aff_ge {v1, v2, v3} {w} <=>
+                     (?xx h.
+                          xx IN affine hull {v1, v2, v3} /\
+                          &0 <= h /\
+                          x = xx + h % nor)) /\
+                (!x y.
+                     {x, y} SUBSET affine hull {v1, v2, v3}
+                     ==> nor dot (x - y) = &0))`,
+  REPEAT STRIP_TAC THEN
+  ONCE_REWRITE_TAC[VECTOR_ARITH `x:real^3 = y + h % z <=> x - y = h % z`] THEN
+  MATCH_MP_TAC(MESON[] `(?a b. P(a - b)) ==> ?a:real^3. P a`) THEN
+  MATCH_MP_TAC LEMMA THEN ASM_REWRITE_TAC[] THEN
+  EXISTS_TAC `affine hull {v1:real^3,v2,v3}` THEN
+  REWRITE_TAC[HULL_SUBSET; plane] THEN
+  ASM_MESON_TAC[NOT_COPLANAR_NOT_COLLINEAR]);;
diff --git a/make.ml b/make.ml
new file mode 100644 (file)
index 0000000..1a6773d
--- /dev/null
+++ b/make.ml
@@ -0,0 +1,36 @@
+(* ========================================================================= *)
+(* Theory of multivariate calculus in Euclidean space.                       *)
+(* ========================================================================= *)
+
+loadt "Library/card.ml";;               (* For countable set theorems.      *)
+loadt "Library/permutations.ml";;       (* For determinants                 *)
+loadt "Library/products.ml";;           (* For determinants and integrals   *)
+loadt "Library/floor.ml";;              (* Useful here and there            *)
+loadt "Multivariate/misc.ml";;          (* Background stuff                 *)
+
+(* ------------------------------------------------------------------------- *)
+(* The main core theory.                                                     *)
+(* ------------------------------------------------------------------------- *)
+
+loadt "Multivariate/vectors.ml";;       (* Basic vectors, linear algebra    *)
+loadt "Multivariate/determinants.ml";;  (* Determinant and trace            *)
+loadt "Multivariate/topology.ml";;      (* Basic topological notions        *)
+loadt "Multivariate/convex.ml";;        (* Convex sets and functions        *)
+loadt "Multivariate/paths.ml";;         (* Paths, simple connectedness etc. *)
+loadt "Multivariate/polytope.ml";;      (* Faces, polytopes, polyhedra etc. *)
+loadt "Multivariate/dimension.ml";;     (* Dimensional theorems             *)
+loadt "Multivariate/derivatives.ml";;   (* Derivatives                      *)
+
+(* ------------------------------------------------------------------------- *)
+(* Work in progress.                                                         *)
+(* ------------------------------------------------------------------------- *)
+
+loadt "Multivariate/clifford.ml";;      (* Geometric (Clifford) algebra     *)
+loadt "Multivariate/integration.ml";;   (* Integration                      *)
+loadt "Multivariate/measure.ml";;       (* Lebesgue measure                 *)
+
+(* ------------------------------------------------------------------------- *)
+(* Updated database, for convenience where dynamic updating doesn't work.    *)
+(* ------------------------------------------------------------------------- *)
+
+loadt "Multivariate/multivariate_database.ml";;