Theory MobiusGeometry

theory MobiusGeometry
  imports MobiusGyroVectorSpace
begin

lemma mobius_collinear_u0v':
  assumes "v  0m"
  shows "Mobius_pre_gyrovector_space.collinear u 0m v  ( k::real. to_complex u = k * (to_complex v))"
  unfolding Mobius_pre_gyrovector_space.collinear_def gyroplus_PoincareDisc_def gyroinv_PoincareDisc_def
  using assms
proof transfer
  fix v u
  assume "cmod v < 1" "cmod u < 1" "v  ozero_m'"
  then have "v  0"
    unfolding ozero_m'_def
    by simp
  have "(t. u = (otimes'_k t v) * v / cor (cmod v))  (k :: real. u = k * v)" (is "?lhs  ?rhs")
  proof
    assume ?lhs
    then show ?rhs
      by (metis of_real_divide times_divide_eq_left)
  next
    assume ?rhs
    then obtain k::real where "u = k * v"
      by auto

    moreover

    have "abs (k * cmod v) < 1"
      by (metis cmod u < 1 u = cor k * v abs_mult abs_norm_cancel norm_mult norm_of_real)

    have "artanh (cmod v)  0"
      using v  0
      by (simp add: cmod v < 1 artanh_not_0)
    
    have " t. (otimes'_k t v) / (cmod v) = k"
    proof-
      let ?t = "artanh(k * cmod v) / artanh (cmod v)"
      have "tanh (?t * artanh (cmod v)) = k * cmod v"
        using artanh (cmod v)  0 tanh_artanh[of "k * cmod v"] abs (k * cmod v) < 1
        by (simp add: field_simps)
      then show ?thesis
        by (metis cmod v < 1 v  0 nonzero_mult_div_cancel_right norm_zero otimes'_k_tanh zero_less_norm_iff)
    qed
    ultimately
    show ?lhs
      by auto
  qed
  then show "(ozero_m' = v  (t. u = oplus_m' ozero_m' (otimes' t (oplus_m' (ominus_m' ozero_m') v)))) 
        ( k::real. u = k * v)"
    using v  0
    unfolding oplus_m'_def ozero_m'_def ominus_m'_def otimes'_def
    by simp
qed

lemma mobius_collinear_u0v:
  shows "Mobius_pre_gyrovector_space.collinear x 0m v  
         v = 0m  ( k::real. to_complex x = k * (to_complex v))"
  by (metis Mobius_pre_gyrovector_space.collinear_def mobius_collinear_u0v')

lemma mobius_between_0uv:
  shows "Mobius_pre_gyrovector_space.between 0m u v  
         ( k::real. 0  k  k  1  to_complex u = k * to_complex v)"
proof (cases "v = 0m")
  case True
  then show ?thesis
    using Mobius_pre_gyrovector_space.between_xyx[of "0m" u]
    by auto
next
  case False
  then show ?thesis
    unfolding Mobius_pre_gyrovector_space.between_def gyroplus_PoincareDisc_def gyrozero_PoincareDisc_def gyroinv_PoincareDisc_def
  proof (transfer)
    fix x y
    assume "cmod y < 1" "y  ozero_m'" "cmod x < 1"
    then have "y  0"
      by (simp add: ozero_m'_def)

    have "(t0. t  1  x = cor (otimes'_k t y) * y / cor (cmod y)) =
          (k0. k  1  x = cor k * y)" (is "?lhs = ?rhs")
    proof
      assume ?lhs
      then obtain t where "0  t" "t  1" "x = (otimes'_k t y / cmod y) * y"
        by auto
      moreover
      have "0  otimes'_k t y / cmod y" 
        unfolding otimes'_k_tanh[OF cmod y < 1]
        using cmod y < 1 t  0 tanh_artanh_nonneg 
        by auto
      moreover
      have "otimes'_k t y / cmod y  1"
        unfolding otimes'_k_tanh[OF cmod y < 1]
        using cmod y < 1 y  0 artanh_nonneg t  1
        by (smt (verit, best) divide_le_eq_1 mult_le_cancel_right2 norm_le_zero_iff strict_mono_less_eq tanh_artanh tanh_real_strict_mono)
      ultimately
      show ?rhs
        by auto
    next
      assume ?rhs
      then obtain k::real where "x = k * y"
        by auto

      moreover

      have "abs (k * cmod y) < 1"
        by (metis cmod x < 1 x = cor k * y abs_mult abs_norm_cancel norm_mult norm_of_real)

      have "artanh (cmod y)  0"
        using y  0
        by (simp add: cmod y < 1 artanh_not_0)
    
      have " t. 0  t  t  1  (otimes'_k t y) / (cmod y) = k"
      proof-
        let ?t = "artanh(k * cmod y) / artanh (cmod y)"
        have "tanh (?t * artanh (cmod y)) = k * cmod y"
          using artanh (cmod y)  0 tanh_artanh[of "k * cmod y"] abs (k * cmod y) < 1
          by (simp add: field_simps)
        moreover
        have "?t  0"
          using k0. k  1  x = cor k * y cmod y < 1 x = cor k * y y  0
          by (smt (verit, ccfv_SIG)  artanh_nonneg calculation divide_eq_0_iff mult_right_cancel norm_le_zero_iff of_real_eq_iff tanh_real_nonneg_iff zero_le_mult_iff)
        moreover
        have "?t  1"
          using k0. k  1  x = cor k * y cmod y < 1 x = cor k * y y  0
          by (smt (verit, ccfv_SIG)  artanh_monotone artanh_nonneg calculation(1) less_divide_eq_1 nonzero_divide_eq_eq of_real_eq_iff tanh_artanh_nonneg zero_less_norm_iff)
        ultimately show ?thesis
          by (metis cmod y < 1 y  0 nonzero_mult_div_cancel_right norm_zero otimes'_k_tanh zero_less_norm_iff)
      qed
      ultimately
      show ?lhs
        by auto
    qed
    then show "(t0. t  1 
                       x = oplus_m' ozero_m' (otimes' t (oplus_m' (ominus_m' ozero_m') y))) =
               (k0. k  1  x = cor k * y)"
      using y  0
      unfolding ozero_m'_def oplus_m'_def ominus_m'_def otimes'_def
      by simp
  qed
qed

(* ------------------------------------------------------------------- *)

abbreviation distance_m_expr :: "complex  complex  real" where
  "distance_m_expr u v  1 + 2 * (cmod (u - v))2 / ((1 - (cmod u)2) * (1 - (cmod v)2))"

definition distance_m :: "complex  complex  real" where 
  "distance_m u v = arcosh (distance_m_expr u v)"

lemma arcosh_artanh_lemma:
  shows "(cmod (1 - cnj u * v))2 - (cmod (u - v))2 = (1 - (cmod u)2) * (1 - (cmod v)2)"
proof-
  have "cor ((cmod (1 - cnj u * v))2 - (cmod (u - v))2) = cor ((1 - (cmod u)2) * (1 - (cmod v)2))"
    unfolding of_real_diff of_real_mult complex_norm_square
    by (simp add: field_simps)
  then show ?thesis
    using of_real_eq_iff by blast
qed

lemma distance_m_expr_ge_1:
  fixes u v :: complex
  assumes "cmod u < 1" "cmod v < 1"
  shows "distance_m_expr u v  1"
proof-
  have "(cmod (u-v))2  0"
    using zero_le_power2 by blast
  moreover
  have "(1 - (cmod u)2) *(1 - (cmod v)2) > 0"
    using assms
    using cmod_def by force
  ultimately 
  show ?thesis
    by simp
qed

lemma arcosh_artanh:
  fixes u v :: complex
  assumes "cmod u <1" "cmod v < 1"
  shows "arcosh (distance_m_expr u v) =
         2 * artanh (cmod ((u-v) / (1 - (cnj u)*v)))"
proof-
  let ?u = "1 - (cmod u)2" and ?v = "1 - (cmod v)2" and ?uv = "(cmod (u - v))2"

  have "arcosh (distance_m_expr u v) =
        ln (distance_m_expr u v + sqrt ((distance_m_expr u v)2 - 1))"
    using arcosh_real_def[OF distance_m_expr_ge_1[OF assms]]
    by simp
  also have " = ln (((cmod (1 - cnj u * v))2 + 2 * cmod (1 - cnj u * v) * cmod (u - v) + ?uv) /
                      (?u * ?v))"
  proof-
    have "distance_m_expr u v = (?u * ?v + 2 * ?uv) / (?u * ?v)"
    proof-
      have "?u  0" "?v  0"
        using assms
        by (metis abs_norm_cancel order_less_irrefl real_sqrt_abs real_sqrt_one right_minus_eq)+  
      then show ?thesis 
        by (simp add: add_divide_distrib)
    qed
    then have *: "distance_m_expr u v = ((cmod (1 - cnj u * v))2 + ?uv) / (?u * ?v)"
      using assms 
      by (smt (verit, ccfv_SIG) arcosh_artanh_lemma)
   
    have "sqrt ((distance_m_expr u v)2 - 1) =
          sqrt (4 * (?uv / (?u * ?v)) + 4 * (?uv / (?u * ?v))2)"
      by (smt (verit, best) add_divide_distrib four_x_squared inner_real_def one_power2 power2_diff real_inner_1_right)
    also have " = sqrt (4 * ?uv * (1 / (?u * ?v) + (cmod (u - v) / (?u * ?v))2))" (is "?lhs = sqrt (4 * ?A * ?B)")
      by (simp add: field_simps)
    also have " = sqrt (4 * ?uv * (?u * ?v + ?uv) / (?u * ?v)2)"
    proof-
      have "?B = (?u * ?v + ?uv) / (?u * ?v)2"
        by (simp add: power_divide power2_eq_square add_divide_distrib)
      then show ?thesis
        by simp
    qed
    also have " = 2 * cmod (u - v) * sqrt (?u * ?v + ?uv) / (?u * ?v)"
      using assms
      by (smt (verit, ccfv_SIG) four_x_squared mult_nonneg_nonneg norm_not_less_zero one_power2 power_mono real_root_divide real_root_mult real_sqrt_unique sqrt_def)
    also have "... = 2 * cmod (u - v) / (?u * ?v) * sqrt (?u * ?v + ?uv)"
      by simp
    finally have **: "sqrt ((distance_m_expr u v)2 - 1) =  
                      2 * cmod (u - v) * cmod (1 - cnj u * v) / (?u * ?v)"
      by (smt (verit, del_insts) arcosh_artanh_lemma norm_ge_zero real_sqrt_abs times_divide_eq_left)

    show ?thesis
      using * **
      by (smt (verit, best) add_divide_distrib power2_sum)
  qed
  also have " = ln ((1 + cmod (u - v) / cmod (1 - cnj u * v)) /
                      (1 - cmod (u - v) / cmod (1 - cnj u * v)))" (is "?lhs = ln (?nom / ?den)")
  proof-
    have *: "?nom = (cmod (u - v) + cmod (1 - cnj u * v)) / cmod (1 - cnj u * v)"
      using assms
      by (metis (no_types, opaque_lifting) add_diff_cancel_left' add_divide_distrib complex_mod_cnj diff_diff_eq2 diff_zero divide_self_if mult_closed_for_unit_disc norm_eq_zero norm_one order_less_irrefl)
    then have **: "?den = (cmod (1 - cnj u * v) - cmod (u - v)) / cmod (1 - cnj u * v)"
      using assms
      by (smt (verit, ccfv_SIG) add_divide_distrib)
    have "?nom / ?den =
          (cmod (u - v) + cmod (1 - cnj u * v)) / (cmod (1 - cnj u * v) - cmod (u - v))"
      using * **
      by force
    also have " = (cmod (1 - cnj u * v) + cmod (u - v))2 / (?u * ?v)" (is "?lhs = ?rhs")
    proof-
      let ?e = "cmod (1 - cnj u * v) + cmod (u - v)"
      have "?lhs = ?lhs * ?e/?e"
        by fastforce
      moreover
      have "(cmod (1 - cnj u * v) - cmod (u - v)) * ?e = ?u * ?v"
        using arcosh_artanh_lemma
        by (simp add: mult.commute power2_eq_square square_diff_square_factored)
      ultimately
      show ?thesis
        by (simp add: power2_eq_square)
    qed
    finally
    show ?thesis
      by (simp add: power2_eq_square field_simps)
  qed
  finally show ?thesis
    unfolding artanh_def
    by (simp add: norm_divide)
qed

definition distancem :: "PoincareDisc  PoincareDisc  real" where
 "distancem u v = 2 * artanh (Mobius_pre_gyrovector_space.distance u v)"

lemma distancem_equiv:
  shows "distancem u v = distance_m (to_complex u) (to_complex v)"
proof-
  have "(m u m v) =
         (cmod ((to_complex u - to_complex v) / (1 - cnj (to_complex u) * (to_complex v))))"
    by transfer (simp add: oplus_m'_def ominus_m'_def norm_divide norm_minus_commute)
  then show ?thesis
  unfolding distancem_def distance_m_def Mobius_pre_gyrovector_space.distance_def gyroinv_PoincareDisc_def gyroplus_PoincareDisc_def
  using arcosh_artanh norm_lt_one norm_p.rep_eq
  by force
qed

definition congm :: "PoincareDisc  PoincareDisc  PoincareDisc  PoincareDisc  bool" where
  "congm a b c d  distancem a b = distancem c d"

end