Theory Bit_Counting
theory Bit_Counting
imports Digit_Expansions.Binary_Operations "HOL-Computational_Algebra.Primes"
begin
section ‹The Coding Technique›
subsection ‹Counting bits and number of carries›
text ‹Count the number of bits in the binary expansion of n›
definition bit_set :: "nat ⇒ nat set" where
"bit_set n = {i. n ¡ i = 1}"
definition count_bits :: "nat ⇒ nat" where
"count_bits n = card (bit_set n)"
text ‹Count the number of carries in the binary addition of a and b›
definition carry_set :: "nat ⇒ nat ⇒ nat set" where
"carry_set a b = {i. bin_carry a b i = 1}"
definition count_carries :: "nat ⇒ nat ⇒ nat" where
"count_carries a b = card (carry_set a b)"
text ‹This shows that ‹{@const count_bits}› is well defined›
lemma bit_set_subset: "bit_set n ⊆ {..<n}"
proof -
{ fix i assume "i ≥ n"
hence "n ¡ i = 0" unfolding nth_bit_def by (simp add: order_le_less_trans) }
thus ?thesis
unfolding bit_set_def
by (metis (mono_tags, lifting) lessThan_iff dual_order.strict_iff_not mem_Collect_eq
nle_le subsetI zero_neq_one)
qed
corollary bit_set_finite: "finite (bit_set n)"
using bit_set_subset finite_subset by fastforce
text ‹We can be more precise when we know how many bits n requires›
lemma bit_set_subset_variant: "n < 2^k ⟹ bit_set n ⊆ {..<k}"
proof -
assume "n < 2^k"
hence "i ≥ k ⟹ n ¡ i = 0" for i
by (metis add.commute add_cancel_left_right aux1_digit_lt_linear aux1_digit_wise_equiv mult_0)
thus ?thesis
unfolding bit_set_def
by (metis (mono_tags, lifting) One_nat_def lessThan_iff less_le_not_le
linorder_neqE_nat mem_Collect_eq nat.simps(3) order_refl subsetI)
qed
corollary count_bits_def_sum: "n < 2^k ⟹ count_bits n = (∑i<k. n ¡ i)"
proof -
assume assm: "n < 2^k"
have "(∑i<k. n ¡ i) = (∑i∈{..<k}. of_bool (n ¡ i = 1))"
by (smt (verit, del_insts) sum.cong not_mod_2_eq_1_eq_0 nth_bit_def of_bool_eq(1) of_bool_eq(2))
also have "... = card ({..<k} ∩ bit_set n)"
unfolding bit_set_def using Groups_Big.sum_of_bool_eq finite_lessThan by simp
also have "... = count_bits n"
unfolding count_bits_def using bit_set_subset_variant[OF assm] by (simp add: inf.absorb2)
finally show ?thesis by simp
qed
corollary count_bits_bounded: "n < 2^k ⟹ count_bits n ≤ k"
unfolding count_bits_def using bit_set_subset_variant
by (metis card_lessThan card_mono finite_lessThan)
text ‹The following lemma shows that ‹{@const count_carries}› is well defined›
lemma carry_set_subset: "carry_set a b ⊆ {..max a b}"
proof -
{ fix i assume "i > max a b"
hence "i > a" and "i > b"
by simp_all
have "a < 2^(i-1)" using `i > a`
by (metis Suc_diff_1 Suc_leI gr_implies_not0 less_exp not_le_imp_less order_less_le_trans)
moreover have "b < 2^(i-1)" using `i > b`
by (metis Suc_diff_1 Suc_leI gr_implies_not0 less_exp not_le_imp_less order_less_le_trans)
ultimately have "a + b < 2^(Suc (i-1))"
by simp
hence ab_bound: "a + b < 2^i"
using `i > a` by simp
have "(a mod 2^i) + (b mod 2^i) = a + b"
using `i > a` `i > b` by (metis less_exp less_imp_add_positive mod_less trans_less_add1)
hence "bin_carry a b i = 0"
unfolding bin_carry_def using ab_bound by simp }
thus ?thesis
unfolding carry_set_def
by (metis (mono_tags, lifting) atMost_iff mem_Collect_eq subsetI
verit_comp_simplify1(3) zero_neq_one)
qed
corollary carry_set_finite: "finite (carry_set a b)"
using carry_set_subset finite_subset by blast
text ‹We can be more precise when we know how many bits $a+b$ requires›
lemma carry_set_subset_variant: "a + b < 2^k ⟹ carry_set a b ⊆ {..<k}"
proof -
assume assm: "a + b < 2^k"
hence "i ≥ k ⟹ bin_carry a b i = 0" for i
unfolding bin_carry_def
using Euclidean_Rings.div_eq_0_iff add_increasing add_increasing2 div_exp_eq
le_antisym le_eq_less_or_eq le_iff_add mod_eq_self_iff_div_eq_0 zero_le
by (smt (verit, ccfv_threshold) div_greater_zero_iff)
thus ?thesis
unfolding carry_set_def
by (metis (full_types, lifting) lessThan_iff linorder_not_less mem_Collect_eq
subsetI zero_neq_one)
qed
corollary count_carries_def_sum: "a + b < 2^k ⟹ count_carries a b = (∑i<k. bin_carry a b i)"
proof -
assume assm: "a + b < 2^k"
have "(∑i<k. bin_carry a b i) = (∑i∈{..<k}. of_bool (bin_carry a b i = 1))"
using sum.cong bin_carry_def
by (smt (verit, best) bin_carry_bounded not_mod_2_eq_0_eq_1 of_bool_eq(1) of_bool_eq(2))
also have "... = card ({..<k} ∩ carry_set a b)"
unfolding carry_set_def using Groups_Big.sum_of_bool_eq finite_lessThan by simp
also have "... = count_carries a b"
unfolding count_carries_def using carry_set_subset_variant[OF assm] by (simp add: inf.absorb2)
finally show ?thesis by auto
qed
text ‹Some elementary properties of ‹{@const count_bits}› and ‹{@const count_carries}››
lemma bit_set_0[simp]: "bit_set 0 = {}"
unfolding bit_set_def nth_bit_def by simp
corollary count_bits_0[simp]: "count_bits 0 = 0"
unfolding count_bits_def by simp
lemma bit_set_1[simp]: "bit_set 1 = {0}"
proof -
have bit_one: "1 ¡ i = (if i = 0 then 1 else 0)" for i
unfolding nth_bit_def
using div_eq_0_iff bits_one_mod_two_eq_one gr_zeroI mod_0
one_div_two_eq_zero one_less_power power_0 zero_neq_numeral
by (metis div_by_1)
thus ?thesis unfolding bit_set_def bit_one by simp
qed
corollary count_bits_1[simp]: "count_bits 1 = 1"
unfolding count_bits_def bit_set_1 by simp
lemma carry_set_n0[simp]: "carry_set n 0 = {}"
unfolding carry_set_def bin_carry_def by simp
lemma carry_set_0n[simp]: "carry_set 0 n = {}"
unfolding carry_set_def bin_carry_def by simp
corollary count_carries_n0[simp]: "count_carries n 0 = 0"
unfolding count_carries_def by simp
corollary count_carries_0n[simp]: "count_carries 0 n = 0"
unfolding count_carries_def by simp
lemma carry_set_sym: "carry_set a b = carry_set b a"
unfolding carry_set_def bin_carry_def by (simp add: add.commute)
corollary count_carries_sym: "count_carries a b = count_carries b a"
unfolding count_carries_def by (simp add: carry_set_sym)
lemma aux_geometric_sum:
"(x::nat) > 1 ⟹ (x-1) * (∑i<n. x^i) = x^n - 1"
proof (induct n)
case 0 show ?case using lessThan_0 by (simp add: algebra_simps)
next
case (Suc n)
have "(x-1) * (∑i<Suc n. x^i) = (x-1) * (∑i<n. x^i) + (x-1) * x^n"
using add_mult_distrib2 by auto
also have "... = x^n - 1 + x^(Suc n) - x^n"
using Suc less_imp_Suc_add by fastforce
also have "... = x^(Suc n) - 1"
using Suc.prems by auto
finally show ?case .
qed
lemma aux_digit_sum_bound:
assumes "1 < (b::nat)" and "∀i<q. f i < b"
shows "(∑i<q. f i * b^i) < b^q"
proof -
have "i < q ⟹ f i * b^i ≤ (b-1) * b^i" for i
by (metis assms le_add_diff_inverse less_Suc_eq_le less_imp_le_nat mult_le_mono1 plus_1_eq_Suc)
hence "(∑i<q. f i * b^i) ≤ (∑i<q. (b-1) * b^i)"
by (meson lessThan_iff sum_mono)
also have "... = b^q - 1"
using sum_distrib_left aux_geometric_sum assms(1) by metis
finally show ?thesis
by (metis assms(1) le_add_diff_inverse le_imp_less_Suc less_imp_le_nat one_le_power
plus_1_eq_Suc)
qed
lemma carry_set_same[simp]: "carry_set a a = Suc ` bit_set a"
(is "?A = ?B")
proof -
have 0: "bin_carry a a (Suc i) = a ¡ i" for i
unfolding bin_carry_def nth_bit_def
by (metis One_nat_def add.commute add_self_div_2 div_exp_eq div_exp_mod_exp_eq plus_1_eq_Suc
power_Suc0_right)
have 1: "?A ⊆ ?B"
proof
fix i assume i_def: "i ∈ carry_set a a"
hence "i > 0"
unfolding carry_set_def bin_carry_def using gr0I by force
hence "a ¡ (i-1) = 1"
using i_def 0 unfolding carry_set_def
by (metis (mono_tags, lifting) One_nat_def Suc_pred mem_Collect_eq)
thus "i ∈ ?B"
using bit_set_def Suc_pred' ‹0 < i› by blast
qed
have 2: "?B ⊆ ?A"
proof
fix i assume i_def: "i ∈ ?B"
hence "a ¡ (i-1) = 1"
using bit_set_def by auto
hence "bin_carry a a i = 1"
using 0 i_def by fastforce
thus "i ∈ ?A"
using carry_set_def by simp
qed
from 1 2 show ?thesis by simp
qed
corollary count_carries_same[simp]: "count_carries a a = count_bits a"
using count_carries_def count_bits_def carry_set_same by (simp add: card_image)
lemma bit_set_pow2[simp]: "bit_set (2^k) = {k}"
proof -
have "(2^k) ¡ i = (if i = k then 1 else 0)" for i
unfolding nth_bit_def
by (metis Suc_mask_eq_exp bit_exp_iff bit_iff_odd nat.simps(3) not_mod_2_eq_1_eq_0
odd_iff_mod_2_eq_one possible_bit_def)
thus ?thesis unfolding bit_set_def by simp
qed
corollary count_bits_pow2[simp]: "count_bits (2^k) = 1"
unfolding count_bits_def by simp
lemma bit_set_block_ones[simp]: "bit_set (2^k - 1) = {..<k}"
proof -
have bit: "(2^k - 1) ¡ i = (if i < k then 1 else 0)" for i
unfolding nth_bit_def
by (meson even_decr_exp_div_exp_iff' mod2_eq_if not_less)
hence "bit_set (2^k - 1) = bit_set (2^k-1) ∩ {..<k}"
unfolding count_bits_def using bit_set_subset_variant by (simp add: inf_absorb1)
also have "... = {i. (2^k-1) ¡ i = 1 ∧ i < k}"
unfolding bit_set_def by (simp add: Collect_conj_eq lessThan_def)
also have "... = {i. i < k}"
unfolding bit by simp
finally show ?thesis
by auto
qed
corollary count_bits_block_ones[simp]: "count_bits (2^k-1) = k"
unfolding count_bits_def bit_set_block_ones by simp
text ‹The binary complement of a number with k bits›
lemma nth_bit_complement:
"a < 2^k ⟹ (2^k-1-a) ¡ i = (if i < k then 1 - (a ¡ i) else 0)"
proof (cases "k = 0")
case True assume "a < 2^k"
hence "a = 0" using True by simp
thus ?thesis using True nth_bit_def by simp
next
case False assume assm: "a < 2^k"
have 0: "∀i. (a ¡ i) * 2^i ≤ 2^i" using nth_bit_bounded by simp
have 1: "∀i. 1 - (a ¡ i) < 2^(Suc 0)" by auto
have 2: "k = Suc (k-1)" using False by simp
have "2^k-1-a = (2^k - 1) - (∑i<k. (a ¡ i) * 2^i)"
using digit_sum_repr[OF assm] by simp
also have "... = (∑i<k. 2^i) - (∑i<k. (a ¡ i) * 2^i)"
using aux_geometric_sum[of "2::nat"] by simp
also have "... = (∑i<k. 2^i - (a ¡ i) * 2^i)"
using sum_diff_distrib[OF 0] .
also have "... = (∑i<k. (1 - a ¡ i) * 2^i)"
using nth_bit_bounded
by (metis (no_types, opaque_lifting) cancel_comm_monoid_add_class.diff_cancel diff_zero
mult.commute mult.right_neutral mult_zero_right not_mod_2_eq_1_eq_0 nth_bit_def)
finally have complement: "2^k-1-a = (∑i=0..k-1. (1 - a ¡ i) * 2^i)"
using 2 by (metis atLeast0LessThan atLeastLessThanSuc_atLeastAtMost)
have "(2^k-1-a) ¡ i = (if i ≤ k-1 then 1 - a ¡ i else 0)"
using nth_digit_gen_power_series[OF 1]
unfolding complement nth_digit_base2_equiv by simp
thus ?thesis using False by simp
qed
lemma bit_set_complement:
"a < 2^k ⟹ bit_set (2^k-1-a) = {..<k} - bit_set a"
proof
assume assm: "a < 2^k"
show "bit_set (2^k-1-a) ⊆ {..<k} - bit_set a"
proof
fix i assume i_def: "i ∈ bit_set (2^k-1-a)"
hence "i < k"
by (metis (mono_tags, lifting) One_nat_def assm bit_set_def mem_Collect_eq
nat.simps(3) nth_bit_complement)
thus "i ∈ {..<k} - bit_set a"
using nth_bit_complement i_def unfolding bit_set_def by (simp add: assm)
qed
next
assume assm: "a < 2^k"
show "{..<k} - bit_set a ⊆ bit_set (2^k-1-a)"
proof
fix i assume "i ∈ {..<k} - bit_set a"
thus "i ∈ bit_set (2^k-1-a)"
using bit_set_def nth_bit_complement[OF assm] by (simp add: nth_bit_def)
qed
qed
corollary count_bits_complement:
"a < 2^k ⟹ count_bits (2^k-1-a) = k - count_bits a"
unfolding count_bits_def using bit_set_complement bit_set_subset_variant
by (simp add: bit_set_finite card_Diff_subset)
lemma carry_set_pow2_block_ones[simp]: "carry_set (2^k) (2^k-1) = {}"
proof -
have "bin_carry (2^k) (2^k-1) i = 0" for i
proof (induct i)
case 0 show ?case unfolding bin_carry_def by simp
next
case (Suc i)
have "i < k ⟹ (2^k) ¡ i + (2^k-1) ¡ i = 1"
using bit_set_pow2 bit_set_block_ones nth_bit_bounded unfolding bit_set_def
by (metis (mono_tags, lifting) One_nat_def Suc_eq_plus1 lessThan_iff mem_Collect_eq
nat_less_le not_mod_2_eq_1_eq_0 nth_bit_def singletonD)
moreover have "i = k ⟹ (2^k) ¡ i + (2^k-1) ¡ i = 1"
using bit_set_pow2 bit_set_block_ones nth_bit_bounded unfolding bit_set_def
by (simp add: nth_bit_def)
moreover have "i > k ⟹ (2^k) ¡ i + (2^k-1) ¡ i = 0"
using nth_bit_bounded unfolding bit_set_def
using add.right_neutral diff_less div_less less_exp linorder_not_less
nat_less_le not_mod_2_eq_1_eq_0 nth_bit_def odd_iff_mod_2_eq_one power_one_right
power_strict_increasing_iff
by (metis even_decr_exp_div_exp_iff')
ultimately show ?case
using sum_carry_formula Suc by force
qed
thus ?thesis unfolding carry_set_def by simp
qed
corollary count_carries_pow2_block_ones[simp]: "count_carries (2^k) (2^k-1) = 0"
unfolding count_carries_def carry_set_pow2_block_ones by simp
lemma bit_set_add_shift:
"a < 2^k ⟹ bit_set (a + b * 2^k) = bit_set a ∪ ((+) k) ` bit_set b"
(is "_ ⟹ ?A = ?B")
proof
assume assm: "a < 2^k" show "?A ⊆ ?B"
proof
fix i assume "i ∈ ?A"
hence i_def: "(a + b * 2^k) ¡ i = 1"
using bit_set_def by simp
{ assume "i < k"
hence "a ¡ i = 1"
using aux2_digit_sum_repr[OF assm] i_def by (simp add: add.commute)
hence "i ∈ bit_set a"
using bit_set_def by simp }
note 0 = this
{ assume "i ≥ k"
hence "(b * 2^k) ¡ i = 1"
using aux1_digit_lt_linear[OF assm] i_def by (simp add: add.commute)
hence "b ¡ (i-k) = 1"
using aux_digit_shift by (metis ‹k ≤ i› le_add_diff_inverse2)
hence "i ∈ ((+) k) ` bit_set b"
using ‹k ≤ i› bit_set_def image_iff by fastforce }
note 1 = this
from 0 1 show "i ∈ ?B" by force
qed
next
assume assm: "a < 2^k" show "?B ⊆ ?A"
proof
fix i assume "i ∈ ?B"
hence i_def: "(a ¡ i = 1 ∧ i < k) ∨ (b ¡ (i-k) = 1 ∧ i ≥ k)"
using bit_set_subset_variant[OF assm] unfolding bit_set_def by auto
thus "i ∈ ?A"
proof
assume "a ¡ i = 1 ∧ i < k"
hence "(a + b * 2^k) ¡ i = 1"
using aux2_digit_sum_repr[OF assm] by (simp add: add.commute)
thus ?thesis
using bit_set_def by simp
next
assume "b ¡ (i-k) = 1 ∧ i ≥ k"
hence "(a + b * 2^k) ¡ i = 1"
using aux1_digit_lt_linear[OF assm] aux_digit_shift
by (metis add.commute le_add_diff_inverse2)
thus ?thesis
using bit_set_def by simp
qed
qed
qed
corollary count_bits_add_shift:
"a < 2^k ⟹ count_bits (a + b * 2^k) = count_bits a + count_bits b"
proof -
assume assm: "a < 2^k"
have disjoint: "bit_set a ∩ ((+) k) ` bit_set b = {}"
proof -
{ fix i assume "i ∈ bit_set a ∩ ((+) k) ` bit_set b"
hence "i < k ∧ i ≥ k"
using bit_set_subset_variant[OF assm] by blast
hence "False" by auto }
thus ?thesis by blast
qed
have "count_bits (a + b * 2^k) = count_bits a + card (((+) k) ` bit_set b)"
unfolding count_bits_def using bit_set_add_shift[OF assm] disjoint
by (simp add: bit_set_finite card_Un_Int)
also have "... = count_bits a + count_bits b"
unfolding count_bits_def by (metis card_image inj_on_add)
finally show ?thesis .
qed
corollary count_bits_even[simp]: "count_bits (2*n) = count_bits n"
using count_bits_add_shift count_bits_0
by (metis add_lessD1 comm_monoid_add_class.add_0 less_exp mult.commute power_one_right)
corollary count_bits_odd[simp]: "count_bits (2*n+1) = 1 + count_bits n"
using count_bits_add_shift count_bits_1
by (metis add.commute less_exp mult.commute power_one_right)
lemma count_bits_digitwise:
assumes "1 ≤ k" and "∀i<q. f i < 2^k"
shows "count_bits (∑i<q. f i * (2^k)^i) = (∑i<q. count_bits (f i))"
using assms
proof (induct q)
case 0 show ?case by simp
next
case (Suc q)
have 0: "1 < (2::nat)^k"
using assms(1) by (meson dual_order.strict_trans2 less_exp)
hence bound: "(∑i<q. f i * (2^k)^i) < 2^(k*q)"
using aux_digit_sum_bound[OF 0] Suc.prems(2) power_mult
by (metis (full_types) less_Suc_eq_le less_imp_le_nat)
have "count_bits (∑i<Suc q. f i * (2^k)^i) =
count_bits ((∑i<q. f i * (2^k)^i) + f q * 2^(k*q))"
by (simp add: power_mult)
also have "... = count_bits (∑i<q. f i * (2^k)^i) + count_bits (f q)"
using count_bits_add_shift[OF bound] by simp
also have "... = (∑i<Suc q. count_bits (f i ))"
using Suc by simp
finally show ?case .
qed
lemma count_carries_count_bits:
"count_bits (a+b) + count_carries a b = count_bits a + count_bits b"
proof -
obtain k where k_def: "a + b < 2^k" using less_exp by blast
have 0: "(∑i<k. bin_carry a b (i+1)) = (∑i<k. bin_carry a b i)"
proof -
have carry_0: "bin_carry a b 0 = 0"
using bin_carry_def by auto
have carry_k: "bin_carry a b k = 0"
by (metis (no_types, lifting) div_eq_0_iff add.commute add_lessD1
bin_carry_def k_def mod_less)
have "(∑i<k. bin_carry a b (i+1)) = (∑i=1..<k+1. bin_carry a b i)"
by (metis add_0 atLeast0LessThan sum.shift_bounds_nat_ivl)
also have "... = bin_carry a b 0 + (∑i=1..<k. bin_carry a b i)+ bin_carry a b k"
using carry_0 by auto
also have "... = (∑i<k. bin_carry a b i)"
using carry_k by (simp add: atLeast0LessThan carry_0 sum_shift_lb_Suc0_0_upt)
finally show ?thesis .
qed
have "(a + b) ¡ i + 2 * bin_carry a b (i+1) = a ¡ i + b ¡ i + bin_carry a b i" for i
using sum_carry_formula sum_digit_formula by simp
hence "(∑i<k. (a + b) ¡ i + 2 * bin_carry a b (i+1)) = (∑i<k. a ¡ i + b ¡ i + bin_carry a b i)"
using sum.cong by presburger
hence "(∑i<k. (a + b) ¡ i) + 2 * (∑i<k. bin_carry a b (i+1)) =
(∑i<k. a ¡ i) + (∑i<k. b ¡ i) + (∑i<k. bin_carry a b i)"
using sum.distrib sum_distrib_left by (smt (z3) sum.cong)
hence "count_bits (a+b) + 2 * count_carries a b = count_bits a + count_bits b + count_carries a b"
using 0 count_bits_def_sum count_carries_def_sum k_def by (metis add.commute add_lessD1)
thus ?thesis by simp
qed
corollary count_bits_add_le: "count_bits (a+b) ≤ count_bits a + count_bits b"
using count_carries_count_bits by (metis le_add1)
text ‹‹{@const count_carries}› can be defined in term of ‹{@const count_bits}››
corollary count_carries_def_alt:
"count_carries a b = count_bits a + count_bits b - count_bits (a+b)"
using count_carries_count_bits by (metis diff_add_inverse)
lemma count_bits_sum_le:
assumes S_fin: "finite S"
shows "count_bits (sum f S) ≤ (∑i∈S. count_bits (f i))"
proof (induct rule: finite_induct[OF S_fin])
case 1 show ?case by simp
next
case (2 x S)
have "count_bits (sum f (insert x S)) = count_bits (f x + sum f S)"
by (simp add: "2.hyps"(1) "2.hyps"(2))
also have "... ≤ count_bits (f x) + count_bits (sum f S)"
using count_bits_add_le by simp
also have "... ≤ count_bits (f x) + (∑i∈S. count_bits (f i))"
by (simp add: "2.hyps"(3))
also have "... = (∑i∈insert x S. count_bits (f i))"
by (simp add: "2.hyps"(1) "2.hyps"(2))
finally show ?case .
qed
lemma aux1_carry_set_add_shift:
"a < 2^k ⟹ c < 2^k ⟹ i ≤ k ⟹ bin_carry (a+b*2^k) (c+d*2^k) i = bin_carry a c i"
proof (induct i)
case 0 thus ?case unfolding bin_carry_def by simp
next
case (Suc i)
have "bin_carry (a+b*2^k) (c+d*2^k) (Suc i) =
((a+b*2^k) ¡ i + (c+d*2^k) ¡ i + bin_carry (a+b*2^k) (c+d*2^k) i) div 2"
using sum_carry_formula by simp
also have "... = (a ¡ i + c ¡ i + bin_carry a c i) div 2"
using Suc aux2_digit_sum_repr by (simp add: add.commute)
also have "... = bin_carry a c (Suc i)"
using sum_carry_formula by simp
finally show ?case .
qed
lemma aux2_carry_set_add_shift:
"a < 2^k ⟹ c < 2^k ⟹ k ≤ i ⟹ bin_carry (a+b*2^k) (c+d*2^k) i ≥ bin_carry b d (i-k)"
proof -
assume assm1: "a < 2^k" and assm2: "c < 2^k" and i_def: "k ≤ i"
show ?thesis
proof (induct rule: nat_induct_at_least[OF i_def])
case 1 show ?case using bin_carry_def assm1 assm2 by simp
next
case (2 i)
have "bin_carry (a + b * 2 ^ k) (c + d * 2 ^ k) (Suc i) =
((a+b*2^k) ¡ i + (c+d*2^k) ¡ i + bin_carry (a+b*2^k) (c+d*2^k) i) div 2"
using sum_carry_formula by simp
also have "... ≥ (b ¡ (i-k) + d ¡ (i-k) + bin_carry b d (i-k)) div 2"
using 2 aux1_digit_lt_linear aux_digit_shift assm1 assm2
by (smt (verit, ccfv_SIG) add.commute add_le_mono div_le_mono le_add_diff_inverse2 order.refl)
finally show ?case
using sum_carry_formula 2 by (metis Suc_diff_le Suc_eq_plus1)
qed
qed
lemma aux3_carry_set_add_shift:
"a + c < 2^k ⟹ k ≤ i ⟹ bin_carry (a+b*2^k) (c+d*2^k) i = bin_carry b d (i-k)"
proof -
assume assm: "a + c < 2^k"
assume i_def: "k ≤ i"
show ?thesis
proof (induct rule: nat_induct_at_least[OF i_def])
case 1 show ?case using bin_carry_def assm by simp
next
case (2 i)
have "bin_carry (a + b * 2 ^ k) (c + d * 2 ^ k) (Suc i) =
((a+b*2^k) ¡ i + (c+d*2^k) ¡ i + bin_carry (a+b*2^k) (c+d*2^k) i) div 2"
using sum_carry_formula by simp
also have "... = (b ¡ (i-k) + d ¡ (i-k) + bin_carry b d (i-k)) div 2"
using "2" aux1_digit_lt_linear aux_digit_shift assm
by (smt (verit, best) add.commute add_lessD1 le_add_diff_inverse2)
also have "... = bin_carry b d (Suc i - k)"
using sum_carry_formula "2" by (metis Suc_diff_le Suc_eq_plus1)
finally show ?case .
qed
qed
lemma carry_set_add_shift:
"a < 2^k ⟹ c < 2^k ⟹ carry_set a c ∪ ((+) k) ` carry_set b d ⊆ carry_set (a+b*2^k) (c+d*2^k)"
(is "_ ⟹ _ ⟹ ?A1 ∪ ?A2 ⊆ ?B")
proof -
assume assm1: "a < 2^k" and assm2: "c < 2^k"
{ fix i assume i_def: "i ∈ ?A1"
have "a + c < 2^(Suc k)"
using assm1 assm2 by auto
hence "i ≤ k"
using i_def carry_set_subset_variant by fastforce
hence "i ∈ ?B"
using carry_set_def i_def aux1_carry_set_add_shift[OF assm1 assm2] by auto }
note 0 = this
{ fix i assume i_def: "i ∈ ?A2"
hence "k ≤ i"
by auto
hence "i ∈ ?B"
using i_def aux2_carry_set_add_shift[OF assm1 assm2] unfolding carry_set_def
by (smt (verit) add_diff_cancel_left' carry_bounded image_iff linorder_not_less
mem_Collect_eq nat_less_le) }
note 1 = this
from 0 1 show ?thesis by auto
qed
corollary count_carries_add_shift:
"a < 2^k ⟹ c < 2^k ⟹ count_carries (a + b*2^k) (c + d*2^k)
≥ count_carries a c + count_carries b d"
proof -
assume assm1: "a < 2^k" and assm2: "c < 2^k"
have "carry_set a c ∩ ((+) k) ` carry_set b d = {}"
proof -
{ fix i assume i_def: "i ∈ carry_set a c ∩ ((+) k) ` carry_set b d"
have "a + c < 2^(Suc k)"
using assm1 assm2 by auto
hence "i < Suc k ∧ i ≥ k"
using carry_set_subset_variant i_def by fastforce
hence "i = k"
by auto
moreover have "0 ∉ carry_set b d"
unfolding carry_set_def bin_carry_def by simp
ultimately have "False"
using i_def by auto }
thus ?thesis by auto
qed
hence "card (carry_set a c ∪ ((+) k) ` carry_set b d) =
card (carry_set a c) + card (carry_set b d)"
by (metis card_Un_disjoint card_image carry_set_finite finite_imageI inj_on_add)
thus ?thesis
unfolding count_carries_def using carry_set_add_shift[OF assm1 assm2]
by (metis card_mono carry_set_finite)
qed
lemma carry_set_add_shift_no_overflow:
"a + c < 2^k ⟹ carry_set (a+b*2^k) (c+d*2^k) = carry_set a c ∪ ((+) k) ` carry_set b d"
(is "_ ⟹ ?A = ?B")
proof
assume assm: "a + c < 2^k" show "?A ⊆ ?B"
proof
fix i assume i_def: "i ∈ ?A"
{ assume "i < k"
hence "bin_carry a c i = 1"
using aux1_carry_set_add_shift assm i_def carry_set_def by simp
hence "i ∈ carry_set a c"
using carry_set_def by simp }
note 0 = this
{ assume "i ≥ k"
hence "bin_carry b d (i-k) = 1"
using aux3_carry_set_add_shift[OF assm] i_def carry_set_def by simp
hence "i ∈ ((+) k) ` carry_set b d"
using carry_set_def ‹k ≤ i› image_iff by fastforce }
note 1 = this
from 0 1 show "i ∈ ?B" by force
qed
next
assume "a + c < 2^k" thus "?B ⊆ ?A"
using carry_set_add_shift
by (meson add_lessD1 linorder_not_less trans_le_add2)
qed
corollary count_carries_add_shift_no_overflow:
"a + c < 2^k ⟹ count_carries (a + b*2^k) (c + d*2^k) = count_carries a c + count_carries b d"
proof -
assume assm: "a + c < 2^k"
have "carry_set a c ∩ ((+) k) ` carry_set b d = {}"
proof -
{ fix i assume "i ∈ carry_set a c ∩ ((+) k) ` carry_set b d"
hence "i < k ∧ i ≥ k"
using carry_set_subset_variant[OF assm] by auto }
thus ?thesis by auto
qed
thus ?thesis
unfolding count_carries_def carry_set_add_shift_no_overflow[OF assm]
by (simp add: card_Un_disjoint card_image carry_set_finite)
qed
corollary count_carries_even_even: "count_carries (2*a) (2*b) = count_carries a b"
using count_carries_add_shift_no_overflow[of "0" "0" "1" "a" "b"] by (simp add: mult.commute)
lemma count_carries_digitwise:
assumes "1 ≤ k" and "∀i<q. f i < 2^k ∧ g i < 2^k"
shows "count_carries (∑i<q. f i * (2^k)^i) (∑i<q. g i * (2^k)^i) ≥
(∑i<q. count_carries (f i) (g i))"
using assms
proof (induct q)
case 0 thus ?case by auto
next
case (Suc q)
have 0:"1 < (2::nat)^k"
using Suc.prems(1) dual_order.strict_trans2 less_exp by blast
have bound: "(∑i<q. f i * (2^k)^i) < 2^(k*q) ∧ (∑i<q. g i * (2^k)^i) < 2^(k*q)"
using aux_digit_sum_bound[OF 0] Suc.prems(2) power_mult by (metis (full_types) less_Suc_eq)
have "count_carries (∑i<q. f i * (2^k)^i) (∑i<q. g i * (2^k)^i) ≥
(∑i<q. count_carries (f i) (g i))"
using Suc less_Suc_eq by presburger
hence "(∑i<Suc q. count_carries (f i) (g i)) ≤
count_carries (∑i<q. f i * (2^k)^i) (∑i<q. g i * (2^k)^i) + count_carries (f q) (g q)"
by simp
also have "... ≤ count_carries ((∑i<q. f i * (2^k)^i) + f q * 2^(k*q)) ((∑i<q. g i * (2^k)^i) + g q * 2^(k*q))"
using bound count_carries_add_shift by simp
also have "... = count_carries (∑i<Suc q. f i * (2^k)^i) (∑i<Suc q. g i * (2^k)^i)"
using power_mult by (smt (verit, del_insts) mult.commute sum.lessThan_Suc)
finally show ?case .
qed
corollary count_carries_digitwise_specific:
assumes "1 ≤ k" and "∀i<q. f i < 2^k ∧ g i < 2^k"
shows "i < q ⟹ count_carries (∑i<q. f i * (2^k)^i) (∑i<q. g i * (2^k)^i) ≥
count_carries (f i) (g i)"
proof -
assume "i < q"
hence "count_carries (f i) (g i) ≤ (∑i<q. count_carries (f i) (g i))"
using member_le_sum by (metis (no_types, lifting) finite_lessThan lessThan_iff zero_le)
thus ?thesis
using count_carries_digitwise[OF assms(1) assms(2)] by auto
qed
lemma count_carries_digitwise_no_overflow:
assumes "k ≥ 1" and "∀i<q. f i + g i < 2^k"
shows "count_carries (∑i<q. f i * (2^k)^i) (∑i<q. g i * (2^k)^i) =
(∑i<q. count_carries (f i) (g i))"
using assms
proof (induct q)
case 0 thus ?case by auto
next
case (Suc q)
have bound: "(∑i<q. f i * (2^k)^i) + (∑i<q. g i * (2^k)^i) < 2^(k*q)"
proof -
have 0: "1 < (2::nat)^k"
using Suc.prems(1) dual_order.strict_trans2 less_exp by blast
have "(∑i<q. f i * (2^k)^i) + (∑i<q. g i * (2^k)^i) = (∑i<q. (f i + g i) * (2^k)^i)"
by (simp add: sum.distrib algebra_simps)
also have "... < (2^k)^q"
using aux_digit_sum_bound[OF 0] Suc.prems(2) less_Suc_eq by presburger
finally show ?thesis
unfolding power_mult .
qed
have "(∑i<Suc q. count_carries (f i) (g i)) =
count_carries (∑i<q. f i * (2^k)^i) (∑i<q. g i * (2^k)^i) + count_carries (f q) (g q)"
using Suc by simp
also have "... = count_carries ((∑i<q. f i * (2^k)^i) + f q * 2^(k*q))
((∑i<q. g i * (2^k)^i) + g q * 2^(k*q))"
using bound count_carries_add_shift_no_overflow assms by auto
also have "... = count_carries (∑i<Suc q. f i * (2^k)^i) (∑i<Suc q. g i * (2^k)^i)"
using power_mult by (smt (verit, del_insts) mult.commute sum.lessThan_Suc)
finally show ?case
by simp
qed
lemma carry_set_empty_iff:
"carry_set a b = {} ⟷ (∀i. a ¡ i + b ¡ i ≤ 1)"
proof
assume "carry_set a b = {}"
hence "bin_carry a b i = 0" for i
unfolding carry_set_def using carry_bounded
by (smt (verit) Collect_empty_eq_bot div_le_dividend div_self empty_def nle_le)
hence "(a ¡ i + b ¡ i) div 2 = 0" for i
using sum_carry_formula by (metis add.right_neutral)
thus "∀i. a ¡ i + b ¡ i ≤ 1"
by (metis Suc_1 add_self_div_2 div_le_mono nat_1_add_1 not_less_eq_eq not_one_le_zero)
next
assume assm: "∀i. a ¡ i + b ¡ i ≤ 1"
hence "bin_carry a b k = 0" for k
using carry_digit_impl by (metis Suc_1 Suc_n_not_le_n)
thus "carry_set a b = {}"
unfolding carry_set_def by simp
qed
corollary count_carries_zero_iff:
"count_carries a b = 0 ⟷ (∀i. a ¡ i + b ¡ i ≤ 1)"
using count_carries_def carry_set_empty_iff by (simp add: carry_set_finite)
lemma no_carry_no_overflow:
assumes "a < 2^k" and "b < 2^k" and "count_carries a b = 0"
shows "a + b < 2^k"
proof -
have "carry_set a b = {}"
using assms(3) count_carries_def carry_set_finite by simp
hence "bin_carry a b i = 0" for i
unfolding carry_set_def using carry_bounded
by (smt (verit) Collect_empty_eq_bot div_le_dividend div_self empty_def nle_le)
hence "(a mod 2^k + b mod 2^k) div 2^k = 0"
using bin_carry_def by simp
hence "(a + b) div 2^k = 0"
using assms(1-2) by simp
thus "a + b < 2^k"
by (simp add: div_eq_0_iff)
qed
lemma count_carries_divisibility_pow2: "count_carries (2^k-1) x = 0 ⟷ 2^k dvd x"
proof
assume "count_carries (2^k-1) x = 0"
hence "((2^k-1) ¡ i) + (x ¡ i) ≤ 1" for i
using count_carries_zero_iff by simp
hence "i < k ⟹ x ¡ i = 0" for i
by (metis add_le_same_cancel2 bot_nat_0.extremum even_decr_exp_div_exp_iff'
le_antisym mod2_eq_if not_less nth_bit_def)
thus "2^k dvd x" using aux2_digit_wise_equiv by presburger
next
assume assm: "2^k dvd x"
{ fix i assume "i < k"
hence "2 * 2^i dvd x"
by (metis Suc_leI assm dvd_trans le_imp_power_dvd power_Suc)
hence "x ¡ i = 0"
unfolding nth_bit_def by auto }
hence "((2^k-1) ¡ i) + (x ¡ i) ≤ 1" for i
using nth_bit_bounded
by (metis Nat.le_diff_conv2 add.right_neutral bot_nat_0.extremum even_decr_exp_div_exp_iff'
mod_eq_0_iff_dvd not_less nth_bit_def)
thus "count_carries (2^k-1) x = 0"
using count_carries_zero_iff by simp
qed
lemma nth_digit_gen_power_series_general:
assumes "1 < b" and "∀k≤q. f k < b"
shows "nth_digit (∑k=0..q. f k * b^k) i b = (if i ≤ q then f i else 0)"
(is "nth_digit ?X _ _ = _")
proof (cases "i ≤ q")
case False
have "?X < b^(Suc q)"
using aux_digit_sum_bound[OF assms(1)] assms(2)
by (metis (full_types) Suc_leI atLeast0AtMost lessThan_Suc_atMost verit_comp_simplify1(3))
thus ?thesis
using False unfolding nth_digit_def
by (metis (no_types, lifting) assms(1) div_less dual_order.strict_trans2
linordered_nonzero_semiring_class.zero_le_one mod_less not_less_eq_eq power_increasing_iff
verit_comp_simplify1(3))
next
case True
have split0: "?X = (∑k<i+1. f k * b^k) + (∑k<q-i. f (k+i+1) * b^k) * b^(i+1)"
proof -
have "(∑k=i+1..q. f k * b^k) = (∑k=Suc i..<Suc q. f k * b^k)"
using Suc_eq_plus1 atLeastLessThanSuc_atLeastAtMost by presburger
also have "... = (∑k=0 + Suc i..<(Suc q - Suc i) + Suc i. f k * b^k)"
by (simp add: True)
also have "... = (∑k=0..<(Suc q - Suc i). f (k + Suc i) * b^(k + Suc i))"
using sum.shift_bounds_nat_ivl by blast
also have "... = (∑k<q-i. f (k+i+1) * b^(k+i+1))"
using atLeast0LessThan by force
also have "... = (∑k<q-i. f (k+i+1) * b^k * b^(i+1))"
by (simp add: power_add algebra_simps)
finally have rewrite: "(∑k=i+1..q. f k * b^k) = (∑k<q-i. f (k+i+1) * b^k) * b^(i+1)"
using sum_distrib_right by (smt (verit) sum.cong)
have "?X = (∑k=0..i. f k * b^k) + (∑k=i+1..q. f k * b^k)"
using sum.ub_add_nat
by (smt (verit, ccfv_threshold) True bot_nat_0.extremum nat_le_iff_add)
thus ?thesis
using rewrite by (metis Suc_eq_plus1 atLeast0AtMost lessThan_Suc_atMost)
qed
have bound0: "(∑k<i+1. f k * b^k) < b^(i+1)"
using aux_digit_sum_bound[OF assms(1)] assms(2) True
using Suc_eq_plus1 le_trans less_Suc_eq_le by presburger
have 0: "nth_digit ?X i b = nth_digit (∑k<i+1. f k * b^k) i b"
(is "_ = nth_digit ?Y _ _")
using aux2_digit_gen_sum_repr[OF bound0] unfolding split0
by (metis (no_types, lifting) add.commute less_add_same_cancel1 zero_less_one)
have split1: "?Y = (∑k<i. f k * b^k) + f i * b^i"
by simp
have bound1: "(∑k<i. f k * b^k) < b^i"
using aux_digit_sum_bound[OF assms(1)] assms(2) True by auto
have 1: "nth_digit ?Y i b = nth_digit (f i * b^i) i b"
using aux3_digit_gen_sum_repr[OF bound1 assms(1)] unfolding split1
by (simp add: add.commute)
have 2: "nth_digit (f i * b^i) i b = f i"
unfolding nth_digit_def using assms(2) True by auto
show ?thesis
using 0 1 2 True by simp
qed
lemma aux_count_bits_multiplicity:
"count_bits (Suc x) + multiplicity 2 (Suc x) = count_bits x + 1"
proof (induct x rule: Bit_Operations.nat_bit_induct)
case zero thus ?case using count_bits_1 by auto
next
case (even x)
have "¬ 2 dvd Suc (2*x)"
by simp
thus ?case
using count_bits_even count_bits_odd by (simp add: multiplicity_eq_zero_iff)
next
case (odd x)
have "multiplicity 2 (2 * Suc x) = multiplicity 2 (Suc x) + 1"
by (metis Suc_1 Suc_eq_plus1 multiplicity_times_same nat.simps(3) odd_one)
thus ?case
using count_bits_even count_bits_odd
by (metis add.commute add_2_eq_Suc add_Suc_right mult_Suc_right odd plus_1_eq_Suc)
qed
lemma count_bits_multiplicity:
"count_bits x = multiplicity 2 (2*x choose x)"
proof (induct x)
case 0
then show ?case
using One_nat_def binomial_n_0 multiplicity_one_nat count_bits_0 by presburger
next
case (Suc x)
have p: "prime_elem (2::nat)"
using prime_elem_nat_iff two_is_prime_nat by presburger
have e: "(2 * Suc x choose Suc x) * Suc x * Suc x = (2*x choose x) * 2 * Suc x * (2*x+1)"
by (smt (z3) Suc_times_binomial_add add.right_neutral add_2_eq_Suc add_Suc_right
add_diff_cancel_left' binomial_absorption mult.commute mult.left_commute mult_2
mult_Suc_right plus_1_eq_Suc)
let ?m = "multiplicity (2::nat)"
have "¬ (2 dvd (2*x+1))" by simp
hence "?m ((2 * Suc x choose Suc x) * Suc x * Suc x) = ?m ((2*x choose x) * 2 * (Suc x))"
by (metis (no_types, lifting) e mult.commute multiplicity_prime_elem_times_other p)
hence "?m ((2 * Suc x choose Suc x) * Suc x) = ?m ((2*x choose x) * 2)"
using prime_elem_multiplicity_mult_distrib[OF p]
by (metis add_is_0 add_right_cancel e mult_is_0 nat.simps(3) zero_neq_one)
hence "?m (2 * Suc x choose Suc x) + ?m (Suc x) = ?m (2*x choose x) + ?m 2"
using prime_elem_multiplicity_mult_distrib[OF p] binomial_eq_0_iff
by (metis less_numeral_extra(3) mult_2 nat.simps(3) nat_zero_less_power_iff not_add_less1
zero_power2)
hence "?m (2 * Suc x choose Suc x) + ?m (Suc x) = count_bits x + 1"
using multiplicity_prime[OF p] Suc by metis
hence "?m (2 * Suc x choose Suc x) = count_bits (Suc x)"
using aux_count_bits_multiplicity by (metis add_diff_cancel_right')
thus ?case by simp
qed
corollary count_bits_divibility_binomial:
"2^k dvd (2*x choose x) ⟷ k ≤ count_bits x"
using count_bits_multiplicity by (simp add: power_dvd_iff_le_multiplicity)
end