Theory Root_Balanced_Tree_Tab
section "Tabulating the Balanced Predicate"
theory Root_Balanced_Tree_Tab
imports
Root_Balanced_Tree
"HOL-Decision_Procs.Approximation"
"HOL-Library.IArray"
begin
locale Min_tab =
fixes p :: "nat ⇒ nat ⇒ bool"
fixes tab :: "nat list"
assumes mono_p: "n ≤ n' ⟹ p n h ⟹ p n' h"
assumes p: "∃n. p n h"
assumes tab_LEAST: "h < length tab ⟹ tab!h = (LEAST n. p n h)"
begin
lemma tab_correct: "h < length tab ⟹ p n h = (n ≥ tab ! h)"
apply auto
using not_le_imp_less not_less_Least tab_LEAST apply auto[1]
by (metis LeastI mono_p p tab_LEAST)
end
definition bal_tab :: "nat list" where
"bal_tab = [0, 1, 1, 2, 4, 6, 10, 16, 25, 40, 64, 101, 161, 256, 406, 645, 1024,
1625, 2580, 4096, 6501, 10321, 16384, 26007, 41285, 65536, 104031, 165140,
262144, 416127, 660561, 1048576, 1664510, 2642245, 4194304, 6658042, 10568983,
16777216, 26632170, 42275935, 67108864, 106528681, 169103740, 268435456,
426114725, 676414963, 1073741824, 1704458900, 2705659852, 4294967296]"
axiomatization where c_def: "c = 3/2"
fun is_floor :: "nat ⇒ nat ⇒ bool" where
"is_floor n h = (let m = floor((2::real) powr ((real(h)-1)/c)) in n ≤ m ∧ m ≤ n)"
text‹Note that @{prop"n ≤ m ∧ m ≤ n"} avoids the technical restriction of the
‹approximation› method which does not support ‹=›, even on integers.›
lemma bal_tab_correct:
"∀i < length bal_tab. is_floor (bal_tab!i) i"
apply(simp add: bal_tab_def c_def All_less_Suc)
apply (approximation 50)
done
lemma ceiling_least_real: "ceiling(r::real) = (LEAST i. r ≤ i)"
by (metis Least_equality ceiling_le le_of_int_ceiling)
lemma floor_greatest_real: "floor(r::real) = (GREATEST i. i ≤ r)"
by (metis Greatest_equality le_floor_iff of_int_floor_le)
lemma LEAST_eq_floor:
"(LEAST n. int h ≤ ⌈c * log 2 (real n + 1)⌉) = floor((2::real) powr ((real(h)-1)/c))"
proof -
have "int h ≤ ⌈c * log 2 (real n + 1)⌉
⟷ 2 powr ((real(h)-1)/c) < real(n)+1" (is "?L = ?R") for n
proof -
have "?L ⟷ h < c * log 2 (real n + 1) + 1" by linarith
also have "… ⟷ (real h-1)/c < log 2 (real n + 1)"
using c1 by(simp add: field_simps)
also have "… ⟷ 2 powr ((real h-1)/c) < 2 powr (log 2 (real n + 1))"
by(simp del: powr_log_cancel)
also have "… ⟷ ?R"
by(simp)
finally show ?thesis .
qed
moreover have "((LEAST n::nat. r < n+1) = nat(floor r))" for r :: real
by(rule Least_equality) linarith+
ultimately show ?thesis by simp
qed
interpretation Min_tab
where p = bal_i and tab = bal_tab
proof(unfold bal_i_def, standard, goal_cases)
case (1 n n' h)
have "int h ≤ ceiling(c * log 2 (real n + 1))" by(rule 1[unfolded bal_i_def])
also have "… ≤ ceiling(c * log 2 (real n' + 1))"
using c1 "1"(1) by (simp add: ceiling_mono)
finally show ?case .
next
case (2 h)
show ?case
proof
show "int h ≤ ⌈c * log 2 (real (2 ^ h - 1) + 1)⌉"
apply(simp add: of_nat_diff log_nat_power) using c1
by (metis ceiling_mono ceiling_of_nat order.order_iff_strict mult.left_neutral mult_eq_0_iff of_nat_0_le_iff mult_le_cancel_right_pos)
qed
next
case 3
thus ?case using bal_tab_correct LEAST_eq_floor
by (simp add: eq_iff[symmetric]) (metis nat_int)
qed
text‹Now we replace the list by an immutable array:›
definition bal_array :: "nat iarray" where
"bal_array = IArray bal_tab"
text‹A trick for code generation: how to get rid of the precondition:›
lemma bal_i_code:
"bal_i n h =
(if h < IArray.length bal_array then IArray.sub bal_array h ≤ n else bal_i n h)"
by (simp add: bal_array_def tab_correct)
end