Theory Poincare_Perpendicular
theory Poincare_Perpendicular
  imports Poincare_Lines_Axis_Intersections
begin
section‹H-perpendicular h-lines in the Poincar\'e model›
definition perpendicular_to_x_axis_cmat :: "complex_mat ⇒ bool" where
 [simp]: "perpendicular_to_x_axis_cmat H ⟷ (let (A, B, C, D) = H in is_real B)"
lift_definition perpendicular_to_x_axis_clmat :: "circline_mat ⇒ bool" is perpendicular_to_x_axis_cmat
  done
lift_definition perpendicular_to_x_axis :: "circline ⇒ bool" is perpendicular_to_x_axis_clmat
  by transfer auto
lemma perpendicular_to_x_axis:
  assumes "is_poincare_line H"
  shows "perpendicular_to_x_axis H ⟷ perpendicular x_axis H"
  using assms
  unfolding perpendicular_def
proof (transfer, transfer)
  fix H
  assume hh: "hermitean H ∧ H ≠ mat_zero" "is_poincare_line_cmat H"
  obtain A B C D where *: "H = (A, B, C, D)"
    by (cases H, auto)
  hence "is_real A" "(cmod B)⇧2 > (cmod A)⇧2" "H = (A, B, cnj B, A)"
    using hermitean_elems[of A B C D] hh
    by auto
  thus "perpendicular_to_x_axis_cmat H =
        (cos_angle_cmat (of_circline_cmat x_axis_cmat) (of_circline_cmat H) = 0)"
    using cmod_square[of B] cmod_square[of A]
    by simp
qed
lemma perpendicular_to_x_axis_y_axis:
  assumes "perpendicular_to_x_axis (poincare_line 0⇩h (of_complex z))" "z ≠ 0"
  shows "is_imag z"
  using assms
  by (transfer, transfer, simp)
lemma wlog_perpendicular_axes:
  assumes in_disc: "u ∈ unit_disc" "v ∈ unit_disc" "z ∈ unit_disc"
  assumes perpendicular: "is_poincare_line H1" "is_poincare_line H2" "perpendicular H1 H2"
  assumes "z ∈ circline_set H1 ∩ circline_set H2" "u ∈ circline_set H1" "v ∈ circline_set H2"
  assumes axes: "⋀ x y. ⟦is_real x; 0 ≤ Re x; Re x < 1; is_imag y; 0 ≤ Im y; Im y < 1⟧ ⟹ P 0⇩h (of_complex x) (of_complex y)"
  assumes moebius: "⋀ M u v w. ⟦unit_disc_fix M; u ∈ unit_disc; v ∈ unit_disc; w ∈ unit_disc; P (moebius_pt M u) (moebius_pt M v) (moebius_pt M w) ⟧ ⟹ P u v w"
  assumes conjugate: "⋀ u v w. ⟦u ∈ unit_disc; v ∈ unit_disc; w ∈ unit_disc; P (conjugate u) (conjugate v) (conjugate w) ⟧ ⟹ P u v w"
  shows "P z u v"
proof-
  have "∀ v H1 H2. is_poincare_line H1 ∧ is_poincare_line H2 ∧ perpendicular H1 H2 ∧
                   z ∈ circline_set H1 ∩ circline_set H2 ∧ u ∈ circline_set H1 ∧ v ∈ circline_set H2 ∧ v ∈ unit_disc ⟶ P z u v" (is "?P z u")
  proof (rule wlog_x_axis[where P="?P"])
    fix x
    assume x: "is_real x" "Re x ≥ 0" "Re x < 1"
    have "of_complex x ∈ unit_disc"
      using x
      by (simp add: cmod_eq_Re)
    show "?P 0⇩h (of_complex x)"
    proof safe
      fix v H1 H2
      assume "v ∈ unit_disc"
      then obtain y where y: "v = of_complex y"
        using inf_or_of_complex[of v]
        by auto
      assume 1: "is_poincare_line H1" "is_poincare_line H2" "perpendicular H1 H2"
      assume 2: "0⇩h ∈ circline_set H1" "0⇩h ∈ circline_set H2" "of_complex x ∈ circline_set H1" "v ∈ circline_set H2"
      show "P 0⇩h (of_complex x) v"
      proof (cases "of_complex x = 0⇩h")
        case True
        show "P 0⇩h (of_complex x) v"
        proof (cases "v = 0⇩h")
          case True
          thus ?thesis
            using ‹of_complex x = 0⇩h›
            using axes[of 0 0]
            by simp
        next
          case False
          show ?thesis
          proof (rule wlog_rotation_to_positive_y_axis)
            show "v ∈ unit_disc" "v ≠ 0⇩h"
              by fact+
          next
            fix y
            assume "is_imag y" "0 < Im y" "Im y < 1"
            thus "P 0⇩h (of_complex x) (of_complex y)"
              using x axes[of x y]
              by simp
          next
            fix φ u
            assume "u ∈ unit_disc" "u ≠ 0⇩h"
                   "P 0⇩h (of_complex x) (moebius_pt (moebius_rotation φ) u)"
            thus "P 0⇩h (of_complex x) u"
              using ‹of_complex x = 0⇩h›
              using moebius[of "moebius_rotation φ"  "0⇩h" "0⇩h" u]
              by simp
          qed
        qed
      next
        case False
        hence *: "poincare_line 0⇩h (of_complex x) = x_axis"
          using x poincare_line_0_real_is_x_axis[of "of_complex x"]
          unfolding circline_set_x_axis
          by auto
        hence "H1 = x_axis"
          using unique_poincare_line[of "0⇩h" "of_complex x" H1] 1 2
          using ‹of_complex x ∈ unit_disc› False
          by simp
        have "is_imag y"
        proof (cases "y = 0")
          case True
          thus ?thesis
            by simp
        next
          case False
          hence "0⇩h ≠ of_complex y"
            using of_complex_zero_iff[of y]
            by metis
          hence "H2 = poincare_line 0⇩h (of_complex y)"
            using 1 2 ‹v ∈ unit_disc›
            using unique_poincare_line[of "0⇩h" "of_complex y" H2] y
            by simp
          thus ?thesis
            using 1 ‹H1 = x_axis›
            using perpendicular_to_x_axis_y_axis[of y] False
            using perpendicular_to_x_axis[of H2]
            by simp
        qed
        show "P 0⇩h (of_complex x) v"
        proof (cases "Im y ≥ 0")
          case True
          thus ?thesis
            using axes[of x y] x y ‹is_imag y› ‹v ∈ unit_disc›
            by (simp add: cmod_eq_Im)
        next
          case False
          show ?thesis
          proof (rule conjugate)
            have "Im (cnj y) < 1"
              using ‹v ∈ unit_disc› y ‹is_imag y› eq_minus_cnj_iff_imag[of y]
              by (simp add: cmod_eq_Im)
            thus "P (conjugate 0⇩h) (conjugate (of_complex x)) (conjugate v)"
              using ‹is_real x› eq_cnj_iff_real[of x] y ‹is_imag y›
              using axes[OF x, of "cnj y"] False
              by simp
            show "0⇩h ∈ unit_disc" "of_complex x ∈ unit_disc" "v ∈ unit_disc"
              by (simp, fact+)
          qed
        qed
      qed
    qed
  next
    show "z ∈ unit_disc" "u ∈ unit_disc"
      by fact+
  next
    fix M u v
    assume *: "unit_disc_fix M" "u ∈ unit_disc" "v ∈ unit_disc"
    assume **: "?P (moebius_pt M u) (moebius_pt M v)"
    show "?P u v"
    proof safe
      fix w H1 H2
      assume ***: "is_poincare_line H1" "is_poincare_line H2" "perpendicular H1 H2"
                  "u ∈ circline_set H1" "u ∈ circline_set H2"
                  "v ∈ circline_set H1" "w ∈ circline_set H2" "w ∈ unit_disc"
      thus "P u v w"
        using moebius[of M u v w] *
        using **[rule_format, of "moebius_circline M H1" "moebius_circline M H2" "moebius_pt M w"]
        by simp
    qed
  qed
  thus ?thesis
    using assms
    by blast
qed
lemma :
  assumes in_disc: "u ∈ unit_disc" "v ∈ unit_disc" "w ∈ unit_disc" "z ∈ unit_disc"
  assumes perpendicular: "u ≠ v" "is_poincare_line H" "perpendicular (poincare_line u v) H"
  assumes "z ∈ circline_set (poincare_line u v) ∩ circline_set H" "w ∈ circline_set H"
  assumes axes: "⋀ u v w. ⟦is_real u; 0 < Re u; Re u < 1; is_real v; -1 < Re v; Re v < 1; Re u ≠ Re v; is_imag w; 0 ≤ Im w; Im w < 1⟧ ⟹ P 0⇩h (of_complex u) (of_complex v) (of_complex w)"
  assumes moebius: "⋀ M z u v w. ⟦unit_disc_fix M; u ∈ unit_disc; v ∈ unit_disc; w ∈ unit_disc; z ∈ unit_disc; P (moebius_pt M z) (moebius_pt M u) (moebius_pt M v) (moebius_pt M w) ⟧ ⟹ P z u v w"
  assumes conjugate: "⋀ z u v w. ⟦u ∈ unit_disc; v ∈ unit_disc; w ∈ unit_disc; P (conjugate z) (conjugate u) (conjugate v) (conjugate w) ⟧ ⟹ P z u v w"
  assumes perm: "P z v u w ⟹ P z u v w"
  shows "P z u v w"
proof-
  obtain m n where mn: "m = u ∨ m = v" "n = u ∨ n = v" "m ≠ n" "m ≠ z"
    using ‹u ≠ v›
    by auto
  have "n ∈ circline_set (poincare_line z m)"
    using ‹z ∈ circline_set (poincare_line u v) ∩ circline_set H›
    using mn
    using unique_poincare_line[of z m "poincare_line u v", symmetric] in_disc
    by auto
  have "∀ n. n ∈ unit_disc ∧ m ≠ n ∧ n ∈ circline_set (poincare_line z m) ∧ m ≠ z ⟶ P z m n w" (is "?Q z m w")
  proof (rule wlog_perpendicular_axes[where P="?Q"])
    show "is_poincare_line (poincare_line u v)"
      using ‹u ≠ v›
      by auto
  next
    show "is_poincare_line H"
      by fact
  next
    show "m ∈ unit_disc" "m ∈ circline_set (poincare_line u v)"
      using mn in_disc
      by auto
  next
    show "w ∈ unit_disc" "z ∈ unit_disc"
      by fact+
  next
    show "z ∈ circline_set (poincare_line u v) ∩ circline_set H"
      by fact
  next
    show "perpendicular (poincare_line u v) H"
      by fact
  next
    show "w ∈ circline_set H"
      by fact
  next
    fix x y
    assume xy: "is_real x" "0 ≤ Re x" "Re x < 1" "is_imag y" "0 ≤ Im y" "Im y < 1"
    show "?Q 0⇩h (of_complex x) (of_complex y)"
    proof safe
      fix n
      assume "n ∈ unit_disc" "of_complex x ≠ n"
      assume "n ∈ circline_set (poincare_line 0⇩h (of_complex x))" "of_complex x ≠ 0⇩h"
      hence "n ∈ circline_set x_axis"
        using poincare_line_0_real_is_x_axis[of "of_complex x"] xy
        by (auto simp add: circline_set_x_axis)
      then obtain n' where n': "n = of_complex n'"
        using inf_or_of_complex[of n] ‹n ∈ unit_disc›
        by auto
      hence "is_real n'"
        using ‹n ∈ circline_set x_axis›
        using of_complex_inj
        unfolding circline_set_x_axis
        by auto
      hence "-1 < Re n'" "Re n' < 1"
        using ‹n ∈ unit_disc› n'
        by (auto simp add: cmod_eq_Re)
      have "Re n' ≠ Re x"
        using complex.expand[of n' x] ‹is_real n'› ‹is_real x› ‹of_complex x ≠ n› n'
        by auto
      have "Re x > 0"
        using xy ‹of_complex x ≠ 0⇩h›
        by (cases "Re x = 0", auto simp add: complex.expand)
      show "P 0⇩h (of_complex x) n (of_complex y)"
        using axes[of x n' y] xy n' ‹Re x > 0› ‹is_real n'› ‹-1 < Re n'› ‹Re n' < 1› ‹Re n' ≠ Re x›
        by simp
    qed
  next
    fix M u v w
    assume 1: "unit_disc_fix M" "u ∈ unit_disc" "v ∈ unit_disc" "w ∈ unit_disc"
    assume 2: "?Q (moebius_pt M u) (moebius_pt M v) (moebius_pt M w)"
    show "?Q u v w"
    proof safe
      fix n
      assume "n ∈ unit_disc" "v ≠ n" "n ∈ circline_set (poincare_line u v)" "v ≠ u"
      thus "P u v n w"
        using moebius[of M v n w u] 1 2[rule_format, of "moebius_pt M n"]
        by fastforce
    qed
  next
    fix u v w
    assume 1: "u ∈ unit_disc" "v ∈ unit_disc" "w ∈ unit_disc"
    assume 2: "?Q (conjugate u) (conjugate v) (conjugate w)"
    show "?Q u v w"
    proof safe
      fix n
      assume "n ∈ unit_disc" "v ≠ n" "n ∈ circline_set (poincare_line u v)" "v ≠ u"
      thus "P u v n w"
        using conjugate[of v n w u] 1 2[rule_format, of "conjugate n"]
        using conjugate_inj
        by auto
    qed
  qed
  thus ?thesis
    using mn in_disc ‹n ∈ circline_set (poincare_line z m)› perm
    by auto
qed
lemma perpendicular_to_x_axis_intersects_x_axis:
  assumes "is_poincare_line H" "perpendicular_to_x_axis H"
  shows "intersects_x_axis H"
  using assms hermitean_elems
  by (transfer, transfer, auto simp add: cmod_eq_Re)
lemma perpendicular_intersects:
  assumes "is_poincare_line H1" "is_poincare_line H2"
  assumes "perpendicular H1 H2"
  shows "∃ z. z ∈ unit_disc ∧ z ∈ circline_set H1 ∩ circline_set H2" (is "?P' H1 H2")
proof-
  have "∀ H2. is_poincare_line H2 ∧ perpendicular H1 H2 ⟶ ?P' H1 H2" (is "?P H1")
  proof (rule wlog_line_x_axis)
    show "?P x_axis"
    proof safe
      fix H2
      assume "is_poincare_line H2" "perpendicular x_axis H2"
      thus "∃z. z ∈ unit_disc ∧ z ∈ circline_set x_axis ∩ circline_set H2"
        using perpendicular_to_x_axis[of H2]
        using perpendicular_to_x_axis_intersects_x_axis[of H2]
        using intersects_x_axis_iff[of H2]
        by auto
    qed
  next
    fix M
    assume "unit_disc_fix M"
    assume *: "?P (moebius_circline M H1)"
    show "?P H1"
    proof safe
      fix H2
      assume "is_poincare_line H2" "perpendicular H1 H2"
      then obtain z where "z ∈ unit_disc" "z ∈ circline_set (moebius_circline M H1) ∧ z ∈ circline_set (moebius_circline M H2)"
        using *[rule_format, of "moebius_circline M H2"] ‹unit_disc_fix M›
        by auto
      thus "∃z. z ∈ unit_disc ∧ z ∈ circline_set H1 ∩ circline_set H2"
        using ‹unit_disc_fix M›
        by (rule_tac x="moebius_pt (-M) z" in exI)
           (metis IntI add.inverse_inverse circline_set_moebius_circline_iff moebius_pt_comp_inv_left uminus_moebius_def unit_disc_fix_discI unit_disc_fix_moebius_uminus)
    qed
  next
    show "is_poincare_line H1"
      by fact
  qed
  thus ?thesis
    using assms
    by auto
qed
definition calc_perpendicular_to_x_axis_cmat :: "complex_vec ⇒ complex_mat" where
 [simp]: "calc_perpendicular_to_x_axis_cmat z =
     (let (z1, z2) = z
       in if z1*cnj z2 + z2*cnj z1 = 0 then
          (0, 1, 1, 0)
       else
          let A = z1*cnj z2 + z2*cnj z1;
              B = -(z1*cnj z1 + z2*cnj z2)
           in (A, B, B, A)
     )"
lift_definition calc_perpendicular_to_x_axis_clmat :: "complex_homo_coords ⇒ circline_mat" is calc_perpendicular_to_x_axis_cmat
  by (auto simp add: hermitean_def mat_adj_def mat_cnj_def Let_def split: if_split_asm)
lift_definition calc_perpendicular_to_x_axis :: "complex_homo ⇒ circline" is calc_perpendicular_to_x_axis_clmat
proof (transfer)
  fix z w
  assume "z ≠ vec_zero" "w ≠ vec_zero"
  obtain z1 z2 w1 w2 where zw: "z = (z1, z2)" "w = (w1, w2)"
    by (cases z, cases w, auto)
  assume "z ≈⇩v w"
  then obtain k where *: "k ≠ 0" "w1 = k*z1" "w2 = k*z2"
    using zw
    by auto
  have "w1 * cnj w2 + w2 * cnj w1 = (k * cnj k) * (z1 * cnj z2 + z2 * cnj z1)"
    using *
    by (auto simp add: field_simps)
  moreover
  have "w1 * cnj w1 + w2 * cnj w2 = (k * cnj k) * (z1 * cnj z1 + z2 * cnj z2)"
    using *
    by (auto simp add: field_simps)
  ultimately
  show "circline_eq_cmat (calc_perpendicular_to_x_axis_cmat z) (calc_perpendicular_to_x_axis_cmat w)"
    using zw *
    apply (auto simp add: Let_def)
    apply (rule_tac x="Re (k * cnj k)" in exI, auto simp add: complex.expand field_simps)
    done
qed
lemma calc_perpendicular_to_x_axis:
  assumes "z ≠ of_complex 1" "z ≠ of_complex (-1)"
  shows "z ∈ circline_set (calc_perpendicular_to_x_axis z) ∧
         is_poincare_line (calc_perpendicular_to_x_axis z) ∧
         perpendicular_to_x_axis (calc_perpendicular_to_x_axis z)"
  using assms
  unfolding circline_set_def perpendicular_def
proof (simp, transfer, transfer)
  fix z :: complex_vec
  obtain z1 z2 where z: "z = (z1, z2)"
    by (cases z, auto)
  assume **: "¬ z ≈⇩v of_complex_cvec 1" "¬ z ≈⇩v of_complex_cvec (- 1)"
  show "on_circline_cmat_cvec (calc_perpendicular_to_x_axis_cmat z) z ∧
        is_poincare_line_cmat (calc_perpendicular_to_x_axis_cmat z) ∧
        perpendicular_to_x_axis_cmat (calc_perpendicular_to_x_axis_cmat z)"
  proof (cases "z1*cnj z2 + z2*cnj z1 = 0")
    case True
    thus ?thesis
      using z
      by (simp add: vec_cnj_def hermitean_def mat_adj_def mat_cnj_def mult.commute)
  next
    case False
    hence "z2 ≠ 0"
      using z
      by auto
    hence "Re (z2 * cnj z2) ≠ 0"
      using ‹z2 ≠ 0›
      by (auto simp add: complex.expand)
    have "z1 ≠ -z2 ∧ z1 ≠ z2"
    proof (rule ccontr)
      assume "¬ ?thesis"
      hence "z ≈⇩v of_complex_cvec 1 ∨ z ≈⇩v of_complex_cvec (-1)"
        using z ‹z2 ≠ 0›
        by auto
      thus False
        using **
        by auto
    qed
    let ?A = "z1*cnj z2 + z2*cnj z1" and ?B = "-(z1*cnj z1 + z2*cnj z2)"
    have "Re(z1*cnj z1 + z2*cnj z2) ≥ 0"
      by auto
    hence "Re ?B ≤ 0"
      by (smt uminus_complex.simps(1))
    hence "abs (Re ?B) = - Re ?B"
      by auto
    also have "... = (Re z1)⇧2 + (Im z1)⇧2 + (Re z2)⇧2 + (Im z2)⇧2"
      by (simp add: power2_eq_square[symmetric])
    also have "... > abs (Re ?A)"
    proof (cases "Re ?A ≥ 0")
      case False
      have "(Re z1 + Re z2)⇧2 + (Im z1 + Im z2)⇧2 > 0"
        using ‹z1 ≠ -z2 ∧ z1 ≠ z2›
        by (metis add.commute add.inverse_unique complex_neq_0 plus_complex.code plus_complex.simps)
      thus ?thesis
        using False
        by (simp add: power2_sum power2_eq_square field_simps)
    next
      case True
      have "(Re z1 - Re z2)⇧2 + (Im z1 - Im z2)⇧2 > 0"
        using ‹z1 ≠ -z2 ∧ z1 ≠ z2›
        by (meson complex_eq_iff right_minus_eq sum_power2_gt_zero_iff)
      thus ?thesis
        using True
        by (simp add: power2_sum power2_eq_square field_simps)
    qed
    finally
    have "abs (Re ?B) > abs (Re ?A)"
      .
    moreover
    have "cmod ?B = abs (Re ?B)" "cmod ?A = abs (Re ?A)"
      by (simp_all add: cmod_eq_Re)
    ultimately
    have "(cmod ?B)⇧2 > (cmod ?A)⇧2"
      by (smt power2_le_imp_le)
    thus ?thesis
      using z False
      by (simp_all add: Let_def hermitean_def mat_adj_def mat_cnj_def cmod_eq_Re vec_cnj_def field_simps)
  qed
qed
lemma ex_perpendicular:
  assumes "is_poincare_line H" "z ∈ unit_disc"
  shows "∃ H'. is_poincare_line H' ∧ perpendicular H H' ∧ z ∈ circline_set H'" (is "?P' H z")
proof-
  have "∀ z. z ∈ unit_disc ⟶ ?P' H z" (is "?P H")
  proof (rule wlog_line_x_axis)
    show "?P x_axis"
    proof safe
      fix z
      assume "z ∈ unit_disc"
      then have "z ≠ of_complex 1" "z ≠ of_complex (-1)"
        by auto
      thus "?P' x_axis z"
        using ‹z ∈ unit_disc›
        using calc_perpendicular_to_x_axis[of z] perpendicular_to_x_axis
        by (rule_tac x = "calc_perpendicular_to_x_axis z" in exI, auto)
    qed
  next
    fix M
    assume "unit_disc_fix M"
    assume *: "?P (moebius_circline M H)"
    show "?P H"
    proof safe
      fix z
      assume "z ∈ unit_disc"
      hence "moebius_pt M z ∈ unit_disc"
        using ‹unit_disc_fix M›
        by auto
      then obtain H' where *: "is_poincare_line H'" "perpendicular (moebius_circline M H) H'" "moebius_pt M z ∈ circline_set H'"
        using *
        by auto
      have h: "H = moebius_circline (-M) (moebius_circline M H)"   
        by auto
      show "?P' H z"
        using * ‹unit_disc_fix M›
        apply (subst h)
        apply (rule_tac x="moebius_circline (-M) H'" in exI)
        apply (simp del: moebius_circline_comp_inv_left)
        done
    qed
  qed fact
  thus ?thesis
    using assms
    by simp
qed
lemma :
  assumes "is_poincare_line H" "z ∈ unit_disc"
  shows "∃ H'. is_poincare_line H' ∧ z ∈ circline_set H' ∧ perpendicular H H' ∧
              (∃ z' ∈ unit_disc. z' ∈ circline_set H' ∩ circline_set H)"
  using assms
  using ex_perpendicular[OF assms]
  using perpendicular_intersects[of H]
  by blast
lemma Pythagoras:
  assumes in_disc: "u ∈ unit_disc" "v ∈ unit_disc" "w ∈ unit_disc" "v ≠ w"
  assumes "distinct[u, v, w] ⟶ perpendicular (poincare_line u v) (poincare_line u w)"
  shows "cosh (poincare_distance v w) = cosh (poincare_distance u v) * cosh (poincare_distance u w)" (is "?P' u v w")
proof (cases "distinct [u, v, w]")
  case False
  thus "?thesis"
    using in_disc
    by (auto simp add: poincare_distance_sym)
next
  case True
  have "distinct [u, v, w] ⟶ ?P' u v w" (is "?P u v w")
  proof (rule wlog_perpendicular_axes[where P="?P"])
    show "is_poincare_line (poincare_line u v)" "is_poincare_line (poincare_line u w)"
      using ‹distinct [u, v, w]›
      by simp_all
  next
    show "perpendicular (poincare_line u v) (poincare_line u w)"
      using True assms
      by simp
  next
    show "u ∈ unit_disc" "v ∈ unit_disc" "w ∈ unit_disc"
      by fact+
  next
    show "v ∈ circline_set (poincare_line u v)" "w ∈ circline_set (poincare_line u w)"
         "u ∈ circline_set (poincare_line u v) ∩ circline_set (poincare_line u w)"
      using ‹distinct [u, v, w]›
      by auto
  next
    fix x y
    assume x: "is_real x" "0 ≤ Re x" "Re x < 1"
    assume y: "is_imag y" "0 ≤ Im y" "Im y < 1"
    have "of_complex x ∈ unit_disc" "of_complex y ∈ unit_disc"
      using x y
      by (simp_all add: cmod_eq_Re cmod_eq_Im)
    show "?P 0⇩h (of_complex x) (of_complex y)"
    proof
      assume "distinct [0⇩h, of_complex x, of_complex y]"
      hence "x ≠ 0" "y ≠ 0"
        by auto
      let ?den1 = "1 - (cmod x)⇧2" and ?den2 = "1 - (cmod y)⇧2"
      have "?den1 > 0" "?den2 > 0"
        using x y
        by (simp_all add: cmod_eq_Re cmod_eq_Im abs_square_less_1)
      let ?d1 = "1 + 2 * (cmod x)⇧2 / ?den1"
      have "cosh (poincare_distance 0⇩h (of_complex x)) = ?d1"
        using ‹?den1 > 0›
        using poincare_distance_formula[of "0⇩h" "of_complex x"] ‹of_complex x ∈ unit_disc›
        by simp
      moreover
      let ?d2 = "1 + 2 * (cmod y)⇧2 / ?den2"
      have "cosh (poincare_distance 0⇩h (of_complex y)) = ?d2"
        using ‹?den2 > 0› ‹of_complex y ∈ unit_disc›
        using poincare_distance_formula[of "0⇩h" "of_complex y"]
        by simp
      moreover
      let ?den = "?den1 * ?den2"
      let ?d3 = "1 + 2 * (cmod (x - y))⇧2 / ?den"
      have "cosh (poincare_distance (of_complex x) (of_complex y)) = ?d3"
        using ‹of_complex x ∈ unit_disc› ‹of_complex y ∈ unit_disc›
        using ‹?den1 > 0› ‹?den2 > 0›
        using poincare_distance_formula[of "of_complex x" "of_complex y"]
        by simp
      moreover
      have "?d1 * ?d2 = ?d3"
      proof-
        have "?d3 = ((1 - (cmod x)⇧2) * (1 - (cmod y)⇧2) + 2 * (cmod (x - y))⇧2) / ?den"
          using ‹?den1 > 0› ‹?den2 > 0›
          by (subst add_num_frac, simp, simp)
        also have "... = (Re ((1 - x * cnj x) * (1 - y * cnj y) + 2 * (x - y)*cnj (x - y)) / ?den)"
          using ‹is_real x› ‹is_imag y›
          by ((subst cmod_square)+, simp)
        also have "... = Re (1 + x * cnj x * y * cnj y
                               + x * cnj x - 2 * y * cnj x - 2 * x * cnj y + y * cnj y) / ?den"
          by (simp add: field_simps)
        also have "... = Re ((1 + y * cnj y) * (1 + x * cnj x)) / ?den"
          using ‹is_real x› ‹is_imag y›
          by (simp add: field_simps)
        finally
        show ?thesis
          using ‹?den1 > 0› ‹?den2 > 0›
          apply (subst add_num_frac, simp)
          apply (subst add_num_frac, simp)
          apply simp
          apply (subst cmod_square)+
          apply (simp add: field_simps)
          done
      qed
      ultimately
      show "?P' 0⇩h (of_complex x) (of_complex y)"
        by simp
    qed
  next
    fix M u v w
    assume 1: "unit_disc_fix M" "u ∈ unit_disc" "v ∈ unit_disc" "w ∈ unit_disc"
    assume 2: "?P (moebius_pt M u) (moebius_pt M v) (moebius_pt M w)"
    show "?P u v w"
      using 1 2
      by auto
  next
    fix u v w
    assume 1:  "u ∈ unit_disc" "v ∈ unit_disc" "w ∈ unit_disc"
    assume 2: "?P (conjugate u) (conjugate v) (conjugate w)"
    show "?P u v w"
      using 1 2
      by (auto simp add: conjugate_inj)
  qed
  thus ?thesis
    using True
    by simp
qed
end