Theory HOL-Examples.Gauss_Numbers

(*   Author:      Florian Haftmann, TU Muenchen; based on existing material on complex numbers›
*)

section ‹Gauss Numbers: integral gauss numbers›

theory Gauss_Numbers
  imports "HOL-Library.Centered_Division"
begin

codatatype gauss = Gauss (Re: int) (Im: int)

lemma gauss_eqI [intro?]:
  ‹x = y› if ‹Re x = Re y› ‹Im x = Im y›
  by (rule gauss.expand) (use that in simp)

lemma gauss_eq_iff:
  ‹x = y ⟷ Re x = Re y ∧ Im x = Im y›
  by (auto intro: gauss_eqI)


subsection ‹Basic arithmetic›

instantiation gauss :: comm_ring_1
begin

primcorec zero_gauss :: ‹gauss›
  where
    ‹Re 0 = 0›
  | ‹Im 0 = 0›

primcorec one_gauss :: ‹gauss›
  where
    ‹Re 1 = 1›
  | ‹Im 1 = 0›

primcorec plus_gauss :: ‹gauss ⇒ gauss ⇒ gauss›
  where
    ‹Re (x + y) = Re x + Re y›
  | ‹Im (x + y) = Im x + Im y›

primcorec uminus_gauss :: ‹gauss ⇒ gauss›
  where
    ‹Re (- x) = - Re x›
  | ‹Im (- x) = - Im x›

primcorec minus_gauss :: ‹gauss ⇒ gauss ⇒ gauss›
  where
    ‹Re (x - y) = Re x - Re y›
  | ‹Im (x - y) = Im x - Im y›

primcorec times_gauss :: ‹gauss ⇒ gauss ⇒ gauss›
  where
    ‹Re (x * y) = Re x * Re y - Im x * Im y›
  | ‹Im (x * y) = Re x * Im y + Im x * Re y›

instance
  by standard (simp_all add: gauss_eq_iff algebra_simps)

end

lemma of_nat_gauss:
  ‹of_nat n = Gauss (int n) 0›
  by (induction n) (simp_all add: gauss_eq_iff)

lemma numeral_gauss:
  ‹numeral n = Gauss (numeral n) 0›
proof -
  have ‹numeral n = (of_nat (numeral n) :: gauss)›
    by simp
  also have ‹… = Gauss (of_nat (numeral n)) 0›
    by (simp add: of_nat_gauss)
  finally show ?thesis
    by simp
qed

lemma of_int_gauss:
  ‹of_int k = Gauss k 0›
  by (simp add: gauss_eq_iff of_int_of_nat of_nat_gauss)

lemma conversion_simps [simp]:
  ‹Re (numeral m) = numeral m›
  ‹Im (numeral m) = 0›
  ‹Re (of_nat n) = int n›
  ‹Im (of_nat n) = 0›
  ‹Re (of_int k) = k›
  ‹Im (of_int k) = 0›
  by (simp_all add: numeral_gauss of_nat_gauss of_int_gauss)

lemma gauss_eq_0:
  ‹z = 0 ⟷ (Re z)2 + (Im z)2 = 0›
  by (simp add: gauss_eq_iff sum_power2_eq_zero_iff)

lemma gauss_neq_0:
  ‹z ≠ 0 ⟷ (Re z)2 + (Im z)2 > 0›
  by (simp add: gauss_eq_0 sum_power2_ge_zero less_le)

lemma Re_sum [simp]:
  ‹Re (sum f s) = (∑x∈s. Re (f x))›
  by (induct s rule: infinite_finite_induct) auto

lemma Im_sum [simp]:
  ‹Im (sum f s) = (∑x∈s. Im (f x))›
  by (induct s rule: infinite_finite_induct) auto

instance gauss :: idom
proof
  fix x y :: gauss
  assume ‹x ≠ 0› ‹y ≠ 0›
  then show ‹x * y ≠ 0›
    by (simp_all add: gauss_eq_iff)
      (smt (verit, best) mult_eq_0_iff mult_neg_neg mult_neg_pos mult_pos_neg mult_pos_pos)
qed



subsection ‹The Gauss Number $i$›

primcorec imaginary_unit :: gauss  (‹𝗂›)
  where
    ‹Re 𝗂 = 0›
  | ‹Im 𝗂 = 1›

lemma Gauss_eq:
  ‹Gauss a b = of_int a + 𝗂 * of_int b›
  by (simp add: gauss_eq_iff)

lemma gauss_eq:
  ‹a = of_int (Re a) + 𝗂 * of_int (Im a)›
  by (simp add: gauss_eq_iff)

lemma gauss_i_not_zero [simp]:
  ‹𝗂 ≠ 0›
  by (simp add: gauss_eq_iff)

lemma gauss_i_not_one [simp]:
  ‹𝗂 ≠ 1›
  by (simp add: gauss_eq_iff)

lemma gauss_i_not_numeral [simp]:
  ‹𝗂 ≠ numeral n›
  by (simp add: gauss_eq_iff)

lemma gauss_i_not_neg_numeral [simp]:
  ‹𝗂 ≠ - numeral n›
  by (simp add: gauss_eq_iff)

lemma i_mult_i_eq [simp]:
  ‹𝗂 * 𝗂 = - 1›
  by (simp add: gauss_eq_iff)

lemma gauss_i_mult_minus [simp]:
  ‹𝗂 * (𝗂 * x) = - x›
  by (simp flip: mult.assoc)

lemma i_squared [simp]:
  ‹𝗂2 = - 1›
  by (simp add: power2_eq_square)

lemma i_even_power [simp]:
  ‹𝗂 ^ (n * 2) = (- 1) ^ n›
  unfolding mult.commute [of n] power_mult by simp

lemma Re_i_times [simp]:
  ‹Re (𝗂 * z) = - Im z›
  by simp

lemma Im_i_times [simp]:
  ‹Im (𝗂 * z) = Re z›
  by simp

lemma i_times_eq_iff:
  ‹𝗂 * w = z ⟷ w = - (𝗂 * z)›
  by auto

lemma is_unit_i [simp]:
  ‹𝗂 dvd 1›
  by (rule dvdI [of _ _ ‹- 𝗂›]) simp

lemma gauss_numeral [code_post]:
  ‹Gauss 0 0 = 0›
  ‹Gauss 1 0 = 1›
  ‹Gauss (- 1) 0 = - 1›
  ‹Gauss (numeral n) 0 = numeral n›
  ‹Gauss (- numeral n) 0 = - numeral n›
  ‹Gauss 0 1 = 𝗂›
  ‹Gauss 0 (- 1) = - 𝗂›
  ‹Gauss 0 (numeral n) = numeral n * 𝗂›
  ‹Gauss 0 (- numeral n) = - numeral n * 𝗂›
  ‹Gauss 1 1 = 1 + 𝗂›
  ‹Gauss (- 1) 1 = - 1 + 𝗂›
  ‹Gauss (numeral n) 1 = numeral n + 𝗂›
  ‹Gauss (- numeral n) 1 = - numeral n + 𝗂›
  ‹Gauss 1 (- 1) = 1 - 𝗂›
  ‹Gauss 1 (numeral n) = 1 + numeral n * 𝗂›
  ‹Gauss 1 (- numeral n) = 1 - numeral n * 𝗂›
  ‹Gauss (- 1) (- 1) = - 1 - 𝗂›
  ‹Gauss (numeral n) (- 1) = numeral n - 𝗂›
  ‹Gauss (- numeral n) (- 1) = - numeral n - 𝗂›
  ‹Gauss (- 1) (numeral n) = - 1 + numeral n * 𝗂›
  ‹Gauss (- 1) (- numeral n) = - 1 - numeral n * 𝗂›
  ‹Gauss (numeral m) (numeral n) = numeral m + numeral n * 𝗂›
  ‹Gauss (- numeral m) (numeral n) = - numeral m + numeral n * 𝗂›
  ‹Gauss (numeral m) (- numeral n) = numeral m - numeral n * 𝗂›
  ‹Gauss (- numeral m) (- numeral n) = - numeral m - numeral n * 𝗂›
  by (simp_all add: gauss_eq_iff)


subsection ‹Gauss Conjugation›

primcorec cnj :: ‹gauss ⇒ gauss›
  where
    ‹Re (cnj z) = Re z›
  | ‹Im (cnj z) = - Im z›

lemma gauss_cnj_cancel_iff [simp]:
  ‹cnj x = cnj y ⟷ x = y›
  by (simp add: gauss_eq_iff)

lemma gauss_cnj_cnj [simp]:
  ‹cnj (cnj z) = z›
  by (simp add: gauss_eq_iff)

lemma gauss_cnj_zero [simp]:
  ‹cnj 0 = 0›
  by (simp add: gauss_eq_iff)

lemma gauss_cnj_zero_iff [iff]:
  ‹cnj z = 0 ⟷ z = 0›
  by (simp add: gauss_eq_iff)

lemma gauss_cnj_one_iff [simp]:
  ‹cnj z = 1 ⟷ z = 1›
  by (simp add: gauss_eq_iff)

lemma gauss_cnj_add [simp]:
  ‹cnj (x + y) = cnj x + cnj y›
  by (simp add: gauss_eq_iff)

lemma cnj_sum [simp]:
  ‹cnj (sum f s) = (∑x∈s. cnj (f x))›
  by (induct s rule: infinite_finite_induct) auto

lemma gauss_cnj_diff [simp]:
  ‹cnj (x - y) = cnj x - cnj y›
  by (simp add: gauss_eq_iff)

lemma gauss_cnj_minus [simp]:
  ‹cnj (- x) = - cnj x›
  by (simp add: gauss_eq_iff)

lemma gauss_cnj_one [simp]:
  ‹cnj 1 = 1›
  by (simp add: gauss_eq_iff)

lemma gauss_cnj_mult [simp]:
  ‹cnj (x * y) = cnj x * cnj y›
  by (simp add: gauss_eq_iff)

lemma cnj_prod [simp]:
  ‹cnj (prod f s) = (∏x∈s. cnj (f x))›
  by (induct s rule: infinite_finite_induct) auto

lemma gauss_cnj_power [simp]:
  ‹cnj (x ^ n) = cnj x ^ n›
  by (induct n) simp_all

lemma gauss_cnj_numeral [simp]:
  ‹cnj (numeral w) = numeral w›
  by (simp add: gauss_eq_iff)

lemma gauss_cnj_of_nat [simp]:
  ‹cnj (of_nat n) = of_nat n›
  by (simp add: gauss_eq_iff)

lemma gauss_cnj_of_int [simp]:
  ‹cnj (of_int z) = of_int z›
  by (simp add: gauss_eq_iff)

lemma gauss_cnj_i [simp]:
  ‹cnj 𝗂 = - 𝗂›
  by (simp add: gauss_eq_iff)

lemma gauss_add_cnj:
  ‹z + cnj z = of_int (2 * Re z)›
  by (simp add: gauss_eq_iff)

lemma gauss_diff_cnj:
  ‹z - cnj z = of_int (2 * Im z) * 𝗂›
  by (simp add: gauss_eq_iff)

lemma gauss_mult_cnj:
  ‹z * cnj z = of_int ((Re z)2 + (Im z)2)›
  by (simp add: gauss_eq_iff power2_eq_square)

lemma cnj_add_mult_eq_Re:
  ‹z * cnj w + cnj z * w = of_int (2 * Re (z * cnj w))›
  by (simp add: gauss_eq_iff)

lemma gauss_In_mult_cnj_zero [simp]:
  ‹Im (z * cnj z) = 0›
  by simp


subsection ‹Algebraic division›

instantiation gauss :: idom_modulo
begin

primcorec divide_gauss :: ‹gauss ⇒ gauss ⇒ gauss›
  where
    ‹Re (x div y) = (Re x * Re y + Im x * Im y) cdiv ((Re y)2 + (Im y)2)›
  | ‹Im (x div y) = (Im x * Re y - Re x * Im y) cdiv ((Re y)2 + (Im y)2)›

primcorec modulo_gauss :: ‹gauss ⇒ gauss ⇒ gauss›
  where
    ‹Re (x mod y) = Re x -
      ((Re x * Re y + Im x * Im y) cdiv ((Re y)2 + (Im y)2) * Re y -
       (Im x * Re y - Re x * Im y) cdiv ((Re y)2 + (Im y)2) * Im y)›
  | ‹Im (x mod y) = Im x -
      ((Re x * Re y + Im x * Im y) cdiv ((Re y)2 + (Im y)2) * Im y +
       (Im x * Re y - Re x * Im y) cdiv ((Re y)2 + (Im y)2) * Re y)›

instance proof
  fix x y :: gauss
  show ‹x div 0 = 0›
    by (simp add: gauss_eq_iff)
  show ‹x * y div y = x› if ‹y ≠ 0›
  proof -
    define Y where ‹Y = (Re y)2 + (Im y)2›
    moreover have ‹Y > 0›
      using that by (simp add: gauss_eq_0 less_le Y_def)
    have *: ‹Im y * (Im y * Re x) + Re x * (Re y * Re y) = Re x * Y›
      ‹Im x * (Im y * Im y) + Im x * (Re y * Re y) = Im x * Y›
      ‹(Im y)2 + (Re y)2 = Y›
      by (simp_all add: power2_eq_square algebra_simps Y_def)
    from ‹Y > 0› show ?thesis
      by (simp add: gauss_eq_iff algebra_simps) (simp add: * nonzero_mult_cdiv_cancel_right)
  qed
  show ‹x div y * y + x mod y = x›
    by (simp add: gauss_eq_iff)
qed

end

instantiation gauss :: euclidean_ring
begin

definition euclidean_size_gauss :: ‹gauss ⇒ nat›
  where ‹euclidean_size x = nat ((Re x)2 + (Im x)2)›

instance proof
  show ‹euclidean_size (0::gauss) = 0›
    by (simp add: euclidean_size_gauss_def)
  show ‹euclidean_size (x mod y) < euclidean_size y› if ‹y ≠ 0› for x y :: gauss
  proof-
    define X and Y and R and I
      where ‹X = (Re x)2 + (Im x)2› and ‹Y = (Re y)2 + (Im y)2›
        and ‹R = Re x * Re y + Im x * Im y› and ‹I = Im x * Re y - Re x * Im y›
    with that have ‹0 < Y› and rhs: ‹int (euclidean_size y) = Y›
      by (simp_all add: gauss_neq_0 euclidean_size_gauss_def)
    have ‹X * Y = R2 + I2›
      by (simp add: R_def I_def X_def Y_def power2_eq_square algebra_simps)
    let ?lhs = ‹X - I * (I cdiv Y) - R * (R cdiv Y)
        - I cdiv Y * (I cmod Y) - R cdiv Y * (R cmod Y)›
    have ‹?lhs = X + Y * (R cdiv Y) * (R cdiv Y) + Y * (I cdiv Y) * (I cdiv Y)
        - 2 * (R cdiv Y * R + I cdiv Y * I)›
      by (simp flip: minus_cmod_eq_mult_cdiv add: algebra_simps)
    also have ‹… = (Re (x mod y))2 + (Im (x mod y))2›
      by (simp add: X_def Y_def R_def I_def algebra_simps power2_eq_square)
    finally have lhs: ‹int (euclidean_size (x mod y)) = ?lhs›
      by (simp add: euclidean_size_gauss_def)
    have ‹?lhs * Y = (I cmod Y)2 + (R cmod Y)2›
      apply (simp add: algebra_simps power2_eq_square ‹X * Y = R2 + I2›)
      apply (simp flip: mult.assoc add.assoc minus_cmod_eq_mult_cdiv)
      apply (simp add: algebra_simps)
      done
    also have ‹… ≤ (Y div 2)2 + (Y div 2)2›
      by (rule add_mono) (use ‹Y > 0› abs_cmod_less_equal [of Y] in ‹simp_all add: power2_le_iff_abs_le›)
    also have ‹… < Y2›
      using ‹Y > 0› by (cases ‹Y = 1›) (simp_all add: power2_eq_square mult_le_less_imp_less flip: mult.assoc)
    finally have ‹?lhs * Y < Y2› .
    with ‹Y > 0› have ‹?lhs < Y›
      by (simp add: power2_eq_square)
    then have ‹int (euclidean_size (x mod y)) < int (euclidean_size y)›
      by (simp only: lhs rhs)
    then show ?thesis
      by simp
  qed
  show ‹euclidean_size x ≤ euclidean_size (x * y)› if ‹y ≠ 0› for x y :: gauss
  proof -
    from that have ‹euclidean_size y > 0›
      by (simp add: euclidean_size_gauss_def gauss_neq_0)
    then have ‹euclidean_size x ≤ euclidean_size x * euclidean_size y›
      by simp
    also have ‹… = nat (((Re x)2 + (Im x)2) * ((Re y)2 + (Im y)2))›
      by (simp add: euclidean_size_gauss_def nat_mult_distrib)
    also have ‹… = euclidean_size (x * y)›
      by (simp add: euclidean_size_gauss_def eq_nat_nat_iff) (simp add: algebra_simps power2_eq_square)
    finally show ?thesis .
  qed
qed

end

end