Theory LLVM_DS_Array_List

section Array-Lists
theory LLVM_DS_Array_List
imports LLVM_DS_NArray
begin
  type_synonym ('a,'l) array_list = "'l word × 'l word × 'a narray"

  subsection Auxiliary Functions

  definition [llvm_inline]: "arl_initial_size  Mreturn ((signed_nat (8::_::len word)))"

  definition arl_push_back' :: "('a::llvm_rep,'l::len2) array_list  'a  ('a,'l) array_list llM"    
    where [llvm_inline]: "arl_push_back' al x  doM {
      let (l,c,a) = al;
      array_upd a l x;
      l  ll_add l (signed_nat 1);
      Mreturn (l,c,a)
    }"
  
      
  definition arl_aux_compute_size :: "'l::len2 word  'l word  'l word llM" 
  where [llvm_inline]:   
    "arl_aux_compute_size c c'  doM {
      max::'l word  ll_max_snat;
      max  ll_udiv max (signed_nat 2);
      b  ll_icmp_ule c max;
      llc_if b (doM {
          c  ll_mul c (signed_nat 2);
          cok  ll_icmp_sle c' c;
          llc_if cok (Mreturn c) (Mreturn c')
        }) 
        (Mreturn c')
    }"
  
  
  definition arl_resize :: "'l word  ('a::llvm_rep,'l::len2) array_list  ('a,'l) array_list llM"
    where [llvm_code]: "arl_resize c' al  doM {
      let (l,c,a) = al;
      c  arl_aux_compute_size c c';
      a'  narray_new TYPE('a) c;
      arraycpy a' a l;
      narray_free a;
      Mreturn (l,c,a')
    }"    
  
      
  definition arl_ensure_capacity :: "'l word  ('a::llvm_rep,'l::len2) array_list  ('a,'l) array_list llM"  
    where [llvm_inline]: "arl_ensure_capacity c' al  doM {
      let (l,c,a) = al;
      cok  ll_icmp_sle c' c;
      llc_if cok (Mreturn (l,c,a)) (arl_resize c' (l,c,a))
    }"

  
  
  subsection Interface Functions

  definition arl_new_raw :: "('a::llvm_rep,'l::len2) array_list llM"
  where [llvm_code,llvm_inline]: "arl_new_raw  doM {
    c  arl_initial_size;
    a  narray_new TYPE('a) c;
    Mreturn (signed_nat 0,c,a)
  }"
    
  definition arl_new :: "'a::llvm_rep itself  'l::len2 itself  ('a,'l) array_list llM"
  where [llvm_inline]: "arl_new TYPE('a::llvm_rep) TYPE('l::len2)  arl_new_raw"

  
  definition arl_new_sz_raw :: "'l::len2 word  ('a::llvm_rep,'l) array_list llM"
  where [llvm_code,llvm_inline]: "arl_new_sz_raw n  doM {
    a  narray_new TYPE('a) n;
    Mreturn (n,n,a)
  }"

  definition arl_new_sz :: "'a::llvm_rep itself  'l::len2 word  ('a,'l) array_list llM" 
    where [llvm_inline]: "arl_new_sz TYPE('a) n  arl_new_sz_raw n"

  definition arl_new_repl :: "'l::len2 word  'a::llvm_rep  ('a,'l) array_list llM" 
    where [llvm_inline]: "arl_new_repl n x  doM {
      a  narray_new_init n x;
      Mreturn (n,n,a)
    }"
    
          
  definition arl_clear :: "('a::llvm_rep,'l::len2) array_list  ('a::llvm_rep,'l) array_list llM"
    where [llvm_code,llvm_inline]: "arl_clear al  doM {
      let (l,c,a) = al;
      Mreturn (signed_nat 0,c,a)
    }"  
    
  definition arl_free :: "('a::llvm_rep,'l::len) array_list  unit llM" 
  where [llvm_code,llvm_inline]: "arl_free al  doM {
    let (_,_,a) = al;
    narray_free a
  }"
  

  definition arl_nth :: "('a::llvm_rep,'l::len2) array_list  'll::len2 word  'a llM"
    where [llvm_code,llvm_inline]: "arl_nth al i  doM {
      let (l,c,a) = al;
      array_nth a i
    }"
    
  definition arl_upd :: "('a::llvm_rep,'l::len2) array_list  'll::len2 word  'a  ('a,'l) array_list llM"
    where [llvm_code,llvm_inline]: "arl_upd al i x  doM {
      let (l,c,a) = al;
      array_upd a i x;
      Mreturn (l,c,a)
    }"
  
  definition arl_len :: "('a::llvm_rep,'l::len2) array_list  'l word llM" 
    where [llvm_code,llvm_inline]: "arl_len al  let (l,c,a) = al in Mreturn l"
    
    
  definition [llvm_code,llvm_inline]: "arl_push_back al x  doM {
    l  arl_len al;
    l  ll_add l (signed_nat 1);
    al  arl_ensure_capacity l al;
    arl_push_back' al x
  }"

  definition [llvm_code,llvm_inline]: "arl_pop_back al  doM {
    let (l,c,a) = al;
    l  ll_sub l (signed_nat 1);
    r  array_nth a l;
    Mreturn (r,(l,c,a))
  }"
  
  definition [llvm_code,llvm_inline]: "arl_take l' al  doM {
    let (l,c,a) = al;
    Mreturn (l',c,a)
  }"

  definition [llvm_code,llvm_inline]: "arl_last al  doM {
    let (l,c,a) = al;
    l  ll_sub l (signed_nat 1);
    r  array_nth a l;
    Mreturn r
  }"
  
  definition [llvm_code,llvm_inline]: "arl_butlast al  doM {
    let (l,c,a) = al;
    l  ll_sub l (signed_nat 1);
    Mreturn (l,c,a)
  }"
  
    
  text Direct access to array underlying array-list 
  definition array_of_arl :: "('a::llvm_rep,'l::len2) array_list  'a ptr" where 
    [llvm_inline]: "array_of_arl  λ(l,c,a). a"
  
  
  export_llvm (debug) (no_header)
    "arl_new_raw :: (64 word,64) array_list llM" is "arl_new"
    "arl_new_sz_raw :: 64 word  (64 word,64) array_list llM"
    "arl_clear :: (64 word,64) array_list  (64 word,64) array_list llM"
    "arl_free :: (64 word,64) array_list  unit llM" is "arl_free"
    "arl_nth :: (64 word,64) array_list  64 word  64 word llM" is "arl_nth"
    "arl_upd :: (64 word,64) array_list  64 word  64 word  (64 word,64) array_list llM" is "arl_upd"
    "arl_len :: (64 word,64) array_list  64 word llM" is "arl_len"
    "arl_push_back :: (64 word,64) array_list  64 word  (64 word,64) array_list llM" is "arl_push_back"
    "arl_pop_back :: (64 word,64) array_list  (64 word × (64 word,64) array_list) llM" is "arl_pop_back"
    "arl_take :: 64 word  (64 word,64) array_list  (64 word,64) array_list llM" is "arl_take"
    "arl_last :: (64 word,64) array_list  64 word llM" is "arl_last"
    "arl_butlast :: (64 word,64) array_list  ((64 word,64) array_list) llM" is "arl_butlast"
    
    
  subsection Reasoning Setup  
  
  definition arl_assn' :: "('a::llvm_rep list × nat, 'l::len2 word × 'l word × 'a ptr) dr_assn"
    where "arl_assn'  mk_assn (λ(xs,c) (li,ci,ai). 
      EXS l a. snat.assn l li ** snat.assn c ci ** narray_assn a ai 
        ** (LENGTH('l)>4  lc  c=length a  xs = take l a))"
      
  definition arl_assn :: "('a::llvm_rep list, 'l::len2 word × 'l word × 'a ptr) dr_assn"
    where "arl_assn  mk_assn (λxs ali. EXS c. arl_assn' (xs,c) ali)"
    
  subsubsection Auxiliary Rules
  
  lemma arl_aux_compute_size_rule[vcg_rules]: 
    "llvm_htriple 
      (d(LENGTH('a)>2) ** snat.assn c ci ** snat.assn c' ci' ** d(cc')) 
      (arl_aux_compute_size ci (ci'::'a::len2 word)) 
      (λri. EXS r. snat.assn r ri ** (max c c'  r))"  
    unfolding arl_aux_compute_size_def
    apply (vcg_monadify)
    by vcg
    
    
  lemma arl_resize_rule[vcg_rules]: 
    "llvm_htriple 
      (snat.assn l li ** snat.assn c (ci::'l::len2 word) ** narray_assn a ai ** snat.assn cn cin
        ** d(LENGTH('l)>2  cn>c  lc  c=length a)
      ) 
      (arl_resize cin (li,ci,ai))
      (λ(li,ci,ai). EXS c' a'. snat.assn l li ** snat.assn c' ci ** narray_assn a' ai
        ** (c'cn  c'=length a'  take l a' = take l a)
      )"  
    unfolding arl_resize_def
    by vcg'
  
    
  lemma arl_ensure_capacity_rule[vcg_rules]: 
    "llvm_htriple
      (arl_assn' (al,oc) ali ** snat.assn c ci) (arl_ensure_capacity ci ali) 
      (λali. EXS c'. arl_assn' (al,c') ali ** (c'c))
    "  
    unfolding arl_assn'_def arl_ensure_capacity_def
    by vcg
    
  lemma arl_push_back'_rule[vcg_rules]:
    "llvm_htriple 
      (arl_assn' (al,c) ali ** d(length al < c)) 
      (arl_push_back' ali x) 
      (λali. EXS c. arl_assn' (al@[x],c) ali)"
    unfolding arl_assn'_def arl_push_back'_def
    apply (vcg_monadify)
    apply vcg'
    apply (auto simp: take_update_last)
    done
        
  lemma arl_len_rule_internal:
    "llvm_htriple (arl_assn' (al,c) ali) (arl_len ali) (λli. arl_assn' (al,c) ali ** snat.assn (length al) li)"  
    unfolding arl_assn'_def arl_len_def
    by vcg
  
  subsubsection Interface Rules

  lemma arl_new_raw_rule[vcg_rules]: 
    "llvm_htriple ((LENGTH('l)>4)) (arl_new_raw) (λali. arl_assn [] (ali::(_,'l::len2)array_list))"
    unfolding arl_new_def arl_new_raw_def arl_initial_size_def arl_assn_def arl_assn'_def
    apply (vcg_monadify)
    by vcg'
  
      
  lemma arl_new_rule[vcg_rules]: 
    "llvm_htriple ((LENGTH('c)>4)) (arl_new TYPE('a::llvm_rep) TYPE('c::len2)) (λali. arl_assn [] ali)"
    unfolding arl_new_def arl_new_raw_def arl_initial_size_def arl_assn_def arl_assn'_def
    apply (vcg_monadify)
    by vcg'

  lemma arl_new_sz_rule[vcg_rules]: 
    "llvm_htriple 
      (snat.assn n ni ** (LENGTH('c::len2)>4)) 
      (arl_new_sz TYPE('a::llvm_rep) (ni::'c word)) 
      (λali. arl_assn (replicate n init) ali)"
    unfolding arl_new_sz_def arl_new_sz_raw_def arl_initial_size_def arl_assn_def arl_assn'_def
    apply (vcg_monadify)
    by vcg'

  lemma arl_new_repl_rule[vcg_rules]: 
    "llvm_htriple 
      (snat.assn n ni ** (LENGTH('c::len2)>4)) 
      (arl_new_repl (ni::'c word) x) 
      (λali. arl_assn (replicate n x) ali)"
    unfolding arl_new_repl_def arl_initial_size_def arl_assn_def arl_assn'_def
    apply (vcg_monadify)
    by vcg'
    
        
  lemma arl_assn_init_pure: 
    "PRECOND (SOLVE_AUTO (4 < LENGTH('l)))    arl_assn [] (init::(_,'l::len2)array_list)"  
    unfolding arl_assn_def arl_assn'_def vcg_tag_defs
    unfolding snat.assn_def snat_invar_def
    supply [fri_rules] = narray_assn_init_pure
    apply simp
    apply (rule ENTAILSD)
    by vcg
    
  lemma arl_clear_rule[vcg_rules]: 
    "llvm_htriple 
      (arl_assn al ali) 
      (arl_clear ali) 
      (λali. arl_assn [] ali)"
    unfolding arl_clear_def arl_assn_def arl_assn'_def
    by (vcg_monadify) vcg'
    
  lemma arl_free_rule[vcg_rules]:
    "llvm_htriple (arl_assn al ali) (arl_free ali) (λ_. )"  
    unfolding arl_assn_def arl_assn'_def arl_free_def
    by vcg
    
  lemma arl_nth_rule[vcg_rules]:
    "llvm_htriple 
      (arl_assn al ali ** snat.assn i ii ** d(i<length al)) 
      (arl_nth ali ii)
      (λx. arl_assn al ali ** (x = al!i))"
    unfolding arl_assn_def arl_assn'_def arl_nth_def
    by vcg
  
  lemma array_of_arl_nth_rule[vcg_rules]: "llvm_htriple 
    (arl_assn xs a ** snat.assn i ii ** (i < length xs))
    (array_nth (array_of_arl a) ii)
    (λx. arl_assn xs a ** (x = xs!i))"
    unfolding arl_assn_def arl_assn'_def array_of_arl_def by vcg
    
  lemma arl_upd_rule[vcg_rules]:
    "llvm_htriple 
      (arl_assn al ali ** snat.assn i ii ** d(i<length al)) 
      (arl_upd ali ii x)
      (λali'. arl_assn (al[i:=x]) ali' ** (ali' = ali))"
    unfolding arl_assn_def arl_assn'_def arl_upd_def
    by vcg
    
  lemma arl_len_rule[vcg_rules]:
    "llvm_htriple (arl_assn al ali) (arl_len ali) (λli. arl_assn al ali ** snat.assn (length al) li)"  
    unfolding arl_assn_def
    supply arl_len_rule_internal[vcg_rules]
    by vcg
    
  lemma arl_push_back_rule[vcg_rules]:
    "llvm_htriple (arl_assn al (ali::(_,'l::len2)array_list) ** d(length al + 1 < max_snat LENGTH('l))) (arl_push_back ali x) (λali. arl_assn (al@[x]) ali)"  
    unfolding arl_assn_def arl_push_back_def
    supply arl_len_rule_internal[vcg_rules]
    apply (vcg_monadify)
    by vcg'

  lemma arl_pop_back_rule[vcg_rules]:
    "llvm_htriple (arl_assn al (ali::(_,'l::len2)array_list) ** d(al[])) (arl_pop_back ali) (λ(x,ali). arl_assn (butlast al) ali ** (x=last al))"  
    unfolding arl_assn_def arl_assn'_def arl_pop_back_def
    supply arl_len_rule_internal[vcg_rules]
    apply (vcg_monadify)
    apply vcg'
    by (auto simp: take_minus_one_conv_butlast last_take_nth_conv)
    
  lemma arl_take_rule[vcg_rules]:
    "llvm_htriple 
      (arl_assn al (ali::(_,'l::len2)array_list) ** snat.assn l li ** d(l  length al)) 
      (arl_take li ali) 
      (λali. arl_assn (take l al) ali)"  
    unfolding arl_assn_def arl_assn'_def arl_take_def
    by vcg
    

  lemma arl_last_rule[vcg_rules]:
    "llvm_htriple (arl_assn al (ali::(_,'l::len2)array_list) ** d(al[])) (arl_last ali) (λx. arl_assn al ali ** (x=last al))"  
    unfolding arl_assn_def arl_assn'_def arl_last_def
    supply arl_len_rule_internal[vcg_rules]
    apply (vcg_monadify)
    apply vcg'
    by (auto simp: last_take_nth_conv)
    
    
  lemma arl_butlast_rule[vcg_rules]:
    "llvm_htriple (arl_assn al (ali::(_,'l::len2)array_list) ** d(al[])) (arl_butlast ali) (λali. arl_assn (butlast al) ali)"  
    unfolding arl_assn_def arl_assn'_def arl_butlast_def
    supply arl_len_rule_internal[vcg_rules]
    apply (vcg_monadify)
    apply vcg'
    by (auto simp: take_minus_one_conv_butlast)
    
    
    
    
        
end