(* ========================================================================= *)
(* 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. *)
(* ------------------------------------------------------------------------- *)
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[]]]);;
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]);;
(* ------------------------------------------------------------------------- *)
(* 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 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 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`]);;
(* ------------------------------------------------------------------------- *)
(* 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 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;;