Theory HOL-Examples.Gauss_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 = R⇧2 + I⇧2›
      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 = R⇧2 + I⇧2›)
      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 ‹… < Y⇧2›
      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 < Y⇧2› .
    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