Theory Data_Integer

section ‹Data: Integers›

theory Data_Integer
  imports
    Numeral_Cpo
    Data_Bool
begin

domain Integer = MkI (lazy int)

instance Integer :: flat
proof
  fix x y :: Integer
  assume "x  y" then show "x =   x = y"
    by (cases x; cases y) simp_all
qed

instantiation Integer :: "{plus,times,minus,uminus,zero,one}"
begin

definition "0 = MkI0"
definition "1 = MkI1"
definition "a + b = (Λ (MkIx) (MkIy). MkI(x + y))ab"
definition "a - b = (Λ (MkIx) (MkIy). MkI(x - y))ab"
definition "a * b = (Λ (MkIx) (MkIy). MkI(x * y))ab"
definition "- a = (Λ (MkIx). MkI(uminus x))a"

instance ..

end

lemma Integer_arith_strict [simp]:
  fixes x :: Integer
  shows " + x = " and "x +  = "
    and " * x = " and "x *  = "
    and " - x = " and "x -  = "
    and "-  = (::Integer)"
  unfolding plus_Integer_def times_Integer_def
  unfolding minus_Integer_def uminus_Integer_def
  by (cases x, simp, simp)+

lemma Integer_arith_simps [simp]:
  "MkIa + MkIb = MkI(a + b)"
  "MkIa * MkIb = MkI(a * b)"
  "MkIa - MkIb = MkI(a - b)"
  "- MkIa = MkI(uminus a)"
  unfolding plus_Integer_def times_Integer_def
  unfolding minus_Integer_def uminus_Integer_def
  by simp_all

lemma plus_MkI_MkI:
  "MkIx + MkIy = MkI(x + y)"
  unfolding plus_Integer_def by simp

instance Integer :: "{plus_cpo,minus_cpo,times_cpo}"
  by standard (simp_all add: flatdom_strict2cont)

instance Integer :: comm_monoid_add
proof
  fix a b c :: Integer
  show "(a + b) + c = a + (b + c)"
    by (cases a; cases b; cases c) simp_all
  show "a + b = b + a"
    by (cases a; cases b) simp_all
  show "0 + a = a"
    unfolding zero_Integer_def
    by (cases a) simp_all
qed

instance Integer :: comm_monoid_mult
proof
  fix a b c :: Integer
  show "(a * b) * c = a * (b * c)"
    by (cases a; cases b; cases c) simp_all
  show "a * b = b * a"
    by (cases a; cases b) simp_all
  show "1 * a = a"
    unfolding one_Integer_def
    by (cases a) simp_all
qed

instance Integer :: comm_semiring
proof
  fix a b c :: Integer
  show "(a + b) * c = a * c + b * c"
    by (cases a; cases b; cases c) (simp_all add: distrib_right)
qed

instance Integer :: semiring_numeral ..

lemma Integer_add_diff_cancel [simp]:
  "b    (a::Integer) + b - b = a"
  by (cases a; cases b) simp_all

lemma zero_Integer_neq_bottom [simp]: "(0::Integer)  "
  by (simp add: zero_Integer_def)

lemma one_Integer_neq_bottom [simp]: "(1::Integer)  "
  by (simp add: one_Integer_def)

lemma plus_Integer_eq_bottom_iff [simp]:
  fixes x y :: Integer shows "x + y =   x =   y = "
  by (cases x, simp, cases y, simp, simp)

lemma diff_Integer_eq_bottom_iff [simp]:
  fixes x y :: Integer shows "x - y =   x =   y = "
  by (cases x, simp, cases y, simp, simp)

lemma mult_Integer_eq_bottom_iff [simp]:
  fixes x y :: Integer shows "x * y =   x =   y = "
  by (cases x, simp, cases y, simp, simp)

lemma minus_Integer_eq_bottom_iff [simp]:
  fixes x :: Integer shows "- x =   x = "
  by (cases x, simp, simp)

lemma numeral_Integer_eq: "numeral k = MkI(numeral k)"
  by (induct k, simp_all only: numeral.simps one_Integer_def plus_MkI_MkI)

lemma numeral_Integer_neq_bottom [simp]: "(numeral k::Integer)  "
  unfolding numeral_Integer_eq by simp

text ‹Symmetric versions are also needed, because the reorient
  simproc does not apply to these comparisons.›

lemma bottom_neq_zero_Integer [simp]: "(::Integer)  0"
  by (simp add: zero_Integer_def)

lemma bottom_neq_one_Integer [simp]: "(::Integer)  1"
  by (simp add: one_Integer_def)

lemma bottom_neq_numeral_Integer [simp]: "(::Integer)  numeral k"
  unfolding numeral_Integer_eq by simp

instantiation Integer :: Ord_linear
begin

definition
  "eq = (Λ (MkIx) (MkIy). if x = y then TT else FF)"

definition
  "compare = (Λ (MkIx) (MkIy).
    if x < y then LT else if x > y then GT else EQ)"

instance proof
  fix x y z :: Integer
  show "comparey = "
    unfolding compare_Integer_def by simp
  show "comparex = "
    unfolding compare_Integer_def by (cases x, simp_all)
  show "oppOrdering(comparexy) = compareyx"
    unfolding compare_Integer_def
    by (cases x, cases y, simp, simp,
        cases y, simp, simp add: not_less less_imp_le)
  show "x = y" if "comparexy = EQ"
    using that
    unfolding compare_Integer_def
    by (cases x, cases y, simp, simp,
        cases y, simp, simp split: if_splits)
  show "comparexz = LT" if "comparexy = LT" and "compareyz = LT"
    using that
    unfolding compare_Integer_def
    by (cases x, simp, cases y, simp, cases z, simp,
        auto split: if_splits)
  show "eqxy = is_EQ(comparexy)"
    unfolding eq_Integer_def compare_Integer_def
    by (cases x, simp, cases y, simp, auto)
  show "comparexx  EQ"
    unfolding compare_Integer_def
    by (cases x, simp_all)
qed

end

lemma eq_MkI_MkI [simp]:
  "eq(MkIm)(MkIn) = (if m = n then TT else FF)"
  by (simp add: eq_Integer_def)

lemma compare_MkI_MkI [simp]:
  "compare(MkIx)(MkIy) = (if x < y then LT else if x > y then GT else EQ)"
  unfolding compare_Integer_def by simp

lemma lt_MkI_MkI [simp]:
  "lt(MkIx)(MkIy) = (if x < y then TT else FF)"
  unfolding lt_def by simp

lemma le_MkI_MkI [simp]:
  "le(MkIx)(MkIy) = (if x  y then TT else FF)"
  unfolding le_def by simp

lemma eq_Integer_bottom_iff [simp]:
  fixes x y :: Integer shows "eqxy =   x =   y = "
  by (cases x, simp, cases y, simp, simp)

lemma compare_Integer_bottom_iff [simp]:
  fixes x y :: Integer shows "comparexy =   x =   y = "
  by (cases x, simp, cases y, simp, simp)

lemma lt_Integer_bottom_iff [simp]:
  fixes x y :: Integer shows "ltxy =   x =   y = "
  by (cases x, simp, cases y, simp, simp)

lemma le_Integer_bottom_iff [simp]:
  fixes x y :: Integer shows "lexy =   x =   y = "
  by (cases x, simp, cases y, simp, simp)

lemma compare_refl_Integer [simp]:
  "(x::Integer)    comparexx = EQ"
  by (cases x) simp_all

lemma eq_refl_Integer [simp]:
  "(x::Integer)    eqxx = TT"
  by (cases x) simp_all

lemma lt_refl_Integer [simp]:
  "(x::Integer)    ltxx = FF"
  by (cases x) simp_all

lemma le_refl_Integer [simp]:
  "(x::Integer)    lexx = TT"
  by (cases x) simp_all

lemma eq_Integer_numeral_simps [simp]:
  "eq(0::Integer)0 = TT"
  "eq(0::Integer)1 = FF"
  "eq(1::Integer)0 = FF"
  "eq(1::Integer)1 = TT"
  "eq(0::Integer)(numeral k) = FF"
  "eq(numeral k)(0::Integer) = FF"
  "k  Num.One  eq(1::Integer)(numeral k) = FF"
  "k  Num.One  eq(numeral k)(1::Integer) = FF"
  "eq(numeral k::Integer)(numeral l) = (if k = l then TT else FF)"
  unfolding zero_Integer_def one_Integer_def numeral_Integer_eq
  by simp_all

lemma compare_Integer_numeral_simps [simp]:
  "compare(0::Integer)0 = EQ"
  "compare(0::Integer)1 = LT"
  "compare(1::Integer)0 = GT"
  "compare(1::Integer)1 = EQ"
  "compare(0::Integer)(numeral k) = LT"
  "compare(numeral k)(0::Integer) = GT"
  "Num.One < k  compare(1::Integer)(numeral k) = LT"
  "Num.One < k  compare(numeral k)(1::Integer) = GT"
  "compare(numeral k::Integer)(numeral l) =
    (if k < l then LT else if k > l then GT else EQ)"
  unfolding zero_Integer_def one_Integer_def numeral_Integer_eq
  by simp_all

lemma lt_Integer_numeral_simps [simp]:
  "lt(0::Integer)0 = FF"
  "lt(0::Integer)1 = TT"
  "lt(1::Integer)0 = FF"
  "lt(1::Integer)1 = FF"
  "lt(0::Integer)(numeral k) = TT"
  "lt(numeral k)(0::Integer) = FF"
  "Num.One < k  lt(1::Integer)(numeral k) = TT"
  "lt(numeral k)(1::Integer) = FF"
  "lt(numeral k::Integer)(numeral l) = (if k < l then TT else FF)"
  unfolding zero_Integer_def one_Integer_def numeral_Integer_eq
  by simp_all

lemma le_Integer_numeral_simps [simp]:
  "le(0::Integer)0 = TT"
  "le(0::Integer)1 = TT"
  "le(1::Integer)0 = FF"
  "le(1::Integer)1 = TT"
  "le(0::Integer)(numeral k) = TT"
  "le(numeral k)(0::Integer) = FF"
  "le(1::Integer)(numeral k) = TT"
  "Num.One < k  le(numeral k)(1::Integer) = FF"
  "le(numeral k::Integer)(numeral l) = (if k  l then TT else FF)"
  unfolding zero_Integer_def one_Integer_def numeral_Integer_eq
  by simp_all

lemma MkI_eq_0_iff [simp]: "MkIn = 0  n = 0"
  unfolding zero_Integer_def by simp

lemma MkI_eq_1_iff [simp]: "MkIn = 1  n = 1"
  unfolding one_Integer_def by simp

lemma MkI_eq_numeral_iff [simp]: "MkIn = numeral k  n = numeral k"
  unfolding numeral_Integer_eq by simp

lemma MkI_0: "MkI0 = 0"
  by simp

lemma MkI_1: "MkI1 = 1"
  by simp

lemma le_plus_1:
  fixes m :: "Integer"
  assumes "lemn = TT"
  shows "lem(n + 1) = TT"
proof -
  from assms have "n  " by auto
  then have "len(n + 1) = TT"
    by (cases n) (auto, metis le_MkI_MkI less_add_one less_le_not_le one_Integer_def plus_MkI_MkI)
  with assms show ?thesis by (auto dest: le_trans)
qed

subsection ‹Induction rules that do not break the abstraction›

lemma nonneg_Integer_induct [consumes 1, case_names 0 step]:
  fixes i :: Integer
  assumes i_nonneg: "le0i = TT"
    and zero: "P 0"
    and step: "i. le1i = TT  P (i - 1)  P i"
  shows "P i"
proof (cases i)
  case bottom
  then have False using i_nonneg by simp
  then show ?thesis ..
next
  case (MkI integer)
  show ?thesis
  proof (cases integer)
    case neg
    then have False using i_nonneg MkI by (auto simp add: zero_Integer_def one_Integer_def)
    then show ?thesis ..
  next
    case (nonneg nat)
    have "P (MkI(int nat))"
    proof(induct nat)
      case 0
      show ?case using zero by (simp add: zero_Integer_def)
    next
      case (Suc nat)
      have "le1(MkI(int (Suc nat))) = TT"
        by (simp add: one_Integer_def)
      moreover
      have "P (MkI(int (Suc nat)) - 1)"
        using Suc
        by (simp add: one_Integer_def)
      ultimately
      show ?case
        by (rule step)
    qed
    then show ?thesis using nonneg MkI by simp
  qed
qed

end