(* ========================================================================= *)
(* 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`,
(* ------------------------------------------------------------------------- *)
(* 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))`;;
add_linear_invariants [VECTOR_ANGLE_LINEAR_IMAGE_EQ];;
(* ------------------------------------------------------------------------- *)
(* Basic properties of vector angles. *)
(* ------------------------------------------------------------------------- *)
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_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). *)
(* ------------------------------------------------------------------------- *)
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 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)`,
let ANGLE = prove
(`!A B C. (A - C) dot (B - C) = dist(A,C) * dist(B,C) * cos(angle(A,C,B))`,
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')`,
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'))`,
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')`,
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)`,
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))`,
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)`,
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`,
(* ------------------------------------------------------------------------- *)
(* 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))`,
(* ------------------------------------------------------------------------- *)
(* 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 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);;
(* ------------------------------------------------------------------------- *)
(* 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))`,
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')`,
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')`,
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')`,
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')`,
(* ------------------------------------------------------------------------- *)
(* Between-ness. *)
(* ------------------------------------------------------------------------- *)
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`,
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]);;