Theory Napoleon
theory Napoleon
imports
"HOL-Decision_Procs.Commutative_Ring"
"Morley_Theorem.Complex_Triangles"
begin
section ‹Napoleon's construction›
text ‹
A complex number ‹s› equal to ‹cis (pi/3)› or
‹cis (-pi/3)› rotates a directed side through one of the two
equilateral-triangle angles. The apex and the centre of the resulting
equilateral triangle are defined parametrically so that the same algebraic
lemmas cover both orientations.
›
definition napoleon_apex :: "complex ⇒ complex ⇒ complex ⇒ complex"
where "napoleon_apex s x y = x + s * (y - x)"
definition napoleon_centre :: "complex ⇒ complex ⇒ complex ⇒ complex"
where "napoleon_centre s x y =
(x + y + napoleon_apex s x y) / 3"
lemma napoleon_apex_displacement:
"napoleon_apex s x y - x = s * (y - x)"
by (simp add: napoleon_apex_def)
lemma equilateral_on_side:
fixes x y s :: complex
assumes "x ≠ y"
and "s = cis (pi / 3) ∨ s = cis (-pi / 3)"
shows
"cdist y x = cdist (napoleon_apex s x y) x ∧
cdist (napoleon_apex s x y) x = cdist (napoleon_apex s x y) y"
proof -
have hyx: "y ≠ x" using assms(1) by auto
have hrot:
"napoleon_apex s x y - x = cis (pi / 3) * (y - x) ∨
napoleon_apex s x y - x = cis (-pi / 3) * (y - x)"
using assms(2) by (auto simp add: napoleon_apex_def)
have h' :
"cdist y x = cdist (napoleon_apex s x y) x ∧
cdist (napoleon_apex s x y) x = cdist (napoleon_apex s x y) y"
using equilateral_caracterization[
THEN iffD2, of y x "napoleon_apex s x y", OF hyx] hrot by blast
show ?thesis using h' by (simp add: cdist_commute)
qed
section ‹Algebra of the three centres›
lemma cis_pi3_square:
"(cis (pi / 3) :: complex) ^ 2 = cis (pi / 3) - 1"
by (auto intro: complex_eqI
simp: cis.code cos_60 sin_60 power2_eq_square algebra_simps)
lemma cis_minus_pi3_square:
"(cis (-pi / 3) :: complex) ^ 2 = cis (-pi / 3) - 1"
by (auto intro: complex_eqI
simp: cis.code cos_60 sin_60 power2_eq_square algebra_simps)
lemma one_minus_cis_pi3:
"(1 :: complex) - cis (pi / 3) = cis (-pi / 3)"
by (auto intro: complex_eqI
simp: cis.code cos_60 sin_60 algebra_simps)
lemma one_minus_cis_minus_pi3:
"(1 :: complex) - cis (-pi / 3) = cis (pi / 3)"
by (auto intro: complex_eqI
simp: cis.code cos_60 sin_60 algebra_simps)
lemma napoleon_centre_cycle:
fixes a b c s :: complex
assumes "s ^ 2 = s - 1"
shows
"napoleon_centre s c a - napoleon_centre s a b =
(1 - s) * (napoleon_centre s b c - napoleon_centre s a b)"
proof -
have hsquare': "s * s = s - 1"
using assms by (simp add: power2_eq_square)
have hmult: "s * (s * z) = (s - 1) * z" for z :: complex
by (simp add: hsquare' mult.assoc[symmetric] algebra_simps)
from hsquare'
show "napoleon_centre s c a - napoleon_centre s a b =
(1 - s) * (napoleon_centre s b c - napoleon_centre s a b)"
unfolding napoleon_centre_def napoleon_apex_def
by (simp add: hmult algebra_simps field_simps)
qed
lemma napoleon_centres_equilateral:
fixes a b c s :: complex
assumes hsquare: "s ^ 2 = s - 1"
and hroot: "1 - s = cis (pi / 3) ∨ 1 - s = cis (-pi / 3)"
shows
"cdist (napoleon_centre s b c) (napoleon_centre s a b) =
cdist (napoleon_centre s c a) (napoleon_centre s a b) ∧
cdist (napoleon_centre s c a) (napoleon_centre s a b) =
cdist (napoleon_centre s c a) (napoleon_centre s b c)"
proof -
have hdiff:
"napoleon_centre s c a - napoleon_centre s a b =
(1 - s) * (napoleon_centre s b c - napoleon_centre s a b)"
by (rule napoleon_centre_cycle[OF hsquare])
show ?thesis
proof (cases "napoleon_centre s b c = napoleon_centre s a b")
case True
have hca:
"napoleon_centre s c a = napoleon_centre s a b"
using hdiff True by simp
show ?thesis by (simp add: True hca)
next
case False
have hrot:
"napoleon_centre s c a - napoleon_centre s a b =
cis (pi / 3) * (napoleon_centre s b c - napoleon_centre s a b) ∨
napoleon_centre s c a - napoleon_centre s a b =
cis (-pi / 3) * (napoleon_centre s b c - napoleon_centre s a b)"
using hdiff hroot by (auto simp add: hdiff)
have h' :
"cdist (napoleon_centre s b c) (napoleon_centre s a b) =
cdist (napoleon_centre s c a) (napoleon_centre s a b) ∧
cdist (napoleon_centre s c a) (napoleon_centre s a b) =
cdist (napoleon_centre s c a) (napoleon_centre s b c)"
using equilateral_caracterization[
THEN iffD2, of "napoleon_centre s b c" "napoleon_centre s a b"
"napoleon_centre s c a", OF False] hrot by blast
show ?thesis by (rule h')
qed
qed
section ‹External orientation and Napoleon's theorem›
text ‹
The sign of the oriented area of the triangle is the sign of the
imaginary part of the quotient below. Choosing the opposite rotation
makes the equilateral triangle on the directed side ‹a b› lie on
the exterior side; the same choice works cyclically on ‹b c› and
‹c a›. This exteriority claim is formalized by
‹external_side›: the signed side orientations of the third vertex
and the constructed apex have strictly negative product.
›
definition napoleon_external_rotation :: "complex ⇒ complex ⇒ complex ⇒ complex"
where
"napoleon_external_rotation a b c =
(if 0 < Im ((c - a) / (b - a))
then cis (-pi / 3)
else cis (pi / 3))"
definition side_orientation :: "complex ⇒ complex ⇒ complex ⇒ real"
where "side_orientation a b x = Im ((x - a) / (b - a))"
definition external_side :: "complex ⇒ complex ⇒ complex ⇒ complex ⇒ bool"
where
"external_side a b c x ⟷
side_orientation a b c * side_orientation a b x < 0"
lemma napoleon_external_rotation_cases:
"napoleon_external_rotation a b c = cis (pi / 3) ∨
napoleon_external_rotation a b c = cis (-pi / 3)"
unfolding napoleon_external_rotation_def
by (split if_split; simp)
lemma napoleon_external_rotation_square:
"napoleon_external_rotation a b c ^ 2 =
napoleon_external_rotation a b c - 1"
proof (cases "0 < Im ((c - a) / (b - a))")
case True
show ?thesis
unfolding napoleon_external_rotation_def
using cis_minus_pi3_square True by (simp add: True)
next
case False
show ?thesis
unfolding napoleon_external_rotation_def
using cis_pi3_square False by (simp add: False)
qed
lemma napoleon_external_rotation_one_minus:
"1 - napoleon_external_rotation a b c = cis (pi / 3) ∨
1 - napoleon_external_rotation a b c = cis (-pi / 3)"
proof (cases "0 < Im ((c - a) / (b - a))")
case True
show ?thesis
unfolding napoleon_external_rotation_def
using one_minus_cis_minus_pi3 True by (simp add: True)
next
case False
show ?thesis
unfolding napoleon_external_rotation_def
using one_minus_cis_pi3 False by (simp add: False)
qed
lemma oriented_area_cycle:
"Im ((c - a) * cnj (b - a)) =
Im ((a - b) * cnj (c - b))"
by (simp add: algebra_simps)
lemma napoleon_external_rotation_cyclic:
"napoleon_external_rotation a b c =
napoleon_external_rotation b c a"
proof -
have hleft:
"0 < Im ((c - a) / (b - a)) ⟷
0 < Im ((c - a) * cnj (b - a))"
using Im_complex_div_gt_0[of "(c - a)" "(b - a)"] by simp
have hright:
"0 < Im ((a - b) / (c - b)) ⟷
0 < Im ((a - b) * cnj (c - b))"
using Im_complex_div_gt_0[of "(a - b)" "(c - b)"] by simp
have harea:
"Im ((c - a) * cnj (b - a)) =
Im ((a - b) * cnj (c - b))"
by (rule oriented_area_cycle)
have hpos:
"0 < Im ((c - a) / (b - a)) ⟷
0 < Im ((a - b) / (c - b))"
using hleft hright harea by (simp add: harea)
show ?thesis
unfolding napoleon_external_rotation_def
using hpos by simp
qed
lemma noncollinear_distinct:
assumes "¬ collinear a b c"
shows "a ≠ b ∧ b ≠ c ∧ c ≠ a"
proof -
have hab: "a ≠ b"
using assms unfolding collinear_def by auto
have hbc: "b ≠ c"
proof
assume "b = c"
with hab have "collinear a b c"
by (simp add: collinear_def)
with assms show False by contradiction
qed
have hca: "c ≠ a"
proof
assume "c = a"
with hab have "collinear a b c"
by (simp add: collinear_def)
with assms show False by contradiction
qed
show ?thesis by (intro conjI; fact)
qed
lemma side_orientation_nonzero:
assumes hncol: "¬ collinear a b c"
shows "side_orientation a b c ≠ 0"
using hncol unfolding side_orientation_def collinear_def by auto
lemma side_orientation_apex:
fixes a b s :: complex
assumes "a ≠ b"
shows
"side_orientation a b (napoleon_apex s a b) = Im s"
proof -
have hba: "b - a ≠ (0 :: complex)" using assms by auto
have hratio:
"(napoleon_apex s a b - a) / (b - a) = s"
unfolding napoleon_apex_def
using hba by (simp add: field_simps)
show ?thesis
unfolding side_orientation_def
using hratio by simp
qed
lemma Im_cis_pi3_pos:
"0 < Im (cis (pi / 3) :: complex)"
proof -
have hroot: "0 < sqrt (3 :: real)"
by (rule real_sqrt_gt_zero) simp
show ?thesis by (simp add: cis.code sin_60 hroot)
qed
lemma Im_cis_minus_pi3_neg:
"Im (cis (-pi / 3) :: complex) < 0"
proof -
have hroot: "0 < sqrt (3 :: real)"
by (rule real_sqrt_gt_zero) simp
show ?thesis by (simp add: cis.code sin_60 hroot)
qed
lemma napoleon_external_side:
fixes a b c :: complex
assumes hncol: "¬ collinear a b c"
shows
"external_side a b c
(napoleon_apex (napoleon_external_rotation a b c) a b)"
proof -
obtain hab hbc hca where "a ≠ b" "b ≠ c" "c ≠ a"
using noncollinear_distinct[OF hncol] by blast
have hside: "side_orientation a b c ≠ 0"
by (rule side_orientation_nonzero[OF hncol])
show ?thesis
unfolding external_side_def
proof (cases "0 < side_orientation a b c")
case True
have hcond: "0 < Im ((c - a) / (b - a))"
using True by (simp add: side_orientation_def)
have hrot:
"napoleon_external_rotation a b c = cis (-pi / 3)"
unfolding napoleon_external_rotation_def side_orientation_def
using hcond by simp
have hapex:
"side_orientation a b
(napoleon_apex (napoleon_external_rotation a b c) a b) < 0"
using side_orientation_apex[OF ‹a ≠ b›]
Im_cis_minus_pi3_neg hrot by simp
show "side_orientation a b c *
side_orientation a b
(napoleon_apex (napoleon_external_rotation a b c) a b) < 0"
by (rule mult_pos_neg[OF True hapex])
next
case False
have hside_neg: "side_orientation a b c < 0"
using hside False by linarith
have hcond: "¬ 0 < Im ((c - a) / (b - a))"
using False by (simp add: side_orientation_def)
have hrot:
"napoleon_external_rotation a b c = cis (pi / 3)"
unfolding napoleon_external_rotation_def side_orientation_def
using hcond by simp
have hapex:
"0 < side_orientation a b
(napoleon_apex (napoleon_external_rotation a b c) a b)"
using side_orientation_apex[OF ‹a ≠ b›]
Im_cis_pi3_pos hrot by simp
show "side_orientation a b c *
side_orientation a b
(napoleon_apex (napoleon_external_rotation a b c) a b) < 0"
by (rule mult_neg_pos[OF hside_neg hapex])
qed
qed
lemma napoleon_external_construction:
assumes hncol: "¬ collinear a b c"
shows
"cdist b a =
cdist (napoleon_apex (napoleon_external_rotation a b c) a b) a ∧
cdist (napoleon_apex (napoleon_external_rotation a b c) a b) a =
cdist (napoleon_apex (napoleon_external_rotation a b c) a b) b ∧
cdist c b =
cdist (napoleon_apex (napoleon_external_rotation a b c) b c) b ∧
cdist (napoleon_apex (napoleon_external_rotation a b c) b c) b =
cdist (napoleon_apex (napoleon_external_rotation a b c) b c) c ∧
cdist a c =
cdist (napoleon_apex (napoleon_external_rotation a b c) c a) c ∧
cdist (napoleon_apex (napoleon_external_rotation a b c) c a) c =
cdist (napoleon_apex (napoleon_external_rotation a b c) c a) a ∧
external_side a b c
(napoleon_apex (napoleon_external_rotation a b c) a b) ∧
external_side b c a
(napoleon_apex (napoleon_external_rotation a b c) b c) ∧
external_side c a b
(napoleon_apex (napoleon_external_rotation a b c) c a)"
proof -
obtain hab hbc hca where "a ≠ b" "b ≠ c" "c ≠ a"
using noncollinear_distinct[OF hncol] by blast
have hs:
"napoleon_external_rotation a b c = cis (pi / 3) ∨
napoleon_external_rotation a b c = cis (-pi / 3)"
by (rule napoleon_external_rotation_cases)
have hab':
"cdist b a =
cdist (napoleon_apex (napoleon_external_rotation a b c) a b) a ∧
cdist (napoleon_apex (napoleon_external_rotation a b c) a b) a =
cdist (napoleon_apex (napoleon_external_rotation a b c) a b) b"
using equilateral_on_side[of a b "napoleon_external_rotation a b c"]
‹a ≠ b› hs by blast
have hbc':
"cdist c b =
cdist (napoleon_apex (napoleon_external_rotation a b c) b c) b ∧
cdist (napoleon_apex (napoleon_external_rotation a b c) b c) b =
cdist (napoleon_apex (napoleon_external_rotation a b c) b c) c"
using equilateral_on_side[of b c "napoleon_external_rotation a b c"]
‹b ≠ c› hs by blast
have hca':
"cdist a c =
cdist (napoleon_apex (napoleon_external_rotation a b c) c a) c ∧
cdist (napoleon_apex (napoleon_external_rotation a b c) c a) c =
cdist (napoleon_apex (napoleon_external_rotation a b c) c a) a"
using equilateral_on_side[of c a "napoleon_external_rotation a b c"]
‹c ≠ a› hs by blast
have hside_ab:
"external_side a b c
(napoleon_apex (napoleon_external_rotation a b c) a b)"
by (rule napoleon_external_side[OF hncol])
have hncol_bca: "¬ collinear b c a"
using hncol by (metis collinear_sym1 collinear_sym2)
have hncol_cab: "¬ collinear c a b"
using hncol by (metis collinear_sym1 collinear_sym2)
have hrot_bc:
"napoleon_external_rotation a b c =
napoleon_external_rotation b c a"
by (rule napoleon_external_rotation_cyclic)
have hrot_ca:
"napoleon_external_rotation a b c =
napoleon_external_rotation c a b"
using napoleon_external_rotation_cyclic[of a b c]
napoleon_external_rotation_cyclic[of b c a] by simp
have hside_bc0:
"external_side b c a
(napoleon_apex (napoleon_external_rotation b c a) b c)"
by (rule napoleon_external_side[OF hncol_bca])
have hside_bc:
"external_side b c a
(napoleon_apex (napoleon_external_rotation a b c) b c)"
using hside_bc0 hrot_bc by (simp add: hrot_bc)
have hside_ca0:
"external_side c a b
(napoleon_apex (napoleon_external_rotation c a b) c a)"
by (rule napoleon_external_side[OF hncol_cab])
have hside_ca:
"external_side c a b
(napoleon_apex (napoleon_external_rotation a b c) c a)"
using hside_ca0 hrot_ca by (simp add: hrot_ca)
show ?thesis using hab' hbc' hca' hside_ab hside_bc hside_ca by blast
qed
theorem napoleon_theorem:
fixes a b c :: complex
assumes hncol: "¬ collinear a b c"
shows
"cdist (napoleon_centre (napoleon_external_rotation a b c) b c)
(napoleon_centre (napoleon_external_rotation a b c) a b) =
cdist (napoleon_centre (napoleon_external_rotation a b c) c a)
(napoleon_centre (napoleon_external_rotation a b c) a b) ∧
cdist (napoleon_centre (napoleon_external_rotation a b c) c a)
(napoleon_centre (napoleon_external_rotation a b c) a b) =
cdist (napoleon_centre (napoleon_external_rotation a b c) c a)
(napoleon_centre (napoleon_external_rotation a b c) b c)"
using napoleon_centres_equilateral[
OF napoleon_external_rotation_square
napoleon_external_rotation_one_minus]
by blast
theorem napoleon_external_theorem:
fixes a b c :: complex
assumes hncol: "¬ collinear a b c"
shows
"(cdist b a =
cdist (napoleon_apex (napoleon_external_rotation a b c) a b) a ∧
cdist (napoleon_apex (napoleon_external_rotation a b c) a b) a =
cdist (napoleon_apex (napoleon_external_rotation a b c) a b) b ∧
cdist c b =
cdist (napoleon_apex (napoleon_external_rotation a b c) b c) b ∧
cdist (napoleon_apex (napoleon_external_rotation a b c) b c) b =
cdist (napoleon_apex (napoleon_external_rotation a b c) b c) c ∧
cdist a c =
cdist (napoleon_apex (napoleon_external_rotation a b c) c a) c ∧
cdist (napoleon_apex (napoleon_external_rotation a b c) c a) c =
cdist (napoleon_apex (napoleon_external_rotation a b c) c a) a ∧
external_side a b c
(napoleon_apex (napoleon_external_rotation a b c) a b) ∧
external_side b c a
(napoleon_apex (napoleon_external_rotation a b c) b c) ∧
external_side c a b
(napoleon_apex (napoleon_external_rotation a b c) c a)) ∧
(cdist (napoleon_centre (napoleon_external_rotation a b c) b c)
(napoleon_centre (napoleon_external_rotation a b c) a b) =
cdist (napoleon_centre (napoleon_external_rotation a b c) c a)
(napoleon_centre (napoleon_external_rotation a b c) a b) ∧
cdist (napoleon_centre (napoleon_external_rotation a b c) c a)
(napoleon_centre (napoleon_external_rotation a b c) a b) =
cdist (napoleon_centre (napoleon_external_rotation a b c) c a)
(napoleon_centre (napoleon_external_rotation a b c) b c))"
using napoleon_external_construction[OF hncol]
napoleon_theorem[OF hncol]
by blast
end