Theory Impl_Uv_Set

theory Impl_Uv_Set
imports
  "../../Iterator/Iterator"
  "../Intf/Intf_Set"
  Native_Word.Uint
begin

  subsection ‹Bit-Vectors as Lists of Words›

  subsubsection ‹Lookup›

  primrec lookup :: "nat  ('a::len) word list  bool" where
    "lookup _ []  False"
  | "lookup n (w#ws)
       (if n<LENGTH('a) then bit w n else lookup (n-LENGTH('a)) ws)"

  lemma lookup_append[simp]: "lookup n (w1@w2 :: 'a::len word list)
     (
      if n < LENGTH('a) * length w1 then
        lookup n w1
      else lookup (n - LENGTH('a) * length w1) w2)"
    by (induction w1 arbitrary: n) auto

  lemma lookup_zeroes[simp]: "lookup i (replicate n (0::'a::len word)) = False"
    by (induction n arbitrary: i) auto

  lemma lookup_out_of_bound:
    fixes uv :: "'a::len word list"
    assumes "¬ i < LENGTH('a::len) * length uv"
    shows "¬ lookup i uv"
    using assms
    by (induction uv arbitrary: i) auto


  subsubsection ‹Empty›

  definition empty :: "'a::len word list" where "empty = []"

  subsubsection ‹Set and Reset Bit›

  function single_bit :: "nat  ('a::len) word list"
    where "single_bit n = (
      if (n<LENGTH('a)) then
        [set_bit 0 n True]
      else 0#single_bit (n-LENGTH('a)))"
    by pat_completeness auto
  termination
    apply (relation "measure id")
    apply simp
    apply (simp add: not_less less_diff_conv2)
    done

  declare single_bit.simps[simp del]

  lemma lookup_single_bit[simp]: "lookup i ((single_bit n)::'a::len word list)  i = n"
    apply (induction n arbitrary: i rule: single_bit.induct)
    apply (subst single_bit.simps)
    apply (auto simp add: bit_simps)
    done

  primrec set_bit :: "nat  'a::len word list  'a::len word list" where
    "set_bit i [] = single_bit i"
  | "set_bit i (w#ws) = (
      if i<LENGTH('a) then
        Bit_Operations.set_bit i w # ws
      else
        w # set_bit (i - LENGTH('a)) ws)"

  lemma set_bit_lookup[simp]: "lookup i (set_bit j ws)  (lookup i ws  i=j)"
    apply (induction ws arbitrary: i j)
     apply (auto simp add: word_size Bit_Operations.bit_set_bit_iff)
    done

  primrec reset_bit :: "nat  'a::len word list  'a::len word list" where
    "reset_bit i [] = []"
  | "reset_bit i (w#ws) = (
      if i<LENGTH('a) then
        unset_bit i w # ws
      else
        w # reset_bit (i - LENGTH('a)) ws)"

  lemma reset_bit_lookup[simp]: "lookup i (reset_bit j ws)  (lookup i ws  ij)"
    apply (induction ws arbitrary: i j)
    apply (auto simp: word_size bit_unset_bit_iff)
    done

  subsubsection ‹Binary Operations›

  context
    includes bit_operations_syntax
  begin

  definition
    is_bin_op_impl
    :: "(boolboolbool)  ('a::len word  'a::len word  'a::len word)  bool"
    where "is_bin_op_impl f g 
    (w v.  i<LENGTH('a). bit (g w v) i  f (bit w i) (bit v i))"

  definition "is_strict_bin_op_impl f g  is_bin_op_impl f g  f False False = False"

  fun binary :: "('a::len word  'a::len word  'a::len word)
     'a::len word list  'a::len word list  'a::len word list"
    where
    "binary f [] [] = []"
  | "binary f [] (w#ws) = f 0 w # binary f [] ws"
  | "binary f (v#vs) [] = f v 0 # binary f vs []"
  | "binary f (v#vs) (w#ws) = f v w # binary f vs ws"

  lemma binary_lookup:
    assumes "is_strict_bin_op_impl f g"
    shows "lookup i (binary g ws vs)  f (lookup i ws) (lookup i vs)"
    using assms
    apply (induction g ws vs arbitrary: i rule: binary.induct)
    apply (auto simp: is_strict_bin_op_impl_def is_bin_op_impl_def)
    done

  subsection ‹Abstraction to Sets of Naturals›

  definition "α uv  {n. lookup n uv}"

  lemma memb_correct: "lookup i ws  iα ws"
    by (auto simp: α_def)

  lemma empty_correct: "α empty = {}"
    by (simp add: α_def empty_def)

  lemma single_bit_correct: "α (single_bit n) = {n}"
    by (simp add: α_def)

  lemma insert_correct: "α (set_bit i ws) = Set.insert i (α ws)"
    by (auto simp add: α_def)

  lemma delete_correct: "α (reset_bit i ws) = (α ws) - {i}"
    by (auto simp add: α_def)

  lemma binary_correct:
    assumes "is_strict_bin_op_impl f g"
    shows "α (binary g ws vs) = { i . f (iα ws) (iα vs) }"
    unfolding α_def
    by (auto simp add: binary_lookup[OF assms])

  fun union :: "'a::len word list  'a::len word list  'a::len word list"
    where
    "union [] ws = ws"
  | "union vs [] = vs"
  | "union (v#vs) (w#ws) = (v OR w) # union vs ws"

  lemma union_lookup[simp]:
    fixes vs :: "'a::len word list"
    shows "lookup i (union vs ws)  lookup i vs  lookup i ws"
    apply (induction vs ws arbitrary: i rule: union.induct)
    apply (auto simp: word_ao_nth)
    done

  lemma union_correct: "α (union ws vs) = α ws  α vs"
    by (auto simp add: α_def)

  fun inter :: "'a::len word list  'a::len word list  'a::len word list"
    where
    "inter [] ws = []"
  | "inter vs [] = []"
  | "inter (v#vs) (w#ws) = (v AND w) # inter vs ws"

  lemma inter_lookup[simp]:
    fixes vs :: "'a::len word list"
    shows "lookup i (inter vs ws)  lookup i vs  lookup i ws"
    apply (induction vs ws arbitrary: i rule: inter.induct)
    apply (auto simp: word_ao_nth)
    done

  lemma inter_correct: "α (inter ws vs) = α ws  α vs"
    by (auto simp add: α_def)


  fun diff :: "'a::len word list  'a::len word list  'a::len word list"
    where
    "diff [] ws = []"
  | "diff vs [] = vs"
  | "diff (v#vs) (w#ws) = (v AND NOT w) # diff vs ws"

  lemma diff_lookup[simp]:
    fixes vs :: "'a::len word list"
    shows "lookup i (diff vs ws)  lookup i vs - lookup i ws"
    apply (induction vs ws arbitrary: i rule: diff.induct)
    apply (auto simp: word_ops_nth_size word_size)
    done

  lemma diff_correct: "α (diff ws vs) = α ws - α vs"
    by (auto simp add: α_def)

  fun zeroes :: "'a::len word list  bool" where
    "zeroes []  True"
  | "zeroes (w#ws)  w=0  zeroes ws"

  lemma zeroes_lookup: "zeroes ws  (i. ¬lookup i ws)"
    apply (induction ws)
    apply (auto simp: word_eq_iff)
    by (metis diff_add_inverse2 not_add_less2)

  lemma isEmpty_correct: "zeroes ws  α ws = {}"
    by (auto simp: zeroes_lookup α_def)

  fun equal :: "'a::len word list  'a::len word list  bool" where
    "equal [] []  True"
  | "equal [] ws  zeroes ws"
  | "equal vs []  zeroes vs"
  | "equal (v#vs) (w#ws)  v=w  equal vs ws"

  lemma equal_lookup:
    fixes vs ws :: "'a::len word list"
    shows "equal vs ws  (i. lookup i vs = lookup i ws)"
  proof (induction vs ws rule: equal.induct)
    fix v w and vs ws :: "'a::len word list"
    assume IH: "equal vs ws = (i. lookup i vs = lookup i ws)"
    show "equal (v # vs) (w # ws) = (i. lookup i (v # vs) = lookup i (w # ws))"
    proof (rule iffI, rule allI)
      fix i
      assume "equal (v#vs) (w#ws)"
      thus "lookup i (v # vs) = lookup i (w # ws)"
        by (auto simp: IH)
    next
      assume "i. lookup i (v # vs) = lookup i (w # ws)"
      thus "equal (v # vs) (w # ws)"
        apply (auto simp: word_eq_iff IH)
        apply metis
        apply metis
        apply (drule_tac x="i + LENGTH('a)" in spec)
        apply auto []
        apply (drule_tac x="i + LENGTH('a)" in spec)
        apply auto []
        done
    qed
  qed (auto simp: zeroes_lookup)

  lemma equal_correct: "equal vs ws  α vs = α ws"
    by (auto simp: α_def equal_lookup)

  fun subseteq :: "'a::len word list  'a::len word list  bool" where
    "subseteq [] ws  True"
  | "subseteq vs []  zeroes vs"
  | "subseteq (v#vs) (w#ws)  (v AND NOT w = 0)  subseteq vs ws"


  lemma subseteq_lookup:
    fixes vs ws :: "'a::len word list"
    shows "subseteq vs ws  (i. lookup i vs  lookup i ws)"
    apply (induction vs ws rule: subseteq.induct)
    apply simp
    apply (auto simp: zeroes_lookup) []
    apply (auto simp: word_ops_nth_size word_size word_eq_iff)
    by (metis diff_add_inverse2 not_add_less2)

  lemma subseteq_correct: "subseteq vs ws  α vs  α ws"
    by (auto simp: α_def subseteq_lookup)


  fun subset :: "'a::len word list  'a::len word list  bool" where
    "subset [] ws  ¬zeroes ws"
  | "subset vs []  False"
  | "subset (v#vs) (w#ws)  (if v=w then subset vs ws else subseteq (v#vs) (w#ws))"

  lemma subset_lookup:
    fixes vs ws :: "'a::len word list"
    shows "subset vs ws  ((i. lookup i vs  lookup i ws)
       (i. ¬lookup i vs  lookup i ws))"
    apply (induction vs ws rule: subset.induct)
    apply (simp add: zeroes_lookup)
    apply (simp add: zeroes_lookup) []
    apply (simp add: subseteq_lookup)
    apply safe
    apply simp_all
    apply (auto simp: word_ops_nth_size word_size word_eq_iff)
    done

  lemma subset_correct: "subset vs ws  α vs  α ws"
    by (auto simp: α_def subset_lookup)


  fun disjoint :: "'a::len word list  'a::len word list  bool" where
    "disjoint [] ws  True"
  | "disjoint vs []  True"
  | "disjoint (v#vs) (w#ws)  (v AND w = 0)  disjoint vs ws"

  lemma disjoint_lookup:
    fixes vs ws :: "'a::len word list"
    shows "disjoint vs ws  (i. ¬(lookup i vs  lookup i ws))"
    apply (induction vs ws rule: disjoint.induct)
    apply simp
    apply simp
    apply (auto simp: word_ops_nth_size word_size word_eq_iff)
    by (metis diff_add_inverse2 not_add_less2)

  lemma disjoint_correct: "disjoint vs ws  α vs  α ws = {}"
    by (auto simp: α_def disjoint_lookup)


subsection ‹Lifting to Uint›
  type_synonym uint_vector = "uint list"

  lift_definition uv_α :: "uint_vector  nat set" is α .
  lift_definition uv_lookup :: "nat  uint_vector  bool" is lookup .
  lift_definition uv_empty :: "uint_vector" is empty .
  lift_definition uv_single_bit :: "nat  uint_vector" is single_bit .
  lift_definition uv_set_bit :: "nat  uint_vector  uint_vector" is set_bit .
  lift_definition uv_reset_bit :: "nat  uint_vector  uint_vector" is reset_bit .
  lift_definition uv_union :: "uint_vector  uint_vector  uint_vector" is union .
  lift_definition uv_inter :: "uint_vector  uint_vector  uint_vector" is inter .
  lift_definition uv_diff :: "uint_vector  uint_vector  uint_vector" is diff .
  lift_definition uv_zeroes :: "uint_vector  bool" is zeroes .
  lift_definition uv_equal :: "uint_vector  uint_vector  bool" is equal .
  lift_definition uv_subseteq :: "uint_vector  uint_vector  bool" is subseteq .
  lift_definition uv_subset :: "uint_vector  uint_vector  bool" is subset .
  lift_definition uv_disjoint :: "uint_vector  uint_vector  bool" is disjoint .

  lemmas uv_memb_correct = memb_correct[where 'a=dflt_size, Transfer.transferred]
  lemmas uv_empty_correct = empty_correct[where 'a=dflt_size, Transfer.transferred]
  lemmas uv_single_bit_correct = single_bit_correct[where 'a=dflt_size, Transfer.transferred]
  lemmas uv_insert_correct = insert_correct[where 'a=dflt_size, Transfer.transferred]
  lemmas uv_delete_correct = delete_correct[where 'a=dflt_size, Transfer.transferred]
  lemmas uv_union_correct = union_correct[where 'a=dflt_size, Transfer.transferred]
  lemmas uv_inter_correct = inter_correct[where 'a=dflt_size, Transfer.transferred]
  lemmas uv_diff_correct = diff_correct[where 'a=dflt_size, Transfer.transferred]
  lemmas uv_isEmpty_correct = isEmpty_correct[where 'a=dflt_size, Transfer.transferred]
  lemmas uv_equal_correct = equal_correct[where 'a=dflt_size, Transfer.transferred]
  lemmas uv_subseteq_correct = subseteq_correct[where 'a=dflt_size, Transfer.transferred]
  lemmas uv_subset_correct = subset_correct[where 'a=dflt_size, Transfer.transferred]
  lemmas uv_disjoint_correct = disjoint_correct[where 'a=dflt_size, Transfer.transferred]



  lemmas [where 'a=dflt_size, Transfer.transferred, code] =
    lookup.simps
    empty_def
    single_bit.simps
    set_bit.simps
    reset_bit.simps
    union.simps
    inter.simps
    diff.simps
    zeroes.simps
    equal.simps
    subseteq.simps
    subset.simps
    disjoint.simps

  end

  hide_const (open) α lookup empty single_bit set_bit reset_bit union inter diff zeroes
    equal subseteq subset disjoint


  subsection ‹Autoref Setup›

  definition uv_set_rel_def_internal:
    "uv_set_rel Rk 
      if Rk=nat_rel then br uv_α (λ_. True) else {}"
  lemma uv_set_rel_def:
    "nat_reluv_set_rel  br uv_α (λ_. True)"
    unfolding uv_set_rel_def_internal relAPP_def by simp

  lemmas [autoref_rel_intf] = REL_INTFI[of "uv_set_rel" i_set]

  lemma uv_set_rel_sv[relator_props]: "single_valued (nat_reluv_set_rel)"
    unfolding uv_set_rel_def by auto

  lemma uv_autoref[autoref_rules,param]:
    "(uv_lookup,(∈))  nat_rel  nat_reluv_set_rel  bool_rel"
    "(uv_empty,{})  nat_reluv_set_rel"
    "(uv_set_bit,insert)  nat_rel  nat_reluv_set_rel  nat_reluv_set_rel"
    "(uv_reset_bit,op_set_delete)  nat_rel  nat_reluv_set_rel  nat_reluv_set_rel"
    "(uv_union,(∪))  nat_reluv_set_rel  nat_reluv_set_rel  nat_reluv_set_rel"
    "(uv_inter,(∩))  nat_reluv_set_rel  nat_reluv_set_rel  nat_reluv_set_rel"
    "(uv_diff,(-))  nat_reluv_set_rel  nat_reluv_set_rel  nat_reluv_set_rel"
    "(uv_zeroes,op_set_isEmpty)  nat_reluv_set_rel  bool_rel"
    "(uv_equal,(=))  nat_reluv_set_rel  nat_reluv_set_rel  bool_rel"
    "(uv_subseteq,(⊆))  nat_reluv_set_rel  nat_reluv_set_rel  bool_rel"
    "(uv_subset,(⊂))  nat_reluv_set_rel  nat_reluv_set_rel  bool_rel"
    "(uv_disjoint,op_set_disjoint)  nat_reluv_set_rel  nat_reluv_set_rel  bool_rel"
    by (auto
      simp: uv_set_rel_def br_def
      simp: uv_memb_correct uv_empty_correct uv_insert_correct uv_delete_correct
      simp: uv_union_correct uv_inter_correct uv_diff_correct uv_isEmpty_correct
      simp: uv_equal_correct uv_subseteq_correct uv_subset_correct uv_disjoint_correct)

  export_code
    uv_lookup
    uv_empty
    uv_single_bit
    uv_set_bit
    uv_reset_bit
    uv_union
    uv_inter
    uv_diff
    uv_zeroes
    uv_equal
    uv_subseteq
    uv_subset
    uv_disjoint
  checking SML Scala Haskell? OCaml?

end