Theory Karatsuba_Code_Nat
section "Code Generation"
theory Karatsuba_Code_Nat
  imports Main "HOL-Library.Code_Binary_Nat" Karatsuba
begin
text "In this theory, the Karatsuba Multiplication implemented in @{text Karatsuba} is used for code
generation. This is not really practical (except beginning at ~3000 decimal digits), but merely a
nice gimmick."
fun from_numeral :: "num ⇒ nat_lsbf" where
  "from_numeral num.One = [True]"
| "from_numeral (num.Bit0 x) = False # from_numeral x"
| "from_numeral (num.Bit1 x) = True # from_numeral x"
lemma from_numeral_nonempty: "from_numeral x ≠ []"
  by (induction x rule: from_numeral.induct; simp)
lemma from_numeral_truncated: "truncated (from_numeral x)"
  unfolding truncated_iff
  by (induction x rule: from_numeral.induct; simp add: from_numeral_nonempty)
lemma to_nat_from_numeral_neq_zero: "to_nat (from_numeral x) ≠ 0"
  using to_nat_zero_iff from_numeral_truncated from_numeral_nonempty by simp
fun to_numeral_of_truncated :: "nat_lsbf ⇒ num" where
"to_numeral_of_truncated [] = num.One"
| "to_numeral_of_truncated [True] = num.One"
| "to_numeral_of_truncated (True # xs) = num.Bit1 (to_numeral_of_truncated xs)"
| "to_numeral_of_truncated (False # xs) = num.Bit0 (to_numeral_of_truncated xs)"
lemma to_numeral_of_truncated_from_numeral:
 "to_numeral_of_truncated (from_numeral x) = x"
  apply (induction x)
  subgoal by simp
  subgoal by simp
  subgoal for x by (cases "from_numeral x"; simp)
  done
lemma nat_of_num_to_numeral_of_truncated:
  assumes "truncated xs"
  assumes "xs ≠ []"
  shows "nat_of_num (to_numeral_of_truncated xs) = to_nat xs"
  using assms proof (induction xs rule: to_numeral_of_truncated.induct)
  case 1
  then show ?case by blast
next
  case 2
  then show ?case by simp
next
  case (3 v va)
  note truncated_Cons_imp_truncated_tl[OF "3.prems"(1)]
  from "3.IH"[OF this] show ?case by simp
next
  case (4 xs)
  from "4.prems"(1) have "xs ≠ []"
    apply (intro ccontr[of "xs ≠ []"])
    by (simp add: truncated_iff)
  note truncated_Cons_imp_truncated_tl[OF "4.prems"(1)]
  from "4.IH"[OF this ‹xs ≠ []›] show ?case by simp
qed
definition to_numeral :: "nat_lsbf ⇒ num" where
  "to_numeral xs = (let xs' = Nat_LSBF.truncate xs in to_numeral_of_truncated xs')"
lemma to_numeral_from_numeral: "to_numeral (from_numeral x) = x"
  unfolding to_numeral_def Let_def
  using from_numeral_truncated  to_numeral_of_truncated_from_numeral
  by simp
lemma nat_of_num_to_numeral:
  assumes "to_nat xs ≠ 0"
  shows "nat_of_num (to_numeral xs) = to_nat xs"
  unfolding to_numeral_def Let_def
  using assms nat_of_num_to_numeral_of_truncated[of "truncate xs", OF truncate_truncate]
  unfolding nat_lsbf.to_f_elem
  using to_nat_zero_iff
  by simp
lemma l0:
  assumes "truncated xs"
  shows "to_numeral_of_truncated xs = num_of_nat (to_nat xs)"
  using assms
  by (metis nat_of_num_inverse nat_of_num_to_numeral_of_truncated num_of_nat.simps(1) to_nat.simps(1) to_numeral_of_truncated.simps(1))
  
lemma l1: "to_numeral xs = num_of_nat (to_nat xs)"
  unfolding to_numeral_def Let_def
  using l0[of "truncate xs"] truncate_truncate[of xs] nat_lsbf.to_f_elem
  by simp
lemma l2: "to_nat (from_numeral x) = nat_of_num x"
  by (metis nat_of_num_to_numeral to_nat_from_numeral_neq_zero to_numeral_from_numeral)
lemma[code]: 
  "(x::num) * y = to_numeral (karatsuba_mul_nat (from_numeral x) (from_numeral y))"
  unfolding l1 karatsuba_mul_nat_correct l2 times_num_def by (rule refl)
end