Theory Chord_Segments
section ‹Intersecting Chord Theorem›
theory Chord_Segments
imports Triangle.Triangle
begin
subsection ‹Preliminaries›
lemma betweenE_if_dist_leq:
  fixes A B X :: "'a::euclidean_space"
  assumes "between (A, B) X"
  assumes "dist A X ≤ dist B X"
  obtains u where "1 / 2 ≤ u" "u ≤ 1" and "X = u *⇩R A + (1 - u) *⇩R B"
proof (cases "A = B")
  assume "A ≠ B"
  from ‹between (A, B) X› obtain u where u: "u ≥ 0" "u ≤ 1" and X: "X = u *⇩R A + (1 - u) *⇩R B"
    by (metis add.commute betweenE between_commute)
  from X have "X = B + u *⇩R (A - B)" and "X = A + (u - 1) *⇩R (A - B)"
    by (simp add: scaleR_diff_left real_vector.scale_right_diff_distrib)+
  from ‹X = B + u *⇩R (A - B)› have dist_B: "dist B X = norm (u *⇩R (A - B))"
    by (auto simp add: dist_norm)
  from ‹X = A + (u - 1) *⇩R (A - B)› have dist_A: "dist A X = norm ((u - 1) *⇩R (A - B))"
    by (auto simp add: dist_norm)
  from ‹A ≠ B› have "norm (A - B) > 0" by auto
  from this ‹dist A X ≤ dist B X› have "u ≥ 1 / 2"
    using dist_A dist_B by simp
  from this ‹u ≤ 1› X that show thesis by blast
next
  assume "A = B"
  define u :: real where "u = 1"
  from ‹between (A, B) X› ‹A = B› have "1 / 2 ≤ u" "u ≤ 1" "X = u *⇩R A + (1 - u) *⇩R B"
    unfolding u_def by auto
  with that show thesis by blast
qed
lemma dist_geq_iff_midpoint_in_between:
  fixes A B X :: "'a::euclidean_space"
  assumes "between (A, B) X"
  shows "dist A X ≤ dist B X ⟷ between (X, B) (midpoint A B)"
proof
  assume "dist A X ≤ dist B X"
  from ‹between (A, B) X› this obtain u
    where u: "1 / 2 ≤ u" "u ≤ 1" and X: "X = u *⇩R A + (1 - u) *⇩R B"
    using betweenE_if_dist_leq by blast
  have M: "midpoint A B = (1 / 2) *⇩R A + (1 / 2) *⇩R B"
    unfolding midpoint_def by (simp add: scaleR_add_right)
  from ‹1 / 2 ≤ u› have 1: "midpoint A B = (1 / (2 * u)) *⇩R X + (1 - (1 / (2 * u))) *⇩R B"
  proof -
    have "(2 - u * 2) / (2 * u) = 1 / u - u / u"
      using u(1) by (simp add: diff_divide_distrib)
    also have "… = 1 / u - 1" using u(1) by auto
    finally have "(2 - u * 2) / (2 * u) = 1 / u - 1" .
    from ‹1 / 2 ≤ u› this show ?thesis
      using X M by (simp add: scaleR_add_right scaleR_add_left[symmetric])
  qed
  moreover from u have 2: "(1 / (2 * u)) ≥ 0" "(1 / (2 * u)) ≤ 1" by auto
  ultimately show "between (X, B) (midpoint A B)"
    using betweenI [of concl: B X]  by (metis add.commute between_commute)
next
  assume "between (X, B) (midpoint A B)"
  then have "between (A, midpoint A B) X"
    using ‹between (A, B) X› between_midpoint(1) between_swap by blast
  then have "dist A X ≤ dist A (midpoint A B)"
    using between zero_le_dist by force
  also have "dist A (midpoint A B) ≤ dist B (midpoint A B)"
    by (simp add: dist_midpoint)
  also from ‹between (X, B) (midpoint A B)› have "dist B (midpoint A B) ≤ dist B X"
    using between zero_le_dist by (metis add.commute dist_commute le_add_same_cancel1)
  finally show "dist A X ≤ dist B X" .
qed
subsection ‹Properties of Chord Segments›
lemma chord_property:
  fixes S C :: "'a :: euclidean_space"
  assumes "dist C S = dist C T"
  assumes "between (S, T) X"
  shows "dist S X * dist X T = (dist C S) ^ 2 - (dist C X) ^ 2"
proof -
  define M where "M = midpoint S T"
  have "between (S, T) M"
    unfolding M_def by (simp add: between_midpoint(1))
  have "dist T M = dist S M"
    unfolding M_def by (simp add: dist_midpoint)
  have distances: "max (dist S X) (dist X T) = (dist S M) + (dist X M) ∧
    min (dist S X) (dist X T) = (dist S M) - (dist X M)"
  proof cases
    assume "dist S X ≤ dist X T"
    then have "between (X, T) M"
      using ‹between (S, T) X› M_def
      by (simp add: dist_geq_iff_midpoint_in_between dist_commute)
    then have "between (S, M) X"
      using ‹between (S, T) X› ‹between (S, T) M› between_swap by blast
    from ‹between (X, T) M› have "dist X T = dist X M + dist M T"
      using between by auto
    moreover from ‹between (S, M) X› have "dist S X = dist S M - dist M X"
      using between dist_commute by force
    ultimately show ?thesis
      using ‹dist S X ≤ dist X T› ‹dist T M = dist S M›
      by (simp add: add.commute dist_commute max_def min_def)
  next
    assume "¬ (dist S X ≤ dist X T)"
    then have "dist T X ≤ dist S X" by (simp add: dist_commute)
    then have "between (S, X) M"
      using ‹between (S, T) X› M_def
      by (simp add: dist_geq_iff_midpoint_in_between midpoint_sym between_commute)
    then have "between (T, M) X"
      using ‹between (S, T) X› ‹between (S, T) M› between_swap between_commute by metis
    from ‹between (S, X) M› have "dist S X = dist S M + dist M X"
      using between by auto
    moreover from ‹between (T, M) X› have "dist T X = dist T M - dist M X"
      using between dist_commute by force
    ultimately show ?thesis
      using ‹¬ dist S X ≤ dist X T› ‹dist T M = dist S M›
      by (metis dist_commute max_def min_def)
  qed
  have "orthogonal (C - M) (S - M)"
    using ‹dist C S = dist C T› M_def
    by (auto simp add: isosceles_triangle_orthogonal_on_midpoint)
  have "orthogonal (C - M) (X - M)"
  proof -
    have "between (S, T) M"
      using M_def between_midpoint(1) by blast
    obtain c where "(X - M) = c *⇩R (S - M)"
    proof (cases "S = M")
      assume "S ≠ M"
      then obtain c where "(X - M) = c *⇩R (S - M)"
        using between_implies_scaled_diff [OF ‹between (S, T) X› ‹between (S, T) M›] by metis
      from this that show thesis by blast
    next
      assume "S = M"
      from this ‹between (S, T) X› have "X = M"
        by (simp add: midpoint_between M_def)
      from ‹X = M› ‹S = M› have "(X - M) = 0 *⇩R (S - M)" by simp
      from this that show thesis by blast
    qed
    from this ‹orthogonal (C - M) (S - M)› show ?thesis
      by (auto intro: orthogonal_clauses(2))
  qed
  from ‹orthogonal (C - M) (S - M)› ‹orthogonal (C - M) (X - M)› have
    "(dist S M) ^ 2 + (dist M C) ^ 2 = (dist C S) ^ 2"
    "(dist X M) ^ 2 + (dist M C) ^ 2 = (dist C X) ^ 2"
    by (auto simp only: Pythagoras)
  then have geometric_observation:
    "(dist S M) ^ 2 = (dist C S) ^ 2 - (dist M C) ^ 2"
    "(dist X M) ^ 2 = (dist C X) ^ 2 - (dist M C) ^ 2"
    by auto
  have "dist S X * dist X T = max (dist S X) (dist X T) * min (dist S X) (dist X T)"
    by (auto split: split_max)
  also have "… = ((dist S M) + (dist X M)) * ((dist S M) - (dist X M))"
    using distances by simp
  also have "… = (dist S M) ^ 2 - (dist X M) ^ 2"
    by (simp add: field_simps power2_eq_square)
  also have "… = ((dist C S) ^ 2 - (dist M C) ^ 2) - ((dist C X) ^ 2 - (dist M C) ^ 2)"
    using geometric_observation by simp
  also have "… = (dist C S) ^ 2 - (dist C X) ^ 2" by simp
  finally show ?thesis .
qed
theorem product_of_chord_segments:
  fixes S⇩1 T⇩1 S⇩2 T⇩2 X C :: "'a :: euclidean_space"
  assumes "between (S⇩1, T⇩1) X" "between (S⇩2, T⇩2) X"
  assumes "dist C S⇩1 = r" "dist C T⇩1 = r"
  assumes "dist C S⇩2 = r" "dist C T⇩2 = r"
  shows "dist S⇩1 X * dist X T⇩1 = dist S⇩2 X * dist X T⇩2"
proof -
  from ‹dist C S⇩1 = r› ‹dist C T⇩1 = r› ‹between (S⇩1, T⇩1) X›
  have "dist S⇩1 X * dist X T⇩1 = r ^ 2 - (dist C X) ^ 2"
    by (subst chord_property) auto
  also from ‹dist C S⇩2 = r› ‹dist C T⇩2 = r› ‹between (S⇩2, T⇩2) X›
  have "… = dist S⇩2 X * dist X T⇩2"
    by (subst chord_property) auto
  finally show ?thesis .
qed
end