Theory Poincare_Circles

theory Poincare_Circles
  imports Poincare_Distance
begin
(* -------------------------------------------------------------------------- *)
section‹H-circles in the Poincar\'e model›
(* -------------------------------------------------------------------------- *)

text‹Circles consist of points that are at the same distance from the center.›
definition poincare_circle :: "complex_homo  real  complex_homo set" where
  "poincare_circle z r = {z'. z'  unit_disc  poincare_distance z z' = r}"

text‹Each h-circle in the Poincar\'e model is represented by an Euclidean circle in the model ---
the center and radius of that euclidean circle are determined by the following formulas.›
definition poincare_circle_euclidean :: "complex_homo  real  euclidean_circle" where
  "poincare_circle_euclidean z r =
      (let R = (cosh r - 1) / 2;
           z' = to_complex z;
           cz = 1 - (cmod z')2;
           k = cz * R + 1
        in (z' / k, cz * sqrt(R * (R + 1)) / k))"

text‹That Euclidean circle has a positive radius and is always fully within the disc.›
lemma poincare_circle_in_disc:
  assumes "r > 0" and "z  unit_disc" and "(ze, re) = poincare_circle_euclidean z r"
  shows "cmod ze < 1" "re > 0" " x  circle ze re. cmod x < 1"
proof-
  let ?R = "(cosh r - 1) / 2"
  let ?z' = "to_complex z"
  let ?cz = "1 - (cmod ?z')2"
  let ?k = "?cz * ?R + 1"
  let ?ze = "?z' / ?k"
  let ?re = "?cz * sqrt(?R * (?R + 1)) / ?k"

  from z  unit_disc
  obtain z' where z': "z = of_complex z'"
    using inf_or_of_complex[of z]
    by auto

  hence "z' = ?z'"
    by simp

  obtain cz where cz: "cz = (1 - (cmod z')2)"
    by auto

  have "cz > 0" "cz  1"
    using z  unit_disc z' cz
    using unit_disc_cmod_square_lt_1
    by fastforce+

  obtain R where R: "R = ?R"
    by blast

  have "R > 0"
    using cosh_gt_1[of r] r > 0
    by (subst R) simp

  obtain k where k: "k = cz * R + 1"
    by auto

  have "k > 1"
    using k R > 0 cz > 0
    by simp

  hence "cmod k = k"
    by simp

  let ?RR = "cz * sqrt(R * (R + 1)) / k"

  have "cmod z' + cz * sqrt(R * (R + 1)) < k"
  proof-
    have "((R+1)-R)2 > 0"
      by simp
    hence "(R+1)2 - 2*R*(R+1) + R2 > 0"
      unfolding power2_diff
      by (simp add: field_simps)
    hence "(R+1)2 + 2*R*(R+1) + R2 - 4*R*(R+1) > 0"
      by simp
    hence "(2*R+1)2 / 4 > R*(R+1)"
      using power2_sum[of "R+1" R]
      by (simp add: field_simps)
    hence "sqrt(R*(R+1)) < (2*R+1) / 2"
      using R > 0
      by (smt arith_geo_mean_sqrt power_divide real_sqrt_four real_sqrt_pow2 zero_le_mult_iff)
    hence "sqrt(R*(R+1)) - R < 1/2"
      by (simp add: field_simps)
    hence "(1 + (cmod z')) * (sqrt(R*(R+1)) - R) < (1 + (cmod z')) *  (1 / 2)"
      by (subst mult_strict_left_mono, simp, smt norm_not_less_zero, simp)
    also have "... < 1"
      using z  unit_disc z'
      by auto
    finally have "(1 - cmod z') * ((1 + cmod z') * (sqrt(R*(R+1)) - R)) < (1 - cmod z') * 1"
      using z  unit_disc z'
      by (subst mult_strict_left_mono, simp_all)
    hence "cz * (sqrt (R*(R+1)) - R) < 1 - cmod z'"
      using square_diff_square_factored[of 1 "cmod z'"]
      by (subst cz, subst (asm) mult.assoc[symmetric], simp add: power2_eq_square field_simps)
    hence "cmod z' + cz * sqrt(R*(R+1)) < 1 + R * cz"
      by (simp add: field_simps)
    thus ?thesis
      using k
      by (simp add: field_simps)
  qed
  hence "cmod z' / k + cz * sqrt(R * (R + 1)) / k < 1"
    using k > 1
    unfolding add_divide_distrib[symmetric]
    by simp
  hence "cmod (z' / k) + cz * sqrt(R * (R + 1)) / k < 1"
    using k > 1
    by simp
  hence "cmod ?ze + ?re < 1"
    using k cz R = ?R z'
    by simp

  moreover

  have "cz * sqrt(R * (R + 1)) / k > 0"
    using cz > 0 R > 0 k > 1
    by auto
  hence "?re > 0"
    using k cz R = ?R z'
    by simp

  moreover

  have "cmod ?ze < 1"
    using cmod ?ze + ?re < 1 ?re > 0
    by simp

  moreover

  have "ze = ?ze" "re = ?re"
    using (ze, re) = poincare_circle_euclidean z r
    unfolding poincare_circle_euclidean_def Let_def
    by simp_all

  moreover

  have " x  circle ze re. cmod x  cmod ze + re"
    using norm_triangle_ineq2[of _ ze]
    unfolding circle_def
    by (smt mem_Collect_eq)

  ultimately

  show "cmod ze < 1" "re > 0" " x  circle ze re. cmod x < 1"
    by auto
qed

text‹The connection between the points on the h-circle and its corresponding Euclidean circle.›
lemma poincare_circle_is_euclidean_circle:
  assumes "z  unit_disc" and "r > 0"
  shows  "let (Ze, Re) = poincare_circle_euclidean z r
           in of_complex ` (circle Ze Re) = poincare_circle z r"
proof-
  {
    fix x
    let ?z = "to_complex z"

    from assms obtain z' where z': "z = of_complex z'" "cmod z' < 1"
      using inf_or_of_complex[of z]
      by auto

    have *: " x. cmod x < 1  1 - (cmod x)2 > 0"
      by (metis less_iff_diff_less_0 minus_diff_eq mult.left_neutral neg_less_0_iff_less norm_mult_less norm_power power2_eq_square)

    let ?R = "(cosh r - 1) / 2"
    obtain R where R: "R = ?R"
      by blast

    let ?cx = "1 - (cmod x)2" and ?cz = "1 - (cmod z')2"  and ?czx = "(cmod (z' - x))2"

    let ?k = "1 + R * ?cz"
    obtain k where k: "k = ?k"
      by blast
    have "R > 0"
      using R cosh_gt_1[OF r > 0]
      by simp

    hence "k > 1"
      using assms z' k *[of z']
      by auto
    hence **: "cor k  0"
      by (smt of_real_eq_0_iff)


    have "of_complex x  poincare_circle z r  cmod x < 1  poincare_distance z (of_complex x) = r"
      unfolding poincare_circle_def
      by auto
    also have "...  cmod x < 1  poincare_distance_formula' ?z x = cosh r"
      using poincare_distance_formula[of z "of_complex x"] cosh_dist[of z "of_complex x"]
      unfolding poincare_distance_formula_def
      using assms
      using arcosh_cosh_real
      by auto
    also have "...  cmod x < 1  ?czx / (?cz * ?cx) = ?R"
      using z'
      by (simp add: field_simps)
    also have "...  cmod x < 1  ?czx = ?R * ?cx * ?cz"
      using assms z' *[of z'] *[of x]
      using nonzero_divide_eq_eq[of "(1 - (cmod x)2) * (1 - (cmod z')2)" "(cmod (z' - x))2" ?R]
      by (auto, simp add: field_simps)
    also have "...  cmod x < 1  (z' - x) * (cnj z' - cnj x) = R * ?cz * (1 - x * cnj x)" (is "_  _  ?l = ?r")
    proof-
      let ?l = "(z' - x) * (cnj z' - cnj x)" and ?r = "R * (1 - Re (z' * cnj z')) * (1 - x * cnj x)"
      have "is_real ?l"
        using eq_cnj_iff_real[of "?l"]
        by simp
      moreover
      have "is_real ?r"
        using eq_cnj_iff_real[of "1 - x * cnj x"]
        using Im_complex_of_real[of "R * (1 - Re (z' * cnj z'))"]
        by simp
      ultimately
      show ?thesis
        apply (subst R[symmetric])
        apply (subst cmod_square)+
        apply (subst complex_eq_if_Re_eq, simp_all add: field_simps)
        done
    qed
    also have "...  cmod x < 1  z' * cnj z' - x * cnj z' - cnj x * z' + x * cnj x = R * ?cz - R * ?cz * x * cnj x"
      unfolding right_diff_distrib left_diff_distrib
      by (simp add: field_simps)
    also have "...  cmod x < 1  k * (x * cnj x) - x * cnj z' - cnj x * z' + z' * cnj z' = R * ?cz" (is "_  _  ?lhs = ?rhs")
      by (subst k) (auto simp add: field_simps)
    also have "...  cmod x < 1  (k * x * cnj x - x * cnj z' - cnj x * z' + z' * cnj z') / k = (R * ?cz) / k"
      using **
      by (auto simp add: Groups.mult_ac(1))
    also have "...  cmod x < 1  x * cnj x - x * cnj z' / k - cnj x * z' / k + z' * cnj z' / k = (R * ?cz) / k"
      using **
      unfolding add_divide_distrib diff_divide_distrib
      by auto
    also have "...  cmod x < 1  (x - z'/k) * cnj(x - z'/k) = (R * ?cz) / k + (z' / k) * cnj(z' / k) - z' * cnj z' / k"
      by (auto simp add: field_simps diff_divide_distrib)
    also have "...  cmod x < 1  (cmod (x - z'/k))2 = (R * ?cz) / k + (cmod z')2 / k2 - (cmod z')2 / k"
      apply (subst complex_mult_cnj_cmod)+
      apply (subst complex_eq_if_Re_eq)
      apply (simp_all add: power_divide)
      done
    also have "...  cmod x < 1  (cmod (x - z'/k))2 = (R * ?cz * k + (cmod z')2 - (cmod z')2 * k) / k2"
      using **
      unfolding add_divide_distrib diff_divide_distrib
      by (simp add: power2_eq_square)
    also have "...  cmod x < 1  (cmod (x - z'/k))2 = ?cz2 * R * (R + 1) / k2" (is "_  _  ?a2 = ?b")
    proof-
      have *: "R * (1 - (cmod z')2) * k + (cmod z')2 - (cmod z')2 * k = (1 - (cmod z')2)2 * R * (R + 1)"
        by (subst k)+ (simp add: field_simps power2_diff)
      thus ?thesis
        by (subst *, simp)
    qed
    also have "...  cmod x < 1  cmod (x - z'/k) = ?cz * sqrt (R * (R + 1)) / k"
      using R > 0 *[of z'] ** k > 1 z  unit_disc z'
      using real_sqrt_unique[of ?a ?b, symmetric]
      by (auto simp add: real_sqrt_divide real_sqrt_mult power_divide power_mult_distrib)
    finally
    have "of_complex x  poincare_circle z r  cmod x < 1  x  circle (z'/k) (?cz * sqrt(R * (R+1)) / k)"
      unfolding circle_def z' k R
      by simp
    hence "of_complex x  poincare_circle z r  (let (Ze, Re) = poincare_circle_euclidean z r in cmod x < 1  x  circle Ze Re)"
      unfolding poincare_circle_euclidean_def Let_def circle_def
      using z' R k
      by (simp add: field_simps)
    hence "of_complex x  poincare_circle z r  (let (Ze, Re) = poincare_circle_euclidean z r in x  circle Ze Re)"
      using poincare_circle_in_disc[OF r > 0 z  unit_disc]
      by auto
  } note * = this
  show ?thesis
    unfolding Let_def
  proof safe
    fix Ze Re x
    assume "poincare_circle_euclidean z r = (Ze, Re)" "x  circle Ze Re"
    thus "of_complex x  poincare_circle z r"
      using *[of x]
      by simp
  next
    fix Ze Re x
    assume **: "poincare_circle_euclidean z r = (Ze, Re)" "x  poincare_circle z r"
    then obtain x' where x': "x = of_complex x'"
      unfolding poincare_circle_def
      using inf_or_of_complex[of x]
      by auto
    hence "x'  circle Ze Re"
      using *[of x'] **
      by simp
    thus "x  of_complex ` circle Ze Re"
      using x'
      by auto
  qed
qed

subsection ‹Intersection of circles in special positions›

text ‹Two h-circles centered at the x-axis intersect at mutually conjugate points›
lemma intersect_poincare_circles_x_axis:
  assumes z: "is_real z1" and "is_real z2" and "r1 > 0" and "r2 > 0" and
             "-1 < Re z1" and "Re z1 < 1" and "-1 < Re z2" and "Re z2 < 1" and
             "z1  z2"
  assumes x1: "x1  poincare_circle (of_complex z1) r1  poincare_circle (of_complex z2) r2" and
          x2: "x2  poincare_circle (of_complex z1) r1  poincare_circle (of_complex z2) r2" and
              "x1  x2"
  shows "x1 = conjugate x2"
proof-
  have in_disc: "of_complex z1  unit_disc" "of_complex z2  unit_disc"
    using assms
    by (auto simp add: cmod_eq_Re)

  obtain x1' x2' where x': "x1 = of_complex x1'" "x2 = of_complex x2'"
    using x1 x2
    using inf_or_of_complex[of x1] inf_or_of_complex[of x2]
    unfolding poincare_circle_def
    by auto

  obtain Ze1 Re1 where 1: "(Ze1, Re1) = poincare_circle_euclidean (of_complex z1) r1"
    by (metis poincare_circle_euclidean_def)
  obtain Ze2 Re2 where 2: "(Ze2, Re2) = poincare_circle_euclidean (of_complex z2) r2"
    by (metis poincare_circle_euclidean_def)
  have circle: "x1'  circle Ze1 Re1  circle Ze2 Re2"  "x2'  circle Ze1 Re1  circle Ze2 Re2"
    using poincare_circle_is_euclidean_circle[of "of_complex z1" r1]
    using poincare_circle_is_euclidean_circle[of "of_complex z2" r2]
    using assms 1 2 of_complex z1  unit_disc of_complex z2  unit_disc x'
    by auto (metis image_iff of_complex_inj)+

  have "is_real Ze1" "is_real Ze2"
    using 1 2 is_real z1 is_real z2
    by (simp_all add: poincare_circle_euclidean_def Let_def)

  have "Re1 > 0" "Re2 > 0"
    using 1 2 in_disc r1 > 0 r2 > 0
    using poincare_circle_in_disc(2)[of r1 "of_complex z1" Ze1 Re1]
    using poincare_circle_in_disc(2)[of r2 "of_complex z2" Ze2 Re2]
    by auto

  have "Ze1  Ze2"
  proof (rule ccontr)
    assume "¬ ?thesis"
    hence eq: "Ze1 = Ze2" "Re1 = Re2"
      using circle(1)
      unfolding circle_def
      by auto

    let ?A = "Ze1 - Re1" and ?B = "Ze1 + Re1"
    have "?A  circle Ze1 Re1" "?B  circle Ze1 Re1"
      using Re1 > 0
      unfolding circle_def
      by simp_all
    hence "of_complex ?A  poincare_circle (of_complex z1) r1" "of_complex ?B  poincare_circle (of_complex z1) r1"
          "of_complex ?A  poincare_circle (of_complex z2) r2" "of_complex ?B  poincare_circle (of_complex z2) r2"
      using eq
      using poincare_circle_is_euclidean_circle[OF of_complex z1  unit_disc r1 > 0]
      using poincare_circle_is_euclidean_circle[OF of_complex z2  unit_disc r2 > 0]
      using 1 2
      by auto blast+
    hence "poincare_distance (of_complex z1) (of_complex ?A) = poincare_distance (of_complex z1) (of_complex ?B)"
          "poincare_distance (of_complex z2) (of_complex ?A) = poincare_distance (of_complex z2) (of_complex ?B)"
          "-1 < Re (Ze1 - Re1)" "Re (Ze1 - Re1) < 1" "-1 < Re (Ze1 + Re1)" "Re (Ze1 + Re1) < 1"
      using is_real Ze1 is_real Ze2
      unfolding poincare_circle_def
      by (auto simp add: cmod_eq_Re)
    hence "z1 = z2"
      using unique_midpoint_x_axis[of "Ze1 - Re1" "Ze1 + Re1"]
      using is_real Ze1 is_real z1 is_real z2 Re1 > 0 -1 < Re z1 Re z1 < 1 -1 < Re z2 Re z2 < 1
      by auto
    thus False
      using z1  z2
      by simp
  qed

  hence *: "(Re x1')2 + (Im x1')2 - 2 * Re x1' * Ze1 + Ze1 * Ze1 - cor (Re1 * Re1) = 0"
           "(Re x1')2 + (Im x1')2 - 2 * Re x1' * Ze2 + Ze2 * Ze2 - cor (Re2 * Re2) = 0"
           "(Re x2')2 + (Im x2')2 - 2 * Re x2' * Ze1 + Ze1 * Ze1 - cor (Re1 * Re1) = 0"
           "(Re x2')2 + (Im x2')2 - 2 * Re x2' * Ze2 + Ze2 * Ze2 - cor (Re2 * Re2) = 0"
    using circle_equation[of Re1 Ze1] circle_equation[of Re2 Ze2] circle
    using eq_cnj_iff_real[of Ze1] is_real Ze1 Re1 > 0
    using eq_cnj_iff_real[of Ze2] is_real Ze2 Re2 > 0
    using complex_add_cnj[of x1']  complex_add_cnj[of x2']
    using distrib_left[of Ze1 x1' "cnj x1'"] distrib_left[of Ze2 x1' "cnj x1'"]
    using distrib_left[of Ze1 x2' "cnj x2'"] distrib_left[of Ze2 x2' "cnj x2'"]
    by (auto simp add: complex_mult_cnj power2_eq_square field_simps)

  hence "- 2 * Re x1' * Ze1 + Ze1 * Ze1 - cor (Re1 * Re1) = - 2 * Re x1' * Ze2 + Ze2 * Ze2 - cor (Re2 * Re2)"
        "- 2 * Re x2' * Ze1 + Ze1 * Ze1 - cor (Re1 * Re1) = - 2 * Re x2' * Ze2 + Ze2 * Ze2 - cor (Re2 * Re2)"
    by (smt add_diff_cancel_right' add_diff_eq eq_iff_diff_eq_0 minus_diff_eq mult_minus_left of_real_minus)+
  hence "2 * Re x1' * (Ze2 - Ze1) =  (Ze2 * Ze2 - cor (Re2 * Re2)) - (Ze1 * Ze1 - cor (Re1 * Re1))"
        "2 * Re x2' * (Ze2 - Ze1) =  (Ze2 * Ze2 - cor (Re2 * Re2)) - (Ze1 * Ze1 - cor (Re1 * Re1))"
    by simp_all (simp add: field_simps)+
  hence "2 * Re x1' * (Ze2 - Ze1) = 2 * Re x2' * (Ze2 - Ze1)"
    by simp
  hence "Re x1' = Re x2'"
    using Ze1  Ze2
    by simp
  moreover
  hence "(Im x1')2 = (Im x2')2"
    using *(1) *(3)
    by (simp add: is_real Ze1 complex_eq_if_Re_eq)
  hence "Im x1' = Im x2'  Im x1' = -Im x2'"
    using power2_eq_iff
    by blast
  ultimately
  show ?thesis
    using x' x1  x2
    using complex.expand
    by (metis cnj.code complex_surj conjugate_of_complex)
qed


text ‹Two h-circles of the same radius centered at mutually conjugate points intersect at the x-axis›
lemma intersect_poincare_circles_conjugate_centers:
  assumes in_disc: "z1  unit_disc" "z2  unit_disc" and 
          "z1  z2" and "z1 = conjugate z2" and "r > 0" and
          u: "u  poincare_circle z1 r  poincare_circle z2 r"
  shows "is_real (to_complex u)"
proof-
  obtain z1e r1e z2e r2e where
   euclidean: "(z1e, r1e) = poincare_circle_euclidean z1 r"
              "(z2e, r2e) = poincare_circle_euclidean z2 r"
    by (metis poincare_circle_euclidean_def)
  obtain z1' z2' where z': "z1 = of_complex z1'" "z2 = of_complex z2'"
    using inf_or_of_complex[of z1] inf_or_of_complex[of z2] in_disc
    by auto
  obtain u' where u': "u = of_complex u'"
    using u inf_or_of_complex[of u]
    by (auto simp add: poincare_circle_def)
  have "z1' = cnj z2'"
    using z1 = conjugate z2 z'
    by (auto simp add: of_complex_inj)
  moreover
  let ?cz = "1 - (cmod z2')2"
  let ?den = "?cz * (cosh r - 1) / 2 + 1"
  have "?cz > 0"
    using in_disc z'
    by (simp add: cmod_def)
  hence "?den  1"
    using cosh_gt_1[OF r > 0]
    by auto
  hence "?den  0"
    by simp
  hence "cor ?den  0"
    using of_real_eq_0_iff
    by blast
  ultimately
  have "r1e = r2e" "z1e = cnj z2e" "z1e  z2e"
    using z' euclidean z1  z2
    unfolding poincare_circle_euclidean_def Let_def
    by simp_all metis

  hence "u'  circle (cnj z2e) r2e  circle z2e r2e" "z2e  cnj z2e"
    using euclidean u u'
    using poincare_circle_is_euclidean_circle[of z1 r]
    using poincare_circle_is_euclidean_circle[of z2 r]
    using in_disc r > 0
    by auto (metis image_iff of_complex_inj)+
  hence "(cmod (u' - z2e))2 = (cmod(u' - cnj z2e))2"
    by (simp add: circle_def)
  hence "(u' - z2e) * (cnj u' - cnj z2e) = (u' - cnj z2e) * (cnj u' - z2e)"
    by (metis complex_cnj_cnj complex_cnj_diff complex_norm_square)
  hence "(z2e - cnj z2e) * (u' - cnj u') = 0"
    by (simp add: field_simps)
  thus ?thesis
    using u' z2e  cnj z2e eq_cnj_iff_real[of u']
    by simp
qed

subsection ‹Congruent triangles›

text‹For every pair of triangles such that its three pairs of sides are pairwise equal there is an
h-isometry (a unit disc preserving Möbius transform, eventually composed with a conjugation) that
maps one triangle onto the other.›
lemma unit_disc_fix_f_congruent_triangles:
  assumes
    in_disc: "u  unit_disc" "v  unit_disc" "w  unit_disc" and
    in_disc': "u'  unit_disc" "v'  unit_disc" "w'  unit_disc" and 
    d: "poincare_distance u v = poincare_distance u' v'"
       "poincare_distance v w = poincare_distance v' w'"
       "poincare_distance u w = poincare_distance u' w'"
  shows
    " M. unit_disc_fix_f M  M u = u'  M v = v'  M w = w'"
proof (cases "u = v  u = w  v = w")
  case True
  thus ?thesis
    using assms
    using poincare_distance_eq_0_iff[of u' v']
    using poincare_distance_eq_0_iff[of v' w']
    using poincare_distance_eq_0_iff[of u' w']
    using poincare_distance_eq_ex_moebius[of v w v' w']
    using poincare_distance_eq_ex_moebius[of u w u' w']
    using poincare_distance_eq_ex_moebius[of u v u' v']
    by (metis unit_disc_fix_f_def)
next
  case False

  have " w u' v' w'. w  unit_disc  u'  unit_disc  v'  unit_disc  w'  unit_disc  w  u  w  v 
    poincare_distance u v = poincare_distance u' v' 
    poincare_distance v w = poincare_distance v' w' 
    poincare_distance u w = poincare_distance u' w' 
    ( M. unit_disc_fix_f M  M u = u'  M v = v'  M w = w')" (is "?P u v")
  proof (rule wlog_positive_x_axis[where P="?P"])
    show "v  unit_disc" "u  unit_disc"
      by fact+
  next
    show "u  v"
      using False
      by simp
  next
    fix x
    assume x: "is_real x" "0 < Re x" "Re x < 1"

    hence "of_complex x  0h"
      using of_complex_zero_iff[of x]
      by (auto simp add: complex.expand)

    show "?P 0h (of_complex x)"
    proof safe
      fix w u' v' w'
      assume in_disc: "w  unit_disc" "u'  unit_disc" "v'  unit_disc" "w'  unit_disc"
      assume "poincare_distance 0h (of_complex x) = poincare_distance u' v'"
      then obtain M' where M': "unit_disc_fix M'" "moebius_pt M' u' = 0h" "moebius_pt M' v' = (of_complex x)"
        using poincare_distance_eq_ex_moebius[of u' v' "0h" "of_complex x"] in_disc x
        by (auto simp add: cmod_eq_Re)

      let ?w = "moebius_pt M' w'"
      have "?w  unit_disc"
        using unit_disc_fix M' w'  unit_disc
        by simp

      assume "w  0h" "w  of_complex x"
      hence dist_gt_0: "poincare_distance 0h w > 0" "poincare_distance (of_complex x) w > 0"
        using poincare_distance_eq_0_iff[of "0h" w] in_disc poincare_distance_ge0[of "0h" w]
        using poincare_distance_eq_0_iff[of "of_complex x" w] in_disc poincare_distance_ge0[of "of_complex x" w]
        using x
        by (simp_all add: cmod_eq_Re)

      assume "poincare_distance (of_complex x) w = poincare_distance v' w'"
             "poincare_distance 0h w = poincare_distance u' w'"
      hence "poincare_distance 0h ?w = poincare_distance 0h w"
            "poincare_distance (of_complex x) ?w = poincare_distance (of_complex x) w"
        using M'(1) M'(2)[symmetric] M'(3)[symmetric] in_disc
        using unit_disc_fix_preserve_poincare_distance[of M' u' w']
        using unit_disc_fix_preserve_poincare_distance[of M' v' w']
        by simp_all
      hence "?w  poincare_circle 0h (poincare_distance 0h w)  poincare_circle (of_complex x) (poincare_distance (of_complex x) w)"
            "w  poincare_circle 0h (poincare_distance 0h w)  poincare_circle (of_complex x) (poincare_distance (of_complex x) w)"
        using ?w  unit_disc w  unit_disc
        unfolding poincare_circle_def
        by simp_all
      hence "?w = w  ?w = conjugate w"
        using intersect_poincare_circles_x_axis[of 0 x "poincare_distance 0h w" "poincare_distance (of_complex x) w" ?w w] x
        using of_complex x  0h dist_gt_0
        using poincare_distance_eq_0_iff
        by auto
      thus "M. unit_disc_fix_f M  M 0h = u'  M (of_complex x) = v'  M w = w'"
      proof
        assume "moebius_pt M' w' = w"
        thus ?thesis
          using M'
          using moebius_pt_invert[of M' u' "0h"]
          using moebius_pt_invert[of M' v' "of_complex x"]
          using moebius_pt_invert[of M' w' "w"]
          apply (rule_tac x="moebius_pt (-M')" in exI)
          apply (simp add: unit_disc_fix_f_def)
          apply (rule_tac x="-M'" in exI, simp)
          done
      next
        let ?M = "moebius_pt (-M')  conjugate"
        assume "moebius_pt M' w' = conjugate w"
        hence "?M w = w'"
          using moebius_pt_invert[of  M' w' "conjugate w"]
          by simp
        moreover
        have "?M 0h = u'" "?M (of_complex x) = v'"
          using moebius_pt_invert[of M' u' "0h"]
          using moebius_pt_invert[of M' v' "of_complex x"]
          using M' is_real x eq_cnj_iff_real[of x]
          by simp_all
        moreover
        have "unit_disc_fix_f ?M"
          using unit_disc_fix M'
          unfolding unit_disc_fix_f_def
          by (rule_tac x="-M'" in exI, simp)
        ultimately
        show ?thesis
          by blast
      qed
    qed
  next
    fix M u v
    assume 1: "unit_disc_fix M" "u  unit_disc" "v  unit_disc"
    let ?Mu = "moebius_pt M u" and ?Mv = "moebius_pt M v"
    assume 2: "?P ?Mu ?Mv"
    show "?P u v"
    proof safe
      fix w u' v' w'
      let ?Mw = "moebius_pt M w" and ?Mu' = "moebius_pt M u'" and ?Mv' = "moebius_pt M v'" and ?Mw' = "moebius_pt M w'"
      assume "w  unit_disc" "u'  unit_disc" "v'  unit_disc" "w'  unit_disc" "w  u" "w  v"
             "poincare_distance u v = poincare_distance u' v'"
             "poincare_distance v w = poincare_distance v' w'"
             "poincare_distance u w = poincare_distance u' w'"
      then obtain M' where M': "unit_disc_fix_f M'" "M' ?Mu = ?Mu'" "M' ?Mv = ?Mv'" "M' ?Mw = ?Mw'"
        using 1 2[rule_format, of ?Mw ?Mu' ?Mv' ?Mw']
        by auto

      let ?M = "moebius_pt (-M)  M'  moebius_pt M"
      show "M. unit_disc_fix_f M  M u = u'  M v = v'  M w = w'"
      proof (rule_tac x="?M" in exI, safe)
        show "unit_disc_fix_f ?M"
          using M'(1) unit_disc_fix M
          by (subst unit_disc_fix_f_comp, subst unit_disc_fix_f_comp, simp_all)
      next
        show "?M u = u'" "?M v = v'" "?M w = w'"
          using M'
          by auto
      qed
    qed
  qed
  thus ?thesis
    using assms False
    by auto
qed

end