Theory Digits_int

theory Digits_int
  imports 
    Complex_Main
begin
section ‹Representation of Integers in Different Number Systems›
text ‹This file is an adaption of Van_der_Waerden/Digits.thy› for representation of the
 Integers (instead of the natural numbers) in different number systems.
The main difference is the integer input in the function digit›.›
text ‹First, we look at some useful lemmas for splitting sums. ›
lemma split_sum_first_elt_less: assumes "n<m" 
  shows "(i{n..<m}. f i) = f n + (i{Suc n ..<m}. f i)"
  using sum.atLeast_Suc_lessThan assms by blast

lemma split_sum_mid_less: assumes "i<(n::nat)"
  shows "(j<n. f j) = (j<i. f j) + (j=i..<n. f j)"
proof -
  have "(j<n. f j) = (j{..<i}  {i..<n}. f j)"
    using i < n by (intro sum.cong) auto
  also have " = (j<i. f j) + (j=i..<n. f j)"
    by (subst sum.union_disjoint) auto
  finally show "(j<n. f j) = (j<i. f j) + (j=i..<n. f j)" .
qed

text ‹In order to use representation of numbers in a basis base› and to calculate the conversion 
to and from integers, we introduce the following locale.›
locale digits =
  fixes base :: int
  assumes base_pos: "base > 0"
begin

text ‹Conversion from basis base to integers: from_digits n d›

\begin{tabular}{lcp{8cm}}
  n:& nat›& length of representation in basis base\\
  d:& nat ⇒ nat›& function of digits in basis base where d i› is the $i$-th digit in basis base\\
  output:& nat›& natural number corresponding to $d(n-1) \dots d(0)$ as integer\\
\end{tabular}
›
fun from_digits :: "nat  (nat  nat)  nat" where
  "from_digits 0 d = 0"
| "from_digits (Suc n) d = d 0 + nat base * from_digits n (d  Suc)"

text ‹Alternative definition using sum:›
lemma from_digits_altdef: "from_digits n d = (i<n. d i * nat base ^ i)"
  by (induction n d rule: from_digits.induct)
     (auto simp add: sum.lessThan_Suc_shift o_def sum_distrib_left 
       sum_distrib_right mult_ac simp del: sum.lessThan_Suc)

lemma int_from_digits:
  "int (from_digits n d) = (i<n. int (d i) * base ^ i)"
unfolding from_digits_altdef using base_pos by auto

text ‹Digit in basis base of some integer number: digit x i›

\begin{tabular}{lcp{8cm}}
  x:& int›& integer\\
  i:& nat›& index\\
  output:& int›& $i$-th digit of representation in basis base of $x$\\
\end{tabular}
›
fun digit :: "int  nat  int" where
  "digit x 0 = ¦x¦ mod base"
| "digit x (Suc i) = digit (¦x¦ div base) i"

text ‹Alternative definition using divisor and modulo:›
lemma digit_altdef: "digit x i = ( ¦x¦ div (base ^ i)) mod base"
proof (induction x i rule: digit.induct)
  case (2 x i)
  show ?case by (subst digit.simps(2), subst 2) (smt (verit, ccfv_SIG) base_pos 
        pos_imp_zdiv_neg_iff power.simps(2) zdiv_zmult2_eq zero_less_power)
qed simp

text ‹Every digit must be smaller that the base.›
lemma digit_less_base: "digit x i < base"
  using base_pos by (auto simp: digit_altdef)

text ‹A representation in basis base› of length $n$ must be less than $base› ^ n$.›
lemma from_digits_less: 
  assumes "i<n. d i < base" 
  shows "from_digits n d < base ^ n"
using assms proof (induct n d rule: from_digits.induct)
  case (2 n d)
  have "from_digits n (d  Suc)  base ^ n -1" using 2 
    by (simp add: "2.hyps")
  moreover have "d 0  base -1" using 2 by simp
  ultimately have "d 0 + base * from_digits n (d  Suc)  
      base - 1 + base * (base^(n) - 1)" 
    by (smt (verit, ccfv_SIG) base_pos mult_less_cancel_left_pos)
  then show "from_digits (Suc n) d < base ^ Suc n" 
    using base_pos by (simp add: right_diff_distrib)
qed auto


text ‹Lemmas for mod› and div› in number systems of basis base›:›
lemma mod_base:  assumes "i. i<n  d i < base" "n>0"
  shows "from_digits n d mod base = d 0 "
proof -
  have "(i<n. d i * base ^ i) mod base = 
          (i<n. d i * base ^ i mod base) mod base"  
  by (subst mod_sum_eq[symmetric]) simp
  then show ?thesis using assms 
    sum.lessThan_Suc_shift[of "(λi. d i * base ^ i mod base)" "n-1"]
    int_from_digits by simp
qed

lemma mod_base_i:  
  assumes "i. i<n  (d i ::nat) < base" "n>0" "i<n"
  shows "(j=i..<n. d j * base ^ (j-i)) mod base = d i "
proof -
  have eq: "(j=i..<n. d j * base ^ (j-i)) mod base = 
        (j=i..<n. d j * base ^ (j-i) mod base) mod base"  
    by (subst mod_sum_eq[symmetric]) simp
  then show ?thesis  using assms 
    split_sum_first_elt_less[where  f = "(λj. d j * base ^ (j-i) mod base)"]
    int_from_digits by auto
qed


lemma div_base_i: 
  assumes "i. i<n  (d i::nat) < base" "n>0" "i<n"
  shows "from_digits n d div (base ^i) = (j=i..<n. d j * base ^ (j-i))"
  unfolding int_from_digits proof -
  have base_exp: "base^(j) =  base^(j-i) * base^i" 
    if "j{i..<n}" for j 
    by (metis Nat.add_diff_assoc2 add_diff_cancel_right' atLeastLessThan_iff 
        power_add that)
  have first:"(j<i. d j * base ^ j)< base ^ i" 
    using assms from_digits_less[where n="i"] 
    unfolding int_from_digits by auto
  have ge_0: "0  (j<i. int (d j) * base ^ j)" using base_pos
  by (metis int_from_digits of_nat_0_le_iff)
  have eq: "(j<n. d j * base ^ j) = 
          (j<i. d j * base ^ j) + (j=i..<n. d j * base ^ j)" 
    using assms split_sum_mid_less[where f="(λj. d j * base^j)"] by auto
  have split_sum: "(j<n. d j * base ^ j) = 
      (j<i. d j * base ^ j) + base^i * (j=i..<n. d j * base ^ (j-i))"
    unfolding eq using base_exp mult.assoc sum_distrib_right
    by (smt (z3) mult.commute sum.cong)
  show "(i<n. d i * base ^ i) div base ^ i = 
             (j = i..<n. d j * base ^ (j - i))" 
    unfolding split_sum using base_pos first div_pos_pos_trivial[OF ge_0 first]
    by (subst div_mult_self2, auto)
qed



text ‹Conversions are inverse to each other.›
lemma digit_from_digits:
  assumes "j. j<n  d j < base" "n>0" "i<n"
  shows   "digit (from_digits n d) i = d i"
  using assms proof (cases "i=0")
  case True
  then show ?thesis
  using assms(1) assms(3) mod_base by force
next
  case False
  have "from_digits n d div base^i mod base = d i" 
    using assms by (auto simp add: div_base_i mod_base_i) 
  then show "digit (from_digits n d) i = d i" 
    unfolding digit_altdef by auto
qed

lemma div_distrib: assumes "i<n" 
  shows "(a*base^n + b) div base^i mod base = b div base^i mod base"
proof -
  have "base^i dvd (a*base^n)" using assms 
    by (simp add: le_imp_power_dvd)
  moreover have "a*base^n div base^i mod base = 0" 
    by (metis Suc_leI assms dvd_imp_mod_0 dvd_mult 
        dvd_mult_imp_div le_imp_power_dvd power_Suc)
  ultimately show ?thesis
    by (metis add.right_neutral div_mult_mod_eq 
        div_plus_div_distrib_dvd_left mod_mult_self3)
qed


lemma(in digits) digits_eq_0:
  assumes "x = 0"
  shows "digit x i = 0"
by (simp add: assms digit_altdef)
end


lemma split_digits_eq_zero:
  assumes "a + base * b = 0" "¦a¦<base" "(base::int)>2"
  shows "a = 0  b=0"
using assms proof (cases "b = 0")
  case True
  then show "a=0  b=0" using assms by auto
next
  case False
  then have "¦b¦  1" by auto
  then have "¦a¦ < ¦base * b¦" using assms(2) assms(3)
    by (subst abs_mult) (smt (verit) mult_le_cancel_left1)
  moreover have "¦a¦ = ¦base * b¦" using assms(1) by auto
  ultimately have False by auto
  then show ?thesis by auto
qed


lemma respresentation_in_basis_eq_zero:
  assumes "(i<n. c i * base^i) = 0" "(base::int) > 2" "i. i<n  ¦c i¦ < base" "i<n"
  shows "c i = 0"
using assms proof (induction n arbitrary: i c)
  case 0
  then show ?case by auto
next
  case (Suc n)
  have eq_0: "c 0 + base * (i<n. c (i+1) * base ^ i) = 0" 
    using Suc(2) unfolding sum.lessThan_Suc_shift power_Suc sum.cong[of "{..<n}" "{..<n}" 
      "(λi. c (Suc i) * (base * base ^ i))" "(λi. base * (c (n + 1) * base ^ n))"]
    by (subst sum_distrib_left)(metis (no_types, lifting) Suc_eq_plus1 mult.left_commute 
      mult_cancel_left1 power_0 sum.cong)
  have "c 0 = 0 " and right: "(i<n. c (i+1) * base ^ i) = 0" 
    using split_digits_eq_zero[OF eq_0 Suc(4)[of 0] Suc(3)] by auto
  have lt_n: "c (i + 1) = 0" if "i<n" for i using Suc(4)
    by (subst Suc(1)[OF right 2<base _ i<n], auto) 
  then show ?case
  proof (cases "i=0")
    case False
    then show ?thesis using Suc(5) lt_n less_Suc_eq_0_disj by auto
  qed (use c 0 = 0 in auto)
qed

end